OSDN Git Service

2005-12-02 Richard Guenther <rguenther@suse.de>
[pf3gnuchains/gcc-fork.git] / gcc / config / sh / sh.c
index 8e6333b..1cbdd99 100644 (file)
@@ -500,6 +500,9 @@ static int hard_regs_intersect_p (HARD_REG_SET *, HARD_REG_SET *);
 #define TARGET_ADJUST_UNROLL_MAX sh_adjust_unroll_max
 #endif
 
+#undef TARGET_SECONDARY_RELOAD
+#define TARGET_SECONDARY_RELOAD sh_secondary_reload
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
 /* Implement TARGET_HANDLE_OPTION.  */
@@ -1238,11 +1241,21 @@ prepare_move_operands (rtx operands[], enum machine_mode mode)
 
   if (mode == Pmode || mode == ptr_mode)
     {
-      rtx op0, op1;
+      rtx op0, op1, opc;
       enum tls_model tls_kind;
 
       op0 = operands[0];
       op1 = operands[1];
+      if (GET_CODE (op1) == CONST
+         && GET_CODE (XEXP (op1, 0)) == PLUS
+         && tls_symbolic_operand (XEXP (XEXP (op1, 0), 0), Pmode))
+       {
+         opc = XEXP (XEXP (op1, 0), 1);
+         op1 = XEXP (XEXP (op1, 0), 0);
+       }
+      else
+       opc = NULL_RTX;
+
       if ((tls_kind = tls_symbolic_operand (op1, Pmode)))
        {
          rtx tga_op1, tga_ret, tmp, tmp2;
@@ -1308,6 +1321,8 @@ prepare_move_operands (rtx operands[], enum machine_mode mode)
            default:
              gcc_unreachable ();
            }
+         if (opc)
+           emit_insn (gen_addsi3 (op1, op1, force_reg (SImode, opc)));
          operands[1] = op1;
        }
     }
@@ -3406,7 +3421,8 @@ fixup_mova (rtx mova)
          gcc_assert (worker
                      && GET_CODE (worker) != CODE_LABEL
                      && GET_CODE (worker) != JUMP_INSN);
-       } while (recog_memoized (worker) != CODE_FOR_casesi_worker_1);
+       } while (GET_CODE (worker) == NOTE
+                || recog_memoized (worker) != CODE_FOR_casesi_worker_1);
       wpat = PATTERN (worker);
       wpat0 = XVECEXP (wpat, 0, 0);
       wpat1 = XVECEXP (wpat, 0, 1);
@@ -6642,20 +6658,20 @@ sh_va_start (tree valist, rtx nextarg)
   f_next_fp_limit = TREE_CHAIN (f_next_fp);
   f_next_stack = TREE_CHAIN (f_next_fp_limit);
 
-  next_o = build (COMPONENT_REF, TREE_TYPE (f_next_o), valist, f_next_o,
-                 NULL_TREE);
-  next_o_limit = build (COMPONENT_REF, TREE_TYPE (f_next_o_limit),
-                       valist, f_next_o_limit, NULL_TREE);
-  next_fp = build (COMPONENT_REF, TREE_TYPE (f_next_fp), valist, f_next_fp,
+  next_o = build3 (COMPONENT_REF, TREE_TYPE (f_next_o), valist, f_next_o,
                   NULL_TREE);
-  next_fp_limit = build (COMPONENT_REF, TREE_TYPE (f_next_fp_limit),
-                        valist, f_next_fp_limit, NULL_TREE);
-  next_stack = build (COMPONENT_REF, TREE_TYPE (f_next_stack),
-                     valist, f_next_stack, NULL_TREE);
+  next_o_limit = build3 (COMPONENT_REF, TREE_TYPE (f_next_o_limit),
+                        valist, f_next_o_limit, NULL_TREE);
+  next_fp = build3 (COMPONENT_REF, TREE_TYPE (f_next_fp), valist, f_next_fp,
+                   NULL_TREE);
+  next_fp_limit = build3 (COMPONENT_REF, TREE_TYPE (f_next_fp_limit),
+                         valist, f_next_fp_limit, NULL_TREE);
+  next_stack = build3 (COMPONENT_REF, TREE_TYPE (f_next_stack),
+                      valist, f_next_stack, NULL_TREE);
 
   /* Call __builtin_saveregs.  */
   u = make_tree (ptr_type_node, expand_builtin_saveregs ());
-  t = build (MODIFY_EXPR, ptr_type_node, next_fp, u);
+  t = build2 (MODIFY_EXPR, ptr_type_node, next_fp, u);
   TREE_SIDE_EFFECTS (t) = 1;
   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
 
@@ -6664,13 +6680,13 @@ sh_va_start (tree valist, rtx nextarg)
     nfp = 8 - nfp;
   else
     nfp = 0;
-  u = fold (build (PLUS_EXPR, ptr_type_node, u,
-                  build_int_cst (NULL_TREE, UNITS_PER_WORD * nfp)));
-  t = build (MODIFY_EXPR, ptr_type_node, next_fp_limit, u);
+  u = fold_build2 (PLUS_EXPR, ptr_type_node, u,
+                  build_int_cst (NULL_TREE, UNITS_PER_WORD * nfp));
+  t = build2 (MODIFY_EXPR, ptr_type_node, next_fp_limit, u);
   TREE_SIDE_EFFECTS (t) = 1;
   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
 
-  t = build (MODIFY_EXPR, ptr_type_node, next_o, u);
+  t = build2 (MODIFY_EXPR, ptr_type_node, next_o, u);
   TREE_SIDE_EFFECTS (t) = 1;
   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
 
@@ -6679,14 +6695,14 @@ sh_va_start (tree valist, rtx nextarg)
     nint = 4 - nint;
   else
     nint = 0;
-  u = fold (build (PLUS_EXPR, ptr_type_node, u,
-                  build_int_cst (NULL_TREE, UNITS_PER_WORD * nint)));
-  t = build (MODIFY_EXPR, ptr_type_node, next_o_limit, u);
+  u = fold_build2 (PLUS_EXPR, ptr_type_node, u,
+                  build_int_cst (NULL_TREE, UNITS_PER_WORD * nint));
+  t = build2 (MODIFY_EXPR, ptr_type_node, next_o_limit, u);
   TREE_SIDE_EFFECTS (t) = 1;
   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
 
   u = make_tree (ptr_type_node, nextarg);
-  t = build (MODIFY_EXPR, ptr_type_node, next_stack, u);
+  t = build2 (MODIFY_EXPR, ptr_type_node, next_stack, u);
   TREE_SIDE_EFFECTS (t) = 1;
   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
 }
@@ -6745,16 +6761,16 @@ sh_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p,
       f_next_fp_limit = TREE_CHAIN (f_next_fp);
       f_next_stack = TREE_CHAIN (f_next_fp_limit);
 
-      next_o = build (COMPONENT_REF, TREE_TYPE (f_next_o), valist, f_next_o,
-                     NULL_TREE);
-      next_o_limit = build (COMPONENT_REF, TREE_TYPE (f_next_o_limit),
-                           valist, f_next_o_limit, NULL_TREE);
-      next_fp = build (COMPONENT_REF, TREE_TYPE (f_next_fp),
-                      valist, f_next_fp, NULL_TREE);
-      next_fp_limit = build (COMPONENT_REF, TREE_TYPE (f_next_fp_limit),
-                            valist, f_next_fp_limit, NULL_TREE);
-      next_stack = build (COMPONENT_REF, TREE_TYPE (f_next_stack),
-                         valist, f_next_stack, NULL_TREE);
+      next_o = build3 (COMPONENT_REF, TREE_TYPE (f_next_o), valist, f_next_o,
+                      NULL_TREE);
+      next_o_limit = build3 (COMPONENT_REF, TREE_TYPE (f_next_o_limit),
+                            valist, f_next_o_limit, NULL_TREE);
+      next_fp = build3 (COMPONENT_REF, TREE_TYPE (f_next_fp),
+                       valist, f_next_fp, NULL_TREE);
+      next_fp_limit = build3 (COMPONENT_REF, TREE_TYPE (f_next_fp_limit),
+                             valist, f_next_fp_limit, NULL_TREE);
+      next_stack = build3 (COMPONENT_REF, TREE_TYPE (f_next_stack),
+                          valist, f_next_stack, NULL_TREE);
 
       /* Structures with a single member with a distinct mode are passed
         like their member.  This is relevant if the latter has a REAL_TYPE
@@ -6813,19 +6829,19 @@ sh_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p,
          if (size > 4 && !is_double)
            tmp = build2 (PLUS_EXPR, TREE_TYPE (tmp), tmp,
                          fold_convert (TREE_TYPE (tmp), size_int (4 - size)));
-         tmp = build (GE_EXPR, boolean_type_node, next_fp_tmp, tmp);
-         cmp = build (COND_EXPR, void_type_node, tmp,
-                      build (GOTO_EXPR, void_type_node, lab_false),
-                      NULL);
+         tmp = build2 (GE_EXPR, boolean_type_node, next_fp_tmp, tmp);
+         cmp = build3 (COND_EXPR, void_type_node, tmp,
+                       build1 (GOTO_EXPR, void_type_node, lab_false),
+                       NULL_TREE);
          if (!is_double)
            gimplify_and_add (cmp, pre_p);
 
          if (TYPE_ALIGN (type) > BITS_PER_WORD || (is_double || size == 16))
            {
              tmp = fold_convert (ptr_type_node, size_int (UNITS_PER_WORD));
-             tmp = build (BIT_AND_EXPR, ptr_type_node, next_fp_tmp, tmp);
-             tmp = build (PLUS_EXPR, ptr_type_node, next_fp_tmp, tmp);
-             tmp = build (MODIFY_EXPR, ptr_type_node, next_fp_tmp, tmp);
+             tmp = build2 (BIT_AND_EXPR, ptr_type_node, next_fp_tmp, tmp);
+             tmp = build2 (PLUS_EXPR, ptr_type_node, next_fp_tmp, tmp);
+             tmp = build2 (MODIFY_EXPR, ptr_type_node, next_fp_tmp, tmp);
              gimplify_and_add (tmp, pre_p);
            }
          if (is_double)
@@ -6845,19 +6861,19 @@ sh_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p,
                = std_gimplify_va_arg_expr (next_fp_tmp, subtype, pre_p, NULL);
              real = get_initialized_tmp_var (real, pre_p, NULL);
 
-             result = build (COMPLEX_EXPR, type, real, imag);
+             result = build2 (COMPLEX_EXPR, type, real, imag);
              result = get_initialized_tmp_var (result, pre_p, NULL);
            }
 #endif /* FUNCTION_ARG_SCmode_WART */
 
-         tmp = build (GOTO_EXPR, void_type_node, lab_over);
+         tmp = build1 (GOTO_EXPR, void_type_node, lab_over);
          gimplify_and_add (tmp, pre_p);
 
-         tmp = build (LABEL_EXPR, void_type_node, lab_false);
+         tmp = build1 (LABEL_EXPR, void_type_node, lab_false);
          gimplify_and_add (tmp, pre_p);
 
          tmp = build1 (ADDR_EXPR, pptr_type_node, next_stack);
-         tmp = build (MODIFY_EXPR, void_type_node, addr, tmp);
+         tmp = build2 (MODIFY_EXPR, void_type_node, addr, tmp);
          gimplify_and_add (tmp, pre_p);
          tmp = build2 (MODIFY_EXPR, ptr_type_node, next_fp_tmp, valist);
          gimplify_and_add (tmp, pre_p);
@@ -6869,37 +6885,37 @@ sh_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p,
       else
        {
          tmp = fold_convert (ptr_type_node, size_int (rsize));
-         tmp = build (PLUS_EXPR, ptr_type_node, next_o, tmp);
-         tmp = build (GT_EXPR, boolean_type_node, tmp, next_o_limit);
-         tmp = build (COND_EXPR, void_type_node, tmp,
-                      build (GOTO_EXPR, void_type_node, lab_false),
-                      NULL);
+         tmp = build2 (PLUS_EXPR, ptr_type_node, next_o, tmp);
+         tmp = build2 (GT_EXPR, boolean_type_node, tmp, next_o_limit);
+         tmp = build3 (COND_EXPR, void_type_node, tmp,
+                       build1 (GOTO_EXPR, void_type_node, lab_false),
+                       NULL_TREE);
          gimplify_and_add (tmp, pre_p);
 
          tmp = build1 (ADDR_EXPR, pptr_type_node, next_o);
-         tmp = build (MODIFY_EXPR, void_type_node, addr, tmp);
+         tmp = build2 (MODIFY_EXPR, void_type_node, addr, tmp);
          gimplify_and_add (tmp, pre_p);
 
-         tmp = build (GOTO_EXPR, void_type_node, lab_over);
+         tmp = build1 (GOTO_EXPR, void_type_node, lab_over);
          gimplify_and_add (tmp, pre_p);
 
-         tmp = build (LABEL_EXPR, void_type_node, lab_false);
+         tmp = build1 (LABEL_EXPR, void_type_node, lab_false);
          gimplify_and_add (tmp, pre_p);
 
          if (size > 4 && ! TARGET_SH4)
            {
-             tmp = build (MODIFY_EXPR, ptr_type_node, next_o, next_o_limit);
+             tmp = build2 (MODIFY_EXPR, ptr_type_node, next_o, next_o_limit);
              gimplify_and_add (tmp, pre_p);
            }
 
          tmp = build1 (ADDR_EXPR, pptr_type_node, next_stack);
-         tmp = build (MODIFY_EXPR, void_type_node, addr, tmp);
+         tmp = build2 (MODIFY_EXPR, void_type_node, addr, tmp);
          gimplify_and_add (tmp, pre_p);
        }
 
       if (!result)
        {
-         tmp = build (LABEL_EXPR, void_type_node, lab_over);
+         tmp = build1 (LABEL_EXPR, void_type_node, lab_over);
          gimplify_and_add (tmp, pre_p);
        }
     }
@@ -6910,10 +6926,10 @@ sh_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p,
   tmp = std_gimplify_va_arg_expr (valist, type, pre_p, NULL);
   if (result)
     {
-      tmp = build (MODIFY_EXPR, void_type_node, result, tmp);
+      tmp = build2 (MODIFY_EXPR, void_type_node, result, tmp);
       gimplify_and_add (tmp, pre_p);
 
-      tmp = build (LABEL_EXPR, void_type_node, lab_over);
+      tmp = build1 (LABEL_EXPR, void_type_node, lab_over);
       gimplify_and_add (tmp, pre_p);
     }
   else
@@ -7854,6 +7870,45 @@ get_fpscr_rtx (void)
   return fpscr_rtx;
 }
 
+static GTY(()) tree fpscr_values;
+
+static void
+emit_fpu_switch (rtx scratch, int index)
+{
+  rtx dst, src;
+
+  if (fpscr_values == NULL)
+    {
+      tree t;
+
+      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);
+      DECL_ARTIFICIAL (t) = 1;
+      DECL_IGNORED_P (t) = 1;
+      DECL_EXTERNAL (t) = 1;
+      TREE_STATIC (t) = 1;
+      TREE_PUBLIC (t) = 1;
+      TREE_USED (t) = 1;
+
+      fpscr_values = t;
+    }
+
+  src = DECL_RTL (fpscr_values);
+  if (no_new_pseudos)
+    {
+      emit_move_insn (scratch, XEXP (src, 0));
+      if (index != 0)
+       emit_insn (gen_addsi3 (scratch, scratch, GEN_INT (index * 4)));
+      src = adjust_automodify_address (src, PSImode, scratch, index * 4);
+    }
+  else
+    src = adjust_address (src, PSImode, index * 4);
+
+  dst = get_fpscr_rtx ();
+  emit_move_insn (dst, src);
+}
+
 void
 emit_sf_insn (rtx pat)
 {
@@ -8006,12 +8061,10 @@ void
 fpscr_set_from_mem (int mode, HARD_REG_SET regs_live)
 {
   enum attr_fp_mode fp_mode = mode;
+  enum attr_fp_mode norm_mode = ACTUAL_NORMAL_MODE (FP_MODE);
   rtx addr_reg = get_free_reg (regs_live);
 
-  if (fp_mode == (enum attr_fp_mode) ACTUAL_NORMAL_MODE (FP_MODE))
-    emit_insn (gen_fpu_switch1 (addr_reg));
-  else
-    emit_insn (gen_fpu_switch0 (addr_reg));
+  emit_fpu_switch (addr_reg, fp_mode == norm_mode);
 }
 
 /* Is the given character a logical line separator for the assembler?  */
@@ -9491,6 +9544,9 @@ sh_register_move_cost (enum machine_mode mode,
       && REGCLASS_HAS_FP_REG (dstclass))
     return 4;
 
+  if (REGCLASS_HAS_FP_REG (dstclass) && srcclass == T_REGS)
+    return ((TARGET_HARD_SH4 && !optimize_size) ? 10 : 7);
+
   if ((REGCLASS_HAS_FP_REG (dstclass) && srcclass == MAC_REGS)
       || (dstclass == MAC_REGS && REGCLASS_HAS_FP_REG (srcclass)))
     return 9;
@@ -10223,10 +10279,10 @@ sh_adjust_unroll_max (struct loop * loop, int insn_count,
                          if (TREE_CODE (type) != ARRAY_TYPE
                              || ! TYPE_SIZE (type) || ! TYPE_SIZE_UNIT (type))
                            break;
-                         size_tree = fold (build (TRUNC_DIV_EXPR,
+                         size_tree = fold_build2 (TRUNC_DIV_EXPR,
                                                   bitsizetype,
                                                   TYPE_SIZE (type),
-                                                  TYPE_SIZE_UNIT (type)));
+                                                  TYPE_SIZE_UNIT (type));
                          if (TREE_CODE (size_tree) == INTEGER_CST
                              && ! TREE_INT_CST_HIGH (size_tree)
                              && TREE_INT_CST_LOW  (size_tree) < max_iterations)
@@ -10619,6 +10675,106 @@ shmedia_prepare_call_address (rtx fnaddr, int is_sibcall)
   return fnaddr;
 }
 
+enum reg_class
+sh_secondary_reload (bool in_p, rtx x, enum reg_class class,
+                    enum machine_mode mode, secondary_reload_info *sri)
+{
+  if (in_p)
+    {
+      if (REGCLASS_HAS_FP_REG (class)
+         && ! TARGET_SHMEDIA
+         && immediate_operand ((x), mode)
+         && ! ((fp_zero_operand (x) || fp_one_operand (x))
+               && mode == SFmode && fldi_ok ()))
+       switch (mode)
+         {
+         case SFmode:
+           sri->icode = CODE_FOR_reload_insf__frn;
+           return NO_REGS;
+         case DFmode:
+           sri->icode = CODE_FOR_reload_indf__frn;
+           return NO_REGS;
+         case SImode:
+           /* ??? If we knew that we are in the appropriate mode -
+              single precision - we could use a reload pattern directly.  */
+           return FPUL_REGS;
+         default:
+           abort ();
+         }
+      if (class == FPUL_REGS
+          && ((GET_CODE (x) == REG
+               && (REGNO (x) == MACL_REG || REGNO (x) == MACH_REG
+                   || REGNO (x) == T_REG))
+              || GET_CODE (x) == PLUS))
+        return GENERAL_REGS;
+      if (class == FPUL_REGS && immediate_operand (x, mode))
+       {
+         if (GET_CODE (x) == CONST_INT && CONST_OK_FOR_I08 (INTVAL (x)))
+           return GENERAL_REGS;
+         sri->icode = CODE_FOR_reload_insi__i_fpul;
+         return NO_REGS;
+       }
+      if (class == FPSCR_REGS
+          && ((GET_CODE (x) == REG && REGNO (x) >= FIRST_PSEUDO_REGISTER)
+              || (GET_CODE (x) == MEM && GET_CODE (XEXP (x, 0)) == PLUS)))
+        return GENERAL_REGS;
+      if (REGCLASS_HAS_FP_REG (class)
+          && TARGET_SHMEDIA
+          && immediate_operand (x, mode)
+          && x != CONST0_RTX (GET_MODE (x))
+          && GET_MODE (x) != V4SFmode)
+        return GENERAL_REGS;
+      if ((mode == QImode || mode == HImode)
+          && TARGET_SHMEDIA && inqhi_operand (x, mode))
+       {
+         sri->icode = ((mode == QImode)
+                       ? CODE_FOR_reload_inqi : CODE_FOR_reload_inhi);
+         return NO_REGS;
+       }
+      if (TARGET_SHMEDIA && class == GENERAL_REGS
+          && (GET_CODE (x) == LABEL_REF || PIC_DIRECT_ADDR_P (x)))
+        return TARGET_REGS;
+    } /* end of input-only processing.  */
+
+  if (((REGCLASS_HAS_FP_REG (class)
+       && (GET_CODE (x) == REG
+           && (GENERAL_OR_AP_REGISTER_P (REGNO (x))
+               || (FP_REGISTER_P (REGNO (x)) && mode == SImode
+                   && TARGET_FMOVD))))
+       || (REGCLASS_HAS_GENERAL_REG (class)
+          && GET_CODE (x) == REG
+          && FP_REGISTER_P (REGNO (x))))
+      && ! TARGET_SHMEDIA
+      && (mode == SFmode || mode == SImode))
+    return FPUL_REGS;
+  if ((class == FPUL_REGS
+       || (REGCLASS_HAS_FP_REG (class)
+           && ! TARGET_SHMEDIA && mode == SImode))
+      && (GET_CODE (x) == MEM
+          || (GET_CODE (x) == REG
+              && (REGNO (x) >= FIRST_PSEUDO_REGISTER
+                  || REGNO (x) == T_REG
+                  || system_reg_operand (x, VOIDmode)))))
+    {
+      if (class == FPUL_REGS)
+       return GENERAL_REGS;
+      return FPUL_REGS;
+    }
+  if ((class == TARGET_REGS
+       || (TARGET_SHMEDIA && class == SIBCALL_REGS))
+      && !EXTRA_CONSTRAINT_Csy (x)
+      && (GET_CODE (x) != REG || ! GENERAL_REGISTER_P (REGNO (x))))
+    return GENERAL_REGS;
+  if ((class == MAC_REGS || class == PR_REGS)
+      && GET_CODE (x) == REG && ! GENERAL_REGISTER_P (REGNO (x))
+      && class != REGNO_REG_CLASS (REGNO (x)))
+    return GENERAL_REGS;
+  if (class != GENERAL_REGS && GET_CODE (x) == REG
+      && TARGET_REGISTER_P (REGNO (x)))
+    return GENERAL_REGS;
+  return NO_REGS;
+}
+
 enum sh_divide_strategy_e sh_div_strategy = SH_DIV_STRATEGY_DEFAULT;
 
 /* This defines the storage for the variable part of a -mboard= option.