<div dir="ltr">On 28 October 2013 11:31, Matt Turner <span dir="ltr"><<a href="mailto:mattst88@gmail.com" target="_blank">mattst88@gmail.com</a>></span> wrote:<br><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
The pass previously searched only backward from an ENDIF (and ELSE) to<br>
find MOVs with the same destination. This commit extends the pass to<br>
also search forward from the IF (and ELSE) to find matching MOVs which<br>
it can replace with SEL instructions before the IF.<br>
<br>
E.g., the pass can now optimize<br>
<br>
(+f0) IF<br>
MOV dst0 ...<br>
MOV dst1 ...<br>
MOV dst2 ...<br>
ELSE<br>
MOV dst0 ...<br>
MOV dst1 ...<br>
MOV dst3 ...<br>
ENDIF<br>
<br>
total instructions in shared programs: 1287457 -> 1287432 (-0.00%)<br>
instructions in affected programs: 15664 -> 15639 (-0.16%)<br>
---<br>
src/mesa/drivers/dri/i965/brw_fs_sel_peephole.cpp | 131 +++++++++++++++++++++-<br>
1 file changed, 129 insertions(+), 2 deletions(-)<br>
<br>
diff --git a/src/mesa/drivers/dri/i965/brw_fs_sel_peephole.cpp b/src/mesa/drivers/dri/i965/brw_fs_sel_peephole.cpp<br>
index 4c0eba9..ebde78b 100644<br>
--- a/src/mesa/drivers/dri/i965/brw_fs_sel_peephole.cpp<br>
+++ b/src/mesa/drivers/dri/i965/brw_fs_sel_peephole.cpp<br>
@@ -86,6 +86,58 @@ find_if_else_from_endif(const cfg_t *cfg, int start_block,<br>
}<br>
<br>
/**<br>
+ * For a given control flow graph <cfg> and number <start_block> of the basic<br>
+ * block ending with an IF instruction, return pointers to the associated<br>
+ * ELSE and ENDIF instructions.<br>
+ *<br>
+ * If no ELSE instruction is found before the associated ENDIF, return false.<br>
+ * Otherwise return true.<br>
+ */<br>
+static bool<br>
+find_else_endif_from_if(const cfg_t *cfg, int start_block,<br>
+ fs_inst **else_inst, fs_inst **endif_inst)<br></blockquote><div><br></div><div>I have similar concerns about this function to the concerns I had about find_if_else_from_endif() in patch 10.5.<br>
</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+{<br>
+ assert(start_block < cfg->num_blocks - 1);<br>
+ assert(else_inst);<br>
+ assert(endif_inst);<br>
+<br>
+ *else_inst = NULL;<br>
+ *endif_inst = NULL;<br>
+<br>
+ int depth = 0;<br>
+ for (int b = start_block + 1; b < cfg->num_blocks; b++) {<br>
+ bblock_t *block = cfg->blocks[b];<br>
+<br>
+ switch (block->end->opcode) {<br>
+ case BRW_OPCODE_ENDIF:<br>
+ if (depth == 0) {<br>
+ *endif_inst = (fs_inst *) block->end;<br>
+ return *else_inst != NULL;<br>
+ }<br>
+ depth--;<br>
+ break;<br>
+ case BRW_OPCODE_ELSE:<br>
+ if (depth == 0) {<br>
+ *else_inst = (fs_inst *) block->end;<br>
+ }<br>
+ /* No change in depth */<br>
+ break;<br>
+ case BRW_OPCODE_IF:<br>
+ case BRW_OPCODE_DO:<br>
+ depth++;<br>
+ break;<br>
+ case BRW_OPCODE_WHILE:<br>
+ depth--;<br>
+ break;<br>
+ default:<br>
+ break;<br>
+ }<br>
+ }<br>
+<br>
+ return false;<br>
+}<br>
+<br>
+/**<br>
* Scans backwards from an ENDIF counting MOV instructions with common<br>
* destinations inside the "then" and "else" blocks of the if statement.<br>
*<br>
@@ -136,6 +188,56 @@ match_movs_from_endif(fs_inst *then_mov[MAX_MOVS], fs_inst *else_mov[MAX_MOVS],<br>
}<br>
<br>
/**<br>
+ * Scans forward from an IF counting MOV instructions with common destinations<br>
+ * inside the "then" and "else" blocks of the if statement.<br>
+ *<br>
+ * A pointer to the fs_inst* for IF is passed as the <if_inst> argument. The<br>
+ * function stores pointers to the MOV instructions in the <then_mov> and<br>
+ * <else_mov> arrays.<br>
+ *<br>
+ * \return the number of MOVs to a common destination found in the two branches<br>
+ *<br>
+ * E.g.:<br>
+ * IF ...<br>
+ * then_mov[0] = MOV g4, ...<br>
+ * then_mov[1] = MOV g5, ...<br>
+ * then_mov[2] = MOV g6, ...<br>
+ * ELSE ...<br>
+ * else_mov[0] = MOV g4, ...<br>
+ * else_mov[1] = MOV g5, ...<br>
+ * else_mov[2] = MOV g7, ...<br>
+ * ENDIF<br>
+ * returns 2 (since only the first two MOVs have a common destination)<br>
+ */<br>
+static int<br>
+match_movs_from_if(fs_inst *then_mov[MAX_MOVS], fs_inst *else_mov[MAX_MOVS],<br>
+ fs_inst *if_inst, fs_inst *else_inst)<br>
+{<br>
+ fs_inst *m = if_inst;<br>
+<br>
+ assert(m->opcode == BRW_OPCODE_IF);<br>
+ m = (fs_inst *) m->next;<br>
+<br>
+ int then_movs = 0;<br>
+ while (then_movs < MAX_MOVS && m->opcode == BRW_OPCODE_MOV) {<br>
+ then_mov[then_movs] = m;<br>
+ m = (fs_inst *) m->next;<br>
+ then_movs++;<br>
+ }<br>
+<br>
+ m = (fs_inst *) else_inst->next;<br>
+<br>
+ int else_movs = 0;<br>
+ while (else_movs < MAX_MOVS && m->opcode == BRW_OPCODE_MOV) {<br>
+ else_mov[else_movs] = m;<br>
+ m = (fs_inst *) m->next;<br>
+ else_movs++;<br>
+ }<br>
+<br>
+ return MIN2(then_movs, else_movs);<br>
+}<br>
+<br>
+/**<br>
* Try to replace IF/MOV+/ELSE/MOV+/ENDIF with SEL.<br>
*<br>
* Many GLSL shaders contain the following pattern:<br>
@@ -202,6 +304,18 @@ fs_visitor::opt_peephole_sel()<br>
<br>
if (movs == 0)<br>
continue;<br>
+ } else if (start->opcode == BRW_OPCODE_IF) {<br>
+ if_inst = start;<br>
+<br>
+ /* Find the associated ELSE and ENDIF instructions for our IF. */<br>
+ if (!find_else_endif_from_if(&cfg, b, &else_inst, &endif_inst))<br>
+ continue;<br>
+<br>
+ /* Find MOVs to a common destination. */<br>
+ movs = match_movs_from_if(then_mov, else_mov, start, else_inst);<br>
+<br>
+ if (movs == 0)<br>
+ continue;<br></blockquote><div><br></div><div>It seems like we're doing some redundant work between this newly added code and the block above it.<br><br>The block above it says "for each 'if', find the matching else and endif. Then try to peephole SEL by walking forward through the then/else instructions."<br>
</div><div>The block below it says "for each 'endif', find the matching if and else. Then try to peephole SEL by walking backward through the then/else instructions."<br><br></div><div>It seems like we could just as easily do: "For each 'endif', find the matching if and else. Then try to peephole SEL by walking forward through the then/else instructions. Then try to peephole SEL by walking backward through the then/else instructions".<br>
<br>An advantage of this approach is that there's no ambiguity about whether we walk forward first or walk backward first. And I think walking forward first is better, because it avoids the problem we talked about in patch 9 of needing to save and restore the flag register.<br>
</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
} else {<br>
continue;<br>
}<br>
@@ -269,8 +383,8 @@ fs_visitor::opt_peephole_sel()<br>
cmp_inst = new(mem_ctx) fs_inst(m);<br>
}<br>
<br>
- /* Insert flag-writing instruction immediately after the ENDIF, and<br>
- * SEL and MOV imm instructions after that.<br>
+ /* Insert flag-writing instruction immediately after the IF or ENDIF,<br>
+ * and SEL and MOV imm instructions after that.<br>
*/<br>
if (start->opcode == BRW_OPCODE_ENDIF) {<br>
endif_inst->insert_after(cmp_inst);<br>
@@ -286,6 +400,19 @@ fs_visitor::opt_peephole_sel()<br>
<br>
/* Appending an instruction may have changed our bblock end. */<br>
block->end = sel_inst[0];<br>
+ } else if (start->opcode == BRW_OPCODE_IF) {<br>
+ if_inst->insert_before(cmp_inst);<br></blockquote><div><br></div><div>With the exception of the gen6 if-with-cmod case, this line can be dropped, and then we don't have the problem with the cmp instruction getting moved to a place where it might have a different meaning. <br>
</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+<br>
+ for (int i = 0; i < movs; i++) {<br>
+ cmp_inst->insert_after(sel_inst[i]);<br>
+ if (mov_imm_inst[i])<br>
+ cmp_inst->insert_after(mov_imm_inst[i]);<br>
+<br>
+ then_mov[i]->remove();<br>
+ else_mov[i]->remove();<br>
+ }<br>
+<br>
+ /* No change to basic block boundaries possible. */<br>
}<br>
}<br>
progress = progress || bb_progress;<br>
<span><font color="#888888">--<br>
1.8.3.2<br>
<br>
_______________________________________________<br>
mesa-dev mailing list<br>
<a href="mailto:mesa-dev@lists.freedesktop.org" target="_blank">mesa-dev@lists.freedesktop.org</a><br>
<a href="http://lists.freedesktop.org/mailman/listinfo/mesa-dev" target="_blank">http://lists.freedesktop.org/mailman/listinfo/mesa-dev</a><br>
</font></span></blockquote></div><br></div></div>