Index: gcc/Makefile.in
===================================================================
--- gcc/Makefile.in	2012-10-23 19:37:49.000000000 +0100
+++ gcc/Makefile.in	2012-10-25 16:44:11.913358869 +0100
@@ -2709,7 +2709,7 @@ print-rtl.o : print-rtl.c $(CONFIG_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: gcc/rtl.h
===================================================================
--- gcc/rtl.h	2012-10-25 13:47:00.397249906 +0100
+++ gcc/rtl.h	2012-10-25 13:47:29.482249833 +0100
@@ -1237,6 +1237,77 @@ costs_add_n_insns (struct full_rtx_costs
   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 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 (rt
 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: gcc/rtlanal.c
===================================================================
--- gcc/rtlanal.c	2012-10-25 13:47:00.396249906 +0100
+++ gcc/rtlanal.c	2012-10-25 14:27:20.161243984 +0100
@@ -38,6 +38,7 @@ Software Foundation; either version 3, o
 #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
     }
 }
 
+/* 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;
+}
Index: gcc/lra-constraints.c
===================================================================
--- gcc/lra-constraints.c	2012-10-25 13:47:00.396249906 +0100
+++ gcc/lra-constraints.c	2012-10-25 19:35:29.520333722 +0100
@@ -152,6 +152,13 @@
 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
 
 /* 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 m
   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;
-}
-
 
 
 /* The page contains major code to choose the current insn alternative
@@ -1356,11 +1042,13 @@ process_addr_reg (rtx *loc, rtx *before,
 {
   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))
     {
@@ -1540,21 +1228,13 @@ uses_hard_regs_p (rtx x, HARD_REG_SET se
     }
   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--)
@@ -2401,115 +2081,92 @@ valid_address_p (enum machine_mode mode
 #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, we can simply add the
-     new displacement to it.  */
-  if (ad->disp_loc)
-    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)
@@ -2520,53 +2177,53 @@ equiv_address_substitution (struct addre
     {
       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;
     }
@@ -2577,7 +2234,7 @@ equiv_address_substitution (struct addre
       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 addre
 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 equiv_address_substitution
 	applied a displacement that made it invalid.
@@ -2669,21 +2307,25 @@ process_address (int nop, rtx *before, r
 
      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
 	  {
@@ -2693,16 +2335,14 @@ process_address (int nop, rtx *before, r
 	    /* 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;
 		  }
 	      }
@@ -2713,25 +2353,25 @@ process_address (int nop, rtx *before, r
 	  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
@@ -2739,16 +2379,16 @@ process_address (int nop, rtx *before, r
 	 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 ();
