diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index dc35247b2b41cf4ab634cd8eb21db32be0546c61..73626e6e689ae2a4a6b12547edc7342dbf6958ea 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,19 @@
+2007-02-02  Bob Wilson  <bob.wilson@acm.org>
+
+	* config/xtensa/xtensa.c (smalloffset_mem_p): Use BASE_REG_P.
+	(xtensa_legitimate_address_p): New.
+	(xtensa_legitimize_address): New.
+	(xtensa_output_addr_const_extra): New.
+	* config/xtensa/xtensa.h (REG_OK_STRICT_FLAG): Define.
+	(BASE_REG_P): New.
+	(REG_OK_FOR_BASE_P): Use BASE_REG_P.
+	(GO_IF_LEGITIMATE_ADDRESS): Move code to xtensa_legitimate_address_p.
+	(LEGITIMIZE_ADDRESS): Move code to xtensa_legitimize_address.
+	(OUTPUT_ADDR_CONST_EXTRA): Move code to xtensa_output_addr_const_extra.
+	* config/xtensa/xtensa-protos.h (xtensa_legitimate_address_p): New.
+	(xtensa_legitimize_address): New.
+	(xtensa_output_addr_const_extra): New.
+
 2007-02-02  Steve Ellcey  <sje@cup.hp.com>
 
 	* config/ia64/ia64.c (ia64_print_operand): Fix compare strings.
diff --git a/gcc/config/xtensa/xtensa-protos.h b/gcc/config/xtensa/xtensa-protos.h
index 762aa0aed61e605fc075dcccc3b52a5b41b84930..f6cca7ac9754570aa327e0bd93f3029786fe39ee 100644
--- a/gcc/config/xtensa/xtensa-protos.h
+++ b/gcc/config/xtensa/xtensa-protos.h
@@ -1,5 +1,5 @@
 /* Prototypes of target machine for GNU compiler for Xtensa.
-   Copyright 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+   Copyright 2001, 2002, 2003, 2004, 2005, 2007 Free Software Foundation, Inc.
    Contributed by Bob Wilson (bwilson@tensilica.com) at Tensilica.
 
 This file is part of GCC.
@@ -52,6 +52,8 @@ extern char *xtensa_emit_branch (bool, bool, rtx *);
 extern char *xtensa_emit_bit_branch (bool, bool, rtx *);
 extern char *xtensa_emit_movcc (bool, bool, bool, rtx *);
 extern char *xtensa_emit_call (int, rtx *);
+extern bool xtensa_legitimate_address_p (enum machine_mode, rtx, bool);
+extern rtx xtensa_legitimize_address (rtx, rtx, enum machine_mode);
 
 #ifdef TREE_CODE
 extern void init_cumulative_args (CUMULATIVE_ARGS *, int);
@@ -60,6 +62,7 @@ extern void xtensa_va_start (tree, rtx);
 
 extern void print_operand (FILE *, rtx, int);
 extern void print_operand_address (FILE *, rtx);
+extern bool xtensa_output_addr_const_extra (FILE *, rtx);
 extern void xtensa_output_literal (FILE *, rtx, enum machine_mode, int);
 extern rtx xtensa_return_addr (int, rtx);
 extern enum reg_class xtensa_preferred_reload_class (rtx, enum reg_class, int);
diff --git a/gcc/config/xtensa/xtensa.c b/gcc/config/xtensa/xtensa.c
index 49a89920239438901f137bcba08a3b4dbe628821..6269f1feef2d44e6dffc2eb444afb86d655733f8 100644
--- a/gcc/config/xtensa/xtensa.c
+++ b/gcc/config/xtensa/xtensa.c
@@ -1,5 +1,6 @@
 /* Subroutines for insn-output.c for Tensilica's Xtensa architecture.
-   Copyright 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+   Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007
+   Free Software Foundation, Inc.
    Contributed by Bob Wilson (bwilson@tensilica.com) at Tensilica.
 
 This file is part of GCC.
@@ -397,7 +398,7 @@ smalloffset_mem_p (rtx op)
     {
       rtx addr = XEXP (op, 0);
       if (GET_CODE (addr) == REG)
-	return REG_OK_FOR_BASE_P (addr);
+	return BASE_REG_P (addr, 0);
       if (GET_CODE (addr) == PLUS)
 	{
 	  rtx offset = XEXP (addr, 0);
@@ -686,7 +687,8 @@ xtensa_expand_conditional_branch (rtx *operands, enum rtx_code test_code)
 
     case CMP_SF:
       if (!TARGET_HARD_FLOAT)
-	fatal_insn ("bad test", gen_rtx_fmt_ee (test_code, VOIDmode, cmp0, cmp1));
+	fatal_insn ("bad test", gen_rtx_fmt_ee (test_code, VOIDmode,
+						cmp0, cmp1));
       invert = FALSE;
       cmp = gen_float_relational (test_code, cmp0, cmp1);
       break;
@@ -1370,6 +1372,92 @@ xtensa_emit_call (int callop, rtx *operands)
 }
 
 
+bool
+xtensa_legitimate_address_p (enum machine_mode mode, rtx addr, bool strict)
+{
+  /* Allow constant pool addresses.  */
+  if (mode != BLKmode && GET_MODE_SIZE (mode) >= UNITS_PER_WORD
+      && ! TARGET_CONST16 && constantpool_address_p (addr))
+    return true;
+
+  while (GET_CODE (addr) == SUBREG)
+    addr = SUBREG_REG (addr);
+
+  /* Allow base registers.  */
+  if (GET_CODE (addr) == REG && BASE_REG_P (addr, strict))
+    return true;
+
+  /* Check for "register + offset" addressing.  */
+  if (GET_CODE (addr) == PLUS)
+    {
+      rtx xplus0 = XEXP (addr, 0);
+      rtx xplus1 = XEXP (addr, 1);
+      enum rtx_code code0;
+      enum rtx_code code1;
+
+      while (GET_CODE (xplus0) == SUBREG)
+	xplus0 = SUBREG_REG (xplus0);
+      code0 = GET_CODE (xplus0);
+
+      while (GET_CODE (xplus1) == SUBREG)
+	xplus1 = SUBREG_REG (xplus1);
+      code1 = GET_CODE (xplus1);
+
+      /* Swap operands if necessary so the register is first.  */
+      if (code0 != REG && code1 == REG)
+	{
+	  xplus0 = XEXP (addr, 1);
+	  xplus1 = XEXP (addr, 0);
+	  code0 = GET_CODE (xplus0);
+	  code1 = GET_CODE (xplus1);
+	}
+
+      if (code0 == REG && BASE_REG_P (xplus0, strict)
+	  && code1 == CONST_INT
+	  && xtensa_mem_offset (INTVAL (xplus1), mode))
+	return true;
+    }
+
+  return false;
+}
+
+
+rtx
+xtensa_legitimize_address (rtx x,
+			   rtx oldx ATTRIBUTE_UNUSED,
+			   enum machine_mode mode)
+{
+  if (GET_CODE (x) == PLUS)
+    {
+      rtx plus0 = XEXP (x, 0);
+      rtx plus1 = XEXP (x, 1);
+
+      if (GET_CODE (plus0) != REG && GET_CODE (plus1) == REG)
+	{
+	  plus0 = XEXP (x, 1);
+	  plus1 = XEXP (x, 0);
+	}
+
+      /* Try to split up the offset to use an ADDMI instruction.  */
+      if (GET_CODE (plus0) == REG
+	  && GET_CODE (plus1) == CONST_INT
+	  && !xtensa_mem_offset (INTVAL (plus1), mode)
+	  && !xtensa_simm8 (INTVAL (plus1))
+	  && xtensa_mem_offset (INTVAL (plus1) & 0xff, mode)
+	  && xtensa_simm8x256 (INTVAL (plus1) & ~0xff))
+	{
+	  rtx temp = gen_reg_rtx (Pmode);
+	  rtx addmi_offset = GEN_INT (INTVAL (plus1) & ~0xff);
+	  emit_insn (gen_rtx_SET (Pmode, temp,
+				  gen_rtx_PLUS (Pmode, plus0, addmi_offset)));
+	  return gen_rtx_PLUS (Pmode, temp, GEN_INT (INTVAL (plus1) & 0xff));
+	}
+    }
+
+  return NULL_RTX;
+}
+
+
 /* Return the debugger register number to use for 'regno'.  */
 
 int
@@ -1820,6 +1908,29 @@ print_operand_address (FILE *file, rtx addr)
 }
 
 
+bool
+xtensa_output_addr_const_extra (FILE *fp, rtx x)
+{
+  if (GET_CODE (x) == UNSPEC && XVECLEN (x, 0) == 1)
+    {
+      switch (XINT (x, 1))
+	{
+	case UNSPEC_PLT:
+	  if (flag_pic)
+	    {
+	      output_addr_const (fp, XVECEXP (x, 0, 0));
+	      fputs ("@PLT", fp);
+	      return true;
+	    }
+	  break;
+	default:
+	  break;
+	}
+    }
+  return false;
+}
+
+
 void
 xtensa_output_literal (FILE *file, rtx x, enum machine_mode mode, int labelno)
 {
diff --git a/gcc/config/xtensa/xtensa.h b/gcc/config/xtensa/xtensa.h
index d1fe0220b983561d895efcd33b13f9fcf09c45b1..11c4184a6d71db02b93de3b291beea4f2b61289a 100644
--- a/gcc/config/xtensa/xtensa.h
+++ b/gcc/config/xtensa/xtensa.h
@@ -1,5 +1,6 @@
 /* Definitions of Tensilica's Xtensa target machine for GNU compiler.
-   Copyright 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+   Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007
+   Free Software Foundation, Inc.
    Contributed by Bob Wilson (bwilson@tensilica.com) at Tensilica.
 
 This file is part of GCC.
@@ -825,39 +826,27 @@ typedef struct xtensa_args
 /* Addressing modes, and classification of registers for them.  */
 
 /* C expressions which are nonzero if register number NUM is suitable
-   for use as a base or index register in operand addresses.  It may
-   be either a suitable hard register or a pseudo register that has
-   been allocated such a hard register. The difference between an
-   index register and a base register is that the index register may
-   be scaled.  */
+   for use as a base or index register in operand addresses.  */
 
+#define REGNO_OK_FOR_INDEX_P(NUM) 0
 #define REGNO_OK_FOR_BASE_P(NUM) \
   (GP_REG_P (NUM) || GP_REG_P ((unsigned) reg_renumber[NUM]))
 
-#define REGNO_OK_FOR_INDEX_P(NUM) 0
-
 /* C expressions that are nonzero if X (assumed to be a `reg' RTX) is
-   valid for use as a base or index 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 `REG_OK_STRICT'.  This usually requires two
-   variant definitions, of which `REG_OK_STRICT' controls the one
-   actually used. The difference between an index register and a base
-   register is that the index register may be scaled.  */
+   valid for use as a base or index register.  */
 
 #ifdef REG_OK_STRICT
+#define REG_OK_STRICT_FLAG 1
+#else
+#define REG_OK_STRICT_FLAG 0
+#endif
 
-#define REG_OK_FOR_INDEX_P(X) 0
-#define REG_OK_FOR_BASE_P(X) \
-  REGNO_OK_FOR_BASE_P (REGNO (X))
-
-#else /* !REG_OK_STRICT */
+#define BASE_REG_P(X, STRICT)						\
+  ((!(STRICT) && REGNO (X) >= FIRST_PSEUDO_REGISTER)			\
+   || REGNO_OK_FOR_BASE_P (REGNO (X)))
 
 #define REG_OK_FOR_INDEX_P(X) 0
-#define REG_OK_FOR_BASE_P(X) \
-  ((REGNO (X) >= FIRST_PSEUDO_REGISTER) || (GP_REG_P (REGNO (X))))
-
-#endif /* !REG_OK_STRICT */
+#define REG_OK_FOR_BASE_P(X) BASE_REG_P (X, REG_OK_STRICT_FLAG)
 
 /* Maximum number of registers that can appear in a valid memory address.  */
 #define MAX_REGS_PER_ADDRESS 1
@@ -865,52 +854,8 @@ typedef struct xtensa_args
 /* Identify valid Xtensa addresses.  */
 #define GO_IF_LEGITIMATE_ADDRESS(MODE, ADDR, LABEL)			\
   do {									\
-    rtx xinsn = (ADDR);							\
-									\
-    /* allow constant pool addresses */					\
-    if ((MODE) != BLKmode && GET_MODE_SIZE (MODE) >= UNITS_PER_WORD	\
-	&& !TARGET_CONST16 && constantpool_address_p (xinsn))		\
-      goto LABEL;							\
-									\
-    while (GET_CODE (xinsn) == SUBREG)					\
-      xinsn = SUBREG_REG (xinsn);					\
-									\
-    /* allow base registers */						\
-    if (GET_CODE (xinsn) == REG && REG_OK_FOR_BASE_P (xinsn))		\
+    if (xtensa_legitimate_address_p (MODE, ADDR, REG_OK_STRICT_FLAG))	\
       goto LABEL;							\
-									\
-    /* check for "register + offset" addressing */			\
-    if (GET_CODE (xinsn) == PLUS)					\
-      {									\
-	rtx xplus0 = XEXP (xinsn, 0);					\
-	rtx xplus1 = XEXP (xinsn, 1);					\
-	enum rtx_code code0;						\
-	enum rtx_code code1;						\
-									\
-	while (GET_CODE (xplus0) == SUBREG)				\
-	  xplus0 = SUBREG_REG (xplus0);					\
-	code0 = GET_CODE (xplus0);					\
-									\
-	while (GET_CODE (xplus1) == SUBREG)				\
-	  xplus1 = SUBREG_REG (xplus1);					\
-	code1 = GET_CODE (xplus1);					\
-									\
-	/* swap operands if necessary so the register is first */	\
-	if (code0 != REG && code1 == REG)				\
-	  {								\
-	    xplus0 = XEXP (xinsn, 1);					\
-	    xplus1 = XEXP (xinsn, 0);					\
-	    code0 = GET_CODE (xplus0);					\
-	    code1 = GET_CODE (xplus1);					\
-	  }								\
-									\
-	if (code0 == REG && REG_OK_FOR_BASE_P (xplus0)			\
-	    && code1 == CONST_INT					\
-	    && xtensa_mem_offset (INTVAL (xplus1), (MODE)))		\
-	  {								\
-	    goto LABEL;							\
-	  }								\
-      }									\
   } while (0)
 
 /* A C expression that is 1 if the RTX X is a constant which is a
@@ -934,36 +879,13 @@ typedef struct xtensa_args
    && GET_CODE (X) != LABEL_REF						\
    && GET_CODE (X) != CONST)
 
-/* Tell GCC how to use ADDMI to generate addresses.  */
 #define LEGITIMIZE_ADDRESS(X, OLDX, MODE, WIN)				\
   do {									\
-    rtx xinsn = (X);							\
-    if (GET_CODE (xinsn) == PLUS)					\
-      { 								\
-	rtx plus0 = XEXP (xinsn, 0);					\
-	rtx plus1 = XEXP (xinsn, 1);					\
-									\
-	if (GET_CODE (plus0) != REG && GET_CODE (plus1) == REG)		\
-	  {								\
-	    plus0 = XEXP (xinsn, 1);					\
-	    plus1 = XEXP (xinsn, 0);					\
-	  }								\
-									\
-	if (GET_CODE (plus0) == REG					\
-	    && GET_CODE (plus1) == CONST_INT				\
-	    && !xtensa_mem_offset (INTVAL (plus1), MODE)		\
-	    && !xtensa_simm8 (INTVAL (plus1))				\
-	    && xtensa_mem_offset (INTVAL (plus1) & 0xff, MODE)		\
-	    && xtensa_simm8x256 (INTVAL (plus1) & ~0xff))		\
-	  {								\
-	    rtx temp = gen_reg_rtx (Pmode);				\
-	    emit_insn (gen_rtx_SET (Pmode, temp,			\
-				gen_rtx_PLUS (Pmode, plus0,		\
-					 GEN_INT (INTVAL (plus1) & ~0xff)))); \
-	    (X) = gen_rtx_PLUS (Pmode, temp,				\
-			   GEN_INT (INTVAL (plus1) & 0xff));		\
-	    goto WIN;							\
-	  }								\
+    rtx new_x = xtensa_legitimize_address (X, OLDX, MODE);		\
+    if (new_x)								\
+      {									\
+	X = new_x;							\
+	goto WIN;							\
       }									\
   } while (0)
 
@@ -1066,20 +988,7 @@ typedef struct xtensa_args
    constants.  Used for PIC-specific UNSPECs.  */
 #define OUTPUT_ADDR_CONST_EXTRA(STREAM, X, FAIL)			\
   do {									\
-    if (flag_pic && GET_CODE (X) == UNSPEC && XVECLEN ((X), 0) == 1)	\
-      {									\
-	switch (XINT ((X), 1))						\
-	  {								\
-	  case UNSPEC_PLT:						\
-	    output_addr_const ((STREAM), XVECEXP ((X), 0, 0));		\
-	    fputs ("@PLT", (STREAM));					\
-	    break;							\
-	  default:							\
-	    goto FAIL;							\
-	  }								\
-	break;								\
-      }									\
-    else								\
+    if (xtensa_output_addr_const_extra (STREAM, X) == FALSE)		\
       goto FAIL;							\
   } while (0)