diff options
Diffstat (limited to 'toolchain-layer/recipes-devtools/gcc/gcc-4.6/linaro/gcc-4.6-linaro-r106869.patch')
-rw-r--r-- | toolchain-layer/recipes-devtools/gcc/gcc-4.6/linaro/gcc-4.6-linaro-r106869.patch | 2389 |
1 files changed, 0 insertions, 2389 deletions
diff --git a/toolchain-layer/recipes-devtools/gcc/gcc-4.6/linaro/gcc-4.6-linaro-r106869.patch b/toolchain-layer/recipes-devtools/gcc/gcc-4.6/linaro/gcc-4.6-linaro-r106869.patch deleted file mode 100644 index de3d2ff4cf..0000000000 --- a/toolchain-layer/recipes-devtools/gcc/gcc-4.6/linaro/gcc-4.6-linaro-r106869.patch +++ /dev/null @@ -1,2389 +0,0 @@ -2012-02-08 Ulrich Weigand <ulrich.weigand@linaro.org> - - gcc/ - * config/arm/arm.c (arm_option_optimization_table): Enable - -fsched-pressure using -fsched-pressure-algorithm=model by - default when optimizing. - -2012-02-08 Richard Sandiford <richard.sandiford@linaro.org> - - gcc/ - * sched-deps.c (fixup_sched_groups): Rename to... - (chain_to_prev_insn): ...this. - (chain_to_prev_insn_p): New function. - (deps_analyze_insn): Use it instead of SCHED_GROUP_P. - -2012-02-08 Richard Sandiford <richard.sandiford@linaro.org> - - gcc/ - * sched-int.h (_haifa_insn_data): Move priority_status. - Add model_index. - (INSN_MODEL_INDEX): New macro. - * haifa-sched.c (insn_delay): New function. - (sched_regno_pressure_class): Update commentary. - (mark_regno_birth_or_death): Pass the liveness bitmap and - pressure array as arguments, instead of using curr_reg_live and - curr_reg_pressure. Only update the pressure if the bit in the - liveness set has changed. - (initiate_reg_pressure_info): Always trust the live-in set for - SCHED_PRESSURE_MODEL. - (initiate_bb_reg_pressure_info): Update call to - mark_regno_birth_or_death. - (dep_list_size): Take the list as argument. - (calculate_reg_deaths): New function, extracted from... - (setup_insn_reg_pressure_info): ...here. - (MODEL_BAR): New macro. - (model_pressure_data, model_insn_info, model_pressure_limit) - (model_pressure_group): New structures. - (model_schedule, model_worklist, model_insns, model_num_insns) - (model_curr_point, model_before_pressure, model_next_priority): - New variables. - (MODEL_PRESSURE_DATA, MODEL_MAX_PRESSURE, MODEL_REF_PRESSURE) - (MODEL_INSN_INFO, MODEL_INSN): New macros. - (model_index, model_update_limit_points_in_group): New functions. - (model_update_limit_points, model_last_use_except): Likewise. - (model_start_update_pressure, model_update_pressure): Likewise. - (model_recompute, model_spill_cost, model_excess_group_cost): Likewise. - (model_excess_cost, model_dump_pressure_points): Likewise. - (model_set_excess_costs): Likewise. - (rank_for_schedule): Extend SCHED_PRIORITY_WEIGHTED ordering to - SCHED_PRIORITY_MODEL. Use insn_delay. Use the order in the model - schedule as an alternative tie-breaker. Update the call to - dep_list_size. - (ready_sort): Call model_set_excess_costs. - (update_register_pressure): Update call to mark_regno_birth_or_death. - Rely on that function to check liveness rather than doing it here. - (model_classify_pressure, model_order_p, model_add_to_worklist_at) - (model_remove_from_worklist, model_add_to_worklist, model_promote_insn) - (model_add_to_schedule, model_analyze_insns, model_init_pressure_group) - (model_record_pressure, model_record_pressures): New functions. - (model_record_final_pressures, model_add_successors_to_worklist) - (model_promote_predecessors, model_choose_insn): Likewise. - (model_reset_queue_indices, model_dump_pressure_summary): Likewise. - (model_start_schedule, model_finalize_pressure_group): Likewise. - (model_end_schedule): Likewise. - (schedule_insn): Say when we're scheduling the next instruction - in the model schedule. - (schedule_insn): Handle SCHED_PRESSURE_MODEL. - (queue_to_ready): Do not add instructions that are - MAX_SCHED_READY_INSNS beyond the current point of the model schedule. - Always allow the next instruction in the model schedule to be added. - (debug_ready_list): Print the INSN_REG_PRESSURE_EXCESS_COST_CHANGE - and delay for SCHED_PRESSURE_MODEL too. - (prune_ready_list): Extend SCHED_PRIORITY_WEIGHTED handling to - SCHED_PRIORITY_MODEL, but also take the DFA into account. - (schedule_block): Call model_start_schedule and model_end_schedule. - Extend SCHED_PRIORITY_WEIGHTED stall handling to SCHED_PRIORITY_MODEL. - (sched_init): Extend INSN_REG_PRESSURE_EXCESS_COST_CHANGE handling - to SCHED_PRESSURE_MODEL, but don't allocate saved_reg_live or - region_ref_regs. - (sched_finish): Update accordingly. - (fix_tick_ready): Extend INSN_REG_PRESSURE_EXCESS_COST_CHANGE handling - to SCHED_PRESSURE_MODEL. - (add_jump_dependencies): Update call to dep_list_size. - (haifa_finish_h_i_d): Fix leak of max_reg_pressure. - (haifa_init_insn): Extend INSN_REG_PRESSURE_EXCESS_COST_CHANGE handling - to SCHED_PRESSURE_MODEL. - * sched-deps.c (init_insn_reg_pressure_info): Likewise, but don't - allocate INSN_MAX_REG_PRESSURE for SCHED_PRESSURE_MODEL. - (sched_analyze_insn): Extend INSN_REG_PRESSURE_EXCESS_COST_CHANGE - handling to SCHED_PRESSURE_MODEL. - -2012-02-08 Richard Sandiford <richard.sandiford@linaro.org> - - gcc/ - * common.opt (fsched-pressure-algorithm=): New option. - * flag-types.h (sched_pressure_algorithm): New enum. - * sched-int.h (sched_pressure_p): Replace with... - (sched_pressure): ...this new variable. - * haifa-sched.c (sched_pressure_p): Replace with... - (sched_pressure): ...this new variable. - (sched_regno_pressure_class, rank_for_schedule, ready_sort) - (update_reg_and_insn_max_reg_pressure, schedule_insn) - (debug_ready_list, schedule_block, sched_init, sched_finish) - (fix_tick_ready, haifa_init_insn): Update accordingly. - * sched-deps.c (init_insn_reg_pressure_info): Likewise. - * sched-rgn.c (schedule_region): Likewise. - -2012-02-08 Richard Sandiford <richard.sandiford@linaro.org> - - gcc/ - Backport from mainline: - - 2011-04-01 Bernd Schmidt <bernds@codesourcery.com> - - * haifa-sched.c (prune_ready_list): New function, broken out of - schedule_block. - (schedule_block): Use it. - -=== modified file 'gcc/common.opt' ---- old/gcc/common.opt 2011-04-11 15:26:47 +0000 -+++ new/gcc/common.opt 2012-02-08 23:38:13 +0000 -@@ -1614,6 +1614,19 @@ - Common Report Var(flag_sched_pressure) Init(0) Optimization - Enable register pressure sensitive insn scheduling - -+fsched-pressure-algorithm= -+Common Joined RejectNegative Enum(sched_pressure_algorithm) Var(flag_sched_pressure_algorithm) Init(SCHED_PRESSURE_WEIGHTED) -+-fira-algorithm=[CB|priority] Set the used IRA algorithm -+ -+Enum -+Name(sched_pressure_algorithm) Type(enum sched_pressure_algorithm) UnknownError(unknown %<fsched-pressure%> algorithm %qs) -+ -+EnumValue -+Enum(sched_pressure_algorithm) String(weighted) Value(SCHED_PRESSURE_WEIGHTED) -+ -+EnumValue -+Enum(sched_pressure_algorithm) String(model) Value(SCHED_PRESSURE_MODEL) -+ - fsched-spec - Common Report Var(flag_schedule_speculative) Init(1) Optimization - Allow speculative motion of non-loads - -=== modified file 'gcc/config/arm/arm.c' ---- old/gcc/config/arm/arm.c 2012-02-01 14:13:07 +0000 -+++ new/gcc/config/arm/arm.c 2012-02-09 00:47:59 +0000 -@@ -311,6 +311,11 @@ - /* Set default optimization options. */ - static const struct default_options arm_option_optimization_table[] = - { -+ /* Enable -fsched-pressure using -fsched-pressure-algorithm=model -+ by default when optimizing. */ -+ { OPT_LEVELS_1_PLUS, OPT_fsched_pressure, NULL, 1 }, -+ { OPT_LEVELS_1_PLUS, OPT_fsched_pressure_algorithm_, -+ NULL, SCHED_PRESSURE_MODEL }, - /* Enable section anchors by default at -O1 or higher. */ - { OPT_LEVELS_1_PLUS, OPT_fsection_anchors, NULL, 1 }, - { OPT_LEVELS_1_PLUS, OPT_fomit_frame_pointer, NULL, 1 }, - -=== modified file 'gcc/flag-types.h' ---- old/gcc/flag-types.h 2010-11-24 13:28:38 +0000 -+++ new/gcc/flag-types.h 2012-02-08 23:38:13 +0000 -@@ -106,6 +106,14 @@ - }; - #endif - -+/* The algorithm used to implement -fsched-pressure. */ -+enum sched_pressure_algorithm -+{ -+ SCHED_PRESSURE_NONE, -+ SCHED_PRESSURE_WEIGHTED, -+ SCHED_PRESSURE_MODEL -+}; -+ - /* The algorithm used for the integrated register allocator (IRA). */ - enum ira_algorithm - { - -=== modified file 'gcc/haifa-sched.c' ---- old/gcc/haifa-sched.c 2011-02-19 20:59:23 +0000 -+++ new/gcc/haifa-sched.c 2012-02-08 23:39:02 +0000 -@@ -348,6 +348,14 @@ - /* Create empty basic block after the specified block. */ - basic_block (* sched_create_empty_bb) (basic_block); - -+/* Return the number of cycles until INSN is expected to be ready. -+ Return zero if it already is. */ -+static int -+insn_delay (rtx insn) -+{ -+ return MAX (INSN_TICK (insn) - clock_var, 0); -+} -+ - static int - may_trap_exp (const_rtx x, int is_store) - { -@@ -571,10 +579,10 @@ - - /* Do register pressure sensitive insn scheduling if the flag is set - up. */ --bool sched_pressure_p; -+enum sched_pressure_algorithm sched_pressure; - - /* Map regno -> its cover class. The map defined only when -- SCHED_PRESSURE_P is true. */ -+ SCHED_PRESSURE != SCHED_PRESSURE_NONE. */ - enum reg_class *sched_regno_cover_class; - - /* The current register pressure. Only elements corresponding cover -@@ -602,10 +610,12 @@ - bitmap_clear (region_ref_regs); - } - --/* Update current register pressure related info after birth (if -- BIRTH_P) or death of register REGNO. */ --static void --mark_regno_birth_or_death (int regno, bool birth_p) -+/* PRESSURE[CL] describes the pressure on register class CL. Update it -+ for the birth (if BIRTH_P) or death (if !BIRTH_P) of register REGNO. -+ LIVE tracks the set of live registers; if it is null, assume that -+ every birth or death is genuine. */ -+static inline void -+mark_regno_birth_or_death (bitmap live, int *pressure, int regno, bool birth_p) - { - enum reg_class cover_class; - -@@ -616,15 +626,17 @@ - { - if (birth_p) - { -- bitmap_set_bit (curr_reg_live, regno); -- curr_reg_pressure[cover_class] -- += ira_reg_class_nregs[cover_class][PSEUDO_REGNO_MODE (regno)]; -+ if (!live || bitmap_set_bit (live, regno)) -+ pressure[cover_class] -+ += (ira_reg_class_nregs -+ [cover_class][PSEUDO_REGNO_MODE (regno)]); - } - else - { -- bitmap_clear_bit (curr_reg_live, regno); -- curr_reg_pressure[cover_class] -- -= ira_reg_class_nregs[cover_class][PSEUDO_REGNO_MODE (regno)]; -+ if (!live || bitmap_clear_bit (live, regno)) -+ pressure[cover_class] -+ -= (ira_reg_class_nregs -+ [cover_class][PSEUDO_REGNO_MODE (regno)]); - } - } - } -@@ -633,13 +645,13 @@ - { - if (birth_p) - { -- bitmap_set_bit (curr_reg_live, regno); -- curr_reg_pressure[cover_class]++; -+ if (!live || bitmap_set_bit (live, regno)) -+ pressure[cover_class]++; - } - else - { -- bitmap_clear_bit (curr_reg_live, regno); -- curr_reg_pressure[cover_class]--; -+ if (!live || bitmap_clear_bit (live, regno)) -+ pressure[cover_class]--; - } - } - } -@@ -657,8 +669,10 @@ - curr_reg_pressure[ira_reg_class_cover[i]] = 0; - bitmap_clear (curr_reg_live); - EXECUTE_IF_SET_IN_BITMAP (live, 0, j, bi) -- if (current_nr_blocks == 1 || bitmap_bit_p (region_ref_regs, j)) -- mark_regno_birth_or_death (j, true); -+ if (sched_pressure == SCHED_PRESSURE_MODEL -+ || current_nr_blocks == 1 -+ || bitmap_bit_p (region_ref_regs, j)) -+ mark_regno_birth_or_death (curr_reg_live, curr_reg_pressure, j, true); - } - - /* Mark registers in X as mentioned in the current region. */ -@@ -712,7 +726,8 @@ - if (regno == INVALID_REGNUM) - break; - if (! bitmap_bit_p (df_get_live_in (bb), regno)) -- mark_regno_birth_or_death (regno, true); -+ mark_regno_birth_or_death (curr_reg_live, curr_reg_pressure, -+ regno, true); - } - #endif - } -@@ -956,19 +971,19 @@ - return true; - } - --/* Compute the number of nondebug forward deps of an insn. */ -+/* Compute the number of nondebug deps in list LIST for INSN. */ - - static int --dep_list_size (rtx insn) -+dep_list_size (rtx insn, sd_list_types_def list) - { - sd_iterator_def sd_it; - dep_t dep; - int dbgcount = 0, nodbgcount = 0; - - if (!MAY_HAVE_DEBUG_INSNS) -- return sd_lists_size (insn, SD_LIST_FORW); -+ return sd_lists_size (insn, list); - -- FOR_EACH_DEP (insn, SD_LIST_FORW, sd_it, dep) -+ FOR_EACH_DEP (insn, list, sd_it, dep) - { - if (DEBUG_INSN_P (DEP_CON (dep))) - dbgcount++; -@@ -976,7 +991,7 @@ - nodbgcount++; - } - -- gcc_assert (dbgcount + nodbgcount == sd_lists_size (insn, SD_LIST_FORW)); -+ gcc_assert (dbgcount + nodbgcount == sd_lists_size (insn, list)); - - return nodbgcount; - } -@@ -995,7 +1010,7 @@ - { - int this_priority = -1; - -- if (dep_list_size (insn) == 0) -+ if (dep_list_size (insn, SD_LIST_FORW) == 0) - /* ??? We should set INSN_PRIORITY to insn_cost when and insn has - some forward deps but all of them are ignored by - contributes_to_priority hook. At the moment we set priority of -@@ -1091,6 +1106,22 @@ - qsort (READY, N_READY, sizeof (rtx), rank_for_schedule); } \ - while (0) - -+/* For each cover class CL, set DEATH[CL] to the number of registers -+ in that class that die in INSN. */ -+ -+static void -+calculate_reg_deaths (rtx insn, int *death) -+{ -+ int i; -+ struct reg_use_data *use; -+ -+ for (i = 0; i < ira_reg_class_cover_size; i++) -+ death[ira_reg_class_cover[i]] = 0; -+ for (use = INSN_REG_USE_LIST (insn); use != NULL; use = use->next_insn_use) -+ if (dying_use_p (use)) -+ mark_regno_birth_or_death (0, death, use->regno, true); -+} -+ - /* Setup info about the current register pressure impact of scheduling - INSN at the current scheduling point. */ - static void -@@ -1102,23 +1133,12 @@ - enum reg_class cl; - struct reg_pressure_data *pressure_info; - int *max_reg_pressure; -- struct reg_use_data *use; - static int death[N_REG_CLASSES]; - - gcc_checking_assert (!DEBUG_INSN_P (insn)); - - excess_cost_change = 0; -- for (i = 0; i < ira_reg_class_cover_size; i++) -- death[ira_reg_class_cover[i]] = 0; -- for (use = INSN_REG_USE_LIST (insn); use != NULL; use = use->next_insn_use) -- if (dying_use_p (use)) -- { -- cl = sched_regno_cover_class[use->regno]; -- if (use->regno < FIRST_PSEUDO_REGISTER) -- death[cl]++; -- else -- death[cl] += ira_reg_class_nregs[cl][PSEUDO_REGNO_MODE (use->regno)]; -- } -+ calculate_reg_deaths (insn, death); - pressure_info = INSN_REG_PRESSURE (insn); - max_reg_pressure = INSN_MAX_REG_PRESSURE (insn); - gcc_assert (pressure_info != NULL && max_reg_pressure != NULL); -@@ -1139,7 +1159,765 @@ - } - INSN_REG_PRESSURE_EXCESS_COST_CHANGE (insn) = excess_cost_change; - } -- -+ -+/* This is the first page of code related to SCHED_PRESSURE_MODEL. -+ It tries to make the scheduler take register pressure into account -+ without introducing too many unnecessary stalls. It hooks into the -+ main scheduling algorithm at several points: -+ -+ - Before scheduling starts, model_start_schedule constructs a -+ "model schedule" for the current block. This model schedule is -+ chosen solely to keep register pressure down. It does not take the -+ target's pipeline or the original instruction order into account, -+ except as a tie-breaker. It also doesn't work to a particular -+ pressure limit. -+ -+ This model schedule gives us an idea of what pressure can be -+ achieved for the block gives us an example of a schedule that -+ keeps to that pressure. It also makes the final schedule less -+ dependent on the original instruction order. This is important -+ because the original order can either be "wide" (many values live -+ at once, such as in user-scheduled code) or "narrow" (few values -+ live at once, such as after loop unrolling, where several -+ iterations are executed sequentially). -+ -+ We do not apply this model schedule to the rtx stream. We simply -+ record it in model_schedule. We also compute the maximum pressure, -+ MP, that was seen during this schedule. -+ -+ - Instructions are added to the ready queue even if they require -+ a stall. The length of the stall is instead computed as: -+ -+ MAX (INSN_TICK (INSN) - clock_var, 0) -+ -+ (= insn_delay). This allows rank_for_schedule to choose between -+ introducing a deliberate stall or increasing pressure. -+ -+ - Before sorting the ready queue, model_set_excess_costs assigns -+ a pressure-based cost to each ready instruction in the queue. -+ This is the instruction's INSN_REG_PRESSURE_EXCESS_COST_CHANGE -+ (ECC for short) and is effectively measured in cycles. -+ -+ - rank_for_schedule ranks instructions based on: -+ -+ ECC (insn) + insn_delay (insn) -+ -+ then as: -+ -+ insn_delay (insn) -+ -+ So, for example, an instruction X1 with an ECC of 1 that can issue -+ now will win over an instruction X0 with an ECC of zero that would -+ introduce a stall of one cycle. However, an instruction X2 with an -+ ECC of 2 that can issue now will lose to X0. -+ -+ - When an instruction is scheduled, model_recompute updates the model -+ schedule with the new pressures (some of which might now exceed the -+ original maximum pressure MP). model_update_limit_points then searches -+ for the new point of maximum pressure, if not already known. */ -+ -+/* Used to separate high-verbosity debug information for SCHED_PRESSURE_MODEL -+ from surrounding debug information. */ -+#define MODEL_BAR \ -+ ";;\t\t+------------------------------------------------------\n" -+ -+/* Information about the pressure on a particular register class at a -+ particular point of the model schedule. */ -+struct model_pressure_data { -+ /* The pressure at this point of the model schedule, or -1 if the -+ point is associated with an instruction that has already been -+ scheduled. */ -+ int ref_pressure; -+ -+ /* The maximum pressure during or after this point of the model schedule. */ -+ int max_pressure; -+}; -+ -+/* Per-instruction information that is used while building the model -+ schedule. Here, "schedule" refers to the model schedule rather -+ than the main schedule. */ -+struct model_insn_info { -+ /* The instruction itself. */ -+ rtx insn; -+ -+ /* If this instruction is in model_worklist, these fields link to the -+ previous (higher-priority) and next (lower-priority) instructions -+ in the list. */ -+ struct model_insn_info *prev; -+ struct model_insn_info *next; -+ -+ /* While constructing the schedule, QUEUE_INDEX describes whether an -+ instruction has already been added to the schedule (QUEUE_SCHEDULED), -+ is in model_worklist (QUEUE_READY), or neither (QUEUE_NOWHERE). -+ old_queue records the value that QUEUE_INDEX had before scheduling -+ started, so that we can restore it once the schedule is complete. */ -+ int old_queue; -+ -+ /* The relative importance of an unscheduled instruction. Higher -+ values indicate greater importance. */ -+ unsigned int model_priority; -+ -+ /* The length of the longest path of satisfied true dependencies -+ that leads to this instruction. */ -+ unsigned int depth; -+ -+ /* The length of the longest path of dependencies of any kind -+ that leads from this instruction. */ -+ unsigned int alap; -+ -+ /* The number of predecessor nodes that must still be scheduled. */ -+ int unscheduled_preds; -+}; -+ -+/* Information about the pressure limit for a particular register class. -+ This structure is used when applying a model schedule to the main -+ schedule. */ -+struct model_pressure_limit { -+ /* The maximum register pressure seen in the original model schedule. */ -+ int orig_pressure; -+ -+ /* The maximum register pressure seen in the current model schedule -+ (which excludes instructions that have already been scheduled). */ -+ int pressure; -+ -+ /* The point of the current model schedule at which PRESSURE is first -+ reached. It is set to -1 if the value needs to be recomputed. */ -+ int point; -+}; -+ -+/* Describes a particular way of measuring register pressure. */ -+struct model_pressure_group { -+ /* Index CCI describes the maximum pressure on ira_reg_class_cover[CCI]. */ -+ struct model_pressure_limit limits[N_REG_CLASSES]; -+ -+ /* Index (POINT * ira_num_pressure_classes + CCI) describes the pressure -+ on register class ira_reg_class_cover[CCI] at point POINT of the -+ current model schedule. A POINT of model_num_insns describes the -+ pressure at the end of the schedule. */ -+ struct model_pressure_data *model; -+}; -+ -+/* Index POINT gives the instruction at point POINT of the model schedule. -+ This array doesn't change during main scheduling. */ -+static VEC (rtx, heap) *model_schedule; -+ -+/* The list of instructions in the model worklist, sorted in order of -+ decreasing priority. */ -+static struct model_insn_info *model_worklist; -+ -+/* Index I describes the instruction with INSN_LUID I. */ -+static struct model_insn_info *model_insns; -+ -+/* The number of instructions in the model schedule. */ -+static int model_num_insns; -+ -+/* The index of the first instruction in model_schedule that hasn't yet been -+ added to the main schedule, or model_num_insns if all of them have. */ -+static int model_curr_point; -+ -+/* Describes the pressure before each instruction in the model schedule. */ -+static struct model_pressure_group model_before_pressure; -+ -+/* The first unused model_priority value (as used in model_insn_info). */ -+static unsigned int model_next_priority; -+ -+ -+/* The model_pressure_data for ira_reg_class_cover[CCI] in GROUP -+ at point POINT of the model schedule. */ -+#define MODEL_PRESSURE_DATA(GROUP, POINT, CCI) \ -+ (&(GROUP)->model[(POINT) * ira_reg_class_cover_size + (CCI)]) -+ -+/* The maximum pressure on ira_reg_class_cover[CCI] in GROUP at or -+ after point POINT of the model schedule. */ -+#define MODEL_MAX_PRESSURE(GROUP, POINT, CCI) \ -+ (MODEL_PRESSURE_DATA (GROUP, POINT, CCI)->max_pressure) -+ -+/* The pressure on ira_reg_class_cover[CCI] in GROUP at point POINT -+ of the model schedule. */ -+#define MODEL_REF_PRESSURE(GROUP, POINT, CCI) \ -+ (MODEL_PRESSURE_DATA (GROUP, POINT, CCI)->ref_pressure) -+ -+/* Information about INSN that is used when creating the model schedule. */ -+#define MODEL_INSN_INFO(INSN) \ -+ (&model_insns[INSN_LUID (INSN)]) -+ -+/* The instruction at point POINT of the model schedule. */ -+#define MODEL_INSN(POINT) \ -+ (VEC_index (rtx, model_schedule, POINT)) -+ -+ -+/* Return INSN's index in the model schedule, or model_num_insns if it -+ doesn't belong to that schedule. */ -+ -+static int -+model_index (rtx insn) -+{ -+ if (INSN_MODEL_INDEX (insn) == 0) -+ return model_num_insns; -+ return INSN_MODEL_INDEX (insn) - 1; -+} -+ -+/* Make sure that GROUP->limits is up-to-date for the current point -+ of the model schedule. */ -+ -+static void -+model_update_limit_points_in_group (struct model_pressure_group *group) -+{ -+ int cci, max_pressure, point; -+ -+ for (cci = 0; cci < ira_reg_class_cover_size; cci++) -+ { -+ /* We may have passed the final point at which the pressure in -+ group->limits[cci].pressure was reached. Update the limit if so. */ -+ max_pressure = MODEL_MAX_PRESSURE (group, model_curr_point, cci); -+ group->limits[cci].pressure = max_pressure; -+ -+ /* Find the point at which MAX_PRESSURE is first reached. We need -+ to search in three cases: -+ -+ - We've already moved past the previous pressure point. -+ In this case we search forward from model_curr_point. -+ -+ - We scheduled the previous point of maximum pressure ahead of -+ its position in the model schedule, but doing so didn't bring -+ the pressure point earlier. In this case we search forward -+ from that previous pressure point. -+ -+ - Scheduling an instruction early caused the maximum pressure -+ to decrease. In this case we will have set the pressure -+ point to -1, and we search forward from model_curr_point. */ -+ point = MAX (group->limits[cci].point, model_curr_point); -+ while (point < model_num_insns -+ && MODEL_REF_PRESSURE (group, point, cci) < max_pressure) -+ point++; -+ group->limits[cci].point = point; -+ -+ gcc_assert (MODEL_REF_PRESSURE (group, point, cci) == max_pressure); -+ gcc_assert (MODEL_MAX_PRESSURE (group, point, cci) == max_pressure); -+ } -+} -+ -+/* Make sure that all register-pressure limits are up-to-date for the -+ current position in the model schedule. */ -+ -+static void -+model_update_limit_points (void) -+{ -+ model_update_limit_points_in_group (&model_before_pressure); -+} -+ -+/* Return the model_index of the last unscheduled use in chain USE -+ outside of USE's instruction. Return -1 if there are no other uses, -+ or model_num_insns if the register is live at the end of the block. */ -+ -+static int -+model_last_use_except (struct reg_use_data *use) -+{ -+ struct reg_use_data *next; -+ int last, index; -+ -+ last = -1; -+ for (next = use->next_regno_use; next != use; next = next->next_regno_use) -+ if (NONDEBUG_INSN_P (next->insn) -+ && QUEUE_INDEX (next->insn) != QUEUE_SCHEDULED) -+ { -+ index = model_index (next->insn); -+ if (index == model_num_insns) -+ return model_num_insns; -+ if (last < index) -+ last = index; -+ } -+ return last; -+} -+ -+/* An instruction with model_index POINT has just been scheduled, and it -+ adds DELTA to the pressure on ira_reg_class_cover[CCI] after POINT - 1. -+ Update MODEL_REF_PRESSURE (GROUP, POINT, CCI) and -+ MODEL_MAX_PRESSURE (GROUP, POINT, CCI) accordingly. */ -+ -+static void -+model_start_update_pressure (struct model_pressure_group *group, -+ int point, int cci, int delta) -+{ -+ int next_max_pressure; -+ -+ if (point == model_num_insns) -+ { -+ /* The instruction wasn't part of the model schedule; it was moved -+ from a different block. Update the pressure for the end of -+ the model schedule. */ -+ MODEL_REF_PRESSURE (group, point, cci) += delta; -+ MODEL_MAX_PRESSURE (group, point, cci) += delta; -+ } -+ else -+ { -+ /* Record that this instruction has been scheduled. Nothing now -+ changes between POINT and POINT + 1, so get the maximum pressure -+ from the latter. If the maximum pressure decreases, the new -+ pressure point may be before POINT. */ -+ MODEL_REF_PRESSURE (group, point, cci) = -1; -+ next_max_pressure = MODEL_MAX_PRESSURE (group, point + 1, cci); -+ if (MODEL_MAX_PRESSURE (group, point, cci) > next_max_pressure) -+ { -+ MODEL_MAX_PRESSURE (group, point, cci) = next_max_pressure; -+ if (group->limits[cci].point == point) -+ group->limits[cci].point = -1; -+ } -+ } -+} -+ -+/* Record that scheduling a later instruction has changed the pressure -+ at point POINT of the model schedule by DELTA (which might be 0). -+ Update GROUP accordingly. Return nonzero if these changes might -+ trigger changes to previous points as well. */ -+ -+static int -+model_update_pressure (struct model_pressure_group *group, -+ int point, int cci, int delta) -+{ -+ int ref_pressure, max_pressure, next_max_pressure; -+ -+ /* If POINT hasn't yet been scheduled, update its pressure. */ -+ ref_pressure = MODEL_REF_PRESSURE (group, point, cci); -+ if (ref_pressure >= 0 && delta != 0) -+ { -+ ref_pressure += delta; -+ MODEL_REF_PRESSURE (group, point, cci) = ref_pressure; -+ -+ /* Check whether the maximum pressure in the overall schedule -+ has increased. (This means that the MODEL_MAX_PRESSURE of -+ every point <= POINT will need to increae too; see below.) */ -+ if (group->limits[cci].pressure < ref_pressure) -+ group->limits[cci].pressure = ref_pressure; -+ -+ /* If we are at maximum pressure, and the maximum pressure -+ point was previously unknown or later than POINT, -+ bring it forward. */ -+ if (group->limits[cci].pressure == ref_pressure -+ && !IN_RANGE (group->limits[cci].point, 0, point)) -+ group->limits[cci].point = point; -+ -+ /* If POINT used to be the point of maximum pressure, but isn't -+ any longer, we need to recalculate it using a forward walk. */ -+ if (group->limits[cci].pressure > ref_pressure -+ && group->limits[cci].point == point) -+ group->limits[cci].point = -1; -+ } -+ -+ /* Update the maximum pressure at POINT. Changes here might also -+ affect the maximum pressure at POINT - 1. */ -+ next_max_pressure = MODEL_MAX_PRESSURE (group, point + 1, cci); -+ max_pressure = MAX (ref_pressure, next_max_pressure); -+ if (MODEL_MAX_PRESSURE (group, point, cci) != max_pressure) -+ { -+ MODEL_MAX_PRESSURE (group, point, cci) = max_pressure; -+ return 1; -+ } -+ return 0; -+} -+ -+/* INSN has just been scheduled. Update the model schedule accordingly. */ -+ -+static void -+model_recompute (rtx insn) -+{ -+ struct { -+ int last_use; -+ int regno; -+ } uses[FIRST_PSEUDO_REGISTER + MAX_RECOG_OPERANDS]; -+ struct reg_use_data *use; -+ struct reg_pressure_data *reg_pressure; -+ int delta[N_REG_CLASSES]; -+ int cci, point, mix, new_last, cl, ref_pressure, queue; -+ unsigned int i, num_uses, num_pending_births; -+ bool print_p; -+ -+ /* The destinations of INSN were previously live from POINT onwards, but are -+ now live from model_curr_point onwards. Set up DELTA accordingly. */ -+ point = model_index (insn); -+ reg_pressure = INSN_REG_PRESSURE (insn); -+ for (cci = 0; cci < ira_reg_class_cover_size; cci++) -+ { -+ cl = ira_reg_class_cover[cci]; -+ delta[cl] = reg_pressure[cci].set_increase; -+ } -+ -+ /* Record which registers previously died at POINT, but which now die -+ before POINT. Adjust DELTA so that it represents the effect of -+ this change after POINT - 1. Set NUM_PENDING_BIRTHS to the number of -+ registers that will be born in the range [model_curr_point, POINT). */ -+ num_uses = 0; -+ num_pending_births = 0; -+ for (use = INSN_REG_USE_LIST (insn); use != NULL; use = use->next_insn_use) -+ { -+ new_last = model_last_use_except (use); -+ if (new_last < point) -+ { -+ gcc_assert (num_uses < ARRAY_SIZE (uses)); -+ uses[num_uses].last_use = new_last; -+ uses[num_uses].regno = use->regno; -+ /* This register is no longer live after POINT - 1. */ -+ mark_regno_birth_or_death (NULL, delta, use->regno, false); -+ num_uses++; -+ if (new_last >= 0) -+ num_pending_births++; -+ } -+ } -+ -+ /* Update the MODEL_REF_PRESSURE and MODEL_MAX_PRESSURE for POINT. -+ Also set each group pressure limit for POINT. */ -+ for (cci = 0; cci < ira_reg_class_cover_size; cci++) -+ { -+ cl = ira_reg_class_cover[cci]; -+ model_start_update_pressure (&model_before_pressure, -+ point, cci, delta[cl]); -+ } -+ -+ /* Walk the model schedule backwards, starting immediately before POINT. */ -+ print_p = false; -+ if (point != model_curr_point) -+ do -+ { -+ point--; -+ insn = MODEL_INSN (point); -+ queue = QUEUE_INDEX (insn); -+ -+ if (queue != QUEUE_SCHEDULED) -+ { -+ /* DELTA describes the effect of the move on the register pressure -+ after POINT. Make it describe the effect on the pressure -+ before POINT. */ -+ i = 0; -+ while (i < num_uses) -+ { -+ if (uses[i].last_use == point) -+ { -+ /* This register is now live again. */ -+ mark_regno_birth_or_death (NULL, delta, -+ uses[i].regno, true); -+ -+ /* Remove this use from the array. */ -+ uses[i] = uses[num_uses - 1]; -+ num_uses--; -+ num_pending_births--; -+ } -+ else -+ i++; -+ } -+ -+ if (sched_verbose >= 5) -+ { -+ char buf[2048]; -+ -+ if (!print_p) -+ { -+ fprintf (sched_dump, MODEL_BAR); -+ fprintf (sched_dump, ";;\t\t| New pressure for model" -+ " schedule\n"); -+ fprintf (sched_dump, MODEL_BAR); -+ print_p = true; -+ } -+ -+ print_pattern (buf, PATTERN (insn), 0); -+ fprintf (sched_dump, ";;\t\t| %3d %4d %-30s ", -+ point, INSN_UID (insn), buf); -+ for (cci = 0; cci < ira_reg_class_cover_size; cci++) -+ { -+ cl = ira_reg_class_cover[cci]; -+ ref_pressure = MODEL_REF_PRESSURE (&model_before_pressure, -+ point, cci); -+ fprintf (sched_dump, " %s:[%d->%d]", -+ reg_class_names[ira_reg_class_cover[cci]], -+ ref_pressure, ref_pressure + delta[cl]); -+ } -+ fprintf (sched_dump, "\n"); -+ } -+ } -+ -+ /* Adjust the pressure at POINT. Set MIX to nonzero if POINT - 1 -+ might have changed as well. */ -+ mix = num_pending_births; -+ for (cci = 0; cci < ira_reg_class_cover_size; cci++) -+ { -+ cl = ira_reg_class_cover[cci]; -+ mix |= delta[cl]; -+ mix |= model_update_pressure (&model_before_pressure, -+ point, cci, delta[cl]); -+ } -+ } -+ while (mix && point > model_curr_point); -+ -+ if (print_p) -+ fprintf (sched_dump, MODEL_BAR); -+} -+ -+/* model_spill_cost (CL, P, P') returns the cost of increasing the -+ pressure on CL from P to P'. We use this to calculate a "base ECC", -+ baseECC (CL, X), for each cover class CL and each instruction X. -+ Supposing X changes the pressure on CL from P to P', and that the -+ maximum pressure on CL in the current model schedule is MP', then: -+ -+ * if X occurs before or at the next point of maximum pressure in -+ the model schedule and P' > MP', then: -+ -+ baseECC (CL, X) = model_spill_cost (CL, MP, P') -+ -+ The idea is that the pressure after scheduling a fixed set of -+ instructions -- in this case, the set up to and including the -+ next maximum pressure point -- is going to be the same regardless -+ of the order; we simply want to keep the intermediate pressure -+ under control. Thus X has a cost of zero unless scheduling it -+ now would exceed MP'. -+ -+ If all increases in the set are by the same amount, no zero-cost -+ instruction will ever cause the pressure to exceed MP'. However, -+ if X is instead moved past an instruction X' with pressure in the -+ range (MP' - (P' - P), MP'), the pressure at X' will increase -+ beyond MP'. Since baseECC is very much a heuristic anyway, -+ it doesn't seem worth the overhead of tracking cases like these. -+ -+ The cost of exceeding MP' is always based on the original maximum -+ pressure MP. This is so that going 2 registers over the original -+ limit has the same cost regardless of whether it comes from two -+ separate +1 deltas or from a single +2 delta. -+ -+ * if X occurs after the next point of maximum pressure in the model -+ schedule and P' > P, then: -+ -+ baseECC (CL, X) = model_spill_cost (CL, MP, MP' + (P' - P)) -+ -+ That is, if we move X forward across a point of maximum pressure, -+ and if X increases the pressure by P' - P, then we conservatively -+ assume that scheduling X next would increase the maximum pressure -+ by P' - P. Again, the cost of doing this is based on the original -+ maximum pressure MP, for the same reason as above. -+ -+ * if P' < P, P > MP, and X occurs at or after the next point of -+ maximum pressure, then: -+ -+ baseECC (CL, X) = -model_spill_cost (CL, MAX (MP, P'), P) -+ -+ That is, if we have already exceeded the original maximum pressure MP, -+ and if X might reduce the maximum pressure again -- or at least push -+ it further back, and thus allow more scheduling freedom -- it is given -+ a negative cost to reflect the improvement. -+ -+ * otherwise, -+ -+ baseECC (CL, X) = 0 -+ -+ In this case, X is not expected to affect the maximum pressure MP', -+ so it has zero cost. -+ -+ We then create a combined value baseECC (X) that is the sum of -+ baseECC (CL, X) for each cover class CL. -+ -+ baseECC (X) could itself be used as the ECC value described above. -+ However, this is often too conservative, in the sense that it -+ tends to make high-priority instructions that increase pressure -+ wait too long in cases where introducing a spill would be better. -+ For this reason the final ECC is a priority-adjusted form of -+ baseECC (X). Specifically, we calculate: -+ -+ P (X) = INSN_PRIORITY (X) - insn_delay (X) - baseECC (X) -+ baseP = MAX { P (X) | baseECC (X) <= 0 } -+ -+ Then: -+ -+ ECC (X) = MAX (MIN (baseP - P (X), baseECC (X)), 0) -+ -+ Thus an instruction's effect on pressure is ignored if it has a high -+ enough priority relative to the ones that don't increase pressure. -+ Negative values of baseECC (X) do not increase the priority of X -+ itself, but they do make it harder for other instructions to -+ increase the pressure further. -+ -+ This pressure cost is deliberately timid. The intention has been -+ to choose a heuristic that rarely interferes with the normal list -+ scheduler in cases where that scheduler would produce good code. -+ We simply want to curb some of its worst excesses. */ -+ -+/* Return the cost of increasing the pressure in class CL from FROM to TO. -+ -+ Here we use the very simplistic cost model that every register above -+ ira_available_class_regs[CL] has a spill cost of 1. We could use other -+ measures instead, such as one based on MEMORY_MOVE_COST. However: -+ -+ (1) In order for an instruction to be scheduled, the higher cost -+ would need to be justified in a single saving of that many stalls. -+ This is overly pessimistic, because the benefit of spilling is -+ often to avoid a sequence of several short stalls rather than -+ a single long one. -+ -+ (2) The cost is still arbitrary. Because we are not allocating -+ registers during scheduling, we have no way of knowing for -+ sure how many memory accesses will be required by each spill, -+ where the spills will be placed within the block, or even -+ which block(s) will contain the spills. -+ -+ So a higher cost than 1 is often too conservative in practice, -+ forcing blocks to contain unnecessary stalls instead of spill code. -+ The simple cost below seems to be the best compromise. It reduces -+ the interference with the normal list scheduler, which helps make -+ it more suitable for a default-on option. */ -+ -+static int -+model_spill_cost (int cl, int from, int to) -+{ -+ from = MAX (from, ira_available_class_regs[cl]); -+ return MAX (to, from) - from; -+} -+ -+/* Return baseECC (ira_reg_class_cover[CCI], POINT), given that -+ P = curr_reg_pressure[ira_reg_class_cover[CCI]] and that -+ P' = P + DELTA. */ -+ -+static int -+model_excess_group_cost (struct model_pressure_group *group, -+ int point, int cci, int delta) -+{ -+ int pressure, cl; -+ -+ cl = ira_reg_class_cover[cci]; -+ if (delta < 0 && point >= group->limits[cci].point) -+ { -+ pressure = MAX (group->limits[cci].orig_pressure, -+ curr_reg_pressure[cl] + delta); -+ return -model_spill_cost (cl, pressure, curr_reg_pressure[cl]); -+ } -+ -+ if (delta > 0) -+ { -+ if (point > group->limits[cci].point) -+ pressure = group->limits[cci].pressure + delta; -+ else -+ pressure = curr_reg_pressure[cl] + delta; -+ -+ if (pressure > group->limits[cci].pressure) -+ return model_spill_cost (cl, group->limits[cci].orig_pressure, -+ pressure); -+ } -+ -+ return 0; -+} -+ -+/* Return baseECC (MODEL_INSN (INSN)). Dump the costs to sched_dump -+ if PRINT_P. */ -+ -+static int -+model_excess_cost (rtx insn, bool print_p) -+{ -+ int point, cci, cl, cost, this_cost, delta; -+ struct reg_pressure_data *insn_reg_pressure; -+ int insn_death[N_REG_CLASSES]; -+ -+ calculate_reg_deaths (insn, insn_death); -+ point = model_index (insn); -+ insn_reg_pressure = INSN_REG_PRESSURE (insn); -+ cost = 0; -+ -+ if (print_p) -+ fprintf (sched_dump, ";;\t\t| %3d %4d | %4d %+3d |", point, -+ INSN_UID (insn), INSN_PRIORITY (insn), insn_delay (insn)); -+ -+ /* Sum up the individual costs for each register class. */ -+ for (cci = 0; cci < ira_reg_class_cover_size; cci++) -+ { -+ cl = ira_reg_class_cover[cci]; -+ delta = insn_reg_pressure[cci].set_increase - insn_death[cl]; -+ this_cost = model_excess_group_cost (&model_before_pressure, -+ point, cci, delta); -+ cost += this_cost; -+ if (print_p) -+ fprintf (sched_dump, " %s:[%d base cost %d]", -+ reg_class_names[cl], delta, this_cost); -+ } -+ -+ if (print_p) -+ fprintf (sched_dump, "\n"); -+ -+ return cost; -+} -+ -+/* Dump the next points of maximum pressure for GROUP. */ -+ -+static void -+model_dump_pressure_points (struct model_pressure_group *group) -+{ -+ int cci, cl; -+ -+ fprintf (sched_dump, ";;\t\t| pressure points"); -+ for (cci = 0; cci < ira_reg_class_cover_size; cci++) -+ { -+ cl = ira_reg_class_cover[cci]; -+ fprintf (sched_dump, " %s:[%d->%d at ", reg_class_names[cl], -+ curr_reg_pressure[cl], group->limits[cci].pressure); -+ if (group->limits[cci].point < model_num_insns) -+ fprintf (sched_dump, "%d:%d]", group->limits[cci].point, -+ INSN_UID (MODEL_INSN (group->limits[cci].point))); -+ else -+ fprintf (sched_dump, "end]"); -+ } -+ fprintf (sched_dump, "\n"); -+} -+ -+/* Set INSN_REG_PRESSURE_EXCESS_COST_CHANGE for INSNS[0...COUNT-1]. */ -+ -+static void -+model_set_excess_costs (rtx *insns, int count) -+{ -+ int i, cost, priority_base, priority; -+ bool print_p; -+ -+ /* Record the baseECC value for each instruction in the model schedule, -+ except that negative costs are converted to zero ones now rather thatn -+ later. Do not assign a cost to debug instructions, since they must -+ not change code-generation decisions. Experiments suggest we also -+ get better results by not assigning a cost to instructions from -+ a different block. -+ -+ Set PRIORITY_BASE to baseP in the block comment above. This is the -+ maximum priority of the "cheap" instructions, which should always -+ include the next model instruction. */ -+ priority_base = 0; -+ print_p = false; -+ for (i = 0; i < count; i++) -+ if (INSN_MODEL_INDEX (insns[i])) -+ { -+ if (sched_verbose >= 6 && !print_p) -+ { -+ fprintf (sched_dump, MODEL_BAR); -+ fprintf (sched_dump, ";;\t\t| Pressure costs for ready queue\n"); -+ model_dump_pressure_points (&model_before_pressure); -+ fprintf (sched_dump, MODEL_BAR); -+ print_p = true; -+ } -+ cost = model_excess_cost (insns[i], print_p); -+ if (cost <= 0) -+ { -+ priority = INSN_PRIORITY (insns[i]) - insn_delay (insns[i]) - cost; -+ priority_base = MAX (priority_base, priority); -+ cost = 0; -+ } -+ INSN_REG_PRESSURE_EXCESS_COST_CHANGE (insns[i]) = cost; -+ } -+ if (print_p) -+ fprintf (sched_dump, MODEL_BAR); -+ -+ /* Use MAX (baseECC, 0) and baseP to calculcate ECC for each -+ instruction. */ -+ for (i = 0; i < count; i++) -+ { -+ cost = INSN_REG_PRESSURE_EXCESS_COST_CHANGE (insns[i]); -+ priority = INSN_PRIORITY (insns[i]) - insn_delay (insns[i]); -+ if (cost > 0 && priority > priority_base) -+ { -+ cost += priority_base - priority; -+ INSN_REG_PRESSURE_EXCESS_COST_CHANGE (insns[i]) = MAX (cost, 0); -+ } -+ } -+} -+ - /* Returns a positive value if x is preferred; returns a negative value if - y is preferred. Should never return 0, since that will make the sort - unstable. */ -@@ -1170,23 +1948,20 @@ - /* Make sure that priority of TMP and TMP2 are initialized. */ - gcc_assert (INSN_PRIORITY_KNOWN (tmp) && INSN_PRIORITY_KNOWN (tmp2)); - -- if (sched_pressure_p) -+ if (sched_pressure != SCHED_PRESSURE_NONE) - { - int diff; - - /* Prefer insn whose scheduling results in the smallest register - pressure excess. */ - if ((diff = (INSN_REG_PRESSURE_EXCESS_COST_CHANGE (tmp) -- + (INSN_TICK (tmp) > clock_var -- ? INSN_TICK (tmp) - clock_var : 0) -+ + insn_delay (tmp) - - INSN_REG_PRESSURE_EXCESS_COST_CHANGE (tmp2) -- - (INSN_TICK (tmp2) > clock_var -- ? INSN_TICK (tmp2) - clock_var : 0))) != 0) -+ - insn_delay (tmp2)))) - return diff; - } - -- -- if (sched_pressure_p -+ if (sched_pressure != SCHED_PRESSURE_NONE - && (INSN_TICK (tmp2) > clock_var || INSN_TICK (tmp) > clock_var)) - { - if (INSN_TICK (tmp) <= clock_var) -@@ -1277,11 +2052,22 @@ - return val; - } - -+ /* Prefer instructions that occur earlier in the model schedule. */ -+ if (sched_pressure == SCHED_PRESSURE_MODEL) -+ { -+ int diff; -+ -+ diff = model_index (tmp) - model_index (tmp2); -+ if (diff != 0) -+ return diff; -+ } -+ - /* Prefer the insn which has more later insns that depend on it. - This gives the scheduler more freedom when scheduling later - instructions at the expense of added register pressure. */ - -- val = (dep_list_size (tmp2) - dep_list_size (tmp)); -+ val = (dep_list_size (tmp2, SD_LIST_FORW) -+ - dep_list_size (tmp, SD_LIST_FORW)); - - if (flag_sched_dep_count_heuristic && val != 0) - return val; -@@ -1480,12 +2266,15 @@ - int i; - rtx *first = ready_lastpos (ready); - -- if (sched_pressure_p) -+ if (sched_pressure == SCHED_PRESSURE_WEIGHTED) - { - for (i = 0; i < ready->n_ready; i++) - if (!DEBUG_INSN_P (first[i])) - setup_insn_reg_pressure_info (first[i]); - } -+ if (sched_pressure == SCHED_PRESSURE_MODEL -+ && model_curr_point < model_num_insns) -+ model_set_excess_costs (first, ready->n_ready); - SCHED_SORT (first, ready->n_ready); - } - -@@ -1551,10 +2340,12 @@ - gcc_checking_assert (!DEBUG_INSN_P (insn)); - - for (use = INSN_REG_USE_LIST (insn); use != NULL; use = use->next_insn_use) -- if (dying_use_p (use) && bitmap_bit_p (curr_reg_live, use->regno)) -- mark_regno_birth_or_death (use->regno, false); -+ if (dying_use_p (use)) -+ mark_regno_birth_or_death (curr_reg_live, curr_reg_pressure, -+ use->regno, false); - for (set = INSN_REG_SET_LIST (insn); set != NULL; set = set->next_insn_set) -- mark_regno_birth_or_death (set->regno, true); -+ mark_regno_birth_or_death (curr_reg_live, curr_reg_pressure, -+ set->regno, true); - } - - /* Set up or update (if UPDATE_P) max register pressure (see its -@@ -1626,11 +2417,618 @@ - void - sched_setup_bb_reg_pressure_info (basic_block bb, rtx after) - { -- gcc_assert (sched_pressure_p); -+ gcc_assert (sched_pressure == SCHED_PRESSURE_WEIGHTED); - initiate_bb_reg_pressure_info (bb); - setup_insn_max_reg_pressure (after, false); - } -- -+ -+/* Return (in order): -+ -+ - positive if INSN adversely affects the pressure on one -+ register class -+ -+ - negative if INSN reduces the pressure on one register class -+ -+ - 0 if INSN doesn't affect the pressure on any register class. */ -+ -+static int -+model_classify_pressure (struct model_insn_info *insn) -+{ -+ struct reg_pressure_data *reg_pressure; -+ int death[N_REG_CLASSES]; -+ int cci, cl, sum; -+ -+ calculate_reg_deaths (insn->insn, death); -+ reg_pressure = INSN_REG_PRESSURE (insn->insn); -+ sum = 0; -+ for (cci = 0; cci < ira_reg_class_cover_size; cci++) -+ { -+ cl = ira_reg_class_cover[cci]; -+ if (death[cl] < reg_pressure[cci].set_increase) -+ return 1; -+ sum += reg_pressure[cci].set_increase - death[cl]; -+ } -+ return sum; -+} -+ -+/* Return true if INSN1 should come before INSN2 in the model schedule. */ -+ -+static int -+model_order_p (struct model_insn_info *insn1, struct model_insn_info *insn2) -+{ -+ unsigned int height1, height2; -+ unsigned int priority1, priority2; -+ -+ /* Prefer instructions with a higher model priority. */ -+ if (insn1->model_priority != insn2->model_priority) -+ return insn1->model_priority > insn2->model_priority; -+ -+ /* Combine the length of the longest path of satisfied true dependencies -+ that leads to each instruction (depth) with the length of the longest -+ path of any dependencies that leads from the instruction (alap). -+ Prefer instructions with the greatest combined length. If the combined -+ lengths are equal, prefer instructions with the greatest depth. -+ -+ The idea is that, if we have a set S of "equal" instructions that each -+ have ALAP value X, and we pick one such instruction I, any true-dependent -+ successors of I that have ALAP value X - 1 should be preferred over S. -+ This encourages the schedule to be "narrow" rather than "wide". -+ However, if I is a low-priority instruction that we decided to -+ schedule because of its model_classify_pressure, and if there -+ is a set of higher-priority instructions T, the aforementioned -+ successors of I should not have the edge over T. */ -+ height1 = insn1->depth + insn1->alap; -+ height2 = insn2->depth + insn2->alap; -+ if (height1 != height2) -+ return height1 > height2; -+ if (insn1->depth != insn2->depth) -+ return insn1->depth > insn2->depth; -+ -+ /* We have no real preference between INSN1 an INSN2 as far as attempts -+ to reduce pressure go. Prefer instructions with higher priorities. */ -+ priority1 = INSN_PRIORITY (insn1->insn); -+ priority2 = INSN_PRIORITY (insn2->insn); -+ if (priority1 != priority2) -+ return priority1 > priority2; -+ -+ /* Use the original rtl sequence as a tie-breaker. */ -+ return insn1 < insn2; -+} -+ -+/* Add INSN to the model worklist immediately after PREV. Add it to the -+ beginning of the list if PREV is null. */ -+ -+static void -+model_add_to_worklist_at (struct model_insn_info *insn, -+ struct model_insn_info *prev) -+{ -+ gcc_assert (QUEUE_INDEX (insn->insn) == QUEUE_NOWHERE); -+ QUEUE_INDEX (insn->insn) = QUEUE_READY; -+ -+ insn->prev = prev; -+ if (prev) -+ { -+ insn->next = prev->next; -+ prev->next = insn; -+ } -+ else -+ { -+ insn->next = model_worklist; -+ model_worklist = insn; -+ } -+ if (insn->next) -+ insn->next->prev = insn; -+} -+ -+/* Remove INSN from the model worklist. */ -+ -+static void -+model_remove_from_worklist (struct model_insn_info *insn) -+{ -+ gcc_assert (QUEUE_INDEX (insn->insn) == QUEUE_READY); -+ QUEUE_INDEX (insn->insn) = QUEUE_NOWHERE; -+ -+ if (insn->prev) -+ insn->prev->next = insn->next; -+ else -+ model_worklist = insn->next; -+ if (insn->next) -+ insn->next->prev = insn->prev; -+} -+ -+/* Add INSN to the model worklist. Start looking for a suitable position -+ between neighbors PREV and NEXT, testing at most MAX_SCHED_READY_INSNS -+ insns either side. A null PREV indicates the beginning of the list and -+ a null NEXT indicates the end. */ -+ -+static void -+model_add_to_worklist (struct model_insn_info *insn, -+ struct model_insn_info *prev, -+ struct model_insn_info *next) -+{ -+ int count; -+ -+ count = MAX_SCHED_READY_INSNS; -+ if (count > 0 && prev && model_order_p (insn, prev)) -+ do -+ { -+ count--; -+ prev = prev->prev; -+ } -+ while (count > 0 && prev && model_order_p (insn, prev)); -+ else -+ while (count > 0 && next && model_order_p (next, insn)) -+ { -+ count--; -+ prev = next; -+ next = next->next; -+ } -+ model_add_to_worklist_at (insn, prev); -+} -+ -+/* INSN may now have a higher priority (in the model_order_p sense) -+ than before. Move it up the worklist if necessary. */ -+ -+static void -+model_promote_insn (struct model_insn_info *insn) -+{ -+ struct model_insn_info *prev; -+ int count; -+ -+ prev = insn->prev; -+ count = MAX_SCHED_READY_INSNS; -+ while (count > 0 && prev && model_order_p (insn, prev)) -+ { -+ count--; -+ prev = prev->prev; -+ } -+ if (prev != insn->prev) -+ { -+ model_remove_from_worklist (insn); -+ model_add_to_worklist_at (insn, prev); -+ } -+} -+ -+/* Add INSN to the end of the model schedule. */ -+ -+static void -+model_add_to_schedule (rtx insn) -+{ -+ unsigned int point; -+ -+ gcc_assert (QUEUE_INDEX (insn) == QUEUE_NOWHERE); -+ QUEUE_INDEX (insn) = QUEUE_SCHEDULED; -+ -+ point = VEC_length (rtx, model_schedule); -+ VEC_quick_push (rtx, model_schedule, insn); -+ INSN_MODEL_INDEX (insn) = point + 1; -+} -+ -+/* Analyze the instructions that are to be scheduled, setting up -+ MODEL_INSN_INFO (...) and model_num_insns accordingly. Add ready -+ instructions to model_worklist. */ -+ -+static void -+model_analyze_insns (void) -+{ -+ rtx start, end, iter; -+ sd_iterator_def sd_it; -+ dep_t dep; -+ struct model_insn_info *insn, *con; -+ -+ model_num_insns = 0; -+ start = PREV_INSN (current_sched_info->next_tail); -+ end = current_sched_info->prev_head; -+ for (iter = start; iter != end; iter = PREV_INSN (iter)) -+ if (NONDEBUG_INSN_P (iter)) -+ { -+ insn = MODEL_INSN_INFO (iter); -+ insn->insn = iter; -+ FOR_EACH_DEP (iter, SD_LIST_FORW, sd_it, dep) -+ { -+ con = MODEL_INSN_INFO (DEP_CON (dep)); -+ if (con->insn && insn->alap < con->alap + 1) -+ insn->alap = con->alap + 1; -+ } -+ -+ insn->old_queue = QUEUE_INDEX (iter); -+ QUEUE_INDEX (iter) = QUEUE_NOWHERE; -+ -+ insn->unscheduled_preds = dep_list_size (iter, SD_LIST_HARD_BACK); -+ if (insn->unscheduled_preds == 0) -+ model_add_to_worklist (insn, NULL, model_worklist); -+ -+ model_num_insns++; -+ } -+} -+ -+/* The global state describes the register pressure at the start of the -+ model schedule. Initialize GROUP accordingly. */ -+ -+static void -+model_init_pressure_group (struct model_pressure_group *group) -+{ -+ int cci, cl; -+ -+ for (cci = 0; cci < ira_reg_class_cover_size; cci++) -+ { -+ cl = ira_reg_class_cover[cci]; -+ group->limits[cci].pressure = curr_reg_pressure[cl]; -+ group->limits[cci].point = 0; -+ } -+ /* Use index model_num_insns to record the state after the last -+ instruction in the model schedule. */ -+ group->model = XNEWVEC (struct model_pressure_data, -+ (model_num_insns + 1) * ira_reg_class_cover_size); -+} -+ -+/* Record that MODEL_REF_PRESSURE (GROUP, POINT, CCI) is PRESSURE. -+ Update the maximum pressure for the whole schedule. */ -+ -+static void -+model_record_pressure (struct model_pressure_group *group, -+ int point, int cci, int pressure) -+{ -+ MODEL_REF_PRESSURE (group, point, cci) = pressure; -+ if (group->limits[cci].pressure < pressure) -+ { -+ group->limits[cci].pressure = pressure; -+ group->limits[cci].point = point; -+ } -+} -+ -+/* INSN has just been added to the end of the model schedule. Record its -+ register-pressure information. */ -+ -+static void -+model_record_pressures (struct model_insn_info *insn) -+{ -+ struct reg_pressure_data *reg_pressure; -+ int point, cci, cl, delta; -+ int death[N_REG_CLASSES]; -+ -+ point = model_index (insn->insn); -+ if (sched_verbose >= 2) -+ { -+ char buf[2048]; -+ -+ if (point == 0) -+ { -+ fprintf (sched_dump, "\n;;\tModel schedule:\n;;\n"); -+ fprintf (sched_dump, ";;\t| idx insn | mpri hght dpth prio |\n"); -+ } -+ print_pattern (buf, PATTERN (insn->insn), 0); -+ fprintf (sched_dump, ";;\t| %3d %4d | %4d %4d %4d %4d | %-30s ", -+ point, INSN_UID (insn->insn), insn->model_priority, -+ insn->depth + insn->alap, insn->depth, -+ INSN_PRIORITY (insn->insn), buf); -+ } -+ calculate_reg_deaths (insn->insn, death); -+ reg_pressure = INSN_REG_PRESSURE (insn->insn); -+ for (cci = 0; cci < ira_reg_class_cover_size; cci++) -+ { -+ cl = ira_reg_class_cover[cci]; -+ delta = reg_pressure[cci].set_increase - death[cl]; -+ if (sched_verbose >= 2) -+ fprintf (sched_dump, " %s:[%d,%+d]", reg_class_names[cl], -+ curr_reg_pressure[cl], delta); -+ model_record_pressure (&model_before_pressure, point, cci, -+ curr_reg_pressure[cl]); -+ } -+ if (sched_verbose >= 2) -+ fprintf (sched_dump, "\n"); -+} -+ -+/* All instructions have been added to the model schedule. Record the -+ final register pressure in GROUP and set up all MODEL_MAX_PRESSUREs. */ -+ -+static void -+model_record_final_pressures (struct model_pressure_group *group) -+{ -+ int point, cci, max_pressure, ref_pressure, cl; -+ -+ for (cci = 0; cci < ira_reg_class_cover_size; cci++) -+ { -+ /* Record the final pressure for this class. */ -+ cl = ira_reg_class_cover[cci]; -+ point = model_num_insns; -+ ref_pressure = curr_reg_pressure[cl]; -+ model_record_pressure (group, point, cci, ref_pressure); -+ -+ /* Record the original maximum pressure. */ -+ group->limits[cci].orig_pressure = group->limits[cci].pressure; -+ -+ /* Update the MODEL_MAX_PRESSURE for every point of the schedule. */ -+ max_pressure = ref_pressure; -+ MODEL_MAX_PRESSURE (group, point, cci) = max_pressure; -+ while (point > 0) -+ { -+ point--; -+ ref_pressure = MODEL_REF_PRESSURE (group, point, cci); -+ max_pressure = MAX (max_pressure, ref_pressure); -+ MODEL_MAX_PRESSURE (group, point, cci) = max_pressure; -+ } -+ } -+} -+ -+/* Update all successors of INSN, given that INSN has just been scheduled. */ -+ -+static void -+model_add_successors_to_worklist (struct model_insn_info *insn) -+{ -+ sd_iterator_def sd_it; -+ struct model_insn_info *con; -+ dep_t dep; -+ -+ FOR_EACH_DEP (insn->insn, SD_LIST_FORW, sd_it, dep) -+ { -+ con = MODEL_INSN_INFO (DEP_CON (dep)); -+ /* Ignore debug instructions, and instructions from other blocks. */ -+ if (con->insn) -+ { -+ con->unscheduled_preds--; -+ -+ /* Update the depth field of each true-dependent successor. -+ Increasing the depth gives them a higher priority than -+ before. */ -+ if (DEP_TYPE (dep) == REG_DEP_TRUE && con->depth < insn->depth + 1) -+ { -+ con->depth = insn->depth + 1; -+ if (QUEUE_INDEX (con->insn) == QUEUE_READY) -+ model_promote_insn (con); -+ } -+ -+ /* If this is a true dependency, or if there are no remaining -+ dependencies for CON (meaning that CON only had non-true -+ dependencies), make sure that CON is on the worklist. -+ We don't bother otherwise because it would tend to fill the -+ worklist with a lot of low-priority instructions that are not -+ yet ready to issue. */ -+ if ((con->depth > 0 || con->unscheduled_preds == 0) -+ && QUEUE_INDEX (con->insn) == QUEUE_NOWHERE) -+ model_add_to_worklist (con, insn, insn->next); -+ } -+ } -+} -+ -+/* Give INSN a higher priority than any current instruction, then give -+ unscheduled predecessors of INSN a higher priority still. If any of -+ those predecessors are not on the model worklist, do the same for its -+ predecessors, and so on. */ -+ -+static void -+model_promote_predecessors (struct model_insn_info *insn) -+{ -+ struct model_insn_info *pro, *first; -+ sd_iterator_def sd_it; -+ dep_t dep; -+ -+ if (sched_verbose >= 7) -+ fprintf (sched_dump, ";;\t+--- priority of %d = %d, priority of", -+ INSN_UID (insn->insn), model_next_priority); -+ insn->model_priority = model_next_priority++; -+ model_remove_from_worklist (insn); -+ model_add_to_worklist_at (insn, NULL); -+ -+ first = NULL; -+ for (;;) -+ { -+ FOR_EACH_DEP (insn->insn, SD_LIST_HARD_BACK, sd_it, dep) -+ { -+ pro = MODEL_INSN_INFO (DEP_PRO (dep)); -+ /* The first test is to ignore debug instructions, and instructions -+ from other blocks. */ -+ if (pro->insn -+ && pro->model_priority != model_next_priority -+ && QUEUE_INDEX (pro->insn) != QUEUE_SCHEDULED) -+ { -+ pro->model_priority = model_next_priority; -+ if (sched_verbose >= 7) -+ fprintf (sched_dump, " %d", INSN_UID (pro->insn)); -+ if (QUEUE_INDEX (pro->insn) == QUEUE_READY) -+ { -+ /* PRO is already in the worklist, but it now has -+ a higher priority than before. Move it at the -+ appropriate place. */ -+ model_remove_from_worklist (pro); -+ model_add_to_worklist (pro, NULL, model_worklist); -+ } -+ else -+ { -+ /* PRO isn't in the worklist. Recursively process -+ its predecessors until we find one that is. */ -+ pro->next = first; -+ first = pro; -+ } -+ } -+ } -+ if (!first) -+ break; -+ insn = first; -+ first = insn->next; -+ } -+ if (sched_verbose >= 7) -+ fprintf (sched_dump, " = %d\n", model_next_priority); -+ model_next_priority++; -+} -+ -+/* Pick one instruction from model_worklist and process it. */ -+ -+static void -+model_choose_insn (void) -+{ -+ struct model_insn_info *insn, *fallback; -+ int count; -+ -+ if (sched_verbose >= 7) -+ { -+ fprintf (sched_dump, ";;\t+--- worklist:\n"); -+ insn = model_worklist; -+ count = MAX_SCHED_READY_INSNS; -+ while (count > 0 && insn) -+ { -+ fprintf (sched_dump, ";;\t+--- %d [%d, %d, %d, %d]\n", -+ INSN_UID (insn->insn), insn->model_priority, -+ insn->depth + insn->alap, insn->depth, -+ INSN_PRIORITY (insn->insn)); -+ count--; -+ insn = insn->next; -+ } -+ } -+ -+ /* Look for a ready instruction whose model_classify_priority is zero -+ or negative, picking the highest-priority one. Adding such an -+ instruction to the schedule now should do no harm, and may actually -+ do some good. -+ -+ Failing that, see whether there is an instruction with the highest -+ extant model_priority that is not yet ready, but which would reduce -+ pressure if it became ready. This is designed to catch cases like: -+ -+ (set (mem (reg R1)) (reg R2)) -+ -+ where the instruction is the last remaining use of R1 and where the -+ value of R2 is not yet available (or vice versa). The death of R1 -+ means that this instruction already reduces pressure. It is of -+ course possible that the computation of R2 involves other registers -+ that are hard to kill, but such cases are rare enough for this -+ heuristic to be a win in general. -+ -+ Failing that, just pick the highest-priority instruction in the -+ worklist. */ -+ count = MAX_SCHED_READY_INSNS; -+ insn = model_worklist; -+ fallback = 0; -+ for (;;) -+ { -+ if (count == 0 || !insn) -+ { -+ insn = fallback ? fallback : model_worklist; -+ break; -+ } -+ if (insn->unscheduled_preds) -+ { -+ if (model_worklist->model_priority == insn->model_priority -+ && !fallback -+ && model_classify_pressure (insn) < 0) -+ fallback = insn; -+ } -+ else -+ { -+ if (model_classify_pressure (insn) <= 0) -+ break; -+ } -+ count--; -+ insn = insn->next; -+ } -+ -+ if (sched_verbose >= 7 && insn != model_worklist) -+ { -+ if (insn->unscheduled_preds) -+ fprintf (sched_dump, ";;\t+--- promoting insn %d, with dependencies\n", -+ INSN_UID (insn->insn)); -+ else -+ fprintf (sched_dump, ";;\t+--- promoting insn %d, which is ready\n", -+ INSN_UID (insn->insn)); -+ } -+ if (insn->unscheduled_preds) -+ /* INSN isn't yet ready to issue. Give all its predecessors the -+ highest priority. */ -+ model_promote_predecessors (insn); -+ else -+ { -+ /* INSN is ready. Add it to the end of model_schedule and -+ process its successors. */ -+ model_add_successors_to_worklist (insn); -+ model_remove_from_worklist (insn); -+ model_add_to_schedule (insn->insn); -+ model_record_pressures (insn); -+ update_register_pressure (insn->insn); -+ } -+} -+ -+/* Restore all QUEUE_INDEXs to the values that they had before -+ model_start_schedule was called. */ -+ -+static void -+model_reset_queue_indices (void) -+{ -+ unsigned int i; -+ rtx insn; -+ -+ FOR_EACH_VEC_ELT (rtx, model_schedule, i, insn) -+ QUEUE_INDEX (insn) = MODEL_INSN_INFO (insn)->old_queue; -+} -+ -+/* We have calculated the model schedule and spill costs. Print a summary -+ to sched_dump. */ -+ -+static void -+model_dump_pressure_summary (void) -+{ -+ int cci, cl; -+ -+ fprintf (sched_dump, ";; Pressure summary:"); -+ for (cci = 0; cci < ira_reg_class_cover_size; cci++) -+ { -+ cl = ira_reg_class_cover[cci]; -+ fprintf (sched_dump, " %s:%d", reg_class_names[cl], -+ model_before_pressure.limits[cci].pressure); -+ } -+ fprintf (sched_dump, "\n\n"); -+} -+ -+/* Initialize the SCHED_PRESSURE_MODEL information for the current -+ scheduling region. */ -+ -+static void -+model_start_schedule (void) -+{ -+ basic_block bb; -+ -+ model_next_priority = 1; -+ model_schedule = VEC_alloc (rtx, heap, sched_max_luid); -+ model_insns = XCNEWVEC (struct model_insn_info, sched_max_luid); -+ -+ bb = BLOCK_FOR_INSN (NEXT_INSN (current_sched_info->prev_head)); -+ initiate_reg_pressure_info (df_get_live_in (bb)); -+ -+ model_analyze_insns (); -+ model_init_pressure_group (&model_before_pressure); -+ while (model_worklist) -+ model_choose_insn (); -+ gcc_assert (model_num_insns == (int) VEC_length (rtx, model_schedule)); -+ if (sched_verbose >= 2) -+ fprintf (sched_dump, "\n"); -+ -+ model_record_final_pressures (&model_before_pressure); -+ model_reset_queue_indices (); -+ -+ XDELETEVEC (model_insns); -+ -+ model_curr_point = 0; -+ initiate_reg_pressure_info (df_get_live_in (bb)); -+ if (sched_verbose >= 1) -+ model_dump_pressure_summary (); -+} -+ -+/* Free the information associated with GROUP. */ -+ -+static void -+model_finalize_pressure_group (struct model_pressure_group *group) -+{ -+ XDELETEVEC (group->model); -+} -+ -+/* Free the information created by model_start_schedule. */ -+ -+static void -+model_end_schedule (void) -+{ -+ model_finalize_pressure_group (&model_before_pressure); -+ VEC_free (rtx, heap, model_schedule); -+} -+ - /* INSN is the "currently executing insn". Launch each insn which was - waiting on INSN. READY is the ready list which contains the insns - that are ready to fire. CLOCK is the current cycle. The function -@@ -1667,10 +3065,14 @@ - reg_class_names[ira_reg_class_cover[i]], - pressure_info[i].set_increase, pressure_info[i].change); - } -+ if (sched_pressure == SCHED_PRESSURE_MODEL -+ && model_curr_point < model_num_insns -+ && model_index (insn) == model_curr_point) -+ fprintf (sched_dump, ":model %d", model_curr_point); - fputc ('\n', sched_dump); - } - -- if (sched_pressure_p && !DEBUG_INSN_P (insn)) -+ if (sched_pressure == SCHED_PRESSURE_WEIGHTED && !DEBUG_INSN_P (insn)) - update_reg_and_insn_max_reg_pressure (insn); - - /* Scheduling instruction should have all its dependencies resolved and -@@ -1728,6 +3130,24 @@ - gcc_assert (QUEUE_INDEX (insn) == QUEUE_NOWHERE); - QUEUE_INDEX (insn) = QUEUE_SCHEDULED; - -+ if (sched_pressure == SCHED_PRESSURE_MODEL -+ && model_curr_point < model_num_insns -+ && NONDEBUG_INSN_P (insn)) -+ { -+ if (model_index (insn) == model_curr_point) -+ do -+ model_curr_point++; -+ while (model_curr_point < model_num_insns -+ && (QUEUE_INDEX (MODEL_INSN (model_curr_point)) -+ == QUEUE_SCHEDULED)); -+ else -+ model_recompute (insn); -+ model_update_limit_points (); -+ update_register_pressure (insn); -+ if (sched_verbose >= 2) -+ print_curr_reg_pressure (); -+ } -+ - gcc_assert (INSN_TICK (insn) >= MIN_TICK); - if (INSN_TICK (insn) > clock_var) - /* INSN has been prematurely moved from the queue to the ready list. -@@ -2056,7 +3476,16 @@ - /* If the ready list is full, delay the insn for 1 cycle. - See the comment in schedule_block for the rationale. */ - if (!reload_completed -- && ready->n_ready - ready->n_debug > MAX_SCHED_READY_INSNS -+ && (ready->n_ready - ready->n_debug > MAX_SCHED_READY_INSNS -+ || (sched_pressure == SCHED_PRESSURE_MODEL -+ /* Limit pressure recalculations to MAX_SCHED_READY_INSNS -+ instructions too. */ -+ && model_index (insn) > (model_curr_point -+ + MAX_SCHED_READY_INSNS))) -+ && !(sched_pressure == SCHED_PRESSURE_MODEL -+ && model_curr_point < model_num_insns -+ /* Always allow the next model instruction to issue. */ -+ && model_index (insn) == model_curr_point) - && !SCHED_GROUP_P (insn) - && insn != skip_insn) - { -@@ -2293,12 +3722,12 @@ - fprintf (sched_dump, " %s:%d", - (*current_sched_info->print_insn) (p[i], 0), - INSN_LUID (p[i])); -- if (sched_pressure_p) -+ if (sched_pressure != SCHED_PRESSURE_NONE) - fprintf (sched_dump, "(cost=%d", - INSN_REG_PRESSURE_EXCESS_COST_CHANGE (p[i])); - if (INSN_TICK (p[i]) > clock_var) - fprintf (sched_dump, ":delay=%d", INSN_TICK (p[i]) - clock_var); -- if (sched_pressure_p) -+ if (sched_pressure != SCHED_PRESSURE_NONE) - fprintf (sched_dump, ")"); - } - fprintf (sched_dump, "\n"); -@@ -2609,8 +4038,8 @@ - { - if (state_dead_lock_p (state) - || insn_finishes_cycle_p (insn)) -- /* We won't issue any more instructions in the next -- choice_state. */ -+ /* We won't issue any more instructions in the next -+ choice_state. */ - top->rest = 0; - else - top->rest--; -@@ -2813,6 +4242,59 @@ - } - } - -+/* Examine all insns on the ready list and queue those which can't be -+ issued in this cycle. TEMP_STATE is temporary scheduler state we -+ can use as scratch space. If FIRST_CYCLE_INSN_P is true, no insns -+ have been issued for the current cycle, which means it is valid to -+ issue an asm statement. */ -+ -+static void -+prune_ready_list (state_t temp_state, bool first_cycle_insn_p) -+{ -+ int i; -+ -+ restart: -+ for (i = 0; i < ready.n_ready; i++) -+ { -+ rtx insn = ready_element (&ready, i); -+ int cost = 0; -+ -+ if (recog_memoized (insn) < 0) -+ { -+ if (!first_cycle_insn_p -+ && (GET_CODE (PATTERN (insn)) == ASM_INPUT -+ || asm_noperands (PATTERN (insn)) >= 0)) -+ cost = 1; -+ } -+ else if (sched_pressure != SCHED_PRESSURE_NONE) -+ { -+ if (sched_pressure == SCHED_PRESSURE_MODEL -+ && INSN_TICK (insn) <= clock_var) -+ { -+ memcpy (temp_state, curr_state, dfa_state_size); -+ if (state_transition (temp_state, insn) >= 0) -+ INSN_TICK (insn) = clock_var + 1; -+ } -+ cost = 0; -+ } -+ else -+ { -+ memcpy (temp_state, curr_state, dfa_state_size); -+ cost = state_transition (temp_state, insn); -+ if (cost < 0) -+ cost = 0; -+ else if (cost == 0) -+ cost = 1; -+ } -+ if (cost >= 1) -+ { -+ ready_remove (&ready, i); -+ queue_insn (insn, cost); -+ goto restart; -+ } -+ } -+} -+ - /* Use forward list scheduling to rearrange insns of block pointed to by - TARGET_BB, possibly bringing insns from subsequent blocks in the same - region. */ -@@ -2882,6 +4364,9 @@ - in try_ready () (which is called through init_ready_list ()). */ - (*current_sched_info->init_ready_list) (); - -+ if (sched_pressure == SCHED_PRESSURE_MODEL) -+ model_start_schedule (); -+ - /* The algorithm is O(n^2) in the number of ready insns at any given - time in the worst case. Before reload we are more likely to have - big lists so truncate them to a reasonable size. */ -@@ -2963,6 +4448,10 @@ - } - while (advance > 0); - -+ prune_ready_list (temp_state, true); -+ if (ready.n_ready == 0) -+ continue; -+ - if (sort_p) - { - /* Sort the ready list based on priority. */ -@@ -3040,7 +4529,7 @@ - fprintf (sched_dump, ";;\tReady list (t = %3d): ", - clock_var); - debug_ready_list (&ready); -- if (sched_pressure_p) -+ if (sched_pressure == SCHED_PRESSURE_WEIGHTED) - print_curr_reg_pressure (); - } - -@@ -3084,7 +4573,8 @@ - else - insn = ready_remove_first (&ready); - -- if (sched_pressure_p && INSN_TICK (insn) > clock_var) -+ if (sched_pressure != SCHED_PRESSURE_NONE -+ && INSN_TICK (insn) > clock_var) - { - ready_add (&ready, insn, true); - advance = 1; -@@ -3112,44 +4602,6 @@ - } - - sort_p = TRUE; -- memcpy (temp_state, curr_state, dfa_state_size); -- if (recog_memoized (insn) < 0) -- { -- asm_p = (GET_CODE (PATTERN (insn)) == ASM_INPUT -- || asm_noperands (PATTERN (insn)) >= 0); -- if (!first_cycle_insn_p && asm_p) -- /* This is asm insn which is tried to be issued on the -- cycle not first. Issue it on the next cycle. */ -- cost = 1; -- else -- /* A USE insn, or something else we don't need to -- understand. We can't pass these directly to -- state_transition because it will trigger a -- fatal error for unrecognizable insns. */ -- cost = 0; -- } -- else if (sched_pressure_p) -- cost = 0; -- else -- { -- cost = state_transition (temp_state, insn); -- if (cost < 0) -- cost = 0; -- else if (cost == 0) -- cost = 1; -- } -- -- if (cost >= 1) -- { -- queue_insn (insn, cost); -- if (SCHED_GROUP_P (insn)) -- { -- advance = cost; -- break; -- } -- -- continue; -- } - - if (current_sched_info->can_schedule_ready_p - && ! (*current_sched_info->can_schedule_ready_p) (insn)) -@@ -3200,11 +4652,17 @@ - reemit_notes (insn); - last_scheduled_insn = insn; - -- if (memcmp (curr_state, temp_state, dfa_state_size) != 0) -- { -- cycle_issued_insns++; -- memcpy (curr_state, temp_state, dfa_state_size); -- } -+ if (recog_memoized (insn) >= 0) -+ { -+ cost = state_transition (curr_state, insn); -+ if (sched_pressure != SCHED_PRESSURE_WEIGHTED) -+ gcc_assert (cost < 0); -+ cycle_issued_insns++; -+ asm_p = false; -+ } -+ else -+ asm_p = (GET_CODE (PATTERN (insn)) == ASM_INPUT -+ || asm_noperands (PATTERN (insn)) >= 0); - - if (targetm.sched.variable_issue) - can_issue_more = -@@ -3225,6 +4683,9 @@ - - first_cycle_insn_p = false; - -+ if (ready.n_ready > 0) -+ prune_ready_list (temp_state, false); -+ - /* Sort the ready list based on priority. This must be - redone here, as schedule_insn may have readied additional - insns that will not be sorted correctly. */ -@@ -3321,6 +4782,9 @@ - } - } - -+ if (sched_pressure == SCHED_PRESSURE_MODEL) -+ model_end_schedule (); -+ - if (sched_verbose) - fprintf (sched_dump, ";; total time = %d\n", clock_var); - -@@ -3424,10 +4888,14 @@ - if (targetm.sched.dispatch (NULL_RTX, IS_DISPATCH_ON)) - targetm.sched.dispatch_do (NULL_RTX, DISPATCH_INIT); - -- sched_pressure_p = (flag_sched_pressure && ! reload_completed -- && common_sched_info->sched_pass_id == SCHED_RGN_PASS); -+ if (flag_sched_pressure -+ && !reload_completed -+ && common_sched_info->sched_pass_id == SCHED_RGN_PASS) -+ sched_pressure = flag_sched_pressure_algorithm; -+ else -+ sched_pressure = SCHED_PRESSURE_NONE; - -- if (sched_pressure_p) -+ if (sched_pressure != SCHED_PRESSURE_NONE) - ira_setup_eliminable_regset (); - - /* Initialize SPEC_INFO. */ -@@ -3504,7 +4972,7 @@ - if (targetm.sched.init_global) - targetm.sched.init_global (sched_dump, sched_verbose, get_max_uid () + 1); - -- if (sched_pressure_p) -+ if (sched_pressure != SCHED_PRESSURE_NONE) - { - int i, max_regno = max_reg_num (); - -@@ -3517,8 +4985,11 @@ - ? ira_class_translate[REGNO_REG_CLASS (i)] - : reg_cover_class (i)); - curr_reg_live = BITMAP_ALLOC (NULL); -- saved_reg_live = BITMAP_ALLOC (NULL); -- region_ref_regs = BITMAP_ALLOC (NULL); -+ if (sched_pressure == SCHED_PRESSURE_WEIGHTED) -+ { -+ saved_reg_live = BITMAP_ALLOC (NULL); -+ region_ref_regs = BITMAP_ALLOC (NULL); -+ } - } - - curr_state = xmalloc (dfa_state_size); -@@ -3618,12 +5089,15 @@ - sched_finish (void) - { - haifa_finish_h_i_d (); -- if (sched_pressure_p) -+ if (sched_pressure != SCHED_PRESSURE_NONE) - { -+ if (sched_pressure == SCHED_PRESSURE_WEIGHTED) -+ { -+ BITMAP_FREE (region_ref_regs); -+ BITMAP_FREE (saved_reg_live); -+ } -+ BITMAP_FREE (curr_reg_live); - free (sched_regno_cover_class); -- BITMAP_FREE (region_ref_regs); -- BITMAP_FREE (saved_reg_live); -- BITMAP_FREE (curr_reg_live); - } - free (curr_state); - -@@ -3936,7 +5410,7 @@ - INSN_TICK (next) = tick; - - delay = tick - clock_var; -- if (delay <= 0 || sched_pressure_p) -+ if (delay <= 0 || sched_pressure != SCHED_PRESSURE_NONE) - delay = QUEUE_READY; - - change_queue_index (next, delay); -@@ -5185,7 +6659,7 @@ - if (insn == jump) - break; - -- if (dep_list_size (insn) == 0) -+ if (dep_list_size (insn, SD_LIST_FORW) == 0) - { - dep_def _new_dep, *new_dep = &_new_dep; - -@@ -5556,6 +7030,7 @@ - - FOR_EACH_VEC_ELT (haifa_insn_data_def, h_i_d, i, data) - { -+ free (data->max_reg_pressure); - if (data->reg_pressure != NULL) - free (data->reg_pressure); - for (use = data->reg_use_list; use != NULL; use = next) - -=== modified file 'gcc/sched-deps.c' ---- old/gcc/sched-deps.c 2011-12-08 13:33:58 +0000 -+++ new/gcc/sched-deps.c 2012-02-08 23:39:45 +0000 -@@ -450,7 +450,7 @@ - static void add_dependence_list_and_free (struct deps_desc *, rtx, - rtx *, int, enum reg_note); - static void delete_all_dependences (rtx); --static void fixup_sched_groups (rtx); -+static void chain_to_prev_insn (rtx); - - static void flush_pending_lists (struct deps_desc *, rtx, int, int); - static void sched_analyze_1 (struct deps_desc *, rtx, rtx); -@@ -1490,7 +1490,7 @@ - the previous nonnote insn. */ - - static void --fixup_sched_groups (rtx insn) -+chain_to_prev_insn (rtx insn) - { - sd_iterator_def sd_it; - dep_t dep; -@@ -1999,7 +1999,7 @@ - static struct reg_pressure_data *pressure_info; - rtx link; - -- gcc_assert (sched_pressure_p); -+ gcc_assert (sched_pressure != SCHED_PRESSURE_NONE); - - if (! INSN_P (insn)) - return; -@@ -2030,8 +2030,9 @@ - len = sizeof (struct reg_pressure_data) * ira_reg_class_cover_size; - pressure_info - = INSN_REG_PRESSURE (insn) = (struct reg_pressure_data *) xmalloc (len); -- INSN_MAX_REG_PRESSURE (insn) = (int *) xcalloc (ira_reg_class_cover_size -- * sizeof (int), 1); -+ if (sched_pressure == SCHED_PRESSURE_WEIGHTED) -+ INSN_MAX_REG_PRESSURE (insn) = (int *) xcalloc (ira_reg_class_cover_size -+ * sizeof (int), 1); - for (i = 0; i < ira_reg_class_cover_size; i++) - { - cl = ira_reg_class_cover[i]; -@@ -2775,7 +2776,7 @@ - || (NONJUMP_INSN_P (insn) && control_flow_insn_p (insn))) - reg_pending_barrier = MOVE_BARRIER; - -- if (sched_pressure_p) -+ if (sched_pressure != SCHED_PRESSURE_NONE) - { - setup_insn_reg_uses (deps, insn); - setup_insn_reg_pressure_info (insn); -@@ -3076,7 +3077,7 @@ - instructions that follow seem like they should be part - of the call group. - -- Also, if we did, fixup_sched_groups() would move the -+ Also, if we did, chain_to_prev_insn would move the - deps of the debug insn to the call insn, modifying - non-debug post-dependency counts of the debug insn - dependencies and otherwise messing with the scheduling -@@ -3222,6 +3223,37 @@ - return true; - } - -+/* Return true if INSN should be made dependent on the previous instruction -+ group, and if all INSN's dependencies should be moved to the first -+ instruction of that group. */ -+ -+static bool -+chain_to_prev_insn_p (rtx insn) -+{ -+ rtx prev, x; -+ -+ /* INSN forms a group with the previous instruction. */ -+ if (SCHED_GROUP_P (insn)) -+ return true; -+ -+ /* If the previous instruction clobbers a register R and this one sets -+ part of R, the clobber was added specifically to help us track the -+ liveness of R. There's no point scheduling the clobber and leaving -+ INSN behind, especially if we move the clobber to another block. */ -+ prev = prev_nonnote_nondebug_insn (insn); -+ if (prev -+ && INSN_P (prev) -+ && BLOCK_FOR_INSN (prev) == BLOCK_FOR_INSN (insn) -+ && GET_CODE (PATTERN (prev)) == CLOBBER) -+ { -+ x = XEXP (PATTERN (prev), 0); -+ if (set_of (x, insn)) -+ return true; -+ } -+ -+ return false; -+} -+ - /* Analyze INSN with DEPS as a context. */ - void - deps_analyze_insn (struct deps_desc *deps, rtx insn) -@@ -3358,8 +3390,9 @@ - - /* Fixup the dependencies in the sched group. */ - if ((NONJUMP_INSN_P (insn) || JUMP_P (insn)) -- && SCHED_GROUP_P (insn) && !sel_sched_p ()) -- fixup_sched_groups (insn); -+ && chain_to_prev_insn_p (insn) -+ && !sel_sched_p ()) -+ chain_to_prev_insn (insn); - } - - /* Initialize DEPS for the new block beginning with HEAD. */ - -=== modified file 'gcc/sched-int.h' ---- old/gcc/sched-int.h 2011-02-02 04:31:35 +0000 -+++ new/gcc/sched-int.h 2012-02-08 23:39:02 +0000 -@@ -651,7 +651,7 @@ - - /* Do register pressure sensitive insn scheduling if the flag is set - up. */ --extern bool sched_pressure_p; -+extern enum sched_pressure_algorithm sched_pressure; - - /* Map regno -> its cover class. The map defined only when - SCHED_PRESSURE_P is true. */ -@@ -773,16 +773,16 @@ - - short cost; - -+ /* '> 0' if priority is valid, -+ '== 0' if priority was not yet computed, -+ '< 0' if priority in invalid and should be recomputed. */ -+ signed char priority_status; -+ - /* Set if there's DEF-USE dependence between some speculatively - moved load insn and this one. */ - unsigned int fed_by_spec_load : 1; - unsigned int is_load_insn : 1; - -- /* '> 0' if priority is valid, -- '== 0' if priority was not yet computed, -- '< 0' if priority in invalid and should be recomputed. */ -- signed char priority_status; -- - /* What speculations are necessary to apply to schedule the instruction. */ - ds_t todo_spec; - -@@ -817,6 +817,7 @@ - /* Info about how scheduling the insn changes cost of register - pressure excess (between source and target). */ - int reg_pressure_excess_cost_change; -+ int model_index; - }; - - typedef struct _haifa_insn_data haifa_insn_data_def; -@@ -839,6 +840,7 @@ - #define INSN_REG_PRESSURE_EXCESS_COST_CHANGE(INSN) \ - (HID (INSN)->reg_pressure_excess_cost_change) - #define INSN_PRIORITY_STATUS(INSN) (HID (INSN)->priority_status) -+#define INSN_MODEL_INDEX(INSN) (HID (INSN)->model_index) - - typedef struct _haifa_deps_insn_data haifa_deps_insn_data_def; - typedef haifa_deps_insn_data_def *haifa_deps_insn_data_t; - -=== modified file 'gcc/sched-rgn.c' ---- old/gcc/sched-rgn.c 2011-06-04 10:15:48 +0000 -+++ new/gcc/sched-rgn.c 2012-02-08 23:38:13 +0000 -@@ -2943,7 +2943,7 @@ - - sched_extend_ready_list (rgn_n_insns); - -- if (sched_pressure_p) -+ if (sched_pressure == SCHED_PRESSURE_WEIGHTED) - { - sched_init_region_reg_pressure_info (); - for (bb = 0; bb < current_nr_blocks; bb++) - |