Fixing GCC's code generation for the MaverickCrunch FPU

Martin Guy <martinwguy@gmail.com> 8 September 2009
Last updated: 2 April 2011


Contents Update 8 September 2009
We have "no known bugs" again. Yay.

Update 18 June 2013
The new release of Debian, "wheezy", has a minimum gcc version of 4.4. The existing gcc-4.2 and 4.3 packages can still be installed and work on it but to run gcc-4.3-crunch you also have to install the libgmp3 package from the previous release, for example:

wget http://ftp.debian.org/debian/pool/main/g/gmp/libgmp3c2_4.3.2+dfsg-1_armel.deb
sudo dpkg -i libgmp3c2_4.3.2+dfsg-1_armel.deb
A blood-and-guts image with title Maverick 9312, found on a Gears of War gaming site
Image found on the "Gears of War" site during a web search for "Maverick 9312"

Preamble

I've been working on GCC-4 to make it generate working code for the Cirrus Logic MaverickCrunch FPU, as found in their ARM-based EP9302, EP9307, EP9312 and EP9315 chips, making floating point-intensive code between 2.5 and 4 times faster.

This follows on from Hasjim Williams' earlier work with gcc-4.1.2 and 4.2.0, a bundle of his more recent ideas and more hacks from me.

If you want to understand the patches themselves, there is an article about the MaverickCrunch FPU and GCC's problems with it on the Debian wiki and I have added commentary at the top of the individual patch files for gcc-4.3.4 or for gcc-4.2.4.

Discussion about this (and other issues with these chips) happens on the linux-cirrus mailing list.

What it does

The 20090908 version

Correctness tests

The compiler passes the following floating point-intensive test suites:

Speed tests

To compare execution speed of crunch-intensive tasks:

The results, on a 200MHz Cirrus Logic EP9307 revision E1 under Debian "armel":

Compiler/options FFTW
mflops
LAME
seconds
libgsm(*)
seconds
openssl
seconds
Soft-float
gcc-4.3 -O2 -ffast-math (softfloat) 3.59365 23.5
gcc-4.4 -O2 -ffast-math (softfloat) 0.51u
Hard-float
gcc-4.2-crunch -mcpu=ep9312 -mfpu=maverick -mfloat-abi=softfp -O2 -ffast-math 6.13138 5.72
gcc-4.3-crunch -mcpu=ep9312 -mfpu=maverick -mfloat-abi=softfp -O2 -ffast-math -mieee 3.83276 -
gcc-4.3-crunch -mcpu=ep9312 -mfpu=maverick -mfloat-abi=softfp -O2 -ffast-math 5.94145 5.72
gcc-4.4-crunch -mcpu=ep9312 -mfpu=maverick -mfloat-abi=softfp -O2 -ffast-math 7.65141(+) 6.52(+) 0.48u

In other words, using the full Maverick instruction set, LAME is 2.5 times faster than with softfloat, and when just using the -mieee subset, it runs 25% faster or about half the speed of the full set, and gcc-4.2 produces significantly faster code than gcc-4.3 or gcc-4.4 except for FFTW, in which gcc-4.4 excels.

(*) Although crunch libgsm is 4 times faster than softfloat, libgsm also has a fixed-point encoder, selected with MULHACK='', which is faster still (the same is true of the speex encoder).
(+) These tests were run on a Sim.One board with a 16-bit RAM data path instead of a 32-bit data path, which slows down all RAM accesses for a net slowdown of about 10%.

Download

The installable binary tarballs, Debian packages and patches are kindly hosted by SimpleMachines who also funded me to do some of this work.

There is also a repository of prebuilt crunch-accelerated Debian packages for the "armel lenny" release. See simplemachines.it/debian

Using it

To get MaverickCrunch instructions you always have to use:
  gcc-4.3-crunch -mcpu=ep9312 -mfpu=maverick -mfloat-abi=softfp
Other relevant options are:
-fno-signed-zeros
(gcc-4.3 only) If you do need to handle Not-a-Number values and infinities in calculations but do not care about the difference between 0 and -0, you can use this flag to enable the Maverick 'negate' instructions for a little extra speed.
-ffinite-math-only
This tells the compiler that NaNs and infinities do not need to be handled; this allows further optimization.
-funsafe-math-optimizations
This enables more optimizations that may give results not in accordance with the strict IEEE-754 math standard. Among others, It enables -fno-signed-zeros and in GCC-4.2 is the least invasive way to enable the Crunch negate instructions.
-ffast-math
This is the most aggressive math optimization flag, enabling all of the above and more.
-mieee
Most of Crunch's instructions take denormal values as zero; this flag only enables the ones that work at full IEEE precision (just multiply and compare).
-mcirrus-di
The FPU also has 64-bit integer instructions but they appear to be buggy. This flag enables them (load, store, add, subtract, convert to/from 32 bit and logical shifts by up to 31 places). Caveat emptor.
When running configure scripts, I normally use:
  ./configure CC=gcc-4.3-crunch CFLAGS="-mcpu=ep9312 -mfpu=maverick -mfloat-abi=softfp -ffast-math -O2"
However it's usually less trouble to make a directory of wrapper scripts replacing all of GCC's command names with the crunch version:
mkdir ~/crunch
cat > ~/crunch/gcc << EOF
#! /bin/sh

exec gcc-4.3-crunch -mcpu=ep9312 -mfpu=maverick -mfloat-abi=softfp -fno-signed-zeros "$@"
EOF
chmod 755 ~/crunch/gcc
ln -s gcc ~/crunch/cc
ln -s gcc ~/crunch/gcc-4.3
ln -s gcc ~/crunch/arm-linux-gnueabi-gcc
and fool the build system into using them
PATH=~/crunch:$PATH ./configure
PATH=~/crunch:$PATH make
PATH=~/crunch:$PATH make install
or, to build accelerated Debian packages:
apt-get source foobar
sudo apt-get build-dep foobar
cd foobar-*
PATH=~/crunch:$PATH dpkg-buildpackage -rfakeroot -B
cd ..
dpkg -i foobar*.deb

Building it from source

Resource requirements

GCC keeps on growing. One of gcc-4.3's C source files, automatically generated during the build, insn-recog.c, is now over 4 MB in size and gcc-4.3 requires 219MB of virtual memory to compile it with normal optimization.

Memory: If you have less than 160MB of physical RAM plus 64MB swap, you will need to stop the compilation, compile that one file without optimisation by saying make CFLAGS=-g and then interrupt it and carry on as usual when that one file has been done.

Disk space: The full sources unpack to 500MB (360MB for gcc-4.2) and a further 200MB (140MB for gcc-4.2) are needed to build the C compiler. If you have less space, you can fetch a "gcc-core" source tarball instead, which only contains the C compiler and unpacks to about 200MB, for a total of 400MB when built.

Build procedure

I go:
    wget ftp://sourceware.org/pub/gcc/releases/gcc-4.3.4/gcc-4.3.4.tar.bz2
    tar xjf gcc-4.3.4.tar.bz2
    cd gcc-4.3.4

    for a in `cat ../gcc-4.3.4-patches/series`
    do
	patch -p1 < ../gcc-4.3.4-patches/$a
    done

    cd ..
    mkdir gcc-4.3.4-build
    cd gcc-4.3.4-build

    # The same basic configuration as Debian
    ../gcc-4.3.6/configure \
	CONFIG_SHELL=/bin/sh \
	--enable-languages=c --prefix=/usr/local \
	--enable-shared --with-system-zlib --without-included-gettext \
	--enable-threads=posix --enable-nls --program-suffix=-4.3-crunch \
	--enable-clocale=gnu --enable-mpfr --disable-libssp \
	--disable-sjlj-exceptions --disable-bootstrap \
	--with-arch=armv4t armv4tl-crunch-linux-gnueabi
    make CFLAGS_FOR_TARGET="-mcpu=ep9312 -mfpu=maverick -mfloat-abi=softfp"
    ../s/install
    ../s/tarball gcc-4.3-crunch
The tarball script dumps a .tar.gz of the essential installed files and another of the source patchset in the ../packages directory.

There is also a test directory here with some program fragments that I used to probe hardware bug presence and characteristics.

Patches for other packages

These are patches for GCC and work fine for all regular C software that I've tried. Some other software packages are known to need Crunch tweaks as well:

binutils

glibc

There are fixes to glibc and binutils to solve these and other issues in a message to the linux-cirrus mailing list, though I haven't seen whether this solves the sin() looping problem or not.

Thanks

Thanks to Hasjim Williams for the work that this is based on, to David Herring for prompting me to start working on this again and to simplemachines.it for funding the completion of these patches and for hosting the tarballs.
Martin Guy <martinwguy@gmail.com> Useful? Donate!