1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
|
// RUN: %clang_cc1 -triple x86_64-linux-android -emit-llvm -O -o - %s \
// RUN: | FileCheck %s --check-prefix=ANDROID --check-prefix=CHECK
// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -O -o - %s \
// RUN: | FileCheck %s --check-prefix=GNU --check-prefix=CHECK
// RUN: %clang_cc1 -triple x86_64 -emit-llvm -O -o - %s \
// RUN: | FileCheck %s --check-prefix=GNU --check-prefix=CHECK
// NaCl is an example of a target for which long double is the same as double.
// RUN: %clang_cc1 -triple x86_64-nacl -emit-llvm -O -o - %s \
// RUN: | FileCheck %s --check-prefix=NACL --check-prefix=CHECK
// Android uses fp128 for long double but other x86_64 targets use x86_fp80.
long double dataLD = 1.0L;
// ANDROID: @dataLD ={{.*}} local_unnamed_addr global fp128 0xL00000000000000003FFF000000000000, align 16
// GNU: @dataLD ={{.*}} local_unnamed_addr global x86_fp80 0xK3FFF8000000000000000, align 16
long double _Complex dataLDC = {1.0L, 1.0L};
// ANDROID: @dataLDC ={{.*}} local_unnamed_addr global { fp128, fp128 } { fp128 0xL00000000000000003FFF000000000000, fp128 0xL00000000000000003FFF000000000000 }, align 16
// GNU: @dataLDC ={{.*}} local_unnamed_addr global { x86_fp80, x86_fp80 } { x86_fp80 0xK3FFF8000000000000000, x86_fp80 0xK3FFF8000000000000000 }, align 16
long double TestLD(long double x) {
return x * x;
// ANDROID: define{{.*}} fp128 @TestLD(fp128 noundef %x)
// GNU: define{{.*}} x86_fp80 @TestLD(x86_fp80 noundef %x)
// NACL: define{{.*}} double @TestLD(double noundef %x)
}
long double _Complex TestLDC(long double _Complex x) {
return x * x;
// ANDROID: define{{.*}} void @TestLDC(ptr {{.*}}, ptr {{.*}} %x)
// GNU: define{{.*}} { x86_fp80, x86_fp80 } @TestLDC(ptr {{.*}} %x)
// NACL: define{{.*}} { double, double } @TestLDC(double noundef %x{{.*}}, double noundef %x{{.*}})
}
typedef __builtin_va_list va_list;
int TestGetVarInt(va_list ap) {
return __builtin_va_arg(ap, int);
// Since int can be passed in memory or register there are two branches.
// CHECK: define{{.*}} i32 @TestGetVarInt(
// CHECK: br label
// CHECK: br label
// CHECK: = phi
// CHECK: ret i32
}
double TestGetVarDouble(va_list ap) {
return __builtin_va_arg(ap, double);
// Since double can be passed in memory or register there are two branches.
// CHECK: define{{.*}} double @TestGetVarDouble(
// CHECK: br label
// CHECK: br label
// CHECK: = phi
// CHECK: ret double
}
long double TestGetVarLD(va_list ap) {
return __builtin_va_arg(ap, long double);
// fp128 and double can be passed in memory or in register, but x86_fp80 is in
// memory.
// ANDROID: define{{.*}} fp128 @TestGetVarLD(
// GNU: define{{.*}} x86_fp80 @TestGetVarLD(
// NACL: define{{.*}} double @TestGetVarLD(
// ANDROID: br label
// ANDROID: br label
// NACL: br
// ANDROID: = phi
// GNU-NOT: br
// GNU-NOT: = phi
// NACL: = phi
// ANDROID: ret fp128
// GNU: ret x86_fp80
}
long double _Complex TestGetVarLDC(va_list ap) {
return __builtin_va_arg(ap, long double _Complex);
// Pair of fp128 or x86_fp80 are passed as struct in memory.
// ANDROID: define{{.*}} void @TestGetVarLDC(ptr {{.*}}, ptr
// GNU: define{{.*}} { x86_fp80, x86_fp80 } @TestGetVarLDC(
// Pair of double can go in SSE registers or memory
// NACL: define{{.*}} { double, double } @TestGetVarLDC(
// ANDROID-NOT: br
// GNU-NOT: br
// NACL: br
// ANDROID-NOT: phi
// GNU-NOT: phi
// NACL: phi
// ANDROID: ret void
// GNU: ret { x86_fp80, x86_fp80 }
// NACL: ret { double, double }
}
void TestVarArg(const char *s, ...);
void TestPassVarInt(int x) {
TestVarArg("A", x);
// CHECK: define{{.*}} void @TestPassVarInt(i32 noundef %x)
// CHECK: call {{.*}} @TestVarArg(ptr {{.*}}, i32 noundef %x)
}
void TestPassVarFloat(float x) {
TestVarArg("A", x);
// CHECK: define{{.*}} void @TestPassVarFloat(float noundef %x)
// CHECK: call {{.*}} @TestVarArg(ptr {{.*}}, double noundef %
}
void TestPassVarDouble(double x) {
TestVarArg("A", x);
// CHECK: define{{.*}} void @TestPassVarDouble(double noundef %x)
// CHECK: call {{.*}} @TestVarArg(ptr {{.*}}, double noundef %x
}
void TestPassVarLD(long double x) {
TestVarArg("A", x);
// ANDROID: define{{.*}} void @TestPassVarLD(fp128 noundef %x)
// ANDROID: call {{.*}} @TestVarArg(ptr {{.*}}, fp128 noundef %x
// GNU: define{{.*}} void @TestPassVarLD(x86_fp80 noundef %x)
// GNU: call {{.*}} @TestVarArg(ptr {{.*}}, x86_fp80 noundef %x
// NACL: define{{.*}} void @TestPassVarLD(double noundef %x)
// NACL: call {{.*}} @TestVarArg(ptr {{.*}}, double noundef %x
}
void TestPassVarLDC(long double _Complex x) {
TestVarArg("A", x);
// ANDROID: define{{.*}} void @TestPassVarLDC(ptr {{.*}} %x)
// ANDROID: store fp128 %{{.*}}, ptr %
// ANDROID-NEXT: store fp128 %{{.*}}, ptr %
// ANDROID-NEXT: call {{.*}} @TestVarArg(ptr {{.*}}, ptr {{.*}} %
// GNU: define{{.*}} void @TestPassVarLDC(ptr {{.*}} %x)
// GNU: store x86_fp80 %{{.*}}, ptr %
// GNU-NEXT: store x86_fp80 %{{.*}}, ptr %
// GNU-NEXT: call {{.*}} @TestVarArg(ptr {{.*}}, ptr {{.*}} %
// NACL: define{{.*}} void @TestPassVarLDC(double noundef %x{{.*}}, double noundef %x{{.*}})
// NACL: call {{.*}} @TestVarArg(ptr {{.*}}, double noundef %x{{.*}}, double noundef %x{{.*}})
}
|