OSDN Git Service

* config/sh/sh.c (prepare_cbranch_operands): Use
[pf3gnuchains/gcc-fork.git] / gcc / config / sh / sh.c
index 4ca2d5c..cf6e1a7 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, 2006, 2007 Free Software Foundation, Inc.
+   2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
    Contributed by Steve Chamberlain (sac@cygnus.com).
    Improved by Jim Wilson (wilson@cygnus.com).
 
@@ -8,7 +8,7 @@ This file is part of GCC.
 
 GCC is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
+the Free Software Foundation; either version 3, or (at your option)
 any later version.
 
 GCC is distributed in the hope that it will be useful,
@@ -17,9 +17,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING.  If not, write to
-the Free Software Foundation, 51 Franklin Street, Fifth Floor,
-Boston, MA 02110-1301, USA.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 #include "config.h"
 #include "system.h"
@@ -52,7 +51,7 @@ Boston, MA 02110-1301, USA.  */
 #include "intl.h"
 #include "sched-int.h"
 #include "ggc.h"
-#include "tree-gimple.h"
+#include "gimple.h"
 #include "cfgloop.h"
 #include "alloc-pool.h"
 #include "tm-constrs.h"
@@ -70,6 +69,14 @@ int code_for_indirect_jump_scratch = CODE_FOR_indirect_jump_scratch;
 #define GEN_ADD3 (*(TARGET_SHMEDIA64 ? gen_adddi3 : gen_addsi3))
 #define GEN_SUB3 (*(TARGET_SHMEDIA64 ? gen_subdi3 : gen_subsi3))
 
+/* Used to simplify the logic below.  Find the attributes wherever
+   they may be.  */
+#define SH_ATTRIBUTES(decl) \
+  (TYPE_P (decl)) ? TYPE_ATTRIBUTES (decl) \
+                 : DECL_ATTRIBUTES (decl) \
+                 ? (DECL_ATTRIBUTES (decl)) \
+                 : TYPE_ATTRIBUTES (TREE_TYPE (decl))
+
 /* Set to 1 by expand_prologue() when the function is an interrupt handler.  */
 int current_function_interrupt;
 
@@ -182,11 +189,14 @@ static rtx push (int);
 static void pop (int);
 static void push_regs (HARD_REG_SET *, int);
 static int calc_live_regs (HARD_REG_SET *);
-static void mark_use (rtx, rtx *);
 static HOST_WIDE_INT rounded_frame_size (int);
 static rtx mark_constant_pool_use (rtx);
 const struct attribute_spec sh_attribute_table[];
 static tree sh_handle_interrupt_handler_attribute (tree *, tree, tree, int, bool *);
+static tree sh_handle_resbank_handler_attribute (tree *, tree,
+                                                tree, int, bool *);
+static tree sh2a_handle_function_vector_handler_attribute (tree *, tree,
+                                                          tree, int, bool *);
 static tree sh_handle_sp_switch_attribute (tree *, tree, tree, int, bool *);
 static tree sh_handle_trap_exit_attribute (tree *, tree, tree, int, bool *);
 static tree sh_handle_renesas_attribute (tree *, tree, tree, int, bool *);
@@ -216,7 +226,7 @@ static bool sh_function_ok_for_sibcall (tree, tree);
 static bool sh_cannot_modify_jumps_p (void);
 static int sh_target_reg_class (void);
 static bool sh_optimize_target_register_callee_saved (bool);
-static bool sh_ms_bitfield_layout_p (tree);
+static bool sh_ms_bitfield_layout_p (const_tree);
 
 static void sh_init_builtins (void);
 static void sh_media_init_builtins (void);
@@ -224,15 +234,15 @@ static rtx sh_expand_builtin (tree, rtx, rtx, enum machine_mode, int);
 static void sh_output_mi_thunk (FILE *, tree, HOST_WIDE_INT, HOST_WIDE_INT, tree);
 static void sh_file_start (void);
 static int flow_dependent_p (rtx, rtx);
-static void flow_dependent_p_1 (rtx, rtx, void *);
+static void flow_dependent_p_1 (rtx, const_rtx, void *);
 static int shiftcosts (rtx);
 static int andcosts (rtx);
 static int addsubcosts (rtx);
 static int multcosts (rtx);
 static bool unspec_caller_rtx_p (rtx);
 static bool sh_cannot_copy_insn_p (rtx);
-static bool sh_rtx_costs (rtx, int, int, int *);
-static int sh_address_cost (rtx);
+static bool sh_rtx_costs (rtx, int, int, int *, bool);
+static int sh_address_cost (rtx, bool);
 static int sh_pr_n_sets (void);
 static rtx sh_allocate_initial_value (rtx);
 static int shmedia_target_regs_stack_space (HARD_REG_SET *);
@@ -244,20 +254,24 @@ static struct save_entry_s *sh5_schedule_saves (HARD_REG_SET *,
                                                struct save_schedule_s *, int);
 
 static rtx sh_struct_value_rtx (tree, int);
-static bool sh_return_in_memory (tree, tree);
+static bool sh_return_in_memory (const_tree, const_tree);
 static rtx sh_builtin_saveregs (void);
 static void sh_setup_incoming_varargs (CUMULATIVE_ARGS *, enum machine_mode, tree, int *, int);
 static bool sh_strict_argument_naming (CUMULATIVE_ARGS *);
 static bool sh_pretend_outgoing_varargs_named (CUMULATIVE_ARGS *);
 static tree sh_build_builtin_va_list (void);
-static tree sh_gimplify_va_arg_expr (tree, tree, tree *, tree *);
+static void sh_va_start (tree, rtx);
+static tree sh_gimplify_va_arg_expr (tree, tree, gimple_seq *, gimple_seq *);
 static bool sh_pass_by_reference (CUMULATIVE_ARGS *, enum machine_mode,
-                                 tree, bool);
+                                 const_tree, bool);
 static bool sh_callee_copies (CUMULATIVE_ARGS *, enum machine_mode,
-                             tree, bool);
+                             const_tree, bool);
 static int sh_arg_partial_bytes (CUMULATIVE_ARGS *, enum machine_mode,
                                 tree, bool);
-static int sh_dwarf_calling_convention (tree);
+static bool sh_scalar_mode_supported_p (enum machine_mode);
+static int sh_dwarf_calling_convention (const_tree);
+static void sh_encode_section_info (tree, rtx, int);
+static int sh2a_function_vector_p (tree);
 
 \f
 /* Initialize the GCC target structure.  */
@@ -283,7 +297,7 @@ static int sh_dwarf_calling_convention (tree);
 #define TARGET_ASM_OUTPUT_MI_THUNK sh_output_mi_thunk
 
 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
-#define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_tree_hwi_hwi_tree_true
+#define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_const_tree_hwi_hwi_const_tree_true
 
 #undef TARGET_ASM_FILE_START
 #define TARGET_ASM_FILE_START sh_file_start
@@ -391,6 +405,9 @@ static int sh_dwarf_calling_convention (tree);
 #undef TARGET_MACHINE_DEPENDENT_REORG
 #define TARGET_MACHINE_DEPENDENT_REORG sh_reorg
 
+#undef TARGET_DWARF_REGISTER_SPAN
+#define TARGET_DWARF_REGISTER_SPAN sh_dwarf_register_span
+
 #ifdef HAVE_AS_TLS
 #undef TARGET_HAVE_TLS
 #define TARGET_HAVE_TLS true
@@ -427,9 +444,13 @@ static int sh_dwarf_calling_convention (tree);
 
 #undef TARGET_BUILD_BUILTIN_VA_LIST
 #define TARGET_BUILD_BUILTIN_VA_LIST sh_build_builtin_va_list
+#undef TARGET_EXPAND_BUILTIN_VA_START
+#define TARGET_EXPAND_BUILTIN_VA_START sh_va_start
 #undef TARGET_GIMPLIFY_VA_ARG_EXPR
 #define TARGET_GIMPLIFY_VA_ARG_EXPR sh_gimplify_va_arg_expr
 
+#undef TARGET_SCALAR_MODE_SUPPORTED_P
+#define TARGET_SCALAR_MODE_SUPPORTED_P sh_scalar_mode_supported_p
 #undef TARGET_VECTOR_MODE_SUPPORTED_P
 #define TARGET_VECTOR_MODE_SUPPORTED_P sh_vector_mode_supported_p
 
@@ -445,6 +466,9 @@ static int sh_dwarf_calling_convention (tree);
 /* Return current register pressure for regmode.  */
 #define CURR_REGMODE_PRESSURE(MODE)    curr_regmode_pressure[((MODE) == SImode) ? 0 : 1]
 
+#undef  TARGET_ENCODE_SECTION_INFO
+#define TARGET_ENCODE_SECTION_INFO     sh_encode_section_info
+
 #ifdef SYMBIAN
 
 #undef  TARGET_ENCODE_SECTION_INFO
@@ -459,6 +483,9 @@ static int sh_dwarf_calling_convention (tree);
 #undef TARGET_SECONDARY_RELOAD
 #define TARGET_SECONDARY_RELOAD sh_secondary_reload
 
+/* Machine-specific symbol_ref flags.  */
+#define SYMBOL_FLAG_FUNCVEC_FUNCTION    (SYMBOL_FLAG_MACH_DEP << 0)
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
 /* Implement TARGET_HANDLE_OPTION.  */
@@ -657,6 +684,9 @@ print_operand_address (FILE *stream, rtx x)
    'd'  print a V2SF reg as dN instead of fpN.
    'm'  print a pair `base,offset' or `base,index', for LD and ST.
    'U'  Likewise for {LD,ST}{HI,LO}.
+   'V'  print the position of a single bit set.
+   'W'  print the position of a single bit cleared.
+   't'  print a memory address which is a register.
    'u'  prints the lowest 16 bits of CONST_INT, as an unsigned value.
    'o'  output an operator.  */
 
@@ -686,7 +716,11 @@ print_operand (FILE *stream, rtx x, int code)
        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");
+       {
+         if (sh_cfun_resbank_handler_p ())
+           fprintf (stream, "resbank\n");
+         fprintf (stream, "rte");
+       }
       else
        fprintf (stream, "rts");
       break;
@@ -792,6 +826,21 @@ print_operand (FILE *stream, rtx x, int code)
          break;
        }
       break;
+
+    case 't':
+      gcc_assert (GET_CODE (x) == MEM);
+      x = XEXP (x, 0);
+      switch (GET_CODE (x))
+       {
+       case REG:
+       case SUBREG:
+         print_operand (stream, x, 0);
+         break;
+       default:
+         break;
+       }
+      break;
+
     case 'o':
       switch (GET_CODE (x))
        {
@@ -859,6 +908,22 @@ print_operand (FILE *stream, rtx x, int code)
        }
       break;
 
+    case 'V':
+      {
+       int num = exact_log2 (INTVAL (x));
+       gcc_assert (num >= 0);
+       fprintf (stream, "#%d", num);
+      }
+      break;
+
+    case 'W':
+      {
+       int num = exact_log2 (~INTVAL (x));
+       gcc_assert (num >= 0);
+       fprintf (stream, "#%d", num);
+      }
+      break;
+
     case 'd':
       gcc_assert (GET_CODE (x) == REG && GET_MODE (x) == V2SFmode);
 
@@ -969,45 +1034,6 @@ print_operand (FILE *stream, rtx x, int code)
          output_address (XEXP (x, 0));
          break;
 
-       case CONST:
-         if (TARGET_SHMEDIA
-             && (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);
-                 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);
-               }
-             fputs (" & 65535)", stream);
-             break;
-           }
-
-         /* Fall through.  */
        default:
          if (TARGET_SH1)
            fputc ('#', stream);
@@ -1018,6 +1044,19 @@ print_operand (FILE *stream, rtx x, int code)
     }
 }
 \f
+
+/* Encode symbol attributes of a SYMBOL_REF into its
+   SYMBOL_REF_FLAGS.  */
+static void
+sh_encode_section_info (tree decl, rtx rtl, int first)
+{
+  default_encode_section_info (decl, rtl, first);
+
+  if (TREE_CODE (decl) == FUNCTION_DECL
+      && sh2a_function_vector_p (decl) && TARGET_SH2A)
+    SYMBOL_REF_FLAGS (XEXP (rtl, 0)) |= SYMBOL_FLAG_FUNCVEC_FUNCTION;
+}
+
 /* Like force_operand, but guarantees that VALUE ends up in TARGET.  */
 static void
 force_into (rtx value, rtx target)
@@ -1192,7 +1231,9 @@ prepare_move_operands (rtx operands[], enum machine_mode mode)
            /* It's ok.  */;
          else
            {
-             temp = no_new_pseudos ? operands[0] : gen_reg_rtx (Pmode);
+             temp = (!can_create_pseudo_p ()
+                     ? operands[0]
+                     : gen_reg_rtx (Pmode));
              operands[1] = legitimize_pic_address (operands[1], mode, temp);
            }
        }
@@ -1200,13 +1241,14 @@ prepare_move_operands (rtx operands[], enum machine_mode mode)
               && GET_CODE (XEXP (operands[1], 0)) == PLUS
               && SYMBOLIC_CONST_P (XEXP (XEXP (operands[1], 0), 0)))
        {
-         temp = no_new_pseudos ? operands[0] : gen_reg_rtx (Pmode);
+         temp = !can_create_pseudo_p () ? operands[0] : gen_reg_rtx (Pmode);
          temp = legitimize_pic_address (XEXP (XEXP (operands[1], 0), 0),
                                         mode, temp);
          operands[1] = expand_binop (mode, add_optab, temp,
                                      XEXP (XEXP (operands[1], 0), 1),
-                                     no_new_pseudos ? temp
-                                     : gen_reg_rtx (Pmode),
+                                     (!can_create_pseudo_p ()
+                                      ? temp
+                                      : gen_reg_rtx (Pmode)),
                                      0, OPTAB_LIB_WIDEN);
        }
     }
@@ -1222,9 +1264,9 @@ prepare_move_operands (rtx operands[], enum machine_mode mode)
        {
          /* This is like change_address_1 (operands[0], mode, 0, 1) ,
             except that we can't use that function because it is static.  */
-         rtx new = change_address (operands[0], mode, 0);
-         MEM_COPY_ATTRIBUTES (new, operands[0]);
-         operands[0] = new;
+         rtx new_rtx = change_address (operands[0], mode, 0);
+         MEM_COPY_ATTRIBUTES (new_rtx, operands[0]);
+         operands[0] = new_rtx;
        }
 
       /* This case can happen while generating code to move the result
@@ -1293,12 +1335,11 @@ prepare_move_operands (rtx operands[], enum machine_mode mode)
                  if (flag_schedule_insns)
                    emit_insn (gen_blockage ());
                  emit_insn (gen_GOTaddr2picreg ());
-                 emit_insn (gen_rtx_USE (VOIDmode, gen_rtx_REG (SImode,
-                                                                PIC_REG)));
+                 emit_use (gen_rtx_REG (SImode, PIC_REG));
                  if (flag_schedule_insns)
                    emit_insn (gen_blockage ());
                }
-             tga_op1 = no_new_pseudos ? op0 : gen_reg_rtx (Pmode);
+             tga_op1 = !can_create_pseudo_p () ? op0 : gen_reg_rtx (Pmode);
              tmp = gen_sym2GOTTPOFF (op1);
              emit_insn (gen_tls_initial_exec (tga_op1, tmp));
              op1 = tga_op1;
@@ -1337,7 +1378,7 @@ prepare_cbranch_operands (rtx *operands, enum machine_mode mode,
   rtx op1;
   rtx scratch = NULL_RTX;
 
-  if (comparison == CODE_FOR_nothing)
+  if (comparison == LAST_AND_UNUSED_RTX_CODE)
     comparison = GET_CODE (operands[0]);
   else
     scratch = operands[4];
@@ -1389,7 +1430,7 @@ prepare_cbranch_operands (rtx *operands, enum machine_mode mode,
        }
     }
   op1 = operands[1];
-  if (!no_new_pseudos)
+  if (can_create_pseudo_p ())
     operands[1] = force_reg (mode, op1);
   /* When we are handling DImode comparisons, we want to keep constants so
      that we can optimize the component comparisons; however, memory loads
@@ -1412,7 +1453,7 @@ prepare_cbranch_operands (rtx *operands, enum machine_mode mode,
          emit_move_insn (scratch, operands[2]);
          operands[2] = scratch;
        }
-      else if (!no_new_pseudos)
+      else if (can_create_pseudo_p ())
        operands[2] = force_reg (mode, operands[2]);
     }
   return comparison;
@@ -1437,9 +1478,7 @@ expand_cbranchsi4 (rtx *operands, enum rtx_code comparison, int probability)
                                           operands[1], operands[2])));
   jump = emit_jump_insn (branch_expander (operands[3]));
   if (probability >= 0)
-    REG_NOTES (jump)
-      = gen_rtx_EXPR_LIST (REG_BR_PROB, GEN_INT (probability),
-                           REG_NOTES (jump));
+    add_reg_note (jump, REG_BR_PROB, GEN_INT (probability));
 
 }
 
@@ -1477,7 +1516,7 @@ expand_cbranchdi4 (rtx *operands, enum rtx_code comparison)
   op2h = gen_highpart_mode (SImode, DImode, operands[2]);
   op1l = gen_lowpart (SImode, operands[1]);
   op2l = gen_lowpart (SImode, operands[2]);
-  msw_taken = msw_skip = lsw_taken = CODE_FOR_nothing;
+  msw_taken = msw_skip = lsw_taken = LAST_AND_UNUSED_RTX_CODE;
   prob = split_branch_probability;
   rev_prob = REG_BR_PROB_BASE - prob;
   switch (comparison)
@@ -1568,9 +1607,9 @@ expand_cbranchdi4 (rtx *operands, enum rtx_code comparison)
       break;
     default: return false;
     }
-  num_branches = ((msw_taken != CODE_FOR_nothing)
-                 + (msw_skip != CODE_FOR_nothing)
-                 + (lsw_taken != CODE_FOR_nothing));
+  num_branches = ((msw_taken != LAST_AND_UNUSED_RTX_CODE)
+                 + (msw_skip != LAST_AND_UNUSED_RTX_CODE)
+                 + (lsw_taken != LAST_AND_UNUSED_RTX_CODE));
   if (comparison != EQ && comparison != NE && num_branches > 1)
     {
       if (!CONSTANT_P (operands[2])
@@ -1596,31 +1635,40 @@ expand_cbranchdi4 (rtx *operands, enum rtx_code comparison)
   operands[4] = NULL_RTX;
   if (reload_completed
       && ! arith_reg_or_0_operand (op2h, SImode) && true_regnum (op1h)
-      && (msw_taken != CODE_FOR_nothing || msw_skip != CODE_FOR_nothing))
+      && (msw_taken != LAST_AND_UNUSED_RTX_CODE
+         || msw_skip != LAST_AND_UNUSED_RTX_CODE))
     {
       emit_move_insn (scratch, operands[2]);
       operands[2] = scratch;
     }
-  if (msw_taken != CODE_FOR_nothing)
+  if (msw_taken != LAST_AND_UNUSED_RTX_CODE)
     expand_cbranchsi4 (operands, msw_taken, msw_taken_prob);
-  if (msw_skip != CODE_FOR_nothing)
+  if (msw_skip != LAST_AND_UNUSED_RTX_CODE)
     {
       rtx taken_label = operands[3];
 
+      /* Operands were possibly modified, but msw_skip doesn't expect this.
+        Always use the original ones.  */
+      if (msw_taken != LAST_AND_UNUSED_RTX_CODE)
+       {
+         operands[1] = op1h;
+         operands[2] = op2h;
+       }
+
       operands[3] = skip_label = gen_label_rtx ();
       expand_cbranchsi4 (operands, msw_skip, msw_skip_prob);
       operands[3] = taken_label;
     }
   operands[1] = op1l;
   operands[2] = op2l;
-  if (lsw_taken != CODE_FOR_nothing)
+  if (lsw_taken != LAST_AND_UNUSED_RTX_CODE)
     {
       if (reload_completed
          && ! arith_reg_or_0_operand (op2l, SImode) && true_regnum (op1l))
        operands[4] = scratch;
       expand_cbranchsi4 (operands, lsw_taken, lsw_taken_prob);
     }
-  if (msw_skip != CODE_FOR_nothing)
+  if (msw_skip != LAST_AND_UNUSED_RTX_CODE)
     emit_label (skip_label);
   return true;
 }
@@ -1717,7 +1765,7 @@ from_compare (rtx *operands, int code)
   else
     insn = gen_rtx_SET (VOIDmode,
                        gen_rtx_REG (SImode, T_REG),
-                       gen_rtx_fmt_ee (code, SImode,
+                       gen_rtx_fmt_ee ((enum rtx_code) code, SImode,
                                        sh_compare_op0, sh_compare_op1));
   if ((TARGET_SH4 || TARGET_SH2A) && GET_MODE_CLASS (mode) == MODE_FLOAT)
     {
@@ -1830,14 +1878,14 @@ print_slot (rtx insn)
 const char *
 output_far_jump (rtx insn, rtx op)
 {
-  struct { rtx lab, reg, op; } this;
+  struct { rtx lab, reg, op; } this_jmp;
   rtx braf_base_lab = NULL_RTX;
   const char *jump;
   int far;
   int offset = branch_dest (insn) - INSN_ADDRESSES (INSN_UID (insn));
   rtx prev;
 
-  this.lab = gen_label_rtx ();
+  this_jmp.lab = gen_label_rtx ();
 
   if (TARGET_SH2
       && offset >= -32764
@@ -1863,10 +1911,10 @@ output_far_jump (rtx insn, rtx op)
   if (GET_CODE ((prev = prev_nonnote_insn (insn))) == INSN
       && INSN_CODE (prev) == CODE_FOR_indirect_jump_scratch)
     {
-      this.reg = SET_DEST (XVECEXP (PATTERN (prev), 0, 0));
-      if (REGNO (this.reg) == R0_REG && flag_pic && ! TARGET_SH2)
+      this_jmp.reg = SET_DEST (XVECEXP (PATTERN (prev), 0, 0));
+      if (REGNO (this_jmp.reg) == R0_REG && flag_pic && ! TARGET_SH2)
        jump = "mov.l   r1,@-r15; mova  %O0,r0; mov.l   @r0,r1; add     r1,r0; mov.l    @r15+,r1; jmp   @%1";
-      output_asm_insn (jump, &this.lab);
+      output_asm_insn (jump, &this_jmp.lab);
       if (dbr_sequence_length ())
        print_slot (final_sequence);
       else
@@ -1878,7 +1926,7 @@ output_far_jump (rtx insn, rtx op)
       if (dbr_sequence_length ())
        print_slot (final_sequence);
 
-      this.reg = gen_rtx_REG (SImode, 13);
+      this_jmp.reg = gen_rtx_REG (SImode, 13);
       /* We must keep the stack aligned to 8-byte boundaries on SH5.
         Fortunately, MACL is fixed and call-clobbered, and we never
         need its value across jumps, so save r13 in it instead of in
@@ -1887,7 +1935,7 @@ output_far_jump (rtx insn, rtx op)
        output_asm_insn ("lds   r13, macl", 0);
       else
        output_asm_insn ("mov.l r13,@-r15", 0);
-      output_asm_insn (jump, &this.lab);
+      output_asm_insn (jump, &this_jmp.lab);
       if (TARGET_SH5)
        output_asm_insn ("sts   macl, r13", 0);
       else
@@ -1901,16 +1949,16 @@ output_far_jump (rtx insn, rtx op)
     }
   if (far)
     output_asm_insn (".align   2", 0);
-  (*targetm.asm_out.internal_label) (asm_out_file, "L", CODE_LABEL_NUMBER (this.lab));
-  this.op = op;
+  (*targetm.asm_out.internal_label) (asm_out_file, "L", CODE_LABEL_NUMBER (this_jmp.lab));
+  this_jmp.op = op;
   if (far && flag_pic)
     {
       if (TARGET_SH2)
-       this.lab = braf_base_lab;
-      output_asm_insn (".long  %O2-%O0", &this.lab);
+       this_jmp.lab = braf_base_lab;
+      output_asm_insn (".long  %O2-%O0", &this_jmp.lab);
     }
   else
-    output_asm_insn (far ? ".long      %O2" : ".word %O2-%O0", &this.lab);
+    output_asm_insn (far ? ".long      %O2" : ".word %O2-%O0", &this_jmp.lab);
   return "";
 }
 
@@ -2007,14 +2055,14 @@ output_branch (int logic, rtx insn, rtx *operands)
     }
 }
 
-/* Output a code sequence for INSN using TEMPLATE with OPERANDS; but before,
+/* Output a code sequence for INSN using TEMPL with OPERANDS; but before,
    fill in operands 9 as a label to the successor insn.
    We try to use jump threading where possible.
    IF CODE matches the comparison in the IF_THEN_ELSE of a following jump,
    we assume the jump is taken.  I.e. EQ means follow jmp and bf, NE means
    follow jmp and bt, if the address is in range.  */
 const char *
-output_branchy_insn (enum rtx_code code, const char *template,
+output_branchy_insn (enum rtx_code code, const char *templ,
                     rtx insn, rtx *operands)
 {
   rtx next_insn = NEXT_INSN (insn);
@@ -2030,7 +2078,7 @@ output_branchy_insn (enum rtx_code code, const char *template,
          INSN_ADDRESSES_NEW (operands[9],
                              INSN_ADDRESSES (INSN_UID (next_insn))
                              + get_attr_length (next_insn));
-         return template;
+         return templ;
        }
       else
        {
@@ -2042,7 +2090,7 @@ output_branchy_insn (enum rtx_code code, const char *template,
                /* branch_true */
                src = XEXP (src, 1);
              operands[9] = src;
-             return template;
+             return templ;
            }
        }
     }
@@ -2051,7 +2099,7 @@ output_branchy_insn (enum rtx_code code, const char *template,
   INSN_ADDRESSES_NEW (operands[9],
                      INSN_ADDRESSES (INSN_UID (insn))
                      + get_attr_length (insn));
-  return template;
+  return templ;
 }
 
 const char *
@@ -2106,22 +2154,18 @@ sh_file_start (void)
 static bool
 unspec_caller_rtx_p (rtx pat)
 {
-  switch (GET_CODE (pat))
+  rtx base, offset;
+  int i;
+
+  split_const (pat, &base, &offset);
+  if (GET_CODE (base) == UNSPEC)
     {
-    case CONST:
-      return unspec_caller_rtx_p (XEXP (pat, 0));
-    case PLUS:
-    case MINUS:
-      if (unspec_caller_rtx_p (XEXP (pat, 0)))
+      if (XINT (base, 1) == UNSPEC_CALLER)
        return true;
-      return unspec_caller_rtx_p (XEXP (pat, 1));
-    case UNSPEC:
-      if (XINT (pat, 1) == UNSPEC_CALLER)
-       return true;
-    default:
-      break;
+      for (i = 0; i < XVECLEN (base, 0); i++)
+       if (unspec_caller_rtx_p (XVECEXP (base, 0, i)))
+         return true;
     }
-
   return false;
 }
 
@@ -2276,7 +2320,7 @@ andcosts (rtx x)
          || satisfies_constraint_J16 (XEXP (x, 1)))
        return 1;
       else
-       return 1 + rtx_cost (XEXP (x, 1), AND);
+       return 1 + rtx_cost (XEXP (x, 1), AND, !optimize_size);
     }
 
   /* These constants are single cycle extu.[bw] instructions.  */
@@ -2376,7 +2420,8 @@ multcosts (rtx x ATTRIBUTE_UNUSED)
    scanned.  In either case, *TOTAL contains the cost result.  */
 
 static bool
-sh_rtx_costs (rtx x, int code, int outer_code, int *total)
+sh_rtx_costs (rtx x, int code, int outer_code, int *total,
+             bool speed ATTRIBUTE_UNUSED)
 {
   switch (code)
     {
@@ -2407,7 +2452,7 @@ sh_rtx_costs (rtx x, int code, int outer_code, int *total)
               && CONST_OK_FOR_K08 (INTVAL (x)))
         *total = 1;
       /* prepare_cmp_insn will force costly constants int registers before
-        the cbrach[sd]i4 patterns can see them, so preserve potentially
+        the cbranch[sd]i4 patterns can see them, so preserve potentially
         interesting ones not covered by I08 above.  */
       else if (outer_code == COMPARE
               && ((unsigned HOST_WIDE_INT) INTVAL (x)
@@ -2434,7 +2479,7 @@ sh_rtx_costs (rtx x, int code, int outer_code, int *total)
       if (TARGET_SHMEDIA)
         *total = COSTS_N_INSNS (4);
       /* prepare_cmp_insn will force costly constants int registers before
-        the cbrachdi4 pattern can see them, so preserve potentially
+        the cbranchdi4 pattern can see them, so preserve potentially
         interesting ones.  */
       else if (outer_code == COMPARE && GET_MODE (x) == DImode)
         *total = 1;
@@ -2502,7 +2547,8 @@ sh_rtx_costs (rtx x, int code, int outer_code, int *total)
    since it increases pressure on r0.  */
 
 static int
-sh_address_cost (rtx X)
+sh_address_cost (rtx X,
+                bool speed ATTRIBUTE_UNUSED)
 {
   return (GET_CODE (X) == PLUS
          && ! CONSTANT_P (XEXP (X, 1))
@@ -3398,7 +3444,7 @@ static rtx
 add_constant (rtx x, enum machine_mode mode, rtx last_value)
 {
   int i;
-  rtx lab, new;
+  rtx lab, new_rtx;
   label_ref_list_t ref, newref;
 
   /* First see if we've already got it.  */
@@ -3414,14 +3460,14 @@ add_constant (rtx x, enum machine_mode mode, rtx last_value)
            }
          if (rtx_equal_p (x, pool_vector[i].value))
            {
-             lab = new = 0;
+             lab = new_rtx = 0;
              if (! last_value
                  || ! i
                  || ! rtx_equal_p (last_value, pool_vector[i-1].value))
                {
-                 new = gen_label_rtx ();
-                 LABEL_REFS (new) = pool_vector[i].label;
-                 pool_vector[i].label = lab = new;
+                 new_rtx = gen_label_rtx ();
+                 LABEL_REFS (new_rtx) = pool_vector[i].label;
+                 pool_vector[i].label = lab = new_rtx;
                }
              if (lab && pool_window_label)
                {
@@ -3431,8 +3477,8 @@ add_constant (rtx x, enum machine_mode mode, rtx last_value)
                  newref->next = ref;
                  pool_vector[pool_window_last].wend = newref;
                }
-             if (new)
-               pool_window_label = new;
+             if (new_rtx)
+               pool_window_label = new_rtx;
              pool_window_last = i;
              return lab;
            }
@@ -3709,7 +3755,8 @@ broken_move (rtx insn)
                && FP_REGISTER_P (REGNO (SET_DEST (pat))))
          && ! (TARGET_SH2A
                && GET_MODE (SET_DEST (pat)) == SImode
-               && satisfies_constraint_I20 (SET_SRC (pat)))
+               && (satisfies_constraint_I20 (SET_SRC (pat))
+                  || satisfies_constraint_I28 (SET_SRC (pat))))
          && ! satisfies_constraint_I08 (SET_SRC (pat)))
        return 1;
     }
@@ -3742,7 +3789,7 @@ fixup_mova (rtx mova)
     {
       rtx worker = mova;
       rtx lab = gen_label_rtx ();
-      rtx wpat, wpat0, wpat1, wsrc, diff;
+      rtx wpat, wpat0, wpat1, wsrc, target, base, diff;
 
       do
        {
@@ -3761,9 +3808,9 @@ fixup_mova (rtx mova)
                           XEXP (XVECEXP (wsrc, 0, 2), 0), lab,
                           XEXP (wpat1, 0)));
       INSN_CODE (worker) = -1;
-      diff = gen_rtx_MINUS (Pmode, XVECEXP (SET_SRC (PATTERN (mova)), 0, 0),
-                           gen_rtx_LABEL_REF (Pmode, lab));
-      diff = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, diff), UNSPEC_PIC);
+      target = XVECEXP (SET_SRC (PATTERN (mova)), 0, 0);
+      base = gen_rtx_LABEL_REF (Pmode, lab);
+      diff = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, target, base), UNSPEC_SYMOFF);
       SET_SRC (PATTERN (mova)) = gen_rtx_CONST (Pmode, diff);
       INSN_CODE (mova) = -1;
     }
@@ -3781,6 +3828,10 @@ untangle_mova (int *num_mova, rtx *first_mova, rtx new_mova)
 
   if (optimize)
     {
+      /* If NEW_MOVA has no address yet, it will be handled later.  */
+      if (INSN_ADDRESSES_SIZE() <= (unsigned) INSN_UID (new_mova))
+       return -1;
+
       n_addr = INSN_ADDRESSES (INSN_UID (new_mova));
       n_target = INSN_ADDRESSES (INSN_UID (XEXP (MOVA_LABELREF (new_mova), 0)));
       if (n_addr > n_target || n_addr + 1022 < n_target)
@@ -3834,6 +3885,7 @@ find_barrier (int num_mova, rtx mova, rtx from)
   rtx barrier_before_mova = 0, found_barrier = 0, good_barrier = 0;
   int si_limit;
   int hi_limit;
+  rtx orig = from;
 
   /* For HImode: range is 510, add 4 because pc counts from address of
      second instruction after this one, subtract 2 for the jump instruction
@@ -3893,6 +3945,7 @@ find_barrier (int num_mova, rtx mova, rtx from)
 
       if (GET_CODE (from) == BARRIER)
        {
+         rtx next;
 
          found_barrier = from;
 
@@ -3901,6 +3954,14 @@ find_barrier (int num_mova, rtx mova, rtx from)
             this kind of barrier.  */
          if (barrier_align (from) > 2)
            good_barrier = from;
+
+         /* If we are at the end of a hot/cold block, dump the constants
+            here.  */
+         next = NEXT_INSN (from);
+         if (next
+             && NOTE_P (next)
+             && NOTE_KIND (next) == NOTE_INSN_SWITCH_TEXT_SECTIONS)
+           break;
        }
 
       if (broken_move (from))
@@ -4057,7 +4118,8 @@ find_barrier (int num_mova, rtx mova, rtx from)
       /* If we exceeded the range, then we must back up over the last
         instruction we looked at.  Otherwise, we just need to undo the
         NEXT_INSN at the end of the loop.  */
-      if (count_hi > hi_limit || count_si > si_limit)
+      if (PREV_INSN (from) != orig
+         && (count_hi > hi_limit || count_si > si_limit))
        from = PREV_INSN (PREV_INSN (from));
       else
        from = PREV_INSN (from);
@@ -4324,7 +4386,7 @@ gen_block_redirect (rtx jump, int addr, int need_block)
       rtx scan;
       /* Don't look for the stack pointer as a scratch register,
         it would cause trouble if an interrupt occurred.  */
-      unsigned try = 0x7fff, used;
+      unsigned attempt = 0x7fff, used;
       int jump_left = flag_expensive_optimizations + 1;
 
       /* It is likely that the most recent eligible instruction is wanted for
@@ -4345,7 +4407,7 @@ gen_block_redirect (rtx jump, int addr, int need_block)
              && GET_CODE (PATTERN (scan)) != CLOBBER
              && get_attr_in_delay_slot (scan) == IN_DELAY_SLOT_YES)
            {
-             try &= ~regs_used (PATTERN (scan), 0);
+             attempt &= ~regs_used (PATTERN (scan), 0);
              break;
            }
        }
@@ -4363,9 +4425,9 @@ gen_block_redirect (rtx jump, int addr, int need_block)
              if (code == CALL_INSN)
                used |= regs_used (CALL_INSN_FUNCTION_USAGE (scan), 0);
              dead |= (used >> 16) & ~used;
-             if (dead & try)
+             if (dead & attempt)
                {
-                 dead &= try;
+                 dead &= attempt;
                  break;
                }
              if (code == JUMP_INSN)
@@ -4715,8 +4777,8 @@ sh_reorg (void)
   mdep_reorg_phase = SH_INSERT_USES_LABELS;
   if (TARGET_RELAX)
     {
-      /* Remove all REG_LABEL notes.  We want to use them for our own
-        purposes.  This works because none of the remaining passes
+      /* Remove all REG_LABEL_OPERAND notes.  We want to use them for our
+        own purposes.  This works because none of the remaining passes
         need to look at them.
 
         ??? But it may break in the future.  We should use a machine
@@ -4727,7 +4789,8 @@ sh_reorg (void)
            {
              rtx note;
 
-             while ((note = find_reg_note (insn, REG_LABEL, NULL_RTX)) != 0)
+             while ((note = find_reg_note (insn, REG_LABEL_OPERAND,
+                                           NULL_RTX)) != 0)
                remove_note (insn, note);
            }
        }
@@ -4878,17 +4941,15 @@ sh_reorg (void)
              continue;
            }
 
-         /* Create a code label, and put it in a REG_LABEL note on
-             the insn which sets the register, and on each call insn
-             which uses the register.  In final_prescan_insn we look
-             for the REG_LABEL notes, and output the appropriate label
+         /* Create a code label, and put it in a REG_LABEL_OPERAND note
+             on the insn which sets the register, and on each call insn
+             which uses the register.  In final_prescan_insn we look for
+             the REG_LABEL_OPERAND notes, and output the appropriate label
              or pseudo-op.  */
 
          label = gen_label_rtx ();
-         REG_NOTES (link) = gen_rtx_INSN_LIST (REG_LABEL, label,
-                                               REG_NOTES (link));
-         REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_LABEL, label,
-                                               REG_NOTES (insn));
+         add_reg_note (link, REG_LABEL_OPERAND, label);
+         add_reg_note (insn, REG_LABEL_OPERAND, label);
          if (rescan)
            {
              scan = link;
@@ -4902,8 +4963,7 @@ sh_reorg (void)
                           && reg_mentioned_p (reg, scan))
                          || ((reg2 = sfunc_uses_reg (scan))
                              && REGNO (reg2) == REGNO (reg))))
-                   REG_NOTES (scan)
-                     = gen_rtx_INSN_LIST (REG_LABEL, label, REG_NOTES (scan));
+                   add_reg_note (scan, REG_LABEL_OPERAND, label);
                }
              while (scan != dies);
            }
@@ -5263,7 +5323,7 @@ split_branches (rtx first)
                    bp->insert_place = insn;
                    bp->address = addr;
                  }
-               ok = redirect_jump (insn, label, 1);
+               ok = redirect_jump (insn, label, 0);
                gcc_assert (ok);
              }
            else
@@ -5404,7 +5464,7 @@ final_prescan_insn (rtx insn, rtx *opvec ATTRIBUTE_UNUSED,
     {
       rtx note;
 
-      note = find_reg_note (insn, REG_LABEL, NULL_RTX);
+      note = find_reg_note (insn, REG_LABEL_OPERAND, NULL_RTX);
       if (note)
        {
          rtx pattern;
@@ -5537,16 +5597,16 @@ output_stack_adjust (int size, rtx reg, int epilogue_p,
              if (epilogue_p > 0)
                {
                  int nreg = 0;
-                 if (current_function_return_rtx)
+                 if (crtl->return_rtx)
                    {
                      enum machine_mode mode;
-                     mode = GET_MODE (current_function_return_rtx);
+                     mode = GET_MODE (crtl->return_rtx);
                      if (BASE_RETURN_VALUE_REG (mode) == FIRST_RET_REG)
                        nreg = HARD_REGNO_NREGS (FIRST_RET_REG, mode);
                    }
                  for (i = 0; i < nreg; i++)
                    CLEAR_HARD_REG_BIT (temps, FIRST_RET_REG + i);
-                 if (current_function_calls_eh_return)
+                 if (crtl->calls_eh_return)
                    {
                      CLEAR_HARD_REG_BIT (temps, EH_RETURN_STACKADJ_REGNO);
                      for (i = 0; i <= 3; i++)
@@ -5623,8 +5683,8 @@ output_stack_adjust (int size, rtx reg, int epilogue_p,
              mem = gen_tmp_stack_mem (Pmode, gen_rtx_POST_INC (Pmode, reg));
              emit_move_insn (tmp_reg, mem);
              /* Tell flow the insns that pop r4/r5 aren't dead.  */
-             emit_insn (gen_rtx_USE (VOIDmode, tmp_reg));
-             emit_insn (gen_rtx_USE (VOIDmode, adj_reg));
+             emit_use (tmp_reg);
+             emit_use (adj_reg);
              return;
            }
          const_reg = gen_rtx_REG (GET_MODE (reg), temp);
@@ -5643,12 +5703,10 @@ output_stack_adjust (int size, rtx reg, int epilogue_p,
              insn = emit_fn (GEN_ADD3 (reg, reg, const_reg));
            }
          if (! epilogue_p)
-           REG_NOTES (insn)
-             = (gen_rtx_EXPR_LIST
-                (REG_FRAME_RELATED_EXPR,
-                 gen_rtx_SET (VOIDmode, reg,
-                              gen_rtx_PLUS (SImode, reg, GEN_INT (size))),
-                 REG_NOTES (insn)));
+           add_reg_note (insn, REG_FRAME_RELATED_EXPR,
+                         gen_rtx_SET (VOIDmode, reg,
+                                      gen_rtx_PLUS (SImode, reg,
+                                                    GEN_INT (size))));
        }
     }
 }
@@ -5684,9 +5742,7 @@ push (int rn)
     x = gen_push (gen_rtx_REG (SImode, rn));
 
   x = frame_insn (x);
-  REG_NOTES (x)
-    = gen_rtx_EXPR_LIST (REG_INC,
-                        gen_rtx_REG (SImode, STACK_POINTER_REGNUM), 0);
+  add_reg_note (x, REG_INC, gen_rtx_REG (SImode, STACK_POINTER_REGNUM));
   return x;
 }
 
@@ -5713,9 +5769,7 @@ pop (int rn)
     x = gen_pop (gen_rtx_REG (SImode, rn));
 
   x = emit_insn (x);
-  REG_NOTES (x)
-    = gen_rtx_EXPR_LIST (REG_INC,
-                        gen_rtx_REG (SImode, STACK_POINTER_REGNUM), 0);
+  add_reg_note (x, REG_INC, gen_rtx_REG (SImode, STACK_POINTER_REGNUM));
 }
 
 /* Generate code to push the regs specified in the mask.  */
@@ -5723,13 +5777,13 @@ pop (int rn)
 static void
 push_regs (HARD_REG_SET *mask, int interrupt_handler)
 {
-  int i;
+  int i = interrupt_handler ? LAST_BANKED_REG + 1 : 0;
   int skip_fpscr = 0;
 
   /* Push PR last; this gives better latencies after the prologue, and
      candidates for the return delay slot when there are no general
      registers pushed.  */
-  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+  for (; i < FIRST_PSEUDO_REGISTER; i++)
     {
       /* If this is an interrupt handler, and the SZ bit varies,
         and we have to push any floating point register, we need
@@ -5747,9 +5801,26 @@ push_regs (HARD_REG_SET *mask, int interrupt_handler)
       if (i != PR_REG
          && (i != FPSCR_REG || ! skip_fpscr)
          && TEST_HARD_REG_BIT (*mask, i))
+           {
+       /* If the ISR has RESBANK attribute assigned, don't push any of
+          the following registers - R0-R14, MACH, MACL and GBR.  */
+      if (! (sh_cfun_resbank_handler_p ()
+            && ((i >= FIRST_GENERAL_REG && i < LAST_GENERAL_REG)
+                || i == MACH_REG
+                || i == MACL_REG
+                || i == GBR_REG)))
+         push (i);
+       }
+    }
+
+  /* Push banked registers last to improve delay slot opportunities.  */
+  if (interrupt_handler)
+    for (i = FIRST_BANKED_REG; i <= LAST_BANKED_REG; i++)
+      if (TEST_HARD_REG_BIT (*mask, i))
        push (i);
-    }
-  if (TEST_HARD_REG_BIT (*mask, PR_REG))
+
+  /* Don't push PR register for an ISR with RESBANK attribute assigned.  */
+  if (TEST_HARD_REG_BIT (*mask, PR_REG) && !sh_cfun_resbank_handler_p ())
     push (PR_REG);
 }
 
@@ -5861,9 +5932,9 @@ calc_live_regs (HARD_REG_SET *live_regs_mask)
   /* Force PR to be live if the prologue has to call the SHmedia
      argument decoder or register saver.  */
   if (TARGET_SHCOMPACT
-      && ((current_function_args_info.call_cookie
+      && ((crtl->args.info.call_cookie
           & ~ CALL_COOKIE_RET_TRAMP (1))
-         || current_function_has_nonlocal_label))
+         || crtl->saves_all_registers))
     pr_live = 1;
   has_call = TARGET_SHMEDIA ? ! leaf_function_p () : pr_live;
   for (count = 0, reg = FIRST_PSEUDO_REGISTER; reg-- != 0; )
@@ -5888,12 +5959,14 @@ calc_live_regs (HARD_REG_SET *live_regs_mask)
          : (/* Only push those regs which are used and need to be saved.  */
             (TARGET_SHCOMPACT
              && flag_pic
-             && current_function_args_info.call_cookie
+             && crtl->args.info.call_cookie
              && reg == PIC_OFFSET_TABLE_REGNUM)
             || (df_regs_ever_live_p (reg)
-                && (!call_really_used_regs[reg]
+                && ((!call_really_used_regs[reg]
+                     && !(reg != PIC_OFFSET_TABLE_REGNUM
+                          && fixed_regs[reg] && call_used_regs[reg]))
                     || (trapa_handler && reg == FPSCR_REG && TARGET_FPU_ANY)))
-            || (current_function_calls_eh_return
+            || (crtl->calls_eh_return
                 && (reg == EH_RETURN_DATA_REGNO (0)
                     || reg == EH_RETURN_DATA_REGNO (1)
                     || reg == EH_RETURN_DATA_REGNO (2)
@@ -6043,7 +6116,7 @@ sh5_schedule_saves (HARD_REG_SET *live_regs_mask, save_schedule *schedule,
          && ! FUNCTION_ARG_REGNO_P (i)
          && i != FIRST_RET_REG
          && ! (cfun->static_chain_decl != NULL && i == STATIC_CHAIN_REGNUM)
-         && ! (current_function_calls_eh_return
+         && ! (crtl->calls_eh_return
                && (i == EH_RETURN_STACKADJ_REGNO
                    || ((unsigned) i >= EH_RETURN_DATA_REGNO (0)
                        && (unsigned) i <= EH_RETURN_DATA_REGNO (3)))))
@@ -6136,16 +6209,16 @@ sh_expand_prologue (void)
 
   /* We have pretend args if we had an object sent partially in registers
      and partially on the stack, e.g. a large structure.  */
-  pretend_args = current_function_pretend_args_size;
+  pretend_args = crtl->args.pretend_args_size;
   if (TARGET_VARARGS_PRETEND_ARGS (current_function_decl)
       && (NPARM_REGS(SImode)
-         > current_function_args_info.arg_count[(int) SH_ARG_INT]))
+         > crtl->args.info.arg_count[(int) SH_ARG_INT]))
     pretend_args = 0;
   output_stack_adjust (-pretend_args
-                      - current_function_args_info.stack_regs * 8,
+                      - crtl->args.info.stack_regs * 8,
                       stack_pointer_rtx, 0, NULL);
 
-  if (TARGET_SHCOMPACT && flag_pic && current_function_args_info.call_cookie)
+  if (TARGET_SHCOMPACT && flag_pic && crtl->args.info.call_cookie)
     /* We're going to use the PIC register to load the address of the
        incoming-argument decoder and/or of the return trampoline from
        the GOT, so make sure the PIC register is preserved and
@@ -6153,7 +6226,7 @@ sh_expand_prologue (void)
     df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
 
   if (TARGET_SHCOMPACT
-      && (current_function_args_info.call_cookie & ~ CALL_COOKIE_RET_TRAMP(1)))
+      && (crtl->args.info.call_cookie & ~ CALL_COOKIE_RET_TRAMP(1)))
     {
       int reg;
 
@@ -6161,20 +6234,20 @@ sh_expand_prologue (void)
         be pushed onto the stack live, so that register renaming
         doesn't overwrite them.  */
       for (reg = 0; reg < NPARM_REGS (SImode); reg++)
-       if (CALL_COOKIE_STACKSEQ_GET (current_function_args_info.call_cookie)
+       if (CALL_COOKIE_STACKSEQ_GET (crtl->args.info.call_cookie)
            >= NPARM_REGS (SImode) - reg)
          for (; reg < NPARM_REGS (SImode); reg++)
            emit_insn (gen_shcompact_preserve_incoming_args
                       (gen_rtx_REG (SImode, FIRST_PARM_REG + reg)));
        else if (CALL_COOKIE_INT_REG_GET
-                (current_function_args_info.call_cookie, reg) == 1)
+                (crtl->args.info.call_cookie, reg) == 1)
          emit_insn (gen_shcompact_preserve_incoming_args
                     (gen_rtx_REG (SImode, FIRST_PARM_REG + reg)));
 
       emit_move_insn (gen_rtx_REG (Pmode, MACL_REG),
                      stack_pointer_rtx);
       emit_move_insn (gen_rtx_REG (SImode, R0_REG),
-                     GEN_INT (current_function_args_info.call_cookie));
+                     GEN_INT (crtl->args.info.call_cookie));
       emit_move_insn (gen_rtx_REG (SImode, MACH_REG),
                      gen_rtx_REG (SImode, R0_REG));
     }
@@ -6188,7 +6261,7 @@ sh_expand_prologue (void)
     }
 
   /* Emit the code for SETUP_VARARGS.  */
-  if (current_function_stdarg)
+  if (cfun->stdarg)
     {
       if (TARGET_VARARGS_PRETEND_ARGS (current_function_decl))
        {
@@ -6199,11 +6272,10 @@ sh_expand_prologue (void)
              rtx insn;
 
              if (i >= (NPARM_REGS(SImode)
-                       - current_function_args_info.arg_count[(int) SH_ARG_INT]
+                       - crtl->args.info.arg_count[(int) SH_ARG_INT]
                        ))
                break;
              insn = push (rn);
-             RTX_FRAME_RELATED_P (insn) = 0;
            }
        }
     }
@@ -6402,27 +6474,23 @@ sh_expand_prologue (void)
               a direct save from the to-be-saved register.  */
            if (REGNO (reg_rtx) != reg)
              {
-               rtx set, note_rtx;
+               rtx set;
 
                set = gen_rtx_SET (VOIDmode, mem_rtx, orig_reg_rtx);
-               note_rtx = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, set,
-                                             REG_NOTES (insn));
-               REG_NOTES (insn) = note_rtx;
+               add_reg_note (insn, REG_FRAME_RELATED_EXPR, set);
              }
 
            if (TARGET_SHCOMPACT && (offset_in_r0 != -1))
              {
                rtx reg_rtx = gen_rtx_REG (mode, reg);
-               rtx set, note_rtx;
+               rtx set;
                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,
-                                             REG_NOTES (insn));
-               REG_NOTES (insn) = note_rtx;
+               add_reg_note (insn, REG_FRAME_RELATED_EXPR, set);
              }
          }
        }
@@ -6459,7 +6527,7 @@ sh_expand_prologue (void)
     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)))
+      && (crtl->args.info.call_cookie & ~ CALL_COOKIE_RET_TRAMP(1)))
     {
       /* This must NOT go through the PLT, otherwise mach and macl
         may be clobbered.  */
@@ -6675,14 +6743,33 @@ sh_expand_epilogue (bool sibcall_p)
     }
   else /* ! TARGET_SH5 */
     {
+      int last_reg;
+
       save_size = 0;
-      if (TEST_HARD_REG_BIT (live_regs_mask, PR_REG))
+       /* For an ISR with RESBANK attribute assigned, don't pop PR
+          register.  */
+      if (TEST_HARD_REG_BIT (live_regs_mask, PR_REG)
+         && !sh_cfun_resbank_handler_p ())     
        {
          if (!frame_pointer_needed)
            emit_insn (gen_blockage ());
          pop (PR_REG);
        }
-      for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+
+      /* Banked registers are poped first to avoid being scheduled in the
+        delay slot. RTE switches banks before the ds instruction.  */
+      if (current_function_interrupt)
+       {
+         for (i = FIRST_BANKED_REG; i <= LAST_BANKED_REG; i++)
+           if (TEST_HARD_REG_BIT (live_regs_mask, i)) 
+             pop (LAST_BANKED_REG - i);
+
+         last_reg = FIRST_PSEUDO_REGISTER - LAST_BANKED_REG - 1;
+       }
+      else
+       last_reg = FIRST_PSEUDO_REGISTER;
+
+      for (i = 0; i < last_reg; i++)
        {
          int j = (FIRST_PSEUDO_REGISTER - 1) - i;
 
@@ -6690,23 +6777,31 @@ sh_expand_epilogue (bool sibcall_p)
              && hard_reg_set_intersect_p (live_regs_mask,
                                          reg_class_contents[DF_REGS]))
            fpscr_deferred = 1;
-         else if (j != PR_REG && TEST_HARD_REG_BIT (live_regs_mask, j))
+         /* For an ISR with RESBANK attribute assigned, don't pop
+            following registers, R0-R14, MACH, MACL and GBR.  */
+         else if (j != PR_REG && TEST_HARD_REG_BIT (live_regs_mask, j) 
+                  && ! (sh_cfun_resbank_handler_p ()
+                        && ((j >= FIRST_GENERAL_REG
+                             && j < LAST_GENERAL_REG)
+                             || j == MACH_REG
+                             || j == MACL_REG
+                             || j == GBR_REG)))
            pop (j);
+
          if (j == FIRST_FP_REG && fpscr_deferred)
            pop (FPSCR_REG);
-
        }
     }
   if (target_flags != save_flags && ! current_function_interrupt)
     emit_insn (gen_toggle_sz ());
   target_flags = save_flags;
 
-  output_stack_adjust (current_function_pretend_args_size
+  output_stack_adjust (crtl->args.pretend_args_size
                       + save_size + d_rounding
-                      + current_function_args_info.stack_regs * 8,
+                      + crtl->args.info.stack_regs * 8,
                       stack_pointer_rtx, e, NULL);
 
-  if (current_function_calls_eh_return)
+  if (crtl->calls_eh_return)
     emit_insn (GEN_ADD3 (stack_pointer_rtx, stack_pointer_rtx,
                         EH_RETURN_STACKADJ_RTX));
 
@@ -6719,7 +6814,7 @@ sh_expand_epilogue (bool sibcall_p)
      USE PR_MEDIA_REG, since it will be explicitly copied to TR0_REG
      by the return pattern.  */
   if (TEST_HARD_REG_BIT (live_regs_mask, PR_REG))
-    emit_insn (gen_rtx_USE (VOIDmode, gen_rtx_REG (SImode, PR_REG)));
+    emit_use (gen_rtx_REG (SImode, PR_REG));
 }
 
 static int sh_need_epilogue_known = 0;
@@ -6773,7 +6868,7 @@ sh_set_return_address (rtx ra, rtx tmp)
 
       emit_insn (GEN_MOV (rr, ra));
       /* Tell flow the register for return isn't dead.  */
-      emit_insn (gen_rtx_USE (VOIDmode, rr));
+      emit_use (rr);
       return;
     }
 
@@ -6820,16 +6915,16 @@ static rtx
 sh_builtin_saveregs (void)
 {
   /* First unnamed integer register.  */
-  int first_intreg = current_function_args_info.arg_count[(int) SH_ARG_INT];
+  int first_intreg = crtl->args.info.arg_count[(int) SH_ARG_INT];
   /* Number of integer registers we need to save.  */
   int n_intregs = MAX (0, NPARM_REGS (SImode) - first_intreg);
   /* First unnamed SFmode float reg */
-  int first_floatreg = current_function_args_info.arg_count[(int) SH_ARG_FLOAT];
+  int first_floatreg = crtl->args.info.arg_count[(int) SH_ARG_FLOAT];
   /* Number of SFmode float regs to save.  */
   int n_floatregs = MAX (0, NPARM_REGS (SFmode) - first_floatreg);
   rtx regbuf, fpregs;
   int bufsize, regno;
-  HOST_WIDE_INT alias_set;
+  alias_set_type alias_set;
 
   if (TARGET_SH5)
     {
@@ -6839,25 +6934,25 @@ sh_builtin_saveregs (void)
 
          while (pushregs < NPARM_REGS (SImode) - 1
                 && (CALL_COOKIE_INT_REG_GET
-                       (current_function_args_info.call_cookie,
+                       (crtl->args.info.call_cookie,
                         NPARM_REGS (SImode) - pushregs)
                     == 1))
            {
-             current_function_args_info.call_cookie
+             crtl->args.info.call_cookie
                &= ~ CALL_COOKIE_INT_REG (NPARM_REGS (SImode)
                                          - pushregs, 1);
              pushregs++;
            }
 
          if (pushregs == NPARM_REGS (SImode))
-           current_function_args_info.call_cookie
+           crtl->args.info.call_cookie
              |= (CALL_COOKIE_INT_REG (0, 1)
                  | CALL_COOKIE_STACKSEQ (pushregs - 1));
          else
-           current_function_args_info.call_cookie
+           crtl->args.info.call_cookie
              |= CALL_COOKIE_STACKSEQ (pushregs);
 
-         current_function_pretend_args_size += 8 * n_intregs;
+         crtl->args.pretend_args_size += 8 * n_intregs;
        }
       if (TARGET_SHCOMPACT)
        return const0_rtx;
@@ -7009,7 +7104,7 @@ sh_build_builtin_va_list (void)
 
 /* Implement `va_start' for varargs and stdarg.  */
 
-void
+static void
 sh_va_start (tree valist, rtx nextarg)
 {
   tree f_next_o, f_next_o_limit, f_next_fp, f_next_fp_limit, f_next_stack;
@@ -7049,39 +7144,40 @@ sh_va_start (tree valist, rtx nextarg)
                       valist, f_next_stack, NULL_TREE);
 
   /* Call __builtin_saveregs.  */
-  u = make_tree (ptr_type_node, expand_builtin_saveregs ());
-  t = build2 (GIMPLE_MODIFY_STMT, ptr_type_node, next_fp, u);
+  u = make_tree (sizetype, expand_builtin_saveregs ());
+  u = fold_convert (ptr_type_node, u);
+  t = build2 (MODIFY_EXPR, ptr_type_node, next_fp, u);
   TREE_SIDE_EFFECTS (t) = 1;
   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
 
-  nfp = current_function_args_info.arg_count[SH_ARG_FLOAT];
+  nfp = crtl->args.info.arg_count[SH_ARG_FLOAT];
   if (nfp < 8)
     nfp = 8 - nfp;
   else
     nfp = 0;
-  u = fold_build2 (PLUS_EXPR, ptr_type_node, u,
-                  build_int_cst (NULL_TREE, UNITS_PER_WORD * nfp));
-  t = build2 (GIMPLE_MODIFY_STMT, ptr_type_node, next_fp_limit, u);
+  u = fold_build2 (POINTER_PLUS_EXPR, ptr_type_node, u,
+                  size_int (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 = build2 (GIMPLE_MODIFY_STMT, 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);
 
-  nint = current_function_args_info.arg_count[SH_ARG_INT];
+  nint = crtl->args.info.arg_count[SH_ARG_INT];
   if (nint < 4)
     nint = 4 - nint;
   else
     nint = 0;
-  u = fold_build2 (PLUS_EXPR, ptr_type_node, u,
-                  build_int_cst (NULL_TREE, UNITS_PER_WORD * nint));
-  t = build2 (GIMPLE_MODIFY_STMT, ptr_type_node, next_o_limit, u);
+  u = fold_build2 (POINTER_PLUS_EXPR, ptr_type_node, u,
+                  size_int (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 = build2 (GIMPLE_MODIFY_STMT, 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);
 }
@@ -7110,8 +7206,8 @@ find_sole_member (tree type)
 /* Implement `va_arg'.  */
 
 static tree
-sh_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p,
-                        tree *post_p ATTRIBUTE_UNUSED)
+sh_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p,
+                        gimple_seq *post_p ATTRIBUTE_UNUSED)
 {
   HOST_WIDE_INT size, rsize;
   tree tmp, pptr_type_node;
@@ -7176,7 +7272,7 @@ sh_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p,
            }
        }
 
-      if (TARGET_SH4)
+      if (TARGET_SH4 || TARGET_SH2A_DOUBLE)
        {
          pass_as_float = ((TREE_CODE (eff_type) == REAL_TYPE && size <= 8)
                           || (TREE_CODE (eff_type) == COMPLEX_TYPE
@@ -7200,32 +7296,31 @@ sh_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p,
          tree cmp;
          bool is_double = size == 8 && TREE_CODE (eff_type) == REAL_TYPE;
 
-         tmp = build1 (ADDR_EXPR, pptr_type_node, next_fp);
-         tmp = build2 (GIMPLE_MODIFY_STMT, void_type_node, addr, tmp);
-         gimplify_and_add (tmp, pre_p);
+         tmp = build1 (ADDR_EXPR, pptr_type_node, unshare_expr (next_fp));
+         gimplify_assign (unshare_expr (addr), tmp, pre_p);
 
-         tmp = build2 (GIMPLE_MODIFY_STMT, ptr_type_node, next_fp_tmp, valist);
-         gimplify_and_add (tmp, pre_p);
+         gimplify_assign (unshare_expr (next_fp_tmp), valist, 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);
+           tmp = build2 (POINTER_PLUS_EXPR, TREE_TYPE (tmp),
+                         unshare_expr (tmp), size_int (4 - size));
+         tmp = build2 (GE_EXPR, boolean_type_node,
+                       unshare_expr (next_fp_tmp), unshare_expr (tmp));
          cmp = build3 (COND_EXPR, void_type_node, tmp,
-                       build1 (GOTO_EXPR, void_type_node, lab_false),
-                       NULL_TREE);
+                       build1 (GOTO_EXPR, void_type_node,
+                               unshare_expr (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 = build2 (BIT_AND_EXPR, ptr_type_node, next_fp_tmp, tmp);
-             tmp = build2 (PLUS_EXPR, ptr_type_node, next_fp_tmp, tmp);
-             tmp = build2 (GIMPLE_MODIFY_STMT, ptr_type_node,
-                           next_fp_tmp, tmp);
-             gimplify_and_add (tmp, pre_p);
+             tmp = fold_convert (sizetype, next_fp_tmp);
+             tmp = build2 (BIT_AND_EXPR, sizetype, tmp,
+                           size_int (UNITS_PER_WORD));
+             tmp = build2 (POINTER_PLUS_EXPR, ptr_type_node,
+                           unshare_expr (next_fp_tmp), tmp);
+             gimplify_assign (unshare_expr (next_fp_tmp), tmp, pre_p);
            }
          if (is_double)
            gimplify_and_add (cmp, pre_p);
@@ -7245,62 +7340,60 @@ sh_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p,
                = std_gimplify_va_arg_expr (next_fp_tmp, subtype, pre_p, NULL);
              real = get_initialized_tmp_var (real, pre_p, NULL);
 
-             result = build2 (COMPLEX_EXPR, type, real, imag);
+             result = build2 (COMPLEX_EXPR, eff_type, real, imag);
+             if (type != eff_type)
+               result = build1 (VIEW_CONVERT_EXPR, type, result);
              result = get_initialized_tmp_var (result, pre_p, NULL);
            }
 #endif /* FUNCTION_ARG_SCmode_WART */
 
-         tmp = build1 (GOTO_EXPR, void_type_node, lab_over);
+         tmp = build1 (GOTO_EXPR, void_type_node, unshare_expr (lab_over));
          gimplify_and_add (tmp, pre_p);
 
-         tmp = build1 (LABEL_EXPR, void_type_node, lab_false);
+         tmp = build1 (LABEL_EXPR, void_type_node, unshare_expr (lab_false));
          gimplify_and_add (tmp, pre_p);
 
-         tmp = build1 (ADDR_EXPR, pptr_type_node, next_stack);
-         tmp = build2 (GIMPLE_MODIFY_STMT, void_type_node, addr, tmp);
-         gimplify_and_add (tmp, pre_p);
-         tmp = build2 (GIMPLE_MODIFY_STMT, ptr_type_node, next_fp_tmp, valist);
-         gimplify_and_add (tmp, pre_p);
+         tmp = build1 (ADDR_EXPR, pptr_type_node, unshare_expr (next_stack));
+         gimplify_assign (unshare_expr (addr), tmp, pre_p);
+         gimplify_assign (unshare_expr (next_fp_tmp),
+                          unshare_expr (valist), pre_p);
 
-         tmp = build2 (GIMPLE_MODIFY_STMT, ptr_type_node, valist, next_fp_tmp);
-         gimplify_and_add (tmp, post_p);
+         gimplify_assign (unshare_expr (valist),
+                          unshare_expr (next_fp_tmp), post_p);
          valist = next_fp_tmp;
        }
       else
        {
-         tmp = fold_convert (ptr_type_node, size_int (rsize));
-         tmp = build2 (PLUS_EXPR, ptr_type_node, next_o, tmp);
-         tmp = build2 (GT_EXPR, boolean_type_node, tmp, next_o_limit);
+         tmp = build2 (POINTER_PLUS_EXPR, ptr_type_node,
+                       unshare_expr (next_o), size_int (rsize));
+         tmp = build2 (GT_EXPR, boolean_type_node, tmp,
+                       unshare_expr (next_o_limit));
          tmp = build3 (COND_EXPR, void_type_node, tmp,
-                       build1 (GOTO_EXPR, void_type_node, lab_false),
-                       NULL_TREE);
+                       build1 (GOTO_EXPR, void_type_node,
+                               unshare_expr (lab_false)),
+                       NULL_TREE);
          gimplify_and_add (tmp, pre_p);
 
-         tmp = build1 (ADDR_EXPR, pptr_type_node, next_o);
-         tmp = build2 (GIMPLE_MODIFY_STMT, void_type_node, addr, tmp);
-         gimplify_and_add (tmp, pre_p);
+         tmp = build1 (ADDR_EXPR, pptr_type_node, unshare_expr (next_o));
+         gimplify_assign (unshare_expr (addr), tmp, pre_p);
 
-         tmp = build1 (GOTO_EXPR, void_type_node, lab_over);
+         tmp = build1 (GOTO_EXPR, void_type_node, unshare_expr (lab_over));
          gimplify_and_add (tmp, pre_p);
 
-         tmp = build1 (LABEL_EXPR, void_type_node, lab_false);
+         tmp = build1 (LABEL_EXPR, void_type_node, unshare_expr (lab_false));
          gimplify_and_add (tmp, pre_p);
 
-         if (size > 4 && ! TARGET_SH4)
-           {
-             tmp = build2 (GIMPLE_MODIFY_STMT, ptr_type_node,
-                           next_o, next_o_limit);
-             gimplify_and_add (tmp, pre_p);
-           }
+         if (size > 4 && ! (TARGET_SH4 || TARGET_SH2A))
+           gimplify_assign (unshare_expr (next_o),
+                            unshare_expr (next_o_limit), pre_p);
 
-         tmp = build1 (ADDR_EXPR, pptr_type_node, next_stack);
-         tmp = build2 (GIMPLE_MODIFY_STMT, void_type_node, addr, tmp);
-         gimplify_and_add (tmp, pre_p);
+         tmp = build1 (ADDR_EXPR, pptr_type_node, unshare_expr (next_stack));
+         gimplify_assign (unshare_expr (addr), tmp, pre_p);
        }
 
       if (!result)
        {
-         tmp = build1 (LABEL_EXPR, void_type_node, lab_over);
+         tmp = build1 (LABEL_EXPR, void_type_node, unshare_expr (lab_over));
          gimplify_and_add (tmp, pre_p);
        }
     }
@@ -7311,10 +7404,9 @@ 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 = build2 (GIMPLE_MODIFY_STMT, void_type_node, result, tmp);
-      gimplify_and_add (tmp, pre_p);
+      gimplify_assign (result, tmp, pre_p);
 
-      tmp = build1 (LABEL_EXPR, void_type_node, lab_over);
+      tmp = build1 (LABEL_EXPR, void_type_node, unshare_expr (lab_over));
       gimplify_and_add (tmp, pre_p);
     }
   else
@@ -7326,8 +7418,28 @@ sh_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p,
   return result;
 }
 
+/* 64 bit floating points memory transfers are paired single precision loads
+   or store. So DWARF information needs fixing in little endian (unless
+   PR=SZ=1 in FPSCR).  */
+rtx
+sh_dwarf_register_span (rtx reg)
+{
+  unsigned regno = REGNO (reg);
+
+  if (WORDS_BIG_ENDIAN || GET_MODE (reg) != DFmode)
+    return NULL_RTX;
+
+  return
+    gen_rtx_PARALLEL (VOIDmode,
+                     gen_rtvec (2,
+                                gen_rtx_REG (SFmode,
+                                             DBX_REGISTER_NUMBER (regno+1)),
+                                gen_rtx_REG (SFmode,
+                                             DBX_REGISTER_NUMBER (regno))));
+}
+
 bool
-sh_promote_prototypes (tree type)
+sh_promote_prototypes (const_tree type)
 {
   if (TARGET_HITACHI)
     return 0;
@@ -7342,8 +7454,8 @@ sh_promote_prototypes (tree type)
    loads them into the full 64-bits registers.  */
 
 static int
-shcompact_byref (CUMULATIVE_ARGS *cum, enum machine_mode mode,
-                tree type, bool named)
+shcompact_byref (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
+                const_tree type, bool named)
 {
   unsigned HOST_WIDE_INT size;
 
@@ -7367,7 +7479,7 @@ shcompact_byref (CUMULATIVE_ARGS *cum, enum machine_mode mode,
 
 static bool
 sh_pass_by_reference (CUMULATIVE_ARGS *cum, enum machine_mode mode,
-                     tree type, bool named)
+                     const_tree type, bool named)
 {
   if (targetm.calls.must_pass_in_stack (mode, type))
     return true;
@@ -7389,7 +7501,7 @@ sh_pass_by_reference (CUMULATIVE_ARGS *cum, enum machine_mode mode,
 
 static bool
 sh_callee_copies (CUMULATIVE_ARGS *cum, enum machine_mode mode,
-                 tree type, bool named ATTRIBUTE_UNUSED)
+                 const_tree type, bool named ATTRIBUTE_UNUSED)
 {
   /* ??? How can it possibly be correct to return true only on the
      caller side of the equation?  Is there someplace else in the
@@ -7688,7 +7800,7 @@ sh_struct_value_rtx (tree fndecl, int incoming ATTRIBUTE_UNUSED)
 /* Worker function for TARGET_RETURN_IN_MEMORY.  */
 
 static bool
-sh_return_in_memory (tree type, tree fndecl)
+sh_return_in_memory (const_tree type, const_tree fndecl)
 {
   if (TARGET_SH5)
     {
@@ -7717,7 +7829,7 @@ sh_setup_incoming_varargs (CUMULATIVE_ARGS *ca,
                           int *pretend_arg_size,
                           int second_time ATTRIBUTE_UNUSED)
 {
-  gcc_assert (current_function_stdarg);
+  gcc_assert (cfun->stdarg);
   if (TARGET_VARARGS_PRETEND_ARGS (current_function_decl))
     {
       int named_parm_regs, anon_parm_regs;
@@ -7781,11 +7893,11 @@ initial_elimination_offset (int from, int to)
 
   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;
+      + crtl->args.info.byref_regs * 8;
 
   if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
     return total_saved_regs_space + total_auto_space
-      + current_function_args_info.byref_regs * 8;
+      + crtl->args.info.byref_regs * 8;
 
   /* Initial gap between fp and sp is 0.  */
   if (from == HARD_FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
@@ -7827,6 +7939,68 @@ initial_elimination_offset (int from, int to)
   else
     return total_auto_space;
 }
+
+/* Parse the -mfixed-range= option string.  */
+void
+sh_fix_range (const char *const_str)
+{
+  int i, first, last;
+  char *str, *dash, *comma;
+  
+  /* str must be of the form REG1'-'REG2{,REG1'-'REG} where REG1 and
+     REG2 are either register names or register numbers.  The effect
+     of this option is to mark the registers in the range from REG1 to
+     REG2 as ``fixed'' so they won't be used by the compiler.  */
+  
+  i = strlen (const_str);
+  str = (char *) alloca (i + 1);
+  memcpy (str, const_str, i + 1);
+  
+  while (1)
+    {
+      dash = strchr (str, '-');
+      if (!dash)
+       {
+         warning (0, "value of -mfixed-range must have form REG1-REG2");
+         return;
+       }
+      *dash = '\0';
+      comma = strchr (dash + 1, ',');
+      if (comma)
+       *comma = '\0';
+      
+      first = decode_reg_name (str);
+      if (first < 0)
+       {
+         warning (0, "unknown register name: %s", str);
+         return;
+       }
+      
+      last = decode_reg_name (dash + 1);
+      if (last < 0)
+       {
+         warning (0, "unknown register name: %s", dash + 1);
+         return;
+       }
+      
+      *dash = '-';
+      
+      if (first > last)
+       {
+         warning (0, "%s-%s is an empty range", str, dash + 1);
+         return;
+       }
+      
+      for (i = first; i <= last; ++i)
+       fixed_regs[i] = call_used_regs[i] = 1;
+
+      if (!comma)
+       break;
+
+      *comma = ',';
+      str = comma + 1;
+    }
+}
 \f
 /* Insert any deferred function attributes from earlier pragmas.  */
 static void
@@ -7858,11 +8032,13 @@ sh_insert_attributes (tree node, tree *attributes)
           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.  */
+      /* However, for sp_switch, trap_exit, nosave_low_regs and resbank,
+        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))
+              || lookup_attribute ("nosave_low_regs", attrs)
+              || lookup_attribute ("resbank", attrs))
        {
          tree *tail;
 
@@ -7870,7 +8046,8 @@ sh_insert_attributes (tree node, tree *attributes)
            {
              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)))
+                 || is_attribute_p ("nosave_low_regs", TREE_PURPOSE (attrs))
+                 || is_attribute_p ("resbank", TREE_PURPOSE (attrs)))
                warning (OPT_Wattributes,
                         "%qs attribute only applies to interrupt functions",
                         IDENTIFIER_POINTER (TREE_PURPOSE (attrs)));
@@ -7917,6 +8094,8 @@ sh_insert_attributes (tree node, tree *attributes)
    renesas -- use Renesas calling/layout conventions (functions and
    structures).
 
+   resbank -- In case of an ISR, use a register bank to save registers
+   R0-R14, MACH, MACL, GBR and PR.  This is useful only on SH2A targets.
 */
 
 const struct attribute_spec sh_attribute_table[] =
@@ -7928,6 +8107,8 @@ const struct attribute_spec sh_attribute_table[] =
   { "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 },
+  { "resbank",           0, 0, true,  false, false, sh_handle_resbank_handler_attribute },
+  { "function_vector",   1, 1, true,  false, false, sh2a_handle_function_vector_handler_attribute },
 #ifdef SYMBIAN
   /* Symbian support adds three new attributes:
      dllexport - for exporting a function/variable that will live in a dll
@@ -7942,18 +8123,41 @@ const struct attribute_spec sh_attribute_table[] =
   { NULL,                0, 0, false, false, false, NULL }
 };
 
+/* Handle a 'resbank' attribute.  */
+static tree
+sh_handle_resbank_handler_attribute (tree * node, tree name,
+                                     tree args ATTRIBUTE_UNUSED,
+                                     int flags ATTRIBUTE_UNUSED,
+                                     bool * no_add_attrs)
+{
+  if (!TARGET_SH2A)
+    {
+      warning (OPT_Wattributes, "%qs attribute is supported only for SH2A",
+               IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
+    }
+  if (TREE_CODE (*node) != FUNCTION_DECL)
+    {
+      warning (OPT_Wattributes, "%qs attribute only applies to functions",
+               IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
+    }
+
+  return NULL_TREE;
+}
+
 /* Handle an "interrupt_handler" attribute; arguments as in
    struct attribute_spec.handler.  */
 static tree
 sh_handle_interrupt_handler_attribute (tree *node, tree name,
-                                      tree args ATTRIBUTE_UNUSED,
-                                      int flags ATTRIBUTE_UNUSED,
-                                      bool *no_add_attrs)
+                                       tree args ATTRIBUTE_UNUSED,
+                                       int flags ATTRIBUTE_UNUSED,
+                                       bool *no_add_attrs)
 {
   if (TREE_CODE (*node) != FUNCTION_DECL)
     {
       warning (OPT_Wattributes, "%qs attribute only applies to functions",
-              IDENTIFIER_POINTER (name));
+               IDENTIFIER_POINTER (name));
       *no_add_attrs = true;
     }
   else if (TARGET_SHCOMPACT)
@@ -7965,6 +8169,96 @@ sh_handle_interrupt_handler_attribute (tree *node, tree name,
   return NULL_TREE;
 }
 
+/* Handle an 'function_vector' attribute; arguments as in
+   struct attribute_spec.handler.  */
+static tree
+sh2a_handle_function_vector_handler_attribute (tree * node, tree name,
+                                               tree args ATTRIBUTE_UNUSED,
+                                               int flags ATTRIBUTE_UNUSED,
+                                               bool * no_add_attrs)
+{
+  if (!TARGET_SH2A)
+    {
+      warning (OPT_Wattributes, "%qs attribute only applies to SH2A",
+               IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
+    }
+  else if (TREE_CODE (*node) != FUNCTION_DECL)
+    {
+      warning (OPT_Wattributes, "%qs attribute only applies to functions",
+               IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
+    }
+  else if (TREE_CODE (TREE_VALUE (args)) != INTEGER_CST)
+    {
+      /* The argument must be a constant integer.  */
+      warning (OPT_Wattributes,
+               "`%s' attribute argument not an integer constant",
+               IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
+    }
+  else if (TREE_INT_CST_LOW (TREE_VALUE (args)) > 255)
+    {
+      /* The argument value must be between 0 to 255.  */
+      warning (OPT_Wattributes,
+               "`%s' attribute argument should be between 0 to 255",
+               IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
+    }
+  return NULL_TREE;
+}
+
+/* Returns 1 if current function has been assigned the attribute
+   'function_vector'.  */
+int
+sh2a_is_function_vector_call (rtx x)
+{
+  if (GET_CODE (x) == SYMBOL_REF
+      && (SYMBOL_REF_FLAGS (x) & SYMBOL_FLAG_FUNCVEC_FUNCTION))
+    {
+      tree tr = SYMBOL_REF_DECL (x);
+
+      if (sh2a_function_vector_p (tr))
+        return 1;
+    }
+
+  return 0;
+}
+
+/* Returns the function vector number, if the the attribute
+   'function_vector' is assigned, otherwise returns zero.  */
+int
+sh2a_get_function_vector_number (rtx x)
+{
+  int num;
+  tree list, t;
+
+  if ((GET_CODE (x) == SYMBOL_REF)
+      && (SYMBOL_REF_FLAGS (x) & SYMBOL_FLAG_FUNCVEC_FUNCTION))
+    {
+      t = SYMBOL_REF_DECL (x);
+
+      if (TREE_CODE (t) != FUNCTION_DECL)
+        return 0;
+
+      list = SH_ATTRIBUTES (t);
+      while (list)
+        {
+          if (is_attribute_p ("function_vector", TREE_PURPOSE (list)))
+            {
+              num = TREE_INT_CST_LOW (TREE_VALUE (TREE_VALUE (list)));
+              return num;
+            }
+
+          list = TREE_CHAIN (list);
+        }
+
+      return 0;
+    }
+  else
+    return 0;
+}
+
 /* Handle an "sp_switch" attribute; arguments as in
    struct attribute_spec.handler.  */
 static tree
@@ -8025,7 +8319,7 @@ sh_handle_renesas_attribute (tree *node ATTRIBUTE_UNUSED,
 
 /* True if __attribute__((renesas)) or -mrenesas.  */
 int
-sh_attr_renesas_p (tree td)
+sh_attr_renesas_p (const_tree td)
 {
   if (TARGET_HITACHI)
     return 1;
@@ -8055,6 +8349,39 @@ sh_cfun_interrupt_handler_p (void)
          != NULL_TREE);
 }
 
+/* Returns 1 if FUNC has been assigned the attribute
+   "function_vector".  */
+int
+sh2a_function_vector_p (tree func)
+{
+  tree list;
+  if (TREE_CODE (func) != FUNCTION_DECL)
+    return 0;
+
+  list = SH_ATTRIBUTES (func);
+  while (list)
+    {
+      if (is_attribute_p ("function_vector", TREE_PURPOSE (list)))
+        return 1;
+
+      list = TREE_CHAIN (list);
+    }
+  return 0;
+}
+
+/* Returns TRUE if given tree has the "resbank" attribute.  */
+
+int
+sh_cfun_resbank_handler_p (void)
+{
+  return ((lookup_attribute ("resbank",
+                             DECL_ATTRIBUTES (current_function_decl))
+           != NULL_TREE)
+          && (lookup_attribute ("interrupt_handler",
+                                DECL_ATTRIBUTES (current_function_decl))
+              != NULL_TREE) && TARGET_SH2A);
+}
+
 /* Implement TARGET_CHECK_PCH_TARGET_FLAGS.  */
 
 static const char *
@@ -8297,7 +8624,7 @@ emit_fpu_switch (rtx scratch, int index)
     }
 
   src = DECL_RTL (fpscr_values);
-  if (no_new_pseudos)
+  if (!can_create_pseudo_p ())
     {
       emit_move_insn (scratch, XEXP (src, 0));
       if (index != 0)
@@ -8349,86 +8676,6 @@ expand_df_binop (rtx (*fun) (rtx, rtx, rtx, rtx), rtx *operands)
                        get_fpscr_rtx ()));
 }
 \f
-/* ??? gcc does flow analysis strictly after common subexpression
-   elimination.  As a result, common subexpression elimination fails
-   when there are some intervening statements setting the same register.
-   If we did nothing about this, this would hurt the precision switching
-   for SH4 badly.  There is some cse after reload, but it is unable to
-   undo the extra register pressure from the unused instructions, and
-   it cannot remove auto-increment loads.
-
-   A C code example that shows this flow/cse weakness for (at least) SH
-   and sparc (as of gcc ss-970706) is this:
-
-double
-f(double a)
-{
-  double d;
-  d = 0.1;
-  a += d;
-  d = 1.1;
-  d = 0.1;
-  a *= d;
-  return a;
-}
-
-   So we add another pass before common subexpression elimination, to
-   remove assignments that are dead due to a following assignment in the
-   same basic block.  */
-
-static void
-mark_use (rtx x, rtx *reg_set_block)
-{
-  enum rtx_code code;
-
-  if (! x)
-    return;
-  code = GET_CODE (x);
-  switch (code)
-    {
-    case REG:
-      {
-       int regno = REGNO (x);
-       int nregs = (regno < FIRST_PSEUDO_REGISTER
-                    ? HARD_REGNO_NREGS (regno, GET_MODE (x))
-                    : 1);
-       do
-         {
-           reg_set_block[regno + nregs - 1] = 0;
-         }
-       while (--nregs);
-       break;
-      }
-    case SET:
-      {
-       rtx dest = SET_DEST (x);
-
-       if (GET_CODE (dest) == SUBREG)
-         dest = SUBREG_REG (dest);
-       if (GET_CODE (dest) != REG)
-         mark_use (dest, reg_set_block);
-       mark_use (SET_SRC (x), reg_set_block);
-       break;
-      }
-    case CLOBBER:
-      break;
-    default:
-      {
-       const char *fmt = GET_RTX_FORMAT (code);
-       int i, j;
-       for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
-         {
-           if (fmt[i] == 'e')
-             mark_use (XEXP (x, i), reg_set_block);
-           else if (fmt[i] == 'E')
-             for (j = XVECLEN (x, i) - 1; j >= 0; j--)
-               mark_use (XVECEXP (x, i, j), reg_set_block);
-         }
-       break;
-      }
-    }
-}
-\f
 static rtx get_free_reg (HARD_REG_SET);
 
 /* This function returns a register to use to load the address to load
@@ -8466,13 +8713,13 @@ fpscr_set_from_mem (int mode, HARD_REG_SET regs_live)
   enum attr_fp_mode norm_mode = ACTUAL_NORMAL_MODE (FP_MODE);
   rtx addr_reg;
 
-  addr_reg = no_new_pseudos ? get_free_reg (regs_live) : NULL_RTX;
+  addr_reg = !can_create_pseudo_p () ? get_free_reg (regs_live) : NULL_RTX;
   emit_fpu_switch (addr_reg, fp_mode == norm_mode);
 }
 
 /* Is the given character a logical line separator for the assembler?  */
 #ifndef IS_ASM_LOGICAL_LINE_SEPARATOR
-#define IS_ASM_LOGICAL_LINE_SEPARATOR(C) ((C) == ';')
+#define IS_ASM_LOGICAL_LINE_SEPARATOR(C, STR) ((C) == ';')
 #endif
 
 int
@@ -8493,7 +8740,7 @@ sh_insn_length_adjustment (rtx insn)
 
   /* SH2e has a bug that prevents the use of annulled branches, so if
      the delay slot is not filled, we'll have to put a NOP in it.  */
-  if (sh_cpu == CPU_SH2E
+  if (sh_cpu_attr == CPU_SH2E
       && GET_CODE (insn) == JUMP_INSN
       && GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC
       && GET_CODE (PATTERN (insn)) != ADDR_VEC
@@ -8507,14 +8754,14 @@ sh_insn_length_adjustment (rtx insn)
     {
       int sum = 0;
       rtx body = PATTERN (insn);
-      const char *template;
+      const char *templ;
       char c;
       int maybe_label = 1;
 
       if (GET_CODE (body) == ASM_INPUT)
-       template = XSTR (body, 0);
+       templ = XSTR (body, 0);
       else if (asm_noperands (body) >= 0)
-       template
+       templ
          = decode_asm_operands (body, NULL, NULL, NULL, NULL, NULL);
       else
        return 0;
@@ -8523,19 +8770,20 @@ sh_insn_length_adjustment (rtx insn)
          int ppi_adjust = 0;
 
          do
-           c = *template++;
+           c = *templ++;
          while (c == ' ' || c == '\t');
          /* all sh-dsp parallel-processing insns start with p.
             The only non-ppi sh insn starting with p is pref.
             The only ppi starting with pr is prnd.  */
-         if ((c == 'p' || c == 'P') && strncasecmp ("re", template, 2))
+         if ((c == 'p' || c == 'P') && strncasecmp ("re", templ, 2))
            ppi_adjust = 2;
          /* The repeat pseudo-insn expands two three insns, a total of
             six bytes in size.  */
          else if ((c == 'r' || c == 'R')
-                  && ! strncasecmp ("epeat", template, 5))
+                  && ! strncasecmp ("epeat", templ, 5))
            ppi_adjust = 4;
-         while (c && c != '\n' && ! IS_ASM_LOGICAL_LINE_SEPARATOR (c))
+         while (c && c != '\n'
+                && ! IS_ASM_LOGICAL_LINE_SEPARATOR (c, templ))
            {
              /* If this is a label, it is obviously not a ppi insn.  */
              if (c == ':' && maybe_label)
@@ -8545,7 +8793,7 @@ sh_insn_length_adjustment (rtx insn)
                }
              else if (c == '\'' || c == '"')
                maybe_label = 0;
-             c = *template++;
+             c = *templ++;
            }
          sum += ppi_adjust;
          maybe_label = c != ':';
@@ -8580,7 +8828,9 @@ nonpic_symbol_mentioned_p (rtx x)
          || XINT (x, 1) == UNSPEC_GOTPLT
          || XINT (x, 1) == UNSPEC_GOTTPOFF
          || XINT (x, 1) == UNSPEC_DTPOFF
-         || XINT (x, 1) == UNSPEC_PLT))
+         || XINT (x, 1) == UNSPEC_PLT
+         || XINT (x, 1) == UNSPEC_SYMOFF
+         || XINT (x, 1) == UNSPEC_PCREL_SYMOFF))
     return 0;
 
   fmt = GET_RTX_FORMAT (GET_CODE (x));
@@ -8963,7 +9213,7 @@ flow_dependent_p (rtx insn, rtx dep_insn)
 
 /* A helper function for flow_dependent_p called through note_stores.  */
 static void
-flow_dependent_p_1 (rtx x, rtx pat ATTRIBUTE_UNUSED, void *data)
+flow_dependent_p_1 (rtx x, const_rtx pat ATTRIBUTE_UNUSED, void *data)
 {
   rtx * pinsn = (rtx *) data;
 
@@ -8993,9 +9243,9 @@ sh_allocate_initial_value (rtx hard_reg)
       if (current_function_is_leaf
          && ! sh_pr_n_sets ()
          && ! (TARGET_SHCOMPACT
-               && ((current_function_args_info.call_cookie
+               && ((crtl->args.info.call_cookie
                     & ~ CALL_COOKIE_RET_TRAMP (1))
-                   || current_function_has_nonlocal_label)))
+                   || crtl->saves_all_registers)))
        x = hard_reg;
       else
        x = gen_frame_mem (Pmode, return_address_pointer_rtx);
@@ -9156,7 +9406,7 @@ find_r0_life_regions (basic_block b)
   int set;
   int death = 0;
 
-  if (REGNO_REG_SET_P (DF_LIVE_IN (b), R0_REG))
+  if (REGNO_REG_SET_P (df_get_live_in (b), R0_REG))
     {
       set = 1;
       live = 1;
@@ -9237,6 +9487,17 @@ sh_md_finish_global (FILE *dump ATTRIBUTE_UNUSED,
     }
 }
 
+/* The scalar modes supported differs from the default version in TImode
+   for 32-bit SHMEDIA.  */
+static bool
+sh_scalar_mode_supported_p (enum machine_mode mode)
+{
+  if (TARGET_SHMEDIA32 && mode == TImode)
+    return false;
+
+  return default_scalar_mode_supported_p (mode);
+}
+
 /* Cache the can_issue_more so that we can return it from reorder2. Also,
    keep count of register pressures on SImode and SFmode. */
 static int
@@ -9399,7 +9660,7 @@ sh_optimize_target_register_callee_saved (bool after_prologue_epilogue_gen)
 }
 
 static bool
-sh_ms_bitfield_layout_p (tree record_type ATTRIBUTE_UNUSED)
+sh_ms_bitfield_layout_p (const_tree record_type ATTRIBUTE_UNUSED)
 {
   return (TARGET_SH5 || TARGET_HITACHI || sh_attr_renesas_p (record_type));
 }
@@ -9564,7 +9825,7 @@ sh_initialize_trampoline (rtx tramp, rtx fnaddr, rtx cxt)
          || (!(TARGET_SH4A_ARCH || TARGET_SH4_300) && TARGET_USERMODE))
        emit_library_call (function_symbol (NULL, "__ic_invalidate",
                                            FUNCTION_ORDINARY),
-                          0, VOIDmode, 1, tramp, SImode);
+                          LCT_NORMAL, VOIDmode, 1, tramp, SImode);
       else
        emit_insn (gen_ic_invalidate_line (tramp));
     }
@@ -9581,7 +9842,7 @@ sh_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
 {
   return (1
          && (! TARGET_SHCOMPACT
-             || current_function_args_info.stack_regs == 0)
+             || crtl->args.info.stack_regs == 0)
          && ! sh_cfun_interrupt_handler_p ()
          && (! flag_pic
              || (decl && ! TREE_PUBLIC (decl))
@@ -9827,7 +10088,7 @@ sh_vector_mode_supported_p (enum machine_mode mode)
 /* Implements target hook dwarf_calling_convention.  Return an enum
    of dwarf_calling_convention.  */
 int
-sh_dwarf_calling_convention (tree func)
+sh_dwarf_calling_convention (const_tree func)
 {
   if (sh_attr_renesas_p (func))
     return DW_CC_GNU_renesas_sh;
@@ -9901,7 +10162,7 @@ sh_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
       argmode = TYPE_MODE (TREE_TYPE (arg));
       if (argmode != opmode)
        arg = build1 (NOP_EXPR, optype, arg);
-      op[nop] = expand_expr (arg, NULL_RTX, opmode, 0);
+      op[nop] = expand_expr (arg, NULL_RTX, opmode, EXPAND_NORMAL);
       if (! (*insn_data[icode].operand[nop].predicate) (op[nop], opmode))
        op[nop] = copy_to_mode_reg (opmode, op[nop]);
     }
@@ -9944,38 +10205,136 @@ sh_expand_unop_v2sf (enum rtx_code code, rtx op0, rtx op1)
 void
 sh_expand_binop_v2sf (enum rtx_code code, rtx op0, rtx op1, rtx op2)
 {
-  rtx sel0 = const0_rtx;
-  rtx sel1 = const1_rtx;
-  rtx (*fn) (rtx, rtx, rtx, rtx, rtx, rtx, rtx, rtx)
-    = gen_binary_sf_op;
   rtx op = gen_rtx_fmt_ee (code, SFmode, op1, op2);
 
-  emit_insn ((*fn) (op0, op1, op2, op, sel0, sel0, sel0, sel1));
-  emit_insn ((*fn) (op0, op1, op2, op, sel1, sel1, sel1, sel0));
+  emit_insn (gen_binary_sf_op0 (op0, op1, op2, op));
+  emit_insn (gen_binary_sf_op1 (op0, op1, op2, op));
+}
+
+/* Return true if hard register REGNO can hold a value of machine-mode MODE.
+   We can allow any mode in any general register.  The special registers
+   only allow SImode.  Don't allow any mode in the PR.
+
+   We cannot hold DCmode values in the XD registers because alter_reg
+   handles subregs of them incorrectly.  We could work around this by
+   spacing the XD registers like the DR registers, but this would require
+   additional memory in every compilation to hold larger register vectors.
+   We could hold SFmode / SCmode values in XD registers, but that
+   would require a tertiary reload when reloading from / to memory,
+   and a secondary reload to reload from / to general regs; that
+   seems to be a loosing proposition.
+
+   We want to allow TImode FP regs so that when V4SFmode is loaded as TImode,
+   it won't be ferried through GP registers first.  */
+
+bool
+sh_hard_regno_mode_ok (unsigned int regno, enum machine_mode mode)
+{
+  if (SPECIAL_REGISTER_P (regno))
+    return mode == SImode;
+
+  if (regno == FPUL_REG)
+    return (mode == SImode || mode == SFmode);
+
+  if (FP_REGISTER_P (regno) && mode == SFmode)
+    return true;
+
+  if (mode == V2SFmode)
+    {
+      if (((FP_REGISTER_P (regno) && (regno - FIRST_FP_REG) % 2 == 0)
+          || GENERAL_REGISTER_P (regno)))
+       return true;
+      else
+       return false;
+    }
+
+  if (mode == V4SFmode)
+    {
+      if ((FP_REGISTER_P (regno) && (regno - FIRST_FP_REG) % 4 == 0)
+         || GENERAL_REGISTER_P (regno))
+       return true;
+      else
+       return false;
+    }
+
+  if (mode == V16SFmode)
+    {
+      if (TARGET_SHMEDIA)
+       {
+         if (FP_REGISTER_P (regno) && (regno - FIRST_FP_REG) % 16 == 0)
+           return true;
+         else
+           return false;
+       }
+      else
+       return regno == FIRST_XD_REG;
+    }
+
+  if (FP_REGISTER_P (regno))
+    {
+      if (mode == SFmode
+         || mode == SImode
+         || ((TARGET_SH2E || TARGET_SHMEDIA) && mode == SCmode)
+         || ((((TARGET_SH4 || TARGET_SH2A_DOUBLE) && mode == DFmode)
+              || mode == DCmode
+              || (TARGET_SHMEDIA
+                  && (mode == DFmode || mode == DImode
+                      || mode == V2SFmode || mode == TImode)))
+             && ((regno - FIRST_FP_REG) & 1) == 0)
+         || ((TARGET_SH4 || TARGET_SHMEDIA) && mode == TImode
+             && ((regno - FIRST_FP_REG) & 3) == 0))
+       return true;
+      else
+       return false;
+    }
+
+  if (XD_REGISTER_P (regno))
+    return mode == DFmode;
+
+  if (TARGET_REGISTER_P (regno))
+    return (mode == DImode || mode == SImode || mode == PDImode);
+
+  if (regno == PR_REG)
+    return mode == SImode;
+
+  if (regno == FPSCR_REG)
+    return mode == PSImode;
+
+  /* FIXME.  This works around PR target/37633 for -O0.  */
+  if (!optimize && TARGET_SHMEDIA32 && GET_MODE_SIZE (mode) > 4)
+    {
+      unsigned int n = GET_MODE_SIZE (mode) / 8;
+
+      if (regno >= FIRST_GENERAL_REG + 10 - n + 1
+         && regno <= FIRST_GENERAL_REG + 14)
+       return false;
+    }
+
+  return true;
 }
 
 /* Return the class of registers for which a mode change from FROM to TO
    is invalid.  */
 bool
 sh_cannot_change_mode_class (enum machine_mode from, enum machine_mode to,
-                            enum reg_class class)
+                            enum reg_class rclass)
 {
   /* We want to enable the use of SUBREGs as a means to
      VEC_SELECT a single element of a vector.  */
   if (to == SFmode && VECTOR_MODE_P (from) && GET_MODE_INNER (from) == SFmode)
-    return (reg_classes_intersect_p (GENERAL_REGS, class));
+    return (reg_classes_intersect_p (GENERAL_REGS, rclass));
 
   if (GET_MODE_SIZE (from) != GET_MODE_SIZE (to))
     {
       if (TARGET_LITTLE_ENDIAN)
        {
          if (GET_MODE_SIZE (to) < 8 || GET_MODE_SIZE (from) < 8)
-           return reg_classes_intersect_p (DF_REGS, class);
+           return reg_classes_intersect_p (DF_REGS, rclass);
        }
       else
        {
          if (GET_MODE_SIZE (from) < 8)
-           return reg_classes_intersect_p (DF_HI_REGS, class);
+           return reg_classes_intersect_p (DF_HI_REGS, rclass);
        }
     }
   return 0;
@@ -10095,7 +10454,7 @@ sh_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
 {
   CUMULATIVE_ARGS cum;
   int structure_value_byref = 0;
-  rtx this, this_value, sibcall, insns, funexp;
+  rtx this_rtx, this_value, sibcall, insns, funexp;
   tree funtype = TREE_TYPE (function);
   int simple_add = CONST_OK_FOR_ADD (delta);
   int did_load = 0;
@@ -10104,7 +10463,6 @@ sh_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
 
   reload_completed = 1;
   epilogue_completed = 1;
-  no_new_pseudos = 1;
   current_function_uses_only_leaf_regs = 1;
 
   emit_note (NOTE_INSN_PROLOGUE_END);
@@ -10124,7 +10482,7 @@ sh_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
 
       FUNCTION_ARG_ADVANCE (cum, Pmode, ptype, 1);
     }
-  this = FUNCTION_ARG (cum, Pmode, ptr_type_node, 1);
+  this_rtx = FUNCTION_ARG (cum, Pmode, ptr_type_node, 1);
 
   /* For SHcompact, we only have r0 for a scratch register: r1 is the
      static chain pointer (even if you can't have nested virtual functions
@@ -10165,7 +10523,7 @@ sh_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
        error ("Need a call-clobbered target register");
     }
 
-  this_value = plus_constant (this, delta);
+  this_value = plus_constant (this_rtx, delta);
   if (vcall_offset
       && (simple_add || scratch0 != scratch1)
       && strict_memory_address_p (ptr_mode, this_value))
@@ -10177,11 +10535,11 @@ sh_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
   if (!delta)
     ; /* Do nothing.  */
   else if (simple_add)
-    emit_move_insn (this, this_value);
+    emit_move_insn (this_rtx, this_value);
   else
     {
       emit_move_insn (scratch1, GEN_INT (delta));
-      emit_insn (gen_add2_insn (this, scratch1));
+      emit_insn (gen_add2_insn (this_rtx, scratch1));
     }
 
   if (vcall_offset)
@@ -10189,7 +10547,7 @@ sh_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
       rtx offset_addr;
 
       if (!did_load)
-       emit_load_ptr (scratch0, this);
+       emit_load_ptr (scratch0, this_rtx);
 
       offset_addr = plus_constant (scratch0, vcall_offset);
       if (strict_memory_address_p (ptr_mode, offset_addr))
@@ -10199,7 +10557,7 @@ sh_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
          /* scratch0 != scratch1, and we have indexed loads.  Get better
             schedule by loading the offset into r1 and using an indexed
             load - then the load of r1 can issue before the load from
-             (this + delta) finishes.  */
+             (this_rtx + delta) finishes.  */
          emit_move_insn (scratch1, GEN_INT (vcall_offset));
          offset_addr = gen_rtx_PLUS (Pmode, scratch0, scratch1);
        }
@@ -10220,7 +10578,7 @@ sh_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
 
       if (Pmode != ptr_mode)
        scratch0 = gen_rtx_TRUNCATE (ptr_mode, scratch0);
-      emit_insn (gen_add2_insn (this, scratch0));
+      emit_insn (gen_add2_insn (this_rtx, scratch0));
     }
 
   /* Generate a tail call to the target function.  */
@@ -10255,7 +10613,7 @@ sh_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
     }
   sibcall = emit_call_insn (sibcall);
   SIBLING_CALL_P (sibcall) = 1;
-  use_reg (&CALL_INSN_FUNCTION_USAGE (sibcall), this);
+  use_reg (&CALL_INSN_FUNCTION_USAGE (sibcall), this_rtx);
   emit_barrier ();
 
   /* Run just enough of rest_of_compilation to do scheduling and get
@@ -10296,7 +10654,7 @@ sh_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
   if (optimize > 0)
     {
       if (! cfun->cfg)
-       init_flow ();
+       init_flow (cfun);
       split_all_insns_noflow ();
     }
 #endif
@@ -10310,26 +10668,10 @@ sh_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
   final_start_function (insns, file, 1);
   final (insns, file, 1);
   final_end_function ();
-
-#if 0
-  if (optimize > 0)
-    {
-      /* Release all memory allocated by df.  */
-      if (rtl_df)
-       {
-         df_finish (rtl_df);
-         rtl_df = NULL;
-       }
-
-      /* Release the bitmap obstacks.  */
-      bitmap_obstack_release (&reg_obstack);
-      bitmap_obstack_release (NULL);
-    }
-#endif
+  free_after_compilation (cfun);
 
   reload_completed = 0;
   epilogue_completed = 0;
-  no_new_pseudos = 0;
 }
 
 rtx
@@ -10399,18 +10741,19 @@ sh_get_pr_initial_val (void)
      PR register on SHcompact, because it might be clobbered by the prologue.
      We check first if that is known to be the case.  */
   if (TARGET_SHCOMPACT
-      && ((current_function_args_info.call_cookie
+      && ((crtl->args.info.call_cookie
           & ~ CALL_COOKIE_RET_TRAMP (1))
-         || current_function_has_nonlocal_label))
+         || crtl->saves_all_registers))
     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.
-     ??? get_hard_reg_initial_val fails if it is called while no_new_pseudos
-     is set, unless it has been called before for the same register.  And even
-     then, we end in trouble if we didn't use the register in the same
-     basic block before.  So call get_hard_reg_initial_val now and wrap it
-     in an unspec if we might need to replace it.  */
+     ??? get_hard_reg_initial_val fails if it is called after register
+     allocation has started, unless it has been called before for the
+     same register.  And even then, we end in trouble if we didn't use
+     the register in the same basic block before.  So call
+     get_hard_reg_initial_val now and wrap it in an unspec if we might
+     need to replace it.  */
   /* ??? We also must do this for TARGET_SH1 in general, because otherwise
      combine can put the pseudo returned by get_hard_reg_initial_val into
      instructions that need a general purpose registers, which will fail to
@@ -10436,9 +10779,12 @@ sh_expand_t_scc (enum rtx_code code, rtx target)
   val = INTVAL (sh_compare_op1);
   if ((code == EQ && val == 1) || (code == NE && val == 0))
     emit_insn (gen_movt (result));
+  else if (TARGET_SH2A && ((code == EQ && val == 0)
+                           || (code == NE && val == 1)))
+    emit_insn (gen_movrt (result));
   else if ((code == EQ && val == 0) || (code == NE && val == 1))
     {
-      emit_insn (gen_rtx_CLOBBER (VOIDmode, result));
+      emit_clobber (result);
       emit_insn (gen_subc (result, result, result));
       emit_insn (gen_addsi3 (result, result, const1_rtx));
     }
@@ -10667,19 +11013,19 @@ replace_n_hard_rtx (rtx x, rtx *replacements, int n_replacements, int modify)
 
   if (GET_CODE (x) == SUBREG)
     {
-      rtx new = replace_n_hard_rtx (SUBREG_REG (x), replacements,
+      rtx new_rtx = replace_n_hard_rtx (SUBREG_REG (x), replacements,
                                    n_replacements, modify);
 
-      if (GET_CODE (new) == CONST_INT)
+      if (GET_CODE (new_rtx) == CONST_INT)
        {
-         x = simplify_subreg (GET_MODE (x), new,
+         x = simplify_subreg (GET_MODE (x), new_rtx,
                               GET_MODE (SUBREG_REG (x)),
                               SUBREG_BYTE (x));
          if (! x)
            abort ();
        }
       else if (modify)
-       SUBREG_REG (x) = new;
+       SUBREG_REG (x) = new_rtx;
 
       return x;
     }
@@ -10727,18 +11073,18 @@ replace_n_hard_rtx (rtx x, rtx *replacements, int n_replacements, int modify)
     }
   else if (GET_CODE (x) == ZERO_EXTEND)
     {
-      rtx new = replace_n_hard_rtx (XEXP (x, 0), replacements,
+      rtx new_rtx = replace_n_hard_rtx (XEXP (x, 0), replacements,
                                    n_replacements, modify);
 
-      if (GET_CODE (new) == CONST_INT)
+      if (GET_CODE (new_rtx) == CONST_INT)
        {
          x = simplify_unary_operation (ZERO_EXTEND, GET_MODE (x),
-                                       new, GET_MODE (XEXP (x, 0)));
+                                       new_rtx, GET_MODE (XEXP (x, 0)));
          if (! x)
            abort ();
        }
       else if (modify)
-       XEXP (x, 0) = new;
+       XEXP (x, 0) = new_rtx;
 
       return x;
     }
@@ -10746,26 +11092,26 @@ replace_n_hard_rtx (rtx x, rtx *replacements, int n_replacements, int modify)
   fmt = GET_RTX_FORMAT (GET_CODE (x));
   for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
     {
-      rtx new;
+      rtx new_rtx;
 
       if (fmt[i] == 'e')
        {
-         new = replace_n_hard_rtx (XEXP (x, i), replacements,
+         new_rtx = replace_n_hard_rtx (XEXP (x, i), replacements,
                                    n_replacements, modify);
-         if (!new)
+         if (!new_rtx)
            return NULL_RTX;
          if (modify)
-           XEXP (x, i) = new;
+           XEXP (x, i) = new_rtx;
        }
       else if (fmt[i] == 'E')
        for (j = XVECLEN (x, i) - 1; j >= 0; j--)
          {
-           new = replace_n_hard_rtx (XVECEXP (x, i, j), replacements,
+           new_rtx = replace_n_hard_rtx (XVECEXP (x, i, j), replacements,
                                      n_replacements, modify);
-         if (!new)
+         if (!new_rtx)
            return NULL_RTX;
            if (modify)
-             XVECEXP (x, i, j) = new;
+             XVECEXP (x, i, j) = new_rtx;
          }
     }
 
@@ -10836,6 +11182,20 @@ sh_contains_memref_p (rtx insn)
   return for_each_rtx (&PATTERN (insn), &sh_contains_memref_p_1, NULL);
 }
 
+/* Return nonzero iff INSN loads a banked register.  */
+int
+sh_loads_bankedreg_p (rtx insn)
+{
+  if (GET_CODE (PATTERN (insn)) == SET)
+    {
+      rtx op = SET_DEST (PATTERN(insn));
+      if (REG_P (op) && BANKED_REGISTER_P (REGNO (op)))
+       return 1;
+    }
+
+  return 0;  
+}
+
 /* FNADDR is the MEM expression from a call expander.  Return an address
    to use in an SHmedia insn pattern.  */
 rtx
@@ -10885,12 +11245,12 @@ shmedia_prepare_call_address (rtx fnaddr, int is_sibcall)
 }
 
 enum reg_class
-sh_secondary_reload (bool in_p, rtx x, enum reg_class class,
+sh_secondary_reload (bool in_p, rtx x, enum reg_class rclass,
                     enum machine_mode mode, secondary_reload_info *sri)
 {
   if (in_p)
     {
-      if (REGCLASS_HAS_FP_REG (class)
+      if (REGCLASS_HAS_FP_REG (rclass)
          && ! TARGET_SHMEDIA
          && immediate_operand ((x), mode)
          && ! ((fp_zero_operand (x) || fp_one_operand (x))
@@ -10910,24 +11270,26 @@ sh_secondary_reload (bool in_p, rtx x, enum reg_class class,
          default:
            abort ();
          }
-      if (class == FPUL_REGS
+      if (rclass == 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 (rclass == FPUL_REGS && immediate_operand (x, mode))
        {
-         if (satisfies_constraint_I08 (x))
+         if (satisfies_constraint_I08 (x) || fp_zero_operand (x))
            return GENERAL_REGS;
+         else if (mode == SFmode)
+           return FP_REGS;
          sri->icode = CODE_FOR_reload_insi__i_fpul;
          return NO_REGS;
        }
-      if (class == FPSCR_REGS
+      if (rclass == 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)
+      if (REGCLASS_HAS_FP_REG (rclass)
           && TARGET_SHMEDIA
           && immediate_operand (x, mode)
           && x != CONST0_RTX (GET_MODE (x))
@@ -10940,24 +11302,24 @@ sh_secondary_reload (bool in_p, rtx x, enum reg_class class,
                        ? 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)))
+      if (TARGET_SHMEDIA && rclass == GENERAL_REGS
+          && (GET_CODE (x) == LABEL_REF || PIC_ADDR_P (x)))
         return TARGET_REGS;
     } /* end of input-only processing.  */
 
-  if (((REGCLASS_HAS_FP_REG (class)
+  if (((REGCLASS_HAS_FP_REG (rclass)
        && (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)
+       || (REGCLASS_HAS_GENERAL_REG (rclass)
           && 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)
+  if ((rclass == FPUL_REGS
+       || (REGCLASS_HAS_FP_REG (rclass)
            && ! TARGET_SHMEDIA && mode == SImode))
       && (GET_CODE (x) == MEM
           || (GET_CODE (x) == REG
@@ -10965,20 +11327,20 @@ sh_secondary_reload (bool in_p, rtx x, enum reg_class class,
                   || REGNO (x) == T_REG
                   || system_reg_operand (x, VOIDmode)))))
     {
-      if (class == FPUL_REGS)
+      if (rclass == FPUL_REGS)
        return GENERAL_REGS;
       return FPUL_REGS;
     }
-  if ((class == TARGET_REGS
-       || (TARGET_SHMEDIA && class == SIBCALL_REGS))
+  if ((rclass == TARGET_REGS
+       || (TARGET_SHMEDIA && rclass == SIBCALL_REGS))
       && !satisfies_constraint_Csy (x)
       && (GET_CODE (x) != REG || ! GENERAL_REGISTER_P (REGNO (x))))
     return GENERAL_REGS;
-  if ((class == MAC_REGS || class == PR_REGS)
+  if ((rclass == MAC_REGS || rclass == PR_REGS)
       && GET_CODE (x) == REG && ! GENERAL_REGISTER_P (REGNO (x))
-      && class != REGNO_REG_CLASS (REGNO (x)))
+      && rclass != REGNO_REG_CLASS (REGNO (x)))
     return GENERAL_REGS;
-  if (class != GENERAL_REGS && GET_CODE (x) == REG
+  if (rclass != GENERAL_REGS && GET_CODE (x) == REG
       && TARGET_REGISTER_P (REGNO (x)))
     return GENERAL_REGS;
   return NO_REGS;