https://github.com/kmpeng updated https://github.com/llvm/llvm-project/pull/132288
>From 7853b27b8fffa6d2c0393a4004abaac9a7954608 Mon Sep 17 00:00:00 2001 From: kmpeng <kaitlinp...@microsoft.com> Date: Tue, 18 Mar 2025 13:25:10 -0700 Subject: [PATCH 01/10] create int_spv_smoothstep intrinsic, create smoothstep lowering & map to int_spv_smoothstep, create SPIR-V backend test cases --- llvm/include/llvm/IR/IntrinsicsSPIRV.td | 1 + .../Target/SPIRV/SPIRVInstructionSelector.cpp | 2 + .../SPIRV/hlsl-intrinsics/smoothstep.ll | 60 ++++++++++++++++++ llvm/test/CodeGen/SPIRV/opencl/smoothstep.ll | 61 +++++++++++++++++++ 4 files changed, 124 insertions(+) create mode 100644 llvm/test/CodeGen/SPIRV/hlsl-intrinsics/smoothstep.ll create mode 100644 llvm/test/CodeGen/SPIRV/opencl/smoothstep.ll diff --git a/llvm/include/llvm/IR/IntrinsicsSPIRV.td b/llvm/include/llvm/IR/IntrinsicsSPIRV.td index 4a0e10db2f1e4..7760961de7b6c 100644 --- a/llvm/include/llvm/IR/IntrinsicsSPIRV.td +++ b/llvm/include/llvm/IR/IntrinsicsSPIRV.td @@ -75,6 +75,7 @@ let TargetPrefix = "spv" in { def int_spv_reflect : DefaultAttrsIntrinsic<[LLVMMatchType<0>], [llvm_anyfloat_ty, LLVMMatchType<0>], [IntrNoMem]>; def int_spv_rsqrt : DefaultAttrsIntrinsic<[LLVMMatchType<0>], [llvm_anyfloat_ty], [IntrNoMem]>; def int_spv_saturate : DefaultAttrsIntrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>], [IntrNoMem]>; + def int_spv_smoothstep : DefaultAttrsIntrinsic<[LLVMMatchType<0>], [llvm_anyfloat_ty, LLVMMatchType<0>, LLVMMatchType<0>], [IntrNoMem]>; def int_spv_step : DefaultAttrsIntrinsic<[LLVMMatchType<0>], [LLVMMatchType<0>, llvm_anyfloat_ty], [IntrNoMem]>; def int_spv_fdot : DefaultAttrsIntrinsic<[LLVMVectorElementType<0>], diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp index bd54590c87cac..1ba022b416808 100644 --- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp @@ -3121,6 +3121,8 @@ bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg, return selectExtInst(ResVReg, ResType, I, CL::rsqrt, GL::InverseSqrt); case Intrinsic::spv_sign: return selectSign(ResVReg, ResType, I); + case Intrinsic::spv_smoothstep: + return selectExtInst(ResVReg, ResType, I, CL::smoothstep, GL::SmoothStep); case Intrinsic::spv_firstbituhigh: // There is no CL equivalent of FindUMsb return selectFirstBitHigh(ResVReg, ResType, I, /*IsSigned=*/false); case Intrinsic::spv_firstbitshigh: // There is no CL equivalent of FindSMsb diff --git a/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/smoothstep.ll b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/smoothstep.ll new file mode 100644 index 0000000000000..09f93ab7955d3 --- /dev/null +++ b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/smoothstep.ll @@ -0,0 +1,60 @@ +; RUN: llc -O0 -verify-machineinstrs -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s +; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %} + +; Make sure SPIRV operation function calls for smoothstep are lowered correctly. + +; CHECK-DAG: %[[#op_ext_glsl:]] = OpExtInstImport "GLSL.std.450" +; CHECK-DAG: %[[#float_16:]] = OpTypeFloat 16 +; CHECK-DAG: %[[#vec4_float_16:]] = OpTypeVector %[[#float_16]] 4 +; CHECK-DAG: %[[#float_32:]] = OpTypeFloat 32 +; CHECK-DAG: %[[#vec4_float_32:]] = OpTypeVector %[[#float_32]] 4 + +define noundef half @smoothstep_half(half noundef %a, half noundef %b, half noundef %c) { +entry: + ; CHECK: %[[#]] = OpFunction %[[#float_16]] None %[[#]] + ; CHECK: %[[#arg0:]] = OpFunctionParameter %[[#float_16]] + ; CHECK: %[[#arg1:]] = OpFunctionParameter %[[#float_16]] + ; CHECK: %[[#arg2:]] = OpFunctionParameter %[[#float_16]] + ; CHECK: %[[#]] = OpExtInst %[[#float_16]] %[[#op_ext_glsl]] SmoothStep %[[#arg0]] %[[#arg1]] %[[#arg2]] + %spv.smoothstep = call half @llvm.spv.smoothstep.f16(half %a, half %b, half %c) + ret half %spv.smoothstep +} + +define noundef float @smoothstep_float(float noundef %a, float noundef %b, float noundef %c) { +entry: + ; CHECK: %[[#]] = OpFunction %[[#float_32]] None %[[#]] + ; CHECK: %[[#arg0:]] = OpFunctionParameter %[[#float_32]] + ; CHECK: %[[#arg1:]] = OpFunctionParameter %[[#float_32]] + ; CHECK: %[[#arg2:]] = OpFunctionParameter %[[#float_32]] + ; CHECK: %[[#]] = OpExtInst %[[#float_32]] %[[#op_ext_glsl]] SmoothStep %[[#arg0]] %[[#arg1]] %[[#arg2]] + %spv.smoothstep = call float @llvm.spv.smoothstep.f32(float %a, float %b, float %c) + ret float %spv.smoothstep +} + +define noundef <4 x half> @smoothstep_half4(<4 x half> noundef %a, <4 x half> noundef %b, <4 x half> noundef %c) { +entry: + ; CHECK: %[[#]] = OpFunction %[[#vec4_float_16]] None %[[#]] + ; CHECK: %[[#arg0:]] = OpFunctionParameter %[[#vec4_float_16]] + ; CHECK: %[[#arg1:]] = OpFunctionParameter %[[#vec4_float_16]] + ; CHECK: %[[#arg2:]] = OpFunctionParameter %[[#vec4_float_16]] + ; CHECK: %[[#]] = OpExtInst %[[#vec4_float_16]] %[[#op_ext_glsl]] SmoothStep %[[#arg0]] %[[#arg1]] %[[#arg2]] + %spv.smoothstep = call <4 x half> @llvm.spv.smoothstep.v4f16(<4 x half> %a, <4 x half> %b, <4 x half> %c) + ret <4 x half> %spv.smoothstep +} + +define noundef <4 x float> @smoothstep_float4(<4 x float> noundef %a, <4 x float> noundef %b, <4 x float> noundef %c) { +entry: + ; CHECK: %[[#]] = OpFunction %[[#vec4_float_32]] None %[[#]] + ; CHECK: %[[#arg0:]] = OpFunctionParameter %[[#vec4_float_32]] + ; CHECK: %[[#arg1:]] = OpFunctionParameter %[[#vec4_float_32]] + ; CHECK: %[[#arg2:]] = OpFunctionParameter %[[#vec4_float_32]] + ; CHECK: %[[#]] = OpExtInst %[[#vec4_float_32]] %[[#op_ext_glsl]] SmoothStep %[[#arg0]] %[[#arg1]] %[[#arg2]] + %spv.smoothstep = call <4 x float> @llvm.spv.smoothstep.v4f32(<4 x float> %a, <4 x float> %b, <4 x float> %c) + ret <4 x float> %spv.smoothstep +} + +declare half @llvm.spv.smoothstep.f16(half, half, half) +declare float @llvm.spv.smoothstep.f32(float, float, float) + +declare <4 x half> @llvm.spv.smoothstep.v4f16(<4 x half>, <4 x half>, <4 x half>) +declare <4 x float> @llvm.spv.smoothstep.v4f32(<4 x float>, <4 x float>, <4 x float>) diff --git a/llvm/test/CodeGen/SPIRV/opencl/smoothstep.ll b/llvm/test/CodeGen/SPIRV/opencl/smoothstep.ll new file mode 100644 index 0000000000000..fe395ace1217b --- /dev/null +++ b/llvm/test/CodeGen/SPIRV/opencl/smoothstep.ll @@ -0,0 +1,61 @@ +; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s +; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s +; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %} +; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown %s -o - -filetype=obj | spirv-val %} + +; CHECK-DAG: %[[#op_ext_cl:]] = OpExtInstImport "OpenCL.std" + +; CHECK-DAG: %[[#float_16:]] = OpTypeFloat 16 +; CHECK-DAG: %[[#vec4_float_16:]] = OpTypeVector %[[#float_16]] 4 +; CHECK-DAG: %[[#float_32:]] = OpTypeFloat 32 +; CHECK-DAG: %[[#vec4_float_32:]] = OpTypeVector %[[#float_32]] 4 + +define noundef half @smoothstep_half(half noundef %a, half noundef %b, half noundef %c) { +entry: + ; CHECK: %[[#]] = OpFunction %[[#float_16]] None %[[#]] + ; CHECK: %[[#arg0:]] = OpFunctionParameter %[[#float_16]] + ; CHECK: %[[#arg1:]] = OpFunctionParameter %[[#float_16]] + ; CHECK: %[[#arg2:]] = OpFunctionParameter %[[#float_16]] + ; CHECK: %[[#]] = OpExtInst %[[#float_16]] %[[#op_ext_cl]] smoothstep %[[#arg0]] %[[#arg1]] %[[#arg2]] + %spv.smoothstep = call half @llvm.spv.smoothstep.f16(half %a, half %b, half %c) + ret half %spv.smoothstep +} + +define noundef float @smoothstep_float(float noundef %a, float noundef %b, float noundef %c) { +entry: + ; CHECK: %[[#]] = OpFunction %[[#float_32]] None %[[#]] + ; CHECK: %[[#arg0:]] = OpFunctionParameter %[[#float_32]] + ; CHECK: %[[#arg1:]] = OpFunctionParameter %[[#float_32]] + ; CHECK: %[[#arg2:]] = OpFunctionParameter %[[#float_32]] + ; CHECK: %[[#]] = OpExtInst %[[#float_32]] %[[#op_ext_cl]] smoothstep %[[#arg0]] %[[#arg1]] %[[#arg2]] + %spv.smoothstep = call float @llvm.spv.smoothstep.f32(float %a, float %b, float %c) + ret float %spv.smoothstep +} + +define noundef <4 x half> @smoothstep_half4(<4 x half> noundef %a, <4 x half> noundef %b, <4 x half> noundef %c) { +entry: + ; CHECK: %[[#]] = OpFunction %[[#vec4_float_16]] None %[[#]] + ; CHECK: %[[#arg0:]] = OpFunctionParameter %[[#vec4_float_16]] + ; CHECK: %[[#arg1:]] = OpFunctionParameter %[[#vec4_float_16]] + ; CHECK: %[[#arg2:]] = OpFunctionParameter %[[#vec4_float_16]] + ; CHECK: %[[#]] = OpExtInst %[[#vec4_float_16]] %[[#op_ext_cl]] smoothstep %[[#arg0]] %[[#arg1]] %[[#arg2]] + %spv.smoothstep = call <4 x half> @llvm.spv.smoothstep.v4f16(<4 x half> %a, <4 x half> %b, <4 x half> %c) + ret <4 x half> %spv.smoothstep +} + +define noundef <4 x float> @smoothstep_float4(<4 x float> noundef %a, <4 x float> noundef %b, <4 x float> noundef %c) { +entry: + ; CHECK: %[[#]] = OpFunction %[[#vec4_float_32]] None %[[#]] + ; CHECK: %[[#arg0:]] = OpFunctionParameter %[[#vec4_float_32]] + ; CHECK: %[[#arg1:]] = OpFunctionParameter %[[#vec4_float_32]] + ; CHECK: %[[#arg2:]] = OpFunctionParameter %[[#vec4_float_32]] + ; CHECK: %[[#]] = OpExtInst %[[#vec4_float_32]] %[[#op_ext_cl]] smoothstep %[[#arg0]] %[[#arg1]] %[[#arg2]] + %spv.smoothstep = call <4 x float> @llvm.spv.smoothstep.v4f32(<4 x float> %a, <4 x float> %b, <4 x float> %c) + ret <4 x float> %spv.smoothstep +} + +declare half @llvm.spv.smoothstep.f16(half, half, half) +declare float @llvm.spv.smoothstep.f32(float, float, float) + +declare <4 x half> @llvm.spv.smoothstep.v4f16(<4 x half>, <4 x half>, <4 x half>) +declare <4 x float> @llvm.spv.smoothstep.v4f32(<4 x float>, <4 x float>, <4 x float>) >From 978a47a570da6250ef315b3b07540f3c730d8602 Mon Sep 17 00:00:00 2001 From: kmpeng <kaitlinp...@microsoft.com> Date: Wed, 19 Mar 2025 14:27:40 -0700 Subject: [PATCH 02/10] implemented smoothstep in hlsl.Intrinsics.h and its spir-v target built-in, added codegen and sema checks/tests --- clang/include/clang/Basic/BuiltinsSPIRV.td | 6 + clang/lib/CodeGen/TargetBuiltins/SPIR.cpp | 16 ++ .../lib/Headers/hlsl/hlsl_intrinsic_helpers.h | 16 ++ clang/lib/Headers/hlsl/hlsl_intrinsics.h | 46 +++++ clang/lib/Sema/SemaSPIRV.cpp | 44 ++++ .../test/CodeGenHLSL/builtins/smoothstep.hlsl | 189 ++++++++++++++++++ clang/test/CodeGenSPIRV/Builtins/smoothstep.c | 32 +++ .../SemaHLSL/BuiltIns/smoothstep-errors.hlsl | 66 ++++++ .../SemaSPIRV/BuiltIns/smoothstep-errors.c | 28 +++ 9 files changed, 443 insertions(+) create mode 100644 clang/test/CodeGenHLSL/builtins/smoothstep.hlsl create mode 100644 clang/test/CodeGenSPIRV/Builtins/smoothstep.c create mode 100644 clang/test/SemaHLSL/BuiltIns/smoothstep-errors.hlsl create mode 100644 clang/test/SemaSPIRV/BuiltIns/smoothstep-errors.c 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/TargetBuiltins/SPIR.cpp b/clang/lib/CodeGen/TargetBuiltins/SPIR.cpp index 844e7c8ad5d4f..d6a5ef2cabd45 100644 --- a/clang/lib/CodeGen/TargetBuiltins/SPIR.cpp +++ b/clang/lib/CodeGen/TargetBuiltins/SPIR.cpp @@ -61,6 +61,22 @@ 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()->isVectorType() && + E->getArg(1)->getType()->isVectorType() && + E->getArg(2)->getType()->isVectorType() && + "SmoothStep operands must be a 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..e35575a607574 100644 --- a/clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h +++ b/clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h @@ -81,6 +81,22 @@ 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) { + T t = saturate((X - Min) / (Max - Min)); + return (3 - 2 * t) * t * t; +} + +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 + // undefined? + vector<T, N> t = saturate((X - Min) / (Max - Min)); + return (3 - 2 * t) * t * t; +#endif +} + } // namespace __detail } // namespace hlsl diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h index 2a9cf554b7420..0a18dd9fa566c 100644 --- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h +++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h @@ -322,5 +322,51 @@ 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. Result is undefined if Min ≥ Max. + +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..ebda4f359edbd 100644 --- a/clang/lib/Sema/SemaSPIRV.cpp +++ b/clang/lib/Sema/SemaSPIRV.cpp @@ -101,6 +101,50 @@ 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 (VTyA == nullptr) { + SemaRef.Diag(A.get()->getBeginLoc(), + diag::err_typecheck_convert_incompatible) + << ArgTyA + << SemaRef.Context.getVectorType(ArgTyA, 2, VectorKind::Generic) << 1 + << 0 << 0; + return true; + } + + ExprResult B = TheCall->getArg(1); + QualType ArgTyB = B.get()->getType(); + auto *VTyB = ArgTyB->getAs<VectorType>(); + if (VTyB == nullptr) { + SemaRef.Diag(A.get()->getBeginLoc(), + diag::err_typecheck_convert_incompatible) + << ArgTyB + << SemaRef.Context.getVectorType(ArgTyB, 2, VectorKind::Generic) << 1 + << 0 << 0; + return true; + } + + ExprResult C = TheCall->getArg(2); + QualType ArgTyC = C.get()->getType(); + auto *VTyC = ArgTyC->getAs<VectorType>(); + if (VTyC == nullptr) { + SemaRef.Diag(A.get()->getBeginLoc(), + diag::err_typecheck_convert_incompatible) + << ArgTyB + << SemaRef.Context.getVectorType(ArgTyC, 2, VectorKind::Generic) << 1 + << 0 << 0; + 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..3ac872b4452b2 --- /dev/null +++ b/clang/test/CodeGenHLSL/builtins/smoothstep.hlsl @@ -0,0 +1,189 @@ +// 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: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn half [[X]], [[MIN]] +// SPVCHECK-NEXT: [[SUB1_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn half [[MAX]], [[MIN]] +// SPVCHECK-NEXT: [[DIV_I:%.*]] = fdiv reassoc nnan ninf nsz arcp afn half [[SUB_I]], [[SUB1_I]] +// SPVCHECK-NEXT: [[HLSL_SATURATE_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn half @llvm.spv.saturate.f16(half [[DIV_I]]) +// SPVCHECK-NEXT: [[MUL_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn half [[HLSL_SATURATE_I]], 0xH4000 +// SPVCHECK-NEXT: [[SUB2_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn half 0xH4200, [[MUL_I]] +// SPVCHECK-NEXT: [[TMP0:%.*]] = fmul reassoc nnan ninf nsz arcp afn half [[HLSL_SATURATE_I]], [[HLSL_SATURATE_I]] +// SPVCHECK-NEXT: [[MUL4_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn half [[TMP0]], [[SUB2_I]] +// SPVCHECK-NEXT: ret half [[MUL4_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: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn float [[X]], [[MIN]] +// SPVCHECK-NEXT: [[SUB1_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn float [[MAX]], [[MIN]] +// SPVCHECK-NEXT: [[DIV_I:%.*]] = fdiv reassoc nnan ninf nsz arcp afn float [[SUB_I]], [[SUB1_I]] +// SPVCHECK-NEXT: [[HLSL_SATURATE_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn float @llvm.spv.saturate.f32(float [[DIV_I]]) +// SPVCHECK-NEXT: [[MUL_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn float [[HLSL_SATURATE_I]], 2.000000e+00 +// SPVCHECK-NEXT: [[SUB2_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn float 3.000000e+00, [[MUL_I]] +// SPVCHECK-NEXT: [[TMP0:%.*]] = fmul reassoc nnan ninf nsz arcp afn float [[HLSL_SATURATE_I]], [[HLSL_SATURATE_I]] +// SPVCHECK-NEXT: [[MUL4_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn float [[TMP0]], [[SUB2_I]] +// SPVCHECK-NEXT: ret float [[MUL4_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 #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <3 x float> [[X]], [[MIN]] +// CHECK-NEXT: [[SUB1_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <3 x float> [[MAX]], [[MIN]] +// CHECK-NEXT: [[DIV_I:%.*]] = fdiv reassoc nnan ninf nsz arcp afn <3 x float> [[SUB_I]], [[SUB1_I]] +// CHECK-NEXT: [[HLSL_SATURATE_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.dx.saturate.v3f32(<3 x float> [[DIV_I]]) +// CHECK-NEXT: [[MUL_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn <3 x float> [[HLSL_SATURATE_I]], splat (float 2.000000e+00) +// CHECK-NEXT: [[SUB2_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <3 x float> splat (float 3.000000e+00), [[MUL_I]] +// CHECK-NEXT: [[TMP0:%.*]] = fmul reassoc nnan ninf nsz arcp afn <3 x float> [[HLSL_SATURATE_I]], [[HLSL_SATURATE_I]] +// CHECK-NEXT: [[MUL4_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn <3 x float> [[TMP0]], [[SUB2_I]] +// CHECK-NEXT: ret <3 x float> [[MUL4_I]] +// +// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) <3 x float> @_Z22test_smoothstep_float3Dv3_fS_S_( +// SPVCHECK-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 #[[ATTR0]] { +// SPVCHECK-NEXT: [[ENTRY:.*:]] +// SPVCHECK-NEXT: [[SPV_SMOOTHSTEP_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef <3 x float> @llvm.spv.smoothstep.v3f32(<3 x float> [[MIN]], <3 x float> [[MAX]], <3 x float> [[X]]) +// SPVCHECK-NEXT: ret <3 x float> [[SPV_SMOOTHSTEP_I]] +// +float3 test_smoothstep_float3(float3 Min, float3 Max, float3 X) { return smoothstep(Min, Max, X); } + +// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> @_Z22test_smoothstep_float4Dv4_fS_S_( +// CHECK-SAME: <4 x float> noundef nofpclass(nan inf) [[MIN:%.*]], <4 x float> noundef nofpclass(nan inf) [[MAX:%.*]], <4 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 <4 x float> [[X]], [[MIN]] +// CHECK-NEXT: [[SUB1_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <4 x float> [[MAX]], [[MIN]] +// CHECK-NEXT: [[DIV_I:%.*]] = fdiv reassoc nnan ninf nsz arcp afn <4 x float> [[SUB_I]], [[SUB1_I]] +// CHECK-NEXT: [[HLSL_SATURATE_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.dx.saturate.v4f32(<4 x float> [[DIV_I]]) +// CHECK-NEXT: [[MUL_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn <4 x float> [[HLSL_SATURATE_I]], splat (float 2.000000e+00) +// CHECK-NEXT: [[SUB2_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <4 x float> splat (float 3.000000e+00), [[MUL_I]] +// CHECK-NEXT: [[TMP0:%.*]] = fmul reassoc nnan ninf nsz arcp afn <4 x float> [[HLSL_SATURATE_I]], [[HLSL_SATURATE_I]] +// CHECK-NEXT: [[MUL4_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn <4 x float> [[TMP0]], [[SUB2_I]] +// CHECK-NEXT: ret <4 x float> [[MUL4_I]] +// +// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) <4 x float> @_Z22test_smoothstep_float4Dv4_fS_S_( +// SPVCHECK-SAME: <4 x float> noundef nofpclass(nan inf) [[MIN:%.*]], <4 x float> noundef nofpclass(nan inf) [[MAX:%.*]], <4 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 <4 x float> @llvm.spv.smoothstep.v4f32(<4 x float> [[MIN]], <4 x float> [[MAX]], <4 x float> [[X]]) +// SPVCHECK-NEXT: ret <4 x float> [[SPV_SMOOTHSTEP_I]] +// +float4 test_smoothstep_float4(float4 Min, float4 Max, float4 X) { return smoothstep(Min, Max, X); } diff --git a/clang/test/CodeGenSPIRV/Builtins/smoothstep.c b/clang/test/CodeGenSPIRV/Builtins/smoothstep.c new file mode 100644 index 0000000000000..b90d51a74b5c6 --- /dev/null +++ b/clang/test/CodeGenSPIRV/Builtins/smoothstep.c @@ -0,0 +1,32 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5 + +// RUN: %clang_cc1 -O1 -triple spirv-pc-vulkan-compute %s -emit-llvm -o - | FileCheck %s + +typedef float float2 __attribute__((ext_vector_type(2))); +typedef float float3 __attribute__((ext_vector_type(3))); +typedef float float4 __attribute__((ext_vector_type(4))); + +// CHECK-LABEL: define spir_func <2 x float> @test_smoothstep_float2( +// CHECK-SAME: <2 x float> noundef [[MIN:%.*]], <2 x float> noundef [[MAX:%.*]], <2 x float> noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[SPV_SMOOTHSTEP:%.*]] = tail call <2 x float> @llvm.spv.smoothstep.v2f32(<2 x float> [[MIN]], <2 x float> [[MAX]], <2 x float> [[X]]) +// CHECK-NEXT: ret <2 x float> [[SPV_SMOOTHSTEP]] +// +float2 test_smoothstep_float2(float2 Min, float2 Max, float2 X) { return __builtin_spirv_smoothstep(Min, Max, X); } + +// CHECK-LABEL: define spir_func <3 x float> @test_smoothstep_float3( +// CHECK-SAME: <3 x float> noundef [[MIN:%.*]], <3 x float> noundef [[MAX:%.*]], <3 x float> noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[SPV_SMOOTHSTEP:%.*]] = tail call <3 x float> @llvm.spv.smoothstep.v3f32(<3 x float> [[MIN]], <3 x float> [[MAX]], <3 x float> [[X]]) +// CHECK-NEXT: ret <3 x float> [[SPV_SMOOTHSTEP]] +// +float3 test_smoothstep_float3(float3 Min, float3 Max, float3 X) { return __builtin_spirv_smoothstep(Min, Max, X); } + +// CHECK-LABEL: define spir_func <4 x float> @test_smoothstep_float4( +// CHECK-SAME: <4 x float> noundef [[MIN:%.*]], <4 x float> noundef [[MAX:%.*]], <4 x float> noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[SPV_SMOOTHSTEP:%.*]] = tail call <4 x float> @llvm.spv.smoothstep.v4f32(<4 x float> [[MIN]], <4 x float> [[MAX]], <4 x float> [[X]]) +// CHECK-NEXT: ret <4 x float> [[SPV_SMOOTHSTEP]] +// +float4 test_smoothstep_float4(float4 Min, float4 Max, float4 X) { return __builtin_spirv_smoothstep(Min, Max, X); } + diff --git a/clang/test/SemaHLSL/BuiltIns/smoothstep-errors.hlsl b/clang/test/SemaHLSL/BuiltIns/smoothstep-errors.hlsl new file mode 100644 index 0000000000000..e5e902d6ab887 --- /dev/null +++ b/clang/test/SemaHLSL/BuiltIns/smoothstep-errors.hlsl @@ -0,0 +1,66 @@ +// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -fnative-half-type -emit-llvm-only -disable-llvm-passes -verify + +float test_no_second_arg(float2 p0) { + return smoothstep(p0); + // expected-error@-1 {{no matching function for call to 'smoothstep'}} + // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 3 arguments, but 1 was provided}} + // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 3 arguments, but 1 was provided}} + // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 3 arguments, but 1 was provided}} + // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 3 arguments, but 1 was provided}} +} + +float test_no_third_arg(float2 p0) { + return smoothstep(p0, p0); + // expected-error@-1 {{no matching function for call to 'smoothstep'}} + // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 3 arguments, but 2 were provided}} + // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 3 arguments, but 2 were provided}} + // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 3 arguments, but 2 were provided}} + // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 3 arguments, but 2 were provided}} +} + +float test_too_many_arg(float2 p0) { + return smoothstep(p0, p0, p0, p0); + // expected-error@-1 {{no matching function for call to 'smoothstep'}} + // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 3 arguments, but 4 were provided}} + // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 3 arguments, but 4 were provided}} + // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 3 arguments, but 4 were provided}} + // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 3 arguments, but 4 were provided}} +} + +float test_double_inputs(double p0, double p1, double p2) { + return smoothstep(p0, p1, p2); + // expected-error@-1 {{no matching function for call to 'smoothstep'}} + // 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 smoothstep(p0, p1, p2); + // expected-error@-1 {{no matching function for call to 'smoothstep'}} + // 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 smoothstep(p0, p1, p2); + // expected-error@-1 {{no matching function for call to 'smoothstep'}} + // 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 N = 1]: no type named 'Type' in 'hlsl::__detail::enable_if<false, half>'}} + // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored: substitution failure [with N = 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 smoothstep(p0, p1, p2); + // expected-error@-1 {{no matching function for call to 'smoothstep'}} + // 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 N = 5]: no type named 'Type' in 'hlsl::__detail::enable_if<false, half>'}} + // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored: substitution failure [with N = 5]: no type named 'Type' in 'hlsl::__detail::enable_if<false, float>'}} +} diff --git a/clang/test/SemaSPIRV/BuiltIns/smoothstep-errors.c b/clang/test/SemaSPIRV/BuiltIns/smoothstep-errors.c new file mode 100644 index 0000000000000..ffa9d30012213 --- /dev/null +++ b/clang/test/SemaSPIRV/BuiltIns/smoothstep-errors.c @@ -0,0 +1,28 @@ +// RUN: %clang_cc1 %s -triple spirv-pc-vulkan-compute -verify + +typedef float float2 __attribute__((ext_vector_type(2))); + +float2 test_no_second_arg(float2 p0) { + return __builtin_spirv_smoothstep(p0); + // expected-error@-1 {{too few arguments to function call, expected 3, have 1}} +} + +float2 test_no_third_arg(float2 p0) { + return __builtin_spirv_smoothstep(p0, p0); + // expected-error@-1 {{too few arguments to function call, expected 3, have 2}} +} + +float2 test_too_many_arg(float2 p0) { + return __builtin_spirv_smoothstep(p0, p0, p0, p0); + // expected-error@-1 {{too many arguments to function call, expected 3, have 4}} +} + +float test_double_scalar_inputs(double p0, double p1, double p2) { + return __builtin_spirv_smoothstep(p0, p1, p2); + // expected-error@-1 {{passing 'double' to parameter of incompatible type '__attribute__((__vector_size__(2 * sizeof(double)))) double' (vector of 2 'double' values)}} +} + +float test_int_scalar_inputs(int p0, int p1, int p2) { + return __builtin_spirv_smoothstep(p0, p1, p2); + // expected-error@-1 {{passing 'int' to parameter of incompatible type '__attribute__((__vector_size__(2 * sizeof(int)))) int' (vector of 2 'int' values)}} +} >From a19eb3e535f70a8d6cde329aecc356dd38320044 Mon Sep 17 00:00:00 2001 From: kmpeng <kaitlinp...@microsoft.com> Date: Thu, 20 Mar 2025 12:50:50 -0700 Subject: [PATCH 03/10] added spirv scalar implementation, updated codegen and sema tests --- clang/lib/CodeGen/TargetBuiltins/SPIR.cpp | 11 ++++--- .../lib/Headers/hlsl/hlsl_intrinsic_helpers.h | 16 ++++++---- clang/lib/Headers/hlsl/hlsl_intrinsics.h | 12 ++++---- clang/lib/Sema/SemaSPIRV.cpp | 23 +++++++------- .../test/CodeGenHLSL/builtins/smoothstep.hlsl | 30 ++++++++----------- clang/test/CodeGenSPIRV/Builtins/smoothstep.c | 14 ++++++++- 6 files changed, 59 insertions(+), 47 deletions(-) diff --git a/clang/lib/CodeGen/TargetBuiltins/SPIR.cpp b/clang/lib/CodeGen/TargetBuiltins/SPIR.cpp index d6a5ef2cabd45..bd8f1c6d6cdb9 100644 --- a/clang/lib/CodeGen/TargetBuiltins/SPIR.cpp +++ b/clang/lib/CodeGen/TargetBuiltins/SPIR.cpp @@ -69,10 +69,13 @@ Value *CodeGenFunction::EmitSPIRVBuiltinExpr(unsigned BuiltinID, E->getArg(1)->getType()->hasFloatingRepresentation() && E->getArg(2)->getType()->hasFloatingRepresentation() && "SmoothStep operands must have a float representation"); - assert(E->getArg(0)->getType()->isVectorType() && - E->getArg(1)->getType()->isVectorType() && - E->getArg(2)->getType()->isVectorType() && - "SmoothStep operands must be a vector"); + 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"); diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h b/clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h index e35575a607574..8cdd63d7e07bb 100644 --- a/clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h +++ b/clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h @@ -82,18 +82,22 @@ constexpr vector<T, N> fmod_vec_impl(vector<T, N> X, vector<T, N> Y) { } template <typename T> constexpr T smoothstep_impl(T Min, T Max, T X) { - T t = saturate((X - Min) / (Max - Min)); - return (3 - 2 * t) * t * t; +#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) { +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 - // undefined? - vector<T, N> t = saturate((X - Min) / (Max - Min)); - return (3 - 2 * t) * t * t; + vector<T, N> S = saturate((X - Min) / (Max - Min)); + return (3 - 2 * S) * S * S; #endif } diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h index 0a18dd9fa566c..fd799b8d874ae 100644 --- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h +++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h @@ -328,13 +328,15 @@ reflect(__detail::HLSL_FIXED_VECTOR<float, L> I, //===----------------------------------------------------------------------===// /// \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]. +/// \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. Result is undefined if Min ≥ Max. +/// 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) @@ -363,8 +365,8 @@ const inline __detail::HLSL_FIXED_VECTOR<half, N> smoothstep( 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) { + __detail::HLSL_FIXED_VECTOR<float, N> Max, + __detail::HLSL_FIXED_VECTOR<float, N> X) { return __detail::smoothstep_vec_impl(Min, Max, X); } diff --git a/clang/lib/Sema/SemaSPIRV.cpp b/clang/lib/Sema/SemaSPIRV.cpp index ebda4f359edbd..d35fce0fcbcda 100644 --- a/clang/lib/Sema/SemaSPIRV.cpp +++ b/clang/lib/Sema/SemaSPIRV.cpp @@ -108,36 +108,33 @@ bool SemaSPIRV::CheckSPIRVBuiltinFunctionCall(unsigned BuiltinID, ExprResult A = TheCall->getArg(0); QualType ArgTyA = A.get()->getType(); auto *VTyA = ArgTyA->getAs<VectorType>(); - if (VTyA == nullptr) { + if (!(ArgTyA->isScalarType() || VTyA)) { SemaRef.Diag(A.get()->getBeginLoc(), - diag::err_typecheck_convert_incompatible) + diag::err_typecheck_expect_any_scalar_or_vector) << ArgTyA - << SemaRef.Context.getVectorType(ArgTyA, 2, VectorKind::Generic) << 1 - << 0 << 0; + << 1; return true; } ExprResult B = TheCall->getArg(1); QualType ArgTyB = B.get()->getType(); auto *VTyB = ArgTyB->getAs<VectorType>(); - if (VTyB == nullptr) { + if (!(ArgTyB->isScalarType() || VTyB)) { SemaRef.Diag(A.get()->getBeginLoc(), - diag::err_typecheck_convert_incompatible) + diag::err_typecheck_expect_any_scalar_or_vector) << ArgTyB - << SemaRef.Context.getVectorType(ArgTyB, 2, VectorKind::Generic) << 1 - << 0 << 0; + << 1; return true; } ExprResult C = TheCall->getArg(2); QualType ArgTyC = C.get()->getType(); auto *VTyC = ArgTyC->getAs<VectorType>(); - if (VTyC == nullptr) { + if (!(ArgTyC->isScalarType() || VTyC)) { SemaRef.Diag(A.get()->getBeginLoc(), - diag::err_typecheck_convert_incompatible) - << ArgTyB - << SemaRef.Context.getVectorType(ArgTyC, 2, VectorKind::Generic) << 1 - << 0 << 0; + diag::err_typecheck_expect_any_scalar_or_vector) + << ArgTyC + << 1; return true; } diff --git a/clang/test/CodeGenHLSL/builtins/smoothstep.hlsl b/clang/test/CodeGenHLSL/builtins/smoothstep.hlsl index 3ac872b4452b2..bbb19692f1225 100644 --- a/clang/test/CodeGenHLSL/builtins/smoothstep.hlsl +++ b/clang/test/CodeGenHLSL/builtins/smoothstep.hlsl @@ -22,15 +22,12 @@ // 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: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn half [[X]], [[MIN]] -// SPVCHECK-NEXT: [[SUB1_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn half [[MAX]], [[MIN]] -// SPVCHECK-NEXT: [[DIV_I:%.*]] = fdiv reassoc nnan ninf nsz arcp afn half [[SUB_I]], [[SUB1_I]] -// SPVCHECK-NEXT: [[HLSL_SATURATE_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn half @llvm.spv.saturate.f16(half [[DIV_I]]) -// SPVCHECK-NEXT: [[MUL_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn half [[HLSL_SATURATE_I]], 0xH4000 -// SPVCHECK-NEXT: [[SUB2_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn half 0xH4200, [[MUL_I]] -// SPVCHECK-NEXT: [[TMP0:%.*]] = fmul reassoc nnan ninf nsz arcp afn half [[HLSL_SATURATE_I]], [[HLSL_SATURATE_I]] -// SPVCHECK-NEXT: [[MUL4_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn half [[TMP0]], [[SUB2_I]] -// SPVCHECK-NEXT: ret half [[MUL4_I]] +// 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); } @@ -113,15 +110,12 @@ half4 test_smoothstep_half4(half4 Min, half4 Max, half4 X) { return smoothstep(M // 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: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn float [[X]], [[MIN]] -// SPVCHECK-NEXT: [[SUB1_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn float [[MAX]], [[MIN]] -// SPVCHECK-NEXT: [[DIV_I:%.*]] = fdiv reassoc nnan ninf nsz arcp afn float [[SUB_I]], [[SUB1_I]] -// SPVCHECK-NEXT: [[HLSL_SATURATE_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn float @llvm.spv.saturate.f32(float [[DIV_I]]) -// SPVCHECK-NEXT: [[MUL_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn float [[HLSL_SATURATE_I]], 2.000000e+00 -// SPVCHECK-NEXT: [[SUB2_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn float 3.000000e+00, [[MUL_I]] -// SPVCHECK-NEXT: [[TMP0:%.*]] = fmul reassoc nnan ninf nsz arcp afn float [[HLSL_SATURATE_I]], [[HLSL_SATURATE_I]] -// SPVCHECK-NEXT: [[MUL4_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn float [[TMP0]], [[SUB2_I]] -// SPVCHECK-NEXT: ret float [[MUL4_I]] +// 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); } diff --git a/clang/test/CodeGenSPIRV/Builtins/smoothstep.c b/clang/test/CodeGenSPIRV/Builtins/smoothstep.c index b90d51a74b5c6..33fd0586e6dc6 100644 --- a/clang/test/CodeGenSPIRV/Builtins/smoothstep.c +++ b/clang/test/CodeGenSPIRV/Builtins/smoothstep.c @@ -6,8 +6,20 @@ 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_smoothstep_float( +// CHECK-SAME: float noundef [[MIN:%.*]], float noundef [[MAX:%.*]], float noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[CONV:%.*]] = fpext float [[MIN]] to double +// CHECK-NEXT: [[CONV1:%.*]] = fpext float [[MAX]] to double +// CHECK-NEXT: [[CONV2:%.*]] = fpext float [[X]] to double +// CHECK-NEXT: [[SPV_SMOOTHSTEP:%.*]] = tail call double @llvm.spv.smoothstep.f64(double [[CONV]], double [[CONV1]], double [[CONV2]]) +// CHECK-NEXT: [[CONV3:%.*]] = fptrunc double [[SPV_SMOOTHSTEP]] to float +// CHECK-NEXT: ret float [[CONV3]] +// +float test_smoothstep_float(float Min, float Max, float X) { return __builtin_spirv_smoothstep(Min, Max, X); } + // CHECK-LABEL: define spir_func <2 x float> @test_smoothstep_float2( -// CHECK-SAME: <2 x float> noundef [[MIN:%.*]], <2 x float> noundef [[MAX:%.*]], <2 x float> noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] { +// CHECK-SAME: <2 x float> noundef [[MIN:%.*]], <2 x float> noundef [[MAX:%.*]], <2 x float> noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[SPV_SMOOTHSTEP:%.*]] = tail call <2 x float> @llvm.spv.smoothstep.v2f32(<2 x float> [[MIN]], <2 x float> [[MAX]], <2 x float> [[X]]) // CHECK-NEXT: ret <2 x float> [[SPV_SMOOTHSTEP]] >From b7e06d0079973a5c18546ac04c071faed7b4c9d8 Mon Sep 17 00:00:00 2001 From: kmpeng <kaitlinp...@microsoft.com> Date: Thu, 20 Mar 2025 13:40:36 -0700 Subject: [PATCH 04/10] remove double and int spv sema tests --- clang/test/SemaSPIRV/BuiltIns/smoothstep-errors.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/clang/test/SemaSPIRV/BuiltIns/smoothstep-errors.c b/clang/test/SemaSPIRV/BuiltIns/smoothstep-errors.c index ffa9d30012213..0f94d2b30e7a4 100644 --- a/clang/test/SemaSPIRV/BuiltIns/smoothstep-errors.c +++ b/clang/test/SemaSPIRV/BuiltIns/smoothstep-errors.c @@ -16,13 +16,3 @@ float2 test_too_many_arg(float2 p0) { return __builtin_spirv_smoothstep(p0, p0, p0, p0); // expected-error@-1 {{too many arguments to function call, expected 3, have 4}} } - -float test_double_scalar_inputs(double p0, double p1, double p2) { - return __builtin_spirv_smoothstep(p0, p1, p2); - // expected-error@-1 {{passing 'double' to parameter of incompatible type '__attribute__((__vector_size__(2 * sizeof(double)))) double' (vector of 2 'double' values)}} -} - -float test_int_scalar_inputs(int p0, int p1, int p2) { - return __builtin_spirv_smoothstep(p0, p1, p2); - // expected-error@-1 {{passing 'int' to parameter of incompatible type '__attribute__((__vector_size__(2 * sizeof(int)))) int' (vector of 2 'int' values)}} -} >From 776a5b7381d8c9e65a5ec32815aaa0123507413b Mon Sep 17 00:00:00 2001 From: kmpeng <kaitlinp...@microsoft.com> Date: Thu, 20 Mar 2025 13:41:01 -0700 Subject: [PATCH 05/10] clang-format --- clang/lib/Sema/SemaSPIRV.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/clang/lib/Sema/SemaSPIRV.cpp b/clang/lib/Sema/SemaSPIRV.cpp index d35fce0fcbcda..2cbb57a739a1a 100644 --- a/clang/lib/Sema/SemaSPIRV.cpp +++ b/clang/lib/Sema/SemaSPIRV.cpp @@ -111,8 +111,7 @@ bool SemaSPIRV::CheckSPIRVBuiltinFunctionCall(unsigned BuiltinID, if (!(ArgTyA->isScalarType() || VTyA)) { SemaRef.Diag(A.get()->getBeginLoc(), diag::err_typecheck_expect_any_scalar_or_vector) - << ArgTyA - << 1; + << ArgTyA << 1; return true; } @@ -122,8 +121,7 @@ bool SemaSPIRV::CheckSPIRVBuiltinFunctionCall(unsigned BuiltinID, if (!(ArgTyB->isScalarType() || VTyB)) { SemaRef.Diag(A.get()->getBeginLoc(), diag::err_typecheck_expect_any_scalar_or_vector) - << ArgTyB - << 1; + << ArgTyB << 1; return true; } @@ -133,8 +131,7 @@ bool SemaSPIRV::CheckSPIRVBuiltinFunctionCall(unsigned BuiltinID, if (!(ArgTyC->isScalarType() || VTyC)) { SemaRef.Diag(A.get()->getBeginLoc(), diag::err_typecheck_expect_any_scalar_or_vector) - << ArgTyC - << 1; + << ArgTyC << 1; return true; } >From bbb501b41dcc96153d03da3720fce213b869e756 Mon Sep 17 00:00:00 2001 From: kmpeng <kaitlinp...@microsoft.com> Date: Fri, 21 Mar 2025 14:40:49 -0700 Subject: [PATCH 06/10] address pr comments - remove scalar/vector assert, change SemaSPIRV.cpp checks --- clang/lib/CodeGen/TargetBuiltins/SPIR.cpp | 10 ++----- clang/lib/Sema/SemaSPIRV.cpp | 32 ++++++++++++++--------- 2 files changed, 22 insertions(+), 20 deletions(-) diff --git a/clang/lib/CodeGen/TargetBuiltins/SPIR.cpp b/clang/lib/CodeGen/TargetBuiltins/SPIR.cpp index bd8f1c6d6cdb9..969aa0b67b5c2 100644 --- a/clang/lib/CodeGen/TargetBuiltins/SPIR.cpp +++ b/clang/lib/CodeGen/TargetBuiltins/SPIR.cpp @@ -69,16 +69,10 @@ Value *CodeGenFunction::EmitSPIRVBuiltinExpr(unsigned BuiltinID, 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"); + ArrayRef<Value *>{Min, Max, X}, /*FMFSource=*/nullptr, + "spv.smoothstep"); } } return nullptr; diff --git a/clang/lib/Sema/SemaSPIRV.cpp b/clang/lib/Sema/SemaSPIRV.cpp index 2cbb57a739a1a..e7f44b81d114b 100644 --- a/clang/lib/Sema/SemaSPIRV.cpp +++ b/clang/lib/Sema/SemaSPIRV.cpp @@ -105,33 +105,41 @@ bool SemaSPIRV::CheckSPIRVBuiltinFunctionCall(unsigned BuiltinID, if (SemaRef.checkArgCount(TheCall, 3)) return true; + // check if the all arguments have floating representation ExprResult A = TheCall->getArg(0); QualType ArgTyA = A.get()->getType(); - auto *VTyA = ArgTyA->getAs<VectorType>(); - if (!(ArgTyA->isScalarType() || VTyA)) { + if (!ArgTyA->hasFloatingRepresentation()) { SemaRef.Diag(A.get()->getBeginLoc(), - diag::err_typecheck_expect_any_scalar_or_vector) - << ArgTyA << 1; + diag::err_typecheck_convert_incompatible) + << ArgTyA << SemaRef.Context.FloatTy << 1 << 0 << 0; return true; } ExprResult B = TheCall->getArg(1); QualType ArgTyB = B.get()->getType(); - auto *VTyB = ArgTyB->getAs<VectorType>(); - if (!(ArgTyB->isScalarType() || VTyB)) { + if (!ArgTyB->hasFloatingRepresentation()) { SemaRef.Diag(A.get()->getBeginLoc(), - diag::err_typecheck_expect_any_scalar_or_vector) - << ArgTyB << 1; + diag::err_typecheck_convert_incompatible) + << ArgTyB << SemaRef.Context.FloatTy << 1 << 0 << 0; return true; } ExprResult C = TheCall->getArg(2); QualType ArgTyC = C.get()->getType(); - auto *VTyC = ArgTyC->getAs<VectorType>(); - if (!(ArgTyC->isScalarType() || VTyC)) { + if (!ArgTyC->hasFloatingRepresentation()) { SemaRef.Diag(A.get()->getBeginLoc(), - diag::err_typecheck_expect_any_scalar_or_vector) - << ArgTyC << 1; + diag::err_typecheck_convert_incompatible) + << ArgTyC << SemaRef.Context.FloatTy << 1 << 0 << 0; + return true; + } + + // check if all arguments are of the same type + if (!(SemaRef.getASTContext().hasSameUnqualifiedType(ArgTyA, ArgTyB) && + SemaRef.getASTContext().hasSameUnqualifiedType(ArgTyA, ArgTyC))) { + SemaRef.Diag(TheCall->getBeginLoc(), + diag::err_vec_builtin_incompatible_vector) + << TheCall->getDirectCallee() << /*useAllTerminology*/ true + << SourceRange(A.get()->getBeginLoc(), C.get()->getEndLoc()); return true; } >From 8e50d0a88574e758029480e72ef250e54f350c4a Mon Sep 17 00:00:00 2001 From: kmpeng <kaitlinp...@microsoft.com> Date: Tue, 25 Mar 2025 10:23:43 -0700 Subject: [PATCH 07/10] address pr comments - add int and mismatched args error tests, remove spirv double test --- clang/test/CodeGenSPIRV/Builtins/smoothstep.c | 7 +++++ .../SemaSPIRV/BuiltIns/smoothstep-errors.c | 26 +++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/clang/test/CodeGenSPIRV/Builtins/smoothstep.c b/clang/test/CodeGenSPIRV/Builtins/smoothstep.c index 33fd0586e6dc6..72317dda1c08e 100644 --- a/clang/test/CodeGenSPIRV/Builtins/smoothstep.c +++ b/clang/test/CodeGenSPIRV/Builtins/smoothstep.c @@ -42,3 +42,10 @@ float3 test_smoothstep_float3(float3 Min, float3 Max, float3 X) { return __built // float4 test_smoothstep_float4(float4 Min, float4 Max, float4 X) { return __builtin_spirv_smoothstep(Min, Max, X); } +// CHECK-LABEL: define spir_func double @test_smoothstep_double( +// CHECK-SAME: double noundef [[MIN:%.*]], double noundef [[MAX:%.*]], double noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[SPV_SMOOTHSTEP:%.*]] = tail call double @llvm.spv.smoothstep.f64(double [[MIN]], double [[MAX]], double [[X]]) +// CHECK-NEXT: ret double [[SPV_SMOOTHSTEP]] +// +double test_smoothstep_double(double Min, double Max, double X) { return __builtin_spirv_smoothstep(Min, Max, X); } diff --git a/clang/test/SemaSPIRV/BuiltIns/smoothstep-errors.c b/clang/test/SemaSPIRV/BuiltIns/smoothstep-errors.c index 0f94d2b30e7a4..3f31596dbc764 100644 --- a/clang/test/SemaSPIRV/BuiltIns/smoothstep-errors.c +++ b/clang/test/SemaSPIRV/BuiltIns/smoothstep-errors.c @@ -1,6 +1,7 @@ // RUN: %clang_cc1 %s -triple spirv-pc-vulkan-compute -verify typedef float float2 __attribute__((ext_vector_type(2))); +typedef float float3 __attribute__((ext_vector_type(3))); float2 test_no_second_arg(float2 p0) { return __builtin_spirv_smoothstep(p0); @@ -16,3 +17,28 @@ float2 test_too_many_arg(float2 p0) { return __builtin_spirv_smoothstep(p0, p0, p0, p0); // expected-error@-1 {{too many arguments to function call, expected 3, have 4}} } + +int test_int_scalar_inputs(int p0) { + return __builtin_spirv_smoothstep(p0, p0, p0); + // expected-error@-1 {{passing 'int' to parameter of incompatible type 'float'}} +} + +float test_mismatched_arg(float p0, float2 p1) { + return __builtin_spirv_smoothstep(p0, p1, p1); + // expected-error@-1 {{all arguments to '__builtin_spirv_smoothstep' must have the same type}} +} + +float test_mismatched_arg2(float p0, float2 p1) { + return __builtin_spirv_smoothstep(p0, p0, p1); + // expected-error@-1 {{all arguments to '__builtin_spirv_smoothstep' must have the same type}} +} + +float test_mismatched_return(float2 p0) { + return __builtin_spirv_smoothstep(p0, p0, p0); + // expected-error@-1 {{returning 'float2' (vector of 2 'float' values) from a function with incompatible result type 'float'}} +} + +float3 test_mismatched_return2(float2 p0) { + return __builtin_spirv_smoothstep(p0, p0, p0); + // expected-error@-1 {{returning 'float2' (vector of 2 'float' values) from a function with incompatible result type 'float3' (vector of 3 'float' values)}} +} \ No newline at end of file >From 9a8739e8037ad2f0af22e52e73c95cd658bc353a Mon Sep 17 00:00:00 2001 From: kmpeng <kaitlinp...@microsoft.com> Date: Tue, 25 Mar 2025 10:57:29 -0700 Subject: [PATCH 08/10] remove spirv double test --- clang/test/CodeGenSPIRV/Builtins/smoothstep.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/clang/test/CodeGenSPIRV/Builtins/smoothstep.c b/clang/test/CodeGenSPIRV/Builtins/smoothstep.c index 72317dda1c08e..508538c98d61a 100644 --- a/clang/test/CodeGenSPIRV/Builtins/smoothstep.c +++ b/clang/test/CodeGenSPIRV/Builtins/smoothstep.c @@ -41,11 +41,3 @@ float3 test_smoothstep_float3(float3 Min, float3 Max, float3 X) { return __built // CHECK-NEXT: ret <4 x float> [[SPV_SMOOTHSTEP]] // float4 test_smoothstep_float4(float4 Min, float4 Max, float4 X) { return __builtin_spirv_smoothstep(Min, Max, X); } - -// CHECK-LABEL: define spir_func double @test_smoothstep_double( -// CHECK-SAME: double noundef [[MIN:%.*]], double noundef [[MAX:%.*]], double noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0]] { -// CHECK-NEXT: [[ENTRY:.*:]] -// CHECK-NEXT: [[SPV_SMOOTHSTEP:%.*]] = tail call double @llvm.spv.smoothstep.f64(double [[MIN]], double [[MAX]], double [[X]]) -// CHECK-NEXT: ret double [[SPV_SMOOTHSTEP]] -// -double test_smoothstep_double(double Min, double Max, double X) { return __builtin_spirv_smoothstep(Min, Max, X); } >From d806dca0e843c3f6ced26425fff922881514e41c Mon Sep 17 00:00:00 2001 From: kmpeng <kaitlinp...@microsoft.com> Date: Tue, 25 Mar 2025 15:23:38 -0700 Subject: [PATCH 09/10] Add CustomTypeChecking, fix codegen tests --- clang/include/clang/Basic/BuiltinsSPIRV.td | 2 +- clang/test/CodeGenHLSL/builtins/smoothstep.hlsl | 16 ++++------------ clang/test/CodeGenSPIRV/Builtins/smoothstep.c | 8 ++------ 3 files changed, 7 insertions(+), 19 deletions(-) diff --git a/clang/include/clang/Basic/BuiltinsSPIRV.td b/clang/include/clang/Basic/BuiltinsSPIRV.td index 2eb4c733b0a42..9f76d672cc7ce 100644 --- a/clang/include/clang/Basic/BuiltinsSPIRV.td +++ b/clang/include/clang/Basic/BuiltinsSPIRV.td @@ -28,6 +28,6 @@ def SPIRVReflect : Builtin { def SPIRVSmoothStep : Builtin { let Spellings = ["__builtin_spirv_smoothstep"]; - let Attributes = [NoThrow, Const]; + let Attributes = [NoThrow, Const, CustomTypeChecking]; let Prototype = "void(...)"; } diff --git a/clang/test/CodeGenHLSL/builtins/smoothstep.hlsl b/clang/test/CodeGenHLSL/builtins/smoothstep.hlsl index bbb19692f1225..f2328c7330e6c 100644 --- a/clang/test/CodeGenHLSL/builtins/smoothstep.hlsl +++ b/clang/test/CodeGenHLSL/builtins/smoothstep.hlsl @@ -22,12 +22,8 @@ // 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]] +// SPVCHECK-NEXT: [[SPV_SMOOTHSTEP_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef half @llvm.spv.smoothstep.f16(half [[MIN]], half [[MAX]], half [[X]]) +// SPVCHECK-NEXT: ret half [[SPV_SMOOTHSTEP_I]] // half test_smoothstep_half(half Min, half Max, half X) { return smoothstep(Min, Max, X); } @@ -110,12 +106,8 @@ half4 test_smoothstep_half4(half4 Min, half4 Max, half4 X) { return smoothstep(M // 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]] +// SPVCHECK-NEXT: [[SPV_SMOOTHSTEP_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef float @llvm.spv.smoothstep.f32(float [[MIN]], float [[MAX]], float [[X]]) +// SPVCHECK-NEXT: ret float [[SPV_SMOOTHSTEP_I]] // float test_smoothstep_float(float Min, float Max, float X) { return smoothstep(Min, Max, X); } diff --git a/clang/test/CodeGenSPIRV/Builtins/smoothstep.c b/clang/test/CodeGenSPIRV/Builtins/smoothstep.c index 508538c98d61a..714db4d9f728c 100644 --- a/clang/test/CodeGenSPIRV/Builtins/smoothstep.c +++ b/clang/test/CodeGenSPIRV/Builtins/smoothstep.c @@ -9,12 +9,8 @@ typedef float float4 __attribute__((ext_vector_type(4))); // CHECK-LABEL: define spir_func float @test_smoothstep_float( // CHECK-SAME: float noundef [[MIN:%.*]], float noundef [[MAX:%.*]], float noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] { // CHECK-NEXT: [[ENTRY:.*:]] -// CHECK-NEXT: [[CONV:%.*]] = fpext float [[MIN]] to double -// CHECK-NEXT: [[CONV1:%.*]] = fpext float [[MAX]] to double -// CHECK-NEXT: [[CONV2:%.*]] = fpext float [[X]] to double -// CHECK-NEXT: [[SPV_SMOOTHSTEP:%.*]] = tail call double @llvm.spv.smoothstep.f64(double [[CONV]], double [[CONV1]], double [[CONV2]]) -// CHECK-NEXT: [[CONV3:%.*]] = fptrunc double [[SPV_SMOOTHSTEP]] to float -// CHECK-NEXT: ret float [[CONV3]] +// CHECK-NEXT: [[SPV_SMOOTHSTEP:%.*]] = tail call float @llvm.spv.smoothstep.f32(float [[MIN]], float [[MAX]], float [[X]]) +// CHECK-NEXT: ret float [[SPV_SMOOTHSTEP]] // float test_smoothstep_float(float Min, float Max, float X) { return __builtin_spirv_smoothstep(Min, Max, X); } >From c07426201f6b50ba289f8f96e3727123bdd9ef1e Mon Sep 17 00:00:00 2001 From: kmpeng <kaitlinp...@microsoft.com> Date: Wed, 26 Mar 2025 14:51:19 -0700 Subject: [PATCH 10/10] reorganized sema spirv checks, added target env to validation step of spirv backend tests --- clang/lib/Sema/SemaSPIRV.cpp | 44 +++++++------------ .../SemaSPIRV/BuiltIns/smoothstep-errors.c | 12 ++++- .../SPIRV/hlsl-intrinsics/smoothstep.ll | 2 +- llvm/test/CodeGen/SPIRV/opencl/smoothstep.ll | 4 +- 4 files changed, 31 insertions(+), 31 deletions(-) diff --git a/clang/lib/Sema/SemaSPIRV.cpp b/clang/lib/Sema/SemaSPIRV.cpp index e7f44b81d114b..7131514d53421 100644 --- a/clang/lib/Sema/SemaSPIRV.cpp +++ b/clang/lib/Sema/SemaSPIRV.cpp @@ -106,36 +106,26 @@ bool SemaSPIRV::CheckSPIRVBuiltinFunctionCall(unsigned BuiltinID, return true; // check if the all arguments have floating representation - ExprResult A = TheCall->getArg(0); - QualType ArgTyA = A.get()->getType(); - if (!ArgTyA->hasFloatingRepresentation()) { - SemaRef.Diag(A.get()->getBeginLoc(), - diag::err_typecheck_convert_incompatible) - << ArgTyA << SemaRef.Context.FloatTy << 1 << 0 << 0; - return true; + 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); - QualType ArgTyB = B.get()->getType(); - if (!ArgTyB->hasFloatingRepresentation()) { - SemaRef.Diag(A.get()->getBeginLoc(), - diag::err_typecheck_convert_incompatible) - << ArgTyB << SemaRef.Context.FloatTy << 1 << 0 << 0; - return true; - } - ExprResult C = TheCall->getArg(2); - QualType ArgTyC = C.get()->getType(); - if (!ArgTyC->hasFloatingRepresentation()) { - SemaRef.Diag(A.get()->getBeginLoc(), - diag::err_typecheck_convert_incompatible) - << ArgTyC << SemaRef.Context.FloatTy << 1 << 0 << 0; - return true; - } - - // check if all arguments are of the same type - if (!(SemaRef.getASTContext().hasSameUnqualifiedType(ArgTyA, ArgTyB) && - SemaRef.getASTContext().hasSameUnqualifiedType(ArgTyA, ArgTyC))) { + 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 @@ -143,7 +133,7 @@ bool SemaSPIRV::CheckSPIRVBuiltinFunctionCall(unsigned BuiltinID, return true; } - QualType RetTy = ArgTyA; + QualType RetTy = A.get()->getType(); TheCall->setType(RetTy); break; } diff --git a/clang/test/SemaSPIRV/BuiltIns/smoothstep-errors.c b/clang/test/SemaSPIRV/BuiltIns/smoothstep-errors.c index 3f31596dbc764..b83217f3e0804 100644 --- a/clang/test/SemaSPIRV/BuiltIns/smoothstep-errors.c +++ b/clang/test/SemaSPIRV/BuiltIns/smoothstep-errors.c @@ -20,7 +20,17 @@ float2 test_too_many_arg(float2 p0) { int test_int_scalar_inputs(int p0) { return __builtin_spirv_smoothstep(p0, p0, p0); - // expected-error@-1 {{passing 'int' to parameter of incompatible type 'float'}} + // expected-error@-1 {{1st argument must be a scalar or vector of floating-point types (was 'int')}} +} + +float test_int_scalar_inputs2(float p0, int p1) { + return __builtin_spirv_smoothstep(p0, p1, p1); + // expected-error@-1 {{2nd argument must be a scalar or vector of floating-point types (was 'int')}} +} + +float test_int_scalar_inputs3(float p0, int p1) { + return __builtin_spirv_smoothstep(p0, p0, p1); + // expected-error@-1 {{3rd argument must be a scalar or vector of floating-point types (was 'int')}} } float test_mismatched_arg(float p0, float2 p1) { diff --git a/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/smoothstep.ll b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/smoothstep.ll index 09f93ab7955d3..9aabd8daae14b 100644 --- a/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/smoothstep.ll +++ b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/smoothstep.ll @@ -1,5 +1,5 @@ ; RUN: llc -O0 -verify-machineinstrs -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s -; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %} +; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val --target-env vulkan1.2 %} ; Make sure SPIRV operation function calls for smoothstep are lowered correctly. diff --git a/llvm/test/CodeGen/SPIRV/opencl/smoothstep.ll b/llvm/test/CodeGen/SPIRV/opencl/smoothstep.ll index fe395ace1217b..d5ab761d9d207 100644 --- a/llvm/test/CodeGen/SPIRV/opencl/smoothstep.ll +++ b/llvm/test/CodeGen/SPIRV/opencl/smoothstep.ll @@ -1,7 +1,7 @@ ; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s ; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s -; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %} -; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown %s -o - -filetype=obj | spirv-val %} +; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val --target-env vulkan1.2 %} +; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown %s -o - -filetype=obj | spirv-val --target-env vulkan1.2 %} ; CHECK-DAG: %[[#op_ext_cl:]] = OpExtInstImport "OpenCL.std" _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits