| ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py |
| ; RUN: llc < %s -mtriple=x86_64-unknown-linux-gnu -verify-machineinstrs | FileCheck %s --check-prefix=LINUX |
| ; RUN: llc < %s -mtriple=x86_64-pc-windows-msvc -verify-machineinstrs | FileCheck %s --check-prefix=WIN64 |
| |
| ; A 128-byte stack adjustment should be emitted as `add rsp, -128` in the |
| ; prologue and `sub rsp, -128` in the epilogue: 128 misses the sign-extended |
| ; 8-bit immediate form, but -128 fits it, saving three bytes each. Windows |
| ; epilogues keep the canonical `add rsp, imm` because the Win64 v1 unwinder |
| ; recognizes epilogues by disassembling for it; prologues are located by |
| ; SizeOfProlog and never disassembled, so they may flip. |
| |
| declare void @escape(ptr) |
| |
| ; One value lives across the call, forcing a single CSR push; the 120 bytes |
| ; of locals then round up to a 128-byte adjustment on Linux. |
| define ptr @frame128(ptr %p) { |
| ; LINUX-LABEL: frame128: |
| ; LINUX: # %bb.0: |
| ; LINUX-NEXT: pushq %rbx |
| ; LINUX-NEXT: .cfi_def_cfa_offset 16 |
| ; LINUX-NEXT: addq $-128, %rsp |
| ; LINUX-NEXT: .cfi_def_cfa_offset 144 |
| ; LINUX-NEXT: .cfi_offset %rbx, -16 |
| ; LINUX-NEXT: movq %rdi, %rbx |
| ; LINUX-NEXT: leaq {{[0-9]+}}(%rsp), %rdi |
| ; LINUX-NEXT: callq escape@PLT |
| ; LINUX-NEXT: movq %rbx, %rax |
| ; LINUX-NEXT: subq $-128, %rsp |
| ; LINUX-NEXT: .cfi_def_cfa_offset 16 |
| ; LINUX-NEXT: popq %rbx |
| ; LINUX-NEXT: .cfi_def_cfa_offset 8 |
| ; LINUX-NEXT: retq |
| ; |
| ; WIN64-LABEL: frame128: |
| ; WIN64: # %bb.0: |
| ; WIN64-NEXT: pushq %rsi |
| ; WIN64-NEXT: .seh_pushreg %rsi |
| ; WIN64-NEXT: subq $160, %rsp |
| ; WIN64-NEXT: .seh_stackalloc 160 |
| ; WIN64-NEXT: .seh_endprologue |
| ; WIN64-NEXT: movq %rcx, %rsi |
| ; WIN64-NEXT: leaq {{[0-9]+}}(%rsp), %rcx |
| ; WIN64-NEXT: callq escape |
| ; WIN64-NEXT: movq %rsi, %rax |
| ; WIN64-NEXT: .seh_startepilogue |
| ; WIN64-NEXT: addq $160, %rsp |
| ; WIN64-NEXT: popq %rsi |
| ; WIN64-NEXT: .seh_endepilogue |
| ; WIN64-NEXT: retq |
| ; WIN64-NEXT: .seh_endproc |
| %buf = alloca [120 x i8] |
| call void @escape(ptr %buf) |
| ret ptr %p |
| } |
| |
| ; The same shape with 96 bytes of locals reaches a 128-byte adjustment on |
| ; Win64 (32-byte shadow area included): the prologue flips to `add rsp, -128` |
| ; but the epilogue must keep `add rsp, 128`. |
| define ptr @frame128_win(ptr %p) { |
| ; LINUX-LABEL: frame128_win: |
| ; LINUX: # %bb.0: |
| ; LINUX-NEXT: pushq %rbx |
| ; LINUX-NEXT: .cfi_def_cfa_offset 16 |
| ; LINUX-NEXT: subq $96, %rsp |
| ; LINUX-NEXT: .cfi_def_cfa_offset 112 |
| ; LINUX-NEXT: .cfi_offset %rbx, -16 |
| ; LINUX-NEXT: movq %rdi, %rbx |
| ; LINUX-NEXT: movq %rsp, %rdi |
| ; LINUX-NEXT: callq escape@PLT |
| ; LINUX-NEXT: movq %rbx, %rax |
| ; LINUX-NEXT: addq $96, %rsp |
| ; LINUX-NEXT: .cfi_def_cfa_offset 16 |
| ; LINUX-NEXT: popq %rbx |
| ; LINUX-NEXT: .cfi_def_cfa_offset 8 |
| ; LINUX-NEXT: retq |
| ; |
| ; WIN64-LABEL: frame128_win: |
| ; WIN64: # %bb.0: |
| ; WIN64-NEXT: pushq %rsi |
| ; WIN64-NEXT: .seh_pushreg %rsi |
| ; WIN64-NEXT: addq $-128, %rsp |
| ; WIN64-NEXT: .seh_stackalloc 128 |
| ; WIN64-NEXT: .seh_endprologue |
| ; WIN64-NEXT: movq %rcx, %rsi |
| ; WIN64-NEXT: leaq {{[0-9]+}}(%rsp), %rcx |
| ; WIN64-NEXT: callq escape |
| ; WIN64-NEXT: movq %rsi, %rax |
| ; WIN64-NEXT: .seh_startepilogue |
| ; WIN64-NEXT: addq $128, %rsp |
| ; WIN64-NEXT: popq %rsi |
| ; WIN64-NEXT: .seh_endepilogue |
| ; WIN64-NEXT: retq |
| ; WIN64-NEXT: .seh_endproc |
| %buf = alloca [96 x i8] |
| call void @escape(ptr %buf) |
| ret ptr %p |
| } |
| |
| ; An adjacent size keeps the plain 32-bit immediate. |
| define ptr @frame144(ptr %p) { |
| ; LINUX-LABEL: frame144: |
| ; LINUX: # %bb.0: |
| ; LINUX-NEXT: pushq %rbx |
| ; LINUX-NEXT: .cfi_def_cfa_offset 16 |
| ; LINUX-NEXT: subq $144, %rsp |
| ; LINUX-NEXT: .cfi_def_cfa_offset 160 |
| ; LINUX-NEXT: .cfi_offset %rbx, -16 |
| ; LINUX-NEXT: movq %rdi, %rbx |
| ; LINUX-NEXT: leaq {{[0-9]+}}(%rsp), %rdi |
| ; LINUX-NEXT: callq escape@PLT |
| ; LINUX-NEXT: movq %rbx, %rax |
| ; LINUX-NEXT: addq $144, %rsp |
| ; LINUX-NEXT: .cfi_def_cfa_offset 16 |
| ; LINUX-NEXT: popq %rbx |
| ; LINUX-NEXT: .cfi_def_cfa_offset 8 |
| ; LINUX-NEXT: retq |
| ; |
| ; WIN64-LABEL: frame144: |
| ; WIN64: # %bb.0: |
| ; WIN64-NEXT: pushq %rsi |
| ; WIN64-NEXT: .seh_pushreg %rsi |
| ; WIN64-NEXT: subq $176, %rsp |
| ; WIN64-NEXT: .seh_stackalloc 176 |
| ; WIN64-NEXT: .seh_endprologue |
| ; WIN64-NEXT: movq %rcx, %rsi |
| ; WIN64-NEXT: leaq {{[0-9]+}}(%rsp), %rcx |
| ; WIN64-NEXT: callq escape |
| ; WIN64-NEXT: movq %rsi, %rax |
| ; WIN64-NEXT: .seh_startepilogue |
| ; WIN64-NEXT: addq $176, %rsp |
| ; WIN64-NEXT: popq %rsi |
| ; WIN64-NEXT: .seh_endepilogue |
| ; WIN64-NEXT: retq |
| ; WIN64-NEXT: .seh_endproc |
| %buf = alloca [136 x i8] |
| call void @escape(ptr %buf) |
| ret ptr %p |
| } |