Commit 927425df by Vladimir Makarov Committed by Vladimir Makarov

re PR rtl-optimization/37397 (IRA performance impact on SPEC CPU 2K/2006)

2008-11-14  Vladimir Makarov  <vmakarov@redhat.com>

	PR rtl-optimization/37397
	* ira-int.h (struct ira_allocno): New member bad_spill_p.
	(ALLOCNO_BAD_SPILL_P): New macro.

	* ira-color.c (push_allocnos_to_stack): Check ALLOCNO_BAD_SPILL_P.

	* ira-build.c (ira_create_allocno): Initialize
	ALLOCNO_BAD_SPILL_P.
	(create_cap_allocno, propagate_allocno_info,
	remove_unnecessary_allocnos): Set up or update
	ALLOCNO_BAD_SPILL_P.
	(update_bad_spill_attribute): New function.
	(ira_build): Call it.

	* ira-costs.c (record_reg_classes): Set up ALLOCNO_BAD_SPILL_P.

From-SVN: r141860
parent 487e299b
2008-11-14 Vladimir Makarov <vmakarov@redhat.com>
PR rtl-optimization/37397
* ira-int.h (struct ira_allocno): New member bad_spill_p.
(ALLOCNO_BAD_SPILL_P): New macro.
* ira-color.c (push_allocnos_to_stack): Check ALLOCNO_BAD_SPILL_P.
* ira-build.c (ira_create_allocno): Initialize
ALLOCNO_BAD_SPILL_P.
(create_cap_allocno, propagate_allocno_info,
remove_unnecessary_allocnos): Set up or update
ALLOCNO_BAD_SPILL_P.
(update_bad_spill_attribute): New function.
(ira_build): Call it.
* ira-costs.c (record_reg_classes): Set up ALLOCNO_BAD_SPILL_P.
2008-11-14 Jakub Jelinek <jakub@redhat.com> 2008-11-14 Jakub Jelinek <jakub@redhat.com>
PR tree-optimization/38104 PR tree-optimization/38104
......
...@@ -456,6 +456,7 @@ ira_create_allocno (int regno, bool cap_p, ira_loop_tree_node_t loop_tree_node) ...@@ -456,6 +456,7 @@ ira_create_allocno (int regno, bool cap_p, ira_loop_tree_node_t loop_tree_node)
ALLOCNO_SOMEWHERE_RENAMED_P (a) = false; ALLOCNO_SOMEWHERE_RENAMED_P (a) = false;
ALLOCNO_CHILD_RENAMED_P (a) = false; ALLOCNO_CHILD_RENAMED_P (a) = false;
ALLOCNO_DONT_REASSIGN_P (a) = false; ALLOCNO_DONT_REASSIGN_P (a) = false;
ALLOCNO_BAD_SPILL_P (a) = false;
ALLOCNO_IN_GRAPH_P (a) = false; ALLOCNO_IN_GRAPH_P (a) = false;
ALLOCNO_ASSIGNED_P (a) = false; ALLOCNO_ASSIGNED_P (a) = false;
ALLOCNO_MAY_BE_SPILLED_P (a) = false; ALLOCNO_MAY_BE_SPILLED_P (a) = false;
...@@ -775,6 +776,7 @@ create_cap_allocno (ira_allocno_t a) ...@@ -775,6 +776,7 @@ create_cap_allocno (ira_allocno_t a)
ira_allocate_and_copy_costs ira_allocate_and_copy_costs
(&ALLOCNO_CONFLICT_HARD_REG_COSTS (cap), cover_class, (&ALLOCNO_CONFLICT_HARD_REG_COSTS (cap), cover_class,
ALLOCNO_CONFLICT_HARD_REG_COSTS (a)); ALLOCNO_CONFLICT_HARD_REG_COSTS (a));
ALLOCNO_BAD_SPILL_P (cap) = ALLOCNO_BAD_SPILL_P (a);
ALLOCNO_NREFS (cap) = ALLOCNO_NREFS (a); ALLOCNO_NREFS (cap) = ALLOCNO_NREFS (a);
ALLOCNO_FREQ (cap) = ALLOCNO_FREQ (a); ALLOCNO_FREQ (cap) = ALLOCNO_FREQ (a);
ALLOCNO_CALL_FREQ (cap) = ALLOCNO_CALL_FREQ (a); ALLOCNO_CALL_FREQ (cap) = ALLOCNO_CALL_FREQ (a);
...@@ -1490,6 +1492,8 @@ propagate_allocno_info (void) ...@@ -1490,6 +1492,8 @@ propagate_allocno_info (void)
&& bitmap_bit_p (ALLOCNO_LOOP_TREE_NODE (a)->border_allocnos, && bitmap_bit_p (ALLOCNO_LOOP_TREE_NODE (a)->border_allocnos,
ALLOCNO_NUM (a))) ALLOCNO_NUM (a)))
{ {
if (! ALLOCNO_BAD_SPILL_P (a))
ALLOCNO_BAD_SPILL_P (parent_a) = false;
ALLOCNO_NREFS (parent_a) += ALLOCNO_NREFS (a); ALLOCNO_NREFS (parent_a) += ALLOCNO_NREFS (a);
ALLOCNO_FREQ (parent_a) += ALLOCNO_FREQ (a); ALLOCNO_FREQ (parent_a) += ALLOCNO_FREQ (a);
ALLOCNO_CALL_FREQ (parent_a) += ALLOCNO_CALL_FREQ (a); ALLOCNO_CALL_FREQ (parent_a) += ALLOCNO_CALL_FREQ (a);
...@@ -1777,6 +1781,8 @@ remove_unnecessary_allocnos (void) ...@@ -1777,6 +1781,8 @@ remove_unnecessary_allocnos (void)
+= ALLOCNO_CALLS_CROSSED_NUM (a); += ALLOCNO_CALLS_CROSSED_NUM (a);
ALLOCNO_EXCESS_PRESSURE_POINTS_NUM (parent_a) ALLOCNO_EXCESS_PRESSURE_POINTS_NUM (parent_a)
+= ALLOCNO_EXCESS_PRESSURE_POINTS_NUM (a); += ALLOCNO_EXCESS_PRESSURE_POINTS_NUM (a);
if (! ALLOCNO_BAD_SPILL_P (a))
ALLOCNO_BAD_SPILL_P (parent_a) = false;
#ifdef STACK_REGS #ifdef STACK_REGS
if (ALLOCNO_TOTAL_NO_STACK_REG_P (a)) if (ALLOCNO_TOTAL_NO_STACK_REG_P (a))
ALLOCNO_TOTAL_NO_STACK_REG_P (parent_a) = true; ALLOCNO_TOTAL_NO_STACK_REG_P (parent_a) = true;
...@@ -1825,6 +1831,69 @@ remove_unnecessary_regions (void) ...@@ -1825,6 +1831,69 @@ remove_unnecessary_regions (void)
/* At this point true value of allocno attribute bad_spill_p means
that there is an insn where allocno occurs and where the allocno
can not be used as memory. The function updates the attribute, now
it can be true only for allocnos which can not be used as memory in
an insn and in whose live ranges there is other allocno deaths.
Spilling allocnos with true value will not improve the code because
it will not make other allocnos colorable and additional reloads
for the corresponding pseudo will be generated in reload pass for
each insn it occurs.
This is a trick mentioned in one classic article of Chaitin etc
which is frequently omitted in other implementations of RA based on
graph coloring. */
static void
update_bad_spill_attribute (void)
{
int i;
ira_allocno_t a;
ira_allocno_iterator ai;
allocno_live_range_t r;
enum reg_class cover_class;
bitmap_head dead_points[N_REG_CLASSES];
for (i = 0; i < ira_reg_class_cover_size; i++)
{
cover_class = ira_reg_class_cover[i];
bitmap_initialize (&dead_points[cover_class], &reg_obstack);
}
FOR_EACH_ALLOCNO (a, ai)
{
cover_class = ALLOCNO_COVER_CLASS (a);
if (cover_class == NO_REGS)
continue;
for (r = ALLOCNO_LIVE_RANGES (a); r != NULL; r = r->next)
bitmap_set_bit (&dead_points[cover_class], r->finish);
}
FOR_EACH_ALLOCNO (a, ai)
{
cover_class = ALLOCNO_COVER_CLASS (a);
if (cover_class == NO_REGS)
continue;
if (! ALLOCNO_BAD_SPILL_P (a))
continue;
for (r = ALLOCNO_LIVE_RANGES (a); r != NULL; r = r->next)
{
for (i = r->start + 1; i < r->finish; i++)
if (bitmap_bit_p (&dead_points[cover_class], i))
break;
if (i < r->finish)
break;
}
if (r != NULL)
ALLOCNO_BAD_SPILL_P (a) = false;
}
for (i = 0; i < ira_reg_class_cover_size; i++)
{
cover_class = ira_reg_class_cover[i];
bitmap_clear (&dead_points[cover_class]);
}
}
/* Set up minimal and maximal live range points for allocnos. */ /* Set up minimal and maximal live range points for allocnos. */
static void static void
setup_min_max_allocno_live_range_point (void) setup_min_max_allocno_live_range_point (void)
...@@ -2438,6 +2507,7 @@ ira_build (bool loops_p) ...@@ -2438,6 +2507,7 @@ ira_build (bool loops_p)
ira_create_allocno_live_ranges (); ira_create_allocno_live_ranges ();
remove_unnecessary_regions (); remove_unnecessary_regions ();
ira_compress_allocno_live_ranges (); ira_compress_allocno_live_ranges ();
update_bad_spill_attribute ();
loops_p = more_one_region_p (); loops_p = more_one_region_p ();
if (loops_p) if (loops_p)
{ {
......
...@@ -1187,7 +1187,10 @@ push_allocnos_to_stack (void) ...@@ -1187,7 +1187,10 @@ push_allocnos_to_stack (void)
* ira_reg_class_nregs[ALLOCNO_COVER_CLASS * ira_reg_class_nregs[ALLOCNO_COVER_CLASS
(i_allocno)] (i_allocno)]
[ALLOCNO_MODE (i_allocno)] + 1)); [ALLOCNO_MODE (i_allocno)] + 1));
if (allocno == NULL || allocno_pri > i_allocno_pri if (allocno == NULL
|| (! ALLOCNO_BAD_SPILL_P (i_allocno)
&& ALLOCNO_BAD_SPILL_P (allocno))
|| allocno_pri > i_allocno_pri
|| (allocno_pri == i_allocno_pri || (allocno_pri == i_allocno_pri
&& (allocno_cost > i_allocno_cost && (allocno_cost > i_allocno_cost
|| (allocno_cost == i_allocno_cost || (allocno_cost == i_allocno_cost
......
...@@ -187,6 +187,10 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops, ...@@ -187,6 +187,10 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops,
int alt; int alt;
int i, j, k; int i, j, k;
rtx set; rtx set;
int insn_allows_mem[MAX_RECOG_OPERANDS];
for (i = 0; i < n_ops; i++)
insn_allows_mem[i] = 0;
/* Process each alternative, each time minimizing an operand's cost /* Process each alternative, each time minimizing an operand's cost
with the cost for each operand in that alternative. */ with the cost for each operand in that alternative. */
...@@ -236,6 +240,8 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops, ...@@ -236,6 +240,8 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops,
j = p[0] - '0'; j = p[0] - '0';
classes[i] = classes[j]; classes[i] = classes[j];
allows_mem[i] = allows_mem[j]; allows_mem[i] = allows_mem[j];
if (allows_mem[i])
insn_allows_mem[i] = 1;
if (! REG_P (op) || REGNO (op) < FIRST_PSEUDO_REGISTER) if (! REG_P (op) || REGNO (op) < FIRST_PSEUDO_REGISTER)
{ {
...@@ -302,6 +308,7 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops, ...@@ -302,6 +308,7 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops,
+ (recog_data.operand_type[i] != OP_OUT + (recog_data.operand_type[i] != OP_OUT
? ira_memory_move_cost[mode][classes[i]][1] : 0) ? ira_memory_move_cost[mode][classes[i]][1] : 0)
- allows_mem[i]) * frequency; - allows_mem[i]) * frequency;
/* If we have assigned a class to this allocno in our /* If we have assigned a class to this allocno in our
first pass, add a cost to this alternative first pass, add a cost to this alternative
corresponding to what we would add if this allocno corresponding to what we would add if this allocno
...@@ -380,7 +387,7 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops, ...@@ -380,7 +387,7 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops,
/* It doesn't seem worth distinguishing between /* It doesn't seem worth distinguishing between
offsettable and non-offsettable addresses offsettable and non-offsettable addresses
here. */ here. */
allows_mem[i] = 1; insn_allows_mem[i] = allows_mem[i] = 1;
if (MEM_P (op)) if (MEM_P (op))
win = 1; win = 1;
break; break;
...@@ -456,7 +463,7 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops, ...@@ -456,7 +463,7 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops,
|| (CONSTANT_P (op) || (CONSTANT_P (op)
&& (! flag_pic || LEGITIMATE_PIC_OPERAND_P (op)))) && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (op))))
win = 1; win = 1;
allows_mem[i] = 1; insn_allows_mem[i] = allows_mem[i] = 1;
case 'r': case 'r':
classes[i] = ira_reg_class_union[classes[i]][GENERAL_REGS]; classes[i] = ira_reg_class_union[classes[i]][GENERAL_REGS];
break; break;
...@@ -472,7 +479,7 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops, ...@@ -472,7 +479,7 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops,
if (EXTRA_MEMORY_CONSTRAINT (c, p)) if (EXTRA_MEMORY_CONSTRAINT (c, p))
{ {
/* Every MEM can be reloaded to fit. */ /* Every MEM can be reloaded to fit. */
allows_mem[i] = 1; insn_allows_mem[i] = allows_mem[i] = 1;
if (MEM_P (op)) if (MEM_P (op))
win = 1; win = 1;
} }
...@@ -625,6 +632,18 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops, ...@@ -625,6 +632,18 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops,
} }
} }
for (i = 0; i < n_ops; i++)
{
ira_allocno_t a;
rtx op = ops[i];
if (! REG_P (op) || REGNO (op) < FIRST_PSEUDO_REGISTER)
continue;
a = ira_curr_regno_allocno_map [REGNO (op)];
if (! ALLOCNO_BAD_SPILL_P (a) && insn_allows_mem[i] == 0)
ALLOCNO_BAD_SPILL_P (a) = true;
}
/* If this insn is a single set copying operand 1 to operand 0 and /* If this insn is a single set copying operand 1 to operand 0 and
one operand is an allocno with the other a hard reg or an allocno one operand is an allocno with the other a hard reg or an allocno
that prefers a hard register that is in its own register class that prefers a hard register that is in its own register class
...@@ -867,6 +886,7 @@ record_address_regs (enum machine_mode mode, rtx x, int context, ...@@ -867,6 +886,7 @@ record_address_regs (enum machine_mode mode, rtx x, int context,
if (REGNO (x) < FIRST_PSEUDO_REGISTER) if (REGNO (x) < FIRST_PSEUDO_REGISTER)
break; break;
ALLOCNO_BAD_SPILL_P (ira_curr_regno_allocno_map[REGNO (x)]) = true;
pp = COSTS_OF_ALLOCNO (allocno_costs, pp = COSTS_OF_ALLOCNO (allocno_costs,
ALLOCNO_NUM (ira_curr_regno_allocno_map ALLOCNO_NUM (ira_curr_regno_allocno_map
[REGNO (x)])); [REGNO (x)]));
......
...@@ -351,6 +351,10 @@ struct ira_allocno ...@@ -351,6 +351,10 @@ struct ira_allocno
region and all its subregions recursively. */ region and all its subregions recursively. */
unsigned int no_stack_reg_p : 1, total_no_stack_reg_p : 1; unsigned int no_stack_reg_p : 1, total_no_stack_reg_p : 1;
#endif #endif
/* TRUE value means that there is no sense to spill the allocno
during coloring because the spill will result in additional
reloads in reload pass. */
unsigned int bad_spill_p : 1;
/* TRUE value means that the allocno was not removed yet from the /* TRUE value means that the allocno was not removed yet from the
conflicting graph during colouring. */ conflicting graph during colouring. */
unsigned int in_graph_p : 1; unsigned int in_graph_p : 1;
...@@ -435,6 +439,7 @@ struct ira_allocno ...@@ -435,6 +439,7 @@ struct ira_allocno
#define ALLOCNO_NO_STACK_REG_P(A) ((A)->no_stack_reg_p) #define ALLOCNO_NO_STACK_REG_P(A) ((A)->no_stack_reg_p)
#define ALLOCNO_TOTAL_NO_STACK_REG_P(A) ((A)->total_no_stack_reg_p) #define ALLOCNO_TOTAL_NO_STACK_REG_P(A) ((A)->total_no_stack_reg_p)
#endif #endif
#define ALLOCNO_BAD_SPILL_P(A) ((A)->bad_spill_p)
#define ALLOCNO_IN_GRAPH_P(A) ((A)->in_graph_p) #define ALLOCNO_IN_GRAPH_P(A) ((A)->in_graph_p)
#define ALLOCNO_ASSIGNED_P(A) ((A)->assigned_p) #define ALLOCNO_ASSIGNED_P(A) ((A)->assigned_p)
#define ALLOCNO_MAY_BE_SPILLED_P(A) ((A)->may_be_spilled_p) #define ALLOCNO_MAY_BE_SPILLED_P(A) ((A)->may_be_spilled_p)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment