[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