[clang] [llvm] [HLSL] Implement the `reflect` HLSL function (PR #122992)
Deric Cheung via llvm-commits
llvm-commits at lists.llvm.org
Fri Jan 17 16:35:26 PST 2025
https://github.com/Icohedron updated https://github.com/llvm/llvm-project/pull/122992
>From 7ddd5b264731ef375d99d012d9fbfd54c744e5b2 Mon Sep 17 00:00:00 2001
From: Icohedron <cheung.deric at gmail.com>
Date: Mon, 13 Jan 2025 21:23:31 +0000
Subject: [PATCH 1/5] Implement `reflect` HLSL function
---
clang/include/clang/Basic/BuiltinsSPIRV.td | 6 +
clang/lib/CodeGen/CGBuiltin.cpp | 13 ++
clang/lib/Headers/hlsl/hlsl_detail.h | 17 ++
clang/lib/Headers/hlsl/hlsl_intrinsics.h | 43 ++++
clang/lib/Sema/SemaSPIRV.cpp | 32 +++
clang/test/CodeGenHLSL/builtins/reflect.hlsl | 195 ++++++++++++++++++
clang/test/CodeGenSPIRV/Builtins/reflect.c | 32 +++
.../SemaHLSL/BuiltIns/reflect-errors.hlsl | 33 +++
.../test/SemaSPIRV/BuiltIns/reflect-errors.c | 23 +++
llvm/include/llvm/IR/IntrinsicsSPIRV.td | 1 +
.../Target/SPIRV/SPIRVInstructionSelector.cpp | 2 +
.../CodeGen/SPIRV/hlsl-intrinsics/reflect.ll | 33 +++
12 files changed, 430 insertions(+)
create mode 100644 clang/test/CodeGenHLSL/builtins/reflect.hlsl
create mode 100644 clang/test/CodeGenSPIRV/Builtins/reflect.c
create mode 100644 clang/test/SemaHLSL/BuiltIns/reflect-errors.hlsl
create mode 100644 clang/test/SemaSPIRV/BuiltIns/reflect-errors.c
create mode 100644 llvm/test/CodeGen/SPIRV/hlsl-intrinsics/reflect.ll
diff --git a/clang/include/clang/Basic/BuiltinsSPIRV.td b/clang/include/clang/Basic/BuiltinsSPIRV.td
index f72c555921dfe68..34933e889ba314b 100644
--- a/clang/include/clang/Basic/BuiltinsSPIRV.td
+++ b/clang/include/clang/Basic/BuiltinsSPIRV.td
@@ -19,3 +19,9 @@ def SPIRVLength : Builtin {
let Attributes = [NoThrow, Const];
let Prototype = "void(...)";
}
+
+def SPIRVReflect : Builtin {
+ let Spellings = ["__builtin_spirv_reflect"];
+ let Attributes = [NoThrow, Const];
+ let Prototype = "void(...)";
+}
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index b80833fd91884d8..ab61609ab35a99f 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -20538,6 +20538,19 @@ Value *CodeGenFunction::EmitSPIRVBuiltinExpr(unsigned BuiltinID,
/*ReturnType=*/X->getType()->getScalarType(), Intrinsic::spv_length,
ArrayRef<Value *>{X}, nullptr, "spv.length");
}
+ case SPIRV::BI__builtin_spirv_reflect: {
+ Value *I = EmitScalarExpr(E->getArg(0));
+ Value *N = EmitScalarExpr(E->getArg(1));
+ assert(E->getArg(0)->getType()->hasFloatingRepresentation() &&
+ E->getArg(1)->getType()->hasFloatingRepresentation() &&
+ "Reflect operands must have a float representation");
+ assert(E->getArg(0)->getType()->isVectorType() &&
+ E->getArg(1)->getType()->isVectorType() &&
+ "Reflect operands must be a vector");
+ return Builder.CreateIntrinsic(
+ /*ReturnType=*/I->getType(), Intrinsic::spv_reflect,
+ ArrayRef<Value *>{I, N}, nullptr, "spv.reflect");
+ }
}
return nullptr;
}
diff --git a/clang/lib/Headers/hlsl/hlsl_detail.h b/clang/lib/Headers/hlsl/hlsl_detail.h
index b2c8cc6c5c3dbb0..3e09f8b10735122 100644
--- a/clang/lib/Headers/hlsl/hlsl_detail.h
+++ b/clang/lib/Headers/hlsl/hlsl_detail.h
@@ -79,6 +79,23 @@ constexpr enable_if_t<is_same<float, T>::value || is_same<half, T>::value, T>
distance_vec_impl(vector<T, N> X, vector<T, N> Y) {
return length_vec_impl(X - Y);
}
+
+template <typename T>
+constexpr enable_if_t<is_same<float, T>::value || is_same<half, T>::value, T>
+reflect_impl(T I, T N) {
+ return I - 2 * N * I * N;
+}
+
+template <typename T, int L>
+constexpr enable_if_t<is_same<float, T>::value || is_same<half, T>::value, T>
+reflect_vec_impl(vector<T, L> I, vector<T, L> N) {
+#if (__has_builtin(__builtin_spirv_reflect))
+ return __builtin_spirv_reflect(I, N);
+#else
+ return I - 2 * N * __builtin_hlsl_dot(I, N);
+#endif
+}
+
} // namespace __detail
} // namespace hlsl
#endif //_HLSL_HLSL_DETAILS_H_
diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h
index d1e4eb08aa7646a..54454cf0ea0d0bd 100644
--- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h
+++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h
@@ -2008,6 +2008,49 @@ double3 rcp(double3);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_rcp)
double4 rcp(double4);
+//===----------------------------------------------------------------------===//
+// reflect builtin
+//===----------------------------------------------------------------------===//
+
+/// \fn T reflect(T I, T N)
+/// \brief Returns a reflection using an incident ray, \a I, and a surface
+/// normal, \a N.
+/// \param I The incident ray.
+/// \param N The surface normal.
+///
+/// The return value is a floating-point vector that represents the reflection
+/// of the incident ray, \a I, off a surface with the normal \a N.
+///
+/// This function calculates the reflection vector using the following formula:
+/// V = I - 2 * N * dot(I N) .
+///
+/// N must already be normalized in order to achieve the desired result.
+///
+/// The operands must all be a scalar or vector whose component type is
+/// floating-point.
+///
+/// Result type and the type of all operands must be the same type.
+
+_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
+const inline half reflect(half I, half N) {
+ return __detail::reflect_impl(I, N);
+}
+
+const inline float reflect(float I, float N) {
+ return __detail::reflect_impl(I, N);
+}
+
+template <int L>
+_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
+const inline half reflect(vector<half, L> I, vector<half, L> N) {
+ return __detail::reflect_vec_impl(I, N);
+}
+
+template <int L>
+const inline float reflect(vector<float, L> I, vector<float, L> N) {
+ return __detail::reflect_vec_impl(I, N);
+}
+
//===----------------------------------------------------------------------===//
// rsqrt builtins
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/Sema/SemaSPIRV.cpp b/clang/lib/Sema/SemaSPIRV.cpp
index dc49fc79073572e..94534485e07c330 100644
--- a/clang/lib/Sema/SemaSPIRV.cpp
+++ b/clang/lib/Sema/SemaSPIRV.cpp
@@ -69,6 +69,38 @@ bool SemaSPIRV::CheckSPIRVBuiltinFunctionCall(unsigned BuiltinID,
TheCall->setType(RetTy);
break;
}
+ case SPIRV::BI__builtin_spirv_reflect: {
+ if (SemaRef.checkArgCount(TheCall, 2))
+ return true;
+
+ ExprResult A = TheCall->getArg(0);
+ QualType ArgTyA = A.get()->getType();
+ auto *VTyA = ArgTyA->getAs<VectorType>();
+ if (VTyA == nullptr) {
+ SemaRef.Diag(A.get()->getBeginLoc(),
+ diag::err_typecheck_convert_incompatible)
+ << ArgTyA
+ << SemaRef.Context.getVectorType(ArgTyA, 2, VectorKind::Generic) << 1
+ << 0 << 0;
+ return true;
+ }
+
+ ExprResult B = TheCall->getArg(1);
+ QualType ArgTyB = B.get()->getType();
+ auto *VTyB = ArgTyB->getAs<VectorType>();
+ if (VTyB == nullptr) {
+ SemaRef.Diag(A.get()->getBeginLoc(),
+ diag::err_typecheck_convert_incompatible)
+ << ArgTyB
+ << SemaRef.Context.getVectorType(ArgTyB, 2, VectorKind::Generic) << 1
+ << 0 << 0;
+ return true;
+ }
+
+ QualType RetTy = ArgTyA;
+ TheCall->setType(RetTy);
+ break;
+ }
}
return false;
}
diff --git a/clang/test/CodeGenHLSL/builtins/reflect.hlsl b/clang/test/CodeGenHLSL/builtins/reflect.hlsl
new file mode 100644
index 000000000000000..66d0a4b6f6a24a9
--- /dev/null
+++ b/clang/test/CodeGenHLSL/builtins/reflect.hlsl
@@ -0,0 +1,195 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5
+// RUN: %clang_cc1 -finclude-default-header -triple \
+// RUN: dxil-pc-shadermodel6.3-library %s -fnative-half-type \
+// RUN: -emit-llvm -O1 -o - | FileCheck %s
+// RUN: %clang_cc1 -finclude-default-header -triple \
+// RUN: spirv-unknown-vulkan-compute %s -fnative-half-type \
+// RUN: -emit-llvm -O1 -o - | FileCheck %s --check-prefix=SPVCHECK
+
+// CHECK-LABEL: define noundef nofpclass(nan inf) half @_Z17test_reflect_halfDhDh(
+// CHECK-SAME: half noundef nofpclass(nan inf) [[I:%.*]], half noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[MUL_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn half [[I]], 0xH4000
+// CHECK-NEXT: [[TMP0:%.*]] = fmul reassoc nnan ninf nsz arcp afn half [[N]], [[N]]
+// CHECK-NEXT: [[MUL2_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn half [[TMP0]], [[MUL_I]]
+// CHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn half [[I]], [[MUL2_I]]
+// CHECK-NEXT: ret half [[SUB_I]]
+//
+// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) half @_Z17test_reflect_halfDhDh(
+// SPVCHECK-SAME: half noundef nofpclass(nan inf) [[I:%.*]], half noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
+// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: [[MUL_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn half [[I]], 0xH4000
+// SPVCHECK-NEXT: [[TMP0:%.*]] = fmul reassoc nnan ninf nsz arcp afn half [[N]], [[N]]
+// SPVCHECK-NEXT: [[MUL2_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn half [[TMP0]], [[MUL_I]]
+// SPVCHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn half [[I]], [[MUL2_I]]
+// SPVCHECK-NEXT: ret half [[SUB_I]]
+//
+half test_reflect_half(half I, half N) {
+ return reflect(I, N);
+}
+
+// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x half> @_Z18test_reflect_half2Dv2_DhS_(
+// CHECK-SAME: <2 x half> noundef nofpclass(nan inf) [[I:%.*]], <2 x half> noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[HLSL_DOT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn half @llvm.dx.fdot.v2f16(<2 x half> [[I]], <2 x half> [[N]])
+// CHECK-NEXT: [[TMP0:%.*]] = extractelement <2 x half> [[I]], i64 0
+// CHECK-NEXT: [[TMP1:%.*]] = extractelement <2 x half> [[N]], i64 0
+// CHECK-NEXT: [[TMP2:%.*]] = fmul reassoc nnan ninf nsz arcp afn half [[TMP1]], 0xH4000
+// CHECK-NEXT: [[TMP3:%.*]] = fmul reassoc nnan ninf nsz arcp afn half [[TMP2]], [[HLSL_DOT_I]]
+// CHECK-NEXT: [[CAST_VTRUNC_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn half [[TMP0]], [[TMP3]]
+// CHECK-NEXT: [[SPLAT_SPLATINSERT:%.*]] = insertelement <2 x half> poison, half [[CAST_VTRUNC_I]], i64 0
+// CHECK-NEXT: [[SPLAT_SPLAT:%.*]] = shufflevector <2 x half> [[SPLAT_SPLATINSERT]], <2 x half> poison, <2 x i32> zeroinitializer
+// CHECK-NEXT: ret <2 x half> [[SPLAT_SPLAT]]
+//
+// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) <2 x half> @_Z18test_reflect_half2Dv2_DhS_(
+// SPVCHECK-SAME: <2 x half> noundef nofpclass(nan inf) [[I:%.*]], <2 x half> noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: [[SPV_REFLECT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn <2 x half> @llvm.spv.reflect.v2f16(<2 x half> [[I]], <2 x half> [[N]])
+// SPVCHECK-NEXT: [[SPLAT_SPLAT:%.*]] = shufflevector <2 x half> [[SPV_REFLECT_I]], <2 x half> poison, <2 x i32> zeroinitializer
+// SPVCHECK-NEXT: ret <2 x half> [[SPLAT_SPLAT]]
+//
+half2 test_reflect_half2(half2 I, half2 N) {
+ return reflect(I, N);
+}
+
+// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x half> @_Z18test_reflect_half3Dv3_DhS_(
+// CHECK-SAME: <3 x half> noundef nofpclass(nan inf) [[I:%.*]], <3 x half> noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[HLSL_DOT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn half @llvm.dx.fdot.v3f16(<3 x half> [[I]], <3 x half> [[N]])
+// CHECK-NEXT: [[TMP0:%.*]] = extractelement <3 x half> [[I]], i64 0
+// CHECK-NEXT: [[TMP1:%.*]] = extractelement <3 x half> [[N]], i64 0
+// CHECK-NEXT: [[TMP2:%.*]] = fmul reassoc nnan ninf nsz arcp afn half [[TMP1]], 0xH4000
+// CHECK-NEXT: [[TMP3:%.*]] = fmul reassoc nnan ninf nsz arcp afn half [[TMP2]], [[HLSL_DOT_I]]
+// CHECK-NEXT: [[CAST_VTRUNC_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn half [[TMP0]], [[TMP3]]
+// CHECK-NEXT: [[SPLAT_SPLATINSERT:%.*]] = insertelement <3 x half> poison, half [[CAST_VTRUNC_I]], i64 0
+// CHECK-NEXT: [[SPLAT_SPLAT:%.*]] = shufflevector <3 x half> [[SPLAT_SPLATINSERT]], <3 x half> poison, <3 x i32> zeroinitializer
+// CHECK-NEXT: ret <3 x half> [[SPLAT_SPLAT]]
+//
+// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) <3 x half> @_Z18test_reflect_half3Dv3_DhS_(
+// SPVCHECK-SAME: <3 x half> noundef nofpclass(nan inf) [[I:%.*]], <3 x half> noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: [[SPV_REFLECT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn <3 x half> @llvm.spv.reflect.v3f16(<3 x half> [[I]], <3 x half> [[N]])
+// SPVCHECK-NEXT: [[SPLAT_SPLAT:%.*]] = shufflevector <3 x half> [[SPV_REFLECT_I]], <3 x half> poison, <3 x i32> zeroinitializer
+// SPVCHECK-NEXT: ret <3 x half> [[SPLAT_SPLAT]]
+//
+half3 test_reflect_half3(half3 I, half3 N) {
+ return reflect(I, N);
+}
+
+// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x half> @_Z18test_reflect_half4Dv4_DhS_(
+// CHECK-SAME: <4 x half> noundef nofpclass(nan inf) [[I:%.*]], <4 x half> noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[HLSL_DOT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn half @llvm.dx.fdot.v4f16(<4 x half> [[I]], <4 x half> [[N]])
+// CHECK-NEXT: [[TMP0:%.*]] = extractelement <4 x half> [[I]], i64 0
+// CHECK-NEXT: [[TMP1:%.*]] = extractelement <4 x half> [[N]], i64 0
+// CHECK-NEXT: [[TMP2:%.*]] = fmul reassoc nnan ninf nsz arcp afn half [[TMP1]], 0xH4000
+// CHECK-NEXT: [[TMP3:%.*]] = fmul reassoc nnan ninf nsz arcp afn half [[TMP2]], [[HLSL_DOT_I]]
+// CHECK-NEXT: [[CAST_VTRUNC_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn half [[TMP0]], [[TMP3]]
+// CHECK-NEXT: [[SPLAT_SPLATINSERT:%.*]] = insertelement <4 x half> poison, half [[CAST_VTRUNC_I]], i64 0
+// CHECK-NEXT: [[SPLAT_SPLAT:%.*]] = shufflevector <4 x half> [[SPLAT_SPLATINSERT]], <4 x half> poison, <4 x i32> zeroinitializer
+// CHECK-NEXT: ret <4 x half> [[SPLAT_SPLAT]]
+//
+// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) <4 x half> @_Z18test_reflect_half4Dv4_DhS_(
+// SPVCHECK-SAME: <4 x half> noundef nofpclass(nan inf) [[I:%.*]], <4 x half> noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: [[SPV_REFLECT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn <4 x half> @llvm.spv.reflect.v4f16(<4 x half> [[I]], <4 x half> [[N]])
+// SPVCHECK-NEXT: [[SPLAT_SPLAT:%.*]] = shufflevector <4 x half> [[SPV_REFLECT_I]], <4 x half> poison, <4 x i32> zeroinitializer
+// SPVCHECK-NEXT: ret <4 x half> [[SPLAT_SPLAT]]
+//
+half4 test_reflect_half4(half4 I, half4 N) {
+ return reflect(I, N);
+}
+
+// CHECK-LABEL: define noundef nofpclass(nan inf) float @_Z18test_reflect_floatff(
+// CHECK-SAME: float noundef nofpclass(nan inf) [[I:%.*]], float noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[MUL_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn float [[I]], 2.000000e+00
+// CHECK-NEXT: [[TMP0:%.*]] = fmul reassoc nnan ninf nsz arcp afn float [[N]], [[N]]
+// CHECK-NEXT: [[MUL2_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn float [[TMP0]], [[MUL_I]]
+// CHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn float [[I]], [[MUL2_I]]
+// CHECK-NEXT: ret float [[SUB_I]]
+//
+// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) float @_Z18test_reflect_floatff(
+// SPVCHECK-SAME: float noundef nofpclass(nan inf) [[I:%.*]], float noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: [[MUL_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn float [[I]], 2.000000e+00
+// SPVCHECK-NEXT: [[TMP0:%.*]] = fmul reassoc nnan ninf nsz arcp afn float [[N]], [[N]]
+// SPVCHECK-NEXT: [[MUL2_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn float [[TMP0]], [[MUL_I]]
+// SPVCHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn float [[I]], [[MUL2_I]]
+// SPVCHECK-NEXT: ret float [[SUB_I]]
+//
+float test_reflect_float(float I, float N) {
+ return reflect(I, N);
+}
+
+// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> @_Z19test_reflect_float2Dv2_fS_(
+// CHECK-SAME: <2 x float> noundef nofpclass(nan inf) [[I:%.*]], <2 x float> noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[HLSL_DOT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn float @llvm.dx.fdot.v2f32(<2 x float> [[I]], <2 x float> [[N]])
+// CHECK-NEXT: [[TMP0:%.*]] = extractelement <2 x float> [[I]], i64 0
+// CHECK-NEXT: [[TMP1:%.*]] = extractelement <2 x float> [[N]], i64 0
+// CHECK-NEXT: [[TMP2:%.*]] = fmul reassoc nnan ninf nsz arcp afn float [[TMP1]], 2.000000e+00
+// CHECK-NEXT: [[TMP3:%.*]] = fmul reassoc nnan ninf nsz arcp afn float [[TMP2]], [[HLSL_DOT_I]]
+// CHECK-NEXT: [[CAST_VTRUNC_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn float [[TMP0]], [[TMP3]]
+// CHECK-NEXT: [[SPLAT_SPLATINSERT:%.*]] = insertelement <2 x float> poison, float [[CAST_VTRUNC_I]], i64 0
+// CHECK-NEXT: [[SPLAT_SPLAT:%.*]] = shufflevector <2 x float> [[SPLAT_SPLATINSERT]], <2 x float> poison, <2 x i32> zeroinitializer
+// CHECK-NEXT: ret <2 x float> [[SPLAT_SPLAT]]
+//
+// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) <2 x float> @_Z19test_reflect_float2Dv2_fS_(
+// SPVCHECK-SAME: <2 x float> noundef nofpclass(nan inf) [[I:%.*]], <2 x float> noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: [[SPV_REFLECT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.spv.reflect.v2f32(<2 x float> [[I]], <2 x float> [[N]])
+// SPVCHECK-NEXT: [[SPLAT_SPLAT:%.*]] = shufflevector <2 x float> [[SPV_REFLECT_I]], <2 x float> poison, <2 x i32> zeroinitializer
+// SPVCHECK-NEXT: ret <2 x float> [[SPLAT_SPLAT]]
+//
+float2 test_reflect_float2(float2 I, float2 N) {
+ return reflect(I, N);
+}
+
+// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> @_Z19test_reflect_float3Dv3_fS_(
+// CHECK-SAME: <3 x float> noundef nofpclass(nan inf) [[I:%.*]], <3 x float> noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[HLSL_DOT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn float @llvm.dx.fdot.v3f32(<3 x float> [[I]], <3 x float> [[N]])
+// CHECK-NEXT: [[TMP0:%.*]] = extractelement <3 x float> [[I]], i64 0
+// CHECK-NEXT: [[TMP1:%.*]] = extractelement <3 x float> [[N]], i64 0
+// CHECK-NEXT: [[TMP2:%.*]] = fmul reassoc nnan ninf nsz arcp afn float [[TMP1]], 2.000000e+00
+// CHECK-NEXT: [[TMP3:%.*]] = fmul reassoc nnan ninf nsz arcp afn float [[TMP2]], [[HLSL_DOT_I]]
+// CHECK-NEXT: [[CAST_VTRUNC_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn float [[TMP0]], [[TMP3]]
+// CHECK-NEXT: [[SPLAT_SPLATINSERT:%.*]] = insertelement <3 x float> poison, float [[CAST_VTRUNC_I]], i64 0
+// CHECK-NEXT: [[SPLAT_SPLAT:%.*]] = shufflevector <3 x float> [[SPLAT_SPLATINSERT]], <3 x float> poison, <3 x i32> zeroinitializer
+// CHECK-NEXT: ret <3 x float> [[SPLAT_SPLAT]]
+//
+// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) <3 x float> @_Z19test_reflect_float3Dv3_fS_(
+// SPVCHECK-SAME: <3 x float> noundef nofpclass(nan inf) [[I:%.*]], <3 x float> noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: [[SPV_REFLECT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.spv.reflect.v3f32(<3 x float> [[I]], <3 x float> [[N]])
+// SPVCHECK-NEXT: [[SPLAT_SPLAT:%.*]] = shufflevector <3 x float> [[SPV_REFLECT_I]], <3 x float> poison, <3 x i32> zeroinitializer
+// SPVCHECK-NEXT: ret <3 x float> [[SPLAT_SPLAT]]
+//
+float3 test_reflect_float3(float3 I, float3 N) {
+ return reflect(I, N);
+}
+
+// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> @_Z19test_reflect_float4Dv4_fS_(
+// CHECK-SAME: <4 x float> noundef nofpclass(nan inf) [[I:%.*]], <4 x float> noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[HLSL_DOT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn float @llvm.dx.fdot.v4f32(<4 x float> [[I]], <4 x float> [[N]])
+// CHECK-NEXT: [[TMP0:%.*]] = extractelement <4 x float> [[I]], i64 0
+// CHECK-NEXT: [[TMP1:%.*]] = extractelement <4 x float> [[N]], i64 0
+// CHECK-NEXT: [[TMP2:%.*]] = fmul reassoc nnan ninf nsz arcp afn float [[TMP1]], 2.000000e+00
+// CHECK-NEXT: [[TMP3:%.*]] = fmul reassoc nnan ninf nsz arcp afn float [[TMP2]], [[HLSL_DOT_I]]
+// CHECK-NEXT: [[CAST_VTRUNC_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn float [[TMP0]], [[TMP3]]
+// CHECK-NEXT: [[SPLAT_SPLATINSERT:%.*]] = insertelement <4 x float> poison, float [[CAST_VTRUNC_I]], i64 0
+// CHECK-NEXT: [[SPLAT_SPLAT:%.*]] = shufflevector <4 x float> [[SPLAT_SPLATINSERT]], <4 x float> poison, <4 x i32> zeroinitializer
+// CHECK-NEXT: ret <4 x float> [[SPLAT_SPLAT]]
+//
+// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) <4 x float> @_Z19test_reflect_float4Dv4_fS_(
+// SPVCHECK-SAME: <4 x float> noundef nofpclass(nan inf) [[I:%.*]], <4 x float> noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: [[SPV_REFLECT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.spv.reflect.v4f32(<4 x float> [[I]], <4 x float> [[N]])
+// SPVCHECK-NEXT: [[SPLAT_SPLAT:%.*]] = shufflevector <4 x float> [[SPV_REFLECT_I]], <4 x float> poison, <4 x i32> zeroinitializer
+// SPVCHECK-NEXT: ret <4 x float> [[SPLAT_SPLAT]]
+//
+float4 test_reflect_float4(float4 I, float4 N) {
+ return reflect(I, N);
+}
diff --git a/clang/test/CodeGenSPIRV/Builtins/reflect.c b/clang/test/CodeGenSPIRV/Builtins/reflect.c
new file mode 100644
index 000000000000000..f51ac27a07457a9
--- /dev/null
+++ b/clang/test/CodeGenSPIRV/Builtins/reflect.c
@@ -0,0 +1,32 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5
+
+// RUN: %clang_cc1 -O1 -triple spirv-pc-vulkan-compute %s -emit-llvm -o - | FileCheck %s
+
+typedef float float2 __attribute__((ext_vector_type(2)));
+typedef float float3 __attribute__((ext_vector_type(3)));
+typedef float float4 __attribute__((ext_vector_type(4)));
+
+// CHECK-LABEL: define spir_func <2 x float> @test_reflect_float2(
+// CHECK-SAME: <2 x float> noundef [[X:%.*]], <2 x float> noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[SPV_REFLECT:%.*]] = tail call <2 x float> @llvm.spv.reflect.v2f32(<2 x float> [[X]], <2 x float> [[Y]])
+// CHECK-NEXT: ret <2 x float> [[SPV_REFLECT]]
+//
+float2 test_reflect_float2(float2 X, float2 Y) { return __builtin_spirv_reflect(X, Y); }
+
+// CHECK-LABEL: define spir_func <3 x float> @test_reflect_float3(
+// CHECK-SAME: <3 x float> noundef [[X:%.*]], <3 x float> noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[SPV_REFLECT:%.*]] = tail call <3 x float> @llvm.spv.reflect.v3f32(<3 x float> [[X]], <3 x float> [[Y]])
+// CHECK-NEXT: ret <3 x float> [[SPV_REFLECT]]
+//
+float3 test_reflect_float3(float3 X, float3 Y) { return __builtin_spirv_reflect(X, Y); }
+
+// CHECK-LABEL: define spir_func <4 x float> @test_reflect_float4(
+// CHECK-SAME: <4 x float> noundef [[X:%.*]], <4 x float> noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[SPV_REFLECT:%.*]] = tail call <4 x float> @llvm.spv.reflect.v4f32(<4 x float> [[X]], <4 x float> [[Y]])
+// CHECK-NEXT: ret <4 x float> [[SPV_REFLECT]]
+//
+float4 test_reflect_float4(float4 X, float4 Y) { return __builtin_spirv_reflect(X, Y); }
+
diff --git a/clang/test/SemaHLSL/BuiltIns/reflect-errors.hlsl b/clang/test/SemaHLSL/BuiltIns/reflect-errors.hlsl
new file mode 100644
index 000000000000000..28cf992ed602bf6
--- /dev/null
+++ b/clang/test/SemaHLSL/BuiltIns/reflect-errors.hlsl
@@ -0,0 +1,33 @@
+// 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_no_second_arg(float2 p0) {
+ return reflect(p0);
+ // expected-error at -1 {{no matching function for call to 'reflect'}}
+ // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate function not viable: requires 2 arguments, but 1 was provided}}
+ // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate function not viable: requires 2 arguments, but 1 was provided}}
+ // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 2 arguments, but 1 was provided}}
+ // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 2 arguments, but 1 was provided}}
+}
+
+float test_too_many_arg(float2 p0) {
+ return reflect(p0, p0, p0);
+ // expected-error at -1 {{no matching function for call to 'reflect'}}
+ // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate function not viable: requires 2 arguments, but 3 were provided}}
+ // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate function not viable: requires 2 arguments, but 3 were provided}}
+ // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 2 arguments, but 3 were provided}}
+ // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 2 arguments, but 3 were provided}}
+}
+
+float test_double_inputs(double p0, double p1) {
+ return reflect(p0, p1);
+ // expected-error at -1 {{call to 'reflect' is ambiguous}}
+ // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate function}}
+ // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate function}}
+}
+
+float test_int_inputs(int p0, int p1) {
+ return reflect(p0, p1);
+ // expected-error at -1 {{call to 'reflect' is ambiguous}}
+ // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate function}}
+ // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate function}}
+}
diff --git a/clang/test/SemaSPIRV/BuiltIns/reflect-errors.c b/clang/test/SemaSPIRV/BuiltIns/reflect-errors.c
new file mode 100644
index 000000000000000..c93dd2ffcc9c3ec
--- /dev/null
+++ b/clang/test/SemaSPIRV/BuiltIns/reflect-errors.c
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 %s -triple spirv-pc-vulkan-compute -verify
+
+typedef float float2 __attribute__((ext_vector_type(2)));
+
+float2 test_no_second_arg(float2 p0) {
+ return __builtin_spirv_reflect(p0);
+ // expected-error at -1 {{too few arguments to function call, expected 2, have 1}}
+}
+
+float2 test_too_many_arg(float2 p0) {
+ return __builtin_spirv_reflect(p0, p0, p0);
+ // expected-error at -1 {{too many arguments to function call, expected 2, have 3}}
+}
+
+float test_double_scalar_inputs(double p0, double p1) {
+ return __builtin_spirv_reflect(p0, p1);
+ // expected-error at -1 {{passing 'double' to parameter of incompatible type '__attribute__((__vector_size__(2 * sizeof(double)))) double' (vector of 2 'double' values)}}
+}
+
+float test_int_scalar_inputs(int p0, int p1) {
+ return __builtin_spirv_reflect(p0, p1);
+ // expected-error at -1 {{passing 'int' to parameter of incompatible type '__attribute__((__vector_size__(2 * sizeof(int)))) int' (vector of 2 'int' values)}}
+}
diff --git a/llvm/include/llvm/IR/IntrinsicsSPIRV.td b/llvm/include/llvm/IR/IntrinsicsSPIRV.td
index be337dbccaf8a9f..4da464d8010f767 100644
--- a/llvm/include/llvm/IR/IntrinsicsSPIRV.td
+++ b/llvm/include/llvm/IR/IntrinsicsSPIRV.td
@@ -71,6 +71,7 @@ let TargetPrefix = "spv" in {
[IntrNoMem] >;
def int_spv_length : DefaultAttrsIntrinsic<[LLVMVectorElementType<0>], [llvm_anyfloat_ty], [IntrNoMem]>;
def int_spv_normalize : DefaultAttrsIntrinsic<[LLVMMatchType<0>], [llvm_anyfloat_ty], [IntrNoMem]>;
+ def int_spv_reflect : DefaultAttrsIntrinsic<[LLVMMatchType<0>], [llvm_anyfloat_ty, LLVMMatchType<0>], [IntrNoMem]>;
def int_spv_rsqrt : DefaultAttrsIntrinsic<[LLVMMatchType<0>], [llvm_anyfloat_ty], [IntrNoMem]>;
def int_spv_saturate : DefaultAttrsIntrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>], [IntrNoMem]>;
def int_spv_step : DefaultAttrsIntrinsic<[LLVMMatchType<0>], [LLVMMatchType<0>, llvm_anyfloat_ty], [IntrNoMem]>;
diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
index f5409c27d6ea3d2..f36af7276b49530 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
@@ -3030,6 +3030,8 @@ bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg,
return selectExtInst(ResVReg, ResType, I, CL::fract, GL::Fract);
case Intrinsic::spv_normalize:
return selectExtInst(ResVReg, ResType, I, CL::normalize, GL::Normalize);
+ case Intrinsic::spv_reflect: // There is no CL equivalent of Reflect
+ return selectExtInst(ResVReg, ResType, I, GL::Reflect);
case Intrinsic::spv_rsqrt:
return selectExtInst(ResVReg, ResType, I, CL::rsqrt, GL::InverseSqrt);
case Intrinsic::spv_sign:
diff --git a/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/reflect.ll b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/reflect.ll
new file mode 100644
index 000000000000000..18962807f84ffce
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/reflect.ll
@@ -0,0 +1,33 @@
+; RUN: llc -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+
+; Make sure SPIRV operation function calls for reflect are lowered correctly.
+
+; CHECK-DAG: %[[#op_ext_glsl:]] = OpExtInstImport "GLSL.std.450"
+; CHECK-DAG: %[[#float_16:]] = OpTypeFloat 16
+; CHECK-DAG: %[[#vec4_float_16:]] = OpTypeVector %[[#float_16]] 4
+; CHECK-DAG: %[[#float_32:]] = OpTypeFloat 32
+; CHECK-DAG: %[[#vec4_float_32:]] = OpTypeVector %[[#float_32]] 4
+
+define noundef <4 x half> @reflect_half4(<4 x half> noundef %a, <4 x half> noundef %b) {
+entry:
+ ; CHECK: %[[#]] = OpFunction %[[#vec4_float_16]] None %[[#]]
+ ; CHECK: %[[#arg0:]] = OpFunctionParameter %[[#vec4_float_16]]
+ ; CHECK: %[[#arg1:]] = OpFunctionParameter %[[#vec4_float_16]]
+ ; CHECK: %[[#]] = OpExtInst %[[#vec4_float_16]] %[[#op_ext_glsl]] Reflect %[[#arg0]] %[[#arg1]]
+ %spv.reflect = call <4 x half> @llvm.spv.reflect.f16(<4 x half> %a, <4 x half> %b)
+ ret <4 x half> %spv.reflect
+}
+
+define noundef <4 x float> @reflect_float4(<4 x float> noundef %a, <4 x float> noundef %b) {
+entry:
+ ; CHECK: %[[#]] = OpFunction %[[#vec4_float_32]] None %[[#]]
+ ; CHECK: %[[#arg0:]] = OpFunctionParameter %[[#vec4_float_32]]
+ ; CHECK: %[[#arg1:]] = OpFunctionParameter %[[#vec4_float_32]]
+ ; CHECK: %[[#]] = OpExtInst %[[#vec4_float_32]] %[[#op_ext_glsl]] Reflect %[[#arg0]] %[[#arg1]]
+ %spv.reflect = call <4 x float> @llvm.spv.reflect.f32(<4 x float> %a, <4 x float> %b)
+ ret <4 x float> %spv.reflect
+}
+
+declare <4 x half> @llvm.spv.reflect.f16(<4 x half>, <4 x half>)
+declare <4 x float> @llvm.spv.reflect.f32(<4 x float>, <4 x float>)
>From 8cc4eed06b120448f2ad982399ad864782524192 Mon Sep 17 00:00:00 2001
From: Icohedron <cheung.deric at gmail.com>
Date: Thu, 16 Jan 2025 19:00:11 +0000
Subject: [PATCH 2/5] Gracefully end codegen when reflect used in a non-Vulkan
env
---
llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
index f36af7276b49530..d15c266c7fd7d2f 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
@@ -3030,8 +3030,10 @@ bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg,
return selectExtInst(ResVReg, ResType, I, CL::fract, GL::Fract);
case Intrinsic::spv_normalize:
return selectExtInst(ResVReg, ResType, I, CL::normalize, GL::Normalize);
- case Intrinsic::spv_reflect: // There is no CL equivalent of Reflect
- return selectExtInst(ResVReg, ResType, I, GL::Reflect);
+ case Intrinsic::spv_reflect:
+ if (STI.isVulkanEnv()) // There is no CL equivalent of Reflect
+ return selectExtInst(ResVReg, ResType, I, GL::Reflect);
+ break;
case Intrinsic::spv_rsqrt:
return selectExtInst(ResVReg, ResType, I, CL::rsqrt, GL::InverseSqrt);
case Intrinsic::spv_sign:
>From 5e568d713b15e77ae3c9b4247cd279ad7001281e Mon Sep 17 00:00:00 2001
From: Icohedron <cheung.deric at gmail.com>
Date: Thu, 16 Jan 2025 19:01:22 +0000
Subject: [PATCH 3/5] Fix return type of reflect_vec_impl
---
clang/lib/Headers/hlsl/hlsl_detail.h | 3 +--
clang/test/CodeGenHLSL/builtins/reflect.hlsl | 12 ++++++------
2 files changed, 7 insertions(+), 8 deletions(-)
diff --git a/clang/lib/Headers/hlsl/hlsl_detail.h b/clang/lib/Headers/hlsl/hlsl_detail.h
index 3e09f8b10735122..0d568539cd66a85 100644
--- a/clang/lib/Headers/hlsl/hlsl_detail.h
+++ b/clang/lib/Headers/hlsl/hlsl_detail.h
@@ -87,8 +87,7 @@ reflect_impl(T I, T N) {
}
template <typename T, int L>
-constexpr enable_if_t<is_same<float, T>::value || is_same<half, T>::value, T>
-reflect_vec_impl(vector<T, L> I, vector<T, L> N) {
+constexpr vector<T, L> reflect_vec_impl(vector<T, L> I, vector<T, L> N) {
#if (__has_builtin(__builtin_spirv_reflect))
return __builtin_spirv_reflect(I, N);
#else
diff --git a/clang/test/CodeGenHLSL/builtins/reflect.hlsl b/clang/test/CodeGenHLSL/builtins/reflect.hlsl
index 66d0a4b6f6a24a9..1babe7bfa1c29e3 100644
--- a/clang/test/CodeGenHLSL/builtins/reflect.hlsl
+++ b/clang/test/CodeGenHLSL/builtins/reflect.hlsl
@@ -44,7 +44,7 @@ half test_reflect_half(half I, half N) {
// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) <2 x half> @_Z18test_reflect_half2Dv2_DhS_(
// SPVCHECK-SAME: <2 x half> noundef nofpclass(nan inf) [[I:%.*]], <2 x half> noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SPVCHECK-NEXT: [[ENTRY:.*:]]
-// SPVCHECK-NEXT: [[SPV_REFLECT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn <2 x half> @llvm.spv.reflect.v2f16(<2 x half> [[I]], <2 x half> [[N]])
+// SPVCHECK-NEXT: [[SPV_REFLECT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef <2 x half> @llvm.spv.reflect.v2f16(<2 x half> [[I]], <2 x half> [[N]])
// SPVCHECK-NEXT: [[SPLAT_SPLAT:%.*]] = shufflevector <2 x half> [[SPV_REFLECT_I]], <2 x half> poison, <2 x i32> zeroinitializer
// SPVCHECK-NEXT: ret <2 x half> [[SPLAT_SPLAT]]
//
@@ -68,7 +68,7 @@ half2 test_reflect_half2(half2 I, half2 N) {
// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) <3 x half> @_Z18test_reflect_half3Dv3_DhS_(
// SPVCHECK-SAME: <3 x half> noundef nofpclass(nan inf) [[I:%.*]], <3 x half> noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SPVCHECK-NEXT: [[ENTRY:.*:]]
-// SPVCHECK-NEXT: [[SPV_REFLECT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn <3 x half> @llvm.spv.reflect.v3f16(<3 x half> [[I]], <3 x half> [[N]])
+// SPVCHECK-NEXT: [[SPV_REFLECT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef <3 x half> @llvm.spv.reflect.v3f16(<3 x half> [[I]], <3 x half> [[N]])
// SPVCHECK-NEXT: [[SPLAT_SPLAT:%.*]] = shufflevector <3 x half> [[SPV_REFLECT_I]], <3 x half> poison, <3 x i32> zeroinitializer
// SPVCHECK-NEXT: ret <3 x half> [[SPLAT_SPLAT]]
//
@@ -92,7 +92,7 @@ half3 test_reflect_half3(half3 I, half3 N) {
// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) <4 x half> @_Z18test_reflect_half4Dv4_DhS_(
// SPVCHECK-SAME: <4 x half> noundef nofpclass(nan inf) [[I:%.*]], <4 x half> noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SPVCHECK-NEXT: [[ENTRY:.*:]]
-// SPVCHECK-NEXT: [[SPV_REFLECT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn <4 x half> @llvm.spv.reflect.v4f16(<4 x half> [[I]], <4 x half> [[N]])
+// SPVCHECK-NEXT: [[SPV_REFLECT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef <4 x half> @llvm.spv.reflect.v4f16(<4 x half> [[I]], <4 x half> [[N]])
// SPVCHECK-NEXT: [[SPLAT_SPLAT:%.*]] = shufflevector <4 x half> [[SPV_REFLECT_I]], <4 x half> poison, <4 x i32> zeroinitializer
// SPVCHECK-NEXT: ret <4 x half> [[SPLAT_SPLAT]]
//
@@ -138,7 +138,7 @@ float test_reflect_float(float I, float N) {
// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) <2 x float> @_Z19test_reflect_float2Dv2_fS_(
// SPVCHECK-SAME: <2 x float> noundef nofpclass(nan inf) [[I:%.*]], <2 x float> noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SPVCHECK-NEXT: [[ENTRY:.*:]]
-// SPVCHECK-NEXT: [[SPV_REFLECT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.spv.reflect.v2f32(<2 x float> [[I]], <2 x float> [[N]])
+// SPVCHECK-NEXT: [[SPV_REFLECT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef <2 x float> @llvm.spv.reflect.v2f32(<2 x float> [[I]], <2 x float> [[N]])
// SPVCHECK-NEXT: [[SPLAT_SPLAT:%.*]] = shufflevector <2 x float> [[SPV_REFLECT_I]], <2 x float> poison, <2 x i32> zeroinitializer
// SPVCHECK-NEXT: ret <2 x float> [[SPLAT_SPLAT]]
//
@@ -162,7 +162,7 @@ float2 test_reflect_float2(float2 I, float2 N) {
// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) <3 x float> @_Z19test_reflect_float3Dv3_fS_(
// SPVCHECK-SAME: <3 x float> noundef nofpclass(nan inf) [[I:%.*]], <3 x float> noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SPVCHECK-NEXT: [[ENTRY:.*:]]
-// SPVCHECK-NEXT: [[SPV_REFLECT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.spv.reflect.v3f32(<3 x float> [[I]], <3 x float> [[N]])
+// SPVCHECK-NEXT: [[SPV_REFLECT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef <3 x float> @llvm.spv.reflect.v3f32(<3 x float> [[I]], <3 x float> [[N]])
// SPVCHECK-NEXT: [[SPLAT_SPLAT:%.*]] = shufflevector <3 x float> [[SPV_REFLECT_I]], <3 x float> poison, <3 x i32> zeroinitializer
// SPVCHECK-NEXT: ret <3 x float> [[SPLAT_SPLAT]]
//
@@ -186,7 +186,7 @@ float3 test_reflect_float3(float3 I, float3 N) {
// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) <4 x float> @_Z19test_reflect_float4Dv4_fS_(
// SPVCHECK-SAME: <4 x float> noundef nofpclass(nan inf) [[I:%.*]], <4 x float> noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SPVCHECK-NEXT: [[ENTRY:.*:]]
-// SPVCHECK-NEXT: [[SPV_REFLECT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.spv.reflect.v4f32(<4 x float> [[I]], <4 x float> [[N]])
+// SPVCHECK-NEXT: [[SPV_REFLECT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef <4 x float> @llvm.spv.reflect.v4f32(<4 x float> [[I]], <4 x float> [[N]])
// SPVCHECK-NEXT: [[SPLAT_SPLAT:%.*]] = shufflevector <4 x float> [[SPV_REFLECT_I]], <4 x float> poison, <4 x i32> zeroinitializer
// SPVCHECK-NEXT: ret <4 x float> [[SPLAT_SPLAT]]
//
>From 79991d5f407ad8fb66cdc952738d286ab5ab76dd Mon Sep 17 00:00:00 2001
From: Icohedron <cheung.deric at gmail.com>
Date: Thu, 16 Jan 2025 19:35:12 +0000
Subject: [PATCH 4/5] Fix reflect codegen
Incorrect return type in hlsl_intrinsics caused vector operations to be performed on the first element only, and unecessary splats where inserted when using the SPIR-V builtin intrinsic via the SPIR-V fast path.
---
clang/lib/Headers/hlsl/hlsl_intrinsics.h | 4 +-
clang/test/CodeGenHLSL/builtins/reflect.hlsl | 102 ++++++++-----------
2 files changed, 44 insertions(+), 62 deletions(-)
diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h
index 54454cf0ea0d0bd..3b47074f07ecf4e 100644
--- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h
+++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h
@@ -2042,12 +2042,12 @@ const inline float reflect(float I, float N) {
template <int L>
_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
-const inline half reflect(vector<half, L> I, vector<half, L> N) {
+const inline vector<half, L> reflect(vector<half, L> I, vector<half, L> N) {
return __detail::reflect_vec_impl(I, N);
}
template <int L>
-const inline float reflect(vector<float, L> I, vector<float, L> N) {
+const inline vector<float, L> reflect(vector<float, L> I, vector<float, L> N) {
return __detail::reflect_vec_impl(I, N);
}
diff --git a/clang/test/CodeGenHLSL/builtins/reflect.hlsl b/clang/test/CodeGenHLSL/builtins/reflect.hlsl
index 1babe7bfa1c29e3..35ee059697c4bad 100644
--- a/clang/test/CodeGenHLSL/builtins/reflect.hlsl
+++ b/clang/test/CodeGenHLSL/builtins/reflect.hlsl
@@ -32,21 +32,18 @@ half test_reflect_half(half I, half N) {
// CHECK-SAME: <2 x half> noundef nofpclass(nan inf) [[I:%.*]], <2 x half> noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
// CHECK-NEXT: [[HLSL_DOT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn half @llvm.dx.fdot.v2f16(<2 x half> [[I]], <2 x half> [[N]])
-// CHECK-NEXT: [[TMP0:%.*]] = extractelement <2 x half> [[I]], i64 0
-// CHECK-NEXT: [[TMP1:%.*]] = extractelement <2 x half> [[N]], i64 0
-// CHECK-NEXT: [[TMP2:%.*]] = fmul reassoc nnan ninf nsz arcp afn half [[TMP1]], 0xH4000
-// CHECK-NEXT: [[TMP3:%.*]] = fmul reassoc nnan ninf nsz arcp afn half [[TMP2]], [[HLSL_DOT_I]]
-// CHECK-NEXT: [[CAST_VTRUNC_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn half [[TMP0]], [[TMP3]]
-// CHECK-NEXT: [[SPLAT_SPLATINSERT:%.*]] = insertelement <2 x half> poison, half [[CAST_VTRUNC_I]], i64 0
-// CHECK-NEXT: [[SPLAT_SPLAT:%.*]] = shufflevector <2 x half> [[SPLAT_SPLATINSERT]], <2 x half> poison, <2 x i32> zeroinitializer
-// CHECK-NEXT: ret <2 x half> [[SPLAT_SPLAT]]
+// CHECK-NEXT: [[DOTSCALAR:%.*]] = fmul reassoc nnan ninf nsz arcp afn half [[HLSL_DOT_I]], 0xH4000
+// CHECK-NEXT: [[TMP0:%.*]] = insertelement <2 x half> poison, half [[DOTSCALAR]], i64 0
+// CHECK-NEXT: [[TMP1:%.*]] = shufflevector <2 x half> [[TMP0]], <2 x half> poison, <2 x i32> zeroinitializer
+// CHECK-NEXT: [[MUL1_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn <2 x half> [[TMP1]], [[N]]
+// CHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <2 x half> [[I]], [[MUL1_I]]
+// CHECK-NEXT: ret <2 x half> [[SUB_I]]
//
// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) <2 x half> @_Z18test_reflect_half2Dv2_DhS_(
// SPVCHECK-SAME: <2 x half> noundef nofpclass(nan inf) [[I:%.*]], <2 x half> noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SPVCHECK-NEXT: [[ENTRY:.*:]]
// SPVCHECK-NEXT: [[SPV_REFLECT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef <2 x half> @llvm.spv.reflect.v2f16(<2 x half> [[I]], <2 x half> [[N]])
-// SPVCHECK-NEXT: [[SPLAT_SPLAT:%.*]] = shufflevector <2 x half> [[SPV_REFLECT_I]], <2 x half> poison, <2 x i32> zeroinitializer
-// SPVCHECK-NEXT: ret <2 x half> [[SPLAT_SPLAT]]
+// SPVCHECK-NEXT: ret <2 x half> [[SPV_REFLECT_I]]
//
half2 test_reflect_half2(half2 I, half2 N) {
return reflect(I, N);
@@ -56,21 +53,18 @@ half2 test_reflect_half2(half2 I, half2 N) {
// CHECK-SAME: <3 x half> noundef nofpclass(nan inf) [[I:%.*]], <3 x half> noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
// CHECK-NEXT: [[HLSL_DOT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn half @llvm.dx.fdot.v3f16(<3 x half> [[I]], <3 x half> [[N]])
-// CHECK-NEXT: [[TMP0:%.*]] = extractelement <3 x half> [[I]], i64 0
-// CHECK-NEXT: [[TMP1:%.*]] = extractelement <3 x half> [[N]], i64 0
-// CHECK-NEXT: [[TMP2:%.*]] = fmul reassoc nnan ninf nsz arcp afn half [[TMP1]], 0xH4000
-// CHECK-NEXT: [[TMP3:%.*]] = fmul reassoc nnan ninf nsz arcp afn half [[TMP2]], [[HLSL_DOT_I]]
-// CHECK-NEXT: [[CAST_VTRUNC_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn half [[TMP0]], [[TMP3]]
-// CHECK-NEXT: [[SPLAT_SPLATINSERT:%.*]] = insertelement <3 x half> poison, half [[CAST_VTRUNC_I]], i64 0
-// CHECK-NEXT: [[SPLAT_SPLAT:%.*]] = shufflevector <3 x half> [[SPLAT_SPLATINSERT]], <3 x half> poison, <3 x i32> zeroinitializer
-// CHECK-NEXT: ret <3 x half> [[SPLAT_SPLAT]]
+// CHECK-NEXT: [[DOTSCALAR:%.*]] = fmul reassoc nnan ninf nsz arcp afn half [[HLSL_DOT_I]], 0xH4000
+// CHECK-NEXT: [[TMP0:%.*]] = insertelement <3 x half> poison, half [[DOTSCALAR]], i64 0
+// CHECK-NEXT: [[TMP1:%.*]] = shufflevector <3 x half> [[TMP0]], <3 x half> poison, <3 x i32> zeroinitializer
+// CHECK-NEXT: [[MUL1_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn <3 x half> [[TMP1]], [[N]]
+// CHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <3 x half> [[I]], [[MUL1_I]]
+// CHECK-NEXT: ret <3 x half> [[SUB_I]]
//
// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) <3 x half> @_Z18test_reflect_half3Dv3_DhS_(
// SPVCHECK-SAME: <3 x half> noundef nofpclass(nan inf) [[I:%.*]], <3 x half> noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SPVCHECK-NEXT: [[ENTRY:.*:]]
// SPVCHECK-NEXT: [[SPV_REFLECT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef <3 x half> @llvm.spv.reflect.v3f16(<3 x half> [[I]], <3 x half> [[N]])
-// SPVCHECK-NEXT: [[SPLAT_SPLAT:%.*]] = shufflevector <3 x half> [[SPV_REFLECT_I]], <3 x half> poison, <3 x i32> zeroinitializer
-// SPVCHECK-NEXT: ret <3 x half> [[SPLAT_SPLAT]]
+// SPVCHECK-NEXT: ret <3 x half> [[SPV_REFLECT_I]]
//
half3 test_reflect_half3(half3 I, half3 N) {
return reflect(I, N);
@@ -80,21 +74,18 @@ half3 test_reflect_half3(half3 I, half3 N) {
// CHECK-SAME: <4 x half> noundef nofpclass(nan inf) [[I:%.*]], <4 x half> noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
// CHECK-NEXT: [[HLSL_DOT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn half @llvm.dx.fdot.v4f16(<4 x half> [[I]], <4 x half> [[N]])
-// CHECK-NEXT: [[TMP0:%.*]] = extractelement <4 x half> [[I]], i64 0
-// CHECK-NEXT: [[TMP1:%.*]] = extractelement <4 x half> [[N]], i64 0
-// CHECK-NEXT: [[TMP2:%.*]] = fmul reassoc nnan ninf nsz arcp afn half [[TMP1]], 0xH4000
-// CHECK-NEXT: [[TMP3:%.*]] = fmul reassoc nnan ninf nsz arcp afn half [[TMP2]], [[HLSL_DOT_I]]
-// CHECK-NEXT: [[CAST_VTRUNC_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn half [[TMP0]], [[TMP3]]
-// CHECK-NEXT: [[SPLAT_SPLATINSERT:%.*]] = insertelement <4 x half> poison, half [[CAST_VTRUNC_I]], i64 0
-// CHECK-NEXT: [[SPLAT_SPLAT:%.*]] = shufflevector <4 x half> [[SPLAT_SPLATINSERT]], <4 x half> poison, <4 x i32> zeroinitializer
-// CHECK-NEXT: ret <4 x half> [[SPLAT_SPLAT]]
+// CHECK-NEXT: [[DOTSCALAR:%.*]] = fmul reassoc nnan ninf nsz arcp afn half [[HLSL_DOT_I]], 0xH4000
+// CHECK-NEXT: [[TMP0:%.*]] = insertelement <4 x half> poison, half [[DOTSCALAR]], i64 0
+// CHECK-NEXT: [[TMP1:%.*]] = shufflevector <4 x half> [[TMP0]], <4 x half> poison, <4 x i32> zeroinitializer
+// CHECK-NEXT: [[MUL1_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn <4 x half> [[TMP1]], [[N]]
+// CHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <4 x half> [[I]], [[MUL1_I]]
+// CHECK-NEXT: ret <4 x half> [[SUB_I]]
//
// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) <4 x half> @_Z18test_reflect_half4Dv4_DhS_(
// SPVCHECK-SAME: <4 x half> noundef nofpclass(nan inf) [[I:%.*]], <4 x half> noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SPVCHECK-NEXT: [[ENTRY:.*:]]
// SPVCHECK-NEXT: [[SPV_REFLECT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef <4 x half> @llvm.spv.reflect.v4f16(<4 x half> [[I]], <4 x half> [[N]])
-// SPVCHECK-NEXT: [[SPLAT_SPLAT:%.*]] = shufflevector <4 x half> [[SPV_REFLECT_I]], <4 x half> poison, <4 x i32> zeroinitializer
-// SPVCHECK-NEXT: ret <4 x half> [[SPLAT_SPLAT]]
+// SPVCHECK-NEXT: ret <4 x half> [[SPV_REFLECT_I]]
//
half4 test_reflect_half4(half4 I, half4 N) {
return reflect(I, N);
@@ -126,21 +117,18 @@ float test_reflect_float(float I, float N) {
// CHECK-SAME: <2 x float> noundef nofpclass(nan inf) [[I:%.*]], <2 x float> noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
// CHECK-NEXT: [[HLSL_DOT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn float @llvm.dx.fdot.v2f32(<2 x float> [[I]], <2 x float> [[N]])
-// CHECK-NEXT: [[TMP0:%.*]] = extractelement <2 x float> [[I]], i64 0
-// CHECK-NEXT: [[TMP1:%.*]] = extractelement <2 x float> [[N]], i64 0
-// CHECK-NEXT: [[TMP2:%.*]] = fmul reassoc nnan ninf nsz arcp afn float [[TMP1]], 2.000000e+00
-// CHECK-NEXT: [[TMP3:%.*]] = fmul reassoc nnan ninf nsz arcp afn float [[TMP2]], [[HLSL_DOT_I]]
-// CHECK-NEXT: [[CAST_VTRUNC_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn float [[TMP0]], [[TMP3]]
-// CHECK-NEXT: [[SPLAT_SPLATINSERT:%.*]] = insertelement <2 x float> poison, float [[CAST_VTRUNC_I]], i64 0
-// CHECK-NEXT: [[SPLAT_SPLAT:%.*]] = shufflevector <2 x float> [[SPLAT_SPLATINSERT]], <2 x float> poison, <2 x i32> zeroinitializer
-// CHECK-NEXT: ret <2 x float> [[SPLAT_SPLAT]]
+// CHECK-NEXT: [[DOTSCALAR:%.*]] = fmul reassoc nnan ninf nsz arcp afn float [[HLSL_DOT_I]], 2.000000e+00
+// CHECK-NEXT: [[TMP0:%.*]] = insertelement <2 x float> poison, float [[DOTSCALAR]], i64 0
+// CHECK-NEXT: [[TMP1:%.*]] = shufflevector <2 x float> [[TMP0]], <2 x float> poison, <2 x i32> zeroinitializer
+// CHECK-NEXT: [[MUL1_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn <2 x float> [[TMP1]], [[N]]
+// CHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <2 x float> [[I]], [[MUL1_I]]
+// CHECK-NEXT: ret <2 x float> [[SUB_I]]
//
// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) <2 x float> @_Z19test_reflect_float2Dv2_fS_(
// SPVCHECK-SAME: <2 x float> noundef nofpclass(nan inf) [[I:%.*]], <2 x float> noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SPVCHECK-NEXT: [[ENTRY:.*:]]
// SPVCHECK-NEXT: [[SPV_REFLECT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef <2 x float> @llvm.spv.reflect.v2f32(<2 x float> [[I]], <2 x float> [[N]])
-// SPVCHECK-NEXT: [[SPLAT_SPLAT:%.*]] = shufflevector <2 x float> [[SPV_REFLECT_I]], <2 x float> poison, <2 x i32> zeroinitializer
-// SPVCHECK-NEXT: ret <2 x float> [[SPLAT_SPLAT]]
+// SPVCHECK-NEXT: ret <2 x float> [[SPV_REFLECT_I]]
//
float2 test_reflect_float2(float2 I, float2 N) {
return reflect(I, N);
@@ -150,21 +138,18 @@ float2 test_reflect_float2(float2 I, float2 N) {
// CHECK-SAME: <3 x float> noundef nofpclass(nan inf) [[I:%.*]], <3 x float> noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
// CHECK-NEXT: [[HLSL_DOT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn float @llvm.dx.fdot.v3f32(<3 x float> [[I]], <3 x float> [[N]])
-// CHECK-NEXT: [[TMP0:%.*]] = extractelement <3 x float> [[I]], i64 0
-// CHECK-NEXT: [[TMP1:%.*]] = extractelement <3 x float> [[N]], i64 0
-// CHECK-NEXT: [[TMP2:%.*]] = fmul reassoc nnan ninf nsz arcp afn float [[TMP1]], 2.000000e+00
-// CHECK-NEXT: [[TMP3:%.*]] = fmul reassoc nnan ninf nsz arcp afn float [[TMP2]], [[HLSL_DOT_I]]
-// CHECK-NEXT: [[CAST_VTRUNC_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn float [[TMP0]], [[TMP3]]
-// CHECK-NEXT: [[SPLAT_SPLATINSERT:%.*]] = insertelement <3 x float> poison, float [[CAST_VTRUNC_I]], i64 0
-// CHECK-NEXT: [[SPLAT_SPLAT:%.*]] = shufflevector <3 x float> [[SPLAT_SPLATINSERT]], <3 x float> poison, <3 x i32> zeroinitializer
-// CHECK-NEXT: ret <3 x float> [[SPLAT_SPLAT]]
+// CHECK-NEXT: [[DOTSCALAR:%.*]] = fmul reassoc nnan ninf nsz arcp afn float [[HLSL_DOT_I]], 2.000000e+00
+// CHECK-NEXT: [[TMP0:%.*]] = insertelement <3 x float> poison, float [[DOTSCALAR]], i64 0
+// CHECK-NEXT: [[TMP1:%.*]] = shufflevector <3 x float> [[TMP0]], <3 x float> poison, <3 x i32> zeroinitializer
+// CHECK-NEXT: [[MUL1_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn <3 x float> [[TMP1]], [[N]]
+// CHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <3 x float> [[I]], [[MUL1_I]]
+// CHECK-NEXT: ret <3 x float> [[SUB_I]]
//
// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) <3 x float> @_Z19test_reflect_float3Dv3_fS_(
// SPVCHECK-SAME: <3 x float> noundef nofpclass(nan inf) [[I:%.*]], <3 x float> noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SPVCHECK-NEXT: [[ENTRY:.*:]]
// SPVCHECK-NEXT: [[SPV_REFLECT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef <3 x float> @llvm.spv.reflect.v3f32(<3 x float> [[I]], <3 x float> [[N]])
-// SPVCHECK-NEXT: [[SPLAT_SPLAT:%.*]] = shufflevector <3 x float> [[SPV_REFLECT_I]], <3 x float> poison, <3 x i32> zeroinitializer
-// SPVCHECK-NEXT: ret <3 x float> [[SPLAT_SPLAT]]
+// SPVCHECK-NEXT: ret <3 x float> [[SPV_REFLECT_I]]
//
float3 test_reflect_float3(float3 I, float3 N) {
return reflect(I, N);
@@ -174,21 +159,18 @@ float3 test_reflect_float3(float3 I, float3 N) {
// CHECK-SAME: <4 x float> noundef nofpclass(nan inf) [[I:%.*]], <4 x float> noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
// CHECK-NEXT: [[HLSL_DOT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn float @llvm.dx.fdot.v4f32(<4 x float> [[I]], <4 x float> [[N]])
-// CHECK-NEXT: [[TMP0:%.*]] = extractelement <4 x float> [[I]], i64 0
-// CHECK-NEXT: [[TMP1:%.*]] = extractelement <4 x float> [[N]], i64 0
-// CHECK-NEXT: [[TMP2:%.*]] = fmul reassoc nnan ninf nsz arcp afn float [[TMP1]], 2.000000e+00
-// CHECK-NEXT: [[TMP3:%.*]] = fmul reassoc nnan ninf nsz arcp afn float [[TMP2]], [[HLSL_DOT_I]]
-// CHECK-NEXT: [[CAST_VTRUNC_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn float [[TMP0]], [[TMP3]]
-// CHECK-NEXT: [[SPLAT_SPLATINSERT:%.*]] = insertelement <4 x float> poison, float [[CAST_VTRUNC_I]], i64 0
-// CHECK-NEXT: [[SPLAT_SPLAT:%.*]] = shufflevector <4 x float> [[SPLAT_SPLATINSERT]], <4 x float> poison, <4 x i32> zeroinitializer
-// CHECK-NEXT: ret <4 x float> [[SPLAT_SPLAT]]
+// CHECK-NEXT: [[DOTSCALAR:%.*]] = fmul reassoc nnan ninf nsz arcp afn float [[HLSL_DOT_I]], 2.000000e+00
+// CHECK-NEXT: [[TMP0:%.*]] = insertelement <4 x float> poison, float [[DOTSCALAR]], i64 0
+// CHECK-NEXT: [[TMP1:%.*]] = shufflevector <4 x float> [[TMP0]], <4 x float> poison, <4 x i32> zeroinitializer
+// CHECK-NEXT: [[MUL1_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn <4 x float> [[TMP1]], [[N]]
+// CHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <4 x float> [[I]], [[MUL1_I]]
+// CHECK-NEXT: ret <4 x float> [[SUB_I]]
//
// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) <4 x float> @_Z19test_reflect_float4Dv4_fS_(
// SPVCHECK-SAME: <4 x float> noundef nofpclass(nan inf) [[I:%.*]], <4 x float> noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SPVCHECK-NEXT: [[ENTRY:.*:]]
// SPVCHECK-NEXT: [[SPV_REFLECT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef <4 x float> @llvm.spv.reflect.v4f32(<4 x float> [[I]], <4 x float> [[N]])
-// SPVCHECK-NEXT: [[SPLAT_SPLAT:%.*]] = shufflevector <4 x float> [[SPV_REFLECT_I]], <4 x float> poison, <4 x i32> zeroinitializer
-// SPVCHECK-NEXT: ret <4 x float> [[SPLAT_SPLAT]]
+// SPVCHECK-NEXT: ret <4 x float> [[SPV_REFLECT_I]]
//
float4 test_reflect_float4(float4 I, float4 N) {
return reflect(I, N);
>From 782e1a28d4f8ddbeb92a9c57b3f071ba837ce129 Mon Sep 17 00:00:00 2001
From: Icohedron <cheung.deric at gmail.com>
Date: Fri, 17 Jan 2025 22:40:09 +0000
Subject: [PATCH 5/5] Emit error on instruction selection of when the GLSL
extended instruction set is not being used
---
.../Target/SPIRV/SPIRVInstructionSelector.cpp | 12 +++++++---
.../CodeGen/SPIRV/opencl/reflect-error.ll | 22 +++++++++++++++++++
2 files changed, 31 insertions(+), 3 deletions(-)
create mode 100644 llvm/test/CodeGen/SPIRV/opencl/reflect-error.ll
diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
index d15c266c7fd7d2f..960c51e9520f3a1 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
@@ -34,6 +34,7 @@
#include "llvm/IR/IntrinsicsSPIRV.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
#define DEBUG_TYPE "spirv-isel"
@@ -3031,9 +3032,14 @@ bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg,
case Intrinsic::spv_normalize:
return selectExtInst(ResVReg, ResType, I, CL::normalize, GL::Normalize);
case Intrinsic::spv_reflect:
- if (STI.isVulkanEnv()) // There is no CL equivalent of Reflect
- return selectExtInst(ResVReg, ResType, I, GL::Reflect);
- break;
+ if (!STI.canUseExtInstSet(SPIRV::InstructionSet::InstructionSet::GLSL_std_450)) {
+ std::string DiagMsg;
+ raw_string_ostream OS(DiagMsg);
+ I.print(OS);
+ DiagMsg = "Intrinsic selection not supported for this instruction set: " + DiagMsg;
+ report_fatal_error(DiagMsg.c_str(), false);
+ }
+ return selectExtInst(ResVReg, ResType, I, GL::Reflect);
case Intrinsic::spv_rsqrt:
return selectExtInst(ResVReg, ResType, I, CL::rsqrt, GL::InverseSqrt);
case Intrinsic::spv_sign:
diff --git a/llvm/test/CodeGen/SPIRV/opencl/reflect-error.ll b/llvm/test/CodeGen/SPIRV/opencl/reflect-error.ll
new file mode 100644
index 000000000000000..c76bcf62748288e
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/opencl/reflect-error.ll
@@ -0,0 +1,22 @@
+; RUN: not llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %s -o /dev/null 2>&1 | FileCheck %s
+; RUN: not llc -verify-machineinstrs -O0 -mtriple=spirv32-unknown-unknown %s -o /dev/null 2>&1 | FileCheck %s
+; RUN: not %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o /dev/null 2>&1 -filetype=obj %}
+; RUN: not %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown %s -o /dev/null 2>&1 -filetype=obj %}
+
+; CHECK: LLVM ERROR: Intrinsic selection not supported for this instruction set: %{{.*}} = G_INTRINSIC intrinsic(@llvm.spv.reflect), %{{.*}}, %{{.*}}
+
+define noundef <4 x half> @reflect_half4(<4 x half> noundef %a, <4 x half> noundef %b) {
+entry:
+ %spv.reflect = call <4 x half> @llvm.spv.reflect.f16(<4 x half> %a, <4 x half> %b)
+ ret <4 x half> %spv.reflect
+}
+
+define noundef <4 x float> @reflect_float4(<4 x float> noundef %a, <4 x float> noundef %b) {
+entry:
+ %spv.reflect = call <4 x float> @llvm.spv.reflect.f32(<4 x float> %a, <4 x float> %b)
+ ret <4 x float> %spv.reflect
+}
+
+declare <4 x half> @llvm.spv.reflect.f16(<4 x half>, <4 x half>)
+declare <4 x float> @llvm.spv.reflect.f32(<4 x float>, <4 x float>)
+
More information about the llvm-commits
mailing list