Kyoungju Sim via llvm-dev
2016-Dec-12 13:46 UTC
[llvm-dev] Problem about 128bit floating-point operations in x86 machines
Hello, I'm making a compiler utilizing LLVM. Because I want the compiler to support 128bit floating-point operations, I added the code for 128bit floating-point operations and tested these operations in i686, x86_64, SPARCv8 and SPARCv9 machines. Generated codes by LLVM operated normally when using x86_64, SPARCv8 and SPARCv9 machines, but generated codes in a x86 machine produce wrong result. Because Clang supports __float128 type, I also tried to test using Clang 3.9 version. However, I could not get the correct result of 128bit floating-point operations using Clang. For example, C source code that included operations of 128bit floating-point is as follows: #include <stdio.h> #include <quadmath.h> int main() { __float128 a = 3.14; char buf[128]; quadmath_snprintf(buf, sizeof(buf), "%QE", -a); printf("%s\n", buf); quadmath_snprintf(buf, sizeof(buf), "%QE", a * 5.0); printf("%s\n", buf); quadmath_snprintf(buf, sizeof(buf), "%QE", a + 5.0); printf("%s\n", buf); return 0; } After compilation, the correct result of the compiled program must be -3.140000E+00 1.570000E+01 8.140000E+00. However, I could not get the right result from the program that compiled by Clang 3.9. (the result of the program that compiled by gcc 4.8.4 was correct) I think that IR codes generated LLVM for 128bit floating-point operations are not wrong, but assembly generated from LLVM IR codes produced wrong result. (: Because the compiled program produced the wrong result only in x86 machine) How can I get the right result of 128bit floating-point operations using LLVM? [ Environments ] - CPU: Intel(R) core(TM) i7-6700 - OS: Ubuntu 14.04 (32bit) - LLVM target triple: i686-pc-linux-gnu - LLVM version: LLVM 3.8 / LLVM 3.9 - Clang version: 3.9 (※ use gcc 4.8.4 for building LLVM & Clang) Thank you. :) Sincerely, Stella -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20161212/f64dd362/attachment.html>
Dan Liew via llvm-dev
2016-Dec-13 00:05 UTC
[llvm-dev] Problem about 128bit floating-point operations in x86 machines
Hi Kyoungju, On 12 December 2016 at 13:46, Kyoungju Sim via llvm-dev <llvm-dev at lists.llvm.org> wrote:> Hello, > > I'm making a compiler utilizing LLVM. > Because I want the compiler to support 128bit floating-point operations, I > added the code for 128bit floating-point operations and tested these > operations in i686, x86_64, SPARCv8 and SPARCv9 machines. > Generated codes by LLVM operated normally when using x86_64, SPARCv8 and > SPARCv9 machines, but generated codes in a x86 machine produce wrong result. > > Because Clang supports __float128 type, I also tried to test using Clang 3.9 > version. > However, I could not get the correct result of 128bit floating-point > operations using Clang. > > For example, C source code that included operations of 128bit floating-point > is as follows: > > #include <stdio.h> > #include <quadmath.h> > > int main() { > __float128 a = 3.14; > char buf[128]; > > quadmath_snprintf(buf, sizeof(buf), "%QE", -a); > printf("%s\n", buf); > quadmath_snprintf(buf, sizeof(buf), "%QE", a * 5.0); > printf("%s\n", buf); > quadmath_snprintf(buf, sizeof(buf), "%QE", a + 5.0); > printf("%s\n", buf); > > return 0; > } > > > After compilation, the correct result of the compiled program must be > > -3.140000E+00 > 1.570000E+01 > 8.140000E+00. > > > However, I could not get the right result from the program that compiled by > Clang 3.9. > (the result of the program that compiled by gcc 4.8.4 was correct) > > I think that IR codes generated LLVM for 128bit floating-point operations > are not wrong, but assembly generated from LLVM IR codes produced wrong > result. > (: Because the compiled program produced the wrong result only in x86 > machine)I can't reproduce this on x86_64. I have Clang 3.9.0 packaged by my distribution (Arch Linux) and apart from me having to tell Clang to look in the right place for the header file I get the output you show above ``` $ clang --version clang version 3.9.0 (tags/RELEASE_390/final) Target: x86_64-unknown-linux-gnu Thread model: posix InstalledDir: /usr/bin $ /usr/bin/clang -O3 -lquadmath -I /usr/lib/gcc/x86_64-pc-linux-gnu/6.2.1/include float128.c && ./a.out -3.140000E+00 1.570000E+01 8.140000E+00 ```> How can I get the right result of 128bit floating-point operations using > LLVM? > > > [ Environments ] > - CPU: Intel(R) core(TM) i7-6700 > - OS: Ubuntu 14.04 (32bit) > - LLVM target triple: i686-pc-linux-gnu > - LLVM version: LLVM 3.8 / LLVM 3.9 > - Clang version: 3.9 > (※ use gcc 4.8.4 for building LLVM & Clang)Huh why are you using a 32-bit version of Ubuntu. You clearly have a 64-bit cpu but your target tripple is "i686...". If I do ``` /usr/bin/clang -O3 -m32 -lquadmath -I /usr/lib/gcc/x86_64-pc-linux-gnu/6.2.1/include float128.c && ./a.out 6.399878E-4935 6.374229E-4935 6.374228E-4935 ``` Which is very very wrong. Non optimized output is diferent too ``` /usr/bin/clang -O0 -m32 -lquadmath -I /usr/lib/gcc/x86_64-pc-linux-gnu/6.2.1/include float128.c && ./a.out -8.378461E+4270 0.000000E+00 1.194574E-4942 ``` I took the liberty of modifying your program slightly to print out the bits (I don't trust printf and the like at all). ``` #include <inttypes.h> #include <quadmath.h> #include <stdint.h> #include <stdio.h> #include <string.h> void dump_float_128(__float128 f, const char *name) { uint64_t data[] = {0, 0}; memcpy(&data, &f, sizeof(f)); // Assuming little-endian printf("%s value: 0x%.16" PRIx64 "%.16" PRIx64 "\n", name, data[1], data[0]); } int main() { __float128 a = 3.14; char buf[128]; dump_float_128(a, "a"); __float128 negA = -a; quadmath_snprintf(buf, sizeof(buf), "%QE", negA); printf("negA: %s\n", buf); dump_float_128(negA, "negA"); __float128 aTimesFive = a * 5.0; quadmath_snprintf(buf, sizeof(buf), "%QE", aTimesFive); printf("aTimeFive: %s\n", buf); dump_float_128(aTimesFive, "aTimesFive"); __float128 aAddFive = a + 5.0; quadmath_snprintf(buf, sizeof(buf), "%QE", aAddFive); printf("aAddFive: %s\n", buf); dump_float_128(aAddFive, "aAddFive"); return 0; } ``` ``` $ /usr/bin/clang -O0 -m32 -lquadmath -I /usr/lib/gcc/x86_64-pc-linux-gnu/6.2.1/include float128.c && ./a.out a value: 0x400091eb851eb851f000000000000000 negA: -6.462522E-4538 negA value: 0x763d4e2ef743adc408048ed0400091eb aTimeFive: 3.645761E-4937 aTimesFive value: 0xb5ed4e31f1312a6d4a36bcc8044d75ae aAddFive: 3.220963E-4945 aAddFive value: 0x0000001af743adc408048ed08001d1eb $ /usr/bin/clang -O0 -m64 -lquadmath -I /usr/lib/gcc/x86_64-pc-linux-gnu/6.2.1/include float128.c && ./a.out a value: 0x400091eb851eb851f000000000000000 negA: -3.140000E+00 negA value: 0xc00091eb851eb851f000000000000000 aTimeFive: 1.570000E+01 aTimesFive value: 0x4002f666666666666c00000000000000 aAddFive: 8.140000E+00 aAddFive value: 0x4002047ae147ae147c00000000000000 ``` The bit representation looks wrong most of the time except the initial constant (although it gets printed wrong). The LLVM IR looks sane to me so I'm guessing this is a codegen bug for x86 32-bit. Dan.