• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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()
f_void(void)5 void 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)
f_int_1(int x)10 int f_int_1(int x) { return x; }
11 
12 // CHECK-LABEL: define zeroext i32 @f_int_2(i32 zeroext %x)
f_int_2(unsigned x)13 unsigned f_int_2(unsigned x) { return x; }
14 
15 // CHECK-LABEL: define i64 @f_int_3(i64 %x)
f_int_3(long long x)16 long long f_int_3(long long x) { return x; }
17 
18 // CHECK-LABEL: define signext i8 @f_int_4(i8 signext %x)
f_int_4(char x)19 char f_int_4(char x) { return x; }
20 
21 // CHECK-LABEL: define fp128 @f_ld(fp128 %x)
f_ld(long double x)22 long double f_ld(long double x) { return x; }
23 
24 // Small structs are passed in registers.
25 struct small {
26   int *a, *b;
27 };
28 
29 // CHECK-LABEL: define %struct.small @f_small(i32* %x.coerce0, i32* %x.coerce1)
f_small(struct small x)30 struct 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.
37 struct medium {
38   int *a, *b;
39   int *c, *d;
40 };
41 
42 // CHECK-LABEL: define %struct.medium @f_medium(%struct.medium* %x)
f_medium(struct medium x)43 struct 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.
50 struct 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)
f_large(struct large x)57 struct 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.
64 struct reg {
65   int a, b;
66 };
67 
68 // CHECK-LABEL: define i64 @f_reg(i64 %x.coerce)
f_reg(struct reg x)69 struct 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.
75 struct 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)
f_mixed(struct mixed x)81 struct mixed f_mixed(struct mixed x) {
82   x.a += 1;
83   return x;
84 }
85 
86 // Struct with padding.
87 struct 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
f_mixed2(struct mixed2 x)95 struct 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.
102 struct 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
f_tiny(struct tiny x)109 struct 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]])
call_tiny()118 void 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 //
f_variable(char * f,...)127 int 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