xref: /llvm-project/llvm/test/CodeGen/X86/x32-va_start.ll (revision f8395f8420cee8fc0854f43c9e88819c0ed54696)
1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
2; RUN: llc < %s -mtriple=x86_64-linux-gnux32 | FileCheck %s -check-prefix=SSE
3; RUN: llc < %s -mtriple=x86_64-linux-gnux32 -mattr=-sse | FileCheck %s -check-prefix=NOSSE
4; RUN: llc < %s -mtriple=i386-linux-gnux32 | FileCheck %s -check-prefix=X32BITABI
5; RUN: llc < %s -mtriple=i686-linux-gnux32 | FileCheck %s -check-prefix=X32BITABI
6;
7; Verifies that x32 va_start lowering is sane. To regenerate this test, use
8; cat <<EOF |
9; #include <stdarg.h>
10;
11; int foo(float a, const char* fmt, ...) {
12;   va_list ap;
13;   va_start(ap, fmt);
14;   int value = va_arg(ap, int);
15;   va_end(ap);
16;   return value;
17; }
18; EOF
19; build/bin/clang -mx32 -O3 -o- -S -emit-llvm -xc -
20;
21target datalayout = "e-m:e-p:32:32-i64:64-f80:128-n8:16:32:64-S128"
22target triple = "x86_64-unknown-linux-gnux32"
23
24%struct.__va_list_tag = type { i32, i32, ptr, ptr }
25
26define i32 @foo(float %a, ptr nocapture readnone %fmt, ...) nounwind {
27; SSE-LABEL: foo:
28; SSE:       # %bb.0: # %entry
29; SSE-NEXT:    subl $72, %esp
30; SSE-NEXT:    movq %rsi, -{{[0-9]+}}(%esp)
31; SSE-NEXT:    movq %rdx, -{{[0-9]+}}(%esp)
32; SSE-NEXT:    movq %rcx, -{{[0-9]+}}(%esp)
33; SSE-NEXT:    movq %r8, -{{[0-9]+}}(%esp)
34; SSE-NEXT:    movq %r9, -{{[0-9]+}}(%esp)
35; SSE-NEXT:    testb %al, %al
36; SSE-NEXT:    je .LBB0_5
37; SSE-NEXT:  # %bb.4: # %entry
38; SSE-NEXT:    movaps %xmm1, -{{[0-9]+}}(%esp)
39; SSE-NEXT:    movaps %xmm2, -{{[0-9]+}}(%esp)
40; SSE-NEXT:    movaps %xmm3, -{{[0-9]+}}(%esp)
41; SSE-NEXT:    movaps %xmm4, (%esp)
42; SSE-NEXT:    movaps %xmm5, {{[0-9]+}}(%esp)
43; SSE-NEXT:    movaps %xmm6, {{[0-9]+}}(%esp)
44; SSE-NEXT:    movaps %xmm7, {{[0-9]+}}(%esp)
45; SSE-NEXT:  .LBB0_5: # %entry
46; SSE-NEXT:    leal -{{[0-9]+}}(%rsp), %eax
47; SSE-NEXT:    movl %eax, -{{[0-9]+}}(%esp)
48; SSE-NEXT:    leal {{[0-9]+}}(%rsp), %eax
49; SSE-NEXT:    movl %eax, -{{[0-9]+}}(%esp)
50; SSE-NEXT:    movabsq $274877906952, %rax # imm = 0x4000000008
51; SSE-NEXT:    movq %rax, -{{[0-9]+}}(%esp)
52; SSE-NEXT:    movl $8, %ecx
53; SSE-NEXT:    cmpl $40, %ecx
54; SSE-NEXT:    ja .LBB0_2
55; SSE-NEXT:  # %bb.1: # %vaarg.in_reg
56; SSE-NEXT:    movl -{{[0-9]+}}(%esp), %eax
57; SSE-NEXT:    addl %ecx, %eax
58; SSE-NEXT:    addl $8, %ecx
59; SSE-NEXT:    movl %ecx, -{{[0-9]+}}(%esp)
60; SSE-NEXT:    jmp .LBB0_3
61; SSE-NEXT:  .LBB0_2: # %vaarg.in_mem
62; SSE-NEXT:    movl -{{[0-9]+}}(%esp), %eax
63; SSE-NEXT:    leal 8(%rax), %ecx
64; SSE-NEXT:    movl %ecx, -{{[0-9]+}}(%esp)
65; SSE-NEXT:  .LBB0_3: # %vaarg.end
66; SSE-NEXT:    movl (%eax), %eax
67; SSE-NEXT:    addl $72, %esp
68; SSE-NEXT:    retq
69;
70; NOSSE-LABEL: foo:
71; NOSSE:       # %bb.0: # %entry
72; NOSSE-NEXT:    movq %rsi, -{{[0-9]+}}(%esp)
73; NOSSE-NEXT:    movq %rdx, -{{[0-9]+}}(%esp)
74; NOSSE-NEXT:    movq %rcx, -{{[0-9]+}}(%esp)
75; NOSSE-NEXT:    movq %r8, -{{[0-9]+}}(%esp)
76; NOSSE-NEXT:    movq %r9, -{{[0-9]+}}(%esp)
77; NOSSE-NEXT:    leal -{{[0-9]+}}(%rsp), %eax
78; NOSSE-NEXT:    movl %eax, -{{[0-9]+}}(%esp)
79; NOSSE-NEXT:    leal {{[0-9]+}}(%rsp), %eax
80; NOSSE-NEXT:    movl %eax, -{{[0-9]+}}(%esp)
81; NOSSE-NEXT:    movabsq $206158430216, %rax # imm = 0x3000000008
82; NOSSE-NEXT:    movq %rax, -{{[0-9]+}}(%esp)
83; NOSSE-NEXT:    movl $8, %ecx
84; NOSSE-NEXT:    cmpl $40, %ecx
85; NOSSE-NEXT:    ja .LBB0_2
86; NOSSE-NEXT:  # %bb.1: # %vaarg.in_reg
87; NOSSE-NEXT:    movl -{{[0-9]+}}(%esp), %eax
88; NOSSE-NEXT:    addl %ecx, %eax
89; NOSSE-NEXT:    addl $8, %ecx
90; NOSSE-NEXT:    movl %ecx, -{{[0-9]+}}(%esp)
91; NOSSE-NEXT:    movl (%eax), %eax
92; NOSSE-NEXT:    retq
93; NOSSE-NEXT:  .LBB0_2: # %vaarg.in_mem
94; NOSSE-NEXT:    movl -{{[0-9]+}}(%esp), %eax
95; NOSSE-NEXT:    leal 8(%rax), %ecx
96; NOSSE-NEXT:    movl %ecx, -{{[0-9]+}}(%esp)
97; NOSSE-NEXT:    movl (%eax), %eax
98; NOSSE-NEXT:    retq
99;
100; X32BITABI-LABEL: foo:
101; X32BITABI:       # %bb.0: # %entry
102; X32BITABI-NEXT:    subl $28, %esp
103; X32BITABI-NEXT:    leal {{[0-9]+}}(%esp), %ecx
104; X32BITABI-NEXT:    movl %ecx, (%esp)
105; X32BITABI-NEXT:    cmpl $40, %ecx
106; X32BITABI-NEXT:    ja .LBB0_2
107; X32BITABI-NEXT:  # %bb.1: # %vaarg.in_reg
108; X32BITABI-NEXT:    movl {{[0-9]+}}(%esp), %eax
109; X32BITABI-NEXT:    addl %ecx, %eax
110; X32BITABI-NEXT:    addl $8, %ecx
111; X32BITABI-NEXT:    movl %ecx, (%esp)
112; X32BITABI-NEXT:    jmp .LBB0_3
113; X32BITABI-NEXT:  .LBB0_2: # %vaarg.in_mem
114; X32BITABI-NEXT:    movl {{[0-9]+}}(%esp), %eax
115; X32BITABI-NEXT:    leal 8(%eax), %ecx
116; X32BITABI-NEXT:    movl %ecx, {{[0-9]+}}(%esp)
117; X32BITABI-NEXT:  .LBB0_3: # %vaarg.end
118; X32BITABI-NEXT:    movl (%eax), %eax
119; X32BITABI-NEXT:    addl $28, %esp
120; X32BITABI-NEXT:    retl
121entry:
122  %ap = alloca [1 x %struct.__va_list_tag], align 16
123  call void @llvm.lifetime.start.p0(i64 16, ptr %ap) #2
124  call void @llvm.va_start(ptr %ap)
125  %gp_offset = load i32, ptr %ap, align 16
126  %fits_in_gp = icmp ult i32 %gp_offset, 41
127  br i1 %fits_in_gp, label %vaarg.in_reg, label %vaarg.in_mem
128
129vaarg.in_reg:                                     ; preds = %entry
130  %0 = getelementptr inbounds [1 x %struct.__va_list_tag], ptr %ap, i32 0, i32 0, i32 3
131  %reg_save_area = load ptr, ptr %0, align 4
132  %1 = getelementptr i8, ptr %reg_save_area, i32 %gp_offset
133  %2 = add i32 %gp_offset, 8
134  store i32 %2, ptr %ap, align 16
135  br label %vaarg.end
136vaarg.in_mem:                                     ; preds = %entry
137  %overflow_arg_area_p = getelementptr inbounds [1 x %struct.__va_list_tag], ptr %ap, i32 0, i32 0, i32 2
138  %overflow_arg_area = load ptr, ptr %overflow_arg_area_p, align 8
139  %overflow_arg_area.next = getelementptr i8, ptr %overflow_arg_area, i32 8
140  store ptr %overflow_arg_area.next, ptr %overflow_arg_area_p, align 8
141  br label %vaarg.end
142
143vaarg.end:                                        ; preds = %vaarg.in_mem, %vaarg.in_reg
144  %vaarg.addr.in = phi ptr [ %1, %vaarg.in_reg ], [ %overflow_arg_area, %vaarg.in_mem ]
145  %3 = load i32, ptr %vaarg.addr.in, align 4
146  call void @llvm.va_end(ptr %ap)
147  call void @llvm.lifetime.end.p0(i64 16, ptr %ap) #2
148  ret i32 %3
149}
150
151; Function Attrs: nounwind argmemonly
152declare void @llvm.lifetime.start.p0(i64, ptr nocapture) nounwind
153
154; Function Attrs: nounwind
155declare void @llvm.va_start(ptr) nounwind
156
157; Function Attrs: nounwind
158declare void @llvm.va_end(ptr) nounwind
159
160; Function Attrs: nounwind argmemonly
161declare void @llvm.lifetime.end.p0(i64, ptr nocapture) nounwind
162
163