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


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

Patch: MODE_CODE_BASE_REG_CLASS


Now that we're in stage1 again, I'd like to dust off this patch which I proposed a while ago. The problem I'm trying to solve is that the Blackfin allows different register classes for register_offset and postincrement addressing modes, and we can't currently describe this to the compiler.

This introduces a MODE_CODE_BASE_REG_CLASS macro, to subsume the existing BASE_REG_CLASS, MODE_BASE_REG_CLASS and MODE_BASE_REG_REG_CLASS macros. Documentation can be found in the tm.texi diff. While I was there, I also tried to clean up the handling of strict/nonstrict addressing modes by moving this knowledge out of the machine-specific files - regclass got a few new functions.

I haven't checked this in - I'm still testing (it has been in our Blackfin 3.4 tree for a while without problems), and if possible I'd like someone else to review this for basic sanity. I'd also like explicit buy-in from the ARM folks who are currently the only users of MODE_BASE_REG_REG_CLASS - will this patch do the right thing on ARM in all cases?


Bernd
Index: regrename.c
===================================================================
--- regrename.c	(revision 107600)
+++ regrename.c	(working copy)
@@ -27,6 +27,7 @@
 #include "tm_p.h"
 #include "insn-config.h"
 #include "regs.h"
+#include "addresses.h"
 #include "hard-reg-set.h"
 #include "basic-block.h"
 #include "reload.h"
@@ -528,7 +529,7 @@
 	rtx op1 = orig_op1;
 	rtx *locI = NULL;
 	rtx *locB = NULL;
-	rtx *locB_reg = NULL;
+	enum rtx_code index_code;
 
 	if (GET_CODE (op0) == SUBREG)
 	  {
@@ -547,59 +548,70 @@
 	  {
 	    locI = &XEXP (x, 0);
 	    locB = &XEXP (x, 1);
+	    index_code = GET_CODE (*locI);
 	  }
 	else if (code1 == MULT || code1 == SIGN_EXTEND || code1 == TRUNCATE
 		 || code1 == ZERO_EXTEND || code0 == MEM)
 	  {
 	    locI = &XEXP (x, 1);
 	    locB = &XEXP (x, 0);
+	    index_code = GET_CODE (*locI);
 	  }
 	else if (code0 == CONST_INT || code0 == CONST
 		 || code0 == SYMBOL_REF || code0 == LABEL_REF)
-	  locB = &XEXP (x, 1);
+	  {
+	    locB = &XEXP (x, 1);
+	    index_code = GET_CODE (XEXP (x, 0));
+	  }
 	else if (code1 == CONST_INT || code1 == CONST
 		 || code1 == SYMBOL_REF || code1 == LABEL_REF)
-	  locB = &XEXP (x, 0);
+	  {
+	    locB = &XEXP (x, 0);
+	    index_code = GET_CODE (XEXP (x, 1));
+	  }
 	else if (code0 == REG && code1 == REG)
 	  {
 	    int index_op;
+	    unsigned regno0 = REGNO (op0), regno1 = REGNO (op1);
 
-	    if (REG_OK_FOR_INDEX_P (op0)
-		&& REG_MODE_OK_FOR_REG_BASE_P (op1, mode))
+	    if (REGNO_OK_FOR_INDEX_P (regno0)
+		&& regno_ok_for_base_p (regno1, mode, PLUS, REG))
 	      index_op = 0;
-	    else if (REG_OK_FOR_INDEX_P (op1)
-		     && REG_MODE_OK_FOR_REG_BASE_P (op0, mode))
+	    else if (REGNO_OK_FOR_INDEX_P (regno1)
+		     && regno_ok_for_base_p (regno0, mode, PLUS, REG))
 	      index_op = 1;
-	    else if (REG_MODE_OK_FOR_REG_BASE_P (op1, mode))
+	    else if (regno_ok_for_base_p (regno1, mode, PLUS, REG))
 	      index_op = 0;
-	    else if (REG_MODE_OK_FOR_REG_BASE_P (op0, mode))
+	    else if (regno_ok_for_base_p (regno0, mode, PLUS, REG))
 	      index_op = 1;
-	    else if (REG_OK_FOR_INDEX_P (op1))
+	    else if (REGNO_OK_FOR_INDEX_P (regno1))
 	      index_op = 1;
 	    else
 	      index_op = 0;
 
 	    locI = &XEXP (x, index_op);
-	    locB_reg = &XEXP (x, !index_op);
+	    locB = &XEXP (x, !index_op);
+	    index_code = GET_CODE (*locI);
 	  }
 	else if (code0 == REG)
 	  {
 	    locI = &XEXP (x, 0);
 	    locB = &XEXP (x, 1);
+	    index_code = GET_CODE (*locI);
 	  }
 	else if (code1 == REG)
 	  {
 	    locI = &XEXP (x, 1);
 	    locB = &XEXP (x, 0);
+	    index_code = GET_CODE (*locI);
 	  }
 
 	if (locI)
 	  scan_rtx_address (insn, locI, INDEX_REG_CLASS, action, mode);
 	if (locB)
-	  scan_rtx_address (insn, locB, MODE_BASE_REG_CLASS (mode), action, mode);
-	if (locB_reg)
-	  scan_rtx_address (insn, locB_reg, MODE_BASE_REG_REG_CLASS (mode),
+	  scan_rtx_address (insn, locB, base_reg_class (mode, PLUS, index_code),
 			    action, mode);
+
 	return;
       }
 
@@ -618,7 +630,7 @@
 
     case MEM:
       scan_rtx_address (insn, &XEXP (x, 0),
-			MODE_BASE_REG_CLASS (GET_MODE (x)), action,
+			base_reg_class (GET_MODE (x), MEM, SCRATCH), action,
 			GET_MODE (x));
       return;
 
@@ -669,7 +681,7 @@
 
     case MEM:
       scan_rtx_address (insn, &XEXP (x, 0),
-			MODE_BASE_REG_CLASS (GET_MODE (x)), action,
+			base_reg_class (GET_MODE (x), MEM, SCRATCH), action,
 			GET_MODE (x));
       return;
 
@@ -1441,7 +1453,7 @@
 	rtx op1 = orig_op1;
 	rtx *locI = NULL;
 	rtx *locB = NULL;
-	rtx *locB_reg = NULL;
+	enum rtx_code index_code;
 
 	if (GET_CODE (op0) == SUBREG)
 	  {
@@ -1460,50 +1472,62 @@
 	  {
 	    locI = &XEXP (x, 0);
 	    locB = &XEXP (x, 1);
+	    index_code = GET_CODE (*locI);
 	  }
 	else if (code1 == MULT || code1 == SIGN_EXTEND || code1 == TRUNCATE
 		 || code1 == ZERO_EXTEND || code0 == MEM)
 	  {
 	    locI = &XEXP (x, 1);
 	    locB = &XEXP (x, 0);
+	    index_code = GET_CODE (*locI);
 	  }
 	else if (code0 == CONST_INT || code0 == CONST
 		 || code0 == SYMBOL_REF || code0 == LABEL_REF)
-	  locB = &XEXP (x, 1);
+	  {
+	    locB = &XEXP (x, 1);
+	    index_code = GET_CODE (XEXP (x, 0));
+	  }
 	else if (code1 == CONST_INT || code1 == CONST
 		 || code1 == SYMBOL_REF || code1 == LABEL_REF)
-	  locB = &XEXP (x, 0);
+	  {
+	    locB = &XEXP (x, 0);
+	    index_code = GET_CODE (XEXP (x, 1));
+	  }
 	else if (code0 == REG && code1 == REG)
 	  {
 	    int index_op;
+	    unsigned regno0 = REGNO (op0), regno1 = REGNO (op1);
 
-	    if (REG_OK_FOR_INDEX_P (op0)
-		&& REG_MODE_OK_FOR_REG_BASE_P (op1, mode))
+	    if (REGNO_OK_FOR_INDEX_P (regno0)
+		&& regno_ok_for_base_p (regno1, mode, PLUS, REG))
 	      index_op = 0;
-	    else if (REG_OK_FOR_INDEX_P (op1)
-		     && REG_MODE_OK_FOR_REG_BASE_P (op0, mode))
+	    else if (REGNO_OK_FOR_INDEX_P (regno1)
+		     && regno_ok_for_base_p (regno0, mode, PLUS, REG))
 	      index_op = 1;
-	    else if (REG_MODE_OK_FOR_REG_BASE_P (op1, mode))
+	    else if (regno_ok_for_base_p (regno1, mode, PLUS, REG))
 	      index_op = 0;
-	    else if (REG_MODE_OK_FOR_REG_BASE_P (op0, mode))
+	    else if (regno_ok_for_base_p (regno0, mode, PLUS, REG))
 	      index_op = 1;
-	    else if (REG_OK_FOR_INDEX_P (op1))
+	    else if (REGNO_OK_FOR_INDEX_P (regno1))
 	      index_op = 1;
 	    else
 	      index_op = 0;
 
 	    locI = &XEXP (x, index_op);
-	    locB_reg = &XEXP (x, !index_op);
+	    locB = &XEXP (x, !index_op);
+	    index_code = GET_CODE (*locI);
 	  }
 	else if (code0 == REG)
 	  {
 	    locI = &XEXP (x, 0);
 	    locB = &XEXP (x, 1);
+	    index_code = GET_CODE (*locI);
 	  }
 	else if (code1 == REG)
 	  {
 	    locI = &XEXP (x, 1);
 	    locB = &XEXP (x, 0);
+	    index_code = GET_CODE (*locI);
 	  }
 
 	if (locI)
@@ -1511,12 +1535,9 @@
 						insn, vd);
 	if (locB)
 	  changed |= replace_oldest_value_addr (locB,
-						MODE_BASE_REG_CLASS (mode),
+						base_reg_class (mode, PLUS,
+								index_code),
 						mode, insn, vd);
-	if (locB_reg)
-	  changed |= replace_oldest_value_addr (locB_reg,
-						MODE_BASE_REG_REG_CLASS (mode),
-						mode, insn, vd);
 	return changed;
       }
 
@@ -1559,7 +1580,8 @@
 replace_oldest_value_mem (rtx x, rtx insn, struct value_data *vd)
 {
   return replace_oldest_value_addr (&XEXP (x, 0),
-				    MODE_BASE_REG_CLASS (GET_MODE (x)),
+				    base_reg_class (GET_MODE (x), MEM,
+						    SCRATCH),
 				    GET_MODE (x), insn, vd);
 }
 
Index: doc/tm.texi
===================================================================
--- doc/tm.texi	(revision 107600)
+++ doc/tm.texi	(working copy)
@@ -2267,6 +2267,16 @@
 addresses have different requirements than other base register uses.
 @end defmac
 
+@defmac MODE_CODE_BASE_REG_CLASS (@var{mode}, @var{outer_code}, @var{index_code})
+A C expression whose value is the register class to which a valid
+base register must belong.  @var{outer_code} and @var{index_code} define the
+context in which the base register occurs.  @var{outer_code} is the code of
+the immediately enclosing expression (@code{MEM} for the top level of an
+address, @code{ADDRESS} for something that occurs in an
+@code{address_operand}).  @var{index_code} is the code of the corresponding
+index expression if @var{outer_code} is @code{PLUS}; @code{SCRATCH} otherwise.
+@end defmac
+
 @defmac INDEX_REG_CLASS
 A macro whose definition is the name of the class to which a valid
 index register must belong.  An index register is one used in an
@@ -2317,7 +2327,9 @@
 @var{mode}.  You should define this macro if the mode of the memory
 reference affects whether a register may be used as a base register.  If
 you define this macro, the compiler will use it instead of
-@code{REGNO_OK_FOR_BASE_P}.
+@code{REGNO_OK_FOR_BASE_P}.  The mode may be @code{VOIDmode} for addresses
+that appear outside a @code{MEM}, i.e. as an @code{address_operand}.
+
 @end defmac
 
 @defmac REGNO_MODE_OK_FOR_REG_BASE_P (@var{num}, @var{mode})
@@ -2327,8 +2339,22 @@
 pseudo register that has been allocated such a hard register.  You should
 define this macro if base plus index addresses have different requirements
 than other base register uses.
+
+Use of this macro is deprecated; please use the more general
+@code{REGNO_MODE_CODE_OK_FOR_BASE_P}.
 @end defmac
 
+@defmac REGNO_MODE_CODE_OK_FOR_BASE_P (@var{num}, @var{mode}, @var{outer_code}, @var{index_code})
+A C expression that is just like @code{REGNO_MODE_OK_FOR_BASE_P}, except that
+that expression may examine the context in which the register appears in the
+memory reference.  @var{outer_code} is the code of the immediately enclosing
+expression (@code{MEM} if at the top level of the address, @code{ADDRESS} for
+something that occurs in an @code{address_operand}).  @var{index_code} is the
+code of the corresponding index expression if @var{outer_code} is @code{PLUS};
+@code{SCRATCH} otherwise.  The mode may be @code{VOIDmode} for addresses
+that appear outside a @code{MEM}, i.e. as an @code{address_operand}.
+@end defmac
+
 @defmac REGNO_OK_FOR_INDEX_P (@var{num})
 A C expression which is nonzero if register number @var{num} is
 suitable for use as an index register in operand addresses.  It may be
@@ -5008,48 +5034,6 @@
 Format}.
 @end defmac
 
-@defmac REG_OK_FOR_BASE_P (@var{x})
-A C expression that is nonzero if @var{x} (assumed to be a @code{reg}
-RTX) is valid for use as a base register.  For hard registers, it
-should always accept those which the hardware permits and reject the
-others.  Whether the macro accepts or rejects pseudo registers must be
-controlled by @code{REG_OK_STRICT} as described above.  This usually
-requires two variant definitions, of which @code{REG_OK_STRICT}
-controls the one actually used.
-@end defmac
-
-@defmac REG_MODE_OK_FOR_BASE_P (@var{x}, @var{mode})
-A C expression that is just like @code{REG_OK_FOR_BASE_P}, except that
-that expression may examine the mode of the memory reference in
-@var{mode}.  You should define this macro if the mode of the memory
-reference affects whether a register may be used as a base register.  If
-you define this macro, the compiler will use it instead of
-@code{REG_OK_FOR_BASE_P}.
-@end defmac
-
-@defmac REG_MODE_OK_FOR_REG_BASE_P (@var{x}, @var{mode})
-A C expression which is nonzero if @var{x} (assumed to be a @code{reg} RTX)
-is suitable for use as a base register in base plus index operand addresses,
-accessing memory in mode @var{mode}.  It may be either a suitable hard
-register or a pseudo register that has been allocated such a hard register.
-You should define this macro if base plus index addresses have different
-requirements than other base register uses.
-@end defmac
-
-@defmac REG_OK_FOR_INDEX_P (@var{x})
-A C expression that is nonzero if @var{x} (assumed to be a @code{reg}
-RTX) is valid for use as an index register.
-
-The difference between an index register and a base register is that
-the index register may be scaled.  If an address involves the sum of
-two registers, neither one of them scaled, then either one may be
-labeled the ``base'' and the other the ``index''; but whichever
-labeling is used must fit the machine's constraints of which registers
-may serve in each capacity.  The compiler will try both labelings,
-looking for one that is valid, and will reload one or both registers
-only if neither labeling works.
-@end defmac
-
 @defmac FIND_BASE_TERM (@var{x})
 A C expression to determine the base term of address @var{x}.
 This macro is used in only one place: `find_base_term' in alias.c.
Index: defaults.h
===================================================================
--- defaults.h	(revision 107600)
+++ defaults.h	(working copy)
@@ -607,40 +607,6 @@
 #define	TARGET_FLOAT_FORMAT	IEEE_FLOAT_FORMAT
 #endif
 
-/* Some macros can be defined by the backend in either a mode-dependent
-   or mode-independent form.  The compiler proper should only use the
-   mode-dependent form, providing VOIDmode when the mode is unknown.
-   We can't poison the macros because the backend may reference them.  */
-
-#ifndef REGNO_MODE_OK_FOR_BASE_P
-#define REGNO_MODE_OK_FOR_BASE_P(REGNO, MODE) REGNO_OK_FOR_BASE_P (REGNO)
-#endif
-
-#ifndef REG_MODE_OK_FOR_BASE_P
-#define REG_MODE_OK_FOR_BASE_P(REG, MODE) REG_OK_FOR_BASE_P (REG)
-#endif
-
-/* Determine the register class for registers suitable to be the base
-   address register in a MEM.  Allow the choice to be dependent upon
-   the mode of the memory access.  */
-#ifndef MODE_BASE_REG_CLASS
-#define MODE_BASE_REG_CLASS(MODE) BASE_REG_CLASS
-#endif
-
-/* Some machines require a different base register class if the index
-   is a register.  By default, assume that a base register is acceptable.  */
-#ifndef MODE_BASE_REG_REG_CLASS
-#define MODE_BASE_REG_REG_CLASS(MODE) MODE_BASE_REG_CLASS(MODE)
-#endif
-
-#ifndef REGNO_MODE_OK_FOR_REG_BASE_P
-#define REGNO_MODE_OK_FOR_REG_BASE_P(REGNO, MODE) REGNO_MODE_OK_FOR_BASE_P (REGNO, MODE)
-#endif
-
-#ifndef REG_MODE_OK_FOR_REG_BASE_P
-#define REG_MODE_OK_FOR_REG_BASE_P(REGNO, MODE) REG_MODE_OK_FOR_BASE_P (REGNO, MODE)
-#endif
-
 #ifndef LARGEST_EXPONENT_IS_NORMAL
 #define LARGEST_EXPONENT_IS_NORMAL(SIZE) 0
 #endif
Index: reload.c
===================================================================
--- reload.c	(revision 107600)
+++ reload.c	(working copy)
@@ -99,6 +99,7 @@
 #include "recog.h"
 #include "reload.h"
 #include "regs.h"
+#include "addresses.h"
 #include "hard-reg-set.h"
 #include "flags.h"
 #include "real.h"
@@ -268,7 +269,8 @@
 static rtx subst_reg_equivs (rtx, rtx);
 static rtx subst_indexed_address (rtx);
 static void update_auto_inc_notes (rtx, int, int);
-static int find_reloads_address_1 (enum machine_mode, rtx, int, rtx *,
+static int find_reloads_address_1 (enum machine_mode, rtx, int,
+				   enum rtx_code, enum rtx_code, rtx *,
 				   int, enum reload_type,int, rtx);
 static void find_reloads_address_part (rtx, rtx *, enum reg_class,
 				       enum machine_mode, int,
@@ -3118,7 +3120,8 @@
 	      case 'p':
 		/* All necessary reloads for an address_operand
 		   were handled in find_reloads_address.  */
-		this_alternative[i] = (int) MODE_BASE_REG_CLASS (VOIDmode);
+		this_alternative[i]
+		  = (int) base_reg_class (VOIDmode, ADDRESS, SCRATCH);
 		win = 1;
 		badop = 0;
 		break;
@@ -3322,7 +3325,8 @@
 
 			/* If we didn't already win, we can reload
 			   the address into a base register.  */
-			this_alternative[i] = (int) MODE_BASE_REG_CLASS (VOIDmode);
+			this_alternative[i]
+			  = (int) base_reg_class (VOIDmode, ADDRESS, SCRATCH);
 			badop = 0;
 			break;
 		      }
@@ -3825,7 +3829,7 @@
 	    operand_reloadnum[i]
 	      = push_reload (XEXP (recog_data.operand[i], 0), NULL_RTX,
 			     &XEXP (recog_data.operand[i], 0), (rtx*) 0,
-			     MODE_BASE_REG_CLASS (VOIDmode),
+			     base_reg_class (VOIDmode, MEM, SCRATCH),
 			     GET_MODE (XEXP (recog_data.operand[i], 0)),
 			     VOIDmode, 0, 0, i, RELOAD_FOR_INPUT);
 	    rld[operand_reloadnum[i]].inc
@@ -4744,12 +4748,12 @@
 	 subject of a CLOBBER in this insn.  */
 
       else if (regno < FIRST_PSEUDO_REGISTER
-	       && REGNO_MODE_OK_FOR_BASE_P (regno, mode)
+	       && regno_ok_for_base_p (regno, mode, MEM, SCRATCH)
 	       && ! regno_clobbered_p (regno, this_insn, mode, 0))
 	return 0;
 
       /* If we do not have one of the cases above, we must do the reload.  */
-      push_reload (ad, NULL_RTX, loc, (rtx*) 0, MODE_BASE_REG_CLASS (mode),
+      push_reload (ad, NULL_RTX, loc, (rtx*) 0, base_reg_class (mode, MEM, SCRATCH),
 		   GET_MODE (ad), VOIDmode, 0, 0, opnum, type);
       return 1;
     }
@@ -4850,7 +4854,7 @@
 	  /* Must use TEM here, not AD, since it is the one that will
 	     have any subexpressions reloaded, if needed.  */
 	  push_reload (tem, NULL_RTX, loc, (rtx*) 0,
-		       MODE_BASE_REG_CLASS (mode), GET_MODE (tem),
+		       base_reg_class (mode, MEM, SCRATCH), GET_MODE (tem),
 		       VOIDmode, 0,
 		       0, opnum, type);
 	  return ! removed_and;
@@ -4867,8 +4871,10 @@
   else if (GET_CODE (ad) == PLUS
 	   && REG_P (XEXP (ad, 0))
 	   && REGNO (XEXP (ad, 0)) < FIRST_PSEUDO_REGISTER
-	   && REG_MODE_OK_FOR_BASE_P (XEXP (ad, 0), mode)
-	   && GET_CODE (XEXP (ad, 1)) == CONST_INT)
+	   && GET_CODE (XEXP (ad, 1)) == CONST_INT
+	   && regno_ok_for_base_p (REGNO (XEXP (ad, 0)), mode, PLUS,
+				   CONST_INT))
+
     {
       /* Unshare the MEM rtx so we can safely alter it.  */
       if (memrefloc)
@@ -4896,7 +4902,8 @@
 	  /* If the sum of two regs is not necessarily valid,
 	     reload the sum into a base reg.
 	     That will at least work.  */
-	  find_reloads_address_part (ad, loc, MODE_BASE_REG_CLASS (mode),
+	  find_reloads_address_part (ad, loc,
+				     base_reg_class (mode, MEM, SCRATCH),
 				     Pmode, opnum, type, ind_levels);
 	}
       return ! removed_and;
@@ -4930,19 +4937,26 @@
 
   for (op_index = 0; op_index < 2; ++op_index)
     {
-      rtx operand;
+      rtx operand, addend;
+      enum rtx_code inner_code;
 
+      if (GET_CODE (ad) != PLUS)
+	  continue;
+
+      inner_code = GET_CODE (XEXP (ad, 0));
       if (!(GET_CODE (ad) == PLUS 
 	    && GET_CODE (XEXP (ad, 1)) == CONST_INT
-	    && (GET_CODE (XEXP (ad, 0)) == PLUS
-		|| GET_CODE (XEXP (ad, 0)) == LO_SUM)))
+	    && (inner_code == PLUS || inner_code == LO_SUM)))
 	continue;
 
       operand = XEXP (XEXP (ad, 0), op_index);
       if (!REG_P (operand) || REGNO (operand) >= FIRST_PSEUDO_REGISTER)
 	continue;
 
-      if ((REG_MODE_OK_FOR_BASE_P (operand, mode)
+      addend = XEXP (XEXP (ad, 0), 1 - op_index);
+
+      if ((regno_ok_for_base_p (REGNO (operand), mode, inner_code,
+				GET_CODE (addend))
 	   || operand == frame_pointer_rtx
 #if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
 	   || operand == hard_frame_pointer_rtx
@@ -4955,11 +4969,10 @@
 				       &XEXP (XEXP (ad, 0), 1 - op_index)))
 	{
 	  rtx offset_reg;
-	  rtx addend;
+	  enum reg_class cls;
 
 	  offset_reg = plus_constant (operand, INTVAL (XEXP (ad, 1)));
-	  addend = XEXP (XEXP (ad, 0), 1 - op_index);
-	  
+
 	  /* Form the adjusted address.  */
 	  if (GET_CODE (XEXP (ad, 0)) == PLUS)
 	    ad = gen_rtx_PLUS (GET_MODE (ad), 
@@ -4971,12 +4984,13 @@
 				 op_index == 0 ? addend : offset_reg);
 	  *loc = ad;
 
+	  cls = base_reg_class (mode, MEM, GET_CODE (addend));
 	  find_reloads_address_part (XEXP (ad, op_index), 
-				     &XEXP (ad, op_index),
-				     MODE_BASE_REG_CLASS (mode),
+				     &XEXP (ad, op_index), cls,
 				     GET_MODE (ad), opnum, type, ind_levels);
-	  find_reloads_address_1 (mode, 
-				  XEXP (ad, 1 - op_index), 1, 
+	  find_reloads_address_1 (mode,
+				  XEXP (ad, 1 - op_index), 1, GET_CODE (ad),
+				  GET_CODE (XEXP (ad, op_index)),
 				  &XEXP (ad, 1 - op_index), opnum,
 				  type, 0, insn);
 
@@ -5022,13 +5036,13 @@
 	    loc = &XEXP (*loc, 0);
 	}
 
-      find_reloads_address_part (ad, loc, MODE_BASE_REG_CLASS (mode),
+      find_reloads_address_part (ad, loc, base_reg_class (mode, MEM, SCRATCH),
 				 Pmode, opnum, type, ind_levels);
       return ! removed_and;
     }
 
-  return find_reloads_address_1 (mode, ad, 0, loc, opnum, type, ind_levels,
-				 insn);
+  return find_reloads_address_1 (mode, ad, 0, MEM, SCRATCH, loc, opnum, type,
+				 ind_levels, insn);
 }
 
 /* Find all pseudo regs appearing in AD
@@ -5239,9 +5253,12 @@
    is strictly valid.)
 
    CONTEXT = 1 means we are considering regs as index regs,
-   = 0 means we are considering them as base regs, = 2 means we
-   are considering them as base regs for REG + REG.
-
+   = 0 means we are considering them as base regs.
+   OUTER_CODE is the code of the enclosing RTX, typically a MEM, a PLUS,
+   or an autoinc code.
+   If CONTEXT == 0 and OUTER_CODE is a PLUS or LO_SUM, then INDEX_CODE
+   is the code of the index part of the address.  Otherwise, pass SCRATCH
+   for this argument.
    OPNUM and TYPE specify the purpose of any reloads made.
 
    IND_LEVELS says how many levels of indirect addressing are
@@ -5262,25 +5279,22 @@
 
 static int
 find_reloads_address_1 (enum machine_mode mode, rtx x, int context,
+			enum rtx_code outer_code, enum rtx_code index_code,
 			rtx *loc, int opnum, enum reload_type type,
 			int ind_levels, rtx insn)
 {
-#define REG_OK_FOR_CONTEXT(CONTEXT, REGNO, MODE)		\
-  ((CONTEXT) == 2					\
-   ? REGNO_MODE_OK_FOR_REG_BASE_P (REGNO, MODE)		\
-   : (CONTEXT) == 1					\
-   ? REGNO_OK_FOR_INDEX_P (REGNO)			\
-   : REGNO_MODE_OK_FOR_BASE_P (REGNO, MODE))
+#define REG_OK_FOR_CONTEXT(CONTEXT, REGNO, MODE, OUTER, INDEX)		\
+  ((CONTEXT) == 0							\
+   ? regno_ok_for_base_p (REGNO, MODE, OUTER, INDEX)			\
+   : REGNO_OK_FOR_INDEX_P (REGNO))					
 
   enum reg_class context_reg_class;
   RTX_CODE code = GET_CODE (x);
 
-  if (context == 2)
-    context_reg_class = MODE_BASE_REG_REG_CLASS (mode);
-  else if (context == 1)
+  if (context == 1)
     context_reg_class = INDEX_REG_CLASS;
   else
-    context_reg_class = MODE_BASE_REG_CLASS (mode);
+    context_reg_class = base_reg_class (mode, outer_code, index_code);
 
   switch (code)
     {
@@ -5337,74 +5351,90 @@
 	if (code0 == MULT || code0 == SIGN_EXTEND || code0 == TRUNCATE
 	    || code0 == ZERO_EXTEND || code1 == MEM)
 	  {
-	    find_reloads_address_1 (mode, orig_op0, 1, &XEXP (x, 0), opnum,
-				    type, ind_levels, insn);
-	    find_reloads_address_1 (mode, orig_op1, 0, &XEXP (x, 1), opnum,
-				    type, ind_levels, insn);
+	    find_reloads_address_1 (mode, orig_op0, 1, PLUS, SCRATCH,
+				    &XEXP (x, 0), opnum, type, ind_levels,
+				    insn);
+	    find_reloads_address_1 (mode, orig_op1, 0, PLUS, code0,
+				    &XEXP (x, 1), opnum, type, ind_levels,
+				    insn);
 	  }
 
 	else if (code1 == MULT || code1 == SIGN_EXTEND || code1 == TRUNCATE
 		 || code1 == ZERO_EXTEND || code0 == MEM)
 	  {
-	    find_reloads_address_1 (mode, orig_op0, 0, &XEXP (x, 0), opnum,
-				    type, ind_levels, insn);
-	    find_reloads_address_1 (mode, orig_op1, 1, &XEXP (x, 1), opnum,
-				    type, ind_levels, insn);
+	    find_reloads_address_1 (mode, orig_op0, 0, PLUS, code1,
+				    &XEXP (x, 0), opnum, type, ind_levels,
+				    insn);
+	    find_reloads_address_1 (mode, orig_op1, 1, PLUS, SCRATCH,
+				    &XEXP (x, 1), opnum, type, ind_levels,
+				    insn);
 	  }
 
 	else if (code0 == CONST_INT || code0 == CONST
 		 || code0 == SYMBOL_REF || code0 == LABEL_REF)
-	  find_reloads_address_1 (mode, orig_op1, 0, &XEXP (x, 1), opnum,
-				  type, ind_levels, insn);
+	  find_reloads_address_1 (mode, orig_op1, 0, PLUS, code0,
+				  &XEXP (x, 1), opnum, type, ind_levels,
+				  insn);
 
 	else if (code1 == CONST_INT || code1 == CONST
 		 || code1 == SYMBOL_REF || code1 == LABEL_REF)
-	  find_reloads_address_1 (mode, orig_op0, 0, &XEXP (x, 0), opnum,
-				  type, ind_levels, insn);
+	  find_reloads_address_1 (mode, orig_op0, 0, PLUS, code1,
+				  &XEXP (x, 0), opnum, type, ind_levels,
+				  insn);
 
 	else if (code0 == REG && code1 == REG)
 	  {
-	    if (REG_OK_FOR_INDEX_P (op0)
-		&& REG_MODE_OK_FOR_REG_BASE_P (op1, mode))
+	    if (REGNO_OK_FOR_INDEX_P (REGNO (op0))
+		&& regno_ok_for_base_p (REGNO (op1), mode, PLUS, REG))
 	      return 0;
-	    else if (REG_OK_FOR_INDEX_P (op1)
-		     && REG_MODE_OK_FOR_REG_BASE_P (op0, mode))
+	    else if (REGNO_OK_FOR_INDEX_P (REGNO (op1))
+		     && regno_ok_for_base_p (REGNO (op0), mode, PLUS, REG))
 	      return 0;
-	    else if (REG_MODE_OK_FOR_REG_BASE_P (op1, mode))
-	      find_reloads_address_1 (mode, orig_op0, 1, &XEXP (x, 0), opnum,
-				      type, ind_levels, insn);
-	    else if (REG_MODE_OK_FOR_REG_BASE_P (op0, mode))
-	      find_reloads_address_1 (mode, orig_op1, 1, &XEXP (x, 1), opnum,
-				      type, ind_levels, insn);
-	    else if (REG_OK_FOR_INDEX_P (op1))
-	      find_reloads_address_1 (mode, orig_op0, 2, &XEXP (x, 0), opnum,
-				      type, ind_levels, insn);
-	    else if (REG_OK_FOR_INDEX_P (op0))
-	      find_reloads_address_1 (mode, orig_op1, 2, &XEXP (x, 1), opnum,
-				      type, ind_levels, insn);
+	    else if (regno_ok_for_base_p (REGNO (op1), mode, PLUS, REG))
+	      find_reloads_address_1 (mode, orig_op0, 1, PLUS, SCRATCH,
+				      &XEXP (x, 0), opnum, type, ind_levels,
+				      insn);
+	    else if (regno_ok_for_base_p (REGNO (op0), mode, PLUS, REG))
+	      find_reloads_address_1 (mode, orig_op1, 1, PLUS, SCRATCH,
+				      &XEXP (x, 1), opnum, type, ind_levels,
+				      insn);
+	    else if (REGNO_OK_FOR_INDEX_P (REGNO (op1)))
+	      find_reloads_address_1 (mode, orig_op0, 0, PLUS, REG,
+				      &XEXP (x, 0), opnum, type, ind_levels,
+				      insn);
+	    else if (REGNO_OK_FOR_INDEX_P (REGNO (op0)))
+	      find_reloads_address_1 (mode, orig_op1, 0, PLUS, REG,
+				      &XEXP (x, 1), opnum, type, ind_levels,
+				      insn);
 	    else
 	      {
-		find_reloads_address_1 (mode, orig_op0, 1, &XEXP (x, 0), opnum,
-					type, ind_levels, insn);
-		find_reloads_address_1 (mode, orig_op1, 0, &XEXP (x, 1), opnum,
-					type, ind_levels, insn);
+		find_reloads_address_1 (mode, orig_op0, 1, PLUS, SCRATCH,
+					&XEXP (x, 0), opnum, type, ind_levels,
+					insn);
+		find_reloads_address_1 (mode, orig_op1, 0, PLUS, REG,
+					&XEXP (x, 1), opnum, type, ind_levels,
+					insn);
 	      }
 	  }
 
 	else if (code0 == REG)
 	  {
-	    find_reloads_address_1 (mode, orig_op0, 1, &XEXP (x, 0), opnum,
-				    type, ind_levels, insn);
-	    find_reloads_address_1 (mode, orig_op1, 0, &XEXP (x, 1), opnum,
-				    type, ind_levels, insn);
+	    find_reloads_address_1 (mode, orig_op0, 1, PLUS, SCRATCH,
+				    &XEXP (x, 0), opnum, type, ind_levels,
+				    insn);
+	    find_reloads_address_1 (mode, orig_op1, 0, PLUS, REG,
+				    &XEXP (x, 1), opnum, type, ind_levels,
+				    insn);
 	  }
 
 	else if (code1 == REG)
 	  {
-	    find_reloads_address_1 (mode, orig_op1, 1, &XEXP (x, 1), opnum,
-				    type, ind_levels, insn);
-	    find_reloads_address_1 (mode, orig_op0, 0, &XEXP (x, 0), opnum,
-				    type, ind_levels, insn);
+	    find_reloads_address_1 (mode, orig_op1, 1, PLUS, SCRATCH,
+				    &XEXP (x, 1), opnum, type, ind_levels,
+				    insn);
+	    find_reloads_address_1 (mode, orig_op0, 0, PLUS, REG,
+				    &XEXP (x, 0), opnum, type, ind_levels,
+				    insn);
 	  }
       }
 
@@ -5415,6 +5445,7 @@
       {
 	rtx op0 = XEXP (x, 0);
 	rtx op1 = XEXP (x, 1);
+	enum rtx_code index_code;
 	int regno;
 	int reloadnum;
 
@@ -5433,12 +5464,14 @@
 	   register with its equivalent constant where applicable.  */
 	if (REG_P (XEXP (op1, 1)))
 	  if (!REGNO_OK_FOR_INDEX_P (REGNO (XEXP (op1, 1))))
-	    find_reloads_address_1 (mode, XEXP (op1, 1), 1, &XEXP (op1, 1),
-				    opnum, type, ind_levels, insn);
+	    find_reloads_address_1 (mode, XEXP (op1, 1), 1, code, SCRATCH,
+				    &XEXP (op1, 1), opnum, type, ind_levels,
+				    insn);
 
 	gcc_assert (REG_P (XEXP (op1, 0)));
 
 	regno = REGNO (XEXP (op1, 0));
+	index_code = GET_CODE (XEXP (op1, 1));
 
 	/* A register that is incremented cannot be constant!  */
 	gcc_assert (regno < FIRST_PSEUDO_REGISTER
@@ -5465,12 +5498,13 @@
 				      ind_levels, insn);
 
 		/* Then reload the memory location into a base
-		    register.  */
+		   register.  */
 		reloadnum = push_reload (tem, tem, &XEXP (x, 0),
-					  &XEXP (op1, 0),
-					  MODE_BASE_REG_CLASS (mode),
-					  GET_MODE (x), GET_MODE (x), 0,
-					  0, opnum, RELOAD_OTHER);
+					 &XEXP (op1, 0),
+					 base_reg_class (mode, code,
+							 index_code),
+					 GET_MODE (x), GET_MODE (x), 0,
+					 0, opnum, RELOAD_OTHER);
 
 		update_auto_inc_notes (this_insn, regno, reloadnum);
 		return 0;
@@ -5481,13 +5515,13 @@
 	  regno = reg_renumber[regno];
 
 	/* We require a base register here...  */
-	if (!REGNO_MODE_OK_FOR_BASE_P (regno, GET_MODE (x)))
+	if (!regno_ok_for_base_p (regno, GET_MODE (x), code, index_code))
 	  {
 	    reloadnum = push_reload (XEXP (op1, 0), XEXP (x, 0),
-				      &XEXP (op1, 0), &XEXP (x, 0),
-				      MODE_BASE_REG_CLASS (mode),
-				      GET_MODE (x), GET_MODE (x), 0, 0,
-				      opnum, RELOAD_OTHER);
+				     &XEXP (op1, 0), &XEXP (x, 0),
+				     base_reg_class (mode, code, index_code),
+				     GET_MODE (x), GET_MODE (x), 0, 0,
+				     opnum, RELOAD_OTHER);
 
 	    update_auto_inc_notes (this_insn, regno, reloadnum);
 	    return 0;
@@ -5545,7 +5579,8 @@
 	  if (reg_renumber[regno] >= 0)
 	    regno = reg_renumber[regno];
 	  if (regno >= FIRST_PSEUDO_REGISTER
-	      || !REG_OK_FOR_CONTEXT (context, regno, mode))
+	      || !REG_OK_FOR_CONTEXT (context, regno, mode, outer_code,
+				      index_code))
 	    {
 	      int reloadnum;
 
@@ -5652,8 +5687,8 @@
 	 reloaded.  Targets that are better off reloading just either part
 	 (or perhaps even a different part of an outer expression), should
 	 define LEGITIMIZE_RELOAD_ADDRESS.  */
-      find_reloads_address_1 (GET_MODE (XEXP (x, 0)), XEXP (x, 0),
-			      context, &XEXP (x, 0), opnum,
+      find_reloads_address_1 (GET_MODE (XEXP (x, 0)), XEXP (x, 0), context,
+			      code, SCRATCH, &XEXP (x, 0), opnum,
 			      type, ind_levels, insn);
       push_reload (x, NULL_RTX, loc, (rtx*) 0,
 		   context_reg_class,
@@ -5721,7 +5756,8 @@
 	  regno = reg_renumber[regno];
 
 	if (regno >= FIRST_PSEUDO_REGISTER
-	    || !REG_OK_FOR_CONTEXT (context, regno, mode))
+	    || !REG_OK_FOR_CONTEXT (context, regno, mode, outer_code,
+				    index_code))
 	  {
 	    push_reload (x, NULL_RTX, loc, (rtx*) 0,
 			 context_reg_class,
@@ -5753,7 +5789,8 @@
 	    {
 	      int regno ATTRIBUTE_UNUSED = subreg_regno (x);
 
-	      if (! REG_OK_FOR_CONTEXT (context, regno, mode))
+	      if (!REG_OK_FOR_CONTEXT (context, regno, mode, outer_code,
+				       index_code))
 		{
 		  push_reload (x, NULL_RTX, loc, (rtx*) 0,
 			       context_reg_class,
@@ -5791,8 +5828,10 @@
     for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
       {
 	if (fmt[i] == 'e')
-	  find_reloads_address_1 (mode, XEXP (x, i), context, &XEXP (x, i),
-				  opnum, type, ind_levels, insn);
+	  /* Pass SCRATCH for INDEX_CODE, since CODE can never be a PLUS once
+	     we get here.  */
+	  find_reloads_address_1 (mode, XEXP (x, i), context, code, SCRATCH,
+				  &XEXP (x, i), opnum, type, ind_levels, insn);
       }
   }
 
Index: caller-save.c
===================================================================
--- caller-save.c	(revision 107600)
+++ caller-save.c	(working copy)
@@ -25,6 +25,7 @@
 #include "tm.h"
 #include "rtl.h"
 #include "regs.h"
+#include "addresses.h"
 #include "insn-config.h"
 #include "flags.h"
 #include "hard-reg-set.h"
@@ -153,7 +154,7 @@
   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
     if (TEST_HARD_REG_BIT
 	(reg_class_contents
-	 [(int) MODE_BASE_REG_CLASS (regno_save_mode [i][1])], i))
+	 [(int) base_reg_class (regno_save_mode [i][1], PLUS, CONST_INT)], i))
       break;
 
   gcc_assert (i < FIRST_PSEUDO_REGISTER);
Index: recog.c
===================================================================
--- recog.c	(revision 107600)
+++ recog.c	(working copy)
@@ -31,6 +31,7 @@
 #include "hard-reg-set.h"
 #include "recog.h"
 #include "regs.h"
+#include "addresses.h"
 #include "expr.h"
 #include "function.h"
 #include "flags.h"
@@ -2205,7 +2206,7 @@
 		case 'p':
 		  op_alt[j].is_address = 1;
 		  op_alt[j].cl = reg_class_subunion[(int) op_alt[j].cl]
-		    [(int) MODE_BASE_REG_CLASS (VOIDmode)];
+		      [(int) base_reg_class (VOIDmode, ADDRESS, SCRATCH)];
 		  break;
 
 		case 'g':
@@ -2226,7 +2227,8 @@
 		      op_alt[j].cl
 			= (reg_class_subunion
 			   [(int) op_alt[j].cl]
-			   [(int) MODE_BASE_REG_CLASS (VOIDmode)]);
+			   [(int) base_reg_class (VOIDmode, ADDRESS,
+						  SCRATCH)]);
 		      break;
 		    }
 
Index: regclass.c
===================================================================
--- regclass.c	(revision 107600)
+++ regclass.c	(working copy)
@@ -36,6 +36,7 @@
 #include "flags.h"
 #include "basic-block.h"
 #include "regs.h"
+#include "addresses.h"
 #include "function.h"
 #include "insn-config.h"
 #include "recog.h"
@@ -861,12 +862,36 @@
 				struct reg_pref *);
 static int copy_cost (rtx, enum machine_mode, enum reg_class, int,
 		      secondary_reload_info *);
-static void record_address_regs (rtx, enum reg_class, int);
+static void record_address_regs (enum machine_mode, rtx, int, enum rtx_code,
+				 enum rtx_code, int);
 #ifdef FORBIDDEN_INC_DEC_CLASSES
 static int auto_inc_dec_reg_p (rtx, enum machine_mode);
 #endif
 static void reg_scan_mark_refs (rtx, rtx, int, unsigned int);
 
+/* Wrapper around REGNO_OK_FOR_INDEX_P, to allow pseudo registers.  */
+
+static inline bool
+ok_for_index_p_nonstrict (rtx reg)
+{
+  unsigned regno = REGNO (reg);
+  return regno >= FIRST_PSEUDO_REGISTER || REGNO_OK_FOR_INDEX_P (regno);
+}
+
+/* A version of regno_ok_for_base_p for use during regclass, when all pseudos
+   should count as OK.  Arguments as for regno_ok_for_base_p.  */
+
+static inline bool
+ok_for_base_p_nonstrict (rtx reg, enum machine_mode mode,
+			 enum rtx_code outer_code, enum rtx_code index_code)
+{
+  unsigned regno = REGNO (reg);
+  if (regno >= FIRST_PSEUDO_REGISTER)
+    return true;
+
+  return ok_for_base_p_1 (regno, mode, outer_code, index_code);
+}
+
 /* Return the reg_class in which pseudo reg number REGNO is best allocated.
    This function is sometimes called before the info has been computed.
    When that happens, just return GENERAL_REGS, which is innocuous.  */
@@ -967,12 +992,13 @@
 	recog_data.operand[i] = SUBREG_REG (recog_data.operand[i]);
 
       if (MEM_P (recog_data.operand[i]))
-	record_address_regs (XEXP (recog_data.operand[i], 0),
-			     MODE_BASE_REG_CLASS (modes[i]), frequency * 2);
+	record_address_regs (GET_MODE (recog_data.operand[i]),
+			     XEXP (recog_data.operand[i], 0),
+			     0, MEM, SCRATCH, frequency * 2);
       else if (constraints[i][0] == 'p'
 	       || EXTRA_ADDRESS_CONSTRAINT (constraints[i][0], constraints[i]))
-	record_address_regs (recog_data.operand[i],
-			     MODE_BASE_REG_CLASS (modes[i]), frequency * 2);
+	record_address_regs (VOIDmode, recog_data.operand[i], 0, ADDRESS,
+			     SCRATCH, frequency * 2);
     }
 
   /* Check for commutative in a separate loop so everything will
@@ -1046,8 +1072,8 @@
 	-= (MEMORY_MOVE_COST (GET_MODE (SET_DEST (set)),
 			      GENERAL_REGS, 1)
 	    * frequency);
-      record_address_regs (XEXP (SET_SRC (set), 0),
-			   MODE_BASE_REG_CLASS (VOIDmode), frequency * 2);
+      record_address_regs (GET_MODE (SET_SRC (set)), XEXP (SET_SRC (set), 0),
+			   0, MEM, SCRATCH, frequency * 2);
       return insn;
     }
 
@@ -1157,14 +1183,21 @@
 		 m = (enum machine_mode) ((int) m + 1))
 	      if (HARD_REGNO_MODE_OK (j, m))
 		{
-		  enum reg_class base_class = MODE_BASE_REG_CLASS (VOIDmode);
+		  enum reg_class base_class;
 
+		  /* ??? There are two assumptions here; that the base class does not
+		     depend on the exact outer code (POST_INC vs. PRE_INC etc.), and
+		     that it does not depend on the machine mode of the memory
+		     reference.  */
+		  base_class = base_reg_class (VOIDmode, POST_INC, SCRATCH);
+
 		  PUT_MODE (r, m);
 
 		  /* If a register is not directly suitable for an
-		     auto-increment or decrement addressing mode and
-		     requires secondary reloads, disallow its class from
-		     being used in such addresses.  */
+		     auto-increment or decrement addressing mode and moving
+		     it to a proper base register requires secondary reloads,
+		     disallow its class from being used in such addresses,
+		     since reload can't handle that case.  */
 
 		  if ((secondary_reload_class (1, base_class, m, r)
 		       || secondary_reload_class (1, base_class, m, r))
@@ -1553,7 +1586,7 @@
 		     address, i.e. BASE_REG_CLASS.  */
 		  classes[i]
 		    = reg_class_subunion[(int) classes[i]]
-		      [(int) MODE_BASE_REG_CLASS (VOIDmode)];
+		    [(int) base_reg_class (VOIDmode, ADDRESS, SCRATCH)];
 		  break;
 
 		case 'm':  case 'o':  case 'V':
@@ -1667,7 +1700,7 @@
 			 address, i.e. BASE_REG_CLASS.  */
 		      classes[i]
 			= reg_class_subunion[(int) classes[i]]
-			  [(int) MODE_BASE_REG_CLASS (VOIDmode)];
+			[(int) base_reg_class (VOIDmode, ADDRESS, SCRATCH)];
 		    }
 #endif
 		  break;
@@ -1899,17 +1932,29 @@
 /* Record the pseudo registers we must reload into hard registers
    in a subexpression of a memory address, X.
 
-   CLASS is the class that the register needs to be in and is either
-   BASE_REG_CLASS or INDEX_REG_CLASS.
+   If CONTEXT is 0, 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.  These three arguments are
+   passed down to base_reg_class.
+
    SCALE is twice the amount to multiply the cost by (it is twice so we
    can represent half-cost adjustments).  */
 
 static void
-record_address_regs (rtx x, enum reg_class class, int scale)
+record_address_regs (enum machine_mode mode, rtx x, int context,
+		     enum rtx_code outer_code, enum rtx_code index_code,
+		     int scale)
 {
   enum rtx_code code = GET_CODE (x);
+  enum reg_class class;
 
+  if (context == 1)
+    class = INDEX_REG_CLASS;
+  else
+    class = base_reg_class (mode, outer_code, index_code);
+
   switch (code)
     {
     case CONST_INT:
@@ -1949,31 +1994,31 @@
 	   be in the first operand.  */
 
 	if (MAX_REGS_PER_ADDRESS == 1)
-	  record_address_regs (arg0, class, scale);
+	  record_address_regs (mode, arg0, 0, PLUS, code1, scale);
 
 	/* 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 == MODE_BASE_REG_CLASS (VOIDmode))
+	else if (INDEX_REG_CLASS == base_reg_class (VOIDmode, PLUS, SCRATCH))
 	  {
-	    record_address_regs (arg0, class, scale);
+	    record_address_regs (mode, arg0, context, PLUS, code1, scale);
 	    if (! CONSTANT_P (arg1))
-	      record_address_regs (arg1, class, scale);
+	      record_address_regs (mode, arg1, context, PLUS, code0, scale);
 	  }
 
 	/* If the second operand is a constant integer, it doesn't change
 	   what class the first operand must be.  */
 
 	else if (code1 == CONST_INT || code1 == CONST_DOUBLE)
-	  record_address_regs (arg0, class, scale);
+	  record_address_regs (mode, arg0, context, PLUS, code1, scale);
 
 	/* If the second operand is a symbolic constant, the first operand
 	   must be an index register.  */
 
 	else if (code1 == SYMBOL_REF || code1 == CONST || code1 == LABEL_REF)
-	  record_address_regs (arg0, INDEX_REG_CLASS, scale);
+	  record_address_regs (mode, arg0, 1, PLUS, code1, scale);
 
 	/* 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
@@ -1981,22 +2026,20 @@
 
 	else if (code0 == REG && code1 == REG
 		 && REGNO (arg0) < FIRST_PSEUDO_REGISTER
-		 && (REG_MODE_OK_FOR_REG_BASE_P (arg0, VOIDmode)
-		     || REG_OK_FOR_INDEX_P (arg0)))
-	  record_address_regs (arg1,
-			       REG_MODE_OK_FOR_REG_BASE_P (arg0, VOIDmode)
-			       ? INDEX_REG_CLASS
-			       : MODE_BASE_REG_REG_CLASS (VOIDmode),
-			       scale);
+		 && (ok_for_base_p_nonstrict (arg0, mode, PLUS, REG)
+		     || ok_for_index_p_nonstrict (arg0)))
+	  record_address_regs (mode, arg1,
+			       ok_for_base_p_nonstrict (arg0, mode, PLUS, REG)
+			       ? 1 : 0,
+			       PLUS, REG, scale);
 	else if (code0 == REG && code1 == REG
 		 && REGNO (arg1) < FIRST_PSEUDO_REGISTER
-		 && (REG_MODE_OK_FOR_REG_BASE_P (arg1, VOIDmode)
-		     || REG_OK_FOR_INDEX_P (arg1)))
-	  record_address_regs (arg0,
-			       REG_MODE_OK_FOR_REG_BASE_P (arg1, VOIDmode)
-			       ? INDEX_REG_CLASS
-			       : MODE_BASE_REG_REG_CLASS (VOIDmode),
-			       scale);
+		 && (ok_for_base_p_nonstrict (arg1, mode, PLUS, REG)
+		     || ok_for_index_p_nonstrict (arg1)))
+	  record_address_regs (mode, arg0,
+			       ok_for_base_p_nonstrict (arg1, mode, PLUS, REG)
+			       ? 1 : 0,
+			       PLUS, REG, scale);
 
 	/* If one operand is known to be a pointer, it must be the base
 	   with the other operand the index.  Likewise if the other operand
@@ -2005,16 +2048,14 @@
 	else if ((code0 == REG && REG_POINTER (arg0))
 		 || code1 == MULT)
 	  {
-	    record_address_regs (arg0, MODE_BASE_REG_REG_CLASS (VOIDmode),
-				 scale);
-	    record_address_regs (arg1, INDEX_REG_CLASS, scale);
+	    record_address_regs (mode, arg0, 0, PLUS, code1, scale);
+	    record_address_regs (mode, arg1, 1, PLUS, code0, scale);
 	  }
 	else if ((code1 == REG && REG_POINTER (arg1))
 		 || code0 == MULT)
 	  {
-	    record_address_regs (arg0, INDEX_REG_CLASS, scale);
-	    record_address_regs (arg1, MODE_BASE_REG_REG_CLASS (VOIDmode),
-				 scale);
+	    record_address_regs (mode, arg0, 1, PLUS, code1, scale);
+	    record_address_regs (mode, arg1, 0, PLUS, code0, scale);
 	  }
 
 	/* Otherwise, count equal chances that each might be a base
@@ -2022,12 +2063,10 @@
 
 	else
 	  {
-	    record_address_regs (arg0, MODE_BASE_REG_REG_CLASS (VOIDmode),
-				 scale / 2);
-	    record_address_regs (arg0, INDEX_REG_CLASS, scale / 2);
-	    record_address_regs (arg1, MODE_BASE_REG_REG_CLASS (VOIDmode),
-				 scale / 2);
-	    record_address_regs (arg1, INDEX_REG_CLASS, scale / 2);
+	    record_address_regs (mode, arg0, 0, PLUS, code1, scale / 2);
+	    record_address_regs (mode, arg0, 1, PLUS, code1, scale / 2);
+	    record_address_regs (mode, arg1, 0, PLUS, code0, scale / 2);
+	    record_address_regs (mode, arg1, 1, PLUS, code0, scale / 2);
 	  }
       }
       break;
@@ -2037,11 +2076,11 @@
 	 if it ends up in the wrong place.  */
     case POST_MODIFY:
     case PRE_MODIFY:
-      record_address_regs (XEXP (x, 0), MODE_BASE_REG_CLASS (VOIDmode),
-			   2 * scale);
+      record_address_regs (mode, XEXP (x, 0), 0, code,
+			   GET_CODE (XEXP (XEXP (x, 1), 1)), 2 * scale);
       if (REG_P (XEXP (XEXP (x, 1), 1)))
-	record_address_regs (XEXP (XEXP (x, 1), 1),
-			     INDEX_REG_CLASS, 2 * scale);
+	record_address_regs (mode, XEXP (XEXP (x, 1), 1), 1, code, REG,
+			     2 * scale);
       break;
 
     case POST_INC:
@@ -2059,7 +2098,7 @@
 	in_inc_dec[REGNO (XEXP (x, 0))] = 1;
 #endif
 
-      record_address_regs (XEXP (x, 0), class, 2 * scale);
+      record_address_regs (mode, XEXP (x, 0), 0, code, SCRATCH, 2 * scale);
       break;
 
     case REG:
@@ -2080,7 +2119,8 @@
 	int i;
 	for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
 	  if (fmt[i] == 'e')
-	    record_address_regs (XEXP (x, i), class, scale);
+	    record_address_regs (mode, XEXP (x, i), context, code, SCRATCH,
+				 scale);
       }
     }
 }
Index: addresses.h
===================================================================
--- addresses.h	(revision 0)
+++ addresses.h	(revision 0)
@@ -0,0 +1,81 @@
+/* Inline functions to test validity of reg classes for addressing modes.
+   Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING.  If not, write to the Free
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.  */
+
+/* Accessor function to unify target macros MODE_CODE_BASE_REG_CLASS,
+   MODE_BASE_REG_REG_CLASS, MODE_BASE_REG_CLASS and BASE_REG_CLASS.
+   Arguments as for the MODE_CODE_BASE_REG_CLASS macro.  */
+
+static inline enum reg_class
+base_reg_class (enum machine_mode mode ATTRIBUTE_UNUSED,
+		enum rtx_code outer_code ATTRIBUTE_UNUSED,
+		enum rtx_code index_code ATTRIBUTE_UNUSED)
+{
+#ifdef MODE_CODE_BASE_REG_CLASS
+  return MODE_CODE_BASE_REG_CLASS (mode, outer_code, index_code);
+#else
+#ifdef MODE_BASE_REG_REG_CLASS
+  if (index_code == REG)
+    return MODE_BASE_REG_REG_CLASS (mode);
+#endif
+#ifdef MODE_BASE_REG_CLASS
+  return MODE_BASE_REG_CLASS (mode);
+#else
+  return BASE_REG_CLASS;
+#endif
+#endif
+}
+
+/* Accessor function to unify target macros REGNO_MODE_CODE_OK_FOR_BASE_P,
+   REGNO_MODE_OK_FOR_REG_BASE_P, REGNO_MODE_OK_FOR_BASE_P and
+   REGNO_OK_FOR_BASE_P.
+   Arguments as for the REGNO_MODE_CODE_OK_FOR_BASE_P macro.  */
+
+static inline bool
+ok_for_base_p_1 (unsigned regno, enum machine_mode mode ATTRIBUTE_UNUSED,
+		     enum rtx_code outer_code ATTRIBUTE_UNUSED,
+		     enum rtx_code index_code ATTRIBUTE_UNUSED)
+{
+#ifdef REGNO_MODE_CODE_OK_FOR_BASE_P
+  return REGNO_MODE_CODE_OK_FOR_BASE_P (regno, mode, outer_code, index_code);
+#else
+#ifdef REGNO_MODE_OK_FOR_REG_BASE_P
+  if (index_code == REG)
+    return REGNO_MODE_OK_FOR_REG_BASE_P (regno, mode);
+#endif
+#ifdef REGNO_MODE_OK_FOR_BASE_P
+  return REGNO_MODE_OK_FOR_BASE_P (regno, mode);
+#else
+  return REGNO_OK_FOR_BASE_P (regno);
+#endif
+#endif
+}
+
+/* Wrapper around ok_for_base_p_1, for use after register allocation is
+   complete.  Arguments as for the called function.  */
+
+static inline bool
+regno_ok_for_base_p (unsigned regno, enum machine_mode mode,
+		     enum rtx_code outer_code, enum rtx_code index_code)
+{
+  if (regno >= FIRST_PSEUDO_REGISTER && reg_renumber[regno] >= 0)
+    regno = reg_renumber[regno];
+
+  return ok_for_base_p_1 (regno, mode, outer_code, index_code);
+}
Index: Makefile.in
===================================================================
--- Makefile.in	(revision 107600)
+++ Makefile.in	(working copy)
@@ -2346,8 +2346,8 @@
    insn-codes.h timevar.h tree-pass.h
 regclass.o : regclass.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
    hard-reg-set.h $(FLAGS_H) $(BASIC_BLOCK_H) $(REGS_H) insn-config.h \
-   $(RECOG_H) reload.h real.h toplev.h function.h output.h $(GGC_H) \
-   $(TM_P_H) $(EXPR_H) $(TIMEVAR_H) gt-regclass.h $(HASHTAB_H)
+   addresses.h $(RECOG_H) reload.h real.h toplev.h function.h output.h \
+   $(GGC_H) $(TM_P_H) $(EXPR_H) $(TIMEVAR_H) gt-regclass.h $(HASHTAB_H)
 local-alloc.o : local-alloc.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
    $(RTL_H) $(FLAGS_H) $(REGS_H) hard-reg-set.h insn-config.h $(RECOG_H) \
    output.h function.h $(INSN_ATTR_H) toplev.h  except.h reload.h $(TM_P_H) \
@@ -2365,11 +2365,11 @@
 reload.o : reload.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
    $(FLAGS_H) output.h $(EXPR_H) $(OPTABS_H) reload.h $(RECOG_H) \
    hard-reg-set.h insn-config.h $(REGS_H) function.h real.h toplev.h \
-   $(TM_P_H) $(PARAMS_H) $(TARGET_H)
+   addresses.h $(TM_P_H) $(PARAMS_H) $(TARGET_H)
 reload1.o : reload1.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
    $(EXPR_H) $(OPTABS_H) reload.h $(REGS_H) hard-reg-set.h insn-config.h \
    $(BASIC_BLOCK_H) $(RECOG_H) output.h function.h toplev.h $(TM_P_H) \
-   except.h $(TREE_H) real.h $(FLAGS_H) $(MACHMODE_H) $(OBSTACK_H)
+   addresses.h except.h $(TREE_H) real.h $(FLAGS_H) $(MACHMODE_H) $(OBSTACK_H)
 rtlhooks.o :  rtlhooks.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
    rtlhooks-def.h $(EXPR_H) $(RECOG_H)
 postreload.o : postreload.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
@@ -2384,7 +2384,7 @@
    $(PARAMS_H) timevar.h tree-pass.h
 caller-save.o : caller-save.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
    $(FLAGS_H) $(REGS_H) hard-reg-set.h insn-config.h $(BASIC_BLOCK_H) function.h \
-   $(RECOG_H) reload.h $(EXPR_H) toplev.h $(TM_P_H)
+   $(RECOG_H) reload.h addresses.h $(EXPR_H) toplev.h $(TM_P_H)
 bt-load.o : bt-load.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) except.h \
    $(RTL_H) hard-reg-set.h $(REGS_H) $(TM_P_H) $(FIBHEAP_H) output.h $(EXPR_H) \
    $(TARGET_H) $(FLAGS_H) $(INSN_ATTR_H) function.h tree-pass.h toplev.h
@@ -2439,7 +2439,7 @@
 recog.o : recog.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
    function.h $(BASIC_BLOCK_H) $(REGS_H) $(RECOG_H) $(EXPR_H) hard-reg-set.h \
    $(FLAGS_H) insn-config.h $(INSN_ATTR_H) real.h toplev.h output.h reload.h \
-   $(TM_P_H) timevar.h tree-pass.h
+   addresses.h $(TM_P_H) timevar.h tree-pass.h
 reg-stack.o : reg-stack.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
    $(RTL_H) $(TREE_H) $(RECOG_H) $(REGS_H) hard-reg-set.h $(FLAGS_H) \
    insn-config.h toplev.h reload.h function.h $(TM_P_H) $(GGC_H) \
@@ -2471,7 +2471,7 @@
 regrename.o : regrename.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
    $(RTL_H) insn-config.h $(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h \
    output.h $(RECOG_H) function.h $(OBSTACK_H) $(FLAGS_H) $(TM_P_H) \
-   reload.h toplev.h timevar.h tree-pass.h
+   reload.h toplev.h timevar.h tree-pass.h addresses.h 
 ifcvt.o : ifcvt.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
    $(REGS_H) toplev.h $(FLAGS_H) insn-config.h function.h $(RECOG_H) \
    $(TARGET_H) $(BASIC_BLOCK_H) $(EXPR_H) output.h except.h $(TM_P_H) \
Index: config/bfin/bfin-protos.h
===================================================================
--- config/bfin/bfin-protos.h	(revision 107600)
+++ config/bfin/bfin-protos.h	(working copy)
@@ -47,6 +47,7 @@
 extern void expand_move (rtx *, Mmode);
 extern void bfin_expand_call (rtx, rtx, rtx, rtx, int);
 extern bool bfin_longcall_p (rtx, int);
+extern bool bfin_dsp_memref_p (rtx);
 extern bool bfin_expand_strmov (rtx, rtx, rtx, rtx);
 
 extern void conditional_register_usage (void);
Index: config/bfin/bfin.c
===================================================================
--- config/bfin/bfin.c	(revision 107601)
+++ config/bfin/bfin.c	(working copy)
@@ -1052,6 +1052,19 @@
   return offset < 0 || offset > 30;
 }
 
+/* Returns true if X is a memory reference using an I register.  */
+bool
+bfin_dsp_memref_p (rtx x)
+{
+  if (! MEM_P (x))
+    return false;
+  x = XEXP (x, 0);
+  if (GET_CODE (x) == POST_INC || GET_CODE (x) == PRE_INC
+      || GET_CODE (x) == PRE_INC || GET_CODE (x) == PRE_DEC)
+    x = XEXP (x, 0);
+  return IREG_P (x);
+}
+
 /* Return cost of the memory address ADDR.
    All addressing modes are equally cheap on the Blackfin.  */
 
@@ -2086,10 +2099,12 @@
 }
 
 static bool
-bfin_valid_reg_p (unsigned int regno, int strict)
+bfin_valid_reg_p (unsigned int regno, int strict, enum machine_mode mode,
+		  enum rtx_code outer_code)
 {
-  return ((strict && REGNO_OK_FOR_BASE_STRICT_P (regno))
-	  || (!strict && REGNO_OK_FOR_BASE_NONSTRICT_P (regno)));
+  if (!strict && regno >= FIRST_PSEUDO_REGISTER)
+    return true;
+  return REGNO_MODE_CODE_OK_FOR_BASE_P (regno, mode, outer_code, SCRATCH);
 }
 
 bool
@@ -2097,12 +2112,12 @@
 {
   switch (GET_CODE (x)) {
   case REG:
-    if (bfin_valid_reg_p (REGNO (x), strict))
+    if (bfin_valid_reg_p (REGNO (x), strict, mode, MEM))
       return true;
     break;
   case PLUS:
     if (REG_P (XEXP (x, 0))
-	&& bfin_valid_reg_p (REGNO (XEXP (x, 0)), strict)
+	&& bfin_valid_reg_p (REGNO (XEXP (x, 0)), strict, mode, PLUS)
 	&& (GET_CODE (XEXP (x, 1)) == UNSPEC
 	    || (GET_CODE (XEXP (x, 1)) == CONST_INT
 		&& bfin_valid_add (mode, INTVAL (XEXP (x, 1))))))
@@ -2112,13 +2127,13 @@
   case POST_DEC:
     if (LEGITIMATE_MODE_FOR_AUTOINC_P (mode)
 	&& REG_P (XEXP (x, 0))
-	&& bfin_valid_reg_p (REGNO (XEXP (x, 0)), strict))
+	&& bfin_valid_reg_p (REGNO (XEXP (x, 0)), strict, mode, POST_INC))
       return true;
   case PRE_DEC:
     if (LEGITIMATE_MODE_FOR_AUTOINC_P (mode)
 	&& XEXP (x, 0) == stack_pointer_rtx
 	&& REG_P (XEXP (x, 0))
-	&& bfin_valid_reg_p (REGNO (XEXP (x, 0)), strict))
+	&& bfin_valid_reg_p (REGNO (XEXP (x, 0)), strict, mode, PRE_DEC))
       return true;
     break;
   default:
Index: config/bfin/bfin.h
===================================================================
--- config/bfin/bfin.h	(revision 107601)
+++ config/bfin/bfin.h	(working copy)
@@ -213,9 +213,13 @@
 
 #define FIRST_PSEUDO_REGISTER 44
 
-#define PREG_P(X) (REG_P (X) && REGNO (X) >= REG_P0 && REGNO (X) <= REG_P7)
+#define PREG_P(X) (REG_P (X) && P_REGNO_P (REGNO (X)))
+#define IREG_P(X) (REG_P (X) && I_REGNO_P (REGNO (X)))
 #define ADDRESS_REGNO_P(X) ((X) >= REG_P0 && (X) <= REG_M3)
 #define D_REGNO_P(X) ((X) <= REG_R7)
+#define P_REGNO_P(X) ((X) >= REG_P0 && (X) <= REG_P7)
+#define I_REGNO_P(X) \
+  ((X) == REG_I0 || (X) == REG_I1 || (X) == REG_I2 || (X) == REG_I3)
 
 #define REGISTER_NAMES { \
   "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7", \
@@ -342,6 +346,7 @@
   DREGS,
   PREGS_CLOBBERED,
   PREGS,
+  IPREGS,
   DPREGS,
   MOST_REGS,
   PROLOGUE_REGS,
@@ -372,6 +377,7 @@
    "DREGS",		\
    "PREGS_CLOBBERED",	\
    "PREGS",		\
+   "IPREGS",		\
    "DPREGS",		\
    "MOST_REGS",		\
    "PROLOGUE_REGS",	\
@@ -410,27 +416,28 @@
     { 0x000000ff,    0 },		/* DREGS */   \
     { 0x00004700,    0x800 },		/* PREGS_CLOBBERED */   \
     { 0x0000ff00,    0x800 },		/* PREGS */   \
+    { 0x000fff00,    0x800 },		/* IPREGS */	\
     { 0x0000ffff,    0x800 },		/* DPREGS */   \
     { 0xffffffff,    0x800 },		/* MOST_REGS */\
     { 0x00000000,    0x7f8 },		/* PROLOGUE_REGS */\
     { 0xffffffff,    0xff8 },		/* NON_A_CC_REGS */\
     { 0xffffffff,    0xfff }}		/* ALL_REGS */
 
-#define BASE_REG_CLASS          PREGS
+#define IREG_POSSIBLE_P(OUTER)				     \
+  ((OUTER) == POST_INC || (OUTER) == PRE_INC		     \
+   || (OUTER) == POST_DEC || (OUTER) == PRE_DEC		     \
+   || (OUTER) == MEM || (OUTER) == ADDRESS)
+
+#define MODE_CODE_BASE_REG_CLASS(MODE, OUTER, INDEX)			\
+  ((MODE) == HImode && IREG_POSSIBLE_P (OUTER) ? IPREGS : PREGS)
+
 #define INDEX_REG_CLASS         PREGS
 
-#define REGNO_OK_FOR_BASE_STRICT_P(X) (REGNO_REG_CLASS (X) == BASE_REG_CLASS)
-#define REGNO_OK_FOR_BASE_NONSTRICT_P(X)  \
- (((X) >= FIRST_PSEUDO_REGISTER) || REGNO_REG_CLASS (X) == BASE_REG_CLASS)
+#define REGNO_MODE_CODE_OK_FOR_BASE_P(X, MODE, OUTER, INDEX)	\
+  (P_REGNO_P (X) || (X) == REG_ARGP				\
+   || (IREG_POSSIBLE_P (OUTER) && (MODE) == HImode		\
+       && I_REGNO_P (X)))
 
-#ifdef REG_OK_STRICT
-#define REGNO_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_STRICT_P (X)
-#else
-#define REGNO_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_NONSTRICT_P (X)
-#endif
-
-#define REG_OK_FOR_BASE_P(X)    (REG_P (X) && REGNO_OK_FOR_BASE_P (REGNO (X)))
-#define REG_OK_FOR_INDEX_P(X)   0
 #define REGNO_OK_FOR_INDEX_P(X)   0
 
 /* Get reg_class from a letter such as appears in the machine description.  */
@@ -462,7 +469,7 @@
 #define REGNO_REG_CLASS(REGNO) \
  ((REGNO) < REG_P0 ? DREGS				\
  : (REGNO) < REG_I0 ? PREGS				\
- : (REGNO) == REG_ARGP ? BASE_REG_CLASS			\
+ : (REGNO) == REG_ARGP ? PREGS				\
  : (REGNO) >= REG_I0 && (REGNO) <= REG_I3 ? IREGS	\
  : (REGNO) >= REG_L0 && (REGNO) <= REG_L3 ? LREGS	\
  : (REGNO) >= REG_B0 && (REGNO) <= REG_B3 ? BREGS	\
Index: config/bfin/bfin.md
===================================================================
--- config/bfin/bfin.md	(revision 107600)
+++ config/bfin/bfin.md	(working copy)
@@ -418,12 +418,23 @@
   [(set (match_operand:HI 0 "nonimmediate_operand" "=x,da,x,d,mr")
         (match_operand:HI 1 "general_operand" "x,xKs7,xKsh,mr,d"))]
   "GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM"
-  "@
-   %0 = %1;
-   %0 = %1 (X);
-   %0 = %1 (X);
-   %0 = W %1 (X);
-   W %0 = %1;"
+{
+  static const char *templates[] = {
+    "%0 = %1;",
+    "%0 = %1 (X);",
+    "%0 = %1 (X);",
+    "%0 = W %1 (X);",
+    "W %0 = %1;",
+    "%h0 = W %1;",
+    "W %0 = %h1;"
+  };
+  int alt = which_alternative;
+  rtx mem = (MEM_P (operands[0]) ? operands[0]
+	     : MEM_P (operands[1]) ? operands[1] : NULL_RTX);
+  if (mem && bfin_dsp_memref_p (mem))
+    alt += 2;
+  return templates[alt];
+}
   [(set_attr "type" "move,mvi,mvi,mcld,mcst")
    (set_attr "length" "2,2,4,*,*")])
 
@@ -588,22 +599,34 @@
 
 ;; Sign and zero extensions
 
-(define_insn "extendhisi2"
+(define_insn_and_split "extendhisi2"
   [(set (match_operand:SI 0 "register_operand" "=d, d")
 	(sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "d, m")))]
   ""
   "@
    %0 = %h1 (X);
    %0 = W %h1 (X);"
+  "reload_completed && bfin_dsp_memref_p (operands[1])"
+  [(set (match_dup 2) (match_dup 1))
+   (set (match_dup 0) (sign_extend:SI (match_dup 2)))]
+{
+  operands[2] = gen_lowpart (HImode, operands[0]);
+}
   [(set_attr "type" "alu0,mcld")])
 
-(define_insn "zero_extendhisi2"
+(define_insn_and_split "zero_extendhisi2"
   [(set (match_operand:SI 0 "register_operand" "=d, d")
 	(zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "d, m")))]
   ""
   "@
    %0 = %h1 (Z);
-   %0 = W%h1 (Z);"
+   %0 = W %h1 (Z);"
+  "reload_completed && bfin_dsp_memref_p (operands[1])"
+  [(set (match_dup 2) (match_dup 1))
+   (set (match_dup 0) (zero_extend:SI (match_dup 2)))]
+{
+  operands[2] = gen_lowpart (HImode, operands[0]);
+}
   [(set_attr "type" "alu0,mcld")])
 
 (define_insn "zero_extendbisi2"
Index: reload1.c
===================================================================
--- reload1.c	(revision 107600)
+++ reload1.c	(working copy)
@@ -35,6 +35,7 @@
 #include "expr.h"
 #include "optabs.h"
 #include "regs.h"
+#include "addresses.h"
 #include "basic-block.h"
 #include "reload.h"
 #include "recog.h"
@@ -1374,7 +1375,7 @@
 
 		case 'p':
 		  cls = (int) reg_class_subunion[cls]
-		    [(int) MODE_BASE_REG_CLASS (VOIDmode)];
+		      [(int) base_reg_class (VOIDmode, ADDRESS, SCRATCH)];
 		  break;
 
 		case 'g':
@@ -1385,7 +1386,7 @@
 		default:
 		  if (EXTRA_ADDRESS_CONSTRAINT (c, p))
 		    cls = (int) reg_class_subunion[cls]
-		      [(int) MODE_BASE_REG_CLASS (VOIDmode)];
+		      [(int) base_reg_class (VOIDmode, ADDRESS, SCRATCH)];
 		  else
 		    cls = (int) reg_class_subunion[cls]
 		      [(int) REG_CLASS_FROM_CONSTRAINT (c, p)];

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