of the entry edges and the exit edges. */ int m_entry_freq, m_exit_freq; }; /* Return the cost of storing the register on entry to the loop and loading it back on exit from the loop. This is the cost to use if the register is spilled within the loop but is successfully allocated in the parent loop. */ inline int ira_loop_border_costs::spill_inside_loop_cost () const { return (m_entry_freq * ira_memory_move_cost[m_mode][m_class][0] + m_exit_freq * ira_memory_move_cost[m_mode][m_class][1]); } /* Return the cost of loading the register on entry to the loop and storing it back on exit from the loop. This is the cost to use if the register is successfully allocated within the loop but is spilled in the parent loop. */ inline int ira_loop_border_costs::spill_outside_loop_cost () const { return (m_entry_freq * ira_memory_move_cost[m_mode][m_class][1] + m_exit_freq * ira_memory_move_cost[m_mode][m_class][0]); } /* Return the cost of moving the pseudo register between different hard registers on entry and exit from the loop. This is the cost to use if the register is successfully allocated within both this loop and the parent loop, but the allocations for the loops differ. */ inline int ira_loop_border_costs::move_between_loops_cost () const { ira_init_register_move_cost_if_necessary (m_mode); auto move_cost = ira_register_move_cost[m_mode][m_class][m_class]; return move_cost * (m_entry_freq + m_exit_freq); } /* Return true if subloops that contain allocnos for A's register can use a different assignment from A. ALLOCATED_P is true for the case in which allocation succeeded for A. EXCLUDE_OLD_RELOAD is true if we should always return false for non-LRA targets. (This is a hack and should be removed along with old reload.) */ inline bool ira_subloop_allocnos_can_differ_p (ira_allocno_t a, bool allocated_p = true, bool exclude_old_reload = true) { if (exclude_old_reload && !ira_use_lra_p) return false; auto regno = ALLOCNO_REGNO (a); if (pic_offset_table_rtx != NULL && regno == (int) REGNO (pic_offset_table_rtx)) return false; ira_assert (regno < ira_reg_equiv_len); if (ira_equiv_no_lvalue_p (regno)) return false; /* Avoid overlapping multi-registers. Moves between them might result in wrong code generation. */ if (allocated_p) { auto pclass = ira_pressure_class_translate[ALLOCNO_CLASS (a)]; if (ira_reg_class_max_nregs[pclass][ALLOCNO_MODE (a)] > 1) return false; } return true; } /* Return true if we should treat A and SUBLOOP_A as belonging to a single region. */ inline bool ira_single_region_allocno_p (ira_allocno_t a, ira_allocno_t subloop_a) { if (flag_ira_region != IRA_REGION_MIXED) return false; if (ALLOCNO_MIGHT_CONFLICT_WITH_PARENT_P (subloop_a)) return false; auto rclass = ALLOCNO_CLASS (a); auto pclass = ira_pressure_class_translate[rclass]; auto loop_used_regs = ALLOCNO_LOOP_TREE_NODE (a)->reg_pressure[pclass]; return loop_used_regs <= ira_class_hard_regs_num[pclass]; } /* Return the set of all hard registers that conflict with A. */ inline HARD_REG_SET ira_total_conflict_hard_regs (ira_allocno_t a) { auto obj_0 = ALLOCNO_OBJECT (a, 0); HARD_REG_SET conflicts = OBJECT_TOTAL_CONFLICT_HARD_REGS (obj_0); for (int i = 1; i < ALLOCNO_NUM_OBJECTS (a); i++) conflicts |= OBJECT_TOTAL_CONFLICT_HARD_REGS (ALLOCNO_OBJECT (a, i)); return conflicts; } /* Return the cost of saving a caller-saved register before each call in A's live range and restoring the same register after each call. */ inline int ira_caller_save_cost (ira_allocno_t a) { auto mode = ALLOCNO_MODE (a); auto rclass = ALLOCNO_CLASS (a); return (ALLOCNO_CALL_FREQ (a) * (ira_memory_move_cost[mode][rclass][0] + ira_memory_move_cost[mode][rclass][1])); } /* A and SUBLOOP_A are allocnos for the same pseudo register, with A's loop immediately enclosing SUBLOOP_A's loop. If we allocate to A a hard register R that is clobbered by a call in SUBLOOP_A, decide which of the following approaches should be used for handling the conflict: (1) Spill R on entry to SUBLOOP_A's loop, assign memory to SUBLOOP_A, and restore R on exit from SUBLOOP_A's loop. (2) Spill R before each necessary call in SUBLOOP_A's live range and restore R after each such call. Return true if (1) is better than (2). SPILL_COST is the cost of doing (1). */ inline bool ira_caller_save_loop_spill_p (ira_allocno_t a, ira_allocno_t subloop_a, int spill_cost) { if (!ira_subloop_allocnos_can_differ_p (a)) return false; /* Calculate the cost of saving a call-clobbered register before each call and restoring it afterwards. */ int call_cost = ira_caller_save_cost (subloop_a); return call_cost && call_cost >= spill_cost; } #endif /* GCC_IRA_INT_H */