OSDN Git Service

* config/xtensa/xtensa.c (xtensa_dbx_register_number): Change first
[pf3gnuchains/gcc-fork.git] / gcc / config / xtensa / xtensa.c
index 8bab197..23798b0 100644 (file)
@@ -1,5 +1,5 @@
 /* Subroutines for insn-output.c for Tensilica's Xtensa architecture.
-   Copyright (C) 2001 Free Software Foundation, Inc.
+   Copyright 2001,2002,2003 Free Software Foundation, Inc.
    Contributed by Bob Wilson (bwilson@tensilica.com) at Tensilica.
 
 This file is part of GCC.
@@ -21,9 +21,10 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 
 #include "config.h"
 #include "system.h"
+#include "coretypes.h"
+#include "tm.h"
 #include "rtl.h"
 #include "regs.h"
-#include "machmode.h"
 #include "hard-reg-set.h"
 #include "basic-block.h"
 #include "real.h"
@@ -42,7 +43,6 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "function.h"
 #include "toplev.h"
 #include "optabs.h"
-#include "output.h"
 #include "libfuncs.h"
 #include "ggc.h"
 #include "target.h"
@@ -51,21 +51,22 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 
 /* Enumeration for all of the relational tests, so that we can build
    arrays indexed by the test type, and not worry about the order
-   of EQ, NE, etc. */
-
-enum internal_test {
-    ITEST_EQ,
-    ITEST_NE,
-    ITEST_GT,
-    ITEST_GE,
-    ITEST_LT,
-    ITEST_LE,
-    ITEST_GTU,
-    ITEST_GEU,
-    ITEST_LTU,
-    ITEST_LEU,
-    ITEST_MAX
-  };
+   of EQ, NE, etc.  */
+
+enum internal_test
+{
+  ITEST_EQ,
+  ITEST_NE,
+  ITEST_GT,
+  ITEST_GE,
+  ITEST_LT,
+  ITEST_LE,
+  ITEST_GTU,
+  ITEST_GEU,
+  ITEST_LTU,
+  ITEST_LEU,
+  ITEST_MAX
+};
 
 /* Cached operands, and operator to compare for use in set/branch on
    condition codes.  */
@@ -90,11 +91,12 @@ const char *xtensa_st_opcodes[(int) MAX_MACHINE_MODE];
 struct machine_function GTY(())
 {
   int accesses_prev_frame;
+  bool incoming_a7_copied;
 };
 
 /* Vector, indexed by hard register number, which contains 1 for a
    register that is allowable in a candidate for leaf function
-   treatment. */
+   treatment.  */
 
 const char xtensa_leaf_regs[FIRST_PSEUDO_REGISTER] =
 {
@@ -107,10 +109,10 @@ const char xtensa_leaf_regs[FIRST_PSEUDO_REGISTER] =
 /* Map hard register number to register class */
 const enum reg_class xtensa_regno_to_class[FIRST_PSEUDO_REGISTER] =
 {
-  GR_REGS,     SP_REG,         GR_REGS,        GR_REGS,
-  GR_REGS,     GR_REGS,        GR_REGS,        GR_REGS,
-  GR_REGS,     GR_REGS,        GR_REGS,        GR_REGS,
-  GR_REGS,     GR_REGS,        GR_REGS,        GR_REGS,
+  RL_REGS,     SP_REG,         RL_REGS,        RL_REGS,
+  RL_REGS,     RL_REGS,        RL_REGS,        GR_REGS,
+  RL_REGS,     RL_REGS,        RL_REGS,        RL_REGS,
+  RL_REGS,     RL_REGS,        RL_REGS,        RL_REGS,
   AR_REGS,     AR_REGS,        BR_REGS,
   FP_REGS,     FP_REGS,        FP_REGS,        FP_REGS,
   FP_REGS,     FP_REGS,        FP_REGS,        FP_REGS,
@@ -188,34 +190,26 @@ enum reg_class xtensa_char_to_class[256] =
   NO_REGS,     NO_REGS,        NO_REGS,        NO_REGS,
 };
 
-static int b4const_or_zero PARAMS ((int));
-static enum internal_test map_test_to_internal_test PARAMS ((enum rtx_code));
-static rtx gen_int_relational PARAMS ((enum rtx_code, rtx, rtx, int *));
-static rtx gen_float_relational PARAMS ((enum rtx_code, rtx, rtx));
-static rtx gen_conditional_move PARAMS ((rtx));
-static rtx fixup_subreg_mem PARAMS ((rtx x));
-static enum machine_mode xtensa_find_mode_for_size PARAMS ((unsigned));
-static struct machine_function * xtensa_init_machine_status PARAMS ((void));
-static void printx PARAMS ((FILE *, signed int));
-static void xtensa_select_rtx_section PARAMS ((enum machine_mode, rtx,
-                                              unsigned HOST_WIDE_INT));
-static void xtensa_encode_section_info PARAMS ((tree, int));
-
-static rtx frame_size_const;
+static int b4const_or_zero (int);
+static enum internal_test map_test_to_internal_test (enum rtx_code);
+static rtx gen_int_relational (enum rtx_code, rtx, rtx, int *);
+static rtx gen_float_relational (enum rtx_code, rtx, rtx);
+static rtx gen_conditional_move (rtx);
+static rtx fixup_subreg_mem (rtx);
+static enum machine_mode xtensa_find_mode_for_size (unsigned);
+static struct machine_function * xtensa_init_machine_status (void);
+static void printx (FILE *, signed int);
+static void xtensa_function_epilogue (FILE *, HOST_WIDE_INT);
+static unsigned int xtensa_multibss_section_type_flags (tree, const char *,
+                                                       int) ATTRIBUTE_UNUSED;
+static void xtensa_select_rtx_section (enum machine_mode, rtx,
+                                      unsigned HOST_WIDE_INT);
+static bool xtensa_rtx_costs (rtx, int, int, int *);
+
 static int current_function_arg_words;
 static const int reg_nonleaf_alloc_order[FIRST_PSEUDO_REGISTER] =
   REG_ALLOC_ORDER;
 \f
-/* This macro generates the assembly code for function entry.
-   FILE is a stdio stream to output the code to.
-   SIZE is an int: how many units of temporary storage to allocate.
-   Refer to the array 'regs_ever_live' to determine which registers
-   to save; 'regs_ever_live[I]' is nonzero if register number I
-   is ever used in the function.  This macro is responsible for
-   knowing which registers should not be saved even if used.  */
-
-#undef TARGET_ASM_FUNCTION_PROLOGUE
-#define TARGET_ASM_FUNCTION_PROLOGUE xtensa_function_prologue
 
 /* This macro generates the assembly code for function exit,
    on machines that need it.  If FUNCTION_EPILOGUE is not defined
@@ -233,8 +227,11 @@ static const int reg_nonleaf_alloc_order[FIRST_PSEUDO_REGISTER] =
 
 #undef TARGET_ASM_SELECT_RTX_SECTION
 #define TARGET_ASM_SELECT_RTX_SECTION  xtensa_select_rtx_section
-#undef TARGET_ENCODE_SECTION_INFO
-#define TARGET_ENCODE_SECTION_INFO  xtensa_encode_section_info
+
+#undef TARGET_RTX_COSTS
+#define TARGET_RTX_COSTS xtensa_rtx_costs
+#undef TARGET_ADDRESS_COST
+#define TARGET_ADDRESS_COST hook_int_rtx_0
 
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
@@ -244,8 +241,7 @@ struct gcc_target targetm = TARGET_INITIALIZER;
  */
 
 int
-xtensa_b4constu (v)
-     int v;
+xtensa_b4constu (int v)
 {
   switch (v)
     {
@@ -271,29 +267,25 @@ xtensa_b4constu (v)
 }
 
 int
-xtensa_simm8x256 (v)
-     int v;
+xtensa_simm8x256 (int v)
 {
   return (v & 255) == 0 && (v >= -32768 && v <= 32512);
 }
 
 int
-xtensa_ai4const (v)
-     int v;
+xtensa_ai4const (int v)
 {
   return (v == -1 || (v >= 1 && v <= 15));
 }
 
 int
-xtensa_simm7 (v)
-     int v;
+xtensa_simm7 (int v)
 {
   return v >= -32 && v <= 95;
 }
 
 int
-xtensa_b4const (v)
-     int v;
+xtensa_b4const (int v)
 {
   switch (v)
     {
@@ -319,61 +311,53 @@ xtensa_b4const (v)
 }
 
 int
-xtensa_simm8 (v)
-     int v;
+xtensa_simm8 (int v)
 {
   return v >= -128 && v <= 127;
 }
 
 int
-xtensa_tp7 (v)
-     int v;
+xtensa_tp7 (int v)
 {
   return (v >= 7 && v <= 22);
 }
 
 int
-xtensa_lsi4x4 (v)
-     int v;
+xtensa_lsi4x4 (int v)
 {
   return (v & 3) == 0 && (v >= 0 && v <= 60);
 }
 
 int
-xtensa_simm12b (v)
-     int v;
+xtensa_simm12b (int v)
 {
   return v >= -2048 && v <= 2047;
 }
 
 int
-xtensa_uimm8 (v)
-     int v;
+xtensa_uimm8 (int v)
 {
   return v >= 0 && v <= 255;
 }
 
 int
-xtensa_uimm8x2 (v)
-     int v;
+xtensa_uimm8x2 (int v)
 {
   return (v & 1) == 0 && (v >= 0 && v <= 510);
 }
 
 int
-xtensa_uimm8x4 (v)
-     int v;
+xtensa_uimm8x4 (int v)
 {
   return (v & 3) == 0 && (v >= 0 && v <= 1020);
 }
 
 
 /* This is just like the standard true_regnum() function except that it
-   works even when reg_renumber is not initialized. */
+   works even when reg_renumber is not initialized.  */
 
 int
-xt_true_regnum (x)
-     rtx x;
+xt_true_regnum (rtx x)
 {
   if (GET_CODE (x) == REG)
     {
@@ -396,64 +380,53 @@ xt_true_regnum (x)
 
 
 int
-add_operand (op, mode)
-    rtx op;
-    enum machine_mode mode;
+add_operand (rtx op, enum machine_mode mode)
 {
-    if (GET_CODE (op) == CONST_INT)
-       return (xtensa_simm8 (INTVAL (op)) ||
-               xtensa_simm8x256 (INTVAL (op)));
+  if (GET_CODE (op) == CONST_INT)
+    return (xtensa_simm8 (INTVAL (op)) || xtensa_simm8x256 (INTVAL (op)));
 
-    return register_operand (op, mode);
+  return register_operand (op, mode);
 }
 
 
 int
-arith_operand (op, mode)
-    rtx op;
-    enum machine_mode mode;
+arith_operand (rtx op, enum machine_mode mode)
 {
-    if (GET_CODE (op) == CONST_INT)
-       return xtensa_simm8 (INTVAL (op));
+  if (GET_CODE (op) == CONST_INT)
+    return xtensa_simm8 (INTVAL (op));
 
-    return register_operand (op, mode);
+  return register_operand (op, mode);
 }
 
 
 int
-nonimmed_operand (op, mode)
-    rtx op;
-    enum machine_mode mode;
+nonimmed_operand (rtx op, enum machine_mode mode)
 {
-    /* We cannot use the standard nonimmediate_operand() predicate because
-       it includes constant pool memory operands. */
+  /* We cannot use the standard nonimmediate_operand() predicate because
+     it includes constant pool memory operands.  */
 
-    if (memory_operand (op, mode))
-       return !constantpool_address_p (XEXP (op, 0));
+  if (memory_operand (op, mode))
+    return !constantpool_address_p (XEXP (op, 0));
 
-    return register_operand (op, mode);
+  return register_operand (op, mode);
 }
 
 
 int
-mem_operand (op, mode)
-    rtx op;
-    enum machine_mode mode;
+mem_operand (rtx op, enum machine_mode mode)
 {
-    /* We cannot use the standard memory_operand() predicate because
-       it includes constant pool memory operands. */
+  /* We cannot use the standard memory_operand() predicate because
+     it includes constant pool memory operands.  */
 
-    if (memory_operand (op, mode))
-       return !constantpool_address_p (XEXP (op, 0));
+  if (memory_operand (op, mode))
+    return !constantpool_address_p (XEXP (op, 0));
 
-    return FALSE;
+  return FALSE;
 }
 
 
 int
-xtensa_valid_move (mode, operands)
-     enum machine_mode mode;
-     rtx *operands;
+xtensa_valid_move (enum machine_mode mode, rtx *operands)
 {
   /* Either the destination or source must be a register, and the
      MAC16 accumulator doesn't count.  */
@@ -462,7 +435,7 @@ xtensa_valid_move (mode, operands)
     {
       int dst_regnum = xt_true_regnum (operands[0]);
 
-      /* The stack pointer can only be assigned with a MOVSP opcode. */
+      /* The stack pointer can only be assigned with a MOVSP opcode.  */
       if (dst_regnum == STACK_POINTER_REGNUM)
        return (mode == SImode
                && register_operand (operands[1], mode)
@@ -482,9 +455,7 @@ xtensa_valid_move (mode, operands)
 
 
 int
-mask_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
+mask_operand (rtx op, enum machine_mode mode)
 {
   if (GET_CODE (op) == CONST_INT)
     return xtensa_mask_immediate (INTVAL (op));
@@ -494,9 +465,7 @@ mask_operand (op, mode)
 
 
 int
-extui_fldsz_operand (op, mode)
-     rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
+extui_fldsz_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
 {
   return ((GET_CODE (op) == CONST_INT)
          && xtensa_mask_immediate ((1 << INTVAL (op)) - 1));
@@ -504,9 +473,7 @@ extui_fldsz_operand (op, mode)
 
 
 int
-sext_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
+sext_operand (rtx op, enum machine_mode mode)
 {
   if (TARGET_SEXT)
     return nonimmed_operand (op, mode);
@@ -515,18 +482,14 @@ sext_operand (op, mode)
 
 
 int
-sext_fldsz_operand (op, mode)
-     rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
+sext_fldsz_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
 {
   return ((GET_CODE (op) == CONST_INT) && xtensa_tp7 (INTVAL (op) - 1));
 }
 
 
 int
-lsbitnum_operand (op, mode)
-     rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
+lsbitnum_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
 {
   if (GET_CODE (op) == CONST_INT)
     {
@@ -539,8 +502,7 @@ lsbitnum_operand (op, mode)
 
 
 static int
-b4const_or_zero (v)
-     int v;
+b4const_or_zero (int v)
 {
   if (v == 0)
     return TRUE;
@@ -549,9 +511,7 @@ b4const_or_zero (v)
 
 
 int
-branch_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
+branch_operand (rtx op, enum machine_mode mode)
 {
   if (GET_CODE (op) == CONST_INT)
     return b4const_or_zero (INTVAL (op));
@@ -561,9 +521,7 @@ branch_operand (op, mode)
 
 
 int
-ubranch_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
+ubranch_operand (rtx op, enum machine_mode mode)
 {
   if (GET_CODE (op) == CONST_INT)
     return xtensa_b4constu (INTVAL (op));
@@ -573,9 +531,7 @@ ubranch_operand (op, mode)
 
 
 int
-call_insn_operand (op, mode)
-     rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
+call_insn_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
 {
   if ((GET_CODE (op) == REG)
       && (op != arg_pointer_rtx)
@@ -586,8 +542,37 @@ call_insn_operand (op, mode)
   if (CONSTANT_ADDRESS_P (op))
     {
       /* Direct calls only allowed to static functions with PIC.  */
-      return (!flag_pic || (GET_CODE (op) == SYMBOL_REF
-                           && SYMBOL_REF_FLAG (op)));
+      if (flag_pic)
+       {
+         tree callee, callee_sec, caller_sec;
+
+         if (GET_CODE (op) != SYMBOL_REF || !SYMBOL_REF_LOCAL_P (op))
+           return FALSE;
+
+         /* Don't attempt a direct call if the callee is known to be in
+            a different section, since there's a good chance it will be
+            out of range.  */
+
+         if (flag_function_sections
+             || DECL_ONE_ONLY (current_function_decl))
+           return FALSE;
+         caller_sec = DECL_SECTION_NAME (current_function_decl);
+         callee = SYMBOL_REF_DECL (op);
+         if (callee)
+           {
+             if (DECL_ONE_ONLY (callee))
+               return FALSE;
+             callee_sec = DECL_SECTION_NAME (callee);
+             if (((caller_sec == NULL_TREE) ^ (callee_sec == NULL_TREE))
+                 || (caller_sec != NULL_TREE
+                     && strcmp (TREE_STRING_POINTER (caller_sec),
+                                TREE_STRING_POINTER (callee_sec)) != 0))
+               return FALSE;
+           }
+         else if (caller_sec != NULL_TREE)
+           return FALSE;
+       }
+      return TRUE;
     }
 
   return FALSE;
@@ -595,31 +580,45 @@ call_insn_operand (op, mode)
 
 
 int
-move_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
+move_operand (rtx op, enum machine_mode mode)
 {
-  if (register_operand (op, mode))
+  if (register_operand (op, mode)
+      || memory_operand (op, mode))
     return TRUE;
 
-  /* Accept CONSTANT_P_RTX, since it will be gone by CSE1 and
-     result in 0/1. */
-  if (GET_CODE (op) == CONSTANT_P_RTX)
-    return TRUE;
+  switch (mode)
+    {
+    case DFmode:
+    case SFmode:
+      return TARGET_CONST16 && CONSTANT_P (op);
 
-  if (GET_CODE (op) == CONST_INT)
-    return xtensa_simm12b (INTVAL (op));
+    case DImode:
+    case SImode:
+      if (TARGET_CONST16)
+       return CONSTANT_P (op);
+      /* fall through */
 
-  if (GET_CODE (op) == MEM)
-    return memory_address_p (mode, XEXP (op, 0));
+    case HImode:
+    case QImode:
+      /* Accept CONSTANT_P_RTX, since it will be gone by CSE1 and
+        result in 0/1.  */
+      if (GET_CODE (op) == CONSTANT_P_RTX)
+       return TRUE;
+
+      if (GET_CODE (op) == CONST_INT && xtensa_simm12b (INTVAL (op)))
+       return TRUE;
+      break;
+
+    default:
+      break;
+    }
 
   return FALSE;
 }
 
 
 int
-smalloffset_mem_p (op)
-     rtx op;
+smalloffset_mem_p (rtx op)
 {
   if (GET_CODE (op) == MEM)
     {
@@ -641,18 +640,7 @@ smalloffset_mem_p (op)
 
 
 int
-smalloffset_double_mem_p (op)
-     rtx op;
-{
-  if (!smalloffset_mem_p (op))
-    return FALSE;
-  return smalloffset_mem_p (adjust_address (op, GET_MODE (op), 4));
-}
-
-
-int
-constantpool_address_p (addr)
-     rtx addr;
+constantpool_address_p (rtx addr)
 {
   rtx sym = addr;
 
@@ -682,8 +670,7 @@ constantpool_address_p (addr)
 
 
 int
-constantpool_mem_p (op)
-     rtx op;
+constantpool_mem_p (rtx op)
 {
   if (GET_CODE (op) == MEM)
     return constantpool_address_p (XEXP (op, 0));
@@ -691,27 +678,10 @@ constantpool_mem_p (op)
 }
 
 
-int
-non_const_move_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
-{
-  if (register_operand (op, mode))
-    return 1;
-  if (GET_CODE (op) == SUBREG)
-    op = SUBREG_REG (op);
-  if (GET_CODE (op) == MEM)
-    return memory_address_p (mode, XEXP (op, 0));
-  return FALSE;
-}
-
-
 /* Accept the floating point constant 1 in the appropriate mode.  */
 
 int
-const_float_1_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
+const_float_1_operand (rtx op, enum machine_mode mode)
 {
   REAL_VALUE_TYPE d;
   static REAL_VALUE_TYPE onedf;
@@ -740,9 +710,7 @@ const_float_1_operand (op, mode)
 
 
 int
-fpmem_offset_operand (op, mode)
-     rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
+fpmem_offset_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
 {
   if (GET_CODE (op) == CONST_INT)
     return xtensa_mem_offset (INTVAL (op), SFmode);
@@ -751,9 +719,7 @@ fpmem_offset_operand (op, mode)
 
 
 void
-xtensa_extend_reg (dst, src)
-     rtx dst;
-     rtx src;
+xtensa_extend_reg (rtx dst, rtx src)
 {
   rtx temp = gen_reg_rtx (SImode);
   rtx shift = GEN_INT (BITS_PER_WORD - GET_MODE_BITSIZE (GET_MODE (src)));
@@ -767,36 +733,8 @@ xtensa_extend_reg (dst, src)
 }
 
 
-void
-xtensa_load_constant (dst, src)
-     rtx dst;
-     rtx src;
-{
-  enum machine_mode mode = GET_MODE (dst);
-  src = force_const_mem (SImode, src);
-
-  /* PC-relative loads are always SImode so we have to add a SUBREG if that
-     is not the desired mode */
-
-  if (mode != SImode)
-    {
-      if (register_operand (dst, mode))
-       dst = simplify_gen_subreg (SImode, dst, mode, 0);
-      else
-       {
-         src = force_reg (SImode, src);
-         src = gen_lowpart_SUBREG (mode, src);
-       }
-    }
-
-  emit_move_insn (dst, src);
-}
-
-
 int
-branch_operator (x, mode)
-     rtx x;
-     enum machine_mode mode;
+branch_operator (rtx x, enum machine_mode mode)
 {
   if (GET_MODE (x) != mode)
     return FALSE;
@@ -816,9 +754,7 @@ branch_operator (x, mode)
 
 
 int
-ubranch_operator (x, mode)
-     rtx x;
-     enum machine_mode mode;
+ubranch_operator (rtx x, enum machine_mode mode)
 {
   if (GET_MODE (x) != mode)
     return FALSE;
@@ -836,9 +772,7 @@ ubranch_operator (x, mode)
 
 
 int
-boolean_operator (x, mode)
-     rtx x;
-     enum machine_mode mode;
+boolean_operator (rtx x, enum machine_mode mode)
 {
   if (GET_MODE (x) != mode)
     return FALSE;
@@ -856,8 +790,7 @@ boolean_operator (x, mode)
 
 
 int
-xtensa_mask_immediate (v)
-     int v;
+xtensa_mask_immediate (int v)
 {
 #define MAX_MASK_SIZE 16
   int mask_size;
@@ -876,9 +809,7 @@ xtensa_mask_immediate (v)
 
 
 int
-xtensa_mem_offset (v, mode)
-     unsigned v;
-     enum machine_mode mode;
+xtensa_mem_offset (unsigned v, enum machine_mode mode)
 {
   switch (mode)
     {
@@ -887,9 +818,9 @@ xtensa_mem_offset (v, mode)
         where we emit an optimized block move operation if the block can be
         moved in < "move_ratio" pieces.  The worst case is when the block is
         aligned but has a size of (3 mod 4) (does this happen?) so that the
-        last piece requires a byte load/store. */
-      return (xtensa_uimm8 (v) &&
-             xtensa_uimm8 (v + MOVE_MAX * LARGEST_MOVE_RATIO));
+        last piece requires a byte load/store.  */
+      return (xtensa_uimm8 (v)
+             && xtensa_uimm8 (v + MOVE_MAX * LARGEST_MOVE_RATIO));
 
     case QImode:
       return xtensa_uimm8 (v);
@@ -908,11 +839,10 @@ xtensa_mem_offset (v, mode)
 }
 
 
-/* Make normal rtx_code into something we can index from an array */
+/* Make normal rtx_code into something we can index from an array */
 
 static enum internal_test
-map_test_to_internal_test (test_code)
-     enum rtx_code test_code;
+map_test_to_internal_test (enum rtx_code test_code)
 {
   enum internal_test test = ITEST_MAX;
 
@@ -936,18 +866,18 @@ map_test_to_internal_test (test_code)
 
 
 /* Generate the code to compare two integer values.  The return value is
-   the comparison expression. */
+   the comparison expression.  */
 
 static rtx
-gen_int_relational (test_code, cmp0, cmp1, p_invert)
-     enum rtx_code test_code;  /* relational test (EQ, etc) */
-     rtx cmp0;                 /* first operand to compare */
-     rtx cmp1;                 /* second operand to compare */
-     int *p_invert;            /* whether branch needs to reverse its test */
+gen_int_relational (enum rtx_code test_code, /* relational test (EQ, etc) */
+                   rtx cmp0, /* first operand to compare */
+                   rtx cmp1, /* second operand to compare */
+                   int *p_invert /* whether branch needs to reverse test */)
 {
-  struct cmp_info {
+  struct cmp_info
+  {
     enum rtx_code test_code;   /* test code to use in insn */
-    int (*const_range_p) PARAMS ((int)); /* predicate function to check range */
+    int (*const_range_p) (int);        /* predicate function to check range */
     int const_add;             /* constant to add (convert LE -> LT) */
     int reverse_regs;          /* reverse registers in test */
     int invert_const;          /* != 0 if invert value if cmp1 is constant */
@@ -1035,15 +965,14 @@ gen_int_relational (test_code, cmp0, cmp1, p_invert)
 
 
 /* Generate the code to compare two float values.  The return value is
-   the comparison expression. */
+   the comparison expression.  */
 
 static rtx
-gen_float_relational (test_code, cmp0, cmp1)
-     enum rtx_code test_code;  /* relational test (EQ, etc) */
-     rtx cmp0;                 /* first operand to compare */
-     rtx cmp1;                 /* second operand to compare */
+gen_float_relational (enum rtx_code test_code, /* relational test (EQ, etc) */
+                     rtx cmp0, /* first operand to compare */
+                     rtx cmp1 /* second operand to compare */)
 {
-  rtx (*gen_fn) PARAMS ((rtx, rtx, rtx));
+  rtx (*gen_fn) (rtx, rtx, rtx);
   rtx brtmp;
   int reverse_regs, invert;
 
@@ -1055,7 +984,7 @@ gen_float_relational (test_code, cmp0, cmp1)
     case GT: reverse_regs = 1; invert = 0; gen_fn = gen_slt_sf; break;
     case LT: reverse_regs = 0; invert = 0; gen_fn = gen_slt_sf; break;
     case GE: reverse_regs = 1; invert = 0; gen_fn = gen_sle_sf; break;
-    default: 
+    default:
       fatal_insn ("bad test", gen_rtx (test_code, VOIDmode, cmp0, cmp1));
       reverse_regs = 0; invert = 0; gen_fn = 0; /* avoid compiler warnings */
     }
@@ -1075,9 +1004,7 @@ gen_float_relational (test_code, cmp0, cmp1)
 
 
 void
-xtensa_expand_conditional_branch (operands, test_code)
-     rtx *operands;
-     enum rtx_code test_code;
+xtensa_expand_conditional_branch (rtx *operands, enum rtx_code test_code)
 {
   enum cmp_type type = branch_type;
   rtx cmp0 = branch_cmp[0];
@@ -1124,8 +1051,7 @@ xtensa_expand_conditional_branch (operands, test_code)
 
 
 static rtx
-gen_conditional_move (cmp)
-     rtx cmp;
+gen_conditional_move (rtx cmp)
 {
   enum rtx_code code = GET_CODE (cmp);
   rtx op0 = branch_cmp[0];
@@ -1139,7 +1065,7 @@ gen_conditional_move (cmp)
         comparison supported in Xtensa.  We shouldn't have to
         transform <LE x const> comparisons, because neither
         xtensa_expand_conditional_branch() nor get_condition() will
-        produce them. */
+        produce them.  */
 
       if ((code == GT) && (op1 == constm1_rtx))
        {
@@ -1198,12 +1124,10 @@ gen_conditional_move (cmp)
 
 
 int
-xtensa_expand_conditional_move (operands, isflt)
-    rtx *operands;
-    int isflt;
+xtensa_expand_conditional_move (rtx *operands, int isflt)
 {
   rtx cmp;
-  rtx (*gen_fn) PARAMS ((rtx, rtx, rtx, rtx, rtx));
+  rtx (*gen_fn) (rtx, rtx, rtx, rtx, rtx);
 
   if (!(cmp = gen_conditional_move (operands[1])))
     return 0;
@@ -1224,13 +1148,12 @@ xtensa_expand_conditional_move (operands, isflt)
 
 
 int
-xtensa_expand_scc (operands)
-     rtx *operands;
+xtensa_expand_scc (rtx *operands)
 {
   rtx dest = operands[0];
   rtx cmp = operands[1];
   rtx one_tmp, zero_tmp;
-  rtx (*gen_fn) PARAMS ((rtx, rtx, rtx, rtx, rtx));
+  rtx (*gen_fn) (rtx, rtx, rtx, rtx, rtx);
 
   if (!(cmp = gen_conditional_move (cmp)))
     return 0;
@@ -1248,75 +1171,99 @@ xtensa_expand_scc (operands)
 }
 
 
-/* Emit insns to move operands[1] into operands[0].
+/* Split OP[1] into OP[2,3] and likewise for OP[0] into OP[0,1].  MODE is
+   for the output, i.e., the input operands are twice as big as MODE.  */
+
+void
+xtensa_split_operand_pair (rtx operands[4], enum machine_mode mode)
+{
+  switch (GET_CODE (operands[1]))
+    {
+    case REG:
+      operands[3] = gen_rtx_REG (mode, REGNO (operands[1]) + 1);
+      operands[2] = gen_rtx_REG (mode, REGNO (operands[1]));
+      break;
+
+    case MEM:
+      operands[3] = adjust_address (operands[1], mode, GET_MODE_SIZE (mode));
+      operands[2] = adjust_address (operands[1], mode, 0);
+      break;
+
+    case CONST_INT:
+    case CONST_DOUBLE:
+      split_double (operands[1], &operands[2], &operands[3]);
+      break;
+
+    default:
+      abort ();
+    }
+
+  switch (GET_CODE (operands[0]))
+    {
+    case REG:
+      operands[1] = gen_rtx_REG (mode, REGNO (operands[0]) + 1);
+      operands[0] = gen_rtx_REG (mode, REGNO (operands[0]));
+      break;
+
+    case MEM:
+      operands[1] = adjust_address (operands[0], mode, GET_MODE_SIZE (mode));
+      operands[0] = adjust_address (operands[0], mode, 0);
+      break;
+
+    default:
+      abort ();
+    }
+}
+
 
+/* Emit insns to move operands[1] into operands[0].
    Return 1 if we have written out everything that needs to be done to
    do the move.  Otherwise, return 0 and the caller will emit the move
    normally.  */
 
 int
-xtensa_emit_move_sequence (operands, mode)
-     rtx *operands;
-     enum machine_mode mode;
+xtensa_emit_move_sequence (rtx *operands, enum machine_mode mode)
 {
   if (CONSTANT_P (operands[1])
       && GET_CODE (operands[1]) != CONSTANT_P_RTX
       && (GET_CODE (operands[1]) != CONST_INT
          || !xtensa_simm12b (INTVAL (operands[1]))))
     {
-      xtensa_load_constant (operands[0], operands[1]);
-      return 1;
-    }
+      if (!TARGET_CONST16)
+       operands[1] = force_const_mem (SImode, operands[1]);
 
-  if (!(reload_in_progress | reload_completed))
-    {
-      if (!xtensa_valid_move (mode, operands))
-       operands[1] = force_reg (mode, operands[1]);
+      /* PC-relative loads are always SImode, and CONST16 is only
+        supported in the movsi pattern, so add a SUBREG for any other
+        (smaller) mode.  */
 
-      /* Check if this move is copying an incoming argument in a7.  If
-        so, emit the move, followed by the special "set_frame_ptr"
-        unspec_volatile insn, at the very beginning of the function.
-        This is necessary because the register allocator will ignore
-        conflicts with a7 and may assign some other pseudo to a7.  If
-        that pseudo was assigned prior to this move, it would clobber
-        the incoming argument in a7.  By copying the argument out of
-        a7 as the very first thing, and then immediately following
-        that with an unspec_volatile to keep the scheduler away, we
-        should avoid any problems.  */
-
-      if (a7_overlap_mentioned_p (operands[1]))
+      if (mode != SImode)
        {
-         rtx mov;
-         switch (mode)
+         if (register_operand (operands[0], mode))
            {
-           case SImode:
-             mov = gen_movsi_internal (operands[0], operands[1]);
-             break;
-           case HImode:
-             mov = gen_movhi_internal (operands[0], operands[1]);
-             break;
-           case QImode:
-             mov = gen_movqi_internal (operands[0], operands[1]);
-             break;
-           default:
-             abort ();
+             operands[0] = simplify_gen_subreg (SImode, operands[0], mode, 0);
+             emit_move_insn (operands[0], operands[1]);
+             return 1;
            }
+         else
+           {
+             operands[1] = force_reg (SImode, operands[1]);
+             operands[1] = gen_lowpart_SUBREG (mode, operands[1]);
+           }
+       }
+    }
 
-         /* Insert the instructions before any other argument copies.
-            (The set_frame_ptr insn comes _after_ the move, so push it
-            out first.)  */
-         push_topmost_sequence ();
-         emit_insn_after (gen_set_frame_ptr (), get_insns ());
-         emit_insn_after (mov, get_insns ());
-         pop_topmost_sequence ();
+  if (!(reload_in_progress | reload_completed))
+    {
+      if (!xtensa_valid_move (mode, operands))
+       operands[1] = force_reg (mode, operands[1]);
 
-         return 1;
-       }
+      if (xtensa_copy_incoming_a7 (operands, mode))
+       return 1;
     }
 
   /* During reload we don't want to emit (subreg:X (mem:Y)) since that
-     instruction won't be recognized after reload. So we remove the
-     subreg and adjust mem accordingly. */
+     instruction won't be recognized after reload, so we remove the
+     subreg and adjust mem accordingly.  */
   if (reload_in_progress)
     {
       operands[0] = fixup_subreg_mem (operands[0]);
@@ -1325,9 +1272,9 @@ xtensa_emit_move_sequence (operands, mode)
   return 0;
 }
 
+
 static rtx
-fixup_subreg_mem (x)
-     rtx x;
+fixup_subreg_mem (rtx x)
 {
   if (GET_CODE (x) == SUBREG
       && GET_CODE (SUBREG_REG (x)) == REG
@@ -1343,6 +1290,72 @@ fixup_subreg_mem (x)
 }
 
 
+/* Check if this move is copying an incoming argument in a7.  If so,
+   emit the move, followed by the special "set_frame_ptr"
+   unspec_volatile insn, at the very beginning of the function.  This
+   is necessary because the register allocator will ignore conflicts
+   with a7 and may assign some other pseudo to a7.  If that pseudo was
+   assigned prior to this move, it would clobber the incoming argument
+   in a7.  By copying the argument out of a7 as the very first thing,
+   and then immediately following that with an unspec_volatile to keep
+   the scheduler away, we should avoid any problems.  */
+
+bool
+xtensa_copy_incoming_a7 (rtx *operands, enum machine_mode mode)
+{
+  if (a7_overlap_mentioned_p (operands[1])
+      && !cfun->machine->incoming_a7_copied)
+    {
+      rtx mov;
+      switch (mode)
+       {
+       case DFmode:
+         mov = gen_movdf_internal (operands[0], operands[1]);
+         break;
+       case SFmode:
+         mov = gen_movsf_internal (operands[0], operands[1]);
+         break;
+       case DImode:
+         mov = gen_movdi_internal (operands[0], operands[1]);
+         break;
+       case SImode:
+         mov = gen_movsi_internal (operands[0], operands[1]);
+         break;
+       case HImode:
+         mov = gen_movhi_internal (operands[0], operands[1]);
+         break;
+       case QImode:
+         mov = gen_movqi_internal (operands[0], operands[1]);
+         break;
+       default:
+         abort ();
+       }
+
+      /* Insert the instructions before any other argument copies.
+        (The set_frame_ptr insn comes _after_ the move, so push it
+        out first.)  */
+      push_topmost_sequence ();
+      emit_insn_after (gen_set_frame_ptr (), get_insns ());
+      emit_insn_after (mov, get_insns ());
+      pop_topmost_sequence ();
+
+      /* Ideally the incoming argument in a7 would only be copied
+        once, since propagating a7 into the body of a function
+        will almost certainly lead to errors.  However, there is
+        at least one harmless case (in GCSE) where the original
+        copy from a7 is changed to copy into a new pseudo.  Thus,
+        we use a flag to only do this special treatment for the
+        first copy of a7.  */
+
+      cfun->machine->incoming_a7_copied = true;
+
+      return 1;
+    }
+
+  return 0;
+}
+
+
 /* Try to expand a block move operation to an RTL block move instruction.
    If not optimizing or if the block size is not a constant or if the
    block is small, the expansion fails and GCC falls back to calling
@@ -1354,8 +1367,7 @@ fixup_subreg_mem (x)
    operands[3] is the alignment */
 
 int
-xtensa_expand_block_move (operands)
-     rtx *operands;
+xtensa_expand_block_move (rtx *operands)
 {
   rtx dest = operands[0];
   rtx src = operands[1];
@@ -1397,16 +1409,14 @@ xtensa_expand_block_move (operands)
     temporary registers, store those N values, and repeat until the
     complete block has been moved.  N=delay_slots+1 */
 
-struct meminsnbuf {
+struct meminsnbuf
+{
   char template[30];
   rtx operands[2];
 };
 
 void
-xtensa_emit_block_move (operands, tmpregs, delay_slots)
-     rtx *operands;
-     rtx *tmpregs;
-     int delay_slots;
+xtensa_emit_block_move (rtx *operands, rtx *tmpregs, int delay_slots)
 {
   rtx dest = operands[0];
   rtx src = operands[1];
@@ -1495,8 +1505,7 @@ xtensa_emit_block_move (operands, tmpregs, delay_slots)
 
 
 static enum machine_mode
-xtensa_find_mode_for_size (item_size)
-     unsigned item_size;
+xtensa_find_mode_for_size (unsigned item_size)
 {
   enum machine_mode mode, tmode;
 
@@ -1527,8 +1536,7 @@ xtensa_find_mode_for_size (item_size)
 
 
 void
-xtensa_expand_nonlocal_goto (operands)
-     rtx *operands;
+xtensa_expand_nonlocal_goto (rtx *operands)
 {
   rtx goto_handler = operands[1];
   rtx containing_fp = operands[3];
@@ -1551,16 +1559,16 @@ xtensa_expand_nonlocal_goto (operands)
 
 
 static struct machine_function *
-xtensa_init_machine_status ()
+xtensa_init_machine_status (void)
 {
   return ggc_alloc_cleared (sizeof (struct machine_function));
 }
 
 
 void
-xtensa_setup_frame_addresses ()
+xtensa_setup_frame_addresses (void)
 {
-  /* Set flag to cause FRAME_POINTER_REQUIRED to be set. */
+  /* Set flag to cause FRAME_POINTER_REQUIRED to be set.  */
   cfun->machine->accesses_prev_frame = 1;
 
   emit_library_call
@@ -1569,23 +1577,21 @@ xtensa_setup_frame_addresses ()
 }
 
 
-/* Emit the assembly for the end of a zero-cost loop. Normally we just emit
-   a comment showing where the end of the loop is. However, if there is a
+/* Emit the assembly for the end of a zero-cost loop.  Normally we just emit
+   a comment showing where the end of the loop is.  However, if there is a
    label or a branch at the end of the loop then we need to place a nop
-   there. If the loop ends with a label we need the nop so that branches
+   there.  If the loop ends with a label we need the nop so that branches
    targetting that label will target the nop (and thus remain in the loop),
    instead of targetting the instruction after the loop (and thus exiting
-   the loop). If the loop ends with a branch, we need the nop in case the
-   branch is targetting a location inside the loop. When the branch
+   the loop).  If the loop ends with a branch, we need the nop in case the
+   branch is targetting a location inside the loop.  When the branch
    executes it will cause the loop count to be decremented even if it is
    taken (because it is the last instruction in the loop), so we need to
    nop after the branch to prevent the loop count from being decremented
-   when the branch is taken. */
+   when the branch is taken.  */
 
 void
-xtensa_emit_loop_end (insn, operands)
-     rtx insn;
-     rtx *operands;
+xtensa_emit_loop_end (rtx insn, rtx *operands)
 {
   char done = 0;
 
@@ -1598,7 +1604,7 @@ xtensa_emit_loop_end (insn, operands)
          break;
 
        case CODE_LABEL:
-         output_asm_insn ("nop.n", operands);
+         output_asm_insn (TARGET_DENSITY ? "nop.n" : "nop", operands);
          done = 1;
          break;
 
@@ -1608,7 +1614,7 @@ xtensa_emit_loop_end (insn, operands)
 
            if (GET_CODE (body) == JUMP_INSN)
              {
-               output_asm_insn ("nop.n", operands);
+               output_asm_insn (TARGET_DENSITY ? "nop.n" : "nop", operands);
                done = 1;
              }
            else if ((GET_CODE (body) != USE)
@@ -1624,15 +1630,13 @@ xtensa_emit_loop_end (insn, operands)
 
 
 char *
-xtensa_emit_call (callop, operands)
-     int callop;
-     rtx *operands;
+xtensa_emit_call (int callop, rtx *operands)
 {
   static char result[64];
   rtx tgt = operands[callop];
 
   if (GET_CODE (tgt) == CONST_INT)
-    sprintf (result, "call8\t0x%x", INTVAL (tgt));
+    sprintf (result, "call8\t0x%lx", INTVAL (tgt));
   else if (register_operand (tgt, VOIDmode))
     sprintf (result, "callx8\t%%%d", callop);
   else
@@ -1642,39 +1646,36 @@ xtensa_emit_call (callop, operands)
 }
 
 
-/* Return the stabs register number to use for 'regno'. */
+/* Return the debugger register number to use for 'regno'.  */
 
 int
-xtensa_dbx_register_number (regno)
-     int regno;
+xtensa_dbx_register_number (int regno)
 {
   int first = -1;
-  
-  if (GP_REG_P (regno)) {
-    regno -= GP_REG_FIRST;
-    first = 0;
-  }
-  else if (BR_REG_P (regno)) {
-    regno -= BR_REG_FIRST;
-    first = 16;
-  }
-  else if (FP_REG_P (regno)) {
-    regno -= FP_REG_FIRST;
-    /* The current numbering convention is that TIE registers are
-       numbered in libcc order beginning with 256.  We can't guarantee
-       that the FP registers will come first, so the following is just
-       a guess.  It seems like we should make a special case for FP
-       registers and give them fixed numbers < 256. */
-    first = 256;
-  }
-  else if (ACC_REG_P (regno))
+
+  if (GP_REG_P (regno))
     {
+      regno -= GP_REG_FIRST;
       first = 0;
-      regno = -1;
+    }
+  else if (BR_REG_P (regno))
+    {
+      regno -= BR_REG_FIRST;
+      first = 16;
+    }
+  else if (FP_REG_P (regno))
+    {
+      regno -= FP_REG_FIRST;
+      first = 48;
+    }
+  else if (ACC_REG_P (regno))
+    {
+      first = 0x200;   /* Start of Xtensa special registers.  */
+      regno = 16;      /* ACCLO is special register 16.  */
     }
 
   /* When optimizing, we sometimes get asked about pseudo-registers
-     that don't represent hard registers. Return 0 for these. */
+     that don't represent hard registers.  Return 0 for these.  */
   if (first == -1)
     return 0;
 
@@ -1687,21 +1688,18 @@ xtensa_dbx_register_number (regno)
 /* Initialize CUMULATIVE_ARGS for a function.  */
 
 void
-init_cumulative_args (cum, fntype, libname)
-     CUMULATIVE_ARGS *cum;     /* argument info to initialize */
-     tree fntype ATTRIBUTE_UNUSED;     /* tree ptr for function decl */
-     rtx libname ATTRIBUTE_UNUSED;     /* SYMBOL_REF of library name or 0 */
+init_cumulative_args (CUMULATIVE_ARGS *cum,
+                     tree fntype ATTRIBUTE_UNUSED,
+                     rtx libname ATTRIBUTE_UNUSED)
 {
   cum->arg_words = 0;
 }
 
+
 /* Advance the argument to the next argument position.  */
 
 void
-function_arg_advance (cum, mode, type)
-     CUMULATIVE_ARGS *cum;     /* current arg information */
-     enum machine_mode mode;   /* current arg mode */
-     tree type;                        /* type of the argument or 0 if lib support */
+function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type)
 {
   int words, max;
   int *arg_words;
@@ -1721,14 +1719,12 @@ function_arg_advance (cum, mode, type)
 
 
 /* Return an RTL expression containing the register for the given mode,
-   or 0 if the argument is to be passed on the stack.  */
+   or 0 if the argument is to be passed on the stack.  INCOMING_P is nonzero
+   if this is an incoming argument to the current function.  */
 
 rtx
-function_arg (cum, mode, type, incoming_p)
-     CUMULATIVE_ARGS *cum;     /* current arg information */
-     enum machine_mode mode;   /* current arg mode */
-     tree type;                        /* type of the argument or 0 if lib support */
-     int incoming_p;           /* computing the incoming registers? */
+function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type,
+             int incoming_p)
 {
   int regbase, words, max;
   int *arg_words;
@@ -1756,7 +1752,7 @@ function_arg (cum, mode, type, incoming_p)
      rtx that is not equal to hard_frame_pointer_rtx.  For BLKmode and
      modes bigger than 2 words (because we only have patterns for
      modes of 2 words or smaller), we can't control the expansion
-     unless we explicitly list the individual registers in a PARALLEL. */
+     unless we explicitly list the individual registers in a PARALLEL.  */
 
   if ((mode == BLKmode || words > 2)
       && regno < A7_REG
@@ -1781,7 +1777,7 @@ function_arg (cum, mode, type, incoming_p)
 
 
 void
-override_options ()
+override_options (void)
 {
   int regno;
   enum machine_mode mode;
@@ -1806,8 +1802,9 @@ override_options ()
   xtensa_char_to_class['C'] = ((TARGET_MUL16) ? GR_REGS: NO_REGS);
   xtensa_char_to_class['D'] = ((TARGET_DENSITY) ? GR_REGS: NO_REGS);
   xtensa_char_to_class['d'] = ((TARGET_DENSITY) ? AR_REGS: NO_REGS);
+  xtensa_char_to_class['W'] = ((TARGET_CONST16) ? GR_REGS: NO_REGS);
 
-  /* Set up array giving whether a given register can hold a given mode. */
+  /* Set up array giving whether a given register can hold a given mode.  */
   for (mode = VOIDmode;
        mode != MAX_MACHINE_MODE;
        mode = (enum machine_mode) ((int) mode + 1))
@@ -1820,8 +1817,8 @@ override_options ()
          int temp;
 
          if (ACC_REG_P (regno))
-           temp = (TARGET_MAC16 &&
-                   (class == MODE_INT) && (size <= UNITS_PER_WORD));
+           temp = (TARGET_MAC16
+                   && (class == MODE_INT) && (size <= UNITS_PER_WORD));
          else if (GP_REG_P (regno))
            temp = ((regno & 1) == 0 || (size <= UNITS_PER_WORD));
          else if (FP_REG_P (regno))
@@ -1837,9 +1834,19 @@ override_options ()
 
   init_machine_status = xtensa_init_machine_status;
 
-  /* Check PIC settings.  There's no need for -fPIC on Xtensa and
-     some targets need to always use PIC.  */
-  if (flag_pic > 1 || (XTENSA_ALWAYS_PIC))
+  /* Check PIC settings.  PIC is only supported when using L32R
+     instructions, and some targets need to always use PIC.  */
+  if (flag_pic && TARGET_CONST16)
+    error ("-f%s is not supported with CONST16 instructions",
+          (flag_pic > 1 ? "PIC" : "pic"));
+  else if (XTENSA_ALWAYS_PIC)
+    {
+      if (TARGET_CONST16)
+       error ("PIC is required but not supported with CONST16 instructions");
+      flag_pic = 1;
+    }
+  /* There's no need for -fPIC (as opposed to -fpic) on Xtensa.  */
+  if (flag_pic > 1)
     flag_pic = 1;
 }
 
@@ -1865,7 +1872,7 @@ override_options ()
    a null pointer for X and the punctuation character for CODE.
 
    'a', 'c', 'l', and 'n' are reserved.
-   
+
    The Xtensa specific codes are:
 
    'd'  CONST_INT, print as signed decimal
@@ -1876,14 +1883,14 @@ override_options ()
    'D'  REG, print second register of double-word register operand
    'N'  MEM, print address of next word following a memory operand
    'v'  MEM, if memory reference is volatile, output a MEMW before it
+   't'  any constant, add "@h" suffix for top 16 bits
+   'b'  any constant, add "@l" suffix for bottom 16 bits
 */
 
 static void
-printx (file, val)
-     FILE *file;
-     signed int val;
+printx (FILE *file, signed int val)
 {
-  /* print a hexadecimal value in a nice way */
+  /* Print a hexadecimal value in a nice way.  */
   if ((val > -0xa) && (val < 0xa))
     fprintf (file, "%d", val);
   else if (val < 0)
@@ -1894,94 +1901,143 @@ printx (file, val)
 
 
 void
-print_operand (file, op, letter)
-     FILE *file;               /* file to write to */
-     rtx op;           /* operand to print */
-     int letter;               /* %<letter> or 0 */
+print_operand (FILE *file, rtx x, int letter)
 {
-  enum rtx_code code;
-
-  if (! op)
+  if (!x)
     error ("PRINT_OPERAND null pointer");
 
-  code = GET_CODE (op);
-  switch (code)
+  switch (letter)
     {
-    case REG:
-    case SUBREG:
-      {
-       int regnum = xt_true_regnum (op);
-       if (letter == 'D')
-         regnum++;
-       fprintf (file, "%s", reg_names[regnum]);
-       break;
-      }
+    case 'D':
+      if (GET_CODE (x) == REG || GET_CODE (x) == SUBREG)
+       fprintf (file, "%s", reg_names[xt_true_regnum (x) + 1]);
+      else
+       output_operand_lossage ("invalid %%D value");
+      break;
 
-    case MEM:
-      /* For a volatile memory reference, emit a MEMW before the
-        load or store.  */
-       if (letter == 'v')
-         {
-           if (MEM_VOLATILE_P (op) && TARGET_SERIALIZE_VOLATILE)
-             fprintf (file, "memw\n\t");
-           break;
-         }
-       else if (letter == 'N')
-         {
-           enum machine_mode mode;
-           switch (GET_MODE (op))
-             {
-             case DFmode: mode = SFmode; break;
-             case DImode: mode = SImode; break;
-             default: abort ();
-             }
-           op = adjust_address (op, mode, 4);
-         }
+    case 'v':
+      if (GET_CODE (x) == MEM)
+       {
+         /* For a volatile memory reference, emit a MEMW before the
+            load or store.  */
+         if (MEM_VOLATILE_P (x))
+           fprintf (file, "memw\n\t");
+       }
+      else
+       output_operand_lossage ("invalid %%v value");
+      break;
 
-       output_address (XEXP (op, 0));
-       break;
+    case 'N':
+      if (GET_CODE (x) == MEM
+         && (GET_MODE (x) == DFmode || GET_MODE (x) == DImode))
+       {
+         x = adjust_address (x, GET_MODE (x) == DFmode ? SFmode : SImode, 4);
+         output_address (XEXP (x, 0));
+       }
+      else
+       output_operand_lossage ("invalid %%N value");
+      break;
 
-    case CONST_INT:
-      switch (letter)
+    case 'K':
+      if (GET_CODE (x) == CONST_INT)
        {
-       case 'K':
-         {
-           int num_bits = 0;
-           unsigned val = INTVAL (op);
-           while (val & 1)
-             {
-               num_bits += 1;
-               val = val >> 1;
-             }
-           if ((val != 0) || (num_bits == 0) || (num_bits > 16))
-             fatal_insn ("invalid mask", op);
+         int num_bits = 0;
+         unsigned val = INTVAL (x);
+         while (val & 1)
+           {
+             num_bits += 1;
+             val = val >> 1;
+           }
+         if ((val != 0) || (num_bits == 0) || (num_bits > 16))
+           fatal_insn ("invalid mask", x);
 
-           fprintf (file, "%d", num_bits);
-           break;
-         }
+         fprintf (file, "%d", num_bits);
+       }
+      else
+       output_operand_lossage ("invalid %%K value");
+      break;
 
-       case 'L':
-         fprintf (file, "%d", (32 - INTVAL (op)) & 0x1f);
-         break;
+    case 'L':
+      if (GET_CODE (x) == CONST_INT)
+       fprintf (file, "%ld", (32 - INTVAL (x)) & 0x1f);
+      else
+       output_operand_lossage ("invalid %%L value");
+      break;
 
-       case 'R':
-         fprintf (file, "%d", INTVAL (op) & 0x1f);
-         break;
+    case 'R':
+      if (GET_CODE (x) == CONST_INT)
+       fprintf (file, "%ld", INTVAL (x) & 0x1f);
+      else
+       output_operand_lossage ("invalid %%R value");
+      break;
 
-       case 'x':
-         printx (file, INTVAL (op));
-         break;
+    case 'x':
+      if (GET_CODE (x) == CONST_INT)
+       printx (file, INTVAL (x));
+      else
+       output_operand_lossage ("invalid %%x value");
+      break;
 
-       case 'd':
-       default:
-         fprintf (file, "%d", INTVAL (op));
-         break;
+    case 'd':
+      if (GET_CODE (x) == CONST_INT)
+       fprintf (file, "%ld", INTVAL (x));
+      else
+       output_operand_lossage ("invalid %%d value");
+      break;
 
+    case 't':
+    case 'b':
+      if (GET_CODE (x) == CONST_INT)
+       {
+         printx (file, INTVAL (x));
+         fputs (letter == 't' ? "@h" : "@l", file);
+       }
+      else if (GET_CODE (x) == CONST_DOUBLE)
+       {
+         REAL_VALUE_TYPE r;
+         REAL_VALUE_FROM_CONST_DOUBLE (r, x);
+         if (GET_MODE (x) == SFmode)
+           {
+             long l;
+             REAL_VALUE_TO_TARGET_SINGLE (r, l);
+             fprintf (file, "0x%08lx@%c", l, letter == 't' ? 'h' : 'l');
+           }
+         else
+           output_operand_lossage ("invalid %%t/%%b value");
+       }
+      else if (GET_CODE (x) == CONST)
+       {
+         /* X must be a symbolic constant on ELF.  Write an expression
+            suitable for 'const16' that sets the high or low 16 bits.  */
+         if (GET_CODE (XEXP (x, 0)) != PLUS
+             || (GET_CODE (XEXP (XEXP (x, 0), 0)) != SYMBOL_REF
+                 && GET_CODE (XEXP (XEXP (x, 0), 0)) != LABEL_REF)
+             || GET_CODE (XEXP (XEXP (x, 0), 1)) != CONST_INT)
+           output_operand_lossage ("invalid %%t/%%b value");
+         print_operand (file, XEXP (XEXP (x, 0), 0), 0);
+         fputs (letter == 't' ? "@h" : "@l", file);
+         /* There must be a non-alphanumeric character between 'h' or 'l'
+            and the number.  The '-' is added by print_operand() already.  */
+         if (INTVAL (XEXP (XEXP (x, 0), 1)) >= 0)
+           fputs ("+", file);
+         print_operand (file, XEXP (XEXP (x, 0), 1), 0);
+       }
+      else
+       {
+         output_addr_const (file, x);
+         fputs (letter == 't' ? "@h" : "@l", file);
        }
       break;
 
     default:
-      output_addr_const (file, op);
+      if (GET_CODE (x) == REG || GET_CODE (x) == SUBREG)
+       fprintf (file, "%s", reg_names[xt_true_regnum (x)]);
+      else if (GET_CODE (x) == MEM)
+       output_address (XEXP (x, 0));
+      else if (GET_CODE (x) == CONST_INT)
+       fprintf (file, "%ld", INTVAL (x));
+      else
+       output_addr_const (file, x);
     }
 }
 
@@ -1991,9 +2047,7 @@ print_operand (file, op, letter)
    reference whose address is ADDR.  ADDR is an RTL expression.  */
 
 void
-print_operand_address (file, addr)
-     FILE *file;
-     rtx addr;
+print_operand_address (FILE *file, rtx addr)
 {
   if (!addr)
     error ("PRINT_OPERAND_ADDRESS, null pointer");
@@ -2048,28 +2102,8 @@ print_operand_address (file, addr)
 }
 
 
-/* Emit either a label, .comm, or .lcomm directive. */
-
-void
-xtensa_declare_object (file, name, init_string, final_string, size)
-     FILE *file;
-     char *name;
-     char *init_string;
-     char *final_string;
-     int size;
-{
-  fputs (init_string, file);           /* "", "\t.comm\t", or "\t.lcomm\t" */
-  assemble_name (file, name);
-  fprintf (file, final_string, size);  /* ":\n", ",%u\n", ",%u\n" */
-}
-
-
 void
-xtensa_output_literal (file, x, mode, labelno)
-     FILE *file;
-     rtx x;
-     enum machine_mode mode;
-     int labelno;
+xtensa_output_literal (FILE *file, rtx x, enum machine_mode mode, int labelno)
 {
   long value_long[2];
   REAL_VALUE_TYPE r;
@@ -2129,16 +2163,15 @@ xtensa_output_literal (file, x, mode, labelno)
 
 
 /* Return the bytes needed to compute the frame pointer from the current
-   stack pointer. */
+   stack pointer.  */
 
 #define STACK_BYTES (STACK_BOUNDARY / BITS_PER_UNIT)
 #define XTENSA_STACK_ALIGN(LOC) (((LOC) + STACK_BYTES-1) & ~(STACK_BYTES-1))
 
 long
-compute_frame_size (size)
-     int size;                 /* # of var. bytes allocated */
+compute_frame_size (int size)
 {
-  /* add space for the incoming static chain value */
+  /* Add space for the incoming static chain value.  */
   if (current_function_needs_context)
     size += (1 * UNITS_PER_WORD);
 
@@ -2151,12 +2184,12 @@ compute_frame_size (size)
 
 
 int
-xtensa_frame_pointer_required ()
+xtensa_frame_pointer_required (void)
 {
   /* The code to expand builtin_frame_addr and builtin_return_addr
      currently uses the hard_frame_pointer instead of frame_pointer.
      This seems wrong but maybe it's necessary for other architectures.
-     This function is derived from the i386 code. */
+     This function is derived from the i386 code.  */
 
   if (cfun->machine->accesses_prev_frame)
     return 1;
@@ -2166,130 +2199,94 @@ xtensa_frame_pointer_required ()
 
 
 void
-xtensa_reorg (first)
-    rtx first;
-{
-  rtx insn, set_frame_ptr_insn = 0;
-    
-  unsigned long tsize = compute_frame_size (get_frame_size ());
-  if (tsize < (1 << (12+3)))
-    frame_size_const = 0;
-  else
-    {
-      frame_size_const = force_const_mem (SImode, GEN_INT (tsize - 16));;
-
-      /* make sure the constant is used so it doesn't get eliminated
-        from the constant pool */
-      emit_insn_before (gen_rtx_USE (SImode, frame_size_const), first);
-    }
-
-  if (!frame_pointer_needed)
-    return;
+xtensa_expand_prologue (void)
+{
+  HOST_WIDE_INT total_size;
+  rtx size_rtx;
 
-  /* Search all instructions, looking for the insn that sets up the
-     frame pointer.  This search will fail if the function does not
-     have an incoming argument in $a7, but in that case, we can just
-     set up the frame pointer at the very beginning of the
-     function. */
+  total_size = compute_frame_size (get_frame_size ());
+  size_rtx = GEN_INT (total_size);
 
-  for (insn = first; insn; insn = NEXT_INSN (insn))
+  if (total_size < (1 << (12+3)))
+    emit_insn (gen_entry (size_rtx, size_rtx));
+  else
     {
-      rtx pat;
-
-      if (!INSN_P (insn))
-       continue;
-
-      pat = PATTERN (insn);
-      if (GET_CODE (pat) == UNSPEC_VOLATILE
-         && (XINT (pat, 1) == UNSPECV_SET_FP))
-       {
-         set_frame_ptr_insn = insn;
-         break;
-       }
+      /* Use a8 as a temporary since a0-a7 may be live.  */
+      rtx tmp_reg = gen_rtx_REG (Pmode, A8_REG);
+      emit_insn (gen_entry (size_rtx, GEN_INT (MIN_FRAME_SIZE)));
+      emit_move_insn (tmp_reg, GEN_INT (total_size - MIN_FRAME_SIZE));
+      emit_insn (gen_subsi3 (tmp_reg, stack_pointer_rtx, tmp_reg));
+      emit_move_insn (stack_pointer_rtx, tmp_reg);
     }
 
-  if (set_frame_ptr_insn)
-    {
-      /* for all instructions prior to set_frame_ptr_insn, replace
-        hard_frame_pointer references with stack_pointer */
-      for (insn = first; insn != set_frame_ptr_insn; insn = NEXT_INSN (insn))
-       {
-         if (INSN_P (insn))
-           PATTERN (insn) = replace_rtx (copy_rtx (PATTERN (insn)),
-                                         hard_frame_pointer_rtx,
-                                         stack_pointer_rtx);
-       }
-    }
-  else
+  if (frame_pointer_needed)
     {
-      /* emit the frame pointer move immediately after the NOTE that starts
-        the function */
-      emit_insn_after (gen_movsi (hard_frame_pointer_rtx,
-                                 stack_pointer_rtx), first);
-    }
-}
+      rtx first, insn, set_frame_ptr_insn = 0;
 
+      push_topmost_sequence ();
+      first = get_insns ();
+      pop_topmost_sequence ();
 
-/* Set up the stack and frame (if desired) for the function.  */
+      /* Search all instructions, looking for the insn that sets up the
+        frame pointer.  This search will fail if the function does not
+        have an incoming argument in $a7, but in that case, we can just
+        set up the frame pointer at the very beginning of the
+        function.  */
 
-void
-xtensa_function_prologue (file, size)
-     FILE *file;
-     int size ATTRIBUTE_UNUSED;
-{
-  unsigned long tsize = compute_frame_size (get_frame_size ());
+      for (insn = first; insn; insn = NEXT_INSN (insn))
+       {
+         rtx pat;
 
-  if (frame_pointer_needed)
-    fprintf (file, "\t.frame\ta7, %ld\n", tsize);
-  else
-    fprintf (file, "\t.frame\tsp, %ld\n", tsize);
+         if (!INSN_P (insn))
+           continue;
 
-  if (tsize < (1 << (12+3)))
-    {
-      fprintf (file, "\tentry\tsp, %ld\n", tsize);
-    }
-  else
-    {
-      fprintf (file, "\tentry\tsp, 16\n");
+         pat = PATTERN (insn);
+         if (GET_CODE (pat) == SET
+             && GET_CODE (SET_SRC (pat)) == UNSPEC_VOLATILE
+             && (XINT (SET_SRC (pat), 1) == UNSPECV_SET_FP))
+           {
+             set_frame_ptr_insn = insn;
+             break;
+           }
+       }
 
-      /* use a8 as a temporary since a0-a7 may be live */
-      fprintf (file, "\tl32r\ta8, ");
-      print_operand (file, frame_size_const, 0);
-      fprintf (file, "\n\tsub\ta8, sp, a8\n");
-      fprintf (file, "\tmovsp\tsp, a8\n");
+      if (set_frame_ptr_insn)
+       {
+         /* For all instructions prior to set_frame_ptr_insn, replace
+            hard_frame_pointer references with stack_pointer.  */
+         for (insn = first;
+              insn != set_frame_ptr_insn;
+              insn = NEXT_INSN (insn))
+           {
+             if (INSN_P (insn))
+               PATTERN (insn) = replace_rtx (copy_rtx (PATTERN (insn)),
+                                             hard_frame_pointer_rtx,
+                                             stack_pointer_rtx);
+           }
+       }
+      else
+       emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx);
     }
 }
 
 
-/* Do any necessary cleanup after a function to restore
-   stack, frame, and regs. */
+/* Clear variables at function end.  */
 
 void
-xtensa_function_epilogue (file, size)
-     FILE *file;
-     int size ATTRIBUTE_UNUSED;
+xtensa_function_epilogue (FILE *file ATTRIBUTE_UNUSED,
+                         HOST_WIDE_INT size ATTRIBUTE_UNUSED)
 {
-  rtx insn = get_last_insn ();
-  /* If the last insn was a BARRIER, we don't have to write anything. */
-  if (GET_CODE (insn) == NOTE)
-    insn = prev_nonnote_insn (insn);
-  if (insn == 0 || GET_CODE (insn) != BARRIER)
-    fprintf (file, TARGET_DENSITY ? "\tretw.n\n" : "\tretw\n");
-
   xtensa_current_frame_size = 0;
 }
 
 
 rtx
-xtensa_return_addr (count, frame)
-     int count;
-     rtx frame;
+xtensa_return_addr (int count, rtx frame)
 {
   rtx result, retaddr;
 
   if (count == -1)
-    retaddr = gen_rtx_REG (Pmode, 0);
+    retaddr = gen_rtx_REG (Pmode, A0_REG);
   else
     {
       rtx addr = plus_constant (frame, -4 * UNITS_PER_WORD);
@@ -2319,10 +2316,10 @@ xtensa_return_addr (count, frame)
    registers.  E.G., if there are 6 argument registers, and each register is
    4 bytes, then __va_stk is set to $sp - (6 * 4); then __va_reg[N*4]
    references argument word N for 0 <= N < 6, and __va_stk[N*4] references
-   argument word N for N >= 6. */
+   argument word N for N >= 6.  */
 
 tree
-xtensa_build_va_list ()
+xtensa_build_va_list (void)
 {
   tree f_stk, f_reg, f_ndx, record, type_decl;
 
@@ -2352,10 +2349,10 @@ xtensa_build_va_list ()
 
 
 /* Save the incoming argument registers on the stack.  Returns the
-   address of the saved registers. */
+   address of the saved registers.  */
 
 rtx
-xtensa_builtin_saveregs ()
+xtensa_builtin_saveregs (void)
 {
   rtx gp_regs, dest;
   int arg_words = current_function_arg_words;
@@ -2378,7 +2375,7 @@ xtensa_builtin_saveregs ()
   /* Note: Don't use move_block_from_reg() here because the incoming
      argument in a7 cannot be represented by hard_frame_pointer_rtx.
      Instead, call gen_raw_REG() directly so that we get a distinct
-     instance of (REG:SI 7). */
+     instance of (REG:SI 7).  */
   for (i = 0; i < gp_left; i++)
     {
       emit_move_insn (operand_subword (dest, i, 1, BLKmode),
@@ -2390,12 +2387,10 @@ xtensa_builtin_saveregs ()
 
 
 /* Implement `va_start' for varargs and stdarg.  We look at the
-   current function to fill in an initial va_list. */
+   current function to fill in an initial va_list.  */
 
 void
-xtensa_va_start (valist, nextarg)
-     tree valist;
-     rtx nextarg ATTRIBUTE_UNUSED;
+xtensa_va_start (tree valist, rtx nextarg ATTRIBUTE_UNUSED)
 {
   tree f_stk, stk;
   tree f_reg, reg;
@@ -2428,7 +2423,7 @@ xtensa_va_start (valist, nextarg)
   TREE_SIDE_EFFECTS (t) = 1;
   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
 
-  /* Set the __va_ndx member. */
+  /* Set the __va_ndx member.  */
   u = build_int_2 (arg_words * UNITS_PER_WORD, 0);
   t = build (MODIFY_EXPR, integer_type_node, ndx, u);
   TREE_SIDE_EFFECTS (t) = 1;
@@ -2439,8 +2434,7 @@ xtensa_va_start (valist, nextarg)
 /* Implement `va_arg'.  */
 
 rtx
-xtensa_va_arg (valist, type)
-     tree valist, type;
+xtensa_va_arg (tree valist, tree type)
 {
   tree f_stk, stk;
   tree f_reg, reg;
@@ -2475,8 +2469,7 @@ xtensa_va_arg (valist, type)
   /* First align __va_ndx to a double word boundary if necessary for this arg:
 
      if (__alignof__ (TYPE) > 4)
-       (AP).__va_ndx = (((AP).__va_ndx + 7) & -8)
-  */
+       (AP).__va_ndx = (((AP).__va_ndx + 7) & -8); */
 
   if (TYPE_ALIGN (type) > BITS_PER_WORD)
     {
@@ -2493,8 +2486,7 @@ xtensa_va_arg (valist, type)
   /* Increment __va_ndx to point past the argument:
 
      orig_ndx = (AP).__va_ndx;
-     (AP).__va_ndx += __va_size (TYPE);
-  */
+     (AP).__va_ndx += __va_size (TYPE); */
 
   orig_ndx = gen_reg_rtx (SImode);
   r = expand_expr (ndx, orig_ndx, SImode, EXPAND_NORMAL);
@@ -2512,8 +2504,7 @@ xtensa_va_arg (valist, type)
 
      if ((AP).__va_ndx <= __MAX_ARGS_IN_REGISTERS * 4
          && !MUST_PASS_IN_STACK (type))
-        __array = (AP).__va_reg;
-  */
+        __array = (AP).__va_reg; */
 
   array = gen_reg_rtx (Pmode);
 
@@ -2546,8 +2537,7 @@ xtensa_va_arg (valist, type)
         if (orig_ndx < __MAX_ARGS_IN_REGISTERS * 4)
             (AP).__va_ndx = __MAX_ARGS_IN_REGISTERS * 4 + __va_size (TYPE);
         __array = (AP).__va_stk;
-       }
-  */
+       } */
 
   lab_false2 = gen_label_rtx ();
   emit_cmp_and_jump_insns (orig_ndx,
@@ -2578,12 +2568,11 @@ xtensa_va_arg (valist, type)
                                : __va_size (TYPE))
 
      The results are endian-dependent because values smaller than one word
-     are aligned differently.
-  */
+     are aligned differently.  */
 
   size = gen_reg_rtx (SImode);
   emit_move_insn (size, va_size);
-  
+
   if (BYTES_BIG_ENDIAN)
     {
       rtx lab_use_va_size = gen_label_rtx ();
@@ -2612,27 +2601,28 @@ xtensa_va_arg (valist, type)
 
 
 enum reg_class
-xtensa_preferred_reload_class (x, class)
-     rtx x;
-     enum reg_class class;
+xtensa_preferred_reload_class (rtx x, enum reg_class class, int isoutput)
 {
-  if (CONSTANT_P (x) && GET_CODE (x) == CONST_DOUBLE)
+  if (!isoutput && CONSTANT_P (x) && GET_CODE (x) == CONST_DOUBLE)
     return NO_REGS;
 
-  /* Don't use sp for reloads! */
-  if (class == AR_REGS)
-    return GR_REGS;
+  /* Don't use the stack pointer or hard frame pointer for reloads!
+     The hard frame pointer would normally be OK except that it may
+     briefly hold an incoming argument in the prologue, and reload
+     won't know that it is live because the hard frame pointer is
+     treated specially.  */
+
+  if (class == AR_REGS || class == GR_REGS)
+    return RL_REGS;
 
   return class;
 }
 
 
 enum reg_class
-xtensa_secondary_reload_class (class, mode, x, isoutput)
-     enum reg_class class;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
-     rtx x;
-     int isoutput;
+xtensa_secondary_reload_class (enum reg_class class,
+                              enum machine_mode mode ATTRIBUTE_UNUSED,
+                              rtx x, int isoutput)
 {
   int regno;
 
@@ -2643,20 +2633,20 @@ xtensa_secondary_reload_class (class, mode, x, isoutput)
   if (!isoutput)
     {
       if (class == FP_REGS && constantpool_mem_p (x))
-       return GR_REGS;
+       return RL_REGS;
     }
 
   if (ACC_REG_P (regno))
-    return (class == GR_REGS ? NO_REGS : GR_REGS);
+    return ((class == GR_REGS || class == RL_REGS) ? NO_REGS : RL_REGS);
   if (class == ACC_REG)
-    return (GP_REG_P (regno) ? NO_REGS : GR_REGS);
+    return (GP_REG_P (regno) ? NO_REGS : RL_REGS);
 
   return NO_REGS;
 }
 
 
 void
-order_regs_for_local_alloc ()
+order_regs_for_local_alloc (void)
 {
   if (!leaf_function_p ())
     {
@@ -2678,31 +2668,30 @@ order_regs_for_local_alloc ()
       for (i = 0; i < num_arg_regs; i++)
        reg_alloc_order[nxt++] = GP_ARG_FIRST + i;
 
+      /* list the coprocessor registers in order */
+      for (i = 0; i < BR_REG_NUM; i++)
+       reg_alloc_order[nxt++] = BR_REG_FIRST + i;
+
       /* list the FP registers in order for now */
       for (i = 0; i < 16; i++)
        reg_alloc_order[nxt++] = FP_REG_FIRST + i;
 
-      /* GCC requires that we list *all* the registers.... */
+      /* GCC requires that we list *all* the registers....  */
       reg_alloc_order[nxt++] = 0;      /* a0 = return address */
       reg_alloc_order[nxt++] = 1;      /* a1 = stack pointer */
       reg_alloc_order[nxt++] = 16;     /* pseudo frame pointer */
       reg_alloc_order[nxt++] = 17;     /* pseudo arg pointer */
 
-      /* list the coprocessor registers in order */
-      for (i = 0; i < BR_REG_NUM; i++)
-       reg_alloc_order[nxt++] = BR_REG_FIRST + i;
-
       reg_alloc_order[nxt++] = ACC_REG_FIRST;  /* MAC16 accumulator */
     }
 }
 
 
 /* A customized version of reg_overlap_mentioned_p that only looks for
-   references to a7 (as opposed to hard_frame_pointer_rtx). */
+   references to a7 (as opposed to hard_frame_pointer_rtx).  */
 
 int
-a7_overlap_mentioned_p (x)
-     rtx x;
+a7_overlap_mentioned_p (rtx x)
 {
   int i, j;
   unsigned int x_regno;
@@ -2746,27 +2735,257 @@ a7_overlap_mentioned_p (x)
   return 0;
 }
 
+
+/* Some Xtensa targets support multiple bss sections.  If the section
+   name ends with ".bss", add SECTION_BSS to the flags.  */
+
+static unsigned int
+xtensa_multibss_section_type_flags (tree decl, const char *name, int reloc)
+{
+  unsigned int flags = default_section_type_flags (decl, name, reloc);
+  const char *suffix;
+
+  suffix = strrchr (name, '.');
+  if (suffix && strcmp (suffix, ".bss") == 0)
+    {
+      if (!decl || (TREE_CODE (decl) == VAR_DECL
+                   && DECL_INITIAL (decl) == NULL_TREE))
+       flags |= SECTION_BSS;  /* @nobits */
+      else
+       warning ("only uninitialized variables can be placed in a "
+                ".bss section");
+    }
+
+  return flags;
+}
+
+
 /* The literal pool stays with the function.  */
 
 static void
-xtensa_select_rtx_section (mode, x, align)
-     enum machine_mode mode ATTRIBUTE_UNUSED;
-     rtx x ATTRIBUTE_UNUSED;
-     unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED;
+xtensa_select_rtx_section (enum machine_mode mode ATTRIBUTE_UNUSED,
+                          rtx x ATTRIBUTE_UNUSED,
+                          unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED)
 {
   function_section (current_function_decl);
 }
 
-/* If we are referencing a function that is static, make the SYMBOL_REF
-   special so that we can generate direct calls to it even with -fpic.  */
 
-static void
-xtensa_encode_section_info (decl, first)
-     tree decl;
-     int first ATTRIBUTE_UNUSED;
+/* Compute a (partial) cost for rtx X.  Return true if the complete
+   cost has been computed, and false if subexpressions should be
+   scanned.  In either case, *TOTAL contains the cost result.  */
+
+static bool
+xtensa_rtx_costs (rtx x, int code, int outer_code, int *total)
 {
-  if (TREE_CODE (decl) == FUNCTION_DECL && ! TREE_PUBLIC (decl))
-    SYMBOL_REF_FLAG (XEXP (DECL_RTL (decl), 0)) = 1;
+  switch (code)
+    {
+    case CONST_INT:
+      switch (outer_code)
+       {
+       case SET:
+         if (xtensa_simm12b (INTVAL (x)))
+           {
+             *total = 4;
+             return true;
+           }
+         break;
+       case PLUS:
+         if (xtensa_simm8 (INTVAL (x))
+             || xtensa_simm8x256 (INTVAL (x)))
+           {
+             *total = 0;
+             return true;
+           }
+         break;
+       case AND:
+         if (xtensa_mask_immediate (INTVAL (x)))
+           {
+             *total = 0;
+             return true;
+           }
+         break;
+       case COMPARE:
+         if ((INTVAL (x) == 0) || xtensa_b4const (INTVAL (x)))
+           {
+             *total = 0;
+             return true;
+           }
+         break;
+       case ASHIFT:
+       case ASHIFTRT:
+       case LSHIFTRT:
+       case ROTATE:
+       case ROTATERT:
+         /* no way to tell if X is the 2nd operand so be conservative */
+       default: break;
+       }
+      if (xtensa_simm12b (INTVAL (x)))
+       *total = 5;
+      else if (TARGET_CONST16)
+       *total = COSTS_N_INSNS (2);
+      else
+       *total = 6;
+      return true;
+
+    case CONST:
+    case LABEL_REF:
+    case SYMBOL_REF:
+      if (TARGET_CONST16)
+       *total = COSTS_N_INSNS (2);
+      else
+       *total = 5;
+      return true;
+
+    case CONST_DOUBLE:
+      if (TARGET_CONST16)
+       *total = COSTS_N_INSNS (4);
+      else
+       *total = 7;
+      return true;
+
+    case MEM:
+      {
+       int num_words =
+         (GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD) ?  2 : 1;
+
+       if (memory_address_p (GET_MODE (x), XEXP ((x), 0)))
+         *total = COSTS_N_INSNS (num_words);
+       else
+         *total = COSTS_N_INSNS (2*num_words);
+       return true;
+      }
+
+    case FFS:
+      *total = COSTS_N_INSNS (TARGET_NSA ? 5 : 50);
+      return true;
+
+    case NOT:
+      *total = COSTS_N_INSNS ((GET_MODE (x) == DImode) ? 3 : 2);
+      return true;
+
+    case AND:
+    case IOR:
+    case XOR:
+      if (GET_MODE (x) == DImode)
+       *total = COSTS_N_INSNS (2);
+      else
+       *total = COSTS_N_INSNS (1);
+      return true;
+
+    case ASHIFT:
+    case ASHIFTRT:
+    case LSHIFTRT:
+      if (GET_MODE (x) == DImode)
+       *total = COSTS_N_INSNS (50);
+      else
+       *total = COSTS_N_INSNS (1);
+      return true;
+
+    case ABS:
+      {
+       enum machine_mode xmode = GET_MODE (x);
+       if (xmode == SFmode)
+         *total = COSTS_N_INSNS (TARGET_HARD_FLOAT ? 1 : 50);
+       else if (xmode == DFmode)
+         *total = COSTS_N_INSNS (50);
+       else
+         *total = COSTS_N_INSNS (4);
+       return true;
+      }
+
+    case PLUS:
+    case MINUS:
+      {
+       enum machine_mode xmode = GET_MODE (x);
+       if (xmode == SFmode)
+         *total = COSTS_N_INSNS (TARGET_HARD_FLOAT ? 1 : 50);
+       else if (xmode == DFmode || xmode == DImode)
+         *total = COSTS_N_INSNS (50);
+       else
+         *total = COSTS_N_INSNS (1);
+       return true;
+      }
+
+    case NEG:
+      *total = COSTS_N_INSNS ((GET_MODE (x) == DImode) ? 4 : 2);
+      return true;
+
+    case MULT:
+      {
+       enum machine_mode xmode = GET_MODE (x);
+       if (xmode == SFmode)
+         *total = COSTS_N_INSNS (TARGET_HARD_FLOAT ? 4 : 50);
+       else if (xmode == DFmode || xmode == DImode)
+         *total = COSTS_N_INSNS (50);
+       else if (TARGET_MUL32)
+         *total = COSTS_N_INSNS (4);
+       else if (TARGET_MAC16)
+         *total = COSTS_N_INSNS (16);
+       else if (TARGET_MUL16)
+         *total = COSTS_N_INSNS (12);
+       else
+         *total = COSTS_N_INSNS (50);
+       return true;
+      }
+
+    case DIV:
+    case MOD:
+      {
+       enum machine_mode xmode = GET_MODE (x);
+       if (xmode == SFmode)
+         {
+           *total = COSTS_N_INSNS (TARGET_HARD_FLOAT_DIV ? 8 : 50);
+           return true;
+         }
+       else if (xmode == DFmode)
+         {
+           *total = COSTS_N_INSNS (50);
+           return true;
+         }
+      }
+      /* fall through */
+
+    case UDIV:
+    case UMOD:
+      {
+       enum machine_mode xmode = GET_MODE (x);
+       if (xmode == DImode)
+         *total = COSTS_N_INSNS (50);
+       else if (TARGET_DIV32)
+         *total = COSTS_N_INSNS (32);
+       else
+         *total = COSTS_N_INSNS (50);
+       return true;
+      }
+
+    case SQRT:
+      if (GET_MODE (x) == SFmode)
+       *total = COSTS_N_INSNS (TARGET_HARD_FLOAT_SQRT ? 8 : 50);
+      else
+       *total = COSTS_N_INSNS (50);
+      return true;
+
+    case SMIN:
+    case UMIN:
+    case SMAX:
+    case UMAX:
+      *total = COSTS_N_INSNS (TARGET_MINMAX ? 1 : 50);
+      return true;
+
+    case SIGN_EXTRACT:
+    case SIGN_EXTEND:
+      *total = COSTS_N_INSNS (TARGET_SEXT ? 1 : 2);
+      return true;
+
+    case ZERO_EXTRACT:
+    case ZERO_EXTEND:
+      *total = COSTS_N_INSNS (1);
+      return true;
+
+    default:
+      return false;
+    }
 }
 
 #include "gt-xtensa.h"