[PATCH][MC/X86_64] Implement Win64 exception handling

Kai Nacke kai.nacke at redstar.de
Wed Jan 8 23:04:50 PST 2014


Hi,

the latest commits broke the patch. This version applies cleanly to trunk.

Regards,
Kai

On 02.01.2014 14:42, Kai Nacke wrote:
> Hi Nico!
>
> On 22.12.2013 12:54, Nico Rieck wrote:
>> Hi Kai!
>>
>> On 04.12.2013 11:27, Kai Nacke wrote:
>>> Further, it seems that LLVM does not generate a LEA instruction in the
>>> frame setup which legally triggers my new code. At least I was unable to
>>> create a test for this. Any suggestion here is welcome.
>>
>> You can use -mcpu=atom to trigger using LEA for SP updates, though this
>> only covers one half. MOV64mr and MOVAPSmr are also never used by LLVM
>> AFAICS.
>
> This was a good hint. I added additional checks for -mcpu=atom which
> checks some generated LEA instructions.
>
>>
>> +  case X86::MOV64mr:
>> +  case X86::MOVAPSmr:
>> +    DReg = MI->getOperand(0).getReg();
>> +    Offset = MI->getOperand(0).getOffset();
>> +    SReg = MI->getOperand(1).getReg();
>>
>> An operand cannot be both a register and an offset. This will assert.
>> Both instructions use a ModRM byte and thus have 6 operands. Of interest
>> here are 0 for base, 3 for offset/disp and 5 for source register. The
>> rest should be enforced to default values.
>
> Since LEA also uses a ModRM byte I modified the code in the same way as
> for the LEA instruction.
>
>> +  case X86::LEA64r:
>> +    DReg = MI->getOperand(0).getReg();
>> +    Offset = MI->getOperand(0).getOffset();
>> +    SReg = MI->getOperand(1).getReg();
>> +    if (SReg == RI->getStackRegister()) {
>> +      if (DReg == RI->getFrameRegister(*MF)) {
>> +        OutStreamer.EmitWin64EHSetFrame(RI->getSEHRegNum(DReg), Offset);
>> +      } else if (DReg == RI->getStackRegister()) {
>> +        OutStreamer.EmitWin64EHAllocStack(Offset);
>> +      }
>> +      else
>> +        llvm_unreachable("X86::X86::LEA64r not allowed with these
>> operands");
>> +    }
>>
>> The LEA offsets here are (and must be) negative and must be explicitly
>> negated. And I think DReg should be checked against the stack register
>> first for those cases when there is no frame register.
>
> I added this, especially the negation. This is checked by the -mcpu=atom
> test.
>
>> Overall there are still a few else-clauses missing to reject.
>
> I also added some more checks. Hopefully I caughtall places.
>
>> I saw you landed the __chkstk_ms change, which simplifies the last three
>> cases. But I'm stating the obvious here. :)
>
> For sure!
>
> The changed patch is attached.
>
> Regards,
> Kai
>
>> -Nico
>> _______________________________________________
>> llvm-commits mailing list
>> llvm-commits at cs.uiuc.edu
>> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
>>
>>
>
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
>

-------------- next part --------------
>From 3cca6a1f16efdae863708c48d8a3ac489508c477 Mon Sep 17 00:00:00 2001
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 |  17 ++-
 lib/Target/X86/X86AsmPrinter.h               |   2 +
 lib/Target/X86/X86ISelLowering.cpp           |   3 +-
 lib/Target/X86/X86MCInstLower.cpp            | 126 +++++++++++++++++++
 test/CodeGen/X86/avx-win64-args.ll           |   2 +
 test/CodeGen/X86/win64_eh.ll                 | 180 +++++++++++++++++++++++++++
 8 files changed, 338 insertions(+), 19 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 4844cf6..851196f 100644
--- a/lib/CodeGen/AsmPrinter/Win64Exception.cpp
+++ b/lib/CodeGen/AsmPrinter/Win64Exception.cpp
@@ -78,9 +78,9 @@ void Win64Exception::beginFunction(const MachineFunction *MF) {
   if (!shouldEmitPersonality)
     return;
 
-  MCSymbol *GCCHandlerSym =
-    Asm->GetExternalSymbolSymbol("_GCC_specific_handler");
-  Asm->OutStreamer.EmitWin64EHHandler(GCCHandlerSym, true, true);
+  const MCSymbol *PersHandlerSym = TLOF.getCFIPersonalitySymbol(Per, Asm->Mang,
+                                                                MMI);
+  Asm->OutStreamer.EmitWin64EHHandler(PersHandlerSym, true, true);
 
   Asm->OutStreamer.EmitLabel(Asm->GetTempSymbol("eh_func_begin",
                                                 Asm->getFunctionNumber()));
@@ -99,14 +99,8 @@ void Win64Exception::endFunction(const MachineFunction *) {
   MMI->TidyLandingPads();
 
   if (shouldEmitPersonality) {
-    const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering();
-    const Function *Per = MMI->getPersonalities()[MMI->getPersonalityIndex()];
-    const MCSymbol *Sym = TLOF.getCFIPersonalitySymbol(Per, Asm->Mang, 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 4cc872e..3d0dc72 100644
--- a/lib/MC/MCObjectFileInfo.cpp
+++ b/lib/MC/MCObjectFileInfo.cpp
@@ -575,11 +575,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.
   DwarfAbbrevSection =
diff --git a/lib/Target/X86/MCTargetDesc/X86MCAsmInfo.cpp b/lib/Target/X86/MCTargetDesc/X86MCAsmInfo.cpp
index 7d93555..4a7976e 100644
--- a/lib/Target/X86/MCTargetDesc/X86MCAsmInfo.cpp
+++ b/lib/Target/X86/MCTargetDesc/X86MCAsmInfo.cpp
@@ -136,7 +136,8 @@ getNonexecutableStackSection(MCContext &Ctx) const {
 void X86MCAsmInfoMicrosoft::anchor() { }
 
 X86MCAsmInfoMicrosoft::X86MCAsmInfoMicrosoft(const Triple &Triple) {
-  if (Triple.getArch() == Triple::x86_64)
+  bool is64Bit = Triple.getArch() == Triple::x86_64;
+  if (is64Bit)
     PrivateGlobalPrefix = ".L";
 
   AssemblerDialect = AsmWriterFlavor;
@@ -144,18 +145,26 @@ X86MCAsmInfoMicrosoft::X86MCAsmInfoMicrosoft(const Triple &Triple) {
   TextAlignFillValue = 0x90;
 
   AllowAtInName = true;
+
+  // Exceptions handling
+  if (is64Bit)
+    ExceptionsType = ExceptionHandling::Win64;
 }
 
 void X86MCAsmInfoGNUCOFF::anchor() { }
 
 X86MCAsmInfoGNUCOFF::X86MCAsmInfoGNUCOFF(const Triple &Triple) {
-  if (Triple.getArch() == Triple::x86_64)
+  bool is64Bit = Triple.getArch() == Triple::x86_64;
+  if (is64Bit)
     PrivateGlobalPrefix = ".L";
 
   AssemblerDialect = AsmWriterFlavor;
 
   TextAlignFillValue = 0x90;
 
-  // Exceptions handling
-  ExceptionsType = ExceptionHandling::DwarfCFI;
+  // Exception handling
+  if (is64Bit && Triple.getOS() == Triple::MinGW32)
+    ExceptionsType = ExceptionHandling::Win64;
+  else
+    ExceptionsType = ExceptionHandling::DwarfCFI;
 }
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 a41faab..b1e7c40 100644
--- a/lib/Target/X86/X86ISelLowering.cpp
+++ b/lib/Target/X86/X86ISelLowering.cpp
@@ -595,7 +595,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 8b4195f..dd5c24a 100644
--- a/lib/Target/X86/X86MCInstLower.cpp
+++ b/lib/Target/X86/X86MCInstLower.cpp
@@ -774,7 +774,126 @@ static void LowerPATCHPOINT(MCStreamer &OS, StackMaps &SM,
   EmitNops(OS, NumBytes - EncodedBytes, Is64Bit);
 }
 
+static bool isCalleeSavedReg(const MachineFunction *MF,
+                             const TargetRegisterInfo *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::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::X86::MOV64rr not allowed with these operands");
+    break;
+  case X86::MOV64mr:
+  case X86::MOVAPSmr:
+    DReg = MI->getOperand(0).getReg();
+    SReg = MI->getOperand(1).getReg();
+    Offset = MI->getOperand(4).getImm();
+    if (DReg == RI->getFrameRegister(*MF) || DReg == RI->getStackRegister()) {
+      if (MI->getOpcode() == X86::MOVAPSmr)
+        OutStreamer.EmitWin64EHSaveXMM(RI->getSEHRegNum(SReg), Offset);
+      else
+        OutStreamer.EmitWin64EHSaveReg(RI->getSEHRegNum(SReg), Offset);
+    } else
+      llvm_unreachable("X86::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()) {
+      assert(Offset < 0 && "Offset must be negativ");
+      if (DReg == RI->getStackRegister()) {
+        OutStreamer.EmitWin64EHAllocStack(-Offset);
+      } else if (DReg == RI->getFrameRegister(*MF)) {
+        OutStreamer.EmitWin64EHSetFrame(RI->getSEHRegNum(DReg), -Offset);
+      } else
+        llvm_unreachable("X86::X86::LEA64r not allowed with these operands");
+    }
+    else
+      llvm_unreachable("X86::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 PROLOG_LABEL.
+  if (MI->getNextNode()) {
+    const MachineInstr *MI2 = MI->getNextNode();
+    if (!(MI2->getFlag(MachineInstr::FrameSetup) ||
+          (MI2->isPrologLabel() && 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:
@@ -886,4 +1005,11 @@ void X86AsmPrinter::EmitInstruction(const MachineInstr *MI) {
   MCInst TmpInst;
   MCInstLowering.Lower(MI, TmpInst);
   OutStreamer.EmitInstruction(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..1e662bd
--- /dev/null
+++ b/test/CodeGen/X86/win64_eh.ll
@@ -0,0 +1,180 @@
+; 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=MINGW64
+; RUN: llc < %s -O0 -mcpu=atom -mtriple=x86_64-pc-mingw32 | FileCheck %s -check-prefix=MINGW64-ATOM
+
+; Check function with nor prolog
+define void @foo0() uwtable {
+entry:
+  ret void
+}
+; WIN64: .seh_proc foo0
+; WIN64: .seh_endprologue
+; WIN64: ret
+; WIN64: .seh_endproc
+
+; MINGW64: .seh_proc foo0
+; MINGW64: .seh_endprologue
+; MINGW64: ret
+; MINGW64: .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: ret
+; WIN64: .seh_endproc
+
+; MINGW64: .seh_proc foo1
+; MINGW64: subq $4000, %rsp
+; MINGW64: .seh_stackalloc 4000
+; MINGW64: .seh_endprologue
+; MINGW64: ret
+; MINGW64: .seh_endproc
+
+; MINGW64-ATOM: .seh_proc foo1
+; MINGW64-ATOM: leaq -4000(%rsp), %rsp
+; MINGW64-ATOM: .seh_stackalloc 4000
+; MINGW64-ATOM: .seh_endprologue
+; MINGW64-ATOM: ret
+; MINGW64-ATOM: .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
+; WIN64: subq %rax, %rsp
+; WIN64: .seh_endprologue
+; WIN64: ret
+; WIN64: .seh_endproc
+
+; MINGW64: .seh_proc foo2
+; MINGW64: movabsq $8000, %rax
+; MINGW64: callq ___chkstk_ms
+; MINGW64: .seh_stackalloc 8000
+; MINGW64: .seh_endprologue
+; MINGW64: ret
+; MINGW64: .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: ret
+; WIN64: .seh_endproc
+
+; MINGW64: .seh_proc foo3
+; MINGW64: pushq %rsi
+; MINGW64: .seh_pushreg 6
+; MINGW64: subq $24, %rsp
+; MINGW64: .seh_stackalloc 24
+; MINGW64: .seh_endprologue
+; MINGW64: ret
+; MINGW64: .seh_endproc
+
+; MINGW64-ATOM: .seh_proc foo3
+; MINGW64-ATOM: pushq %rsi
+; MINGW64-ATOM: .seh_pushreg 6
+; MINGW64-ATOM: leaq -24(%rsp), %rsp
+; MINGW64-ATOM: .seh_stackalloc 24
+; MINGW64-ATOM: .seh_endprologue
+; MINGW64-ATOM: ret
+; MINGW64-ATOM: .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: ret
+; WIN64: .seh_handlerdata
+; WIN64: .seh_endproc
+
+; MINGW64: .seh_proc foo4
+; MINGW64: .seh_handler _d_eh_personality, @unwind, @except
+; MINGW64: subq $56, %rsp
+; MINGW64: .seh_stackalloc 56
+; MINGW64: .seh_endprologue
+; MINGW64: ret
+; MINGW64: .seh_handlerdata
+; MINGW64: .seh_endproc
-- 
1.8.0.msysgit.0



More information about the llvm-commits mailing list