1// RUN: %clang_cc1 -triple sparcv9-unknown-unknown -emit-llvm %s -o - | FileCheck %s
2#include <stdarg.h>
3
4// CHECK-LABEL: define void @f_void()
5void f_void(void) {}
6
7// Arguments and return values smaller than the word size are extended.
8
9// CHECK-LABEL: define signext i32 @f_int_1(i32 signext %x)
10int f_int_1(int x) { return x; }
11
12// CHECK-LABEL: define zeroext i32 @f_int_2(i32 zeroext %x)
13unsigned f_int_2(unsigned x) { return x; }
14
15// CHECK-LABEL: define i64 @f_int_3(i64 %x)
16long long f_int_3(long long x) { return x; }
17
18// CHECK-LABEL: define signext i8 @f_int_4(i8 signext %x)
19char f_int_4(char x) { return x; }
20
21// CHECK-LABEL: define fp128 @f_ld(fp128 %x)
22long double f_ld(long double x) { return x; }
23
24// Small structs are passed in registers.
25struct small {
26  int *a, *b;
27};
28
29// CHECK-LABEL: define %struct.small @f_small(i32* %x.coerce0, i32* %x.coerce1)
30struct small f_small(struct small x) {
31  x.a += *x.b;
32  x.b = 0;
33  return x;
34}
35
36// Medium-sized structs are passed indirectly, but can be returned in registers.
37struct medium {
38  int *a, *b;
39  int *c, *d;
40};
41
42// CHECK-LABEL: define %struct.medium @f_medium(%struct.medium* %x)
43struct medium f_medium(struct medium x) {
44  x.a += *x.b;
45  x.b = 0;
46  return x;
47}
48
49// Large structs are also returned indirectly.
50struct large {
51  int *a, *b;
52  int *c, *d;
53  int x;
54};
55
56// CHECK-LABEL: define void @f_large(%struct.large* noalias sret %agg.result, %struct.large* %x)
57struct large f_large(struct large x) {
58  x.a += *x.b;
59  x.b = 0;
60  return x;
61}
62
63// A 64-bit struct fits in a register.
64struct reg {
65  int a, b;
66};
67
68// CHECK-LABEL: define i64 @f_reg(i64 %x.coerce)
69struct reg f_reg(struct reg x) {
70  x.a += x.b;
71  return x;
72}
73
74// Structs with mixed int and float parts require the inreg attribute.
75struct mixed {
76  int a;
77  float b;
78};
79
80// CHECK-LABEL: define inreg %struct.mixed @f_mixed(i32 inreg %x.coerce0, float inreg %x.coerce1)
81struct mixed f_mixed(struct mixed x) {
82  x.a += 1;
83  return x;
84}
85
86// Struct with padding.
87struct mixed2 {
88  int a;
89  double b;
90};
91
92// CHECK: define { i64, double } @f_mixed2(i64 %x.coerce0, double %x.coerce1)
93// CHECK: store i64 %x.coerce0
94// CHECK: store double %x.coerce1
95struct mixed2 f_mixed2(struct mixed2 x) {
96  x.a += 1;
97  return x;
98}
99
100// Struct with single element and padding in passed in the high bits of a
101// register.
102struct tiny {
103  char a;
104};
105
106// CHECK-LABEL: define i64 @f_tiny(i64 %x.coerce)
107// CHECK: %[[HB:[^ ]+]] = lshr i64 %x.coerce, 56
108// CHECK: = trunc i64 %[[HB]] to i8
109struct tiny f_tiny(struct tiny x) {
110  x.a += 1;
111  return x;
112}
113
114// CHECK-LABEL: define void @call_tiny()
115// CHECK: %[[XV:[^ ]+]] = zext i8 %{{[^ ]+}} to i64
116// CHECK: %[[HB:[^ ]+]] = shl i64 %[[XV]], 56
117// CHECK: = call i64 @f_tiny(i64 %[[HB]])
118void call_tiny() {
119  struct tiny x = { 1 };
120  f_tiny(x);
121}
122
123// CHECK-LABEL: define signext i32 @f_variable(i8* %f, ...)
124// CHECK: %ap = alloca i8*
125// CHECK: call void @llvm.va_start
126//
127int f_variable(char *f, ...) {
128  int s = 0;
129  char c;
130  va_list ap;
131  va_start(ap, f);
132  while ((c = *f++)) switch (c) {
133
134// CHECK: %[[CUR:[^ ]+]] = load i8*, i8** %ap
135// CHECK-DAG: %[[NXT:[^ ]+]] = getelementptr inbounds i8, i8* %[[CUR]], i64 8
136// CHECK-DAG: store i8* %[[NXT]], i8** %ap
137// CHECK-DAG: %[[EXT:[^ ]+]] = getelementptr inbounds i8, i8* %[[CUR]], i64 4
138// CHECK-DAG: %[[ADR:[^ ]+]] = bitcast i8* %[[EXT]] to i32*
139// CHECK-DAG: load i32, i32* %[[ADR]]
140// CHECK: br
141  case 'i':
142    s += va_arg(ap, int);
143    break;
144
145// CHECK: %[[CUR:[^ ]+]] = load i8*, i8** %ap
146// CHECK-DAG: %[[NXT:[^ ]+]] = getelementptr inbounds i8, i8* %[[CUR]], i64 8
147// CHECK-DAG: store i8* %[[NXT]], i8** %ap
148// CHECK-DAG: %[[ADR:[^ ]+]] = bitcast i8* %[[CUR]] to i64*
149// CHECK-DAG: load i64, i64* %[[ADR]]
150// CHECK: br
151  case 'l':
152    s += va_arg(ap, long);
153    break;
154
155// CHECK: %[[CUR:[^ ]+]] = load i8*, i8** %ap
156// CHECK-DAG: %[[NXT:[^ ]+]] = getelementptr inbounds i8, i8* %[[CUR]], i64 8
157// CHECK-DAG: store i8* %[[NXT]], i8** %ap
158// CHECK-DAG: %[[ADR:[^ ]+]] = bitcast i8* %[[CUR]] to %struct.tiny*
159// CHECK: br
160  case 't':
161    s += va_arg(ap, struct tiny).a;
162    break;
163
164// CHECK: %[[CUR:[^ ]+]] = load i8*, i8** %ap
165// CHECK-DAG: %[[NXT:[^ ]+]] = getelementptr inbounds i8, i8* %[[CUR]], i64 16
166// CHECK-DAG: store i8* %[[NXT]], i8** %ap
167// CHECK-DAG: %[[ADR:[^ ]+]] = bitcast i8* %[[CUR]] to %struct.small*
168// CHECK: br
169  case 's':
170    s += *va_arg(ap, struct small).a;
171    break;
172
173// CHECK: %[[CUR:[^ ]+]] = load i8*, i8** %ap
174// CHECK-DAG: %[[NXT:[^ ]+]] = getelementptr inbounds i8, i8* %[[CUR]], i64 8
175// CHECK-DAG: store i8* %[[NXT]], i8** %ap
176// CHECK-DAG: %[[IND:[^ ]+]] = bitcast i8* %[[CUR]] to %struct.medium**
177// CHECK-DAG: %[[ADR:[^ ]+]] = load %struct.medium*, %struct.medium** %[[IND]]
178// CHECK: br
179  case 'm':
180    s += *va_arg(ap, struct medium).a;
181    break;
182  }
183  return s;
184}
185