aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/CodeGen
diff options
context:
space:
mode:
authorPhoebe Wang <phoebe.wang@intel.com>2023-03-29 08:20:14 +0800
committerPhoebe Wang <phoebe.wang@intel.com>2023-03-29 08:59:56 +0800
commit0efe111365ae176671e01252d24028047d807a84 (patch)
tree488e2952809357cd92bac7ea9f90916165f8f016 /llvm/lib/CodeGen
parent4c55fd974b9f7e26ead646150eadfe549f27ad6f (diff)
downloadllvm-0efe111365ae176671e01252d24028047d807a84.zip
llvm-0efe111365ae176671e01252d24028047d807a84.tar.gz
llvm-0efe111365ae176671e01252d24028047d807a84.tar.bz2
Reland "[Windows SEH]: HARDWARE EXCEPTION HANDLING (MSVC -EHa) - Part 2"
This reverts commit db6a979ae82410e42430e47afa488936ba8e3025. Reland D102817 without any change. The previous revert was a mistake. Differential Revision: https://reviews.llvm.org/D102817
Diffstat (limited to 'llvm/lib/CodeGen')
-rw-r--r--llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp18
-rw-r--r--llvm/lib/CodeGen/AsmPrinter/WinException.cpp6
-rw-r--r--llvm/lib/CodeGen/BranchFolding.cpp2
-rw-r--r--llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp5
-rw-r--r--llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp42
-rw-r--r--llvm/lib/CodeGen/WinEHPrepare.cpp140
6 files changed, 210 insertions, 3 deletions
diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
index c8a88a1..47623e6 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -1627,6 +1627,7 @@ void AsmPrinter::emitFunctionBody() {
// Print out code for the function.
bool HasAnyRealCode = false;
int NumInstsInFunction = 0;
+ bool IsEHa = MMI->getModule()->getModuleFlag("eh-asynch");
bool CanDoExtraAnalysis = ORE->allowExtraAnalysis(DEBUG_TYPE);
for (auto &MBB : *MF) {
@@ -1665,10 +1666,25 @@ void AsmPrinter::emitFunctionBody() {
emitFrameAlloc(MI);
break;
case TargetOpcode::ANNOTATION_LABEL:
- case TargetOpcode::EH_LABEL:
case TargetOpcode::GC_LABEL:
OutStreamer->emitLabel(MI.getOperand(0).getMCSymbol());
break;
+ case TargetOpcode::EH_LABEL:
+ OutStreamer->emitLabel(MI.getOperand(0).getMCSymbol());
+ // For AsynchEH, insert a Nop if followed by a trap inst
+ // Or the exception won't be caught.
+ // (see MCConstantExpr::create(1,..) in WinException.cpp)
+ // Ignore SDiv/UDiv because a DIV with Const-0 divisor
+ // must have being turned into an UndefValue.
+ // Div with variable opnds won't be the first instruction in
+ // an EH region as it must be led by at least a Load
+ {
+ auto MI2 = std::next(MI.getIterator());
+ if (IsEHa && MI2 != MBB.end() &&
+ (MI2->mayLoadOrStore() || MI2->mayRaiseFPException()))
+ emitNops(1);
+ }
+ break;
case TargetOpcode::INLINEASM:
case TargetOpcode::INLINEASM_BR:
emitInlineAsm(&MI);
diff --git a/llvm/lib/CodeGen/AsmPrinter/WinException.cpp b/llvm/lib/CodeGen/AsmPrinter/WinException.cpp
index 7a80043..6bfb5a6 100644
--- a/llvm/lib/CodeGen/AsmPrinter/WinException.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/WinException.cpp
@@ -762,7 +762,11 @@ void WinException::emitCXXFrameHandler3Table(const MachineFunction *MF) {
OS.emitInt32(0);
AddComment("EHFlags");
- OS.emitInt32(1);
+ if (MMI->getModule()->getModuleFlag("eh-asynch")) {
+ OS.emitInt32(0);
+ } else {
+ OS.emitInt32(1);
+ }
// UnwindMapEntry {
// int32_t ToState;
diff --git a/llvm/lib/CodeGen/BranchFolding.cpp b/llvm/lib/CodeGen/BranchFolding.cpp
index d5bf62c..b5ac90c 100644
--- a/llvm/lib/CodeGen/BranchFolding.cpp
+++ b/llvm/lib/CodeGen/BranchFolding.cpp
@@ -1207,7 +1207,7 @@ bool BranchFolder::OptimizeBranches(MachineFunction &MF) {
MadeChange |= OptimizeBlock(&MBB);
// If it is dead, remove it.
- if (MBB.pred_empty()) {
+ if (MBB.pred_empty() && !MBB.isMachineBlockAddressTaken()) {
RemoveDeadBlock(&MBB);
MadeChange = true;
++NumDeadBlocks;
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index 1abbe9b..1107da1 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -2971,6 +2971,7 @@ void SelectionDAGBuilder::visitInvoke(const InvokeInst &I) {
// catchswitch for successors.
MachineBasicBlock *Return = FuncInfo.MBBMap[I.getSuccessor(0)];
const BasicBlock *EHPadBB = I.getSuccessor(1);
+ MachineBasicBlock *EHPadMBB = FuncInfo.MBBMap[EHPadBB];
// Deopt bundles are lowered in LowerCallSiteWithDeoptBundle, and we don't
// have to do anything here to lower funclet bundles.
@@ -2995,6 +2996,10 @@ void SelectionDAGBuilder::visitInvoke(const InvokeInst &I) {
case Intrinsic::seh_scope_begin:
case Intrinsic::seh_try_end:
case Intrinsic::seh_scope_end:
+ if (EHPadMBB)
+ // a block referenced by EH table
+ // so dtor-funclet not removed by opts
+ EHPadMBB->setMachineBlockAddressTaken();
break;
case Intrinsic::experimental_patchpoint_void:
case Intrinsic::experimental_patchpoint_i64:
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
index 8d1cc04..bdbf32a 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
@@ -59,6 +59,7 @@
#include "llvm/CodeGen/TargetRegisterInfo.h"
#include "llvm/CodeGen/TargetSubtargetInfo.h"
#include "llvm/CodeGen/ValueTypes.h"
+#include "llvm/CodeGen/WinEHFuncInfo.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
@@ -1292,6 +1293,43 @@ bool SelectionDAGISel::PrepareEHLandingPad() {
return true;
}
+// Mark and Report IPToState for each Block under IsEHa
+void SelectionDAGISel::reportIPToStateForBlocks(MachineFunction *MF) {
+ MachineModuleInfo &MMI = MF->getMMI();
+ llvm::WinEHFuncInfo *EHInfo = MF->getWinEHFuncInfo();
+ if (!EHInfo)
+ return;
+ for (auto MBBI = MF->begin(), E = MF->end(); MBBI != E; ++MBBI) {
+ MachineBasicBlock *MBB = &*MBBI;
+ const BasicBlock *BB = MBB->getBasicBlock();
+ int State = EHInfo->BlockToStateMap[BB];
+ if (BB->getFirstMayFaultInst()) {
+ // Report IP range only for blocks with Faulty inst
+ auto MBBb = MBB->getFirstNonPHI();
+ MachineInstr *MIb = &*MBBb;
+ if (MIb->isTerminator())
+ continue;
+
+ // Insert EH Labels
+ MCSymbol *BeginLabel = MMI.getContext().createTempSymbol();
+ MCSymbol *EndLabel = MMI.getContext().createTempSymbol();
+ EHInfo->addIPToStateRange(State, BeginLabel, EndLabel);
+ BuildMI(*MBB, MBBb, SDB->getCurDebugLoc(),
+ TII->get(TargetOpcode::EH_LABEL))
+ .addSym(BeginLabel);
+ auto MBBe = MBB->instr_end();
+ MachineInstr *MIe = &*(--MBBe);
+ // insert before (possible multiple) terminators
+ while (MIe->isTerminator())
+ MIe = &*(--MBBe);
+ ++MBBe;
+ BuildMI(*MBB, MBBe, SDB->getCurDebugLoc(),
+ TII->get(TargetOpcode::EH_LABEL))
+ .addSym(EndLabel);
+ }
+ }
+}
+
/// isFoldedOrDeadInstruction - Return true if the specified instruction is
/// side-effect free and is either dead or folded into a generated instruction.
/// Return false if it needs to be emitted.
@@ -1649,6 +1687,10 @@ void SelectionDAGISel::SelectAllBasicBlocks(const Function &Fn) {
ElidedArgCopyInstrs.clear();
}
+ // AsynchEH: Report Block State under -AsynchEH
+ if (Fn.getParent()->getModuleFlag("eh-asynch"))
+ reportIPToStateForBlocks(MF);
+
SP.copyToMachineFrameInfo(MF->getFrameInfo());
SwiftError->propagateVRegs();
diff --git a/llvm/lib/CodeGen/WinEHPrepare.cpp b/llvm/lib/CodeGen/WinEHPrepare.cpp
index e97f640..d6d4af0 100644
--- a/llvm/lib/CodeGen/WinEHPrepare.cpp
+++ b/llvm/lib/CodeGen/WinEHPrepare.cpp
@@ -216,6 +216,127 @@ static void calculateStateNumbersForInvokes(const Function *Fn,
}
}
+// See comments below for calculateSEHStateForAsynchEH().
+// State - incoming State of normal paths
+struct WorkItem {
+ const BasicBlock *Block;
+ int State;
+ WorkItem(const BasicBlock *BB, int St) {
+ Block = BB;
+ State = St;
+ }
+};
+void llvm::calculateCXXStateForAsynchEH(const BasicBlock *BB, int State,
+ WinEHFuncInfo &EHInfo) {
+ SmallVector<struct WorkItem *, 8> WorkList;
+ struct WorkItem *WI = new WorkItem(BB, State);
+ WorkList.push_back(WI);
+
+ while (!WorkList.empty()) {
+ WI = WorkList.pop_back_val();
+ const BasicBlock *BB = WI->Block;
+ int State = WI->State;
+ delete WI;
+ if (EHInfo.BlockToStateMap.count(BB) && EHInfo.BlockToStateMap[BB] <= State)
+ continue; // skip blocks already visited by lower State
+
+ const llvm::Instruction *I = BB->getFirstNonPHI();
+ const llvm::Instruction *TI = BB->getTerminator();
+ if (I->isEHPad())
+ State = EHInfo.EHPadStateMap[I];
+ EHInfo.BlockToStateMap[BB] = State; // Record state, also flag visiting
+
+ if ((isa<CleanupReturnInst>(TI) || isa<CatchReturnInst>(TI)) && State > 0) {
+ // Retrive the new State
+ State = EHInfo.CxxUnwindMap[State].ToState; // Retrive next State
+ } else if (isa<InvokeInst>(TI)) {
+ auto *Call = dyn_cast<CallBase>(TI);
+ const Function *Fn = Call->getCalledFunction();
+ if (Fn && Fn->isIntrinsic() &&
+ (Fn->getIntrinsicID() == Intrinsic::seh_scope_begin ||
+ Fn->getIntrinsicID() == Intrinsic::seh_try_begin))
+ // Retrive the new State from seh_scope_begin
+ State = EHInfo.InvokeStateMap[cast<InvokeInst>(TI)];
+ else if (Fn && Fn->isIntrinsic() &&
+ (Fn->getIntrinsicID() == Intrinsic::seh_scope_end ||
+ Fn->getIntrinsicID() == Intrinsic::seh_try_end)) {
+ // In case of conditional ctor, let's retrieve State from Invoke
+ State = EHInfo.InvokeStateMap[cast<InvokeInst>(TI)];
+ // end of current state, retrive new state from UnwindMap
+ State = EHInfo.CxxUnwindMap[State].ToState;
+ }
+ }
+ // Continue push successors into worklist
+ for (auto *SuccBB : successors(BB)) {
+ WI = new WorkItem(SuccBB, State);
+ WorkList.push_back(WI);
+ }
+ }
+}
+
+// The central theory of this routine is based on the following:
+// A _try scope is always a SEME (Single Entry Multiple Exits) region
+// as jumping into a _try is not allowed
+// The single entry must start with a seh_try_begin() invoke with a
+// correct State number that is the initial state of the SEME.
+// Through control-flow, state number is propagated into all blocks.
+// Side exits marked by seh_try_end() will unwind to parent state via
+// existing SEHUnwindMap[].
+// Side exits can ONLY jump into parent scopes (lower state number).
+// Thus, when a block succeeds various states from its predecessors,
+// the lowest State trumphs others.
+// If some exits flow to unreachable, propagation on those paths terminate,
+// not affecting remaining blocks.
+void llvm::calculateSEHStateForAsynchEH(const BasicBlock *BB, int State,
+ WinEHFuncInfo &EHInfo) {
+ SmallVector<struct WorkItem *, 8> WorkList;
+ struct WorkItem *WI = new WorkItem(BB, State);
+ WorkList.push_back(WI);
+
+ while (!WorkList.empty()) {
+ WI = WorkList.pop_back_val();
+ const BasicBlock *BB = WI->Block;
+ int State = WI->State;
+ delete WI;
+ if (EHInfo.BlockToStateMap.count(BB) && EHInfo.BlockToStateMap[BB] <= State)
+ continue; // skip blocks already visited by lower State
+
+ const llvm::Instruction *I = BB->getFirstNonPHI();
+ const llvm::Instruction *TI = BB->getTerminator();
+ if (I->isEHPad())
+ State = EHInfo.EHPadStateMap[I];
+ EHInfo.BlockToStateMap[BB] = State; // Record state
+
+ if (isa<CatchPadInst>(I) && isa<CatchReturnInst>(TI)) {
+ const Constant *FilterOrNull = cast<Constant>(
+ cast<CatchPadInst>(I)->getArgOperand(0)->stripPointerCasts());
+ const Function *Filter = dyn_cast<Function>(FilterOrNull);
+ if (!Filter || !Filter->getName().startswith("__IsLocalUnwind"))
+ State = EHInfo.SEHUnwindMap[State].ToState; // Retrive next State
+ } else if ((isa<CleanupReturnInst>(TI) || isa<CatchReturnInst>(TI)) &&
+ State > 0) {
+ // Retrive the new State.
+ State = EHInfo.SEHUnwindMap[State].ToState; // Retrive next State
+ } else if (isa<InvokeInst>(TI)) {
+ auto *Call = dyn_cast<CallBase>(TI);
+ const Function *Fn = Call->getCalledFunction();
+ if (Fn && Fn->isIntrinsic() &&
+ Fn->getIntrinsicID() == Intrinsic::seh_try_begin)
+ // Retrive the new State from seh_try_begin
+ State = EHInfo.InvokeStateMap[cast<InvokeInst>(TI)];
+ else if (Fn && Fn->isIntrinsic() &&
+ Fn->getIntrinsicID() == Intrinsic::seh_try_end)
+ // end of current state, retrive new state from UnwindMap
+ State = EHInfo.SEHUnwindMap[State].ToState;
+ }
+ // Continue push successors into worklist
+ for (auto *SuccBB : successors(BB)) {
+ WI = new WorkItem(SuccBB, State);
+ WorkList.push_back(WI);
+ }
+ }
+}
+
// Given BB which ends in an unwind edge, return the EHPad that this BB belongs
// to. If the unwind edge came from an invoke, return null.
static const BasicBlock *getEHPadFromPredecessor(const BasicBlock *BB,
@@ -276,6 +397,7 @@ static void calculateCXXStateNumbers(WinEHFuncInfo &FuncInfo,
for (const auto *CatchPad : Handlers) {
FuncInfo.FuncletBaseStateMap[CatchPad] = CatchLow;
+ FuncInfo.EHPadStateMap[CatchPad] = CatchLow;
for (const User *U : CatchPad->users()) {
const auto *UserI = cast<Instruction>(U);
if (auto *InnerCatchSwitch = dyn_cast<CatchSwitchInst>(UserI)) {
@@ -384,6 +506,7 @@ static void calculateSEHStateNumbers(WinEHFuncInfo &FuncInfo,
// Everything in the __try block uses TryState as its parent state.
FuncInfo.EHPadStateMap[CatchSwitch] = TryState;
+ FuncInfo.EHPadStateMap[CatchPad] = TryState;
LLVM_DEBUG(dbgs() << "Assigning state #" << TryState << " to BB "
<< CatchPadBB->getName() << '\n');
for (const BasicBlock *PredBlock : predecessors(BB))
@@ -464,6 +587,12 @@ void llvm::calculateSEHStateNumbers(const Function *Fn,
}
calculateStateNumbersForInvokes(Fn, FuncInfo);
+
+ bool IsEHa = Fn->getParent()->getModuleFlag("eh-asynch");
+ if (IsEHa) {
+ const BasicBlock *EntryBB = &(Fn->getEntryBlock());
+ calculateSEHStateForAsynchEH(EntryBB, -1, FuncInfo);
+ }
}
void llvm::calculateWinCXXEHStateNumbers(const Function *Fn,
@@ -482,6 +611,12 @@ void llvm::calculateWinCXXEHStateNumbers(const Function *Fn,
}
calculateStateNumbersForInvokes(Fn, FuncInfo);
+
+ bool IsEHa = Fn->getParent()->getModuleFlag("eh-asynch");
+ if (IsEHa) {
+ const BasicBlock *EntryBB = &(Fn->getEntryBlock());
+ calculateCXXStateForAsynchEH(EntryBB, -1, FuncInfo);
+ }
}
static int addClrEHHandler(WinEHFuncInfo &FuncInfo, int HandlerParentState,
@@ -1253,4 +1388,9 @@ void WinEHFuncInfo::addIPToStateRange(const InvokeInst *II,
LabelToStateMap[InvokeBegin] = std::make_pair(InvokeStateMap[II], InvokeEnd);
}
+void WinEHFuncInfo::addIPToStateRange(int State, MCSymbol* InvokeBegin,
+ MCSymbol* InvokeEnd) {
+ LabelToStateMap[InvokeBegin] = std::make_pair(State, InvokeEnd);
+}
+
WinEHFuncInfo::WinEHFuncInfo() = default;