blob: 77160674ab204046599ff6be48d79ea9b06a8d56 [file] [log] [blame]
Chih-Hung Hsieh7993e182015-12-14 22:08:36 +00001; RUN: llc < %s -O2 -mtriple=x86_64-linux-android -mattr=+mmx | FileCheck %s
2; RUN: llc < %s -O2 -mtriple=x86_64-linux-gnu -mattr=+mmx | FileCheck %s
3
4; These tests were generated from simplified libm C code.
5; When compiled for the x86_64-linux-android target,
6; long double is mapped to f128 type that should be passed
7; in SSE registers. When the f128 type calling convention
8; problem was fixed, old llvm code failed to handle f128 values
9; in several f128/i128 type operations. These unit tests hopefully
10; will catch regression in any future change in this area.
11; To modified or enhance these test cases, please consult libm
12; code pattern and compile with -target x86_64-linux-android
13; to generate IL. The __float128 keyword if not accepted by
14; clang, just define it to "long double".
15;
16
17; typedef long double __float128;
18; union IEEEl2bits {
19; __float128 e;
20; struct {
21; unsigned long manl :64;
22; unsigned long manh :48;
23; unsigned int exp :15;
24; unsigned int sign :1;
25; } bits;
26; struct {
27; unsigned long manl :64;
28; unsigned long manh :48;
29; unsigned int expsign :16;
30; } xbits;
31; };
32
33; C code:
34; void foo(__float128 x);
35; void TestUnionLD1(__float128 s, unsigned long n) {
36; union IEEEl2bits u;
37; __float128 w;
38; u.e = s;
39; u.bits.manh = n;
40; w = u.e;
41; foo(w);
42; }
43define void @TestUnionLD1(fp128 %s, i64 %n) #0 {
44entry:
45 %0 = bitcast fp128 %s to i128
46 %1 = zext i64 %n to i128
47 %bf.value = shl nuw i128 %1, 64
48 %bf.shl = and i128 %bf.value, 5192296858534809181786422619668480
49 %bf.clear = and i128 %0, -5192296858534809181786422619668481
50 %bf.set = or i128 %bf.shl, %bf.clear
51 %2 = bitcast i128 %bf.set to fp128
52 tail call void @foo(fp128 %2) #2
53 ret void
54; CHECK-LABEL: TestUnionLD1:
55; CHECK: movaps %xmm0, -24(%rsp)
56; CHECK-NEXT: movq -24(%rsp), %rax
57; CHECK-NEXT: movabsq $281474976710655, %rcx
58; CHECK-NEXT: andq %rdi, %rcx
59; CHECK-NEXT: movabsq $-281474976710656, %rdx
60; CHECK-NEXT: andq -16(%rsp), %rdx
61; CHECK-NEXT: movq %rax, -40(%rsp)
62; CHECK-NEXT: orq %rcx, %rdx
63; CHECK-NEXT: movq %rdx, -32(%rsp)
64; CHECK-NEXT: movaps -40(%rsp), %xmm0
65; CHECK-NEXT: jmp foo
66}
67
68; C code:
69; __float128 TestUnionLD2(__float128 s) {
70; union IEEEl2bits u;
71; __float128 w;
72; u.e = s;
73; u.bits.manl = 0;
74; w = u.e;
75; return w;
76; }
77define fp128 @TestUnionLD2(fp128 %s) #0 {
78entry:
79 %0 = bitcast fp128 %s to i128
80 %bf.clear = and i128 %0, -18446744073709551616
81 %1 = bitcast i128 %bf.clear to fp128
82 ret fp128 %1
83; CHECK-LABEL: TestUnionLD2:
84; CHECK: movaps %xmm0, -24(%rsp)
85; CHECK-NEXT: movq -16(%rsp), %rax
86; CHECK-NEXT: movq %rax, -32(%rsp)
87; CHECK-NEXT: movq $0, -40(%rsp)
88; CHECK-NEXT: movaps -40(%rsp), %xmm0
89; CHECK-NEXT: retq
90}
91
92; C code:
93; __float128 TestI128_1(__float128 x)
94; {
95; union IEEEl2bits z;
96; z.e = x;
97; z.bits.sign = 0;
98; return (z.e < 0.1L) ? 1.0L : 2.0L;
99; }
100define fp128 @TestI128_1(fp128 %x) #0 {
101entry:
102 %0 = bitcast fp128 %x to i128
103 %bf.clear = and i128 %0, 170141183460469231731687303715884105727
104 %1 = bitcast i128 %bf.clear to fp128
105 %cmp = fcmp olt fp128 %1, 0xL999999999999999A3FFB999999999999
106 %cond = select i1 %cmp, fp128 0xL00000000000000003FFF000000000000, fp128 0xL00000000000000004000000000000000
107 ret fp128 %cond
108; CHECK-LABEL: TestI128_1:
109; CHECK: movaps %xmm0,
110; CHECK: movabsq $9223372036854775807,
111; CHECK: callq __lttf2
112; CHECK: testl %eax, %eax
113; CHECK: movaps {{.*}}, %xmm0
114; CHECK: retq
115}
116
117; C code:
118; __float128 TestI128_2(__float128 x, __float128 y)
119; {
120; unsigned short hx;
121; union IEEEl2bits ge_u;
122; ge_u.e = x;
123; hx = ge_u.xbits.expsign;
124; return (hx & 0x8000) == 0 ? x : y;
125; }
126define fp128 @TestI128_2(fp128 %x, fp128 %y) #0 {
127entry:
128 %0 = bitcast fp128 %x to i128
129 %cmp = icmp sgt i128 %0, -1
130 %cond = select i1 %cmp, fp128 %x, fp128 %y
131 ret fp128 %cond
132; CHECK-LABEL: TestI128_2:
133; CHECK: movaps %xmm0, -24(%rsp)
134; CHECK-NEXT: cmpq $0, -16(%rsp)
135; CHECK-NEXT: jns
136; CHECK: movaps %xmm1, %xmm0
137; CHECK: retq
138}
139
140; C code:
141; __float128 TestI128_3(__float128 x, int *ex)
142; {
143; union IEEEl2bits u;
144; u.e = x;
145; if (u.bits.exp == 0) {
146; u.e *= 0x1.0p514;
147; u.bits.exp = 0x3ffe;
148; }
149; return (u.e);
150; }
151define fp128 @TestI128_3(fp128 %x, i32* nocapture readnone %ex) #0 {
152entry:
153 %0 = bitcast fp128 %x to i128
154 %bf.cast = and i128 %0, 170135991163610696904058773219554885632
155 %cmp = icmp eq i128 %bf.cast, 0
156 br i1 %cmp, label %if.then, label %if.end
157
158if.then: ; preds = %entry
159 %mul = fmul fp128 %x, 0xL00000000000000004201000000000000
160 %1 = bitcast fp128 %mul to i128
161 %bf.clear4 = and i128 %1, -170135991163610696904058773219554885633
162 %bf.set = or i128 %bf.clear4, 85060207136517546210586590865283612672
163 br label %if.end
164
165if.end: ; preds = %if.then, %entry
166 %u.sroa.0.0 = phi i128 [ %bf.set, %if.then ], [ %0, %entry ]
167 %2 = bitcast i128 %u.sroa.0.0 to fp128
168 ret fp128 %2
169; CHECK-LABEL: TestI128_3:
170; CHECK: movaps %xmm0,
171; CHECK: movabsq $9223090561878065152,
172; CHECK: testq
173; CHECK: callq __multf3
174; CHECK-NEXT: movaps %xmm0
175; CHECK: movabsq $-9223090561878065153,
176; CHECK: movabsq $4611123068473966592,
177; CHECK: retq
178}
179
180; C code:
181; __float128 TestI128_4(__float128 x)
182; {
183; union IEEEl2bits u;
184; __float128 df;
185; u.e = x;
186; u.xbits.manl = 0;
187; df = u.e;
188; return x + df;
189; }
190define fp128 @TestI128_4(fp128 %x) #0 {
191entry:
192 %0 = bitcast fp128 %x to i128
193 %bf.clear = and i128 %0, -18446744073709551616
194 %1 = bitcast i128 %bf.clear to fp128
195 %add = fadd fp128 %1, %x
196 ret fp128 %add
197; CHECK-LABEL: TestI128_4:
198; CHECK: movaps %xmm0, %xmm1
199; CHECK-NEXT: movaps %xmm1, 16(%rsp)
200; CHECK-NEXT: movq 24(%rsp), %rax
201; CHECK-NEXT: movq %rax, 8(%rsp)
202; CHECK-NEXT: movq $0, (%rsp)
203; CHECK-NEXT: movaps (%rsp), %xmm0
204; CHECK-NEXT: callq __addtf3
205; CHECK: retq
206}
207
208@v128 = common global i128 0, align 16
209@v128_2 = common global i128 0, align 16
210
211; C code:
212; unsigned __int128 v128, v128_2;
213; void TestShift128_2() {
214; v128 = ((v128 << 96) | v128_2);
215; }
216define void @TestShift128_2() #2 {
217entry:
218 %0 = load i128, i128* @v128, align 16
219 %shl = shl i128 %0, 96
220 %1 = load i128, i128* @v128_2, align 16
221 %or = or i128 %shl, %1
222 store i128 %or, i128* @v128, align 16
223 ret void
224; CHECK-LABEL: TestShift128_2:
225; CHECK: movq v128(%rip), %rax
226; CHECK-NEXT: shlq $32, %rax
227; CHECK-NEXT: movq v128_2(%rip), %rcx
228; CHECK-NEXT: orq v128_2+8(%rip), %rax
229; CHECK-NEXT: movq %rcx, v128(%rip)
230; CHECK-NEXT: movq %rax, v128+8(%rip)
231; CHECK-NEXT: retq
232}
233
234define fp128 @acosl(fp128 %x) #0 {
235entry:
236 %0 = bitcast fp128 %x to i128
237 %bf.clear = and i128 %0, -18446744073709551616
238 %1 = bitcast i128 %bf.clear to fp128
239 %add = fadd fp128 %1, %x
240 ret fp128 %add
241; CHECK-LABEL: acosl:
242; CHECK: movaps %xmm0, %xmm1
243; CHECK-NEXT: movaps %xmm1, 16(%rsp)
244; CHECK-NEXT: movq 24(%rsp), %rax
245; CHECK-NEXT: movq %rax, 8(%rsp)
246; CHECK-NEXT: movq $0, (%rsp)
247; CHECK-NEXT: movaps (%rsp), %xmm0
248; CHECK-NEXT: callq __addtf3
249; CHECK: retq
250}
251
252; Compare i128 values and check i128 constants.
253define fp128 @TestComp(fp128 %x, fp128 %y) #0 {
254entry:
255 %0 = bitcast fp128 %x to i128
256 %cmp = icmp sgt i128 %0, -1
257 %cond = select i1 %cmp, fp128 %x, fp128 %y
258 ret fp128 %cond
259; CHECK-LABEL: TestComp:
260; CHECK: movaps %xmm0, -24(%rsp)
261; CHECK-NEXT: cmpq $0, -16(%rsp)
262; CHECK-NEXT: jns
263; CHECK: movaps %xmm1, %xmm0
264; CHECK: retq
265}
266
267declare void @foo(fp128) #1
268
269; Test logical operations on fp128 values.
270define fp128 @TestFABS_LD(fp128 %x) #0 {
271entry:
272 %call = tail call fp128 @fabsl(fp128 %x) #2
273 ret fp128 %call
274; CHECK-LABEL: TestFABS_LD
275; CHECK: andps {{.*}}, %xmm0
276; CHECK-NEXT: retq
277}
278
279declare fp128 @fabsl(fp128) #1
280
281declare fp128 @copysignl(fp128, fp128) #1
282
283; Test more complicated logical operations generated from copysignl.
284define void @TestCopySign({ fp128, fp128 }* noalias nocapture sret %agg.result, { fp128, fp128 }* byval nocapture readonly align 16 %z) #0 {
285entry:
286 %z.realp = getelementptr inbounds { fp128, fp128 }, { fp128, fp128 }* %z, i64 0, i32 0
287 %z.real = load fp128, fp128* %z.realp, align 16
288 %z.imagp = getelementptr inbounds { fp128, fp128 }, { fp128, fp128 }* %z, i64 0, i32 1
289 %z.imag4 = load fp128, fp128* %z.imagp, align 16
290 %cmp = fcmp ogt fp128 %z.real, %z.imag4
291 %sub = fsub fp128 %z.imag4, %z.imag4
292 br i1 %cmp, label %if.then, label %cleanup
293
294if.then: ; preds = %entry
295 %call = tail call fp128 @fabsl(fp128 %sub) #2
296 br label %cleanup
297
298cleanup: ; preds = %entry, %if.then
299 %z.real.sink = phi fp128 [ %z.real, %if.then ], [ %sub, %entry ]
300 %call.sink = phi fp128 [ %call, %if.then ], [ %z.real, %entry ]
301 %call5 = tail call fp128 @copysignl(fp128 %z.real.sink, fp128 %z.imag4) #2
302 %0 = getelementptr inbounds { fp128, fp128 }, { fp128, fp128 }* %agg.result, i64 0, i32 0
303 %1 = getelementptr inbounds { fp128, fp128 }, { fp128, fp128 }* %agg.result, i64 0, i32 1
304 store fp128 %call.sink, fp128* %0, align 16
305 store fp128 %call5, fp128* %1, align 16
306 ret void
307; CHECK-LABEL: TestCopySign
308; CHECK-NOT: call
309; CHECK: callq __subtf3
310; CHECK-NOT: call
311; CHECK: callq __gttf2
312; CHECK-NOT: call
313; CHECK: andps {{.*}}, %xmm0
314; CHECK: retq
315}
316
317
318attributes #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" }
319attributes #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" }
320attributes #2 = { nounwind readnone }