[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