[llvm] f57abf5 - [SPIRV] Promote scalar arguments to vector for `OpExtInst` in `generateExtInst` instead of `SPIRVRegularizer` (#170155)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Dec 11 00:17:31 PST 2025
Author: Juan Manuel Martinez CaamaƱo
Date: 2025-12-11T09:17:27+01:00
New Revision: f57abf519b8e3a58182a442a78a09de91105680c
URL: https://github.com/llvm/llvm-project/commit/f57abf519b8e3a58182a442a78a09de91105680c
DIFF: https://github.com/llvm/llvm-project/commit/f57abf519b8e3a58182a442a78a09de91105680c.diff
LOG: [SPIRV] Promote scalar arguments to vector for `OpExtInst` in `generateExtInst` instead of `SPIRVRegularizer` (#170155)
This patch consist of 2 parts:
* A first part that removes the scalar to vector promotion for built-ins
in the `SPIRVRegularizer`;
* and a second part that implements the promotion for built-ins from
scalar to vector in `generateExtInst`.
The implementation in `SPIRVRegularizer` had several issues:
* It rolled its own built-in pattern matching that was extremely
permissive
* the compiler would crash if the built-in had a definition
* the compiler would crash if the built-in had no arguments
* The compiler would crash if there were more than 2 function
definitions in the module.
* It'd be better if this was implemented as a module pass; where we
iterate over the users of the function, instead of scanning the whole
module for callers.
This patch does the scalar to vector promotion just before the
`OpExtInst` is generated. Without relying on the IR transformation.
One change in the generated code from the previous implementation is
that this version uses a single `OpCompositeConstruct` operation to
convert the scalar into a vector. The old implementation inserted an
element at the 0 position in an `undef` vector (using
`OpCompositeInsert`); then copied that element for every vector element
using `OpVectorShuffle`.
This patch also adds a test (`OpExtInst_vector_promotion_bug.ll`) that
highlights an issue in the builtin pattern matching that we're using:
our pattern matching doesn't consider the number of arguments, only the
demangled name, first and last arguments (`min(int,int,int)` matches the same builtin as `min(int, int)`).
Added:
llvm/test/CodeGen/SPIRV/transcoding/OpExtInst_vector_promotion.ll
llvm/test/CodeGen/SPIRV/transcoding/OpExtInst_vector_promotion_bug.ll
Modified:
llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp
llvm/lib/Target/SPIRV/SPIRVRegularizer.cpp
Removed:
llvm/test/CodeGen/SPIRV/transcoding/OpMin.ll
################################################################################
diff --git a/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp b/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp
index e5ba0201c0cc1..b111909fc25cc 100644
--- a/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp
@@ -1154,10 +1154,63 @@ 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
//===----------------------------------------------------------------------===//
+static SmallVector<Register>
+getBuiltinCallArguments(const SPIRV::IncomingCall *Call, uint32_t BuiltinNumber,
+ MachineIRBuilder &MIRBuilder, SPIRVGlobalRegistry *GR) {
+
+ Register ReturnTypeId = GR->getSPIRVTypeID(Call->ReturnType);
+ unsigned ResultElementCount =
+ GR->getScalarOrVectorComponentCount(ReturnTypeId);
+ bool MayNeedPromotionToVec =
+ builtinMayNeedPromotionToVec(BuiltinNumber) && ResultElementCount > 1;
+
+ if (!MayNeedPromotionToVec)
+ return {Call->Arguments.begin(), Call->Arguments.end()};
+
+ SmallVector<Register> Arguments;
+ for (Register Argument : Call->Arguments) {
+ Register VecArg = Argument;
+ SPIRVType *ArgumentType = GR->getSPIRVTypeForVReg(Argument);
+ if (ArgumentType != Call->ReturnType) {
+ VecArg = createVirtualRegister(Call->ReturnType, GR, MIRBuilder);
+ auto VecSplat = MIRBuilder.buildInstr(SPIRV::OpCompositeConstruct)
+ .addDef(VecArg)
+ .addUse(ReturnTypeId);
+ for (unsigned I = 0; I != ResultElementCount; ++I)
+ VecSplat.addUse(Argument);
+ }
+ Arguments.push_back(VecArg);
+ }
+ return Arguments;
+}
+
static bool generateExtInst(const SPIRV::IncomingCall *Call,
MachineIRBuilder &MIRBuilder,
SPIRVGlobalRegistry *GR, const CallBase &CB) {
@@ -1179,16 +1232,21 @@ static bool generateExtInst(const SPIRV::IncomingCall *Call,
: SPIRV::OpenCLExtInst::fmax;
}
+ Register ReturnTypeId = GR->getSPIRVTypeID(Call->ReturnType);
+ SmallVector<Register> Arguments =
+ getBuiltinCallArguments(Call, Number, MIRBuilder, GR);
+
// 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/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_promotion.ll b/llvm/test/CodeGen/SPIRV/transcoding/OpExtInst_vector_promotion.ll
new file mode 100644
index 0000000000000..b406f8b71f7e6
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/transcoding/OpExtInst_vector_promotion.ll
@@ -0,0 +1,179 @@
+; 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.
+;
+; 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: %[[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
+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: %[[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
+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: %[[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
+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: %[[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
+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: %[[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
+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: %[[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
+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: %[[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
+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: %[[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
+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: %[[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
+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: %[[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
+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: %[[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
+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
+}
+
+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()
diff --git a/llvm/test/CodeGen/SPIRV/transcoding/OpExtInst_vector_promotion_bug.ll b/llvm/test/CodeGen/SPIRV/transcoding/OpExtInst_vector_promotion_bug.ll
new file mode 100644
index 0000000000000..b81f373be33c3
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/transcoding/OpExtInst_vector_promotion_bug.ll
@@ -0,0 +1,21 @@
+; 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
+; 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)
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)
More information about the llvm-commits
mailing list