return REG_FREQ_FROM_EDGE_FREQ (freq);
}
+/* Construct an object that describes the boundary between A and its
+ parent allocno. */
+ira_loop_border_costs::ira_loop_border_costs (ira_allocno_t a)
+ : m_mode (ALLOCNO_MODE (a)),
+ m_class (ALLOCNO_CLASS (a)),
+ m_entry_freq (ira_loop_edge_freq (ALLOCNO_LOOP_TREE_NODE (a),
+ ALLOCNO_REGNO (a), false)),
+ m_exit_freq (ira_loop_edge_freq (ALLOCNO_LOOP_TREE_NODE (a),
+ ALLOCNO_REGNO (a), true))
+{
+}
+
/* Calculate and return the cost of putting allocno A into memory. */
static int
calculate_allocno_spill_cost (ira_allocno_t a)
{
int regno, cost;
- machine_mode mode;
- enum reg_class rclass;
ira_allocno_t parent_allocno;
ira_loop_tree_node_t parent_node, loop_node;
return cost;
if ((parent_allocno = parent_node->regno_allocno_map[regno]) == NULL)
return cost;
- mode = ALLOCNO_MODE (a);
- rclass = ALLOCNO_CLASS (a);
+ ira_loop_border_costs border_costs (a);
if (ALLOCNO_HARD_REGNO (parent_allocno) < 0)
- cost -= (ira_memory_move_cost[mode][rclass][0]
- * ira_loop_edge_freq (loop_node, regno, true)
- + ira_memory_move_cost[mode][rclass][1]
- * ira_loop_edge_freq (loop_node, regno, false));
+ cost -= border_costs.spill_outside_loop_cost ();
else
- {
- ira_init_register_move_cost_if_necessary (mode);
- cost += ((ira_memory_move_cost[mode][rclass][1]
- * ira_loop_edge_freq (loop_node, regno, true)
- + ira_memory_move_cost[mode][rclass][0]
- * ira_loop_edge_freq (loop_node, regno, false))
- - (ira_register_move_cost[mode][rclass][rclass]
- * (ira_loop_edge_freq (loop_node, regno, false)
- + ira_loop_edge_freq (loop_node, regno, true))));
- }
+ cost += (border_costs.spill_inside_loop_cost ()
+ - border_costs.move_between_loops_cost ());
return cost;
}
color_pass (ira_loop_tree_node_t loop_tree_node)
{
int regno, hard_regno, index = -1, n;
- int cost, exit_freq, enter_freq;
+ int cost;
unsigned int j;
bitmap_iterator bi;
machine_mode mode;
}
continue;
}
- exit_freq = ira_loop_edge_freq (subloop_node, regno, true);
- enter_freq = ira_loop_edge_freq (subloop_node, regno, false);
ira_assert (regno < ira_reg_equiv_len);
if (ira_equiv_no_lvalue_p (regno))
{
}
else if (hard_regno < 0)
{
+ ira_loop_border_costs border_costs (subloop_allocno);
ALLOCNO_UPDATED_MEMORY_COST (subloop_allocno)
- -= ((ira_memory_move_cost[mode][rclass][1] * enter_freq)
- + (ira_memory_move_cost[mode][rclass][0] * exit_freq));
+ -= border_costs.spill_outside_loop_cost ();
}
else
{
+ ira_loop_border_costs border_costs (subloop_allocno);
aclass = ALLOCNO_CLASS (subloop_allocno);
ira_init_register_move_cost_if_necessary (mode);
- cost = (ira_register_move_cost[mode][rclass][rclass]
- * (exit_freq + enter_freq));
+ cost = border_costs.move_between_loops_cost ();
ira_allocate_and_set_or_copy_costs
(&ALLOCNO_UPDATED_HARD_REG_COSTS (subloop_allocno), aclass,
ALLOCNO_UPDATED_CLASS_COST (subloop_allocno),
ALLOCNO_UPDATED_CLASS_COST (subloop_allocno)
= ALLOCNO_UPDATED_HARD_REG_COSTS (subloop_allocno)[index];
ALLOCNO_UPDATED_MEMORY_COST (subloop_allocno)
- += (ira_memory_move_cost[mode][rclass][0] * enter_freq
- + ira_memory_move_cost[mode][rclass][1] * exit_freq);
+ += border_costs.spill_inside_loop_cost ();
}
}
}
{
int cost, regno, hard_regno, hard_regno2, index;
bool changed_p;
- int enter_freq, exit_freq;
machine_mode mode;
enum reg_class rclass;
ira_allocno_t a, parent_allocno, subloop_allocno;
- (ALLOCNO_HARD_REG_COSTS (subloop_allocno) == NULL
? ALLOCNO_CLASS_COST (subloop_allocno)
: ALLOCNO_HARD_REG_COSTS (subloop_allocno)[index]));
- exit_freq = ira_loop_edge_freq (subloop_node, regno, true);
- enter_freq = ira_loop_edge_freq (subloop_node, regno, false);
+ ira_loop_border_costs border_costs (subloop_allocno);
if ((hard_regno2 = ALLOCNO_HARD_REGNO (subloop_allocno)) < 0)
- cost -= (ira_memory_move_cost[mode][rclass][0] * exit_freq
- + ira_memory_move_cost[mode][rclass][1] * enter_freq);
+ cost -= border_costs.spill_outside_loop_cost ();
else
{
- cost
- += (ira_memory_move_cost[mode][rclass][0] * exit_freq
- + ira_memory_move_cost[mode][rclass][1] * enter_freq);
+ cost += border_costs.spill_outside_loop_cost ();
if (hard_regno2 != hard_regno)
- cost -= (ira_register_move_cost[mode][rclass][rclass]
- * (exit_freq + enter_freq));
+ cost -= border_costs.move_between_loops_cost ();
}
}
if ((parent = loop_node->parent) != NULL
&& (parent_allocno = parent->regno_allocno_map[regno]) != NULL)
{
ira_assert (rclass == ALLOCNO_CLASS (parent_allocno));
- exit_freq = ira_loop_edge_freq (loop_node, regno, true);
- enter_freq = ira_loop_edge_freq (loop_node, regno, false);
+ ira_loop_border_costs border_costs (a);
if ((hard_regno2 = ALLOCNO_HARD_REGNO (parent_allocno)) < 0)
- cost -= (ira_memory_move_cost[mode][rclass][0] * exit_freq
- + ira_memory_move_cost[mode][rclass][1] * enter_freq);
+ cost -= border_costs.spill_outside_loop_cost ();
else
{
- cost
- += (ira_memory_move_cost[mode][rclass][1] * exit_freq
- + ira_memory_move_cost[mode][rclass][0] * enter_freq);
+ cost += border_costs.spill_inside_loop_cost ();
if (hard_regno2 != hard_regno)
- cost -= (ira_register_move_cost[mode][rclass][rclass]
- * (exit_freq + enter_freq));
+ cost -= border_costs.move_between_loops_cost ();
}
}
if (cost < 0)
ALLOCNO_MODE (a), regno);
}
+/* Represents the boundary between an allocno in one loop and its parent
+ allocno in the enclosing loop. It is usually possible to change a
+ register's allocation on this boundary; the class provides routines
+ for calculating the cost of such changes. */
+class ira_loop_border_costs
+{
+public:
+ ira_loop_border_costs (ira_allocno_t);
+
+ int move_between_loops_cost () const;
+ int spill_outside_loop_cost () const;
+ int spill_inside_loop_cost () const;
+
+private:
+ /* The mode and class of the child allocno. */
+ machine_mode m_mode;
+ reg_class m_class;
+
+ /* Sums the frequencies 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);
+}
+
#endif /* GCC_IRA_INT_H */