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

Reply via email to