Skip to content

Commit d3e77f5

Browse files
authored
Try to use non-volatile registers for preserve_none parameters (#88333)
This uses non-volatile registers for the first four (six on Windows) registers used for `preserve_none` argument passing. This allows these registers to stay "pinned", even if the body of the `preserve_none` function contains calls to other "normal" functions. Example: ```c void boring(void); __attribute__((preserve_none)) void (continuation)(void *, void *, void *, void *); __attribute__((preserve_none)) void entry(void *a, void *b, void *c, void *d) { boring(); __attribute__((musttail)) return continuation(a, b, c, d); } ``` Before: ```asm pushq %rax movq %rcx, %rbx movq %rdx, %r14 movq %rsi, %r15 movq %rdi, %r12 callq boring@PLT movq %r12, %rdi movq %r15, %rsi movq %r14, %rdx movq %rbx, %rcx popq %rax jmp continuation@PLT ``` After: ```asm pushq %rax callq boring@PLT popq %rax jmp continuation@PLT ```
1 parent 657eda3 commit d3e77f5

File tree

4 files changed

+64
-22
lines changed

4 files changed

+64
-22
lines changed

clang/include/clang/Basic/AttrDocs.td

+3-2
Original file line numberDiff line numberDiff line change
@@ -5663,11 +5663,12 @@ The ``preserve_none`` calling convention tries to preserve as few general
56635663
registers as possible. So all general registers are caller saved registers. It
56645664
also uses more general registers to pass arguments. This attribute doesn't
56655665
impact floating-point registers (XMMs/YMMs). Floating-point registers still
5666-
follow the c calling convention.
5666+
follow the c calling convention. ``preserve_none``'s ABI is still unstable, and
5667+
may be changed in the future.
56675668

56685669
- Only RSP and RBP are preserved by callee.
56695670

5670-
- Register RDI, RSI, RDX, RCX, R8, R9, R11, R12, R13, R14, R15 and RAX now can
5671+
- Register R12, R13, R14, R15, RDI, RSI, RDX, RCX, R8, R9, R11, and RAX now can
56715672
be used to pass function arguments.
56725673
}];
56735674
}

llvm/lib/Target/X86/X86CallingConv.td

+6-4
Original file line numberDiff line numberDiff line change
@@ -1063,11 +1063,13 @@ def CC_X86_64_Preserve_None : CallingConv<[
10631063
// - R10 'nest' parameter
10641064
// - RBX base pointer
10651065
// - R16 - R31 these are not available everywhere
1066-
CCIfType<[i32], CCAssignToReg<[EDI, ESI, EDX, ECX, R8D, R9D,
1067-
R11D, R12D, R13D, R14D, R15D, EAX]>>,
1066+
// Use non-volatile registers first, so functions using this convention can
1067+
// call "normal" functions without saving and restoring incoming values:
1068+
CCIfType<[i32], CCAssignToReg<[R12D, R13D, R14D, R15D, EDI, ESI,
1069+
EDX, ECX, R8D, R9D, R11D, EAX]>>,
10681070

1069-
CCIfType<[i64], CCAssignToReg<[RDI, RSI, RDX, RCX, R8, R9,
1070-
R11, R12, R13, R14, R15, RAX]>>,
1071+
CCIfType<[i64], CCAssignToReg<[R12, R13, R14, R15, RDI, RSI,
1072+
RDX, RCX, R8, R9, R11, RAX]>>,
10711073

10721074
// Otherwise it's the same as the regular C calling convention.
10731075
CCDelegateTo<CC_X86_64_C>

llvm/test/CodeGen/X86/preserve_nonecc_call.ll

+34-16
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ define void @caller1(ptr %a) {
2727
; CHECK-NEXT: .cfi_offset %r13, -32
2828
; CHECK-NEXT: .cfi_offset %r14, -24
2929
; CHECK-NEXT: .cfi_offset %r15, -16
30+
; CHECK-NEXT: movq %rdi, %r12
3031
; CHECK-NEXT: callq callee@PLT
3132
; CHECK-NEXT: popq %rbx
3233
; CHECK-NEXT: .cfi_def_cfa_offset 40
@@ -61,17 +62,17 @@ define preserve_nonecc i64 @callee_with_many_param(i64 %a1, i64 %a2, i64 %a3, i6
6162
; CHECK: # %bb.0:
6263
; CHECK-NEXT: pushq %rax
6364
; CHECK-NEXT: .cfi_def_cfa_offset 16
65+
; CHECK-NEXT: movq %r13, %r12
66+
; CHECK-NEXT: movq %r14, %r13
67+
; CHECK-NEXT: movq %r15, %r14
68+
; CHECK-NEXT: movq %rdi, %r15
6469
; CHECK-NEXT: movq %rsi, %rdi
6570
; CHECK-NEXT: movq %rdx, %rsi
6671
; CHECK-NEXT: movq %rcx, %rdx
6772
; CHECK-NEXT: movq %r8, %rcx
6873
; CHECK-NEXT: movq %r9, %r8
6974
; CHECK-NEXT: movq %r11, %r9
70-
; CHECK-NEXT: movq %r12, %r11
71-
; CHECK-NEXT: movq %r13, %r12
72-
; CHECK-NEXT: movq %r14, %r13
73-
; CHECK-NEXT: movq %r15, %r14
74-
; CHECK-NEXT: movq %rax, %r15
75+
; CHECK-NEXT: movq %rax, %r11
7576
; CHECK-NEXT: callq callee_with_many_param2@PLT
7677
; CHECK-NEXT: popq %rcx
7778
; CHECK-NEXT: .cfi_def_cfa_offset 8
@@ -98,17 +99,17 @@ define i64 @caller3() {
9899
; CHECK-NEXT: .cfi_offset %r13, -32
99100
; CHECK-NEXT: .cfi_offset %r14, -24
100101
; CHECK-NEXT: .cfi_offset %r15, -16
101-
; CHECK-NEXT: movl $1, %edi
102-
; CHECK-NEXT: movl $2, %esi
103-
; CHECK-NEXT: movl $3, %edx
104-
; CHECK-NEXT: movl $4, %ecx
105-
; CHECK-NEXT: movl $5, %r8d
106-
; CHECK-NEXT: movl $6, %r9d
107-
; CHECK-NEXT: movl $7, %r11d
108-
; CHECK-NEXT: movl $8, %r12d
109-
; CHECK-NEXT: movl $9, %r13d
110-
; CHECK-NEXT: movl $10, %r14d
111-
; CHECK-NEXT: movl $11, %r15d
102+
; CHECK-NEXT: movl $1, %r12d
103+
; CHECK-NEXT: movl $2, %r13d
104+
; CHECK-NEXT: movl $3, %r14d
105+
; CHECK-NEXT: movl $4, %r15d
106+
; CHECK-NEXT: movl $5, %edi
107+
; CHECK-NEXT: movl $6, %esi
108+
; CHECK-NEXT: movl $7, %edx
109+
; CHECK-NEXT: movl $8, %ecx
110+
; CHECK-NEXT: movl $9, %r8d
111+
; CHECK-NEXT: movl $10, %r9d
112+
; CHECK-NEXT: movl $11, %r11d
112113
; CHECK-NEXT: movl $12, %eax
113114
; CHECK-NEXT: callq callee_with_many_param@PLT
114115
; CHECK-NEXT: popq %rbx
@@ -125,3 +126,20 @@ define i64 @caller3() {
125126
%ret = call preserve_nonecc i64 @callee_with_many_param(i64 1, i64 2, i64 3, i64 4, i64 5, i64 6, i64 7, i64 8, i64 9, i64 10, i64 11, i64 12)
126127
ret i64 %ret
127128
}
129+
130+
; Non-volatile registers are used to pass the first few parameters.
131+
declare void @boring()
132+
declare preserve_nonecc void @continuation(ptr, ptr, ptr, ptr)
133+
define preserve_nonecc void @entry(ptr %r12, ptr %r13, ptr %r14, ptr %r15) {
134+
; CHECK-LABEL: entry:
135+
; CHECK: # %bb.0:
136+
; CHECK-NEXT: pushq %rax
137+
; CHECK-NEXT: .cfi_def_cfa_offset 16
138+
; CHECK-NEXT: callq boring@PLT
139+
; CHECK-NEXT: popq %rax
140+
; CHECK-NEXT: .cfi_def_cfa_offset 8
141+
; CHECK-NEXT: jmp continuation@PLT # TAILCALL
142+
call void @boring()
143+
musttail call preserve_nonecc void @continuation(ptr %r12, ptr %r13, ptr %r14, ptr %r15)
144+
ret void
145+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 4
2+
; RUN: llc -mtriple=x86_64-pc-windows-msvc -mcpu=corei7 < %s | FileCheck %s
3+
4+
; Non-volatile registers are used to pass the first few parameters.
5+
declare void @boring()
6+
declare preserve_nonecc void @continuation(ptr, ptr, ptr, ptr, ptr, ptr)
7+
define preserve_nonecc void @entry(ptr %r12, ptr %r13, ptr %r14, ptr %r15, ptr %rdi, ptr %rsi) {
8+
; CHECK-LABEL: entry:
9+
; CHECK: # %bb.0:
10+
; CHECK-NEXT: subq $40, %rsp
11+
; CHECK-NEXT: .seh_stackalloc 40
12+
; CHECK-NEXT: .seh_endprologue
13+
; CHECK-NEXT: callq boring
14+
; CHECK-NEXT: nop
15+
; CHECK-NEXT: addq $40, %rsp
16+
; CHECK-NEXT: jmp continuation # TAILCALL
17+
; CHECK-NEXT: .seh_endproc
18+
call void @boring()
19+
musttail call preserve_nonecc void @continuation(ptr %r12, ptr %r13, ptr %r14, ptr %r15, ptr %rdi, ptr %rsi)
20+
ret void
21+
}

0 commit comments

Comments
 (0)