-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[HLSL] Make casting functions constexpr #108902
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
[HLSL] Make casting functions constexpr #108902
Conversation
This marks the `bit_cast` helper as `constexpr` and allows the casts implemented with it to also be `constexpr`. This is largely not a functional change, but it enables using the casts in expressions that need to be resolved at compile time as demonstrated with the static asserts in the new tests.
@llvm/pr-subscribers-hlsl @llvm/pr-subscribers-backend-x86 Author: Chris B (llvm-beanz) ChangesThis marks the Full diff: https://github.com/llvm/llvm-project/pull/108902.diff 5 Files Affected:
diff --git a/clang/lib/Headers/hlsl/hlsl_detail.h b/clang/lib/Headers/hlsl/hlsl_detail.h
index 9801d86208159f..40849dcdf187e4 100644
--- a/clang/lib/Headers/hlsl/hlsl_detail.h
+++ b/clang/lib/Headers/hlsl/hlsl_detail.h
@@ -13,23 +13,23 @@ namespace hlsl {
namespace __detail {
-#define _HLSL_INLINE \
- __attribute__((__always_inline__, __nodebug__)) static inline
-
template <bool B, typename T> struct enable_if {};
template <typename T> struct enable_if<true, T> {
using Type = T;
};
+template <bool B, class T = void>
+using enable_if_t = typename enable_if<B, T>::Type;
+
template <typename U, typename T, int N>
-_HLSL_INLINE typename enable_if<sizeof(U) == sizeof(T), vector<U, N> >::Type
+constexpr enable_if_t<sizeof(U) == sizeof(T), vector<U, N> >
bit_cast(vector<T, N> V) {
return __builtin_bit_cast(vector<U, N>, V);
}
template <typename U, typename T>
-_HLSL_INLINE typename enable_if<sizeof(U) == sizeof(T), U>::Type bit_cast(T F) {
+constexpr enable_if_t<sizeof(U) == sizeof(T), U> bit_cast(T F) {
return __builtin_bit_cast(U, F);
}
diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h
index 6a50d50ebd3479..12f58ef0718695 100644
--- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h
+++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h
@@ -370,11 +370,11 @@ bool any(double4);
/// \param Val The input value.
template <typename T, int N>
-_HLSL_INLINE vector<float, N> asfloat(vector<T, N> V) {
+constexpr vector<float, N> asfloat(vector<T, N> V) {
return __detail::bit_cast<float, T, N>(V);
}
-template <typename T> _HLSL_INLINE float asfloat(T F) {
+template <typename T> constexpr float asfloat(T F) {
return __detail::bit_cast<float, T>(F);
}
@@ -415,11 +415,11 @@ float4 asin(float4);
/// \param Val The input value.
template <typename T, int N>
-_HLSL_INLINE vector<uint, N> asuint(vector<T, N> V) {
+constexpr vector<uint, N> asuint(vector<T, N> V) {
return __detail::bit_cast<uint, T, N>(V);
}
-template <typename T> _HLSL_INLINE uint asuint(T F) {
+template <typename T> constexpr uint asuint(T F) {
return __detail::bit_cast<uint, T>(F);
}
diff --git a/clang/test/CodeGenHLSL/builtins/asuint.hlsl b/clang/test/CodeGenHLSL/builtins/asuint.hlsl
index ac3dae26d6caed..252a434ccce0dc 100644
--- a/clang/test/CodeGenHLSL/builtins/asuint.hlsl
+++ b/clang/test/CodeGenHLSL/builtins/asuint.hlsl
@@ -1,40 +1,40 @@
// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple dxil-pc-shadermodel6.3-library %s -fnative-half-type -emit-llvm -O1 -o - | FileCheck %s
-// CHECK: define {{.*}}test_uint{{.*}}(i32 {{.*}} [[VAL:%.*]]){{.*}}
+// CHECK: define {{.*}}test_uint{{.*}}(i32 {{.*}} [[VAL:%.*]]){{.*}}
// CHECK-NOT: bitcast
// CHECK: ret i32 [[VAL]]
uint test_uint(uint p0) {
return asuint(p0);
}
-// CHECK: define {{.*}}test_int{{.*}}(i32 {{.*}} [[VAL:%.*]]){{.*}}
+// CHECK: define {{.*}}test_int{{.*}}(i32 {{.*}} [[VAL:%.*]]){{.*}}
// CHECK-NOT: bitcast
// CHECK: ret i32 [[VAL]]
uint test_int(int p0) {
return asuint(p0);
}
-// CHECK: define {{.*}}test_float{{.*}}(float {{.*}} [[VAL:%.*]]){{.*}}
+// CHECK: define {{.*}}test_float{{.*}}(float {{.*}} [[VAL:%.*]]){{.*}}
// CHECK: bitcast float [[VAL]] to i32
uint test_float(float p0) {
return asuint(p0);
}
-// CHECK: define {{.*}}test_vector_uint{{.*}}(<4 x i32> {{.*}} [[VAL:%.*]]){{.*}}
+// CHECK: define {{.*}}test_vector_uint{{.*}}(<4 x i32> {{.*}} [[VAL:%.*]]){{.*}}
// CHECK-NOT: bitcast
// CHECK: ret <4 x i32> [[VAL]]
uint4 test_vector_uint(uint4 p0) {
return asuint(p0);
}
-// CHECK: define {{.*}}test_vector_int{{.*}}(<4 x i32> {{.*}} [[VAL:%.*]]){{.*}}
+// CHECK: define {{.*}}test_vector_int{{.*}}(<4 x i32> {{.*}} [[VAL:%.*]]){{.*}}
// CHECK-NOT: bitcast
// CHECK: ret <4 x i32> [[VAL]]
uint4 test_vector_int(int4 p0) {
return asuint(p0);
}
-// CHECK: define {{.*}}test_vector_float{{.*}}(<4 x float> {{.*}} [[VAL:%.*]]){{.*}}
+// CHECK: define {{.*}}test_vector_float{{.*}}(<4 x float> {{.*}} [[VAL:%.*]]){{.*}}
// CHECK: bitcast <4 x float> [[VAL]] to <4 x i32>
uint4 test_vector_float(float4 p0) {
return asuint(p0);
diff --git a/clang/test/SemaHLSL/BuiltIns/asfloat-constexpr.hlsl b/clang/test/SemaHLSL/BuiltIns/asfloat-constexpr.hlsl
new file mode 100644
index 00000000000000..b2a54d23173e57
--- /dev/null
+++ b/clang/test/SemaHLSL/BuiltIns/asfloat-constexpr.hlsl
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -verify
+
+// expected-no-diagnostics
+
+// Because asuint should be constant evaluated, all the static asserts below
+// should work!
+void ConstExprTest() {
+ static_assert(asfloat(0x3f800000) == 1.0f, "One");
+ static_assert(asfloat(0x40000000.xxx).y == 2.0f, "Two");
+}
diff --git a/clang/test/SemaHLSL/BuiltIns/asuint-constexpr.hlsl b/clang/test/SemaHLSL/BuiltIns/asuint-constexpr.hlsl
new file mode 100644
index 00000000000000..be6afda3be6636
--- /dev/null
+++ b/clang/test/SemaHLSL/BuiltIns/asuint-constexpr.hlsl
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -verify
+
+// expected-no-diagnostics
+
+// Because asuint should be constant evaluated, all the static asserts below
+// should work!
+void ConstExprTest() {
+ static_assert(asuint(1) == 1u, "One");
+ static_assert(asuint(2.xxx).y == 2u, "Two");
+}
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
Co-authored-by: joaosaffran <[email protected]>
#define _HLSL_INLINE \ | ||
__attribute__((__always_inline__, __nodebug__)) static inline |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that while constexpr implies inline
and since it also implies const
dropping static here is fine too, we are dropping the two attributes here.
always_inlineshouldn't matter, but dropping
nodebugpresumably does have an effect. I don't fully understand what
nodebug` is gaining us though, and if we really want to use it we should probably do that more systematically in this header anyway, so this all seems fine.
This marks the
bit_cast
helper asconstexpr
and allows the casts implemented with it to also beconstexpr
. This is largely not a functional change, but it enables using the casts in expressions that need to be resolved at compile time as demonstrated with the static asserts in the new tests.