481 lines
16 KiB
Diff
481 lines
16 KiB
Diff
Updated to continue working on llvm 3.5 head by martell malone
|
|
|
|
Source Url: http://lists.cs.uiuc.edu/pipermail/llvm-commits/Week-of-Mon-20131216/198988.html
|
|
|
|
From: kai <kai at redstar.de>
|
|
Date: Wed, 29 May 2013 07:10:59 +0200
|
|
Subject: [PATCH] Add Win64 exception handling.
|
|
|
|
This patch enables Dwarf exception handling on Windows 64 based on the
|
|
structured exception handling (SEH) mechanism built into the OS. This
|
|
is similar to the way exception handling is implemented in gcc 4.8
|
|
(mingw64) on Windows 64.
|
|
|
|
For each instruction in the frame setup range, the needed unwind
|
|
information is emitted. In order to match the gcc implementation, the
|
|
personality function is emitted as handler function and the Dwarf code
|
|
is emitted as handler data.
|
|
|
|
Most of this patch is based on work by Charles Davis.
|
|
---
|
|
lib/CodeGen/AsmPrinter/Win64Exception.cpp | 12 +--
|
|
lib/MC/MCObjectFileInfo.cpp | 15 ++--
|
|
lib/Target/X86/MCTargetDesc/X86MCAsmInfo.cpp | 15 +++-
|
|
lib/Target/X86/X86AsmPrinter.h | 2 +
|
|
lib/Target/X86/X86ISelLowering.cpp | 3 +-
|
|
lib/Target/X86/X86MCInstLower.cpp | 129 ++++++++++++++++++++++++++
|
|
test/CodeGen/X86/avx-win64-args.ll | 2 +
|
|
test/CodeGen/X86/win64_eh.ll | 130 +++++++++++++++++++++++++++
|
|
8 files changed, 290 insertions(+), 18 deletions(-)
|
|
create mode 100644 test/CodeGen/X86/win64_eh.ll
|
|
|
|
diff --git a/lib/CodeGen/AsmPrinter/Win64Exception.cpp b/lib/CodeGen/AsmPrinter/Win64Exception.cpp
|
|
index eda444bd..268b5c6 100644
|
|
--- a/lib/CodeGen/AsmPrinter/Win64Exception.cpp
|
|
+++ b/lib/CodeGen/AsmPrinter/Win64Exception.cpp
|
|
@@ -78,9 +78,9 @@
|
|
if (!shouldEmitPersonality)
|
|
return;
|
|
|
|
- MCSymbol *GCCHandlerSym =
|
|
- Asm->GetExternalSymbolSymbol("_GCC_specific_handler");
|
|
- Asm->OutStreamer.EmitWin64EHHandler(GCCHandlerSym, true, true);
|
|
+ const MCSymbol *PersHandlerSym = TLOF.getCFIPersonalitySymbol(Per, *Asm->Mang,
|
|
+ Asm->TM, MMI);
|
|
+ Asm->OutStreamer.EmitWin64EHHandler(PersHandlerSym, true, true);
|
|
|
|
Asm->OutStreamer.EmitLabel(Asm->GetTempSymbol("eh_func_begin",
|
|
Asm->getFunctionNumber()));
|
|
@@ -99,15 +99,8 @@
|
|
MMI->TidyLandingPads();
|
|
|
|
if (shouldEmitPersonality) {
|
|
- const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering();
|
|
- const Function *Per = MMI->getPersonalities()[MMI->getPersonalityIndex()];
|
|
- const MCSymbol *Sym =
|
|
- TLOF.getCFIPersonalitySymbol(Per, *Asm->Mang, Asm->TM, MMI);
|
|
-
|
|
Asm->OutStreamer.PushSection();
|
|
Asm->OutStreamer.EmitWin64EHHandlerData();
|
|
- Asm->OutStreamer.EmitValue(MCSymbolRefExpr::Create(Sym, Asm->OutContext),
|
|
- 4);
|
|
EmitExceptionTable();
|
|
Asm->OutStreamer.PopSection();
|
|
}
|
|
diff --git a/lib/MC/MCObjectFileInfo.cpp b/lib/MC/MCObjectFileInfo.cpp
|
|
index a160f29..e5e55f0 100644
|
|
--- a/lib/MC/MCObjectFileInfo.cpp
|
|
+++ b/lib/MC/MCObjectFileInfo.cpp
|
|
@@ -606,11 +606,16 @@ void MCObjectFileInfo::InitCOFFMCObjectFileInfo(Triple T) {
|
|
// though it contains relocatable pointers. In PIC mode, this is probably a
|
|
// big runtime hit for C++ apps. Either the contents of the LSDA need to be
|
|
// adjusted or this should be a data section.
|
|
- LSDASection =
|
|
- Ctx->getCOFFSection(".gcc_except_table",
|
|
- COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
|
|
- COFF::IMAGE_SCN_MEM_READ,
|
|
- SectionKind::getReadOnly());
|
|
+ if (T.getOS() == Triple::Win32) {
|
|
+ // On Windows with SEH, the LSDA is emitted into the .xdata section
|
|
+ LSDASection = 0;
|
|
+ } else {
|
|
+ LSDASection =
|
|
+ Ctx->getCOFFSection(".gcc_except_table",
|
|
+ COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
|
|
+ COFF::IMAGE_SCN_MEM_READ,
|
|
+ SectionKind::getReadOnly());
|
|
+ }
|
|
|
|
// Debug info.
|
|
COFFDebugSymbolsSection =
|
|
diff --git a/lib/Target/X86/MCTargetDesc/X86MCAsmInfo.cpp b/lib/Target/X86/MCTargetDesc/X86MCAsmInfo.cpp
|
|
index 6561804..2a537db 100644
|
|
--- a/lib/Target/X86/MCTargetDesc/X86MCAsmInfo.cpp
|
|
+++ b/lib/Target/X86/MCTargetDesc/X86MCAsmInfo.cpp
|
|
@@ -141,9 +141,15 @@
|
|
|
|
void X86MCAsmInfoMicrosoft::anchor() { }
|
|
|
|
-X86MCAsmInfoMicrosoft::X86MCAsmInfoMicrosoft(const Triple &Triple) {
|
|
- if (Triple.getArch() == Triple::x86_64)
|
|
+X86MCAsmInfoMicrosoft::X86MCAsmInfoMicrosoft(const Triple &T) {
|
|
+ bool is64Bit = T.getArch() == Triple::x86_64;
|
|
+
|
|
+ if (is64Bit) {
|
|
PrivateGlobalPrefix = ".L";
|
|
+ ExceptionsType = ExceptionHandling::Win64;
|
|
+ }
|
|
+
|
|
+ PointerSize = is64Bit ? 8 : 4;
|
|
|
|
AssemblerDialect = AsmWriterFlavor;
|
|
|
|
@@ -156,18 +162,23 @@
|
|
|
|
void X86MCAsmInfoGNUCOFF::anchor() { }
|
|
|
|
-X86MCAsmInfoGNUCOFF::X86MCAsmInfoGNUCOFF(const Triple &Triple) {
|
|
- if (Triple.getArch() == Triple::x86_64) {
|
|
+X86MCAsmInfoGNUCOFF::X86MCAsmInfoGNUCOFF(const Triple &T) {
|
|
+ bool is64Bit = T.getArch() == Triple::x86_64;
|
|
+
|
|
+ if (is64Bit)
|
|
PrivateGlobalPrefix = ".L";
|
|
- PointerSize = 8;
|
|
- }
|
|
+
|
|
+ PointerSize = is64Bit ? 8 : 4;
|
|
|
|
AssemblerDialect = AsmWriterFlavor;
|
|
|
|
TextAlignFillValue = 0x90;
|
|
|
|
// Exceptions handling
|
|
- ExceptionsType = ExceptionHandling::DwarfCFI;
|
|
+ if (is64Bit && T.isWindowsGNUEnvironment())
|
|
+ ExceptionsType = ExceptionHandling::Win64;
|
|
+ else
|
|
+ ExceptionsType = ExceptionHandling::DwarfCFI;
|
|
|
|
UseIntegratedAssembler = true;
|
|
}
|
|
diff --git a/lib/Target/X86/X86AsmPrinter.h b/lib/Target/X86/X86AsmPrinter.h
|
|
index d6adf68..2477a84 100644
|
|
--- a/lib/Target/X86/X86AsmPrinter.h
|
|
+++ b/lib/Target/X86/X86AsmPrinter.h
|
|
@@ -27,6 +27,8 @@ class LLVM_LIBRARY_VISIBILITY X86AsmPrinter : public AsmPrinter {
|
|
const X86Subtarget *Subtarget;
|
|
StackMaps SM;
|
|
|
|
+ void EmitUnwindingInstruction(const MachineInstr *MI);
|
|
+
|
|
public:
|
|
explicit X86AsmPrinter(TargetMachine &TM, MCStreamer &Streamer)
|
|
: AsmPrinter(TM, Streamer), SM(*this) {
|
|
diff --git a/lib/Target/X86/X86ISelLowering.cpp b/lib/Target/X86/X86ISelLowering.cpp
|
|
index 4ce2ea3..e292701 100644
|
|
--- a/lib/Target/X86/X86ISelLowering.cpp
|
|
+++ b/lib/Target/X86/X86ISelLowering.cpp
|
|
@@ -597,7 +597,8 @@ void X86TargetLowering::resetOperationActions() {
|
|
// FIXME - use subtarget debug flags
|
|
if (!Subtarget->isTargetDarwin() &&
|
|
!Subtarget->isTargetELF() &&
|
|
- !Subtarget->isTargetCygMing()) {
|
|
+ !Subtarget->isTargetCygMing() &&
|
|
+ !Subtarget->isTargetWin64()) {
|
|
setOperationAction(ISD::EH_LABEL, MVT::Other, Expand);
|
|
}
|
|
|
|
diff --git a/lib/Target/X86/X86MCInstLower.cpp b/lib/Target/X86/X86MCInstLower.cpp
|
|
index 6f88cf1..2eab008 100644
|
|
--- a/lib/Target/X86/X86MCInstLower.cpp
|
|
+++ b/lib/Target/X86/X86MCInstLower.cpp
|
|
@@ -13,6 +13,7 @@
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "X86AsmPrinter.h"
|
|
+#include "X86RegisterInfo.h"
|
|
#include "InstPrinter/X86ATTInstPrinter.h"
|
|
#include "MCTargetDesc/X86BaseInfo.h"
|
|
#include "llvm/ADT/SmallString.h"
|
|
@@ -20,6 +21,7 @@
|
|
#include "llvm/CodeGen/MachineModuleInfoImpls.h"
|
|
#include "llvm/CodeGen/StackMaps.h"
|
|
#include "llvm/IR/DataLayout.h"
|
|
+#include "llvm/IR/Function.h"
|
|
#include "llvm/IR/GlobalValue.h"
|
|
#include "llvm/IR/Mangler.h"
|
|
#include "llvm/MC/MCAsmInfo.h"
|
|
@@ -777,7 +779,129 @@ static void LowerPATCHPOINT(MCStreamer &OS, StackMaps &SM,
|
|
EmitNops(OS, NumBytes - EncodedBytes, Is64Bit, STI);
|
|
}
|
|
|
|
+static bool isCalleeSavedReg(const MachineFunction *MF,
|
|
+ const X86RegisterInfo *RI, unsigned Reg) {
|
|
+ const uint16_t *NVRegs = RI->getCalleeSavedRegs(MF);
|
|
+ while (*NVRegs) {
|
|
+ if (*NVRegs == Reg)
|
|
+ return true;
|
|
+ NVRegs++;
|
|
+ }
|
|
+ return false;
|
|
+}
|
|
+
|
|
+void X86AsmPrinter::EmitUnwindingInstruction(const MachineInstr *MI) {
|
|
+ assert(MI->getFlag(MachineInstr::FrameSetup) &&
|
|
+ "Only call frame setup instructions allowed here!");
|
|
+ unsigned SReg, DReg;
|
|
+ int64_t Offset;
|
|
+ const X86RegisterInfo *RI =
|
|
+ static_cast<const X86RegisterInfo *>(TM.getRegisterInfo());
|
|
+ switch (MI->getOpcode()) {
|
|
+ default: llvm_unreachable("Unknown frame setup opcode!");
|
|
+ case X86::PUSH64r:
|
|
+ SReg = MI->getOperand(0).getReg();
|
|
+ if (isCalleeSavedReg(MI->getParent()->getParent(), RI, SReg))
|
|
+ OutStreamer.EmitWin64EHPushReg(RI->getSEHRegNum(SReg));
|
|
+ else
|
|
+ OutStreamer.EmitWin64EHAllocStack(8);
|
|
+ break;
|
|
+ case X86::SUB64ri8:
|
|
+ case X86::SUB64ri32:
|
|
+ DReg = MI->getOperand(0).getReg();
|
|
+ Offset = MI->getOperand(2).getImm();
|
|
+ if (DReg == RI->getStackRegister()) {
|
|
+ OutStreamer.EmitWin64EHAllocStack(Offset);
|
|
+ } else
|
|
+ llvm_unreachable("X86::SUB64ri8/32 not allowed with these operands");
|
|
+ break;
|
|
+ case X86::MOV64rr:
|
|
+ DReg = MI->getOperand(0).getReg();
|
|
+ SReg = MI->getOperand(1).getReg();
|
|
+ if (DReg == RI->getFrameRegister(*MF) && SReg == RI->getStackRegister())
|
|
+ OutStreamer.EmitWin64EHSetFrame(RI->getSEHRegNum(DReg), 0);
|
|
+ else
|
|
+ llvm_unreachable("X86::MOV64rr not allowed with these operands");
|
|
+ break;
|
|
+ case X86::MOV64mr:
|
|
+ case X86::MOVAPSmr:
|
|
+ DReg = MI->getOperand(0).getReg();
|
|
+ SReg = MI->getOperand(5).getReg();
|
|
+ if (DReg == RI->getFrameRegister(*MF) || DReg == RI->getStackRegister()) {
|
|
+ Offset = MI->getOperand(3).getImm();
|
|
+ if (MI->getOperand(1).getImm() != 1 || MI->getOperand(2).getImm() != 0 ||
|
|
+ MI->getOperand(4).getImm() != 0)
|
|
+ llvm_unreachable("X86::MOV64mr not allowed with these operands");
|
|
+ if (MI->getOpcode() == X86::MOVAPSmr)
|
|
+ OutStreamer.EmitWin64EHSaveXMM(RI->getSEHRegNum(SReg), Offset);
|
|
+ else
|
|
+ OutStreamer.EmitWin64EHSaveReg(RI->getSEHRegNum(SReg), Offset);
|
|
+ } else
|
|
+ llvm_unreachable("X86::MOV64mr not allowed with these operands");
|
|
+ break;
|
|
+ case X86::LEA64r:
|
|
+ DReg = MI->getOperand(0).getReg();
|
|
+ SReg = MI->getOperand(1).getReg();
|
|
+ Offset = MI->getOperand(4).getImm();
|
|
+ if (SReg == RI->getStackRegister() && Offset > 0) {
|
|
+ // Check stack register first in case there is no frame register.
|
|
+ if (DReg == RI->getStackRegister()) {
|
|
+ OutStreamer.EmitWin64EHAllocStack(Offset);
|
|
+ } else if (DReg == RI->getFrameRegister(*MF)) {
|
|
+ OutStreamer.EmitWin64EHSetFrame(RI->getSEHRegNum(DReg), Offset);
|
|
+ } else
|
|
+ llvm_unreachable("X86::LEA64r not allowed with these operands");
|
|
+ }
|
|
+ else
|
|
+ llvm_unreachable("X86::LEA64r not allowed with these operands");
|
|
+ break;
|
|
+ case X86::MOV64ri:
|
|
+ // Occurs before alloca()/call to __chkstk/___chkstk_ms
|
|
+ if (!(MI->getNextNode()
|
|
+ && MI->getNextNode()->getOpcode() == X86::W64ALLOCA
|
|
+ && MI->getOperand(0).getReg() == X86::RAX))
|
|
+ llvm_unreachable("X86::MOV64ri only allowed before X86::W64ALLOCA");
|
|
+ break;
|
|
+ case X86::W64ALLOCA:
|
|
+ // Occurs if call to __chkstk/___chkstk_ms is used.
|
|
+ break;
|
|
+ case X86::SUB64rr:
|
|
+ // Occurs after call to __chkstk/___chkstk_ms on Win64
|
|
+ if (!(MI->getPrevNode()
|
|
+ && MI->getPrevNode()->getOpcode() == X86::W64ALLOCA
|
|
+ && MI->getOperand(0).getReg() == RI->getStackRegister()
|
|
+ && MI->getOperand(2).getReg() == X86::RAX
|
|
+ && getSubtarget().isTargetWin64()))
|
|
+ llvm_unreachable("X86::SUB64rr only allowed after X86::W64ALLOCA");
|
|
+ const MachineInstr *MoveMI = MI->getPrevNode()->getPrevNode();
|
|
+ if (!(MoveMI && MoveMI->getOpcode() == X86::MOV64ri))
|
|
+ llvm_unreachable("X86::MOV64ri required before X86::W64ALLOCA");
|
|
+ Offset = MoveMI->getOperand(1).getImm();
|
|
+ OutStreamer.EmitWin64EHAllocStack(Offset);
|
|
+ break;
|
|
+ }
|
|
+ // Prolog ends if next instruction does not have the FrameSetup flag
|
|
+ // and is not the CFI_Instruction.
|
|
+ if (MI->getNextNode()) {
|
|
+ const MachineInstr *MI2 = MI->getNextNode();
|
|
+ if (!(MI2->getFlag(MachineInstr::FrameSetup) ||
|
|
+ (MI2->isCFIInstruction() && MI2->getNextNode() &&
|
|
+ MI2->getNextNode()->getFlag(MachineInstr::FrameSetup)))) {
|
|
+ OutStreamer.EmitWin64EHEndProlog();
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
void X86AsmPrinter::EmitInstruction(const MachineInstr *MI) {
|
|
+ // Emit end of prolog for Win64-style EH if there is no framesetup.
|
|
+ if (MAI->getExceptionHandlingType() == ExceptionHandling::Win64 &&
|
|
+ !MI->getFlag(MachineInstr::FrameSetup) &&
|
|
+ MI->getParent()->getParent()->getFunction()->needsUnwindTableEntry() &&
|
|
+ MI == MI->getParent()->instr_begin() &&
|
|
+ MI->getParent()->getNumber() == 0) {
|
|
+ OutStreamer.EmitWin64EHEndProlog();
|
|
+ }
|
|
+
|
|
X86MCInstLower MCInstLowering(*MF, *this);
|
|
switch (MI->getOpcode()) {
|
|
case TargetOpcode::DBG_VALUE:
|
|
@@ -888,4 +1012,11 @@ void X86AsmPrinter::EmitInstruction(const MachineInstr *MI) {
|
|
MCInst TmpInst;
|
|
MCInstLowering.Lower(MI, TmpInst);
|
|
EmitToStreamer(OutStreamer, TmpInst);
|
|
+
|
|
+ // Emit SEH unwind info for Win64-style EH.
|
|
+ if (MAI->getExceptionHandlingType() == ExceptionHandling::Win64 &&
|
|
+ MI->getFlag(MachineInstr::FrameSetup) &&
|
|
+ MI->getParent()->getParent()->getFunction()->needsUnwindTableEntry()) {
|
|
+ EmitUnwindingInstruction(MI);
|
|
+ }
|
|
}
|
|
diff --git a/test/CodeGen/X86/avx-win64-args.ll b/test/CodeGen/X86/avx-win64-args.ll
|
|
index 85b2634..3b2f3d4 100644
|
|
--- a/test/CodeGen/X86/avx-win64-args.ll
|
|
+++ b/test/CodeGen/X86/avx-win64-args.ll
|
|
@@ -1,4 +1,6 @@
|
|
; RUN: llc < %s -mcpu=corei7-avx -mattr=+avx | FileCheck %s
|
|
+; XFAIL: *
|
|
+; See PR16779.
|
|
target triple = "x86_64-pc-win32"
|
|
|
|
declare <8 x float> @foo(<8 x float>, i32)
|
|
diff --git a/test/CodeGen/X86/win64_eh.ll b/test/CodeGen/X86/win64_eh.ll
|
|
new file mode 100644
|
|
index 0000000..101ae39
|
|
--- /dev/null
|
|
+++ b/test/CodeGen/X86/win64_eh.ll
|
|
@@ -0,0 +1,130 @@
|
|
+; RUN: llc < %s -O0 -mcpu=corei7 -mtriple=x86_64-pc-win32 | FileCheck %s -check-prefix=WIN64
|
|
+; RUN: llc < %s -O0 -mcpu=corei7 -mtriple=x86_64-pc-mingw32 | FileCheck %s -check-prefix=WIN64
|
|
+
|
|
+; Check function without prolog
|
|
+define void @foo0() uwtable {
|
|
+entry:
|
|
+ ret void
|
|
+}
|
|
+; WIN64: .seh_proc foo0
|
|
+; WIN64: .seh_endprologue
|
|
+; WIN64: ret
|
|
+; WIN64: .seh_endproc
|
|
+
|
|
+; Checks a small stack allocation
|
|
+define void @foo1() uwtable {
|
|
+entry:
|
|
+ %baz = alloca [2000 x i16], align 2
|
|
+ ret void
|
|
+}
|
|
+; WIN64: .seh_proc foo1
|
|
+; WIN64: subq $4000, %rsp
|
|
+; WIN64: .seh_stackalloc 4000
|
|
+; WIN64: .seh_endprologue
|
|
+; WIN64: addq $4000, %rsp
|
|
+; WIN64: ret
|
|
+; WIN64: .seh_endproc
|
|
+
|
|
+; Checks a stack allocation requiring call to __chkstk/___chkstk_ms
|
|
+define void @foo2() uwtable {
|
|
+entry:
|
|
+ %baz = alloca [4000 x i16], align 2
|
|
+ ret void
|
|
+}
|
|
+; WIN64: .seh_proc foo2
|
|
+; WIN64: movabsq $8000, %rax
|
|
+; WIN64: callq {{__chkstk|___chkstk_ms}}
|
|
+; WIN64: subq %rax, %rsp
|
|
+; WIN64: .seh_stackalloc 8000
|
|
+; WIN64: .seh_endprologue
|
|
+; WIN64: addq $8000, %rsp
|
|
+; WIN64: ret
|
|
+; WIN64: .seh_endproc
|
|
+
|
|
+
|
|
+; Checks stack push
|
|
+define i32 @foo3(i32 %f_arg, i32 %e_arg, i32 %d_arg, i32 %c_arg, i32 %b_arg, i32 %a_arg) uwtable {
|
|
+entry:
|
|
+ %a = alloca i32
|
|
+ %b = alloca i32
|
|
+ %c = alloca i32
|
|
+ %d = alloca i32
|
|
+ %e = alloca i32
|
|
+ %f = alloca i32
|
|
+ store i32 %a_arg, i32* %a
|
|
+ store i32 %b_arg, i32* %b
|
|
+ store i32 %c_arg, i32* %c
|
|
+ store i32 %d_arg, i32* %d
|
|
+ store i32 %e_arg, i32* %e
|
|
+ store i32 %f_arg, i32* %f
|
|
+ %tmp = load i32* %a
|
|
+ %tmp1 = mul i32 %tmp, 2
|
|
+ %tmp2 = load i32* %b
|
|
+ %tmp3 = mul i32 %tmp2, 3
|
|
+ %tmp4 = add i32 %tmp1, %tmp3
|
|
+ %tmp5 = load i32* %c
|
|
+ %tmp6 = mul i32 %tmp5, 5
|
|
+ %tmp7 = add i32 %tmp4, %tmp6
|
|
+ %tmp8 = load i32* %d
|
|
+ %tmp9 = mul i32 %tmp8, 7
|
|
+ %tmp10 = add i32 %tmp7, %tmp9
|
|
+ %tmp11 = load i32* %e
|
|
+ %tmp12 = mul i32 %tmp11, 11
|
|
+ %tmp13 = add i32 %tmp10, %tmp12
|
|
+ %tmp14 = load i32* %f
|
|
+ %tmp15 = mul i32 %tmp14, 13
|
|
+ %tmp16 = add i32 %tmp13, %tmp15
|
|
+ ret i32 %tmp16
|
|
+}
|
|
+; WIN64: .seh_proc foo3
|
|
+; WIN64: pushq %rsi
|
|
+; WIN64: .seh_pushreg 6
|
|
+; WIN64: subq $24, %rsp
|
|
+; WIN64: .seh_stackalloc 24
|
|
+; WIN64: .seh_endprologue
|
|
+; WIN64: addq $24, %rsp
|
|
+; WIN64: popq %rsi
|
|
+; WIN64: ret
|
|
+; WIN64: .seh_endproc
|
|
+
|
|
+
|
|
+; Check emission of eh handler and handler data
|
|
+declare i32 @_d_eh_personality(i32, i32, i64, i8*, i8*)
|
|
+declare void @_d_eh_resume_unwind(i8*)
|
|
+
|
|
+declare i32 @bar()
|
|
+
|
|
+define i32 @foo4() #0 {
|
|
+entry:
|
|
+ %step = alloca i32, align 4
|
|
+ store i32 0, i32* %step
|
|
+ %tmp = load i32* %step
|
|
+
|
|
+ %tmp1 = invoke i32 @bar()
|
|
+ to label %finally unwind label %landingpad
|
|
+
|
|
+finally:
|
|
+ store i32 1, i32* %step
|
|
+ br label %endtryfinally
|
|
+
|
|
+landingpad:
|
|
+ %landing_pad = landingpad { i8*, i32 } personality i32 (i32, i32, i64, i8*, i8*)* @_d_eh_personality
|
|
+ cleanup
|
|
+ %tmp3 = extractvalue { i8*, i32 } %landing_pad, 0
|
|
+ store i32 2, i32* %step
|
|
+ call void @_d_eh_resume_unwind(i8* %tmp3)
|
|
+ unreachable
|
|
+
|
|
+endtryfinally:
|
|
+ %tmp10 = load i32* %step
|
|
+ ret i32 %tmp10
|
|
+}
|
|
+; WIN64: .seh_proc foo4
|
|
+; WIN64: .seh_handler _d_eh_personality, @unwind, @except
|
|
+; WIN64: subq $56, %rsp
|
|
+; WIN64: .seh_stackalloc 56
|
|
+; WIN64: .seh_endprologue
|
|
+; WIN64: addq $56, %rsp
|
|
+; WIN64: ret
|
|
+; WIN64: .seh_handlerdata
|
|
+; WIN64: .seh_endproc
|
|
--
|
|
1.8.5.4
|
|
|