mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-01-11 21:00:17 +01:00
lima: ppir: optimize branches
Implement 2 optimizations for branches: 1) if unconditional branch target is a block that only has unconditional branch, propagate the target 2) optimize following contruction: block 1: ... if (cond) block 3 block 2: branch block N block 3: ... into block 1: ... if (!cond) block N block 2: block 3: ... Note: optimization 1) significantly improves runtime of if ladders, but it is not visible in shader-db because we do not track shortest/longest path and it doesn't always create dead code (usually just a single instruction) Reviewed-by: Erico Nunes <nunes.erico@gmail.com> Signed-off-by: Vasily Khoruzhick <anarsoul@gmail.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/33754>
This commit is contained in:
parent
69b119bc00
commit
fa9ddbe82b
1 changed files with 144 additions and 6 deletions
|
|
@ -43,16 +43,24 @@ static bool ppir_block_succ_is_seq(ppir_block *pred, ppir_block *succ)
|
|||
|
||||
static void ppir_block_update_successor(ppir_block *pred,
|
||||
ppir_block *old_succ,
|
||||
ppir_block *new_succ)
|
||||
ppir_block *new_succ,
|
||||
bool invert_cond)
|
||||
{
|
||||
list_for_each_entry_safe(ppir_node, node, &pred->node_list, list) {
|
||||
if (node->op == ppir_op_branch) {
|
||||
ppir_branch_node *branch = ppir_node_to_branch(node);
|
||||
if (branch->target == old_succ)
|
||||
branch->target = new_succ;
|
||||
if (invert_cond) {
|
||||
assert(ppir_node_get_src_num(node) == 2);
|
||||
branch->cond_eq = !branch->cond_eq;
|
||||
branch->cond_gt = !branch->cond_gt;
|
||||
branch->cond_lt = !branch->cond_lt;
|
||||
}
|
||||
if (branch->target == NULL) {
|
||||
/* We can only remove unconditional branches */
|
||||
assert(ppir_node_get_src_num(node) == 0);
|
||||
ppir_debug("ppir_block_update_successor: deleting branch %d\n", node->index);
|
||||
ppir_node_delete(node);
|
||||
}
|
||||
}
|
||||
|
|
@ -63,7 +71,7 @@ static void ppir_block_update_successor(ppir_block *pred,
|
|||
pred->successors[i] = new_succ;
|
||||
}
|
||||
|
||||
if (!new_succ)
|
||||
if (!pred->successors[0] && !pred->successors[1])
|
||||
pred->stop = true;
|
||||
}
|
||||
|
||||
|
|
@ -75,7 +83,7 @@ static bool ppir_propagate_block_successors(ppir_compiler *comp)
|
|||
if (block->successors[i] && ppir_block_is_empty(block->successors[i])) {
|
||||
ppir_block *succ_block = block->successors[i];
|
||||
assert(!succ_block->successors[1]);
|
||||
ppir_block_update_successor(block, block->successors[i], succ_block->successors[0]);
|
||||
ppir_block_update_successor(block, block->successors[i], succ_block->successors[0], false);
|
||||
progress = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -83,6 +91,14 @@ static bool ppir_propagate_block_successors(ppir_compiler *comp)
|
|||
return progress;
|
||||
}
|
||||
|
||||
static void ppir_renumber_blocks(ppir_compiler *comp)
|
||||
{
|
||||
int index = 0;
|
||||
list_for_each_entry(ppir_block, block, &comp->block_list, list) {
|
||||
block->index = index++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Removes empty blocks */
|
||||
static bool ppir_remove_empty_blocks(ppir_compiler *comp)
|
||||
{
|
||||
|
|
@ -102,6 +118,9 @@ static bool ppir_remove_empty_blocks(ppir_compiler *comp)
|
|||
}
|
||||
}
|
||||
|
||||
if (progress)
|
||||
ppir_renumber_blocks(comp);
|
||||
|
||||
return progress;
|
||||
}
|
||||
|
||||
|
|
@ -251,10 +270,91 @@ static bool ppir_node_has_succ(ppir_compiler *comp, ppir_node *node)
|
|||
return false;
|
||||
}
|
||||
|
||||
/* Must be run after ppir_renumber_blocks() */
|
||||
static bool ppir_opt_cond_branch(ppir_compiler *comp)
|
||||
{
|
||||
/* Walk blocks in order, find a block with two successors. It's always a
|
||||
* block with an conditional branch. One of the successors is a target of
|
||||
* the branch, and the other is sequential successor. Let's call them
|
||||
* seq_succ and branch_succ. If branch_succ->index == seq_succ->index + 1,
|
||||
* and branch_succ contains just an unconditional branch (let's call it
|
||||
* branch2), we can inverse condition of branch, update its target to
|
||||
* target of branch2 and drop seq_succ block.
|
||||
*/
|
||||
bool progress = false;
|
||||
list_for_each_entry(ppir_block, block, &comp->block_list, list) {
|
||||
if (!block->successors[1] || !block->successors[0])
|
||||
continue;
|
||||
|
||||
if ((block->index + 1) != block->successors[0]->index)
|
||||
continue;
|
||||
|
||||
if ((block->successors[0]->index + 1) != block->successors[1]->index)
|
||||
continue;
|
||||
|
||||
if (!list_is_singular(&block->successors[0]->node_list))
|
||||
continue;
|
||||
|
||||
ppir_node *node = ppir_block_first_node(block->successors[0]);
|
||||
if (node->op != ppir_op_branch)
|
||||
continue;
|
||||
|
||||
if (ppir_node_get_src_num(node) != 0)
|
||||
continue;
|
||||
|
||||
ppir_block *seq_succ = block->successors[0];
|
||||
ppir_block *branch_succ = block->successors[1];
|
||||
ppir_branch_node *branch2 = ppir_node_to_branch(node);
|
||||
ppir_block_update_successor(block, branch_succ, branch2->target, true);
|
||||
ppir_block_update_successor(block, seq_succ, branch_succ, false);
|
||||
ppir_debug("ppir_opt_cond_branch: deleting branch %d\n", node->index);
|
||||
ppir_node_delete(node);
|
||||
ppir_block *old_succ = branch2->target;
|
||||
ppir_block_update_successor(seq_succ, old_succ, branch_succ, false);
|
||||
|
||||
progress = true;
|
||||
}
|
||||
|
||||
return progress;
|
||||
}
|
||||
|
||||
static bool ppir_opt_propagate_branch_target(ppir_compiler *comp)
|
||||
{
|
||||
bool progress = false;
|
||||
|
||||
/* Check if branch targets a block that has a single unconditional branch
|
||||
* and update branch target in this case
|
||||
*/
|
||||
list_for_each_entry(ppir_block, block, &comp->block_list, list) {
|
||||
list_for_each_entry(ppir_node, node, &block->node_list, list) {
|
||||
if (node->op != ppir_op_branch)
|
||||
continue;
|
||||
|
||||
ppir_branch_node *branch = ppir_node_to_branch(node);
|
||||
ppir_block *target = branch->target;
|
||||
|
||||
if (!list_is_singular(&target->node_list))
|
||||
continue;
|
||||
|
||||
ppir_node *node2 = ppir_block_first_node(target);
|
||||
if (node2->op != ppir_op_branch)
|
||||
continue;
|
||||
if (ppir_node_get_src_num(node2))
|
||||
continue;
|
||||
|
||||
ppir_branch_node *branch2 = ppir_node_to_branch(node2);
|
||||
ppir_block_update_successor(block, branch->target, branch2->target, false);
|
||||
progress = true;
|
||||
}
|
||||
}
|
||||
|
||||
return progress;
|
||||
}
|
||||
|
||||
/* Dead code elimination */
|
||||
static bool ppir_dce(ppir_compiler *comp)
|
||||
{
|
||||
|
||||
/* Delete root nodes with no successors */
|
||||
list_for_each_entry(ppir_block, block, &comp->block_list, list) {
|
||||
list_for_each_entry_safe(ppir_node, node, &block->node_list, list) {
|
||||
if (ppir_node_is_root(node) && !ppir_node_has_succ(comp, node)) {
|
||||
|
|
@ -265,9 +365,41 @@ static bool ppir_dce(ppir_compiler *comp)
|
|||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
if (list_is_singular(&comp->block_list))
|
||||
return false;
|
||||
|
||||
/* Delete unreacheable blocks */
|
||||
int num_blocks = list_length(&comp->block_list);
|
||||
BITSET_WORD *reachable = rzalloc_array(comp, BITSET_WORD, num_blocks);
|
||||
/* Block 0 is entry, it is always reachable */
|
||||
BITSET_SET(reachable, 0);
|
||||
/* Discard block is always reachable */
|
||||
if (comp->uses_discard)
|
||||
BITSET_SET(reachable, comp->discard_block->index);
|
||||
list_for_each_entry(ppir_block, block, &comp->block_list, list) {
|
||||
for (int i = 0; i < 2; i++) {
|
||||
if (!block->successors[i])
|
||||
continue;
|
||||
BITSET_SET(reachable, block->successors[i]->index);
|
||||
}
|
||||
}
|
||||
|
||||
bool progress = false;
|
||||
list_for_each_entry(ppir_block, block, &comp->block_list, list) {
|
||||
if (BITSET_TEST(reachable, block->index))
|
||||
continue;
|
||||
list_for_each_entry_safe_rev(ppir_node, node, &block->node_list, list) {
|
||||
ppir_debug("DCE: deleting node %d\n", node->index);
|
||||
ppir_node_delete(node);
|
||||
progress = true;
|
||||
}
|
||||
}
|
||||
|
||||
ralloc_free(reachable);
|
||||
return progress;
|
||||
}
|
||||
|
||||
|
||||
bool ppir_opt_prog(ppir_compiler *comp)
|
||||
{
|
||||
bool progress;
|
||||
|
|
@ -278,7 +410,13 @@ bool ppir_opt_prog(ppir_compiler *comp)
|
|||
} while (progress);
|
||||
|
||||
do {
|
||||
progress = ppir_remove_empty_blocks(comp);
|
||||
progress = ppir_opt_propagate_branch_target(comp);
|
||||
progress |= ppir_opt_cond_branch(comp);
|
||||
progress |= ppir_remove_empty_blocks(comp);
|
||||
} while (progress);
|
||||
|
||||
do {
|
||||
progress = ppir_remove_empty_blocks(comp);
|
||||
progress |= ppir_dce(comp);
|
||||
} while (progress);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue