diff options
author | Phoebe Wang <phoebe.wang@intel.com> | 2023-03-29 08:20:14 +0800 |
---|---|---|
committer | Phoebe Wang <phoebe.wang@intel.com> | 2023-03-29 08:59:56 +0800 |
commit | 0efe111365ae176671e01252d24028047d807a84 (patch) | |
tree | 488e2952809357cd92bac7ea9f90916165f8f016 /llvm/lib/CodeGen | |
parent | 4c55fd974b9f7e26ead646150eadfe549f27ad6f (diff) | |
download | llvm-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.cpp | 18 | ||||
-rw-r--r-- | llvm/lib/CodeGen/AsmPrinter/WinException.cpp | 6 | ||||
-rw-r--r-- | llvm/lib/CodeGen/BranchFolding.cpp | 2 | ||||
-rw-r--r-- | llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp | 5 | ||||
-rw-r--r-- | llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp | 42 | ||||
-rw-r--r-- | llvm/lib/CodeGen/WinEHPrepare.cpp | 140 |
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; |