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](https://github.com/llvm/llvm-project/pull/123853#issuecomment-2608389396) 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 https://github.com/llvm/llvm-project/pull/125599#discussion_r1966650839 and https://github.com/llvm/llvm-project/pull/125599#discussion_r1966650839
This commit is contained in:
@@ -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(...)";
|
||||
}
|
||||
|
||||
@@ -20829,6 +20829,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;
|
||||
}
|
||||
|
||||
@@ -79,6 +79,22 @@ 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 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
|
||||
return I - 2 * N * __builtin_hlsl_dot(I, N);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace __detail
|
||||
} // namespace hlsl
|
||||
#endif //_HLSL_HLSL_DETAILS_H_
|
||||
|
||||
@@ -2030,6 +2030,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 vector<half, L> reflect(vector<half, L> I, vector<half, L> N) {
|
||||
return __detail::reflect_vec_impl(I, N);
|
||||
}
|
||||
|
||||
template <int L>
|
||||
const inline vector<float, L> reflect(vector<float, L> I, vector<float, L> N) {
|
||||
return __detail::reflect_vec_impl(I, N);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// rsqrt builtins
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
177
clang/test/CodeGenHLSL/builtins/reflect.hlsl
Normal file
177
clang/test/CodeGenHLSL/builtins/reflect.hlsl
Normal file
@@ -0,0 +1,177 @@
|
||||
// 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: [[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: ret <2 x half> [[SPV_REFLECT_I]]
|
||||
//
|
||||
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: [[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: ret <3 x half> [[SPV_REFLECT_I]]
|
||||
//
|
||||
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: [[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: ret <4 x half> [[SPV_REFLECT_I]]
|
||||
//
|
||||
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: [[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: ret <2 x float> [[SPV_REFLECT_I]]
|
||||
//
|
||||
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: [[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: ret <3 x float> [[SPV_REFLECT_I]]
|
||||
//
|
||||
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: [[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: ret <4 x float> [[SPV_REFLECT_I]]
|
||||
//
|
||||
float4 test_reflect_float4(float4 I, float4 N) {
|
||||
return reflect(I, N);
|
||||
}
|
||||
32
clang/test/CodeGenSPIRV/Builtins/reflect.c
Normal file
32
clang/test/CodeGenSPIRV/Builtins/reflect.c
Normal file
@@ -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); }
|
||||
|
||||
33
clang/test/SemaHLSL/BuiltIns/reflect-errors.hlsl
Normal file
33
clang/test/SemaHLSL/BuiltIns/reflect-errors.hlsl
Normal file
@@ -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@-1 {{no matching function for call to 'reflect'}}
|
||||
// expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function not viable: requires 2 arguments, but 1 was provided}}
|
||||
// expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function not viable: requires 2 arguments, but 1 was provided}}
|
||||
// expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 2 arguments, but 1 was provided}}
|
||||
// expected-note@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@-1 {{no matching function for call to 'reflect'}}
|
||||
// expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function not viable: requires 2 arguments, but 3 were provided}}
|
||||
// expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function not viable: requires 2 arguments, but 3 were provided}}
|
||||
// expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 2 arguments, but 3 were provided}}
|
||||
// expected-note@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@-1 {{call to 'reflect' is ambiguous}}
|
||||
// expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function}}
|
||||
// expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function}}
|
||||
}
|
||||
|
||||
float test_int_inputs(int p0, int p1) {
|
||||
return reflect(p0, p1);
|
||||
// expected-error@-1 {{call to 'reflect' is ambiguous}}
|
||||
// expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function}}
|
||||
// expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function}}
|
||||
}
|
||||
23
clang/test/SemaSPIRV/BuiltIns/reflect-errors.c
Normal file
23
clang/test/SemaSPIRV/BuiltIns/reflect-errors.c
Normal file
@@ -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@-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@-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@-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@-1 {{passing 'int' to parameter of incompatible type '__attribute__((__vector_size__(2 * sizeof(int)))) int' (vector of 2 'int' values)}}
|
||||
}
|
||||
@@ -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]>;
|
||||
|
||||
@@ -273,10 +273,8 @@ private:
|
||||
bool selectPhi(Register ResVReg, const SPIRVType *ResType,
|
||||
MachineInstr &I) const;
|
||||
|
||||
[[maybe_unused]] bool selectExtInst(Register ResVReg,
|
||||
const SPIRVType *RestType,
|
||||
MachineInstr &I,
|
||||
GL::GLSLExtInst GLInst) const;
|
||||
bool selectExtInst(Register ResVReg, const SPIRVType *RestType,
|
||||
MachineInstr &I, GL::GLSLExtInst GLInst) const;
|
||||
bool selectExtInst(Register ResVReg, const SPIRVType *ResType,
|
||||
MachineInstr &I, CL::OpenCLExtInst CLInst) const;
|
||||
bool selectExtInst(Register ResVReg, const SPIRVType *ResType,
|
||||
@@ -905,6 +903,14 @@ bool SPIRVInstructionSelector::selectExtInst(Register ResVReg,
|
||||
const SPIRVType *ResType,
|
||||
MachineInstr &I,
|
||||
GL::GLSLExtInst GLInst) const {
|
||||
if (!STI.canUseExtInstSet(
|
||||
SPIRV::InstructionSet::InstructionSet::GLSL_std_450)) {
|
||||
std::string DiagMsg;
|
||||
raw_string_ostream OS(DiagMsg);
|
||||
I.print(OS, true, false, false, false);
|
||||
DiagMsg += " is only supported with the GLSL extended instruction set.\n";
|
||||
report_fatal_error(DiagMsg.c_str(), false);
|
||||
}
|
||||
return selectExtInst(ResVReg, ResType, I,
|
||||
{{SPIRV::InstructionSet::GLSL_std_450, GLInst}});
|
||||
}
|
||||
@@ -3061,6 +3067,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:
|
||||
return selectExtInst(ResVReg, ResType, I, GL::Reflect);
|
||||
case Intrinsic::spv_rsqrt:
|
||||
return selectExtInst(ResVReg, ResType, I, CL::rsqrt, GL::InverseSqrt);
|
||||
case Intrinsic::spv_sign:
|
||||
|
||||
33
llvm/test/CodeGen/SPIRV/hlsl-intrinsics/reflect.ll
Normal file
33
llvm/test/CodeGen/SPIRV/hlsl-intrinsics/reflect.ll
Normal file
@@ -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>)
|
||||
13
llvm/test/CodeGen/SPIRV/opencl/reflect-error.ll
Normal file
13
llvm/test/CodeGen/SPIRV/opencl/reflect-error.ll
Normal file
@@ -0,0 +1,13 @@
|
||||
; 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
|
||||
|
||||
; CHECK: LLVM ERROR: %{{.*}} = G_INTRINSIC intrinsic(@llvm.spv.reflect), %{{.*}}, %{{.*}} is only supported with the GLSL extended instruction set.
|
||||
|
||||
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 float> @llvm.spv.reflect.f32(<4 x float>, <4 x float>)
|
||||
|
||||
Reference in New Issue
Block a user