diff options
Diffstat (limited to 'gcc/config/sparc/sparc.c')
-rw-r--r-- | gcc/config/sparc/sparc.c | 1020 |
1 files changed, 101 insertions, 919 deletions
diff --git a/gcc/config/sparc/sparc.c b/gcc/config/sparc/sparc.c index f2b3585413b..2f7633638bc 100644 --- a/gcc/config/sparc/sparc.c +++ b/gcc/config/sparc/sparc.c @@ -140,22 +140,14 @@ static int function_arg_slotno PARAMS ((const CUMULATIVE_ARGS *, static int supersparc_adjust_cost PARAMS ((rtx, rtx, rtx, int)); static int hypersparc_adjust_cost PARAMS ((rtx, rtx, rtx, int)); -static int ultrasparc_adjust_cost PARAMS ((rtx, rtx, rtx, int)); static void sparc_output_addr_vec PARAMS ((rtx)); static void sparc_output_addr_diff_vec PARAMS ((rtx)); static void sparc_output_deferred_case_vectors PARAMS ((void)); static void sparc_add_gc_roots PARAMS ((void)); -static void mark_ultrasparc_pipeline_state PARAMS ((void *)); static int check_return_regs PARAMS ((rtx)); static int epilogue_renumber PARAMS ((rtx *, int)); static bool sparc_assemble_integer PARAMS ((rtx, unsigned int, int)); -static int ultra_cmove_results_ready_p PARAMS ((rtx)); -static int ultra_fpmode_conflict_exists PARAMS ((enum machine_mode)); -static rtx *ultra_find_type PARAMS ((int, rtx *, int)); -static void ultra_build_types_avail PARAMS ((rtx *, int)); -static void ultra_flush_pipeline PARAMS ((void)); -static void ultra_rescan_pipeline_state PARAMS ((rtx *, int)); static int set_extends PARAMS ((rtx)); static void output_restore_regs PARAMS ((FILE *, int)); static void sparc_output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT)); @@ -169,15 +161,13 @@ static void sparc_nonflat_function_prologue PARAMS ((FILE *, HOST_WIDE_INT, #ifdef OBJECT_FORMAT_ELF static void sparc_elf_asm_named_section PARAMS ((const char *, unsigned int)); #endif -static void ultrasparc_sched_reorder PARAMS ((FILE *, int, rtx *, int)); -static int ultrasparc_variable_issue PARAMS ((rtx)); -static void ultrasparc_sched_init PARAMS ((void)); static int sparc_adjust_cost PARAMS ((rtx, rtx, rtx, int)); static int sparc_issue_rate PARAMS ((void)); -static int sparc_variable_issue PARAMS ((FILE *, int, rtx, int)); static void sparc_sched_init PARAMS ((FILE *, int, int)); -static int sparc_sched_reorder PARAMS ((FILE *, int, rtx *, int *, int)); +static int sparc_use_dfa_pipeline_interface PARAMS ((void)); +static int sparc_use_sched_lookahead PARAMS ((void)); +static rtx sparc_cycle_display PARAMS ((int, rtx)); /* Option handling. */ @@ -231,12 +221,14 @@ enum processor_type sparc_cpu; #define TARGET_SCHED_ADJUST_COST sparc_adjust_cost #undef TARGET_SCHED_ISSUE_RATE #define TARGET_SCHED_ISSUE_RATE sparc_issue_rate -#undef TARGET_SCHED_VARIABLE_ISSUE -#define TARGET_SCHED_VARIABLE_ISSUE sparc_variable_issue #undef TARGET_SCHED_INIT #define TARGET_SCHED_INIT sparc_sched_init -#undef TARGET_SCHED_REORDER -#define TARGET_SCHED_REORDER sparc_sched_reorder +#undef TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE +#define TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE sparc_use_dfa_pipeline_interface +#undef TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD +#define TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD sparc_use_sched_lookahead +#undef TARGET_SCHED_CYCLE_DISPLAY +#define TARGET_SCHED_CYCLE_DISPLAY sparc_cycle_display struct gcc_target targetm = TARGET_INITIALIZER; @@ -273,6 +265,7 @@ sparc_override_options () { TARGET_CPU_supersparc, "supersparc" }, { TARGET_CPU_v9, "v9" }, { TARGET_CPU_ultrasparc, "ultrasparc" }, + { TARGET_CPU_ultrasparc3, "ultrasparc3" }, { 0, 0 } }; const struct cpu_default *def; @@ -305,6 +298,9 @@ sparc_override_options () /* Although insns using %y are deprecated, it is a clear win on current ultrasparcs. */ |MASK_DEPRECATED_V8_INSNS}, + /* TI ultrasparc III */ + /* ??? Check if %y issue still holds true in ultra3. */ + { "ultrasparc3", PROCESSOR_ULTRASPARC3, MASK_ISA, MASK_V9|MASK_DEPRECATED_V8_INSNS}, { 0, 0, 0, 0 } }; const struct cpu_table *cpu; @@ -417,7 +413,9 @@ sparc_override_options () target_flags &= ~MASK_STACK_BIAS; /* Supply a default value for align_functions. */ - if (align_functions == 0 && sparc_cpu == PROCESSOR_ULTRASPARC) + if (align_functions == 0 + && (sparc_cpu == PROCESSOR_ULTRASPARC + || sparc_cpu == PROCESSOR_ULTRASPARC3)) align_functions = 32; /* Validate PCC_STRUCT_RETURN. */ @@ -6479,7 +6477,8 @@ sparc64_initialize_trampoline (tramp, fnaddr, cxt) emit_move_insn (gen_rtx_MEM (DImode, plus_constant (tramp, 24)), fnaddr); emit_insn (gen_flushdi (validize_mem (gen_rtx_MEM (DImode, tramp)))); - if (sparc_cpu != PROCESSOR_ULTRASPARC) + if (sparc_cpu != PROCESSOR_ULTRASPARC + && sparc_cpu != PROCESSOR_ULTRASPARC3) emit_insn (gen_flushdi (validize_mem (gen_rtx_MEM (DImode, plus_constant (tramp, 8))))); } @@ -7332,157 +7331,6 @@ hypersparc_adjust_cost (insn, link, dep_insn, cost) } static int -ultrasparc_adjust_cost (insn, link, dep_insn, cost) - rtx insn; - rtx link; - rtx dep_insn; - int cost; -{ - enum attr_type insn_type, dep_type; - rtx pat = PATTERN(insn); - rtx dep_pat = PATTERN (dep_insn); - - if (recog_memoized (insn) < 0 || recog_memoized (dep_insn) < 0) - return cost; - - insn_type = get_attr_type (insn); - dep_type = get_attr_type (dep_insn); - - /* Nothing issues in parallel with integer multiplies, so - mark as zero cost since the scheduler can not do anything - about it. */ - if (insn_type == TYPE_IMUL || insn_type == TYPE_IDIV) - return 0; - -#define SLOW_FP(dep_type) \ -(dep_type == TYPE_FPSQRTS || dep_type == TYPE_FPSQRTD || \ - dep_type == TYPE_FPDIVS || dep_type == TYPE_FPDIVD) - - switch (REG_NOTE_KIND (link)) - { - case 0: - /* Data dependency; DEP_INSN writes a register that INSN reads some - cycles later. */ - - if (dep_type == TYPE_CMOVE) - { - /* Instructions that read the result of conditional moves cannot - be in the same group or the following group. */ - return cost + 1; - } - - switch (insn_type) - { - /* UltraSPARC can dual issue a store and an instruction setting - the value stored, except for divide and square root. */ - case TYPE_FPSTORE: - if (! SLOW_FP (dep_type)) - return 0; - return cost; - - case TYPE_STORE: - if (GET_CODE (pat) != SET || GET_CODE (dep_pat) != SET) - return cost; - - if (rtx_equal_p (SET_DEST (dep_pat), SET_SRC (pat))) - /* The dependency between the two instructions is on the data - that is being stored. Assume that the address of the store - is not also dependent. */ - return 0; - return cost; - - case TYPE_LOAD: - case TYPE_SLOAD: - case TYPE_FPLOAD: - /* A load does not return data until at least 11 cycles after - a store to the same location. 3 cycles are accounted for - in the load latency; add the other 8 here. */ - if (dep_type == TYPE_STORE || dep_type == TYPE_FPSTORE) - { - /* If the addresses are not equal this may be a false - dependency because pointer aliasing could not be - determined. Add only 2 cycles in that case. 2 is - an arbitrary compromise between 8, which would cause - the scheduler to generate worse code elsewhere to - compensate for a dependency which might not really - exist, and 0. */ - if (GET_CODE (pat) != SET || GET_CODE (dep_pat) != SET - || GET_CODE (SET_SRC (pat)) != MEM - || GET_CODE (SET_DEST (dep_pat)) != MEM - || ! rtx_equal_p (XEXP (SET_SRC (pat), 0), - XEXP (SET_DEST (dep_pat), 0))) - return cost + 2; - - return cost + 8; - } - return cost; - - case TYPE_BRANCH: - /* Compare to branch latency is 0. There is no benefit from - separating compare and branch. */ - if (dep_type == TYPE_COMPARE) - return 0; - /* Floating point compare to branch latency is less than - compare to conditional move. */ - if (dep_type == TYPE_FPCMP) - return cost - 1; - return cost; - - case TYPE_FPCMOVE: - /* FMOVR class instructions can not issue in the same cycle - or the cycle after an instruction which writes any - integer register. Model this as cost 2 for dependent - instructions. */ - if (dep_type == TYPE_IALU - && cost < 2) - return 2; - /* Otherwise check as for integer conditional moves. */ - - case TYPE_CMOVE: - /* Conditional moves involving integer registers wait until - 3 cycles after loads return data. The interlock applies - to all loads, not just dependent loads, but that is hard - to model. */ - if (dep_type == TYPE_LOAD || dep_type == TYPE_SLOAD) - return cost + 3; - return cost; - - default: - break; - } - break; - - case REG_DEP_ANTI: - /* Divide and square root lock destination registers for full latency. */ - if (! SLOW_FP (dep_type)) - return 0; - break; - - case REG_DEP_OUTPUT: - /* IEU and FPU instruction that have the same destination - register cannot be grouped together. */ - return cost + 1; - - default: - break; - } - - /* Other costs not accounted for: - - Single precision floating point loads lock the other half of - the even/odd register pair. - - Several hazards associated with ldd/std are ignored because these - instructions are rarely generated for V9. - - The floating point pipeline can not have both a single and double - precision operation active at the same time. Format conversions - and graphics instructions are given honorary double precision status. - - call and jmpl are always the first instruction in a group. */ - - return cost; - -#undef SLOW_FP -} - -static int sparc_adjust_cost(insn, link, dep, cost) rtx insn; rtx link; @@ -7498,792 +7346,143 @@ sparc_adjust_cost(insn, link, dep, cost) case PROCESSOR_SPARCLITE86X: cost = hypersparc_adjust_cost (insn, link, dep, cost); break; - case PROCESSOR_ULTRASPARC: - cost = ultrasparc_adjust_cost (insn, link, dep, cost); - break; default: break; } return cost; } -/* This describes the state of the UltraSPARC pipeline during - instruction scheduling. */ - -#define TMASK(__x) ((unsigned)1 << ((int)(__x))) -#define UMASK(__x) ((unsigned)1 << ((int)(__x))) - -enum ultra_code { NONE=0, /* no insn at all */ - IEU0, /* shifts and conditional moves */ - IEU1, /* condition code setting insns, calls+jumps */ - IEUN, /* all other single cycle ieu insns */ - LSU, /* loads and stores */ - CTI, /* branches */ - FPM, /* FPU pipeline 1, multiplies and divides */ - FPA, /* FPU pipeline 2, all other operations */ - SINGLE, /* single issue instructions */ - NUM_ULTRA_CODES }; - -static enum ultra_code ultra_code_from_mask PARAMS ((int)); -static void ultra_schedule_insn PARAMS ((rtx *, rtx *, int, enum ultra_code)); - -static const char *const ultra_code_names[NUM_ULTRA_CODES] = { - "NONE", "IEU0", "IEU1", "IEUN", "LSU", "CTI", - "FPM", "FPA", "SINGLE" }; - -struct ultrasparc_pipeline_state { - /* The insns in this group. */ - rtx group[4]; - - /* The code for each insn. */ - enum ultra_code codes[4]; - - /* Which insns in this group have been committed by the - scheduler. This is how we determine how many more - can issue this cycle. */ - char commit[4]; - - /* How many insns in this group. */ - char group_size; - - /* Mask of free slots still in this group. */ - char free_slot_mask; - - /* The slotter uses the following to determine what other - insn types can still make their way into this group. */ - char contents [NUM_ULTRA_CODES]; - char num_ieu_insns; -}; - -#define ULTRA_NUM_HIST 8 -static struct ultrasparc_pipeline_state ultra_pipe_hist[ULTRA_NUM_HIST]; -static int ultra_cur_hist; -static int ultra_cycles_elapsed; - -#define ultra_pipe (ultra_pipe_hist[ultra_cur_hist]) - -/* Given TYPE_MASK compute the ultra_code it has. */ -static enum ultra_code -ultra_code_from_mask (type_mask) - int type_mask; -{ - if (type_mask & (TMASK (TYPE_SHIFT) | TMASK (TYPE_CMOVE))) - return IEU0; - else if (type_mask & (TMASK (TYPE_COMPARE) | - TMASK (TYPE_CALL) | - TMASK (TYPE_SIBCALL) | - TMASK (TYPE_UNCOND_BRANCH))) - return IEU1; - else if (type_mask & TMASK (TYPE_IALU)) - return IEUN; - else if (type_mask & (TMASK (TYPE_LOAD) | TMASK (TYPE_SLOAD) | - TMASK (TYPE_STORE) | TMASK (TYPE_FPLOAD) | - TMASK (TYPE_FPSTORE))) - return LSU; - else if (type_mask & (TMASK (TYPE_FPMUL) | TMASK (TYPE_FPDIVS) | - TMASK (TYPE_FPDIVD) | TMASK (TYPE_FPSQRTS) | - TMASK (TYPE_FPSQRTD))) - return FPM; - else if (type_mask & (TMASK (TYPE_FPMOVE) | TMASK (TYPE_FPCMOVE) | - TMASK (TYPE_FP) | TMASK (TYPE_FPCMP))) - return FPA; - else if (type_mask & TMASK (TYPE_BRANCH)) - return CTI; - - return SINGLE; -} - -/* Check INSN (a conditional move) and make sure that it's - results are available at this cycle. Return 1 if the - results are in fact ready. */ -static int -ultra_cmove_results_ready_p (insn) - rtx insn; +static void +sparc_sched_init (dump, sched_verbose, max_ready) + FILE *dump ATTRIBUTE_UNUSED; + int sched_verbose ATTRIBUTE_UNUSED; + int max_ready ATTRIBUTE_UNUSED; { - struct ultrasparc_pipeline_state *up; - int entry, slot; - - /* If this got dispatched in the previous - group, the results are not ready. */ - entry = (ultra_cur_hist - 1) & (ULTRA_NUM_HIST - 1); - up = &ultra_pipe_hist[entry]; - slot = 4; - while (--slot >= 0) - if (up->group[slot] == insn) - return 0; - - return 1; } - -/* Walk backwards in pipeline history looking for FPU - operations which use a mode different than FPMODE and - will create a stall if an insn using FPMODE were to be - dispatched this cycle. */ + static int -ultra_fpmode_conflict_exists (fpmode) - enum machine_mode fpmode; +sparc_use_dfa_pipeline_interface () { - int hist_ent; - int hist_lim; - - hist_ent = (ultra_cur_hist - 1) & (ULTRA_NUM_HIST - 1); - if (ultra_cycles_elapsed < 4) - hist_lim = ultra_cycles_elapsed; - else - hist_lim = 4; - while (hist_lim > 0) - { - struct ultrasparc_pipeline_state *up = &ultra_pipe_hist[hist_ent]; - int slot = 4; - - while (--slot >= 0) - { - rtx insn = up->group[slot]; - enum machine_mode this_mode; - rtx pat; - - if (! insn - || GET_CODE (insn) != INSN - || (pat = PATTERN (insn)) == 0 - || GET_CODE (pat) != SET) - continue; - - this_mode = GET_MODE (SET_DEST (pat)); - if ((this_mode != SFmode - && this_mode != DFmode) - || this_mode == fpmode) - continue; - - /* If it is not FMOV, FABS, FNEG, FDIV, or FSQRT then - we will get a stall. Loads and stores are independent - of these rules. */ - if (GET_CODE (SET_SRC (pat)) != ABS - && GET_CODE (SET_SRC (pat)) != NEG - && ((TMASK (get_attr_type (insn)) & - (TMASK (TYPE_FPDIVS) | TMASK (TYPE_FPDIVD) | - TMASK (TYPE_FPMOVE) | TMASK (TYPE_FPSQRTS) | - TMASK (TYPE_FPSQRTD) | - TMASK (TYPE_LOAD) | TMASK (TYPE_STORE))) == 0)) - return 1; - } - hist_lim--; - hist_ent = (hist_ent - 1) & (ULTRA_NUM_HIST - 1); - } - - /* No conflicts, safe to dispatch. */ + if ((1 << sparc_cpu) & + ((1 << PROCESSOR_ULTRASPARC) | (1 << PROCESSOR_CYPRESS) | + (1 << PROCESSOR_SUPERSPARC) | (1 << PROCESSOR_HYPERSPARC) | + (1 << PROCESSOR_SPARCLITE86X) | (1 << PROCESSOR_TSC701) | + (1 << PROCESSOR_ULTRASPARC3))) + return 1; return 0; } -/* Find an instruction in LIST which has one of the - type attributes enumerated in TYPE_MASK. START - says where to begin the search. - - NOTE: This scheme depends upon the fact that we - have less than 32 distinct type attributes. */ - -static int ultra_types_avail; - -static rtx * -ultra_find_type (type_mask, list, start) - int type_mask; - rtx *list; - int start; -{ - int i; - - /* Short circuit if no such insn exists in the ready - at the moment. */ - if ((type_mask & ultra_types_avail) == 0) - return 0; - - for (i = start; i >= 0; i--) - { - rtx insn = list[i]; - - if (recog_memoized (insn) >= 0 - && (TMASK(get_attr_type (insn)) & type_mask)) - { - enum machine_mode fpmode = SFmode; - rtx pat = 0; - int slot; - int check_depend = 0; - int check_fpmode_conflict = 0; - - if (GET_CODE (insn) == INSN - && (pat = PATTERN(insn)) != 0 - && GET_CODE (pat) == SET - && !(type_mask & (TMASK (TYPE_STORE) | - TMASK (TYPE_FPSTORE)))) - { - check_depend = 1; - if (GET_MODE (SET_DEST (pat)) == SFmode - || GET_MODE (SET_DEST (pat)) == DFmode) - { - fpmode = GET_MODE (SET_DEST (pat)); - check_fpmode_conflict = 1; - } - } - - slot = 4; - while(--slot >= 0) - { - rtx slot_insn = ultra_pipe.group[slot]; - rtx slot_pat; - - /* Already issued, bad dependency, or FPU - mode conflict. */ - if (slot_insn != 0 - && (slot_pat = PATTERN (slot_insn)) != 0 - && ((insn == slot_insn) - || (check_depend == 1 - && GET_CODE (slot_insn) == INSN - && GET_CODE (slot_pat) == SET - && ((GET_CODE (SET_DEST (slot_pat)) == REG - && GET_CODE (SET_SRC (pat)) == REG - && REGNO (SET_DEST (slot_pat)) == - REGNO (SET_SRC (pat))) - || (GET_CODE (SET_DEST (slot_pat)) == SUBREG - && GET_CODE (SET_SRC (pat)) == SUBREG - && REGNO (SUBREG_REG (SET_DEST (slot_pat))) == - REGNO (SUBREG_REG (SET_SRC (pat))) - && SUBREG_BYTE (SET_DEST (slot_pat)) == - SUBREG_BYTE (SET_SRC (pat))))) - || (check_fpmode_conflict == 1 - && GET_CODE (slot_insn) == INSN - && GET_CODE (slot_pat) == SET - && (GET_MODE (SET_DEST (slot_pat)) == SFmode - || GET_MODE (SET_DEST (slot_pat)) == DFmode) - && GET_MODE (SET_DEST (slot_pat)) != fpmode))) - goto next; - } - - /* Check for peculiar result availability and dispatch - interference situations. */ - if (pat != 0 - && ultra_cycles_elapsed > 0) - { - rtx link; - - for (link = LOG_LINKS (insn); link; link = XEXP (link, 1)) - { - rtx link_insn = XEXP (link, 0); - if (GET_CODE (link_insn) == INSN - && recog_memoized (link_insn) >= 0 - && (TMASK (get_attr_type (link_insn)) & - (TMASK (TYPE_CMOVE) | TMASK (TYPE_FPCMOVE))) - && ! ultra_cmove_results_ready_p (link_insn)) - goto next; - } - - if (check_fpmode_conflict - && ultra_fpmode_conflict_exists (fpmode)) - goto next; - } - - return &list[i]; - } - next: - ; - } +static int +sparc_use_sched_lookahead () +{ + if (sparc_cpu == PROCESSOR_ULTRASPARC + || sparc_cpu == PROCESSOR_ULTRASPARC3) + return 4; + if ((1 << sparc_cpu) & + ((1 << PROCESSOR_SUPERSPARC) | (1 << PROCESSOR_HYPERSPARC) | + (1 << PROCESSOR_SPARCLITE86X))) + return 3; return 0; } -static void -ultra_build_types_avail (ready, n_ready) - rtx *ready; - int n_ready; +static rtx +sparc_cycle_display (clock, last) + int clock; + rtx last; { - int i = n_ready - 1; - - ultra_types_avail = 0; - while(i >= 0) - { - rtx insn = ready[i]; + if (reload_completed) + return emit_insn_after (gen_cycle_display (GEN_INT (clock)), last); + else + return last; +} - if (recog_memoized (insn) >= 0) - ultra_types_avail |= TMASK (get_attr_type (insn)); +/* Make sure that the dependency between OUT_INSN and + IN_INSN (a store) is on the store data not the address + operand(s) of the store. */ - i -= 1; - } -} +int +ultrasparc_store_bypass_p (out_insn, in_insn) + rtx out_insn, in_insn; +{ + rtx out_pat, in_pat; + unsigned int regno; -/* Place insn pointed to my IP into the pipeline. - Make element THIS of READY be that insn if it - is not already. TYPE indicates the pipeline class - this insn falls into. */ -static void -ultra_schedule_insn (ip, ready, this, type) - rtx *ip; - rtx *ready; - int this; - enum ultra_code type; -{ - int pipe_slot; - char mask = ultra_pipe.free_slot_mask; - rtx temp; + if (recog_memoized (in_insn) < 0) + return 0; - /* Obtain free slot. */ - for (pipe_slot = 0; pipe_slot < 4; pipe_slot++) - if ((mask & (1 << pipe_slot)) != 0) - break; - if (pipe_slot == 4) + if (get_attr_type (in_insn) != TYPE_STORE + && get_attr_type (in_insn) != TYPE_FPSTORE) abort (); - /* In it goes, and it hasn't been committed yet. */ - ultra_pipe.group[pipe_slot] = *ip; - ultra_pipe.codes[pipe_slot] = type; - ultra_pipe.contents[type] = 1; - if (UMASK (type) & - (UMASK (IEUN) | UMASK (IEU0) | UMASK (IEU1))) - ultra_pipe.num_ieu_insns += 1; + out_pat = PATTERN (out_insn); + in_pat = PATTERN (in_insn); - ultra_pipe.free_slot_mask = (mask & ~(1 << pipe_slot)); - ultra_pipe.group_size += 1; - ultra_pipe.commit[pipe_slot] = 0; + if ((GET_CODE (out_pat) != SET + && GET_CODE (out_pat) != PARALLEL) + || GET_CODE (in_pat) != SET) + abort (); - /* Update ready list. */ - temp = *ip; - while (ip != &ready[this]) + if (GET_CODE (SET_SRC (in_pat)) == REG) { - ip[0] = ip[1]; - ++ip; + regno = REGNO (SET_SRC (in_pat)); } - *ip = temp; -} - -/* Advance to the next pipeline group. */ -static void -ultra_flush_pipeline () -{ - ultra_cur_hist = (ultra_cur_hist + 1) & (ULTRA_NUM_HIST - 1); - ultra_cycles_elapsed += 1; - memset ((char *) &ultra_pipe, 0, sizeof ultra_pipe); - ultra_pipe.free_slot_mask = 0xf; -} - -/* Init our data structures for this current block. */ -static void -ultrasparc_sched_init () -{ - memset ((char *) ultra_pipe_hist, 0, sizeof ultra_pipe_hist); - ultra_cur_hist = 0; - ultra_cycles_elapsed = 0; - ultra_pipe.free_slot_mask = 0xf; -} - -static void -sparc_sched_init (dump, sched_verbose, max_ready) - FILE *dump ATTRIBUTE_UNUSED; - int sched_verbose ATTRIBUTE_UNUSED; - int max_ready ATTRIBUTE_UNUSED; -{ - if (sparc_cpu == PROCESSOR_ULTRASPARC) - ultrasparc_sched_init (); -} - -/* INSN has been scheduled, update pipeline commit state - and return how many instructions are still to be - scheduled in this group. */ -static int -ultrasparc_variable_issue (insn) - rtx insn; -{ - struct ultrasparc_pipeline_state *up = &ultra_pipe; - int i, left_to_fire; - - left_to_fire = 0; - for (i = 0; i < 4; i++) + else if (GET_CODE (SET_SRC (in_pat)) == SUBREG) { - if (up->group[i] == 0) - continue; - - if (up->group[i] == insn) - { - up->commit[i] = 1; - } - else if (! up->commit[i]) - left_to_fire++; + regno = REGNO (SUBREG_REG (SET_SRC (in_pat))); } - - return left_to_fire; -} - -static int -sparc_variable_issue (dump, sched_verbose, insn, cim) - FILE *dump ATTRIBUTE_UNUSED; - int sched_verbose ATTRIBUTE_UNUSED; - rtx insn; - int cim; -{ - if (sparc_cpu == PROCESSOR_ULTRASPARC) - return ultrasparc_variable_issue (insn); else - return cim - 1; -} - -/* In actual_hazard_this_instance, we may have yanked some - instructions from the ready list due to conflict cost - adjustments. If so, and such an insn was in our pipeline - group, remove it and update state. */ -static void -ultra_rescan_pipeline_state (ready, n_ready) - rtx *ready; - int n_ready; -{ - struct ultrasparc_pipeline_state *up = &ultra_pipe; - int i; + return 0; - for (i = 0; i < 4; i++) + if (GET_CODE (out_pat) == PARALLEL) { - rtx insn = up->group[i]; - int j; + int i; - if (! insn) - continue; + for (i = 0; i < XVECLEN (out_pat, 0); i++) + { + rtx exp = XVECEXP (out_pat, 0, i); - /* If it has been committed, then it was removed from - the ready list because it was actually scheduled, - and that is not the case we are searching for here. */ - if (up->commit[i] != 0) - continue; + if (GET_CODE (exp) != SET) + return 0; - for (j = n_ready - 1; j >= 0; j--) - if (ready[j] == insn) - break; + if (GET_CODE (SET_DEST (exp)) == REG + && regno == REGNO (SET_DEST (exp))) + return 1; - /* If we didn't find it, toss it. */ - if (j < 0) - { - enum ultra_code ucode = up->codes[i]; - - up->group[i] = 0; - up->codes[i] = NONE; - up->contents[ucode] = 0; - if (UMASK (ucode) & - (UMASK (IEUN) | UMASK (IEU0) | UMASK (IEU1))) - up->num_ieu_insns -= 1; - - up->free_slot_mask |= (1 << i); - up->group_size -= 1; - up->commit[i] = 0; + if (GET_CODE (SET_DEST (exp)) == SUBREG + && regno == REGNO (SUBREG_REG (SET_DEST (exp)))) + return 1; } } -} - -static void -ultrasparc_sched_reorder (dump, sched_verbose, ready, n_ready) - FILE *dump; - int sched_verbose; - rtx *ready; - int n_ready; -{ - struct ultrasparc_pipeline_state *up = &ultra_pipe; - int i, this_insn; - - if (sched_verbose) + else if (GET_CODE (SET_DEST (out_pat)) == REG) { - int n; - - fprintf (dump, "\n;;\tUltraSPARC Looking at ["); - for (n = n_ready - 1; n >= 0; n--) - { - rtx insn = ready[n]; - enum ultra_code ucode; - - if (recog_memoized (insn) < 0) - continue; - ucode = ultra_code_from_mask (TMASK (get_attr_type (insn))); - if (n != 0) - fprintf (dump, "%s(%d) ", - ultra_code_names[ucode], - INSN_UID (insn)); - else - fprintf (dump, "%s(%d)", - ultra_code_names[ucode], - INSN_UID (insn)); - } - fprintf (dump, "]\n"); + return regno == REGNO (SET_DEST (out_pat)); } - - this_insn = n_ready - 1; - - /* Skip over junk we don't understand. */ - while ((this_insn >= 0) - && recog_memoized (ready[this_insn]) < 0) - this_insn--; - - ultra_build_types_avail (ready, this_insn + 1); - - while (this_insn >= 0) { - int old_group_size = up->group_size; - - if (up->group_size != 0) - { - int num_committed; - - num_committed = (up->commit[0] + up->commit[1] + - up->commit[2] + up->commit[3]); - /* If nothing has been commited from our group, or all of - them have. Clear out the (current cycle's) pipeline - state and start afresh. */ - if (num_committed == 0 - || num_committed == up->group_size) - { - ultra_flush_pipeline (); - up = &ultra_pipe; - old_group_size = 0; - } - else - { - /* OK, some ready list insns got requeued and thus removed - from the ready list. Account for this fact. */ - ultra_rescan_pipeline_state (ready, n_ready); - - /* Something "changed", make this look like a newly - formed group so the code at the end of the loop - knows that progress was in fact made. */ - if (up->group_size != old_group_size) - old_group_size = 0; - } - } - - if (up->group_size == 0) - { - /* If the pipeline is (still) empty and we have any single - group insns, get them out now as this is a good time. */ - rtx *ip = ultra_find_type ((TMASK (TYPE_RETURN) | TMASK (TYPE_IDIV) | - TMASK (TYPE_IMUL) | TMASK (TYPE_CMOVE) | - TMASK (TYPE_MULTI) | TMASK (TYPE_MISC)), - ready, this_insn); - if (ip) - { - ultra_schedule_insn (ip, ready, this_insn, SINGLE); - break; - } - - /* If we are not in the process of emptying out the pipe, try to - obtain an instruction which must be the first in it's group. */ - ip = ultra_find_type ((TMASK (TYPE_CALL) | - TMASK (TYPE_SIBCALL) | - TMASK (TYPE_CALL_NO_DELAY_SLOT) | - TMASK (TYPE_UNCOND_BRANCH)), - ready, this_insn); - if (ip) - { - ultra_schedule_insn (ip, ready, this_insn, IEU1); - this_insn--; - } - else if ((ip = ultra_find_type ((TMASK (TYPE_FPDIVS) | - TMASK (TYPE_FPDIVD) | - TMASK (TYPE_FPSQRTS) | - TMASK (TYPE_FPSQRTD)), - ready, this_insn)) != 0) - { - ultra_schedule_insn (ip, ready, this_insn, FPM); - this_insn--; - } - } - - /* Try to fill the integer pipeline. First, look for an IEU0 specific - operation. We can't do more IEU operations if the first 3 slots are - all full or we have dispatched two IEU insns already. */ - if ((up->free_slot_mask & 0x7) != 0 - && up->num_ieu_insns < 2 - && up->contents[IEU0] == 0 - && up->contents[IEUN] == 0) - { - rtx *ip = ultra_find_type (TMASK(TYPE_SHIFT), ready, this_insn); - if (ip) - { - ultra_schedule_insn (ip, ready, this_insn, IEU0); - this_insn--; - } - } - - /* If we can, try to find an IEU1 specific or an unnamed - IEU instruction. */ - if ((up->free_slot_mask & 0x7) != 0 - && up->num_ieu_insns < 2) - { - rtx *ip = ultra_find_type ((TMASK (TYPE_IALU) | - (up->contents[IEU1] == 0 ? TMASK (TYPE_COMPARE) : 0)), - ready, this_insn); - if (ip) - { - rtx insn = *ip; - - ultra_schedule_insn (ip, ready, this_insn, - (!up->contents[IEU1] - && get_attr_type (insn) == TYPE_COMPARE) - ? IEU1 : IEUN); - this_insn--; - } - } - - /* If only one IEU insn has been found, try to find another unnamed - IEU operation or an IEU1 specific one. */ - if ((up->free_slot_mask & 0x7) != 0 - && up->num_ieu_insns < 2) - { - rtx *ip; - int tmask = TMASK (TYPE_IALU); - - if (!up->contents[IEU1]) - tmask |= TMASK (TYPE_COMPARE); - ip = ultra_find_type (tmask, ready, this_insn); - if (ip) - { - rtx insn = *ip; - - ultra_schedule_insn (ip, ready, this_insn, - (!up->contents[IEU1] - && get_attr_type (insn) == TYPE_COMPARE) - ? IEU1 : IEUN); - this_insn--; - } - } - - /* Try for a load or store, but such an insn can only be issued - if it is within' one of the first 3 slots. */ - if ((up->free_slot_mask & 0x7) != 0 - && up->contents[LSU] == 0) - { - rtx *ip = ultra_find_type ((TMASK (TYPE_LOAD) | TMASK (TYPE_SLOAD) | - TMASK (TYPE_STORE) | TMASK (TYPE_FPLOAD) | - TMASK (TYPE_FPSTORE)), ready, this_insn); - if (ip) - { - ultra_schedule_insn (ip, ready, this_insn, LSU); - this_insn--; - } - } - - /* Now find FPU operations, first FPM class. But not divisions or - square-roots because those will break the group up. Unlike all - the previous types, these can go in any slot. */ - if (up->free_slot_mask != 0 - && up->contents[FPM] == 0) - { - rtx *ip = ultra_find_type (TMASK (TYPE_FPMUL), ready, this_insn); - if (ip) - { - ultra_schedule_insn (ip, ready, this_insn, FPM); - this_insn--; - } - } - - /* Continue on with FPA class if we have not filled the group already. */ - if (up->free_slot_mask != 0 - && up->contents[FPA] == 0) - { - rtx *ip = ultra_find_type ((TMASK (TYPE_FPMOVE) | TMASK (TYPE_FPCMOVE) | - TMASK (TYPE_FP) | TMASK (TYPE_FPCMP)), - ready, this_insn); - if (ip) - { - ultra_schedule_insn (ip, ready, this_insn, FPA); - this_insn--; - } - } - - /* Finally, maybe stick a branch in here. */ - if (up->free_slot_mask != 0 - && up->contents[CTI] == 0) - { - rtx *ip = ultra_find_type (TMASK (TYPE_BRANCH), ready, this_insn); - - /* Try to slip in a branch only if it is one of the - next 2 in the ready list. */ - if (ip && ((&ready[this_insn] - ip) < 2)) - { - ultra_schedule_insn (ip, ready, this_insn, CTI); - this_insn--; - } - } - - up->group_size = 0; - for (i = 0; i < 4; i++) - if ((up->free_slot_mask & (1 << i)) == 0) - up->group_size++; - - /* See if we made any progress... */ - if (old_group_size != up->group_size) - break; - - /* Clean out the (current cycle's) pipeline state - and try once more. If we placed no instructions - into the pipeline at all, it means a real hard - conflict exists with some earlier issued instruction - so we must advance to the next cycle to clear it up. */ - if (up->group_size == 0) - { - ultra_flush_pipeline (); - up = &ultra_pipe; - } - else - { - memset ((char *) &ultra_pipe, 0, sizeof ultra_pipe); - ultra_pipe.free_slot_mask = 0xf; - } - } - - if (sched_verbose) + else if (GET_CODE (SET_DEST (out_pat)) == SUBREG) { - int n, gsize; - - fprintf (dump, ";;\tUltraSPARC Launched ["); - gsize = up->group_size; - for (n = 0; n < 4; n++) - { - rtx insn = up->group[n]; - - if (! insn) - continue; - - gsize -= 1; - if (gsize != 0) - fprintf (dump, "%s(%d) ", - ultra_code_names[up->codes[n]], - INSN_UID (insn)); - else - fprintf (dump, "%s(%d)", - ultra_code_names[up->codes[n]], - INSN_UID (insn)); - } - fprintf (dump, "]\n"); + return regno == REGNO (SUBREG_REG (SET_DEST (out_pat))); } -} -static int -sparc_sched_reorder (dump, sched_verbose, ready, n_readyp, clock) - FILE *dump; - int sched_verbose; - rtx *ready; - int *n_readyp; - int clock ATTRIBUTE_UNUSED; -{ - if (sparc_cpu == PROCESSOR_ULTRASPARC) - ultrasparc_sched_reorder (dump, sched_verbose, ready, *n_readyp); - return sparc_issue_rate (); + return 0; } -static int +static int sparc_issue_rate () { switch (sparc_cpu) { - default: - return 1; - case PROCESSOR_V9: + default: + return 1; + case PROCESSOR_V9: /* Assume V9 processors are capable of at least dual-issue. */ return 2; - case PROCESSOR_SUPERSPARC: - return 3; + case PROCESSOR_SUPERSPARC: + return 3; case PROCESSOR_HYPERSPARC: case PROCESSOR_SPARCLITE86X: return 2; - case PROCESSOR_ULTRASPARC: - return 4; + case PROCESSOR_ULTRASPARC: + case PROCESSOR_ULTRASPARC3: + return 4; } } @@ -8564,21 +7763,6 @@ sparc_profile_hook (labelno) emit_library_call (fun, LCT_NORMAL, VOIDmode, 1, lab, Pmode); } -/* Mark ARG, which is really a struct ultrasparc_pipline_state *, for - GC. */ - -static void -mark_ultrasparc_pipeline_state (arg) - void *arg; -{ - struct ultrasparc_pipeline_state *ups; - size_t i; - - ups = (struct ultrasparc_pipeline_state *) arg; - for (i = 0; i < ARRAY_SIZE (ups->group); ++i) - ggc_mark_rtx (ups->group[i]); -} - /* Called to register all of our global variables with the garbage collector. */ @@ -8591,8 +7775,6 @@ sparc_add_gc_roots () ggc_add_rtx_root (&get_pc_symbol, 1); ggc_add_rtx_root (&sparc_addr_diff_list, 1); ggc_add_rtx_root (&sparc_addr_list, 1); - ggc_add_root (ultra_pipe_hist, ARRAY_SIZE (ultra_pipe_hist), - sizeof (ultra_pipe_hist[0]), &mark_ultrasparc_pipeline_state); } #ifdef OBJECT_FORMAT_ELF |