OSDN Git Service

* doc/invoke.texi: Document -mbitops for SH.
[pf3gnuchains/gcc-fork.git] / gcc / config / sh / sh.c
index 02a8713..6013c2a 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 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"
@@ -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;
 
@@ -186,6 +193,10 @@ 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 *);
@@ -215,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);
@@ -243,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 void sh_va_start (tree, rtx);
 static tree sh_gimplify_va_arg_expr (tree, tree, tree *, tree *);
 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.  */
@@ -282,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
@@ -426,9 +441,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
 
@@ -444,6 +463,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
@@ -458,6 +480,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.  */
@@ -656,6 +681,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.  */
 
@@ -685,7 +713,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;
@@ -791,6 +823,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))
        {
@@ -858,6 +905,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);
 
@@ -1017,6 +1080,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)
@@ -2409,7 +2485,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)
@@ -2436,7 +2512,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;
@@ -3711,7 +3787,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;
     }
@@ -3836,6 +3913,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
@@ -3895,6 +3973,7 @@ find_barrier (int num_mova, rtx mova, rtx from)
 
       if (GET_CODE (from) == BARRIER)
        {
+         rtx next;
 
          found_barrier = from;
 
@@ -3903,6 +3982,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))
@@ -4059,7 +4146,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);
@@ -4717,8 +4805,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
@@ -4729,7 +4817,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);
            }
        }
@@ -4880,16 +4969,16 @@ 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) = gen_rtx_INSN_LIST (REG_LABEL_OPERAND, label,
                                                REG_NOTES (link));
-         REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_LABEL, label,
+         REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_LABEL_OPERAND, label,
                                                REG_NOTES (insn));
          if (rescan)
            {
@@ -4905,7 +4994,8 @@ sh_reorg (void)
                          || ((reg2 = sfunc_uses_reg (scan))
                              && REGNO (reg2) == REGNO (reg))))
                    REG_NOTES (scan)
-                     = gen_rtx_INSN_LIST (REG_LABEL, label, REG_NOTES (scan));
+                     = gen_rtx_INSN_LIST (REG_LABEL_OPERAND, label,
+                                          REG_NOTES (scan));
                }
              while (scan != dies);
            }
@@ -5265,7 +5355,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
@@ -5406,7 +5496,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;
@@ -5749,7 +5839,16 @@ push_regs (HARD_REG_SET *mask, int interrupt_handler)
       if (i != PR_REG
          && (i != FPSCR_REG || ! skip_fpscr)
          && TEST_HARD_REG_BIT (*mask, i))
-       push (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.  */
@@ -5758,7 +5857,8 @@ push_regs (HARD_REG_SET *mask, int interrupt_handler)
       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);
 }
 
@@ -5872,7 +5972,7 @@ calc_live_regs (HARD_REG_SET *live_regs_mask)
   if (TARGET_SHCOMPACT
       && ((current_function_args_info.call_cookie
           & ~ CALL_COOKIE_RET_TRAMP (1))
-         || current_function_has_nonlocal_label))
+         || current_function_saves_all_registers))
     pr_live = 1;
   has_call = TARGET_SHMEDIA ? ! leaf_function_p () : pr_live;
   for (count = 0, reg = FIRST_PSEUDO_REGISTER; reg-- != 0; )
@@ -6687,7 +6787,10 @@ sh_expand_epilogue (bool sibcall_p)
       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 ());
@@ -6715,7 +6818,15 @@ 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)
@@ -6854,7 +6965,7 @@ sh_builtin_saveregs (void)
   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)
     {
@@ -7034,7 +7145,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;
@@ -7202,7 +7313,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
@@ -7314,7 +7425,7 @@ sh_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p,
          tmp = build1 (LABEL_EXPR, void_type_node, lab_false);
          gimplify_and_add (tmp, pre_p);
 
-         if (size > 4 && ! TARGET_SH4)
+         if (size > 4 && ! (TARGET_SH4 || TARGET_SH2A))
            {
              tmp = build2 (GIMPLE_MODIFY_STMT, ptr_type_node,
                            next_o, next_o_limit);
@@ -7355,7 +7466,7 @@ sh_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p,
 }
 
 bool
-sh_promote_prototypes (tree type)
+sh_promote_prototypes (const_tree type)
 {
   if (TARGET_HITACHI)
     return 0;
@@ -7370,8 +7481,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;
 
@@ -7395,7 +7506,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;
@@ -7417,7 +7528,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
@@ -7716,7 +7827,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)
     {
@@ -7886,11 +7997,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;
 
@@ -7898,7 +8011,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)));
@@ -7945,6 +8059,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[] =
@@ -7956,6 +8072,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
@@ -7970,18 +8088,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)
@@ -7993,6 +8134,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
@@ -8053,7 +8284,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;
@@ -8083,6 +8314,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 *
@@ -8420,7 +8684,7 @@ fpscr_set_from_mem (int mode, HARD_REG_SET regs_live)
 
 /* 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
@@ -8483,7 +8747,8 @@ sh_insn_length_adjustment (rtx insn)
          else if ((c == 'r' || c == 'R')
                   && ! strncasecmp ("epeat", template, 5))
            ppi_adjust = 4;
-         while (c && c != '\n' && ! IS_ASM_LOGICAL_LINE_SEPARATOR (c))
+         while (c && c != '\n'
+                && ! IS_ASM_LOGICAL_LINE_SEPARATOR (c, template))
            {
              /* If this is a label, it is obviously not a ppi insn.  */
              if (c == ':' && maybe_label)
@@ -8943,7 +9208,7 @@ sh_allocate_initial_value (rtx hard_reg)
          && ! (TARGET_SHCOMPACT
                && ((current_function_args_info.call_cookie
                     & ~ CALL_COOKIE_RET_TRAMP (1))
-                   || current_function_has_nonlocal_label)))
+                   || current_function_saves_all_registers)))
        x = hard_reg;
       else
        x = gen_frame_mem (Pmode, return_address_pointer_rtx);
@@ -9185,6 +9450,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
@@ -9347,7 +9623,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));
 }
@@ -9775,7 +10051,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;
@@ -9892,14 +10168,10 @@ 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 the class of registers for which a mode change from FROM to TO
@@ -10257,22 +10529,7 @@ 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;
@@ -10347,7 +10604,7 @@ sh_get_pr_initial_val (void)
   if (TARGET_SHCOMPACT
       && ((current_function_args_info.call_cookie
           & ~ CALL_COOKIE_RET_TRAMP (1))
-         || current_function_has_nonlocal_label))
+         || current_function_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
@@ -10383,6 +10640,9 @@ 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));
@@ -10879,8 +11139,10 @@ sh_secondary_reload (bool in_p, rtx x, enum reg_class class,
         return GENERAL_REGS;
       if (class == 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;
        }