On this patch, I add some infrastructure to say whether a given mode can go in
a general purpose register, floating point register, or altivec register, and
if it can, what kinds of addressing is legal for the mode.  In addition, I have
switched to using memset to setup the arrays indexed by mode.

I've rewritten this infrastructure since I submitted version 1 of the patch.
At present, this is only an infrastructure change, and the compiler generates
the same code underneath before and after the patch.

I switched rs6000_legitimate_address_p so that it uses this new infrastructure
to determine if a mode can do auto update as part of the address.  I found that
the code in rs6000_legitimate_address_p was not obvious what they were trying
to do.  I discovered for some 32-bit abis, the types DImode, DFmode, and
DDmode, would allow addresses with PRE_INC or PRE_DEC, but not PRE_MODIFY.  At
present, I am generating the same code, but in a later patch, we can allow
PRE_MODIFY for those types as well.  I noticed this when I was doing version 1
of the patches, and I was generating more auto update addressing forms than
before.

I have run bootstrap and make check with no regressions with these patches.  I
have also tested code for various 32/64-bit targets (power8, power7, power6x,
power6, power5, power 5+, power4, cell, 476 with/with floating point, g4, g5,
e5500, e6500, and xilinx full/lite/no floating point), and I found the code
generated is identical.

Can I install these patches in GCC 4.9 on the trunk?

2013-10-07  Michael Meissner  <meiss...@linux.vnet.ibm.com>

        * config/rs6000/rs6000.c (enum rs6000_reload_reg_type): Add new
        fields to the reg_addr array that describes the valid addressing
        mode for any register, general purpose registers, floating point
        registers, and Altivec registers.
        (FIRST_RELOAD_REG_CLASS): Likewise.
        (LAST_RELOAD_REG_CLASS): Likewise.
        (struct reload_reg_map_type): Likewise.
        (reload_reg_map_type): Likewise.
        (RELOAD_REG_VALID): Likewise.
        (RELOAD_REG_MULTIPLE): Likewise.
        (RELOAD_REG_INDEXED): Likewise.
        (RELOAD_REG_OFFSET): Likewise.
        (RELOAD_REG_PRE_INCDEC): Likewise.
        (RELOAD_REG_PRE_MODIFY): Likewise.
        (reg_addr): Likewise.
        (mode_supports_pre_incdec_p): New helper functions to say whether
        a given mode supports PRE_INC, PRE_DEC, and PRE_MODIFY.
        (mode_supports_pre_modify_p): Likewise.
        (rs6000_debug_vector_unit): Rearrange the -mdebug=reg output to
        print the valid address mode bits for each mode.
        (rs6000_debug_print_mode): Likewise.
        (rs6000_debug_reg_global): Likewise.
        (rs6000_setup_reg_addr_masks): New function to set up the address
        mask bits for each type.
        (rs6000_init_hard_regno_mode_ok): Use memset to clear arrays.
        Call rs6000_setup_reg_addr_masks to set up the address mask bits.
        (rs6000_legitimate_address_p): Use mode_supports_pre_incdec_p and
        mode_supports_pre_modify_p to determine if PRE_INC, PRE_DEC, and
        PRE_MODIFY are supported.
        (rs6000_print_options_internal): Tweak the debug output slightly.

-- 
Michael Meissner, IBM
IBM, M/S 2506R, 550 King Street, Littleton, MA 01460, USA
email: meiss...@linux.vnet.ibm.com, phone: +1 (978) 899-4797
Index: gcc/config/rs6000/rs6000.c
===================================================================
--- gcc/config/rs6000/rs6000.c  
(.../svn+ssh://meiss...@gcc.gnu.org/svn/gcc/trunk/gcc/config/rs6000)    
(revision 203166)
+++ gcc/config/rs6000/rs6000.c  (.../gcc/config/rs6000) (working copy)
@@ -313,6 +313,50 @@ static enum rs6000_reg_type reg_class_to
 
 #define IS_FP_VECT_REG_TYPE(RTYPE) IN_RANGE(RTYPE, VSX_REG_TYPE, FPR_REG_TYPE)
 
+
+/* Register classes we care about in secondary reload or go if legitimate
+   address.  We only need to worry about GPR, FPR, and Altivec registers here,
+   along an ANY field that is the OR of the 3 register classes.  */
+
+enum rs6000_reload_reg_type {
+  RELOAD_REG_GPR,                      /* General purpose registers.  */
+  RELOAD_REG_FPR,                      /* Traditional floating point regs.  */
+  RELOAD_REG_AV,                       /* Altivec registers.  */
+  RELOAD_REG_ANY,                      /* OR of GPR, FPR, Altivec masks.  */
+  N_RELOAD_REG
+};
+
+/* For setting up register classes, loop through the 3 register classes mapping
+   into real registers, and skip the ANY class, which is just an OR of the
+   bits.  */
+#define FIRST_RELOAD_REG_CLASS RELOAD_REG_GPR
+#define LAST_RELOAD_REG_CLASS  RELOAD_REG_AV
+
+/* Map reload register type to a register in the register class.  */
+struct reload_reg_map_type {
+  const char *name;                    /* Register class name.  */
+  int reg;                             /* Register in the register class.  */
+};
+
+static const struct reload_reg_map_type reload_reg_map[N_RELOAD_REG] = {
+  { "Gpr",     FIRST_GPR_REGNO },      /* RELOAD_REG_GPR.  */
+  { "Fpr",     FIRST_FPR_REGNO },      /* RELOAD_REG_FPR.  */
+  { "Av.",     FIRST_ALTIVEC_REGNO },  /* RELOAD_REG_AV.  */
+  { "Any",     -1 },                   /* RELOAD_REG_ANY.  */
+};
+
+/* Mask bits for each register class, indexed per mode.  Historically the
+   compiler has been more restrictive which types can do PRE_MODIFY instead of
+   PRE_INC and PRE_DEC, so keep track of sepaate bits for these two.  */
+typedef unsigned char addr_mask_type;
+
+#define RELOAD_REG_VALID       0x01    /* Mode valid in register..  */
+#define RELOAD_REG_MULTIPLE    0x02    /* Mode takes multiple registers.  */
+#define RELOAD_REG_INDEXED     0x04    /* Reg+reg addressing.  */
+#define RELOAD_REG_OFFSET      0x08    /* Reg+offset addressing. */
+#define RELOAD_REG_PRE_INCDEC  0x10    /* PRE_INC/PRE_DEC valid.  */
+#define RELOAD_REG_PRE_MODIFY  0x20    /* PRE_MODIFY valid.  */
+
 /* Register type masks based on the type, of valid addressing modes.  */
 struct rs6000_reg_addr {
   enum insn_code reload_load;          /* INSN to reload for loading. */
@@ -320,10 +364,27 @@ struct rs6000_reg_addr {
   enum insn_code reload_fpr_gpr;       /* INSN to move from FPR to GPR.  */
   enum insn_code reload_gpr_vsx;       /* INSN to move from GPR to VSX.  */
   enum insn_code reload_vsx_gpr;       /* INSN to move from VSX to GPR.  */
+  addr_mask_type addr_mask[(int)N_RELOAD_REG]; /* Valid address masks.  */
 };
 
 static struct rs6000_reg_addr reg_addr[NUM_MACHINE_MODES];
 
+/* Helper function to say whether a mode supports PRE_INC or PRE_DEC.  */
+static inline bool
+mode_supports_pre_incdec_p (enum machine_mode mode)
+{
+  return ((reg_addr[mode].addr_mask[RELOAD_REG_ANY] & RELOAD_REG_PRE_INCDEC)
+         != 0);
+}
+
+/* Helper function to say whether a mode supports PRE_MODIFY.  */
+static inline bool
+mode_supports_pre_modify_p (enum machine_mode mode)
+{
+  return ((reg_addr[mode].addr_mask[RELOAD_REG_ANY] & RELOAD_REG_PRE_MODIFY)
+         != 0);
+}
+
 
 /* Target cpu costs.  */
 
@@ -1777,6 +1838,63 @@ rs6000_debug_reg_print (int first_regno,
     }
 }
 
+static const char *
+rs6000_debug_vector_unit (enum rs6000_vector v)
+{
+  const char *ret;
+
+  switch (v)
+    {
+    case VECTOR_NONE:     ret = "none";      break;
+    case VECTOR_ALTIVEC:   ret = "altivec";   break;
+    case VECTOR_VSX:      ret = "vsx";       break;
+    case VECTOR_P8_VECTOR: ret = "p8_vector"; break;
+    case VECTOR_PAIRED:           ret = "paired";    break;
+    case VECTOR_SPE:      ret = "spe";       break;
+    case VECTOR_OTHER:    ret = "other";     break;
+    default:              ret = "unknown";   break;
+    }
+
+  return ret;
+}
+
+/* Print the address masks in a human readble fashion.  */
+DEBUG_FUNCTION void
+rs6000_debug_print_mode (ssize_t m)
+{
+  ssize_t rc;
+
+  fprintf (stderr, "Mode: %-5s", GET_MODE_NAME (m));
+  for (rc = 0; rc < N_RELOAD_REG; rc++)
+    {
+      addr_mask_type mask = reg_addr[m].addr_mask[rc];
+      fprintf (stderr,
+              "  %s: %c%c%c%c%c%c",
+              reload_reg_map[rc].name,
+              (mask & RELOAD_REG_VALID)      != 0 ? 'v' : ' ',
+              (mask & RELOAD_REG_MULTIPLE)   != 0 ? 'm' : ' ',
+              (mask & RELOAD_REG_INDEXED)    != 0 ? 'i' : ' ',
+              (mask & RELOAD_REG_OFFSET)     != 0 ? 'o' : ' ',
+              (mask & RELOAD_REG_PRE_INCDEC) != 0 ? '+' : ' ',
+              (mask & RELOAD_REG_PRE_MODIFY) != 0 ? '+' : ' ');
+    }
+
+  if (rs6000_vector_unit[m] != VECTOR_NONE
+      || rs6000_vector_mem[m] != VECTOR_NONE
+      || (reg_addr[m].reload_store != CODE_FOR_nothing)
+      || (reg_addr[m].reload_load != CODE_FOR_nothing))
+    {
+      fprintf (stderr,
+              "  Vector-arith=%-10s Vector-mem=%-10s Reload=%c%c",
+              rs6000_debug_vector_unit (rs6000_vector_unit[m]),
+              rs6000_debug_vector_unit (rs6000_vector_mem[m]),
+              (reg_addr[m].reload_store != CODE_FOR_nothing) ? 's' : '*',
+              (reg_addr[m].reload_load != CODE_FOR_nothing) ? 'l' : '*');
+    }
+
+  fputs ("\n", stderr);
+}
+
 #define DEBUG_FMT_ID "%-32s= "
 #define DEBUG_FMT_D   DEBUG_FMT_ID "%d\n"
 #define DEBUG_FMT_WX  DEBUG_FMT_ID "%#.12" HOST_WIDE_INT_PRINT "x: "
@@ -1800,17 +1918,6 @@ rs6000_debug_reg_global (void)
   const char *cmodel_str;
   struct cl_target_option cl_opts;
 
-  /* Map enum rs6000_vector to string.  */
-  static const char *rs6000_debug_vector_unit[] = {
-    "none",
-    "altivec",
-    "vsx",
-    "p8_vector",
-    "paired",
-    "spe",
-    "other"
-  };
-
   /* Modes we want tieable information on.  */
   static const enum machine_mode print_tieable_modes[] = {
     QImode,
@@ -1928,24 +2035,11 @@ rs6000_debug_reg_global (void)
           reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_wy]],
           reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_wz]]);
 
+  nl = "\n";
   for (m = 0; m < NUM_MACHINE_MODES; ++m)
-    if (rs6000_vector_unit[m] || rs6000_vector_mem[m]
-       || (reg_addr[m].reload_load != CODE_FOR_nothing)
-       || (reg_addr[m].reload_store != CODE_FOR_nothing))
-      {
-       nl = "\n";
-       fprintf (stderr,
-                "Vector mode: %-5s arithmetic: %-10s move: %-10s "
-                "reload-out: %c reload-in: %c\n",
-                GET_MODE_NAME (m),
-                rs6000_debug_vector_unit[ rs6000_vector_unit[m] ],
-                rs6000_debug_vector_unit[ rs6000_vector_mem[m] ],
-                (reg_addr[m].reload_store != CODE_FOR_nothing) ? 'y' : 'n',
-                (reg_addr[m].reload_load != CODE_FOR_nothing) ? 'y' : 'n');
-      }
+    rs6000_debug_print_mode (m);
 
-  if (nl)
-    fputs (nl, stderr);
+  fputs ("\n", stderr);
 
   for (m1 = 0; m1 < ARRAY_SIZE (print_tieable_modes); m1++)
     {
@@ -2181,6 +2275,101 @@ rs6000_debug_reg_global (void)
           (int)RS6000_BUILTIN_COUNT);
 }
 
+
+/* Update the addr mask bits in reg_addr to help secondary reload and go if
+   legitimate address support to figure out the appropriate addressing to
+   use.  */
+
+static void
+rs6000_setup_reg_addr_masks (void)
+{
+  ssize_t rc, reg, m, nregs;
+  addr_mask_type any_addr_mask, addr_mask;
+
+  for (m = 0; m < NUM_MACHINE_MODES; ++m)
+    {
+      /* SDmode is special in that we want to access it only via REG+REG
+        addressing on power7 and above, since we want to use the LFIWZX and
+        STFIWZX instructions to load it.  */
+      bool indexed_only_p = (m == SDmode && TARGET_NO_SDMODE_STACK);
+
+      any_addr_mask = 0;
+      for (rc = FIRST_RELOAD_REG_CLASS; rc <= LAST_RELOAD_REG_CLASS; rc++)
+       {
+         addr_mask = 0;
+         reg = reload_reg_map[rc].reg;
+
+         /* Can mode values go in the GPR/FPR/Altivec registers?  */
+         if (reg >= 0 && rs6000_hard_regno_mode_ok_p[m][reg])
+           {
+             nregs = rs6000_hard_regno_nregs[m][reg];
+             addr_mask |= RELOAD_REG_VALID;
+
+             /* Indicate if the mode takes more than 1 physical register.  If
+                it takes a single register, indicate it can do REG+REG
+                addressing.  */
+             if (nregs > 1 || m == BLKmode)
+               addr_mask |= RELOAD_REG_MULTIPLE;
+             else
+               addr_mask |= RELOAD_REG_INDEXED;
+
+             /* Figure out if we can do PRE_INC, PRE_DEC, or PRE_MODIFY
+                addressing.  Restrict addressing on SPE for 64-bit types
+                because of the SUBREG hackery used to address 64-bit floats in
+                '32-bit' GPRs.  To simplify secondary reload, don't allow
+                update forms on scalar floating point types that can go in the
+                upper registers.  */
+
+             if (TARGET_UPDATE
+                 && (rc == RELOAD_REG_GPR || rc == RELOAD_REG_FPR)
+                 && GET_MODE_SIZE (m) <= 8
+                 && !VECTOR_MODE_P (m)
+                 && !COMPLEX_MODE_P (m)
+                 && !indexed_only_p
+                 && !(TARGET_E500_DOUBLE && GET_MODE_SIZE (m) == 8)
+                 && !(m == DFmode && TARGET_UPPER_REGS_DF)
+                 && !(m == SFmode && TARGET_UPPER_REGS_SF))
+               {
+                 addr_mask |= RELOAD_REG_PRE_INCDEC;
+
+                 /* PRE_MODIFY is more restricted than PRE_INC/PRE_DEC in that
+                    we don't allow PRE_MODIFY for some multi-register
+                    operations.  */
+                 switch (m)
+                   {
+                   default:
+                     addr_mask |= RELOAD_REG_PRE_MODIFY;
+                     break;
+
+                   case DImode:
+                     if (TARGET_POWERPC64)
+                       addr_mask |= RELOAD_REG_PRE_MODIFY;
+                     break;
+
+                   case DFmode:
+                   case DDmode:
+                     if (TARGET_DF_INSN)
+                       addr_mask |= RELOAD_REG_PRE_MODIFY;
+                     break;
+                   }
+               }
+           }
+
+         /* GPR and FPR registers can do REG+OFFSET addressing, except
+            possibly for SDmode.  */
+         if ((addr_mask != 0) && !indexed_only_p
+             && (rc == RELOAD_REG_GPR || rc == RELOAD_REG_FPR))
+           addr_mask |= RELOAD_REG_OFFSET;
+
+         reg_addr[m].addr_mask[rc] = addr_mask;
+         any_addr_mask |= addr_mask;
+       }
+
+      reg_addr[m].addr_mask[RELOAD_REG_ANY] = any_addr_mask;
+    }
+}
+
+
 /* Initialize the various global tables that are based on register size.  */
 static void
 rs6000_init_hard_regno_mode_ok (bool global_init_p)
@@ -2253,18 +2442,15 @@ rs6000_init_hard_regno_mode_ok (bool glo
   /* Precalculate the valid memory formats as well as the vector information,
      this must be set up before the rs6000_hard_regno_nregs_internal calls
      below.  */
-  for (m = 0; m < NUM_MACHINE_MODES; ++m)
-    {
-      rs6000_vector_unit[m] = rs6000_vector_mem[m] = VECTOR_NONE;
-      reg_addr[m].reload_load = CODE_FOR_nothing;
-      reg_addr[m].reload_store = CODE_FOR_nothing;
-      reg_addr[m].reload_fpr_gpr = CODE_FOR_nothing;
-      reg_addr[m].reload_gpr_vsx = CODE_FOR_nothing;
-      reg_addr[m].reload_vsx_gpr = CODE_FOR_nothing;
-    }
+  gcc_assert ((int)VECTOR_NONE == 0);
+  memset ((void *) &rs6000_vector_unit[0], '\0', sizeof (rs6000_vector_unit));
+  memset ((void *) &rs6000_vector_mem[0], '\0', sizeof (rs6000_vector_unit));
+
+  gcc_assert ((int)CODE_FOR_nothing == 0);
+  memset ((void *) &reg_addr[0], '\0', sizeof (reg_addr));
 
-  for (c = 0; c < (int)(int)RS6000_CONSTRAINT_MAX; c++)
-    rs6000_constraints[c] = NO_REGS;
+  gcc_assert ((int)NO_REGS == 0);
+  memset ((void *) &rs6000_constraints[0], '\0', sizeof (rs6000_constraints));
 
   /* The VSX hardware allows native alignment for vectors, but control whether 
the compiler
      believes it can use native alignment or still uses 128-bit alignment.  */
@@ -2660,6 +2846,11 @@ rs6000_init_hard_regno_mode_ok (bool glo
        }
     }
 
+  /* Update the addr mask bits in reg_addr to help secondary reload and go if
+     legitimate address support to figure out the appropriate addressing to
+     use.  */
+  rs6000_setup_reg_addr_masks ();
+
   if (global_init_p || TARGET_DEBUG_TARGET)
     {
       if (TARGET_DEBUG_REG)
@@ -7162,17 +7353,9 @@ rs6000_legitimate_address_p (enum machin
     return 0;
   if (legitimate_indirect_address_p (x, reg_ok_strict))
     return 1;
-  if ((GET_CODE (x) == PRE_INC || GET_CODE (x) == PRE_DEC)
-      && !ALTIVEC_OR_VSX_VECTOR_MODE (mode)
-      && !SPE_VECTOR_MODE (mode)
-      && mode != TFmode
-      && mode != TDmode
-      && mode != TImode
-      && mode != PTImode
-      /* Restrict addressing for DI because of our SUBREG hackery.  */
-      && !(TARGET_E500_DOUBLE
-          && (mode == DFmode || mode == DDmode || mode == DImode))
-      && TARGET_UPDATE
+  if (TARGET_UPDATE
+      && (GET_CODE (x) == PRE_INC || GET_CODE (x) == PRE_DEC)
+      && mode_supports_pre_incdec_p (mode)
       && legitimate_indirect_address_p (XEXP (x, 0), reg_ok_strict))
     return 1;
   if (virtual_stack_registers_memory_p (x))
@@ -7212,21 +7395,8 @@ rs6000_legitimate_address_p (enum machin
       && !avoiding_indexed_address_p (mode)
       && legitimate_indexed_address_p (x, reg_ok_strict))
     return 1;
-  if (GET_CODE (x) == PRE_MODIFY
-      && mode != TImode
-      && mode != PTImode
-      && mode != TFmode
-      && mode != TDmode
-      && ((TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT)
-         || TARGET_POWERPC64
-         || ((mode != DFmode && mode != DDmode) || TARGET_E500_DOUBLE))
-      && (TARGET_POWERPC64 || mode != DImode)
-      && !ALTIVEC_OR_VSX_VECTOR_MODE (mode)
-      && !SPE_VECTOR_MODE (mode)
-      /* Restrict addressing for DI because of our SUBREG hackery.  */
-      && !(TARGET_E500_DOUBLE
-          && (mode == DFmode || mode == DDmode || mode == DImode))
-      && TARGET_UPDATE
+  if (TARGET_UPDATE && GET_CODE (x) == PRE_MODIFY
+      && mode_supports_pre_modify_p (mode)
       && legitimate_indirect_address_p (XEXP (x, 0), reg_ok_strict)
       && (rs6000_legitimate_offset_address_p (mode, XEXP (x, 1),
                                              reg_ok_strict, false)
@@ -29803,7 +29973,6 @@ rs6000_print_options_internal (FILE *fil
   size_t cur_column;
   size_t max_column = 76;
   const char *comma = "";
-  const char *nl = "\n";
 
   if (indent)
     start_column += fprintf (file, "%*s", indent, "");
@@ -29834,7 +30003,6 @@ rs6000_print_options_internal (FILE *fil
              fprintf (stderr, ", \\\n%*s", (int)start_column, "");
              cur_column = start_column + len;
              comma = "";
-             nl = "\n\n";
            }
 
          fprintf (file, "%s%s%s%s", comma, prefix, no_str,
@@ -29844,7 +30012,7 @@ rs6000_print_options_internal (FILE *fil
        }
     }
 
-  fputs (nl, file);
+  fputs ("\n", file);
 }
 
 /* Helper function to print the current isa options on a line.  */

Reply via email to