diff options
Diffstat (limited to 'llvm/lib')
-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 | ||||
-rw-r--r-- | llvm/lib/Target/X86/X86ISelLowering.cpp | 17 | ||||
-rw-r--r-- | llvm/lib/Target/X86/X86WinEHState.cpp | 79 |
7 files changed, 219 insertions, 13 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; diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp index 88598a1ddd0..72f18cc1143 100644 --- a/llvm/lib/Target/X86/X86ISelLowering.cpp +++ b/llvm/lib/Target/X86/X86ISelLowering.cpp @@ -15506,6 +15506,23 @@ static SDValue LowerINTRINSIC_WO_CHAIN(SDValue Op, const X86Subtarget *Subtarget DAG.getTargetExternalSymbol(Name.data(), VT, X86II::MO_NOPREFIX); return DAG.getNode(X86ISD::Wrapper, dl, VT, Result); } + + case Intrinsic::eh_exceptioninfo: { + // Compute the symbol for the LSDA. We know it'll get emitted later. + MachineFunction &MF = DAG.getMachineFunction(); + SDValue Op1 = Op.getOperand(1); + auto *Fn = cast<Function>(cast<GlobalAddressSDNode>(Op1)->getGlobal()); + MCSymbol *LSDASym = MF.getMMI().getContext().getOrCreateLSDASymbol( + GlobalValue::getRealLinkageName(Fn->getName())); + StringRef Name = LSDASym->getName(); + assert(Name.data()[Name.size()] == '\0' && "not null terminated"); + + // Generate a simple absolute symbol reference. This intrinsic is only + // supported on 32-bit Windows, which isn't PIC. + SDValue Result = + DAG.getTargetExternalSymbol(Name.data(), VT, X86II::MO_NOPREFIX); + return DAG.getNode(X86ISD::Wrapper, dl, VT, Result); + } } } diff --git a/llvm/lib/Target/X86/X86WinEHState.cpp b/llvm/lib/Target/X86/X86WinEHState.cpp index ce69ea72199..0c4aabab880 100644 --- a/llvm/lib/Target/X86/X86WinEHState.cpp +++ b/llvm/lib/Target/X86/X86WinEHState.cpp @@ -63,9 +63,12 @@ private: void linkExceptionRegistration(IRBuilder<> &Builder, Value *Handler); void unlinkExceptionRegistration(IRBuilder<> &Builder); void addCXXStateStores(Function &F, MachineModuleInfo &MMI); + void addSEHStateStores(Function &F, MachineModuleInfo &MMI); void addCXXStateStoresToFunclet(Value *ParentRegNode, WinEHFuncInfo &FuncInfo, Function &F, int BaseState); void insertStateNumberStore(Value *ParentRegNode, Instruction *IP, int State); + iplist<Instruction>::iterator + rewriteExceptionInfoIntrinsics(IntrinsicInst *Intrin); Value *emitEHLSDA(IRBuilder<> &Builder, Function *F); @@ -171,8 +174,10 @@ bool WinEHStatePass::runOnFunction(Function &F) { auto *MMIPtr = getAnalysisIfAvailable<MachineModuleInfo>(); assert(MMIPtr && "MachineModuleInfo should always be available"); MachineModuleInfo &MMI = *MMIPtr; - if (Personality == EHPersonality::MSVC_CXX) { - addCXXStateStores(F, MMI); + switch (Personality) { + default: llvm_unreachable("unexpected personality function"); + case EHPersonality::MSVC_CXX: addCXXStateStores(F, MMI); break; + case EHPersonality::MSVC_X86SEH: addSEHStateStores(F, MMI); break; } // Reset per-function state. @@ -472,6 +477,76 @@ void WinEHStatePass::addCXXStateStoresToFunclet(Value *ParentRegNode, } } +/// Assign every distinct landingpad a unique state number for SEH. Unlike C++ +/// EH, we can use this very simple algorithm while C++ EH cannot because catch +/// handlers aren't outlined and the runtime doesn't have to figure out which +/// catch handler frame to unwind to. +/// FIXME: __finally blocks are outlined, so this approach may break down there. +void WinEHStatePass::addSEHStateStores(Function &F, MachineModuleInfo &MMI) { + WinEHFuncInfo &FuncInfo = MMI.getWinEHFuncInfo(&F); + + // Iterate all the instructions and emit state number stores. + int CurState = 0; + for (BasicBlock &BB : F) { + for (auto I = BB.begin(), E = BB.end(); I != E; ++I) { + if (auto *CI = dyn_cast<CallInst>(I)) { + auto *Intrin = dyn_cast<IntrinsicInst>(CI); + if (Intrin) { + I = rewriteExceptionInfoIntrinsics(Intrin); + // Calls that "don't throw" are considered to be able to throw asynch + // exceptions, but intrinsics cannot. + continue; + } + insertStateNumberStore(RegNode, CI, -1); + } else if (auto *II = dyn_cast<InvokeInst>(I)) { + // Look up the state number of the landingpad this unwinds to. + LandingPadInst *LPI = II->getUnwindDest()->getLandingPadInst(); + auto InsertionPair = + FuncInfo.LandingPadStateMap.insert(std::make_pair(LPI, 0)); + auto Iter = InsertionPair.first; + int &State = Iter->second; + bool Inserted = InsertionPair.second; + if (Inserted) { + // Each action consumes a state number. + auto *EHActions = cast<IntrinsicInst>(LPI->getNextNode()); + SmallVector<std::unique_ptr<ActionHandler>, 4> ActionList; + parseEHActions(EHActions, ActionList); + assert(!ActionList.empty()); + CurState += ActionList.size(); + State += ActionList.size() - 1; + } + insertStateNumberStore(RegNode, II, State); + } + } + } +} + +/// Rewrite llvm.eh.exceptioncode and llvm.eh.exceptioninfo to memory loads in +/// IR. +iplist<Instruction>::iterator +WinEHStatePass::rewriteExceptionInfoIntrinsics(IntrinsicInst *Intrin) { + Intrinsic::ID ID = Intrin->getIntrinsicID(); + if (ID != Intrinsic::eh_exceptioncode && ID != Intrinsic::eh_exceptioninfo) + return Intrin; + + // RegNode->ExceptionPointers + IRBuilder<> Builder(Intrin); + Value *Ptrs = + Builder.CreateLoad(Builder.CreateStructGEP(RegNodeTy, RegNode, 1)); + Value *Res; + if (ID == Intrinsic::eh_exceptioncode) { + // Ptrs->ExceptionRecord->Code + Ptrs = Builder.CreateBitCast( + Ptrs, Builder.getInt32Ty()->getPointerTo()->getPointerTo()); + Value *Rec = Builder.CreateLoad(Ptrs); + Res = Builder.CreateLoad(Rec); + } else { + Res = Ptrs; + } + Intrin->replaceAllUsesWith(Res); + return Intrin->eraseFromParent(); +} + void WinEHStatePass::insertStateNumberStore(Value *ParentRegNode, Instruction *IP, int State) { IRBuilder<> Builder(IP); |