Skip to content

Commit 458c685

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 1975e4b commit 458c685

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
@@ -2800,20 +2800,34 @@ bool IRTranslator::translateCall(const User &U, MachineIRBuilder &MIRBuilder) {
28002800
if (translateKnownIntrinsic(CI, ID, MIRBuilder))
28012801
return true;
28022802

2803+
TargetLowering::IntrinsicInfo Info;
2804+
bool IsTgtMemIntrinsic = TLI->getTgtMemIntrinsic(Info, CI, *MF, ID);
2805+
2806+
return translateTargetIntrinsic(CI, ID, MIRBuilder,
2807+
IsTgtMemIntrinsic ? &Info : nullptr);
2808+
}
2809+
2810+
/// Translate a call to a target intrinsic.
2811+
/// Depending on whether TLI->getTgtMemIntrinsic() is true, TgtMemIntrinsicInfo
2812+
/// is a pointer to the correspondingly populated IntrinsicInfo object.
2813+
/// Otherwise, this pointer is null.
2814+
bool IRTranslator::translateTargetIntrinsic(
2815+
const CallBase &CB, Intrinsic::ID ID, MachineIRBuilder &MIRBuilder,
2816+
TargetLowering::IntrinsicInfo *TgtMemIntrinsicInfo) {
28032817
ArrayRef<Register> ResultRegs;
2804-
if (!CI.getType()->isVoidTy())
2805-
ResultRegs = getOrCreateVRegs(CI);
2818+
if (!CB.getType()->isVoidTy())
2819+
ResultRegs = getOrCreateVRegs(CB);
28062820

28072821
// Ignore the callsite attributes. Backend code is most likely not expecting
28082822
// an intrinsic to sometimes have side effects and sometimes not.
28092823
MachineInstrBuilder MIB = MIRBuilder.buildIntrinsic(ID, ResultRegs);
2810-
if (isa<FPMathOperator>(CI))
2811-
MIB->copyIRFlags(CI);
2824+
if (isa<FPMathOperator>(CB))
2825+
MIB->copyIRFlags(CB);
28122826

2813-
for (const auto &Arg : enumerate(CI.args())) {
2827+
for (const auto &Arg : enumerate(CB.args())) {
28142828
// If this is required to be an immediate, don't materialize it in a
28152829
// register.
2816-
if (CI.paramHasAttr(Arg.index(), Attribute::ImmArg)) {
2830+
if (CB.paramHasAttr(Arg.index(), Attribute::ImmArg)) {
28172831
if (ConstantInt *CI = dyn_cast<ConstantInt>(Arg.value())) {
28182832
// imm arguments are more convenient than cimm (and realistically
28192833
// probably sufficient), so use them.
@@ -2842,29 +2856,32 @@ bool IRTranslator::translateCall(const User &U, MachineIRBuilder &MIRBuilder) {
28422856
}
28432857

28442858
// Add a MachineMemOperand if it is a target mem intrinsic.
2845-
TargetLowering::IntrinsicInfo Info;
2846-
// TODO: Add a GlobalISel version of getTgtMemIntrinsic.
2847-
if (TLI->getTgtMemIntrinsic(Info, CI, *MF, ID)) {
2848-
Align Alignment = Info.align.value_or(
2849-
DL->getABITypeAlign(Info.memVT.getTypeForEVT(F->getContext())));
2850-
LLT MemTy = Info.memVT.isSimple()
2851-
? getLLTForMVT(Info.memVT.getSimpleVT())
2852-
: LLT::scalar(Info.memVT.getStoreSizeInBits());
2859+
if (TgtMemIntrinsicInfo) {
2860+
const Function *F = CB.getCalledFunction();
2861+
2862+
Align Alignment = TgtMemIntrinsicInfo->align.value_or(DL->getABITypeAlign(
2863+
TgtMemIntrinsicInfo->memVT.getTypeForEVT(F->getContext())));
2864+
LLT MemTy =
2865+
TgtMemIntrinsicInfo->memVT.isSimple()
2866+
? getLLTForMVT(TgtMemIntrinsicInfo->memVT.getSimpleVT())
2867+
: LLT::scalar(TgtMemIntrinsicInfo->memVT.getStoreSizeInBits());
28532868

28542869
// TODO: We currently just fallback to address space 0 if getTgtMemIntrinsic
28552870
// didn't yield anything useful.
28562871
MachinePointerInfo MPI;
2857-
if (Info.ptrVal)
2858-
MPI = MachinePointerInfo(Info.ptrVal, Info.offset);
2859-
else if (Info.fallbackAddressSpace)
2860-
MPI = MachinePointerInfo(*Info.fallbackAddressSpace);
2872+
if (TgtMemIntrinsicInfo->ptrVal)
2873+
MPI = MachinePointerInfo(TgtMemIntrinsicInfo->ptrVal,
2874+
TgtMemIntrinsicInfo->offset);
2875+
else if (TgtMemIntrinsicInfo->fallbackAddressSpace)
2876+
MPI = MachinePointerInfo(*TgtMemIntrinsicInfo->fallbackAddressSpace);
28612877
MIB.addMemOperand(MF->getMachineMemOperand(
2862-
MPI, Info.flags, MemTy, Alignment, CI.getAAMetadata(),
2863-
/*Ranges=*/nullptr, Info.ssid, Info.order, Info.failureOrder));
2878+
MPI, TgtMemIntrinsicInfo->flags, MemTy, Alignment, CB.getAAMetadata(),
2879+
/*Ranges=*/nullptr, TgtMemIntrinsicInfo->ssid,
2880+
TgtMemIntrinsicInfo->order, TgtMemIntrinsicInfo->failureOrder));
28642881
}
28652882

2866-
if (CI.isConvergent()) {
2867-
if (auto Bundle = CI.getOperandBundle(LLVMContext::OB_convergencectrl)) {
2883+
if (CB.isConvergent()) {
2884+
if (auto Bundle = CB.getOperandBundle(LLVMContext::OB_convergencectrl)) {
28682885
auto *Token = Bundle->Inputs[0].get();
28692886
Register TokenReg = getOrCreateVReg(*Token);
28702887
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
@@ -3489,8 +3489,7 @@ void SelectionDAGBuilder::visitCallBr(const CallBrInst &I) {
34893489

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

5315-
/// visitTargetIntrinsic - Lower a call of a target intrinsic to an INTRINSIC
5316-
/// node.
5317-
void SelectionDAGBuilder::visitTargetIntrinsic(const CallInst &I,
5318-
unsigned Intrinsic) {
5319-
// Ignore the callsite's attributes. A specific call site may be marked with
5320-
// readnone, but the lowering code will expect the chain based on the
5321-
// definition.
5314+
/// Check if this intrinsic call depends on the chain (1st return value)
5315+
/// and if it only *loads* memory.
5316+
/// Ignore the callsite's attributes. A specific call site may be marked with
5317+
/// readnone, but the lowering code will expect the chain based on the
5318+
/// definition.
5319+
std::pair<bool, bool>
5320+
SelectionDAGBuilder::getTargetIntrinsicCallProperties(const CallBase &I) {
53225321
const Function *F = I.getCalledFunction();
53235322
bool HasChain = !F->doesNotAccessMemory();
53245323
bool OnlyLoad =
53255324
HasChain && F->onlyReadsMemory() && F->willReturn() && F->doesNotThrow();
53265325

5326+
return {HasChain, OnlyLoad};
5327+
}
5328+
5329+
SmallVector<SDValue, 8> SelectionDAGBuilder::getTargetIntrinsicOperands(
5330+
const CallBase &I, bool HasChain, bool OnlyLoad,
5331+
TargetLowering::IntrinsicInfo *TgtMemIntrinsicInfo) {
5332+
const TargetLowering &TLI = DAG.getTargetLoweringInfo();
5333+
53275334
// Build the operand list.
53285335
SmallVector<SDValue, 8> Ops;
53295336
if (HasChain) { // If this intrinsic has side-effects, chainify it.
@@ -5335,17 +5342,10 @@ void SelectionDAGBuilder::visitTargetIntrinsic(const CallInst &I,
53355342
}
53365343
}
53375344

5338-
// Info is set by getTgtMemIntrinsic
5339-
TargetLowering::IntrinsicInfo Info;
5340-
const TargetLowering &TLI = DAG.getTargetLoweringInfo();
5341-
bool IsTgtIntrinsic = TLI.getTgtMemIntrinsic(Info, I,
5342-
DAG.getMachineFunction(),
5343-
Intrinsic);
5344-
53455345
// Add the intrinsic ID as an integer operand if it's not a target intrinsic.
5346-
if (!IsTgtIntrinsic || Info.opc == ISD::INTRINSIC_VOID ||
5347-
Info.opc == ISD::INTRINSIC_W_CHAIN)
5348-
Ops.push_back(DAG.getTargetConstant(Intrinsic, getCurSDLoc(),
5346+
if (!TgtMemIntrinsicInfo || TgtMemIntrinsicInfo->opc == ISD::INTRINSIC_VOID ||
5347+
TgtMemIntrinsicInfo->opc == ISD::INTRINSIC_W_CHAIN)
5348+
Ops.push_back(DAG.getTargetConstant(I.getIntrinsicID(), getCurSDLoc(),
53495349
TLI.getPointerTy(DAG.getDataLayout())));
53505350

53515351
// Add all operands of the call to the operand list.
@@ -5368,13 +5368,88 @@ void SelectionDAGBuilder::visitTargetIntrinsic(const CallInst &I,
53685368
}
53695369
}
53705370

5371+
if (auto Bundle = I.getOperandBundle(LLVMContext::OB_convergencectrl)) {
5372+
auto *Token = Bundle->Inputs[0].get();
5373+
SDValue ConvControlToken = getValue(Token);
5374+
assert(Ops.back().getValueType() != MVT::Glue &&
5375+
"Did not expected another glue node here.");
5376+
ConvControlToken =
5377+
DAG.getNode(ISD::CONVERGENCECTRL_GLUE, {}, MVT::Glue, ConvControlToken);
5378+
Ops.push_back(ConvControlToken);
5379+
}
5380+
5381+
return Ops;
5382+
}
5383+
5384+
SDVTList SelectionDAGBuilder::getTargetIntrinsicVTList(const CallBase &I,
5385+
bool HasChain) {
5386+
const TargetLowering &TLI = DAG.getTargetLoweringInfo();
5387+
53715388
SmallVector<EVT, 4> ValueVTs;
53725389
ComputeValueVTs(TLI, DAG.getDataLayout(), I.getType(), ValueVTs);
53735390

53745391
if (HasChain)
53755392
ValueVTs.push_back(MVT::Other);
53765393

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

53795454
// Propagate fast-math-flags from IR to node(s).
53805455
SDNodeFlags Flags;
@@ -5385,19 +5460,9 @@ void SelectionDAGBuilder::visitTargetIntrinsic(const CallInst &I,
53855460
// Create the node.
53865461
SDValue Result;
53875462

5388-
if (auto Bundle = I.getOperandBundle(LLVMContext::OB_convergencectrl)) {
5389-
auto *Token = Bundle->Inputs[0].get();
5390-
SDValue ConvControlToken = getValue(Token);
5391-
assert(Ops.back().getValueType() != MVT::Glue &&
5392-
"Did not expected another glue node here.");
5393-
ConvControlToken =
5394-
DAG.getNode(ISD::CONVERGENCECTRL_GLUE, {}, MVT::Glue, ConvControlToken);
5395-
Ops.push_back(ConvControlToken);
5396-
}
5397-
53985463
// In some cases, custom collection of operands from CallInst I may be needed.
53995464
TLI.CollectTargetIntrinsicOperands(I, Ops, DAG);
5400-
if (IsTgtIntrinsic) {
5465+
if (IsTgtMemIntrinsic) {
54015466
// This is target intrinsic that touches memory
54025467
//
54035468
// TODO: We currently just fallback to address space 0 if getTgtMemIntrinsic
@@ -5417,34 +5482,11 @@ void SelectionDAGBuilder::visitTargetIntrinsic(const CallInst &I,
54175482
Info.ssid, Info.order, Info.failureOrder);
54185483
Result =
54195484
DAG.getMemIntrinsicNode(Info.opc, getCurSDLoc(), VTs, Ops, MemVT, MMO);
5420-
} else if (!HasChain) {
5421-
Result = DAG.getNode(ISD::INTRINSIC_WO_CHAIN, getCurSDLoc(), VTs, Ops);
5422-
} else if (!I.getType()->isVoidTy()) {
5423-
Result = DAG.getNode(ISD::INTRINSIC_W_CHAIN, getCurSDLoc(), VTs, Ops);
54245485
} else {
5425-
Result = DAG.getNode(ISD::INTRINSIC_VOID, getCurSDLoc(), VTs, Ops);
5486+
Result = getTargetNonMemIntrinsicNode(I, HasChain, Ops, VTs);
54265487
}
54275488

5428-
if (HasChain) {
5429-
SDValue Chain = Result.getValue(Result.getNode()->getNumValues()-1);
5430-
if (OnlyLoad)
5431-
PendingLoads.push_back(Chain);
5432-
else
5433-
DAG.setRoot(Chain);
5434-
}
5435-
5436-
if (!I.getType()->isVoidTy()) {
5437-
if (!isa<VectorType>(I.getType()))
5438-
Result = lowerRangeToAssertZExt(DAG, I, Result);
5439-
5440-
MaybeAlign Alignment = I.getRetAlign();
5441-
5442-
// Insert `assertalign` node if there's an alignment.
5443-
if (InsertAssertAlign && Alignment) {
5444-
Result =
5445-
DAG.getAssertAlign(getCurSDLoc(), Result, Alignment.valueOrOne());
5446-
}
5447-
}
5489+
Result = handleTargetIntrinsicRet(I, HasChain, OnlyLoad, Result);
54485490

54495491
setValue(&I, Result);
54505492
}

llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h

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

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

0 commit comments

Comments
 (0)