📄 sched.c
字号:
if (unit >= 0) { int instance = unit;#if MAX_MULTIPLICITY > 1 /* Find the first free instance of the function unit and use that one. We assume that one is free. */ for (i = function_units[unit].multiplicity - 1; i > 0; i--) { if (! actual_hazard_this_instance (unit, instance, insn, clock, 0)) break; instance += FUNCTION_UNITS_SIZE; }#endif unit_last_insn[instance] = insn; unit_tick[instance] = (clock + function_units[unit].max_blockage); } else for (i = 0, unit = ~unit; unit; i++, unit >>= 1) if ((unit & 1) != 0) schedule_unit (i, insn, clock);}/* Return the actual hazard cost of executing INSN on the units encoded by UNIT at time CLOCK if the previous actual hazard cost was COST. */__inline static intactual_hazard (unit, insn, clock, cost) int unit, clock, cost; rtx insn;{ int i; if (unit >= 0) { /* Find the instance of the function unit with the minimum hazard. */ int instance = unit; int best_cost = actual_hazard_this_instance (unit, instance, insn, clock, cost); int this_cost;#if MAX_MULTIPLICITY > 1 if (best_cost > cost) { for (i = function_units[unit].multiplicity - 1; i > 0; i--) { instance += FUNCTION_UNITS_SIZE; this_cost = actual_hazard_this_instance (unit, instance, insn, clock, cost); if (this_cost < best_cost) { best_cost = this_cost; if (this_cost <= cost) break; } } }#endif cost = MAX (cost, best_cost); } else for (i = 0, unit = ~unit; unit; i++, unit >>= 1) if ((unit & 1) != 0) cost = actual_hazard (i, insn, clock, cost); return cost;}/* Return the potential hazard cost of executing an instruction on the units encoded by UNIT if the previous potential hazard cost was COST. An insn with a large blockage time is chosen in preference to one with a smaller time; an insn that uses a unit that is more likely to be used is chosen in preference to one with a unit that is less used. We are trying to minimize a subsequent actual hazard. */__inline static intpotential_hazard (unit, insn, cost) int unit, cost; rtx insn;{ int i, ncost; unsigned int minb, maxb; if (unit >= 0) { minb = maxb = function_units[unit].max_blockage; if (maxb > 1) { if (function_units[unit].blockage_range_function) { maxb = minb = blockage_range (unit, insn); maxb = MAX_BLOCKAGE_COST (maxb); minb = MIN_BLOCKAGE_COST (minb); } if (maxb > 1) { /* Make the number of instructions left dominate. Make the minimum delay dominate the maximum delay. If all these are the same, use the unit number to add an arbitrary ordering. Other terms can be added. */ ncost = minb * 0x40 + maxb; ncost *= (unit_n_insns[unit] - 1) * 0x1000 + unit; if (ncost > cost) cost = ncost; } } } else for (i = 0, unit = ~unit; unit; i++, unit >>= 1) if ((unit & 1) != 0) cost = potential_hazard (i, insn, cost); return cost;}/* Compute cost of executing INSN given the dependence LINK on the insn USED. This is the number of virtual cycles taken between instruction issue and instruction results. */__inline static intinsn_cost (insn, link, used) rtx insn, link, used;{ register int cost = INSN_COST (insn); if (cost == 0) { recog_memoized (insn); /* A USE insn, or something else we don't need to understand. We can't pass these directly to result_ready_cost because it will trigger a fatal error for unrecognizable insns. */ if (INSN_CODE (insn) < 0) { INSN_COST (insn) = 1; return 1; } else { cost = result_ready_cost (insn); if (cost < 1) cost = 1; INSN_COST (insn) = cost; } } /* A USE insn should never require the value used to be computed. This allows the computation of a function's result and parameter values to overlap the return and call. */ recog_memoized (used); if (INSN_CODE (used) < 0) LINK_COST_FREE (link) = 1; /* If some dependencies vary the cost, compute the adjustment. Most commonly, the adjustment is complete: either the cost is ignored (in the case of an output- or anti-dependence), or the cost is unchanged. These values are cached in the link as LINK_COST_FREE and LINK_COST_ZERO. */ if (LINK_COST_FREE (link)) cost = 1;#ifdef ADJUST_COST else if (! LINK_COST_ZERO (link)) { int ncost = cost; ADJUST_COST (used, link, insn, ncost); if (ncost <= 1) LINK_COST_FREE (link) = ncost = 1; if (cost == ncost) LINK_COST_ZERO (link) = 1; cost = ncost; }#endif return cost;}/* Compute the priority number for INSN. */static intpriority (insn) rtx insn;{ if (insn && GET_RTX_CLASS (GET_CODE (insn)) == 'i') { int prev_priority; int max_priority; int this_priority = INSN_PRIORITY (insn); rtx prev; if (this_priority > 0) return this_priority; max_priority = 1; /* Nonzero if these insns must be scheduled together. */ if (SCHED_GROUP_P (insn)) { prev = insn; while (SCHED_GROUP_P (prev)) { prev = PREV_INSN (prev); INSN_REF_COUNT (prev) += 1; } } for (prev = LOG_LINKS (insn); prev; prev = XEXP (prev, 1)) { rtx x = XEXP (prev, 0); /* A dependence pointing to a note or deleted insn is always obsolete, because sched_analyze_insn will have created any necessary new dependences which replace it. Notes and deleted insns can be created when instructions are deleted by insn splitting, or by register allocation. */ if (GET_CODE (x) == NOTE || INSN_DELETED_P (x)) { remove_dependence (insn, x); continue; } /* Clear the link cost adjustment bits. */ LINK_COST_FREE (prev) = 0;#ifdef ADJUST_COST LINK_COST_ZERO (prev) = 0;#endif /* This priority calculation was chosen because it results in the least instruction movement, and does not hurt the performance of the resulting code compared to the old algorithm. This makes the sched algorithm more stable, which results in better code, because there is less register pressure, cross jumping is more likely to work, and debugging is easier. When all instructions have a latency of 1, there is no need to move any instructions. Subtracting one here ensures that in such cases all instructions will end up with a priority of one, and hence no scheduling will be done. The original code did not subtract the one, and added the insn_cost of the current instruction to its priority (e.g. move the insn_cost call down to the end). */ prev_priority = priority (x) + insn_cost (x, prev, insn) - 1; if (prev_priority > max_priority) max_priority = prev_priority; INSN_REF_COUNT (x) += 1; } prepare_unit (insn_unit (insn)); INSN_PRIORITY (insn) = max_priority; return INSN_PRIORITY (insn); } return 0;}/* Remove all INSN_LISTs and EXPR_LISTs from the pending lists and add them to the unused_*_list variables, so that they can be reused. */static voidfree_pending_lists (){ register rtx link, prev_link; if (pending_read_insns) { prev_link = pending_read_insns; link = XEXP (prev_link, 1); while (link) { prev_link = link; link = XEXP (link, 1); } XEXP (prev_link, 1) = unused_insn_list; unused_insn_list = pending_read_insns; pending_read_insns = 0; } if (pending_write_insns) { prev_link = pending_write_insns; link = XEXP (prev_link, 1); while (link) { prev_link = link; link = XEXP (link, 1); } XEXP (prev_link, 1) = unused_insn_list; unused_insn_list = pending_write_insns; pending_write_insns = 0; } if (pending_read_mems) { prev_link = pending_read_mems; link = XEXP (prev_link, 1); while (link) { prev_link = link; link = XEXP (link, 1); } XEXP (prev_link, 1) = unused_expr_list; unused_expr_list = pending_read_mems; pending_read_mems = 0; } if (pending_write_mems) { prev_link = pending_write_mems; link = XEXP (prev_link, 1); while (link) { prev_link = link; link = XEXP (link, 1); } XEXP (prev_link, 1) = unused_expr_list; unused_expr_list = pending_write_mems; pending_write_mems = 0; }}/* Add an INSN and MEM reference pair to a pending INSN_LIST and MEM_LIST. The MEM is a memory reference contained within INSN, which we are saving so that we can do memory aliasing on it. */static voidadd_insn_mem_dependence (insn_list, mem_list, insn, mem) rtx *insn_list, *mem_list, insn, mem;{ register rtx link; if (unused_insn_list) { link = unused_insn_list; unused_insn_list = XEXP (link, 1); } else link = rtx_alloc (INSN_LIST); XEXP (link, 0) = insn; XEXP (link, 1) = *insn_list; *insn_list = link; if (unused_expr_list) { link = unused_expr_list; unused_expr_list = XEXP (link, 1); } else link = rtx_alloc (EXPR_LIST); XEXP (link, 0) = mem; XEXP (link, 1) = *mem_list; *mem_list = link; pending_lists_length++;}/* Make a dependency between every memory reference on the pending lists and INSN, thus flushing the pending lists. */static voidflush_pending_lists (insn) rtx insn;{ rtx link; while (pending_read_insns) { add_dependence (insn, XEXP (pending_read_insns, 0), REG_DEP_ANTI); link = pending_read_insns; pending_read_insns = XEXP (pending_read_insns, 1); XEXP (link, 1) = unused_insn_list; unused_insn_list = link; link = pending_read_mems; pending_read_mems = XEXP (pending_read_mems, 1); XEXP (link, 1) = unused_expr_list; unused_expr_list = link; } while (pending_write_insns) { add_dependence (insn, XEXP (pending_write_insns, 0), REG_DEP_ANTI); link = pending_write_insns; pending_write_insns = XEXP (pending_write_insns, 1); XEXP (link, 1) = unused_insn_list; unused_insn_list = link; link = pending_write_mems; pending_write_mems = XEXP (pending_write_mems, 1); XEXP (link, 1) = unused_expr_list; unused_expr_list = link; } pending_lists_length = 0; if (last_pending_memory_flush) add_dependence (insn, last_pending_memory_flush, REG_DEP_ANTI); last_pending_memory_flush = insn;}/* Analyze a single SET or CLOBBER rtx, X, creating all dependencies generated by the write to the destination of X, and reads of everything mentioned. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -