Skip to content

Commit eed5f06

Browse files
[Offload][Conformance] Add randomized tests for single-precision bivariate math functions (llvm#154663)
This patch adds a new set of randomized conformance tests for single-precision bivariate math functions. The functions included in this set were selected based on the following criteria: - An implementation exists in `libc/src/math/generic` (i.e., it is not just a wrapper around a compiler built-in). - The corresponding LLVM CPU libm implementation is correctly rounded. - The function is listed in Table 65 of the OpenCL C Specification v3.0.19.
1 parent e20fa4f commit eed5f06

File tree

8 files changed

+276
-0
lines changed

8 files changed

+276
-0
lines changed

offload/unittests/Conformance/device_code/CUDAMath.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ using namespace kernels;
2626
// Helpers
2727
//===----------------------------------------------------------------------===//
2828

29+
static inline float powfRoundedExponent(float Base, float Exponent) {
30+
return __nv_powf(Base, __nv_roundf(Exponent));
31+
}
32+
2933
static inline float sincosfSin(float X) {
3034
float SinX, CosX;
3135
__nv_sincosf(X, &SinX, &CosX);
@@ -69,6 +73,11 @@ __gpu_kernel void atanfKernel(const float *X, float *Out,
6973
runKernelBody<__nv_atanf>(NumElements, Out, X);
7074
}
7175

76+
__gpu_kernel void atan2fKernel(const float *X, const float *Y, float *Out,
77+
size_t NumElements) noexcept {
78+
runKernelBody<__nv_atan2f>(NumElements, Out, X, Y);
79+
}
80+
7281
__gpu_kernel void atanhfKernel(const float *X, float *Out,
7382
size_t NumElements) noexcept {
7483
runKernelBody<__nv_atanhf>(NumElements, Out, X);
@@ -119,6 +128,11 @@ __gpu_kernel void expm1fKernel(const float *X, float *Out,
119128
runKernelBody<__nv_expm1f>(NumElements, Out, X);
120129
}
121130

131+
__gpu_kernel void hypotfKernel(const float *X, float *Y, float *Out,
132+
size_t NumElements) noexcept {
133+
runKernelBody<__nv_hypotf>(NumElements, Out, X, Y);
134+
}
135+
122136
__gpu_kernel void logKernel(const double *X, double *Out,
123137
size_t NumElements) noexcept {
124138
runKernelBody<__nv_log>(NumElements, Out, X);
@@ -144,6 +158,17 @@ __gpu_kernel void log2fKernel(const float *X, float *Out,
144158
runKernelBody<__nv_log2f>(NumElements, Out, X);
145159
}
146160

161+
__gpu_kernel void powfKernel(const float *X, float *Y, float *Out,
162+
size_t NumElements) noexcept {
163+
runKernelBody<__nv_powf>(NumElements, Out, X, Y);
164+
}
165+
166+
__gpu_kernel void powfRoundedExponentKernel(const float *X, float *Y,
167+
float *Out,
168+
size_t NumElements) noexcept {
169+
runKernelBody<powfRoundedExponent>(NumElements, Out, X, Y);
170+
}
171+
147172
__gpu_kernel void sinfKernel(const float *X, float *Out,
148173
size_t NumElements) noexcept {
149174
runKernelBody<__nv_sinf>(NumElements, Out, X);

offload/unittests/Conformance/device_code/DeviceAPIs.hpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ float __nv_acoshf(float);
5353
float __nv_asinf(float);
5454
float __nv_asinhf(float);
5555
float __nv_atanf(float);
56+
float __nv_atan2f(float, float);
5657
float __nv_atanhf(float);
5758
float __nv_cbrtf(float);
5859
float __nv_cosf(float);
@@ -63,11 +64,14 @@ float __nv_expf(float);
6364
float __nv_exp10f(float);
6465
float __nv_exp2f(float);
6566
float __nv_expm1f(float);
67+
float __nv_hypotf(float, float);
6668
double __nv_log(double);
6769
float __nv_logf(float);
6870
float __nv_log10f(float);
6971
float __nv_log1pf(float);
7072
float __nv_log2f(float);
73+
float __nv_powf(float, float);
74+
float __nv_roundf(float);
7175
float __nv_sinf(float);
7276
void __nv_sincosf(float, float *, float *);
7377
float __nv_sinhf(float);
@@ -87,6 +91,7 @@ float __ocml_acosh_f32(float);
8791
float __ocml_asin_f32(float);
8892
float __ocml_asinh_f32(float);
8993
float __ocml_atan_f32(float);
94+
float __ocml_atan2_f32(float, float);
9095
float __ocml_atanh_f32(float);
9196
float __ocml_cbrt_f32(float);
9297
float __ocml_cos_f32(float);
@@ -97,11 +102,14 @@ float __ocml_exp_f32(float);
97102
float __ocml_exp10_f32(float);
98103
float __ocml_exp2_f32(float);
99104
float __ocml_expm1_f32(float);
105+
float __ocml_hypot_f32(float, float);
100106
double __ocml_log_f64(double);
101107
float __ocml_log_f32(float);
102108
float __ocml_log10_f32(float);
103109
float __ocml_log1p_f32(float);
104110
float __ocml_log2_f32(float);
111+
float __ocml_pow_f32(float, float);
112+
float __ocml_round_f32(float);
105113
float __ocml_sin_f32(float);
106114
float __ocml_sincos_f32(float, float *);
107115
float __ocml_sinh_f32(float);

offload/unittests/Conformance/device_code/HIPMath.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ using namespace kernels;
2626
// Helpers
2727
//===----------------------------------------------------------------------===//
2828

29+
static inline float powfRoundedExponent(float Base, float Exponent) {
30+
return __ocml_pow_f32(Base, __ocml_round_f32(Exponent));
31+
}
32+
2933
static inline float sincosfSin(float X) {
3034
float CosX;
3135
float SinX = __ocml_sincos_f32(X, &CosX);
@@ -69,6 +73,11 @@ __gpu_kernel void atanfKernel(const float *X, float *Out,
6973
runKernelBody<__ocml_atan_f32>(NumElements, Out, X);
7074
}
7175

76+
__gpu_kernel void atan2fKernel(const float *X, const float *Y, float *Out,
77+
size_t NumElements) noexcept {
78+
runKernelBody<__ocml_atan2_f32>(NumElements, Out, X, Y);
79+
}
80+
7281
__gpu_kernel void atanhfKernel(const float *X, float *Out,
7382
size_t NumElements) noexcept {
7483
runKernelBody<__ocml_atanh_f32>(NumElements, Out, X);
@@ -119,6 +128,11 @@ __gpu_kernel void expm1fKernel(const float *X, float *Out,
119128
runKernelBody<__ocml_expm1_f32>(NumElements, Out, X);
120129
}
121130

131+
__gpu_kernel void hypotfKernel(const float *X, float *Y, float *Out,
132+
size_t NumElements) noexcept {
133+
runKernelBody<__ocml_hypot_f32>(NumElements, Out, X, Y);
134+
}
135+
122136
__gpu_kernel void logKernel(const double *X, double *Out,
123137
size_t NumElements) noexcept {
124138
runKernelBody<__ocml_log_f64>(NumElements, Out, X);
@@ -144,6 +158,17 @@ __gpu_kernel void log2fKernel(const float *X, float *Out,
144158
runKernelBody<__ocml_log2_f32>(NumElements, Out, X);
145159
}
146160

161+
__gpu_kernel void powfKernel(const float *X, float *Y, float *Out,
162+
size_t NumElements) noexcept {
163+
runKernelBody<__ocml_pow_f32>(NumElements, Out, X, Y);
164+
}
165+
166+
__gpu_kernel void powfRoundedExponentKernel(const float *X, float *Y,
167+
float *Out,
168+
size_t NumElements) noexcept {
169+
runKernelBody<powfRoundedExponent>(NumElements, Out, X, Y);
170+
}
171+
147172
__gpu_kernel void sinfKernel(const float *X, float *Out,
148173
size_t NumElements) noexcept {
149174
runKernelBody<__ocml_sin_f32>(NumElements, Out, X);

offload/unittests/Conformance/device_code/LLVMLibm.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ using namespace kernels;
2525
// Helpers
2626
//===----------------------------------------------------------------------===//
2727

28+
static inline float powfRoundedExponent(float Base, float Exponent) {
29+
return powf(Base, roundf(Exponent));
30+
}
31+
2832
static inline float sincosfSin(float X) {
2933
float SinX, CosX;
3034
sincosf(X, &SinX, &CosX);
@@ -68,6 +72,11 @@ __gpu_kernel void atanfKernel(const float *X, float *Out,
6872
runKernelBody<atanf>(NumElements, Out, X);
6973
}
7074

75+
__gpu_kernel void atan2fKernel(const float *X, const float *Y, float *Out,
76+
size_t NumElements) noexcept {
77+
runKernelBody<atan2f>(NumElements, Out, X, Y);
78+
}
79+
7180
__gpu_kernel void atanhfKernel(const float *X, float *Out,
7281
size_t NumElements) noexcept {
7382
runKernelBody<atanhf>(NumElements, Out, X);
@@ -118,6 +127,11 @@ __gpu_kernel void expm1fKernel(const float *X, float *Out,
118127
runKernelBody<expm1f>(NumElements, Out, X);
119128
}
120129

130+
__gpu_kernel void hypotfKernel(const float *X, float *Y, float *Out,
131+
size_t NumElements) noexcept {
132+
runKernelBody<hypotf>(NumElements, Out, X, Y);
133+
}
134+
121135
__gpu_kernel void hypotf16Kernel(const float16 *X, float16 *Y, float16 *Out,
122136
size_t NumElements) noexcept {
123137
runKernelBody<hypotf16>(NumElements, Out, X, Y);
@@ -148,6 +162,17 @@ __gpu_kernel void log2fKernel(const float *X, float *Out,
148162
runKernelBody<log2f>(NumElements, Out, X);
149163
}
150164

165+
__gpu_kernel void powfKernel(const float *X, float *Y, float *Out,
166+
size_t NumElements) noexcept {
167+
runKernelBody<powf>(NumElements, Out, X, Y);
168+
}
169+
170+
__gpu_kernel void powfRoundedExponentKernel(const float *X, float *Y,
171+
float *Out,
172+
size_t NumElements) noexcept {
173+
runKernelBody<powfRoundedExponent>(NumElements, Out, X, Y);
174+
}
175+
151176
__gpu_kernel void sinfKernel(const float *X, float *Out,
152177
size_t NumElements) noexcept {
153178
runKernelBody<sinf>(NumElements, Out, X);
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
///
9+
/// \file
10+
/// This file contains the conformance test of the atan2f function.
11+
///
12+
//===----------------------------------------------------------------------===//
13+
14+
#include "mathtest/CommandLineExtras.hpp"
15+
#include "mathtest/IndexedRange.hpp"
16+
#include "mathtest/RandomGenerator.hpp"
17+
#include "mathtest/RandomState.hpp"
18+
#include "mathtest/TestConfig.hpp"
19+
#include "mathtest/TestRunner.hpp"
20+
21+
#include "llvm/ADT/StringRef.h"
22+
23+
#include <cstdlib>
24+
#include <math.h>
25+
26+
namespace mathtest {
27+
28+
template <> struct FunctionConfig<atan2f> {
29+
static constexpr llvm::StringRef Name = "atan2f";
30+
static constexpr llvm::StringRef KernelName = "atan2fKernel";
31+
32+
// Source: The Khronos Group, The OpenCL C Specification v3.0.19, Sec. 7.4,
33+
// Table 65, Khronos Registry [July 10, 2025].
34+
static constexpr uint64_t UlpTolerance = 6;
35+
};
36+
} // namespace mathtest
37+
38+
int main(int argc, const char **argv) {
39+
llvm::cl::ParseCommandLineOptions(argc, argv,
40+
"Conformance test of the atan2f function");
41+
42+
using namespace mathtest;
43+
44+
uint64_t Seed = 42;
45+
uint64_t Size = 1ULL << 32;
46+
IndexedRange<float> RangeX;
47+
IndexedRange<float> RangeY;
48+
RandomGenerator<float, float> Generator(SeedTy{Seed}, Size, RangeX, RangeY);
49+
50+
const auto Configs = cl::getTestConfigs();
51+
const llvm::StringRef DeviceBinaryDir = DEVICE_BINARY_DIR;
52+
const bool IsVerbose = cl::IsVerbose;
53+
54+
bool Passed =
55+
runTests<atan2f>(Generator, Configs, DeviceBinaryDir, IsVerbose);
56+
57+
return Passed ? EXIT_SUCCESS : EXIT_FAILURE;
58+
}

offload/unittests/Conformance/tests/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ add_conformance_test(acoshf AcoshfTest.cpp)
88
add_conformance_test(asinf AsinfTest.cpp)
99
add_conformance_test(asinhf AsinhfTest.cpp)
1010
add_conformance_test(atanf AtanfTest.cpp)
11+
add_conformance_test(atan2f Atan2fTest.cpp)
1112
add_conformance_test(atanhf AtanhfTest.cpp)
1213
add_conformance_test(cbrtf CbrtfTest.cpp)
1314
add_conformance_test(cosf CosfTest.cpp)
@@ -18,12 +19,14 @@ add_conformance_test(expf ExpfTest.cpp)
1819
add_conformance_test(exp10f Exp10fTest.cpp)
1920
add_conformance_test(exp2f Exp2fTest.cpp)
2021
add_conformance_test(expm1f Expm1fTest.cpp)
22+
add_conformance_test(hypotf HypotfTest.cpp)
2123
add_conformance_test(hypotf16 Hypotf16Test.cpp)
2224
add_conformance_test(log LogTest.cpp)
2325
add_conformance_test(logf LogfTest.cpp)
2426
add_conformance_test(log10f Log10fTest.cpp)
2527
add_conformance_test(log1pf Log1pfTest.cpp)
2628
add_conformance_test(log2f Log2fTest.cpp)
29+
add_conformance_test(powf PowfTest.cpp)
2730
add_conformance_test(sinf SinfTest.cpp)
2831
add_conformance_test(sincosf SincosfTest.cpp)
2932
add_conformance_test(sinhf SinhfTest.cpp)
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
///
9+
/// \file
10+
/// This file contains the conformance test of the hypotf function.
11+
///
12+
//===----------------------------------------------------------------------===//
13+
14+
#include "mathtest/CommandLineExtras.hpp"
15+
#include "mathtest/IndexedRange.hpp"
16+
#include "mathtest/RandomGenerator.hpp"
17+
#include "mathtest/RandomState.hpp"
18+
#include "mathtest/TestConfig.hpp"
19+
#include "mathtest/TestRunner.hpp"
20+
21+
#include "llvm/ADT/StringRef.h"
22+
23+
#include <cstdlib>
24+
#include <math.h>
25+
26+
namespace mathtest {
27+
28+
template <> struct FunctionConfig<hypotf> {
29+
static constexpr llvm::StringRef Name = "hypotf";
30+
static constexpr llvm::StringRef KernelName = "hypotfKernel";
31+
32+
// Source: The Khronos Group, The OpenCL C Specification v3.0.19, Sec. 7.4,
33+
// Table 65, Khronos Registry [July 10, 2025].
34+
static constexpr uint64_t UlpTolerance = 4;
35+
};
36+
} // namespace mathtest
37+
38+
int main(int argc, const char **argv) {
39+
llvm::cl::ParseCommandLineOptions(argc, argv,
40+
"Conformance test of the hypotf function");
41+
42+
using namespace mathtest;
43+
44+
uint64_t Seed = 42;
45+
uint64_t Size = 1ULL << 32;
46+
IndexedRange<float> RangeX;
47+
IndexedRange<float> RangeY;
48+
RandomGenerator<float, float> Generator(SeedTy{Seed}, Size, RangeX, RangeY);
49+
50+
const auto Configs = cl::getTestConfigs();
51+
const llvm::StringRef DeviceBinaryDir = DEVICE_BINARY_DIR;
52+
const bool IsVerbose = cl::IsVerbose;
53+
54+
bool Passed =
55+
runTests<hypotf>(Generator, Configs, DeviceBinaryDir, IsVerbose);
56+
57+
return Passed ? EXIT_SUCCESS : EXIT_FAILURE;
58+
}

0 commit comments

Comments
 (0)