Skip to content

Commit cad96ad

Browse files
authored
[NFC] Refactor target intrinsic call lowering (#153204)
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 cc8478b commit cad96ad

File tree

4 files changed

+150
-78
lines changed

4 files changed

+150
-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
@@ -2821,20 +2821,34 @@ bool IRTranslator::translateCall(const User &U, MachineIRBuilder &MIRBuilder) {
28212821
if (translateKnownIntrinsic(CI, ID, MIRBuilder))
28222822
return true;
28232823

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

28282842
// Ignore the callsite attributes. Backend code is most likely not expecting
28292843
// an intrinsic to sometimes have side effects and sometimes not.
28302844
MachineInstrBuilder MIB = MIRBuilder.buildIntrinsic(ID, ResultRegs);
2831-
if (isa<FPMathOperator>(CI))
2832-
MIB->copyIRFlags(CI);
2845+
if (isa<FPMathOperator>(CB))
2846+
MIB->copyIRFlags(CB);
28332847

2834-
for (const auto &Arg : enumerate(CI.args())) {
2848+
for (const auto &Arg : enumerate(CB.args())) {
28352849
// If this is required to be an immediate, don't materialize it in a
28362850
// register.
2837-
if (CI.paramHasAttr(Arg.index(), Attribute::ImmArg)) {
2851+
if (CB.paramHasAttr(Arg.index(), Attribute::ImmArg)) {
28382852
if (ConstantInt *CI = dyn_cast<ConstantInt>(Arg.value())) {
28392853
// imm arguments are more convenient than cimm (and realistically
28402854
// probably sufficient), so use them.
@@ -2863,29 +2877,33 @@ bool IRTranslator::translateCall(const User &U, MachineIRBuilder &MIRBuilder) {
28632877
}
28642878

28652879
// Add a MachineMemOperand if it is a target mem intrinsic.
2866-
TargetLowering::IntrinsicInfo Info;
2867-
// TODO: Add a GlobalISel version of getTgtMemIntrinsic.
2868-
if (TLI->getTgtMemIntrinsic(Info, CI, *MF, ID)) {
2869-
Align Alignment = Info.align.value_or(
2870-
DL->getABITypeAlign(Info.memVT.getTypeForEVT(F->getContext())));
2871-
LLT MemTy = Info.memVT.isSimple()
2872-
? getLLTForMVT(Info.memVT.getSimpleVT())
2873-
: LLT::scalar(Info.memVT.getStoreSizeInBits());
2880+
if (TgtMemIntrinsicInfo) {
2881+
const Function *F = CB.getCalledFunction();
2882+
2883+
Align Alignment = TgtMemIntrinsicInfo->align.value_or(DL->getABITypeAlign(
2884+
TgtMemIntrinsicInfo->memVT.getTypeForEVT(F->getContext())));
2885+
LLT MemTy =
2886+
TgtMemIntrinsicInfo->memVT.isSimple()
2887+
? getLLTForMVT(TgtMemIntrinsicInfo->memVT.getSimpleVT())
2888+
: LLT::scalar(TgtMemIntrinsicInfo->memVT.getStoreSizeInBits());
28742889

28752890
// TODO: We currently just fallback to address space 0 if getTgtMemIntrinsic
28762891
// didn't yield anything useful.
28772892
MachinePointerInfo MPI;
2878-
if (Info.ptrVal)
2879-
MPI = MachinePointerInfo(Info.ptrVal, Info.offset);
2880-
else if (Info.fallbackAddressSpace)
2881-
MPI = MachinePointerInfo(*Info.fallbackAddressSpace);
2893+
if (TgtMemIntrinsicInfo->ptrVal) {
2894+
MPI = MachinePointerInfo(TgtMemIntrinsicInfo->ptrVal,
2895+
TgtMemIntrinsicInfo->offset);
2896+
} else if (TgtMemIntrinsicInfo->fallbackAddressSpace) {
2897+
MPI = MachinePointerInfo(*TgtMemIntrinsicInfo->fallbackAddressSpace);
2898+
}
28822899
MIB.addMemOperand(MF->getMachineMemOperand(
2883-
MPI, Info.flags, MemTy, Alignment, CI.getAAMetadata(),
2884-
/*Ranges=*/nullptr, Info.ssid, Info.order, Info.failureOrder));
2900+
MPI, TgtMemIntrinsicInfo->flags, MemTy, Alignment, CB.getAAMetadata(),
2901+
/*Ranges=*/nullptr, TgtMemIntrinsicInfo->ssid,
2902+
TgtMemIntrinsicInfo->order, TgtMemIntrinsicInfo->failureOrder));
28852903
}
28862904

2887-
if (CI.isConvergent()) {
2888-
if (auto Bundle = CI.getOperandBundle(LLVMContext::OB_convergencectrl)) {
2905+
if (CB.isConvergent()) {
2906+
if (auto Bundle = CB.getOperandBundle(LLVMContext::OB_convergencectrl)) {
28892907
auto *Token = Bundle->Inputs[0].get();
28902908
Register TokenReg = getOrCreateVReg(*Token);
28912909
MIB.addUse(TokenReg, RegState::Implicit);

llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp

Lines changed: 95 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,85 @@ 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 (MaybeAlign Alignment = I.getRetAlign(); InsertAssertAlign && Alignment) {
5427+
// Insert `assertalign` node if there's an alignment.
5428+
Result = DAG.getAssertAlign(getCurSDLoc(), Result, Alignment.valueOrOne());
5429+
} else if (!isa<VectorType>(I.getType())) {
5430+
Result = lowerRangeToAssertZExt(DAG, I, Result);
5431+
}
5432+
5433+
return Result;
5434+
}
5435+
5436+
/// visitTargetIntrinsic - Lower a call of a target intrinsic to an INTRINSIC
5437+
/// node.
5438+
void SelectionDAGBuilder::visitTargetIntrinsic(const CallInst &I,
5439+
unsigned Intrinsic) {
5440+
auto [HasChain, OnlyLoad] = getTargetIntrinsicCallProperties(I);
5441+
5442+
// Info is set by getTgtMemIntrinsic
5443+
TargetLowering::IntrinsicInfo Info;
5444+
const TargetLowering &TLI = DAG.getTargetLoweringInfo();
5445+
bool IsTgtMemIntrinsic =
5446+
TLI.getTgtMemIntrinsic(Info, I, DAG.getMachineFunction(), Intrinsic);
5447+
5448+
SmallVector<SDValue, 8> Ops = getTargetIntrinsicOperands(
5449+
I, HasChain, OnlyLoad, IsTgtMemIntrinsic ? &Info : nullptr);
5450+
SDVTList VTs = getTargetIntrinsicVTList(I, HasChain);
53795451

53805452
// Propagate fast-math-flags from IR to node(s).
53815453
SDNodeFlags Flags;
@@ -5386,19 +5458,9 @@ void SelectionDAGBuilder::visitTargetIntrinsic(const CallInst &I,
53865458
// Create the node.
53875459
SDValue Result;
53885460

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-
53995461
// In some cases, custom collection of operands from CallInst I may be needed.
54005462
TLI.CollectTargetIntrinsicOperands(I, Ops, DAG);
5401-
if (IsTgtIntrinsic) {
5463+
if (IsTgtMemIntrinsic) {
54025464
// This is target intrinsic that touches memory
54035465
//
54045466
// TODO: We currently just fallback to address space 0 if getTgtMemIntrinsic
@@ -5418,34 +5480,11 @@ void SelectionDAGBuilder::visitTargetIntrinsic(const CallInst &I,
54185480
Info.ssid, Info.order, Info.failureOrder);
54195481
Result =
54205482
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);
54255483
} else {
5426-
Result = DAG.getNode(ISD::INTRINSIC_VOID, getCurSDLoc(), VTs, Ops);
5484+
Result = getTargetNonMemIntrinsicNode(*I.getType(), HasChain, Ops, VTs);
54275485
}
54285486

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-
}
5487+
Result = handleTargetIntrinsicRet(I, HasChain, OnlyLoad, Result);
54495488

54505489
setValue(&I, Result);
54515490
}

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)