-
Notifications
You must be signed in to change notification settings - Fork 13.3k
[HLSL] Implement the faceforward
intrinsic
#135878
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
@llvm/pr-subscribers-clang @llvm/pr-subscribers-hlsl Author: Kaitlin Peng (kmpeng) ChangesResolves #99114. There will be a follow-up PR on pattern matching later. Tasks completed:
Incomplete tasks:
Patch is 27.53 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/135878.diff 12 Files Affected:
diff --git a/clang/include/clang/Basic/BuiltinsSPIRV.td b/clang/include/clang/Basic/BuiltinsSPIRV.td
index 9f76d672cc7ce..cc0c2f960f8d2 100644
--- a/clang/include/clang/Basic/BuiltinsSPIRV.td
+++ b/clang/include/clang/Basic/BuiltinsSPIRV.td
@@ -31,3 +31,9 @@ def SPIRVSmoothStep : Builtin {
let Attributes = [NoThrow, Const, CustomTypeChecking];
let Prototype = "void(...)";
}
+
+def SPIRVFaceForward : Builtin {
+ let Spellings = ["__builtin_spirv_faceforward"];
+ let Attributes = [NoThrow, Const, CustomTypeChecking];
+ let Prototype = "void(...)";
+}
diff --git a/clang/lib/CodeGen/TargetBuiltins/SPIR.cpp b/clang/lib/CodeGen/TargetBuiltins/SPIR.cpp
index 92e2c1c6da68f..c1bcc9ae084d0 100644
--- a/clang/lib/CodeGen/TargetBuiltins/SPIR.cpp
+++ b/clang/lib/CodeGen/TargetBuiltins/SPIR.cpp
@@ -71,6 +71,18 @@ Value *CodeGenFunction::EmitSPIRVBuiltinExpr(unsigned BuiltinID,
ArrayRef<Value *>{Min, Max, X}, /*FMFSource=*/nullptr,
"spv.smoothstep");
}
+ case SPIRV::BI__builtin_spirv_faceforward: {
+ Value *N = EmitScalarExpr(E->getArg(0));
+ Value *I = EmitScalarExpr(E->getArg(1));
+ Value *Ng = EmitScalarExpr(E->getArg(2));
+ assert(E->getArg(0)->getType()->hasFloatingRepresentation() &&
+ E->getArg(1)->getType()->hasFloatingRepresentation() &&
+ E->getArg(2)->getType()->hasFloatingRepresentation() &&
+ "FaceForward operands must have a float representation");
+ return Builder.CreateIntrinsic(
+ /*ReturnType=*/N->getType(), Intrinsic::spv_smoothstep,
+ ArrayRef<Value *>{N, I, Ng}, /*FMFSource=*/nullptr, "spv.faceforward");
+ }
}
return nullptr;
}
diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h b/clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h
index 3a8a9b6fa2a45..b2332419dc034 100644
--- a/clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h
+++ b/clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h
@@ -126,6 +126,24 @@ template <typename T> constexpr vector<T, 4> lit_impl(T NDotL, T NDotH, T M) {
return Result;
}
+template <typename T> constexpr T faceforward_impl(T N, T I, T Ng) {
+#if (__has_builtin(__builtin_spirv_faceforward))
+ return __builtin_spirv_faceforward(N, I, Ng);
+#else
+ return select(I * Ng < 0, N, -N);
+#endif
+}
+
+template <typename T, int L>
+constexpr vector<T, L> faceforward_vec_impl(vector<T, L> N, vector<T, L> I,
+ vector<T, L> Ng) {
+#if (__has_builtin(__builtin_spirv_faceforward))
+ return __builtin_spirv_faceforward(N, I, Ng);
+#else
+ return select(dot(I, Ng) < 0, N, -N);
+#endif
+}
+
} // namespace __detail
} // namespace hlsl
diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h
index 35ff80052cf43..f4af34ea28b86 100644
--- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h
+++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h
@@ -214,6 +214,53 @@ const inline double4 dst(double4 Src0, double4 Src1) {
return __detail::dst_impl(Src0, Src1);
}
+//===----------------------------------------------------------------------===//
+// faceforward builtin
+//===----------------------------------------------------------------------===//
+
+/// \fn T faceforward(T N, T I, T Ng)
+/// \brief Flips the surface-normal (if needed) to face in a direction opposite
+/// to \a I. Returns the result in \a N.
+/// \param N The resulting floating-point surface-normal vector.
+/// \param I A floating-point, incident vector that points from the view
+/// position to the shading position.
+/// \param Ng A floating-point surface-normal vector.
+///
+/// Return a floating-point, surface normal vector that is facing the view
+/// direction.
+
+template <typename T>
+_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
+const inline __detail::enable_if_t<__detail::is_arithmetic<T>::Value &&
+ __detail::is_same<half, T>::value,
+ T> faceforward(T N, T I, T Ng) {
+ return __detail::faceforward_impl(N, I, Ng);
+}
+
+template <typename T>
+const inline __detail::enable_if_t<
+ __detail::is_arithmetic<T>::Value && __detail::is_same<float, T>::value, T>
+faceforward(T N, T I, T Ng) {
+ return __detail::faceforward_impl(N, I, Ng);
+}
+
+template <int L>
+_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
+const inline __detail::HLSL_FIXED_VECTOR<half, L> faceforward(
+ __detail::HLSL_FIXED_VECTOR<half, L> N,
+ __detail::HLSL_FIXED_VECTOR<half, L> I,
+ __detail::HLSL_FIXED_VECTOR<half, L> Ng) {
+ return __detail::faceforward_vec_impl(N, I, Ng);
+}
+
+template <int L>
+const inline __detail::HLSL_FIXED_VECTOR<float, L>
+faceforward(__detail::HLSL_FIXED_VECTOR<float, L> N,
+ __detail::HLSL_FIXED_VECTOR<float, L> I,
+ __detail::HLSL_FIXED_VECTOR<float, L> Ng) {
+ return __detail::faceforward_vec_impl(N, I, Ng);
+}
+
//===----------------------------------------------------------------------===//
// fmod builtins
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/Sema/SemaSPIRV.cpp b/clang/lib/Sema/SemaSPIRV.cpp
index 7131514d53421..ed40d005c8ce5 100644
--- a/clang/lib/Sema/SemaSPIRV.cpp
+++ b/clang/lib/Sema/SemaSPIRV.cpp
@@ -137,6 +137,42 @@ bool SemaSPIRV::CheckSPIRVBuiltinFunctionCall(unsigned BuiltinID,
TheCall->setType(RetTy);
break;
}
+ case SPIRV::BI__builtin_spirv_faceforward: {
+ if (SemaRef.checkArgCount(TheCall, 3))
+ return true;
+
+ // check if all arguments have floating representation
+ for (unsigned i = 0; i < TheCall->getNumArgs(); ++i) {
+ ExprResult Arg = TheCall->getArg(i);
+ QualType ArgTy = Arg.get()->getType();
+ if (!ArgTy->hasFloatingRepresentation()) {
+ SemaRef.Diag(Arg.get()->getBeginLoc(),
+ diag::err_builtin_invalid_arg_type)
+ << i + 1 << /* scalar or vector */ 5 << /* no int */ 0 << /* fp */ 1
+ << ArgTy;
+ return true;
+ }
+ }
+
+ // check if all arguments are of the same type
+ ExprResult A = TheCall->getArg(0);
+ ExprResult B = TheCall->getArg(1);
+ ExprResult C = TheCall->getArg(2);
+ if (!(SemaRef.getASTContext().hasSameUnqualifiedType(A.get()->getType(),
+ B.get()->getType()) &&
+ SemaRef.getASTContext().hasSameUnqualifiedType(A.get()->getType(),
+ C.get()->getType()))) {
+ SemaRef.Diag(TheCall->getBeginLoc(),
+ diag::err_vec_builtin_incompatible_vector)
+ << TheCall->getDirectCallee() << /*useAllTerminology*/ true
+ << SourceRange(A.get()->getBeginLoc(), C.get()->getEndLoc());
+ return true;
+ }
+
+ QualType RetTy = A.get()->getType();
+ TheCall->setType(RetTy);
+ break;
+ }
}
return false;
}
diff --git a/clang/test/CodeGenHLSL/builtins/faceforward.hlsl b/clang/test/CodeGenHLSL/builtins/faceforward.hlsl
new file mode 100644
index 0000000000000..d1942a4bc4b6c
--- /dev/null
+++ b/clang/test/CodeGenHLSL/builtins/faceforward.hlsl
@@ -0,0 +1,94 @@
+// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \
+// RUN: dxil-pc-shadermodel6.3-library %s -fnative-half-type \
+// RUN: -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -finclude-default-header -triple \
+// RUN: spirv-unknown-vulkan-compute %s -fnative-half-type \
+// RUN: -emit-llvm -o - | FileCheck %s --check-prefix=SPVCHECK
+
+// CHECK-LABEL: test_faceforward_half
+// CHECK: %mul.i = fmul reassoc nnan ninf nsz arcp afn half %{{.*}}, %{{.*}}
+// CHECK: %cmp.i = fcmp reassoc nnan ninf nsz arcp afn olt half %mul.i, 0xH0000
+// CHECK: %fneg.i = fneg reassoc nnan ninf nsz arcp afn half %{{.*}}
+// CHECK: %hlsl.select.i = select reassoc nnan ninf nsz arcp afn i1 %cmp.i, half %{{.*}}, half %fneg.i
+// CHECK: ret half %hlsl.select.i
+// SPVCHECK-LABEL: test_faceforward_half
+// SPVCHECK: %spv.faceforward.i = call reassoc nnan ninf nsz arcp afn noundef half @llvm.spv.smoothstep.f16(half %{{.*}}, half %{{.*}}, half %{{.*}})
+// SPVCHECK: ret half %spv.faceforward.i
+half test_faceforward_half(half N, half I, half Ng) { return faceforward(N, I, Ng); }
+
+// CHECK-LABEL: test_faceforward_half2
+// CHECK: %hlsl.dot.i = call reassoc nnan ninf nsz arcp afn half @llvm.dx.fdot.v2f16(<2 x half> %{{.*}}, <2 x half> %{{.*}})
+// CHECK: %cmp.i = fcmp reassoc nnan ninf nsz arcp afn olt half %hlsl.dot.i, 0xH0000
+// CHECK: %fneg.i = fneg reassoc nnan ninf nsz arcp afn <2 x half> %{{.*}}
+// CHECK: %hlsl.select.i = select reassoc nnan ninf nsz arcp afn i1 %cmp.i, <2 x half> %{{.*}}, <2 x half> %fneg.i
+// CHECK: ret <2 x half> %hlsl.select.i
+// SPVCHECK-LABEL: test_faceforward_half2
+// SPVCHECK: %spv.faceforward.i = call reassoc nnan ninf nsz arcp afn noundef <2 x half> @llvm.spv.smoothstep.v2f16(<2 x half> %{{.*}}, <2 x half> %{{.*}}, <2 x half> %{{.*}})
+// SPVCHECK: ret <2 x half> %spv.faceforward.i
+half2 test_faceforward_half2(half2 N, half2 I, half2 Ng) { return faceforward(N, I, Ng); }
+
+// CHECK-LABEL: test_faceforward_half3
+// CHECK: %hlsl.dot.i = call reassoc nnan ninf nsz arcp afn half @llvm.dx.fdot.v3f16(<3 x half> %{{.*}}, <3 x half> %{{.*}})
+// CHECK: %cmp.i = fcmp reassoc nnan ninf nsz arcp afn olt half %hlsl.dot.i, 0xH0000
+// CHECK: %fneg.i = fneg reassoc nnan ninf nsz arcp afn <3 x half> %{{.*}}
+// CHECK: %hlsl.select.i = select reassoc nnan ninf nsz arcp afn i1 %cmp.i, <3 x half> %{{.*}}, <3 x half> %fneg.i
+// CHECK: ret <3 x half> %hlsl.select.i
+// SPVCHECK-LABEL: test_faceforward_half3
+// SPVCHECK: %spv.faceforward.i = call reassoc nnan ninf nsz arcp afn noundef <3 x half> @llvm.spv.smoothstep.v3f16(<3 x half> %{{.*}}, <3 x half> %{{.*}}, <3 x half> %{{.*}})
+// SPVCHECK: ret <3 x half> %spv.faceforward.i
+half3 test_faceforward_half3(half3 N, half3 I, half3 Ng) { return faceforward(N, I, Ng); }
+
+// CHECK-LABEL: test_faceforward_half4
+// CHECK: %hlsl.dot.i = call reassoc nnan ninf nsz arcp afn half @llvm.dx.fdot.v4f16(<4 x half> %{{.*}}, <4 x half> %{{.*}})
+// CHECK: %cmp.i = fcmp reassoc nnan ninf nsz arcp afn olt half %hlsl.dot.i, 0xH0000
+// CHECK: %fneg.i = fneg reassoc nnan ninf nsz arcp afn <4 x half> %{{.*}}
+// CHECK: %hlsl.select.i = select reassoc nnan ninf nsz arcp afn i1 %cmp.i, <4 x half> %{{.*}}, <4 x half> %fneg.i
+// CHECK: ret <4 x half> %hlsl.select.i
+// SPVCHECK-LABEL: test_faceforward_half4
+// SPVCHECK: %spv.faceforward.i = call reassoc nnan ninf nsz arcp afn noundef <4 x half> @llvm.spv.smoothstep.v4f16(<4 x half> %{{.*}}, <4 x half> %{{.*}}, <4 x half> %{{.*}})
+// SPVCHECK: ret <4 x half> %spv.faceforward.i
+half4 test_faceforward_half4(half4 N, half4 I, half4 Ng) { return faceforward(N, I, Ng); }
+
+// CHECK-LABEL: test_faceforward_float
+// CHECK: %mul.i = fmul reassoc nnan ninf nsz arcp afn float %{{.*}}, %{{.*}}
+// CHECK: %cmp.i = fcmp reassoc nnan ninf nsz arcp afn olt float %mul.i, 0.000000e+00
+// CHECK: %fneg.i = fneg reassoc nnan ninf nsz arcp afn float %{{.*}}
+// CHECK: %hlsl.select.i = select reassoc nnan ninf nsz arcp afn i1 %cmp.i, float %{{.*}}, float %fneg.i
+// CHECK: ret float %hlsl.select.i
+// SPVCHECK-LABEL: test_faceforward_float
+// SPVCHECK: %spv.faceforward.i = call reassoc nnan ninf nsz arcp afn noundef float @llvm.spv.smoothstep.f32(float %{{.*}}, float %{{.*}}, float %{{.*}})
+// SPVCHECK: ret float %spv.faceforward.i
+float test_faceforward_float(float N, float I, float Ng) { return faceforward(N, I, Ng); }
+
+// CHECK-LABEL: test_faceforward_float2
+// CHECK: %hlsl.dot.i = call reassoc nnan ninf nsz arcp afn float @llvm.dx.fdot.v2f32(<2 x float> %{{.*}}, <2 x float> %{{.*}})
+// CHECK: %cmp.i = fcmp reassoc nnan ninf nsz arcp afn olt float %hlsl.dot.i, 0.000000e+00
+// CHECK: %fneg.i = fneg reassoc nnan ninf nsz arcp afn <2 x float> %{{.*}}
+// CHECK: %hlsl.select.i = select reassoc nnan ninf nsz arcp afn i1 %cmp.i, <2 x float> %{{.*}}, <2 x float> %fneg.i
+// CHECK: ret <2 x float> %hlsl.select.i
+// SPVCHECK-LABEL: test_faceforward_float2
+// SPVCHECK: %spv.faceforward.i = call reassoc nnan ninf nsz arcp afn noundef <2 x float> @llvm.spv.smoothstep.v2f32(<2 x float> %{{.*}}, <2 x float> %{{.*}}, <2 x float> %{{.*}})
+// SPVCHECK: ret <2 x float> %spv.faceforward.i
+float2 test_faceforward_float2(float2 N, float2 I, float2 Ng) { return faceforward(N, I, Ng); }
+
+// CHECK-LABEL: test_faceforward_float3
+// CHECK: %hlsl.dot.i = call reassoc nnan ninf nsz arcp afn float @llvm.dx.fdot.v3f32(<3 x float> %{{.*}}, <3 x float> %{{.*}})
+// CHECK: %cmp.i = fcmp reassoc nnan ninf nsz arcp afn olt float %hlsl.dot.i, 0.000000e+00
+// CHECK: %fneg.i = fneg reassoc nnan ninf nsz arcp afn <3 x float> %{{.*}}
+// CHECK: %hlsl.select.i = select reassoc nnan ninf nsz arcp afn i1 %cmp.i, <3 x float> %{{.*}}, <3 x float> %fneg.i
+// CHECK: ret <3 x float> %hlsl.select.i
+// SPVCHECK-LABEL: test_faceforward_float3
+// SPVCHECK: %spv.faceforward.i = call reassoc nnan ninf nsz arcp afn noundef <3 x float> @llvm.spv.smoothstep.v3f32(<3 x float> %{{.*}}, <3 x float> %{{.*}}, <3 x float> %{{.*}})
+// SPVCHECK: ret <3 x float> %spv.faceforward.i
+float3 test_faceforward_float3(float3 N, float3 I, float3 Ng) { return faceforward(N, I, Ng); }
+
+// CHECK-LABEL: test_faceforward_float4
+// CHECK: %hlsl.dot.i = call reassoc nnan ninf nsz arcp afn float @llvm.dx.fdot.v4f32(<4 x float> %{{.*}}, <4 x float> %{{.*}})
+// CHECK: %cmp.i = fcmp reassoc nnan ninf nsz arcp afn olt float %hlsl.dot.i, 0.000000e+00
+// CHECK: %fneg.i = fneg reassoc nnan ninf nsz arcp afn <4 x float> %{{.*}}
+// CHECK: %hlsl.select.i = select reassoc nnan ninf nsz arcp afn i1 %cmp.i, <4 x float> %{{.*}}, <4 x float> %fneg.i
+// CHECK: ret <4 x float> %hlsl.select.i
+// SPVCHECK-LABEL: test_faceforward_float4
+// SPVCHECK: %spv.faceforward.i = call reassoc nnan ninf nsz arcp afn noundef <4 x float> @llvm.spv.smoothstep.v4f32(<4 x float> %{{.*}}, <4 x float> %{{.*}}, <4 x float> %{{.*}})
+// SPVCHECK: ret <4 x float> %spv.faceforward.i
+float4 test_faceforward_float4(float4 N, float4 I, float4 Ng) { return faceforward(N, I, Ng); }
diff --git a/clang/test/CodeGenSPIRV/Builtins/faceforward.c b/clang/test/CodeGenSPIRV/Builtins/faceforward.c
new file mode 100644
index 0000000000000..17e3268aab9ef
--- /dev/null
+++ b/clang/test/CodeGenSPIRV/Builtins/faceforward.c
@@ -0,0 +1,35 @@
+// 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 float @test_faceforward_float(
+// CHECK-SAME: float noundef [[N:%.*]], float noundef [[I:%.*]], float noundef [[NG:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[SPV_FACEFORWARD:%.*]] = tail call float @llvm.spv.smoothstep.f32(float [[N]], float [[I]], float [[NG]])
+// CHECK-NEXT: ret float [[SPV_FACEFORWARD]]
+float test_faceforward_float(float N, float I, float Ng) { return __builtin_spirv_faceforward(N, I, Ng); }
+
+// CHECK-LABEL: define spir_func <2 x float> @test_faceforward_float2(
+// CHECK-SAME: <2 x float> noundef [[N:%.*]], <2 x float> noundef [[I:%.*]], <2 x float> noundef [[NG:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[SPV_FACEFORWARD:%.*]] = tail call <2 x float> @llvm.spv.smoothstep.v2f32(<2 x float> [[N]], <2 x float> [[I]], <2 x float> [[NG]])
+// CHECK-NEXT: ret <2 x float> [[SPV_FACEFORWARD]]
+float2 test_faceforward_float2(float2 N, float2 I, float2 Ng) { return __builtin_spirv_faceforward(N, I, Ng); }
+
+// CHECK-LABEL: define spir_func <3 x float> @test_faceforward_float3(
+// CHECK-SAME: <3 x float> noundef [[N:%.*]], <3 x float> noundef [[I:%.*]], <3 x float> noundef [[NG:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[SPV_FACEFORWARD:%.*]] = tail call <3 x float> @llvm.spv.smoothstep.v3f32(<3 x float> [[N]], <3 x float> [[I]], <3 x float> [[NG]])
+// CHECK-NEXT: ret <3 x float> [[SPV_FACEFORWARD]]
+float3 test_faceforward_float3(float3 N, float3 I, float3 Ng) { return __builtin_spirv_faceforward(N, I, Ng); }
+
+// CHECK-LABEL: define spir_func <4 x float> @test_faceforward_float4(
+// CHECK-SAME: <4 x float> noundef [[N:%.*]], <4 x float> noundef [[I:%.*]], <4 x float> noundef [[NG:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[SPV_FACEFORWARD:%.*]] = tail call <4 x float> @llvm.spv.smoothstep.v4f32(<4 x float> [[N]], <4 x float> [[I]], <4 x float> [[NG]])
+// CHECK-NEXT: ret <4 x float> [[SPV_FACEFORWARD]]
+float4 test_faceforward_float4(float4 N, float4 I, float4 Ng) { return __builtin_spirv_faceforward(N, I, Ng); }
diff --git a/clang/test/SemaHLSL/BuiltIns/faceforward-errors.hlsl b/clang/test/SemaHLSL/BuiltIns/faceforward-errors.hlsl
new file mode 100644
index 0000000000000..469d55995f966
--- /dev/null
+++ b/clang/test/SemaHLSL/BuiltIns/faceforward-errors.hlsl
@@ -0,0 +1,39 @@
+// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -fnative-half-type -emit-llvm-only -disable-llvm-passes -verify
+
+float test_double_inputs(double p0, double p1, double p2) {
+ return faceforward(p0, p1, p2);
+ // expected-error@-1 {{no matching function for call to 'faceforward'}}
+ // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored}}
+ // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored}}
+ // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored}}
+ // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored}}
+}
+
+float test_int_inputs(int p0, int p1, int p2) {
+ return faceforward(p0, p1, p2);
+ // expected-error@-1 {{no matching function for call to 'faceforward'}}
+ // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored}}
+ // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored}}
+ // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored}}
+ // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored}}
+}
+
+float1 test_vec1_inputs(float1 p0, float1 p1, float1 p2) {
+ return faceforward(p0, p1, p2);
+ // expected-error@-1 {{no matching function for call to 'faceforward'}}
+ // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored: substitution failure [with T = float1]: no type named 'Type' in 'hlsl::__detail::enable_if<false, vector<float, 1>>'}}
+ // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored: substitution failure [with T = float1]: no type named 'Type' in 'hlsl::__detail::enable_if<false, vector<float, 1>>'}}
+ // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored: substitution failure [with L = 1]: no type named 'Type' in 'hlsl::__detail::enable_if<false, half>'}}
+ // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored: substitution failure [with L = 1]: no type named 'Type' in 'hlsl::__detail::enable_if<false, float>'}}
+}
+
+typedef float float5 __attribute__((ext_vector_type(5)));
+
+float5 test_vec5_inputs(float5 p0, float5 p1, float5 p2) {
+ return faceforward(p0, p1, p2);
+ // expected-error@-1 {{no matching function for call to 'faceforward'}}
+ // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored: substitution failure [with T = float5]: no type named 'Type' in 'hlsl::__detail::enable_if<false, vector<float, 5>>'}}
+ // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored: substitution failure [with T = float5]: no type named 'Type' in 'hlsl::__detail::enable_if<false, vector<float, 5>>'}}
+ // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored: substitution failure [with L = 5]: no type named 'Type' in 'hlsl::__detail::enable_if<false, half>'}}
+ // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored: substitution failure [with L = 5]: no type named 'Type' in 'hlsl::__detail::enable_if<false, float>'}}
+}
diff --git a/clang/test/SemaSPIRV/BuiltIns/faceforward-errors.c b/clang/test/SemaSPIRV/BuiltIns/faceforward-errors.c
new file mode 100644
index 0000000000000..28089709e6bd5
--- /dev/null
+++ b/clang/test/SemaSPIRV/BuiltIns/faceforward-errors.c
@@ -0,0...
[truncated]
|
@llvm/pr-subscribers-backend-spir-v Author: Kaitlin Peng (kmpeng) ChangesResolves #99114. There will be a follow-up PR on pattern matching later. Tasks completed:
Incomplete tasks:
Patch is 27.53 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/135878.diff 12 Files Affected:
diff --git a/clang/include/clang/Basic/BuiltinsSPIRV.td b/clang/include/clang/Basic/BuiltinsSPIRV.td
index 9f76d672cc7ce..cc0c2f960f8d2 100644
--- a/clang/include/clang/Basic/BuiltinsSPIRV.td
+++ b/clang/include/clang/Basic/BuiltinsSPIRV.td
@@ -31,3 +31,9 @@ def SPIRVSmoothStep : Builtin {
let Attributes = [NoThrow, Const, CustomTypeChecking];
let Prototype = "void(...)";
}
+
+def SPIRVFaceForward : Builtin {
+ let Spellings = ["__builtin_spirv_faceforward"];
+ let Attributes = [NoThrow, Const, CustomTypeChecking];
+ let Prototype = "void(...)";
+}
diff --git a/clang/lib/CodeGen/TargetBuiltins/SPIR.cpp b/clang/lib/CodeGen/TargetBuiltins/SPIR.cpp
index 92e2c1c6da68f..c1bcc9ae084d0 100644
--- a/clang/lib/CodeGen/TargetBuiltins/SPIR.cpp
+++ b/clang/lib/CodeGen/TargetBuiltins/SPIR.cpp
@@ -71,6 +71,18 @@ Value *CodeGenFunction::EmitSPIRVBuiltinExpr(unsigned BuiltinID,
ArrayRef<Value *>{Min, Max, X}, /*FMFSource=*/nullptr,
"spv.smoothstep");
}
+ case SPIRV::BI__builtin_spirv_faceforward: {
+ Value *N = EmitScalarExpr(E->getArg(0));
+ Value *I = EmitScalarExpr(E->getArg(1));
+ Value *Ng = EmitScalarExpr(E->getArg(2));
+ assert(E->getArg(0)->getType()->hasFloatingRepresentation() &&
+ E->getArg(1)->getType()->hasFloatingRepresentation() &&
+ E->getArg(2)->getType()->hasFloatingRepresentation() &&
+ "FaceForward operands must have a float representation");
+ return Builder.CreateIntrinsic(
+ /*ReturnType=*/N->getType(), Intrinsic::spv_smoothstep,
+ ArrayRef<Value *>{N, I, Ng}, /*FMFSource=*/nullptr, "spv.faceforward");
+ }
}
return nullptr;
}
diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h b/clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h
index 3a8a9b6fa2a45..b2332419dc034 100644
--- a/clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h
+++ b/clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h
@@ -126,6 +126,24 @@ template <typename T> constexpr vector<T, 4> lit_impl(T NDotL, T NDotH, T M) {
return Result;
}
+template <typename T> constexpr T faceforward_impl(T N, T I, T Ng) {
+#if (__has_builtin(__builtin_spirv_faceforward))
+ return __builtin_spirv_faceforward(N, I, Ng);
+#else
+ return select(I * Ng < 0, N, -N);
+#endif
+}
+
+template <typename T, int L>
+constexpr vector<T, L> faceforward_vec_impl(vector<T, L> N, vector<T, L> I,
+ vector<T, L> Ng) {
+#if (__has_builtin(__builtin_spirv_faceforward))
+ return __builtin_spirv_faceforward(N, I, Ng);
+#else
+ return select(dot(I, Ng) < 0, N, -N);
+#endif
+}
+
} // namespace __detail
} // namespace hlsl
diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h
index 35ff80052cf43..f4af34ea28b86 100644
--- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h
+++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h
@@ -214,6 +214,53 @@ const inline double4 dst(double4 Src0, double4 Src1) {
return __detail::dst_impl(Src0, Src1);
}
+//===----------------------------------------------------------------------===//
+// faceforward builtin
+//===----------------------------------------------------------------------===//
+
+/// \fn T faceforward(T N, T I, T Ng)
+/// \brief Flips the surface-normal (if needed) to face in a direction opposite
+/// to \a I. Returns the result in \a N.
+/// \param N The resulting floating-point surface-normal vector.
+/// \param I A floating-point, incident vector that points from the view
+/// position to the shading position.
+/// \param Ng A floating-point surface-normal vector.
+///
+/// Return a floating-point, surface normal vector that is facing the view
+/// direction.
+
+template <typename T>
+_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
+const inline __detail::enable_if_t<__detail::is_arithmetic<T>::Value &&
+ __detail::is_same<half, T>::value,
+ T> faceforward(T N, T I, T Ng) {
+ return __detail::faceforward_impl(N, I, Ng);
+}
+
+template <typename T>
+const inline __detail::enable_if_t<
+ __detail::is_arithmetic<T>::Value && __detail::is_same<float, T>::value, T>
+faceforward(T N, T I, T Ng) {
+ return __detail::faceforward_impl(N, I, Ng);
+}
+
+template <int L>
+_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
+const inline __detail::HLSL_FIXED_VECTOR<half, L> faceforward(
+ __detail::HLSL_FIXED_VECTOR<half, L> N,
+ __detail::HLSL_FIXED_VECTOR<half, L> I,
+ __detail::HLSL_FIXED_VECTOR<half, L> Ng) {
+ return __detail::faceforward_vec_impl(N, I, Ng);
+}
+
+template <int L>
+const inline __detail::HLSL_FIXED_VECTOR<float, L>
+faceforward(__detail::HLSL_FIXED_VECTOR<float, L> N,
+ __detail::HLSL_FIXED_VECTOR<float, L> I,
+ __detail::HLSL_FIXED_VECTOR<float, L> Ng) {
+ return __detail::faceforward_vec_impl(N, I, Ng);
+}
+
//===----------------------------------------------------------------------===//
// fmod builtins
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/Sema/SemaSPIRV.cpp b/clang/lib/Sema/SemaSPIRV.cpp
index 7131514d53421..ed40d005c8ce5 100644
--- a/clang/lib/Sema/SemaSPIRV.cpp
+++ b/clang/lib/Sema/SemaSPIRV.cpp
@@ -137,6 +137,42 @@ bool SemaSPIRV::CheckSPIRVBuiltinFunctionCall(unsigned BuiltinID,
TheCall->setType(RetTy);
break;
}
+ case SPIRV::BI__builtin_spirv_faceforward: {
+ if (SemaRef.checkArgCount(TheCall, 3))
+ return true;
+
+ // check if all arguments have floating representation
+ for (unsigned i = 0; i < TheCall->getNumArgs(); ++i) {
+ ExprResult Arg = TheCall->getArg(i);
+ QualType ArgTy = Arg.get()->getType();
+ if (!ArgTy->hasFloatingRepresentation()) {
+ SemaRef.Diag(Arg.get()->getBeginLoc(),
+ diag::err_builtin_invalid_arg_type)
+ << i + 1 << /* scalar or vector */ 5 << /* no int */ 0 << /* fp */ 1
+ << ArgTy;
+ return true;
+ }
+ }
+
+ // check if all arguments are of the same type
+ ExprResult A = TheCall->getArg(0);
+ ExprResult B = TheCall->getArg(1);
+ ExprResult C = TheCall->getArg(2);
+ if (!(SemaRef.getASTContext().hasSameUnqualifiedType(A.get()->getType(),
+ B.get()->getType()) &&
+ SemaRef.getASTContext().hasSameUnqualifiedType(A.get()->getType(),
+ C.get()->getType()))) {
+ SemaRef.Diag(TheCall->getBeginLoc(),
+ diag::err_vec_builtin_incompatible_vector)
+ << TheCall->getDirectCallee() << /*useAllTerminology*/ true
+ << SourceRange(A.get()->getBeginLoc(), C.get()->getEndLoc());
+ return true;
+ }
+
+ QualType RetTy = A.get()->getType();
+ TheCall->setType(RetTy);
+ break;
+ }
}
return false;
}
diff --git a/clang/test/CodeGenHLSL/builtins/faceforward.hlsl b/clang/test/CodeGenHLSL/builtins/faceforward.hlsl
new file mode 100644
index 0000000000000..d1942a4bc4b6c
--- /dev/null
+++ b/clang/test/CodeGenHLSL/builtins/faceforward.hlsl
@@ -0,0 +1,94 @@
+// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \
+// RUN: dxil-pc-shadermodel6.3-library %s -fnative-half-type \
+// RUN: -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -finclude-default-header -triple \
+// RUN: spirv-unknown-vulkan-compute %s -fnative-half-type \
+// RUN: -emit-llvm -o - | FileCheck %s --check-prefix=SPVCHECK
+
+// CHECK-LABEL: test_faceforward_half
+// CHECK: %mul.i = fmul reassoc nnan ninf nsz arcp afn half %{{.*}}, %{{.*}}
+// CHECK: %cmp.i = fcmp reassoc nnan ninf nsz arcp afn olt half %mul.i, 0xH0000
+// CHECK: %fneg.i = fneg reassoc nnan ninf nsz arcp afn half %{{.*}}
+// CHECK: %hlsl.select.i = select reassoc nnan ninf nsz arcp afn i1 %cmp.i, half %{{.*}}, half %fneg.i
+// CHECK: ret half %hlsl.select.i
+// SPVCHECK-LABEL: test_faceforward_half
+// SPVCHECK: %spv.faceforward.i = call reassoc nnan ninf nsz arcp afn noundef half @llvm.spv.smoothstep.f16(half %{{.*}}, half %{{.*}}, half %{{.*}})
+// SPVCHECK: ret half %spv.faceforward.i
+half test_faceforward_half(half N, half I, half Ng) { return faceforward(N, I, Ng); }
+
+// CHECK-LABEL: test_faceforward_half2
+// CHECK: %hlsl.dot.i = call reassoc nnan ninf nsz arcp afn half @llvm.dx.fdot.v2f16(<2 x half> %{{.*}}, <2 x half> %{{.*}})
+// CHECK: %cmp.i = fcmp reassoc nnan ninf nsz arcp afn olt half %hlsl.dot.i, 0xH0000
+// CHECK: %fneg.i = fneg reassoc nnan ninf nsz arcp afn <2 x half> %{{.*}}
+// CHECK: %hlsl.select.i = select reassoc nnan ninf nsz arcp afn i1 %cmp.i, <2 x half> %{{.*}}, <2 x half> %fneg.i
+// CHECK: ret <2 x half> %hlsl.select.i
+// SPVCHECK-LABEL: test_faceforward_half2
+// SPVCHECK: %spv.faceforward.i = call reassoc nnan ninf nsz arcp afn noundef <2 x half> @llvm.spv.smoothstep.v2f16(<2 x half> %{{.*}}, <2 x half> %{{.*}}, <2 x half> %{{.*}})
+// SPVCHECK: ret <2 x half> %spv.faceforward.i
+half2 test_faceforward_half2(half2 N, half2 I, half2 Ng) { return faceforward(N, I, Ng); }
+
+// CHECK-LABEL: test_faceforward_half3
+// CHECK: %hlsl.dot.i = call reassoc nnan ninf nsz arcp afn half @llvm.dx.fdot.v3f16(<3 x half> %{{.*}}, <3 x half> %{{.*}})
+// CHECK: %cmp.i = fcmp reassoc nnan ninf nsz arcp afn olt half %hlsl.dot.i, 0xH0000
+// CHECK: %fneg.i = fneg reassoc nnan ninf nsz arcp afn <3 x half> %{{.*}}
+// CHECK: %hlsl.select.i = select reassoc nnan ninf nsz arcp afn i1 %cmp.i, <3 x half> %{{.*}}, <3 x half> %fneg.i
+// CHECK: ret <3 x half> %hlsl.select.i
+// SPVCHECK-LABEL: test_faceforward_half3
+// SPVCHECK: %spv.faceforward.i = call reassoc nnan ninf nsz arcp afn noundef <3 x half> @llvm.spv.smoothstep.v3f16(<3 x half> %{{.*}}, <3 x half> %{{.*}}, <3 x half> %{{.*}})
+// SPVCHECK: ret <3 x half> %spv.faceforward.i
+half3 test_faceforward_half3(half3 N, half3 I, half3 Ng) { return faceforward(N, I, Ng); }
+
+// CHECK-LABEL: test_faceforward_half4
+// CHECK: %hlsl.dot.i = call reassoc nnan ninf nsz arcp afn half @llvm.dx.fdot.v4f16(<4 x half> %{{.*}}, <4 x half> %{{.*}})
+// CHECK: %cmp.i = fcmp reassoc nnan ninf nsz arcp afn olt half %hlsl.dot.i, 0xH0000
+// CHECK: %fneg.i = fneg reassoc nnan ninf nsz arcp afn <4 x half> %{{.*}}
+// CHECK: %hlsl.select.i = select reassoc nnan ninf nsz arcp afn i1 %cmp.i, <4 x half> %{{.*}}, <4 x half> %fneg.i
+// CHECK: ret <4 x half> %hlsl.select.i
+// SPVCHECK-LABEL: test_faceforward_half4
+// SPVCHECK: %spv.faceforward.i = call reassoc nnan ninf nsz arcp afn noundef <4 x half> @llvm.spv.smoothstep.v4f16(<4 x half> %{{.*}}, <4 x half> %{{.*}}, <4 x half> %{{.*}})
+// SPVCHECK: ret <4 x half> %spv.faceforward.i
+half4 test_faceforward_half4(half4 N, half4 I, half4 Ng) { return faceforward(N, I, Ng); }
+
+// CHECK-LABEL: test_faceforward_float
+// CHECK: %mul.i = fmul reassoc nnan ninf nsz arcp afn float %{{.*}}, %{{.*}}
+// CHECK: %cmp.i = fcmp reassoc nnan ninf nsz arcp afn olt float %mul.i, 0.000000e+00
+// CHECK: %fneg.i = fneg reassoc nnan ninf nsz arcp afn float %{{.*}}
+// CHECK: %hlsl.select.i = select reassoc nnan ninf nsz arcp afn i1 %cmp.i, float %{{.*}}, float %fneg.i
+// CHECK: ret float %hlsl.select.i
+// SPVCHECK-LABEL: test_faceforward_float
+// SPVCHECK: %spv.faceforward.i = call reassoc nnan ninf nsz arcp afn noundef float @llvm.spv.smoothstep.f32(float %{{.*}}, float %{{.*}}, float %{{.*}})
+// SPVCHECK: ret float %spv.faceforward.i
+float test_faceforward_float(float N, float I, float Ng) { return faceforward(N, I, Ng); }
+
+// CHECK-LABEL: test_faceforward_float2
+// CHECK: %hlsl.dot.i = call reassoc nnan ninf nsz arcp afn float @llvm.dx.fdot.v2f32(<2 x float> %{{.*}}, <2 x float> %{{.*}})
+// CHECK: %cmp.i = fcmp reassoc nnan ninf nsz arcp afn olt float %hlsl.dot.i, 0.000000e+00
+// CHECK: %fneg.i = fneg reassoc nnan ninf nsz arcp afn <2 x float> %{{.*}}
+// CHECK: %hlsl.select.i = select reassoc nnan ninf nsz arcp afn i1 %cmp.i, <2 x float> %{{.*}}, <2 x float> %fneg.i
+// CHECK: ret <2 x float> %hlsl.select.i
+// SPVCHECK-LABEL: test_faceforward_float2
+// SPVCHECK: %spv.faceforward.i = call reassoc nnan ninf nsz arcp afn noundef <2 x float> @llvm.spv.smoothstep.v2f32(<2 x float> %{{.*}}, <2 x float> %{{.*}}, <2 x float> %{{.*}})
+// SPVCHECK: ret <2 x float> %spv.faceforward.i
+float2 test_faceforward_float2(float2 N, float2 I, float2 Ng) { return faceforward(N, I, Ng); }
+
+// CHECK-LABEL: test_faceforward_float3
+// CHECK: %hlsl.dot.i = call reassoc nnan ninf nsz arcp afn float @llvm.dx.fdot.v3f32(<3 x float> %{{.*}}, <3 x float> %{{.*}})
+// CHECK: %cmp.i = fcmp reassoc nnan ninf nsz arcp afn olt float %hlsl.dot.i, 0.000000e+00
+// CHECK: %fneg.i = fneg reassoc nnan ninf nsz arcp afn <3 x float> %{{.*}}
+// CHECK: %hlsl.select.i = select reassoc nnan ninf nsz arcp afn i1 %cmp.i, <3 x float> %{{.*}}, <3 x float> %fneg.i
+// CHECK: ret <3 x float> %hlsl.select.i
+// SPVCHECK-LABEL: test_faceforward_float3
+// SPVCHECK: %spv.faceforward.i = call reassoc nnan ninf nsz arcp afn noundef <3 x float> @llvm.spv.smoothstep.v3f32(<3 x float> %{{.*}}, <3 x float> %{{.*}}, <3 x float> %{{.*}})
+// SPVCHECK: ret <3 x float> %spv.faceforward.i
+float3 test_faceforward_float3(float3 N, float3 I, float3 Ng) { return faceforward(N, I, Ng); }
+
+// CHECK-LABEL: test_faceforward_float4
+// CHECK: %hlsl.dot.i = call reassoc nnan ninf nsz arcp afn float @llvm.dx.fdot.v4f32(<4 x float> %{{.*}}, <4 x float> %{{.*}})
+// CHECK: %cmp.i = fcmp reassoc nnan ninf nsz arcp afn olt float %hlsl.dot.i, 0.000000e+00
+// CHECK: %fneg.i = fneg reassoc nnan ninf nsz arcp afn <4 x float> %{{.*}}
+// CHECK: %hlsl.select.i = select reassoc nnan ninf nsz arcp afn i1 %cmp.i, <4 x float> %{{.*}}, <4 x float> %fneg.i
+// CHECK: ret <4 x float> %hlsl.select.i
+// SPVCHECK-LABEL: test_faceforward_float4
+// SPVCHECK: %spv.faceforward.i = call reassoc nnan ninf nsz arcp afn noundef <4 x float> @llvm.spv.smoothstep.v4f32(<4 x float> %{{.*}}, <4 x float> %{{.*}}, <4 x float> %{{.*}})
+// SPVCHECK: ret <4 x float> %spv.faceforward.i
+float4 test_faceforward_float4(float4 N, float4 I, float4 Ng) { return faceforward(N, I, Ng); }
diff --git a/clang/test/CodeGenSPIRV/Builtins/faceforward.c b/clang/test/CodeGenSPIRV/Builtins/faceforward.c
new file mode 100644
index 0000000000000..17e3268aab9ef
--- /dev/null
+++ b/clang/test/CodeGenSPIRV/Builtins/faceforward.c
@@ -0,0 +1,35 @@
+// 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 float @test_faceforward_float(
+// CHECK-SAME: float noundef [[N:%.*]], float noundef [[I:%.*]], float noundef [[NG:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[SPV_FACEFORWARD:%.*]] = tail call float @llvm.spv.smoothstep.f32(float [[N]], float [[I]], float [[NG]])
+// CHECK-NEXT: ret float [[SPV_FACEFORWARD]]
+float test_faceforward_float(float N, float I, float Ng) { return __builtin_spirv_faceforward(N, I, Ng); }
+
+// CHECK-LABEL: define spir_func <2 x float> @test_faceforward_float2(
+// CHECK-SAME: <2 x float> noundef [[N:%.*]], <2 x float> noundef [[I:%.*]], <2 x float> noundef [[NG:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[SPV_FACEFORWARD:%.*]] = tail call <2 x float> @llvm.spv.smoothstep.v2f32(<2 x float> [[N]], <2 x float> [[I]], <2 x float> [[NG]])
+// CHECK-NEXT: ret <2 x float> [[SPV_FACEFORWARD]]
+float2 test_faceforward_float2(float2 N, float2 I, float2 Ng) { return __builtin_spirv_faceforward(N, I, Ng); }
+
+// CHECK-LABEL: define spir_func <3 x float> @test_faceforward_float3(
+// CHECK-SAME: <3 x float> noundef [[N:%.*]], <3 x float> noundef [[I:%.*]], <3 x float> noundef [[NG:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[SPV_FACEFORWARD:%.*]] = tail call <3 x float> @llvm.spv.smoothstep.v3f32(<3 x float> [[N]], <3 x float> [[I]], <3 x float> [[NG]])
+// CHECK-NEXT: ret <3 x float> [[SPV_FACEFORWARD]]
+float3 test_faceforward_float3(float3 N, float3 I, float3 Ng) { return __builtin_spirv_faceforward(N, I, Ng); }
+
+// CHECK-LABEL: define spir_func <4 x float> @test_faceforward_float4(
+// CHECK-SAME: <4 x float> noundef [[N:%.*]], <4 x float> noundef [[I:%.*]], <4 x float> noundef [[NG:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[SPV_FACEFORWARD:%.*]] = tail call <4 x float> @llvm.spv.smoothstep.v4f32(<4 x float> [[N]], <4 x float> [[I]], <4 x float> [[NG]])
+// CHECK-NEXT: ret <4 x float> [[SPV_FACEFORWARD]]
+float4 test_faceforward_float4(float4 N, float4 I, float4 Ng) { return __builtin_spirv_faceforward(N, I, Ng); }
diff --git a/clang/test/SemaHLSL/BuiltIns/faceforward-errors.hlsl b/clang/test/SemaHLSL/BuiltIns/faceforward-errors.hlsl
new file mode 100644
index 0000000000000..469d55995f966
--- /dev/null
+++ b/clang/test/SemaHLSL/BuiltIns/faceforward-errors.hlsl
@@ -0,0 +1,39 @@
+// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -fnative-half-type -emit-llvm-only -disable-llvm-passes -verify
+
+float test_double_inputs(double p0, double p1, double p2) {
+ return faceforward(p0, p1, p2);
+ // expected-error@-1 {{no matching function for call to 'faceforward'}}
+ // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored}}
+ // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored}}
+ // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored}}
+ // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored}}
+}
+
+float test_int_inputs(int p0, int p1, int p2) {
+ return faceforward(p0, p1, p2);
+ // expected-error@-1 {{no matching function for call to 'faceforward'}}
+ // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored}}
+ // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored}}
+ // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored}}
+ // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored}}
+}
+
+float1 test_vec1_inputs(float1 p0, float1 p1, float1 p2) {
+ return faceforward(p0, p1, p2);
+ // expected-error@-1 {{no matching function for call to 'faceforward'}}
+ // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored: substitution failure [with T = float1]: no type named 'Type' in 'hlsl::__detail::enable_if<false, vector<float, 1>>'}}
+ // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored: substitution failure [with T = float1]: no type named 'Type' in 'hlsl::__detail::enable_if<false, vector<float, 1>>'}}
+ // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored: substitution failure [with L = 1]: no type named 'Type' in 'hlsl::__detail::enable_if<false, half>'}}
+ // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored: substitution failure [with L = 1]: no type named 'Type' in 'hlsl::__detail::enable_if<false, float>'}}
+}
+
+typedef float float5 __attribute__((ext_vector_type(5)));
+
+float5 test_vec5_inputs(float5 p0, float5 p1, float5 p2) {
+ return faceforward(p0, p1, p2);
+ // expected-error@-1 {{no matching function for call to 'faceforward'}}
+ // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored: substitution failure [with T = float5]: no type named 'Type' in 'hlsl::__detail::enable_if<false, vector<float, 5>>'}}
+ // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored: substitution failure [with T = float5]: no type named 'Type' in 'hlsl::__detail::enable_if<false, vector<float, 5>>'}}
+ // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored: substitution failure [with L = 5]: no type named 'Type' in 'hlsl::__detail::enable_if<false, half>'}}
+ // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored: substitution failure [with L = 5]: no type named 'Type' in 'hlsl::__detail::enable_if<false, float>'}}
+}
diff --git a/clang/test/SemaSPIRV/BuiltIns/faceforward-errors.c b/clang/test/SemaSPIRV/BuiltIns/faceforward-errors.c
new file mode 100644
index 0000000000000..28089709e6bd5
--- /dev/null
+++ b/clang/test/SemaSPIRV/BuiltIns/faceforward-errors.c
@@ -0,0...
[truncated]
|
@llvm/pr-subscribers-clang-codegen Author: Kaitlin Peng (kmpeng) ChangesResolves #99114. There will be a follow-up PR on pattern matching later. Tasks completed:
Incomplete tasks:
Patch is 27.53 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/135878.diff 12 Files Affected:
diff --git a/clang/include/clang/Basic/BuiltinsSPIRV.td b/clang/include/clang/Basic/BuiltinsSPIRV.td
index 9f76d672cc7ce..cc0c2f960f8d2 100644
--- a/clang/include/clang/Basic/BuiltinsSPIRV.td
+++ b/clang/include/clang/Basic/BuiltinsSPIRV.td
@@ -31,3 +31,9 @@ def SPIRVSmoothStep : Builtin {
let Attributes = [NoThrow, Const, CustomTypeChecking];
let Prototype = "void(...)";
}
+
+def SPIRVFaceForward : Builtin {
+ let Spellings = ["__builtin_spirv_faceforward"];
+ let Attributes = [NoThrow, Const, CustomTypeChecking];
+ let Prototype = "void(...)";
+}
diff --git a/clang/lib/CodeGen/TargetBuiltins/SPIR.cpp b/clang/lib/CodeGen/TargetBuiltins/SPIR.cpp
index 92e2c1c6da68f..c1bcc9ae084d0 100644
--- a/clang/lib/CodeGen/TargetBuiltins/SPIR.cpp
+++ b/clang/lib/CodeGen/TargetBuiltins/SPIR.cpp
@@ -71,6 +71,18 @@ Value *CodeGenFunction::EmitSPIRVBuiltinExpr(unsigned BuiltinID,
ArrayRef<Value *>{Min, Max, X}, /*FMFSource=*/nullptr,
"spv.smoothstep");
}
+ case SPIRV::BI__builtin_spirv_faceforward: {
+ Value *N = EmitScalarExpr(E->getArg(0));
+ Value *I = EmitScalarExpr(E->getArg(1));
+ Value *Ng = EmitScalarExpr(E->getArg(2));
+ assert(E->getArg(0)->getType()->hasFloatingRepresentation() &&
+ E->getArg(1)->getType()->hasFloatingRepresentation() &&
+ E->getArg(2)->getType()->hasFloatingRepresentation() &&
+ "FaceForward operands must have a float representation");
+ return Builder.CreateIntrinsic(
+ /*ReturnType=*/N->getType(), Intrinsic::spv_smoothstep,
+ ArrayRef<Value *>{N, I, Ng}, /*FMFSource=*/nullptr, "spv.faceforward");
+ }
}
return nullptr;
}
diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h b/clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h
index 3a8a9b6fa2a45..b2332419dc034 100644
--- a/clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h
+++ b/clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h
@@ -126,6 +126,24 @@ template <typename T> constexpr vector<T, 4> lit_impl(T NDotL, T NDotH, T M) {
return Result;
}
+template <typename T> constexpr T faceforward_impl(T N, T I, T Ng) {
+#if (__has_builtin(__builtin_spirv_faceforward))
+ return __builtin_spirv_faceforward(N, I, Ng);
+#else
+ return select(I * Ng < 0, N, -N);
+#endif
+}
+
+template <typename T, int L>
+constexpr vector<T, L> faceforward_vec_impl(vector<T, L> N, vector<T, L> I,
+ vector<T, L> Ng) {
+#if (__has_builtin(__builtin_spirv_faceforward))
+ return __builtin_spirv_faceforward(N, I, Ng);
+#else
+ return select(dot(I, Ng) < 0, N, -N);
+#endif
+}
+
} // namespace __detail
} // namespace hlsl
diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h
index 35ff80052cf43..f4af34ea28b86 100644
--- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h
+++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h
@@ -214,6 +214,53 @@ const inline double4 dst(double4 Src0, double4 Src1) {
return __detail::dst_impl(Src0, Src1);
}
+//===----------------------------------------------------------------------===//
+// faceforward builtin
+//===----------------------------------------------------------------------===//
+
+/// \fn T faceforward(T N, T I, T Ng)
+/// \brief Flips the surface-normal (if needed) to face in a direction opposite
+/// to \a I. Returns the result in \a N.
+/// \param N The resulting floating-point surface-normal vector.
+/// \param I A floating-point, incident vector that points from the view
+/// position to the shading position.
+/// \param Ng A floating-point surface-normal vector.
+///
+/// Return a floating-point, surface normal vector that is facing the view
+/// direction.
+
+template <typename T>
+_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
+const inline __detail::enable_if_t<__detail::is_arithmetic<T>::Value &&
+ __detail::is_same<half, T>::value,
+ T> faceforward(T N, T I, T Ng) {
+ return __detail::faceforward_impl(N, I, Ng);
+}
+
+template <typename T>
+const inline __detail::enable_if_t<
+ __detail::is_arithmetic<T>::Value && __detail::is_same<float, T>::value, T>
+faceforward(T N, T I, T Ng) {
+ return __detail::faceforward_impl(N, I, Ng);
+}
+
+template <int L>
+_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
+const inline __detail::HLSL_FIXED_VECTOR<half, L> faceforward(
+ __detail::HLSL_FIXED_VECTOR<half, L> N,
+ __detail::HLSL_FIXED_VECTOR<half, L> I,
+ __detail::HLSL_FIXED_VECTOR<half, L> Ng) {
+ return __detail::faceforward_vec_impl(N, I, Ng);
+}
+
+template <int L>
+const inline __detail::HLSL_FIXED_VECTOR<float, L>
+faceforward(__detail::HLSL_FIXED_VECTOR<float, L> N,
+ __detail::HLSL_FIXED_VECTOR<float, L> I,
+ __detail::HLSL_FIXED_VECTOR<float, L> Ng) {
+ return __detail::faceforward_vec_impl(N, I, Ng);
+}
+
//===----------------------------------------------------------------------===//
// fmod builtins
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/Sema/SemaSPIRV.cpp b/clang/lib/Sema/SemaSPIRV.cpp
index 7131514d53421..ed40d005c8ce5 100644
--- a/clang/lib/Sema/SemaSPIRV.cpp
+++ b/clang/lib/Sema/SemaSPIRV.cpp
@@ -137,6 +137,42 @@ bool SemaSPIRV::CheckSPIRVBuiltinFunctionCall(unsigned BuiltinID,
TheCall->setType(RetTy);
break;
}
+ case SPIRV::BI__builtin_spirv_faceforward: {
+ if (SemaRef.checkArgCount(TheCall, 3))
+ return true;
+
+ // check if all arguments have floating representation
+ for (unsigned i = 0; i < TheCall->getNumArgs(); ++i) {
+ ExprResult Arg = TheCall->getArg(i);
+ QualType ArgTy = Arg.get()->getType();
+ if (!ArgTy->hasFloatingRepresentation()) {
+ SemaRef.Diag(Arg.get()->getBeginLoc(),
+ diag::err_builtin_invalid_arg_type)
+ << i + 1 << /* scalar or vector */ 5 << /* no int */ 0 << /* fp */ 1
+ << ArgTy;
+ return true;
+ }
+ }
+
+ // check if all arguments are of the same type
+ ExprResult A = TheCall->getArg(0);
+ ExprResult B = TheCall->getArg(1);
+ ExprResult C = TheCall->getArg(2);
+ if (!(SemaRef.getASTContext().hasSameUnqualifiedType(A.get()->getType(),
+ B.get()->getType()) &&
+ SemaRef.getASTContext().hasSameUnqualifiedType(A.get()->getType(),
+ C.get()->getType()))) {
+ SemaRef.Diag(TheCall->getBeginLoc(),
+ diag::err_vec_builtin_incompatible_vector)
+ << TheCall->getDirectCallee() << /*useAllTerminology*/ true
+ << SourceRange(A.get()->getBeginLoc(), C.get()->getEndLoc());
+ return true;
+ }
+
+ QualType RetTy = A.get()->getType();
+ TheCall->setType(RetTy);
+ break;
+ }
}
return false;
}
diff --git a/clang/test/CodeGenHLSL/builtins/faceforward.hlsl b/clang/test/CodeGenHLSL/builtins/faceforward.hlsl
new file mode 100644
index 0000000000000..d1942a4bc4b6c
--- /dev/null
+++ b/clang/test/CodeGenHLSL/builtins/faceforward.hlsl
@@ -0,0 +1,94 @@
+// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \
+// RUN: dxil-pc-shadermodel6.3-library %s -fnative-half-type \
+// RUN: -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -finclude-default-header -triple \
+// RUN: spirv-unknown-vulkan-compute %s -fnative-half-type \
+// RUN: -emit-llvm -o - | FileCheck %s --check-prefix=SPVCHECK
+
+// CHECK-LABEL: test_faceforward_half
+// CHECK: %mul.i = fmul reassoc nnan ninf nsz arcp afn half %{{.*}}, %{{.*}}
+// CHECK: %cmp.i = fcmp reassoc nnan ninf nsz arcp afn olt half %mul.i, 0xH0000
+// CHECK: %fneg.i = fneg reassoc nnan ninf nsz arcp afn half %{{.*}}
+// CHECK: %hlsl.select.i = select reassoc nnan ninf nsz arcp afn i1 %cmp.i, half %{{.*}}, half %fneg.i
+// CHECK: ret half %hlsl.select.i
+// SPVCHECK-LABEL: test_faceforward_half
+// SPVCHECK: %spv.faceforward.i = call reassoc nnan ninf nsz arcp afn noundef half @llvm.spv.smoothstep.f16(half %{{.*}}, half %{{.*}}, half %{{.*}})
+// SPVCHECK: ret half %spv.faceforward.i
+half test_faceforward_half(half N, half I, half Ng) { return faceforward(N, I, Ng); }
+
+// CHECK-LABEL: test_faceforward_half2
+// CHECK: %hlsl.dot.i = call reassoc nnan ninf nsz arcp afn half @llvm.dx.fdot.v2f16(<2 x half> %{{.*}}, <2 x half> %{{.*}})
+// CHECK: %cmp.i = fcmp reassoc nnan ninf nsz arcp afn olt half %hlsl.dot.i, 0xH0000
+// CHECK: %fneg.i = fneg reassoc nnan ninf nsz arcp afn <2 x half> %{{.*}}
+// CHECK: %hlsl.select.i = select reassoc nnan ninf nsz arcp afn i1 %cmp.i, <2 x half> %{{.*}}, <2 x half> %fneg.i
+// CHECK: ret <2 x half> %hlsl.select.i
+// SPVCHECK-LABEL: test_faceforward_half2
+// SPVCHECK: %spv.faceforward.i = call reassoc nnan ninf nsz arcp afn noundef <2 x half> @llvm.spv.smoothstep.v2f16(<2 x half> %{{.*}}, <2 x half> %{{.*}}, <2 x half> %{{.*}})
+// SPVCHECK: ret <2 x half> %spv.faceforward.i
+half2 test_faceforward_half2(half2 N, half2 I, half2 Ng) { return faceforward(N, I, Ng); }
+
+// CHECK-LABEL: test_faceforward_half3
+// CHECK: %hlsl.dot.i = call reassoc nnan ninf nsz arcp afn half @llvm.dx.fdot.v3f16(<3 x half> %{{.*}}, <3 x half> %{{.*}})
+// CHECK: %cmp.i = fcmp reassoc nnan ninf nsz arcp afn olt half %hlsl.dot.i, 0xH0000
+// CHECK: %fneg.i = fneg reassoc nnan ninf nsz arcp afn <3 x half> %{{.*}}
+// CHECK: %hlsl.select.i = select reassoc nnan ninf nsz arcp afn i1 %cmp.i, <3 x half> %{{.*}}, <3 x half> %fneg.i
+// CHECK: ret <3 x half> %hlsl.select.i
+// SPVCHECK-LABEL: test_faceforward_half3
+// SPVCHECK: %spv.faceforward.i = call reassoc nnan ninf nsz arcp afn noundef <3 x half> @llvm.spv.smoothstep.v3f16(<3 x half> %{{.*}}, <3 x half> %{{.*}}, <3 x half> %{{.*}})
+// SPVCHECK: ret <3 x half> %spv.faceforward.i
+half3 test_faceforward_half3(half3 N, half3 I, half3 Ng) { return faceforward(N, I, Ng); }
+
+// CHECK-LABEL: test_faceforward_half4
+// CHECK: %hlsl.dot.i = call reassoc nnan ninf nsz arcp afn half @llvm.dx.fdot.v4f16(<4 x half> %{{.*}}, <4 x half> %{{.*}})
+// CHECK: %cmp.i = fcmp reassoc nnan ninf nsz arcp afn olt half %hlsl.dot.i, 0xH0000
+// CHECK: %fneg.i = fneg reassoc nnan ninf nsz arcp afn <4 x half> %{{.*}}
+// CHECK: %hlsl.select.i = select reassoc nnan ninf nsz arcp afn i1 %cmp.i, <4 x half> %{{.*}}, <4 x half> %fneg.i
+// CHECK: ret <4 x half> %hlsl.select.i
+// SPVCHECK-LABEL: test_faceforward_half4
+// SPVCHECK: %spv.faceforward.i = call reassoc nnan ninf nsz arcp afn noundef <4 x half> @llvm.spv.smoothstep.v4f16(<4 x half> %{{.*}}, <4 x half> %{{.*}}, <4 x half> %{{.*}})
+// SPVCHECK: ret <4 x half> %spv.faceforward.i
+half4 test_faceforward_half4(half4 N, half4 I, half4 Ng) { return faceforward(N, I, Ng); }
+
+// CHECK-LABEL: test_faceforward_float
+// CHECK: %mul.i = fmul reassoc nnan ninf nsz arcp afn float %{{.*}}, %{{.*}}
+// CHECK: %cmp.i = fcmp reassoc nnan ninf nsz arcp afn olt float %mul.i, 0.000000e+00
+// CHECK: %fneg.i = fneg reassoc nnan ninf nsz arcp afn float %{{.*}}
+// CHECK: %hlsl.select.i = select reassoc nnan ninf nsz arcp afn i1 %cmp.i, float %{{.*}}, float %fneg.i
+// CHECK: ret float %hlsl.select.i
+// SPVCHECK-LABEL: test_faceforward_float
+// SPVCHECK: %spv.faceforward.i = call reassoc nnan ninf nsz arcp afn noundef float @llvm.spv.smoothstep.f32(float %{{.*}}, float %{{.*}}, float %{{.*}})
+// SPVCHECK: ret float %spv.faceforward.i
+float test_faceforward_float(float N, float I, float Ng) { return faceforward(N, I, Ng); }
+
+// CHECK-LABEL: test_faceforward_float2
+// CHECK: %hlsl.dot.i = call reassoc nnan ninf nsz arcp afn float @llvm.dx.fdot.v2f32(<2 x float> %{{.*}}, <2 x float> %{{.*}})
+// CHECK: %cmp.i = fcmp reassoc nnan ninf nsz arcp afn olt float %hlsl.dot.i, 0.000000e+00
+// CHECK: %fneg.i = fneg reassoc nnan ninf nsz arcp afn <2 x float> %{{.*}}
+// CHECK: %hlsl.select.i = select reassoc nnan ninf nsz arcp afn i1 %cmp.i, <2 x float> %{{.*}}, <2 x float> %fneg.i
+// CHECK: ret <2 x float> %hlsl.select.i
+// SPVCHECK-LABEL: test_faceforward_float2
+// SPVCHECK: %spv.faceforward.i = call reassoc nnan ninf nsz arcp afn noundef <2 x float> @llvm.spv.smoothstep.v2f32(<2 x float> %{{.*}}, <2 x float> %{{.*}}, <2 x float> %{{.*}})
+// SPVCHECK: ret <2 x float> %spv.faceforward.i
+float2 test_faceforward_float2(float2 N, float2 I, float2 Ng) { return faceforward(N, I, Ng); }
+
+// CHECK-LABEL: test_faceforward_float3
+// CHECK: %hlsl.dot.i = call reassoc nnan ninf nsz arcp afn float @llvm.dx.fdot.v3f32(<3 x float> %{{.*}}, <3 x float> %{{.*}})
+// CHECK: %cmp.i = fcmp reassoc nnan ninf nsz arcp afn olt float %hlsl.dot.i, 0.000000e+00
+// CHECK: %fneg.i = fneg reassoc nnan ninf nsz arcp afn <3 x float> %{{.*}}
+// CHECK: %hlsl.select.i = select reassoc nnan ninf nsz arcp afn i1 %cmp.i, <3 x float> %{{.*}}, <3 x float> %fneg.i
+// CHECK: ret <3 x float> %hlsl.select.i
+// SPVCHECK-LABEL: test_faceforward_float3
+// SPVCHECK: %spv.faceforward.i = call reassoc nnan ninf nsz arcp afn noundef <3 x float> @llvm.spv.smoothstep.v3f32(<3 x float> %{{.*}}, <3 x float> %{{.*}}, <3 x float> %{{.*}})
+// SPVCHECK: ret <3 x float> %spv.faceforward.i
+float3 test_faceforward_float3(float3 N, float3 I, float3 Ng) { return faceforward(N, I, Ng); }
+
+// CHECK-LABEL: test_faceforward_float4
+// CHECK: %hlsl.dot.i = call reassoc nnan ninf nsz arcp afn float @llvm.dx.fdot.v4f32(<4 x float> %{{.*}}, <4 x float> %{{.*}})
+// CHECK: %cmp.i = fcmp reassoc nnan ninf nsz arcp afn olt float %hlsl.dot.i, 0.000000e+00
+// CHECK: %fneg.i = fneg reassoc nnan ninf nsz arcp afn <4 x float> %{{.*}}
+// CHECK: %hlsl.select.i = select reassoc nnan ninf nsz arcp afn i1 %cmp.i, <4 x float> %{{.*}}, <4 x float> %fneg.i
+// CHECK: ret <4 x float> %hlsl.select.i
+// SPVCHECK-LABEL: test_faceforward_float4
+// SPVCHECK: %spv.faceforward.i = call reassoc nnan ninf nsz arcp afn noundef <4 x float> @llvm.spv.smoothstep.v4f32(<4 x float> %{{.*}}, <4 x float> %{{.*}}, <4 x float> %{{.*}})
+// SPVCHECK: ret <4 x float> %spv.faceforward.i
+float4 test_faceforward_float4(float4 N, float4 I, float4 Ng) { return faceforward(N, I, Ng); }
diff --git a/clang/test/CodeGenSPIRV/Builtins/faceforward.c b/clang/test/CodeGenSPIRV/Builtins/faceforward.c
new file mode 100644
index 0000000000000..17e3268aab9ef
--- /dev/null
+++ b/clang/test/CodeGenSPIRV/Builtins/faceforward.c
@@ -0,0 +1,35 @@
+// 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 float @test_faceforward_float(
+// CHECK-SAME: float noundef [[N:%.*]], float noundef [[I:%.*]], float noundef [[NG:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[SPV_FACEFORWARD:%.*]] = tail call float @llvm.spv.smoothstep.f32(float [[N]], float [[I]], float [[NG]])
+// CHECK-NEXT: ret float [[SPV_FACEFORWARD]]
+float test_faceforward_float(float N, float I, float Ng) { return __builtin_spirv_faceforward(N, I, Ng); }
+
+// CHECK-LABEL: define spir_func <2 x float> @test_faceforward_float2(
+// CHECK-SAME: <2 x float> noundef [[N:%.*]], <2 x float> noundef [[I:%.*]], <2 x float> noundef [[NG:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[SPV_FACEFORWARD:%.*]] = tail call <2 x float> @llvm.spv.smoothstep.v2f32(<2 x float> [[N]], <2 x float> [[I]], <2 x float> [[NG]])
+// CHECK-NEXT: ret <2 x float> [[SPV_FACEFORWARD]]
+float2 test_faceforward_float2(float2 N, float2 I, float2 Ng) { return __builtin_spirv_faceforward(N, I, Ng); }
+
+// CHECK-LABEL: define spir_func <3 x float> @test_faceforward_float3(
+// CHECK-SAME: <3 x float> noundef [[N:%.*]], <3 x float> noundef [[I:%.*]], <3 x float> noundef [[NG:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[SPV_FACEFORWARD:%.*]] = tail call <3 x float> @llvm.spv.smoothstep.v3f32(<3 x float> [[N]], <3 x float> [[I]], <3 x float> [[NG]])
+// CHECK-NEXT: ret <3 x float> [[SPV_FACEFORWARD]]
+float3 test_faceforward_float3(float3 N, float3 I, float3 Ng) { return __builtin_spirv_faceforward(N, I, Ng); }
+
+// CHECK-LABEL: define spir_func <4 x float> @test_faceforward_float4(
+// CHECK-SAME: <4 x float> noundef [[N:%.*]], <4 x float> noundef [[I:%.*]], <4 x float> noundef [[NG:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[SPV_FACEFORWARD:%.*]] = tail call <4 x float> @llvm.spv.smoothstep.v4f32(<4 x float> [[N]], <4 x float> [[I]], <4 x float> [[NG]])
+// CHECK-NEXT: ret <4 x float> [[SPV_FACEFORWARD]]
+float4 test_faceforward_float4(float4 N, float4 I, float4 Ng) { return __builtin_spirv_faceforward(N, I, Ng); }
diff --git a/clang/test/SemaHLSL/BuiltIns/faceforward-errors.hlsl b/clang/test/SemaHLSL/BuiltIns/faceforward-errors.hlsl
new file mode 100644
index 0000000000000..469d55995f966
--- /dev/null
+++ b/clang/test/SemaHLSL/BuiltIns/faceforward-errors.hlsl
@@ -0,0 +1,39 @@
+// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -fnative-half-type -emit-llvm-only -disable-llvm-passes -verify
+
+float test_double_inputs(double p0, double p1, double p2) {
+ return faceforward(p0, p1, p2);
+ // expected-error@-1 {{no matching function for call to 'faceforward'}}
+ // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored}}
+ // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored}}
+ // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored}}
+ // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored}}
+}
+
+float test_int_inputs(int p0, int p1, int p2) {
+ return faceforward(p0, p1, p2);
+ // expected-error@-1 {{no matching function for call to 'faceforward'}}
+ // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored}}
+ // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored}}
+ // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored}}
+ // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored}}
+}
+
+float1 test_vec1_inputs(float1 p0, float1 p1, float1 p2) {
+ return faceforward(p0, p1, p2);
+ // expected-error@-1 {{no matching function for call to 'faceforward'}}
+ // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored: substitution failure [with T = float1]: no type named 'Type' in 'hlsl::__detail::enable_if<false, vector<float, 1>>'}}
+ // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored: substitution failure [with T = float1]: no type named 'Type' in 'hlsl::__detail::enable_if<false, vector<float, 1>>'}}
+ // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored: substitution failure [with L = 1]: no type named 'Type' in 'hlsl::__detail::enable_if<false, half>'}}
+ // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored: substitution failure [with L = 1]: no type named 'Type' in 'hlsl::__detail::enable_if<false, float>'}}
+}
+
+typedef float float5 __attribute__((ext_vector_type(5)));
+
+float5 test_vec5_inputs(float5 p0, float5 p1, float5 p2) {
+ return faceforward(p0, p1, p2);
+ // expected-error@-1 {{no matching function for call to 'faceforward'}}
+ // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored: substitution failure [with T = float5]: no type named 'Type' in 'hlsl::__detail::enable_if<false, vector<float, 5>>'}}
+ // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored: substitution failure [with T = float5]: no type named 'Type' in 'hlsl::__detail::enable_if<false, vector<float, 5>>'}}
+ // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored: substitution failure [with L = 5]: no type named 'Type' in 'hlsl::__detail::enable_if<false, half>'}}
+ // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored: substitution failure [with L = 5]: no type named 'Type' in 'hlsl::__detail::enable_if<false, float>'}}
+}
diff --git a/clang/test/SemaSPIRV/BuiltIns/faceforward-errors.c b/clang/test/SemaSPIRV/BuiltIns/faceforward-errors.c
new file mode 100644
index 0000000000000..28089709e6bd5
--- /dev/null
+++ b/clang/test/SemaSPIRV/BuiltIns/faceforward-errors.c
@@ -0,0...
[truncated]
|
88acb07
to
06324ca
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a collection of nits. LGTM
…ap to int_spv_faceforward, create SPIR-V backend test case
…t built-in, added codegen and sema tests
…x specification in tests, clarify faceforward desc
…arg is float in sema spirv checks, add half tests to codegen spirv test
a67d579
to
ec4575c
Compare
Resolves #99114. There will be a follow-up PR on pattern matching later.
Tasks completed:
faceforward
inhlsl_intrinsics.h
/hlsl_intrinsic_helpers.h
faceforward
SPIR-V target builtin inclang/include/clang/Basic/BuiltinsSPIRV.td
hlsl_intrinsic_helpers.h
faceforward
toCheckSPIRVBuiltinFunctionCall
inclang/lib/Sema/SemaSPIRV.cpp
faceforward
builtin toEmitSPIRVBuiltinExpr
inSPIR.cpp
clang/test/CodeGenHLSL/builtins/faceforward.hlsl
clang/test/CodeGenSPIRV/Builtins/faceforward.c
clang/test/SemaHLSL/BuiltIns/faceforward-errors.hlsl
clang/test/SemaSPIRV/BuiltIns/faceforward-errors.c
int_spv_faceforward
intrinsic inIntrinsicsSPIRV.td
SPIRVInstructionSelector.cpp
create thefaceforward
lowering and map it toint_spv_faceforward
inSPIRVInstructionSelector::selectIntrinsic
llvm/test/CodeGen/SPIRV/hlsl-intrinsics/faceforward.ll
XFAIL
s when spirv-tools are enabled. The issue is being tracked in #136344Incomplete tasks:
llvm/test/CodeGen/SPIRV/opencl/faceforward.ll
faceforward
function