summaryrefslogtreecommitdiffstats
path: root/test/CodeGen/sparcv9-abi.c
diff options
context:
space:
mode:
Diffstat (limited to 'test/CodeGen/sparcv9-abi.c')
-rw-r--r--test/CodeGen/sparcv9-abi.c181
1 files changed, 181 insertions, 0 deletions
diff --git a/test/CodeGen/sparcv9-abi.c b/test/CodeGen/sparcv9-abi.c
new file mode 100644
index 0000000..4ba4be8
--- /dev/null
+++ b/test/CodeGen/sparcv9-abi.c
@@ -0,0 +1,181 @@
+// RUN: %clang_cc1 -triple sparcv9-unknown-unknown -emit-llvm %s -o - | FileCheck %s
+#include <stdarg.h>
+
+// CHECK-LABEL: define void @f_void()
+void f_void(void) {}
+
+// Arguments and return values smaller than the word size are extended.
+
+// CHECK-LABEL: define signext i32 @f_int_1(i32 signext %x)
+int f_int_1(int x) { return x; }
+
+// CHECK-LABEL: define zeroext i32 @f_int_2(i32 zeroext %x)
+unsigned f_int_2(unsigned x) { return x; }
+
+// CHECK-LABEL: define i64 @f_int_3(i64 %x)
+long long f_int_3(long long x) { return x; }
+
+// CHECK-LABEL: define signext i8 @f_int_4(i8 signext %x)
+char f_int_4(char x) { return x; }
+
+// Small structs are passed in registers.
+struct small {
+ int *a, *b;
+};
+
+// CHECK-LABEL: define %struct.small @f_small(i32* %x.coerce0, i32* %x.coerce1)
+struct small f_small(struct small x) {
+ x.a += *x.b;
+ x.b = 0;
+ return x;
+}
+
+// Medium-sized structs are passed indirectly, but can be returned in registers.
+struct medium {
+ int *a, *b;
+ int *c, *d;
+};
+
+// CHECK-LABEL: define %struct.medium @f_medium(%struct.medium* %x)
+struct medium f_medium(struct medium x) {
+ x.a += *x.b;
+ x.b = 0;
+ return x;
+}
+
+// Large structs are also returned indirectly.
+struct large {
+ int *a, *b;
+ int *c, *d;
+ int x;
+};
+
+// CHECK-LABEL: define void @f_large(%struct.large* noalias sret %agg.result, %struct.large* %x)
+struct large f_large(struct large x) {
+ x.a += *x.b;
+ x.b = 0;
+ return x;
+}
+
+// A 64-bit struct fits in a register.
+struct reg {
+ int a, b;
+};
+
+// CHECK-LABEL: define i64 @f_reg(i64 %x.coerce)
+struct reg f_reg(struct reg x) {
+ x.a += x.b;
+ return x;
+}
+
+// Structs with mixed int and float parts require the inreg attribute.
+struct mixed {
+ int a;
+ float b;
+};
+
+// CHECK-LABEL: define inreg %struct.mixed @f_mixed(i32 inreg %x.coerce0, float inreg %x.coerce1)
+struct mixed f_mixed(struct mixed x) {
+ x.a += 1;
+ return x;
+}
+
+// Struct with padding.
+struct mixed2 {
+ int a;
+ double b;
+};
+
+// CHECK: define { i64, double } @f_mixed2(i64 %x.coerce0, double %x.coerce1)
+// CHECK: store i64 %x.coerce0
+// CHECK: store double %x.coerce1
+struct mixed2 f_mixed2(struct mixed2 x) {
+ x.a += 1;
+ return x;
+}
+
+// Struct with single element and padding in passed in the high bits of a
+// register.
+struct tiny {
+ char a;
+};
+
+// CHECK-LABEL: define i64 @f_tiny(i64 %x.coerce)
+// CHECK: %[[HB:[^ ]+]] = lshr i64 %x.coerce, 56
+// CHECK: = trunc i64 %[[HB]] to i8
+struct tiny f_tiny(struct tiny x) {
+ x.a += 1;
+ return x;
+}
+
+// CHECK-LABEL: define void @call_tiny()
+// CHECK: %[[XV:[^ ]+]] = zext i8 %{{[^ ]+}} to i64
+// CHECK: %[[HB:[^ ]+]] = shl i64 %[[XV]], 56
+// CHECK: = call i64 @f_tiny(i64 %[[HB]])
+void call_tiny() {
+ struct tiny x = { 1 };
+ f_tiny(x);
+}
+
+// CHECK-LABEL: define signext i32 @f_variable(i8* %f, ...)
+// CHECK: %ap = alloca i8*
+// CHECK: call void @llvm.va_start
+//
+int f_variable(char *f, ...) {
+ int s = 0;
+ char c;
+ va_list ap;
+ va_start(ap, f);
+ while ((c = *f++)) switch (c) {
+
+// CHECK: %[[CUR:[^ ]+]] = load i8** %ap
+// CHECK-DAG: %[[NXT:[^ ]+]] = getelementptr i8* %[[CUR]], i32 8
+// CHECK-DAG: store i8* %[[NXT]], i8** %ap
+// CHECK-DAG: %[[EXT:[^ ]+]] = getelementptr i8* %[[CUR]], i32 4
+// CHECK-DAG: %[[ADR:[^ ]+]] = bitcast i8* %[[EXT]] to i32*
+// CHECK-DAG: load i32* %[[ADR]]
+// CHECK: br
+ case 'i':
+ s += va_arg(ap, int);
+ break;
+
+// CHECK: %[[CUR:[^ ]+]] = load i8** %ap
+// CHECK-DAG: %[[NXT:[^ ]+]] = getelementptr i8* %[[CUR]], i32 8
+// CHECK-DAG: store i8* %[[NXT]], i8** %ap
+// CHECK-DAG: %[[ADR:[^ ]+]] = bitcast i8* %[[CUR]] to i64*
+// CHECK-DAG: load i64* %[[ADR]]
+// CHECK: br
+ case 'l':
+ s += va_arg(ap, long);
+ break;
+
+// CHECK: %[[CUR:[^ ]+]] = load i8** %ap
+// CHECK-DAG: %[[NXT:[^ ]+]] = getelementptr i8* %[[CUR]], i32 8
+// CHECK-DAG: store i8* %[[NXT]], i8** %ap
+// CHECK-DAG: %[[ADR:[^ ]+]] = bitcast i8* %[[CUR]] to %struct.tiny*
+// CHECK: br
+ case 't':
+ s += va_arg(ap, struct tiny).a;
+ break;
+
+// CHECK: %[[CUR:[^ ]+]] = load i8** %ap
+// CHECK-DAG: %[[NXT:[^ ]+]] = getelementptr i8* %[[CUR]], i32 16
+// CHECK-DAG: store i8* %[[NXT]], i8** %ap
+// CHECK-DAG: %[[ADR:[^ ]+]] = bitcast i8* %[[CUR]] to %struct.small*
+// CHECK: br
+ case 's':
+ s += *va_arg(ap, struct small).a;
+ break;
+
+// CHECK: %[[CUR:[^ ]+]] = load i8** %ap
+// CHECK-DAG: %[[NXT:[^ ]+]] = getelementptr i8* %[[CUR]], i32 8
+// CHECK-DAG: store i8* %[[NXT]], i8** %ap
+// CHECK-DAG: %[[IND:[^ ]+]] = bitcast i8* %[[CUR]] to %struct.medium**
+// CHECK-DAG: %[[ADR:[^ ]+]] = load %struct.medium** %[[IND]]
+// CHECK: br
+ case 'm':
+ s += *va_arg(ap, struct medium).a;
+ break;
+ }
+ return s;
+}
OpenPOWER on IntegriCloud