This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[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;
 }


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]