OSDN Git Service

* config/sh/sh.c (sh_override_options): When flag_exceptions or
[pf3gnuchains/gcc-fork.git] / gcc / config / sh / sh.c
index cf6e1a7..a4be11c 100644 (file)
@@ -37,7 +37,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "insn-attr.h"
 #include "toplev.h"
 #include "recog.h"
-#include "c-pragma.h"
 #include "integrate.h"
 #include "dwarf2.h"
 #include "tm_p.h"
@@ -50,6 +49,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "cfglayout.h"
 #include "intl.h"
 #include "sched-int.h"
+#include "params.h"
 #include "ggc.h"
 #include "gimple.h"
 #include "cfgloop.h"
@@ -106,12 +106,6 @@ static int skip_cycles = 0;
    and returned from sh_reorder2.  */
 static short cached_can_issue_more;
 
-/* Saved operands from the last compare to use when we generate an scc
-   or bcc insn.  */
-
-rtx sh_compare_op0;
-rtx sh_compare_op1;
-
 /* Provides the class number of the smallest class containing
    reg number.  */
 
@@ -191,7 +185,6 @@ static void push_regs (HARD_REG_SET *, int);
 static int calc_live_regs (HARD_REG_SET *);
 static HOST_WIDE_INT rounded_frame_size (int);
 static rtx mark_constant_pool_use (rtx);
-const struct attribute_spec sh_attribute_table[];
 static tree sh_handle_interrupt_handler_attribute (tree *, tree, tree, int, bool *);
 static tree sh_handle_resbank_handler_attribute (tree *, tree,
                                                 tree, int, bool *);
@@ -224,7 +217,7 @@ static int sh_variable_issue (FILE *, int, rtx, int);
 static bool sh_function_ok_for_sibcall (tree, tree);
 
 static bool sh_cannot_modify_jumps_p (void);
-static int sh_target_reg_class (void);
+static enum reg_class sh_target_reg_class (void);
 static bool sh_optimize_target_register_callee_saved (bool);
 static bool sh_ms_bitfield_layout_p (const_tree);
 
@@ -245,6 +238,8 @@ static bool sh_rtx_costs (rtx, int, int, int *, bool);
 static int sh_address_cost (rtx, bool);
 static int sh_pr_n_sets (void);
 static rtx sh_allocate_initial_value (rtx);
+static bool sh_legitimate_address_p (enum machine_mode, rtx, bool);
+static rtx sh_legitimize_address (rtx, rtx, enum machine_mode);
 static int shmedia_target_regs_stack_space (HARD_REG_SET *);
 static int shmedia_reserve_space_for_target_registers_p (int, HARD_REG_SET *);
 static int shmedia_target_regs_stack_adjust (HARD_REG_SET *);
@@ -262,6 +257,11 @@ static bool sh_pretend_outgoing_varargs_named (CUMULATIVE_ARGS *);
 static tree sh_build_builtin_va_list (void);
 static void sh_va_start (tree, rtx);
 static tree sh_gimplify_va_arg_expr (tree, tree, gimple_seq *, gimple_seq *);
+static enum machine_mode sh_promote_function_mode (const_tree type,
+                                                  enum machine_mode,
+                                                  int *punsignedp,
+                                                  const_tree funtype,
+                                                  int for_return);
 static bool sh_pass_by_reference (CUMULATIVE_ARGS *, enum machine_mode,
                                  const_tree, bool);
 static bool sh_callee_copies (CUMULATIVE_ARGS *, enum machine_mode,
@@ -272,7 +272,31 @@ static bool sh_scalar_mode_supported_p (enum machine_mode);
 static int sh_dwarf_calling_convention (const_tree);
 static void sh_encode_section_info (tree, rtx, int);
 static int sh2a_function_vector_p (tree);
+\f
+static const struct attribute_spec sh_attribute_table[] =
+{
+  /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
+  { "interrupt_handler", 0, 0, true,  false, false, sh_handle_interrupt_handler_attribute },
+  { "sp_switch",         1, 1, true,  false, false, sh_handle_sp_switch_attribute },
+  { "trap_exit",         1, 1, true,  false, false, sh_handle_trap_exit_attribute },
+  { "renesas",           0, 0, false, true, false, sh_handle_renesas_attribute },
+  { "trapa_handler",     0, 0, true,  false, false, sh_handle_interrupt_handler_attribute },
+  { "nosave_low_regs",   0, 0, true,  false, false, sh_handle_interrupt_handler_attribute },
+  { "resbank",           0, 0, true,  false, false, sh_handle_resbank_handler_attribute },
+  { "function_vector",   1, 1, true,  false, false, sh2a_handle_function_vector_handler_attribute },
+#ifdef SYMBIAN
+  /* Symbian support adds three new attributes:
+     dllexport - for exporting a function/variable that will live in a dll
+     dllimport - for importing a function/variable from a dll
 
+     Microsoft allows multiple declspecs in one __declspec, separating
+     them with spaces.  We do NOT support this.  Instead, use __declspec
+     multiple times.  */
+  { "dllimport",         0, 0, true,  false, false, sh_symbian_handle_dll_attribute },
+  { "dllexport",         0, 0, true,  false, false, sh_symbian_handle_dll_attribute },
+#endif
+  { NULL,                0, 0, false, false, false, NULL }
+};
 \f
 /* Initialize the GCC target structure.  */
 #undef TARGET_ATTRIBUTE_TABLE
@@ -374,6 +398,9 @@ static int sh2a_function_vector_p (tree);
 #undef TARGET_SCHED_INIT
 #define TARGET_SCHED_INIT sh_md_init
 
+#undef TARGET_LEGITIMIZE_ADDRESS
+#define TARGET_LEGITIMIZE_ADDRESS sh_legitimize_address
+
 #undef TARGET_CANNOT_MODIFY_JUMPS_P
 #define TARGET_CANNOT_MODIFY_JUMPS_P sh_cannot_modify_jumps_p
 #undef TARGET_BRANCH_TARGET_REGISTER_CLASS
@@ -415,10 +442,8 @@ static int sh2a_function_vector_p (tree);
 
 #undef TARGET_PROMOTE_PROTOTYPES
 #define TARGET_PROMOTE_PROTOTYPES sh_promote_prototypes
-#undef TARGET_PROMOTE_FUNCTION_ARGS
-#define TARGET_PROMOTE_FUNCTION_ARGS sh_promote_prototypes
-#undef TARGET_PROMOTE_FUNCTION_RETURN
-#define TARGET_PROMOTE_FUNCTION_RETURN sh_promote_prototypes
+#undef TARGET_PROMOTE_FUNCTION_MODE
+#define TARGET_PROMOTE_FUNCTION_MODE sh_promote_function_mode
 
 #undef TARGET_STRUCT_VALUE_RTX
 #define TARGET_STRUCT_VALUE_RTX sh_struct_value_rtx
@@ -483,6 +508,9 @@ static int sh2a_function_vector_p (tree);
 #undef TARGET_SECONDARY_RELOAD
 #define TARGET_SECONDARY_RELOAD sh_secondary_reload
 
+#undef TARGET_LEGITIMATE_ADDRESS_P
+#define TARGET_LEGITIMATE_ADDRESS_P    sh_legitimate_address_p
+
 /* Machine-specific symbol_ref flags.  */
 #define SYMBOL_FLAG_FUNCVEC_FUNCTION    (SYMBOL_FLAG_MACH_DEP << 0)
 
@@ -609,6 +637,299 @@ sh_handle_option (size_t code, const char *arg ATTRIBUTE_UNUSED,
     }
 }
 \f
+/* Set default optimization options.  */
+void
+sh_optimization_options (int level ATTRIBUTE_UNUSED, int size ATTRIBUTE_UNUSED)
+{
+  if (level)
+    {
+      flag_omit_frame_pointer = 2;
+      if (!size)
+       sh_div_str = "inv:minlat";
+    }
+  if (size)
+    {
+      target_flags |= MASK_SMALLCODE;
+      sh_div_str = SH_DIV_STR_FOR_SIZE ;
+    }
+  else
+    TARGET_CBRANCHDI4 = 1;
+  /* We can't meaningfully test TARGET_SHMEDIA here, because -m options
+     haven't been parsed yet, hence we'd read only the default.
+     sh_target_reg_class will return NO_REGS if this is not SHMEDIA, so
+     it's OK to always set flag_branch_target_load_optimize.  */
+  if (level > 1)
+    {
+      flag_branch_target_load_optimize = 1;
+      if (!size)
+       target_flags |= MASK_SAVE_ALL_TARGET_REGS;
+    }
+  /* Likewise, we can't meaningfully test TARGET_SH2E / TARGET_IEEE
+     here, so leave it to OVERRIDE_OPTIONS to set
+    flag_finite_math_only.  We set it to 2 here so we know if the user
+    explicitly requested this to be on or off.  */
+  flag_finite_math_only = 2;
+  /* If flag_schedule_insns is 1, we set it to 2 here so we know if
+     the user explicitly requested this to be on or off.  */
+  if (flag_schedule_insns > 0)
+    flag_schedule_insns = 2;
+
+  set_param_value ("simultaneous-prefetches", 2);
+}
+
+/* Implement OVERRIDE_OPTIONS macro.  Validate and override various
+   options, and do some machine dependent initialization.  */
+void
+sh_override_options (void)
+{
+  int regno;
+
+  SUBTARGET_OVERRIDE_OPTIONS;
+  if (flag_finite_math_only == 2)
+    flag_finite_math_only
+      = !flag_signaling_nans && TARGET_SH2E && ! TARGET_IEEE;
+  if (TARGET_SH2E && !flag_finite_math_only)
+    target_flags |= MASK_IEEE;
+  sh_cpu = PROCESSOR_SH1;
+  assembler_dialect = 0;
+  if (TARGET_SH2)
+    sh_cpu = PROCESSOR_SH2;
+  if (TARGET_SH2E)
+    sh_cpu = PROCESSOR_SH2E;
+  if (TARGET_SH2A)
+    sh_cpu = PROCESSOR_SH2A;
+  if (TARGET_SH3)
+    sh_cpu = PROCESSOR_SH3;
+  if (TARGET_SH3E)
+    sh_cpu = PROCESSOR_SH3E;
+  if (TARGET_SH4)
+    {
+      assembler_dialect = 1;
+      sh_cpu = PROCESSOR_SH4;
+    }
+  if (TARGET_SH4A_ARCH)
+    {
+      assembler_dialect = 1;
+      sh_cpu = PROCESSOR_SH4A;
+    }
+  if (TARGET_SH5)
+    {
+      sh_cpu = PROCESSOR_SH5;
+      target_flags |= MASK_ALIGN_DOUBLE;
+      if (TARGET_SHMEDIA_FPU)
+       target_flags |= MASK_FMOVD;
+      if (TARGET_SHMEDIA)
+       {
+         /* There are no delay slots on SHmedia.  */
+         flag_delayed_branch = 0;
+         /* Relaxation isn't yet supported for SHmedia */
+         target_flags &= ~MASK_RELAX;
+         /* After reload, if conversion does little good but can cause
+            ICEs:
+            - find_if_block doesn't do anything for SH because we don't
+              have conditional execution patterns.  (We use conditional
+              move patterns, which are handled differently, and only
+              before reload).
+            - find_cond_trap doesn't do anything for the SH because we
+              don't have conditional traps.
+            - find_if_case_1 uses redirect_edge_and_branch_force in
+              the only path that does an optimization, and this causes
+              an ICE when branch targets are in registers.
+            - find_if_case_2 doesn't do anything for the SHmedia after
+              reload except when it can redirect a tablejump - and
+              that's rather rare.  */
+         flag_if_conversion2 = 0;
+         if (! strcmp (sh_div_str, "call"))
+           sh_div_strategy = SH_DIV_CALL;
+         else if (! strcmp (sh_div_str, "call2"))
+           sh_div_strategy = SH_DIV_CALL2;
+         if (! strcmp (sh_div_str, "fp") && TARGET_FPU_ANY)
+           sh_div_strategy = SH_DIV_FP;
+         else if (! strcmp (sh_div_str, "inv"))
+           sh_div_strategy = SH_DIV_INV;
+         else if (! strcmp (sh_div_str, "inv:minlat"))
+           sh_div_strategy = SH_DIV_INV_MINLAT;
+         else if (! strcmp (sh_div_str, "inv20u"))
+           sh_div_strategy = SH_DIV_INV20U;
+         else if (! strcmp (sh_div_str, "inv20l"))
+           sh_div_strategy = SH_DIV_INV20L;
+         else if (! strcmp (sh_div_str, "inv:call2"))
+           sh_div_strategy = SH_DIV_INV_CALL2;
+         else if (! strcmp (sh_div_str, "inv:call"))
+           sh_div_strategy = SH_DIV_INV_CALL;
+         else if (! strcmp (sh_div_str, "inv:fp"))
+           {
+             if (TARGET_FPU_ANY)
+               sh_div_strategy = SH_DIV_INV_FP;
+             else
+               sh_div_strategy = SH_DIV_INV;
+           }
+         TARGET_CBRANCHDI4 = 0;
+         /* Assembler CFI isn't yet fully supported for SHmedia.  */
+         flag_dwarf2_cfi_asm = 0;
+       }
+    }
+  else
+    {
+       /* Only the sh64-elf assembler fully supports .quad properly.  */
+       targetm.asm_out.aligned_op.di = NULL;
+       targetm.asm_out.unaligned_op.di = NULL;
+    }
+  if (TARGET_SH1)
+    {
+      if (! strcmp (sh_div_str, "call-div1"))
+       sh_div_strategy = SH_DIV_CALL_DIV1;
+      else if (! strcmp (sh_div_str, "call-fp")
+              && (TARGET_FPU_DOUBLE
+                  || (TARGET_HARD_SH4 && TARGET_SH2E)
+                  || (TARGET_SHCOMPACT && TARGET_FPU_ANY)))
+       sh_div_strategy = SH_DIV_CALL_FP;
+      else if (! strcmp (sh_div_str, "call-table") && TARGET_SH2)
+       sh_div_strategy = SH_DIV_CALL_TABLE;
+      else
+       /* Pick one that makes most sense for the target in general.
+          It is not much good to use different functions depending
+          on -Os, since then we'll end up with two different functions
+          when some of the code is compiled for size, and some for
+          speed.  */
+
+       /* SH4 tends to emphasize speed.  */
+       if (TARGET_HARD_SH4)
+         sh_div_strategy = SH_DIV_CALL_TABLE;
+       /* These have their own way of doing things.  */
+       else if (TARGET_SH2A)
+         sh_div_strategy = SH_DIV_INTRINSIC;
+       /* ??? Should we use the integer SHmedia function instead?  */
+       else if (TARGET_SHCOMPACT && TARGET_FPU_ANY)
+         sh_div_strategy = SH_DIV_CALL_FP;
+        /* SH1 .. SH3 cores often go into small-footprint systems, so
+          default to the smallest implementation available.  */
+       else if (TARGET_SH2)    /* ??? EXPERIMENTAL */
+         sh_div_strategy = SH_DIV_CALL_TABLE;
+       else
+         sh_div_strategy = SH_DIV_CALL_DIV1;
+    }
+  if (!TARGET_SH1)
+    TARGET_PRETEND_CMOVE = 0;
+  if (sh_divsi3_libfunc[0])
+    ; /* User supplied - leave it alone.  */
+  else if (TARGET_DIVIDE_CALL_FP)
+    sh_divsi3_libfunc = "__sdivsi3_i4";
+  else if (TARGET_DIVIDE_CALL_TABLE)
+    sh_divsi3_libfunc = "__sdivsi3_i4i";
+  else if (TARGET_SH5)
+    sh_divsi3_libfunc = "__sdivsi3_1";
+  else
+    sh_divsi3_libfunc = "__sdivsi3";
+  if (sh_branch_cost == -1)
+    sh_branch_cost
+      = TARGET_SH5 ? 1 : ! TARGET_SH2 || TARGET_HARD_SH4 ? 2 : 1;
+
+  for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+    if (! VALID_REGISTER_P (regno))
+      sh_register_names[regno][0] = '\0';
+
+  for (regno = 0; regno < ADDREGNAMES_SIZE; regno++)
+    if (! VALID_REGISTER_P (ADDREGNAMES_REGNO (regno)))
+      sh_additional_register_names[regno][0] = '\0';
+
+  if (flag_omit_frame_pointer == 2)
+   {
+     /* The debugging information is sufficient,
+        but gdb doesn't implement this yet */
+     if (0)
+      flag_omit_frame_pointer
+        = (PREFERRED_DEBUGGING_TYPE == DWARF2_DEBUG);
+     else
+      flag_omit_frame_pointer = 0;
+   }
+
+  if ((flag_pic && ! TARGET_PREFERGOT)
+      || (TARGET_SHMEDIA && !TARGET_PT_FIXED))
+    flag_no_function_cse = 1;
+
+  if (SMALL_REGISTER_CLASSES)
+    {
+      /* Never run scheduling before reload, since that can
+        break global alloc, and generates slower code anyway due
+        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
+        PIC, SH3 and lower as they give spill failures for R0.  */
+      if (!TARGET_HARD_SH4 || flag_pic)
+        flag_schedule_insns = 0;
+      /* ??? Current exception handling places basic block boundaries
+        after call_insns.  It causes the high pressure on R0 and gives
+        spill failures for R0 in reload.  See PR 22553 and the thread
+        on gcc-patches
+         <http://gcc.gnu.org/ml/gcc-patches/2005-10/msg00816.html>.  */
+      else if (flag_exceptions)
+       {
+         if (flag_schedule_insns == 1)
+           warning (0, "ignoring -fschedule-insns because of exception handling bug");
+         flag_schedule_insns = 0;
+       }
+      else if (flag_schedule_insns == 2)
+       flag_schedule_insns = 0;
+    }
+
+  /* Unwinding with -freorder-blocks-and-partition does not work on this
+     architecture, because it requires far jumps to label crossing between
+     hot/cold sections which are rejected on this architecture.  */
+  if (flag_reorder_blocks_and_partition)
+    {
+      if (flag_exceptions)
+       {
+         inform (input_location, 
+                 "-freorder-blocks-and-partition does not work with "
+                 "exceptions on this architecture");
+         flag_reorder_blocks_and_partition = 0;
+         flag_reorder_blocks = 1;
+       }
+      else if (flag_unwind_tables)
+       {
+         inform (input_location,
+                 "-freorder-blocks-and-partition does not support unwind "
+                 "info on this architecture");
+         flag_reorder_blocks_and_partition = 0;
+         flag_reorder_blocks = 1;
+       }
+    }
+
+  if (align_loops == 0)
+    align_loops =  1 << (TARGET_SH5 ? 3 : 2);
+  if (align_jumps == 0)
+    align_jumps = 1 << CACHE_LOG;
+  else if (align_jumps < (TARGET_SHMEDIA ? 4 : 2))
+    align_jumps = TARGET_SHMEDIA ? 4 : 2;
+
+  /* Allocation boundary (in *bytes*) for the code of a function.
+     SH1: 32 bit alignment is faster, because instructions are always
+     fetched as a pair from a longword boundary.
+     SH2 .. SH5 : align to cache line start.  */
+  if (align_functions == 0)
+    align_functions
+      = TARGET_SMALLCODE ? FUNCTION_BOUNDARY/8 : (1 << CACHE_LOG);
+  /* 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;
+
+      /* Also take possible .long constants / mova tables int account. */
+      if (min_align < 4)
+       min_align = 4;
+      if (align_functions < min_align)
+       align_functions = min_align;
+    }
+
+  if (sh_fixed_range_str)
+    sh_fix_range (sh_fixed_range_str);
+}
+\f
 /* Print the operand address in x to the stream.  */
 
 void
@@ -828,7 +1149,7 @@ print_operand (FILE *stream, rtx x, int code)
       break;
 
     case 't':
-      gcc_assert (GET_CODE (x) == MEM);
+      gcc_assert (MEM_P (x));
       x = XEXP (x, 0);
       switch (GET_CODE (x))
        {
@@ -861,15 +1182,15 @@ print_operand (FILE *stream, rtx x, int code)
     case 'M':
       if (TARGET_SHMEDIA)
        {
-         if (GET_CODE (x) == MEM
+         if (MEM_P (x)
              && GET_CODE (XEXP (x, 0)) == PLUS
-             && (GET_CODE (XEXP (XEXP (x, 0), 1)) == REG
+             && (REG_P (XEXP (XEXP (x, 0), 1))
                  || GET_CODE (XEXP (XEXP (x, 0), 1)) == SUBREG))
            fputc ('x', stream);
        }
       else
        {
-         if (GET_CODE (x) == MEM)
+         if (MEM_P (x))
            {
              switch (GET_MODE (x))
                {
@@ -885,7 +1206,7 @@ print_operand (FILE *stream, rtx x, int code)
       break;
 
     case 'm':
-      gcc_assert (GET_CODE (x) == MEM);
+      gcc_assert (MEM_P (x));
       x = XEXP (x, 0);
       /* Fall through.  */
     case 'U':
@@ -925,7 +1246,7 @@ print_operand (FILE *stream, rtx x, int code)
       break;
 
     case 'd':
-      gcc_assert (GET_CODE (x) == REG && GET_MODE (x) == V2SFmode);
+      gcc_assert (REG_P (x) && GET_MODE (x) == V2SFmode);
 
       fprintf ((stream), "d%s", reg_names[REGNO (x)] + 1);
       break;
@@ -938,7 +1259,7 @@ print_operand (FILE *stream, rtx x, int code)
        }
       goto default_output;
     case 'u':
-      if (GET_CODE (x) == CONST_INT)
+      if (CONST_INT_P (x))
        {
          fprintf ((stream), "%u", (unsigned) INTVAL (x) & (0x10000 - 1));
          break;
@@ -964,7 +1285,7 @@ print_operand (FILE *stream, rtx x, int code)
                    == GET_MODE_SIZE (GET_MODE (SUBREG_REG (inner))))
                && subreg_lowpart_p (inner))
              inner = SUBREG_REG (inner);
-           if (GET_CODE (inner) == CONST_INT)
+           if (CONST_INT_P (inner))
              {
                x = GEN_INT (trunc_int_for_mode (INTVAL (inner), GET_MODE (x)));
                goto default_output;
@@ -973,7 +1294,7 @@ print_operand (FILE *stream, rtx x, int code)
            if (GET_CODE (inner) == SUBREG
                && (GET_MODE_SIZE (GET_MODE (inner))
                    < GET_MODE_SIZE (GET_MODE (SUBREG_REG (inner))))
-               && GET_CODE (SUBREG_REG (inner)) == REG)
+               && REG_P (SUBREG_REG (inner)))
              {
                offset = subreg_regno_offset (REGNO (SUBREG_REG (inner)),
                                              GET_MODE (SUBREG_REG (inner)),
@@ -981,7 +1302,7 @@ print_operand (FILE *stream, rtx x, int code)
                                              GET_MODE (inner));
                inner = SUBREG_REG (inner);
              }
-           if (GET_CODE (inner) != REG || GET_MODE_SIZE (inner_mode) > 8)
+           if (!REG_P (inner) || GET_MODE_SIZE (inner_mode) > 8)
              abort ();
            /* Floating point register pairs are always big endian;
               general purpose registers are 64 bit wide.  */
@@ -1006,7 +1327,7 @@ print_operand (FILE *stream, rtx x, int code)
          goto default_output;
        case SUBREG:
          gcc_assert (SUBREG_BYTE (x) == 0
-                     && GET_CODE (SUBREG_REG (x)) == REG);
+                     && REG_P (SUBREG_REG (x)));
 
          x = SUBREG_REG (x);
          /* Fall through.  */
@@ -1020,7 +1341,7 @@ print_operand (FILE *stream, rtx x, int code)
          else if (FP_REGISTER_P (REGNO (x))
                   && mode == V4SFmode)
            fprintf ((stream), "fv%s", reg_names[regno] + 2);
-         else if (GET_CODE (x) == REG
+         else if (REG_P (x)
                   && mode == V2SFmode)
            fprintf ((stream), "fp%s", reg_names[regno] + 2);
          else if (FP_REGISTER_P (REGNO (x))
@@ -1077,7 +1398,7 @@ int
 expand_block_move (rtx *operands)
 {
   int align = INTVAL (operands[3]);
-  int constp = (GET_CODE (operands[2]) == CONST_INT);
+  int constp = (CONST_INT_P (operands[2]));
   int bytes = (constp ? INTVAL (operands[2]) : 0);
 
   if (! constp)
@@ -1218,12 +1539,12 @@ prepare_move_operands (rtx operands[], enum machine_mode mode)
   if ((mode == SImode || mode == DImode)
       && flag_pic
       && ! ((mode == Pmode || mode == ptr_mode)
-           && tls_symbolic_operand (operands[1], Pmode) != 0))
+           && tls_symbolic_operand (operands[1], Pmode) != TLS_MODEL_NONE))
     {
       rtx temp;
       if (SYMBOLIC_CONST_P (operands[1]))
        {
-         if (GET_CODE (operands[0]) == MEM)
+         if (MEM_P (operands[0]))
            operands[1] = force_reg (Pmode, operands[1]);
          else if (TARGET_SHMEDIA
                   && GET_CODE (operands[1]) == LABEL_REF
@@ -1260,7 +1581,7 @@ prepare_move_operands (rtx operands[], enum machine_mode mode)
          && ! sh_register_operand (operands[1], mode))
        operands[1] = copy_to_mode_reg (mode, operands[1]);
 
-      if (GET_CODE (operands[0]) == MEM && ! memory_operand (operands[0], mode))
+      if (MEM_P (operands[0]) && ! memory_operand (operands[0], mode))
        {
          /* This is like change_address_1 (operands[0], mode, 0, 1) ,
             except that we can't use that function because it is static.  */
@@ -1275,9 +1596,9 @@ prepare_move_operands (rtx operands[], enum machine_mode mode)
         being used for the source.  */
       else if (TARGET_SH1
               && refers_to_regno_p (R0_REG, R0_REG + 1, operands[1], (rtx *)0)
-              && GET_CODE (operands[0]) == MEM
+              && MEM_P (operands[0])
               && GET_CODE (XEXP (operands[0], 0)) == PLUS
-              && GET_CODE (XEXP (XEXP (operands[0], 0), 1)) == REG)
+              && REG_P (XEXP (XEXP (operands[0], 0), 1)))
        operands[1] = copy_to_mode_reg (mode, operands[1]);
     }
 
@@ -1290,7 +1611,8 @@ prepare_move_operands (rtx operands[], enum machine_mode mode)
       op1 = operands[1];
       if (GET_CODE (op1) == CONST
          && GET_CODE (XEXP (op1, 0)) == PLUS
-         && tls_symbolic_operand (XEXP (XEXP (op1, 0), 0), Pmode))
+         && (tls_symbolic_operand (XEXP (XEXP (op1, 0), 0), Pmode)
+             != TLS_MODEL_NONE))
        {
          opc = XEXP (XEXP (op1, 0), 1);
          op1 = XEXP (XEXP (op1, 0), 0);
@@ -1298,7 +1620,7 @@ prepare_move_operands (rtx operands[], enum machine_mode mode)
       else
        opc = NULL_RTX;
 
-      if ((tls_kind = tls_symbolic_operand (op1, Pmode)))
+      if ((tls_kind = tls_symbolic_operand (op1, Pmode)) != TLS_MODEL_NONE)
        {
          rtx tga_op1, tga_ret, tmp, tmp2;
 
@@ -1382,8 +1704,8 @@ prepare_cbranch_operands (rtx *operands, enum machine_mode mode,
     comparison = GET_CODE (operands[0]);
   else
     scratch = operands[4];
-  if (GET_CODE (operands[1]) == CONST_INT
-      && GET_CODE (operands[2]) != CONST_INT)
+  if (CONST_INT_P (operands[1])
+      && !CONST_INT_P (operands[2]))
     {
       rtx tmp = operands[1];
 
@@ -1391,7 +1713,7 @@ prepare_cbranch_operands (rtx *operands, enum machine_mode mode,
       operands[2] = tmp;
       comparison = swap_condition (comparison);
     }
-  if (GET_CODE (operands[2]) == CONST_INT)
+  if (CONST_INT_P (operands[2]))
     {
       HOST_WIDE_INT val = INTVAL (operands[2]);
       if ((val == -1 || val == -0x81)
@@ -1442,7 +1764,7 @@ prepare_cbranch_operands (rtx *operands, enum machine_mode mode,
      allocated to a different hard register, thus we load the constant into
      a register unless it is zero.  */
   if (!REG_P (operands[2])
-      && (GET_CODE (operands[2]) != CONST_INT
+      && (!CONST_INT_P (operands[2])
          || (mode == SImode && operands[2] != CONST0_RTX (SImode)
              && ((comparison != EQ && comparison != NE)
                  || (REG_P (op1) && REGNO (op1) != R0_REG)
@@ -1567,7 +1889,7 @@ expand_cbranchdi4 (rtx *operands, enum rtx_code comparison)
       break;
     case GTU: case GT:
       msw_taken = comparison;
-      if (GET_CODE (op2l) == CONST_INT && INTVAL (op2l) == -1)
+      if (CONST_INT_P (op2l) && INTVAL (op2l) == -1)
        break;
       if (comparison != GTU || op2h != CONST0_RTX (SImode))
        msw_skip = swap_condition (msw_taken);
@@ -1591,7 +1913,7 @@ expand_cbranchdi4 (rtx *operands, enum rtx_code comparison)
       lsw_taken = LTU;
       break;
     case LEU: case LE:
-      if (GET_CODE (op2l) == CONST_INT && INTVAL (op2l) == -1)
+      if (CONST_INT_P (op2l) && INTVAL (op2l) == -1)
        msw_taken = comparison;
       else
        {
@@ -1634,7 +1956,8 @@ expand_cbranchdi4 (rtx *operands, enum rtx_code comparison)
   operands[2] = op2h;
   operands[4] = NULL_RTX;
   if (reload_completed
-      && ! arith_reg_or_0_operand (op2h, SImode) && true_regnum (op1h)
+      && ! 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))
     {
@@ -1664,8 +1987,12 @@ expand_cbranchdi4 (rtx *operands, enum rtx_code comparison)
   if (lsw_taken != LAST_AND_UNUSED_RTX_CODE)
     {
       if (reload_completed
-         && ! arith_reg_or_0_operand (op2l, SImode) && true_regnum (op1l))
-       operands[4] = scratch;
+         && ! 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);
     }
   if (msw_skip != LAST_AND_UNUSED_RTX_CODE)
@@ -1673,10 +2000,26 @@ expand_cbranchdi4 (rtx *operands, enum rtx_code comparison)
   return true;
 }
 
+/* Emit INSN, possibly in a PARALLEL with an USE of fpscr for SH4.  */
+
+static void
+sh_emit_set_t_insn (rtx insn, enum machine_mode mode)
+{
+  if ((TARGET_SH4 || TARGET_SH2A) && GET_MODE_CLASS (mode) == MODE_FLOAT)
+    {
+      insn = gen_rtx_PARALLEL (VOIDmode,
+                      gen_rtvec (2, insn,
+                                 gen_rtx_USE (VOIDmode, get_fpscr_rtx ())));
+      (mode == SFmode ? emit_sf_insn : emit_df_insn) (insn);
+    }
+  else
+    emit_insn (insn);
+}
+
 /* Prepare the operands for an scc instruction; make sure that the
-   compare has been done.  */
-rtx
-prepare_scc_operands (enum rtx_code code)
+   compare has been done and the result is in T_REG.  */
+void
+sh_emit_scc_to_t (enum rtx_code code, rtx op0, rtx op1)
 {
   rtx t_reg = gen_rtx_REG (SImode, T_REG);
   enum rtx_code oldcode = code;
@@ -1705,77 +2048,222 @@ prepare_scc_operands (enum rtx_code code)
     }
   if (code != oldcode)
     {
-      rtx tmp = sh_compare_op0;
-      sh_compare_op0 = sh_compare_op1;
-      sh_compare_op1 = tmp;
+      rtx tmp = op0;
+      op0 = op1;
+      op1 = tmp;
     }
 
-  mode = GET_MODE (sh_compare_op0);
+  mode = GET_MODE (op0);
   if (mode == VOIDmode)
-    mode = GET_MODE (sh_compare_op1);
+    mode = GET_MODE (op1);
 
-  sh_compare_op0 = force_reg (mode, sh_compare_op0);
+  op0 = force_reg (mode, op0);
   if ((code != EQ && code != NE
-       && (sh_compare_op1 != const0_rtx
+       && (op1 != const0_rtx
           || code == GTU  || code == GEU || code == LTU || code == LEU))
-      || (mode == DImode && sh_compare_op1 != const0_rtx)
+      || (mode == DImode && op1 != const0_rtx)
       || (TARGET_SH2E && GET_MODE_CLASS (mode) == MODE_FLOAT))
-    sh_compare_op1 = force_reg (mode, sh_compare_op1);
+    op1 = force_reg (mode, op1);
 
-  if ((TARGET_SH4 || TARGET_SH2A) && GET_MODE_CLASS (mode) == MODE_FLOAT)
-    (mode == SFmode ? emit_sf_insn : emit_df_insn)
-     (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2,
-               gen_rtx_SET (VOIDmode, t_reg,
-                            gen_rtx_fmt_ee (code, SImode,
-                                            sh_compare_op0, sh_compare_op1)),
-               gen_rtx_USE (VOIDmode, get_fpscr_rtx ()))));
-  else
-    emit_insn (gen_rtx_SET (VOIDmode, t_reg,
-                           gen_rtx_fmt_ee (code, SImode,
-                                           sh_compare_op0, sh_compare_op1)));
+  sh_emit_set_t_insn (gen_rtx_SET (VOIDmode, t_reg,
+                                  gen_rtx_fmt_ee (code, SImode, op0, op1)),
+                     mode);
+}
+
+rtx
+sh_emit_cheap_store_flag (enum machine_mode mode, enum rtx_code code,
+                         rtx op0, rtx op1)
+{
+  rtx target = gen_reg_rtx (SImode);
+  rtx tmp;
+
+  gcc_assert (TARGET_SHMEDIA);
+  switch (code)
+    {
+    case EQ:
+    case GT:
+    case LT:
+    case UNORDERED:
+    case GTU:
+    case LTU:
+      tmp = gen_rtx_fmt_ee (code, SImode, op0, op1);
+      emit_insn (gen_cstore4_media (target, tmp, op0, op1));
+      code = NE;
+      break;
+
+    case NE:
+    case GE:
+    case LE:
+    case ORDERED:
+    case GEU:
+    case LEU:
+      tmp = gen_rtx_fmt_ee (reverse_condition (code), mode, op0, op1);
+      emit_insn (gen_cstore4_media (target, tmp, op0, op1));
+      code = EQ;
+      break;
+
+    case UNEQ:
+    case UNGE:
+    case UNGT:
+    case UNLE:
+    case UNLT:
+    case LTGT:
+      return NULL_RTX;
+
+    default:
+      gcc_unreachable ();
+    }
+
+  if (mode == DImode)
+    {
+      rtx t2 = gen_reg_rtx (DImode);
+      emit_insn (gen_extendsidi2 (t2, target));
+      target = t2;
+    }
 
-  return t_reg;
+  return gen_rtx_fmt_ee (code, VOIDmode, target, const0_rtx);
 }
 
 /* Called from the md file, set up the operands of a compare instruction.  */
 
 void
-from_compare (rtx *operands, int code)
+sh_emit_compare_and_branch (rtx *operands, enum machine_mode mode)
 {
-  enum machine_mode mode = GET_MODE (sh_compare_op0);
-  rtx insn;
-  if (mode == VOIDmode)
-    mode = GET_MODE (sh_compare_op1);
-  if (code != EQ
-      || mode == DImode
-      || (TARGET_SH2E && GET_MODE_CLASS (mode) == MODE_FLOAT))
+  enum rtx_code code = GET_CODE (operands[0]);
+  enum rtx_code branch_code;
+  rtx op0 = operands[1];
+  rtx op1 = operands[2];
+  rtx insn, tem;
+  bool need_ccmpeq = false;
+
+  if (TARGET_SH2E && GET_MODE_CLASS (mode) == MODE_FLOAT)
     {
-      /* Force args into regs, since we can't use constants here.  */
-      sh_compare_op0 = force_reg (mode, sh_compare_op0);
-      if (sh_compare_op1 != const0_rtx
-         || code == GTU  || code == GEU
-         || (TARGET_SH2E && GET_MODE_CLASS (mode) == MODE_FLOAT))
-       sh_compare_op1 = force_reg (mode, sh_compare_op1);
+      op0 = force_reg (mode, op0);
+      op1 = force_reg (mode, op1);
+    }
+  else
+    {
+      if (code != EQ || mode == DImode)
+        {
+          /* Force args into regs, since we can't use constants here.  */
+          op0 = force_reg (mode, op0);
+          if (op1 != const0_rtx || code == GTU  || code == GEU)
+           op1 = force_reg (mode, op1);
+        }
     }
-  if (TARGET_SH2E && GET_MODE_CLASS (mode) == MODE_FLOAT && code == GE)
+
+  if (GET_MODE_CLASS (mode) == MODE_FLOAT)
     {
-      from_compare (operands, GT);
-      insn = gen_ieee_ccmpeqsf_t (sh_compare_op0, sh_compare_op1);
+      if (code == LT
+         || (code == LE && TARGET_IEEE && TARGET_SH2E)
+         || (code == GE && !(TARGET_IEEE && TARGET_SH2E)))
+       {
+         tem = op0, op0 = op1, op1 = tem;
+         code = swap_condition (code);
+       }
+
+      /* GE becomes fcmp/gt+fcmp/eq, for SH2E and TARGET_IEEE only.  */
+      if (code == GE)
+       {
+         gcc_assert (TARGET_IEEE && TARGET_SH2E);
+          need_ccmpeq = true;
+         code = GT;
+       }
+
+      /* Now we can have EQ, NE, GT, LE.  NE and LE are then transformed
+        to EQ/GT respectively.  */
+      gcc_assert (code == EQ || code == GT || code == NE || code == LE);
     }
+
+  switch (code)
+    {
+    case EQ:
+    case GT:
+    case GE:
+    case GTU:
+    case GEU:
+      branch_code = code;
+      break;
+    case NE:
+    case LT:
+    case LE:
+    case LTU:
+    case LEU:
+      branch_code = reverse_condition (code);
+      break;
+    default:
+      gcc_unreachable ();
+    }
+
+  insn = gen_rtx_SET (VOIDmode,
+                     gen_rtx_REG (SImode, T_REG),
+                     gen_rtx_fmt_ee (branch_code, SImode, op0, op1));
+
+  sh_emit_set_t_insn (insn, mode);
+  if (need_ccmpeq)
+    sh_emit_set_t_insn (gen_ieee_ccmpeqsf_t (op0, op1), mode);
+
+  if (branch_code == code)
+    emit_jump_insn (gen_branch_true (operands[3]));
   else
-    insn = gen_rtx_SET (VOIDmode,
-                       gen_rtx_REG (SImode, T_REG),
-                       gen_rtx_fmt_ee ((enum rtx_code) code, SImode,
-                                       sh_compare_op0, sh_compare_op1));
-  if ((TARGET_SH4 || TARGET_SH2A) && GET_MODE_CLASS (mode) == MODE_FLOAT)
+    emit_jump_insn (gen_branch_false (operands[3]));
+}
+
+void
+sh_emit_compare_and_set (rtx *operands, enum machine_mode mode)
+{
+  enum rtx_code code = GET_CODE (operands[1]);
+  rtx op0 = operands[2];
+  rtx op1 = operands[3];
+  rtx lab = NULL_RTX;
+  bool invert = false;
+  rtx tem;
+
+  op0 = force_reg (mode, op0);
+  if ((code != EQ && code != NE
+       && (op1 != const0_rtx
+          || code == GTU  || code == GEU || code == LTU || code == LEU))
+      || (mode == DImode && op1 != const0_rtx)
+      || (TARGET_SH2E && GET_MODE_CLASS (mode) == MODE_FLOAT))
+    op1 = force_reg (mode, op1);
+
+  if (GET_MODE_CLASS (mode) == MODE_FLOAT)
     {
-      insn = gen_rtx_PARALLEL (VOIDmode,
-                     gen_rtvec (2, insn,
-                                gen_rtx_USE (VOIDmode, get_fpscr_rtx ())));
-      (mode == SFmode ? emit_sf_insn : emit_df_insn) (insn);
+      if (code == LT || code == LE)
+       {
+         code = swap_condition (code);
+         tem = op0, op0 = op1, op1 = tem;
+       }
+      if (code == GE)
+        {
+          if (TARGET_IEEE)
+            {
+              lab = gen_label_rtx ();
+              sh_emit_scc_to_t (EQ, op0, op1);
+              emit_jump_insn (gen_branch_true (lab));
+              code = GT;
+           }
+          else
+            {
+              code = LT;
+              invert = true;
+           }
+        }
     }
+
+  if (code == NE)
+    {
+      code = EQ;
+      invert = true;
+    }
+
+  sh_emit_scc_to_t (code, op0, op1);
+  if (lab)
+    emit_label (lab);
+  if (invert)
+    emit_insn (gen_movnegt (operands[0]));
   else
-    emit_insn (insn);
+    emit_move_insn (operands[0], gen_rtx_REG (SImode, T_REG));
 }
 \f
 /* Functions to output assembly code.  */
@@ -1792,7 +2280,7 @@ output_movedouble (rtx insn ATTRIBUTE_UNUSED, rtx operands[],
   rtx dst = operands[0];
   rtx src = operands[1];
 
-  if (GET_CODE (dst) == MEM
+  if (MEM_P (dst)
       && GET_CODE (XEXP (dst, 0)) == PRE_DEC)
     return "mov.l      %T1,%0\n\tmov.l %1,%0";
 
@@ -1810,7 +2298,7 @@ output_movedouble (rtx insn ATTRIBUTE_UNUSED, rtx operands[],
       else
        return "mov     %1,%0\n\tmov    %T1,%T0";
     }
-  else if (GET_CODE (src) == CONST_INT)
+  else if (CONST_INT_P (src))
     {
       if (INTVAL (src) < 0)
        output_asm_insn ("mov   #-1,%S0", operands);
@@ -1819,7 +2307,7 @@ output_movedouble (rtx insn ATTRIBUTE_UNUSED, rtx operands[],
 
       return "mov      %1,%R0";
     }
-  else if (GET_CODE (src) == MEM)
+  else if (MEM_P (src))
     {
       int ptrreg = -1;
       int dreg = REGNO (dst);
@@ -1844,7 +2332,7 @@ output_movedouble (rtx insn ATTRIBUTE_UNUSED, rtx operands[],
             supported, so we can't use the 'o' constraint.
             Thus we must check for and handle r0+REG addresses here.
             We punt for now, since this is likely very rare.  */
-         gcc_assert (GET_CODE (XEXP (inside, 1)) != REG);
+         gcc_assert (!REG_P (XEXP (inside, 1)));
          break;
          
        case LABEL_REF:
@@ -1908,7 +2396,7 @@ output_far_jump (rtx insn, rtx op)
        jump = "mov.l   %O0,%1; jmp     @%1";
     }
   /* If we have a scratch register available, use it.  */
-  if (GET_CODE ((prev = prev_nonnote_insn (insn))) == INSN
+  if (NONJUMP_INSN_P ((prev = prev_nonnote_insn (insn)))
       && INSN_CODE (prev) == CODE_FOR_indirect_jump_scratch)
     {
       this_jmp.reg = SET_DEST (XVECEXP (PATTERN (prev), 0, 0));
@@ -2067,7 +2555,7 @@ output_branchy_insn (enum rtx_code code, const char *templ,
 {
   rtx next_insn = NEXT_INSN (insn);
 
-  if (next_insn && GET_CODE (next_insn) == JUMP_INSN && condjump_p (next_insn))
+  if (next_insn && JUMP_P (next_insn) && condjump_p (next_insn))
     {
       rtx src = SET_SRC (PATTERN (next_insn));
       if (GET_CODE (src) == IF_THEN_ELSE && GET_CODE (XEXP (src, 0)) != code)
@@ -2180,7 +2668,7 @@ sh_cannot_copy_insn_p (rtx insn)
   if (!reload_completed || !flag_pic)
     return false;
 
-  if (GET_CODE (insn) != INSN)
+  if (!NONJUMP_INSN_P (insn))
     return false;
   if (asm_noperands (insn) >= 0)
     return false;
@@ -2247,7 +2735,7 @@ int
 shift_insns_rtx (rtx insn)
 {
   rtx set_src = SET_SRC (XVECEXP (PATTERN (insn), 0, 0));
-  int shift_count = INTVAL (XEXP (set_src, 1));
+  int shift_count = INTVAL (XEXP (set_src, 1)) & 31;
   enum rtx_code shift_code = GET_CODE (set_src);
 
   switch (shift_code)
@@ -2275,7 +2763,7 @@ shiftcosts (rtx x)
   if (GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD)
     {
       if (GET_MODE (x) == DImode
-         && GET_CODE (XEXP (x, 1)) == CONST_INT
+         && CONST_INT_P (XEXP (x, 1))
          && INTVAL (XEXP (x, 1)) == 1)
        return 2;
 
@@ -2283,12 +2771,13 @@ shiftcosts (rtx x)
       return MAX_COST;
     }
   /* If shift by a non constant, then this will be expensive.  */
-  if (GET_CODE (XEXP (x, 1)) != CONST_INT)
+  if (!CONST_INT_P (XEXP (x, 1)))
     return SH_DYNAMIC_SHIFT_COST;
 
-  value = INTVAL (XEXP (x, 1));
+  /* Otherwise, return the true cost in instructions.  Cope with out of range
+     shift counts more or less arbitrarily.  */
+  value = INTVAL (XEXP (x, 1)) & 31;
 
-  /* Otherwise, return the true cost in instructions.  */
   if (GET_CODE (x) == ASHIFTRT)
     {
       int cost = ashiftrt_insns[value];
@@ -2309,7 +2798,7 @@ andcosts (rtx x)
   int i;
 
   /* Anding with a register is a single cycle and instruction.  */
-  if (GET_CODE (XEXP (x, 1)) != CONST_INT)
+  if (!CONST_INT_P (XEXP (x, 1)))
     return 1;
 
   i = INTVAL (XEXP (x, 1));
@@ -2345,12 +2834,12 @@ static inline int
 addsubcosts (rtx x)
 {
   /* Adding a register is a single cycle insn.  */
-  if (GET_CODE (XEXP (x, 1)) == REG
+  if (REG_P (XEXP (x, 1))
       || GET_CODE (XEXP (x, 1)) == SUBREG)
     return 1;
 
   /* Likewise for small constants.  */
-  if (GET_CODE (XEXP (x, 1)) == CONST_INT
+  if (CONST_INT_P (XEXP (x, 1))
       && CONST_OK_FOR_ADD (INTVAL (XEXP (x, 1))))
     return 1;
 
@@ -2637,7 +3126,7 @@ gen_shifty_op (int code, rtx *operands)
   int max, i;
 
   /* Truncate the shift count in case it is out of bounds.  */
-  value = value & 0x1f;
+  value = value & 31;
 
   if (value == 31)
     {
@@ -2651,7 +3140,7 @@ gen_shifty_op (int code, rtx *operands)
        {
          /* There is a two instruction sequence for 31 bit left shifts,
             but it requires r0.  */
-         if (GET_CODE (operands[0]) == REG && REGNO (operands[0]) == 0)
+         if (REG_P (operands[0]) && REGNO (operands[0]) == 0)
            {
              emit_insn (gen_andsi3 (operands[0], operands[0], const1_rtx));
              emit_insn (gen_rotlsi3_31 (operands[0], operands[0]));
@@ -2719,7 +3208,7 @@ expand_ashiftrt (rtx *operands)
 
   if (TARGET_SH3)
     {
-      if (GET_CODE (operands[2]) != CONST_INT)
+      if (!CONST_INT_P (operands[2]))
        {
          rtx count = copy_to_mode_reg (SImode, operands[2]);
          emit_insn (gen_negsi2 (count, count));
@@ -2735,7 +3224,7 @@ expand_ashiftrt (rtx *operands)
          return 1;
        }
     }
-  if (GET_CODE (operands[2]) != CONST_INT)
+  if (!CONST_INT_P (operands[2]))
     return 0;
 
   value = INTVAL (operands[2]) & 31;
@@ -2790,7 +3279,7 @@ expand_ashiftrt (rtx *operands)
 int
 sh_dynamicalize_shift_p (rtx count)
 {
-  return shift_insns[INTVAL (count)] > 1 + SH_DYNAMIC_SHIFT_COST;
+  return shift_insns[INTVAL (count) & 31] > 1 + SH_DYNAMIC_SHIFT_COST;
 }
 
 /* Try to find a good way to implement the combiner pattern
@@ -2826,7 +3315,7 @@ shl_and_kind (rtx left_rtx, rtx mask_rtx, int *attrp)
 
   if (left < 0 || left > 31)
     return 0;
-  if (GET_CODE (mask_rtx) == CONST_INT)
+  if (CONST_INT_P (mask_rtx))
     mask = (unsigned HOST_WIDE_INT) INTVAL (mask_rtx) >> left;
   else
     mask = (unsigned HOST_WIDE_INT) GET_MODE_MASK (SImode) >> left;
@@ -2950,11 +3439,11 @@ int
 shl_and_scr_length (rtx insn)
 {
   rtx set_src = SET_SRC (XVECEXP (PATTERN (insn), 0, 0));
-  int len = shift_insns[INTVAL (XEXP (set_src, 1))];
+  int len = shift_insns[INTVAL (XEXP (set_src, 1)) & 31];
   rtx op = XEXP (set_src, 0);
-  len += shift_insns[INTVAL (XEXP (op, 1))] + 1;
+  len += shift_insns[INTVAL (XEXP (op, 1)) & 31] + 1;
   op = XEXP (XEXP (op, 0), 0);
-  return len + shift_insns[INTVAL (XEXP (op, 1))];
+  return len + shift_insns[INTVAL (XEXP (op, 1)) & 31];
 }
 
 /* Generate rtl for instructions for which shl_and_kind advised a particular
@@ -3563,7 +4052,7 @@ dump_table (rtx start, rtx barrier)
       scan = emit_insn_after (gen_align_4 (), scan);
       need_align = 0;
       for (; start != barrier; start = NEXT_INSN (start))
-       if (GET_CODE (start) == INSN
+       if (NONJUMP_INSN_P (start)
            && recog_memoized (start) == CODE_FOR_casesi_worker_2)
          {
            rtx src = SET_SRC (XVECEXP (PATTERN (start), 0, 0));
@@ -3707,7 +4196,7 @@ dump_table (rtx start, rtx barrier)
 static int
 hi_const (rtx src)
 {
-  return (GET_CODE (src) == CONST_INT
+  return (CONST_INT_P (src)
          && INTVAL (src) >= -32768
          && INTVAL (src) <= 32767);
 }
@@ -3723,7 +4212,7 @@ hi_const (rtx src)
 static int
 broken_move (rtx insn)
 {
-  if (GET_CODE (insn) == INSN)
+  if (NONJUMP_INSN_P (insn))
     {
       rtx pat = PATTERN (insn);
       if (GET_CODE (pat) == PARALLEL)
@@ -3741,17 +4230,16 @@ broken_move (rtx insn)
                && GET_CODE (SET_SRC (pat)) == CONST_DOUBLE
                && (fp_zero_operand (SET_SRC (pat))
                    || fp_one_operand (SET_SRC (pat)))
-               /* ??? If this is a -m4 or -m4-single compilation, in general
-                  we don't know the current setting of fpscr, so disable fldi.
+               /* In general we don't know the current setting of fpscr, so disable fldi.
                   There is an exception if this was a register-register move
                   before reload - and hence it was ascertained that we have
                   single precision setting - and in a post-reload optimization
                   we changed this to do a constant load.  In that case
                   we don't have an r0 clobber, hence we must use fldi.  */
-               && (! TARGET_SH4 || TARGET_FMOVD
+               && (TARGET_FMOVD
                    || (GET_CODE (XEXP (XVECEXP (PATTERN (insn), 0, 2), 0))
                        == SCRATCH))
-               && GET_CODE (SET_DEST (pat)) == REG
+               && REG_P (SET_DEST (pat))
                && FP_REGISTER_P (REGNO (SET_DEST (pat))))
          && ! (TARGET_SH2A
                && GET_MODE (SET_DEST (pat)) == SImode
@@ -3767,7 +4255,7 @@ broken_move (rtx insn)
 static int
 mova_p (rtx insn)
 {
-  return (GET_CODE (insn) == INSN
+  return (NONJUMP_INSN_P (insn)
          && GET_CODE (PATTERN (insn)) == SET
          && GET_CODE (SET_SRC (PATTERN (insn))) == UNSPEC
          && XINT (SET_SRC (PATTERN (insn)), 1) == UNSPEC_MOVA
@@ -3795,9 +4283,9 @@ fixup_mova (rtx mova)
        {
          worker = NEXT_INSN (worker);
          gcc_assert (worker
-                     && GET_CODE (worker) != CODE_LABEL
-                     && GET_CODE (worker) != JUMP_INSN);
-       } while (GET_CODE (worker) == NOTE
+                     && !LABEL_P (worker)
+                     && !JUMP_P (worker));
+       } while (NOTE_P (worker)
                 || recog_memoized (worker) != CODE_FOR_casesi_worker_1);
       wpat = PATTERN (worker);
       wpat0 = XVECEXP (wpat, 0, 0);
@@ -3915,12 +4403,12 @@ find_barrier (int num_mova, rtx mova, rtx from)
         call, determine the alignment.  N.B.  When find_barrier recurses for
         an out-of-reach mova, we might see labels at the start of previously
         inserted constant tables.  */
-      if (GET_CODE (from) == CODE_LABEL
+      if (LABEL_P (from)
          && CODE_LABEL_NUMBER (from) <= max_labelno_before_reorg)
        {
          if (optimize)
            new_align = 1 << label_to_alignment (from);
-         else if (GET_CODE (prev_nonnote_insn (from)) == BARRIER)
+         else if (BARRIER_P (prev_nonnote_insn (from)))
            new_align = 1 << barrier_align (from);
          else
            new_align = 1;
@@ -3930,7 +4418,7 @@ find_barrier (int num_mova, rtx mova, rtx from)
         for explicit alignments.  If the table is long, we might be forced
         to emit the new table in front of it; the length of the alignment
         might be the last straw.  */
-      else if (GET_CODE (from) == INSN
+      else if (NONJUMP_INSN_P (from)
               && GET_CODE (PATTERN (from)) == UNSPEC_VOLATILE
               && XINT (PATTERN (from), 1) == UNSPECV_ALIGN)
        new_align = INTVAL (XVECEXP (PATTERN (from), 0, 0));
@@ -3938,12 +4426,12 @@ find_barrier (int num_mova, rtx mova, rtx from)
         at the end.  That is better than putting it in front because
         this way, we don't need extra alignment for adding a 4-byte-aligned
         mov(a) label to a 2/4 or 8/4 byte aligned table.  */
-      else if (GET_CODE (from) == INSN
+      else if (NONJUMP_INSN_P (from)
               && GET_CODE (PATTERN (from)) == UNSPEC_VOLATILE
               && XINT (PATTERN (from), 1) == UNSPECV_CONST_END)
        return from;
 
-      if (GET_CODE (from) == BARRIER)
+      if (BARRIER_P (from))
        {
          rtx next;
 
@@ -4029,9 +4517,7 @@ find_barrier (int num_mova, rtx mova, rtx from)
          if (found_si > count_si)
            count_si = found_si;
        }
-      else if (GET_CODE (from) == JUMP_INSN
-              && (GET_CODE (PATTERN (from)) == ADDR_VEC
-                  || GET_CODE (PATTERN (from)) == ADDR_DIFF_VEC))
+      else if (JUMP_TABLE_DATA_P (from))
        {
          if ((num_mova > 1 && GET_MODE (prev_nonnote_insn (from)) == VOIDmode)
              || (num_mova
@@ -4058,7 +4544,7 @@ find_barrier (int num_mova, rtx mova, rtx from)
            }
        }
       /* For the SH1, we generate alignments even after jumps-around-jumps.  */
-      else if (GET_CODE (from) == JUMP_INSN
+      else if (JUMP_P (from)
               && ! TARGET_SH2
               && ! TARGET_SMALLCODE)
        new_align = 4;
@@ -4129,8 +4615,8 @@ find_barrier (int num_mova, rtx mova, rtx 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 (GET_CODE (from) == JUMP_INSN || GET_CODE (from) == NOTE
-            || GET_CODE (from) == CODE_LABEL)
+      while (NOTE_P (from) || JUMP_P (from)
+            || LABEL_P (from))
        from = PREV_INSN (from);
 
       from = emit_jump_insn_after (gen_jump (label), from);
@@ -4153,7 +4639,7 @@ sfunc_uses_reg (rtx insn)
   int i;
   rtx pattern, part, reg_part, reg;
 
-  if (GET_CODE (insn) != INSN)
+  if (!NONJUMP_INSN_P (insn))
     return 0;
   pattern = PATTERN (insn);
   if (GET_CODE (pattern) != PARALLEL || get_attr_type (insn) != TYPE_SFUNC)
@@ -4174,7 +4660,7 @@ sfunc_uses_reg (rtx insn)
       if (part == reg_part || GET_CODE (part) == CLOBBER)
        continue;
       if (reg_mentioned_p (reg, ((GET_CODE (part) == SET
-                                 && GET_CODE (SET_DEST (part)) == REG)
+                                 && REG_P (SET_DEST (part)))
                                 ? SET_SRC (part) : part)))
        return 0;
     }
@@ -4197,18 +4683,18 @@ noncall_uses_reg (rtx reg, rtx insn, rtx *set)
     {
       pattern = single_set (insn);
       if (pattern
-         && GET_CODE (SET_DEST (pattern)) == REG
+         && REG_P (SET_DEST (pattern))
          && REGNO (reg) == REGNO (SET_DEST (pattern)))
        *set = pattern;
       return 0;
     }
-  if (GET_CODE (insn) != CALL_INSN)
+  if (!CALL_P (insn))
     {
       /* We don't use rtx_equal_p because we don't care if the mode is
         different.  */
       pattern = single_set (insn);
       if (pattern
-         && GET_CODE (SET_DEST (pattern)) == REG
+         && REG_P (SET_DEST (pattern))
          && REGNO (reg) == REGNO (SET_DEST (pattern)))
        {
          rtx par, part;
@@ -4247,7 +4733,7 @@ noncall_uses_reg (rtx reg, rtx insn, rtx *set)
        {
          /* We don't use rtx_equal_p, because we don't care if the
              mode is different.  */
-         if (GET_CODE (SET_DEST (pattern)) != REG
+         if (!REG_P (SET_DEST (pattern))
              || REGNO (reg) != REGNO (SET_DEST (pattern)))
            return 1;
 
@@ -4258,7 +4744,7 @@ noncall_uses_reg (rtx reg, rtx insn, rtx *set)
     }
 
   if (GET_CODE (pattern) != CALL
-      || GET_CODE (XEXP (pattern, 0)) != MEM
+      || !MEM_P (XEXP (pattern, 0))
       || ! rtx_equal_p (reg, XEXP (XEXP (pattern, 0), 0)))
     return 1;
 
@@ -4291,7 +4777,7 @@ regs_used (rtx x, int is_dest)
       {
        rtx y = SUBREG_REG (x);
 
-       if (GET_CODE (y) != REG)
+       if (!REG_P (y))
          break;
        if (REGNO (y) < 16)
          return (((1 << HARD_REGNO_NREGS (0, GET_MODE (x))) - 1)
@@ -4354,7 +4840,7 @@ gen_block_redirect (rtx jump, int addr, int need_block)
   rtx dest;
 
   /* First, check if we already have an instruction that satisfies our need.  */
-  if (prev && GET_CODE (prev) == INSN && ! INSN_DELETED_P (prev))
+  if (prev && NONJUMP_INSN_P (prev) && ! INSN_DELETED_P (prev))
     {
       if (INSN_CODE (prev) == CODE_FOR_indirect_jump_scratch)
        return prev;
@@ -4451,7 +4937,7 @@ gen_block_redirect (rtx jump, int addr, int need_block)
   else if (optimize && need_block >= 0)
     {
       rtx next = next_active_insn (next_active_insn (dest));
-      if (next && GET_CODE (next) == JUMP_INSN
+      if (next && JUMP_P (next)
          && GET_CODE (PATTERN (next)) == SET
          && recog_memoized (next) == CODE_FOR_jump_compact)
        {
@@ -4568,7 +5054,7 @@ fixup_addr_diff_vecs (rtx first)
     {
       rtx vec_lab, pat, prev, prevpat, x, braf_label;
 
-      if (GET_CODE (insn) != JUMP_INSN
+      if (!JUMP_P (insn)
          || GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC)
        continue;
       pat = PATTERN (insn);
@@ -4577,7 +5063,7 @@ fixup_addr_diff_vecs (rtx first)
       /* Search the matching casesi_jump_2.  */
       for (prev = vec_lab; ; prev = PREV_INSN (prev))
        {
-         if (GET_CODE (prev) != JUMP_INSN)
+         if (!JUMP_P (prev))
            continue;
          prevpat = PATTERN (prev);
          if (GET_CODE (prevpat) != PARALLEL || XVECLEN (prevpat, 0) != 2)
@@ -4666,7 +5152,7 @@ barrier_align (rtx barrier_or_label)
       prev = prev_real_insn (prev);
 
       for (slot = 2, credit = (1 << (CACHE_LOG - 2)) + 2;
-          credit >= 0 && prev && GET_CODE (prev) == INSN;
+          credit >= 0 && prev && NONJUMP_INSN_P (prev);
           prev = prev_real_insn (prev))
        {
          jump_to_next = 0;
@@ -4690,7 +5176,7 @@ barrier_align (rtx barrier_or_label)
          credit -= get_attr_length (prev);
        }
       if (prev
-         && GET_CODE (prev) == JUMP_INSN
+         && JUMP_P (prev)
          && JUMP_LABEL (prev))
        {
          rtx x;
@@ -4734,7 +5220,7 @@ sh_loop_align (rtx label)
 
   do
     next = next_nonnote_insn (next);
-  while (next && GET_CODE (next) == CODE_LABEL);
+  while (next && LABEL_P (next));
 
   if (! next
       || ! INSN_P (next)
@@ -4800,7 +5286,7 @@ sh_reorg (void)
          rtx pattern, reg, link, set, scan, dies, label;
          int rescan = 0, foundinsn = 0;
 
-         if (GET_CODE (insn) == CALL_INSN)
+         if (CALL_P (insn))
            {
              pattern = PATTERN (insn);
 
@@ -4810,7 +5296,7 @@ sh_reorg (void)
                pattern = SET_SRC (pattern);
 
              if (GET_CODE (pattern) != CALL
-                 || GET_CODE (XEXP (pattern, 0)) != MEM)
+                 || !MEM_P (XEXP (pattern, 0)))
                continue;
 
              reg = XEXP (XEXP (pattern, 0), 0);
@@ -4822,13 +5308,13 @@ sh_reorg (void)
                continue;
            }
 
-         if (GET_CODE (reg) != REG)
+         if (!REG_P (reg))
            continue;
 
          /* Try scanning backward to find where the register is set.  */
          link = NULL;
          for (scan = PREV_INSN (insn);
-              scan && GET_CODE (scan) != CODE_LABEL;
+              scan && !LABEL_P (scan);
               scan = PREV_INSN (scan))
            {
              if (! INSN_P (scan))
@@ -4880,7 +5366,7 @@ sh_reorg (void)
                 the call, and can result in situations where a single call
                 insn may have two targets depending on where we came from.  */
 
-             if (GET_CODE (scan) == CODE_LABEL && ! foundinsn)
+             if (LABEL_P (scan) && ! foundinsn)
                break;
 
              if (! INSN_P (scan))
@@ -4890,7 +5376,7 @@ sh_reorg (void)
                  safely, we would have to check that all the
                  instructions at the jump destination did not use REG.  */
 
-             if (GET_CODE (scan) == JUMP_INSN)
+             if (JUMP_P (scan))
                break;
 
              if (! reg_mentioned_p (reg, scan))
@@ -4903,7 +5389,7 @@ sh_reorg (void)
                foundinsn = 1;
 
              if (scan != insn
-                 && (GET_CODE (scan) == CALL_INSN || sfunc_uses_reg (scan)))
+                 && (CALL_P (scan) || sfunc_uses_reg (scan)))
                {
                  /* There is a function call to this register other
                      than the one we are checking.  If we optimize
@@ -4959,7 +5445,7 @@ sh_reorg (void)
 
                  scan = NEXT_INSN (scan);
                  if (scan != insn
-                     && ((GET_CODE (scan) == CALL_INSN
+                     && ((CALL_P (scan)
                           && reg_mentioned_p (reg, scan))
                          || ((reg2 = sfunc_uses_reg (scan))
                              && REGNO (reg2) == REGNO (reg))))
@@ -4999,7 +5485,7 @@ sh_reorg (void)
              num_mova = 0;
            }
        }
-      else if (GET_CODE (insn) == JUMP_INSN
+      else if (JUMP_P (insn)
               && GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC
               && num_mova
               /* ??? loop invariant motion can also move a mova out of a
@@ -5034,7 +5520,7 @@ sh_reorg (void)
            }
        }
       if (broken_move (insn)
-         || (GET_CODE (insn) == INSN
+         || (NONJUMP_INSN_P (insn)
              && recog_memoized (insn) == CODE_FOR_casesi_worker_2))
        {
          rtx scan;
@@ -5054,9 +5540,9 @@ sh_reorg (void)
          /* Now find all the moves between the points and modify them.  */
          for (scan = insn; scan != barrier; scan = NEXT_INSN (scan))
            {
-             if (GET_CODE (scan) == CODE_LABEL)
+             if (LABEL_P (scan))
                last_float = 0;
-             if (GET_CODE (scan) == INSN
+             if (NONJUMP_INSN_P (scan)
                  && recog_memoized (scan) == CODE_FOR_casesi_worker_2)
                need_aligned_label = 1;
              if (broken_move (scan))
@@ -5089,7 +5575,7 @@ sh_reorg (void)
                        }
                      dst = gen_rtx_REG (HImode, REGNO (dst) + offset);
                    }
-                 if (GET_CODE (dst) == REG && FP_ANY_REGISTER_P (REGNO (dst)))
+                 if (REG_P (dst) && FP_ANY_REGISTER_P (REGNO (dst)))
                    {
                      /* This must be an insn that clobbers r0.  */
                      rtx *clobberp = &XVECEXP (PATTERN (scan), 0,
@@ -5124,7 +5610,7 @@ sh_reorg (void)
                          /* If we are not optimizing, then there may not be
                             a note.  */
                          if (note)
-                           PUT_MODE (note, REG_INC);
+                           PUT_REG_NOTE_KIND (note, REG_INC);
 
                          *last_float_addr = r0_inc_rtx;
                        }
@@ -5218,7 +5704,7 @@ get_dest_uid (rtx label, int max_uid)
       dest = NEXT_INSN (dest);
       dest_uid = INSN_UID (dest);
     }
-  if (GET_CODE (dest) == JUMP_INSN && GET_CODE (PATTERN (dest)) == RETURN)
+  if (JUMP_P (dest) && GET_CODE (PATTERN (dest)) == RETURN)
     return 0;
   return dest_uid;
 }
@@ -5252,7 +5738,7 @@ split_branches (rtx first)
           so transform it into a note.  */
        SET_INSN_DELETED (insn);
       }
-    else if (GET_CODE (insn) == JUMP_INSN
+    else if (JUMP_P (insn)
             /* Don't mess with ADDR_DIFF_VEC */
             && (GET_CODE (PATTERN (insn)) == SET
                 || GET_CODE (PATTERN (insn)) == RETURN))
@@ -5340,9 +5826,9 @@ split_branches (rtx first)
                                            0));
 
                if (beyond
-                   && (GET_CODE (beyond) == JUMP_INSN
+                   && (JUMP_P (beyond)
                        || ((beyond = next_active_insn (beyond))
-                           && GET_CODE (beyond) == JUMP_INSN))
+                           && JUMP_P (beyond)))
                    && GET_CODE (PATTERN (beyond)) == SET
                    && recog_memoized (beyond) == CODE_FOR_jump_compact
                    && ((INSN_ADDRESSES
@@ -5355,9 +5841,9 @@ split_branches (rtx first)
 
            next = next_active_insn (insn);
 
-           if ((GET_CODE (next) == JUMP_INSN
+           if ((JUMP_P (next)
                 || ((next = next_active_insn (next))
-                    && GET_CODE (next) == JUMP_INSN))
+                    && JUMP_P (next)))
                && GET_CODE (PATTERN (next)) == SET
                && recog_memoized (next) == CODE_FOR_jump_compact
                && ((INSN_ADDRESSES
@@ -5921,7 +6407,7 @@ calc_live_regs (HARD_REG_SET *live_regs_mask)
     {
       rtx pr_initial = has_hard_reg_initial_val (Pmode, PR_REG);
       pr_live = (pr_initial
-                ? (GET_CODE (pr_initial) != REG
+                ? (!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
@@ -6283,13 +6769,19 @@ sh_expand_prologue (void)
   /* If we're supposed to switch stacks at function entry, do so now.  */
   if (sp_switch_attr)
     {
+      rtx lab, newsrc;
       /* 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 (TREE_VALUE (sp_switch_attr)));
+       = ggc_strdup (TREE_STRING_POINTER (arg));
       rtx sp_switch = gen_rtx_SYMBOL_REF (Pmode, s);
 
-      emit_insn (gen_sp_switch_1 (sp_switch));
+      lab = add_constant (sp_switch, SImode, 0);
+      newsrc = gen_rtx_LABEL_REF (VOIDmode, lab);
+      newsrc = gen_const_mem (SImode, newsrc);
+
+      emit_insn (gen_sp_switch_1 (newsrc));
     }
 
   d = calc_live_regs (&live_regs_mask);
@@ -6347,7 +6839,7 @@ sh_expand_prologue (void)
       tmp_pnt = schedule.temps;
       for (entry = &schedule.entries[1]; entry->mode != VOIDmode; entry++)
         {
-         enum machine_mode mode = entry->mode;
+         enum machine_mode mode = (enum machine_mode) entry->mode;
          unsigned int reg = entry->reg;
          rtx reg_rtx, mem_rtx, pre_dec = NULL_RTX;
          rtx orig_reg_rtx;
@@ -6361,32 +6853,27 @@ sh_expand_prologue (void)
                                                 stack_pointer_rtx,
                                                 GEN_INT (offset)));
 
-         GO_IF_LEGITIMATE_ADDRESS (mode, XEXP (mem_rtx, 0), try_pre_dec);
-
-         gcc_assert (r0);
-         mem_rtx = NULL_RTX;
-
-       try_pre_dec:
-         do
-           if (HAVE_PRE_DECREMENT
-               && (offset_in_r0 - offset == GET_MODE_SIZE (mode)
-                   || mem_rtx == NULL_RTX
-                   || reg == PR_REG || SPECIAL_REGISTER_P (reg)))
-             {
-               pre_dec = gen_frame_mem (mode, gen_rtx_PRE_DEC (Pmode, r0));
+         if (!memory_address_p (mode, XEXP (mem_rtx, 0)))
+           {
+             gcc_assert (r0);
+             mem_rtx = NULL_RTX;
+           }
 
-               GO_IF_LEGITIMATE_ADDRESS (mode, XEXP (pre_dec, 0),
-                                         pre_dec_ok);
+         if (HAVE_PRE_DECREMENT
+             && (offset_in_r0 - offset == GET_MODE_SIZE (mode)
+                 || mem_rtx == NULL_RTX
+                 || reg == PR_REG || SPECIAL_REGISTER_P (reg)))
+           {
+             pre_dec = gen_frame_mem (mode, gen_rtx_PRE_DEC (Pmode, r0));
 
+             if (!memory_address_p (mode, XEXP (pre_dec, 0)))
                pre_dec = NULL_RTX;
-
-               break;
-
-             pre_dec_ok:
-               mem_rtx = NULL_RTX;
-               offset += GET_MODE_SIZE (mode);
-             }
-         while (0);
+             else
+               {
+                 mem_rtx = NULL_RTX;
+                 offset += GET_MODE_SIZE (mode);
+               }
+           }
 
          if (mem_rtx != NULL_RTX)
            goto addr_ok;
@@ -6582,10 +7069,9 @@ sh_expand_epilogue (bool sibcall_p)
 
   if (frame_pointer_needed)
     {
-      /* We must avoid scheduling the epilogue with previous basic blocks
-        when exception handling is enabled.  See PR/18032.  */
-      if (flag_exceptions)
-       emit_insn (gen_blockage ());
+      /* We must avoid scheduling the epilogue with previous basic blocks.
+        See PR/18032 and PR/40313.  */
+      emit_insn (gen_blockage ());
       output_stack_adjust (frame_size, hard_frame_pointer_rtx, e,
                           &live_regs_mask);
 
@@ -6637,7 +7123,7 @@ sh_expand_epilogue (bool sibcall_p)
       tmp_pnt = schedule.temps;
       for (; entry->mode != VOIDmode; entry--)
        {
-         enum machine_mode mode = entry->mode;
+         enum machine_mode mode = (enum machine_mode) entry->mode;
          int reg = entry->reg;
          rtx reg_rtx, mem_rtx, post_inc = NULL_RTX, insn;
 
@@ -6649,31 +7135,22 @@ sh_expand_epilogue (bool sibcall_p)
                                                 stack_pointer_rtx,
                                                 GEN_INT (offset)));
 
-         GO_IF_LEGITIMATE_ADDRESS (mode, XEXP (mem_rtx, 0), try_post_inc);
-
-         mem_rtx = NULL_RTX;
-
-       try_post_inc:
-         do
-           if (HAVE_POST_INCREMENT
-               && (offset == offset_in_r0
-                   || (offset + GET_MODE_SIZE (mode) != d + d_rounding
-                       && mem_rtx == NULL_RTX)
-                   || reg == PR_REG || SPECIAL_REGISTER_P (reg)))
-             {
-               post_inc = gen_frame_mem (mode, gen_rtx_POST_INC (Pmode, r0));
+         if (!memory_address_p (mode, XEXP (mem_rtx, 0)))
+           mem_rtx = NULL_RTX;
 
-               GO_IF_LEGITIMATE_ADDRESS (mode, XEXP (post_inc, 0),
-                                         post_inc_ok);
+         if (HAVE_POST_INCREMENT
+             && (offset == offset_in_r0
+                 || (offset + GET_MODE_SIZE (mode) != d + d_rounding
+                     && mem_rtx == NULL_RTX)
+                 || reg == PR_REG || SPECIAL_REGISTER_P (reg)))
+           {
+             post_inc = gen_frame_mem (mode, gen_rtx_POST_INC (Pmode, r0));
 
+             if (!memory_address_p (mode, XEXP (post_inc, 0)))
                post_inc = NULL_RTX;
-
-               break;
-
-             post_inc_ok:
+             else
                mem_rtx = NULL_RTX;
-             }
-         while (0);
+           }
 
          if (mem_rtx != NULL_RTX)
            goto addr_ok;
@@ -6900,6 +7377,8 @@ sh_set_return_address (rtx ra, rtx tmp)
 
   tmp = gen_frame_mem (Pmode, tmp);
   emit_insn (GEN_MOV (tmp, ra));
+  /* Tell this store isn't dead.  */
+  emit_use (tmp);
 }
 
 /* Clear variables at function end.  */
@@ -7072,17 +7551,22 @@ sh_build_builtin_va_list (void)
 
   record = (*lang_hooks.types.make_type) (RECORD_TYPE);
 
-  f_next_o = build_decl (FIELD_DECL, get_identifier ("__va_next_o"),
+  f_next_o = build_decl (BUILTINS_LOCATION,
+                        FIELD_DECL, get_identifier ("__va_next_o"),
                         ptr_type_node);
-  f_next_o_limit = build_decl (FIELD_DECL,
+  f_next_o_limit = build_decl (BUILTINS_LOCATION,
+                              FIELD_DECL,
                               get_identifier ("__va_next_o_limit"),
                               ptr_type_node);
-  f_next_fp = build_decl (FIELD_DECL, get_identifier ("__va_next_fp"),
+  f_next_fp = build_decl (BUILTINS_LOCATION,
+                         FIELD_DECL, get_identifier ("__va_next_fp"),
                          ptr_type_node);
-  f_next_fp_limit = build_decl (FIELD_DECL,
+  f_next_fp_limit = build_decl (BUILTINS_LOCATION,
+                               FIELD_DECL,
                                get_identifier ("__va_next_fp_limit"),
                                ptr_type_node);
-  f_next_stack = build_decl (FIELD_DECL, get_identifier ("__va_next_stack"),
+  f_next_stack = build_decl (BUILTINS_LOCATION,
+                            FIELD_DECL, get_identifier ("__va_next_stack"),
                             ptr_type_node);
 
   DECL_FIELD_CONTEXT (f_next_o) = record;
@@ -7285,8 +7769,8 @@ sh_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p,
        }
 
       addr = create_tmp_var (pptr_type_node, NULL);
-      lab_false = create_artificial_label ();
-      lab_over = create_artificial_label ();
+      lab_false = create_artificial_label (UNKNOWN_LOCATION);
+      lab_over = create_artificial_label (UNKNOWN_LOCATION);
 
       valist = build1 (INDIRECT_REF, ptr_type_node, addr);
 
@@ -7405,7 +7889,7 @@ sh_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p,
   if (result)
     {
       gimplify_assign (result, tmp, pre_p);
-
+      result = build1 (NOP_EXPR, TREE_TYPE (result), result);
       tmp = build1 (LABEL_EXPR, void_type_node, unshare_expr (lab_over));
       gimplify_and_add (tmp, pre_p);
     }
@@ -7438,6 +7922,17 @@ sh_dwarf_register_span (rtx reg)
                                              DBX_REGISTER_NUMBER (regno))));
 }
 
+static enum machine_mode
+sh_promote_function_mode (const_tree type, enum machine_mode mode,
+                         int *punsignedp, const_tree funtype,
+                         int for_return ATTRIBUTE_UNUSED)
+{
+  if (sh_promote_prototypes (funtype))
+    return promote_mode (type, mode, punsignedp);
+  else
+    return mode;
+}
+
 bool
 sh_promote_prototypes (const_tree type)
 {
@@ -8049,8 +8544,8 @@ sh_insert_attributes (tree node, tree *attributes)
                  || is_attribute_p ("nosave_low_regs", TREE_PURPOSE (attrs))
                  || is_attribute_p ("resbank", TREE_PURPOSE (attrs)))
                warning (OPT_Wattributes,
-                        "%qs attribute only applies to interrupt functions",
-                        IDENTIFIER_POINTER (TREE_PURPOSE (attrs)));
+                        "%qE attribute only applies to interrupt functions",
+                        TREE_PURPOSE (attrs));
              else
                {
                  *tail = tree_cons (TREE_PURPOSE (attrs), NULL_TREE,
@@ -8098,31 +8593,6 @@ sh_insert_attributes (tree node, tree *attributes)
    R0-R14, MACH, MACL, GBR and PR.  This is useful only on SH2A targets.
 */
 
-const struct attribute_spec sh_attribute_table[] =
-{
-  /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
-  { "interrupt_handler", 0, 0, true,  false, false, sh_handle_interrupt_handler_attribute },
-  { "sp_switch",         1, 1, true,  false, false, sh_handle_sp_switch_attribute },
-  { "trap_exit",         1, 1, true,  false, false, sh_handle_trap_exit_attribute },
-  { "renesas",           0, 0, false, true, false, sh_handle_renesas_attribute },
-  { "trapa_handler",     0, 0, true,  false, false, sh_handle_interrupt_handler_attribute },
-  { "nosave_low_regs",   0, 0, true,  false, false, sh_handle_interrupt_handler_attribute },
-  { "resbank",           0, 0, true,  false, false, sh_handle_resbank_handler_attribute },
-  { "function_vector",   1, 1, true,  false, false, sh2a_handle_function_vector_handler_attribute },
-#ifdef SYMBIAN
-  /* Symbian support adds three new attributes:
-     dllexport - for exporting a function/variable that will live in a dll
-     dllimport - for importing a function/variable from a dll
-
-     Microsoft allows multiple declspecs in one __declspec, separating
-     them with spaces.  We do NOT support this.  Instead, use __declspec
-     multiple times.  */
-  { "dllimport",         0, 0, true,  false, false, sh_symbian_handle_dll_attribute },
-  { "dllexport",         0, 0, true,  false, false, sh_symbian_handle_dll_attribute },
-#endif
-  { NULL,                0, 0, false, false, false, NULL }
-};
-
 /* Handle a 'resbank' attribute.  */
 static tree
 sh_handle_resbank_handler_attribute (tree * node, tree name,
@@ -8132,14 +8602,14 @@ sh_handle_resbank_handler_attribute (tree * node, tree name,
 {
   if (!TARGET_SH2A)
     {
-      warning (OPT_Wattributes, "%qs attribute is supported only for SH2A",
-               IDENTIFIER_POINTER (name));
+      warning (OPT_Wattributes, "%qE attribute is supported only for SH2A",
+               name);
       *no_add_attrs = true;
     }
   if (TREE_CODE (*node) != FUNCTION_DECL)
     {
-      warning (OPT_Wattributes, "%qs attribute only applies to functions",
-               IDENTIFIER_POINTER (name));
+      warning (OPT_Wattributes, "%qE attribute only applies to functions",
+               name);
       *no_add_attrs = true;
     }
 
@@ -8156,8 +8626,8 @@ sh_handle_interrupt_handler_attribute (tree *node, tree name,
 {
   if (TREE_CODE (*node) != FUNCTION_DECL)
     {
-      warning (OPT_Wattributes, "%qs attribute only applies to functions",
-               IDENTIFIER_POINTER (name));
+      warning (OPT_Wattributes, "%qE attribute only applies to functions",
+               name);
       *no_add_attrs = true;
     }
   else if (TARGET_SHCOMPACT)
@@ -8179,30 +8649,30 @@ sh2a_handle_function_vector_handler_attribute (tree * node, tree name,
 {
   if (!TARGET_SH2A)
     {
-      warning (OPT_Wattributes, "%qs attribute only applies to SH2A",
-               IDENTIFIER_POINTER (name));
+      warning (OPT_Wattributes, "%qE attribute only applies to SH2A",
+               name);
       *no_add_attrs = true;
     }
   else if (TREE_CODE (*node) != FUNCTION_DECL)
     {
-      warning (OPT_Wattributes, "%qs attribute only applies to functions",
-               IDENTIFIER_POINTER (name));
+      warning (OPT_Wattributes, "%qE attribute only applies to functions",
+               name);
       *no_add_attrs = true;
     }
   else if (TREE_CODE (TREE_VALUE (args)) != INTEGER_CST)
     {
       /* The argument must be a constant integer.  */
       warning (OPT_Wattributes,
-               "`%s' attribute argument not an integer constant",
-               IDENTIFIER_POINTER (name));
+               "%qE attribute argument not an integer constant",
+               name);
       *no_add_attrs = true;
     }
   else if (TREE_INT_CST_LOW (TREE_VALUE (args)) > 255)
     {
       /* The argument value must be between 0 to 255.  */
       warning (OPT_Wattributes,
-               "`%s' attribute argument should be between 0 to 255",
-               IDENTIFIER_POINTER (name));
+               "%qE attribute argument should be between 0 to 255",
+               name);
       *no_add_attrs = true;
     }
   return NULL_TREE;
@@ -8267,15 +8737,15 @@ sh_handle_sp_switch_attribute (tree *node, tree name, tree args,
 {
   if (TREE_CODE (*node) != FUNCTION_DECL)
     {
-      warning (OPT_Wattributes, "%qs attribute only applies to functions",
-              IDENTIFIER_POINTER (name));
+      warning (OPT_Wattributes, "%qE attribute only applies to functions",
+              name);
       *no_add_attrs = true;
     }
   else if (TREE_CODE (TREE_VALUE (args)) != STRING_CST)
     {
       /* The argument must be a constant string.  */
-      warning (OPT_Wattributes, "%qs attribute argument not a string constant",
-              IDENTIFIER_POINTER (name));
+      warning (OPT_Wattributes, "%qE attribute argument not a string constant",
+              name);
       *no_add_attrs = true;
     }
 
@@ -8290,8 +8760,8 @@ sh_handle_trap_exit_attribute (tree *node, tree name, tree args,
 {
   if (TREE_CODE (*node) != FUNCTION_DECL)
     {
-      warning (OPT_Wattributes, "%qs attribute only applies to functions",
-              IDENTIFIER_POINTER (name));
+      warning (OPT_Wattributes, "%qE attribute only applies to functions",
+              name);
       *no_add_attrs = true;
     }
   /* The argument specifies a trap number to be used in a trapa instruction
@@ -8299,8 +8769,8 @@ sh_handle_trap_exit_attribute (tree *node, tree name, tree args,
   else if (TREE_CODE (TREE_VALUE (args)) != INTEGER_CST)
     {
       /* The argument must be a constant integer.  */
-      warning (OPT_Wattributes, "%qs attribute argument not an "
-              "integer constant", IDENTIFIER_POINTER (name));
+      warning (OPT_Wattributes, "%qE attribute argument not an "
+              "integer constant", name);
       *no_add_attrs = true;
     }
 
@@ -8444,7 +8914,7 @@ fp_one_operand (rtx op)
   return REAL_VALUES_EQUAL (r, dconst1);
 }
 
-/* For -m4 and -m4-single-only, mode switching is used.  If we are
+/* In general mode switching is used.  If we are
    compiling without -mfmovd, movsf_ie isn't taken into account for
    mode switching.  We could check in machine_dependent_reorg for
    cases where we know we are in single precision mode, but there is
@@ -8454,7 +8924,7 @@ fp_one_operand (rtx op)
 int
 fldi_ok (void)
 {
-  return ! TARGET_SH4 || TARGET_FMOVD || reload_completed;
+  return 1;
 }
 
 int
@@ -8465,11 +8935,11 @@ tertiary_reload_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
 }
 
 /* Return the TLS type for TLS symbols, 0 for otherwise.  */
-int
+enum tls_model
 tls_symbolic_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
 {
   if (GET_CODE (op) != SYMBOL_REF)
-    return 0;
+    return TLS_MODEL_NONE;
   return SYMBOL_REF_TLS_MODEL (op);
 }
 \f
@@ -8501,7 +8971,7 @@ reg_unused_after (rtx reg, rtx insn)
      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);
-  if (set && GET_CODE (SET_DEST (set)) != MEM
+  if (set && !MEM_P (SET_DEST (set))
       && reg_overlap_mentioned_p (reg, SET_DEST (set)))
     return 1;
 
@@ -8540,9 +9010,9 @@ reg_unused_after (rtx reg, rtx insn)
              rtx this_insn = XVECEXP (PATTERN (insn), 0, i);
              rtx set = single_set (this_insn);
 
-             if (GET_CODE (this_insn) == CALL_INSN)
+             if (CALL_P (this_insn))
                code = CALL_INSN;
-             else if (GET_CODE (this_insn) == JUMP_INSN)
+             else if (JUMP_P (this_insn))
                {
                  if (INSN_ANNULLED_BRANCH_P (this_insn))
                    return 0;
@@ -8553,7 +9023,7 @@ reg_unused_after (rtx reg, rtx insn)
                return 0;
              if (set && reg_overlap_mentioned_p (reg, SET_DEST (set)))
                {
-                 if (GET_CODE (SET_DEST (set)) != MEM)
+                 if (!MEM_P (SET_DEST (set)))
                    retval = 1;
                  else
                    return 0;
@@ -8572,7 +9042,7 @@ reg_unused_after (rtx reg, rtx insn)
       if (set && reg_overlap_mentioned_p (reg, SET_SRC (set)))
        return 0;
       if (set && reg_overlap_mentioned_p (reg, SET_DEST (set)))
-       return GET_CODE (SET_DEST (set)) != MEM;
+       return !MEM_P (SET_DEST (set));
       if (set == 0 && reg_overlap_mentioned_p (reg, PATTERN (insn)))
        return 0;
 
@@ -8612,7 +9082,8 @@ emit_fpu_switch (rtx scratch, int index)
 
       t = build_index_type (integer_one_node);
       t = build_array_type (integer_type_node, t);
-      t = build_decl (VAR_DECL, get_identifier ("__fpscr_values"), t);
+      t = build_decl (BUILTINS_LOCATION,
+                     VAR_DECL, get_identifier ("__fpscr_values"), t);
       DECL_ARTIFICIAL (t) = 1;
       DECL_IGNORED_P (t) = 1;
       DECL_EXTERNAL (t) = 1;
@@ -8709,7 +9180,7 @@ get_free_reg (HARD_REG_SET regs_live)
 void
 fpscr_set_from_mem (int mode, HARD_REG_SET regs_live)
 {
-  enum attr_fp_mode fp_mode = mode;
+  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;
 
@@ -8727,11 +9198,11 @@ sh_insn_length_adjustment (rtx insn)
 {
   /* Instructions with unfilled delay slots take up an extra two bytes for
      the nop in the delay slot.  */
-  if (((GET_CODE (insn) == INSN
+  if (((NONJUMP_INSN_P (insn)
        && GET_CODE (PATTERN (insn)) != USE
        && GET_CODE (PATTERN (insn)) != CLOBBER)
-       || GET_CODE (insn) == CALL_INSN
-       || (GET_CODE (insn) == JUMP_INSN
+       || CALL_P (insn)
+       || (JUMP_P (insn)
           && GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC
           && GET_CODE (PATTERN (insn)) != ADDR_VEC))
       && GET_CODE (PATTERN (NEXT_INSN (PREV_INSN (insn)))) != SEQUENCE
@@ -8741,7 +9212,7 @@ sh_insn_length_adjustment (rtx insn)
   /* SH2e has a bug that prevents the use of annulled branches, so if
      the delay slot is not filled, we'll have to put a NOP in it.  */
   if (sh_cpu_attr == CPU_SH2E
-      && GET_CODE (insn) == JUMP_INSN
+      && JUMP_P (insn)
       && GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC
       && GET_CODE (PATTERN (insn)) != ADDR_VEC
       && get_attr_type (insn) == TYPE_CBRANCH
@@ -8750,7 +9221,7 @@ sh_insn_length_adjustment (rtx insn)
 
   /* sh-dsp parallel processing insn take four bytes instead of two.  */
 
-  if (GET_CODE (insn) == INSN)
+  if (NONJUMP_INSN_P (insn))
     {
       int sum = 0;
       rtx body = PATTERN (insn);
@@ -8804,6 +9275,124 @@ sh_insn_length_adjustment (rtx insn)
   return 0;
 }
 \f
+/* Return TRUE for a valid displacement for the REG+disp addressing
+   with MODE.  */
+
+/* ??? The SH2e does not have the REG+disp addressing mode when loading values
+   into the FRx registers.  We implement this by setting the maximum offset
+   to zero when the value is SFmode.  This also restricts loading of SFmode
+   values into the integer registers, but that can't be helped.  */
+
+/* The SH allows a displacement in a QI or HI amode, but only when the
+   other operand is R0. GCC doesn't handle this very well, so we forgot
+   all of that.
+
+   A legitimate index for a QI or HI is 0, SI can be any number 0..63,
+   DI can be any number 0..60.  */
+
+bool
+sh_legitimate_index_p (enum machine_mode mode, rtx op)
+{
+  if (CONST_INT_P (op))
+    {
+      if (TARGET_SHMEDIA)
+       {
+         int size;
+
+         /* Check if this the address of an unaligned load / store.  */
+         if (mode == VOIDmode)
+           return CONST_OK_FOR_I06 (INTVAL (op));
+
+         size = GET_MODE_SIZE (mode);
+         return (!(INTVAL (op) & (size - 1))
+                 && INTVAL (op) >= -512 * size
+                 && INTVAL (op) < 512 * size);
+       }
+
+      if (TARGET_SH2A)
+       {
+         if (GET_MODE_SIZE (mode) == 1
+               && (unsigned) INTVAL (op) < 4096)
+           return true;
+       }
+
+      if ((GET_MODE_SIZE (mode) == 4
+          && (unsigned) INTVAL (op) < 64
+          && !(INTVAL (op) & 3)
+          && !(TARGET_SH2E && mode == SFmode))
+         || (GET_MODE_SIZE (mode) == 4
+             && (unsigned) INTVAL (op) < 16383
+             && !(INTVAL (op) & 3) && TARGET_SH2A))
+       return true;
+
+      if ((GET_MODE_SIZE (mode) == 8
+          && (unsigned) INTVAL (op) < 60
+          && !(INTVAL (op) & 3)
+          && !((TARGET_SH4 || TARGET_SH2A) && mode == DFmode))
+         || ((GET_MODE_SIZE (mode)==8)
+             && (unsigned) INTVAL (op) < 8192
+             && !(INTVAL (op) & (TARGET_SH2A_DOUBLE ? 7 : 3))
+             && (TARGET_SH2A && mode == DFmode)))
+       return true;
+    }
+
+  return false;
+}
+
+/* Recognize an RTL expression that is a valid memory address for
+   an instruction.
+   The MODE argument is the machine mode for the MEM expression
+   that wants to use this address.
+   Allow  REG
+         REG+disp
+         REG+r0
+         REG++
+         --REG  */
+
+static bool
+sh_legitimate_address_p (enum machine_mode mode, rtx x, bool strict)
+{
+  if (MAYBE_BASE_REGISTER_RTX_P (x, strict))
+    return true;
+  else if ((GET_CODE (x) == POST_INC || GET_CODE (x) == PRE_DEC)
+          && ! TARGET_SHMEDIA
+          && MAYBE_BASE_REGISTER_RTX_P (XEXP (x, 0), strict))
+    return true;
+  else if (GET_CODE (x) == PLUS
+          && (mode != PSImode || reload_completed))
+    {
+      rtx xop0 = XEXP (x, 0);
+      rtx xop1 = XEXP (x, 1);
+
+      if (GET_MODE_SIZE (mode) <= 8
+         && MAYBE_BASE_REGISTER_RTX_P (xop0, strict)
+         && sh_legitimate_index_p (mode, xop1))
+       return true;
+
+      if ((ALLOW_INDEXED_ADDRESS || GET_MODE (x) == DImode
+          || ((xop0 == stack_pointer_rtx
+               || xop0 == hard_frame_pointer_rtx)
+              && REG_P (xop1) && REGNO (xop1) == R0_REG)
+          || ((xop1 == stack_pointer_rtx
+               || xop1 == hard_frame_pointer_rtx)
+              && REG_P (xop0) && REGNO (xop0) == R0_REG))
+         && ((!TARGET_SHMEDIA && GET_MODE_SIZE (mode) <= 4)
+             || (TARGET_SHMEDIA && GET_MODE_SIZE (mode) <= 8)
+             || ((TARGET_SH4 || TARGET_SH2A_DOUBLE)
+                 && TARGET_FMOVD && mode == DFmode)))
+       {
+         if (MAYBE_BASE_REGISTER_RTX_P (xop1, strict)
+             && MAYBE_INDEX_REGISTER_RTX_P (xop0, strict))
+           return true;
+         if (MAYBE_INDEX_REGISTER_RTX_P (xop1, strict)
+             && MAYBE_BASE_REGISTER_RTX_P (xop0, strict))
+           return true;
+       }
+    }
+
+  return false;
+}
+\f
 /* Return TRUE if X references a SYMBOL_REF or LABEL_REF whose symbol
    isn't protected by a PIC unspec.  */
 int
@@ -8857,7 +9446,7 @@ rtx
 legitimize_pic_address (rtx orig, enum machine_mode mode ATTRIBUTE_UNUSED,
                        rtx reg)
 {
-  if (tls_symbolic_operand (orig, Pmode))
+  if (tls_symbolic_operand (orig, Pmode) != TLS_MODEL_NONE)
     return orig;
 
   if (GET_CODE (orig) == LABEL_REF
@@ -8880,6 +9469,60 @@ legitimize_pic_address (rtx orig, enum machine_mode mode ATTRIBUTE_UNUSED,
   return orig;
 }
 
+/* Try machine-dependent ways of modifying an illegitimate address
+   to be legitimate.  If we find one, return the new, valid address.
+   Otherwise, return X.
+
+   For the SH, if X is almost suitable for indexing, but the offset is
+   out of range, convert it into a normal form so that CSE has a chance
+   of reducing the number of address registers used.  */
+
+static rtx
+sh_legitimize_address (rtx x, rtx oldx, enum machine_mode mode)
+{
+  if (flag_pic)
+    x = legitimize_pic_address (oldx, mode, NULL_RTX);
+
+  if (GET_CODE (x) == PLUS
+      && (GET_MODE_SIZE (mode) == 4
+         || GET_MODE_SIZE (mode) == 8)
+      && CONST_INT_P (XEXP (x, 1))
+      && BASE_REGISTER_RTX_P (XEXP (x, 0))
+      && ! TARGET_SHMEDIA
+      && ! ((TARGET_SH4 || TARGET_SH2A_DOUBLE) && mode == DFmode)
+      && ! (TARGET_SH2E && mode == SFmode))
+    {
+      rtx index_rtx = XEXP (x, 1);
+      HOST_WIDE_INT offset = INTVAL (index_rtx), offset_base;
+      rtx sum;
+
+      /* On rare occasions, we might get an unaligned pointer
+        that is indexed in a way to give an aligned address.
+        Therefore, keep the lower two bits in offset_base.  */
+      /* Instead of offset_base 128..131 use 124..127, so that
+        simple add suffices.  */
+      if (offset > 127)
+       offset_base = ((offset + 4) & ~60) - 4;
+      else
+       offset_base = offset & ~60;
+
+      /* Sometimes the normal form does not suit DImode.  We
+        could avoid that by using smaller ranges, but that
+        would give less optimized code when SImode is
+        prevalent.  */
+      if (GET_MODE_SIZE (mode) + offset - offset_base <= 64)
+       {
+         sum = expand_binop (Pmode, add_optab, XEXP (x, 0),
+                             GEN_INT (offset_base), NULL_RTX, 0,
+                             OPTAB_LIB_WIDEN);
+
+         return gen_rtx_PLUS (Pmode, sum, GEN_INT (offset - offset_base));
+       }
+    }
+
+  return x;
+}
+
 /* Mark the use of a constant in the literal table. If the constant
    has multiple labels, make it unique.  */
 static rtx
@@ -8905,7 +9548,7 @@ mark_constant_pool_use (rtx x)
   lab = x;
   for (insn = PREV_INSN (x); insn; insn = PREV_INSN (insn))
     {
-      if (GET_CODE (insn) != CODE_LABEL
+      if (!LABEL_P (insn)
          || LABEL_REFS (insn) != NEXT_INSN (insn))
        break;
       lab = insn;
@@ -8917,7 +9560,7 @@ mark_constant_pool_use (rtx x)
   /* Mark constants in a window.  */
   for (insn = NEXT_INSN (x); insn; insn = NEXT_INSN (insn))
     {
-      if (GET_CODE (insn) != INSN)
+      if (!NONJUMP_INSN_P (insn))
        continue;
 
       pattern = PATTERN (insn);
@@ -9091,7 +9734,7 @@ sh_adjust_cost (rtx insn, rtx link ATTRIBUTE_UNUSED, rtx dep_insn, int cost)
        }
       /* The only input for a call that is timing-critical is the
         function's address.  */
-      if (GET_CODE (insn) == CALL_INSN)
+      if (CALL_P (insn))
        {
          rtx call = PATTERN (insn);
 
@@ -9099,7 +9742,7 @@ sh_adjust_cost (rtx insn, rtx link ATTRIBUTE_UNUSED, rtx dep_insn, int cost)
            call = XVECEXP (call, 0 ,0);
          if (GET_CODE (call) == SET)
            call = SET_SRC (call);
-         if (GET_CODE (call) == CALL && GET_CODE (XEXP (call, 0)) == MEM
+         if (GET_CODE (call) == CALL && MEM_P (XEXP (call, 0))
                  /* sibcalli_thunk uses a symbol_ref in an unspec.  */
              && (GET_CODE (XEXP (XEXP (call, 0), 0)) == UNSPEC
                  || ! reg_set_p (XEXP (XEXP (call, 0), 0), dep_insn)))
@@ -9277,7 +9920,7 @@ find_set_regmode_weight (rtx x, enum machine_mode mode)
     return 1;
   if (GET_CODE (x) == SET && register_operand (SET_DEST (x), mode))
     {
-      if (GET_CODE (SET_DEST (x)) == REG)
+      if (REG_P (SET_DEST (x)))
        {
          if (!reg_mentioned_p (SET_DEST (x), SET_SRC (x)))
            return 1;
@@ -9314,7 +9957,7 @@ find_insn_regmode_weight (rtx insn, enum machine_mode mode)
       if (REG_NOTE_KIND (x) == REG_DEAD || REG_NOTE_KIND (x) == REG_UNUSED)
        {
          rtx note = XEXP (x, 0);
-         if (GET_CODE (note) == REG && GET_MODE (note) == mode)
+         if (REG_P (note) && GET_MODE (note) == mode)
            reg_weight--;
        }
     }
@@ -9636,7 +10279,7 @@ sh_cannot_modify_jumps_p (void)
   return (TARGET_SHMEDIA && (reload_in_progress || reload_completed));
 }
 
-static int
+static enum reg_class
 sh_target_reg_class (void)
 {
   return TARGET_SHMEDIA ? TARGET_REGS : NO_REGS;
@@ -10356,7 +10999,7 @@ sh_mark_label (rtx address, int nuses)
       address = XVECEXP (address, 0, 0);
     }
   if (GET_CODE (address) == LABEL_REF
-      && GET_CODE (XEXP (address, 0)) == CODE_LABEL)
+      && LABEL_P (XEXP (address, 0)))
     LABEL_NUSES (XEXP (address, 0)) += nuses;
 }
 
@@ -10623,41 +11266,12 @@ sh_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
   insn_locators_alloc ();
   insns = get_insns ();
 
-#if 0
-  if (optimize > 0)
-    {
-      /* Initialize the bitmap obstacks.  */
-      bitmap_obstack_initialize (NULL);
-      bitmap_obstack_initialize (&reg_obstack);
-      if (! cfun->cfg)
-       init_flow ();
-      rtl_register_cfg_hooks ();
-      init_rtl_bb_info (ENTRY_BLOCK_PTR);
-      init_rtl_bb_info (EXIT_BLOCK_PTR);
-      ENTRY_BLOCK_PTR->flags |= BB_RTL;
-      EXIT_BLOCK_PTR->flags |= BB_RTL;
-      find_basic_blocks (insns);
-
-      if (flag_schedule_insns_after_reload)
-       {
-         life_analysis (PROP_FINAL);
-
-         split_all_insns (1);
-
-         schedule_insns ();
-       }
-      /* We must split jmp insn in PIC case.  */
-      else if (flag_pic)
-       split_all_insns_noflow ();
-    }
-#else
   if (optimize > 0)
     {
       if (! cfun->cfg)
        init_flow (cfun);
       split_all_insns_noflow ();
     }
-#endif
 
   sh_reorg ();
 
@@ -10766,22 +11380,26 @@ sh_get_pr_initial_val (void)
 }
 
 int
-sh_expand_t_scc (enum rtx_code code, rtx target)
+sh_expand_t_scc (rtx operands[])
 {
+  enum rtx_code code = GET_CODE (operands[1]);
+  rtx target = operands[0];
+  rtx op0 = operands[2];
+  rtx op1 = operands[3];
   rtx result = target;
   HOST_WIDE_INT val;
 
-  if (GET_CODE (sh_compare_op0) != REG || REGNO (sh_compare_op0) != T_REG
-      || GET_CODE (sh_compare_op1) != CONST_INT)
+  if (!REG_P (op0) || REGNO (op0) != T_REG
+      || !CONST_INT_P (op1))
     return 0;
-  if (GET_CODE (result) != REG)
+  if (!REG_P (result))
     result = gen_reg_rtx (SImode);
-  val = INTVAL (sh_compare_op1);
+  val = INTVAL (op1);
   if ((code == EQ && val == 1) || (code == NE && val == 0))
     emit_insn (gen_movt (result));
   else if (TARGET_SH2A && ((code == EQ && val == 0)
                            || (code == NE && val == 1)))
-    emit_insn (gen_movrt (result));
+    emit_insn (gen_xorsi3_movrt (result));
   else if ((code == EQ && val == 0) || (code == NE && val == 1))
     {
       emit_clobber (result);
@@ -10828,7 +11446,7 @@ check_use_sfunc_addr (rtx insn, rtx reg)
   /* Search for the sfunc.  It should really come right after INSN.  */
   while ((insn = NEXT_INSN (insn)))
     {
-      if (GET_CODE (insn) == CODE_LABEL || GET_CODE (insn) == JUMP_INSN)
+      if (LABEL_P (insn) || JUMP_P (insn))
        break;
       if (! INSN_P (insn))
        continue;
@@ -11016,7 +11634,7 @@ replace_n_hard_rtx (rtx x, rtx *replacements, int n_replacements, int modify)
       rtx new_rtx = replace_n_hard_rtx (SUBREG_REG (x), replacements,
                                    n_replacements, modify);
 
-      if (GET_CODE (new_rtx) == CONST_INT)
+      if (CONST_INT_P (new_rtx))
        {
          x = simplify_subreg (GET_MODE (x), new_rtx,
                               GET_MODE (SUBREG_REG (x)),
@@ -11029,7 +11647,7 @@ replace_n_hard_rtx (rtx x, rtx *replacements, int n_replacements, int modify)
 
       return x;
     }
-  else if (GET_CODE (x) == REG)
+  else if (REG_P (x))
     {
       unsigned regno = REGNO (x);
       unsigned nregs = (regno < FIRST_PSEUDO_REGISTER
@@ -11042,7 +11660,7 @@ replace_n_hard_rtx (rtx x, rtx *replacements, int n_replacements, int modify)
          rtx to = replacements[i*2+1];
          unsigned from_regno, from_nregs, to_regno, new_regno;
 
-         if (GET_CODE (from) != REG)
+         if (!REG_P (from))
            continue;
          from_regno = REGNO (from);
          from_nregs = (from_regno < FIRST_PSEUDO_REGISTER
@@ -11051,7 +11669,7 @@ replace_n_hard_rtx (rtx x, rtx *replacements, int n_replacements, int modify)
            {
              if (regno < from_regno
                  || regno + nregs > from_regno + nregs
-                 || GET_CODE (to) != REG
+                 || !REG_P (to)
                  || result)
                return NULL_RTX;
              to_regno = REGNO (to);
@@ -11076,7 +11694,7 @@ replace_n_hard_rtx (rtx x, rtx *replacements, int n_replacements, int modify)
       rtx new_rtx = replace_n_hard_rtx (XEXP (x, 0), replacements,
                                    n_replacements, modify);
 
-      if (GET_CODE (new_rtx) == CONST_INT)
+      if (CONST_INT_P (new_rtx))
        {
          x = simplify_unary_operation (ZERO_EXTEND, GET_MODE (x),
                                        new_rtx, GET_MODE (XEXP (x, 0)));
@@ -11152,7 +11770,7 @@ shmedia_cleanup_truncate (rtx *p, void *n_changes)
   if (GET_CODE (x) != TRUNCATE)
     return 0;
   reg = XEXP (x, 0);
-  if (GET_MODE_SIZE (GET_MODE (reg)) > 8 && GET_CODE (reg) == REG)
+  if (GET_MODE_SIZE (GET_MODE (reg)) > 8 && REG_P (reg))
     {
       enum machine_mode reg_mode = GET_MODE (reg);
       XEXP (x, 0) = simplify_subreg (DImode, reg, reg_mode,
@@ -11172,7 +11790,7 @@ shmedia_cleanup_truncate (rtx *p, void *n_changes)
 static int
 sh_contains_memref_p_1 (rtx *loc, void *data ATTRIBUTE_UNUSED)
 {
-  return (GET_CODE (*loc) == MEM);
+  return (MEM_P (*loc));
 }
 
 /* Return nonzero iff INSN contains a MEM.  */
@@ -11271,7 +11889,7 @@ sh_secondary_reload (bool in_p, rtx x, enum reg_class rclass,
            abort ();
          }
       if (rclass == FPUL_REGS
-          && ((GET_CODE (x) == REG
+          && ((REG_P (x)
                && (REGNO (x) == MACL_REG || REGNO (x) == MACH_REG
                    || REGNO (x) == T_REG))
               || GET_CODE (x) == PLUS))
@@ -11286,8 +11904,8 @@ sh_secondary_reload (bool in_p, rtx x, enum reg_class rclass,
          return NO_REGS;
        }
       if (rclass == FPSCR_REGS
-          && ((GET_CODE (x) == REG && REGNO (x) >= FIRST_PSEUDO_REGISTER)
-              || (GET_CODE (x) == MEM && GET_CODE (XEXP (x, 0)) == PLUS)))
+          && ((REG_P (x) && REGNO (x) >= FIRST_PSEUDO_REGISTER)
+              || (MEM_P (x) && GET_CODE (XEXP (x, 0)) == PLUS)))
         return GENERAL_REGS;
       if (REGCLASS_HAS_FP_REG (rclass)
           && TARGET_SHMEDIA
@@ -11308,12 +11926,12 @@ sh_secondary_reload (bool in_p, rtx x, enum reg_class rclass,
     } /* end of input-only processing.  */
 
   if (((REGCLASS_HAS_FP_REG (rclass)
-       && (GET_CODE (x) == REG
+       && (REG_P (x)
            && (GENERAL_OR_AP_REGISTER_P (REGNO (x))
                || (FP_REGISTER_P (REGNO (x)) && mode == SImode
                    && TARGET_FMOVD))))
        || (REGCLASS_HAS_GENERAL_REG (rclass)
-          && GET_CODE (x) == REG
+          && REG_P (x)
           && FP_REGISTER_P (REGNO (x))))
       && ! TARGET_SHMEDIA
       && (mode == SFmode || mode == SImode))
@@ -11321,8 +11939,8 @@ sh_secondary_reload (bool in_p, rtx x, enum reg_class rclass,
   if ((rclass == FPUL_REGS
        || (REGCLASS_HAS_FP_REG (rclass)
            && ! TARGET_SHMEDIA && mode == SImode))
-      && (GET_CODE (x) == MEM
-          || (GET_CODE (x) == REG
+      && (MEM_P (x)
+          || (REG_P (x)
               && (REGNO (x) >= FIRST_PSEUDO_REGISTER
                   || REGNO (x) == T_REG
                   || system_reg_operand (x, VOIDmode)))))
@@ -11334,13 +11952,13 @@ sh_secondary_reload (bool in_p, rtx x, enum reg_class rclass,
   if ((rclass == TARGET_REGS
        || (TARGET_SHMEDIA && rclass == SIBCALL_REGS))
       && !satisfies_constraint_Csy (x)
-      && (GET_CODE (x) != REG || ! GENERAL_REGISTER_P (REGNO (x))))
+      && (!REG_P (x) || ! GENERAL_REGISTER_P (REGNO (x))))
     return GENERAL_REGS;
   if ((rclass == MAC_REGS || rclass == PR_REGS)
-      && GET_CODE (x) == REG && ! GENERAL_REGISTER_P (REGNO (x))
+      && REG_P (x) && ! GENERAL_REGISTER_P (REGNO (x))
       && rclass != REGNO_REG_CLASS (REGNO (x)))
     return GENERAL_REGS;
-  if (rclass != GENERAL_REGS && GET_CODE (x) == REG
+  if (rclass != GENERAL_REGS && REG_P (x)
       && TARGET_REGISTER_P (REGNO (x)))
     return GENERAL_REGS;
   return NO_REGS;