i965/fs: Improve performance of copy/constant propagation.

Use a simple chaining hash table for the ACP.  This is not really very good,
because we still do a full walk of the tree per destination write, but it
still reduces fp-long-alu runtime from 5.3 to 3.9s.

Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
This commit is contained in:
Eric Anholt 2012-09-21 16:06:17 +02:00
parent fb5bf03a20
commit 6a514494fa
2 changed files with 30 additions and 18 deletions

View file

@ -246,8 +246,7 @@ public:
bool opt_copy_propagate();
bool try_copy_propagate(fs_inst *inst, int arg, acp_entry *entry);
bool try_constant_propagate(fs_inst *inst, acp_entry *entry);
bool opt_copy_propagate_local(void *mem_ctx, fs_bblock *block,
exec_list *acp);
bool opt_copy_propagate_local(void *mem_ctx, fs_bblock *block);
bool register_coalesce();
bool register_coalesce_2();
bool compute_to_mrf();

View file

@ -195,38 +195,52 @@ fs_visitor::try_constant_propagate(fs_inst *inst, acp_entry *entry)
* list.
*/
bool
fs_visitor::opt_copy_propagate_local(void *mem_ctx,
fs_bblock *block, exec_list *acp)
fs_visitor::opt_copy_propagate_local(void *mem_ctx, fs_bblock *block)
{
bool progress = false;
int acp_count = 16;
exec_list acp[acp_count];
for (fs_inst *inst = block->start;
inst != block->end->next;
inst = (fs_inst *)inst->next) {
/* Try propagating into this instruction. */
foreach_list(entry_node, acp) {
acp_entry *entry = (acp_entry *)entry_node;
for (int i = 0; i < 3; i++) {
if (inst->src[i].file != GRF)
continue;
if (try_constant_propagate(inst, entry))
progress = true;
foreach_list(entry_node, &acp[inst->src[i].reg % acp_count]) {
acp_entry *entry = (acp_entry *)entry_node;
for (int i = 0; i < 3; i++) {
if (try_copy_propagate(inst, i, entry))
progress = true;
}
if (try_constant_propagate(inst, entry))
progress = true;
if (try_copy_propagate(inst, i, entry))
progress = true;
}
}
/* kill the destination from the ACP */
if (inst->dst.file == GRF) {
foreach_list_safe(entry_node, acp) {
foreach_list_safe(entry_node, &acp[inst->dst.reg % acp_count]) {
acp_entry *entry = (acp_entry *)entry_node;
if (inst->overwrites_reg(entry->dst) ||
inst->overwrites_reg(entry->src)) {
if (inst->overwrites_reg(entry->dst)) {
entry->remove();
}
}
/* Oops, we only have the chaining hash based on the destination, not
* the source, so walk across the entire table.
*/
for (int i = 0; i < acp_count; i++) {
foreach_list_safe(entry_node, &acp[i]) {
acp_entry *entry = (acp_entry *)entry_node;
if (inst->overwrites_reg(entry->src))
entry->remove();
}
}
}
/* If this instruction is a raw copy, add it to the ACP. */
@ -246,7 +260,7 @@ fs_visitor::opt_copy_propagate_local(void *mem_ctx,
acp_entry *entry = ralloc(mem_ctx, acp_entry);
entry->dst = inst->dst;
entry->src = inst->src[0];
acp->push_tail(entry);
acp[entry->dst.reg % acp_count].push_tail(entry);
}
}
@ -263,9 +277,8 @@ fs_visitor::opt_copy_propagate()
for (int b = 0; b < cfg.num_blocks; b++) {
fs_bblock *block = cfg.blocks[b];
exec_list acp;
progress = opt_copy_propagate_local(mem_ctx, block, &acp) || progress;
progress = opt_copy_propagate_local(mem_ctx, block) || progress;
}
ralloc_free(mem_ctx);