OSDN Git Service

2005-12-02 Richard Guenther <rguenther@suse.de>
[pf3gnuchains/gcc-fork.git] / gcc / config / c4x / c4x.c
index e3ab61b..3757523 100644 (file)
@@ -1,5 +1,6 @@
 /* Subroutines for assembler code output on the TMS320C[34]x
-   Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004
+   Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2003,
+   2004, 2005
    Free Software Foundation, Inc.
 
    Contributed by Michael Hayes (m.hayes@elec.canterbury.ac.nz)
@@ -19,8 +20,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GCC; see the file COPYING.  If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
 
 /* Some output-actions in c4x.md need these.  */
 #include "config.h"
@@ -42,7 +43,6 @@ Boston, MA 02111-1307, USA.  */
 #include "optabs.h"
 #include "libfuncs.h"
 #include "flags.h"
-#include "loop.h"
 #include "recog.h"
 #include "ggc.h"
 #include "cpplib.h"
@@ -153,9 +153,6 @@ enum machine_mode c4x_caller_save_map[FIRST_PSEUDO_REGISTER] =
 rtx c4x_compare_op0;
 rtx c4x_compare_op1;
 
-const char *c4x_rpts_cycles_string;
-int c4x_rpts_cycles = 0;       /* Max. cycles for RPTS.  */
-const char *c4x_cpu_version_string;
 int c4x_cpu_version = 40;      /* CPU version C30/31/32/33/40/44.  */
 
 /* Pragma definitions.  */
@@ -168,19 +165,13 @@ tree interrupt_tree = NULL_TREE;
 tree naked_tree = NULL_TREE;
 
 /* Forward declarations */
+static bool c4x_handle_option (size_t, const char *, int);
 static int c4x_isr_reg_used_p (unsigned int);
 static int c4x_leaf_function_p (void);
 static int c4x_naked_function_p (void);
-static int c4x_immed_float_p (rtx);
-static int c4x_a_register (rtx);
-static int c4x_x_register (rtx);
 static int c4x_immed_int_constant (rtx);
 static int c4x_immed_float_constant (rtx);
-static int c4x_K_constant (rtx);
-static int c4x_N_constant (rtx);
-static int c4x_O_constant (rtx);
 static int c4x_R_indirect (rtx);
-static int c4x_S_indirect (rtx);
 static void c4x_S_address_parse (rtx , int *, int *, int *, int *);
 static int c4x_valid_operands (enum rtx_code, rtx *, enum machine_mode, int);
 static int c4x_arn_reg_operand (rtx, enum machine_mode, unsigned int);
@@ -195,7 +186,7 @@ static int c4x_label_ref_used_p (rtx, rtx);
 static tree c4x_handle_fntype_attribute (tree *, tree, tree, int, bool *);
 const struct attribute_spec c4x_attribute_table[];
 static void c4x_insert_attributes (tree, tree *);
-static void c4x_asm_named_section (const char *, unsigned int);
+static void c4x_asm_named_section (const char *, unsigned int, tree);
 static int c4x_adjust_cost (rtx, rtx, rtx, int);
 static void c4x_globalize_label (FILE *, const char *);
 static bool c4x_rtx_costs (rtx, int, int, int *);
@@ -222,6 +213,13 @@ static tree c4x_gimplify_va_arg_expr (tree, tree, tree *, tree *);
 #undef TARGET_ASM_EXTERNAL_LIBCALL
 #define TARGET_ASM_EXTERNAL_LIBCALL c4x_external_libcall
 
+/* Play safe, not the fastest code.  */
+#undef TARGET_DEFAULT_TARGET_FLAGS
+#define TARGET_DEFAULT_TARGET_FLAGS (MASK_ALIASES | MASK_PARALLEL \
+                                    | MASK_PARALLEL_MPY | MASK_RPTB)
+#undef TARGET_HANDLE_OPTION
+#define TARGET_HANDLE_OPTION c4x_handle_option
+
 #undef TARGET_ATTRIBUTE_TABLE
 #define TARGET_ATTRIBUTE_TABLE c4x_attribute_table
 
@@ -259,67 +257,45 @@ static tree c4x_gimplify_va_arg_expr (tree, tree, tree *, tree *);
 
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
-/* Override command line options.
-   Called once after all options have been parsed.
-   Mostly we process the processor
-   type and sometimes adjust other TARGET_ options.  */
+/* Implement TARGET_HANDLE_OPTION.  */
 
-void
-c4x_override_options (void)
+static bool
+c4x_handle_option (size_t code, const char *arg, int value)
 {
-  if (c4x_rpts_cycles_string)
-    c4x_rpts_cycles = atoi (c4x_rpts_cycles_string);
-  else
-    c4x_rpts_cycles = 0;
-
-  if (TARGET_C30)
-    c4x_cpu_version = 30;
-  else if (TARGET_C31)
-    c4x_cpu_version = 31;
-  else if (TARGET_C32)
-    c4x_cpu_version = 32;
-  else if (TARGET_C33)
-    c4x_cpu_version = 33;
-  else if (TARGET_C40)
-    c4x_cpu_version = 40;
-  else if (TARGET_C44)
-    c4x_cpu_version = 44;
-  else
-    c4x_cpu_version = 40;             
-
-  /* -mcpu=xx overrides -m40 etc.  */
-  if (c4x_cpu_version_string)
+  switch (code)
     {
-      const char *p = c4x_cpu_version_string;
-      
-      /* Also allow -mcpu=c30 etc.  */
-      if (*p == 'c' || *p == 'C')
-       p++;
-      c4x_cpu_version = atoi (p);
-    }
-
-  target_flags &= ~(C30_FLAG | C31_FLAG | C32_FLAG | C33_FLAG |
-                   C40_FLAG | C44_FLAG);
+    case OPT_m30: c4x_cpu_version = 30; return true;
+    case OPT_m31: c4x_cpu_version = 31; return true;
+    case OPT_m32: c4x_cpu_version = 32; return true;
+    case OPT_m33: c4x_cpu_version = 33; return true;
+    case OPT_m40: c4x_cpu_version = 40; return true;
+    case OPT_m44: c4x_cpu_version = 44; return true;
+
+    case OPT_mcpu_:
+      if (arg[0] == 'c' || arg[0] == 'C')
+       arg++;
+      value = atoi (arg);
+      switch (value)
+       {
+       case 30: case 31: case 32: case 33: case 40: case 44:
+         c4x_cpu_version = value;
+         return true;
+       }
+      return false;
 
-  switch (c4x_cpu_version)
-    {
-    case 30: target_flags |= C30_FLAG; break;
-    case 31: target_flags |= C31_FLAG; break;
-    case 32: target_flags |= C32_FLAG; break;
-    case 33: target_flags |= C33_FLAG; break;
-    case 40: target_flags |= C40_FLAG; break;
-    case 44: target_flags |= C44_FLAG; break;
     default:
-      warning ("unknown CPU version %d, using 40.\n", c4x_cpu_version);
-      c4x_cpu_version = 40;
-      target_flags |= C40_FLAG;
+      return true;
     }
+}
 
-  if (TARGET_C30 || TARGET_C31 || TARGET_C32 || TARGET_C33)
-    target_flags |= C3X_FLAG;
-  else
-    target_flags &= ~C3X_FLAG;
+/* Override command line options.
+   Called once after all options have been parsed.
+   Mostly we process the processor
+   type and sometimes adjust other TARGET_ options.  */
 
+void
+c4x_override_options (void)
+{
   /* Convert foo / 8.0 into foo * 0.125, etc.  */
   set_fast_math_flags (1);
 
@@ -327,6 +303,15 @@ c4x_override_options (void)
      This provides compatibility with the old -mno-aliases option.  */
   if (! TARGET_ALIASES && ! flag_argument_noalias)
     flag_argument_noalias = 1;
+
+  if (!TARGET_C3X)
+    target_flags |= MASK_MPYI | MASK_DB;
+
+  if (optimize < 2)
+    target_flags &= ~(MASK_RPTB | MASK_PARALLEL);
+
+  if (!TARGET_PARALLEL)
+    target_flags &= ~MASK_PARALLEL_MPY;
 }
 
 
@@ -737,13 +722,13 @@ c4x_gimplify_va_arg_expr (tree valist, tree type,
   if (indirect)
     type = build_pointer_type (type);
 
-  t = build (PREDECREMENT_EXPR, TREE_TYPE (valist), valist,
-            build_int_cst (NULL_TREE, int_size_in_bytes (type), 0));
+  t = build2 (PREDECREMENT_EXPR, TREE_TYPE (valist), valist,
+             build_int_cst (NULL_TREE, int_size_in_bytes (type)));
   t = fold_convert (build_pointer_type (type), t);
-  t = build_fold_indirect_ref (t);
+  t = build_va_arg_indirect_ref (t);
 
   if (indirect)
-    t = build_fold_indirect_ref (t);
+    t = build_va_arg_indirect_ref (t);
 
   return t;
 }
@@ -2158,7 +2143,7 @@ c4x_print_operand_address (FILE *file, rtx addr)
 /* Return nonzero if the floating point operand will fit
    in the immediate field.  */
 
-static int
+int
 c4x_immed_float_p (rtx op)
 {
   long convval[2];
@@ -2468,14 +2453,14 @@ c4x_reorg (void)
 }
 
 
-static int
+int
 c4x_a_register (rtx op)
 {
   return REG_P (op) && IS_ADDR_OR_PSEUDO_REG (op);
 }
 
 
-static int
+int
 c4x_x_register (rtx op)
 {
   return REG_P (op) && IS_INDEX_OR_PSEUDO_REG (op);
@@ -2551,7 +2536,7 @@ c4x_J_constant (rtx op)
 }
 
 
-static int
+int
 c4x_K_constant (rtx op)
 {
   if (TARGET_C3X || ! c4x_immed_int_constant (op))
@@ -2567,14 +2552,14 @@ c4x_L_constant (rtx op)
 }
 
 
-static int
+int
 c4x_N_constant (rtx op)
 {
   return c4x_immed_int_constant (op) && IS_NOT_UINT16_CONST (INTVAL (op));
 }
 
 
-static int
+int
 c4x_O_constant (rtx op)
 {
   return c4x_immed_int_constant (op) && IS_HIGH_CONST (INTVAL (op));
@@ -2779,7 +2764,7 @@ c4x_S_constraint (rtx op)
 }
 
 
-static int
+int
 c4x_S_indirect (rtx op)
 {
   enum machine_mode mode = GET_MODE (op);
@@ -2915,88 +2900,6 @@ c4x_autoinc_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
 }
 
 
-/* Match any operand.  */
-
-int
-any_operand (register rtx op ATTRIBUTE_UNUSED,
-            enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  return 1;
-}
-
-
-/* Nonzero if OP is a floating point value with value 0.0.  */
-
-int
-fp_zero_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  REAL_VALUE_TYPE r;
-
-  if (GET_CODE (op) != CONST_DOUBLE)
-    return 0;
-  REAL_VALUE_FROM_CONST_DOUBLE (r, op);
-  return REAL_VALUES_EQUAL (r, dconst0);
-}
-
-
-int
-const_operand (register rtx op, register enum machine_mode mode)
-{
-  switch (mode)
-    {
-    case QFmode:
-    case HFmode:
-      if (GET_CODE (op) != CONST_DOUBLE
-         || GET_MODE (op) != mode
-         || GET_MODE_CLASS (mode) != MODE_FLOAT)
-       return 0;
-
-      return c4x_immed_float_p (op);
-
-#if Pmode != QImode
-    case Pmode:
-#endif
-    case QImode:
-      if (GET_CODE (op) != CONST_INT
-         || (GET_MODE (op) != VOIDmode && GET_MODE (op) != mode)
-         || GET_MODE_CLASS (mode) != MODE_INT)
-       return 0;
-
-      return IS_HIGH_CONST (INTVAL (op)) || IS_INT16_CONST (INTVAL (op));
-
-    case HImode:
-      return 0;
-
-    default:
-      return 0;
-    }
-}
-
-
-int
-stik_const_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  return c4x_K_constant (op);
-}
-
-
-int
-not_const_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  return c4x_N_constant (op);
-}
-
-
-int
-reg_operand (rtx op, enum machine_mode mode)
-{
-  if (GET_CODE (op) == SUBREG
-      && GET_MODE (op) == QFmode)
-    return 0;
-  return register_operand (op, mode);
-}
-
-
 int
 mixed_subreg_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
 {
@@ -3075,325 +2978,6 @@ not_rc_reg (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
 }
 
 
-/* Extended precision register R0-R1.  */
-
-int
-r0r1_reg_operand (rtx op, enum machine_mode mode)
-{
-  if (! reg_operand (op, mode))
-    return 0;
-  if (GET_CODE (op) == SUBREG)
-    op = SUBREG_REG (op);
-  return REG_P (op) && IS_R0R1_OR_PSEUDO_REG (op);
-}
-
-
-/* Extended precision register R2-R3.  */
-
-int
-r2r3_reg_operand (rtx op, enum machine_mode mode)
-{
-  if (! reg_operand (op, mode))
-    return 0;
-  if (GET_CODE (op) == SUBREG)
-    op = SUBREG_REG (op);
-  return REG_P (op) && IS_R2R3_OR_PSEUDO_REG (op);
-}
-
-
-/* Low extended precision register R0-R7.  */
-
-int
-ext_low_reg_operand (rtx op, enum machine_mode mode)
-{
-  if (! reg_operand (op, mode))
-    return 0;
-  if (GET_CODE (op) == SUBREG)
-    op = SUBREG_REG (op);
-  return REG_P (op) && IS_EXT_LOW_OR_PSEUDO_REG (op);
-}
-
-
-/* Extended precision register.  */
-
-int
-ext_reg_operand (rtx op, enum machine_mode mode)
-{
-  if (! reg_operand (op, mode))
-    return 0;
-  if (GET_CODE (op) == SUBREG)
-    op = SUBREG_REG (op);
-  if (! REG_P (op))
-    return 0;
-  return IS_EXT_OR_PSEUDO_REG (op);
-}
-
-
-/* Standard precision register.  */
-
-int
-std_reg_operand (rtx op, enum machine_mode mode)
-{
-  if (! reg_operand (op, mode))
-    return 0;
-  if (GET_CODE (op) == SUBREG)
-    op = SUBREG_REG (op);
-  return REG_P (op) && IS_STD_OR_PSEUDO_REG (op);
-}
-
-/* Standard precision or normal register.  */
-
-int
-std_or_reg_operand (rtx op, enum machine_mode mode)
-{
-  if (reload_in_progress)
-    return std_reg_operand (op, mode);
-  return reg_operand (op, mode);
-}
-
-/* Address register.  */
-
-int
-addr_reg_operand (rtx op, enum machine_mode mode)
-{
-  if (! reg_operand (op, mode))
-    return 0;
-  return c4x_a_register (op);
-}
-
-
-/* Index register.  */
-
-int
-index_reg_operand (rtx op, enum machine_mode mode)
-{
-  if (! reg_operand (op, mode))
-    return 0;
-  if (GET_CODE (op) == SUBREG)
-    op = SUBREG_REG (op);
-  return c4x_x_register (op);
-}
-
-
-/* DP register.  */
-
-int
-dp_reg_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  return REG_P (op) && IS_DP_OR_PSEUDO_REG (op);
-}
-
-
-/* SP register.  */
-
-int
-sp_reg_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  return REG_P (op) && IS_SP_OR_PSEUDO_REG (op);
-}
-
-
-/* ST register.  */
-
-int
-st_reg_operand (register rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  return REG_P (op) && IS_ST_OR_PSEUDO_REG (op);
-}
-
-
-/* RC register.  */
-
-int
-rc_reg_operand (register rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  return REG_P (op) && IS_RC_OR_PSEUDO_REG (op);
-}
-
-
-int
-call_address_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  return (REG_P (op) || symbolic_address_operand (op, mode));
-}
-
-
-/* Symbolic address operand.  */
-
-int
-symbolic_address_operand (register rtx op,
-                         enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  switch (GET_CODE (op))
-    {
-    case CONST:
-    case SYMBOL_REF:
-    case LABEL_REF:
-      return 1;
-    default:
-      return 0;
-    }
-}
-
-
-/* Check dst operand of a move instruction.  */
-
-int
-dst_operand (rtx op, enum machine_mode mode)
-{
-  if (GET_CODE (op) == SUBREG
-      && mixed_subreg_operand (op, mode))
-    return 0;
-
-  if (REG_P (op))
-    return reg_operand (op, mode);
-
-  return nonimmediate_operand (op, mode);
-}
-
-
-/* Check src operand of two operand arithmetic instructions.  */
-
-int
-src_operand (rtx op, enum machine_mode mode)
-{
-  if (GET_CODE (op) == SUBREG
-      && mixed_subreg_operand (op, mode))
-    return 0;
-
-  if (REG_P (op))
-    return reg_operand (op, mode);
-
-  if (mode == VOIDmode)
-    mode = GET_MODE (op);
-
-  if (GET_CODE (op) == CONST_INT)
-    return (mode == QImode || mode == Pmode || mode == HImode)
-      && c4x_I_constant (op);
-
-  /* We don't like CONST_DOUBLE integers.  */
-  if (GET_CODE (op) == CONST_DOUBLE)
-    return c4x_H_constant (op);
-
-  /* Disallow symbolic addresses.  Only the predicate
-     symbolic_address_operand will match these.  */
-  if (GET_CODE (op) == SYMBOL_REF
-      || GET_CODE (op) == LABEL_REF
-      || GET_CODE (op) == CONST)
-    return 0;
-
-  /* If TARGET_LOAD_DIRECT_MEMS is nonzero, disallow direct memory
-     access to symbolic addresses.  These operands will get forced
-     into a register and the movqi expander will generate a
-     HIGH/LO_SUM pair if TARGET_EXPOSE_LDP is nonzero.  */
-  if (GET_CODE (op) == MEM
-      && ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
-          || GET_CODE (XEXP (op, 0)) == LABEL_REF
-          || GET_CODE (XEXP (op, 0)) == CONST)))
-    return !TARGET_EXPOSE_LDP && 
-      ! TARGET_LOAD_DIRECT_MEMS && GET_MODE (op) == mode;
-
-  return general_operand (op, mode);
-}
-
-
-int
-src_hi_operand (rtx op, enum machine_mode mode)
-{
-  if (c4x_O_constant (op))
-    return 1;
-  return src_operand (op, mode);
-}
-
-
-/* Check src operand of two operand logical instructions.  */
-
-int
-lsrc_operand (rtx op, enum machine_mode mode)
-{
-  if (mode == VOIDmode)
-    mode = GET_MODE (op);
-
-  if (mode != QImode && mode != Pmode)
-    fatal_insn ("mode not QImode", op);
-
-  if (GET_CODE (op) == CONST_INT)
-    return c4x_L_constant (op) || c4x_J_constant (op);
-
-  return src_operand (op, mode);
-}
-
-
-/* Check src operand of two operand tricky instructions.  */
-
-int
-tsrc_operand (rtx op, enum machine_mode mode)
-{
-  if (mode == VOIDmode)
-    mode = GET_MODE (op);
-
-  if (mode != QImode && mode != Pmode)
-    fatal_insn ("mode not QImode", op);
-
-  if (GET_CODE (op) == CONST_INT)
-    return c4x_L_constant (op) || c4x_N_constant (op) || c4x_J_constant (op);
-
-  return src_operand (op, mode);
-}
-
-
-/* Check src operand of two operand non immedidate instructions.  */
-
-int
-nonimmediate_src_operand (rtx op, enum machine_mode mode)
-{
-  if (GET_CODE (op) == CONST_INT || GET_CODE (op) == CONST_DOUBLE)
-    return 0;
-
-  return src_operand (op, mode);
-}
-
-
-/* Check logical src operand of two operand non immedidate instructions.  */
-
-int
-nonimmediate_lsrc_operand (rtx op, enum machine_mode mode)
-{
-  if (GET_CODE (op) == CONST_INT || GET_CODE (op) == CONST_DOUBLE)
-    return 0;
-
-  return lsrc_operand (op, mode);
-}
-
-
-int
-reg_or_const_operand (rtx op, enum machine_mode mode)
-{
-  return reg_operand (op, mode) || const_operand (op, mode);
-}
-
-
-/* Check for indirect operands allowable in parallel instruction.  */
-
-int
-par_ind_operand (rtx op, enum machine_mode mode)
-{
-  if (mode != VOIDmode && mode != GET_MODE (op))
-    return 0;
-
-  return c4x_S_indirect (op);
-}
-
-
-/* Check for operands allowable in parallel instruction.  */
-
-int
-parallel_operand (rtx op, enum machine_mode mode)
-{
-  return ext_low_reg_operand (op, mode) || par_ind_operand (op, mode);
-}
-
-
 static void 
 c4x_S_address_parse (rtx op, int *base, int *incdec, int *index, int *disp)
 {
@@ -4410,16 +3994,8 @@ c4x_external_ref (const char *name)
 static void
 c4x_file_start (void)
 {
-  int dspversion = 0;
-  if (TARGET_C30) dspversion = 30;
-  if (TARGET_C31) dspversion = 31;
-  if (TARGET_C32) dspversion = 32;
-  if (TARGET_C33) dspversion = 33;
-  if (TARGET_C40) dspversion = 40;
-  if (TARGET_C44) dspversion = 44;
-
   default_file_start ();
-  fprintf (asm_out_file, "\t.version\t%d\n", dspversion);
+  fprintf (asm_out_file, "\t.version\t%d\n", c4x_cpu_version);
   fputs ("\n\t.data\ndata_sec:\n", asm_out_file);
 }
 
@@ -4497,7 +4073,7 @@ c4x_handle_fntype_attribute (tree *node, tree name,
 {
   if (TREE_CODE (*node) != FUNCTION_TYPE)
     {
-      warning ("`%s' attribute only applies to functions",
+      warning (OPT_Wattributes, "%qs attribute only applies to functions",
               IDENTIFIER_POINTER (name));
       *no_add_attrs = true;
     }
@@ -4522,8 +4098,8 @@ c4x_rptb_rpts_p (rtx insn, rtx op)
          where they are and print a warning.  We should
          probably move these insns before the repeat block insn.  */
       if (TARGET_DEBUG)
-       fatal_insn("c4x_rptb_rpts_p: Repeat block top label moved\n",
-                  insn);
+       fatal_insn ("c4x_rptb_rpts_p: Repeat block top label moved",
+                   insn);
       return 0;
     }
 
@@ -4924,7 +4500,8 @@ c4x_init_libfuncs (void)
 }
 
 static void
-c4x_asm_named_section (const char *name, unsigned int flags ATTRIBUTE_UNUSED)
+c4x_asm_named_section (const char *name, unsigned int flags ATTRIBUTE_UNUSED,
+                      tree decl ATTRIBUTE_UNUSED)
 {
   fprintf (asm_out_file, "\t.sect\t\"%s\"\n", name);
 }