[clang] [llvm] [HLSL] Adding HLSL `clip` function. (PR #114588)

via cfe-commits cfe-commits at lists.llvm.org
Thu Nov 14 11:15:28 PST 2024


https://github.com/joaosaffran updated https://github.com/llvm/llvm-project/pull/114588

>From 087c2dfeffbadba4df12d5c429bb1e22e9034a3f Mon Sep 17 00:00:00 2001
From: Joao Saffran <jderezende at microsoft.com>
Date: Tue, 29 Oct 2024 19:39:31 +0000
Subject: [PATCH 1/5] adding llvm intrinsic

---
 clang/include/clang/Basic/Builtins.td     |  6 ++++++
 clang/lib/CodeGen/CGBuiltin.cpp           | 10 ++++++++++
 clang/lib/CodeGen/CGHLSLRuntime.h         |  1 +
 clang/lib/Headers/hlsl/hlsl_intrinsics.h  | 17 +++++++++++++++++
 clang/lib/Sema/SemaHLSL.cpp               |  8 ++++++++
 clang/test/CodeGenHLSL/builtins/clip.hlsl | 14 ++++++++++++++
 llvm/include/llvm/IR/IntrinsicsDirectX.td |  1 +
 llvm/include/llvm/IR/IntrinsicsSPIRV.td   |  1 +
 8 files changed, 58 insertions(+)
 create mode 100644 clang/test/CodeGenHLSL/builtins/clip.hlsl

diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index 4360e0bf9840f1..bbbace6e193e66 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -4895,6 +4895,12 @@ def HLSLSplitDouble: LangBuiltin<"HLSL_LANG"> {
   let Prototype = "void(...)";
 }
 
+def HLSLClip: LangBuiltin<"HLSL_LANG"> {
+  let Spellings = ["__builtin_hlsl_elementwise_clip"];
+  let Attributes = [NoThrow, Const];
+  let Prototype = "void(bool)";
+}
+
 // Builtins for XRay.
 def XRayCustomEvent : Builtin {
   let Spellings = ["__xray_customevent"];
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 430ac5626f89d7..2f3e094e882863 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -19180,6 +19180,16 @@ case Builtin::BI__builtin_hlsl_elementwise_isinf: {
            "asuint operands types mismatch");
     return handleHlslSplitdouble(E, this);
   }
+  case Builtin::BI__builtin_hlsl_elementwise_clip:
+
+    assert(E->getArg(0)->getType()->hasFloatingRepresentation() &&
+           "clip operands types mismatch");
+
+    Value *Op0 = EmitScalarExpr(E->getArg(0));
+    auto *CMP =
+        Builder.CreateFCmpOLT(Op0, ConstantFP::get(Builder.getFloatTy(), 0.0));
+    return Builder.CreateIntrinsic(
+        VoidTy, CGM.getHLSLRuntime().getClipIntrinsic(), {CMP}, nullptr);
   }
   return nullptr;
 }
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h
index 381a5959ec098e..a1089595683a3d 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.h
+++ b/clang/lib/CodeGen/CGHLSLRuntime.h
@@ -94,6 +94,7 @@ class CGHLSLRuntime {
   GENERATE_HLSL_INTRINSIC_FUNCTION(WaveActiveCountBits, wave_active_countbits)
   GENERATE_HLSL_INTRINSIC_FUNCTION(WaveIsFirstLane, wave_is_first_lane)
   GENERATE_HLSL_INTRINSIC_FUNCTION(WaveReadLaneAt, wave_readlane)
+  GENERATE_HLSL_INTRINSIC_FUNCTION(Clip, clip)  
   GENERATE_HLSL_INTRINSIC_FUNCTION(FirstBitUHigh, firstbituhigh)
   GENERATE_HLSL_INTRINSIC_FUNCTION(FirstBitSHigh, firstbitshigh)
   GENERATE_HLSL_INTRINSIC_FUNCTION(NClamp, nclamp)
diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h
index 2ee3827d720495..f84f48fc1c122d 100644
--- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h
+++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h
@@ -655,6 +655,23 @@ double3 clamp(double3, double3, double3);
 _HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
 double4 clamp(double4, double4, double4);
 
+//===----------------------------------------------------------------------===//
+// clip builtins
+//===----------------------------------------------------------------------===//
+
+/// \fn void clip(T Val)
+/// \brief Discards the current pixel if the specified value is less than zero.
+/// \param Val The input value.
+
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clip)
+void clip(float);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clip)
+void clip(float2);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clip)
+void clip(float3);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clip)
+void clip(float4);
+
 //===----------------------------------------------------------------------===//
 // cos builtins
 //===----------------------------------------------------------------------===//
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 65b0d9cd65637f..32efb089ca1714 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -2135,6 +2135,14 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
       return true;
     break;
   }
+  case Builtin::BI__builtin_hlsl_elementwise_clip: {
+    if (SemaRef.checkArgCount(TheCall, 1))
+      return true;
+
+    if (CheckScalarOrVector(&SemaRef, TheCall, SemaRef.Context.FloatTy, 0))
+      return true;
+    break;
+  }
   case Builtin::BI__builtin_elementwise_acos:
   case Builtin::BI__builtin_elementwise_asin:
   case Builtin::BI__builtin_elementwise_atan:
diff --git a/clang/test/CodeGenHLSL/builtins/clip.hlsl b/clang/test/CodeGenHLSL/builtins/clip.hlsl
new file mode 100644
index 00000000000000..426ec8f128436a
--- /dev/null
+++ b/clang/test/CodeGenHLSL/builtins/clip.hlsl
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple dxil-pc-shadermodel6.3-pixel %s -fnative-half-type -emit-llvm -o - | FileCheck %s
+
+RWBuffer<float4> Buf;
+
+//CHECK-LABEL: define void @main()
+float4 main( ) {
+  float4 p1 = Buf[0];
+  //CHECK: [[LOAD:%.*]] = load <4 x float>, ptr %p1{{.*}}, align 16
+  //CHECK-NEXT: [[EXTR:%.*]] = extractelement <4 x float> [[LOAD]], i32 3
+  //CHECK-NEXT: [[FCMP:%.*]] = fcmp olt float [[EXTR]], 0.000000e+00
+  //CHECK-NEXT: call void @llvm.dx.clip(i1 [[FCMP]])
+  clip(p1.a);
+  return p1;
+}
diff --git a/llvm/include/llvm/IR/IntrinsicsDirectX.td b/llvm/include/llvm/IR/IntrinsicsDirectX.td
index 178cb8e814ddca..f73f1ca5010f27 100644
--- a/llvm/include/llvm/IR/IntrinsicsDirectX.td
+++ b/llvm/include/llvm/IR/IntrinsicsDirectX.td
@@ -99,6 +99,7 @@ def int_dx_step : DefaultAttrsIntrinsic<[LLVMMatchType<0>], [llvm_anyfloat_ty, L
 def int_dx_splitdouble : DefaultAttrsIntrinsic<[llvm_anyint_ty, LLVMMatchType<0>], 
     [LLVMScalarOrSameVectorWidth<0, llvm_double_ty>], [IntrNoMem]>;
 def int_dx_radians : DefaultAttrsIntrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>], [IntrNoMem]>;
+def int_dx_clip : DefaultAttrsIntrinsic<[], [llvm_i1_ty], [IntrNoMem]>;
 def int_dx_firstbituhigh : DefaultAttrsIntrinsic<[LLVMScalarOrSameVectorWidth<0, llvm_i32_ty>], [llvm_anyint_ty], [IntrNoMem]>;
 def int_dx_firstbitshigh : DefaultAttrsIntrinsic<[LLVMScalarOrSameVectorWidth<0, llvm_i32_ty>], [llvm_anyint_ty], [IntrNoMem]>;
 }
diff --git a/llvm/include/llvm/IR/IntrinsicsSPIRV.td b/llvm/include/llvm/IR/IntrinsicsSPIRV.td
index 962b25560d7510..5308ffc73bdf95 100644
--- a/llvm/include/llvm/IR/IntrinsicsSPIRV.td
+++ b/llvm/include/llvm/IR/IntrinsicsSPIRV.td
@@ -91,6 +91,7 @@ let TargetPrefix = "spv" in {
   def int_spv_sign : DefaultAttrsIntrinsic<[LLVMScalarOrSameVectorWidth<0, llvm_i32_ty>], [llvm_any_ty], [IntrNoMem]>;
   def int_spv_radians : DefaultAttrsIntrinsic<[LLVMMatchType<0>], [llvm_anyfloat_ty], [IntrNoMem]>;
   def int_spv_group_memory_barrier_with_group_sync : DefaultAttrsIntrinsic<[], [], []>;
+  def int_spv_clip : DefaultAttrsIntrinsic<[], [llvm_i1_ty], [IntrNoMem]>;
   def int_spv_uclamp : DefaultAttrsIntrinsic<[llvm_anyint_ty], [LLVMMatchType<0>, LLVMMatchType<0>, LLVMMatchType<0>], [IntrNoMem]>;
   def int_spv_sclamp : DefaultAttrsIntrinsic<[llvm_anyint_ty], [LLVMMatchType<0>, LLVMMatchType<0>, LLVMMatchType<0>], [IntrNoMem]>;
   def int_spv_nclamp : DefaultAttrsIntrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>, LLVMMatchType<0>, LLVMMatchType<0>], [IntrNoMem]>;

>From 0f68438c755e73815c2c3db6846070ae1d7214a3 Mon Sep 17 00:00:00 2001
From: Joao Saffran <jderezende at microsoft.com>
Date: Wed, 30 Oct 2024 23:29:44 +0000
Subject: [PATCH 2/5] adding DXIL and SPIRV codegen

---
 clang/lib/CodeGen/CGBuiltin.cpp               | 32 ++++++++++++---
 clang/test/CodeGenHLSL/builtins/clip.hlsl     |  9 ++---
 llvm/lib/Target/DirectX/DXIL.td               | 40 +++++++++++++++++--
 llvm/lib/Target/SPIRV/SPIRVInstrInfo.td       |  1 +
 .../Target/SPIRV/SPIRVInstructionSelector.cpp | 20 ++++++++++
 llvm/test/CodeGen/DirectX/clip.ll             | 11 +++++
 .../CodeGen/SPIRV/hlsl-intrinsics/clip.ll     | 18 +++++++++
 7 files changed, 115 insertions(+), 16 deletions(-)
 create mode 100644 llvm/test/CodeGen/DirectX/clip.ll
 create mode 100644 llvm/test/CodeGen/SPIRV/hlsl-intrinsics/clip.ll

diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 2f3e094e882863..f8244eb412be1b 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -99,6 +99,31 @@ static void initializeAlloca(CodeGenFunction &CGF, AllocaInst *AI, Value *Size,
   I->addAnnotationMetadata("auto-init");
 }
 
+static Value *handleHlslClip(const CallExpr *E, CodeGenFunction *CGF) {
+  Value *Op0 = CGF->EmitScalarExpr(E->getArg(0));
+  auto *CMP = CGF->Builder.CreateFCmpOLT(
+      Op0, ConstantFP::get(CGF->Builder.getFloatTy(), 0.0));
+
+  if (CGF->CGM.getTarget().getTriple().isDXIL())
+    return CGF->Builder.CreateIntrinsic(CGF->VoidTy, llvm::Intrinsic::dx_clip,
+                                        {CMP}, nullptr);
+
+  BasicBlock *LT0 = CGF->createBasicBlock("lt0", CGF->CurFn);
+  BasicBlock *End = CGF->createBasicBlock("end", CGF->CurFn);
+
+  CGF->Builder.CreateCondBr(CMP, LT0, End);
+
+  CGF->Builder.SetInsertPoint(LT0);
+
+  auto *IntrCall = CGF->Builder.CreateIntrinsic(
+      CGF->VoidTy, llvm::Intrinsic::spv_clip, {}, nullptr);
+
+  CGF->Builder.CreateBr(End);
+
+  CGF->Builder.SetInsertPoint(End);
+  return IntrCall;
+}
+
 static Value *handleHlslSplitdouble(const CallExpr *E, CodeGenFunction *CGF) {
   Value *Op0 = CGF->EmitScalarExpr(E->getArg(0));
   const auto *OutArg1 = dyn_cast<HLSLOutArgExpr>(E->getArg(1));
@@ -19184,12 +19209,7 @@ case Builtin::BI__builtin_hlsl_elementwise_isinf: {
 
     assert(E->getArg(0)->getType()->hasFloatingRepresentation() &&
            "clip operands types mismatch");
-
-    Value *Op0 = EmitScalarExpr(E->getArg(0));
-    auto *CMP =
-        Builder.CreateFCmpOLT(Op0, ConstantFP::get(Builder.getFloatTy(), 0.0));
-    return Builder.CreateIntrinsic(
-        VoidTy, CGM.getHLSLRuntime().getClipIntrinsic(), {CMP}, nullptr);
+    return handleHlslClip(E, this);
   }
   return nullptr;
 }
diff --git a/clang/test/CodeGenHLSL/builtins/clip.hlsl b/clang/test/CodeGenHLSL/builtins/clip.hlsl
index 426ec8f128436a..994a7c9f3311c3 100644
--- a/clang/test/CodeGenHLSL/builtins/clip.hlsl
+++ b/clang/test/CodeGenHLSL/builtins/clip.hlsl
@@ -1,14 +1,11 @@
 // RUN: %clang_cc1 -finclude-default-header -x hlsl -triple dxil-pc-shadermodel6.3-pixel %s -fnative-half-type -emit-llvm -o - | FileCheck %s
-
-RWBuffer<float4> Buf;
+// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple spirv-vulkan-pixel %s -fnative-half-type -emit-llvm -o - | FileCheck %s
 
 //CHECK-LABEL: define void @main()
-float4 main( ) {
-  float4 p1 = Buf[0];
+void test(float Buf) {
   //CHECK: [[LOAD:%.*]] = load <4 x float>, ptr %p1{{.*}}, align 16
   //CHECK-NEXT: [[EXTR:%.*]] = extractelement <4 x float> [[LOAD]], i32 3
   //CHECK-NEXT: [[FCMP:%.*]] = fcmp olt float [[EXTR]], 0.000000e+00
   //CHECK-NEXT: call void @llvm.dx.clip(i1 [[FCMP]])
-  clip(p1.a);
-  return p1;
+  clip(Buf);
 }
diff --git a/llvm/lib/Target/DirectX/DXIL.td b/llvm/lib/Target/DirectX/DXIL.td
index 078f0591a67515..78ccb70bbf3b38 100644
--- a/llvm/lib/Target/DirectX/DXIL.td
+++ b/llvm/lib/Target/DirectX/DXIL.td
@@ -770,6 +770,15 @@ def CheckAccessFullyMapped : DXILOp<71, checkAccessFullyMapped> {
   let stages = [Stages<DXIL1_0, [all_stages]>];
 }
 
+def Discard : DXILOp<82, discard> {
+  let Doc = "discard the current pixel";
+  let LLVMIntrinsic = int_dx_clip;
+  let arguments = [Int1Ty];
+  let result = VoidTy;
+  let stages = [Stages<DXIL1_0, [pixel]>];
+  let attributes = [Attributes<DXIL1_0, [ReadNone]>];
+}
+
 def ThreadId :  DXILOp<93, threadId> {
   let Doc = "Reads the thread ID";
   let LLVMIntrinsic = int_dx_thread_id;
@@ -862,6 +871,15 @@ def WaveIsFirstLane :  DXILOp<110, waveIsFirstLane> {
   let attributes = [Attributes<DXIL1_0, [ReadNone]>];
 }
 
+def WaveGetLaneIndex : DXILOp<111, waveGetLaneIndex> {
+  let Doc = "returns the index of the current lane in the wave";
+  let LLVMIntrinsic = int_dx_wave_getlaneindex;
+  let arguments = [];
+  let result = Int32Ty;
+  let stages = [Stages<DXIL1_0, [all_stages]>];
+  let attributes = [Attributes<DXIL1_0, [ReadNone]>];
+}
+
 def WaveReadLaneAt:  DXILOp<117, waveReadLaneAt> {
   let Doc = "returns the value from the specified lane";
   let LLVMIntrinsic = int_dx_wave_readlane;
@@ -872,10 +890,24 @@ def WaveReadLaneAt:  DXILOp<117, waveReadLaneAt> {
   let attributes = [Attributes<DXIL1_0, [ReadNone]>];
 }
 
-def WaveGetLaneIndex : DXILOp<111, waveGetLaneIndex> {
-  let Doc = "returns the index of the current lane in the wave";
-  let LLVMIntrinsic = int_dx_wave_getlaneindex;
-  let arguments = [];
+def AnnotateHandle : DXILOp<217, annotateHandle> {
+  let Doc = "annotate handle with resource properties";
+  let arguments = [HandleTy, ResPropsTy];
+  let result = HandleTy;
+  let stages = [Stages<DXIL1_6, [all_stages]>];
+}
+
+def CreateHandleFromBinding : DXILOp<218, createHandleFromBinding> {
+  let Doc = "create resource handle from binding";
+  let arguments = [ResBindTy, Int32Ty, Int1Ty];
+  let result = HandleTy;
+  let stages = [Stages<DXIL1_6, [all_stages]>];
+}
+
+def WaveAllBitCount : DXILOp<135, waveAllOp> {
+  let Doc = "returns the count of bits set to 1 across the wave";
+  let LLVMIntrinsic = int_dx_wave_active_countbits;
+  let arguments = [Int1Ty];
   let result = Int32Ty;
   let stages = [Stages<DXIL1_0, [all_stages]>];
   let attributes = [Attributes<DXIL1_0, [ReadNone]>];
diff --git a/llvm/lib/Target/SPIRV/SPIRVInstrInfo.td b/llvm/lib/Target/SPIRV/SPIRVInstrInfo.td
index 130b557f9e8484..fde23d9d0ca5f0 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstrInfo.td
+++ b/llvm/lib/Target/SPIRV/SPIRVInstrInfo.td
@@ -639,6 +639,7 @@ let isReturn = 1, hasDelaySlot = 0, isBarrier = 0, isTerminator = 1, isNotDuplic
 }
 def OpLifetimeStart: Op<256, (outs), (ins ID:$ptr, i32imm:$sz), "OpLifetimeStart $ptr, $sz">;
 def OpLifetimeStop: Op<257, (outs), (ins ID:$ptr, i32imm:$sz), "OpLifetimeStop $ptr, $sz">;
+def OpDemoteToHelperInvocation: SimpleOp<"OpDemoteToHelperInvocation", 5380>;
 
 // 3.42.18 Atomic Instructions
 
diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
index a968b65c173067..8e43df58f7a631 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
@@ -164,6 +164,9 @@ class SPIRVInstructionSelector : public InstructionSelector {
                  unsigned comparisonOpcode, MachineInstr &I) const;
   bool selectCross(Register ResVReg, const SPIRVType *ResType,
                    MachineInstr &I) const;
+  bool selectClip(Register ResVReg, const SPIRVType *ResType,
+                  MachineInstr &I) const;
+
   bool selectICmp(Register ResVReg, const SPIRVType *ResType,
                   MachineInstr &I) const;
   bool selectFCmp(Register ResVReg, const SPIRVType *ResType,
@@ -2154,6 +2157,20 @@ bool SPIRVInstructionSelector::selectSplatVector(Register ResVReg,
   return MIB.constrainAllUses(TII, TRI, RBI);
 }
 
+bool SPIRVInstructionSelector::selectClip(Register ResVReg,
+                                          const SPIRVType *ResType,
+                                          MachineInstr &I) const {
+
+  const auto Opcode =
+      STI.getTargetTriple().getVulkanVersion() < llvm::VersionTuple(1, 3)
+          ? SPIRV::OpKill
+          : SPIRV::OpDemoteToHelperInvocation;
+
+  MachineBasicBlock &BB = *I.getParent();
+  return BuildMI(BB, I, I.getDebugLoc(), TII.get(Opcode))
+      .constrainAllUses(TII, TRI, RBI);
+}
+
 bool SPIRVInstructionSelector::selectCmp(Register ResVReg,
                                          const SPIRVType *ResType,
                                          unsigned CmpOpc,
@@ -2809,6 +2826,9 @@ bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg,
     selectHandleFromBinding(ResVReg, ResType, I);
     return true;
   }
+  case Intrinsic::spv_clip: {
+    return selectClip(ResVReg, ResType, I);
+  }
   default: {
     std::string DiagMsg;
     raw_string_ostream OS(DiagMsg);
diff --git a/llvm/test/CodeGen/DirectX/clip.ll b/llvm/test/CodeGen/DirectX/clip.ll
new file mode 100644
index 00000000000000..54ff924675dbb3
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/clip.ll
@@ -0,0 +1,11 @@
+; RUN: opt -S -dxil-intrinsic-expansion -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-pixel %s | FileCheck %s
+
+; CHECK-LABEL: define void @test_dxil_lowering
+; CHECK: call void @dx.op.discard(i32 82, i1 %0)
+;
+define void @test_dxil_lowering(float noundef %p) #0 {
+entry:
+  %0 = fcmp olt float %p, 0.000000e+00
+  call void @llvm.dx.clip(i1 %0)
+  ret void
+}
diff --git a/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/clip.ll b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/clip.ll
new file mode 100644
index 00000000000000..4c133258f69ba2
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/clip.ll
@@ -0,0 +1,18 @@
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+
+
+; CHECK-LABEL: define void @test_dxil_lowering
+; CHECK: call void @dx.op.discard(i32 82, i1 %0)
+;
+define spir_func void @test_dxil_lowering(float noundef %Buf) #0 {
+entry:
+  %Buf.addr = alloca float, align 4
+  store float %Buf, ptr %Buf.addr, align 4
+  %1 = load float, ptr %Buf.addr, align 4
+  %2 = fcmp olt float %1, 0.000000e+00
+  call void @llvm.spv.clip(i1 %2)
+  ret void
+}
+
+declare void @llvm.spv.clip(i1) #1

>From b621ea88d0492949e3266686b4e4ea38b3602a75 Mon Sep 17 00:00:00 2001
From: Joao Saffran <jderezende at microsoft.com>
Date: Thu, 31 Oct 2024 19:30:14 +0000
Subject: [PATCH 3/5] adding tests

---
 clang/include/clang/Basic/Builtins.td         |  2 +-
 clang/lib/CodeGen/CGBuiltin.cpp               | 23 ++++++++++-
 clang/test/CodeGenHLSL/builtins/clip.hlsl     | 39 +++++++++++++++----
 .../Target/SPIRV/SPIRVInstructionSelector.cpp |  9 ++---
 .../CodeGen/SPIRV/hlsl-intrinsics/clip.ll     | 39 +++++++++++++++----
 5 files changed, 89 insertions(+), 23 deletions(-)

diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index bbbace6e193e66..a7197ffa33520b 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -4898,7 +4898,7 @@ def HLSLSplitDouble: LangBuiltin<"HLSL_LANG"> {
 def HLSLClip: LangBuiltin<"HLSL_LANG"> {
   let Spellings = ["__builtin_hlsl_elementwise_clip"];
   let Attributes = [NoThrow, Const];
-  let Prototype = "void(bool)";
+  let Prototype = "void(...)";
 }
 
 // Builtins for XRay.
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index f8244eb412be1b..7d3c9c9bd3305a 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -41,8 +41,10 @@
 #include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/Analysis/ValueTracking.h"
+#include "llvm/IR/Constants.h"
 #include "llvm/IR/DataLayout.h"
 #include "llvm/IR/InlineAsm.h"
+#include "llvm/IR/InstrTypes.h"
 #include "llvm/IR/Intrinsics.h"
 #include "llvm/IR/IntrinsicsAArch64.h"
 #include "llvm/IR/IntrinsicsAMDGPU.h"
@@ -55,12 +57,14 @@
 #include "llvm/IR/IntrinsicsR600.h"
 #include "llvm/IR/IntrinsicsRISCV.h"
 #include "llvm/IR/IntrinsicsS390.h"
+#include "llvm/IR/IntrinsicsSPIRV.h"
 #include "llvm/IR/IntrinsicsVE.h"
 #include "llvm/IR/IntrinsicsWebAssembly.h"
 #include "llvm/IR/IntrinsicsX86.h"
 #include "llvm/IR/MDBuilder.h"
 #include "llvm/IR/MatrixBuilder.h"
 #include "llvm/IR/MemoryModelRelaxationAnnotations.h"
+#include "llvm/IR/Type.h"
 #include "llvm/Support/AMDGPUAddrSpace.h"
 #include "llvm/Support/ConvertUTF.h"
 #include "llvm/Support/MathExtras.h"
@@ -101,13 +105,28 @@ static void initializeAlloca(CodeGenFunction &CGF, AllocaInst *AI, Value *Size,
 
 static Value *handleHlslClip(const CallExpr *E, CodeGenFunction *CGF) {
   Value *Op0 = CGF->EmitScalarExpr(E->getArg(0));
-  auto *CMP = CGF->Builder.CreateFCmpOLT(
-      Op0, ConstantFP::get(CGF->Builder.getFloatTy(), 0.0));
+
+  Constant *FZeroConst = ConstantFP::getZero(CGF->FloatTy);
+  Value *CMP;
+
+  if (const auto *VecTy = E->getArg(0)->getType()->getAs<clang::VectorType>()) {
+    FZeroConst = ConstantVector::getSplat(
+        ElementCount::getFixed(VecTy->getNumElements()), FZeroConst);
+    CMP = CGF->Builder.CreateFCmpOLT(Op0, FZeroConst);
+  } else
+    CMP = CGF->Builder.CreateFCmpOLT(Op0, FZeroConst);
 
   if (CGF->CGM.getTarget().getTriple().isDXIL())
     return CGF->Builder.CreateIntrinsic(CGF->VoidTy, llvm::Intrinsic::dx_clip,
                                         {CMP}, nullptr);
 
+  if (const auto *VecTy = E->getArg(0)->getType()->getAs<clang::VectorType>()){
+
+    CMP = CGF->Builder.CreateIntrinsic(CGF->Builder.getInt1Ty(), llvm::Intrinsic::spv_any,
+                                        {CMP}, nullptr);
+  }
+    
+
   BasicBlock *LT0 = CGF->createBasicBlock("lt0", CGF->CurFn);
   BasicBlock *End = CGF->createBasicBlock("end", CGF->CurFn);
 
diff --git a/clang/test/CodeGenHLSL/builtins/clip.hlsl b/clang/test/CodeGenHLSL/builtins/clip.hlsl
index 994a7c9f3311c3..0445db8a5d3e06 100644
--- a/clang/test/CodeGenHLSL/builtins/clip.hlsl
+++ b/clang/test/CodeGenHLSL/builtins/clip.hlsl
@@ -1,11 +1,36 @@
 // RUN: %clang_cc1 -finclude-default-header -x hlsl -triple dxil-pc-shadermodel6.3-pixel %s -fnative-half-type -emit-llvm -o - | FileCheck %s
-// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple spirv-vulkan-pixel %s -fnative-half-type -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple spirv-vulkan-pixel %s -fnative-half-type -emit-llvm -o - | FileCheck %s --check-prefix=SPIRV
 
-//CHECK-LABEL: define void @main()
-void test(float Buf) {
-  //CHECK: [[LOAD:%.*]] = load <4 x float>, ptr %p1{{.*}}, align 16
-  //CHECK-NEXT: [[EXTR:%.*]] = extractelement <4 x float> [[LOAD]], i32 3
-  //CHECK-NEXT: [[FCMP:%.*]] = fcmp olt float [[EXTR]], 0.000000e+00
-  //CHECK-NEXT: call void @llvm.dx.clip(i1 [[FCMP]])
+
+void test_scalar(float Buf) {
+  // CHECK:      define void @{{.*}}test_scalar{{.*}}(float {{.*}} [[VALP:%.*]])
+  // CHECK:      [[LOAD:%.*]] = load float, ptr [[VALP]].addr, align 4
+  // CHECK-NEXT: [[FCMP:%.*]] = fcmp olt float [[LOAD]], 0.000000e+00
+  // CHECK-NEXT: call void @llvm.dx.clip.i1(i1 [[FCMP]])
+  //
+  // SPIRV:      define spir_func void @{{.*}}test_scalar{{.*}}(float {{.*}} [[VALP:%.*]])
+  // SPIRV:      [[LOAD:%.*]] = load float, ptr [[VALP]].addr, align 4
+  // SPIRV-NEXT: [[FCMP:%.*]] = fcmp olt float [[LOAD]], 0.000000e+00
+  // SPIRV-NEXT: br i1 [[FCMP]], label %[[LTL:.*]], label %[[ENDL:.*]]
+  // SPIRV: [[LTL]]: ; preds = %entry
+  // SPIRV-NEXT: call void @llvm.spv.clip()
+  // SPIRV: br label %[[ENDL]]
+  clip(Buf);
+}
+
+void test_vector4(float4 Buf) {
+  // CHECK:      define void @{{.*}}test_vector{{.*}}(<4 x float> {{.*}} [[VALP:%.*]])
+  // CHECK:      [[LOAD:%.*]] = load <4 x float>, ptr [[VALP]].addr, align 16
+  // CHECK-NEXT: [[FCMP:%.*]] = fcmp olt <4 x float> [[LOAD]], zeroinitializer
+  // CHECK-NEXT: call void @llvm.dx.clip.v4i1(<4 x i1> [[FCMP]])
+  //
+  // SPIRV:      define spir_func void @{{.*}}test_vector{{.*}}(<4 x float> {{.*}} [[VALP:%.*]])
+  // SPIRV:      [[LOAD:%.*]] = load <4 x float>, ptr [[VALP]].addr, align 16
+  // SPIRV-NEXT: [[FCMP:%.*]] = fcmp olt <4 x float> [[LOAD]], zeroinitializer
+  // SPIRV-NEXT: [[RED:%.*]] = call i1 @llvm.vector.reduce.or.v4i1(<4 x i1> [[FCMP]])
+  // SPIRV-NEXT: br i1 [[RED]], label %[[LTL:.*]], label %[[ENDL:.*]]
+  // SPIRV: [[LTL]]: ; preds = %entry
+  // SPIRV-NEXT: call void @llvm.spv.clip()
+  // SPIRV-NEXT: br label %[[ENDL]]
   clip(Buf);
 }
diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
index 8e43df58f7a631..c3fcbe77d43f7c 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
@@ -32,6 +32,7 @@
 #include "llvm/CodeGen/TargetOpcodes.h"
 #include "llvm/IR/IntrinsicsSPIRV.h"
 #include "llvm/Support/Debug.h"
+#include "llvm/Support/VersionTuple.h"
 
 #define DEBUG_TYPE "spirv-isel"
 
@@ -2160,11 +2161,9 @@ bool SPIRVInstructionSelector::selectSplatVector(Register ResVReg,
 bool SPIRVInstructionSelector::selectClip(Register ResVReg,
                                           const SPIRVType *ResType,
                                           MachineInstr &I) const {
-
-  const auto Opcode =
-      STI.getTargetTriple().getVulkanVersion() < llvm::VersionTuple(1, 3)
-          ? SPIRV::OpKill
-          : SPIRV::OpDemoteToHelperInvocation;
+  const auto Opcode = (STI.isAtLeastSPIRVVer(VersionTuple(1, 6)))
+                          ? SPIRV::OpDemoteToHelperInvocation
+                          : SPIRV::OpKill;
 
   MachineBasicBlock &BB = *I.getParent();
   return BuildMI(BB, I, I.getDebugLoc(), TII.get(Opcode))
diff --git a/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/clip.ll b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/clip.ll
index 4c133258f69ba2..8c1214c9e67cbc 100644
--- a/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/clip.ll
+++ b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/clip.ll
@@ -2,17 +2,40 @@
 ; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %}
 
 
-; CHECK-LABEL: define void @test_dxil_lowering
-; CHECK: call void @dx.op.discard(i32 82, i1 %0)
-;
-define spir_func void @test_dxil_lowering(float noundef %Buf) #0 {
+define void @test_scalar_lowering(float noundef %Buf) {
 entry:
   %Buf.addr = alloca float, align 4
   store float %Buf, ptr %Buf.addr, align 4
-  %1 = load float, ptr %Buf.addr, align 4
-  %2 = fcmp olt float %1, 0.000000e+00
-  call void @llvm.spv.clip(i1 %2)
+  %0 = load float, ptr %Buf.addr, align 4
+  %1 = fcmp olt float %0, 0.000000e+00
+  br i1 %1, label %lt0, label %end
+
+lt0:                                              ; preds = %entry
+  call void @llvm.spv.clip()
+  br label %end
+
+end:                                              ; preds = %lt0, %entry
+  ret void
+}
+
+declare void @llvm.spv.clip()
+
+
+define void @test_vector(<4 x float> noundef %Buf) {
+entry:
+  %Buf.addr = alloca <4 x float>, align 16
+  store <4 x float> %Buf, ptr %Buf.addr, align 16
+  %1 = load <4 x float>, ptr %Buf.addr, align 16
+  %2 = fcmp olt <4 x float> %1, zeroinitializer
+  %3 = call i1 @llvm.vector.reduce.or.v4i1(<4 x i1> %2)
+  br i1 %3, label %lt0, label %end
+
+lt0:                                              ; preds = %entry
+  call void @llvm.spv.clip()
+  br label %end
+
+end:                                              ; preds = %lt0, %entry
   ret void
 }
 
-declare void @llvm.spv.clip(i1) #1
+declare i1 @llvm.vector.reduce.or.v4i1(<4 x i1>) #3

>From 2b225101089204285a180be5beef825040d011f8 Mon Sep 17 00:00:00 2001
From: Joao Saffran <jderezende at microsoft.com>
Date: Fri, 1 Nov 2024 18:11:35 +0000
Subject: [PATCH 4/5] adding tests

---
 clang/lib/CodeGen/CGBuiltin.cpp               | 24 +++-----
 clang/test/CodeGenHLSL/builtins/clip.hlsl     | 17 +++---
 clang/test/SemaHLSL/BuiltIns/clip-errors.hlsl | 22 ++++++++
 llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp    |  4 +-
 .../Target/SPIRV/SPIRVInstructionSelector.cpp | 21 +++++--
 llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp | 11 ++++
 .../lib/Target/SPIRV/SPIRVSymbolicOperands.td |  1 +
 llvm/test/CodeGen/DirectX/clip.ll             | 24 +++++++-
 .../CodeGen/SPIRV/hlsl-intrinsics/clip.ll     | 56 +++++++++++++++----
 9 files changed, 139 insertions(+), 41 deletions(-)
 create mode 100644 clang/test/SemaHLSL/BuiltIns/clip-errors.hlsl

diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 7d3c9c9bd3305a..85302feb1950ba 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -41,10 +41,8 @@
 #include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/Analysis/ValueTracking.h"
-#include "llvm/IR/Constants.h"
 #include "llvm/IR/DataLayout.h"
 #include "llvm/IR/InlineAsm.h"
-#include "llvm/IR/InstrTypes.h"
 #include "llvm/IR/Intrinsics.h"
 #include "llvm/IR/IntrinsicsAArch64.h"
 #include "llvm/IR/IntrinsicsAMDGPU.h"
@@ -57,14 +55,12 @@
 #include "llvm/IR/IntrinsicsR600.h"
 #include "llvm/IR/IntrinsicsRISCV.h"
 #include "llvm/IR/IntrinsicsS390.h"
-#include "llvm/IR/IntrinsicsSPIRV.h"
 #include "llvm/IR/IntrinsicsVE.h"
 #include "llvm/IR/IntrinsicsWebAssembly.h"
 #include "llvm/IR/IntrinsicsX86.h"
 #include "llvm/IR/MDBuilder.h"
 #include "llvm/IR/MatrixBuilder.h"
 #include "llvm/IR/MemoryModelRelaxationAnnotations.h"
-#include "llvm/IR/Type.h"
 #include "llvm/Support/AMDGPUAddrSpace.h"
 #include "llvm/Support/ConvertUTF.h"
 #include "llvm/Support/MathExtras.h"
@@ -112,7 +108,10 @@ static Value *handleHlslClip(const CallExpr *E, CodeGenFunction *CGF) {
   if (const auto *VecTy = E->getArg(0)->getType()->getAs<clang::VectorType>()) {
     FZeroConst = ConstantVector::getSplat(
         ElementCount::getFixed(VecTy->getNumElements()), FZeroConst);
-    CMP = CGF->Builder.CreateFCmpOLT(Op0, FZeroConst);
+    auto *FCompInst = CGF->Builder.CreateFCmpOLT(Op0, FZeroConst);
+    CMP = CGF->Builder.CreateIntrinsic(
+        CGF->Builder.getInt1Ty(), CGF->CGM.getHLSLRuntime().getAnyIntrinsic(),
+        {FCompInst}, nullptr);
   } else
     CMP = CGF->Builder.CreateFCmpOLT(Op0, FZeroConst);
 
@@ -120,13 +119,6 @@ static Value *handleHlslClip(const CallExpr *E, CodeGenFunction *CGF) {
     return CGF->Builder.CreateIntrinsic(CGF->VoidTy, llvm::Intrinsic::dx_clip,
                                         {CMP}, nullptr);
 
-  if (const auto *VecTy = E->getArg(0)->getType()->getAs<clang::VectorType>()){
-
-    CMP = CGF->Builder.CreateIntrinsic(CGF->Builder.getInt1Ty(), llvm::Intrinsic::spv_any,
-                                        {CMP}, nullptr);
-  }
-    
-
   BasicBlock *LT0 = CGF->createBasicBlock("lt0", CGF->CurFn);
   BasicBlock *End = CGF->createBasicBlock("end", CGF->CurFn);
 
@@ -134,13 +126,13 @@ static Value *handleHlslClip(const CallExpr *E, CodeGenFunction *CGF) {
 
   CGF->Builder.SetInsertPoint(LT0);
 
-  auto *IntrCall = CGF->Builder.CreateIntrinsic(
-      CGF->VoidTy, llvm::Intrinsic::spv_clip, {}, nullptr);
+  CGF->Builder.CreateIntrinsic(CGF->VoidTy, llvm::Intrinsic::spv_clip, {},
+                               nullptr);
 
-  CGF->Builder.CreateBr(End);
+  auto *BrCall = CGF->Builder.CreateBr(End);
 
   CGF->Builder.SetInsertPoint(End);
-  return IntrCall;
+  return BrCall;
 }
 
 static Value *handleHlslSplitdouble(const CallExpr *E, CodeGenFunction *CGF) {
diff --git a/clang/test/CodeGenHLSL/builtins/clip.hlsl b/clang/test/CodeGenHLSL/builtins/clip.hlsl
index 0445db8a5d3e06..81976839bbe7d9 100644
--- a/clang/test/CodeGenHLSL/builtins/clip.hlsl
+++ b/clang/test/CodeGenHLSL/builtins/clip.hlsl
@@ -6,15 +6,17 @@ void test_scalar(float Buf) {
   // CHECK:      define void @{{.*}}test_scalar{{.*}}(float {{.*}} [[VALP:%.*]])
   // CHECK:      [[LOAD:%.*]] = load float, ptr [[VALP]].addr, align 4
   // CHECK-NEXT: [[FCMP:%.*]] = fcmp olt float [[LOAD]], 0.000000e+00
-  // CHECK-NEXT: call void @llvm.dx.clip.i1(i1 [[FCMP]])
+  // CHECK-NO:   call i1 @llvm.dx.any
+  // CHECK-NEXT: call void @llvm.dx.clip(i1 [[FCMP]])
   //
   // SPIRV:      define spir_func void @{{.*}}test_scalar{{.*}}(float {{.*}} [[VALP:%.*]])
   // SPIRV:      [[LOAD:%.*]] = load float, ptr [[VALP]].addr, align 4
   // SPIRV-NEXT: [[FCMP:%.*]] = fcmp olt float [[LOAD]], 0.000000e+00
+  // SPIRV-NO:   call i1 @llvm.dx.any
   // SPIRV-NEXT: br i1 [[FCMP]], label %[[LTL:.*]], label %[[ENDL:.*]]
-  // SPIRV: [[LTL]]: ; preds = %entry
+  // SPIRV:      [[LTL]]: ; preds = %entry
   // SPIRV-NEXT: call void @llvm.spv.clip()
-  // SPIRV: br label %[[ENDL]]
+  // SPIRV:      br label %[[ENDL]]
   clip(Buf);
 }
 
@@ -22,14 +24,15 @@ void test_vector4(float4 Buf) {
   // CHECK:      define void @{{.*}}test_vector{{.*}}(<4 x float> {{.*}} [[VALP:%.*]])
   // CHECK:      [[LOAD:%.*]] = load <4 x float>, ptr [[VALP]].addr, align 16
   // CHECK-NEXT: [[FCMP:%.*]] = fcmp olt <4 x float> [[LOAD]], zeroinitializer
-  // CHECK-NEXT: call void @llvm.dx.clip.v4i1(<4 x i1> [[FCMP]])
+  // CHECK-NEXT: [[ANYC:%.*]] = call i1 @llvm.dx.any.v4i1(<4 x i1> [[FCMP]])
+  // CHECK-NEXT: call void @llvm.dx.clip(i1 [[ANYC]])
   //
   // SPIRV:      define spir_func void @{{.*}}test_vector{{.*}}(<4 x float> {{.*}} [[VALP:%.*]])
   // SPIRV:      [[LOAD:%.*]] = load <4 x float>, ptr [[VALP]].addr, align 16
   // SPIRV-NEXT: [[FCMP:%.*]] = fcmp olt <4 x float> [[LOAD]], zeroinitializer
-  // SPIRV-NEXT: [[RED:%.*]] = call i1 @llvm.vector.reduce.or.v4i1(<4 x i1> [[FCMP]])
-  // SPIRV-NEXT: br i1 [[RED]], label %[[LTL:.*]], label %[[ENDL:.*]]
-  // SPIRV: [[LTL]]: ; preds = %entry
+  // SPIRV-NEXT: [[ANYC:%.*]] = call i1 @llvm.spv.any.v4i1(<4 x i1> [[FCMP]]) 
+  // SPIRV-NEXT: br i1 [[ANYC]], label %[[LTL:.*]], label %[[ENDL:.*]]
+  // SPIRV:      [[LTL]]: ; preds = %entry
   // SPIRV-NEXT: call void @llvm.spv.clip()
   // SPIRV-NEXT: br label %[[ENDL]]
   clip(Buf);
diff --git a/clang/test/SemaHLSL/BuiltIns/clip-errors.hlsl b/clang/test/SemaHLSL/BuiltIns/clip-errors.hlsl
new file mode 100644
index 00000000000000..570b4bc18dcd4b
--- /dev/null
+++ b/clang/test/SemaHLSL/BuiltIns/clip-errors.hlsl
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -fnative-half-type -verify
+
+
+void test_arg_missing() {
+  __builtin_hlsl_elementwise_clip();
+ // expected-error at -1 {{too few arguments to function call, expected 1, have 0}} 
+}
+
+void test_too_many_args(float p1, float p2) {
+  __builtin_hlsl_elementwise_clip(p1, p2);
+ // expected-error at -1 {{too many arguments to function call, expected 1, have 2}} 
+}
+
+void test_first_arg_type_mismatch(bool p) {
+  __builtin_hlsl_elementwise_clip(p);
+ // expected-error at -1 {{invalid operand of type 'bool' where 'float' or a vector of such type is required}} 
+}
+
+void test_first_arg_type_mismatch_2(half p) {
+  __builtin_hlsl_elementwise_clip(p);
+ // expected-error at -1 {{invalid operand of type 'double' where 'float' or a vector of such type is required}} 
+}
diff --git a/llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp b/llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp
index e58366017966a7..86f9c785b7652e 100644
--- a/llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp
@@ -75,7 +75,9 @@ static const std::map<std::string, SPIRV::Extension::Extension>
         {"SPV_KHR_cooperative_matrix",
          SPIRV::Extension::Extension::SPV_KHR_cooperative_matrix},
         {"SPV_KHR_non_semantic_info",
-         SPIRV::Extension::Extension::SPV_KHR_non_semantic_info}};
+         SPIRV::Extension::Extension::SPV_KHR_non_semantic_info},
+        {"SPV_EXT_demote_to_helper_invocation",
+         SPIRV::Extension::Extension::SPV_EXT_demote_to_helper_invocation}};
 
 bool SPIRVExtensionsParser::parse(cl::Option &O, llvm::StringRef ArgName,
                                   llvm::StringRef ArgValue,
diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
index c3fcbe77d43f7c..13c2e7ed340431 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
@@ -32,7 +32,6 @@
 #include "llvm/CodeGen/TargetOpcodes.h"
 #include "llvm/IR/IntrinsicsSPIRV.h"
 #include "llvm/Support/Debug.h"
-#include "llvm/Support/VersionTuple.h"
 
 #define DEBUG_TYPE "spirv-isel"
 
@@ -2161,9 +2160,23 @@ bool SPIRVInstructionSelector::selectSplatVector(Register ResVReg,
 bool SPIRVInstructionSelector::selectClip(Register ResVReg,
                                           const SPIRVType *ResType,
                                           MachineInstr &I) const {
-  const auto Opcode = (STI.isAtLeastSPIRVVer(VersionTuple(1, 6)))
-                          ? SPIRV::OpDemoteToHelperInvocation
-                          : SPIRV::OpKill;
+
+  unsigned Opcode;
+
+  if (STI.isAtLeastSPIRVVer(VersionTuple(1, 6))) {
+    if (!STI.canUseExtension(
+            SPIRV::Extension::SPV_EXT_demote_to_helper_invocation))
+      report_fatal_error(
+          "llvm.spv.clip intrinsic: this instruction requires the following "
+          "SPIR-V extension: SPV_EXT_demote_to_helper_invocation",
+          false);
+    Opcode = SPIRV::OpDemoteToHelperInvocation;
+  } else {
+    Opcode = SPIRV::OpKill;
+    // OpKill must be the last operation of any basic block.
+    MachineInstr *NextI = I.getNextNode();
+    NextI->removeFromParent();
+  }
 
   MachineBasicBlock &BB = *I.getParent();
   return BuildMI(BB, I, I.getDebugLoc(), TII.get(Opcode))
diff --git a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
index e8641b3a105dec..f0aaeb1b60c9bd 100644
--- a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
@@ -1411,6 +1411,17 @@ void addInstrRequirements(const MachineInstr &MI,
   case SPIRV::OpUDot:
     AddDotProductRequirements(MI, Reqs, ST);
     break;
+
+  case SPIRV::OpKill: {
+    Reqs.addCapability(SPIRV::Capability::Shader);
+  } break;
+  case SPIRV::OpDemoteToHelperInvocation:
+    if (ST.canUseExtension(
+            SPIRV::Extension::SPV_EXT_demote_to_helper_invocation)) {
+      Reqs.addExtension(SPIRV::Extension::SPV_EXT_demote_to_helper_invocation);
+      Reqs.addCapability(SPIRV::Capability::DemoteToHelperInvocation);
+    }
+    break;
   default:
     break;
   }
diff --git a/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td b/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td
index 5a00a7785b7745..4ae247bafb684f 100644
--- a/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td
+++ b/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td
@@ -456,6 +456,7 @@ defm VulkanMemoryModelDeviceScopeKHR : CapabilityOperand<5346, 0, 0, [], []>;
 defm ImageFootprintNV : CapabilityOperand<5282, 0, 0, [], []>;
 defm FragmentBarycentricNV : CapabilityOperand<5284, 0, 0, [], []>;
 defm ComputeDerivativeGroupQuadsNV : CapabilityOperand<5288, 0, 0, [], []>;
+defm DemoteToHelperInvocation : CapabilityOperand<5379, 0, 0, [SPV_EXT_demote_to_helper_invocation], []>;
 defm ComputeDerivativeGroupLinearNV : CapabilityOperand<5350, 0, 0, [], []>;
 defm FragmentDensityEXT : CapabilityOperand<5291, 0, 0, [], [Shader]>;
 defm PhysicalStorageBufferAddressesEXT : CapabilityOperand<5347, 0, 0, [], [Shader]>;
diff --git a/llvm/test/CodeGen/DirectX/clip.ll b/llvm/test/CodeGen/DirectX/clip.ll
index 54ff924675dbb3..71789e7048363a 100644
--- a/llvm/test/CodeGen/DirectX/clip.ll
+++ b/llvm/test/CodeGen/DirectX/clip.ll
@@ -1,11 +1,29 @@
-; RUN: opt -S -dxil-intrinsic-expansion -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-pixel %s | FileCheck %s
+; RUN: opt -passes='function(scalarizer),module(dxil-op-lower,dxil-intrinsic-expansion)' -S -mtriple=dxil-pc-shadermodel6.3-pixel %s | FileCheck %s
 
-; CHECK-LABEL: define void @test_dxil_lowering
+; CHECK-LABEL: define void @test_scalar
 ; CHECK: call void @dx.op.discard(i32 82, i1 %0)
 ;
-define void @test_dxil_lowering(float noundef %p) #0 {
+define void @test_scalar(float noundef %p) #0 {
 entry:
   %0 = fcmp olt float %p, 0.000000e+00
   call void @llvm.dx.clip(i1 %0)
   ret void
 }
+
+; CHECK-LABEL: define void @test_vector
+; CHECK:       [[EXTR0:%.*]] = extractelement <4 x i1> [[INP:%.*]], i64 0
+; CHECK-NEXT:  [[EXTR1:%.*]] = extractelement <4 x i1> [[INP:%.*]], i64 1
+; CHECK-NEXT:  [[OR1:%.*]] = or i1 [[EXTR0]], [[EXTR1]]
+; CHECK-NEXT:  [[EXTR2:%.*]] = extractelement <4 x i1> [[INP:%.*]], i64 2
+; CHECK-NEXT:  [[OR2:%.*]] = or i1 [[OR1]], [[EXTR2]]
+; CHECK-NEXT:  [[EXTR3:%.*]] = extractelement <4 x i1> [[INP:%.*]], i64 3
+; CHECK-NEXT:  [[OR3:%.*]] = or i1 [[OR2]], [[EXTR3]]
+; CHECK-NEXT:  call void @dx.op.discard(i32 82, i1 [[OR3]])
+;
+define void @test_vector(<4 x float> noundef %p) #0 {
+entry:
+  %0 = fcmp olt <4 x float> %p, zeroinitializer
+  %1 = call i1 @llvm.dx.any.v4i1(<4 x i1> %0)
+  call void @llvm.dx.clip(i1 %1)
+  ret void
+}
diff --git a/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/clip.ll b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/clip.ll
index 8c1214c9e67cbc..89db4be3494ebd 100644
--- a/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/clip.ll
+++ b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/clip.ll
@@ -1,14 +1,40 @@
-; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s --check-prefixes=CHECK,SPIRV15
+; RUN: llc -verify-machineinstrs -spirv-ext=+SPV_EXT_demote_to_helper_invocation -O0 -mtriple=spirv32v1.6-unknown-unknown %s -o - | FileCheck %s --check-prefixes=CHECK,SPIRV16
 ; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %}
 
 
-define void @test_scalar_lowering(float noundef %Buf) {
+; Make sure lowering is correctly generating spirv code.
+
+; CHECK-DAG:   %[[#float:]] = OpTypeFloat 32
+; CHECK-DAG:   %[[#void:]]  = OpTypeVoid
+; CHECK-DAG:   %[[#bool:]]  = OpTypeBool
+; CHECK-DAG:   %[[#v4bool:]]  = OpTypeVector %[[#bool]] 4
+; CHECK-DAG:   %[[#v4float:]] = OpTypeVector %[[#float]] 4
+; CHECK-DAG:   %[[#fzero:]] = OpConstant %[[#float]] 0
+; CHECK-DAG:   %[[#v4fzero:]] = OpConstantNull %[[#v4float]]
+; SPIRV16-DAG: %[[#vecfuncopptr:]] = OpTypePointer Function %[[#v4float]]
+; SPIRV16-DAG: %[[#funcopptr:]] = OpTypePointer Function %[[#float]]
+
+define void @test_scalar(float noundef %Buf) {
 entry:
+; CHECK-LABEL: ; -- Begin function test_scalar
+; SPIRV16:     %[[#param:]] = OpVariable %[[#funcopptr]] Function
+; SPIRV16:     %[[#load:]] = OpLoad %[[#float]] %[[#param]] Aligned 4
+; SPIRV15:     %[[#load:]] = OpFunctionParameter %[[#float]]
+; CHECK:       %[[#cmplt:]] = OpFOrdLessThan %[[#bool]] %[[#load]] %[[#fzero]]
+; CHECK:       OpBranchConditional %[[#cmplt]] %[[#truel:]] %[[#endl:]]
+; CHECK:       %[[#truel]] = OpLabel
+; SPIRV15:     OpKill
+; SPIRV16-NO:  OpKill
+; SPIRV15-NO:  OpBranch %[[#endl]]
+; SPIRV16:     OpDemoteToHelperInvocation
+; SPIRV16:     OpBranch %[[#endl]]
+; CHECK:       %[[#endl]] = OpLabel
   %Buf.addr = alloca float, align 4
   store float %Buf, ptr %Buf.addr, align 4
-  %0 = load float, ptr %Buf.addr, align 4
-  %1 = fcmp olt float %0, 0.000000e+00
-  br i1 %1, label %lt0, label %end
+  %1 = load float, ptr %Buf.addr, align 4
+  %2 = fcmp olt float %1, 0.000000e+00
+  br i1 %2, label %lt0, label %end
 
 lt0:                                              ; preds = %entry
   call void @llvm.spv.clip()
@@ -17,17 +43,29 @@ lt0:                                              ; preds = %entry
 end:                                              ; preds = %lt0, %entry
   ret void
 }
-
 declare void @llvm.spv.clip()
 
-
 define void @test_vector(<4 x float> noundef %Buf) {
 entry:
+; CHECK-LABEL: ; -- Begin function test_vector
+; SPIRV16:     %[[#param:]] = OpVariable %[[#vecfuncopptr]] Function
+; SPIRV16:     %[[#loadvec:]] = OpLoad %[[#v4float]] %[[#param]] Aligned 16
+; SPIRV15:     %[[#loadvec:]] = OpFunctionParameter %[[#v4float]]
+; CHECK:       %[[#cmplt:]] = OpFOrdLessThan %[[#v4bool]] %[[#loadvec]] %[[#v4fzero]]
+; CHECK:       %[[#opany:]] = OpAny %[[#bool]] %[[#cmplt]]
+; CHECK:       OpBranchConditional %[[#opany]]  %[[#truel:]] %[[#endl:]]
+; CHECK:       %[[#truel]] = OpLabel
+; SPIRV15:     OpKill
+; SPIRV16-NO:  OpKill
+; SPIRV15-NO:  OpBranch %[[#endl]]
+; SPIRV16:     OpDemoteToHelperInvocation
+; SPIRV16:     OpBranch %[[#endl]]
+; CHECK:       %[[#endl]] = OpLabel
   %Buf.addr = alloca <4 x float>, align 16
   store <4 x float> %Buf, ptr %Buf.addr, align 16
   %1 = load <4 x float>, ptr %Buf.addr, align 16
   %2 = fcmp olt <4 x float> %1, zeroinitializer
-  %3 = call i1 @llvm.vector.reduce.or.v4i1(<4 x i1> %2)
+  %3 = call i1 @llvm.spv.any.v4i1(<4 x i1> %2)
   br i1 %3, label %lt0, label %end
 
 lt0:                                              ; preds = %entry
@@ -37,5 +75,3 @@ lt0:                                              ; preds = %entry
 end:                                              ; preds = %lt0, %entry
   ret void
 }
-
-declare i1 @llvm.vector.reduce.or.v4i1(<4 x i1>) #3

>From 2e1f4dd70aadfdbf81c1eb4893c2a056c71c8cf3 Mon Sep 17 00:00:00 2001
From: Joao Saffran <jderezende at microsoft.com>
Date: Fri, 8 Nov 2024 07:06:52 +0000
Subject: [PATCH 5/5] addressing pr comments

---
 clang/lib/CodeGen/CGBuiltin.cpp               | 28 +++++++++-------
 clang/lib/CodeGen/CGHLSLRuntime.h             |  1 -
 clang/test/CodeGenHLSL/builtins/clip.hlsl     | 10 +++---
 clang/test/SemaHLSL/BuiltIns/clip-errors.hlsl |  7 +++-
 llvm/docs/SPIRVUsage.rst                      |  2 ++
 llvm/include/llvm/IR/IntrinsicsDirectX.td     |  2 +-
 llvm/include/llvm/IR/IntrinsicsSPIRV.td       |  2 +-
 llvm/lib/Target/DirectX/DXIL.td               | 33 +++----------------
 llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp    |  6 ++--
 .../Target/SPIRV/SPIRVInstructionSelector.cpp | 24 ++++++--------
 llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp | 19 ++++++-----
 .../lib/Target/SPIRV/SPIRVSymbolicOperands.td |  2 +-
 llvm/test/CodeGen/DirectX/clip.ll             |  6 ++--
 .../CodeGen/SPIRV/hlsl-intrinsics/clip.ll     | 28 ++++++++--------
 14 files changed, 79 insertions(+), 91 deletions(-)

diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 85302feb1950ba..85e0a0f9f45349 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -104,6 +104,7 @@ static Value *handleHlslClip(const CallExpr *E, CodeGenFunction *CGF) {
 
   Constant *FZeroConst = ConstantFP::getZero(CGF->FloatTy);
   Value *CMP;
+  Value *LastInstr;
 
   if (const auto *VecTy = E->getArg(0)->getType()->getAs<clang::VectorType>()) {
     FZeroConst = ConstantVector::getSplat(
@@ -116,23 +117,27 @@ static Value *handleHlslClip(const CallExpr *E, CodeGenFunction *CGF) {
     CMP = CGF->Builder.CreateFCmpOLT(Op0, FZeroConst);
 
   if (CGF->CGM.getTarget().getTriple().isDXIL())
-    return CGF->Builder.CreateIntrinsic(CGF->VoidTy, llvm::Intrinsic::dx_clip,
-                                        {CMP}, nullptr);
+    LastInstr = CGF->Builder.CreateIntrinsic(
+        CGF->VoidTy, llvm::Intrinsic::dx_discard, {CMP}, nullptr);
+  else if (CGF->CGM.getTarget().getTriple().isSPIRV()) {
+    BasicBlock *LT0 = CGF->createBasicBlock("lt0", CGF->CurFn);
+    BasicBlock *End = CGF->createBasicBlock("end", CGF->CurFn);
 
-  BasicBlock *LT0 = CGF->createBasicBlock("lt0", CGF->CurFn);
-  BasicBlock *End = CGF->createBasicBlock("end", CGF->CurFn);
+    CGF->Builder.CreateCondBr(CMP, LT0, End);
 
-  CGF->Builder.CreateCondBr(CMP, LT0, End);
+    CGF->Builder.SetInsertPoint(LT0);
 
-  CGF->Builder.SetInsertPoint(LT0);
+    CGF->Builder.CreateIntrinsic(CGF->VoidTy, llvm::Intrinsic::spv_discard, {},
+                                 nullptr);
 
-  CGF->Builder.CreateIntrinsic(CGF->VoidTy, llvm::Intrinsic::spv_clip, {},
-                               nullptr);
+    LastInstr = CGF->Builder.CreateBr(End);
 
-  auto *BrCall = CGF->Builder.CreateBr(End);
+    CGF->Builder.SetInsertPoint(End);
+  } else {
+    llvm_unreachable("Backend Codegen not supported.");
+  }
 
-  CGF->Builder.SetInsertPoint(End);
-  return BrCall;
+  return LastInstr;
 }
 
 static Value *handleHlslSplitdouble(const CallExpr *E, CodeGenFunction *CGF) {
@@ -19217,7 +19222,6 @@ case Builtin::BI__builtin_hlsl_elementwise_isinf: {
     return handleHlslSplitdouble(E, this);
   }
   case Builtin::BI__builtin_hlsl_elementwise_clip:
-
     assert(E->getArg(0)->getType()->hasFloatingRepresentation() &&
            "clip operands types mismatch");
     return handleHlslClip(E, this);
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h
index a1089595683a3d..381a5959ec098e 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.h
+++ b/clang/lib/CodeGen/CGHLSLRuntime.h
@@ -94,7 +94,6 @@ class CGHLSLRuntime {
   GENERATE_HLSL_INTRINSIC_FUNCTION(WaveActiveCountBits, wave_active_countbits)
   GENERATE_HLSL_INTRINSIC_FUNCTION(WaveIsFirstLane, wave_is_first_lane)
   GENERATE_HLSL_INTRINSIC_FUNCTION(WaveReadLaneAt, wave_readlane)
-  GENERATE_HLSL_INTRINSIC_FUNCTION(Clip, clip)  
   GENERATE_HLSL_INTRINSIC_FUNCTION(FirstBitUHigh, firstbituhigh)
   GENERATE_HLSL_INTRINSIC_FUNCTION(FirstBitSHigh, firstbitshigh)
   GENERATE_HLSL_INTRINSIC_FUNCTION(NClamp, nclamp)
diff --git a/clang/test/CodeGenHLSL/builtins/clip.hlsl b/clang/test/CodeGenHLSL/builtins/clip.hlsl
index 81976839bbe7d9..73839ae47f5904 100644
--- a/clang/test/CodeGenHLSL/builtins/clip.hlsl
+++ b/clang/test/CodeGenHLSL/builtins/clip.hlsl
@@ -7,15 +7,15 @@ void test_scalar(float Buf) {
   // CHECK:      [[LOAD:%.*]] = load float, ptr [[VALP]].addr, align 4
   // CHECK-NEXT: [[FCMP:%.*]] = fcmp olt float [[LOAD]], 0.000000e+00
   // CHECK-NO:   call i1 @llvm.dx.any
-  // CHECK-NEXT: call void @llvm.dx.clip(i1 [[FCMP]])
+  // CHECK-NEXT: call void @llvm.dx.discard(i1 [[FCMP]])
   //
   // SPIRV:      define spir_func void @{{.*}}test_scalar{{.*}}(float {{.*}} [[VALP:%.*]])
   // SPIRV:      [[LOAD:%.*]] = load float, ptr [[VALP]].addr, align 4
   // SPIRV-NEXT: [[FCMP:%.*]] = fcmp olt float [[LOAD]], 0.000000e+00
-  // SPIRV-NO:   call i1 @llvm.dx.any
+  // SPIRV-NO:   call i1 @llvm.spv.any
   // SPIRV-NEXT: br i1 [[FCMP]], label %[[LTL:.*]], label %[[ENDL:.*]]
   // SPIRV:      [[LTL]]: ; preds = %entry
-  // SPIRV-NEXT: call void @llvm.spv.clip()
+  // SPIRV-NEXT: call void @llvm.spv.discard()
   // SPIRV:      br label %[[ENDL]]
   clip(Buf);
 }
@@ -25,7 +25,7 @@ void test_vector4(float4 Buf) {
   // CHECK:      [[LOAD:%.*]] = load <4 x float>, ptr [[VALP]].addr, align 16
   // CHECK-NEXT: [[FCMP:%.*]] = fcmp olt <4 x float> [[LOAD]], zeroinitializer
   // CHECK-NEXT: [[ANYC:%.*]] = call i1 @llvm.dx.any.v4i1(<4 x i1> [[FCMP]])
-  // CHECK-NEXT: call void @llvm.dx.clip(i1 [[ANYC]])
+  // CHECK-NEXT: call void @llvm.dx.discard(i1 [[ANYC]])
   //
   // SPIRV:      define spir_func void @{{.*}}test_vector{{.*}}(<4 x float> {{.*}} [[VALP:%.*]])
   // SPIRV:      [[LOAD:%.*]] = load <4 x float>, ptr [[VALP]].addr, align 16
@@ -33,7 +33,7 @@ void test_vector4(float4 Buf) {
   // SPIRV-NEXT: [[ANYC:%.*]] = call i1 @llvm.spv.any.v4i1(<4 x i1> [[FCMP]]) 
   // SPIRV-NEXT: br i1 [[ANYC]], label %[[LTL:.*]], label %[[ENDL:.*]]
   // SPIRV:      [[LTL]]: ; preds = %entry
-  // SPIRV-NEXT: call void @llvm.spv.clip()
+  // SPIRV-NEXT: call void @llvm.spv.discard()
   // SPIRV-NEXT: br label %[[ENDL]]
   clip(Buf);
 }
diff --git a/clang/test/SemaHLSL/BuiltIns/clip-errors.hlsl b/clang/test/SemaHLSL/BuiltIns/clip-errors.hlsl
index 570b4bc18dcd4b..871e512e128c54 100644
--- a/clang/test/SemaHLSL/BuiltIns/clip-errors.hlsl
+++ b/clang/test/SemaHLSL/BuiltIns/clip-errors.hlsl
@@ -16,7 +16,12 @@ void test_first_arg_type_mismatch(bool p) {
  // expected-error at -1 {{invalid operand of type 'bool' where 'float' or a vector of such type is required}} 
 }
 
-void test_first_arg_type_mismatch_2(half p) {
+void test_first_arg_type_mismatch_3(half3 p) {
+  __builtin_hlsl_elementwise_clip(p);
+ // expected-error at -1 {{invalid operand of type 'half3' (aka 'vector<half, 3>') where 'float' or a vector of such type is required}} 
+}
+
+void test_first_arg_type_mismatch_3(double p) {
   __builtin_hlsl_elementwise_clip(p);
  // expected-error at -1 {{invalid operand of type 'double' where 'float' or a vector of such type is required}} 
 }
diff --git a/llvm/docs/SPIRVUsage.rst b/llvm/docs/SPIRVUsage.rst
index 0fcaa366c8a3e0..4fe142865df738 100644
--- a/llvm/docs/SPIRVUsage.rst
+++ b/llvm/docs/SPIRVUsage.rst
@@ -149,6 +149,8 @@ list of supported SPIR-V extensions, sorted alphabetically by their extension na
      - Adds atomic min and max instruction on floating-point numbers.
    * - ``SPV_EXT_arithmetic_fence``
      - Adds an instruction that prevents fast-math optimizations between its argument and the expression that contains it.
+   * - ``SPV_EXT_demote_to_helper_invocation``
+     - Adds an instruction that demotes a fragment shader invocation to a helper invocation.
    * - ``SPV_INTEL_arbitrary_precision_integers``
      - Allows generating arbitrary width integer types.
    * - ``SPV_INTEL_bfloat16_conversion``
diff --git a/llvm/include/llvm/IR/IntrinsicsDirectX.td b/llvm/include/llvm/IR/IntrinsicsDirectX.td
index f73f1ca5010f27..669052b11ca127 100644
--- a/llvm/include/llvm/IR/IntrinsicsDirectX.td
+++ b/llvm/include/llvm/IR/IntrinsicsDirectX.td
@@ -99,7 +99,7 @@ def int_dx_step : DefaultAttrsIntrinsic<[LLVMMatchType<0>], [llvm_anyfloat_ty, L
 def int_dx_splitdouble : DefaultAttrsIntrinsic<[llvm_anyint_ty, LLVMMatchType<0>], 
     [LLVMScalarOrSameVectorWidth<0, llvm_double_ty>], [IntrNoMem]>;
 def int_dx_radians : DefaultAttrsIntrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>], [IntrNoMem]>;
-def int_dx_clip : DefaultAttrsIntrinsic<[], [llvm_i1_ty], [IntrNoMem]>;
+def int_dx_discard : DefaultAttrsIntrinsic<[], [llvm_i1_ty], []>;
 def int_dx_firstbituhigh : DefaultAttrsIntrinsic<[LLVMScalarOrSameVectorWidth<0, llvm_i32_ty>], [llvm_anyint_ty], [IntrNoMem]>;
 def int_dx_firstbitshigh : DefaultAttrsIntrinsic<[LLVMScalarOrSameVectorWidth<0, llvm_i32_ty>], [llvm_anyint_ty], [IntrNoMem]>;
 }
diff --git a/llvm/include/llvm/IR/IntrinsicsSPIRV.td b/llvm/include/llvm/IR/IntrinsicsSPIRV.td
index 5308ffc73bdf95..0aa39601282fd6 100644
--- a/llvm/include/llvm/IR/IntrinsicsSPIRV.td
+++ b/llvm/include/llvm/IR/IntrinsicsSPIRV.td
@@ -91,7 +91,7 @@ let TargetPrefix = "spv" in {
   def int_spv_sign : DefaultAttrsIntrinsic<[LLVMScalarOrSameVectorWidth<0, llvm_i32_ty>], [llvm_any_ty], [IntrNoMem]>;
   def int_spv_radians : DefaultAttrsIntrinsic<[LLVMMatchType<0>], [llvm_anyfloat_ty], [IntrNoMem]>;
   def int_spv_group_memory_barrier_with_group_sync : DefaultAttrsIntrinsic<[], [], []>;
-  def int_spv_clip : DefaultAttrsIntrinsic<[], [llvm_i1_ty], [IntrNoMem]>;
+  def int_spv_discard : DefaultAttrsIntrinsic<[], [], []>;
   def int_spv_uclamp : DefaultAttrsIntrinsic<[llvm_anyint_ty], [LLVMMatchType<0>, LLVMMatchType<0>, LLVMMatchType<0>], [IntrNoMem]>;
   def int_spv_sclamp : DefaultAttrsIntrinsic<[llvm_anyint_ty], [LLVMMatchType<0>, LLVMMatchType<0>, LLVMMatchType<0>], [IntrNoMem]>;
   def int_spv_nclamp : DefaultAttrsIntrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>, LLVMMatchType<0>, LLVMMatchType<0>], [IntrNoMem]>;
diff --git a/llvm/lib/Target/DirectX/DXIL.td b/llvm/lib/Target/DirectX/DXIL.td
index 78ccb70bbf3b38..6cec4f5620d0b8 100644
--- a/llvm/lib/Target/DirectX/DXIL.td
+++ b/llvm/lib/Target/DirectX/DXIL.td
@@ -772,7 +772,7 @@ def CheckAccessFullyMapped : DXILOp<71, checkAccessFullyMapped> {
 
 def Discard : DXILOp<82, discard> {
   let Doc = "discard the current pixel";
-  let LLVMIntrinsic = int_dx_clip;
+  let LLVMIntrinsic = int_dx_discard;
   let arguments = [Int1Ty];
   let result = VoidTy;
   let stages = [Stages<DXIL1_0, [pixel]>];
@@ -871,15 +871,6 @@ def WaveIsFirstLane :  DXILOp<110, waveIsFirstLane> {
   let attributes = [Attributes<DXIL1_0, [ReadNone]>];
 }
 
-def WaveGetLaneIndex : DXILOp<111, waveGetLaneIndex> {
-  let Doc = "returns the index of the current lane in the wave";
-  let LLVMIntrinsic = int_dx_wave_getlaneindex;
-  let arguments = [];
-  let result = Int32Ty;
-  let stages = [Stages<DXIL1_0, [all_stages]>];
-  let attributes = [Attributes<DXIL1_0, [ReadNone]>];
-}
-
 def WaveReadLaneAt:  DXILOp<117, waveReadLaneAt> {
   let Doc = "returns the value from the specified lane";
   let LLVMIntrinsic = int_dx_wave_readlane;
@@ -890,24 +881,10 @@ def WaveReadLaneAt:  DXILOp<117, waveReadLaneAt> {
   let attributes = [Attributes<DXIL1_0, [ReadNone]>];
 }
 
-def AnnotateHandle : DXILOp<217, annotateHandle> {
-  let Doc = "annotate handle with resource properties";
-  let arguments = [HandleTy, ResPropsTy];
-  let result = HandleTy;
-  let stages = [Stages<DXIL1_6, [all_stages]>];
-}
-
-def CreateHandleFromBinding : DXILOp<218, createHandleFromBinding> {
-  let Doc = "create resource handle from binding";
-  let arguments = [ResBindTy, Int32Ty, Int1Ty];
-  let result = HandleTy;
-  let stages = [Stages<DXIL1_6, [all_stages]>];
-}
-
-def WaveAllBitCount : DXILOp<135, waveAllOp> {
-  let Doc = "returns the count of bits set to 1 across the wave";
-  let LLVMIntrinsic = int_dx_wave_active_countbits;
-  let arguments = [Int1Ty];
+def WaveGetLaneIndex : DXILOp<111, waveGetLaneIndex> {
+  let Doc = "returns the index of the current lane in the wave";
+  let LLVMIntrinsic = int_dx_wave_getlaneindex;
+  let arguments = [];
   let result = Int32Ty;
   let stages = [Stages<DXIL1_0, [all_stages]>];
   let attributes = [Attributes<DXIL1_0, [ReadNone]>];
diff --git a/llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp b/llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp
index 86f9c785b7652e..b3510b2c79a425 100644
--- a/llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp
@@ -30,6 +30,8 @@ static const std::map<std::string, SPIRV::Extension::Extension>
          SPIRV::Extension::Extension::SPV_EXT_shader_atomic_float_min_max},
         {"SPV_EXT_arithmetic_fence",
          SPIRV::Extension::Extension::SPV_EXT_arithmetic_fence},
+        {"SPV_EXT_demote_to_helper_invocation",
+         SPIRV::Extension::Extension::SPV_EXT_demote_to_helper_invocation},
         {"SPV_INTEL_arbitrary_precision_integers",
          SPIRV::Extension::Extension::SPV_INTEL_arbitrary_precision_integers},
         {"SPV_INTEL_cache_controls",
@@ -75,9 +77,7 @@ static const std::map<std::string, SPIRV::Extension::Extension>
         {"SPV_KHR_cooperative_matrix",
          SPIRV::Extension::Extension::SPV_KHR_cooperative_matrix},
         {"SPV_KHR_non_semantic_info",
-         SPIRV::Extension::Extension::SPV_KHR_non_semantic_info},
-        {"SPV_EXT_demote_to_helper_invocation",
-         SPIRV::Extension::Extension::SPV_EXT_demote_to_helper_invocation}};
+         SPIRV::Extension::Extension::SPV_KHR_non_semantic_info}};
 
 bool SPIRVExtensionsParser::parse(cl::Option &O, llvm::StringRef ArgName,
                                   llvm::StringRef ArgValue,
diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
index 13c2e7ed340431..e682016a27b111 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
@@ -164,8 +164,8 @@ class SPIRVInstructionSelector : public InstructionSelector {
                  unsigned comparisonOpcode, MachineInstr &I) const;
   bool selectCross(Register ResVReg, const SPIRVType *ResType,
                    MachineInstr &I) const;
-  bool selectClip(Register ResVReg, const SPIRVType *ResType,
-                  MachineInstr &I) const;
+  bool selectDiscard(Register ResVReg, const SPIRVType *ResType,
+                     MachineInstr &I) const;
 
   bool selectICmp(Register ResVReg, const SPIRVType *ResType,
                   MachineInstr &I) const;
@@ -2157,19 +2157,15 @@ bool SPIRVInstructionSelector::selectSplatVector(Register ResVReg,
   return MIB.constrainAllUses(TII, TRI, RBI);
 }
 
-bool SPIRVInstructionSelector::selectClip(Register ResVReg,
-                                          const SPIRVType *ResType,
-                                          MachineInstr &I) const {
+bool SPIRVInstructionSelector::selectDiscard(Register ResVReg,
+                                             const SPIRVType *ResType,
+                                             MachineInstr &I) const {
 
   unsigned Opcode;
 
-  if (STI.isAtLeastSPIRVVer(VersionTuple(1, 6))) {
-    if (!STI.canUseExtension(
-            SPIRV::Extension::SPV_EXT_demote_to_helper_invocation))
-      report_fatal_error(
-          "llvm.spv.clip intrinsic: this instruction requires the following "
-          "SPIR-V extension: SPV_EXT_demote_to_helper_invocation",
-          false);
+  if (STI.canUseExtension(
+          SPIRV::Extension::SPV_EXT_demote_to_helper_invocation) ||
+      STI.isAtLeastSPIRVVer(llvm::VersionTuple(1, 6))) {
     Opcode = SPIRV::OpDemoteToHelperInvocation;
   } else {
     Opcode = SPIRV::OpKill;
@@ -2838,8 +2834,8 @@ bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg,
     selectHandleFromBinding(ResVReg, ResType, I);
     return true;
   }
-  case Intrinsic::spv_clip: {
-    return selectClip(ResVReg, ResType, I);
+  case Intrinsic::spv_discard: {
+    return selectDiscard(ResVReg, ResType, I);
   }
   default: {
     std::string DiagMsg;
diff --git a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
index f0aaeb1b60c9bd..0bfc5138d56e4f 100644
--- a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
@@ -633,7 +633,8 @@ void RequirementHandler::initAvailableCapabilities(const SPIRVSubtarget &ST) {
   if (ST.isAtLeastSPIRVVer(VersionTuple(1, 6)))
     addAvailableCaps({Capability::DotProduct, Capability::DotProductInputAll,
                       Capability::DotProductInput4x8Bit,
-                      Capability::DotProductInput4x8BitPacked});
+                      Capability::DotProductInput4x8BitPacked,
+                      Capability::DemoteToHelperInvocation});
 
   // Add capabilities enabled by extensions.
   for (auto Extension : ST.getAllAvailableExtensions()) {
@@ -1407,21 +1408,23 @@ void addInstrRequirements(const MachineInstr &MI,
       Reqs.addCapability(SPIRV::Capability::SplitBarrierINTEL);
     }
     break;
-  case SPIRV::OpSDot:
-  case SPIRV::OpUDot:
-    AddDotProductRequirements(MI, Reqs, ST);
-    break;
-
   case SPIRV::OpKill: {
     Reqs.addCapability(SPIRV::Capability::Shader);
   } break;
   case SPIRV::OpDemoteToHelperInvocation:
+    Reqs.addCapability(SPIRV::Capability::DemoteToHelperInvocation);
+
     if (ST.canUseExtension(
             SPIRV::Extension::SPV_EXT_demote_to_helper_invocation)) {
-      Reqs.addExtension(SPIRV::Extension::SPV_EXT_demote_to_helper_invocation);
-      Reqs.addCapability(SPIRV::Capability::DemoteToHelperInvocation);
+      if (!ST.isAtLeastSPIRVVer(llvm::VersionTuple(1, 6)))
+        Reqs.addExtension(
+            SPIRV::Extension::SPV_EXT_demote_to_helper_invocation);
     }
     break;
+  case SPIRV::OpSDot:
+  case SPIRV::OpUDot:
+    AddDotProductRequirements(MI, Reqs, ST);
+    break;
   default:
     break;
   }
diff --git a/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td b/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td
index 4ae247bafb684f..b88f6f5766a053 100644
--- a/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td
+++ b/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td
@@ -456,7 +456,7 @@ defm VulkanMemoryModelDeviceScopeKHR : CapabilityOperand<5346, 0, 0, [], []>;
 defm ImageFootprintNV : CapabilityOperand<5282, 0, 0, [], []>;
 defm FragmentBarycentricNV : CapabilityOperand<5284, 0, 0, [], []>;
 defm ComputeDerivativeGroupQuadsNV : CapabilityOperand<5288, 0, 0, [], []>;
-defm DemoteToHelperInvocation : CapabilityOperand<5379, 0, 0, [SPV_EXT_demote_to_helper_invocation], []>;
+defm DemoteToHelperInvocation : CapabilityOperand<5379, 0x10600, 0, [SPV_EXT_demote_to_helper_invocation], []>;
 defm ComputeDerivativeGroupLinearNV : CapabilityOperand<5350, 0, 0, [], []>;
 defm FragmentDensityEXT : CapabilityOperand<5291, 0, 0, [], [Shader]>;
 defm PhysicalStorageBufferAddressesEXT : CapabilityOperand<5347, 0, 0, [], [Shader]>;
diff --git a/llvm/test/CodeGen/DirectX/clip.ll b/llvm/test/CodeGen/DirectX/clip.ll
index 71789e7048363a..2a9ec59156e7cc 100644
--- a/llvm/test/CodeGen/DirectX/clip.ll
+++ b/llvm/test/CodeGen/DirectX/clip.ll
@@ -6,7 +6,7 @@
 define void @test_scalar(float noundef %p) #0 {
 entry:
   %0 = fcmp olt float %p, 0.000000e+00
-  call void @llvm.dx.clip(i1 %0)
+  call void @llvm.dx.discard(i1 %0)
   ret void
 }
 
@@ -24,6 +24,8 @@ define void @test_vector(<4 x float> noundef %p) #0 {
 entry:
   %0 = fcmp olt <4 x float> %p, zeroinitializer
   %1 = call i1 @llvm.dx.any.v4i1(<4 x i1> %0)
-  call void @llvm.dx.clip(i1 %1)
+  call void @llvm.dx.discard(i1 %1)
   ret void
 }
+
+declare void @llvm.dx.discard(i1)
diff --git a/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/clip.ll b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/clip.ll
index 89db4be3494ebd..831592610d1067 100644
--- a/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/clip.ll
+++ b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/clip.ll
@@ -1,10 +1,16 @@
-; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s --check-prefixes=CHECK,SPIRV15
-; RUN: llc -verify-machineinstrs -spirv-ext=+SPV_EXT_demote_to_helper_invocation -O0 -mtriple=spirv32v1.6-unknown-unknown %s -o - | FileCheck %s --check-prefixes=CHECK,SPIRV16
-; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv1.5-unknown-unknown %s -o - | FileCheck %s --check-prefixes=CHECK,SPIRV15
+; RUN: llc -verify-machineinstrs -spirv-ext=+SPV_EXT_demote_to_helper_invocation -O0 -mtriple=spirv1.5-unknown-unknown %s -o - | FileCheck %s --check-prefixes=CHECK,SPIRV16,WITH-EXTENSION,WITH-CAPABILITY
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv1.6-unknown-unknown %s -o - | FileCheck %s --check-prefixes=CHECK,SPIRV16,WITH-CAPABILITY
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv1.5-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+; RUN: %if spirv-tools %{ llc -O0 -spirv-ext=+SPV_EXT_demote_to_helper_invocation -mtriple=spirv1.5-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv1.6-unknown-unknown %s -o - -filetype=obj | spirv-val %}
 
 
 ; Make sure lowering is correctly generating spirv code.
 
+; WITH-CAPABILITY-DAG: OpCapability DemoteToHelperInvocation
+; WITH-EXTENSION-DAG: OpExtension "SPV_EXT_demote_to_helper_invocation"
+
 ; CHECK-DAG:   %[[#float:]] = OpTypeFloat 32
 ; CHECK-DAG:   %[[#void:]]  = OpTypeVoid
 ; CHECK-DAG:   %[[#bool:]]  = OpTypeBool
@@ -12,15 +18,11 @@
 ; CHECK-DAG:   %[[#v4float:]] = OpTypeVector %[[#float]] 4
 ; CHECK-DAG:   %[[#fzero:]] = OpConstant %[[#float]] 0
 ; CHECK-DAG:   %[[#v4fzero:]] = OpConstantNull %[[#v4float]]
-; SPIRV16-DAG: %[[#vecfuncopptr:]] = OpTypePointer Function %[[#v4float]]
-; SPIRV16-DAG: %[[#funcopptr:]] = OpTypePointer Function %[[#float]]
 
 define void @test_scalar(float noundef %Buf) {
 entry:
 ; CHECK-LABEL: ; -- Begin function test_scalar
-; SPIRV16:     %[[#param:]] = OpVariable %[[#funcopptr]] Function
-; SPIRV16:     %[[#load:]] = OpLoad %[[#float]] %[[#param]] Aligned 4
-; SPIRV15:     %[[#load:]] = OpFunctionParameter %[[#float]]
+; CHECK:       %[[#load:]] = OpFunctionParameter %[[#float]]
 ; CHECK:       %[[#cmplt:]] = OpFOrdLessThan %[[#bool]] %[[#load]] %[[#fzero]]
 ; CHECK:       OpBranchConditional %[[#cmplt]] %[[#truel:]] %[[#endl:]]
 ; CHECK:       %[[#truel]] = OpLabel
@@ -37,20 +39,18 @@ entry:
   br i1 %2, label %lt0, label %end
 
 lt0:                                              ; preds = %entry
-  call void @llvm.spv.clip()
+  call void @llvm.spv.discard()
   br label %end
 
 end:                                              ; preds = %lt0, %entry
   ret void
 }
-declare void @llvm.spv.clip()
+declare void @llvm.spv.discard()
 
 define void @test_vector(<4 x float> noundef %Buf) {
 entry:
 ; CHECK-LABEL: ; -- Begin function test_vector
-; SPIRV16:     %[[#param:]] = OpVariable %[[#vecfuncopptr]] Function
-; SPIRV16:     %[[#loadvec:]] = OpLoad %[[#v4float]] %[[#param]] Aligned 16
-; SPIRV15:     %[[#loadvec:]] = OpFunctionParameter %[[#v4float]]
+; CHECK:       %[[#loadvec:]] = OpFunctionParameter %[[#v4float]]
 ; CHECK:       %[[#cmplt:]] = OpFOrdLessThan %[[#v4bool]] %[[#loadvec]] %[[#v4fzero]]
 ; CHECK:       %[[#opany:]] = OpAny %[[#bool]] %[[#cmplt]]
 ; CHECK:       OpBranchConditional %[[#opany]]  %[[#truel:]] %[[#endl:]]
@@ -69,7 +69,7 @@ entry:
   br i1 %3, label %lt0, label %end
 
 lt0:                                              ; preds = %entry
-  call void @llvm.spv.clip()
+  call void @llvm.spv.discard()
   br label %end
 
 end:                                              ; preds = %lt0, %entry



More information about the cfe-commits mailing list