OSDN Git Service

* config/xtensa/xtensa.c (xtensa_return_in_msb): New function.
[pf3gnuchains/gcc-fork.git] / gcc / config / xtensa / xtensa.c
index 3c382d9..cb03b53 100644 (file)
@@ -1,5 +1,5 @@
 /* Subroutines for insn-output.c for Tensilica's Xtensa architecture.
-   Copyright 2001,2002,2003 Free Software Foundation, Inc.
+   Copyright 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
    Contributed by Bob Wilson (bwilson@tensilica.com) at Tensilica.
 
 This file is part of GCC.
@@ -53,19 +53,20 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
    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
-  };
+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,7 +91,9 @@ const char *xtensa_st_opcodes[(int) MAX_MACHINE_MODE];
 struct machine_function GTY(())
 {
   int accesses_prev_frame;
-  bool incoming_a7_copied;
+  bool need_a7_copy;
+  bool vararg_a7;
+  rtx set_frame_ptr_insn;
 };
 
 /* Vector, indexed by hard register number, which contains 1 for a
@@ -189,21 +192,25 @@ 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_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));
-static unsigned int xtensa_multibss_section_type_flags
-  PARAMS ((tree, const char *, int));
-static void xtensa_select_rtx_section
-  PARAMS ((enum machine_mode, rtx, unsigned HOST_WIDE_INT));
-static bool xtensa_rtx_costs PARAMS ((rtx, int, int, int *));
+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 bool xtensa_return_in_msb (tree);
+static void printx (FILE *, signed int);
+static void xtensa_function_epilogue (FILE *, HOST_WIDE_INT);
+static rtx xtensa_builtin_saveregs (void);
+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 tree xtensa_build_builtin_va_list (void);
+static bool xtensa_return_in_memory (tree, tree);
 
 static int current_function_arg_words;
 static const int reg_nonleaf_alloc_order[FIRST_PSEUDO_REGISTER] =
@@ -232,6 +239,25 @@ static const int reg_nonleaf_alloc_order[FIRST_PSEUDO_REGISTER] =
 #undef TARGET_ADDRESS_COST
 #define TARGET_ADDRESS_COST hook_int_rtx_0
 
+#undef TARGET_BUILD_BUILTIN_VA_LIST
+#define TARGET_BUILD_BUILTIN_VA_LIST xtensa_build_builtin_va_list
+
+#undef TARGET_PROMOTE_FUNCTION_ARGS
+#define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_tree_true
+#undef TARGET_PROMOTE_FUNCTION_RETURN
+#define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_tree_true
+#undef TARGET_PROMOTE_PROTOTYPES
+#define TARGET_PROMOTE_PROTOTYPES hook_bool_tree_true
+
+#undef TARGET_RETURN_IN_MEMORY
+#define TARGET_RETURN_IN_MEMORY xtensa_return_in_memory
+
+#undef TARGET_EXPAND_BUILTIN_SAVEREGS
+#define TARGET_EXPAND_BUILTIN_SAVEREGS xtensa_builtin_saveregs
+
+#undef TARGET_RETURN_IN_MSB
+#define TARGET_RETURN_IN_MSB xtensa_return_in_msb
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
 
@@ -240,8 +266,7 @@ struct gcc_target targetm = TARGET_INITIALIZER;
  */
 
 int
-xtensa_b4constu (v)
-     int v;
+xtensa_b4constu (int v)
 {
   switch (v)
     {
@@ -267,29 +292,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)
     {
@@ -315,50 +336,43 @@ 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);
 }
@@ -368,8 +382,7 @@ xtensa_uimm8x4 (v)
    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)
     {
@@ -392,9 +405,7 @@ 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)));
@@ -404,9 +415,7 @@ add_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));
@@ -416,9 +425,7 @@ arith_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.  */
@@ -431,9 +438,7 @@ nonimmed_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.  */
@@ -446,9 +451,7 @@ mem_operand (op, mode)
 
 
 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.  */
@@ -477,9 +480,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));
@@ -489,9 +490,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));
@@ -499,9 +498,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);
@@ -510,18 +507,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)
     {
@@ -534,8 +527,7 @@ lsbitnum_operand (op, mode)
 
 
 static int
-b4const_or_zero (v)
-     int v;
+b4const_or_zero (int v)
 {
   if (v == 0)
     return TRUE;
@@ -544,9 +536,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));
@@ -556,9 +546,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));
@@ -568,9 +556,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)
@@ -581,8 +567,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_LOCAL_P (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;
@@ -590,9 +605,7 @@ 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)
       || memory_operand (op, mode))
@@ -608,7 +621,7 @@ move_operand (op, mode)
     case SImode:
       if (TARGET_CONST16)
        return CONSTANT_P (op);
-      /* fall through */
+      /* Fall through.  */
 
     case HImode:
     case QImode:
@@ -630,8 +643,7 @@ move_operand (op, mode)
 
 
 int
-smalloffset_mem_p (op)
-     rtx op;
+smalloffset_mem_p (rtx op)
 {
   if (GET_CODE (op) == MEM)
     {
@@ -653,8 +665,7 @@ smalloffset_mem_p (op)
 
 
 int
-constantpool_address_p (addr)
-     rtx addr;
+constantpool_address_p (rtx addr)
 {
   rtx sym = addr;
 
@@ -662,12 +673,12 @@ constantpool_address_p (addr)
     {
       rtx offset;
 
-      /* only handle (PLUS (SYM, OFFSET)) form */
+      /* Only handle (PLUS (SYM, OFFSET)) form.  */
       addr = XEXP (addr, 0);
       if (GET_CODE (addr) != PLUS)
        return FALSE;
 
-      /* make sure the address is word aligned */
+      /* Make sure the address is word aligned.  */
       offset = XEXP (addr, 1);
       if ((GET_CODE (offset) != CONST_INT)
          || ((INTVAL (offset) & 3) != 0))
@@ -684,8 +695,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));
@@ -696,9 +706,7 @@ constantpool_mem_p (op)
 /* 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;
@@ -727,9 +735,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);
@@ -738,14 +744,12 @@ 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)));
 
-  /* generate paradoxical subregs as needed so that the modes match */
+  /* Generate paradoxical subregs as needed so that the modes match.  */
   src = simplify_gen_subreg (SImode, src, GET_MODE (src), 0);
   dst = simplify_gen_subreg (SImode, dst, GET_MODE (dst), 0);
 
@@ -755,9 +759,7 @@ xtensa_extend_reg (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;
@@ -777,9 +779,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;
@@ -797,9 +797,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;
@@ -817,8 +815,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;
@@ -837,9 +834,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)
     {
@@ -869,11 +864,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;
 
@@ -900,15 +894,15 @@ map_test_to_internal_test (test_code)
    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 */
@@ -991,7 +985,7 @@ gen_int_relational (test_code, cmp0, cmp1, p_invert)
       cmp1 = temp;
     }
 
-  return gen_rtx (p_info->test_code, VOIDmode, cmp0, cmp1);
+  return gen_rtx_fmt_ee (p_info->test_code, VOIDmode, cmp0, cmp1);
 }
 
 
@@ -999,12 +993,11 @@ gen_int_relational (test_code, cmp0, cmp1, p_invert)
    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;
 
@@ -1017,7 +1010,7 @@ gen_float_relational (test_code, cmp0, cmp1)
     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:
-      fatal_insn ("bad test", gen_rtx (test_code, VOIDmode, cmp0, cmp1));
+      fatal_insn ("bad test", gen_rtx_fmt_ee (test_code, VOIDmode, cmp0, cmp1));
       reverse_regs = 0; invert = 0; gen_fn = 0; /* avoid compiler warnings */
     }
 
@@ -1031,14 +1024,12 @@ gen_float_relational (test_code, cmp0, cmp1)
   brtmp = gen_rtx_REG (CCmode, FPCC_REGNUM);
   emit_insn (gen_fn (brtmp, cmp0, cmp1));
 
-  return gen_rtx (invert ? EQ : NE, VOIDmode, brtmp, const0_rtx);
+  return gen_rtx_fmt_ee (invert ? EQ : NE, VOIDmode, brtmp, const0_rtx);
 }
 
 
 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];
@@ -1051,7 +1042,7 @@ xtensa_expand_conditional_branch (operands, test_code)
     {
     case CMP_DF:
     default:
-      fatal_insn ("bad test", gen_rtx (test_code, VOIDmode, cmp0, cmp1));
+      fatal_insn ("bad test", gen_rtx_fmt_ee (test_code, VOIDmode, cmp0, cmp1));
 
     case CMP_SI:
       invert = FALSE;
@@ -1060,7 +1051,7 @@ xtensa_expand_conditional_branch (operands, test_code)
 
     case CMP_SF:
       if (!TARGET_HARD_FLOAT)
-       fatal_insn ("bad test", gen_rtx (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;
@@ -1085,8 +1076,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];
@@ -1107,18 +1097,18 @@ gen_conditional_move (cmp)
          code = GE;
          op1 = const0_rtx;
        }
-      cmp = gen_rtx (code, VOIDmode, cc0_rtx, const0_rtx);
+      cmp = gen_rtx_fmt_ee (code, VOIDmode, cc0_rtx, const0_rtx);
 
       if (boolean_operator (cmp, VOIDmode))
        {
-         /* swap the operands to make const0 second */
+         /* Swap the operands to make const0 second.  */
          if (op0 == const0_rtx)
            {
              op0 = op1;
              op1 = const0_rtx;
            }
 
-         /* if not comparing against zero, emit a comparison (subtract) */
+         /* If not comparing against zero, emit a comparison (subtract).  */
          if (op1 != const0_rtx)
            {
              op0 = expand_binop (SImode, sub_optab, op0, op1,
@@ -1128,7 +1118,7 @@ gen_conditional_move (cmp)
        }
       else if (branch_operator (cmp, VOIDmode))
        {
-         /* swap the operands to make const0 second */
+         /* Swap the operands to make const0 second.  */
          if (op0 == const0_rtx)
            {
              op0 = op1;
@@ -1148,7 +1138,7 @@ gen_conditional_move (cmp)
       else
        return 0;
 
-      return gen_rtx (code, VOIDmode, op0, op1);
+      return gen_rtx_fmt_ee (code, VOIDmode, op0, op1);
     }
 
   if (TARGET_HARD_FLOAT && (branch_type == CMP_SF))
@@ -1159,12 +1149,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;
@@ -1185,13 +1173,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;
@@ -1213,9 +1200,7 @@ xtensa_expand_scc (operands)
    for the output, i.e., the input operands are twice as big as MODE.  */
 
 void
-xtensa_split_operand_pair (operands, mode)
-     rtx operands[4];
-     enum machine_mode mode;
+xtensa_split_operand_pair (rtx operands[4], enum machine_mode mode)
 {
   switch (GET_CODE (operands[1]))
     {
@@ -1262,9 +1247,7 @@ xtensa_split_operand_pair (operands, mode)
    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
@@ -1294,14 +1277,11 @@ xtensa_emit_move_sequence (operands, mode)
        }
     }
 
-  if (!(reload_in_progress | reload_completed))
-    {
-      if (!xtensa_valid_move (mode, operands))
-       operands[1] = force_reg (mode, operands[1]);
+  if (!(reload_in_progress | reload_completed)
+      && !xtensa_valid_move (mode, operands))
+    operands[1] = force_reg (mode, operands[1]);
 
-      if (xtensa_copy_incoming_a7 (operands, mode))
-       return 1;
-    }
+  operands[1] = xtensa_copy_incoming_a7 (operands[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
@@ -1316,8 +1296,7 @@ xtensa_emit_move_sequence (operands, mode)
 
 
 static rtx
-fixup_subreg_mem (x)
-     rtx x;
+fixup_subreg_mem (rtx x)
 {
   if (GET_CODE (x) == SUBREG
       && GET_CODE (SUBREG_REG (x)) == REG
@@ -1333,71 +1312,114 @@ 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.  */
+/* Check if an incoming argument in a7 is expected to be used soon and
+   if OPND is a register or register pair that includes a7.  If so,
+   create a new pseudo and copy a7 into that pseudo at the very
+   beginning of the function, followed by the special "set_frame_ptr"
+   unspec_volatile insn.  The return value is either the original
+   operand, if it is not a7, or the new pseudo containing a copy of
+   the incoming argument.  This is necessary because the register
+   allocator will ignore conflicts with a7 and may either assign some
+   other pseudo to a7 or use a7 as the hard_frame_pointer, clobbering
+   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.  Putting the set_frame_ptr insn at the beginning, with
+   only the a7 copy before it, also makes it easier for the prologue
+   expander to initialize the frame pointer after the a7 copy and to
+   fix up the a7 copy to use the stack pointer instead of the frame
+   pointer.  */
 
-bool
-xtensa_copy_incoming_a7 (operands, mode)
-     rtx *operands;
-     enum machine_mode mode;
+rtx
+xtensa_copy_incoming_a7 (rtx opnd)
 {
-  if (a7_overlap_mentioned_p (operands[1])
-      && !cfun->machine->incoming_a7_copied)
+  rtx entry_insns = 0;
+  rtx reg, tmp;
+  enum machine_mode mode;
+
+  if (!cfun->machine->need_a7_copy)
+    return opnd;
+
+  /* This function should never be called again once a7 has been copied.  */
+  if (cfun->machine->set_frame_ptr_insn)
+    abort ();
+
+  mode = GET_MODE (opnd);
+
+  /* The operand using a7 may come in a later instruction, so just return
+     the original operand if it doesn't use a7.  */
+  reg = opnd;
+  if (GET_CODE (reg) == SUBREG)
     {
-      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 ();
-       }
+      if (SUBREG_BYTE (reg) != 0)
+       abort ();
+      reg = SUBREG_REG (reg);
+    }
+  if (GET_CODE (reg) != REG
+      || REGNO (reg) > A7_REG
+      || REGNO (reg) + HARD_REGNO_NREGS (A7_REG, mode) <= A7_REG)
+    return opnd;
 
-      /* 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 ();
+  /* 1-word args will always be in a7; 2-word args in a6/a7.  */
+  if (REGNO (reg) + HARD_REGNO_NREGS (A7_REG, mode) - 1 != A7_REG)
+    abort ();
 
-      /* 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->need_a7_copy = false;
 
-      cfun->machine->incoming_a7_copied = true;
+  /* Copy a7 to a new pseudo at the function entry.  Use gen_raw_REG to
+     create the REG for a7 so that hard_frame_pointer_rtx is not used.  */
 
-      return 1;
+  push_to_sequence (entry_insns);
+  tmp = gen_reg_rtx (mode);
+
+  switch (mode)
+    {
+    case DFmode:
+    case DImode:
+      emit_insn (gen_movsi_internal (gen_rtx_SUBREG (SImode, tmp, 0),
+                                    gen_rtx_REG (SImode, A7_REG - 1)));
+      emit_insn (gen_movsi_internal (gen_rtx_SUBREG (SImode, tmp, 4),
+                                    gen_raw_REG (SImode, A7_REG)));
+      break;
+    case SFmode:
+      emit_insn (gen_movsf_internal (tmp, gen_raw_REG (mode, A7_REG)));
+      break;
+    case SImode:
+      emit_insn (gen_movsi_internal (tmp, gen_raw_REG (mode, A7_REG)));
+      break;
+    case HImode:
+      emit_insn (gen_movhi_internal (tmp, gen_raw_REG (mode, A7_REG)));
+      break;
+    case QImode:
+      emit_insn (gen_movqi_internal (tmp, gen_raw_REG (mode, A7_REG)));
+      break;
+    default:
+      abort ();
     }
 
-  return 0;
+  cfun->machine->set_frame_ptr_insn = emit_insn (gen_set_frame_ptr ());
+  entry_insns = get_insns ();
+  end_sequence ();
+
+  if (cfun->machine->vararg_a7)
+    {
+      /* This is called from within builtin_savereg, so we're already
+        inside a start_sequence that will be placed at the start of
+        the function.  */
+      emit_insn (entry_insns);
+    }
+  else
+    {
+      /* Put entry_insns after the NOTE that starts the function.  If
+        this is inside a start_sequence, make the outer-level insn
+        chain current, so the code is placed at the start of the
+        function.  */
+      push_topmost_sequence ();
+      emit_insn_after (entry_insns, get_insns ());
+      pop_topmost_sequence ();
+    }
+
+  return tmp;
 }
 
 
@@ -1412,8 +1434,7 @@ xtensa_copy_incoming_a7 (operands, mode)
    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];
@@ -1421,26 +1442,26 @@ xtensa_expand_block_move (operands)
   int align = XINT (operands[3], 0);
   int num_pieces, move_ratio;
 
-  /* If this is not a fixed size move, just call memcpy */
+  /* If this is not a fixed size move, just call memcpy */
   if (!optimize || (GET_CODE (operands[2]) != CONST_INT))
     return 0;
 
-  /* Anything to move? */
+  /* Anything to move?  */
   if (bytes <= 0)
     return 1;
 
   if (align > MOVE_MAX)
     align = MOVE_MAX;
 
-  /* decide whether to expand inline based on the optimization level */
+  /* Decide whether to expand inline based on the optimization level.  */
   move_ratio = 4;
   if (optimize > 2)
     move_ratio = LARGEST_MOVE_RATIO;
-  num_pieces = (bytes / align) + (bytes % align); /* close enough anyway */
+  num_pieces = (bytes / align) + (bytes % align); /* Close enough anyway.  */
   if (num_pieces >= move_ratio)
     return 0;
 
-  /* make sure the memory addresses are valid */
+  /* Make sure the memory addresses are valid.  */
   operands[0] = validize_mem (dest);
   operands[1] = validize_mem (src);
 
@@ -1450,21 +1471,19 @@ xtensa_expand_block_move (operands)
 }
 
 
-/*  Emit a sequence of instructions to implement a block move, trying
-    to hide load delay slots as much as possible.  Load N values into
-    temporary registers, store those N values, and repeat until the
-    complete block has been moved.  N=delay_slots+1 */
+/* Emit a sequence of instructions to implement a block move, trying
+   to hide load delay slots as much as possible.  Load N values into
+   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];
@@ -1511,7 +1530,7 @@ xtensa_emit_block_move (operands, tmpregs, delay_slots)
 
          if (bytes < item_size)
            {
-             /* find a smaller item_size which we can load & store */
+             /* Find a smaller item_size which we can load & store.  */
              item_size = bytes;
              mode = xtensa_find_mode_for_size (item_size);
              item_size = GET_MODE_SIZE (mode);
@@ -1519,7 +1538,7 @@ xtensa_emit_block_move (operands, tmpregs, delay_slots)
              stname = xtensa_st_opcodes[(int) mode];
            }
 
-         /* record the load instruction opcode and operands */
+         /* Record the load instruction opcode and operands.  */
          addr = plus_constant (from_addr, offset);
          mem = gen_rtx_MEM (mode, addr);
          if (! memory_address_p (mode, addr))
@@ -1529,7 +1548,7 @@ xtensa_emit_block_move (operands, tmpregs, delay_slots)
          ldinsns[n].operands[1] = mem;
          sprintf (ldinsns[n].template, "%s\t%%0, %%1", ldname);
 
-         /* record the store instruction opcode and operands */
+         /* Record the store instruction opcode and operands.  */
          addr = plus_constant (to_addr, offset);
          mem = gen_rtx_MEM (mode, addr);
          if (! memory_address_p (mode, addr))
@@ -1543,7 +1562,7 @@ xtensa_emit_block_move (operands, tmpregs, delay_slots)
          bytes -= item_size;
        }
 
-      /* now output the loads followed by the stores */
+      /* Now output the loads followed by the stores.  */
       for (n = 0; n < chunk_size; n++)
        output_asm_insn (ldinsns[n].template, ldinsns[n].operands);
       for (n = 0; n < chunk_size; n++)
@@ -1553,8 +1572,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;
 
@@ -1562,7 +1580,7 @@ xtensa_find_mode_for_size (item_size)
     {
       mode = VOIDmode;
 
-      /* find mode closest to but not bigger than item_size */
+      /* Find mode closest to but not bigger than item_size.  */
       for (tmode = GET_CLASS_NARROWEST_MODE (MODE_INT);
           tmode != VOIDmode; tmode = GET_MODE_WIDER_MODE (tmode))
        if (GET_MODE_SIZE (tmode) <= item_size)
@@ -1576,7 +1594,7 @@ xtensa_find_mode_for_size (item_size)
          && xtensa_st_opcodes[(int) mode])
        break;
 
-      /* cannot load & store this mode; try something smaller */
+      /* Cannot load & store this mode; try something smaller.  */
       item_size -= 1;
     }
 
@@ -1585,14 +1603,13 @@ 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];
 
-  /* generate a call to "__xtensa_nonlocal_goto" (in libgcc); the code
-     is too big to generate in-line */
+  /* Generate a call to "__xtensa_nonlocal_goto" (in libgcc); the code
+     is too big to generate in-line */
 
   if (GET_CODE (containing_fp) != REG)
     containing_fp = force_reg (Pmode, containing_fp);
@@ -1609,14 +1626,14 @@ 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.  */
   cfun->machine->accesses_prev_frame = 1;
@@ -1631,19 +1648,17 @@ xtensa_setup_frame_addresses ()
    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
-   targetting that label will target the nop (and thus remain in the loop),
-   instead of targetting the instruction after the loop (and thus exiting
+   targeting that label will target the nop (and thus remain in the loop),
+   instead of targeting 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
+   branch is targeting 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.  */
 
 void
-xtensa_emit_loop_end (insn, operands)
-     rtx insn;
-     rtx *operands;
+xtensa_emit_loop_end (rtx insn, rtx *operands)
 {
   char done = 0;
 
@@ -1682,9 +1697,7 @@ 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];
@@ -1700,11 +1713,10 @@ 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;
 
@@ -1721,17 +1733,12 @@ xtensa_dbx_register_number (regno)
   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;
+      first = 48;
     }
   else if (ACC_REG_P (regno))
     {
-      first = 0;
-      regno = -1;
+      first = 0x200;   /* Start of Xtensa special registers.  */
+      regno = 16;      /* ACCLO is special register 16.  */
     }
 
   /* When optimizing, we sometimes get asked about pseudo-registers
@@ -1748,21 +1755,17 @@ 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, int incoming)
 {
   cum->arg_words = 0;
+  cum->incoming = incoming;
 }
 
+
 /* 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;
@@ -1782,19 +1785,16 @@ 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;
   int regno;
-  enum machine_mode result_mode;
 
   arg_words = &cum->arg_words;
   regbase = (incoming_p ? GP_ARG_FIRST : GP_OUTGOING_ARG_FIRST);
@@ -1811,38 +1811,25 @@ function_arg (cum, mode, type, incoming_p)
     return (rtx)0;
 
   regno = regbase + *arg_words;
-  result_mode = (mode == BLKmode ? TYPE_MODE (type) : mode);
 
-  /* We need to make sure that references to a7 are represented with
-     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.  */
+  if (cum->incoming && regno <= A7_REG && regno + words > A7_REG)
+    cfun->machine->need_a7_copy = true;
 
-  if ((mode == BLKmode || words > 2)
-      && regno < A7_REG
-      && regno + words > A7_REG)
-    {
-      rtx result;
-      int n;
+  return gen_rtx_REG (mode, regno);
+}
 
-      result = gen_rtx_PARALLEL (result_mode, rtvec_alloc (words));
-      for (n = 0; n < words; n++)
-       {
-         XVECEXP (result, 0, n) =
-           gen_rtx_EXPR_LIST (VOIDmode,
-                              gen_raw_REG (SImode, regno + n),
-                              GEN_INT (n * UNITS_PER_WORD));
-       }
-      return result;
-    }
 
-  return gen_raw_REG (result_mode, regno);
+static bool
+xtensa_return_in_msb (tree valtype)
+{
+  return (TARGET_BIG_ENDIAN
+         && AGGREGATE_TYPE_P (valtype)
+         && int_size_in_bytes (valtype) >= UNITS_PER_WORD);
 }
 
 
 void
-override_options ()
+override_options (void)
 {
   int regno;
   enum machine_mode mode;
@@ -1850,7 +1837,7 @@ override_options ()
   if (!TARGET_BOOLEANS && TARGET_HARD_FLOAT)
     error ("boolean registers required for the floating-point option");
 
-  /* set up the tables of ld/st opcode names for block moves */
+  /* Set up the tables of ld/st opcode names for block moves.  */
   xtensa_ld_opcodes[(int) SImode] = "l32i";
   xtensa_ld_opcodes[(int) HImode] = "l16ui";
   xtensa_ld_opcodes[(int) QImode] = "l8ui";
@@ -1953,11 +1940,9 @@ override_options ()
 */
 
 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)
@@ -1968,10 +1953,7 @@ printx (file, val)
 
 
 void
-print_operand (file, x, letter)
-     FILE *file;               /* file to write to */
-     rtx x;                    /* operand to print */
-     int letter;               /* %<letter> or 0 */
+print_operand (FILE *file, rtx x, int letter)
 {
   if (!x)
     error ("PRINT_OPERAND null pointer");
@@ -2117,9 +2099,7 @@ print_operand (file, x, 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");
@@ -2175,11 +2155,7 @@ print_operand_address (file, addr)
 
 
 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;
@@ -2245,10 +2221,9 @@ xtensa_output_literal (file, x, mode, labelno)
 #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);
 
@@ -2261,7 +2236,7 @@ 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.
@@ -2276,7 +2251,7 @@ xtensa_frame_pointer_required ()
 
 
 void
-xtensa_expand_prologue ()
+xtensa_expand_prologue (void)
 {
   HOST_WIDE_INT total_size;
   rtx size_rtx;
@@ -2298,41 +2273,18 @@ xtensa_expand_prologue ()
 
   if (frame_pointer_needed)
     {
-      rtx first, insn, set_frame_ptr_insn = 0;
-
-      push_topmost_sequence ();
-      first = get_insns ();
-      pop_topmost_sequence ();
-
-      /* 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.  */
-
-      for (insn = first; insn; insn = NEXT_INSN (insn))
+      if (cfun->machine->set_frame_ptr_insn)
        {
-         rtx pat;
+         rtx first, insn;
 
-         if (!INSN_P (insn))
-           continue;
+         push_topmost_sequence ();
+         first = get_insns ();
+         pop_topmost_sequence ();
 
-         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;
-           }
-       }
-
-      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 != cfun->machine->set_frame_ptr_insn;
               insn = NEXT_INSN (insn))
            {
              if (INSN_P (insn))
@@ -2350,18 +2302,15 @@ xtensa_expand_prologue ()
 /* Clear variables at function end.  */
 
 void
-xtensa_function_epilogue (file, size)
-     FILE *file ATTRIBUTE_UNUSED;
-     HOST_WIDE_INT size ATTRIBUTE_UNUSED;
+xtensa_function_epilogue (FILE *file ATTRIBUTE_UNUSED,
+                         HOST_WIDE_INT size ATTRIBUTE_UNUSED)
 {
   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;
 
@@ -2398,8 +2347,8 @@ xtensa_return_addr (count, frame)
    references argument word N for 0 <= N < 6, and __va_stk[N*4] references
    argument word N for N >= 6.  */
 
-tree
-xtensa_build_va_list ()
+static tree
+xtensa_build_builtin_va_list (void)
 {
   tree f_stk, f_reg, f_ndx, record, type_decl;
 
@@ -2431,18 +2380,17 @@ xtensa_build_va_list ()
 /* Save the incoming argument registers on the stack.  Returns the
    address of the saved registers.  */
 
-rtx
-xtensa_builtin_saveregs ()
+static rtx
+xtensa_builtin_saveregs (void)
 {
   rtx gp_regs, dest;
   int arg_words = current_function_arg_words;
   int gp_left = MAX_ARGS_IN_REGISTERS - arg_words;
-  int i;
 
-  if (gp_left == 0)
+  if (gp_left <= 0)
     return const0_rtx;
 
-  /* allocate the general-purpose register space */
+  /* Allocate the general-purpose register space.  */
   gp_regs = assign_stack_local
     (BLKmode, MAX_ARGS_IN_REGISTERS * UNITS_PER_WORD, -1);
   set_mem_alias_set (gp_regs, get_varargs_alias_set ());
@@ -2451,16 +2399,9 @@ xtensa_builtin_saveregs ()
   dest = change_address (gp_regs, SImode,
                         plus_constant (XEXP (gp_regs, 0),
                                        arg_words * UNITS_PER_WORD));
-
-  /* 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).  */
-  for (i = 0; i < gp_left; i++)
-    {
-      emit_move_insn (operand_subword (dest, i, 1, BLKmode),
-                     gen_raw_REG (SImode, GP_ARG_FIRST + arg_words + i));
-    }
+  cfun->machine->need_a7_copy = true;
+  cfun->machine->vararg_a7 = true;
+  move_block_from_reg (GP_ARG_FIRST + arg_words, dest, gp_left);
 
   return XEXP (gp_regs, 0);
 }
@@ -2470,9 +2411,7 @@ xtensa_builtin_saveregs ()
    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;
@@ -2516,8 +2455,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;
@@ -2526,6 +2464,25 @@ xtensa_va_arg (valist, type)
   rtx array, orig_ndx, r, addr, size, va_size;
   rtx lab_false, lab_over, lab_false2;
 
+  /* Handle complex values as separate real and imaginary parts.  */
+  if (TREE_CODE (type) == COMPLEX_TYPE)
+    {
+      rtx real_part, imag_part, concat_val, local_copy;
+
+      real_part = xtensa_va_arg (valist, TREE_TYPE (type));
+      imag_part = xtensa_va_arg (valist, TREE_TYPE (type));
+
+      /* Make a copy of the value in case the parts are not contiguous.  */
+      real_part = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (type)), real_part);
+      imag_part = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (type)), imag_part);
+      concat_val = gen_rtx_CONCAT (TYPE_MODE (type), real_part, imag_part);
+
+      local_copy = assign_temp (type, 0, 1, 0);
+      emit_move_insn (local_copy, concat_val);
+
+      return XEXP (local_copy, 0);
+    }
+
   f_stk = TYPE_FIELDS (va_list_type_node);
   f_reg = TREE_CHAIN (f_stk);
   f_ndx = TREE_CHAIN (f_reg);
@@ -2552,8 +2509,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)
     {
@@ -2570,8 +2526,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);
@@ -2589,8 +2544,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);
 
@@ -2623,8 +2577,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,
@@ -2655,8 +2608,7 @@ 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);
@@ -2689,10 +2641,7 @@ xtensa_va_arg (valist, type)
 
 
 enum reg_class
-xtensa_preferred_reload_class (x, class, isoutput)
-     rtx x;
-     enum reg_class class;
-     int isoutput;
+xtensa_preferred_reload_class (rtx x, enum reg_class class, int isoutput)
 {
   if (!isoutput && CONSTANT_P (x) && GET_CODE (x) == CONST_DOUBLE)
     return NO_REGS;
@@ -2711,11 +2660,9 @@ xtensa_preferred_reload_class (x, class, isoutput)
 
 
 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;
 
@@ -2739,7 +2686,7 @@ xtensa_secondary_reload_class (class, mode, x, isoutput)
 
 
 void
-order_regs_for_local_alloc ()
+order_regs_for_local_alloc (void)
 {
   if (!leaf_function_p ())
     {
@@ -2751,8 +2698,8 @@ order_regs_for_local_alloc ()
       int i, num_arg_regs;
       int nxt = 0;
 
-      /* use the AR registers in increasing order (skipping a0 and a1)
-        but save the incoming argument registers for a last resort */
+      /* Use the AR registers in increasing order (skipping a0 and a1)
+        but save the incoming argument registers for a last resort */
       num_arg_regs = current_function_args_info.arg_words;
       if (num_arg_regs > MAX_ARGS_IN_REGISTERS)
        num_arg_regs = MAX_ARGS_IN_REGISTERS;
@@ -2761,11 +2708,11 @@ 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 */
+      /* 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 */
+      /* List the FP registers in order for now.  */
       for (i = 0; i < 16; i++)
        reg_alloc_order[nxt++] = FP_REG_FIRST + i;
 
@@ -2780,64 +2727,11 @@ order_regs_for_local_alloc ()
 }
 
 
-/* A customized version of reg_overlap_mentioned_p that only looks for
-   references to a7 (as opposed to hard_frame_pointer_rtx).  */
-
-int
-a7_overlap_mentioned_p (x)
-     rtx x;
-{
-  int i, j;
-  unsigned int x_regno;
-  const char *fmt;
-
-  if (GET_CODE (x) == REG)
-    {
-      x_regno = REGNO (x);
-      return (x != hard_frame_pointer_rtx
-             && x_regno < A7_REG + 1
-             && x_regno + HARD_REGNO_NREGS (A7_REG, GET_MODE (x)) > A7_REG);
-    }
-
-  if (GET_CODE (x) == SUBREG
-      && GET_CODE (SUBREG_REG (x)) == REG
-      && REGNO (SUBREG_REG (x)) < FIRST_PSEUDO_REGISTER)
-    {
-      x_regno = subreg_regno (x);
-      return (SUBREG_REG (x) != hard_frame_pointer_rtx
-             && x_regno < A7_REG + 1
-             && x_regno + HARD_REGNO_NREGS (A7_REG, GET_MODE (x)) > A7_REG);
-    }
-
-  /* X does not match, so try its subexpressions.  */
-  fmt = GET_RTX_FORMAT (GET_CODE (x));
-  for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
-    {
-      if (fmt[i] == 'e')
-       {
-         if (a7_overlap_mentioned_p (XEXP (x, i)))
-           return 1;
-       }
-      else if (fmt[i] == 'E')
-       {
-         for (j = XVECLEN (x, i) - 1; j >=0; j--)
-           if (a7_overlap_mentioned_p (XVECEXP (x, i, j)))
-             return 1;
-       }
-    }
-
-  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 (decl, name, reloc)
-     tree decl;
-     const char *name;
-     int reloc;
+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;
@@ -2860,23 +2754,20 @@ xtensa_multibss_section_type_flags (decl, name, reloc)
 /* 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);
 }
 
+
 /* 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 (x, code, outer_code, total)
-     rtx x;
-     int code, outer_code;
-     int *total;
+xtensa_rtx_costs (rtx x, int code, int outer_code, int *total)
 {
   switch (code)
     {
@@ -2917,7 +2808,7 @@ xtensa_rtx_costs (x, code, outer_code, total)
        case LSHIFTRT:
        case ROTATE:
        case ROTATERT:
-         /* no way to tell if X is the 2nd operand so be conservative */
+         /* No way to tell if X is the 2nd operand so be conservative.  */
        default: break;
        }
       if (xtensa_simm12b (INTVAL (x)))
@@ -3044,7 +2935,7 @@ xtensa_rtx_costs (x, code, outer_code, total)
            return true;
          }
       }
-      /* fall through */
+      /* Fall through.  */
 
     case UDIV:
     case UMOD:
@@ -3088,4 +2979,13 @@ xtensa_rtx_costs (x, code, outer_code, total)
     }
 }
 
+/* Worker function for TARGET_RETURN_IN_MEMORY.  */
+
+static bool
+xtensa_return_in_memory (tree type, tree fntype ATTRIBUTE_UNUSED)
+{
+  return ((unsigned HOST_WIDE_INT) int_size_in_bytes (type)
+         > 4 * UNITS_PER_WORD);
+}
+
 #include "gt-xtensa.h"