This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] PPC e500 complex double fix and rtlanal subreg offset (PR 24036)
- From: David Edelsohn <dje at watson dot ibm dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Mon, 17 Jul 2006 12:19:54 -0400
- Subject: [PATCH] PPC e500 complex double fix and rtlanal subreg offset (PR 24036)
: ADDPATCH middle-end :
Use of complex double on e500 double targets currently causes an
ICE in subreg_offset_representable_p() because rs6000_hard_regno_nregs
does not return self-consistent results for all float modes:
if (TARGET_E500_DOUBLE && mode == DFmode)
return 1;
DFmode is 1 reg, but the default computation for DCmode returns 4 regs.
The e500 uses GPRs to hold both integer and floating point values.
The variant that supports double precision can hold a complete double
precision floating point value in a single register, but only a single
word integer, e.g., the integer register does not span the entire floating
register.
This configuration causes problems for GCC later in
subreg_offset_representable_p(), which adds computations with
int_mode_for_mode() to handle "holes" such as XFmode spanning three 32-bit
FPRs but 128 bits in memory.
The e500 double falls into this same case because nregs_xmode_unit
is 1 and nregs_xmode_unit_int is 2, for xmode of DCmode. This causes
nregs_xmode to be computed as
nregs_xmode = nregs_xmode_unit_int * GET_MODE_NUNITS (xmode);
which is 4 and not 2 as would be calculated from
nregs_xmode = hard_regno_nregs[xregno][xmode];
nregs_ymode, for ymode of DFmode, is computed directly from
hard_regno_nregs:
nregs_ymode = hard_regno_nregs[xregno][ymode];
which is 1. For the e500, this causes an assertion to fail:
mode_multiple = GET_MODE_SIZE (xmode) / GET_MODE_SIZE (ymode);
nregs_multiple = nregs_xmode / nregs_ymode;
gcc_assert ((mode_multiple % nregs_multiple) == 0);
but the computation leading to the assertion currently does not make sense
because nregs_xmode and nregs_ymode are not necesasrily in the same
"units". Dimensional analysis demonstrates that one cannot divide those
two numbers and get a useful result because nregs_xmode can be in "int"
units and nregs_ymode in "float" units.
My proposed solution is to compute nregs_ymode using the same
algorithm as nregs_xmode. If nregs_xmode is computed using the xmode unit
int, then nregs_ymode is computed with the same units.
Comments?
Bootstrapped and regression tested on powerpc-ibm-aix5.2.0.0.
Thanks, David
PR target/24036
* rtlanal.c (subreg_regno_offset): If nregs_xmode uses
xmode_unit_int, compute nregs_ymode similarly.
(subreg_offset_representable_p): Same.
* config/rs6000/rs6000.c (rs6000_hard_regno_nregs): Use
UNITS_PER_FP_WORD for e500 GPRs containing doubles.
Index: rtlanal.c
===================================================================
--- rtlanal.c (revision 115491)
+++ rtlanal.c (working copy)
@@ -2960,8 +2960,11 @@
nregs_xmode = nregs_xmode_unit_int * GET_MODE_NUNITS (xmode);
else
nregs_xmode = hard_regno_nregs[xregno][xmode];
-
- nregs_ymode = hard_regno_nregs[xregno][ymode];
+
+ if (nregs_xmode_unit_int != hard_regno_nregs[xregno][xmode_unit])
+ nregs_ymode = nregs_xmode_unit_int * GET_MODE_NUNITS (ymode);
+ else
+ nregs_ymode = hard_regno_nregs[xregno][ymode];
/* If this is a big endian paradoxical subreg, which uses more actual
hard registers than the original register, we must return a negative
@@ -3049,7 +3052,10 @@
else
nregs_xmode = hard_regno_nregs[xregno][xmode];
- nregs_ymode = hard_regno_nregs[xregno][ymode];
+ if (nregs_xmode_unit != nregs_xmode_unit_int)
+ nregs_ymode = nregs_xmode_unit_int * GET_MODE_NUNITS (ymode);
+ else
+ nregs_ymode = hard_regno_nregs[xregno][ymode];
/* Paradoxical subregs are otherwise valid. */
if (offset == 0
Index: config/rs6000/rs6000.c
===================================================================
--- config/rs6000/rs6000.c (revision 115491)
+++ config/rs6000/rs6000.c (working copy)
@@ -3638,15 +3638,15 @@
if (FP_REGNO_P (regno))
return (GET_MODE_SIZE (mode) + UNITS_PER_FP_WORD - 1) / UNITS_PER_FP_WORD;
- if (TARGET_E500_DOUBLE && mode == DFmode)
- return 1;
-
if (SPE_SIMD_REGNO_P (regno) && TARGET_SPE && SPE_VECTOR_MODE (mode))
return (GET_MODE_SIZE (mode) + UNITS_PER_SPE_WORD - 1) / UNITS_PER_SPE_WORD;
if (ALTIVEC_REGNO_P (regno))
return
(GET_MODE_SIZE (mode) + UNITS_PER_ALTIVEC_WORD - 1) / UNITS_PER_ALTIVEC_WORD;
+
+ if (TARGET_E500_DOUBLE && FLOAT_MODE_P (mode))
+ return (GET_MODE_SIZE (mode) + UNITS_PER_FP_WORD - 1) / UNITS_PER_FP_WORD;
return (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
}