diff options
Diffstat (limited to 'gcc/config/arm/arm.c')
-rw-r--r-- | gcc/config/arm/arm.c | 30 |
1 files changed, 30 insertions, 0 deletions
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index c8c4301..bc802ad 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -793,6 +793,9 @@ static const struct attribute_spec arm_attribute_table[] = #undef TARGET_MODES_TIEABLE_P #define TARGET_MODES_TIEABLE_P arm_modes_tieable_p + +#undef TARGET_CAN_CHANGE_MODE_CLASS +#define TARGET_CAN_CHANGE_MODE_CLASS arm_can_change_mode_class /* Obstack for minipool constant handling. */ static struct obstack minipool_obstack; @@ -31243,6 +31246,33 @@ arm_coproc_ldc_stc_legitimate_address (rtx op) return false; } +/* Implement TARGET_CAN_CHANGE_MODE_CLASS. + + In VFPv1, VFP registers could only be accessed in the mode they were + set, so subregs would be invalid there. However, we don't 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. + + 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. */ + +static bool +arm_can_change_mode_class (machine_mode from, machine_mode to, + reg_class_t rclass) +{ + if (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, rclass)) + return false; + return true; +} + #if CHECKING_P namespace selftest { |