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

Kai Nacke kai.nacke at redstar.de
Wed Dec 4 02:27:48 PST 2013


Hi Nico!

It took some time but now I think I have integrated all comments.

1) SEH generation is now enabled for 64bit mingw32, too.
2) The unit tests now check for Win64 and mingw32.
3) assert() is replace with llvm_unreachable() to produce an error even 
in release builds.
4) Unwind info is generated for the LEA instruction.

During implementation, I noticed that gcc 4.8.x produces code different 
from LLVM in mingw/cygwin environment. The simple C code

int test()
{
     int x[4096];
     return 1;
}

creates this prolog:

	pushq	%rbp
	.seh_pushreg	%rbp
	movl	$16384, %eax
	call	___chkstk_ms
	subq	%rax, %rsp
	.seh_stackalloc	16384
	leaq	128(%rsp), %rbp
	.seh_setframe	%rbp, 128
	.seh_endprologue

As you can see there is a call to ___chkstk_ms which has the same 
interface as __chkstk for MSVC. Taking advantage of this simplifies the 
prolog generation and would simplify my code, too. I attach a patch for 
this change here, too. @Anton: Any objections against this change?

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.

Regards,
Kai



On 22.11.2013 20:07, Nico Rieck wrote:
> On 22.11.2013 18:06, Kai Nacke wrote:
>> My understanding is that LEA instructions to adjust the stack pointer
>> are invalid in prolog code. But I recheck in MSDN.
>
> Hm. I can't find anything that explicitly forbids this. If it's a simple
> LEA like "leaq -48(%rsp), %rsp" an alloc unwind code should be fine.
>
>>> Have you planned to fix PR16779, too?
>>
>> Well, only if I find a good solution. (I already tried but had no
>> success.)
>
> My first impression was that the general principle (over-allocate and
> align later on) shouldn't be too difficult to, though the prolog
> generating code is quite complex already. Did you stumble upon other
> problems?
>
> -Nico
>

-------------- next part --------------
>From 48e3a407c6ff8397e6958bf0f33027061bf54369 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 |  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                 | 162 +++++++++++++++++++++++++++
 8 files changed, 322 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 422b0fd..2bd1a4e 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 8ef4a0a..3de482f 100644
--- a/lib/MC/MCObjectFileInfo.cpp
+++ b/lib/MC/MCObjectFileInfo.cpp
@@ -574,11 +574,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 9304dec..dc6e1de 100644
--- a/lib/Target/X86/MCTargetDesc/X86MCAsmInfo.cpp
+++ b/lib/Target/X86/MCTargetDesc/X86MCAsmInfo.cpp
@@ -125,7 +125,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) {
     GlobalPrefix = '\0';
     PrivateGlobalPrefix = ".L";
   }
@@ -135,12 +136,17 @@ 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) {
     GlobalPrefix = '\0';
     PrivateGlobalPrefix = ".L";
   }
@@ -150,5 +156,8 @@ X86MCAsmInfoGNUCOFF::X86MCAsmInfoGNUCOFF(const Triple &Triple) {
   TextAlignFillValue = 0x90;
 
   // Exceptions handling
-  ExceptionsType = ExceptionHandling::DwarfCFI;
+  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 cf47dc4..106cf0b 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 825f216..ddecede 100644
--- a/lib/Target/X86/X86ISelLowering.cpp
+++ b/lib/Target/X86/X86ISelLowering.cpp
@@ -596,7 +596,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 85af0b4..76796dd 100644
--- a/lib/Target/X86/X86MCInstLower.cpp
+++ b/lib/Target/X86/X86MCInstLower.cpp
@@ -770,7 +770,129 @@ 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;
+  unsigned 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);
+    }
+  } 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);
+    break;
+  case X86::MOV64mr:
+  case X86::MOVAPSmr:
+    DReg = MI->getOperand(0).getReg();
+    Offset = MI->getOperand(0).getOffset();
+    SReg = MI->getOperand(1).getReg();
+    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);
+    }
+    break;
+  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");
+    }
+    else
+      llvm_unreachable("X86::X86::LEA64r not allowed with these operands");
+    break;
+  case X86::MOV64ri:
+    // Occurs before alloca()/call to __chkstk
+    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 is used. Adjust stack on CygMing.
+    if (getSubtarget().isTargetCygMing()) {
+      const MachineInstr *MoveMI = MI->getPrevNode();
+      if (!(MoveMI && MoveMI->getOpcode() == X86::MOV64ri))
+        llvm_unreachable("X86::MOV64ri required before X86::W64ALLOCA");
+      Offset = MoveMI->getOperand(1).getImm();
+      OutStreamer.EmitWin64EHAllocStack(Offset);
+    }
+    break;
+  case X86::SUB64rr:
+    // Occurs after call to __chkstk 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:
@@ -882,4 +1004,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..fc6d28c
--- /dev/null
+++ b/test/CodeGen/X86/win64_eh.ll
@@ -0,0 +1,162 @@
+; RUN: llc < %s -O0 -mtriple=x86_64-pc-win32 | FileCheck %s -check-prefix=WIN64
+; RUN: llc < %s -O0 -mtriple=x86_64-pc-mingw32 | FileCheck %s -check-prefix=MINGW64
+
+; 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
+
+
+; Checks a stack allocation requiring call to __chkstk
+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
+; 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
+
+
+; 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

-------------- next part --------------
diff --git a/lib/Target/X86/X86FrameLowering.cpp b/lib/Target/X86/X86FrameLowering.cpp
index a06ba9d..d8c6a6a 100644
--- a/lib/Target/X86/X86FrameLowering.cpp
+++ b/lib/Target/X86/X86FrameLowering.cpp
@@ -608,14 +608,12 @@ void X86FrameLowering::emitPrologue(MachineFunction &MF) const {
   // virtual memory manager are allocated in correct sequence.
   if (NumBytes >= 4096 && STI.isOSWindows() && !STI.isTargetEnvMacho()) {
     const char *StackProbeSymbol;
-    bool isSPUpdateNeeded = false;
 
     if (Is64Bit) {
-      if (STI.isTargetCygMing())
-        StackProbeSymbol = "___chkstk";
-      else {
+      if (STI.isTargetCygMing()) {
+        StackProbeSymbol = "___chkstk_ms";
+      } else {
         StackProbeSymbol = "__chkstk";
-        isSPUpdateNeeded = true;
       }
     } else if (STI.isTargetCygMing())
       StackProbeSymbol = "_alloca";
@@ -657,15 +655,15 @@ void X86FrameLowering::emitPrologue(MachineFunction &MF) const {
       .addReg(X86::EFLAGS, RegState::Define | RegState::Implicit)
       .setMIFlag(MachineInstr::FrameSetup);
 
-    // MSVC x64's __chkstk does not adjust %rsp itself.
-    // It also does not clobber %rax so we can reuse it when adjusting %rsp.
-    if (isSPUpdateNeeded) {
+    if (Is64Bit) {
+      // MSVC x64's __chkstk and cygwin/mingw's ___chkstk_ms do not adjust %rsp
+      // themself. It also does not clobber %rax so we can reuse it when
+      // adjusting %rsp.
       BuildMI(MBB, MBBI, DL, TII.get(X86::SUB64rr), StackPtr)
         .addReg(StackPtr)
         .addReg(X86::RAX)
         .setMIFlag(MachineInstr::FrameSetup);
     }
-
     if (isEAXAlive) {
         // Restore EAX
         MachineInstr *MI = addRegOffset(BuildMI(MF, DL, TII.get(X86::MOV32rm),
diff --git a/test/CodeGen/X86/win64_alloca_dynalloca.ll b/test/CodeGen/X86/win64_alloca_dynalloca.ll
index aff5305..a6b6536 100644
--- a/test/CodeGen/X86/win64_alloca_dynalloca.ll
+++ b/test/CodeGen/X86/win64_alloca_dynalloca.ll
@@ -12,11 +12,11 @@ entry:
 
   %buf0 = alloca i8, i64 4096, align 1
 
-; ___chkstk must adjust %rsp.
+; ___chkstk_ms does not adjust %rsp.
 ; M64: movq  %rsp, %rbp
 ; M64:       $4096, %rax
-; M64: callq ___chkstk
-; M64-NOT:   %rsp
+; M64: callq ___chkstk_ms
+; M64: subq  %rax, %rsp
 
 ; __chkstk does not adjust %rsp.
 ; W64: movq  %rsp, %rbp
diff --git a/test/CodeGen/X86/win_chkstk.ll b/test/CodeGen/X86/win_chkstk.ll
index 3f522ea..0c02c1a 100644
--- a/test/CodeGen/X86/win_chkstk.ll
+++ b/test/CodeGen/X86/win_chkstk.ll
@@ -17,7 +17,7 @@ entry:
 ; WIN_X32:    calll __chkstk
 ; WIN_X64:    callq __chkstk
 ; MINGW_X32:  calll __alloca
-; MINGW_X64:  callq ___chkstk
+; MINGW_X64:  callq ___chkstk_ms
 ; LINUX-NOT:  call __chkstk
   %array4096 = alloca [4096 x i8], align 16       ; <[4096 x i8]*> [#uses=0]
   ret i32 0
@@ -36,7 +36,7 @@ entry:
 ; WIN_X64:       ret
 
 ; MINGW_X64:     # BB#0:
-; MINGW_X64-NOT: callq _alloca
+; MINGW_X64-NOT: callq ___chkstk_ms
 ; MINGW_X64:     ret
 
 ; LINUX:         # BB#0:
@@ -53,7 +53,7 @@ entry:
 ; WIN_X32:    calll __chkstk
 ; WIN_X64:    callq __chkstk
 ; MINGW_X32:  calll __alloca
-; MINGW_X64:  callq ___chkstk
+; MINGW_X64:  callq ___chkstk_ms
 ; LINUX-NOT:  call __chkstk
   %array4096 = alloca [4096 x i8], align 16       ; <[4096 x i8]*> [#uses=0]
   ret i32 0


More information about the llvm-commits mailing list