1 // RUN: %clang_cc1 -triple mips-unknown-linux -o - -emit-llvm %s | FileCheck %s -check-prefixes=ALL,O32 -enable-var-scope
2 // RUN: %clang_cc1 -triple mipsel-unknown-linux -o - -emit-llvm %s | FileCheck %s -check-prefixes=ALL,O32 -enable-var-scope
3 // RUN: %clang_cc1 -triple mips64-unknown-linux -o - -emit-llvm  -target-abi n32 %s | FileCheck %s -check-prefixes=ALL,N32,NEW -enable-var-scope
4 // RUN: %clang_cc1 -triple mips64-unknown-linux -o - -emit-llvm  -target-abi n32 %s | FileCheck %s -check-prefixes=ALL,N32,NEW -enable-var-scope
5 // RUN: %clang_cc1 -triple mips64-unknown-linux -o - -emit-llvm %s | FileCheck %s -check-prefixes=ALL,N64,NEW -enable-var-scope
6 // RUN: %clang_cc1 -triple mips64el-unknown-linux -o - -emit-llvm %s | FileCheck %s -check-prefixes=ALL,N64,NEW -enable-var-scope
7 
8 #include <stdarg.h>
9 
10 typedef int v4i32 __attribute__ ((__vector_size__ (16)));
11 
test_i32(char * fmt,...)12 int test_i32(char *fmt, ...) {
13   va_list va;
14 
15   va_start(va, fmt);
16   int v = va_arg(va, int);
17   va_end(va);
18 
19   return v;
20 }
21 
22 // O32-LABEL: define{{.*}} i32 @test_i32(i8*{{.*}} %fmt, ...)
23 // N32-LABEL: define{{.*}} signext i32 @test_i32(i8*{{.*}} %fmt, ...)
24 // N64-LABEL: define{{.*}} signext i32 @test_i32(i8*{{.*}} %fmt, ...)
25 //
26 // O32:   %va = alloca i8*, align [[$PTRALIGN:4]]
27 // N32:   %va = alloca i8*, align [[$PTRALIGN:4]]
28 // N64:   %va = alloca i8*, align [[$PTRALIGN:8]]
29 // ALL:   [[V:%.*]] = alloca i32, align 4
30 // NEW:   [[PROMOTION_TEMP:%.*]] = alloca i32, align 4
31 //
32 // ALL:   [[VA:%.+]] = bitcast i8** %va to i8*
33 // ALL:   call void @llvm.va_start(i8* [[VA]])
34 // ALL:   [[AP_CUR:%.+]] = load i8*, i8** %va, align [[$PTRALIGN]]
35 // O32:   [[AP_NEXT:%.+]] = getelementptr inbounds i8, i8* [[AP_CUR]], [[$INTPTR_T:i32]] [[$CHUNKSIZE:4]]
36 // NEW:   [[AP_NEXT:%.+]] = getelementptr inbounds i8, i8* [[AP_CUR]], [[$INTPTR_T:i32|i64]] [[$CHUNKSIZE:8]]
37 //
38 // ALL:   store i8* [[AP_NEXT]], i8** %va, align [[$PTRALIGN]]
39 //
40 // O32:   [[AP_CAST:%.+]] = bitcast i8* [[AP_CUR]] to [[CHUNK_T:i32]]*
41 // O32:   [[ARG:%.+]] = load i32, i32* [[AP_CAST]], align [[CHUNKALIGN:4]]
42 //
43 // N32:   [[AP_CAST:%.+]] = bitcast i8* [[AP_CUR]] to [[CHUNK_T:i64]]*
44 // N32:   [[TMP:%.+]] = load i64, i64* [[AP_CAST]], align [[CHUNKALIGN:8]]
45 // N64:   [[AP_CAST:%.+]] = bitcast i8* [[AP_CUR]] to [[CHUNK_T:i64]]*
46 // N64:   [[TMP:%.+]] = load i64, i64* [[AP_CAST]], align [[CHUNKALIGN:8]]
47 // NEW:   [[TMP2:%.+]] = trunc i64 [[TMP]] to i32
48 // NEW:   store i32 [[TMP2]], i32* [[PROMOTION_TEMP]], align 4
49 // NEW:   [[ARG:%.+]] = load i32, i32* [[PROMOTION_TEMP]], align 4
50 // ALL:   store i32 [[ARG]], i32* [[V]], align 4
51 //
52 // ALL:   [[VA1:%.+]] = bitcast i8** %va to i8*
53 // ALL:   call void @llvm.va_end(i8* [[VA1]])
54 // ALL: }
55 
test_i64(char * fmt,...)56 long long test_i64(char *fmt, ...) {
57   va_list va;
58 
59   va_start(va, fmt);
60   long long v = va_arg(va, long long);
61   va_end(va);
62 
63   return v;
64 }
65 
66 // ALL-LABEL: define{{.*}} i64 @test_i64(i8*{{.*}} %fmt, ...)
67 //
68 // ALL:   %va = alloca i8*, align [[$PTRALIGN]]
69 // ALL:   [[VA:%.+]] = bitcast i8** %va to i8*
70 // ALL:   call void @llvm.va_start(i8* [[VA]])
71 // ALL:   [[AP_CUR:%.+]] = load i8*, i8** %va, align [[$PTRALIGN]]
72 //
73 // i64 is 8-byte aligned, while this is within O32's stack alignment there's no
74 // guarantee that the offset is still 8-byte aligned after earlier reads.
75 // O32:   [[TMP1:%.+]] = ptrtoint i8* [[AP_CUR]] to i32
76 // O32:   [[TMP2:%.+]] = add i32 [[TMP1]], 7
77 // O32:   [[TMP3:%.+]] = and i32 [[TMP2]], -8
78 // O32:   [[AP_CUR:%.+]] = inttoptr i32 [[TMP3]] to i8*
79 //
80 // ALL:   [[AP_NEXT:%.+]] = getelementptr inbounds i8, i8* [[AP_CUR]], [[$INTPTR_T]] 8
81 // ALL:   store i8* [[AP_NEXT]], i8** %va, align [[$PTRALIGN]]
82 //
83 // ALL:   [[AP_CAST:%.*]] = bitcast i8* [[AP_CUR]] to i64*
84 // ALL:   [[ARG:%.+]] = load i64, i64* [[AP_CAST]], align 8
85 //
86 // ALL:   [[VA1:%.+]] = bitcast i8** %va to i8*
87 // ALL:   call void @llvm.va_end(i8* [[VA1]])
88 // ALL: }
89 
test_ptr(char * fmt,...)90 char *test_ptr(char *fmt, ...) {
91   va_list va;
92 
93   va_start(va, fmt);
94   char *v = va_arg(va, char *);
95   va_end(va);
96 
97   return v;
98 }
99 
100 // ALL-LABEL: define{{.*}} i8* @test_ptr(i8*{{.*}} %fmt, ...)
101 //
102 // ALL:   %va = alloca i8*, align [[$PTRALIGN]]
103 // ALL:   [[V:%.*]] = alloca i8*, align [[$PTRALIGN]]
104 // N32:   [[AP_CAST:%.+]] = alloca i8*, align 4
105 // ALL:   [[VA:%.+]] = bitcast i8** %va to i8*
106 // ALL:   call void @llvm.va_start(i8* [[VA]])
107 // ALL:   [[AP_CUR:%.+]] = load i8*, i8** %va, align [[$PTRALIGN]]
108 // ALL:   [[AP_NEXT:%.+]] = getelementptr inbounds i8, i8* [[AP_CUR]], [[$INTPTR_T]] [[$CHUNKSIZE]]
109 // ALL:   store i8* [[AP_NEXT]], i8** %va, align [[$PTRALIGN]]
110 //
111 // When the chunk size matches the pointer size, this is easy.
112 // O32:   [[AP_CAST:%.+]] = bitcast i8* [[AP_CUR]] to i8**
113 // N64:   [[AP_CAST:%.+]] = bitcast i8* [[AP_CUR]] to i8**
114 // Otherwise we need a promotion temporary.
115 // N32:   [[TMP1:%.+]] = bitcast i8* [[AP_CUR]] to i64*
116 // N32:   [[TMP2:%.+]] = load i64, i64* [[TMP1]], align 8
117 // N32:   [[TMP3:%.+]] = trunc i64 [[TMP2]] to i32
118 // N32:   [[PTR:%.+]] = inttoptr i32 [[TMP3]] to i8*
119 // N32:   store i8* [[PTR]], i8** [[AP_CAST]], align 4
120 //
121 // ALL:   [[ARG:%.+]] = load i8*, i8** [[AP_CAST]], align [[$PTRALIGN]]
122 // ALL:   store i8* [[ARG]], i8** [[V]], align [[$PTRALIGN]]
123 //
124 // ALL:   [[VA1:%.+]] = bitcast i8** %va to i8*
125 // ALL:   call void @llvm.va_end(i8* [[VA1]])
126 // ALL: }
127 
test_v4i32(char * fmt,...)128 int test_v4i32(char *fmt, ...) {
129   va_list va;
130 
131   va_start(va, fmt);
132   v4i32 v = va_arg(va, v4i32);
133   va_end(va);
134 
135   return v[0];
136 }
137 
138 // O32-LABEL: define{{.*}} i32 @test_v4i32(i8*{{.*}} %fmt, ...)
139 // N32-LABEL: define{{.*}} signext i32 @test_v4i32(i8*{{.*}} %fmt, ...)
140 // N64-LABEL: define{{.*}} signext i32 @test_v4i32(i8*{{.*}} %fmt, ...)
141 //
142 // ALL:   %va = alloca i8*, align [[$PTRALIGN]]
143 // ALL:   [[V:%.+]] = alloca <4 x i32>, align 16
144 // ALL:   [[VA1:%.+]] = bitcast i8** %va to i8*
145 // ALL:   call void @llvm.va_start(i8* [[VA1]])
146 // ALL:   [[AP_CUR:%.+]] = load i8*, i8** %va, align [[$PTRALIGN]]
147 //
148 // Vectors are 16-byte aligned, however the O32 ABI has a maximum alignment of
149 // 8-bytes since the base of the stack is 8-byte aligned.
150 // O32:   [[TMP1:%.+]] = ptrtoint i8* [[AP_CUR]] to i32
151 // O32:   [[TMP2:%.+]] = add i32 [[TMP1]], 7
152 // O32:   [[TMP3:%.+]] = and i32 [[TMP2]], -8
153 // O32:   [[AP_CUR:%.+]] = inttoptr i32 [[TMP3]] to i8*
154 //
155 // NEW:   [[TMP1:%.+]] = ptrtoint i8* [[AP_CUR]] to [[$INTPTR_T]]
156 // NEW:   [[TMP2:%.+]] = add [[$INTPTR_T]] [[TMP1]], 15
157 // NEW:   [[TMP3:%.+]] = and [[$INTPTR_T]] [[TMP2]], -16
158 // NEW:   [[AP_CUR:%.+]] = inttoptr [[$INTPTR_T]] [[TMP3]] to i8*
159 //
160 // ALL:   [[AP_NEXT:%.+]] = getelementptr inbounds i8, i8* [[AP_CUR]], [[$INTPTR_T]] 16
161 // ALL:   store i8* [[AP_NEXT]], i8** %va, align [[$PTRALIGN]]
162 //
163 // ALL:   [[AP_CAST:%.+]] = bitcast i8* [[AP_CUR]] to <4 x i32>*
164 // O32:   [[ARG:%.+]] = load <4 x i32>, <4 x i32>* [[AP_CAST]], align 8
165 // N64:   [[ARG:%.+]] = load <4 x i32>, <4 x i32>* [[AP_CAST]], align 16
166 // N32:   [[ARG:%.+]] = load <4 x i32>, <4 x i32>* [[AP_CAST]], align 16
167 // ALL:   store <4 x i32> [[ARG]], <4 x i32>* [[V]], align 16
168 //
169 // ALL:   [[VA1:%.+]] = bitcast i8** %va to i8*
170 // ALL:   call void @llvm.va_end(i8* [[VA1]])
171 // ALL:   [[VECEXT:%.+]] = extractelement <4 x i32> {{.*}}, i32 0
172 // ALL:   ret i32 [[VECEXT]]
173 // ALL: }
174