[llvm] [SPIRV] Fix enqueue empty kernel (PR #187671)
Dmitry Sidorov via llvm-commits
llvm-commits at lists.llvm.org
Fri Apr 17 05:17:34 PDT 2026
================
@@ -2797,85 +2794,136 @@ getOrCreateSPIRVDeviceEventPointer(MachineIRBuilder &MIRBuilder,
static bool buildEnqueueKernel(const SPIRV::IncomingCall *Call,
MachineIRBuilder &MIRBuilder,
SPIRVGlobalRegistry *GR) {
+ // In this function there are three stages:
+ // 1. prepare call indexes in order we expect them.
+ // 2. process all arguments which requered preparation.
+ // 3. create a SPIRV operator with arguments.
+
MachineRegisterInfo *MRI = MIRBuilder.getMRI();
const DataLayout &DL = MIRBuilder.getDataLayout();
- bool IsSpirvOp = Call->isSpirvOp();
- bool HasEvents = Call->Builtin->Name.contains("events") || IsSpirvOp;
const SPIRVTypeInst Int32Ty = GR->getOrCreateSPIRVIntegerType(32, MIRBuilder);
- // Make vararg instructions before OpEnqueueKernel.
- // Local sizes arguments: Sizes of block invoke arguments. Clang generates
- // local size operands as an array, so we need to unpack them.
+ // 1. prepare call indexes in order we expect them.
+ // Based on clang sources, clang/lib/CodeGen/CGBuiltin.cpp, BIenqueue_kernel,
+ // We expect 4 different layouts of call arguments:
+ // 1) No events, no vargs: {Queue, Flags, Range, Kernel, Block};
+ // 2) No events, varargs: {Queue, Flags, Range, Kernel, Block, NumElem,
+ // ElemPtr};
+ // 3) events, no varargs: {Queue, Flags, Range, NumEvents,
+ // EventWaitList, EventRet, Kernel, Block};
+ // 4) events, varargs: {Queue,
+ // Flags, Range, NumEvents, EventWaitList, EventRet, Kernel, Block,
+ // NumElem, ElemPtr};
+ //
+ // We also may expect __spirv_EnqueueKernel
+
+ bool IsSpirvOp = Call->isSpirvOp();
+ bool HasEvents = Call->Builtin->Name.contains("_events") || IsSpirvOp;
+ bool HasVarArgs = Call->Builtin->Name.contains("_varargs") || IsSpirvOp;
+
+ const unsigned NumArgs = Call->Arguments.size();
+ const unsigned BaseArgIdx = 0;
+ const unsigned IncorrectIdx = NumArgs + 1;
+
+ const unsigned QueueIdx = BaseArgIdx;
+ const unsigned FlagsIdx = BaseArgIdx + 1;
+ const unsigned NDRangeIdx = BaseArgIdx + 2;
+ const unsigned NumEventsIdx = HasEvents ? BaseArgIdx + 3 : IncorrectIdx;
+ const unsigned WaitEventsIdx = HasEvents ? BaseArgIdx + 4 : IncorrectIdx;
+ const unsigned RetEventIdx = HasEvents ? BaseArgIdx + 5 : IncorrectIdx;
+ const unsigned InvokeIdx = BaseArgIdx + 3 + (HasEvents ? 3 : 0);
+ const unsigned ParamIdx = BaseArgIdx + 4 + (HasEvents ? 3 : 0);
+ const unsigned LocalSizeNumElemIdx =
+ HasVarArgs ? (BaseArgIdx + 5 + (HasEvents ? 3 : 0)) : IncorrectIdx;
+ const unsigned LocalSizeElemPtrIdx =
+ HasVarArgs ? (BaseArgIdx + 6 + (HasEvents ? 3 : 0)) : IncorrectIdx;
+
+ const unsigned LastArgIdx =
+ (BaseArgIdx + 4 + (HasEvents ? 3 : 0) + (HasVarArgs ? 2 : 0));
+ assert(LastArgIdx < NumArgs && "Incorrect number arguments");
+
+ // 2. Process all arguments which requered preparation.
+ // 2.1 Events - use Call arguments, or use dummy nulls in case of absence of
+ // events
+ Register NumEventsReg;
+ Register WaitEventsReg;
+ Register RetEventReg;
+ if (HasEvents) {
+ NumEventsReg = Call->Arguments[NumEventsIdx];
+ WaitEventsReg = Call->Arguments[WaitEventsIdx];
+ RetEventReg = Call->Arguments[RetEventIdx];
+ } else {
+ NumEventsReg = buildConstantIntReg32(0, MIRBuilder, GR);
+ Register NullPtr = GR->getOrCreateConstNullPtr(
+ MIRBuilder, getOrCreateSPIRVDeviceEventPointer(MIRBuilder, GR));
+ WaitEventsReg = NullPtr;
+ RetEventReg = NullPtr;
+ }
+
+ // 2.2 Invoke (Kernel)
+ assert(getBlockStructInstr(Call->Arguments[InvokeIdx], MRI)->getOpcode() ==
+ TargetOpcode::G_GLOBAL_VALUE);
+
+ // 2.3 Param, Param Size, Param Align
+ Register BlockLiteralReg = Call->Arguments[ParamIdx];
+ const SPIRVTypeInst Int8Ty = GR->getOrCreateSPIRVIntegerType(8, MIRBuilder);
+ const SPIRVTypeInst Int8PtrGen = GR->getOrCreateSPIRVPointerType(
+ Int8Ty, MIRBuilder, SPIRV::StorageClass::Generic);
+ Type *PType = const_cast<Type *>(getBlockStructType(BlockLiteralReg, MRI));
+
+ Register ParamReg = createVirtualRegister(Int8PtrGen, GR, MIRBuilder);
+ MIRBuilder.buildInstr(SPIRV::OpBitcast)
+ .addDef(ParamReg)
+ .addUse(GR->getSPIRVTypeID(Int8PtrGen))
+ .addUse(BlockLiteralReg);
+ // TODO: these numbers should be obtained from block literal structure.
+ Register ParamSizeReg =
+ buildConstantIntReg32(DL.getTypeStoreSize(PType), MIRBuilder, GR);
+ Register ParamAlignReg =
+ buildConstantIntReg32(DL.getPrefTypeAlign(PType).value(), MIRBuilder, GR);
+
+ // 2.4 Local Size Array
SmallVector<Register, 16> LocalSizes;
- if (Call->Builtin->Name.contains("_varargs") || IsSpirvOp) {
- const unsigned LocalSizeArrayIdx = HasEvents ? 9 : 6;
- Register GepReg = Call->Arguments[LocalSizeArrayIdx];
- MachineInstr *GepMI = MRI->getUniqueVRegDef(GepReg);
- assert(isSpvIntrinsic(*GepMI, Intrinsic::spv_gep) &&
- GepMI->getOperand(3).isReg());
- Register ArrayReg = GepMI->getOperand(3).getReg();
- MachineInstr *ArrayMI = MRI->getUniqueVRegDef(ArrayReg);
- const Type *LocalSizeTy = getMachineInstrType(ArrayMI);
- assert(LocalSizeTy && "Local size type is expected");
- const uint64_t LocalSizeNum =
- cast<ArrayType>(LocalSizeTy)->getNumElements();
- unsigned SC = storageClassToAddressSpace(SPIRV::StorageClass::Generic);
- const LLT LLType = LLT::pointer(SC, GR->getPointerSize());
- const SPIRVTypeInst PointerSizeTy = GR->getOrCreateSPIRVPointerType(
- Int32Ty, MIRBuilder, SPIRV::StorageClass::Function);
- for (unsigned I = 0; I < LocalSizeNum; ++I) {
+ if (HasVarArgs) {
+ Register LocalSizeNumElem = Call->Arguments[LocalSizeNumElemIdx];
+ MachineInstr *LocalSizeNumElemMI = MRI->getUniqueVRegDef(LocalSizeNumElem);
+ const MachineOperand &ConstOp = LocalSizeNumElemMI->getOperand(1);
+ assert(LocalSizeNumElemMI->getOpcode() == TargetOpcode::G_CONSTANT &&
+ ConstOp.isCImm() && "Expected constant immediate");
+ uint64_t NumElem = ConstOp.getCImm()->getValue().getZExtValue();
+
+ Register LocalSizeArrayReg = Call->Arguments[LocalSizeElemPtrIdx];
+
+ for (unsigned i = 0; i < NumElem; ++i) {
Register Reg = MRI->createVirtualRegister(&SPIRV::pIDRegClass);
- MRI->setType(Reg, LLType);
- GR->assignSPIRVTypeToVReg(PointerSizeTy, Reg, MIRBuilder.getMF());
----------------
MrSidims wrote:
Why these are removed?
https://github.com/llvm/llvm-project/pull/187671
More information about the llvm-commits
mailing list