OSDN Git Service

2006-03-11 Steven Bosscher <stevenb.gcc@gmail.com>
[pf3gnuchains/gcc-fork.git] / gcc / config / sh / sh.c
index 41f6e72..53b6244 100644 (file)
@@ -1,6 +1,6 @@
 /* Output routines for GCC for Renesas / SuperH SH.
    Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
-   2003, 2004, 2005 Free Software Foundation, Inc.
+   2003, 2004, 2005, 2006 Free Software Foundation, Inc.
    Contributed by Steve Chamberlain (sac@cygnus.com).
    Improved by Jim Wilson (wilson@cygnus.com).
 
@@ -18,8 +18,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GCC; see the file COPYING.  If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
 
 #include "config.h"
 #include "system.h"
@@ -53,6 +53,7 @@ Boston, MA 02111-1307, USA.  */
 #include "ggc.h"
 #include "tree-gimple.h"
 #include "cfgloop.h"
+#include "alloc-pool.h"
 
 
 int code_for_indirect_jump_scratch = CODE_FOR_indirect_jump_scratch;
@@ -70,35 +71,8 @@ int code_for_indirect_jump_scratch = CODE_FOR_indirect_jump_scratch;
 /* Set to 1 by expand_prologue() when the function is an interrupt handler.  */
 int current_function_interrupt;
 
-/* ??? The pragma interrupt support will not work for SH3.  */
-/* This is set by #pragma interrupt and #pragma trapa, and causes gcc to
-   output code for the next function appropriate for an interrupt handler.  */
-int pragma_interrupt;
-
-/* This is set by the trap_exit attribute for functions.   It specifies
-   a trap number to be used in a trapa instruction at function exit
-   (instead of an rte instruction).  */
-int trap_exit;
-
-/* This is used by the sp_switch attribute for functions.  It specifies
-   a variable holding the address of the stack the interrupt function
-   should switch to/from at entry/exit.  */
-rtx sp_switch;
-
-/* This is set by #pragma trapa, and is similar to the above, except that
-   the compiler doesn't emit code to preserve all registers.  */
-static int pragma_trapa;
-
-/* This is set by #pragma nosave_low_regs.  This is useful on the SH3,
-   which has a separate set of low regs for User and Supervisor modes.
-   This should only be used for the lowest level of interrupts.  Higher levels
-   of interrupts must save the registers in case they themselves are
-   interrupted.  */
-int pragma_nosave_low_regs;
-
-/* This is used for communication between TARGET_SETUP_INCOMING_VARARGS and
-   sh_expand_prologue.  */
-int current_function_anonymous_args;
+tree sh_deferred_function_attributes;
+tree *sh_deferred_function_attributes_tail = &sh_deferred_function_attributes;
 
 /* Global variables for machine-dependent things.  */
 
@@ -169,7 +143,7 @@ enum reg_class regno_reg_class[FIRST_PSEUDO_REGISTER] =
   DF_REGS, DF_REGS, DF_REGS, DF_REGS,
   NO_REGS, GENERAL_REGS, PR_REGS, T_REGS,
   MAC_REGS, MAC_REGS, FPUL_REGS, FPSCR_REGS,
-  GENERAL_REGS,
+  GENERAL_REGS, GENERAL_REGS,
 };
 
 char sh_register_names[FIRST_PSEUDO_REGISTER] \
@@ -198,6 +172,7 @@ int assembler_dialect;
 
 static bool shmedia_space_reserved_for_target_registers;
 
+static bool sh_handle_option (size_t, const char *, int);
 static void split_branches (rtx);
 static int branch_dest (rtx);
 static void force_into (rtx, rtx);
@@ -227,6 +202,7 @@ static tree sh_handle_trap_exit_attribute (tree *, tree, tree, int, bool *);
 static tree sh_handle_renesas_attribute (tree *, tree, tree, int, bool *);
 static void sh_output_function_epilogue (FILE *, HOST_WIDE_INT);
 static void sh_insert_attributes (tree, tree *);
+static const char *sh_check_pch_target_flags (int);
 static int sh_adjust_cost (rtx, rtx, rtx, int);
 static int sh_issue_rate (void);
 static int sh_dfa_new_cycle (FILE *, int, rtx, int, int, int *sort_p);
@@ -269,6 +245,8 @@ static int sh_address_cost (rtx);
 #ifdef TARGET_ADJUST_UNROLL_MAX
 static int sh_adjust_unroll_max (struct loop *, int, int, int, int);
 #endif
+static int sh_pr_n_sets (void);
+static rtx sh_allocate_initial_value (rtx);
 static int shmedia_target_regs_stack_space (HARD_REG_SET *);
 static int shmedia_reserve_space_for_target_registers_p (int, HARD_REG_SET *);
 static int shmedia_target_regs_stack_adjust (HARD_REG_SET *);
@@ -325,6 +303,11 @@ static int hard_regs_intersect_p (HARD_REG_SET *, HARD_REG_SET *);
 #undef TARGET_ASM_FILE_START_FILE_DIRECTIVE
 #define TARGET_ASM_FILE_START_FILE_DIRECTIVE true
 
+#undef TARGET_DEFAULT_TARGET_FLAGS
+#define TARGET_DEFAULT_TARGET_FLAGS TARGET_DEFAULT
+#undef TARGET_HANDLE_OPTION
+#define TARGET_HANDLE_OPTION sh_handle_option
+
 #undef TARGET_INSERT_ATTRIBUTES
 #define TARGET_INSERT_ATTRIBUTES sh_insert_attributes
 
@@ -415,6 +398,8 @@ static int hard_regs_intersect_p (HARD_REG_SET *, HARD_REG_SET *);
 #define TARGET_RTX_COSTS sh_rtx_costs
 #undef TARGET_ADDRESS_COST
 #define TARGET_ADDRESS_COST sh_address_cost
+#undef TARGET_ALLOCATE_INITIAL_VALUE
+#define TARGET_ALLOCATE_INITIAL_VALUE sh_allocate_initial_value
 
 #undef TARGET_MACHINE_DEPENDENT_REORG
 #define TARGET_MACHINE_DEPENDENT_REORG sh_reorg
@@ -461,8 +446,8 @@ static int hard_regs_intersect_p (HARD_REG_SET *, HARD_REG_SET *);
 #undef TARGET_VECTOR_MODE_SUPPORTED_P
 #define TARGET_VECTOR_MODE_SUPPORTED_P sh_vector_mode_supported_p
 
-#undef TARGET_PCH_VALID_P
-#define TARGET_PCH_VALID_P sh_pch_valid_p
+#undef TARGET_CHECK_PCH_TARGET_FLAGS
+#define TARGET_CHECK_PCH_TARGET_FLAGS sh_check_pch_target_flags
 
 #undef TARGET_DWARF_CALLING_CONVENTION
 #define TARGET_DWARF_CALLING_CONVENTION sh_dwarf_calling_convention
@@ -489,8 +474,117 @@ static int hard_regs_intersect_p (HARD_REG_SET *, HARD_REG_SET *);
 #define TARGET_ADJUST_UNROLL_MAX sh_adjust_unroll_max
 #endif
 
+#undef TARGET_SECONDARY_RELOAD
+#define TARGET_SECONDARY_RELOAD sh_secondary_reload
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
+/* Implement TARGET_HANDLE_OPTION.  */
+
+static bool
+sh_handle_option (size_t code, const char *arg ATTRIBUTE_UNUSED,
+                 int value ATTRIBUTE_UNUSED)
+{
+  switch (code)
+    {
+    case OPT_m1:
+      target_flags = (target_flags & ~MASK_ARCH) | SELECT_SH1;
+      return true;
+
+    case OPT_m2:
+      target_flags = (target_flags & ~MASK_ARCH) | SELECT_SH2;
+      return true;
+
+    case OPT_m2a:
+      target_flags = (target_flags & ~MASK_ARCH) | SELECT_SH2A;
+      return true;
+
+    case OPT_m2a_nofpu:
+      target_flags = (target_flags & ~MASK_ARCH) | SELECT_SH2A_NOFPU;
+      return true;
+
+    case OPT_m2a_single:
+      target_flags = (target_flags & ~MASK_ARCH) | SELECT_SH2A_SINGLE;
+      return true;
+
+    case OPT_m2a_single_only:
+      target_flags = (target_flags & ~MASK_ARCH) | SELECT_SH2A_SINGLE_ONLY;
+      return true;
+
+    case OPT_m2e:
+      target_flags = (target_flags & ~MASK_ARCH) | SELECT_SH2E;
+      return true;
+
+    case OPT_m3:
+      target_flags = (target_flags & ~MASK_ARCH) | SELECT_SH3;
+      return true;
+
+    case OPT_m3e:
+      target_flags = (target_flags & ~MASK_ARCH) | SELECT_SH3E;
+      return true;
+
+    case OPT_m4:
+      target_flags = (target_flags & ~MASK_ARCH) | SELECT_SH4;
+      return true;
+
+    case OPT_m4_nofpu:
+      target_flags = (target_flags & ~MASK_ARCH) | SELECT_SH4_NOFPU;
+      return true;
+
+    case OPT_m4_single:
+      target_flags = (target_flags & ~MASK_ARCH) | SELECT_SH4_SINGLE;
+      return true;
+
+    case OPT_m4_single_only:
+      target_flags = (target_flags & ~MASK_ARCH) | SELECT_SH4_SINGLE_ONLY;
+      return true;
+
+    case OPT_m4a:
+      target_flags = (target_flags & ~MASK_ARCH) | SELECT_SH4A;
+      return true;
+
+    case OPT_m4a_nofpu:
+    case OPT_m4al:
+      target_flags = (target_flags & ~MASK_ARCH) | SELECT_SH4A_NOFPU;
+      return true;
+
+    case OPT_m4a_single:
+      target_flags = (target_flags & ~MASK_ARCH) | SELECT_SH4A_SINGLE;
+      return true;
+
+    case OPT_m4a_single_only:
+      target_flags = (target_flags & ~MASK_ARCH) | SELECT_SH4A_SINGLE_ONLY;
+      return true;
+
+    case OPT_m5_32media:
+      target_flags = (target_flags & ~MASK_ARCH) | SELECT_SH5_32MEDIA;
+      return true;
+
+    case OPT_m5_32media_nofpu:
+      target_flags = (target_flags & ~MASK_ARCH) | SELECT_SH5_32MEDIA_NOFPU;
+      return true;
+
+    case OPT_m5_64media:
+      target_flags = (target_flags & ~MASK_ARCH) | SELECT_SH5_64MEDIA;
+      return true;
+
+    case OPT_m5_64media_nofpu:
+      target_flags = (target_flags & ~MASK_ARCH) | SELECT_SH5_64MEDIA_NOFPU;
+      return true;
+
+    case OPT_m5_compact:
+      target_flags = (target_flags & ~MASK_ARCH) | SELECT_SH5_COMPACT;
+      return true;
+
+    case OPT_m5_compact_nofpu:
+      target_flags = (target_flags & ~MASK_ARCH) | SELECT_SH5_COMPACT_NOFPU;
+      return true;
+
+    default:
+      return true;
+    }
+}
+\f
 /* Print the operand address in x to the stream.  */
 
 void
@@ -576,6 +670,8 @@ print_operand (FILE *stream, rtx x, int code)
 
   switch (code)
     {
+      tree trapa_attr;
+
     case '.':
       if (final_sequence
          && ! INSN_ANNULLED_BRANCH_P (XVECEXP (final_sequence, 0, 0))
@@ -586,8 +682,11 @@ print_operand (FILE *stream, rtx x, int code)
       fprintf (stream, "%s", LOCAL_LABEL_PREFIX);
       break;
     case '@':
-      if (trap_exit)
-       fprintf (stream, "trapa #%d", trap_exit);
+      trapa_attr = lookup_attribute ("trap_exit",
+                                     DECL_ATTRIBUTES (current_function_decl));
+      if (trapa_attr)
+       fprintf (stream, "trapa #%ld",
+                (long) TREE_INT_CST_LOW (TREE_VALUE (TREE_VALUE (trapa_attr))));
       else if (sh_cfun_interrupt_handler_p ())
        fprintf (stream, "rte");
       else
@@ -617,11 +716,66 @@ print_operand (FILE *stream, rtx x, int code)
       x = mark_constant_pool_use (x);
       output_addr_const (stream, x);
       break;
+    /* N.B.: %R / %S / %T adjust memory addresses by four.
+       For SHMEDIA, that means they can be used to access the first and
+       second 32 bit part of a 64 bit (or larger) value that
+       might be held in floating point registers or memory.
+       While they can be used to access 64 bit parts of a larger value
+       held in general purpose registers, that won't work with memory -
+       neither for fp registers, since the frxx names are used.  */
     case 'R':
-      fputs (reg_names[REGNO (x) + LSW], (stream));
+      if (REG_P (x) || GET_CODE (x) == SUBREG)
+       {
+         regno = true_regnum (x);
+         regno += FP_REGISTER_P (regno) ? 1 : LSW;
+         fputs (reg_names[regno], (stream));
+       }
+      else if (MEM_P (x))
+       {
+         x = adjust_address (x, SImode, 4 * LSW);
+         print_operand_address (stream, XEXP (x, 0));
+       }
+      else
+       {
+         rtx sub = NULL_RTX;
+
+         mode = GET_MODE (x);
+         if (mode == VOIDmode)
+           mode = DImode;
+         if (GET_MODE_SIZE (mode) >= 8)
+           sub = simplify_subreg (SImode, x, mode, 4 * LSW);
+         if (sub)
+           print_operand (stream, sub, 0);
+         else
+           output_operand_lossage ("invalid operand to %%R");
+       }
       break;
     case 'S':
-      fputs (reg_names[REGNO (x) + MSW], (stream));
+      if (REG_P (x) || GET_CODE (x) == SUBREG)
+       {
+         regno = true_regnum (x);
+         regno += FP_REGISTER_P (regno) ? 0 : MSW;
+         fputs (reg_names[regno], (stream));
+       }
+      else if (MEM_P (x))
+       {
+         x = adjust_address (x, SImode, 4 * MSW);
+         print_operand_address (stream, XEXP (x, 0));
+       }
+      else
+       {
+         rtx sub = NULL_RTX;
+
+         mode = GET_MODE (x);
+         if (mode == VOIDmode)
+           mode = DImode;
+         if (GET_MODE_SIZE (mode) >= 8)
+           sub = simplify_subreg (SImode, x, mode, 4 * MSW);
+         if (sub)
+           print_operand (stream, sub, 0);
+         else
+           output_operand_lossage ("invalid operand to %%S");
+       }
       break;
     case 'T':
       /* Next word of a double.  */
@@ -801,35 +955,38 @@ print_operand (FILE *stream, rtx x, int code)
 
        case CONST:
          if (TARGET_SHMEDIA
-             && GET_CODE (XEXP (x, 0)) == SIGN_EXTEND
+             && (GET_CODE (XEXP (x, 0)) == SIGN_EXTEND
+                 || GET_CODE (XEXP (x, 0)) == ZERO_EXTEND)
              && (GET_MODE (XEXP (x, 0)) == DImode
                  || GET_MODE (XEXP (x, 0)) == SImode)
              && GET_CODE (XEXP (XEXP (x, 0), 0)) == TRUNCATE
              && GET_MODE (XEXP (XEXP (x, 0), 0)) == HImode)
            {
              rtx val = XEXP (XEXP (XEXP (x, 0), 0), 0);
+             rtx val2 = val;
+             bool nested_expr = false;
 
              fputc ('(', stream);
              if (GET_CODE (val) == ASHIFTRT)
                {
                  fputc ('(', stream);
-                 if (GET_CODE (XEXP (val, 0)) == CONST)
-                   fputc ('(', stream);
-                 output_addr_const (stream, XEXP (val, 0));
-                 if (GET_CODE (XEXP (val, 0)) == CONST)
-                   fputc (')', stream);
+                 val2 = XEXP (val, 0);
+               }
+             if (GET_CODE (val2) == CONST
+                 || GET_RTX_CLASS (GET_CODE (val2)) != RTX_OBJ)
+               {
+                 fputc ('(', stream);
+                 nested_expr = true;
+               }
+             output_addr_const (stream, val2);
+             if (nested_expr)
+               fputc (')', stream);
+             if (GET_CODE (val) == ASHIFTRT)
+               {
                  fputs (" >> ", stream);
                  output_addr_const (stream, XEXP (val, 1));
                  fputc (')', stream);
                }
-             else
-               {
-                 if (GET_CODE (val) == CONST)
-                   fputc ('(', stream);
-                 output_addr_const (stream, val);
-                 if (GET_CODE (val) == CONST)
-                   fputc (')', stream);
-               }
              fputs (" & 65535)", stream);
              break;
            }
@@ -1066,11 +1223,21 @@ prepare_move_operands (rtx operands[], enum machine_mode mode)
 
   if (mode == Pmode || mode == ptr_mode)
     {
-      rtx op0, op1;
+      rtx op0, op1, opc;
       enum tls_model tls_kind;
 
       op0 = operands[0];
       op1 = operands[1];
+      if (GET_CODE (op1) == CONST
+         && GET_CODE (XEXP (op1, 0)) == PLUS
+         && tls_symbolic_operand (XEXP (XEXP (op1, 0), 0), Pmode))
+       {
+         opc = XEXP (XEXP (op1, 0), 1);
+         op1 = XEXP (XEXP (op1, 0), 0);
+       }
+      else
+       opc = NULL_RTX;
+
       if ((tls_kind = tls_symbolic_operand (op1, Pmode)))
        {
          rtx tga_op1, tga_ret, tmp, tmp2;
@@ -1136,6 +1303,8 @@ prepare_move_operands (rtx operands[], enum machine_mode mode)
            default:
              gcc_unreachable ();
            }
+         if (opc)
+           emit_insn (gen_addsi3 (op1, op1, force_reg (SImode, opc)));
          operands[1] = op1;
        }
     }
@@ -1569,7 +1738,8 @@ output_branchy_insn (enum rtx_code code, const char *template,
 const char *
 output_ieee_ccmpeq (rtx insn, rtx *operands)
 {
-  return output_branchy_insn (NE, "bt\t%l9\\;fcmp/eq\t%1,%0", insn, operands);
+  return output_branchy_insn (NE, "bt\t%l9\n\tfcmp/eq\t%1,%0",
+                             insn, operands);
 }
 \f
 /* Output the start of the assembler file.  */
@@ -1597,7 +1767,7 @@ sh_file_start (void)
   else
     /* Switch to the data section so that the coffsem symbol
        isn't in the text section.  */
-    data_section ();
+    switch_to_section (data_section);
 
   if (TARGET_LITTLE_ENDIAN)
     fputs ("\t.little\n", asm_out_file);
@@ -1637,7 +1807,7 @@ unspec_caller_rtx_p (rtx pat)
 }
 
 /* Indicate that INSN cannot be duplicated.  This is true for insn
-   that generates an unique label.  */
+   that generates a unique label.  */
 
 static bool
 sh_cannot_copy_insn_p (rtx insn)
@@ -1783,12 +1953,12 @@ andcosts (rtx x)
 
   if (TARGET_SHMEDIA)
     {
-      if ((GET_CODE (XEXP (x, 1)) == CONST_INT
-          && CONST_OK_FOR_I16 (INTVAL (XEXP (x, 1))))
-         || EXTRA_CONSTRAINT_C16 (XEXP (x, 1)))
+      if (GET_CODE (XEXP (x, 1)) == CONST_INT
+         && (CONST_OK_FOR_I10 (INTVAL (XEXP (x, 1)))
+             || CONST_OK_FOR_J16 (INTVAL (XEXP (x, 1)))))
        return 1;
       else
-       return 2;
+       return 1 + rtx_cost (XEXP (x, 1), AND);
     }
 
   /* These constants are single cycle extu.[bw] instructions.  */
@@ -1852,8 +2022,8 @@ addsubcosts (rtx x)
 static inline int
 multcosts (rtx x ATTRIBUTE_UNUSED)
 {
-  if (*sh_multcost_str)
-    return atoi (sh_multcost_str);
+  if (sh_multcost >= 0)
+    return sh_multcost;
   if (TARGET_SHMEDIA)
     /* ??? We have a mul insn, but it has a latency of three, and doesn't
        accept constants.  Ideally, we would use a cost of one or two and
@@ -1908,9 +2078,9 @@ sh_rtx_costs (rtx x, int code, int outer_code, int *total)
          else if (CONST_OK_FOR_I16 (INTVAL (x) >> 16))
            *total = COSTS_N_INSNS ((outer_code != SET) + 1);
          else if (CONST_OK_FOR_I16 ((INTVAL (x) >> 16) >> 16))
-           *total = COSTS_N_INSNS (3);
+           *total = COSTS_N_INSNS ((outer_code != SET) + 2);
           else
-           *total = COSTS_N_INSNS (4);
+           *total = COSTS_N_INSNS ((outer_code != SET) + 3);
          return true;
         }
       if (CONST_OK_FOR_I08 (INTVAL (x)))
@@ -2795,9 +2965,17 @@ gen_datalabel_ref (rtx sym)
 }
 
 \f
+static alloc_pool label_ref_list_pool;
+
+typedef struct label_ref_list_d
+{
+  rtx label;
+  struct label_ref_list_d *next;
+} *label_ref_list_t;
+
 /* The SH cannot load a large constant into a register, constants have to
    come from a pc relative load.  The reference of a pc relative load
-   instruction must be less than 1k infront of the instruction.  This
+   instruction must be less than 1k in front of the instruction.  This
    means that we often have to dump a constant inside a function, and
    generate code to branch around it.
 
@@ -2852,7 +3030,7 @@ typedef struct
 {
   rtx value;                   /* Value in table.  */
   rtx label;                   /* Label of value.  */
-  rtx wend;                    /* End of window.  */
+  label_ref_list_t wend;       /* End of window.  */
   enum machine_mode mode;      /* Mode of value.  */
 
   /* True if this constant is accessed as part of a post-increment
@@ -2886,7 +3064,8 @@ static rtx
 add_constant (rtx x, enum machine_mode mode, rtx last_value)
 {
   int i;
-  rtx lab, new, ref, newref;
+  rtx lab, new;
+  label_ref_list_t ref, newref;
 
   /* First see if we've already got it.  */
   for (i = 0; i < pool_size; i++)
@@ -2912,9 +3091,10 @@ add_constant (rtx x, enum machine_mode mode, rtx last_value)
                }
              if (lab && pool_window_label)
                {
-                 newref = gen_rtx_LABEL_REF (VOIDmode, pool_window_label);
+                 newref = (label_ref_list_t) pool_alloc (label_ref_list_pool);
+                 newref->label = pool_window_label;
                  ref = pool_vector[pool_window_last].wend;
-                 LABEL_NEXTREF (newref) = ref;
+                 newref->next = ref;
                  pool_vector[pool_window_last].wend = newref;
                }
              if (new)
@@ -2936,13 +3116,14 @@ add_constant (rtx x, enum machine_mode mode, rtx last_value)
     lab = gen_label_rtx ();
   pool_vector[pool_size].mode = mode;
   pool_vector[pool_size].label = lab;
-  pool_vector[pool_size].wend = NULL_RTX;
+  pool_vector[pool_size].wend = NULL;
   pool_vector[pool_size].part_of_sequence_p = (lab == 0);
   if (lab && pool_window_label)
     {
-      newref = gen_rtx_LABEL_REF (VOIDmode, pool_window_label);
+      newref = (label_ref_list_t) pool_alloc (label_ref_list_pool);
+      newref->label = pool_window_label;
       ref = pool_vector[pool_window_last].wend;
-      LABEL_NEXTREF (newref) = ref;
+      newref->next = ref;
       pool_vector[pool_window_last].wend = newref;
     }
   if (lab)
@@ -2964,7 +3145,8 @@ dump_table (rtx start, rtx barrier)
   rtx scan = barrier;
   int i;
   int need_align = 1;
-  rtx lab, ref;
+  rtx lab;
+  label_ref_list_t ref;
   int have_df = 0;
 
   /* Do two passes, first time dump out the HI sized constants.  */
@@ -2984,9 +3166,9 @@ dump_table (rtx start, rtx barrier)
            scan = emit_label_after (lab, scan);
          scan = emit_insn_after (gen_consttable_2 (p->value, const0_rtx),
                                  scan);
-         for (ref = p->wend; ref; ref = LABEL_NEXTREF (ref))
+         for (ref = p->wend; ref; ref = ref->next)
            {
-             lab = XEXP (ref, 0);
+             lab = ref->label;
              scan = emit_insn_after (gen_consttable_window_end (lab), scan);
            }
        }
@@ -3034,9 +3216,9 @@ dump_table (rtx start, rtx barrier)
                    emit_label_before (lab, align_insn);
                  emit_insn_before (gen_consttable_4 (p->value, const0_rtx),
                                    align_insn);
-                 for (ref = p->wend; ref; ref = LABEL_NEXTREF (ref))
+                 for (ref = p->wend; ref; ref = ref->next)
                    {
-                     lab = XEXP (ref, 0);
+                     lab = ref->label;
                      emit_insn_before (gen_consttable_window_end (lab),
                                        align_insn);
                    }
@@ -3072,9 +3254,9 @@ dump_table (rtx start, rtx barrier)
 
          if (p->mode != HImode)
            {
-             for (ref = p->wend; ref; ref = LABEL_NEXTREF (ref))
+             for (ref = p->wend; ref; ref = ref->next)
                {
-                 lab = XEXP (ref, 0);
+                 lab = ref->label;
                  scan = emit_insn_after (gen_consttable_window_end (lab),
                                          scan);
                }
@@ -3124,9 +3306,9 @@ dump_table (rtx start, rtx barrier)
 
       if (p->mode != HImode)
        {
-         for (ref = p->wend; ref; ref = LABEL_NEXTREF (ref))
+         for (ref = p->wend; ref; ref = ref->next)
            {
-             lab = XEXP (ref, 0);
+             lab = ref->label;
              scan = emit_insn_after (gen_consttable_window_end (lab), scan);
            }
        }
@@ -3233,7 +3415,8 @@ fixup_mova (rtx mova)
          gcc_assert (worker
                      && GET_CODE (worker) != CODE_LABEL
                      && GET_CODE (worker) != JUMP_INSN);
-       } while (recog_memoized (worker) != CODE_FOR_casesi_worker_1);
+       } while (GET_CODE (worker) == NOTE
+                || recog_memoized (worker) != CODE_FOR_casesi_worker_1);
       wpat = PATTERN (worker);
       wpat0 = XVECEXP (wpat, 0, 0);
       wpat1 = XVECEXP (wpat, 0, 1);
@@ -4347,9 +4530,12 @@ sh_reorg (void)
       mdep_reorg_phase = SH_SHORTEN_BRANCHES0;
       shorten_branches (first);
     }
+
   /* Scan the function looking for move instructions which have to be
      changed to pc-relative loads and insert the literal tables.  */
-
+  label_ref_list_pool = create_alloc_pool ("label references list",
+                                          sizeof (struct label_ref_list_d),
+                                          30);
   mdep_reorg_phase = SH_FIXUP_PCLOAD;
   for (insn = first, num_mova = 0; insn; insn = NEXT_INSN (insn))
     {
@@ -4494,7 +4680,7 @@ sh_reorg (void)
                        }
                      last_float_move = scan;
                      last_float = src;
-                     newsrc = gen_rtx_MEM (mode,
+                     newsrc = gen_const_mem (mode,
                                        (((TARGET_SH4 && ! TARGET_FMOVD)
                                          || REGNO (dst) == FPUL_REG)
                                         ? r0_inc_rtx
@@ -4530,7 +4716,8 @@ sh_reorg (void)
          insn = barrier;
        }
     }
-
+  free_alloc_pool (label_ref_list_pool);
+  
   mdep_reorg_phase = SH_SHORTEN_BRANCHES1;
   INSN_ADDRESSES_FREE ();
   split_branches (first);
@@ -4833,12 +5020,10 @@ final_prescan_insn (rtx insn, rtx *opvec ATTRIBUTE_UNUSED,
          rtx pattern;
 
          pattern = PATTERN (insn);
+         if (GET_CODE (pattern) == PARALLEL)
+           pattern = XVECEXP (pattern, 0, 0);
          switch (GET_CODE (pattern))
            {
-           case PARALLEL:
-             pattern = XVECEXP (pattern, 0, 0);
-             break;
-
            case SET:
              if (GET_CODE (SET_SRC (pattern)) != CALL
                  && get_attr_type (insn) != TYPE_SFUNC)
@@ -5028,20 +5213,20 @@ output_stack_adjust (int size, rtx reg, int epilogue_p,
 
              adj_reg = gen_rtx_REG (GET_MODE (reg), 4);
              tmp_reg = gen_rtx_REG (GET_MODE (reg), 5);
-             emit_move_insn (gen_rtx_MEM (Pmode, reg), adj_reg);
+             emit_move_insn (gen_tmp_stack_mem (Pmode, reg), adj_reg);
              emit_insn (GEN_MOV (adj_reg, GEN_INT (size)));
              emit_insn (GEN_ADD3 (adj_reg, adj_reg, reg));
-             mem = gen_rtx_MEM (Pmode, gen_rtx_PRE_DEC (Pmode, adj_reg));
+             mem = gen_tmp_stack_mem (Pmode, gen_rtx_PRE_DEC (Pmode, adj_reg));
+             emit_move_insn (mem, tmp_reg);
+             emit_move_insn (tmp_reg, gen_tmp_stack_mem (Pmode, reg));
+             mem = gen_tmp_stack_mem (Pmode, gen_rtx_PRE_DEC (Pmode, adj_reg));
              emit_move_insn (mem, tmp_reg);
-               emit_move_insn (tmp_reg, gen_rtx_MEM (Pmode, reg));
-               mem = gen_rtx_MEM (Pmode, gen_rtx_PRE_DEC (Pmode, adj_reg));
-               emit_move_insn (mem, tmp_reg);
-               emit_move_insn (reg, adj_reg);
-               mem = gen_rtx_MEM (Pmode, gen_rtx_POST_INC (Pmode, reg));
-               emit_move_insn (adj_reg, mem);
-               mem = gen_rtx_MEM (Pmode, gen_rtx_POST_INC (Pmode, reg));
-               emit_move_insn (tmp_reg, mem);
-               return;
+             emit_move_insn (reg, adj_reg);
+             mem = gen_tmp_stack_mem (Pmode, gen_rtx_POST_INC (Pmode, reg));
+             emit_move_insn (adj_reg, mem);
+             mem = gen_tmp_stack_mem (Pmode, gen_rtx_POST_INC (Pmode, reg));
+             emit_move_insn (tmp_reg, mem);
+             return;
            }
          const_reg = gen_rtx_REG (GET_MODE (reg), temp);
 
@@ -5228,24 +5413,30 @@ calc_live_regs (HARD_REG_SET *live_regs_mask)
 {
   unsigned int reg;
   int count;
-  int interrupt_handler;
+  tree attrs;
+  bool interrupt_or_trapa_handler, trapa_handler, interrupt_handler;
+  bool nosave_low_regs;
   int pr_live, has_call;
 
-  interrupt_handler = sh_cfun_interrupt_handler_p ();
+  attrs = DECL_ATTRIBUTES (current_function_decl);
+  interrupt_or_trapa_handler = sh_cfun_interrupt_handler_p ();
+  trapa_handler = lookup_attribute ("trapa_handler", attrs) != NULL_TREE;
+  interrupt_handler = interrupt_or_trapa_handler && ! trapa_handler;
+  nosave_low_regs = lookup_attribute ("nosave_low_regs", attrs) != NULL_TREE;
 
   CLEAR_HARD_REG_SET (*live_regs_mask);
   if ((TARGET_SH4 || TARGET_SH2A_DOUBLE) && TARGET_FMOVD && interrupt_handler
       && regs_ever_live[FPSCR_REG])
-    target_flags &= ~FPU_SINGLE_BIT;
+    target_flags &= ~MASK_FPU_SINGLE;
   /* If we can save a lot of saves by switching to double mode, do that.  */
   else if ((TARGET_SH4 || TARGET_SH2A_DOUBLE) && TARGET_FMOVD && TARGET_FPU_SINGLE)
     for (count = 0, reg = FIRST_FP_REG; reg <= LAST_FP_REG; reg += 2)
       if (regs_ever_live[reg] && regs_ever_live[reg+1]
          && (! call_really_used_regs[reg]
-             || (interrupt_handler && ! pragma_trapa))
+             || interrupt_handler)
          && ++count > 2)
        {
-         target_flags &= ~FPU_SINGLE_BIT;
+         target_flags &= ~MASK_FPU_SINGLE;
          break;
        }
   /* PR_MEDIA_REG is a general purpose register, thus global_alloc already
@@ -5280,14 +5471,15 @@ calc_live_regs (HARD_REG_SET *live_regs_mask)
     {
       if (reg == (TARGET_SHMEDIA ? PR_MEDIA_REG : PR_REG)
          ? pr_live
-         : (interrupt_handler && ! pragma_trapa)
+         : interrupt_handler
          ? (/* Need to save all the regs ever live.  */
             (regs_ever_live[reg]
              || (call_really_used_regs[reg]
                  && (! fixed_regs[reg] || reg == MACH_REG || reg == MACL_REG
                      || reg == PIC_OFFSET_TABLE_REGNUM)
                  && has_call)
-             || (has_call && REGISTER_NATURAL_MODE (reg) == SImode
+             || (TARGET_SHMEDIA && has_call
+                 && REGISTER_NATURAL_MODE (reg) == SImode
                  && (GENERAL_REGISTER_P (reg) || TARGET_REGISTER_P (reg))))
             && reg != STACK_POINTER_REGNUM && reg != ARG_POINTER_REGNUM
             && reg != RETURN_ADDRESS_POINTER_REGNUM
@@ -5299,7 +5491,9 @@ calc_live_regs (HARD_REG_SET *live_regs_mask)
              && flag_pic
              && current_function_args_info.call_cookie
              && reg == PIC_OFFSET_TABLE_REGNUM)
-            || (regs_ever_live[reg] && ! call_really_used_regs[reg])
+            || (regs_ever_live[reg]
+                && (!call_really_used_regs[reg]
+                    || (trapa_handler && reg == FPSCR_REG && TARGET_FPU_ANY)))
             || (current_function_calls_eh_return
                 && (reg == EH_RETURN_DATA_REGNO (0)
                     || reg == EH_RETURN_DATA_REGNO (1)
@@ -5327,10 +5521,12 @@ calc_live_regs (HARD_REG_SET *live_regs_mask)
              else if (XD_REGISTER_P (reg))
                {
                  /* Must switch to double mode to access these registers.  */
-                 target_flags &= ~FPU_SINGLE_BIT;
+                 target_flags &= ~MASK_FPU_SINGLE;
                }
            }
        }
+      if (nosave_low_regs && reg == R8_REG)
+       break;
     }
   /* If we have a target register optimization pass after prologue / epilogue
      threading, we need to assume all target registers will be live even if
@@ -5534,6 +5730,8 @@ sh_expand_prologue (void)
   int d_rounding = 0;
   int save_flags = target_flags;
   int pretend_args;
+  tree sp_switch_attr
+    = lookup_attribute ("sp_switch", DECL_ATTRIBUTES (current_function_decl));
 
   current_function_interrupt = sh_cfun_interrupt_handler_p ();
 
@@ -5623,8 +5821,16 @@ sh_expand_prologue (void)
     }
 
   /* If we're supposed to switch stacks at function entry, do so now.  */
-  if (sp_switch)
-    emit_insn (gen_sp_switch_1 ());
+  if (sp_switch_attr)
+    {
+      /* The argument specifies a variable holding the address of the
+        stack the interrupt function should switch to/from at entry/exit.  */
+      const char *s
+       = ggc_strdup (TREE_STRING_POINTER (TREE_VALUE (sp_switch_attr)));
+      rtx sp_switch = gen_rtx_SYMBOL_REF (Pmode, s);
+
+      emit_insn (gen_sp_switch_1 (sp_switch));
+    }
 
   d = calc_live_regs (&live_regs_mask);
   /* ??? Maybe we could save some switching if we can move a mode switch
@@ -5690,10 +5896,10 @@ sh_expand_prologue (void)
 
          reg_rtx = gen_rtx_REG (mode, reg);
 
-         mem_rtx = gen_rtx_MEM (mode,
-                                gen_rtx_PLUS (Pmode,
-                                              stack_pointer_rtx,
-                                              GEN_INT (offset)));
+         mem_rtx = gen_frame_mem (mode,
+                                  gen_rtx_PLUS (Pmode,
+                                                stack_pointer_rtx,
+                                                GEN_INT (offset)));
 
          GO_IF_LEGITIMATE_ADDRESS (mode, XEXP (mem_rtx, 0), try_pre_dec);
 
@@ -5707,8 +5913,7 @@ sh_expand_prologue (void)
                    || mem_rtx == NULL_RTX
                    || reg == PR_REG || SPECIAL_REGISTER_P (reg)))
              {
-               pre_dec = gen_rtx_MEM (mode,
-                                      gen_rtx_PRE_DEC (Pmode, r0));
+               pre_dec = gen_frame_mem (mode, gen_rtx_PRE_DEC (Pmode, r0));
 
                GO_IF_LEGITIMATE_ADDRESS (mode, XEXP (pre_dec, 0),
                                          pre_dec_ok);
@@ -5756,12 +5961,12 @@ sh_expand_prologue (void)
              mem_rtx = pre_dec;
            }
          else if (sp_in_r0)
-           mem_rtx = gen_rtx_MEM (mode, r0);
+           mem_rtx = gen_frame_mem (mode, r0);
          else
-           mem_rtx = gen_rtx_MEM (mode,
-                                  gen_rtx_PLUS (Pmode,
-                                                stack_pointer_rtx,
-                                                r0));
+           mem_rtx = gen_frame_mem (mode,
+                                    gen_rtx_PLUS (Pmode,
+                                                  stack_pointer_rtx,
+                                                  r0));
 
          /* We must not use an r0-based address for target-branch
             registers or for special registers without pre-dec
@@ -5821,10 +6026,10 @@ sh_expand_prologue (void)
              {
                rtx reg_rtx = gen_rtx_REG (mode, reg);
                rtx set, note_rtx;
-               rtx mem_rtx = gen_rtx_MEM (mode,
-                                          gen_rtx_PLUS (Pmode,
-                                                        stack_pointer_rtx,
-                                                        GEN_INT (offset)));
+               rtx mem_rtx = gen_frame_mem (mode,
+                                            gen_rtx_PLUS (Pmode,
+                                                          stack_pointer_rtx,
+                                                          GEN_INT (offset)));
 
                set = gen_rtx_SET (VOIDmode, mem_rtx, reg_rtx);
                note_rtx = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, set,
@@ -5888,7 +6093,7 @@ sh_expand_prologue (void)
                       stack_pointer_rtx, 0, NULL);
 
   if (frame_pointer_needed)
-    frame_insn (GEN_MOV (frame_pointer_rtx, stack_pointer_rtx));
+    frame_insn (GEN_MOV (hard_frame_pointer_rtx, stack_pointer_rtx));
 
   if (TARGET_SHCOMPACT
       && (current_function_args_info.call_cookie & ~ CALL_COOKIE_RET_TRAMP(1)))
@@ -5950,14 +6155,15 @@ sh_expand_epilogue (bool sibcall_p)
         when exception handling is enabled.  See PR/18032.  */
       if (flag_exceptions)
        emit_insn (gen_blockage ());
-      output_stack_adjust (frame_size, frame_pointer_rtx, e, &live_regs_mask);
+      output_stack_adjust (frame_size, hard_frame_pointer_rtx, e,
+                          &live_regs_mask);
 
       /* We must avoid moving the stack pointer adjustment past code
         which reads from the local frame, else an interrupt could
         occur after the SP adjustment and clobber data in the local
         frame.  */
       emit_insn (gen_blockage ());
-      emit_insn (GEN_MOV (stack_pointer_rtx, frame_pointer_rtx));
+      emit_insn (GEN_MOV (stack_pointer_rtx, hard_frame_pointer_rtx));
     }
   else if (frame_size)
     {
@@ -6007,10 +6213,10 @@ sh_expand_epilogue (bool sibcall_p)
          offset = offset_base + entry->offset;
          reg_rtx = gen_rtx_REG (mode, reg);
 
-         mem_rtx = gen_rtx_MEM (mode,
-                                gen_rtx_PLUS (Pmode,
-                                              stack_pointer_rtx,
-                                              GEN_INT (offset)));
+         mem_rtx = gen_frame_mem (mode,
+                                  gen_rtx_PLUS (Pmode,
+                                                stack_pointer_rtx,
+                                                GEN_INT (offset)));
 
          GO_IF_LEGITIMATE_ADDRESS (mode, XEXP (mem_rtx, 0), try_post_inc);
 
@@ -6024,8 +6230,7 @@ sh_expand_epilogue (bool sibcall_p)
                        && mem_rtx == NULL_RTX)
                    || reg == PR_REG || SPECIAL_REGISTER_P (reg)))
              {
-               post_inc = gen_rtx_MEM (mode,
-                                       gen_rtx_POST_INC (Pmode, r0));
+               post_inc = gen_frame_mem (mode, gen_rtx_POST_INC (Pmode, r0));
 
                GO_IF_LEGITIMATE_ADDRESS (mode, XEXP (post_inc, 0),
                                          post_inc_ok);
@@ -6071,12 +6276,12 @@ sh_expand_epilogue (bool sibcall_p)
              offset_in_r0 += GET_MODE_SIZE (mode);
            }
          else if (sp_in_r0)
-           mem_rtx = gen_rtx_MEM (mode, r0);
+           mem_rtx = gen_frame_mem (mode, r0);
          else
-           mem_rtx = gen_rtx_MEM (mode,
-                                  gen_rtx_PLUS (Pmode,
-                                                stack_pointer_rtx,
-                                                r0));
+           mem_rtx = gen_frame_mem (mode,
+                                    gen_rtx_PLUS (Pmode,
+                                                  stack_pointer_rtx,
+                                                  r0));
 
          gcc_assert ((reg != PR_REG && !SPECIAL_REGISTER_P (reg))
                      || mem_rtx == post_inc);
@@ -6144,7 +6349,7 @@ sh_expand_epilogue (bool sibcall_p)
                         EH_RETURN_STACKADJ_RTX));
 
   /* Switch back to the normal stack if necessary.  */
-  if (sp_switch)
+  if (lookup_attribute ("sp_switch", DECL_ATTRIBUTES (current_function_decl)))
     emit_insn (gen_sp_switch_2 ());
 
   /* Tell flow the insn that pops PR isn't dead.  */
@@ -6234,9 +6439,9 @@ sh_set_return_address (rtx ra, rtx tmp)
     pr_offset = rounded_frame_size (d);
 
   emit_insn (GEN_MOV (tmp, GEN_INT (pr_offset)));
-  emit_insn (GEN_ADD3 (tmp, tmp, frame_pointer_rtx));
+  emit_insn (GEN_ADD3 (tmp, tmp, hard_frame_pointer_rtx));
 
-  tmp = gen_rtx_MEM (Pmode, tmp);
+  tmp = gen_frame_mem (Pmode, tmp);
   emit_insn (GEN_MOV (tmp, ra));
 }
 
@@ -6246,9 +6451,7 @@ static void
 sh_output_function_epilogue (FILE *file ATTRIBUTE_UNUSED,
                             HOST_WIDE_INT size ATTRIBUTE_UNUSED)
 {
-  trap_exit = pragma_interrupt = pragma_trapa = pragma_nosave_low_regs = 0;
   sh_need_epilogue_known = 0;
-  sp_switch = NULL_RTX;
 }
 
 static rtx
@@ -6313,8 +6516,7 @@ sh_builtin_saveregs (void)
   bufsize = (n_intregs * UNITS_PER_WORD) + (n_floatregs * UNITS_PER_WORD);
 
   if (TARGET_SHMEDIA)
-    regbuf = gen_rtx_MEM (BLKmode,
-                         gen_rtx_REG (Pmode, ARG_POINTER_REGNUM));
+    regbuf = gen_frame_mem (BLKmode, gen_rtx_REG (Pmode, ARG_POINTER_REGNUM));
   else if (n_floatregs & 1)
     {
       rtx addr;
@@ -6324,8 +6526,18 @@ sh_builtin_saveregs (void)
       emit_insn (gen_iorsi3 (addr, addr, GEN_INT (UNITS_PER_WORD)));
       regbuf = change_address (regbuf, BLKmode, addr);
     }
+  else if (STACK_BOUNDARY < 64 && TARGET_FPU_DOUBLE && n_floatregs)
+    {
+      rtx addr, mask;
+
+      regbuf = assign_stack_local (BLKmode, bufsize + UNITS_PER_WORD, 0);
+      addr = copy_to_mode_reg (Pmode, plus_constant (XEXP (regbuf, 0), 4));
+      mask = copy_to_mode_reg (Pmode, GEN_INT (-8));
+      emit_insn (gen_andsi3 (addr, addr, mask));
+      regbuf = change_address (regbuf, BLKmode, addr);
+    }
   else
-    regbuf = assign_stack_local (BLKmode, bufsize, 0);
+    regbuf = assign_stack_local (BLKmode, bufsize, TARGET_FPU_DOUBLE ? 64 : 0);
   alias_set = get_varargs_alias_set ();
   set_mem_alias_set (regbuf, alias_set);
 
@@ -6360,8 +6572,7 @@ sh_builtin_saveregs (void)
        {
          emit_insn (gen_addsi3 (fpregs, fpregs,
                                 GEN_INT (-2 * UNITS_PER_WORD)));
-         mem = gen_rtx_MEM (DFmode, fpregs);
-         set_mem_alias_set (mem, alias_set);
+         mem = change_address (regbuf, DFmode, fpregs);
          emit_move_insn (mem,
                          gen_rtx_REG (DFmode, BASE_ARG_REG (DFmode) + regno));
        }
@@ -6369,8 +6580,7 @@ sh_builtin_saveregs (void)
       if (regno & 1)
        {
          emit_insn (gen_addsi3 (fpregs, fpregs, GEN_INT (-UNITS_PER_WORD)));
-         mem = gen_rtx_MEM (SFmode, fpregs);
-         set_mem_alias_set (mem, alias_set);
+         mem = change_address (regbuf, SFmode, fpregs);
          emit_move_insn (mem,
                          gen_rtx_REG (SFmode, BASE_ARG_REG (SFmode) + regno
                                                - (TARGET_LITTLE_ENDIAN != 0)));
@@ -6382,8 +6592,7 @@ sh_builtin_saveregs (void)
         rtx mem;
 
        emit_insn (gen_addsi3 (fpregs, fpregs, GEN_INT (-UNITS_PER_WORD)));
-       mem = gen_rtx_MEM (SFmode, fpregs);
-       set_mem_alias_set (mem, alias_set);
+       mem = change_address (regbuf, SFmode, fpregs);
        emit_move_insn (mem,
                        gen_rtx_REG (SFmode, BASE_ARG_REG (SFmode) + regno));
       }
@@ -6466,20 +6675,20 @@ sh_va_start (tree valist, rtx nextarg)
   f_next_fp_limit = TREE_CHAIN (f_next_fp);
   f_next_stack = TREE_CHAIN (f_next_fp_limit);
 
-  next_o = build (COMPONENT_REF, TREE_TYPE (f_next_o), valist, f_next_o,
-                 NULL_TREE);
-  next_o_limit = build (COMPONENT_REF, TREE_TYPE (f_next_o_limit),
-                       valist, f_next_o_limit, NULL_TREE);
-  next_fp = build (COMPONENT_REF, TREE_TYPE (f_next_fp), valist, f_next_fp,
+  next_o = build3 (COMPONENT_REF, TREE_TYPE (f_next_o), valist, f_next_o,
                   NULL_TREE);
-  next_fp_limit = build (COMPONENT_REF, TREE_TYPE (f_next_fp_limit),
-                        valist, f_next_fp_limit, NULL_TREE);
-  next_stack = build (COMPONENT_REF, TREE_TYPE (f_next_stack),
-                     valist, f_next_stack, NULL_TREE);
+  next_o_limit = build3 (COMPONENT_REF, TREE_TYPE (f_next_o_limit),
+                        valist, f_next_o_limit, NULL_TREE);
+  next_fp = build3 (COMPONENT_REF, TREE_TYPE (f_next_fp), valist, f_next_fp,
+                   NULL_TREE);
+  next_fp_limit = build3 (COMPONENT_REF, TREE_TYPE (f_next_fp_limit),
+                         valist, f_next_fp_limit, NULL_TREE);
+  next_stack = build3 (COMPONENT_REF, TREE_TYPE (f_next_stack),
+                      valist, f_next_stack, NULL_TREE);
 
   /* Call __builtin_saveregs.  */
   u = make_tree (ptr_type_node, expand_builtin_saveregs ());
-  t = build (MODIFY_EXPR, ptr_type_node, next_fp, u);
+  t = build2 (MODIFY_EXPR, ptr_type_node, next_fp, u);
   TREE_SIDE_EFFECTS (t) = 1;
   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
 
@@ -6488,13 +6697,13 @@ sh_va_start (tree valist, rtx nextarg)
     nfp = 8 - nfp;
   else
     nfp = 0;
-  u = fold (build (PLUS_EXPR, ptr_type_node, u,
-                  build_int_cst (NULL_TREE, UNITS_PER_WORD * nfp)));
-  t = build (MODIFY_EXPR, ptr_type_node, next_fp_limit, u);
+  u = fold_build2 (PLUS_EXPR, ptr_type_node, u,
+                  build_int_cst (NULL_TREE, UNITS_PER_WORD * nfp));
+  t = build2 (MODIFY_EXPR, ptr_type_node, next_fp_limit, u);
   TREE_SIDE_EFFECTS (t) = 1;
   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
 
-  t = build (MODIFY_EXPR, ptr_type_node, next_o, u);
+  t = build2 (MODIFY_EXPR, ptr_type_node, next_o, u);
   TREE_SIDE_EFFECTS (t) = 1;
   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
 
@@ -6503,18 +6712,39 @@ sh_va_start (tree valist, rtx nextarg)
     nint = 4 - nint;
   else
     nint = 0;
-  u = fold (build (PLUS_EXPR, ptr_type_node, u,
-                  build_int_cst (NULL_TREE, UNITS_PER_WORD * nint)));
-  t = build (MODIFY_EXPR, ptr_type_node, next_o_limit, u);
+  u = fold_build2 (PLUS_EXPR, ptr_type_node, u,
+                  build_int_cst (NULL_TREE, UNITS_PER_WORD * nint));
+  t = build2 (MODIFY_EXPR, ptr_type_node, next_o_limit, u);
   TREE_SIDE_EFFECTS (t) = 1;
   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
 
   u = make_tree (ptr_type_node, nextarg);
-  t = build (MODIFY_EXPR, ptr_type_node, next_stack, u);
+  t = build2 (MODIFY_EXPR, ptr_type_node, next_stack, u);
   TREE_SIDE_EFFECTS (t) = 1;
   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
 }
 
+/* TYPE is a RECORD_TYPE.  If there is only a single non-zero-sized
+   member, return it.  */
+static tree
+find_sole_member (tree type)
+{
+  tree field, member = NULL_TREE;
+
+  for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
+    {
+      if (TREE_CODE (field) != FIELD_DECL)
+       continue;
+      if (!DECL_SIZE (field))
+       return NULL_TREE;
+      if (integer_zerop (DECL_SIZE (field)))
+       continue;
+      if (member)
+       return NULL_TREE;
+      member = field;
+    }
+  return member;
+}
 /* Implement `va_arg'.  */
 
 static tree
@@ -6525,6 +6755,7 @@ sh_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p,
   tree tmp, pptr_type_node;
   tree addr, lab_over = NULL, result = NULL;
   int pass_by_ref = targetm.calls.must_pass_in_stack (TYPE_MODE (type), type);
+  tree eff_type;
 
   if (pass_by_ref)
     type = build_pointer_type (type);
@@ -6540,6 +6771,7 @@ sh_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p,
       tree next_o, next_o_limit, next_fp, next_fp_limit, next_stack;
       int pass_as_float;
       tree lab_false;
+      tree member;
 
       f_next_o = TYPE_FIELDS (va_list_type_node);
       f_next_o_limit = TREE_CHAIN (f_next_o);
@@ -6547,38 +6779,51 @@ sh_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p,
       f_next_fp_limit = TREE_CHAIN (f_next_fp);
       f_next_stack = TREE_CHAIN (f_next_fp_limit);
 
-      next_o = build (COMPONENT_REF, TREE_TYPE (f_next_o), valist, f_next_o,
-                     NULL_TREE);
-      next_o_limit = build (COMPONENT_REF, TREE_TYPE (f_next_o_limit),
-                           valist, f_next_o_limit, NULL_TREE);
-      next_fp = build (COMPONENT_REF, TREE_TYPE (f_next_fp),
-                      valist, f_next_fp, NULL_TREE);
-      next_fp_limit = build (COMPONENT_REF, TREE_TYPE (f_next_fp_limit),
-                            valist, f_next_fp_limit, NULL_TREE);
-      next_stack = build (COMPONENT_REF, TREE_TYPE (f_next_stack),
-                         valist, f_next_stack, NULL_TREE);
+      next_o = build3 (COMPONENT_REF, TREE_TYPE (f_next_o), valist, f_next_o,
+                      NULL_TREE);
+      next_o_limit = build3 (COMPONENT_REF, TREE_TYPE (f_next_o_limit),
+                            valist, f_next_o_limit, NULL_TREE);
+      next_fp = build3 (COMPONENT_REF, TREE_TYPE (f_next_fp),
+                       valist, f_next_fp, NULL_TREE);
+      next_fp_limit = build3 (COMPONENT_REF, TREE_TYPE (f_next_fp_limit),
+                             valist, f_next_fp_limit, NULL_TREE);
+      next_stack = build3 (COMPONENT_REF, TREE_TYPE (f_next_stack),
+                          valist, f_next_stack, NULL_TREE);
 
       /* Structures with a single member with a distinct mode are passed
         like their member.  This is relevant if the latter has a REAL_TYPE
         or COMPLEX_TYPE type.  */
-      if (TREE_CODE (type) == RECORD_TYPE
-         && TYPE_FIELDS (type)
-         && TREE_CODE (TYPE_FIELDS (type)) == FIELD_DECL
-         && (TREE_CODE (TREE_TYPE (TYPE_FIELDS (type))) == REAL_TYPE
-             || TREE_CODE (TREE_TYPE (TYPE_FIELDS (type))) == COMPLEX_TYPE)
-          && TREE_CHAIN (TYPE_FIELDS (type)) == NULL_TREE)
-       type = TREE_TYPE (TYPE_FIELDS (type));
+      eff_type = type;
+      while (TREE_CODE (eff_type) == RECORD_TYPE
+            && (member = find_sole_member (eff_type))
+            && (TREE_CODE (TREE_TYPE (member)) == REAL_TYPE
+                || TREE_CODE (TREE_TYPE (member)) == COMPLEX_TYPE
+                || TREE_CODE (TREE_TYPE (member)) == RECORD_TYPE))
+       {
+         tree field_type = TREE_TYPE (member);
+
+         if (TYPE_MODE (eff_type) == TYPE_MODE (field_type))
+           eff_type = field_type;
+         else
+           {
+             gcc_assert ((TYPE_ALIGN (eff_type)
+                          < GET_MODE_ALIGNMENT (TYPE_MODE (field_type)))
+                         || (TYPE_ALIGN (eff_type)
+                             > GET_MODE_BITSIZE (TYPE_MODE (field_type))));
+             break;
+           }
+       }
 
       if (TARGET_SH4)
        {
-         pass_as_float = ((TREE_CODE (type) == REAL_TYPE && size <= 8)
-                          || (TREE_CODE (type) == COMPLEX_TYPE
-                              && TREE_CODE (TREE_TYPE (type)) == REAL_TYPE
+         pass_as_float = ((TREE_CODE (eff_type) == REAL_TYPE && size <= 8)
+                          || (TREE_CODE (eff_type) == COMPLEX_TYPE
+                              && TREE_CODE (TREE_TYPE (eff_type)) == REAL_TYPE
                               && size <= 16));
        }
       else
        {
-         pass_as_float = (TREE_CODE (type) == REAL_TYPE && size == 4);
+         pass_as_float = (TREE_CODE (eff_type) == REAL_TYPE && size == 4);
        }
 
       addr = create_tmp_var (pptr_type_node, NULL);
@@ -6589,92 +6834,109 @@ sh_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p,
 
       if (pass_as_float)
        {
-         int first_floatreg
-           = current_function_args_info.arg_count[(int) SH_ARG_FLOAT];
-         int n_floatregs = MAX (0, NPARM_REGS (SFmode) - first_floatreg);
+         tree next_fp_tmp = create_tmp_var (TREE_TYPE (f_next_fp), NULL);
+         tree cmp;
+         bool is_double = size == 8 && TREE_CODE (eff_type) == REAL_TYPE;
 
-         tmp = build (GE_EXPR, boolean_type_node, next_fp, next_fp_limit);
-         tmp = build (COND_EXPR, void_type_node, tmp,
-                      build (GOTO_EXPR, void_type_node, lab_false),
-                      NULL);
+         tmp = build1 (ADDR_EXPR, pptr_type_node, next_fp);
+         tmp = build2 (MODIFY_EXPR, void_type_node, addr, tmp);
          gimplify_and_add (tmp, pre_p);
 
-         if (TYPE_ALIGN (type) > BITS_PER_WORD
-             || (((TREE_CODE (type) == REAL_TYPE && size == 8) || size == 16)
-                 && (n_floatregs & 1)))
+         tmp = build2 (MODIFY_EXPR, ptr_type_node, next_fp_tmp, valist);
+         gimplify_and_add (tmp, pre_p);
+         tmp = next_fp_limit;
+         if (size > 4 && !is_double)
+           tmp = build2 (PLUS_EXPR, TREE_TYPE (tmp), tmp,
+                         fold_convert (TREE_TYPE (tmp), size_int (4 - size)));
+         tmp = build2 (GE_EXPR, boolean_type_node, next_fp_tmp, tmp);
+         cmp = build3 (COND_EXPR, void_type_node, tmp,
+                       build1 (GOTO_EXPR, void_type_node, lab_false),
+                       NULL_TREE);
+         if (!is_double)
+           gimplify_and_add (cmp, pre_p);
+
+         if (TYPE_ALIGN (eff_type) > BITS_PER_WORD
+             || (is_double || size == 16))
            {
              tmp = fold_convert (ptr_type_node, size_int (UNITS_PER_WORD));
-             tmp = build (BIT_AND_EXPR, ptr_type_node, next_fp, tmp);
-             tmp = build (PLUS_EXPR, ptr_type_node, next_fp, tmp);
-             tmp = build (MODIFY_EXPR, ptr_type_node, next_fp, tmp);
+             tmp = build2 (BIT_AND_EXPR, ptr_type_node, next_fp_tmp, tmp);
+             tmp = build2 (PLUS_EXPR, ptr_type_node, next_fp_tmp, tmp);
+             tmp = build2 (MODIFY_EXPR, ptr_type_node, next_fp_tmp, tmp);
              gimplify_and_add (tmp, pre_p);
            }
-
-         tmp = build1 (ADDR_EXPR, pptr_type_node, next_fp);
-         tmp = build (MODIFY_EXPR, void_type_node, addr, tmp);
-         gimplify_and_add (tmp, pre_p);
+         if (is_double)
+           gimplify_and_add (cmp, pre_p);
 
 #ifdef FUNCTION_ARG_SCmode_WART
-         if (TYPE_MODE (type) == SCmode && TARGET_SH4 && TARGET_LITTLE_ENDIAN)
+         if (TYPE_MODE (eff_type) == SCmode
+             && TARGET_SH4 && TARGET_LITTLE_ENDIAN)
            {
-             tree subtype = TREE_TYPE (type);
+             tree subtype = TREE_TYPE (eff_type);
              tree real, imag;
 
-             imag = std_gimplify_va_arg_expr (valist, subtype, pre_p, NULL);
+             imag
+               = std_gimplify_va_arg_expr (next_fp_tmp, subtype, pre_p, NULL);
              imag = get_initialized_tmp_var (imag, pre_p, NULL);
 
-             real = std_gimplify_va_arg_expr (valist, subtype, pre_p, NULL);
+             real
+               = std_gimplify_va_arg_expr (next_fp_tmp, subtype, pre_p, NULL);
              real = get_initialized_tmp_var (real, pre_p, NULL);
 
-             result = build (COMPLEX_EXPR, type, real, imag);
+             result = build2 (COMPLEX_EXPR, type, real, imag);
              result = get_initialized_tmp_var (result, pre_p, NULL);
            }
 #endif /* FUNCTION_ARG_SCmode_WART */
 
-         tmp = build (GOTO_EXPR, void_type_node, lab_over);
+         tmp = build1 (GOTO_EXPR, void_type_node, lab_over);
          gimplify_and_add (tmp, pre_p);
 
-         tmp = build (LABEL_EXPR, void_type_node, lab_false);
+         tmp = build1 (LABEL_EXPR, void_type_node, lab_false);
          gimplify_and_add (tmp, pre_p);
 
          tmp = build1 (ADDR_EXPR, pptr_type_node, next_stack);
-         tmp = build (MODIFY_EXPR, void_type_node, addr, tmp);
+         tmp = build2 (MODIFY_EXPR, void_type_node, addr, tmp);
          gimplify_and_add (tmp, pre_p);
+         tmp = build2 (MODIFY_EXPR, ptr_type_node, next_fp_tmp, valist);
+         gimplify_and_add (tmp, pre_p);
+
+         tmp = build2 (MODIFY_EXPR, ptr_type_node, valist, next_fp_tmp);
+         gimplify_and_add (tmp, post_p);
+         valist = next_fp_tmp;
        }
       else
        {
          tmp = fold_convert (ptr_type_node, size_int (rsize));
-         tmp = build (PLUS_EXPR, ptr_type_node, next_o, tmp);
-         tmp = build (GT_EXPR, boolean_type_node, tmp, next_o_limit);
-         tmp = build (COND_EXPR, void_type_node, tmp,
-                      build (GOTO_EXPR, void_type_node, lab_false),
-                      NULL);
+         tmp = build2 (PLUS_EXPR, ptr_type_node, next_o, tmp);
+         tmp = build2 (GT_EXPR, boolean_type_node, tmp, next_o_limit);
+         tmp = build3 (COND_EXPR, void_type_node, tmp,
+                       build1 (GOTO_EXPR, void_type_node, lab_false),
+                       NULL_TREE);
          gimplify_and_add (tmp, pre_p);
 
          tmp = build1 (ADDR_EXPR, pptr_type_node, next_o);
-         tmp = build (MODIFY_EXPR, void_type_node, addr, tmp);
+         tmp = build2 (MODIFY_EXPR, void_type_node, addr, tmp);
          gimplify_and_add (tmp, pre_p);
 
-         tmp = build (GOTO_EXPR, void_type_node, lab_over);
+         tmp = build1 (GOTO_EXPR, void_type_node, lab_over);
          gimplify_and_add (tmp, pre_p);
 
-         tmp = build (LABEL_EXPR, void_type_node, lab_false);
+         tmp = build1 (LABEL_EXPR, void_type_node, lab_false);
          gimplify_and_add (tmp, pre_p);
 
          if (size > 4 && ! TARGET_SH4)
            {
-             tmp = build (MODIFY_EXPR, ptr_type_node, next_o, next_o_limit);
+             tmp = build2 (MODIFY_EXPR, ptr_type_node, next_o, next_o_limit);
              gimplify_and_add (tmp, pre_p);
            }
 
          tmp = build1 (ADDR_EXPR, pptr_type_node, next_stack);
-         tmp = build (MODIFY_EXPR, void_type_node, addr, tmp);
+         tmp = build2 (MODIFY_EXPR, void_type_node, addr, tmp);
          gimplify_and_add (tmp, pre_p);
        }
 
       if (!result)
        {
-         tmp = build (LABEL_EXPR, void_type_node, lab_over);
+         tmp = build1 (LABEL_EXPR, void_type_node, lab_over);
          gimplify_and_add (tmp, pre_p);
        }
     }
@@ -6685,17 +6947,17 @@ sh_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p,
   tmp = std_gimplify_va_arg_expr (valist, type, pre_p, NULL);
   if (result)
     {
-      tmp = build (MODIFY_EXPR, void_type_node, result, tmp);
+      tmp = build2 (MODIFY_EXPR, void_type_node, result, tmp);
       gimplify_and_add (tmp, pre_p);
 
-      tmp = build (LABEL_EXPR, void_type_node, lab_over);
+      tmp = build1 (LABEL_EXPR, void_type_node, lab_over);
       gimplify_and_add (tmp, pre_p);
     }
   else
     result = tmp;
 
   if (pass_by_ref)
-    result = build_fold_indirect_ref (result);
+    result = build_va_arg_indirect_ref (result);
 
   return result;
 }
@@ -7153,7 +7415,7 @@ initial_elimination_offset (int from, int to)
 
   total_saved_regs_space = regs_saved + regs_saved_rounding;
 
-  if (from == ARG_POINTER_REGNUM && to == FRAME_POINTER_REGNUM)
+  if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
     return total_saved_regs_space + total_auto_space
       + current_function_args_info.byref_regs * 8;
 
@@ -7162,11 +7424,18 @@ initial_elimination_offset (int from, int to)
       + current_function_args_info.byref_regs * 8;
 
   /* Initial gap between fp and sp is 0.  */
-  if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
+  if (from == HARD_FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
     return 0;
 
+  if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
+    return rounded_frame_size (0);
+
+  if (from == FRAME_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
+    return rounded_frame_size (0);
+
   gcc_assert (from == RETURN_ADDRESS_POINTER_REGNUM
-             && (to == FRAME_POINTER_REGNUM || to == STACK_POINTER_REGNUM));
+             && (to == HARD_FRAME_POINTER_REGNUM
+                 || to == STACK_POINTER_REGNUM));
   if (TARGET_SH5)
     {
       int n = total_saved_regs_space;
@@ -7195,42 +7464,69 @@ initial_elimination_offset (int from, int to)
     return total_auto_space;
 }
 \f
-/* Handle machine specific pragmas to be semi-compatible with Renesas
-   compiler.  */
-
-void
-sh_pr_interrupt (struct cpp_reader *pfile ATTRIBUTE_UNUSED)
-{
-  pragma_interrupt = 1;
-}
-
-void
-sh_pr_trapa (struct cpp_reader *pfile ATTRIBUTE_UNUSED)
-{
-  pragma_interrupt = pragma_trapa = 1;
-}
-
-void
-sh_pr_nosave_low_regs (struct cpp_reader *pfile ATTRIBUTE_UNUSED)
-{
-  pragma_nosave_low_regs = 1;
-}
-
-/* Generate 'handle_interrupt' attribute for decls */
-
+/* Insert any deferred function attributes from earlier pragmas.  */
 static void
 sh_insert_attributes (tree node, tree *attributes)
 {
-  if (! pragma_interrupt
-      || TREE_CODE (node) != FUNCTION_DECL)
+  tree attrs;
+
+  if (TREE_CODE (node) != FUNCTION_DECL)
     return;
 
   /* We are only interested in fields.  */
   if (!DECL_P (node))
     return;
 
-  /* Add a 'handle_interrupt' attribute.  */
-  * attributes = tree_cons (get_identifier ("interrupt_handler"), NULL, * attributes);
+  /* Append the attributes to the deferred attributes.  */
+  *sh_deferred_function_attributes_tail = *attributes;
+  attrs = sh_deferred_function_attributes;
+  if (!attrs)
+    return;
+
+  /* Some attributes imply or require the interrupt attribute.  */
+  if (!lookup_attribute ("interrupt_handler", attrs)
+      && !lookup_attribute ("interrupt_handler", DECL_ATTRIBUTES (node)))
+    {
+      /* If we have a trapa_handler, but no interrupt_handler attribute,
+        insert an interrupt_handler attribute.  */
+      if (lookup_attribute ("trapa_handler", attrs) != NULL_TREE)
+       /* We can't use sh_pr_interrupt here because that's not in the
+          java frontend.  */
+       attrs
+         = tree_cons (get_identifier("interrupt_handler"), NULL_TREE, attrs);
+      /* However, for sp_switch, trap_exit and nosave_low_regs, if the
+        interrupt attribute is missing, we ignore the attribute and warn.  */
+      else if (lookup_attribute ("sp_switch", attrs)
+              || lookup_attribute ("trap_exit", attrs)
+              || lookup_attribute ("nosave_low_regs", attrs))
+       {
+         tree *tail;
+
+         for (tail = attributes; attrs; attrs = TREE_CHAIN (attrs))
+           {
+             if (is_attribute_p ("sp_switch", TREE_PURPOSE (attrs))
+                 || is_attribute_p ("trap_exit", TREE_PURPOSE (attrs))
+                 || is_attribute_p ("nosave_low_regs", TREE_PURPOSE (attrs)))
+               warning (OPT_Wattributes,
+                        "%qs attribute only applies to interrupt functions",
+                        IDENTIFIER_POINTER (TREE_PURPOSE (attrs)));
+             else
+               {
+                 *tail = tree_cons (TREE_PURPOSE (attrs), NULL_TREE,
+                                    NULL_TREE);
+                 tail = &TREE_CHAIN (*tail);
+               }
+           }
+         attrs = *attributes;
+       }
+    }
+
+  /* Install the processed list.  */
+  *attributes = attrs;
+
+  /* Clear deferred attributes.  */
+  sh_deferred_function_attributes = NULL_TREE;
+  sh_deferred_function_attributes_tail = &sh_deferred_function_attributes;
 
   return;
 }
@@ -7239,12 +7535,21 @@ sh_insert_attributes (tree node, tree *attributes)
 
    interrupt_handler -- specifies this function is an interrupt handler.
 
+   trapa_handler - like above, but don't save all registers.
+
    sp_switch -- specifies an alternate stack for an interrupt handler
    to run on.
 
    trap_exit -- use a trapa to exit an interrupt function instead of
    an rte instruction.
 
+   nosave_low_regs - don't save r0..r7 in an interrupt handler.
+     This is useful on the SH3 and upwards,
+     which has a separate set of low regs for User and Supervisor modes.
+     This should only be used for the lowest level of interrupts.  Higher levels
+     of interrupts must save the registers in case they themselves are
+     interrupted.
+
    renesas -- use Renesas calling/layout conventions (functions and
    structures).
 
@@ -7257,6 +7562,8 @@ const struct attribute_spec sh_attribute_table[] =
   { "sp_switch",         1, 1, true,  false, false, sh_handle_sp_switch_attribute },
   { "trap_exit",         1, 1, true,  false, false, sh_handle_trap_exit_attribute },
   { "renesas",           0, 0, false, true, false, sh_handle_renesas_attribute },
+  { "trapa_handler",     0, 0, true,  false, false, sh_handle_interrupt_handler_attribute },
+  { "nosave_low_regs",   0, 0, true,  false, false, sh_handle_interrupt_handler_attribute },
 #ifdef SYMBIAN
   /* Symbian support adds three new attributes:
      dllexport - for exporting a function/variable that will live in a dll
@@ -7281,7 +7588,7 @@ sh_handle_interrupt_handler_attribute (tree *node, tree name,
 {
   if (TREE_CODE (*node) != FUNCTION_DECL)
     {
-      warning (0, "%qs attribute only applies to functions",
+      warning (OPT_Wattributes, "%qs attribute only applies to functions",
               IDENTIFIER_POINTER (name));
       *no_add_attrs = true;
     }
@@ -7302,29 +7609,17 @@ sh_handle_sp_switch_attribute (tree *node, tree name, tree args,
 {
   if (TREE_CODE (*node) != FUNCTION_DECL)
     {
-      warning (0, "%qs attribute only applies to functions",
-              IDENTIFIER_POINTER (name));
-      *no_add_attrs = true;
-    }
-  else if (!pragma_interrupt)
-    {
-      /* The sp_switch attribute only has meaning for interrupt functions.  */
-      warning (0, "%qs attribute only applies to interrupt functions",
+      warning (OPT_Wattributes, "%qs attribute only applies to functions",
               IDENTIFIER_POINTER (name));
       *no_add_attrs = true;
     }
   else if (TREE_CODE (TREE_VALUE (args)) != STRING_CST)
     {
       /* The argument must be a constant string.  */
-      warning (0, "%qs attribute argument not a string constant",
+      warning (OPT_Wattributes, "%qs attribute argument not a string constant",
               IDENTIFIER_POINTER (name));
       *no_add_attrs = true;
     }
-  else
-    {
-      const char *s = ggc_strdup (TREE_STRING_POINTER (TREE_VALUE (args)));
-      sp_switch = gen_rtx_SYMBOL_REF (VOIDmode, s);
-    }
 
   return NULL_TREE;
 }
@@ -7337,28 +7632,19 @@ sh_handle_trap_exit_attribute (tree *node, tree name, tree args,
 {
   if (TREE_CODE (*node) != FUNCTION_DECL)
     {
-      warning (0, "%qs attribute only applies to functions",
-              IDENTIFIER_POINTER (name));
-      *no_add_attrs = true;
-    }
-  else if (!pragma_interrupt)
-    {
-      /* The trap_exit attribute only has meaning for interrupt functions.  */
-      warning (0, "%qs attribute only applies to interrupt functions",
+      warning (OPT_Wattributes, "%qs attribute only applies to functions",
               IDENTIFIER_POINTER (name));
       *no_add_attrs = true;
     }
+  /* The argument specifies a trap number to be used in a trapa instruction
+     at function exit (instead of an rte instruction).  */
   else if (TREE_CODE (TREE_VALUE (args)) != INTEGER_CST)
     {
       /* The argument must be a constant integer.  */
-      warning (0, "%qs attribute argument not an integer constant",
-              IDENTIFIER_POINTER (name));
+      warning (OPT_Wattributes, "%qs attribute argument not an "
+              "integer constant", IDENTIFIER_POINTER (name));
       *no_add_attrs = true;
     }
-  else
-    {
-      trap_exit = TREE_INT_CST_LOW (TREE_VALUE (args));
-    }
 
   return NULL_TREE;
 }
@@ -7383,6 +7669,8 @@ sh_attr_renesas_p (tree td)
     return 0;
   if (DECL_P (td))
     td = TREE_TYPE (td);
+  if (td == error_mark_node)
+    return 0;
   return (lookup_attribute ("renesas", TYPE_ATTRIBUTES (td))
          != NULL_TREE);
 }
@@ -7403,100 +7691,20 @@ sh_cfun_interrupt_handler_p (void)
          != NULL_TREE);
 }
 
-/* ??? target_switches in toplev.c is static, hence we have to duplicate it.  */
-static const struct
-{
-  const char *const name;
-  const int value;
-  const char *const description;
-}
-sh_target_switches[] = TARGET_SWITCHES;
-#define target_switches sh_target_switches
+/* Implement TARGET_CHECK_PCH_TARGET_FLAGS.  */
 
-/* Like default_pch_valid_p, but take flag_mask into account.  */
-const char *
-sh_pch_valid_p (const void *data_p, size_t len)
+static const char *
+sh_check_pch_target_flags (int old_flags)
 {
-#ifdef TARGET_OPTIONS
-  /* ??? We have a copy of this in toplev.c, but it is static.  */
-  static const struct
-    {
-      const char *const prefix;
-      const char **const variable;
-      const char *const description;
-      const char *const value;
-    }
-  target_options[] = TARGET_OPTIONS;
-#endif
-
-  const char *data = (const char *)data_p;
-  const char *flag_that_differs = NULL;
-  size_t i;
-  int old_flags;
-  int flag_mask
-    = (SH1_BIT | SH2_BIT | SH3_BIT | SH_E_BIT | HARD_SH4_BIT | FPU_SINGLE_BIT
-       | SH4_BIT | HITACHI_BIT | LITTLE_ENDIAN_BIT);
-
-  /* -fpic and -fpie also usually make a PCH invalid.  */
-  if (data[0] != flag_pic)
-    return _("created and used with different settings of -fpic");
-  if (data[1] != flag_pie)
-    return _("created and used with different settings of -fpie");
-  data += 2;
-
-  /* Check target_flags.  */
-  memcpy (&old_flags, data, sizeof (target_flags));
-  if (((old_flags ^ target_flags) & flag_mask) != 0)
-    {
-      for (i = 0; i < ARRAY_SIZE (target_switches); i++)
-       {
-         int bits;
-
-         bits = target_switches[i].value;
-         if (bits < 0)
-           bits = -bits;
-         bits &= flag_mask;
-         if ((target_flags & bits) != (old_flags & bits))
-           {
-             flag_that_differs = target_switches[i].name;
-             goto make_message;
-           }
-       }
-      gcc_unreachable ();
-    }
-  data += sizeof (target_flags);
-  len -= sizeof (target_flags);
-
-  /* Check string options.  */
-#ifdef TARGET_OPTIONS
-  for (i = 0; i < ARRAY_SIZE (target_options); i++)
-    {
-      const char *str = *target_options[i].variable;
-      size_t l;
-      if (! str)
-       str = "";
-      l = strlen (str) + 1;
-      if (len < l || memcmp (data, str, l) != 0)
-       {
-         flag_that_differs = target_options[i].prefix;
-         goto make_message;
-       }
-      data += l;
-      len -= l;
-    }
-#endif
-
+  if ((old_flags ^ target_flags) & (MASK_SH1 | MASK_SH2 | MASK_SH3
+                                   | MASK_SH_E | MASK_HARD_SH4
+                                   | MASK_FPU_SINGLE | MASK_SH4))
+    return _("created and used with different architectures / ABIs");
+  if ((old_flags ^ target_flags) & MASK_HITACHI)
+    return _("created and used with different ABIs");
+  if ((old_flags ^ target_flags) & MASK_LITTLE_ENDIAN)
+    return _("created and used with different endianness");
   return NULL;
-
- make_message:
-  {
-    char *r;
-    asprintf (&r, _("created and used with differing settings of '-m%s'"),
-                 flag_that_differs);
-    if (r == NULL)
-      return _("out of memory");
-    return r;
-  }
 }
 \f
 /* Predicates used by the templates.  */
@@ -7517,341 +7725,46 @@ system_reg_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
   return 0;
 }
 
-/* Returns 1 if OP can be source of a simple move operation.
-   Same as general_operand, but a LABEL_REF is valid, PRE_DEC is
-   invalid as are subregs of system registers.  */
+/* Nonzero if OP is a floating point value with value 0.0.  */
 
 int
-general_movsrc_operand (rtx op, enum machine_mode mode)
+fp_zero_operand (rtx op)
 {
-  if (GET_CODE (op) == MEM)
-    {
-      rtx inside = XEXP (op, 0);
-      if (GET_CODE (inside) == CONST)
-       inside = XEXP (inside, 0);
-
-      if (GET_CODE (inside) == LABEL_REF)
-       return 1;
-
-      if (GET_CODE (inside) == PLUS
-         && GET_CODE (XEXP (inside, 0)) == LABEL_REF
-         && GET_CODE (XEXP (inside, 1)) == CONST_INT)
-       return 1;
-
-      /* Only post inc allowed.  */
-      if (GET_CODE (inside) == PRE_DEC)
-       return 0;
-    }
+  REAL_VALUE_TYPE r;
 
-  if ((mode == QImode || mode == HImode)
-      && (GET_CODE (op) == SUBREG
-         && GET_CODE (XEXP (op, 0)) == REG
-         && system_reg_operand (XEXP (op, 0), mode)))
+  if (GET_MODE (op) != SFmode)
     return 0;
 
-  if (TARGET_SHMEDIA
-      && (GET_CODE (op) == PARALLEL || GET_CODE (op) == CONST_VECTOR)
-      && sh_rep_vec (op, mode))
-    return 1;
-  if (TARGET_SHMEDIA && 1
-      && GET_CODE (op) == SUBREG && GET_MODE (op) == mode
-      && SUBREG_REG (op) == const0_rtx && subreg_lowpart_p (op))
-    /* FIXME */ abort (); /* return 1; */
-  return general_operand (op, mode);
+  REAL_VALUE_FROM_CONST_DOUBLE (r, op);
+  return REAL_VALUES_EQUAL (r, dconst0) && ! REAL_VALUE_MINUS_ZERO (r);
 }
 
-/* Returns 1 if OP can be a destination of a move.
-   Same as general_operand, but no preinc allowed.  */
+/* Nonzero if OP is a floating point value with value 1.0.  */
 
 int
-general_movdst_operand (rtx op, enum machine_mode mode)
+fp_one_operand (rtx op)
 {
-  /* Only pre dec allowed.  */
-  if (GET_CODE (op) == MEM && GET_CODE (XEXP (op, 0)) == POST_INC)
-    return 0;
-  if (mode == DImode && TARGET_SHMEDIA && GET_CODE (op) == SUBREG
-      && GET_MODE_SIZE (GET_MODE (SUBREG_REG (op))) < 8
-      && ! (high_life_started || reload_completed))
+  REAL_VALUE_TYPE r;
+
+  if (GET_MODE (op) != SFmode)
     return 0;
 
-  return general_operand (op, mode);
+  REAL_VALUE_FROM_CONST_DOUBLE (r, op);
+  return REAL_VALUES_EQUAL (r, dconst1);
 }
 
-/* Returns 1 if OP is a normal arithmetic register.  */
-
+/* For -m4 and -m4-single-only, mode switching is used.  If we are
+   compiling without -mfmovd, movsf_ie isn't taken into account for
+   mode switching.  We could check in machine_dependent_reorg for
+   cases where we know we are in single precision mode, but there is
+   interface to find that out during reload, so we must avoid
+   choosing an fldi alternative during reload and thus failing to
+   allocate a scratch register for the constant loading.  */
 int
-arith_reg_operand (rtx op, enum machine_mode mode)
+fldi_ok (void)
 {
-  if (register_operand (op, mode))
-    {
-      int regno;
-
-      if (GET_CODE (op) == REG)
-       regno = REGNO (op);
-      else if (GET_CODE (op) == SUBREG && GET_CODE (SUBREG_REG (op)) == REG)
-       regno = REGNO (SUBREG_REG (op));
-      else
-       return 1;
-
-      return (regno != T_REG && regno != PR_REG
-             && ! TARGET_REGISTER_P (regno)
-             && (regno != FPUL_REG || TARGET_SH4)
-             && regno != MACH_REG && regno != MACL_REG);
-    }
-  /* Allow a no-op sign extension - compare LOAD_EXTEND_OP.
-     We allow SImode here, as not using an FP register is just a matter of
-     proper register allocation.  */
-  if (TARGET_SHMEDIA
-      && GET_MODE (op) == DImode && GET_CODE (op) == SIGN_EXTEND
-      && GET_MODE (XEXP (op, 0)) == SImode
-      && GET_CODE (XEXP (op, 0)) != SUBREG)
-    return register_operand (XEXP (op, 0), VOIDmode);
-#if 0 /* Can't do this because of PROMOTE_MODE for unsigned vars.  */
-  if (GET_MODE (op) == SImode && GET_CODE (op) == SIGN_EXTEND
-      && GET_MODE (XEXP (op, 0)) == HImode
-      && GET_CODE (XEXP (op, 0)) == REG
-      && REGNO (XEXP (op, 0)) <= LAST_GENERAL_REG)
-    return register_operand (XEXP (op, 0), VOIDmode);
-#endif
-  if (GET_MODE_CLASS (GET_MODE (op)) == MODE_VECTOR_INT
-      && GET_CODE (op) == SUBREG
-      && GET_MODE (SUBREG_REG (op)) == DImode
-      && GET_CODE (SUBREG_REG (op)) == SIGN_EXTEND
-      && GET_MODE (XEXP (SUBREG_REG (op), 0)) == SImode
-      && GET_CODE (XEXP (SUBREG_REG (op), 0)) != SUBREG)
-    return register_operand (XEXP (SUBREG_REG (op), 0), VOIDmode);
-  return 0;
-}
-
-/* Like above, but for DImode destinations: forbid paradoxical DImode subregs,
-   because this would lead to missing sign extensions when truncating from
-   DImode to SImode.  */
-int
-arith_reg_dest (rtx op, enum machine_mode mode)
-{
-  if (mode == DImode && GET_CODE (op) == SUBREG
-      && GET_MODE_SIZE (GET_MODE (SUBREG_REG (op))) < 8
-      && TARGET_SHMEDIA)
-    return 0;
-  return arith_reg_operand (op, mode);
-}
-
-/* Like arith_reg_operand, but for register source operands of narrow
-  logical SHMEDIA operations: forbid subregs of DImode / TImode regs.  */
-int
-logical_reg_operand (rtx op, enum machine_mode mode)
-{
-  if (TARGET_SHMEDIA
-      && GET_CODE (op) == SUBREG
-      && GET_MODE_SIZE (GET_MODE (SUBREG_REG (op))) > 4
-      && mode != DImode)
-    return 0;
-  return arith_reg_operand (op, mode);
-}
-
-int
-int_gpr_dest (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  enum machine_mode op_mode = GET_MODE (op);
-
-  if (GET_MODE_CLASS (op_mode) != MODE_INT
-      || GET_MODE_SIZE (op_mode) >= UNITS_PER_WORD)
-    return 0;
-  if (! reload_completed)
-    return 0;
-  return true_regnum (op) <= LAST_GENERAL_REG;
-}
-
-int
-fp_arith_reg_operand (rtx op, enum machine_mode mode)
-{
-  if (register_operand (op, mode))
-    {
-      int regno;
-
-      if (GET_CODE (op) == REG)
-       regno = REGNO (op);
-      else if (GET_CODE (op) == SUBREG && GET_CODE (SUBREG_REG (op)) == REG)
-       regno = REGNO (SUBREG_REG (op));
-      else
-       return 1;
-
-      return (regno >= FIRST_PSEUDO_REGISTER
-             || FP_REGISTER_P (regno));
-    }
-  return 0;
-}
-
-int
-fp_arith_reg_dest (rtx op, enum machine_mode mode)
-{
-  if (mode == DImode && GET_CODE (op) == SUBREG
-      && GET_MODE_SIZE (GET_MODE (SUBREG_REG (op))) < 8)
-    return 0;
-  return fp_arith_reg_operand (op, mode);
-}
-
-/* Returns 1 if OP is a valid source operand for an arithmetic insn.  */
-
-int
-arith_operand (rtx op, enum machine_mode mode)
-{
-  if (arith_reg_operand (op, mode))
-    return 1;
-
-  if (TARGET_SHMEDIA)
-    {
-      /* FIXME: We should be checking whether the CONST_INT fits in a
-        CONST_OK_FOR_I16 here, but this causes reload_cse to crash when
-        attempting to transform a sequence of two 64-bit sets of the
-        same register from literal constants into a set and an add,
-        when the difference is too wide for an add.  */
-      if (GET_CODE (op) == CONST_INT
-         || EXTRA_CONSTRAINT_C16 (op))
-       return 1;
-      else if (GET_CODE (op) == TRUNCATE
-              && ! system_reg_operand (XEXP (op, 0), VOIDmode)
-              && (mode == VOIDmode || mode == GET_MODE (op))
-              && (GET_MODE_SIZE (GET_MODE (op))
-                  < GET_MODE_SIZE (GET_MODE (XEXP (op, 0))))
-              && (! FP_REGISTER_P (REGNO (XEXP (op, 0)))
-                  || GET_MODE_SIZE (GET_MODE (op)) == 4))
-       return register_operand (XEXP (op, 0), VOIDmode);
-      else
-       return 0;
-    }
-  else if (GET_CODE (op) == CONST_INT && CONST_OK_FOR_I08 (INTVAL (op)))
-    return 1;
-
-  return 0;
-}
-
-/* Returns 1 if OP is a valid source operand for a compare insn.  */
-
-int
-arith_reg_or_0_operand (rtx op, enum machine_mode mode)
-{
-  if (arith_reg_operand (op, mode))
-    return 1;
-
-  if (EXTRA_CONSTRAINT_Z (op))
-    return 1;
-
-  return 0;
-}
-
-/* Return 1 if OP is a valid source operand for xor.  */
-
-int
-xor_operand (rtx op, enum machine_mode mode)
-{
-  if (GET_CODE (op) == CONST_INT)
-    return (TARGET_SHMEDIA
-           ? (CONST_OK_FOR_I06 (INTVAL (op))
-              || (no_new_pseudos && INTVAL (op) == 0xff))
-           : CONST_OK_FOR_K08 (INTVAL (op)));
-  if (TARGET_SHMEDIA
-      && mode != DImode && GET_CODE (op) == SUBREG
-      && GET_MODE_SIZE (GET_MODE (SUBREG_REG (op))) > 4)
-    return 0;
-  return arith_reg_operand (op, mode);
-}
-
-/* Return 1 if OP is a valid source operand for shmedia cmpgt / cmpgtu.  */
-int
-cmp_operand (rtx op, enum machine_mode mode)
-{
-  if (GET_CODE (op) == CONST_INT && CONST_OK_FOR_N (INTVAL (op)))
-    return 1;
-  if (TARGET_SHMEDIA
-      && mode != DImode && GET_CODE (op) == SUBREG
-      && GET_MODE_SIZE (GET_MODE (SUBREG_REG (op))) > 4)
-    return 0;
-  return arith_reg_operand (op, mode);
-}
-
-/* Returns 1 if OP is a valid source operand for a logical operation.  */
-
-int
-logical_operand (rtx op, enum machine_mode mode)
-{
-  if (TARGET_SHMEDIA
-      && mode != DImode && GET_CODE (op) == SUBREG
-      && GET_MODE_SIZE (GET_MODE (SUBREG_REG (op))) > 4)
-    return 0;
-
-  if (arith_reg_operand (op, mode))
-    return 1;
-
-  if (TARGET_SHMEDIA)
-    {
-      if (GET_CODE (op) == CONST_INT && CONST_OK_FOR_I10 (INTVAL (op)))
-       return 1;
-      else
-       return 0;
-    }
-  else if (GET_CODE (op) == CONST_INT && CONST_OK_FOR_K08 (INTVAL (op)))
-    return 1;
-
-  return 0;
-}
-
-int
-and_operand (rtx op, enum machine_mode mode)
-{
-  if (logical_operand (op, mode))
-    return 1;
-
-  /* Check mshflo.l / mshflhi.l opportunities.  */
-  if (TARGET_SHMEDIA
-      && mode == DImode
-      && GET_CODE (op) == CONST_INT
-      && CONST_OK_FOR_J16 (INTVAL (op)))
-    return 1;
-
-  return 0;
-}
-
-/* Nonzero if OP is a floating point value with value 0.0.  */
-
-int
-fp_zero_operand (rtx op)
-{
-  REAL_VALUE_TYPE r;
-
-  if (GET_MODE (op) != SFmode)
-    return 0;
-
-  REAL_VALUE_FROM_CONST_DOUBLE (r, op);
-  return REAL_VALUES_EQUAL (r, dconst0) && ! REAL_VALUE_MINUS_ZERO (r);
-}
-
-/* Nonzero if OP is a floating point value with value 1.0.  */
-
-int
-fp_one_operand (rtx op)
-{
-  REAL_VALUE_TYPE r;
-
-  if (GET_MODE (op) != SFmode)
-    return 0;
-
-  REAL_VALUE_FROM_CONST_DOUBLE (r, op);
-  return REAL_VALUES_EQUAL (r, dconst1);
-}
-
-/* For -m4 and -m4-single-only, mode switching is used.  If we are
-   compiling without -mfmovd, movsf_ie isn't taken into account for
-   mode switching.  We could check in machine_dependent_reorg for
-   cases where we know we are in single precision mode, but there is
-   interface to find that out during reload, so we must avoid
-   choosing an fldi alternative during reload and thus failing to
-   allocate a scratch register for the constant loading.  */
-int
-fldi_ok (void)
-{
-  return ! TARGET_SH4 || TARGET_FMOVD || reload_completed;
-}
+  return ! TARGET_SH4 || TARGET_FMOVD || reload_completed;
+}
 
 int
 tertiary_reload_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
@@ -7860,33 +7773,6 @@ tertiary_reload_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
   return code == MEM || (TARGET_SH4 && code == CONST_DOUBLE);
 }
 
-int
-fpscr_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  return (GET_CODE (op) == REG
-         && (REGNO (op) == FPSCR_REG
-             || (REGNO (op) >= FIRST_PSEUDO_REGISTER
-                 && !(reload_in_progress || reload_completed)))
-         && GET_MODE (op) == PSImode);
-}
-
-int
-fpul_operand (rtx op, enum machine_mode mode)
-{
-  if (TARGET_SHMEDIA)
-    return fp_arith_reg_operand (op, mode);
-
-  return (GET_CODE (op) == REG
-         && (REGNO (op) == FPUL_REG || REGNO (op) >= FIRST_PSEUDO_REGISTER)
-         && GET_MODE (op) == mode);
-}
-
-int
-symbol_ref_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  return (GET_CODE (op) == SYMBOL_REF);
-}
-
 /* Return the TLS type for TLS symbols, 0 for otherwise.  */
 int
 tls_symbolic_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
@@ -7895,366 +7781,6 @@ tls_symbolic_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
     return 0;
   return SYMBOL_REF_TLS_MODEL (op);
 }
-
-int
-commutative_float_operator (rtx op, enum machine_mode mode)
-{
-  if (GET_MODE (op) != mode)
-    return 0;
-  switch (GET_CODE (op))
-    {
-    case PLUS:
-    case MULT:
-      return 1;
-    default:
-      break;
-    }
-  return 0;
-}
-
-int
-noncommutative_float_operator (rtx op, enum machine_mode mode)
-{
-  if (GET_MODE (op) != mode)
-    return 0;
-  switch (GET_CODE (op))
-    {
-    case MINUS:
-    case DIV:
-      return 1;
-    default:
-      break;
-    }
-  return 0;
-}
-
-int
-unary_float_operator (rtx op, enum machine_mode mode)
-{
-  if (GET_MODE (op) != mode)
-    return 0;
-  switch (GET_CODE (op))
-    {
-    case ABS:
-    case NEG:
-    case SQRT:
-      return 1;
-    default:
-      break;
-    }
-  return 0;
-}
-
-int
-binary_float_operator (rtx op, enum machine_mode mode)
-{
-  if (GET_MODE (op) != mode)
-    return 0;
-  switch (GET_CODE (op))
-    {
-    case PLUS:
-    case MINUS:
-    case MULT:
-    case DIV:
-      return 1;
-    default:
-      break;
-    }
-  return 0;
-}
-
-int
-binary_logical_operator (rtx op, enum machine_mode mode)
-{
-  if (GET_MODE (op) != mode)
-    return 0;
-  switch (GET_CODE (op))
-    {
-    case IOR:
-    case AND:
-    case XOR:
-      return 1;
-    default:
-      break;
-    }
-  return 0;
-}
-
-int
-equality_comparison_operator (rtx op, enum machine_mode mode)
-{
-  return ((mode == VOIDmode || GET_MODE (op) == mode)
-         && (GET_CODE (op) == EQ || GET_CODE (op) == NE));
-}
-
-int
-greater_comparison_operator (rtx op, enum machine_mode mode)
-{
-  if (mode != VOIDmode && GET_MODE (op) != mode)
-    return 0;
-  switch (GET_CODE (op))
-    {
-    case GT:
-    case GE:
-    case GTU:
-    case GEU:
-      return 1;
-    default:
-      return 0;
-    }
-}
-
-int
-less_comparison_operator (rtx op, enum machine_mode mode)
-{
-  if (mode != VOIDmode && GET_MODE (op) != mode)
-    return 0;
-  switch (GET_CODE (op))
-    {
-    case LT:
-    case LE:
-    case LTU:
-    case LEU:
-      return 1;
-    default:
-      return 0;
-    }
-}
-
-int
-shift_operator (rtx op, enum machine_mode mode)
-{
-  if (mode != VOIDmode && GET_MODE (op) != mode)
-    return 0;
-  switch (GET_CODE (op))
-    {
-    case ASHIFT:
-    case ASHIFTRT:
-    case LSHIFTRT:
-      return 1;
-    default:
-      return 0;
-    }
-}
-
-int
-logical_operator (rtx op, enum machine_mode mode)
-{
-  if (mode != VOIDmode && GET_MODE (op) != mode)
-    return 0;
-  switch (GET_CODE (op))
-    {
-    case AND:
-    case IOR:
-    case XOR:
-      return 1;
-    default:
-      return 0;
-    }
-}
-
-/* Accept pseudos and branch target registers.  */
-int
-target_reg_operand (rtx op, enum machine_mode mode)
-{
-  if (mode == VOIDmode
-     ? GET_MODE (op) != Pmode && GET_MODE (op) != PDImode
-     : mode != GET_MODE (op))
-    return 0;
-
-  if (GET_CODE (op) == SUBREG)
-    op = XEXP (op, 0);
-
-  if (GET_CODE (op) != REG)
-    return 0;
-
-  /* We must protect ourselves from matching pseudos that are virtual
-     register, because they will eventually be replaced with hardware
-     registers that aren't branch-target registers.  */
-  if (REGNO (op) > LAST_VIRTUAL_REGISTER
-      || TARGET_REGISTER_P (REGNO (op)))
-    return 1;
-
-  return 0;
-}
-
-/* Same as target_reg_operand, except that label_refs and symbol_refs
-   are accepted before reload.  */
-int
-target_operand (rtx op, enum machine_mode mode)
-{
-  if (mode != VOIDmode && mode != Pmode)
-    return 0;
-
-  if ((GET_MODE (op) == Pmode || GET_MODE (op) == VOIDmode)
-      && EXTRA_CONSTRAINT_Csy (op))
-    return ! reload_completed;
-
-  return target_reg_operand (op, mode);
-}
-
-int
-mextr_bit_offset (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  HOST_WIDE_INT i;
-
-  if (GET_CODE (op) != CONST_INT)
-    return 0;
-  i = INTVAL (op);
-  return i >= 1 * 8 && i <= 7 * 8 && (i & 7) == 0;
-}
-
-int
-extend_reg_operand (rtx op, enum machine_mode mode)
-{
-  return (GET_CODE (op) == TRUNCATE
-         ? arith_operand
-         : arith_reg_operand) (op, mode);
-}
-
-int
-trunc_hi_operand (rtx op, enum machine_mode mode)
-{
-  enum machine_mode op_mode = GET_MODE (op);
-
-  if (op_mode != SImode && op_mode != DImode
-      && op_mode != V4HImode && op_mode != V2SImode)
-    return 0;
-  return extend_reg_operand (op, mode);
-}
-
-int
-extend_reg_or_0_operand (rtx op, enum machine_mode mode)
-{
-  return (GET_CODE (op) == TRUNCATE
-         ? arith_operand
-         : arith_reg_or_0_operand) (op, mode);
-}
-
-int
-minuend_operand (rtx op, enum machine_mode mode)
-{
-  return op == constm1_rtx || extend_reg_or_0_operand (op, mode);
-}
-
-int
-general_extend_operand (rtx op, enum machine_mode mode)
-{
-  return (GET_CODE (op) == TRUNCATE
-         ? arith_operand
-         : nonimmediate_operand) (op, mode);
-}
-
-int
-ua_address_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  if (GET_CODE (op) == PLUS
-      && (GET_CODE (XEXP (op, 1)) != CONST_INT
-         || ! CONST_OK_FOR_I06 (INTVAL (XEXP (op, 1)))))
-    return 0;
-  return address_operand (op, QImode);
-}
-
-int
-cache_address_operand (rtx op, enum machine_mode mode)
-{
-  if (GET_CODE (op) == PLUS)
-    {
-      if (GET_CODE (XEXP (op, 0)) != REG)
-       return 0;
-      if (GET_CODE (XEXP (op, 1)) != CONST_INT
-         || (INTVAL (XEXP (op, 1)) & 31))
-       return 0;
-    }
-  else if (GET_CODE (op) != REG)
-    return 0;
-  return address_operand (op, mode);
-}
-
-int
-inqhi_operand (rtx op, enum machine_mode mode)
-{
-  if (GET_CODE (op) != TRUNCATE || mode != GET_MODE (op))
-    return 0;
-  op = XEXP (op, 0);
-  /* Can't use true_regnum here because copy_cost wants to know about
-     SECONDARY_INPUT_RELOAD_CLASS.  */
-  return GET_CODE (op) == REG && FP_REGISTER_P (REGNO (op));
-}
-
-int
-sh_rep_vec (rtx v, enum machine_mode mode)
-{
-  int i;
-  rtx x, y;
-
-  if ((GET_CODE (v) != CONST_VECTOR && GET_CODE (v) != PARALLEL)
-      || (GET_MODE (v) != mode && mode != VOIDmode))
-    return 0;
-  i = XVECLEN (v, 0) - 2;
-  x = XVECEXP (v, 0, i + 1);
-  if (GET_MODE_UNIT_SIZE (mode) == 1)
-    {
-      y = XVECEXP (v, 0, i);
-      for (i -= 2; i >= 0; i -= 2)
-       if (! rtx_equal_p (XVECEXP (v, 0, i + 1), x)
-           || ! rtx_equal_p (XVECEXP (v, 0, i), y))
-         return 0;
-    }
-  else
-    for (; i >= 0; i--)
-      if (XVECEXP (v, 0, i) != x)
-       return 0;
-  return 1;
-}
-
-/* Determine if V is a constant vector matching MODE with only one element
-   that is not a sign extension.  Two byte-sized elements count as one.  */
-int
-sh_1el_vec (rtx v, enum machine_mode mode)
-{
-  int unit_size;
-  int i, last, least, sign_ix;
-  rtx sign;
-
-  if (GET_CODE (v) != CONST_VECTOR
-      || (GET_MODE (v) != mode && mode != VOIDmode))
-    return 0;
-  /* Determine numbers of last and of least significant elements.  */
-  last = XVECLEN (v, 0) - 1;
-  least = TARGET_LITTLE_ENDIAN ? 0 : last;
-  if (GET_CODE (XVECEXP (v, 0, least)) != CONST_INT)
-    return 0;
-  sign_ix = least;
-  if (GET_MODE_UNIT_SIZE (mode) == 1)
-    sign_ix = TARGET_LITTLE_ENDIAN ? 1 : last - 1;
-  if (GET_CODE (XVECEXP (v, 0, sign_ix)) != CONST_INT)
-    return 0;
-  unit_size = GET_MODE_UNIT_SIZE (GET_MODE (v));
-  sign = (INTVAL (XVECEXP (v, 0, sign_ix)) >> (unit_size * BITS_PER_UNIT - 1)
-         ? constm1_rtx : const0_rtx);
-  i = XVECLEN (v, 0) - 1;
-  do
-    if (i != least && i != sign_ix && XVECEXP (v, 0, i) != sign)
-      return 0;
-  while (--i);
-  return 1;
-}
-
-int
-sh_const_vec (rtx v, enum machine_mode mode)
-{
-  int i;
-
-  if (GET_CODE (v) != CONST_VECTOR
-      || (GET_MODE (v) != mode && mode != VOIDmode))
-    return 0;
-  i = XVECLEN (v, 0) - 1;
-  for (; i >= 0; i--)
-    if (GET_CODE (XVECEXP (v, 0, i)) != CONST_INT)
-      return 0;
-  return 1;
-}
 \f
 /* Return the destination address of a branch.  */
 
@@ -8382,6 +7908,45 @@ get_fpscr_rtx (void)
   return fpscr_rtx;
 }
 
+static GTY(()) tree fpscr_values;
+
+static void
+emit_fpu_switch (rtx scratch, int index)
+{
+  rtx dst, src;
+
+  if (fpscr_values == NULL)
+    {
+      tree t;
+
+      t = build_index_type (integer_one_node);
+      t = build_array_type (integer_type_node, t);
+      t = build_decl (VAR_DECL, get_identifier ("__fpscr_values"), t);
+      DECL_ARTIFICIAL (t) = 1;
+      DECL_IGNORED_P (t) = 1;
+      DECL_EXTERNAL (t) = 1;
+      TREE_STATIC (t) = 1;
+      TREE_PUBLIC (t) = 1;
+      TREE_USED (t) = 1;
+
+      fpscr_values = t;
+    }
+
+  src = DECL_RTL (fpscr_values);
+  if (no_new_pseudos)
+    {
+      emit_move_insn (scratch, XEXP (src, 0));
+      if (index != 0)
+       emit_insn (gen_addsi3 (scratch, scratch, GEN_INT (index * 4)));
+      src = adjust_automodify_address (src, PSImode, scratch, index * 4);
+    }
+  else
+    src = adjust_address (src, PSImode, index * 4);
+
+  dst = get_fpscr_rtx ();
+  emit_move_insn (dst, src);
+}
+
 void
 emit_sf_insn (rtx pat)
 {
@@ -8534,12 +8099,10 @@ void
 fpscr_set_from_mem (int mode, HARD_REG_SET regs_live)
 {
   enum attr_fp_mode fp_mode = mode;
+  enum attr_fp_mode norm_mode = ACTUAL_NORMAL_MODE (FP_MODE);
   rtx addr_reg = get_free_reg (regs_live);
 
-  if (fp_mode == (enum attr_fp_mode) ACTUAL_NORMAL_MODE (FP_MODE))
-    emit_insn (gen_fpu_switch1 (addr_reg));
-  else
-    emit_insn (gen_fpu_switch0 (addr_reg));
+  emit_fpu_switch (addr_reg, fp_mode == norm_mode);
 }
 
 /* Is the given character a logical line separator for the assembler?  */
@@ -8766,12 +8329,6 @@ mark_constant_pool_use (rtx x)
 
   return lab;
 }
-
-int
-ua_offset (rtx c, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  return GET_CODE (c) == CONST_INT && CONST_OK_FOR_I06 (INTVAL (c));
-}
 \f
 /* Return true if it's possible to redirect BRANCH1 to the destination
    of an unconditional jump BRANCH2.  We only want to do this if the
@@ -9003,16 +8560,41 @@ flow_dependent_p_1 (rtx x, rtx pat ATTRIBUTE_UNUSED, void *data)
     *pinsn = NULL_RTX;
 }
 
-/* For use by ALLOCATE_INITIAL_VALUE.  Note that sh.md contains some
+/* For use by sh_allocate_initial_value.  Note that sh.md contains some
    'special function' patterns (type sfunc) that clobber pr, but that
    do not look like function calls to leaf_function_p.  Hence we must
    do this extra check.  */
-int
+static int
 sh_pr_n_sets (void)
 {
   return REG_N_SETS (TARGET_SHMEDIA ? PR_MEDIA_REG : PR_REG);
 }
 
+/* Return where to allocate pseudo for a given hard register initial
+   value.  */
+static rtx
+sh_allocate_initial_value (rtx hard_reg)
+{
+  rtx x;
+
+  if (REGNO (hard_reg) == (TARGET_SHMEDIA ? PR_MEDIA_REG : PR_REG))
+    {
+      if (current_function_is_leaf
+         && ! sh_pr_n_sets ()
+         && ! (TARGET_SHCOMPACT
+               && ((current_function_args_info.call_cookie
+                    & ~ CALL_COOKIE_RET_TRAMP (1))
+                   || current_function_has_nonlocal_label)))
+       x = hard_reg;
+      else
+       x = gen_frame_mem (Pmode, return_address_pointer_rtx);
+    }
+  else
+    x = NULL_RTX;
+
+  return x;
+}
+
 /* This function returns "2" to indicate dual issue for the SH4
    processor.  To be used by the DFA pipeline description.  */
 static int
@@ -9399,6 +8981,8 @@ sh_ms_bitfield_layout_p (tree record_type ATTRIBUTE_UNUSED)
 void
 sh_initialize_trampoline (rtx tramp, rtx fnaddr, rtx cxt)
 {
+  rtx tramp_mem = gen_frame_mem (BLKmode, tramp);
+
   if (TARGET_SHMEDIA64)
     {
       rtx tramp_templ;
@@ -9427,34 +9011,32 @@ sh_initialize_trampoline (rtx tramp, rtx fnaddr, rtx cxt)
          insn = gen_rtx_IOR (DImode, insn, gen_int_mode (0xec000010, SImode));
          insn = force_operand (insn, NULL_RTX);
          insn = gen_lowpart (SImode, insn);
-         emit_move_insn (gen_rtx_MEM (SImode, tramp), insn);
+         emit_move_insn (change_address (tramp_mem, SImode, NULL_RTX), insn);
          insn = gen_rtx_LSHIFTRT (DImode, fnaddr, GEN_INT (38));
          insn = gen_rtx_AND (DImode, insn, mask);
          insn = force_operand (gen_rtx_IOR (DImode, movi1, insn), NULL_RTX);
          insn = gen_lowpart (SImode, insn);
-         emit_move_insn (gen_rtx_MEM (SImode, plus_constant (tramp, 4)), insn);
+         emit_move_insn (adjust_address (tramp_mem, SImode, 4), insn);
          insn = gen_rtx_LSHIFTRT (DImode, fnaddr, GEN_INT (22));
          insn = gen_rtx_AND (DImode, insn, mask);
          insn = force_operand (gen_rtx_IOR (DImode, shori1, insn), NULL_RTX);
          insn = gen_lowpart (SImode, insn);
-         emit_move_insn (gen_rtx_MEM (SImode, plus_constant (tramp, 8)), insn);
+         emit_move_insn (adjust_address (tramp_mem, SImode, 8), insn);
          insn = gen_rtx_LSHIFTRT (DImode, fnaddr, GEN_INT (6));
          insn = gen_rtx_AND (DImode, insn, mask);
          insn = force_operand (gen_rtx_IOR (DImode, shori1, insn), NULL_RTX);
          insn = gen_lowpart (SImode, insn);
-         emit_move_insn (gen_rtx_MEM (SImode, plus_constant (tramp, 12)),
-                         insn);
+         emit_move_insn (adjust_address (tramp_mem, SImode, 12), insn);
          insn = gen_rtx_ASHIFT (DImode, fnaddr, GEN_INT (10));
          insn = gen_rtx_AND (DImode, insn, mask);
          insn = force_operand (gen_rtx_IOR (DImode, shori1, insn), NULL_RTX);
          insn = gen_lowpart (SImode, insn);
-         emit_move_insn (gen_rtx_MEM (SImode, plus_constant (tramp, 16)),
-                         insn);
-         emit_move_insn (gen_rtx_MEM (SImode, plus_constant (tramp, 20)),
+         emit_move_insn (adjust_address (tramp_mem, SImode, 16), insn);
+         emit_move_insn (adjust_address (tramp_mem, SImode, 20),
                          GEN_INT (0x6bf10600));
-         emit_move_insn (gen_rtx_MEM (SImode, plus_constant (tramp, 24)),
+         emit_move_insn (adjust_address (tramp_mem, SImode, 24),
                          GEN_INT (0x4415fc10));
-         emit_move_insn (gen_rtx_MEM (SImode, plus_constant (tramp, 28)),
+         emit_move_insn (adjust_address (tramp_mem, SImode, 28),
                          GEN_INT (0x4401fff0));
          emit_insn (gen_ic_invalidate_line (tramp));
          return;
@@ -9463,18 +9045,15 @@ sh_initialize_trampoline (rtx tramp, rtx fnaddr, rtx cxt)
       fixed_len = TRAMPOLINE_SIZE - 2 * GET_MODE_SIZE (Pmode);
 
       tramp_templ = gen_datalabel_ref (tramp_templ);
-      dst = gen_rtx_MEM (BLKmode, tramp);
-      src = gen_rtx_MEM (BLKmode, tramp_templ);
+      dst = tramp_mem;
+      src = gen_const_mem (BLKmode, tramp_templ);
       set_mem_align (dst, 256);
       set_mem_align (src, 64);
       emit_block_move (dst, src, GEN_INT (fixed_len), BLOCK_OP_NORMAL);
 
-      emit_move_insn (gen_rtx_MEM (Pmode, plus_constant (tramp,        fixed_len)),
-                     fnaddr);
-      emit_move_insn (gen_rtx_MEM (Pmode,
-                                  plus_constant (tramp,
-                                                 fixed_len
-                                                 + GET_MODE_SIZE (Pmode))),
+      emit_move_insn (adjust_address (tramp_mem, Pmode, fixed_len), fnaddr);
+      emit_move_insn (adjust_address (tramp_mem, Pmode,
+                                     fixed_len + GET_MODE_SIZE (Pmode)),
                      cxt);
       emit_insn (gen_ic_invalidate_line (tramp));
       return;
@@ -9502,7 +9081,7 @@ sh_initialize_trampoline (rtx tramp, rtx fnaddr, rtx cxt)
       emit_insn (gen_rotrdi3_mextr (quad0, quad0,
                                    GEN_INT (TARGET_LITTLE_ENDIAN ? 24 : 56)));
       emit_insn (gen_ashldi3_media (quad0, quad0, const2_rtx));
-      emit_move_insn (gen_rtx_MEM (DImode, tramp), quad0);
+      emit_move_insn (change_address (tramp_mem, DImode, NULL_RTX), quad0);
       emit_insn (gen_mshflo_w_x (gen_rtx_SUBREG (V4HImode, cxtload, 0),
                                 gen_rtx_SUBREG (V2HImode, cxt, 0),
                                 movishori));
@@ -9519,8 +9098,8 @@ sh_initialize_trampoline (rtx tramp, rtx fnaddr, rtx cxt)
          emit_insn (gen_mextr4 (quad1, cxtload, ptabs));
          emit_insn (gen_mshflo_l_di (quad2, blink, cxtload));
        }
-      emit_move_insn (gen_rtx_MEM (DImode, plus_constant (tramp, 8)), quad1);
-      emit_move_insn (gen_rtx_MEM (DImode, plus_constant (tramp, 16)), quad2);
+      emit_move_insn (adjust_address (tramp_mem, DImode, 8), quad1);
+      emit_move_insn (adjust_address (tramp_mem, DImode, 16), quad2);
       emit_insn (gen_ic_invalidate_line (tramp));
       return;
     }
@@ -9529,16 +9108,14 @@ sh_initialize_trampoline (rtx tramp, rtx fnaddr, rtx cxt)
       emit_insn (gen_initialize_trampoline (tramp, cxt, fnaddr));
       return;
     }
-  emit_move_insn (gen_rtx_MEM (SImode, tramp),
+  emit_move_insn (change_address (tramp_mem, SImode, NULL_RTX),
                  gen_int_mode (TARGET_LITTLE_ENDIAN ? 0xd301d202 : 0xd202d301,
                                SImode));
-  emit_move_insn (gen_rtx_MEM (SImode, plus_constant (tramp, 4)),
+  emit_move_insn (adjust_address (tramp_mem, SImode, 4),
                  gen_int_mode (TARGET_LITTLE_ENDIAN ? 0x0009422b : 0x422b0009,
                                SImode));
-  emit_move_insn (gen_rtx_MEM (SImode, plus_constant (tramp, 8)),
-                 cxt);
-  emit_move_insn (gen_rtx_MEM (SImode, plus_constant (tramp, 12)),
-                 fnaddr);
+  emit_move_insn (adjust_address (tramp_mem, SImode, 8), cxt);
+  emit_move_insn (adjust_address (tramp_mem, SImode, 12), fnaddr);
   if (TARGET_HARVARD)
     {
       if (TARGET_USERMODE)
@@ -10005,6 +9582,9 @@ sh_register_move_cost (enum machine_mode mode,
       && REGCLASS_HAS_FP_REG (dstclass))
     return 4;
 
+  if (REGCLASS_HAS_FP_REG (dstclass) && srcclass == T_REGS)
+    return ((TARGET_HARD_SH4 && !optimize_size) ? 10 : 7);
+
   if ((REGCLASS_HAS_FP_REG (dstclass) && srcclass == MAC_REGS)
       || (dstclass == MAC_REGS && REGCLASS_HAS_FP_REG (srcclass)))
     return 9;
@@ -10036,8 +9616,8 @@ sh_register_move_cost (enum machine_mode mode,
   if (TARGET_SHMEDIA
       && ((srcclass) == TARGET_REGS || (srcclass) == SIBCALL_REGS))
     {
-      if (*sh_gettrcost_str)
-       return atoi (sh_gettrcost_str);
+      if (sh_gettrcost >= 0)
+       return sh_gettrcost;
       else if (!TARGET_PT_FIXED)
        return 100;
     }
@@ -10055,63 +9635,12 @@ sh_register_move_cost (enum machine_mode mode,
   return 2 * ((GET_MODE_SIZE (mode) + 3) / 4U);
 }
 
-/* Like register_operand, but take into account that SHMEDIA can use
-   the constant zero like a general register.  */
-int
-sh_register_operand (rtx op, enum machine_mode mode)
-{
-  if (op == CONST0_RTX (mode) && TARGET_SHMEDIA)
-    return 1;
-  return register_operand (op, mode);
-}
-
-int
-cmpsi_operand (rtx op, enum machine_mode mode)
-{
-  if (GET_CODE (op) == REG && REGNO (op) == T_REG
-      && GET_MODE (op) == SImode
-      && TARGET_SH1)
-    return 1;
-  return arith_operand (op, mode);
-}
-
-int
-shift_count_reg_operand (rtx op, enum machine_mode mode)
-{
-  if ((GET_CODE (op) == ZERO_EXTEND || GET_CODE (op) == SIGN_EXTEND
-       || (GET_CODE (op) == SUBREG && SUBREG_BYTE (op) == 0))
-      && (mode == VOIDmode || mode == GET_MODE (op))
-      && GET_MODE_BITSIZE (GET_MODE (XEXP (op, 0))) >= 6
-      && GET_MODE_CLASS (GET_MODE (XEXP (op, 0))) == MODE_INT)
-    {
-      mode = VOIDmode;
-      do
-       op = XEXP (op, 0);
-      while ((GET_CODE (op) == ZERO_EXTEND || GET_CODE (op) == SIGN_EXTEND
-             || GET_CODE (op) == TRUNCATE)
-            && GET_MODE_BITSIZE (GET_MODE (XEXP (op, 0))) >= 6
-            && GET_MODE_CLASS (GET_MODE (XEXP (op, 0))) == MODE_INT);
-
-    }
-  return arith_reg_operand (op, mode);
-}
-
-int
-shift_count_operand (rtx op, enum machine_mode mode)
-{
-  return (CONSTANT_P (op)
-         ? (GET_CODE (op) == CONST_INT
-            ? (unsigned) INTVAL (op) < GET_MODE_BITSIZE (mode)
-            : nonmemory_operand (op, mode))
-         : shift_count_reg_operand (op, mode));
-}
-
 static rtx emit_load_ptr (rtx, rtx);
 
 static rtx
 emit_load_ptr (rtx reg, rtx addr)
 {
-  rtx mem = gen_rtx_MEM (ptr_mode, addr);
+  rtx mem = gen_const_mem (ptr_mode, addr);
 
   if (Pmode != ptr_mode)
     mem = gen_rtx_SIGN_EXTEND (Pmode, mem);
@@ -10296,7 +9825,7 @@ sh_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
   insn_locators_initialize ();
   insns = get_insns ();
 
-  if (optimize > 0 && flag_schedule_insns_after_reload)
+  if (optimize > 0)
     {
       /* Initialize the bitmap obstacks.  */
       bitmap_obstack_initialize (NULL);
@@ -10304,31 +9833,36 @@ sh_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
       if (! cfun->cfg)
        init_flow ();
       rtl_register_cfg_hooks ();
+      init_rtl_bb_info (ENTRY_BLOCK_PTR);
+      init_rtl_bb_info (EXIT_BLOCK_PTR);
+      ENTRY_BLOCK_PTR->flags |= BB_RTL;
+      EXIT_BLOCK_PTR->flags |= BB_RTL;
       find_basic_blocks (insns);
-      life_analysis (dump_file, PROP_FINAL);
 
-      split_all_insns (1);
+      if (flag_schedule_insns_after_reload)
+       {
+         life_analysis (PROP_FINAL);
+
+         split_all_insns (1);
 
-      schedule_insns (dump_file);
+         schedule_insns ();
+       }
+      /* We must split jmp insn in PIC case.  */
+      else if (flag_pic)
+       split_all_insns_noflow ();
     }
 
   sh_reorg ();
 
   if (optimize > 0 && flag_delayed_branch)
-    {
-      if (! cfun->cfg)
-       {
-         init_flow ();
-         find_basic_blocks (insns);
-       }
-      dbr_schedule (insns, dump_file);
-    }
+    dbr_schedule (insns);
+
   shorten_branches (insns);
   final_start_function (insns, file, 1);
   final (insns, file, 1);
   final_end_function ();
 
-  if (optimize > 0 && flag_schedule_insns_after_reload)
+  if (optimize > 0)
     {
       /* Release all memory allocated by flow.  */
       free_basic_block_vars ();
@@ -10413,7 +9947,7 @@ sh_get_pr_initial_val (void)
       && ((current_function_args_info.call_cookie
           & ~ CALL_COOKIE_RET_TRAMP (1))
          || current_function_has_nonlocal_label))
-    return gen_rtx_MEM (SImode, return_address_pointer_rtx);
+    return gen_frame_mem (SImode, return_address_pointer_rtx);
 
   /* If we haven't finished rtl generation, there might be a nonlocal label
      that we haven't seen yet.
@@ -10508,27 +10042,6 @@ check_use_sfunc_addr (rtx insn, rtx reg)
   gcc_unreachable ();
 }
 
-/* Returns 1 if OP is a MEM that can be source of a simple move operation.  */
-
-int
-unaligned_load_operand (rtx op, enum machine_mode mode)
-{
-  rtx inside;
-
-  if (GET_CODE (op) != MEM || GET_MODE (op) != mode)
-    return 0;
-
-  inside = XEXP (op, 0);
-
-  if (GET_CODE (inside) == POST_INC)
-    inside = XEXP (inside, 0);
-
-  if (GET_CODE (inside) == REG)
-    return 1;
-
-  return 0;
-}
-
 /* This function returns a constant rtx that represents pi / 2**15 in
    SFmode.  it's used to scale SFmode angles, in radians, to a
    fixed-point signed 16.16-bit fraction of a full circle, i.e., 2*pi
@@ -10649,7 +10162,7 @@ sh_init_cumulative_args (CUMULATIVE_ARGS *  pcum,
             the TYPE or the FNDECL available so we synthesize the
             contents of that function as best we can.  */
          pcum->force_mem =
-           (TARGET_DEFAULT & HITACHI_BIT)
+           (TARGET_DEFAULT & MASK_HITACHI)
            && (mode == BLKmode
                || (GET_MODE_SIZE (mode) > 4
                    && !(mode == DFmode
@@ -10804,10 +10317,10 @@ sh_adjust_unroll_max (struct loop * loop, int insn_count,
                          if (TREE_CODE (type) != ARRAY_TYPE
                              || ! TYPE_SIZE (type) || ! TYPE_SIZE_UNIT (type))
                            break;
-                         size_tree = fold (build (TRUNC_DIV_EXPR,
+                         size_tree = fold_build2 (TRUNC_DIV_EXPR,
                                                   bitsizetype,
                                                   TYPE_SIZE (type),
-                                                  TYPE_SIZE_UNIT (type)));
+                                                  TYPE_SIZE_UNIT (type));
                          if (TREE_CODE (size_tree) == INTEGER_CST
                              && ! TREE_INT_CST_HIGH (size_tree)
                              && TREE_INT_CST_LOW  (size_tree) < max_iterations)
@@ -11145,7 +10658,7 @@ sh_contains_memref_p_1 (rtx *loc, void *data ATTRIBUTE_UNUSED)
   return (GET_CODE (*loc) == MEM);
 }
 
-/* Return non-zero iff INSN contains a MEM.  */
+/* Return nonzero iff INSN contains a MEM.  */
 int
 sh_contains_memref_p (rtx insn)
 {
@@ -11200,11 +10713,106 @@ shmedia_prepare_call_address (rtx fnaddr, int is_sibcall)
   return fnaddr;
 }
 
-const char *sh_multcost_str = "";
-const char *sh_gettrcost_str = "";
-const char *sh_div_str = "";
-const char *sh_divsi3_libfunc = "";
-const char *cut2_workaround_str = "";
+enum reg_class
+sh_secondary_reload (bool in_p, rtx x, enum reg_class class,
+                    enum machine_mode mode, secondary_reload_info *sri)
+{
+  if (in_p)
+    {
+      if (REGCLASS_HAS_FP_REG (class)
+         && ! TARGET_SHMEDIA
+         && immediate_operand ((x), mode)
+         && ! ((fp_zero_operand (x) || fp_one_operand (x))
+               && mode == SFmode && fldi_ok ()))
+       switch (mode)
+         {
+         case SFmode:
+           sri->icode = CODE_FOR_reload_insf__frn;
+           return NO_REGS;
+         case DFmode:
+           sri->icode = CODE_FOR_reload_indf__frn;
+           return NO_REGS;
+         case SImode:
+           /* ??? If we knew that we are in the appropriate mode -
+              single precision - we could use a reload pattern directly.  */
+           return FPUL_REGS;
+         default:
+           abort ();
+         }
+      if (class == FPUL_REGS
+          && ((GET_CODE (x) == REG
+               && (REGNO (x) == MACL_REG || REGNO (x) == MACH_REG
+                   || REGNO (x) == T_REG))
+              || GET_CODE (x) == PLUS))
+        return GENERAL_REGS;
+      if (class == FPUL_REGS && immediate_operand (x, mode))
+       {
+         if (GET_CODE (x) == CONST_INT && CONST_OK_FOR_I08 (INTVAL (x)))
+           return GENERAL_REGS;
+         sri->icode = CODE_FOR_reload_insi__i_fpul;
+         return NO_REGS;
+       }
+      if (class == FPSCR_REGS
+          && ((GET_CODE (x) == REG && REGNO (x) >= FIRST_PSEUDO_REGISTER)
+              || (GET_CODE (x) == MEM && GET_CODE (XEXP (x, 0)) == PLUS)))
+        return GENERAL_REGS;
+      if (REGCLASS_HAS_FP_REG (class)
+          && TARGET_SHMEDIA
+          && immediate_operand (x, mode)
+          && x != CONST0_RTX (GET_MODE (x))
+          && GET_MODE (x) != V4SFmode)
+        return GENERAL_REGS;
+      if ((mode == QImode || mode == HImode)
+          && TARGET_SHMEDIA && inqhi_operand (x, mode))
+       {
+         sri->icode = ((mode == QImode)
+                       ? CODE_FOR_reload_inqi : CODE_FOR_reload_inhi);
+         return NO_REGS;
+       }
+      if (TARGET_SHMEDIA && class == GENERAL_REGS
+          && (GET_CODE (x) == LABEL_REF || PIC_DIRECT_ADDR_P (x)))
+        return TARGET_REGS;
+    } /* end of input-only processing.  */
+
+  if (((REGCLASS_HAS_FP_REG (class)
+       && (GET_CODE (x) == REG
+           && (GENERAL_OR_AP_REGISTER_P (REGNO (x))
+               || (FP_REGISTER_P (REGNO (x)) && mode == SImode
+                   && TARGET_FMOVD))))
+       || (REGCLASS_HAS_GENERAL_REG (class)
+          && GET_CODE (x) == REG
+          && FP_REGISTER_P (REGNO (x))))
+      && ! TARGET_SHMEDIA
+      && (mode == SFmode || mode == SImode))
+    return FPUL_REGS;
+  if ((class == FPUL_REGS
+       || (REGCLASS_HAS_FP_REG (class)
+           && ! TARGET_SHMEDIA && mode == SImode))
+      && (GET_CODE (x) == MEM
+          || (GET_CODE (x) == REG
+              && (REGNO (x) >= FIRST_PSEUDO_REGISTER
+                  || REGNO (x) == T_REG
+                  || system_reg_operand (x, VOIDmode)))))
+    {
+      if (class == FPUL_REGS)
+       return GENERAL_REGS;
+      return FPUL_REGS;
+    }
+  if ((class == TARGET_REGS
+       || (TARGET_SHMEDIA && class == SIBCALL_REGS))
+      && !EXTRA_CONSTRAINT_Csy (x)
+      && (GET_CODE (x) != REG || ! GENERAL_REGISTER_P (REGNO (x))))
+    return GENERAL_REGS;
+  if ((class == MAC_REGS || class == PR_REGS)
+      && GET_CODE (x) == REG && ! GENERAL_REGISTER_P (REGNO (x))
+      && class != REGNO_REG_CLASS (REGNO (x)))
+    return GENERAL_REGS;
+  if (class != GENERAL_REGS && GET_CODE (x) == REG
+      && TARGET_REGISTER_P (REGNO (x)))
+    return GENERAL_REGS;
+  return NO_REGS;
+}
+
 enum sh_divide_strategy_e sh_div_strategy = SH_DIV_STRATEGY_DEFAULT;
 
 /* This defines the storage for the variable part of a -mboard= option.