Consider following code:
#include <iostream>
int main() {
double a=54;
double b=10;
long double g=3;
std::cout << a/b << std::endl;
int i=g;
std::cout << a/b << std::endl;
return 0;
}
Compiled on x86 platform gives result as expected:
$ ./a.out
5.4
5.4
Compiled on PowerPc (ppc32) platform result is a bit different:
# ./a.out.ppc
5.4
5.39999
It seems that if 'long double' is casted to 'int' data type it effects on 'double' division precision.
I don't know why it is happening and how to fix it. Any help please?
Platform: Linux
Compiler:
$ /usr/bin/powerpc-e500v2-linux-gnu-g++ -v
Using built-in specs.
COLLECT_GCC=/usr/bin/powerpc-e500v2-linux-gnu-g++
COLLECT_LTO_WRAPPER=/usr/libexec/gcc/powerpc-e500v2-linux-gnu/9.4.0/lto-wrapper
Target: powerpc-e500v2-linux-gnu
Configured with: /var/tmp/portage/cross-powerpc-e500v2-linux-gnu/gcc-9.4.0/work/gcc-9.4.0/configure --host=x86_64-pc-linux-gnu --target=powerpc-e500v2-linux-gnu --build=x86_64-pc-linux-gnu --prefix=/usr --bindir=/usr/x86_64-pc-linux-gnu/powerpc-e500v2-linux-gnu/gcc-bin/9.4.0 --includedir=/usr/lib/gcc/powerpc-e500v2-linux-gnu/9.4.0/include --datadir=/usr/share/gcc-data/powerpc-e500v2-linux-gnu/9.4.0 --mandir=/usr/share/gcc-data/powerpc-e500v2-linux-gnu/9.4.0/man --infodir=/usr/share/gcc-data/powerpc-e500v2-linux-gnu/9.4.0/info --with-gxx-include-dir=/usr/lib/gcc/powerpc-e500v2-linux-gnu/9.4.0/include/g++-v9 --with-python-dir=/share/gcc-data/powerpc-e500v2-linux-gnu/9.4.0/python --enable-languages=c,c++,fortran --enable-obsolete --enable-secureplt --disable-werror --with-system-zlib --enable-nls --without-included-gettext --disable-libunwind-exceptions --enable-checking=release --with-bugurl=https://bugs.gentoo.org/ --with-pkgversion='Gentoo 9.4.0 p1' --disable-esp --enable-libstdcxx-time --enable-poison-system-directories --with-sysroot=/usr/powerpc-e500v2-linux-gnu --disable-bootstrap --enable-__cxa_atexit --enable-clocale=gnu --disable-multilib --disable-fixed-point --enable-e500-double --enable-targets=all --enable-libgomp --disable-libssp --disable-libada --disable-systemtap --disable-vtable-verify --disable-libvtv --enable-lto --without-isl --enable-default-pie --enable-default-ssp
Thread model: posix
gcc version 9.4.0 (Gentoo 9.4.0 p1)
Pure C version & assembly:
$ cat main2.cpp
#include <stdio.h>
int main() {
double a=54;
double b=10;
long double g=3;
printf("%f\n", a/b);
int i=g;
printf("%f\n", a/b);
return 0;
}
$ /usr/bin/powerpc-e500v2-linux-gnu-gcc -S main2.cpp -o a.out.asm
$ cat a.out.asm
.file "main2.cpp"
.machine ppc
.section ".text"
.section .rodata
.align 2
.LC6:
.string "%f\n"
.section ".got2","aw"
.align 2
.LCTOC1 = .+32768
.LC1:
.long .LC0
.LC3:
.long .LC2
.LC5:
.long .LC4
.LC7:
.long .LC6
.section ".text"
.align 2
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
stwu 1,-96(1)
.cfi_def_cfa_offset 96
mflr 0
stw 0,100(1)
stw 30,88(1)
stw 31,92(1)
.cfi_offset 65, 4
.cfi_offset 30, -8
.cfi_offset 31, -4
mr 31,1
.cfi_def_cfa_register 31
bcl 20,31,.L3
.L3:
mflr 30
addis 30,30,.LCTOC1-.L3@ha
addi 30,30,.LCTOC1-.L3@l
lwz 9,.LC1-.LCTOC1(30)
lfd 0,0(9)
stfd 0,48(31)
lwz 9,.LC3-.LCTOC1(30)
lfd 0,0(9)
stfd 0,56(31)
lwz 9,.LC5-.LCTOC1(30)
lfd 0,0(9)
lfd 1,8(9)
addi 9,31,64
stfd 0,0(9)
stfd 1,8(9)
lfd 12,48(31)
lfd 0,56(31)
fdiv 0,12,0
fmr 1,0
lwz 3,.LC7-.LCTOC1(30)
creqv 6,6,6
bl printf+32768@plt
addi 9,31,64
lfd 0,0(9)
lfd 1,8(9)
mffs 12
mtfsb1 31
mtfsb0 30
fadd 0,0,1
mtfsf 1,12
fctiwz 0,0
stfd 0,24(31)
lwz 9,28(31)
stw 9,44(31)
lfd 12,48(31)
lfd 0,56(31)
fdiv 0,12,0
fmr 1,0
lwz 3,.LC7-.LCTOC1(30)
creqv 6,6,6
bl printf+32768@plt
li 9,0
mr 3,9
addi 11,31,96
lwz 0,4(11)
mtlr 0
lwz 30,-8(11)
lwz 31,-4(11)
.cfi_def_cfa 11, 0
mr 1,11
.cfi_restore 31
.cfi_restore 30
.cfi_def_cfa_register 1
blr
.cfi_endproc
.LFE0:
.size main,.-main
.section .rodata
.align 3
.LC0:
.long 1078657024
.long 0
.align 3
.LC2:
.long 1076101120
.long 0
.align 4
.LC4:
.long 1074266112
.long 0
.long 0
.long 0
.ident "GCC: (Gentoo 9.4.0 p1) 9.4.0"
.gnu_attribute 4, 5
.section .note.GNU-stack,"",@progbits
Ok. I found the bug I think:
GCC assembly of 'long double' to 'int' casting:
7c: 39 3f 00 40 addi r9,r31,64
80: c8 09 00 00 lfd f0,0(r9)
84: c8 29 00 08 lfd f1,8(r9)
88: fd 80 04 8e mffs f12
8c: ff e0 00 4c mtfsb1 31
90: ff c0 00 8c mtfsb0 30
94: fc 00 08 2a fadd f0,f0,f1
98: fc 02 65 8e mtfsf 1,f12
9c: fc 00 00 1e fctiwz f0,f0
a0: d8 1f 00 18 stfd f0,24(r31)
a4: 81 3f 00 1c lwz r9,28(r31)
a8: 91 3f 00 2c stw r9,44(r31)
This is crucial:
mtfsb1 31
mtfsb0 30
It is manipulating on Rounding bits. These bits are not restored after 'cast' operation. IMO it is GCC bug but I cannot find any reference.