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 15 define void @TestFPExtF32_F128() { 16 entry: 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 34 define void @TestFPExtF64_F128() { 35 entry: 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 53 define void @TestFPToSIF128_I32() { 54 entry: 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 70 define void @TestFPToUIF128_U32() { 71 entry: 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 87 define void @TestFPToSIF128_I64() { 88 entry: 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 106 define void @TestFPToUIF128_U64() { 107 entry: 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 125 define void @TestFPTruncF128_F32() { 126 entry: 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 143 define void @TestFPTruncF128_F64() { 144 entry: 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 161 define void @TestSIToFPI32_F128() { 162 entry: 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 178 define void @TestUIToFPU32_F128() #2 { 179 entry: 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 195 define void @TestSIToFPI64_F128(){ 196 entry: 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 212 define void @TestUIToFPU64_F128() #2 { 213 entry: 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 229 define i32 @TestConst128(fp128 %v) { 230 entry: 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 ; } 260 define i32 @TestBits128(fp128 %ld) { 261 entry: 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 ; } 302 define fp128 @TestPair128(i64 %a, i64 %b) { 303 entry: 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 326 define fp128 @TestTruncCopysign(fp128 %x, i32 %n) { 327 entry: 328 %cmp = icmp sgt i32 %n, 50000 329 br i1 %cmp, label %if.then, label %cleanup 330 331 if.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 337 cleanup: ; 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 360 declare double @copysign(double, double) #1 361 362 attributes #2 = { nounwind readnone } 363