diff --git a/sycl/include/sycl/stl_wrappers/__sycl_cmath_wrapper_impl.hpp b/sycl/include/sycl/stl_wrappers/__sycl_cmath_wrapper_impl.hpp index a888058bd3715..dc35e16361632 100644 --- a/sycl/include/sycl/stl_wrappers/__sycl_cmath_wrapper_impl.hpp +++ b/sycl/include/sycl/stl_wrappers/__sycl_cmath_wrapper_impl.hpp @@ -19,8 +19,6 @@ #define __SYCL_DEVICE_C \ extern "C" __attribute__((sycl_device_only, always_inline)) -// For std::enable_if, std::is_integral, std::is_floating_point, std::is_same, -// and std::conjunction #include // Promotion templates: the C++ standard library provides overloads that allow @@ -29,27 +27,29 @@ // When multiple floating point arguments are available passing arguments with // different precision should promote to the larger type. The template helpers // below provide the machinery to define these promoting overloads. -template || std::is_floating_point_v)> -struct __sycl_promote { -private: - // Integer types are promoted to double. - template - static std::enable_if_t, double> test(); - - // Floating point types are used as-is. - template - static std::enable_if_t, U> test(); - -public: - // We rely on dummy templated methods and decltype to select the right type - // based on the input T. - typedef decltype(test()) type; +template > struct __sycl_promote { + using type = double; }; // Variant without ::type to allow SFINAE for non-promotable types. template struct __sycl_promote {}; +// float and double are left as is +template <> struct __sycl_promote { + using type = float; +}; +template <> struct __sycl_promote { + using type = double; +}; +// long double is not supported yet, so we don't define it, +// letting it SFINAE away too. +// We don't provide these overloads to makes sure that +// mixed precision calls that include long double are +// resolved to the "host" overload (defined by the real ), +// matching the behavior without promotion. +// Our long double overloads would fail to compile because +// we'd be trying to call SPIR-V built-ins that don't support long double. + // With two or three parameters we need to promote integers and possibly // floating point types. We rely on operator+ with decltype to deduce the // overall promotion type. This is only needed if at least one of the parameter @@ -68,6 +68,9 @@ using __sycl_promote_t = // // TODO: Consider targets that don't have double support. // TODO: Enable long double support where possible. +// TODO: float16_t and bfloat16_t support if the standard library +// supports C++23. +// TODO: constexpr support for these functions (C++23, C++26) // // The following two macros provide an easy way to define these overloads for // basic built-ins with one or two floating-point parameters. diff --git a/sycl/test/check_device_code/math-builtins/cmath-fallback-ld.cpp b/sycl/test/check_device_code/math-builtins/cmath-fallback-ld.cpp new file mode 100644 index 0000000000000..ad92f190e7c49 --- /dev/null +++ b/sycl/test/check_device_code/math-builtins/cmath-fallback-ld.cpp @@ -0,0 +1,19 @@ +// Note: This isn't really target specific and should be switched to spir when +// it's enabled for it. + +// RUN: %clang -fsycl -fsyntax-only -fsycl-targets=nvptx64-nvidia-cuda -nocudalib %s + +// Check that mixed calls with long double don't cause compile errors on the +// device. Long double is not supported on the device for cmath built-ins. We +// can't make this an error during overload resolution, because in SYCL all +// functions are semantically checked for both host and device. + +#include + +long double f(double f, double d, long double ld, int *pi) { + long double r = 0.l; + r = std::fmod(d, ld); + r = std::remquo(d, ld, pi); + r = std::fma(f, d, ld); + return r; +}