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<BasicBlock *> &getReturnTargets() { return ReturnTargets; }
-
- void setExceptionVar(const Value *Val) { ExceptionObjectVar = Val; }
- void setExceptionVarIndex(int Index) { ExceptionObjectIndex = Index; }
- int getExceptionVarIndex() const { return ExceptionObjectIndex; }
- void setReturnTargets(TinyPtrVector<BasicBlock *> &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<BasicBlock *> 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<std::unique_ptr<ActionHandler>> &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<const BasicBlock *, MachineBasicBlock *> MBBOrBasicBlock;
typedef PointerUnion<const Value *, const MachineBasicBlock *> 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.
DenseMap<const CatchReturnInst *, const BasicBlock *>
CatchRetSuccessorColorMap;
DenseMap<MCSymbol *, std::pair<int, MCSymbol *>> InvokeToStateMap;
- SmallVector<WinEHUnwindMapEntry, 4> UnwindMap;
+ SmallVector<CxxUnwindMapEntry, 4> CxxUnwindMap;
SmallVector<WinEHTryBlockMapEntry, 4> TryBlockMap;
SmallVector<SEHUnwindMapEntry, 4> SEHUnwindMap;
SmallVector<ClrEHUnwindMapEntry, 4> 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);
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],
// 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.
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;
}
}
"Undefined result: Shift count out of range", &I);
}
-static bool
-allPredsCameFromLandingPad(BasicBlock *BB,
- SmallSet<BasicBlock *, 4> &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<BasicBlock *, 4> &VisitedBlocks) {
- VisitedBlocks.insert(BB);
- for (BasicBlock::iterator I = InstBegin, E = BB->end(); I != E; ++I) {
- IntrinsicInst *IC = dyn_cast<IntrinsicInst>(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<BasicBlock *, 4> 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<BasicBlock::iterator>(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<BasicBlock *, 4> &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<IntrinsicInst>(&*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<LandingPadInst>(*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<BasicBlock *, 4> 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.
/// 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) {
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<LandingPadInfo> &PadInfos = MMI->getLandingPads();
- SmallVector<const LandingPadInfo *, 64> 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<unsigned, 64> FirstActions;
- FirstActions.resize(LandingPads.size());
- SmallVector<CallSiteEntry, 64> 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,
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;
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())
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
// };
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
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
BaseState = -2;
}
- if (!FuncInfo.SEHUnwindMap.empty()) {
- for (SEHUnwindMapEntry &UME : FuncInfo.SEHUnwindMap) {
- MCSymbol *ExceptOrFinally =
- UME.Handler.get<MachineBasicBlock *>()->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<LandingPadInfo> &PadInfos = MMI->getLandingPads();
- SmallVector<const LandingPadInfo *, 4> LPads;
- LPads.reserve((PadInfos.size()));
- for (const LandingPadInfo &LPInfo : PadInfos)
- LPads.push_back(&LPInfo);
- std::sort(LPads.begin(), LPads.end(),
- [](const LandingPadInfo *L, const LandingPadInfo *R) {
- return L->WinEHState < R->WinEHState;
- });
-
- // For each action in each lpad, emit one of these:
- // struct ScopeTableEntry {
- // int32_t EnclosingLevel;
- // int32_t (__cdecl *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<MachineBasicBlock *>()->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
}
}
// 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<DbgDeclareInst>(II);
assert(DI->getVariable() && "Missing variable");
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);
H.Handler = MBBMap[BB];
}
}
- for (WinEHUnwindMapEntry &UME : EHInfo.UnwindMap)
+ for (CxxUnwindMapEntry &UME : EHInfo.CxxUnwindMap)
if (UME.Cleanup)
if (const auto *BB = dyn_cast<BasicBlock>(UME.Cleanup.get<const Value *>()))
UME.Cleanup = MBBMap[BB];
}
}
-void FunctionLoweringInfo::addSEHHandlersForLPads(
- ArrayRef<const LandingPadInst *> 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<IntrinsicInst>(LP->getNextNode());
- if (!ActionsCall ||
- ActionsCall->getIntrinsicID() != Intrinsic::eh_actions)
- continue;
-
- // Parse the llvm.eh.actions call we found.
- MachineBasicBlock *LPadMBB = MBBMap[LP->getParent()];
- SmallVector<std::unique_ptr<ActionHandler>, 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<CatchHandler>(Action)) {
- const auto *Filter =
- dyn_cast<Function>(CH->getSelector()->stripPointerCasts());
- assert((Filter || CH->getSelector()->isNullValue()) &&
- "expected function or catch-all");
- const auto *RecoverBA =
- cast<BlockAddress>(CH->getHandlerBlockOrFunc());
- MMI.addSEHCatchHandler(LPadMBB, Filter, RecoverBA);
- } else {
- assert(isa<CleanupHandler>(Action));
- const auto *Fini = cast<Function>(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.
}
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;
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: {
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<Function>(Personality->stripPointerCasts()))
- MF->getMMI().addPersonality(PF);
- EHPersonality PersonalityType = classifyEHPersonality(Personality);
-
- if (isFuncletEHPersonality(PersonalityType)) {
- SmallVector<MachineBasicBlock *, 4> ClauseBBs;
- const IntrinsicInst *ActionsCall =
- dyn_cast<IntrinsicInst>(LLVMBB->getFirstInsertionPt());
- // Get all invoke BBs that unwind to this landingpad.
- SmallVector<MachineBasicBlock *, 4> 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);
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<Value *, TinyPtrVector<AllocaInst *>> FrameVarInfoMap;
-
-// TinyPtrVector cannot hold nullptr, so we need our own sentinel that isn't
-// quite null.
-AllocaInst *getCatchObjectSentinel() {
- return static_cast<AllocaInst *>(nullptr) + 1;
-}
-
-typedef SmallSet<BasicBlock *, 4> VisitedBlockSet;
-
-class LandingPadActions;
-class LandingPadMap;
-
-typedef DenseMap<const BasicBlock *, CatchHandler *> CatchHandlerMapTy;
-typedef DenseMap<const BasicBlock *, CleanupHandler *> CleanupHandlerMapTy;
-
class WinEHPrepare : public FunctionPass {
public:
static char ID; // Pass identification, replacement for typeid.
}
private:
- bool prepareExceptionHandlers(Function &F,
- SmallVectorImpl<LandingPadInst *> &LPads);
- void identifyEHBlocks(Function &F, SmallVectorImpl<LandingPadInst *> &LPads);
- void promoteLandingPadValues(LandingPadInst *LPad);
- void demoteValuesLiveAcrossHandlers(Function &F,
- SmallVectorImpl<LandingPadInst *> &LPads);
- void findSEHEHReturnPoints(Function &F,
- SetVector<BasicBlock *> &EHReturnBlocks);
- void findCXXEHReturnPoints(Function &F,
- SetVector<BasicBlock *> &EHReturnBlocks);
- void getPossibleReturnTargets(Function *ParentF, Function *HandlerF,
- SetVector<BasicBlock*> &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,
Triple TheTriple;
// All fields are reset by runOnFunction.
- DominatorTree *DT = nullptr;
- const TargetLibraryInfo *LibInfo = nullptr;
EHPersonality Personality = EHPersonality::Unknown;
- CatchHandlerMapTy CatchHandlerMap;
- CleanupHandlerMapTy CleanupHandlerMap;
- DenseMap<const LandingPadInst *, LandingPadMap> LPadMaps;
- SmallPtrSet<BasicBlock *, 4> NormalBlocks;
- SmallPtrSet<BasicBlock *, 4> EHBlocks;
- SetVector<BasicBlock *> 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<LandingPadInst *, const LandingPadInst *> 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<const BasicBlock *, BasicBlock *> LPadTargetBlocks;
-
- // Map from outlined handler to call to parent local address. Only used for
- // 32-bit EH.
- DenseMap<Function *, Value *> HandlerToParentFP;
-
- AllocaInst *SEHExceptionCodeSlot = nullptr;
std::map<BasicBlock *, std::set<BasicBlock *>> BlockColors;
std::map<BasicBlock *, std::set<BasicBlock *>> FuncletBlocks;
std::map<BasicBlock *, std::set<BasicBlock *>> 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<const ExtractValueInst *> ExtractedEHPtrs;
- TinyPtrVector<const ExtractValueInst *> 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<LandingPadInst *, const LandingPadInst *> &NestedLPads,
- DominatorTree *DT, SmallPtrSetImpl<BasicBlock *> &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<BasicBlock *> &getReturnTargets() { return ReturnTargets; }
-
-private:
- Value *CurrentSelector;
-
- Value *ExceptionObjectVar;
- TinyPtrVector<BasicBlock *> ReturnTargets;
-
- // This will be a reference to the field of the same name in the WinEHPrepare
- // object which instantiates this WinEHCatchDirector object.
- DenseMap<LandingPadInst *, const LandingPadInst *> &NestedLPtoOriginalLP;
- DominatorTree *DT;
- SmallPtrSetImpl<BasicBlock *> &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<ActionHandler *> &actions() { return Actions; }
- SmallVectorImpl<ActionHandler *>::iterator begin() { return Actions.begin(); }
- SmallVectorImpl<ActionHandler *>::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<ActionHandler *, 4> Actions;
- bool HasCleanupHandlers;
-};
-
} // end anonymous namespace
char WinEHPrepare::ID = 0;
return new WinEHPrepare(TM);
}
-static bool
-findExceptionalConstructs(Function &Fn,
- SmallVectorImpl<LandingPadInst *> &LPads,
- SmallVectorImpl<ResumeInst *> &Resumes,
- SmallVectorImpl<BasicBlock *> &EntryBlocks) {
- bool ForExplicitEH = false;
+static void findFuncletEntryPoints(Function &Fn,
+ SmallVectorImpl<BasicBlock *> &EntryBlocks) {
+ EntryBlocks.push_back(&Fn.getEntryBlock());
for (BasicBlock &BB : Fn) {
Instruction *First = BB.getFirstNonPHI();
- if (auto *LP = dyn_cast<LandingPadInst>(First)) {
- LPads.push_back(LP);
- } else if (First->isEHPad()) {
- if (!ForExplicitEH)
- EntryBlocks.push_back(&Fn.getEntryBlock());
- if (!isa<CatchEndPadInst>(First) && !isa<CleanupEndPadInst>(First))
- EntryBlocks.push_back(&BB);
- ForExplicitEH = true;
- }
- if (auto *Resume = dyn_cast<ResumeInst>(BB.getTerminator()))
- Resumes.push_back(Resume);
+ if (!First->isEHPad())
+ continue;
+ assert(!isa<LandingPadInst>(First) &&
+ "landingpad cannot be used with funclet EH personality");
+ // Find EH pad blocks that represent funclet start points.
+ if (!isa<CatchEndPadInst>(First) && !isa<CleanupEndPadInst>(First))
+ EntryBlocks.push_back(&BB);
}
- return ForExplicitEH;
}
bool WinEHPrepare::runOnFunction(Function &Fn) {
// not.
removeUnreachableBlocks(Fn);
- SmallVector<LandingPadInst *, 4> LPads;
- SmallVector<ResumeInst *, 4> Resumes;
SmallVector<BasicBlock *, 4> 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<DominatorTreeWrapperPass>().getDomTree();
- LibInfo = &getAnalysis<TargetLibraryInfoWrapperPass>().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; }
AU.addRequired<TargetLibraryInfoWrapperPass>();
}
-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<BasicBlock *> &ReachableBBs,
- SetVector<BasicBlock *> &Worklist,
- const SetVector<BasicBlock *> *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<InvokeInst>(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<Instruction>(II->getOperand(0));
- auto *Op1 = dyn_cast<Instruction>(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<BasicBlock *> &EHReturnBlocks) {
- for (auto BBI = F.begin(), BBE = F.end(); BBI != BBE; ++BBI) {
- BasicBlock *BB = &*BBI;
- for (Instruction &I : *BB) {
- if (match(&I, m_Intrinsic<Intrinsic::eh_begincatch>())) {
- Instruction *SplitPt =
- findBeginCatchSplitPoint(BB, cast<IntrinsicInst>(&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<Intrinsic::eh_endcatch>())) {
- // 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<BranchInst>(I.getNextNode());
- if (!Br || !Br->isUnconditional() ||
- isa<PHINode>(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<ConstantPointerNull>(LP->getClause(N - 1)));
-}
-
-/// Find all points where exceptions control rejoins normal control flow via
-/// selector dispatch.
-void WinEHPrepare::findSEHEHReturnPoints(
- Function &F, SetVector<BasicBlock *> &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<LandingPadInst *> &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<PHINode>(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<BasicBlock *> 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<LandingPadInst *> &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<Instruction *, 10> EHVals;
- for (BasicBlock &BB : F) {
- LandingPadInst *LP = BB.getLandingPadInst();
- if (!LP)
- continue;
- EHVals.insert(LP);
- for (User *U : LP->users()) {
- auto *EI = dyn_cast<ExtractValueInst>(U);
- if (!EI)
- continue;
- EHVals.insert(EI);
- for (User *U2 : EI->users()) {
- if (auto *PN = dyn_cast<PHINode>(U2))
- EHVals.insert(PN);
- }
- }
- }
-
- SetVector<Argument *> ArgsToDemote;
- SetVector<Instruction *> 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<Constant>(Op) || isa<BasicBlock>(Op) || isa<InlineAsm>(Op))
- continue;
- auto *AI = dyn_cast<AllocaInst>(Op);
- if (AI && AI->isStaticAlloca())
- continue;
-
- if (auto *Arg = dyn_cast<Argument>(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<Instruction>(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<User *, 4> Users(Arg->user_begin(), Arg->user_end());
- for (User *U : Users) {
- auto *I = dyn_cast<Instruction>(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<PHINode>(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<LandingPadInst *> &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<Intrinsic::eh_actions>()))
- 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<std::pair<CallInst*, IndirectBrInst *>, 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<Intrinsic::eh_actions>())) {
- 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<CatchHandler>(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<PHINode>(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<Instruction *, 4> SEHCodeUses;
- SmallVector<Instruction *, 4> EHUndefs;
- for (User *U : LPad->users()) {
- auto *E = dyn_cast<ExtractValueInst>(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<Use *, 4> Uses;
- for (Use &U : E->uses())
- Uses.push_back(&U);
- for (Use *U : Uses) {
- auto *I = cast<Instruction>(U->getUser());
- if (isa<ResumeInst>(I))
- continue;
- if (auto *Phi = dyn_cast<PHINode>(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<Value *> ActionArgs;
- for (ActionHandler *Action : Actions) {
- // Action codes from docs are: 0 cleanup, 1 catch.
- if (auto *CatchAction = dyn_cast<CatchHandler>(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<Value *>(CatchAction->getExceptionVar());
- if (EHObj && !isa<ConstantPointerNull>(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<BasicBlock *> ReturnTargets;
- for (ActionHandler *Action : Actions) {
- if (auto *CatchAction = dyn_cast<CatchHandler>(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<BasicBlock*> CheckedTargets;
- SmallVector<std::unique_ptr<ActionHandler>, 4> ActionList;
- for (auto &LPadImplPair : LPadImpls) {
- IntrinsicInst *Recover = cast<IntrinsicInst>(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<BasicBlock *> ReturnTargets;
- for (const auto &Action : ActionList) {
- if (auto *CA = dyn_cast<CatchHandler>(Action.get())) {
- Function *Handler = cast<Function>(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<BranchInst>(Target->getTerminator());
- if (Br && Br->isUnconditional() &&
- Br != Target->getFirstNonPHIOrDbgOrLifetime()) {
- Instruction *Prev = Br->getPrevNode();
- if (match(cast<Value>(Prev), m_Intrinsic<Intrinsic::eh_endcatch>()))
- 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<Value *, 8> 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<IntrinsicInst>(&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<AllocaInst *> &Allocas = VarInfoEntry.second;
- AllocaInst *ParentAlloca = cast<AllocaInst>(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<Instruction>(
- 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<BasicBlock *, 4> UserBlocks;
- for (User *U : SEHExceptionCodeSlot->users()) {
- if (auto *Inst = dyn_cast<Instruction>(U))
- UserBlocks.insert(Inst->getParent());
- }
- PromoteMemToReg(SEHExceptionCodeSlot, *DT);
- // After the promotion, kill off dead instructions.
- for (BasicBlock *BB : UserBlocks)
- SimplifyInstructionsInBlock(BB, LibInfo);
- }
- }
-
- // Clean up the handler action maps we created for this function
- 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<AllocaInst *, 2> 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<ExtractValueInst>(U);
- if (!Extract)
- continue;
-
- for (auto *EU : Extract->users()) {
- if (auto *Store = dyn_cast<StoreInst>(EU)) {
- auto *AV = cast<AllocaInst>(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<Value *, 4> Users(LPad->user_begin(), LPad->user_end());
- for (auto *U : Users)
- RecursivelyDeleteTriviallyDeadInstructions(U);
-}
-
-void WinEHPrepare::getPossibleReturnTargets(Function *ParentF,
- Function *HandlerF,
- SetVector<BasicBlock*> &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<IntrinsicInst>(LPI->getNextNode());
- SmallVector<std::unique_ptr<ActionHandler>, 4> ActionList;
- parseEHActions(Recover, ActionList);
- for (const auto &Action : ActionList) {
- if (auto *CH = dyn_cast<CatchHandler>(Action.get())) {
- Function *NestedF = cast<Function>(CH->getHandlerBlockOrFunc());
- getPossibleReturnTargets(ParentF, NestedF, Targets);
- }
- }
- }
-
- auto *Ret = dyn_cast<ReturnInst>(BB.getTerminator());
- if (!Ret)
- continue;
-
- // Handler functions must always return a block address.
- BlockAddress *BA = cast<BlockAddress>(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<IndirectBrInst>(OutlinedBB->getTerminator());
- if (!Branch) {
- // If the landing pad wasn't in outlined form, it should be a stub with
- // an unreachable terminator.
- assert(isa<UnreachableInst>(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<IntrinsicInst>(Recover);
-
- // Remap the return target in the nested handler.
- SmallVector<BlockAddress *, 4> ActionTargets;
- SmallVector<std::unique_ptr<ActionHandler>, 4> ActionList;
- parseEHActions(EHActions, ActionList);
- for (const auto &Action : ActionList) {
- auto *Catch = dyn_cast<CatchHandler>(Action.get());
- if (!Catch)
- continue;
- // The dyn_cast to function here selects C++ catch handlers and skips
- // SEH catch handlers.
- auto *Handler = dyn_cast<Function>(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<ReturnInst>(NestedHandlerBB.getTerminator());
- if (!Ret)
- continue;
-
- // Handler functions must always return a block address.
- BlockAddress *BA = cast<BlockAddress>(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<IntrinsicInst>(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<Intrinsic::eh_typeid_for>(m_Constant(Selector))) &&
- !match(RHS, m_Intrinsic<Intrinsic::eh_typeid_for>(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<Value>(II), m_Intrinsic<Intrinsic::eh_begincatch>()))
- 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<InvokeInst>(Terminator);
- if (II)
- return;
- // If we've already recorded a return instruction, keep looking for invokes.
- if (!Ret)
- Ret = dyn_cast<ReturnInst>(Terminator);
- // If we haven't recorded an unreachable instruction, try this terminator.
- if (!Unreached)
- Unreached = dyn_cast<UnreachableInst>(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<WinEHCloningDirectorBase> Director;
-
- ValueToValueMapTy VMap;
-
- LandingPadMap &LPadMap = LPadMaps[LPad];
- if (!LPadMap.isInitialized())
- LPadMap.mapLandingPad(LPad);
- if (auto *CatchAction = dyn_cast<CatchHandler>(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<ReturnInst *, 8> 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<PHINode>(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<CatchHandler>(Action)) {
- WinEHCatchDirector *CatchDirector =
- reinterpret_cast<WinEHCatchDirector *>(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<BasicBlock>(MapEntry.first) || MapEntry.second == nullptr)
- continue;
- const BasicBlock *MappedBB = cast<BasicBlock>(MapEntry.first);
- for (auto *Pred : predecessors(const_cast<BasicBlock *>(MappedBB))) {
- auto *Branch = dyn_cast<BranchInst>(Pred->getTerminator());
- if (!Branch || !Branch->isUnconditional() || Pred->size() <= 1)
- continue;
- BasicBlock::iterator II =
- const_cast<BranchInst *>(Branch)->getIterator();
- --II;
- if (match(cast<Value>(II), m_Intrinsic<Intrinsic::eh_endcatch>())) {
- // 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<BasicBlock>(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<BasicBlock *> 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<ExtractValueInst>(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<Value *>(V), m_Intrinsic<Intrinsic::localaddress>());
-}
-
-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<LandingPadInst>(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<IndirectBrInst>(Inst)) {
- return handleIndirectBr(VMap, IBr, NewBB);
- }
-
- if (auto *Invoke = dyn_cast<InvokeInst>(Inst))
- return handleInvoke(VMap, Invoke, NewBB);
-
- if (auto *Resume = dyn_cast<ResumeInst>(Inst))
- return handleResume(VMap, Resume, NewBB);
-
- if (auto *Cmp = dyn_cast<CmpInst>(Inst))
- return handleCompare(VMap, Cmp, NewBB);
-
- if (match(Inst, m_Intrinsic<Intrinsic::eh_begincatch>()))
- return handleBeginCatch(VMap, Inst, NewBB);
- if (match(Inst, m_Intrinsic<Intrinsic::eh_endcatch>()))
- return handleEndCatch(VMap, Inst, NewBB);
- if (match(Inst, m_Intrinsic<Intrinsic::eh_typeid_for>()))
- 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<Intrinsic::eh_actions>()))
- 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<LandingPadInst>(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<ConstantPointerNull>(ExceptionObjectVar))
- return CloningDirector::SkipInstruction;
- assert(cast<AllocaInst>(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<IntrinsicInst>(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<BranchInst>(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<BasicBlock *>(ParentBB),
- const_cast<Instruction *>(cast<Instruction>(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<IntrinsicInst>(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<LandingPadInst>(VMap[LPad])] = LPad;
-
- // We should only get here for landing pads that have already been outlined.
- assert(match(LPad->getNextNode(), m_Intrinsic<Intrinsic::eh_actions>()));
-
- // Copy the indirectbr, but only include targets that were previously
- // identified as EH blocks and are dominated by the nested landing pad.
- SetVector<const BasicBlock *> ReturnTargets;
- for (int I = 0, E = IBr->getNumDestinations(); I < E; ++I) {
- auto *TargetBB = IBr->getDestination(I);
- if (EHBlocks.count(const_cast<BasicBlock*>(TargetBB)) &&
- DT->dominates(ParentBB, TargetBB)) {
- DEBUG(dbgs() << " Adding destination " << TargetBB->getName() << "\n");
- ReturnTargets.insert(TargetBB);
- }
- }
- IndirectBrInst *NewBranch =
- IndirectBrInst::Create(const_cast<Value *>(IBr->getAddress()),
- ReturnTargets.size(), NewBB);
- for (auto *Target : ReturnTargets)
- NewBranch->addDestination(const_cast<BasicBlock*>(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<Intrinsic::eh_typeid_for>())) {
- IntrinCall = dyn_cast<IntrinsicInst>(Compare->getOperand(0));
- } else if (match(Compare->getOperand(1),
- m_Intrinsic<Intrinsic::eh_typeid_for>())) {
- IntrinCall = dyn_cast<IntrinsicInst>(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<BasicBlock *>(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<Value *, 16> CallArgs(Invoke->op_begin(), Invoke->op_end() - 3);
- // Insert a normal call instruction...
- CallInst *NewCall =
- CallInst::Create(const_cast<Value *>(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<Intrinsic::eh_typeid_for>()) ||
- match(Compare->getOperand(1), m_Intrinsic<Intrinsic::eh_typeid_for>())) {
- 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<Instruction>(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<AllocaInst>(V)) {
- assert(AV->isStaticAlloca() &&
- "cannot materialize un-demoted dynamic alloca");
- AllocaInst *NewAlloca = dyn_cast<AllocaInst>(AV->clone());
- Builder.Insert(NewAlloca, AV->getName());
- FrameVarInfo[AV].push_back(NewAlloca);
- return NewAlloca;
- }
-
- if (isa<Instruction>(V) || isa<Argument>(V)) {
- Function *Parent = isa<Instruction>(V)
- ? cast<Instruction>(V)->getParent()->getParent()
- : cast<Argument>(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:
-//
-// <cleanup handler>
-// <selector comparison>
-// <catch handler>
-// <cleanup handler>
-// <selector comparison>
-// <catch handler>
-// <cleanup handler>
-// ...
-//
-// 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<ConstantPointerNull>(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<ConstantPointerNull>(
- 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<CatchHandler>(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<BranchInst>(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<ResumeInst>(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<PHINode>(ResumeVal) && !isa<LandingPadInst>(ResumeVal)) {
- Insert2 = dyn_cast<InsertValueInst>(ResumeVal);
- if (!Insert2)
- return createCleanupHandler(Actions, CleanupHandlerMap, BB);
- Insert1 = dyn_cast<InsertValueInst>(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<BranchInst>(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<CmpInst>(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<Intrinsic::eh_typeid_for>()))
- 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<InvokeInst>(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<Intrinsic::eh_begincatch>()))
- return;
- // If this a nested landing pad, it may contain an endcatch call.
- if (match(Inst, m_Intrinsic<Intrinsic::eh_endcatch>()))
- 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<std::unique_ptr<ActionHandler>> &Actions) {
- assert(II->getIntrinsicID() == Intrinsic::eh_actions &&
- "attempted to parse non eh.actions intrinsic");
- for (unsigned I = 0, E = II->getNumArgOperands(); I != E;) {
- uint64_t ActionKind =
- cast<ConstantInt>(II->getArgOperand(I))->getZExtValue();
- if (ActionKind == /*catch=*/1) {
- auto *Selector = cast<Constant>(II->getArgOperand(I + 1));
- ConstantInt *EHObjIndex = cast<ConstantInt>(II->getArgOperand(I + 2));
- int64_t EHObjIndexVal = EHObjIndex->getSExtValue();
- Constant *Handler = cast<Constant>(II->getArgOperand(I + 3));
- I += 4;
- auto CH = make_unique<CatchHandler>(/*BB=*/nullptr, Selector,
- /*NextBB=*/nullptr);
- CH->setHandlerBlockOrFunc(Handler);
- CH->setExceptionVarIndex(EHObjIndexVal);
- Actions.push_back(std::move(CH));
- } else if (ActionKind == 0) {
- Constant *Handler = cast<Constant>(II->getArgOperand(I + 1));
- I += 2;
- auto CH = make_unique<CleanupHandler>(/*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();
}
void llvm::calculateCatchReturnSuccessorColors(const Function *Fn,
WinEHFuncInfo &FuncInfo) {
- SmallVector<LandingPadInst *, 4> LPads;
- SmallVector<ResumeInst *, 4> Resumes;
SmallVector<BasicBlock *, 4> EntryBlocks;
// colorFunclets needs the set of EntryBlocks, get them using
- // findExceptionalConstructs.
- bool ForExplicitEH = findExceptionalConstructs(const_cast<Function &>(*Fn),
- LPads, Resumes, EntryBlocks);
- if (!ForExplicitEH)
- return;
+ // findFuncletEntryPoints.
+ findFuncletEntryPoints(const_cast<Function &>(*Fn), EntryBlocks);
std::map<BasicBlock *, std::set<BasicBlock *>> BlockColors;
std::map<BasicBlock *, std::set<BasicBlock *>> FuncletBlocks;
}
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
}
}
-/// 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<BasicBlock *, 4> ExceptBlocks;
- for (BasicBlock &BB : F) {
- for (auto I = BB.begin(), E = BB.end(); I != E; ++I) {
- if (auto *CI = dyn_cast<CallInst>(I)) {
- auto *Intrin = dyn_cast<IntrinsicInst>(CI);
- if (Intrin) {
- // Calls that "don't throw" are considered to be able to throw asynch
- // exceptions, but intrinsics cannot.
- continue;
- }
- insertStateNumberStore(RegNode, CI, -1);
- } else if (auto *II = dyn_cast<InvokeInst>(I)) {
- // Look up the state number of the landingpad this unwinds to.
- LandingPadInst *LPI = II->getUnwindDest()->getLandingPadInst();
- auto InsertionPair =
- FuncInfo.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<IntrinsicInst>(LPI->getNextNode());
- SmallVector<std::unique_ptr<ActionHandler>, 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<CatchHandler>(Handler.get())) {
- auto *BA = cast<BlockAddress>(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);
+++ /dev/null
-; 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()
-
+++ /dev/null
-; 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 }
+++ /dev/null
-; 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 }
+++ /dev/null
-; 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)"}
+++ /dev/null
-; 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)"}
+++ /dev/null
-; 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)"}
+++ /dev/null
-; 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()
+++ /dev/null
-; 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)
+++ /dev/null
-; 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)"}
+++ /dev/null
-; 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)"}
+++ /dev/null
-; 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)"}
+++ /dev/null
-; 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)"}
+++ /dev/null
-; 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)"}
+++ /dev/null
-; 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)"}
+++ /dev/null
-; 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)"}
+++ /dev/null
-; 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)"}
+++ /dev/null
-; 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)"}
+++ /dev/null
-; 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}
+++ /dev/null
-; 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 = '<stdin>'
-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)"}
+++ /dev/null
-; 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)"}
+++ /dev/null
-; 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
+++ /dev/null
-; 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
+++ /dev/null
-; 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
+++ /dev/null
-; 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)
+++ /dev/null
-; 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 "}
+++ /dev/null
-; 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 }
+++ /dev/null
-; 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 "}
+++ /dev/null
-; 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()
+++ /dev/null
-; 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*