diff options
Diffstat (limited to 'llvm/lib/CodeGen')
-rw-r--r-- | llvm/lib/CodeGen/AsmPrinter/WinException.cpp | 89 | ||||
-rw-r--r-- | llvm/lib/CodeGen/AsmPrinter/WinException.h | 7 | ||||
-rw-r--r-- | llvm/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp | 17 | ||||
-rw-r--r-- | llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp | 1 | ||||
-rw-r--r-- | llvm/lib/CodeGen/WinEHPrepare.cpp | 22 |
5 files changed, 125 insertions, 11 deletions
diff --git a/llvm/lib/CodeGen/AsmPrinter/WinException.cpp b/llvm/lib/CodeGen/AsmPrinter/WinException.cpp index f1663503c08..1143b044cad 100644 --- a/llvm/lib/CodeGen/AsmPrinter/WinException.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/WinException.cpp @@ -144,7 +144,7 @@ void WinException::endFunction(const MachineFunction *MF) { if (Per == EHPersonality::MSVC_Win64SEH) emitCSpecificHandlerTable(); else if (Per == EHPersonality::MSVC_X86SEH) - emitCSpecificHandlerTable(); // FIXME + emitExceptHandlerTable(MF); else if (Per == EHPersonality::MSVC_CXX) emitCXXFrameHandler3Table(MF); else @@ -541,3 +541,90 @@ void WinException::extendIP2StateTable(const MachineFunction *MF, } } } + +/// Emit the language-specific data that _except_handler3 and 4 expect. This is +/// functionally equivalent to the __C_specific_handler table, except it is +/// indexed by state number instead of IP. +void WinException::emitExceptHandlerTable(const MachineFunction *MF) { + auto &OS = *Asm->OutStreamer; + + // Emit the __ehtable label that we use for llvm.x86.seh.lsda. + const Function *F = MF->getFunction(); + StringRef FLinkageName = GlobalValue::getRealLinkageName(F->getName()); + MCSymbol *LSDALabel = Asm->OutContext.getOrCreateLSDASymbol(FLinkageName); + OS.EmitLabel(LSDALabel); + + const Function *Per = MMI->getPersonality(); + StringRef PerName = Per->getName(); + int BaseState = -1; + if (PerName == "_except_handler4") { + // The LSDA for _except_handler4 starts with this struct, followed by the + // scope table: + // + // struct EH4ScopeTable { + // int32_t GSCookieOffset; + // int32_t GSCookieXOROffset; + // int32_t EHCookieOffset; + // int32_t EHCookieXOROffset; + // ScopeTableEntry ScopeRecord[]; + // }; + // + // Only the EHCookieOffset field appears to vary, and it appears to be the + // offset from the final saved SP value to the retaddr. + OS.EmitIntValue(-2, 4); + OS.EmitIntValue(0, 4); + // FIXME: Calculate. + OS.EmitIntValue(9999, 4); + OS.EmitIntValue(0, 4); + BaseState = -2; + } + + // Build a list of pointers to LandingPadInfos and then sort by WinEHState. + const std::vector<LandingPadInfo> &PadInfos = MMI->getLandingPads(); + SmallVector<const LandingPadInfo *, 4> LPads; + LPads.reserve((PadInfos.size())); + for (const LandingPadInfo &LPInfo : PadInfos) + LPads.push_back(&LPInfo); + std::sort(LPads.begin(), LPads.end(), + [](const LandingPadInfo *L, const LandingPadInfo *R) { + return L->WinEHState < R->WinEHState; + }); + + // For each action in each lpad, emit one of these: + // struct ScopeTableEntry { + // int32_t EnclosingLevel; + // int32_t (__cdecl *FilterOrFinally)(); + // void *HandlerLabel; + // }; + // + // The "outermost" action will use BaseState as its enclosing level. Each + // other action will refer to the previous state as its enclosing level. + int CurState = 0; + for (const LandingPadInfo *LPInfo : LPads) { + int EnclosingLevel = BaseState; + assert(CurState + LPInfo->SEHHandlers.size() - 1 == LPInfo->WinEHState && + "gaps in the SEH scope table"); + for (const SEHHandler &Handler : LPInfo->SEHHandlers) { + // Emit the filter or finally function pointer, if present. Otherwise, + // emit '1' to indicate a catch-all. + const MCExpr *FilterOrFinally; + if (const Function *F = Handler.FilterOrFinally) + FilterOrFinally = create32bitRef(Asm->getSymbol(F)); + else + FilterOrFinally = MCConstantExpr::create(1, Asm->OutContext); + + // Compute the recovery address, which is a block address or null. + const BlockAddress *BA = Handler.RecoverBA; + const MCExpr *RecoverBBOrNull = + create32bitRef(BA ? Asm->GetBlockAddressSymbol(BA) : nullptr); + + OS.EmitIntValue(EnclosingLevel, 4); + OS.EmitValue(FilterOrFinally, 4); + OS.EmitValue(RecoverBBOrNull, 4); + + // The next state unwinds to this state. + EnclosingLevel = CurState; + CurState++; + } + } +} diff --git a/llvm/lib/CodeGen/AsmPrinter/WinException.h b/llvm/lib/CodeGen/AsmPrinter/WinException.h index 478899b79da..4e276bc95f2 100644 --- a/llvm/lib/CodeGen/AsmPrinter/WinException.h +++ b/llvm/lib/CodeGen/AsmPrinter/WinException.h @@ -38,8 +38,15 @@ class WinException : public EHStreamer { void emitCSpecificHandlerTable(); + /// Emit the EH table data for 32-bit and 64-bit functions using + /// the __CxxFrameHandler3 personality. void emitCXXFrameHandler3Table(const MachineFunction *MF); + /// Emit the EH table data for _except_handler3 and _except_handler4 + /// personality functions. These are only used on 32-bit and do not use CFI + /// tables. + void emitExceptHandlerTable(const MachineFunction *MF); + void extendIP2StateTable(const MachineFunction *MF, const Function *ParentF, WinEHFuncInfo &FuncInfo); diff --git a/llvm/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp b/llvm/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp index f3d75cb32a7..e6116245bb4 100644 --- a/llvm/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp @@ -264,15 +264,22 @@ void FunctionLoweringInfo::set(const Function &fn, MachineFunction &mf, if (!isMSVCEHPersonality(Personality)) return; - if (Personality == EHPersonality::MSVC_Win64SEH) { + if (Personality == EHPersonality::MSVC_Win64SEH || + Personality == EHPersonality::MSVC_X86SEH) { addSEHHandlersForLPads(LPads); - } else if (Personality == EHPersonality::MSVC_CXX) { + } + + WinEHFuncInfo &EHInfo = MMI.getWinEHFuncInfo(&fn); + if (Personality == EHPersonality::MSVC_CXX) { const Function *WinEHParentFn = MMI.getWinEHParent(&fn); - WinEHFuncInfo &EHInfo = MMI.getWinEHFuncInfo(WinEHParentFn); calculateWinCXXEHStateNumbers(WinEHParentFn, EHInfo); + } - // Copy the state numbers to LandingPadInfo for the current function, which - // could be a handler or the parent. + // Copy the state numbers to LandingPadInfo for the current function, which + // could be a handler or the parent. This should happen for 32-bit SEH and + // C++ EH. + if (Personality == EHPersonality::MSVC_CXX || + Personality == EHPersonality::MSVC_X86SEH) { for (const LandingPadInst *LP : LPads) { MachineBasicBlock *LPadMBB = MBBMap[LP->getParent()]; MMI.addWinEHState(LPadMBB, EHInfo.LandingPadStateMap[LP]); diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp index 8ba957d6287..4035820244a 100644 --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -4983,6 +4983,7 @@ SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) { assert(Reg && "cannot get exception code on this platform"); MVT PtrVT = TLI.getPointerTy(); const TargetRegisterClass *PtrRC = TLI.getRegClassFor(PtrVT); + assert(FuncInfo.MBB->isLandingPad() && "eh.exceptioncode in non-lpad"); unsigned VReg = FuncInfo.MBB->addLiveIn(Reg, PtrRC); SDValue N = DAG.getCopyFromReg(DAG.getEntryNode(), getCurSDLoc(), VReg, PtrVT); diff --git a/llvm/lib/CodeGen/WinEHPrepare.cpp b/llvm/lib/CodeGen/WinEHPrepare.cpp index c2b3d84ca36..6bdc9c95d61 100644 --- a/llvm/lib/CodeGen/WinEHPrepare.cpp +++ b/llvm/lib/CodeGen/WinEHPrepare.cpp @@ -24,6 +24,7 @@ #include "llvm/ADT/Triple.h" #include "llvm/ADT/TinyPtrVector.h" #include "llvm/Analysis/LibCallSemantics.h" +#include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/CodeGen/WinEHFuncInfo.h" #include "llvm/IR/Dominators.h" #include "llvm/IR/Function.h" @@ -124,6 +125,7 @@ private: // All fields are reset by runOnFunction. DominatorTree *DT = nullptr; + const TargetLibraryInfo *LibInfo = nullptr; EHPersonality Personality = EHPersonality::Unknown; CatchHandlerMapTy CatchHandlerMap; CleanupHandlerMapTy CleanupHandlerMap; @@ -384,6 +386,7 @@ bool WinEHPrepare::runOnFunction(Function &Fn) { return false; DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree(); + LibInfo = &getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(); // If there were any landing pads, prepareExceptionHandlers will make changes. prepareExceptionHandlers(Fn, LPads); @@ -394,6 +397,7 @@ bool WinEHPrepare::doFinalization(Module &M) { return false; } void WinEHPrepare::getAnalysisUsage(AnalysisUsage &AU) const { AU.addRequired<DominatorTreeWrapperPass>(); + AU.addRequired<TargetLibraryInfoWrapperPass>(); } static bool isSelectorDispatch(BasicBlock *BB, BasicBlock *&CatchHandler, @@ -1016,10 +1020,17 @@ bool WinEHPrepare::prepareExceptionHandlers( Builder.CreateCall(FrameEscapeFn, AllocasToEscape); if (SEHExceptionCodeSlot) { - if (SEHExceptionCodeSlot->hasNUses(0)) - SEHExceptionCodeSlot->eraseFromParent(); - else if (isAllocaPromotable(SEHExceptionCodeSlot)) + if (isAllocaPromotable(SEHExceptionCodeSlot)) { + SmallPtrSet<BasicBlock *, 4> UserBlocks; + for (User *U : SEHExceptionCodeSlot->users()) { + if (auto *Inst = dyn_cast<Instruction>(U)) + UserBlocks.insert(Inst->getParent()); + } PromoteMemToReg(SEHExceptionCodeSlot, *DT); + // After the promotion, kill off dead instructions. + for (BasicBlock *BB : UserBlocks) + SimplifyInstructionsInBlock(BB, LibInfo); + } } // Clean up the handler action maps we created for this function @@ -1029,6 +1040,7 @@ bool WinEHPrepare::prepareExceptionHandlers( CleanupHandlerMap.clear(); HandlerToParentFP.clear(); DT = nullptr; + LibInfo = nullptr; SEHExceptionCodeSlot = nullptr; EHBlocks.clear(); NormalBlocks.clear(); @@ -1143,7 +1155,6 @@ void WinEHPrepare::completeNestedLandingPad(Function *ParentFn, ++II; // The instruction after the landing pad should now be a call to eh.actions. const Instruction *Recover = II; - assert(match(Recover, m_Intrinsic<Intrinsic::eh_actions>())); const IntrinsicInst *EHActions = cast<IntrinsicInst>(Recover); // Remap the return target in the nested handler. @@ -2454,6 +2465,8 @@ void WinEHPrepare::findCleanupHandlers(LandingPadActions &Actions, void llvm::parseEHActions( const IntrinsicInst *II, SmallVectorImpl<std::unique_ptr<ActionHandler>> &Actions) { + assert(II->getIntrinsicID() == Intrinsic::eh_actions && + "attempted to parse non eh.actions intrinsic"); for (unsigned I = 0, E = II->getNumArgOperands(); I != E;) { uint64_t ActionKind = cast<ConstantInt>(II->getArgOperand(I))->getZExtValue(); @@ -2766,7 +2779,6 @@ void WinEHNumbering::calculateStateNumbers(const Function &F) { auto *ActionsCall = dyn_cast<IntrinsicInst>(LPI->getNextNode()); if (!ActionsCall) continue; - assert(ActionsCall->getIntrinsicID() == Intrinsic::eh_actions); parseEHActions(ActionsCall, ActionList); if (ActionList.empty()) continue; |