Hi,
the attached Ada testcase triggers an ICE with -mbig-endian -mhard-float:
eric@polaris:~/build/gcc/arm-linux-gnueabi> gcc/xgcc -Bgcc -S p.adb -I
gcc/ada/rts -mbig-endian -mhard-float
+===========================GNAT BUG DETECTED==============================+
| 6.0.0 20151220 (experimental) [trunk revision 231856] (arm-linux-gnueabi)
GCC error:|
| in emit_move_multi_word, at expr.c:3452
because the middle-end is trying to copy an OImode value from VFP registers
and the back-end refuses it in big-endian mode:
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.
The only exception is going from a 128-bit to a 64-bit type. In that case
the data layout happens to be consistent for big-endian, so we explicitly
allow that case. */
#define CANNOT_CHANGE_MODE_CLASS(FROM, TO, CLASS) \
(TARGET_VFP && TARGET_BIG_END \
&& !(GET_MODE_SIZE (FROM) == 16 && GET_MODE_SIZE (TO) == 8) \
&& (GET_MODE_SIZE (FROM) > UNITS_PER_WORD \
|| GET_MODE_SIZE (TO) > UNITS_PER_WORD) \
&& reg_classes_intersect_p (VFP_REGS, (CLASS)))
That's very likely not reproducible in the C family of languages because the
code generates a RECORD_TYPE with OImode. The other thing to note is that
this works for TImode because, in this case, the back-end returns a PARALLEL
instead of a bare REG for the return value register.
Hence the attached patch, which extends this treatment to all integer modes
larger than TImode. Tested on arm-none-eabi, OK for the mainline?
2015-12-21 Eric Botcazou <ebotca...@adacore.com>
* config/arm/arm.c (aapcs_vfp_allocate_return_reg): Treat all integer
modes larger than TImode as TImode if NEON is not enabled.
--
Eric Botcazou
Index: config/arm/arm.c
===================================================================
--- config/arm/arm.c (revision 231856)
+++ config/arm/arm.c (working copy)
@@ -5846,7 +5846,10 @@ aapcs_vfp_allocate_return_reg (enum arm_
if (!use_vfp_abi (pcs_variant, false))
return NULL;
- if (mode == BLKmode || (mode == TImode && !TARGET_NEON))
+ if (mode == BLKmode
+ || (GET_MODE_CLASS (mode) == MODE_INT
+ && GET_MODE_SIZE (mode) >= GET_MODE_SIZE (TImode)
+ && !TARGET_NEON))
{
int count;
machine_mode ag_mode;