Leandro Lacerda 2abd58cb7e
[Offload] Add framework for math conformance tests (#149242)
This PR introduces the initial version of a C++ framework for the
conformance testing of GPU math library functions, building upon the
skeleton provided in #146391.

The main goal of this framework is to systematically measure the
accuracy of math functions in the GPU libc, verifying correctness or at
least conformance to standards like OpenCL via exhaustive or random
accuracy tests.
2025-07-29 11:08:27 -05:00

101 lines
3.1 KiB
C++

//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
/// \file
/// This file contains the definition of the HostRefChecker class, which
/// verifies the results of a device computation against a reference
/// implementation on the host.
///
//===----------------------------------------------------------------------===//
#ifndef MATHTEST_HOSTREFCHECKER_HPP
#define MATHTEST_HOSTREFCHECKER_HPP
#include "mathtest/Numerics.hpp"
#include "mathtest/Support.hpp"
#include "mathtest/TestResult.hpp"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/Sequence.h"
#include "llvm/Support/Parallel.h"
#include <cstddef>
#include <tuple>
#include <utility>
namespace mathtest {
template <auto Func> class HostRefChecker {
using FunctionTraits = FunctionTraits<Func>;
using InTypesTuple = typename FunctionTraits::ArgTypesTuple;
using FunctionConfig = FunctionConfig<Func>;
template <typename... Ts>
using BuffersTupleType = std::tuple<llvm::ArrayRef<Ts>...>;
public:
using OutType = typename FunctionTraits::ReturnType;
private:
template <typename... Ts>
using PartialResultType = TestResult<OutType, Ts...>;
public:
using ResultType = ApplyTupleTypes_t<InTypesTuple, PartialResultType>;
using InBuffersTupleType = ApplyTupleTypes_t<InTypesTuple, BuffersTupleType>;
HostRefChecker() = delete;
static ResultType check(InBuffersTupleType InBuffersTuple,
llvm::ArrayRef<OutType> OutBuffer) noexcept {
const std::size_t BufferSize = OutBuffer.size();
std::apply(
[&](const auto &...InBuffers) {
assert(
((InBuffers.size() == BufferSize) && ...) &&
"All input buffers must have the same size as the output buffer");
},
InBuffersTuple);
assert((BufferSize != 0) && "Buffer size cannot be zero");
ResultType Init;
auto Transform = [&](std::size_t Index) {
auto CurrentInputsTuple = std::apply(
[&](const auto &...InBuffers) {
return std::make_tuple(InBuffers[Index]...);
},
InBuffersTuple);
const OutType Actual = OutBuffer[Index];
const OutType Expected = std::apply(Func, CurrentInputsTuple);
const auto UlpDistance = computeUlpDistance(Actual, Expected);
const bool IsFailure = UlpDistance > FunctionConfig::UlpTolerance;
return ResultType(UlpDistance, IsFailure,
typename ResultType::TestCase(
std::move(CurrentInputsTuple), Actual, Expected));
};
auto Reduce = [](ResultType A, const ResultType &B) {
A.accumulate(B);
return A;
};
const auto Indexes = llvm::seq(BufferSize);
return llvm::parallelTransformReduce(Indexes.begin(), Indexes.end(), Init,
Reduce, Transform);
}
};
} // namespace mathtest
#endif // MATHTEST_HOSTREFCHECKER_HPP