]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
gcc/
authorrsandifo <rsandifo@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 26 Oct 2012 06:41:53 +0000 (06:41 +0000)
committerrsandifo <rsandifo@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 26 Oct 2012 06:41:53 +0000 (06:41 +0000)
PR bootstrap/55049
* Makefile.in (rtlanal.o): Add dependency on addresses.h.
* rtl.h (address_info): New structure.
(strip_address_mutations, decompose_address, decompose_lea_address)
(decompose_mem_address, update_address, get_index_scale)
(get_index_code): Declare.
* rtlanal.c: Include addresses.h.
(strip_address_mutations, must_be_base_p, must_be_index_p)
(set_address_segment, set_address_base, set_address_index)
(set_address_disp, decompose_incdec_address, decompose_automod_address)
(extract_plus_operands, baseness, decompose_normal_address)
(decompose_address, decompose_lea_address, decompose_mem_address)
(update_address, get_index_scale, get_index_code): New functions.
* lra-constraints.c (strip_subreg): New function.
(address, extract_loc_address_regs, extract_address_regs)
(get_index_scale): Delete.
(process_addr_reg): Apply strip_subreg to the location.
(uses_hard_regs_p): Use decompose_mem_address.
(valid_address_p, base_plus_disp_to_reg, can_add_disp_p)
(equiv_address_substitution): Take an address_info rather
than an address.  Remove other arguments.  Avoid using Pmode.
(process_address): Use decompose_mem_address and decompose_lea_address.
Update calls to above functions.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@192837 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/Makefile.in
gcc/lra-constraints.c
gcc/rtl.h
gcc/rtlanal.c

index be75b81aab5ef5d172fad69eecb412be11572b52..9d1dd5069a27dd48d868fc59a9c9e5ae3f8afb96 100644 (file)
@@ -1,3 +1,29 @@
+2012-10-26  Richard Sandiford  <rdsandiford@googlemail.com>
+
+       PR bootstrap/55049
+       * Makefile.in (rtlanal.o): Add dependency on addresses.h.
+       * rtl.h (address_info): New structure.
+       (strip_address_mutations, decompose_address, decompose_lea_address)
+       (decompose_mem_address, update_address, get_index_scale)
+       (get_index_code): Declare.
+       * rtlanal.c: Include addresses.h.
+       (strip_address_mutations, must_be_base_p, must_be_index_p)
+       (set_address_segment, set_address_base, set_address_index)
+       (set_address_disp, decompose_incdec_address, decompose_automod_address)
+       (extract_plus_operands, baseness, decompose_normal_address)
+       (decompose_address, decompose_lea_address, decompose_mem_address)
+       (update_address, get_index_scale, get_index_code): New functions.
+       * lra-constraints.c (strip_subreg): New function.
+       (address, extract_loc_address_regs, extract_address_regs)
+       (get_index_scale): Delete.
+       (process_addr_reg): Apply strip_subreg to the location.
+       (uses_hard_regs_p): Use decompose_mem_address.
+       (valid_address_p, base_plus_disp_to_reg, can_add_disp_p)
+       (equiv_address_substitution): Take an address_info rather
+       than an address.  Remove other arguments.  Avoid using Pmode.
+       (process_address): Use decompose_mem_address and decompose_lea_address.
+       Update calls to above functions.
+
 2012-10-26  Richard Sandiford  <rdsandiford@googlemail.com>
 
        * lra-constraints.c (process_address): Tighten arguments to
index c729ee6f7d8daad4520f1f2cff481977e0f1974a..96765fe3dd098a87d0c2f769ded9a781ffa767e5 100644 (file)
@@ -2709,7 +2709,7 @@ print-rtl.o : print-rtl.c $(CONFIG_H) $(SYSTEM_H) coretypes.h dumpfile.h $(TM_H)
 rtlanal.o : rtlanal.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(DIAGNOSTIC_CORE_H) \
    $(RTL_H) hard-reg-set.h $(TM_P_H) insn-config.h $(RECOG_H) \
    $(FLAGS_H) $(REGS_H) output.h $(TARGET_H) $(FUNCTION_H) $(TREE_H) \
-   $(DF_H) $(EMIT_RTL_H)
+   $(DF_H) $(EMIT_RTL_H) addresses.h
 
 varasm.o : varasm.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
    $(RTL_H) $(FLAGS_H) $(FUNCTION_H) $(EXPR_H) hard-reg-set.h $(REGS_H) \
index ffc067b36346466e7a13d01ea7299662eddf4d60..9e4d3b1f6def1946af7ce69d4465c433c1579f0f 100644 (file)
@@ -152,6 +152,13 @@ static enum machine_mode curr_operand_mode[MAX_RECOG_OPERANDS];
 static int new_regno_start;
 static int new_insn_uid_start;
 
+/* If LOC is nonnull, strip any outer subreg from it.  */
+static inline rtx *
+strip_subreg (rtx *loc)
+{
+  return loc && GET_CODE (*loc) == SUBREG ? &SUBREG_REG (*loc) : loc;
+}
+
 /* Return hard regno of REGNO or if it is was not assigned to a hard
    register, use a hard register from its allocno class.  */
 static int
@@ -435,28 +442,6 @@ get_reload_reg (enum op_type type, enum machine_mode mode, rtx original,
 
 /* The page contains code to extract memory address parts.  */
 
-/* Info about base and index regs of an address.  In some rare cases,
-   base/index register can be actually memory. In this case we will
-   reload it.  */
-struct address
-{
-  /* NULL if there is no a base register.  */
-  rtx *base_reg_loc;
-  /* Second location of {post/pre}_modify, NULL otherwise.  */
-  rtx *base_reg_loc2;
-  /* NULL if there is no an index register.  */
-  rtx *index_reg_loc;
-  /* Location of index reg * scale or index_reg_loc otherwise.  */
-  rtx *index_loc;
-  /* NULL if there is no a displacement.  */
-  rtx *disp_loc;
-  /* Defined if base_reg_loc is not NULL.  */
-  enum rtx_code base_outer_code, index_code;
-  /* True if the base register is modified in the address, for
-     example, in PRE_INC.  */
-  bool base_modify_p;
-};
-
 /* Wrapper around REGNO_OK_FOR_INDEX_P, to allow pseudos.  */
 static inline bool
 ok_for_index_p_nonstrict (rtx reg)
@@ -479,305 +464,6 @@ ok_for_base_p_nonstrict (rtx reg, enum machine_mode mode, addr_space_t as,
   return ok_for_base_p_1 (regno, mode, as, outer_code, index_code);
 }
 
-/* Process address part in space AS (or all address if TOP_P) with
-   location *LOC to extract address characteristics.
-
-   If CONTEXT_P is false, we are looking at the base part of an
-   address, otherwise we are looking at the index part.
-
-   MODE is the mode of the memory reference; OUTER_CODE and INDEX_CODE
-   give the context that the rtx appears in; MODIFY_P if *LOC is
-   modified.  */
-static void
-extract_loc_address_regs (bool top_p, enum machine_mode mode, addr_space_t as,
-                         rtx *loc, bool context_p, enum rtx_code outer_code,
-                         enum rtx_code index_code,
-                         bool modify_p, struct address *ad)
-{
-  rtx x = *loc;
-  enum rtx_code code = GET_CODE (x);
-  bool base_ok_p;
-
-  switch (code)
-    {
-    case CONST_INT:
-    case CONST:
-    case SYMBOL_REF:
-    case LABEL_REF:
-      if (! context_p)
-       {
-         lra_assert (top_p);
-         ad->disp_loc = loc;
-       }
-      return;
-
-    case CC0:
-    case PC:
-      return;
-
-    case ZERO_EXTEND:
-      /* Pass TOP_P for displacement.  */
-      extract_loc_address_regs (top_p, mode, as, &XEXP (*loc, 0), context_p,
-                               code, index_code, modify_p, ad);
-      return;
-
-    case PLUS:
-    case LO_SUM:
-      /* When we have an address that is a sum, we must determine
-        whether registers are "base" or "index" regs.  If there is a
-        sum of two registers, we must choose one to be the
-        "base".  */
-      {
-       rtx *arg0_loc = &XEXP (x, 0);
-       rtx *arg1_loc = &XEXP (x, 1);
-       rtx *tloc;
-       rtx arg0 = *arg0_loc;
-       rtx arg1 = *arg1_loc;
-       enum rtx_code code0 = GET_CODE (arg0);
-       enum rtx_code code1 = GET_CODE (arg1);
-
-       /* Look inside subregs.  */
-       if (code0 == SUBREG)
-         {
-           arg0_loc = &SUBREG_REG (arg0);
-           arg0 = *arg0_loc;
-           code0 = GET_CODE (arg0);
-         }
-       if (code1 == SUBREG)
-         {
-           arg1_loc = &SUBREG_REG (arg1);
-           arg1 = *arg1_loc;
-           code1 = GET_CODE (arg1);
-         }
-
-       if (CONSTANT_P (arg0)
-           || code1 == PLUS || code1 == MULT || code1 == ASHIFT)
-         {
-           tloc = arg1_loc;
-           arg1_loc = arg0_loc;
-           arg0_loc = tloc;
-           arg0 = *arg0_loc;
-           code0 = GET_CODE (arg0);
-           arg1 = *arg1_loc;
-           code1 = GET_CODE (arg1);
-         }
-       /* If this machine only allows one register per address, it
-          must be in the first operand.  */
-       if (MAX_REGS_PER_ADDRESS == 1 || code == LO_SUM)
-         {
-           lra_assert (ad->disp_loc == NULL);
-           ad->disp_loc = arg1_loc;
-           extract_loc_address_regs (false, mode, as, arg0_loc, false, code,
-                                     code1, modify_p, ad);
-         }
-       /* Base + disp addressing  */
-       else if (code0 != PLUS && code0 != MULT && code0 != ASHIFT
-                && CONSTANT_P (arg1))
-         {
-           lra_assert (ad->disp_loc == NULL);
-           ad->disp_loc = arg1_loc;
-           extract_loc_address_regs (false, mode, as, arg0_loc, false, PLUS,
-                                     code1, modify_p, ad);
-         }
-       /* If index and base registers are the same on this machine,
-          just record registers in any non-constant operands.  We
-          assume here, as well as in the tests below, that all
-          addresses are in canonical form.  */
-       else if (INDEX_REG_CLASS
-                == base_reg_class (VOIDmode, as, PLUS, SCRATCH)
-                && code0 != PLUS && code0 != MULT && code0 != ASHIFT)
-         {
-           extract_loc_address_regs (false, mode, as, arg0_loc, false, PLUS,
-                                     code1, modify_p, ad);
-           lra_assert (! CONSTANT_P (arg1));
-           extract_loc_address_regs (false, mode, as, arg1_loc, true, PLUS,
-                                     code0, modify_p, ad);
-         }
-       /* It might be [base + ]index * scale + disp. */
-       else if (CONSTANT_P (arg1))
-         {
-           lra_assert (ad->disp_loc == NULL);
-           ad->disp_loc = arg1_loc;
-           extract_loc_address_regs (false, mode, as, arg0_loc, context_p,
-                                     PLUS, code0, modify_p, ad);
-         }
-       /* If both operands are registers but one is already a hard
-          register of index or reg-base class, give the other the
-          class that the hard register is not.  */
-       else if (code0 == REG && code1 == REG
-                && REGNO (arg0) < FIRST_PSEUDO_REGISTER
-                && ((base_ok_p
-                     = ok_for_base_p_nonstrict (arg0, mode, as, PLUS, REG))
-                    || ok_for_index_p_nonstrict (arg0)))
-         {
-           extract_loc_address_regs (false, mode, as, arg0_loc, ! base_ok_p,
-                                     PLUS, REG, modify_p, ad);
-           extract_loc_address_regs (false, mode, as, arg1_loc, base_ok_p,
-                                     PLUS, REG, modify_p, ad);
-         }
-       else if (code0 == REG && code1 == REG
-                && REGNO (arg1) < FIRST_PSEUDO_REGISTER
-                && ((base_ok_p
-                     = ok_for_base_p_nonstrict (arg1, mode, as, PLUS, REG))
-                    || ok_for_index_p_nonstrict (arg1)))
-         {
-           extract_loc_address_regs (false, mode, as, arg0_loc, base_ok_p,
-                                     PLUS, REG, modify_p, ad);
-           extract_loc_address_regs (false, mode, as, arg1_loc, ! base_ok_p,
-                                     PLUS, REG, modify_p, ad);
-         }
-       /* Otherwise, count equal chances that each might be a base or
-          index register.  This case should be rare.  */
-       else
-         {
-           extract_loc_address_regs (false, mode, as, arg0_loc, false, PLUS,
-                                     code1, modify_p, ad);
-           extract_loc_address_regs (false, mode, as, arg1_loc,
-                                     ad->base_reg_loc != NULL, PLUS,
-                                     code0, modify_p, ad);
-         }
-      }
-      break;
-
-    case MULT:
-    case ASHIFT:
-      {
-       rtx *arg0_loc = &XEXP (x, 0);
-       enum rtx_code code0 = GET_CODE (*arg0_loc);
-       
-       if (code0 == CONST_INT)
-         arg0_loc = &XEXP (x, 1);
-       extract_loc_address_regs (false, mode, as, arg0_loc, true,
-                                 outer_code, code, modify_p, ad);
-       lra_assert (ad->index_loc == NULL);
-       ad->index_loc = loc;
-       break;
-      }
-
-    case POST_MODIFY:
-    case PRE_MODIFY:
-      extract_loc_address_regs (false, mode, as, &XEXP (x, 0), false,
-                               code, GET_CODE (XEXP (XEXP (x, 1), 1)),
-                               true, ad);
-      lra_assert (rtx_equal_p (XEXP (XEXP (x, 1), 0), XEXP (x, 0)));
-      ad->base_reg_loc2 = &XEXP (XEXP (x, 1), 0);
-      if (REG_P (XEXP (XEXP (x, 1), 1)))
-       extract_loc_address_regs (false, mode, as, &XEXP (XEXP (x, 1), 1),
-                                 true, code, REG, modify_p, ad);
-      break;
-
-    case POST_INC:
-    case PRE_INC:
-    case POST_DEC:
-    case PRE_DEC:
-      extract_loc_address_regs (false, mode, as, &XEXP (x, 0), false, code,
-                               SCRATCH, true, ad);
-      break;
-
-      /* We process memory as a register.  That means we flatten
-        addresses.  In other words, the final code will never
-        contains memory in an address even if the target supports
-        such addresses (it is too rare these days).  Memory also can
-        occur in address as a result some previous transformations
-        like equivalence substitution.  */
-    case MEM:
-    case REG:
-      if (context_p)
-       {
-         lra_assert (ad->index_reg_loc == NULL);
-         ad->index_reg_loc = loc;
-       }
-      else
-       {
-         lra_assert (ad->base_reg_loc == NULL);
-         ad->base_reg_loc = loc;
-         ad->base_outer_code = outer_code;
-         ad->index_code = index_code;
-         ad->base_modify_p = modify_p;
-       }
-      break;
-    default:
-      {
-       const char *fmt = GET_RTX_FORMAT (code);
-       int i;
-
-       if (GET_RTX_LENGTH (code) != 1
-           || fmt[0] != 'e' || GET_CODE (XEXP (x, 0)) != UNSPEC)
-         {
-           for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
-             if (fmt[i] == 'e')
-               extract_loc_address_regs (false, mode, as, &XEXP (x, i),
-                                         context_p, code, SCRATCH,
-                                         modify_p, ad);
-           break;
-         }
-       /* fall through for case UNARY_OP (UNSPEC ...)  */
-      }
-
-    case UNSPEC:
-      if (ad->disp_loc == NULL)
-       ad->disp_loc = loc;
-      else if (ad->base_reg_loc == NULL)
-       {
-         ad->base_reg_loc = loc;
-         ad->base_outer_code = outer_code;
-         ad->index_code = index_code;
-         ad->base_modify_p = modify_p;
-       }
-      else
-       {
-         lra_assert (ad->index_reg_loc == NULL);
-         ad->index_reg_loc = loc;
-       }
-      break;
-
-    }
-}
-
-
-/* Describe address *LOC in AD.  There are two cases:
-   - *LOC is the address in a (mem ...).  In this case OUTER_CODE is MEM
-     and AS is the mem's address space.
-   - *LOC is matched to an address constraint such as 'p'.  In this case
-     OUTER_CODE is ADDRESS and AS is ADDR_SPACE_GENERIC.  */
-static void
-extract_address_regs (enum machine_mode mem_mode, addr_space_t as,
-                     rtx *loc, enum rtx_code outer_code, struct address *ad)
-{
-  ad->base_reg_loc = ad->base_reg_loc2
-    = ad->index_reg_loc = ad->index_loc = ad->disp_loc = NULL;
-  ad->base_outer_code = SCRATCH;
-  ad->index_code = SCRATCH;
-  ad->base_modify_p = false;
-  extract_loc_address_regs (true, mem_mode, as, loc, false, outer_code,
-                           SCRATCH, false, ad);  
-  if (ad->index_loc == NULL)
-    /* SUBREG ??? */
-    ad->index_loc = ad->index_reg_loc;
-}
-
-/* Return the scale applied to *AD->INDEX_REG_LOC, or 0 if the index is
-   more complicated than that.  */
-static HOST_WIDE_INT
-get_index_scale (struct address *ad)
-{
-  rtx index = *ad->index_loc;
-  if (GET_CODE (index) == MULT
-      && CONST_INT_P (XEXP (index, 1))
-      && ad->index_reg_loc == &XEXP (index, 0))
-    return INTVAL (XEXP (index, 1));
-
-  if (GET_CODE (index) == ASHIFT
-      && CONST_INT_P (XEXP (index, 1))
-      && ad->index_reg_loc == &XEXP (index, 0))
-    return (HOST_WIDE_INT) 1 << INTVAL (XEXP (index, 1));
-
-  if (ad->index_reg_loc == ad->index_loc)
-    return 1;
-
-  return 0;
-}
-
 \f
 
 /* The page contains major code to choose the current insn alternative
@@ -1354,11 +1040,13 @@ process_addr_reg (rtx *loc, rtx *before, rtx *after, enum reg_class cl)
 {
   int regno;
   enum reg_class rclass, new_class;
-  rtx reg = *loc;
+  rtx reg;
   rtx new_reg;
   enum machine_mode mode;
   bool before_p = false;
 
+  loc = strip_subreg (loc);
+  reg = *loc;
   mode = GET_MODE (reg);
   if (! REG_P (reg))
     {
@@ -1538,21 +1226,13 @@ uses_hard_regs_p (rtx x, HARD_REG_SET set)
     }
   if (MEM_P (x))
     {
-      struct address ad;
-      enum machine_mode mode = GET_MODE (x);
-      rtx *addr_loc = &XEXP (x, 0);
+      struct address_info ad;
 
-      extract_address_regs (mode, MEM_ADDR_SPACE (x), addr_loc, MEM, &ad);
-      if (ad.base_reg_loc != NULL)
-       {
-         if (uses_hard_regs_p (*ad.base_reg_loc, set))
-           return true;
-       }
-      if (ad.index_reg_loc != NULL)
-       {
-         if (uses_hard_regs_p (*ad.index_reg_loc, set))
-           return true;
-       }
+      decompose_mem_address (&ad, x);
+      if (ad.base_term != NULL && uses_hard_regs_p (*ad.base_term, set))
+       return true;
+      if (ad.index_term != NULL && uses_hard_regs_p (*ad.index_term, set))
+       return true;
     }
   fmt = GET_RTX_FORMAT (code);
   for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
@@ -2399,115 +2079,92 @@ valid_address_p (enum machine_mode mode ATTRIBUTE_UNUSED,
 #endif
 }
 
-/* Return whether address X, described by AD, is valid for mode MODE
-   and address space AS.  */
+/* Return whether address AD is valid.  */
 
 static bool
-valid_address_p (struct address *ad, enum machine_mode mode, rtx x,
-                addr_space_t as)
+valid_address_p (struct address_info *ad)
 {
   /* Some ports do not check displacements for eliminable registers,
      so we replace them temporarily with the elimination target.  */
   rtx saved_base_reg = NULL_RTX;
   rtx saved_index_reg = NULL_RTX;
-  if (ad->base_reg_loc != NULL)
+  rtx *base_term = strip_subreg (ad->base_term);
+  rtx *index_term = strip_subreg (ad->index_term);
+  if (base_term != NULL)
     {
-      saved_base_reg = *ad->base_reg_loc;
-      lra_eliminate_reg_if_possible (ad->base_reg_loc);
-      if (ad->base_reg_loc2 != NULL)
-       *ad->base_reg_loc2 = *ad->base_reg_loc;
+      saved_base_reg = *base_term;
+      lra_eliminate_reg_if_possible (base_term);
+      if (ad->base_term2 != NULL)
+       *ad->base_term2 = *ad->base_term;
     }
-  if (ad->index_reg_loc != NULL)
+  if (index_term != NULL)
     {
-      saved_index_reg = *ad->index_reg_loc;
-      lra_eliminate_reg_if_possible (ad->index_reg_loc);
+      saved_index_reg = *index_term;
+      lra_eliminate_reg_if_possible (index_term);
     }
-  bool ok_p = valid_address_p (mode, x, as);
+  bool ok_p = valid_address_p (ad->mode, *ad->outer, ad->as);
   if (saved_base_reg != NULL_RTX)
     {
-      *ad->base_reg_loc = saved_base_reg;
-      if (ad->base_reg_loc2 != NULL)
-       *ad->base_reg_loc2 = saved_base_reg;
+      *base_term = saved_base_reg;
+      if (ad->base_term2 != NULL)
+       *ad->base_term2 = *ad->base_term;
     }
   if (saved_index_reg != NULL_RTX)
-    *ad->index_reg_loc = saved_index_reg;
+    *index_term = saved_index_reg;
   return ok_p;
 }
 
-/* Make reload base reg + disp from address AD in space AS of memory
-   with MODE into a new pseudo.         Return the new pseudo.  */
+/* Make reload base reg + disp from address AD.  Return the new pseudo.  */
 static rtx
-base_plus_disp_to_reg (enum machine_mode mode, addr_space_t as,
-                      struct address *ad)
+base_plus_disp_to_reg (struct address_info *ad)
 {
   enum reg_class cl;
   rtx new_reg;
 
-  lra_assert (ad->base_reg_loc != NULL && ad->disp_loc != NULL);
-  cl = base_reg_class (mode, as, ad->base_outer_code, ad->index_code);
-  new_reg = lra_create_new_reg (Pmode, NULL_RTX, cl, "base + disp");
-  lra_emit_add (new_reg, *ad->base_reg_loc, *ad->disp_loc);
+  lra_assert (ad->base == ad->base_term && ad->disp == ad->disp_term);
+  cl = base_reg_class (ad->mode, ad->as, ad->base_outer_code,
+                      get_index_code (ad));
+  new_reg = lra_create_new_reg (GET_MODE (*ad->base_term), NULL_RTX,
+                               cl, "base + disp");
+  lra_emit_add (new_reg, *ad->base_term, *ad->disp_term);
   return new_reg;
 }
 
-/* Return true if we can add a displacement to address ADDR_LOC,
-   which is described by AD, even if that makes the address invalid.
-   The fix-up code requires any new address to be the sum of the base,
-   index and displacement fields of an AD-like structure.  */
+/* Return true if we can add a displacement to address AD, even if that
+   makes the address invalid.  The fix-up code requires any new address
+   to be the sum of the BASE_TERM, INDEX and DISP_TERM fields.  */
 static bool
-can_add_disp_p (struct address *ad, rtx *addr_loc)
+can_add_disp_p (struct address_info *ad)
 {
-  /* Automodified addresses have a fixed form.  */
-  if (ad->base_modify_p)
-    return false;
-
-  /* If the address already has a displacement, and is not an UNSPEC,
-     we can simply add the new displacement to it.  */
-  if (ad->disp_loc && GET_CODE (*ad->disp_loc) == UNSPEC)
-    return true;
-
-  /* If the address is entirely a base or index, we can try adding
-     a constant to it.  */
-  if (addr_loc == ad->base_reg_loc || addr_loc == ad->index_loc)
-    return true;
-
-  /* Likewise if the address is entirely a sum of the base and index.  */
-  if (GET_CODE (*addr_loc) == PLUS)
-    {
-      rtx *op0 = &XEXP (*addr_loc, 0);
-      rtx *op1 = &XEXP (*addr_loc, 1);
-      if (op0 == ad->base_reg_loc && op1 == ad->index_loc)
-       return true;
-      if (op1 == ad->base_reg_loc && op0 == ad->index_loc)
-       return true;
-    }
-  return false;
+  return (!ad->autoinc_p
+         && ad->segment == NULL
+         && ad->base == ad->base_term
+         && ad->disp == ad->disp_term);
 }
 
-/* Make substitution in address AD in space AS with location ADDR_LOC.
-   Update AD and ADDR_LOC if it is necessary.  Return true if a
-   substitution was made.  */
+/* Make equiv substitution in address AD.  Return true if a substitution
+   was made.  */
 static bool
-equiv_address_substitution (struct address *ad, rtx *addr_loc,
-                           enum machine_mode mode, addr_space_t as,
-                           enum rtx_code code)
+equiv_address_substitution (struct address_info *ad)
 {
-  rtx base_reg, new_base_reg, index_reg, new_index_reg;
+  rtx base_reg, new_base_reg, index_reg, new_index_reg, *base_term, *index_term;
   HOST_WIDE_INT disp, scale;
   bool change_p;
 
-  if (ad->base_reg_loc == NULL)
+  base_term = strip_subreg (ad->base_term);
+  if (base_term == NULL)
     base_reg = new_base_reg = NULL_RTX;
   else
     {
-      base_reg = *ad->base_reg_loc;
+      base_reg = *base_term;
       new_base_reg = get_equiv_substitution (base_reg);
     }
-  if (ad->index_reg_loc == NULL)
+  index_term = strip_subreg (ad->index_term);
+  if (index_term == NULL)
     index_reg = new_index_reg = NULL_RTX;
   else
     {
-      index_reg = *ad->index_reg_loc;
+      index_reg = *index_term;
       new_index_reg = get_equiv_substitution (index_reg);
     }
   if (base_reg == new_base_reg && index_reg == new_index_reg)
@@ -2518,53 +2175,53 @@ equiv_address_substitution (struct address *ad, rtx *addr_loc,
     {
       fprintf (lra_dump_file, "Changing address in insn %d ",
               INSN_UID (curr_insn));
-      print_value_slim (lra_dump_file, *addr_loc, 1);
+      print_value_slim (lra_dump_file, *ad->outer, 1);
     }
   if (base_reg != new_base_reg)
     {
       if (REG_P (new_base_reg))
        {
-         *ad->base_reg_loc = new_base_reg;
+         *base_term = new_base_reg;
          change_p = true;
        }
       else if (GET_CODE (new_base_reg) == PLUS
               && REG_P (XEXP (new_base_reg, 0))
               && CONST_INT_P (XEXP (new_base_reg, 1))
-              && can_add_disp_p (ad, addr_loc))
+              && can_add_disp_p (ad))
        {
          disp += INTVAL (XEXP (new_base_reg, 1));
-         *ad->base_reg_loc = XEXP (new_base_reg, 0);
+         *base_term = XEXP (new_base_reg, 0);
          change_p = true;
        }
-      if (ad->base_reg_loc2 != NULL)
-       *ad->base_reg_loc2 = *ad->base_reg_loc;
+      if (ad->base_term2 != NULL)
+       *ad->base_term2 = *ad->base_term;
     }
   if (index_reg != new_index_reg)
     {
       if (REG_P (new_index_reg))
        {
-         *ad->index_reg_loc = new_index_reg;
+         *index_term = new_index_reg;
          change_p = true;
        }
       else if (GET_CODE (new_index_reg) == PLUS
               && REG_P (XEXP (new_index_reg, 0))
               && CONST_INT_P (XEXP (new_index_reg, 1))
-              && can_add_disp_p (ad, addr_loc)
+              && can_add_disp_p (ad)
               && (scale = get_index_scale (ad)))
        {
          disp += INTVAL (XEXP (new_index_reg, 1)) * scale;
-         *ad->index_reg_loc = XEXP (new_index_reg, 0);
+         *index_term = XEXP (new_index_reg, 0);
          change_p = true;
        }
     }
   if (disp != 0)
     {
-      if (ad->disp_loc != NULL)
-       *ad->disp_loc = plus_constant (Pmode, *ad->disp_loc, disp);
+      if (ad->disp != NULL)
+       *ad->disp = plus_constant (GET_MODE (*ad->inner), *ad->disp, disp);
       else
        {
-         *addr_loc = gen_rtx_PLUS (Pmode, *addr_loc, GEN_INT (disp));
-         extract_address_regs (mode, as, addr_loc, code, ad);
+         *ad->inner = plus_constant (GET_MODE (*ad->inner), *ad->inner, disp);
+         update_address (ad);
        }
       change_p = true;
     }
@@ -2575,7 +2232,7 @@ equiv_address_substitution (struct address *ad, rtx *addr_loc,
       else
        {
          fprintf (lra_dump_file, " on equiv ");
-         print_value_slim (lra_dump_file, *addr_loc, 1);
+         print_value_slim (lra_dump_file, *ad->outer, 1);
          fprintf (lra_dump_file, "\n");
        }
     }
@@ -2604,62 +2261,43 @@ equiv_address_substitution (struct address *ad, rtx *addr_loc,
 static bool
 process_address (int nop, rtx *before, rtx *after)
 {
-  struct address ad;
-  enum machine_mode mode;
-  rtx new_reg, *addr_loc;
-  addr_space_t as;
+  struct address_info ad;
+  rtx new_reg;
   rtx op = *curr_id->operand_loc[nop];
   const char *constraint = curr_static_id->operand[nop].constraint;
   bool change_p;
-  enum rtx_code code;
 
   if (constraint[0] == 'p'
       || EXTRA_ADDRESS_CONSTRAINT (constraint[0], constraint))
-    {
-      mode = VOIDmode;
-      addr_loc = curr_id->operand_loc[nop];
-      as = ADDR_SPACE_GENERIC;
-      code = ADDRESS;
-    }
+    decompose_lea_address (&ad, curr_id->operand_loc[nop]);
   else if (MEM_P (op))
-    {
-      mode = GET_MODE (op);
-      addr_loc = &XEXP (op, 0);
-      as = MEM_ADDR_SPACE (op);
-      code = MEM;
-    }
+    decompose_mem_address (&ad, op);
   else if (GET_CODE (op) == SUBREG
           && MEM_P (SUBREG_REG (op)))
-    {
-      mode = GET_MODE (SUBREG_REG (op));
-      addr_loc = &XEXP (SUBREG_REG (op), 0);
-      as = MEM_ADDR_SPACE (SUBREG_REG (op));
-      code = MEM;
-    }
+    decompose_mem_address (&ad, SUBREG_REG (op));
   else
     return false;
-  if (GET_CODE (*addr_loc) == AND)
-    addr_loc = &XEXP (*addr_loc, 0);
-  extract_address_regs (mode, as, addr_loc, code, &ad);
-  change_p = equiv_address_substitution (&ad, addr_loc, mode, as, code);
-  if (ad.base_reg_loc != NULL
+  change_p = equiv_address_substitution (&ad);
+  if (ad.base_term != NULL
       && (process_addr_reg
-         (ad.base_reg_loc, before,
-          (ad.base_modify_p && REG_P (*ad.base_reg_loc)
-           && find_regno_note (curr_insn, REG_DEAD,
-                               REGNO (*ad.base_reg_loc)) == NULL_RTX
+         (ad.base_term, before,
+          (ad.autoinc_p
+           && !(REG_P (*ad.base_term)
+                && find_regno_note (curr_insn, REG_DEAD,
+                                    REGNO (*ad.base_term)) != NULL_RTX)
            ? after : NULL),
-          base_reg_class (mode, as, ad.base_outer_code, ad.index_code))))
+          base_reg_class (ad.mode, ad.as, ad.base_outer_code,
+                          get_index_code (&ad)))))
     {
       change_p = true;
-      if (ad.base_reg_loc2 != NULL)
-       *ad.base_reg_loc2 = *ad.base_reg_loc;
+      if (ad.base_term2 != NULL)
+       *ad.base_term2 = *ad.base_term;
     }
-  if (ad.index_reg_loc != NULL
-      && process_addr_reg (ad.index_reg_loc, before, NULL, INDEX_REG_CLASS))
+  if (ad.index_term != NULL
+      && process_addr_reg (ad.index_term, before, NULL, INDEX_REG_CLASS))
     change_p = true;
 
-  /* There are three cases where the shape of *ADDR_LOC may now be invalid:
+  /* There are three cases where the shape of *AD.INNER may now be invalid:
 
      1) the original address was valid, but either elimination or
        equiv_address_substitution applied a displacement that made
@@ -2670,21 +2308,25 @@ process_address (int nop, rtx *before, rtx *after)
 
      3) the address is a frame address with an invalid offset.
 
-     All these cases involve a displacement, so there is no point
-     revalidating when there is no displacement.  */
-  if (ad.disp_loc == NULL || valid_address_p (&ad, mode, *addr_loc, as))
+     All these cases involve a displacement and a non-autoinc address,
+     so there is no point revalidating other types.  */
+  if (ad.disp == NULL || ad.autoinc_p || valid_address_p (&ad))
     return change_p;
 
   /* Any index existed before LRA started, so we can assume that the
      presence and shape of the index is valid.  */
   push_to_sequence (*before);
-  if (ad.base_reg_loc == NULL)
+  gcc_assert (ad.segment == NULL);
+  gcc_assert (ad.disp == ad.disp_term);
+  if (ad.base == NULL)
     {
-      if (ad.index_reg_loc == NULL)
+      if (ad.index == NULL)
        {
          int code = -1;
-         enum reg_class cl = base_reg_class (mode, as, SCRATCH, SCRATCH);
-         
+         enum reg_class cl = base_reg_class (ad.mode, ad.as,
+                                             SCRATCH, SCRATCH);
+         rtx disp = *ad.disp;
+
          new_reg = lra_create_new_reg (Pmode, NULL_RTX, cl, "disp");
 #ifdef HAVE_lo_sum
          {
@@ -2694,16 +2336,14 @@ process_address (int nop, rtx *before, rtx *after)
            /* disp => lo_sum (new_base, disp), case (2) above.  */
            insn = emit_insn (gen_rtx_SET
                              (VOIDmode, new_reg,
-                              gen_rtx_HIGH (Pmode, copy_rtx (*ad.disp_loc))));
+                              gen_rtx_HIGH (Pmode, copy_rtx (disp))));
            code = recog_memoized (insn);
            if (code >= 0)
              {
-               rtx save = *ad.disp_loc;
-
-               *ad.disp_loc = gen_rtx_LO_SUM (Pmode, new_reg, *ad.disp_loc);
-               if (! valid_address_p (mode, *ad.disp_loc, as))
+               *ad.disp = gen_rtx_LO_SUM (Pmode, new_reg, disp);
+               if (! valid_address_p (ad.mode, *ad.outer, ad.as))
                  {
-                   *ad.disp_loc = save;
+                   *ad.disp = disp;
                    code = -1;
                  }
              }
@@ -2714,25 +2354,25 @@ process_address (int nop, rtx *before, rtx *after)
          if (code < 0)
            {
              /* disp => new_base, case (2) above.  */
-             lra_emit_move (new_reg, *ad.disp_loc);
-             *ad.disp_loc = new_reg;
+             lra_emit_move (new_reg, disp);
+             *ad.disp = new_reg;
            }
        }
       else
        {
          /* index * scale + disp => new base + index * scale,
             case (1) above.  */
-         enum reg_class cl = base_reg_class (mode, as, PLUS,
-                                             GET_CODE (*ad.index_loc));
+         enum reg_class cl = base_reg_class (ad.mode, ad.as, PLUS,
+                                             GET_CODE (*ad.index));
 
          lra_assert (INDEX_REG_CLASS != NO_REGS);
          new_reg = lra_create_new_reg (Pmode, NULL_RTX, cl, "disp");
-         lra_emit_move (new_reg, *ad.disp_loc);
-         *addr_loc = simplify_gen_binary (PLUS, GET_MODE (new_reg),
-                                          new_reg, *ad.index_loc);
+         lra_emit_move (new_reg, *ad.disp);
+         *ad.inner = simplify_gen_binary (PLUS, GET_MODE (new_reg),
+                                          new_reg, *ad.index);
        }
     }
-  else if (ad.index_reg_loc == NULL)
+  else if (ad.index == NULL)
     {
       /* base + disp => new base, cases (1) and (3) above.  */
       /* Another option would be to reload the displacement into an
@@ -2740,16 +2380,16 @@ process_address (int nop, rtx *before, rtx *after)
         address reloads that have the same base and different
         displacements, so reloading into an index register would
         not necessarily be a win.  */
-      new_reg = base_plus_disp_to_reg (mode, as, &ad);
-      *addr_loc = new_reg;
+      new_reg = base_plus_disp_to_reg (&ad);
+      *ad.inner = new_reg;
     }
   else
     {
       /* base + scale * index + disp => new base + scale * index,
         case (1) above.  */
-      new_reg = base_plus_disp_to_reg (mode, as, &ad);
-      *addr_loc = simplify_gen_binary (PLUS, GET_MODE (new_reg),
-                                      new_reg, *ad.index_loc);
+      new_reg = base_plus_disp_to_reg (&ad);
+      *ad.inner = simplify_gen_binary (PLUS, GET_MODE (new_reg),
+                                      new_reg, *ad.index);
     }
   *before = get_insns ();
   end_sequence ();
index 361669ac19126fdcf74f81a8d9a55e7c054116d7..43a49c44ed7c412ac63f502aedc45d6212785401 100644 (file)
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -1237,6 +1237,77 @@ costs_add_n_insns (struct full_rtx_costs *c, int n)
   c->size += COSTS_N_INSNS (n);
 }
 
+/* Information about an address.  This structure is supposed to be able
+   to represent all supported target addresses.  Please extend it if it
+   is not yet general enough.  */
+struct address_info {
+  /* The mode of the value being addressed, or VOIDmode if this is
+     a load-address operation with no known address mode.  */
+  enum machine_mode mode;
+
+  /* The address space.  */
+  addr_space_t as;
+
+  /* A pointer to the top-level address.  */
+  rtx *outer;
+
+  /* A pointer to the inner address, after all address mutations
+     have been stripped from the top-level address.  It can be one
+     of the following:
+
+     - A {PRE,POST}_{INC,DEC} of *BASE.  SEGMENT, INDEX and DISP are null.
+
+     - A {PRE,POST}_MODIFY of *BASE.  In this case either INDEX or DISP
+       points to the step value, depending on whether the step is variable
+       or constant respectively.  SEGMENT is null.
+
+     - A plain sum of the form SEGMENT + BASE + INDEX + DISP,
+       with null fields evaluating to 0.  */
+  rtx *inner;
+
+  /* Components that make up *INNER.  Each one may be null or nonnull.
+     When nonnull, their meanings are as follows:
+
+     - *SEGMENT is the "segment" of memory to which the address refers.
+       This value is entirely target-specific and is only called a "segment"
+       because that's its most typical use.  It contains exactly one UNSPEC,
+       pointed to by SEGMENT_TERM.  The contents of *SEGMENT do not need
+       reloading.
+
+     - *BASE is a variable expression representing a base address.
+       It contains exactly one REG, SUBREG or MEM, pointed to by BASE_TERM.
+
+     - *INDEX is a variable expression representing an index value.
+       It may be a scaled expression, such as a MULT.  It has exactly
+       one REG, SUBREG or MEM, pointed to by INDEX_TERM.
+
+     - *DISP is a constant, possibly mutated.  DISP_TERM points to the
+       unmutated RTX_CONST_OBJ.  */
+  rtx *segment;
+  rtx *base;
+  rtx *index;
+  rtx *disp;
+
+  rtx *segment_term;
+  rtx *base_term;
+  rtx *index_term;
+  rtx *disp_term;
+
+  /* In a {PRE,POST}_MODIFY address, this points to a second copy
+     of BASE_TERM, otherwise it is null.  */
+  rtx *base_term2;
+
+  /* ADDRESS if this structure describes an address operand, MEM if
+     it describes a MEM address.  */
+  enum rtx_code addr_outer_code;
+
+  /* If BASE is nonnull, this is the code of the rtx that contains it.  */
+  enum rtx_code base_outer_code;
+
+  /* True if this is an RTX_AUTOINC address.  */
+  bool autoinc_p;
+};
+
 extern void init_rtlanal (void);
 extern int rtx_cost (rtx, enum rtx_code, int, bool);
 extern int address_cost (rtx, enum machine_mode, addr_space_t, bool);
@@ -1260,6 +1331,14 @@ extern bool constant_pool_constant_p (rtx);
 extern bool truncated_to_mode (enum machine_mode, const_rtx);
 extern int low_bitmask_len (enum machine_mode, unsigned HOST_WIDE_INT);
 extern void split_double (rtx, rtx *, rtx *);
+extern rtx *strip_address_mutations (rtx *, enum rtx_code * = 0);
+extern void decompose_address (struct address_info *, rtx *,
+                              enum machine_mode, addr_space_t, enum rtx_code);
+extern void decompose_lea_address (struct address_info *, rtx *);
+extern void decompose_mem_address (struct address_info *, rtx);
+extern void update_address (struct address_info *);
+extern HOST_WIDE_INT get_index_scale (const struct address_info *);
+extern enum rtx_code get_index_code (const struct address_info *);
 
 #ifndef GENERATOR_FILE
 /* Return the cost of SET X.  SPEED_P is true if optimizing for speed
index a101a2920394a01316c1f78efda0ff64a9fdf2aa..399886c1a94a1994721f8bcc6352fefb5a4c216a 100644 (file)
@@ -38,6 +38,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "df.h"
 #include "tree.h"
 #include "emit-rtl.h"  /* FIXME: Can go away once crtl is moved to rtl.h.  */
+#include "addresses.h"
 
 /* Forward declarations */
 static void set_of_1 (rtx, const_rtx, void *);
@@ -5438,3 +5439,371 @@ split_double (rtx value, rtx *first, rtx *second)
     }
 }
 
+/* Strip outer address "mutations" from LOC and return a pointer to the
+   inner value.  If OUTER_CODE is nonnull, store the code of the innermost
+   stripped expression there.
+
+   "Mutations" either convert between modes or apply some kind of
+   alignment.  */
+
+rtx *
+strip_address_mutations (rtx *loc, enum rtx_code *outer_code)
+{
+  for (;;)
+    {
+      enum rtx_code code = GET_CODE (*loc);
+      if (GET_RTX_CLASS (code) == RTX_UNARY)
+       /* Things like SIGN_EXTEND, ZERO_EXTEND and TRUNCATE can be
+          used to convert between pointer sizes.  */
+       loc = &XEXP (*loc, 0);
+      else if (code == AND && CONST_INT_P (XEXP (*loc, 1)))
+       /* (and ... (const_int -X)) is used to align to X bytes.  */
+       loc = &XEXP (*loc, 0);
+      else
+       return loc;
+      if (outer_code)
+       *outer_code = code;
+    }
+}
+
+/* Return true if X must be a base rather than an index.  */
+
+static bool
+must_be_base_p (rtx x)
+{
+  return GET_CODE (x) == LO_SUM;
+}
+
+/* Return true if X must be an index rather than a base.  */
+
+static bool
+must_be_index_p (rtx x)
+{
+  return GET_CODE (x) == MULT || GET_CODE (x) == ASHIFT;
+}
+
+/* Set the segment part of address INFO to LOC, given that INNER is the
+   unmutated value.  */
+
+static void
+set_address_segment (struct address_info *info, rtx *loc, rtx *inner)
+{
+  gcc_checking_assert (GET_CODE (*inner) == UNSPEC);
+
+  gcc_assert (!info->segment);
+  info->segment = loc;
+  info->segment_term = inner;
+}
+
+/* Set the base part of address INFO to LOC, given that INNER is the
+   unmutated value.  */
+
+static void
+set_address_base (struct address_info *info, rtx *loc, rtx *inner)
+{
+  if (GET_CODE (*inner) == LO_SUM)
+    inner = strip_address_mutations (&XEXP (*inner, 0));
+  gcc_checking_assert (REG_P (*inner)
+                      || MEM_P (*inner)
+                      || GET_CODE (*inner) == SUBREG);
+
+  gcc_assert (!info->base);
+  info->base = loc;
+  info->base_term = inner;
+}
+
+/* Set the index part of address INFO to LOC, given that INNER is the
+   unmutated value.  */
+
+static void
+set_address_index (struct address_info *info, rtx *loc, rtx *inner)
+{
+  if ((GET_CODE (*inner) == MULT || GET_CODE (*inner) == ASHIFT)
+      && CONSTANT_P (XEXP (*inner, 1)))
+    inner = strip_address_mutations (&XEXP (*inner, 0));
+  gcc_checking_assert (REG_P (*inner)
+                      || MEM_P (*inner)
+                      || GET_CODE (*inner) == SUBREG);
+
+  gcc_assert (!info->index);
+  info->index = loc;
+  info->index_term = inner;
+}
+
+/* Set the displacement part of address INFO to LOC, given that INNER
+   is the constant term.  */
+
+static void
+set_address_disp (struct address_info *info, rtx *loc, rtx *inner)
+{
+  gcc_checking_assert (CONSTANT_P (*inner));
+
+  gcc_assert (!info->disp);
+  info->disp = loc;
+  info->disp_term = inner;
+}
+
+/* INFO->INNER describes a {PRE,POST}_{INC,DEC} address.  Set up the
+   rest of INFO accordingly.  */
+
+static void
+decompose_incdec_address (struct address_info *info)
+{
+  info->autoinc_p = true;
+
+  rtx *base = &XEXP (*info->inner, 0);
+  set_address_base (info, base, base);
+  gcc_checking_assert (info->base == info->base_term);
+
+  /* These addresses are only valid when the size of the addressed
+     value is known.  */
+  gcc_checking_assert (info->mode != VOIDmode);
+}
+
+/* INFO->INNER describes a {PRE,POST}_MODIFY address.  Set up the rest
+   of INFO accordingly.  */
+
+static void
+decompose_automod_address (struct address_info *info)
+{
+  info->autoinc_p = true;
+
+  rtx *base = &XEXP (*info->inner, 0);
+  set_address_base (info, base, base);
+  gcc_checking_assert (info->base == info->base_term);
+
+  rtx plus = XEXP (*info->inner, 1);
+  gcc_assert (GET_CODE (plus) == PLUS);
+
+  info->base_term2 = &XEXP (plus, 0);
+  gcc_checking_assert (rtx_equal_p (*info->base_term, *info->base_term2));
+
+  rtx *step = &XEXP (plus, 1);
+  rtx *inner_step = strip_address_mutations (step);
+  if (CONSTANT_P (*inner_step))
+    set_address_disp (info, step, inner_step);
+  else
+    set_address_index (info, step, inner_step);
+}
+
+/* Treat *LOC as a tree of PLUS operands and store pointers to the summed
+   values in [PTR, END).  Return a pointer to the end of the used array.  */
+
+static rtx **
+extract_plus_operands (rtx *loc, rtx **ptr, rtx **end)
+{
+  rtx x = *loc;
+  if (GET_CODE (x) == PLUS)
+    {
+      ptr = extract_plus_operands (&XEXP (x, 0), ptr, end);
+      ptr = extract_plus_operands (&XEXP (x, 1), ptr, end);
+    }
+  else
+    {
+      gcc_assert (ptr != end);
+      *ptr++ = loc;
+    }
+  return ptr;
+}
+
+/* Evaluate the likelihood of X being a base or index value, returning
+   positive if it is likely to be a base, negative if it is likely to be
+   an index, and 0 if we can't tell.  Make the magnitude of the return
+   value reflect the amount of confidence we have in the answer.
+
+   MODE, AS, OUTER_CODE and INDEX_CODE are as for ok_for_base_p_1.  */
+
+static int
+baseness (rtx x, enum machine_mode mode, addr_space_t as,
+         enum rtx_code outer_code, enum rtx_code index_code)
+{
+  /* See whether we can be certain.  */
+  if (must_be_base_p (x))
+    return 3;
+  if (must_be_index_p (x))
+    return -3;
+
+  /* Believe *_POINTER unless the address shape requires otherwise.  */
+  if (REG_P (x) && REG_POINTER (x))
+    return 2;
+  if (MEM_P (x) && MEM_POINTER (x))
+    return 2;
+
+  if (REG_P (x) && HARD_REGISTER_P (x))
+    {
+      /* X is a hard register.  If it only fits one of the base
+        or index classes, choose that interpretation.  */
+      int regno = REGNO (x);
+      bool base_p = ok_for_base_p_1 (regno, mode, as, outer_code, index_code);
+      bool index_p = REGNO_OK_FOR_INDEX_P (regno);
+      if (base_p != index_p)
+       return base_p ? 1 : -1;
+    }
+  return 0;
+}
+
+/* INFO->INNER describes a normal, non-automodified address.
+   Fill in the rest of INFO accordingly.  */
+
+static void
+decompose_normal_address (struct address_info *info)
+{
+  /* Treat the address as the sum of up to four values.  */
+  rtx *ops[4];
+  size_t n_ops = extract_plus_operands (info->inner, ops,
+                                       ops + ARRAY_SIZE (ops)) - ops;
+
+  /* If there is more than one component, any base component is in a PLUS.  */
+  if (n_ops > 1)
+    info->base_outer_code = PLUS;
+
+  /* Separate the parts that contain a REG or MEM from those that don't.
+     Record the latter in INFO and leave the former in OPS.  */
+  rtx *inner_ops[4];
+  size_t out = 0;
+  for (size_t in = 0; in < n_ops; ++in)
+    {
+      rtx *loc = ops[in];
+      rtx *inner = strip_address_mutations (loc);
+      if (CONSTANT_P (*inner))
+       set_address_disp (info, loc, inner);
+      else if (GET_CODE (*inner) == UNSPEC)
+       set_address_segment (info, loc, inner);
+      else
+       {
+         ops[out] = loc;
+         inner_ops[out] = inner;
+         ++out;
+       }
+    }
+
+  /* Classify the remaining OPS members as bases and indexes.  */
+  if (out == 1)
+    {
+      /* Assume that the remaining value is a base unless the shape
+        requires otherwise.  */
+      if (!must_be_index_p (*inner_ops[0]))
+       set_address_base (info, ops[0], inner_ops[0]);
+      else
+       set_address_index (info, ops[0], inner_ops[0]);
+    }
+  else if (out == 2)
+    {
+      /* In the event of a tie, assume the base comes first.  */
+      if (baseness (*inner_ops[0], info->mode, info->as, PLUS,
+                   GET_CODE (*ops[1]))
+         >= baseness (*inner_ops[1], info->mode, info->as, PLUS,
+                      GET_CODE (*ops[0])))
+       {
+         set_address_base (info, ops[0], inner_ops[0]);
+         set_address_index (info, ops[1], inner_ops[1]);
+       }
+      else
+       {
+         set_address_base (info, ops[1], inner_ops[1]);
+         set_address_index (info, ops[0], inner_ops[0]);
+       }
+    }
+  else
+    gcc_assert (out == 0);
+}
+
+/* Describe address *LOC in *INFO.  MODE is the mode of the addressed value,
+   or VOIDmode if not known.  AS is the address space associated with LOC.
+   OUTER_CODE is MEM if *LOC is a MEM address and ADDRESS otherwise.  */
+
+void
+decompose_address (struct address_info *info, rtx *loc, enum machine_mode mode,
+                  addr_space_t as, enum rtx_code outer_code)
+{
+  memset (info, 0, sizeof (*info));
+  info->mode = mode;
+  info->as = as;
+  info->addr_outer_code = outer_code;
+  info->outer = loc;
+  info->inner = strip_address_mutations (loc, &outer_code);
+  info->base_outer_code = outer_code;
+  switch (GET_CODE (*info->inner))
+    {
+    case PRE_DEC:
+    case PRE_INC:
+    case POST_DEC:
+    case POST_INC:
+      decompose_incdec_address (info);
+      break;
+
+    case PRE_MODIFY:
+    case POST_MODIFY:
+      decompose_automod_address (info);
+      break;
+
+    default:
+      decompose_normal_address (info);
+      break;
+    }
+}
+
+/* Describe address operand LOC in INFO.  */
+
+void
+decompose_lea_address (struct address_info *info, rtx *loc)
+{
+  decompose_address (info, loc, VOIDmode, ADDR_SPACE_GENERIC, ADDRESS);
+}
+
+/* Describe the address of MEM X in INFO.  */
+
+void
+decompose_mem_address (struct address_info *info, rtx x)
+{
+  gcc_assert (MEM_P (x));
+  decompose_address (info, &XEXP (x, 0), GET_MODE (x),
+                    MEM_ADDR_SPACE (x), MEM);
+}
+
+/* Update INFO after a change to the address it describes.  */
+
+void
+update_address (struct address_info *info)
+{
+  decompose_address (info, info->outer, info->mode, info->as,
+                    info->addr_outer_code);
+}
+
+/* Return the scale applied to *INFO->INDEX_TERM, or 0 if the index is
+   more complicated than that.  */
+
+HOST_WIDE_INT
+get_index_scale (const struct address_info *info)
+{
+  rtx index = *info->index;
+  if (GET_CODE (index) == MULT
+      && CONST_INT_P (XEXP (index, 1))
+      && info->index_term == &XEXP (index, 0))
+    return INTVAL (XEXP (index, 1));
+
+  if (GET_CODE (index) == ASHIFT
+      && CONST_INT_P (XEXP (index, 1))
+      && info->index_term == &XEXP (index, 0))
+    return (HOST_WIDE_INT) 1 << INTVAL (XEXP (index, 1));
+
+  if (info->index == info->index_term)
+    return 1;
+
+  return 0;
+}
+
+/* Return the "index code" of INFO, in the form required by
+   ok_for_base_p_1.  */
+
+enum rtx_code
+get_index_code (const struct address_info *info)
+{
+  if (info->index)
+    return GET_CODE (*info->index);
+
+  if (info->disp)
+    return GET_CODE (*info->disp);
+
+  return SCRATCH;
+}