1 // RUN: %clang_cc1 -triple sparcv9-unknown-unknown -emit-llvm %s -o - | FileCheck %s
4 // CHECK-LABEL: define{{.*}} void @f_void()
7 // Arguments and return values smaller than the word size are extended.
9 // CHECK-LABEL: define{{.*}} signext i32 @f_int_1(i32 noundef signext %x)
10 int f_int_1(int x
) { return x
; }
12 // CHECK-LABEL: define{{.*}} zeroext i32 @f_int_2(i32 noundef zeroext %x)
13 unsigned f_int_2(unsigned x
) { return x
; }
15 // CHECK-LABEL: define{{.*}} i64 @f_int_3(i64 noundef %x)
16 long long f_int_3(long long x
) { return x
; }
18 // CHECK-LABEL: define{{.*}} signext i8 @f_int_4(i8 noundef signext %x)
19 char f_int_4(char x
) { return x
; }
21 // CHECK-LABEL: define{{.*}} fp128 @f_ld(fp128 noundef %x)
22 long double f_ld(long double x
) { return x
; }
24 // Zero-sized structs reserves an argument register slot if passed directly.
26 struct emptyarr
{ struct empty a
[10]; };
28 // CHECK-LABEL: define{{.*}} i64 @f_empty(i64 %x.coerce)
29 struct empty
f_empty(struct empty x
) { return x
; }
31 // CHECK-LABEL: define{{.*}} i64 @f_emptyarr(i64 %x.coerce)
32 struct empty
f_emptyarr(struct emptyarr x
) { return x
.a
[0]; }
34 // CHECK-LABEL: define{{.*}} i64 @f_emptyvar(i32 noundef zeroext %count, ...)
35 long f_emptyvar(unsigned count
, ...) {
38 va_start(args
, count
);
40 // CHECK: %[[CUR:[^ ]+]] = load ptr, ptr %args
41 // CHECK-DAG: %[[NXT:[^ ]+]] = getelementptr inbounds i8, ptr %[[CUR]], i64 8
42 // CHECK-DAG: store ptr %[[NXT]], ptr %args
43 va_arg(args
, struct empty
);
45 // CHECK: %[[CUR:[^ ]+]] = load ptr, ptr %args
46 // CHECK-DAG: %[[NXT:[^ ]+]] = getelementptr inbounds i8, ptr %[[CUR]], i64 8
47 // CHECK-DAG: store ptr %[[NXT]], ptr %args
48 // CHECK-DAG: load i64, ptr %[[CUR]]
49 ret
= va_arg(args
, long);
54 // If the zero-sized struct is contained in a non-zero-sized struct,
55 // though, it doesn't reserve any registers.
56 struct emptymixed
{ struct empty a
; long b
; };
57 struct emptyflex
{ unsigned count
; struct empty data
[10]; };
59 // CHECK-LABEL: define{{.*}} i64 @f_emptymixed(i64 %x.coerce)
60 long f_emptymixed(struct emptymixed x
) { return x
.b
; }
62 // CHECK-LABEL: define{{.*}} i64 @f_emptyflex(i64 %x.coerce, i64 noundef %y)
63 long f_emptyflex(struct emptyflex x
, long y
) { return y
; }
65 // Small structs are passed in registers.
70 // CHECK-LABEL: define{{.*}} %struct.small @f_small(ptr %x.coerce0, ptr %x.coerce1)
71 struct small
f_small(struct small x
) {
77 // Medium-sized structs are passed indirectly, but can be returned in registers.
83 // CHECK-LABEL: define{{.*}} %struct.medium @f_medium(ptr noundef %x)
84 struct medium
f_medium(struct medium x
) {
90 // Large structs are also returned indirectly.
97 // CHECK-LABEL: define{{.*}} void @f_large(ptr dead_on_unwind noalias writable sret(%struct.large) align 8 %agg.result, ptr noundef %x)
98 struct large
f_large(struct large x
) {
104 // A 64-bit struct fits in a register.
109 // CHECK-LABEL: define{{.*}} i64 @f_reg(i64 %x.coerce)
110 struct reg
f_reg(struct reg x
) {
115 // Structs with mixed int and float parts require the inreg attribute.
121 // CHECK-LABEL: define{{.*}} inreg %struct.mixed @f_mixed(i32 inreg %x.coerce0, float inreg %x.coerce1)
122 struct mixed
f_mixed(struct mixed x
) {
127 // Struct with padding.
133 // CHECK: define{{.*}} { i64, double } @f_mixed2(i64 %x.coerce0, double %x.coerce1)
134 // CHECK: store i64 %x.coerce0
135 // CHECK: store double %x.coerce1
136 struct mixed2
f_mixed2(struct mixed2 x
) {
141 // Struct with single element and padding in passed in the high bits of a
147 // CHECK-LABEL: define{{.*}} i64 @f_tiny(i64 %x.coerce)
148 // CHECK: %[[HB:[^ ]+]] = lshr i64 %x.coerce, 56
149 // CHECK: = trunc i64 %[[HB]] to i8
150 struct tiny
f_tiny(struct tiny x
) {
155 // CHECK-LABEL: define{{.*}} void @call_tiny()
156 // CHECK: %[[XV:[^ ]+]] = zext i8 %{{[^ ]+}} to i64
157 // CHECK: %[[HB:[^ ]+]] = shl i64 %[[XV]], 56
158 // CHECK: = call i64 @f_tiny(i64 %[[HB]])
159 void call_tiny(void) {
160 struct tiny x
= { 1 };
164 // CHECK-LABEL: define{{.*}} signext i32 @f_variable(ptr noundef %f, ...)
165 // CHECK: %ap = alloca ptr
166 // CHECK: call void @llvm.va_start
168 int f_variable(char *f
, ...) {
173 while ((c
= *f
++)) switch (c
) {
175 // CHECK: %[[CUR:[^ ]+]] = load ptr, ptr %ap
176 // CHECK-DAG: %[[NXT:[^ ]+]] = getelementptr inbounds i8, ptr %[[CUR]], i64 8
177 // CHECK-DAG: store ptr %[[NXT]], ptr %ap
178 // CHECK-DAG: %[[EXT:[^ ]+]] = getelementptr inbounds i8, ptr %[[CUR]], i64 4
179 // CHECK-DAG: load i32, ptr %[[EXT]]
182 s
+= va_arg(ap
, int);
185 // CHECK: %[[CUR:[^ ]+]] = load ptr, ptr %ap
186 // CHECK-DAG: %[[NXT:[^ ]+]] = getelementptr inbounds i8, ptr %[[CUR]], i64 8
187 // CHECK-DAG: store ptr %[[NXT]], ptr %ap
188 // CHECK-DAG: load i64, ptr %[[CUR]]
191 s
+= va_arg(ap
, long);
194 // CHECK: %[[CUR:[^ ]+]] = load ptr, ptr %ap
195 // CHECK-DAG: %[[NXT:[^ ]+]] = getelementptr inbounds i8, ptr %[[CUR]], i64 8
196 // CHECK-DAG: store ptr %[[NXT]], ptr %ap
199 s
+= va_arg(ap
, struct tiny
).a
;
202 // CHECK: %[[CUR:[^ ]+]] = load ptr, ptr %ap
203 // CHECK-DAG: %[[NXT:[^ ]+]] = getelementptr inbounds i8, ptr %[[CUR]], i64 16
204 // CHECK-DAG: store ptr %[[NXT]], ptr %ap
207 s
+= *va_arg(ap
, struct small
).a
;
210 // CHECK: %[[CUR:[^ ]+]] = load ptr, ptr %ap
211 // CHECK-DAG: %[[NXT:[^ ]+]] = getelementptr inbounds i8, ptr %[[CUR]], i64 8
212 // CHECK-DAG: store ptr %[[NXT]], ptr %ap
213 // CHECK-DAG: %[[ADR:[^ ]+]] = load ptr, ptr %[[CUR]]
216 s
+= *va_arg(ap
, struct medium
).a
;