Skip to content

Commit 94a4337

Browse files
committed
[NFC] Refactor target intrinsic call lowering
Refactor intrinsic call handling in SelectionDAGBuilder and IRTranslator to prepare the addition of intrinsic support to the callbr instruction, which should then share code with the handling of the normal call instruction.
1 parent 47408c3 commit 94a4337

File tree

4 files changed

+152
-78
lines changed

4 files changed

+152
-78
lines changed

llvm/include/llvm/CodeGen/GlobalISel/IRTranslator.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,10 @@ class IRTranslator : public MachineFunctionPass {
297297
/// \pre \p U is a call instruction.
298298
bool translateCall(const User &U, MachineIRBuilder &MIRBuilder);
299299

300+
bool translateTargetIntrinsic(
301+
const CallBase &CB, Intrinsic::ID ID, MachineIRBuilder &MIRBuilder,
302+
TargetLowering::IntrinsicInfo *TgtMemIntrinsicInfo = nullptr);
303+
300304
/// When an invoke or a cleanupret unwinds to the next EH pad, there are
301305
/// many places it could ultimately go. In the IR, we have a single unwind
302306
/// destination, but in the machine CFG, we enumerate all the possible blocks.

llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp

Lines changed: 39 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2789,20 +2789,34 @@ bool IRTranslator::translateCall(const User &U, MachineIRBuilder &MIRBuilder) {
27892789
if (translateKnownIntrinsic(CI, ID, MIRBuilder))
27902790
return true;
27912791

2792+
TargetLowering::IntrinsicInfo Info;
2793+
bool IsTgtMemIntrinsic = TLI->getTgtMemIntrinsic(Info, CI, *MF, ID);
2794+
2795+
return translateTargetIntrinsic(CI, ID, MIRBuilder,
2796+
IsTgtMemIntrinsic ? &Info : nullptr);
2797+
}
2798+
2799+
/// Translate a call to a target intrinsic.
2800+
/// Depending on whether TLI->getTgtMemIntrinsic() is true, TgtMemIntrinsicInfo
2801+
/// is a pointer to the correspondingly populated IntrinsicInfo object.
2802+
/// Otherwise, this pointer is null.
2803+
bool IRTranslator::translateTargetIntrinsic(
2804+
const CallBase &CB, Intrinsic::ID ID, MachineIRBuilder &MIRBuilder,
2805+
TargetLowering::IntrinsicInfo *TgtMemIntrinsicInfo) {
27922806
ArrayRef<Register> ResultRegs;
2793-
if (!CI.getType()->isVoidTy())
2794-
ResultRegs = getOrCreateVRegs(CI);
2807+
if (!CB.getType()->isVoidTy())
2808+
ResultRegs = getOrCreateVRegs(CB);
27952809

27962810
// Ignore the callsite attributes. Backend code is most likely not expecting
27972811
// an intrinsic to sometimes have side effects and sometimes not.
27982812
MachineInstrBuilder MIB = MIRBuilder.buildIntrinsic(ID, ResultRegs);
2799-
if (isa<FPMathOperator>(CI))
2800-
MIB->copyIRFlags(CI);
2813+
if (isa<FPMathOperator>(CB))
2814+
MIB->copyIRFlags(CB);
28012815

2802-
for (const auto &Arg : enumerate(CI.args())) {
2816+
for (const auto &Arg : enumerate(CB.args())) {
28032817
// If this is required to be an immediate, don't materialize it in a
28042818
// register.
2805-
if (CI.paramHasAttr(Arg.index(), Attribute::ImmArg)) {
2819+
if (CB.paramHasAttr(Arg.index(), Attribute::ImmArg)) {
28062820
if (ConstantInt *CI = dyn_cast<ConstantInt>(Arg.value())) {
28072821
// imm arguments are more convenient than cimm (and realistically
28082822
// probably sufficient), so use them.
@@ -2831,29 +2845,32 @@ bool IRTranslator::translateCall(const User &U, MachineIRBuilder &MIRBuilder) {
28312845
}
28322846

28332847
// Add a MachineMemOperand if it is a target mem intrinsic.
2834-
TargetLowering::IntrinsicInfo Info;
2835-
// TODO: Add a GlobalISel version of getTgtMemIntrinsic.
2836-
if (TLI->getTgtMemIntrinsic(Info, CI, *MF, ID)) {
2837-
Align Alignment = Info.align.value_or(
2838-
DL->getABITypeAlign(Info.memVT.getTypeForEVT(F->getContext())));
2839-
LLT MemTy = Info.memVT.isSimple()
2840-
? getLLTForMVT(Info.memVT.getSimpleVT())
2841-
: LLT::scalar(Info.memVT.getStoreSizeInBits());
2848+
if (TgtMemIntrinsicInfo) {
2849+
const Function *F = CB.getCalledFunction();
2850+
2851+
Align Alignment = TgtMemIntrinsicInfo->align.value_or(DL->getABITypeAlign(
2852+
TgtMemIntrinsicInfo->memVT.getTypeForEVT(F->getContext())));
2853+
LLT MemTy =
2854+
TgtMemIntrinsicInfo->memVT.isSimple()
2855+
? getLLTForMVT(TgtMemIntrinsicInfo->memVT.getSimpleVT())
2856+
: LLT::scalar(TgtMemIntrinsicInfo->memVT.getStoreSizeInBits());
28422857

28432858
// TODO: We currently just fallback to address space 0 if getTgtMemIntrinsic
28442859
// didn't yield anything useful.
28452860
MachinePointerInfo MPI;
2846-
if (Info.ptrVal)
2847-
MPI = MachinePointerInfo(Info.ptrVal, Info.offset);
2848-
else if (Info.fallbackAddressSpace)
2849-
MPI = MachinePointerInfo(*Info.fallbackAddressSpace);
2861+
if (TgtMemIntrinsicInfo->ptrVal)
2862+
MPI = MachinePointerInfo(TgtMemIntrinsicInfo->ptrVal,
2863+
TgtMemIntrinsicInfo->offset);
2864+
else if (TgtMemIntrinsicInfo->fallbackAddressSpace)
2865+
MPI = MachinePointerInfo(*TgtMemIntrinsicInfo->fallbackAddressSpace);
28502866
MIB.addMemOperand(MF->getMachineMemOperand(
2851-
MPI, Info.flags, MemTy, Alignment, CI.getAAMetadata(),
2852-
/*Ranges=*/nullptr, Info.ssid, Info.order, Info.failureOrder));
2867+
MPI, TgtMemIntrinsicInfo->flags, MemTy, Alignment, CB.getAAMetadata(),
2868+
/*Ranges=*/nullptr, TgtMemIntrinsicInfo->ssid,
2869+
TgtMemIntrinsicInfo->order, TgtMemIntrinsicInfo->failureOrder));
28532870
}
28542871

2855-
if (CI.isConvergent()) {
2856-
if (auto Bundle = CI.getOperandBundle(LLVMContext::OB_convergencectrl)) {
2872+
if (CB.isConvergent()) {
2873+
if (auto Bundle = CB.getOperandBundle(LLVMContext::OB_convergencectrl)) {
28572874
auto *Token = Bundle->Inputs[0].get();
28582875
Register TokenReg = getOrCreateVReg(*Token);
28592876
MIB.addUse(TokenReg, RegState::Implicit);

llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp

Lines changed: 98 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -3490,8 +3490,7 @@ void SelectionDAGBuilder::visitCallBr(const CallBrInst &I) {
34903490

34913491
// Update successor info.
34923492
addSuccessorWithProb(CallBrMBB, Return, BranchProbability::getOne());
3493-
for (unsigned i = 0, e = I.getNumIndirectDests(); i < e; ++i) {
3494-
BasicBlock *Dest = I.getIndirectDest(i);
3493+
for (BasicBlock *Dest : I.getIndirectDests()) {
34953494
MachineBasicBlock *Target = FuncInfo.getMBB(Dest);
34963495
Target->setIsInlineAsmBrIndirectTarget();
34973496
// If we introduce a type of asm goto statement that is permitted to use an
@@ -5304,18 +5303,26 @@ void SelectionDAGBuilder::visitAtomicStore(const StoreInst &I) {
53045303
DAG.setRoot(OutChain);
53055304
}
53065305

5307-
/// visitTargetIntrinsic - Lower a call of a target intrinsic to an INTRINSIC
5308-
/// node.
5309-
void SelectionDAGBuilder::visitTargetIntrinsic(const CallInst &I,
5310-
unsigned Intrinsic) {
5311-
// Ignore the callsite's attributes. A specific call site may be marked with
5312-
// readnone, but the lowering code will expect the chain based on the
5313-
// definition.
5306+
/// Check if this intrinsic call depends on the chain (1st return value)
5307+
/// and if it only *loads* memory.
5308+
/// Ignore the callsite's attributes. A specific call site may be marked with
5309+
/// readnone, but the lowering code will expect the chain based on the
5310+
/// definition.
5311+
std::pair<bool, bool>
5312+
SelectionDAGBuilder::getTargetIntrinsicCallProperties(const CallBase &I) {
53145313
const Function *F = I.getCalledFunction();
53155314
bool HasChain = !F->doesNotAccessMemory();
53165315
bool OnlyLoad =
53175316
HasChain && F->onlyReadsMemory() && F->willReturn() && F->doesNotThrow();
53185317

5318+
return {HasChain, OnlyLoad};
5319+
}
5320+
5321+
SmallVector<SDValue, 8> SelectionDAGBuilder::getTargetIntrinsicOperands(
5322+
const CallBase &I, bool HasChain, bool OnlyLoad,
5323+
TargetLowering::IntrinsicInfo *TgtMemIntrinsicInfo) {
5324+
const TargetLowering &TLI = DAG.getTargetLoweringInfo();
5325+
53195326
// Build the operand list.
53205327
SmallVector<SDValue, 8> Ops;
53215328
if (HasChain) { // If this intrinsic has side-effects, chainify it.
@@ -5327,17 +5334,10 @@ void SelectionDAGBuilder::visitTargetIntrinsic(const CallInst &I,
53275334
}
53285335
}
53295336

5330-
// Info is set by getTgtMemIntrinsic
5331-
TargetLowering::IntrinsicInfo Info;
5332-
const TargetLowering &TLI = DAG.getTargetLoweringInfo();
5333-
bool IsTgtIntrinsic = TLI.getTgtMemIntrinsic(Info, I,
5334-
DAG.getMachineFunction(),
5335-
Intrinsic);
5336-
53375337
// Add the intrinsic ID as an integer operand if it's not a target intrinsic.
5338-
if (!IsTgtIntrinsic || Info.opc == ISD::INTRINSIC_VOID ||
5339-
Info.opc == ISD::INTRINSIC_W_CHAIN)
5340-
Ops.push_back(DAG.getTargetConstant(Intrinsic, getCurSDLoc(),
5338+
if (!TgtMemIntrinsicInfo || TgtMemIntrinsicInfo->opc == ISD::INTRINSIC_VOID ||
5339+
TgtMemIntrinsicInfo->opc == ISD::INTRINSIC_W_CHAIN)
5340+
Ops.push_back(DAG.getTargetConstant(I.getIntrinsicID(), getCurSDLoc(),
53415341
TLI.getPointerTy(DAG.getDataLayout())));
53425342

53435343
// Add all operands of the call to the operand list.
@@ -5360,13 +5360,88 @@ void SelectionDAGBuilder::visitTargetIntrinsic(const CallInst &I,
53605360
}
53615361
}
53625362

5363+
if (auto Bundle = I.getOperandBundle(LLVMContext::OB_convergencectrl)) {
5364+
auto *Token = Bundle->Inputs[0].get();
5365+
SDValue ConvControlToken = getValue(Token);
5366+
assert(Ops.back().getValueType() != MVT::Glue &&
5367+
"Did not expected another glue node here.");
5368+
ConvControlToken =
5369+
DAG.getNode(ISD::CONVERGENCECTRL_GLUE, {}, MVT::Glue, ConvControlToken);
5370+
Ops.push_back(ConvControlToken);
5371+
}
5372+
5373+
return Ops;
5374+
}
5375+
5376+
SDVTList SelectionDAGBuilder::getTargetIntrinsicVTList(const CallBase &I,
5377+
bool HasChain) {
5378+
const TargetLowering &TLI = DAG.getTargetLoweringInfo();
5379+
53635380
SmallVector<EVT, 4> ValueVTs;
53645381
ComputeValueVTs(TLI, DAG.getDataLayout(), I.getType(), ValueVTs);
53655382

53665383
if (HasChain)
53675384
ValueVTs.push_back(MVT::Other);
53685385

5369-
SDVTList VTs = DAG.getVTList(ValueVTs);
5386+
return DAG.getVTList(ValueVTs);
5387+
}
5388+
5389+
/// Get an INTRINSIC node for a target intrinsic which does not touch touch
5390+
/// memory.
5391+
SDValue SelectionDAGBuilder::getTargetNonMemIntrinsicNode(
5392+
const CallBase &I, bool HasChain, SmallVector<SDValue, 8> &Ops,
5393+
SDVTList &VTs) {
5394+
if (!HasChain)
5395+
return DAG.getNode(ISD::INTRINSIC_WO_CHAIN, getCurSDLoc(), VTs, Ops);
5396+
if (!I.getType()->isVoidTy())
5397+
return DAG.getNode(ISD::INTRINSIC_W_CHAIN, getCurSDLoc(), VTs, Ops);
5398+
return DAG.getNode(ISD::INTRINSIC_VOID, getCurSDLoc(), VTs, Ops);
5399+
}
5400+
5401+
/// Set root, convert return type if necessaey and check alignment.
5402+
SDValue SelectionDAGBuilder::handleTargetIntrinsicRet(const CallBase &I,
5403+
bool HasChain,
5404+
bool OnlyLoad,
5405+
SDValue Result) {
5406+
if (HasChain) {
5407+
SDValue Chain = Result.getValue(Result.getNode()->getNumValues() - 1);
5408+
if (OnlyLoad)
5409+
PendingLoads.push_back(Chain);
5410+
else
5411+
DAG.setRoot(Chain);
5412+
}
5413+
5414+
if (I.getType()->isVoidTy())
5415+
return Result;
5416+
5417+
if (!isa<VectorType>(I.getType()))
5418+
Result = lowerRangeToAssertZExt(DAG, I, Result);
5419+
5420+
MaybeAlign Alignment = I.getRetAlign();
5421+
5422+
// Insert `assertalign` node if there's an alignment.
5423+
if (InsertAssertAlign && Alignment) {
5424+
Result = DAG.getAssertAlign(getCurSDLoc(), Result, Alignment.valueOrOne());
5425+
}
5426+
5427+
return Result;
5428+
}
5429+
5430+
/// visitTargetIntrinsic - Lower a call of a target intrinsic to an INTRINSIC
5431+
/// node.
5432+
void SelectionDAGBuilder::visitTargetIntrinsic(const CallInst &I,
5433+
unsigned Intrinsic) {
5434+
auto [HasChain, OnlyLoad] = getTargetIntrinsicCallProperties(I);
5435+
5436+
// Info is set by getTgtMemIntrinsic
5437+
TargetLowering::IntrinsicInfo Info;
5438+
const TargetLowering &TLI = DAG.getTargetLoweringInfo();
5439+
bool IsTgtMemIntrinsic =
5440+
TLI.getTgtMemIntrinsic(Info, I, DAG.getMachineFunction(), Intrinsic);
5441+
5442+
SmallVector<SDValue, 8> Ops = getTargetIntrinsicOperands(
5443+
I, HasChain, OnlyLoad, IsTgtMemIntrinsic ? &Info : nullptr);
5444+
SDVTList VTs = getTargetIntrinsicVTList(I, HasChain);
53705445

53715446
// Propagate fast-math-flags from IR to node(s).
53725447
SDNodeFlags Flags;
@@ -5377,19 +5452,9 @@ void SelectionDAGBuilder::visitTargetIntrinsic(const CallInst &I,
53775452
// Create the node.
53785453
SDValue Result;
53795454

5380-
if (auto Bundle = I.getOperandBundle(LLVMContext::OB_convergencectrl)) {
5381-
auto *Token = Bundle->Inputs[0].get();
5382-
SDValue ConvControlToken = getValue(Token);
5383-
assert(Ops.back().getValueType() != MVT::Glue &&
5384-
"Did not expected another glue node here.");
5385-
ConvControlToken =
5386-
DAG.getNode(ISD::CONVERGENCECTRL_GLUE, {}, MVT::Glue, ConvControlToken);
5387-
Ops.push_back(ConvControlToken);
5388-
}
5389-
53905455
// In some cases, custom collection of operands from CallInst I may be needed.
53915456
TLI.CollectTargetIntrinsicOperands(I, Ops, DAG);
5392-
if (IsTgtIntrinsic) {
5457+
if (IsTgtMemIntrinsic) {
53935458
// This is target intrinsic that touches memory
53945459
//
53955460
// TODO: We currently just fallback to address space 0 if getTgtMemIntrinsic
@@ -5409,34 +5474,11 @@ void SelectionDAGBuilder::visitTargetIntrinsic(const CallInst &I,
54095474
Info.ssid, Info.order, Info.failureOrder);
54105475
Result =
54115476
DAG.getMemIntrinsicNode(Info.opc, getCurSDLoc(), VTs, Ops, MemVT, MMO);
5412-
} else if (!HasChain) {
5413-
Result = DAG.getNode(ISD::INTRINSIC_WO_CHAIN, getCurSDLoc(), VTs, Ops);
5414-
} else if (!I.getType()->isVoidTy()) {
5415-
Result = DAG.getNode(ISD::INTRINSIC_W_CHAIN, getCurSDLoc(), VTs, Ops);
54165477
} else {
5417-
Result = DAG.getNode(ISD::INTRINSIC_VOID, getCurSDLoc(), VTs, Ops);
5478+
Result = getTargetNonMemIntrinsicNode(I, HasChain, Ops, VTs);
54185479
}
54195480

5420-
if (HasChain) {
5421-
SDValue Chain = Result.getValue(Result.getNode()->getNumValues()-1);
5422-
if (OnlyLoad)
5423-
PendingLoads.push_back(Chain);
5424-
else
5425-
DAG.setRoot(Chain);
5426-
}
5427-
5428-
if (!I.getType()->isVoidTy()) {
5429-
if (!isa<VectorType>(I.getType()))
5430-
Result = lowerRangeToAssertZExt(DAG, I, Result);
5431-
5432-
MaybeAlign Alignment = I.getRetAlign();
5433-
5434-
// Insert `assertalign` node if there's an alignment.
5435-
if (InsertAssertAlign && Alignment) {
5436-
Result =
5437-
DAG.getAssertAlign(getCurSDLoc(), Result, Alignment.valueOrOne());
5438-
}
5439-
}
5481+
Result = handleTargetIntrinsicRet(I, HasChain, OnlyLoad, Result);
54405482

54415483
setValue(&I, Result);
54425484
}

llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -708,6 +708,17 @@ class SelectionDAGBuilder {
708708
MCSymbol *&BeginLabel);
709709
SDValue lowerEndEH(SDValue Chain, const InvokeInst *II,
710710
const BasicBlock *EHPadBB, MCSymbol *BeginLabel);
711+
712+
std::pair<bool, bool> getTargetIntrinsicCallProperties(const CallBase &I);
713+
SmallVector<SDValue, 8> getTargetIntrinsicOperands(
714+
const CallBase &I, bool HasChain, bool OnlyLoad,
715+
TargetLowering::IntrinsicInfo *TgtMemIntrinsicInfo = nullptr);
716+
SDVTList getTargetIntrinsicVTList(const CallBase &I, bool HasChain);
717+
SDValue getTargetNonMemIntrinsicNode(const CallBase &I, bool HasChain,
718+
SmallVector<SDValue, 8> &Ops,
719+
SDVTList &VTs);
720+
SDValue handleTargetIntrinsicRet(const CallBase &I, bool HasChain,
721+
bool OnlyLoad, SDValue Result);
711722
};
712723

713724
/// This struct represents the registers (physical or virtual)

0 commit comments

Comments
 (0)