@@ -34,6 +34,12 @@ bool SPIRVCallLowering::lowerReturn(MachineIRBuilder &MIRBuilder,
34
34
const Value *Val, ArrayRef<Register> VRegs,
35
35
FunctionLoweringInfo &FLI,
36
36
Register SwiftErrorVReg) const {
37
+ // Maybe run postponed production of types for function pointers
38
+ if (IndirectCalls.size () > 0 ) {
39
+ produceIndirectPtrTypes (MIRBuilder);
40
+ IndirectCalls.clear ();
41
+ }
42
+
37
43
// Currently all return types should use a single register.
38
44
// TODO: handle the case of multiple registers.
39
45
if (VRegs.size () > 1 )
@@ -292,7 +298,6 @@ bool SPIRVCallLowering::lowerFormalArguments(MachineIRBuilder &MIRBuilder,
292
298
}
293
299
}
294
300
295
- // Generate a SPIR-V type for the function.
296
301
auto MRI = MIRBuilder.getMRI ();
297
302
Register FuncVReg = MRI->createGenericVirtualRegister (LLT::scalar (32 ));
298
303
MRI->setRegClass (FuncVReg, &SPIRV::IDRegClass);
@@ -301,17 +306,17 @@ bool SPIRVCallLowering::lowerFormalArguments(MachineIRBuilder &MIRBuilder,
301
306
SPIRVType *RetTy = GR->getOrCreateSPIRVType (FTy->getReturnType (), MIRBuilder);
302
307
SPIRVType *FuncTy = GR->getOrCreateOpTypeFunctionWithArgs (
303
308
FTy, RetTy, ArgTypeVRegs, MIRBuilder);
304
-
305
- // Build the OpTypeFunction declaring it.
306
309
uint32_t FuncControl = getFunctionControl (F);
307
310
308
- MIRBuilder.buildInstr (SPIRV::OpFunction)
309
- .addDef (FuncVReg)
310
- .addUse (GR->getSPIRVTypeID (RetTy))
311
- .addImm (FuncControl)
312
- .addUse (GR->getSPIRVTypeID (FuncTy));
311
+ // Add OpFunction instruction
312
+ MachineInstrBuilder MB = MIRBuilder.buildInstr (SPIRV::OpFunction)
313
+ .addDef (FuncVReg)
314
+ .addUse (GR->getSPIRVTypeID (RetTy))
315
+ .addImm (FuncControl)
316
+ .addUse (GR->getSPIRVTypeID (FuncTy));
317
+ GR->recordFunctionDefinition (&F, &MB.getInstr ()->getOperand (0 ));
313
318
314
- // Add OpFunctionParameters.
319
+ // Add OpFunctionParameter instructions
315
320
int i = 0 ;
316
321
for (const auto &Arg : F.args ()) {
317
322
assert (VRegs[i].size () == 1 && " Formal arg has multiple vregs" );
@@ -343,9 +348,56 @@ bool SPIRVCallLowering::lowerFormalArguments(MachineIRBuilder &MIRBuilder,
343
348
{static_cast <uint32_t >(LnkTy)}, F.getGlobalIdentifier ());
344
349
}
345
350
351
+ // Handle function pointers decoration
352
+ const auto *ST =
353
+ static_cast <const SPIRVSubtarget *>(&MIRBuilder.getMF ().getSubtarget ());
354
+ bool hasFunctionPointers =
355
+ ST->canUseExtension (SPIRV::Extension::SPV_INTEL_function_pointers);
356
+ if (hasFunctionPointers) {
357
+ if (F.hasFnAttribute (" referenced-indirectly" )) {
358
+ assert ((F.getCallingConv () != CallingConv::SPIR_KERNEL) &&
359
+ " Unexpected 'referenced-indirectly' attribute of the kernel "
360
+ " function" );
361
+ buildOpDecorate (FuncVReg, MIRBuilder,
362
+ SPIRV::Decoration::ReferencedIndirectlyINTEL, {});
363
+ }
364
+ }
365
+
346
366
return true ;
347
367
}
348
368
369
+ // Used to postpone producing of indirect function pointer types after all
370
+ // indirect calls info is collected
371
+ // TODO:
372
+ // - add a topological sort of IndirectCalls to ensure the best types knowledge
373
+ // - we may need to fix function formal parameter types if they are opaque
374
+ // pointers used as function pointers in these indirect calls
375
+ void SPIRVCallLowering::produceIndirectPtrTypes (
376
+ MachineIRBuilder &MIRBuilder) const {
377
+ // Create indirect call data types if any
378
+ MachineFunction &MF = MIRBuilder.getMF ();
379
+ for (auto const &IC : IndirectCalls) {
380
+ SPIRVType *SpirvRetTy = GR->getOrCreateSPIRVType (IC.RetTy , MIRBuilder);
381
+ SmallVector<SPIRVType *, 4 > SpirvArgTypes;
382
+ for (size_t i = 0 ; i < IC.ArgTys .size (); ++i) {
383
+ SPIRVType *SPIRVTy = GR->getOrCreateSPIRVType (IC.ArgTys [i], MIRBuilder);
384
+ SpirvArgTypes.push_back (SPIRVTy);
385
+ if (!GR->getSPIRVTypeForVReg (IC.ArgRegs [i]))
386
+ GR->assignSPIRVTypeToVReg (SPIRVTy, IC.ArgRegs [i], MF);
387
+ }
388
+ // SPIR-V function type:
389
+ FunctionType *FTy =
390
+ FunctionType::get (const_cast <Type *>(IC.RetTy ), IC.ArgTys , false );
391
+ SPIRVType *SpirvFuncTy = GR->getOrCreateOpTypeFunctionWithArgs (
392
+ FTy, SpirvRetTy, SpirvArgTypes, MIRBuilder);
393
+ // SPIR-V pointer to function type:
394
+ SPIRVType *IndirectFuncPtrTy = GR->getOrCreateSPIRVPointerType (
395
+ SpirvFuncTy, MIRBuilder, SPIRV::StorageClass::Function);
396
+ // Correct the Calee type
397
+ GR->assignSPIRVTypeToVReg (IndirectFuncPtrTy, IC.Callee , MF);
398
+ }
399
+ }
400
+
349
401
bool SPIRVCallLowering::lowerCall (MachineIRBuilder &MIRBuilder,
350
402
CallLoweringInfo &Info) const {
351
403
// Currently call returns should have single vregs.
@@ -356,45 +408,44 @@ bool SPIRVCallLowering::lowerCall(MachineIRBuilder &MIRBuilder,
356
408
GR->setCurrentFunc (MF);
357
409
FunctionType *FTy = nullptr ;
358
410
const Function *CF = nullptr ;
411
+ std::string DemangledName;
412
+ const Type *OrigRetTy = Info.OrigRet .Ty ;
359
413
360
414
// Emit a regular OpFunctionCall. If it's an externally declared function,
361
415
// be sure to emit its type and function declaration here. It will be hoisted
362
416
// globally later.
363
417
if (Info.Callee .isGlobal ()) {
418
+ std::string FuncName = Info.Callee .getGlobal ()->getName ().str ();
419
+ DemangledName = getOclOrSpirvBuiltinDemangledName (FuncName);
364
420
CF = dyn_cast_or_null<const Function>(Info.Callee .getGlobal ());
365
421
// TODO: support constexpr casts and indirect calls.
366
422
if (CF == nullptr )
367
423
return false ;
368
- FTy = getOriginalFunctionType (*CF);
424
+ if ((FTy = getOriginalFunctionType (*CF)) != nullptr )
425
+ OrigRetTy = FTy->getReturnType ();
369
426
}
370
427
371
428
MachineRegisterInfo *MRI = MIRBuilder.getMRI ();
372
429
Register ResVReg =
373
430
Info.OrigRet .Regs .empty () ? Register (0 ) : Info.OrigRet .Regs [0 ];
374
- std::string FuncName = Info.Callee .getGlobal ()->getName ().str ();
375
- std::string DemangledName = getOclOrSpirvBuiltinDemangledName (FuncName);
376
431
const auto *ST = static_cast <const SPIRVSubtarget *>(&MF.getSubtarget ());
377
432
// TODO: check that it's OCL builtin, then apply OpenCL_std.
378
433
if (!DemangledName.empty () && CF && CF->isDeclaration () &&
379
434
ST->canUseExtInstSet (SPIRV::InstructionSet::OpenCL_std)) {
380
- const Type *OrigRetTy = Info.OrigRet .Ty ;
381
- if (FTy)
382
- OrigRetTy = FTy->getReturnType ();
383
435
SmallVector<Register, 8 > ArgVRegs;
384
436
for (auto Arg : Info.OrigArgs ) {
385
437
assert (Arg.Regs .size () == 1 && " Call arg has multiple VRegs" );
386
438
ArgVRegs.push_back (Arg.Regs [0 ]);
387
439
SPIRVType *SPIRVTy = GR->getOrCreateSPIRVType (Arg.Ty , MIRBuilder);
388
440
if (!GR->getSPIRVTypeForVReg (Arg.Regs [0 ]))
389
- GR->assignSPIRVTypeToVReg (SPIRVTy, Arg.Regs [0 ], MIRBuilder. getMF () );
441
+ GR->assignSPIRVTypeToVReg (SPIRVTy, Arg.Regs [0 ], MF );
390
442
}
391
443
if (auto Res = SPIRV::lowerBuiltin (
392
444
DemangledName, SPIRV::InstructionSet::OpenCL_std, MIRBuilder,
393
445
ResVReg, OrigRetTy, ArgVRegs, GR))
394
446
return *Res;
395
447
}
396
- if (CF && CF->isDeclaration () &&
397
- !GR->find (CF, &MIRBuilder.getMF ()).isValid ()) {
448
+ if (CF && CF->isDeclaration () && !GR->find (CF, &MF).isValid ()) {
398
449
// Emit the type info and forward function declaration to the first MBB
399
450
// to ensure VReg definition dependencies are valid across all MBBs.
400
451
MachineIRBuilder FirstBlockBuilder;
@@ -416,14 +467,40 @@ bool SPIRVCallLowering::lowerCall(MachineIRBuilder &MIRBuilder,
416
467
lowerFormalArguments (FirstBlockBuilder, *CF, VRegArgs, FuncInfo);
417
468
}
418
469
470
+ unsigned CallOp;
471
+ if (Info.CB ->isIndirectCall ()) {
472
+ if (!ST->canUseExtension (SPIRV::Extension::SPV_INTEL_function_pointers))
473
+ report_fatal_error (" An indirect call is encountered but SPIR-V without "
474
+ " extensions does not support it" ,
475
+ false );
476
+ // Set instruction operation according to SPV_INTEL_function_pointers
477
+ CallOp = SPIRV::OpFunctionPointerCallINTEL;
478
+ // Collect information about the indirect call to support possible
479
+ // specification of opaque ptr types of parent function's parameters
480
+ Register CalleeReg = Info.Callee .getReg ();
481
+ if (CalleeReg.isValid ()) {
482
+ SPIRVCallLowering::SPIRVIndirectCall IndirectCall;
483
+ IndirectCall.Callee = CalleeReg;
484
+ IndirectCall.RetTy = OrigRetTy;
485
+ for (const auto &Arg : Info.OrigArgs ) {
486
+ assert (Arg.Regs .size () == 1 && " Call arg has multiple VRegs" );
487
+ IndirectCall.ArgTys .push_back (Arg.Ty );
488
+ IndirectCall.ArgRegs .push_back (Arg.Regs [0 ]);
489
+ }
490
+ IndirectCalls.push_back (IndirectCall);
491
+ }
492
+ } else {
493
+ // Emit a regular OpFunctionCall
494
+ CallOp = SPIRV::OpFunctionCall;
495
+ }
496
+
419
497
// Make sure there's a valid return reg, even for functions returning void.
420
498
if (!ResVReg.isValid ())
421
499
ResVReg = MIRBuilder.getMRI ()->createVirtualRegister (&SPIRV::IDRegClass);
422
- SPIRVType *RetType =
423
- GR->assignTypeToVReg (FTy->getReturnType (), ResVReg, MIRBuilder);
500
+ SPIRVType *RetType = GR->assignTypeToVReg (OrigRetTy, ResVReg, MIRBuilder);
424
501
425
- // Emit the OpFunctionCall and its args.
426
- auto MIB = MIRBuilder.buildInstr (SPIRV::OpFunctionCall )
502
+ // Emit the call instruction and its args.
503
+ auto MIB = MIRBuilder.buildInstr (CallOp )
427
504
.addDef (ResVReg)
428
505
.addUse (GR->getSPIRVTypeID (RetType))
429
506
.add (Info.Callee );
0 commit comments