/* 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 */
};
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. */
#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
#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
#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
};
}
\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
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. */
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;
}
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
{
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;
}
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))
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)
{
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;
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,
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
spaces -= 2;
}
- if (! TARGET_V9)
- labelno = "";
- else
+ if (TARGET_V9)
{
rtx note;
int v8 = 0;
spaces -= 3;
}
}
+ else
+ labelno = "";
+
if (spaces > 0)
*p++ = '\t';
else
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.
/* 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
/* 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
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;
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;