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!