[llvm] [Offload][Conformance] Add `RandomGenerator` for large input spaces (PR #154252)
Leandro Lacerda via llvm-commits
llvm-commits at lists.llvm.org
Tue Aug 19 04:47:03 PDT 2025
https://github.com/leandrolcampos updated https://github.com/llvm/llvm-project/pull/154252
>From 2c6904b209c3a6ff3b2995258058d7954db41449 Mon Sep 17 00:00:00 2001
From: Leandro Augusto Lacerda Campos <leandrolcampos at yahoo.com.br>
Date: Mon, 18 Aug 2025 22:50:54 -0300
Subject: [PATCH 1/5] Add `RandomGenerator` for large input spaces
---
.../Conformance/device_code/CUDAMath.cpp | 5 +
.../Conformance/device_code/DeviceAPIs.hpp | 2 +
.../Conformance/device_code/HIPMath.cpp | 5 +
.../Conformance/device_code/LLVMLibm.cpp | 5 +
.../include/mathtest/ExhaustiveGenerator.hpp | 103 +++++------------
.../include/mathtest/RandomGenerator.hpp | 88 +++++++++++++++
.../include/mathtest/RandomState.hpp | 49 +++++++++
.../include/mathtest/RangeBasedGenerator.hpp | 104 ++++++++++++++++++
.../Conformance/tests/CMakeLists.txt | 1 +
.../unittests/Conformance/tests/LogTest.cpp | 66 +++++++++++
10 files changed, 353 insertions(+), 75 deletions(-)
create mode 100644 offload/unittests/Conformance/include/mathtest/RandomGenerator.hpp
create mode 100644 offload/unittests/Conformance/include/mathtest/RandomState.hpp
create mode 100644 offload/unittests/Conformance/include/mathtest/RangeBasedGenerator.hpp
create mode 100644 offload/unittests/Conformance/tests/LogTest.cpp
diff --git a/offload/unittests/Conformance/device_code/CUDAMath.cpp b/offload/unittests/Conformance/device_code/CUDAMath.cpp
index a351e924b8f89..86c5d698d80af 100644
--- a/offload/unittests/Conformance/device_code/CUDAMath.cpp
+++ b/offload/unittests/Conformance/device_code/CUDAMath.cpp
@@ -119,6 +119,11 @@ __gpu_kernel void expm1fKernel(const float *X, float *Out,
runKernelBody<__nv_expm1f>(NumElements, Out, X);
}
+__gpu_kernel void logKernel(const double *X, double *Out,
+ size_t NumElements) noexcept {
+ runKernelBody<__nv_log>(NumElements, Out, X);
+}
+
__gpu_kernel void logfKernel(const float *X, float *Out,
size_t NumElements) noexcept {
runKernelBody<__nv_logf>(NumElements, Out, X);
diff --git a/offload/unittests/Conformance/device_code/DeviceAPIs.hpp b/offload/unittests/Conformance/device_code/DeviceAPIs.hpp
index 8476dcbeff0c9..7941a05010cc7 100644
--- a/offload/unittests/Conformance/device_code/DeviceAPIs.hpp
+++ b/offload/unittests/Conformance/device_code/DeviceAPIs.hpp
@@ -63,6 +63,7 @@ float __nv_expf(float);
float __nv_exp10f(float);
float __nv_exp2f(float);
float __nv_expm1f(float);
+double __nv_log(double);
float __nv_logf(float);
float __nv_log10f(float);
float __nv_log1pf(float);
@@ -96,6 +97,7 @@ float __ocml_exp_f32(float);
float __ocml_exp10_f32(float);
float __ocml_exp2_f32(float);
float __ocml_expm1_f32(float);
+double __ocml_log_f64(double);
float __ocml_log_f32(float);
float __ocml_log10_f32(float);
float __ocml_log1p_f32(float);
diff --git a/offload/unittests/Conformance/device_code/HIPMath.cpp b/offload/unittests/Conformance/device_code/HIPMath.cpp
index 36efe6b2696ab..55f67669872c5 100644
--- a/offload/unittests/Conformance/device_code/HIPMath.cpp
+++ b/offload/unittests/Conformance/device_code/HIPMath.cpp
@@ -119,6 +119,11 @@ __gpu_kernel void expm1fKernel(const float *X, float *Out,
runKernelBody<__ocml_expm1_f32>(NumElements, Out, X);
}
+__gpu_kernel void logKernel(const double *X, double *Out,
+ size_t NumElements) noexcept {
+ runKernelBody<__ocml_log_f64>(NumElements, Out, X);
+}
+
__gpu_kernel void logfKernel(const float *X, float *Out,
size_t NumElements) noexcept {
runKernelBody<__ocml_log_f32>(NumElements, Out, X);
diff --git a/offload/unittests/Conformance/device_code/LLVMLibm.cpp b/offload/unittests/Conformance/device_code/LLVMLibm.cpp
index 8869d87017486..cf33e0a86e94c 100644
--- a/offload/unittests/Conformance/device_code/LLVMLibm.cpp
+++ b/offload/unittests/Conformance/device_code/LLVMLibm.cpp
@@ -123,6 +123,11 @@ __gpu_kernel void hypotf16Kernel(const float16 *X, float16 *Y, float16 *Out,
runKernelBody<hypotf16>(NumElements, Out, X, Y);
}
+__gpu_kernel void logKernel(const double *X, double *Out,
+ size_t NumElements) noexcept {
+ runKernelBody<log>(NumElements, Out, X);
+}
+
__gpu_kernel void logfKernel(const float *X, float *Out,
size_t NumElements) noexcept {
runKernelBody<logf>(NumElements, Out, X);
diff --git a/offload/unittests/Conformance/include/mathtest/ExhaustiveGenerator.hpp b/offload/unittests/Conformance/include/mathtest/ExhaustiveGenerator.hpp
index 6f7f7a9b665d0..1bed91251a041 100644
--- a/offload/unittests/Conformance/include/mathtest/ExhaustiveGenerator.hpp
+++ b/offload/unittests/Conformance/include/mathtest/ExhaustiveGenerator.hpp
@@ -8,8 +8,8 @@
///
/// \file
/// This file contains the definition of the ExhaustiveGenerator class, a
-/// concrete input generator that exhaustively creates inputs from a given
-/// sequence of ranges.
+/// concrete range-based generator that exhaustively creates inputs from a
+/// given sequence of ranges.
///
//===----------------------------------------------------------------------===//
@@ -17,14 +17,9 @@
#define MATHTEST_EXHAUSTIVEGENERATOR_HPP
#include "mathtest/IndexedRange.hpp"
-#include "mathtest/InputGenerator.hpp"
+#include "mathtest/RangeBasedGenerator.hpp"
-#include "llvm/ADT/ArrayRef.h"
-#include "llvm/Support/Parallel.h"
-
-#include <algorithm>
#include <array>
-#include <cassert>
#include <cstddef>
#include <cstdint>
#include <tuple>
@@ -33,73 +28,44 @@ namespace mathtest {
template <typename... InTypes>
class [[nodiscard]] ExhaustiveGenerator final
- : public InputGenerator<InTypes...> {
- static constexpr std::size_t NumInputs = sizeof...(InTypes);
- static_assert(NumInputs > 0, "The number of inputs must be at least 1");
+ : public RangeBasedGenerator<ExhaustiveGenerator<InTypes...>, InTypes...> {
+
+ friend class RangeBasedGenerator<ExhaustiveGenerator<InTypes...>, InTypes...>;
+
+ using Base = RangeBasedGenerator<ExhaustiveGenerator<InTypes...>, InTypes...>;
+ using IndexArrayType = std::array<uint64_t, Base::NumInputs>;
+
+ using Base::InputSpaceSize;
+ using Base::RangesTuple;
+ using Base::SizeToGenerate;
public:
explicit constexpr ExhaustiveGenerator(
const IndexedRange<InTypes> &...Ranges) noexcept
- : RangesTuple(Ranges...) {
- bool Overflowed = getSizeWithOverflow(Ranges..., Size);
-
- assert(!Overflowed && "The input space size is too large");
- assert((Size > 0) && "The input space size must be at least 1");
+ : Base(Ranges...) {
+ SizeToGenerate = InputSpaceSize;
IndexArrayType DimSizes = {};
std::size_t DimIndex = 0;
((DimSizes[DimIndex++] = Ranges.getSize()), ...);
- Strides[NumInputs - 1] = 1;
- if constexpr (NumInputs > 1)
- for (int Index = static_cast<int>(NumInputs) - 2; Index >= 0; --Index)
+ Strides[Base::NumInputs - 1] = 1;
+ if constexpr (Base::NumInputs > 1)
+ for (int Index = static_cast<int>(Base::NumInputs) - 2; Index >= 0;
+ --Index)
Strides[Index] = Strides[Index + 1] * DimSizes[Index + 1];
}
- void reset() noexcept override { NextFlatIndex = 0; }
-
- [[nodiscard]] std::size_t
- fill(llvm::MutableArrayRef<InTypes>... Buffers) noexcept override {
- const std::array<std::size_t, NumInputs> BufferSizes = {Buffers.size()...};
- const std::size_t BufferSize = BufferSizes[0];
- assert((BufferSize != 0) && "Buffer size cannot be zero");
- assert(std::all_of(BufferSizes.begin(), BufferSizes.end(),
- [&](std::size_t Size) { return Size == BufferSize; }) &&
- "All input buffers must have the same size");
-
- if (NextFlatIndex >= Size)
- return 0;
-
- const auto BatchSize = std::min<uint64_t>(BufferSize, Size - NextFlatIndex);
- const auto CurrentFlatIndex = NextFlatIndex;
- NextFlatIndex += BatchSize;
-
- auto BufferPtrsTuple = std::make_tuple(Buffers.data()...);
-
- llvm::parallelFor(0, BatchSize, [&](std::size_t Offset) {
- writeInputs(CurrentFlatIndex, Offset, BufferPtrsTuple);
- });
-
- return static_cast<std::size_t>(BatchSize);
- }
-
private:
- using RangesTupleType = std::tuple<IndexedRange<InTypes>...>;
- using IndexArrayType = std::array<uint64_t, NumInputs>;
-
- static bool getSizeWithOverflow(const IndexedRange<InTypes> &...Ranges,
- uint64_t &Size) noexcept {
- Size = 1;
- bool Overflowed = false;
-
- auto Multiplier = [&](const uint64_t RangeSize) {
- if (!Overflowed)
- Overflowed = __builtin_mul_overflow(Size, RangeSize, &Size);
- };
+ constexpr IndexArrayType getNDIndex(uint64_t FlatIndex) const noexcept {
+ IndexArrayType NDIndex;
- (Multiplier(Ranges.getSize()), ...);
+ for (std::size_t Index = 0; Index < Base::NumInputs; ++Index) {
+ NDIndex[Index] = FlatIndex / Strides[Index];
+ FlatIndex -= NDIndex[Index] * Strides[Index];
+ }
- return Overflowed;
+ return NDIndex;
}
template <typename BufferPtrsTupleType>
@@ -109,31 +75,18 @@ class [[nodiscard]] ExhaustiveGenerator final
writeInputsImpl<0>(NDIndex, Offset, BufferPtrsTuple);
}
- constexpr IndexArrayType getNDIndex(uint64_t FlatIndex) const noexcept {
- IndexArrayType NDIndex;
-
- for (std::size_t Index = 0; Index < NumInputs; ++Index) {
- NDIndex[Index] = FlatIndex / Strides[Index];
- FlatIndex -= NDIndex[Index] * Strides[Index];
- }
-
- return NDIndex;
- }
-
template <std::size_t Index, typename BufferPtrsTupleType>
void writeInputsImpl(IndexArrayType NDIndex, uint64_t Offset,
BufferPtrsTupleType BufferPtrsTuple) const noexcept {
- if constexpr (Index < NumInputs) {
+ if constexpr (Index < Base::NumInputs) {
const auto &Range = std::get<Index>(RangesTuple);
std::get<Index>(BufferPtrsTuple)[Offset] = Range[NDIndex[Index]];
+
writeInputsImpl<Index + 1>(NDIndex, Offset, BufferPtrsTuple);
}
}
- uint64_t Size = 1;
- RangesTupleType RangesTuple;
IndexArrayType Strides = {};
- uint64_t NextFlatIndex = 0;
};
} // namespace mathtest
diff --git a/offload/unittests/Conformance/include/mathtest/RandomGenerator.hpp b/offload/unittests/Conformance/include/mathtest/RandomGenerator.hpp
new file mode 100644
index 0000000000000..0c62370f17c7a
--- /dev/null
+++ b/offload/unittests/Conformance/include/mathtest/RandomGenerator.hpp
@@ -0,0 +1,88 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 RandomGenerator class, a concrete
+/// range-based generator that randomly creates inputs from a given sequence of
+/// ranges.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef MATHTEST_RANDOMGENERATOR_HPP
+#define MATHTEST_RANDOMGENERATOR_HPP
+
+#include "mathtest/IndexedRange.hpp"
+#include "mathtest/RandomState.hpp"
+#include "mathtest/RangeBasedGenerator.hpp"
+
+#include <cstddef>
+#include <cstdint>
+#include <tuple>
+
+namespace mathtest {
+
+template <typename... InTypes>
+class [[nodiscard]] RandomGenerator final
+ : public RangeBasedGenerator<RandomGenerator<InTypes...>, InTypes...> {
+
+ friend class RangeBasedGenerator<RandomGenerator<InTypes...>, InTypes...>;
+
+ using Base = RangeBasedGenerator<RandomGenerator<InTypes...>, InTypes...>;
+
+ using Base::RangesTuple;
+ using Base::SizeToGenerate;
+
+public:
+ explicit constexpr RandomGenerator(
+ SeedTy BaseSeed, uint64_t Size,
+ const IndexedRange<InTypes> &...Ranges) noexcept
+ : Base(Ranges...), BaseSeed(BaseSeed) {
+ SizeToGenerate = Size;
+ }
+
+private:
+ static uint64_t getRandomIndex(RandomState &RNG,
+ uint64_t RangeSize) noexcept {
+ if (RangeSize == 0)
+ return 0;
+
+ const uint64_t Threshold = (-RangeSize) % RangeSize;
+
+ uint64_t RandomNumber;
+ do {
+ RandomNumber = RNG.next();
+ } while (RandomNumber < Threshold);
+
+ return RandomNumber % RangeSize;
+ }
+
+ template <typename BufferPtrsTupleType>
+ void writeInputs(uint64_t CurrentFlatIndex, uint64_t Offset,
+ BufferPtrsTupleType BufferPtrsTuple) const noexcept {
+
+ RandomState RNG(SeedTy{BaseSeed.Value ^ (CurrentFlatIndex + Offset)});
+ writeInputsImpl<0>(RNG, Offset, BufferPtrsTuple);
+ }
+
+ template <std::size_t Index, typename BufferPtrsTupleType>
+ void writeInputsImpl(RandomState &RNG, uint64_t Offset,
+ BufferPtrsTupleType BufferPtrsTuple) const noexcept {
+ if constexpr (Index < Base::NumInputs) {
+ const auto &Range = std::get<Index>(RangesTuple);
+ const auto RandomIndex = getRandomIndex(RNG, Range.getSize());
+ std::get<Index>(BufferPtrsTuple)[Offset] = Range[RandomIndex];
+
+ writeInputsImpl<Index + 1>(RNG, Offset, BufferPtrsTuple);
+ }
+ }
+
+ SeedTy BaseSeed;
+};
+} // namespace mathtest
+
+#endif // MATHTEST_RANDOMGENERATOR_HPP
diff --git a/offload/unittests/Conformance/include/mathtest/RandomState.hpp b/offload/unittests/Conformance/include/mathtest/RandomState.hpp
new file mode 100644
index 0000000000000..a09cc18c57142
--- /dev/null
+++ b/offload/unittests/Conformance/include/mathtest/RandomState.hpp
@@ -0,0 +1,49 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 RandomState class, a fast and
+/// lightweight pseudo-random number generator.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef MATHTEST_RANDOMSTATE_HPP
+#define MATHTEST_RANDOMSTATE_HPP
+
+#include <cstdint>
+
+struct SeedTy {
+ uint64_t Value;
+};
+
+class [[nodiscard]] RandomState {
+ uint64_t State;
+
+ [[nodiscard]] static uint64_t splitMix64(uint64_t X) noexcept {
+ X += 0x9E3779B97F4A7C15ULL;
+ X = (X ^ (X >> 30)) * 0xBF58476D1CE4E5B9ULL;
+ X = (X ^ (X >> 27)) * 0x94D049BB133111EBULL;
+ X = (X ^ (X >> 31));
+ return X ? X : 0x9E3779B97F4A7C15ULL;
+ }
+
+public:
+ explicit inline RandomState(SeedTy Seed) noexcept
+ : State(splitMix64(Seed.Value)) {}
+
+ [[nodiscard]] inline uint64_t next() noexcept {
+ uint64_t X = State;
+ X ^= X >> 12;
+ X ^= X << 25;
+ X ^= X >> 27;
+ State = X;
+ return X * 0x2545F4914F6CDD1DULL;
+ }
+};
+
+#endif // MATHTEST_RANDOMSTATE_HPP
diff --git a/offload/unittests/Conformance/include/mathtest/RangeBasedGenerator.hpp b/offload/unittests/Conformance/include/mathtest/RangeBasedGenerator.hpp
new file mode 100644
index 0000000000000..7e8b0889b9625
--- /dev/null
+++ b/offload/unittests/Conformance/include/mathtest/RangeBasedGenerator.hpp
@@ -0,0 +1,104 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 RangeBasedGenerator class, a base
+/// class for input generators that operate on a sequence of ranges.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef MATHTEST_RANGEBASEDGENERATOR_HPP
+#define MATHTEST_RANGEBASEDGENERATOR_HPP
+
+#include "mathtest/IndexedRange.hpp"
+#include "mathtest/InputGenerator.hpp"
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Support/Parallel.h"
+
+#include <algorithm>
+#include <array>
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <tuple>
+
+namespace mathtest {
+
+template <typename Derived, typename... InTypes>
+class [[nodiscard]] RangeBasedGenerator : public InputGenerator<InTypes...> {
+public:
+ void reset() noexcept override { NextFlatIndex = 0; }
+
+ [[nodiscard]] std::size_t
+ fill(llvm::MutableArrayRef<InTypes>... Buffers) noexcept override {
+ const std::array<std::size_t, NumInputs> BufferSizes = {Buffers.size()...};
+ const std::size_t BufferSize = BufferSizes[0];
+ assert((BufferSize != 0) && "Buffer size cannot be zero");
+ assert(std::all_of(BufferSizes.begin(), BufferSizes.end(),
+ [&](std::size_t Size) { return Size == BufferSize; }) &&
+ "All input buffers must have the same size");
+
+ if (NextFlatIndex >= SizeToGenerate)
+ return 0;
+
+ const auto BatchSize =
+ std::min<uint64_t>(BufferSize, SizeToGenerate - NextFlatIndex);
+ const auto CurrentFlatIndex = NextFlatIndex;
+ NextFlatIndex += BatchSize;
+
+ auto BufferPtrsTuple = std::make_tuple(Buffers.data()...);
+
+ llvm::parallelFor(0, BatchSize, [&](std::size_t Offset) {
+ static_cast<Derived *>(this)->writeInputs(CurrentFlatIndex, Offset,
+ BufferPtrsTuple);
+ });
+
+ return static_cast<std::size_t>(BatchSize);
+ }
+
+protected:
+ using RangesTupleType = std::tuple<IndexedRange<InTypes>...>;
+
+ static constexpr std::size_t NumInputs = sizeof...(InTypes);
+ static_assert(NumInputs > 0, "The number of inputs must be at least 1");
+
+ explicit constexpr RangeBasedGenerator(
+ const IndexedRange<InTypes> &...Ranges) noexcept
+ : RangesTuple(Ranges...) {
+ bool Overflowed = getSizeWithOverflow(Ranges..., InputSpaceSize);
+
+ assert(!Overflowed && "The input space size is too large");
+ assert((InputSpaceSize > 0) && "The input space size must be at least 1");
+ }
+
+ uint64_t SizeToGenerate = 0;
+ uint64_t InputSpaceSize = 1;
+ RangesTupleType RangesTuple;
+
+private:
+ static bool getSizeWithOverflow(const IndexedRange<InTypes> &...Ranges,
+ uint64_t &Size) noexcept {
+ Size = 1;
+ bool Overflowed = false;
+
+ auto Multiplier = [&](const uint64_t RangeSize) {
+ if (!Overflowed)
+ Overflowed = __builtin_mul_overflow(Size, RangeSize, &Size);
+ };
+
+ (Multiplier(Ranges.getSize()), ...);
+
+ return Overflowed;
+ }
+
+ uint64_t NextFlatIndex = 0;
+};
+} // namespace mathtest
+
+#endif // MATHTEST_RANGEBASEDGENERATOR_HPP
diff --git a/offload/unittests/Conformance/tests/CMakeLists.txt b/offload/unittests/Conformance/tests/CMakeLists.txt
index 8c0109ba62ce3..7d45e7a8a5865 100644
--- a/offload/unittests/Conformance/tests/CMakeLists.txt
+++ b/offload/unittests/Conformance/tests/CMakeLists.txt
@@ -19,6 +19,7 @@ add_conformance_test(exp10f Exp10fTest.cpp)
add_conformance_test(exp2f Exp2fTest.cpp)
add_conformance_test(expm1f Expm1fTest.cpp)
add_conformance_test(hypotf16 Hypotf16Test.cpp)
+add_conformance_test(log LogTest.cpp)
add_conformance_test(logf LogfTest.cpp)
add_conformance_test(log10f Log10fTest.cpp)
add_conformance_test(log1pf Log1pfTest.cpp)
diff --git a/offload/unittests/Conformance/tests/LogTest.cpp b/offload/unittests/Conformance/tests/LogTest.cpp
new file mode 100644
index 0000000000000..ae568e2c47404
--- /dev/null
+++ b/offload/unittests/Conformance/tests/LogTest.cpp
@@ -0,0 +1,66 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 conformance test of the log function.
+///
+//===----------------------------------------------------------------------===//
+
+#include "mathtest/CommandLineExtras.hpp"
+#include "mathtest/IndexedRange.hpp"
+#include "mathtest/RandomGenerator.hpp"
+#include "mathtest/RandomState.hpp"
+#include "mathtest/TestConfig.hpp"
+#include "mathtest/TestRunner.hpp"
+
+#include "llvm/ADT/StringRef.h"
+
+#include <cstdlib>
+#include <limits>
+#include <math.h>
+
+namespace {
+
+// Disambiguate the overloaded 'log' function to select the double version
+constexpr auto logd // NOLINT(readability-identifier-naming)
+ = static_cast<double (*)(double)>(log);
+} // namespace
+
+namespace mathtest {
+
+template <> struct FunctionConfig<logd> {
+ static constexpr llvm::StringRef Name = "log";
+ static constexpr llvm::StringRef KernelName = "logKernel";
+
+ // Source: The Khronos Group, The OpenCL C Specification v3.0.19, Sec. 7.4,
+ // Table 68, Khronos Registry [July 10, 2025].
+ static constexpr uint64_t UlpTolerance = 3;
+};
+} // namespace mathtest
+
+int main(int argc, const char **argv) {
+ llvm::cl::ParseCommandLineOptions(argc, argv,
+ "Conformance test of the log function");
+
+ using namespace mathtest;
+
+ uint64_t Seed = 42;
+ uint64_t Size = 1ULL << 32;
+ IndexedRange<double> Range(/*Begin=*/0.0,
+ /*End=*/std::numeric_limits<double>::infinity(),
+ /*Inclusive=*/true);
+ RandomGenerator<double> Generator(SeedTy{Seed}, Size, Range);
+
+ const auto Configs = cl::getTestConfigs();
+ const llvm::StringRef DeviceBinaryDir = DEVICE_BINARY_DIR;
+ const bool IsVerbose = cl::IsVerbose;
+
+ bool Passed = runTests<logd>(Generator, Configs, DeviceBinaryDir, IsVerbose);
+
+ return Passed ? EXIT_SUCCESS : EXIT_FAILURE;
+}
>From 2e71a0a3ad9acfff3d5ed51a0c94c2520d260b18 Mon Sep 17 00:00:00 2001
From: Leandro Augusto Lacerda Campos <leandrolcampos at yahoo.com.br>
Date: Tue, 19 Aug 2025 00:22:39 -0300
Subject: [PATCH 2/5] Apply `[[nodiscard]]` and `constexpr` consistently
---
.../include/mathtest/ExhaustiveGenerator.hpp | 3 ++-
.../include/mathtest/RandomGenerator.hpp | 4 ++--
.../include/mathtest/RandomState.hpp | 4 ++--
.../include/mathtest/RangeBasedGenerator.hpp | 22 +++++++++++++------
4 files changed, 21 insertions(+), 12 deletions(-)
diff --git a/offload/unittests/Conformance/include/mathtest/ExhaustiveGenerator.hpp b/offload/unittests/Conformance/include/mathtest/ExhaustiveGenerator.hpp
index 1bed91251a041..df87e0fcfa756 100644
--- a/offload/unittests/Conformance/include/mathtest/ExhaustiveGenerator.hpp
+++ b/offload/unittests/Conformance/include/mathtest/ExhaustiveGenerator.hpp
@@ -57,7 +57,8 @@ class [[nodiscard]] ExhaustiveGenerator final
}
private:
- constexpr IndexArrayType getNDIndex(uint64_t FlatIndex) const noexcept {
+ [[nodiscard]] constexpr IndexArrayType
+ getNDIndex(uint64_t FlatIndex) const noexcept {
IndexArrayType NDIndex;
for (std::size_t Index = 0; Index < Base::NumInputs; ++Index) {
diff --git a/offload/unittests/Conformance/include/mathtest/RandomGenerator.hpp b/offload/unittests/Conformance/include/mathtest/RandomGenerator.hpp
index 0c62370f17c7a..395775fac609c 100644
--- a/offload/unittests/Conformance/include/mathtest/RandomGenerator.hpp
+++ b/offload/unittests/Conformance/include/mathtest/RandomGenerator.hpp
@@ -46,8 +46,8 @@ class [[nodiscard]] RandomGenerator final
}
private:
- static uint64_t getRandomIndex(RandomState &RNG,
- uint64_t RangeSize) noexcept {
+ [[nodiscard]] static uint64_t getRandomIndex(RandomState &RNG,
+ uint64_t RangeSize) noexcept {
if (RangeSize == 0)
return 0;
diff --git a/offload/unittests/Conformance/include/mathtest/RandomState.hpp b/offload/unittests/Conformance/include/mathtest/RandomState.hpp
index a09cc18c57142..012573d664a3b 100644
--- a/offload/unittests/Conformance/include/mathtest/RandomState.hpp
+++ b/offload/unittests/Conformance/include/mathtest/RandomState.hpp
@@ -24,7 +24,7 @@ struct SeedTy {
class [[nodiscard]] RandomState {
uint64_t State;
- [[nodiscard]] static uint64_t splitMix64(uint64_t X) noexcept {
+ [[nodiscard]] static constexpr uint64_t splitMix64(uint64_t X) noexcept {
X += 0x9E3779B97F4A7C15ULL;
X = (X ^ (X >> 30)) * 0xBF58476D1CE4E5B9ULL;
X = (X ^ (X >> 27)) * 0x94D049BB133111EBULL;
@@ -33,7 +33,7 @@ class [[nodiscard]] RandomState {
}
public:
- explicit inline RandomState(SeedTy Seed) noexcept
+ explicit constexpr RandomState(SeedTy Seed) noexcept
: State(splitMix64(Seed.Value)) {}
[[nodiscard]] inline uint64_t next() noexcept {
diff --git a/offload/unittests/Conformance/include/mathtest/RangeBasedGenerator.hpp b/offload/unittests/Conformance/include/mathtest/RangeBasedGenerator.hpp
index 7e8b0889b9625..9ba1d26e18971 100644
--- a/offload/unittests/Conformance/include/mathtest/RangeBasedGenerator.hpp
+++ b/offload/unittests/Conformance/include/mathtest/RangeBasedGenerator.hpp
@@ -26,6 +26,7 @@
#include <cassert>
#include <cstddef>
#include <cstdint>
+#include <optional>
#include <tuple>
namespace mathtest {
@@ -71,9 +72,12 @@ class [[nodiscard]] RangeBasedGenerator : public InputGenerator<InTypes...> {
explicit constexpr RangeBasedGenerator(
const IndexedRange<InTypes> &...Ranges) noexcept
: RangesTuple(Ranges...) {
- bool Overflowed = getSizeWithOverflow(Ranges..., InputSpaceSize);
+ const auto MaybeInputSpaceSize = getInputSpaceSize(Ranges...);
+
+ assert(MaybeInputSpaceSize.has_value() &&
+ "The input space size is too large");
+ InputSpaceSize = *MaybeInputSpaceSize;
- assert(!Overflowed && "The input space size is too large");
assert((InputSpaceSize > 0) && "The input space size must be at least 1");
}
@@ -82,19 +86,23 @@ class [[nodiscard]] RangeBasedGenerator : public InputGenerator<InTypes...> {
RangesTupleType RangesTuple;
private:
- static bool getSizeWithOverflow(const IndexedRange<InTypes> &...Ranges,
- uint64_t &Size) noexcept {
- Size = 1;
+ [[nodiscard]] static constexpr std::optional<uint64_t>
+ getInputSpaceSize(const IndexedRange<InTypes> &...Ranges) noexcept {
+ uint64_t InputSpaceSize = 1;
bool Overflowed = false;
auto Multiplier = [&](const uint64_t RangeSize) {
if (!Overflowed)
- Overflowed = __builtin_mul_overflow(Size, RangeSize, &Size);
+ Overflowed =
+ __builtin_mul_overflow(InputSpaceSize, RangeSize, &InputSpaceSize);
};
(Multiplier(Ranges.getSize()), ...);
- return Overflowed;
+ if (Overflowed)
+ return std::nullopt;
+
+ return InputSpaceSize;
}
uint64_t NextFlatIndex = 0;
>From 590170b7ebaf5adedce3b1133b44eea6c183e99e Mon Sep 17 00:00:00 2001
From: Leandro Augusto Lacerda Campos <leandrolcampos at yahoo.com.br>
Date: Tue, 19 Aug 2025 08:05:51 -0300
Subject: [PATCH 3/5] Add reference for the PRNG algorithm
---
.../unittests/Conformance/include/mathtest/RandomState.hpp | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/offload/unittests/Conformance/include/mathtest/RandomState.hpp b/offload/unittests/Conformance/include/mathtest/RandomState.hpp
index 012573d664a3b..2651b02bbbd10 100644
--- a/offload/unittests/Conformance/include/mathtest/RandomState.hpp
+++ b/offload/unittests/Conformance/include/mathtest/RandomState.hpp
@@ -10,6 +10,10 @@
/// This file contains the definition of the RandomState class, a fast and
/// lightweight pseudo-random number generator.
///
+/// The implementation is based on the xorshift* generator, seeded using the
+/// SplitMix64 generator for robust initialization. For more details on the
+/// algorithm, see: https://en.wikipedia.org/wiki/Xorshift
+///
//===----------------------------------------------------------------------===//
#ifndef MATHTEST_RANDOMSTATE_HPP
>From 64be5acd57d18f6de71a0325b53c7b012f285f95 Mon Sep 17 00:00:00 2001
From: Leandro Augusto Lacerda Campos <leandrolcampos at yahoo.com.br>
Date: Tue, 19 Aug 2025 08:09:41 -0300
Subject: [PATCH 4/5] Remove `[[nodiscard]]` from the `next()` method of
`RandomState`
---
offload/unittests/Conformance/include/mathtest/RandomState.hpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/offload/unittests/Conformance/include/mathtest/RandomState.hpp b/offload/unittests/Conformance/include/mathtest/RandomState.hpp
index 2651b02bbbd10..322d53175236f 100644
--- a/offload/unittests/Conformance/include/mathtest/RandomState.hpp
+++ b/offload/unittests/Conformance/include/mathtest/RandomState.hpp
@@ -40,7 +40,7 @@ class [[nodiscard]] RandomState {
explicit constexpr RandomState(SeedTy Seed) noexcept
: State(splitMix64(Seed.Value)) {}
- [[nodiscard]] inline uint64_t next() noexcept {
+ inline uint64_t next() noexcept {
uint64_t X = State;
X ^= X >> 12;
X ^= X << 25;
>From 4f22449dd2e401ef47bd0be98f4f6b2a1ab89b01 Mon Sep 17 00:00:00 2001
From: Leandro Augusto Lacerda Campos <leandrolcampos at yahoo.com.br>
Date: Tue, 19 Aug 2025 08:46:41 -0300
Subject: [PATCH 5/5] Move `getInputSpaceSize` to `ExhaustiveGenerator`
---
.../include/mathtest/ExhaustiveGenerator.hpp | 31 ++++++++++++--
.../include/mathtest/RandomGenerator.hpp | 6 +--
.../include/mathtest/RangeBasedGenerator.hpp | 40 ++++---------------
3 files changed, 37 insertions(+), 40 deletions(-)
diff --git a/offload/unittests/Conformance/include/mathtest/ExhaustiveGenerator.hpp b/offload/unittests/Conformance/include/mathtest/ExhaustiveGenerator.hpp
index df87e0fcfa756..39c6838eecf7e 100644
--- a/offload/unittests/Conformance/include/mathtest/ExhaustiveGenerator.hpp
+++ b/offload/unittests/Conformance/include/mathtest/ExhaustiveGenerator.hpp
@@ -20,8 +20,10 @@
#include "mathtest/RangeBasedGenerator.hpp"
#include <array>
+#include <cassert>
#include <cstddef>
#include <cstdint>
+#include <optional>
#include <tuple>
namespace mathtest {
@@ -35,15 +37,19 @@ class [[nodiscard]] ExhaustiveGenerator final
using Base = RangeBasedGenerator<ExhaustiveGenerator<InTypes...>, InTypes...>;
using IndexArrayType = std::array<uint64_t, Base::NumInputs>;
- using Base::InputSpaceSize;
using Base::RangesTuple;
- using Base::SizeToGenerate;
+ using Base::Size;
public:
explicit constexpr ExhaustiveGenerator(
const IndexedRange<InTypes> &...Ranges) noexcept
: Base(Ranges...) {
- SizeToGenerate = InputSpaceSize;
+ const auto MaybeSize = getInputSpaceSize(Ranges...);
+
+ assert(MaybeSize.has_value() && "The size is too large");
+ Size = *MaybeSize;
+
+ assert((Size > 0) && "The size must be at least 1");
IndexArrayType DimSizes = {};
std::size_t DimIndex = 0;
@@ -87,6 +93,25 @@ class [[nodiscard]] ExhaustiveGenerator final
}
}
+ [[nodiscard]] static constexpr std::optional<uint64_t>
+ getInputSpaceSize(const IndexedRange<InTypes> &...Ranges) noexcept {
+ uint64_t InputSpaceSize = 1;
+ bool Overflowed = false;
+
+ auto Multiplier = [&](const uint64_t RangeSize) {
+ if (!Overflowed)
+ Overflowed =
+ __builtin_mul_overflow(InputSpaceSize, RangeSize, &InputSpaceSize);
+ };
+
+ (Multiplier(Ranges.getSize()), ...);
+
+ if (Overflowed)
+ return std::nullopt;
+
+ return InputSpaceSize;
+ }
+
IndexArrayType Strides = {};
};
} // namespace mathtest
diff --git a/offload/unittests/Conformance/include/mathtest/RandomGenerator.hpp b/offload/unittests/Conformance/include/mathtest/RandomGenerator.hpp
index 395775fac609c..436cd05f0a3d3 100644
--- a/offload/unittests/Conformance/include/mathtest/RandomGenerator.hpp
+++ b/offload/unittests/Conformance/include/mathtest/RandomGenerator.hpp
@@ -35,15 +35,13 @@ class [[nodiscard]] RandomGenerator final
using Base = RangeBasedGenerator<RandomGenerator<InTypes...>, InTypes...>;
using Base::RangesTuple;
- using Base::SizeToGenerate;
+ using Base::Size;
public:
explicit constexpr RandomGenerator(
SeedTy BaseSeed, uint64_t Size,
const IndexedRange<InTypes> &...Ranges) noexcept
- : Base(Ranges...), BaseSeed(BaseSeed) {
- SizeToGenerate = Size;
- }
+ : Base(Size, Ranges...), BaseSeed(BaseSeed) {}
private:
[[nodiscard]] static uint64_t getRandomIndex(RandomState &RNG,
diff --git a/offload/unittests/Conformance/include/mathtest/RangeBasedGenerator.hpp b/offload/unittests/Conformance/include/mathtest/RangeBasedGenerator.hpp
index 9ba1d26e18971..5e1e1139aba96 100644
--- a/offload/unittests/Conformance/include/mathtest/RangeBasedGenerator.hpp
+++ b/offload/unittests/Conformance/include/mathtest/RangeBasedGenerator.hpp
@@ -26,7 +26,6 @@
#include <cassert>
#include <cstddef>
#include <cstdint>
-#include <optional>
#include <tuple>
namespace mathtest {
@@ -45,11 +44,10 @@ class [[nodiscard]] RangeBasedGenerator : public InputGenerator<InTypes...> {
[&](std::size_t Size) { return Size == BufferSize; }) &&
"All input buffers must have the same size");
- if (NextFlatIndex >= SizeToGenerate)
+ if (NextFlatIndex >= Size)
return 0;
- const auto BatchSize =
- std::min<uint64_t>(BufferSize, SizeToGenerate - NextFlatIndex);
+ const auto BatchSize = std::min<uint64_t>(BufferSize, Size - NextFlatIndex);
const auto CurrentFlatIndex = NextFlatIndex;
NextFlatIndex += BatchSize;
@@ -71,40 +69,16 @@ class [[nodiscard]] RangeBasedGenerator : public InputGenerator<InTypes...> {
explicit constexpr RangeBasedGenerator(
const IndexedRange<InTypes> &...Ranges) noexcept
- : RangesTuple(Ranges...) {
- const auto MaybeInputSpaceSize = getInputSpaceSize(Ranges...);
+ : RangesTuple(Ranges...) {}
- assert(MaybeInputSpaceSize.has_value() &&
- "The input space size is too large");
- InputSpaceSize = *MaybeInputSpaceSize;
-
- assert((InputSpaceSize > 0) && "The input space size must be at least 1");
- }
+ explicit constexpr RangeBasedGenerator(
+ uint64_t Size, const IndexedRange<InTypes> &...Ranges) noexcept
+ : RangesTuple(Ranges...), Size(Size) {}
- uint64_t SizeToGenerate = 0;
- uint64_t InputSpaceSize = 1;
RangesTupleType RangesTuple;
+ uint64_t Size = 0;
private:
- [[nodiscard]] static constexpr std::optional<uint64_t>
- getInputSpaceSize(const IndexedRange<InTypes> &...Ranges) noexcept {
- uint64_t InputSpaceSize = 1;
- bool Overflowed = false;
-
- auto Multiplier = [&](const uint64_t RangeSize) {
- if (!Overflowed)
- Overflowed =
- __builtin_mul_overflow(InputSpaceSize, RangeSize, &InputSpaceSize);
- };
-
- (Multiplier(Ranges.getSize()), ...);
-
- if (Overflowed)
- return std::nullopt;
-
- return InputSpaceSize;
- }
-
uint64_t NextFlatIndex = 0;
};
} // namespace mathtest
More information about the llvm-commits
mailing list