MachineBasicBlock *LandingPadBlock; // Landing pad block.
SmallVector<MCSymbol*, 1> BeginLabels; // Labels prior to invoke.
SmallVector<MCSymbol*, 1> EndLabels; // Labels after invoke.
- SmallVector<MCSymbol*, 1> ClauseLabels; // Labels for each clause.
MCSymbol *LandingPadLabel; // Label at beginning of landing pad.
const Function *Personality; // Personality function.
std::vector<int> TypeIds; // List of type ids (filters negative)
///
void addCleanup(MachineBasicBlock *LandingPad);
- /// Add a clause for a landing pad. Returns a new label for the clause. This
- /// is used by EH schemes that have more than one landing pad. In this case,
- /// each clause gets its own basic block.
- MCSymbol *addClauseForLandingPad(MachineBasicBlock *LandingPad);
-
/// getTypeIDFor - Return the type id for the specified typeinfo. This is
/// function wide.
unsigned getTypeIDFor(const GlobalValue *TI);
for (unsigned J = NumShared, M = TypeIds.size(); J != M; ++J) {
int TypeID = TypeIds[J];
assert(-1 - TypeID < (int)FilterOffsets.size() && "Unknown filter id!");
- int ValueForTypeID =
- isFilterEHSelector(TypeID) ? FilterOffsets[-1 - TypeID] : TypeID;
+ int ValueForTypeID = TypeID < 0 ? FilterOffsets[-1 - TypeID] : TypeID;
unsigned SizeTypeID = getSLEB128Size(ValueForTypeID);
int NextAction = SizeAction ? -(SizeAction + SizeTypeID) : 0;
CallSiteEntry Site = {
BeginLabel,
LastLabel,
- LandingPad,
+ LandingPad->LandingPadLabel,
FirstActions[P.PadIndex]
};
// Try to merge with the previous call-site. SJLJ doesn't do this
if (PreviousIsInvoke && !IsSJLJ) {
CallSiteEntry &Prev = CallSites.back();
- if (Site.LPad == Prev.LPad && Site.Action == Prev.Action) {
+ if (Site.PadLabel == Prev.PadLabel && Site.Action == Prev.Action) {
// Extend the range of the previous entry.
Prev.EndLabel = Site.EndLabel;
continue;
// Offset of the landing pad, counted in 16-byte bundles relative to the
// @LPStart address.
- if (!S.LPad) {
+ if (!S.PadLabel) {
if (VerboseAsm)
Asm->OutStreamer.AddComment(" has no landing pad");
Asm->OutStreamer.EmitIntValue(0, 4/*size*/);
} else {
if (VerboseAsm)
Asm->OutStreamer.AddComment(Twine(" jumps to ") +
- S.LPad->LandingPadLabel->getName());
- Asm->EmitLabelDifference(S.LPad->LandingPadLabel, EHFuncBeginSym, 4);
+ S.PadLabel->getName());
+ Asm->EmitLabelDifference(S.PadLabel, EHFuncBeginSym, 4);
}
// Offset of the first associated action record, relative to the start of
unsigned TypeID = *I;
if (VerboseAsm) {
--Entry;
- if (isFilterEHSelector(TypeID))
+ if (TypeID != 0)
Asm->OutStreamer.AddComment("FilterInfo " + Twine(Entry));
}
class MachineInstr;
class MachineFunction;
class AsmPrinter;
-class MCSymbol;
-class MCSymbolRefExpr;
template <typename T>
class SmallVectorImpl;
/// Structure describing an entry in the call-site table.
struct CallSiteEntry {
// The 'try-range' is BeginLabel .. EndLabel.
- MCSymbol *BeginLabel; // Null indicates the start of the function.
- MCSymbol *EndLabel; // Null indicates the end of the function.
+ MCSymbol *BeginLabel; // zero indicates the start of the function.
+ MCSymbol *EndLabel; // zero indicates the end of the function.
- // LPad contains the landing pad start labels.
- const LandingPadInfo *LPad; // Null indicates that there is no landing pad.
+ // The landing pad starts at PadLabel.
+ MCSymbol *PadLabel; // zero indicates that there is no landing pad.
unsigned Action;
};
virtual void emitTypeInfos(unsigned TTypeEncoding);
- // Helpers for for identifying what kind of clause an EH typeid or selector
- // corresponds to. Negative selectors are for filter clauses, the zero
- // selector is for cleanups, and positive selectors are for catch clauses.
- static bool isFilterEHSelector(int Selector) { return Selector < 0; }
- static bool isCleanupEHSelector(int Selector) { return Selector == 0; }
- static bool isCatchEHSelector(int Selector) { return Selector > 0; }
-
public:
EHStreamer(AsmPrinter *A);
virtual ~EHStreamer();
if (shouldEmitPersonality) {
Asm->OutStreamer.PushSection();
-
- // Emit an UNWIND_INFO struct describing the prologue.
Asm->OutStreamer.EmitWinEHHandlerData();
-
- // Emit either MSVC-compatible tables or the usual Itanium-style LSDA after
- // the UNWIND_INFO struct.
- if (Asm->MAI->getExceptionHandlingType() == ExceptionHandling::MSVC) {
- const Function *Per = MMI->getPersonalities()[MMI->getPersonalityIndex()];
- if (Per->getName() == "__C_specific_handler")
- emitCSpecificHandlerTable();
- else
- report_fatal_error(Twine("unexpected personality function: ") +
- Per->getName());
- } else {
- emitExceptionTable();
- }
-
+ emitExceptionTable();
Asm->OutStreamer.PopSection();
}
Asm->OutStreamer.EmitWinCFIEndProc();
}
-
-const MCSymbolRefExpr *Win64Exception::createImageRel32(const MCSymbol *Value) {
- return MCSymbolRefExpr::Create(Value, MCSymbolRefExpr::VK_COFF_IMGREL32,
- Asm->OutContext);
-}
-
-/// Emit the language-specific data that __C_specific_handler expects. This
-/// handler lives in the x64 Microsoft C runtime and allows catching or cleaning
-/// up after faults with __try, __except, and __finally. The typeinfo values
-/// are not really RTTI data, but pointers to filter functions that return an
-/// integer (1, 0, or -1) indicating how to handle the exception. For __finally
-/// blocks and other cleanups, the landing pad label is zero, and the filter
-/// function is actually a cleanup handler with the same prototype. A catch-all
-/// entry is modeled with a null filter function field and a non-zero landing
-/// pad label.
-///
-/// Possible filter function return values:
-/// EXCEPTION_EXECUTE_HANDLER (1):
-/// Jump to the landing pad label after cleanups.
-/// EXCEPTION_CONTINUE_SEARCH (0):
-/// Continue searching this table or continue unwinding.
-/// EXCEPTION_CONTINUE_EXECUTION (-1):
-/// Resume execution at the trapping PC.
-///
-/// Inferred table structure:
-/// struct Table {
-/// int NumEntries;
-/// struct Entry {
-/// imagerel32 LabelStart;
-/// imagerel32 LabelEnd;
-/// imagerel32 FilterOrFinally; // Zero means catch-all.
-/// imagerel32 LabelLPad; // Zero means __finally.
-/// } Entries[NumEntries];
-/// };
-void Win64Exception::emitCSpecificHandlerTable() {
- const std::vector<LandingPadInfo> &PadInfos = MMI->getLandingPads();
-
- // 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.
- 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->GetTempSymbol("eh_func_begin", Asm->getFunctionNumber());
- MCSymbol *EHFuncEndSym =
- Asm->GetTempSymbol("eh_func_end", Asm->getFunctionNumber());
-
- // Emit the number of table entries.
- unsigned NumEntries = 0;
- for (const CallSiteEntry &CSE : CallSites) {
- if (!CSE.LPad)
- continue; // Ignore gaps.
- for (int Selector : CSE.LPad->TypeIds) {
- // Ignore C++ filter clauses in SEH.
- // FIXME: Implement cleanup clauses.
- if (isCatchEHSelector(Selector))
- ++NumEntries;
- }
- }
- Asm->OutStreamer.EmitIntValue(NumEntries, 4);
-
- // 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 =
- createImageRel32(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 = MCBinaryExpr::CreateAdd(createImageRel32(CSE.EndLabel),
- MCConstantExpr::Create(1, Asm->OutContext),
- Asm->OutContext);
- } else {
- End = createImageRel32(EHFuncEndSym);
- }
-
- // These aren't really type info globals, they are actually pointers to
- // filter functions ordered by selector. The zero selector is used for
- // cleanups, so slot zero corresponds to selector 1.
- const std::vector<const GlobalValue *> &SelectorToFilter = MMI->getTypeInfos();
-
- // Do a parallel iteration across typeids and clause labels, skipping filter
- // clauses.
- assert(LPad->TypeIds.size() == LPad->ClauseLabels.size());
- for (size_t I = 0, E = LPad->TypeIds.size(); I < E; ++I) {
- // AddLandingPadInfo stores the clauses in reverse, but there is a FIXME
- // to change that.
- int Selector = LPad->TypeIds[E - I - 1];
- MCSymbol *ClauseLabel = LPad->ClauseLabels[I];
-
- // Ignore C++ filter clauses in SEH.
- // FIXME: Implement cleanup clauses.
- if (!isCatchEHSelector(Selector))
- continue;
-
- Asm->OutStreamer.EmitValue(Begin, 4);
- Asm->OutStreamer.EmitValue(End, 4);
- if (isCatchEHSelector(Selector)) {
- assert(unsigned(Selector - 1) < SelectorToFilter.size());
- const GlobalValue *TI = SelectorToFilter[Selector - 1];
- if (TI) // Emit the filter function pointer.
- Asm->OutStreamer.EmitValue(createImageRel32(Asm->getSymbol(TI)), 4);
- else // Otherwise, this is a "catch i8* null", or catch all.
- Asm->OutStreamer.EmitIntValue(0, 4);
- }
- Asm->OutStreamer.EmitValue(createImageRel32(ClauseLabel), 4);
- }
- }
-}
/// Per-function flag to indicate if frame moves info should be emitted.
bool shouldEmitMoves;
- void emitCSpecificHandlerTable();
-
- const MCSymbolRefExpr *createImageRel32(const MCSymbol *Value);
-
public:
//===--------------------------------------------------------------------===//
// Main entry points.
LP.TypeIds.push_back(0);
}
-MCSymbol *
-MachineModuleInfo::addClauseForLandingPad(MachineBasicBlock *LandingPad) {
- MCSymbol *ClauseLabel = Context.CreateTempSymbol();
- LandingPadInfo &LP = getOrCreateLandingPadInfo(LandingPad);
- LP.ClauseLabels.push_back(ClauseLabel);
- return ClauseLabel;
-}
-
/// TidyLandingPads - Remap landing pad labels and remove any deleted landing
/// pads.
void MachineModuleInfo::TidyLandingPads(DenseMap<MCSymbol*, uintptr_t> *LPMap) {
case ExceptionHandling::DwarfCFI:
case ExceptionHandling::ARM:
case ExceptionHandling::ItaniumWinEH:
- case ExceptionHandling::MSVC: // FIXME: Needs preparation.
addPass(createDwarfEHPass(TM));
break;
+ case ExceptionHandling::MSVC: // FIXME: Add preparation.
case ExceptionHandling::None:
addPass(createLowerInvokePass());
// Get the two live-in registers as SDValues. The physregs have already been
// copied into virtual registers.
SDValue Ops[2];
- if (FuncInfo.ExceptionPointerVirtReg) {
- Ops[0] = DAG.getZExtOrTrunc(
- DAG.getCopyFromReg(DAG.getEntryNode(), getCurSDLoc(),
- FuncInfo.ExceptionPointerVirtReg, TLI.getPointerTy()),
- getCurSDLoc(), ValueVTs[0]);
- } else {
- Ops[0] = DAG.getConstant(0, TLI.getPointerTy());
- }
+ Ops[0] = DAG.getZExtOrTrunc(
+ DAG.getCopyFromReg(DAG.getEntryNode(), getCurSDLoc(),
+ FuncInfo.ExceptionPointerVirtReg, TLI.getPointerTy()),
+ getCurSDLoc(), ValueVTs[0]);
Ops[1] = DAG.getZExtOrTrunc(
DAG.getCopyFromReg(DAG.getEntryNode(), getCurSDLoc(),
FuncInfo.ExceptionSelectorVirtReg, TLI.getPointerTy()),
setValue(&LP, Res);
}
-unsigned
-SelectionDAGBuilder::visitLandingPadClauseBB(GlobalValue *ClauseGV,
- MachineBasicBlock *LPadBB) {
- SDValue Chain = getControlRoot();
-
- // Get the typeid that we will dispatch on later.
- const TargetLowering &TLI = DAG.getTargetLoweringInfo();
- const TargetRegisterClass *RC = TLI.getRegClassFor(TLI.getPointerTy());
- unsigned VReg = FuncInfo.MF->getRegInfo().createVirtualRegister(RC);
- unsigned TypeID = DAG.getMachineFunction().getMMI().getTypeIDFor(ClauseGV);
- SDValue Sel = DAG.getConstant(TypeID, TLI.getPointerTy());
- Chain = DAG.getCopyToReg(Chain, getCurSDLoc(), VReg, Sel);
-
- // Branch to the main landing pad block.
- MachineBasicBlock *ClauseMBB = FuncInfo.MBB;
- ClauseMBB->addSuccessor(LPadBB);
- DAG.setRoot(DAG.getNode(ISD::BR, getCurSDLoc(), MVT::Other, Chain,
- DAG.getBasicBlock(LPadBB)));
- return VReg;
-}
-
/// handleSmallSwitchCaseRange - Emit a series of specific tests (suitable for
/// small case ranges).
bool SelectionDAGBuilder::handleSmallSwitchRange(CaseRec& CR,
void visitJumpTable(JumpTable &JT);
void visitJumpTableHeader(JumpTable &JT, JumpTableHeader &JTH,
MachineBasicBlock *SwitchBB);
- unsigned visitLandingPadClauseBB(GlobalValue *ClauseGV,
- MachineBasicBlock *LPadMBB);
private:
// These all get lowered before this pass.
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Analysis/BranchProbabilityInfo.h"
#include "llvm/Analysis/CFG.h"
-#include "llvm/CodeGen/Analysis.h"
#include "llvm/CodeGen/FastISel.h"
#include "llvm/CodeGen/FunctionLoweringInfo.h"
#include "llvm/CodeGen/GCMetadata.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
-#include "llvm/MC/MCAsmInfo.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
void SelectionDAGISel::PrepareEHLandingPad() {
MachineBasicBlock *MBB = FuncInfo->MBB;
- const TargetRegisterClass *PtrRC = TLI->getRegClassFor(TLI->getPointerTy());
-
// Add a label to mark the beginning of the landing pad. Deletion of the
// landing pad can thus be detected via the MachineModuleInfo.
MCSymbol *Label = MF->getMMI().addLandingPad(MBB);
BuildMI(*MBB, FuncInfo->InsertPt, SDB->getCurDebugLoc(), II)
.addSym(Label);
- if (TM.getMCAsmInfo()->getExceptionHandlingType() ==
- ExceptionHandling::MSVC) {
- // Make virtual registers and a series of labels that fill in values for the
- // clauses.
- auto &RI = MF->getRegInfo();
- FuncInfo->ExceptionSelectorVirtReg = RI.createVirtualRegister(PtrRC);
-
- // Get all invoke BBs that will unwind into the clause BBs.
- SmallVector<MachineBasicBlock *, 4> InvokeBBs(MBB->pred_begin(),
- MBB->pred_end());
-
- // Emit separate machine basic blocks with separate labels for each clause
- // before the main landing pad block.
- const BasicBlock *LLVMBB = MBB->getBasicBlock();
- const LandingPadInst *LPadInst = LLVMBB->getLandingPadInst();
- MachineInstrBuilder SelectorPHI = BuildMI(
- *MBB, MBB->begin(), SDB->getCurDebugLoc(), TII->get(TargetOpcode::PHI),
- FuncInfo->ExceptionSelectorVirtReg);
- for (unsigned I = 0, E = LPadInst->getNumClauses(); I != E; ++I) {
- MachineBasicBlock *ClauseBB = MF->CreateMachineBasicBlock(LLVMBB);
- MF->insert(MBB, ClauseBB);
-
- // 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->setIsLandingPad();
-
- GlobalValue *ClauseGV = ExtractTypeInfo(LPadInst->getClause(I));
-
- // Start the BB with a label.
- MCSymbol *ClauseLabel = MF->getMMI().addClauseForLandingPad(MBB);
- BuildMI(*ClauseBB, ClauseBB->begin(), SDB->getCurDebugLoc(), II)
- .addSym(ClauseLabel);
-
- // Construct a simple BB that defines a register with the typeid constant.
- FuncInfo->MBB = ClauseBB;
- FuncInfo->InsertPt = ClauseBB->end();
- unsigned VReg = SDB->visitLandingPadClauseBB(ClauseGV, MBB);
- CurDAG->setRoot(SDB->getRoot());
- SDB->clear();
- CodeGenAndEmitDAG();
-
- // Add the typeid virtual register to the phi in the main landing pad.
- SelectorPHI.addReg(VReg).addMBB(ClauseBB);
- }
-
- // Remove the edge from the invoke to the lpad.
- for (MachineBasicBlock *InvokeBB : InvokeBBs)
- InvokeBB->removeSuccessor(MBB);
-
- // Restore FuncInfo back to its previous state and select the main landing
- // pad block.
- FuncInfo->MBB = MBB;
- FuncInfo->InsertPt = MBB->end();
- return;
- }
-
// Mark exception register as live in.
+ const TargetRegisterClass *PtrRC = TLI->getRegClassFor(TLI->getPointerTy());
if (unsigned Reg = TLI->getExceptionPointerRegister())
FuncInfo->ExceptionPointerVirtReg = MBB->addLiveIn(Reg, PtrRC);
+++ /dev/null
-; RUN: llc -mtriple x86_64-pc-windows-msvc < %s | FileCheck %s
-
-define void @two_invoke_merged() {
-entry:
- invoke void @try_body()
- to label %again unwind label %lpad
-
-again:
- invoke void @try_body()
- to label %done unwind label %lpad
-
-done:
- ret void
-
-lpad:
- %vals = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*)
- catch i8* bitcast (i32 (i8*, i8*)* @filt0 to i8*)
- catch i8* bitcast (i32 (i8*, i8*)* @filt1 to i8*)
- %sel = extractvalue { i8*, i32 } %vals, 1
- call void @use_selector(i32 %sel)
- ret void
-}
-
-; Normal path code
-
-; CHECK-LABEL: {{^}}two_invoke_merged:
-; CHECK: .seh_proc two_invoke_merged
-; CHECK: .seh_handler __C_specific_handler, @unwind, @except
-; CHECK: .Ltmp0:
-; CHECK: callq try_body
-; CHECK-NEXT: .Ltmp1:
-; CHECK: .Ltmp2:
-; CHECK: callq try_body
-; CHECK-NEXT: .Ltmp3:
-; CHECK: retq
-
-; Landing pad code
-
-; CHECK: .Ltmp5:
-; CHECK: movl $1, %ecx
-; CHECK: jmp
-; CHECK: .Ltmp6:
-; CHECK: movl $2, %ecx
-; CHECK: callq use_selector
-
-; CHECK: .seh_handlerdata
-; CHECK-NEXT: .long 2
-; CHECK-NEXT: .long .Ltmp0@IMGREL
-; CHECK-NEXT: .long .Ltmp3@IMGREL+1
-; CHECK-NEXT: .long filt0@IMGREL
-; CHECK-NEXT: .long .Ltmp5@IMGREL
-; CHECK-NEXT: .long .Ltmp0@IMGREL
-; CHECK-NEXT: .long .Ltmp3@IMGREL+1
-; CHECK-NEXT: .long filt1@IMGREL
-; CHECK-NEXT: .long .Ltmp6@IMGREL
-; CHECK: .text
-; CHECK: .seh_endproc
-
-define void @two_invoke_gap() {
-entry:
- invoke void @try_body()
- to label %again unwind label %lpad
-
-again:
- call void @do_nothing_on_unwind()
- invoke void @try_body()
- to label %done unwind label %lpad
-
-done:
- ret void
-
-lpad:
- %vals = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*)
- catch i8* bitcast (i32 (i8*, i8*)* @filt0 to i8*)
- %sel = extractvalue { i8*, i32 } %vals, 1
- call void @use_selector(i32 %sel)
- ret void
-}
-
-; Normal path code
-
-; CHECK-LABEL: {{^}}two_invoke_gap:
-; CHECK: .seh_proc two_invoke_gap
-; CHECK: .seh_handler __C_specific_handler, @unwind, @except
-; CHECK: .Ltmp11:
-; CHECK: callq try_body
-; CHECK-NEXT: .Ltmp12:
-; CHECK: callq do_nothing_on_unwind
-; CHECK: .Ltmp13:
-; CHECK: callq try_body
-; CHECK-NEXT: .Ltmp14:
-; CHECK: retq
-
-; Landing pad code
-
-; CHECK: .Ltmp16:
-; CHECK: movl $1, %ecx
-; CHECK: callq use_selector
-
-; CHECK: .seh_handlerdata
-; CHECK-NEXT: .long 2
-; CHECK-NEXT: .long .Ltmp11@IMGREL
-; CHECK-NEXT: .long .Ltmp12@IMGREL+1
-; CHECK-NEXT: .long filt0@IMGREL
-; CHECK-NEXT: .long .Ltmp16@IMGREL
-; CHECK-NEXT: .long .Ltmp13@IMGREL
-; CHECK-NEXT: .long .Ltmp14@IMGREL+1
-; CHECK-NEXT: .long filt0@IMGREL
-; CHECK-NEXT: .long .Ltmp16@IMGREL
-; CHECK: .text
-; CHECK: .seh_endproc
-
-define void @two_invoke_nounwind_gap() {
-entry:
- invoke void @try_body()
- to label %again unwind label %lpad
-
-again:
- call void @cannot_unwind()
- invoke void @try_body()
- to label %done unwind label %lpad
-
-done:
- ret void
-
-lpad:
- %vals = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*)
- catch i8* bitcast (i32 (i8*, i8*)* @filt0 to i8*)
- %sel = extractvalue { i8*, i32 } %vals, 1
- call void @use_selector(i32 %sel)
- ret void
-}
-
-; Normal path code
-
-; CHECK-LABEL: {{^}}two_invoke_nounwind_gap:
-; CHECK: .seh_proc two_invoke_nounwind_gap
-; CHECK: .seh_handler __C_specific_handler, @unwind, @except
-; CHECK: .Ltmp21:
-; CHECK: callq try_body
-; CHECK-NEXT: .Ltmp22:
-; CHECK: callq cannot_unwind
-; CHECK: .Ltmp23:
-; CHECK: callq try_body
-; CHECK-NEXT: .Ltmp24:
-; CHECK: retq
-
-; Landing pad code
-
-; CHECK: .Ltmp26:
-; CHECK: movl $1, %ecx
-; CHECK: callq use_selector
-
-; CHECK: .seh_handlerdata
-; CHECK-NEXT: .long 1
-; CHECK-NEXT: .long .Ltmp21@IMGREL
-; CHECK-NEXT: .long .Ltmp24@IMGREL+1
-; CHECK-NEXT: .long filt0@IMGREL
-; CHECK-NEXT: .long .Ltmp26@IMGREL
-; CHECK: .text
-; CHECK: .seh_endproc
-
-declare void @try_body()
-declare void @do_nothing_on_unwind()
-declare void @cannot_unwind() nounwind
-declare void @use_selector(i32)
-
-declare i32 @filt0(i8* %eh_info, i8* %rsp)
-declare i32 @filt1(i8* %eh_info, i8* %rsp)
-
-declare void @handler0()
-declare void @handler1()
-
-declare i32 @__C_specific_handler(...)
-declare i32 @llvm.eh.typeid.for(i8*) readnone nounwind
+++ /dev/null
-; RUN: llc -mtriple x86_64-pc-windows-msvc < %s | FileCheck %s
-
-; This test case is also intended to be run manually as a complete functional
-; test. It should link, print something, and exit zero rather than crashing.
-; It is the hypothetical lowering of a C source program that looks like:
-;
-; int safe_div(int *n, int *d) {
-; int r;
-; __try {
-; __try {
-; r = *n / *d;
-; } __except(GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION) {
-; puts("EXCEPTION_ACCESS_VIOLATION");
-; r = -1;
-; }
-; } __except(GetExceptionCode() == EXCEPTION_INT_DIVIDE_BY_ZERO) {
-; puts("EXCEPTION_INT_DIVIDE_BY_ZERO");
-; r = -2;
-; }
-; return r;
-; }
-
-@str1 = internal constant [27 x i8] c"EXCEPTION_ACCESS_VIOLATION\00"
-@str2 = internal constant [29 x i8] c"EXCEPTION_INT_DIVIDE_BY_ZERO\00"
-
-define i32 @safe_div(i32* %n, i32* %d) {
-entry:
- %r = alloca i32, align 4
- invoke void @try_body(i32* %r, i32* %n, i32* %d)
- to label %__try.cont unwind label %lpad
-
-lpad:
- %vals = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*)
- catch i8* bitcast (i32 (i8*, i8*)* @safe_div_filt0 to i8*)
- catch i8* bitcast (i32 (i8*, i8*)* @safe_div_filt1 to i8*)
- %ehptr = extractvalue { i8*, i32 } %vals, 0
- %sel = extractvalue { i8*, i32 } %vals, 1
- %filt0_val = call i32 @llvm.eh.typeid.for(i8* bitcast (i32 (i8*, i8*)* @safe_div_filt0 to i8*))
- %is_filt0 = icmp eq i32 %sel, %filt0_val
- br i1 %is_filt0, label %handler0, label %eh.dispatch1
-
-eh.dispatch1:
- %filt1_val = call i32 @llvm.eh.typeid.for(i8* bitcast (i32 (i8*, i8*)* @safe_div_filt1 to i8*))
- %is_filt1 = icmp eq i32 %sel, %filt1_val
- br i1 %is_filt1, label %handler1, label %eh.resume
-
-handler0:
- call void @puts(i8* getelementptr ([27 x i8]* @str1, i32 0, i32 0))
- store i32 -1, i32* %r, align 4
- br label %__try.cont
-
-handler1:
- call void @puts(i8* getelementptr ([29 x i8]* @str2, i32 0, i32 0))
- store i32 -2, i32* %r, align 4
- br label %__try.cont
-
-eh.resume:
- resume { i8*, i32 } %vals
-
-__try.cont:
- %safe_ret = load i32* %r, align 4
- ret i32 %safe_ret
-}
-
-; Normal path code
-
-; CHECK: {{^}}safe_div:
-; CHECK: .seh_proc safe_div
-; CHECK: .seh_handler __C_specific_handler, @unwind, @except
-; CHECK: .Ltmp0:
-; CHECK: leaq [[rloc:.*\(%rsp\)]], %rcx
-; CHECK: callq try_body
-; CHECK-NEXT: .Ltmp1
-; CHECK: .LBB0_7:
-; CHECK: movl [[rloc]], %eax
-; CHECK: retq
-
-; Landing pad code
-
-; CHECK: .Ltmp3:
-; CHECK: movl $1, %[[sel:[a-z]+]]
-; CHECK: .Ltmp4
-; CHECK: movl $2, %[[sel]]
-; CHECK: .L{{.*}}:
-; CHECK: cmpl $1, %[[sel]]
-
-; CHECK: # %handler0
-; CHECK: callq puts
-; CHECK: movl $-1, [[rloc]]
-; CHECK: jmp .LBB0_7
-
-; CHECK: cmpl $2, %[[sel]]
-
-; CHECK: # %handler1
-; CHECK: callq puts
-; CHECK: movl $-2, [[rloc]]
-; CHECK: jmp .LBB0_7
-
-; FIXME: EH preparation should not call _Unwind_Resume.
-; CHECK: callq _Unwind_Resume
-; CHECK: ud2
-
-; CHECK: .seh_handlerdata
-; CHECK: .long 2
-; CHECK: .long .Ltmp0@IMGREL
-; CHECK: .long .Ltmp1@IMGREL+1
-; CHECK: .long safe_div_filt0@IMGREL
-; CHECK: .long .Ltmp3@IMGREL
-; CHECK: .long .Ltmp0@IMGREL
-; CHECK: .long .Ltmp1@IMGREL+1
-; CHECK: .long safe_div_filt1@IMGREL
-; CHECK: .long .Ltmp4@IMGREL
-; CHECK: .text
-; CHECK: .seh_endproc
-
-
-define void @try_body(i32* %r, i32* %n, i32* %d) {
-entry:
- %0 = load i32* %n, align 4
- %1 = load i32* %d, align 4
- %div = sdiv i32 %0, %1
- store i32 %div, i32* %r, align 4
- ret void
-}
-
-; The prototype of these filter functions is:
-; int filter(EXCEPTION_POINTERS *eh_ptrs, void *rbp);
-
-; The definition of EXCEPTION_POINTERS is:
-; typedef struct _EXCEPTION_POINTERS {
-; EXCEPTION_RECORD *ExceptionRecord;
-; CONTEXT *ContextRecord;
-; } EXCEPTION_POINTERS;
-
-; The definition of EXCEPTION_RECORD is:
-; typedef struct _EXCEPTION_RECORD {
-; DWORD ExceptionCode;
-; ...
-; } EXCEPTION_RECORD;
-
-; The exception code can be retreived with two loads, one for the record
-; pointer and one for the code. The values of local variables can be
-; accessed via rbp, but that would require additional not yet implemented LLVM
-; support.
-
-define i32 @safe_div_filt0(i8* %eh_ptrs, i8* %rbp) {
- %eh_ptrs_c = bitcast i8* %eh_ptrs to i32**
- %eh_rec = load i32** %eh_ptrs_c
- %eh_code = load i32* %eh_rec
- ; EXCEPTION_ACCESS_VIOLATION = 0xC0000005
- %cmp = icmp eq i32 %eh_code, 3221225477
- %filt.res = zext i1 %cmp to i32
- ret i32 %filt.res
-}
-
-define i32 @safe_div_filt1(i8* %eh_ptrs, i8* %rbp) {
- %eh_ptrs_c = bitcast i8* %eh_ptrs to i32**
- %eh_rec = load i32** %eh_ptrs_c
- %eh_code = load i32* %eh_rec
- ; EXCEPTION_INT_DIVIDE_BY_ZERO = 0xC0000094
- %cmp = icmp eq i32 %eh_code, 3221225620
- %filt.res = zext i1 %cmp to i32
- ret i32 %filt.res
-}
-
-@str_result = internal constant [21 x i8] c"safe_div result: %d\0A\00"
-
-define i32 @main() {
- %d.addr = alloca i32, align 4
- %n.addr = alloca i32, align 4
-
- store i32 10, i32* %n.addr, align 4
- store i32 2, i32* %d.addr, align 4
- %r1 = call i32 @safe_div(i32* %n.addr, i32* %d.addr)
- call void (i8*, ...)* @printf(i8* getelementptr ([21 x i8]* @str_result, i32 0, i32 0), i32 %r1)
-
- store i32 10, i32* %n.addr, align 4
- store i32 0, i32* %d.addr, align 4
- %r2 = call i32 @safe_div(i32* %n.addr, i32* %d.addr)
- call void (i8*, ...)* @printf(i8* getelementptr ([21 x i8]* @str_result, i32 0, i32 0), i32 %r2)
-
- %r3 = call i32 @safe_div(i32* %n.addr, i32* null)
- call void (i8*, ...)* @printf(i8* getelementptr ([21 x i8]* @str_result, i32 0, i32 0), i32 %r3)
- ret i32 0
-}
-
-define void @_Unwind_Resume() {
- call void @abort()
- unreachable
-}
-
-declare i32 @__C_specific_handler(...)
-declare i32 @llvm.eh.typeid.for(i8*) readnone nounwind
-declare void @puts(i8*)
-declare void @printf(i8*, ...)
-declare void @abort()