1; RUN: llc < %s -O2 -mtriple=x86_64-linux-android -mattr=+mmx | FileCheck %s --check-prefix=X64 2; RUN: llc < %s -O2 -mtriple=x86_64-linux-gnu -mattr=+mmx | FileCheck %s --check-prefix=X64 3; RUN: llc < %s -O2 -mtriple=i686-linux-gnu -mattr=+mmx | FileCheck %s --check-prefix=X32 4 5; Check soft floating point conversion function calls. 6 7@vi32 = common global i32 0, align 4 8@vi64 = common global i64 0, align 8 9@vu32 = common global i32 0, align 4 10@vu64 = common global i64 0, align 8 11@vf32 = common global float 0.000000e+00, align 4 12@vf64 = common global double 0.000000e+00, align 8 13@vf128 = common global fp128 0xL00000000000000000000000000000000, align 16 14 15define void @TestFPExtF32_F128() { 16entry: 17 %0 = load float, float* @vf32, align 4 18 %conv = fpext float %0 to fp128 19 store fp128 %conv, fp128* @vf128, align 16 20 ret void 21; X32-LABEL: TestFPExtF32_F128: 22; X32: flds vf32 23; X32: fstps 24; X32: calll __extendsftf2 25; X32: retl 26; 27; X64-LABEL: TestFPExtF32_F128: 28; X64: movss vf32(%rip), %xmm0 29; X64-NEXT: callq __extendsftf2 30; X64-NEXT: movaps %xmm0, vf128(%rip) 31; X64: retq 32} 33 34define void @TestFPExtF64_F128() { 35entry: 36 %0 = load double, double* @vf64, align 8 37 %conv = fpext double %0 to fp128 38 store fp128 %conv, fp128* @vf128, align 16 39 ret void 40; X32-LABEL: TestFPExtF64_F128: 41; X32: fldl vf64 42; X32: fstpl 43; X32: calll __extenddftf2 44; X32: retl 45; 46; X64-LABEL: TestFPExtF64_F128: 47; X64: movsd vf64(%rip), %xmm0 48; X64-NEXT: callq __extenddftf2 49; X64-NEXT: movapd %xmm0, vf128(%rip) 50; X64: ret 51} 52 53define void @TestFPToSIF128_I32() { 54entry: 55 %0 = load fp128, fp128* @vf128, align 16 56 %conv = fptosi fp128 %0 to i32 57 store i32 %conv, i32* @vi32, align 4 58 ret void 59; X32-LABEL: TestFPToSIF128_I32: 60; X32: calll __fixtfsi 61; X32: retl 62; 63; X64-LABEL: TestFPToSIF128_I32: 64; X64: movaps vf128(%rip), %xmm0 65; X64-NEXT: callq __fixtfsi 66; X64-NEXT: movl %eax, vi32(%rip) 67; X64: retq 68} 69 70define void @TestFPToUIF128_U32() { 71entry: 72 %0 = load fp128, fp128* @vf128, align 16 73 %conv = fptoui fp128 %0 to i32 74 store i32 %conv, i32* @vu32, align 4 75 ret void 76; X32-LABEL: TestFPToUIF128_U32: 77; X32: calll __fixunstfsi 78; X32: retl 79; 80; X64-LABEL: TestFPToUIF128_U32: 81; X64: movaps vf128(%rip), %xmm0 82; X64-NEXT: callq __fixunstfsi 83; X64-NEXT: movl %eax, vu32(%rip) 84; X64: retq 85} 86 87define void @TestFPToSIF128_I64() { 88entry: 89 %0 = load fp128, fp128* @vf128, align 16 90 %conv = fptosi fp128 %0 to i32 91 %conv1 = sext i32 %conv to i64 92 store i64 %conv1, i64* @vi64, align 8 93 ret void 94; X32-LABEL: TestFPToSIF128_I64: 95; X32: calll __fixtfsi 96; X32: retl 97; 98; X64-LABEL: TestFPToSIF128_I64: 99; X64: movaps vf128(%rip), %xmm0 100; X64-NEXT: callq __fixtfsi 101; X64-NEXT: cltq 102; X64-NEXT: movq %rax, vi64(%rip) 103; X64: retq 104} 105 106define void @TestFPToUIF128_U64() { 107entry: 108 %0 = load fp128, fp128* @vf128, align 16 109 %conv = fptoui fp128 %0 to i32 110 %conv1 = zext i32 %conv to i64 111 store i64 %conv1, i64* @vu64, align 8 112 ret void 113; X32-LABEL: TestFPToUIF128_U64: 114; X32: calll __fixunstfsi 115; X32: retl 116; 117; X64-LABEL: TestFPToUIF128_U64: 118; X64: movaps vf128(%rip), %xmm0 119; X64-NEXT: callq __fixunstfsi 120; X64-NEXT: movl %eax, %eax 121; X64-NEXT: movq %rax, vu64(%rip) 122; X64: retq 123} 124 125define void @TestFPTruncF128_F32() { 126entry: 127 %0 = load fp128, fp128* @vf128, align 16 128 %conv = fptrunc fp128 %0 to float 129 store float %conv, float* @vf32, align 4 130 ret void 131; X32-LABEL: TestFPTruncF128_F32: 132; X32: calll __trunctfsf2 133; X32: fstps vf32 134; X32: retl 135; 136; X64-LABEL: TestFPTruncF128_F32: 137; X64: movaps vf128(%rip), %xmm0 138; X64-NEXT: callq __trunctfsf2 139; X64-NEXT: movss %xmm0, vf32(%rip) 140; X64: retq 141} 142 143define void @TestFPTruncF128_F64() { 144entry: 145 %0 = load fp128, fp128* @vf128, align 16 146 %conv = fptrunc fp128 %0 to double 147 store double %conv, double* @vf64, align 8 148 ret void 149; X32-LABEL: TestFPTruncF128_F64: 150; X32: calll __trunctfdf2 151; X32: fstpl vf64 152; X32: retl 153; 154; X64-LABEL: TestFPTruncF128_F64: 155; X64: movapd vf128(%rip), %xmm0 156; X64-NEXT: callq __trunctfdf2 157; X64-NEXT: movsd %xmm0, vf64(%rip) 158; X64: retq 159} 160 161define void @TestSIToFPI32_F128() { 162entry: 163 %0 = load i32, i32* @vi32, align 4 164 %conv = sitofp i32 %0 to fp128 165 store fp128 %conv, fp128* @vf128, align 16 166 ret void 167; X32-LABEL: TestSIToFPI32_F128: 168; X32: calll __floatsitf 169; X32: retl 170; 171; X64-LABEL: TestSIToFPI32_F128: 172; X64: movl vi32(%rip), %edi 173; X64-NEXT: callq __floatsitf 174; X64-NEXT: movaps %xmm0, vf128(%rip) 175; X64: retq 176} 177 178define void @TestUIToFPU32_F128() #2 { 179entry: 180 %0 = load i32, i32* @vu32, align 4 181 %conv = uitofp i32 %0 to fp128 182 store fp128 %conv, fp128* @vf128, align 16 183 ret void 184; X32-LABEL: TestUIToFPU32_F128: 185; X32: calll __floatunsitf 186; X32: retl 187; 188; X64-LABEL: TestUIToFPU32_F128: 189; X64: movl vu32(%rip), %edi 190; X64-NEXT: callq __floatunsitf 191; X64-NEXT: movaps %xmm0, vf128(%rip) 192; X64: retq 193} 194 195define void @TestSIToFPI64_F128(){ 196entry: 197 %0 = load i64, i64* @vi64, align 8 198 %conv = sitofp i64 %0 to fp128 199 store fp128 %conv, fp128* @vf128, align 16 200 ret void 201; X32-LABEL: TestSIToFPI64_F128: 202; X32: calll __floatditf 203; X32: retl 204; 205; X64-LABEL: TestSIToFPI64_F128: 206; X64: movq vi64(%rip), %rdi 207; X64-NEXT: callq __floatditf 208; X64-NEXT: movaps %xmm0, vf128(%rip) 209; X64: retq 210} 211 212define void @TestUIToFPU64_F128() #2 { 213entry: 214 %0 = load i64, i64* @vu64, align 8 215 %conv = uitofp i64 %0 to fp128 216 store fp128 %conv, fp128* @vf128, align 16 217 ret void 218; X32-LABEL: TestUIToFPU64_F128: 219; X32: calll __floatunditf 220; X32: retl 221; 222; X64-LABEL: TestUIToFPU64_F128: 223; X64: movq vu64(%rip), %rdi 224; X64-NEXT: callq __floatunditf 225; X64-NEXT: movaps %xmm0, vf128(%rip) 226; X64: retq 227} 228 229define i32 @TestConst128(fp128 %v) { 230entry: 231 %cmp = fcmp ogt fp128 %v, 0xL00000000000000003FFF000000000000 232 %conv = zext i1 %cmp to i32 233 ret i32 %conv 234; X32-LABEL: TestConst128: 235; X32: calll __gttf2 236; X32: retl 237; 238; X64-LABEL: TestConst128: 239; X64: movaps {{.*}}, %xmm1 240; X64-NEXT: callq __gttf2 241; X64-NEXT: xorl 242; X64-NEXT: test 243; X64: retq 244} 245 246; C code: 247; struct TestBits_ieee_ext { 248; unsigned v1; 249; unsigned v2; 250; }; 251; union TestBits_LDU { 252; FP128 ld; 253; struct TestBits_ieee_ext bits; 254; }; 255; int TestBits128(FP128 ld) { 256; union TestBits_LDU u; 257; u.ld = ld * ld; 258; return ((u.bits.v1 | u.bits.v2) == 0); 259; } 260define i32 @TestBits128(fp128 %ld) { 261entry: 262 %mul = fmul fp128 %ld, %ld 263 %0 = bitcast fp128 %mul to i128 264 %shift = lshr i128 %0, 32 265 %or5 = or i128 %shift, %0 266 %or = trunc i128 %or5 to i32 267 %cmp = icmp eq i32 %or, 0 268 %conv = zext i1 %cmp to i32 269 ret i32 %conv 270; X32-LABEL: TestBits128: 271; X32: calll __multf3 272; X32: retl 273; 274; X64-LABEL: TestBits128: 275; X64: movaps %xmm0, %xmm1 276; X64-NEXT: callq __multf3 277; X64-NEXT: movaps %xmm0, (%rsp) 278; X64-NEXT: movq (%rsp), 279; X64-NEXT: movq % 280; X64-NEXT: shrq $32, 281; X64: xorl %eax, %eax 282; X64-NEXT: orl 283; X64-NEXT: sete %al 284; X64: retq 285; 286; If TestBits128 fails due to any llvm or clang change, 287; please make sure the original simplified C code will 288; be compiled into correct IL and assembly code, not 289; just this TestBits128 test case. Better yet, try to 290; test the whole libm and its test cases. 291} 292 293; C code: (compiled with -target x86_64-linux-android) 294; typedef long double __float128; 295; __float128 TestPair128(unsigned long a, unsigned long b) { 296; unsigned __int128 n; 297; unsigned __int128 v1 = ((unsigned __int128)a << 64); 298; unsigned __int128 v2 = (unsigned __int128)b; 299; n = (v1 | v2) + 3; 300; return *(__float128*)&n; 301; } 302define fp128 @TestPair128(i64 %a, i64 %b) { 303entry: 304 %conv = zext i64 %a to i128 305 %shl = shl nuw i128 %conv, 64 306 %conv1 = zext i64 %b to i128 307 %or = or i128 %shl, %conv1 308 %add = add i128 %or, 3 309 %0 = bitcast i128 %add to fp128 310 ret fp128 %0 311; X32-LABEL: TestPair128: 312; X32: addl 313; X32-NEXT: adcl 314; X32-NEXT: adcl 315; X32-NEXT: adcl 316; X32: retl 317; 318; X64-LABEL: TestPair128: 319; X64: addq $3, %rsi 320; X64: movq %rsi, -24(%rsp) 321; X64: movq %rdi, -16(%rsp) 322; X64: movaps -24(%rsp), %xmm0 323; X64-NEXT: retq 324} 325 326define fp128 @TestTruncCopysign(fp128 %x, i32 %n) { 327entry: 328 %cmp = icmp sgt i32 %n, 50000 329 br i1 %cmp, label %if.then, label %cleanup 330 331if.then: ; preds = %entry 332 %conv = fptrunc fp128 %x to double 333 %call = tail call double @copysign(double 0x7FF0000000000000, double %conv) #2 334 %conv1 = fpext double %call to fp128 335 br label %cleanup 336 337cleanup: ; preds = %entry, %if.then 338 %retval.0 = phi fp128 [ %conv1, %if.then ], [ %x, %entry ] 339 ret fp128 %retval.0 340; X32-LABEL: TestTruncCopysign: 341; X32: calll __trunctfdf2 342; X32: fstpl 343; X32: flds 344; X32: flds 345; X32: fstp 346; X32: fldz 347; X32: fstp 348; X32: fstpl 349; X32: calll __extenddftf2 350; X32: retl 351; 352; X64-LABEL: TestTruncCopysign: 353; X64: callq __trunctfdf2 354; X64-NEXT: andpd {{.*}}, %xmm0 355; X64-NEXT: orpd {{.*}}, %xmm0 356; X64-NEXT: callq __extenddftf2 357; X64: retq 358} 359 360declare double @copysign(double, double) #1 361 362attributes #2 = { nounwind readnone } 363