Skip to content

[Offload][Conformance] Add tests for single-precision math functions #152013

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

leandrolcampos
Copy link
Contributor

This patch adds a new set of conformance tests for single-precision math functions provided by the LLVM libm for GPUs.

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.

@llvmbot llvmbot added the offload label Aug 4, 2025
@llvmbot
Copy link
Member

llvmbot commented Aug 4, 2025

@llvm/pr-subscribers-offload

Author: Leandro Lacerda (leandrolcampos)

Changes

This patch adds a new set of conformance tests for single-precision math functions provided by the LLVM libm for GPUs.

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.

Patch is 62.08 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/152013.diff

30 Files Affected:

  • (modified) offload/unittests/Conformance/device_code/CMakeLists.txt (+1-1)
  • (added) offload/unittests/Conformance/device_code/Common.hpp (+38)
  • (modified) offload/unittests/Conformance/device_code/LLVMLibm.cpp (+156-12)
  • (added) offload/unittests/Conformance/tests/AcosfTest.cpp (+53)
  • (added) offload/unittests/Conformance/tests/AcoshfTest.cpp (+57)
  • (added) offload/unittests/Conformance/tests/AsinfTest.cpp (+53)
  • (added) offload/unittests/Conformance/tests/AsinhfTest.cpp (+54)
  • (added) offload/unittests/Conformance/tests/AtanfTest.cpp (+53)
  • (added) offload/unittests/Conformance/tests/AtanhfTest.cpp (+56)
  • (modified) offload/unittests/Conformance/tests/CMakeLists.txt (+25)
  • (added) offload/unittests/Conformance/tests/CbrtfTest.cpp (+53)
  • (added) offload/unittests/Conformance/tests/CosfTest.cpp (+53)
  • (added) offload/unittests/Conformance/tests/CoshfTest.cpp (+53)
  • (added) offload/unittests/Conformance/tests/CospifTest.cpp (+56)
  • (added) offload/unittests/Conformance/tests/ErffTest.cpp (+53)
  • (added) offload/unittests/Conformance/tests/Exp10fTest.cpp (+54)
  • (added) offload/unittests/Conformance/tests/Exp2fTest.cpp (+53)
  • (added) offload/unittests/Conformance/tests/ExpfTest.cpp (+53)
  • (added) offload/unittests/Conformance/tests/Expm1fTest.cpp (+54)
  • (modified) offload/unittests/Conformance/tests/Hypotf16Test.cpp (+1-4)
  • (added) offload/unittests/Conformance/tests/Log10fTest.cpp (+57)
  • (added) offload/unittests/Conformance/tests/Log1pfTest.cpp (+57)
  • (added) offload/unittests/Conformance/tests/Log2fTest.cpp (+56)
  • (added) offload/unittests/Conformance/tests/SincosfTest.cpp (+77)
  • (added) offload/unittests/Conformance/tests/SinfTest.cpp (+53)
  • (added) offload/unittests/Conformance/tests/SinhfTest.cpp (+53)
  • (added) offload/unittests/Conformance/tests/SinpifTest.cpp (+56)
  • (added) offload/unittests/Conformance/tests/TanfTest.cpp (+53)
  • (added) offload/unittests/Conformance/tests/TanhfTest.cpp (+53)
  • (added) offload/unittests/Conformance/tests/TanpifTest.cpp (+56)
diff --git a/offload/unittests/Conformance/device_code/CMakeLists.txt b/offload/unittests/Conformance/device_code/CMakeLists.txt
index 9cbd11096292c..a7f504dbadc9b 100644
--- a/offload/unittests/Conformance/device_code/CMakeLists.txt
+++ b/offload/unittests/Conformance/device_code/CMakeLists.txt
@@ -1,4 +1,4 @@
-add_offload_test_device_code(LLVMLibm.cpp llvm-libm -stdlib -fno-builtin)
+add_offload_test_device_code(LLVMLibm.cpp llvm-libm -O3 -stdlib -fno-builtin -I.)
 
 add_custom_target(conformance_device_binaries DEPENDS llvm-libm.bin)
 set(OFFLOAD_CONFORMANCE_DEVICE_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR} PARENT_SCOPE)
diff --git a/offload/unittests/Conformance/device_code/Common.hpp b/offload/unittests/Conformance/device_code/Common.hpp
new file mode 100644
index 0000000000000..5f9c3bf673559
--- /dev/null
+++ b/offload/unittests/Conformance/device_code/Common.hpp
@@ -0,0 +1,38 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 common utilities for defining device kernel wrappers to
+/// math functions.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef COMMON_HPP
+#define COMMON_HPP
+
+#include <gpuintrin.h>
+#include <stddef.h>
+#include <stdint.h>
+
+namespace common {
+
+typedef _Float16 float16;
+
+template <auto Func, typename OutType, typename... InTypes>
+__attribute__((always_inline)) void
+runKernelBody(size_t NumElements, OutType *Out, const InTypes *...Ins) {
+  uint32_t Index =
+      __gpu_num_threads_x() * __gpu_block_id_x() + __gpu_thread_id_x();
+
+  if (Index < NumElements) {
+    Out[Index] = Func(Ins[Index]...);
+  }
+}
+} // namespace common
+
+#endif // COMMON_HPP
diff --git a/offload/unittests/Conformance/device_code/LLVMLibm.cpp b/offload/unittests/Conformance/device_code/LLVMLibm.cpp
index 2c3d9bc5bf5cf..8d9412ee73c44 100644
--- a/offload/unittests/Conformance/device_code/LLVMLibm.cpp
+++ b/offload/unittests/Conformance/device_code/LLVMLibm.cpp
@@ -12,29 +12,173 @@
 ///
 //===----------------------------------------------------------------------===//
 
+#include "Common.hpp"
+
 #include <gpuintrin.h>
 #include <math.h>
 #include <stddef.h>
-#include <stdint.h>
 
-typedef _Float16 float16;
+using namespace common;
+
+//===----------------------------------------------------------------------===//
+// Helpers
+//===----------------------------------------------------------------------===//
+
+static inline float sincosfSin(float X) {
+  float SinX, CosX;
+  sincosf(X, &SinX, &CosX);
+  return SinX;
+}
+
+static inline float sincosfCos(float X) {
+  float SinX, CosX;
+  sincosf(X, &SinX, &CosX);
+  return CosX;
+}
+
+//===----------------------------------------------------------------------===//
+// Kernels
+//===----------------------------------------------------------------------===//
 
 extern "C" {
 
+__gpu_kernel void acosfKernel(const float *X, float *Out,
+                              size_t NumElements) noexcept {
+  runKernelBody<acosf>(NumElements, Out, X);
+}
+
+__gpu_kernel void acoshfKernel(const float *X, float *Out,
+                               size_t NumElements) noexcept {
+  runKernelBody<acoshf>(NumElements, Out, X);
+}
+
+__gpu_kernel void asinfKernel(const float *X, float *Out,
+                              size_t NumElements) noexcept {
+  runKernelBody<asinf>(NumElements, Out, X);
+}
+
+__gpu_kernel void asinhfKernel(const float *X, float *Out,
+                               size_t NumElements) noexcept {
+  runKernelBody<asinhf>(NumElements, Out, X);
+}
+
+__gpu_kernel void atanfKernel(const float *X, float *Out,
+                              size_t NumElements) noexcept {
+  runKernelBody<atanf>(NumElements, Out, X);
+}
+
+__gpu_kernel void atanhfKernel(const float *X, float *Out,
+                               size_t NumElements) noexcept {
+  runKernelBody<atanhf>(NumElements, Out, X);
+}
+
+__gpu_kernel void cbrtfKernel(const float *X, float *Out,
+                              size_t NumElements) noexcept {
+  runKernelBody<cbrtf>(NumElements, Out, X);
+}
+
+__gpu_kernel void cosfKernel(const float *X, float *Out,
+                             size_t NumElements) noexcept {
+  runKernelBody<cosf>(NumElements, Out, X);
+}
+
+__gpu_kernel void coshfKernel(const float *X, float *Out,
+                              size_t NumElements) noexcept {
+  runKernelBody<coshf>(NumElements, Out, X);
+}
+
+__gpu_kernel void cospifKernel(const float *X, float *Out,
+                               size_t NumElements) noexcept {
+  runKernelBody<cospif>(NumElements, Out, X);
+}
+
+__gpu_kernel void erffKernel(const float *X, float *Out,
+                             size_t NumElements) noexcept {
+  runKernelBody<erff>(NumElements, Out, X);
+}
+
+__gpu_kernel void expfKernel(const float *X, float *Out,
+                             size_t NumElements) noexcept {
+  runKernelBody<expf>(NumElements, Out, X);
+}
+
+__gpu_kernel void exp10fKernel(const float *X, float *Out,
+                               size_t NumElements) noexcept {
+  runKernelBody<exp10f>(NumElements, Out, X);
+}
+
+__gpu_kernel void exp2fKernel(const float *X, float *Out,
+                              size_t NumElements) noexcept {
+  runKernelBody<exp2f>(NumElements, Out, X);
+}
+
+__gpu_kernel void expm1fKernel(const float *X, float *Out,
+                               size_t NumElements) noexcept {
+  runKernelBody<expm1f>(NumElements, Out, X);
+}
+
 __gpu_kernel void hypotf16Kernel(const float16 *X, float16 *Y, float16 *Out,
-                                 size_t NumElements) {
-  uint32_t Index =
-      __gpu_num_threads_x() * __gpu_block_id_x() + __gpu_thread_id_x();
+                                 size_t NumElements) noexcept {
+  runKernelBody<hypotf16>(NumElements, Out, X, Y);
+}
+
+__gpu_kernel void logfKernel(const float *X, float *Out,
+                             size_t NumElements) noexcept {
+  runKernelBody<logf>(NumElements, Out, X);
+}
+
+__gpu_kernel void log10fKernel(const float *X, float *Out,
+                               size_t NumElements) noexcept {
+  runKernelBody<log10f>(NumElements, Out, X);
+}
 
-  if (Index < NumElements)
-    Out[Index] = hypotf16(X[Index], Y[Index]);
+__gpu_kernel void log1pfKernel(const float *X, float *Out,
+                               size_t NumElements) noexcept {
+  runKernelBody<log1pf>(NumElements, Out, X);
 }
 
-__gpu_kernel void logfKernel(const float *X, float *Out, size_t NumElements) {
-  uint32_t Index =
-      __gpu_num_threads_x() * __gpu_block_id_x() + __gpu_thread_id_x();
+__gpu_kernel void log2fKernel(const float *X, float *Out,
+                              size_t NumElements) noexcept {
+  runKernelBody<log2f>(NumElements, Out, X);
+}
+
+__gpu_kernel void sinfKernel(const float *X, float *Out,
+                             size_t NumElements) noexcept {
+  runKernelBody<sinf>(NumElements, Out, X);
+}
+
+__gpu_kernel void sincosfSinKernel(const float *X, float *Out,
+                                   size_t NumElements) noexcept {
+  runKernelBody<sincosfSin>(NumElements, Out, X);
+}
+
+__gpu_kernel void sincosfCosKernel(const float *X, float *Out,
+                                   size_t NumElements) noexcept {
+  runKernelBody<sincosfCos>(NumElements, Out, X);
+}
+
+__gpu_kernel void sinhfKernel(const float *X, float *Out,
+                              size_t NumElements) noexcept {
+  runKernelBody<sinhf>(NumElements, Out, X);
+}
+
+__gpu_kernel void sinpifKernel(const float *X, float *Out,
+                               size_t NumElements) noexcept {
+  runKernelBody<sinpif>(NumElements, Out, X);
+}
+
+__gpu_kernel void tanfKernel(const float *X, float *Out,
+                             size_t NumElements) noexcept {
+  runKernelBody<tanf>(NumElements, Out, X);
+}
+
+__gpu_kernel void tanhfKernel(const float *X, float *Out,
+                              size_t NumElements) noexcept {
+  runKernelBody<tanhf>(NumElements, Out, X);
+}
 
-  if (Index < NumElements)
-    Out[Index] = logf(X[Index]);
+__gpu_kernel void tanpifKernel(const float *X, float *Out,
+                               size_t NumElements) noexcept {
+  runKernelBody<tanpif>(NumElements, Out, X);
 }
 } // extern "C"
diff --git a/offload/unittests/Conformance/tests/AcosfTest.cpp b/offload/unittests/Conformance/tests/AcosfTest.cpp
new file mode 100644
index 0000000000000..e69ee3b7d1fd7
--- /dev/null
+++ b/offload/unittests/Conformance/tests/AcosfTest.cpp
@@ -0,0 +1,53 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 acosf function.
+///
+//===----------------------------------------------------------------------===//
+
+#include "mathtest/CommandLineExtras.hpp"
+#include "mathtest/ExhaustiveGenerator.hpp"
+#include "mathtest/IndexedRange.hpp"
+#include "mathtest/TestConfig.hpp"
+#include "mathtest/TestRunner.hpp"
+
+#include "llvm/ADT/StringRef.h"
+
+#include <cstdlib>
+#include <math.h>
+
+namespace mathtest {
+
+template <> struct FunctionConfig<acosf> {
+  static constexpr llvm::StringRef Name = "acosf";
+  static constexpr llvm::StringRef KernelName = "acosfKernel";
+
+  // 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;
+};
+} // namespace mathtest
+
+int main(int argc, const char **argv) {
+  llvm::cl::ParseCommandLineOptions(argc, argv,
+                                    "Conformance test of the acosf function");
+
+  using namespace mathtest;
+
+  IndexedRange<float> Range;
+  ExhaustiveGenerator<float> Generator(Range);
+
+  const auto Configs = cl::getTestConfigs();
+  const llvm::StringRef DeviceBinaryDir = DEVICE_BINARY_DIR;
+  const bool IsVerbose = cl::IsVerbose;
+
+  bool Passed = runTests<acosf>(Generator, Configs, DeviceBinaryDir, IsVerbose);
+
+  return Passed ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/offload/unittests/Conformance/tests/AcoshfTest.cpp b/offload/unittests/Conformance/tests/AcoshfTest.cpp
new file mode 100644
index 0000000000000..4d43a661c3535
--- /dev/null
+++ b/offload/unittests/Conformance/tests/AcoshfTest.cpp
@@ -0,0 +1,57 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 acoshf function.
+///
+//===----------------------------------------------------------------------===//
+
+#include "mathtest/CommandLineExtras.hpp"
+#include "mathtest/ExhaustiveGenerator.hpp"
+#include "mathtest/IndexedRange.hpp"
+#include "mathtest/TestConfig.hpp"
+#include "mathtest/TestRunner.hpp"
+
+#include "llvm/ADT/StringRef.h"
+
+#include <cstdlib>
+#include <limits>
+#include <math.h>
+
+namespace mathtest {
+
+template <> struct FunctionConfig<acoshf> {
+  static constexpr llvm::StringRef Name = "acoshf";
+  static constexpr llvm::StringRef KernelName = "acoshfKernel";
+
+  // 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;
+};
+} // namespace mathtest
+
+int main(int argc, const char **argv) {
+  llvm::cl::ParseCommandLineOptions(argc, argv,
+                                    "Conformance test of the acoshf function");
+
+  using namespace mathtest;
+
+  IndexedRange<float> Range(/*Begin=*/1.0f,
+                            /*End=*/std::numeric_limits<float>::infinity(),
+                            /*Inclusive=*/true);
+  ExhaustiveGenerator<float> Generator(Range);
+
+  const auto Configs = cl::getTestConfigs();
+  const llvm::StringRef DeviceBinaryDir = DEVICE_BINARY_DIR;
+  const bool IsVerbose = cl::IsVerbose;
+
+  bool Passed =
+      runTests<acoshf>(Generator, Configs, DeviceBinaryDir, IsVerbose);
+
+  return Passed ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/offload/unittests/Conformance/tests/AsinfTest.cpp b/offload/unittests/Conformance/tests/AsinfTest.cpp
new file mode 100644
index 0000000000000..991f79b111efe
--- /dev/null
+++ b/offload/unittests/Conformance/tests/AsinfTest.cpp
@@ -0,0 +1,53 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 asinf function.
+///
+//===----------------------------------------------------------------------===//
+
+#include "mathtest/CommandLineExtras.hpp"
+#include "mathtest/ExhaustiveGenerator.hpp"
+#include "mathtest/IndexedRange.hpp"
+#include "mathtest/TestConfig.hpp"
+#include "mathtest/TestRunner.hpp"
+
+#include "llvm/ADT/StringRef.h"
+
+#include <cstdlib>
+#include <math.h>
+
+namespace mathtest {
+
+template <> struct FunctionConfig<asinf> {
+  static constexpr llvm::StringRef Name = "asinf";
+  static constexpr llvm::StringRef KernelName = "asinfKernel";
+
+  // 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;
+};
+} // namespace mathtest
+
+int main(int argc, const char **argv) {
+  llvm::cl::ParseCommandLineOptions(argc, argv,
+                                    "Conformance test of the asinf function");
+
+  using namespace mathtest;
+
+  IndexedRange<float> Range;
+  ExhaustiveGenerator<float> Generator(Range);
+
+  const auto Configs = cl::getTestConfigs();
+  const llvm::StringRef DeviceBinaryDir = DEVICE_BINARY_DIR;
+  const bool IsVerbose = cl::IsVerbose;
+
+  bool Passed = runTests<asinf>(Generator, Configs, DeviceBinaryDir, IsVerbose);
+
+  return Passed ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/offload/unittests/Conformance/tests/AsinhfTest.cpp b/offload/unittests/Conformance/tests/AsinhfTest.cpp
new file mode 100644
index 0000000000000..9439383772314
--- /dev/null
+++ b/offload/unittests/Conformance/tests/AsinhfTest.cpp
@@ -0,0 +1,54 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 asinhf function.
+///
+//===----------------------------------------------------------------------===//
+
+#include "mathtest/CommandLineExtras.hpp"
+#include "mathtest/ExhaustiveGenerator.hpp"
+#include "mathtest/IndexedRange.hpp"
+#include "mathtest/TestConfig.hpp"
+#include "mathtest/TestRunner.hpp"
+
+#include "llvm/ADT/StringRef.h"
+
+#include <cstdlib>
+#include <math.h>
+
+namespace mathtest {
+
+template <> struct FunctionConfig<asinhf> {
+  static constexpr llvm::StringRef Name = "asinhf";
+  static constexpr llvm::StringRef KernelName = "asinhfKernel";
+
+  // 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;
+};
+} // namespace mathtest
+
+int main(int argc, const char **argv) {
+  llvm::cl::ParseCommandLineOptions(argc, argv,
+                                    "Conformance test of the asinhf function");
+
+  using namespace mathtest;
+
+  IndexedRange<float> Range;
+  ExhaustiveGenerator<float> Generator(Range);
+
+  const auto Configs = cl::getTestConfigs();
+  const llvm::StringRef DeviceBinaryDir = DEVICE_BINARY_DIR;
+  const bool IsVerbose = cl::IsVerbose;
+
+  bool Passed =
+      runTests<asinhf>(Generator, Configs, DeviceBinaryDir, IsVerbose);
+
+  return Passed ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/offload/unittests/Conformance/tests/AtanfTest.cpp b/offload/unittests/Conformance/tests/AtanfTest.cpp
new file mode 100644
index 0000000000000..64068ef6bff0c
--- /dev/null
+++ b/offload/unittests/Conformance/tests/AtanfTest.cpp
@@ -0,0 +1,53 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 atanf function.
+///
+//===----------------------------------------------------------------------===//
+
+#include "mathtest/CommandLineExtras.hpp"
+#include "mathtest/ExhaustiveGenerator.hpp"
+#include "mathtest/IndexedRange.hpp"
+#include "mathtest/TestConfig.hpp"
+#include "mathtest/TestRunner.hpp"
+
+#include "llvm/ADT/StringRef.h"
+
+#include <cstdlib>
+#include <math.h>
+
+namespace mathtest {
+
+template <> struct FunctionConfig<atanf> {
+  static constexpr llvm::StringRef Name = "atanf";
+  static constexpr llvm::StringRef KernelName = "atanfKernel";
+
+  // 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 = 5;
+};
+} // namespace mathtest
+
+int main(int argc, const char **argv) {
+  llvm::cl::ParseCommandLineOptions(argc, argv,
+                                    "Conformance test of the atanf function");
+
+  using namespace mathtest;
+
+  IndexedRange<float> Range;
+  ExhaustiveGenerator<float> Generator(Range);
+
+  const auto Configs = cl::getTestConfigs();
+  const llvm::StringRef DeviceBinaryDir = DEVICE_BINARY_DIR;
+  const bool IsVerbose = cl::IsVerbose;
+
+  bool Passed = runTests<atanf>(Generator, Configs, DeviceBinaryDir, IsVerbose);
+
+  return Passed ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/offload/unittests/Conformance/tests/AtanhfTest.cpp b/offload/unittests/Conformance/tests/AtanhfTest.cpp
new file mode 100644
index 0000000000000..66b934c2f925e
--- /dev/null
+++ b/offload/unittests/Conformance/tests/AtanhfTest.cpp
@@ -0,0 +1,56 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 atanhf function.
+///
+//===----------------------------------------------------------------------===//
+
+#include "mathtest/CommandLineExtras.hpp"
+#include "mathtest/ExhaustiveGenerator.hpp"
+#include "mathtest/IndexedRange.hpp"
+#include "mathtest/TestConfig.hpp"
+#include "mathtest/TestRunner.hpp"
+
+#include "llvm/ADT/StringRef.h"
+
+#include <cstdlib>
+#include <math.h>
+
+namespace mathtest {
+
+template <> struct FunctionConfig<atanhf> {
+  static constexpr llvm::StringRef Name = "atanhf";
+  static constexpr llvm::StringRef KernelName = "atanhfKernel";
+
+  // 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 = 5;
+};
+} ...
[truncated]

@leandrolcampos
Copy link
Contributor Author

Test Results for Single-Precision Math Functions in llvm-libm on CUDA

Function ULP Tolerance Max ULP Distance Status
acosf 4 1 PASSED
acoshf 4 1 PASSED
asinf 4 1 PASSED
asinhf 4 1 PASSED
atanf 5 0 PASSED
atanhf 5 0 PASSED
cbrtf 2 0 PASSED
cosf 4 1 PASSED
coshf 4 0 PASSED
cospif 4 0 PASSED
erff 16 0 PASSED
expf 3 0 PASSED
exp10f 3 0 PASSED
exp2f 3 1 PASSED
expm1f 3 1 PASSED
logf 3 1 PASSED
log10f 3 1 PASSED
log1pf 2 1 PASSED
log2f 3 0 PASSED
sinf 4 1 PASSED
sincosf (sin part) 4 1 PASSED
sincosf (cos part) 4 1 PASSED
sinhf 4 1 PASSED
sinpif 4 0 PASSED
tanf 5 0 PASSED
tanhf 5 0 PASSED
tanpif 6 0 PASSED

Device: NVIDIA GeForce RTX 4070 Laptop GPU

Copy link
Contributor

@jhuber6 jhuber6 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly boilerplate, two nits.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants