From a50e2aa7ac23d6ba010751318501c23ed7485f10 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Wed, 10 Apr 2013 21:03:44 +0000 Subject: [PATCH 2/6] SPARC, GCC 4.8: Errata changes gcc/ChangeLog 2013-11-18 Sebastian Huber Backport from mainline 2013-04-10 Steven Bosscher * 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. --- gcc/config/sparc/sparc.c | 243 ++++++++++++++++++++++++++-------------------- gcc/config/sparc/t-sparc | 2 +- 2 files changed, 139 insertions(+), 106 deletions(-) diff --git a/gcc/config/sparc/sparc.c b/gcc/config/sparc/sparc.c index 7e87b47..4f81b83 100644 --- a/gcc/config/sparc/sparc.c +++ b/gcc/config/sparc/sparc.c @@ -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); @@ -680,9 +680,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 @@ -804,6 +801,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) { @@ -1241,6 +1368,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. */ @@ -10897,107 +11031,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 * diff --git a/gcc/config/sparc/t-sparc b/gcc/config/sparc/t-sparc index d7b17fb..664f4a4 100644 --- a/gcc/config/sparc/t-sparc +++ b/gcc/config/sparc/t-sparc @@ -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 -- 1.7.7