[WinEH] Ensure that funclets obey the x64 ABI
authorDavid Majnemer <david.majnemer@gmail.com>
Tue, 29 Sep 2015 22:33:36 +0000 (22:33 +0000)
committerDavid Majnemer <david.majnemer@gmail.com>
Tue, 29 Sep 2015 22:33:36 +0000 (22:33 +0000)
The x64 ABI requires that epilogues do not contain code other than stack
adjustments and some limited control flow.  However, we'd insert code to
initialize the return address after stack adjustments.  Instead, insert
EAX/RAX with the current value before we create the stack adjustments in
the epilogue.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@248839 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Target/X86/X86ExpandPseudo.cpp
lib/Target/X86/X86FrameLowering.cpp
test/CodeGen/X86/win-catchpad-csrs.ll
test/CodeGen/X86/win-catchpad.ll
test/CodeGen/X86/win-funclet-cfi.ll

index c9441bd0c2f1394ecd13ae318be838bfa497c6f4..6a5a28e546f2b2ad464ea06d1f33980605709df0 100644 (file)
@@ -141,41 +141,6 @@ bool X86ExpandPseudo::ExpandMI(MachineBasicBlock &MBB,
     // The EH_RETURN pseudo is really removed during the MC Lowering.
     return true;
   }
-
-  case X86::CLEANUPRET: {
-    // Replace CATCHRET with the appropriate RET.
-    unsigned RetOp = STI->is64Bit() ? X86::RETQ : X86::RETL;
-    BuildMI(MBB, MBBI, DL, TII->get(RetOp));
-    MBBI->eraseFromParent();
-    return true;
-  }
-
-  case X86::CATCHRET: {
-    MachineBasicBlock *TargetMBB = MBBI->getOperand(0).getMBB();
-
-    // Fill EAX/RAX with the address of the target block.
-    unsigned ReturnReg = STI->is64Bit() ? X86::RAX : X86::EAX;
-    unsigned RetOp = STI->is64Bit() ? X86::RETQ : X86::RETL;
-    if (STI->is64Bit()) {
-      // LEA64r TargetMBB(%rip), %rax
-      BuildMI(MBB, MBBI, DL, TII->get(X86::LEA64r), ReturnReg)
-          .addReg(X86::RIP)
-          .addImm(0)
-          .addReg(0)
-          .addMBB(TargetMBB)
-          .addReg(0);
-    } else {
-      // MOV32ri $TargetMBB, %eax
-      BuildMI(MBB, MBBI, DL, TII->get(X86::MOV32ri))
-          .addReg(ReturnReg)
-          .addMBB(TargetMBB);
-    }
-
-    // Replace CATCHRET with the appropriate RET.
-    BuildMI(MBB, MBBI, DL, TII->get(RetOp)).addReg(ReturnReg);
-    MBBI->eraseFromParent();
-    return true;
-  }
   }
   llvm_unreachable("Previous switch has a fallthrough?");
 }
index 0e6b5c4b4045b2cdae19825d99780f5b52773140..b0bd6983654fd33587f5ad121344e85e986d5d11 100644 (file)
@@ -1093,9 +1093,26 @@ void X86FrameLowering::emitEpilogue(MachineFunction &MF,
     if (STI.is32Bit()) {
       RestoreMBB = MF.CreateMachineBasicBlock(MBB.getBasicBlock());
       MF.insert(TargetMBB, RestoreMBB);
-      MBB.transferSuccessors(RestoreMBB);
+      MBB.removeSuccessor(TargetMBB);
       MBB.addSuccessor(RestoreMBB);
-      MBBI->getOperand(0).setMBB(RestoreMBB);
+      RestoreMBB->addSuccessor(TargetMBB);
+    }
+
+    // Fill EAX/RAX with the address of the target block.
+    unsigned ReturnReg = STI.is64Bit() ? X86::RAX : X86::EAX;
+    if (STI.is64Bit()) {
+      // LEA64r RestoreMBB(%rip), %rax
+      BuildMI(MBB, MBBI, DL, TII.get(X86::LEA64r), ReturnReg)
+          .addReg(X86::RIP)
+          .addImm(0)
+          .addReg(0)
+          .addMBB(RestoreMBB)
+          .addReg(0);
+    } else {
+      // MOV32ri $RestoreMBB, %eax
+      BuildMI(MBB, MBBI, DL, TII.get(X86::MOV32ri))
+          .addReg(ReturnReg)
+          .addMBB(RestoreMBB);
     }
 
     // Pop EBP.
@@ -1111,12 +1128,24 @@ void X86FrameLowering::emitEpilogue(MachineFunction &MF,
       BuildMI(*RestoreMBB, RestoreMBBI, DL, TII.get(X86::JMP_4))
           .addMBB(TargetMBB);
     }
-  } else if (isFuncletReturnInstr(MBBI)) {
+    // Replace CATCHRET with the appropriate RET.
+    unsigned RetOp = STI.is64Bit() ? X86::RETQ : X86::RETL;
+    MachineBasicBlock::iterator NewExit =
+        BuildMI(MBB, MBBI, DL, TII.get(RetOp)).addReg(ReturnReg);
+    MBBI->eraseFromParent();
+    MBBI = NewExit;
+  } else if (MBBI->getOpcode() == X86::CLEANUPRET) {
     NumBytes = MFI->getMaxCallFrameSize();
     assert(hasFP(MF) && "EH funclets without FP not yet implemented");
     BuildMI(MBB, MBBI, DL, TII.get(Is64Bit ? X86::POP64r : X86::POP32r),
             MachineFramePtr)
         .setMIFlag(MachineInstr::FrameDestroy);
+    // Replace CLEANUPRET with the appropriate RET.
+    unsigned RetOp = STI.is64Bit() ? X86::RETQ : X86::RETL;
+    MachineBasicBlock::iterator NewExit =
+        BuildMI(MBB, MBBI, DL, TII.get(RetOp));
+    MBBI->eraseFromParent();
+    MBBI = NewExit;
   } else if (hasFP(MF)) {
     // Calculate required stack adjustment.
     uint64_t FrameSize = StackSize - SlotSize;
index 6603f4e6d927e4e942ba2636d63322da61dbc1e0..4a745121cc470df00b742494345e049743108603 100644 (file)
@@ -80,9 +80,9 @@ catchendblock:                                    ; preds = %catch,
 ; X86: movl $1, -{{[0-9]+}}(%ebp)
 ; X86: movl $2, (%esp)
 ; X86: calll _f
-; X86: addl $16, %esp
+; X86: movl $[[restorebb]], %eax
+; X86-NEXT: addl $16, %esp
 ; X86-NEXT: popl %ebp
-; X86-NEXT: movl $[[restorebb]], %eax
 ; X86-NEXT: retl
 
 ; X86: L__ehtable$try_catch_catch:
@@ -125,9 +125,9 @@ catchendblock:                                    ; preds = %catch,
 ; X64: subq $32, %rsp
 ; X64: movl $2, %ecx
 ; X64: callq f
+; X64: leaq [[contbb]](%rip), %rax
 ; X64: addq $32, %rsp
 ; X64: popq %rbp
-; X64: leaq [[contbb]](%rip), %rax
 ; X64: retq
 
 ; X64: $handlerMap$0$try_catch_catch:
index 7af13e67975c6547fcfb08b8b9644c91fd58cbb2..5a700b444f2c7b61006ee84529e022d81a9ae87e 100644 (file)
@@ -73,7 +73,13 @@ catchendblock:                                    ; preds = %catch, %catch.2, %c
 ; X86: [[contbb:LBB0_[0-9]+]]: # %try.cont
 ; X86: retl
 
-; X86: [[restorebb:LBB0_[0-9]+]]: # %invoke.cont.3
+; FIXME: These should be de-duplicated.
+; X86: [[restorebb1:LBB0_[0-9]+]]: # %invoke.cont.2
+; X86: movl -16(%ebp), %esp
+; X86: addl $12, %ebp
+; X86: jmp [[contbb]]
+
+; X86: [[restorebb2:LBB0_[0-9]+]]: # %invoke.cont.3
 ; X86: movl -16(%ebp), %esp
 ; X86: addl $12, %ebp
 ; X86: jmp [[contbb]]
@@ -89,9 +95,9 @@ catchendblock:                                    ; preds = %catch, %catch.2, %c
 ; X86-DAG: movl %[[addr_reg]], 4(%esp)
 ; X86-DAG: movl %[[e_reg]], (%esp)
 ; X86: calll _f
+; X86-NEXT: movl $[[restorebb1]], %eax
 ; X86-NEXT: addl $8, %esp
 ; X86-NEXT: popl %ebp
-; X86-NEXT: movl $[[restorebb]], %eax
 ; X86-NEXT: retl
 
 ; X86: "?catch$[[catch2bb:[0-9]+]]@?0?try_catch_catch@4HA":
@@ -104,9 +110,9 @@ catchendblock:                                    ; preds = %catch, %catch.2, %c
 ; X86-DAG: movl %[[addr_reg]], 4(%esp)
 ; X86-DAG: movl $3, (%esp)
 ; X86: calll _f
+; X86-NEXT: movl $[[restorebb2]], %eax
 ; X86-NEXT: addl $8, %esp
 ; X86-NEXT: popl %ebp
-; X86-NEXT: movl $[[restorebb]], %eax
 ; X86-NEXT: retl
 
 ; X86: L__ehtable$try_catch_catch:
@@ -147,9 +153,9 @@ catchendblock:                                    ; preds = %catch, %catch.2, %c
 ; X64-DAG: leaq -[[local_offs]](%rbp), %rdx
 ; X64-DAG: movl [[e_addr:[-0-9]+]](%rbp), %ecx
 ; X64: callq f
-; X64: addq $32, %rsp
+; X64: leaq [[contbb]](%rip), %rax
+; X64-NEXT: addq $32, %rsp
 ; X64-NEXT: popq %rbp
-; X64-NEXT: leaq [[contbb]](%rip), %rax
 ; X64-NEXT: retq
 
 ; X64: "?catch$[[catch2bb:[0-9]+]]@?0?try_catch_catch@4HA":
@@ -162,9 +168,9 @@ catchendblock:                                    ; preds = %catch, %catch.2, %c
 ; X64-DAG: movl $3, %ecx
 ; X64: callq f
 ; X64: .Ltmp3
-; X64: addq $32, %rsp
+; X64: leaq [[contbb]](%rip), %rax
+; X64-NEXT: addq $32, %rsp
 ; X64-NEXT: popq %rbp
-; X64-NEXT: leaq [[contbb]](%rip), %rax
 ; X64-NEXT: retq
 
 ; X64: $cppxdata$try_catch_catch:
index 30883791d8efc30ad16efcd5da16265d3442b251..63a81d8155185e7b8e430f0eb7b234b123dd76dc 100644 (file)
@@ -89,9 +89,9 @@ declare i32 @__CxxFrameHandler3(...)
 ; Prologue is done, emit the .seh_endprologue directive.
 ; CHECK: .seh_endprologue
 
-; Make sure there is a nop after a call if the call precedes the epilogue.
+; Make sure there is at least one instruction after a call before the epilogue.
 ; CHECK: callq g
-; CHECK-NEXT: nop
+; CHECK-NEXT: leaq    .LBB0_{{[0-9]+}}(%rip), %rax
 
 ; Emit a reference to the LSDA.
 ; CHECK: .seh_handlerdata