aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
diff options
context:
space:
mode:
authorcynecx <me@cynecx.net>2021-05-13 19:05:11 +0100
committerAmanieu d'Antras <amanieu@gmail.com>2021-05-13 19:13:03 +0100
commit8ec9fd483949ca3b23053effcac226dcc56e7a95 (patch)
treec85cb91a5668b9af25f8e87a1679cf9bb451bef4 /llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
parent9d3eb7885d916b22bc673334f71a10e3b2835174 (diff)
downloadllvm-8ec9fd483949ca3b23053effcac226dcc56e7a95.zip
llvm-8ec9fd483949ca3b23053effcac226dcc56e7a95.tar.gz
llvm-8ec9fd483949ca3b23053effcac226dcc56e7a95.tar.bz2
Support unwinding from inline assembly
I've taken the following steps to add unwinding support from inline assembly: 1) Add a new `unwind` "attribute" (like `sideeffect`) to the asm syntax: ``` invoke void asm sideeffect unwind "call thrower", "~{dirflag},~{fpsr},~{flags}"() to label %exit unwind label %uexit ``` 2.) Add Bitcode writing/reading support + LLVM-IR parsing. 3.) Emit EHLabels around inline assembly lowering (SelectionDAGBuilder + GlobalISel) when `InlineAsm::canThrow` is enabled. 4.) Tweak InstCombineCalls/InlineFunction pass to not mark inline assembly "calls" as nounwind. 5.) Add clang support by introducing a new clobber: "unwind", which lower to the `canThrow` being enabled. 6.) Don't allow unwinding callbr. Reviewed By: Amanieu Differential Revision: https://reviews.llvm.org/D95745
Diffstat (limited to 'llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp')
-rw-r--r--llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp123
1 files changed, 80 insertions, 43 deletions
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index 4b2d811..e9eea5b 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -2873,7 +2873,7 @@ void SelectionDAGBuilder::visitInvoke(const InvokeInst &I) {
const Value *Callee(I.getCalledOperand());
const Function *Fn = dyn_cast<Function>(Callee);
if (isa<InlineAsm>(Callee))
- visitInlineAsm(I);
+ visitInlineAsm(I, EHPadBB);
else if (Fn && Fn->isIntrinsic()) {
switch (Fn->getIntrinsicID()) {
default:
@@ -7281,36 +7281,72 @@ void SelectionDAGBuilder::visitVectorPredicationIntrinsic(
setValue(&VPIntrin, Result);
}
-std::pair<SDValue, SDValue>
-SelectionDAGBuilder::lowerInvokable(TargetLowering::CallLoweringInfo &CLI,
- const BasicBlock *EHPadBB) {
+SDValue SelectionDAGBuilder::lowerStartEH(SDValue Chain,
+ const BasicBlock *EHPadBB,
+ MCSymbol *&BeginLabel) {
MachineFunction &MF = DAG.getMachineFunction();
MachineModuleInfo &MMI = MF.getMMI();
- MCSymbol *BeginLabel = nullptr;
- if (EHPadBB) {
- // Insert a label before the invoke call to mark the try range. This can be
- // used to detect deletion of the invoke via the MachineModuleInfo.
- BeginLabel = MMI.getContext().createTempSymbol();
+ // Insert a label before the invoke call to mark the try range. This can be
+ // used to detect deletion of the invoke via the MachineModuleInfo.
+ BeginLabel = MMI.getContext().createTempSymbol();
- // For SjLj, keep track of which landing pads go with which invokes
- // so as to maintain the ordering of pads in the LSDA.
- unsigned CallSiteIndex = MMI.getCurrentCallSite();
- if (CallSiteIndex) {
- MF.setCallSiteBeginLabel(BeginLabel, CallSiteIndex);
- LPadToCallSiteMap[FuncInfo.MBBMap[EHPadBB]].push_back(CallSiteIndex);
+ // For SjLj, keep track of which landing pads go with which invokes
+ // so as to maintain the ordering of pads in the LSDA.
+ unsigned CallSiteIndex = MMI.getCurrentCallSite();
+ if (CallSiteIndex) {
+ MF.setCallSiteBeginLabel(BeginLabel, CallSiteIndex);
+ LPadToCallSiteMap[FuncInfo.MBBMap[EHPadBB]].push_back(CallSiteIndex);
- // Now that the call site is handled, stop tracking it.
- MMI.setCurrentCallSite(0);
- }
+ // Now that the call site is handled, stop tracking it.
+ MMI.setCurrentCallSite(0);
+ }
+
+ return DAG.getEHLabel(getCurSDLoc(), Chain, BeginLabel);
+}
+SDValue SelectionDAGBuilder::lowerEndEH(SDValue Chain, const InvokeInst *II,
+ const BasicBlock *EHPadBB,
+ MCSymbol *BeginLabel) {
+ assert(BeginLabel && "BeginLabel should've been set");
+
+ MachineFunction &MF = DAG.getMachineFunction();
+ MachineModuleInfo &MMI = MF.getMMI();
+
+ // Insert a label at the end of the invoke call to mark the try range. This
+ // can be used to detect deletion of the invoke via the MachineModuleInfo.
+ MCSymbol *EndLabel = MMI.getContext().createTempSymbol();
+ Chain = DAG.getEHLabel(getCurSDLoc(), Chain, EndLabel);
+
+ // Inform MachineModuleInfo of range.
+ auto Pers = classifyEHPersonality(FuncInfo.Fn->getPersonalityFn());
+ // There is a platform (e.g. wasm) that uses funclet style IR but does not
+ // actually use outlined funclets and their LSDA info style.
+ if (MF.hasEHFunclets() && isFuncletEHPersonality(Pers)) {
+ assert(II && "II should've been set");
+ WinEHFuncInfo *EHInfo = MF.getWinEHFuncInfo();
+ EHInfo->addIPToStateRange(II, BeginLabel, EndLabel);
+ } else if (!isScopedEHPersonality(Pers)) {
+ assert(EHPadBB);
+ MF.addInvoke(FuncInfo.MBBMap[EHPadBB], BeginLabel, EndLabel);
+ }
+
+ return Chain;
+}
+
+std::pair<SDValue, SDValue>
+SelectionDAGBuilder::lowerInvokable(TargetLowering::CallLoweringInfo &CLI,
+ const BasicBlock *EHPadBB) {
+ MCSymbol *BeginLabel = nullptr;
+
+ if (EHPadBB) {
// Both PendingLoads and PendingExports must be flushed here;
// this call might not return.
(void)getRoot();
- DAG.setRoot(DAG.getEHLabel(getCurSDLoc(), getControlRoot(), BeginLabel));
-
+ DAG.setRoot(lowerStartEH(getControlRoot(), EHPadBB, BeginLabel));
CLI.setChain(getRoot());
}
+
const TargetLowering &TLI = DAG.getTargetLoweringInfo();
std::pair<SDValue, SDValue> Result = TLI.LowerCallTo(CLI);
@@ -7332,22 +7368,8 @@ SelectionDAGBuilder::lowerInvokable(TargetLowering::CallLoweringInfo &CLI,
}
if (EHPadBB) {
- // Insert a label at the end of the invoke call to mark the try range. This
- // can be used to detect deletion of the invoke via the MachineModuleInfo.
- MCSymbol *EndLabel = MMI.getContext().createTempSymbol();
- DAG.setRoot(DAG.getEHLabel(getCurSDLoc(), getRoot(), EndLabel));
-
- // Inform MachineModuleInfo of range.
- auto Pers = classifyEHPersonality(FuncInfo.Fn->getPersonalityFn());
- // There is a platform (e.g. wasm) that uses funclet style IR but does not
- // actually use outlined funclets and their LSDA info style.
- if (MF.hasEHFunclets() && isFuncletEHPersonality(Pers)) {
- assert(CLI.CB);
- WinEHFuncInfo *EHInfo = DAG.getMachineFunction().getWinEHFuncInfo();
- EHInfo->addIPToStateRange(cast<InvokeInst>(CLI.CB), BeginLabel, EndLabel);
- } else if (!isScopedEHPersonality(Pers)) {
- MF.addInvoke(FuncInfo.MBBMap[EHPadBB], BeginLabel, EndLabel);
- }
+ DAG.setRoot(lowerEndEH(getRoot(), cast_or_null<InvokeInst>(CLI.CB), EHPadBB,
+ BeginLabel));
}
return Result;
@@ -8317,7 +8339,8 @@ public:
} // end anonymous namespace
/// visitInlineAsm - Handle a call to an InlineAsm object.
-void SelectionDAGBuilder::visitInlineAsm(const CallBase &Call) {
+void SelectionDAGBuilder::visitInlineAsm(const CallBase &Call,
+ const BasicBlock *EHPadBB) {
const InlineAsm *IA = cast<InlineAsm>(Call.getCalledOperand());
/// ConstraintOperands - Information about all of the constraints.
@@ -8405,19 +8428,28 @@ void SelectionDAGBuilder::visitInlineAsm(const CallBase &Call) {
ExtraInfo.update(T);
}
-
// We won't need to flush pending loads if this asm doesn't touch
// memory and is nonvolatile.
SDValue Flag, Chain = (HasSideEffect) ? getRoot() : DAG.getRoot();
+ bool EmitEHLabels = isa<InvokeInst>(Call) && IA->canThrow();
+ if (EmitEHLabels) {
+ assert(EHPadBB && "InvokeInst must have an EHPadBB");
+ }
bool IsCallBr = isa<CallBrInst>(Call);
- if (IsCallBr) {
- // If this is a callbr we need to flush pending exports since inlineasm_br
- // is a terminator. We need to do this before nodes are glued to
- // the inlineasm_br node.
+
+ if (IsCallBr || EmitEHLabels) {
+ // If this is a callbr or invoke we need to flush pending exports since
+ // inlineasm_br and invoke are terminators.
+ // We need to do this before nodes are glued to the inlineasm_br node.
Chain = getControlRoot();
}
+ MCSymbol *BeginLabel = nullptr;
+ if (EmitEHLabels) {
+ Chain = lowerStartEH(Chain, EHPadBB, BeginLabel);
+ }
+
// Second pass over the constraints: compute which constraint option to use.
for (SDISelAsmOperandInfo &OpInfo : ConstraintOperands) {
// If this is an output operand with a matching input operand, look up the
@@ -8808,8 +8840,13 @@ void SelectionDAGBuilder::visitInlineAsm(const CallBase &Call) {
if (!OutChains.empty())
Chain = DAG.getNode(ISD::TokenFactor, getCurSDLoc(), MVT::Other, OutChains);
+ if (EmitEHLabels) {
+ Chain = lowerEndEH(Chain, cast<InvokeInst>(&Call), EHPadBB, BeginLabel);
+ }
+
// Only Update Root if inline assembly has a memory effect.
- if (ResultValues.empty() || HasSideEffect || !OutChains.empty() || IsCallBr)
+ if (ResultValues.empty() || HasSideEffect || !OutChains.empty() || IsCallBr ||
+ EmitEHLabels)
DAG.setRoot(Chain);
}