[PATCH][X86_64/MC] Emit personality function and Dwarf EH data for Win64 SEH

Kai Nacke kai.nacke at redstar.de
Sun Sep 15 12:33:30 PDT 2013


On 15.09.2013 20:45, Anton Korobeynikov wrote:
> Kai,
>
> Just to make stuff clear: are you going to submit clang patches, so
> the _GCC_specific_handler is emitted in IR on mingw64, for example?

I am going to submit a patch so that LLVM generates the required 
UNWIND_INFO for Win64 SEH. Clang could use this to generate EH handling 
on mingw64 which uses the way described by me (I currently do not intend 
to extend clang in this way but I also could have a look at it).
The name of the handler is always part of the landingpad IR. Depending 
on the language, clang emits already different personality function 
names. The list is in clang\lib\CodeGen\CGException.cpp.

In essence, my patch simply emits the name of the personality function 
from the landingpad IR.

To make it really clear I attach the intended next patch. The code has 
still some rough edges but I used it successfully for EH handling with 
the LDC compiler.

Regards
Kai

>
> On Sun, Sep 15, 2013 at 10:27 PM, Kai Nacke <kai.nacke at redstar.de> wrote:
>> Hi!
>>
>> Currently, the MC code emits a hard-coded name for the personality function.
>> Obviously the function specified by the user should be emitted as language
>> handler.
>> There is no special language data section for SEH. Instead the data is
>> emitted after the unwind data and the reference to the handler function.
>> See also the specification for the struct UNWIND_INFO in the msdn:
>> http://msdn.microsoft.com/en-us/library/ddssxxy8.aspx
>>
>> This is the same as gcc 4.8.0 does. In case of SEH the handler function is
>> called __gcc_personality_imp and the LSDA is stored in the handler data.
>>
>> The attached patch changes the output to be conformant to the specification.
>> As of now there is no code path which can trigger this code therefore no
>> test case is included. My next patch enables proper EH handling on Win64 and
>> will include test cases for this change, too.
>>
>> Please review.
>>
>> Regards
>> Kai
>
>
>

-------------- next part --------------
From 7d54484a94f0c6e41427ffba19d2f1128c1b5192 Mon Sep 17 00:00:00 2001
From: kai <kai at redstar.de>
Date: Wed, 29 May 2013 07:10:59 +0200
Subject: [PATCH 4/4] Add Win64 exception handling.

This patch enables exception handling on Windows based on the
structured exception handling mechanism built into the OS.
Most of this patch is based on work by Charles Davis.
---
 lib/Target/X86/MCTargetDesc/X86MCAsmInfo.cpp |  7 ++-
 lib/Target/X86/X86AsmPrinter.h               |  3 ++
 lib/Target/X86/X86ISelLowering.cpp           |  3 +-
 lib/Target/X86/X86MCInstLower.cpp            | 70 ++++++++++++++++++++++++++++
 4 files changed, 81 insertions(+), 2 deletions(-)

diff --git a/lib/Target/X86/MCTargetDesc/X86MCAsmInfo.cpp b/lib/Target/X86/MCTargetDesc/X86MCAsmInfo.cpp
index 36b6eb4..6b484d5 100644
--- a/lib/Target/X86/MCTargetDesc/X86MCAsmInfo.cpp
+++ b/lib/Target/X86/MCTargetDesc/X86MCAsmInfo.cpp
@@ -130,7 +130,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 = "";
     PrivateGlobalPrefix = ".L";
   }
@@ -138,6 +139,10 @@ X86MCAsmInfoMicrosoft::X86MCAsmInfoMicrosoft(const Triple &Triple) {
   AssemblerDialect = AsmWriterFlavor;
 
   TextAlignFillValue = 0x90;
+
+  // Exceptions handling
+  if (is64Bit)
+    ExceptionsType = ExceptionHandling::Win64;
 }
 
 void X86MCAsmInfoGNUCOFF::anchor() { }
diff --git a/lib/Target/X86/X86AsmPrinter.h b/lib/Target/X86/X86AsmPrinter.h
index 6eed5ce..aa4227d 100644
--- a/lib/Target/X86/X86AsmPrinter.h
+++ b/lib/Target/X86/X86AsmPrinter.h
@@ -24,6 +24,9 @@ class MCStreamer;
 
 class LLVM_LIBRARY_VISIBILITY X86AsmPrinter : public AsmPrinter {
   const X86Subtarget *Subtarget;
+
+  void EmitUnwindingInstruction(const MachineInstr *MI);
+
  public:
   explicit X86AsmPrinter(TargetMachine &TM, MCStreamer &Streamer)
     : AsmPrinter(TM, Streamer) {
diff --git a/lib/Target/X86/X86ISelLowering.cpp b/lib/Target/X86/X86ISelLowering.cpp
index b3cac05..a738a5e 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 c7c00b5..57fb82e 100644
--- a/lib/Target/X86/X86MCInstLower.cpp
+++ b/lib/Target/X86/X86MCInstLower.cpp
@@ -685,6 +685,70 @@ static void LowerTlsAddr(MCStreamer &OutStreamer,
     .addExpr(tlsRef));
 }
 
+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::MOV64ri:
+  case X86::W64ALLOCA:
+    // Occurs if alloca() is used
+    break;
+  }
+  if (MI->getNextNode() &&
+      !MI->getNextNode()->getFlag(MachineInstr::FrameSetup)) {
+    OutStreamer.EmitWin64EHEndProlog();
+  }
+}
+
 void X86AsmPrinter::EmitInstruction(const MachineInstr *MI) {
   X86MCInstLower MCInstLowering(Mang, *MF, *this);
   switch (MI->getOpcode()) {
@@ -779,4 +843,10 @@ 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);
 }
-- 
1.8.0.msysgit.0



More information about the llvm-commits mailing list