| 1 | // RUN: %clang_cc1 -msoft-float -mfloat-abi soft -triple powerpc64le-unknown-linux-gnu -emit-llvm -o - %s | FileCheck -check-prefix=CHECK -check-prefix=CHECK-LE %s |
| 2 | // RUN: %clang_cc1 -msoft-float -mfloat-abi soft -triple powerpc64-unknown-linux-gnu -emit-llvm -o - %s | FileCheck -check-prefix=CHECK -check-prefix=CHECK-BE %s |
| 3 | |
| 4 | // Test float returns and params. |
| 5 | |
| 6 | // CHECK: define float @func_p1(float %x) |
| 7 | float func_p1(float x) { return x; } |
| 8 | |
| 9 | // CHECK: define double @func_p2(double %x) |
| 10 | double func_p2(double x) { return x; } |
| 11 | |
| 12 | // CHECK: define ppc_fp128 @func_p3(ppc_fp128 %x) |
| 13 | long double func_p3(long double x) { return x; } |
| 14 | |
| 15 | // Test homogeneous float aggregate passing and returning. |
| 16 | |
| 17 | struct f1 { float f[1]; }; |
| 18 | struct f2 { float f[2]; }; |
| 19 | struct f3 { float f[3]; }; |
| 20 | struct f4 { float f[4]; }; |
| 21 | struct f5 { float f[5]; }; |
| 22 | struct f6 { float f[6]; }; |
| 23 | struct f7 { float f[7]; }; |
| 24 | struct f8 { float f[8]; }; |
| 25 | struct f9 { float f[9]; }; |
| 26 | |
| 27 | struct fab { float a; float b; }; |
| 28 | struct fabc { float a; float b; float c; }; |
| 29 | |
| 30 | struct f2a2b { float a[2]; float b[2]; }; |
| 31 | |
| 32 | // CHECK-LE: define i32 @func_f1(float inreg %x.coerce) |
| 33 | // CHECK-BE: define void @func_f1(%struct.f1* noalias sret %agg.result, float inreg %x.coerce) |
| 34 | struct f1 func_f1(struct f1 x) { return x; } |
| 35 | |
| 36 | // CHECK-LE: define i64 @func_f2(i64 %x.coerce) |
| 37 | // CHECK-BE: define void @func_f2(%struct.f2* noalias sret %agg.result, i64 %x.coerce) |
| 38 | struct f2 func_f2(struct f2 x) { return x; } |
| 39 | |
| 40 | // CHECK-LE: define { i64, i64 } @func_f3([2 x i64] %x.coerce) |
| 41 | // CHECK-BE: define void @func_f3(%struct.f3* noalias sret %agg.result, [2 x i64] %x.coerce) |
| 42 | struct f3 func_f3(struct f3 x) { return x; } |
| 43 | |
| 44 | // CHECK-LE: define { i64, i64 } @func_f4([2 x i64] %x.coerce) |
| 45 | // CHECK-BE: define void @func_f4(%struct.f4* noalias sret %agg.result, [2 x i64] %x.coerce) |
| 46 | struct f4 func_f4(struct f4 x) { return x; } |
| 47 | |
| 48 | // CHECK: define void @func_f5(%struct.f5* noalias sret %agg.result, [3 x i64] %x.coerce) |
| 49 | struct f5 func_f5(struct f5 x) { return x; } |
| 50 | |
| 51 | // CHECK: define void @func_f6(%struct.f6* noalias sret %agg.result, [3 x i64] %x.coerce) |
| 52 | struct f6 func_f6(struct f6 x) { return x; } |
| 53 | |
| 54 | // CHECK: define void @func_f7(%struct.f7* noalias sret %agg.result, [4 x i64] %x.coerce) |
| 55 | struct f7 func_f7(struct f7 x) { return x; } |
| 56 | |
| 57 | // CHECK: define void @func_f8(%struct.f8* noalias sret %agg.result, [4 x i64] %x.coerce) |
| 58 | struct f8 func_f8(struct f8 x) { return x; } |
| 59 | |
| 60 | // CHECK: define void @func_f9(%struct.f9* noalias sret %agg.result, [5 x i64] %x.coerce) |
| 61 | struct f9 func_f9(struct f9 x) { return x; } |
| 62 | |
| 63 | // CHECK-LE: define i64 @func_fab(i64 %x.coerce) |
| 64 | // CHECK-BE: define void @func_fab(%struct.fab* noalias sret %agg.result, i64 %x.coerce) |
| 65 | struct fab func_fab(struct fab x) { return x; } |
| 66 | |
| 67 | // CHECK-LE: define { i64, i64 } @func_fabc([2 x i64] %x.coerce) |
| 68 | // CHECK-BE: define void @func_fabc(%struct.fabc* noalias sret %agg.result, [2 x i64] %x.coerce) |
| 69 | struct fabc func_fabc(struct fabc x) { return x; } |
| 70 | |
| 71 | // CHECK-LE: define { i64, i64 } @func_f2a2b([2 x i64] %x.coerce) |
| 72 | // CHECK-BE: define void @func_f2a2b(%struct.f2a2b* noalias sret %agg.result, [2 x i64] %x.coerce) |
| 73 | struct f2a2b func_f2a2b(struct f2a2b x) { return x; } |
| 74 | |
| 75 | // CHECK-LABEL: @call_f1 |
| 76 | // CHECK-BE: %[[TMP0:[^ ]+]] = alloca %struct.f1, align 4 |
| 77 | // CHECK: %[[TMP:[^ ]+]] = load float, float* getelementptr inbounds (%struct.f1, %struct.f1* @global_f1, i32 0, i32 0, i32 0), align 4 |
| 78 | // CHECK-LE: call i32 @func_f1(float inreg %[[TMP]]) |
| 79 | // CHECK-BE: call void @func_f1(%struct.f1* sret %[[TMP0]], float inreg %[[TMP]]) |
| 80 | struct f1 global_f1; |
| 81 | void call_f1(void) { global_f1 = func_f1(global_f1); } |
| 82 | |
| 83 | // CHECK-LABEL: @call_f2 |
| 84 | // CHECK-BE: %[[TMP0:[^ ]+]] = alloca %struct.f2, align 4 |
| 85 | // CHECK: %[[TMP:[^ ]+]] = load i64, i64* bitcast (%struct.f2* @global_f2 to i64*), align 4 |
| 86 | // CHECK-LE: call i64 @func_f2(i64 %[[TMP]]) |
| 87 | // CHECK-BE: call void @func_f2(%struct.f2* sret %[[TMP0]], i64 %[[TMP]]) |
| 88 | struct f2 global_f2; |
| 89 | void call_f2(void) { global_f2 = func_f2(global_f2); } |
| 90 | |
| 91 | // CHECK-LABEL: @call_f3 |
| 92 | // CHECK-BE: %[[TMP0:[^ ]+]] = alloca %struct.f3, align 4 |
| 93 | // CHECK: %[[TMP1:[^ ]+]] = alloca [2 x i64] |
| 94 | // CHECK: %[[TMP2:[^ ]+]] = bitcast [2 x i64]* %[[TMP1]] to i8* |
| 95 | // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %[[TMP2]], i8* align 4 bitcast (%struct.f3* @global_f3 to i8*), i64 12, i1 false) |
| 96 | // CHECK: %[[TMP3:[^ ]+]] = load [2 x i64], [2 x i64]* %[[TMP1]] |
| 97 | // CHECK-LE: call { i64, i64 } @func_f3([2 x i64] %[[TMP3]]) |
| 98 | // CHECK-BE: call void @func_f3(%struct.f3* sret %[[TMP0]], [2 x i64] %[[TMP3]]) |
| 99 | struct f3 global_f3; |
| 100 | void call_f3(void) { global_f3 = func_f3(global_f3); } |
| 101 | |
| 102 | // CHECK-LABEL: @call_f4 |
| 103 | // CHECK-BE: %[[TMP0:[^ ]+]] = alloca %struct.f4, align 4 |
| 104 | // CHECK: %[[TMP:[^ ]+]] = load [2 x i64], [2 x i64]* bitcast (%struct.f4* @global_f4 to [2 x i64]*), align 4 |
| 105 | // CHECK-LE: call { i64, i64 } @func_f4([2 x i64] %[[TMP]]) |
| 106 | // CHECK-BE: call void @func_f4(%struct.f4* sret %[[TMP0]], [2 x i64] %[[TMP]]) |
| 107 | struct f4 global_f4; |
| 108 | void call_f4(void) { global_f4 = func_f4(global_f4); } |
| 109 | |
| 110 | // CHECK-LABEL: @call_f5 |
| 111 | // CHECK: %[[TMP0:[^ ]+]] = alloca %struct.f5, align 4 |
| 112 | // CHECK: %[[TMP1:[^ ]+]] = alloca [3 x i64] |
| 113 | // CHECK: %[[TMP2:[^ ]+]] = bitcast [3 x i64]* %[[TMP1]] to i8* |
| 114 | // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %[[TMP2]], i8* align 4 bitcast (%struct.f5* @global_f5 to i8*), i64 20, i1 false) |
| 115 | // CHECK: %[[TMP3:[^ ]+]] = load [3 x i64], [3 x i64]* %[[TMP1]] |
| 116 | // CHECK: call void @func_f5(%struct.f5* sret %[[TMP0]], [3 x i64] %[[TMP3]]) |
| 117 | struct f5 global_f5; |
| 118 | void call_f5(void) { global_f5 = func_f5(global_f5); } |
| 119 | |
| 120 | // CHECK-LABEL: @call_f6 |
| 121 | // CHECK: %[[TMP0:[^ ]+]] = alloca %struct.f6, align 4 |
| 122 | // CHECK: %[[TMP:[^ ]+]] = load [3 x i64], [3 x i64]* bitcast (%struct.f6* @global_f6 to [3 x i64]*), align 4 |
| 123 | // CHECK: call void @func_f6(%struct.f6* sret %[[TMP0]], [3 x i64] %[[TMP]]) |
| 124 | struct f6 global_f6; |
| 125 | void call_f6(void) { global_f6 = func_f6(global_f6); } |
| 126 | |
| 127 | // CHECK-LABEL: @call_f7 |
| 128 | // CHECK: %[[TMP0:[^ ]+]] = alloca %struct.f7, align 4 |
| 129 | // CHECK: %[[TMP1:[^ ]+]] = alloca [4 x i64], align 8 |
| 130 | // CHECK: %[[TMP2:[^ ]+]] = bitcast [4 x i64]* %[[TMP1]] to i8* |
| 131 | // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %[[TMP2]], i8* align 4 bitcast (%struct.f7* @global_f7 to i8*), i64 28, i1 false) |
| 132 | // CHECK: %[[TMP3:[^ ]+]] = load [4 x i64], [4 x i64]* %[[TMP1]], align 8 |
| 133 | // CHECK: call void @func_f7(%struct.f7* sret %[[TMP0]], [4 x i64] %[[TMP3]]) |
| 134 | struct f7 global_f7; |
| 135 | void call_f7(void) { global_f7 = func_f7(global_f7); } |
| 136 | |
| 137 | // CHECK-LABEL: @call_f8 |
| 138 | // CHECK: %[[TMP0:[^ ]+]] = alloca %struct.f8, align 4 |
| 139 | // CHECK: %[[TMP:[^ ]+]] = load [4 x i64], [4 x i64]* bitcast (%struct.f8* @global_f8 to [4 x i64]*), align 4 |
| 140 | // CHECK: call void @func_f8(%struct.f8* sret %[[TMP0]], [4 x i64] %[[TMP]]) |
| 141 | struct f8 global_f8; |
| 142 | void call_f8(void) { global_f8 = func_f8(global_f8); } |
| 143 | |
| 144 | // CHECK-LABEL: @call_f9 |
| 145 | // CHECK: %[[TMP1:[^ ]+]] = alloca [5 x i64] |
| 146 | // CHECK: %[[TMP2:[^ ]+]] = bitcast [5 x i64]* %[[TMP1]] to i8* |
| 147 | // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %[[TMP2]], i8* align 4 bitcast (%struct.f9* @global_f9 to i8*), i64 36, i1 false) |
| 148 | // CHECK: %[[TMP3:[^ ]+]] = load [5 x i64], [5 x i64]* %[[TMP1]] |
| 149 | // CHECK: call void @func_f9(%struct.f9* sret %{{[^ ]+}}, [5 x i64] %[[TMP3]]) |
| 150 | struct f9 global_f9; |
| 151 | void call_f9(void) { global_f9 = func_f9(global_f9); } |
| 152 | |
| 153 | // CHECK-LABEL: @call_fab |
| 154 | // CHECK: %[[TMP0:[^ ]+]] = alloca %struct.fab, align 4 |
| 155 | // CHECK: %[[TMP:[^ ]+]] = load i64, i64* bitcast (%struct.fab* @global_fab to i64*), align 4 |
| 156 | // CHECK-LE: %call = call i64 @func_fab(i64 %[[TMP]]) |
| 157 | // CHECK-BE: call void @func_fab(%struct.fab* sret %[[TMP0]], i64 %[[TMP]]) |
| 158 | struct fab global_fab; |
| 159 | void call_fab(void) { global_fab = func_fab(global_fab); } |
| 160 | |
| 161 | // CHECK-LABEL: @call_fabc |
| 162 | // CHECK-BE: %[[TMPX:[^ ]+]] = alloca %struct.fabc, align 4 |
| 163 | // CHECK: %[[TMP0:[^ ]+]] = alloca [2 x i64], align 8 |
| 164 | // CHECK: %[[TMP2:[^ ]+]] = bitcast [2 x i64]* %[[TMP0]] to i8* |
| 165 | // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %[[TMP2]], i8* align 4 bitcast (%struct.fabc* @global_fabc to i8*), i64 12, i1 false) |
| 166 | // CHECK: %[[TMP3:[^ ]+]] = load [2 x i64], [2 x i64]* %[[TMP0]], align 8 |
| 167 | // CHECK-LE: %call = call { i64, i64 } @func_fabc([2 x i64] %[[TMP3]]) |
| 168 | // CHECK-BE: call void @func_fabc(%struct.fabc* sret %[[TMPX]], [2 x i64] %[[TMP3]]) |
| 169 | struct fabc global_fabc; |
| 170 | void call_fabc(void) { global_fabc = func_fabc(global_fabc); } |
| 171 | |
| 172 | |