From 0e1a925bb3cccdf1f64ac22d09014cb0c1f4821d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Manuel=20Martinez=20Caama=C3=B1o?= Date: Mon, 1 Dec 2025 12:55:28 +0100 Subject: [PATCH 1/9] [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 5) + ret void +} + +define spir_kernel void @U_MIN() { +entry: + %call = tail call spir_func <2 x i32> @_Z3minDv2_jj(<2 x i32> , 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 5) + ret void +} + +define spir_kernel void @F_MIN() { +entry: + %call = tail call spir_func <2 x float> @_Z3minDv2_ff(<2 x float> , 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 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 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 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 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 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> , <2 x float> , 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> ) + 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 5) #2 - ret void -} - -declare spir_func <2 x i32> @_Z3minDv2_ii(<2 x i32>, i32) From 49b38fe725a5fc3d16cf07748a9d48beea780b22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Manuel=20Martinez=20Caama=C3=B1o?= Date: Mon, 1 Dec 2025 09:46:23 +0100 Subject: [PATCH 2/9] [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 @@ -25,9 +24,7 @@ using namespace llvm; namespace { -struct SPIRVRegularizer : public FunctionPass, InstVisitor { - DenseMap Old2NewFuncs; - +struct SPIRVRegularizer : public FunctionPass { public: static char ID; SPIRVRegularizer() : FunctionPass(ID) {} @@ -37,11 +34,8 @@ struct SPIRVRegularizer : public FunctionPass, InstVisitor { 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(Arg0Ty); - for (unsigned I = 1, E = CI->arg_size(); Uniform && (I != E); ++I) - Uniform = isa(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 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 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 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(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 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 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 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 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 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 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 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 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 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> , <2 x float> , 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> ) 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 b6cc5bbe020864d99e91619e519a6538d0d7b416 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Manuel=20Martinez=20Caama=C3=B1o?= Date: Mon, 1 Dec 2025 12:54:56 +0100 Subject: [PATCH 3/9] [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 e5ba0201c0cc1..97c66e3668a89 100644 --- a/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp @@ -1154,6 +1154,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 //===----------------------------------------------------------------------===// @@ -1179,16 +1202,37 @@ static bool generateExtInst(const SPIRV::IncomingCall *Call, : SPIRV::OpenCLExtInst::fmax; } + Register ReturnTypeId = GR->getSPIRVTypeID(Call->ReturnType); + SmallVector 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(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 f256ad7c89fbe9a253e68a67e155774ee4435a86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Manuel=20Martinez=20Caama=C3=B1o?= Date: Mon, 1 Dec 2025 16:22:03 +0100 Subject: [PATCH 4/9] [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 4c11225c941195d4bcbd257b2d30ddbf9b6c1977 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Manuel=20Martinez=20Caama=C3=B1o?= Date: Mon, 1 Dec 2025 17:13:58 +0100 Subject: [PATCH 5/9] [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 From aa44e80f160b63474b77852a4050c8f6dbfac6f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Manuel=20Martinez=20Caama=C3=B1o?= Date: Wed, 3 Dec 2025 08:57:20 +0100 Subject: [PATCH 6/9] [Review] Broadcast->Splat & Move code to helper --- llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp | 50 ++++++++++++++++--------- 1 file changed, 32 insertions(+), 18 deletions(-) diff --git a/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp b/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp index 97c66e3668a89..0c5e8b4241245 100644 --- a/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp @@ -1181,6 +1181,36 @@ static bool builtinMayNeedPromotionToVec(uint32_t BuiltinNumber) { // Implementation functions for each builtin group //===----------------------------------------------------------------------===// +static SmallVector +getOpExtCallArguments(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 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) { @@ -1203,24 +1233,8 @@ static bool generateExtInst(const SPIRV::IncomingCall *Call, } Register ReturnTypeId = GR->getSPIRVTypeID(Call->ReturnType); - SmallVector 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); - } + SmallVector Arguments = + getOpExtCallArguments(Call, Number, MIRBuilder, GR); // Build extended instruction. auto MIB = From fc77377d8c02aa8af34fa51c93a4b58fee76c71f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Manuel=20Martinez=20Caama=C3=B1o?= Date: Wed, 3 Dec 2025 09:17:15 +0100 Subject: [PATCH 7/9] [Revew] getOpExtCallArguments->getBuiltinCallArguments --- llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp b/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp index 0c5e8b4241245..b111909fc25cc 100644 --- a/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp @@ -1182,8 +1182,8 @@ static bool builtinMayNeedPromotionToVec(uint32_t BuiltinNumber) { //===----------------------------------------------------------------------===// static SmallVector -getOpExtCallArguments(const SPIRV::IncomingCall *Call, uint32_t BuiltinNumber, - MachineIRBuilder &MIRBuilder, SPIRVGlobalRegistry *GR) { +getBuiltinCallArguments(const SPIRV::IncomingCall *Call, uint32_t BuiltinNumber, + MachineIRBuilder &MIRBuilder, SPIRVGlobalRegistry *GR) { Register ReturnTypeId = GR->getSPIRVTypeID(Call->ReturnType); unsigned ResultElementCount = @@ -1234,7 +1234,7 @@ static bool generateExtInst(const SPIRV::IncomingCall *Call, Register ReturnTypeId = GR->getSPIRVTypeID(Call->ReturnType); SmallVector Arguments = - getOpExtCallArguments(Call, Number, MIRBuilder, GR); + getBuiltinCallArguments(Call, Number, MIRBuilder, GR); // Build extended instruction. auto MIB = From cc58394c877ef80e0cdabff41b3ca5be49e52c32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Manuel=20Martinez=20Caama=C3=B1o?= Date: Wed, 10 Dec 2025 14:01:40 +0100 Subject: [PATCH 8/9] [Review] promoton -> promotion in test name --- ...OpExtInst_vector_promoton.ll => OpExtInst_vector_promotion.ll} | 0 ...t_vector_promoton_bug.ll => OpExtInst_vector_promotion_bug.ll} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename llvm/test/CodeGen/SPIRV/transcoding/{OpExtInst_vector_promoton.ll => OpExtInst_vector_promotion.ll} (100%) rename llvm/test/CodeGen/SPIRV/transcoding/{OpExtInst_vector_promoton_bug.ll => OpExtInst_vector_promotion_bug.ll} (100%) diff --git a/llvm/test/CodeGen/SPIRV/transcoding/OpExtInst_vector_promoton.ll b/llvm/test/CodeGen/SPIRV/transcoding/OpExtInst_vector_promotion.ll similarity index 100% rename from llvm/test/CodeGen/SPIRV/transcoding/OpExtInst_vector_promoton.ll rename to llvm/test/CodeGen/SPIRV/transcoding/OpExtInst_vector_promotion.ll diff --git a/llvm/test/CodeGen/SPIRV/transcoding/OpExtInst_vector_promoton_bug.ll b/llvm/test/CodeGen/SPIRV/transcoding/OpExtInst_vector_promotion_bug.ll similarity index 100% rename from llvm/test/CodeGen/SPIRV/transcoding/OpExtInst_vector_promoton_bug.ll rename to llvm/test/CodeGen/SPIRV/transcoding/OpExtInst_vector_promotion_bug.ll From a2b1bda8f73b06472c87d854334fd07165198022 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Manuel=20Martinez=20Caama=C3=B1o?= Date: Wed, 10 Dec 2025 14:12:44 +0100 Subject: [PATCH 9/9] [Review] missing . --- .../CodeGen/SPIRV/transcoding/OpExtInst_vector_promotion.ll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/llvm/test/CodeGen/SPIRV/transcoding/OpExtInst_vector_promotion.ll b/llvm/test/CodeGen/SPIRV/transcoding/OpExtInst_vector_promotion.ll index 56bf7fa7605de..b406f8b71f7e6 100644 --- a/llvm/test/CodeGen/SPIRV/transcoding/OpExtInst_vector_promotion.ll +++ b/llvm/test/CodeGen/SPIRV/transcoding/OpExtInst_vector_promotion.ll @@ -4,8 +4,8 @@ ; 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 +; 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