[llvm] [Offload][Conformance] Add randomized tests for double-precision math functions (PR #155003)

Leandro Lacerda via llvm-commits llvm-commits at lists.llvm.org
Fri Aug 22 11:14:22 PDT 2025


https://github.com/leandrolcampos created https://github.com/llvm/llvm-project/pull/155003

This patch adds a set of randomized conformance tests for double-precision 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 68 of the OpenCL C Specification v3.0.19.

>From a393a77cfefcbced284c0523fceec7db77b6d220 Mon Sep 17 00:00:00 2001
From: Leandro Augusto Lacerda Campos <leandrolcampos at yahoo.com.br>
Date: Fri, 22 Aug 2025 15:11:01 -0300
Subject: [PATCH] Add randomized tests for double-precision math functions

---
 .../Conformance/device_code/CUDAMath.cpp      | 94 +++++++++++++++++-
 .../Conformance/device_code/DeviceAPIs.hpp    | 30 ++++++
 .../Conformance/device_code/HIPMath.cpp       | 94 +++++++++++++++++-
 .../Conformance/device_code/LLVMLibm.cpp      | 96 ++++++++++++++++++-
 .../unittests/Conformance/tests/AcosTest.cpp  | 63 ++++++++++++
 .../unittests/Conformance/tests/AsinTest.cpp  | 63 ++++++++++++
 .../Conformance/tests/CMakeLists.txt          | 15 +++
 .../unittests/Conformance/tests/CbrtTest.cpp  | 63 ++++++++++++
 .../unittests/Conformance/tests/CosTest.cpp   | 63 ++++++++++++
 .../unittests/Conformance/tests/Exp10Test.cpp | 64 +++++++++++++
 .../unittests/Conformance/tests/Exp2Test.cpp  | 63 ++++++++++++
 .../unittests/Conformance/tests/ExpTest.cpp   | 63 ++++++++++++
 .../unittests/Conformance/tests/Expm1Test.cpp | 64 +++++++++++++
 .../unittests/Conformance/tests/HypotTest.cpp | 65 +++++++++++++
 .../unittests/Conformance/tests/Log10Test.cpp | 67 +++++++++++++
 .../unittests/Conformance/tests/Log1pTest.cpp | 67 +++++++++++++
 .../unittests/Conformance/tests/Log2Test.cpp  | 66 +++++++++++++
 .../unittests/Conformance/tests/SinTest.cpp   | 63 ++++++++++++
 .../Conformance/tests/SincosTest.cpp          | 80 ++++++++++++++++
 .../unittests/Conformance/tests/TanTest.cpp   | 63 ++++++++++++
 20 files changed, 1302 insertions(+), 4 deletions(-)
 create mode 100644 offload/unittests/Conformance/tests/AcosTest.cpp
 create mode 100644 offload/unittests/Conformance/tests/AsinTest.cpp
 create mode 100644 offload/unittests/Conformance/tests/CbrtTest.cpp
 create mode 100644 offload/unittests/Conformance/tests/CosTest.cpp
 create mode 100644 offload/unittests/Conformance/tests/Exp10Test.cpp
 create mode 100644 offload/unittests/Conformance/tests/Exp2Test.cpp
 create mode 100644 offload/unittests/Conformance/tests/ExpTest.cpp
 create mode 100644 offload/unittests/Conformance/tests/Expm1Test.cpp
 create mode 100644 offload/unittests/Conformance/tests/HypotTest.cpp
 create mode 100644 offload/unittests/Conformance/tests/Log10Test.cpp
 create mode 100644 offload/unittests/Conformance/tests/Log1pTest.cpp
 create mode 100644 offload/unittests/Conformance/tests/Log2Test.cpp
 create mode 100644 offload/unittests/Conformance/tests/SinTest.cpp
 create mode 100644 offload/unittests/Conformance/tests/SincosTest.cpp
 create mode 100644 offload/unittests/Conformance/tests/TanTest.cpp

diff --git a/offload/unittests/Conformance/device_code/CUDAMath.cpp b/offload/unittests/Conformance/device_code/CUDAMath.cpp
index d47607a7c862e..d80660b2e3c74 100644
--- a/offload/unittests/Conformance/device_code/CUDAMath.cpp
+++ b/offload/unittests/Conformance/device_code/CUDAMath.cpp
@@ -30,6 +30,18 @@ static inline float powfRoundedExponent(float Base, float Exponent) {
   return __nv_powf(Base, __nv_roundf(Exponent));
 }
 
+static inline double sincosSin(double X) {
+  double SinX, CosX;
+  __nv_sincos(X, &SinX, &CosX);
+  return SinX;
+}
+
+static inline double sincosCos(double X) {
+  double SinX, CosX;
+  __nv_sincos(X, &SinX, &CosX);
+  return CosX;
+}
+
 static inline float sincosfSin(float X) {
   float SinX, CosX;
   __nv_sincosf(X, &SinX, &CosX);
@@ -48,6 +60,11 @@ static inline float sincosfCos(float X) {
 
 extern "C" {
 
+__gpu_kernel void acosKernel(const double *X, double *Out,
+                             size_t NumElements) noexcept {
+  runKernelBody<__nv_acos>(NumElements, Out, X);
+}
+
 __gpu_kernel void acosfKernel(const float *X, float *Out,
                               size_t NumElements) noexcept {
   runKernelBody<__nv_acosf>(NumElements, Out, X);
@@ -58,6 +75,11 @@ __gpu_kernel void acoshfKernel(const float *X, float *Out,
   runKernelBody<__nv_acoshf>(NumElements, Out, X);
 }
 
+__gpu_kernel void asinKernel(const double *X, double *Out,
+                             size_t NumElements) noexcept {
+  runKernelBody<__nv_asin>(NumElements, Out, X);
+}
+
 __gpu_kernel void asinfKernel(const float *X, float *Out,
                               size_t NumElements) noexcept {
   runKernelBody<__nv_asinf>(NumElements, Out, X);
@@ -83,11 +105,21 @@ __gpu_kernel void atanhfKernel(const float *X, float *Out,
   runKernelBody<__nv_atanhf>(NumElements, Out, X);
 }
 
+__gpu_kernel void cbrtKernel(const double *X, double *Out,
+                             size_t NumElements) noexcept {
+  runKernelBody<__nv_cbrt>(NumElements, Out, X);
+}
+
 __gpu_kernel void cbrtfKernel(const float *X, float *Out,
                               size_t NumElements) noexcept {
   runKernelBody<__nv_cbrtf>(NumElements, Out, X);
 }
 
+__gpu_kernel void cosKernel(const double *X, double *Out,
+                            size_t NumElements) noexcept {
+  runKernelBody<__nv_cos>(NumElements, Out, X);
+}
+
 __gpu_kernel void cosfKernel(const float *X, float *Out,
                              size_t NumElements) noexcept {
   runKernelBody<__nv_cosf>(NumElements, Out, X);
@@ -108,27 +140,52 @@ __gpu_kernel void erffKernel(const float *X, float *Out,
   runKernelBody<__nv_erff>(NumElements, Out, X);
 }
 
+__gpu_kernel void expKernel(const double *X, double *Out,
+                            size_t NumElements) noexcept {
+  runKernelBody<__nv_exp>(NumElements, Out, X);
+}
+
 __gpu_kernel void expfKernel(const float *X, float *Out,
                              size_t NumElements) noexcept {
   runKernelBody<__nv_expf>(NumElements, Out, X);
 }
 
+__gpu_kernel void exp10Kernel(const double *X, double *Out,
+                              size_t NumElements) noexcept {
+  runKernelBody<__nv_exp10>(NumElements, Out, X);
+}
+
 __gpu_kernel void exp10fKernel(const float *X, float *Out,
                                size_t NumElements) noexcept {
   runKernelBody<__nv_exp10f>(NumElements, Out, X);
 }
 
+__gpu_kernel void exp2Kernel(const double *X, double *Out,
+                             size_t NumElements) noexcept {
+  runKernelBody<__nv_exp2>(NumElements, Out, X);
+}
+
 __gpu_kernel void exp2fKernel(const float *X, float *Out,
                               size_t NumElements) noexcept {
   runKernelBody<__nv_exp2f>(NumElements, Out, X);
 }
 
+__gpu_kernel void expm1Kernel(const double *X, double *Out,
+                              size_t NumElements) noexcept {
+  runKernelBody<__nv_expm1>(NumElements, Out, X);
+}
+
 __gpu_kernel void expm1fKernel(const float *X, float *Out,
                                size_t NumElements) noexcept {
   runKernelBody<__nv_expm1f>(NumElements, Out, X);
 }
 
-__gpu_kernel void hypotfKernel(const float *X, float *Y, float *Out,
+__gpu_kernel void hypotKernel(const double *X, const double *Y, double *Out,
+                              size_t NumElements) noexcept {
+  runKernelBody<__nv_hypot>(NumElements, Out, X, Y);
+}
+
+__gpu_kernel void hypotfKernel(const float *X, const float *Y, float *Out,
                                size_t NumElements) noexcept {
   runKernelBody<__nv_hypotf>(NumElements, Out, X, Y);
 }
@@ -143,16 +200,31 @@ __gpu_kernel void logfKernel(const float *X, float *Out,
   runKernelBody<__nv_logf>(NumElements, Out, X);
 }
 
+__gpu_kernel void log10Kernel(const double *X, double *Out,
+                              size_t NumElements) noexcept {
+  runKernelBody<__nv_log10>(NumElements, Out, X);
+}
+
 __gpu_kernel void log10fKernel(const float *X, float *Out,
                                size_t NumElements) noexcept {
   runKernelBody<__nv_log10f>(NumElements, Out, X);
 }
 
+__gpu_kernel void log1pKernel(const double *X, double *Out,
+                              size_t NumElements) noexcept {
+  runKernelBody<__nv_log1p>(NumElements, Out, X);
+}
+
 __gpu_kernel void log1pfKernel(const float *X, float *Out,
                                size_t NumElements) noexcept {
   runKernelBody<__nv_log1pf>(NumElements, Out, X);
 }
 
+__gpu_kernel void log2Kernel(const double *X, double *Out,
+                             size_t NumElements) noexcept {
+  runKernelBody<__nv_log2>(NumElements, Out, X);
+}
+
 __gpu_kernel void log2fKernel(const float *X, float *Out,
                               size_t NumElements) noexcept {
   runKernelBody<__nv_log2f>(NumElements, Out, X);
@@ -169,11 +241,26 @@ __gpu_kernel void powfRoundedExponentKernel(const float *X, float *Y,
   runKernelBody<powfRoundedExponent>(NumElements, Out, X, Y);
 }
 
+__gpu_kernel void sinKernel(const double *X, double *Out,
+                            size_t NumElements) noexcept {
+  runKernelBody<__nv_sin>(NumElements, Out, X);
+}
+
 __gpu_kernel void sinfKernel(const float *X, float *Out,
                              size_t NumElements) noexcept {
   runKernelBody<__nv_sinf>(NumElements, Out, X);
 }
 
+__gpu_kernel void sincosSinKernel(const double *X, double *Out,
+                                  size_t NumElements) noexcept {
+  runKernelBody<sincosSin>(NumElements, Out, X);
+}
+
+__gpu_kernel void sincosCosKernel(const double *X, double *Out,
+                                  size_t NumElements) noexcept {
+  runKernelBody<sincosCos>(NumElements, Out, X);
+}
+
 __gpu_kernel void sincosfSinKernel(const float *X, float *Out,
                                    size_t NumElements) noexcept {
   runKernelBody<sincosfSin>(NumElements, Out, X);
@@ -194,6 +281,11 @@ __gpu_kernel void sinpifKernel(const float *X, float *Out,
   runKernelBody<__nv_sinpif>(NumElements, Out, X);
 }
 
+__gpu_kernel void tanKernel(const double *X, double *Out,
+                            size_t NumElements) noexcept {
+  runKernelBody<__nv_tan>(NumElements, Out, X);
+}
+
 __gpu_kernel void tanfKernel(const float *X, float *Out,
                              size_t NumElements) noexcept {
   runKernelBody<__nv_tanf>(NumElements, Out, X);
diff --git a/offload/unittests/Conformance/device_code/DeviceAPIs.hpp b/offload/unittests/Conformance/device_code/DeviceAPIs.hpp
index 6504fff125640..32f21991d9ec3 100644
--- a/offload/unittests/Conformance/device_code/DeviceAPIs.hpp
+++ b/offload/unittests/Conformance/device_code/DeviceAPIs.hpp
@@ -48,34 +48,49 @@ extern const inline uint32_t __oclc_ISA_version = 9000;
 
 extern "C" {
 
+double __nv_acos(double);
 float __nv_acosf(float);
 float __nv_acoshf(float);
+double __nv_asin(double);
 float __nv_asinf(float);
 float __nv_asinhf(float);
 float __nv_atanf(float);
 float __nv_atan2f(float, float);
 float __nv_atanhf(float);
+double __nv_cbrt(double);
 float __nv_cbrtf(float);
+double __nv_cos(double);
 float __nv_cosf(float);
 float __nv_coshf(float);
 float __nv_cospif(float);
 float __nv_erff(float);
+double __nv_exp(double);
 float __nv_expf(float);
+double __nv_exp10(double);
 float __nv_exp10f(float);
+double __nv_exp2(double);
 float __nv_exp2f(float);
+double __nv_expm1(double);
 float __nv_expm1f(float);
+double __nv_hypot(double, double);
 float __nv_hypotf(float, float);
 double __nv_log(double);
 float __nv_logf(float);
+double __nv_log10(double);
 float __nv_log10f(float);
+double __nv_log1p(double);
 float __nv_log1pf(float);
+double __nv_log2(double);
 float __nv_log2f(float);
 float __nv_powf(float, float);
 float __nv_roundf(float);
+double __nv_sin(double);
 float __nv_sinf(float);
+void __nv_sincos(double, double *, double *);
 void __nv_sincosf(float, float *, float *);
 float __nv_sinhf(float);
 float __nv_sinpif(float);
+double __nv_tan(double);
 float __nv_tanf(float);
 float __nv_tanhf(float);
 } // extern "C"
@@ -86,34 +101,49 @@ float __nv_tanhf(float);
 
 extern "C" {
 
+double __ocml_acos_f64(double);
 float __ocml_acos_f32(float);
 float __ocml_acosh_f32(float);
+double __ocml_asin_f64(double);
 float __ocml_asin_f32(float);
 float __ocml_asinh_f32(float);
 float __ocml_atan_f32(float);
 float __ocml_atan2_f32(float, float);
 float __ocml_atanh_f32(float);
+double __ocml_cbrt_f64(double);
 float __ocml_cbrt_f32(float);
+double __ocml_cos_f64(double);
 float __ocml_cos_f32(float);
 float __ocml_cosh_f32(float);
 float __ocml_cospi_f32(float);
 float __ocml_erf_f32(float);
+double __ocml_exp_f64(double);
 float __ocml_exp_f32(float);
+double __ocml_exp10_f64(double);
 float __ocml_exp10_f32(float);
+double __ocml_exp2_f64(double);
 float __ocml_exp2_f32(float);
+double __ocml_expm1_f64(double);
 float __ocml_expm1_f32(float);
+double __ocml_hypot_f64(double, double);
 float __ocml_hypot_f32(float, float);
 double __ocml_log_f64(double);
 float __ocml_log_f32(float);
+double __ocml_log10_f64(double);
 float __ocml_log10_f32(float);
+double __ocml_log1p_f64(double);
 float __ocml_log1p_f32(float);
+double __ocml_log2_f64(double);
 float __ocml_log2_f32(float);
 float __ocml_pow_f32(float, float);
 float __ocml_round_f32(float);
+double __ocml_sin_f64(double);
 float __ocml_sin_f32(float);
+double __ocml_sincos_f64(double, double *);
 float __ocml_sincos_f32(float, float *);
 float __ocml_sinh_f32(float);
 float __ocml_sinpi_f32(float);
+double __ocml_tan_f64(double);
 float __ocml_tan_f32(float);
 float __ocml_tanh_f32(float);
 } // extern "C"
diff --git a/offload/unittests/Conformance/device_code/HIPMath.cpp b/offload/unittests/Conformance/device_code/HIPMath.cpp
index 74a7f5c3a9492..71dea4c8d2656 100644
--- a/offload/unittests/Conformance/device_code/HIPMath.cpp
+++ b/offload/unittests/Conformance/device_code/HIPMath.cpp
@@ -30,6 +30,18 @@ static inline float powfRoundedExponent(float Base, float Exponent) {
   return __ocml_pow_f32(Base, __ocml_round_f32(Exponent));
 }
 
+static inline double sincosSin(double X) {
+  double CosX;
+  double SinX = __ocml_sincos_f64(X, &CosX);
+  return SinX;
+}
+
+static inline double sincosCos(double X) {
+  double CosX;
+  double SinX = __ocml_sincos_f64(X, &CosX);
+  return CosX;
+}
+
 static inline float sincosfSin(float X) {
   float CosX;
   float SinX = __ocml_sincos_f32(X, &CosX);
@@ -48,6 +60,11 @@ static inline float sincosfCos(float X) {
 
 extern "C" {
 
+__gpu_kernel void acosKernel(const double *X, double *Out,
+                             size_t NumElements) noexcept {
+  runKernelBody<__ocml_acos_f64>(NumElements, Out, X);
+}
+
 __gpu_kernel void acosfKernel(const float *X, float *Out,
                               size_t NumElements) noexcept {
   runKernelBody<__ocml_acos_f32>(NumElements, Out, X);
@@ -58,6 +75,11 @@ __gpu_kernel void acoshfKernel(const float *X, float *Out,
   runKernelBody<__ocml_acosh_f32>(NumElements, Out, X);
 }
 
+__gpu_kernel void asinKernel(const double *X, double *Out,
+                             size_t NumElements) noexcept {
+  runKernelBody<__ocml_asin_f64>(NumElements, Out, X);
+}
+
 __gpu_kernel void asinfKernel(const float *X, float *Out,
                               size_t NumElements) noexcept {
   runKernelBody<__ocml_asin_f32>(NumElements, Out, X);
@@ -83,11 +105,21 @@ __gpu_kernel void atanhfKernel(const float *X, float *Out,
   runKernelBody<__ocml_atanh_f32>(NumElements, Out, X);
 }
 
+__gpu_kernel void cbrtKernel(const double *X, double *Out,
+                             size_t NumElements) noexcept {
+  runKernelBody<__ocml_cbrt_f64>(NumElements, Out, X);
+}
+
 __gpu_kernel void cbrtfKernel(const float *X, float *Out,
                               size_t NumElements) noexcept {
   runKernelBody<__ocml_cbrt_f32>(NumElements, Out, X);
 }
 
+__gpu_kernel void cosKernel(const double *X, double *Out,
+                            size_t NumElements) noexcept {
+  runKernelBody<__ocml_cos_f64>(NumElements, Out, X);
+}
+
 __gpu_kernel void cosfKernel(const float *X, float *Out,
                              size_t NumElements) noexcept {
   runKernelBody<__ocml_cos_f32>(NumElements, Out, X);
@@ -108,27 +140,52 @@ __gpu_kernel void erffKernel(const float *X, float *Out,
   runKernelBody<__ocml_erf_f32>(NumElements, Out, X);
 }
 
+__gpu_kernel void expKernel(const double *X, double *Out,
+                            size_t NumElements) noexcept {
+  runKernelBody<__ocml_exp_f64>(NumElements, Out, X);
+}
+
 __gpu_kernel void expfKernel(const float *X, float *Out,
                              size_t NumElements) noexcept {
   runKernelBody<__ocml_exp_f32>(NumElements, Out, X);
 }
 
+__gpu_kernel void exp10Kernel(const double *X, double *Out,
+                              size_t NumElements) noexcept {
+  runKernelBody<__ocml_exp10_f64>(NumElements, Out, X);
+}
+
 __gpu_kernel void exp10fKernel(const float *X, float *Out,
                                size_t NumElements) noexcept {
   runKernelBody<__ocml_exp10_f32>(NumElements, Out, X);
 }
 
+__gpu_kernel void exp2Kernel(const double *X, double *Out,
+                             size_t NumElements) noexcept {
+  runKernelBody<__ocml_exp2_f64>(NumElements, Out, X);
+}
+
 __gpu_kernel void exp2fKernel(const float *X, float *Out,
                               size_t NumElements) noexcept {
   runKernelBody<__ocml_exp2_f32>(NumElements, Out, X);
 }
 
+__gpu_kernel void expm1Kernel(const double *X, double *Out,
+                              size_t NumElements) noexcept {
+  runKernelBody<__ocml_expm1_f64>(NumElements, Out, X);
+}
+
 __gpu_kernel void expm1fKernel(const float *X, float *Out,
                                size_t NumElements) noexcept {
   runKernelBody<__ocml_expm1_f32>(NumElements, Out, X);
 }
 
-__gpu_kernel void hypotfKernel(const float *X, float *Y, float *Out,
+__gpu_kernel void hypotKernel(const double *X, const double *Y, double *Out,
+                              size_t NumElements) noexcept {
+  runKernelBody<__ocml_hypot_f64>(NumElements, Out, X, Y);
+}
+
+__gpu_kernel void hypotfKernel(const float *X, const float *Y, float *Out,
                                size_t NumElements) noexcept {
   runKernelBody<__ocml_hypot_f32>(NumElements, Out, X, Y);
 }
@@ -143,16 +200,31 @@ __gpu_kernel void logfKernel(const float *X, float *Out,
   runKernelBody<__ocml_log_f32>(NumElements, Out, X);
 }
 
+__gpu_kernel void log10Kernel(const double *X, double *Out,
+                              size_t NumElements) noexcept {
+  runKernelBody<__ocml_log10_f64>(NumElements, Out, X);
+}
+
 __gpu_kernel void log10fKernel(const float *X, float *Out,
                                size_t NumElements) noexcept {
   runKernelBody<__ocml_log10_f32>(NumElements, Out, X);
 }
 
+__gpu_kernel void log1pKernel(const double *X, double *Out,
+                              size_t NumElements) noexcept {
+  runKernelBody<__ocml_log1p_f64>(NumElements, Out, X);
+}
+
 __gpu_kernel void log1pfKernel(const float *X, float *Out,
                                size_t NumElements) noexcept {
   runKernelBody<__ocml_log1p_f32>(NumElements, Out, X);
 }
 
+__gpu_kernel void log2Kernel(const double *X, double *Out,
+                             size_t NumElements) noexcept {
+  runKernelBody<__ocml_log2_f64>(NumElements, Out, X);
+}
+
 __gpu_kernel void log2fKernel(const float *X, float *Out,
                               size_t NumElements) noexcept {
   runKernelBody<__ocml_log2_f32>(NumElements, Out, X);
@@ -169,11 +241,26 @@ __gpu_kernel void powfRoundedExponentKernel(const float *X, float *Y,
   runKernelBody<powfRoundedExponent>(NumElements, Out, X, Y);
 }
 
+__gpu_kernel void sinKernel(const double *X, double *Out,
+                            size_t NumElements) noexcept {
+  runKernelBody<__ocml_sin_f64>(NumElements, Out, X);
+}
+
 __gpu_kernel void sinfKernel(const float *X, float *Out,
                              size_t NumElements) noexcept {
   runKernelBody<__ocml_sin_f32>(NumElements, Out, X);
 }
 
+__gpu_kernel void sincosSinKernel(const double *X, double *Out,
+                                  size_t NumElements) noexcept {
+  runKernelBody<sincosSin>(NumElements, Out, X);
+}
+
+__gpu_kernel void sincosCosKernel(const double *X, double *Out,
+                                  size_t NumElements) noexcept {
+  runKernelBody<sincosCos>(NumElements, Out, X);
+}
+
 __gpu_kernel void sincosfSinKernel(const float *X, float *Out,
                                    size_t NumElements) noexcept {
   runKernelBody<sincosfSin>(NumElements, Out, X);
@@ -194,6 +281,11 @@ __gpu_kernel void sinpifKernel(const float *X, float *Out,
   runKernelBody<__ocml_sinpi_f32>(NumElements, Out, X);
 }
 
+__gpu_kernel void tanKernel(const double *X, double *Out,
+                            size_t NumElements) noexcept {
+  runKernelBody<__ocml_tan_f64>(NumElements, Out, X);
+}
+
 __gpu_kernel void tanfKernel(const float *X, float *Out,
                              size_t NumElements) noexcept {
   runKernelBody<__ocml_tan_f32>(NumElements, Out, X);
diff --git a/offload/unittests/Conformance/device_code/LLVMLibm.cpp b/offload/unittests/Conformance/device_code/LLVMLibm.cpp
index 20ad796c6d172..e25f8e1c6c042 100644
--- a/offload/unittests/Conformance/device_code/LLVMLibm.cpp
+++ b/offload/unittests/Conformance/device_code/LLVMLibm.cpp
@@ -29,6 +29,18 @@ static inline float powfRoundedExponent(float Base, float Exponent) {
   return powf(Base, roundf(Exponent));
 }
 
+static inline double sincosSin(double X) {
+  double SinX, CosX;
+  sincos(X, &SinX, &CosX);
+  return SinX;
+}
+
+static inline double sincosCos(double X) {
+  double SinX, CosX;
+  sincos(X, &SinX, &CosX);
+  return CosX;
+}
+
 static inline float sincosfSin(float X) {
   float SinX, CosX;
   sincosf(X, &SinX, &CosX);
@@ -47,6 +59,11 @@ static inline float sincosfCos(float X) {
 
 extern "C" {
 
+__gpu_kernel void acosKernel(const double *X, double *Out,
+                             size_t NumElements) noexcept {
+  runKernelBody<acos>(NumElements, Out, X);
+}
+
 __gpu_kernel void acosfKernel(const float *X, float *Out,
                               size_t NumElements) noexcept {
   runKernelBody<acosf>(NumElements, Out, X);
@@ -57,6 +74,11 @@ __gpu_kernel void acoshfKernel(const float *X, float *Out,
   runKernelBody<acoshf>(NumElements, Out, X);
 }
 
+__gpu_kernel void asinKernel(const double *X, double *Out,
+                             size_t NumElements) noexcept {
+  runKernelBody<asin>(NumElements, Out, X);
+}
+
 __gpu_kernel void asinfKernel(const float *X, float *Out,
                               size_t NumElements) noexcept {
   runKernelBody<asinf>(NumElements, Out, X);
@@ -82,11 +104,21 @@ __gpu_kernel void atanhfKernel(const float *X, float *Out,
   runKernelBody<atanhf>(NumElements, Out, X);
 }
 
+__gpu_kernel void cbrtKernel(const double *X, double *Out,
+                             size_t NumElements) noexcept {
+  runKernelBody<cbrt>(NumElements, Out, X);
+}
+
 __gpu_kernel void cbrtfKernel(const float *X, float *Out,
                               size_t NumElements) noexcept {
   runKernelBody<cbrtf>(NumElements, Out, X);
 }
 
+__gpu_kernel void cosKernel(const double *X, double *Out,
+                            size_t NumElements) noexcept {
+  runKernelBody<cos>(NumElements, Out, X);
+}
+
 __gpu_kernel void cosfKernel(const float *X, float *Out,
                              size_t NumElements) noexcept {
   runKernelBody<cosf>(NumElements, Out, X);
@@ -107,32 +139,57 @@ __gpu_kernel void erffKernel(const float *X, float *Out,
   runKernelBody<erff>(NumElements, Out, X);
 }
 
+__gpu_kernel void expKernel(const double *X, double *Out,
+                            size_t NumElements) noexcept {
+  runKernelBody<exp>(NumElements, Out, X);
+}
+
 __gpu_kernel void expfKernel(const float *X, float *Out,
                              size_t NumElements) noexcept {
   runKernelBody<expf>(NumElements, Out, X);
 }
 
+__gpu_kernel void exp10Kernel(const double *X, double *Out,
+                              size_t NumElements) noexcept {
+  runKernelBody<exp10>(NumElements, Out, X);
+}
+
 __gpu_kernel void exp10fKernel(const float *X, float *Out,
                                size_t NumElements) noexcept {
   runKernelBody<exp10f>(NumElements, Out, X);
 }
 
+__gpu_kernel void exp2Kernel(const double *X, double *Out,
+                             size_t NumElements) noexcept {
+  runKernelBody<exp2>(NumElements, Out, X);
+}
+
 __gpu_kernel void exp2fKernel(const float *X, float *Out,
                               size_t NumElements) noexcept {
   runKernelBody<exp2f>(NumElements, Out, X);
 }
 
+__gpu_kernel void expm1Kernel(const double *X, double *Out,
+                              size_t NumElements) noexcept {
+  runKernelBody<expm1>(NumElements, Out, X);
+}
+
 __gpu_kernel void expm1fKernel(const float *X, float *Out,
                                size_t NumElements) noexcept {
   runKernelBody<expm1f>(NumElements, Out, X);
 }
 
-__gpu_kernel void hypotfKernel(const float *X, float *Y, float *Out,
+__gpu_kernel void hypotKernel(const double *X, const double *Y, double *Out,
+                              size_t NumElements) noexcept {
+  runKernelBody<hypot>(NumElements, Out, X, Y);
+}
+
+__gpu_kernel void hypotfKernel(const float *X, const float *Y, float *Out,
                                size_t NumElements) noexcept {
   runKernelBody<hypotf>(NumElements, Out, X, Y);
 }
 
-__gpu_kernel void hypotf16Kernel(const float16 *X, float16 *Y, float16 *Out,
+__gpu_kernel void hypotf16Kernel(const float16 *X, const float16 *Y, float16 *Out,
                                  size_t NumElements) noexcept {
   runKernelBody<hypotf16>(NumElements, Out, X, Y);
 }
@@ -147,16 +204,31 @@ __gpu_kernel void logfKernel(const float *X, float *Out,
   runKernelBody<logf>(NumElements, Out, X);
 }
 
+__gpu_kernel void log10Kernel(const double *X, double *Out,
+                              size_t NumElements) noexcept {
+  runKernelBody<log10>(NumElements, Out, X);
+}
+
 __gpu_kernel void log10fKernel(const float *X, float *Out,
                                size_t NumElements) noexcept {
   runKernelBody<log10f>(NumElements, Out, X);
 }
 
+__gpu_kernel void log1pKernel(const double *X, double *Out,
+                              size_t NumElements) noexcept {
+  runKernelBody<log1p>(NumElements, Out, X);
+}
+
 __gpu_kernel void log1pfKernel(const float *X, float *Out,
                                size_t NumElements) noexcept {
   runKernelBody<log1pf>(NumElements, Out, X);
 }
 
+__gpu_kernel void log2Kernel(const double *X, double *Out,
+                             size_t NumElements) noexcept {
+  runKernelBody<log2>(NumElements, Out, X);
+}
+
 __gpu_kernel void log2fKernel(const float *X, float *Out,
                               size_t NumElements) noexcept {
   runKernelBody<log2f>(NumElements, Out, X);
@@ -173,11 +245,26 @@ __gpu_kernel void powfRoundedExponentKernel(const float *X, float *Y,
   runKernelBody<powfRoundedExponent>(NumElements, Out, X, Y);
 }
 
+__gpu_kernel void sinKernel(const double *X, double *Out,
+                            size_t NumElements) noexcept {
+  runKernelBody<sin>(NumElements, Out, X);
+}
+
 __gpu_kernel void sinfKernel(const float *X, float *Out,
                              size_t NumElements) noexcept {
   runKernelBody<sinf>(NumElements, Out, X);
 }
 
+__gpu_kernel void sincosSinKernel(const double *X, double *Out,
+                                  size_t NumElements) noexcept {
+  runKernelBody<sincosSin>(NumElements, Out, X);
+}
+
+__gpu_kernel void sincosCosKernel(const double *X, double *Out,
+                                  size_t NumElements) noexcept {
+  runKernelBody<sincosCos>(NumElements, Out, X);
+}
+
 __gpu_kernel void sincosfSinKernel(const float *X, float *Out,
                                    size_t NumElements) noexcept {
   runKernelBody<sincosfSin>(NumElements, Out, X);
@@ -198,6 +285,11 @@ __gpu_kernel void sinpifKernel(const float *X, float *Out,
   runKernelBody<sinpif>(NumElements, Out, X);
 }
 
+__gpu_kernel void tanKernel(const double *X, double *Out,
+                            size_t NumElements) noexcept {
+  runKernelBody<tan>(NumElements, Out, X);
+}
+
 __gpu_kernel void tanfKernel(const float *X, float *Out,
                              size_t NumElements) noexcept {
   runKernelBody<tanf>(NumElements, Out, X);
diff --git a/offload/unittests/Conformance/tests/AcosTest.cpp b/offload/unittests/Conformance/tests/AcosTest.cpp
new file mode 100644
index 0000000000000..ba98b2947343f
--- /dev/null
+++ b/offload/unittests/Conformance/tests/AcosTest.cpp
@@ -0,0 +1,63 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 acos 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 <math.h>
+
+namespace {
+
+// Disambiguate the overloaded 'acos' function to select the double version
+constexpr auto acosd // NOLINT(readability-identifier-naming)
+    = static_cast<double (*)(double)>(acos);
+} // namespace
+
+namespace mathtest {
+
+template <> struct FunctionConfig<acosd> {
+  static constexpr llvm::StringRef Name = "acos";
+  static constexpr llvm::StringRef KernelName = "acosKernel";
+
+  // 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 = 4;
+};
+} // namespace mathtest
+
+int main(int argc, const char **argv) {
+  llvm::cl::ParseCommandLineOptions(argc, argv,
+                                    "Conformance test of the acos function");
+
+  using namespace mathtest;
+
+  uint64_t Seed = 42;
+  uint64_t Size = 1ULL << 32;
+  IndexedRange<double> Range;
+  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<acosd>(Generator, Configs, DeviceBinaryDir, IsVerbose);
+
+  return Passed ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/offload/unittests/Conformance/tests/AsinTest.cpp b/offload/unittests/Conformance/tests/AsinTest.cpp
new file mode 100644
index 0000000000000..3594d5e115e08
--- /dev/null
+++ b/offload/unittests/Conformance/tests/AsinTest.cpp
@@ -0,0 +1,63 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 asin 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 <math.h>
+
+namespace {
+
+// Disambiguate the overloaded 'asin' function to select the double version
+constexpr auto asind // NOLINT(readability-identifier-naming)
+    = static_cast<double (*)(double)>(asin);
+} // namespace
+
+namespace mathtest {
+
+template <> struct FunctionConfig<asind> {
+  static constexpr llvm::StringRef Name = "asin";
+  static constexpr llvm::StringRef KernelName = "asinKernel";
+
+  // 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 = 4;
+};
+} // namespace mathtest
+
+int main(int argc, const char **argv) {
+  llvm::cl::ParseCommandLineOptions(argc, argv,
+                                    "Conformance test of the asin function");
+
+  using namespace mathtest;
+
+  uint64_t Seed = 42;
+  uint64_t Size = 1ULL << 32;
+  IndexedRange<double> Range;
+  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<asind>(Generator, Configs, DeviceBinaryDir, IsVerbose);
+
+  return Passed ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/offload/unittests/Conformance/tests/CMakeLists.txt b/offload/unittests/Conformance/tests/CMakeLists.txt
index 0bac08d6ed919..b608a52f8061d 100644
--- a/offload/unittests/Conformance/tests/CMakeLists.txt
+++ b/offload/unittests/Conformance/tests/CMakeLists.txt
@@ -3,34 +3,49 @@ if(NOT TARGET libc)
     return()
 endif()
 
+add_conformance_test(acos AcosTest.cpp)
 add_conformance_test(acosf AcosfTest.cpp)
 add_conformance_test(acoshf AcoshfTest.cpp)
+add_conformance_test(asin AsinTest.cpp)
 add_conformance_test(asinf AsinfTest.cpp)
 add_conformance_test(asinhf AsinhfTest.cpp)
 add_conformance_test(atanf AtanfTest.cpp)
 add_conformance_test(atan2f Atan2fTest.cpp)
 add_conformance_test(atanhf AtanhfTest.cpp)
+add_conformance_test(cbrt CbrtTest.cpp)
 add_conformance_test(cbrtf CbrtfTest.cpp)
+add_conformance_test(cos CosTest.cpp)
 add_conformance_test(cosf CosfTest.cpp)
 add_conformance_test(coshf CoshfTest.cpp)
 add_conformance_test(cospif CospifTest.cpp)
 add_conformance_test(erff ErffTest.cpp)
+add_conformance_test(exp ExpTest.cpp)
 add_conformance_test(expf ExpfTest.cpp)
+add_conformance_test(exp10 Exp10Test.cpp)
 add_conformance_test(exp10f Exp10fTest.cpp)
+add_conformance_test(exp2 Exp2Test.cpp)
 add_conformance_test(exp2f Exp2fTest.cpp)
+add_conformance_test(expm1 Expm1Test.cpp)
 add_conformance_test(expm1f Expm1fTest.cpp)
+add_conformance_test(hypot HypotTest.cpp)
 add_conformance_test(hypotf HypotfTest.cpp)
 add_conformance_test(hypotf16 Hypotf16Test.cpp)
 add_conformance_test(log LogTest.cpp)
 add_conformance_test(logf LogfTest.cpp)
+add_conformance_test(log10 Log10Test.cpp)
 add_conformance_test(log10f Log10fTest.cpp)
+add_conformance_test(log1p Log1pTest.cpp)
 add_conformance_test(log1pf Log1pfTest.cpp)
+add_conformance_test(log2 Log2Test.cpp)
 add_conformance_test(log2f Log2fTest.cpp)
 add_conformance_test(powf PowfTest.cpp)
+add_conformance_test(sin SinTest.cpp)
 add_conformance_test(sinf SinfTest.cpp)
+add_conformance_test(sincos SincosTest.cpp)
 add_conformance_test(sincosf SincosfTest.cpp)
 add_conformance_test(sinhf SinhfTest.cpp)
 add_conformance_test(sinpif SinpifTest.cpp)
+add_conformance_test(tan TanTest.cpp)
 add_conformance_test(tanf TanfTest.cpp)
 add_conformance_test(tanhf TanhfTest.cpp)
 add_conformance_test(tanpif TanpifTest.cpp)
diff --git a/offload/unittests/Conformance/tests/CbrtTest.cpp b/offload/unittests/Conformance/tests/CbrtTest.cpp
new file mode 100644
index 0000000000000..3a6523b66ad83
--- /dev/null
+++ b/offload/unittests/Conformance/tests/CbrtTest.cpp
@@ -0,0 +1,63 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 cbrt 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 <math.h>
+
+namespace {
+
+// Disambiguate the overloaded 'cbrt' function to select the double version
+constexpr auto cbrtd // NOLINT(readability-identifier-naming)
+    = static_cast<double (*)(double)>(cbrt);
+} // namespace
+
+namespace mathtest {
+
+template <> struct FunctionConfig<cbrtd> {
+  static constexpr llvm::StringRef Name = "cbrt";
+  static constexpr llvm::StringRef KernelName = "cbrtKernel";
+
+  // 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 = 2;
+};
+} // namespace mathtest
+
+int main(int argc, const char **argv) {
+  llvm::cl::ParseCommandLineOptions(argc, argv,
+                                    "Conformance test of the cbrt function");
+
+  using namespace mathtest;
+
+  uint64_t Seed = 42;
+  uint64_t Size = 1ULL << 32;
+  IndexedRange<double> Range;
+  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<cbrtd>(Generator, Configs, DeviceBinaryDir, IsVerbose);
+
+  return Passed ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/offload/unittests/Conformance/tests/CosTest.cpp b/offload/unittests/Conformance/tests/CosTest.cpp
new file mode 100644
index 0000000000000..e3d3d3da81800
--- /dev/null
+++ b/offload/unittests/Conformance/tests/CosTest.cpp
@@ -0,0 +1,63 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 cos 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 <math.h>
+
+namespace {
+
+// Disambiguate the overloaded 'cos' function to select the double version
+constexpr auto cosd // NOLINT(readability-identifier-naming)
+    = static_cast<double (*)(double)>(cos);
+} // namespace
+
+namespace mathtest {
+
+template <> struct FunctionConfig<cosd> {
+  static constexpr llvm::StringRef Name = "cos";
+  static constexpr llvm::StringRef KernelName = "cosKernel";
+
+  // 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 = 4;
+};
+} // namespace mathtest
+
+int main(int argc, const char **argv) {
+  llvm::cl::ParseCommandLineOptions(argc, argv,
+                                    "Conformance test of the cos function");
+
+  using namespace mathtest;
+
+  uint64_t Seed = 42;
+  uint64_t Size = 1ULL << 32;
+  IndexedRange<double> Range;
+  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<cosd>(Generator, Configs, DeviceBinaryDir, IsVerbose);
+
+  return Passed ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/offload/unittests/Conformance/tests/Exp10Test.cpp b/offload/unittests/Conformance/tests/Exp10Test.cpp
new file mode 100644
index 0000000000000..05af4780213b1
--- /dev/null
+++ b/offload/unittests/Conformance/tests/Exp10Test.cpp
@@ -0,0 +1,64 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 exp10 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 <math.h>
+
+namespace {
+
+// Disambiguate the overloaded 'exp10' function to select the double version
+constexpr auto exp10d // NOLINT(readability-identifier-naming)
+    = static_cast<double (*)(double)>(exp10);
+} // namespace
+
+namespace mathtest {
+
+template <> struct FunctionConfig<exp10d> {
+  static constexpr llvm::StringRef Name = "exp10";
+  static constexpr llvm::StringRef KernelName = "exp10Kernel";
+
+  // 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 exp10 function");
+
+  using namespace mathtest;
+
+  uint64_t Seed = 42;
+  uint64_t Size = 1ULL << 32;
+  IndexedRange<double> Range;
+  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<exp10d>(Generator, Configs, DeviceBinaryDir, IsVerbose);
+
+  return Passed ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/offload/unittests/Conformance/tests/Exp2Test.cpp b/offload/unittests/Conformance/tests/Exp2Test.cpp
new file mode 100644
index 0000000000000..bb2fa10a0dfa6
--- /dev/null
+++ b/offload/unittests/Conformance/tests/Exp2Test.cpp
@@ -0,0 +1,63 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 exp2 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 <math.h>
+
+namespace {
+
+// Disambiguate the overloaded 'exp2' function to select the double version
+constexpr auto exp2d // NOLINT(readability-identifier-naming)
+    = static_cast<double (*)(double)>(exp2);
+} // namespace
+
+namespace mathtest {
+
+template <> struct FunctionConfig<exp2d> {
+  static constexpr llvm::StringRef Name = "exp2";
+  static constexpr llvm::StringRef KernelName = "exp2Kernel";
+
+  // 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 exp2 function");
+
+  using namespace mathtest;
+
+  uint64_t Seed = 42;
+  uint64_t Size = 1ULL << 32;
+  IndexedRange<double> Range;
+  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<exp2d>(Generator, Configs, DeviceBinaryDir, IsVerbose);
+
+  return Passed ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/offload/unittests/Conformance/tests/ExpTest.cpp b/offload/unittests/Conformance/tests/ExpTest.cpp
new file mode 100644
index 0000000000000..9aa52b17905ea
--- /dev/null
+++ b/offload/unittests/Conformance/tests/ExpTest.cpp
@@ -0,0 +1,63 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 exp 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 <math.h>
+
+namespace {
+
+// Disambiguate the overloaded 'exp' function to select the double version
+constexpr auto expd // NOLINT(readability-identifier-naming)
+    = static_cast<double (*)(double)>(exp);
+} // namespace
+
+namespace mathtest {
+
+template <> struct FunctionConfig<expd> {
+  static constexpr llvm::StringRef Name = "exp";
+  static constexpr llvm::StringRef KernelName = "expKernel";
+
+  // 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 exp function");
+
+  using namespace mathtest;
+
+  uint64_t Seed = 42;
+  uint64_t Size = 1ULL << 32;
+  IndexedRange<double> Range;
+  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<expd>(Generator, Configs, DeviceBinaryDir, IsVerbose);
+
+  return Passed ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/offload/unittests/Conformance/tests/Expm1Test.cpp b/offload/unittests/Conformance/tests/Expm1Test.cpp
new file mode 100644
index 0000000000000..a27944bf722f8
--- /dev/null
+++ b/offload/unittests/Conformance/tests/Expm1Test.cpp
@@ -0,0 +1,64 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 expm1 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 <math.h>
+
+namespace {
+
+// Disambiguate the overloaded 'expm1' function to select the double version
+constexpr auto expm1d // NOLINT(readability-identifier-naming)
+    = static_cast<double (*)(double)>(expm1);
+} // namespace
+
+namespace mathtest {
+
+template <> struct FunctionConfig<expm1d> {
+  static constexpr llvm::StringRef Name = "expm1";
+  static constexpr llvm::StringRef KernelName = "expm1Kernel";
+
+  // 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 expm1 function");
+
+  using namespace mathtest;
+
+  uint64_t Seed = 42;
+  uint64_t Size = 1ULL << 32;
+  IndexedRange<double> Range;
+  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<expm1d>(Generator, Configs, DeviceBinaryDir, IsVerbose);
+
+  return Passed ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/offload/unittests/Conformance/tests/HypotTest.cpp b/offload/unittests/Conformance/tests/HypotTest.cpp
new file mode 100644
index 0000000000000..0417ad901d5ee
--- /dev/null
+++ b/offload/unittests/Conformance/tests/HypotTest.cpp
@@ -0,0 +1,65 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 hypot 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 <math.h>
+
+namespace {
+
+// Disambiguate the overloaded 'hypot' function to select the double version
+constexpr auto hypotd // NOLINT(readability-identifier-naming)
+    = static_cast<double (*)(double, double)>(hypot);
+} // namespace
+
+namespace mathtest {
+
+template <> struct FunctionConfig<hypotd> {
+  static constexpr llvm::StringRef Name = "hypot";
+  static constexpr llvm::StringRef KernelName = "hypotKernel";
+
+  // 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 = 4;
+};
+} // namespace mathtest
+
+int main(int argc, const char **argv) {
+  llvm::cl::ParseCommandLineOptions(argc, argv,
+                                    "Conformance test of the hypot function");
+
+  using namespace mathtest;
+
+  uint64_t Seed = 42;
+  uint64_t Size = 1ULL << 32;
+  IndexedRange<double> RangeX;
+  IndexedRange<double> RangeY;
+  RandomGenerator<double, double> Generator(SeedTy{Seed}, Size, RangeX, RangeY);
+
+  const auto Configs = cl::getTestConfigs();
+  const llvm::StringRef DeviceBinaryDir = DEVICE_BINARY_DIR;
+  const bool IsVerbose = cl::IsVerbose;
+
+  bool Passed =
+      runTests<hypotd>(Generator, Configs, DeviceBinaryDir, IsVerbose);
+
+  return Passed ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/offload/unittests/Conformance/tests/Log10Test.cpp b/offload/unittests/Conformance/tests/Log10Test.cpp
new file mode 100644
index 0000000000000..bf46f11e960bf
--- /dev/null
+++ b/offload/unittests/Conformance/tests/Log10Test.cpp
@@ -0,0 +1,67 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 log10 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 'log10' function to select the double version
+constexpr auto log10d // NOLINT(readability-identifier-naming)
+    = static_cast<double (*)(double)>(log10);
+} // namespace
+
+namespace mathtest {
+
+template <> struct FunctionConfig<log10d> {
+  static constexpr llvm::StringRef Name = "log10";
+  static constexpr llvm::StringRef KernelName = "log10Kernel";
+
+  // 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 log10 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<log10d>(Generator, Configs, DeviceBinaryDir, IsVerbose);
+
+  return Passed ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/offload/unittests/Conformance/tests/Log1pTest.cpp b/offload/unittests/Conformance/tests/Log1pTest.cpp
new file mode 100644
index 0000000000000..0c3a9042f1605
--- /dev/null
+++ b/offload/unittests/Conformance/tests/Log1pTest.cpp
@@ -0,0 +1,67 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 log1p 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 'log1p' function to select the double version
+constexpr auto log1pd // NOLINT(readability-identifier-naming)
+    = static_cast<double (*)(double)>(log1p);
+} // namespace
+
+namespace mathtest {
+
+template <> struct FunctionConfig<log1pd> {
+  static constexpr llvm::StringRef Name = "log1p";
+  static constexpr llvm::StringRef KernelName = "log1pKernel";
+
+  // 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 = 2;
+};
+} // namespace mathtest
+
+int main(int argc, const char **argv) {
+  llvm::cl::ParseCommandLineOptions(argc, argv,
+                                    "Conformance test of the log1p 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<log1pd>(Generator, Configs, DeviceBinaryDir, IsVerbose);
+
+  return Passed ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/offload/unittests/Conformance/tests/Log2Test.cpp b/offload/unittests/Conformance/tests/Log2Test.cpp
new file mode 100644
index 0000000000000..2ae7e5c232928
--- /dev/null
+++ b/offload/unittests/Conformance/tests/Log2Test.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 log2 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 'log2' function to select the double version
+constexpr auto log2d // NOLINT(readability-identifier-naming)
+    = static_cast<double (*)(double)>(log2);
+} // namespace
+
+namespace mathtest {
+
+template <> struct FunctionConfig<log2d> {
+  static constexpr llvm::StringRef Name = "log2";
+  static constexpr llvm::StringRef KernelName = "log2Kernel";
+
+  // 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 log2 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<log2d>(Generator, Configs, DeviceBinaryDir, IsVerbose);
+
+  return Passed ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/offload/unittests/Conformance/tests/SinTest.cpp b/offload/unittests/Conformance/tests/SinTest.cpp
new file mode 100644
index 0000000000000..36897d74c96af
--- /dev/null
+++ b/offload/unittests/Conformance/tests/SinTest.cpp
@@ -0,0 +1,63 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 sin 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 <math.h>
+
+namespace {
+
+// Disambiguate the overloaded 'sin' function to select the double version
+constexpr auto sind // NOLINT(readability-identifier-naming)
+    = static_cast<double (*)(double)>(sin);
+} // namespace
+
+namespace mathtest {
+
+template <> struct FunctionConfig<sind> {
+  static constexpr llvm::StringRef Name = "sin";
+  static constexpr llvm::StringRef KernelName = "sinKernel";
+
+  // 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 = 4;
+};
+} // namespace mathtest
+
+int main(int argc, const char **argv) {
+  llvm::cl::ParseCommandLineOptions(argc, argv,
+                                    "Conformance test of the sin function");
+
+  using namespace mathtest;
+
+  uint64_t Seed = 42;
+  uint64_t Size = 1ULL << 32;
+  IndexedRange<double> Range;
+  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<sind>(Generator, Configs, DeviceBinaryDir, IsVerbose);
+
+  return Passed ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/offload/unittests/Conformance/tests/SincosTest.cpp b/offload/unittests/Conformance/tests/SincosTest.cpp
new file mode 100644
index 0000000000000..f240f6885ec00
--- /dev/null
+++ b/offload/unittests/Conformance/tests/SincosTest.cpp
@@ -0,0 +1,80 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 sincos 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 <math.h>
+
+static inline double sincosSin(double X) {
+  double SinX, CosX;
+  sincos(X, &SinX, &CosX);
+  return SinX;
+}
+
+static inline double sincosCos(double X) {
+  double SinX, CosX;
+  sincos(X, &SinX, &CosX);
+  return CosX;
+}
+
+namespace mathtest {
+
+template <> struct FunctionConfig<sincosSin> {
+  static constexpr llvm::StringRef Name = "sincos (sin part)";
+  static constexpr llvm::StringRef KernelName = "sincosSinKernel";
+
+  // Source: The Khronos Group, The OpenCL C Specification v3.0.19, Sec. 7.4,
+  //         Table 65, Khronos Registry [July 10, 2025].
+  static constexpr uint64_t UlpTolerance = 4;
+};
+
+template <> struct FunctionConfig<sincosCos> {
+  static constexpr llvm::StringRef Name = "sincos (cos part)";
+  static constexpr llvm::StringRef KernelName = "sincosCosKernel";
+
+  // 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 = 4;
+};
+} // namespace mathtest
+
+int main(int argc, const char **argv) {
+  llvm::cl::ParseCommandLineOptions(argc, argv,
+                                    "Conformance test of the sincos function");
+
+  using namespace mathtest;
+
+  uint64_t Seed = 42;
+  uint64_t Size = 1ULL << 32;
+  IndexedRange<double> Range;
+  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 SinPartPassed =
+      runTests<sincosSin>(Generator, Configs, DeviceBinaryDir, IsVerbose);
+  bool CosPartPassed =
+      runTests<sincosCos>(Generator, Configs, DeviceBinaryDir, IsVerbose);
+
+  return (SinPartPassed && CosPartPassed) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/offload/unittests/Conformance/tests/TanTest.cpp b/offload/unittests/Conformance/tests/TanTest.cpp
new file mode 100644
index 0000000000000..3a9a05874450e
--- /dev/null
+++ b/offload/unittests/Conformance/tests/TanTest.cpp
@@ -0,0 +1,63 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 tan 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 <math.h>
+
+namespace {
+
+// Disambiguate the overloaded 'tan' function to select the double version
+constexpr auto tand // NOLINT(readability-identifier-naming)
+    = static_cast<double (*)(double)>(tan);
+} // namespace
+
+namespace mathtest {
+
+template <> struct FunctionConfig<tand> {
+  static constexpr llvm::StringRef Name = "tan";
+  static constexpr llvm::StringRef KernelName = "tanKernel";
+
+  // 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 = 5;
+};
+} // namespace mathtest
+
+int main(int argc, const char **argv) {
+  llvm::cl::ParseCommandLineOptions(argc, argv,
+                                    "Conformance test of the tan function");
+
+  using namespace mathtest;
+
+  uint64_t Seed = 42;
+  uint64_t Size = 1ULL << 32;
+  IndexedRange<double> Range;
+  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<tand>(Generator, Configs, DeviceBinaryDir, IsVerbose);
+
+  return Passed ? EXIT_SUCCESS : EXIT_FAILURE;
+}



More information about the llvm-commits mailing list