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