-
Notifications
You must be signed in to change notification settings - Fork 13k
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
[HLSL] Implement the smoothstep
intrinsic
#132288
base: main
Are you sure you want to change the base?
Conversation
@llvm/pr-subscribers-backend-x86 @llvm/pr-subscribers-clang Author: Kaitlin Peng (kmpeng) ChangesCloses #99156. Tasks completed:
Patch is 41.67 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/132288.diff 13 Files Affected:
diff --git a/clang/include/clang/Basic/BuiltinsSPIRV.td b/clang/include/clang/Basic/BuiltinsSPIRV.td
index 34933e889ba31..2eb4c733b0a42 100644
--- a/clang/include/clang/Basic/BuiltinsSPIRV.td
+++ b/clang/include/clang/Basic/BuiltinsSPIRV.td
@@ -25,3 +25,9 @@ def SPIRVReflect : Builtin {
let Attributes = [NoThrow, Const];
let Prototype = "void(...)";
}
+
+def SPIRVSmoothStep : Builtin {
+ let Spellings = ["__builtin_spirv_smoothstep"];
+ let Attributes = [NoThrow, Const];
+ let Prototype = "void(...)";
+}
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index c126f88b9e3a5..ac92f89415724 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -20955,6 +20955,25 @@ Value *CodeGenFunction::EmitSPIRVBuiltinExpr(unsigned BuiltinID,
/*ReturnType=*/I->getType(), Intrinsic::spv_reflect,
ArrayRef<Value *>{I, N}, nullptr, "spv.reflect");
}
+ case SPIRV::BI__builtin_spirv_smoothstep: {
+ Value *Min = EmitScalarExpr(E->getArg(0));
+ Value *Max = EmitScalarExpr(E->getArg(1));
+ Value *X = EmitScalarExpr(E->getArg(2));
+ assert(E->getArg(0)->getType()->hasFloatingRepresentation() &&
+ E->getArg(1)->getType()->hasFloatingRepresentation() &&
+ E->getArg(2)->getType()->hasFloatingRepresentation() &&
+ "SmoothStep operands must have a float representation");
+ assert((E->getArg(0)->getType()->isScalarType() ||
+ E->getArg(0)->getType()->isVectorType()) &&
+ (E->getArg(1)->getType()->isScalarType() ||
+ E->getArg(1)->getType()->isVectorType()) &&
+ (E->getArg(2)->getType()->isScalarType() ||
+ E->getArg(2)->getType()->isVectorType()) &&
+ "SmoothStep operands must be a scalar or vector");
+ return Builder.CreateIntrinsic(
+ /*ReturnType=*/Min->getType(), Intrinsic::spv_smoothstep,
+ ArrayRef<Value *>{Min, Max, X}, nullptr, "spv.smoothstep");
+ }
}
return nullptr;
}
diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h b/clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h
index 89ab664e90ba9..8cdd63d7e07bb 100644
--- a/clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h
+++ b/clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h
@@ -81,6 +81,26 @@ constexpr vector<T, N> fmod_vec_impl(vector<T, N> X, vector<T, N> Y) {
#endif
}
+template <typename T> constexpr T smoothstep_impl(T Min, T Max, T X) {
+#if (__has_builtin(__builtin_spirv_smoothstep))
+ return __builtin_spirv_smoothstep(Min, Max, X);
+#else
+ T S = saturate((X - Min) / (Max - Min));
+ return (3 - 2 * S) * S * S;
+#endif
+}
+
+template <typename T, int N>
+constexpr vector<T, N> smoothstep_vec_impl(vector<T, N> Min, vector<T, N> Max,
+ vector<T, N> X) {
+#if (__has_builtin(__builtin_spirv_smoothstep))
+ return __builtin_spirv_smoothstep(Min, Max, X);
+#else
+ vector<T, N> S = saturate((X - Min) / (Max - Min));
+ return (3 - 2 * S) * S * S;
+#endif
+}
+
} // namespace __detail
} // namespace hlsl
diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h
index a48a8e998a015..3803a87d32afc 100644
--- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h
+++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h
@@ -264,5 +264,53 @@ reflect(__detail::HLSL_FIXED_VECTOR<float, L> I,
__detail::HLSL_FIXED_VECTOR<float, L> N) {
return __detail::reflect_vec_impl(I, N);
}
+
+//===----------------------------------------------------------------------===//
+// smoothstep builtin
+//===----------------------------------------------------------------------===//
+
+/// \fn T smoothstep(T Min, T Max, T X)
+/// \brief Returns a smooth Hermite interpolation between 0 and 1, if \a X is in
+/// the range [\a Min, \a Max].
+/// \param Min The minimum range of the x parameter.
+/// \param Max The maximum range of the x parameter.
+/// \param X The specified value to be interpolated.
+///
+/// The return value is 0.0 if \a X ≤ \a Min and 1.0 if \a X ≥ \a Max. When \a
+/// Min < \a X < \a Max, the function performs smooth Hermite interpolation
+/// between 0 and 1.
+
+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> smoothstep(T Min, T Max, T X) {
+ return __detail::smoothstep_impl(Min, Max, X);
+}
+
+template <typename T>
+const inline __detail::enable_if_t<
+ __detail::is_arithmetic<T>::Value && __detail::is_same<float, T>::value, T>
+smoothstep(T Min, T Max, T X) {
+ return __detail::smoothstep_impl(Min, Max, X);
+}
+
+template <int N>
+_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
+const inline __detail::HLSL_FIXED_VECTOR<half, N> smoothstep(
+ __detail::HLSL_FIXED_VECTOR<half, N> Min,
+ __detail::HLSL_FIXED_VECTOR<half, N> Max,
+ __detail::HLSL_FIXED_VECTOR<half, N> X) {
+ return __detail::smoothstep_vec_impl(Min, Max, X);
+}
+
+template <int N>
+const inline __detail::HLSL_FIXED_VECTOR<float, N>
+smoothstep(__detail::HLSL_FIXED_VECTOR<float, N> Min,
+ __detail::HLSL_FIXED_VECTOR<float, N> Max,
+ __detail::HLSL_FIXED_VECTOR<float, N> X) {
+ return __detail::smoothstep_vec_impl(Min, Max, X);
+}
+
} // namespace hlsl
#endif //_HLSL_HLSL_INTRINSICS_H_
diff --git a/clang/lib/Sema/SemaSPIRV.cpp b/clang/lib/Sema/SemaSPIRV.cpp
index 94534485e07c3..2cbb57a739a1a 100644
--- a/clang/lib/Sema/SemaSPIRV.cpp
+++ b/clang/lib/Sema/SemaSPIRV.cpp
@@ -101,6 +101,44 @@ bool SemaSPIRV::CheckSPIRVBuiltinFunctionCall(unsigned BuiltinID,
TheCall->setType(RetTy);
break;
}
+ case SPIRV::BI__builtin_spirv_smoothstep: {
+ if (SemaRef.checkArgCount(TheCall, 3))
+ return true;
+
+ ExprResult A = TheCall->getArg(0);
+ QualType ArgTyA = A.get()->getType();
+ auto *VTyA = ArgTyA->getAs<VectorType>();
+ if (!(ArgTyA->isScalarType() || VTyA)) {
+ SemaRef.Diag(A.get()->getBeginLoc(),
+ diag::err_typecheck_expect_any_scalar_or_vector)
+ << ArgTyA << 1;
+ return true;
+ }
+
+ ExprResult B = TheCall->getArg(1);
+ QualType ArgTyB = B.get()->getType();
+ auto *VTyB = ArgTyB->getAs<VectorType>();
+ if (!(ArgTyB->isScalarType() || VTyB)) {
+ SemaRef.Diag(A.get()->getBeginLoc(),
+ diag::err_typecheck_expect_any_scalar_or_vector)
+ << ArgTyB << 1;
+ return true;
+ }
+
+ ExprResult C = TheCall->getArg(2);
+ QualType ArgTyC = C.get()->getType();
+ auto *VTyC = ArgTyC->getAs<VectorType>();
+ if (!(ArgTyC->isScalarType() || VTyC)) {
+ SemaRef.Diag(A.get()->getBeginLoc(),
+ diag::err_typecheck_expect_any_scalar_or_vector)
+ << ArgTyC << 1;
+ return true;
+ }
+
+ QualType RetTy = ArgTyA;
+ TheCall->setType(RetTy);
+ break;
+ }
}
return false;
}
diff --git a/clang/test/CodeGenHLSL/builtins/smoothstep.hlsl b/clang/test/CodeGenHLSL/builtins/smoothstep.hlsl
new file mode 100644
index 0000000000000..bbb19692f1225
--- /dev/null
+++ b/clang/test/CodeGenHLSL/builtins/smoothstep.hlsl
@@ -0,0 +1,183 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5
+// RUN: %clang_cc1 -finclude-default-header -x hlsl -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 @_Z20test_smoothstep_halfDhDhDh(
+// CHECK-SAME: half noundef nofpclass(nan inf) [[MIN:%.*]], half noundef nofpclass(nan inf) [[MAX:%.*]], half noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn half [[X]], [[MIN]]
+// CHECK-NEXT: [[SUB1_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn half [[MAX]], [[MIN]]
+// CHECK-NEXT: [[DIV_I:%.*]] = fdiv reassoc nnan ninf nsz arcp afn half [[SUB_I]], [[SUB1_I]]
+// CHECK-NEXT: [[HLSL_SATURATE_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn half @llvm.dx.saturate.f16(half [[DIV_I]])
+// CHECK-NEXT: [[MUL_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn half [[HLSL_SATURATE_I]], 0xH4000
+// CHECK-NEXT: [[SUB2_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn half 0xH4200, [[MUL_I]]
+// CHECK-NEXT: [[TMP0:%.*]] = fmul reassoc nnan ninf nsz arcp afn half [[HLSL_SATURATE_I]], [[HLSL_SATURATE_I]]
+// CHECK-NEXT: [[MUL4_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn half [[TMP0]], [[SUB2_I]]
+// CHECK-NEXT: ret half [[MUL4_I]]
+//
+// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) half @_Z20test_smoothstep_halfDhDhDh(
+// SPVCHECK-SAME: half noundef nofpclass(nan inf) [[MIN:%.*]], half noundef nofpclass(nan inf) [[MAX:%.*]], half noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
+// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: [[CONV_I:%.*]] = fpext reassoc nnan ninf nsz arcp afn half [[MIN]] to double
+// SPVCHECK-NEXT: [[CONV1_I:%.*]] = fpext reassoc nnan ninf nsz arcp afn half [[MAX]] to double
+// SPVCHECK-NEXT: [[CONV2_I:%.*]] = fpext reassoc nnan ninf nsz arcp afn half [[X]] to double
+// SPVCHECK-NEXT: [[SPV_SMOOTHSTEP_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn double @llvm.spv.smoothstep.f64(double [[CONV_I]], double [[CONV1_I]], double [[CONV2_I]])
+// SPVCHECK-NEXT: [[CONV3_I:%.*]] = fptrunc reassoc nnan ninf nsz arcp afn double [[SPV_SMOOTHSTEP_I]] to half
+// SPVCHECK-NEXT: ret half [[CONV3_I]]
+//
+half test_smoothstep_half(half Min, half Max, half X) { return smoothstep(Min, Max, X); }
+
+// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x half> @_Z21test_smoothstep_half2Dv2_DhS_S_(
+// CHECK-SAME: <2 x half> noundef nofpclass(nan inf) [[MIN:%.*]], <2 x half> noundef nofpclass(nan inf) [[MAX:%.*]], <2 x half> noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <2 x half> [[X]], [[MIN]]
+// CHECK-NEXT: [[SUB1_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <2 x half> [[MAX]], [[MIN]]
+// CHECK-NEXT: [[DIV_I:%.*]] = fdiv reassoc nnan ninf nsz arcp afn <2 x half> [[SUB_I]], [[SUB1_I]]
+// CHECK-NEXT: [[HLSL_SATURATE_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn <2 x half> @llvm.dx.saturate.v2f16(<2 x half> [[DIV_I]])
+// CHECK-NEXT: [[MUL_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn <2 x half> [[HLSL_SATURATE_I]], splat (half 0xH4000)
+// CHECK-NEXT: [[SUB2_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <2 x half> splat (half 0xH4200), [[MUL_I]]
+// CHECK-NEXT: [[TMP0:%.*]] = fmul reassoc nnan ninf nsz arcp afn <2 x half> [[HLSL_SATURATE_I]], [[HLSL_SATURATE_I]]
+// CHECK-NEXT: [[MUL4_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn <2 x half> [[TMP0]], [[SUB2_I]]
+// CHECK-NEXT: ret <2 x half> [[MUL4_I]]
+//
+// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) <2 x half> @_Z21test_smoothstep_half2Dv2_DhS_S_(
+// SPVCHECK-SAME: <2 x half> noundef nofpclass(nan inf) [[MIN:%.*]], <2 x half> noundef nofpclass(nan inf) [[MAX:%.*]], <2 x half> noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: [[SPV_SMOOTHSTEP_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef <2 x half> @llvm.spv.smoothstep.v2f16(<2 x half> [[MIN]], <2 x half> [[MAX]], <2 x half> [[X]])
+// SPVCHECK-NEXT: ret <2 x half> [[SPV_SMOOTHSTEP_I]]
+//
+half2 test_smoothstep_half2(half2 Min, half2 Max, half2 X) { return smoothstep(Min, Max, X); }
+
+// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x half> @_Z21test_smoothstep_half3Dv3_DhS_S_(
+// CHECK-SAME: <3 x half> noundef nofpclass(nan inf) [[MIN:%.*]], <3 x half> noundef nofpclass(nan inf) [[MAX:%.*]], <3 x half> noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <3 x half> [[X]], [[MIN]]
+// CHECK-NEXT: [[SUB1_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <3 x half> [[MAX]], [[MIN]]
+// CHECK-NEXT: [[DIV_I:%.*]] = fdiv reassoc nnan ninf nsz arcp afn <3 x half> [[SUB_I]], [[SUB1_I]]
+// CHECK-NEXT: [[HLSL_SATURATE_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn <3 x half> @llvm.dx.saturate.v3f16(<3 x half> [[DIV_I]])
+// CHECK-NEXT: [[MUL_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn <3 x half> [[HLSL_SATURATE_I]], splat (half 0xH4000)
+// CHECK-NEXT: [[SUB2_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <3 x half> splat (half 0xH4200), [[MUL_I]]
+// CHECK-NEXT: [[TMP0:%.*]] = fmul reassoc nnan ninf nsz arcp afn <3 x half> [[HLSL_SATURATE_I]], [[HLSL_SATURATE_I]]
+// CHECK-NEXT: [[MUL4_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn <3 x half> [[TMP0]], [[SUB2_I]]
+// CHECK-NEXT: ret <3 x half> [[MUL4_I]]
+//
+// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) <3 x half> @_Z21test_smoothstep_half3Dv3_DhS_S_(
+// SPVCHECK-SAME: <3 x half> noundef nofpclass(nan inf) [[MIN:%.*]], <3 x half> noundef nofpclass(nan inf) [[MAX:%.*]], <3 x half> noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: [[SPV_SMOOTHSTEP_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef <3 x half> @llvm.spv.smoothstep.v3f16(<3 x half> [[MIN]], <3 x half> [[MAX]], <3 x half> [[X]])
+// SPVCHECK-NEXT: ret <3 x half> [[SPV_SMOOTHSTEP_I]]
+//
+half3 test_smoothstep_half3(half3 Min, half3 Max, half3 X) { return smoothstep(Min, Max, X); }
+
+// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x half> @_Z21test_smoothstep_half4Dv4_DhS_S_(
+// CHECK-SAME: <4 x half> noundef nofpclass(nan inf) [[MIN:%.*]], <4 x half> noundef nofpclass(nan inf) [[MAX:%.*]], <4 x half> noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <4 x half> [[X]], [[MIN]]
+// CHECK-NEXT: [[SUB1_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <4 x half> [[MAX]], [[MIN]]
+// CHECK-NEXT: [[DIV_I:%.*]] = fdiv reassoc nnan ninf nsz arcp afn <4 x half> [[SUB_I]], [[SUB1_I]]
+// CHECK-NEXT: [[HLSL_SATURATE_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn <4 x half> @llvm.dx.saturate.v4f16(<4 x half> [[DIV_I]])
+// CHECK-NEXT: [[MUL_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn <4 x half> [[HLSL_SATURATE_I]], splat (half 0xH4000)
+// CHECK-NEXT: [[SUB2_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <4 x half> splat (half 0xH4200), [[MUL_I]]
+// CHECK-NEXT: [[TMP0:%.*]] = fmul reassoc nnan ninf nsz arcp afn <4 x half> [[HLSL_SATURATE_I]], [[HLSL_SATURATE_I]]
+// CHECK-NEXT: [[MUL4_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn <4 x half> [[TMP0]], [[SUB2_I]]
+// CHECK-NEXT: ret <4 x half> [[MUL4_I]]
+//
+// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) <4 x half> @_Z21test_smoothstep_half4Dv4_DhS_S_(
+// SPVCHECK-SAME: <4 x half> noundef nofpclass(nan inf) [[MIN:%.*]], <4 x half> noundef nofpclass(nan inf) [[MAX:%.*]], <4 x half> noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: [[SPV_SMOOTHSTEP_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef <4 x half> @llvm.spv.smoothstep.v4f16(<4 x half> [[MIN]], <4 x half> [[MAX]], <4 x half> [[X]])
+// SPVCHECK-NEXT: ret <4 x half> [[SPV_SMOOTHSTEP_I]]
+//
+half4 test_smoothstep_half4(half4 Min, half4 Max, half4 X) { return smoothstep(Min, Max, X); }
+
+// CHECK-LABEL: define noundef nofpclass(nan inf) float @_Z21test_smoothstep_floatfff(
+// CHECK-SAME: float noundef nofpclass(nan inf) [[MIN:%.*]], float noundef nofpclass(nan inf) [[MAX:%.*]], float noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn float [[X]], [[MIN]]
+// CHECK-NEXT: [[SUB1_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn float [[MAX]], [[MIN]]
+// CHECK-NEXT: [[DIV_I:%.*]] = fdiv reassoc nnan ninf nsz arcp afn float [[SUB_I]], [[SUB1_I]]
+// CHECK-NEXT: [[HLSL_SATURATE_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn float @llvm.dx.saturate.f32(float [[DIV_I]])
+// CHECK-NEXT: [[MUL_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn float [[HLSL_SATURATE_I]], 2.000000e+00
+// CHECK-NEXT: [[SUB2_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn float 3.000000e+00, [[MUL_I]]
+// CHECK-NEXT: [[TMP0:%.*]] = fmul reassoc nnan ninf nsz arcp afn float [[HLSL_SATURATE_I]], [[HLSL_SATURATE_I]]
+// CHECK-NEXT: [[MUL4_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn float [[TMP0]], [[SUB2_I]]
+// CHECK-NEXT: ret float [[MUL4_I]]
+//
+// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) float @_Z21test_smoothstep_floatfff(
+// SPVCHECK-SAME: float noundef nofpclass(nan inf) [[MIN:%.*]], float noundef nofpclass(nan inf) [[MAX:%.*]], float noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: [[CONV_I:%.*]] = fpext reassoc nnan ninf nsz arcp afn float [[MIN]] to double
+// SPVCHECK-NEXT: [[CONV1_I:%.*]] = fpext reassoc nnan ninf nsz arcp afn float [[MAX]] to double
+// SPVCHECK-NEXT: [[CONV2_I:%.*]] = fpext reassoc nnan ninf nsz arcp afn float [[X]] to double
+// SPVCHECK-NEXT: [[SPV_SMOOTHSTEP_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn double @llvm.spv.smoothstep.f64(double [[CONV_I]], double [[CONV1_I]], double [[CONV2_I]])
+// SPVCHECK-NEXT: [[CONV3_I:%.*]] = fptrunc reassoc nnan ninf nsz arcp afn double [[SPV_SMOOTHSTEP_I]] to float
+// SPVCHECK-NEXT: ret float [[CONV3_I]]
+//
+float test_smoothstep_float(float Min, float Max, float X) { return smoothstep(Min, Max, X); }
+
+// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> @_Z22test_smoothstep_float2Dv2_fS_S_(
+// CHECK-SAME: <2 x float> noundef nofpclass(nan inf) [[MIN:%.*]], <2 x float> noundef nofpclass(nan inf) [[MAX:%.*]], <2 x float> noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <2 x float> [[X]], [[MIN]]
+// CHECK-NEXT: [[SUB1_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <2 x float> [[MAX]], [[MIN]]
+// CHECK-NEXT: [[DIV_I:%.*]] = fdiv reassoc nnan ninf nsz arcp afn <2 x float> [[SUB_I]], [[SUB1_I]]
+// CHECK-NEXT: [[HLSL_SATURATE_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.dx.saturate.v2f32(<2 x float> [[DIV_I]])
+// CHECK-NEXT: [[MUL_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn <2 x float> [[HLSL_SATURATE_I]], splat (float 2.000000e+00)
+// CHECK-NEXT: [[SUB2_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <2 x float> splat (float 3.000000e+00), [[MUL_I]]
+// CHECK-NEXT: [[TMP0:%.*]] = fmul reassoc nnan ninf nsz arcp afn <2 x float> [[HLSL_SATURATE_I]], [[HLSL_SATURATE_I]]
+// CHECK-NEXT: [[MUL4_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn <2 x float> [[TMP0]], [[SUB2_I]]
+// CHECK-NEXT: ret <2 x float> [[MUL4_I]]
+//
+// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) <2 x float> @_Z22test_smoothstep_float2Dv2_fS_S_(
+// SPVCHECK-SAME: <2 x float> noundef nofpclass(nan inf) [[MIN:%.*]], <2 x float> noundef nofpclass(nan inf) [[MAX:%.*]], <2 x float> noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: [[SPV_SMOOTHSTEP_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef <2 x float> @llvm.spv.smoothstep.v2f32(<2 x float> [[MIN]], <2 x float> [[MAX]], <2 x float> [[X]])
+// SPVCHECK-NEXT: ret <2 x float> [[SPV_SMOOTHSTEP_I]]
+//
+float2 test_smoothstep_float2(float2 Min, float2 Max, float2 X) { return smoothstep(Min, Max, X); }
+
+// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> @_Z22test_smoothstep_float3Dv3_fS_S_(
+// CHECK-SAME: <3 x float> noundef nofpclass(nan inf) [[MIN:%.*]], <3 x float> noundef nofpclass(nan inf) [[MAX:%.*]], <3 x float> noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr ...
[truncated]
|
@llvm/pr-subscribers-clang-codegen Author: Kaitlin Peng (kmpeng) ChangesCloses #99156. Tasks completed:
Patch is 41.67 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/132288.diff 13 Files Affected:
diff --git a/clang/include/clang/Basic/BuiltinsSPIRV.td b/clang/include/clang/Basic/BuiltinsSPIRV.td
index 34933e889ba31..2eb4c733b0a42 100644
--- a/clang/include/clang/Basic/BuiltinsSPIRV.td
+++ b/clang/include/clang/Basic/BuiltinsSPIRV.td
@@ -25,3 +25,9 @@ def SPIRVReflect : Builtin {
let Attributes = [NoThrow, Const];
let Prototype = "void(...)";
}
+
+def SPIRVSmoothStep : Builtin {
+ let Spellings = ["__builtin_spirv_smoothstep"];
+ let Attributes = [NoThrow, Const];
+ let Prototype = "void(...)";
+}
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index c126f88b9e3a5..ac92f89415724 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -20955,6 +20955,25 @@ Value *CodeGenFunction::EmitSPIRVBuiltinExpr(unsigned BuiltinID,
/*ReturnType=*/I->getType(), Intrinsic::spv_reflect,
ArrayRef<Value *>{I, N}, nullptr, "spv.reflect");
}
+ case SPIRV::BI__builtin_spirv_smoothstep: {
+ Value *Min = EmitScalarExpr(E->getArg(0));
+ Value *Max = EmitScalarExpr(E->getArg(1));
+ Value *X = EmitScalarExpr(E->getArg(2));
+ assert(E->getArg(0)->getType()->hasFloatingRepresentation() &&
+ E->getArg(1)->getType()->hasFloatingRepresentation() &&
+ E->getArg(2)->getType()->hasFloatingRepresentation() &&
+ "SmoothStep operands must have a float representation");
+ assert((E->getArg(0)->getType()->isScalarType() ||
+ E->getArg(0)->getType()->isVectorType()) &&
+ (E->getArg(1)->getType()->isScalarType() ||
+ E->getArg(1)->getType()->isVectorType()) &&
+ (E->getArg(2)->getType()->isScalarType() ||
+ E->getArg(2)->getType()->isVectorType()) &&
+ "SmoothStep operands must be a scalar or vector");
+ return Builder.CreateIntrinsic(
+ /*ReturnType=*/Min->getType(), Intrinsic::spv_smoothstep,
+ ArrayRef<Value *>{Min, Max, X}, nullptr, "spv.smoothstep");
+ }
}
return nullptr;
}
diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h b/clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h
index 89ab664e90ba9..8cdd63d7e07bb 100644
--- a/clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h
+++ b/clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h
@@ -81,6 +81,26 @@ constexpr vector<T, N> fmod_vec_impl(vector<T, N> X, vector<T, N> Y) {
#endif
}
+template <typename T> constexpr T smoothstep_impl(T Min, T Max, T X) {
+#if (__has_builtin(__builtin_spirv_smoothstep))
+ return __builtin_spirv_smoothstep(Min, Max, X);
+#else
+ T S = saturate((X - Min) / (Max - Min));
+ return (3 - 2 * S) * S * S;
+#endif
+}
+
+template <typename T, int N>
+constexpr vector<T, N> smoothstep_vec_impl(vector<T, N> Min, vector<T, N> Max,
+ vector<T, N> X) {
+#if (__has_builtin(__builtin_spirv_smoothstep))
+ return __builtin_spirv_smoothstep(Min, Max, X);
+#else
+ vector<T, N> S = saturate((X - Min) / (Max - Min));
+ return (3 - 2 * S) * S * S;
+#endif
+}
+
} // namespace __detail
} // namespace hlsl
diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h
index a48a8e998a015..3803a87d32afc 100644
--- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h
+++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h
@@ -264,5 +264,53 @@ reflect(__detail::HLSL_FIXED_VECTOR<float, L> I,
__detail::HLSL_FIXED_VECTOR<float, L> N) {
return __detail::reflect_vec_impl(I, N);
}
+
+//===----------------------------------------------------------------------===//
+// smoothstep builtin
+//===----------------------------------------------------------------------===//
+
+/// \fn T smoothstep(T Min, T Max, T X)
+/// \brief Returns a smooth Hermite interpolation between 0 and 1, if \a X is in
+/// the range [\a Min, \a Max].
+/// \param Min The minimum range of the x parameter.
+/// \param Max The maximum range of the x parameter.
+/// \param X The specified value to be interpolated.
+///
+/// The return value is 0.0 if \a X ≤ \a Min and 1.0 if \a X ≥ \a Max. When \a
+/// Min < \a X < \a Max, the function performs smooth Hermite interpolation
+/// between 0 and 1.
+
+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> smoothstep(T Min, T Max, T X) {
+ return __detail::smoothstep_impl(Min, Max, X);
+}
+
+template <typename T>
+const inline __detail::enable_if_t<
+ __detail::is_arithmetic<T>::Value && __detail::is_same<float, T>::value, T>
+smoothstep(T Min, T Max, T X) {
+ return __detail::smoothstep_impl(Min, Max, X);
+}
+
+template <int N>
+_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
+const inline __detail::HLSL_FIXED_VECTOR<half, N> smoothstep(
+ __detail::HLSL_FIXED_VECTOR<half, N> Min,
+ __detail::HLSL_FIXED_VECTOR<half, N> Max,
+ __detail::HLSL_FIXED_VECTOR<half, N> X) {
+ return __detail::smoothstep_vec_impl(Min, Max, X);
+}
+
+template <int N>
+const inline __detail::HLSL_FIXED_VECTOR<float, N>
+smoothstep(__detail::HLSL_FIXED_VECTOR<float, N> Min,
+ __detail::HLSL_FIXED_VECTOR<float, N> Max,
+ __detail::HLSL_FIXED_VECTOR<float, N> X) {
+ return __detail::smoothstep_vec_impl(Min, Max, X);
+}
+
} // namespace hlsl
#endif //_HLSL_HLSL_INTRINSICS_H_
diff --git a/clang/lib/Sema/SemaSPIRV.cpp b/clang/lib/Sema/SemaSPIRV.cpp
index 94534485e07c3..2cbb57a739a1a 100644
--- a/clang/lib/Sema/SemaSPIRV.cpp
+++ b/clang/lib/Sema/SemaSPIRV.cpp
@@ -101,6 +101,44 @@ bool SemaSPIRV::CheckSPIRVBuiltinFunctionCall(unsigned BuiltinID,
TheCall->setType(RetTy);
break;
}
+ case SPIRV::BI__builtin_spirv_smoothstep: {
+ if (SemaRef.checkArgCount(TheCall, 3))
+ return true;
+
+ ExprResult A = TheCall->getArg(0);
+ QualType ArgTyA = A.get()->getType();
+ auto *VTyA = ArgTyA->getAs<VectorType>();
+ if (!(ArgTyA->isScalarType() || VTyA)) {
+ SemaRef.Diag(A.get()->getBeginLoc(),
+ diag::err_typecheck_expect_any_scalar_or_vector)
+ << ArgTyA << 1;
+ return true;
+ }
+
+ ExprResult B = TheCall->getArg(1);
+ QualType ArgTyB = B.get()->getType();
+ auto *VTyB = ArgTyB->getAs<VectorType>();
+ if (!(ArgTyB->isScalarType() || VTyB)) {
+ SemaRef.Diag(A.get()->getBeginLoc(),
+ diag::err_typecheck_expect_any_scalar_or_vector)
+ << ArgTyB << 1;
+ return true;
+ }
+
+ ExprResult C = TheCall->getArg(2);
+ QualType ArgTyC = C.get()->getType();
+ auto *VTyC = ArgTyC->getAs<VectorType>();
+ if (!(ArgTyC->isScalarType() || VTyC)) {
+ SemaRef.Diag(A.get()->getBeginLoc(),
+ diag::err_typecheck_expect_any_scalar_or_vector)
+ << ArgTyC << 1;
+ return true;
+ }
+
+ QualType RetTy = ArgTyA;
+ TheCall->setType(RetTy);
+ break;
+ }
}
return false;
}
diff --git a/clang/test/CodeGenHLSL/builtins/smoothstep.hlsl b/clang/test/CodeGenHLSL/builtins/smoothstep.hlsl
new file mode 100644
index 0000000000000..bbb19692f1225
--- /dev/null
+++ b/clang/test/CodeGenHLSL/builtins/smoothstep.hlsl
@@ -0,0 +1,183 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5
+// RUN: %clang_cc1 -finclude-default-header -x hlsl -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 @_Z20test_smoothstep_halfDhDhDh(
+// CHECK-SAME: half noundef nofpclass(nan inf) [[MIN:%.*]], half noundef nofpclass(nan inf) [[MAX:%.*]], half noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn half [[X]], [[MIN]]
+// CHECK-NEXT: [[SUB1_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn half [[MAX]], [[MIN]]
+// CHECK-NEXT: [[DIV_I:%.*]] = fdiv reassoc nnan ninf nsz arcp afn half [[SUB_I]], [[SUB1_I]]
+// CHECK-NEXT: [[HLSL_SATURATE_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn half @llvm.dx.saturate.f16(half [[DIV_I]])
+// CHECK-NEXT: [[MUL_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn half [[HLSL_SATURATE_I]], 0xH4000
+// CHECK-NEXT: [[SUB2_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn half 0xH4200, [[MUL_I]]
+// CHECK-NEXT: [[TMP0:%.*]] = fmul reassoc nnan ninf nsz arcp afn half [[HLSL_SATURATE_I]], [[HLSL_SATURATE_I]]
+// CHECK-NEXT: [[MUL4_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn half [[TMP0]], [[SUB2_I]]
+// CHECK-NEXT: ret half [[MUL4_I]]
+//
+// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) half @_Z20test_smoothstep_halfDhDhDh(
+// SPVCHECK-SAME: half noundef nofpclass(nan inf) [[MIN:%.*]], half noundef nofpclass(nan inf) [[MAX:%.*]], half noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
+// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: [[CONV_I:%.*]] = fpext reassoc nnan ninf nsz arcp afn half [[MIN]] to double
+// SPVCHECK-NEXT: [[CONV1_I:%.*]] = fpext reassoc nnan ninf nsz arcp afn half [[MAX]] to double
+// SPVCHECK-NEXT: [[CONV2_I:%.*]] = fpext reassoc nnan ninf nsz arcp afn half [[X]] to double
+// SPVCHECK-NEXT: [[SPV_SMOOTHSTEP_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn double @llvm.spv.smoothstep.f64(double [[CONV_I]], double [[CONV1_I]], double [[CONV2_I]])
+// SPVCHECK-NEXT: [[CONV3_I:%.*]] = fptrunc reassoc nnan ninf nsz arcp afn double [[SPV_SMOOTHSTEP_I]] to half
+// SPVCHECK-NEXT: ret half [[CONV3_I]]
+//
+half test_smoothstep_half(half Min, half Max, half X) { return smoothstep(Min, Max, X); }
+
+// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x half> @_Z21test_smoothstep_half2Dv2_DhS_S_(
+// CHECK-SAME: <2 x half> noundef nofpclass(nan inf) [[MIN:%.*]], <2 x half> noundef nofpclass(nan inf) [[MAX:%.*]], <2 x half> noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <2 x half> [[X]], [[MIN]]
+// CHECK-NEXT: [[SUB1_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <2 x half> [[MAX]], [[MIN]]
+// CHECK-NEXT: [[DIV_I:%.*]] = fdiv reassoc nnan ninf nsz arcp afn <2 x half> [[SUB_I]], [[SUB1_I]]
+// CHECK-NEXT: [[HLSL_SATURATE_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn <2 x half> @llvm.dx.saturate.v2f16(<2 x half> [[DIV_I]])
+// CHECK-NEXT: [[MUL_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn <2 x half> [[HLSL_SATURATE_I]], splat (half 0xH4000)
+// CHECK-NEXT: [[SUB2_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <2 x half> splat (half 0xH4200), [[MUL_I]]
+// CHECK-NEXT: [[TMP0:%.*]] = fmul reassoc nnan ninf nsz arcp afn <2 x half> [[HLSL_SATURATE_I]], [[HLSL_SATURATE_I]]
+// CHECK-NEXT: [[MUL4_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn <2 x half> [[TMP0]], [[SUB2_I]]
+// CHECK-NEXT: ret <2 x half> [[MUL4_I]]
+//
+// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) <2 x half> @_Z21test_smoothstep_half2Dv2_DhS_S_(
+// SPVCHECK-SAME: <2 x half> noundef nofpclass(nan inf) [[MIN:%.*]], <2 x half> noundef nofpclass(nan inf) [[MAX:%.*]], <2 x half> noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: [[SPV_SMOOTHSTEP_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef <2 x half> @llvm.spv.smoothstep.v2f16(<2 x half> [[MIN]], <2 x half> [[MAX]], <2 x half> [[X]])
+// SPVCHECK-NEXT: ret <2 x half> [[SPV_SMOOTHSTEP_I]]
+//
+half2 test_smoothstep_half2(half2 Min, half2 Max, half2 X) { return smoothstep(Min, Max, X); }
+
+// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x half> @_Z21test_smoothstep_half3Dv3_DhS_S_(
+// CHECK-SAME: <3 x half> noundef nofpclass(nan inf) [[MIN:%.*]], <3 x half> noundef nofpclass(nan inf) [[MAX:%.*]], <3 x half> noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <3 x half> [[X]], [[MIN]]
+// CHECK-NEXT: [[SUB1_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <3 x half> [[MAX]], [[MIN]]
+// CHECK-NEXT: [[DIV_I:%.*]] = fdiv reassoc nnan ninf nsz arcp afn <3 x half> [[SUB_I]], [[SUB1_I]]
+// CHECK-NEXT: [[HLSL_SATURATE_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn <3 x half> @llvm.dx.saturate.v3f16(<3 x half> [[DIV_I]])
+// CHECK-NEXT: [[MUL_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn <3 x half> [[HLSL_SATURATE_I]], splat (half 0xH4000)
+// CHECK-NEXT: [[SUB2_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <3 x half> splat (half 0xH4200), [[MUL_I]]
+// CHECK-NEXT: [[TMP0:%.*]] = fmul reassoc nnan ninf nsz arcp afn <3 x half> [[HLSL_SATURATE_I]], [[HLSL_SATURATE_I]]
+// CHECK-NEXT: [[MUL4_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn <3 x half> [[TMP0]], [[SUB2_I]]
+// CHECK-NEXT: ret <3 x half> [[MUL4_I]]
+//
+// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) <3 x half> @_Z21test_smoothstep_half3Dv3_DhS_S_(
+// SPVCHECK-SAME: <3 x half> noundef nofpclass(nan inf) [[MIN:%.*]], <3 x half> noundef nofpclass(nan inf) [[MAX:%.*]], <3 x half> noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: [[SPV_SMOOTHSTEP_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef <3 x half> @llvm.spv.smoothstep.v3f16(<3 x half> [[MIN]], <3 x half> [[MAX]], <3 x half> [[X]])
+// SPVCHECK-NEXT: ret <3 x half> [[SPV_SMOOTHSTEP_I]]
+//
+half3 test_smoothstep_half3(half3 Min, half3 Max, half3 X) { return smoothstep(Min, Max, X); }
+
+// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x half> @_Z21test_smoothstep_half4Dv4_DhS_S_(
+// CHECK-SAME: <4 x half> noundef nofpclass(nan inf) [[MIN:%.*]], <4 x half> noundef nofpclass(nan inf) [[MAX:%.*]], <4 x half> noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <4 x half> [[X]], [[MIN]]
+// CHECK-NEXT: [[SUB1_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <4 x half> [[MAX]], [[MIN]]
+// CHECK-NEXT: [[DIV_I:%.*]] = fdiv reassoc nnan ninf nsz arcp afn <4 x half> [[SUB_I]], [[SUB1_I]]
+// CHECK-NEXT: [[HLSL_SATURATE_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn <4 x half> @llvm.dx.saturate.v4f16(<4 x half> [[DIV_I]])
+// CHECK-NEXT: [[MUL_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn <4 x half> [[HLSL_SATURATE_I]], splat (half 0xH4000)
+// CHECK-NEXT: [[SUB2_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <4 x half> splat (half 0xH4200), [[MUL_I]]
+// CHECK-NEXT: [[TMP0:%.*]] = fmul reassoc nnan ninf nsz arcp afn <4 x half> [[HLSL_SATURATE_I]], [[HLSL_SATURATE_I]]
+// CHECK-NEXT: [[MUL4_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn <4 x half> [[TMP0]], [[SUB2_I]]
+// CHECK-NEXT: ret <4 x half> [[MUL4_I]]
+//
+// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) <4 x half> @_Z21test_smoothstep_half4Dv4_DhS_S_(
+// SPVCHECK-SAME: <4 x half> noundef nofpclass(nan inf) [[MIN:%.*]], <4 x half> noundef nofpclass(nan inf) [[MAX:%.*]], <4 x half> noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: [[SPV_SMOOTHSTEP_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef <4 x half> @llvm.spv.smoothstep.v4f16(<4 x half> [[MIN]], <4 x half> [[MAX]], <4 x half> [[X]])
+// SPVCHECK-NEXT: ret <4 x half> [[SPV_SMOOTHSTEP_I]]
+//
+half4 test_smoothstep_half4(half4 Min, half4 Max, half4 X) { return smoothstep(Min, Max, X); }
+
+// CHECK-LABEL: define noundef nofpclass(nan inf) float @_Z21test_smoothstep_floatfff(
+// CHECK-SAME: float noundef nofpclass(nan inf) [[MIN:%.*]], float noundef nofpclass(nan inf) [[MAX:%.*]], float noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn float [[X]], [[MIN]]
+// CHECK-NEXT: [[SUB1_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn float [[MAX]], [[MIN]]
+// CHECK-NEXT: [[DIV_I:%.*]] = fdiv reassoc nnan ninf nsz arcp afn float [[SUB_I]], [[SUB1_I]]
+// CHECK-NEXT: [[HLSL_SATURATE_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn float @llvm.dx.saturate.f32(float [[DIV_I]])
+// CHECK-NEXT: [[MUL_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn float [[HLSL_SATURATE_I]], 2.000000e+00
+// CHECK-NEXT: [[SUB2_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn float 3.000000e+00, [[MUL_I]]
+// CHECK-NEXT: [[TMP0:%.*]] = fmul reassoc nnan ninf nsz arcp afn float [[HLSL_SATURATE_I]], [[HLSL_SATURATE_I]]
+// CHECK-NEXT: [[MUL4_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn float [[TMP0]], [[SUB2_I]]
+// CHECK-NEXT: ret float [[MUL4_I]]
+//
+// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) float @_Z21test_smoothstep_floatfff(
+// SPVCHECK-SAME: float noundef nofpclass(nan inf) [[MIN:%.*]], float noundef nofpclass(nan inf) [[MAX:%.*]], float noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: [[CONV_I:%.*]] = fpext reassoc nnan ninf nsz arcp afn float [[MIN]] to double
+// SPVCHECK-NEXT: [[CONV1_I:%.*]] = fpext reassoc nnan ninf nsz arcp afn float [[MAX]] to double
+// SPVCHECK-NEXT: [[CONV2_I:%.*]] = fpext reassoc nnan ninf nsz arcp afn float [[X]] to double
+// SPVCHECK-NEXT: [[SPV_SMOOTHSTEP_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn double @llvm.spv.smoothstep.f64(double [[CONV_I]], double [[CONV1_I]], double [[CONV2_I]])
+// SPVCHECK-NEXT: [[CONV3_I:%.*]] = fptrunc reassoc nnan ninf nsz arcp afn double [[SPV_SMOOTHSTEP_I]] to float
+// SPVCHECK-NEXT: ret float [[CONV3_I]]
+//
+float test_smoothstep_float(float Min, float Max, float X) { return smoothstep(Min, Max, X); }
+
+// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> @_Z22test_smoothstep_float2Dv2_fS_S_(
+// CHECK-SAME: <2 x float> noundef nofpclass(nan inf) [[MIN:%.*]], <2 x float> noundef nofpclass(nan inf) [[MAX:%.*]], <2 x float> noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <2 x float> [[X]], [[MIN]]
+// CHECK-NEXT: [[SUB1_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <2 x float> [[MAX]], [[MIN]]
+// CHECK-NEXT: [[DIV_I:%.*]] = fdiv reassoc nnan ninf nsz arcp afn <2 x float> [[SUB_I]], [[SUB1_I]]
+// CHECK-NEXT: [[HLSL_SATURATE_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.dx.saturate.v2f32(<2 x float> [[DIV_I]])
+// CHECK-NEXT: [[MUL_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn <2 x float> [[HLSL_SATURATE_I]], splat (float 2.000000e+00)
+// CHECK-NEXT: [[SUB2_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <2 x float> splat (float 3.000000e+00), [[MUL_I]]
+// CHECK-NEXT: [[TMP0:%.*]] = fmul reassoc nnan ninf nsz arcp afn <2 x float> [[HLSL_SATURATE_I]], [[HLSL_SATURATE_I]]
+// CHECK-NEXT: [[MUL4_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn <2 x float> [[TMP0]], [[SUB2_I]]
+// CHECK-NEXT: ret <2 x float> [[MUL4_I]]
+//
+// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) <2 x float> @_Z22test_smoothstep_float2Dv2_fS_S_(
+// SPVCHECK-SAME: <2 x float> noundef nofpclass(nan inf) [[MIN:%.*]], <2 x float> noundef nofpclass(nan inf) [[MAX:%.*]], <2 x float> noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: [[SPV_SMOOTHSTEP_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef <2 x float> @llvm.spv.smoothstep.v2f32(<2 x float> [[MIN]], <2 x float> [[MAX]], <2 x float> [[X]])
+// SPVCHECK-NEXT: ret <2 x float> [[SPV_SMOOTHSTEP_I]]
+//
+float2 test_smoothstep_float2(float2 Min, float2 Max, float2 X) { return smoothstep(Min, Max, X); }
+
+// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> @_Z22test_smoothstep_float3Dv3_fS_S_(
+// CHECK-SAME: <3 x float> noundef nofpclass(nan inf) [[MIN:%.*]], <3 x float> noundef nofpclass(nan inf) [[MAX:%.*]], <3 x float> noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr ...
[truncated]
|
@llvm/pr-subscribers-llvm-ir Author: Kaitlin Peng (kmpeng) ChangesCloses #99156. Tasks completed:
Patch is 41.67 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/132288.diff 13 Files Affected:
diff --git a/clang/include/clang/Basic/BuiltinsSPIRV.td b/clang/include/clang/Basic/BuiltinsSPIRV.td
index 34933e889ba31..2eb4c733b0a42 100644
--- a/clang/include/clang/Basic/BuiltinsSPIRV.td
+++ b/clang/include/clang/Basic/BuiltinsSPIRV.td
@@ -25,3 +25,9 @@ def SPIRVReflect : Builtin {
let Attributes = [NoThrow, Const];
let Prototype = "void(...)";
}
+
+def SPIRVSmoothStep : Builtin {
+ let Spellings = ["__builtin_spirv_smoothstep"];
+ let Attributes = [NoThrow, Const];
+ let Prototype = "void(...)";
+}
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index c126f88b9e3a5..ac92f89415724 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -20955,6 +20955,25 @@ Value *CodeGenFunction::EmitSPIRVBuiltinExpr(unsigned BuiltinID,
/*ReturnType=*/I->getType(), Intrinsic::spv_reflect,
ArrayRef<Value *>{I, N}, nullptr, "spv.reflect");
}
+ case SPIRV::BI__builtin_spirv_smoothstep: {
+ Value *Min = EmitScalarExpr(E->getArg(0));
+ Value *Max = EmitScalarExpr(E->getArg(1));
+ Value *X = EmitScalarExpr(E->getArg(2));
+ assert(E->getArg(0)->getType()->hasFloatingRepresentation() &&
+ E->getArg(1)->getType()->hasFloatingRepresentation() &&
+ E->getArg(2)->getType()->hasFloatingRepresentation() &&
+ "SmoothStep operands must have a float representation");
+ assert((E->getArg(0)->getType()->isScalarType() ||
+ E->getArg(0)->getType()->isVectorType()) &&
+ (E->getArg(1)->getType()->isScalarType() ||
+ E->getArg(1)->getType()->isVectorType()) &&
+ (E->getArg(2)->getType()->isScalarType() ||
+ E->getArg(2)->getType()->isVectorType()) &&
+ "SmoothStep operands must be a scalar or vector");
+ return Builder.CreateIntrinsic(
+ /*ReturnType=*/Min->getType(), Intrinsic::spv_smoothstep,
+ ArrayRef<Value *>{Min, Max, X}, nullptr, "spv.smoothstep");
+ }
}
return nullptr;
}
diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h b/clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h
index 89ab664e90ba9..8cdd63d7e07bb 100644
--- a/clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h
+++ b/clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h
@@ -81,6 +81,26 @@ constexpr vector<T, N> fmod_vec_impl(vector<T, N> X, vector<T, N> Y) {
#endif
}
+template <typename T> constexpr T smoothstep_impl(T Min, T Max, T X) {
+#if (__has_builtin(__builtin_spirv_smoothstep))
+ return __builtin_spirv_smoothstep(Min, Max, X);
+#else
+ T S = saturate((X - Min) / (Max - Min));
+ return (3 - 2 * S) * S * S;
+#endif
+}
+
+template <typename T, int N>
+constexpr vector<T, N> smoothstep_vec_impl(vector<T, N> Min, vector<T, N> Max,
+ vector<T, N> X) {
+#if (__has_builtin(__builtin_spirv_smoothstep))
+ return __builtin_spirv_smoothstep(Min, Max, X);
+#else
+ vector<T, N> S = saturate((X - Min) / (Max - Min));
+ return (3 - 2 * S) * S * S;
+#endif
+}
+
} // namespace __detail
} // namespace hlsl
diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h
index a48a8e998a015..3803a87d32afc 100644
--- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h
+++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h
@@ -264,5 +264,53 @@ reflect(__detail::HLSL_FIXED_VECTOR<float, L> I,
__detail::HLSL_FIXED_VECTOR<float, L> N) {
return __detail::reflect_vec_impl(I, N);
}
+
+//===----------------------------------------------------------------------===//
+// smoothstep builtin
+//===----------------------------------------------------------------------===//
+
+/// \fn T smoothstep(T Min, T Max, T X)
+/// \brief Returns a smooth Hermite interpolation between 0 and 1, if \a X is in
+/// the range [\a Min, \a Max].
+/// \param Min The minimum range of the x parameter.
+/// \param Max The maximum range of the x parameter.
+/// \param X The specified value to be interpolated.
+///
+/// The return value is 0.0 if \a X ≤ \a Min and 1.0 if \a X ≥ \a Max. When \a
+/// Min < \a X < \a Max, the function performs smooth Hermite interpolation
+/// between 0 and 1.
+
+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> smoothstep(T Min, T Max, T X) {
+ return __detail::smoothstep_impl(Min, Max, X);
+}
+
+template <typename T>
+const inline __detail::enable_if_t<
+ __detail::is_arithmetic<T>::Value && __detail::is_same<float, T>::value, T>
+smoothstep(T Min, T Max, T X) {
+ return __detail::smoothstep_impl(Min, Max, X);
+}
+
+template <int N>
+_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
+const inline __detail::HLSL_FIXED_VECTOR<half, N> smoothstep(
+ __detail::HLSL_FIXED_VECTOR<half, N> Min,
+ __detail::HLSL_FIXED_VECTOR<half, N> Max,
+ __detail::HLSL_FIXED_VECTOR<half, N> X) {
+ return __detail::smoothstep_vec_impl(Min, Max, X);
+}
+
+template <int N>
+const inline __detail::HLSL_FIXED_VECTOR<float, N>
+smoothstep(__detail::HLSL_FIXED_VECTOR<float, N> Min,
+ __detail::HLSL_FIXED_VECTOR<float, N> Max,
+ __detail::HLSL_FIXED_VECTOR<float, N> X) {
+ return __detail::smoothstep_vec_impl(Min, Max, X);
+}
+
} // namespace hlsl
#endif //_HLSL_HLSL_INTRINSICS_H_
diff --git a/clang/lib/Sema/SemaSPIRV.cpp b/clang/lib/Sema/SemaSPIRV.cpp
index 94534485e07c3..2cbb57a739a1a 100644
--- a/clang/lib/Sema/SemaSPIRV.cpp
+++ b/clang/lib/Sema/SemaSPIRV.cpp
@@ -101,6 +101,44 @@ bool SemaSPIRV::CheckSPIRVBuiltinFunctionCall(unsigned BuiltinID,
TheCall->setType(RetTy);
break;
}
+ case SPIRV::BI__builtin_spirv_smoothstep: {
+ if (SemaRef.checkArgCount(TheCall, 3))
+ return true;
+
+ ExprResult A = TheCall->getArg(0);
+ QualType ArgTyA = A.get()->getType();
+ auto *VTyA = ArgTyA->getAs<VectorType>();
+ if (!(ArgTyA->isScalarType() || VTyA)) {
+ SemaRef.Diag(A.get()->getBeginLoc(),
+ diag::err_typecheck_expect_any_scalar_or_vector)
+ << ArgTyA << 1;
+ return true;
+ }
+
+ ExprResult B = TheCall->getArg(1);
+ QualType ArgTyB = B.get()->getType();
+ auto *VTyB = ArgTyB->getAs<VectorType>();
+ if (!(ArgTyB->isScalarType() || VTyB)) {
+ SemaRef.Diag(A.get()->getBeginLoc(),
+ diag::err_typecheck_expect_any_scalar_or_vector)
+ << ArgTyB << 1;
+ return true;
+ }
+
+ ExprResult C = TheCall->getArg(2);
+ QualType ArgTyC = C.get()->getType();
+ auto *VTyC = ArgTyC->getAs<VectorType>();
+ if (!(ArgTyC->isScalarType() || VTyC)) {
+ SemaRef.Diag(A.get()->getBeginLoc(),
+ diag::err_typecheck_expect_any_scalar_or_vector)
+ << ArgTyC << 1;
+ return true;
+ }
+
+ QualType RetTy = ArgTyA;
+ TheCall->setType(RetTy);
+ break;
+ }
}
return false;
}
diff --git a/clang/test/CodeGenHLSL/builtins/smoothstep.hlsl b/clang/test/CodeGenHLSL/builtins/smoothstep.hlsl
new file mode 100644
index 0000000000000..bbb19692f1225
--- /dev/null
+++ b/clang/test/CodeGenHLSL/builtins/smoothstep.hlsl
@@ -0,0 +1,183 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5
+// RUN: %clang_cc1 -finclude-default-header -x hlsl -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 @_Z20test_smoothstep_halfDhDhDh(
+// CHECK-SAME: half noundef nofpclass(nan inf) [[MIN:%.*]], half noundef nofpclass(nan inf) [[MAX:%.*]], half noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn half [[X]], [[MIN]]
+// CHECK-NEXT: [[SUB1_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn half [[MAX]], [[MIN]]
+// CHECK-NEXT: [[DIV_I:%.*]] = fdiv reassoc nnan ninf nsz arcp afn half [[SUB_I]], [[SUB1_I]]
+// CHECK-NEXT: [[HLSL_SATURATE_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn half @llvm.dx.saturate.f16(half [[DIV_I]])
+// CHECK-NEXT: [[MUL_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn half [[HLSL_SATURATE_I]], 0xH4000
+// CHECK-NEXT: [[SUB2_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn half 0xH4200, [[MUL_I]]
+// CHECK-NEXT: [[TMP0:%.*]] = fmul reassoc nnan ninf nsz arcp afn half [[HLSL_SATURATE_I]], [[HLSL_SATURATE_I]]
+// CHECK-NEXT: [[MUL4_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn half [[TMP0]], [[SUB2_I]]
+// CHECK-NEXT: ret half [[MUL4_I]]
+//
+// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) half @_Z20test_smoothstep_halfDhDhDh(
+// SPVCHECK-SAME: half noundef nofpclass(nan inf) [[MIN:%.*]], half noundef nofpclass(nan inf) [[MAX:%.*]], half noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
+// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: [[CONV_I:%.*]] = fpext reassoc nnan ninf nsz arcp afn half [[MIN]] to double
+// SPVCHECK-NEXT: [[CONV1_I:%.*]] = fpext reassoc nnan ninf nsz arcp afn half [[MAX]] to double
+// SPVCHECK-NEXT: [[CONV2_I:%.*]] = fpext reassoc nnan ninf nsz arcp afn half [[X]] to double
+// SPVCHECK-NEXT: [[SPV_SMOOTHSTEP_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn double @llvm.spv.smoothstep.f64(double [[CONV_I]], double [[CONV1_I]], double [[CONV2_I]])
+// SPVCHECK-NEXT: [[CONV3_I:%.*]] = fptrunc reassoc nnan ninf nsz arcp afn double [[SPV_SMOOTHSTEP_I]] to half
+// SPVCHECK-NEXT: ret half [[CONV3_I]]
+//
+half test_smoothstep_half(half Min, half Max, half X) { return smoothstep(Min, Max, X); }
+
+// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x half> @_Z21test_smoothstep_half2Dv2_DhS_S_(
+// CHECK-SAME: <2 x half> noundef nofpclass(nan inf) [[MIN:%.*]], <2 x half> noundef nofpclass(nan inf) [[MAX:%.*]], <2 x half> noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <2 x half> [[X]], [[MIN]]
+// CHECK-NEXT: [[SUB1_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <2 x half> [[MAX]], [[MIN]]
+// CHECK-NEXT: [[DIV_I:%.*]] = fdiv reassoc nnan ninf nsz arcp afn <2 x half> [[SUB_I]], [[SUB1_I]]
+// CHECK-NEXT: [[HLSL_SATURATE_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn <2 x half> @llvm.dx.saturate.v2f16(<2 x half> [[DIV_I]])
+// CHECK-NEXT: [[MUL_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn <2 x half> [[HLSL_SATURATE_I]], splat (half 0xH4000)
+// CHECK-NEXT: [[SUB2_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <2 x half> splat (half 0xH4200), [[MUL_I]]
+// CHECK-NEXT: [[TMP0:%.*]] = fmul reassoc nnan ninf nsz arcp afn <2 x half> [[HLSL_SATURATE_I]], [[HLSL_SATURATE_I]]
+// CHECK-NEXT: [[MUL4_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn <2 x half> [[TMP0]], [[SUB2_I]]
+// CHECK-NEXT: ret <2 x half> [[MUL4_I]]
+//
+// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) <2 x half> @_Z21test_smoothstep_half2Dv2_DhS_S_(
+// SPVCHECK-SAME: <2 x half> noundef nofpclass(nan inf) [[MIN:%.*]], <2 x half> noundef nofpclass(nan inf) [[MAX:%.*]], <2 x half> noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: [[SPV_SMOOTHSTEP_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef <2 x half> @llvm.spv.smoothstep.v2f16(<2 x half> [[MIN]], <2 x half> [[MAX]], <2 x half> [[X]])
+// SPVCHECK-NEXT: ret <2 x half> [[SPV_SMOOTHSTEP_I]]
+//
+half2 test_smoothstep_half2(half2 Min, half2 Max, half2 X) { return smoothstep(Min, Max, X); }
+
+// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x half> @_Z21test_smoothstep_half3Dv3_DhS_S_(
+// CHECK-SAME: <3 x half> noundef nofpclass(nan inf) [[MIN:%.*]], <3 x half> noundef nofpclass(nan inf) [[MAX:%.*]], <3 x half> noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <3 x half> [[X]], [[MIN]]
+// CHECK-NEXT: [[SUB1_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <3 x half> [[MAX]], [[MIN]]
+// CHECK-NEXT: [[DIV_I:%.*]] = fdiv reassoc nnan ninf nsz arcp afn <3 x half> [[SUB_I]], [[SUB1_I]]
+// CHECK-NEXT: [[HLSL_SATURATE_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn <3 x half> @llvm.dx.saturate.v3f16(<3 x half> [[DIV_I]])
+// CHECK-NEXT: [[MUL_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn <3 x half> [[HLSL_SATURATE_I]], splat (half 0xH4000)
+// CHECK-NEXT: [[SUB2_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <3 x half> splat (half 0xH4200), [[MUL_I]]
+// CHECK-NEXT: [[TMP0:%.*]] = fmul reassoc nnan ninf nsz arcp afn <3 x half> [[HLSL_SATURATE_I]], [[HLSL_SATURATE_I]]
+// CHECK-NEXT: [[MUL4_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn <3 x half> [[TMP0]], [[SUB2_I]]
+// CHECK-NEXT: ret <3 x half> [[MUL4_I]]
+//
+// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) <3 x half> @_Z21test_smoothstep_half3Dv3_DhS_S_(
+// SPVCHECK-SAME: <3 x half> noundef nofpclass(nan inf) [[MIN:%.*]], <3 x half> noundef nofpclass(nan inf) [[MAX:%.*]], <3 x half> noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: [[SPV_SMOOTHSTEP_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef <3 x half> @llvm.spv.smoothstep.v3f16(<3 x half> [[MIN]], <3 x half> [[MAX]], <3 x half> [[X]])
+// SPVCHECK-NEXT: ret <3 x half> [[SPV_SMOOTHSTEP_I]]
+//
+half3 test_smoothstep_half3(half3 Min, half3 Max, half3 X) { return smoothstep(Min, Max, X); }
+
+// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x half> @_Z21test_smoothstep_half4Dv4_DhS_S_(
+// CHECK-SAME: <4 x half> noundef nofpclass(nan inf) [[MIN:%.*]], <4 x half> noundef nofpclass(nan inf) [[MAX:%.*]], <4 x half> noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <4 x half> [[X]], [[MIN]]
+// CHECK-NEXT: [[SUB1_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <4 x half> [[MAX]], [[MIN]]
+// CHECK-NEXT: [[DIV_I:%.*]] = fdiv reassoc nnan ninf nsz arcp afn <4 x half> [[SUB_I]], [[SUB1_I]]
+// CHECK-NEXT: [[HLSL_SATURATE_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn <4 x half> @llvm.dx.saturate.v4f16(<4 x half> [[DIV_I]])
+// CHECK-NEXT: [[MUL_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn <4 x half> [[HLSL_SATURATE_I]], splat (half 0xH4000)
+// CHECK-NEXT: [[SUB2_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <4 x half> splat (half 0xH4200), [[MUL_I]]
+// CHECK-NEXT: [[TMP0:%.*]] = fmul reassoc nnan ninf nsz arcp afn <4 x half> [[HLSL_SATURATE_I]], [[HLSL_SATURATE_I]]
+// CHECK-NEXT: [[MUL4_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn <4 x half> [[TMP0]], [[SUB2_I]]
+// CHECK-NEXT: ret <4 x half> [[MUL4_I]]
+//
+// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) <4 x half> @_Z21test_smoothstep_half4Dv4_DhS_S_(
+// SPVCHECK-SAME: <4 x half> noundef nofpclass(nan inf) [[MIN:%.*]], <4 x half> noundef nofpclass(nan inf) [[MAX:%.*]], <4 x half> noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: [[SPV_SMOOTHSTEP_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef <4 x half> @llvm.spv.smoothstep.v4f16(<4 x half> [[MIN]], <4 x half> [[MAX]], <4 x half> [[X]])
+// SPVCHECK-NEXT: ret <4 x half> [[SPV_SMOOTHSTEP_I]]
+//
+half4 test_smoothstep_half4(half4 Min, half4 Max, half4 X) { return smoothstep(Min, Max, X); }
+
+// CHECK-LABEL: define noundef nofpclass(nan inf) float @_Z21test_smoothstep_floatfff(
+// CHECK-SAME: float noundef nofpclass(nan inf) [[MIN:%.*]], float noundef nofpclass(nan inf) [[MAX:%.*]], float noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn float [[X]], [[MIN]]
+// CHECK-NEXT: [[SUB1_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn float [[MAX]], [[MIN]]
+// CHECK-NEXT: [[DIV_I:%.*]] = fdiv reassoc nnan ninf nsz arcp afn float [[SUB_I]], [[SUB1_I]]
+// CHECK-NEXT: [[HLSL_SATURATE_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn float @llvm.dx.saturate.f32(float [[DIV_I]])
+// CHECK-NEXT: [[MUL_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn float [[HLSL_SATURATE_I]], 2.000000e+00
+// CHECK-NEXT: [[SUB2_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn float 3.000000e+00, [[MUL_I]]
+// CHECK-NEXT: [[TMP0:%.*]] = fmul reassoc nnan ninf nsz arcp afn float [[HLSL_SATURATE_I]], [[HLSL_SATURATE_I]]
+// CHECK-NEXT: [[MUL4_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn float [[TMP0]], [[SUB2_I]]
+// CHECK-NEXT: ret float [[MUL4_I]]
+//
+// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) float @_Z21test_smoothstep_floatfff(
+// SPVCHECK-SAME: float noundef nofpclass(nan inf) [[MIN:%.*]], float noundef nofpclass(nan inf) [[MAX:%.*]], float noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: [[CONV_I:%.*]] = fpext reassoc nnan ninf nsz arcp afn float [[MIN]] to double
+// SPVCHECK-NEXT: [[CONV1_I:%.*]] = fpext reassoc nnan ninf nsz arcp afn float [[MAX]] to double
+// SPVCHECK-NEXT: [[CONV2_I:%.*]] = fpext reassoc nnan ninf nsz arcp afn float [[X]] to double
+// SPVCHECK-NEXT: [[SPV_SMOOTHSTEP_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn double @llvm.spv.smoothstep.f64(double [[CONV_I]], double [[CONV1_I]], double [[CONV2_I]])
+// SPVCHECK-NEXT: [[CONV3_I:%.*]] = fptrunc reassoc nnan ninf nsz arcp afn double [[SPV_SMOOTHSTEP_I]] to float
+// SPVCHECK-NEXT: ret float [[CONV3_I]]
+//
+float test_smoothstep_float(float Min, float Max, float X) { return smoothstep(Min, Max, X); }
+
+// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> @_Z22test_smoothstep_float2Dv2_fS_S_(
+// CHECK-SAME: <2 x float> noundef nofpclass(nan inf) [[MIN:%.*]], <2 x float> noundef nofpclass(nan inf) [[MAX:%.*]], <2 x float> noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <2 x float> [[X]], [[MIN]]
+// CHECK-NEXT: [[SUB1_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <2 x float> [[MAX]], [[MIN]]
+// CHECK-NEXT: [[DIV_I:%.*]] = fdiv reassoc nnan ninf nsz arcp afn <2 x float> [[SUB_I]], [[SUB1_I]]
+// CHECK-NEXT: [[HLSL_SATURATE_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.dx.saturate.v2f32(<2 x float> [[DIV_I]])
+// CHECK-NEXT: [[MUL_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn <2 x float> [[HLSL_SATURATE_I]], splat (float 2.000000e+00)
+// CHECK-NEXT: [[SUB2_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <2 x float> splat (float 3.000000e+00), [[MUL_I]]
+// CHECK-NEXT: [[TMP0:%.*]] = fmul reassoc nnan ninf nsz arcp afn <2 x float> [[HLSL_SATURATE_I]], [[HLSL_SATURATE_I]]
+// CHECK-NEXT: [[MUL4_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn <2 x float> [[TMP0]], [[SUB2_I]]
+// CHECK-NEXT: ret <2 x float> [[MUL4_I]]
+//
+// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) <2 x float> @_Z22test_smoothstep_float2Dv2_fS_S_(
+// SPVCHECK-SAME: <2 x float> noundef nofpclass(nan inf) [[MIN:%.*]], <2 x float> noundef nofpclass(nan inf) [[MAX:%.*]], <2 x float> noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: [[SPV_SMOOTHSTEP_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef <2 x float> @llvm.spv.smoothstep.v2f32(<2 x float> [[MIN]], <2 x float> [[MAX]], <2 x float> [[X]])
+// SPVCHECK-NEXT: ret <2 x float> [[SPV_SMOOTHSTEP_I]]
+//
+float2 test_smoothstep_float2(float2 Min, float2 Max, float2 X) { return smoothstep(Min, Max, X); }
+
+// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> @_Z22test_smoothstep_float3Dv3_fS_S_(
+// CHECK-SAME: <3 x float> noundef nofpclass(nan inf) [[MIN:%.*]], <3 x float> noundef nofpclass(nan inf) [[MAX:%.*]], <3 x float> noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr ...
[truncated]
|
@llvm/pr-subscribers-hlsl Author: Kaitlin Peng (kmpeng) ChangesCloses #99156. Tasks completed:
Patch is 41.67 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/132288.diff 13 Files Affected:
diff --git a/clang/include/clang/Basic/BuiltinsSPIRV.td b/clang/include/clang/Basic/BuiltinsSPIRV.td
index 34933e889ba31..2eb4c733b0a42 100644
--- a/clang/include/clang/Basic/BuiltinsSPIRV.td
+++ b/clang/include/clang/Basic/BuiltinsSPIRV.td
@@ -25,3 +25,9 @@ def SPIRVReflect : Builtin {
let Attributes = [NoThrow, Const];
let Prototype = "void(...)";
}
+
+def SPIRVSmoothStep : Builtin {
+ let Spellings = ["__builtin_spirv_smoothstep"];
+ let Attributes = [NoThrow, Const];
+ let Prototype = "void(...)";
+}
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index c126f88b9e3a5..ac92f89415724 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -20955,6 +20955,25 @@ Value *CodeGenFunction::EmitSPIRVBuiltinExpr(unsigned BuiltinID,
/*ReturnType=*/I->getType(), Intrinsic::spv_reflect,
ArrayRef<Value *>{I, N}, nullptr, "spv.reflect");
}
+ case SPIRV::BI__builtin_spirv_smoothstep: {
+ Value *Min = EmitScalarExpr(E->getArg(0));
+ Value *Max = EmitScalarExpr(E->getArg(1));
+ Value *X = EmitScalarExpr(E->getArg(2));
+ assert(E->getArg(0)->getType()->hasFloatingRepresentation() &&
+ E->getArg(1)->getType()->hasFloatingRepresentation() &&
+ E->getArg(2)->getType()->hasFloatingRepresentation() &&
+ "SmoothStep operands must have a float representation");
+ assert((E->getArg(0)->getType()->isScalarType() ||
+ E->getArg(0)->getType()->isVectorType()) &&
+ (E->getArg(1)->getType()->isScalarType() ||
+ E->getArg(1)->getType()->isVectorType()) &&
+ (E->getArg(2)->getType()->isScalarType() ||
+ E->getArg(2)->getType()->isVectorType()) &&
+ "SmoothStep operands must be a scalar or vector");
+ return Builder.CreateIntrinsic(
+ /*ReturnType=*/Min->getType(), Intrinsic::spv_smoothstep,
+ ArrayRef<Value *>{Min, Max, X}, nullptr, "spv.smoothstep");
+ }
}
return nullptr;
}
diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h b/clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h
index 89ab664e90ba9..8cdd63d7e07bb 100644
--- a/clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h
+++ b/clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h
@@ -81,6 +81,26 @@ constexpr vector<T, N> fmod_vec_impl(vector<T, N> X, vector<T, N> Y) {
#endif
}
+template <typename T> constexpr T smoothstep_impl(T Min, T Max, T X) {
+#if (__has_builtin(__builtin_spirv_smoothstep))
+ return __builtin_spirv_smoothstep(Min, Max, X);
+#else
+ T S = saturate((X - Min) / (Max - Min));
+ return (3 - 2 * S) * S * S;
+#endif
+}
+
+template <typename T, int N>
+constexpr vector<T, N> smoothstep_vec_impl(vector<T, N> Min, vector<T, N> Max,
+ vector<T, N> X) {
+#if (__has_builtin(__builtin_spirv_smoothstep))
+ return __builtin_spirv_smoothstep(Min, Max, X);
+#else
+ vector<T, N> S = saturate((X - Min) / (Max - Min));
+ return (3 - 2 * S) * S * S;
+#endif
+}
+
} // namespace __detail
} // namespace hlsl
diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h
index a48a8e998a015..3803a87d32afc 100644
--- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h
+++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h
@@ -264,5 +264,53 @@ reflect(__detail::HLSL_FIXED_VECTOR<float, L> I,
__detail::HLSL_FIXED_VECTOR<float, L> N) {
return __detail::reflect_vec_impl(I, N);
}
+
+//===----------------------------------------------------------------------===//
+// smoothstep builtin
+//===----------------------------------------------------------------------===//
+
+/// \fn T smoothstep(T Min, T Max, T X)
+/// \brief Returns a smooth Hermite interpolation between 0 and 1, if \a X is in
+/// the range [\a Min, \a Max].
+/// \param Min The minimum range of the x parameter.
+/// \param Max The maximum range of the x parameter.
+/// \param X The specified value to be interpolated.
+///
+/// The return value is 0.0 if \a X ≤ \a Min and 1.0 if \a X ≥ \a Max. When \a
+/// Min < \a X < \a Max, the function performs smooth Hermite interpolation
+/// between 0 and 1.
+
+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> smoothstep(T Min, T Max, T X) {
+ return __detail::smoothstep_impl(Min, Max, X);
+}
+
+template <typename T>
+const inline __detail::enable_if_t<
+ __detail::is_arithmetic<T>::Value && __detail::is_same<float, T>::value, T>
+smoothstep(T Min, T Max, T X) {
+ return __detail::smoothstep_impl(Min, Max, X);
+}
+
+template <int N>
+_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
+const inline __detail::HLSL_FIXED_VECTOR<half, N> smoothstep(
+ __detail::HLSL_FIXED_VECTOR<half, N> Min,
+ __detail::HLSL_FIXED_VECTOR<half, N> Max,
+ __detail::HLSL_FIXED_VECTOR<half, N> X) {
+ return __detail::smoothstep_vec_impl(Min, Max, X);
+}
+
+template <int N>
+const inline __detail::HLSL_FIXED_VECTOR<float, N>
+smoothstep(__detail::HLSL_FIXED_VECTOR<float, N> Min,
+ __detail::HLSL_FIXED_VECTOR<float, N> Max,
+ __detail::HLSL_FIXED_VECTOR<float, N> X) {
+ return __detail::smoothstep_vec_impl(Min, Max, X);
+}
+
} // namespace hlsl
#endif //_HLSL_HLSL_INTRINSICS_H_
diff --git a/clang/lib/Sema/SemaSPIRV.cpp b/clang/lib/Sema/SemaSPIRV.cpp
index 94534485e07c3..2cbb57a739a1a 100644
--- a/clang/lib/Sema/SemaSPIRV.cpp
+++ b/clang/lib/Sema/SemaSPIRV.cpp
@@ -101,6 +101,44 @@ bool SemaSPIRV::CheckSPIRVBuiltinFunctionCall(unsigned BuiltinID,
TheCall->setType(RetTy);
break;
}
+ case SPIRV::BI__builtin_spirv_smoothstep: {
+ if (SemaRef.checkArgCount(TheCall, 3))
+ return true;
+
+ ExprResult A = TheCall->getArg(0);
+ QualType ArgTyA = A.get()->getType();
+ auto *VTyA = ArgTyA->getAs<VectorType>();
+ if (!(ArgTyA->isScalarType() || VTyA)) {
+ SemaRef.Diag(A.get()->getBeginLoc(),
+ diag::err_typecheck_expect_any_scalar_or_vector)
+ << ArgTyA << 1;
+ return true;
+ }
+
+ ExprResult B = TheCall->getArg(1);
+ QualType ArgTyB = B.get()->getType();
+ auto *VTyB = ArgTyB->getAs<VectorType>();
+ if (!(ArgTyB->isScalarType() || VTyB)) {
+ SemaRef.Diag(A.get()->getBeginLoc(),
+ diag::err_typecheck_expect_any_scalar_or_vector)
+ << ArgTyB << 1;
+ return true;
+ }
+
+ ExprResult C = TheCall->getArg(2);
+ QualType ArgTyC = C.get()->getType();
+ auto *VTyC = ArgTyC->getAs<VectorType>();
+ if (!(ArgTyC->isScalarType() || VTyC)) {
+ SemaRef.Diag(A.get()->getBeginLoc(),
+ diag::err_typecheck_expect_any_scalar_or_vector)
+ << ArgTyC << 1;
+ return true;
+ }
+
+ QualType RetTy = ArgTyA;
+ TheCall->setType(RetTy);
+ break;
+ }
}
return false;
}
diff --git a/clang/test/CodeGenHLSL/builtins/smoothstep.hlsl b/clang/test/CodeGenHLSL/builtins/smoothstep.hlsl
new file mode 100644
index 0000000000000..bbb19692f1225
--- /dev/null
+++ b/clang/test/CodeGenHLSL/builtins/smoothstep.hlsl
@@ -0,0 +1,183 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5
+// RUN: %clang_cc1 -finclude-default-header -x hlsl -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 @_Z20test_smoothstep_halfDhDhDh(
+// CHECK-SAME: half noundef nofpclass(nan inf) [[MIN:%.*]], half noundef nofpclass(nan inf) [[MAX:%.*]], half noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn half [[X]], [[MIN]]
+// CHECK-NEXT: [[SUB1_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn half [[MAX]], [[MIN]]
+// CHECK-NEXT: [[DIV_I:%.*]] = fdiv reassoc nnan ninf nsz arcp afn half [[SUB_I]], [[SUB1_I]]
+// CHECK-NEXT: [[HLSL_SATURATE_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn half @llvm.dx.saturate.f16(half [[DIV_I]])
+// CHECK-NEXT: [[MUL_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn half [[HLSL_SATURATE_I]], 0xH4000
+// CHECK-NEXT: [[SUB2_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn half 0xH4200, [[MUL_I]]
+// CHECK-NEXT: [[TMP0:%.*]] = fmul reassoc nnan ninf nsz arcp afn half [[HLSL_SATURATE_I]], [[HLSL_SATURATE_I]]
+// CHECK-NEXT: [[MUL4_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn half [[TMP0]], [[SUB2_I]]
+// CHECK-NEXT: ret half [[MUL4_I]]
+//
+// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) half @_Z20test_smoothstep_halfDhDhDh(
+// SPVCHECK-SAME: half noundef nofpclass(nan inf) [[MIN:%.*]], half noundef nofpclass(nan inf) [[MAX:%.*]], half noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
+// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: [[CONV_I:%.*]] = fpext reassoc nnan ninf nsz arcp afn half [[MIN]] to double
+// SPVCHECK-NEXT: [[CONV1_I:%.*]] = fpext reassoc nnan ninf nsz arcp afn half [[MAX]] to double
+// SPVCHECK-NEXT: [[CONV2_I:%.*]] = fpext reassoc nnan ninf nsz arcp afn half [[X]] to double
+// SPVCHECK-NEXT: [[SPV_SMOOTHSTEP_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn double @llvm.spv.smoothstep.f64(double [[CONV_I]], double [[CONV1_I]], double [[CONV2_I]])
+// SPVCHECK-NEXT: [[CONV3_I:%.*]] = fptrunc reassoc nnan ninf nsz arcp afn double [[SPV_SMOOTHSTEP_I]] to half
+// SPVCHECK-NEXT: ret half [[CONV3_I]]
+//
+half test_smoothstep_half(half Min, half Max, half X) { return smoothstep(Min, Max, X); }
+
+// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x half> @_Z21test_smoothstep_half2Dv2_DhS_S_(
+// CHECK-SAME: <2 x half> noundef nofpclass(nan inf) [[MIN:%.*]], <2 x half> noundef nofpclass(nan inf) [[MAX:%.*]], <2 x half> noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <2 x half> [[X]], [[MIN]]
+// CHECK-NEXT: [[SUB1_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <2 x half> [[MAX]], [[MIN]]
+// CHECK-NEXT: [[DIV_I:%.*]] = fdiv reassoc nnan ninf nsz arcp afn <2 x half> [[SUB_I]], [[SUB1_I]]
+// CHECK-NEXT: [[HLSL_SATURATE_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn <2 x half> @llvm.dx.saturate.v2f16(<2 x half> [[DIV_I]])
+// CHECK-NEXT: [[MUL_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn <2 x half> [[HLSL_SATURATE_I]], splat (half 0xH4000)
+// CHECK-NEXT: [[SUB2_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <2 x half> splat (half 0xH4200), [[MUL_I]]
+// CHECK-NEXT: [[TMP0:%.*]] = fmul reassoc nnan ninf nsz arcp afn <2 x half> [[HLSL_SATURATE_I]], [[HLSL_SATURATE_I]]
+// CHECK-NEXT: [[MUL4_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn <2 x half> [[TMP0]], [[SUB2_I]]
+// CHECK-NEXT: ret <2 x half> [[MUL4_I]]
+//
+// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) <2 x half> @_Z21test_smoothstep_half2Dv2_DhS_S_(
+// SPVCHECK-SAME: <2 x half> noundef nofpclass(nan inf) [[MIN:%.*]], <2 x half> noundef nofpclass(nan inf) [[MAX:%.*]], <2 x half> noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: [[SPV_SMOOTHSTEP_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef <2 x half> @llvm.spv.smoothstep.v2f16(<2 x half> [[MIN]], <2 x half> [[MAX]], <2 x half> [[X]])
+// SPVCHECK-NEXT: ret <2 x half> [[SPV_SMOOTHSTEP_I]]
+//
+half2 test_smoothstep_half2(half2 Min, half2 Max, half2 X) { return smoothstep(Min, Max, X); }
+
+// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x half> @_Z21test_smoothstep_half3Dv3_DhS_S_(
+// CHECK-SAME: <3 x half> noundef nofpclass(nan inf) [[MIN:%.*]], <3 x half> noundef nofpclass(nan inf) [[MAX:%.*]], <3 x half> noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <3 x half> [[X]], [[MIN]]
+// CHECK-NEXT: [[SUB1_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <3 x half> [[MAX]], [[MIN]]
+// CHECK-NEXT: [[DIV_I:%.*]] = fdiv reassoc nnan ninf nsz arcp afn <3 x half> [[SUB_I]], [[SUB1_I]]
+// CHECK-NEXT: [[HLSL_SATURATE_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn <3 x half> @llvm.dx.saturate.v3f16(<3 x half> [[DIV_I]])
+// CHECK-NEXT: [[MUL_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn <3 x half> [[HLSL_SATURATE_I]], splat (half 0xH4000)
+// CHECK-NEXT: [[SUB2_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <3 x half> splat (half 0xH4200), [[MUL_I]]
+// CHECK-NEXT: [[TMP0:%.*]] = fmul reassoc nnan ninf nsz arcp afn <3 x half> [[HLSL_SATURATE_I]], [[HLSL_SATURATE_I]]
+// CHECK-NEXT: [[MUL4_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn <3 x half> [[TMP0]], [[SUB2_I]]
+// CHECK-NEXT: ret <3 x half> [[MUL4_I]]
+//
+// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) <3 x half> @_Z21test_smoothstep_half3Dv3_DhS_S_(
+// SPVCHECK-SAME: <3 x half> noundef nofpclass(nan inf) [[MIN:%.*]], <3 x half> noundef nofpclass(nan inf) [[MAX:%.*]], <3 x half> noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: [[SPV_SMOOTHSTEP_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef <3 x half> @llvm.spv.smoothstep.v3f16(<3 x half> [[MIN]], <3 x half> [[MAX]], <3 x half> [[X]])
+// SPVCHECK-NEXT: ret <3 x half> [[SPV_SMOOTHSTEP_I]]
+//
+half3 test_smoothstep_half3(half3 Min, half3 Max, half3 X) { return smoothstep(Min, Max, X); }
+
+// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x half> @_Z21test_smoothstep_half4Dv4_DhS_S_(
+// CHECK-SAME: <4 x half> noundef nofpclass(nan inf) [[MIN:%.*]], <4 x half> noundef nofpclass(nan inf) [[MAX:%.*]], <4 x half> noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <4 x half> [[X]], [[MIN]]
+// CHECK-NEXT: [[SUB1_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <4 x half> [[MAX]], [[MIN]]
+// CHECK-NEXT: [[DIV_I:%.*]] = fdiv reassoc nnan ninf nsz arcp afn <4 x half> [[SUB_I]], [[SUB1_I]]
+// CHECK-NEXT: [[HLSL_SATURATE_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn <4 x half> @llvm.dx.saturate.v4f16(<4 x half> [[DIV_I]])
+// CHECK-NEXT: [[MUL_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn <4 x half> [[HLSL_SATURATE_I]], splat (half 0xH4000)
+// CHECK-NEXT: [[SUB2_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <4 x half> splat (half 0xH4200), [[MUL_I]]
+// CHECK-NEXT: [[TMP0:%.*]] = fmul reassoc nnan ninf nsz arcp afn <4 x half> [[HLSL_SATURATE_I]], [[HLSL_SATURATE_I]]
+// CHECK-NEXT: [[MUL4_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn <4 x half> [[TMP0]], [[SUB2_I]]
+// CHECK-NEXT: ret <4 x half> [[MUL4_I]]
+//
+// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) <4 x half> @_Z21test_smoothstep_half4Dv4_DhS_S_(
+// SPVCHECK-SAME: <4 x half> noundef nofpclass(nan inf) [[MIN:%.*]], <4 x half> noundef nofpclass(nan inf) [[MAX:%.*]], <4 x half> noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: [[SPV_SMOOTHSTEP_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef <4 x half> @llvm.spv.smoothstep.v4f16(<4 x half> [[MIN]], <4 x half> [[MAX]], <4 x half> [[X]])
+// SPVCHECK-NEXT: ret <4 x half> [[SPV_SMOOTHSTEP_I]]
+//
+half4 test_smoothstep_half4(half4 Min, half4 Max, half4 X) { return smoothstep(Min, Max, X); }
+
+// CHECK-LABEL: define noundef nofpclass(nan inf) float @_Z21test_smoothstep_floatfff(
+// CHECK-SAME: float noundef nofpclass(nan inf) [[MIN:%.*]], float noundef nofpclass(nan inf) [[MAX:%.*]], float noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn float [[X]], [[MIN]]
+// CHECK-NEXT: [[SUB1_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn float [[MAX]], [[MIN]]
+// CHECK-NEXT: [[DIV_I:%.*]] = fdiv reassoc nnan ninf nsz arcp afn float [[SUB_I]], [[SUB1_I]]
+// CHECK-NEXT: [[HLSL_SATURATE_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn float @llvm.dx.saturate.f32(float [[DIV_I]])
+// CHECK-NEXT: [[MUL_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn float [[HLSL_SATURATE_I]], 2.000000e+00
+// CHECK-NEXT: [[SUB2_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn float 3.000000e+00, [[MUL_I]]
+// CHECK-NEXT: [[TMP0:%.*]] = fmul reassoc nnan ninf nsz arcp afn float [[HLSL_SATURATE_I]], [[HLSL_SATURATE_I]]
+// CHECK-NEXT: [[MUL4_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn float [[TMP0]], [[SUB2_I]]
+// CHECK-NEXT: ret float [[MUL4_I]]
+//
+// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) float @_Z21test_smoothstep_floatfff(
+// SPVCHECK-SAME: float noundef nofpclass(nan inf) [[MIN:%.*]], float noundef nofpclass(nan inf) [[MAX:%.*]], float noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: [[CONV_I:%.*]] = fpext reassoc nnan ninf nsz arcp afn float [[MIN]] to double
+// SPVCHECK-NEXT: [[CONV1_I:%.*]] = fpext reassoc nnan ninf nsz arcp afn float [[MAX]] to double
+// SPVCHECK-NEXT: [[CONV2_I:%.*]] = fpext reassoc nnan ninf nsz arcp afn float [[X]] to double
+// SPVCHECK-NEXT: [[SPV_SMOOTHSTEP_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn double @llvm.spv.smoothstep.f64(double [[CONV_I]], double [[CONV1_I]], double [[CONV2_I]])
+// SPVCHECK-NEXT: [[CONV3_I:%.*]] = fptrunc reassoc nnan ninf nsz arcp afn double [[SPV_SMOOTHSTEP_I]] to float
+// SPVCHECK-NEXT: ret float [[CONV3_I]]
+//
+float test_smoothstep_float(float Min, float Max, float X) { return smoothstep(Min, Max, X); }
+
+// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> @_Z22test_smoothstep_float2Dv2_fS_S_(
+// CHECK-SAME: <2 x float> noundef nofpclass(nan inf) [[MIN:%.*]], <2 x float> noundef nofpclass(nan inf) [[MAX:%.*]], <2 x float> noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <2 x float> [[X]], [[MIN]]
+// CHECK-NEXT: [[SUB1_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <2 x float> [[MAX]], [[MIN]]
+// CHECK-NEXT: [[DIV_I:%.*]] = fdiv reassoc nnan ninf nsz arcp afn <2 x float> [[SUB_I]], [[SUB1_I]]
+// CHECK-NEXT: [[HLSL_SATURATE_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.dx.saturate.v2f32(<2 x float> [[DIV_I]])
+// CHECK-NEXT: [[MUL_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn <2 x float> [[HLSL_SATURATE_I]], splat (float 2.000000e+00)
+// CHECK-NEXT: [[SUB2_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <2 x float> splat (float 3.000000e+00), [[MUL_I]]
+// CHECK-NEXT: [[TMP0:%.*]] = fmul reassoc nnan ninf nsz arcp afn <2 x float> [[HLSL_SATURATE_I]], [[HLSL_SATURATE_I]]
+// CHECK-NEXT: [[MUL4_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn <2 x float> [[TMP0]], [[SUB2_I]]
+// CHECK-NEXT: ret <2 x float> [[MUL4_I]]
+//
+// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) <2 x float> @_Z22test_smoothstep_float2Dv2_fS_S_(
+// SPVCHECK-SAME: <2 x float> noundef nofpclass(nan inf) [[MIN:%.*]], <2 x float> noundef nofpclass(nan inf) [[MAX:%.*]], <2 x float> noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: [[SPV_SMOOTHSTEP_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef <2 x float> @llvm.spv.smoothstep.v2f32(<2 x float> [[MIN]], <2 x float> [[MAX]], <2 x float> [[X]])
+// SPVCHECK-NEXT: ret <2 x float> [[SPV_SMOOTHSTEP_I]]
+//
+float2 test_smoothstep_float2(float2 Min, float2 Max, float2 X) { return smoothstep(Min, Max, X); }
+
+// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> @_Z22test_smoothstep_float3Dv3_fS_S_(
+// CHECK-SAME: <3 x float> noundef nofpclass(nan inf) [[MIN:%.*]], <3 x float> noundef nofpclass(nan inf) [[MAX:%.*]], <3 x float> noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr ...
[truncated]
|
c8f6bf5
to
ac7c175
Compare
✅ With the latest revision this PR passed the undef deprecator. |
53d55ef
to
c8f6bf5
Compare
… to int_spv_smoothstep, create SPIR-V backend test cases
…lt-in, added codegen and sema checks/tests
… spirv double test
ff214b4
to
9a8739e
Compare
} | ||
|
||
template <typename T> | ||
const inline __detail::enable_if_t< |
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.
the clang format seems very different than the half case. See if you can get these to look a little closer.
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.
I'm not sure how to do this when clang-format is an automatic process. The other intrinsics are also formatted the same way as mine.
QualType ArgTyA = A.get()->getType(); | ||
if (!ArgTyA->hasFloatingRepresentation()) { | ||
SemaRef.Diag(A.get()->getBeginLoc(), | ||
diag::err_typecheck_convert_incompatible) |
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.
we are in the process of removing out usages of err_typecheck_convert_incompatible
because it forces an assumption on our part of what the expected type is, in this case SemaRef.Context.FloatTy
. Look into err_builtin_invalid_arg_type
instead. It should give us the option to tell the user that this api supports vector floats and and half types.
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.
Don't we also want to say the api supports matrices though? I don't think I can do that with err_builtin_invalid_arg_type
unless I edit DiagnosticSemaKinds.td
—the closest I can get is this message:
1st argument must be a scalar or vector of floating-point types (was 'int')
return true; | ||
|
||
// check if the all arguments have floating representation | ||
ExprResult A = TheCall->getArg(0); |
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.
it might be worth looping over the args and checking hasFloatingRepresentation
for each arg to determing which diag to emit. Feel free to write a helper if you need it.
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.
I'm already checking hasFloatingRepresentation
for all of the args and emitting the corresponding diag. Do you want me to move the individual checks into a for loop?
Closes #99156.
Tasks completed:
smoothstep
using HLSL source inhlsl_intrinsics.h
smoothstep
SPIR-V target built-in inclang/include/clang/Basic/BuiltinsSPIRV.td
smoothstep
toCheckSPIRVBuiltinFunctionCall
inclang/lib/Sema/SemaSPIRV.cpp
smoothstep
toEmitSPIRVBuiltinExpr
inclang/lib/CodeGen/TargetBuiltins/SPIR.cpp
clang/test/CodeGenHLSL/builtins/smoothstep.hlsl
clang/test/CodeGenSPIRV/Builtins/smoothstep.c
clang/test/SemaHLSL/BuiltIns/smoothstep-errors.hlsl
clang/test/SemaSPIRV/BuiltIns/smoothstep-errors.c
int_spv_smoothstep
intrinsic inIntrinsicsSPIRV.td
smoothstep
lowering and map it toint_spv_smoothstep
inSPIRVInstructionSelector::selectIntrinsic
llvm/test/CodeGen/SPIRV/hlsl-intrinsics/smoothstep.ll
llvm/test/CodeGen/SPIRV/opencl/smoothstep.ll