summaryrefslogtreecommitdiffstats
path: root/llvm/test
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/test')
-rw-r--r--llvm/test/CodeGen/X86/fp128-calling-conv.ll47
-rw-r--r--llvm/test/CodeGen/X86/fp128-cast.ll279
-rw-r--r--llvm/test/CodeGen/X86/fp128-compare.ll96
-rw-r--r--llvm/test/CodeGen/X86/fp128-i128.ll320
-rw-r--r--llvm/test/CodeGen/X86/fp128-libcalls.ll107
-rw-r--r--llvm/test/CodeGen/X86/fp128-load.ll35
-rw-r--r--llvm/test/CodeGen/X86/fp128-store.ll14
-rw-r--r--llvm/test/CodeGen/X86/soft-fp.ll35
8 files changed, 929 insertions, 4 deletions
diff --git a/llvm/test/CodeGen/X86/fp128-calling-conv.ll b/llvm/test/CodeGen/X86/fp128-calling-conv.ll
new file mode 100644
index 00000000000..e1dab30847c
--- /dev/null
+++ b/llvm/test/CodeGen/X86/fp128-calling-conv.ll
@@ -0,0 +1,47 @@
+; RUN: llc < %s -O2 -mtriple=x86_64-linux-android -mattr=+mmx | FileCheck %s
+; RUN: llc < %s -O2 -mtriple=x86_64-linux-gnu -mattr=+mmx | FileCheck %s
+
+; __float128 myFP128 = 1.0L; // x86_64-linux-android
+@myFP128 = global fp128 0xL00000000000000003FFF000000000000, align 16
+
+; The first few parameters are passed in registers and the other are on stack.
+
+define fp128 @TestParam_FP128_0(fp128 %d0, fp128 %d1, fp128 %d2, fp128 %d3, fp128 %d4, fp128 %d5, fp128 %d6, fp128 %d7, fp128 %d8, fp128 %d9, fp128 %d10, fp128 %d11, fp128 %d12, fp128 %d13, fp128 %d14, fp128 %d15, fp128 %d16, fp128 %d17, fp128 %d18, fp128 %d19) {
+entry:
+ ret fp128 %d0
+; CHECK-LABEL: TestParam_FP128_0:
+; CHECK-NOT: mov
+; CHECK: retq
+}
+
+define fp128 @TestParam_FP128_1(fp128 %d0, fp128 %d1, fp128 %d2, fp128 %d3, fp128 %d4, fp128 %d5, fp128 %d6, fp128 %d7, fp128 %d8, fp128 %d9, fp128 %d10, fp128 %d11, fp128 %d12, fp128 %d13, fp128 %d14, fp128 %d15, fp128 %d16, fp128 %d17, fp128 %d18, fp128 %d19) {
+entry:
+ ret fp128 %d1
+; CHECK-LABEL: TestParam_FP128_1:
+; CHECK: movaps %xmm1, %xmm0
+; CHECK-NEXT: retq
+}
+
+define fp128 @TestParam_FP128_7(fp128 %d0, fp128 %d1, fp128 %d2, fp128 %d3, fp128 %d4, fp128 %d5, fp128 %d6, fp128 %d7, fp128 %d8, fp128 %d9, fp128 %d10, fp128 %d11, fp128 %d12, fp128 %d13, fp128 %d14, fp128 %d15, fp128 %d16, fp128 %d17, fp128 %d18, fp128 %d19) {
+entry:
+ ret fp128 %d7
+; CHECK-LABEL: TestParam_FP128_7:
+; CHECK: movaps %xmm7, %xmm0
+; CHECK-NEXT: retq
+}
+
+define fp128 @TestParam_FP128_8(fp128 %d0, fp128 %d1, fp128 %d2, fp128 %d3, fp128 %d4, fp128 %d5, fp128 %d6, fp128 %d7, fp128 %d8, fp128 %d9, fp128 %d10, fp128 %d11, fp128 %d12, fp128 %d13, fp128 %d14, fp128 %d15, fp128 %d16, fp128 %d17, fp128 %d18, fp128 %d19) {
+entry:
+ ret fp128 %d8
+; CHECK-LABEL: TestParam_FP128_8:
+; CHECK: movaps 8(%rsp), %xmm0
+; CHECK-NEXT: retq
+}
+
+define fp128 @TestParam_FP128_9(fp128 %d0, fp128 %d1, fp128 %d2, fp128 %d3, fp128 %d4, fp128 %d5, fp128 %d6, fp128 %d7, fp128 %d8, fp128 %d9, fp128 %d10, fp128 %d11, fp128 %d12, fp128 %d13, fp128 %d14, fp128 %d15, fp128 %d16, fp128 %d17, fp128 %d18, fp128 %d19) {
+entry:
+ ret fp128 %d9
+; CHECK-LABEL: TestParam_FP128_9:
+; CHECK: movaps 24(%rsp), %xmm0
+; CHECK-NEXT: retq
+}
diff --git a/llvm/test/CodeGen/X86/fp128-cast.ll b/llvm/test/CodeGen/X86/fp128-cast.ll
new file mode 100644
index 00000000000..73878e31d0e
--- /dev/null
+++ b/llvm/test/CodeGen/X86/fp128-cast.ll
@@ -0,0 +1,279 @@
+; RUN: llc < %s -O2 -mtriple=x86_64-linux-android -mattr=+mmx | FileCheck %s
+; RUN: llc < %s -O2 -mtriple=x86_64-linux-gnu -mattr=+mmx | FileCheck %s
+
+; Check soft floating point conversion function calls.
+
+@vi32 = common global i32 0, align 4
+@vi64 = common global i64 0, align 8
+@vu32 = common global i32 0, align 4
+@vu64 = common global i64 0, align 8
+@vf32 = common global float 0.000000e+00, align 4
+@vf64 = common global double 0.000000e+00, align 8
+@vf128 = common global fp128 0xL00000000000000000000000000000000, align 16
+
+define void @TestFPExtF32_F128() {
+entry:
+ %0 = load float, float* @vf32, align 4
+ %conv = fpext float %0 to fp128
+ store fp128 %conv, fp128* @vf128, align 16
+ ret void
+; CHECK-LABEL: TestFPExtF32_F128:
+; CHECK: movss vf32(%rip), %xmm0
+; CHECK-NEXT: callq __extendsftf2
+; CHECK-NEXT: movaps %xmm0, vf128(%rip)
+; CHECK: retq
+}
+
+define void @TestFPExtF64_F128() {
+entry:
+ %0 = load double, double* @vf64, align 8
+ %conv = fpext double %0 to fp128
+ store fp128 %conv, fp128* @vf128, align 16
+ ret void
+; CHECK-LABEL: TestFPExtF64_F128:
+; CHECK: movsd vf64(%rip), %xmm0
+; CHECK-NEXT: callq __extenddftf2
+; CHECK-NEXT: movapd %xmm0, vf128(%rip)
+; CHECK: ret
+}
+
+define void @TestFPToSIF128_I32() {
+entry:
+ %0 = load fp128, fp128* @vf128, align 16
+ %conv = fptosi fp128 %0 to i32
+ store i32 %conv, i32* @vi32, align 4
+ ret void
+; CHECK-LABEL: TestFPToSIF128_I32:
+; CHECK: movaps vf128(%rip), %xmm0
+; CHECK-NEXT: callq __fixtfsi
+; CHECK-NEXT: movl %eax, vi32(%rip)
+; CHECK: retq
+}
+
+define void @TestFPToUIF128_U32() {
+entry:
+ %0 = load fp128, fp128* @vf128, align 16
+ %conv = fptoui fp128 %0 to i32
+ store i32 %conv, i32* @vu32, align 4
+ ret void
+; CHECK-LABEL: TestFPToUIF128_U32:
+; CHECK: movaps vf128(%rip), %xmm0
+; CHECK-NEXT: callq __fixunstfsi
+; CHECK-NEXT: movl %eax, vu32(%rip)
+; CHECK: retq
+}
+
+define void @TestFPToSIF128_I64() {
+entry:
+ %0 = load fp128, fp128* @vf128, align 16
+ %conv = fptosi fp128 %0 to i32
+ %conv1 = sext i32 %conv to i64
+ store i64 %conv1, i64* @vi64, align 8
+ ret void
+; CHECK-LABEL: TestFPToSIF128_I64:
+; CHECK: movaps vf128(%rip), %xmm0
+; CHECK-NEXT: callq __fixtfsi
+; CHECK-NEXT: cltq
+; CHECK-NEXT: movq %rax, vi64(%rip)
+; CHECK: retq
+}
+
+define void @TestFPToUIF128_U64() {
+entry:
+ %0 = load fp128, fp128* @vf128, align 16
+ %conv = fptoui fp128 %0 to i32
+ %conv1 = zext i32 %conv to i64
+ store i64 %conv1, i64* @vu64, align 8
+ ret void
+; CHECK-LABEL: TestFPToUIF128_U64:
+; CHECK: movaps vf128(%rip), %xmm0
+; CHECK-NEXT: callq __fixunstfsi
+; CHECK-NEXT: movl %eax, %eax
+; CHECK-NEXT: movq %rax, vu64(%rip)
+; CHECK: retq
+}
+
+define void @TestFPTruncF128_F32() {
+entry:
+ %0 = load fp128, fp128* @vf128, align 16
+ %conv = fptrunc fp128 %0 to float
+ store float %conv, float* @vf32, align 4
+ ret void
+; CHECK-LABEL: TestFPTruncF128_F32:
+; CHECK: movaps vf128(%rip), %xmm0
+; CHECK-NEXT: callq __trunctfsf2
+; CHECK-NEXT: movss %xmm0, vf32(%rip)
+; CHECK: retq
+}
+
+define void @TestFPTruncF128_F64() {
+entry:
+ %0 = load fp128, fp128* @vf128, align 16
+ %conv = fptrunc fp128 %0 to double
+ store double %conv, double* @vf64, align 8
+ ret void
+; CHECK-LABEL: TestFPTruncF128_F64:
+; CHECK: movapd vf128(%rip), %xmm0
+; CHECK-NEXT: callq __trunctfdf2
+; CHECK-NEXT: movsd %xmm0, vf64(%rip)
+; CHECK: retq
+}
+
+define void @TestSIToFPI32_F128() {
+entry:
+ %0 = load i32, i32* @vi32, align 4
+ %conv = sitofp i32 %0 to fp128
+ store fp128 %conv, fp128* @vf128, align 16
+ ret void
+; CHECK-LABEL: TestSIToFPI32_F128:
+; CHECK: movl vi32(%rip), %edi
+; CHECK-NEXT: callq __floatsitf
+; CHECK-NEXT: movaps %xmm0, vf128(%rip)
+; CHECK: retq
+}
+
+define void @TestUIToFPU32_F128() #2 {
+entry:
+ %0 = load i32, i32* @vu32, align 4
+ %conv = uitofp i32 %0 to fp128
+ store fp128 %conv, fp128* @vf128, align 16
+ ret void
+; CHECK-LABEL: TestUIToFPU32_F128:
+; CHECK: movl vu32(%rip), %edi
+; CHECK-NEXT: callq __floatunsitf
+; CHECK-NEXT: movaps %xmm0, vf128(%rip)
+; CHECK: retq
+}
+
+define void @TestSIToFPI64_F128(){
+entry:
+ %0 = load i64, i64* @vi64, align 8
+ %conv = sitofp i64 %0 to fp128
+ store fp128 %conv, fp128* @vf128, align 16
+ ret void
+; CHECK-LABEL: TestSIToFPI64_F128:
+; CHECK: movq vi64(%rip), %rdi
+; CHECK-NEXT: callq __floatditf
+; CHECK-NEXT: movaps %xmm0, vf128(%rip)
+; CHECK: retq
+}
+
+define void @TestUIToFPU64_F128() #2 {
+entry:
+ %0 = load i64, i64* @vu64, align 8
+ %conv = uitofp i64 %0 to fp128
+ store fp128 %conv, fp128* @vf128, align 16
+ ret void
+; CHECK-LABEL: TestUIToFPU64_F128:
+; CHECK: movq vu64(%rip), %rdi
+; CHECK-NEXT: callq __floatunditf
+; CHECK-NEXT: movaps %xmm0, vf128(%rip)
+; CHECK: retq
+}
+
+define i32 @TestConst128(fp128 %v) {
+entry:
+ %cmp = fcmp ogt fp128 %v, 0xL00000000000000003FFF000000000000
+ %conv = zext i1 %cmp to i32
+ ret i32 %conv
+; CHECK-LABEL: TestConst128:
+; CHECK: movaps {{.*}}, %xmm1
+; CHECK-NEXT: callq __gttf2
+; CHECK-NEXT: test
+; CHECK: retq
+}
+
+; C code:
+; struct TestBits_ieee_ext {
+; unsigned v1;
+; unsigned v2;
+; };
+; union TestBits_LDU {
+; FP128 ld;
+; struct TestBits_ieee_ext bits;
+; };
+; int TestBits128(FP128 ld) {
+; union TestBits_LDU u;
+; u.ld = ld * ld;
+; return ((u.bits.v1 | u.bits.v2) == 0);
+; }
+define i32 @TestBits128(fp128 %ld) {
+entry:
+ %mul = fmul fp128 %ld, %ld
+ %0 = bitcast fp128 %mul to i128
+ %shift = lshr i128 %0, 32
+ %or5 = or i128 %shift, %0
+ %or = trunc i128 %or5 to i32
+ %cmp = icmp eq i32 %or, 0
+ %conv = zext i1 %cmp to i32
+ ret i32 %conv
+; CHECK-LABEL: TestBits128:
+; CHECK: movaps %xmm0, %xmm1
+; CHECK-NEXT: callq __multf3
+; CHECK-NEXT: movaps %xmm0, (%rsp)
+; CHECK-NEXT: movq (%rsp),
+; CHECK-NEXT: movq %
+; CHECK-NEXT: shrq $32,
+; CHECK: orl
+; CHECK-NEXT: sete %al
+; CHECK-NEXT: movzbl %al, %eax
+; CHECK: retq
+;
+; If TestBits128 fails due to any llvm or clang change,
+; please make sure the original simplified C code will
+; be compiled into correct IL and assembly code, not
+; just this TestBits128 test case. Better yet, try to
+; test the whole libm and its test cases.
+}
+
+; C code: (compiled with -target x86_64-linux-android)
+; typedef long double __float128;
+; __float128 TestPair128(unsigned long a, unsigned long b) {
+; unsigned __int128 n;
+; unsigned __int128 v1 = ((unsigned __int128)a << 64);
+; unsigned __int128 v2 = (unsigned __int128)b;
+; n = (v1 | v2) + 3;
+; return *(__float128*)&n;
+; }
+define fp128 @TestPair128(i64 %a, i64 %b) {
+entry:
+ %conv = zext i64 %a to i128
+ %shl = shl nuw i128 %conv, 64
+ %conv1 = zext i64 %b to i128
+ %or = or i128 %shl, %conv1
+ %add = add i128 %or, 3
+ %0 = bitcast i128 %add to fp128
+ ret fp128 %0
+; CHECK-LABEL: TestPair128:
+; CHECK: addq $3, %rsi
+; CHECK: movq %rsi, -24(%rsp)
+; CHECK: movq %rdi, -16(%rsp)
+; CHECK: movaps -24(%rsp), %xmm0
+; CHECK-NEXT: retq
+}
+
+define fp128 @TestTruncCopysign(fp128 %x, i32 %n) {
+entry:
+ %cmp = icmp sgt i32 %n, 50000
+ br i1 %cmp, label %if.then, label %cleanup
+
+if.then: ; preds = %entry
+ %conv = fptrunc fp128 %x to double
+ %call = tail call double @copysign(double 0x7FF0000000000000, double %conv) #2
+ %conv1 = fpext double %call to fp128
+ br label %cleanup
+
+cleanup: ; preds = %entry, %if.then
+ %retval.0 = phi fp128 [ %conv1, %if.then ], [ %x, %entry ]
+ ret fp128 %retval.0
+; CHECK-LABEL: TestTruncCopysign:
+; CHECK: callq __trunctfdf2
+; CHECK-NEXT: andpd {{.*}}, %xmm0
+; CHECK-NEXT: orpd {{.*}}, %xmm0
+; CHECK-NEXT: callq __extenddftf2
+; CHECK: retq
+}
+
+declare double @copysign(double, double) #1
+
+attributes #2 = { nounwind readnone }
diff --git a/llvm/test/CodeGen/X86/fp128-compare.ll b/llvm/test/CodeGen/X86/fp128-compare.ll
new file mode 100644
index 00000000000..b5d4fbe1b74
--- /dev/null
+++ b/llvm/test/CodeGen/X86/fp128-compare.ll
@@ -0,0 +1,96 @@
+; RUN: llc < %s -O2 -mtriple=x86_64-linux-android -mattr=+mmx | FileCheck %s
+; RUN: llc < %s -O2 -mtriple=x86_64-linux-gnu -mattr=+mmx | FileCheck %s
+
+define i32 @TestComp128GT(fp128 %d1, fp128 %d2) {
+entry:
+ %cmp = fcmp ogt fp128 %d1, %d2
+ %conv = zext i1 %cmp to i32
+ ret i32 %conv
+; CHECK-LABEL: TestComp128GT:
+; CHECK: callq __gttf2
+; CHECK: setg %al
+; CHECK: movzbl %al, %eax
+; CHECK: retq
+}
+
+define i32 @TestComp128GE(fp128 %d1, fp128 %d2) {
+entry:
+ %cmp = fcmp oge fp128 %d1, %d2
+ %conv = zext i1 %cmp to i32
+ ret i32 %conv
+; CHECK-LABEL: TestComp128GE:
+; CHECK: callq __getf2
+; CHECK: testl %eax, %eax
+; CHECK: setns %al
+; CHECK: movzbl %al, %eax
+; CHECK: retq
+}
+
+define i32 @TestComp128LT(fp128 %d1, fp128 %d2) {
+entry:
+ %cmp = fcmp olt fp128 %d1, %d2
+ %conv = zext i1 %cmp to i32
+ ret i32 %conv
+; CHECK-LABEL: TestComp128LT:
+; CHECK: callq __lttf2
+; CHECK-NEXT: shrl $31, %eax
+; CHECK: retq
+;
+; The 'shrl' is a special optimization in llvm to combine
+; the effect of 'fcmp olt' and 'zext'. The main purpose is
+; to test soften call to __lttf2.
+}
+
+define i32 @TestComp128LE(fp128 %d1, fp128 %d2) {
+entry:
+ %cmp = fcmp ole fp128 %d1, %d2
+ %conv = zext i1 %cmp to i32
+ ret i32 %conv
+; CHECK-LABEL: TestComp128LE:
+; CHECK: callq __letf2
+; CHECK-NEXT: testl %eax, %eax
+; CHECK: setle %al
+; CHECK: movzbl %al, %eax
+; CHECK: retq
+}
+
+define i32 @TestComp128EQ(fp128 %d1, fp128 %d2) {
+entry:
+ %cmp = fcmp oeq fp128 %d1, %d2
+ %conv = zext i1 %cmp to i32
+ ret i32 %conv
+; CHECK-LABEL: TestComp128EQ:
+; CHECK: callq __eqtf2
+; CHECK-NEXT: testl %eax, %eax
+; CHECK: sete %al
+; CHECK: movzbl %al, %eax
+; CHECK: retq
+}
+
+define i32 @TestComp128NE(fp128 %d1, fp128 %d2) {
+entry:
+ %cmp = fcmp une fp128 %d1, %d2
+ %conv = zext i1 %cmp to i32
+ ret i32 %conv
+; CHECK-LABEL: TestComp128NE:
+; CHECK: callq __netf2
+; CHECK-NEXT: testl %eax, %eax
+; CHECK: setne %al
+; CHECK: movzbl %al, %eax
+; CHECK: retq
+}
+
+define fp128 @TestMax(fp128 %x, fp128 %y) {
+entry:
+ %cmp = fcmp ogt fp128 %x, %y
+ %cond = select i1 %cmp, fp128 %x, fp128 %y
+ ret fp128 %cond
+; CHECK-LABEL: TestMax:
+; CHECK: movaps %xmm1
+; CHECK: movaps %xmm0
+; CHECK: callq __gttf2
+; CHECK: movaps {{.*}}, %xmm0
+; CHECK: testl %eax, %eax
+; CHECK: movaps {{.*}}, %xmm0
+; CHECK: retq
+}
diff --git a/llvm/test/CodeGen/X86/fp128-i128.ll b/llvm/test/CodeGen/X86/fp128-i128.ll
new file mode 100644
index 00000000000..77160674ab2
--- /dev/null
+++ b/llvm/test/CodeGen/X86/fp128-i128.ll
@@ -0,0 +1,320 @@
+; RUN: llc < %s -O2 -mtriple=x86_64-linux-android -mattr=+mmx | FileCheck %s
+; RUN: llc < %s -O2 -mtriple=x86_64-linux-gnu -mattr=+mmx | FileCheck %s
+
+; These tests were generated from simplified libm C code.
+; When compiled for the x86_64-linux-android target,
+; long double is mapped to f128 type that should be passed
+; in SSE registers. When the f128 type calling convention
+; problem was fixed, old llvm code failed to handle f128 values
+; in several f128/i128 type operations. These unit tests hopefully
+; will catch regression in any future change in this area.
+; To modified or enhance these test cases, please consult libm
+; code pattern and compile with -target x86_64-linux-android
+; to generate IL. The __float128 keyword if not accepted by
+; clang, just define it to "long double".
+;
+
+; typedef long double __float128;
+; union IEEEl2bits {
+; __float128 e;
+; struct {
+; unsigned long manl :64;
+; unsigned long manh :48;
+; unsigned int exp :15;
+; unsigned int sign :1;
+; } bits;
+; struct {
+; unsigned long manl :64;
+; unsigned long manh :48;
+; unsigned int expsign :16;
+; } xbits;
+; };
+
+; C code:
+; void foo(__float128 x);
+; void TestUnionLD1(__float128 s, unsigned long n) {
+; union IEEEl2bits u;
+; __float128 w;
+; u.e = s;
+; u.bits.manh = n;
+; w = u.e;
+; foo(w);
+; }
+define void @TestUnionLD1(fp128 %s, i64 %n) #0 {
+entry:
+ %0 = bitcast fp128 %s to i128
+ %1 = zext i64 %n to i128
+ %bf.value = shl nuw i128 %1, 64
+ %bf.shl = and i128 %bf.value, 5192296858534809181786422619668480
+ %bf.clear = and i128 %0, -5192296858534809181786422619668481
+ %bf.set = or i128 %bf.shl, %bf.clear
+ %2 = bitcast i128 %bf.set to fp128
+ tail call void @foo(fp128 %2) #2
+ ret void
+; CHECK-LABEL: TestUnionLD1:
+; CHECK: movaps %xmm0, -24(%rsp)
+; CHECK-NEXT: movq -24(%rsp), %rax
+; CHECK-NEXT: movabsq $281474976710655, %rcx
+; CHECK-NEXT: andq %rdi, %rcx
+; CHECK-NEXT: movabsq $-281474976710656, %rdx
+; CHECK-NEXT: andq -16(%rsp), %rdx
+; CHECK-NEXT: movq %rax, -40(%rsp)
+; CHECK-NEXT: orq %rcx, %rdx
+; CHECK-NEXT: movq %rdx, -32(%rsp)
+; CHECK-NEXT: movaps -40(%rsp), %xmm0
+; CHECK-NEXT: jmp foo
+}
+
+; C code:
+; __float128 TestUnionLD2(__float128 s) {
+; union IEEEl2bits u;
+; __float128 w;
+; u.e = s;
+; u.bits.manl = 0;
+; w = u.e;
+; return w;
+; }
+define fp128 @TestUnionLD2(fp128 %s) #0 {
+entry:
+ %0 = bitcast fp128 %s to i128
+ %bf.clear = and i128 %0, -18446744073709551616
+ %1 = bitcast i128 %bf.clear to fp128
+ ret fp128 %1
+; CHECK-LABEL: TestUnionLD2:
+; CHECK: movaps %xmm0, -24(%rsp)
+; CHECK-NEXT: movq -16(%rsp), %rax
+; CHECK-NEXT: movq %rax, -32(%rsp)
+; CHECK-NEXT: movq $0, -40(%rsp)
+; CHECK-NEXT: movaps -40(%rsp), %xmm0
+; CHECK-NEXT: retq
+}
+
+; C code:
+; __float128 TestI128_1(__float128 x)
+; {
+; union IEEEl2bits z;
+; z.e = x;
+; z.bits.sign = 0;
+; return (z.e < 0.1L) ? 1.0L : 2.0L;
+; }
+define fp128 @TestI128_1(fp128 %x) #0 {
+entry:
+ %0 = bitcast fp128 %x to i128
+ %bf.clear = and i128 %0, 170141183460469231731687303715884105727
+ %1 = bitcast i128 %bf.clear to fp128
+ %cmp = fcmp olt fp128 %1, 0xL999999999999999A3FFB999999999999
+ %cond = select i1 %cmp, fp128 0xL00000000000000003FFF000000000000, fp128 0xL00000000000000004000000000000000
+ ret fp128 %cond
+; CHECK-LABEL: TestI128_1:
+; CHECK: movaps %xmm0,
+; CHECK: movabsq $9223372036854775807,
+; CHECK: callq __lttf2
+; CHECK: testl %eax, %eax
+; CHECK: movaps {{.*}}, %xmm0
+; CHECK: retq
+}
+
+; C code:
+; __float128 TestI128_2(__float128 x, __float128 y)
+; {
+; unsigned short hx;
+; union IEEEl2bits ge_u;
+; ge_u.e = x;
+; hx = ge_u.xbits.expsign;
+; return (hx & 0x8000) == 0 ? x : y;
+; }
+define fp128 @TestI128_2(fp128 %x, fp128 %y) #0 {
+entry:
+ %0 = bitcast fp128 %x to i128
+ %cmp = icmp sgt i128 %0, -1
+ %cond = select i1 %cmp, fp128 %x, fp128 %y
+ ret fp128 %cond
+; CHECK-LABEL: TestI128_2:
+; CHECK: movaps %xmm0, -24(%rsp)
+; CHECK-NEXT: cmpq $0, -16(%rsp)
+; CHECK-NEXT: jns
+; CHECK: movaps %xmm1, %xmm0
+; CHECK: retq
+}
+
+; C code:
+; __float128 TestI128_3(__float128 x, int *ex)
+; {
+; union IEEEl2bits u;
+; u.e = x;
+; if (u.bits.exp == 0) {
+; u.e *= 0x1.0p514;
+; u.bits.exp = 0x3ffe;
+; }
+; return (u.e);
+; }
+define fp128 @TestI128_3(fp128 %x, i32* nocapture readnone %ex) #0 {
+entry:
+ %0 = bitcast fp128 %x to i128
+ %bf.cast = and i128 %0, 170135991163610696904058773219554885632
+ %cmp = icmp eq i128 %bf.cast, 0
+ br i1 %cmp, label %if.then, label %if.end
+
+if.then: ; preds = %entry
+ %mul = fmul fp128 %x, 0xL00000000000000004201000000000000
+ %1 = bitcast fp128 %mul to i128
+ %bf.clear4 = and i128 %1, -170135991163610696904058773219554885633
+ %bf.set = or i128 %bf.clear4, 85060207136517546210586590865283612672
+ br label %if.end
+
+if.end: ; preds = %if.then, %entry
+ %u.sroa.0.0 = phi i128 [ %bf.set, %if.then ], [ %0, %entry ]
+ %2 = bitcast i128 %u.sroa.0.0 to fp128
+ ret fp128 %2
+; CHECK-LABEL: TestI128_3:
+; CHECK: movaps %xmm0,
+; CHECK: movabsq $9223090561878065152,
+; CHECK: testq
+; CHECK: callq __multf3
+; CHECK-NEXT: movaps %xmm0
+; CHECK: movabsq $-9223090561878065153,
+; CHECK: movabsq $4611123068473966592,
+; CHECK: retq
+}
+
+; C code:
+; __float128 TestI128_4(__float128 x)
+; {
+; union IEEEl2bits u;
+; __float128 df;
+; u.e = x;
+; u.xbits.manl = 0;
+; df = u.e;
+; return x + df;
+; }
+define fp128 @TestI128_4(fp128 %x) #0 {
+entry:
+ %0 = bitcast fp128 %x to i128
+ %bf.clear = and i128 %0, -18446744073709551616
+ %1 = bitcast i128 %bf.clear to fp128
+ %add = fadd fp128 %1, %x
+ ret fp128 %add
+; CHECK-LABEL: TestI128_4:
+; CHECK: movaps %xmm0, %xmm1
+; CHECK-NEXT: movaps %xmm1, 16(%rsp)
+; CHECK-NEXT: movq 24(%rsp), %rax
+; CHECK-NEXT: movq %rax, 8(%rsp)
+; CHECK-NEXT: movq $0, (%rsp)
+; CHECK-NEXT: movaps (%rsp), %xmm0
+; CHECK-NEXT: callq __addtf3
+; CHECK: retq
+}
+
+@v128 = common global i128 0, align 16
+@v128_2 = common global i128 0, align 16
+
+; C code:
+; unsigned __int128 v128, v128_2;
+; void TestShift128_2() {
+; v128 = ((v128 << 96) | v128_2);
+; }
+define void @TestShift128_2() #2 {
+entry:
+ %0 = load i128, i128* @v128, align 16
+ %shl = shl i128 %0, 96
+ %1 = load i128, i128* @v128_2, align 16
+ %or = or i128 %shl, %1
+ store i128 %or, i128* @v128, align 16
+ ret void
+; CHECK-LABEL: TestShift128_2:
+; CHECK: movq v128(%rip), %rax
+; CHECK-NEXT: shlq $32, %rax
+; CHECK-NEXT: movq v128_2(%rip), %rcx
+; CHECK-NEXT: orq v128_2+8(%rip), %rax
+; CHECK-NEXT: movq %rcx, v128(%rip)
+; CHECK-NEXT: movq %rax, v128+8(%rip)
+; CHECK-NEXT: retq
+}
+
+define fp128 @acosl(fp128 %x) #0 {
+entry:
+ %0 = bitcast fp128 %x to i128
+ %bf.clear = and i128 %0, -18446744073709551616
+ %1 = bitcast i128 %bf.clear to fp128
+ %add = fadd fp128 %1, %x
+ ret fp128 %add
+; CHECK-LABEL: acosl:
+; CHECK: movaps %xmm0, %xmm1
+; CHECK-NEXT: movaps %xmm1, 16(%rsp)
+; CHECK-NEXT: movq 24(%rsp), %rax
+; CHECK-NEXT: movq %rax, 8(%rsp)
+; CHECK-NEXT: movq $0, (%rsp)
+; CHECK-NEXT: movaps (%rsp), %xmm0
+; CHECK-NEXT: callq __addtf3
+; CHECK: retq
+}
+
+; Compare i128 values and check i128 constants.
+define fp128 @TestComp(fp128 %x, fp128 %y) #0 {
+entry:
+ %0 = bitcast fp128 %x to i128
+ %cmp = icmp sgt i128 %0, -1
+ %cond = select i1 %cmp, fp128 %x, fp128 %y
+ ret fp128 %cond
+; CHECK-LABEL: TestComp:
+; CHECK: movaps %xmm0, -24(%rsp)
+; CHECK-NEXT: cmpq $0, -16(%rsp)
+; CHECK-NEXT: jns
+; CHECK: movaps %xmm1, %xmm0
+; CHECK: retq
+}
+
+declare void @foo(fp128) #1
+
+; Test logical operations on fp128 values.
+define fp128 @TestFABS_LD(fp128 %x) #0 {
+entry:
+ %call = tail call fp128 @fabsl(fp128 %x) #2
+ ret fp128 %call
+; CHECK-LABEL: TestFABS_LD
+; CHECK: andps {{.*}}, %xmm0
+; CHECK-NEXT: retq
+}
+
+declare fp128 @fabsl(fp128) #1
+
+declare fp128 @copysignl(fp128, fp128) #1
+
+; Test more complicated logical operations generated from copysignl.
+define void @TestCopySign({ fp128, fp128 }* noalias nocapture sret %agg.result, { fp128, fp128 }* byval nocapture readonly align 16 %z) #0 {
+entry:
+ %z.realp = getelementptr inbounds { fp128, fp128 }, { fp128, fp128 }* %z, i64 0, i32 0
+ %z.real = load fp128, fp128* %z.realp, align 16
+ %z.imagp = getelementptr inbounds { fp128, fp128 }, { fp128, fp128 }* %z, i64 0, i32 1
+ %z.imag4 = load fp128, fp128* %z.imagp, align 16
+ %cmp = fcmp ogt fp128 %z.real, %z.imag4
+ %sub = fsub fp128 %z.imag4, %z.imag4
+ br i1 %cmp, label %if.then, label %cleanup
+
+if.then: ; preds = %entry
+ %call = tail call fp128 @fabsl(fp128 %sub) #2
+ br label %cleanup
+
+cleanup: ; preds = %entry, %if.then
+ %z.real.sink = phi fp128 [ %z.real, %if.then ], [ %sub, %entry ]
+ %call.sink = phi fp128 [ %call, %if.then ], [ %z.real, %entry ]
+ %call5 = tail call fp128 @copysignl(fp128 %z.real.sink, fp128 %z.imag4) #2
+ %0 = getelementptr inbounds { fp128, fp128 }, { fp128, fp128 }* %agg.result, i64 0, i32 0
+ %1 = getelementptr inbounds { fp128, fp128 }, { fp128, fp128 }* %agg.result, i64 0, i32 1
+ store fp128 %call.sink, fp128* %0, align 16
+ store fp128 %call5, fp128* %1, align 16
+ ret void
+; CHECK-LABEL: TestCopySign
+; CHECK-NOT: call
+; CHECK: callq __subtf3
+; CHECK-NOT: call
+; CHECK: callq __gttf2
+; CHECK-NOT: call
+; CHECK: andps {{.*}}, %xmm0
+; CHECK: retq
+}
+
+
+attributes #0 = { nounwind uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+ssse3,+sse3,+popcnt,+sse,+sse2,+sse4.1,+sse4.2" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+ssse3,+sse3,+popcnt,+sse,+sse2,+sse4.1,+sse4.2" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #2 = { nounwind readnone }
diff --git a/llvm/test/CodeGen/X86/fp128-libcalls.ll b/llvm/test/CodeGen/X86/fp128-libcalls.ll
new file mode 100644
index 00000000000..ee5fa447448
--- /dev/null
+++ b/llvm/test/CodeGen/X86/fp128-libcalls.ll
@@ -0,0 +1,107 @@
+; RUN: llc < %s -O2 -mtriple=x86_64-linux-android -mattr=+mmx | FileCheck %s
+; RUN: llc < %s -O2 -mtriple=x86_64-linux-gnu -mattr=+mmx | FileCheck %s
+
+; Check all soft floating point library function calls.
+
+@vf64 = common global double 0.000000e+00, align 8
+@vf128 = common global fp128 0xL00000000000000000000000000000000, align 16
+
+define void @Test128Add(fp128 %d1, fp128 %d2) {
+entry:
+ %add = fadd fp128 %d1, %d2
+ store fp128 %add, fp128* @vf128, align 16
+ ret void
+; CHECK-LABEL: Test128Add:
+; CHECK: callq __addtf3
+; CHECK-NEXT: movaps %xmm0, vf128(%rip)
+; CHECK: retq
+}
+
+define void @Test128_1Add(fp128 %d1){
+entry:
+ %0 = load fp128, fp128* @vf128, align 16
+ %add = fadd fp128 %0, %d1
+ store fp128 %add, fp128* @vf128, align 16
+ ret void
+; CHECK-LABEL: Test128_1Add:
+; CHECK: movaps %xmm0, %xmm1
+; CHECK-NEXT: movaps vf128(%rip), %xmm0
+; CHECK-NEXT: callq __addtf3
+; CHECK-NEXT: movaps %xmm0, vf128(%rip)
+; CHECK: retq
+}
+
+define void @Test128Sub(fp128 %d1, fp128 %d2){
+entry:
+ %sub = fsub fp128 %d1, %d2
+ store fp128 %sub, fp128* @vf128, align 16
+ ret void
+; CHECK-LABEL: Test128Sub:
+; CHECK: callq __subtf3
+; CHECK-NEXT: movaps %xmm0, vf128(%rip)
+; CHECK: retq
+}
+
+define void @Test128_1Sub(fp128 %d1){
+entry:
+ %0 = load fp128, fp128* @vf128, align 16
+ %sub = fsub fp128 %0, %d1
+ store fp128 %sub, fp128* @vf128, align 16
+ ret void
+; CHECK-LABEL: Test128_1Sub:
+; CHECK: movaps %xmm0, %xmm1
+; CHECK-NEXT: movaps vf128(%rip), %xmm0
+; CHECK-NEXT: callq __subtf3
+; CHECK-NEXT: movaps %xmm0, vf128(%rip)
+; CHECK: retq
+}
+
+define void @Test128Mul(fp128 %d1, fp128 %d2){
+entry:
+ %mul = fmul fp128 %d1, %d2
+ store fp128 %mul, fp128* @vf128, align 16
+ ret void
+; CHECK-LABEL: Test128Mul:
+; CHECK: callq __multf3
+; CHECK-NEXT: movaps %xmm0, vf128(%rip)
+; CHECK: retq
+}
+
+define void @Test128_1Mul(fp128 %d1){
+entry:
+ %0 = load fp128, fp128* @vf128, align 16
+ %mul = fmul fp128 %0, %d1
+ store fp128 %mul, fp128* @vf128, align 16
+ ret void
+; CHECK-LABEL: Test128_1Mul:
+; CHECK: movaps %xmm0, %xmm1
+; CHECK-NEXT: movaps vf128(%rip), %xmm0
+; CHECK-NEXT: callq __multf3
+; CHECK-NEXT: movaps %xmm0, vf128(%rip)
+; CHECK: retq
+}
+
+define void @Test128Div(fp128 %d1, fp128 %d2){
+entry:
+ %div = fdiv fp128 %d1, %d2
+ store fp128 %div, fp128* @vf128, align 16
+ ret void
+; CHECK-LABEL: Test128Div:
+; CHECK: callq __divtf3
+; CHECK-NEXT: movaps %xmm0, vf128(%rip)
+; CHECK: retq
+}
+
+define void @Test128_1Div(fp128 %d1){
+entry:
+ %0 = load fp128, fp128* @vf128, align 16
+ %div = fdiv fp128 %0, %d1
+ store fp128 %div, fp128* @vf128, align 16
+ ret void
+; CHECK-LABEL: Test128_1Div:
+; CHECK: movaps %xmm0, %xmm1
+; CHECK-NEXT: movaps vf128(%rip), %xmm0
+; CHECK-NEXT: callq __divtf3
+; CHECK-NEXT: movaps %xmm0, vf128(%rip)
+; CHECK: retq
+}
diff --git a/llvm/test/CodeGen/X86/fp128-load.ll b/llvm/test/CodeGen/X86/fp128-load.ll
new file mode 100644
index 00000000000..73bacf87275
--- /dev/null
+++ b/llvm/test/CodeGen/X86/fp128-load.ll
@@ -0,0 +1,35 @@
+; RUN: llc < %s -O2 -mtriple=x86_64-linux-android -mattr=+mmx | FileCheck %s
+; RUN: llc < %s -O2 -mtriple=x86_64-linux-gnu -mattr=+mmx | FileCheck %s
+
+; __float128 myFP128 = 1.0L; // x86_64-linux-android
+@my_fp128 = global fp128 0xL00000000000000003FFF000000000000, align 16
+
+define fp128 @get_fp128() {
+entry:
+ %0 = load fp128, fp128* @my_fp128, align 16
+ ret fp128 %0
+; CHECK-LABEL: get_fp128:
+; CHECK: movaps my_fp128(%rip), %xmm0
+; CHECK-NEXT: retq
+}
+
+@TestLoadExtend.data = internal unnamed_addr constant [2 x float] [float 0x3FB99999A0000000, float 0x3FC99999A0000000], align 4
+
+define fp128 @TestLoadExtend(fp128 %x, i32 %n) {
+entry:
+ %idxprom = sext i32 %n to i64
+ %arrayidx = getelementptr inbounds [2 x float], [2 x float]* @TestLoadExtend.data, i64 0, i64 %idxprom
+ %0 = load float, float* %arrayidx, align 4
+ %conv = fpext float %0 to fp128
+ ret fp128 %conv
+; CHECK-LABEL: TestLoadExtend:
+; CHECK: movslq %edi, %rax
+; CHECK-NEXT: movss TestLoadExtend.data(,%rax,4), %xmm0
+; CHECK-NEXT: callq __extendsftf2
+; CHECK: retq
+}
+
+; CHECK-LABEL: my_fp128:
+; CHECK-NEXT: .quad 0
+; CHECK-NEXT: .quad 4611404543450677248
+; CHECK-NEXT: .size my_fp128, 16
diff --git a/llvm/test/CodeGen/X86/fp128-store.ll b/llvm/test/CodeGen/X86/fp128-store.ll
new file mode 100644
index 00000000000..ca3af637cff
--- /dev/null
+++ b/llvm/test/CodeGen/X86/fp128-store.ll
@@ -0,0 +1,14 @@
+; RUN: llc < %s -O2 -mtriple=x86_64-linux-android -mattr=+mmx | FileCheck %s
+; RUN: llc < %s -O2 -mtriple=x86_64-linux-gnu -mattr=+mmx | FileCheck %s
+
+; __float128 myFP128 = 1.0L; // x86_64-linux-android
+@myFP128 = global fp128 0xL00000000000000003FFF000000000000, align 16
+
+define void @set_FP128(fp128 %x) {
+entry:
+ store fp128 %x, fp128* @myFP128, align 16
+ ret void
+; CHECK-LABEL: set_FP128:
+; CHECK: movaps %xmm0, myFP128(%rip)
+; CHECK-NEXT: retq
+}
diff --git a/llvm/test/CodeGen/X86/soft-fp.ll b/llvm/test/CodeGen/X86/soft-fp.ll
index aff51cea75d..138e66c394b 100644
--- a/llvm/test/CodeGen/X86/soft-fp.ll
+++ b/llvm/test/CodeGen/X86/soft-fp.ll
@@ -1,8 +1,14 @@
-; RUN: llc < %s -march=x86 -mattr=+sse2,+soft-float | FileCheck %s
-; RUN: llc < %s -march=x86-64 -mattr=+sse2,+soft-float | FileCheck %s
-; RUN: llc < %s -mtriple=x86_64-gnux32 -mattr=+sse2,+soft-float | FileCheck %s
+; RUN: llc < %s -march=x86 -mattr=+mmx,+sse,+soft-float \
+; RUN: | FileCheck %s --check-prefix=SOFT1 --check-prefix=CHECK
+; RUN: llc < %s -march=x86-64 -mattr=+mmx,+sse2,+soft-float \
+; RUN: | FileCheck %s --check-prefix=SOFT2 --check-prefix=CHECK
+; RUN: llc < %s -march=x86-64 -mattr=+mmx,+sse \
+; RUN: | FileCheck %s --check-prefix=SSE1 --check-prefix=CHECK
+; RUN: llc < %s -march=x86-64 -mattr=+mmx,+sse2 \
+; RUN: | FileCheck %s --check-prefix=SSE2 --check-prefix=CHECK
+; RUN: llc < %s -mtriple=x86_64-gnux32 -mattr=+mmx,+sse2,+soft-float | FileCheck %s
-; CHECK-NOT: xmm{[0-9]+}
+; CHECK-NOT: xmm{{[0-9]+}}
%struct.__va_list_tag = type { i32, i32, i8*, i8* }
@@ -15,6 +21,8 @@ entry:
call void @bar(%struct.__va_list_tag* %va3) nounwind
call void @llvm.va_end(i8* %va12)
ret i32 undef
+; CHECK-LABEL: t1:
+; CHECK: ret{{[lq]}}
}
declare void @llvm.va_start(i8*) nounwind
@@ -27,4 +35,23 @@ define float @t2(float %a, float %b) nounwind readnone {
entry:
%0 = fadd float %a, %b ; <float> [#uses=1]
ret float %0
+; CHECK-LABEL: t2:
+; SOFT1-NOT: xmm{{[0-9]+}}
+; SOFT2-NOT: xmm{{[0-9]+}}
+; SSE1: xmm{{[0-9]+}}
+; SSE2: xmm{{[0-9]+}}
+; CHECK: ret{{[lq]}}
+}
+
+; soft-float means no SSE instruction and passing fp128 as pair of i64.
+define fp128 @t3(fp128 %a, fp128 %b) nounwind readnone {
+entry:
+ %0 = fadd fp128 %b, %a
+ ret fp128 %0
+; CHECK-LABEL: t3:
+; SOFT1-NOT: xmm{{[0-9]+}}
+; SOFT2-NOT: xmm{{[0-9]+}}
+; SSE1: xmm{{[0-9]+}}
+; SSE2: xmm{{[0-9]+}}
+; CHECK: ret{{[lq]}}
}
OpenPOWER on IntegriCloud