[llvm] 031866f - [X86] Don't double count the interrupt stack alignment push in StackSize (#224029)

via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 22 03:52:10 PDT 2026


Author: Timur Golubovich
Date: 2026-09-22T12:52:04+02:00
New Revision: 031866ff849401f9f42c5fba1e9a84ece38dadbc

URL: https://github.com/llvm/llvm-project/commit/031866ff849401f9f42c5fba1e9a84ece38dadbc
DIFF: https://github.com/llvm/llvm-project/commit/031866ff849401f9f42c5fba1e9a84ece38dadbc.diff

LOG: [X86] Don't double count the interrupt stack alignment push in StackSize (#224029)

emitPrologue pushes a slot to give an error-code handler the
return-address parity the frame layout assumes, but StackSize counted
that push as well. NumBytes derives from StackSize, so the subq grew by
8 too and left RSP at 8 mod 16 at every call. Object addresses are
unchanged.

Fixes #44560, fixes #50195

---------

Co-authored-by: Claude Opus 5 <noreply at anthropic.com>

Added: 
    

Modified: 
    llvm/lib/Target/X86/X86FrameLowering.cpp
    llvm/test/CodeGen/X86/x86-64-intrcc.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/X86/X86FrameLowering.cpp b/llvm/lib/Target/X86/X86FrameLowering.cpp
index 7b9f03c87ecdc..fad665e31bbe5 100644
--- a/llvm/lib/Target/X86/X86FrameLowering.cpp
+++ b/llvm/lib/Target/X86/X86FrameLowering.cpp
@@ -1783,9 +1783,6 @@ void X86FrameLowering::emitPrologue(MachineFunction &MF,
   // stack alignment.
   if (Fn.getCallingConv() == CallingConv::X86_INTR && Is64Bit &&
       Fn.arg_size() == 2) {
-    StackSize += 8;
-    MFI.setStackSize(StackSize);
-
     // Update the stack pointer by pushing a register. This is the instruction
     // emitted that would be end up being emitted by a call to `emitSPUpdate`.
     // Hard-coding the update to a push avoids emitting a second

diff  --git a/llvm/test/CodeGen/X86/x86-64-intrcc.ll b/llvm/test/CodeGen/X86/x86-64-intrcc.ll
index 5fc606eb566ea..5f9e84378c24a 100644
--- a/llvm/test/CodeGen/X86/x86-64-intrcc.ll
+++ b/llvm/test/CodeGen/X86/x86-64-intrcc.ll
@@ -1,3 +1,4 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --no_x86_scrub_sp
 ; RUN: llc -mtriple=x86_64-unknown-unknown < %s | FileCheck %s
 ; RUN: llc -mtriple=x86_64-unknown-unknown -O0 < %s | FileCheck %s -check-prefix=CHECK0
 
@@ -8,18 +9,27 @@
 
 ; Spills rax, putting original esp at +8.
 ; No stack adjustment if declared with no error code
-define x86_intrcc void @test_isr_no_ecode(ptr byval(%struct.interrupt_frame) %frame) {
-  ; CHECK-LABEL: test_isr_no_ecode:
-  ; CHECK: pushq %rax
-  ; CHECK: movq 24(%rsp), %rax
-  ; CHECK: popq %rax
-  ; CHECK: iretq
-  ; CHECK0-LABEL: test_isr_no_ecode:
-  ; CHECK0: pushq %rax
-  ; CHECK0: leaq 8(%rsp), %rax
-  ; CHECK0: movq 16(%rax), %rax
-  ; CHECK0: popq %rax
-  ; CHECK0: iretq
+define x86_intrcc void @test_isr_no_ecode(ptr byval(%struct.interrupt_frame) %frame) nounwind {
+; CHECK-LABEL: test_isr_no_ecode:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    pushq %rax
+; CHECK-NEXT:    cld
+; CHECK-NEXT:    movq 24(%rsp), %rax
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    popq %rax
+; CHECK-NEXT:    iretq
+;
+; CHECK0-LABEL: test_isr_no_ecode:
+; CHECK0:       # %bb.0:
+; CHECK0-NEXT:    pushq %rax
+; CHECK0-NEXT:    cld
+; CHECK0-NEXT:    leaq 8(%rsp), %rax
+; CHECK0-NEXT:    movq 16(%rax), %rax
+; CHECK0-NEXT:    #APP
+; CHECK0-NEXT:    #NO_APP
+; CHECK0-NEXT:    popq %rax
+; CHECK0-NEXT:    iretq
   %pflags = getelementptr inbounds %struct.interrupt_frame, ptr %frame, i32 0, i32 2
   %flags = load i64, ptr %pflags, align 4
   call void asm sideeffect "", "r"(i64 %flags)
@@ -28,28 +38,37 @@ define x86_intrcc void @test_isr_no_ecode(ptr byval(%struct.interrupt_frame) %fr
 
 ; Spills rax and rcx, putting original rsp at +16. Stack is adjusted up another 8 bytes
 ; before return, popping the error code.
-define x86_intrcc void @test_isr_ecode(ptr byval(%struct.interrupt_frame) %frame, i64 %ecode) {
-  ; CHECK-LABEL: test_isr_ecode
-  ; CHECK: pushq %rax
-  ; CHECK: pushq %rax
-  ; CHECK: pushq %rcx
-  ; CHECK: movq 24(%rsp), %rax
-  ; CHECK: movq 48(%rsp), %rcx
-  ; CHECK: popq %rcx
-  ; CHECK: popq %rax
-  ; CHECK: addq $16, %rsp
-  ; CHECK: iretq
-  ; CHECK0-LABEL: test_isr_ecode
-  ; CHECK0: pushq %rax
-  ; CHECK0: pushq %rax
-  ; CHECK0: pushq %rcx
-  ; CHECK0: movq 24(%rsp), %rcx
-  ; CHECK0: leaq 32(%rsp), %rax
-  ; CHECK0: movq 16(%rax), %rax
-  ; CHECK0: popq %rcx
-  ; CHECK0: popq %rax
-  ; CHECK0: addq $16, %rsp
-  ; CHECK0: iretq
+define x86_intrcc void @test_isr_ecode(ptr byval(%struct.interrupt_frame) %frame, i64 %ecode) nounwind {
+; CHECK-LABEL: test_isr_ecode:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    pushq %rax
+; CHECK-NEXT:    pushq %rax
+; CHECK-NEXT:    pushq %rcx
+; CHECK-NEXT:    cld
+; CHECK-NEXT:    movq 24(%rsp), %rax
+; CHECK-NEXT:    movq 48(%rsp), %rcx
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    popq %rcx
+; CHECK-NEXT:    popq %rax
+; CHECK-NEXT:    addq $16, %rsp
+; CHECK-NEXT:    iretq
+;
+; CHECK0-LABEL: test_isr_ecode:
+; CHECK0:       # %bb.0:
+; CHECK0-NEXT:    pushq %rax
+; CHECK0-NEXT:    pushq %rax
+; CHECK0-NEXT:    pushq %rcx
+; CHECK0-NEXT:    cld
+; CHECK0-NEXT:    movq 24(%rsp), %rcx
+; CHECK0-NEXT:    leaq 32(%rsp), %rax
+; CHECK0-NEXT:    movq 16(%rax), %rax
+; CHECK0-NEXT:    #APP
+; CHECK0-NEXT:    #NO_APP
+; CHECK0-NEXT:    popq %rcx
+; CHECK0-NEXT:    popq %rax
+; CHECK0-NEXT:    addq $16, %rsp
+; CHECK0-NEXT:    iretq
   %pflags = getelementptr inbounds %struct.interrupt_frame, ptr %frame, i32 0, i32 2
   %flags = load i64, ptr %pflags, align 4
   call void asm sideeffect "", "r,r"(i64 %flags, i64 %ecode)
@@ -57,49 +76,67 @@ define x86_intrcc void @test_isr_ecode(ptr byval(%struct.interrupt_frame) %frame
 }
 
 ; All clobbered registers must be saved
-define x86_intrcc void @test_isr_clobbers(ptr byval(%struct.interrupt_frame) %frame, i64 %ecode) {
+define x86_intrcc void @test_isr_clobbers(ptr byval(%struct.interrupt_frame) %frame, i64 %ecode) nounwind {
+; CHECK-LABEL: test_isr_clobbers:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    pushq %rax
+; CHECK-NEXT:    pushq %rax
+; CHECK-NEXT:    pushq %rbp
+; CHECK-NEXT:    pushq %r11
+; CHECK-NEXT:    pushq %rbx
+; CHECK-NEXT:    movaps %xmm0, -24(%rsp) # 16-byte Spill
+; CHECK-NEXT:    cld
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    movaps -24(%rsp), %xmm0 # 16-byte Reload
+; CHECK-NEXT:    popq %rbx
+; CHECK-NEXT:    popq %r11
+; CHECK-NEXT:    popq %rbp
+; CHECK-NEXT:    popq %rax
+; CHECK-NEXT:    addq $16, %rsp
+; CHECK-NEXT:    iretq
+;
+; CHECK0-LABEL: test_isr_clobbers:
+; CHECK0:       # %bb.0:
+; CHECK0-NEXT:    pushq %rax
+; CHECK0-NEXT:    pushq %rax
+; CHECK0-NEXT:    pushq %rbp
+; CHECK0-NEXT:    pushq %r11
+; CHECK0-NEXT:    pushq %rbx
+; CHECK0-NEXT:    movaps %xmm0, -24(%rsp) # 16-byte Spill
+; CHECK0-NEXT:    cld
+; CHECK0-NEXT:    #APP
+; CHECK0-NEXT:    #NO_APP
+; CHECK0-NEXT:    movaps -24(%rsp), %xmm0 # 16-byte Reload
+; CHECK0-NEXT:    popq %rbx
+; CHECK0-NEXT:    popq %r11
+; CHECK0-NEXT:    popq %rbp
+; CHECK0-NEXT:    popq %rax
+; CHECK0-NEXT:    addq $16, %rsp
+; CHECK0-NEXT:    iretq
   call void asm sideeffect "", "~{rax},~{rbx},~{rbp},~{r11},~{xmm0}"()
-  ; CHECK-LABEL: test_isr_clobbers
-
-  ; CHECK: pushq %rax
-  ; CHECK: pushq %rbp
-  ; CHECK: pushq %r11
-  ; CHECK: pushq %rbx
-  ; CHECK: movaps %xmm0
-  ; CHECK: movaps {{.*}}, %xmm0
-  ; CHECK: popq %rbx
-  ; CHECK: popq %r11
-  ; CHECK: popq %rbp
-  ; CHECK: popq %rax
-  ; CHECK: addq $16, %rsp
-  ; CHECK: iretq
-  ; CHECK0-LABEL: test_isr_clobbers
-
-  ; CHECK0: pushq %rax
-  ; CHECK0: pushq %rbp
-  ; CHECK0: pushq %r11
-  ; CHECK0: pushq %rbx
-  ; CHECK0: movaps %xmm0
-  ; CHECK0: movaps {{.*}}, %xmm0
-  ; CHECK0: popq %rbx
-  ; CHECK0: popq %r11
-  ; CHECK0: popq %rbp
-  ; CHECK0: popq %rax
-  ; CHECK0: addq $16, %rsp
-  ; CHECK0: iretq
   ret void
 }
 
 @f80 = common dso_local global x86_fp80 0xK00000000000000000000, align 4
 
 ; Test that the presence of x87 does not crash the FP stackifier
-define x86_intrcc void @test_isr_x87(ptr byval(%struct.interrupt_frame) %frame) {
-  ; CHECK-LABEL: test_isr_x87
-  ; CHECK-DAG: fldt f80
-  ; CHECK-DAG: fld1
-  ; CHECK: faddp
-  ; CHECK-NEXT: fstpt f80
-  ; CHECK-NEXT: iretq
+define x86_intrcc void @test_isr_x87(ptr byval(%struct.interrupt_frame) %frame) nounwind {
+; CHECK-LABEL: test_isr_x87:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    fldt f80(%rip)
+; CHECK-NEXT:    fld1
+; CHECK-NEXT:    faddp %st, %st(1)
+; CHECK-NEXT:    fstpt f80(%rip)
+; CHECK-NEXT:    iretq
+;
+; CHECK0-LABEL: test_isr_x87:
+; CHECK0:       # %bb.0: # %entry
+; CHECK0-NEXT:    fldt f80(%rip)
+; CHECK0-NEXT:    fld1
+; CHECK0-NEXT:    faddp %st, %st(1)
+; CHECK0-NEXT:    fstpt f80(%rip)
+; CHECK0-NEXT:    iretq
 entry:
   %ld = load x86_fp80, ptr @f80, align 4
   %add = fadd x86_fp80 %ld, 0xK3FFF8000000000000000
@@ -110,16 +147,36 @@ entry:
 ; Use a frame pointer to check the offsets. No return address, arguments start
 ; at RBP+4.
 define dso_local x86_intrcc void @test_fp_1(ptr byval(%struct.interrupt_frame) %p) #0 {
-  ; CHECK-LABEL: test_fp_1:
-  ; CHECK: # %bb.0: # %entry
-  ; CHECK-NEXT: pushq %rbp
-  ; CHECK-NEXT: movq %rsp, %rbp
-  ; CHECK-DAG: leaq 8(%rbp), %[[R1:[^ ]*]]
-  ; CHECK-DAG: leaq 40(%rbp), %[[R2:[^ ]*]]
-  ; CHECK: movq %[[R1]], sink_address
-  ; CHECK: movq %[[R2]], sink_address
-  ; CHECK: popq %rbp
-  ; CHECK: iretq
+; CHECK-LABEL: test_fp_1:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    pushq %rbp
+; CHECK-NEXT:    movq %rsp, %rbp
+; CHECK-NEXT:    pushq %rax
+; CHECK-NEXT:    pushq %rcx
+; CHECK-NEXT:    leaq 40(%rbp), %rax
+; CHECK-NEXT:    leaq 8(%rbp), %rcx
+; CHECK-NEXT:    movq %rcx, sink_address(%rip)
+; CHECK-NEXT:    movq %rax, sink_address(%rip)
+; CHECK-NEXT:    popq %rcx
+; CHECK-NEXT:    popq %rax
+; CHECK-NEXT:    popq %rbp
+; CHECK-NEXT:    iretq
+;
+; CHECK0-LABEL: test_fp_1:
+; CHECK0:       # %bb.0: # %entry
+; CHECK0-NEXT:    pushq %rbp
+; CHECK0-NEXT:    movq %rsp, %rbp
+; CHECK0-NEXT:    pushq %rax
+; CHECK0-NEXT:    pushq %rcx
+; CHECK0-NEXT:    leaq 8(%rbp), %rcx
+; CHECK0-NEXT:    movq %rcx, %rax
+; CHECK0-NEXT:    addq $32, %rax
+; CHECK0-NEXT:    movq %rcx, sink_address(%rip)
+; CHECK0-NEXT:    movq %rax, sink_address(%rip)
+; CHECK0-NEXT:    popq %rcx
+; CHECK0-NEXT:    popq %rax
+; CHECK0-NEXT:    popq %rbp
+; CHECK0-NEXT:    iretq
 entry:
   %arrayidx2 = getelementptr inbounds %struct.interrupt_frame, ptr %p, i64 0, i32 4
   store volatile ptr %p, ptr @sink_address
@@ -129,23 +186,51 @@ entry:
 
 ; The error code is between RBP and the interrupt_frame.
 define dso_local x86_intrcc void @test_fp_2(ptr byval(%struct.interrupt_frame) %p, i64 %err) #0 {
-  ; CHECK-LABEL: test_fp_2:
-  ; CHECK: # %bb.0: # %entry
+; CHECK-LABEL: test_fp_2:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    pushq %rax
+; CHECK-NEXT:    pushq %rbp
+; CHECK-NEXT:    movq %rsp, %rbp
+; CHECK-NEXT:    pushq %rax
+; CHECK-NEXT:    pushq %rdx
+; CHECK-NEXT:    pushq %rcx
+; CHECK-NEXT:    movq 16(%rbp), %rax
+; CHECK-NEXT:    leaq 56(%rbp), %rcx
+; CHECK-NEXT:    leaq 24(%rbp), %rdx
+; CHECK-NEXT:    movq %rdx, sink_address(%rip)
+; CHECK-NEXT:    movq %rcx, sink_address(%rip)
+; CHECK-NEXT:    movq %rax, sink_i32(%rip)
+; CHECK-NEXT:    popq %rcx
+; CHECK-NEXT:    popq %rdx
+; CHECK-NEXT:    popq %rax
+; CHECK-NEXT:    popq %rbp
+; CHECK-NEXT:    addq $16, %rsp
+; CHECK-NEXT:    iretq
+;
+; CHECK0-LABEL: test_fp_2:
+; CHECK0:       # %bb.0: # %entry
+; CHECK0-NEXT:    pushq %rax
+; CHECK0-NEXT:    pushq %rbp
+; CHECK0-NEXT:    movq %rsp, %rbp
+; CHECK0-NEXT:    pushq %rax
+; CHECK0-NEXT:    pushq %rdx
+; CHECK0-NEXT:    pushq %rcx
+; CHECK0-NEXT:    movq 16(%rbp), %rax
+; CHECK0-NEXT:    leaq 24(%rbp), %rdx
+; CHECK0-NEXT:    movq %rdx, %rcx
+; CHECK0-NEXT:    addq $32, %rcx
+; CHECK0-NEXT:    movq %rdx, sink_address(%rip)
+; CHECK0-NEXT:    movq %rcx, sink_address(%rip)
+; CHECK0-NEXT:    movq %rax, sink_i32(%rip)
+; CHECK0-NEXT:    popq %rcx
+; CHECK0-NEXT:    popq %rdx
+; CHECK0-NEXT:    popq %rax
+; CHECK0-NEXT:    popq %rbp
+; CHECK0-NEXT:    addq $16, %rsp
+; CHECK0-NEXT:    iretq
   ; This RAX push is just to align the stack.
-  ; CHECK-NEXT: pushq %rax
-  ; CHECK-NEXT: pushq %rbp
-  ; CHECK-NEXT: movq %rsp, %rbp
-  ; CHECK-DAG: movq 16(%rbp), %[[R3:[^ ]*]]
-  ; CHECK-DAG: leaq 24(%rbp), %[[R1:[^ ]*]]
-  ; CHECK-DAG: leaq 56(%rbp), %[[R2:[^ ]*]]
-  ; CHECK: movq %[[R1]], sink_address(%rip)
-  ; CHECK: movq %[[R2]], sink_address(%rip)
-  ; CHECK: movq %[[R3]], sink_i32(%rip)
-  ; CHECK: popq %rbp
   ; Pop off both the error code and the 8 byte alignment adjustment from the
   ; prologue.
-  ; CHECK: addq $16, %rsp
-  ; CHECK: iretq
 entry:
   %arrayidx2 = getelementptr inbounds %struct.interrupt_frame, ptr %p, i64 0, i32 4
   store volatile ptr %p, ptr @sink_address
@@ -156,14 +241,33 @@ entry:
 
 ; Test argument copy elision when copied to a local alloca.
 define x86_intrcc void @test_copy_elide(ptr byval(%struct.interrupt_frame) %frame, i64 %err) #0 {
-  ; CHECK-LABEL: test_copy_elide:
-  ; CHECK: # %bb.0: # %entry
+; CHECK-LABEL: test_copy_elide:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    pushq %rax
+; CHECK-NEXT:    pushq %rbp
+; CHECK-NEXT:    movq %rsp, %rbp
+; CHECK-NEXT:    pushq %rax
+; CHECK-NEXT:    leaq 16(%rbp), %rax
+; CHECK-NEXT:    movq %rax, sink_address(%rip)
+; CHECK-NEXT:    popq %rax
+; CHECK-NEXT:    popq %rbp
+; CHECK-NEXT:    addq $16, %rsp
+; CHECK-NEXT:    iretq
+;
+; CHECK0-LABEL: test_copy_elide:
+; CHECK0:       # %bb.0: # %entry
+; CHECK0-NEXT:    pushq %rax
+; CHECK0-NEXT:    pushq %rbp
+; CHECK0-NEXT:    movq %rsp, %rbp
+; CHECK0-NEXT:    pushq %rax
+; CHECK0-NEXT:    movq 16(%rbp), %rax
+; CHECK0-NEXT:    leaq 16(%rbp), %rax
+; CHECK0-NEXT:    movq %rax, sink_address(%rip)
+; CHECK0-NEXT:    popq %rax
+; CHECK0-NEXT:    popq %rbp
+; CHECK0-NEXT:    addq $16, %rsp
+; CHECK0-NEXT:    iretq
   ; This RAX push is just to align the stack.
-  ; CHECK-NEXT: pushq %rax
-  ; CHECK-NEXT: pushq %rbp
-  ; CHECK-NEXT: movq %rsp, %rbp
-  ; CHECK: leaq 16(%rbp), %[[R1:[^ ]*]]
-  ; CHECK: movq %[[R1]], sink_address(%rip)
 entry:
   %err.addr = alloca i64, align 4
   store i64 %err, ptr %err.addr, align 4
@@ -171,14 +275,135 @@ entry:
   ret void
 }
 
+; An error-code handler is entered with RSP 16-byte aligned, so the pushes and
+; the subq together have to be a multiple of 16 for the call below to be ABI
+; correct. The chain pins the push count as well as the subq so that the total is
+; actually checked; it also catches STACKALLOC_W_PROBING, whose comment line
+; would break it.
+;
+; The checked-in output is currently wrong: 10 * 8 + 280 == 360 == 8 mod 16.
 define x86_intrcc void @test_stack_allocation(ptr byval(%struct.interrupt_frame) %frame, i64 %err) #1 {
-  ; CHECK-LABEL: test_stack_allocation:
-  ; CHECK: # %bb.0: # %entry
-
-  ;; Ensure that STACKALLOC_W_PROBING isn't emitted.
-  ; CHECK-NOT: # fixed size alloca with probing
-  ;; Ensure that stack space is allocated.
-  ; CHECK: subq    $280, %rsp
+; CHECK-LABEL: test_stack_allocation:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    pushq %rax
+; CHECK-NEXT:    pushq %rax
+; CHECK-NEXT:    pushq %r11
+; CHECK-NEXT:    pushq %r10
+; CHECK-NEXT:    pushq %r9
+; CHECK-NEXT:    pushq %r8
+; CHECK-NEXT:    pushq %rdi
+; CHECK-NEXT:    pushq %rsi
+; CHECK-NEXT:    pushq %rdx
+; CHECK-NEXT:    pushq %rcx
+; CHECK-NEXT:    subq $272, %rsp # imm = 0x110
+; CHECK-NEXT:    movaps %xmm15, 256(%rsp) # 16-byte Spill
+; CHECK-NEXT:    movaps %xmm14, 240(%rsp) # 16-byte Spill
+; CHECK-NEXT:    movaps %xmm13, 224(%rsp) # 16-byte Spill
+; CHECK-NEXT:    movaps %xmm12, 208(%rsp) # 16-byte Spill
+; CHECK-NEXT:    movaps %xmm11, 192(%rsp) # 16-byte Spill
+; CHECK-NEXT:    movaps %xmm10, 176(%rsp) # 16-byte Spill
+; CHECK-NEXT:    movaps %xmm9, 160(%rsp) # 16-byte Spill
+; CHECK-NEXT:    movaps %xmm8, 144(%rsp) # 16-byte Spill
+; CHECK-NEXT:    movaps %xmm7, 128(%rsp) # 16-byte Spill
+; CHECK-NEXT:    movaps %xmm6, 112(%rsp) # 16-byte Spill
+; CHECK-NEXT:    movaps %xmm5, 96(%rsp) # 16-byte Spill
+; CHECK-NEXT:    movaps %xmm4, 80(%rsp) # 16-byte Spill
+; CHECK-NEXT:    movaps %xmm3, 64(%rsp) # 16-byte Spill
+; CHECK-NEXT:    movaps %xmm2, 48(%rsp) # 16-byte Spill
+; CHECK-NEXT:    movaps %xmm1, 32(%rsp) # 16-byte Spill
+; CHECK-NEXT:    movaps %xmm0, 16(%rsp) # 16-byte Spill
+; CHECK-NEXT:    cld
+; CHECK-NEXT:    leaq 8(%rsp), %rdi
+; CHECK-NEXT:    callq external_function at PLT
+; CHECK-NEXT:    movaps 16(%rsp), %xmm0 # 16-byte Reload
+; CHECK-NEXT:    movaps 32(%rsp), %xmm1 # 16-byte Reload
+; CHECK-NEXT:    movaps 48(%rsp), %xmm2 # 16-byte Reload
+; CHECK-NEXT:    movaps 64(%rsp), %xmm3 # 16-byte Reload
+; CHECK-NEXT:    movaps 80(%rsp), %xmm4 # 16-byte Reload
+; CHECK-NEXT:    movaps 96(%rsp), %xmm5 # 16-byte Reload
+; CHECK-NEXT:    movaps 112(%rsp), %xmm6 # 16-byte Reload
+; CHECK-NEXT:    movaps 128(%rsp), %xmm7 # 16-byte Reload
+; CHECK-NEXT:    movaps 144(%rsp), %xmm8 # 16-byte Reload
+; CHECK-NEXT:    movaps 160(%rsp), %xmm9 # 16-byte Reload
+; CHECK-NEXT:    movaps 176(%rsp), %xmm10 # 16-byte Reload
+; CHECK-NEXT:    movaps 192(%rsp), %xmm11 # 16-byte Reload
+; CHECK-NEXT:    movaps 208(%rsp), %xmm12 # 16-byte Reload
+; CHECK-NEXT:    movaps 224(%rsp), %xmm13 # 16-byte Reload
+; CHECK-NEXT:    movaps 240(%rsp), %xmm14 # 16-byte Reload
+; CHECK-NEXT:    movaps 256(%rsp), %xmm15 # 16-byte Reload
+; CHECK-NEXT:    addq $272, %rsp # imm = 0x110
+; CHECK-NEXT:    popq %rcx
+; CHECK-NEXT:    popq %rdx
+; CHECK-NEXT:    popq %rsi
+; CHECK-NEXT:    popq %rdi
+; CHECK-NEXT:    popq %r8
+; CHECK-NEXT:    popq %r9
+; CHECK-NEXT:    popq %r10
+; CHECK-NEXT:    popq %r11
+; CHECK-NEXT:    popq %rax
+; CHECK-NEXT:    addq $16, %rsp
+; CHECK-NEXT:    iretq
+;
+; CHECK0-LABEL: test_stack_allocation:
+; CHECK0:       # %bb.0: # %entry
+; CHECK0-NEXT:    pushq %rax
+; CHECK0-NEXT:    pushq %rax
+; CHECK0-NEXT:    pushq %r11
+; CHECK0-NEXT:    pushq %r10
+; CHECK0-NEXT:    pushq %r9
+; CHECK0-NEXT:    pushq %r8
+; CHECK0-NEXT:    pushq %rdi
+; CHECK0-NEXT:    pushq %rsi
+; CHECK0-NEXT:    pushq %rdx
+; CHECK0-NEXT:    pushq %rcx
+; CHECK0-NEXT:    subq $272, %rsp # imm = 0x110
+; CHECK0-NEXT:    movaps %xmm15, 256(%rsp) # 16-byte Spill
+; CHECK0-NEXT:    movaps %xmm14, 240(%rsp) # 16-byte Spill
+; CHECK0-NEXT:    movaps %xmm13, 224(%rsp) # 16-byte Spill
+; CHECK0-NEXT:    movaps %xmm12, 208(%rsp) # 16-byte Spill
+; CHECK0-NEXT:    movaps %xmm11, 192(%rsp) # 16-byte Spill
+; CHECK0-NEXT:    movaps %xmm10, 176(%rsp) # 16-byte Spill
+; CHECK0-NEXT:    movaps %xmm9, 160(%rsp) # 16-byte Spill
+; CHECK0-NEXT:    movaps %xmm8, 144(%rsp) # 16-byte Spill
+; CHECK0-NEXT:    movaps %xmm7, 128(%rsp) # 16-byte Spill
+; CHECK0-NEXT:    movaps %xmm6, 112(%rsp) # 16-byte Spill
+; CHECK0-NEXT:    movaps %xmm5, 96(%rsp) # 16-byte Spill
+; CHECK0-NEXT:    movaps %xmm4, 80(%rsp) # 16-byte Spill
+; CHECK0-NEXT:    movaps %xmm3, 64(%rsp) # 16-byte Spill
+; CHECK0-NEXT:    movaps %xmm2, 48(%rsp) # 16-byte Spill
+; CHECK0-NEXT:    movaps %xmm1, 32(%rsp) # 16-byte Spill
+; CHECK0-NEXT:    movaps %xmm0, 16(%rsp) # 16-byte Spill
+; CHECK0-NEXT:    cld
+; CHECK0-NEXT:    leaq 8(%rsp), %rdi
+; CHECK0-NEXT:    callq external_function at PLT
+; CHECK0-NEXT:    movaps 16(%rsp), %xmm0 # 16-byte Reload
+; CHECK0-NEXT:    movaps 32(%rsp), %xmm1 # 16-byte Reload
+; CHECK0-NEXT:    movaps 48(%rsp), %xmm2 # 16-byte Reload
+; CHECK0-NEXT:    movaps 64(%rsp), %xmm3 # 16-byte Reload
+; CHECK0-NEXT:    movaps 80(%rsp), %xmm4 # 16-byte Reload
+; CHECK0-NEXT:    movaps 96(%rsp), %xmm5 # 16-byte Reload
+; CHECK0-NEXT:    movaps 112(%rsp), %xmm6 # 16-byte Reload
+; CHECK0-NEXT:    movaps 128(%rsp), %xmm7 # 16-byte Reload
+; CHECK0-NEXT:    movaps 144(%rsp), %xmm8 # 16-byte Reload
+; CHECK0-NEXT:    movaps 160(%rsp), %xmm9 # 16-byte Reload
+; CHECK0-NEXT:    movaps 176(%rsp), %xmm10 # 16-byte Reload
+; CHECK0-NEXT:    movaps 192(%rsp), %xmm11 # 16-byte Reload
+; CHECK0-NEXT:    movaps 208(%rsp), %xmm12 # 16-byte Reload
+; CHECK0-NEXT:    movaps 224(%rsp), %xmm13 # 16-byte Reload
+; CHECK0-NEXT:    movaps 240(%rsp), %xmm14 # 16-byte Reload
+; CHECK0-NEXT:    movaps 256(%rsp), %xmm15 # 16-byte Reload
+; CHECK0-NEXT:    addq $272, %rsp # imm = 0x110
+; CHECK0-NEXT:    popq %rcx
+; CHECK0-NEXT:    popq %rdx
+; CHECK0-NEXT:    popq %rsi
+; CHECK0-NEXT:    popq %rdi
+; CHECK0-NEXT:    popq %r8
+; CHECK0-NEXT:    popq %r9
+; CHECK0-NEXT:    popq %r10
+; CHECK0-NEXT:    popq %r11
+; CHECK0-NEXT:    popq %rax
+; CHECK0-NEXT:    addq $16, %rsp
+; CHECK0-NEXT:    iretq
 entry:
   %some_allocation = alloca i64
   ;; Call a un-inlineable function to ensure the allocation isn't put in the red zone.
@@ -186,6 +411,144 @@ entry:
   ret void
 }
 
+; An over-aligned local realigns the stack. If the frame size carries the extra
+; 8 bytes of the parity push, the object lands at 8 mod 64 and
+; getFrameIndexReference asserts. The subq must stay a multiple of 64.
+define x86_intrcc void @test_realigned_object(ptr byval(%struct.interrupt_frame) %frame, i64 %err) #0 {
+; CHECK-LABEL: test_realigned_object:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    pushq %rax
+; CHECK-NEXT:    pushq %rbp
+; CHECK-NEXT:    movq %rsp, %rbp
+; CHECK-NEXT:    pushq %rax
+; CHECK-NEXT:    pushq %r11
+; CHECK-NEXT:    pushq %r10
+; CHECK-NEXT:    pushq %r9
+; CHECK-NEXT:    pushq %r8
+; CHECK-NEXT:    pushq %rdi
+; CHECK-NEXT:    pushq %rsi
+; CHECK-NEXT:    pushq %rdx
+; CHECK-NEXT:    pushq %rcx
+; CHECK-NEXT:    andq $-64, %rsp
+; CHECK-NEXT:    subq $320, %rsp # imm = 0x140
+; CHECK-NEXT:    movaps %xmm15, -96(%rbp) # 16-byte Spill
+; CHECK-NEXT:    movaps %xmm14, -112(%rbp) # 16-byte Spill
+; CHECK-NEXT:    movaps %xmm13, -128(%rbp) # 16-byte Spill
+; CHECK-NEXT:    movaps %xmm12, -144(%rbp) # 16-byte Spill
+; CHECK-NEXT:    movaps %xmm11, -160(%rbp) # 16-byte Spill
+; CHECK-NEXT:    movaps %xmm10, -176(%rbp) # 16-byte Spill
+; CHECK-NEXT:    movaps %xmm9, -192(%rbp) # 16-byte Spill
+; CHECK-NEXT:    movaps %xmm8, -208(%rbp) # 16-byte Spill
+; CHECK-NEXT:    movaps %xmm7, -224(%rbp) # 16-byte Spill
+; CHECK-NEXT:    movaps %xmm6, -240(%rbp) # 16-byte Spill
+; CHECK-NEXT:    movaps %xmm5, -256(%rbp) # 16-byte Spill
+; CHECK-NEXT:    movaps %xmm4, -272(%rbp) # 16-byte Spill
+; CHECK-NEXT:    movaps %xmm3, -288(%rbp) # 16-byte Spill
+; CHECK-NEXT:    movaps %xmm2, -304(%rbp) # 16-byte Spill
+; CHECK-NEXT:    movaps %xmm1, -320(%rbp) # 16-byte Spill
+; CHECK-NEXT:    movaps %xmm0, -336(%rbp) # 16-byte Spill
+; CHECK-NEXT:    cld
+; CHECK-NEXT:    movq %rsp, %rdi
+; CHECK-NEXT:    callq external_function at PLT
+; CHECK-NEXT:    movaps -336(%rbp), %xmm0 # 16-byte Reload
+; CHECK-NEXT:    movaps -320(%rbp), %xmm1 # 16-byte Reload
+; CHECK-NEXT:    movaps -304(%rbp), %xmm2 # 16-byte Reload
+; CHECK-NEXT:    movaps -288(%rbp), %xmm3 # 16-byte Reload
+; CHECK-NEXT:    movaps -272(%rbp), %xmm4 # 16-byte Reload
+; CHECK-NEXT:    movaps -256(%rbp), %xmm5 # 16-byte Reload
+; CHECK-NEXT:    movaps -240(%rbp), %xmm6 # 16-byte Reload
+; CHECK-NEXT:    movaps -224(%rbp), %xmm7 # 16-byte Reload
+; CHECK-NEXT:    movaps -208(%rbp), %xmm8 # 16-byte Reload
+; CHECK-NEXT:    movaps -192(%rbp), %xmm9 # 16-byte Reload
+; CHECK-NEXT:    movaps -176(%rbp), %xmm10 # 16-byte Reload
+; CHECK-NEXT:    movaps -160(%rbp), %xmm11 # 16-byte Reload
+; CHECK-NEXT:    movaps -144(%rbp), %xmm12 # 16-byte Reload
+; CHECK-NEXT:    movaps -128(%rbp), %xmm13 # 16-byte Reload
+; CHECK-NEXT:    movaps -112(%rbp), %xmm14 # 16-byte Reload
+; CHECK-NEXT:    movaps -96(%rbp), %xmm15 # 16-byte Reload
+; CHECK-NEXT:    leaq -72(%rbp), %rsp
+; CHECK-NEXT:    popq %rcx
+; CHECK-NEXT:    popq %rdx
+; CHECK-NEXT:    popq %rsi
+; CHECK-NEXT:    popq %rdi
+; CHECK-NEXT:    popq %r8
+; CHECK-NEXT:    popq %r9
+; CHECK-NEXT:    popq %r10
+; CHECK-NEXT:    popq %r11
+; CHECK-NEXT:    popq %rax
+; CHECK-NEXT:    popq %rbp
+; CHECK-NEXT:    addq $16, %rsp
+; CHECK-NEXT:    iretq
+;
+; CHECK0-LABEL: test_realigned_object:
+; CHECK0:       # %bb.0:
+; CHECK0-NEXT:    pushq %rax
+; CHECK0-NEXT:    pushq %rbp
+; CHECK0-NEXT:    movq %rsp, %rbp
+; CHECK0-NEXT:    pushq %rax
+; CHECK0-NEXT:    pushq %r11
+; CHECK0-NEXT:    pushq %r10
+; CHECK0-NEXT:    pushq %r9
+; CHECK0-NEXT:    pushq %r8
+; CHECK0-NEXT:    pushq %rdi
+; CHECK0-NEXT:    pushq %rsi
+; CHECK0-NEXT:    pushq %rdx
+; CHECK0-NEXT:    pushq %rcx
+; CHECK0-NEXT:    andq $-64, %rsp
+; CHECK0-NEXT:    subq $320, %rsp # imm = 0x140
+; CHECK0-NEXT:    movaps %xmm15, -96(%rbp) # 16-byte Spill
+; CHECK0-NEXT:    movaps %xmm14, -112(%rbp) # 16-byte Spill
+; CHECK0-NEXT:    movaps %xmm13, -128(%rbp) # 16-byte Spill
+; CHECK0-NEXT:    movaps %xmm12, -144(%rbp) # 16-byte Spill
+; CHECK0-NEXT:    movaps %xmm11, -160(%rbp) # 16-byte Spill
+; CHECK0-NEXT:    movaps %xmm10, -176(%rbp) # 16-byte Spill
+; CHECK0-NEXT:    movaps %xmm9, -192(%rbp) # 16-byte Spill
+; CHECK0-NEXT:    movaps %xmm8, -208(%rbp) # 16-byte Spill
+; CHECK0-NEXT:    movaps %xmm7, -224(%rbp) # 16-byte Spill
+; CHECK0-NEXT:    movaps %xmm6, -240(%rbp) # 16-byte Spill
+; CHECK0-NEXT:    movaps %xmm5, -256(%rbp) # 16-byte Spill
+; CHECK0-NEXT:    movaps %xmm4, -272(%rbp) # 16-byte Spill
+; CHECK0-NEXT:    movaps %xmm3, -288(%rbp) # 16-byte Spill
+; CHECK0-NEXT:    movaps %xmm2, -304(%rbp) # 16-byte Spill
+; CHECK0-NEXT:    movaps %xmm1, -320(%rbp) # 16-byte Spill
+; CHECK0-NEXT:    movaps %xmm0, -336(%rbp) # 16-byte Spill
+; CHECK0-NEXT:    cld
+; CHECK0-NEXT:    movq %rsp, %rdi
+; CHECK0-NEXT:    callq external_function at PLT
+; CHECK0-NEXT:    movaps -336(%rbp), %xmm0 # 16-byte Reload
+; CHECK0-NEXT:    movaps -320(%rbp), %xmm1 # 16-byte Reload
+; CHECK0-NEXT:    movaps -304(%rbp), %xmm2 # 16-byte Reload
+; CHECK0-NEXT:    movaps -288(%rbp), %xmm3 # 16-byte Reload
+; CHECK0-NEXT:    movaps -272(%rbp), %xmm4 # 16-byte Reload
+; CHECK0-NEXT:    movaps -256(%rbp), %xmm5 # 16-byte Reload
+; CHECK0-NEXT:    movaps -240(%rbp), %xmm6 # 16-byte Reload
+; CHECK0-NEXT:    movaps -224(%rbp), %xmm7 # 16-byte Reload
+; CHECK0-NEXT:    movaps -208(%rbp), %xmm8 # 16-byte Reload
+; CHECK0-NEXT:    movaps -192(%rbp), %xmm9 # 16-byte Reload
+; CHECK0-NEXT:    movaps -176(%rbp), %xmm10 # 16-byte Reload
+; CHECK0-NEXT:    movaps -160(%rbp), %xmm11 # 16-byte Reload
+; CHECK0-NEXT:    movaps -144(%rbp), %xmm12 # 16-byte Reload
+; CHECK0-NEXT:    movaps -128(%rbp), %xmm13 # 16-byte Reload
+; CHECK0-NEXT:    movaps -112(%rbp), %xmm14 # 16-byte Reload
+; CHECK0-NEXT:    movaps -96(%rbp), %xmm15 # 16-byte Reload
+; CHECK0-NEXT:    leaq -72(%rbp), %rsp
+; CHECK0-NEXT:    popq %rcx
+; CHECK0-NEXT:    popq %rdx
+; CHECK0-NEXT:    popq %rsi
+; CHECK0-NEXT:    popq %rdi
+; CHECK0-NEXT:    popq %r8
+; CHECK0-NEXT:    popq %r9
+; CHECK0-NEXT:    popq %r10
+; CHECK0-NEXT:    popq %r11
+; CHECK0-NEXT:    popq %rax
+; CHECK0-NEXT:    popq %rbp
+; CHECK0-NEXT:    addq $16, %rsp
+; CHECK0-NEXT:    iretq
+  %over_aligned = alloca i64, align 64
+  call void @external_function(ptr %over_aligned)
+  ret void
+}
+
 declare void @external_function(ptr)
 
 attributes #0 = { nounwind "frame-pointer"="all" }


        


More information about the llvm-commits mailing list