[clang] [llvm] [HLSL] Implement `reflect` HLSL function (PR #122992)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Jan 14 16:47:20 PST 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-hlsl
Author: Deric Cheung (Icohedron)
<details>
<summary>Changes</summary>
Fixes #<!-- -->99152
Tasks completed:
- Implement `reflect` in `clang/lib/Headers/hlsl/hlsl_intrinsics.h`
- Implement the `reflect` SPIR-V target built-in in `clang/include/clang/Basic/BuiltinsSPIRV.td`
- Add a SPIR-V fast path in `clang/lib/Headers/hlsl/hlsl_detail.h` in the form
```c++
#if (__has_builtin(__builtin_spirv_reflect))
return __builtin_spirv_reflect(...);
#else
return ...; // regular behavior
#endif
```
- Add codegen for the SPIR-V `reflect` built-in to `EmitSPIRVBuiltinExpr` in `clang/lib/CodeGen/CGBuiltin.cpp`
- Add HLSL codegen tests to `clang/test/CodeGenHLSL/builtins/reflect.hlsl`
- Add SPIR-V built-in codegen tests to `clang/test/CodeGenSPIRV/Builtins/reflect.c`
- Add sema tests to `clang/test/SemaHLSL/BuiltIns/reflect-errors.hlsl`
- Add SPIR-V sema tests to `clang/test/CodeGenSPIRV/Builtins/reflect-errors.c`
- Create the `int_spv_reflect` intrinsic in `llvm/include/llvm/IR/IntrinsicsSPIRV.td`
- In `llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp` create the `reflect` lowering and map it to `int_spv_reflect` in `SPIRVInstructionSelector::selectIntrinsic`
- Create a SPIR-V backend test case in `llvm/test/CodeGen/SPIRV/hlsl-intrinsics/reflect.ll`
Additional tasks completed:
- Implement sema check for the `reflect` SPIR-V built-in in `clang/lib/Sema/SemaSPIRV.cpp`
- Required for HLSL codegen to work via the SPIR-V fast path, otherwise the test `clang/test/CodeGenHLSL/builtins/reflect.hlsl` outright fails to compile
Incomplete tasks:
- Create SPIR-V backend test case in llvm/test/CodeGen/SPIRV/opencl/reflect.ll
- I do not think an OpenCL test is applicable in this case because the [OpenCL SPIR-V extended instruction set](https://registry.khronos.org/SPIR-V/specs/unified1/OpenCL.ExtendedInstructionSet.100.html) does not include a `reflect` function
---
Patch is 29.45 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/122992.diff
12 Files Affected:
- (modified) clang/include/clang/Basic/BuiltinsSPIRV.td (+6)
- (modified) clang/lib/CodeGen/CGBuiltin.cpp (+13)
- (modified) clang/lib/Headers/hlsl/hlsl_detail.h (+17)
- (modified) clang/lib/Headers/hlsl/hlsl_intrinsics.h (+43)
- (modified) clang/lib/Sema/SemaSPIRV.cpp (+32)
- (added) clang/test/CodeGenHLSL/builtins/reflect.hlsl (+195)
- (added) clang/test/CodeGenSPIRV/Builtins/reflect.c (+32)
- (added) clang/test/SemaHLSL/BuiltIns/reflect-errors.hlsl (+33)
- (added) clang/test/SemaSPIRV/BuiltIns/reflect-errors.c (+23)
- (modified) llvm/include/llvm/IR/IntrinsicsSPIRV.td (+1)
- (modified) llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp (+2)
- (added) llvm/test/CodeGen/SPIRV/hlsl-intrinsics/reflect.ll (+33)
``````````diff
diff --git a/clang/include/clang/Basic/BuiltinsSPIRV.td b/clang/include/clang/Basic/BuiltinsSPIRV.td
index 1e66939b822ef8..ce00459fc8ede7 100644
--- a/clang/include/clang/Basic/BuiltinsSPIRV.td
+++ b/clang/include/clang/Basic/BuiltinsSPIRV.td
@@ -13,3 +13,9 @@ def SPIRVDistance : 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 1b25d365932c30..b9e680685b05e0 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -20487,6 +20487,19 @@ Value *CodeGenFunction::EmitSPIRVBuiltinExpr(unsigned BuiltinID,
/*ReturnType=*/X->getType()->getScalarType(), Intrinsic::spv_distance,
ArrayRef<Value *>{X, Y}, nullptr, "spv.distance");
}
+ 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 19d83ea5471c7c..624a7b05b56ad0 100644
--- a/clang/lib/Headers/hlsl/hlsl_detail.h
+++ b/clang/lib/Headers/hlsl/hlsl_detail.h
@@ -68,6 +68,23 @@ distance_vec_impl(vector<T, N> X, vector<T, N> Y) {
return length_vec_impl(X - Y);
#endif
}
+
+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 d2d3abd92ea6a8..484ae708342a59 100644
--- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h
+++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h
@@ -1919,6 +1919,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 d2de64826c6eb3..5d8da023c0c55d 100644
--- a/clang/lib/Sema/SemaSPIRV.cpp
+++ b/clang/lib/Sema/SemaSPIRV.cpp
@@ -51,6 +51,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 00000000000000..66d0a4b6f6a24a
--- /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> @...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/122992
More information about the llvm-commits
mailing list