Skip to content

Commit 78a0103

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 db52c15 commit 78a0103

File tree

4 files changed

+153
-78
lines changed

4 files changed

+153
-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 translateIntrinsic(
301+
const CallBase &CB, Intrinsic::ID ID, MachineIRBuilder &MIRBuilder,
302+
const 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: 40 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2817,20 +2817,34 @@ bool IRTranslator::translateCall(const User &U, MachineIRBuilder &MIRBuilder) {
28172817
if (translateKnownIntrinsic(CI, ID, MIRBuilder))
28182818
return true;
28192819

2820+
TargetLowering::IntrinsicInfo Info;
2821+
bool IsTgtMemIntrinsic = TLI->getTgtMemIntrinsic(Info, CI, *MF, ID);
2822+
2823+
return translateIntrinsic(CI, ID, MIRBuilder,
2824+
IsTgtMemIntrinsic ? &Info : nullptr);
2825+
}
2826+
2827+
/// Translate a call to an intrinsic.
2828+
/// Depending on whether TLI->getTgtMemIntrinsic() is true, TgtMemIntrinsicInfo
2829+
/// is a pointer to the correspondingly populated IntrinsicInfo object.
2830+
/// Otherwise, this pointer is null.
2831+
bool IRTranslator::translateIntrinsic(
2832+
const CallBase &CB, Intrinsic::ID ID, MachineIRBuilder &MIRBuilder,
2833+
const TargetLowering::IntrinsicInfo *TgtMemIntrinsicInfo) {
28202834
ArrayRef<Register> ResultRegs;
2821-
if (!CI.getType()->isVoidTy())
2822-
ResultRegs = getOrCreateVRegs(CI);
2835+
if (!CB.getType()->isVoidTy())
2836+
ResultRegs = getOrCreateVRegs(CB);
28232837

28242838
// Ignore the callsite attributes. Backend code is most likely not expecting
28252839
// an intrinsic to sometimes have side effects and sometimes not.
28262840
MachineInstrBuilder MIB = MIRBuilder.buildIntrinsic(ID, ResultRegs);
2827-
if (isa<FPMathOperator>(CI))
2828-
MIB->copyIRFlags(CI);
2841+
if (isa<FPMathOperator>(CB))
2842+
MIB->copyIRFlags(CB);
28292843

2830-
for (const auto &Arg : enumerate(CI.args())) {
2844+
for (const auto &Arg : enumerate(CB.args())) {
28312845
// If this is required to be an immediate, don't materialize it in a
28322846
// register.
2833-
if (CI.paramHasAttr(Arg.index(), Attribute::ImmArg)) {
2847+
if (CB.paramHasAttr(Arg.index(), Attribute::ImmArg)) {
28342848
if (ConstantInt *CI = dyn_cast<ConstantInt>(Arg.value())) {
28352849
// imm arguments are more convenient than cimm (and realistically
28362850
// probably sufficient), so use them.
@@ -2859,29 +2873,33 @@ bool IRTranslator::translateCall(const User &U, MachineIRBuilder &MIRBuilder) {
28592873
}
28602874

28612875
// Add a MachineMemOperand if it is a target mem intrinsic.
2862-
TargetLowering::IntrinsicInfo Info;
2863-
// TODO: Add a GlobalISel version of getTgtMemIntrinsic.
2864-
if (TLI->getTgtMemIntrinsic(Info, CI, *MF, ID)) {
2865-
Align Alignment = Info.align.value_or(
2866-
DL->getABITypeAlign(Info.memVT.getTypeForEVT(F->getContext())));
2867-
LLT MemTy = Info.memVT.isSimple()
2868-
? getLLTForMVT(Info.memVT.getSimpleVT())
2869-
: LLT::scalar(Info.memVT.getStoreSizeInBits());
2876+
if (TgtMemIntrinsicInfo) {
2877+
const Function *F = CB.getCalledFunction();
2878+
2879+
Align Alignment = TgtMemIntrinsicInfo->align.value_or(DL->getABITypeAlign(
2880+
TgtMemIntrinsicInfo->memVT.getTypeForEVT(F->getContext())));
2881+
LLT MemTy =
2882+
TgtMemIntrinsicInfo->memVT.isSimple()
2883+
? getLLTForMVT(TgtMemIntrinsicInfo->memVT.getSimpleVT())
2884+
: LLT::scalar(TgtMemIntrinsicInfo->memVT.getStoreSizeInBits());
28702885

28712886
// TODO: We currently just fallback to address space 0 if getTgtMemIntrinsic
28722887
// didn't yield anything useful.
28732888
MachinePointerInfo MPI;
2874-
if (Info.ptrVal)
2875-
MPI = MachinePointerInfo(Info.ptrVal, Info.offset);
2876-
else if (Info.fallbackAddressSpace)
2877-
MPI = MachinePointerInfo(*Info.fallbackAddressSpace);
2889+
if (TgtMemIntrinsicInfo->ptrVal) {
2890+
MPI = MachinePointerInfo(TgtMemIntrinsicInfo->ptrVal,
2891+
TgtMemIntrinsicInfo->offset);
2892+
} else if (TgtMemIntrinsicInfo->fallbackAddressSpace) {
2893+
MPI = MachinePointerInfo(*TgtMemIntrinsicInfo->fallbackAddressSpace);
2894+
}
28782895
MIB.addMemOperand(MF->getMachineMemOperand(
2879-
MPI, Info.flags, MemTy, Alignment, CI.getAAMetadata(),
2880-
/*Ranges=*/nullptr, Info.ssid, Info.order, Info.failureOrder));
2896+
MPI, TgtMemIntrinsicInfo->flags, MemTy, Alignment, CB.getAAMetadata(),
2897+
/*Ranges=*/nullptr, TgtMemIntrinsicInfo->ssid,
2898+
TgtMemIntrinsicInfo->order, TgtMemIntrinsicInfo->failureOrder));
28812899
}
28822900

2883-
if (CI.isConvergent()) {
2884-
if (auto Bundle = CI.getOperandBundle(LLVMContext::OB_convergencectrl)) {
2901+
if (CB.isConvergent()) {
2902+
if (auto Bundle = CB.getOperandBundle(LLVMContext::OB_convergencectrl)) {
28852903
auto *Token = Bundle->Inputs[0].get();
28862904
Register TokenReg = getOrCreateVReg(*Token);
28872905
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
@@ -3526,8 +3526,7 @@ void SelectionDAGBuilder::visitCallBr(const CallBrInst &I) {
35263526

35273527
// Update successor info.
35283528
addSuccessorWithProb(CallBrMBB, Return, BranchProbability::getOne());
3529-
for (unsigned i = 0, e = I.getNumIndirectDests(); i < e; ++i) {
3530-
BasicBlock *Dest = I.getIndirectDest(i);
3529+
for (BasicBlock *Dest : I.getIndirectDests()) {
35313530
MachineBasicBlock *Target = FuncInfo.getMBB(Dest);
35323531
Target->setIsInlineAsmBrIndirectTarget();
35333532
// If we introduce a type of asm goto statement that is permitted to use an
@@ -5313,18 +5312,26 @@ void SelectionDAGBuilder::visitAtomicStore(const StoreInst &I) {
53135312
DAG.setRoot(OutChain);
53145313
}
53155314

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

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

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

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

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

53755393
if (HasChain)
53765394
ValueVTs.push_back(MVT::Other);
53775395

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

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

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

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

54505492
setValue(&I, Result);
54515493
}

llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -727,6 +727,17 @@ class SelectionDAGBuilder {
727727
MCSymbol *&BeginLabel);
728728
SDValue lowerEndEH(SDValue Chain, const InvokeInst *II,
729729
const BasicBlock *EHPadBB, MCSymbol *BeginLabel);
730+
731+
std::pair<bool, bool> getTargetIntrinsicCallProperties(const CallBase &I);
732+
SmallVector<SDValue, 8> getTargetIntrinsicOperands(
733+
const CallBase &I, bool HasChain, bool OnlyLoad,
734+
TargetLowering::IntrinsicInfo *TgtMemIntrinsicInfo = nullptr);
735+
SDVTList getTargetIntrinsicVTList(const CallBase &I, bool HasChain);
736+
SDValue getTargetNonMemIntrinsicNode(const Type &IntrinsicVT, bool HasChain,
737+
ArrayRef<SDValue> Ops,
738+
const SDVTList &VTs);
739+
SDValue handleTargetIntrinsicRet(const CallBase &I, bool HasChain,
740+
bool OnlyLoad, SDValue Result);
730741
};
731742

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

0 commit comments

Comments
 (0)