gcc 4.7.2 generates incorrect code for big-endian ARM VFP processors
when storing a local double to a packed memory location, as described
in bug 56351.
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=56351

A fix has been submitted to the trunk by Julian Brown:
http://gcc.gnu.org/git/?p=gcc.git;a=patch;h=4f0e4afcb2a9d345ed7e9c14233fb97d3a3e8d3c

This fix is not included in the latest 4.7 snapshot.  Can we please
include it in the 4.7 branch so that this serious codegen bug is fixed
in 4.7.3?

Unfortunately, it's a not a trivial backport, as it appears that
support for ARM FPA floating point has been removed from gcc since
4.7.  Below is my best attempt at a backport - it works for me, on a
big-endian VFP processor.  I'm not familiar with this code, though -
Julian, can you take a look and confirm whether I'm doing this right?

2013-02-15 Seth LaForge <set...@google.com>

        * config/arm/arm.h (CANNOT_CHANGE_MODE_CLASS): Avoid subreg'ing
        VFP D registers in big-endian mode.
        Backported from a change by Julian Brown <jul...@codesourcery.com>

diff -urp gcc-4.7.2/gcc/config/arm/arm.h gcc-4.7.2.new/gcc/config/arm/arm.h
--- gcc-4.7.2/gcc/config/arm/arm.h      2012-01-09 20:14:09.000000000 -0800
+++ gcc-4.7.2.new/gcc/config/arm/arm.h  2013-02-15 14:03:09.113531299 -0800
@@ -1123,11 +1123,18 @@ enum reg_class
 /* FPA registers can't do subreg as all values are reformatted to internal
    precision.  In VFPv1, VFP registers could only be accessed in the mode
    they were set, so subregs would be invalid there too.  However, we don't
-   support VFPv1 at the moment, and the restriction was lifted in VFPv2.  */
+   support VFPv1 at the moment, and the restriction was lifted in VFPv2.
+   In big-endian mode, modes greater than word size (i.e. DFmode) are stored in
+   VFP registers in little-endian order.  We can't describe that accurately to
+   GCC, so avoid taking subregs of such values.  */
 #define CANNOT_CHANGE_MODE_CLASS(FROM, TO, CLASS)              \
-  (GET_MODE_SIZE (FROM) != GET_MODE_SIZE (TO)                  \
-   ? reg_classes_intersect_p (FPA_REGS, (CLASS))               \
-   : 0)
+  (TARGET_VFP                                                  \
+  ? TARGET_BIG_END                                             \
+    && (GET_MODE_SIZE (FROM) > UNITS_PER_WORD                  \
+       || GET_MODE_SIZE (TO) > UNITS_PER_WORD)                 \
+    && reg_classes_intersect_p (VFP_REGS, (CLASS))             \
+  : GET_MODE_SIZE (FROM) != GET_MODE_SIZE (TO)                 \
+    && reg_classes_intersect_p (FPA_REGS, (CLASS)))

 /* The class value for index registers, and the one for base regs.  */
 #define INDEX_REG_CLASS  (TARGET_THUMB1 ? LO_REGS : GENERAL_REGS)

Reply via email to