[llvm] [SPIRV] Promote scalar arguments to vector for `OpExtInst` in `generateExtInst` instead of `SPIRVRegularizer` (PR #170155)

Juan Manuel Martinez CaamaƱo via llvm-commits llvm-commits at lists.llvm.org
Mon Dec 1 08:22:42 PST 2025


https://github.com/jmmartinez updated https://github.com/llvm/llvm-project/pull/170155

>From 1ae5ff46aae65da3a495dc2c6d638e0adabefb7a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Juan=20Manuel=20Martinez=20Caama=C3=B1o?=
 <jmartinezcaamao at gmail.com>
Date: Mon, 1 Dec 2025 12:55:28 +0100
Subject: [PATCH 1/5] [NFC][SPIRV] Update OpMin test to show that the promotion
 to vector is broken

---
 .../transcoding/OpExtInst_vector_promoton.ll  | 96 +++++++++++++++++++
 llvm/test/CodeGen/SPIRV/transcoding/OpMin.ll  | 16 ----
 2 files changed, 96 insertions(+), 16 deletions(-)
 create mode 100644 llvm/test/CodeGen/SPIRV/transcoding/OpExtInst_vector_promoton.ll
 delete mode 100644 llvm/test/CodeGen/SPIRV/transcoding/OpMin.ll

diff --git a/llvm/test/CodeGen/SPIRV/transcoding/OpExtInst_vector_promoton.ll b/llvm/test/CodeGen/SPIRV/transcoding/OpExtInst_vector_promoton.ll
new file mode 100644
index 0000000000000..6c0248285b93d
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/transcoding/OpExtInst_vector_promoton.ll
@@ -0,0 +1,96 @@
+; RUN: not llc -O0 -mtriple=spirv32-unknown-unknown %s -o -
+;
+; Some OpenCL builtins have mixed vector-scalar variants, but OpExtInt only supports
+; versions where all the arguments have the same type.
+
+define spir_kernel void @S_MIN() {
+entry:
+  %call = tail call spir_func <2 x i32> @_Z3minDv2_ii(<2 x i32> <i32 1, i32 10>, i32 5)
+  ret void
+}
+
+define spir_kernel void @U_MIN() {
+entry:
+  %call = tail call spir_func <2 x i32> @_Z3minDv2_jj(<2 x i32> <i32 1, i32 10>, i32 5)
+  ret void
+}
+
+define spir_kernel void @S_MAX() {
+entry:
+  %call = tail call spir_func <2 x i32> @_Z3maxDv2_ii(<2 x i32> <i32 1, i32 10>, i32 5)
+  ret void
+}
+
+define spir_kernel void @F_MIN() {
+entry:
+  %call = tail call spir_func <2 x float> @_Z3minDv2_ff(<2 x float> <float 1.0, float 10.0>, float 5.0)
+  ret void
+}
+
+define spir_kernel void @F_MAX() {
+entry:
+  %call = tail call spir_func <2 x float> @_Z3maxDv2_ff(<2 x float> <float 1.0, float 10.0>, float 5.0)
+  ret void
+}
+
+define spir_kernel void @F_FMIN() {
+entry:
+  %call = tail call spir_func <2 x float> @_Z4fminDv2_ff(<2 x float> <float 1.0, float 10.0>, float 5.0)
+  ret void
+}
+
+define spir_kernel void @F_FMAX() {
+entry:
+  %call = tail call spir_func <2 x float> @_Z4fmaxDv2_ff(<2 x float> <float 1.0, float 10.0>, float 5.0)
+  ret void
+}
+
+define spir_kernel void @S_CLAMP() {
+entry:
+  %call = tail call spir_func <2 x i32> @_Z5clampDv2_iii(<2 x i32> <i32 1, i32 10>, i32 5, i32 6)
+  ret void
+}
+
+define spir_kernel void @F_CLAMP() {
+entry:
+  %call = tail call spir_func <2 x float> @_Z5clampDv2_fff(<2 x float> <float 1.0, float 10.0>, float 5.0, float 6.0)
+  ret void
+}
+
+define spir_kernel void @MIX() {
+entry:
+  %call = tail call spir_func <2 x float> @_Z3mixDv2_fS_f(<2 x float> <float 1.0, float 10.0>, <2 x float> <float 2.0, float 20.0>, float 0.5)
+  ret void
+}
+
+define spir_kernel void @SMOOTHSTEP() {
+entry:
+  %call = tail call spir_func <2 x float> @_Z10smoothstepffDv2_f(float 1.0, float 0.5, <2 x float> <float 1.0, float 10.0>)
+  ret void
+}
+
+define spir_kernel void @ill_0() {
+entry:
+  tail call spir_func void @_Z3minv()
+  ret void
+}
+
+define spir_kernel void @ill_1() {
+entry:
+  tail call spir_func void @_Z3miniii(i32 1, i32 2, i32 3)
+  ret void
+}
+
+declare spir_func <2 x i32> @_Z3minDv2_ii(<2 x i32>, i32)
+declare spir_func <2 x i32> @_Z3minDv2_jj(<2 x i32>, i32)
+declare spir_func <2 x i32> @_Z3maxDv2_ii(<2 x i32>, i32)
+declare spir_func <2 x float> @_Z3minDv2_ff(<2 x float>, float)
+declare spir_func <2 x float> @_Z3maxDv2_ff(<2 x float>, float)
+declare spir_func <2 x float> @_Z4fminDv2_ff(<2 x float>, float)
+declare spir_func <2 x float> @_Z4fmaxDv2_ff(<2 x float>, float)
+declare spir_func <2 x i32> @_Z5clampDv2_iii(<2 x i32>, i32)
+declare spir_func <2 x float> @_Z5clampDv2_fff(<2 x float>, float)
+declare spir_func <2 x float> @_Z3mixDv2_fS_f(<2 x float>, <2 x float>, float)
+declare spir_func <2 x float> @_Z10smoothstepffDv2_f(float, float, <2 x float>)
+declare spir_func void @_Z3minv()
+declare spir_func i32 @_Z3miniii(i32, i32, i32)
diff --git a/llvm/test/CodeGen/SPIRV/transcoding/OpMin.ll b/llvm/test/CodeGen/SPIRV/transcoding/OpMin.ll
deleted file mode 100644
index 5cc3ea01e5191..0000000000000
--- a/llvm/test/CodeGen/SPIRV/transcoding/OpMin.ll
+++ /dev/null
@@ -1,16 +0,0 @@
-; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV
-
-; CHECK-SPIRV: %[[#SetInstID:]] = OpExtInstImport "OpenCL.std"
-; CHECK-SPIRV: %[[#IntTypeID:]] = OpTypeInt 32 [[#]]
-; CHECK-SPIRV: %[[#Int2TypeID:]] = OpTypeVector %[[#IntTypeID]] 2
-; CHECK-SPIRV: %[[#CompositeID:]] = OpCompositeInsert %[[#Int2TypeID]] %[[#]] %[[#]] [[#]]
-; CHECK-SPIRV: %[[#ShuffleID:]] = OpVectorShuffle %[[#Int2TypeID]] %[[#CompositeID]] %[[#]] [[#]] [[#]]
-; CHECK-SPIRV: %[[#]] = OpExtInst %[[#Int2TypeID]] %[[#SetInstID]] s_min %[[#]] %[[#ShuffleID]]
-
-define spir_kernel void @test() {
-entry:
-  %call = tail call spir_func <2 x i32> @_Z3minDv2_ii(<2 x i32> <i32 1, i32 10>, i32 5) #2
-  ret void
-}
-
-declare spir_func <2 x i32> @_Z3minDv2_ii(<2 x i32>, i32)

>From 8861954a02672b3d5fa392a631aa5c5778a96397 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Juan=20Manuel=20Martinez=20Caama=C3=B1o?=
 <jmartinezcaamao at gmail.com>
Date: Mon, 1 Dec 2025 09:46:23 +0100
Subject: [PATCH 2/5] [SPIRV] Remove the vector-scalar min/max/fmin/fmax IR
 rewriting

---
 llvm/lib/Target/SPIRV/SPIRVRegularizer.cpp    | 102 +-----------------
 .../transcoding/OpExtInst_vector_promoton.ll  |  85 ++++++++++++++-
 2 files changed, 87 insertions(+), 100 deletions(-)

diff --git a/llvm/lib/Target/SPIRV/SPIRVRegularizer.cpp b/llvm/lib/Target/SPIRV/SPIRVRegularizer.cpp
index 1b95f09974c61..653c9ad53e888 100644
--- a/llvm/lib/Target/SPIRV/SPIRVRegularizer.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVRegularizer.cpp
@@ -12,11 +12,10 @@
 //===----------------------------------------------------------------------===//
 
 #include "SPIRV.h"
-#include "llvm/Demangle/Demangle.h"
+#include "llvm/IR/Constants.h"
 #include "llvm/IR/InstIterator.h"
-#include "llvm/IR/InstVisitor.h"
+#include "llvm/IR/Instructions.h"
 #include "llvm/IR/PassManager.h"
-#include "llvm/Transforms/Utils/Cloning.h"
 
 #include <list>
 
@@ -25,9 +24,7 @@
 using namespace llvm;
 
 namespace {
-struct SPIRVRegularizer : public FunctionPass, InstVisitor<SPIRVRegularizer> {
-  DenseMap<Function *, Function *> Old2NewFuncs;
-
+struct SPIRVRegularizer : public FunctionPass {
 public:
   static char ID;
   SPIRVRegularizer() : FunctionPass(ID) {}
@@ -37,11 +34,8 @@ struct SPIRVRegularizer : public FunctionPass, InstVisitor<SPIRVRegularizer> {
   void getAnalysisUsage(AnalysisUsage &AU) const override {
     FunctionPass::getAnalysisUsage(AU);
   }
-  void visitCallInst(CallInst &CI);
 
 private:
-  void visitCallScalToVec(CallInst *CI, StringRef MangledName,
-                          StringRef DemangledName);
   void runLowerConstExpr(Function &F);
 };
 } // namespace
@@ -157,98 +151,8 @@ void SPIRVRegularizer::runLowerConstExpr(Function &F) {
   }
 }
 
-// It fixes calls to OCL builtins that accept vector arguments and one of them
-// is actually a scalar splat.
-void SPIRVRegularizer::visitCallInst(CallInst &CI) {
-  auto F = CI.getCalledFunction();
-  if (!F)
-    return;
-
-  auto MangledName = F->getName();
-  char *NameStr = itaniumDemangle(F->getName().data());
-  if (!NameStr)
-    return;
-  StringRef DemangledName(NameStr);
-
-  // TODO: add support for other builtins.
-  if (DemangledName.starts_with("fmin") || DemangledName.starts_with("fmax") ||
-      DemangledName.starts_with("min") || DemangledName.starts_with("max"))
-    visitCallScalToVec(&CI, MangledName, DemangledName);
-  free(NameStr);
-}
-
-void SPIRVRegularizer::visitCallScalToVec(CallInst *CI, StringRef MangledName,
-                                          StringRef DemangledName) {
-  // Check if all arguments have the same type - it's simple case.
-  auto Uniform = true;
-  Type *Arg0Ty = CI->getOperand(0)->getType();
-  auto IsArg0Vector = isa<VectorType>(Arg0Ty);
-  for (unsigned I = 1, E = CI->arg_size(); Uniform && (I != E); ++I)
-    Uniform = isa<VectorType>(CI->getOperand(I)->getType()) == IsArg0Vector;
-  if (Uniform)
-    return;
-
-  auto *OldF = CI->getCalledFunction();
-  Function *NewF = nullptr;
-  auto [It, Inserted] = Old2NewFuncs.try_emplace(OldF);
-  if (Inserted) {
-    AttributeList Attrs = CI->getCalledFunction()->getAttributes();
-    SmallVector<Type *, 2> ArgTypes = {OldF->getArg(0)->getType(), Arg0Ty};
-    auto *NewFTy =
-        FunctionType::get(OldF->getReturnType(), ArgTypes, OldF->isVarArg());
-    NewF = Function::Create(NewFTy, OldF->getLinkage(), OldF->getName(),
-                            *OldF->getParent());
-    ValueToValueMapTy VMap;
-    auto NewFArgIt = NewF->arg_begin();
-    for (auto &Arg : OldF->args()) {
-      auto ArgName = Arg.getName();
-      NewFArgIt->setName(ArgName);
-      VMap[&Arg] = &(*NewFArgIt++);
-    }
-    SmallVector<ReturnInst *, 8> Returns;
-    CloneFunctionInto(NewF, OldF, VMap,
-                      CloneFunctionChangeType::LocalChangesOnly, Returns);
-    NewF->setAttributes(Attrs);
-    It->second = NewF;
-  } else {
-    NewF = It->second;
-  }
-  assert(NewF);
-
-  // This produces an instruction sequence that implements a splat of
-  // CI->getOperand(1) to a vector Arg0Ty. However, we use InsertElementInst
-  // and ShuffleVectorInst to generate the same code as the SPIR-V translator.
-  // For instance (transcoding/OpMin.ll), this call
-  //   call spir_func <2 x i32> @_Z3minDv2_ii(<2 x i32> <i32 1, i32 10>, i32 5)
-  // is translated to
-  //    %8 = OpUndef %v2uint
-  //   %14 = OpConstantComposite %v2uint %uint_1 %uint_10
-  //   ...
-  //   %10 = OpCompositeInsert %v2uint %uint_5 %8 0
-  //   %11 = OpVectorShuffle %v2uint %10 %8 0 0
-  // %call = OpExtInst %v2uint %1 s_min %14 %11
-  auto ConstInt = ConstantInt::get(IntegerType::get(CI->getContext(), 32), 0);
-  PoisonValue *PVal = PoisonValue::get(Arg0Ty);
-  Instruction *Inst = InsertElementInst::Create(
-      PVal, CI->getOperand(1), ConstInt, "", CI->getIterator());
-  ElementCount VecElemCount = cast<VectorType>(Arg0Ty)->getElementCount();
-  Constant *ConstVec = ConstantVector::getSplat(VecElemCount, ConstInt);
-  Value *NewVec =
-      new ShuffleVectorInst(Inst, PVal, ConstVec, "", CI->getIterator());
-  CI->setOperand(1, NewVec);
-  CI->replaceUsesOfWith(OldF, NewF);
-  CI->mutateFunctionType(NewF->getFunctionType());
-}
-
 bool SPIRVRegularizer::runOnFunction(Function &F) {
   runLowerConstExpr(F);
-  visit(F);
-  for (auto &OldNew : Old2NewFuncs) {
-    Function *OldF = OldNew.first;
-    Function *NewF = OldNew.second;
-    NewF->takeName(OldF);
-    OldF->eraseFromParent();
-  }
   return true;
 }
 
diff --git a/llvm/test/CodeGen/SPIRV/transcoding/OpExtInst_vector_promoton.ll b/llvm/test/CodeGen/SPIRV/transcoding/OpExtInst_vector_promoton.ll
index 6c0248285b93d..731220e52e8e7 100644
--- a/llvm/test/CodeGen/SPIRV/transcoding/OpExtInst_vector_promoton.ll
+++ b/llvm/test/CodeGen/SPIRV/transcoding/OpExtInst_vector_promoton.ll
@@ -1,81 +1,164 @@
-; RUN: not llc -O0 -mtriple=spirv32-unknown-unknown %s -o -
+; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown %s -o - -filetype=obj | not spirv-val %}
 ;
 ; Some OpenCL builtins have mixed vector-scalar variants, but OpExtInt only supports
 ; versions where all the arguments have the same type.
+;
+; We generate code, but it is invalid
+; We should generate vector versions for these cases
 
 define spir_kernel void @S_MIN() {
+; CHECK-LABEL:   OpFunction %{{[0-9]+}} None %{{[0-9]+}} ; -- Begin function S_MIN
+; CHECK-NEXT:    OpLabel
+; CHECK-NEXT:    %{{[0-9]+}} = OpExtInst %{{[0-9]+}} %{{[0-9]+}} s_min %{{[0-9]+}} %{{[0-9]+}}
+; CHECK-NEXT:    OpReturn
+; CHECK-NEXT:    OpFunctionEnd
+; CHECK-NEXT:    ; -- End function
 entry:
   %call = tail call spir_func <2 x i32> @_Z3minDv2_ii(<2 x i32> <i32 1, i32 10>, i32 5)
   ret void
 }
 
 define spir_kernel void @U_MIN() {
+; CHECK-LABEL:   OpFunction %{{[0-9]+}} None %{{[0-9]+}} ; -- Begin function U_MIN
+; CHECK-NEXT:    OpLabel
+; CHECK-NEXT:    %{{[0-9]+}} = OpExtInst %{{[0-9]+}} %{{[0-9]+}} u_min %{{[0-9]+}} %{{[0-9]+}}
+; CHECK-NEXT:    OpReturn
+; CHECK-NEXT:    OpFunctionEnd
+; CHECK-NEXT:    ; -- End function
 entry:
   %call = tail call spir_func <2 x i32> @_Z3minDv2_jj(<2 x i32> <i32 1, i32 10>, i32 5)
   ret void
 }
 
 define spir_kernel void @S_MAX() {
+; CHECK-LABEL: OpFunction %{{[0-9]+}} None %{{[0-9]+}} ; -- Begin function S_MAX
+; CHECK-NEXT:    OpLabel
+; CHECK-NEXT:    %{{[0-9]+}} = OpExtInst %{{[0-9]+}} %{{[0-9]+}} s_max %{{[0-9]+}} %{{[0-9]+}}
+; CHECK-NEXT:    OpReturn
+; CHECK-NEXT:    OpFunctionEnd
+; CHECK-NEXT:    ; -- End function
 entry:
   %call = tail call spir_func <2 x i32> @_Z3maxDv2_ii(<2 x i32> <i32 1, i32 10>, i32 5)
   ret void
 }
 
 define spir_kernel void @F_MIN() {
+; CHECK-LABEL: OpFunction %{{[0-9]+}} None %{{[0-9]+}} ; -- Begin function F_MIN
+; CHECK-NEXT:    OpLabel
+; CHECK-NEXT:    %{{[0-9]+}} = OpExtInst %{{[0-9]+}} %{{[0-9]+}} fmin %{{[0-9]+}} %{{[0-9]+}}
+; CHECK-NEXT:    OpReturn
+; CHECK-NEXT:    OpFunctionEnd
+; CHECK-NEXT:    ; -- End function
 entry:
   %call = tail call spir_func <2 x float> @_Z3minDv2_ff(<2 x float> <float 1.0, float 10.0>, float 5.0)
   ret void
 }
 
 define spir_kernel void @F_MAX() {
+; CHECK-LABEL:   OpFunction %{{[0-9]+}} None %{{[0-9]+}} ; -- Begin function F_MAX
+; CHECK-NEXT:    OpLabel
+; CHECK-NEXT:    %{{[0-9]+}} = OpExtInst %{{[0-9]+}} %{{[0-9]+}} fmax %{{[0-9]+}} %{{[0-9]+}}
+; CHECK-NEXT:    OpReturn
+; CHECK-NEXT:    OpFunctionEnd
+; CHECK-NEXT:    ; -- End function
 entry:
   %call = tail call spir_func <2 x float> @_Z3maxDv2_ff(<2 x float> <float 1.0, float 10.0>, float 5.0)
   ret void
 }
 
 define spir_kernel void @F_FMIN() {
+; CHECK-LABEL:   OpFunction %{{[0-9]+}} None %{{[0-9]+}} ; -- Begin function F_FMIN
+; CHECK-NEXT:    OpLabel
+; CHECK-NEXT:    %{{[0-9]+}} = OpExtInst %{{[0-9]+}} %{{[0-9]+}} fmin %{{[0-9]+}} %{{[0-9]+}}
+; CHECK-NEXT:    OpReturn
+; CHECK-NEXT:    OpFunctionEnd
+; CHECK-NEXT:    ; -- End function
 entry:
   %call = tail call spir_func <2 x float> @_Z4fminDv2_ff(<2 x float> <float 1.0, float 10.0>, float 5.0)
   ret void
 }
 
 define spir_kernel void @F_FMAX() {
+; CHECK-LABEL:   OpFunction %{{[0-9]+}} None %{{[0-9]+}} ; -- Begin function F_FMAX
+; CHECK-NEXT:    OpLabel
+; CHECK-NEXT:    %{{[0-9]+}} = OpExtInst %{{[0-9]+}} %{{[0-9]+}} fmax %{{[0-9]+}} %{{[0-9]+}}
+; CHECK-NEXT:    OpReturn
+; CHECK-NEXT:    OpFunctionEnd
+; CHECK-NEXT:    ; -- End function
 entry:
   %call = tail call spir_func <2 x float> @_Z4fmaxDv2_ff(<2 x float> <float 1.0, float 10.0>, float 5.0)
   ret void
 }
 
 define spir_kernel void @S_CLAMP() {
+; CHECK-LABEL:   OpFunction %{{[0-9]+}} None %{{[0-9]+}} ; -- Begin function S_CLAMP
+; CHECK-NEXT:    OpLabel
+; CHECK-NEXT:    %{{[0-9]+}} = OpExtInst %{{[0-9]+}} %{{[0-9]+}} s_clamp %{{[0-9]+}} %{{[0-9]+}} %{{[0-9]+}}
+; CHECK-NEXT:    OpReturn
+; CHECK-NEXT:    OpFunctionEnd
+; CHECK-NEXT:    ; -- End function
 entry:
   %call = tail call spir_func <2 x i32> @_Z5clampDv2_iii(<2 x i32> <i32 1, i32 10>, i32 5, i32 6)
   ret void
 }
 
 define spir_kernel void @F_CLAMP() {
+; CHECK-LABEL:   OpFunction %{{[0-9]+}} None %{{[0-9]+}} ; -- Begin function F_CLAMP
+; CHECK-NEXT:    OpLabel
+; CHECK-NEXT:    %{{[0-9]+}} = OpExtInst %{{[0-9]+}} %{{[0-9]+}} fclamp %{{[0-9]+}} %{{[0-9]+}} %{{[0-9]+}}
+; CHECK-NEXT:    OpReturn
+; CHECK-NEXT:    OpFunctionEnd
+; CHECK-NEXT:    ; -- End function
 entry:
   %call = tail call spir_func <2 x float> @_Z5clampDv2_fff(<2 x float> <float 1.0, float 10.0>, float 5.0, float 6.0)
   ret void
 }
 
 define spir_kernel void @MIX() {
+; CHECK-LABEL:   OpFunction %{{[0-9]+}} None %{{[0-9]+}} ; -- Begin function MIX
+; CHECK-NEXT:    OpLabel
+; CHECK-NEXT:    %{{[0-9]+}} = OpExtInst %{{[0-9]+}} %{{[0-9]+}} mix %{{[0-9]+}} %{{[0-9]+}} %{{[0-9]+}}
+; CHECK-NEXT:    OpReturn
+; CHECK-NEXT:    OpFunctionEnd
+; CHECK-NEXT:    ; -- End function
 entry:
   %call = tail call spir_func <2 x float> @_Z3mixDv2_fS_f(<2 x float> <float 1.0, float 10.0>, <2 x float> <float 2.0, float 20.0>, float 0.5)
   ret void
 }
 
 define spir_kernel void @SMOOTHSTEP() {
+; CHECK-LABEL:   OpFunction %{{[0-9]+}} None %{{[0-9]+}} ; -- Begin function SMOOTHSTEP
+; CHECK-NEXT:    OpLabel
+; CHECK-NEXT:    %{{[0-9]+}} = OpExtInst %{{[0-9]+}} %{{[0-9]+}} smoothstep %{{[0-9]+}} %{{[0-9]+}} %{{[0-9]+}}
+; CHECK-NEXT:    OpReturn
+; CHECK-NEXT:    OpFunctionEnd
+; CHECK-NEXT:    ; -- End function
 entry:
   %call = tail call spir_func <2 x float> @_Z10smoothstepffDv2_f(float 1.0, float 0.5, <2 x float> <float 1.0, float 10.0>)
   ret void
 }
 
 define spir_kernel void @ill_0() {
+; CHECK-LABEL:   OpFunction %{{[0-9]+}} None %{{[0-9]+}} ; -- Begin function ill_0
+; CHECK-NEXT:    OpLabel
+; CHECK-NEXT:    OpFunctionCall %{{[0-9]+}} %{{[0-9]+}}
+; CHECK-NEXT:    OpReturn
+; CHECK-NEXT:    OpFunctionEnd
+; CHECK-NEXT:    ; -- End function
 entry:
   tail call spir_func void @_Z3minv()
   ret void
 }
 
 define spir_kernel void @ill_1() {
+; CHECK-LABEL:   OpFunction %{{[0-9]+}} None %{{[0-9]+}} ; -- Begin function ill_1
+; CHECK-NEXT:    OpLabel
+; This is wrong, we should generate a regular call
+; CHECK-NEXT:    %{{[0-9]+}} = OpExtInst %{{[0-9]+}} %{{[0-9]+}} s_min %{{[0-9]+}} %{{[0-9]+}} %{{[0-9]+}}
+; CHECK-NEXT:    OpReturn
+; CHECK-NEXT:    OpFunctionEnd
+; CHECK-NEXT:    ; -- End function
 entry:
   tail call spir_func void @_Z3miniii(i32 1, i32 2, i32 3)
   ret void

>From 3dd4e3aa97bf056d2c255ad585d41a70d6b66b65 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Juan=20Manuel=20Martinez=20Caama=C3=B1o?=
 <jmartinezcaamao at gmail.com>
Date: Mon, 1 Dec 2025 12:54:56 +0100
Subject: [PATCH 3/5] [SPIRV] Promote scalar arguments to vector for OpExtInst

---
 llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp       | 48 ++++++++++++++++++-
 .../transcoding/OpExtInst_vector_promoton.ll  | 36 +++++++++-----
 2 files changed, 71 insertions(+), 13 deletions(-)

diff --git a/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp b/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp
index 87ebee6a14eac..6ae0106d0129b 100644
--- a/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp
@@ -1157,6 +1157,29 @@ static unsigned getNumSizeComponents(SPIRVType *imgType) {
   return arrayed ? numComps + 1 : numComps;
 }
 
+static bool builtinMayNeedPromotionToVec(uint32_t BuiltinNumber) {
+  switch (BuiltinNumber) {
+  case SPIRV::OpenCLExtInst::s_min:
+  case SPIRV::OpenCLExtInst::u_min:
+  case SPIRV::OpenCLExtInst::s_max:
+  case SPIRV::OpenCLExtInst::u_max:
+  case SPIRV::OpenCLExtInst::fmax:
+  case SPIRV::OpenCLExtInst::fmin:
+  case SPIRV::OpenCLExtInst::fmax_common:
+  case SPIRV::OpenCLExtInst::fmin_common:
+  case SPIRV::OpenCLExtInst::s_clamp:
+  case SPIRV::OpenCLExtInst::fclamp:
+  case SPIRV::OpenCLExtInst::u_clamp:
+  case SPIRV::OpenCLExtInst::mix:
+  case SPIRV::OpenCLExtInst::step:
+  case SPIRV::OpenCLExtInst::smoothstep:
+    return true;
+  default:
+    break;
+  }
+  return false;
+}
+
 //===----------------------------------------------------------------------===//
 // Implementation functions for each builtin group
 //===----------------------------------------------------------------------===//
@@ -1182,16 +1205,37 @@ static bool generateExtInst(const SPIRV::IncomingCall *Call,
                  : SPIRV::OpenCLExtInst::fmax;
   }
 
+  Register ReturnTypeId = GR->getSPIRVTypeID(Call->ReturnType);
+  SmallVector<Register> Arguments;
+  unsigned ResultElementCount =
+      GR->getScalarOrVectorComponentCount(ReturnTypeId);
+  bool MayNeedPromotionToVec =
+      builtinMayNeedPromotionToVec(Number) && ResultElementCount > 1;
+  for (Register Argument : Call->Arguments) {
+    Register PromotedArg = Argument;
+    SPIRVType *ArgumentType = GR->getSPIRVTypeForVReg(Argument);
+    if (MayNeedPromotionToVec && ArgumentType != Call->ReturnType) {
+      PromotedArg = createVirtualRegister(Call->ReturnType, GR, MIRBuilder);
+      auto VecBroadcast = MIRBuilder.buildInstr(SPIRV::OpCompositeConstruct)
+                              .addDef(PromotedArg)
+                              .addUse(ReturnTypeId);
+      for (unsigned I = 0; I != ResultElementCount; ++I)
+        VecBroadcast.addUse(Argument);
+    }
+    Arguments.push_back(PromotedArg);
+  }
+
   // Build extended instruction.
   auto MIB =
       MIRBuilder.buildInstr(SPIRV::OpExtInst)
           .addDef(Call->ReturnRegister)
-          .addUse(GR->getSPIRVTypeID(Call->ReturnType))
+          .addUse(ReturnTypeId)
           .addImm(static_cast<uint32_t>(SPIRV::InstructionSet::OpenCL_std))
           .addImm(Number);
 
-  for (auto Argument : Call->Arguments)
+  for (Register Argument : Arguments)
     MIB.addUse(Argument);
+
   MIB.getInstr()->copyIRFlags(CB);
   if (OrigNumber == SPIRV::OpenCLExtInst::fmin_common ||
       OrigNumber == SPIRV::OpenCLExtInst::fmax_common) {
diff --git a/llvm/test/CodeGen/SPIRV/transcoding/OpExtInst_vector_promoton.ll b/llvm/test/CodeGen/SPIRV/transcoding/OpExtInst_vector_promoton.ll
index 731220e52e8e7..6f6a9d71b1c88 100644
--- a/llvm/test/CodeGen/SPIRV/transcoding/OpExtInst_vector_promoton.ll
+++ b/llvm/test/CodeGen/SPIRV/transcoding/OpExtInst_vector_promoton.ll
@@ -10,7 +10,8 @@
 define spir_kernel void @S_MIN() {
 ; CHECK-LABEL:   OpFunction %{{[0-9]+}} None %{{[0-9]+}} ; -- Begin function S_MIN
 ; CHECK-NEXT:    OpLabel
-; CHECK-NEXT:    %{{[0-9]+}} = OpExtInst %{{[0-9]+}} %{{[0-9]+}} s_min %{{[0-9]+}} %{{[0-9]+}}
+; CHECK-NEXT:    %[[VEC:[0-9]+]] = OpCompositeConstruct %[[VECTYPE:[0-9]+]] %[[SCALAR:[0-9]+]] %[[SCALAR]]
+; CHECK-NEXT:    %{{[0-9]+}} = OpExtInst %[[VECTYPE]] %{{[0-9]+}} s_min %{{[0-9]+}} %[[VEC]]
 ; CHECK-NEXT:    OpReturn
 ; CHECK-NEXT:    OpFunctionEnd
 ; CHECK-NEXT:    ; -- End function
@@ -22,7 +23,8 @@ entry:
 define spir_kernel void @U_MIN() {
 ; CHECK-LABEL:   OpFunction %{{[0-9]+}} None %{{[0-9]+}} ; -- Begin function U_MIN
 ; CHECK-NEXT:    OpLabel
-; CHECK-NEXT:    %{{[0-9]+}} = OpExtInst %{{[0-9]+}} %{{[0-9]+}} u_min %{{[0-9]+}} %{{[0-9]+}}
+; CHECK-NEXT:    %[[VEC:[0-9]+]] = OpCompositeConstruct %[[VECTYPE:[0-9]+]] %[[SCALAR:[0-9]+]] %[[SCALAR]]
+; CHECK-NEXT:    %{{[0-9]+}} = OpExtInst %[[VECTYPE]] %{{[0-9]+}} u_min %{{[0-9]+}} %[[VEC]]
 ; CHECK-NEXT:    OpReturn
 ; CHECK-NEXT:    OpFunctionEnd
 ; CHECK-NEXT:    ; -- End function
@@ -34,7 +36,8 @@ entry:
 define spir_kernel void @S_MAX() {
 ; CHECK-LABEL: OpFunction %{{[0-9]+}} None %{{[0-9]+}} ; -- Begin function S_MAX
 ; CHECK-NEXT:    OpLabel
-; CHECK-NEXT:    %{{[0-9]+}} = OpExtInst %{{[0-9]+}} %{{[0-9]+}} s_max %{{[0-9]+}} %{{[0-9]+}}
+; CHECK-NEXT:    %[[VEC:[0-9]+]] = OpCompositeConstruct %[[VECTYPE:[0-9]+]] %[[SCALAR:[0-9]+]] %[[SCALAR]]
+; CHECK-NEXT:    %{{[0-9]+}} = OpExtInst %[[VECTYPE]] %{{[0-9]+}} s_max %{{[0-9]+}} %[[VEC]]
 ; CHECK-NEXT:    OpReturn
 ; CHECK-NEXT:    OpFunctionEnd
 ; CHECK-NEXT:    ; -- End function
@@ -46,7 +49,8 @@ entry:
 define spir_kernel void @F_MIN() {
 ; CHECK-LABEL: OpFunction %{{[0-9]+}} None %{{[0-9]+}} ; -- Begin function F_MIN
 ; CHECK-NEXT:    OpLabel
-; CHECK-NEXT:    %{{[0-9]+}} = OpExtInst %{{[0-9]+}} %{{[0-9]+}} fmin %{{[0-9]+}} %{{[0-9]+}}
+; CHECK-NEXT:    %[[VEC:[0-9]+]] = OpCompositeConstruct %[[VECTYPE:[0-9]+]] %[[SCALAR:[0-9]+]] %[[SCALAR]]
+; CHECK-NEXT:    %{{[0-9]+}} = OpExtInst %[[VECTYPE]] %{{[0-9]+}} fmin %{{[0-9]+}} %[[VEC]]
 ; CHECK-NEXT:    OpReturn
 ; CHECK-NEXT:    OpFunctionEnd
 ; CHECK-NEXT:    ; -- End function
@@ -58,7 +62,8 @@ entry:
 define spir_kernel void @F_MAX() {
 ; CHECK-LABEL:   OpFunction %{{[0-9]+}} None %{{[0-9]+}} ; -- Begin function F_MAX
 ; CHECK-NEXT:    OpLabel
-; CHECK-NEXT:    %{{[0-9]+}} = OpExtInst %{{[0-9]+}} %{{[0-9]+}} fmax %{{[0-9]+}} %{{[0-9]+}}
+; CHECK-NEXT:    %[[VEC:[0-9]+]] = OpCompositeConstruct %[[VECTYPE:[0-9]+]] %[[SCALAR:[0-9]+]] %[[SCALAR]]
+; CHECK-NEXT:    %{{[0-9]+}} = OpExtInst %[[VECTYPE]] %{{[0-9]+}} fmax %{{[0-9]+}} %[[VEC]]
 ; CHECK-NEXT:    OpReturn
 ; CHECK-NEXT:    OpFunctionEnd
 ; CHECK-NEXT:    ; -- End function
@@ -70,7 +75,8 @@ entry:
 define spir_kernel void @F_FMIN() {
 ; CHECK-LABEL:   OpFunction %{{[0-9]+}} None %{{[0-9]+}} ; -- Begin function F_FMIN
 ; CHECK-NEXT:    OpLabel
-; CHECK-NEXT:    %{{[0-9]+}} = OpExtInst %{{[0-9]+}} %{{[0-9]+}} fmin %{{[0-9]+}} %{{[0-9]+}}
+; CHECK-NEXT:    %[[VEC:[0-9]+]] = OpCompositeConstruct %[[VECTYPE:[0-9]+]] %[[SCALAR:[0-9]+]] %[[SCALAR]]
+; CHECK-NEXT:    %{{[0-9]+}} = OpExtInst %[[VECTYPE]] %{{[0-9]+}} fmin %{{[0-9]+}} %[[VEC]]
 ; CHECK-NEXT:    OpReturn
 ; CHECK-NEXT:    OpFunctionEnd
 ; CHECK-NEXT:    ; -- End function
@@ -82,7 +88,8 @@ entry:
 define spir_kernel void @F_FMAX() {
 ; CHECK-LABEL:   OpFunction %{{[0-9]+}} None %{{[0-9]+}} ; -- Begin function F_FMAX
 ; CHECK-NEXT:    OpLabel
-; CHECK-NEXT:    %{{[0-9]+}} = OpExtInst %{{[0-9]+}} %{{[0-9]+}} fmax %{{[0-9]+}} %{{[0-9]+}}
+; CHECK-NEXT:    %[[VEC:[0-9]+]] = OpCompositeConstruct %[[VECTYPE:[0-9]+]] %[[SCALAR:[0-9]+]] %[[SCALAR]]
+; CHECK-NEXT:    %{{[0-9]+}} = OpExtInst %[[VECTYPE]] %{{[0-9]+}} fmax %{{[0-9]+}} %[[VEC]]
 ; CHECK-NEXT:    OpReturn
 ; CHECK-NEXT:    OpFunctionEnd
 ; CHECK-NEXT:    ; -- End function
@@ -94,7 +101,9 @@ entry:
 define spir_kernel void @S_CLAMP() {
 ; CHECK-LABEL:   OpFunction %{{[0-9]+}} None %{{[0-9]+}} ; -- Begin function S_CLAMP
 ; CHECK-NEXT:    OpLabel
-; CHECK-NEXT:    %{{[0-9]+}} = OpExtInst %{{[0-9]+}} %{{[0-9]+}} s_clamp %{{[0-9]+}} %{{[0-9]+}} %{{[0-9]+}}
+; CHECK-NEXT:    %[[VEC_0:[0-9]+]] = OpCompositeConstruct %[[VECTYPE:[0-9]+]] %[[SCALAR_0:[0-9]+]] %[[SCALAR_0]]
+; CHECK-NEXT:    %[[VEC_1:[0-9]+]] = OpCompositeConstruct %[[VECTYPE:[0-9]+]] %[[SCALAR_1:[0-9]+]] %[[SCALAR_1]]
+; CHECK-NEXT:    %{{[0-9]+}} = OpExtInst %[[VECTYPE]] %{{[0-9]+}} s_clamp %{{[0-9]+}} %[[VEC_0]] %[[VEC_1]]
 ; CHECK-NEXT:    OpReturn
 ; CHECK-NEXT:    OpFunctionEnd
 ; CHECK-NEXT:    ; -- End function
@@ -106,7 +115,9 @@ entry:
 define spir_kernel void @F_CLAMP() {
 ; CHECK-LABEL:   OpFunction %{{[0-9]+}} None %{{[0-9]+}} ; -- Begin function F_CLAMP
 ; CHECK-NEXT:    OpLabel
-; CHECK-NEXT:    %{{[0-9]+}} = OpExtInst %{{[0-9]+}} %{{[0-9]+}} fclamp %{{[0-9]+}} %{{[0-9]+}} %{{[0-9]+}}
+; CHECK-NEXT:    %[[VEC_0:[0-9]+]] = OpCompositeConstruct %[[VECTYPE:[0-9]+]] %[[SCALAR_0:[0-9]+]] %[[SCALAR_0]]
+; CHECK-NEXT:    %[[VEC_1:[0-9]+]] = OpCompositeConstruct %[[VECTYPE:[0-9]+]] %[[SCALAR_1:[0-9]+]] %[[SCALAR_1]]
+; CHECK-NEXT:    %{{[0-9]+}} = OpExtInst %[[VECTYPE]] %{{[0-9]+}} fclamp %{{[0-9]+}} %[[VEC_0]] %[[VEC_1]]
 ; CHECK-NEXT:    OpReturn
 ; CHECK-NEXT:    OpFunctionEnd
 ; CHECK-NEXT:    ; -- End function
@@ -118,7 +129,8 @@ entry:
 define spir_kernel void @MIX() {
 ; CHECK-LABEL:   OpFunction %{{[0-9]+}} None %{{[0-9]+}} ; -- Begin function MIX
 ; CHECK-NEXT:    OpLabel
-; CHECK-NEXT:    %{{[0-9]+}} = OpExtInst %{{[0-9]+}} %{{[0-9]+}} mix %{{[0-9]+}} %{{[0-9]+}} %{{[0-9]+}}
+; CHECK-NEXT:    %[[VEC:[0-9]+]] = OpCompositeConstruct %[[VECTYPE:[0-9]+]] %[[SCALAR:[0-9]+]] %[[SCALAR]]
+; CHECK-NEXT:    %{{[0-9]+}} = OpExtInst %[[VECTYPE]] %{{[0-9]+}} mix %{{[0-9]+}} %{{[0-9]+}} %[[VEC]]
 ; CHECK-NEXT:    OpReturn
 ; CHECK-NEXT:    OpFunctionEnd
 ; CHECK-NEXT:    ; -- End function
@@ -130,7 +142,9 @@ entry:
 define spir_kernel void @SMOOTHSTEP() {
 ; CHECK-LABEL:   OpFunction %{{[0-9]+}} None %{{[0-9]+}} ; -- Begin function SMOOTHSTEP
 ; CHECK-NEXT:    OpLabel
-; CHECK-NEXT:    %{{[0-9]+}} = OpExtInst %{{[0-9]+}} %{{[0-9]+}} smoothstep %{{[0-9]+}} %{{[0-9]+}} %{{[0-9]+}}
+; CHECK-NEXT:    %[[VEC_0:[0-9]+]] = OpCompositeConstruct %[[VECTYPE:[0-9]+]] %[[SCALAR_0:[0-9]+]] %[[SCALAR_0]]
+; CHECK-NEXT:    %[[VEC_1:[0-9]+]] = OpCompositeConstruct %[[VECTYPE:[0-9]+]] %[[SCALAR_1:[0-9]+]] %[[SCALAR_1]]
+; CHECK-NEXT:    %{{[0-9]+}} = OpExtInst %[[VECTYPE]] %{{[0-9]+}} smoothstep %[[VEC_0]] %[[VEC_1]] %{{[0-9]+}}
 ; CHECK-NEXT:    OpReturn
 ; CHECK-NEXT:    OpFunctionEnd
 ; CHECK-NEXT:    ; -- End function

>From 7ab63e03d8780b2d250d5387a82710da0c074389 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Juan=20Manuel=20Martinez=20Caama=C3=B1o?=
 <jmartinezcaamao at gmail.com>
Date: Mon, 1 Dec 2025 16:22:03 +0100
Subject: [PATCH 4/5] [Review] for clarity, split the test case in two

---
 .../transcoding/OpExtInst_vector_promoton.ll  | 16 +--------------
 .../OpExtInst_vector_promoton_bug.ll          | 20 +++++++++++++++++++
 2 files changed, 21 insertions(+), 15 deletions(-)
 create mode 100644 llvm/test/CodeGen/SPIRV/transcoding/OpExtInst_vector_promoton_bug.ll

diff --git a/llvm/test/CodeGen/SPIRV/transcoding/OpExtInst_vector_promoton.ll b/llvm/test/CodeGen/SPIRV/transcoding/OpExtInst_vector_promoton.ll
index 6f6a9d71b1c88..9867b274d761c 100644
--- a/llvm/test/CodeGen/SPIRV/transcoding/OpExtInst_vector_promoton.ll
+++ b/llvm/test/CodeGen/SPIRV/transcoding/OpExtInst_vector_promoton.ll
@@ -1,5 +1,5 @@
 ; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s
-; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown %s -o - -filetype=obj | not spirv-val %}
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown %s -o - -filetype=obj | spirv-val %}
 ;
 ; Some OpenCL builtins have mixed vector-scalar variants, but OpExtInt only supports
 ; versions where all the arguments have the same type.
@@ -165,19 +165,6 @@ entry:
   ret void
 }
 
-define spir_kernel void @ill_1() {
-; CHECK-LABEL:   OpFunction %{{[0-9]+}} None %{{[0-9]+}} ; -- Begin function ill_1
-; CHECK-NEXT:    OpLabel
-; This is wrong, we should generate a regular call
-; CHECK-NEXT:    %{{[0-9]+}} = OpExtInst %{{[0-9]+}} %{{[0-9]+}} s_min %{{[0-9]+}} %{{[0-9]+}} %{{[0-9]+}}
-; CHECK-NEXT:    OpReturn
-; CHECK-NEXT:    OpFunctionEnd
-; CHECK-NEXT:    ; -- End function
-entry:
-  tail call spir_func void @_Z3miniii(i32 1, i32 2, i32 3)
-  ret void
-}
-
 declare spir_func <2 x i32> @_Z3minDv2_ii(<2 x i32>, i32)
 declare spir_func <2 x i32> @_Z3minDv2_jj(<2 x i32>, i32)
 declare spir_func <2 x i32> @_Z3maxDv2_ii(<2 x i32>, i32)
@@ -190,4 +177,3 @@ declare spir_func <2 x float> @_Z5clampDv2_fff(<2 x float>, float)
 declare spir_func <2 x float> @_Z3mixDv2_fS_f(<2 x float>, <2 x float>, float)
 declare spir_func <2 x float> @_Z10smoothstepffDv2_f(float, float, <2 x float>)
 declare spir_func void @_Z3minv()
-declare spir_func i32 @_Z3miniii(i32, i32, i32)
diff --git a/llvm/test/CodeGen/SPIRV/transcoding/OpExtInst_vector_promoton_bug.ll b/llvm/test/CodeGen/SPIRV/transcoding/OpExtInst_vector_promoton_bug.ll
new file mode 100644
index 0000000000000..5037d15e65cde
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/transcoding/OpExtInst_vector_promoton_bug.ll
@@ -0,0 +1,20 @@
+; XFAIL: *
+; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+;
+; _Z3miniii is not a valid OpenCL intrinsic, do not treat it like one.
+
+define spir_kernel void @ill_1() {
+; CHECK-LABEL:   OpFunction %{{[0-9]+}} None %{{[0-9]+}} ; -- Begin function ill_1
+; CHECK-NEXT:    OpLabel
+; This is wrong, we should generate a regular call
+; CHECK-NEXT:    %{{[0-9]+}} = OpExtInst %{{[0-9]+}} %{{[0-9]+}} s_min %{{[0-9]+}} %{{[0-9]+}} %{{[0-9]+}}
+; CHECK-NEXT:    OpReturn
+; CHECK-NEXT:    OpFunctionEnd
+; CHECK-NEXT:    ; -- End function
+entry:
+  tail call spir_func void @_Z3miniii(i32 1, i32 2, i32 3)
+  ret void
+}
+
+declare spir_func i32 @_Z3miniii(i32, i32, i32)

>From b0a276ad627f719c462cfc26a3c4ef68feefb92b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Juan=20Manuel=20Martinez=20Caama=C3=B1o?=
 <jmartinezcaamao at gmail.com>
Date: Mon, 1 Dec 2025 17:13:58 +0100
Subject: [PATCH 5/5] [Review] Fix the _bug test such that it passes if
 spirv-tools is not available.

---
 .../CodeGen/SPIRV/transcoding/OpExtInst_vector_promoton.ll | 4 ++--
 .../SPIRV/transcoding/OpExtInst_vector_promoton_bug.ll     | 7 ++++---
 2 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/llvm/test/CodeGen/SPIRV/transcoding/OpExtInst_vector_promoton.ll b/llvm/test/CodeGen/SPIRV/transcoding/OpExtInst_vector_promoton.ll
index 9867b274d761c..56bf7fa7605de 100644
--- a/llvm/test/CodeGen/SPIRV/transcoding/OpExtInst_vector_promoton.ll
+++ b/llvm/test/CodeGen/SPIRV/transcoding/OpExtInst_vector_promoton.ll
@@ -1,5 +1,5 @@
-; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s
-; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+; RUN: llc -O0 -mtriple=spirv32-unknown-unknown < %s | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown < %s -filetype=obj | spirv-val %}
 ;
 ; Some OpenCL builtins have mixed vector-scalar variants, but OpExtInt only supports
 ; versions where all the arguments have the same type.
diff --git a/llvm/test/CodeGen/SPIRV/transcoding/OpExtInst_vector_promoton_bug.ll b/llvm/test/CodeGen/SPIRV/transcoding/OpExtInst_vector_promoton_bug.ll
index 5037d15e65cde..b81f373be33c3 100644
--- a/llvm/test/CodeGen/SPIRV/transcoding/OpExtInst_vector_promoton_bug.ll
+++ b/llvm/test/CodeGen/SPIRV/transcoding/OpExtInst_vector_promoton_bug.ll
@@ -1,8 +1,9 @@
-; XFAIL: *
-; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s
-; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+; RUN: llc -O0 -mtriple=spirv32-unknown-unknown < %s | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown < %s -filetype=obj | not spirv-val 2>&1 | FileCheck %s --check-prefix=VALIDATOR %}
 ;
 ; _Z3miniii is not a valid OpenCL intrinsic, do not treat it like one.
+;
+; VALIDATOR: Invalid instruction OpExtInst starting at word {{[0-9]+}}: expected no more operands after 7 words, but stated word count is 8
 
 define spir_kernel void @ill_1() {
 ; CHECK-LABEL:   OpFunction %{{[0-9]+}} None %{{[0-9]+}} ; -- Begin function ill_1



More information about the llvm-commits mailing list