[Bug target/64074] New: PowerPC E500: Passing of double parameters not EABI compliant
florian.miedniak at web dot de
gcc-bugzilla@gcc.gnu.org
Tue Nov 25 20:27:00 GMT 2014
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64074
Bug ID: 64074
Summary: PowerPC E500: Passing of double parameters not EABI
compliant
Product: gcc
Version: 4.7.3
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: target
Assignee: unassigned at gcc dot gnu.org
Reporter: florian.miedniak at web dot de
Created attachment 34118
--> https://gcc.gnu.org/bugzilla/attachment.cgi?id=34118&action=edit
minimal testcase, preprocessed
For target PowerPC E500, GCC 4.7.3/4.8.2 fails to pass 64-bit parameters
(double) according to PowerPC EABI (lower and higher 32-bit parts in two GPRs).
Instead it emits a vector load opcode (evldd) and uses whole 64-bits of one GPR
to pass the double parameter (See attached minimal example).
void main(void)
{
double a = 5.0;
foo(a);
}
compiled with:
powerpc-elf-eabi-gcc.exe -mcpu=8540 -c test.c -o test.o -mdouble-float
-mfloat-gprs=double
produces:
0000004c <main>:
4c: 94 21 ff e0 stwu r1,-32(r1)
50: 7c 08 02 a6 mflr r0
54: 90 01 00 24 stw r0,36(r1)
58: 93 e1 00 1c stw r31,28(r1)
5c: 7c 3f 0b 78 mr r31,r1
60: 48 00 00 01 bl 60 <main+0x14>
64: 3d 20 00 00 lis r9,0
68: 39 29 00 00 addi r9,r9,0
6c: 11 29 03 01 evldd r9,0(r9)
70: 11 3f 0b 21 evstdd r9,8(r31)
74: 10 7f 0b 01 evldd r3,8(r31) <-------------
78: 48 00 00 01 bl 78 <main+0x2c>
7c: 39 7f 00 20 addi r11,r31,32
80: 80 0b 00 04 lwz r0,4(r11)
84: 7c 08 03 a6 mtlr r0
88: 83 eb ff fc lwz r31,-4(r11)
8c: 7d 61 5b 78 mr r1,r11
90: 4e 80 00 20 blr
This is not a problem as long as the callee is compiled with (same) GCC, too.
Things break, if you want to link with e.g. a library that is compiled with
another compiler that expects double to be passed in two regs (here: r3/r4).
I'm seeing this problem with:
- GCC 4.7.3 configured with: ../../../src/gcc-4.7.3/configure
--prefix=/c/toolchain/install/powerpc-elf-eabi --enable-languages=c,c++
--build=i686-pc-mingw32 --host=i686-pc-mingw32 --target=powerpc-elf-eabi
--disable-nls --enable-debug --with-gcc --with-gnu-as --with-gnu-ld
--with-stabs --disable-multilib --disable-shared --disable-win32-registry
--without-headers --with-newlib --disable-wchar_t --disable-libstdcxx-pch
--verbose
c:/powerpc-elf-eabi/bin/../libexec/gcc/powerpc-elf-eabi/4.7.3/cc1.exe
-fpreprocessed test.i -quiet -dumpbase test.c -mcpu=8540 -mdouble-float
-mfloat-gprs=double -auxbase-strip test.o -version -o test.s
GNU C (GCC) version 4.7.3 (powerpc-elf-eabi)
compiled by GNU C version 4.8.1, GMP version 4.3.2, MPFR version 2.4.2, MPC
version 0.8.1
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
c://powerpc-elf-eabi/bin/../lib/gcc/powerpc-elf-eabi/4.7.3/../../../../powerpc-elf-eabi/bin/as.exe
-v -me500 -many -o test.o test.s
GNU assembler version 2.23.2 (powerpc-elf-eabi) using BFD version (GNU
Binutils) 2.23.2
- GCC 4.8.2 configured with:
Configured with: ./configure
--prefix=/home/v/buildroot-2014.05/output/host/usr
--sysconfdir=/home/v/buildroot-2014.05/output/host/etc --enable-shared
--enable-static --target=powerpc-buildroot-linux-uclibcspe
--with-sysroot=/home/v/buildroot-2014.05/output/host/usr/powerpc-buildroot-linux-uclibcspe/sysroot
--disable-__cxa_atexit --with-gnu-ld --disable-libssp --disable-multilib
--with-gmp=/home/v/buildroot-2014.05/output/host/usr
--with-mpfr=/home/v/buildroot-2014.05/output/host/usr --disable-libquadmath
--disable-libsanitizer --enable-tls --disable-libmudflap --enable-threads
--with-mpc=/home/v/buildroot-2014.05/output/host/usr --disable-decimal-float
--with-tune=8548 --with-pkgversion='Buildroot 2014.05'
--with-bugurl=http://bugs.buildroot.net/ --enable-e500_double
--with-long-double-128 --enable-languages=c --disable-largefile
--with-build-time-tools=/home/v/buildroot-2014.05/output/host/usr/powerpc-buildroot-linux-uclibcspe/bin
--disable-libgomp
Searching the web and bugzilla, I found out that this topic (and e500 handling
in general) was addressed several times in the past. Though, it appeared to me,
that this should be working with GCC 4.7.x, shouldn't it?
I already had a look at GCC PowerPC sources and suspected that
rs6000_function_arg() and rs6000_spe_function_arg() are responsible for the
PowerPC specific calling convention behaviour. But I didn't succeed yet in
tracking down where exactly the (wrong?) decision to use one single 64-bit GPR
instead of two is made.
I found this code snippet in rs6000_function_arg() very promising:
else if (TARGET_SPE_ABI && TARGET_SPE
&& (SPE_VECTOR_MODE (mode)
|| (TARGET_E500_DOUBLE && (mode == DFmode
|| mode == DCmode
|| mode == TFmode
|| mode == TCmode)))
return rs6000_spe_function_arg (cum, mode, type);
But simply removing the second part of the OR expression ("TARGET_E500_DOUBLE
..."), unfortunately didn't have any effect.
Finally, here are the results of trying to get a workaround:
- Compiling with -mfloat-grps=single -> "fixes" this problem at the (for us
unaffordable) cost that GCC seems to disable double arithmetics to some extend
and is emitting a huge bunch of emulation intrinsics instead.
- Compiling with -mspe=no -mno-spe -mabi=no-spe in all possible combinations
-> No effect seen
- Replacing the function call by some inline assembly that fills the correct
registers and then calls the function -> Very short term solution for us, but
quite hackish and in fact doing the job the compiler should do for us!
More information about the Gcc-bugs
mailing list