https://github.com/kmpeng created https://github.com/llvm/llvm-project/pull/138182
Closes #99133. Implemented `ldexp` entirely in `hlsl_intrinsics.h` and `hlsl_intrinsic_helpers.h`, added coresponding tests in `clang/test/CodeGenHLSL/builtins/ldexp.hlsl` and `clang/test/SemaHLSL/BuiltIns/ldexp-errors.hlsl`. >From d5187a940fc0a16325eedb0c67bcf647deb95d8f Mon Sep 17 00:00:00 2001 From: kmpeng <kaitlinp...@microsoft.com> Date: Thu, 1 May 2025 11:48:47 -0700 Subject: [PATCH] ldexp implementation and tests --- .../lib/Headers/hlsl/hlsl_intrinsic_helpers.h | 4 ++ clang/lib/Headers/hlsl/hlsl_intrinsics.h | 41 ++++++++++++++++ clang/test/CodeGenHLSL/builtins/ldexp.hlsl | 49 +++++++++++++++++++ .../test/SemaHLSL/BuiltIns/ldexp-errors.hlsl | 39 +++++++++++++++ 4 files changed, 133 insertions(+) create mode 100644 clang/test/CodeGenHLSL/builtins/ldexp.hlsl create mode 100644 clang/test/SemaHLSL/BuiltIns/ldexp-errors.hlsl diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h b/clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h index 3180492b7de36..4eb7b8f45c85a 100644 --- a/clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h +++ b/clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h @@ -134,6 +134,10 @@ template <typename T> constexpr T faceforward_impl(T N, T I, T Ng) { #endif } +template <typename T> constexpr T ldexp_impl(T X, T Exp) { + return exp2(Exp) * X; +} + } // namespace __detail } // namespace hlsl diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h index 193e7e6e99498..ffeb09bb49bef 100644 --- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h +++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h @@ -303,6 +303,47 @@ fmod(__detail::HLSL_FIXED_VECTOR<float, N> X, return __detail::fmod_vec_impl(X, Y); } +//===----------------------------------------------------------------------===// +// ldexp builtins +//===----------------------------------------------------------------------===// + +/// \fn T ldexp(T X, T Exp) +/// \brief Returns the result of multiplying \a X by two, raised to the power of \a Exp. +/// \param X [in] The specified value. +/// \param Exp [in] The specified exponent. +/// +/// This function uses the following formula: X * 2^Exp + +template <typename T> +_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2) +const inline __detail::enable_if_t<__detail::is_arithmetic<T>::Value && + __detail::is_same<half, T>::value, + T> ldexp(T X, T Exp) { + return __detail::ldexp_impl(X, Exp); +} + +template <typename T> +const inline __detail::enable_if_t< + __detail::is_arithmetic<T>::Value && __detail::is_same<float, T>::value, T> +ldexp(T X, T Exp) { + return __detail::ldexp_impl(X, Exp); +} + +template <int N> +_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2) +const inline __detail::HLSL_FIXED_VECTOR<half, N> ldexp( + __detail::HLSL_FIXED_VECTOR<half, N> X, + __detail::HLSL_FIXED_VECTOR<half, N> Exp) { + return __detail::ldexp_impl(X, Exp); +} + +template <int N> +const inline __detail::HLSL_FIXED_VECTOR<float, N> +ldexp(__detail::HLSL_FIXED_VECTOR<float, N> X, + __detail::HLSL_FIXED_VECTOR<float, N> Exp) { + return __detail::ldexp_impl(X, Exp); +} + //===----------------------------------------------------------------------===// // length builtins //===----------------------------------------------------------------------===// diff --git a/clang/test/CodeGenHLSL/builtins/ldexp.hlsl b/clang/test/CodeGenHLSL/builtins/ldexp.hlsl new file mode 100644 index 0000000000000..6a6c04318f805 --- /dev/null +++ b/clang/test/CodeGenHLSL/builtins/ldexp.hlsl @@ -0,0 +1,49 @@ +// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple dxil-pc-shadermodel6.3-library %s -fnative-half-type -emit-llvm -o - | FileCheck %s + +// CHECK-LABEL: test_ldexp_half +// CHECK: %elt.exp2.i = call reassoc nnan ninf nsz arcp afn half @llvm.exp2.f16(half %{{.*}}) +// CHECK: %mul.i = fmul reassoc nnan ninf nsz arcp afn half %elt.exp2.i, %{{.*}} +// CHECK: ret half %mul.i +half test_ldexp_half(half X, half Exp) { return ldexp(X, Exp); } + +// CHECK-LABEL: test_ldexp_half2 +// CHECK: %elt.exp2.i = call reassoc nnan ninf nsz arcp afn <2 x half> @llvm.exp2.v2f16(<2 x half> %{{.*}}) +// CHECK: %mul.i = fmul reassoc nnan ninf nsz arcp afn <2 x half> %elt.exp2.i, %{{.*}} +// CHECK: ret <2 x half> %mul.i +half2 test_ldexp_half2(half2 X, half2 Exp) { return ldexp(X, Exp); } + +// CHECK-LABEL: test_ldexp_half3 +// CHECK: %elt.exp2.i = call reassoc nnan ninf nsz arcp afn <3 x half> @llvm.exp2.v3f16(<3 x half> %{{.*}}) +// CHECK: %mul.i = fmul reassoc nnan ninf nsz arcp afn <3 x half> %elt.exp2.i, %{{.*}} +// CHECK: ret <3 x half> %mul.i +half3 test_ldexp_half3(half3 X, half3 Exp) { return ldexp(X, Exp); } + +// CHECK-LABEL: test_ldexp_half4 +// CHECK: %elt.exp2.i = call reassoc nnan ninf nsz arcp afn <4 x half> @llvm.exp2.v4f16(<4 x half> %{{.*}}) +// CHECK: %mul.i = fmul reassoc nnan ninf nsz arcp afn <4 x half> %elt.exp2.i, %{{.*}} +// CHECK: ret <4 x half> %mul.i +half4 test_ldexp_half4(half4 X, half4 Exp) { return ldexp(X, Exp); } + +// CHECK-LABEL: test_ldexp_float +// CHECK: %elt.exp2.i = call reassoc nnan ninf nsz arcp afn float @llvm.exp2.f32(float %{{.*}}) +// CHECK: %mul.i = fmul reassoc nnan ninf nsz arcp afn float %elt.exp2.i, %{{.*}} +// CHECK: ret float %mul.i +float test_ldexp_float(float X, float Exp) { return ldexp(X, Exp); } + +// CHECK-LABEL: test_ldexp_float2 +// CHECK: %elt.exp2.i = call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.exp2.v2f32(<2 x float> %{{.*}}) +// CHECK: %mul.i = fmul reassoc nnan ninf nsz arcp afn <2 x float> %elt.exp2.i, %{{.*}} +// CHECK: ret <2 x float> %mul.i +float2 test_ldexp_float2(float2 X, float2 Exp) { return ldexp(X, Exp); } + +// CHECK-LABEL: test_ldexp_float3 +// CHECK: %elt.exp2.i = call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.exp2.v3f32(<3 x float> %{{.*}}) +// CHECK: %mul.i = fmul reassoc nnan ninf nsz arcp afn <3 x float> %elt.exp2.i, %{{.*}} +// CHECK: ret <3 x float> %mul.i +float3 test_ldexp_float3(float3 X, float3 Exp) { return ldexp(X, Exp); } + +// CHECK-LABEL: test_ldexp_float4 +// CHECK: %elt.exp2.i = call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.exp2.v4f32(<4 x float> %{{.*}}) +// CHECK: %mul.i = fmul reassoc nnan ninf nsz arcp afn <4 x float> %elt.exp2.i, %{{.*}} +// CHECK: ret <4 x float> %mul.i +float4 test_ldexp_float4(float4 X, float4 Exp) { return ldexp(X, Exp); } diff --git a/clang/test/SemaHLSL/BuiltIns/ldexp-errors.hlsl b/clang/test/SemaHLSL/BuiltIns/ldexp-errors.hlsl new file mode 100644 index 0000000000000..0bc7f7e40f5d3 --- /dev/null +++ b/clang/test/SemaHLSL/BuiltIns/ldexp-errors.hlsl @@ -0,0 +1,39 @@ +// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -fnative-half-type -emit-llvm-only -disable-llvm-passes -verify + +float test_double_inputs(double p0, double p1) { + return ldexp(p0, p1); + // expected-error@-1 {{no matching function for call to 'ldexp'}} + // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored}} + // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored}} + // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored}} + // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored}} +} + +float test_int_inputs(int p0, int p1, int p2) { + return ldexp(p0, p1); + // expected-error@-1 {{no matching function for call to 'ldexp'}} + // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored}} + // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored}} + // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored}} + // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored}} +} + +float1 test_vec1_inputs(float1 p0, float1 p1) { + return ldexp(p0, p1); + // expected-error@-1 {{no matching function for call to 'ldexp'}} + // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored: substitution failure [with T = float1]: no type named 'Type' in 'hlsl::__detail::enable_if<false, vector<float, 1>>'}} + // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored: substitution failure [with T = float1]: no type named 'Type' in 'hlsl::__detail::enable_if<false, vector<float, 1>>'}} + // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored: substitution failure [with N = 1]: no type named 'Type' in 'hlsl::__detail::enable_if<false, half>'}} + // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored: substitution failure [with N = 1]: no type named 'Type' in 'hlsl::__detail::enable_if<false, float>'}} +} + +typedef float float5 __attribute__((ext_vector_type(5))); + +float5 test_vec5_inputs(float5 p0, float5 p1) { + return ldexp(p0, p1); + // expected-error@-1 {{no matching function for call to 'ldexp'}} + // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored: substitution failure [with T = float5]: no type named 'Type' in 'hlsl::__detail::enable_if<false, vector<float, 5>>'}} + // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored: substitution failure [with T = float5]: no type named 'Type' in 'hlsl::__detail::enable_if<false, vector<float, 5>>'}} + // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored: substitution failure [with N = 5]: no type named 'Type' in 'hlsl::__detail::enable_if<false, half>'}} + // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored: substitution failure [with N = 5]: no type named 'Type' in 'hlsl::__detail::enable_if<false, float>'}} +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits