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() 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) 10 int f_int_1(int x) { return x; } 11 12 // CHECK-LABEL: define zeroext i32 @f_int_2(i32 zeroext %x) 13 unsigned f_int_2(unsigned x) { return x; } 14 15 // CHECK-LABEL: define i64 @f_int_3(i64 %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) 19 char f_int_4(char x) { return x; } 20 21 // CHECK-LABEL: define fp128 @f_ld(fp128 %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) 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) 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) 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) 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) 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 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 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]]) 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 // 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