]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/config/sh/sh.c
Update copyright years.
[thirdparty/gcc.git] / gcc / config / sh / sh.c
index cddb31c8e62bfe537aa7a74b4c7c986334599252..1564109c9425752f7ceb8e6c7d67910a9d3f8b8b 100644 (file)
@@ -1,5 +1,5 @@
 /* Output routines for GCC for Renesas / SuperH SH.
-   Copyright (C) 1993-2016 Free Software Foundation, Inc.
+   Copyright (C) 1993-2021 Free Software Foundation, Inc.
    Contributed by Steve Chamberlain (sac@cygnus.com).
    Improved by Jim Wilson (wilson@cygnus.com).
 
@@ -21,6 +21,8 @@ along with GCC; see the file COPYING3.  If not see
 
 #include <sstream>
 
+#define IN_TARGET_CODE 1
+
 #include "config.h"
 #define INCLUDE_VECTOR
 #include "system.h"
@@ -32,8 +34,10 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimple.h"
 #include "cfghooks.h"
 #include "df.h"
+#include "memmodel.h"
 #include "tm_p.h"
 #include "stringpool.h"
+#include "attribs.h"
 #include "optabs.h"
 #include "emit-rtl.h"
 #include "recog.h"
@@ -61,6 +65,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "context.h"
 #include "builtins.h"
 #include "rtl-iter.h"
+#include "regs.h"
+#include "toplev.h"
 
 /* This file should be included last.  */
 #include "target-def.h"
@@ -80,8 +86,9 @@ int code_for_indirect_jump_scratch = CODE_FOR_indirect_jump_scratch;
                  ? (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;
+/* Set to true by expand_prologue() when the function is an
+   interrupt handler.  */
+bool current_function_interrupt;
 
 tree sh_deferred_function_attributes;
 tree *sh_deferred_function_attributes_tail = &sh_deferred_function_attributes;
@@ -180,10 +187,10 @@ static void sh_reorg (void);
 static void sh_option_override (void);
 static void sh_override_options_after_change (void);
 static void output_stack_adjust (int, rtx, int, HARD_REG_SET *, bool);
-static rtx_insn *frame_insn (rtx);
+static rtx_insn* emit_frame_insn (rtx);
 static rtx push (int);
 static void pop (int);
-static void push_regs (HARD_REG_SET *, int);
+static void push_regs (HARD_REG_SET* mask, bool interrupt_handler);
 static int calc_live_regs (HARD_REG_SET *);
 static HOST_WIDE_INT rounded_frame_size (int);
 static bool sh_frame_pointer_required (void);
@@ -208,11 +215,11 @@ static void sh_print_operand (FILE *, rtx, int);
 static void sh_print_operand_address (FILE *, machine_mode, rtx);
 static bool sh_print_operand_punct_valid_p (unsigned char code);
 static bool sh_asm_output_addr_const_extra (FILE *file, rtx x);
-static void sh_output_function_epilogue (FILE *, HOST_WIDE_INT);
+static void sh_output_function_epilogue (FILE *);
 static void sh_insert_attributes (tree, tree *);
 static const char *sh_check_pch_target_flags (int);
 static int sh_register_move_cost (machine_mode, reg_class_t, reg_class_t);
-static int sh_adjust_cost (rtx_insn *, rtx, rtx_insn *, int);
+static int sh_adjust_cost (rtx_insn *, int, rtx_insn *, int, unsigned int);
 static int sh_issue_rate (void);
 static int sh_dfa_new_cycle (FILE *, int, rtx_insn *, int, int, int *sort_p);
 static short find_set_regmode_weight (rtx, machine_mode);
@@ -233,8 +240,6 @@ static int sh_variable_issue (FILE *, int, rtx_insn *, int);
 static bool sh_function_ok_for_sibcall (tree, tree);
 
 static bool sh_can_follow_jump (const rtx_insn *, const rtx_insn *);
-static reg_class_t sh_target_reg_class (void);
-static bool sh_optimize_target_register_callee_saved (bool);
 static bool sh_ms_bitfield_layout_p (const_tree);
 
 static void sh_init_builtins (void);
@@ -244,7 +249,7 @@ static void sh_output_mi_thunk (FILE *, tree, HOST_WIDE_INT,
                                HOST_WIDE_INT, tree);
 static void sh_file_start (void);
 static bool sh_assemble_integer (rtx, unsigned int, int);
-static bool flow_dependent_p (rtx, rtx);
+static bool flow_dependent_p (rtx_insn *, rtx_insn *);
 static void flow_dependent_p_1 (rtx, const_rtx, void *);
 static int shiftcosts (rtx);
 static int and_xor_ior_costs (rtx, int);
@@ -265,9 +270,9 @@ static bool sh_legitimate_address_p (machine_mode, rtx, bool);
 static rtx sh_legitimize_address (rtx, rtx, machine_mode);
 static rtx sh_delegitimize_address (rtx);
 static bool sh_cannot_substitute_mem_equiv_p (rtx);
-static bool sh_legitimize_address_displacement (rtx *, rtx *, machine_mode);
+static bool sh_legitimize_address_displacement (rtx *, rtx *,
+                                               poly_int64, machine_mode);
 static int scavenge_reg (HARD_REG_SET *s);
-struct save_schedule_s;
 
 static rtx sh_struct_value_rtx (tree, int);
 static rtx sh_function_value (const_tree, const_tree, bool);
@@ -275,8 +280,8 @@ static bool sh_function_value_regno_p (const unsigned int);
 static rtx sh_libcall_value (machine_mode, const_rtx);
 static bool sh_return_in_memory (const_tree, const_tree);
 static rtx sh_builtin_saveregs (void);
-static void sh_setup_incoming_varargs (cumulative_args_t, machine_mode,
-                                      tree, int *, int);
+static void sh_setup_incoming_varargs (cumulative_args_t,
+                                      const function_arg_info &, int *, int);
 static bool sh_strict_argument_naming (cumulative_args_t);
 static bool sh_pretend_outgoing_varargs_named (cumulative_args_t);
 static void sh_atomic_assign_expand_fenv (tree *, tree *, tree *);
@@ -289,16 +294,13 @@ static machine_mode sh_promote_function_mode (const_tree type,
                                                   int *punsignedp,
                                                   const_tree funtype,
                                                   int for_return);
-static bool sh_pass_by_reference (cumulative_args_t, machine_mode,
-                                 const_tree, bool);
-static bool sh_callee_copies (cumulative_args_t, machine_mode,
-                             const_tree, bool);
-static int sh_arg_partial_bytes (cumulative_args_t, machine_mode,
-                                tree, bool);
-static void sh_function_arg_advance (cumulative_args_t, machine_mode,
-                                    const_tree, bool);
-static rtx sh_function_arg (cumulative_args_t, machine_mode,
-                           const_tree, bool);
+static bool sh_pass_by_reference (cumulative_args_t,
+                                 const function_arg_info &);
+static bool sh_callee_copies (cumulative_args_t, const function_arg_info &);
+static int sh_arg_partial_bytes (cumulative_args_t, const function_arg_info &);
+static void sh_function_arg_advance (cumulative_args_t,
+                                    const function_arg_info &);
+static rtx sh_function_arg (cumulative_args_t, const function_arg_info &);
 static int sh_dwarf_calling_convention (const_tree);
 static void sh_encode_section_info (tree, rtx, int);
 static bool sh2a_function_vector_p (tree);
@@ -321,28 +323,32 @@ static bool sh_legitimate_combined_insn (rtx_insn* insn);
 static bool sh_fixed_condition_code_regs (unsigned int* p1, unsigned int* p2);
 
 static void sh_init_sync_libfuncs (void) ATTRIBUTE_UNUSED;
+static unsigned int sh_hard_regno_nregs (unsigned int, machine_mode);
+static bool sh_hard_regno_mode_ok (unsigned int, machine_mode);
+static bool sh_modes_tieable_p (machine_mode, machine_mode);
+static bool sh_can_change_mode_class (machine_mode, machine_mode, reg_class_t);
 \f
 static const struct attribute_spec sh_attribute_table[] =
 {
-  /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
-       affects_type_identity } */
-  { "interrupt_handler", 0, 0, true,  false, false,
-    sh_handle_interrupt_handler_attribute, false },
-  { "sp_switch",         1, 1, true,  false, false,
-     sh_handle_sp_switch_attribute, false },
-  { "trap_exit",         1, 1, true,  false, false,
-    sh_handle_trap_exit_attribute, false },
-  { "renesas",           0, 0, false, true, false,
-    sh_handle_renesas_attribute, false },
-  { "trapa_handler",     0, 0, true,  false, false,
-    sh_handle_interrupt_handler_attribute, false },
-  { "nosave_low_regs",   0, 0, true,  false, false,
-    sh_handle_interrupt_handler_attribute, false },
-  { "resbank",           0, 0, true,  false, false,
-    sh_handle_resbank_handler_attribute, false },
-  { "function_vector",   1, 1, true,  false, false,
-    sh2a_handle_function_vector_handler_attribute, false },
-  { NULL,                0, 0, false, false, false, NULL, false }
+  /* { name, min_len, max_len, decl_req, type_req, fn_type_req,
+       affects_type_identity, handler, exclude } */
+  { "interrupt_handler", 0, 0, true,  false, false, false,
+    sh_handle_interrupt_handler_attribute, NULL },
+  { "sp_switch",         1, 1, true,  false, false, false,
+     sh_handle_sp_switch_attribute, NULL },
+  { "trap_exit",         1, 1, true,  false, false, false,
+    sh_handle_trap_exit_attribute, NULL },
+  { "renesas",           0, 0, false, true, false, false,
+    sh_handle_renesas_attribute, NULL },
+  { "trapa_handler",     0, 0, true,  false, false, false,
+    sh_handle_interrupt_handler_attribute, NULL },
+  { "nosave_low_regs",   0, 0, true,  false, false, false,
+    sh_handle_interrupt_handler_attribute, NULL },
+  { "resbank",           0, 0, true,  false, false, false,
+    sh_handle_resbank_handler_attribute, NULL },
+  { "function_vector",   1, 1, true,  false, false, false,
+    sh2a_handle_function_vector_handler_attribute, NULL },
+  { NULL,                0, 0, false, false, false, false, NULL, NULL }
 };
 \f
 /* Initialize the GCC target structure.  */
@@ -355,12 +361,6 @@ static const struct attribute_spec sh_attribute_table[] =
 #undef TARGET_ASM_UNALIGNED_SI_OP
 #define TARGET_ASM_UNALIGNED_SI_OP "\t.ualong\t"
 
-/* These are NULLed out on non-SH5 in TARGET_OPTION_OVERRIDE.  */
-#undef TARGET_ASM_UNALIGNED_DI_OP
-#define TARGET_ASM_UNALIGNED_DI_OP "\t.uaquad\t"
-#undef TARGET_ASM_ALIGNED_DI_OP
-#define TARGET_ASM_ALIGNED_DI_OP "\t.quad\t"
-
 #undef TARGET_OPTION_OVERRIDE
 #define TARGET_OPTION_OVERRIDE sh_option_override
 
@@ -471,11 +471,6 @@ static const struct attribute_spec sh_attribute_table[] =
 
 #undef TARGET_CAN_FOLLOW_JUMP
 #define TARGET_CAN_FOLLOW_JUMP sh_can_follow_jump
-#undef TARGET_BRANCH_TARGET_REGISTER_CLASS
-#define TARGET_BRANCH_TARGET_REGISTER_CLASS sh_target_reg_class
-#undef TARGET_BRANCH_TARGET_REGISTER_CALLEE_SAVED
-#define TARGET_BRANCH_TARGET_REGISTER_CALLEE_SAVED \
-  sh_optimize_target_register_callee_saved
 
 #undef TARGET_MS_BITFIELD_LAYOUT_P
 #define TARGET_MS_BITFIELD_LAYOUT_P sh_ms_bitfield_layout_p
@@ -652,6 +647,23 @@ static const struct attribute_spec sh_attribute_table[] =
 #undef TARGET_CANNOT_FORCE_CONST_MEM
 #define TARGET_CANNOT_FORCE_CONST_MEM sh_cannot_force_const_mem_p
 
+#undef TARGET_HARD_REGNO_NREGS
+#define TARGET_HARD_REGNO_NREGS sh_hard_regno_nregs
+#undef TARGET_HARD_REGNO_MODE_OK
+#define TARGET_HARD_REGNO_MODE_OK sh_hard_regno_mode_ok
+
+#undef TARGET_MODES_TIEABLE_P
+#define TARGET_MODES_TIEABLE_P sh_modes_tieable_p
+
+#undef TARGET_CAN_CHANGE_MODE_CLASS
+#define TARGET_CAN_CHANGE_MODE_CLASS sh_can_change_mode_class
+
+#undef TARGET_CONSTANT_ALIGNMENT
+#define TARGET_CONSTANT_ALIGNMENT constant_alignment_word_strings
+
+#undef  TARGET_HAVE_SPECULATION_SAFE_VALUE
+#define TARGET_HAVE_SPECULATION_SAFE_VALUE speculation_safe_value_not_needed
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
 
@@ -725,7 +737,7 @@ got_mode_name:;
     {
       if (tokens[i] == "strict")
        ret.strict = true;
-      else if (tokens[i].find ("gbr-offset=") == 0)
+      else if (!tokens[i].compare (0, strlen ("gbr-offset="), "gbr-offset="))
        {
          std::string offset_str = tokens[i].substr (strlen ("gbr-offset="));
          ret.tcb_gbr_offset = integral_argument (offset_str.c_str ());
@@ -788,7 +800,7 @@ register_sh_passes (void)
   /* Run sh_treg_combine pass after register allocation and basic block
      reordering as this sometimes creates new opportunities.  */
   register_pass (make_pass_sh_treg_combine (g, true, "sh_treg_combine3"),
-                PASS_POS_INSERT_AFTER, "split4", 1);
+                PASS_POS_INSERT_AFTER, "split3", 1);
 
   /* Optimize sett and clrt insns, by e.g. removing them if the T bit value
      is known after a conditional branch.
@@ -806,12 +818,6 @@ sh_option_override (void)
   int regno;
 
   SUBTARGET_OVERRIDE_OPTIONS;
-  if (optimize > 1 && !optimize_size)
-    target_flags |= MASK_SAVE_ALL_TARGET_REGS;
-
-  /* Set default values of TARGET_CBRANCHDI4 and TARGET_CMPEQDI_T.  */
-  TARGET_CBRANCHDI4 = 1;
-  TARGET_CMPEQDI_T = 0;
 
   sh_cpu = PROCESSOR_SH1;
   assembler_dialect = 0;
@@ -836,10 +842,6 @@ sh_option_override (void)
       sh_cpu = PROCESSOR_SH4A;
     }
 
-  /* Only the sh64-elf assembler fully supports .quad properly.  */
-  targetm.asm_out.aligned_op.di = NULL;
-  targetm.asm_out.unaligned_op.di = NULL;
-
   /* User/priviledged mode is supported only on SH3* and SH4*.
      Disable it for everything else.  */
   if (!TARGET_SH3 && TARGET_USERMODE)
@@ -919,7 +921,7 @@ sh_option_override (void)
         to the pressure on R0.  */
       /* Enable sched1 for SH4 if the user explicitly requests.
         When sched1 is enabled, the ready queue will be reordered by
-        the target hooks if pressure is high.  We can not do this for
+        the target hooks if pressure is high.  We cannot do this for
         PIC, SH3 and lower as they give spill failures for R0.  */
       if (!TARGET_HARD_SH4 || flag_pic)
        flag_schedule_insns = 0;
@@ -931,7 +933,7 @@ sh_option_override (void)
       else if (flag_exceptions)
        {
          if (flag_schedule_insns && global_options_set.x_flag_schedule_insns)
-           warning (0, "ignoring -fschedule-insns because of exception "
+           warning (0, "ignoring %<-fschedule-insns%> because of exception "
                        "handling bug");
          flag_schedule_insns = 0;
        }
@@ -949,18 +951,20 @@ sh_option_override (void)
       && flag_omit_frame_pointer && !TARGET_ACCUMULATE_OUTGOING_ARGS)
     {
       warning (0, "unwind tables currently require either a frame pointer "
-              "or -maccumulate-outgoing-args for correctness");
+              "or %<-maccumulate-outgoing-args%> for correctness");
       TARGET_ACCUMULATE_OUTGOING_ARGS = 1;
     }
 
   if (flag_unsafe_math_optimizations)
     {
       /* Enable fsca insn for SH4A if not otherwise specified by the user.  */
-      if (global_options_set.x_TARGET_FSCA == 0 && TARGET_SH4A_FP)
+      if (global_options_set.x_TARGET_FSCA == 0
+         && (TARGET_SH4A_FP || TARGET_FPU_SH4_300))
        TARGET_FSCA = 1;
 
       /* Enable fsrra insn for SH4A if not otherwise specified by the user.  */
-      if (global_options_set.x_TARGET_FSRRA == 0 && TARGET_SH4A_FP)
+      if (global_options_set.x_TARGET_FSRRA == 0
+         && (TARGET_SH4A_FP || TARGET_FPU_SH4_300))
        TARGET_FSRRA = 1;
     }
 
@@ -1006,29 +1010,38 @@ sh_override_options_after_change (void)
       Aligning all jumps increases the code size, even if it might
       result in slightly faster code.  Thus, it is set to the smallest 
       alignment possible if not specified by the user.  */
-  if (align_loops == 0)
-    align_loops = optimize_size ? 2 : 4;
+  if (flag_align_loops && !str_align_loops)
+    str_align_loops = optimize_size ? "2" : "4";
 
-  if (align_jumps == 0)
-    align_jumps = 2;
-  else if (align_jumps < 2)
-    align_jumps = 2;
+  /* Parse values so that we can compare for current value.  */
+  parse_alignment_opts ();
+  if (flag_align_jumps && !str_align_jumps)
+    str_align_jumps = "2";
+  else if (align_jumps.levels[0].get_value () < 2)
+    str_align_jumps = "2";
 
-  if (align_functions == 0)
-    align_functions = optimize_size ? 2 : 4;
+  if (flag_align_functions && !str_align_functions)
+    str_align_functions = optimize_size ? "2" : "4";
 
   /* The linker relaxation code breaks when a function contains
      alignments that are larger than that at the start of a
      compilation unit.  */
   if (TARGET_RELAX)
     {
-      int min_align = align_loops > align_jumps ? align_loops : align_jumps;
+      /* Parse values so that we can compare for current value.  */
+      parse_alignment_opts ();
+      int min_align = MAX (align_loops.levels[0].get_value (),
+                          align_jumps.levels[0].get_value ());
 
       /* Also take possible .long constants / mova tables into account.        */
       if (min_align < 4)
        min_align = 4;
-      if (align_functions < min_align)
-       align_functions = min_align;
+      if (align_functions.levels[0].get_value () < min_align)
+       {
+         char *r = XNEWVEC (char, 16);
+         sprintf (r, "%d", min_align);
+         str_align_functions = r;
+       }
     }
 }
 \f
@@ -1061,8 +1074,16 @@ sh_print_operand_address (FILE *stream, machine_mode /*mode*/, rtx x)
              int base_num = true_regnum (base);
              int index_num = true_regnum (index);
 
-             fprintf (stream, "@(r0,%s)",
-                      reg_names[MAX (base_num, index_num)]);
+             /* If base or index is R0, make sure that it comes first.
+                Usually one of them will be R0, but the order might be wrong.
+                If neither base nor index are R0 it's an error and we just
+                pass it on to the assembler.  This avoids silent wrong code
+                bugs.  */
+             if (base_num == 0 && index_num != 0)
+               std::swap (base_num, index_num);
+
+             fprintf (stream, "@(%s,%s)", reg_names[index_num],
+                                          reg_names[base_num]);
              break;
            }
 
@@ -1153,7 +1174,9 @@ sh_print_operand (FILE *stream, rtx x, int code)
       {
        rtx note = find_reg_note (current_output_insn, REG_BR_PROB, 0);
 
-       if (note && XINT (note, 0) * 2 < REG_BR_PROB_BASE)
+       if (note
+           && profile_probability::from_reg_br_prob_note (XINT (note, 0))
+              < profile_probability::even ())
          fputs ("/u", stream);
        break;
       }
@@ -1283,11 +1306,11 @@ sh_print_operand (FILE *stream, rtx x, int code)
        {
          switch (GET_MODE (x))
            {
-           case QImode: fputs (".b", stream); break;
-           case HImode: fputs (".w", stream); break;
-           case SImode: fputs (".l", stream); break;
-           case SFmode: fputs (".s", stream); break;
-           case DFmode: fputs (".d", stream); break;
+           case E_QImode: fputs (".b", stream); break;
+           case E_HImode: fputs (".w", stream); break;
+           case E_SImode: fputs (".l", stream); break;
+           case E_SFmode: fputs (".s", stream); break;
+           case E_DFmode: fputs (".d", stream); break;
            default: gcc_unreachable ();
            }
        }
@@ -1395,8 +1418,8 @@ sh_print_operand (FILE *stream, rtx x, int code)
            /* Floating point register pairs are always big endian;
               general purpose registers are 64 bit wide.  */
            regno = REGNO (inner);
-           regno = (HARD_REGNO_NREGS (regno, inner_mode)
-                    - HARD_REGNO_NREGS (regno, mode))
+           regno = (hard_regno_nregs (regno, inner_mode)
+                    - hard_regno_nregs (regno, mode))
                     + offset;
            x = inner;
            goto reg;
@@ -1666,11 +1689,9 @@ prepare_move_operands (rtx operands[], machine_mode mode)
 
   if (mode == Pmode || mode == ptr_mode)
     {
-      rtx op0, op1, opc;
-      enum tls_model tls_kind;
-
-      op0 = operands[0];
-      op1 = operands[1];
+      rtx op0 = operands[0];
+      rtx op1 = operands[1];
+      rtx opc;
       if (GET_CODE (op1) == CONST
          && GET_CODE (XEXP (op1, 0)) == PLUS
          && (tls_symbolic_operand (XEXP (XEXP (op1, 0), 0), Pmode)
@@ -1682,6 +1703,8 @@ prepare_move_operands (rtx operands[], machine_mode mode)
       else
        opc = NULL_RTX;
 
+      enum tls_model tls_kind;
+
       if (! reload_in_progress && ! reload_completed
          && (tls_kind = tls_symbolic_operand (op1, Pmode)) != TLS_MODEL_NONE)
        {
@@ -1702,7 +1725,7 @@ prepare_move_operands (rtx operands[], machine_mode mode)
              emit_use (gen_rtx_REG (SImode, PIC_REG));
              if (flag_schedule_insns)
                emit_insn (gen_blockage ());
-       }
+           }
 
          switch (tls_kind)
            {
@@ -1932,28 +1955,67 @@ sh_fixed_condition_code_regs (unsigned int* p1, unsigned int* p2)
   return true;
 }
 
+/* Try to calculate the branch distance of a conditional branch in bytes.
+
+   FIXME: Because of PR 59189 we can't use the CFG here.  Instead just
+   walk from this insn into the next (fall-through) basic block and see if
+   we hit the label.  */
+unsigned int
+sh_cbranch_distance (rtx_insn* _cbranch_insn, unsigned int max_dist)
+{
+  rtx_jump_insn* cbranch_insn = safe_as_a<rtx_jump_insn*> (_cbranch_insn);
+
+  if (dump_file)
+    {
+      fprintf (dump_file, "sh_cbranch_distance insn = \n");
+      print_rtl_single (dump_file, cbranch_insn);
+    }
+
+  unsigned int dist = 0;
+
+  for (rtx_insn* i = next_nonnote_insn (cbranch_insn);
+       i != NULL && dist < max_dist; i = next_nonnote_insn (i))
+    {
+      const unsigned int i_len = get_attr_length (i);
+      dist += i_len;
+
+      if (dump_file)
+       fprintf (dump_file, "  insn %d  length = %u  dist = %u\n",
+                INSN_UID (i), i_len, dist);
+
+      if (rtx_code_label* l = dyn_cast<rtx_code_label*> (i))
+       {
+         if (l == cbranch_insn->jump_target ())
+           {
+             if (dump_file)
+               fprintf (dump_file, "  cbranch dist = %u\n", dist);
+             return dist;
+           }
+         break;
+       }
+    }
+
+  if (dump_file)
+    fprintf (dump_file, "  cbranch dist = unknown\n");
+
+  return unknown_cbranch_distance;
+}
+
 enum rtx_code
 prepare_cbranch_operands (rtx *operands, machine_mode mode,
                          enum rtx_code comparison)
 {
-  /* The scratch reg is only available when this is invoked from within
-     the cbranchdi4_i splitter, through expand_cbranchdi4.  */
-  rtx scratch = NULL_RTX;
+  gcc_assert (can_create_pseudo_p ());
 
   if (comparison == LAST_AND_UNUSED_RTX_CODE)
     comparison = GET_CODE (operands[0]);
-  else
-    scratch = operands[4];
 
   sh_canonicalize_comparison (comparison, operands[1], operands[2],
                              mode, false);
 
-  /* Notice that this function is also invoked after reload by
-     the cbranchdi4_i pattern, through expand_cbranchdi4.  */
   rtx op1 = operands[1];
+  operands[1] = force_reg (mode, op1);
 
-  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
      are better issued as a whole so that they can be scheduled well.
@@ -1969,20 +2031,14 @@ prepare_cbranch_operands (rtx *operands, machine_mode mode,
              && ((comparison != EQ && comparison != NE)
                  || (REG_P (op1) && REGNO (op1) != R0_REG)
                  || !satisfies_constraint_I08 (operands[2])))))
-    {
-      if (scratch && GET_MODE (scratch) == mode)
-       {
-         emit_move_insn (scratch, operands[2]);
-         operands[2] = scratch;
-       }
-      else if (can_create_pseudo_p ())
-       operands[2] = force_reg (mode, operands[2]);
-    }
+    operands[2] = force_reg (mode, operands[2]);
+
   return comparison;
 }
 
-void
-expand_cbranchsi4 (rtx *operands, enum rtx_code comparison, int probability)
+static void
+expand_cbranchsi4 (rtx *operands, enum rtx_code comparison,
+                  profile_probability probability)
 {
   rtx (*branch_expander) (rtx) = gen_branch_true;
   comparison = prepare_cbranch_operands (operands, SImode, comparison);
@@ -1997,8 +2053,15 @@ expand_cbranchsi4 (rtx *operands, enum rtx_code comparison, int probability)
                          gen_rtx_fmt_ee (comparison, SImode,
                                          operands[1], operands[2])));
   rtx_insn *jump = emit_jump_insn (branch_expander (operands[3]));
-  if (probability >= 0)
-    add_int_reg_note (jump, REG_BR_PROB, probability);
+  if (probability.initialized_p ())
+    add_reg_br_prob_note (jump, probability);
+}
+
+void
+expand_cbranchsi4 (rtx *operands, enum rtx_code comparison)
+{
+  expand_cbranchsi4 (operands, comparison,
+                    profile_probability::uninitialized ());
 }
 
 /* ??? How should we distribute probabilities when more than one branch
@@ -2025,9 +2088,10 @@ expand_cbranchdi4 (rtx *operands, enum rtx_code comparison)
   rtx_code_label *skip_label = NULL;
   rtx op1h, op1l, op2h, op2l;
   int num_branches;
-  int prob, rev_prob;
-  int msw_taken_prob = -1, msw_skip_prob = -1, lsw_taken_prob = -1;
-  rtx scratch = operands[4];
+  profile_probability prob, rev_prob;
+  profile_probability msw_taken_prob = profile_probability::uninitialized (),
+                     msw_skip_prob = profile_probability::uninitialized (),
+                     lsw_taken_prob = profile_probability::uninitialized ();
 
   comparison = prepare_cbranch_operands (operands, DImode, comparison);
   op1h = gen_highpart_mode (SImode, DImode, operands[1]);
@@ -2036,50 +2100,28 @@ expand_cbranchdi4 (rtx *operands, enum rtx_code comparison)
   op2l = gen_lowpart (SImode, operands[2]);
   msw_taken = msw_skip = lsw_taken = LAST_AND_UNUSED_RTX_CODE;
   prob = split_branch_probability;
-  rev_prob = REG_BR_PROB_BASE - prob;
+  rev_prob = prob.invert ();
   switch (comparison)
     {
-    /* ??? Should we use the cmpeqdi_t pattern for equality comparisons?
-       That costs 1 cycle more when the first branch can be predicted taken,
-       but saves us mispredicts because only one branch needs prediction.
-       It also enables generating the cmpeqdi_t-1 pattern.  */
     case EQ:
-      if (TARGET_CMPEQDI_T)
-       {
-         emit_insn (gen_cmpeqdi_t (operands[1], operands[2]));
-         emit_jump_insn (gen_branch_true (operands[3]));
-         return true;
-       }
       msw_skip = NE;
       lsw_taken = EQ;
-      if (prob >= 0)
+      if (prob.initialized_p ())
        {
-         // If we had more precision, we'd use rev_prob - (rev_prob >> 32) .
+         /* FIXME: This is not optimal.  We do not really know the probability
+            that values differ by MCW only, but we should probably distribute
+            probabilities more evenly.  */
          msw_skip_prob = rev_prob;
-         if (REG_BR_PROB_BASE <= 65535)
-           lsw_taken_prob = prob ? REG_BR_PROB_BASE : 0;
-         else
-           {
-             lsw_taken_prob
-               = (prob
-                  ? (REG_BR_PROB_BASE
-                     - ((gcov_type) REG_BR_PROB_BASE * rev_prob
-                        / ((gcov_type) prob << 32)))
-                  : 0);
-           }
+         lsw_taken_prob = prob > profile_probability::never ()
+                          ? profile_probability::guessed_always ()
+                          : profile_probability::guessed_never ();
        }
       break;
     case NE:
-      if (TARGET_CMPEQDI_T)
-       {
-         emit_insn (gen_cmpeqdi_t (operands[1], operands[2]));
-         emit_jump_insn (gen_branch_false (operands[3]));
-         return true;
-       }
       msw_taken = NE;
       msw_taken_prob = prob;
       lsw_taken = NE;
-      lsw_taken_prob = 0;
+      lsw_taken_prob = profile_probability::guessed_never ();
       break;
     case GTU: case GT:
       msw_taken = comparison;
@@ -2132,18 +2174,20 @@ expand_cbranchdi4 (rtx *operands, enum rtx_code comparison)
   if (comparison != EQ && comparison != NE && num_branches > 1)
     {
       if (!CONSTANT_P (operands[2])
-         && prob >= (int) (REG_BR_PROB_BASE * 3 / 8U)
-         && prob <= (int) (REG_BR_PROB_BASE * 5 / 8U))
-       {
-         msw_taken_prob = prob / 2U;
-         msw_skip_prob
-           = REG_BR_PROB_BASE * rev_prob / (REG_BR_PROB_BASE + rev_prob);
+         && prob.initialized_p ()
+         && prob.to_reg_br_prob_base () >= (int) (REG_BR_PROB_BASE * 3 / 8U)
+         && prob.to_reg_br_prob_base () <= (int) (REG_BR_PROB_BASE * 5 / 8U))
+       {
+         msw_taken_prob = prob.apply_scale (1, 2);
+         msw_skip_prob = rev_prob.apply_scale (REG_BR_PROB_BASE,
+                                               rev_prob.to_reg_br_prob_base ()
+                                               + REG_BR_PROB_BASE);
          lsw_taken_prob = prob;
        }
       else
        {
          msw_taken_prob = prob;
-         msw_skip_prob = REG_BR_PROB_BASE;
+         msw_skip_prob = profile_probability::guessed_always ();
          /* ??? If we have a constant op2h, should we use that when
             calculating lsw_taken_prob?  */
          lsw_taken_prob = prob;
@@ -2151,16 +2195,7 @@ expand_cbranchdi4 (rtx *operands, enum rtx_code comparison)
     }
   operands[1] = op1h;
   operands[2] = op2h;
-  operands[4] = NULL_RTX;
-  if (reload_completed
-      && ! arith_reg_or_0_operand (op2h, SImode)
-      && (true_regnum (op1h) || (comparison != EQ && comparison != NE))
-      && (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 != LAST_AND_UNUSED_RTX_CODE)
     expand_cbranchsi4 (operands, msw_taken, msw_taken_prob);
   if (msw_skip != LAST_AND_UNUSED_RTX_CODE)
@@ -2173,13 +2208,6 @@ expand_cbranchdi4 (rtx *operands, enum rtx_code comparison)
        {
          operands[1] = op1h;
          operands[2] = op2h;
-         if (reload_completed
-             && ! arith_reg_or_0_operand (op2h, SImode)
-             && (true_regnum (op1h) || (comparison != EQ && comparison != NE)))
-           {
-             emit_move_insn (scratch, operands[2]);
-             operands[2] = scratch;
-           }
        }
 
       operands[3] = skip_label = gen_label_rtx ();
@@ -2189,16 +2217,7 @@ expand_cbranchdi4 (rtx *operands, enum rtx_code comparison)
   operands[1] = op1l;
   operands[2] = op2l;
   if (lsw_taken != LAST_AND_UNUSED_RTX_CODE)
-    {
-      if (reload_completed
-         && ! arith_reg_or_0_operand (op2l, SImode)
-         && (true_regnum (op1l) || (lsw_taken != EQ && lsw_taken != NE)))
-       {
-         emit_move_insn (scratch, operands[2]);
-         operands[2] = scratch;
-       }
-      expand_cbranchsi4 (operands, lsw_taken, lsw_taken_prob);
-    }
+    expand_cbranchsi4 (operands, lsw_taken, lsw_taken_prob);
   if (msw_skip != LAST_AND_UNUSED_RTX_CODE)
     emit_label (skip_label);
   return true;
@@ -2269,7 +2288,6 @@ sh_emit_scc_to_t (enum rtx_code code, rtx op0, rtx op1)
 {
   rtx t_reg = get_t_reg_rtx ();
   enum rtx_code oldcode = code;
-  machine_mode mode;
 
   /* First need a compare insn.  */
   switch (code)
@@ -2295,7 +2313,7 @@ sh_emit_scc_to_t (enum rtx_code code, rtx op0, rtx op1)
   if (code != oldcode)
     std::swap (op0, op1);
 
-  mode = GET_MODE (op0);
+  machine_mode mode = GET_MODE (op0);
   if (mode == VOIDmode)
     mode = GET_MODE (op1);
 
@@ -2689,6 +2707,7 @@ output_branch (int logic, rtx_insn *insn, rtx *operands)
 
          return "";
        }
+      /* FALLTHRU */
       /* When relaxing, handle this like a short branch.  The linker
         will fix it up if it still doesn't fit after relaxation.  */
     case 2:
@@ -2714,7 +2733,7 @@ output_branch (int logic, rtx_insn *insn, rtx *operands)
 
          return "";
        }
-      /* When relaxing, fall through.  */
+      /* FALLTHRU */
     case 4:
       {
        char buffer[10];
@@ -2838,14 +2857,13 @@ static bool
 unspec_caller_rtx_p (rtx pat)
 {
   rtx base, offset;
-  int i;
-
   split_const (pat, &base, &offset);
+
   if (GET_CODE (base) == UNSPEC)
     {
       if (XINT (base, 1) == UNSPEC_CALLER)
        return true;
-      for (i = 0; i < XVECLEN (base, 0); i++)
+      for (int i = 0; i < XVECLEN (base, 0); i++)
        if (unspec_caller_rtx_p (XVECEXP (base, 0, i)))
          return true;
     }
@@ -2857,8 +2875,6 @@ unspec_caller_rtx_p (rtx pat)
 static bool
 sh_cannot_copy_insn_p (rtx_insn *insn)
 {
-  rtx pat;
-
   if (!reload_completed || !flag_pic)
     return false;
 
@@ -2867,7 +2883,7 @@ sh_cannot_copy_insn_p (rtx_insn *insn)
   if (asm_noperands (insn) >= 0)
     return false;
 
-  pat = PATTERN (insn);
+  rtx pat = PATTERN (insn);
 
   if (GET_CODE (pat) == CLOBBER || GET_CODE (pat) == USE)
     return false;
@@ -3227,6 +3243,12 @@ sh_rtx_costs (rtx x, machine_mode mode ATTRIBUTE_UNUSED, int outer_code,
         vector-move, so we have to provide the correct cost in the number
         of move insns to load/store the reg of the mode in question.  */
     case SET:
+      if (sh_movt_set_dest (x) != NULL || sh_movrt_set_dest (x) != NULL)
+       {
+         *total = COSTS_N_INSNS (1);
+         return true;
+       }
+
       if (register_operand (SET_DEST (x), VOIDmode)
            && (register_operand (SET_SRC (x), VOIDmode)
                || satisfies_constraint_Z (SET_SRC (x))))
@@ -3268,10 +3290,19 @@ sh_rtx_costs (rtx x, machine_mode mode ATTRIBUTE_UNUSED, int outer_code,
          *total = 1; //COSTS_N_INSNS (1);
          return true;
        }
+
+      /* div0s variant.  */
+      if (GET_CODE (XEXP (x, 0)) == XOR
+         && GET_CODE (XEXP (XEXP (x, 0), 0)) == XOR
+         && CONST_INT_P (XEXP (XEXP (x, 0), 1)))
+       {
+         *total = 1;
+         return true;
+       }
       return false;
 
     /* The cost of a sign or zero extend depends on whether the source is a
-       reg or a mem.  In case of a mem take the address into acount.  */
+       reg or a mem.  In case of a mem take the address into account.  */
     case SIGN_EXTEND:
       if (arith_reg_operand (XEXP (x, 0), GET_MODE (XEXP (x, 0))))
        {
@@ -3473,7 +3504,7 @@ sh_rtx_costs (rtx x, machine_mode mode ATTRIBUTE_UNUSED, int outer_code,
          *total = COSTS_N_INSNS (1);
          return true;
        }
-      /* Fall through to shiftcosts.  */
+      /* FALLTHRU */
     case ASHIFT:
     case ASHIFTRT:
       {
@@ -4081,12 +4112,14 @@ gen_shl_and (rtx dest, rtx left_rtx, rtx mask_rtx, rtx source)
       }
     case 4:
       shift_gen_fun = gen_shifty_op;
+      /* FALLTHRU */
     case 3:
       /* If the topmost bit that matters is set, set the topmost bits
         that don't matter.  This way, we might be able to get a shorter
         signed constant.  */
       if (mask & ((HOST_WIDE_INT) 1 << (31 - total_shift)))
        mask |= (HOST_WIDE_INT) ((HOST_WIDE_INT_M1U) << (31 - total_shift));
+      /* FALLTHRU */
     case 2:
       /* Don't expand fine-grained when combining, because that will
          make the pattern fail.  */
@@ -4483,12 +4516,11 @@ static int max_labelno_before_reorg;
 static rtx_code_label *
 add_constant (rtx x, machine_mode mode, rtx last_value)
 {
-  int i;
   rtx_code_label *lab, *new_rtx;
   label_ref_list_t ref, newref;
 
   /* First see if we've already got it.  */
-  for (i = 0; i < pool_size; i++)
+  for (int i = 0; i < pool_size; i++)
     {
       if (x->code == pool_vector[i].value->code
          && mode == pool_vector[i].mode)
@@ -4562,15 +4594,14 @@ static void
 dump_table (rtx_insn *start, rtx_insn *barrier)
 {
   rtx_insn *scan = barrier;
-  int i;
   bool need_align = true;
-  rtx lab;
+  rtx_code_label *lab;
   label_ref_list_t ref;
   bool have_df = false;
 
   /* Do two passes, first time dump out the HI sized constants.  */
 
-  for (i = 0; i < pool_size; i++)
+  for (int i = 0; i < pool_size; i++)
     {
       pool_node *p = &pool_vector[i];
 
@@ -4581,7 +4612,8 @@ dump_table (rtx_insn *start, rtx_insn *barrier)
              scan = emit_insn_after (gen_align_2 (), scan);
              need_align = false;
            }
-         for (lab = p->label; lab; lab = LABEL_REFS (lab))
+         for (lab = p->label; lab;
+              lab = safe_as_a <rtx_code_label *> (LABEL_REFS (lab)))
            scan = emit_label_after (lab, scan);
          scan = emit_insn_after (gen_consttable_2 (p->value, const0_rtx),
                                  scan);
@@ -4608,7 +4640,7 @@ dump_table (rtx_insn *start, rtx_insn *barrier)
            rtx src = SET_SRC (XVECEXP (PATTERN (start), 0, 0));
            rtx lab = XEXP (XVECEXP (src, 0, 3), 0);
 
-           scan = emit_label_after (lab, scan);
+           scan = emit_label_after (as_a <rtx_insn *> (lab), scan);
          }
     }
   if (TARGET_FMOVD && TARGET_ALIGN_DOUBLE && have_df)
@@ -4619,19 +4651,20 @@ dump_table (rtx_insn *start, rtx_insn *barrier)
       scan = emit_insn_after (gen_align_log (GEN_INT (3)), scan);
       need_align = false;
 
-      for (i = 0; i < pool_size; i++)
+      for (int i = 0; i < pool_size; i++)
        {
          pool_node *p = &pool_vector[i];
 
          switch (p->mode)
            {
-           case HImode:
+           case E_HImode:
              break;
-           case SImode:
-           case SFmode:
+           case E_SImode:
+           case E_SFmode:
              if (align_insn && !p->part_of_sequence_p)
                {
-                 for (lab = p->label; lab; lab = LABEL_REFS (lab))
+                 for (lab = p->label; lab;
+                      lab = safe_as_a <rtx_code_label *> (LABEL_REFS (lab)))
                    emit_label_before (lab, align_insn);
                  emit_insn_before (gen_consttable_4 (p->value, const0_rtx),
                                    align_insn);
@@ -4647,22 +4680,25 @@ dump_table (rtx_insn *start, rtx_insn *barrier)
                }
              else
                {
-                 for (lab = p->label; lab; lab = LABEL_REFS (lab))
+                 for (lab = p->label; lab;
+                      lab = safe_as_a <rtx_code_label *> (LABEL_REFS (lab)))
                    scan = emit_label_after (lab, scan);
                  scan = emit_insn_after (gen_consttable_4 (p->value,
                                                            const0_rtx), scan);
                  need_align = ! need_align;
                }
              break;
-           case DFmode:
+           case E_DFmode:
              if (need_align)
                {
                  scan = emit_insn_after (gen_align_log (GEN_INT (3)), scan);
                  align_insn = scan;
                  need_align = false;
                }
-           case DImode:
-             for (lab = p->label; lab; lab = LABEL_REFS (lab))
+             /* FALLTHRU */
+           case E_DImode:
+             for (lab = p->label; lab;
+                  lab = safe_as_a <rtx_code_label *> (LABEL_REFS (lab)))
                scan = emit_label_after (lab, scan);
              scan = emit_insn_after (gen_consttable_8 (p->value, const0_rtx),
                                      scan);
@@ -4685,36 +4721,38 @@ dump_table (rtx_insn *start, rtx_insn *barrier)
       pool_size = 0;
     }
 
-  for (i = 0; i < pool_size; i++)
+  for (int i = 0; i < pool_size; i++)
     {
       pool_node *p = &pool_vector[i];
 
       switch (p->mode)
        {
-       case HImode:
+       case E_HImode:
          break;
-       case SImode:
-       case SFmode:
+       case E_SImode:
+       case E_SFmode:
          if (need_align)
            {
              need_align = false;
              scan = emit_label_after (gen_label_rtx (), scan);
              scan = emit_insn_after (gen_align_4 (), scan);
            }
-         for (lab = p->label; lab; lab = LABEL_REFS (lab))
+         for (lab = p->label; lab;
+              lab = safe_as_a <rtx_code_label *> (LABEL_REFS (lab)))
            scan = emit_label_after (lab, scan);
          scan = emit_insn_after (gen_consttable_4 (p->value, const0_rtx),
                                  scan);
          break;
-       case DFmode:
-       case DImode:
+       case E_DFmode:
+       case E_DImode:
          if (need_align)
            {
              need_align = false;
              scan = emit_label_after (gen_label_rtx (), scan);
              scan = emit_insn_after (gen_align_4 (), scan);
            }
-         for (lab = p->label; lab; lab = LABEL_REFS (lab))
+         for (lab = p->label; lab;
+              lab = safe_as_a <rtx_code_label *> (LABEL_REFS (lab)))
            scan = emit_label_after (lab, scan);
          scan = emit_insn_after (gen_consttable_8 (p->value, const0_rtx),
                                  scan);
@@ -4951,7 +4989,7 @@ find_barrier (int num_mova, rtx_insn *mova, rtx_insn *from)
          && CODE_LABEL_NUMBER (from) <= max_labelno_before_reorg)
        {
          if (optimize)
-           new_align = 1 << label_to_alignment (from);
+           new_align = 1 << label_to_alignment (from).levels[0].log;
          else if (BARRIER_P (prev_nonnote_insn (from)))
            new_align = 1 << barrier_align (from);
          else
@@ -5083,7 +5121,7 @@ find_barrier (int num_mova, rtx_insn *mova, rtx_insn *from)
                  && (prev_nonnote_insn (from)
                      == XEXP (MOVA_LABELREF (mova), 0))))
            num_mova--;
-         if (barrier_align (next_real_insn (from)) == align_jumps_log)
+         if (barrier_align (next_real_insn (from)) == align_jumps.levels[0].log)
            {
              /* We have just passed the barrier in front of the
                 ADDR_DIFF_VEC, which is stored in found_barrier.  Since
@@ -5205,18 +5243,22 @@ find_barrier (int num_mova, rtx_insn *mova, rtx_insn *from)
         around the constant pool table will be hit.  Putting it before
         a jump makes it more likely that the bra delay slot will be
         filled.  */
-      while (NOTE_P (from) || JUMP_P (from)
-            || LABEL_P (from))
+      while (NOTE_P (from) || JUMP_P (from) || LABEL_P (from))
        from = PREV_INSN (from);
 
-      /* Make sure we do not split between a call and its corresponding
-        CALL_ARG_LOCATION note.  */
       if (CALL_P (from))
        {
-         rtx_insn *next = NEXT_INSN (from);
-         if (next && NOTE_P (next)
-             && NOTE_KIND (next) == NOTE_INSN_CALL_ARG_LOCATION)
-           from = next;
+         bool sibcall_p = SIBLING_CALL_P (from);
+
+         /* If FROM was a sibling call, then we know that control
+            will not return.  In fact, we were guaranteed to hit
+            a barrier before another real insn.
+
+            The jump around the constant pool is unnecessary.  It
+            costs space, but more importantly it confuses dwarf2cfi
+            generation.  */
+         if (sibcall_p)
+           return emit_barrier_after (from);
        }
 
       from = emit_jump_insn_after (gen_jump (label), from);
@@ -5254,7 +5296,7 @@ sfunc_uses_reg (rtx_insn *insn)
   if (! reg_part)
     return NULL_RTX;
   reg = XEXP (reg_part, 0);
-  for (i = XVECLEN (pattern, 0) - 1; i >= 0; i--)
+  for (int i = XVECLEN (pattern, 0) - 1; i >= 0; i--)
     {
       part = XVECEXP (pattern, 0, i);
       if (part == reg_part || GET_CODE (part) == CLOBBER)
@@ -5273,14 +5315,12 @@ sfunc_uses_reg (rtx_insn *insn)
 static bool
 noncall_uses_reg (rtx reg, rtx_insn *insn, rtx *set)
 {
-  rtx pattern, reg2;
-
   *set = NULL_RTX;
 
-  reg2 = sfunc_uses_reg (insn);
+  rtx reg2 = sfunc_uses_reg (insn);
   if (reg2 && REGNO (reg2) == REGNO (reg))
     {
-      pattern = single_set (insn);
+      rtx pattern = single_set (insn);
       if (pattern
          && REG_P (SET_DEST (pattern))
          && REGNO (reg) == REGNO (SET_DEST (pattern)))
@@ -5291,7 +5331,7 @@ noncall_uses_reg (rtx reg, rtx_insn *insn, rtx *set)
     {
       /* We don't use rtx_equal_p because we don't care if the mode is
         different.  */
-      pattern = single_set (insn);
+      rtx pattern = single_set (insn);
       if (pattern
          && REG_P (SET_DEST (pattern))
          && REGNO (reg) == REGNO (SET_DEST (pattern)))
@@ -5314,13 +5354,11 @@ noncall_uses_reg (rtx reg, rtx_insn *insn, rtx *set)
       return true;
     }
 
-  pattern = PATTERN (insn);
+  rtx pattern = PATTERN (insn);
 
   if (GET_CODE (pattern) == PARALLEL)
     {
-      int i;
-
-      for (i = XVECLEN (pattern, 0) - 1; i >= 1; i--)
+      for (int i = XVECLEN (pattern, 0) - 1; i >= 1; i--)
        if (reg_mentioned_p (reg, XVECEXP (pattern, 0, i)))
          return true;
       pattern = XVECEXP (pattern, 0, 0);
@@ -5360,7 +5398,7 @@ regs_used (rtx x, int is_dest)
 {
   enum rtx_code code;
   const char *fmt;
-  int i, used = 0;
+  int used = 0;
 
   if (! x)
     return used;
@@ -5369,7 +5407,7 @@ regs_used (rtx x, int is_dest)
     {
     case REG:
       if (REGNO (x) < 16)
-       return (((1 << HARD_REGNO_NREGS (0, GET_MODE (x))) - 1)
+       return (((1 << hard_regno_nregs (0, GET_MODE (x))) - 1)
                << (REGNO (x) + is_dest));
       return 0;
     case SUBREG:
@@ -5379,7 +5417,7 @@ regs_used (rtx x, int is_dest)
        if (!REG_P (y))
          break;
        if (REGNO (y) < 16)
-         return (((1 << HARD_REGNO_NREGS (0, GET_MODE (x))) - 1)
+         return (((1 << hard_regno_nregs (0, GET_MODE (x))) - 1)
                  << (REGNO (y) +
                      subreg_regno_offset (REGNO (y),
                                           GET_MODE (y),
@@ -5407,12 +5445,11 @@ regs_used (rtx x, int is_dest)
 
   fmt = GET_RTX_FORMAT (code);
 
-  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+  for (int i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
     {
       if (fmt[i] == 'E')
        {
-         int j;
-         for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+         for (int j = XVECLEN (x, i) - 1; j >= 0; j--)
            used |= regs_used (XVECEXP (x, i, j), is_dest);
        }
       else if (fmt[i] == 'e')
@@ -5435,7 +5472,6 @@ gen_block_redirect (rtx_insn *jump, int addr, int need_block)
 {
   int dead = 0;
   rtx_insn *prev = prev_nonnote_insn (jump);
-  rtx dest;
 
   /* First, check if we already have an instruction that satisfies our need.  */
   if (prev && NONJUMP_INSN_P (prev) && ! prev->deleted ())
@@ -5461,7 +5497,7 @@ gen_block_redirect (rtx_insn *jump, int addr, int need_block)
     }
   /* We can't use JUMP_LABEL here because it might be undefined
      when not optimizing.  */
-  dest = XEXP (SET_SRC (PATTERN (jump)), 0);
+  rtx dest = XEXP (SET_SRC (PATTERN (jump)), 0);
   /* If the branch is out of range, try to find a scratch register for it.  */
   if (optimize
       && (INSN_ADDRESSES (INSN_UID (dest)) - addr + (unsigned) 4092
@@ -5479,11 +5515,9 @@ gen_block_redirect (rtx_insn *jump, int addr, int need_block)
 
       for (scan = jump; (scan = PREV_INSN (scan)); )
        {
-         enum rtx_code code;
-
          if (scan->deleted ())
            continue;
-         code = GET_CODE (scan);
+         rtx_code code = GET_CODE (scan);
          if (code == CODE_LABEL || code == JUMP_INSN)
            break;
          if (code == INSN
@@ -5498,11 +5532,9 @@ gen_block_redirect (rtx_insn *jump, int addr, int need_block)
       for (used = dead = 0, scan = JUMP_LABEL_AS_INSN (jump);
           (scan = NEXT_INSN (scan)); )
        {
-         enum rtx_code code;
-
          if (scan->deleted ())
            continue;
-         code = GET_CODE (scan);
+         rtx_code code = GET_CODE (scan);
          if (INSN_P (scan))
            {
              used |= regs_used (PATTERN (scan), 0);
@@ -5534,7 +5566,8 @@ gen_block_redirect (rtx_insn *jump, int addr, int need_block)
 
   else if (optimize && need_block >= 0)
     {
-      rtx_insn *next = next_active_insn (next_active_insn (dest));
+      rtx_insn *next = next_active_insn (as_a<rtx_insn *> (dest));
+      next = next_active_insn (next);
       if (next && JUMP_P (next)
          && GET_CODE (PATTERN (next)) == SET
          && recog_memoized (next) == CODE_FOR_jump_compact)
@@ -5598,15 +5631,14 @@ struct far_branch
   int address;
 };
 
-static void gen_far_branch (struct far_branch *);
 enum mdep_reorg_phase_e mdep_reorg_phase;
+
 static void
 gen_far_branch (struct far_branch *bp)
 {
   rtx_insn *insn = bp->insert_place;
   rtx_jump_insn *jump;
   rtx_code_label *label = gen_label_rtx ();
-  int ok;
 
   emit_label_after (label, insn);
   if (bp->far_label)
@@ -5635,7 +5667,7 @@ gen_far_branch (struct far_branch *bp)
       JUMP_LABEL (jump) = pat;
     }
 
-  ok = invert_jump (as_a <rtx_jump_insn *> (insn), label, 1);
+  bool ok = invert_jump (as_a <rtx_jump_insn *> (insn), label, 1);
   gcc_assert (ok);
 
   /* If we are branching around a jump (rather than a return), prevent
@@ -5692,7 +5724,7 @@ fixup_addr_diff_vecs (rtx_insn *first)
       /* Emit the reference label of the braf where it belongs, right after
         the casesi_jump_2 (i.e. braf).  */
       braf_label = XEXP (XEXP (SET_SRC (XVECEXP (prevpat, 0, 0)), 1), 0);
-      emit_label_after (braf_label, prev);
+      emit_label_after (as_a <rtx_insn *> (braf_label), prev);
 
       /* Fix up the ADDR_DIF_VEC to be relative
         to the reference address of the braf.  */
@@ -5705,8 +5737,6 @@ fixup_addr_diff_vecs (rtx_insn *first)
 int
 barrier_align (rtx_insn *barrier_or_label)
 {
-  rtx next, pat;
-
   if (! barrier_or_label)
     return 0;
 
@@ -5719,21 +5749,21 @@ barrier_align (rtx_insn *barrier_or_label)
       && PREV_INSN (barrier_or_label)
       && JUMP_TABLE_DATA_P (PREV_INSN (barrier_or_label)))
     {
-      pat = PATTERN (PREV_INSN (barrier_or_label));
+      rtx pat = PATTERN (PREV_INSN (barrier_or_label));
       /* If this is a very small table, we want to keep the alignment after
         the table to the minimum for proper code alignment.  */
       return ((optimize_size
               || ((unsigned) XVECLEN (pat, 1) * GET_MODE_SIZE (GET_MODE (pat))
                   <= (unsigned) 1 << (CACHE_LOG - 2)))
-             ? 1 : align_jumps_log);
+             ? 1 : align_jumps.levels[0].log);
     }
 
-  next = next_active_insn (barrier_or_label);
+  rtx_insn *next = next_active_insn (barrier_or_label);
 
   if (! next)
     return 0;
 
-  pat = PATTERN (next);
+  rtx pat = PATTERN (next);
 
   if (GET_CODE (pat) == UNSPEC_VOLATILE && XINT (pat, 1) == UNSPECV_ALIGN)
     /* This is a barrier in front of a constant table.  */
@@ -5743,7 +5773,7 @@ barrier_align (rtx_insn *barrier_or_label)
     return 0;
 
   if (! TARGET_SH2 || ! optimize)
-    return align_jumps_log;
+    return align_jumps.levels[0].log;
 
   /* When fixing up pcloads, a constant table might be inserted just before
      the basic block that ends with the barrier.  Thus, we can't trust the
@@ -5798,7 +5828,7 @@ barrier_align (rtx_insn *barrier_or_label)
        {
          rtx_insn *x;
          if (jump_to_next
-             || next_real_insn (JUMP_LABEL (prev)) == next
+             || next_real_insn (JUMP_LABEL_AS_INSN (prev)) == next
              /* If relax_delay_slots() decides NEXT was redundant
                 with some previous instruction, it will have
                 redirected PREV's jump to the following insn.  */
@@ -5821,7 +5851,7 @@ barrier_align (rtx_insn *barrier_or_label)
        }
     }
 
-  return align_jumps_log;
+  return align_jumps.levels[0].log;
 }
 
 /* If we are inside a phony loop, almost any kind of label can turn up as the
@@ -5847,7 +5877,7 @@ sh_loop_align (rtx_insn *label)
       || recog_memoized (next) == CODE_FOR_consttable_2)
     return 0;
 
-  return align_loops_log;
+  return align_loops.levels[0].log;
 }
 
 /* Do a final pass over the function, just before delayed branch
@@ -6298,14 +6328,14 @@ sh_reorg (void)
 
 /* Return the UID of the insn that follows the specified label.  */
 int
-get_dest_uid (rtx label, int max_uid)
+get_dest_uid (rtx_insn *label, int max_uid)
 {
   rtx_insn *dest = next_real_insn (label);
-  int dest_uid;
+
   if (! dest)
     /* This can happen for an undefined label.  */
     return 0;
-  dest_uid = INSN_UID (dest);
+  int dest_uid = INSN_UID (dest);
   /* If this is a newly created branch redirection blocking instruction,
      we cannot index the branch_uid or insn_addresses arrays with its
      uid.  But then, we won't need to, because the actual destination is
@@ -6358,7 +6388,7 @@ split_branches (rtx_insn *first)
            if (get_attr_length (insn) > 4)
              {
                rtx src = SET_SRC (PATTERN (insn));
-               rtx olabel = XEXP (XEXP (src, 1), 0);
+               rtx_insn *olabel = safe_as_a <rtx_insn *> (XEXP (XEXP (src, 1), 0));
                int addr = INSN_ADDRESSES (INSN_UID (insn));
                rtx_insn *label = 0;
                int dest_uid = get_dest_uid (olabel, max_uid);
@@ -6429,9 +6459,8 @@ split_branches (rtx_insn *first)
                /* We can't use JUMP_LABEL here because it might be undefined
                   when not optimizing.  */
                /* A syntax error might cause beyond to be NULL_RTX.  */
-               beyond
-                 = next_active_insn (XEXP (XEXP (SET_SRC (PATTERN (insn)), 1),
-                                           0));
+               rtx temp = XEXP (XEXP (SET_SRC (PATTERN (insn)), 1), 0);
+               beyond = next_active_insn (as_a<rtx_insn *> (temp));
 
                if (beyond
                    && (JUMP_P (beyond)
@@ -6564,14 +6593,9 @@ final_prescan_insn (rtx_insn *insn, rtx *opvec ATTRIBUTE_UNUSED,
 
   if (TARGET_RELAX)
     {
-      rtx note;
-
-      note = find_reg_note (insn, REG_LABEL_OPERAND, NULL_RTX);
-      if (note)
+      if (rtx note = find_reg_note (insn, REG_LABEL_OPERAND, NULL_RTX))
        {
-         rtx pattern;
-
-         pattern = PATTERN (insn);
+         rtx pattern = PATTERN (insn);
          if (GET_CODE (pattern) == PARALLEL)
            pattern = XVECEXP (pattern, 0, 0);
          switch (GET_CODE (pattern))
@@ -6584,7 +6608,7 @@ final_prescan_insn (rtx_insn *insn, rtx *opvec ATTRIBUTE_UNUSED,
                    (asm_out_file, "L", CODE_LABEL_NUMBER (XEXP (note, 0)));
                  break;
                }
-             /* else FALLTHROUGH */
+             /* FALLTHROUGH */
            case CALL:
              asm_fprintf (asm_out_file, "\t.uses %LL%d\n",
                           CODE_LABEL_NUMBER (XEXP (note, 0)));
@@ -6602,12 +6626,10 @@ final_prescan_insn (rtx_insn *insn, rtx *opvec ATTRIBUTE_UNUSED,
 const char *
 output_jump_label_table (void)
 {
-  int i;
-
   if (pool_size)
     {
       fprintf (asm_out_file, "\t.align 2\n");
-      for (i = 0; i < pool_size; i++)
+      for (int i = 0; i < pool_size; i++)
        {
          pool_node *p = &pool_vector[i];
 
@@ -6652,7 +6674,7 @@ static void
 output_stack_adjust (int size, rtx reg, int epilogue_p,
                     HARD_REG_SET *live_regs_mask, bool frame_p)
 {
-  rtx_insn *(*emit_fn) (rtx) = frame_p ? &frame_insn : &emit_insn;
+  rtx_insn *(*emit_fn) (rtx) = frame_p ? &emit_frame_insn : &emit_insn;
   if (size)
     {
       HOST_WIDE_INT align = STACK_BOUNDARY / BITS_PER_UNIT;
@@ -6686,13 +6708,13 @@ output_stack_adjust (int size, rtx reg, int epilogue_p,
             to handle this case, so just die when we see it.  */
          if (epilogue_p < 0
              || current_function_interrupt
-             || ! call_really_used_regs[temp] || fixed_regs[temp])
+             || ! call_used_regs[temp] || fixed_regs[temp])
            temp = -1;
          if (temp < 0 && ! current_function_interrupt && epilogue_p >= 0)
            {
-             HARD_REG_SET temps;
-             COPY_HARD_REG_SET (temps, call_used_reg_set);
-             AND_COMPL_HARD_REG_SET (temps, call_fixed_reg_set);
+             HARD_REG_SET temps = (regs_invalidated_by_call
+                                   & ~fixed_reg_set
+                                   & savable_regs);
              if (epilogue_p > 0)
                {
                  int nreg = 0;
@@ -6701,7 +6723,7 @@ output_stack_adjust (int size, rtx reg, int epilogue_p,
                      machine_mode mode;
                      mode = GET_MODE (crtl->return_rtx);
                      if (BASE_RETURN_VALUE_REG (mode) == FIRST_RET_REG)
-                       nreg = HARD_REGNO_NREGS (FIRST_RET_REG, mode);
+                       nreg = hard_regno_nregs (FIRST_RET_REG, mode);
                    }
                  for (i = 0; i < nreg; i++)
                    CLEAR_HARD_REG_BIT (temps, FIRST_RET_REG + i);
@@ -6726,7 +6748,7 @@ output_stack_adjust (int size, rtx reg, int epilogue_p,
            {
              HARD_REG_SET temps;
 
-             COPY_HARD_REG_SET (temps, *live_regs_mask);
+             temps = *live_regs_mask;
              CLEAR_HARD_REG_BIT (temps, REGNO (reg));
              temp = scavenge_reg (&temps);
            }
@@ -6802,10 +6824,9 @@ output_stack_adjust (int size, rtx reg, int epilogue_p,
     }
 }
 
-/* Emit the specified insn and mark it as frame related.
-   FIXME: Rename this to emit_frame_insn.  */
+/* Emit the specified insn and mark it as frame related.  */
 static rtx_insn *
-frame_insn (rtx x)
+emit_frame_insn (rtx x)
 {
   rtx_insn *insn = emit_insn (x);
   RTX_FRAME_RELATED_P (insn) = 1;
@@ -6833,7 +6854,7 @@ push (int rn)
   else
     x = gen_push (gen_rtx_REG (SImode, rn));
 
-  x = frame_insn (x);
+  x = emit_frame_insn (x);
   add_reg_note (x, REG_INC, gen_rtx_REG (SImode, STACK_POINTER_REGNUM));
   return x;
 }
@@ -6876,15 +6897,15 @@ pop (int rn)
 
 /* Generate code to push the regs specified in the mask.  */
 static void
-push_regs (HARD_REG_SET *mask, int interrupt_handler)
+push_regs (HARD_REG_SET *mask, bool interrupt_handler)
 {
-  int i = interrupt_handler ? LAST_BANKED_REG + 1 : 0;
-  int skip_fpscr = 0;
+  bool skip_fpscr = false;
 
   /* 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 < FIRST_PSEUDO_REGISTER; i++)
+  for (int i = interrupt_handler ? LAST_BANKED_REG + 1 : 0;
+       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
@@ -6892,12 +6913,9 @@ push_regs (HARD_REG_SET *mask, int interrupt_handler)
       if (i == FIRST_FP_REG && interrupt_handler && TARGET_FMOVD
          && hard_reg_set_intersect_p (*mask, reg_class_contents[DF_REGS]))
        {
-         HARD_REG_SET unsaved;
-
          push (FPSCR_REG);
-         COMPL_HARD_REG_SET (unsaved, *mask);
-         fpscr_set_from_mem (NORMAL_MODE (FP_MODE), unsaved);
-         skip_fpscr = 1;
+         fpscr_set_from_mem (NORMAL_MODE (FP_MODE), ~*mask);
+         skip_fpscr = true;
        }
       if (i != PR_REG
          && (i != FPSCR_REG || ! skip_fpscr)
@@ -6923,7 +6941,7 @@ push_regs (HARD_REG_SET *mask, int interrupt_handler)
        {
          unsigned int count = 0;
 
-         for (i = FIRST_BANKED_REG; i <= LAST_BANKED_REG; i++)
+         for (int i = FIRST_BANKED_REG; i <= LAST_BANKED_REG; i++)
            if (TEST_HARD_REG_BIT (*mask, i))
              count++;
            else
@@ -6945,8 +6963,8 @@ push_regs (HARD_REG_SET *mask, int interrupt_handler)
             insns.  */
          emit_insn (gen_blockage ());
          x = gen_movml_push_banked (sp_reg);
-         x = frame_insn (x);
-         for (i = FIRST_BANKED_REG; i <= LAST_BANKED_REG; i++)
+         x = emit_frame_insn (x);
+         for (int i = FIRST_BANKED_REG; i <= LAST_BANKED_REG; i++)
            {
              mem = gen_rtx_MEM (SImode, plus_constant (Pmode, sp_reg, i * 4));
              reg = gen_rtx_REG (SImode, i);
@@ -6958,7 +6976,7 @@ push_regs (HARD_REG_SET *mask, int interrupt_handler)
          emit_insn (gen_blockage ());
        }
       else
-       for (i = FIRST_BANKED_REG; i <= LAST_BANKED_REG; i++)
+       for (int i = FIRST_BANKED_REG; i <= LAST_BANKED_REG; i++)
          if (TEST_HARD_REG_BIT (*mask, i))
            push (i);
     }
@@ -6978,11 +6996,9 @@ static int
 calc_live_regs (HARD_REG_SET *live_regs_mask)
 {
   unsigned int reg;
-  int count;
   tree attrs;
   bool interrupt_or_trapa_handler, trapa_handler, interrupt_handler;
   bool nosave_low_regs;
-  int pr_live, has_call;
 
   attrs = DECL_ATTRIBUTES (current_function_decl);
   interrupt_or_trapa_handler = sh_cfun_interrupt_handler_p ();
@@ -6996,9 +7012,9 @@ calc_live_regs (HARD_REG_SET *live_regs_mask)
     target_flags &= ~MASK_FPU_SINGLE;
   /* If we can save a lot of saves by switching to double mode, do that.  */
   else if (TARGET_FPU_DOUBLE && TARGET_FMOVD && TARGET_FPU_SINGLE)
-    for (count = 0, reg = FIRST_FP_REG; reg <= LAST_FP_REG; reg += 2)
+    for (int count = 0, reg = FIRST_FP_REG; reg <= LAST_FP_REG; reg += 2)
       if (df_regs_ever_live_p (reg) && df_regs_ever_live_p (reg+1)
-         && (! call_really_used_regs[reg]
+         && (! call_used_regs[reg]
              || interrupt_handler)
          && ++count > 2)
        {
@@ -7006,20 +7022,22 @@ calc_live_regs (HARD_REG_SET *live_regs_mask)
          break;
        }
 
-    {
-      rtx pr_initial = has_hard_reg_initial_val (Pmode, PR_REG);
-      pr_live = (pr_initial
+
+  rtx pr_initial = has_hard_reg_initial_val (Pmode, PR_REG);
+  bool pr_live = (pr_initial
                 ? (!REG_P (pr_initial)
                    || REGNO (pr_initial) != (PR_REG))
                 : df_regs_ever_live_p (PR_REG));
-      /* For Shcompact, if not optimizing, we end up with a memory reference
-        using the return address pointer for __builtin_return_address even
-        though there is no actual need to put the PR register on the stack.  */
-      pr_live |= df_regs_ever_live_p (RETURN_ADDRESS_POINTER_REGNUM);
-    }
+  /* For Shcompact, if not optimizing, we end up with a memory reference
+     using the return address pointer for __builtin_return_address even
+     though there is no actual need to put the PR register on the stack.  */
+  pr_live |= df_regs_ever_live_p (RETURN_ADDRESS_POINTER_REGNUM);
+
   /* Force PR to be live if the prologue has to call the SHmedia
      argument decoder or register saver.  */
-  has_call = pr_live;
+  bool has_call = pr_live;
+
+  int count;
   for (count = 0, reg = FIRST_PSEUDO_REGISTER; reg-- != 0; )
     {
       if (reg == PR_REG
@@ -7027,7 +7045,7 @@ calc_live_regs (HARD_REG_SET *live_regs_mask)
          : interrupt_handler
          ? (/* Need to save all the regs ever live.  */
             (df_regs_ever_live_p (reg)
-             || (call_really_used_regs[reg]
+             || (call_used_regs[reg]
                  && (! fixed_regs[reg] || reg == MACH_REG || reg == MACL_REG
                      || reg == PIC_OFFSET_TABLE_REGNUM)
                  && has_call))
@@ -7040,9 +7058,10 @@ calc_live_regs (HARD_REG_SET *live_regs_mask)
          : (/* Only push those regs which are used and need to be saved.  */
             (false)
             || (df_regs_ever_live_p (reg)
-                && ((!call_really_used_regs[reg]
+                && ((!call_used_regs[reg]
                      && !(reg != PIC_OFFSET_TABLE_REGNUM
-                          && fixed_regs[reg] && call_used_regs[reg]))
+                          && fixed_regs[reg]
+                          && call_used_or_fixed_reg_p (reg)))
                     || (trapa_handler && reg == FPSCR_REG && TARGET_FPU_ANY)))
             || (crtl->calls_eh_return
                 && (reg == EH_RETURN_DATA_REGNO (0)
@@ -7078,30 +7097,6 @@ calc_live_regs (HARD_REG_SET *live_regs_mask)
       if (nosave_low_regs && reg == R8_REG)
        break;
     }
-  /* If we have a target register optimization pass after prologue / epilogue
-     threading, we need to assume all target registers will be live even if
-     they aren't now.  */
-  if (flag_branch_target_load_optimize2 && TARGET_SAVE_ALL_TARGET_REGS)
-    for (reg = LAST_TARGET_REG; reg >= FIRST_TARGET_REG; reg--)
-      if ((! call_really_used_regs[reg] || interrupt_handler)
-         && ! TEST_HARD_REG_BIT (*live_regs_mask, reg))
-       {
-         SET_HARD_REG_BIT (*live_regs_mask, reg);
-         count += GET_MODE_SIZE (REGISTER_NATURAL_MODE (reg));
-       }
-  /* If this is an interrupt handler, we don't have any call-clobbered
-     registers we can conveniently use for target register save/restore.
-     Make sure we save at least one general purpose register when we need
-     to save target registers.  */
-  if (interrupt_handler
-      && hard_reg_set_intersect_p (*live_regs_mask,
-                                  reg_class_contents[TARGET_REGS])
-      && ! hard_reg_set_intersect_p (*live_regs_mask,
-                                    reg_class_contents[GENERAL_REGS]))
-    {
-      SET_HARD_REG_BIT (*live_regs_mask, R0_REG);
-      count += GET_MODE_SIZE (REGISTER_NATURAL_MODE (R0_REG));
-    }
 
   return count;
 }
@@ -7123,68 +7118,11 @@ rounded_frame_size (int pushed)
   return ((size + pushed + align - 1) & -align) - pushed;
 }
 
-/* Choose a call-clobbered target-branch register that remains
-   unchanged along the whole function.  We set it up as the return
-   value in the prologue.  */
-int
-sh_media_register_for_return (void)
-{
-  int regno;
-  int tr0_used;
-
-  if (! crtl->is_leaf)
-    return -1;
-  if (lookup_attribute ("interrupt_handler",
-                       DECL_ATTRIBUTES (current_function_decl)))
-    return -1;
-  if (sh_cfun_interrupt_handler_p ())
-    return -1;
-
-  tr0_used = flag_pic && df_regs_ever_live_p (PIC_OFFSET_TABLE_REGNUM);
-
-  for (regno = FIRST_TARGET_REG + tr0_used; regno <= LAST_TARGET_REG; regno++)
-    if (call_really_used_regs[regno] && ! df_regs_ever_live_p (regno))
-      return regno;
-
-  return -1;
-}
-
-/* The maximum registers we need to save are:
-   - 62 general purpose registers (r15 is stack pointer, r63 is zero)
-   - 32 floating point registers (for each pair, we save none,
-         one single precision value, or a double precision value).
-   -  8 target registers
-   -  add 1 entry for a delimiter.  */
-#define MAX_SAVED_REGS (62+32+8)
-
-typedef struct save_entry_s
-{
-  unsigned char reg;
-  unsigned char mode;
-  short offset;
-} save_entry;
-
-#define MAX_TEMPS 4
-
-/* There will be a delimiter entry with VOIDmode both at the start and the
-   end of a filled in schedule.  The end delimiter has the offset of the
-   save with the smallest (i.e. most negative) offset.  */
-typedef struct save_schedule_s
-{
-  save_entry entries[MAX_SAVED_REGS + 2];
-  int temps[MAX_TEMPS+1];
-} save_schedule;
-
 /* Expand code for the function prologue.  */
 void
 sh_expand_prologue (void)
 {
-  HARD_REG_SET live_regs_mask;
-  int d, i;
-  int d_rounding = 0;
   int save_flags = target_flags;
-  int pretend_args;
-  int stack_usage;
   tree sp_switch_attr
     = lookup_attribute ("sp_switch", DECL_ATTRIBUTES (current_function_decl));
 
@@ -7192,16 +7130,14 @@ 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 = crtl->args.pretend_args_size;
+  int pretend_args = crtl->args.pretend_args_size;
   if (TARGET_VARARGS_PRETEND_ARGS (current_function_decl)
       && (NPARM_REGS(SImode)
          > crtl->args.info.arg_count[(int) SH_ARG_INT]))
     pretend_args = 0;
 
-  output_stack_adjust (-pretend_args
-                      - crtl->args.info.stack_regs * 8,
-                      stack_pointer_rtx, 0, NULL, true);
-  stack_usage = pretend_args + crtl->args.info.stack_regs * 8;
+  output_stack_adjust (-pretend_args, stack_pointer_rtx, 0, NULL, true);
+  int stack_usage = pretend_args;
 
   /* Emit the code for SETUP_VARARGS.  */
   if (cfun->stdarg)
@@ -7209,7 +7145,7 @@ sh_expand_prologue (void)
       if (TARGET_VARARGS_PRETEND_ARGS (current_function_decl))
        {
          /* Push arg regs as if they'd been provided by caller in stack.  */
-         for (i = 0; i < NPARM_REGS(SImode); i++)
+         for (int i = 0; i < NPARM_REGS(SImode); i++)
            {
              int rn = NPARM_REGS(SImode) + FIRST_PARM_REG - i - 1;
 
@@ -7230,8 +7166,7 @@ sh_expand_prologue (void)
       /* The argument specifies a variable holding the address of the
         stack the interrupt function should switch to/from at entry/exit.  */
       tree arg = TREE_VALUE ( TREE_VALUE (sp_switch_attr));
-      const char *s
-       = ggc_strdup (TREE_STRING_POINTER (arg));
+      const char* s = ggc_strdup (TREE_STRING_POINTER (arg));
       rtx sp_switch = gen_rtx_SYMBOL_REF (Pmode, s);
 
       lab = add_constant (sp_switch, SImode, 0);
@@ -7240,7 +7175,8 @@ sh_expand_prologue (void)
       emit_insn (gen_sp_switch_1 (newsrc));
     }
 
-  d = calc_live_regs (&live_regs_mask);
+  HARD_REG_SET live_regs_mask;
+  int d = calc_live_regs (&live_regs_mask);
   /* ??? Maybe we could save some switching if we can move a mode switch
      that already happens to be at the function start into the prologue.  */
   if (target_flags != save_flags && ! current_function_interrupt)
@@ -7258,12 +7194,12 @@ sh_expand_prologue (void)
 
   target_flags = save_flags;
 
-  output_stack_adjust (-rounded_frame_size (d) + d_rounding,
+  output_stack_adjust (-rounded_frame_size (d),
                       stack_pointer_rtx, 0, NULL, true);
-  stack_usage += rounded_frame_size (d) - d_rounding;
+  stack_usage += rounded_frame_size (d);
 
   if (frame_pointer_needed)
-    frame_insn (GEN_MOV (hard_frame_pointer_rtx, stack_pointer_rtx));
+    emit_frame_insn (GEN_MOV (hard_frame_pointer_rtx, stack_pointer_rtx));
 
   /* If we are profiling, make sure no instructions are scheduled before
      the call to mcount.  Similarly if some call instructions are swapped
@@ -7280,19 +7216,15 @@ sh_expand_prologue (void)
 void
 sh_expand_epilogue (bool sibcall_p)
 {
-  HARD_REG_SET live_regs_mask;
-  int d, i;
-  int d_rounding = 0;
-
   int save_flags = target_flags;
-  int frame_size, save_size;
-  int fpscr_deferred = 0;
+  bool fpscr_deferred = false;
   int e = sibcall_p ? -1 : 1;
 
-  d = calc_live_regs (&live_regs_mask);
+  HARD_REG_SET live_regs_mask;
+  int d = calc_live_regs (&live_regs_mask);
 
-  save_size = d;
-  frame_size = rounded_frame_size (d);
+  int save_size = d;
+  int frame_size = rounded_frame_size (d);
 
   if (frame_pointer_needed)
     {
@@ -7307,7 +7239,7 @@ sh_expand_epilogue (bool sibcall_p)
         occur after the SP adjustment and clobber data in the local
         frame.  */
       emit_insn (gen_blockage ());
-      frame_insn (GEN_MOV (stack_pointer_rtx, hard_frame_pointer_rtx));
+      emit_frame_insn (GEN_MOV (stack_pointer_rtx, hard_frame_pointer_rtx));
     }
   else if (frame_size)
     {
@@ -7349,7 +7281,7 @@ sh_expand_epilogue (bool sibcall_p)
            {
              unsigned int count = 0;
 
-             for (i = FIRST_BANKED_REG; i <= LAST_BANKED_REG; i++)
+             for (int i = FIRST_BANKED_REG; i <= LAST_BANKED_REG; i++)
                if (TEST_HARD_REG_BIT (live_regs_mask, i))
                  count++;
                else
@@ -7373,7 +7305,7 @@ sh_expand_epilogue (bool sibcall_p)
              emit_insn (gen_blockage ());
            }
          else
-           for (i = LAST_BANKED_REG; i >= FIRST_BANKED_REG; i--)
+           for (int i = LAST_BANKED_REG; i >= FIRST_BANKED_REG; i--)
              if (TEST_HARD_REG_BIT (live_regs_mask, i))
                pop (i);
 
@@ -7382,14 +7314,14 @@ sh_expand_epilogue (bool sibcall_p)
       else
        last_reg = FIRST_PSEUDO_REGISTER;
 
-      for (i = 0; i < last_reg; i++)
+      for (int i = 0; i < last_reg; i++)
        {
          int j = (FIRST_PSEUDO_REGISTER - 1) - i;
 
          if (j == FPSCR_REG && current_function_interrupt && TARGET_FMOVD
              && hard_reg_set_intersect_p (live_regs_mask,
                                          reg_class_contents[DF_REGS]))
-           fpscr_deferred = 1;
+           fpscr_deferred = true;
          /* 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) 
@@ -7409,9 +7341,7 @@ sh_expand_epilogue (bool sibcall_p)
     emit_insn (gen_toggle_sz ());
   target_flags = save_flags;
 
-  output_stack_adjust (crtl->args.pretend_args_size
-                      + save_size + d_rounding
-                      + crtl->args.info.stack_regs * 8,
+  output_stack_adjust (crtl->args.pretend_args_size + save_size,
                       stack_pointer_rtx, e, NULL, true);
 
   if (crtl->calls_eh_return)
@@ -7423,9 +7353,6 @@ sh_expand_epilogue (bool sibcall_p)
     emit_insn (gen_sp_switch_2 ());
 
   /* Tell flow the insn that pops PR isn't dead.  */
-  /* PR_REG will never be live in SHmedia mode, and we don't need to
-     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_use (gen_rtx_REG (SImode, PR_REG));
 }
@@ -7438,8 +7365,7 @@ sh_set_return_address (rtx ra, rtx tmp)
   HARD_REG_SET live_regs_mask;
   int d = calc_live_regs (&live_regs_mask);
 
-  /* If pr_reg isn't life, we can set it (or the register given in
-     sh_media_register_for_return) directly.  */
+  /* If pr_reg isn't life, we can set it directly.  */
   if (! TEST_HARD_REG_BIT (live_regs_mask, PR_REG))
     {
       rtx rr = gen_rtx_REG (SImode, PR_REG);
@@ -7466,8 +7392,7 @@ sh_set_return_address (rtx ra, rtx tmp)
 
 /* Clear variables at function end.  */
 static void
-sh_output_function_epilogue (FILE *file ATTRIBUTE_UNUSED,
-                            HOST_WIDE_INT size ATTRIBUTE_UNUSED)
+sh_output_function_epilogue (FILE *)
 {
 }
 
@@ -7486,9 +7411,9 @@ sh_builtin_saveregs (void)
   int bufsize, regno;
   alias_set_type alias_set;
 
-  if (! TARGET_SH2E && ! TARGET_SH4)
+  if (!TARGET_FPU_ANY)
     {
-      error ("__builtin_saveregs not supported by this subtarget");
+      error ("%<__builtin_saveregs%> not supported by this subtarget");
       return const0_rtx;
     }
 
@@ -7727,30 +7652,25 @@ static tree
 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;
+  tree tmp;
   tree addr, lab_over = NULL, result = NULL;
-  bool pass_by_ref;
   tree eff_type;
 
-  if (!VOID_TYPE_P (type))
-    pass_by_ref = targetm.calls.must_pass_in_stack (TYPE_MODE (type), type);
-  else
-    pass_by_ref = false;
+  const bool pass_by_ref
+    = !VOID_TYPE_P (type) && must_pass_va_arg_in_stack (type);
 
   if (pass_by_ref)
     type = build_pointer_type (type);
 
-  size = int_size_in_bytes (type);
-  rsize = (size + UNITS_PER_WORD - 1) & -UNITS_PER_WORD;
-  pptr_type_node = build_pointer_type (ptr_type_node);
+  HOST_WIDE_INT size = int_size_in_bytes (type);
+  HOST_WIDE_INT rsize = (size + UNITS_PER_WORD - 1) & -UNITS_PER_WORD;
+  tree pptr_type_node = build_pointer_type (ptr_type_node);
 
   if ((TARGET_SH2E || TARGET_SH4)
       && ! (TARGET_HITACHI || sh_cfun_attr_renesas_p ()))
     {
       tree f_next_o, f_next_o_limit, f_next_fp, f_next_fp_limit, f_next_stack;
       tree next_o, next_o_limit, next_fp, next_fp_limit, next_stack;
-      int pass_as_float;
       tree lab_false;
       tree member;
 
@@ -7795,6 +7715,7 @@ sh_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p,
            }
        }
 
+      bool pass_as_float;
       if (TARGET_FPU_DOUBLE)
        {
          pass_as_float = ((TREE_CODE (eff_type) == REAL_TYPE && size <= 8)
@@ -7979,12 +7900,11 @@ sh_promote_prototypes (const_tree type)
 }
 
 static bool
-sh_pass_by_reference (cumulative_args_t cum_v, machine_mode mode,
-                     const_tree type, bool named ATTRIBUTE_UNUSED)
+sh_pass_by_reference (cumulative_args_t cum_v, const function_arg_info &arg)
 {
   CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
 
-  if (targetm.calls.must_pass_in_stack (mode, type))
+  if (targetm.calls.must_pass_in_stack (arg))
     return true;
 
   /* ??? std_gimplify_va_arg_expr passes NULL for cum.  That function
@@ -7997,17 +7917,32 @@ sh_pass_by_reference (cumulative_args_t cum_v, machine_mode mode,
 }
 
 static bool
-sh_callee_copies (cumulative_args_t cum, machine_mode mode,
-                 const_tree type, bool named ATTRIBUTE_UNUSED)
+sh_callee_copies (cumulative_args_t cum, const function_arg_info &arg)
 {
   /* ??? How can it possibly be correct to return true only on the
      caller side of the equation?  Is there someplace else in the
      sh backend that's magically producing the copies?  */
   return (get_cumulative_args (cum)->outgoing
-         && ((mode == BLKmode ? TYPE_ALIGN (type) : GET_MODE_ALIGNMENT (mode))
+         && ((arg.mode == BLKmode
+              ? TYPE_ALIGN (arg.type)
+              : GET_MODE_ALIGNMENT (arg.mode))
              % SH_MIN_ALIGN_FOR_CALLEE_COPY == 0));
 }
 
+static sh_arg_class
+get_sh_arg_class (machine_mode mode)
+{
+  if (TARGET_FPU_ANY && mode == SFmode)
+    return SH_ARG_FLOAT;
+
+  if (TARGET_FPU_DOUBLE
+      && (GET_MODE_CLASS (mode) == MODE_FLOAT
+         || GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT))
+    return SH_ARG_FLOAT;
+
+  return SH_ARG_INT;
+}
+
 /* Round a register number up to a proper boundary for an arg of mode
    MODE.
    The SH doesn't care about double alignment, so we only
@@ -8023,9 +7958,9 @@ sh_round_reg (const CUMULATIVE_ARGS& cum, machine_mode mode)
          && (mode == DFmode || mode == DCmode)
          && cum.arg_count[(int) SH_ARG_FLOAT] < NPARM_REGS (mode)))
      && GET_MODE_UNIT_SIZE (mode) > UNITS_PER_WORD)
-    ? (cum.arg_count[(int) GET_SH_ARG_CLASS (mode)]
-       + (cum.arg_count[(int) GET_SH_ARG_CLASS (mode)] & 1))
-    : cum.arg_count[(int) GET_SH_ARG_CLASS (mode)]);
+    ? (cum.arg_count[(int) get_sh_arg_class (mode)]
+       + (cum.arg_count[(int) get_sh_arg_class (mode)] & 1))
+    : cum.arg_count[(int) get_sh_arg_class (mode)]);
 }
 
 /* Return true if arg of the specified mode should be passed in a register
@@ -8051,26 +7986,23 @@ sh_pass_in_reg_p (const CUMULATIVE_ARGS& cum, machine_mode mode,
              + int_size_in_bytes (type))
             <= NPARM_REGS (SImode) * UNITS_PER_WORD)
          : ((sh_round_reg (cum, mode)
-             + HARD_REGNO_NREGS (BASE_ARG_REG (mode), mode))
+             + sh_hard_regno_nregs (BASE_ARG_REG (mode), mode))
             <= NPARM_REGS (mode)))
        : sh_round_reg (cum, mode) < NPARM_REGS (mode)));
 }
 
 static int
-sh_arg_partial_bytes (cumulative_args_t cum_v, machine_mode mode,
-                     tree type, bool named ATTRIBUTE_UNUSED)
+sh_arg_partial_bytes (cumulative_args_t cum_v, const function_arg_info &arg)
 {
   CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
   int words = 0;
 
-  if (sh_pass_in_reg_p (*cum, mode, type)
+  if (sh_pass_in_reg_p (*cum, arg.mode, arg.type)
       && !TARGET_FPU_DOUBLE
-      && (sh_round_reg (*cum, mode)
-         + (mode != BLKmode
-            ? CEIL (GET_MODE_SIZE (mode), UNITS_PER_WORD)
-            : CEIL (int_size_in_bytes (type), UNITS_PER_WORD))
-         > NPARM_REGS (mode)))
-    words = NPARM_REGS (mode) - sh_round_reg (*cum, mode);
+      && (sh_round_reg (*cum, arg.mode)
+         + CEIL (arg.promoted_size_in_bytes (), UNITS_PER_WORD)
+         > NPARM_REGS (arg.mode)))
+    words = NPARM_REGS (arg.mode) - sh_round_reg (*cum, arg.mode);
 
   return words * UNITS_PER_WORD;
 }
@@ -8080,30 +8012,25 @@ sh_arg_partial_bytes (cumulative_args_t cum_v, machine_mode mode,
    Value is zero to push the argument on the stack,
    or a hard register in which to store the argument.
 
-   MODE is the argument's machine mode.
-   TYPE is the data type of the argument (as a tree).
-    This is null for libcalls where that information may
-    not be available.
    CUM is a variable of type CUMULATIVE_ARGS which gives info about
     the preceding args and about the function being called.
-   NAMED is nonzero if this argument is a named parameter
-    (otherwise it is an extra parameter matching an ellipsis).
+   ARG is a description of the argument.
 
    On SH the first args are normally in registers
    and the rest are pushed.  Any arg that starts within the first
    NPARM_REGS words is at least partially passed in a register unless
    its data type forbids.  */
 static rtx
-sh_function_arg (cumulative_args_t ca_v, machine_mode mode,
-                const_tree type, bool named)
+sh_function_arg (cumulative_args_t ca_v, const function_arg_info &arg)
 {
   CUMULATIVE_ARGS *ca = get_cumulative_args (ca_v);
+  machine_mode mode = arg.mode;
 
-  if (mode == VOIDmode)
+  if (arg.end_marker_p ())
     return ca->renesas_abi ? const1_rtx : const0_rtx;
 
-  if (sh_pass_in_reg_p (*ca, mode, type)
-      && (named || ! (TARGET_HITACHI || ca->renesas_abi)))
+  if (sh_pass_in_reg_p (*ca, mode, arg.type)
+      && (arg.named || ! (TARGET_HITACHI || ca->renesas_abi)))
     {
       int regno;
 
@@ -8142,23 +8069,20 @@ sh_function_arg (cumulative_args_t ca_v, machine_mode mode,
   return NULL_RTX;
 }
 
-/* Update the data in CUM to advance over an argument
-   of mode MODE and data type TYPE.
-   (TYPE is null for libcalls where that information may not be
-   available.)  */
+/* Update the data in CUM to advance over argument ARG.  */
 static void
-sh_function_arg_advance (cumulative_args_t ca_v, machine_mode mode,
-                        const_tree type, bool named ATTRIBUTE_UNUSED)
+sh_function_arg_advance (cumulative_args_t ca_v,
+                        const function_arg_info &arg)
 {
   CUMULATIVE_ARGS *ca = get_cumulative_args (ca_v);
 
   if (ca->force_mem)
-    ca->force_mem = 0;
+    ca->force_mem = false;
 
   if ((TARGET_HITACHI || ca->renesas_abi) && TARGET_FPU_DOUBLE)
     {
       /* Note that we've used the skipped register.  */
-      if (mode == SFmode && ca->free_single_fp_reg)
+      if (arg.mode == SFmode && ca->free_single_fp_reg)
        {
          ca->free_single_fp_reg = 0;
          return;
@@ -8167,21 +8091,19 @@ sh_function_arg_advance (cumulative_args_t ca_v, machine_mode mode,
         skipped in order to align the DF value.  We note this skipped
         register, because the next SF value will use it, and not the
         SF that follows the DF.  */
-      if (mode == DFmode
+      if (arg.mode == DFmode
          && sh_round_reg (*ca, DFmode) != sh_round_reg (*ca, SFmode))
        {
          ca->free_single_fp_reg = (sh_round_reg (*ca, SFmode)
-                                   + BASE_ARG_REG (mode));
+                                   + BASE_ARG_REG (arg.mode));
        }
     }
 
   if (! ((TARGET_SH4 || TARGET_SH2A) || ca->renesas_abi)
-      || sh_pass_in_reg_p (*ca, mode, type))
-    (ca->arg_count[(int) GET_SH_ARG_CLASS (mode)]
-     = (sh_round_reg (*ca, mode)
-       + (mode == BLKmode
-          ? CEIL (int_size_in_bytes (type), UNITS_PER_WORD)
-          : CEIL (GET_MODE_SIZE (mode), UNITS_PER_WORD))));
+      || sh_pass_in_reg_p (*ca, arg.mode, arg.type))
+    (ca->arg_count[(int) get_sh_arg_class (arg.mode)]
+     = (sh_round_reg (*ca, arg.mode)
+       + CEIL (arg.promoted_size_in_bytes (), UNITS_PER_WORD)));
 }
 
 /* The Renesas calling convention doesn't quite fit into this scheme since
@@ -8254,8 +8176,7 @@ sh_return_in_memory (const_tree type, const_tree fndecl)
    function that tell if a function uses varargs or stdarg.  */
 static void
 sh_setup_incoming_varargs (cumulative_args_t ca,
-                          machine_mode mode,
-                          tree type,
+                          const function_arg_info &arg,
                           int *pretend_arg_size,
                           int second_time ATTRIBUTE_UNUSED)
 {
@@ -8264,10 +8185,9 @@ sh_setup_incoming_varargs (cumulative_args_t ca,
     {
       int named_parm_regs, anon_parm_regs;
 
-      named_parm_regs = (sh_round_reg (*get_cumulative_args (ca), mode)
-                        + (mode == BLKmode
-                           ? CEIL (int_size_in_bytes (type), UNITS_PER_WORD)
-                           : CEIL (GET_MODE_SIZE (mode), UNITS_PER_WORD)));
+      named_parm_regs = (sh_round_reg (*get_cumulative_args (ca), arg.mode)
+                        + CEIL (arg.promoted_size_in_bytes (),
+                                UNITS_PER_WORD));
       anon_parm_regs = NPARM_REGS (SImode) - named_parm_regs;
       if (anon_parm_regs > 0)
        *pretend_arg_size = anon_parm_regs * 4;
@@ -8294,27 +8214,22 @@ sh_pretend_outgoing_varargs_named (cumulative_args_t ca_v)
 int
 initial_elimination_offset (int from, int to)
 {
-  int regs_saved;
-  int regs_saved_rounding = 0;
-  int total_saved_regs_space;
-  int total_auto_space;
+  const int regs_saved_rounding = 0;
   int save_flags = target_flags;
   HARD_REG_SET live_regs_mask;
 
-  regs_saved = calc_live_regs (&live_regs_mask);
+  int regs_saved = calc_live_regs (&live_regs_mask);
 
-  total_auto_space = rounded_frame_size (regs_saved) - regs_saved_rounding;
+  int total_auto_space = rounded_frame_size (regs_saved) - regs_saved_rounding;
   target_flags = save_flags;
 
-  total_saved_regs_space = regs_saved + regs_saved_rounding;
+  int total_saved_regs_space = regs_saved + regs_saved_rounding;
 
   if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
-    return total_saved_regs_space + total_auto_space
-          + crtl->args.info.byref_regs * 8;
+    return total_saved_regs_space + total_auto_space;
 
   if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
-    return total_saved_regs_space + total_auto_space
-          + crtl->args.info.byref_regs * 8;
+    return total_saved_regs_space + total_auto_space;
 
   /* Initial gap between fp and sp is 0.  */
   if (from == HARD_FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
@@ -8336,39 +8251,34 @@ initial_elimination_offset (int from, int to)
 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);
+  char* str = strcpy ((char*)alloca (strlen (const_str) + 1), const_str);
 
   while (1)
     {
-      dash = strchr (str, '-');
+      char* dash = strchr (str, '-');
       if (!dash)
        {
-         warning (0, "value of -mfixed-range must have form REG1-REG2");
+         warning (0, "value of %<-mfixed-range%> must have form REG1-REG2");
          return;
        }
       *dash = '\0';
-      comma = strchr (dash + 1, ',');
+      char* comma = strchr (dash + 1, ',');
       if (comma)
        *comma = '\0';
 
-      first = decode_reg_name (str);
+      int first = decode_reg_name (str);
       if (first < 0)
        {
          warning (0, "unknown register name: %s", str);
          return;
        }
 
-      last = decode_reg_name (dash + 1);
+      int last = decode_reg_name (dash + 1);
       if (last < 0)
        {
          warning (0, "unknown register name: %s", dash + 1);
@@ -8383,8 +8293,8 @@ sh_fix_range (const char *const_str)
          return;
        }
 
-      for (i = first; i <= last; ++i)
-       fixed_regs[i] = call_used_regs[i] = 1;
+      for (int i = first; i <= last; ++i)
+       fixed_regs[i] = 1;
 
       if (!comma)
        break;
@@ -8398,8 +8308,6 @@ sh_fix_range (const char *const_str)
 static void
 sh_insert_attributes (tree node, tree *attributes)
 {
-  tree attrs;
-
   if (TREE_CODE (node) != FUNCTION_DECL)
     return;
 
@@ -8409,7 +8317,7 @@ sh_insert_attributes (tree node, tree *attributes)
 
   /* Append the attributes to the deferred attributes.  */
   *sh_deferred_function_attributes_tail = *attributes;
-  attrs = sh_deferred_function_attributes;
+  tree attrs = sh_deferred_function_attributes;
   if (!attrs)
     return;
 
@@ -8604,28 +8512,17 @@ sh2a_is_function_vector_call (rtx x)
 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);
+      tree 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);
-       }
+      for (tree list = SH_ATTRIBUTES (t); list; list = TREE_CHAIN (list))
+       if (is_attribute_p ("function_vector", TREE_PURPOSE (list)))
+         return TREE_INT_CST_LOW (TREE_VALUE (TREE_VALUE (list)));
 
       return 0;
     }
@@ -8703,8 +8600,7 @@ sh_attr_renesas_p (const_tree td)
     td = TREE_TYPE (td);
   if (td == error_mark_node)
     return false;
-  return (lookup_attribute ("renesas", TYPE_ATTRIBUTES (td))
-         != NULL_TREE);
+  return lookup_attribute ("renesas", TYPE_ATTRIBUTES (td)) != NULL_TREE;
 }
 
 /* True if __attribute__((renesas)) or -mrenesas, for the current
@@ -8730,18 +8626,13 @@ sh_cfun_interrupt_handler_p (void)
 bool
 sh2a_function_vector_p (tree func)
 {
-  tree list;
   if (TREE_CODE (func) != FUNCTION_DECL)
     return false;
 
-  list = SH_ATTRIBUTES (func);
-  while (list)
-    {
-      if (is_attribute_p ("function_vector", TREE_PURPOSE (list)))
-       return true;
+  for (tree list = SH_ATTRIBUTES (func); list; list = TREE_CHAIN (list))
+    if (is_attribute_p ("function_vector", get_attribute_name (list)))
+      return true;
 
-      list = TREE_CHAIN (list);
-    }
   return false;
 }
 
@@ -8801,12 +8692,10 @@ system_reg_operand (rtx op, machine_mode mode ATTRIBUTE_UNUSED)
 bool
 fp_zero_operand (rtx op)
 {
-  const REAL_VALUE_TYPE *r;
-
   if (GET_MODE (op) != SFmode)
     return false;
 
-  r = CONST_DOUBLE_REAL_VALUE (op);
+  const REAL_VALUE_TYPE* r = CONST_DOUBLE_REAL_VALUE (op);
   return real_equal (r, &dconst0) && ! REAL_VALUE_MINUS_ZERO (*r);
 }
 
@@ -8834,13 +8723,11 @@ static int
 branch_dest (rtx branch)
 {
   rtx dest = SET_SRC (PATTERN (branch));
-  int dest_uid;
 
   if (GET_CODE (dest) == IF_THEN_ELSE)
     dest = XEXP (dest, 1);
-  dest = XEXP (dest, 0);
-  dest_uid = INSN_UID (dest);
-  return INSN_ADDRESSES (dest_uid);
+
+  return INSN_ADDRESSES (INSN_UID (XEXP (dest, 0)));
 }
 \f
 /* Return nonzero if REG is not used after INSN.
@@ -8849,24 +8736,20 @@ branch_dest (rtx branch)
 bool
 reg_unused_after (rtx reg, rtx_insn *insn)
 {
-  enum rtx_code code;
-  rtx set;
-
   /* If the reg is set by this instruction, then it is safe for our
      case.  Disregard the case where this is a store to memory, since
      we are checking a register used in the store address.  */
-  set = single_set (insn);
+  rtx set = single_set (insn);
   if (set && !MEM_P (SET_DEST (set))
       && reg_overlap_mentioned_p (reg, SET_DEST (set)))
     return true;
 
   while ((insn = NEXT_INSN (insn)))
     {
-      rtx set;
       if (!INSN_P (insn))
        continue;
 
-      code = GET_CODE (insn);
+      rtx_code code = GET_CODE (insn);
 
 #if 0
       /* If this is a label that existed before reload, then the register
@@ -8888,10 +8771,9 @@ reg_unused_after (rtx reg, rtx_insn *insn)
       else if (code == INSN && GET_CODE (PATTERN (insn)) == SEQUENCE)
        {
          rtx_sequence *seq = as_a <rtx_sequence *> (PATTERN (insn));
-         int i;
-         int retval = 0;
+         bool retval = false;
 
-         for (i = 0; i < seq->len (); i++)
+         for (int i = 0; i < seq->len (); i++)
            {
              rtx_insn *this_insn = seq->insn (i);
              rtx set = single_set (this_insn);
@@ -8918,21 +8800,21 @@ reg_unused_after (rtx reg, rtx_insn *insn)
                  && reg_overlap_mentioned_p (reg, PATTERN (this_insn)))
                return false;
            }
-         if (retval == 1)
+         if (retval)
            return true;
          else if (code == JUMP_INSN)
            return false;
        }
 
-      set = single_set (insn);
+      rtx set = single_set (insn);
       if (set && reg_overlap_mentioned_p (reg, SET_SRC (set)))
        return false;
       if (set && reg_overlap_mentioned_p (reg, SET_DEST (set)))
        return !MEM_P (SET_DEST (set));
-      if (set == 0 && reg_overlap_mentioned_p (reg, PATTERN (insn)))
+      if (set == NULL && reg_overlap_mentioned_p (reg, PATTERN (insn)))
        return false;
 
-      if (code == CALL_INSN && call_really_used_regs[REGNO (reg)])
+      if (code == CALL_INSN && call_used_regs[REGNO (reg)])
        return true;
     }
   return true;
@@ -8953,13 +8835,9 @@ static GTY(()) tree fpscr_values;
 static void
 emit_fpu_switch (rtx scratch, int index)
 {
-  rtx src;
-
   if (fpscr_values == NULL)
     {
-      tree t;
-
-      t = build_index_type (integer_one_node);
+      tree t = build_index_type (integer_one_node);
       t = build_array_type (integer_type_node, t);
       t = build_decl (BUILTINS_LOCATION,
                      VAR_DECL, get_identifier ("__fpscr_values"), t);
@@ -8973,7 +8851,7 @@ emit_fpu_switch (rtx scratch, int index)
       fpscr_values = t;
     }
 
-  src = DECL_RTL (fpscr_values);
+  rtx src = DECL_RTL (fpscr_values);
   if (!can_create_pseudo_p ())
     {
       emit_move_insn (scratch, XEXP (src, 0));
@@ -9021,9 +8899,8 @@ fpscr_set_from_mem (int mode, HARD_REG_SET regs_live)
 {
   enum attr_fp_mode fp_mode = (enum attr_fp_mode) mode;
   enum attr_fp_mode norm_mode = ACTUAL_NORMAL_MODE (FP_MODE);
-  rtx addr_reg;
 
-  addr_reg = !can_create_pseudo_p () ? get_free_reg (regs_live) : NULL_RTX;
+  rtx addr_reg = !can_create_pseudo_p () ? get_free_reg (regs_live) : NULL_RTX;
   emit_fpu_switch (addr_reg, fp_mode == norm_mode);
 }
 
@@ -9035,13 +8912,11 @@ fpscr_set_from_mem (int mode, HARD_REG_SET regs_live)
 static bool
 sequence_insn_p (rtx_insn *insn)
 {
-  rtx_insn *prev, *next;
-
-  prev = PREV_INSN (insn);
+  rtx_insn* prev = PREV_INSN (insn);
   if (prev == NULL)
     return false;
 
-  next = NEXT_INSN (prev);
+  rtx_insn* next = NEXT_INSN (prev);
   if (next == NULL)
     return false;
 
@@ -9205,9 +9080,6 @@ sh_legitimate_address_p (machine_mode mode, rtx x, bool strict)
 bool
 nonpic_symbol_mentioned_p (rtx x)
 {
-  const char *fmt;
-  int i;
-
   if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF
       || GET_CODE (x) == PC)
     return true;
@@ -9233,13 +9105,12 @@ nonpic_symbol_mentioned_p (rtx x)
          || XINT (x, 1) == UNSPEC_GOTOFFFUNCDESC))
     return false;
 
-  fmt = GET_RTX_FORMAT (GET_CODE (x));
-  for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
+  const char* fmt = GET_RTX_FORMAT (GET_CODE (x));
+  for (int i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
     {
       if (fmt[i] == 'E')
        {
-         int j;
-         for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+         for (int j = XVECLEN (x, i) - 1; j >= 0; j--)
            if (nonpic_symbol_mentioned_p (XVECEXP (x, i, j)))
              return true;
        }
@@ -9253,8 +9124,7 @@ nonpic_symbol_mentioned_p (rtx x)
 /* Convert a non-PIC address in `orig' to a PIC address using @GOT or
    @GOTOFF in `reg'.  */
 rtx
-legitimize_pic_address (rtx orig, machine_mode mode ATTRIBUTE_UNUSED,
-                       rtx reg)
+legitimize_pic_address (rtx orig, machine_mode mode ATTRIBUTE_UNUSED, rtx reg)
 {
   if (tls_symbolic_operand (orig, Pmode) != TLS_MODEL_NONE)
     return orig;
@@ -9470,16 +9340,14 @@ sh_legitimize_reload_address (rtx *p, machine_mode mode, int opnum,
 static rtx
 sh_delegitimize_address (rtx orig_x)
 {
-  rtx x, y;
-
   orig_x = delegitimize_mem_from_attrs (orig_x);
 
-  x = orig_x;
+  rtx x = orig_x;
   if (MEM_P (x))
     x = XEXP (x, 0);
   if (GET_CODE (x) == CONST)
     {
-      y = XEXP (x, 0);
+      rtx y = XEXP (x, 0);
       if (GET_CODE (y) == UNSPEC)
        {
          if (XINT (y, 1) == UNSPEC_GOT
@@ -9509,9 +9377,6 @@ sh_delegitimize_address (rtx orig_x)
 static rtx
 mark_constant_pool_use (rtx x)
 {
-  rtx_insn *insn, *lab;
-  rtx pattern;
-
   if (x == NULL_RTX)
     return x;
 
@@ -9527,8 +9392,8 @@ mark_constant_pool_use (rtx x)
 
   /* Get the first label in the list of labels for the same constant
      and delete another labels in the list.  */
-  lab = as_a <rtx_insn *> (x);
-  for (insn = PREV_INSN (lab); insn; insn = PREV_INSN (insn))
+  rtx_insn* lab = as_a <rtx_insn*> (x);
+  for (rtx_insn* insn = PREV_INSN (lab); insn; insn = PREV_INSN (insn))
     {
       if (!LABEL_P (insn)
          || LABEL_REFS (insn) != NEXT_INSN (insn))
@@ -9540,12 +9405,13 @@ mark_constant_pool_use (rtx x)
     as_a<rtx_insn *> (insn)->set_deleted ();
 
   /* Mark constants in a window.  */
-  for (insn = NEXT_INSN (as_a <rtx_insn *> (x)); insn; insn = NEXT_INSN (insn))
+  for (rtx_insn* insn = NEXT_INSN (as_a <rtx_insn *> (x)); insn;
+       insn = NEXT_INSN (insn))
     {
       if (!NONJUMP_INSN_P (insn))
        continue;
 
-      pattern = PATTERN (insn);
+      rtx pattern = PATTERN (insn);
       if (GET_CODE (pattern) != UNSPEC_VOLATILE)
        continue;
 
@@ -9633,21 +9499,18 @@ sh_hard_regno_rename_ok (unsigned int old_reg ATTRIBUTE_UNUSED,
    the same cost as a data-dependence.  The return value should be
    the new value for COST.  */
 static int
-sh_adjust_cost (rtx_insn *insn, rtx link ATTRIBUTE_UNUSED,
-               rtx_insn *dep_insn, int cost)
+sh_adjust_cost (rtx_insn *insn, int dep_type, rtx_insn *dep_insn, int cost,
+               unsigned int)
 {
   rtx reg, use_pat;
 
-  if (REG_NOTE_KIND (link) == 0)
+  if (dep_type == 0)
     {
-      enum attr_type type;
-      rtx dep_set;
-
       if (recog_memoized (insn) < 0
          || recog_memoized (dep_insn) < 0)
        return cost;
 
-      dep_set = single_set (dep_insn);
+      rtx dep_set = single_set (dep_insn);
 
       /* The latency that we specify in the scheduling description refers
         to the actual output, not to an auto-increment register; for that,
@@ -9693,8 +9556,8 @@ sh_adjust_cost (rtx_insn *insn, rtx link ATTRIBUTE_UNUSED,
        }
       if (TARGET_HARD_SH4 && !TARGET_SH4_300)
        {
-         enum attr_type dep_type = get_attr_type (dep_insn);
-
+         attr_type dep_type = get_attr_type (dep_insn);
+         attr_type type;
          if (dep_type == TYPE_FLOAD || dep_type == TYPE_PCFLOAD)
            cost--;
          else if ((dep_type == TYPE_LOAD_SI || dep_type == TYPE_PCLOAD_SI)
@@ -9734,6 +9597,7 @@ sh_adjust_cost (rtx_insn *insn, rtx link ATTRIBUTE_UNUSED,
       else if (TARGET_SH4_300)
        {
          /* Stores need their input register two cycles later.  */
+         attr_type type;
          if (dep_set && cost >= 1
              && ((type = get_attr_type (insn)) == TYPE_STORE
                  || type == TYPE_PSTORE
@@ -9757,7 +9621,7 @@ sh_adjust_cost (rtx_insn *insn, rtx link ATTRIBUTE_UNUSED,
   /* An anti-dependence penalty of two applies if the first insn is a double
      precision fadd / fsub / fmul.  */
   else if (!TARGET_SH4_300
-          && REG_NOTE_KIND (link) == REG_DEP_ANTI
+          && dep_type == REG_DEP_ANTI
           && recog_memoized (dep_insn) >= 0
           && (get_attr_type (dep_insn) == TYPE_DFP_ARITH
               || get_attr_type (dep_insn) == TYPE_DFP_MUL)
@@ -9772,11 +9636,11 @@ sh_adjust_cost (rtx_insn *insn, rtx link ATTRIBUTE_UNUSED,
 /* Check if INSN is flow-dependent on DEP_INSN.  Can also be used to check
    if DEP_INSN is anti-flow dependent on INSN.  */
 static bool
-flow_dependent_p (rtx insn, rtx dep_insn)
+flow_dependent_p (rtx_insn *insn, rtx_insn *dep_insn)
 {
   rtx tmp = PATTERN (insn);
 
-  note_stores (PATTERN (dep_insn), flow_dependent_p_1, &tmp);
+  note_stores (dep_insn, flow_dependent_p_1, &tmp);
   return tmp == NULL_RTX;
 }
 
@@ -9853,12 +9717,9 @@ find_set_regmode_weight (rtx x, machine_mode mode)
 static short
 find_insn_regmode_weight (rtx insn, machine_mode mode)
 {
-  short reg_weight = 0;
-  rtx x;
-
   /* Increment weight for each register born here.  */
-  x = PATTERN (insn);
-  reg_weight += find_set_regmode_weight (x, mode);
+  rtx x = PATTERN (insn);
+  short reg_weight = find_set_regmode_weight (x, mode);
   if (GET_CODE (x) == PARALLEL)
     {
       int j;
@@ -9953,27 +9814,24 @@ ready_reorder (rtx_insn **ready, int nready)
 static int
 find_r0_life_regions (basic_block b)
 {
-  rtx_insn *end, *insn;
-  rtx pset;
-  rtx r0_reg;
-  int live;
+  bool live;
   int set;
   int death = 0;
 
   if (REGNO_REG_SET_P (df_get_live_in (b), R0_REG))
     {
       set = 1;
-      live = 1;
+      live = true;
     }
   else
     {
       set = 0;
-      live = 0;
+      live = false;
     }
 
-  insn = BB_HEAD (b);
-  end = BB_END (b);
-  r0_reg = gen_rtx_REG (SImode, R0_REG);
+  rtx_insn* insn = BB_HEAD (b);
+  rtx_insn* end = BB_END (b);
+  rtx r0_reg = gen_rtx_REG (SImode, R0_REG);
   while (1)
     {
       if (INSN_P (insn))
@@ -9981,15 +9839,17 @@ find_r0_life_regions (basic_block b)
          if (find_regno_note (insn, REG_DEAD, R0_REG))
            {
              death++;
-             live = 0;
+             live = false;
            }
+
+         rtx pset;
          if (!live
              && (pset = single_set (insn))
              && reg_overlap_mentioned_p (r0_reg, SET_DEST (pset))
              && !find_regno_note (insn, REG_UNUSED, R0_REG))
            {
              set++;
-             live = 1;
+             live = true;
            }
        }
       if (insn == end)
@@ -10170,19 +10030,6 @@ sh_dfa_new_cycle (FILE *sched_dump ATTRIBUTE_UNUSED,
   return 0;
 }
 
-static reg_class_t
-sh_target_reg_class (void)
-{
-  return NO_REGS;
-}
-
-static bool
-sh_optimize_target_register_callee_saved (bool after_prologue_epilogue_gen
-                                         ATTRIBUTE_UNUSED)
-{
-  return false;
-}
-
 static bool
 sh_ms_bitfield_layout_p (const_tree record_type ATTRIBUTE_UNUSED)
 {
@@ -10269,7 +10116,7 @@ sh_trampoline_init (rtx tramp_mem, tree fndecl, rtx cxt)
          || (!(TARGET_SH4A || TARGET_SH4_300) && TARGET_USERMODE))
        emit_library_call (function_symbol (NULL, "__ic_invalidate",
                                            FUNCTION_ORDINARY).sym,
-                          LCT_NORMAL, VOIDmode, 1, tramp, SImode);
+                          LCT_NORMAL, VOIDmode, tramp, SImode);
       else
        emit_insn (gen_ic_invalidate_line (tramp));
     }
@@ -10282,10 +10129,6 @@ sh_trampoline_adjust_address (rtx tramp)
   return tramp;
 }
 
-/* FIXME: This is overly conservative.  A SHcompact function that
-   receives arguments ``by reference'' will have them stored in its
-   own stack frame, so it must not pass pointers or references to
-   these arguments to other functions by means of sibling calls.  */
 /* If PIC, we cannot make sibling calls to global functions
    because the PLT requires r12 to be live.  */
 static bool
@@ -10602,7 +10445,7 @@ sh_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
                   machine_mode mode ATTRIBUTE_UNUSED, int ignore)
 {
   tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
-  unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
+  unsigned int fcode = DECL_MD_FUNCTION_CODE (fndecl);
   const struct builtin_description *d = &bdesc[fcode];
   enum insn_code icode = d->icode;
   int signature = d->signature;
@@ -10625,15 +10468,14 @@ sh_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
 
   for (int i = 1; i <= 3; i++, nop++)
     {
-      tree arg;
-      machine_mode opmode, argmode;
-      tree optype;
-
       if (! signature_args[signature][i])
        break;
-      arg = CALL_EXPR_ARG (exp, i - 1);
+      tree arg = CALL_EXPR_ARG (exp, i - 1);
       if (arg == error_mark_node)
        return const0_rtx;
+
+      machine_mode opmode;
+      tree optype;
       if (signature_args[signature][i] & 8)
        {
          opmode = ptr_mode;
@@ -10644,7 +10486,8 @@ sh_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
          opmode = insn_data[icode].operand[nop].mode;
          optype = (*lang_hooks.types.type_for_mode) (opmode, 0);
        }
-      argmode = TYPE_MODE (TREE_TYPE (arg));
+
+      machine_mode argmode = TYPE_MODE (TREE_TYPE (arg));
       if (argmode != opmode)
        arg = build1 (NOP_EXPR, optype, arg);
       op[nop] = expand_expr (arg, NULL_RTX, opmode, EXPAND_NORMAL);
@@ -10677,7 +10520,19 @@ sh_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
   return target;
 }
 
-/* Return true if hard register REGNO can hold a value of machine-mode MODE.
+/* Implement TARGET_HARD_REGNO_NREGS.  On the SH all but the XD regs are
+   UNITS_PER_WORD bits wide.  */
+
+static unsigned int
+sh_hard_regno_nregs (unsigned int regno, machine_mode mode)
+{
+  if (XD_REGISTER_P (regno))
+    return CEIL (GET_MODE_SIZE (mode), 2 * UNITS_PER_WORD);
+  return CEIL (GET_MODE_SIZE (mode), UNITS_PER_WORD);
+}
+
+/* Implement TARGET_HARD_REGNO_MODE_OK.
+
    We can allow any mode in any general register.  The special registers
    only allow SImode.  Don't allow any mode in the PR.
 
@@ -10692,7 +10547,7 @@ sh_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
 
    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
+static bool
 sh_hard_regno_mode_ok (unsigned int regno, machine_mode mode)
 {
   if (SPECIAL_REGISTER_P (regno))
@@ -10742,9 +10597,6 @@ sh_hard_regno_mode_ok (unsigned int regno, machine_mode mode)
   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;
 
@@ -10754,8 +10606,24 @@ sh_hard_regno_mode_ok (unsigned int regno, machine_mode mode)
   return true;
 }
 
+/* Implement TARGET_MODES_TIEABLE_P.
+
+   If TARGET_HARD_REGNO_MODE_OK could produce different values for MODE1
+   and MODE2, for any hard reg, then this must be false for correct output.
+   That's the case for xd registers: we don't hold SFmode values in
+   them, so we can't tie an SFmode pseudos with one in another
+   floating-point mode.  */
+
+static bool
+sh_modes_tieable_p (machine_mode mode1, machine_mode mode2)
+{
+  return (mode1 == mode2
+         || (GET_MODE_CLASS (mode1) == GET_MODE_CLASS (mode2)
+             && (mode1 != SFmode && mode2 != SFmode)));
+}
+
 /* Specify the modes required to caller save a given hard regno.
-   choose_hard_reg_mode chooses mode based on HARD_REGNO_MODE_OK
+   choose_hard_reg_mode chooses mode based on TARGET_HARD_REGNO_MODE_OK
    and returns ?Imode for float regs when sh_hard_regno_mode_ok
    permits integer modes on them.  That makes LRA's split process
    unhappy.  See PR55212.
@@ -10771,14 +10639,13 @@ sh_hard_regno_caller_save_mode (unsigned int regno, unsigned int nregs,
              && ((regno - FIRST_FP_REG) & 1) == 0)))
     return mode;
 
-  return choose_hard_reg_mode (regno, nregs, false);
+  return choose_hard_reg_mode (regno, nregs, NULL);
 }
 
-/* Return the class of registers for which a mode change from FROM to TO
-   is invalid.  */
-bool
-sh_cannot_change_mode_class (machine_mode from, machine_mode to,
-                            enum reg_class rclass)
+/* Implement TARGET_CAN_CHANGE_MODE_CLASS.  */
+static bool
+sh_can_change_mode_class (machine_mode from, machine_mode to,
+                         reg_class_t rclass)
 {
   /* We want to enable the use of SUBREGs as a means to
      VEC_SELECT a single element of a vector.  */
@@ -10788,22 +10655,22 @@ sh_cannot_change_mode_class (machine_mode from, machine_mode to,
      on the stack with displacement addressing, as it happens with -O0.
      Thus we disallow the mode change for -O0.  */
   if (to == SFmode && VECTOR_MODE_P (from) && GET_MODE_INNER (from) == SFmode)
-    return optimize ? (reg_classes_intersect_p (GENERAL_REGS, rclass)) : false;
+    return optimize ? !reg_classes_intersect_p (GENERAL_REGS, rclass) : true;
 
   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, rclass);
+           return !reg_classes_intersect_p (DF_REGS, rclass);
        }
       else
        {
          if (GET_MODE_SIZE (from) < 8)
-           return reg_classes_intersect_p (DF_REGS, rclass);
+           return !reg_classes_intersect_p (DF_REGS, rclass);
        }
     }
-  return false;
+  return true;
 }
 
 /* Return true if registers in machine mode MODE will likely be
@@ -10886,10 +10753,6 @@ sh_register_move_cost (machine_mode mode,
          && (dstclass == PR_REGS || dstclass == MAC_REGS)))
     return 7;
 
-  if ((srcclass == TARGET_REGS && ! REGCLASS_HAS_GENERAL_REG (dstclass))
-      || ((dstclass) == TARGET_REGS && ! REGCLASS_HAS_GENERAL_REG (srcclass)))
-    return 20;
-
   if ((srcclass == FPSCR_REGS && ! REGCLASS_HAS_GENERAL_REG (dstclass))
       || (dstclass == FPSCR_REGS && ! REGCLASS_HAS_GENERAL_REG (srcclass)))
   return 4;
@@ -10917,6 +10780,7 @@ sh_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
                    HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset,
                    tree function)
 {
+  const char *fnname = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (thunk_fndecl));
   CUMULATIVE_ARGS cum;
   int structure_value_byref = 0;
   rtx this_rtx, this_value, sibcall, funexp;
@@ -10945,10 +10809,11 @@ sh_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
     {
       tree ptype = build_pointer_type (TREE_TYPE (funtype));
 
-      sh_function_arg_advance (pack_cumulative_args (&cum), Pmode, ptype, true);
+      function_arg_info ptr_arg (ptype, Pmode, /*named=*/true);
+      sh_function_arg_advance (pack_cumulative_args (&cum), ptr_arg);
     }
-  this_rtx
-    = sh_function_arg (pack_cumulative_args (&cum), Pmode, ptr_type_node, true);
+  function_arg_info ptr_arg (ptr_type_node, Pmode, /*named=*/true);
+  this_rtx = sh_function_arg (pack_cumulative_args (&cum), ptr_arg);
 
   /* 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
@@ -10956,16 +10821,16 @@ sh_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
      registers are used for argument passing, are callee-saved, or reserved.  */
   /* We need to check call_used_regs / fixed_regs in case -fcall_saved-reg /
      -ffixed-reg has been used.  */
-  if (! call_used_regs[0] || fixed_regs[0])
+  if (! call_used_or_fixed_reg_p (0) || fixed_regs[0])
     error ("r0 needs to be available as a call-clobbered register");
   scratch0 = scratch1 = scratch2 = gen_rtx_REG (Pmode, 0);
 
     {
-      if (call_used_regs[1] && ! fixed_regs[1])
+      if (call_used_or_fixed_reg_p (1) && ! fixed_regs[1])
        scratch1 = gen_rtx_REG (ptr_mode, 1);
       /* N.B., if not TARGET_HITACHI, register 2 is used to pass the pointer
         pointing where to return struct values.  */
-      if (call_used_regs[3] && ! fixed_regs[3])
+      if (call_used_or_fixed_reg_p (3) && ! fixed_regs[3])
        scratch2 = gen_rtx_REG (Pmode, 3);
     }
 
@@ -11012,12 +10877,6 @@ sh_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
          emit_insn (gen_add2_insn (scratch0, GEN_INT (vcall_offset)));
          offset_addr = scratch0;
        }
-      else if (scratch0 != scratch1)
-       {
-         emit_move_insn (scratch1, GEN_INT (vcall_offset));
-         emit_insn (gen_add2_insn (scratch0, scratch1));
-         offset_addr = scratch0;
-       }
       else
        gcc_unreachable (); /* FIXME */
       emit_load_ptr (scratch0, offset_addr);
@@ -11066,8 +10925,7 @@ sh_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
   emit_barrier ();
 
   /* Run just enough of rest_of_compilation to do scheduling and get
-     the insns emitted.  Note that use_thunk calls
-     assemble_start_function and assemble_end_function.  */
+     the insns emitted.  */
 
   insns = get_insns ();
 
@@ -11080,9 +10938,11 @@ sh_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
 
   sh_reorg ();
   shorten_branches (insns);
+  assemble_start_function (thunk_fndecl, fnname);
   final_start_function (insns, file, 1);
   final (insns, file, 1);
   final_end_function ();
+  assemble_end_function (thunk_fndecl, fnname);
 
   reload_completed = 0;
   epilogue_completed = 0;
@@ -11154,12 +11014,12 @@ function_symbol (rtx target, const char *name, sh_function_kind kind)
   return function_symbol_result (sym, lab);
 }
 
-/* Find the number of a general purpose register in S.  */
+/* Find the number of the first general purpose register in S that
+   is not set.  */
 static int
 scavenge_reg (HARD_REG_SET *s)
 {
-  int r;
-  for (r = FIRST_GENERAL_REG; r <= LAST_GENERAL_REG; r++)
+  for (int r = FIRST_GENERAL_REG; r <= LAST_GENERAL_REG; r++)
     if (TEST_HARD_REG_BIT (*s, r))
       return r;
   return -1;
@@ -11192,14 +11052,13 @@ sh_expand_t_scc (rtx operands[])
   rtx op0 = operands[2];
   rtx op1 = operands[3];
   rtx result = target;
-  HOST_WIDE_INT val;
 
   if (!REG_P (op0) || REGNO (op0) != T_REG
       || !CONST_INT_P (op1))
     return false;
   if (!REG_P (result))
     result = gen_reg_rtx (SImode);
-  val = INTVAL (op1);
+  HOST_WIDE_INT val = INTVAL (op1);
   if ((code == EQ && val == 1) || (code == NE && val == 0))
     emit_insn (gen_movt (result, get_t_reg_rtx ()));
   else if ((code == EQ && val == 0) || (code == NE && val == 1))
@@ -11217,14 +11076,11 @@ sh_expand_t_scc (rtx operands[])
 static rtx
 extract_sfunc_addr (rtx insn)
 {
-  rtx pattern, part = NULL_RTX;
-  int len, i;
-
-  pattern = PATTERN (insn);
-  len = XVECLEN (pattern, 0);
-  for (i = 0; i < len; i++)
+  rtx pattern = PATTERN (insn);
+  const int len = XVECLEN (pattern, 0);
+  for (int i = 0; i < len; i++)
     {
-      part = XVECEXP (pattern, 0, i);
+      rtx part = XVECEXP (pattern, 0, i);
       if (GET_CODE (part) == USE && GET_MODE (XEXP (part, 0)) == Pmode
          && GENERAL_REGISTER_P (true_regnum (XEXP (part, 0))))
        return XEXP (part, 0);
@@ -11309,13 +11165,10 @@ sh_init_cumulative_args (CUMULATIVE_ARGS *  pcum,
 {
   pcum->arg_count [(int) SH_ARG_FLOAT] = 0;
   pcum->free_single_fp_reg = 0;
-  pcum->stack_regs = 0;
-  pcum->byref_regs = 0;
-  pcum->byref = 0;
-  pcum->outgoing = (n_named_args == -1) ? 0 : 1;
+  pcum->outgoing = n_named_args != -1;
 
-  /* XXX - Should we check TARGET_HITACHI here ???  */
-  pcum->renesas_abi = sh_attr_renesas_p (fntype) ? 1 : 0;
+  /* FIXME: Should we check TARGET_HITACHI here ???  */
+  pcum->renesas_abi = sh_attr_renesas_p (fntype);
 
   if (fntype)
     {
@@ -11327,7 +11180,7 @@ sh_init_cumulative_args (CUMULATIVE_ARGS *  pcum,
   else
     {
       pcum->arg_count [(int) SH_ARG_INT] = 0;
-      pcum->prototype_p = FALSE;
+      pcum->prototype_p = false;
       if (mode != VOIDmode)
        {
          /* If the default ABI is the Renesas ABI then all library
@@ -11346,7 +11199,7 @@ sh_init_cumulative_args (CUMULATIVE_ARGS *  pcum,
                         && TARGET_FPU_DOUBLE)));
        }
       else
-       pcum->force_mem = FALSE;
+       pcum->force_mem = false;
     }
 }
 
@@ -11436,13 +11289,13 @@ sh_secondary_reload (bool in_p, rtx x, reg_class_t rclass_i,
          && ! ((fp_zero_operand (x) || fp_one_operand (x)) && mode == SFmode))
        switch (mode)
          {
-         case SFmode:
+         case E_SFmode:
            sri->icode = CODE_FOR_reload_insf__frn;
            return NO_REGS;
-         case DFmode:
+         case E_DFmode:
            sri->icode = CODE_FOR_reload_indf__frn;
            return NO_REGS;
-         case SImode:
+         case E_SImode:
            /* ??? If we knew that we are in the appropriate mode -
               single precision - we could use a reload pattern directly.  */
            return FPUL_REGS;
@@ -11491,17 +11344,11 @@ sh_secondary_reload (bool in_p, rtx x, reg_class_t rclass_i,
        return GENERAL_REGS;
       return NO_REGS;  // LRA wants NO_REGS here, it used to be FPUL_REGS;
     }
-  if (rclass == TARGET_REGS
-      && !satisfies_constraint_Csy (x)
-      && (!REG_P (x) || ! GENERAL_REGISTER_P (REGNO (x))))
-    return GENERAL_REGS;
+
   if ((rclass == MAC_REGS || rclass == PR_REGS)
       && REG_P (x) && ! GENERAL_REGISTER_P (REGNO (x))
       && rclass != REGNO_REG_CLASS (REGNO (x)))
     return GENERAL_REGS;
-  if (rclass != GENERAL_REGS && REG_P (x)
-      && TARGET_REGISTER_P (REGNO (x)))
-    return GENERAL_REGS;
 
  /* If here fall back to loading FPUL register through general registers.
     This case can happen when movsi_ie insn is picked initially to
@@ -11550,20 +11397,21 @@ sh_cannot_substitute_mem_equiv_p (rtx)
   return true;
 }
 
-/* Return true if DISP can be legitimized.  */
+/* Implement TARGET_LEGITIMIZE_ADDRESS_DISPLACEMENT.  */
 static bool
-sh_legitimize_address_displacement (rtx *disp, rtx *offs,
+sh_legitimize_address_displacement (rtx *offset1, rtx *offset2,
+                                   poly_int64 orig_offset,
                                    machine_mode mode)
 {
   if ((TARGET_FPU_DOUBLE && mode == DFmode)
       || (TARGET_SH2E && mode == SFmode))
     return false;
 
-  struct disp_adjust adj = sh_find_mov_disp_adjust (mode, INTVAL (*disp));
+  struct disp_adjust adj = sh_find_mov_disp_adjust (mode, orig_offset);
   if (adj.offset_adjust != NULL_RTX && adj.mov_disp != NULL_RTX)
     {
-      *disp = adj.mov_disp;
-      *offs = adj.offset_adjust;
+      *offset1 = adj.offset_adjust;
+      *offset2 = adj.mov_disp;
       return true;
     }
  
@@ -11602,35 +11450,30 @@ sh_movsf_ie_ra_split_p (rtx op0, rtx op1, rtx op2)
 static void
 sh_conditional_register_usage (void)
 {
-  int regno;
-  for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno ++)
+  for (int regno = 0; regno < FIRST_PSEUDO_REGISTER; regno ++)
     if (! VALID_REGISTER_P (regno))
-      fixed_regs[regno] = call_used_regs[regno] = 1;
+      fixed_regs[regno] = 1;
   /* R8 and R9 are call-clobbered on SH5, but not on earlier SH ABIs.  */
   if (flag_pic)
-    {
-      fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1;
-      call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 1;
-    }
+    fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1;
   if (TARGET_FDPIC)
     {
       fixed_regs[PIC_REG] = 1;
       call_used_regs[PIC_REG] = 1;
-      call_really_used_regs[PIC_REG] = 1;
     }
   /* Renesas saves and restores mac registers on call.  */
   if (TARGET_HITACHI && ! TARGET_NOMACSAVE)
     {
-      call_really_used_regs[MACH_REG] = 0;
-      call_really_used_regs[MACL_REG] = 0;
+      call_used_regs[MACH_REG] = 0;
+      call_used_regs[MACL_REG] = 0;
     }
 
-  for (regno = FIRST_GENERAL_REG; regno <= LAST_GENERAL_REG; regno++)
-    if (! fixed_regs[regno] && call_really_used_regs[regno])
+  for (int regno = FIRST_GENERAL_REG; regno <= LAST_GENERAL_REG; regno++)
+    if (! fixed_regs[regno] && call_used_regs[regno])
       SET_HARD_REG_BIT (reg_class_contents[SIBCALL_REGS], regno);
 
-  call_really_used_regs[FPSCR_MODES_REG] = 0;
-  call_really_used_regs[FPSCR_STAT_REG] = 0;
+  call_used_regs[FPSCR_MODES_REG] = 0;
+  call_used_regs[FPSCR_STAT_REG] = 0;
 }
 
 /* Implement TARGET_LEGITIMATE_CONSTANT_P
@@ -11673,9 +11516,6 @@ sh_init_sync_libfuncs (void)
 bool
 sh_can_use_simple_return_p (void)
 {
-  HARD_REG_SET live_regs_mask;
-  int d;
-
   if (! reload_completed || frame_pointer_needed)
     return false;
 
@@ -11684,7 +11524,8 @@ sh_can_use_simple_return_p (void)
     return false;
 
   /* Finally, allow for pr save.  */
-  d = calc_live_regs (&live_regs_mask);
+  HARD_REG_SET live_regs_mask;
+  int d = calc_live_regs (&live_regs_mask);
 
   if (rounded_frame_size (d) > 4)
    return false;
@@ -11858,7 +11699,7 @@ sh_find_equiv_gbr_addr (rtx_insn* insn, rtx mem)
        {
          if (CALL_P (DF_REF_INSN (d)))
            {
-             if (REGNO_REG_SET_P (regs_invalidated_by_call_regset, GBR_REG))
+             if (TEST_HARD_REG_BIT (regs_invalidated_by_call, GBR_REG))
                return NULL_RTX;
              else
                continue;
@@ -11927,13 +11768,15 @@ sh_is_nott_insn (const rtx_insn* i)
 rtx
 sh_movt_set_dest (const rtx_insn* i)
 {
-  if (i == NULL)
-    return NULL;
+  return i == NULL ? NULL : sh_movt_set_dest (PATTERN (i));
+}
 
-  const_rtx p = PATTERN (i);
-  return GET_CODE (p) == SET
-        && arith_reg_dest (XEXP (p, 0), SImode)
-        && t_reg_operand (XEXP (p, 1), VOIDmode) ? XEXP (p, 0) : NULL;
+rtx
+sh_movt_set_dest (const_rtx pat)
+{
+  return GET_CODE (pat) == SET
+        && arith_reg_dest (XEXP (pat, 0), SImode)
+        && t_reg_operand (XEXP (pat, 1), VOIDmode) ? XEXP (pat, 0) : NULL;
 }
 
 /* Given an insn, check whether it's a 'movrt' kind of insn, i.e. an insn
@@ -11942,18 +11785,20 @@ sh_movt_set_dest (const rtx_insn* i)
 rtx
 sh_movrt_set_dest (const rtx_insn* i)
 {
-  if (i == NULL)
-    return NULL;
-
-  const_rtx p = PATTERN (i);
+  return i == NULL ? NULL : sh_movrt_set_dest (PATTERN (i));
+}
 
+rtx
+sh_movrt_set_dest (const_rtx pat)
+{
   /* The negc movrt replacement is inside a parallel.  */
-  if (GET_CODE (p) == PARALLEL)
-    p = XVECEXP (p, 0, 0);
+  if (GET_CODE (pat) == PARALLEL)
+    pat = XVECEXP (pat, 0, 0);
+
+  return GET_CODE (pat) == SET
+        && arith_reg_dest (XEXP (pat, 0), SImode)
+        && negt_reg_operand (XEXP (pat, 1), VOIDmode) ? XEXP (pat, 0) : NULL;
 
-  return GET_CODE (p) == SET
-        && arith_reg_dest (XEXP (p, 0), SImode)
-        && negt_reg_operand (XEXP (p, 1), VOIDmode) ? XEXP (p, 0) : NULL;
 }
 
 /* Given an insn and a reg number, tell whether the reg dies or is unused
@@ -12052,8 +11897,8 @@ sh_is_logical_t_store_expr (rtx op, rtx_insn* insn)
 
       else
        {
-         set_of_reg op_set = sh_find_set_of_reg (ops[i], insn,
-                                                 prev_nonnote_insn_bb);
+         set_of_reg op_set = sh_find_set_of_reg
+           (ops[i], insn, prev_nonnote_nondebug_insn_bb);
          if (op_set.set_src == NULL_RTX)
            continue;
 
@@ -12085,7 +11930,8 @@ sh_try_omit_signzero_extend (rtx extended_op, rtx_insn* insn)
   if (GET_MODE (extended_op) != SImode)
     return NULL_RTX;
 
-  set_of_reg s = sh_find_set_of_reg (extended_op, insn, prev_nonnote_insn_bb);
+  set_of_reg s = sh_find_set_of_reg (extended_op, insn,
+                                    prev_nonnote_nondebug_insn_bb);
   if (s.set_src == NULL_RTX)
     return NULL_RTX;
 
@@ -12121,10 +11967,10 @@ sh_split_movrt_negc_to_movt_xor (rtx_insn* curr_insn, rtx operands[])
   if (!can_create_pseudo_p ())
     return false;
 
-  set_of_reg t_before_negc = sh_find_set_of_reg (get_t_reg_rtx (), curr_insn,
-                                                prev_nonnote_insn_bb);
-  set_of_reg t_after_negc = sh_find_set_of_reg (get_t_reg_rtx (), curr_insn,
-                                               next_nonnote_insn_bb);
+  set_of_reg t_before_negc = sh_find_set_of_reg
+    (get_t_reg_rtx (), curr_insn, prev_nonnote_nondebug_insn_bb);
+  set_of_reg t_after_negc = sh_find_set_of_reg
+    (get_t_reg_rtx (), curr_insn, next_nonnote_nondebug_insn_bb);
 
   if (t_before_negc.set_rtx != NULL_RTX && t_after_negc.set_rtx != NULL_RTX
       && rtx_equal_p (t_before_negc.set_rtx, t_after_negc.set_rtx)
@@ -12165,8 +12011,8 @@ sh_find_extending_set_of_reg (rtx reg, rtx_insn* curr_insn)
      Also try to look through the first extension that we hit.  There are some
      cases, where a zero_extend is followed an (implicit) sign_extend, and it
      fails to see the sign_extend.  */
-  sh_extending_set_of_reg result =
-       sh_find_set_of_reg (reg, curr_insn, prev_nonnote_insn_bb, true);
+  sh_extending_set_of_reg result = sh_find_set_of_reg
+    (reg, curr_insn, prev_nonnote_nondebug_insn_bb, true);
 
   if (result.set_src != NULL)
     {
@@ -12224,9 +12070,11 @@ sh_extending_set_of_reg::use_as_extended_reg (rtx_insn* use_at_insn) const
        rtx r = gen_reg_rtx (SImode);
        rtx_insn* i0;
        if (from_mode == QImode)
-         i0 = emit_insn_after (gen_extendqisi2 (r, set_src), insn);
+         i0 = sh_check_add_incdec_notes (
+                       emit_insn_after (gen_extendqisi2 (r, set_src), insn));
        else if (from_mode == HImode)
-         i0 = emit_insn_after (gen_extendhisi2 (r, set_src), insn);
+         i0 = sh_check_add_incdec_notes (
+                       emit_insn_after (gen_extendhisi2 (r, set_src), insn));
        else
          gcc_unreachable ();
 
@@ -12644,7 +12492,7 @@ static void
 sh_emit_mode_set (int entity ATTRIBUTE_UNUSED, int mode,
                  int prev_mode, HARD_REG_SET regs_live ATTRIBUTE_UNUSED)
 {
-  if ((TARGET_SH4A_FP || TARGET_SH4_300)
+  if ((TARGET_SH4A_FP || TARGET_FPU_SH4_300)
       && prev_mode != FP_MODE_NONE && prev_mode != mode)
     {
       emit_insn (gen_toggle_pr ());
@@ -12730,11 +12578,11 @@ sh_use_by_pieces_infrastructure_p (unsigned HOST_WIDE_INT size,
   switch (op)
     {
       case MOVE_BY_PIECES:
-       return move_by_pieces_ninsns (size, align, MOVE_MAX_PIECES + 1)
+       return by_pieces_ninsns (size, align, MOVE_MAX_PIECES + 1, op)
          < (!speed_p ? 2 : (align >= 32) ? 16 : 2);
       case STORE_BY_PIECES:
       case SET_BY_PIECES:
-       return move_by_pieces_ninsns (size, align, STORE_MAX_PIECES + 1)
+       return by_pieces_ninsns (size, align, STORE_MAX_PIECES + 1, op)
          < (!speed_p ? 2 : (align >= 32) ? 16 : 2);
       default:
        return default_use_by_pieces_infrastructure_p (size, align,