OSDN Git Service

* tree.h (build_int_cst): New, sign extended constant.
[pf3gnuchains/gcc-fork.git] / gcc / config / sh / sh.c
index 4003f16..31104e5 100644 (file)
@@ -2,7 +2,7 @@
    Copyright (C) 1993, 1994, 1995, 1997, 1997, 1998, 1999, 2000, 2001, 2002,
    2003, 2004 Free Software Foundation, Inc.
    Contributed by Steve Chamberlain (sac@cygnus.com).
-   Improved by Jim Wilson (wilson@cygnus.com). 
+   Improved by Jim Wilson (wilson@cygnus.com).
 
 This file is part of GCC.
 
@@ -227,7 +227,6 @@ static tree sh_handle_renesas_attribute (tree *, tree, tree, int, bool *);
 static void sh_output_function_epilogue (FILE *, HOST_WIDE_INT);
 static void sh_insert_attributes (tree, tree *);
 static int sh_adjust_cost (rtx, rtx, rtx, int);
-static int sh_use_dfa_interface (void);
 static int sh_issue_rate (void);
 static int sh_dfa_new_cycle (FILE *, int, rtx, int, int, int *sort_p);
 static short find_set_regmode_weight (rtx, enum machine_mode);
@@ -243,7 +242,7 @@ static int sh_reorder (FILE *, int, rtx *, int *, int);
 static int sh_reorder2 (FILE *, int, rtx *, int *, int);
 static void sh_md_init (FILE *, int, int);
 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);
@@ -282,6 +281,8 @@ static bool sh_strict_argument_naming (CUMULATIVE_ARGS *);
 static bool sh_pretend_outgoing_varargs_named (CUMULATIVE_ARGS *);
 static tree sh_build_builtin_va_list (void);
 static tree sh_gimplify_va_arg_expr (tree, tree, tree *, tree *);
+static bool sh_pass_by_reference (CUMULATIVE_ARGS *, enum machine_mode,
+                                 tree, bool);
 
 \f
 /* Initialize the GCC target structure.  */
@@ -320,19 +321,16 @@ static tree sh_gimplify_va_arg_expr (tree, tree, tree *, tree *);
 #undef TARGET_SCHED_ADJUST_COST
 #define TARGET_SCHED_ADJUST_COST sh_adjust_cost
 
-#undef TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE 
-#define TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE \
-                               sh_use_dfa_interface
 #undef TARGET_SCHED_ISSUE_RATE
 #define TARGET_SCHED_ISSUE_RATE sh_issue_rate
 
 /* The next 5 hooks have been implemented for reenabling sched1.  With the
    help of these macros we are limiting the movement of insns in sched1 to
-   reduce the register pressure.  The overall idea is to keep count of SImode 
+   reduce the register pressure.  The overall idea is to keep count of SImode
    and SFmode regs required by already scheduled insns. When these counts
    cross some threshold values; give priority to insns that free registers.
    The insn that frees registers is most likely to be the insn with lowest
-   LUID (original insn order); but such an insn might be there in the stalled 
+   LUID (original insn order); but such an insn might be there in the stalled
    queue (Q) instead of the ready queue (R).  To solve this, we skip cycles
    upto a max of 8 cycles so that such insns may move from Q -> R.
 
@@ -342,7 +340,7 @@ static tree sh_gimplify_va_arg_expr (tree, tree, tree *, tree *);
    scheduler; it is called inside the sched_init function just after
    find_insn_reg_weights function call. It is used to calculate the SImode
    and SFmode weights of insns of basic blocks; much similar to what
-   find_insn_reg_weights does. 
+   find_insn_reg_weights does.
    TARGET_SCHED_FINISH_GLOBAL: Corresponding cleanup hook.
 
    TARGET_SCHED_DFA_NEW_CYCLE: Skip cycles if high register pressure is
@@ -438,12 +436,17 @@ static tree sh_gimplify_va_arg_expr (tree, tree, tree *, tree *);
 #define TARGET_PRETEND_OUTGOING_VARARGS_NAMED sh_pretend_outgoing_varargs_named
 #undef TARGET_MUST_PASS_IN_STACK
 #define TARGET_MUST_PASS_IN_STACK must_pass_in_stack_var_size
+#undef TARGET_PASS_BY_REFERENCE
+#define TARGET_PASS_BY_REFERENCE sh_pass_by_reference
 
 #undef TARGET_BUILD_BUILTIN_VA_LIST
 #define TARGET_BUILD_BUILTIN_VA_LIST sh_build_builtin_va_list
 #undef TARGET_GIMPLIFY_VA_ARG_EXPR
 #define TARGET_GIMPLIFY_VA_ARG_EXPR sh_gimplify_va_arg_expr
 
+#undef TARGET_VECTOR_MODE_SUPPORTED_P
+#define TARGET_VECTOR_MODE_SUPPORTED_P sh_vector_mode_supported_p
+
 #undef TARGET_PCH_VALID_P
 #define TARGET_PCH_VALID_P sh_pch_valid_p
 
@@ -537,6 +540,7 @@ print_operand_address (FILE *stream, rtx x)
    'T'  print the next word of a dp value - same as 'R' in big endian mode.
    'M'  print an `x' if `m' will print `base,index'.
    'N'  print 'r63' if the operand is (const_int 0).
+   'd'  print a V2SF reg as dN instead of fpN.
    'm'  print a pair `base,offset' or `base,index', for LD and ST.
    'u'  prints the lowest 16 bits of CONST_INT, as an unsigned value.
    'o'  output an operator.  */
@@ -651,6 +655,13 @@ print_operand (FILE *stream, rtx x, int code)
        }
       break;
 
+    case 'd':
+      if (GET_CODE (x) != REG || GET_MODE (x) != V2SFmode)
+       abort ();
+
+      fprintf ((stream), "d%s", reg_names[REGNO (x)] + 1);
+      break;
+
     case 'N':
       if (x == CONST0_RTX (GET_MODE (x)))
        {
@@ -703,7 +714,7 @@ print_operand (FILE *stream, rtx x, int code)
        case MEM:
          output_address (XEXP (x, 0));
          break;
-         
+
        case CONST:
          if (TARGET_SHMEDIA
              && GET_CODE (XEXP (x, 0)) == SIGN_EXTEND
@@ -772,9 +783,48 @@ expand_block_move (rtx *operands)
   int constp = (GET_CODE (operands[2]) == CONST_INT);
   int bytes = (constp ? INTVAL (operands[2]) : 0);
 
+  if (! constp)
+    return 0;
+
+  /* If we could use mov.l to move words and dest is word-aligned, we
+     can use movua.l for loads and still generate a relatively short
+     and efficient sequence.  */
+  if (TARGET_SH4A_ARCH && align < 4
+      && MEM_ALIGN (operands[0]) >= 32
+      && can_move_by_pieces (bytes, 32))
+    {
+      rtx dest = copy_rtx (operands[0]);
+      rtx src = copy_rtx (operands[1]);
+      /* We could use different pseudos for each copied word, but
+        since movua can only load into r0, it's kind of
+        pointless.  */
+      rtx temp = gen_reg_rtx (SImode);
+      rtx src_addr = copy_addr_to_reg (XEXP (src, 0));
+      int copied = 0;
+
+      while (copied + 4 <= bytes)
+       {
+         rtx to = adjust_address (dest, SImode, copied);
+         rtx from = adjust_automodify_address (src, SImode, src_addr, copied);
+
+         emit_insn (gen_movua (temp, from));
+         emit_move_insn (src_addr, plus_constant (src_addr, 4));
+         emit_move_insn (to, temp);
+         copied += 4;
+       }
+
+      if (copied < bytes)
+       move_by_pieces (adjust_address (dest, BLKmode, copied),
+                       adjust_automodify_address (src, BLKmode,
+                                                  src_addr, copied),
+                       bytes - copied, align, 0);
+
+      return 1;
+    }
+
   /* If it isn't a constant number of bytes, or if it doesn't have 4 byte
      alignment, or if it isn't a multiple of 4 bytes, then fail.  */
-  if (! constp || align < 4 || (bytes % 4 != 0))
+  if (align < 4 || (bytes % 4 != 0))
     return 0;
 
   if (TARGET_HARD_SH4)
@@ -956,7 +1006,7 @@ prepare_move_operands (rtx operands[], enum machine_mode mode)
        {
          rtx tga_op1, tga_ret, tmp, tmp2;
 
-         
+
          switch (tls_kind)
            {
            case TLS_MODEL_GLOBAL_DYNAMIC:
@@ -995,7 +1045,6 @@ prepare_move_operands (rtx operands[], enum machine_mode mode)
              emit_insn (gen_load_gbr (tmp2));
              tmp = gen_reg_rtx (Pmode);
              emit_insn (gen_symTPOFF2reg (tmp, op1));
-             RTX_UNCHANGING_P (tmp) = 1;
 
              if (register_operand (op0, Pmode))
                op1 = op0;
@@ -1064,7 +1113,7 @@ prepare_scc_operands (enum rtx_code code)
       || (TARGET_SH2E && GET_MODE_CLASS (mode) == MODE_FLOAT))
     sh_compare_op1 = force_reg (mode, sh_compare_op1);
 
-  if (TARGET_SH4 && GET_MODE_CLASS (mode) == MODE_FLOAT)
+  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,
@@ -1109,7 +1158,7 @@ from_compare (rtx *operands, int code)
                        gen_rtx_REG (SImode, T_REG),
                        gen_rtx_fmt_ee (code, SImode,
                                        sh_compare_op0, sh_compare_op1));
-  if (TARGET_SH4 && GET_MODE_CLASS (mode) == MODE_FLOAT)
+  if ((TARGET_SH4 || TARGET_SH2A) && GET_MODE_CLASS (mode) == MODE_FLOAT)
     {
       insn = gen_rtx_PARALLEL (VOIDmode,
                      gen_rtvec (2, insn,
@@ -1324,11 +1373,11 @@ output_branch (int logic, rtx insn, rtx *operands)
          int label = lf++;
          /* The call to print_slot will clobber the operands.  */
          rtx op0 = operands[0];
-    
+
          /* If the instruction in the delay slot is annulled (true), then
             there is no delay slot where we can put it now.  The only safe
             place for it is after the label.  final will do that by default.  */
-    
+
          if (final_sequence
              && ! INSN_ANNULLED_BRANCH_P (XVECEXP (final_sequence, 0, 0)))
            {
@@ -1338,11 +1387,11 @@ output_branch (int logic, rtx insn, rtx *operands)
            }
          else
            asm_fprintf (asm_out_file, "\tb%s\t%LLF%d\n", logic ? "f" : "t", label);
-    
+
          output_asm_insn ("bra\t%l0", &op0);
          fprintf (asm_out_file, "\tnop\n");
          (*targetm.asm_out.internal_label) (asm_out_file, "LF", label);
-    
+
          return "";
        }
       /* When relaxing, handle this like a short branch.  The linker
@@ -1374,7 +1423,7 @@ output_branch (int logic, rtx insn, rtx *operands)
     case 4:
       {
        char buffer[10];
-       
+
        sprintf (buffer, "b%s%ss\t%%l0",
                 logic ? "t" : "f",
                 ASSEMBLER_DIALECT ? "/" : ".");
@@ -1449,7 +1498,7 @@ sh_file_start (void)
   fputs ("\t.section .directive, \"SM\", @progbits, 1\n", asm_out_file);
   fputs ("\t.asciz \"#<SYMEDIT>#\\n\"\n", asm_out_file);
 #endif
-  
+
   if (TARGET_ELF)
     /* We need to show the text section with the proper
        attributes as in TEXT_SECTION_ASM_OP, before dwarf2out
@@ -1553,7 +1602,7 @@ static const short shift_amounts[32][5] = {
 /* Likewise, but for shift amounts < 16, up to three highmost bits
    might be clobbered.  This is typically used when combined with some
    kind of sign or zero extension.  */
-   
+
 static const char ext_shift_insns[]    =
   { 0,1,1,2,2,3,2,2,1,2,2,3,3,3,2,2,1,2,2,3,3,4,3,3,2,3,3,4,4,4,3,3};
 
@@ -1917,7 +1966,7 @@ gen_ashift_hi (int type, int n, rtx reg)
 
 /* Output RTL to split a constant shift into its component SH constant
    shift instructions.  */
-   
+
 void
 gen_shifty_op (int code, rtx *operands)
 {
@@ -1926,7 +1975,7 @@ gen_shifty_op (int code, rtx *operands)
 
   /* Truncate the shift count in case it is out of bounds.  */
   value = value & 0x1f;
+
   if (value == 31)
     {
       if (code == LSHIFTRT)
@@ -1960,7 +2009,7 @@ gen_shifty_op (int code, rtx *operands)
   for (i = 0; i < max; i++)
     gen_ashift (code, shift_amounts[value][i], operands[0]);
 }
-   
+
 /* Same as above, but optimized for values where the topmost bits don't
    matter.  */
 
@@ -2239,9 +2288,6 @@ shl_and_scr_length (rtx insn)
   return len + shift_insns[INTVAL (XEXP (op, 1))];
 }
 
-/* Generating rtl? */
-extern int rtx_equal_function_value_matters;
-
 /* Generate rtl for instructions for which shl_and_kind advised a particular
    method of generating them, i.e. returned zero.  */
 
@@ -2312,11 +2358,11 @@ gen_shl_and (rtx dest, rtx left_rtx, rtx mask_rtx, rtx source)
     case 2:
       /* Don't expand fine-grained when combining, because that will
          make the pattern fail.  */
-      if (rtx_equal_function_value_matters
+      if (currently_expanding_to_rtl
          || reload_in_progress || reload_completed)
        {
          rtx operands[3];
-  
+
          /* Cases 3 and 4 should be handled by this split
             only while combining  */
          if (kind > 2)
@@ -2509,7 +2555,7 @@ gen_shl_sext (rtx dest, rtx left_rtx, rtx size_rtx, rtx source)
 
        /* Don't expand fine-grained when combining, because that will
           make the pattern fail.  */
-       if (! rtx_equal_function_value_matters
+       if (! currently_expanding_to_rtl
            && ! reload_in_progress && ! reload_completed)
          {
            emit_insn (gen_shl_sext_ext (dest, source, left_rtx, size_rtx));
@@ -2564,7 +2610,7 @@ gen_shl_sext (rtx dest, rtx left_rtx, rtx size_rtx, rtx source)
     case 5:
       {
        int i = 16 - size;
-       if (! rtx_equal_function_value_matters
+       if (! currently_expanding_to_rtl
            && ! reload_in_progress && ! reload_completed)
          emit_insn (gen_shl_sext_ext (dest, source, left_rtx, size_rtx));
        else
@@ -2583,7 +2629,7 @@ gen_shl_sext (rtx dest, rtx left_rtx, rtx size_rtx, rtx source)
     case 7:
       /* Don't expand fine-grained when combining, because that will
         make the pattern fail.  */
-      if (! rtx_equal_function_value_matters
+      if (! currently_expanding_to_rtl
          && ! reload_in_progress && ! reload_completed)
        {
          emit_insn (gen_shl_sext_ext (dest, source, left_rtx, size_rtx));
@@ -2615,7 +2661,7 @@ gen_datalabel_ref (rtx sym)
                          gen_rtx_UNSPEC (GET_MODE (sym),
                                          gen_rtvec (1, sym),
                                          UNSPEC_DATALABEL));
-    
+
   if (GET_CODE (sym) != SYMBOL_REF)
     abort ();
 
@@ -2912,7 +2958,7 @@ dump_table (rtx start, rtx barrier)
 
       pool_size = 0;
     }
-  
+
   for (i = 0; i < pool_size; i++)
     {
       pool_node *p = &pool_vector[i];
@@ -3019,6 +3065,10 @@ broken_move (rtx insn)
                        == SCRATCH))
                && GET_CODE (SET_DEST (pat)) == REG
                && FP_REGISTER_P (REGNO (SET_DEST (pat))))
+         && ! (TARGET_SH2A
+               && GET_MODE (SET_DEST (pat)) == SImode
+               && GET_CODE (SET_SRC (pat)) == CONST_INT
+               && CONST_OK_FOR_I20 (INTVAL (SET_SRC (pat))))
          && (GET_CODE (SET_SRC (pat)) != CONST_INT
              || ! CONST_OK_FOR_I08 (INTVAL (SET_SRC (pat)))))
        return 1;
@@ -3466,7 +3516,7 @@ regs_used (rtx x, int is_dest)
     case SUBREG:
       {
        rtx y = SUBREG_REG (x);
-     
+
        if (GET_CODE (y) != REG)
          break;
        if (REGNO (y) < 16)
@@ -3521,7 +3571,7 @@ regs_used (rtx x, int is_dest)
    pass 1.  Pass 2 if a definite blocking insn is needed.
    -1 is used internally to avoid deep recursion.
    If a blocking instruction is made or recognized, return it.  */
-   
+
 static rtx
 gen_block_redirect (rtx jump, int addr, int need_block)
 {
@@ -3564,11 +3614,11 @@ gen_block_redirect (rtx jump, int addr, int need_block)
         it would cause trouble if an interrupt occurred.  */
       unsigned try = 0x7fff, used;
       int jump_left = flag_expensive_optimizations + 1;
-    
+
       /* It is likely that the most recent eligible instruction is wanted for
         the delay slot.  Therefore, find out which registers it uses, and
         try to avoid using them.  */
-        
+
       for (scan = jump; (scan = PREV_INSN (scan)); )
        {
          enum rtx_code code;
@@ -3623,7 +3673,7 @@ gen_block_redirect (rtx jump, int addr, int need_block)
      threading with a jump beyond the delay slot insn.
      Don't check if we are called recursively; the jump has been or will be
      checked in a different invocation then.  */
-       
+
   else if (optimize && need_block >= 0)
     {
       rtx next = next_active_insn (next_active_insn (dest));
@@ -3658,7 +3708,7 @@ gen_block_redirect (rtx jump, int addr, int need_block)
         Hence, after delay slot scheduling, we'll have to expect
         NOTE_INSN_BLOCK_END notes between the indirect_jump_scratch and
         the jump.  */
-        
+
       INSN_LOCATOR (insn) = INSN_LOCATOR (jump);
       INSN_CODE (insn) = CODE_FOR_indirect_jump_scratch;
       return insn;
@@ -3763,6 +3813,10 @@ fixup_addr_diff_vecs (rtx first)
          if (GET_CODE (x) == LABEL_REF && XEXP (x, 0) == vec_lab)
            break;
        }
+      /* FIXME: This is a bug in the optimizer, but it seems harmless
+        to just avoid panicing.  */
+      if (!prev)
+       continue;
 
       /* Emit the reference label of the braf where it belongs, right after
         the casesi_jump_2 (i.e. braf).  */
@@ -3782,7 +3836,7 @@ barrier_align (rtx barrier_or_label)
 {
   rtx next = next_real_insn (barrier_or_label), pat, prev;
   int slot, credit, jump_to_next = 0;
+
   if (! next)
     return 0;
 
@@ -3824,11 +3878,11 @@ barrier_align (rtx barrier_or_label)
         an alignment, against that of fetching unneeded insn in front of the
         branch target when there is no alignment.  */
 
-      /* There are two delay_slot cases to consider.  One is the simple case 
-        where the preceding branch is to the insn beyond the barrier (simple 
-        delay slot filling), and the other is where the preceding branch has 
-        a delay slot that is a duplicate of the insn after the barrier 
-        (fill_eager_delay_slots) and the branch is to the insn after the insn 
+      /* There are two delay_slot cases to consider.  One is the simple case
+        where the preceding branch is to the insn beyond the barrier (simple
+        delay slot filling), and the other is where the preceding branch has
+        a delay slot that is a duplicate of the insn after the barrier
+        (fill_eager_delay_slots) and the branch is to the insn after the insn
         after the barrier.  */
 
       /* PREV is presumed to be the JUMP_INSN for the barrier under
@@ -3846,7 +3900,7 @@ barrier_align (rtx barrier_or_label)
          if (GET_CODE (PATTERN (prev)) == SEQUENCE)
            {
              prev = XVECEXP (PATTERN (prev), 0, 1);
-             if (INSN_UID (prev) == INSN_UID (next)) 
+             if (INSN_UID (prev) == INSN_UID (next))
                {
                  /* Delay slot was filled with insn at jump target.  */
                  jump_to_next = 1;
@@ -3873,8 +3927,8 @@ barrier_align (rtx barrier_or_label)
              /* There is no upper bound on redundant instructions
                 that might have been skipped, but we must not put an
                 alignment where none had been before.  */
-             || (x = (NEXT_INSN (NEXT_INSN (PREV_INSN (prev)))),           
-                 (INSN_P (x) 
+             || (x = (NEXT_INSN (NEXT_INSN (PREV_INSN (prev)))),
+                 (INSN_P (x)
                   && (INSN_CODE (x) == CODE_FOR_block_branch_redirect
                       || INSN_CODE (x) == CODE_FOR_indirect_jump_scratch
                       || INSN_CODE (x) == CODE_FOR_stuff_delay_slot))))
@@ -3887,7 +3941,7 @@ barrier_align (rtx barrier_or_label)
            }
        }
     }
-  
+
   return align_jumps_log;
 }
 
@@ -4331,7 +4385,6 @@ sh_reorg (void)
                      /* Remove the clobber of r0.  */
                      *clobberp = gen_rtx_CLOBBER (GET_MODE (clobber),
                                                   gen_rtx_SCRATCH (Pmode));
-                     RTX_UNCHANGING_P (newsrc) = 1;
                    }
                  /* This is a mova needing a label.  Create it.  */
                  else if (GET_CODE (src) == UNSPEC
@@ -4347,9 +4400,8 @@ sh_reorg (void)
                  else
                    {
                      lab = add_constant (src, mode, 0);
-                     newsrc = gen_rtx_MEM (mode,
-                                           gen_rtx_LABEL_REF (VOIDmode, lab));
-                     RTX_UNCHANGING_P (newsrc) = 1;
+                     newsrc = gen_rtx_LABEL_REF (VOIDmode, lab);
+                     newsrc = gen_const_mem (mode, newsrc);
                    }
                  *patp = gen_rtx_SET (VOIDmode, dst, newsrc);
                  INSN_CODE (scan) = -1;
@@ -4452,7 +4504,7 @@ split_branches (rtx first)
        if (type == TYPE_CBRANCH)
          {
            rtx next, beyond;
-    
+
            if (get_attr_length (insn) > 4)
              {
                rtx src = SET_SRC (PATTERN (insn));
@@ -4461,7 +4513,7 @@ split_branches (rtx first)
                rtx label = 0;
                int dest_uid = get_dest_uid (olabel, max_uid);
                struct far_branch *bp = uid_branch[dest_uid];
-    
+
                /* redirect_jump needs a valid JUMP_LABEL, and it might delete
                   the label if the LABEL_NUSES count drops to zero.  There is
                   always a jump_optimize pass that sets these values, but it
@@ -4529,7 +4581,7 @@ split_branches (rtx first)
                beyond
                  = next_active_insn (XEXP (XEXP (SET_SRC (PATTERN (insn)), 1),
                                            0));
-       
+
                if (beyond
                    && (GET_CODE (beyond) == JUMP_INSN
                        || ((beyond = next_active_insn (beyond))
@@ -4543,11 +4595,12 @@ split_branches (rtx first)
                  gen_block_redirect (beyond,
                                      INSN_ADDRESSES (INSN_UID (beyond)), 1);
              }
-    
+
            next = next_active_insn (insn);
 
            if ((GET_CODE (next) == JUMP_INSN
-                || GET_CODE (next = next_active_insn (next)) == JUMP_INSN)
+                || ((next = next_active_insn (next))
+                    && GET_CODE (next) == JUMP_INSN))
                && GET_CODE (PATTERN (next)) == SET
                && recog_memoized (next) == CODE_FOR_jump_compact
                && ((INSN_ADDRESSES
@@ -4739,8 +4792,12 @@ output_stack_adjust (int size, rtx reg, int epilogue_p,
     {
       HOST_WIDE_INT align = STACK_BOUNDARY / BITS_PER_UNIT;
 
+/* This test is bogus, as output_stack_adjust is used to re-align the
+   stack.  */
+#if 0
       if (size % align)
        abort ();
+#endif
 
       if (CONST_OK_FOR_ADD (size))
        emit_fn (GEN_ADD3 (reg, reg, GEN_INT (size)));
@@ -4765,7 +4822,7 @@ output_stack_adjust (int size, rtx reg, int epilogue_p,
             to handle this case, so just abort when we see it.  */
          if (epilogue_p < 0
              || current_function_interrupt
-             || ! call_used_regs[temp] || fixed_regs[temp])
+             || ! call_really_used_regs[temp] || fixed_regs[temp])
            temp = -1;
          if (temp < 0 && ! current_function_interrupt
              && (TARGET_SHMEDIA || epilogue_p >= 0))
@@ -4901,7 +4958,7 @@ push (int rn)
     x = gen_push_fpul ();
   else if (rn == FPSCR_REG)
     x = gen_push_fpscr ();
-  else if (TARGET_SH4 && TARGET_FMOVD && ! TARGET_FPU_SINGLE
+  else if ((TARGET_SH4 || TARGET_SH2A_DOUBLE) && TARGET_FMOVD && ! TARGET_FPU_SINGLE
           && FP_OR_XD_REGISTER_P (rn))
     {
       if (FP_REGISTER_P (rn) && (rn - FIRST_FP_REG) & 1)
@@ -4930,7 +4987,7 @@ pop (int rn)
     x = gen_pop_fpul ();
   else if (rn == FPSCR_REG)
     x = gen_pop_fpscr ();
-  else if (TARGET_SH4 && TARGET_FMOVD && ! TARGET_FPU_SINGLE
+  else if ((TARGET_SH4 || TARGET_SH2A_DOUBLE) && TARGET_FMOVD && ! TARGET_FPU_SINGLE
           && FP_OR_XD_REGISTER_P (rn))
     {
       if (FP_REGISTER_P (rn) && (rn - FIRST_FP_REG) & 1)
@@ -4941,7 +4998,7 @@ pop (int rn)
     x = gen_pop_e (gen_rtx_REG (SFmode, rn));
   else
     x = gen_pop (gen_rtx_REG (SImode, rn));
-    
+
   x = emit_insn (x);
   REG_NOTES (x)
     = gen_rtx_EXPR_LIST (REG_INC,
@@ -4995,14 +5052,14 @@ shmedia_target_regs_stack_space (HARD_REG_SET *live_regs_mask)
   int interrupt_handler = sh_cfun_interrupt_handler_p ();
 
   for (reg = LAST_TARGET_REG; reg >= FIRST_TARGET_REG; reg--)
-    if ((! call_used_regs[reg] || interrupt_handler)
+    if ((! call_really_used_regs[reg] || interrupt_handler)
         && ! TEST_HARD_REG_BIT (*live_regs_mask, reg))
       /* Leave space to save this target register on the stack,
         in case target register allocation wants to use it.  */
       stack_space += GET_MODE_SIZE (REGISTER_NATURAL_MODE (reg));
   return stack_space;
 }
-   
+
 /* Decide whether we should reserve space for callee-save target registers,
    in case target register allocation wants to use them.  REGS_SAVED is
    the space, in bytes, that is already required for register saves.
@@ -5048,14 +5105,15 @@ calc_live_regs (HARD_REG_SET *live_regs_mask)
   interrupt_handler = sh_cfun_interrupt_handler_p ();
 
   CLEAR_HARD_REG_SET (*live_regs_mask);
-  if (TARGET_SH4 && TARGET_FMOVD && interrupt_handler
+  if ((TARGET_SH4 || TARGET_SH2A_DOUBLE) && TARGET_FMOVD && interrupt_handler
       && regs_ever_live[FPSCR_REG])
     target_flags &= ~FPU_SINGLE_BIT;
   /* If we can save a lot of saves by switching to double mode, do that.  */
-  else if (TARGET_SH4 && TARGET_FMOVD && TARGET_FPU_SINGLE)
+  else if ((TARGET_SH4 || TARGET_SH2A_DOUBLE) && TARGET_FMOVD && TARGET_FPU_SINGLE)
     for (count = 0, reg = FIRST_FP_REG; reg <= LAST_FP_REG; reg += 2)
       if (regs_ever_live[reg] && regs_ever_live[reg+1]
-         && (! call_used_regs[reg] || (interrupt_handler && ! pragma_trapa))
+         && (! call_really_used_regs[reg]
+             || (interrupt_handler && ! pragma_trapa))
          && ++count > 2)
        {
          target_flags &= ~FPU_SINGLE_BIT;
@@ -5096,8 +5154,9 @@ calc_live_regs (HARD_REG_SET *live_regs_mask)
          : (interrupt_handler && ! pragma_trapa)
          ? (/* Need to save all the regs ever live.  */
             (regs_ever_live[reg]
-             || (call_used_regs[reg]
-                 && (! fixed_regs[reg] || reg == MACH_REG || reg == MACL_REG)
+             || (call_really_used_regs[reg]
+                 && (! fixed_regs[reg] || reg == MACH_REG || reg == MACL_REG
+                     || reg == PIC_OFFSET_TABLE_REGNUM)
                  && has_call)
              || (has_call && REGISTER_NATURAL_MODE (reg) == SImode
                  && (GENERAL_REGISTER_P (reg) || TARGET_REGISTER_P (reg))))
@@ -5111,7 +5170,7 @@ calc_live_regs (HARD_REG_SET *live_regs_mask)
              && flag_pic
              && current_function_args_info.call_cookie
              && reg == (int) PIC_OFFSET_TABLE_REGNUM)
-            || (regs_ever_live[reg] && ! call_used_regs[reg])
+            || (regs_ever_live[reg] && ! call_really_used_regs[reg])
             || (current_function_calls_eh_return
                 && (reg == (int) EH_RETURN_DATA_REGNO (0)
                     || reg == (int) EH_RETURN_DATA_REGNO (1)
@@ -5125,7 +5184,7 @@ calc_live_regs (HARD_REG_SET *live_regs_mask)
          SET_HARD_REG_BIT (*live_regs_mask, reg);
          count += GET_MODE_SIZE (REGISTER_NATURAL_MODE (reg));
 
-         if ((TARGET_SH4 || TARGET_SH5) && TARGET_FMOVD
+         if ((TARGET_SH4 || TARGET_SH2A_DOUBLE || TARGET_SH5) && TARGET_FMOVD
              && GET_MODE_CLASS (REGISTER_NATURAL_MODE (reg)) == MODE_FLOAT)
            {
              if (FP_REGISTER_P (reg))
@@ -5151,7 +5210,7 @@ calc_live_regs (HARD_REG_SET *live_regs_mask)
       && TARGET_SAVE_ALL_TARGET_REGS
       && shmedia_space_reserved_for_target_registers)
     for (reg = LAST_TARGET_REG; reg >= FIRST_TARGET_REG; reg--)
-      if ((! call_used_regs[reg] || interrupt_handler)
+      if ((! call_really_used_regs[reg] || interrupt_handler)
          && ! TEST_HARD_REG_BIT (*live_regs_mask, reg))
        {
          SET_HARD_REG_BIT (*live_regs_mask, reg);
@@ -5206,7 +5265,7 @@ sh_media_register_for_return (void)
   tr0_used = flag_pic && regs_ever_live[PIC_OFFSET_TABLE_REGNUM];
 
   for (regno = FIRST_TARGET_REG + tr0_used; regno <= LAST_TARGET_REG; regno++)
-    if (call_used_regs[regno] && ! regs_ever_live[regno])
+    if (call_really_used_regs[regno] && ! regs_ever_live[regno])
       return regno;
 
   return -1;
@@ -5242,7 +5301,7 @@ typedef struct save_schedule_s
    use reverse order.  Returns the last entry written to (not counting
    the delimiter).  OFFSET_BASE is a number to be added to all offset
    entries.  */
-   
+
 static save_entry *
 sh5_schedule_saves (HARD_REG_SET *live_regs_mask, save_schedule *schedule,
                    int offset_base)
@@ -5254,7 +5313,7 @@ sh5_schedule_saves (HARD_REG_SET *live_regs_mask, save_schedule *schedule,
 
   if (! current_function_interrupt)
     for (i = FIRST_GENERAL_REG; tmpx < MAX_TEMPS && i <= LAST_GENERAL_REG; i++)
-      if (call_used_regs[i] && ! fixed_regs[i] && i != PR_MEDIA_REG
+      if (call_really_used_regs[i] && ! fixed_regs[i] && i != PR_MEDIA_REG
          && ! FUNCTION_ARG_REGNO_P (i)
          && i != FIRST_RET_REG
          && ! (cfun->static_chain_decl != NULL && i == STATIC_CHAIN_REGNUM)
@@ -5422,7 +5481,7 @@ sh_expand_prologue (void)
              int rn = NPARM_REGS(SImode) + FIRST_PARM_REG - i - 1;
              rtx insn;
 
-             if (i >= (NPARM_REGS(SImode) 
+             if (i >= (NPARM_REGS(SImode)
                        - current_function_args_info.arg_count[(int) SH_ARG_INT]
                        ))
                break;
@@ -5441,7 +5500,7 @@ sh_expand_prologue (void)
      that already happens to be at the function start into the prologue.  */
   if (target_flags != save_flags && ! current_function_interrupt)
     emit_insn (gen_toggle_sz ());
-    
+
   if (TARGET_SH5)
     {
       int offset_base, offset;
@@ -5454,7 +5513,7 @@ sh_expand_prologue (void)
       save_entry *entry;
       int *tmp_pnt;
 
-      if (call_used_regs[R0_REG] && ! fixed_regs[R0_REG]
+      if (call_really_used_regs[R0_REG] && ! fixed_regs[R0_REG]
          && ! current_function_interrupt)
        r0 = gen_rtx_REG (Pmode, R0_REG);
 
@@ -5549,7 +5608,7 @@ sh_expand_prologue (void)
                               GEN_INT (offset - offset_in_r0)));
              offset_in_r0 += offset - offset_in_r0;
            }
-                                             
+
          if (pre_dec != NULL_RTX)
            {
              if (! sp_in_r0)
@@ -5611,7 +5670,7 @@ sh_expand_prologue (void)
            insn = emit_move_insn (mem_rtx, reg_rtx);
            RTX_FRAME_RELATED_P (insn) = 1;
 
-           if (TARGET_SHCOMPACT && (offset_in_r0 != -1)) 
+           if (TARGET_SHCOMPACT && (offset_in_r0 != -1))
              {
                rtx reg_rtx = gen_rtx_REG (mode, reg);
                rtx set, note_rtx;
@@ -5824,12 +5883,12 @@ sh_expand_epilogue (bool sibcall_p)
                post_inc = NULL_RTX;
 
                break;
-               
+
              post_inc_ok:
                mem_rtx = NULL_RTX;
              }
          while (0);
-         
+
          if (mem_rtx != NULL_RTX)
            goto addr_ok;
 
@@ -5846,7 +5905,7 @@ sh_expand_epilogue (bool sibcall_p)
                               GEN_INT (offset - offset_in_r0)));
              offset_in_r0 += offset - offset_in_r0;
            }
-             
+
          if (post_inc != NULL_RTX)
            {
              if (! sp_in_r0)
@@ -5856,7 +5915,7 @@ sh_expand_epilogue (bool sibcall_p)
                                  (Pmode, r0, stack_pointer_rtx));
                  sp_in_r0 = 1;
                }
-             
+
              mem_rtx = post_inc;
 
              offset_in_r0 += GET_MODE_SIZE (mode);
@@ -5911,7 +5970,7 @@ sh_expand_epilogue (bool sibcall_p)
       for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
        {
          int j = (FIRST_PSEUDO_REGISTER - 1) - i;
-  
+
          if (j == FPSCR_REG && current_function_interrupt && TARGET_FMOVD
              && hard_regs_intersect_p (&live_regs_mask,
                                        &reg_class_contents[DF_REGS]))
@@ -6008,7 +6067,7 @@ sh_set_return_address (rtx ra, rtx tmp)
       int offset;
       save_schedule schedule;
       save_entry *entry;
-      
+
       entry = sh5_schedule_saves (&live_regs_mask, &schedule, 0);
       offset = entry[1].offset;
       for (; entry->mode != VOIDmode; entry--)
@@ -6090,7 +6149,7 @@ sh_builtin_saveregs (void)
       if (TARGET_SHCOMPACT)
        return const0_rtx;
     }
-  
+
   if (! TARGET_SH2E && ! TARGET_SH4 && ! TARGET_SH5)
     {
       error ("__builtin_saveregs not supported by this subtarget");
@@ -6147,7 +6206,7 @@ sh_builtin_saveregs (void)
   emit_move_insn (fpregs, XEXP (regbuf, 0));
   emit_insn (gen_addsi3 (fpregs, fpregs,
                         GEN_INT (n_floatregs * UNITS_PER_WORD)));
-  if (TARGET_SH4)
+  if (TARGET_SH4 || TARGET_SH2A_DOUBLE)
     {
       rtx mem;
       for (regno = NPARM_REGS (DFmode) - 2; regno >= first_floatreg; regno -= 2)
@@ -6156,7 +6215,7 @@ sh_builtin_saveregs (void)
                                 GEN_INT (-2 * UNITS_PER_WORD)));
          mem = gen_rtx_MEM (DFmode, fpregs);
          set_mem_alias_set (mem, alias_set);
-         emit_move_insn (mem, 
+         emit_move_insn (mem,
                          gen_rtx_REG (DFmode, BASE_ARG_REG (DFmode) + regno));
        }
       regno = first_floatreg;
@@ -6283,7 +6342,7 @@ sh_va_start (tree valist, rtx nextarg)
   else
     nfp = 0;
   u = fold (build (PLUS_EXPR, ptr_type_node, u,
-                  build_int_2 (UNITS_PER_WORD * nfp, 0)));
+                  build_int_cst (NULL_TREE, UNITS_PER_WORD * nfp)));
   t = build (MODIFY_EXPR, ptr_type_node, next_fp_limit, u);
   TREE_SIDE_EFFECTS (t) = 1;
   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
@@ -6298,7 +6357,7 @@ sh_va_start (tree valist, rtx nextarg)
   else
     nint = 0;
   u = fold (build (PLUS_EXPR, ptr_type_node, u,
-                  build_int_2 (UNITS_PER_WORD * nint, 0)));
+                  build_int_cst (NULL_TREE, UNITS_PER_WORD * nint)));
   t = build (MODIFY_EXPR, ptr_type_node, next_o_limit, u);
   TREE_SIDE_EFFECTS (t) = 1;
   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
@@ -6318,7 +6377,7 @@ sh_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p,
   HOST_WIDE_INT size, rsize;
   tree tmp, pptr_type_node;
   tree addr, lab_over, result = NULL;
-  int pass_by_ref = targetm.calls.must_pass_in_stack (TYPE_MODE (type), type);
+  int pass_by_ref = pass_by_reference (NULL, TYPE_MODE (type), type, false);
 
   if (pass_by_ref)
     type = build_pointer_type (type);
@@ -6504,6 +6563,51 @@ sh_promote_prototypes (tree type)
   return ! sh_attr_renesas_p (type);
 }
 
+/* Whether an argument must be passed by reference.  On SHcompact, we
+   pretend arguments wider than 32-bits that would have been passed in
+   registers are passed by reference, so that an SHmedia trampoline
+   loads them into the full 64-bits registers.  */
+
+static int
+shcompact_byref (CUMULATIVE_ARGS *cum, enum machine_mode mode,
+                tree type, bool named)
+{
+  unsigned HOST_WIDE_INT size;
+
+  if (type)
+    size = int_size_in_bytes (type);
+  else
+    size = GET_MODE_SIZE (mode);
+
+  if (cum->arg_count[SH_ARG_INT] < NPARM_REGS (SImode)
+      && (!named
+         || GET_SH_ARG_CLASS (mode) == SH_ARG_INT
+         || (GET_SH_ARG_CLASS (mode) == SH_ARG_FLOAT
+             && cum->arg_count[SH_ARG_FLOAT] >= NPARM_REGS (SFmode)))
+      && size > 4
+      && !SHCOMPACT_FORCE_ON_STACK (mode, type)
+      && !SH5_WOULD_BE_PARTIAL_NREGS (*cum, mode, type, named))
+    return size;
+  else
+    return 0;
+}
+
+static bool
+sh_pass_by_reference (CUMULATIVE_ARGS *cum, enum machine_mode mode,
+                     tree type, bool named)
+{
+  if (targetm.calls.must_pass_in_stack (mode, type))
+    return true;
+
+  if (TARGET_SHCOMPACT)
+    {
+      cum->byref = shcompact_byref (cum, mode, type, named);
+      return cum->byref != 0;
+    }
+
+  return false;
+}
+
 /* Define where to put the arguments to a function.
    Value is zero to push the argument on the stack,
    or a hard register in which to store the argument.
@@ -6567,7 +6671,7 @@ sh_function_arg (CUMULATIVE_ARGS *ca, enum machine_mode mode,
       return gen_rtx_REG (mode, regno);
 
     }
-  
+
   if (TARGET_SH5)
     {
       if (mode == VOIDmode && TARGET_SHCOMPACT)
@@ -6605,7 +6709,7 @@ sh_function_arg (CUMULATIVE_ARGS *ca, enum machine_mode mode,
 
   return 0;
 }
+
 /* Update the data in CUM to advance over an argument
    of mode MODE and data type TYPE.
    (TYPE is null for libcalls where that information may not be
@@ -6746,7 +6850,7 @@ sh_function_arg_advance (CUMULATIVE_ARGS *ca, enum machine_mode mode,
        }
     }
 
-  if (! (TARGET_SH4 || ca->renesas_abi)
+  if (! ((TARGET_SH4 || TARGET_SH2A) || ca->renesas_abi)
       || PASS_IN_REG_P (*ca, mode, type))
     (ca->arg_count[(int) GET_SH_ARG_CLASS (mode)]
      = (ROUND_REG (*ca, mode)
@@ -6882,7 +6986,7 @@ initial_elimination_offset (int from, int to)
          int pr_reg = TARGET_SHMEDIA ? PR_MEDIA_REG : PR_REG;
          save_schedule schedule;
          save_entry *entry;
-         
+
          n += total_auto_space;
 
          /* If it wasn't saved, there's not much we can do.  */
@@ -6973,7 +7077,7 @@ const struct attribute_spec sh_attribute_table[] =
   /* 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.  */
@@ -7136,7 +7240,7 @@ sh_pch_valid_p (const void *data_p, size_t len)
   int flag_mask
     = (SH1_BIT | SH2_BIT | SH3_BIT | SH_E_BIT | HARD_SH4_BIT | FPU_SINGLE_BIT
        | SH4_BIT | HITACHI_BIT | LITTLE_ENDIAN_BIT);
-  
+
   /* -fpic and -fpie also usually make a PCH invalid.  */
   if (data[0] != flag_pic)
     return _("created and used with different settings of -fpic");
@@ -7166,7 +7270,7 @@ sh_pch_valid_p (const void *data_p, size_t len)
     }
   data += sizeof (target_flags);
   len -= sizeof (target_flags);
-  
+
   /* Check string options.  */
 #ifdef TARGET_OPTIONS
   for (i = 0; i < ARRAY_SIZE (target_options); i++)
@@ -7187,7 +7291,7 @@ sh_pch_valid_p (const void *data_p, size_t len)
 #endif
 
   return NULL;
-  
+
  make_message:
   {
     char *r;
@@ -7473,7 +7577,10 @@ tertiary_reload_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
 int
 fpscr_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
 {
-  return (GET_CODE (op) == REG && REGNO (op) == FPSCR_REG
+  return (GET_CODE (op) == REG
+         && (REGNO (op) == FPSCR_REG
+             || (REGNO (op) >= FIRST_PSEUDO_REGISTER
+                 && !(reload_in_progress || reload_completed)))
          && GET_MODE (op) == PSImode);
 }
 
@@ -7799,7 +7906,7 @@ sh_const_vec (rtx v, enum machine_mode mode)
 }
 \f
 /* Return the destination address of a branch.  */
-   
+
 static int
 branch_dest (rtx branch)
 {
@@ -7901,7 +8008,7 @@ reg_unused_after (rtx reg, rtx insn)
       if (set == 0 && reg_overlap_mentioned_p (reg, PATTERN (insn)))
        return 0;
 
-      if (code == CALL_INSN && call_used_regs[REGNO (reg)])
+      if (code == CALL_INSN && call_really_used_regs[REGNO (reg)])
        return 1;
     }
   return 1;
@@ -7989,7 +8096,7 @@ f(double a)
    remove assignments that are dead due to a following assignment in the
    same basic block.  */
 
-static void 
+static void
 mark_use (rtx x, rtx *reg_set_block)
 {
   enum rtx_code code;
@@ -8072,7 +8179,7 @@ get_free_reg (HARD_REG_SET regs_live)
   abort ();
 }
 
-/* This function will set the fpscr from memory. 
+/* This function will set the fpscr from memory.
    MODE is the mode we are setting it to.  */
 void
 fpscr_set_from_mem (int mode, HARD_REG_SET regs_live)
@@ -8118,7 +8225,7 @@ sh_insn_length_adjustment (rtx insn)
     return 2;
 
   /* sh-dsp parallel processing insn take four bytes instead of two.  */
-     
+
   if (GET_CODE (insn) == INSN)
     {
       int sum = 0;
@@ -8314,7 +8421,7 @@ mark_constant_pool_use (rtx x)
 /* Return true if it's possible to redirect BRANCH1 to the destination
    of an unconditional jump BRANCH2.  We only want to do this if the
    resulting branch will have a short displacement.  */
-int 
+int
 sh_can_redirect_branch (rtx branch1, rtx branch2)
 {
   if (flag_expensive_optimizations && simplejump_p (branch2))
@@ -8322,21 +8429,21 @@ sh_can_redirect_branch (rtx branch1, rtx branch2)
       rtx dest = XEXP (SET_SRC (single_set (branch2)), 0);
       rtx insn;
       int distance;
-      
-      for (distance = 0, insn = NEXT_INSN (branch1); 
-          insn && distance < 256; 
+
+      for (distance = 0, insn = NEXT_INSN (branch1);
+          insn && distance < 256;
           insn = PREV_INSN (insn))
        {
-         if (insn == dest)    
+         if (insn == dest)
            return 1;
          else
            distance += get_attr_length (insn);
        }
-      for (distance = 0, insn = NEXT_INSN (branch1); 
-          insn && distance < 256; 
+      for (distance = 0, insn = NEXT_INSN (branch1);
+          insn && distance < 256;
           insn = NEXT_INSN (insn))
        {
-         if (insn == dest)    
+         if (insn == dest)
            return 1;
          else
            distance += get_attr_length (insn);
@@ -8502,19 +8609,6 @@ sh_pr_n_sets (void)
   return REG_N_SETS (TARGET_SHMEDIA ? PR_MEDIA_REG : PR_REG);
 }
 
-/* This Function returns nonzero if the DFA based scheduler interface
-   is to be used.  At present this is only supported properly for the SH4.
-   For the SH1 the current DFA model is just the converted form of the old
-   pipeline model description.  */
-static int
-sh_use_dfa_interface (void)
-{
-  if (TARGET_SH1)
-    return 1;
-  else
-    return 0;
-}
-
 /* This function returns "2" to indicate dual issue for the SH4
    processor.  To be used by the DFA pipeline description.  */
 static int
@@ -8615,7 +8709,7 @@ rank_for_reorder (const void *x, const void *y)
   if (SCHED_GROUP_P (tmp) != SCHED_GROUP_P (tmp2))
     return SCHED_GROUP_P (tmp2) ? 1 : -1;
 
-  /* If insns are equally good, sort by INSN_LUID (original insn order), This 
+  /* If insns are equally good, sort by INSN_LUID (original insn order), This
      minimizes instruction movement, thus minimizing sched's effect on
      register pressure.  */
   return INSN_LUID (tmp) - INSN_LUID (tmp2);
@@ -8770,7 +8864,7 @@ sh_reorder (FILE *dump ATTRIBUTE_UNUSED,
 }
 
 /* Skip cycles if the current register pressure is high.  */
-static int 
+static int
 sh_reorder2 (FILE *dump ATTRIBUTE_UNUSED,
             int sched_verbose ATTRIBUTE_UNUSED,
             rtx *ready ATTRIBUTE_UNUSED,
@@ -8780,7 +8874,7 @@ sh_reorder2 (FILE *dump ATTRIBUTE_UNUSED,
   if (reload_completed)
     return cached_can_issue_more;
 
-  if (high_pressure(SFmode) || high_pressure (SImode)) 
+  if (high_pressure(SFmode) || high_pressure (SImode))
     skip_cycles = 1;
 
   return cached_can_issue_more;
@@ -8788,11 +8882,11 @@ sh_reorder2 (FILE *dump ATTRIBUTE_UNUSED,
 
 /* Skip cycles without sorting the ready queue. This will move insn from
    Q->R. If this is the last cycle we are skipping; allow sorting of ready
-   queue by sh_reorder.  */ 
+   queue by sh_reorder.  */
 
-/* Generally, skipping these many cycles are sufficient for all insns to move 
-   from Q -> R.  */ 
-#define MAX_SKIPS 8 
+/* Generally, skipping these many cycles are sufficient for all insns to move
+   from Q -> R.  */
+#define MAX_SKIPS 8
 
 static int
 sh_dfa_new_cycle (FILE *sched_dump ATTRIBUTE_UNUSED,
@@ -8805,7 +8899,7 @@ sh_dfa_new_cycle (FILE *sched_dump ATTRIBUTE_UNUSED,
   if (reload_completed)
     return 0;
 
-  if (skip_cycles) 
+  if (skip_cycles)
     {
       if ((clock_var - last_clock_var) < MAX_SKIPS)
        {
@@ -8852,7 +8946,7 @@ sh_ms_bitfield_layout_p (tree record_type ATTRIBUTE_UNUSED)
   return (TARGET_SH5 || TARGET_HITACHI || sh_attr_renesas_p (record_type));
 }
 \f
-/* 
+/*
    On the SH1..SH4, the trampoline looks like
    2 0002 D202                 mov.l   l2,r2
    1 0000 D301                 mov.l   l1,r3
@@ -8946,7 +9040,7 @@ sh_initialize_trampoline (rtx tramp, rtx fnaddr, rtx cxt)
       emit_move_insn (gen_rtx_MEM (Pmode,
                                   plus_constant (tramp,
                                                  fixed_len
-                                                 + GET_MODE_SIZE (Pmode))), 
+                                                 + GET_MODE_SIZE (Pmode))),
                      cxt);
       emit_insn (gen_ic_invalidate_line (tramp));
       return;
@@ -9028,7 +9122,7 @@ sh_initialize_trampoline (rtx tramp, rtx fnaddr, rtx cxt)
 static bool
 sh_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
 {
-  return (decl 
+  return (decl
          && (! TARGET_SHCOMPACT
              || current_function_args_info.stack_regs == 0)
          && ! sh_cfun_interrupt_handler_p ());
@@ -9242,11 +9336,31 @@ sh_media_init_builtins (void)
          if (signature < SH_BLTIN_NUM_SHARED_SIGNATURES)
            shared[signature] = type;
        }
-      builtin_function (d->name, type, d - bdesc, BUILT_IN_MD,
-                       NULL, NULL_TREE);
+      lang_hooks.builtin_function (d->name, type, d - bdesc, BUILT_IN_MD,
+                                  NULL, NULL_TREE);
     }
 }
 
+/* Implements target hook vector_mode_supported_p.  */
+bool
+sh_vector_mode_supported_p (enum machine_mode mode)
+{
+  if (TARGET_FPU_ANY
+      && ((mode == V2SFmode)
+         || (mode == V4SFmode)
+         || (mode == V16SFmode)))
+    return true;
+
+  else if (TARGET_SHMEDIA
+          && ((mode == V8QImode)
+              || (mode == V2HImode)
+              || (mode == V4HImode)
+              || (mode == V2SImode)))
+    return true;
+
+  return false;
+}
+
 static void
 sh_init_builtins (void)
 {
@@ -9365,6 +9479,11 @@ bool
 sh_cannot_change_mode_class (enum machine_mode from, enum machine_mode to,
                             enum reg_class class)
 {
+  /* We want to enable the use of SUBREGs as a means to
+     VEC_SELECT a single element of a vector.  */
+  if (to == SFmode && VECTOR_MODE_P (from) && GET_MODE_INNER (from) == SFmode)
+    return (reg_classes_intersect_p (GENERAL_REGS, class));
+
   if (GET_MODE_SIZE (from) != GET_MODE_SIZE (to))
     {
       if (TARGET_LITTLE_ENDIAN)
@@ -9442,7 +9561,7 @@ sh_register_move_cost (enum machine_mode mode,
 
   if ((dstclass == FPUL_REGS
        && (srcclass == PR_REGS || srcclass == MAC_REGS || srcclass == T_REGS))
-      || (srcclass == FPUL_REGS                
+      || (srcclass == FPUL_REGS
          && (dstclass == PR_REGS || dstclass == MAC_REGS)))
     return 7;
 
@@ -9517,7 +9636,7 @@ sh_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
 
   /* Find the "this" pointer.  We have such a wide range of ABIs for the
      SH that it's best to do this completely machine independently.
-     "this" is passed as first argument, unless a structure return pointer 
+     "this" is passed as first argument, unless a structure return pointer
      comes first, in which case "this" comes second.  */
   INIT_CUMULATIVE_ARGS (cum, funtype, NULL_RTX, 0, 1);
 #ifndef PCC_STATIC_STRUCT_RETURN
@@ -9525,7 +9644,7 @@ sh_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
     structure_value_byref = 1;
 #endif /* not PCC_STATIC_STRUCT_RETURN */
   if (structure_value_byref && sh_struct_value_rtx (function, 0) == 0)
-    { 
+    {
       tree ptype = build_pointer_type (TREE_TYPE (funtype));
 
       FUNCTION_ARG_ADVANCE (cum, Pmode, ptype, 1);
@@ -9631,6 +9750,9 @@ sh_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
 
   if (optimize > 0 && flag_schedule_insns_after_reload)
     {
+      if (! basic_block_info)
+       init_flow ();
+      rtl_register_cfg_hooks ();
       find_basic_blocks (insns, max_reg_num (), dump_file);
       life_analysis (dump_file, PROP_FINAL);
 
@@ -9778,7 +9900,7 @@ check_use_sfunc_addr (rtx insn, rtx reg)
        break;
       if (! INSN_P (insn))
        continue;
-       
+
       if (GET_CODE (PATTERN (insn)) == SEQUENCE)
        insn = XVECEXP (PATTERN (insn), 0, 0);
       if (GET_CODE (PATTERN (insn)) != PARALLEL
@@ -9789,4 +9911,87 @@ check_use_sfunc_addr (rtx insn, rtx reg)
   abort ();
 }
 
+/* Returns 1 if OP is a MEM that can be source of a simple move operation.  */
+
+int
+unaligned_load_operand (rtx op, enum machine_mode mode)
+{
+  rtx inside;
+
+  if (GET_CODE (op) != MEM || GET_MODE (op) != mode)
+    return 0;
+
+  inside = XEXP (op, 0);
+
+  if (GET_CODE (inside) == POST_INC)
+    inside = XEXP (inside, 0);
+
+  if (GET_CODE (inside) == REG)
+    return 1;
+
+  return 0;
+}
+
+/* This function returns a constant rtx that represents pi / 2**15 in
+   SFmode.  it's used to scale SFmode angles, in radians, to a
+   fixed-point signed 16.16-bit fraction of a full circle, i.e., 2*pi
+   maps to 0x10000).  */
+
+static GTY(()) rtx sh_fsca_sf2int_rtx;
+
+rtx
+sh_fsca_sf2int (void)
+{
+  if (! sh_fsca_sf2int_rtx)
+    {
+      REAL_VALUE_TYPE rv;
+
+      real_from_string (&rv, "10430.378350470453");
+      sh_fsca_sf2int_rtx = const_double_from_real_value (rv, SFmode);
+    }
+
+  return sh_fsca_sf2int_rtx;
+}
+
+/* This function returns a constant rtx that represents pi / 2**15 in
+   DFmode.  it's used to scale DFmode angles, in radians, to a
+   fixed-point signed 16.16-bit fraction of a full circle, i.e., 2*pi
+   maps to 0x10000).  */
+
+static GTY(()) rtx sh_fsca_df2int_rtx;
+
+rtx
+sh_fsca_df2int (void)
+{
+  if (! sh_fsca_df2int_rtx)
+    {
+      REAL_VALUE_TYPE rv;
+
+      real_from_string (&rv, "10430.378350470453");
+      sh_fsca_df2int_rtx = const_double_from_real_value (rv, DFmode);
+    }
+
+  return sh_fsca_df2int_rtx;
+}
+
+/* This function returns a constant rtx that represents 2**15 / pi in
+   SFmode.  it's used to scale a fixed-point signed 16.16-bit fraction
+   of a full circle back to a SFmode value, i.e., 0x10000 maps to
+   2*pi).  */
+
+static GTY(()) rtx sh_fsca_int2sf_rtx;
+
+rtx
+sh_fsca_int2sf (void)
+{
+  if (! sh_fsca_int2sf_rtx)
+    {
+      REAL_VALUE_TYPE rv;
+
+      real_from_string (&rv, "9.587379924285257e-5");
+      sh_fsca_int2sf_rtx = const_double_from_real_value (rv, SFmode);
+    }
+
+  return sh_fsca_int2sf_rtx;
+}
 #include "gt-sh.h"