]> granicus.if.org Git - llvm/commitdiff
x86 interrupt calling convention: re-align stack pointer on 64-bit if an error code...
authorAmjad Aboud <amjad.aboud@intel.com>
Mon, 3 Apr 2017 20:28:45 +0000 (20:28 +0000)
committerAmjad Aboud <amjad.aboud@intel.com>
Mon, 3 Apr 2017 20:28:45 +0000 (20:28 +0000)
The x86_64 ABI requires that the stack is 16 byte aligned on function calls. Thus, the 8-byte error code, which is pushed by the CPU for certain exceptions, leads to a misaligned stack. This results in bugs such as Bug 26413, where misaligned movaps instructions are generated.

This commit fixes the misalignment by adjusting the stack pointer in these cases. The adjustment is done at the beginning of the prologue generation by subtracting another 8 bytes from the stack pointer. These additional bytes are popped again in the function epilogue.

Fixes Bug 26413

Patch by Philipp Oppermann.

Differential Revision: https://reviews.llvm.org/D30049

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

lib/Target/X86/X86FrameLowering.cpp
lib/Target/X86/X86ISelLowering.cpp
test/CodeGen/X86/x86-64-intrcc-nosse.ll
test/CodeGen/X86/x86-64-intrcc.ll

index a80be2047d29621a8cad13a1ceb543badae1ac7f..fc5c9ac2e25f374aee21418906128520c0c9afac 100644 (file)
@@ -988,6 +988,16 @@ void X86FrameLowering::emitPrologue(MachineFunction &MF,
         .getValueAsString()
         .getAsInteger(0, StackProbeSize);
 
+  // Re-align the stack on 64-bit if the x86-interrupt calling convention is
+  // used and an error code was pushed, since the x86-64 ABI requires a 16-byte
+  // stack alignment.
+  if (Fn->getCallingConv() == CallingConv::X86_INTR && Is64Bit &&
+      Fn->arg_size() == 2) {
+    StackSize += 8;
+    MFI.setStackSize(StackSize);
+    emitSPUpdate(MBB, MBBI, -8, /*InEpilogue=*/false);
+  }
+
   // If this is x86-64 and the Red Zone is not disabled, if we are a leaf
   // function, and use up to 128 bytes of stack space, don't have a frame
   // pointer, calls, or dynamic alloca then we do not need to adjust the
index b01fcc9082311b9e854a09e3939593b9ec169b6e..fc39d9bff71d1837b927954ce7b4ec51795125e3 100644 (file)
@@ -2791,6 +2791,11 @@ X86TargetLowering::LowerMemArgument(SDValue Chain, CallingConv::ID CallConv,
     // Offset of last argument need to be set to -4/-8 bytes.
     // Where offset of the first argument out of two, should be set to 0 bytes.
     Offset = (Subtarget.is64Bit() ? 8 : 4) * ((i + 1) % Ins.size() - 1);
+    if (Subtarget.is64Bit() && Ins.size() == 2) {
+      // The stack pointer needs to be realigned for 64 bit handlers with error
+      // code, so the argument offset changes by 8 bytes.
+      Offset += 8;
+    }
   }
 
   // FIXME: For now, all byval parameter objects are marked mutable. This can be
@@ -3248,8 +3253,9 @@ SDValue X86TargetLowering::LowerFormalArguments(
                        MF.getTarget().Options.GuaranteedTailCallOpt)) {
     FuncInfo->setBytesToPopOnReturn(StackSize); // Callee pops everything.
   } else if (CallConv == CallingConv::X86_INTR && Ins.size() == 2) {
-    // X86 interrupts must pop the error code if present
-    FuncInfo->setBytesToPopOnReturn(Is64Bit ? 8 : 4);
+    // X86 interrupts must pop the error code (and the alignment padding) if
+    // present.
+    FuncInfo->setBytesToPopOnReturn(Is64Bit ? 16 : 4);
   } else {
     FuncInfo->setBytesToPopOnReturn(0); // Callee pops nothing.
     // If this is an sret function, the return should pop the hidden pointer.
index 0bb4e47adf094138e190b80b1075638b151590ca..ab84088c34447ff0c7057827722ac747f99ae5a5 100644 (file)
@@ -9,10 +9,11 @@
 define x86_intrcc void @test_isr_sse_clobbers(%struct.interrupt_frame* %frame, i64 %ecode) {
   ; CHECK-LABEL: test_isr_sse_clobbers:
   ; CHECK:       # BB#0:
+  ; CHECK-NEXT:    pushq %rax
   ; CHECK-NEXT:    cld
   ; CHECK-NEXT:    #APP
   ; CHECK-NEXT:    #NO_APP
-  ; CHECK-NEXT:    addq $8, %rsp
+  ; CHECK-NEXT:    addq $16, %rsp
   ; CHECK-NEXT:    iretq
   call void asm sideeffect "", "~{xmm0},~{xmm6}"()
   ret void
index 2bcf3cde478a659a28b6beda70fb52c920bc5390..c8bc9e716ce54d62ba4497a1307e60ea6fcedc66 100644 (file)
@@ -30,22 +30,24 @@ define x86_intrcc void @test_isr_no_ecode(%struct.interrupt_frame* %frame) {
 define x86_intrcc void @test_isr_ecode(%struct.interrupt_frame* %frame, i64 %ecode) {
   ; CHECK-LABEL: test_isr_ecode
   ; CHECK: pushq %rax
+  ; CHECK: pushq %rax
   ; CHECK: pushq %rcx
-  ; CHECK: movq 16(%rsp), %rax
-  ; CHECK: movq 40(%rsp), %rcx
+  ; CHECK: movq 24(%rsp), %rax
+  ; CHECK: movq 48(%rsp), %rcx
   ; CHECK: popq %rcx
   ; CHECK: popq %rax
-  ; CHECK: addq $8, %rsp
+  ; CHECK: addq $16, %rsp
   ; CHECK: iretq
   ; CHECK0-LABEL: test_isr_ecode
   ; CHECK0: pushq %rax
+  ; CHECK0: pushq %rax
   ; CHECK0: pushq %rcx
-  ; CHECK0: movq 16(%rsp), %rax
-  ; CHECK0: leaq 24(%rsp), %rcx
+  ; CHECK0: movq 24(%rsp), %rax
+  ; CHECK0: leaq 32(%rsp), %rcx
   ; CHECK0: movq 16(%rcx), %rcx
   ; CHECK0: popq %rcx
   ; CHECK0: popq %rax
-  ; CHECK0: addq $8, %rsp
+  ; CHECK0: addq $16, %rsp
   ; CHECK0: iretq
   %pflags = getelementptr inbounds %struct.interrupt_frame, %struct.interrupt_frame* %frame, i32 0, i32 2
   %flags = load i64, i64* %pflags, align 4
@@ -58,6 +60,7 @@ define x86_intrcc void @test_isr_clobbers(%struct.interrupt_frame* %frame, i64 %
   call void asm sideeffect "", "~{rax},~{rbx},~{rbp},~{r11},~{xmm0}"()
   ; CHECK-LABEL: test_isr_clobbers
   ; CHECK-SSE-NEXT: pushq %rax
+  ; CHECK-SSE-NEXT: pushq %rax
   ; CHECK-SSE-NEXT; pushq %r11
   ; CHECK-SSE-NEXT: pushq %rbp
   ; CHECK-SSE-NEXT: pushq %rbx
@@ -80,7 +83,7 @@ define x86_intrcc void @test_isr_clobbers(%struct.interrupt_frame* %frame, i64 %
   ; CHECK0-SSE-NEXT: popq %rbp
   ; CHECK0-SSE-NEXT: popq %r11
   ; CHECK0-SSE-NEXT: popq %rax
-  ; CHECK0-SSE-NEXT: addq $8, %rsp
+  ; CHECK0-SSE-NEXT: addq $16, %rsp
   ; CHECK0-SSE-NEXT: iretq
   ret void
 }