OSDN Git Service

* final.c (output_in_slot): New global variable.
[pf3gnuchains/gcc-fork.git] / gcc / config / sparc / sparc.c
index ef9e337..cf7ac04 100644 (file)
@@ -52,145 +52,145 @@ Boston, MA 02111-1307, USA.  */
 /* Processor costs */
 static const
 struct processor_costs cypress_costs = {
-  2, /* int load */
-  2, /* int signed load */
-  2, /* int zeroed load */
-  2, /* float load */
-  5, /* fmov, fneg, fabs */
-  5, /* fadd, fsub */
-  1, /* fcmp */
-  1, /* fmov, fmovr */
-  7, /* fmul */
-  37, /* fdivs */
-  37, /* fdivd */
-  63, /* fsqrts */
-  63, /* fsqrtd */
-  1, /* imul */
-  1, /* imulX */
+  COSTS_N_INSNS (2), /* int load */
+  COSTS_N_INSNS (2), /* int signed load */
+  COSTS_N_INSNS (2), /* int zeroed load */
+  COSTS_N_INSNS (2), /* float load */
+  COSTS_N_INSNS (5), /* fmov, fneg, fabs */
+  COSTS_N_INSNS (5), /* fadd, fsub */
+  COSTS_N_INSNS (1), /* fcmp */
+  COSTS_N_INSNS (1), /* fmov, fmovr */
+  COSTS_N_INSNS (7), /* fmul */
+  COSTS_N_INSNS (37), /* fdivs */
+  COSTS_N_INSNS (37), /* fdivd */
+  COSTS_N_INSNS (63), /* fsqrts */
+  COSTS_N_INSNS (63), /* fsqrtd */
+  COSTS_N_INSNS (1), /* imul */
+  COSTS_N_INSNS (1), /* imulX */
   0, /* imul bit factor */
-  1, /* idiv */
-  1, /* idivX */
-  1, /* movcc/movr */
+  COSTS_N_INSNS (1), /* idiv */
+  COSTS_N_INSNS (1), /* idivX */
+  COSTS_N_INSNS (1), /* movcc/movr */
   0, /* shift penalty */
 };
 
 static const
 struct processor_costs supersparc_costs = {
-  1, /* int load */
-  1, /* int signed load */
-  1, /* int zeroed load */
-  0, /* float load */
-  3, /* fmov, fneg, fabs */
-  3, /* fadd, fsub */
-  3, /* fcmp */
-  1, /* fmov, fmovr */
-  3, /* fmul */
-  6, /* fdivs */
-  9, /* fdivd */
-  12, /* fsqrts */
-  12, /* fsqrtd */
-  4, /* imul */
-  4, /* imulX */
+  COSTS_N_INSNS (1), /* int load */
+  COSTS_N_INSNS (1), /* int signed load */
+  COSTS_N_INSNS (1), /* int zeroed load */
+  COSTS_N_INSNS (0), /* float load */
+  COSTS_N_INSNS (3), /* fmov, fneg, fabs */
+  COSTS_N_INSNS (3), /* fadd, fsub */
+  COSTS_N_INSNS (3), /* fcmp */
+  COSTS_N_INSNS (1), /* fmov, fmovr */
+  COSTS_N_INSNS (3), /* fmul */
+  COSTS_N_INSNS (6), /* fdivs */
+  COSTS_N_INSNS (9), /* fdivd */
+  COSTS_N_INSNS (12), /* fsqrts */
+  COSTS_N_INSNS (12), /* fsqrtd */
+  COSTS_N_INSNS (4), /* imul */
+  COSTS_N_INSNS (4), /* imulX */
   0, /* imul bit factor */
-  4, /* idiv */
-  4, /* idivX */
-  1, /* movcc/movr */
+  COSTS_N_INSNS (4), /* idiv */
+  COSTS_N_INSNS (4), /* idivX */
+  COSTS_N_INSNS (1), /* movcc/movr */
   1, /* shift penalty */
 };
 
 static const
 struct processor_costs hypersparc_costs = {
-  1, /* int load */
-  1, /* int signed load */
-  1, /* int zeroed load */
-  1, /* float load */
-  1, /* fmov, fneg, fabs */
-  1, /* fadd, fsub */
-  1, /* fcmp */
-  1, /* fmov, fmovr */
-  1, /* fmul */
-  8, /* fdivs */
-  12, /* fdivd */
-  17, /* fsqrts */
-  17, /* fsqrtd */
-  17, /* imul */
-  17, /* imulX */
+  COSTS_N_INSNS (1), /* int load */
+  COSTS_N_INSNS (1), /* int signed load */
+  COSTS_N_INSNS (1), /* int zeroed load */
+  COSTS_N_INSNS (1), /* float load */
+  COSTS_N_INSNS (1), /* fmov, fneg, fabs */
+  COSTS_N_INSNS (1), /* fadd, fsub */
+  COSTS_N_INSNS (1), /* fcmp */
+  COSTS_N_INSNS (1), /* fmov, fmovr */
+  COSTS_N_INSNS (1), /* fmul */
+  COSTS_N_INSNS (8), /* fdivs */
+  COSTS_N_INSNS (12), /* fdivd */
+  COSTS_N_INSNS (17), /* fsqrts */
+  COSTS_N_INSNS (17), /* fsqrtd */
+  COSTS_N_INSNS (17), /* imul */
+  COSTS_N_INSNS (17), /* imulX */
   0, /* imul bit factor */
-  17, /* idiv */
-  17, /* idivX */
-  1, /* movcc/movr */
+  COSTS_N_INSNS (17), /* idiv */
+  COSTS_N_INSNS (17), /* idivX */
+  COSTS_N_INSNS (1), /* movcc/movr */
   0, /* shift penalty */
 };
 
 static const
 struct processor_costs sparclet_costs = {
-  3, /* int load */
-  3, /* int signed load */
-  1, /* int zeroed load */
-  1, /* float load */
-  1, /* fmov, fneg, fabs */
-  1, /* fadd, fsub */
-  1, /* fcmp */
-  1, /* fmov, fmovr */
-  1, /* fmul */
-  1, /* fdivs */
-  1, /* fdivd */
-  1, /* fsqrts */
-  1, /* fsqrtd */
-  5, /* imul */
-  5, /* imulX */
+  COSTS_N_INSNS (3), /* int load */
+  COSTS_N_INSNS (3), /* int signed load */
+  COSTS_N_INSNS (1), /* int zeroed load */
+  COSTS_N_INSNS (1), /* float load */
+  COSTS_N_INSNS (1), /* fmov, fneg, fabs */
+  COSTS_N_INSNS (1), /* fadd, fsub */
+  COSTS_N_INSNS (1), /* fcmp */
+  COSTS_N_INSNS (1), /* fmov, fmovr */
+  COSTS_N_INSNS (1), /* fmul */
+  COSTS_N_INSNS (1), /* fdivs */
+  COSTS_N_INSNS (1), /* fdivd */
+  COSTS_N_INSNS (1), /* fsqrts */
+  COSTS_N_INSNS (1), /* fsqrtd */
+  COSTS_N_INSNS (5), /* imul */
+  COSTS_N_INSNS (5), /* imulX */
   0, /* imul bit factor */
-  5, /* idiv */
-  5, /* idivX */
-  1, /* movcc/movr */
+  COSTS_N_INSNS (5), /* idiv */
+  COSTS_N_INSNS (5), /* idivX */
+  COSTS_N_INSNS (1), /* movcc/movr */
   0, /* shift penalty */
 };
 
 static const
 struct processor_costs ultrasparc_costs = {
-  2, /* int load */
-  3, /* int signed load */
-  2, /* int zeroed load */
-  2, /* float load */
-  1, /* fmov, fneg, fabs */
-  4, /* fadd, fsub */
-  1, /* fcmp */
-  2, /* fmov, fmovr */
-  4, /* fmul */
-  13, /* fdivs */
-  23, /* fdivd */
-  13, /* fsqrts */
-  23, /* fsqrtd */
-  4, /* imul */
-  4, /* imulX */
+  COSTS_N_INSNS (2), /* int load */
+  COSTS_N_INSNS (3), /* int signed load */
+  COSTS_N_INSNS (2), /* int zeroed load */
+  COSTS_N_INSNS (2), /* float load */
+  COSTS_N_INSNS (1), /* fmov, fneg, fabs */
+  COSTS_N_INSNS (4), /* fadd, fsub */
+  COSTS_N_INSNS (1), /* fcmp */
+  COSTS_N_INSNS (2), /* fmov, fmovr */
+  COSTS_N_INSNS (4), /* fmul */
+  COSTS_N_INSNS (13), /* fdivs */
+  COSTS_N_INSNS (23), /* fdivd */
+  COSTS_N_INSNS (13), /* fsqrts */
+  COSTS_N_INSNS (23), /* fsqrtd */
+  COSTS_N_INSNS (4), /* imul */
+  COSTS_N_INSNS (4), /* imulX */
   2, /* imul bit factor */
-  37, /* idiv */
-  68, /* idivX */
-  2, /* movcc/movr */
+  COSTS_N_INSNS (37), /* idiv */
+  COSTS_N_INSNS (68), /* idivX */
+  COSTS_N_INSNS (2), /* movcc/movr */
   2, /* shift penalty */
 };
 
 static const
 struct processor_costs ultrasparc3_costs = {
-  2, /* int load */
-  3, /* int signed load */
-  3, /* int zeroed load */
-  2, /* float load */
-  3, /* fmov, fneg, fabs */
-  4, /* fadd, fsub */
-  5, /* fcmp */
-  3, /* fmov, fmovr */
-  4, /* fmul */
-  17, /* fdivs */
-  20, /* fdivd */
-  20, /* fsqrts */
-  29, /* fsqrtd */
-  6, /* imul */
-  6, /* imulX */
+  COSTS_N_INSNS (2), /* int load */
+  COSTS_N_INSNS (3), /* int signed load */
+  COSTS_N_INSNS (3), /* int zeroed load */
+  COSTS_N_INSNS (2), /* float load */
+  COSTS_N_INSNS (3), /* fmov, fneg, fabs */
+  COSTS_N_INSNS (4), /* fadd, fsub */
+  COSTS_N_INSNS (5), /* fcmp */
+  COSTS_N_INSNS (3), /* fmov, fmovr */
+  COSTS_N_INSNS (4), /* fmul */
+  COSTS_N_INSNS (17), /* fdivs */
+  COSTS_N_INSNS (20), /* fdivd */
+  COSTS_N_INSNS (20), /* fsqrts */
+  COSTS_N_INSNS (29), /* fsqrtd */
+  COSTS_N_INSNS (6), /* imul */
+  COSTS_N_INSNS (6), /* imulX */
   0, /* imul bit factor */
-  40, /* idiv */
-  71, /* idivX */
-  2, /* movcc/movr */
+  COSTS_N_INSNS (40), /* idiv */
+  COSTS_N_INSNS (71), /* idivX */
+  COSTS_N_INSNS (2), /* movcc/movr */
   0, /* shift penalty */
 };
 
@@ -332,6 +332,11 @@ static rtx sparc_struct_value_rtx (tree, int);
 static bool sparc_return_in_memory (tree, tree);
 static bool sparc_strict_argument_naming (CUMULATIVE_ARGS *);
 static tree sparc_gimplify_va_arg (tree, tree, tree *, tree *);
+static bool sparc_pass_by_reference (CUMULATIVE_ARGS *,
+                                    enum machine_mode, tree, bool);
+#ifdef SUBTARGET_ATTRIBUTE_TABLE
+const struct attribute_spec sparc_attribute_table[];
+#endif
 \f
 /* Option handling.  */
 
@@ -387,8 +392,6 @@ enum processor_type sparc_cpu;
 #define TARGET_SCHED_ISSUE_RATE sparc_issue_rate
 #undef TARGET_SCHED_INIT
 #define TARGET_SCHED_INIT sparc_sched_init
-#undef TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE
-#define TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE hook_int_void_1
 #undef TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD
 #define TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD sparc_use_sched_lookahead
 
@@ -434,6 +437,10 @@ enum processor_type sparc_cpu;
 #define TARGET_STRUCT_VALUE_RTX sparc_struct_value_rtx
 #undef TARGET_RETURN_IN_MEMORY
 #define TARGET_RETURN_IN_MEMORY sparc_return_in_memory
+#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 sparc_pass_by_reference
 
 #undef TARGET_EXPAND_BUILTIN_SAVEREGS
 #define TARGET_EXPAND_BUILTIN_SAVEREGS sparc_builtin_saveregs
@@ -446,6 +453,16 @@ enum processor_type sparc_cpu;
 #undef TARGET_LATE_RTL_PROLOGUE_EPILOGUE
 #define TARGET_LATE_RTL_PROLOGUE_EPILOGUE true
 
+#ifdef SUBTARGET_INSERT_ATTRIBUTES
+#undef TARGET_INSERT_ATTRIBUTES
+#define TARGET_INSERT_ATTRIBUTES SUBTARGET_INSERT_ATTRIBUTES
+#endif
+
+#ifdef SUBTARGET_ATTRIBUTE_TABLE
+#undef TARGET_ATTRIBUTE_TABLE
+#define TARGET_ATTRIBUTE_TABLE sparc_attribute_table
+#endif
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
 /* Validate and override various options, and do some machine dependent
@@ -682,6 +699,16 @@ sparc_override_options (void)
     };
 }
 \f
+#ifdef SUBTARGET_ATTRIBUTE_TABLE
+/* Table of valid machine attributes.  */
+const struct attribute_spec sparc_attribute_table[] =
+{
+  /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
+  SUBTARGET_ATTRIBUTE_TABLE,
+  { NULL,        0, 0, false, false, false, NULL }
+};
+#endif
+\f
 /* Miscellaneous utilities.  */
 
 /* Nonzero if CODE, a comparison, is suitable for use in v9 conditional move
@@ -3778,11 +3805,10 @@ legitimize_pic_address (rtx orig, enum machine_mode mode ATTRIBUTE_UNUSED,
       else
        address = orig;
 
-      pic_ref = gen_rtx_MEM (Pmode,
-                            gen_rtx_PLUS (Pmode,
-                                          pic_offset_table_rtx, address));
+      pic_ref = gen_const_mem (Pmode,
+                              gen_rtx_PLUS (Pmode,
+                                            pic_offset_table_rtx, address));
       current_function_uses_pic_offset_table = 1;
-      RTX_UNCHANGING_P (pic_ref) = 1;
       insn = emit_move_insn (reg, pic_ref);
       /* Put a REG_EQUAL note on this insn, so that it can be optimized
         by loop.  */
@@ -4681,7 +4707,7 @@ output_return (rtx insn)
          if (! delay)
            abort ();
 
-         final_scan_insn (delay, asm_out_file, 1, 0, 1, NULL);
+         final_scan_insn (delay, asm_out_file, 1, 0, 2, NULL);
          PATTERN (delay) = gen_blockage ();
          INSN_CODE (delay) = -1;
        }
@@ -4730,7 +4756,7 @@ output_return (rtx insn)
              epilogue_renumber (&pat, 0);
              fprintf (asm_out_file, "\treturn\t%%i7+%d\n",
                       sparc_skip_caller_unimp ? 12 : 8);
-             final_scan_insn (delay, asm_out_file, 1, 0, 1, NULL);
+             final_scan_insn (delay, asm_out_file, 1, 0, 2, NULL);
            }
          else
            {
@@ -4791,7 +4817,7 @@ output_sibcall (rtx insn, rtx call_operand)
 
          output_asm_insn ("sethi\t%%hi(%a0), %%g1", operands);
          output_asm_insn ("jmp\t%%g1 + %%lo(%a0)", operands);
-         final_scan_insn (delay, asm_out_file, 1, 0, 1, NULL);
+         final_scan_insn (delay, asm_out_file, 1, 0, 2, NULL);
 
          PATTERN (delay) = gen_blockage ();
          INSN_CODE (delay) = -1;
@@ -5705,8 +5731,8 @@ function_arg_partial_nregs (const struct sparc_args *cum,
     }
   else
     {
-      /* We are guaranteed by function_arg_pass_by_reference that the size
-        of the argument is not greater than 16 bytes, so we only need to
+      /* We are guaranteed by pass_by_reference that the size of the
+        argument is not greater than 16 bytes, so we only need to
         return 1 if the argument is partially passed in registers.  */
 
       if (type && AGGREGATE_TYPE_P (type))
@@ -5737,16 +5763,16 @@ function_arg_partial_nregs (const struct sparc_args *cum,
   return 0;
 }
 
-/* Handle the FUNCTION_ARG_PASS_BY_REFERENCE macro.
+/* Return true if the argument should be passed by reference.
    !v9: The SPARC ABI stipulates passing struct arguments (of any size) and
    quad-precision floats by invisible reference.
    v9: Aggregates greater than 16 bytes are passed by reference.
    For Pascal, also pass arrays by reference.  */
 
-int
-function_arg_pass_by_reference (const struct sparc_args *cum ATTRIBUTE_UNUSED,
-                               enum machine_mode mode, tree type,
-                               int named ATTRIBUTE_UNUSED)
+static bool
+sparc_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
+                        enum machine_mode mode, tree type,
+                        bool named ATTRIBUTE_UNUSED)
 {
   if (TARGET_ARCH32)
     {
@@ -6001,7 +6027,7 @@ sparc_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
   bool indirect;
   tree ptrtype = build_pointer_type (type);
 
-  if (function_arg_pass_by_reference (0, TYPE_MODE (type), type, 0))
+  if (pass_by_reference (NULL, TYPE_MODE (type), type, 0))
     {
       indirect = true;
       size = rsize = UNITS_PER_WORD;
@@ -6083,18 +6109,77 @@ sparc_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
   return build_fold_indirect_ref (addr);
 }
 \f
+/* Return the string to output an unconditional branch to LABEL, which is
+   the operand number of the label.
+
+   DEST is the destination insn (i.e. the label), INSN is the source.  */
+
+const char *
+output_ubranch (rtx dest, int label, rtx insn)
+{
+  static char string[64];
+  bool noop = false;
+  char *p;
+
+  /* TurboSPARC is reported to have problems with
+     with
+       foo: b,a foo
+     i.e. an empty loop with the annul bit set.  The workaround is to use 
+        foo: b foo; nop
+     instead.  */
+
+  if (! TARGET_V9 && flag_delayed_branch
+      && (INSN_ADDRESSES (INSN_UID (dest))
+         == INSN_ADDRESSES (INSN_UID (insn))))
+    {
+      strcpy (string, "b\t");
+      noop = true;
+    }
+  else
+    {
+      bool v9_form = false;
+
+      if (TARGET_V9 && INSN_ADDRESSES_SET_P ())
+       {
+         int delta = (INSN_ADDRESSES (INSN_UID (dest))
+                      - INSN_ADDRESSES (INSN_UID (insn)));
+         /* Leave some instructions for "slop".  */
+         if (delta >= -260000 && delta < 260000)
+           v9_form = true;
+       }
+
+      if (v9_form)
+       strcpy (string, "ba%*,pt\t%%xcc, ");
+      else
+       strcpy (string, "b%*\t");
+    }
+
+  p = strchr (string, '\0');
+  *p++ = '%';
+  *p++ = 'l';
+  *p++ = '0' + label;
+  *p++ = '%';
+  if (noop)
+    *p++ = '#';
+  else
+    *p++ = '(';
+  *p = '\0';
+
+  return string;
+}
+
 /* Return the string to output a conditional branch to LABEL, which is
    the operand number of the label.  OP is the conditional expression.
    XEXP (OP, 0) is assumed to be a condition code register (integer or
    floating point) and its mode specifies what kind of comparison we made.
 
+   DEST is the destination insn (i.e. the label), INSN is the source.
+
    REVERSED is nonzero if we should reverse the sense of the comparison.
 
    ANNUL is nonzero if we should generate an annulling branch.
 
-   NOOP is nonzero if we have to follow this branch by a noop.
-
-   INSN, if set, is the insn.  */
+   NOOP is nonzero if we have to follow this branch by a noop.  */
 
 const char *
 output_cbranch (rtx op, rtx dest, int label, int reversed, int annul,
@@ -6129,7 +6214,7 @@ output_cbranch (rtx op, rtx dest, int label, int reversed, int annul,
       nop
      ba .LC29  */
 
-  far = get_attr_length (insn) >= 3;
+  far = TARGET_V9 && (get_attr_length (insn) >= 3);
   if (reversed ^ far)
     {
       /* Reversal of FP compares takes care -- an ordered compare
@@ -6259,9 +6344,7 @@ output_cbranch (rtx op, rtx dest, int label, int reversed, int annul,
       spaces -= 2;
     }
 
-  if (! TARGET_V9)
-    labelno = "";
-  else
+  if (TARGET_V9)
     {
       rtx note;
       int v8 = 0;
@@ -6311,6 +6394,9 @@ output_cbranch (rtx op, rtx dest, int label, int reversed, int annul,
          spaces -= 3;
        }
     }
+  else
+    labelno = "";
+
   if (spaces > 0)
     *p++ = '\t';
   else
@@ -6554,6 +6640,8 @@ sparc_emit_fixunsdi (rtx *operands, enum machine_mode mode)
    operand number of the reg.  OP is the conditional expression.  The mode
    of REG says what kind of comparison we made.
 
+   DEST is the destination insn (i.e. the label), INSN is the source.
+
    REVERSED is nonzero if we should reverse the sense of the comparison.
 
    ANNUL is nonzero if we should generate an annulling branch.
@@ -7507,7 +7595,7 @@ sparc_initialize_trampoline (rtx tramp, rtx fnaddr, rtx cxt)
 
   /* Call __enable_execute_stack after writing onto the stack to make sure
      the stack address is accessible.  */
-#ifdef TRANSFER_FROM_TRAMPOLINE
+#ifdef ENABLE_EXECUTE_STACK
   emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__enable_execute_stack"),
                      LCT_NORMAL, VOIDmode, 1, tramp, Pmode);
 #endif
@@ -7548,7 +7636,7 @@ sparc64_initialize_trampoline (rtx tramp, rtx fnaddr, rtx cxt)
 
   /* Call __enable_execute_stack after writing onto the stack to make sure
      the stack address is accessible.  */
-#ifdef TRANSFER_FROM_TRAMPOLINE
+#ifdef ENABLE_EXECUTE_STACK
   emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__enable_execute_stack"),
                      LCT_NORMAL, VOIDmode, 1, tramp, Pmode);
 #endif
@@ -8317,6 +8405,8 @@ sparc_rtx_costs (rtx x, int code, int outer_code, int *total)
     case MULT:
       if (float_mode_p)
        *total = sparc_costs->float_mul;
+      else if (! TARGET_HARD_MUL)
+       *total = COSTS_N_INSNS (25);
       else
        {
          int bit_cost;
@@ -8350,12 +8440,13 @@ sparc_rtx_costs (rtx x, int code, int outer_code, int *total)
              if (nbits < 3)
                nbits = 3;
              bit_cost = (nbits - 3) / sparc_costs->int_mul_bit_factor;
+             bit_cost = COSTS_N_INSNS (bit_cost);
            }
 
          if (mode == DImode)
-           *total = COSTS_N_INSNS (sparc_costs->int_mulX) + bit_cost;
+           *total = sparc_costs->int_mulX + bit_cost;
          else
-           *total = COSTS_N_INSNS (sparc_costs->int_mul) + bit_cost;
+           *total = sparc_costs->int_mul + bit_cost;
        }
       return false;