Skip to content

Commit 121c876

Browse files
[SYCL][NVPTX][AMDGCN] Fix compilation for cmath long double (#19558)
Make sure to not define `long double` wrappers in the cmath wrapper. We unintentionally defined these for two or three argument functions with mixed types. These definitions fail to compile if we try to use them, because there are no SPIR-V builtins for long double. By not defining them, overload resolution will pick the "host" versions. We can't make overload resolution fail, because function bodies that are not called on the device still need to be semantically valid for the device. This was discovered by the SYCL CTS, in its reference implementation for the builtins. That code is never called on the device, but it needs to compile without errors. --------- Co-authored-by: Steffen Larsen <[email protected]>
1 parent 63c70a1 commit 121c876

File tree

2 files changed

+40
-18
lines changed

2 files changed

+40
-18
lines changed

sycl/include/sycl/stl_wrappers/__sycl_cmath_wrapper_impl.hpp

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@
1919
#define __SYCL_DEVICE_C \
2020
extern "C" __attribute__((sycl_device_only, always_inline))
2121

22-
// For std::enable_if, std::is_integral, std::is_floating_point, std::is_same,
23-
// and std::conjunction
2422
#include <type_traits>
2523

2624
// Promotion templates: the C++ standard library provides overloads that allow
@@ -29,27 +27,29 @@
2927
// When multiple floating point arguments are available passing arguments with
3028
// different precision should promote to the larger type. The template helpers
3129
// below provide the machinery to define these promoting overloads.
32-
template <typename T,
33-
bool = (std::is_integral_v<T> || std::is_floating_point_v<T>)>
34-
struct __sycl_promote {
35-
private:
36-
// Integer types are promoted to double.
37-
template <typename U>
38-
static std::enable_if_t<std::is_integral_v<U>, double> test();
39-
40-
// Floating point types are used as-is.
41-
template <typename U>
42-
static std::enable_if_t<std::is_floating_point_v<U>, U> test();
43-
44-
public:
45-
// We rely on dummy templated methods and decltype to select the right type
46-
// based on the input T.
47-
typedef decltype(test<T>()) type;
30+
template <typename T, bool = std::is_integral_v<T>> struct __sycl_promote {
31+
using type = double;
4832
};
4933

5034
// Variant without ::type to allow SFINAE for non-promotable types.
5135
template <typename T> struct __sycl_promote<T, false> {};
5236

37+
// float and double are left as is
38+
template <> struct __sycl_promote<float> {
39+
using type = float;
40+
};
41+
template <> struct __sycl_promote<double> {
42+
using type = double;
43+
};
44+
// long double is not supported yet, so we don't define it,
45+
// letting it SFINAE away too.
46+
// We don't provide these overloads to makes sure that
47+
// mixed precision calls that include long double are
48+
// resolved to the "host" overload (defined by the real <cmath>),
49+
// matching the behavior without promotion.
50+
// Our long double overloads would fail to compile because
51+
// we'd be trying to call SPIR-V built-ins that don't support long double.
52+
5353
// With two or three parameters we need to promote integers and possibly
5454
// floating point types. We rely on operator+ with decltype to deduce the
5555
// overall promotion type. This is only needed if at least one of the parameter
@@ -68,6 +68,9 @@ using __sycl_promote_t =
6868
//
6969
// TODO: Consider targets that don't have double support.
7070
// TODO: Enable long double support where possible.
71+
// TODO: float16_t and bfloat16_t support if the standard library
72+
// supports C++23.
73+
// TODO: constexpr support for these functions (C++23, C++26)
7174
//
7275
// The following two macros provide an easy way to define these overloads for
7376
// basic built-ins with one or two floating-point parameters.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Note: This isn't really target specific and should be switched to spir when
2+
// it's enabled for it.
3+
4+
// RUN: %clang -fsycl -fsyntax-only -fsycl-targets=nvptx64-nvidia-cuda -nocudalib %s
5+
6+
// Check that mixed calls with long double don't cause compile errors on the
7+
// device. Long double is not supported on the device for cmath built-ins. We
8+
// can't make this an error during overload resolution, because in SYCL all
9+
// functions are semantically checked for both host and device.
10+
11+
#include <cmath>
12+
13+
long double f(double f, double d, long double ld, int *pi) {
14+
long double r = 0.l;
15+
r = std::fmod(d, ld);
16+
r = std::remquo(d, ld, pi);
17+
r = std::fma(f, d, ld);
18+
return r;
19+
}

0 commit comments

Comments
 (0)