sparc.c: Include tree-pass.h.
* config/sparc/sparc.c: Include tree-pass.h. (TARGET_MACHINE_DEPENDENT_REORG): Do not redefine. (sparc_reorg): Rename to sparc_do_work_around_errata. Move to head of file. Change return type. Split off gate function. (sparc_gate_work_around_errata): New function. (pass_work_around_errata): New pass definition. (insert_pass_work_around_errata) New pass insert definition to insert pass_work_around_errata just after delayed-branch scheduling. (sparc_option_override): Insert the pass. * config/sparc/t-sparc (sparc.o): Add TREE_PASS_H dependence. From-SVN: r197681
This commit is contained in:
parent
89deeb3b7e
commit
0ea8a6f9c7
|
@ -1,3 +1,16 @@
|
|||
2013-04-10 Steven Bosscher <steven@gcc.gnu.org>
|
||||
|
||||
* config/sparc/sparc.c: Include tree-pass.h.
|
||||
(TARGET_MACHINE_DEPENDENT_REORG): Do not redefine.
|
||||
(sparc_reorg): Rename to sparc_do_work_around_errata. Move to
|
||||
head of file. Change return type. Split off gate function.
|
||||
(sparc_gate_work_around_errata): New function.
|
||||
(pass_work_around_errata): New pass definition.
|
||||
(insert_pass_work_around_errata) New pass insert definition to
|
||||
insert pass_work_around_errata just after delayed-branch scheduling.
|
||||
(sparc_option_override): Insert the pass.
|
||||
* config/sparc/t-sparc (sparc.o): Add TREE_PASS_H dependence.
|
||||
|
||||
2013-04-10 David S. Miller <davem@davemloft.net>
|
||||
|
||||
* config/sparc/sparc.h (ASM_CPU_SPEC): Pass -Av8 if -mcpu=supersparc
|
||||
|
|
|
@ -52,6 +52,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
#include "params.h"
|
||||
#include "df.h"
|
||||
#include "opts.h"
|
||||
#include "tree-pass.h"
|
||||
|
||||
/* Processor costs */
|
||||
|
||||
|
@ -538,7 +539,6 @@ static void sparc_output_mi_thunk (FILE *, tree, HOST_WIDE_INT,
|
|||
HOST_WIDE_INT, tree);
|
||||
static bool sparc_can_output_mi_thunk (const_tree, HOST_WIDE_INT,
|
||||
HOST_WIDE_INT, const_tree);
|
||||
static void sparc_reorg (void);
|
||||
static struct machine_function * sparc_init_machine_status (void);
|
||||
static bool sparc_cannot_force_const_mem (enum machine_mode, rtx);
|
||||
static rtx sparc_tls_get_addr (void);
|
||||
|
@ -681,9 +681,6 @@ char sparc_hard_reg_printed[8];
|
|||
#undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
|
||||
#define TARGET_ASM_CAN_OUTPUT_MI_THUNK sparc_can_output_mi_thunk
|
||||
|
||||
#undef TARGET_MACHINE_DEPENDENT_REORG
|
||||
#define TARGET_MACHINE_DEPENDENT_REORG sparc_reorg
|
||||
|
||||
#undef TARGET_RTX_COSTS
|
||||
#define TARGET_RTX_COSTS sparc_rtx_costs
|
||||
#undef TARGET_ADDRESS_COST
|
||||
|
@ -808,6 +805,136 @@ char sparc_hard_reg_printed[8];
|
|||
|
||||
struct gcc_target targetm = TARGET_INITIALIZER;
|
||||
|
||||
/* We use a machine specific pass to enable workarounds for errata.
|
||||
We need to have the (essentially) final form of the insn stream in order
|
||||
to properly detect the various hazards. Therefore, this machine specific
|
||||
pass runs as late as possible. The pass is inserted in the pass pipeline
|
||||
at the end of sparc_options_override. */
|
||||
|
||||
static bool
|
||||
sparc_gate_work_around_errata (void)
|
||||
{
|
||||
/* The only erratum we handle for now is that of the AT697F processor. */
|
||||
return sparc_fix_at697f != 0;
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
sparc_do_work_around_errata (void)
|
||||
{
|
||||
rtx insn, next;
|
||||
|
||||
/* Now look for specific patterns in the insn stream. */
|
||||
for (insn = get_insns (); insn; insn = next)
|
||||
{
|
||||
bool insert_nop = false;
|
||||
rtx set;
|
||||
|
||||
/* Look for a single-word load into an odd-numbered FP register. */
|
||||
if (NONJUMP_INSN_P (insn)
|
||||
&& (set = single_set (insn)) != NULL_RTX
|
||||
&& GET_MODE_SIZE (GET_MODE (SET_SRC (set))) == 4
|
||||
&& MEM_P (SET_SRC (set))
|
||||
&& REG_P (SET_DEST (set))
|
||||
&& REGNO (SET_DEST (set)) > 31
|
||||
&& REGNO (SET_DEST (set)) % 2 != 0)
|
||||
{
|
||||
/* The wrong dependency is on the enclosing double register. */
|
||||
unsigned int x = REGNO (SET_DEST (set)) - 1;
|
||||
unsigned int src1, src2, dest;
|
||||
int code;
|
||||
|
||||
/* If the insn has a delay slot, then it cannot be problematic. */
|
||||
next = next_active_insn (insn);
|
||||
if (NONJUMP_INSN_P (next) && GET_CODE (PATTERN (next)) == SEQUENCE)
|
||||
code = -1;
|
||||
else
|
||||
{
|
||||
extract_insn (next);
|
||||
code = INSN_CODE (next);
|
||||
}
|
||||
|
||||
switch (code)
|
||||
{
|
||||
case CODE_FOR_adddf3:
|
||||
case CODE_FOR_subdf3:
|
||||
case CODE_FOR_muldf3:
|
||||
case CODE_FOR_divdf3:
|
||||
dest = REGNO (recog_data.operand[0]);
|
||||
src1 = REGNO (recog_data.operand[1]);
|
||||
src2 = REGNO (recog_data.operand[2]);
|
||||
if (src1 != src2)
|
||||
{
|
||||
/* Case [1-4]:
|
||||
ld [address], %fx+1
|
||||
FPOPd %f{x,y}, %f{y,x}, %f{x,y} */
|
||||
if ((src1 == x || src2 == x)
|
||||
&& (dest == src1 || dest == src2))
|
||||
insert_nop = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Case 5:
|
||||
ld [address], %fx+1
|
||||
FPOPd %fx, %fx, %fx */
|
||||
if (src1 == x
|
||||
&& dest == src1
|
||||
&& (code == CODE_FOR_adddf3 || code == CODE_FOR_muldf3))
|
||||
insert_nop = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case CODE_FOR_sqrtdf2:
|
||||
dest = REGNO (recog_data.operand[0]);
|
||||
src1 = REGNO (recog_data.operand[1]);
|
||||
/* Case 6:
|
||||
ld [address], %fx+1
|
||||
fsqrtd %fx, %fx */
|
||||
if (src1 == x && dest == src1)
|
||||
insert_nop = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
next = NEXT_INSN (insn);
|
||||
|
||||
if (insert_nop)
|
||||
emit_insn_after (gen_nop (), insn);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct rtl_opt_pass pass_work_around_errata =
|
||||
{
|
||||
{
|
||||
RTL_PASS,
|
||||
"errata", /* name */
|
||||
OPTGROUP_NONE, /* optinfo_flags */
|
||||
sparc_gate_work_around_errata, /* gate */
|
||||
sparc_do_work_around_errata, /* execute */
|
||||
NULL, /* sub */
|
||||
NULL, /* next */
|
||||
0, /* static_pass_number */
|
||||
TV_MACH_DEP, /* tv_id */
|
||||
0, /* properties_required */
|
||||
0, /* properties_provided */
|
||||
0, /* properties_destroyed */
|
||||
0, /* todo_flags_start */
|
||||
TODO_verify_rtl_sharing, /* todo_flags_finish */
|
||||
}
|
||||
};
|
||||
|
||||
struct register_pass_info insert_pass_work_around_errata =
|
||||
{
|
||||
&pass_work_around_errata.pass, /* pass */
|
||||
"dbr", /* reference_pass_name */
|
||||
1, /* ref_pass_instance_number */
|
||||
PASS_POS_INSERT_AFTER /* po_op */
|
||||
};
|
||||
|
||||
/* Helpers for TARGET_DEBUG_OPTIONS. */
|
||||
static void
|
||||
dump_target_flag_bits (const int flags)
|
||||
{
|
||||
|
@ -1245,6 +1372,13 @@ sparc_option_override (void)
|
|||
pessimizes for double floating-point registers. */
|
||||
if (!global_options_set.x_flag_ira_share_save_slots)
|
||||
flag_ira_share_save_slots = 0;
|
||||
|
||||
/* We register a machine specific pass to work around errata, if any.
|
||||
The pass mut be scheduled as late as possible so that we have the
|
||||
(essentially) final form of the insn stream to work on.
|
||||
Registering the pass must be done at start up. It's convenient to
|
||||
do it here. */
|
||||
register_pass (&insert_pass_work_around_errata);
|
||||
}
|
||||
|
||||
/* Miscellaneous utilities. */
|
||||
|
@ -10906,107 +11040,6 @@ sparc_can_output_mi_thunk (const_tree thunk_fndecl ATTRIBUTE_UNUSED,
|
|||
return (vcall_offset >= -32768 || ! fixed_regs[5]);
|
||||
}
|
||||
|
||||
/* We use the machine specific reorg pass to enable workarounds for errata. */
|
||||
|
||||
static void
|
||||
sparc_reorg (void)
|
||||
{
|
||||
rtx insn, next;
|
||||
|
||||
/* The only erratum we handle for now is that of the AT697F processor. */
|
||||
if (!sparc_fix_at697f)
|
||||
return;
|
||||
|
||||
/* We need to have the (essentially) final form of the insn stream in order
|
||||
to properly detect the various hazards. Run delay slot scheduling. */
|
||||
if (optimize > 0 && flag_delayed_branch)
|
||||
{
|
||||
cleanup_barriers ();
|
||||
dbr_schedule (get_insns ());
|
||||
}
|
||||
|
||||
/* Now look for specific patterns in the insn stream. */
|
||||
for (insn = get_insns (); insn; insn = next)
|
||||
{
|
||||
bool insert_nop = false;
|
||||
rtx set;
|
||||
|
||||
/* Look for a single-word load into an odd-numbered FP register. */
|
||||
if (NONJUMP_INSN_P (insn)
|
||||
&& (set = single_set (insn)) != NULL_RTX
|
||||
&& GET_MODE_SIZE (GET_MODE (SET_SRC (set))) == 4
|
||||
&& MEM_P (SET_SRC (set))
|
||||
&& REG_P (SET_DEST (set))
|
||||
&& REGNO (SET_DEST (set)) > 31
|
||||
&& REGNO (SET_DEST (set)) % 2 != 0)
|
||||
{
|
||||
/* The wrong dependency is on the enclosing double register. */
|
||||
unsigned int x = REGNO (SET_DEST (set)) - 1;
|
||||
unsigned int src1, src2, dest;
|
||||
int code;
|
||||
|
||||
/* If the insn has a delay slot, then it cannot be problematic. */
|
||||
next = next_active_insn (insn);
|
||||
if (NONJUMP_INSN_P (next) && GET_CODE (PATTERN (next)) == SEQUENCE)
|
||||
code = -1;
|
||||
else
|
||||
{
|
||||
extract_insn (next);
|
||||
code = INSN_CODE (next);
|
||||
}
|
||||
|
||||
switch (code)
|
||||
{
|
||||
case CODE_FOR_adddf3:
|
||||
case CODE_FOR_subdf3:
|
||||
case CODE_FOR_muldf3:
|
||||
case CODE_FOR_divdf3:
|
||||
dest = REGNO (recog_data.operand[0]);
|
||||
src1 = REGNO (recog_data.operand[1]);
|
||||
src2 = REGNO (recog_data.operand[2]);
|
||||
if (src1 != src2)
|
||||
{
|
||||
/* Case [1-4]:
|
||||
ld [address], %fx+1
|
||||
FPOPd %f{x,y}, %f{y,x}, %f{x,y} */
|
||||
if ((src1 == x || src2 == x)
|
||||
&& (dest == src1 || dest == src2))
|
||||
insert_nop = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Case 5:
|
||||
ld [address], %fx+1
|
||||
FPOPd %fx, %fx, %fx */
|
||||
if (src1 == x
|
||||
&& dest == src1
|
||||
&& (code == CODE_FOR_adddf3 || code == CODE_FOR_muldf3))
|
||||
insert_nop = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case CODE_FOR_sqrtdf2:
|
||||
dest = REGNO (recog_data.operand[0]);
|
||||
src1 = REGNO (recog_data.operand[1]);
|
||||
/* Case 6:
|
||||
ld [address], %fx+1
|
||||
fsqrtd %fx, %fx */
|
||||
if (src1 == x && dest == src1)
|
||||
insert_nop = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
next = NEXT_INSN (insn);
|
||||
|
||||
if (insert_nop)
|
||||
emit_insn_after (gen_nop (), insn);
|
||||
}
|
||||
}
|
||||
|
||||
/* How to allocate a 'struct machine_function'. */
|
||||
|
||||
static struct machine_function *
|
||||
|
|
|
@ -23,7 +23,7 @@ sparc.o: $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
|
|||
insn-codes.h conditions.h output.h $(INSN_ATTR_H) $(FLAGS_H) \
|
||||
$(FUNCTION_H) $(EXCEPT_H) $(EXPR_H) $(OPTABS_H) $(RECOG_H) \
|
||||
$(DIAGNOSTIC_CORE_H) $(GGC_H) $(TM_P_H) debug.h $(TARGET_H) \
|
||||
$(TARGET_DEF_H) $(COMMON_TARGET_H) $(GIMPLE_H) \
|
||||
$(TARGET_DEF_H) $(COMMON_TARGET_H) $(GIMPLE_H) $(TREE_PASS_H) \
|
||||
langhooks.h reload.h $(PARAMS_H) $(DF_H) $(OPTS_H) \
|
||||
gt-sparc.h
|
||||
|
||||
|
|
Loading…
Reference in New Issue