Skip to content

Commit 5cc1016

Browse files
[llvm][SelectionDAGBuilder] codegen callbr.landingpad intrinsic
Given a CallBrInst, retain its first virtual register in SelectionDagBuilder's FunctionLoweringInfo if there's corresponding landingpad. Walk the list of COPY MachineInstr to find the original virtual and physical registers defined by the INLINEASM_BR MachineInst. Test cases from https://reviews.llvm.org/D139565. Link: llvm#59538 Part 3 from https://discourse.llvm.org/t/rfc-syncing-asm-goto-with-outputs-with-gcc/65453/8 Follow up patches still need to wire up CallBrPrepare into the pass pipelines. Reviewed By: efriedma, void Differential Revision: https://reviews.llvm.org/D140160
1 parent 28d45c8 commit 5cc1016

File tree

6 files changed

+1203
-1
lines changed

6 files changed

+1203
-1
lines changed

llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp

Lines changed: 115 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2123,7 +2123,8 @@ void SelectionDAGBuilder::CopyToExportRegsIfNeeded(const Value *V) {
21232123

21242124
DenseMap<const Value *, Register>::iterator VMI = FuncInfo.ValueMap.find(V);
21252125
if (VMI != FuncInfo.ValueMap.end()) {
2126-
assert(!V->use_empty() && "Unused value assigned virtual registers!");
2126+
assert((!V->use_empty() || isa<CallBrInst>(V)) &&
2127+
"Unused value assigned virtual registers!");
21272128
CopyValueToVirtualRegister(V, VMI->second);
21282129
}
21292130
}
@@ -7317,6 +7318,9 @@ void SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I,
73177318
case Intrinsic::experimental_vector_splice:
73187319
visitVectorSplice(I);
73197320
return;
7321+
case Intrinsic::callbr_landingpad:
7322+
visitCallBrLandingPad(I);
7323+
return;
73207324
}
73217325
}
73227326

@@ -11592,3 +11596,113 @@ void SelectionDAGBuilder::visitVectorSplice(const CallInst &I) {
1159211596
Mask.push_back(Idx + i);
1159311597
setValue(&I, DAG.getVectorShuffle(VT, DL, V1, V2, Mask));
1159411598
}
11599+
11600+
// Consider the following MIR after SelectionDAG, which produces output in
11601+
// phyregs in the first case or virtregs in the second case.
11602+
//
11603+
// INLINEASM_BR ..., implicit-def $ebx, ..., implicit-def $edx
11604+
// %5:gr32 = COPY $ebx
11605+
// %6:gr32 = COPY $edx
11606+
// %1:gr32 = COPY %6:gr32
11607+
// %0:gr32 = COPY %5:gr32
11608+
//
11609+
// INLINEASM_BR ..., def %5:gr32, ..., def %6:gr32
11610+
// %1:gr32 = COPY %6:gr32
11611+
// %0:gr32 = COPY %5:gr32
11612+
//
11613+
// Given %0, we'd like to return $ebx in the first case and %5 in the second.
11614+
// Given %1, we'd like to return $edx in the first case and %6 in the second.
11615+
//
11616+
// If a callbr has outputs, it will have a single mapping in FuncInfo.ValueMap
11617+
// to a single virtreg (such as %0). The remaining outputs monotonically
11618+
// increase in virtreg number from there. If a callbr has no outputs, then it
11619+
// should not have a corresponding callbr landingpad; in fact, the callbr
11620+
// landingpad would not even be able to refer to such a callbr.
11621+
static Register FollowCopyChain(MachineRegisterInfo &MRI, Register Reg) {
11622+
MachineInstr *MI = MRI.def_begin(Reg)->getParent();
11623+
// There is definitely at least one copy.
11624+
assert(MI->getOpcode() == TargetOpcode::COPY &&
11625+
"start of copy chain MUST be COPY");
11626+
Reg = MI->getOperand(1).getReg();
11627+
MI = MRI.def_begin(Reg)->getParent();
11628+
// There may be an optional second copy.
11629+
if (MI->getOpcode() == TargetOpcode::COPY) {
11630+
assert(Reg.isVirtual() && "expected COPY of virtual register");
11631+
Reg = MI->getOperand(1).getReg();
11632+
assert(Reg.isPhysical() && "expected COPY of physical register");
11633+
MI = MRI.def_begin(Reg)->getParent();
11634+
}
11635+
// The start of the chain must be an INLINEASM_BR.
11636+
assert(MI->getOpcode() == TargetOpcode::INLINEASM_BR &&
11637+
"end of copy chain MUST be INLINEASM_BR");
11638+
return Reg;
11639+
}
11640+
11641+
// We must do this walk rather than the simpler
11642+
// setValue(&I, getCopyFromRegs(CBR, CBR->getType()));
11643+
// otherwise we will end up with copies of virtregs only valid along direct
11644+
// edges.
11645+
void SelectionDAGBuilder::visitCallBrLandingPad(const CallInst &I) {
11646+
SmallVector<EVT, 8> ResultVTs;
11647+
SmallVector<SDValue, 8> ResultValues;
11648+
const auto *CBR =
11649+
cast<CallBrInst>(I.getParent()->getUniquePredecessor()->getTerminator());
11650+
11651+
const TargetLowering &TLI = DAG.getTargetLoweringInfo();
11652+
const TargetRegisterInfo *TRI = DAG.getSubtarget().getRegisterInfo();
11653+
MachineRegisterInfo &MRI = DAG.getMachineFunction().getRegInfo();
11654+
11655+
unsigned InitialDef = FuncInfo.ValueMap[CBR];
11656+
SDValue Chain = DAG.getRoot();
11657+
11658+
// Re-parse the asm constraints string.
11659+
TargetLowering::AsmOperandInfoVector TargetConstraints =
11660+
TLI.ParseConstraints(DAG.getDataLayout(), TRI, *CBR);
11661+
for (auto &T : TargetConstraints) {
11662+
SDISelAsmOperandInfo OpInfo(T);
11663+
if (OpInfo.Type != InlineAsm::isOutput)
11664+
continue;
11665+
11666+
// Pencil in OpInfo.ConstraintType and OpInfo.ConstraintVT based on the
11667+
// individual constraint.
11668+
TLI.ComputeConstraintToUse(OpInfo, OpInfo.CallOperand, &DAG);
11669+
11670+
switch (OpInfo.ConstraintType) {
11671+
case TargetLowering::C_Register:
11672+
case TargetLowering::C_RegisterClass: {
11673+
// Fill in OpInfo.AssignedRegs.Regs.
11674+
getRegistersForValue(DAG, getCurSDLoc(), OpInfo, OpInfo);
11675+
11676+
// getRegistersForValue may produce 1 to many registers based on whether
11677+
// the OpInfo.ConstraintVT is legal on the target or not.
11678+
for (size_t i = 0, e = OpInfo.AssignedRegs.Regs.size(); i != e; ++i) {
11679+
Register OriginalDef = FollowCopyChain(MRI, InitialDef++);
11680+
if (Register::isPhysicalRegister(OriginalDef))
11681+
FuncInfo.MBB->addLiveIn(OriginalDef);
11682+
// Update the assigned registers to use the original defs.
11683+
OpInfo.AssignedRegs.Regs[i] = OriginalDef;
11684+
}
11685+
11686+
SDValue V = OpInfo.AssignedRegs.getCopyFromRegs(
11687+
DAG, FuncInfo, getCurSDLoc(), Chain, nullptr, CBR);
11688+
ResultValues.push_back(V);
11689+
ResultVTs.push_back(OpInfo.ConstraintVT);
11690+
break;
11691+
}
11692+
case TargetLowering::C_Other: {
11693+
SDValue Flag;
11694+
SDValue V = TLI.LowerAsmOutputForConstraint(Chain, Flag, getCurSDLoc(),
11695+
OpInfo, DAG);
11696+
++InitialDef;
11697+
ResultValues.push_back(V);
11698+
ResultVTs.push_back(OpInfo.ConstraintVT);
11699+
break;
11700+
}
11701+
default:
11702+
break;
11703+
}
11704+
}
11705+
SDValue V = DAG.getNode(ISD::MERGE_VALUES, getCurSDLoc(),
11706+
DAG.getVTList(ResultVTs), ResultValues);
11707+
setValue(&I, V);
11708+
}

llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -534,6 +534,7 @@ class SelectionDAGBuilder {
534534
// These all get lowered before this pass.
535535
void visitInvoke(const InvokeInst &I);
536536
void visitCallBr(const CallBrInst &I);
537+
void visitCallBrLandingPad(const CallInst &I);
537538
void visitResume(const ResumeInst &I);
538539

539540
void visitUnary(const User &I, unsigned Opcode);

0 commit comments

Comments
 (0)