summaryrefslogtreecommitdiff
path: root/src/gallium/drivers
diff options
context:
space:
mode:
authorErico Nunes <nunes.erico@gmail.com>2022-04-26 11:09:24 +0200
committerMarge Bot <emma+marge@anholt.net>2022-05-23 09:07:03 +0000
commitc3f13ee5511501a350c2fba5ab3369e6bb5aa46c (patch)
tree1a5b38aa2d48be1ee73a0d52bde909202a97c2df /src/gallium/drivers
parent5718629a704ced0e3186ded2f39d51d28c0a1aa8 (diff)
lima/ppir: optimize branch comparison when possible
The branch operation supports comparisons, so it may be possible to merge a previous comparison operation with the branch operation. There are several restrictions to do it at this stage, but it may save instructions in many cases. Signed-off-by: Erico Nunes <nunes.erico@gmail.com> Reviewed-by: Vasily Khoruzhick <anarsoul@gmail.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/16163>
Diffstat (limited to 'src/gallium/drivers')
-rw-r--r--src/gallium/drivers/lima/ir/pp/lower.c103
1 files changed, 98 insertions, 5 deletions
diff --git a/src/gallium/drivers/lima/ir/pp/lower.c b/src/gallium/drivers/lima/ir/pp/lower.c
index deed1c7f2c9..6170297c1aa 100644
--- a/src/gallium/drivers/lima/ir/pp/lower.c
+++ b/src/gallium/drivers/lima/ir/pp/lower.c
@@ -322,6 +322,98 @@ static bool ppir_lower_sat(ppir_block *block, ppir_node *node)
return true;
}
+static bool ppir_lower_branch_merge_condition(ppir_block *block, ppir_node *node)
+{
+ /* Check if we can merge a condition with a branch instruction,
+ * removing the need for a select instruction */
+ assert(node->type == ppir_node_type_branch);
+
+ if (!ppir_node_has_single_pred(node))
+ return false;
+
+ ppir_node *pred = ppir_node_first_pred(node);
+ assert(pred);
+
+ if (pred->type != ppir_node_type_alu)
+ return false;
+
+ switch (pred->op)
+ {
+ case ppir_op_lt:
+ case ppir_op_gt:
+ case ppir_op_le:
+ case ppir_op_ge:
+ case ppir_op_eq:
+ case ppir_op_ne:
+ break;
+ default:
+ return false;
+ }
+
+ ppir_dest *dest = ppir_node_get_dest(pred);
+ if (!ppir_node_has_single_succ(pred) || dest->type != ppir_target_ssa)
+ return false;
+
+ ppir_alu_node *cond = ppir_node_to_alu(pred);
+ /* branch can't reference pipeline registers */
+ if (cond->src[0].type == ppir_target_pipeline ||
+ cond->src[1].type == ppir_target_pipeline)
+ return false;
+
+ /* branch can't use flags */
+ if (cond->src[0].negate || cond->src[0].absolute ||
+ cond->src[1].negate || cond->src[1].absolute)
+ return false;
+
+ /* at this point, it can be successfully be replaced. */
+ ppir_branch_node *branch = ppir_node_to_branch(node);
+ switch (pred->op)
+ {
+ case ppir_op_le:
+ branch->cond_gt = true;
+ break;
+ case ppir_op_lt:
+ branch->cond_eq = true;
+ branch->cond_gt = true;
+ break;
+ case ppir_op_ge:
+ branch->cond_lt = true;
+ break;
+ case ppir_op_gt:
+ branch->cond_eq = true;
+ branch->cond_lt = true;
+ break;
+ case ppir_op_eq:
+ branch->cond_lt = true;
+ branch->cond_gt = true;
+ break;
+ case ppir_op_ne:
+ branch->cond_eq = true;
+ break;
+ default:
+ assert(0);
+ break;
+ }
+
+ assert(cond->num_src == 2);
+
+ branch->num_src = 2;
+ branch->src[0] = cond->src[0];
+ branch->src[1] = cond->src[1];
+
+ /* for all nodes before the condition */
+ ppir_node_foreach_pred_safe(pred, dep) {
+ /* insert the branch node as successor */
+ ppir_node *p = dep->pred;
+ ppir_node_remove_dep(dep);
+ ppir_node_add_dep(node, p, ppir_dep_src);
+ }
+
+ ppir_node_delete(pred);
+
+ return true;
+}
+
static bool ppir_lower_branch(ppir_block *block, ppir_node *node)
{
ppir_branch_node *branch = ppir_node_to_branch(node);
@@ -330,6 +422,12 @@ static bool ppir_lower_branch(ppir_block *block, ppir_node *node)
if (branch->num_src == 0)
return true;
+ /* Check if we can merge a condition with the branch */
+ if (ppir_lower_branch_merge_condition(block, node))
+ return true;
+
+ /* If the condition cannot be merged, fall back to a
+ * comparison against zero */
ppir_const_node *zero = ppir_node_create(block, ppir_op_const, -1, 0);
if (!zero)
@@ -342,11 +440,6 @@ static bool ppir_lower_branch(ppir_block *block, ppir_node *node)
zero->dest.ssa.num_components = 1;
zero->dest.write_mask = 0x01;
- /* For now we're just comparing branch condition with 0,
- * in future we should look whether it's possible to move
- * comparision node into branch itself and use current
- * way as a fallback for complex conditions.
- */
ppir_node_target_assign(&branch->src[1], &zero->node);
if (branch->negate)