Skip to content

Commit 305d273

Browse files
authored
Reland "[HLSL] Implement the reflect HLSL function" (#125599)
This PR relands #122992. A reland was attempted before (#123853), but it [failed to pass the `sanitizer-aarch64-linux-bootstrap-hwasan` buildbot](#123853 (comment)) due to the test `llvm/test/CodeGen/SPIRV/opencl/reflect-error.ll` The issue has since been patched thanks to @vitalybuka, so the PR is safe to reland without any changes. See #125599 (comment) and #125599 (comment)
1 parent 49c3120 commit 305d273

File tree

13 files changed

+434
-4
lines changed

13 files changed

+434
-4
lines changed

clang/include/clang/Basic/BuiltinsSPIRV.td

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,9 @@ def SPIRVLength : Builtin {
1919
let Attributes = [NoThrow, Const];
2020
let Prototype = "void(...)";
2121
}
22+
23+
def SPIRVReflect : Builtin {
24+
let Spellings = ["__builtin_spirv_reflect"];
25+
let Attributes = [NoThrow, Const];
26+
let Prototype = "void(...)";
27+
}

clang/lib/CodeGen/CGBuiltin.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20829,6 +20829,19 @@ Value *CodeGenFunction::EmitSPIRVBuiltinExpr(unsigned BuiltinID,
2082920829
/*ReturnType=*/X->getType()->getScalarType(), Intrinsic::spv_length,
2083020830
ArrayRef<Value *>{X}, nullptr, "spv.length");
2083120831
}
20832+
case SPIRV::BI__builtin_spirv_reflect: {
20833+
Value *I = EmitScalarExpr(E->getArg(0));
20834+
Value *N = EmitScalarExpr(E->getArg(1));
20835+
assert(E->getArg(0)->getType()->hasFloatingRepresentation() &&
20836+
E->getArg(1)->getType()->hasFloatingRepresentation() &&
20837+
"Reflect operands must have a float representation");
20838+
assert(E->getArg(0)->getType()->isVectorType() &&
20839+
E->getArg(1)->getType()->isVectorType() &&
20840+
"Reflect operands must be a vector");
20841+
return Builder.CreateIntrinsic(
20842+
/*ReturnType=*/I->getType(), Intrinsic::spv_reflect,
20843+
ArrayRef<Value *>{I, N}, nullptr, "spv.reflect");
20844+
}
2083220845
}
2083320846
return nullptr;
2083420847
}

clang/lib/Headers/hlsl/hlsl_detail.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,22 @@ constexpr enable_if_t<is_same<float, T>::value || is_same<half, T>::value, T>
7979
distance_vec_impl(vector<T, N> X, vector<T, N> Y) {
8080
return length_vec_impl(X - Y);
8181
}
82+
83+
template <typename T>
84+
constexpr enable_if_t<is_same<float, T>::value || is_same<half, T>::value, T>
85+
reflect_impl(T I, T N) {
86+
return I - 2 * N * I * N;
87+
}
88+
89+
template <typename T, int L>
90+
constexpr vector<T, L> reflect_vec_impl(vector<T, L> I, vector<T, L> N) {
91+
#if (__has_builtin(__builtin_spirv_reflect))
92+
return __builtin_spirv_reflect(I, N);
93+
#else
94+
return I - 2 * N * __builtin_hlsl_dot(I, N);
95+
#endif
96+
}
97+
8298
} // namespace __detail
8399
} // namespace hlsl
84100
#endif //_HLSL_HLSL_DETAILS_H_

clang/lib/Headers/hlsl/hlsl_intrinsics.h

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2030,6 +2030,49 @@ double3 rcp(double3);
20302030
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_rcp)
20312031
double4 rcp(double4);
20322032

2033+
//===----------------------------------------------------------------------===//
2034+
// reflect builtin
2035+
//===----------------------------------------------------------------------===//
2036+
2037+
/// \fn T reflect(T I, T N)
2038+
/// \brief Returns a reflection using an incident ray, \a I, and a surface
2039+
/// normal, \a N.
2040+
/// \param I The incident ray.
2041+
/// \param N The surface normal.
2042+
///
2043+
/// The return value is a floating-point vector that represents the reflection
2044+
/// of the incident ray, \a I, off a surface with the normal \a N.
2045+
///
2046+
/// This function calculates the reflection vector using the following formula:
2047+
/// V = I - 2 * N * dot(I N) .
2048+
///
2049+
/// N must already be normalized in order to achieve the desired result.
2050+
///
2051+
/// The operands must all be a scalar or vector whose component type is
2052+
/// floating-point.
2053+
///
2054+
/// Result type and the type of all operands must be the same type.
2055+
2056+
_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
2057+
const inline half reflect(half I, half N) {
2058+
return __detail::reflect_impl(I, N);
2059+
}
2060+
2061+
const inline float reflect(float I, float N) {
2062+
return __detail::reflect_impl(I, N);
2063+
}
2064+
2065+
template <int L>
2066+
_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
2067+
const inline vector<half, L> reflect(vector<half, L> I, vector<half, L> N) {
2068+
return __detail::reflect_vec_impl(I, N);
2069+
}
2070+
2071+
template <int L>
2072+
const inline vector<float, L> reflect(vector<float, L> I, vector<float, L> N) {
2073+
return __detail::reflect_vec_impl(I, N);
2074+
}
2075+
20332076
//===----------------------------------------------------------------------===//
20342077
// rsqrt builtins
20352078
//===----------------------------------------------------------------------===//

clang/lib/Sema/SemaSPIRV.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,38 @@ bool SemaSPIRV::CheckSPIRVBuiltinFunctionCall(unsigned BuiltinID,
6969
TheCall->setType(RetTy);
7070
break;
7171
}
72+
case SPIRV::BI__builtin_spirv_reflect: {
73+
if (SemaRef.checkArgCount(TheCall, 2))
74+
return true;
75+
76+
ExprResult A = TheCall->getArg(0);
77+
QualType ArgTyA = A.get()->getType();
78+
auto *VTyA = ArgTyA->getAs<VectorType>();
79+
if (VTyA == nullptr) {
80+
SemaRef.Diag(A.get()->getBeginLoc(),
81+
diag::err_typecheck_convert_incompatible)
82+
<< ArgTyA
83+
<< SemaRef.Context.getVectorType(ArgTyA, 2, VectorKind::Generic) << 1
84+
<< 0 << 0;
85+
return true;
86+
}
87+
88+
ExprResult B = TheCall->getArg(1);
89+
QualType ArgTyB = B.get()->getType();
90+
auto *VTyB = ArgTyB->getAs<VectorType>();
91+
if (VTyB == nullptr) {
92+
SemaRef.Diag(A.get()->getBeginLoc(),
93+
diag::err_typecheck_convert_incompatible)
94+
<< ArgTyB
95+
<< SemaRef.Context.getVectorType(ArgTyB, 2, VectorKind::Generic) << 1
96+
<< 0 << 0;
97+
return true;
98+
}
99+
100+
QualType RetTy = ArgTyA;
101+
TheCall->setType(RetTy);
102+
break;
103+
}
72104
}
73105
return false;
74106
}
Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5
2+
// RUN: %clang_cc1 -finclude-default-header -triple \
3+
// RUN: dxil-pc-shadermodel6.3-library %s -fnative-half-type \
4+
// RUN: -emit-llvm -O1 -o - | FileCheck %s
5+
// RUN: %clang_cc1 -finclude-default-header -triple \
6+
// RUN: spirv-unknown-vulkan-compute %s -fnative-half-type \
7+
// RUN: -emit-llvm -O1 -o - | FileCheck %s --check-prefix=SPVCHECK
8+
9+
// CHECK-LABEL: define noundef nofpclass(nan inf) half @_Z17test_reflect_halfDhDh(
10+
// CHECK-SAME: half noundef nofpclass(nan inf) [[I:%.*]], half noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
11+
// CHECK-NEXT: [[ENTRY:.*:]]
12+
// CHECK-NEXT: [[MUL_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn half [[I]], 0xH4000
13+
// CHECK-NEXT: [[TMP0:%.*]] = fmul reassoc nnan ninf nsz arcp afn half [[N]], [[N]]
14+
// CHECK-NEXT: [[MUL2_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn half [[TMP0]], [[MUL_I]]
15+
// CHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn half [[I]], [[MUL2_I]]
16+
// CHECK-NEXT: ret half [[SUB_I]]
17+
//
18+
// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) half @_Z17test_reflect_halfDhDh(
19+
// SPVCHECK-SAME: half noundef nofpclass(nan inf) [[I:%.*]], half noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
20+
// SPVCHECK-NEXT: [[ENTRY:.*:]]
21+
// SPVCHECK-NEXT: [[MUL_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn half [[I]], 0xH4000
22+
// SPVCHECK-NEXT: [[TMP0:%.*]] = fmul reassoc nnan ninf nsz arcp afn half [[N]], [[N]]
23+
// SPVCHECK-NEXT: [[MUL2_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn half [[TMP0]], [[MUL_I]]
24+
// SPVCHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn half [[I]], [[MUL2_I]]
25+
// SPVCHECK-NEXT: ret half [[SUB_I]]
26+
//
27+
half test_reflect_half(half I, half N) {
28+
return reflect(I, N);
29+
}
30+
31+
// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x half> @_Z18test_reflect_half2Dv2_DhS_(
32+
// CHECK-SAME: <2 x half> noundef nofpclass(nan inf) [[I:%.*]], <2 x half> noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0]] {
33+
// CHECK-NEXT: [[ENTRY:.*:]]
34+
// 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]])
35+
// CHECK-NEXT: [[DOTSCALAR:%.*]] = fmul reassoc nnan ninf nsz arcp afn half [[HLSL_DOT_I]], 0xH4000
36+
// CHECK-NEXT: [[TMP0:%.*]] = insertelement <2 x half> poison, half [[DOTSCALAR]], i64 0
37+
// CHECK-NEXT: [[TMP1:%.*]] = shufflevector <2 x half> [[TMP0]], <2 x half> poison, <2 x i32> zeroinitializer
38+
// CHECK-NEXT: [[MUL1_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn <2 x half> [[TMP1]], [[N]]
39+
// CHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <2 x half> [[I]], [[MUL1_I]]
40+
// CHECK-NEXT: ret <2 x half> [[SUB_I]]
41+
//
42+
// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) <2 x half> @_Z18test_reflect_half2Dv2_DhS_(
43+
// SPVCHECK-SAME: <2 x half> noundef nofpclass(nan inf) [[I:%.*]], <2 x half> noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0]] {
44+
// SPVCHECK-NEXT: [[ENTRY:.*:]]
45+
// 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]])
46+
// SPVCHECK-NEXT: ret <2 x half> [[SPV_REFLECT_I]]
47+
//
48+
half2 test_reflect_half2(half2 I, half2 N) {
49+
return reflect(I, N);
50+
}
51+
52+
// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x half> @_Z18test_reflect_half3Dv3_DhS_(
53+
// CHECK-SAME: <3 x half> noundef nofpclass(nan inf) [[I:%.*]], <3 x half> noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0]] {
54+
// CHECK-NEXT: [[ENTRY:.*:]]
55+
// 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]])
56+
// CHECK-NEXT: [[DOTSCALAR:%.*]] = fmul reassoc nnan ninf nsz arcp afn half [[HLSL_DOT_I]], 0xH4000
57+
// CHECK-NEXT: [[TMP0:%.*]] = insertelement <3 x half> poison, half [[DOTSCALAR]], i64 0
58+
// CHECK-NEXT: [[TMP1:%.*]] = shufflevector <3 x half> [[TMP0]], <3 x half> poison, <3 x i32> zeroinitializer
59+
// CHECK-NEXT: [[MUL1_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn <3 x half> [[TMP1]], [[N]]
60+
// CHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <3 x half> [[I]], [[MUL1_I]]
61+
// CHECK-NEXT: ret <3 x half> [[SUB_I]]
62+
//
63+
// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) <3 x half> @_Z18test_reflect_half3Dv3_DhS_(
64+
// SPVCHECK-SAME: <3 x half> noundef nofpclass(nan inf) [[I:%.*]], <3 x half> noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0]] {
65+
// SPVCHECK-NEXT: [[ENTRY:.*:]]
66+
// 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]])
67+
// SPVCHECK-NEXT: ret <3 x half> [[SPV_REFLECT_I]]
68+
//
69+
half3 test_reflect_half3(half3 I, half3 N) {
70+
return reflect(I, N);
71+
}
72+
73+
// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x half> @_Z18test_reflect_half4Dv4_DhS_(
74+
// CHECK-SAME: <4 x half> noundef nofpclass(nan inf) [[I:%.*]], <4 x half> noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0]] {
75+
// CHECK-NEXT: [[ENTRY:.*:]]
76+
// 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]])
77+
// CHECK-NEXT: [[DOTSCALAR:%.*]] = fmul reassoc nnan ninf nsz arcp afn half [[HLSL_DOT_I]], 0xH4000
78+
// CHECK-NEXT: [[TMP0:%.*]] = insertelement <4 x half> poison, half [[DOTSCALAR]], i64 0
79+
// CHECK-NEXT: [[TMP1:%.*]] = shufflevector <4 x half> [[TMP0]], <4 x half> poison, <4 x i32> zeroinitializer
80+
// CHECK-NEXT: [[MUL1_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn <4 x half> [[TMP1]], [[N]]
81+
// CHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <4 x half> [[I]], [[MUL1_I]]
82+
// CHECK-NEXT: ret <4 x half> [[SUB_I]]
83+
//
84+
// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) <4 x half> @_Z18test_reflect_half4Dv4_DhS_(
85+
// SPVCHECK-SAME: <4 x half> noundef nofpclass(nan inf) [[I:%.*]], <4 x half> noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0]] {
86+
// SPVCHECK-NEXT: [[ENTRY:.*:]]
87+
// 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]])
88+
// SPVCHECK-NEXT: ret <4 x half> [[SPV_REFLECT_I]]
89+
//
90+
half4 test_reflect_half4(half4 I, half4 N) {
91+
return reflect(I, N);
92+
}
93+
94+
// CHECK-LABEL: define noundef nofpclass(nan inf) float @_Z18test_reflect_floatff(
95+
// CHECK-SAME: float noundef nofpclass(nan inf) [[I:%.*]], float noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0]] {
96+
// CHECK-NEXT: [[ENTRY:.*:]]
97+
// CHECK-NEXT: [[MUL_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn float [[I]], 2.000000e+00
98+
// CHECK-NEXT: [[TMP0:%.*]] = fmul reassoc nnan ninf nsz arcp afn float [[N]], [[N]]
99+
// CHECK-NEXT: [[MUL2_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn float [[TMP0]], [[MUL_I]]
100+
// CHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn float [[I]], [[MUL2_I]]
101+
// CHECK-NEXT: ret float [[SUB_I]]
102+
//
103+
// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) float @_Z18test_reflect_floatff(
104+
// SPVCHECK-SAME: float noundef nofpclass(nan inf) [[I:%.*]], float noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0]] {
105+
// SPVCHECK-NEXT: [[ENTRY:.*:]]
106+
// SPVCHECK-NEXT: [[MUL_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn float [[I]], 2.000000e+00
107+
// SPVCHECK-NEXT: [[TMP0:%.*]] = fmul reassoc nnan ninf nsz arcp afn float [[N]], [[N]]
108+
// SPVCHECK-NEXT: [[MUL2_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn float [[TMP0]], [[MUL_I]]
109+
// SPVCHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn float [[I]], [[MUL2_I]]
110+
// SPVCHECK-NEXT: ret float [[SUB_I]]
111+
//
112+
float test_reflect_float(float I, float N) {
113+
return reflect(I, N);
114+
}
115+
116+
// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> @_Z19test_reflect_float2Dv2_fS_(
117+
// CHECK-SAME: <2 x float> noundef nofpclass(nan inf) [[I:%.*]], <2 x float> noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0]] {
118+
// CHECK-NEXT: [[ENTRY:.*:]]
119+
// 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]])
120+
// CHECK-NEXT: [[DOTSCALAR:%.*]] = fmul reassoc nnan ninf nsz arcp afn float [[HLSL_DOT_I]], 2.000000e+00
121+
// CHECK-NEXT: [[TMP0:%.*]] = insertelement <2 x float> poison, float [[DOTSCALAR]], i64 0
122+
// CHECK-NEXT: [[TMP1:%.*]] = shufflevector <2 x float> [[TMP0]], <2 x float> poison, <2 x i32> zeroinitializer
123+
// CHECK-NEXT: [[MUL1_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn <2 x float> [[TMP1]], [[N]]
124+
// CHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <2 x float> [[I]], [[MUL1_I]]
125+
// CHECK-NEXT: ret <2 x float> [[SUB_I]]
126+
//
127+
// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) <2 x float> @_Z19test_reflect_float2Dv2_fS_(
128+
// SPVCHECK-SAME: <2 x float> noundef nofpclass(nan inf) [[I:%.*]], <2 x float> noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0]] {
129+
// SPVCHECK-NEXT: [[ENTRY:.*:]]
130+
// 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]])
131+
// SPVCHECK-NEXT: ret <2 x float> [[SPV_REFLECT_I]]
132+
//
133+
float2 test_reflect_float2(float2 I, float2 N) {
134+
return reflect(I, N);
135+
}
136+
137+
// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> @_Z19test_reflect_float3Dv3_fS_(
138+
// CHECK-SAME: <3 x float> noundef nofpclass(nan inf) [[I:%.*]], <3 x float> noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0]] {
139+
// CHECK-NEXT: [[ENTRY:.*:]]
140+
// 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]])
141+
// CHECK-NEXT: [[DOTSCALAR:%.*]] = fmul reassoc nnan ninf nsz arcp afn float [[HLSL_DOT_I]], 2.000000e+00
142+
// CHECK-NEXT: [[TMP0:%.*]] = insertelement <3 x float> poison, float [[DOTSCALAR]], i64 0
143+
// CHECK-NEXT: [[TMP1:%.*]] = shufflevector <3 x float> [[TMP0]], <3 x float> poison, <3 x i32> zeroinitializer
144+
// CHECK-NEXT: [[MUL1_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn <3 x float> [[TMP1]], [[N]]
145+
// CHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <3 x float> [[I]], [[MUL1_I]]
146+
// CHECK-NEXT: ret <3 x float> [[SUB_I]]
147+
//
148+
// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) <3 x float> @_Z19test_reflect_float3Dv3_fS_(
149+
// SPVCHECK-SAME: <3 x float> noundef nofpclass(nan inf) [[I:%.*]], <3 x float> noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0]] {
150+
// SPVCHECK-NEXT: [[ENTRY:.*:]]
151+
// 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]])
152+
// SPVCHECK-NEXT: ret <3 x float> [[SPV_REFLECT_I]]
153+
//
154+
float3 test_reflect_float3(float3 I, float3 N) {
155+
return reflect(I, N);
156+
}
157+
158+
// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> @_Z19test_reflect_float4Dv4_fS_(
159+
// CHECK-SAME: <4 x float> noundef nofpclass(nan inf) [[I:%.*]], <4 x float> noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0]] {
160+
// CHECK-NEXT: [[ENTRY:.*:]]
161+
// 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]])
162+
// CHECK-NEXT: [[DOTSCALAR:%.*]] = fmul reassoc nnan ninf nsz arcp afn float [[HLSL_DOT_I]], 2.000000e+00
163+
// CHECK-NEXT: [[TMP0:%.*]] = insertelement <4 x float> poison, float [[DOTSCALAR]], i64 0
164+
// CHECK-NEXT: [[TMP1:%.*]] = shufflevector <4 x float> [[TMP0]], <4 x float> poison, <4 x i32> zeroinitializer
165+
// CHECK-NEXT: [[MUL1_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn <4 x float> [[TMP1]], [[N]]
166+
// CHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <4 x float> [[I]], [[MUL1_I]]
167+
// CHECK-NEXT: ret <4 x float> [[SUB_I]]
168+
//
169+
// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) <4 x float> @_Z19test_reflect_float4Dv4_fS_(
170+
// SPVCHECK-SAME: <4 x float> noundef nofpclass(nan inf) [[I:%.*]], <4 x float> noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0]] {
171+
// SPVCHECK-NEXT: [[ENTRY:.*:]]
172+
// 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]])
173+
// SPVCHECK-NEXT: ret <4 x float> [[SPV_REFLECT_I]]
174+
//
175+
float4 test_reflect_float4(float4 I, float4 N) {
176+
return reflect(I, N);
177+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5
2+
3+
// RUN: %clang_cc1 -O1 -triple spirv-pc-vulkan-compute %s -emit-llvm -o - | FileCheck %s
4+
5+
typedef float float2 __attribute__((ext_vector_type(2)));
6+
typedef float float3 __attribute__((ext_vector_type(3)));
7+
typedef float float4 __attribute__((ext_vector_type(4)));
8+
9+
// CHECK-LABEL: define spir_func <2 x float> @test_reflect_float2(
10+
// CHECK-SAME: <2 x float> noundef [[X:%.*]], <2 x float> noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
11+
// CHECK-NEXT: [[ENTRY:.*:]]
12+
// CHECK-NEXT: [[SPV_REFLECT:%.*]] = tail call <2 x float> @llvm.spv.reflect.v2f32(<2 x float> [[X]], <2 x float> [[Y]])
13+
// CHECK-NEXT: ret <2 x float> [[SPV_REFLECT]]
14+
//
15+
float2 test_reflect_float2(float2 X, float2 Y) { return __builtin_spirv_reflect(X, Y); }
16+
17+
// CHECK-LABEL: define spir_func <3 x float> @test_reflect_float3(
18+
// CHECK-SAME: <3 x float> noundef [[X:%.*]], <3 x float> noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] {
19+
// CHECK-NEXT: [[ENTRY:.*:]]
20+
// CHECK-NEXT: [[SPV_REFLECT:%.*]] = tail call <3 x float> @llvm.spv.reflect.v3f32(<3 x float> [[X]], <3 x float> [[Y]])
21+
// CHECK-NEXT: ret <3 x float> [[SPV_REFLECT]]
22+
//
23+
float3 test_reflect_float3(float3 X, float3 Y) { return __builtin_spirv_reflect(X, Y); }
24+
25+
// CHECK-LABEL: define spir_func <4 x float> @test_reflect_float4(
26+
// CHECK-SAME: <4 x float> noundef [[X:%.*]], <4 x float> noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] {
27+
// CHECK-NEXT: [[ENTRY:.*:]]
28+
// CHECK-NEXT: [[SPV_REFLECT:%.*]] = tail call <4 x float> @llvm.spv.reflect.v4f32(<4 x float> [[X]], <4 x float> [[Y]])
29+
// CHECK-NEXT: ret <4 x float> [[SPV_REFLECT]]
30+
//
31+
float4 test_reflect_float4(float4 X, float4 Y) { return __builtin_spirv_reflect(X, Y); }
32+

0 commit comments

Comments
 (0)