From: Reid Kleckner Date: Fri, 9 Oct 2015 23:34:53 +0000 (+0000) Subject: [WinEH] Delete the old landingpad implementation of Windows EH X-Git-Url: http://plrg.eecs.uci.edu/git/?p=oota-llvm.git;a=commitdiff_plain;h=c839e943d0bd5ad7cba913bb5892341cb149eb95 [WinEH] Delete the old landingpad implementation of Windows EH The new implementation works at least as well as the old implementation did. Also delete the associated preparation tests. They don't exercise interesting corner cases of the new implementation. All the codegen tests of the EH tables have already been ported. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@249918 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/llvm/CodeGen/WinEHFuncInfo.h b/include/llvm/CodeGen/WinEHFuncInfo.h index 773931ff7cd..89a75058247 100644 --- a/include/llvm/CodeGen/WinEHFuncInfo.h +++ b/include/llvm/CodeGen/WinEHFuncInfo.h @@ -33,99 +33,18 @@ class MCSymbol; class MachineBasicBlock; class Value; -enum ActionType { Catch, Cleanup }; - -class ActionHandler { -public: - ActionHandler(BasicBlock *BB, ActionType Type) - : StartBB(BB), Type(Type), EHState(-1), HandlerBlockOrFunc(nullptr) {} - - ActionType getType() const { return Type; } - BasicBlock *getStartBlock() const { return StartBB; } - - bool hasBeenProcessed() { return HandlerBlockOrFunc != nullptr; } - - void setHandlerBlockOrFunc(Constant *F) { HandlerBlockOrFunc = F; } - Constant *getHandlerBlockOrFunc() { return HandlerBlockOrFunc; } - - void setEHState(int State) { EHState = State; } - int getEHState() const { return EHState; } - -private: - BasicBlock *StartBB; - ActionType Type; - int EHState; - - // Can be either a BlockAddress or a Function depending on the EH personality. - Constant *HandlerBlockOrFunc; -}; - -class CatchHandler : public ActionHandler { -public: - CatchHandler(BasicBlock *BB, Constant *Selector, BasicBlock *NextBB) - : ActionHandler(BB, ActionType::Catch), Selector(Selector), - NextBB(NextBB), ExceptionObjectVar(nullptr), - ExceptionObjectIndex(-1) {} - - // Method for support type inquiry through isa, cast, and dyn_cast: - static inline bool classof(const ActionHandler *H) { - return H->getType() == ActionType::Catch; - } - - Constant *getSelector() const { return Selector; } - BasicBlock *getNextBB() const { return NextBB; } - - const Value *getExceptionVar() { return ExceptionObjectVar; } - TinyPtrVector &getReturnTargets() { return ReturnTargets; } - - void setExceptionVar(const Value *Val) { ExceptionObjectVar = Val; } - void setExceptionVarIndex(int Index) { ExceptionObjectIndex = Index; } - int getExceptionVarIndex() const { return ExceptionObjectIndex; } - void setReturnTargets(TinyPtrVector &Targets) { - ReturnTargets = Targets; - } - -private: - Constant *Selector; - BasicBlock *NextBB; - // While catch handlers are being outlined the ExceptionObjectVar field will - // be populated with the instruction in the parent frame that corresponds - // to the exception object (or nullptr if the catch does not use an - // exception object) and the ExceptionObjectIndex field will be -1. - // When the parseEHActions function is called to populate a vector of - // instances of this class, the ExceptionObjectVar field will be nullptr - // and the ExceptionObjectIndex will be the index of the exception object in - // the parent function's localescape block. - const Value *ExceptionObjectVar; - int ExceptionObjectIndex; - TinyPtrVector ReturnTargets; -}; - -class CleanupHandler : public ActionHandler { -public: - CleanupHandler(BasicBlock *BB) : ActionHandler(BB, ActionType::Cleanup) {} - - // Method for support type inquiry through isa, cast, and dyn_cast: - static inline bool classof(const ActionHandler *H) { - return H->getType() == ActionType::Cleanup; - } -}; - -void parseEHActions(const IntrinsicInst *II, - SmallVectorImpl> &Actions); - -// The following structs respresent the .xdata for functions using C++ -// exceptions on Windows. +// The following structs respresent the .xdata tables for various +// Windows-related EH personalities. typedef PointerUnion MBBOrBasicBlock; typedef PointerUnion ValueOrMBB; -struct WinEHUnwindMapEntry { +struct CxxUnwindMapEntry { int ToState; ValueOrMBB Cleanup; }; -/// Similar to WinEHUnwindMapEntry, but supports SEH filters. +/// Similar to CxxUnwindMapEntry, but supports SEH filters. struct SEHUnwindMapEntry { /// If unwinding continues through this handler, transition to the handler at /// this state. This indexes into SEHUnwindMap. @@ -174,13 +93,13 @@ struct WinEHFuncInfo { DenseMap CatchRetSuccessorColorMap; DenseMap> InvokeToStateMap; - SmallVector UnwindMap; + SmallVector CxxUnwindMap; SmallVector TryBlockMap; SmallVector SEHUnwindMap; SmallVector ClrEHUnwindMap; int UnwindHelpFrameIdx = INT_MAX; - int getLastStateNumber() const { return UnwindMap.size() - 1; } + int getLastStateNumber() const { return CxxUnwindMap.size() - 1; } void addIPToStateRange(const BasicBlock *PadBB, MCSymbol *InvokeBegin, MCSymbol *InvokeEnd); diff --git a/include/llvm/IR/Intrinsics.td b/include/llvm/IR/Intrinsics.td index d40390ed3b4..fa43eb6a30e 100644 --- a/include/llvm/IR/Intrinsics.td +++ b/include/llvm/IR/Intrinsics.td @@ -429,13 +429,6 @@ def int_eh_typeid_for : Intrinsic<[llvm_i32_ty], [llvm_ptr_ty], [IntrNoMem]>; def int_eh_return_i32 : Intrinsic<[], [llvm_i32_ty, llvm_ptr_ty]>; def int_eh_return_i64 : Intrinsic<[], [llvm_i64_ty, llvm_ptr_ty]>; -// eh.begincatch takes a pointer returned by a landingpad instruction and -// copies the exception object into the memory pointed to by the second -// parameter. If the second parameter is null, no copy occurs. -def int_eh_begincatch : Intrinsic<[], [llvm_ptr_ty, llvm_ptr_ty], - [NoCapture<0>, NoCapture<1>]>; -def int_eh_endcatch : Intrinsic<[], []>; - // eh.exceptionpointer returns the pointer to the exception caught by // the given `catchpad`. def int_eh_exceptionpointer : Intrinsic<[llvm_anyptr_ty], [llvm_token_ty], @@ -444,12 +437,6 @@ def int_eh_exceptionpointer : Intrinsic<[llvm_anyptr_ty], [llvm_token_ty], // Gets the exception code from a catchpad token. Only used on some platforms. def int_eh_exceptioncode : Intrinsic<[llvm_i32_ty], [llvm_token_ty], [IntrNoMem]>; -// Represents the list of actions to take when an exception is thrown. -def int_eh_actions : Intrinsic<[llvm_ptr_ty], [llvm_vararg_ty], []>; - -// FIXME: Remove this when landing pad EH can be removed. -def int_eh_exceptioncode_old : Intrinsic<[llvm_i32_ty], [], [IntrReadMem]>; - // __builtin_unwind_init is an undocumented GCC intrinsic that causes all // callee-saved registers to be saved and restored (regardless of whether they // are used) in the calling function. It is used by libgcc_eh. diff --git a/lib/Analysis/Lint.cpp b/lib/Analysis/Lint.cpp index 15acc783f07..b63049c2591 100644 --- a/lib/Analysis/Lint.cpp +++ b/lib/Analysis/Lint.cpp @@ -345,13 +345,6 @@ void Lint::visitCallSite(CallSite CS) { visitMemoryReference(I, CS.getArgument(0), MemoryLocation::UnknownSize, 0, nullptr, MemRef::Read | MemRef::Write); break; - - case Intrinsic::eh_begincatch: - visitEHBeginCatch(II); - break; - case Intrinsic::eh_endcatch: - visitEHEndCatch(II); - break; } } @@ -511,187 +504,6 @@ void Lint::visitShl(BinaryOperator &I) { "Undefined result: Shift count out of range", &I); } -static bool -allPredsCameFromLandingPad(BasicBlock *BB, - SmallSet &VisitedBlocks) { - VisitedBlocks.insert(BB); - if (BB->isLandingPad()) - return true; - // If we find a block with no predecessors, the search failed. - if (pred_empty(BB)) - return false; - for (BasicBlock *Pred : predecessors(BB)) { - if (VisitedBlocks.count(Pred)) - continue; - if (!allPredsCameFromLandingPad(Pred, VisitedBlocks)) - return false; - } - return true; -} - -static bool -allSuccessorsReachEndCatch(BasicBlock *BB, BasicBlock::iterator InstBegin, - IntrinsicInst **SecondBeginCatch, - SmallSet &VisitedBlocks) { - VisitedBlocks.insert(BB); - for (BasicBlock::iterator I = InstBegin, E = BB->end(); I != E; ++I) { - IntrinsicInst *IC = dyn_cast(I); - if (IC && IC->getIntrinsicID() == Intrinsic::eh_endcatch) - return true; - // If we find another begincatch while looking for an endcatch, - // that's also an error. - if (IC && IC->getIntrinsicID() == Intrinsic::eh_begincatch) { - *SecondBeginCatch = IC; - return false; - } - } - - // If we reach a block with no successors while searching, the - // search has failed. - if (succ_empty(BB)) - return false; - // Otherwise, search all of the successors. - for (BasicBlock *Succ : successors(BB)) { - if (VisitedBlocks.count(Succ)) - continue; - if (!allSuccessorsReachEndCatch(Succ, Succ->begin(), SecondBeginCatch, - VisitedBlocks)) - return false; - } - return true; -} - -void Lint::visitEHBeginCatch(IntrinsicInst *II) { - // The checks in this function make a potentially dubious assumption about - // the CFG, namely that any block involved in a catch is only used for the - // catch. This will very likely be true of IR generated by a front end, - // but it may cease to be true, for example, if the IR is run through a - // pass which combines similar blocks. - // - // In general, if we encounter a block the isn't dominated by the catch - // block while we are searching the catch block's successors for a call - // to end catch intrinsic, then it is possible that it will be legal for - // a path through this block to never reach a call to llvm.eh.endcatch. - // An analogous statement could be made about our search for a landing - // pad among the catch block's predecessors. - // - // What is actually required is that no path is possible at runtime that - // reaches a call to llvm.eh.begincatch without having previously visited - // a landingpad instruction and that no path is possible at runtime that - // calls llvm.eh.begincatch and does not subsequently call llvm.eh.endcatch - // (mentally adjusting for the fact that in reality these calls will be - // removed before code generation). - // - // Because this is a lint check, we take a pessimistic approach and warn if - // the control flow is potentially incorrect. - - SmallSet VisitedBlocks; - BasicBlock *CatchBB = II->getParent(); - - // The begin catch must occur in a landing pad block or all paths - // to it must have come from a landing pad. - Assert(allPredsCameFromLandingPad(CatchBB, VisitedBlocks), - "llvm.eh.begincatch may be reachable without passing a landingpad", - II); - - // Reset the visited block list. - VisitedBlocks.clear(); - - IntrinsicInst *SecondBeginCatch = nullptr; - - // This has to be called before it is asserted. Otherwise, the first assert - // below can never be hit. - bool EndCatchFound = allSuccessorsReachEndCatch( - CatchBB, std::next(static_cast(II)), - &SecondBeginCatch, VisitedBlocks); - Assert( - SecondBeginCatch == nullptr, - "llvm.eh.begincatch may be called a second time before llvm.eh.endcatch", - II, SecondBeginCatch); - Assert(EndCatchFound, - "Some paths from llvm.eh.begincatch may not reach llvm.eh.endcatch", - II); -} - -static bool allPredCameFromBeginCatch( - BasicBlock *BB, BasicBlock::reverse_iterator InstRbegin, - IntrinsicInst **SecondEndCatch, SmallSet &VisitedBlocks) { - VisitedBlocks.insert(BB); - // Look for a begincatch in this block. - for (BasicBlock::reverse_iterator RI = InstRbegin, RE = BB->rend(); RI != RE; - ++RI) { - IntrinsicInst *IC = dyn_cast(&*RI); - if (IC && IC->getIntrinsicID() == Intrinsic::eh_begincatch) - return true; - // If we find another end catch before we find a begin catch, that's - // an error. - if (IC && IC->getIntrinsicID() == Intrinsic::eh_endcatch) { - *SecondEndCatch = IC; - return false; - } - // If we encounter a landingpad instruction, the search failed. - if (isa(*RI)) - return false; - } - // If while searching we find a block with no predeccesors, - // the search failed. - if (pred_empty(BB)) - return false; - // Search any predecessors we haven't seen before. - for (BasicBlock *Pred : predecessors(BB)) { - if (VisitedBlocks.count(Pred)) - continue; - if (!allPredCameFromBeginCatch(Pred, Pred->rbegin(), SecondEndCatch, - VisitedBlocks)) - return false; - } - return true; -} - -void Lint::visitEHEndCatch(IntrinsicInst *II) { - // The check in this function makes a potentially dubious assumption about - // the CFG, namely that any block involved in a catch is only used for the - // catch. This will very likely be true of IR generated by a front end, - // but it may cease to be true, for example, if the IR is run through a - // pass which combines similar blocks. - // - // In general, if we encounter a block the isn't post-dominated by the - // end catch block while we are searching the end catch block's predecessors - // for a call to the begin catch intrinsic, then it is possible that it will - // be legal for a path to reach the end catch block without ever having - // called llvm.eh.begincatch. - // - // What is actually required is that no path is possible at runtime that - // reaches a call to llvm.eh.endcatch without having previously visited - // a call to llvm.eh.begincatch (mentally adjusting for the fact that in - // reality these calls will be removed before code generation). - // - // Because this is a lint check, we take a pessimistic approach and warn if - // the control flow is potentially incorrect. - - BasicBlock *EndCatchBB = II->getParent(); - - // Alls paths to the end catch call must pass through a begin catch call. - - // If llvm.eh.begincatch wasn't called in the current block, we'll use this - // lambda to recursively look for it in predecessors. - SmallSet VisitedBlocks; - IntrinsicInst *SecondEndCatch = nullptr; - - // This has to be called before it is asserted. Otherwise, the first assert - // below can never be hit. - bool BeginCatchFound = - allPredCameFromBeginCatch(EndCatchBB, BasicBlock::reverse_iterator(II), - &SecondEndCatch, VisitedBlocks); - Assert( - SecondEndCatch == nullptr, - "llvm.eh.endcatch may be called a second time after llvm.eh.begincatch", - II, SecondEndCatch); - Assert(BeginCatchFound, - "llvm.eh.endcatch may be reachable without passing llvm.eh.begincatch", - II); -} - static bool isZero(Value *V, const DataLayout &DL, DominatorTree *DT, AssumptionCache *AC) { // Assume undef could be zero. diff --git a/lib/CodeGen/AsmPrinter/WinException.cpp b/lib/CodeGen/AsmPrinter/WinException.cpp index 63be0daa708..adc47650235 100644 --- a/lib/CodeGen/AsmPrinter/WinException.cpp +++ b/lib/CodeGen/AsmPrinter/WinException.cpp @@ -418,7 +418,7 @@ invoke_ranges(WinEHFuncInfo &EHInfo, const MachineBasicBlock &MBB) { /// imagerel32 LabelStart; /// imagerel32 LabelEnd; /// imagerel32 FilterOrFinally; // One means catch-all. -/// imagerel32 ExceptOrNull; // Zero means __finally. +/// imagerel32 LabelLPad; // Zero means __finally. /// } Entries[NumEntries]; /// }; void WinException::emitCSpecificHandlerTable(const MachineFunction *MF) { @@ -426,153 +426,69 @@ void WinException::emitCSpecificHandlerTable(const MachineFunction *MF) { MCContext &Ctx = Asm->OutContext; WinEHFuncInfo &FuncInfo = MMI->getWinEHFuncInfo(MF->getFunction()); - if (!FuncInfo.SEHUnwindMap.empty()) { - // Remember what state we were in the last time we found a begin try label. - // This allows us to coalesce many nearby invokes with the same state into - // one entry. - int LastEHState = -1; - MCSymbol *LastBeginLabel = nullptr; - MCSymbol *LastEndLabel = nullptr; - - // Use the assembler to compute the number of table entries through label - // difference and division. - MCSymbol *TableBegin = - Ctx.createTempSymbol("lsda_begin", /*AlwaysAddSuffix=*/true); - MCSymbol *TableEnd = - Ctx.createTempSymbol("lsda_end", /*AlwaysAddSuffix=*/true); - const MCExpr *LabelDiff = - MCBinaryExpr::createSub(MCSymbolRefExpr::create(TableEnd, Ctx), - MCSymbolRefExpr::create(TableBegin, Ctx), Ctx); - const MCExpr *EntrySize = MCConstantExpr::create(16, Ctx); - const MCExpr *EntryCount = - MCBinaryExpr::createDiv(LabelDiff, EntrySize, Ctx); - OS.EmitValue(EntryCount, 4); - - OS.EmitLabel(TableBegin); - - // Iterate over all the invoke try ranges. Unlike MSVC, LLVM currently only - // models exceptions from invokes. LLVM also allows arbitrary reordering of - // the code, so our tables end up looking a bit different. Rather than - // trying to match MSVC's tables exactly, we emit a denormalized table. For - // each range of invokes in the same state, we emit table entries for all - // the actions that would be taken in that state. This means our tables are - // slightly bigger, which is OK. - for (const auto &MBB : *MF) { - // Break out before we enter into a finally funclet. - // FIXME: We need to emit separate EH tables for cleanups. - if (MBB.isEHFuncletEntry() && &MBB != MF->begin()) - break; - - for (InvokeRange &I : invoke_ranges(FuncInfo, MBB)) { - // If this invoke is in the same state as the last invoke and there were - // no non-throwing calls between it, extend the range to include both - // and continue. - if (!I.SawPotentiallyThrowing && I.State == LastEHState) { - LastEndLabel = I.EndLabel; - continue; - } - // If this invoke ends a previous one, emit all the actions for this - // state. - if (LastEHState != -1) - emitSEHActionsForRange(FuncInfo, LastBeginLabel, LastEndLabel, - LastEHState); + // Remember what state we were in the last time we found a begin try label. + // This allows us to coalesce many nearby invokes with the same state into + // one entry. + int LastEHState = -1; + MCSymbol *LastBeginLabel = nullptr; + MCSymbol *LastEndLabel = nullptr; + + // Use the assembler to compute the number of table entries through label + // difference and division. + MCSymbol *TableBegin = + Ctx.createTempSymbol("lsda_begin", /*AlwaysAddSuffix=*/true); + MCSymbol *TableEnd = + Ctx.createTempSymbol("lsda_end", /*AlwaysAddSuffix=*/true); + const MCExpr *LabelDiff = + MCBinaryExpr::createSub(MCSymbolRefExpr::create(TableEnd, Ctx), + MCSymbolRefExpr::create(TableBegin, Ctx), Ctx); + const MCExpr *EntrySize = MCConstantExpr::create(16, Ctx); + const MCExpr *EntryCount = MCBinaryExpr::createDiv(LabelDiff, EntrySize, Ctx); + OS.EmitValue(EntryCount, 4); + + OS.EmitLabel(TableBegin); + + // Iterate over all the invoke try ranges. Unlike MSVC, LLVM currently only + // models exceptions from invokes. LLVM also allows arbitrary reordering of + // the code, so our tables end up looking a bit different. Rather than + // trying to match MSVC's tables exactly, we emit a denormalized table. For + // each range of invokes in the same state, we emit table entries for all + // the actions that would be taken in that state. This means our tables are + // slightly bigger, which is OK. + for (const auto &MBB : *MF) { + // Break out before we enter into a finally funclet. + // FIXME: We need to emit separate EH tables for cleanups. + if (MBB.isEHFuncletEntry() && &MBB != MF->begin()) + break; - LastBeginLabel = I.BeginLabel; + for (InvokeRange &I : invoke_ranges(FuncInfo, MBB)) { + // If this invoke is in the same state as the last invoke and there were + // no non-throwing calls between it, extend the range to include both + // and continue. + if (!I.SawPotentiallyThrowing && I.State == LastEHState) { LastEndLabel = I.EndLabel; - LastEHState = I.State; + continue; } - } - if (LastEndLabel) - emitSEHActionsForRange(FuncInfo, LastBeginLabel, LastEndLabel, - LastEHState); + // If this invoke ends a previous one, emit all the actions for this + // state. + if (LastEHState != -1) + emitSEHActionsForRange(FuncInfo, LastBeginLabel, LastEndLabel, + LastEHState); - OS.EmitLabel(TableEnd); - return; + LastBeginLabel = I.BeginLabel; + LastEndLabel = I.EndLabel; + LastEHState = I.State; + } } - // Simplifying assumptions for first implementation: - // - Cleanups are not implemented. - // - Filters are not implemented. - - // The Itanium LSDA table sorts similar landing pads together to simplify the - // actions table, but we don't need that. - const std::vector &PadInfos = MMI->getLandingPads(); - SmallVector LandingPads; - LandingPads.reserve(PadInfos.size()); - for (const auto &LP : PadInfos) - LandingPads.push_back(&LP); - - // Compute label ranges for call sites as we would for the Itanium LSDA, but - // use an all zero action table because we aren't using these actions. - SmallVector FirstActions; - FirstActions.resize(LandingPads.size()); - SmallVector CallSites; - computeCallSiteTable(CallSites, LandingPads, FirstActions); - - MCSymbol *EHFuncBeginSym = Asm->getFunctionBegin(); - MCSymbol *EHFuncEndSym = Asm->getFunctionEnd(); - - // Emit the number of table entries. - unsigned NumEntries = 0; - for (const CallSiteEntry &CSE : CallSites) { - if (!CSE.LPad) - continue; // Ignore gaps. - NumEntries += CSE.LPad->SEHHandlers.size(); - } - OS.EmitIntValue(NumEntries, 4); + // Hitting the end of the function causes us to emit the range for the + // previous invoke. + if (LastEndLabel) + emitSEHActionsForRange(FuncInfo, LastBeginLabel, LastEndLabel, LastEHState); - // If there are no actions, we don't need to iterate again. - if (NumEntries == 0) - return; - - // Emit the four-label records for each call site entry. The table has to be - // sorted in layout order, and the call sites should already be sorted. - for (const CallSiteEntry &CSE : CallSites) { - // Ignore gaps. Unlike the Itanium model, unwinding through a frame without - // an EH table entry will propagate the exception rather than terminating - // the program. - if (!CSE.LPad) - continue; - const LandingPadInfo *LPad = CSE.LPad; - - // Compute the label range. We may reuse the function begin and end labels - // rather than forming new ones. - const MCExpr *Begin = - create32bitRef(CSE.BeginLabel ? CSE.BeginLabel : EHFuncBeginSym); - const MCExpr *End; - if (CSE.EndLabel) { - // The interval is half-open, so we have to add one to include the return - // address of the last invoke in the range. - End = getLabelPlusOne(CSE.EndLabel); - } else { - End = create32bitRef(EHFuncEndSym); - } - - // Emit an entry for each action. - for (SEHHandler Handler : LPad->SEHHandlers) { - OS.EmitValue(Begin, 4); - OS.EmitValue(End, 4); - - // Emit the filter or finally function pointer, if present. Otherwise, - // emit '1' to indicate a catch-all. - const Function *F = Handler.FilterOrFinally; - if (F) - OS.EmitValue(create32bitRef(Asm->getSymbol(F)), 4); - else - OS.EmitIntValue(1, 4); - - // Emit the recovery address, if present. Otherwise, this must be a - // finally. - const BlockAddress *BA = Handler.RecoverBA; - if (BA) - OS.EmitValue( - create32bitRef(Asm->GetBlockAddressSymbol(BA)), 4); - else - OS.EmitIntValue(0, 4); - } - } + OS.EmitLabel(TableEnd); } void WinException::emitSEHActionsForRange(WinEHFuncInfo &FuncInfo, @@ -583,12 +499,6 @@ void WinException::emitSEHActionsForRange(WinEHFuncInfo &FuncInfo, assert(BeginLabel && EndLabel); while (State != -1) { - // struct Entry { - // imagerel32 LabelStart; - // imagerel32 LabelEnd; - // imagerel32 FilterOrFinally; // One means catch-all. - // imagerel32 ExceptOrNull; // Zero means __finally. - // }; SEHUnwindMapEntry &UME = FuncInfo.SEHUnwindMap[State]; const MCExpr *FilterOrFinally; const MCExpr *ExceptOrNull; @@ -641,7 +551,7 @@ void WinException::emitCXXFrameHandler3Table(const MachineFunction *MF) { MCSymbol *UnwindMapXData = nullptr; MCSymbol *TryBlockMapXData = nullptr; MCSymbol *IPToStateXData = nullptr; - if (!FuncInfo.UnwindMap.empty()) + if (!FuncInfo.CxxUnwindMap.empty()) UnwindMapXData = Asm->OutContext.getOrCreateSymbol( Twine("$stateUnwindMap$", FuncLinkageName)); if (!FuncInfo.TryBlockMap.empty()) @@ -669,7 +579,7 @@ void WinException::emitCXXFrameHandler3Table(const MachineFunction *MF) { OS.EmitValueToAlignment(4); OS.EmitLabel(FuncInfoXData); OS.EmitIntValue(0x19930522, 4); // MagicNumber - OS.EmitIntValue(FuncInfo.UnwindMap.size(), 4); // MaxState + OS.EmitIntValue(FuncInfo.CxxUnwindMap.size(), 4); // MaxState OS.EmitValue(create32bitRef(UnwindMapXData), 4); // UnwindMap OS.EmitIntValue(FuncInfo.TryBlockMap.size(), 4); // NumTryBlocks OS.EmitValue(create32bitRef(TryBlockMapXData), 4); // TryBlockMap @@ -686,7 +596,7 @@ void WinException::emitCXXFrameHandler3Table(const MachineFunction *MF) { // }; if (UnwindMapXData) { OS.EmitLabel(UnwindMapXData); - for (const WinEHUnwindMapEntry &UME : FuncInfo.UnwindMap) { + for (const CxxUnwindMapEntry &UME : FuncInfo.CxxUnwindMap) { MCSymbol *CleanupSym = getMCSymbolForMBBOrGV(Asm, UME.Cleanup); OS.EmitIntValue(UME.ToState, 4); // ToState OS.EmitValue(create32bitRef(CleanupSym), 4); // Action @@ -719,7 +629,7 @@ void WinException::emitCXXFrameHandler3Table(const MachineFunction *MF) { assert(0 <= TBME.TryLow && "bad trymap interval"); assert(TBME.TryLow <= TBME.TryHigh && "bad trymap interval"); assert(TBME.TryHigh < TBME.CatchHigh && "bad trymap interval"); - assert(TBME.CatchHigh < int(FuncInfo.UnwindMap.size()) && + assert(TBME.CatchHigh < int(FuncInfo.CxxUnwindMap.size()) && "bad trymap interval"); OS.EmitIntValue(TBME.TryLow, 4); // TryLow @@ -903,66 +813,15 @@ void WinException::emitExceptHandlerTable(const MachineFunction *MF) { BaseState = -2; } - if (!FuncInfo.SEHUnwindMap.empty()) { - for (SEHUnwindMapEntry &UME : FuncInfo.SEHUnwindMap) { - MCSymbol *ExceptOrFinally = - UME.Handler.get()->getSymbol(); - // -1 is usually the base state for "unwind to caller", but for - // _except_handler4 it's -2. Do that replacement here if necessary. - int ToState = UME.ToState == -1 ? BaseState : UME.ToState; - OS.EmitIntValue(ToState, 4); // ToState - OS.EmitValue(create32bitRef(UME.Filter), 4); // Filter - OS.EmitValue(create32bitRef(ExceptOrFinally), 4); // Except/Finally - } - return; - } - // FIXME: The following code is for the old landingpad-based SEH - // implementation. Remove it when possible. - - // Build a list of pointers to LandingPadInfos and then sort by WinEHState. - const std::vector &PadInfos = MMI->getLandingPads(); - SmallVector 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 *Filter)(); - // void *HandlerOrFinally; - // }; - // - // 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 + int(LPInfo->SEHHandlers.size()) - 1 == - LPInfo->WinEHState && - "gaps in the SEH scope table"); - for (auto I = LPInfo->SEHHandlers.rbegin(), E = LPInfo->SEHHandlers.rend(); - I != E; ++I) { - const SEHHandler &Handler = *I; - const BlockAddress *BA = Handler.RecoverBA; - const Function *F = Handler.FilterOrFinally; - assert(F && "cannot catch all in 32-bit SEH without filter function"); - const MCExpr *FilterOrNull = - create32bitRef(BA ? Asm->getSymbol(F) : nullptr); - const MCExpr *ExceptOrFinally = create32bitRef( - BA ? Asm->GetBlockAddressSymbol(BA) : Asm->getSymbol(F)); - - OS.EmitIntValue(EnclosingLevel, 4); - OS.EmitValue(FilterOrNull, 4); - OS.EmitValue(ExceptOrFinally, 4); - - // The next state unwinds to this state. - EnclosingLevel = CurState; - CurState++; - } + assert(!FuncInfo.SEHUnwindMap.empty()); + for (SEHUnwindMapEntry &UME : FuncInfo.SEHUnwindMap) { + MCSymbol *ExceptOrFinally = + UME.Handler.get()->getSymbol(); + // -1 is usually the base state for "unwind to caller", but for + // _except_handler4 it's -2. Do that replacement here if necessary. + int ToState = UME.ToState == -1 ? BaseState : UME.ToState; + OS.EmitIntValue(ToState, 4); // ToState + OS.EmitValue(create32bitRef(UME.Filter), 4); // Filter + OS.EmitValue(create32bitRef(ExceptOrFinally), 4); // Except/Finally } } diff --git a/lib/CodeGen/SelectionDAG/FastISel.cpp b/lib/CodeGen/SelectionDAG/FastISel.cpp index 13b097cfc60..1e2f2fb0429 100644 --- a/lib/CodeGen/SelectionDAG/FastISel.cpp +++ b/lib/CodeGen/SelectionDAG/FastISel.cpp @@ -1103,13 +1103,6 @@ bool FastISel::selectIntrinsicCall(const IntrinsicInst *II) { // The donothing intrinsic does, well, nothing. case Intrinsic::donothing: return true; - case Intrinsic::eh_actions: { - unsigned ResultReg = getRegForValue(UndefValue::get(II->getType())); - if (!ResultReg) - return false; - updateValueMap(II, ResultReg); - return true; - } case Intrinsic::dbg_declare: { const DbgDeclareInst *DI = cast(II); assert(DI->getVariable() && "Missing variable"); diff --git a/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp b/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp index cf2d84f9a11..d9b32d92c8e 100644 --- a/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp +++ b/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp @@ -283,11 +283,6 @@ void FunctionLoweringInfo::set(const Function &fn, MachineFunction &mf, if (!isFuncletEHPersonality(Personality)) return; - if (Personality == EHPersonality::MSVC_Win64SEH || - Personality == EHPersonality::MSVC_X86SEH) { - addSEHHandlersForLPads(LPads); - } - // Calculate state numbers if we haven't already. WinEHFuncInfo &EHInfo = MMI.getWinEHFuncInfo(&fn); const Function *WinEHParentFn = MMI.getWinEHParent(&fn); @@ -313,7 +308,7 @@ void FunctionLoweringInfo::set(const Function &fn, MachineFunction &mf, H.Handler = MBBMap[BB]; } } - for (WinEHUnwindMapEntry &UME : EHInfo.UnwindMap) + for (CxxUnwindMapEntry &UME : EHInfo.CxxUnwindMap) if (UME.Cleanup) if (const auto *BB = dyn_cast(UME.Cleanup.get())) UME.Cleanup = MBBMap[BB]; @@ -345,44 +340,6 @@ void FunctionLoweringInfo::set(const Function &fn, MachineFunction &mf, } } -void FunctionLoweringInfo::addSEHHandlersForLPads( - ArrayRef LPads) { - MachineModuleInfo &MMI = MF->getMMI(); - - // Iterate over all landing pads with llvm.eh.actions calls. - for (const LandingPadInst *LP : LPads) { - const IntrinsicInst *ActionsCall = - dyn_cast(LP->getNextNode()); - if (!ActionsCall || - ActionsCall->getIntrinsicID() != Intrinsic::eh_actions) - continue; - - // Parse the llvm.eh.actions call we found. - MachineBasicBlock *LPadMBB = MBBMap[LP->getParent()]; - SmallVector, 4> Actions; - parseEHActions(ActionsCall, Actions); - - // Iterate EH actions from most to least precedence, which means - // iterating in reverse. - for (auto I = Actions.rbegin(), E = Actions.rend(); I != E; ++I) { - ActionHandler *Action = I->get(); - if (auto *CH = dyn_cast(Action)) { - const auto *Filter = - dyn_cast(CH->getSelector()->stripPointerCasts()); - assert((Filter || CH->getSelector()->isNullValue()) && - "expected function or catch-all"); - const auto *RecoverBA = - cast(CH->getHandlerBlockOrFunc()); - MMI.addSEHCatchHandler(LPadMBB, Filter, RecoverBA); - } else { - assert(isa(Action)); - const auto *Fini = cast(Action->getHandlerBlockOrFunc()); - MMI.addSEHCleanupHandler(LPadMBB, Fini); - } - } - } -} - /// clear - Clear out all the function-specific state. This returns this /// FunctionLoweringInfo to an empty state, ready to be used for a /// different function. diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp index 9e315194c98..071317c5a53 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -5152,9 +5152,6 @@ SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) { } case Intrinsic::clear_cache: return TLI.getClearCacheBuiltinName(); - case Intrinsic::eh_actions: - setValue(&I, DAG.getUNDEF(TLI.getPointerTy(DAG.getDataLayout()))); - return nullptr; case Intrinsic::donothing: // ignore return nullptr; @@ -5238,22 +5235,6 @@ SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) { return nullptr; } - case Intrinsic::eh_begincatch: - case Intrinsic::eh_endcatch: - llvm_unreachable("begin/end catch intrinsics not lowered in codegen"); - case Intrinsic::eh_exceptioncode_old: { - unsigned Reg = TLI.getExceptionPointerRegister(); - assert(Reg && "cannot get exception code on this platform"); - MVT PtrVT = TLI.getPointerTy(DAG.getDataLayout()); - const TargetRegisterClass *PtrRC = TLI.getRegClassFor(PtrVT); - assert(FuncInfo.MBB->isEHPad() && "eh.exceptioncode in non-lpad"); - unsigned VReg = FuncInfo.MBB->addLiveIn(Reg, PtrRC); - SDValue N = - DAG.getCopyFromReg(DAG.getEntryNode(), getCurSDLoc(), VReg, PtrVT); - N = DAG.getZExtOrTrunc(N, getCurSDLoc(), MVT::i32); - setValue(&I, N); - return nullptr; - } case Intrinsic::eh_exceptionpointer: case Intrinsic::eh_exceptioncode: { diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp index 0df05683b4f..2a25131dbad 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp @@ -973,43 +973,6 @@ bool SelectionDAGISel::PrepareEHLandingPad() { BuildMI(*MBB, FuncInfo->InsertPt, SDB->getCurDebugLoc(), II) .addSym(Label); - // If this personality function uses funclets, we need to split the landing - // pad into several BBs. - const Constant *Personality = MF->getFunction()->getPersonalityFn(); - if (const auto *PF = dyn_cast(Personality->stripPointerCasts())) - MF->getMMI().addPersonality(PF); - EHPersonality PersonalityType = classifyEHPersonality(Personality); - - if (isFuncletEHPersonality(PersonalityType)) { - SmallVector ClauseBBs; - const IntrinsicInst *ActionsCall = - dyn_cast(LLVMBB->getFirstInsertionPt()); - // Get all invoke BBs that unwind to this landingpad. - SmallVector InvokeBBs(MBB->pred_begin(), - MBB->pred_end()); - if (ActionsCall && ActionsCall->getIntrinsicID() == Intrinsic::eh_actions) { - // If this is a call to llvm.eh.actions followed by indirectbr, then we've - // run WinEHPrepare, and we should remove this block from the machine CFG. - // Mark the targets of the indirectbr as landingpads instead. - for (const BasicBlock *LLVMSucc : successors(LLVMBB)) { - MachineBasicBlock *ClauseBB = FuncInfo->MBBMap[LLVMSucc]; - // Add the edge from the invoke to the clause. - for (MachineBasicBlock *InvokeBB : InvokeBBs) - InvokeBB->addSuccessor(ClauseBB); - - // Mark the clause as a landing pad or MI passes will delete it. - ClauseBB->setIsEHPad(); - } - } - - // Remove the edge from the invoke to the lpad. - for (MachineBasicBlock *InvokeBB : InvokeBBs) - InvokeBB->removeSuccessor(MBB); - - // Don't select instructions for the landingpad. - return false; - } - // Mark exception register as live in. if (unsigned Reg = TLI->getExceptionPointerRegister()) FuncInfo->ExceptionPointerVirtReg = MBB->addLiveIn(Reg, PtrRC); diff --git a/lib/CodeGen/WinEHPrepare.cpp b/lib/CodeGen/WinEHPrepare.cpp index 11a7edec48f..5affb3f0924 100644 --- a/lib/CodeGen/WinEHPrepare.cpp +++ b/lib/CodeGen/WinEHPrepare.cpp @@ -63,27 +63,6 @@ static cl::opt DisableCleanups( namespace { -// This map is used to model frame variable usage during outlining, to -// construct a structure type to hold the frame variables in a frame -// allocation block, and to remap the frame variable allocas (including -// spill locations as needed) to GEPs that get the variable from the -// frame allocation structure. -typedef MapVector> FrameVarInfoMap; - -// TinyPtrVector cannot hold nullptr, so we need our own sentinel that isn't -// quite null. -AllocaInst *getCatchObjectSentinel() { - return static_cast(nullptr) + 1; -} - -typedef SmallSet VisitedBlockSet; - -class LandingPadActions; -class LandingPadMap; - -typedef DenseMap CatchHandlerMapTy; -typedef DenseMap CleanupHandlerMapTy; - class WinEHPrepare : public FunctionPass { public: static char ID; // Pass identification, replacement for typeid. @@ -104,36 +83,6 @@ public: } private: - bool prepareExceptionHandlers(Function &F, - SmallVectorImpl &LPads); - void identifyEHBlocks(Function &F, SmallVectorImpl &LPads); - void promoteLandingPadValues(LandingPadInst *LPad); - void demoteValuesLiveAcrossHandlers(Function &F, - SmallVectorImpl &LPads); - void findSEHEHReturnPoints(Function &F, - SetVector &EHReturnBlocks); - void findCXXEHReturnPoints(Function &F, - SetVector &EHReturnBlocks); - void getPossibleReturnTargets(Function *ParentF, Function *HandlerF, - SetVector &Targets); - void completeNestedLandingPad(Function *ParentFn, - LandingPadInst *OutlinedLPad, - const LandingPadInst *OriginalLPad, - FrameVarInfoMap &VarInfo); - Function *createHandlerFunc(Function *ParentFn, Type *RetTy, - const Twine &Name, Module *M, Value *&ParentFP); - bool outlineHandler(ActionHandler *Action, Function *SrcFn, - LandingPadInst *LPad, BasicBlock *StartBB, - FrameVarInfoMap &VarInfo); - void addStubInvokeToHandlerIfNeeded(Function *Handler); - - void mapLandingPadBlocks(LandingPadInst *LPad, LandingPadActions &Actions); - CatchHandler *findCatchHandler(BasicBlock *BB, BasicBlock *&NextBB, - VisitedBlockSet &VisitedBlocks); - void findCleanupHandlers(LandingPadActions &Actions, BasicBlock *StartBB, - BasicBlock *EndBB); - - void processSEHCatchHandler(CatchHandler *Handler, BasicBlock *StartBB); void insertPHIStores(PHINode *OriginalPHI, AllocaInst *SpillSlot); void insertPHIStore(BasicBlock *PredBlock, Value *PredVal, AllocaInst *SpillSlot, @@ -159,236 +108,13 @@ private: Triple TheTriple; // All fields are reset by runOnFunction. - DominatorTree *DT = nullptr; - const TargetLibraryInfo *LibInfo = nullptr; EHPersonality Personality = EHPersonality::Unknown; - CatchHandlerMapTy CatchHandlerMap; - CleanupHandlerMapTy CleanupHandlerMap; - DenseMap LPadMaps; - SmallPtrSet NormalBlocks; - SmallPtrSet EHBlocks; - SetVector EHReturnBlocks; - - // This maps landing pad instructions found in outlined handlers to - // the landing pad instruction in the parent function from which they - // were cloned. The cloned/nested landing pad is used as the key - // because the landing pad may be cloned into multiple handlers. - // This map will be used to add the llvm.eh.actions call to the nested - // landing pads after all handlers have been outlined. - DenseMap NestedLPtoOriginalLP; - - // This maps blocks in the parent function which are destinations of - // catch handlers to cloned blocks in (other) outlined handlers. This - // handles the case where a nested landing pads has a catch handler that - // returns to a handler function rather than the parent function. - // The original block is used as the key here because there should only - // ever be one handler function from which the cloned block is not pruned. - // The original block will be pruned from the parent function after all - // handlers have been outlined. This map will be used to adjust the - // return instructions of handlers which return to the block that was - // outlined into a handler. This is done after all handlers have been - // outlined but before the outlined code is pruned from the parent function. - DenseMap LPadTargetBlocks; - - // Map from outlined handler to call to parent local address. Only used for - // 32-bit EH. - DenseMap HandlerToParentFP; - - AllocaInst *SEHExceptionCodeSlot = nullptr; std::map> BlockColors; std::map> FuncletBlocks; std::map> FuncletChildren; }; -class WinEHFrameVariableMaterializer : public ValueMaterializer { -public: - WinEHFrameVariableMaterializer(Function *OutlinedFn, Value *ParentFP, - FrameVarInfoMap &FrameVarInfo); - ~WinEHFrameVariableMaterializer() override {} - - Value *materializeValueFor(Value *V) override; - - void escapeCatchObject(Value *V); - -private: - FrameVarInfoMap &FrameVarInfo; - IRBuilder<> Builder; -}; - -class LandingPadMap { -public: - LandingPadMap() : OriginLPad(nullptr) {} - void mapLandingPad(const LandingPadInst *LPad); - - bool isInitialized() { return OriginLPad != nullptr; } - - bool isOriginLandingPadBlock(const BasicBlock *BB) const; - bool isLandingPadSpecificInst(const Instruction *Inst) const; - - void remapEHValues(ValueToValueMapTy &VMap, Value *EHPtrValue, - Value *SelectorValue) const; - -private: - const LandingPadInst *OriginLPad; - // We will normally only see one of each of these instructions, but - // if more than one occurs for some reason we can handle that. - TinyPtrVector ExtractedEHPtrs; - TinyPtrVector ExtractedSelectors; -}; - -class WinEHCloningDirectorBase : public CloningDirector { -public: - WinEHCloningDirectorBase(Function *HandlerFn, Value *ParentFP, - FrameVarInfoMap &VarInfo, LandingPadMap &LPadMap) - : Materializer(HandlerFn, ParentFP, VarInfo), - SelectorIDType(Type::getInt32Ty(HandlerFn->getContext())), - Int8PtrType(Type::getInt8PtrTy(HandlerFn->getContext())), - LPadMap(LPadMap), ParentFP(ParentFP) {} - - CloningAction handleInstruction(ValueToValueMapTy &VMap, - const Instruction *Inst, - BasicBlock *NewBB) override; - - virtual CloningAction handleBeginCatch(ValueToValueMapTy &VMap, - const Instruction *Inst, - BasicBlock *NewBB) = 0; - virtual CloningAction handleEndCatch(ValueToValueMapTy &VMap, - const Instruction *Inst, - BasicBlock *NewBB) = 0; - virtual CloningAction handleTypeIdFor(ValueToValueMapTy &VMap, - const Instruction *Inst, - BasicBlock *NewBB) = 0; - virtual CloningAction handleIndirectBr(ValueToValueMapTy &VMap, - const IndirectBrInst *IBr, - BasicBlock *NewBB) = 0; - virtual CloningAction handleInvoke(ValueToValueMapTy &VMap, - const InvokeInst *Invoke, - BasicBlock *NewBB) = 0; - virtual CloningAction handleResume(ValueToValueMapTy &VMap, - const ResumeInst *Resume, - BasicBlock *NewBB) = 0; - virtual CloningAction handleCompare(ValueToValueMapTy &VMap, - const CmpInst *Compare, - BasicBlock *NewBB) = 0; - virtual CloningAction handleLandingPad(ValueToValueMapTy &VMap, - const LandingPadInst *LPad, - BasicBlock *NewBB) = 0; - - ValueMaterializer *getValueMaterializer() override { return &Materializer; } - -protected: - WinEHFrameVariableMaterializer Materializer; - Type *SelectorIDType; - Type *Int8PtrType; - LandingPadMap &LPadMap; - - /// The value representing the parent frame pointer. - Value *ParentFP; -}; - -class WinEHCatchDirector : public WinEHCloningDirectorBase { -public: - WinEHCatchDirector( - Function *CatchFn, Value *ParentFP, Value *Selector, - FrameVarInfoMap &VarInfo, LandingPadMap &LPadMap, - DenseMap &NestedLPads, - DominatorTree *DT, SmallPtrSetImpl &EHBlocks) - : WinEHCloningDirectorBase(CatchFn, ParentFP, VarInfo, LPadMap), - CurrentSelector(Selector->stripPointerCasts()), - ExceptionObjectVar(nullptr), NestedLPtoOriginalLP(NestedLPads), - DT(DT), EHBlocks(EHBlocks) {} - - CloningAction handleBeginCatch(ValueToValueMapTy &VMap, - const Instruction *Inst, - BasicBlock *NewBB) override; - CloningAction handleEndCatch(ValueToValueMapTy &VMap, const Instruction *Inst, - BasicBlock *NewBB) override; - CloningAction handleTypeIdFor(ValueToValueMapTy &VMap, - const Instruction *Inst, - BasicBlock *NewBB) override; - CloningAction handleIndirectBr(ValueToValueMapTy &VMap, - const IndirectBrInst *IBr, - BasicBlock *NewBB) override; - CloningAction handleInvoke(ValueToValueMapTy &VMap, const InvokeInst *Invoke, - BasicBlock *NewBB) override; - CloningAction handleResume(ValueToValueMapTy &VMap, const ResumeInst *Resume, - BasicBlock *NewBB) override; - CloningAction handleCompare(ValueToValueMapTy &VMap, const CmpInst *Compare, - BasicBlock *NewBB) override; - CloningAction handleLandingPad(ValueToValueMapTy &VMap, - const LandingPadInst *LPad, - BasicBlock *NewBB) override; - - Value *getExceptionVar() { return ExceptionObjectVar; } - TinyPtrVector &getReturnTargets() { return ReturnTargets; } - -private: - Value *CurrentSelector; - - Value *ExceptionObjectVar; - TinyPtrVector ReturnTargets; - - // This will be a reference to the field of the same name in the WinEHPrepare - // object which instantiates this WinEHCatchDirector object. - DenseMap &NestedLPtoOriginalLP; - DominatorTree *DT; - SmallPtrSetImpl &EHBlocks; -}; - -class WinEHCleanupDirector : public WinEHCloningDirectorBase { -public: - WinEHCleanupDirector(Function *CleanupFn, Value *ParentFP, - FrameVarInfoMap &VarInfo, LandingPadMap &LPadMap) - : WinEHCloningDirectorBase(CleanupFn, ParentFP, VarInfo, - LPadMap) {} - - CloningAction handleBeginCatch(ValueToValueMapTy &VMap, - const Instruction *Inst, - BasicBlock *NewBB) override; - CloningAction handleEndCatch(ValueToValueMapTy &VMap, const Instruction *Inst, - BasicBlock *NewBB) override; - CloningAction handleTypeIdFor(ValueToValueMapTy &VMap, - const Instruction *Inst, - BasicBlock *NewBB) override; - CloningAction handleIndirectBr(ValueToValueMapTy &VMap, - const IndirectBrInst *IBr, - BasicBlock *NewBB) override; - CloningAction handleInvoke(ValueToValueMapTy &VMap, const InvokeInst *Invoke, - BasicBlock *NewBB) override; - CloningAction handleResume(ValueToValueMapTy &VMap, const ResumeInst *Resume, - BasicBlock *NewBB) override; - CloningAction handleCompare(ValueToValueMapTy &VMap, const CmpInst *Compare, - BasicBlock *NewBB) override; - CloningAction handleLandingPad(ValueToValueMapTy &VMap, - const LandingPadInst *LPad, - BasicBlock *NewBB) override; -}; - -class LandingPadActions { -public: - LandingPadActions() : HasCleanupHandlers(false) {} - - void insertCatchHandler(CatchHandler *Action) { Actions.push_back(Action); } - void insertCleanupHandler(CleanupHandler *Action) { - Actions.push_back(Action); - HasCleanupHandlers = true; - } - - bool includesCleanup() const { return HasCleanupHandlers; } - - SmallVectorImpl &actions() { return Actions; } - SmallVectorImpl::iterator begin() { return Actions.begin(); } - SmallVectorImpl::iterator end() { return Actions.end(); } - -private: - // Note that this class does not own the ActionHandler objects in this vector. - // The ActionHandlers are owned by the CatchHandlerMap and CleanupHandlerMap - // in the WinEHPrepare class. - SmallVector Actions; - bool HasCleanupHandlers; -}; - } // end anonymous namespace char WinEHPrepare::ID = 0; @@ -399,27 +125,19 @@ FunctionPass *llvm::createWinEHPass(const TargetMachine *TM) { return new WinEHPrepare(TM); } -static bool -findExceptionalConstructs(Function &Fn, - SmallVectorImpl &LPads, - SmallVectorImpl &Resumes, - SmallVectorImpl &EntryBlocks) { - bool ForExplicitEH = false; +static void findFuncletEntryPoints(Function &Fn, + SmallVectorImpl &EntryBlocks) { + EntryBlocks.push_back(&Fn.getEntryBlock()); for (BasicBlock &BB : Fn) { Instruction *First = BB.getFirstNonPHI(); - if (auto *LP = dyn_cast(First)) { - LPads.push_back(LP); - } else if (First->isEHPad()) { - if (!ForExplicitEH) - EntryBlocks.push_back(&Fn.getEntryBlock()); - if (!isa(First) && !isa(First)) - EntryBlocks.push_back(&BB); - ForExplicitEH = true; - } - if (auto *Resume = dyn_cast(BB.getTerminator())) - Resumes.push_back(Resume); + if (!First->isEHPad()) + continue; + assert(!isa(First) && + "landingpad cannot be used with funclet EH personality"); + // Find EH pad blocks that represent funclet start points. + if (!isa(First) && !isa(First)) + EntryBlocks.push_back(&BB); } - return ForExplicitEH; } bool WinEHPrepare::runOnFunction(Function &Fn) { @@ -442,25 +160,9 @@ bool WinEHPrepare::runOnFunction(Function &Fn) { // not. removeUnreachableBlocks(Fn); - SmallVector LPads; - SmallVector Resumes; SmallVector EntryBlocks; - bool ForExplicitEH = - findExceptionalConstructs(Fn, LPads, Resumes, EntryBlocks); - - if (ForExplicitEH) - return prepareExplicitEH(Fn, EntryBlocks); - - // No need to prepare functions that lack landing pads. - if (LPads.empty()) - return false; - - DT = &getAnalysis().getDomTree(); - LibInfo = &getAnalysis().getTLI(); - - // If there were any landing pads, prepareExceptionHandlers will make changes. - prepareExceptionHandlers(Fn, LPads); - return true; + findFuncletEntryPoints(Fn, EntryBlocks); + return prepareExplicitEH(Fn, EntryBlocks); } bool WinEHPrepare::doFinalization(Module &M) { return false; } @@ -470,2140 +172,12 @@ void WinEHPrepare::getAnalysisUsage(AnalysisUsage &AU) const { AU.addRequired(); } -static bool isSelectorDispatch(BasicBlock *BB, BasicBlock *&CatchHandler, - Constant *&Selector, BasicBlock *&NextBB); - -// Finds blocks reachable from the starting set Worklist. Does not follow unwind -// edges or blocks listed in StopPoints. -static void findReachableBlocks(SmallPtrSetImpl &ReachableBBs, - SetVector &Worklist, - const SetVector *StopPoints) { - while (!Worklist.empty()) { - BasicBlock *BB = Worklist.pop_back_val(); - - // Don't cross blocks that we should stop at. - if (StopPoints && StopPoints->count(BB)) - continue; - - if (!ReachableBBs.insert(BB).second) - continue; // Already visited. - - // Don't follow unwind edges of invokes. - if (auto *II = dyn_cast(BB->getTerminator())) { - Worklist.insert(II->getNormalDest()); - continue; - } - - // Otherwise, follow all successors. - Worklist.insert(succ_begin(BB), succ_end(BB)); - } -} - -// Attempt to find an instruction where a block can be split before -// a call to llvm.eh.begincatch and its operands. If the block -// begins with the begincatch call or one of its adjacent operands -// the block will not be split. -static Instruction *findBeginCatchSplitPoint(BasicBlock *BB, - IntrinsicInst *II) { - // If the begincatch call is already the first instruction in the block, - // don't split. - Instruction *FirstNonPHI = BB->getFirstNonPHI(); - if (II == FirstNonPHI) - return nullptr; - - // If either operand is in the same basic block as the instruction and - // isn't used by another instruction before the begincatch call, include it - // in the split block. - auto *Op0 = dyn_cast(II->getOperand(0)); - auto *Op1 = dyn_cast(II->getOperand(1)); - - Instruction *I = II->getPrevNode(); - Instruction *LastI = II; - - while (I == Op0 || I == Op1) { - // If the block begins with one of the operands and there are no other - // instructions between the operand and the begincatch call, don't split. - if (I == FirstNonPHI) - return nullptr; - - LastI = I; - I = I->getPrevNode(); - } - - // If there is at least one instruction in the block before the begincatch - // call and its operands, split the block at either the begincatch or - // its operand. - return LastI; -} - -/// Find all points where exceptional control rejoins normal control flow via -/// llvm.eh.endcatch. Add them to the normal bb reachability worklist. -void WinEHPrepare::findCXXEHReturnPoints( - Function &F, SetVector &EHReturnBlocks) { - for (auto BBI = F.begin(), BBE = F.end(); BBI != BBE; ++BBI) { - BasicBlock *BB = &*BBI; - for (Instruction &I : *BB) { - if (match(&I, m_Intrinsic())) { - Instruction *SplitPt = - findBeginCatchSplitPoint(BB, cast(&I)); - if (SplitPt) { - // Split the block before the llvm.eh.begincatch call to allow - // cleanup and catch code to be distinguished later. - // Do not update BBI because we still need to process the - // portion of the block that we are splitting off. - SplitBlock(BB, SplitPt, DT); - break; - } - } - if (match(&I, m_Intrinsic())) { - // Split the block after the call to llvm.eh.endcatch if there is - // anything other than an unconditional branch, or if the successor - // starts with a phi. - auto *Br = dyn_cast(I.getNextNode()); - if (!Br || !Br->isUnconditional() || - isa(Br->getSuccessor(0)->begin())) { - DEBUG(dbgs() << "splitting block " << BB->getName() - << " with llvm.eh.endcatch\n"); - BBI = SplitBlock(BB, I.getNextNode(), DT)->getIterator(); - } - // The next BB is normal control flow. - EHReturnBlocks.insert(BB->getTerminator()->getSuccessor(0)); - break; - } - } - } -} - -static bool isCatchAllLandingPad(const BasicBlock *BB) { - const LandingPadInst *LP = BB->getLandingPadInst(); - if (!LP) - return false; - unsigned N = LP->getNumClauses(); - return (N > 0 && LP->isCatch(N - 1) && - isa(LP->getClause(N - 1))); -} - -/// Find all points where exceptions control rejoins normal control flow via -/// selector dispatch. -void WinEHPrepare::findSEHEHReturnPoints( - Function &F, SetVector &EHReturnBlocks) { - for (auto BBI = F.begin(), BBE = F.end(); BBI != BBE; ++BBI) { - BasicBlock *BB = &*BBI; - // If the landingpad is a catch-all, treat the whole lpad as if it is - // reachable from normal control flow. - // FIXME: This is imprecise. We need a better way of identifying where a - // catch-all starts and cleanups stop. As far as LLVM is concerned, there - // is no difference. - if (isCatchAllLandingPad(BB)) { - EHReturnBlocks.insert(BB); - continue; - } - - BasicBlock *CatchHandler; - BasicBlock *NextBB; - Constant *Selector; - if (isSelectorDispatch(BB, CatchHandler, Selector, NextBB)) { - // Split the edge if there are multiple predecessors. This creates a place - // where we can insert EH recovery code. - if (!CatchHandler->getSinglePredecessor()) { - DEBUG(dbgs() << "splitting EH return edge from " << BB->getName() - << " to " << CatchHandler->getName() << '\n'); - CatchHandler = SplitCriticalEdge( - BB, std::find(succ_begin(BB), succ_end(BB), CatchHandler)); - BBI = CatchHandler->getIterator(); - } - EHReturnBlocks.insert(CatchHandler); - } - } -} - -void WinEHPrepare::identifyEHBlocks(Function &F, - SmallVectorImpl &LPads) { - DEBUG(dbgs() << "Demoting values live across exception handlers in function " - << F.getName() << '\n'); - - // Build a set of all non-exceptional blocks and exceptional blocks. - // - Non-exceptional blocks are blocks reachable from the entry block while - // not following invoke unwind edges. - // - Exceptional blocks are blocks reachable from landingpads. Analysis does - // not follow llvm.eh.endcatch blocks, which mark a transition from - // exceptional to normal control. - - if (Personality == EHPersonality::MSVC_CXX) - findCXXEHReturnPoints(F, EHReturnBlocks); - else - findSEHEHReturnPoints(F, EHReturnBlocks); - - DEBUG({ - dbgs() << "identified the following blocks as EH return points:\n"; - for (BasicBlock *BB : EHReturnBlocks) - dbgs() << " " << BB->getName() << '\n'; - }); - -// Join points should not have phis at this point, unless they are a -// landingpad, in which case we will demote their phis later. -#ifndef NDEBUG - for (BasicBlock *BB : EHReturnBlocks) - assert((BB->isLandingPad() || !isa(BB->begin())) && - "non-lpad EH return block has phi"); -#endif - - // Normal blocks are the blocks reachable from the entry block and all EH - // return points. - SetVector Worklist; - Worklist = EHReturnBlocks; - Worklist.insert(&F.getEntryBlock()); - findReachableBlocks(NormalBlocks, Worklist, nullptr); - DEBUG({ - dbgs() << "marked the following blocks as normal:\n"; - for (BasicBlock *BB : NormalBlocks) - dbgs() << " " << BB->getName() << '\n'; - }); - - // Exceptional blocks are the blocks reachable from landingpads that don't - // cross EH return points. - Worklist.clear(); - for (auto *LPI : LPads) - Worklist.insert(LPI->getParent()); - findReachableBlocks(EHBlocks, Worklist, &EHReturnBlocks); - DEBUG({ - dbgs() << "marked the following blocks as exceptional:\n"; - for (BasicBlock *BB : EHBlocks) - dbgs() << " " << BB->getName() << '\n'; - }); - -} - -/// Ensure that all values live into and out of exception handlers are stored -/// in memory. -/// FIXME: This falls down when values are defined in one handler and live into -/// another handler. For example, a cleanup defines a value used only by a -/// catch handler. -void WinEHPrepare::demoteValuesLiveAcrossHandlers( - Function &F, SmallVectorImpl &LPads) { - DEBUG(dbgs() << "Demoting values live across exception handlers in function " - << F.getName() << '\n'); - - // identifyEHBlocks() should have been called before this function. - assert(!NormalBlocks.empty()); - - // Try to avoid demoting EH pointer and selector values. They get in the way - // of our pattern matching. - SmallPtrSet EHVals; - for (BasicBlock &BB : F) { - LandingPadInst *LP = BB.getLandingPadInst(); - if (!LP) - continue; - EHVals.insert(LP); - for (User *U : LP->users()) { - auto *EI = dyn_cast(U); - if (!EI) - continue; - EHVals.insert(EI); - for (User *U2 : EI->users()) { - if (auto *PN = dyn_cast(U2)) - EHVals.insert(PN); - } - } - } - - SetVector ArgsToDemote; - SetVector InstrsToDemote; - for (BasicBlock &BB : F) { - bool IsNormalBB = NormalBlocks.count(&BB); - bool IsEHBB = EHBlocks.count(&BB); - if (!IsNormalBB && !IsEHBB) - continue; // Blocks that are neither normal nor EH are unreachable. - for (Instruction &I : BB) { - for (Value *Op : I.operands()) { - // Don't demote static allocas, constants, and labels. - if (isa(Op) || isa(Op) || isa(Op)) - continue; - auto *AI = dyn_cast(Op); - if (AI && AI->isStaticAlloca()) - continue; - - if (auto *Arg = dyn_cast(Op)) { - if (IsEHBB) { - DEBUG(dbgs() << "Demoting argument " << *Arg - << " used by EH instr: " << I << "\n"); - ArgsToDemote.insert(Arg); - } - continue; - } - - // Don't demote EH values. - auto *OpI = cast(Op); - if (EHVals.count(OpI)) - continue; - - BasicBlock *OpBB = OpI->getParent(); - // If a value is produced and consumed in the same BB, we don't need to - // demote it. - if (OpBB == &BB) - continue; - bool IsOpNormalBB = NormalBlocks.count(OpBB); - bool IsOpEHBB = EHBlocks.count(OpBB); - if (IsNormalBB != IsOpNormalBB || IsEHBB != IsOpEHBB) { - DEBUG({ - dbgs() << "Demoting instruction live in-out from EH:\n"; - dbgs() << "Instr: " << *OpI << '\n'; - dbgs() << "User: " << I << '\n'; - }); - InstrsToDemote.insert(OpI); - } - } - } - } - - // Demote values live into and out of handlers. - // FIXME: This demotion is inefficient. We should insert spills at the point - // of definition, insert one reload in each handler that uses the value, and - // insert reloads in the BB used to rejoin normal control flow. - Instruction *AllocaInsertPt = &*F.getEntryBlock().getFirstInsertionPt(); - for (Instruction *I : InstrsToDemote) - DemoteRegToStack(*I, false, AllocaInsertPt); - - // Demote arguments separately, and only for uses in EH blocks. - for (Argument *Arg : ArgsToDemote) { - auto *Slot = new AllocaInst(Arg->getType(), nullptr, - Arg->getName() + ".reg2mem", AllocaInsertPt); - SmallVector Users(Arg->user_begin(), Arg->user_end()); - for (User *U : Users) { - auto *I = dyn_cast(U); - if (I && EHBlocks.count(I->getParent())) { - auto *Reload = new LoadInst(Slot, Arg->getName() + ".reload", false, I); - U->replaceUsesOfWith(Arg, Reload); - } - } - new StoreInst(Arg, Slot, AllocaInsertPt); - } - - // Demote landingpad phis, as the landingpad will be removed from the machine - // CFG. - for (LandingPadInst *LPI : LPads) { - BasicBlock *BB = LPI->getParent(); - while (auto *Phi = dyn_cast(BB->begin())) - DemotePHIToStack(Phi, AllocaInsertPt); - } - - DEBUG(dbgs() << "Demoted " << InstrsToDemote.size() << " instructions and " - << ArgsToDemote.size() << " arguments for WinEHPrepare\n\n"); -} - -bool WinEHPrepare::prepareExceptionHandlers( - Function &F, SmallVectorImpl &LPads) { - // Don't run on functions that are already prepared. - for (LandingPadInst *LPad : LPads) { - BasicBlock *LPadBB = LPad->getParent(); - for (Instruction &Inst : *LPadBB) - if (match(&Inst, m_Intrinsic())) - return false; - } - - identifyEHBlocks(F, LPads); - demoteValuesLiveAcrossHandlers(F, LPads); - - // These containers are used to re-map frame variables that are used in - // outlined catch and cleanup handlers. They will be populated as the - // handlers are outlined. - FrameVarInfoMap FrameVarInfo; - - bool HandlersOutlined = false; - - Module *M = F.getParent(); - LLVMContext &Context = M->getContext(); - - // Create a new function to receive the handler contents. - PointerType *Int8PtrType = Type::getInt8PtrTy(Context); - Type *Int32Type = Type::getInt32Ty(Context); - Function *ActionIntrin = Intrinsic::getDeclaration(M, Intrinsic::eh_actions); - - if (isAsynchronousEHPersonality(Personality)) { - // FIXME: Switch the ehptr type to i32 and then switch this. - SEHExceptionCodeSlot = - new AllocaInst(Int8PtrType, nullptr, "seh_exception_code", - &*F.getEntryBlock().getFirstInsertionPt()); - } - - // In order to handle the case where one outlined catch handler returns - // to a block within another outlined catch handler that would otherwise - // be unreachable, we need to outline the nested landing pad before we - // outline the landing pad which encloses it. - if (!isAsynchronousEHPersonality(Personality)) - std::sort(LPads.begin(), LPads.end(), - [this](LandingPadInst *const &L, LandingPadInst *const &R) { - return DT->properlyDominates(R->getParent(), L->getParent()); - }); - - // This container stores the llvm.eh.recover and IndirectBr instructions - // that make up the body of each landing pad after it has been outlined. - // We need to defer the population of the target list for the indirectbr - // until all landing pads have been outlined so that we can handle the - // case of blocks in the target that are reached only from nested - // landing pads. - SmallVector, 4> LPadImpls; - - for (LandingPadInst *LPad : LPads) { - // Look for evidence that this landingpad has already been processed. - bool LPadHasActionList = false; - BasicBlock *LPadBB = LPad->getParent(); - for (Instruction &Inst : *LPadBB) { - if (match(&Inst, m_Intrinsic())) { - LPadHasActionList = true; - break; - } - } - - // If we've already outlined the handlers for this landingpad, - // there's nothing more to do here. - if (LPadHasActionList) - continue; - - // If either of the values in the aggregate returned by the landing pad is - // extracted and stored to memory, promote the stored value to a register. - promoteLandingPadValues(LPad); - - LandingPadActions Actions; - mapLandingPadBlocks(LPad, Actions); - - HandlersOutlined |= !Actions.actions().empty(); - for (ActionHandler *Action : Actions) { - if (Action->hasBeenProcessed()) - continue; - BasicBlock *StartBB = Action->getStartBlock(); - - // SEH doesn't do any outlining for catches. Instead, pass the handler - // basic block addr to llvm.eh.actions and list the block as a return - // target. - if (isAsynchronousEHPersonality(Personality)) { - if (auto *CatchAction = dyn_cast(Action)) { - processSEHCatchHandler(CatchAction, StartBB); - continue; - } - } - - outlineHandler(Action, &F, LPad, StartBB, FrameVarInfo); - } - - // Split the block after the landingpad instruction so that it is just a - // call to llvm.eh.actions followed by indirectbr. - assert(!isa(LPadBB->begin()) && "lpad phi not removed"); - SplitBlock(LPadBB, LPad->getNextNode(), DT); - // Erase the branch inserted by the split so we can insert indirectbr. - LPadBB->getTerminator()->eraseFromParent(); - - // Replace all extracted values with undef and ultimately replace the - // landingpad with undef. - SmallVector SEHCodeUses; - SmallVector EHUndefs; - for (User *U : LPad->users()) { - auto *E = dyn_cast(U); - if (!E) - continue; - assert(E->getNumIndices() == 1 && - "Unexpected operation: extracting both landing pad values"); - unsigned Idx = *E->idx_begin(); - assert((Idx == 0 || Idx == 1) && "unexpected index"); - if (Idx == 0 && isAsynchronousEHPersonality(Personality)) - SEHCodeUses.push_back(E); - else - EHUndefs.push_back(E); - } - for (Instruction *E : EHUndefs) { - E->replaceAllUsesWith(UndefValue::get(E->getType())); - E->eraseFromParent(); - } - LPad->replaceAllUsesWith(UndefValue::get(LPad->getType())); - - // Rewrite uses of the exception pointer to loads of an alloca. - while (!SEHCodeUses.empty()) { - Instruction *E = SEHCodeUses.pop_back_val(); - SmallVector Uses; - for (Use &U : E->uses()) - Uses.push_back(&U); - for (Use *U : Uses) { - auto *I = cast(U->getUser()); - if (isa(I)) - continue; - if (auto *Phi = dyn_cast(I)) - SEHCodeUses.push_back(Phi); - else - U->set(new LoadInst(SEHExceptionCodeSlot, "sehcode", false, I)); - } - E->replaceAllUsesWith(UndefValue::get(E->getType())); - E->eraseFromParent(); - } - - // Add a call to describe the actions for this landing pad. - std::vector ActionArgs; - for (ActionHandler *Action : Actions) { - // Action codes from docs are: 0 cleanup, 1 catch. - if (auto *CatchAction = dyn_cast(Action)) { - ActionArgs.push_back(ConstantInt::get(Int32Type, 1)); - ActionArgs.push_back(CatchAction->getSelector()); - // Find the frame escape index of the exception object alloca in the - // parent. - int FrameEscapeIdx = -1; - Value *EHObj = const_cast(CatchAction->getExceptionVar()); - if (EHObj && !isa(EHObj)) { - auto I = FrameVarInfo.find(EHObj); - assert(I != FrameVarInfo.end() && - "failed to map llvm.eh.begincatch var"); - FrameEscapeIdx = std::distance(FrameVarInfo.begin(), I); - } - ActionArgs.push_back(ConstantInt::get(Int32Type, FrameEscapeIdx)); - } else { - ActionArgs.push_back(ConstantInt::get(Int32Type, 0)); - } - ActionArgs.push_back(Action->getHandlerBlockOrFunc()); - } - CallInst *Recover = - CallInst::Create(ActionIntrin, ActionArgs, "recover", LPadBB); - - SetVector ReturnTargets; - for (ActionHandler *Action : Actions) { - if (auto *CatchAction = dyn_cast(Action)) { - const auto &CatchTargets = CatchAction->getReturnTargets(); - ReturnTargets.insert(CatchTargets.begin(), CatchTargets.end()); - } - } - IndirectBrInst *Branch = - IndirectBrInst::Create(Recover, ReturnTargets.size(), LPadBB); - for (BasicBlock *Target : ReturnTargets) - Branch->addDestination(Target); - - if (!isAsynchronousEHPersonality(Personality)) { - // C++ EH must repopulate the targets later to handle the case of - // targets that are reached indirectly through nested landing pads. - LPadImpls.push_back(std::make_pair(Recover, Branch)); - } - - } // End for each landingpad - - // If nothing got outlined, there is no more processing to be done. - if (!HandlersOutlined) - return false; - - // Replace any nested landing pad stubs with the correct action handler. - // This must be done before we remove unreachable blocks because it - // cleans up references to outlined blocks that will be deleted. - for (auto &LPadPair : NestedLPtoOriginalLP) - completeNestedLandingPad(&F, LPadPair.first, LPadPair.second, FrameVarInfo); - NestedLPtoOriginalLP.clear(); - - // Update the indirectbr instructions' target lists if necessary. - SetVector CheckedTargets; - SmallVector, 4> ActionList; - for (auto &LPadImplPair : LPadImpls) { - IntrinsicInst *Recover = cast(LPadImplPair.first); - IndirectBrInst *Branch = LPadImplPair.second; - - // Get a list of handlers called by - parseEHActions(Recover, ActionList); - - // Add an indirect branch listing possible successors of the catch handlers. - SetVector ReturnTargets; - for (const auto &Action : ActionList) { - if (auto *CA = dyn_cast(Action.get())) { - Function *Handler = cast(CA->getHandlerBlockOrFunc()); - getPossibleReturnTargets(&F, Handler, ReturnTargets); - } - } - ActionList.clear(); - // Clear any targets we already knew about. - for (unsigned int I = 0, E = Branch->getNumDestinations(); I < E; ++I) { - BasicBlock *KnownTarget = Branch->getDestination(I); - if (ReturnTargets.count(KnownTarget)) - ReturnTargets.remove(KnownTarget); - } - for (BasicBlock *Target : ReturnTargets) { - Branch->addDestination(Target); - // The target may be a block that we excepted to get pruned. - // If it is, it may contain a call to llvm.eh.endcatch. - if (CheckedTargets.insert(Target)) { - // Earlier preparations guarantee that all calls to llvm.eh.endcatch - // will be followed by an unconditional branch. - auto *Br = dyn_cast(Target->getTerminator()); - if (Br && Br->isUnconditional() && - Br != Target->getFirstNonPHIOrDbgOrLifetime()) { - Instruction *Prev = Br->getPrevNode(); - if (match(cast(Prev), m_Intrinsic())) - Prev->eraseFromParent(); - } - } - } - } - LPadImpls.clear(); - - F.addFnAttr("wineh-parent", F.getName()); - - // Delete any blocks that were only used by handlers that were outlined above. - removeUnreachableBlocks(F); - - BasicBlock *Entry = &F.getEntryBlock(); - IRBuilder<> Builder(F.getParent()->getContext()); - Builder.SetInsertPoint(Entry, Entry->getFirstInsertionPt()); - - Function *FrameEscapeFn = - Intrinsic::getDeclaration(M, Intrinsic::localescape); - Function *RecoverFrameFn = - Intrinsic::getDeclaration(M, Intrinsic::localrecover); - SmallVector AllocasToEscape; - - // Scan the entry block for an existing call to llvm.localescape. We need to - // keep escaping those objects. - for (Instruction &I : F.front()) { - auto *II = dyn_cast(&I); - if (II && II->getIntrinsicID() == Intrinsic::localescape) { - auto Args = II->arg_operands(); - AllocasToEscape.append(Args.begin(), Args.end()); - II->eraseFromParent(); - break; - } - } - - // Finally, replace all of the temporary allocas for frame variables used in - // the outlined handlers with calls to llvm.localrecover. - for (auto &VarInfoEntry : FrameVarInfo) { - Value *ParentVal = VarInfoEntry.first; - TinyPtrVector &Allocas = VarInfoEntry.second; - AllocaInst *ParentAlloca = cast(ParentVal); - - // FIXME: We should try to sink unescaped allocas from the parent frame into - // the child frame. If the alloca is escaped, we have to use the lifetime - // markers to ensure that the alloca is only live within the child frame. - - // Add this alloca to the list of things to escape. - AllocasToEscape.push_back(ParentAlloca); - - // Next replace all outlined allocas that are mapped to it. - for (AllocaInst *TempAlloca : Allocas) { - if (TempAlloca == getCatchObjectSentinel()) - continue; // Skip catch parameter sentinels. - Function *HandlerFn = TempAlloca->getParent()->getParent(); - llvm::Value *FP = HandlerToParentFP[HandlerFn]; - assert(FP); - - // FIXME: Sink this localrecover into the blocks where it is used. - Builder.SetInsertPoint(TempAlloca); - Builder.SetCurrentDebugLocation(TempAlloca->getDebugLoc()); - Value *RecoverArgs[] = { - Builder.CreateBitCast(&F, Int8PtrType, ""), FP, - llvm::ConstantInt::get(Int32Type, AllocasToEscape.size() - 1)}; - Instruction *RecoveredAlloca = - Builder.CreateCall(RecoverFrameFn, RecoverArgs); - - // Add a pointer bitcast if the alloca wasn't an i8. - if (RecoveredAlloca->getType() != TempAlloca->getType()) { - RecoveredAlloca->setName(Twine(TempAlloca->getName()) + ".i8"); - RecoveredAlloca = cast( - Builder.CreateBitCast(RecoveredAlloca, TempAlloca->getType())); - } - TempAlloca->replaceAllUsesWith(RecoveredAlloca); - TempAlloca->removeFromParent(); - RecoveredAlloca->takeName(TempAlloca); - delete TempAlloca; - } - } // End for each FrameVarInfo entry. - - // Insert 'call void (...)* @llvm.localescape(...)' at the end of the entry - // block. - Builder.SetInsertPoint(&F.getEntryBlock().back()); - Builder.CreateCall(FrameEscapeFn, AllocasToEscape); - - if (SEHExceptionCodeSlot) { - if (isAllocaPromotable(SEHExceptionCodeSlot)) { - SmallPtrSet UserBlocks; - for (User *U : SEHExceptionCodeSlot->users()) { - if (auto *Inst = dyn_cast(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 - DeleteContainerSeconds(CatchHandlerMap); - CatchHandlerMap.clear(); - DeleteContainerSeconds(CleanupHandlerMap); - CleanupHandlerMap.clear(); - HandlerToParentFP.clear(); - DT = nullptr; - LibInfo = nullptr; - SEHExceptionCodeSlot = nullptr; - EHBlocks.clear(); - NormalBlocks.clear(); - EHReturnBlocks.clear(); - - return HandlersOutlined; -} - -void WinEHPrepare::promoteLandingPadValues(LandingPadInst *LPad) { - // If the return values of the landing pad instruction are extracted and - // stored to memory, we want to promote the store locations to reg values. - SmallVector EHAllocas; - - // The landingpad instruction returns an aggregate value. Typically, its - // value will be passed to a pair of extract value instructions and the - // results of those extracts are often passed to store instructions. - // In unoptimized code the stored value will often be loaded and then stored - // again. - for (auto *U : LPad->users()) { - ExtractValueInst *Extract = dyn_cast(U); - if (!Extract) - continue; - - for (auto *EU : Extract->users()) { - if (auto *Store = dyn_cast(EU)) { - auto *AV = cast(Store->getPointerOperand()); - EHAllocas.push_back(AV); - } - } - } - - // We can't do this without a dominator tree. - assert(DT); - - if (!EHAllocas.empty()) { - PromoteMemToReg(EHAllocas, *DT); - EHAllocas.clear(); - } - - // After promotion, some extracts may be trivially dead. Remove them. - SmallVector Users(LPad->user_begin(), LPad->user_end()); - for (auto *U : Users) - RecursivelyDeleteTriviallyDeadInstructions(U); -} - -void WinEHPrepare::getPossibleReturnTargets(Function *ParentF, - Function *HandlerF, - SetVector &Targets) { - for (BasicBlock &BB : *HandlerF) { - // If the handler contains landing pads, check for any - // handlers that may return directly to a block in the - // parent function. - if (auto *LPI = BB.getLandingPadInst()) { - IntrinsicInst *Recover = cast(LPI->getNextNode()); - SmallVector, 4> ActionList; - parseEHActions(Recover, ActionList); - for (const auto &Action : ActionList) { - if (auto *CH = dyn_cast(Action.get())) { - Function *NestedF = cast(CH->getHandlerBlockOrFunc()); - getPossibleReturnTargets(ParentF, NestedF, Targets); - } - } - } - - auto *Ret = dyn_cast(BB.getTerminator()); - if (!Ret) - continue; - - // Handler functions must always return a block address. - BlockAddress *BA = cast(Ret->getReturnValue()); - - // If this is the handler for a nested landing pad, the - // return address may have been remapped to a block in the - // parent handler. We're not interested in those. - if (BA->getFunction() != ParentF) - continue; - - Targets.insert(BA->getBasicBlock()); - } -} - -void WinEHPrepare::completeNestedLandingPad(Function *ParentFn, - LandingPadInst *OutlinedLPad, - const LandingPadInst *OriginalLPad, - FrameVarInfoMap &FrameVarInfo) { - // Get the nested block and erase the unreachable instruction that was - // temporarily inserted as its terminator. - LLVMContext &Context = ParentFn->getContext(); - BasicBlock *OutlinedBB = OutlinedLPad->getParent(); - // If the nested landing pad was outlined before the landing pad that enclosed - // it, it will already be in outlined form. In that case, we just need to see - // if the returns and the enclosing branch instruction need to be updated. - IndirectBrInst *Branch = - dyn_cast(OutlinedBB->getTerminator()); - if (!Branch) { - // If the landing pad wasn't in outlined form, it should be a stub with - // an unreachable terminator. - assert(isa(OutlinedBB->getTerminator())); - OutlinedBB->getTerminator()->eraseFromParent(); - // That should leave OutlinedLPad as the last instruction in its block. - assert(&OutlinedBB->back() == OutlinedLPad); - } - - // The original landing pad will have already had its action intrinsic - // built by the outlining loop. We need to clone that into the outlined - // location. It may also be necessary to add references to the exception - // variables to the outlined handler in which this landing pad is nested - // and remap return instructions in the nested handlers that should return - // to an address in the outlined handler. - Function *OutlinedHandlerFn = OutlinedBB->getParent(); - BasicBlock::const_iterator II = OriginalLPad->getIterator(); - ++II; - // The instruction after the landing pad should now be a call to eh.actions. - const Instruction *Recover = &*II; - const IntrinsicInst *EHActions = cast(Recover); - - // Remap the return target in the nested handler. - SmallVector ActionTargets; - SmallVector, 4> ActionList; - parseEHActions(EHActions, ActionList); - for (const auto &Action : ActionList) { - auto *Catch = dyn_cast(Action.get()); - if (!Catch) - continue; - // The dyn_cast to function here selects C++ catch handlers and skips - // SEH catch handlers. - auto *Handler = dyn_cast(Catch->getHandlerBlockOrFunc()); - if (!Handler) - continue; - // Visit all the return instructions, looking for places that return - // to a location within OutlinedHandlerFn. - for (BasicBlock &NestedHandlerBB : *Handler) { - auto *Ret = dyn_cast(NestedHandlerBB.getTerminator()); - if (!Ret) - continue; - - // Handler functions must always return a block address. - BlockAddress *BA = cast(Ret->getReturnValue()); - // The original target will have been in the main parent function, - // but if it is the address of a block that has been outlined, it - // should be a block that was outlined into OutlinedHandlerFn. - assert(BA->getFunction() == ParentFn); - - // Ignore targets that aren't part of an outlined handler function. - if (!LPadTargetBlocks.count(BA->getBasicBlock())) - continue; - - // If the return value is the address ofF a block that we - // previously outlined into the parent handler function, replace - // the return instruction and add the mapped target to the list - // of possible return addresses. - BasicBlock *MappedBB = LPadTargetBlocks[BA->getBasicBlock()]; - assert(MappedBB->getParent() == OutlinedHandlerFn); - BlockAddress *NewBA = BlockAddress::get(OutlinedHandlerFn, MappedBB); - Ret->eraseFromParent(); - ReturnInst::Create(Context, NewBA, &NestedHandlerBB); - ActionTargets.push_back(NewBA); - } - } - ActionList.clear(); - - if (Branch) { - // If the landing pad was already in outlined form, just update its targets. - for (unsigned int I = Branch->getNumDestinations(); I > 0; --I) - Branch->removeDestination(I); - // Add the previously collected action targets. - for (auto *Target : ActionTargets) - Branch->addDestination(Target->getBasicBlock()); - } else { - // If the landing pad was previously stubbed out, fill in its outlined form. - IntrinsicInst *NewEHActions = cast(EHActions->clone()); - OutlinedBB->getInstList().push_back(NewEHActions); - - // Insert an indirect branch into the outlined landing pad BB. - IndirectBrInst *IBr = IndirectBrInst::Create(NewEHActions, 0, OutlinedBB); - // Add the previously collected action targets. - for (auto *Target : ActionTargets) - IBr->addDestination(Target->getBasicBlock()); - } -} - -// This function examines a block to determine whether the block ends with a -// conditional branch to a catch handler based on a selector comparison. -// This function is used both by the WinEHPrepare::findSelectorComparison() and -// WinEHCleanupDirector::handleTypeIdFor(). -static bool isSelectorDispatch(BasicBlock *BB, BasicBlock *&CatchHandler, - Constant *&Selector, BasicBlock *&NextBB) { - ICmpInst::Predicate Pred; - BasicBlock *TBB, *FBB; - Value *LHS, *RHS; - - if (!match(BB->getTerminator(), - m_Br(m_ICmp(Pred, m_Value(LHS), m_Value(RHS)), TBB, FBB))) - return false; - - if (!match(LHS, - m_Intrinsic(m_Constant(Selector))) && - !match(RHS, m_Intrinsic(m_Constant(Selector)))) - return false; - - if (Pred == CmpInst::ICMP_EQ) { - CatchHandler = TBB; - NextBB = FBB; - return true; - } - - if (Pred == CmpInst::ICMP_NE) { - CatchHandler = FBB; - NextBB = TBB; - return true; - } - - return false; -} - -static bool isCatchBlock(BasicBlock *BB) { - for (BasicBlock::iterator II = BB->getFirstNonPHIOrDbg()->getIterator(), - IE = BB->end(); - II != IE; ++II) { - if (match(cast(II), m_Intrinsic())) - return true; - } - return false; -} - -static BasicBlock *createStubLandingPad(Function *Handler) { - // FIXME: Finish this! - LLVMContext &Context = Handler->getContext(); - BasicBlock *StubBB = BasicBlock::Create(Context, "stub"); - Handler->getBasicBlockList().push_back(StubBB); - IRBuilder<> Builder(StubBB); - LandingPadInst *LPad = Builder.CreateLandingPad( - llvm::StructType::get(Type::getInt8PtrTy(Context), - Type::getInt32Ty(Context), nullptr), - 0); - // Insert a call to llvm.eh.actions so that we don't try to outline this lpad. - Function *ActionIntrin = - Intrinsic::getDeclaration(Handler->getParent(), Intrinsic::eh_actions); - Builder.CreateCall(ActionIntrin, {}, "recover"); - LPad->setCleanup(true); - Builder.CreateUnreachable(); - return StubBB; -} - -// Cycles through the blocks in an outlined handler function looking for an -// invoke instruction and inserts an invoke of llvm.donothing with an empty -// landing pad if none is found. The code that generates the .xdata tables for -// the handler needs at least one landing pad to identify the parent function's -// personality. -void WinEHPrepare::addStubInvokeToHandlerIfNeeded(Function *Handler) { - ReturnInst *Ret = nullptr; - UnreachableInst *Unreached = nullptr; - for (BasicBlock &BB : *Handler) { - TerminatorInst *Terminator = BB.getTerminator(); - // If we find an invoke, there is nothing to be done. - auto *II = dyn_cast(Terminator); - if (II) - return; - // If we've already recorded a return instruction, keep looking for invokes. - if (!Ret) - Ret = dyn_cast(Terminator); - // If we haven't recorded an unreachable instruction, try this terminator. - if (!Unreached) - Unreached = dyn_cast(Terminator); - } - - // If we got this far, the handler contains no invokes. We should have seen - // at least one return or unreachable instruction. We'll insert an invoke of - // llvm.donothing ahead of that instruction. - assert(Ret || Unreached); - TerminatorInst *Term; - if (Ret) - Term = Ret; - else - Term = Unreached; - BasicBlock *OldRetBB = Term->getParent(); - BasicBlock *NewRetBB = SplitBlock(OldRetBB, Term, DT); - // SplitBlock adds an unconditional branch instruction at the end of the - // parent block. We want to replace that with an invoke call, so we can - // erase it now. - OldRetBB->getTerminator()->eraseFromParent(); - BasicBlock *StubLandingPad = createStubLandingPad(Handler); - Function *F = - Intrinsic::getDeclaration(Handler->getParent(), Intrinsic::donothing); - InvokeInst::Create(F, NewRetBB, StubLandingPad, None, "", OldRetBB); -} - -// FIXME: Consider sinking this into lib/Target/X86 somehow. TargetLowering -// usually doesn't build LLVM IR, so that's probably the wrong place. -Function *WinEHPrepare::createHandlerFunc(Function *ParentFn, Type *RetTy, - const Twine &Name, Module *M, - Value *&ParentFP) { - // x64 uses a two-argument prototype where the parent FP is the second - // argument. x86 uses no arguments, just the incoming EBP value. - LLVMContext &Context = M->getContext(); - Type *Int8PtrType = Type::getInt8PtrTy(Context); - FunctionType *FnType; - if (TheTriple.getArch() == Triple::x86_64) { - Type *ArgTys[2] = {Int8PtrType, Int8PtrType}; - FnType = FunctionType::get(RetTy, ArgTys, false); - } else { - FnType = FunctionType::get(RetTy, None, false); - } - - Function *Handler = - Function::Create(FnType, GlobalVariable::InternalLinkage, Name, M); - BasicBlock *Entry = BasicBlock::Create(Context, "entry"); - Handler->getBasicBlockList().push_front(Entry); - if (TheTriple.getArch() == Triple::x86_64) { - ParentFP = &(Handler->getArgumentList().back()); - } else { - assert(M); - Function *FrameAddressFn = - Intrinsic::getDeclaration(M, Intrinsic::frameaddress); - Function *RecoverFPFn = - Intrinsic::getDeclaration(M, Intrinsic::x86_seh_recoverfp); - IRBuilder<> Builder(&Handler->getEntryBlock()); - Value *EBP = - Builder.CreateCall(FrameAddressFn, {Builder.getInt32(1)}, "ebp"); - Value *ParentI8Fn = Builder.CreateBitCast(ParentFn, Int8PtrType); - ParentFP = Builder.CreateCall(RecoverFPFn, {ParentI8Fn, EBP}); - } - return Handler; -} - -bool WinEHPrepare::outlineHandler(ActionHandler *Action, Function *SrcFn, - LandingPadInst *LPad, BasicBlock *StartBB, - FrameVarInfoMap &VarInfo) { - Module *M = SrcFn->getParent(); - LLVMContext &Context = M->getContext(); - Type *Int8PtrType = Type::getInt8PtrTy(Context); - - // Create a new function to receive the handler contents. - Value *ParentFP; - Function *Handler; - if (Action->getType() == Catch) { - Handler = createHandlerFunc(SrcFn, Int8PtrType, SrcFn->getName() + ".catch", M, - ParentFP); - } else { - Handler = createHandlerFunc(SrcFn, Type::getVoidTy(Context), - SrcFn->getName() + ".cleanup", M, ParentFP); - } - Handler->setPersonalityFn(SrcFn->getPersonalityFn()); - HandlerToParentFP[Handler] = ParentFP; - Handler->addFnAttr("wineh-parent", SrcFn->getName()); - BasicBlock *Entry = &Handler->getEntryBlock(); - - // Generate a standard prolog to setup the frame recovery structure. - IRBuilder<> Builder(Context); - Builder.SetInsertPoint(Entry); - Builder.SetCurrentDebugLocation(LPad->getDebugLoc()); - - std::unique_ptr Director; - - ValueToValueMapTy VMap; - - LandingPadMap &LPadMap = LPadMaps[LPad]; - if (!LPadMap.isInitialized()) - LPadMap.mapLandingPad(LPad); - if (auto *CatchAction = dyn_cast(Action)) { - Constant *Sel = CatchAction->getSelector(); - Director.reset(new WinEHCatchDirector(Handler, ParentFP, Sel, VarInfo, - LPadMap, NestedLPtoOriginalLP, DT, - EHBlocks)); - LPadMap.remapEHValues(VMap, UndefValue::get(Int8PtrType), - ConstantInt::get(Type::getInt32Ty(Context), 1)); - } else { - Director.reset( - new WinEHCleanupDirector(Handler, ParentFP, VarInfo, LPadMap)); - LPadMap.remapEHValues(VMap, UndefValue::get(Int8PtrType), - UndefValue::get(Type::getInt32Ty(Context))); - } - - SmallVector Returns; - ClonedCodeInfo OutlinedFunctionInfo; - - // If the start block contains PHI nodes, we need to map them. - BasicBlock::iterator II = StartBB->begin(); - while (auto *PN = dyn_cast(II)) { - bool Mapped = false; - // Look for PHI values that we have already mapped (such as the selector). - for (Value *Val : PN->incoming_values()) { - if (VMap.count(Val)) { - VMap[PN] = VMap[Val]; - Mapped = true; - } - } - // If we didn't find a match for this value, map it as an undef. - if (!Mapped) { - VMap[PN] = UndefValue::get(PN->getType()); - } - ++II; - } - - // The landing pad value may be used by PHI nodes. It will ultimately be - // eliminated, but we need it in the map for intermediate handling. - VMap[LPad] = UndefValue::get(LPad->getType()); - - // Skip over PHIs and, if applicable, landingpad instructions. - II = StartBB->getFirstInsertionPt(); - - CloneAndPruneIntoFromInst(Handler, SrcFn, &*II, VMap, - /*ModuleLevelChanges=*/false, Returns, "", - &OutlinedFunctionInfo, Director.get()); - - // Move all the instructions in the cloned "entry" block into our entry block. - // Depending on how the parent function was laid out, the block that will - // correspond to the outlined entry block may not be the first block in the - // list. We can recognize it, however, as the cloned block which has no - // predecessors. Any other block wouldn't have been cloned if it didn't - // have a predecessor which was also cloned. - Function::iterator ClonedIt = std::next(Function::iterator(Entry)); - while (!pred_empty(&*ClonedIt)) - ++ClonedIt; - assert(ClonedIt != Entry->getParent()->end()); - BasicBlock *ClonedEntryBB = &*ClonedIt; - Entry->getInstList().splice(Entry->end(), ClonedEntryBB->getInstList()); - ClonedEntryBB->eraseFromParent(); - - // Make sure we can identify the handler's personality later. - addStubInvokeToHandlerIfNeeded(Handler); - - if (auto *CatchAction = dyn_cast(Action)) { - WinEHCatchDirector *CatchDirector = - reinterpret_cast(Director.get()); - CatchAction->setExceptionVar(CatchDirector->getExceptionVar()); - CatchAction->setReturnTargets(CatchDirector->getReturnTargets()); - - // Look for blocks that are not part of the landing pad that we just - // outlined but terminate with a call to llvm.eh.endcatch and a - // branch to a block that is in the handler we just outlined. - // These blocks will be part of a nested landing pad that intends to - // return to an address in this handler. This case is best handled - // after both landing pads have been outlined, so for now we'll just - // save the association of the blocks in LPadTargetBlocks. The - // return instructions which are created from these branches will be - // replaced after all landing pads have been outlined. - for (const auto MapEntry : VMap) { - // VMap maps all values and blocks that were just cloned, but dead - // blocks which were pruned will map to nullptr. - if (!isa(MapEntry.first) || MapEntry.second == nullptr) - continue; - const BasicBlock *MappedBB = cast(MapEntry.first); - for (auto *Pred : predecessors(const_cast(MappedBB))) { - auto *Branch = dyn_cast(Pred->getTerminator()); - if (!Branch || !Branch->isUnconditional() || Pred->size() <= 1) - continue; - BasicBlock::iterator II = - const_cast(Branch)->getIterator(); - --II; - if (match(cast(II), m_Intrinsic())) { - // This would indicate that a nested landing pad wants to return - // to a block that is outlined into two different handlers. - assert(!LPadTargetBlocks.count(MappedBB)); - LPadTargetBlocks[MappedBB] = cast(MapEntry.second); - } - } - } - } // End if (CatchAction) - - Action->setHandlerBlockOrFunc(Handler); - - return true; -} - -/// This BB must end in a selector dispatch. All we need to do is pass the -/// handler block to llvm.eh.actions and list it as a possible indirectbr -/// target. -void WinEHPrepare::processSEHCatchHandler(CatchHandler *CatchAction, - BasicBlock *StartBB) { - BasicBlock *HandlerBB; - BasicBlock *NextBB; - Constant *Selector; - bool Res = isSelectorDispatch(StartBB, HandlerBB, Selector, NextBB); - if (Res) { - // If this was EH dispatch, this must be a conditional branch to the handler - // block. - // FIXME: Handle instructions in the dispatch block. Currently we drop them, - // leading to crashes if some optimization hoists stuff here. - assert(CatchAction->getSelector() && HandlerBB && - "expected catch EH dispatch"); - } else { - // This must be a catch-all. Split the block after the landingpad. - assert(CatchAction->getSelector()->isNullValue() && "expected catch-all"); - HandlerBB = SplitBlock(StartBB, &*StartBB->getFirstInsertionPt(), DT); - } - IRBuilder<> Builder(&*HandlerBB->getFirstInsertionPt()); - Function *EHCodeFn = Intrinsic::getDeclaration( - StartBB->getParent()->getParent(), Intrinsic::eh_exceptioncode_old); - Value *Code = Builder.CreateCall(EHCodeFn, {}, "sehcode"); - Code = Builder.CreateIntToPtr(Code, SEHExceptionCodeSlot->getAllocatedType()); - Builder.CreateStore(Code, SEHExceptionCodeSlot); - CatchAction->setHandlerBlockOrFunc(BlockAddress::get(HandlerBB)); - TinyPtrVector Targets(HandlerBB); - CatchAction->setReturnTargets(Targets); -} - -void LandingPadMap::mapLandingPad(const LandingPadInst *LPad) { - // Each instance of this class should only ever be used to map a single - // landing pad. - assert(OriginLPad == nullptr || OriginLPad == LPad); - - // If the landing pad has already been mapped, there's nothing more to do. - if (OriginLPad == LPad) - return; - - OriginLPad = LPad; - - // The landingpad instruction returns an aggregate value. Typically, its - // value will be passed to a pair of extract value instructions and the - // results of those extracts will have been promoted to reg values before - // this routine is called. - for (auto *U : LPad->users()) { - const ExtractValueInst *Extract = dyn_cast(U); - if (!Extract) - continue; - assert(Extract->getNumIndices() == 1 && - "Unexpected operation: extracting both landing pad values"); - unsigned int Idx = *(Extract->idx_begin()); - assert((Idx == 0 || Idx == 1) && - "Unexpected operation: extracting an unknown landing pad element"); - if (Idx == 0) { - ExtractedEHPtrs.push_back(Extract); - } else if (Idx == 1) { - ExtractedSelectors.push_back(Extract); - } - } -} - -bool LandingPadMap::isOriginLandingPadBlock(const BasicBlock *BB) const { - return BB->getLandingPadInst() == OriginLPad; -} - -bool LandingPadMap::isLandingPadSpecificInst(const Instruction *Inst) const { - if (Inst == OriginLPad) - return true; - for (auto *Extract : ExtractedEHPtrs) { - if (Inst == Extract) - return true; - } - for (auto *Extract : ExtractedSelectors) { - if (Inst == Extract) - return true; - } - return false; -} - -void LandingPadMap::remapEHValues(ValueToValueMapTy &VMap, Value *EHPtrValue, - Value *SelectorValue) const { - // Remap all landing pad extract instructions to the specified values. - for (auto *Extract : ExtractedEHPtrs) - VMap[Extract] = EHPtrValue; - for (auto *Extract : ExtractedSelectors) - VMap[Extract] = SelectorValue; -} - -static bool isLocalAddressCall(const Value *V) { - return match(const_cast(V), m_Intrinsic()); -} - -CloningDirector::CloningAction WinEHCloningDirectorBase::handleInstruction( - ValueToValueMapTy &VMap, const Instruction *Inst, BasicBlock *NewBB) { - // If this is one of the boilerplate landing pad instructions, skip it. - // The instruction will have already been remapped in VMap. - if (LPadMap.isLandingPadSpecificInst(Inst)) - return CloningDirector::SkipInstruction; - - // Nested landing pads that have not already been outlined will be cloned as - // stubs, with just the landingpad instruction and an unreachable instruction. - // When all landingpads have been outlined, we'll replace this with the - // llvm.eh.actions call and indirect branch created when the landing pad was - // outlined. - if (auto *LPad = dyn_cast(Inst)) { - return handleLandingPad(VMap, LPad, NewBB); - } - - // Nested landing pads that have already been outlined will be cloned in their - // outlined form, but we need to intercept the ibr instruction to filter out - // targets that do not return to the handler we are outlining. - if (auto *IBr = dyn_cast(Inst)) { - return handleIndirectBr(VMap, IBr, NewBB); - } - - if (auto *Invoke = dyn_cast(Inst)) - return handleInvoke(VMap, Invoke, NewBB); - - if (auto *Resume = dyn_cast(Inst)) - return handleResume(VMap, Resume, NewBB); - - if (auto *Cmp = dyn_cast(Inst)) - return handleCompare(VMap, Cmp, NewBB); - - if (match(Inst, m_Intrinsic())) - return handleBeginCatch(VMap, Inst, NewBB); - if (match(Inst, m_Intrinsic())) - return handleEndCatch(VMap, Inst, NewBB); - if (match(Inst, m_Intrinsic())) - return handleTypeIdFor(VMap, Inst, NewBB); - - // When outlining llvm.localaddress(), remap that to the second argument, - // which is the FP of the parent. - if (isLocalAddressCall(Inst)) { - VMap[Inst] = ParentFP; - return CloningDirector::SkipInstruction; - } - - // Continue with the default cloning behavior. - return CloningDirector::CloneInstruction; -} - -CloningDirector::CloningAction WinEHCatchDirector::handleLandingPad( - ValueToValueMapTy &VMap, const LandingPadInst *LPad, BasicBlock *NewBB) { - // If the instruction after the landing pad is a call to llvm.eh.actions - // the landing pad has already been outlined. In this case, we should - // clone it because it may return to a block in the handler we are - // outlining now that would otherwise be unreachable. The landing pads - // are sorted before outlining begins to enable this case to work - // properly. - const Instruction *NextI = LPad->getNextNode(); - if (match(NextI, m_Intrinsic())) - return CloningDirector::CloneInstruction; - - // If the landing pad hasn't been outlined yet, the landing pad we are - // outlining now does not dominate it and so it cannot return to a block - // in this handler. In that case, we can just insert a stub landing - // pad now and patch it up later. - Instruction *NewInst = LPad->clone(); - if (LPad->hasName()) - NewInst->setName(LPad->getName()); - // Save this correlation for later processing. - NestedLPtoOriginalLP[cast(NewInst)] = LPad; - VMap[LPad] = NewInst; - BasicBlock::InstListType &InstList = NewBB->getInstList(); - InstList.push_back(NewInst); - InstList.push_back(new UnreachableInst(NewBB->getContext())); - return CloningDirector::StopCloningBB; -} - -CloningDirector::CloningAction WinEHCatchDirector::handleBeginCatch( - ValueToValueMapTy &VMap, const Instruction *Inst, BasicBlock *NewBB) { - // The argument to the call is some form of the first element of the - // landingpad aggregate value, but that doesn't matter. It isn't used - // here. - // The second argument is an outparameter where the exception object will be - // stored. Typically the exception object is a scalar, but it can be an - // aggregate when catching by value. - // FIXME: Leave something behind to indicate where the exception object lives - // for this handler. Should it be part of llvm.eh.actions? - assert(ExceptionObjectVar == nullptr && "Multiple calls to " - "llvm.eh.begincatch found while " - "outlining catch handler."); - ExceptionObjectVar = Inst->getOperand(1)->stripPointerCasts(); - if (isa(ExceptionObjectVar)) - return CloningDirector::SkipInstruction; - assert(cast(ExceptionObjectVar)->isStaticAlloca() && - "catch parameter is not static alloca"); - Materializer.escapeCatchObject(ExceptionObjectVar); - return CloningDirector::SkipInstruction; -} - -CloningDirector::CloningAction -WinEHCatchDirector::handleEndCatch(ValueToValueMapTy &VMap, - const Instruction *Inst, BasicBlock *NewBB) { - auto *IntrinCall = dyn_cast(Inst); - // It might be interesting to track whether or not we are inside a catch - // function, but that might make the algorithm more brittle than it needs - // to be. - - // The end catch call can occur in one of two places: either in a - // landingpad block that is part of the catch handlers exception mechanism, - // or at the end of the catch block. However, a catch-all handler may call - // end catch from the original landing pad. If the call occurs in a nested - // landing pad block, we must skip it and continue so that the landing pad - // gets cloned. - auto *ParentBB = IntrinCall->getParent(); - if (ParentBB->isLandingPad() && !LPadMap.isOriginLandingPadBlock(ParentBB)) - return CloningDirector::SkipInstruction; - - // If an end catch occurs anywhere else we want to terminate the handler - // with a return to the code that follows the endcatch call. If the - // next instruction is not an unconditional branch, we need to split the - // block to provide a clear target for the return instruction. - BasicBlock *ContinueBB; - auto Next = std::next(BasicBlock::const_iterator(IntrinCall)); - const BranchInst *Branch = dyn_cast(Next); - if (!Branch || !Branch->isUnconditional()) { - // We're interrupting the cloning process at this location, so the - // const_cast we're doing here will not cause a problem. - ContinueBB = SplitBlock(const_cast(ParentBB), - const_cast(cast(Next))); - } else { - ContinueBB = Branch->getSuccessor(0); - } - - ReturnInst::Create(NewBB->getContext(), BlockAddress::get(ContinueBB), NewBB); - ReturnTargets.push_back(ContinueBB); - - // We just added a terminator to the cloned block. - // Tell the caller to stop processing the current basic block so that - // the branch instruction will be skipped. - return CloningDirector::StopCloningBB; -} - -CloningDirector::CloningAction WinEHCatchDirector::handleTypeIdFor( - ValueToValueMapTy &VMap, const Instruction *Inst, BasicBlock *NewBB) { - auto *IntrinCall = dyn_cast(Inst); - Value *Selector = IntrinCall->getArgOperand(0)->stripPointerCasts(); - // This causes a replacement that will collapse the landing pad CFG based - // on the filter function we intend to match. - if (Selector == CurrentSelector) - VMap[Inst] = ConstantInt::get(SelectorIDType, 1); - else - VMap[Inst] = ConstantInt::get(SelectorIDType, 0); - // Tell the caller not to clone this instruction. - return CloningDirector::SkipInstruction; -} - -CloningDirector::CloningAction WinEHCatchDirector::handleIndirectBr( - ValueToValueMapTy &VMap, - const IndirectBrInst *IBr, - BasicBlock *NewBB) { - // If this indirect branch is not part of a landing pad block, just clone it. - const BasicBlock *ParentBB = IBr->getParent(); - if (!ParentBB->isLandingPad()) - return CloningDirector::CloneInstruction; - - // If it is part of a landing pad, we want to filter out target blocks - // that are not part of the handler we are outlining. - const LandingPadInst *LPad = ParentBB->getLandingPadInst(); - - // Save this correlation for later processing. - NestedLPtoOriginalLP[cast(VMap[LPad])] = LPad; - - // We should only get here for landing pads that have already been outlined. - assert(match(LPad->getNextNode(), m_Intrinsic())); - - // Copy the indirectbr, but only include targets that were previously - // identified as EH blocks and are dominated by the nested landing pad. - SetVector ReturnTargets; - for (int I = 0, E = IBr->getNumDestinations(); I < E; ++I) { - auto *TargetBB = IBr->getDestination(I); - if (EHBlocks.count(const_cast(TargetBB)) && - DT->dominates(ParentBB, TargetBB)) { - DEBUG(dbgs() << " Adding destination " << TargetBB->getName() << "\n"); - ReturnTargets.insert(TargetBB); - } - } - IndirectBrInst *NewBranch = - IndirectBrInst::Create(const_cast(IBr->getAddress()), - ReturnTargets.size(), NewBB); - for (auto *Target : ReturnTargets) - NewBranch->addDestination(const_cast(Target)); - - // The operands and targets of the branch instruction are remapped later - // because it is a terminator. Tell the cloning code to clone the - // blocks we just added to the target list. - return CloningDirector::CloneSuccessors; -} - -CloningDirector::CloningAction -WinEHCatchDirector::handleInvoke(ValueToValueMapTy &VMap, - const InvokeInst *Invoke, BasicBlock *NewBB) { - return CloningDirector::CloneInstruction; -} - -CloningDirector::CloningAction -WinEHCatchDirector::handleResume(ValueToValueMapTy &VMap, - const ResumeInst *Resume, BasicBlock *NewBB) { - // Resume instructions shouldn't be reachable from catch handlers. - // We still need to handle it, but it will be pruned. - BasicBlock::InstListType &InstList = NewBB->getInstList(); - InstList.push_back(new UnreachableInst(NewBB->getContext())); - return CloningDirector::StopCloningBB; -} - -CloningDirector::CloningAction -WinEHCatchDirector::handleCompare(ValueToValueMapTy &VMap, - const CmpInst *Compare, BasicBlock *NewBB) { - const IntrinsicInst *IntrinCall = nullptr; - if (match(Compare->getOperand(0), m_Intrinsic())) { - IntrinCall = dyn_cast(Compare->getOperand(0)); - } else if (match(Compare->getOperand(1), - m_Intrinsic())) { - IntrinCall = dyn_cast(Compare->getOperand(1)); - } - if (IntrinCall) { - Value *Selector = IntrinCall->getArgOperand(0)->stripPointerCasts(); - // This causes a replacement that will collapse the landing pad CFG based - // on the filter function we intend to match. - if (Selector == CurrentSelector->stripPointerCasts()) { - VMap[Compare] = ConstantInt::get(SelectorIDType, 1); - } else { - VMap[Compare] = ConstantInt::get(SelectorIDType, 0); - } - return CloningDirector::SkipInstruction; - } - return CloningDirector::CloneInstruction; -} - -CloningDirector::CloningAction WinEHCleanupDirector::handleLandingPad( - ValueToValueMapTy &VMap, const LandingPadInst *LPad, BasicBlock *NewBB) { - // The MS runtime will terminate the process if an exception occurs in a - // cleanup handler, so we shouldn't encounter landing pads in the actual - // cleanup code, but they may appear in catch blocks. Depending on where - // we started cloning we may see one, but it will get dropped during dead - // block pruning. - Instruction *NewInst = new UnreachableInst(NewBB->getContext()); - VMap[LPad] = NewInst; - BasicBlock::InstListType &InstList = NewBB->getInstList(); - InstList.push_back(NewInst); - return CloningDirector::StopCloningBB; -} - -CloningDirector::CloningAction WinEHCleanupDirector::handleBeginCatch( - ValueToValueMapTy &VMap, const Instruction *Inst, BasicBlock *NewBB) { - // Cleanup code may flow into catch blocks or the catch block may be part - // of a branch that will be optimized away. We'll insert a return - // instruction now, but it may be pruned before the cloning process is - // complete. - ReturnInst::Create(NewBB->getContext(), nullptr, NewBB); - return CloningDirector::StopCloningBB; -} - -CloningDirector::CloningAction WinEHCleanupDirector::handleEndCatch( - ValueToValueMapTy &VMap, const Instruction *Inst, BasicBlock *NewBB) { - // Cleanup handlers nested within catch handlers may begin with a call to - // eh.endcatch. We can just ignore that instruction. - return CloningDirector::SkipInstruction; -} - -CloningDirector::CloningAction WinEHCleanupDirector::handleTypeIdFor( - ValueToValueMapTy &VMap, const Instruction *Inst, BasicBlock *NewBB) { - // If we encounter a selector comparison while cloning a cleanup handler, - // we want to stop cloning immediately. Anything after the dispatch - // will be outlined into a different handler. - BasicBlock *CatchHandler; - Constant *Selector; - BasicBlock *NextBB; - if (isSelectorDispatch(const_cast(Inst->getParent()), - CatchHandler, Selector, NextBB)) { - ReturnInst::Create(NewBB->getContext(), nullptr, NewBB); - return CloningDirector::StopCloningBB; - } - // If eg.typeid.for is called for any other reason, it can be ignored. - VMap[Inst] = ConstantInt::get(SelectorIDType, 0); - return CloningDirector::SkipInstruction; -} - -CloningDirector::CloningAction WinEHCleanupDirector::handleIndirectBr( - ValueToValueMapTy &VMap, - const IndirectBrInst *IBr, - BasicBlock *NewBB) { - // No special handling is required for cleanup cloning. - return CloningDirector::CloneInstruction; -} - -CloningDirector::CloningAction WinEHCleanupDirector::handleInvoke( - ValueToValueMapTy &VMap, const InvokeInst *Invoke, BasicBlock *NewBB) { - // All invokes in cleanup handlers can be replaced with calls. - SmallVector CallArgs(Invoke->op_begin(), Invoke->op_end() - 3); - // Insert a normal call instruction... - CallInst *NewCall = - CallInst::Create(const_cast(Invoke->getCalledValue()), CallArgs, - Invoke->getName(), NewBB); - NewCall->setCallingConv(Invoke->getCallingConv()); - NewCall->setAttributes(Invoke->getAttributes()); - NewCall->setDebugLoc(Invoke->getDebugLoc()); - VMap[Invoke] = NewCall; - - // Remap the operands. - llvm::RemapInstruction(NewCall, VMap, RF_None, nullptr, &Materializer); - - // Insert an unconditional branch to the normal destination. - BranchInst::Create(Invoke->getNormalDest(), NewBB); - - // The unwind destination won't be cloned into the new function, so - // we don't need to clean up its phi nodes. - - // We just added a terminator to the cloned block. - // Tell the caller to stop processing the current basic block. - return CloningDirector::CloneSuccessors; -} - -CloningDirector::CloningAction WinEHCleanupDirector::handleResume( - ValueToValueMapTy &VMap, const ResumeInst *Resume, BasicBlock *NewBB) { - ReturnInst::Create(NewBB->getContext(), nullptr, NewBB); - - // We just added a terminator to the cloned block. - // Tell the caller to stop processing the current basic block so that - // the branch instruction will be skipped. - return CloningDirector::StopCloningBB; -} - -CloningDirector::CloningAction -WinEHCleanupDirector::handleCompare(ValueToValueMapTy &VMap, - const CmpInst *Compare, BasicBlock *NewBB) { - if (match(Compare->getOperand(0), m_Intrinsic()) || - match(Compare->getOperand(1), m_Intrinsic())) { - VMap[Compare] = ConstantInt::get(SelectorIDType, 1); - return CloningDirector::SkipInstruction; - } - return CloningDirector::CloneInstruction; -} - -WinEHFrameVariableMaterializer::WinEHFrameVariableMaterializer( - Function *OutlinedFn, Value *ParentFP, FrameVarInfoMap &FrameVarInfo) - : FrameVarInfo(FrameVarInfo), Builder(OutlinedFn->getContext()) { - BasicBlock *EntryBB = &OutlinedFn->getEntryBlock(); - - // New allocas should be inserted in the entry block, but after the parent FP - // is established if it is an instruction. - BasicBlock::iterator InsertPoint = EntryBB->getFirstInsertionPt(); - if (auto *FPInst = dyn_cast(ParentFP)) - InsertPoint = std::next(FPInst->getIterator()); - Builder.SetInsertPoint(EntryBB, InsertPoint); -} - -Value *WinEHFrameVariableMaterializer::materializeValueFor(Value *V) { - // If we're asked to materialize a static alloca, we temporarily create an - // alloca in the outlined function and add this to the FrameVarInfo map. When - // all the outlining is complete, we'll replace these temporary allocas with - // calls to llvm.localrecover. - if (auto *AV = dyn_cast(V)) { - assert(AV->isStaticAlloca() && - "cannot materialize un-demoted dynamic alloca"); - AllocaInst *NewAlloca = dyn_cast(AV->clone()); - Builder.Insert(NewAlloca, AV->getName()); - FrameVarInfo[AV].push_back(NewAlloca); - return NewAlloca; - } - - if (isa(V) || isa(V)) { - Function *Parent = isa(V) - ? cast(V)->getParent()->getParent() - : cast(V)->getParent(); - errs() - << "Failed to demote instruction used in exception handler of function " - << GlobalValue::getRealLinkageName(Parent->getName()) << ":\n"; - errs() << " " << *V << '\n'; - report_fatal_error("WinEHPrepare failed to demote instruction"); - } - - // Don't materialize other values. - return nullptr; -} - -void WinEHFrameVariableMaterializer::escapeCatchObject(Value *V) { - // Catch parameter objects have to live in the parent frame. When we see a use - // of a catch parameter, add a sentinel to the multimap to indicate that it's - // used from another handler. This will prevent us from trying to sink the - // alloca into the handler and ensure that the catch parameter is present in - // the call to llvm.localescape. - FrameVarInfo[V].push_back(getCatchObjectSentinel()); -} - -// This function maps the catch and cleanup handlers that are reachable from the -// specified landing pad. The landing pad sequence will have this basic shape: -// -// -// -// -// -// -// -// -// ... -// -// Any of the cleanup slots may be absent. The cleanup slots may be occupied by -// any arbitrary control flow, but all paths through the cleanup code must -// eventually reach the next selector comparison and no path can skip to a -// different selector comparisons, though some paths may terminate abnormally. -// Therefore, we will use a depth first search from the start of any given -// cleanup block and stop searching when we find the next selector comparison. -// -// If the landingpad instruction does not have a catch clause, we will assume -// that any instructions other than selector comparisons and catch handlers can -// be ignored. In practice, these will only be the boilerplate instructions. -// -// The catch handlers may also have any control structure, but we are only -// interested in the start of the catch handlers, so we don't need to actually -// follow the flow of the catch handlers. The start of the catch handlers can -// be located from the compare instructions, but they can be skipped in the -// flow by following the contrary branch. -void WinEHPrepare::mapLandingPadBlocks(LandingPadInst *LPad, - LandingPadActions &Actions) { - unsigned int NumClauses = LPad->getNumClauses(); - unsigned int HandlersFound = 0; - BasicBlock *BB = LPad->getParent(); - - DEBUG(dbgs() << "Mapping landing pad: " << BB->getName() << "\n"); - - if (NumClauses == 0) { - findCleanupHandlers(Actions, BB, nullptr); - return; - } - - VisitedBlockSet VisitedBlocks; - - while (HandlersFound != NumClauses) { - BasicBlock *NextBB = nullptr; - - // Skip over filter clauses. - if (LPad->isFilter(HandlersFound)) { - ++HandlersFound; - continue; - } - - // See if the clause we're looking for is a catch-all. - // If so, the catch begins immediately. - Constant *ExpectedSelector = - LPad->getClause(HandlersFound)->stripPointerCasts(); - if (isa(ExpectedSelector)) { - // The catch all must occur last. - assert(HandlersFound == NumClauses - 1); - - // There can be additional selector dispatches in the call chain that we - // need to ignore. - BasicBlock *CatchBlock = nullptr; - Constant *Selector; - while (BB && isSelectorDispatch(BB, CatchBlock, Selector, NextBB)) { - DEBUG(dbgs() << " Found extra catch dispatch in block " - << CatchBlock->getName() << "\n"); - BB = NextBB; - } - - // Add the catch handler to the action list. - CatchHandler *Action = nullptr; - if (CatchHandlerMap.count(BB) && CatchHandlerMap[BB] != nullptr) { - // If the CatchHandlerMap already has an entry for this BB, re-use it. - Action = CatchHandlerMap[BB]; - assert(Action->getSelector() == ExpectedSelector); - } else { - // We don't expect a selector dispatch, but there may be a call to - // llvm.eh.begincatch, which separates catch handling code from - // cleanup code in the same control flow. This call looks for the - // begincatch intrinsic. - Action = findCatchHandler(BB, NextBB, VisitedBlocks); - if (Action) { - // For C++ EH, check if there is any interesting cleanup code before - // we begin the catch. This is important because cleanups cannot - // rethrow exceptions but code called from catches can. For SEH, it - // isn't important if some finally code before a catch-all is executed - // out of line or after recovering from the exception. - if (Personality == EHPersonality::MSVC_CXX) - findCleanupHandlers(Actions, BB, BB); - } else { - // If an action was not found, it means that the control flows - // directly into the catch-all handler and there is no cleanup code. - // That's an expected situation and we must create a catch action. - // Since this is a catch-all handler, the selector won't actually - // appear in the code anywhere. ExpectedSelector here is the constant - // null ptr that we got from the landing pad instruction. - Action = new CatchHandler(BB, ExpectedSelector, nullptr); - CatchHandlerMap[BB] = Action; - } - } - Actions.insertCatchHandler(Action); - DEBUG(dbgs() << " Catch all handler at block " << BB->getName() << "\n"); - ++HandlersFound; - - // Once we reach a catch-all, don't expect to hit a resume instruction. - BB = nullptr; - break; - } - - CatchHandler *CatchAction = findCatchHandler(BB, NextBB, VisitedBlocks); - assert(CatchAction); - - // See if there is any interesting code executed before the dispatch. - findCleanupHandlers(Actions, BB, CatchAction->getStartBlock()); - - // When the source program contains multiple nested try blocks the catch - // handlers can get strung together in such a way that we can encounter - // a dispatch for a selector that we've already had a handler for. - if (CatchAction->getSelector()->stripPointerCasts() == ExpectedSelector) { - ++HandlersFound; - - // Add the catch handler to the action list. - DEBUG(dbgs() << " Found catch dispatch in block " - << CatchAction->getStartBlock()->getName() << "\n"); - Actions.insertCatchHandler(CatchAction); - } else { - // Under some circumstances optimized IR will flow unconditionally into a - // handler block without checking the selector. This can only happen if - // the landing pad has a catch-all handler and the handler for the - // preceding catch clause is identical to the catch-call handler - // (typically an empty catch). In this case, the handler must be shared - // by all remaining clauses. - if (isa( - CatchAction->getSelector()->stripPointerCasts())) { - DEBUG(dbgs() << " Applying early catch-all handler in block " - << CatchAction->getStartBlock()->getName() - << " to all remaining clauses.\n"); - Actions.insertCatchHandler(CatchAction); - return; - } - - DEBUG(dbgs() << " Found extra catch dispatch in block " - << CatchAction->getStartBlock()->getName() << "\n"); - } - - // Move on to the block after the catch handler. - BB = NextBB; - } - - // If we didn't wind up in a catch-all, see if there is any interesting code - // executed before the resume. - findCleanupHandlers(Actions, BB, BB); - - // It's possible that some optimization moved code into a landingpad that - // wasn't - // previously being used for cleanup. If that happens, we need to execute - // that - // extra code from a cleanup handler. - if (Actions.includesCleanup() && !LPad->isCleanup()) - LPad->setCleanup(true); -} - -// This function searches starting with the input block for the next -// block that terminates with a branch whose condition is based on a selector -// comparison. This may be the input block. See the mapLandingPadBlocks -// comments for a discussion of control flow assumptions. -// -CatchHandler *WinEHPrepare::findCatchHandler(BasicBlock *BB, - BasicBlock *&NextBB, - VisitedBlockSet &VisitedBlocks) { - // See if we've already found a catch handler use it. - // Call count() first to avoid creating a null entry for blocks - // we haven't seen before. - if (CatchHandlerMap.count(BB) && CatchHandlerMap[BB] != nullptr) { - CatchHandler *Action = cast(CatchHandlerMap[BB]); - NextBB = Action->getNextBB(); - return Action; - } - - // VisitedBlocks applies only to the current search. We still - // need to consider blocks that we've visited while mapping other - // landing pads. - VisitedBlocks.insert(BB); - - BasicBlock *CatchBlock = nullptr; - Constant *Selector = nullptr; - - // If this is the first time we've visited this block from any landing pad - // look to see if it is a selector dispatch block. - if (!CatchHandlerMap.count(BB)) { - if (isSelectorDispatch(BB, CatchBlock, Selector, NextBB)) { - CatchHandler *Action = new CatchHandler(BB, Selector, NextBB); - CatchHandlerMap[BB] = Action; - return Action; - } - // If we encounter a block containing an llvm.eh.begincatch before we - // find a selector dispatch block, the handler is assumed to be - // reached unconditionally. This happens for catch-all blocks, but - // it can also happen for other catch handlers that have been combined - // with the catch-all handler during optimization. - if (isCatchBlock(BB)) { - PointerType *Int8PtrTy = Type::getInt8PtrTy(BB->getContext()); - Constant *NullSelector = ConstantPointerNull::get(Int8PtrTy); - CatchHandler *Action = new CatchHandler(BB, NullSelector, nullptr); - CatchHandlerMap[BB] = Action; - return Action; - } - } - - // Visit each successor, looking for the dispatch. - // FIXME: We expect to find the dispatch quickly, so this will probably - // work better as a breadth first search. - for (BasicBlock *Succ : successors(BB)) { - if (VisitedBlocks.count(Succ)) - continue; - - CatchHandler *Action = findCatchHandler(Succ, NextBB, VisitedBlocks); - if (Action) - return Action; - } - return nullptr; -} - -// These are helper functions to combine repeated code from findCleanupHandlers. -static void createCleanupHandler(LandingPadActions &Actions, - CleanupHandlerMapTy &CleanupHandlerMap, - BasicBlock *BB) { - CleanupHandler *Action = new CleanupHandler(BB); - CleanupHandlerMap[BB] = Action; - Actions.insertCleanupHandler(Action); - DEBUG(dbgs() << " Found cleanup code in block " - << Action->getStartBlock()->getName() << "\n"); -} - -static CallSite matchOutlinedFinallyCall(BasicBlock *BB, - Instruction *MaybeCall) { - // Look for finally blocks that Clang has already outlined for us. - // %fp = call i8* @llvm.localaddress() - // call void @"fin$parent"(iN 1, i8* %fp) - if (isLocalAddressCall(MaybeCall) && MaybeCall != BB->getTerminator()) - MaybeCall = MaybeCall->getNextNode(); - CallSite FinallyCall(MaybeCall); - if (!FinallyCall || FinallyCall.arg_size() != 2) - return CallSite(); - if (!match(FinallyCall.getArgument(0), m_SpecificInt(1))) - return CallSite(); - if (!isLocalAddressCall(FinallyCall.getArgument(1))) - return CallSite(); - return FinallyCall; -} - -static BasicBlock *followSingleUnconditionalBranches(BasicBlock *BB) { - // Skip single ubr blocks. - while (BB->getFirstNonPHIOrDbg() == BB->getTerminator()) { - auto *Br = dyn_cast(BB->getTerminator()); - if (Br && Br->isUnconditional()) - BB = Br->getSuccessor(0); - else - return BB; - } - return BB; -} - -// This function searches starting with the input block for the next block that -// contains code that is not part of a catch handler and would not be eliminated -// during handler outlining. -// -void WinEHPrepare::findCleanupHandlers(LandingPadActions &Actions, - BasicBlock *StartBB, BasicBlock *EndBB) { - // Here we will skip over the following: - // - // landing pad prolog: - // - // Unconditional branches - // - // Selector dispatch - // - // Resume pattern - // - // Anything else marks the start of an interesting block - - BasicBlock *BB = StartBB; - // Anything other than an unconditional branch will kick us out of this loop - // one way or another. - while (BB) { - BB = followSingleUnconditionalBranches(BB); - // If we've already scanned this block, don't scan it again. If it is - // a cleanup block, there will be an action in the CleanupHandlerMap. - // If we've scanned it and it is not a cleanup block, there will be a - // nullptr in the CleanupHandlerMap. If we have not scanned it, there will - // be no entry in the CleanupHandlerMap. We must call count() first to - // avoid creating a null entry for blocks we haven't scanned. - if (CleanupHandlerMap.count(BB)) { - if (auto *Action = CleanupHandlerMap[BB]) { - Actions.insertCleanupHandler(Action); - DEBUG(dbgs() << " Found cleanup code in block " - << Action->getStartBlock()->getName() << "\n"); - // FIXME: This cleanup might chain into another, and we need to discover - // that. - return; - } else { - // Here we handle the case where the cleanup handler map contains a - // value for this block but the value is a nullptr. This means that - // we have previously analyzed the block and determined that it did - // not contain any cleanup code. Based on the earlier analysis, we - // know the block must end in either an unconditional branch, a - // resume or a conditional branch that is predicated on a comparison - // with a selector. Either the resume or the selector dispatch - // would terminate the search for cleanup code, so the unconditional - // branch is the only case for which we might need to continue - // searching. - BasicBlock *SuccBB = followSingleUnconditionalBranches(BB); - if (SuccBB == BB || SuccBB == EndBB) - return; - BB = SuccBB; - continue; - } - } - - // Create an entry in the cleanup handler map for this block. Initially - // we create an entry that says this isn't a cleanup block. If we find - // cleanup code, the caller will replace this entry. - CleanupHandlerMap[BB] = nullptr; - - TerminatorInst *Terminator = BB->getTerminator(); - - // Landing pad blocks have extra instructions we need to accept. - LandingPadMap *LPadMap = nullptr; - if (BB->isLandingPad()) { - LandingPadInst *LPad = BB->getLandingPadInst(); - LPadMap = &LPadMaps[LPad]; - if (!LPadMap->isInitialized()) - LPadMap->mapLandingPad(LPad); - } - - // Look for the bare resume pattern: - // %lpad.val1 = insertvalue { i8*, i32 } undef, i8* %exn, 0 - // %lpad.val2 = insertvalue { i8*, i32 } %lpad.val1, i32 %sel, 1 - // resume { i8*, i32 } %lpad.val2 - if (auto *Resume = dyn_cast(Terminator)) { - InsertValueInst *Insert1 = nullptr; - InsertValueInst *Insert2 = nullptr; - Value *ResumeVal = Resume->getOperand(0); - // If the resume value isn't a phi or landingpad value, it should be a - // series of insertions. Identify them so we can avoid them when scanning - // for cleanups. - if (!isa(ResumeVal) && !isa(ResumeVal)) { - Insert2 = dyn_cast(ResumeVal); - if (!Insert2) - return createCleanupHandler(Actions, CleanupHandlerMap, BB); - Insert1 = dyn_cast(Insert2->getAggregateOperand()); - if (!Insert1) - return createCleanupHandler(Actions, CleanupHandlerMap, BB); - } - for (BasicBlock::iterator II = BB->getFirstNonPHIOrDbg()->getIterator(), - IE = BB->end(); - II != IE; ++II) { - Instruction *Inst = &*II; - if (LPadMap && LPadMap->isLandingPadSpecificInst(Inst)) - continue; - if (Inst == Insert1 || Inst == Insert2 || Inst == Resume) - continue; - if (!Inst->hasOneUse() || - (Inst->user_back() != Insert1 && Inst->user_back() != Insert2)) { - return createCleanupHandler(Actions, CleanupHandlerMap, BB); - } - } - return; - } - - BranchInst *Branch = dyn_cast(Terminator); - if (Branch && Branch->isConditional()) { - // Look for the selector dispatch. - // %2 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIf to i8*)) - // %matches = icmp eq i32 %sel, %2 - // br i1 %matches, label %catch14, label %eh.resume - CmpInst *Compare = dyn_cast(Branch->getCondition()); - if (!Compare || !Compare->isEquality()) - return createCleanupHandler(Actions, CleanupHandlerMap, BB); - for (BasicBlock::iterator II = BB->getFirstNonPHIOrDbg()->getIterator(), - IE = BB->end(); - II != IE; ++II) { - Instruction *Inst = &*II; - if (LPadMap && LPadMap->isLandingPadSpecificInst(Inst)) - continue; - if (Inst == Compare || Inst == Branch) - continue; - if (match(Inst, m_Intrinsic())) - continue; - return createCleanupHandler(Actions, CleanupHandlerMap, BB); - } - // The selector dispatch block should always terminate our search. - assert(BB == EndBB); - return; - } - - if (isAsynchronousEHPersonality(Personality)) { - // If this is a landingpad block, split the block at the first non-landing - // pad instruction. - Instruction *MaybeCall = BB->getFirstNonPHIOrDbg(); - if (LPadMap) { - while (MaybeCall != BB->getTerminator() && - LPadMap->isLandingPadSpecificInst(MaybeCall)) - MaybeCall = MaybeCall->getNextNode(); - } - - // Look for outlined finally calls on x64, since those happen to match the - // prototype provided by the runtime. - if (TheTriple.getArch() == Triple::x86_64) { - if (CallSite FinallyCall = matchOutlinedFinallyCall(BB, MaybeCall)) { - Function *Fin = FinallyCall.getCalledFunction(); - assert(Fin && "outlined finally call should be direct"); - auto *Action = new CleanupHandler(BB); - Action->setHandlerBlockOrFunc(Fin); - Actions.insertCleanupHandler(Action); - CleanupHandlerMap[BB] = Action; - DEBUG(dbgs() << " Found frontend-outlined finally call to " - << Fin->getName() << " in block " - << Action->getStartBlock()->getName() << "\n"); - - // Split the block if there were more interesting instructions and - // look for finally calls in the normal successor block. - BasicBlock *SuccBB = BB; - if (FinallyCall.getInstruction() != BB->getTerminator() && - FinallyCall.getInstruction()->getNextNode() != - BB->getTerminator()) { - SuccBB = - SplitBlock(BB, FinallyCall.getInstruction()->getNextNode(), DT); - } else { - if (FinallyCall.isInvoke()) { - SuccBB = cast(FinallyCall.getInstruction()) - ->getNormalDest(); - } else { - SuccBB = BB->getUniqueSuccessor(); - assert(SuccBB && - "splitOutlinedFinallyCalls didn't insert a branch"); - } - } - BB = SuccBB; - if (BB == EndBB) - return; - continue; - } - } - } - - // Anything else is either a catch block or interesting cleanup code. - for (BasicBlock::iterator II = BB->getFirstNonPHIOrDbg()->getIterator(), - IE = BB->end(); - II != IE; ++II) { - Instruction *Inst = &*II; - if (LPadMap && LPadMap->isLandingPadSpecificInst(Inst)) - continue; - // Unconditional branches fall through to this loop. - if (Inst == Branch) - continue; - // If this is a catch block, there is no cleanup code to be found. - if (match(Inst, m_Intrinsic())) - return; - // If this a nested landing pad, it may contain an endcatch call. - if (match(Inst, m_Intrinsic())) - return; - // Anything else makes this interesting cleanup code. - return createCleanupHandler(Actions, CleanupHandlerMap, BB); - } - - // Only unconditional branches in empty blocks should get this far. - assert(Branch && Branch->isUnconditional()); - if (BB == EndBB) - return; - BB = Branch->getSuccessor(0); - } -} - -// This is a public function, declared in WinEHFuncInfo.h and is also -// referenced by WinEHNumbering in FunctionLoweringInfo.cpp. -void llvm::parseEHActions( - const IntrinsicInst *II, - SmallVectorImpl> &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(II->getArgOperand(I))->getZExtValue(); - if (ActionKind == /*catch=*/1) { - auto *Selector = cast(II->getArgOperand(I + 1)); - ConstantInt *EHObjIndex = cast(II->getArgOperand(I + 2)); - int64_t EHObjIndexVal = EHObjIndex->getSExtValue(); - Constant *Handler = cast(II->getArgOperand(I + 3)); - I += 4; - auto CH = make_unique(/*BB=*/nullptr, Selector, - /*NextBB=*/nullptr); - CH->setHandlerBlockOrFunc(Handler); - CH->setExceptionVarIndex(EHObjIndexVal); - Actions.push_back(std::move(CH)); - } else if (ActionKind == 0) { - Constant *Handler = cast(II->getArgOperand(I + 1)); - I += 2; - auto CH = make_unique(/*BB=*/nullptr); - CH->setHandlerBlockOrFunc(Handler); - Actions.push_back(std::move(CH)); - } else { - llvm_unreachable("Expected either a catch or cleanup handler!"); - } - } - std::reverse(Actions.begin(), Actions.end()); -} - static int addUnwindMapEntry(WinEHFuncInfo &FuncInfo, int ToState, const Value *V) { - WinEHUnwindMapEntry UME; + CxxUnwindMapEntry UME; UME.ToState = ToState; UME.Cleanup = V; - FuncInfo.UnwindMap.push_back(UME); + FuncInfo.CxxUnwindMap.push_back(UME); return FuncInfo.getLastStateNumber(); } @@ -3120,15 +694,10 @@ void WinEHPrepare::colorFunclets(Function &F, void llvm::calculateCatchReturnSuccessorColors(const Function *Fn, WinEHFuncInfo &FuncInfo) { - SmallVector LPads; - SmallVector Resumes; SmallVector EntryBlocks; // colorFunclets needs the set of EntryBlocks, get them using - // findExceptionalConstructs. - bool ForExplicitEH = findExceptionalConstructs(const_cast(*Fn), - LPads, Resumes, EntryBlocks); - if (!ForExplicitEH) - return; + // findFuncletEntryPoints. + findFuncletEntryPoints(const_cast(*Fn), EntryBlocks); std::map> BlockColors; std::map> FuncletBlocks; diff --git a/lib/Target/X86/X86WinEHState.cpp b/lib/Target/X86/X86WinEHState.cpp index 993879e399b..ed909c58e9b 100644 --- a/lib/Target/X86/X86WinEHState.cpp +++ b/lib/Target/X86/X86WinEHState.cpp @@ -429,14 +429,27 @@ void WinEHStatePass::unlinkExceptionRegistration(IRBuilder<> &Builder) { } void WinEHStatePass::addCXXStateStores(Function &F, WinEHFuncInfo &FuncInfo) { - calculateWinCXXEHStateNumbers(&F, FuncInfo); + // Set up RegNodeEscapeIndex + int RegNodeEscapeIndex = escapeRegNode(F); + FuncInfo.EHRegNodeEscapeIndex = RegNodeEscapeIndex; - // The base state for the parent is -1. + calculateWinCXXEHStateNumbers(&F, FuncInfo); addStateStoresToFunclet(RegNode, FuncInfo, F, -1); +} - // Set up RegNodeEscapeIndex +/// 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. +void WinEHStatePass::addSEHStateStores(Function &F, WinEHFuncInfo &FuncInfo) { + // Remember and return the index that we used. We save it in WinEHFuncInfo so + // that we can lower llvm.x86.seh.recoverfp later in filter functions without + // too much trouble. int RegNodeEscapeIndex = escapeRegNode(F); FuncInfo.EHRegNodeEscapeIndex = RegNodeEscapeIndex; + + calculateSEHStateNumbers(&F, FuncInfo); + addStateStoresToFunclet(RegNode, FuncInfo, F, -1); } /// Escape RegNode so that we can access it from child handlers. Find the call @@ -503,92 +516,6 @@ void WinEHStatePass::addStateStoresToFunclet(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, WinEHFuncInfo &FuncInfo) { - // Remember and return the index that we used. We save it in WinEHFuncInfo so - // that we can lower llvm.x86.seh.recoverfp later in filter functions without - // too much trouble. - int RegNodeEscapeIndex = escapeRegNode(F); - FuncInfo.EHRegNodeEscapeIndex = RegNodeEscapeIndex; - - // If this funciton uses the new EH IR, use the explicit state numbering - // algorithm and return early. - bool UsesLPads = false; - for (BasicBlock &BB : F) { - if (BB.isLandingPad()) { - UsesLPads = true; - break; - } - } - if (!UsesLPads) { - calculateSEHStateNumbers(&F, FuncInfo); - addStateStoresToFunclet(RegNode, FuncInfo, F, -1); - return; - } - // FIXME: Delete the rest of this code and clean things up when new EH is - // done. - - // Iterate all the instructions and emit state number stores. - int CurState = 0; - SmallPtrSet ExceptBlocks; - for (BasicBlock &BB : F) { - for (auto I = BB.begin(), E = BB.end(); I != E; ++I) { - if (auto *CI = dyn_cast(I)) { - auto *Intrin = dyn_cast(CI); - if (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(I)) { - // Look up the state number of the landingpad this unwinds to. - LandingPadInst *LPI = II->getUnwindDest()->getLandingPadInst(); - auto InsertionPair = - FuncInfo.EHPadStateMap.insert(std::make_pair(LPI, CurState)); - auto Iter = InsertionPair.first; - int &State = Iter->second; - bool Inserted = InsertionPair.second; - if (Inserted) { - // Each action consumes a state number. - auto *EHActions = cast(LPI->getNextNode()); - SmallVector, 4> ActionList; - parseEHActions(EHActions, ActionList); - assert(!ActionList.empty()); - CurState += ActionList.size(); - State += ActionList.size() - 1; - - // Remember all the __except block targets. - for (auto &Handler : ActionList) { - if (auto *CH = dyn_cast(Handler.get())) { - auto *BA = cast(CH->getHandlerBlockOrFunc()); -#ifndef NDEBUG - for (BasicBlock *Pred : predecessors(BA->getBasicBlock())) - assert(Pred->isLandingPad() && - "WinEHPrepare failed to split block"); -#endif - ExceptBlocks.insert(BA->getBasicBlock()); - } - } - } - insertStateNumberStore(RegNode, II, State); - } - } - } - - // Insert llvm.x86.seh.restoreframe() into each __except block. - Function *RestoreFrame = - Intrinsic::getDeclaration(TheModule, Intrinsic::x86_seh_restoreframe); - for (BasicBlock *ExceptBB : ExceptBlocks) { - IRBuilder<> Builder(ExceptBB->begin()); - Builder.CreateCall(RestoreFrame, {}); - } -} - void WinEHStatePass::insertStateNumberStore(Value *ParentRegNode, Instruction *IP, int State) { IRBuilder<> Builder(IP); diff --git a/test/Analysis/Lint/cppeh-catch-intrinsics.ll b/test/Analysis/Lint/cppeh-catch-intrinsics.ll deleted file mode 100644 index 19480a2f60f..00000000000 --- a/test/Analysis/Lint/cppeh-catch-intrinsics.ll +++ /dev/null @@ -1,278 +0,0 @@ -; RUN: opt -lint -disable-output < %s 2>&1 | FileCheck %s - -; This test is meant to prove that the Verifier is able to identify a variety -; of errors with the llvm.eh.begincatch and llvm.eh.endcatch intrinsics. -; See cppeh-catch-intrinsics-clean for correct uses. - -target triple = "x86_64-pc-windows-msvc" - -declare void @llvm.eh.begincatch(i8*, i8*) - -declare void @llvm.eh.endcatch() - -@_ZTIi = external constant i8* - -; Function Attrs: uwtable -define void @test_missing_endcatch() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) { -; CHECK: Some paths from llvm.eh.begincatch may not reach llvm.eh.endcatch -; CHECK-NEXT: call void @llvm.eh.begincatch(i8* %exn, i8* null) -entry: - invoke void @_Z9may_throwv() - to label %try.cont unwind label %lpad - -lpad: ; preds = %entry - %0 = landingpad { i8*, i32 } - catch i8* bitcast (i8** @_ZTIi to i8*) - %exn = extractvalue { i8*, i32 } %0, 0 - %sel = extractvalue { i8*, i32 } %0, 1 - %1 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*)) - %matches = icmp eq i32 %sel, %1 - br i1 %matches, label %catch, label %eh.resume - -catch: ; preds = %lpad - call void @llvm.eh.begincatch(i8* %exn, i8* null) - call void @_Z10handle_intv() - br label %invoke.cont2 - -invoke.cont2: ; preds = %catch - br label %try.cont - -try.cont: ; preds = %invoke.cont2, %entry - ret void - -eh.resume: ; preds = %catch.dispatch - resume { i8*, i32 } %0 -} - -; Function Attrs: uwtable -define void @test_missing_begincatch() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) { -; CHECK: llvm.eh.endcatch may be reachable without passing llvm.eh.begincatch -; CHECK-NEXT: call void @llvm.eh.endcatch() -entry: - invoke void @_Z9may_throwv() - to label %try.cont unwind label %lpad - -lpad: ; preds = %entry - %0 = landingpad { i8*, i32 } - catch i8* bitcast (i8** @_ZTIi to i8*) - %exn = extractvalue { i8*, i32 } %0, 0 - %sel = extractvalue { i8*, i32 } %0, 1 - %1 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*)) - %matches = icmp eq i32 %sel, %1 - br i1 %matches, label %catch, label %eh.resume - -catch: ; preds = %lpad - call void @_Z10handle_intv() - br label %invoke.cont2 - -invoke.cont2: ; preds = %catch - call void @llvm.eh.endcatch() - br label %try.cont - -try.cont: ; preds = %invoke.cont2, %entry - ret void - -eh.resume: ; preds = %catch.dispatch - resume { i8*, i32 } %0 -} - -; Function Attrs: uwtable -define void @test_multiple_begin() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) { -; CHECK: llvm.eh.begincatch may be called a second time before llvm.eh.endcatch -; CHECK-NEXT: call void @llvm.eh.begincatch(i8* %exn, i8* null) -; CHECK-NEXT: call void @llvm.eh.begincatch(i8* %exn, i8* null) -entry: - invoke void @_Z9may_throwv() - to label %try.cont unwind label %lpad - -lpad: ; preds = %entry - %0 = landingpad { i8*, i32 } - catch i8* bitcast (i8** @_ZTIi to i8*) - %exn = extractvalue { i8*, i32 } %0, 0 - %sel = extractvalue { i8*, i32 } %0, 1 - %1 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*)) - %matches = icmp eq i32 %sel, %1 - br i1 %matches, label %catch, label %eh.resume - -catch: ; preds = %lpad - call void @llvm.eh.begincatch(i8* %exn, i8* null) - call void @_Z10handle_intv() - br label %invoke.cont2 - -invoke.cont2: ; preds = %catch - call void @llvm.eh.begincatch(i8* %exn, i8* null) - call void @llvm.eh.endcatch() - br label %try.cont - -try.cont: ; preds = %invoke.cont2, %entry - ret void - -eh.resume: ; preds = %catch.dispatch - resume { i8*, i32 } %0 -} - -; Function Attrs: uwtable -define void @test_multiple_end() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) { -; CHECK: llvm.eh.endcatch may be called a second time after llvm.eh.begincatch -; CHECK-NEXT: call void @llvm.eh.endcatch() -; CHECK-NEXT: call void @llvm.eh.endcatch() -entry: - invoke void @_Z9may_throwv() - to label %try.cont unwind label %lpad - -lpad: ; preds = %entry - %0 = landingpad { i8*, i32 } - catch i8* bitcast (i8** @_ZTIi to i8*) - %exn = extractvalue { i8*, i32 } %0, 0 - %sel = extractvalue { i8*, i32 } %0, 1 - %1 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*)) - %matches = icmp eq i32 %sel, %1 - br i1 %matches, label %catch, label %eh.resume - -catch: ; preds = %lpad - call void @llvm.eh.begincatch(i8* %exn, i8* null) - call void @_Z10handle_intv() - call void @llvm.eh.endcatch() - br label %invoke.cont2 - -invoke.cont2: ; preds = %catch - call void @llvm.eh.endcatch() - br label %try.cont - -try.cont: ; preds = %invoke.cont2, %entry - ret void - -eh.resume: ; preds = %catch.dispatch - resume { i8*, i32 } %0 -} - - -; Function Attrs: uwtable -define void @test_begincatch_without_lpad() { -; CHECK: llvm.eh.begincatch may be reachable without passing a landingpad -; CHECK-NEXT: call void @llvm.eh.begincatch(i8* %exn, i8* null) -entry: - %exn = alloca i8 - call void @llvm.eh.begincatch(i8* %exn, i8* null) - call void @_Z10handle_intv() - br label %invoke.cont2 - -invoke.cont2: ; preds = %catch - call void @llvm.eh.endcatch() - br label %try.cont - -try.cont: ; preds = %invoke.cont2, %entry - ret void -} - -; Function Attrs: uwtable -define void @test_branch_to_begincatch_with_no_lpad(i32 %fake.sel) personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) { -; CHECK: llvm.eh.begincatch may be reachable without passing a landingpad -; CHECK-NEXT: call void @llvm.eh.begincatch(i8* %exn2, i8* null) -entry: - %fake.exn = alloca i8 - invoke void @_Z9may_throwv() - to label %catch unwind label %lpad - -lpad: ; preds = %entry - %0 = landingpad { i8*, i32 } - catch i8* bitcast (i8** @_ZTIi to i8*) - %exn = extractvalue { i8*, i32 } %0, 0 - %sel = extractvalue { i8*, i32 } %0, 1 - %1 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*)) - %matches = icmp eq i32 %sel, %1 - br i1 %matches, label %catch, label %eh.resume - - invoke void @_Z9may_throwv() - to label %try.cont unwind label %lpad - -catch: ; preds = %lpad, %entry - %exn2 = phi i8* [%exn, %lpad], [%fake.exn, %entry] - %sel2 = phi i32 [%sel, %lpad], [%fake.sel, %entry] - call void @llvm.eh.begincatch(i8* %exn2, i8* null) - call void @_Z10handle_intv() - %matches1 = icmp eq i32 %sel2, 0 - br i1 %matches1, label %invoke.cont2, label %invoke.cont3 - -invoke.cont2: ; preds = %catch - call void @llvm.eh.endcatch() - br label %try.cont - -invoke.cont3: ; preds = %catch - call void @llvm.eh.endcatch() - br label %eh.resume - -try.cont: ; preds = %invoke.cont2 - ret void - -eh.resume: ; preds = %catch.dispatch - %lpad.val = insertvalue { i8*, i32 } undef, i32 0, 1 - resume { i8*, i32 } %lpad.val -} - -; Function Attrs: uwtable -define void @test_branch_missing_endcatch() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) { -; CHECK: Some paths from llvm.eh.begincatch may not reach llvm.eh.endcatch -; CHECK-NEXT: call void @llvm.eh.begincatch(i8* %exn2, i8* null) -entry: - invoke void @_Z9may_throwv() - to label %invoke.cont unwind label %lpad - -invoke.cont: - invoke void @_Z9may_throwv() - to label %invoke.cont unwind label %lpad1 - -lpad: ; preds = %entry - %0 = landingpad { i8*, i32 } - catch i8* bitcast (i8** @_ZTIi to i8*) - %exn = extractvalue { i8*, i32 } %0, 0 - %sel = extractvalue { i8*, i32 } %0, 1 - %1 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*)) - %matches = icmp eq i32 %sel, %1 - br i1 %matches, label %catch, label %eh.resume - - invoke void @_Z9may_throwv() - to label %try.cont unwind label %lpad - -lpad1: ; preds = %entry - %l1.0 = landingpad { i8*, i32 } - cleanup - catch i8* bitcast (i8** @_ZTIi to i8*) - %exn1 = extractvalue { i8*, i32 } %l1.0, 0 - %sel1 = extractvalue { i8*, i32 } %l1.0, 1 - %l1.1 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*)) - %matchesl1 = icmp eq i32 %sel1, %l1.1 - br i1 %matchesl1, label %catch, label %eh.resume - -catch: ; preds = %lpad, %lpad1 - %exn2 = phi i8* [%exn, %lpad], [%exn1, %lpad1] - %sel2 = phi i32 [%sel, %lpad], [%sel1, %lpad1] - call void @llvm.eh.begincatch(i8* %exn2, i8* null) - call void @_Z10handle_intv() - %matches1 = icmp eq i32 %sel2, 0 - br i1 %matches1, label %invoke.cont2, label %invoke.cont3 - -invoke.cont2: ; preds = %catch - call void @llvm.eh.endcatch() - br label %try.cont - -invoke.cont3: ; preds = %catch - br label %eh.resume - -try.cont: ; preds = %invoke.cont2, %entry - ret void - -eh.resume: ; preds = %catch.dispatch - %lpad.val = insertvalue { i8*, i32 } undef, i32 0, 1 - resume { i8*, i32 } %lpad.val -} - -declare void @_Z9may_throwv() - -declare i32 @__CxxFrameHandler3(...) - -; Function Attrs: nounwind readnone -declare i32 @llvm.eh.typeid.for(i8*) - -declare void @_Z10handle_intv() - diff --git a/test/CodeGen/WinEH/cppeh-alloca-sink.ll b/test/CodeGen/WinEH/cppeh-alloca-sink.ll deleted file mode 100644 index f215dca2ddd..00000000000 --- a/test/CodeGen/WinEH/cppeh-alloca-sink.ll +++ /dev/null @@ -1,180 +0,0 @@ -; RUN: opt -mtriple=x86_64-pc-windows-msvc -winehprepare -S -o - < %s | FileCheck %s - -; This test describes two difficult cases in sinking allocas into child frames. -; We don't currently do this optimization, but we'll need to tweak these tests -; when we do. - -; This test is based on the following code: -; -; // In this case we can sink the alloca from the parent into the catch because -; // the lifetime is limited to the catch. -; extern "C" void may_throw(); -; extern "C" void sink_alloca_to_catch() { -; try { -; may_throw(); -; } catch (int) { -; volatile int only_used_in_catch = 42; -; } -; } -; -; // In this case we cannot. The variable should live as long as the parent -; // frame lives. -; extern "C" void use_catch_var(int *); -; extern "C" void dont_sink_alloca_to_catch(int n) { -; int live_in_out_catch = 0; -; while (n > 0) { -; try { -; may_throw(); -; } catch (int) { -; use_catch_var(&live_in_out_catch); -; } -; n--; -; } -; } - -target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128" -target triple = "x86_64-pc-windows-msvc" - -declare void @may_throw() #1 -declare i32 @__CxxFrameHandler3(...) -declare i32 @llvm.eh.typeid.for(i8*) #2 -declare void @llvm.eh.begincatch(i8* nocapture, i8* nocapture) #3 -declare void @llvm.eh.endcatch() #3 - -%rtti.TypeDescriptor2 = type { i8**, i8*, [3 x i8] } -%eh.CatchHandlerType = type { i32, i8* } - -$"\01??_R0H@8" = comdat any - -@"\01??_7type_info@@6B@" = external constant i8* -@"\01??_R0H@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".H\00" }, comdat -@llvm.eh.handlertype.H.0 = private unnamed_addr constant %eh.CatchHandlerType { i32 0, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*) }, section "llvm.metadata" - -; Function Attrs: uwtable -define void @sink_alloca_to_catch() #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) { -entry: - %0 = alloca i32 - %only_used_in_catch = alloca i32, align 4 - invoke void @may_throw() - to label %try.cont unwind label %lpad - -lpad: ; preds = %entry - %1 = landingpad { i8*, i32 } - catch %eh.CatchHandlerType* @llvm.eh.handlertype.H.0 - %2 = extractvalue { i8*, i32 } %1, 1 - %3 = tail call i32 @llvm.eh.typeid.for(i8* bitcast (%eh.CatchHandlerType* @llvm.eh.handlertype.H.0 to i8*)) #3 - %matches = icmp eq i32 %2, %3 - br i1 %matches, label %catch, label %eh.resume - -catch: ; preds = %lpad - %4 = extractvalue { i8*, i32 } %1, 0 - call void @llvm.eh.begincatch(i8* %4, i8* null) #3 - store volatile i32 42, i32* %only_used_in_catch, align 4 - tail call void @llvm.eh.endcatch() #3 - br label %try.cont - -try.cont: ; preds = %entry, %catch - ret void - -eh.resume: ; preds = %lpad - resume { i8*, i32 } %1 -} - -; CHECK-LABEL: define void @sink_alloca_to_catch() -; CHECK: call void (...) @llvm.localescape(i32* %only_used_in_catch) - -declare void @use_catch_var(i32*) #1 - -; Function Attrs: uwtable -define void @dont_sink_alloca_to_catch(i32 %n) #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) { -entry: - %0 = alloca i32 - %n.addr = alloca i32, align 4 - %live_in_out_catch = alloca i32, align 4 - %exn.slot = alloca i8* - %ehselector.slot = alloca i32 - store i32 %n, i32* %n.addr, align 4 - br label %while.cond - -while.cond: ; preds = %try.cont, %entry - %1 = load i32, i32* %n.addr, align 4 - %cmp = icmp sgt i32 %1, 0 - br i1 %cmp, label %while.body, label %while.end - -while.body: ; preds = %while.cond - invoke void @may_throw() - to label %invoke.cont unwind label %lpad - -invoke.cont: ; preds = %while.body - br label %try.cont - -lpad: ; preds = %while.body - %2 = landingpad { i8*, i32 } - catch i8* bitcast (%eh.CatchHandlerType* @llvm.eh.handlertype.H.0 to i8*) - %3 = extractvalue { i8*, i32 } %2, 0 - store i8* %3, i8** %exn.slot - %4 = extractvalue { i8*, i32 } %2, 1 - store i32 %4, i32* %ehselector.slot - br label %catch.dispatch - -catch.dispatch: ; preds = %lpad - %sel = load i32, i32* %ehselector.slot - %5 = call i32 @llvm.eh.typeid.for(i8* bitcast (%eh.CatchHandlerType* @llvm.eh.handlertype.H.0 to i8*)) #3 - %matches = icmp eq i32 %sel, %5 - br i1 %matches, label %catch, label %eh.resume - -catch: ; preds = %catch.dispatch - %exn = load i8*, i8** %exn.slot - call void @llvm.eh.begincatch(i8* %exn, i8* null) #3 - invoke void @use_catch_var(i32* %live_in_out_catch) - to label %invoke.cont2 unwind label %lpad1 - -invoke.cont2: ; preds = %catch - call void @llvm.eh.endcatch() #3 - br label %try.cont - -try.cont: ; preds = %invoke.cont2, %invoke.cont - %6 = load i32, i32* %0 - %7 = load i32, i32* %n.addr, align 4 - %dec = add nsw i32 %7, -1 - store i32 %dec, i32* %n.addr, align 4 - br label %while.cond - -lpad1: ; preds = %catch - %8 = landingpad { i8*, i32 } - cleanup - %9 = extractvalue { i8*, i32 } %8, 0 - store i8* %9, i8** %exn.slot - %10 = extractvalue { i8*, i32 } %8, 1 - store i32 %10, i32* %ehselector.slot - call void @llvm.eh.endcatch() #3 - br label %eh.resume - -while.end: ; preds = %while.cond - ret void - -eh.resume: ; preds = %lpad1, %catch.dispatch - %exn3 = load i8*, i8** %exn.slot - %sel4 = load i32, i32* %ehselector.slot - %lpad.val = insertvalue { i8*, i32 } undef, i8* %exn3, 0 - %lpad.val5 = insertvalue { i8*, i32 } %lpad.val, i32 %sel4, 1 - resume { i8*, i32 } %lpad.val5 -} - -; CHECK-LABEL: define void @dont_sink_alloca_to_catch(i32 %n) -; CHECK: call void (...) @llvm.localescape(i32* %live_in_out_catch) - -; CHECK-LABEL: define internal i8* @sink_alloca_to_catch.catch(i8*, i8*) -; CHECK: %only_used_in_catch.i8 = call i8* @llvm.localrecover({{.*}}, i32 0) -; CHECK: %only_used_in_catch = bitcast - -; CHECK-LABEL: define internal i8* @dont_sink_alloca_to_catch.catch(i8*, i8*) -; CHECK: %live_in_out_catch.i8 = call i8* @llvm.localrecover({{.*}}, i32 0) -; CHECK: %live_in_out_catch = bitcast - - - -attributes #0 = { uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "unsafe-fp-math"="false" "use-soft-float"="false" } -attributes #1 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "unsafe-fp-math"="false" "use-soft-float"="false" } -attributes #2 = { nounwind readnone } -attributes #3 = { nounwind } diff --git a/test/CodeGen/WinEH/cppeh-catch-all-win32.ll b/test/CodeGen/WinEH/cppeh-catch-all-win32.ll deleted file mode 100644 index b2e84b90d69..00000000000 --- a/test/CodeGen/WinEH/cppeh-catch-all-win32.ll +++ /dev/null @@ -1,86 +0,0 @@ -; RUN: opt -winehprepare -S -o - < %s | FileCheck %s - -; This test is based on the following code: -; -; extern "C" void may_throw(); -; extern "C" void handle_exception(); -; extern "C" void test() { -; try { -; may_throw(); -; } catch (...) { -; handle_exception(); -; } -; } - -target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32" -target triple = "i686-pc-windows-msvc" - -; The function entry in this case remains unchanged. -; CHECK: define void @test() -; CHECK: entry: -; CHECK: invoke void @may_throw() -; CHECK: to label %invoke.cont unwind label %[[LPAD_LABEL:lpad[0-9]*]] - -define void @test() #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) { -entry: - %exn.slot = alloca i8* - %ehselector.slot = alloca i32 - invoke void @may_throw() - to label %invoke.cont unwind label %lpad - -invoke.cont: ; preds = %entry - br label %try.cont - -; CHECK: [[LPAD_LABEL]]:{{[ ]+}}; preds = %entry -; CHECK: landingpad { i8*, i32 } -; CHECK-NEXT: catch i8* null -; CHECK-NEXT: [[RECOVER:\%.+]] = call i8* (...) @llvm.eh.actions(i32 1, i8* null, i32 -1, i8* ()* @test.catch) -; CHECK-NEXT: indirectbr i8* [[RECOVER]], [label %try.cont] - -lpad: ; preds = %entry - %0 = landingpad { i8*, i32 } - catch i8* null - %1 = extractvalue { i8*, i32 } %0, 0 - store i8* %1, i8** %exn.slot - %2 = extractvalue { i8*, i32 } %0, 1 - store i32 %2, i32* %ehselector.slot - br label %catch - -; CHECK-NOT: catch: -; CHECK-NOT: @handle_exception() - -catch: ; preds = %lpad - %exn = load i8*, i8** %exn.slot - call void @llvm.eh.begincatch(i8* %exn, i8* null) #1 - call void @handle_exception() - call void @llvm.eh.endcatch() #1 - br label %try.cont - -try.cont: ; preds = %catch, %invoke.cont - ret void - -; CHECK: } -} - -; CHECK: define internal i8* @test.catch() -; CHECK: call i8* @llvm.frameaddress(i32 1) -; CHECK: call i8* @llvm.x86.seh.recoverfp(i8* bitcast (void ()* @test to i8*), i8* %{{.*}}) -; CHECK: call void @handle_exception() -; CHECK: ret i8* blockaddress(@test, %try.cont) -; CHECK: } - - -declare void @may_throw() #0 - -declare i32 @__CxxFrameHandler3(...) - -; Function Attrs: nounwind -declare void @llvm.eh.begincatch(i8* nocapture, i8* nocapture) #1 - -declare void @handle_exception() #0 - -; Function Attrs: nounwind -declare void @llvm.eh.endcatch() #1 - -attributes #0 = { "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } -attributes #1 = { nounwind } diff --git a/test/CodeGen/WinEH/cppeh-catch-and-throw.ll b/test/CodeGen/WinEH/cppeh-catch-and-throw.ll deleted file mode 100644 index d604b86deb3..00000000000 --- a/test/CodeGen/WinEH/cppeh-catch-and-throw.ll +++ /dev/null @@ -1,143 +0,0 @@ -; RUN: opt -mtriple=x86_64-pc-windows-msvc -winehprepare -S -o - < %s | FileCheck %s - -; This test is based on the following code: -; -; class Obj { -; public: -; ~Obj(); -; }; -; -; void test(void) -; { -; try { -; Obj o; -; throw 1; -; } catch (...) { -; throw; -; } -; } - -; ModuleID = 'cppeh-catch-and-throw.cpp' -target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128" -target triple = "x86_64-pc-windows-msvc" - -%rtti.TypeDescriptor2 = type { i8**, i8*, [3 x i8] } -%eh.CatchableType = type { i32, i32, i32, i32, i32, i32, i32 } -%eh.CatchableTypeArray.1 = type { i32, [1 x i32] } -%eh.ThrowInfo = type { i32, i32, i32, i32 } -%class.Obj = type { i8 } - -$"\01??_R0H@8" = comdat any - -$"_CT??_R0H@84" = comdat any - -$_CTA1H = comdat any - -$_TI1H = comdat any - -@"\01??_7type_info@@6B@" = external constant i8* -@"\01??_R0H@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".H\00" }, comdat -@__ImageBase = external constant i8 -@"_CT??_R0H@84" = linkonce_odr unnamed_addr constant %eh.CatchableType { i32 1, i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32), i32 0, i32 -1, i32 0, i32 4, i32 0 }, section ".xdata", comdat -@_CTA1H = linkonce_odr unnamed_addr constant %eh.CatchableTypeArray.1 { i32 1, [1 x i32] [i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%eh.CatchableType* @"_CT??_R0H@84" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32)] }, section ".xdata", comdat -@_TI1H = linkonce_odr unnamed_addr constant %eh.ThrowInfo { i32 0, i32 0, i32 0, i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%eh.CatchableTypeArray.1* @_CTA1H to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32) }, section ".xdata", comdat - -; This is just a minimal check to verify that main was handled by WinEHPrepare. -; CHECK: define void @"\01?test@@YAXXZ"() -; CHECK: entry: -; CHECK: call void (...) @llvm.localescape -; CHECK: invoke void @_CxxThrowException -; CHECK: } - -; Function Attrs: uwtable -define void @"\01?test@@YAXXZ"() #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) { -entry: - %o = alloca %class.Obj, align 1 - %tmp = alloca i32, align 4 - %exn.slot = alloca i8* - %ehselector.slot = alloca i32 - store i32 1, i32* %tmp - %0 = bitcast i32* %tmp to i8* - invoke void @_CxxThrowException(i8* %0, %eh.ThrowInfo* @_TI1H) #3 - to label %unreachable unwind label %lpad - -lpad: ; preds = %entry - %1 = landingpad { i8*, i32 } - catch i8* null - %2 = extractvalue { i8*, i32 } %1, 0 - store i8* %2, i8** %exn.slot - %3 = extractvalue { i8*, i32 } %1, 1 - store i32 %3, i32* %ehselector.slot - call void @"\01??1Obj@@QEAA@XZ"(%class.Obj* %o) #2 - br label %catch - -catch: ; preds = %lpad - %exn = load i8*, i8** %exn.slot - call void @llvm.eh.begincatch(i8* %exn, i8* null) #2 - invoke void @_CxxThrowException(i8* null, %eh.ThrowInfo* null) #3 - to label %unreachable unwind label %lpad1 - -lpad1: ; preds = %catch - %4 = landingpad { i8*, i32 } - cleanup - %5 = extractvalue { i8*, i32 } %4, 0 - store i8* %5, i8** %exn.slot - %6 = extractvalue { i8*, i32 } %4, 1 - store i32 %6, i32* %ehselector.slot - call void @llvm.eh.endcatch() #2 - br label %eh.resume - -try.cont: ; No predecessors! - ret void - -eh.resume: ; preds = %lpad1 - %exn2 = load i8*, i8** %exn.slot - %sel = load i32, i32* %ehselector.slot - %lpad.val = insertvalue { i8*, i32 } undef, i8* %exn2, 0 - %lpad.val3 = insertvalue { i8*, i32 } %lpad.val, i32 %sel, 1 - resume { i8*, i32 } %lpad.val3 - -unreachable: ; preds = %catch, %entry - unreachable -} - -; Verify that we inserted a stub invoke into the outlined cleanup handler. -; -; CHECK-LABEL: define internal void @"\01?test@@YAXXZ.cleanup"(i8*, i8*) -; CHECK: entry: -; CHECK: call i8* @llvm.localrecover -; CHECK: call void @"\01??1Obj@@QEAA@XZ" -; CHECK: invoke void @llvm.donothing() -; CHECK: to label %[[SPLIT_LABEL:.+]] unwind label %[[LPAD_LABEL:.+]] -; -; CHECK: [[SPLIT_LABEL]] -; -; CHECK: [[LPAD_LABEL]] -; CHECK: landingpad { i8*, i32 } -; CHECK: cleanup -; CHECK: unreachable -; CHECK: } - -declare void @_CxxThrowException(i8*, %eh.ThrowInfo*) - -declare i32 @__CxxFrameHandler3(...) - -; Function Attrs: nounwind -declare void @"\01??1Obj@@QEAA@XZ"(%class.Obj*) #1 - -; Function Attrs: nounwind -declare void @llvm.eh.begincatch(i8* nocapture, i8* nocapture) #2 - -; Function Attrs: nounwind -declare void @llvm.eh.endcatch() #2 - -attributes #0 = { uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "unsafe-fp-math"="false" "use-soft-float"="false" } -attributes #1 = { nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "unsafe-fp-math"="false" "use-soft-float"="false" } -attributes #2 = { nounwind } -attributes #3 = { noreturn } - -!llvm.module.flags = !{!0} -!llvm.ident = !{!1} - -!0 = !{i32 1, !"PIC Level", i32 2} -!1 = !{!"clang version 3.7.0 (trunk 235214) (llvm/trunk 235213)"} diff --git a/test/CodeGen/WinEH/cppeh-catch-scalar.ll b/test/CodeGen/WinEH/cppeh-catch-scalar.ll deleted file mode 100644 index 3b5ab746d63..00000000000 --- a/test/CodeGen/WinEH/cppeh-catch-scalar.ll +++ /dev/null @@ -1,126 +0,0 @@ -; RUN: opt -mtriple=x86_64-pc-windows-msvc -winehprepare -S -o - < %s | FileCheck %s - -; This test is based on the following code: -; -; void test() -; { -; try { -; may_throw(); -; } catch (int i) { -; handle_int(i); -; } -; } -; -; Parts of the IR have been hand-edited to simplify the test case. -; The full IR will be restored when Windows C++ EH support is complete. - -;ModuleID = 'cppeh-catch-scalar.cpp' -target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" -target triple = "x86_64-pc-windows-msvc" - -@_ZTIi = external constant i8* - -; The function entry will be rewritten like this. -; CHECK: define void @_Z4testv() -; CHECK: entry: -; CHECK: [[I_PTR:\%.+]] = alloca i32, align 4 -; CHECK: call void (...) @llvm.localescape(i32* [[I_PTR]]) -; CHECK: invoke void @_Z9may_throwv() -; CHECK: to label %invoke.cont unwind label %[[LPAD_LABEL:lpad[0-9]*]] - -; Function Attrs: uwtable -define void @_Z4testv() #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) { -entry: - %exn.slot = alloca i8* - %ehselector.slot = alloca i32 - %i = alloca i32, align 4 - invoke void @_Z9may_throwv() - to label %invoke.cont unwind label %lpad - -invoke.cont: ; preds = %entry - br label %try.cont - -; CHECK: [[LPAD_LABEL]]:{{[ ]+}}; preds = %entry -; CHECK: landingpad { i8*, i32 } -; CHECK-NEXT: catch i8* bitcast (i8** @_ZTIi to i8*) -; CHECK-NEXT: [[RECOVER:\%.+]] = call i8* (...) @llvm.eh.actions(i32 1, i8* bitcast (i8** @_ZTIi to i8*), i32 0, i8* (i8*, i8*)* @_Z4testv.catch) -; CHECK-NEXT: indirectbr i8* [[RECOVER]], [label %try.cont] - -lpad: ; preds = %entry - %tmp = landingpad { i8*, i32 } - catch i8* bitcast (i8** @_ZTIi to i8*) - %tmp1 = extractvalue { i8*, i32 } %tmp, 0 - store i8* %tmp1, i8** %exn.slot - %tmp2 = extractvalue { i8*, i32 } %tmp, 1 - store i32 %tmp2, i32* %ehselector.slot - br label %catch.dispatch - -; CHECK-NOT: catch-dispatch: - -catch.dispatch: ; preds = %lpad - %sel = load i32, i32* %ehselector.slot - %tmp3 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*)) #3 - %matches = icmp eq i32 %sel, %tmp3 - br i1 %matches, label %catch, label %eh.resume - -; CHECK-NOT: catch: - -catch: ; preds = %catch.dispatch - %exn11 = load i8*, i8** %exn.slot - %i.i8 = bitcast i32* %i to i8* - call void @llvm.eh.begincatch(i8* %exn11, i8* %i.i8) #3 - %tmp7 = load i32, i32* %i, align 4 - call void @_Z10handle_inti(i32 %tmp7) - br label %invoke.cont2 - -; CHECK-NOT: invoke.cont2: - -invoke.cont2: ; preds = %catch - call void @llvm.eh.endcatch() #3 - br label %try.cont - -try.cont: ; preds = %invoke.cont2, %invoke.cont - ret void - -; CHECK-NOT: eh.resume: - -eh.resume: ; preds = %catch.dispatch - %exn3 = load i8*, i8** %exn.slot - %sel4 = load i32, i32* %ehselector.slot - %lpad.val = insertvalue { i8*, i32 } undef, i8* %exn3, 0 - %lpad.val5 = insertvalue { i8*, i32 } %lpad.val, i32 %sel4, 1 - resume { i8*, i32 } %lpad.val5 - -; CHECK: } -} - -; CHECK: define internal i8* @_Z4testv.catch(i8*, i8*) -; CHECK: entry: -; CHECK: [[RECOVER_I:\%.+]] = call i8* @llvm.localrecover(i8* bitcast (void ()* @_Z4testv to i8*), i8* %1, i32 0) -; CHECK: [[I_PTR1:\%.+]] = bitcast i8* [[RECOVER_I]] to i32* -; CHECK: [[TMP:\%.+]] = load i32, i32* [[I_PTR1]], align 4 -; CHECK: call void @_Z10handle_inti(i32 [[TMP]]) -; CHECK: ret i8* blockaddress(@_Z4testv, %try.cont) -; CHECK: } - -declare void @_Z9may_throwv() #1 - -declare i32 @__CxxFrameHandler3(...) - -; Function Attrs: nounwind readnone -declare i32 @llvm.eh.typeid.for(i8*) #2 - -declare void @llvm.eh.begincatch(i8*, i8*) - -declare void @llvm.eh.endcatch() - -declare void @_Z10handle_inti(i32) #1 - -attributes #0 = { uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } -attributes #1 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } -attributes #2 = { nounwind readnone } -attributes #3 = { nounwind } - -!llvm.ident = !{!0} - -!0 = !{!"clang version 3.7.0 (trunk 227474) (llvm/trunk 227508)"} diff --git a/test/CodeGen/WinEH/cppeh-catch-unwind.ll b/test/CodeGen/WinEH/cppeh-catch-unwind.ll deleted file mode 100644 index 8fdda9bbc02..00000000000 --- a/test/CodeGen/WinEH/cppeh-catch-unwind.ll +++ /dev/null @@ -1,240 +0,0 @@ -; RUN: opt -mtriple=x86_64-pc-windows-msvc -winehprepare -S -o - < %s | FileCheck %s - -; This test was generated from the following source: -; -; void test() { -; try { -; SomeClass obj; -; may_throw(); -; try { -; may_throw(); -; } catch (int) { -; handle_exception(); -; } -; } catch (int) { -; handle_exception(); -; } -; } -; -; The code above was compiled with the -O2 option. - -; ModuleID = 'catch-unwind.cpp' -target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" -target triple = "x86_64-pc-windows-msvc" - -%rtti.TypeDescriptor2 = type { i8**, i8*, [3 x i8] } -%class.SomeClass = type { i8 } - -$"\01??_R0H@8" = comdat any - -@"\01??_7type_info@@6B@" = external constant i8* -@"\01??_R0H@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".H\00" }, comdat - - -; CHECK-LABEL: define void @"\01?test@@YAXXZ"() #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) { -; CHECK: entry: -; CHECK: [[OBJ_PTR:\%.+]] = alloca %class.SomeClass -; CHECK: [[TMP0:\%.+]] = alloca i32, align 4 -; CHECK: [[TMP1:\%.+]] = alloca i32, align 4 -; CHECK: call void (...) @llvm.localescape(i32* [[TMP1]], %class.SomeClass* [[OBJ_PTR]], i32* [[TMP0]]) -; CHECK: %call = invoke %class.SomeClass* @"\01??0SomeClass@@QEAA@XZ"(%class.SomeClass* %obj) -; CHECK: to label %invoke.cont unwind label %[[LPAD_LABEL:lpad[0-9]*]] - -; Function Attrs: uwtable -define void @"\01?test@@YAXXZ"() #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) { -entry: - %obj = alloca %class.SomeClass, align 1 - %0 = alloca i32, align 4 - %1 = alloca i32, align 4 - %call = invoke %class.SomeClass* @"\01??0SomeClass@@QEAA@XZ"(%class.SomeClass* %obj) - to label %invoke.cont unwind label %lpad - -; CHECK: invoke.cont: -; CHECK: invoke void @"\01?may_throw@@YAXXZ"() -; CHECK: to label %invoke.cont2 unwind label %[[LPAD1_LABEL:lpad[0-9]*]] - -invoke.cont: ; preds = %entry - invoke void @"\01?may_throw@@YAXXZ"() - to label %invoke.cont2 unwind label %lpad1 - -; CHECK: invoke.cont2: -; CHECK: invoke void @"\01?may_throw@@YAXXZ"() -; CHECK: to label %try.cont unwind label %[[LPAD3_LABEL:lpad[0-9]*]] - -invoke.cont2: ; preds = %invoke.cont - invoke void @"\01?may_throw@@YAXXZ"() - to label %try.cont unwind label %lpad3 - -; CHECK: [[LPAD_LABEL]]:{{[ ]+}}; preds = %entry -; CHECK: [[LPAD_VAL:\%.+]] = landingpad { i8*, i32 } -; CHECK-NEXT: catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*) -; CHECK-NEXT: [[RECOVER:\%.+]] = call i8* (...) @llvm.eh.actions(i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*), i32 0, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch") -; CHECK-NEXT: indirectbr i8* [[RECOVER]], [label %try.cont15] - -lpad: ; preds = %entry - %2 = landingpad { i8*, i32 } - catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*) - %3 = extractvalue { i8*, i32 } %2, 0 - %4 = extractvalue { i8*, i32 } %2, 1 - br label %catch.dispatch7 - -; CHECK: [[LPAD1_LABEL]]:{{[ ]+}}; preds = %invoke.cont -; CHECK: [[LPAD1_VAL:\%.+]] = landingpad { i8*, i32 } -; CHECK-NEXT: cleanup -; CHECK-NEXT: catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*) -; CHECK-NEXT: [[RECOVER1:\%.+]] = call i8* (...) @llvm.eh.actions(i32 0, void (i8*, i8*)* @"\01?test@@YAXXZ.cleanup", i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*), i32 0, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch") -; CHECK-NEXT: indirectbr i8* [[RECOVER1]], [label %try.cont15] - -lpad1: ; preds = %invoke.cont - %5 = landingpad { i8*, i32 } - cleanup - catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*) - %6 = extractvalue { i8*, i32 } %5, 0 - %7 = extractvalue { i8*, i32 } %5, 1 - br label %ehcleanup - -; CHECK: [[LPAD3_LABEL]]:{{[ ]+}}; preds = %invoke.cont2 -; CHECK: [[LPAD3_VAL:\%.+]] = landingpad { i8*, i32 } -; CHECK-NEXT: cleanup -; CHECK-NEXT: catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*) -; CHECK-NEXT: [[RECOVER3:\%.+]] = call i8* (...) @llvm.eh.actions(i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*), i32 2, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch.1", i32 0, void (i8*, i8*)* @"\01?test@@YAXXZ.cleanup") -; CHECK-NEXT: indirectbr i8* [[RECOVER3]], [label %try.cont, label %try.cont15] - -lpad3: ; preds = %invoke.cont2 - %8 = landingpad { i8*, i32 } - cleanup - catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*) - %9 = extractvalue { i8*, i32 } %8, 0 - %10 = extractvalue { i8*, i32 } %8, 1 - %11 = call i32 @llvm.eh.typeid.for(i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*)) #3 - %matches = icmp eq i32 %10, %11 - br i1 %matches, label %catch, label %ehcleanup - -; CHECK-NOT: catch: -catch: ; preds = %lpad3 - %12 = bitcast i32* %0 to i8* - call void @llvm.eh.begincatch(i8* %9, i8* %12) #3 - invoke void @"\01?handle_exception@@YAXXZ"() - to label %invoke.cont6 unwind label %lpad5 - -; CHECK-NOT: invoke.cont6: -invoke.cont6: ; preds = %catch - call void @llvm.eh.endcatch() #3 - br label %try.cont - -try.cont: ; preds = %invoke.cont2, %invoke.cont6 - call void @"\01??1SomeClass@@QEAA@XZ"(%class.SomeClass* %obj) #3 - br label %try.cont15 - -; CHECK-NOT: lpad5: -lpad5: ; preds = %catch - %13 = landingpad { i8*, i32 } - cleanup - catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*) - %14 = extractvalue { i8*, i32 } %13, 0 - %15 = extractvalue { i8*, i32 } %13, 1 - call void @llvm.eh.endcatch() #3 - br label %ehcleanup - -; CHECK-NOT: ehcleanup -ehcleanup: ; preds = %lpad5, %lpad3, %lpad1 - %exn.slot.0 = phi i8* [ %14, %lpad5 ], [ %9, %lpad3 ], [ %6, %lpad1 ] - %ehselector.slot.0 = phi i32 [ %15, %lpad5 ], [ %10, %lpad3 ], [ %7, %lpad1 ] - call void @"\01??1SomeClass@@QEAA@XZ"(%class.SomeClass* %obj) #3 - br label %catch.dispatch7 - -; CHECK-NOT: catch.dispatch7: -catch.dispatch7: ; preds = %ehcleanup, %lpad - %exn.slot.1 = phi i8* [ %exn.slot.0, %ehcleanup ], [ %3, %lpad ] - %ehselector.slot.1 = phi i32 [ %ehselector.slot.0, %ehcleanup ], [ %4, %lpad ] - %16 = call i32 @llvm.eh.typeid.for(i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*)) #3 - %matches9 = icmp eq i32 %ehselector.slot.1, %16 - br i1 %matches9, label %catch10, label %eh.resume - -; CHECK-NOT: catch10: -catch10: ; preds = %catch.dispatch7 - %17 = bitcast i32* %1 to i8* - call void @llvm.eh.begincatch(i8* %exn.slot.1, i8* %17) #3 - call void @"\01?handle_exception@@YAXXZ"() - br label %invoke.cont13 - -; CHECK-NOT: invoke.cont13: -invoke.cont13: ; preds = %catch10 - call void @llvm.eh.endcatch() #3 - br label %try.cont15 - -try.cont15: ; preds = %invoke.cont13, %try.cont - ret void - -; CHECK-NOT: eh.resume -eh.resume: ; preds = %catch.dispatch7 - %lpad.val = insertvalue { i8*, i32 } undef, i8* %exn.slot.1, 0 - %lpad.val18 = insertvalue { i8*, i32 } %lpad.val, i32 %ehselector.slot.1, 1 - resume { i8*, i32 } %lpad.val18 - -; CHECK: } -} - -; CHECK-LABEL: define internal i8* @"\01?test@@YAXXZ.catch"(i8*, i8*) -; CHECK: entry: -; CHECK: [[RECOVER_TMP1:\%.+]] = call i8* @llvm.localrecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 0) -; CHECK: [[TMP1_PTR:\%.+]] = bitcast i8* [[RECOVER_TMP1]] to i32* -; CHECK: call void @"\01?handle_exception@@YAXXZ"() -; CHECK: ret i8* blockaddress(@"\01?test@@YAXXZ", %try.cont15) -; CHECK: } - -; CHECK-LABEL: define internal void @"\01?test@@YAXXZ.cleanup"(i8*, i8*) -; CHECK: entry: -; CHECK: [[RECOVER_OBJ:\%.+]] = call i8* @llvm.localrecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 1) -; CHECK: [[OBJ_PTR:\%.+]] = bitcast i8* %obj.i8 to %class.SomeClass* -; CHECK: call void @"\01??1SomeClass@@QEAA@XZ"(%class.SomeClass* [[OBJ_PTR]]) -; CHECK: ret void -; CHECK: } - -; CHECK-LABEL: define internal i8* @"\01?test@@YAXXZ.catch.1"(i8*, i8*) -; CHECK: entry: -; CHECK: [[RECOVER_TMP0:\%.+]] = call i8* @llvm.localrecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 2) -; CHECK: [[TMP0_PTR:\%.+]] = bitcast i8* [[RECOVER_TMP0]] to i32* -; CHECK: invoke void @"\01?handle_exception@@YAXXZ"() -; CHECK: to label %invoke.cont6 unwind label %[[LPAD5_LABEL:lpad[0-9]+]] -; -; CHECK: invoke.cont6: ; preds = %entry -; CHECK: ret i8* blockaddress(@"\01?test@@YAXXZ", %try.cont) -; -; CHECK: [[LPAD5_LABEL]]:{{[ ]+}}; preds = %entry -; CHECK: [[LPAD5_VAL:\%.+]] = landingpad { i8*, i32 } -; CHECK: cleanup -; CHECK: catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*) -; CHECK: } - -declare %class.SomeClass* @"\01??0SomeClass@@QEAA@XZ"(%class.SomeClass* returned) #1 - -declare i32 @__CxxFrameHandler3(...) - -declare void @"\01?may_throw@@YAXXZ"() #1 - -; Function Attrs: nounwind readnone -declare i32 @llvm.eh.typeid.for(i8*) #2 - -; Function Attrs: nounwind -declare void @llvm.eh.begincatch(i8* nocapture, i8* nocapture) #3 - -declare void @"\01?handle_exception@@YAXXZ"() #1 - -; Function Attrs: nounwind -declare void @llvm.eh.endcatch() #3 - -; Function Attrs: nounwind -declare void @"\01??1SomeClass@@QEAA@XZ"(%class.SomeClass*) #4 - -attributes #0 = { uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } -attributes #1 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } -attributes #2 = { nounwind readnone } -attributes #3 = { nounwind } -attributes #4 = { nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } - -!llvm.module.flags = !{!0} -!llvm.ident = !{!1} - -!0 = !{i32 1, !"PIC Level", i32 2} -!1 = !{!"clang version 3.7.0 (trunk 232069) (llvm/trunk 232070)"} diff --git a/test/CodeGen/WinEH/cppeh-cleanup-invoke.ll b/test/CodeGen/WinEH/cppeh-cleanup-invoke.ll deleted file mode 100644 index 7e5f659f2a4..00000000000 --- a/test/CodeGen/WinEH/cppeh-cleanup-invoke.ll +++ /dev/null @@ -1,91 +0,0 @@ -; RUN: opt -winehprepare -S < %s | FileCheck %s - -target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128" -target triple = "x86_64-pc-windows-msvc" - -; Modified based on this code: -; struct HasDtor { -; ~HasDtor(); -; }; -; extern "C" void may_throw(); -; int main() { -; try { -; HasDtor o; -; may_throw(); -; } catch (int) { -; } -; } - -%rtti.TypeDescriptor2 = type { i8**, i8*, [3 x i8] } -%eh.CatchHandlerType = type { i32, i8* } -%struct.HasDtor = type { i8 } - -$"\01??_R0H@8" = comdat any - -@"\01??_7type_info@@6B@" = external constant i8* -@"\01??_R0H@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".H\00" }, comdat -@llvm.eh.handlertype.H.0 = private unnamed_addr constant %eh.CatchHandlerType { i32 0, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*) }, section "llvm.metadata" - -define i32 @main() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) { -entry: - %o = alloca %struct.HasDtor, align 1 - invoke void @may_throw() - to label %invoke.cont2 unwind label %lpad1 - -invoke.cont2: ; preds = %invoke.cont - call void @"\01??1HasDtor@@QEAA@XZ"(%struct.HasDtor* %o) - br label %try.cont - -lpad: ; preds = %entry - %0 = landingpad { i8*, i32 } - catch %eh.CatchHandlerType* @llvm.eh.handlertype.H.0 - %1 = extractvalue { i8*, i32 } %0, 0 - %2 = extractvalue { i8*, i32 } %0, 1 - br label %catch.dispatch - -lpad1: ; preds = %invoke.cont - %3 = landingpad { i8*, i32 } - cleanup - catch %eh.CatchHandlerType* @llvm.eh.handlertype.H.0 - %4 = extractvalue { i8*, i32 } %3, 0 - %5 = extractvalue { i8*, i32 } %3, 1 - invoke void @"\01??1HasDtor@@QEAA@XZ"(%struct.HasDtor* %o) - to label %catch.dispatch unwind label %lpad - -catch.dispatch: ; preds = %lpad1, %lpad - %exn.slot.0 = phi i8* [ %4, %lpad1 ], [ %1, %lpad ] - %ehselector.slot.0 = phi i32 [ %5, %lpad1 ], [ %2, %lpad ] - %6 = call i32 @llvm.eh.typeid.for(i8* bitcast (%eh.CatchHandlerType* @llvm.eh.handlertype.H.0 to i8*)) - %matches = icmp eq i32 %ehselector.slot.0, %6 - br i1 %matches, label %catch, label %eh.resume - -catch: ; preds = %catch.dispatch - call void @llvm.eh.begincatch(i8* %exn.slot.0, i8* null) - call void @llvm.eh.endcatch() - br label %try.cont - -try.cont: ; preds = %catch, %invoke.cont2 - ret i32 0 - -eh.resume: ; preds = %catch.dispatch - %lpad.val = insertvalue { i8*, i32 } undef, i8* %exn.slot.0, 0 - %lpad.val5 = insertvalue { i8*, i32 } %lpad.val, i32 %ehselector.slot.0, 1 - resume { i8*, i32 } %lpad.val5 -} - -; CHECK-LABEL: define i32 @main() -; CHECK: @llvm.eh.actions(i32 0, void (i8*, i8*)* @main.cleanup, i32 1, i8* bitcast (%eh.CatchHandlerType* @llvm.eh.handlertype.H.0 to i8*), i32 -1, i8* (i8*, i8*)* @main.catch) - -; CHECK-LABEL: define internal void @main.cleanup(i8*, i8*) -; CHECK: call void @"\01??1HasDtor@@QEAA@XZ"(%struct.HasDtor* %{{.*}}) -; CHECK: ret void - -declare void @may_throw() - -declare i32 @__CxxFrameHandler3(...) - -declare void @"\01??1HasDtor@@QEAA@XZ"(%struct.HasDtor*) - -declare i32 @llvm.eh.typeid.for(i8*) -declare void @llvm.eh.begincatch(i8* nocapture, i8* nocapture) -declare void @llvm.eh.endcatch() diff --git a/test/CodeGen/WinEH/cppeh-demote-liveout.ll b/test/CodeGen/WinEH/cppeh-demote-liveout.ll deleted file mode 100644 index 309952bfc94..00000000000 --- a/test/CodeGen/WinEH/cppeh-demote-liveout.ll +++ /dev/null @@ -1,72 +0,0 @@ -; RUN: opt -mtriple=x86_64-pc-windows-msvc -winehprepare -S < %s | FileCheck %s - -; Notionally based on this C++ source: -; int liveout_catch(int p) { -; int val = p + 1; -; try { -; might_throw(); -; } catch (int) { -; val++; -; } -; return val; -; } - -declare void @llvm.eh.begincatch(i8*, i8*) -declare void @llvm.eh.endcatch() -declare void @might_throw() -declare i32 @__CxxFrameHandler3(...) -declare i32 @llvm.eh.typeid.for(i8*) - -@typeinfo.int = external global i32 - -define i32 @liveout_catch(i32 %p) personality i32 (...)* @__CxxFrameHandler3 { -entry: - %val.entry = add i32 %p, 1 - invoke void @might_throw() - to label %ret unwind label %lpad - -lpad: - %ehvals = landingpad { i8*, i32 } - cleanup - catch i32* @typeinfo.int - %ehptr = extractvalue { i8*, i32 } %ehvals, 0 - %sel = extractvalue { i8*, i32 } %ehvals, 1 - %int_sel = call i32 @llvm.eh.typeid.for(i8* bitcast (i32* @typeinfo.int to i8*)) - %match = icmp eq i32 %sel, %int_sel - br i1 %match, label %catchit, label %resume - -catchit: - call void @llvm.eh.begincatch(i8* %ehptr, i8* null) - %val.lpad = add i32 %val.entry, 1 - call void @llvm.eh.endcatch() - br label %ret - -ret: - %rv = phi i32 [%val.entry, %entry], [%val.lpad, %catchit] - ret i32 %rv - -resume: - resume {i8*, i32} %ehvals -} - -; CHECK-LABEL: define i32 @liveout_catch(i32 %p) -; CHECK: %val.entry = add i32 %p, 1 -; CHECK-NEXT: store i32 %val.entry, i32* %val.entry.reg2mem -; CHECK: invoke void @might_throw() -; -; CHECK: landingpad -; CHECK: indirectbr i8* {{.*}}, [label %catchit.split] -; -; CHECK: catchit.split: -; CHECK: load i32, i32* %val.lpad.reg2mem -; CHECK: br label %ret -; -; CHECK: ret: -; CHECK: %rv = phi i32 [ {{.*}}, %entry ], [ {{.*}}, %catchit.split ] -; CHECK: ret i32 - -; CHECK-LABEL: define internal i8* @liveout_catch.catch(i8*, i8*) -; CHECK: %[[val:[^ ]*]] = load i32, i32* -; CHECK-NEXT: %[[val_lpad:[^ ]*]] = add i32 %[[val]], 1 -; CHECK-NEXT: store i32 %[[val_lpad]], i32* -; CHECK: ret i8* blockaddress(@liveout_catch, %catchit.split) diff --git a/test/CodeGen/WinEH/cppeh-frame-vars.ll b/test/CodeGen/WinEH/cppeh-frame-vars.ll deleted file mode 100644 index c2dbd8ecab6..00000000000 --- a/test/CodeGen/WinEH/cppeh-frame-vars.ll +++ /dev/null @@ -1,272 +0,0 @@ -; RUN: opt -mtriple=x86_64-pc-windows-msvc -winehprepare -S -o - < %s | FileCheck %s - -; This test is based on the following code: -; -; struct SomeData { -; int a; -; int b; -; }; -; -; void may_throw(); -; void does_not_throw(int i); -; void dump(int *, int, SomeData&); -; -; void test() { -; int NumExceptions = 0; -; int ExceptionVal[10]; -; SomeData Data = { 0, 0 }; -; -; for (int i = 0; i < 10; ++i) { -; try { -; may_throw(); -; Data.a += i; -; } -; catch (int e) { -; ExceptionVal[NumExceptions] = e; -; ++NumExceptions; -; if (e == i) -; Data.b += e; -; else -; Data.a += e; -; } -; does_not_throw(NumExceptions); -; } -; dump(ExceptionVal, NumExceptions, Data); -; } - -; ModuleID = 'cppeh-frame-vars.cpp' -target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" -target triple = "x86_64-pc-windows-msvc" - -%rtti.TypeDescriptor2 = type { i8**, i8*, [3 x i8] } -%struct.SomeData = type { i32, i32 } - -$"\01??_R0H@8" = comdat any - -@"\01??_7type_info@@6B@" = external constant i8* -@"\01??_R0H@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".H\00" }, comdat - -; The function entry should be rewritten like this. -; CHECK: define void @"\01?test@@YAXXZ"() -; CHECK: entry: -; CHECK: [[NUMEXCEPTIONS_PTR:\%.+]] = alloca i32, align 4 -; CHECK: [[EXCEPTIONVAL_PTR:\%.+]] = alloca [10 x i32], align 16 -; CHECK: [[DATA_PTR:\%.+]] = alloca %struct.SomeData, align 4 -; CHECK: [[I_PTR:\%.+]] = alloca i32, align 4 -; CHECK: [[E_PTR:\%.+]] = alloca i32, align 4 -; CHECK: store i32 0, i32* [[NUMEXCEPTIONS_PTR]], align 4 -; CHECK: [[TMP:\%.+]] = bitcast %struct.SomeData* [[DATA_PTR]] to i8* -; CHECK: call void @llvm.memset(i8* [[TMP]], i8 0, i64 8, i32 4, i1 false) -; CHECK: store i32 0, i32* [[I_PTR]], align 4 -; CHECK: call void (...) @llvm.localescape(i32* [[E_PTR]], i32* [[NUMEXCEPTIONS_PTR]], [10 x i32]* [[EXCEPTIONVAL_PTR]], i32* [[I_PTR]], %struct.SomeData* [[DATA_PTR]]) -; CHECK: br label %for.cond - -; Function Attrs: uwtable -define void @"\01?test@@YAXXZ"() #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) { -entry: - %NumExceptions = alloca i32, align 4 - %ExceptionVal = alloca [10 x i32], align 16 - %Data = alloca %struct.SomeData, align 4 - %i = alloca i32, align 4 - %exn.slot = alloca i8* - %ehselector.slot = alloca i32 - %e = alloca i32, align 4 - store i32 0, i32* %NumExceptions, align 4 - %tmp = bitcast %struct.SomeData* %Data to i8* - call void @llvm.memset(i8* %tmp, i8 0, i64 8, i32 4, i1 false) - store i32 0, i32* %i, align 4 - br label %for.cond - -for.cond: ; preds = %for.inc, %entry - %tmp1 = load i32, i32* %i, align 4 - %cmp = icmp slt i32 %tmp1, 10 - br i1 %cmp, label %for.body, label %for.end - -; CHECK: for.body: -; CHECK: invoke void @"\01?may_throw@@YAXXZ"() -; CHECK: to label %invoke.cont unwind label %[[LPAD_LABEL:lpad[0-9]*]] - -for.body: ; preds = %for.cond - invoke void @"\01?may_throw@@YAXXZ"() - to label %invoke.cont unwind label %lpad - -invoke.cont: ; preds = %for.body - %tmp2 = load i32, i32* %i, align 4 - %a = getelementptr inbounds %struct.SomeData, %struct.SomeData* %Data, i32 0, i32 0 - %tmp3 = load i32, i32* %a, align 4 - %add = add nsw i32 %tmp3, %tmp2 - store i32 %add, i32* %a, align 4 - br label %try.cont - -; CHECK: [[LPAD_LABEL]]:{{[ ]+}}; preds = %for.body -; CHECK: landingpad { i8*, i32 } -; CHECK-NEXT: catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*) -; CHECK-NEXT: [[RECOVER:\%.+]] = call i8* (...) @llvm.eh.actions(i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*), i32 0, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch") -; CHECK-NEXT: indirectbr i8* [[RECOVER]], [label %try.cont] - -lpad: ; preds = %for.body - %tmp4 = landingpad { i8*, i32 } - catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*) - %tmp5 = extractvalue { i8*, i32 } %tmp4, 0 - store i8* %tmp5, i8** %exn.slot - %tmp6 = extractvalue { i8*, i32 } %tmp4, 1 - store i32 %tmp6, i32* %ehselector.slot - br label %catch.dispatch - -; CHECK-NOT: catch.dispatch: - -catch.dispatch: ; preds = %lpad - %sel = load i32, i32* %ehselector.slot - %tmp7 = call i32 @llvm.eh.typeid.for(i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*)) #1 - %matches = icmp eq i32 %sel, %tmp7 - br i1 %matches, label %catch, label %eh.resume - -; CHECK-NOT: catch: - -catch: ; preds = %catch.dispatch - %exn = load i8*, i8** %exn.slot - %e.i8 = bitcast i32* %e to i8* - call void @llvm.eh.begincatch(i8* %exn, i8* %e.i8) #1 - %tmp11 = load i32, i32* %e, align 4 - %tmp12 = load i32, i32* %NumExceptions, align 4 - %idxprom = sext i32 %tmp12 to i64 - %arrayidx = getelementptr inbounds [10 x i32], [10 x i32]* %ExceptionVal, i32 0, i64 %idxprom - store i32 %tmp11, i32* %arrayidx, align 4 - %tmp13 = load i32, i32* %NumExceptions, align 4 - %inc = add nsw i32 %tmp13, 1 - store i32 %inc, i32* %NumExceptions, align 4 - %tmp14 = load i32, i32* %e, align 4 - %tmp15 = load i32, i32* %i, align 4 - %cmp1 = icmp eq i32 %tmp14, %tmp15 - br i1 %cmp1, label %if.then, label %if.else - -; CHECK-NOT: if.then: - -if.then: ; preds = %catch - %tmp16 = load i32, i32* %e, align 4 - %b = getelementptr inbounds %struct.SomeData, %struct.SomeData* %Data, i32 0, i32 1 - %tmp17 = load i32, i32* %b, align 4 - %add2 = add nsw i32 %tmp17, %tmp16 - store i32 %add2, i32* %b, align 4 - br label %if.end - -; CHECK-NOT: if.else: - -if.else: ; preds = %catch - %tmp18 = load i32, i32* %e, align 4 - %a3 = getelementptr inbounds %struct.SomeData, %struct.SomeData* %Data, i32 0, i32 0 - %tmp19 = load i32, i32* %a3, align 4 - %add4 = add nsw i32 %tmp19, %tmp18 - store i32 %add4, i32* %a3, align 4 - br label %if.end - -; CHECK-NOT: if.end: - -if.end: ; preds = %if.else, %if.then - call void @llvm.eh.endcatch() #1 - br label %try.cont - -try.cont: ; preds = %if.end, %invoke.cont - %tmp20 = load i32, i32* %NumExceptions, align 4 - call void @"\01?does_not_throw@@YAXH@Z"(i32 %tmp20) - br label %for.inc - -for.inc: ; preds = %try.cont - %tmp21 = load i32, i32* %i, align 4 - %inc5 = add nsw i32 %tmp21, 1 - store i32 %inc5, i32* %i, align 4 - br label %for.cond - -for.end: ; preds = %for.cond - %tmp22 = load i32, i32* %NumExceptions, align 4 - %arraydecay = getelementptr inbounds [10 x i32], [10 x i32]* %ExceptionVal, i32 0, i32 0 - call void @"\01?dump@@YAXPEAHHAEAUSomeData@@@Z"(i32* %arraydecay, i32 %tmp22, %struct.SomeData* dereferenceable(8) %Data) - ret void - -; CHECK-NOT: eh.resume: - -eh.resume: ; preds = %catch.dispatch - %exn6 = load i8*, i8** %exn.slot - %sel7 = load i32, i32* %ehselector.slot - %lpad.val = insertvalue { i8*, i32 } undef, i8* %exn6, 0 - %lpad.val8 = insertvalue { i8*, i32 } %lpad.val, i32 %sel7, 1 - resume { i8*, i32 } %lpad.val8 - -; CHECK: } -} - -; The following catch handler should be outlined. -; CHECK-LABEL: define internal i8* @"\01?test@@YAXXZ.catch"(i8*, i8*) -; CHECK: entry: -; CHECK: [[RECOVER_E:\%.+]] = call i8* @llvm.localrecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 0) -; CHECK: [[E_PTR1:\%.+]] = bitcast i8* [[RECOVER_E]] to i32* -; CHECK: [[RECOVER_NUMEXCEPTIONS:\%.+]] = call i8* @llvm.localrecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 1) -; CHECK: [[NUMEXCEPTIONS_PTR1:\%.+]] = bitcast i8* [[RECOVER_NUMEXCEPTIONS]] to i32* -; CHECK: [[RECOVER_EXCEPTIONVAL:\%.+]] = call i8* @llvm.localrecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 2) -; CHECK: [[EXCEPTIONVAL_PTR1:\%.+]] = bitcast i8* [[RECOVER_EXCEPTIONVAL]] to [10 x i32]* -; CHECK: [[RECOVER_I:\%.+]] = call i8* @llvm.localrecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 3) -; CHECK: [[I_PTR1:\%.+]] = bitcast i8* [[RECOVER_I]] to i32* -; CHECK: [[RECOVER_DATA:\%.+]] = call i8* @llvm.localrecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 4) -; CHECK: [[DATA_PTR1:\%.+]] = bitcast i8* [[RECOVER_DATA]] to %struct.SomeData* -; CHECK: [[TMP:\%.+]] = load i32, i32* [[E_PTR1]], align 4 -; CHECK: [[TMP1:\%.+]] = load i32, i32* [[NUMEXCEPTIONS_PTR]], align 4 -; CHECK: [[IDXPROM:\%.+]] = sext i32 [[TMP1]] to i64 -; CHECK: [[ARRAYIDX:\%.+]] = getelementptr inbounds [10 x i32], [10 x i32]* [[EXCEPTIONVAL_PTR1]], i32 0, i64 [[IDXPROM]] -; CHECK: store i32 [[TMP]], i32* [[ARRAYIDX]], align 4 -; CHECK: [[TMP2:\%.+]] = load i32, i32* [[NUMEXCEPTIONS_PTR1]], align 4 -; CHECK: [[INC:\%.+]] = add nsw i32 [[TMP2]], 1 -; CHECK: store i32 [[INC]], i32* [[NUMEXCEPTIONS_PTR]], align 4 -; CHECK: [[TMP3:\%.+]] = load i32, i32* [[E_PTR1]], align 4 -; CHECK: [[TMP4:\%.+]] = load i32, i32* [[I_PTR1]], align 4 -; CHECK: [[CMP:\%.+]] = icmp eq i32 [[TMP3]], [[TMP4]] -; CHECK: br i1 [[CMP]], label %if.then, label %if.else -; -; CHECK: if.then: ; preds = %entry -; CHECK: [[TMP5:\%.+]] = load i32, i32* [[E_PTR1]], align 4 -; CHECK: [[B_PTR:\%.+]] = getelementptr inbounds %struct.SomeData, %struct.SomeData* [[DATA_PTR1]], i32 0, i32 1 -; CHECK: [[TMP6:\%.+]] = load i32, i32* [[B_PTR]], align 4 -; CHECK: %add2 = add nsw i32 [[TMP6]], [[TMP5]] -; CHECK: store i32 [[ADD:\%.+]], i32* [[B_PTR]], align 4 -; CHECK: br label %if.end -; -; CHECK: if.else: ; preds = %entry -; CHECK: [[TMP7:\%.+]] = load i32, i32* %e, align 4 -; CHECK: [[A3:\%.+]] = getelementptr inbounds %struct.SomeData, %struct.SomeData* %Data, i32 0, i32 0 -; CHECK: [[TMP8:\%.+]] = load i32, i32* %a3, align 4 -; CHECK: [[ADD1:\%.+]] = add nsw i32 [[TMP8]], [[TMP7]] -; CHECK: store i32 [[ADD1]], i32* [[A3]], align 4 -; CHECK: br label %if.end -; -; CHECK: if.end: ; preds = %if.else, %if.then -; CHECK: ret i8* blockaddress(@"\01?test@@YAXXZ", %try.cont) -; CHECK: } - - -; Function Attrs: nounwind -declare void @llvm.memset(i8* nocapture, i8, i64, i32, i1) #1 - -declare void @"\01?may_throw@@YAXXZ"() #2 - -declare i32 @__CxxFrameHandler3(...) - -; Function Attrs: nounwind readnone -declare i32 @llvm.eh.typeid.for(i8*) #3 - -declare void @llvm.eh.begincatch(i8*, i8*) - -declare void @llvm.eh.endcatch() - -declare void @"\01?does_not_throw@@YAXH@Z"(i32) #2 - -declare void @"\01?dump@@YAXPEAHHAEAUSomeData@@@Z"(i32*, i32, %struct.SomeData* dereferenceable(8)) #2 - -attributes #0 = { uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } -attributes #1 = { nounwind } -attributes #2 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } -attributes #3 = { nounwind readnone } - -!llvm.module.flags = !{!0} -!llvm.ident = !{!1} - -!0 = !{i32 1, !"PIC Level", i32 2} -!1 = !{!"clang version 3.7.0 (trunk 228868)"} diff --git a/test/CodeGen/WinEH/cppeh-inalloca.ll b/test/CodeGen/WinEH/cppeh-inalloca.ll deleted file mode 100644 index 649c5e72e2d..00000000000 --- a/test/CodeGen/WinEH/cppeh-inalloca.ll +++ /dev/null @@ -1,194 +0,0 @@ -; RUN: opt -mtriple=x86_64-pc-windows-msvc -winehprepare -S -o - < %s | FileCheck %s - -; This test is built from the following code: -; struct A { -; A(int a); -; A(const A &o); -; ~A(); -; int a; -; }; -; -; void may_throw(); -; -; int test(A a) { -; try { -; may_throw(); -; } -; catch (int e) { -; return a.a + e; -; } -; return 0; -; } -; -; The test was built for a 32-bit Windows target and then the reference to -; the inalloca instruction was manually sunk into the landingpad. - -; ModuleID = 'cppeh-inalloca.cpp' - -%rtti.TypeDescriptor2 = type { i8**, i8*, [3 x i8] } -%struct.A = type { i32 } - -$"\01??_R0H@8" = comdat any - -@"\01??_7type_info@@6B@" = external constant i8* -@"\01??_R0H@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".H\00" }, comdat - -; The function entry should be rewritten like this. -; CHECK: define i32 @"\01?test@@YAHUA@@@Z"(<{ %struct.A }>* inalloca) -; CHECK: entry: -; CHECK: [[TMP_REGMEM:\%.+]] = alloca <{ %struct.A }>* -; CHECK: store <{ %struct.A }>* %0, <{ %struct.A }>** [[TMP_REGMEM]] -; CHECK: [[RETVAL:\%.+]] = alloca i32, align 4 -; CHECK: [[E_PTR:\%.+]] = alloca i32, align 4 -; CHECK: [[CLEANUP_SLOT:\%.+]] = alloca i32 -; CHECK: call void (...) @llvm.localescape(i32* %e, <{ %struct.A }>** [[TMP_REGMEM]], i32* [[RETVAL]], i32* [[CLEANUP_SLOT]]) -; CHECK: invoke void @"\01?may_throw@@YAXXZ"() -; CHECK: to label %invoke.cont unwind label %[[LPAD_LABEL:lpad[0-9]*]] - -define i32 @"\01?test@@YAHUA@@@Z"(<{ %struct.A }>* inalloca) #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) { -entry: - %retval = alloca i32, align 4 - %exn.slot = alloca i8* - %ehselector.slot = alloca i32 - %e = alloca i32, align 4 - %cleanup.dest.slot = alloca i32 - invoke void @"\01?may_throw@@YAXXZ"() - to label %invoke.cont unwind label %lpad - -invoke.cont: ; preds = %entry - br label %try.cont - -; CHECK: [[LPAD_LABEL]]:{{[ ]+}}; preds = %entry -; CHECK: landingpad { i8*, i32 } -; CHECK-NEXT: cleanup -; CHECK-NEXT: catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*) -; CHECK-NEXT: [[RECOVER:\%recover.*]] = call i8* (...) @llvm.eh.actions(i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*), i32 0, i8* (i8*, i8*)* @"\01?test@@YAHUA@@@Z.catch", i32 0, void (i8*, i8*)* @"\01?test@@YAHUA@@@Z.cleanup") -; CHECK-NEXT: indirectbr i8* [[RECOVER]], [label %cleanup] - -lpad: ; preds = %entry - %1 = landingpad { i8*, i32 } - cleanup - catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*) - %2 = extractvalue { i8*, i32 } %1, 0 - store i8* %2, i8** %exn.slot - %3 = extractvalue { i8*, i32 } %1, 1 - store i32 %3, i32* %ehselector.slot - br label %catch.dispatch - -; CHECK-NOT: catch.dispatch: - -catch.dispatch: ; preds = %lpad - %sel = load i32, i32* %ehselector.slot - %4 = call i32 @llvm.eh.typeid.for(i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*)) #3 - %matches = icmp eq i32 %sel, %4 - br i1 %matches, label %catch, label %ehcleanup - -; CHECK-NOT: catch: - -catch: ; preds = %catch.dispatch - %exn = load i8*, i8** %exn.slot - %e.i8 = bitcast i32* %e to i8* - call void @llvm.eh.begincatch(i8* %exn, i8* %e.i8) #3 - %a = getelementptr inbounds <{ %struct.A }>, <{ %struct.A }>* %0, i32 0, i32 0 - %a1 = getelementptr inbounds %struct.A, %struct.A* %a, i32 0, i32 0 - %tmp8 = load i32, i32* %a1, align 4 - %tmp9 = load i32, i32* %e, align 4 - %add = add nsw i32 %tmp8, %tmp9 - store i32 %add, i32* %retval - store i32 1, i32* %cleanup.dest.slot - call void @llvm.eh.endcatch() #3 - br label %cleanup - -try.cont: ; preds = %invoke.cont - store i32 0, i32* %retval - store i32 1, i32* %cleanup.dest.slot - br label %cleanup - -; The cleanup block should be re-written like this. -; CHECK: cleanup:{{[ ]+}}; preds = %[[LPAD_LABEL]], %try.cont -; CHECK: %a2 = getelementptr inbounds <{ %struct.A }>, <{ %struct.A }>* %0, i32 0, i32 0 -; CHECK: call x86_thiscallcc void @"\01??1A@@QAE@XZ"(%struct.A* %a2) -; CHECK: [[TMP1:\%.+]] = load i32, i32* [[RETVAL]] -; CHECK: ret i32 [[TMP1]] - -cleanup: ; preds = %try.cont, %catch - %a2 = getelementptr inbounds <{ %struct.A }>, <{ %struct.A }>* %0, i32 0, i32 0 - call x86_thiscallcc void @"\01??1A@@QAE@XZ"(%struct.A* %a2) #3 - %tmp10 = load i32, i32* %retval - ret i32 %tmp10 - -; CHECK-NOT: ehcleanup: - -ehcleanup: ; preds = %catch.dispatch - %a3 = getelementptr inbounds <{ %struct.A }>, <{ %struct.A }>* %0, i32 0, i32 0 - call x86_thiscallcc void @"\01??1A@@QAE@XZ"(%struct.A* %a3) #3 - br label %eh.resume - -; CHECK-NOT: eh.resume: - -eh.resume: ; preds = %ehcleanup - %exn2 = load i8*, i8** %exn.slot - %sel3 = load i32, i32* %ehselector.slot - %lpad.val = insertvalue { i8*, i32 } undef, i8* %exn2, 0 - %lpad.val4 = insertvalue { i8*, i32 } %lpad.val, i32 %sel3, 1 - resume { i8*, i32 } %lpad.val4 - -; CHECK: } -} - -; The following catch handler should be outlined. -; CHECK: define internal i8* @"\01?test@@YAHUA@@@Z.catch"(i8*, i8*) -; CHECK: entry: -; CHECK: [[RECOVER_E:\%.+]] = call i8* @llvm.localrecover(i8* bitcast (i32 (<{ %struct.A }>*)* @"\01?test@@YAHUA@@@Z" to i8*), i8* %1, i32 0) -; CHECK: [[E_PTR:\%.+]] = bitcast i8* [[RECOVER_E]] to i32* -; CHECK: [[RECOVER_EH_TEMP:\%.+]] = call i8* @llvm.localrecover(i8* bitcast (i32 (<{ %struct.A }>*)* @"\01?test@@YAHUA@@@Z" to i8*), i8* %1, i32 1) -; CHECK: [[EH_TEMP:\%.+]] = bitcast i8* [[RECOVER_EH_TEMP]] to <{ %struct.A }>** -; CHECK: [[RECOVER_RETVAL:\%.+]] = call i8* @llvm.localrecover(i8* bitcast (i32 (<{ %struct.A }>*)* @"\01?test@@YAHUA@@@Z" to i8*), i8* %1, i32 2) -; CHECK: [[RETVAL1:\%.+]] = bitcast i8* [[RECOVER_RETVAL]] to i32* -; CHECK: [[RECOVER_CLEANUPSLOT:\%.+]] = call i8* @llvm.localrecover(i8* bitcast (i32 (<{ %struct.A }>*)* @"\01?test@@YAHUA@@@Z" to i8*), i8* %1, i32 3) -; CHECK: [[CLEANUPSLOT1:\%.+]] = bitcast i8* [[RECOVER_CLEANUPSLOT]] to i32* -; CHECK: [[E_I8PTR:\%.+]] = bitcast i32* [[E_PTR]] to i8* -; CHECK: [[TMP_RELOAD:\%.+]] = load <{ %struct.A }>*, <{ %struct.A }>** [[EH_TEMP]] -; CHECK: [[RECOVER_A:\%.+]] = getelementptr inbounds <{ %struct.A }>, <{ %struct.A }>* [[TMP_RELOAD]], i32 0, i32 0 -; CHECK: [[A1:\%.+]] = getelementptr inbounds %struct.A, %struct.A* [[RECOVER_A]], i32 0, i32 0 -; CHECK: [[TMP2:\%.+]] = load i32, i32* [[A1]], align 4 -; CHECK: [[TMP3:\%.+]] = load i32, i32* [[E_PTR]], align 4 -; CHECK: [[ADD:\%.+]] = add nsw i32 [[TMP2]], [[TMP3]] -; CHECK: store i32 [[ADD]], i32* [[RETVAL1]] -; CHECK: store i32 1, i32* [[CLEANUPSLOT1]] -; CHECK: ret i8* blockaddress(@"\01?test@@YAHUA@@@Z", %cleanup) -; CHECK: } - -; The following cleanup handler should be outlined. -; CHECK: define internal void @"\01?test@@YAHUA@@@Z.cleanup"(i8*, i8*) -; CHECK: entry: -; CHECK: [[RECOVER_EH_TEMP1:\%.+]] = call i8* @llvm.localrecover(i8* bitcast (i32 (<{ %struct.A }>*)* @"\01?test@@YAHUA@@@Z" to i8*), i8* %1, i32 1) -; CHECK: [[EH_TEMP1:\%.+]] = bitcast i8* [[RECOVER_EH_TEMP]] to <{ %struct.A }>** -; CHECK: [[TMP_RELOAD1:\%.+]] = load <{ %struct.A }>*, <{ %struct.A }>** [[EH_TEMP1]] -; CHECK: [[A3:\%.+]] = getelementptr inbounds <{ %struct.A }>, <{ %struct.A }>* [[TMP_RELOAD1]], i32 0, i32 0 -; CHECK: call x86_thiscallcc void @"\01??1A@@QAE@XZ"(%struct.A* [[A3]]) -; CHECK: ret void -; CHECK: } - -declare void @"\01?may_throw@@YAXXZ"() #0 - -declare i32 @__CxxFrameHandler3(...) - -; Function Attrs: nounwind readnone -declare i32 @llvm.eh.typeid.for(i8*) #1 - -declare void @llvm.eh.begincatch(i8*, i8*) - -declare void @llvm.eh.endcatch() - -; Function Attrs: nounwind -declare x86_thiscallcc void @"\01??1A@@QAE@XZ"(%struct.A*) #2 - -attributes #0 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } -attributes #1 = { nounwind readnone } -attributes #2 = { nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } -attributes #3 = { nounwind } - -!llvm.ident = !{!0} - -!0 = !{!"clang version 3.7.0 (trunk 228868)"} diff --git a/test/CodeGen/WinEH/cppeh-min-unwind.ll b/test/CodeGen/WinEH/cppeh-min-unwind.ll deleted file mode 100644 index 98d6d6fcacb..00000000000 --- a/test/CodeGen/WinEH/cppeh-min-unwind.ll +++ /dev/null @@ -1,99 +0,0 @@ -; RUN: opt -mtriple=x86_64-pc-windows-msvc -winehprepare -S -o - < %s | FileCheck %s - -; This test was generated from the following source: -; -; class SomeClass { -; public: -; SomeClass(); -; ~SomeClass(); -; }; -; -; void test() { -; SomeClass obj; -; may_throw(); -; } - - -; ModuleID = 'min-unwind.cpp' -target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" -target triple = "x86_64-pc-windows-msvc" - -%class.SomeClass = type { [28 x i32] } - -; The function entry should be rewritten like this. -; CHECK: define void @_Z4testv() -; CHECK: entry: -; CHECK: [[OBJ_PTR:\%.+]] = alloca %class.SomeClass, align 4 -; CHECK: call void @_ZN9SomeClassC1Ev(%class.SomeClass* [[OBJ_PTR]]) -; CHECK: call void (...) @llvm.localescape(%class.SomeClass* [[OBJ_PTR]]) -; CHECK: invoke void @_Z9may_throwv() -; CHECK: to label %invoke.cont unwind label %[[LPAD_LABEL:lpad[0-9]*]] - -; Function Attrs: uwtable -define void @_Z4testv() #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) { -entry: - %obj = alloca %class.SomeClass, align 4 - %exn.slot = alloca i8* - %ehselector.slot = alloca i32 - call void @_ZN9SomeClassC1Ev(%class.SomeClass* %obj) - invoke void @_Z9may_throwv() - to label %invoke.cont unwind label %lpad - -invoke.cont: ; preds = %entry - call void @_ZN9SomeClassD1Ev(%class.SomeClass* %obj) - ret void - -; CHECK: [[LPAD_LABEL]]:{{[ ]+}}; preds = %entry -; CHECK: landingpad { i8*, i32 } -; CHECK-NEXT: cleanup -; CHECK-NEXT: [[RECOVER:\%.+]] = call i8* (...) @llvm.eh.actions(i32 0, void (i8*, i8*)* @_Z4testv.cleanup) -; CHECK-NEXT: indirectbr i8* [[RECOVER]], [] - -lpad: ; preds = %entry - %tmp = landingpad { i8*, i32 } - cleanup - %tmp1 = extractvalue { i8*, i32 } %tmp, 0 - store i8* %tmp1, i8** %exn.slot - %tmp2 = extractvalue { i8*, i32 } %tmp, 1 - store i32 %tmp2, i32* %ehselector.slot - call void @_ZN9SomeClassD1Ev(%class.SomeClass* %obj) - br label %eh.resume - -; CHECK-NOT: eh.resume: - -eh.resume: ; preds = %lpad - %exn = load i8*, i8** %exn.slot - %sel = load i32, i32* %ehselector.slot - %lpad.val = insertvalue { i8*, i32 } undef, i8* %exn, 0 - %lpad.val2 = insertvalue { i8*, i32 } %lpad.val, i32 %sel, 1 - resume { i8*, i32 } %lpad.val2 - -; CHECK: } -} - -; This cleanup handler should be outlined. -; CHECK: define internal void @_Z4testv.cleanup(i8*, i8*) -; CHECK: entry: -; CHECK: [[RECOVER_OBJ:\%.+]] = call i8* @llvm.localrecover(i8* bitcast (void ()* @_Z4testv to i8*), i8* %1, i32 0) -; CHECK: [[OBJ_PTR1:\%.+]] = bitcast i8* [[RECOVER_OBJ]] to %class.SomeClass* -; CHECK: call void @_ZN9SomeClassD1Ev(%class.SomeClass* [[OBJ_PTR1]]) -; CHECK: ret void -; CHECK: } - -declare void @_ZN9SomeClassC1Ev(%class.SomeClass*) #1 - -declare void @_Z9may_throwv() #1 - -declare i32 @__CxxFrameHandler3(...) - -declare void @_ZN9SomeClassD1Ev(%class.SomeClass*) #1 - -attributes #0 = { uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } -attributes #1 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } -attributes #2 = { noinline noreturn nounwind } -attributes #3 = { noreturn nounwind } -attributes #4 = { nounwind } - -!llvm.ident = !{!0} - -!0 = !{!"clang version 3.7.0 (trunk 226027)"} diff --git a/test/CodeGen/WinEH/cppeh-mixed-catch-and-cleanup.ll b/test/CodeGen/WinEH/cppeh-mixed-catch-and-cleanup.ll deleted file mode 100644 index c69633f17e2..00000000000 --- a/test/CodeGen/WinEH/cppeh-mixed-catch-and-cleanup.ll +++ /dev/null @@ -1,106 +0,0 @@ -; RUN: opt -mtriple=x86_64-pc-windows-msvc -winehprepare -S -o - < %s | FileCheck %s - -; This test is based on the following code: -; -; void test() -; { -; try { -; Obj o; -; may_throw(); -; } catch (...) { -; } -; } -; -; The purpose of this test is to verify that we create separate catch and -; cleanup handlers. When compiling for the C++ 11 standard, this isn't -; strictly necessary, since calling the destructor from the catch handler -; would be logically equivalent to calling it from a cleanup handler. -; However, if the -std=c++98 option is used, an exception in the cleanup -; code should terminate the process (the MSVCRT runtime will do that) but -; if the destructor is called from the catch handler, it wouldn't terminate -; the process - - -; ModuleID = 'cppeh-mixed-catch-and-cleanup.cpp' -target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128" -target triple = "x86_64-pc-windows-msvc" - -%class.Obj = type { i8 } - -; This just verifies that the function was processed by WinEHPrepare. -; -; CHECK-LABEL: define void @"\01?test@@YAXXZ"() -; CHECK: entry: -; CHECK: call void (...) @llvm.localescape -; CHECK: } - -; Function Attrs: nounwind uwtable -define void @"\01?test@@YAXXZ"() #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) { -entry: - %o = alloca %class.Obj, align 1 - %exn.slot = alloca i8* - %ehselector.slot = alloca i32 - invoke void @"\01?may_throw@@YAXXZ"() - to label %invoke.cont unwind label %lpad - -invoke.cont: ; preds = %entry - call void @"\01??1Obj@@QEAA@XZ"(%class.Obj* %o) #3 - br label %try.cont - -lpad: ; preds = %entry - %0 = landingpad { i8*, i32 } - catch i8* null - %1 = extractvalue { i8*, i32 } %0, 0 - store i8* %1, i8** %exn.slot - %2 = extractvalue { i8*, i32 } %0, 1 - store i32 %2, i32* %ehselector.slot - call void @"\01??1Obj@@QEAA@XZ"(%class.Obj* %o) #3 - %exn = load i8*, i8** %exn.slot - call void @llvm.eh.begincatch(i8* %exn, i8* null) #3 - call void @llvm.eh.endcatch() #3 - br label %try.cont - -try.cont: ; preds = %catch, %invoke.cont - ret void -} - -; Verify that a cleanup handler was created and that it calls ~Obj(). -; CHECK-LABEL: define internal void @"\01?test@@YAXXZ.cleanup"(i8*, i8*) -; CHECK: entry: -; CHECK: @llvm.localrecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 0) -; CHECK: call void @"\01??1Obj@@QEAA@XZ" -; CHECK: ret void -; CHECK: } - -; Verify that a catch handler was created and that it does not call ~Obj(). -; CHECK-LABEL: define internal i8* @"\01?test@@YAXXZ.catch"(i8*, i8*) -; CHECK: entry: -; CHECK-NOT: call void @"\01??1Obj@@QEAA@XZ" -; CHECK: ret i8* blockaddress(@"\01?test@@YAXXZ", %try.cont) -; CHECK: } - - - -declare void @"\01?may_throw@@YAXXZ"() #1 - -declare i32 @__CxxFrameHandler3(...) - -; Function Attrs: nounwind -declare void @"\01??1Obj@@QEAA@XZ"(%class.Obj*) #2 - -; Function Attrs: nounwind -declare void @llvm.eh.begincatch(i8* nocapture, i8* nocapture) #3 - -; Function Attrs: nounwind -declare void @llvm.eh.endcatch() #3 - -attributes #0 = { nounwind uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "unsafe-fp-math"="false" "use-soft-float"="false" } -attributes #1 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "unsafe-fp-math"="false" "use-soft-float"="false" } -attributes #2 = { nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "unsafe-fp-math"="false" "use-soft-float"="false" } -attributes #3 = { nounwind } - -!llvm.module.flags = !{!0} -!llvm.ident = !{!1} - -!0 = !{i32 1, !"PIC Level", i32 2} -!1 = !{!"clang version 3.7.0 (trunk 235779) (llvm/trunk 235769)"} diff --git a/test/CodeGen/WinEH/cppeh-multi-catch.ll b/test/CodeGen/WinEH/cppeh-multi-catch.ll deleted file mode 100644 index 266cdea20cd..00000000000 --- a/test/CodeGen/WinEH/cppeh-multi-catch.ll +++ /dev/null @@ -1,226 +0,0 @@ -; RUN: opt -mtriple=x86_64-pc-windows-msvc -winehprepare -S -o - < %s | FileCheck %s - -; This test is based on the following code: -; -; void test() -; { -; try { -; may_throw(); -; } catch (int i) { -; handle_int(i); -; } catch (long long ll) { -; handle_long_long(ll); -; } catch (SomeClass &obj) { -; handle_obj(&obj); -; } catch (...) { -; handle_exception(); -; } -; } -; -; The catch handlers were edited to insert 'ret void' after the endcatch call. - -; ModuleID = 'catch-with-type.cpp' -target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128" -target triple = "x86_64-pc-windows-msvc" - -%rtti.TypeDescriptor2 = type { i8**, i8*, [3 x i8] } -%eh.HandlerMapEntry = type { i32, i32 } -%rtti.TypeDescriptor3 = type { i8**, i8*, [4 x i8] } -%rtti.TypeDescriptor15 = type { i8**, i8*, [16 x i8] } -%class.SomeClass = type { i8 } - -$"\01??_R0H@8" = comdat any - -$"\01??_R0_J@8" = comdat any - -$"\01??_R0?AVSomeClass@@@8" = comdat any - -@"\01??_7type_info@@6B@" = external constant i8* -@"\01??_R0H@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".H\00" }, comdat -@__ImageBase = external constant i8 -@llvm.eh.handlermapentry.H = private unnamed_addr constant %eh.HandlerMapEntry { i32 0, i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32) }, section "llvm.metadata" -@"\01??_R0_J@8" = linkonce_odr global %rtti.TypeDescriptor3 { i8** @"\01??_7type_info@@6B@", i8* null, [4 x i8] c"._J\00" }, comdat -@llvm.eh.handlermapentry._J = private unnamed_addr constant %eh.HandlerMapEntry { i32 0, i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.TypeDescriptor3* @"\01??_R0_J@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32) }, section "llvm.metadata" -@"\01??_R0?AVSomeClass@@@8" = linkonce_odr global %rtti.TypeDescriptor15 { i8** @"\01??_7type_info@@6B@", i8* null, [16 x i8] c".?AVSomeClass@@\00" }, comdat -@"llvm.eh.handlermapentry.reference.?AVSomeClass@@" = private unnamed_addr constant %eh.HandlerMapEntry { i32 8, i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.TypeDescriptor15* @"\01??_R0?AVSomeClass@@@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32) }, section "llvm.metadata" - - -; CHECK: define void @"\01?test@@YAXXZ"() #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) { -; CHECK: entry: -; CHECK: [[OBJ_PTR:\%.+]] = alloca %class.SomeClass*, align 8 -; CHECK: [[LL_PTR:\%.+]] = alloca i64, align 8 -; CHECK: [[I_PTR:\%.+]] = alloca i32, align 4 -; CHECK: call void (...) @llvm.localescape(i32* [[I_PTR]], i64* [[LL_PTR]], %class.SomeClass** [[OBJ_PTR]]) -; CHECK: invoke void @"\01?may_throw@@YAXXZ"() -; CHECK: to label %invoke.cont unwind label %[[LPAD_LABEL:lpad[0-9]*]] - -; Function Attrs: uwtable -define void @"\01?test@@YAXXZ"() #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) { -entry: - %exn.slot = alloca i8* - %ehselector.slot = alloca i32 - %obj = alloca %class.SomeClass*, align 8 - %ll = alloca i64, align 8 - %i = alloca i32, align 4 - invoke void @"\01?may_throw@@YAXXZ"() - to label %invoke.cont unwind label %lpad - -invoke.cont: ; preds = %entry - br label %try.cont - -; CHECK: [[LPAD_LABEL]]:{{[ ]+}}; preds = %entry -; CHECK: landingpad { i8*, i32 } -; CHECK-NEXT: catch %eh.HandlerMapEntry* @llvm.eh.handlermapentry.H -; CHECK-NEXT: catch %eh.HandlerMapEntry* @llvm.eh.handlermapentry._J -; CHECK-NEXT: catch %eh.HandlerMapEntry* @"llvm.eh.handlermapentry.reference.?AVSomeClass@@" -; CHECK-NEXT: catch i8* null -; CHECK-NEXT: [[RECOVER:\%.+]] = call i8* (...) @llvm.eh.actions( -; CHECK-SAME: i32 1, i8* bitcast (%eh.HandlerMapEntry* @llvm.eh.handlermapentry.H to i8*), i32 0, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch", -; CHECK-SAME: i32 1, i8* bitcast (%eh.HandlerMapEntry* @llvm.eh.handlermapentry._J to i8*), i32 1, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch.1", -; CHECK-SAME: i32 1, i8* bitcast (%eh.HandlerMapEntry* @"llvm.eh.handlermapentry.reference.?AVSomeClass@@" to i8*), i32 2, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch.2", -; CHECK-SAME: i32 1, i8* null, i32 -1, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch.3") -; CHECK-NEXT: indirectbr i8* [[RECOVER]], [label %ret] - -lpad: ; preds = %entry - %0 = landingpad { i8*, i32 } - catch %eh.HandlerMapEntry* @llvm.eh.handlermapentry.H - catch %eh.HandlerMapEntry* @llvm.eh.handlermapentry._J - catch %eh.HandlerMapEntry* @"llvm.eh.handlermapentry.reference.?AVSomeClass@@" - catch i8* null - %1 = extractvalue { i8*, i32 } %0, 0 - store i8* %1, i8** %exn.slot - %2 = extractvalue { i8*, i32 } %0, 1 - store i32 %2, i32* %ehselector.slot - br label %catch.dispatch - -; CHECK-NOT: catch.dispatch: -catch.dispatch: ; preds = %lpad - %sel = load i32, i32* %ehselector.slot - %3 = call i32 @llvm.eh.typeid.for(i8* bitcast (%eh.HandlerMapEntry* @llvm.eh.handlermapentry.H to i8*)) #3 - %matches = icmp eq i32 %sel, %3 - br i1 %matches, label %catch14, label %catch.fallthrough - -ret: - ret void - -; CHECK-NOT: catch14: -; CHECK: ret: -; CHECK-NEXT: ret void -catch14: ; preds = %catch.dispatch - %exn15 = load i8*, i8** %exn.slot - %4 = bitcast i32* %i to i8* - call void @llvm.eh.begincatch(i8* %exn15, i8* %4) #3 - %5 = load i32, i32* %i, align 4 - call void @"\01?handle_int@@YAXH@Z"(i32 %5) - call void @llvm.eh.endcatch() #3 - br label %ret - -try.cont: ; preds = %invoke.cont - br label %ret - -; CHECK-NOT: catch.fallthrough: -catch.fallthrough: ; preds = %catch.dispatch - %6 = call i32 @llvm.eh.typeid.for(i8* bitcast (%eh.HandlerMapEntry* @llvm.eh.handlermapentry._J to i8*)) #3 - %matches1 = icmp eq i32 %sel, %6 - br i1 %matches1, label %catch10, label %catch.fallthrough2 - -; CHECK-NOT: catch10: -catch10: ; preds = %catch.fallthrough - %exn11 = load i8*, i8** %exn.slot - %7 = bitcast i64* %ll to i8* - call void @llvm.eh.begincatch(i8* %exn11, i8* %7) #3 - %8 = load i64, i64* %ll, align 8 - call void @"\01?handle_long_long@@YAX_J@Z"(i64 %8) - call void @llvm.eh.endcatch() #3 - br label %ret - -; CHECK-NOT: catch.fallthrough2: -catch.fallthrough2: ; preds = %catch.fallthrough - %9 = call i32 @llvm.eh.typeid.for(i8* bitcast (%eh.HandlerMapEntry* @"llvm.eh.handlermapentry.reference.?AVSomeClass@@" to i8*)) #3 - %matches3 = icmp eq i32 %sel, %9 - br i1 %matches3, label %catch6, label %catch - -; CHECK-NOT: catch6: -catch6: ; preds = %catch.fallthrough2 - %exn7 = load i8*, i8** %exn.slot - %10 = bitcast %class.SomeClass** %obj to i8* - call void @llvm.eh.begincatch(i8* %exn7, i8* %10) #3 - %11 = load %class.SomeClass*, %class.SomeClass** %obj, align 8 - call void @"\01?handle_obj@@YAXPEAVSomeClass@@@Z"(%class.SomeClass* %11) - call void @llvm.eh.endcatch() #3 - br label %ret - -; CHECK-NOT: catch: -catch: ; preds = %catch.fallthrough2 - %exn = load i8*, i8** %exn.slot - call void @llvm.eh.begincatch(i8* %exn, i8* null) #3 - call void @"\01?handle_exception@@YAXXZ"() call void @llvm.eh.endcatch() #3 - br label %ret -; CHECK: } -} - -; CHECK-LABEL: define internal i8* @"\01?test@@YAXXZ.catch"(i8*, i8*) -; CHECK: entry: -; CHECK: [[RECOVER_I:\%.+]] = call i8* @llvm.localrecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 0) -; CHECK: [[I_PTR:\%.+]] = bitcast i8* [[RECOVER_I]] to i32* -; CHECK: [[TMP1:\%.+]] = load i32, i32* [[I_PTR]], align 4 -; CHECK: call void @"\01?handle_int@@YAXH@Z"(i32 [[TMP1]]) -; CHECK: ret i8* blockaddress(@"\01?test@@YAXXZ", %ret) -; CHECK: } - -; CHECK-LABEL: define internal i8* @"\01?test@@YAXXZ.catch.1"(i8*, i8*) -; CHECK: entry: -; CHECK: [[RECOVER_LL:\%.+]] = call i8* @llvm.localrecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 1) -; CHECK: [[LL_PTR:\%.+]] = bitcast i8* [[RECOVER_LL]] to i64* -; CHECK: [[TMP2:\%.+]] = load i64, i64* [[LL_PTR]], align 8 -; CHECK: call void @"\01?handle_long_long@@YAX_J@Z"(i64 [[TMP2]]) -; CHECK: ret i8* blockaddress(@"\01?test@@YAXXZ", %ret) -; CHECK: } - -; CHECK-LABEL: define internal i8* @"\01?test@@YAXXZ.catch.2"(i8*, i8*) -; CHECK: entry: -; CHECK: [[RECOVER_OBJ:\%.+]] = call i8* @llvm.localrecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 2) -; CHECK: [[OBJ_PTR:\%.+]] = bitcast i8* [[RECOVER_OBJ]] to %class.SomeClass** -; CHECK: [[TMP3:\%.+]] = load %class.SomeClass*, %class.SomeClass** [[OBJ_PTR]], align 8 -; CHECK: call void @"\01?handle_obj@@YAXPEAVSomeClass@@@Z"(%class.SomeClass* [[TMP3]]) -; CHECK: ret i8* blockaddress(@"\01?test@@YAXXZ", %ret) -; CHECK: } - -; CHECK-LABEL: define internal i8* @"\01?test@@YAXXZ.catch.3"(i8*, i8*) -; CHECK: entry: -; CHECK: call void @"\01?handle_exception@@YAXXZ"() -; CHECK: ret i8* blockaddress(@"\01?test@@YAXXZ", %ret) -; CHECK: } - - -declare void @"\01?may_throw@@YAXXZ"() #1 - -declare i32 @__CxxFrameHandler3(...) - -; Function Attrs: nounwind readnone -declare i32 @llvm.eh.typeid.for(i8*) #2 - -; Function Attrs: nounwind -declare void @llvm.eh.begincatch(i8* nocapture, i8* nocapture) #3 - -declare void @"\01?handle_exception@@YAXXZ"() #1 - -; Function Attrs: nounwind -declare void @llvm.eh.endcatch() #3 - -declare void @"\01?handle_obj@@YAXPEAVSomeClass@@@Z"(%class.SomeClass*) #1 - -declare void @"\01?handle_long_long@@YAX_J@Z"(i64) #1 - -declare void @"\01?handle_int@@YAXH@Z"(i32) #1 - -attributes #0 = { uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } -attributes #1 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } -attributes #2 = { nounwind readnone } -attributes #3 = { nounwind } - -!llvm.module.flags = !{!0} -!llvm.ident = !{!1} - -!0 = !{i32 1, !"PIC Level", i32 2} -!1 = !{!"clang version 3.7.0 (trunk 233155) (llvm/trunk 233153)"} diff --git a/test/CodeGen/WinEH/cppeh-nested-1.ll b/test/CodeGen/WinEH/cppeh-nested-1.ll deleted file mode 100644 index d525d8a1a67..00000000000 --- a/test/CodeGen/WinEH/cppeh-nested-1.ll +++ /dev/null @@ -1,194 +0,0 @@ -; RUN: opt -mtriple=x86_64-pc-windows-msvc -winehprepare -S -o - < %s | FileCheck %s - -; This test is based on the following code: -; -;void test() -;{ -; try { -; try { -; may_throw(); -; } catch (int i) { -; handle_int(i); -; } -; } catch (float f) { -; handle_float(f); -; } -; done(); -;} - -; ModuleID = 'cppeh-nested-1.cpp' -target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" -target triple = "x86_64-pc-windows-msvc" - -%rtti.TypeDescriptor2 = type { i8**, i8*, [3 x i8] } - -$"\01??_R0M@8" = comdat any - -$"\01??_R0H@8" = comdat any - -@"\01??_7type_info@@6B@" = external constant i8* -@"\01??_R0M@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".M\00" }, comdat -@"\01??_R0H@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".H\00" }, comdat - -; CHECK: define void @"\01?test@@YAXXZ"() -; CHECK: entry: -; CHECK: %i = alloca i32, align 4 -; CHECK: %f = alloca float, align 4 -; CHECK: call void (...) @llvm.localescape(float* %f, i32* %i) -; CHECK: invoke void @"\01?may_throw@@YAXXZ"() -; CHECK: to label %invoke.cont unwind label %[[LPAD_LABEL:lpad[0-9]*]] - -; Function Attrs: uwtable -define void @"\01?test@@YAXXZ"() #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) { -entry: - %exn.slot = alloca i8* - %ehselector.slot = alloca i32 - %i = alloca i32, align 4 - %f = alloca float, align 4 - invoke void @"\01?may_throw@@YAXXZ"() - to label %invoke.cont unwind label %lpad - -invoke.cont: ; preds = %entry - br label %try.cont - -; CHECK: [[LPAD_LABEL]]: -; CHECK: landingpad { i8*, i32 } -; CHECK: catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*) -; CHECK: catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0M@8" to i8*) -; CHECK: [[RECOVER:\%.+]] = call i8* (...) @llvm.eh.actions(i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*), i32 1, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch.1", i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0M@8" to i8*), i32 0, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch") -; CHECK: indirectbr i8* [[RECOVER]], [label %try.cont, label %try.cont10] - -lpad: ; preds = %entry - %0 = landingpad { i8*, i32 } - catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*) - catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0M@8" to i8*) - %1 = extractvalue { i8*, i32 } %0, 0 - store i8* %1, i8** %exn.slot - %2 = extractvalue { i8*, i32 } %0, 1 - store i32 %2, i32* %ehselector.slot - br label %catch.dispatch - -; CHECK-NOT: catch.dispatch: -catch.dispatch: ; preds = %lpad - %sel = load i32, i32* %ehselector.slot - %3 = call i32 @llvm.eh.typeid.for(i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*)) #3 - %matches = icmp eq i32 %sel, %3 - br i1 %matches, label %catch, label %catch.dispatch3 - -; CHECK-NOT: catch: -catch: ; preds = %catch.dispatch - %exn = load i8*, i8** %exn.slot - %4 = bitcast i32* %i to i8* - call void @llvm.eh.begincatch(i8* %exn, i8* %4) #3 - %5 = load i32, i32* %i, align 4 - invoke void @"\01?handle_int@@YAXH@Z"(i32 %5) - to label %invoke.cont2 unwind label %lpad1 - -; CHECK-NOT: invoke.cont2: -invoke.cont2: ; preds = %catch - call void @llvm.eh.endcatch() #3 - br label %try.cont - -try.cont: ; preds = %invoke.cont2, %invoke.cont - br label %try.cont10 - -; CHECK-NOT: lpad1: -lpad1: ; preds = %catch - %6 = landingpad { i8*, i32 } - catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0M@8" to i8*) - %7 = extractvalue { i8*, i32 } %6, 0 - store i8* %7, i8** %exn.slot - %8 = extractvalue { i8*, i32 } %6, 1 - store i32 %8, i32* %ehselector.slot - call void @llvm.eh.endcatch() #3 - br label %catch.dispatch3 - -; CHECK-NOT: catch.dispatch3: -catch.dispatch3: ; preds = %lpad1, %catch.dispatch - %sel4 = load i32, i32* %ehselector.slot - %9 = call i32 @llvm.eh.typeid.for(i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0M@8" to i8*)) #3 - %matches5 = icmp eq i32 %sel4, %9 - br i1 %matches5, label %catch6, label %eh.resume - -; CHECK-NOT: catch6: -catch6: ; preds = %catch.dispatch3 - %exn7 = load i8*, i8** %exn.slot - %10 = bitcast float* %f to i8* - call void @llvm.eh.begincatch(i8* %exn7, i8* %10) #3 - %11 = load float, float* %f, align 4 - call void @"\01?handle_float@@YAXM@Z"(float %11) - call void @llvm.eh.endcatch() #3 - br label %try.cont10 - -try.cont10: ; preds = %catch6, %try.cont - call void @"\01?done@@YAXXZ"() - ret void - -; CHECK-NOT: eh.resume: -eh.resume: ; %catch.dispatch3 - %exn11 = load i8*, i8** %exn.slot - %sel12 = load i32, i32* %ehselector.slot - %lpad.val = insertvalue { i8*, i32 } undef, i8* %exn11, 0 - %lpad.val13 = insertvalue { i8*, i32 } %lpad.val, i32 %sel12, 1 - resume { i8*, i32 } %lpad.val13 -; CHECK: } -} - -; CHECK: define internal i8* @"\01?test@@YAXXZ.catch"(i8*, i8*) -; CHECK: entry: -; CHECK: [[RECOVER_F1:\%.+]] = call i8* @llvm.localrecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 0) -; CHECK: [[F_PTR1:\%.+]] = bitcast i8* [[RECOVER_F1]] to float* -; CHECK: [[TMP2:\%.+]] = load float, float* [[F_PTR1]], align 4 -; CHECK: call void @"\01?handle_float@@YAXM@Z"(float [[TMP2]]) -; CHECK: ret i8* blockaddress(@"\01?test@@YAXXZ", %try.cont10) -; CHECK: } - -; CHECK: define internal i8* @"\01?test@@YAXXZ.catch.1"(i8*, i8*) -; CHECK: entry: -; CHECK: [[RECOVER_I:\%.+]] = call i8* @llvm.localrecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 1) -; CHECK: [[I_PTR:\%.+]] = bitcast i8* [[RECOVER_I]] to i32* -; CHECK: [[TMP1:\%.+]] = load i32, i32* [[I_PTR]], align 4 -; CHECK: invoke void @"\01?handle_int@@YAXH@Z"(i32 [[TMP1]]) -; CHECK: to label %invoke.cont2 unwind label %[[LPAD1_LABEL:lpad[0-9]*]] -; -; CHECK: invoke.cont2: -; CHECK: ret i8* blockaddress(@"\01?test@@YAXXZ", %try.cont) -; -; CHECK: [[LPAD1_LABEL]]:{{[ ]+}}; preds = %entry -; CHECK: [[LPAD1_VAL:\%.+]] = landingpad { i8*, i32 } -; CHECK: catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0M@8" to i8*) -; CHECK: [[RECOVER1:\%.+]] = call i8* (...) @llvm.eh.actions(i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0M@8" to i8*), i32 0, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch") -; CHECK: indirectbr i8* [[RECOVER1]], [] -; -; CHECK: } - - -declare void @"\01?may_throw@@YAXXZ"() #1 - -declare i32 @__CxxFrameHandler3(...) - -; Function Attrs: nounwind readnone -declare i32 @llvm.eh.typeid.for(i8*) #2 - -; Function Attrs: nounwind -declare void @llvm.eh.begincatch(i8* nocapture, i8* nocapture) #3 - -declare void @"\01?handle_int@@YAXH@Z"(i32) #1 - -; Function Attrs: nounwind -declare void @llvm.eh.endcatch() #3 - -declare void @"\01?handle_float@@YAXM@Z"(float) #1 - -declare void @"\01?done@@YAXXZ"() #1 - -attributes #0 = { uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } -attributes #1 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } -attributes #2 = { nounwind readnone } -attributes #3 = { nounwind } - -!llvm.module.flags = !{!0} -!llvm.ident = !{!1} - -!0 = !{i32 1, !"PIC Level", i32 2} -!1 = !{!"clang version 3.7.0 (trunk 232069) (llvm/trunk 232070)"} diff --git a/test/CodeGen/WinEH/cppeh-nested-2.ll b/test/CodeGen/WinEH/cppeh-nested-2.ll deleted file mode 100644 index 2764e7478c7..00000000000 --- a/test/CodeGen/WinEH/cppeh-nested-2.ll +++ /dev/null @@ -1,324 +0,0 @@ -; RUN: opt -mtriple=x86_64-pc-windows-msvc -winehprepare -S -o - < %s | FileCheck %s - -; This test is based on the following code: -; -; class Inner { -; public: -; Inner(); -; ~Inner(); -; }; -; class Outer { -; public: -; Outer(); -; ~Outer(); -; }; -; void test() { -; try { -; Outer outer; -; try { -; Inner inner; -; may_throw(); -; } catch (int i) { -; handle_int(i); -; } -; } catch (float f) { -; handle_float(f); -; } -; done(); -; } - -; ModuleID = 'nested-2.cpp' -target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" -target triple = "x86_64-pc-windows-msvc" - -%class.Outer = type { i8 } -%class.Inner = type { i8 } - -@_ZTIf = external constant i8* -@_ZTIi = external constant i8* - -; The function entry should be rewritten like this. -; CHECK: define void @_Z4testv() -; CHECK: entry: -; CHECK: %outer = alloca %class.Outer, align 1 -; CHECK: %inner = alloca %class.Inner, align 1 -; CHECK: %i = alloca i32, align 4 -; CHECK: %f = alloca float, align 4 -; CHECK: call void (...) @llvm.localescape(float* %f, i32* %i, %class.Outer* %outer, %class.Inner* %inner) -; CHECK: invoke void @_ZN5OuterC1Ev(%class.Outer* %outer) -; CHECK: to label %invoke.cont unwind label %[[LPAD_LABEL:lpad[0-9]*]] - -; Function Attrs: uwtable -define void @_Z4testv() #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) { -entry: - %outer = alloca %class.Outer, align 1 - %exn.slot = alloca i8* - %ehselector.slot = alloca i32 - %inner = alloca %class.Inner, align 1 - %i = alloca i32, align 4 - %f = alloca float, align 4 - invoke void @_ZN5OuterC1Ev(%class.Outer* %outer) - to label %invoke.cont unwind label %lpad - -; CHECK: invoke.cont: -; CHECK: invoke void @_ZN5InnerC1Ev(%class.Inner* %inner) -; CHECK: to label %invoke.cont2 unwind label %[[LPAD1_LABEL:lpad[0-9]*]] - -invoke.cont: ; preds = %entry - invoke void @_ZN5InnerC1Ev(%class.Inner* %inner) - to label %invoke.cont2 unwind label %lpad1 - -; CHECK: invoke.cont2: -; CHECK: invoke void @_Z9may_throwv() -; CHECK: to label %invoke.cont4 unwind label %[[LPAD3_LABEL:lpad[0-9]*]] - -invoke.cont2: ; preds = %invoke.cont - invoke void @_Z9may_throwv() - to label %invoke.cont4 unwind label %lpad3 - -; CHECK: invoke.cont4: -; CHECK: invoke void @_ZN5InnerD1Ev(%class.Inner* %inner) -; CHECK: to label %invoke.cont5 unwind label %[[LPAD1_LABEL]] - -invoke.cont4: ; preds = %invoke.cont2 - invoke void @_ZN5InnerD1Ev(%class.Inner* %inner) - to label %invoke.cont5 unwind label %lpad1 - -; CHECK: invoke.cont5: -; CHECK: br label %try.cont - -invoke.cont5: ; preds = %invoke.cont4 - br label %try.cont - -; CHECK: [[LPAD_LABEL]]: -; CHECK: landingpad { i8*, i32 } -; CHECK-NEXT: catch i8* bitcast (i8** @_ZTIf to i8*) -; CHECK-NEXT: [[RECOVER:\%.+]] = call i8* (...) @llvm.eh.actions(i32 1, i8* bitcast (i8** @_ZTIf to i8*), i32 0, i8* (i8*, i8*)* @_Z4testv.catch) -; CHECK-NEXT: indirectbr i8* [[RECOVER]], [label %try.cont19] - -lpad: ; preds = %try.cont, %entry - %tmp = landingpad { i8*, i32 } - catch i8* bitcast (i8** @_ZTIf to i8*) - %tmp1 = extractvalue { i8*, i32 } %tmp, 0 - store i8* %tmp1, i8** %exn.slot - %tmp2 = extractvalue { i8*, i32 } %tmp, 1 - store i32 %tmp2, i32* %ehselector.slot - br label %catch.dispatch11 - -; CHECK: [[LPAD1_LABEL]]: -; CHECK: landingpad { i8*, i32 } -; CHECK-NEXT: cleanup -; CHECK-NEXT: catch i8* bitcast (i8** @_ZTIi to i8*) -; CHECK-NEXT: catch i8* bitcast (i8** @_ZTIf to i8*) -; CHECK-NEXT: [[RECOVER1:\%.+]] = call i8* (...) @llvm.eh.actions( -; CHECK-SAME: i32 1, i8* bitcast (i8** @_ZTIi to i8*), i32 1, i8* (i8*, i8*)* @_Z4testv.catch.1, -; CHECK-SAME: i32 0, void (i8*, i8*)* @_Z4testv.cleanup, -; CHECK-SAME: i32 1, i8* bitcast (i8** @_ZTIf to i8*), i32 0, i8* (i8*, i8*)* @_Z4testv.catch) -; CHECK-NEXT: indirectbr i8* [[RECOVER1]], [label %try.cont, label %try.cont19] - -lpad1: ; preds = %invoke.cont4, %invoke.cont - %tmp3 = landingpad { i8*, i32 } - cleanup - catch i8* bitcast (i8** @_ZTIi to i8*) - catch i8* bitcast (i8** @_ZTIf to i8*) - %tmp4 = extractvalue { i8*, i32 } %tmp3, 0 - store i8* %tmp4, i8** %exn.slot - %tmp5 = extractvalue { i8*, i32 } %tmp3, 1 - store i32 %tmp5, i32* %ehselector.slot - br label %catch.dispatch - -; CHECK: [[LPAD3_LABEL]]: -; CHECK: landingpad { i8*, i32 } -; CHECK-NEXT: cleanup -; CHECK-NEXT: catch i8* bitcast (i8** @_ZTIi to i8*) -; CHECK-NEXT: catch i8* bitcast (i8** @_ZTIf to i8*) -; CHECK-NEXT: [[RECOVER3:\%.+]] = call i8* (...) @llvm.eh.actions( -; CHECK-SAME: i32 0, void (i8*, i8*)* @_Z4testv.cleanup.2, -; CHECK-SAME: i32 1, i8* bitcast (i8** @_ZTIi to i8*), i32 1, i8* (i8*, i8*)* @_Z4testv.catch.1, -; CHECK-SAME: i32 0, void (i8*, i8*)* @_Z4testv.cleanup, -; CHECK-SAME: i32 1, i8* bitcast (i8** @_ZTIf to i8*), i32 0, i8* (i8*, i8*)* @_Z4testv.catch) -; CHECK-NEXT: indirectbr i8* [[RECOVER3]], [label %try.cont, label %try.cont19] - -lpad3: ; preds = %invoke.cont2 - %tmp6 = landingpad { i8*, i32 } - cleanup - catch i8* bitcast (i8** @_ZTIi to i8*) - catch i8* bitcast (i8** @_ZTIf to i8*) - %tmp7 = extractvalue { i8*, i32 } %tmp6, 0 - store i8* %tmp7, i8** %exn.slot - %tmp8 = extractvalue { i8*, i32 } %tmp6, 1 - store i32 %tmp8, i32* %ehselector.slot - call void @_ZN5InnerD1Ev(%class.Inner* %inner) - br label %catch.dispatch - -; CHECK-NOT: catch.dispatch: - -catch.dispatch: ; preds = %lpad3, %lpad1 - %sel = load i32, i32* %ehselector.slot - %tmp9 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*)) #4 - %matches = icmp eq i32 %sel, %tmp9 - br i1 %matches, label %catch, label %ehcleanup - -; CHECK-NOT: catch: - -catch: ; preds = %catch.dispatch - %exn = load i8*, i8** %exn.slot - %i.i8 = bitcast i32* %i to i8* - call void @llvm.eh.begincatch(i8* %exn, i8* %i.i8) #4 - %tmp13 = load i32, i32* %i, align 4 - invoke void @_Z10handle_inti(i32 %tmp13) - to label %invoke.cont8 unwind label %lpad7 - -; CHECK-NOT: invoke.cont8: - -invoke.cont8: ; preds = %catch - call void @llvm.eh.endcatch() #4 - br label %try.cont - -; CHECK: try.cont: -; CHECK: invoke void @_ZN5OuterD1Ev(%class.Outer* %outer) -; CHECK: to label %invoke.cont9 unwind label %[[LPAD_LABEL]] - -try.cont: ; preds = %invoke.cont8, %invoke.cont5 - invoke void @_ZN5OuterD1Ev(%class.Outer* %outer) - to label %invoke.cont9 unwind label %lpad - -invoke.cont9: ; preds = %try.cont - br label %try.cont19 - -; CHECK-NOT: lpad7: - -lpad7: ; preds = %catch - %tmp14 = landingpad { i8*, i32 } - cleanup - catch i8* bitcast (i8** @_ZTIf to i8*) - %tmp15 = extractvalue { i8*, i32 } %tmp14, 0 - store i8* %tmp15, i8** %exn.slot - %tmp16 = extractvalue { i8*, i32 } %tmp14, 1 - store i32 %tmp16, i32* %ehselector.slot - call void @llvm.eh.endcatch() #4 - br label %ehcleanup - -; CHECK-NOT: ehcleanup: ; preds = %lpad7, %catch.dispatch - -ehcleanup: ; preds = %lpad7, %catch.dispatch - call void @_ZN5OuterD1Ev(%class.Outer* %outer) - br label %catch.dispatch11 - -; CHECK-NOT: catch.dispatch11: - -catch.dispatch11: ; preds = %ehcleanup, %lpad - %sel12 = load i32, i32* %ehselector.slot - %tmp17 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIf to i8*)) #4 - %matches13 = icmp eq i32 %sel12, %tmp17 - br i1 %matches13, label %catch14, label %eh.resume - -; CHECK-NOT: catch14: - -catch14: ; preds = %catch.dispatch11 - %exn15 = load i8*, i8** %exn.slot - %f.i8 = bitcast float* %f to i8* - call void @llvm.eh.begincatch(i8* %exn15, i8* %f.i8) #4 - %tmp21 = load float, float* %f, align 4 - call void @_Z12handle_floatf(float %tmp21) - call void @llvm.eh.endcatch() #4 - br label %try.cont19 - -try.cont19: ; preds = %catch14, %invoke.cont9 - call void @_Z4donev() - ret void - -; CHECK-NOT: eh.resume: - -eh.resume: ; preds = %catch.dispatch11 - %exn20 = load i8*, i8** %exn.slot - %sel21 = load i32, i32* %ehselector.slot - %lpad.val = insertvalue { i8*, i32 } undef, i8* %exn20, 0 - %lpad.val22 = insertvalue { i8*, i32 } %lpad.val, i32 %sel21, 1 - resume { i8*, i32 } %lpad.val22 - -; CHECK: } -} - -; This catch handler should be outlined. -; CHECK: define internal i8* @_Z4testv.catch(i8*, i8*) -; CHECK: entry: -; CHECK: [[RECOVER_F:\%.+]] = call i8* @llvm.localrecover(i8* bitcast (void ()* @_Z4testv to i8*), i8* %1, i32 0) -; CHECK: [[F_PTR:\%.+]] = bitcast i8* [[RECOVER_F]] to float* -; CHECK: [[TMP:\%.+]] = load float, float* [[F_PTR]], align 4 -; CHECK: call void @_Z12handle_floatf(float [[TMP]]) -; CHECK: ret i8* blockaddress(@_Z4testv, %try.cont19) -; CHECK: } - -; This catch handler should be outlined. -; CHECK: define internal i8* @_Z4testv.catch.1(i8*, i8*) -; CHECK: entry: -; CHECK: [[RECOVER_I:\%.+]] = call i8* @llvm.localrecover(i8* bitcast (void ()* @_Z4testv to i8*), i8* %1, i32 1) -; CHECK: [[I_PTR:\%.+]] = bitcast i8* [[RECOVER_I]] to i32* -; CHECK: [[TMP1:\%.+]] = load i32, i32* [[I_PTR]], align 4 -; CHECK: invoke void @_Z10handle_inti(i32 [[TMP1]]) -; CHECK: to label %invoke.cont8 unwind label %[[LPAD7_LABEL:lpad[0-9]*]] -; -; CHECK: invoke.cont8: ; preds = %entry -; CHECK: ret i8* blockaddress(@_Z4testv, %try.cont) -; -; CHECK: [[LPAD7_LABEL]]:{{[ ]+}}; preds = %entry -; CHECK: [[LPAD7_VAL:\%.+]] = landingpad { i8*, i32 } -; (FIXME) The nested handler body isn't being populated yet. -; CHECK: } - -; This cleanup handler should be outlined. -; CHECK: define internal void @_Z4testv.cleanup(i8*, i8*) -; CHECK: entry: -; CHECK: [[RECOVER_OUTER:\%.+]] = call i8* @llvm.localrecover(i8* bitcast (void ()* @_Z4testv to i8*), i8* %1, i32 2) -; CHECK: [[OUTER_PTR:\%.+]] = bitcast i8* [[RECOVER_OUTER]] to %class.Outer* -; CHECK: call void @_ZN5OuterD1Ev(%class.Outer* [[OUTER_PTR]]) -; CHECK: ret void -; CHECK: } - -; This cleanup handler should be outlined. -; CHECK: define internal void @_Z4testv.cleanup.2(i8*, i8*) -; CHECK: entry: -; CHECK: [[RECOVER_INNER:\%.+]] = call i8* @llvm.localrecover(i8* bitcast (void ()* @_Z4testv to i8*), i8* %1, i32 3) -; CHECK: [[INNER_PTR:\%.+]] = bitcast i8* [[RECOVER_INNER]] to %class.Inner* -; CHECK: call void @_ZN5InnerD1Ev(%class.Inner* [[INNER_PTR]]) -; CHECK: ret void -; CHECK: } - - - -declare void @_ZN5OuterC1Ev(%class.Outer*) #1 - -declare i32 @__CxxFrameHandler3(...) - -declare void @_ZN5InnerC1Ev(%class.Inner*) #1 - -declare void @_Z9may_throwv() #1 - -declare void @_ZN5InnerD1Ev(%class.Inner*) #1 - -declare void @llvm.eh.begincatch(i8*, i8*) - -; Function Attrs: nounwind readnone -declare i32 @llvm.eh.typeid.for(i8*) #3 - -declare void @_Z10handle_inti(i32) #1 - -declare void @llvm.eh.endcatch() - -declare void @_ZN5OuterD1Ev(%class.Outer*) #1 - -declare void @_Z12handle_floatf(float) #1 - -declare void @_Z4donev() #1 - -attributes #0 = { uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } -attributes #1 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } -attributes #2 = { noinline noreturn nounwind } -attributes #3 = { nounwind readnone } -attributes #4 = { nounwind } -attributes #5 = { noreturn nounwind } - -!llvm.ident = !{!0} - -!0 = !{!"clang version 3.7.0 (trunk 226027)"} diff --git a/test/CodeGen/WinEH/cppeh-nested-3.ll b/test/CodeGen/WinEH/cppeh-nested-3.ll deleted file mode 100644 index 88759f406fb..00000000000 --- a/test/CodeGen/WinEH/cppeh-nested-3.ll +++ /dev/null @@ -1,260 +0,0 @@ -; RUN: opt -mtriple=x86_64-pc-windows-msvc -winehprepare -S -o - < %s | FileCheck %s - -; This test is based on the following code: -; -;void test() -;{ -; try { -; try { -; may_throw(); -; } catch (int i) { -; try { -; may_throw(); -; } -; catch (int j) { -; i = j; -; } -; handle_int(i); -; } -; } catch (float f) { -; handle_float(f); -; } -; done(); -;} - -; ModuleID = 'cppeh-nested-3.cpp' -target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" -target triple = "x86_64-pc-windows-msvc" - -%rtti.TypeDescriptor2 = type { i8**, i8*, [3 x i8] } - -$"\01??_R0M@8" = comdat any - -$"\01??_R0H@8" = comdat any - -@"\01??_7type_info@@6B@" = external constant i8* -@"\01??_R0M@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".M\00" }, comdat -@"\01??_R0H@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".H\00" }, comdat - -; CHECK: define void @"\01?test@@YAXXZ"() -; CHECK: entry: -; CHECK: %i = alloca i32, align 4 -; CHECK: %j = alloca i32, align 4 -; CHECK: %f = alloca float, align 4 -; CHECK: call void (...) @llvm.localescape(i32* %j, i32* %i, float* %f) -; CHECK: invoke void @"\01?may_throw@@YAXXZ"() -; CHECK: to label %invoke.cont unwind label %[[LPAD_LABEL:lpad[0-9]*]] - -; Function Attrs: uwtable -define void @"\01?test@@YAXXZ"() #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) { -entry: - %exn.slot = alloca i8* - %ehselector.slot = alloca i32 - %i = alloca i32, align 4 - %j = alloca i32, align 4 - %f = alloca float, align 4 - invoke void @"\01?may_throw@@YAXXZ"() - to label %invoke.cont unwind label %lpad - -invoke.cont: ; preds = %entry - br label %try.cont10 - -; CHECK: [[LPAD_LABEL]]: -; CHECK: landingpad { i8*, i32 } -; CHECK: catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*) -; CHECK: catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0M@8" to i8*) -; CHECK: [[RECOVER:\%.+]] = call i8* (...) @llvm.eh.actions(i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*), i32 1, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch.2", i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0M@8" to i8*), i32 2, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch.1") -; CHECK: indirectbr i8* [[RECOVER]], [label %try.cont10, label %try.cont19] - -lpad: ; preds = %entry - %0 = landingpad { i8*, i32 } - catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*) - catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0M@8" to i8*) - %1 = extractvalue { i8*, i32 } %0, 0 - store i8* %1, i8** %exn.slot - %2 = extractvalue { i8*, i32 } %0, 1 - store i32 %2, i32* %ehselector.slot - br label %catch.dispatch - -; CHECK-NOT: catch.dispatch: -catch.dispatch: ; preds = %lpad - %sel = load i32, i32* %ehselector.slot - %3 = call i32 @llvm.eh.typeid.for(i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*)) #3 - %matches = icmp eq i32 %sel, %3 - br i1 %matches, label %catch, label %catch.dispatch11 - -; CHECK-NOT: catch: -catch: ; preds = %catch.dispatch - %exn = load i8*, i8** %exn.slot - %4 = bitcast i32* %i to i8* - call void @llvm.eh.begincatch(i8* %exn, i8* %4) #3 - invoke void @"\01?may_throw@@YAXXZ"() - to label %invoke.cont2 unwind label %lpad1 - -; CHECK-NOT: invoke.cont2: -invoke.cont2: ; preds = %catch - br label %try.cont - -; CHECK-NOT: lpad1: -lpad1: ; preds = %catch - %5 = landingpad { i8*, i32 } - catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*) - catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0M@8" to i8*) - %6 = extractvalue { i8*, i32 } %5, 0 - store i8* %6, i8** %exn.slot - %7 = extractvalue { i8*, i32 } %5, 1 - store i32 %7, i32* %ehselector.slot - br label %catch.dispatch3 - -; CHECK-NOT: catch.dispatch3: -catch.dispatch3: ; preds = %lpad1 - %sel4 = load i32, i32* %ehselector.slot - %8 = call i32 @llvm.eh.typeid.for(i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*)) #3 - %matches5 = icmp eq i32 %sel4, %8 - br i1 %matches5, label %catch6, label %catch.dispatch11 - -; CHECK-NOT: catch6: -catch6: ; preds = %catch.dispatch3 - %exn7 = load i8*, i8** %exn.slot - %9 = bitcast i32* %j to i8* - call void @llvm.eh.begincatch(i8* %exn7, i8* %9) #3 - %10 = load i32, i32* %j, align 4 - store i32 %10, i32* %i, align 4 - call void @llvm.eh.endcatch() #3 - br label %try.cont - -; CHECK-NOT: try.cont: -try.cont: ; preds = %catch6, %invoke.cont2 - %11 = load i32, i32* %i, align 4 - invoke void @"\01?handle_int@@YAXH@Z"(i32 %11) - to label %invoke.cont9 unwind label %lpad8 - -; CHECK-NOT: invoke.cont9: -invoke.cont9: ; preds = %try.cont - call void @llvm.eh.endcatch() #3 - br label %try.cont10 - -try.cont10: ; preds = %invoke.cont9, %invoke.cont - br label %try.cont19 - -; CHECK-NOT: lpad8: -lpad8: ; preds = %try.cont - %12 = landingpad { i8*, i32 } - catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0M@8" to i8*) - %13 = extractvalue { i8*, i32 } %12, 0 - store i8* %13, i8** %exn.slot - %14 = extractvalue { i8*, i32 } %12, 1 - store i32 %14, i32* %ehselector.slot - call void @llvm.eh.endcatch() #3 - br label %catch.dispatch11 - -; CHECK-NOT: catch.dispatch11: -catch.dispatch11: ; preds = %lpad8, %catch.dispatch3, %catch.dispatch - %sel12 = load i32, i32* %ehselector.slot - %15 = call i32 @llvm.eh.typeid.for(i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0M@8" to i8*)) #3 - %matches13 = icmp eq i32 %sel12, %15 - br i1 %matches13, label %catch14, label %eh.resume - -; CHECK-NOT: catch14: -catch14: ; preds = %catch.dispatch11 - %exn15 = load i8*, i8** %exn.slot - %16 = bitcast float* %f to i8* - call void @llvm.eh.begincatch(i8* %exn15, i8* %16) #3 - %17 = load float, float* %f, align 4 - call void @"\01?handle_float@@YAXM@Z"(float %17) - call void @llvm.eh.endcatch() #3 - br label %try.cont19 - -try.cont19: ; preds = %catch14, %try.cont10 - call void @"\01?done@@YAXXZ"() - ret void - -; CHECK-NOT: eh.resume: -eh.resume: ; preds = %lpad16, %catch.dispatch11 - %exn20 = load i8*, i8** %exn.slot - %sel21 = load i32, i32* %ehselector.slot - %lpad.val = insertvalue { i8*, i32 } undef, i8* %exn20, 0 - %lpad.val22 = insertvalue { i8*, i32 } %lpad.val, i32 %sel21, 1 - resume { i8*, i32 } %lpad.val22 -; CHECK: } -} - -; CHECK: define internal i8* @"\01?test@@YAXXZ.catch"(i8*, i8*) -; CHECK: entry: -; CHECK: [[RECOVER_J:\%.+]] = call i8* @llvm.localrecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 0) -; CHECK: [[J_PTR:\%.+]] = bitcast i8* [[RECOVER_J]] to i32* -; CHECK: [[RECOVER_I1:\%.+]] = call i8* @llvm.localrecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 1) -; CHECK: [[I_PTR1:\%.+]] = bitcast i8* [[RECOVER_I1]] to i32* -; CHECK: [[TMP3:\%.+]] = load i32, i32* [[J_PTR]], align 4 -; CHECK: store i32 [[TMP3]], i32* [[I_PTR1]] -; CHECK: ret i8* blockaddress(@"\01?test@@YAXXZ.catch.2", %invoke.cont2) -; CHECK: } - -; CHECK: define internal i8* @"\01?test@@YAXXZ.catch.1"(i8*, i8*) -; CHECK: entry: -; CHECK: [[RECOVER_F:\%.+]] = call i8* @llvm.localrecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 2) -; CHECK: [[F_PTR:\%.+]] = bitcast i8* [[RECOVER_F]] to float* -; CHECK: [[TMP2:\%.+]] = load float, float* [[F_PTR]], align 4 -; CHECK: call void @"\01?handle_float@@YAXM@Z"(float [[TMP2]]) -; CHECK: ret i8* blockaddress(@"\01?test@@YAXXZ", %try.cont19) -; CHECK: } - -; CHECK: define internal i8* @"\01?test@@YAXXZ.catch.2"(i8*, i8*) -; CHECK: entry: -; CHECK: [[RECOVER_I:\%.+]] = call i8* @llvm.localrecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 1) -; CHECK: [[I_PTR:\%.+]] = bitcast i8* [[RECOVER_I]] to i32* -; CHECK: invoke void @"\01?may_throw@@YAXXZ"() -; CHECK: to label %invoke.cont2 unwind label %[[LPAD1_LABEL:lpad[0-9]*]] -; -; CHECK: invoke.cont2: ; preds = %[[LPAD1_LABEL]], %entry -; CHECK: [[TMP1:\%.+]] = load i32, i32* [[I_PTR]], align 4 -; CHECK: invoke void @"\01?handle_int@@YAXH@Z"(i32 [[TMP1]]) -; CHECK: to label %invoke.cont9 unwind label %[[LPAD8_LABEL:lpad[0-9]*]] -; -; CHECK: [[LPAD1_LABEL]]:{{[ ]+}}; preds = %entry -; CHECK: [[LPAD1_VAL:\%.+]] = landingpad { i8*, i32 } -; CHECK: catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*) -; CHECK: catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0M@8" to i8*) -; CHECK: [[RECOVER1:\%.+]] = call i8* (...) @llvm.eh.actions(i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*), i32 0, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch", i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0M@8" to i8*), i32 2, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch.1") -; CHECK: indirectbr i8* [[RECOVER1]], [label %invoke.cont2] -; -; CHECK: invoke.cont9: -; CHECK: ret i8* blockaddress(@"\01?test@@YAXXZ", %try.cont10) -; -; CHECK: [[LPAD8_LABEL]]:{{[ ]+}}; preds = %invoke.cont2 -; CHECK: [[LPAD8_VAL:\%.+]] = landingpad { i8*, i32 } -; CHECK: catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0M@8" to i8*) -; CHECK: [[RECOVER2:\%.+]] = call i8* (...) @llvm.eh.actions(i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0M@8" to i8*), i32 2, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch.1") -; CHECK: indirectbr i8* [[RECOVER2]], [] -; -; CHECK: } - -declare void @"\01?may_throw@@YAXXZ"() #1 - -declare i32 @__CxxFrameHandler3(...) - -; Function Attrs: nounwind readnone -declare i32 @llvm.eh.typeid.for(i8*) #2 - -; Function Attrs: nounwind -declare void @llvm.eh.begincatch(i8* nocapture, i8* nocapture) #3 - -; Function Attrs: nounwind -declare void @llvm.eh.endcatch() #3 - -declare void @"\01?handle_int@@YAXH@Z"(i32) #1 - -declare void @"\01?handle_float@@YAXM@Z"(float) #1 - -declare void @"\01?done@@YAXXZ"() #1 - -attributes #0 = { uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } -attributes #1 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } -attributes #2 = { nounwind readnone } -attributes #3 = { nounwind } - -!llvm.module.flags = !{!0} -!llvm.ident = !{!1} - -!0 = !{i32 1, !"PIC Level", i32 2} -!1 = !{!"clang version 3.7.0 (trunk 232069) (llvm/trunk 232070)"} diff --git a/test/CodeGen/WinEH/cppeh-nested-rethrow.ll b/test/CodeGen/WinEH/cppeh-nested-rethrow.ll deleted file mode 100644 index 53f532c8eb1..00000000000 --- a/test/CodeGen/WinEH/cppeh-nested-rethrow.ll +++ /dev/null @@ -1,212 +0,0 @@ -; RUN: opt -mtriple=x86_64-pc-windows-msvc -winehprepare -S -o - < %s | FileCheck %s - -; This test was generated from the following code. -; -; void test1() { -; try { -; try { -; throw 1; -; } catch(...) { throw; } -; } catch (...) { } -; } -; void test2() { -; try { -; throw 1; -; } catch(...) { -; try { -; throw; -; } catch (...) {} -; } -; } -; -; These two functions result in functionally equivalent code, but the last -; catch block contains a call to llvm.eh.endcatch that tripped up processing -; during development. -; -; The main purpose of this test is to verify that we can correctly -; handle the case of nested landing pads that return directly to a block in -; the parent function. - -; ModuleID = 'cppeh-nested-rethrow.cpp' -target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128" -target triple = "x86_64-pc-windows-msvc" - -%rtti.TypeDescriptor2 = type { i8**, i8*, [3 x i8] } -%eh.CatchableType = type { i32, i32, i32, i32, i32, i32, i32 } -%eh.CatchableTypeArray.1 = type { i32, [1 x i32] } -%eh.ThrowInfo = type { i32, i32, i32, i32 } - -$"\01??_R0H@8" = comdat any - -$"_CT??_R0H@84" = comdat any - -$_CTA1H = comdat any - -$_TI1H = comdat any - -@"\01??_7type_info@@6B@" = external constant i8* -@"\01??_R0H@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".H\00" }, comdat -@__ImageBase = external constant i8 -@"_CT??_R0H@84" = linkonce_odr unnamed_addr constant %eh.CatchableType { i32 1, i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32), i32 0, i32 -1, i32 0, i32 4, i32 0 }, section ".xdata", comdat -@_CTA1H = linkonce_odr unnamed_addr constant %eh.CatchableTypeArray.1 { i32 1, [1 x i32] [i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%eh.CatchableType* @"_CT??_R0H@84" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32)] }, section ".xdata", comdat -@_TI1H = linkonce_odr unnamed_addr constant %eh.ThrowInfo { i32 0, i32 0, i32 0, i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%eh.CatchableTypeArray.1* @_CTA1H to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32) }, section ".xdata", comdat - -; CHECK-LABEL: define void @"\01?test1@@YAXXZ"() -; CHECK: entry: -; CHECK: call void (...) @llvm.localescape - -; Function Attrs: nounwind uwtable -define void @"\01?test1@@YAXXZ"() #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) { -entry: - %tmp = alloca i32, align 4 - %exn.slot = alloca i8* - %ehselector.slot = alloca i32 - store i32 1, i32* %tmp - %0 = bitcast i32* %tmp to i8* - invoke void @_CxxThrowException(i8* %0, %eh.ThrowInfo* @_TI1H) #2 - to label %unreachable unwind label %lpad - -lpad: ; preds = %entry - %1 = landingpad { i8*, i32 } - catch i8* null - %2 = extractvalue { i8*, i32 } %1, 0 - store i8* %2, i8** %exn.slot - %3 = extractvalue { i8*, i32 } %1, 1 - store i32 %3, i32* %ehselector.slot - br label %catch - -catch: ; preds = %lpad - %exn = load i8*, i8** %exn.slot - call void @llvm.eh.begincatch(i8* %exn, i8* null) #1 - invoke void @_CxxThrowException(i8* null, %eh.ThrowInfo* null) #2 - to label %unreachable unwind label %lpad1 - -lpad1: ; preds = %catch - %4 = landingpad { i8*, i32 } - catch i8* null - %5 = extractvalue { i8*, i32 } %4, 0 - store i8* %5, i8** %exn.slot - %6 = extractvalue { i8*, i32 } %4, 1 - store i32 %6, i32* %ehselector.slot - br label %catch2 - -catch2: ; preds = %lpad1 - %exn3 = load i8*, i8** %exn.slot - call void @llvm.eh.begincatch(i8* %exn3, i8* null) #1 - call void @llvm.eh.endcatch() #1 - br label %try.cont.4 - -; This block should not be eliminated. -; CHECK: try.cont.4: -try.cont.4: ; preds = %catch2, %try.cont - ret void - -try.cont: ; No predecessors! - br label %try.cont.4 - -unreachable: ; preds = %catch, %entry - unreachable -; CHECK: } -} - -declare void @_CxxThrowException(i8*, %eh.ThrowInfo*) - -declare i32 @__CxxFrameHandler3(...) - -; Function Attrs: nounwind -declare void @llvm.eh.begincatch(i8* nocapture, i8* nocapture) #1 - -; Function Attrs: nounwind -declare void @llvm.eh.endcatch() #1 - -; CHECK-LABEL: define void @"\01?test2@@YAXXZ"() -; CHECK: entry: -; CHECK: call void (...) @llvm.localescape - -; Function Attrs: nounwind uwtable -define void @"\01?test2@@YAXXZ"() #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) { -entry: - %tmp = alloca i32, align 4 - %exn.slot = alloca i8* - %ehselector.slot = alloca i32 - store i32 1, i32* %tmp - %0 = bitcast i32* %tmp to i8* - invoke void @_CxxThrowException(i8* %0, %eh.ThrowInfo* @_TI1H) #2 - to label %unreachable unwind label %lpad - -lpad: ; preds = %entry - %1 = landingpad { i8*, i32 } - catch i8* null - %2 = extractvalue { i8*, i32 } %1, 0 - store i8* %2, i8** %exn.slot - %3 = extractvalue { i8*, i32 } %1, 1 - store i32 %3, i32* %ehselector.slot - br label %catch - -catch: ; preds = %lpad - %exn = load i8*, i8** %exn.slot - call void @llvm.eh.begincatch(i8* %exn, i8* null) #1 - invoke void @_CxxThrowException(i8* null, %eh.ThrowInfo* null) #2 - to label %unreachable unwind label %lpad1 - -lpad1: ; preds = %catch - %4 = landingpad { i8*, i32 } - catch i8* null - %5 = extractvalue { i8*, i32 } %4, 0 - store i8* %5, i8** %exn.slot - %6 = extractvalue { i8*, i32 } %4, 1 - store i32 %6, i32* %ehselector.slot - br label %catch2 - -catch2: ; preds = %lpad1 - %exn3 = load i8*, i8** %exn.slot - call void @llvm.eh.begincatch(i8* %exn3, i8* null) #1 - call void @llvm.eh.endcatch() #1 - br label %try.cont - -; This block should not be eliminated. -; CHECK: try.cont: -; The endcatch call should be eliminated. -; CHECK-NOT: call void @llvm.eh.endcatch() -try.cont: ; preds = %catch2 - call void @llvm.eh.endcatch() #1 - br label %try.cont.4 - -try.cont.4: ; preds = %try.cont - ret void - -unreachable: ; preds = %catch, %entry - unreachable -; CHECK: } -} - -; The outlined test1.catch handler should return to a valid block address. -; CHECK-LABEL: define internal i8* @"\01?test1@@YAXXZ.catch"(i8*, i8*) -; CHECK-NOT: ret i8* inttoptr (i32 1 to i8*) -; CHECK: } - -; The outlined test1.catch1 handler should not contain a return instruction. -; CHECK-LABEL: define internal i8* @"\01?test1@@YAXXZ.catch.1"(i8*, i8*) -; CHECK-NOT: ret -; CHECK: } - -; The outlined test2.catch handler should return to a valid block address. -; CHECK-LABEL: define internal i8* @"\01?test2@@YAXXZ.catch"(i8*, i8*) -; CHECK-NOT: ret i8* inttoptr (i32 1 to i8*) -; CHECK: } - -; The outlined test2.catch2 handler should not contain a return instruction. -; CHECK-LABEL: define internal i8* @"\01?test2@@YAXXZ.catch.2"(i8*, i8*) -; CHECK-NOT: ret -; CHECK: } - - -attributes #0 = { nounwind uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" } -attributes #1 = { nounwind } -attributes #2 = { noreturn } - -!llvm.module.flags = !{!0} -!llvm.ident = !{!1} - -!0 = !{i32 1, !"PIC Level", i32 2} -!1 = !{!"clang version 3.7.0 (trunk 236059)"} diff --git a/test/CodeGen/WinEH/cppeh-nonalloca-frame-values.ll b/test/CodeGen/WinEH/cppeh-nonalloca-frame-values.ll deleted file mode 100644 index 7b474c9d38a..00000000000 --- a/test/CodeGen/WinEH/cppeh-nonalloca-frame-values.ll +++ /dev/null @@ -1,278 +0,0 @@ -; RUN: opt -mtriple=x86_64-pc-windows-msvc -winehprepare -S -o - < %s | FileCheck %s - -; This test is based on the following code: -; -; struct SomeData { -; int a; -; int b; -; }; -; -; void may_throw(); -; void does_not_throw(int i); -; void dump(int *, int, SomeData&); -; -; void test() { -; int NumExceptions = 0; -; int ExceptionVal[10]; -; SomeData Data = { 0, 0 }; -; -; for (int i = 0; i < 10; ++i) { -; try { -; may_throw(); -; Data.a += i; -; } -; catch (int e) { -; ExceptionVal[NumExceptions] = e; -; ++NumExceptions; -; if (e == i) -; Data.b += e; -; else -; Data.a += e; -; } -; does_not_throw(NumExceptions); -; } -; dump(ExceptionVal, NumExceptions, Data); -; } -; -; Unlike the cppeh-frame-vars.ll test, this test was generated using -O2 -; optimization, which results in non-alloca values being used in the -; catch handler. - -; ModuleID = 'cppeh-frame-vars.cpp' -target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" -target triple = "x86_64-pc-windows-msvc" - -%rtti.TypeDescriptor2 = type { i8**, i8*, [3 x i8] } -%struct.SomeData = type { i32, i32 } - -$"\01??_R0H@8" = comdat any - -@"\01??_7type_info@@6B@" = external constant i8* -@"\01??_R0H@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".H\00" }, comdat - -; The function entry should be rewritten like this. -; CHECK: define void @"\01?test@@YAXXZ"() -; CHECK: entry: -; CHECK: [[NUMEXCEPTIONS_REGMEM:\%.+]] = alloca i32 -; CHECK: [[I_REGMEM:\%.+]] = alloca i32 -; CHECK: [[B_REGMEM:\%.+]] = alloca i32* -; CHECK: [[A_REGMEM:\%.+]] = alloca i32* -; CHECK: [[E_PTR:\%.+]] = alloca i32, align 4 -; CHECK: [[EXCEPTIONVAL:\%.+]] = alloca [10 x i32], align 16 -; CHECK: [[DATA_PTR:\%.+]] = alloca i64, align 8 -; CHECK: [[TMPCAST:\%.+]] = bitcast i64* [[DATA_PTR]] to %struct.SomeData* -; CHECK: [[TMP:\%.+]] = bitcast [10 x i32]* [[EXCEPTIONVAL]] to i8* -; CHECK: call void @llvm.lifetime.start(i64 40, i8* [[TMP]]) -; CHECK: store i64 0, i64* [[DATA_PTR]], align 8 -; CHECK: [[A_PTR:\%.+]] = bitcast i64* [[DATA_PTR]] to i32* -; CHECK: store i32* [[A_PTR]], i32** [[A_REGMEM]] -; CHECK: [[B_PTR:\%.+]] = getelementptr inbounds %struct.SomeData, %struct.SomeData* [[TMPCAST]], i64 0, i32 1 -; CHECK: store i32* [[B_PTR]], i32** [[B_REGMEM]] -; CHECK: call void (...) @llvm.localescape(i32* %e, i32* %NumExceptions.020.reg2mem, [10 x i32]* [[EXCEPTIONVAL]], i32* %inc.reg2mem, i32* [[I_REGMEM]], i32** [[A_REGMEM]], i32** [[B_REGMEM]]) -; CHECK: br label %for.body - -; Function Attrs: uwtable -define void @"\01?test@@YAXXZ"() #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) { -entry: - %e = alloca i32, align 4 - %ExceptionVal = alloca [10 x i32], align 16 - %Data = alloca i64, align 8 - %tmpcast = bitcast i64* %Data to %struct.SomeData* - %0 = bitcast [10 x i32]* %ExceptionVal to i8* - call void @llvm.lifetime.start(i64 40, i8* %0) #1 - store i64 0, i64* %Data, align 8 - %a = bitcast i64* %Data to i32* - %b = getelementptr inbounds %struct.SomeData, %struct.SomeData* %tmpcast, i64 0, i32 1 - br label %for.body - -; CHECK: for.body: -; CHECK: [[NUMEXCEPTIONS_PHI:\%.*]] = phi i32 [ 0, %entry ], [ {{\%NumExceptions.*}}, %try.cont ] -; CHECK: [[I_PHI:\%.*]] = phi i32 [ 0, %entry ], [ {{\%inc.*}}, %try.cont ] -; CHECK: store i32 [[I_PHI]], i32* [[I_REGMEM]] -; CHECK: store i32 [[NUMEXCEPTIONS_PHI]], i32* [[NUMEXCEPTIONS_REGMEM]] -; CHECK: invoke void @"\01?may_throw@@YAXXZ"() -for.body: ; preds = %entry, %try.cont - %NumExceptions.020 = phi i32 [ 0, %entry ], [ %NumExceptions.1, %try.cont ] - %i.019 = phi i32 [ 0, %entry ], [ %inc5, %try.cont ] - invoke void @"\01?may_throw@@YAXXZ"() - to label %invoke.cont unwind label %lpad - -; CHECK: invoke.cont: ; preds = %for.body -; CHECK: [[A_RELOAD:\%.+]] = load i32*, i32** [[A_REGMEM]] -; CHECK: [[TMP1:\%.+]] = load i32, i32* [[A_RELOAD]], align 8 -; CHECK: [[I_RELOAD:\%.+]] = load i32, i32* [[I_REGMEM]] -; CHECK: [[ADD:\%.+]] = add nsw i32 [[TMP1]], [[I_RELOAD]] -; CHECK: [[A_RELOAD1:\%.+]] = load i32*, i32** [[A_REGMEM]] -; CHECK: [[NUMEXCEPTIONS_RELOAD:\%.+]] = load i32, i32* [[NUMEXCEPTIONS_REGMEM]] -; CHECK: br label %try.cont -invoke.cont: ; preds = %for.body - %1 = load i32, i32* %a, align 8, !tbaa !2 - %add = add nsw i32 %1, %i.019 - store i32 %add, i32* %a, align 8, !tbaa !2 - br label %try.cont - -; CHECK: [[LPAD_LABEL:lpad[0-9]*]]:{{[ ]+}}; preds = %for.body -; CHECK: landingpad { i8*, i32 } -; CHECK-NEXT: catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*) -; CHECK-NEXT: [[RECOVER:\%.+]] = call i8* (...) @llvm.eh.actions(i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*), i32 0, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch") -; CHECK-NEXT: indirectbr i8* [[RECOVER]], [label %[[SPLIT_RECOVER_BB:.*]]] - -lpad: ; preds = %for.body - %2 = landingpad { i8*, i32 } - catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*) - %3 = extractvalue { i8*, i32 } %2, 1 - %4 = tail call i32 @llvm.eh.typeid.for(i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*)) #1 - %matches = icmp eq i32 %3, %4 - br i1 %matches, label %catch, label %eh.resume - -; CHECK-NOT: catch: - -catch: ; preds = %lpad - %5 = extractvalue { i8*, i32 } %2, 0 - %e.i8 = bitcast i32* %e to i8* - call void @llvm.eh.begincatch(i8* %5, i8* %e.i8) #1 - %tmp8 = load i32, i32* %e, align 4, !tbaa !7 - %idxprom = sext i32 %NumExceptions.020 to i64 - %arrayidx = getelementptr inbounds [10 x i32], [10 x i32]* %ExceptionVal, i64 0, i64 %idxprom - store i32 %tmp8, i32* %arrayidx, align 4, !tbaa !7 - %inc = add nsw i32 %NumExceptions.020, 1 - %cmp1 = icmp eq i32 %tmp8, %i.019 - br i1 %cmp1, label %if.then, label %if.else - -if.then: ; preds = %catch - %tmp9 = load i32, i32* %b, align 4, !tbaa !8 - %add2 = add nsw i32 %tmp9, %i.019 - store i32 %add2, i32* %b, align 4, !tbaa !8 - br label %if.end - -; CHECK-NOT: if.else: - -if.else: ; preds = %catch - %tmp10 = load i32, i32* %a, align 8, !tbaa !2 - %add4 = add nsw i32 %tmp10, %tmp8 - store i32 %add4, i32* %a, align 8, !tbaa !2 - br label %if.end - -; CHECK-NOT: if.end: -; CHECK: [[SPLIT_RECOVER_BB]]: -; CHECK: [[INC_RELOAD:\%.*]] = load i32, i32* -; CHECK: br label %try.cont - -if.end: ; preds = %if.else, %if.then - tail call void @llvm.eh.endcatch() #1 - br label %try.cont - -; CHECK: try.cont:{{[ ]+}}; preds = %[[SPLIT_RECOVER_BB]], %invoke.cont -; CHECK: [[NUMEXCEPTIONS_PHI:\%.*]] = phi i32 [ [[NUMEXCEPTIONS_RELOAD]], %invoke.cont ], [ [[INC_RELOAD]], %[[SPLIT_RECOVER_BB]] ] -; CHECK: tail call void @"\01?does_not_throw@@YAXH@Z"(i32 [[NUMEXCEPTIONS_PHI]]) -; CHECK: [[I_RELOAD:\%.+]] = load i32, i32* [[I_REGMEM]] -; CHECK: [[INC:\%.+]] = add nuw nsw i32 [[I_RELOAD]], 1 -; CHECK: [[CMP:\%.+]] = icmp slt i32 [[INC]], 10 -; CHECK: br i1 [[CMP]], label %for.body, label %for.end - -try.cont: ; preds = %if.end, %invoke.cont - %NumExceptions.1 = phi i32 [ %NumExceptions.020, %invoke.cont ], [ %inc, %if.end ] - tail call void @"\01?does_not_throw@@YAXH@Z"(i32 %NumExceptions.1) - %inc5 = add nuw nsw i32 %i.019, 1 - %cmp = icmp slt i32 %inc5, 10 - br i1 %cmp, label %for.body, label %for.end - -for.end: ; preds = %try.cont - %NumExceptions.1.lcssa = phi i32 [ %NumExceptions.1, %try.cont ] - %arraydecay = getelementptr inbounds [10 x i32], [10 x i32]* %ExceptionVal, i64 0, i64 0 - call void @"\01?dump@@YAXPEAHHAEAUSomeData@@@Z"(i32* %arraydecay, i32 %NumExceptions.1.lcssa, %struct.SomeData* dereferenceable(8) %tmpcast) - call void @llvm.lifetime.end(i64 40, i8* %0) #1 - ret void - -eh.resume: ; preds = %lpad - %.lcssa = phi { i8*, i32 } [ %2, %lpad ] - resume { i8*, i32 } %.lcssa -} - -; The following catch handler should be outlined. -; CHECK: define internal i8* @"\01?test@@YAXXZ.catch"(i8*, i8*) -; CHECK: entry: -; CHECK: [[RECOVER_E:\%.+]] = call i8* @llvm.localrecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 0) -; CHECK: [[E_PTR:\%.+]] = bitcast i8* [[RECOVER_E]] to i32* -; CHECK: [[RECOVER_NUMEXCEPTIONS:\%.+]] = call i8* @llvm.localrecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 1) -; CHECK: [[NUMEXCEPTIONS_REGMEM:\%.+]] = bitcast i8* [[RECOVER_NUMEXCEPTIONS]] to i32* -; CHECK: [[RECOVER_EXCEPTIONVAL:\%.+]] = call i8* @llvm.localrecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 2) -; CHECK: [[EXCEPTIONVAL:\%.+]] = bitcast i8* [[RECOVER_EXCEPTIONVAL]] to [10 x i32]* -; CHECK: [[RECOVER_INC:\%.+]] = call i8* @llvm.localrecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 3) -; CHECK: [[INC_REGMEM:\%.+]] = bitcast i8* [[RECOVER_INC]] to i32* -; CHECK: [[RECOVER_I:\%.+]] = call i8* @llvm.localrecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 4) -; CHECK: [[I_REGMEM:\%.+]] = bitcast i8* [[RECOVER_I]] to i32* -; CHECK: [[RECOVER_A:\%.+]] = call i8* @llvm.localrecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 5) -; CHECK: [[A_REGMEM:\%.+]] = bitcast i8* [[RECOVER_A]] to i32** -; CHECK: [[RECOVER_B:\%.+]] = call i8* @llvm.localrecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 6) -; CHECK: [[B_REGMEM:\%.+]] = bitcast i8* [[RECOVER_B]] to i32** -; CHECK: [[E_I8PTR:\%.+]] = bitcast i32* [[E_PTR]] to i8* -; CHECK: [[TMP:\%.+]] = load i32, i32* [[E_PTR]], align 4 -; CHECK: [[NUMEXCEPTIONS_RELOAD:\%.+]] = load i32, i32* [[NUMEXCEPTIONS_REGMEM]] -; CHECK: [[IDXPROM:\%.+]] = sext i32 [[NUMEXCEPTIONS_RELOAD]] to i64 -; CHECK: [[ARRAYIDX:\%.+]] = getelementptr inbounds [10 x i32], [10 x i32]* [[EXCEPTIONVAL]], i64 0, i64 [[IDXPROM]] -; CHECK: store i32 [[TMP]], i32* [[ARRAYIDX]], align 4 -; CHECK: [[NUMEXCEPTIONS_RELOAD:\%.+]] = load i32, i32* [[NUMEXCEPTIONS_REGMEM]] -; CHECK: [[INC:\%.+]] = add nsw i32 [[NUMEXCEPTIONS_RELOAD]], 1 -; CHECK: [[CMP:\%.+]] = icmp eq i32 [[TMP]], [[I_RELOAD]] -; CHECK: br i1 [[CMP]], label %if.then, label %if.else -; -; CHECK: if.then:{{[ ]+}}; preds = %entry -; CHECK: [[B_RELOAD:\%.+]] = load i32*, i32** [[B_REGMEM]] -; CHECK: [[TMP1:\%.+]] = load i32, i32* [[B_RELOAD]], align 4 -; CHECK: [[I_RELOAD:\%.+]] = load i32, i32* [[I_REGMEM]] -; CHECK: [[ADD:\%.+]] = add nsw i32 [[TMP1]], [[I_RELOAD]] -; CHECK: [[B_RELOAD:\%.+]] = load i32*, i32** [[B_REGMEM]] -; CHECK: store i32 [[ADD]], i32* [[B_RELOAD]], align 4 -; CHECK: br label %if.end -; -; CHECK: if.else:{{[ ]+}}; preds = %entry -; CHECK: [[A_RELOAD:\%.+]] = load i32*, i32** [[A_REGMEM]] -; CHECK: [[TMP2:\%.+]] = load i32, i32* [[A_RELOAD]], align 8 -; CHECK: [[ADD2:\%.+]] = add nsw i32 [[TMP2]], [[TMP]] -; CHECK: [[A_RELOAD:\%.+]] = load i32*, i32** [[A_REGMEM]] -; CHECK: store i32 [[ADD2]], i32* [[A_RELOAD]], align 8 -; CHECK: br label %if.end -; -; CHECK: if.end:{{[ ]+}}; preds = %if.else, %if.then -; CHECK: ret i8* blockaddress(@"\01?test@@YAXXZ", %[[SPLIT_RECOVER_BB]]) -; CHECK: } - -; Function Attrs: nounwind -declare void @llvm.lifetime.start(i64, i8* nocapture) #1 - -declare void @"\01?may_throw@@YAXXZ"() #2 - -declare i32 @__CxxFrameHandler3(...) - -; Function Attrs: nounwind readnone -declare i32 @llvm.eh.typeid.for(i8*) #3 - -declare void @llvm.eh.begincatch(i8*, i8*) - -declare void @llvm.eh.endcatch() - -declare void @"\01?does_not_throw@@YAXH@Z"(i32) #2 - -declare void @"\01?dump@@YAXPEAHHAEAUSomeData@@@Z"(i32*, i32, %struct.SomeData* dereferenceable(8)) #2 - -; Function Attrs: nounwind -declare void @llvm.lifetime.end(i64, i8* nocapture) #1 - -attributes #0 = { uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } -attributes #1 = { nounwind } -attributes #2 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } -attributes #3 = { nounwind readnone } - -!llvm.module.flags = !{!0} -!llvm.ident = !{!1} - -!0 = !{i32 1, !"PIC Level", i32 2} -!1 = !{!"clang version 3.7.0 (trunk 228868)"} -!2 = !{!3, !4, i64 0} -!3 = !{!"?AUSomeData@@", !4, i64 0, !4, i64 4} -!4 = !{!"int", !5, i64 0} -!5 = !{!"omnipotent char", !6, i64 0} -!6 = !{!"Simple C/C++ TBAA"} -!7 = !{!4, !4, i64 0} -!8 = !{!3, !4, i64 4} diff --git a/test/CodeGen/WinEH/cppeh-shared-empty-catch.ll b/test/CodeGen/WinEH/cppeh-shared-empty-catch.ll deleted file mode 100644 index 87ccc9d9ded..00000000000 --- a/test/CodeGen/WinEH/cppeh-shared-empty-catch.ll +++ /dev/null @@ -1,110 +0,0 @@ -; RUN: opt -mtriple=x86_64-pc-windows-msvc -winehprepare -S -o - < %s | FileCheck %s - -; This test is based on the following source, built with -O2 -; -; void f() { -; try { -; g(); -; try { -; throw; -; } catch (int) { -; } -; } catch (...) { -; } -; } -; - -; ModuleID = '' -target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128" -target triple = "x86_64-pc-windows-msvc" - -%rtti.TypeDescriptor2 = type { i8**, i8*, [3 x i8] } -%eh.CatchHandlerType = type { i32, i8* } -%eh.ThrowInfo = type { i32, i32, i32, i32 } - -$"\01??_R0H@8" = comdat any - -@"\01??_7type_info@@6B@" = external constant i8* -@"\01??_R0H@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".H\00" }, comdat -@llvm.eh.handlertype.H.0 = private unnamed_addr constant %eh.CatchHandlerType { i32 0, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*) }, section "llvm.metadata" - -; CHECK-LABEL: define void @"\01?f@@YAXXZ"() -; CHECK: entry: -; CHECK: call void (...) @llvm.localescape() -; CHECK: invoke void @"\01?g@@YAXXZ"() - -; Function Attrs: nounwind -define void @"\01?f@@YAXXZ"() #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) { -entry: - invoke void @"\01?g@@YAXXZ"() - to label %invoke.cont unwind label %lpad - -; CHECK-LABEL: invoke.cont: -; CHECK: invoke void @_CxxThrowException(i8* null, %eh.ThrowInfo* null) -; CHECK: to label %unreachable unwind label %[[LPAD1_LABEL:lpad[0-9]+]] - -invoke.cont: ; preds = %entry - invoke void @_CxxThrowException(i8* null, %eh.ThrowInfo* null) #4 - to label %unreachable unwind label %lpad1 - -lpad: ; preds = %entry - %0 = landingpad { i8*, i32 } - catch i8* null - %1 = extractvalue { i8*, i32 } %0, 0 - br label %catch2 - -; Note: Even though this landing pad has two catch clauses, it only has one action because both -; handlers do the same thing. -; CHECK: [[LPAD1_LABEL]]: -; CHECK: landingpad { i8*, i32 } -; CHECK-NEXT: catch %eh.CatchHandlerType* @llvm.eh.handlertype.H.0 -; CHECK-NEXT: catch i8* null -; CHECK-NEXT: [[RECOVER:\%.+]] = call i8* (...) @llvm.eh.actions(i32 1, i8* null, i32 -1, i8* (i8*, i8*)* @"\01?f@@YAXXZ.catch") -; CHECK-NEXT: indirectbr i8* [[RECOVER]], [label %try.cont4] - -lpad1: ; preds = %invoke.cont - %2 = landingpad { i8*, i32 } - catch %eh.CatchHandlerType* @llvm.eh.handlertype.H.0 - catch i8* null - %3 = extractvalue { i8*, i32 } %2, 0 - br label %catch2 - -catch2: ; preds = %lpad1, %lpad - %exn.slot.0 = phi i8* [ %3, %lpad1 ], [ %1, %lpad ] - tail call void @llvm.eh.begincatch(i8* %exn.slot.0, i8* null) #3 - tail call void @llvm.eh.endcatch() #3 - br label %try.cont4 - -try.cont4: ; preds = %catch, %catch2 - ret void - -unreachable: ; preds = %invoke.cont - unreachable - -; CHECK: } -} - -declare void @"\01?g@@YAXXZ"() #1 - -declare i32 @__CxxFrameHandler3(...) - -declare void @_CxxThrowException(i8*, %eh.ThrowInfo*) - -; Function Attrs: nounwind readnone -declare i32 @llvm.eh.typeid.for(i8*) #2 - -; Function Attrs: nounwind -declare void @llvm.eh.begincatch(i8* nocapture, i8* nocapture) #3 - -; Function Attrs: nounwind -declare void @llvm.eh.endcatch() #3 - -attributes #0 = { nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } -attributes #1 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } -attributes #2 = { nounwind readnone } -attributes #3 = { nounwind } -attributes #4 = { noreturn } - -!llvm.ident = !{!0} - -!0 = !{!"clang version 3.7.0 (trunk 235112) (llvm/trunk 235121)"} diff --git a/test/CodeGen/WinEH/cppeh-similar-catch-blocks.ll b/test/CodeGen/WinEH/cppeh-similar-catch-blocks.ll deleted file mode 100644 index 09213536815..00000000000 --- a/test/CodeGen/WinEH/cppeh-similar-catch-blocks.ll +++ /dev/null @@ -1,394 +0,0 @@ -; RUN: opt -mtriple=x86_64-pc-windows-msvc -winehprepare -S -o - < %s | FileCheck %s - -; This test is based on the following code: -; -; int main(void) { -; try { -; try { -; throw 'a'; -; } catch (char c) { -; printf("%c\n", c); -; } -; throw 1; -; } catch(int x) { -; printf("%d\n", x); -; } catch(...) { -; printf("...\n"); -; } -; try { -; try { -; throw 'b'; -; } catch (char c) { -; printf("%c\n", c); -; } -; throw 2; -; } catch(int x) { -; printf("%d\n", x); -; } catch (char c) { -; printf("%c\n", c); -; } catch(...) { -; printf("...\n"); -; } -; return 0; -; } - -; This test is just checking for failures in processing the IR. -; Extensive handler matching is not required. - -; ModuleID = 'cppeh-similar-catch-blocks.cpp' -target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128" -target triple = "x86_64-pc-windows-msvc" - -%rtti.TypeDescriptor2 = type { i8**, i8*, [3 x i8] } -%eh.CatchHandlerType = type { i32, i8* } -%eh.CatchableType = type { i32, i32, i32, i32, i32, i32, i32 } -%eh.CatchableTypeArray.1 = type { i32, [1 x i32] } -%eh.ThrowInfo = type { i32, i32, i32, i32 } - -$"\01??_R0H@8" = comdat any - -$"\01??_R0D@8" = comdat any - -$"_CT??_R0D@81" = comdat any - -$_CTA1D = comdat any - -$_TI1D = comdat any - -$"\01??_C@_03PJCJOCBM@?$CFc?6?$AA@" = comdat any - -$"_CT??_R0H@84" = comdat any - -$_CTA1H = comdat any - -$_TI1H = comdat any - -$"\01??_C@_04MPPNMCOK@?4?4?4?6?$AA@" = comdat any - -$"\01??_C@_03PMGGPEJJ@?$CFd?6?$AA@" = comdat any - -@"\01??_7type_info@@6B@" = external constant i8* -@"\01??_R0H@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".H\00" }, comdat -@llvm.eh.handlertype.H.0 = private unnamed_addr constant %eh.CatchHandlerType { i32 0, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*) }, section "llvm.metadata" -@"\01??_R0D@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".D\00" }, comdat -@llvm.eh.handlertype.D.0 = private unnamed_addr constant %eh.CatchHandlerType { i32 0, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0D@8" to i8*) }, section "llvm.metadata" -@__ImageBase = external constant i8 -@"_CT??_R0D@81" = linkonce_odr unnamed_addr constant %eh.CatchableType { i32 1, i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.TypeDescriptor2* @"\01??_R0D@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32), i32 0, i32 -1, i32 0, i32 1, i32 0 }, section ".xdata", comdat -@_CTA1D = linkonce_odr unnamed_addr constant %eh.CatchableTypeArray.1 { i32 1, [1 x i32] [i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%eh.CatchableType* @"_CT??_R0D@81" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32)] }, section ".xdata", comdat -@_TI1D = linkonce_odr unnamed_addr constant %eh.ThrowInfo { i32 0, i32 0, i32 0, i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%eh.CatchableTypeArray.1* @_CTA1D to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32) }, section ".xdata", comdat -@"\01??_C@_03PJCJOCBM@?$CFc?6?$AA@" = linkonce_odr unnamed_addr constant [4 x i8] c"%c\0A\00", comdat, align 1 -@"_CT??_R0H@84" = linkonce_odr unnamed_addr constant %eh.CatchableType { i32 1, i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32), i32 0, i32 -1, i32 0, i32 4, i32 0 }, section ".xdata", comdat -@_CTA1H = linkonce_odr unnamed_addr constant %eh.CatchableTypeArray.1 { i32 1, [1 x i32] [i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%eh.CatchableType* @"_CT??_R0H@84" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32)] }, section ".xdata", comdat -@_TI1H = linkonce_odr unnamed_addr constant %eh.ThrowInfo { i32 0, i32 0, i32 0, i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%eh.CatchableTypeArray.1* @_CTA1H to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32) }, section ".xdata", comdat -@"\01??_C@_04MPPNMCOK@?4?4?4?6?$AA@" = linkonce_odr unnamed_addr constant [5 x i8] c"...\0A\00", comdat, align 1 -@"\01??_C@_03PMGGPEJJ@?$CFd?6?$AA@" = linkonce_odr unnamed_addr constant [4 x i8] c"%d\0A\00", comdat, align 1 - -; This is just a minimal check to verify that main was handled by WinEHPrepare. -; CHECK: define i32 @main() -; CHECK: entry: -; CHECK: call void (...) @llvm.localescape(i32* [[X_PTR:\%.+]], i32* [[X2_PTR:\%.+]], i8* [[C2_PTR:\%.+]], i8* [[C3_PTR:\%.+]], i8* [[C_PTR:\%.+]]) -; CHECK: invoke void @_CxxThrowException -; CHECK: } - -; Function Attrs: uwtable -define i32 @main() #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) { -entry: - %retval = alloca i32, align 4 - %tmp = alloca i8, align 1 - %exn.slot = alloca i8* - %ehselector.slot = alloca i32 - %c = alloca i8, align 1 - %tmp3 = alloca i32, align 4 - %x = alloca i32, align 4 - %tmp20 = alloca i8, align 1 - %c28 = alloca i8, align 1 - %tmp34 = alloca i32, align 4 - %c48 = alloca i8, align 1 - %x56 = alloca i32, align 4 - store i32 0, i32* %retval - store i8 97, i8* %tmp - invoke void @_CxxThrowException(i8* %tmp, %eh.ThrowInfo* @_TI1D) #4 - to label %unreachable unwind label %lpad - -lpad: ; preds = %entry - %0 = landingpad { i8*, i32 } - catch %eh.CatchHandlerType* @llvm.eh.handlertype.D.0 - catch %eh.CatchHandlerType* @llvm.eh.handlertype.H.0 - catch i8* null - %1 = extractvalue { i8*, i32 } %0, 0 - store i8* %1, i8** %exn.slot - %2 = extractvalue { i8*, i32 } %0, 1 - store i32 %2, i32* %ehselector.slot - br label %catch.dispatch - -catch.dispatch: ; preds = %lpad - %sel = load i32, i32* %ehselector.slot - %3 = call i32 @llvm.eh.typeid.for(i8* bitcast (%eh.CatchHandlerType* @llvm.eh.handlertype.D.0 to i8*)) #2 - %matches = icmp eq i32 %sel, %3 - br i1 %matches, label %catch, label %catch.dispatch5 - -catch: ; preds = %catch.dispatch - %exn = load i8*, i8** %exn.slot - call void @llvm.eh.begincatch(i8* %exn, i8* %c) #2 - %4 = load i8, i8* %c, align 1 - %conv = sext i8 %4 to i32 - %call = invoke i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @"\01??_C@_03PJCJOCBM@?$CFc?6?$AA@", i32 0, i32 0), i32 %conv) - to label %invoke.cont unwind label %lpad2 - -invoke.cont: ; preds = %catch - call void @llvm.eh.endcatch() #2 - br label %try.cont - -try.cont: ; preds = %invoke.cont - store i32 1, i32* %tmp3 - %5 = bitcast i32* %tmp3 to i8* - invoke void @_CxxThrowException(i8* %5, %eh.ThrowInfo* @_TI1H) #4 - to label %unreachable unwind label %lpad4 - -lpad2: ; preds = %catch - %6 = landingpad { i8*, i32 } - catch %eh.CatchHandlerType* @llvm.eh.handlertype.H.0 - catch i8* null - %7 = extractvalue { i8*, i32 } %6, 0 - store i8* %7, i8** %exn.slot - %8 = extractvalue { i8*, i32 } %6, 1 - store i32 %8, i32* %ehselector.slot - call void @llvm.eh.endcatch() #2 - br label %catch.dispatch5 - -lpad4: ; preds = %try.cont - %9 = landingpad { i8*, i32 } - catch %eh.CatchHandlerType* @llvm.eh.handlertype.H.0 - catch i8* null - %10 = extractvalue { i8*, i32 } %9, 0 - store i8* %10, i8** %exn.slot - %11 = extractvalue { i8*, i32 } %9, 1 - store i32 %11, i32* %ehselector.slot - br label %catch.dispatch5 - -catch.dispatch5: ; preds = %lpad4, %lpad2, %catch.dispatch - %sel6 = load i32, i32* %ehselector.slot - %12 = call i32 @llvm.eh.typeid.for(i8* bitcast (%eh.CatchHandlerType* @llvm.eh.handlertype.H.0 to i8*)) #2 - %matches7 = icmp eq i32 %sel6, %12 - br i1 %matches7, label %catch13, label %catch8 - -catch13: ; preds = %catch.dispatch5 - %exn14 = load i8*, i8** %exn.slot - %13 = bitcast i32* %x to i8* - call void @llvm.eh.begincatch(i8* %exn14, i8* %13) #2 - %14 = load i32, i32* %x, align 4 - %call18 = invoke i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @"\01??_C@_03PMGGPEJJ@?$CFd?6?$AA@", i32 0, i32 0), i32 %14) - to label %invoke.cont17 unwind label %lpad16 - -invoke.cont17: ; preds = %catch13 - call void @llvm.eh.endcatch() #2 - br label %try.cont19 - -try.cont19: ; preds = %invoke.cont17, %invoke.cont11 - store i8 98, i8* %tmp20 - invoke void @_CxxThrowException(i8* %tmp20, %eh.ThrowInfo* @_TI1D) #4 - to label %unreachable unwind label %lpad21 - -catch8: ; preds = %catch.dispatch5 - %exn9 = load i8*, i8** %exn.slot - call void @llvm.eh.begincatch(i8* %exn9, i8* null) #2 - %call12 = invoke i32 (i8*, ...) @printf(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @"\01??_C@_04MPPNMCOK@?4?4?4?6?$AA@", i32 0, i32 0)) - to label %invoke.cont11 unwind label %lpad10 - -invoke.cont11: ; preds = %catch8 - call void @llvm.eh.endcatch() #2 - br label %try.cont19 - -lpad10: ; preds = %catch8 - %15 = landingpad { i8*, i32 } - cleanup - %16 = extractvalue { i8*, i32 } %15, 0 - store i8* %16, i8** %exn.slot - %17 = extractvalue { i8*, i32 } %15, 1 - store i32 %17, i32* %ehselector.slot - call void @llvm.eh.endcatch() #2 - br label %eh.resume - -lpad16: ; preds = %catch13 - %18 = landingpad { i8*, i32 } - cleanup - %19 = extractvalue { i8*, i32 } %18, 0 - store i8* %19, i8** %exn.slot - %20 = extractvalue { i8*, i32 } %18, 1 - store i32 %20, i32* %ehselector.slot - call void @llvm.eh.endcatch() #2 - br label %eh.resume - -lpad21: ; preds = %try.cont19 - %21 = landingpad { i8*, i32 } - catch i8* bitcast (%eh.CatchHandlerType* @llvm.eh.handlertype.D.0 to i8*) - catch i8* bitcast (%eh.CatchHandlerType* @llvm.eh.handlertype.H.0 to i8*) - catch i8* null - %22 = extractvalue { i8*, i32 } %21, 0 - store i8* %22, i8** %exn.slot - %23 = extractvalue { i8*, i32 } %21, 1 - store i32 %23, i32* %ehselector.slot - br label %catch.dispatch22 - -catch.dispatch22: ; preds = %lpad21 - %sel23 = load i32, i32* %ehselector.slot - %24 = call i32 @llvm.eh.typeid.for(i8* bitcast (%eh.CatchHandlerType* @llvm.eh.handlertype.D.0 to i8*)) #2 - %matches24 = icmp eq i32 %sel23, %24 - br i1 %matches24, label %catch25, label %catch.dispatch36 - -catch25: ; preds = %catch.dispatch22 - %exn26 = load i8*, i8** %exn.slot - call void @llvm.eh.begincatch(i8* %exn26, i8* %c28) #2 - %25 = load i8, i8* %c28, align 1 - %conv29 = sext i8 %25 to i32 - %call32 = invoke i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @"\01??_C@_03PJCJOCBM@?$CFc?6?$AA@", i32 0, i32 0), i32 %conv29) - to label %invoke.cont31 unwind label %lpad30 - -invoke.cont31: ; preds = %catch25 - call void @llvm.eh.endcatch() #2 - br label %try.cont33 - -try.cont33: ; preds = %invoke.cont31 - store i32 2, i32* %tmp34 - %26 = bitcast i32* %tmp34 to i8* - invoke void @_CxxThrowException(i8* %26, %eh.ThrowInfo* @_TI1H) #4 - to label %unreachable unwind label %lpad35 - -lpad30: ; preds = %catch25 - %27 = landingpad { i8*, i32 } - catch i8* bitcast (%eh.CatchHandlerType* @llvm.eh.handlertype.H.0 to i8*) - catch i8* bitcast (%eh.CatchHandlerType* @llvm.eh.handlertype.D.0 to i8*) - catch i8* null - %28 = extractvalue { i8*, i32 } %27, 0 - store i8* %28, i8** %exn.slot - %29 = extractvalue { i8*, i32 } %27, 1 - store i32 %29, i32* %ehselector.slot - call void @llvm.eh.endcatch() #2 - br label %catch.dispatch36 - -lpad35: ; preds = %try.cont33 - %30 = landingpad { i8*, i32 } - catch i8* bitcast (%eh.CatchHandlerType* @llvm.eh.handlertype.H.0 to i8*) - catch i8* bitcast (%eh.CatchHandlerType* @llvm.eh.handlertype.D.0 to i8*) - catch i8* null - %31 = extractvalue { i8*, i32 } %30, 0 - store i8* %31, i8** %exn.slot - %32 = extractvalue { i8*, i32 } %30, 1 - store i32 %32, i32* %ehselector.slot - br label %catch.dispatch36 - -catch.dispatch36: ; preds = %lpad35, %lpad30, %catch.dispatch22 - %sel37 = load i32, i32* %ehselector.slot - %33 = call i32 @llvm.eh.typeid.for(i8* bitcast (%eh.CatchHandlerType* @llvm.eh.handlertype.H.0 to i8*)) #2 - %matches38 = icmp eq i32 %sel37, %33 - br i1 %matches38, label %catch53, label %catch.fallthrough - -catch53: ; preds = %catch.dispatch36 - %exn54 = load i8*, i8** %exn.slot - %34 = bitcast i32* %x56 to i8* - call void @llvm.eh.begincatch(i8* %exn54, i8* %34) #2 - %35 = load i32, i32* %x56, align 4 - %call59 = invoke i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @"\01??_C@_03PMGGPEJJ@?$CFd?6?$AA@", i32 0, i32 0), i32 %35) - to label %invoke.cont58 unwind label %lpad57 - -invoke.cont58: ; preds = %catch53 - call void @llvm.eh.endcatch() #2 - br label %try.cont60 - -try.cont60: ; preds = %invoke.cont58, %invoke.cont51, %invoke.cont43 - ret i32 0 - -catch.fallthrough: ; preds = %catch.dispatch36 - %36 = call i32 @llvm.eh.typeid.for(i8* bitcast (%eh.CatchHandlerType* @llvm.eh.handlertype.D.0 to i8*)) #2 - %matches39 = icmp eq i32 %sel37, %36 - br i1 %matches39, label %catch45, label %catch40 - -catch45: ; preds = %catch.fallthrough - %exn46 = load i8*, i8** %exn.slot - call void @llvm.eh.begincatch(i8* %exn46, i8* %c48) #2 - %37 = load i8, i8* %c48, align 1 - %conv49 = sext i8 %37 to i32 - %call52 = invoke i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @"\01??_C@_03PJCJOCBM@?$CFc?6?$AA@", i32 0, i32 0), i32 %conv49) - to label %invoke.cont51 unwind label %lpad50 - -invoke.cont51: ; preds = %catch45 - call void @llvm.eh.endcatch() #2 - br label %try.cont60 - -catch40: ; preds = %catch.fallthrough - %exn41 = load i8*, i8** %exn.slot - call void @llvm.eh.begincatch(i8* %exn41, i8* null) #2 - %call44 = invoke i32 (i8*, ...) @printf(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @"\01??_C@_04MPPNMCOK@?4?4?4?6?$AA@", i32 0, i32 0)) - to label %invoke.cont43 unwind label %lpad42 - -invoke.cont43: ; preds = %catch40 - call void @llvm.eh.endcatch() #2 - br label %try.cont60 - -lpad42: ; preds = %catch40 - %38 = landingpad { i8*, i32 } - cleanup - %39 = extractvalue { i8*, i32 } %38, 0 - store i8* %39, i8** %exn.slot - %40 = extractvalue { i8*, i32 } %38, 1 - store i32 %40, i32* %ehselector.slot - call void @llvm.eh.endcatch() #2 - br label %eh.resume - -lpad50: ; preds = %catch45 - %41 = landingpad { i8*, i32 } - cleanup - %42 = extractvalue { i8*, i32 } %41, 0 - store i8* %42, i8** %exn.slot - %43 = extractvalue { i8*, i32 } %41, 1 - store i32 %43, i32* %ehselector.slot - call void @llvm.eh.endcatch() #2 - br label %eh.resume - -lpad57: ; preds = %catch53 - %44 = landingpad { i8*, i32 } - cleanup - %45 = extractvalue { i8*, i32 } %44, 0 - store i8* %45, i8** %exn.slot - %46 = extractvalue { i8*, i32 } %44, 1 - store i32 %46, i32* %ehselector.slot - call void @llvm.eh.endcatch() #2 - br label %eh.resume - -eh.resume: ; preds = %lpad57, %lpad50, %lpad42, %lpad16, %lpad10 - %exn61 = load i8*, i8** %exn.slot - %sel62 = load i32, i32* %ehselector.slot - %lpad.val = insertvalue { i8*, i32 } undef, i8* %exn61, 0 - %lpad.val63 = insertvalue { i8*, i32 } %lpad.val, i32 %sel62, 1 - resume { i8*, i32 } %lpad.val63 - -unreachable: ; preds = %try.cont33, %try.cont19, %try.cont, %entry - unreachable -} - -declare void @_CxxThrowException(i8*, %eh.ThrowInfo*) - -declare i32 @__CxxFrameHandler3(...) - -; Function Attrs: nounwind readnone -declare i32 @llvm.eh.typeid.for(i8*) #1 - -; Function Attrs: nounwind -declare void @llvm.eh.begincatch(i8* nocapture, i8* nocapture) #2 - -declare i32 @printf(i8*, ...) #3 - -; Function Attrs: nounwind -declare void @llvm.eh.endcatch() #2 - -attributes #0 = { uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "unsafe-fp-math"="false" "use-soft-float"="false" } -attributes #1 = { nounwind readnone } -attributes #2 = { nounwind } -attributes #3 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "unsafe-fp-math"="false" "use-soft-float"="false" } -attributes #4 = { noreturn } - -!llvm.module.flags = !{!0} -!llvm.ident = !{!1} - -!0 = !{i32 1, !"PIC Level", i32 2} -!1 = !{!"clang version 3.7.0 (trunk 235214) (llvm/trunk 235213)"} diff --git a/test/CodeGen/WinEH/seh-catch-all.ll b/test/CodeGen/WinEH/seh-catch-all.ll deleted file mode 100644 index 1255496f78f..00000000000 --- a/test/CodeGen/WinEH/seh-catch-all.ll +++ /dev/null @@ -1,59 +0,0 @@ -; RUN: opt -S -winehprepare -mtriple=x86_64-pc-windows-msvc < %s | FileCheck %s -; RUN: opt -S -winehprepare -mtriple=x86_64-pc-windows-coreclr < %s | FileCheck %s - -target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128" - -@str.__except = internal unnamed_addr constant [9 x i8] c"__except\00", align 1 - -; Function Attrs: uwtable - -declare i32 @puts(i8*) - -define void @may_crash() { -entry: - store volatile i32 42, i32* null, align 4 - ret void -} - -declare i32 @__C_specific_handler(...) - -; Function Attrs: nounwind readnone -declare i8* @llvm.frameaddress(i32) - -; Function Attrs: uwtable -define void @seh_catch_all() personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) { -entry: - %exn.slot = alloca i8* - %ehselector.slot = alloca i32 - invoke void @may_crash() - to label %invoke.cont unwind label %lpad - -invoke.cont: ; preds = %entry - br label %__try.cont - -lpad: ; preds = %entry - %0 = landingpad { i8*, i32 } - catch i8* null - %1 = extractvalue { i8*, i32 } %0, 0 - store i8* %1, i8** %exn.slot - %2 = extractvalue { i8*, i32 } %0, 1 - store i32 %2, i32* %ehselector.slot - br label %__except - -__except: ; preds = %lpad - %call = call i32 @puts(i8* getelementptr inbounds ([9 x i8], [9 x i8]* @str.__except, i32 0, i32 0)) - br label %__try.cont - -__try.cont: ; preds = %__except, %invoke.cont - ret void -} - -; CHECK-LABEL: define void @seh_catch_all() -; CHECK: landingpad -; CHECK-NEXT: catch i8* null -; CHECK-NEXT: call i8* (...) @llvm.eh.actions(i32 1, i8* null, i32 -1, i8* blockaddress(@seh_catch_all, %lpad.split)) -; CHECK-NEXT: indirectbr -; -; CHECK: lpad.split: -; CHECK-NOT: extractvalue -; CHECK: call i32 @puts diff --git a/test/CodeGen/WinEH/seh-exception-code.ll b/test/CodeGen/WinEH/seh-exception-code.ll deleted file mode 100644 index acb3d5c5e47..00000000000 --- a/test/CodeGen/WinEH/seh-exception-code.ll +++ /dev/null @@ -1,66 +0,0 @@ -; RUN: opt -winehprepare -S < %s | FileCheck %s - -; WinEHPrepare was crashing during phi demotion. - -target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128" -target triple = "x86_64-pc-windows-msvc18.0.0" - -declare i32 @__C_specific_handler(...) - -@str = linkonce_odr unnamed_addr constant [16 x i8] c"caught it! %lx\0A\00", align 1 - -; Function Attrs: nounwind uwtable -declare void @maycrash() - -; Function Attrs: nounwind -declare i32 @printf(i8* nocapture readonly, ...) - -; Function Attrs: nounwind uwtable -define void @doit() personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) { -entry: - invoke void @maycrash() - to label %invoke.cont unwind label %lpad - -invoke.cont: ; preds = %entry - invoke void @maycrash() - to label %__try.cont unwind label %lpad.1 - -lpad: ; preds = %entry - %0 = landingpad { i8*, i32 } - catch i8* null - %1 = extractvalue { i8*, i32 } %0, 0 - br label %__except - -lpad.1: ; preds = %invoke.cont, %lpad - %2 = landingpad { i8*, i32 } - catch i8* null - %3 = extractvalue { i8*, i32 } %2, 0 - br label %__except - -__except: ; preds = %lpad, %lpad.1 - %exn.slot.0 = phi i8* [ %3, %lpad.1 ], [ %1, %lpad ] - %4 = ptrtoint i8* %exn.slot.0 to i64 - %5 = trunc i64 %4 to i32 - %call = tail call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([16 x i8], [16 x i8]* @str, i64 0, i64 0), i32 %5) - br label %__try.cont - -__try.cont: ; preds = %invoke.cont, %__except - ret void -} - -; CHECK-LABEL: define void @doit() -; CHECK: landingpad -; CHECK: indirectbr i8* %{{[^,]*}}, [label %[[except_split1:.*]]] -; CHECK: [[except_split1]]: -; CHECK: call i32 @llvm.eh.exceptioncode.old() -; CHECK: br label %__except -; -; CHECK: landingpad -; CHECK: indirectbr i8* %{{[^,]*}}, [label %[[except_split2:.*]]] -; CHECK: [[except_split2]]: -; CHECK: call i32 @llvm.eh.exceptioncode.old() -; CHECK: br label %__except -; -; CHECK: __except: -; CHECK: phi -; CHECK: call i32 (i8*, ...) @printf diff --git a/test/CodeGen/WinEH/seh-exception-code2.ll b/test/CodeGen/WinEH/seh-exception-code2.ll deleted file mode 100644 index 6b64a7923f6..00000000000 --- a/test/CodeGen/WinEH/seh-exception-code2.ll +++ /dev/null @@ -1,91 +0,0 @@ -; RUN: opt -winehprepare -S < %s | FileCheck %s - -; WinEHPrepare was crashing during phi demotion. - -target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128" -target triple = "x86_64-pc-windows-msvc18.0.0" - -declare i32 @__C_specific_handler(...) - -@str = linkonce_odr unnamed_addr constant [16 x i8] c"caught it! %lx\0A\00", align 1 - -declare void @maycrash() -declare void @finally(i1 %abnormal) -declare i32 @printf(i8* nocapture readonly, ...) -declare i32 @llvm.eh.typeid.for(i8*) - -; Function Attrs: nounwind uwtable -define void @doit() personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) { -entry: - invoke void @maycrash() - to label %invoke.cont unwind label %lpad.1 - -invoke.cont: ; preds = %entry - invoke void @maycrash() - to label %__try.cont unwind label %lpad - -lpad: ; preds = %entry - %lp0 = landingpad { i8*, i32 } - cleanup - catch i8* bitcast (i32 (i8*, i8*)* @"\01?filt$0@0@doit@@" to i8*) - %ehptr.0 = extractvalue { i8*, i32 } %lp0, 0 - %ehsel.0 = extractvalue { i8*, i32 } %lp0, 1 - call void @finally(i1 true) - br label %ehdispatch - -lpad.1: ; preds = %invoke.cont, %lpad - %lp1 = landingpad { i8*, i32 } - catch i8* bitcast (i32 (i8*, i8*)* @"\01?filt$0@0@doit@@" to i8*) - %ehptr.1 = extractvalue { i8*, i32 } %lp1, 0 - %ehsel.1 = extractvalue { i8*, i32 } %lp1, 1 - br label %ehdispatch - -ehdispatch: - %ehptr.2 = phi i8* [ %ehptr.0, %lpad ], [ %ehptr.1, %lpad.1 ] - %ehsel.2 = phi i32 [ %ehsel.0, %lpad ], [ %ehsel.1, %lpad.1 ] - %mysel = call i32 @llvm.eh.typeid.for(i8* bitcast (i32 (i8*, i8*)* @"\01?filt$0@0@doit@@" to i8*)) - %matches = icmp eq i32 %ehsel.2, %mysel - br i1 %matches, label %__except, label %eh.resume - -__except: ; preds = %lpad, %lpad.1 - %t4 = ptrtoint i8* %ehptr.2 to i64 - %t5 = trunc i64 %t4 to i32 - %call = tail call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([16 x i8], [16 x i8]* @str, i64 0, i64 0), i32 %t5) - br label %__try.cont - -__try.cont: ; preds = %invoke.cont, %__except - call void @finally(i1 false) - ret void - -eh.resume: - %ehvals0 = insertvalue { i8*, i32 } undef, i8* %ehptr.2, 0 - %ehvals = insertvalue { i8*, i32 } %ehvals0, i32 %ehsel.2, 1 - resume { i8*, i32 } %ehvals -} - -define internal i32 @"\01?filt$0@0@doit@@"(i8* %exception_pointers, i8* %frame_pointer) #1 { -entry: - %0 = bitcast i8* %exception_pointers to { i32*, i8* }* - %1 = getelementptr inbounds { i32*, i8* }, { i32*, i8* }* %0, i32 0, i32 0 - %2 = load i32*, i32** %1 - %3 = load i32, i32* %2 - %cmp = icmp eq i32 %3, -1073741819 - %4 = zext i1 %cmp to i32 - ret i32 %4 -} - -; CHECK-LABEL: define void @doit() -; CHECK: %lp0 = landingpad { i8*, i32 } -; CHECK-NEXT: cleanup -; CHECK-NEXT: catch i8* -; CHECK-NEXT: call i8* (...) @llvm.eh.actions({{.*}}) -; CHECK-NEXT: indirectbr i8* %{{[^,]*}}, [label %__except] -; -; CHECK: %lp1 = landingpad { i8*, i32 } -; CHECK-NEXT: catch i8* -; CHECK-NEXT: call i8* (...) @llvm.eh.actions({{.*}}) -; CHECK-NEXT: indirectbr i8* %{{[^,]*}}, [label %__except] -; -; CHECK: __except: -; CHECK: call i32 @llvm.eh.exceptioncode.old() -; CHECK: call i32 (i8*, ...) @printf diff --git a/test/CodeGen/WinEH/seh-inlined-finally.ll b/test/CodeGen/WinEH/seh-inlined-finally.ll deleted file mode 100644 index 07fe6000867..00000000000 --- a/test/CodeGen/WinEH/seh-inlined-finally.ll +++ /dev/null @@ -1,83 +0,0 @@ -; RUN: opt -S -winehprepare -mtriple=x86_64-pc-windows-msvc < %s | FileCheck %s -; RUN: opt -S -winehprepare -mtriple=x86_64-pc-windows-coreclr < %s | FileCheck %s - -; Check that things work when the mid-level optimizer inlines the finally -; block. - -target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128" - -%struct._RTL_CRITICAL_SECTION = type { %struct._RTL_CRITICAL_SECTION_DEBUG*, i32, i32, i8*, i8*, i64 } -%struct._RTL_CRITICAL_SECTION_DEBUG = type { i16, i16, %struct._RTL_CRITICAL_SECTION*, %struct._LIST_ENTRY, i32, i32, i32, i16, i16 } -%struct._LIST_ENTRY = type { %struct._LIST_ENTRY*, %struct._LIST_ENTRY* } - -declare i32 @puts(i8*) -declare void @may_crash() -declare i32 @__C_specific_handler(...) -declare i8* @llvm.localrecover(i8*, i8*, i32) #1 -declare i8* @llvm.localaddress() -declare void @llvm.localescape(...) -declare dllimport void @EnterCriticalSection(%struct._RTL_CRITICAL_SECTION*) -declare dllimport void @LeaveCriticalSection(%struct._RTL_CRITICAL_SECTION*) - -define void @use_finally() personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) { -entry: - invoke void @may_crash() - to label %invoke.cont unwind label %lpad - -invoke.cont: ; preds = %entry - %call.i = tail call i32 @puts(i8* null) - ret void - -lpad: ; preds = %entry - %0 = landingpad { i8*, i32 } - cleanup - %call.i2 = tail call i32 @puts(i8* null) - resume { i8*, i32 } %0 -} - -; CHECK-LABEL: define void @use_finally() -; CHECK: invoke void @may_crash() -; -; CHECK: landingpad -; CHECK-NEXT: cleanup -; CHECK-NEXT: call i8* (...) @llvm.eh.actions(i32 0, void (i8*, i8*)* @use_finally.cleanup) -; CHECK-NEXT: indirectbr i8* %recover, [] - -; Function Attrs: nounwind uwtable -define i32 @call_may_crash_locked() personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) { -entry: - %p = alloca %struct._RTL_CRITICAL_SECTION, align 8 - call void (...) @llvm.localescape(%struct._RTL_CRITICAL_SECTION* %p) - call void @EnterCriticalSection(%struct._RTL_CRITICAL_SECTION* %p) - invoke void @may_crash() - to label %invoke.cont unwind label %lpad - -invoke.cont: ; preds = %entry - %tmp2 = call i8* @llvm.localaddress() - %tmp3 = call i8* @llvm.localrecover(i8* bitcast (i32 ()* @call_may_crash_locked to i8*), i8* %tmp2, i32 0) #2 - %tmp6 = bitcast i8* %tmp3 to %struct._RTL_CRITICAL_SECTION* - call void @LeaveCriticalSection(%struct._RTL_CRITICAL_SECTION* %tmp6) - ret i32 42 - -lpad: ; preds = %entry - %tmp7 = landingpad { i8*, i32 } - cleanup - %tmp8 = call i8* @llvm.localaddress() - %tmp9 = call i8* @llvm.localrecover(i8* bitcast (i32 ()* @call_may_crash_locked to i8*), i8* %tmp8, i32 0) - %tmp12 = bitcast i8* %tmp9 to %struct._RTL_CRITICAL_SECTION* - call void @LeaveCriticalSection(%struct._RTL_CRITICAL_SECTION* %tmp12) - resume { i8*, i32 } %tmp7 -} - -; CHECK-LABEL: define i32 @call_may_crash_locked() -; CHECK: invoke void @may_crash() -; -; CHECK: landingpad -; CHECK-NEXT: cleanup -; CHECK-NEXT: call i8* (...) @llvm.eh.actions(i32 0, void (i8*, i8*)* @call_may_crash_locked.cleanup) -; CHECK-NEXT: indirectbr i8* %recover, [] - -; CHECK-LABEL: define internal void @call_may_crash_locked.cleanup(i8*, i8*) -; CHECK: %tmp9 = call i8* @llvm.localrecover(i8* bitcast (i32 ()* @call_may_crash_locked to i8*), i8* %1, i32 0) -; CHECK: %tmp12 = bitcast i8* %tmp9 to %struct._RTL_CRITICAL_SECTION* -; CHECK: call void @LeaveCriticalSection(%struct._RTL_CRITICAL_SECTION* %tmp12) diff --git a/test/CodeGen/WinEH/seh-outlined-finally-win32.ll b/test/CodeGen/WinEH/seh-outlined-finally-win32.ll deleted file mode 100644 index 3649433c4b6..00000000000 --- a/test/CodeGen/WinEH/seh-outlined-finally-win32.ll +++ /dev/null @@ -1,172 +0,0 @@ -; RUN: opt -S -winehprepare < %s | FileCheck %s - -; Test case based on this code: -; -; extern "C" int _abnormal_termination(); -; #pragma intrinsic(_abnormal_termination) -; extern "C" int printf(const char *, ...); -; extern "C" void may_crash() { -; *(volatile int *)0 = 42; -; } -; int main() { -; int myres = 0; -; __try { -; __try { -; may_crash(); -; } __finally { -; printf("inner finally %d\n", _abnormal_termination()); -; may_crash(); -; } -; } __finally { -; printf("outer finally %d\n", _abnormal_termination()); -; } -; } -; -; Note that if the inner finally crashes, the outer finally still runs. There -; is nothing like a std::terminate call in this situation. - -target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32" -target triple = "i686-pc-windows-msvc" - -$"\01??_C@_0BC@LHHILCPN@outer?5finally?5?$CFd?6?$AA@" = comdat any - -$"\01??_C@_0BC@JELAHKN@inner?5finally?5?$CFd?6?$AA@" = comdat any - -@"\01??_C@_0BC@LHHILCPN@outer?5finally?5?$CFd?6?$AA@" = linkonce_odr unnamed_addr constant [18 x i8] c"outer finally %d\0A\00", comdat, align 1 -@"\01??_C@_0BC@JELAHKN@inner?5finally?5?$CFd?6?$AA@" = linkonce_odr unnamed_addr constant [18 x i8] c"inner finally %d\0A\00", comdat, align 1 - -; Function Attrs: nounwind -define void @may_crash() #0 { -entry: - store volatile i32 42, i32* null, align 4 - ret void -} - -; Function Attrs: nounwind -define i32 @main() #0 personality i8* bitcast (i32 (...)* @_except_handler3 to i8*) { -entry: - %myres = alloca i32, align 4 - %exn.slot = alloca i8* - %ehselector.slot = alloca i32 - store i32 0, i32* %myres, align 4 - invoke void @may_crash() #4 - to label %invoke.cont unwind label %lpad - -invoke.cont: ; preds = %entry - %0 = call i8* @llvm.frameaddress(i32 0) - invoke void @"\01?fin$1@0@main@@"(i8 zeroext 0, i8* %0) #4 - to label %invoke.cont.2 unwind label %lpad.1 - -invoke.cont.2: ; preds = %invoke.cont - %1 = call i8* @llvm.frameaddress(i32 0) - call void @"\01?fin$0@0@main@@"(i8 zeroext 0, i8* %1) - ret i32 0 - -lpad: ; preds = %entry - %2 = landingpad { i8*, i32 } - cleanup - %3 = extractvalue { i8*, i32 } %2, 0 - store i8* %3, i8** %exn.slot - %4 = extractvalue { i8*, i32 } %2, 1 - store i32 %4, i32* %ehselector.slot - %5 = call i8* @llvm.frameaddress(i32 0) - invoke void @"\01?fin$1@0@main@@"(i8 zeroext 1, i8* %5) #4 - to label %invoke.cont.3 unwind label %lpad.1 - -lpad.1: ; preds = %lpad, %invoke.cont - %6 = landingpad { i8*, i32 } - cleanup - %7 = extractvalue { i8*, i32 } %6, 0 - store i8* %7, i8** %exn.slot - %8 = extractvalue { i8*, i32 } %6, 1 - store i32 %8, i32* %ehselector.slot - br label %ehcleanup - -invoke.cont.3: ; preds = %lpad - br label %ehcleanup - -ehcleanup: ; preds = %invoke.cont.3, %lpad.1 - %9 = call i8* @llvm.frameaddress(i32 0) - call void @"\01?fin$0@0@main@@"(i8 zeroext 1, i8* %9) - br label %eh.resume - -eh.resume: ; preds = %ehcleanup - %exn = load i8*, i8** %exn.slot - %sel = load i32, i32* %ehselector.slot - %lpad.val = insertvalue { i8*, i32 } undef, i8* %exn, 0 - %lpad.val.4 = insertvalue { i8*, i32 } %lpad.val, i32 %sel, 1 - resume { i8*, i32 } %lpad.val.4 -} - -; CHECK-LABEL: define i32 @main() -; CHECK: invoke void @may_crash() -; -; CHECK: landingpad { i8*, i32 } -; CHECK-NEXT: cleanup -; CHECK-NEXT: call i8* (...) @llvm.eh.actions(i32 0, void ()* @main.cleanup) -; CHECK-NEXT: indirectbr -; -; CHECK: landingpad { i8*, i32 } -; CHECK-NEXT: cleanup -; CHECK-NEXT: call i8* (...) @llvm.eh.actions(i32 0, void ()* @main.cleanup.1) -; CHECK-NEXT: indirectbr - -; CHECK-LABEL: define internal void @main.cleanup() -; CHECK: call i8* @llvm.frameaddress(i32 1) -; CHECK: call i8* @llvm.x86.seh.recoverfp(i8* bitcast (i32 ()* @main to i8*), i8* %{{.*}}) -; CHECK: call void @"\01?fin$1@0@main@@"(i8 zeroext 1, i8* %{{.*}}) -; CHECK: call void @"\01?fin$0@0@main@@"(i8 zeroext 1, i8* %{{.*}}) - -; CHECK-LABEL: define internal void @main.cleanup.1() -; CHECK: call i8* @llvm.frameaddress(i32 1) -; CHECK: call i8* @llvm.x86.seh.recoverfp(i8* bitcast (i32 ()* @main to i8*), i8* %{{.*}}) -; CHECK: call void @"\01?fin$0@0@main@@"(i8 zeroext 1, i8* %{{.*}}) - -; Function Attrs: noinline nounwind -define internal void @"\01?fin$0@0@main@@"(i8 zeroext %abnormal_termination, i8* %frame_pointer) #1 { -entry: - %frame_pointer.addr = alloca i8*, align 4 - %abnormal_termination.addr = alloca i8, align 1 - %0 = call i8* @llvm.frameaddress(i32 1) - %1 = call i8* @llvm.x86.seh.recoverfp(i8* bitcast (i32 ()* @main to i8*), i8* %0) - store i8* %frame_pointer, i8** %frame_pointer.addr, align 4 - store i8 %abnormal_termination, i8* %abnormal_termination.addr, align 1 - %2 = zext i8 %abnormal_termination to i32 - %call = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([18 x i8], [18 x i8]* @"\01??_C@_0BC@LHHILCPN@outer?5finally?5?$CFd?6?$AA@", i32 0, i32 0), i32 %2) - ret void -} - -; Function Attrs: nounwind readnone -declare i8* @llvm.frameaddress(i32) #2 - -; Function Attrs: nounwind readnone -declare i8* @llvm.x86.seh.recoverfp(i8*, i8*) #2 - -declare i32 @printf(i8*, ...) #3 - -; Function Attrs: noinline nounwind -define internal void @"\01?fin$1@0@main@@"(i8 zeroext %abnormal_termination, i8* %frame_pointer) #1 { -entry: - %frame_pointer.addr = alloca i8*, align 4 - %abnormal_termination.addr = alloca i8, align 1 - %0 = call i8* @llvm.frameaddress(i32 1) - %1 = call i8* @llvm.x86.seh.recoverfp(i8* bitcast (i32 ()* @main to i8*), i8* %0) - store i8* %frame_pointer, i8** %frame_pointer.addr, align 4 - store i8 %abnormal_termination, i8* %abnormal_termination.addr, align 1 - %2 = zext i8 %abnormal_termination to i32 - %call = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([18 x i8], [18 x i8]* @"\01??_C@_0BC@JELAHKN@inner?5finally?5?$CFd?6?$AA@", i32 0, i32 0), i32 %2) - call void @may_crash() - ret void -} - -declare i32 @_except_handler3(...) - -attributes #0 = { nounwind "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } -attributes #1 = { noinline nounwind "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } -attributes #2 = { nounwind readnone } -attributes #3 = { "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } -attributes #4 = { noinline } - -!llvm.ident = !{!0} - -!0 = !{!"clang version 3.7.0 "} diff --git a/test/CodeGen/WinEH/seh-outlined-finally.ll b/test/CodeGen/WinEH/seh-outlined-finally.ll deleted file mode 100644 index b46b4e97672..00000000000 --- a/test/CodeGen/WinEH/seh-outlined-finally.ll +++ /dev/null @@ -1,155 +0,0 @@ -; RUN: opt -S -winehprepare -mtriple=x86_64-windows-msvc < %s | FileCheck %s -; RUN: opt -S -winehprepare -mtriple=x86_64-windows-coreclr < %s | FileCheck %s - -; Test case based on this code: -; -; extern "C" int _abnormal_termination(); -; #pragma intrinsic(_abnormal_termination) -; extern "C" int printf(const char *, ...); -; extern "C" void may_crash() { -; *(volatile int *)0 = 42; -; } -; int main() { -; int myres = 0; -; __try { -; __try { -; may_crash(); -; } __finally { -; printf("inner finally %d\n", _abnormal_termination()); -; may_crash(); -; } -; } __finally { -; printf("outer finally %d\n", _abnormal_termination()); -; } -; } -; -; Note that if the inner finally crashes, the outer finally still runs. There -; is nothing like a std::terminate call in this situation. - -target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128" - -@str_outer_finally = linkonce_odr unnamed_addr constant [18 x i8] c"outer finally %d\0A\00", align 1 -@str_inner_finally = linkonce_odr unnamed_addr constant [18 x i8] c"inner finally %d\0A\00", align 1 - -; Function Attrs: nounwind uwtable -define void @may_crash() #0 { -entry: - store volatile i32 42, i32* null, align 4 - ret void -} - -; Function Attrs: uwtable -define i32 @main() #1 personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) { -entry: - %myres = alloca i32, align 4 - %exn.slot = alloca i8* - %ehselector.slot = alloca i32 - store i32 0, i32* %myres, align 4 - invoke void @may_crash() #4 - to label %invoke.cont unwind label %lpad - -invoke.cont: ; preds = %entry - %0 = call i8* @llvm.localaddress() - invoke void @"\01?fin$1@0@main@@"(i1 zeroext false, i8* %0) #4 - to label %invoke.cont2 unwind label %lpad1 - -invoke.cont2: ; preds = %invoke.cont - %1 = call i8* @llvm.localaddress() - call void @"\01?fin$0@0@main@@"(i1 zeroext false, i8* %1) - ret i32 0 - -lpad: ; preds = %entry - %2 = landingpad { i8*, i32 } - cleanup - %3 = extractvalue { i8*, i32 } %2, 0 - store i8* %3, i8** %exn.slot - %4 = extractvalue { i8*, i32 } %2, 1 - store i32 %4, i32* %ehselector.slot - %5 = call i8* @llvm.localaddress() - invoke void @"\01?fin$1@0@main@@"(i1 zeroext true, i8* %5) #4 - to label %invoke.cont3 unwind label %lpad1 - -lpad1: ; preds = %lpad, %invoke.cont - %6 = landingpad { i8*, i32 } - cleanup - %7 = extractvalue { i8*, i32 } %6, 0 - store i8* %7, i8** %exn.slot - %8 = extractvalue { i8*, i32 } %6, 1 - store i32 %8, i32* %ehselector.slot - br label %ehcleanup - -invoke.cont3: ; preds = %lpad - br label %ehcleanup - -ehcleanup: ; preds = %invoke.cont3, %lpad1 - %9 = call i8* @llvm.localaddress() - call void @"\01?fin$0@0@main@@"(i1 zeroext true, i8* %9) - br label %eh.resume - -eh.resume: ; preds = %ehcleanup - %exn = load i8*, i8** %exn.slot - %sel = load i32, i32* %ehselector.slot - %lpad.val = insertvalue { i8*, i32 } undef, i8* %exn, 0 - %lpad.val4 = insertvalue { i8*, i32 } %lpad.val, i32 %sel, 1 - resume { i8*, i32 } %lpad.val4 -} - -; CHECK-NOT: define internal void @ - -; CHECK-LABEL: define i32 @main() -; CHECK: invoke void @may_crash() -; -; CHECK: landingpad { i8*, i32 } -; CHECK-NEXT: cleanup -; CHECK-NEXT: call i8* (...) @llvm.eh.actions(i32 0, void (i1, i8*)* @"\01?fin$1@0@main@@", i32 0, void (i1, i8*)* @"\01?fin$0@0@main@@") -; CHECK-NEXT: indirectbr -; -; CHECK: landingpad { i8*, i32 } -; CHECK-NEXT: cleanup -; CHECK-NEXT: call i8* (...) @llvm.eh.actions(i32 0, void (i1, i8*)* @"\01?fin$0@0@main@@") -; CHECK-NEXT: indirectbr - -; There should not be any *new* cleanup helpers, just the existing ones. -; CHECK-NOT: define internal void @ -; CHECK: define internal void @"\01?fin$0@0@main@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer) -; CHECK-NOT: define internal void @ -; CHECK: define internal void @"\01?fin$1@0@main@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer) -; CHECK-NOT: define internal void @ - -define internal void @"\01?fin$0@0@main@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer) #2 { -entry: - %frame_pointer.addr = alloca i8*, align 8 - %abnormal_termination.addr = alloca i8, align 1 - store i8* %frame_pointer, i8** %frame_pointer.addr, align 8 - %frombool = zext i1 %abnormal_termination to i8 - store i8 %frombool, i8* %abnormal_termination.addr, align 1 - %0 = zext i1 %abnormal_termination to i32 - %call = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([18 x i8], [18 x i8]* @str_outer_finally, i32 0, i32 0), i32 %0) - ret void -} - -declare i32 @printf(i8*, ...) #2 - -define internal void @"\01?fin$1@0@main@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer) #2 { -entry: - %frame_pointer.addr = alloca i8*, align 8 - %abnormal_termination.addr = alloca i8, align 1 - store i8* %frame_pointer, i8** %frame_pointer.addr, align 8 - %frombool = zext i1 %abnormal_termination to i8 - store i8 %frombool, i8* %abnormal_termination.addr, align 1 - %0 = zext i1 %abnormal_termination to i32 - %call = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([18 x i8], [18 x i8]* @str_inner_finally, i32 0, i32 0), i32 %0) - call void @may_crash() - ret void -} - -declare i32 @__C_specific_handler(...) - -; Function Attrs: nounwind readnone -declare i8* @llvm.localaddress() #3 - -attributes #0 = { nounwind uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "unsafe-fp-math"="false" "use-soft-float"="false" } -attributes #1 = { uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "unsafe-fp-math"="false" "use-soft-float"="false" } -attributes #2 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "unsafe-fp-math"="false" "use-soft-float"="false" } -attributes #3 = { nounwind readnone } -attributes #4 = { noinline } diff --git a/test/CodeGen/WinEH/seh-prepared-basic.ll b/test/CodeGen/WinEH/seh-prepared-basic.ll deleted file mode 100644 index 51ffe7bb3bd..00000000000 --- a/test/CodeGen/WinEH/seh-prepared-basic.ll +++ /dev/null @@ -1,86 +0,0 @@ -; RUN: llc -mtriple=x86_64-pc-windows-msvc < %s | FileCheck %s -; RUN: llc -mtriple=x86_64-pc-windows-coreclr < %s | FileCheck %s - -; Test case based on this code: -; extern "C" unsigned long _exception_code(); -; extern "C" int filt(unsigned long); -; extern "C" void g(); -; extern "C" void do_except() { -; __try { -; g(); -; } __except(filt(_exception_code())) { -; } -; } - -target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128" - -; Function Attrs: uwtable -define void @do_except() #0 personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) { -entry: - call void (...) @llvm.localescape() - invoke void @g() #5 - to label %__try.cont unwind label %lpad1 - -lpad1: ; preds = %entry - %ehvals = landingpad { i8*, i32 } - catch i8* bitcast (i32 (i8*, i8*)* @"\01?filt$0@0@do_except@@" to i8*) - %recover = call i8* (...) @llvm.eh.actions(i32 1, i8* bitcast (i32 (i8*, i8*)* @"\01?filt$0@0@do_except@@" to i8*), i32 -1, i8* blockaddress(@do_except, %__try.cont)) - indirectbr i8* %recover, [label %__try.cont] - -__try.cont: ; preds = %lpad1, %entry - ret void -} - -; CHECK-LABEL: do_except: -; CHECK: .seh_handler __C_specific_handler -; CHECK-NOT: jmpq * -; CHECK: .seh_handlerdata -; CHECK-NEXT: .text -; CHECK: .seh_endproc -; CHECK: .section .xdata,"dr" -; CHECK-NEXT: .long 1 -; CHECK-NEXT: .long .Ltmp{{.*}} -; CHECK-NEXT: .long .Ltmp{{.*}} -; CHECK-NEXT: .long "?filt$0@0@do_except@@"@IMGREL -; CHECK-NEXT: .long .Ltmp{{.*}}@IMGREL - -; Function Attrs: noinline nounwind -define internal i32 @"\01?filt$0@0@do_except@@"(i8* nocapture readonly %exception_pointers, i8* nocapture readnone %frame_pointer) #1 { -entry: - %0 = bitcast i8* %exception_pointers to i32** - %1 = load i32*, i32** %0, align 8 - %2 = load i32, i32* %1, align 4 - %call = tail call i32 @filt(i32 %2) #4 - ret i32 %call -} - -declare i32 @filt(i32) #2 - -declare void @g() #2 - -declare i32 @__C_specific_handler(...) - -; Function Attrs: nounwind readnone -declare i32 @llvm.eh.typeid.for(i8*) #3 - -; Function Attrs: nounwind -declare i8* @llvm.eh.actions(...) #4 - -; Function Attrs: nounwind -declare void @llvm.localescape(...) #4 - -; Function Attrs: nounwind readnone -declare i8* @llvm.localrecover(i8*, i8*, i32) #3 - -attributes #0 = { uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "unsafe-fp-math"="false" "use-soft-float"="false" "wineh-parent"="do_except" } -attributes #1 = { noinline nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "unsafe-fp-math"="false" "use-soft-float"="false" } -attributes #2 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "unsafe-fp-math"="false" "use-soft-float"="false" } -attributes #3 = { nounwind readnone } -attributes #4 = { nounwind } -attributes #5 = { noinline } - -!llvm.module.flags = !{!0} -!llvm.ident = !{!1} - -!0 = !{i32 1, !"PIC Level", i32 2} -!1 = !{!"clang version 3.7.0 "} diff --git a/test/CodeGen/WinEH/seh-resume-phi.ll b/test/CodeGen/WinEH/seh-resume-phi.ll deleted file mode 100644 index f629a4dd50c..00000000000 --- a/test/CodeGen/WinEH/seh-resume-phi.ll +++ /dev/null @@ -1,66 +0,0 @@ -; RUN: opt -S -winehprepare -mtriple=x86_64-pc-windows-msvc < %s | FileCheck %s -; RUN: opt -S -winehprepare -mtriple=x86_64-pc-windows-coreclr < %s | FileCheck %s - -target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128" - -declare void @might_crash(i8* %ehptr) -declare i32 @filt() -declare void @cleanup() -declare i32 @__C_specific_handler(...) -declare i32 @llvm.eh.typeid.for(i8*) - -define void @resume_phi() personality i32 (...)* @__C_specific_handler { -entry: - invoke void @might_crash(i8* null) - to label %return unwind label %lpad1 - -lpad1: - %ehvals1 = landingpad { i8*, i32 } - catch i32 ()* @filt - %ehptr1 = extractvalue { i8*, i32 } %ehvals1, 0 - %ehsel1 = extractvalue { i8*, i32 } %ehvals1, 1 - %filt_sel = tail call i32 @llvm.eh.typeid.for(i8* bitcast (i32 ()* @filt to i8*)) - %matches = icmp eq i32 %ehsel1, %filt_sel - br i1 %matches, label %__except, label %eh.resume - -__except: - invoke void @might_crash(i8* %ehptr1) - to label %return unwind label %lpad2 - -lpad2: - %ehvals2 = landingpad { i8*, i32 } - cleanup - %ehptr2 = extractvalue { i8*, i32 } %ehvals2, 0 - %ehsel2 = extractvalue { i8*, i32 } %ehvals2, 1 - call void @cleanup() - br label %eh.resume - -return: - ret void - -eh.resume: - %ehptr.phi = phi i8* [ %ehptr1, %lpad1 ], [ %ehptr2, %lpad2 ] - %ehsel.phi = phi i32 [ %ehsel1, %lpad1 ], [ %ehsel2, %lpad2 ] - %ehval.phi1 = insertvalue { i8*, i32 } undef, i8* %ehptr.phi, 0 - %ehval.phi2 = insertvalue { i8*, i32 } %ehval.phi1, i32 %ehsel.phi, 1 - resume { i8*, i32 } %ehval.phi2 -} - -; CHECK-LABEL: define void @resume_phi() -; CHECK: invoke void @might_crash(i8* null) -; CHECK: landingpad { i8*, i32 } -; CHECK-NEXT: catch i32 ()* @filt -; CHECK-NEXT: call i8* (...) @llvm.eh.actions( -; CHECK-SAME: i32 1, i8* bitcast (i32 ()* @filt to i8*), i32 -1, i8* blockaddress(@resume_phi, %__except)) -; CHECK-NEXT: indirectbr {{.*}} [label %__except] -; -; CHECK: __except: -; CHECK: call i32 @llvm.eh.exceptioncode.old() -; CHECK: invoke void @might_crash(i8* %{{.*}}) -; CHECK: landingpad { i8*, i32 } -; CHECK-NEXT: cleanup -; CHECK-NEXT: call i8* (...) @llvm.eh.actions(i32 0, void (i8*, i8*)* @resume_phi.cleanup) -; CHECK-NEXT: indirectbr {{.*}} [] - -; CHECK-LABEL: define internal void @resume_phi.cleanup(i8*, i8*) -; CHECK: call void @cleanup() diff --git a/test/CodeGen/WinEH/seh-simple.ll b/test/CodeGen/WinEH/seh-simple.ll deleted file mode 100644 index 9974548ba33..00000000000 --- a/test/CodeGen/WinEH/seh-simple.ll +++ /dev/null @@ -1,235 +0,0 @@ -; RUN: opt -S -winehprepare -mtriple=x86_64-windows-msvc < %s \ -; RUN: | FileCheck %s --check-prefix=CHECK --check-prefix=X64 -; RUN: opt -S -winehprepare -mtriple=x86_64-windows-coreclr < %s \ -; RUN: | FileCheck %s --check-prefix=CHECK --check-prefix=X64 - -; This test should also pass in 32-bit using _except_handler3. -; RUN: sed -e 's/__C_specific_handler/_except_handler3/' %s \ -; RUN: | opt -S -winehprepare -mtriple=i686-windows-msvc \ -; RUN: | FileCheck %s --check-prefix=CHECK --check-prefix=X86 - -declare void @cleanup() -declare i32 @filt() -declare void @might_crash() -declare i32 @__C_specific_handler(...) -declare i32 @llvm.eh.typeid.for(i8*) - -define i32 @simple_except_store() personality i32 (...)* @__C_specific_handler { -entry: - %retval = alloca i32 - store i32 0, i32* %retval - invoke void @might_crash() - to label %return unwind label %lpad - -lpad: - %ehvals = landingpad { i8*, i32 } - catch i32 ()* @filt - %sel = extractvalue { i8*, i32 } %ehvals, 1 - %filt_sel = tail call i32 @llvm.eh.typeid.for(i8* bitcast (i32 ()* @filt to i8*)) - %matches = icmp eq i32 %sel, %filt_sel - br i1 %matches, label %__except, label %eh.resume - -__except: - store i32 1, i32* %retval - br label %return - -return: - %r = load i32, i32* %retval - ret i32 %r - -eh.resume: - resume { i8*, i32 } %ehvals -} - -; CHECK-LABEL: define i32 @simple_except_store() -; CHECK: landingpad { i8*, i32 } -; CHECK-NEXT: catch i32 ()* @filt -; CHECK-NEXT: call i8* (...) @llvm.eh.actions(i32 1, i8* bitcast (i32 ()* @filt to i8*), i32 -1, i8* blockaddress(@simple_except_store, %__except)) -; CHECK-NEXT: indirectbr {{.*}} [label %__except] - -define i32 @catch_all() personality i32 (...)* @__C_specific_handler { -entry: - %retval = alloca i32 - store i32 0, i32* %retval - invoke void @might_crash() - to label %return unwind label %lpad - -lpad: - %ehvals = landingpad { i8*, i32 } - catch i8* null - store i32 1, i32* %retval - br label %return - -return: - %r = load i32, i32* %retval - ret i32 %r -} - -; CHECK-LABEL: define i32 @catch_all() -; CHECK: landingpad { i8*, i32 } -; CHECK-NEXT: catch i8* null -; CHECK-NEXT: call i8* (...) @llvm.eh.actions(i32 1, i8* null, i32 -1, i8* blockaddress(@catch_all, %lpad.split)) -; CHECK-NEXT: indirectbr {{.*}} [label %lpad.split] -; -; CHECK: lpad.split: -; CHECK: store i32 1, i32* %retval - - -define i32 @except_phi() personality i32 (...)* @__C_specific_handler { -entry: - invoke void @might_crash() - to label %return unwind label %lpad - -lpad: - %ehvals = landingpad { i8*, i32 } - catch i32 ()* @filt - %sel = extractvalue { i8*, i32 } %ehvals, 1 - %filt_sel = tail call i32 @llvm.eh.typeid.for(i8* bitcast (i32 ()* @filt to i8*)) - %matches = icmp eq i32 %sel, %filt_sel - br i1 %matches, label %return, label %eh.resume - -return: - %r = phi i32 [0, %entry], [1, %lpad] - ret i32 %r - -eh.resume: - resume { i8*, i32 } %ehvals -} - -; CHECK-LABEL: define i32 @except_phi() -; CHECK: landingpad { i8*, i32 } -; CHECK-NEXT: catch i32 ()* @filt -; CHECK-NEXT: call i8* (...) @llvm.eh.actions(i32 1, i8* bitcast (i32 ()* @filt to i8*), i32 -1, i8* blockaddress(@except_phi, %lpad.return_crit_edge)) -; CHECK-NEXT: indirectbr {{.*}} [label %lpad.return_crit_edge] -; -; CHECK: lpad.return_crit_edge: -; CHECK: br label %return -; -; CHECK: return: -; CHECK-NEXT: %r = phi i32 [ 0, %entry ], [ 1, %lpad.return_crit_edge ] -; CHECK-NEXT: ret i32 %r - -define i32 @except_join() personality i32 (...)* @__C_specific_handler { -entry: - invoke void @might_crash() - to label %return unwind label %lpad - -lpad: - %ehvals = landingpad { i8*, i32 } - catch i32 ()* @filt - %sel = extractvalue { i8*, i32 } %ehvals, 1 - %filt_sel = tail call i32 @llvm.eh.typeid.for(i8* bitcast (i32 ()* @filt to i8*)) - %matches = icmp eq i32 %sel, %filt_sel - br i1 %matches, label %return, label %eh.resume - -return: - ret i32 0 - -eh.resume: - resume { i8*, i32 } %ehvals -} - -; CHECK-LABEL: define i32 @except_join() -; CHECK: landingpad { i8*, i32 } -; CHECK-NEXT: catch i32 ()* @filt -; CHECK-NEXT: call i8* (...) @llvm.eh.actions(i32 1, i8* bitcast (i32 ()* @filt to i8*), i32 -1, i8* blockaddress(@except_join, %lpad.return_crit_edge)) -; CHECK-NEXT: indirectbr {{.*}} [label %lpad.return_crit_edge] -; -; CHECK: lpad.return_crit_edge: -; CHECK: br label %return -; -; CHECK: return: -; CHECK-NEXT: ret i32 0 - -define i32 @lpad_phi() personality i32 (...)* @__C_specific_handler { -entry: - invoke void @might_crash() - to label %cont unwind label %lpad - -cont: - invoke void @might_crash() - to label %return unwind label %lpad - -lpad: - %ncalls.1 = phi i32 [ 0, %entry ], [ 1, %cont ] - %ehvals = landingpad { i8*, i32 } - catch i32 ()* @filt - %sel = extractvalue { i8*, i32 } %ehvals, 1 - %filt_sel = tail call i32 @llvm.eh.typeid.for(i8* bitcast (i32 ()* @filt to i8*)) - %matches = icmp eq i32 %sel, %filt_sel - br i1 %matches, label %return, label %eh.resume - -return: - %r = phi i32 [2, %cont], [%ncalls.1, %lpad] - ret i32 %r - -eh.resume: - resume { i8*, i32 } %ehvals -} - -; CHECK-LABEL: define i32 @lpad_phi() -; CHECK: alloca i32 -; CHECK: store i32 0, i32* -; CHECK: invoke void @might_crash() -; CHECK: store i32 1, i32* -; CHECK: invoke void @might_crash() -; CHECK: landingpad { i8*, i32 } -; CHECK-NEXT: cleanup -; CHECK-NEXT: catch i32 ()* @filt -; CHECK-NEXT: call i8* (...) @llvm.eh.actions(i32 0, void ({{.*}})* @lpad_phi.cleanup, i32 1, i8* bitcast (i32 ()* @filt to i8*), i32 -1, i8* blockaddress(@lpad_phi, %lpad.return_crit_edge)) -; CHECK-NEXT: indirectbr {{.*}} [label %lpad.return_crit_edge] -; -; CHECK: lpad.return_crit_edge: -; CHECK: load i32, i32* -; CHECK: br label %return -; -; CHECK: return: -; CHECK-NEXT: %r = phi i32 [ 2, %cont ], [ %{{.*}}, %lpad.return_crit_edge ] -; CHECK-NEXT: ret i32 %r - -define i32 @cleanup_and_except() personality i32 (...)* @__C_specific_handler { -entry: - invoke void @might_crash() - to label %return unwind label %lpad - -lpad: - %ehvals = landingpad { i8*, i32 } - cleanup - catch i32 ()* @filt - call void @cleanup() - %sel = extractvalue { i8*, i32 } %ehvals, 1 - %filt_sel = tail call i32 @llvm.eh.typeid.for(i8* bitcast (i32 ()* @filt to i8*)) - %matches = icmp eq i32 %sel, %filt_sel - br i1 %matches, label %return, label %eh.resume - -return: - %r = phi i32 [0, %entry], [1, %lpad] - ret i32 %r - -eh.resume: - resume { i8*, i32 } %ehvals -} - -; CHECK-LABEL: define i32 @cleanup_and_except() -; CHECK: landingpad { i8*, i32 } -; CHECK-NEXT: cleanup -; CHECK-NEXT: catch i32 ()* @filt -; CHECK-NEXT: call i8* (...) @llvm.eh.actions( -; CHECK: i32 0, void ({{.*}})* @cleanup_and_except.cleanup, -; CHECK: i32 1, i8* bitcast (i32 ()* @filt to i8*), i32 -1, i8* blockaddress(@cleanup_and_except, %lpad.return_crit_edge)) -; CHECK-NEXT: indirectbr {{.*}} [label %lpad.return_crit_edge] -; -; CHECK: lpad.return_crit_edge: -; CHECK: br label %return -; -; CHECK: return: -; CHECK-NEXT: %r = phi i32 [ 0, %entry ], [ 1, %lpad.return_crit_edge ] -; CHECK-NEXT: ret i32 %r - -; FIXME: This cleanup is an artifact of bad demotion. -; X64-LABEL: define internal void @lpad_phi.cleanup(i8*, i8*) -; X86-LABEL: define internal void @lpad_phi.cleanup() -; X86: call i8* @llvm.frameaddress(i32 1) -; CHECK: call i8* @llvm.localrecover({{.*}}) -; CHECK: load i32 -; CHECK: store i32 %{{.*}}, i32*