[WinEH] Delete the old landingpad implementation of Windows EH

The new implementation works at least as well as the old implementation
did.

Also delete the associated preparation tests. They don't exercise
interesting corner cases of the new implementation. All the codegen
tests of the EH tables have already been ported.

llvm-svn: 249918
This commit is contained in:
Reid Kleckner 2015-10-09 23:34:53 +00:00
parent eb7cd6c889
commit 14e773500e
39 changed files with 108 additions and 8039 deletions

View File

@ -33,99 +33,18 @@ class MCSymbol;
class MachineBasicBlock;
class Value;
enum ActionType { Catch, Cleanup };
class ActionHandler {
public:
ActionHandler(BasicBlock *BB, ActionType Type)
: StartBB(BB), Type(Type), EHState(-1), HandlerBlockOrFunc(nullptr) {}
ActionType getType() const { return Type; }
BasicBlock *getStartBlock() const { return StartBB; }
bool hasBeenProcessed() { return HandlerBlockOrFunc != nullptr; }
void setHandlerBlockOrFunc(Constant *F) { HandlerBlockOrFunc = F; }
Constant *getHandlerBlockOrFunc() { return HandlerBlockOrFunc; }
void setEHState(int State) { EHState = State; }
int getEHState() const { return EHState; }
private:
BasicBlock *StartBB;
ActionType Type;
int EHState;
// Can be either a BlockAddress or a Function depending on the EH personality.
Constant *HandlerBlockOrFunc;
};
class CatchHandler : public ActionHandler {
public:
CatchHandler(BasicBlock *BB, Constant *Selector, BasicBlock *NextBB)
: ActionHandler(BB, ActionType::Catch), Selector(Selector),
NextBB(NextBB), ExceptionObjectVar(nullptr),
ExceptionObjectIndex(-1) {}
// Method for support type inquiry through isa, cast, and dyn_cast:
static inline bool classof(const ActionHandler *H) {
return H->getType() == ActionType::Catch;
}
Constant *getSelector() const { return Selector; }
BasicBlock *getNextBB() const { return NextBB; }
const Value *getExceptionVar() { return ExceptionObjectVar; }
TinyPtrVector<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.
@ -174,13 +93,13 @@ struct WinEHFuncInfo {
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);

View File

@ -429,13 +429,6 @@ def int_eh_typeid_for : Intrinsic<[llvm_i32_ty], [llvm_ptr_ty], [IntrNoMem]>;
def int_eh_return_i32 : Intrinsic<[], [llvm_i32_ty, llvm_ptr_ty]>;
def int_eh_return_i64 : Intrinsic<[], [llvm_i64_ty, llvm_ptr_ty]>;
// eh.begincatch takes a pointer returned by a landingpad instruction and
// copies the exception object into the memory pointed to by the second
// parameter. If the second parameter is null, no copy occurs.
def int_eh_begincatch : Intrinsic<[], [llvm_ptr_ty, llvm_ptr_ty],
[NoCapture<0>, NoCapture<1>]>;
def int_eh_endcatch : Intrinsic<[], []>;
// eh.exceptionpointer returns the pointer to the exception caught by
// the given `catchpad`.
def int_eh_exceptionpointer : Intrinsic<[llvm_anyptr_ty], [llvm_token_ty],
@ -444,12 +437,6 @@ def int_eh_exceptionpointer : Intrinsic<[llvm_anyptr_ty], [llvm_token_ty],
// Gets the exception code from a catchpad token. Only used on some platforms.
def int_eh_exceptioncode : Intrinsic<[llvm_i32_ty], [llvm_token_ty], [IntrNoMem]>;
// Represents the list of actions to take when an exception is thrown.
def int_eh_actions : Intrinsic<[llvm_ptr_ty], [llvm_vararg_ty], []>;
// FIXME: Remove this when landing pad EH can be removed.
def int_eh_exceptioncode_old : Intrinsic<[llvm_i32_ty], [], [IntrReadMem]>;
// __builtin_unwind_init is an undocumented GCC intrinsic that causes all
// callee-saved registers to be saved and restored (regardless of whether they
// are used) in the calling function. It is used by libgcc_eh.

View File

@ -345,13 +345,6 @@ void Lint::visitCallSite(CallSite CS) {
visitMemoryReference(I, CS.getArgument(0), MemoryLocation::UnknownSize, 0,
nullptr, MemRef::Read | MemRef::Write);
break;
case Intrinsic::eh_begincatch:
visitEHBeginCatch(II);
break;
case Intrinsic::eh_endcatch:
visitEHEndCatch(II);
break;
}
}
@ -511,187 +504,6 @@ void Lint::visitShl(BinaryOperator &I) {
"Undefined result: Shift count out of range", &I);
}
static bool
allPredsCameFromLandingPad(BasicBlock *BB,
SmallSet<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.

View File

@ -418,7 +418,7 @@ invoke_ranges(WinEHFuncInfo &EHInfo, const MachineBasicBlock &MBB) {
/// imagerel32 LabelStart;
/// imagerel32 LabelEnd;
/// imagerel32 FilterOrFinally; // One means catch-all.
/// imagerel32 ExceptOrNull; // Zero means __finally.
/// imagerel32 LabelLPad; // Zero means __finally.
/// } Entries[NumEntries];
/// };
void WinException::emitCSpecificHandlerTable(const MachineFunction *MF) {
@ -426,153 +426,69 @@ void WinException::emitCSpecificHandlerTable(const MachineFunction *MF) {
MCContext &Ctx = Asm->OutContext;
WinEHFuncInfo &FuncInfo = MMI->getWinEHFuncInfo(MF->getFunction());
if (!FuncInfo.SEHUnwindMap.empty()) {
// Remember what state we were in the last time we found a begin try label.
// This allows us to coalesce many nearby invokes with the same state into
// one entry.
int LastEHState = -1;
MCSymbol *LastBeginLabel = nullptr;
MCSymbol *LastEndLabel = nullptr;
// Use the assembler to compute the number of table entries through label
// difference and division.
MCSymbol *TableBegin =
Ctx.createTempSymbol("lsda_begin", /*AlwaysAddSuffix=*/true);
MCSymbol *TableEnd =
Ctx.createTempSymbol("lsda_end", /*AlwaysAddSuffix=*/true);
const MCExpr *LabelDiff =
MCBinaryExpr::createSub(MCSymbolRefExpr::create(TableEnd, Ctx),
MCSymbolRefExpr::create(TableBegin, Ctx), Ctx);
const MCExpr *EntrySize = MCConstantExpr::create(16, Ctx);
const MCExpr *EntryCount =
MCBinaryExpr::createDiv(LabelDiff, EntrySize, Ctx);
OS.EmitValue(EntryCount, 4);
// 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;
OS.EmitLabel(TableBegin);
// 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);
// 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;
OS.EmitLabel(TableBegin);
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;
}
// 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;
// If this invoke ends a previous one, emit all the actions for this
// state.
if (LastEHState != -1)
emitSEHActionsForRange(FuncInfo, LastBeginLabel, LastEndLabel,
LastEHState);
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;
}
// 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);
// 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);
LastBeginLabel = I.BeginLabel;
LastEndLabel = I.EndLabel;
LastEHState = I.State;
}
}
// Hitting the end of the function causes us to emit the range for the
// previous invoke.
if (LastEndLabel)
emitSEHActionsForRange(FuncInfo, LastBeginLabel, LastEndLabel, LastEHState);
OS.EmitLabel(TableEnd);
}
void WinException::emitSEHActionsForRange(WinEHFuncInfo &FuncInfo,
@ -583,12 +499,6 @@ void WinException::emitSEHActionsForRange(WinEHFuncInfo &FuncInfo,
assert(BeginLabel && EndLabel);
while (State != -1) {
// struct Entry {
// imagerel32 LabelStart;
// imagerel32 LabelEnd;
// imagerel32 FilterOrFinally; // One means catch-all.
// imagerel32 ExceptOrNull; // Zero means __finally.
// };
SEHUnwindMapEntry &UME = FuncInfo.SEHUnwindMap[State];
const MCExpr *FilterOrFinally;
const MCExpr *ExceptOrNull;
@ -641,7 +551,7 @@ void WinException::emitCXXFrameHandler3Table(const MachineFunction *MF) {
MCSymbol *UnwindMapXData = nullptr;
MCSymbol *TryBlockMapXData = nullptr;
MCSymbol *IPToStateXData = nullptr;
if (!FuncInfo.UnwindMap.empty())
if (!FuncInfo.CxxUnwindMap.empty())
UnwindMapXData = Asm->OutContext.getOrCreateSymbol(
Twine("$stateUnwindMap$", FuncLinkageName));
if (!FuncInfo.TryBlockMap.empty())
@ -669,7 +579,7 @@ void WinException::emitCXXFrameHandler3Table(const MachineFunction *MF) {
OS.EmitValueToAlignment(4);
OS.EmitLabel(FuncInfoXData);
OS.EmitIntValue(0x19930522, 4); // MagicNumber
OS.EmitIntValue(FuncInfo.UnwindMap.size(), 4); // MaxState
OS.EmitIntValue(FuncInfo.CxxUnwindMap.size(), 4); // MaxState
OS.EmitValue(create32bitRef(UnwindMapXData), 4); // UnwindMap
OS.EmitIntValue(FuncInfo.TryBlockMap.size(), 4); // NumTryBlocks
OS.EmitValue(create32bitRef(TryBlockMapXData), 4); // TryBlockMap
@ -686,7 +596,7 @@ void WinException::emitCXXFrameHandler3Table(const MachineFunction *MF) {
// };
if (UnwindMapXData) {
OS.EmitLabel(UnwindMapXData);
for (const WinEHUnwindMapEntry &UME : FuncInfo.UnwindMap) {
for (const CxxUnwindMapEntry &UME : FuncInfo.CxxUnwindMap) {
MCSymbol *CleanupSym = getMCSymbolForMBBOrGV(Asm, UME.Cleanup);
OS.EmitIntValue(UME.ToState, 4); // ToState
OS.EmitValue(create32bitRef(CleanupSym), 4); // Action
@ -719,7 +629,7 @@ void WinException::emitCXXFrameHandler3Table(const MachineFunction *MF) {
assert(0 <= TBME.TryLow && "bad trymap interval");
assert(TBME.TryLow <= TBME.TryHigh && "bad trymap interval");
assert(TBME.TryHigh < TBME.CatchHigh && "bad trymap interval");
assert(TBME.CatchHigh < int(FuncInfo.UnwindMap.size()) &&
assert(TBME.CatchHigh < int(FuncInfo.CxxUnwindMap.size()) &&
"bad trymap interval");
OS.EmitIntValue(TBME.TryLow, 4); // TryLow
@ -903,66 +813,15 @@ void WinException::emitExceptHandlerTable(const MachineFunction *MF) {
BaseState = -2;
}
if (!FuncInfo.SEHUnwindMap.empty()) {
for (SEHUnwindMapEntry &UME : FuncInfo.SEHUnwindMap) {
MCSymbol *ExceptOrFinally =
UME.Handler.get<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
}
}

View File

@ -1103,13 +1103,6 @@ bool FastISel::selectIntrinsicCall(const IntrinsicInst *II) {
// The donothing intrinsic does, well, nothing.
case Intrinsic::donothing:
return true;
case Intrinsic::eh_actions: {
unsigned ResultReg = getRegForValue(UndefValue::get(II->getType()));
if (!ResultReg)
return false;
updateValueMap(II, ResultReg);
return true;
}
case Intrinsic::dbg_declare: {
const DbgDeclareInst *DI = cast<DbgDeclareInst>(II);
assert(DI->getVariable() && "Missing variable");

View File

@ -283,11 +283,6 @@ void FunctionLoweringInfo::set(const Function &fn, MachineFunction &mf,
if (!isFuncletEHPersonality(Personality))
return;
if (Personality == EHPersonality::MSVC_Win64SEH ||
Personality == EHPersonality::MSVC_X86SEH) {
addSEHHandlersForLPads(LPads);
}
// Calculate state numbers if we haven't already.
WinEHFuncInfo &EHInfo = MMI.getWinEHFuncInfo(&fn);
const Function *WinEHParentFn = MMI.getWinEHParent(&fn);
@ -313,7 +308,7 @@ void FunctionLoweringInfo::set(const Function &fn, MachineFunction &mf,
H.Handler = MBBMap[BB];
}
}
for (WinEHUnwindMapEntry &UME : EHInfo.UnwindMap)
for (CxxUnwindMapEntry &UME : EHInfo.CxxUnwindMap)
if (UME.Cleanup)
if (const auto *BB = dyn_cast<BasicBlock>(UME.Cleanup.get<const Value *>()))
UME.Cleanup = MBBMap[BB];
@ -345,44 +340,6 @@ void FunctionLoweringInfo::set(const Function &fn, MachineFunction &mf,
}
}
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.

View File

@ -5152,9 +5152,6 @@ SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) {
}
case Intrinsic::clear_cache:
return TLI.getClearCacheBuiltinName();
case Intrinsic::eh_actions:
setValue(&I, DAG.getUNDEF(TLI.getPointerTy(DAG.getDataLayout())));
return nullptr;
case Intrinsic::donothing:
// ignore
return nullptr;
@ -5238,22 +5235,6 @@ SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) {
return nullptr;
}
case Intrinsic::eh_begincatch:
case Intrinsic::eh_endcatch:
llvm_unreachable("begin/end catch intrinsics not lowered in codegen");
case Intrinsic::eh_exceptioncode_old: {
unsigned Reg = TLI.getExceptionPointerRegister();
assert(Reg && "cannot get exception code on this platform");
MVT PtrVT = TLI.getPointerTy(DAG.getDataLayout());
const TargetRegisterClass *PtrRC = TLI.getRegClassFor(PtrVT);
assert(FuncInfo.MBB->isEHPad() && "eh.exceptioncode in non-lpad");
unsigned VReg = FuncInfo.MBB->addLiveIn(Reg, PtrRC);
SDValue N =
DAG.getCopyFromReg(DAG.getEntryNode(), getCurSDLoc(), VReg, PtrVT);
N = DAG.getZExtOrTrunc(N, getCurSDLoc(), MVT::i32);
setValue(&I, N);
return nullptr;
}
case Intrinsic::eh_exceptionpointer:
case Intrinsic::eh_exceptioncode: {

View File

@ -973,43 +973,6 @@ bool SelectionDAGISel::PrepareEHLandingPad() {
BuildMI(*MBB, FuncInfo->InsertPt, SDB->getCurDebugLoc(), II)
.addSym(Label);
// If this personality function uses funclets, we need to split the landing
// pad into several BBs.
const Constant *Personality = MF->getFunction()->getPersonalityFn();
if (const auto *PF = dyn_cast<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);

File diff suppressed because it is too large Load Diff

View File

@ -429,14 +429,27 @@ void WinEHStatePass::unlinkExceptionRegistration(IRBuilder<> &Builder) {
}
void WinEHStatePass::addCXXStateStores(Function &F, WinEHFuncInfo &FuncInfo) {
calculateWinCXXEHStateNumbers(&F, FuncInfo);
// The base state for the parent is -1.
addStateStoresToFunclet(RegNode, FuncInfo, F, -1);
// Set up RegNodeEscapeIndex
int RegNodeEscapeIndex = escapeRegNode(F);
FuncInfo.EHRegNodeEscapeIndex = RegNodeEscapeIndex;
calculateWinCXXEHStateNumbers(&F, FuncInfo);
addStateStoresToFunclet(RegNode, FuncInfo, F, -1);
}
/// Assign every distinct landingpad a unique state number for SEH. Unlike C++
/// EH, we can use this very simple algorithm while C++ EH cannot because catch
/// handlers aren't outlined and the runtime doesn't have to figure out which
/// catch handler frame to unwind to.
void WinEHStatePass::addSEHStateStores(Function &F, WinEHFuncInfo &FuncInfo) {
// Remember and return the index that we used. We save it in WinEHFuncInfo so
// that we can lower llvm.x86.seh.recoverfp later in filter functions without
// too much trouble.
int RegNodeEscapeIndex = escapeRegNode(F);
FuncInfo.EHRegNodeEscapeIndex = RegNodeEscapeIndex;
calculateSEHStateNumbers(&F, FuncInfo);
addStateStoresToFunclet(RegNode, FuncInfo, F, -1);
}
/// Escape RegNode so that we can access it from child handlers. Find the call
@ -503,92 +516,6 @@ void WinEHStatePass::addStateStoresToFunclet(Value *ParentRegNode,
}
}
/// Assign every distinct landingpad a unique state number for SEH. Unlike C++
/// EH, we can use this very simple algorithm while C++ EH cannot because catch
/// handlers aren't outlined and the runtime doesn't have to figure out which
/// catch handler frame to unwind to.
/// FIXME: __finally blocks are outlined, so this approach may break down there.
void WinEHStatePass::addSEHStateStores(Function &F, WinEHFuncInfo &FuncInfo) {
// Remember and return the index that we used. We save it in WinEHFuncInfo so
// that we can lower llvm.x86.seh.recoverfp later in filter functions without
// too much trouble.
int RegNodeEscapeIndex = escapeRegNode(F);
FuncInfo.EHRegNodeEscapeIndex = RegNodeEscapeIndex;
// If this funciton uses the new EH IR, use the explicit state numbering
// algorithm and return early.
bool UsesLPads = false;
for (BasicBlock &BB : F) {
if (BB.isLandingPad()) {
UsesLPads = true;
break;
}
}
if (!UsesLPads) {
calculateSEHStateNumbers(&F, FuncInfo);
addStateStoresToFunclet(RegNode, FuncInfo, F, -1);
return;
}
// FIXME: Delete the rest of this code and clean things up when new EH is
// done.
// Iterate all the instructions and emit state number stores.
int CurState = 0;
SmallPtrSet<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);

View File

@ -1,278 +0,0 @@
; RUN: opt -lint -disable-output < %s 2>&1 | FileCheck %s
; This test is meant to prove that the Verifier is able to identify a variety
; of errors with the llvm.eh.begincatch and llvm.eh.endcatch intrinsics.
; See cppeh-catch-intrinsics-clean for correct uses.
target triple = "x86_64-pc-windows-msvc"
declare void @llvm.eh.begincatch(i8*, i8*)
declare void @llvm.eh.endcatch()
@_ZTIi = external constant i8*
; Function Attrs: uwtable
define void @test_missing_endcatch() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
; CHECK: Some paths from llvm.eh.begincatch may not reach llvm.eh.endcatch
; CHECK-NEXT: call void @llvm.eh.begincatch(i8* %exn, i8* null)
entry:
invoke void @_Z9may_throwv()
to label %try.cont unwind label %lpad
lpad: ; preds = %entry
%0 = landingpad { i8*, i32 }
catch i8* bitcast (i8** @_ZTIi to i8*)
%exn = extractvalue { i8*, i32 } %0, 0
%sel = extractvalue { i8*, i32 } %0, 1
%1 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*))
%matches = icmp eq i32 %sel, %1
br i1 %matches, label %catch, label %eh.resume
catch: ; preds = %lpad
call void @llvm.eh.begincatch(i8* %exn, i8* null)
call void @_Z10handle_intv()
br label %invoke.cont2
invoke.cont2: ; preds = %catch
br label %try.cont
try.cont: ; preds = %invoke.cont2, %entry
ret void
eh.resume: ; preds = %catch.dispatch
resume { i8*, i32 } %0
}
; Function Attrs: uwtable
define void @test_missing_begincatch() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
; CHECK: llvm.eh.endcatch may be reachable without passing llvm.eh.begincatch
; CHECK-NEXT: call void @llvm.eh.endcatch()
entry:
invoke void @_Z9may_throwv()
to label %try.cont unwind label %lpad
lpad: ; preds = %entry
%0 = landingpad { i8*, i32 }
catch i8* bitcast (i8** @_ZTIi to i8*)
%exn = extractvalue { i8*, i32 } %0, 0
%sel = extractvalue { i8*, i32 } %0, 1
%1 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*))
%matches = icmp eq i32 %sel, %1
br i1 %matches, label %catch, label %eh.resume
catch: ; preds = %lpad
call void @_Z10handle_intv()
br label %invoke.cont2
invoke.cont2: ; preds = %catch
call void @llvm.eh.endcatch()
br label %try.cont
try.cont: ; preds = %invoke.cont2, %entry
ret void
eh.resume: ; preds = %catch.dispatch
resume { i8*, i32 } %0
}
; Function Attrs: uwtable
define void @test_multiple_begin() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
; CHECK: llvm.eh.begincatch may be called a second time before llvm.eh.endcatch
; CHECK-NEXT: call void @llvm.eh.begincatch(i8* %exn, i8* null)
; CHECK-NEXT: call void @llvm.eh.begincatch(i8* %exn, i8* null)
entry:
invoke void @_Z9may_throwv()
to label %try.cont unwind label %lpad
lpad: ; preds = %entry
%0 = landingpad { i8*, i32 }
catch i8* bitcast (i8** @_ZTIi to i8*)
%exn = extractvalue { i8*, i32 } %0, 0
%sel = extractvalue { i8*, i32 } %0, 1
%1 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*))
%matches = icmp eq i32 %sel, %1
br i1 %matches, label %catch, label %eh.resume
catch: ; preds = %lpad
call void @llvm.eh.begincatch(i8* %exn, i8* null)
call void @_Z10handle_intv()
br label %invoke.cont2
invoke.cont2: ; preds = %catch
call void @llvm.eh.begincatch(i8* %exn, i8* null)
call void @llvm.eh.endcatch()
br label %try.cont
try.cont: ; preds = %invoke.cont2, %entry
ret void
eh.resume: ; preds = %catch.dispatch
resume { i8*, i32 } %0
}
; Function Attrs: uwtable
define void @test_multiple_end() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
; CHECK: llvm.eh.endcatch may be called a second time after llvm.eh.begincatch
; CHECK-NEXT: call void @llvm.eh.endcatch()
; CHECK-NEXT: call void @llvm.eh.endcatch()
entry:
invoke void @_Z9may_throwv()
to label %try.cont unwind label %lpad
lpad: ; preds = %entry
%0 = landingpad { i8*, i32 }
catch i8* bitcast (i8** @_ZTIi to i8*)
%exn = extractvalue { i8*, i32 } %0, 0
%sel = extractvalue { i8*, i32 } %0, 1
%1 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*))
%matches = icmp eq i32 %sel, %1
br i1 %matches, label %catch, label %eh.resume
catch: ; preds = %lpad
call void @llvm.eh.begincatch(i8* %exn, i8* null)
call void @_Z10handle_intv()
call void @llvm.eh.endcatch()
br label %invoke.cont2
invoke.cont2: ; preds = %catch
call void @llvm.eh.endcatch()
br label %try.cont
try.cont: ; preds = %invoke.cont2, %entry
ret void
eh.resume: ; preds = %catch.dispatch
resume { i8*, i32 } %0
}
; Function Attrs: uwtable
define void @test_begincatch_without_lpad() {
; CHECK: llvm.eh.begincatch may be reachable without passing a landingpad
; CHECK-NEXT: call void @llvm.eh.begincatch(i8* %exn, i8* null)
entry:
%exn = alloca i8
call void @llvm.eh.begincatch(i8* %exn, i8* null)
call void @_Z10handle_intv()
br label %invoke.cont2
invoke.cont2: ; preds = %catch
call void @llvm.eh.endcatch()
br label %try.cont
try.cont: ; preds = %invoke.cont2, %entry
ret void
}
; Function Attrs: uwtable
define void @test_branch_to_begincatch_with_no_lpad(i32 %fake.sel) personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
; CHECK: llvm.eh.begincatch may be reachable without passing a landingpad
; CHECK-NEXT: call void @llvm.eh.begincatch(i8* %exn2, i8* null)
entry:
%fake.exn = alloca i8
invoke void @_Z9may_throwv()
to label %catch unwind label %lpad
lpad: ; preds = %entry
%0 = landingpad { i8*, i32 }
catch i8* bitcast (i8** @_ZTIi to i8*)
%exn = extractvalue { i8*, i32 } %0, 0
%sel = extractvalue { i8*, i32 } %0, 1
%1 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*))
%matches = icmp eq i32 %sel, %1
br i1 %matches, label %catch, label %eh.resume
invoke void @_Z9may_throwv()
to label %try.cont unwind label %lpad
catch: ; preds = %lpad, %entry
%exn2 = phi i8* [%exn, %lpad], [%fake.exn, %entry]
%sel2 = phi i32 [%sel, %lpad], [%fake.sel, %entry]
call void @llvm.eh.begincatch(i8* %exn2, i8* null)
call void @_Z10handle_intv()
%matches1 = icmp eq i32 %sel2, 0
br i1 %matches1, label %invoke.cont2, label %invoke.cont3
invoke.cont2: ; preds = %catch
call void @llvm.eh.endcatch()
br label %try.cont
invoke.cont3: ; preds = %catch
call void @llvm.eh.endcatch()
br label %eh.resume
try.cont: ; preds = %invoke.cont2
ret void
eh.resume: ; preds = %catch.dispatch
%lpad.val = insertvalue { i8*, i32 } undef, i32 0, 1
resume { i8*, i32 } %lpad.val
}
; Function Attrs: uwtable
define void @test_branch_missing_endcatch() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
; CHECK: Some paths from llvm.eh.begincatch may not reach llvm.eh.endcatch
; CHECK-NEXT: call void @llvm.eh.begincatch(i8* %exn2, i8* null)
entry:
invoke void @_Z9may_throwv()
to label %invoke.cont unwind label %lpad
invoke.cont:
invoke void @_Z9may_throwv()
to label %invoke.cont unwind label %lpad1
lpad: ; preds = %entry
%0 = landingpad { i8*, i32 }
catch i8* bitcast (i8** @_ZTIi to i8*)
%exn = extractvalue { i8*, i32 } %0, 0
%sel = extractvalue { i8*, i32 } %0, 1
%1 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*))
%matches = icmp eq i32 %sel, %1
br i1 %matches, label %catch, label %eh.resume
invoke void @_Z9may_throwv()
to label %try.cont unwind label %lpad
lpad1: ; preds = %entry
%l1.0 = landingpad { i8*, i32 }
cleanup
catch i8* bitcast (i8** @_ZTIi to i8*)
%exn1 = extractvalue { i8*, i32 } %l1.0, 0
%sel1 = extractvalue { i8*, i32 } %l1.0, 1
%l1.1 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*))
%matchesl1 = icmp eq i32 %sel1, %l1.1
br i1 %matchesl1, label %catch, label %eh.resume
catch: ; preds = %lpad, %lpad1
%exn2 = phi i8* [%exn, %lpad], [%exn1, %lpad1]
%sel2 = phi i32 [%sel, %lpad], [%sel1, %lpad1]
call void @llvm.eh.begincatch(i8* %exn2, i8* null)
call void @_Z10handle_intv()
%matches1 = icmp eq i32 %sel2, 0
br i1 %matches1, label %invoke.cont2, label %invoke.cont3
invoke.cont2: ; preds = %catch
call void @llvm.eh.endcatch()
br label %try.cont
invoke.cont3: ; preds = %catch
br label %eh.resume
try.cont: ; preds = %invoke.cont2, %entry
ret void
eh.resume: ; preds = %catch.dispatch
%lpad.val = insertvalue { i8*, i32 } undef, i32 0, 1
resume { i8*, i32 } %lpad.val
}
declare void @_Z9may_throwv()
declare i32 @__CxxFrameHandler3(...)
; Function Attrs: nounwind readnone
declare i32 @llvm.eh.typeid.for(i8*)
declare void @_Z10handle_intv()

View File

@ -1,180 +0,0 @@
; RUN: opt -mtriple=x86_64-pc-windows-msvc -winehprepare -S -o - < %s | FileCheck %s
; This test describes two difficult cases in sinking allocas into child frames.
; We don't currently do this optimization, but we'll need to tweak these tests
; when we do.
; This test is based on the following code:
;
; // In this case we can sink the alloca from the parent into the catch because
; // the lifetime is limited to the catch.
; extern "C" void may_throw();
; extern "C" void sink_alloca_to_catch() {
; try {
; may_throw();
; } catch (int) {
; volatile int only_used_in_catch = 42;
; }
; }
;
; // In this case we cannot. The variable should live as long as the parent
; // frame lives.
; extern "C" void use_catch_var(int *);
; extern "C" void dont_sink_alloca_to_catch(int n) {
; int live_in_out_catch = 0;
; while (n > 0) {
; try {
; may_throw();
; } catch (int) {
; use_catch_var(&live_in_out_catch);
; }
; n--;
; }
; }
target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-windows-msvc"
declare void @may_throw() #1
declare i32 @__CxxFrameHandler3(...)
declare i32 @llvm.eh.typeid.for(i8*) #2
declare void @llvm.eh.begincatch(i8* nocapture, i8* nocapture) #3
declare void @llvm.eh.endcatch() #3
%rtti.TypeDescriptor2 = type { i8**, i8*, [3 x i8] }
%eh.CatchHandlerType = type { i32, i8* }
$"\01??_R0H@8" = comdat any
@"\01??_7type_info@@6B@" = external constant i8*
@"\01??_R0H@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".H\00" }, comdat
@llvm.eh.handlertype.H.0 = private unnamed_addr constant %eh.CatchHandlerType { i32 0, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*) }, section "llvm.metadata"
; Function Attrs: uwtable
define void @sink_alloca_to_catch() #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
entry:
%0 = alloca i32
%only_used_in_catch = alloca i32, align 4
invoke void @may_throw()
to label %try.cont unwind label %lpad
lpad: ; preds = %entry
%1 = landingpad { i8*, i32 }
catch %eh.CatchHandlerType* @llvm.eh.handlertype.H.0
%2 = extractvalue { i8*, i32 } %1, 1
%3 = tail call i32 @llvm.eh.typeid.for(i8* bitcast (%eh.CatchHandlerType* @llvm.eh.handlertype.H.0 to i8*)) #3
%matches = icmp eq i32 %2, %3
br i1 %matches, label %catch, label %eh.resume
catch: ; preds = %lpad
%4 = extractvalue { i8*, i32 } %1, 0
call void @llvm.eh.begincatch(i8* %4, i8* null) #3
store volatile i32 42, i32* %only_used_in_catch, align 4
tail call void @llvm.eh.endcatch() #3
br label %try.cont
try.cont: ; preds = %entry, %catch
ret void
eh.resume: ; preds = %lpad
resume { i8*, i32 } %1
}
; CHECK-LABEL: define void @sink_alloca_to_catch()
; CHECK: call void (...) @llvm.localescape(i32* %only_used_in_catch)
declare void @use_catch_var(i32*) #1
; Function Attrs: uwtable
define void @dont_sink_alloca_to_catch(i32 %n) #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
entry:
%0 = alloca i32
%n.addr = alloca i32, align 4
%live_in_out_catch = alloca i32, align 4
%exn.slot = alloca i8*
%ehselector.slot = alloca i32
store i32 %n, i32* %n.addr, align 4
br label %while.cond
while.cond: ; preds = %try.cont, %entry
%1 = load i32, i32* %n.addr, align 4
%cmp = icmp sgt i32 %1, 0
br i1 %cmp, label %while.body, label %while.end
while.body: ; preds = %while.cond
invoke void @may_throw()
to label %invoke.cont unwind label %lpad
invoke.cont: ; preds = %while.body
br label %try.cont
lpad: ; preds = %while.body
%2 = landingpad { i8*, i32 }
catch i8* bitcast (%eh.CatchHandlerType* @llvm.eh.handlertype.H.0 to i8*)
%3 = extractvalue { i8*, i32 } %2, 0
store i8* %3, i8** %exn.slot
%4 = extractvalue { i8*, i32 } %2, 1
store i32 %4, i32* %ehselector.slot
br label %catch.dispatch
catch.dispatch: ; preds = %lpad
%sel = load i32, i32* %ehselector.slot
%5 = call i32 @llvm.eh.typeid.for(i8* bitcast (%eh.CatchHandlerType* @llvm.eh.handlertype.H.0 to i8*)) #3
%matches = icmp eq i32 %sel, %5
br i1 %matches, label %catch, label %eh.resume
catch: ; preds = %catch.dispatch
%exn = load i8*, i8** %exn.slot
call void @llvm.eh.begincatch(i8* %exn, i8* null) #3
invoke void @use_catch_var(i32* %live_in_out_catch)
to label %invoke.cont2 unwind label %lpad1
invoke.cont2: ; preds = %catch
call void @llvm.eh.endcatch() #3
br label %try.cont
try.cont: ; preds = %invoke.cont2, %invoke.cont
%6 = load i32, i32* %0
%7 = load i32, i32* %n.addr, align 4
%dec = add nsw i32 %7, -1
store i32 %dec, i32* %n.addr, align 4
br label %while.cond
lpad1: ; preds = %catch
%8 = landingpad { i8*, i32 }
cleanup
%9 = extractvalue { i8*, i32 } %8, 0
store i8* %9, i8** %exn.slot
%10 = extractvalue { i8*, i32 } %8, 1
store i32 %10, i32* %ehselector.slot
call void @llvm.eh.endcatch() #3
br label %eh.resume
while.end: ; preds = %while.cond
ret void
eh.resume: ; preds = %lpad1, %catch.dispatch
%exn3 = load i8*, i8** %exn.slot
%sel4 = load i32, i32* %ehselector.slot
%lpad.val = insertvalue { i8*, i32 } undef, i8* %exn3, 0
%lpad.val5 = insertvalue { i8*, i32 } %lpad.val, i32 %sel4, 1
resume { i8*, i32 } %lpad.val5
}
; CHECK-LABEL: define void @dont_sink_alloca_to_catch(i32 %n)
; CHECK: call void (...) @llvm.localescape(i32* %live_in_out_catch)
; CHECK-LABEL: define internal i8* @sink_alloca_to_catch.catch(i8*, i8*)
; CHECK: %only_used_in_catch.i8 = call i8* @llvm.localrecover({{.*}}, i32 0)
; CHECK: %only_used_in_catch = bitcast
; CHECK-LABEL: define internal i8* @dont_sink_alloca_to_catch.catch(i8*, i8*)
; CHECK: %live_in_out_catch.i8 = call i8* @llvm.localrecover({{.*}}, i32 0)
; CHECK: %live_in_out_catch = bitcast
attributes #0 = { uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #2 = { nounwind readnone }
attributes #3 = { nounwind }

View File

@ -1,86 +0,0 @@
; RUN: opt -winehprepare -S -o - < %s | FileCheck %s
; This test is based on the following code:
;
; extern "C" void may_throw();
; extern "C" void handle_exception();
; extern "C" void test() {
; try {
; may_throw();
; } catch (...) {
; handle_exception();
; }
; }
target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32"
target triple = "i686-pc-windows-msvc"
; The function entry in this case remains unchanged.
; CHECK: define void @test()
; CHECK: entry:
; CHECK: invoke void @may_throw()
; CHECK: to label %invoke.cont unwind label %[[LPAD_LABEL:lpad[0-9]*]]
define void @test() #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
entry:
%exn.slot = alloca i8*
%ehselector.slot = alloca i32
invoke void @may_throw()
to label %invoke.cont unwind label %lpad
invoke.cont: ; preds = %entry
br label %try.cont
; CHECK: [[LPAD_LABEL]]:{{[ ]+}}; preds = %entry
; CHECK: landingpad { i8*, i32 }
; CHECK-NEXT: catch i8* null
; CHECK-NEXT: [[RECOVER:\%.+]] = call i8* (...) @llvm.eh.actions(i32 1, i8* null, i32 -1, i8* ()* @test.catch)
; CHECK-NEXT: indirectbr i8* [[RECOVER]], [label %try.cont]
lpad: ; preds = %entry
%0 = landingpad { i8*, i32 }
catch i8* null
%1 = extractvalue { i8*, i32 } %0, 0
store i8* %1, i8** %exn.slot
%2 = extractvalue { i8*, i32 } %0, 1
store i32 %2, i32* %ehselector.slot
br label %catch
; CHECK-NOT: catch:
; CHECK-NOT: @handle_exception()
catch: ; preds = %lpad
%exn = load i8*, i8** %exn.slot
call void @llvm.eh.begincatch(i8* %exn, i8* null) #1
call void @handle_exception()
call void @llvm.eh.endcatch() #1
br label %try.cont
try.cont: ; preds = %catch, %invoke.cont
ret void
; CHECK: }
}
; CHECK: define internal i8* @test.catch()
; CHECK: call i8* @llvm.frameaddress(i32 1)
; CHECK: call i8* @llvm.x86.seh.recoverfp(i8* bitcast (void ()* @test to i8*), i8* %{{.*}})
; CHECK: call void @handle_exception()
; CHECK: ret i8* blockaddress(@test, %try.cont)
; CHECK: }
declare void @may_throw() #0
declare i32 @__CxxFrameHandler3(...)
; Function Attrs: nounwind
declare void @llvm.eh.begincatch(i8* nocapture, i8* nocapture) #1
declare void @handle_exception() #0
; Function Attrs: nounwind
declare void @llvm.eh.endcatch() #1
attributes #0 = { "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { nounwind }

View File

@ -1,143 +0,0 @@
; RUN: opt -mtriple=x86_64-pc-windows-msvc -winehprepare -S -o - < %s | FileCheck %s
; This test is based on the following code:
;
; class Obj {
; public:
; ~Obj();
; };
;
; void test(void)
; {
; try {
; Obj o;
; throw 1;
; } catch (...) {
; throw;
; }
; }
; ModuleID = 'cppeh-catch-and-throw.cpp'
target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-windows-msvc"
%rtti.TypeDescriptor2 = type { i8**, i8*, [3 x i8] }
%eh.CatchableType = type { i32, i32, i32, i32, i32, i32, i32 }
%eh.CatchableTypeArray.1 = type { i32, [1 x i32] }
%eh.ThrowInfo = type { i32, i32, i32, i32 }
%class.Obj = type { i8 }
$"\01??_R0H@8" = comdat any
$"_CT??_R0H@84" = comdat any
$_CTA1H = comdat any
$_TI1H = comdat any
@"\01??_7type_info@@6B@" = external constant i8*
@"\01??_R0H@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".H\00" }, comdat
@__ImageBase = external constant i8
@"_CT??_R0H@84" = linkonce_odr unnamed_addr constant %eh.CatchableType { i32 1, i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32), i32 0, i32 -1, i32 0, i32 4, i32 0 }, section ".xdata", comdat
@_CTA1H = linkonce_odr unnamed_addr constant %eh.CatchableTypeArray.1 { i32 1, [1 x i32] [i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%eh.CatchableType* @"_CT??_R0H@84" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32)] }, section ".xdata", comdat
@_TI1H = linkonce_odr unnamed_addr constant %eh.ThrowInfo { i32 0, i32 0, i32 0, i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%eh.CatchableTypeArray.1* @_CTA1H to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32) }, section ".xdata", comdat
; This is just a minimal check to verify that main was handled by WinEHPrepare.
; CHECK: define void @"\01?test@@YAXXZ"()
; CHECK: entry:
; CHECK: call void (...) @llvm.localescape
; CHECK: invoke void @_CxxThrowException
; CHECK: }
; Function Attrs: uwtable
define void @"\01?test@@YAXXZ"() #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
entry:
%o = alloca %class.Obj, align 1
%tmp = alloca i32, align 4
%exn.slot = alloca i8*
%ehselector.slot = alloca i32
store i32 1, i32* %tmp
%0 = bitcast i32* %tmp to i8*
invoke void @_CxxThrowException(i8* %0, %eh.ThrowInfo* @_TI1H) #3
to label %unreachable unwind label %lpad
lpad: ; preds = %entry
%1 = landingpad { i8*, i32 }
catch i8* null
%2 = extractvalue { i8*, i32 } %1, 0
store i8* %2, i8** %exn.slot
%3 = extractvalue { i8*, i32 } %1, 1
store i32 %3, i32* %ehselector.slot
call void @"\01??1Obj@@QEAA@XZ"(%class.Obj* %o) #2
br label %catch
catch: ; preds = %lpad
%exn = load i8*, i8** %exn.slot
call void @llvm.eh.begincatch(i8* %exn, i8* null) #2
invoke void @_CxxThrowException(i8* null, %eh.ThrowInfo* null) #3
to label %unreachable unwind label %lpad1
lpad1: ; preds = %catch
%4 = landingpad { i8*, i32 }
cleanup
%5 = extractvalue { i8*, i32 } %4, 0
store i8* %5, i8** %exn.slot
%6 = extractvalue { i8*, i32 } %4, 1
store i32 %6, i32* %ehselector.slot
call void @llvm.eh.endcatch() #2
br label %eh.resume
try.cont: ; No predecessors!
ret void
eh.resume: ; preds = %lpad1
%exn2 = load i8*, i8** %exn.slot
%sel = load i32, i32* %ehselector.slot
%lpad.val = insertvalue { i8*, i32 } undef, i8* %exn2, 0
%lpad.val3 = insertvalue { i8*, i32 } %lpad.val, i32 %sel, 1
resume { i8*, i32 } %lpad.val3
unreachable: ; preds = %catch, %entry
unreachable
}
; Verify that we inserted a stub invoke into the outlined cleanup handler.
;
; CHECK-LABEL: define internal void @"\01?test@@YAXXZ.cleanup"(i8*, i8*)
; CHECK: entry:
; CHECK: call i8* @llvm.localrecover
; CHECK: call void @"\01??1Obj@@QEAA@XZ"
; CHECK: invoke void @llvm.donothing()
; CHECK: to label %[[SPLIT_LABEL:.+]] unwind label %[[LPAD_LABEL:.+]]
;
; CHECK: [[SPLIT_LABEL]]
;
; CHECK: [[LPAD_LABEL]]
; CHECK: landingpad { i8*, i32 }
; CHECK: cleanup
; CHECK: unreachable
; CHECK: }
declare void @_CxxThrowException(i8*, %eh.ThrowInfo*)
declare i32 @__CxxFrameHandler3(...)
; Function Attrs: nounwind
declare void @"\01??1Obj@@QEAA@XZ"(%class.Obj*) #1
; Function Attrs: nounwind
declare void @llvm.eh.begincatch(i8* nocapture, i8* nocapture) #2
; Function Attrs: nounwind
declare void @llvm.eh.endcatch() #2
attributes #0 = { uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #2 = { nounwind }
attributes #3 = { noreturn }
!llvm.module.flags = !{!0}
!llvm.ident = !{!1}
!0 = !{i32 1, !"PIC Level", i32 2}
!1 = !{!"clang version 3.7.0 (trunk 235214) (llvm/trunk 235213)"}

View File

@ -1,126 +0,0 @@
; RUN: opt -mtriple=x86_64-pc-windows-msvc -winehprepare -S -o - < %s | FileCheck %s
; This test is based on the following code:
;
; void test()
; {
; try {
; may_throw();
; } catch (int i) {
; handle_int(i);
; }
; }
;
; Parts of the IR have been hand-edited to simplify the test case.
; The full IR will be restored when Windows C++ EH support is complete.
;ModuleID = 'cppeh-catch-scalar.cpp'
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-windows-msvc"
@_ZTIi = external constant i8*
; The function entry will be rewritten like this.
; CHECK: define void @_Z4testv()
; CHECK: entry:
; CHECK: [[I_PTR:\%.+]] = alloca i32, align 4
; CHECK: call void (...) @llvm.localescape(i32* [[I_PTR]])
; CHECK: invoke void @_Z9may_throwv()
; CHECK: to label %invoke.cont unwind label %[[LPAD_LABEL:lpad[0-9]*]]
; Function Attrs: uwtable
define void @_Z4testv() #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
entry:
%exn.slot = alloca i8*
%ehselector.slot = alloca i32
%i = alloca i32, align 4
invoke void @_Z9may_throwv()
to label %invoke.cont unwind label %lpad
invoke.cont: ; preds = %entry
br label %try.cont
; CHECK: [[LPAD_LABEL]]:{{[ ]+}}; preds = %entry
; CHECK: landingpad { i8*, i32 }
; CHECK-NEXT: catch i8* bitcast (i8** @_ZTIi to i8*)
; CHECK-NEXT: [[RECOVER:\%.+]] = call i8* (...) @llvm.eh.actions(i32 1, i8* bitcast (i8** @_ZTIi to i8*), i32 0, i8* (i8*, i8*)* @_Z4testv.catch)
; CHECK-NEXT: indirectbr i8* [[RECOVER]], [label %try.cont]
lpad: ; preds = %entry
%tmp = landingpad { i8*, i32 }
catch i8* bitcast (i8** @_ZTIi to i8*)
%tmp1 = extractvalue { i8*, i32 } %tmp, 0
store i8* %tmp1, i8** %exn.slot
%tmp2 = extractvalue { i8*, i32 } %tmp, 1
store i32 %tmp2, i32* %ehselector.slot
br label %catch.dispatch
; CHECK-NOT: catch-dispatch:
catch.dispatch: ; preds = %lpad
%sel = load i32, i32* %ehselector.slot
%tmp3 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*)) #3
%matches = icmp eq i32 %sel, %tmp3
br i1 %matches, label %catch, label %eh.resume
; CHECK-NOT: catch:
catch: ; preds = %catch.dispatch
%exn11 = load i8*, i8** %exn.slot
%i.i8 = bitcast i32* %i to i8*
call void @llvm.eh.begincatch(i8* %exn11, i8* %i.i8) #3
%tmp7 = load i32, i32* %i, align 4
call void @_Z10handle_inti(i32 %tmp7)
br label %invoke.cont2
; CHECK-NOT: invoke.cont2:
invoke.cont2: ; preds = %catch
call void @llvm.eh.endcatch() #3
br label %try.cont
try.cont: ; preds = %invoke.cont2, %invoke.cont
ret void
; CHECK-NOT: eh.resume:
eh.resume: ; preds = %catch.dispatch
%exn3 = load i8*, i8** %exn.slot
%sel4 = load i32, i32* %ehselector.slot
%lpad.val = insertvalue { i8*, i32 } undef, i8* %exn3, 0
%lpad.val5 = insertvalue { i8*, i32 } %lpad.val, i32 %sel4, 1
resume { i8*, i32 } %lpad.val5
; CHECK: }
}
; CHECK: define internal i8* @_Z4testv.catch(i8*, i8*)
; CHECK: entry:
; CHECK: [[RECOVER_I:\%.+]] = call i8* @llvm.localrecover(i8* bitcast (void ()* @_Z4testv to i8*), i8* %1, i32 0)
; CHECK: [[I_PTR1:\%.+]] = bitcast i8* [[RECOVER_I]] to i32*
; CHECK: [[TMP:\%.+]] = load i32, i32* [[I_PTR1]], align 4
; CHECK: call void @_Z10handle_inti(i32 [[TMP]])
; CHECK: ret i8* blockaddress(@_Z4testv, %try.cont)
; CHECK: }
declare void @_Z9may_throwv() #1
declare i32 @__CxxFrameHandler3(...)
; Function Attrs: nounwind readnone
declare i32 @llvm.eh.typeid.for(i8*) #2
declare void @llvm.eh.begincatch(i8*, i8*)
declare void @llvm.eh.endcatch()
declare void @_Z10handle_inti(i32) #1
attributes #0 = { uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #2 = { nounwind readnone }
attributes #3 = { nounwind }
!llvm.ident = !{!0}
!0 = !{!"clang version 3.7.0 (trunk 227474) (llvm/trunk 227508)"}

View File

@ -1,240 +0,0 @@
; RUN: opt -mtriple=x86_64-pc-windows-msvc -winehprepare -S -o - < %s | FileCheck %s
; This test was generated from the following source:
;
; void test() {
; try {
; SomeClass obj;
; may_throw();
; try {
; may_throw();
; } catch (int) {
; handle_exception();
; }
; } catch (int) {
; handle_exception();
; }
; }
;
; The code above was compiled with the -O2 option.
; ModuleID = 'catch-unwind.cpp'
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-windows-msvc"
%rtti.TypeDescriptor2 = type { i8**, i8*, [3 x i8] }
%class.SomeClass = type { i8 }
$"\01??_R0H@8" = comdat any
@"\01??_7type_info@@6B@" = external constant i8*
@"\01??_R0H@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".H\00" }, comdat
; CHECK-LABEL: define void @"\01?test@@YAXXZ"() #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
; CHECK: entry:
; CHECK: [[OBJ_PTR:\%.+]] = alloca %class.SomeClass
; CHECK: [[TMP0:\%.+]] = alloca i32, align 4
; CHECK: [[TMP1:\%.+]] = alloca i32, align 4
; CHECK: call void (...) @llvm.localescape(i32* [[TMP1]], %class.SomeClass* [[OBJ_PTR]], i32* [[TMP0]])
; CHECK: %call = invoke %class.SomeClass* @"\01??0SomeClass@@QEAA@XZ"(%class.SomeClass* %obj)
; CHECK: to label %invoke.cont unwind label %[[LPAD_LABEL:lpad[0-9]*]]
; Function Attrs: uwtable
define void @"\01?test@@YAXXZ"() #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
entry:
%obj = alloca %class.SomeClass, align 1
%0 = alloca i32, align 4
%1 = alloca i32, align 4
%call = invoke %class.SomeClass* @"\01??0SomeClass@@QEAA@XZ"(%class.SomeClass* %obj)
to label %invoke.cont unwind label %lpad
; CHECK: invoke.cont:
; CHECK: invoke void @"\01?may_throw@@YAXXZ"()
; CHECK: to label %invoke.cont2 unwind label %[[LPAD1_LABEL:lpad[0-9]*]]
invoke.cont: ; preds = %entry
invoke void @"\01?may_throw@@YAXXZ"()
to label %invoke.cont2 unwind label %lpad1
; CHECK: invoke.cont2:
; CHECK: invoke void @"\01?may_throw@@YAXXZ"()
; CHECK: to label %try.cont unwind label %[[LPAD3_LABEL:lpad[0-9]*]]
invoke.cont2: ; preds = %invoke.cont
invoke void @"\01?may_throw@@YAXXZ"()
to label %try.cont unwind label %lpad3
; CHECK: [[LPAD_LABEL]]:{{[ ]+}}; preds = %entry
; CHECK: [[LPAD_VAL:\%.+]] = landingpad { i8*, i32 }
; CHECK-NEXT: catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*)
; CHECK-NEXT: [[RECOVER:\%.+]] = call i8* (...) @llvm.eh.actions(i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*), i32 0, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch")
; CHECK-NEXT: indirectbr i8* [[RECOVER]], [label %try.cont15]
lpad: ; preds = %entry
%2 = landingpad { i8*, i32 }
catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*)
%3 = extractvalue { i8*, i32 } %2, 0
%4 = extractvalue { i8*, i32 } %2, 1
br label %catch.dispatch7
; CHECK: [[LPAD1_LABEL]]:{{[ ]+}}; preds = %invoke.cont
; CHECK: [[LPAD1_VAL:\%.+]] = landingpad { i8*, i32 }
; CHECK-NEXT: cleanup
; CHECK-NEXT: catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*)
; CHECK-NEXT: [[RECOVER1:\%.+]] = call i8* (...) @llvm.eh.actions(i32 0, void (i8*, i8*)* @"\01?test@@YAXXZ.cleanup", i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*), i32 0, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch")
; CHECK-NEXT: indirectbr i8* [[RECOVER1]], [label %try.cont15]
lpad1: ; preds = %invoke.cont
%5 = landingpad { i8*, i32 }
cleanup
catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*)
%6 = extractvalue { i8*, i32 } %5, 0
%7 = extractvalue { i8*, i32 } %5, 1
br label %ehcleanup
; CHECK: [[LPAD3_LABEL]]:{{[ ]+}}; preds = %invoke.cont2
; CHECK: [[LPAD3_VAL:\%.+]] = landingpad { i8*, i32 }
; CHECK-NEXT: cleanup
; CHECK-NEXT: catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*)
; CHECK-NEXT: [[RECOVER3:\%.+]] = call i8* (...) @llvm.eh.actions(i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*), i32 2, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch.1", i32 0, void (i8*, i8*)* @"\01?test@@YAXXZ.cleanup")
; CHECK-NEXT: indirectbr i8* [[RECOVER3]], [label %try.cont, label %try.cont15]
lpad3: ; preds = %invoke.cont2
%8 = landingpad { i8*, i32 }
cleanup
catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*)
%9 = extractvalue { i8*, i32 } %8, 0
%10 = extractvalue { i8*, i32 } %8, 1
%11 = call i32 @llvm.eh.typeid.for(i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*)) #3
%matches = icmp eq i32 %10, %11
br i1 %matches, label %catch, label %ehcleanup
; CHECK-NOT: catch:
catch: ; preds = %lpad3
%12 = bitcast i32* %0 to i8*
call void @llvm.eh.begincatch(i8* %9, i8* %12) #3
invoke void @"\01?handle_exception@@YAXXZ"()
to label %invoke.cont6 unwind label %lpad5
; CHECK-NOT: invoke.cont6:
invoke.cont6: ; preds = %catch
call void @llvm.eh.endcatch() #3
br label %try.cont
try.cont: ; preds = %invoke.cont2, %invoke.cont6
call void @"\01??1SomeClass@@QEAA@XZ"(%class.SomeClass* %obj) #3
br label %try.cont15
; CHECK-NOT: lpad5:
lpad5: ; preds = %catch
%13 = landingpad { i8*, i32 }
cleanup
catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*)
%14 = extractvalue { i8*, i32 } %13, 0
%15 = extractvalue { i8*, i32 } %13, 1
call void @llvm.eh.endcatch() #3
br label %ehcleanup
; CHECK-NOT: ehcleanup
ehcleanup: ; preds = %lpad5, %lpad3, %lpad1
%exn.slot.0 = phi i8* [ %14, %lpad5 ], [ %9, %lpad3 ], [ %6, %lpad1 ]
%ehselector.slot.0 = phi i32 [ %15, %lpad5 ], [ %10, %lpad3 ], [ %7, %lpad1 ]
call void @"\01??1SomeClass@@QEAA@XZ"(%class.SomeClass* %obj) #3
br label %catch.dispatch7
; CHECK-NOT: catch.dispatch7:
catch.dispatch7: ; preds = %ehcleanup, %lpad
%exn.slot.1 = phi i8* [ %exn.slot.0, %ehcleanup ], [ %3, %lpad ]
%ehselector.slot.1 = phi i32 [ %ehselector.slot.0, %ehcleanup ], [ %4, %lpad ]
%16 = call i32 @llvm.eh.typeid.for(i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*)) #3
%matches9 = icmp eq i32 %ehselector.slot.1, %16
br i1 %matches9, label %catch10, label %eh.resume
; CHECK-NOT: catch10:
catch10: ; preds = %catch.dispatch7
%17 = bitcast i32* %1 to i8*
call void @llvm.eh.begincatch(i8* %exn.slot.1, i8* %17) #3
call void @"\01?handle_exception@@YAXXZ"()
br label %invoke.cont13
; CHECK-NOT: invoke.cont13:
invoke.cont13: ; preds = %catch10
call void @llvm.eh.endcatch() #3
br label %try.cont15
try.cont15: ; preds = %invoke.cont13, %try.cont
ret void
; CHECK-NOT: eh.resume
eh.resume: ; preds = %catch.dispatch7
%lpad.val = insertvalue { i8*, i32 } undef, i8* %exn.slot.1, 0
%lpad.val18 = insertvalue { i8*, i32 } %lpad.val, i32 %ehselector.slot.1, 1
resume { i8*, i32 } %lpad.val18
; CHECK: }
}
; CHECK-LABEL: define internal i8* @"\01?test@@YAXXZ.catch"(i8*, i8*)
; CHECK: entry:
; CHECK: [[RECOVER_TMP1:\%.+]] = call i8* @llvm.localrecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 0)
; CHECK: [[TMP1_PTR:\%.+]] = bitcast i8* [[RECOVER_TMP1]] to i32*
; CHECK: call void @"\01?handle_exception@@YAXXZ"()
; CHECK: ret i8* blockaddress(@"\01?test@@YAXXZ", %try.cont15)
; CHECK: }
; CHECK-LABEL: define internal void @"\01?test@@YAXXZ.cleanup"(i8*, i8*)
; CHECK: entry:
; CHECK: [[RECOVER_OBJ:\%.+]] = call i8* @llvm.localrecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 1)
; CHECK: [[OBJ_PTR:\%.+]] = bitcast i8* %obj.i8 to %class.SomeClass*
; CHECK: call void @"\01??1SomeClass@@QEAA@XZ"(%class.SomeClass* [[OBJ_PTR]])
; CHECK: ret void
; CHECK: }
; CHECK-LABEL: define internal i8* @"\01?test@@YAXXZ.catch.1"(i8*, i8*)
; CHECK: entry:
; CHECK: [[RECOVER_TMP0:\%.+]] = call i8* @llvm.localrecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 2)
; CHECK: [[TMP0_PTR:\%.+]] = bitcast i8* [[RECOVER_TMP0]] to i32*
; CHECK: invoke void @"\01?handle_exception@@YAXXZ"()
; CHECK: to label %invoke.cont6 unwind label %[[LPAD5_LABEL:lpad[0-9]+]]
;
; CHECK: invoke.cont6: ; preds = %entry
; CHECK: ret i8* blockaddress(@"\01?test@@YAXXZ", %try.cont)
;
; CHECK: [[LPAD5_LABEL]]:{{[ ]+}}; preds = %entry
; CHECK: [[LPAD5_VAL:\%.+]] = landingpad { i8*, i32 }
; CHECK: cleanup
; CHECK: catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*)
; CHECK: }
declare %class.SomeClass* @"\01??0SomeClass@@QEAA@XZ"(%class.SomeClass* returned) #1
declare i32 @__CxxFrameHandler3(...)
declare void @"\01?may_throw@@YAXXZ"() #1
; Function Attrs: nounwind readnone
declare i32 @llvm.eh.typeid.for(i8*) #2
; Function Attrs: nounwind
declare void @llvm.eh.begincatch(i8* nocapture, i8* nocapture) #3
declare void @"\01?handle_exception@@YAXXZ"() #1
; Function Attrs: nounwind
declare void @llvm.eh.endcatch() #3
; Function Attrs: nounwind
declare void @"\01??1SomeClass@@QEAA@XZ"(%class.SomeClass*) #4
attributes #0 = { uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #2 = { nounwind readnone }
attributes #3 = { nounwind }
attributes #4 = { nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
!llvm.module.flags = !{!0}
!llvm.ident = !{!1}
!0 = !{i32 1, !"PIC Level", i32 2}
!1 = !{!"clang version 3.7.0 (trunk 232069) (llvm/trunk 232070)"}

View File

@ -1,91 +0,0 @@
; RUN: opt -winehprepare -S < %s | FileCheck %s
target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-windows-msvc"
; Modified based on this code:
; struct HasDtor {
; ~HasDtor();
; };
; extern "C" void may_throw();
; int main() {
; try {
; HasDtor o;
; may_throw();
; } catch (int) {
; }
; }
%rtti.TypeDescriptor2 = type { i8**, i8*, [3 x i8] }
%eh.CatchHandlerType = type { i32, i8* }
%struct.HasDtor = type { i8 }
$"\01??_R0H@8" = comdat any
@"\01??_7type_info@@6B@" = external constant i8*
@"\01??_R0H@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".H\00" }, comdat
@llvm.eh.handlertype.H.0 = private unnamed_addr constant %eh.CatchHandlerType { i32 0, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*) }, section "llvm.metadata"
define i32 @main() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
entry:
%o = alloca %struct.HasDtor, align 1
invoke void @may_throw()
to label %invoke.cont2 unwind label %lpad1
invoke.cont2: ; preds = %invoke.cont
call void @"\01??1HasDtor@@QEAA@XZ"(%struct.HasDtor* %o)
br label %try.cont
lpad: ; preds = %entry
%0 = landingpad { i8*, i32 }
catch %eh.CatchHandlerType* @llvm.eh.handlertype.H.0
%1 = extractvalue { i8*, i32 } %0, 0
%2 = extractvalue { i8*, i32 } %0, 1
br label %catch.dispatch
lpad1: ; preds = %invoke.cont
%3 = landingpad { i8*, i32 }
cleanup
catch %eh.CatchHandlerType* @llvm.eh.handlertype.H.0
%4 = extractvalue { i8*, i32 } %3, 0
%5 = extractvalue { i8*, i32 } %3, 1
invoke void @"\01??1HasDtor@@QEAA@XZ"(%struct.HasDtor* %o)
to label %catch.dispatch unwind label %lpad
catch.dispatch: ; preds = %lpad1, %lpad
%exn.slot.0 = phi i8* [ %4, %lpad1 ], [ %1, %lpad ]
%ehselector.slot.0 = phi i32 [ %5, %lpad1 ], [ %2, %lpad ]
%6 = call i32 @llvm.eh.typeid.for(i8* bitcast (%eh.CatchHandlerType* @llvm.eh.handlertype.H.0 to i8*))
%matches = icmp eq i32 %ehselector.slot.0, %6
br i1 %matches, label %catch, label %eh.resume
catch: ; preds = %catch.dispatch
call void @llvm.eh.begincatch(i8* %exn.slot.0, i8* null)
call void @llvm.eh.endcatch()
br label %try.cont
try.cont: ; preds = %catch, %invoke.cont2
ret i32 0
eh.resume: ; preds = %catch.dispatch
%lpad.val = insertvalue { i8*, i32 } undef, i8* %exn.slot.0, 0
%lpad.val5 = insertvalue { i8*, i32 } %lpad.val, i32 %ehselector.slot.0, 1
resume { i8*, i32 } %lpad.val5
}
; CHECK-LABEL: define i32 @main()
; CHECK: @llvm.eh.actions(i32 0, void (i8*, i8*)* @main.cleanup, i32 1, i8* bitcast (%eh.CatchHandlerType* @llvm.eh.handlertype.H.0 to i8*), i32 -1, i8* (i8*, i8*)* @main.catch)
; CHECK-LABEL: define internal void @main.cleanup(i8*, i8*)
; CHECK: call void @"\01??1HasDtor@@QEAA@XZ"(%struct.HasDtor* %{{.*}})
; CHECK: ret void
declare void @may_throw()
declare i32 @__CxxFrameHandler3(...)
declare void @"\01??1HasDtor@@QEAA@XZ"(%struct.HasDtor*)
declare i32 @llvm.eh.typeid.for(i8*)
declare void @llvm.eh.begincatch(i8* nocapture, i8* nocapture)
declare void @llvm.eh.endcatch()

View File

@ -1,72 +0,0 @@
; RUN: opt -mtriple=x86_64-pc-windows-msvc -winehprepare -S < %s | FileCheck %s
; Notionally based on this C++ source:
; int liveout_catch(int p) {
; int val = p + 1;
; try {
; might_throw();
; } catch (int) {
; val++;
; }
; return val;
; }
declare void @llvm.eh.begincatch(i8*, i8*)
declare void @llvm.eh.endcatch()
declare void @might_throw()
declare i32 @__CxxFrameHandler3(...)
declare i32 @llvm.eh.typeid.for(i8*)
@typeinfo.int = external global i32
define i32 @liveout_catch(i32 %p) personality i32 (...)* @__CxxFrameHandler3 {
entry:
%val.entry = add i32 %p, 1
invoke void @might_throw()
to label %ret unwind label %lpad
lpad:
%ehvals = landingpad { i8*, i32 }
cleanup
catch i32* @typeinfo.int
%ehptr = extractvalue { i8*, i32 } %ehvals, 0
%sel = extractvalue { i8*, i32 } %ehvals, 1
%int_sel = call i32 @llvm.eh.typeid.for(i8* bitcast (i32* @typeinfo.int to i8*))
%match = icmp eq i32 %sel, %int_sel
br i1 %match, label %catchit, label %resume
catchit:
call void @llvm.eh.begincatch(i8* %ehptr, i8* null)
%val.lpad = add i32 %val.entry, 1
call void @llvm.eh.endcatch()
br label %ret
ret:
%rv = phi i32 [%val.entry, %entry], [%val.lpad, %catchit]
ret i32 %rv
resume:
resume {i8*, i32} %ehvals
}
; CHECK-LABEL: define i32 @liveout_catch(i32 %p)
; CHECK: %val.entry = add i32 %p, 1
; CHECK-NEXT: store i32 %val.entry, i32* %val.entry.reg2mem
; CHECK: invoke void @might_throw()
;
; CHECK: landingpad
; CHECK: indirectbr i8* {{.*}}, [label %catchit.split]
;
; CHECK: catchit.split:
; CHECK: load i32, i32* %val.lpad.reg2mem
; CHECK: br label %ret
;
; CHECK: ret:
; CHECK: %rv = phi i32 [ {{.*}}, %entry ], [ {{.*}}, %catchit.split ]
; CHECK: ret i32
; CHECK-LABEL: define internal i8* @liveout_catch.catch(i8*, i8*)
; CHECK: %[[val:[^ ]*]] = load i32, i32*
; CHECK-NEXT: %[[val_lpad:[^ ]*]] = add i32 %[[val]], 1
; CHECK-NEXT: store i32 %[[val_lpad]], i32*
; CHECK: ret i8* blockaddress(@liveout_catch, %catchit.split)

View File

@ -1,272 +0,0 @@
; RUN: opt -mtriple=x86_64-pc-windows-msvc -winehprepare -S -o - < %s | FileCheck %s
; This test is based on the following code:
;
; struct SomeData {
; int a;
; int b;
; };
;
; void may_throw();
; void does_not_throw(int i);
; void dump(int *, int, SomeData&);
;
; void test() {
; int NumExceptions = 0;
; int ExceptionVal[10];
; SomeData Data = { 0, 0 };
;
; for (int i = 0; i < 10; ++i) {
; try {
; may_throw();
; Data.a += i;
; }
; catch (int e) {
; ExceptionVal[NumExceptions] = e;
; ++NumExceptions;
; if (e == i)
; Data.b += e;
; else
; Data.a += e;
; }
; does_not_throw(NumExceptions);
; }
; dump(ExceptionVal, NumExceptions, Data);
; }
; ModuleID = 'cppeh-frame-vars.cpp'
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-windows-msvc"
%rtti.TypeDescriptor2 = type { i8**, i8*, [3 x i8] }
%struct.SomeData = type { i32, i32 }
$"\01??_R0H@8" = comdat any
@"\01??_7type_info@@6B@" = external constant i8*
@"\01??_R0H@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".H\00" }, comdat
; The function entry should be rewritten like this.
; CHECK: define void @"\01?test@@YAXXZ"()
; CHECK: entry:
; CHECK: [[NUMEXCEPTIONS_PTR:\%.+]] = alloca i32, align 4
; CHECK: [[EXCEPTIONVAL_PTR:\%.+]] = alloca [10 x i32], align 16
; CHECK: [[DATA_PTR:\%.+]] = alloca %struct.SomeData, align 4
; CHECK: [[I_PTR:\%.+]] = alloca i32, align 4
; CHECK: [[E_PTR:\%.+]] = alloca i32, align 4
; CHECK: store i32 0, i32* [[NUMEXCEPTIONS_PTR]], align 4
; CHECK: [[TMP:\%.+]] = bitcast %struct.SomeData* [[DATA_PTR]] to i8*
; CHECK: call void @llvm.memset(i8* [[TMP]], i8 0, i64 8, i32 4, i1 false)
; CHECK: store i32 0, i32* [[I_PTR]], align 4
; CHECK: call void (...) @llvm.localescape(i32* [[E_PTR]], i32* [[NUMEXCEPTIONS_PTR]], [10 x i32]* [[EXCEPTIONVAL_PTR]], i32* [[I_PTR]], %struct.SomeData* [[DATA_PTR]])
; CHECK: br label %for.cond
; Function Attrs: uwtable
define void @"\01?test@@YAXXZ"() #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
entry:
%NumExceptions = alloca i32, align 4
%ExceptionVal = alloca [10 x i32], align 16
%Data = alloca %struct.SomeData, align 4
%i = alloca i32, align 4
%exn.slot = alloca i8*
%ehselector.slot = alloca i32
%e = alloca i32, align 4
store i32 0, i32* %NumExceptions, align 4
%tmp = bitcast %struct.SomeData* %Data to i8*
call void @llvm.memset(i8* %tmp, i8 0, i64 8, i32 4, i1 false)
store i32 0, i32* %i, align 4
br label %for.cond
for.cond: ; preds = %for.inc, %entry
%tmp1 = load i32, i32* %i, align 4
%cmp = icmp slt i32 %tmp1, 10
br i1 %cmp, label %for.body, label %for.end
; CHECK: for.body:
; CHECK: invoke void @"\01?may_throw@@YAXXZ"()
; CHECK: to label %invoke.cont unwind label %[[LPAD_LABEL:lpad[0-9]*]]
for.body: ; preds = %for.cond
invoke void @"\01?may_throw@@YAXXZ"()
to label %invoke.cont unwind label %lpad
invoke.cont: ; preds = %for.body
%tmp2 = load i32, i32* %i, align 4
%a = getelementptr inbounds %struct.SomeData, %struct.SomeData* %Data, i32 0, i32 0
%tmp3 = load i32, i32* %a, align 4
%add = add nsw i32 %tmp3, %tmp2
store i32 %add, i32* %a, align 4
br label %try.cont
; CHECK: [[LPAD_LABEL]]:{{[ ]+}}; preds = %for.body
; CHECK: landingpad { i8*, i32 }
; CHECK-NEXT: catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*)
; CHECK-NEXT: [[RECOVER:\%.+]] = call i8* (...) @llvm.eh.actions(i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*), i32 0, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch")
; CHECK-NEXT: indirectbr i8* [[RECOVER]], [label %try.cont]
lpad: ; preds = %for.body
%tmp4 = landingpad { i8*, i32 }
catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*)
%tmp5 = extractvalue { i8*, i32 } %tmp4, 0
store i8* %tmp5, i8** %exn.slot
%tmp6 = extractvalue { i8*, i32 } %tmp4, 1
store i32 %tmp6, i32* %ehselector.slot
br label %catch.dispatch
; CHECK-NOT: catch.dispatch:
catch.dispatch: ; preds = %lpad
%sel = load i32, i32* %ehselector.slot
%tmp7 = call i32 @llvm.eh.typeid.for(i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*)) #1
%matches = icmp eq i32 %sel, %tmp7
br i1 %matches, label %catch, label %eh.resume
; CHECK-NOT: catch:
catch: ; preds = %catch.dispatch
%exn = load i8*, i8** %exn.slot
%e.i8 = bitcast i32* %e to i8*
call void @llvm.eh.begincatch(i8* %exn, i8* %e.i8) #1
%tmp11 = load i32, i32* %e, align 4
%tmp12 = load i32, i32* %NumExceptions, align 4
%idxprom = sext i32 %tmp12 to i64
%arrayidx = getelementptr inbounds [10 x i32], [10 x i32]* %ExceptionVal, i32 0, i64 %idxprom
store i32 %tmp11, i32* %arrayidx, align 4
%tmp13 = load i32, i32* %NumExceptions, align 4
%inc = add nsw i32 %tmp13, 1
store i32 %inc, i32* %NumExceptions, align 4
%tmp14 = load i32, i32* %e, align 4
%tmp15 = load i32, i32* %i, align 4
%cmp1 = icmp eq i32 %tmp14, %tmp15
br i1 %cmp1, label %if.then, label %if.else
; CHECK-NOT: if.then:
if.then: ; preds = %catch
%tmp16 = load i32, i32* %e, align 4
%b = getelementptr inbounds %struct.SomeData, %struct.SomeData* %Data, i32 0, i32 1
%tmp17 = load i32, i32* %b, align 4
%add2 = add nsw i32 %tmp17, %tmp16
store i32 %add2, i32* %b, align 4
br label %if.end
; CHECK-NOT: if.else:
if.else: ; preds = %catch
%tmp18 = load i32, i32* %e, align 4
%a3 = getelementptr inbounds %struct.SomeData, %struct.SomeData* %Data, i32 0, i32 0
%tmp19 = load i32, i32* %a3, align 4
%add4 = add nsw i32 %tmp19, %tmp18
store i32 %add4, i32* %a3, align 4
br label %if.end
; CHECK-NOT: if.end:
if.end: ; preds = %if.else, %if.then
call void @llvm.eh.endcatch() #1
br label %try.cont
try.cont: ; preds = %if.end, %invoke.cont
%tmp20 = load i32, i32* %NumExceptions, align 4
call void @"\01?does_not_throw@@YAXH@Z"(i32 %tmp20)
br label %for.inc
for.inc: ; preds = %try.cont
%tmp21 = load i32, i32* %i, align 4
%inc5 = add nsw i32 %tmp21, 1
store i32 %inc5, i32* %i, align 4
br label %for.cond
for.end: ; preds = %for.cond
%tmp22 = load i32, i32* %NumExceptions, align 4
%arraydecay = getelementptr inbounds [10 x i32], [10 x i32]* %ExceptionVal, i32 0, i32 0
call void @"\01?dump@@YAXPEAHHAEAUSomeData@@@Z"(i32* %arraydecay, i32 %tmp22, %struct.SomeData* dereferenceable(8) %Data)
ret void
; CHECK-NOT: eh.resume:
eh.resume: ; preds = %catch.dispatch
%exn6 = load i8*, i8** %exn.slot
%sel7 = load i32, i32* %ehselector.slot
%lpad.val = insertvalue { i8*, i32 } undef, i8* %exn6, 0
%lpad.val8 = insertvalue { i8*, i32 } %lpad.val, i32 %sel7, 1
resume { i8*, i32 } %lpad.val8
; CHECK: }
}
; The following catch handler should be outlined.
; CHECK-LABEL: define internal i8* @"\01?test@@YAXXZ.catch"(i8*, i8*)
; CHECK: entry:
; CHECK: [[RECOVER_E:\%.+]] = call i8* @llvm.localrecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 0)
; CHECK: [[E_PTR1:\%.+]] = bitcast i8* [[RECOVER_E]] to i32*
; CHECK: [[RECOVER_NUMEXCEPTIONS:\%.+]] = call i8* @llvm.localrecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 1)
; CHECK: [[NUMEXCEPTIONS_PTR1:\%.+]] = bitcast i8* [[RECOVER_NUMEXCEPTIONS]] to i32*
; CHECK: [[RECOVER_EXCEPTIONVAL:\%.+]] = call i8* @llvm.localrecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 2)
; CHECK: [[EXCEPTIONVAL_PTR1:\%.+]] = bitcast i8* [[RECOVER_EXCEPTIONVAL]] to [10 x i32]*
; CHECK: [[RECOVER_I:\%.+]] = call i8* @llvm.localrecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 3)
; CHECK: [[I_PTR1:\%.+]] = bitcast i8* [[RECOVER_I]] to i32*
; CHECK: [[RECOVER_DATA:\%.+]] = call i8* @llvm.localrecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 4)
; CHECK: [[DATA_PTR1:\%.+]] = bitcast i8* [[RECOVER_DATA]] to %struct.SomeData*
; CHECK: [[TMP:\%.+]] = load i32, i32* [[E_PTR1]], align 4
; CHECK: [[TMP1:\%.+]] = load i32, i32* [[NUMEXCEPTIONS_PTR]], align 4
; CHECK: [[IDXPROM:\%.+]] = sext i32 [[TMP1]] to i64
; CHECK: [[ARRAYIDX:\%.+]] = getelementptr inbounds [10 x i32], [10 x i32]* [[EXCEPTIONVAL_PTR1]], i32 0, i64 [[IDXPROM]]
; CHECK: store i32 [[TMP]], i32* [[ARRAYIDX]], align 4
; CHECK: [[TMP2:\%.+]] = load i32, i32* [[NUMEXCEPTIONS_PTR1]], align 4
; CHECK: [[INC:\%.+]] = add nsw i32 [[TMP2]], 1
; CHECK: store i32 [[INC]], i32* [[NUMEXCEPTIONS_PTR]], align 4
; CHECK: [[TMP3:\%.+]] = load i32, i32* [[E_PTR1]], align 4
; CHECK: [[TMP4:\%.+]] = load i32, i32* [[I_PTR1]], align 4
; CHECK: [[CMP:\%.+]] = icmp eq i32 [[TMP3]], [[TMP4]]
; CHECK: br i1 [[CMP]], label %if.then, label %if.else
;
; CHECK: if.then: ; preds = %entry
; CHECK: [[TMP5:\%.+]] = load i32, i32* [[E_PTR1]], align 4
; CHECK: [[B_PTR:\%.+]] = getelementptr inbounds %struct.SomeData, %struct.SomeData* [[DATA_PTR1]], i32 0, i32 1
; CHECK: [[TMP6:\%.+]] = load i32, i32* [[B_PTR]], align 4
; CHECK: %add2 = add nsw i32 [[TMP6]], [[TMP5]]
; CHECK: store i32 [[ADD:\%.+]], i32* [[B_PTR]], align 4
; CHECK: br label %if.end
;
; CHECK: if.else: ; preds = %entry
; CHECK: [[TMP7:\%.+]] = load i32, i32* %e, align 4
; CHECK: [[A3:\%.+]] = getelementptr inbounds %struct.SomeData, %struct.SomeData* %Data, i32 0, i32 0
; CHECK: [[TMP8:\%.+]] = load i32, i32* %a3, align 4
; CHECK: [[ADD1:\%.+]] = add nsw i32 [[TMP8]], [[TMP7]]
; CHECK: store i32 [[ADD1]], i32* [[A3]], align 4
; CHECK: br label %if.end
;
; CHECK: if.end: ; preds = %if.else, %if.then
; CHECK: ret i8* blockaddress(@"\01?test@@YAXXZ", %try.cont)
; CHECK: }
; Function Attrs: nounwind
declare void @llvm.memset(i8* nocapture, i8, i64, i32, i1) #1
declare void @"\01?may_throw@@YAXXZ"() #2
declare i32 @__CxxFrameHandler3(...)
; Function Attrs: nounwind readnone
declare i32 @llvm.eh.typeid.for(i8*) #3
declare void @llvm.eh.begincatch(i8*, i8*)
declare void @llvm.eh.endcatch()
declare void @"\01?does_not_throw@@YAXH@Z"(i32) #2
declare void @"\01?dump@@YAXPEAHHAEAUSomeData@@@Z"(i32*, i32, %struct.SomeData* dereferenceable(8)) #2
attributes #0 = { uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { nounwind }
attributes #2 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #3 = { nounwind readnone }
!llvm.module.flags = !{!0}
!llvm.ident = !{!1}
!0 = !{i32 1, !"PIC Level", i32 2}
!1 = !{!"clang version 3.7.0 (trunk 228868)"}

View File

@ -1,194 +0,0 @@
; RUN: opt -mtriple=x86_64-pc-windows-msvc -winehprepare -S -o - < %s | FileCheck %s
; This test is built from the following code:
; struct A {
; A(int a);
; A(const A &o);
; ~A();
; int a;
; };
;
; void may_throw();
;
; int test(A a) {
; try {
; may_throw();
; }
; catch (int e) {
; return a.a + e;
; }
; return 0;
; }
;
; The test was built for a 32-bit Windows target and then the reference to
; the inalloca instruction was manually sunk into the landingpad.
; ModuleID = 'cppeh-inalloca.cpp'
%rtti.TypeDescriptor2 = type { i8**, i8*, [3 x i8] }
%struct.A = type { i32 }
$"\01??_R0H@8" = comdat any
@"\01??_7type_info@@6B@" = external constant i8*
@"\01??_R0H@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".H\00" }, comdat
; The function entry should be rewritten like this.
; CHECK: define i32 @"\01?test@@YAHUA@@@Z"(<{ %struct.A }>* inalloca)
; CHECK: entry:
; CHECK: [[TMP_REGMEM:\%.+]] = alloca <{ %struct.A }>*
; CHECK: store <{ %struct.A }>* %0, <{ %struct.A }>** [[TMP_REGMEM]]
; CHECK: [[RETVAL:\%.+]] = alloca i32, align 4
; CHECK: [[E_PTR:\%.+]] = alloca i32, align 4
; CHECK: [[CLEANUP_SLOT:\%.+]] = alloca i32
; CHECK: call void (...) @llvm.localescape(i32* %e, <{ %struct.A }>** [[TMP_REGMEM]], i32* [[RETVAL]], i32* [[CLEANUP_SLOT]])
; CHECK: invoke void @"\01?may_throw@@YAXXZ"()
; CHECK: to label %invoke.cont unwind label %[[LPAD_LABEL:lpad[0-9]*]]
define i32 @"\01?test@@YAHUA@@@Z"(<{ %struct.A }>* inalloca) #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
entry:
%retval = alloca i32, align 4
%exn.slot = alloca i8*
%ehselector.slot = alloca i32
%e = alloca i32, align 4
%cleanup.dest.slot = alloca i32
invoke void @"\01?may_throw@@YAXXZ"()
to label %invoke.cont unwind label %lpad
invoke.cont: ; preds = %entry
br label %try.cont
; CHECK: [[LPAD_LABEL]]:{{[ ]+}}; preds = %entry
; CHECK: landingpad { i8*, i32 }
; CHECK-NEXT: cleanup
; CHECK-NEXT: catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*)
; CHECK-NEXT: [[RECOVER:\%recover.*]] = call i8* (...) @llvm.eh.actions(i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*), i32 0, i8* (i8*, i8*)* @"\01?test@@YAHUA@@@Z.catch", i32 0, void (i8*, i8*)* @"\01?test@@YAHUA@@@Z.cleanup")
; CHECK-NEXT: indirectbr i8* [[RECOVER]], [label %cleanup]
lpad: ; preds = %entry
%1 = landingpad { i8*, i32 }
cleanup
catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*)
%2 = extractvalue { i8*, i32 } %1, 0
store i8* %2, i8** %exn.slot
%3 = extractvalue { i8*, i32 } %1, 1
store i32 %3, i32* %ehselector.slot
br label %catch.dispatch
; CHECK-NOT: catch.dispatch:
catch.dispatch: ; preds = %lpad
%sel = load i32, i32* %ehselector.slot
%4 = call i32 @llvm.eh.typeid.for(i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*)) #3
%matches = icmp eq i32 %sel, %4
br i1 %matches, label %catch, label %ehcleanup
; CHECK-NOT: catch:
catch: ; preds = %catch.dispatch
%exn = load i8*, i8** %exn.slot
%e.i8 = bitcast i32* %e to i8*
call void @llvm.eh.begincatch(i8* %exn, i8* %e.i8) #3
%a = getelementptr inbounds <{ %struct.A }>, <{ %struct.A }>* %0, i32 0, i32 0
%a1 = getelementptr inbounds %struct.A, %struct.A* %a, i32 0, i32 0
%tmp8 = load i32, i32* %a1, align 4
%tmp9 = load i32, i32* %e, align 4
%add = add nsw i32 %tmp8, %tmp9
store i32 %add, i32* %retval
store i32 1, i32* %cleanup.dest.slot
call void @llvm.eh.endcatch() #3
br label %cleanup
try.cont: ; preds = %invoke.cont
store i32 0, i32* %retval
store i32 1, i32* %cleanup.dest.slot
br label %cleanup
; The cleanup block should be re-written like this.
; CHECK: cleanup:{{[ ]+}}; preds = %[[LPAD_LABEL]], %try.cont
; CHECK: %a2 = getelementptr inbounds <{ %struct.A }>, <{ %struct.A }>* %0, i32 0, i32 0
; CHECK: call x86_thiscallcc void @"\01??1A@@QAE@XZ"(%struct.A* %a2)
; CHECK: [[TMP1:\%.+]] = load i32, i32* [[RETVAL]]
; CHECK: ret i32 [[TMP1]]
cleanup: ; preds = %try.cont, %catch
%a2 = getelementptr inbounds <{ %struct.A }>, <{ %struct.A }>* %0, i32 0, i32 0
call x86_thiscallcc void @"\01??1A@@QAE@XZ"(%struct.A* %a2) #3
%tmp10 = load i32, i32* %retval
ret i32 %tmp10
; CHECK-NOT: ehcleanup:
ehcleanup: ; preds = %catch.dispatch
%a3 = getelementptr inbounds <{ %struct.A }>, <{ %struct.A }>* %0, i32 0, i32 0
call x86_thiscallcc void @"\01??1A@@QAE@XZ"(%struct.A* %a3) #3
br label %eh.resume
; CHECK-NOT: eh.resume:
eh.resume: ; preds = %ehcleanup
%exn2 = load i8*, i8** %exn.slot
%sel3 = load i32, i32* %ehselector.slot
%lpad.val = insertvalue { i8*, i32 } undef, i8* %exn2, 0
%lpad.val4 = insertvalue { i8*, i32 } %lpad.val, i32 %sel3, 1
resume { i8*, i32 } %lpad.val4
; CHECK: }
}
; The following catch handler should be outlined.
; CHECK: define internal i8* @"\01?test@@YAHUA@@@Z.catch"(i8*, i8*)
; CHECK: entry:
; CHECK: [[RECOVER_E:\%.+]] = call i8* @llvm.localrecover(i8* bitcast (i32 (<{ %struct.A }>*)* @"\01?test@@YAHUA@@@Z" to i8*), i8* %1, i32 0)
; CHECK: [[E_PTR:\%.+]] = bitcast i8* [[RECOVER_E]] to i32*
; CHECK: [[RECOVER_EH_TEMP:\%.+]] = call i8* @llvm.localrecover(i8* bitcast (i32 (<{ %struct.A }>*)* @"\01?test@@YAHUA@@@Z" to i8*), i8* %1, i32 1)
; CHECK: [[EH_TEMP:\%.+]] = bitcast i8* [[RECOVER_EH_TEMP]] to <{ %struct.A }>**
; CHECK: [[RECOVER_RETVAL:\%.+]] = call i8* @llvm.localrecover(i8* bitcast (i32 (<{ %struct.A }>*)* @"\01?test@@YAHUA@@@Z" to i8*), i8* %1, i32 2)
; CHECK: [[RETVAL1:\%.+]] = bitcast i8* [[RECOVER_RETVAL]] to i32*
; CHECK: [[RECOVER_CLEANUPSLOT:\%.+]] = call i8* @llvm.localrecover(i8* bitcast (i32 (<{ %struct.A }>*)* @"\01?test@@YAHUA@@@Z" to i8*), i8* %1, i32 3)
; CHECK: [[CLEANUPSLOT1:\%.+]] = bitcast i8* [[RECOVER_CLEANUPSLOT]] to i32*
; CHECK: [[E_I8PTR:\%.+]] = bitcast i32* [[E_PTR]] to i8*
; CHECK: [[TMP_RELOAD:\%.+]] = load <{ %struct.A }>*, <{ %struct.A }>** [[EH_TEMP]]
; CHECK: [[RECOVER_A:\%.+]] = getelementptr inbounds <{ %struct.A }>, <{ %struct.A }>* [[TMP_RELOAD]], i32 0, i32 0
; CHECK: [[A1:\%.+]] = getelementptr inbounds %struct.A, %struct.A* [[RECOVER_A]], i32 0, i32 0
; CHECK: [[TMP2:\%.+]] = load i32, i32* [[A1]], align 4
; CHECK: [[TMP3:\%.+]] = load i32, i32* [[E_PTR]], align 4
; CHECK: [[ADD:\%.+]] = add nsw i32 [[TMP2]], [[TMP3]]
; CHECK: store i32 [[ADD]], i32* [[RETVAL1]]
; CHECK: store i32 1, i32* [[CLEANUPSLOT1]]
; CHECK: ret i8* blockaddress(@"\01?test@@YAHUA@@@Z", %cleanup)
; CHECK: }
; The following cleanup handler should be outlined.
; CHECK: define internal void @"\01?test@@YAHUA@@@Z.cleanup"(i8*, i8*)
; CHECK: entry:
; CHECK: [[RECOVER_EH_TEMP1:\%.+]] = call i8* @llvm.localrecover(i8* bitcast (i32 (<{ %struct.A }>*)* @"\01?test@@YAHUA@@@Z" to i8*), i8* %1, i32 1)
; CHECK: [[EH_TEMP1:\%.+]] = bitcast i8* [[RECOVER_EH_TEMP]] to <{ %struct.A }>**
; CHECK: [[TMP_RELOAD1:\%.+]] = load <{ %struct.A }>*, <{ %struct.A }>** [[EH_TEMP1]]
; CHECK: [[A3:\%.+]] = getelementptr inbounds <{ %struct.A }>, <{ %struct.A }>* [[TMP_RELOAD1]], i32 0, i32 0
; CHECK: call x86_thiscallcc void @"\01??1A@@QAE@XZ"(%struct.A* [[A3]])
; CHECK: ret void
; CHECK: }
declare void @"\01?may_throw@@YAXXZ"() #0
declare i32 @__CxxFrameHandler3(...)
; Function Attrs: nounwind readnone
declare i32 @llvm.eh.typeid.for(i8*) #1
declare void @llvm.eh.begincatch(i8*, i8*)
declare void @llvm.eh.endcatch()
; Function Attrs: nounwind
declare x86_thiscallcc void @"\01??1A@@QAE@XZ"(%struct.A*) #2
attributes #0 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { nounwind readnone }
attributes #2 = { nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #3 = { nounwind }
!llvm.ident = !{!0}
!0 = !{!"clang version 3.7.0 (trunk 228868)"}

View File

@ -1,99 +0,0 @@
; RUN: opt -mtriple=x86_64-pc-windows-msvc -winehprepare -S -o - < %s | FileCheck %s
; This test was generated from the following source:
;
; class SomeClass {
; public:
; SomeClass();
; ~SomeClass();
; };
;
; void test() {
; SomeClass obj;
; may_throw();
; }
; ModuleID = 'min-unwind.cpp'
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-windows-msvc"
%class.SomeClass = type { [28 x i32] }
; The function entry should be rewritten like this.
; CHECK: define void @_Z4testv()
; CHECK: entry:
; CHECK: [[OBJ_PTR:\%.+]] = alloca %class.SomeClass, align 4
; CHECK: call void @_ZN9SomeClassC1Ev(%class.SomeClass* [[OBJ_PTR]])
; CHECK: call void (...) @llvm.localescape(%class.SomeClass* [[OBJ_PTR]])
; CHECK: invoke void @_Z9may_throwv()
; CHECK: to label %invoke.cont unwind label %[[LPAD_LABEL:lpad[0-9]*]]
; Function Attrs: uwtable
define void @_Z4testv() #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
entry:
%obj = alloca %class.SomeClass, align 4
%exn.slot = alloca i8*
%ehselector.slot = alloca i32
call void @_ZN9SomeClassC1Ev(%class.SomeClass* %obj)
invoke void @_Z9may_throwv()
to label %invoke.cont unwind label %lpad
invoke.cont: ; preds = %entry
call void @_ZN9SomeClassD1Ev(%class.SomeClass* %obj)
ret void
; CHECK: [[LPAD_LABEL]]:{{[ ]+}}; preds = %entry
; CHECK: landingpad { i8*, i32 }
; CHECK-NEXT: cleanup
; CHECK-NEXT: [[RECOVER:\%.+]] = call i8* (...) @llvm.eh.actions(i32 0, void (i8*, i8*)* @_Z4testv.cleanup)
; CHECK-NEXT: indirectbr i8* [[RECOVER]], []
lpad: ; preds = %entry
%tmp = landingpad { i8*, i32 }
cleanup
%tmp1 = extractvalue { i8*, i32 } %tmp, 0
store i8* %tmp1, i8** %exn.slot
%tmp2 = extractvalue { i8*, i32 } %tmp, 1
store i32 %tmp2, i32* %ehselector.slot
call void @_ZN9SomeClassD1Ev(%class.SomeClass* %obj)
br label %eh.resume
; CHECK-NOT: eh.resume:
eh.resume: ; preds = %lpad
%exn = load i8*, i8** %exn.slot
%sel = load i32, i32* %ehselector.slot
%lpad.val = insertvalue { i8*, i32 } undef, i8* %exn, 0
%lpad.val2 = insertvalue { i8*, i32 } %lpad.val, i32 %sel, 1
resume { i8*, i32 } %lpad.val2
; CHECK: }
}
; This cleanup handler should be outlined.
; CHECK: define internal void @_Z4testv.cleanup(i8*, i8*)
; CHECK: entry:
; CHECK: [[RECOVER_OBJ:\%.+]] = call i8* @llvm.localrecover(i8* bitcast (void ()* @_Z4testv to i8*), i8* %1, i32 0)
; CHECK: [[OBJ_PTR1:\%.+]] = bitcast i8* [[RECOVER_OBJ]] to %class.SomeClass*
; CHECK: call void @_ZN9SomeClassD1Ev(%class.SomeClass* [[OBJ_PTR1]])
; CHECK: ret void
; CHECK: }
declare void @_ZN9SomeClassC1Ev(%class.SomeClass*) #1
declare void @_Z9may_throwv() #1
declare i32 @__CxxFrameHandler3(...)
declare void @_ZN9SomeClassD1Ev(%class.SomeClass*) #1
attributes #0 = { uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #2 = { noinline noreturn nounwind }
attributes #3 = { noreturn nounwind }
attributes #4 = { nounwind }
!llvm.ident = !{!0}
!0 = !{!"clang version 3.7.0 (trunk 226027)"}

View File

@ -1,106 +0,0 @@
; RUN: opt -mtriple=x86_64-pc-windows-msvc -winehprepare -S -o - < %s | FileCheck %s
; This test is based on the following code:
;
; void test()
; {
; try {
; Obj o;
; may_throw();
; } catch (...) {
; }
; }
;
; The purpose of this test is to verify that we create separate catch and
; cleanup handlers. When compiling for the C++ 11 standard, this isn't
; strictly necessary, since calling the destructor from the catch handler
; would be logically equivalent to calling it from a cleanup handler.
; However, if the -std=c++98 option is used, an exception in the cleanup
; code should terminate the process (the MSVCRT runtime will do that) but
; if the destructor is called from the catch handler, it wouldn't terminate
; the process
; ModuleID = 'cppeh-mixed-catch-and-cleanup.cpp'
target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-windows-msvc"
%class.Obj = type { i8 }
; This just verifies that the function was processed by WinEHPrepare.
;
; CHECK-LABEL: define void @"\01?test@@YAXXZ"()
; CHECK: entry:
; CHECK: call void (...) @llvm.localescape
; CHECK: }
; Function Attrs: nounwind uwtable
define void @"\01?test@@YAXXZ"() #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
entry:
%o = alloca %class.Obj, align 1
%exn.slot = alloca i8*
%ehselector.slot = alloca i32
invoke void @"\01?may_throw@@YAXXZ"()
to label %invoke.cont unwind label %lpad
invoke.cont: ; preds = %entry
call void @"\01??1Obj@@QEAA@XZ"(%class.Obj* %o) #3
br label %try.cont
lpad: ; preds = %entry
%0 = landingpad { i8*, i32 }
catch i8* null
%1 = extractvalue { i8*, i32 } %0, 0
store i8* %1, i8** %exn.slot
%2 = extractvalue { i8*, i32 } %0, 1
store i32 %2, i32* %ehselector.slot
call void @"\01??1Obj@@QEAA@XZ"(%class.Obj* %o) #3
%exn = load i8*, i8** %exn.slot
call void @llvm.eh.begincatch(i8* %exn, i8* null) #3
call void @llvm.eh.endcatch() #3
br label %try.cont
try.cont: ; preds = %catch, %invoke.cont
ret void
}
; Verify that a cleanup handler was created and that it calls ~Obj().
; CHECK-LABEL: define internal void @"\01?test@@YAXXZ.cleanup"(i8*, i8*)
; CHECK: entry:
; CHECK: @llvm.localrecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 0)
; CHECK: call void @"\01??1Obj@@QEAA@XZ"
; CHECK: ret void
; CHECK: }
; Verify that a catch handler was created and that it does not call ~Obj().
; CHECK-LABEL: define internal i8* @"\01?test@@YAXXZ.catch"(i8*, i8*)
; CHECK: entry:
; CHECK-NOT: call void @"\01??1Obj@@QEAA@XZ"
; CHECK: ret i8* blockaddress(@"\01?test@@YAXXZ", %try.cont)
; CHECK: }
declare void @"\01?may_throw@@YAXXZ"() #1
declare i32 @__CxxFrameHandler3(...)
; Function Attrs: nounwind
declare void @"\01??1Obj@@QEAA@XZ"(%class.Obj*) #2
; Function Attrs: nounwind
declare void @llvm.eh.begincatch(i8* nocapture, i8* nocapture) #3
; Function Attrs: nounwind
declare void @llvm.eh.endcatch() #3
attributes #0 = { nounwind uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #2 = { nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #3 = { nounwind }
!llvm.module.flags = !{!0}
!llvm.ident = !{!1}
!0 = !{i32 1, !"PIC Level", i32 2}
!1 = !{!"clang version 3.7.0 (trunk 235779) (llvm/trunk 235769)"}

View File

@ -1,226 +0,0 @@
; RUN: opt -mtriple=x86_64-pc-windows-msvc -winehprepare -S -o - < %s | FileCheck %s
; This test is based on the following code:
;
; void test()
; {
; try {
; may_throw();
; } catch (int i) {
; handle_int(i);
; } catch (long long ll) {
; handle_long_long(ll);
; } catch (SomeClass &obj) {
; handle_obj(&obj);
; } catch (...) {
; handle_exception();
; }
; }
;
; The catch handlers were edited to insert 'ret void' after the endcatch call.
; ModuleID = 'catch-with-type.cpp'
target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-windows-msvc"
%rtti.TypeDescriptor2 = type { i8**, i8*, [3 x i8] }
%eh.HandlerMapEntry = type { i32, i32 }
%rtti.TypeDescriptor3 = type { i8**, i8*, [4 x i8] }
%rtti.TypeDescriptor15 = type { i8**, i8*, [16 x i8] }
%class.SomeClass = type { i8 }
$"\01??_R0H@8" = comdat any
$"\01??_R0_J@8" = comdat any
$"\01??_R0?AVSomeClass@@@8" = comdat any
@"\01??_7type_info@@6B@" = external constant i8*
@"\01??_R0H@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".H\00" }, comdat
@__ImageBase = external constant i8
@llvm.eh.handlermapentry.H = private unnamed_addr constant %eh.HandlerMapEntry { i32 0, i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32) }, section "llvm.metadata"
@"\01??_R0_J@8" = linkonce_odr global %rtti.TypeDescriptor3 { i8** @"\01??_7type_info@@6B@", i8* null, [4 x i8] c"._J\00" }, comdat
@llvm.eh.handlermapentry._J = private unnamed_addr constant %eh.HandlerMapEntry { i32 0, i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.TypeDescriptor3* @"\01??_R0_J@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32) }, section "llvm.metadata"
@"\01??_R0?AVSomeClass@@@8" = linkonce_odr global %rtti.TypeDescriptor15 { i8** @"\01??_7type_info@@6B@", i8* null, [16 x i8] c".?AVSomeClass@@\00" }, comdat
@"llvm.eh.handlermapentry.reference.?AVSomeClass@@" = private unnamed_addr constant %eh.HandlerMapEntry { i32 8, i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.TypeDescriptor15* @"\01??_R0?AVSomeClass@@@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32) }, section "llvm.metadata"
; CHECK: define void @"\01?test@@YAXXZ"() #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
; CHECK: entry:
; CHECK: [[OBJ_PTR:\%.+]] = alloca %class.SomeClass*, align 8
; CHECK: [[LL_PTR:\%.+]] = alloca i64, align 8
; CHECK: [[I_PTR:\%.+]] = alloca i32, align 4
; CHECK: call void (...) @llvm.localescape(i32* [[I_PTR]], i64* [[LL_PTR]], %class.SomeClass** [[OBJ_PTR]])
; CHECK: invoke void @"\01?may_throw@@YAXXZ"()
; CHECK: to label %invoke.cont unwind label %[[LPAD_LABEL:lpad[0-9]*]]
; Function Attrs: uwtable
define void @"\01?test@@YAXXZ"() #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
entry:
%exn.slot = alloca i8*
%ehselector.slot = alloca i32
%obj = alloca %class.SomeClass*, align 8
%ll = alloca i64, align 8
%i = alloca i32, align 4
invoke void @"\01?may_throw@@YAXXZ"()
to label %invoke.cont unwind label %lpad
invoke.cont: ; preds = %entry
br label %try.cont
; CHECK: [[LPAD_LABEL]]:{{[ ]+}}; preds = %entry
; CHECK: landingpad { i8*, i32 }
; CHECK-NEXT: catch %eh.HandlerMapEntry* @llvm.eh.handlermapentry.H
; CHECK-NEXT: catch %eh.HandlerMapEntry* @llvm.eh.handlermapentry._J
; CHECK-NEXT: catch %eh.HandlerMapEntry* @"llvm.eh.handlermapentry.reference.?AVSomeClass@@"
; CHECK-NEXT: catch i8* null
; CHECK-NEXT: [[RECOVER:\%.+]] = call i8* (...) @llvm.eh.actions(
; CHECK-SAME: i32 1, i8* bitcast (%eh.HandlerMapEntry* @llvm.eh.handlermapentry.H to i8*), i32 0, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch",
; CHECK-SAME: i32 1, i8* bitcast (%eh.HandlerMapEntry* @llvm.eh.handlermapentry._J to i8*), i32 1, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch.1",
; CHECK-SAME: i32 1, i8* bitcast (%eh.HandlerMapEntry* @"llvm.eh.handlermapentry.reference.?AVSomeClass@@" to i8*), i32 2, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch.2",
; CHECK-SAME: i32 1, i8* null, i32 -1, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch.3")
; CHECK-NEXT: indirectbr i8* [[RECOVER]], [label %ret]
lpad: ; preds = %entry
%0 = landingpad { i8*, i32 }
catch %eh.HandlerMapEntry* @llvm.eh.handlermapentry.H
catch %eh.HandlerMapEntry* @llvm.eh.handlermapentry._J
catch %eh.HandlerMapEntry* @"llvm.eh.handlermapentry.reference.?AVSomeClass@@"
catch i8* null
%1 = extractvalue { i8*, i32 } %0, 0
store i8* %1, i8** %exn.slot
%2 = extractvalue { i8*, i32 } %0, 1
store i32 %2, i32* %ehselector.slot
br label %catch.dispatch
; CHECK-NOT: catch.dispatch:
catch.dispatch: ; preds = %lpad
%sel = load i32, i32* %ehselector.slot
%3 = call i32 @llvm.eh.typeid.for(i8* bitcast (%eh.HandlerMapEntry* @llvm.eh.handlermapentry.H to i8*)) #3
%matches = icmp eq i32 %sel, %3
br i1 %matches, label %catch14, label %catch.fallthrough
ret:
ret void
; CHECK-NOT: catch14:
; CHECK: ret:
; CHECK-NEXT: ret void
catch14: ; preds = %catch.dispatch
%exn15 = load i8*, i8** %exn.slot
%4 = bitcast i32* %i to i8*
call void @llvm.eh.begincatch(i8* %exn15, i8* %4) #3
%5 = load i32, i32* %i, align 4
call void @"\01?handle_int@@YAXH@Z"(i32 %5)
call void @llvm.eh.endcatch() #3
br label %ret
try.cont: ; preds = %invoke.cont
br label %ret
; CHECK-NOT: catch.fallthrough:
catch.fallthrough: ; preds = %catch.dispatch
%6 = call i32 @llvm.eh.typeid.for(i8* bitcast (%eh.HandlerMapEntry* @llvm.eh.handlermapentry._J to i8*)) #3
%matches1 = icmp eq i32 %sel, %6
br i1 %matches1, label %catch10, label %catch.fallthrough2
; CHECK-NOT: catch10:
catch10: ; preds = %catch.fallthrough
%exn11 = load i8*, i8** %exn.slot
%7 = bitcast i64* %ll to i8*
call void @llvm.eh.begincatch(i8* %exn11, i8* %7) #3
%8 = load i64, i64* %ll, align 8
call void @"\01?handle_long_long@@YAX_J@Z"(i64 %8)
call void @llvm.eh.endcatch() #3
br label %ret
; CHECK-NOT: catch.fallthrough2:
catch.fallthrough2: ; preds = %catch.fallthrough
%9 = call i32 @llvm.eh.typeid.for(i8* bitcast (%eh.HandlerMapEntry* @"llvm.eh.handlermapentry.reference.?AVSomeClass@@" to i8*)) #3
%matches3 = icmp eq i32 %sel, %9
br i1 %matches3, label %catch6, label %catch
; CHECK-NOT: catch6:
catch6: ; preds = %catch.fallthrough2
%exn7 = load i8*, i8** %exn.slot
%10 = bitcast %class.SomeClass** %obj to i8*
call void @llvm.eh.begincatch(i8* %exn7, i8* %10) #3
%11 = load %class.SomeClass*, %class.SomeClass** %obj, align 8
call void @"\01?handle_obj@@YAXPEAVSomeClass@@@Z"(%class.SomeClass* %11)
call void @llvm.eh.endcatch() #3
br label %ret
; CHECK-NOT: catch:
catch: ; preds = %catch.fallthrough2
%exn = load i8*, i8** %exn.slot
call void @llvm.eh.begincatch(i8* %exn, i8* null) #3
call void @"\01?handle_exception@@YAXXZ"() call void @llvm.eh.endcatch() #3
br label %ret
; CHECK: }
}
; CHECK-LABEL: define internal i8* @"\01?test@@YAXXZ.catch"(i8*, i8*)
; CHECK: entry:
; CHECK: [[RECOVER_I:\%.+]] = call i8* @llvm.localrecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 0)
; CHECK: [[I_PTR:\%.+]] = bitcast i8* [[RECOVER_I]] to i32*
; CHECK: [[TMP1:\%.+]] = load i32, i32* [[I_PTR]], align 4
; CHECK: call void @"\01?handle_int@@YAXH@Z"(i32 [[TMP1]])
; CHECK: ret i8* blockaddress(@"\01?test@@YAXXZ", %ret)
; CHECK: }
; CHECK-LABEL: define internal i8* @"\01?test@@YAXXZ.catch.1"(i8*, i8*)
; CHECK: entry:
; CHECK: [[RECOVER_LL:\%.+]] = call i8* @llvm.localrecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 1)
; CHECK: [[LL_PTR:\%.+]] = bitcast i8* [[RECOVER_LL]] to i64*
; CHECK: [[TMP2:\%.+]] = load i64, i64* [[LL_PTR]], align 8
; CHECK: call void @"\01?handle_long_long@@YAX_J@Z"(i64 [[TMP2]])
; CHECK: ret i8* blockaddress(@"\01?test@@YAXXZ", %ret)
; CHECK: }
; CHECK-LABEL: define internal i8* @"\01?test@@YAXXZ.catch.2"(i8*, i8*)
; CHECK: entry:
; CHECK: [[RECOVER_OBJ:\%.+]] = call i8* @llvm.localrecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 2)
; CHECK: [[OBJ_PTR:\%.+]] = bitcast i8* [[RECOVER_OBJ]] to %class.SomeClass**
; CHECK: [[TMP3:\%.+]] = load %class.SomeClass*, %class.SomeClass** [[OBJ_PTR]], align 8
; CHECK: call void @"\01?handle_obj@@YAXPEAVSomeClass@@@Z"(%class.SomeClass* [[TMP3]])
; CHECK: ret i8* blockaddress(@"\01?test@@YAXXZ", %ret)
; CHECK: }
; CHECK-LABEL: define internal i8* @"\01?test@@YAXXZ.catch.3"(i8*, i8*)
; CHECK: entry:
; CHECK: call void @"\01?handle_exception@@YAXXZ"()
; CHECK: ret i8* blockaddress(@"\01?test@@YAXXZ", %ret)
; CHECK: }
declare void @"\01?may_throw@@YAXXZ"() #1
declare i32 @__CxxFrameHandler3(...)
; Function Attrs: nounwind readnone
declare i32 @llvm.eh.typeid.for(i8*) #2
; Function Attrs: nounwind
declare void @llvm.eh.begincatch(i8* nocapture, i8* nocapture) #3
declare void @"\01?handle_exception@@YAXXZ"() #1
; Function Attrs: nounwind
declare void @llvm.eh.endcatch() #3
declare void @"\01?handle_obj@@YAXPEAVSomeClass@@@Z"(%class.SomeClass*) #1
declare void @"\01?handle_long_long@@YAX_J@Z"(i64) #1
declare void @"\01?handle_int@@YAXH@Z"(i32) #1
attributes #0 = { uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #2 = { nounwind readnone }
attributes #3 = { nounwind }
!llvm.module.flags = !{!0}
!llvm.ident = !{!1}
!0 = !{i32 1, !"PIC Level", i32 2}
!1 = !{!"clang version 3.7.0 (trunk 233155) (llvm/trunk 233153)"}

View File

@ -1,194 +0,0 @@
; RUN: opt -mtriple=x86_64-pc-windows-msvc -winehprepare -S -o - < %s | FileCheck %s
; This test is based on the following code:
;
;void test()
;{
; try {
; try {
; may_throw();
; } catch (int i) {
; handle_int(i);
; }
; } catch (float f) {
; handle_float(f);
; }
; done();
;}
; ModuleID = 'cppeh-nested-1.cpp'
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-windows-msvc"
%rtti.TypeDescriptor2 = type { i8**, i8*, [3 x i8] }
$"\01??_R0M@8" = comdat any
$"\01??_R0H@8" = comdat any
@"\01??_7type_info@@6B@" = external constant i8*
@"\01??_R0M@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".M\00" }, comdat
@"\01??_R0H@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".H\00" }, comdat
; CHECK: define void @"\01?test@@YAXXZ"()
; CHECK: entry:
; CHECK: %i = alloca i32, align 4
; CHECK: %f = alloca float, align 4
; CHECK: call void (...) @llvm.localescape(float* %f, i32* %i)
; CHECK: invoke void @"\01?may_throw@@YAXXZ"()
; CHECK: to label %invoke.cont unwind label %[[LPAD_LABEL:lpad[0-9]*]]
; Function Attrs: uwtable
define void @"\01?test@@YAXXZ"() #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
entry:
%exn.slot = alloca i8*
%ehselector.slot = alloca i32
%i = alloca i32, align 4
%f = alloca float, align 4
invoke void @"\01?may_throw@@YAXXZ"()
to label %invoke.cont unwind label %lpad
invoke.cont: ; preds = %entry
br label %try.cont
; CHECK: [[LPAD_LABEL]]:
; CHECK: landingpad { i8*, i32 }
; CHECK: catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*)
; CHECK: catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0M@8" to i8*)
; CHECK: [[RECOVER:\%.+]] = call i8* (...) @llvm.eh.actions(i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*), i32 1, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch.1", i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0M@8" to i8*), i32 0, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch")
; CHECK: indirectbr i8* [[RECOVER]], [label %try.cont, label %try.cont10]
lpad: ; preds = %entry
%0 = landingpad { i8*, i32 }
catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*)
catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0M@8" to i8*)
%1 = extractvalue { i8*, i32 } %0, 0
store i8* %1, i8** %exn.slot
%2 = extractvalue { i8*, i32 } %0, 1
store i32 %2, i32* %ehselector.slot
br label %catch.dispatch
; CHECK-NOT: catch.dispatch:
catch.dispatch: ; preds = %lpad
%sel = load i32, i32* %ehselector.slot
%3 = call i32 @llvm.eh.typeid.for(i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*)) #3
%matches = icmp eq i32 %sel, %3
br i1 %matches, label %catch, label %catch.dispatch3
; CHECK-NOT: catch:
catch: ; preds = %catch.dispatch
%exn = load i8*, i8** %exn.slot
%4 = bitcast i32* %i to i8*
call void @llvm.eh.begincatch(i8* %exn, i8* %4) #3
%5 = load i32, i32* %i, align 4
invoke void @"\01?handle_int@@YAXH@Z"(i32 %5)
to label %invoke.cont2 unwind label %lpad1
; CHECK-NOT: invoke.cont2:
invoke.cont2: ; preds = %catch
call void @llvm.eh.endcatch() #3
br label %try.cont
try.cont: ; preds = %invoke.cont2, %invoke.cont
br label %try.cont10
; CHECK-NOT: lpad1:
lpad1: ; preds = %catch
%6 = landingpad { i8*, i32 }
catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0M@8" to i8*)
%7 = extractvalue { i8*, i32 } %6, 0
store i8* %7, i8** %exn.slot
%8 = extractvalue { i8*, i32 } %6, 1
store i32 %8, i32* %ehselector.slot
call void @llvm.eh.endcatch() #3
br label %catch.dispatch3
; CHECK-NOT: catch.dispatch3:
catch.dispatch3: ; preds = %lpad1, %catch.dispatch
%sel4 = load i32, i32* %ehselector.slot
%9 = call i32 @llvm.eh.typeid.for(i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0M@8" to i8*)) #3
%matches5 = icmp eq i32 %sel4, %9
br i1 %matches5, label %catch6, label %eh.resume
; CHECK-NOT: catch6:
catch6: ; preds = %catch.dispatch3
%exn7 = load i8*, i8** %exn.slot
%10 = bitcast float* %f to i8*
call void @llvm.eh.begincatch(i8* %exn7, i8* %10) #3
%11 = load float, float* %f, align 4
call void @"\01?handle_float@@YAXM@Z"(float %11)
call void @llvm.eh.endcatch() #3
br label %try.cont10
try.cont10: ; preds = %catch6, %try.cont
call void @"\01?done@@YAXXZ"()
ret void
; CHECK-NOT: eh.resume:
eh.resume: ; %catch.dispatch3
%exn11 = load i8*, i8** %exn.slot
%sel12 = load i32, i32* %ehselector.slot
%lpad.val = insertvalue { i8*, i32 } undef, i8* %exn11, 0
%lpad.val13 = insertvalue { i8*, i32 } %lpad.val, i32 %sel12, 1
resume { i8*, i32 } %lpad.val13
; CHECK: }
}
; CHECK: define internal i8* @"\01?test@@YAXXZ.catch"(i8*, i8*)
; CHECK: entry:
; CHECK: [[RECOVER_F1:\%.+]] = call i8* @llvm.localrecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 0)
; CHECK: [[F_PTR1:\%.+]] = bitcast i8* [[RECOVER_F1]] to float*
; CHECK: [[TMP2:\%.+]] = load float, float* [[F_PTR1]], align 4
; CHECK: call void @"\01?handle_float@@YAXM@Z"(float [[TMP2]])
; CHECK: ret i8* blockaddress(@"\01?test@@YAXXZ", %try.cont10)
; CHECK: }
; CHECK: define internal i8* @"\01?test@@YAXXZ.catch.1"(i8*, i8*)
; CHECK: entry:
; CHECK: [[RECOVER_I:\%.+]] = call i8* @llvm.localrecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 1)
; CHECK: [[I_PTR:\%.+]] = bitcast i8* [[RECOVER_I]] to i32*
; CHECK: [[TMP1:\%.+]] = load i32, i32* [[I_PTR]], align 4
; CHECK: invoke void @"\01?handle_int@@YAXH@Z"(i32 [[TMP1]])
; CHECK: to label %invoke.cont2 unwind label %[[LPAD1_LABEL:lpad[0-9]*]]
;
; CHECK: invoke.cont2:
; CHECK: ret i8* blockaddress(@"\01?test@@YAXXZ", %try.cont)
;
; CHECK: [[LPAD1_LABEL]]:{{[ ]+}}; preds = %entry
; CHECK: [[LPAD1_VAL:\%.+]] = landingpad { i8*, i32 }
; CHECK: catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0M@8" to i8*)
; CHECK: [[RECOVER1:\%.+]] = call i8* (...) @llvm.eh.actions(i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0M@8" to i8*), i32 0, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch")
; CHECK: indirectbr i8* [[RECOVER1]], []
;
; CHECK: }
declare void @"\01?may_throw@@YAXXZ"() #1
declare i32 @__CxxFrameHandler3(...)
; Function Attrs: nounwind readnone
declare i32 @llvm.eh.typeid.for(i8*) #2
; Function Attrs: nounwind
declare void @llvm.eh.begincatch(i8* nocapture, i8* nocapture) #3
declare void @"\01?handle_int@@YAXH@Z"(i32) #1
; Function Attrs: nounwind
declare void @llvm.eh.endcatch() #3
declare void @"\01?handle_float@@YAXM@Z"(float) #1
declare void @"\01?done@@YAXXZ"() #1
attributes #0 = { uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #2 = { nounwind readnone }
attributes #3 = { nounwind }
!llvm.module.flags = !{!0}
!llvm.ident = !{!1}
!0 = !{i32 1, !"PIC Level", i32 2}
!1 = !{!"clang version 3.7.0 (trunk 232069) (llvm/trunk 232070)"}

View File

@ -1,324 +0,0 @@
; RUN: opt -mtriple=x86_64-pc-windows-msvc -winehprepare -S -o - < %s | FileCheck %s
; This test is based on the following code:
;
; class Inner {
; public:
; Inner();
; ~Inner();
; };
; class Outer {
; public:
; Outer();
; ~Outer();
; };
; void test() {
; try {
; Outer outer;
; try {
; Inner inner;
; may_throw();
; } catch (int i) {
; handle_int(i);
; }
; } catch (float f) {
; handle_float(f);
; }
; done();
; }
; ModuleID = 'nested-2.cpp'
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-windows-msvc"
%class.Outer = type { i8 }
%class.Inner = type { i8 }
@_ZTIf = external constant i8*
@_ZTIi = external constant i8*
; The function entry should be rewritten like this.
; CHECK: define void @_Z4testv()
; CHECK: entry:
; CHECK: %outer = alloca %class.Outer, align 1
; CHECK: %inner = alloca %class.Inner, align 1
; CHECK: %i = alloca i32, align 4
; CHECK: %f = alloca float, align 4
; CHECK: call void (...) @llvm.localescape(float* %f, i32* %i, %class.Outer* %outer, %class.Inner* %inner)
; CHECK: invoke void @_ZN5OuterC1Ev(%class.Outer* %outer)
; CHECK: to label %invoke.cont unwind label %[[LPAD_LABEL:lpad[0-9]*]]
; Function Attrs: uwtable
define void @_Z4testv() #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
entry:
%outer = alloca %class.Outer, align 1
%exn.slot = alloca i8*
%ehselector.slot = alloca i32
%inner = alloca %class.Inner, align 1
%i = alloca i32, align 4
%f = alloca float, align 4
invoke void @_ZN5OuterC1Ev(%class.Outer* %outer)
to label %invoke.cont unwind label %lpad
; CHECK: invoke.cont:
; CHECK: invoke void @_ZN5InnerC1Ev(%class.Inner* %inner)
; CHECK: to label %invoke.cont2 unwind label %[[LPAD1_LABEL:lpad[0-9]*]]
invoke.cont: ; preds = %entry
invoke void @_ZN5InnerC1Ev(%class.Inner* %inner)
to label %invoke.cont2 unwind label %lpad1
; CHECK: invoke.cont2:
; CHECK: invoke void @_Z9may_throwv()
; CHECK: to label %invoke.cont4 unwind label %[[LPAD3_LABEL:lpad[0-9]*]]
invoke.cont2: ; preds = %invoke.cont
invoke void @_Z9may_throwv()
to label %invoke.cont4 unwind label %lpad3
; CHECK: invoke.cont4:
; CHECK: invoke void @_ZN5InnerD1Ev(%class.Inner* %inner)
; CHECK: to label %invoke.cont5 unwind label %[[LPAD1_LABEL]]
invoke.cont4: ; preds = %invoke.cont2
invoke void @_ZN5InnerD1Ev(%class.Inner* %inner)
to label %invoke.cont5 unwind label %lpad1
; CHECK: invoke.cont5:
; CHECK: br label %try.cont
invoke.cont5: ; preds = %invoke.cont4
br label %try.cont
; CHECK: [[LPAD_LABEL]]:
; CHECK: landingpad { i8*, i32 }
; CHECK-NEXT: catch i8* bitcast (i8** @_ZTIf to i8*)
; CHECK-NEXT: [[RECOVER:\%.+]] = call i8* (...) @llvm.eh.actions(i32 1, i8* bitcast (i8** @_ZTIf to i8*), i32 0, i8* (i8*, i8*)* @_Z4testv.catch)
; CHECK-NEXT: indirectbr i8* [[RECOVER]], [label %try.cont19]
lpad: ; preds = %try.cont, %entry
%tmp = landingpad { i8*, i32 }
catch i8* bitcast (i8** @_ZTIf to i8*)
%tmp1 = extractvalue { i8*, i32 } %tmp, 0
store i8* %tmp1, i8** %exn.slot
%tmp2 = extractvalue { i8*, i32 } %tmp, 1
store i32 %tmp2, i32* %ehselector.slot
br label %catch.dispatch11
; CHECK: [[LPAD1_LABEL]]:
; CHECK: landingpad { i8*, i32 }
; CHECK-NEXT: cleanup
; CHECK-NEXT: catch i8* bitcast (i8** @_ZTIi to i8*)
; CHECK-NEXT: catch i8* bitcast (i8** @_ZTIf to i8*)
; CHECK-NEXT: [[RECOVER1:\%.+]] = call i8* (...) @llvm.eh.actions(
; CHECK-SAME: i32 1, i8* bitcast (i8** @_ZTIi to i8*), i32 1, i8* (i8*, i8*)* @_Z4testv.catch.1,
; CHECK-SAME: i32 0, void (i8*, i8*)* @_Z4testv.cleanup,
; CHECK-SAME: i32 1, i8* bitcast (i8** @_ZTIf to i8*), i32 0, i8* (i8*, i8*)* @_Z4testv.catch)
; CHECK-NEXT: indirectbr i8* [[RECOVER1]], [label %try.cont, label %try.cont19]
lpad1: ; preds = %invoke.cont4, %invoke.cont
%tmp3 = landingpad { i8*, i32 }
cleanup
catch i8* bitcast (i8** @_ZTIi to i8*)
catch i8* bitcast (i8** @_ZTIf to i8*)
%tmp4 = extractvalue { i8*, i32 } %tmp3, 0
store i8* %tmp4, i8** %exn.slot
%tmp5 = extractvalue { i8*, i32 } %tmp3, 1
store i32 %tmp5, i32* %ehselector.slot
br label %catch.dispatch
; CHECK: [[LPAD3_LABEL]]:
; CHECK: landingpad { i8*, i32 }
; CHECK-NEXT: cleanup
; CHECK-NEXT: catch i8* bitcast (i8** @_ZTIi to i8*)
; CHECK-NEXT: catch i8* bitcast (i8** @_ZTIf to i8*)
; CHECK-NEXT: [[RECOVER3:\%.+]] = call i8* (...) @llvm.eh.actions(
; CHECK-SAME: i32 0, void (i8*, i8*)* @_Z4testv.cleanup.2,
; CHECK-SAME: i32 1, i8* bitcast (i8** @_ZTIi to i8*), i32 1, i8* (i8*, i8*)* @_Z4testv.catch.1,
; CHECK-SAME: i32 0, void (i8*, i8*)* @_Z4testv.cleanup,
; CHECK-SAME: i32 1, i8* bitcast (i8** @_ZTIf to i8*), i32 0, i8* (i8*, i8*)* @_Z4testv.catch)
; CHECK-NEXT: indirectbr i8* [[RECOVER3]], [label %try.cont, label %try.cont19]
lpad3: ; preds = %invoke.cont2
%tmp6 = landingpad { i8*, i32 }
cleanup
catch i8* bitcast (i8** @_ZTIi to i8*)
catch i8* bitcast (i8** @_ZTIf to i8*)
%tmp7 = extractvalue { i8*, i32 } %tmp6, 0
store i8* %tmp7, i8** %exn.slot
%tmp8 = extractvalue { i8*, i32 } %tmp6, 1
store i32 %tmp8, i32* %ehselector.slot
call void @_ZN5InnerD1Ev(%class.Inner* %inner)
br label %catch.dispatch
; CHECK-NOT: catch.dispatch:
catch.dispatch: ; preds = %lpad3, %lpad1
%sel = load i32, i32* %ehselector.slot
%tmp9 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*)) #4
%matches = icmp eq i32 %sel, %tmp9
br i1 %matches, label %catch, label %ehcleanup
; CHECK-NOT: catch:
catch: ; preds = %catch.dispatch
%exn = load i8*, i8** %exn.slot
%i.i8 = bitcast i32* %i to i8*
call void @llvm.eh.begincatch(i8* %exn, i8* %i.i8) #4
%tmp13 = load i32, i32* %i, align 4
invoke void @_Z10handle_inti(i32 %tmp13)
to label %invoke.cont8 unwind label %lpad7
; CHECK-NOT: invoke.cont8:
invoke.cont8: ; preds = %catch
call void @llvm.eh.endcatch() #4
br label %try.cont
; CHECK: try.cont:
; CHECK: invoke void @_ZN5OuterD1Ev(%class.Outer* %outer)
; CHECK: to label %invoke.cont9 unwind label %[[LPAD_LABEL]]
try.cont: ; preds = %invoke.cont8, %invoke.cont5
invoke void @_ZN5OuterD1Ev(%class.Outer* %outer)
to label %invoke.cont9 unwind label %lpad
invoke.cont9: ; preds = %try.cont
br label %try.cont19
; CHECK-NOT: lpad7:
lpad7: ; preds = %catch
%tmp14 = landingpad { i8*, i32 }
cleanup
catch i8* bitcast (i8** @_ZTIf to i8*)
%tmp15 = extractvalue { i8*, i32 } %tmp14, 0
store i8* %tmp15, i8** %exn.slot
%tmp16 = extractvalue { i8*, i32 } %tmp14, 1
store i32 %tmp16, i32* %ehselector.slot
call void @llvm.eh.endcatch() #4
br label %ehcleanup
; CHECK-NOT: ehcleanup: ; preds = %lpad7, %catch.dispatch
ehcleanup: ; preds = %lpad7, %catch.dispatch
call void @_ZN5OuterD1Ev(%class.Outer* %outer)
br label %catch.dispatch11
; CHECK-NOT: catch.dispatch11:
catch.dispatch11: ; preds = %ehcleanup, %lpad
%sel12 = load i32, i32* %ehselector.slot
%tmp17 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIf to i8*)) #4
%matches13 = icmp eq i32 %sel12, %tmp17
br i1 %matches13, label %catch14, label %eh.resume
; CHECK-NOT: catch14:
catch14: ; preds = %catch.dispatch11
%exn15 = load i8*, i8** %exn.slot
%f.i8 = bitcast float* %f to i8*
call void @llvm.eh.begincatch(i8* %exn15, i8* %f.i8) #4
%tmp21 = load float, float* %f, align 4
call void @_Z12handle_floatf(float %tmp21)
call void @llvm.eh.endcatch() #4
br label %try.cont19
try.cont19: ; preds = %catch14, %invoke.cont9
call void @_Z4donev()
ret void
; CHECK-NOT: eh.resume:
eh.resume: ; preds = %catch.dispatch11
%exn20 = load i8*, i8** %exn.slot
%sel21 = load i32, i32* %ehselector.slot
%lpad.val = insertvalue { i8*, i32 } undef, i8* %exn20, 0
%lpad.val22 = insertvalue { i8*, i32 } %lpad.val, i32 %sel21, 1
resume { i8*, i32 } %lpad.val22
; CHECK: }
}
; This catch handler should be outlined.
; CHECK: define internal i8* @_Z4testv.catch(i8*, i8*)
; CHECK: entry:
; CHECK: [[RECOVER_F:\%.+]] = call i8* @llvm.localrecover(i8* bitcast (void ()* @_Z4testv to i8*), i8* %1, i32 0)
; CHECK: [[F_PTR:\%.+]] = bitcast i8* [[RECOVER_F]] to float*
; CHECK: [[TMP:\%.+]] = load float, float* [[F_PTR]], align 4
; CHECK: call void @_Z12handle_floatf(float [[TMP]])
; CHECK: ret i8* blockaddress(@_Z4testv, %try.cont19)
; CHECK: }
; This catch handler should be outlined.
; CHECK: define internal i8* @_Z4testv.catch.1(i8*, i8*)
; CHECK: entry:
; CHECK: [[RECOVER_I:\%.+]] = call i8* @llvm.localrecover(i8* bitcast (void ()* @_Z4testv to i8*), i8* %1, i32 1)
; CHECK: [[I_PTR:\%.+]] = bitcast i8* [[RECOVER_I]] to i32*
; CHECK: [[TMP1:\%.+]] = load i32, i32* [[I_PTR]], align 4
; CHECK: invoke void @_Z10handle_inti(i32 [[TMP1]])
; CHECK: to label %invoke.cont8 unwind label %[[LPAD7_LABEL:lpad[0-9]*]]
;
; CHECK: invoke.cont8: ; preds = %entry
; CHECK: ret i8* blockaddress(@_Z4testv, %try.cont)
;
; CHECK: [[LPAD7_LABEL]]:{{[ ]+}}; preds = %entry
; CHECK: [[LPAD7_VAL:\%.+]] = landingpad { i8*, i32 }
; (FIXME) The nested handler body isn't being populated yet.
; CHECK: }
; This cleanup handler should be outlined.
; CHECK: define internal void @_Z4testv.cleanup(i8*, i8*)
; CHECK: entry:
; CHECK: [[RECOVER_OUTER:\%.+]] = call i8* @llvm.localrecover(i8* bitcast (void ()* @_Z4testv to i8*), i8* %1, i32 2)
; CHECK: [[OUTER_PTR:\%.+]] = bitcast i8* [[RECOVER_OUTER]] to %class.Outer*
; CHECK: call void @_ZN5OuterD1Ev(%class.Outer* [[OUTER_PTR]])
; CHECK: ret void
; CHECK: }
; This cleanup handler should be outlined.
; CHECK: define internal void @_Z4testv.cleanup.2(i8*, i8*)
; CHECK: entry:
; CHECK: [[RECOVER_INNER:\%.+]] = call i8* @llvm.localrecover(i8* bitcast (void ()* @_Z4testv to i8*), i8* %1, i32 3)
; CHECK: [[INNER_PTR:\%.+]] = bitcast i8* [[RECOVER_INNER]] to %class.Inner*
; CHECK: call void @_ZN5InnerD1Ev(%class.Inner* [[INNER_PTR]])
; CHECK: ret void
; CHECK: }
declare void @_ZN5OuterC1Ev(%class.Outer*) #1
declare i32 @__CxxFrameHandler3(...)
declare void @_ZN5InnerC1Ev(%class.Inner*) #1
declare void @_Z9may_throwv() #1
declare void @_ZN5InnerD1Ev(%class.Inner*) #1
declare void @llvm.eh.begincatch(i8*, i8*)
; Function Attrs: nounwind readnone
declare i32 @llvm.eh.typeid.for(i8*) #3
declare void @_Z10handle_inti(i32) #1
declare void @llvm.eh.endcatch()
declare void @_ZN5OuterD1Ev(%class.Outer*) #1
declare void @_Z12handle_floatf(float) #1
declare void @_Z4donev() #1
attributes #0 = { uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #2 = { noinline noreturn nounwind }
attributes #3 = { nounwind readnone }
attributes #4 = { nounwind }
attributes #5 = { noreturn nounwind }
!llvm.ident = !{!0}
!0 = !{!"clang version 3.7.0 (trunk 226027)"}

View File

@ -1,260 +0,0 @@
; RUN: opt -mtriple=x86_64-pc-windows-msvc -winehprepare -S -o - < %s | FileCheck %s
; This test is based on the following code:
;
;void test()
;{
; try {
; try {
; may_throw();
; } catch (int i) {
; try {
; may_throw();
; }
; catch (int j) {
; i = j;
; }
; handle_int(i);
; }
; } catch (float f) {
; handle_float(f);
; }
; done();
;}
; ModuleID = 'cppeh-nested-3.cpp'
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-windows-msvc"
%rtti.TypeDescriptor2 = type { i8**, i8*, [3 x i8] }
$"\01??_R0M@8" = comdat any
$"\01??_R0H@8" = comdat any
@"\01??_7type_info@@6B@" = external constant i8*
@"\01??_R0M@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".M\00" }, comdat
@"\01??_R0H@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".H\00" }, comdat
; CHECK: define void @"\01?test@@YAXXZ"()
; CHECK: entry:
; CHECK: %i = alloca i32, align 4
; CHECK: %j = alloca i32, align 4
; CHECK: %f = alloca float, align 4
; CHECK: call void (...) @llvm.localescape(i32* %j, i32* %i, float* %f)
; CHECK: invoke void @"\01?may_throw@@YAXXZ"()
; CHECK: to label %invoke.cont unwind label %[[LPAD_LABEL:lpad[0-9]*]]
; Function Attrs: uwtable
define void @"\01?test@@YAXXZ"() #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
entry:
%exn.slot = alloca i8*
%ehselector.slot = alloca i32
%i = alloca i32, align 4
%j = alloca i32, align 4
%f = alloca float, align 4
invoke void @"\01?may_throw@@YAXXZ"()
to label %invoke.cont unwind label %lpad
invoke.cont: ; preds = %entry
br label %try.cont10
; CHECK: [[LPAD_LABEL]]:
; CHECK: landingpad { i8*, i32 }
; CHECK: catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*)
; CHECK: catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0M@8" to i8*)
; CHECK: [[RECOVER:\%.+]] = call i8* (...) @llvm.eh.actions(i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*), i32 1, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch.2", i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0M@8" to i8*), i32 2, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch.1")
; CHECK: indirectbr i8* [[RECOVER]], [label %try.cont10, label %try.cont19]
lpad: ; preds = %entry
%0 = landingpad { i8*, i32 }
catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*)
catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0M@8" to i8*)
%1 = extractvalue { i8*, i32 } %0, 0
store i8* %1, i8** %exn.slot
%2 = extractvalue { i8*, i32 } %0, 1
store i32 %2, i32* %ehselector.slot
br label %catch.dispatch
; CHECK-NOT: catch.dispatch:
catch.dispatch: ; preds = %lpad
%sel = load i32, i32* %ehselector.slot
%3 = call i32 @llvm.eh.typeid.for(i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*)) #3
%matches = icmp eq i32 %sel, %3
br i1 %matches, label %catch, label %catch.dispatch11
; CHECK-NOT: catch:
catch: ; preds = %catch.dispatch
%exn = load i8*, i8** %exn.slot
%4 = bitcast i32* %i to i8*
call void @llvm.eh.begincatch(i8* %exn, i8* %4) #3
invoke void @"\01?may_throw@@YAXXZ"()
to label %invoke.cont2 unwind label %lpad1
; CHECK-NOT: invoke.cont2:
invoke.cont2: ; preds = %catch
br label %try.cont
; CHECK-NOT: lpad1:
lpad1: ; preds = %catch
%5 = landingpad { i8*, i32 }
catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*)
catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0M@8" to i8*)
%6 = extractvalue { i8*, i32 } %5, 0
store i8* %6, i8** %exn.slot
%7 = extractvalue { i8*, i32 } %5, 1
store i32 %7, i32* %ehselector.slot
br label %catch.dispatch3
; CHECK-NOT: catch.dispatch3:
catch.dispatch3: ; preds = %lpad1
%sel4 = load i32, i32* %ehselector.slot
%8 = call i32 @llvm.eh.typeid.for(i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*)) #3
%matches5 = icmp eq i32 %sel4, %8
br i1 %matches5, label %catch6, label %catch.dispatch11
; CHECK-NOT: catch6:
catch6: ; preds = %catch.dispatch3
%exn7 = load i8*, i8** %exn.slot
%9 = bitcast i32* %j to i8*
call void @llvm.eh.begincatch(i8* %exn7, i8* %9) #3
%10 = load i32, i32* %j, align 4
store i32 %10, i32* %i, align 4
call void @llvm.eh.endcatch() #3
br label %try.cont
; CHECK-NOT: try.cont:
try.cont: ; preds = %catch6, %invoke.cont2
%11 = load i32, i32* %i, align 4
invoke void @"\01?handle_int@@YAXH@Z"(i32 %11)
to label %invoke.cont9 unwind label %lpad8
; CHECK-NOT: invoke.cont9:
invoke.cont9: ; preds = %try.cont
call void @llvm.eh.endcatch() #3
br label %try.cont10
try.cont10: ; preds = %invoke.cont9, %invoke.cont
br label %try.cont19
; CHECK-NOT: lpad8:
lpad8: ; preds = %try.cont
%12 = landingpad { i8*, i32 }
catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0M@8" to i8*)
%13 = extractvalue { i8*, i32 } %12, 0
store i8* %13, i8** %exn.slot
%14 = extractvalue { i8*, i32 } %12, 1
store i32 %14, i32* %ehselector.slot
call void @llvm.eh.endcatch() #3
br label %catch.dispatch11
; CHECK-NOT: catch.dispatch11:
catch.dispatch11: ; preds = %lpad8, %catch.dispatch3, %catch.dispatch
%sel12 = load i32, i32* %ehselector.slot
%15 = call i32 @llvm.eh.typeid.for(i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0M@8" to i8*)) #3
%matches13 = icmp eq i32 %sel12, %15
br i1 %matches13, label %catch14, label %eh.resume
; CHECK-NOT: catch14:
catch14: ; preds = %catch.dispatch11
%exn15 = load i8*, i8** %exn.slot
%16 = bitcast float* %f to i8*
call void @llvm.eh.begincatch(i8* %exn15, i8* %16) #3
%17 = load float, float* %f, align 4
call void @"\01?handle_float@@YAXM@Z"(float %17)
call void @llvm.eh.endcatch() #3
br label %try.cont19
try.cont19: ; preds = %catch14, %try.cont10
call void @"\01?done@@YAXXZ"()
ret void
; CHECK-NOT: eh.resume:
eh.resume: ; preds = %lpad16, %catch.dispatch11
%exn20 = load i8*, i8** %exn.slot
%sel21 = load i32, i32* %ehselector.slot
%lpad.val = insertvalue { i8*, i32 } undef, i8* %exn20, 0
%lpad.val22 = insertvalue { i8*, i32 } %lpad.val, i32 %sel21, 1
resume { i8*, i32 } %lpad.val22
; CHECK: }
}
; CHECK: define internal i8* @"\01?test@@YAXXZ.catch"(i8*, i8*)
; CHECK: entry:
; CHECK: [[RECOVER_J:\%.+]] = call i8* @llvm.localrecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 0)
; CHECK: [[J_PTR:\%.+]] = bitcast i8* [[RECOVER_J]] to i32*
; CHECK: [[RECOVER_I1:\%.+]] = call i8* @llvm.localrecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 1)
; CHECK: [[I_PTR1:\%.+]] = bitcast i8* [[RECOVER_I1]] to i32*
; CHECK: [[TMP3:\%.+]] = load i32, i32* [[J_PTR]], align 4
; CHECK: store i32 [[TMP3]], i32* [[I_PTR1]]
; CHECK: ret i8* blockaddress(@"\01?test@@YAXXZ.catch.2", %invoke.cont2)
; CHECK: }
; CHECK: define internal i8* @"\01?test@@YAXXZ.catch.1"(i8*, i8*)
; CHECK: entry:
; CHECK: [[RECOVER_F:\%.+]] = call i8* @llvm.localrecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 2)
; CHECK: [[F_PTR:\%.+]] = bitcast i8* [[RECOVER_F]] to float*
; CHECK: [[TMP2:\%.+]] = load float, float* [[F_PTR]], align 4
; CHECK: call void @"\01?handle_float@@YAXM@Z"(float [[TMP2]])
; CHECK: ret i8* blockaddress(@"\01?test@@YAXXZ", %try.cont19)
; CHECK: }
; CHECK: define internal i8* @"\01?test@@YAXXZ.catch.2"(i8*, i8*)
; CHECK: entry:
; CHECK: [[RECOVER_I:\%.+]] = call i8* @llvm.localrecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 1)
; CHECK: [[I_PTR:\%.+]] = bitcast i8* [[RECOVER_I]] to i32*
; CHECK: invoke void @"\01?may_throw@@YAXXZ"()
; CHECK: to label %invoke.cont2 unwind label %[[LPAD1_LABEL:lpad[0-9]*]]
;
; CHECK: invoke.cont2: ; preds = %[[LPAD1_LABEL]], %entry
; CHECK: [[TMP1:\%.+]] = load i32, i32* [[I_PTR]], align 4
; CHECK: invoke void @"\01?handle_int@@YAXH@Z"(i32 [[TMP1]])
; CHECK: to label %invoke.cont9 unwind label %[[LPAD8_LABEL:lpad[0-9]*]]
;
; CHECK: [[LPAD1_LABEL]]:{{[ ]+}}; preds = %entry
; CHECK: [[LPAD1_VAL:\%.+]] = landingpad { i8*, i32 }
; CHECK: catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*)
; CHECK: catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0M@8" to i8*)
; CHECK: [[RECOVER1:\%.+]] = call i8* (...) @llvm.eh.actions(i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*), i32 0, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch", i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0M@8" to i8*), i32 2, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch.1")
; CHECK: indirectbr i8* [[RECOVER1]], [label %invoke.cont2]
;
; CHECK: invoke.cont9:
; CHECK: ret i8* blockaddress(@"\01?test@@YAXXZ", %try.cont10)
;
; CHECK: [[LPAD8_LABEL]]:{{[ ]+}}; preds = %invoke.cont2
; CHECK: [[LPAD8_VAL:\%.+]] = landingpad { i8*, i32 }
; CHECK: catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0M@8" to i8*)
; CHECK: [[RECOVER2:\%.+]] = call i8* (...) @llvm.eh.actions(i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0M@8" to i8*), i32 2, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch.1")
; CHECK: indirectbr i8* [[RECOVER2]], []
;
; CHECK: }
declare void @"\01?may_throw@@YAXXZ"() #1
declare i32 @__CxxFrameHandler3(...)
; Function Attrs: nounwind readnone
declare i32 @llvm.eh.typeid.for(i8*) #2
; Function Attrs: nounwind
declare void @llvm.eh.begincatch(i8* nocapture, i8* nocapture) #3
; Function Attrs: nounwind
declare void @llvm.eh.endcatch() #3
declare void @"\01?handle_int@@YAXH@Z"(i32) #1
declare void @"\01?handle_float@@YAXM@Z"(float) #1
declare void @"\01?done@@YAXXZ"() #1
attributes #0 = { uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #2 = { nounwind readnone }
attributes #3 = { nounwind }
!llvm.module.flags = !{!0}
!llvm.ident = !{!1}
!0 = !{i32 1, !"PIC Level", i32 2}
!1 = !{!"clang version 3.7.0 (trunk 232069) (llvm/trunk 232070)"}

View File

@ -1,212 +0,0 @@
; RUN: opt -mtriple=x86_64-pc-windows-msvc -winehprepare -S -o - < %s | FileCheck %s
; This test was generated from the following code.
;
; void test1() {
; try {
; try {
; throw 1;
; } catch(...) { throw; }
; } catch (...) { }
; }
; void test2() {
; try {
; throw 1;
; } catch(...) {
; try {
; throw;
; } catch (...) {}
; }
; }
;
; These two functions result in functionally equivalent code, but the last
; catch block contains a call to llvm.eh.endcatch that tripped up processing
; during development.
;
; The main purpose of this test is to verify that we can correctly
; handle the case of nested landing pads that return directly to a block in
; the parent function.
; ModuleID = 'cppeh-nested-rethrow.cpp'
target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-windows-msvc"
%rtti.TypeDescriptor2 = type { i8**, i8*, [3 x i8] }
%eh.CatchableType = type { i32, i32, i32, i32, i32, i32, i32 }
%eh.CatchableTypeArray.1 = type { i32, [1 x i32] }
%eh.ThrowInfo = type { i32, i32, i32, i32 }
$"\01??_R0H@8" = comdat any
$"_CT??_R0H@84" = comdat any
$_CTA1H = comdat any
$_TI1H = comdat any
@"\01??_7type_info@@6B@" = external constant i8*
@"\01??_R0H@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".H\00" }, comdat
@__ImageBase = external constant i8
@"_CT??_R0H@84" = linkonce_odr unnamed_addr constant %eh.CatchableType { i32 1, i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32), i32 0, i32 -1, i32 0, i32 4, i32 0 }, section ".xdata", comdat
@_CTA1H = linkonce_odr unnamed_addr constant %eh.CatchableTypeArray.1 { i32 1, [1 x i32] [i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%eh.CatchableType* @"_CT??_R0H@84" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32)] }, section ".xdata", comdat
@_TI1H = linkonce_odr unnamed_addr constant %eh.ThrowInfo { i32 0, i32 0, i32 0, i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%eh.CatchableTypeArray.1* @_CTA1H to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32) }, section ".xdata", comdat
; CHECK-LABEL: define void @"\01?test1@@YAXXZ"()
; CHECK: entry:
; CHECK: call void (...) @llvm.localescape
; Function Attrs: nounwind uwtable
define void @"\01?test1@@YAXXZ"() #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
entry:
%tmp = alloca i32, align 4
%exn.slot = alloca i8*
%ehselector.slot = alloca i32
store i32 1, i32* %tmp
%0 = bitcast i32* %tmp to i8*
invoke void @_CxxThrowException(i8* %0, %eh.ThrowInfo* @_TI1H) #2
to label %unreachable unwind label %lpad
lpad: ; preds = %entry
%1 = landingpad { i8*, i32 }
catch i8* null
%2 = extractvalue { i8*, i32 } %1, 0
store i8* %2, i8** %exn.slot
%3 = extractvalue { i8*, i32 } %1, 1
store i32 %3, i32* %ehselector.slot
br label %catch
catch: ; preds = %lpad
%exn = load i8*, i8** %exn.slot
call void @llvm.eh.begincatch(i8* %exn, i8* null) #1
invoke void @_CxxThrowException(i8* null, %eh.ThrowInfo* null) #2
to label %unreachable unwind label %lpad1
lpad1: ; preds = %catch
%4 = landingpad { i8*, i32 }
catch i8* null
%5 = extractvalue { i8*, i32 } %4, 0
store i8* %5, i8** %exn.slot
%6 = extractvalue { i8*, i32 } %4, 1
store i32 %6, i32* %ehselector.slot
br label %catch2
catch2: ; preds = %lpad1
%exn3 = load i8*, i8** %exn.slot
call void @llvm.eh.begincatch(i8* %exn3, i8* null) #1
call void @llvm.eh.endcatch() #1
br label %try.cont.4
; This block should not be eliminated.
; CHECK: try.cont.4:
try.cont.4: ; preds = %catch2, %try.cont
ret void
try.cont: ; No predecessors!
br label %try.cont.4
unreachable: ; preds = %catch, %entry
unreachable
; CHECK: }
}
declare void @_CxxThrowException(i8*, %eh.ThrowInfo*)
declare i32 @__CxxFrameHandler3(...)
; Function Attrs: nounwind
declare void @llvm.eh.begincatch(i8* nocapture, i8* nocapture) #1
; Function Attrs: nounwind
declare void @llvm.eh.endcatch() #1
; CHECK-LABEL: define void @"\01?test2@@YAXXZ"()
; CHECK: entry:
; CHECK: call void (...) @llvm.localescape
; Function Attrs: nounwind uwtable
define void @"\01?test2@@YAXXZ"() #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
entry:
%tmp = alloca i32, align 4
%exn.slot = alloca i8*
%ehselector.slot = alloca i32
store i32 1, i32* %tmp
%0 = bitcast i32* %tmp to i8*
invoke void @_CxxThrowException(i8* %0, %eh.ThrowInfo* @_TI1H) #2
to label %unreachable unwind label %lpad
lpad: ; preds = %entry
%1 = landingpad { i8*, i32 }
catch i8* null
%2 = extractvalue { i8*, i32 } %1, 0
store i8* %2, i8** %exn.slot
%3 = extractvalue { i8*, i32 } %1, 1
store i32 %3, i32* %ehselector.slot
br label %catch
catch: ; preds = %lpad
%exn = load i8*, i8** %exn.slot
call void @llvm.eh.begincatch(i8* %exn, i8* null) #1
invoke void @_CxxThrowException(i8* null, %eh.ThrowInfo* null) #2
to label %unreachable unwind label %lpad1
lpad1: ; preds = %catch
%4 = landingpad { i8*, i32 }
catch i8* null
%5 = extractvalue { i8*, i32 } %4, 0
store i8* %5, i8** %exn.slot
%6 = extractvalue { i8*, i32 } %4, 1
store i32 %6, i32* %ehselector.slot
br label %catch2
catch2: ; preds = %lpad1
%exn3 = load i8*, i8** %exn.slot
call void @llvm.eh.begincatch(i8* %exn3, i8* null) #1
call void @llvm.eh.endcatch() #1
br label %try.cont
; This block should not be eliminated.
; CHECK: try.cont:
; The endcatch call should be eliminated.
; CHECK-NOT: call void @llvm.eh.endcatch()
try.cont: ; preds = %catch2
call void @llvm.eh.endcatch() #1
br label %try.cont.4
try.cont.4: ; preds = %try.cont
ret void
unreachable: ; preds = %catch, %entry
unreachable
; CHECK: }
}
; The outlined test1.catch handler should return to a valid block address.
; CHECK-LABEL: define internal i8* @"\01?test1@@YAXXZ.catch"(i8*, i8*)
; CHECK-NOT: ret i8* inttoptr (i32 1 to i8*)
; CHECK: }
; The outlined test1.catch1 handler should not contain a return instruction.
; CHECK-LABEL: define internal i8* @"\01?test1@@YAXXZ.catch.1"(i8*, i8*)
; CHECK-NOT: ret
; CHECK: }
; The outlined test2.catch handler should return to a valid block address.
; CHECK-LABEL: define internal i8* @"\01?test2@@YAXXZ.catch"(i8*, i8*)
; CHECK-NOT: ret i8* inttoptr (i32 1 to i8*)
; CHECK: }
; The outlined test2.catch2 handler should not contain a return instruction.
; CHECK-LABEL: define internal i8* @"\01?test2@@YAXXZ.catch.2"(i8*, i8*)
; CHECK-NOT: ret
; CHECK: }
attributes #0 = { nounwind uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { nounwind }
attributes #2 = { noreturn }
!llvm.module.flags = !{!0}
!llvm.ident = !{!1}
!0 = !{i32 1, !"PIC Level", i32 2}
!1 = !{!"clang version 3.7.0 (trunk 236059)"}

View File

@ -1,278 +0,0 @@
; RUN: opt -mtriple=x86_64-pc-windows-msvc -winehprepare -S -o - < %s | FileCheck %s
; This test is based on the following code:
;
; struct SomeData {
; int a;
; int b;
; };
;
; void may_throw();
; void does_not_throw(int i);
; void dump(int *, int, SomeData&);
;
; void test() {
; int NumExceptions = 0;
; int ExceptionVal[10];
; SomeData Data = { 0, 0 };
;
; for (int i = 0; i < 10; ++i) {
; try {
; may_throw();
; Data.a += i;
; }
; catch (int e) {
; ExceptionVal[NumExceptions] = e;
; ++NumExceptions;
; if (e == i)
; Data.b += e;
; else
; Data.a += e;
; }
; does_not_throw(NumExceptions);
; }
; dump(ExceptionVal, NumExceptions, Data);
; }
;
; Unlike the cppeh-frame-vars.ll test, this test was generated using -O2
; optimization, which results in non-alloca values being used in the
; catch handler.
; ModuleID = 'cppeh-frame-vars.cpp'
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-windows-msvc"
%rtti.TypeDescriptor2 = type { i8**, i8*, [3 x i8] }
%struct.SomeData = type { i32, i32 }
$"\01??_R0H@8" = comdat any
@"\01??_7type_info@@6B@" = external constant i8*
@"\01??_R0H@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".H\00" }, comdat
; The function entry should be rewritten like this.
; CHECK: define void @"\01?test@@YAXXZ"()
; CHECK: entry:
; CHECK: [[NUMEXCEPTIONS_REGMEM:\%.+]] = alloca i32
; CHECK: [[I_REGMEM:\%.+]] = alloca i32
; CHECK: [[B_REGMEM:\%.+]] = alloca i32*
; CHECK: [[A_REGMEM:\%.+]] = alloca i32*
; CHECK: [[E_PTR:\%.+]] = alloca i32, align 4
; CHECK: [[EXCEPTIONVAL:\%.+]] = alloca [10 x i32], align 16
; CHECK: [[DATA_PTR:\%.+]] = alloca i64, align 8
; CHECK: [[TMPCAST:\%.+]] = bitcast i64* [[DATA_PTR]] to %struct.SomeData*
; CHECK: [[TMP:\%.+]] = bitcast [10 x i32]* [[EXCEPTIONVAL]] to i8*
; CHECK: call void @llvm.lifetime.start(i64 40, i8* [[TMP]])
; CHECK: store i64 0, i64* [[DATA_PTR]], align 8
; CHECK: [[A_PTR:\%.+]] = bitcast i64* [[DATA_PTR]] to i32*
; CHECK: store i32* [[A_PTR]], i32** [[A_REGMEM]]
; CHECK: [[B_PTR:\%.+]] = getelementptr inbounds %struct.SomeData, %struct.SomeData* [[TMPCAST]], i64 0, i32 1
; CHECK: store i32* [[B_PTR]], i32** [[B_REGMEM]]
; CHECK: call void (...) @llvm.localescape(i32* %e, i32* %NumExceptions.020.reg2mem, [10 x i32]* [[EXCEPTIONVAL]], i32* %inc.reg2mem, i32* [[I_REGMEM]], i32** [[A_REGMEM]], i32** [[B_REGMEM]])
; CHECK: br label %for.body
; Function Attrs: uwtable
define void @"\01?test@@YAXXZ"() #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
entry:
%e = alloca i32, align 4
%ExceptionVal = alloca [10 x i32], align 16
%Data = alloca i64, align 8
%tmpcast = bitcast i64* %Data to %struct.SomeData*
%0 = bitcast [10 x i32]* %ExceptionVal to i8*
call void @llvm.lifetime.start(i64 40, i8* %0) #1
store i64 0, i64* %Data, align 8
%a = bitcast i64* %Data to i32*
%b = getelementptr inbounds %struct.SomeData, %struct.SomeData* %tmpcast, i64 0, i32 1
br label %for.body
; CHECK: for.body:
; CHECK: [[NUMEXCEPTIONS_PHI:\%.*]] = phi i32 [ 0, %entry ], [ {{\%NumExceptions.*}}, %try.cont ]
; CHECK: [[I_PHI:\%.*]] = phi i32 [ 0, %entry ], [ {{\%inc.*}}, %try.cont ]
; CHECK: store i32 [[I_PHI]], i32* [[I_REGMEM]]
; CHECK: store i32 [[NUMEXCEPTIONS_PHI]], i32* [[NUMEXCEPTIONS_REGMEM]]
; CHECK: invoke void @"\01?may_throw@@YAXXZ"()
for.body: ; preds = %entry, %try.cont
%NumExceptions.020 = phi i32 [ 0, %entry ], [ %NumExceptions.1, %try.cont ]
%i.019 = phi i32 [ 0, %entry ], [ %inc5, %try.cont ]
invoke void @"\01?may_throw@@YAXXZ"()
to label %invoke.cont unwind label %lpad
; CHECK: invoke.cont: ; preds = %for.body
; CHECK: [[A_RELOAD:\%.+]] = load i32*, i32** [[A_REGMEM]]
; CHECK: [[TMP1:\%.+]] = load i32, i32* [[A_RELOAD]], align 8
; CHECK: [[I_RELOAD:\%.+]] = load i32, i32* [[I_REGMEM]]
; CHECK: [[ADD:\%.+]] = add nsw i32 [[TMP1]], [[I_RELOAD]]
; CHECK: [[A_RELOAD1:\%.+]] = load i32*, i32** [[A_REGMEM]]
; CHECK: [[NUMEXCEPTIONS_RELOAD:\%.+]] = load i32, i32* [[NUMEXCEPTIONS_REGMEM]]
; CHECK: br label %try.cont
invoke.cont: ; preds = %for.body
%1 = load i32, i32* %a, align 8, !tbaa !2
%add = add nsw i32 %1, %i.019
store i32 %add, i32* %a, align 8, !tbaa !2
br label %try.cont
; CHECK: [[LPAD_LABEL:lpad[0-9]*]]:{{[ ]+}}; preds = %for.body
; CHECK: landingpad { i8*, i32 }
; CHECK-NEXT: catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*)
; CHECK-NEXT: [[RECOVER:\%.+]] = call i8* (...) @llvm.eh.actions(i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*), i32 0, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch")
; CHECK-NEXT: indirectbr i8* [[RECOVER]], [label %[[SPLIT_RECOVER_BB:.*]]]
lpad: ; preds = %for.body
%2 = landingpad { i8*, i32 }
catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*)
%3 = extractvalue { i8*, i32 } %2, 1
%4 = tail call i32 @llvm.eh.typeid.for(i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*)) #1
%matches = icmp eq i32 %3, %4
br i1 %matches, label %catch, label %eh.resume
; CHECK-NOT: catch:
catch: ; preds = %lpad
%5 = extractvalue { i8*, i32 } %2, 0
%e.i8 = bitcast i32* %e to i8*
call void @llvm.eh.begincatch(i8* %5, i8* %e.i8) #1
%tmp8 = load i32, i32* %e, align 4, !tbaa !7
%idxprom = sext i32 %NumExceptions.020 to i64
%arrayidx = getelementptr inbounds [10 x i32], [10 x i32]* %ExceptionVal, i64 0, i64 %idxprom
store i32 %tmp8, i32* %arrayidx, align 4, !tbaa !7
%inc = add nsw i32 %NumExceptions.020, 1
%cmp1 = icmp eq i32 %tmp8, %i.019
br i1 %cmp1, label %if.then, label %if.else
if.then: ; preds = %catch
%tmp9 = load i32, i32* %b, align 4, !tbaa !8
%add2 = add nsw i32 %tmp9, %i.019
store i32 %add2, i32* %b, align 4, !tbaa !8
br label %if.end
; CHECK-NOT: if.else:
if.else: ; preds = %catch
%tmp10 = load i32, i32* %a, align 8, !tbaa !2
%add4 = add nsw i32 %tmp10, %tmp8
store i32 %add4, i32* %a, align 8, !tbaa !2
br label %if.end
; CHECK-NOT: if.end:
; CHECK: [[SPLIT_RECOVER_BB]]:
; CHECK: [[INC_RELOAD:\%.*]] = load i32, i32*
; CHECK: br label %try.cont
if.end: ; preds = %if.else, %if.then
tail call void @llvm.eh.endcatch() #1
br label %try.cont
; CHECK: try.cont:{{[ ]+}}; preds = %[[SPLIT_RECOVER_BB]], %invoke.cont
; CHECK: [[NUMEXCEPTIONS_PHI:\%.*]] = phi i32 [ [[NUMEXCEPTIONS_RELOAD]], %invoke.cont ], [ [[INC_RELOAD]], %[[SPLIT_RECOVER_BB]] ]
; CHECK: tail call void @"\01?does_not_throw@@YAXH@Z"(i32 [[NUMEXCEPTIONS_PHI]])
; CHECK: [[I_RELOAD:\%.+]] = load i32, i32* [[I_REGMEM]]
; CHECK: [[INC:\%.+]] = add nuw nsw i32 [[I_RELOAD]], 1
; CHECK: [[CMP:\%.+]] = icmp slt i32 [[INC]], 10
; CHECK: br i1 [[CMP]], label %for.body, label %for.end
try.cont: ; preds = %if.end, %invoke.cont
%NumExceptions.1 = phi i32 [ %NumExceptions.020, %invoke.cont ], [ %inc, %if.end ]
tail call void @"\01?does_not_throw@@YAXH@Z"(i32 %NumExceptions.1)
%inc5 = add nuw nsw i32 %i.019, 1
%cmp = icmp slt i32 %inc5, 10
br i1 %cmp, label %for.body, label %for.end
for.end: ; preds = %try.cont
%NumExceptions.1.lcssa = phi i32 [ %NumExceptions.1, %try.cont ]
%arraydecay = getelementptr inbounds [10 x i32], [10 x i32]* %ExceptionVal, i64 0, i64 0
call void @"\01?dump@@YAXPEAHHAEAUSomeData@@@Z"(i32* %arraydecay, i32 %NumExceptions.1.lcssa, %struct.SomeData* dereferenceable(8) %tmpcast)
call void @llvm.lifetime.end(i64 40, i8* %0) #1
ret void
eh.resume: ; preds = %lpad
%.lcssa = phi { i8*, i32 } [ %2, %lpad ]
resume { i8*, i32 } %.lcssa
}
; The following catch handler should be outlined.
; CHECK: define internal i8* @"\01?test@@YAXXZ.catch"(i8*, i8*)
; CHECK: entry:
; CHECK: [[RECOVER_E:\%.+]] = call i8* @llvm.localrecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 0)
; CHECK: [[E_PTR:\%.+]] = bitcast i8* [[RECOVER_E]] to i32*
; CHECK: [[RECOVER_NUMEXCEPTIONS:\%.+]] = call i8* @llvm.localrecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 1)
; CHECK: [[NUMEXCEPTIONS_REGMEM:\%.+]] = bitcast i8* [[RECOVER_NUMEXCEPTIONS]] to i32*
; CHECK: [[RECOVER_EXCEPTIONVAL:\%.+]] = call i8* @llvm.localrecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 2)
; CHECK: [[EXCEPTIONVAL:\%.+]] = bitcast i8* [[RECOVER_EXCEPTIONVAL]] to [10 x i32]*
; CHECK: [[RECOVER_INC:\%.+]] = call i8* @llvm.localrecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 3)
; CHECK: [[INC_REGMEM:\%.+]] = bitcast i8* [[RECOVER_INC]] to i32*
; CHECK: [[RECOVER_I:\%.+]] = call i8* @llvm.localrecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 4)
; CHECK: [[I_REGMEM:\%.+]] = bitcast i8* [[RECOVER_I]] to i32*
; CHECK: [[RECOVER_A:\%.+]] = call i8* @llvm.localrecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 5)
; CHECK: [[A_REGMEM:\%.+]] = bitcast i8* [[RECOVER_A]] to i32**
; CHECK: [[RECOVER_B:\%.+]] = call i8* @llvm.localrecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 6)
; CHECK: [[B_REGMEM:\%.+]] = bitcast i8* [[RECOVER_B]] to i32**
; CHECK: [[E_I8PTR:\%.+]] = bitcast i32* [[E_PTR]] to i8*
; CHECK: [[TMP:\%.+]] = load i32, i32* [[E_PTR]], align 4
; CHECK: [[NUMEXCEPTIONS_RELOAD:\%.+]] = load i32, i32* [[NUMEXCEPTIONS_REGMEM]]
; CHECK: [[IDXPROM:\%.+]] = sext i32 [[NUMEXCEPTIONS_RELOAD]] to i64
; CHECK: [[ARRAYIDX:\%.+]] = getelementptr inbounds [10 x i32], [10 x i32]* [[EXCEPTIONVAL]], i64 0, i64 [[IDXPROM]]
; CHECK: store i32 [[TMP]], i32* [[ARRAYIDX]], align 4
; CHECK: [[NUMEXCEPTIONS_RELOAD:\%.+]] = load i32, i32* [[NUMEXCEPTIONS_REGMEM]]
; CHECK: [[INC:\%.+]] = add nsw i32 [[NUMEXCEPTIONS_RELOAD]], 1
; CHECK: [[CMP:\%.+]] = icmp eq i32 [[TMP]], [[I_RELOAD]]
; CHECK: br i1 [[CMP]], label %if.then, label %if.else
;
; CHECK: if.then:{{[ ]+}}; preds = %entry
; CHECK: [[B_RELOAD:\%.+]] = load i32*, i32** [[B_REGMEM]]
; CHECK: [[TMP1:\%.+]] = load i32, i32* [[B_RELOAD]], align 4
; CHECK: [[I_RELOAD:\%.+]] = load i32, i32* [[I_REGMEM]]
; CHECK: [[ADD:\%.+]] = add nsw i32 [[TMP1]], [[I_RELOAD]]
; CHECK: [[B_RELOAD:\%.+]] = load i32*, i32** [[B_REGMEM]]
; CHECK: store i32 [[ADD]], i32* [[B_RELOAD]], align 4
; CHECK: br label %if.end
;
; CHECK: if.else:{{[ ]+}}; preds = %entry
; CHECK: [[A_RELOAD:\%.+]] = load i32*, i32** [[A_REGMEM]]
; CHECK: [[TMP2:\%.+]] = load i32, i32* [[A_RELOAD]], align 8
; CHECK: [[ADD2:\%.+]] = add nsw i32 [[TMP2]], [[TMP]]
; CHECK: [[A_RELOAD:\%.+]] = load i32*, i32** [[A_REGMEM]]
; CHECK: store i32 [[ADD2]], i32* [[A_RELOAD]], align 8
; CHECK: br label %if.end
;
; CHECK: if.end:{{[ ]+}}; preds = %if.else, %if.then
; CHECK: ret i8* blockaddress(@"\01?test@@YAXXZ", %[[SPLIT_RECOVER_BB]])
; CHECK: }
; Function Attrs: nounwind
declare void @llvm.lifetime.start(i64, i8* nocapture) #1
declare void @"\01?may_throw@@YAXXZ"() #2
declare i32 @__CxxFrameHandler3(...)
; Function Attrs: nounwind readnone
declare i32 @llvm.eh.typeid.for(i8*) #3
declare void @llvm.eh.begincatch(i8*, i8*)
declare void @llvm.eh.endcatch()
declare void @"\01?does_not_throw@@YAXH@Z"(i32) #2
declare void @"\01?dump@@YAXPEAHHAEAUSomeData@@@Z"(i32*, i32, %struct.SomeData* dereferenceable(8)) #2
; Function Attrs: nounwind
declare void @llvm.lifetime.end(i64, i8* nocapture) #1
attributes #0 = { uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { nounwind }
attributes #2 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #3 = { nounwind readnone }
!llvm.module.flags = !{!0}
!llvm.ident = !{!1}
!0 = !{i32 1, !"PIC Level", i32 2}
!1 = !{!"clang version 3.7.0 (trunk 228868)"}
!2 = !{!3, !4, i64 0}
!3 = !{!"?AUSomeData@@", !4, i64 0, !4, i64 4}
!4 = !{!"int", !5, i64 0}
!5 = !{!"omnipotent char", !6, i64 0}
!6 = !{!"Simple C/C++ TBAA"}
!7 = !{!4, !4, i64 0}
!8 = !{!3, !4, i64 4}

View File

@ -1,110 +0,0 @@
; RUN: opt -mtriple=x86_64-pc-windows-msvc -winehprepare -S -o - < %s | FileCheck %s
; This test is based on the following source, built with -O2
;
; void f() {
; try {
; g();
; try {
; throw;
; } catch (int) {
; }
; } catch (...) {
; }
; }
;
; ModuleID = '<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)"}

View File

@ -1,394 +0,0 @@
; RUN: opt -mtriple=x86_64-pc-windows-msvc -winehprepare -S -o - < %s | FileCheck %s
; This test is based on the following code:
;
; int main(void) {
; try {
; try {
; throw 'a';
; } catch (char c) {
; printf("%c\n", c);
; }
; throw 1;
; } catch(int x) {
; printf("%d\n", x);
; } catch(...) {
; printf("...\n");
; }
; try {
; try {
; throw 'b';
; } catch (char c) {
; printf("%c\n", c);
; }
; throw 2;
; } catch(int x) {
; printf("%d\n", x);
; } catch (char c) {
; printf("%c\n", c);
; } catch(...) {
; printf("...\n");
; }
; return 0;
; }
; This test is just checking for failures in processing the IR.
; Extensive handler matching is not required.
; ModuleID = 'cppeh-similar-catch-blocks.cpp'
target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-windows-msvc"
%rtti.TypeDescriptor2 = type { i8**, i8*, [3 x i8] }
%eh.CatchHandlerType = type { i32, i8* }
%eh.CatchableType = type { i32, i32, i32, i32, i32, i32, i32 }
%eh.CatchableTypeArray.1 = type { i32, [1 x i32] }
%eh.ThrowInfo = type { i32, i32, i32, i32 }
$"\01??_R0H@8" = comdat any
$"\01??_R0D@8" = comdat any
$"_CT??_R0D@81" = comdat any
$_CTA1D = comdat any
$_TI1D = comdat any
$"\01??_C@_03PJCJOCBM@?$CFc?6?$AA@" = comdat any
$"_CT??_R0H@84" = comdat any
$_CTA1H = comdat any
$_TI1H = comdat any
$"\01??_C@_04MPPNMCOK@?4?4?4?6?$AA@" = comdat any
$"\01??_C@_03PMGGPEJJ@?$CFd?6?$AA@" = comdat any
@"\01??_7type_info@@6B@" = external constant i8*
@"\01??_R0H@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".H\00" }, comdat
@llvm.eh.handlertype.H.0 = private unnamed_addr constant %eh.CatchHandlerType { i32 0, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*) }, section "llvm.metadata"
@"\01??_R0D@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".D\00" }, comdat
@llvm.eh.handlertype.D.0 = private unnamed_addr constant %eh.CatchHandlerType { i32 0, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0D@8" to i8*) }, section "llvm.metadata"
@__ImageBase = external constant i8
@"_CT??_R0D@81" = linkonce_odr unnamed_addr constant %eh.CatchableType { i32 1, i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.TypeDescriptor2* @"\01??_R0D@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32), i32 0, i32 -1, i32 0, i32 1, i32 0 }, section ".xdata", comdat
@_CTA1D = linkonce_odr unnamed_addr constant %eh.CatchableTypeArray.1 { i32 1, [1 x i32] [i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%eh.CatchableType* @"_CT??_R0D@81" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32)] }, section ".xdata", comdat
@_TI1D = linkonce_odr unnamed_addr constant %eh.ThrowInfo { i32 0, i32 0, i32 0, i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%eh.CatchableTypeArray.1* @_CTA1D to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32) }, section ".xdata", comdat
@"\01??_C@_03PJCJOCBM@?$CFc?6?$AA@" = linkonce_odr unnamed_addr constant [4 x i8] c"%c\0A\00", comdat, align 1
@"_CT??_R0H@84" = linkonce_odr unnamed_addr constant %eh.CatchableType { i32 1, i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32), i32 0, i32 -1, i32 0, i32 4, i32 0 }, section ".xdata", comdat
@_CTA1H = linkonce_odr unnamed_addr constant %eh.CatchableTypeArray.1 { i32 1, [1 x i32] [i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%eh.CatchableType* @"_CT??_R0H@84" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32)] }, section ".xdata", comdat
@_TI1H = linkonce_odr unnamed_addr constant %eh.ThrowInfo { i32 0, i32 0, i32 0, i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%eh.CatchableTypeArray.1* @_CTA1H to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32) }, section ".xdata", comdat
@"\01??_C@_04MPPNMCOK@?4?4?4?6?$AA@" = linkonce_odr unnamed_addr constant [5 x i8] c"...\0A\00", comdat, align 1
@"\01??_C@_03PMGGPEJJ@?$CFd?6?$AA@" = linkonce_odr unnamed_addr constant [4 x i8] c"%d\0A\00", comdat, align 1
; This is just a minimal check to verify that main was handled by WinEHPrepare.
; CHECK: define i32 @main()
; CHECK: entry:
; CHECK: call void (...) @llvm.localescape(i32* [[X_PTR:\%.+]], i32* [[X2_PTR:\%.+]], i8* [[C2_PTR:\%.+]], i8* [[C3_PTR:\%.+]], i8* [[C_PTR:\%.+]])
; CHECK: invoke void @_CxxThrowException
; CHECK: }
; Function Attrs: uwtable
define i32 @main() #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
entry:
%retval = alloca i32, align 4
%tmp = alloca i8, align 1
%exn.slot = alloca i8*
%ehselector.slot = alloca i32
%c = alloca i8, align 1
%tmp3 = alloca i32, align 4
%x = alloca i32, align 4
%tmp20 = alloca i8, align 1
%c28 = alloca i8, align 1
%tmp34 = alloca i32, align 4
%c48 = alloca i8, align 1
%x56 = alloca i32, align 4
store i32 0, i32* %retval
store i8 97, i8* %tmp
invoke void @_CxxThrowException(i8* %tmp, %eh.ThrowInfo* @_TI1D) #4
to label %unreachable unwind label %lpad
lpad: ; preds = %entry
%0 = landingpad { i8*, i32 }
catch %eh.CatchHandlerType* @llvm.eh.handlertype.D.0
catch %eh.CatchHandlerType* @llvm.eh.handlertype.H.0
catch i8* null
%1 = extractvalue { i8*, i32 } %0, 0
store i8* %1, i8** %exn.slot
%2 = extractvalue { i8*, i32 } %0, 1
store i32 %2, i32* %ehselector.slot
br label %catch.dispatch
catch.dispatch: ; preds = %lpad
%sel = load i32, i32* %ehselector.slot
%3 = call i32 @llvm.eh.typeid.for(i8* bitcast (%eh.CatchHandlerType* @llvm.eh.handlertype.D.0 to i8*)) #2
%matches = icmp eq i32 %sel, %3
br i1 %matches, label %catch, label %catch.dispatch5
catch: ; preds = %catch.dispatch
%exn = load i8*, i8** %exn.slot
call void @llvm.eh.begincatch(i8* %exn, i8* %c) #2
%4 = load i8, i8* %c, align 1
%conv = sext i8 %4 to i32
%call = invoke i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @"\01??_C@_03PJCJOCBM@?$CFc?6?$AA@", i32 0, i32 0), i32 %conv)
to label %invoke.cont unwind label %lpad2
invoke.cont: ; preds = %catch
call void @llvm.eh.endcatch() #2
br label %try.cont
try.cont: ; preds = %invoke.cont
store i32 1, i32* %tmp3
%5 = bitcast i32* %tmp3 to i8*
invoke void @_CxxThrowException(i8* %5, %eh.ThrowInfo* @_TI1H) #4
to label %unreachable unwind label %lpad4
lpad2: ; preds = %catch
%6 = landingpad { i8*, i32 }
catch %eh.CatchHandlerType* @llvm.eh.handlertype.H.0
catch i8* null
%7 = extractvalue { i8*, i32 } %6, 0
store i8* %7, i8** %exn.slot
%8 = extractvalue { i8*, i32 } %6, 1
store i32 %8, i32* %ehselector.slot
call void @llvm.eh.endcatch() #2
br label %catch.dispatch5
lpad4: ; preds = %try.cont
%9 = landingpad { i8*, i32 }
catch %eh.CatchHandlerType* @llvm.eh.handlertype.H.0
catch i8* null
%10 = extractvalue { i8*, i32 } %9, 0
store i8* %10, i8** %exn.slot
%11 = extractvalue { i8*, i32 } %9, 1
store i32 %11, i32* %ehselector.slot
br label %catch.dispatch5
catch.dispatch5: ; preds = %lpad4, %lpad2, %catch.dispatch
%sel6 = load i32, i32* %ehselector.slot
%12 = call i32 @llvm.eh.typeid.for(i8* bitcast (%eh.CatchHandlerType* @llvm.eh.handlertype.H.0 to i8*)) #2
%matches7 = icmp eq i32 %sel6, %12
br i1 %matches7, label %catch13, label %catch8
catch13: ; preds = %catch.dispatch5
%exn14 = load i8*, i8** %exn.slot
%13 = bitcast i32* %x to i8*
call void @llvm.eh.begincatch(i8* %exn14, i8* %13) #2
%14 = load i32, i32* %x, align 4
%call18 = invoke i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @"\01??_C@_03PMGGPEJJ@?$CFd?6?$AA@", i32 0, i32 0), i32 %14)
to label %invoke.cont17 unwind label %lpad16
invoke.cont17: ; preds = %catch13
call void @llvm.eh.endcatch() #2
br label %try.cont19
try.cont19: ; preds = %invoke.cont17, %invoke.cont11
store i8 98, i8* %tmp20
invoke void @_CxxThrowException(i8* %tmp20, %eh.ThrowInfo* @_TI1D) #4
to label %unreachable unwind label %lpad21
catch8: ; preds = %catch.dispatch5
%exn9 = load i8*, i8** %exn.slot
call void @llvm.eh.begincatch(i8* %exn9, i8* null) #2
%call12 = invoke i32 (i8*, ...) @printf(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @"\01??_C@_04MPPNMCOK@?4?4?4?6?$AA@", i32 0, i32 0))
to label %invoke.cont11 unwind label %lpad10
invoke.cont11: ; preds = %catch8
call void @llvm.eh.endcatch() #2
br label %try.cont19
lpad10: ; preds = %catch8
%15 = landingpad { i8*, i32 }
cleanup
%16 = extractvalue { i8*, i32 } %15, 0
store i8* %16, i8** %exn.slot
%17 = extractvalue { i8*, i32 } %15, 1
store i32 %17, i32* %ehselector.slot
call void @llvm.eh.endcatch() #2
br label %eh.resume
lpad16: ; preds = %catch13
%18 = landingpad { i8*, i32 }
cleanup
%19 = extractvalue { i8*, i32 } %18, 0
store i8* %19, i8** %exn.slot
%20 = extractvalue { i8*, i32 } %18, 1
store i32 %20, i32* %ehselector.slot
call void @llvm.eh.endcatch() #2
br label %eh.resume
lpad21: ; preds = %try.cont19
%21 = landingpad { i8*, i32 }
catch i8* bitcast (%eh.CatchHandlerType* @llvm.eh.handlertype.D.0 to i8*)
catch i8* bitcast (%eh.CatchHandlerType* @llvm.eh.handlertype.H.0 to i8*)
catch i8* null
%22 = extractvalue { i8*, i32 } %21, 0
store i8* %22, i8** %exn.slot
%23 = extractvalue { i8*, i32 } %21, 1
store i32 %23, i32* %ehselector.slot
br label %catch.dispatch22
catch.dispatch22: ; preds = %lpad21
%sel23 = load i32, i32* %ehselector.slot
%24 = call i32 @llvm.eh.typeid.for(i8* bitcast (%eh.CatchHandlerType* @llvm.eh.handlertype.D.0 to i8*)) #2
%matches24 = icmp eq i32 %sel23, %24
br i1 %matches24, label %catch25, label %catch.dispatch36
catch25: ; preds = %catch.dispatch22
%exn26 = load i8*, i8** %exn.slot
call void @llvm.eh.begincatch(i8* %exn26, i8* %c28) #2
%25 = load i8, i8* %c28, align 1
%conv29 = sext i8 %25 to i32
%call32 = invoke i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @"\01??_C@_03PJCJOCBM@?$CFc?6?$AA@", i32 0, i32 0), i32 %conv29)
to label %invoke.cont31 unwind label %lpad30
invoke.cont31: ; preds = %catch25
call void @llvm.eh.endcatch() #2
br label %try.cont33
try.cont33: ; preds = %invoke.cont31
store i32 2, i32* %tmp34
%26 = bitcast i32* %tmp34 to i8*
invoke void @_CxxThrowException(i8* %26, %eh.ThrowInfo* @_TI1H) #4
to label %unreachable unwind label %lpad35
lpad30: ; preds = %catch25
%27 = landingpad { i8*, i32 }
catch i8* bitcast (%eh.CatchHandlerType* @llvm.eh.handlertype.H.0 to i8*)
catch i8* bitcast (%eh.CatchHandlerType* @llvm.eh.handlertype.D.0 to i8*)
catch i8* null
%28 = extractvalue { i8*, i32 } %27, 0
store i8* %28, i8** %exn.slot
%29 = extractvalue { i8*, i32 } %27, 1
store i32 %29, i32* %ehselector.slot
call void @llvm.eh.endcatch() #2
br label %catch.dispatch36
lpad35: ; preds = %try.cont33
%30 = landingpad { i8*, i32 }
catch i8* bitcast (%eh.CatchHandlerType* @llvm.eh.handlertype.H.0 to i8*)
catch i8* bitcast (%eh.CatchHandlerType* @llvm.eh.handlertype.D.0 to i8*)
catch i8* null
%31 = extractvalue { i8*, i32 } %30, 0
store i8* %31, i8** %exn.slot
%32 = extractvalue { i8*, i32 } %30, 1
store i32 %32, i32* %ehselector.slot
br label %catch.dispatch36
catch.dispatch36: ; preds = %lpad35, %lpad30, %catch.dispatch22
%sel37 = load i32, i32* %ehselector.slot
%33 = call i32 @llvm.eh.typeid.for(i8* bitcast (%eh.CatchHandlerType* @llvm.eh.handlertype.H.0 to i8*)) #2
%matches38 = icmp eq i32 %sel37, %33
br i1 %matches38, label %catch53, label %catch.fallthrough
catch53: ; preds = %catch.dispatch36
%exn54 = load i8*, i8** %exn.slot
%34 = bitcast i32* %x56 to i8*
call void @llvm.eh.begincatch(i8* %exn54, i8* %34) #2
%35 = load i32, i32* %x56, align 4
%call59 = invoke i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @"\01??_C@_03PMGGPEJJ@?$CFd?6?$AA@", i32 0, i32 0), i32 %35)
to label %invoke.cont58 unwind label %lpad57
invoke.cont58: ; preds = %catch53
call void @llvm.eh.endcatch() #2
br label %try.cont60
try.cont60: ; preds = %invoke.cont58, %invoke.cont51, %invoke.cont43
ret i32 0
catch.fallthrough: ; preds = %catch.dispatch36
%36 = call i32 @llvm.eh.typeid.for(i8* bitcast (%eh.CatchHandlerType* @llvm.eh.handlertype.D.0 to i8*)) #2
%matches39 = icmp eq i32 %sel37, %36
br i1 %matches39, label %catch45, label %catch40
catch45: ; preds = %catch.fallthrough
%exn46 = load i8*, i8** %exn.slot
call void @llvm.eh.begincatch(i8* %exn46, i8* %c48) #2
%37 = load i8, i8* %c48, align 1
%conv49 = sext i8 %37 to i32
%call52 = invoke i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @"\01??_C@_03PJCJOCBM@?$CFc?6?$AA@", i32 0, i32 0), i32 %conv49)
to label %invoke.cont51 unwind label %lpad50
invoke.cont51: ; preds = %catch45
call void @llvm.eh.endcatch() #2
br label %try.cont60
catch40: ; preds = %catch.fallthrough
%exn41 = load i8*, i8** %exn.slot
call void @llvm.eh.begincatch(i8* %exn41, i8* null) #2
%call44 = invoke i32 (i8*, ...) @printf(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @"\01??_C@_04MPPNMCOK@?4?4?4?6?$AA@", i32 0, i32 0))
to label %invoke.cont43 unwind label %lpad42
invoke.cont43: ; preds = %catch40
call void @llvm.eh.endcatch() #2
br label %try.cont60
lpad42: ; preds = %catch40
%38 = landingpad { i8*, i32 }
cleanup
%39 = extractvalue { i8*, i32 } %38, 0
store i8* %39, i8** %exn.slot
%40 = extractvalue { i8*, i32 } %38, 1
store i32 %40, i32* %ehselector.slot
call void @llvm.eh.endcatch() #2
br label %eh.resume
lpad50: ; preds = %catch45
%41 = landingpad { i8*, i32 }
cleanup
%42 = extractvalue { i8*, i32 } %41, 0
store i8* %42, i8** %exn.slot
%43 = extractvalue { i8*, i32 } %41, 1
store i32 %43, i32* %ehselector.slot
call void @llvm.eh.endcatch() #2
br label %eh.resume
lpad57: ; preds = %catch53
%44 = landingpad { i8*, i32 }
cleanup
%45 = extractvalue { i8*, i32 } %44, 0
store i8* %45, i8** %exn.slot
%46 = extractvalue { i8*, i32 } %44, 1
store i32 %46, i32* %ehselector.slot
call void @llvm.eh.endcatch() #2
br label %eh.resume
eh.resume: ; preds = %lpad57, %lpad50, %lpad42, %lpad16, %lpad10
%exn61 = load i8*, i8** %exn.slot
%sel62 = load i32, i32* %ehselector.slot
%lpad.val = insertvalue { i8*, i32 } undef, i8* %exn61, 0
%lpad.val63 = insertvalue { i8*, i32 } %lpad.val, i32 %sel62, 1
resume { i8*, i32 } %lpad.val63
unreachable: ; preds = %try.cont33, %try.cont19, %try.cont, %entry
unreachable
}
declare void @_CxxThrowException(i8*, %eh.ThrowInfo*)
declare i32 @__CxxFrameHandler3(...)
; Function Attrs: nounwind readnone
declare i32 @llvm.eh.typeid.for(i8*) #1
; Function Attrs: nounwind
declare void @llvm.eh.begincatch(i8* nocapture, i8* nocapture) #2
declare i32 @printf(i8*, ...) #3
; Function Attrs: nounwind
declare void @llvm.eh.endcatch() #2
attributes #0 = { uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { nounwind readnone }
attributes #2 = { nounwind }
attributes #3 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #4 = { noreturn }
!llvm.module.flags = !{!0}
!llvm.ident = !{!1}
!0 = !{i32 1, !"PIC Level", i32 2}
!1 = !{!"clang version 3.7.0 (trunk 235214) (llvm/trunk 235213)"}

View File

@ -1,59 +0,0 @@
; RUN: opt -S -winehprepare -mtriple=x86_64-pc-windows-msvc < %s | FileCheck %s
; RUN: opt -S -winehprepare -mtriple=x86_64-pc-windows-coreclr < %s | FileCheck %s
target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
@str.__except = internal unnamed_addr constant [9 x i8] c"__except\00", align 1
; Function Attrs: uwtable
declare i32 @puts(i8*)
define void @may_crash() {
entry:
store volatile i32 42, i32* null, align 4
ret void
}
declare i32 @__C_specific_handler(...)
; Function Attrs: nounwind readnone
declare i8* @llvm.frameaddress(i32)
; Function Attrs: uwtable
define void @seh_catch_all() personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) {
entry:
%exn.slot = alloca i8*
%ehselector.slot = alloca i32
invoke void @may_crash()
to label %invoke.cont unwind label %lpad
invoke.cont: ; preds = %entry
br label %__try.cont
lpad: ; preds = %entry
%0 = landingpad { i8*, i32 }
catch i8* null
%1 = extractvalue { i8*, i32 } %0, 0
store i8* %1, i8** %exn.slot
%2 = extractvalue { i8*, i32 } %0, 1
store i32 %2, i32* %ehselector.slot
br label %__except
__except: ; preds = %lpad
%call = call i32 @puts(i8* getelementptr inbounds ([9 x i8], [9 x i8]* @str.__except, i32 0, i32 0))
br label %__try.cont
__try.cont: ; preds = %__except, %invoke.cont
ret void
}
; CHECK-LABEL: define void @seh_catch_all()
; CHECK: landingpad
; CHECK-NEXT: catch i8* null
; CHECK-NEXT: call i8* (...) @llvm.eh.actions(i32 1, i8* null, i32 -1, i8* blockaddress(@seh_catch_all, %lpad.split))
; CHECK-NEXT: indirectbr
;
; CHECK: lpad.split:
; CHECK-NOT: extractvalue
; CHECK: call i32 @puts

View File

@ -1,66 +0,0 @@
; RUN: opt -winehprepare -S < %s | FileCheck %s
; WinEHPrepare was crashing during phi demotion.
target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-windows-msvc18.0.0"
declare i32 @__C_specific_handler(...)
@str = linkonce_odr unnamed_addr constant [16 x i8] c"caught it! %lx\0A\00", align 1
; Function Attrs: nounwind uwtable
declare void @maycrash()
; Function Attrs: nounwind
declare i32 @printf(i8* nocapture readonly, ...)
; Function Attrs: nounwind uwtable
define void @doit() personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) {
entry:
invoke void @maycrash()
to label %invoke.cont unwind label %lpad
invoke.cont: ; preds = %entry
invoke void @maycrash()
to label %__try.cont unwind label %lpad.1
lpad: ; preds = %entry
%0 = landingpad { i8*, i32 }
catch i8* null
%1 = extractvalue { i8*, i32 } %0, 0
br label %__except
lpad.1: ; preds = %invoke.cont, %lpad
%2 = landingpad { i8*, i32 }
catch i8* null
%3 = extractvalue { i8*, i32 } %2, 0
br label %__except
__except: ; preds = %lpad, %lpad.1
%exn.slot.0 = phi i8* [ %3, %lpad.1 ], [ %1, %lpad ]
%4 = ptrtoint i8* %exn.slot.0 to i64
%5 = trunc i64 %4 to i32
%call = tail call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([16 x i8], [16 x i8]* @str, i64 0, i64 0), i32 %5)
br label %__try.cont
__try.cont: ; preds = %invoke.cont, %__except
ret void
}
; CHECK-LABEL: define void @doit()
; CHECK: landingpad
; CHECK: indirectbr i8* %{{[^,]*}}, [label %[[except_split1:.*]]]
; CHECK: [[except_split1]]:
; CHECK: call i32 @llvm.eh.exceptioncode.old()
; CHECK: br label %__except
;
; CHECK: landingpad
; CHECK: indirectbr i8* %{{[^,]*}}, [label %[[except_split2:.*]]]
; CHECK: [[except_split2]]:
; CHECK: call i32 @llvm.eh.exceptioncode.old()
; CHECK: br label %__except
;
; CHECK: __except:
; CHECK: phi
; CHECK: call i32 (i8*, ...) @printf

View File

@ -1,91 +0,0 @@
; RUN: opt -winehprepare -S < %s | FileCheck %s
; WinEHPrepare was crashing during phi demotion.
target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-windows-msvc18.0.0"
declare i32 @__C_specific_handler(...)
@str = linkonce_odr unnamed_addr constant [16 x i8] c"caught it! %lx\0A\00", align 1
declare void @maycrash()
declare void @finally(i1 %abnormal)
declare i32 @printf(i8* nocapture readonly, ...)
declare i32 @llvm.eh.typeid.for(i8*)
; Function Attrs: nounwind uwtable
define void @doit() personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) {
entry:
invoke void @maycrash()
to label %invoke.cont unwind label %lpad.1
invoke.cont: ; preds = %entry
invoke void @maycrash()
to label %__try.cont unwind label %lpad
lpad: ; preds = %entry
%lp0 = landingpad { i8*, i32 }
cleanup
catch i8* bitcast (i32 (i8*, i8*)* @"\01?filt$0@0@doit@@" to i8*)
%ehptr.0 = extractvalue { i8*, i32 } %lp0, 0
%ehsel.0 = extractvalue { i8*, i32 } %lp0, 1
call void @finally(i1 true)
br label %ehdispatch
lpad.1: ; preds = %invoke.cont, %lpad
%lp1 = landingpad { i8*, i32 }
catch i8* bitcast (i32 (i8*, i8*)* @"\01?filt$0@0@doit@@" to i8*)
%ehptr.1 = extractvalue { i8*, i32 } %lp1, 0
%ehsel.1 = extractvalue { i8*, i32 } %lp1, 1
br label %ehdispatch
ehdispatch:
%ehptr.2 = phi i8* [ %ehptr.0, %lpad ], [ %ehptr.1, %lpad.1 ]
%ehsel.2 = phi i32 [ %ehsel.0, %lpad ], [ %ehsel.1, %lpad.1 ]
%mysel = call i32 @llvm.eh.typeid.for(i8* bitcast (i32 (i8*, i8*)* @"\01?filt$0@0@doit@@" to i8*))
%matches = icmp eq i32 %ehsel.2, %mysel
br i1 %matches, label %__except, label %eh.resume
__except: ; preds = %lpad, %lpad.1
%t4 = ptrtoint i8* %ehptr.2 to i64
%t5 = trunc i64 %t4 to i32
%call = tail call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([16 x i8], [16 x i8]* @str, i64 0, i64 0), i32 %t5)
br label %__try.cont
__try.cont: ; preds = %invoke.cont, %__except
call void @finally(i1 false)
ret void
eh.resume:
%ehvals0 = insertvalue { i8*, i32 } undef, i8* %ehptr.2, 0
%ehvals = insertvalue { i8*, i32 } %ehvals0, i32 %ehsel.2, 1
resume { i8*, i32 } %ehvals
}
define internal i32 @"\01?filt$0@0@doit@@"(i8* %exception_pointers, i8* %frame_pointer) #1 {
entry:
%0 = bitcast i8* %exception_pointers to { i32*, i8* }*
%1 = getelementptr inbounds { i32*, i8* }, { i32*, i8* }* %0, i32 0, i32 0
%2 = load i32*, i32** %1
%3 = load i32, i32* %2
%cmp = icmp eq i32 %3, -1073741819
%4 = zext i1 %cmp to i32
ret i32 %4
}
; CHECK-LABEL: define void @doit()
; CHECK: %lp0 = landingpad { i8*, i32 }
; CHECK-NEXT: cleanup
; CHECK-NEXT: catch i8*
; CHECK-NEXT: call i8* (...) @llvm.eh.actions({{.*}})
; CHECK-NEXT: indirectbr i8* %{{[^,]*}}, [label %__except]
;
; CHECK: %lp1 = landingpad { i8*, i32 }
; CHECK-NEXT: catch i8*
; CHECK-NEXT: call i8* (...) @llvm.eh.actions({{.*}})
; CHECK-NEXT: indirectbr i8* %{{[^,]*}}, [label %__except]
;
; CHECK: __except:
; CHECK: call i32 @llvm.eh.exceptioncode.old()
; CHECK: call i32 (i8*, ...) @printf

View File

@ -1,83 +0,0 @@
; RUN: opt -S -winehprepare -mtriple=x86_64-pc-windows-msvc < %s | FileCheck %s
; RUN: opt -S -winehprepare -mtriple=x86_64-pc-windows-coreclr < %s | FileCheck %s
; Check that things work when the mid-level optimizer inlines the finally
; block.
target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
%struct._RTL_CRITICAL_SECTION = type { %struct._RTL_CRITICAL_SECTION_DEBUG*, i32, i32, i8*, i8*, i64 }
%struct._RTL_CRITICAL_SECTION_DEBUG = type { i16, i16, %struct._RTL_CRITICAL_SECTION*, %struct._LIST_ENTRY, i32, i32, i32, i16, i16 }
%struct._LIST_ENTRY = type { %struct._LIST_ENTRY*, %struct._LIST_ENTRY* }
declare i32 @puts(i8*)
declare void @may_crash()
declare i32 @__C_specific_handler(...)
declare i8* @llvm.localrecover(i8*, i8*, i32) #1
declare i8* @llvm.localaddress()
declare void @llvm.localescape(...)
declare dllimport void @EnterCriticalSection(%struct._RTL_CRITICAL_SECTION*)
declare dllimport void @LeaveCriticalSection(%struct._RTL_CRITICAL_SECTION*)
define void @use_finally() personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) {
entry:
invoke void @may_crash()
to label %invoke.cont unwind label %lpad
invoke.cont: ; preds = %entry
%call.i = tail call i32 @puts(i8* null)
ret void
lpad: ; preds = %entry
%0 = landingpad { i8*, i32 }
cleanup
%call.i2 = tail call i32 @puts(i8* null)
resume { i8*, i32 } %0
}
; CHECK-LABEL: define void @use_finally()
; CHECK: invoke void @may_crash()
;
; CHECK: landingpad
; CHECK-NEXT: cleanup
; CHECK-NEXT: call i8* (...) @llvm.eh.actions(i32 0, void (i8*, i8*)* @use_finally.cleanup)
; CHECK-NEXT: indirectbr i8* %recover, []
; Function Attrs: nounwind uwtable
define i32 @call_may_crash_locked() personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) {
entry:
%p = alloca %struct._RTL_CRITICAL_SECTION, align 8
call void (...) @llvm.localescape(%struct._RTL_CRITICAL_SECTION* %p)
call void @EnterCriticalSection(%struct._RTL_CRITICAL_SECTION* %p)
invoke void @may_crash()
to label %invoke.cont unwind label %lpad
invoke.cont: ; preds = %entry
%tmp2 = call i8* @llvm.localaddress()
%tmp3 = call i8* @llvm.localrecover(i8* bitcast (i32 ()* @call_may_crash_locked to i8*), i8* %tmp2, i32 0) #2
%tmp6 = bitcast i8* %tmp3 to %struct._RTL_CRITICAL_SECTION*
call void @LeaveCriticalSection(%struct._RTL_CRITICAL_SECTION* %tmp6)
ret i32 42
lpad: ; preds = %entry
%tmp7 = landingpad { i8*, i32 }
cleanup
%tmp8 = call i8* @llvm.localaddress()
%tmp9 = call i8* @llvm.localrecover(i8* bitcast (i32 ()* @call_may_crash_locked to i8*), i8* %tmp8, i32 0)
%tmp12 = bitcast i8* %tmp9 to %struct._RTL_CRITICAL_SECTION*
call void @LeaveCriticalSection(%struct._RTL_CRITICAL_SECTION* %tmp12)
resume { i8*, i32 } %tmp7
}
; CHECK-LABEL: define i32 @call_may_crash_locked()
; CHECK: invoke void @may_crash()
;
; CHECK: landingpad
; CHECK-NEXT: cleanup
; CHECK-NEXT: call i8* (...) @llvm.eh.actions(i32 0, void (i8*, i8*)* @call_may_crash_locked.cleanup)
; CHECK-NEXT: indirectbr i8* %recover, []
; CHECK-LABEL: define internal void @call_may_crash_locked.cleanup(i8*, i8*)
; CHECK: %tmp9 = call i8* @llvm.localrecover(i8* bitcast (i32 ()* @call_may_crash_locked to i8*), i8* %1, i32 0)
; CHECK: %tmp12 = bitcast i8* %tmp9 to %struct._RTL_CRITICAL_SECTION*
; CHECK: call void @LeaveCriticalSection(%struct._RTL_CRITICAL_SECTION* %tmp12)

View File

@ -1,172 +0,0 @@
; RUN: opt -S -winehprepare < %s | FileCheck %s
; Test case based on this code:
;
; extern "C" int _abnormal_termination();
; #pragma intrinsic(_abnormal_termination)
; extern "C" int printf(const char *, ...);
; extern "C" void may_crash() {
; *(volatile int *)0 = 42;
; }
; int main() {
; int myres = 0;
; __try {
; __try {
; may_crash();
; } __finally {
; printf("inner finally %d\n", _abnormal_termination());
; may_crash();
; }
; } __finally {
; printf("outer finally %d\n", _abnormal_termination());
; }
; }
;
; Note that if the inner finally crashes, the outer finally still runs. There
; is nothing like a std::terminate call in this situation.
target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32"
target triple = "i686-pc-windows-msvc"
$"\01??_C@_0BC@LHHILCPN@outer?5finally?5?$CFd?6?$AA@" = comdat any
$"\01??_C@_0BC@JELAHKN@inner?5finally?5?$CFd?6?$AA@" = comdat any
@"\01??_C@_0BC@LHHILCPN@outer?5finally?5?$CFd?6?$AA@" = linkonce_odr unnamed_addr constant [18 x i8] c"outer finally %d\0A\00", comdat, align 1
@"\01??_C@_0BC@JELAHKN@inner?5finally?5?$CFd?6?$AA@" = linkonce_odr unnamed_addr constant [18 x i8] c"inner finally %d\0A\00", comdat, align 1
; Function Attrs: nounwind
define void @may_crash() #0 {
entry:
store volatile i32 42, i32* null, align 4
ret void
}
; Function Attrs: nounwind
define i32 @main() #0 personality i8* bitcast (i32 (...)* @_except_handler3 to i8*) {
entry:
%myres = alloca i32, align 4
%exn.slot = alloca i8*
%ehselector.slot = alloca i32
store i32 0, i32* %myres, align 4
invoke void @may_crash() #4
to label %invoke.cont unwind label %lpad
invoke.cont: ; preds = %entry
%0 = call i8* @llvm.frameaddress(i32 0)
invoke void @"\01?fin$1@0@main@@"(i8 zeroext 0, i8* %0) #4
to label %invoke.cont.2 unwind label %lpad.1
invoke.cont.2: ; preds = %invoke.cont
%1 = call i8* @llvm.frameaddress(i32 0)
call void @"\01?fin$0@0@main@@"(i8 zeroext 0, i8* %1)
ret i32 0
lpad: ; preds = %entry
%2 = landingpad { i8*, i32 }
cleanup
%3 = extractvalue { i8*, i32 } %2, 0
store i8* %3, i8** %exn.slot
%4 = extractvalue { i8*, i32 } %2, 1
store i32 %4, i32* %ehselector.slot
%5 = call i8* @llvm.frameaddress(i32 0)
invoke void @"\01?fin$1@0@main@@"(i8 zeroext 1, i8* %5) #4
to label %invoke.cont.3 unwind label %lpad.1
lpad.1: ; preds = %lpad, %invoke.cont
%6 = landingpad { i8*, i32 }
cleanup
%7 = extractvalue { i8*, i32 } %6, 0
store i8* %7, i8** %exn.slot
%8 = extractvalue { i8*, i32 } %6, 1
store i32 %8, i32* %ehselector.slot
br label %ehcleanup
invoke.cont.3: ; preds = %lpad
br label %ehcleanup
ehcleanup: ; preds = %invoke.cont.3, %lpad.1
%9 = call i8* @llvm.frameaddress(i32 0)
call void @"\01?fin$0@0@main@@"(i8 zeroext 1, i8* %9)
br label %eh.resume
eh.resume: ; preds = %ehcleanup
%exn = load i8*, i8** %exn.slot
%sel = load i32, i32* %ehselector.slot
%lpad.val = insertvalue { i8*, i32 } undef, i8* %exn, 0
%lpad.val.4 = insertvalue { i8*, i32 } %lpad.val, i32 %sel, 1
resume { i8*, i32 } %lpad.val.4
}
; CHECK-LABEL: define i32 @main()
; CHECK: invoke void @may_crash()
;
; CHECK: landingpad { i8*, i32 }
; CHECK-NEXT: cleanup
; CHECK-NEXT: call i8* (...) @llvm.eh.actions(i32 0, void ()* @main.cleanup)
; CHECK-NEXT: indirectbr
;
; CHECK: landingpad { i8*, i32 }
; CHECK-NEXT: cleanup
; CHECK-NEXT: call i8* (...) @llvm.eh.actions(i32 0, void ()* @main.cleanup.1)
; CHECK-NEXT: indirectbr
; CHECK-LABEL: define internal void @main.cleanup()
; CHECK: call i8* @llvm.frameaddress(i32 1)
; CHECK: call i8* @llvm.x86.seh.recoverfp(i8* bitcast (i32 ()* @main to i8*), i8* %{{.*}})
; CHECK: call void @"\01?fin$1@0@main@@"(i8 zeroext 1, i8* %{{.*}})
; CHECK: call void @"\01?fin$0@0@main@@"(i8 zeroext 1, i8* %{{.*}})
; CHECK-LABEL: define internal void @main.cleanup.1()
; CHECK: call i8* @llvm.frameaddress(i32 1)
; CHECK: call i8* @llvm.x86.seh.recoverfp(i8* bitcast (i32 ()* @main to i8*), i8* %{{.*}})
; CHECK: call void @"\01?fin$0@0@main@@"(i8 zeroext 1, i8* %{{.*}})
; Function Attrs: noinline nounwind
define internal void @"\01?fin$0@0@main@@"(i8 zeroext %abnormal_termination, i8* %frame_pointer) #1 {
entry:
%frame_pointer.addr = alloca i8*, align 4
%abnormal_termination.addr = alloca i8, align 1
%0 = call i8* @llvm.frameaddress(i32 1)
%1 = call i8* @llvm.x86.seh.recoverfp(i8* bitcast (i32 ()* @main to i8*), i8* %0)
store i8* %frame_pointer, i8** %frame_pointer.addr, align 4
store i8 %abnormal_termination, i8* %abnormal_termination.addr, align 1
%2 = zext i8 %abnormal_termination to i32
%call = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([18 x i8], [18 x i8]* @"\01??_C@_0BC@LHHILCPN@outer?5finally?5?$CFd?6?$AA@", i32 0, i32 0), i32 %2)
ret void
}
; Function Attrs: nounwind readnone
declare i8* @llvm.frameaddress(i32) #2
; Function Attrs: nounwind readnone
declare i8* @llvm.x86.seh.recoverfp(i8*, i8*) #2
declare i32 @printf(i8*, ...) #3
; Function Attrs: noinline nounwind
define internal void @"\01?fin$1@0@main@@"(i8 zeroext %abnormal_termination, i8* %frame_pointer) #1 {
entry:
%frame_pointer.addr = alloca i8*, align 4
%abnormal_termination.addr = alloca i8, align 1
%0 = call i8* @llvm.frameaddress(i32 1)
%1 = call i8* @llvm.x86.seh.recoverfp(i8* bitcast (i32 ()* @main to i8*), i8* %0)
store i8* %frame_pointer, i8** %frame_pointer.addr, align 4
store i8 %abnormal_termination, i8* %abnormal_termination.addr, align 1
%2 = zext i8 %abnormal_termination to i32
%call = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([18 x i8], [18 x i8]* @"\01??_C@_0BC@JELAHKN@inner?5finally?5?$CFd?6?$AA@", i32 0, i32 0), i32 %2)
call void @may_crash()
ret void
}
declare i32 @_except_handler3(...)
attributes #0 = { nounwind "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { noinline nounwind "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #2 = { nounwind readnone }
attributes #3 = { "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #4 = { noinline }
!llvm.ident = !{!0}
!0 = !{!"clang version 3.7.0 "}

View File

@ -1,155 +0,0 @@
; RUN: opt -S -winehprepare -mtriple=x86_64-windows-msvc < %s | FileCheck %s
; RUN: opt -S -winehprepare -mtriple=x86_64-windows-coreclr < %s | FileCheck %s
; Test case based on this code:
;
; extern "C" int _abnormal_termination();
; #pragma intrinsic(_abnormal_termination)
; extern "C" int printf(const char *, ...);
; extern "C" void may_crash() {
; *(volatile int *)0 = 42;
; }
; int main() {
; int myres = 0;
; __try {
; __try {
; may_crash();
; } __finally {
; printf("inner finally %d\n", _abnormal_termination());
; may_crash();
; }
; } __finally {
; printf("outer finally %d\n", _abnormal_termination());
; }
; }
;
; Note that if the inner finally crashes, the outer finally still runs. There
; is nothing like a std::terminate call in this situation.
target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
@str_outer_finally = linkonce_odr unnamed_addr constant [18 x i8] c"outer finally %d\0A\00", align 1
@str_inner_finally = linkonce_odr unnamed_addr constant [18 x i8] c"inner finally %d\0A\00", align 1
; Function Attrs: nounwind uwtable
define void @may_crash() #0 {
entry:
store volatile i32 42, i32* null, align 4
ret void
}
; Function Attrs: uwtable
define i32 @main() #1 personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) {
entry:
%myres = alloca i32, align 4
%exn.slot = alloca i8*
%ehselector.slot = alloca i32
store i32 0, i32* %myres, align 4
invoke void @may_crash() #4
to label %invoke.cont unwind label %lpad
invoke.cont: ; preds = %entry
%0 = call i8* @llvm.localaddress()
invoke void @"\01?fin$1@0@main@@"(i1 zeroext false, i8* %0) #4
to label %invoke.cont2 unwind label %lpad1
invoke.cont2: ; preds = %invoke.cont
%1 = call i8* @llvm.localaddress()
call void @"\01?fin$0@0@main@@"(i1 zeroext false, i8* %1)
ret i32 0
lpad: ; preds = %entry
%2 = landingpad { i8*, i32 }
cleanup
%3 = extractvalue { i8*, i32 } %2, 0
store i8* %3, i8** %exn.slot
%4 = extractvalue { i8*, i32 } %2, 1
store i32 %4, i32* %ehselector.slot
%5 = call i8* @llvm.localaddress()
invoke void @"\01?fin$1@0@main@@"(i1 zeroext true, i8* %5) #4
to label %invoke.cont3 unwind label %lpad1
lpad1: ; preds = %lpad, %invoke.cont
%6 = landingpad { i8*, i32 }
cleanup
%7 = extractvalue { i8*, i32 } %6, 0
store i8* %7, i8** %exn.slot
%8 = extractvalue { i8*, i32 } %6, 1
store i32 %8, i32* %ehselector.slot
br label %ehcleanup
invoke.cont3: ; preds = %lpad
br label %ehcleanup
ehcleanup: ; preds = %invoke.cont3, %lpad1
%9 = call i8* @llvm.localaddress()
call void @"\01?fin$0@0@main@@"(i1 zeroext true, i8* %9)
br label %eh.resume
eh.resume: ; preds = %ehcleanup
%exn = load i8*, i8** %exn.slot
%sel = load i32, i32* %ehselector.slot
%lpad.val = insertvalue { i8*, i32 } undef, i8* %exn, 0
%lpad.val4 = insertvalue { i8*, i32 } %lpad.val, i32 %sel, 1
resume { i8*, i32 } %lpad.val4
}
; CHECK-NOT: define internal void @
; CHECK-LABEL: define i32 @main()
; CHECK: invoke void @may_crash()
;
; CHECK: landingpad { i8*, i32 }
; CHECK-NEXT: cleanup
; CHECK-NEXT: call i8* (...) @llvm.eh.actions(i32 0, void (i1, i8*)* @"\01?fin$1@0@main@@", i32 0, void (i1, i8*)* @"\01?fin$0@0@main@@")
; CHECK-NEXT: indirectbr
;
; CHECK: landingpad { i8*, i32 }
; CHECK-NEXT: cleanup
; CHECK-NEXT: call i8* (...) @llvm.eh.actions(i32 0, void (i1, i8*)* @"\01?fin$0@0@main@@")
; CHECK-NEXT: indirectbr
; There should not be any *new* cleanup helpers, just the existing ones.
; CHECK-NOT: define internal void @
; CHECK: define internal void @"\01?fin$0@0@main@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)
; CHECK-NOT: define internal void @
; CHECK: define internal void @"\01?fin$1@0@main@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)
; CHECK-NOT: define internal void @
define internal void @"\01?fin$0@0@main@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer) #2 {
entry:
%frame_pointer.addr = alloca i8*, align 8
%abnormal_termination.addr = alloca i8, align 1
store i8* %frame_pointer, i8** %frame_pointer.addr, align 8
%frombool = zext i1 %abnormal_termination to i8
store i8 %frombool, i8* %abnormal_termination.addr, align 1
%0 = zext i1 %abnormal_termination to i32
%call = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([18 x i8], [18 x i8]* @str_outer_finally, i32 0, i32 0), i32 %0)
ret void
}
declare i32 @printf(i8*, ...) #2
define internal void @"\01?fin$1@0@main@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer) #2 {
entry:
%frame_pointer.addr = alloca i8*, align 8
%abnormal_termination.addr = alloca i8, align 1
store i8* %frame_pointer, i8** %frame_pointer.addr, align 8
%frombool = zext i1 %abnormal_termination to i8
store i8 %frombool, i8* %abnormal_termination.addr, align 1
%0 = zext i1 %abnormal_termination to i32
%call = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([18 x i8], [18 x i8]* @str_inner_finally, i32 0, i32 0), i32 %0)
call void @may_crash()
ret void
}
declare i32 @__C_specific_handler(...)
; Function Attrs: nounwind readnone
declare i8* @llvm.localaddress() #3
attributes #0 = { nounwind uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #2 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #3 = { nounwind readnone }
attributes #4 = { noinline }

View File

@ -1,86 +0,0 @@
; RUN: llc -mtriple=x86_64-pc-windows-msvc < %s | FileCheck %s
; RUN: llc -mtriple=x86_64-pc-windows-coreclr < %s | FileCheck %s
; Test case based on this code:
; extern "C" unsigned long _exception_code();
; extern "C" int filt(unsigned long);
; extern "C" void g();
; extern "C" void do_except() {
; __try {
; g();
; } __except(filt(_exception_code())) {
; }
; }
target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
; Function Attrs: uwtable
define void @do_except() #0 personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) {
entry:
call void (...) @llvm.localescape()
invoke void @g() #5
to label %__try.cont unwind label %lpad1
lpad1: ; preds = %entry
%ehvals = landingpad { i8*, i32 }
catch i8* bitcast (i32 (i8*, i8*)* @"\01?filt$0@0@do_except@@" to i8*)
%recover = call i8* (...) @llvm.eh.actions(i32 1, i8* bitcast (i32 (i8*, i8*)* @"\01?filt$0@0@do_except@@" to i8*), i32 -1, i8* blockaddress(@do_except, %__try.cont))
indirectbr i8* %recover, [label %__try.cont]
__try.cont: ; preds = %lpad1, %entry
ret void
}
; CHECK-LABEL: do_except:
; CHECK: .seh_handler __C_specific_handler
; CHECK-NOT: jmpq *
; CHECK: .seh_handlerdata
; CHECK-NEXT: .text
; CHECK: .seh_endproc
; CHECK: .section .xdata,"dr"
; CHECK-NEXT: .long 1
; CHECK-NEXT: .long .Ltmp{{.*}}
; CHECK-NEXT: .long .Ltmp{{.*}}
; CHECK-NEXT: .long "?filt$0@0@do_except@@"@IMGREL
; CHECK-NEXT: .long .Ltmp{{.*}}@IMGREL
; Function Attrs: noinline nounwind
define internal i32 @"\01?filt$0@0@do_except@@"(i8* nocapture readonly %exception_pointers, i8* nocapture readnone %frame_pointer) #1 {
entry:
%0 = bitcast i8* %exception_pointers to i32**
%1 = load i32*, i32** %0, align 8
%2 = load i32, i32* %1, align 4
%call = tail call i32 @filt(i32 %2) #4
ret i32 %call
}
declare i32 @filt(i32) #2
declare void @g() #2
declare i32 @__C_specific_handler(...)
; Function Attrs: nounwind readnone
declare i32 @llvm.eh.typeid.for(i8*) #3
; Function Attrs: nounwind
declare i8* @llvm.eh.actions(...) #4
; Function Attrs: nounwind
declare void @llvm.localescape(...) #4
; Function Attrs: nounwind readnone
declare i8* @llvm.localrecover(i8*, i8*, i32) #3
attributes #0 = { uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "unsafe-fp-math"="false" "use-soft-float"="false" "wineh-parent"="do_except" }
attributes #1 = { noinline nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #2 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #3 = { nounwind readnone }
attributes #4 = { nounwind }
attributes #5 = { noinline }
!llvm.module.flags = !{!0}
!llvm.ident = !{!1}
!0 = !{i32 1, !"PIC Level", i32 2}
!1 = !{!"clang version 3.7.0 "}

View File

@ -1,66 +0,0 @@
; RUN: opt -S -winehprepare -mtriple=x86_64-pc-windows-msvc < %s | FileCheck %s
; RUN: opt -S -winehprepare -mtriple=x86_64-pc-windows-coreclr < %s | FileCheck %s
target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
declare void @might_crash(i8* %ehptr)
declare i32 @filt()
declare void @cleanup()
declare i32 @__C_specific_handler(...)
declare i32 @llvm.eh.typeid.for(i8*)
define void @resume_phi() personality i32 (...)* @__C_specific_handler {
entry:
invoke void @might_crash(i8* null)
to label %return unwind label %lpad1
lpad1:
%ehvals1 = landingpad { i8*, i32 }
catch i32 ()* @filt
%ehptr1 = extractvalue { i8*, i32 } %ehvals1, 0
%ehsel1 = extractvalue { i8*, i32 } %ehvals1, 1
%filt_sel = tail call i32 @llvm.eh.typeid.for(i8* bitcast (i32 ()* @filt to i8*))
%matches = icmp eq i32 %ehsel1, %filt_sel
br i1 %matches, label %__except, label %eh.resume
__except:
invoke void @might_crash(i8* %ehptr1)
to label %return unwind label %lpad2
lpad2:
%ehvals2 = landingpad { i8*, i32 }
cleanup
%ehptr2 = extractvalue { i8*, i32 } %ehvals2, 0
%ehsel2 = extractvalue { i8*, i32 } %ehvals2, 1
call void @cleanup()
br label %eh.resume
return:
ret void
eh.resume:
%ehptr.phi = phi i8* [ %ehptr1, %lpad1 ], [ %ehptr2, %lpad2 ]
%ehsel.phi = phi i32 [ %ehsel1, %lpad1 ], [ %ehsel2, %lpad2 ]
%ehval.phi1 = insertvalue { i8*, i32 } undef, i8* %ehptr.phi, 0
%ehval.phi2 = insertvalue { i8*, i32 } %ehval.phi1, i32 %ehsel.phi, 1
resume { i8*, i32 } %ehval.phi2
}
; CHECK-LABEL: define void @resume_phi()
; CHECK: invoke void @might_crash(i8* null)
; CHECK: landingpad { i8*, i32 }
; CHECK-NEXT: catch i32 ()* @filt
; CHECK-NEXT: call i8* (...) @llvm.eh.actions(
; CHECK-SAME: i32 1, i8* bitcast (i32 ()* @filt to i8*), i32 -1, i8* blockaddress(@resume_phi, %__except))
; CHECK-NEXT: indirectbr {{.*}} [label %__except]
;
; CHECK: __except:
; CHECK: call i32 @llvm.eh.exceptioncode.old()
; CHECK: invoke void @might_crash(i8* %{{.*}})
; CHECK: landingpad { i8*, i32 }
; CHECK-NEXT: cleanup
; CHECK-NEXT: call i8* (...) @llvm.eh.actions(i32 0, void (i8*, i8*)* @resume_phi.cleanup)
; CHECK-NEXT: indirectbr {{.*}} []
; CHECK-LABEL: define internal void @resume_phi.cleanup(i8*, i8*)
; CHECK: call void @cleanup()

View File

@ -1,235 +0,0 @@
; RUN: opt -S -winehprepare -mtriple=x86_64-windows-msvc < %s \
; RUN: | FileCheck %s --check-prefix=CHECK --check-prefix=X64
; RUN: opt -S -winehprepare -mtriple=x86_64-windows-coreclr < %s \
; RUN: | FileCheck %s --check-prefix=CHECK --check-prefix=X64
; This test should also pass in 32-bit using _except_handler3.
; RUN: sed -e 's/__C_specific_handler/_except_handler3/' %s \
; RUN: | opt -S -winehprepare -mtriple=i686-windows-msvc \
; RUN: | FileCheck %s --check-prefix=CHECK --check-prefix=X86
declare void @cleanup()
declare i32 @filt()
declare void @might_crash()
declare i32 @__C_specific_handler(...)
declare i32 @llvm.eh.typeid.for(i8*)
define i32 @simple_except_store() personality i32 (...)* @__C_specific_handler {
entry:
%retval = alloca i32
store i32 0, i32* %retval
invoke void @might_crash()
to label %return unwind label %lpad
lpad:
%ehvals = landingpad { i8*, i32 }
catch i32 ()* @filt
%sel = extractvalue { i8*, i32 } %ehvals, 1
%filt_sel = tail call i32 @llvm.eh.typeid.for(i8* bitcast (i32 ()* @filt to i8*))
%matches = icmp eq i32 %sel, %filt_sel
br i1 %matches, label %__except, label %eh.resume
__except:
store i32 1, i32* %retval
br label %return
return:
%r = load i32, i32* %retval
ret i32 %r
eh.resume:
resume { i8*, i32 } %ehvals
}
; CHECK-LABEL: define i32 @simple_except_store()
; CHECK: landingpad { i8*, i32 }
; CHECK-NEXT: catch i32 ()* @filt
; CHECK-NEXT: call i8* (...) @llvm.eh.actions(i32 1, i8* bitcast (i32 ()* @filt to i8*), i32 -1, i8* blockaddress(@simple_except_store, %__except))
; CHECK-NEXT: indirectbr {{.*}} [label %__except]
define i32 @catch_all() personality i32 (...)* @__C_specific_handler {
entry:
%retval = alloca i32
store i32 0, i32* %retval
invoke void @might_crash()
to label %return unwind label %lpad
lpad:
%ehvals = landingpad { i8*, i32 }
catch i8* null
store i32 1, i32* %retval
br label %return
return:
%r = load i32, i32* %retval
ret i32 %r
}
; CHECK-LABEL: define i32 @catch_all()
; CHECK: landingpad { i8*, i32 }
; CHECK-NEXT: catch i8* null
; CHECK-NEXT: call i8* (...) @llvm.eh.actions(i32 1, i8* null, i32 -1, i8* blockaddress(@catch_all, %lpad.split))
; CHECK-NEXT: indirectbr {{.*}} [label %lpad.split]
;
; CHECK: lpad.split:
; CHECK: store i32 1, i32* %retval
define i32 @except_phi() personality i32 (...)* @__C_specific_handler {
entry:
invoke void @might_crash()
to label %return unwind label %lpad
lpad:
%ehvals = landingpad { i8*, i32 }
catch i32 ()* @filt
%sel = extractvalue { i8*, i32 } %ehvals, 1
%filt_sel = tail call i32 @llvm.eh.typeid.for(i8* bitcast (i32 ()* @filt to i8*))
%matches = icmp eq i32 %sel, %filt_sel
br i1 %matches, label %return, label %eh.resume
return:
%r = phi i32 [0, %entry], [1, %lpad]
ret i32 %r
eh.resume:
resume { i8*, i32 } %ehvals
}
; CHECK-LABEL: define i32 @except_phi()
; CHECK: landingpad { i8*, i32 }
; CHECK-NEXT: catch i32 ()* @filt
; CHECK-NEXT: call i8* (...) @llvm.eh.actions(i32 1, i8* bitcast (i32 ()* @filt to i8*), i32 -1, i8* blockaddress(@except_phi, %lpad.return_crit_edge))
; CHECK-NEXT: indirectbr {{.*}} [label %lpad.return_crit_edge]
;
; CHECK: lpad.return_crit_edge:
; CHECK: br label %return
;
; CHECK: return:
; CHECK-NEXT: %r = phi i32 [ 0, %entry ], [ 1, %lpad.return_crit_edge ]
; CHECK-NEXT: ret i32 %r
define i32 @except_join() personality i32 (...)* @__C_specific_handler {
entry:
invoke void @might_crash()
to label %return unwind label %lpad
lpad:
%ehvals = landingpad { i8*, i32 }
catch i32 ()* @filt
%sel = extractvalue { i8*, i32 } %ehvals, 1
%filt_sel = tail call i32 @llvm.eh.typeid.for(i8* bitcast (i32 ()* @filt to i8*))
%matches = icmp eq i32 %sel, %filt_sel
br i1 %matches, label %return, label %eh.resume
return:
ret i32 0
eh.resume:
resume { i8*, i32 } %ehvals
}
; CHECK-LABEL: define i32 @except_join()
; CHECK: landingpad { i8*, i32 }
; CHECK-NEXT: catch i32 ()* @filt
; CHECK-NEXT: call i8* (...) @llvm.eh.actions(i32 1, i8* bitcast (i32 ()* @filt to i8*), i32 -1, i8* blockaddress(@except_join, %lpad.return_crit_edge))
; CHECK-NEXT: indirectbr {{.*}} [label %lpad.return_crit_edge]
;
; CHECK: lpad.return_crit_edge:
; CHECK: br label %return
;
; CHECK: return:
; CHECK-NEXT: ret i32 0
define i32 @lpad_phi() personality i32 (...)* @__C_specific_handler {
entry:
invoke void @might_crash()
to label %cont unwind label %lpad
cont:
invoke void @might_crash()
to label %return unwind label %lpad
lpad:
%ncalls.1 = phi i32 [ 0, %entry ], [ 1, %cont ]
%ehvals = landingpad { i8*, i32 }
catch i32 ()* @filt
%sel = extractvalue { i8*, i32 } %ehvals, 1
%filt_sel = tail call i32 @llvm.eh.typeid.for(i8* bitcast (i32 ()* @filt to i8*))
%matches = icmp eq i32 %sel, %filt_sel
br i1 %matches, label %return, label %eh.resume
return:
%r = phi i32 [2, %cont], [%ncalls.1, %lpad]
ret i32 %r
eh.resume:
resume { i8*, i32 } %ehvals
}
; CHECK-LABEL: define i32 @lpad_phi()
; CHECK: alloca i32
; CHECK: store i32 0, i32*
; CHECK: invoke void @might_crash()
; CHECK: store i32 1, i32*
; CHECK: invoke void @might_crash()
; CHECK: landingpad { i8*, i32 }
; CHECK-NEXT: cleanup
; CHECK-NEXT: catch i32 ()* @filt
; CHECK-NEXT: call i8* (...) @llvm.eh.actions(i32 0, void ({{.*}})* @lpad_phi.cleanup, i32 1, i8* bitcast (i32 ()* @filt to i8*), i32 -1, i8* blockaddress(@lpad_phi, %lpad.return_crit_edge))
; CHECK-NEXT: indirectbr {{.*}} [label %lpad.return_crit_edge]
;
; CHECK: lpad.return_crit_edge:
; CHECK: load i32, i32*
; CHECK: br label %return
;
; CHECK: return:
; CHECK-NEXT: %r = phi i32 [ 2, %cont ], [ %{{.*}}, %lpad.return_crit_edge ]
; CHECK-NEXT: ret i32 %r
define i32 @cleanup_and_except() personality i32 (...)* @__C_specific_handler {
entry:
invoke void @might_crash()
to label %return unwind label %lpad
lpad:
%ehvals = landingpad { i8*, i32 }
cleanup
catch i32 ()* @filt
call void @cleanup()
%sel = extractvalue { i8*, i32 } %ehvals, 1
%filt_sel = tail call i32 @llvm.eh.typeid.for(i8* bitcast (i32 ()* @filt to i8*))
%matches = icmp eq i32 %sel, %filt_sel
br i1 %matches, label %return, label %eh.resume
return:
%r = phi i32 [0, %entry], [1, %lpad]
ret i32 %r
eh.resume:
resume { i8*, i32 } %ehvals
}
; CHECK-LABEL: define i32 @cleanup_and_except()
; CHECK: landingpad { i8*, i32 }
; CHECK-NEXT: cleanup
; CHECK-NEXT: catch i32 ()* @filt
; CHECK-NEXT: call i8* (...) @llvm.eh.actions(
; CHECK: i32 0, void ({{.*}})* @cleanup_and_except.cleanup,
; CHECK: i32 1, i8* bitcast (i32 ()* @filt to i8*), i32 -1, i8* blockaddress(@cleanup_and_except, %lpad.return_crit_edge))
; CHECK-NEXT: indirectbr {{.*}} [label %lpad.return_crit_edge]
;
; CHECK: lpad.return_crit_edge:
; CHECK: br label %return
;
; CHECK: return:
; CHECK-NEXT: %r = phi i32 [ 0, %entry ], [ 1, %lpad.return_crit_edge ]
; CHECK-NEXT: ret i32 %r
; FIXME: This cleanup is an artifact of bad demotion.
; X64-LABEL: define internal void @lpad_phi.cleanup(i8*, i8*)
; X86-LABEL: define internal void @lpad_phi.cleanup()
; X86: call i8* @llvm.frameaddress(i32 1)
; CHECK: call i8* @llvm.localrecover({{.*}})
; CHECK: load i32
; CHECK: store i32 %{{.*}}, i32*