<div dir="ltr">On 29 October 2013 23:37, 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:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">


Before this patch, the following code would not be optimized even though<br>
the final two instructions were common to the then and else blocks:<br>
<br>
   (+f0) IF<br>
   MOV dst2 ...<br>
   MOV dst1 ...<br>
   MOV dst0 ...<br>
   ELSE<br>
   MOV dst3 ...<br>
   MOV dst1 ...<br>
   MOV dst0 ...<br>
   ENDIF<br>
<br>
This commit extends the peephole to handle this case.<br>
<br>
total instructions in shared programs: 1362275 -> 1361817 (-0.03%)<br>
instructions in affected programs:     35527 -> 35069 (-1.29%)<br>
---<br>
Split mistakenly squashed patches.<br>
<br>
 src/mesa/drivers/dri/i965/brw_fs_sel_peephole.cpp | 93 +++++++++++++++++------<br>
 1 file changed, 71 insertions(+), 22 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 11c3677..8638f43 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>
@@ -34,32 +34,84 @@<br>
 #define MAX_MOVS 8 /**< The maximum number of MOVs to attempt to match. */<br>
<br>
 /**<br>
+ * For a given control flow graph <cfg> and number <start_block> of the basic<br>
+ * block ending with an ENDIF instruction, return pointers to the associated<br>
+ * IF and ELSE instructions.<br>
+ *<br>
+ * If no ELSE instruction is found before the associated IF, return false.<br>
+ * Otherwise return true.<br>
+ */<br>
+static bool<br>
+find_if_else_from_endif(const cfg_t *cfg, int start_block,<br>
+                        fs_inst **if_inst, fs_inst **else_inst)<br></blockquote><div><br></div><div>Two concerns about this function:<br><br>1. I'm worried that it's going to be fragile because it relies on an undocumented behaviour of brw_cfg.cpp, namely the fact that the basic blocks are generated in the order in which they appear in the program.<br>


<br></div><div>2. It seems like a lot of work to go to, given the fact that this information is trivially available while we're building the cfg.<br><br>How about if instead we modify brw_cfg.cpp so that when it's building the cfg, it records pointers from the endif block to the corresponding if and else instructions?  Then we could drop this function entirely and just pull the information out of the cfg when we need it.<br>


</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+{<br>
+   assert(start_block > 0);<br>
+   assert(if_inst);<br>
+   assert(else_inst);<br>
+<br>
+   *if_inst = NULL;<br>
+   *else_inst = NULL;<br>
+<br>
+   int depth = 0;<br>
+   for (int b = start_block - 1; b >= 0; b--) {<br>
+      bblock_t *block = cfg->blocks[b];<br>
+<br>
+      switch (block->end->opcode) {<br>
+      case BRW_OPCODE_IF:<br>
+         if (depth == 0) {<br>
+            *if_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_ENDIF:<br>
+      case BRW_OPCODE_WHILE:<br>
+         depth++;<br>
+         break;<br>
+      case BRW_OPCODE_DO:<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>
- * A pointer to the fs_inst* for ENDIF is passed as the <match> argument. The<br>
- * function stores pointers to the MOV instructions in the <then_mov> and<br>
- * <else_mov> arrays. If the function is successful, the <match> points to the<br>
- * fs_inst* pointing to the IF instruction at the beginning of the block.<br>
+ * A pointer to the fs_inst* for ENDIF is passed as the <endif_inst> argument.<br>
+ * The 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>
- *         or zero if an error occurred.<br>
  *<br>
  * E.g.:<br>
- *    match       = IF ...<br>
+ *                  IF ...<br>
+ *    then_mov[2] = MOV g2, ...<br>
  *    then_mov[1] = MOV g4, ...<br>
  *    then_mov[0] = MOV g5, ...<br>
  *                  ELSE ...<br>
+ *    then_mov[2] = MOV g3, ...<br>
  *    else_mov[1] = MOV g4, ...<br>
  *    else_mov[0] = MOV g5, ...<br>
  *                  ENDIF<br>
- *    returns 2.<br>
+ *    returns 2 (since only the first two MOVs have a common destination)<br></blockquote><div><br></div><div>Actually, for this example code it will return 3, since it's the caller that checks whether the MOVs have a common destination.<br>
<br></div><div>Also, I failed to notice on my first read of this patch that it extends match_movs_from_endif() to be able to handle non-MOV instructions inside the IF/ELSE block.  You might want to change your example to:<br>
<br> *                  IF ...<br> *                  ...other instructions...<br> *    then_mov[2] = MOV g2, ...<br> *    then_mov[1] = MOV g4, ...<br> *    then_mov[0] = MOV g5, ...<br> *                  ELSE ...<br> *                  ...other instructions...<br>
 *    then_mov[2] = MOV g3, ...<br> *    else_mov[1] = MOV g4, ...<br> *    else_mov[0] = MOV g5, ...<br> *                  ENDIF<br><br></div><div>just so that there's no confusion about that.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">

  */<br>
 static int<br>
 match_movs_from_endif(fs_inst *then_mov[MAX_MOVS], fs_inst *else_mov[MAX_MOVS],<br>
-                      fs_inst **match)<br>
+                      fs_inst *endif_inst, fs_inst *else_inst)<br>
 {<br>
-   fs_inst *m = *match;<br>
+   fs_inst *m = endif_inst;<br>
<br>
    assert(m->opcode == BRW_OPCODE_ENDIF);<br>
    m = (fs_inst *) m->prev;<br>
@@ -71,9 +123,7 @@ match_movs_from_endif(fs_inst *then_mov[MAX_MOVS], fs_inst *else_mov[MAX_MOVS],<br>
       else_movs++;<br>
    }<br>
<br>
-   if (m->opcode != BRW_OPCODE_ELSE)<br>
-      return 0;<br>
-   m = (fs_inst *) m->prev;<br>
+   m = (fs_inst *) else_inst->prev;<br>
<br>
    int then_movs = 0;<br>
    while (then_movs < MAX_MOVS && m->opcode == BRW_OPCODE_MOV) {<br>
@@ -82,10 +132,6 @@ match_movs_from_endif(fs_inst *then_mov[MAX_MOVS], fs_inst *else_mov[MAX_MOVS],<br>
       then_movs++;<br>
    }<br>
<br>
-   if (m->opcode != BRW_OPCODE_IF)<br>
-      return 0;<br>
-<br>
-   *match = m;<br>
    return MIN2(then_movs, else_movs);<br>
 }<br>
<br>
@@ -134,7 +180,7 @@ fs_visitor::opt_peephole_sel()<br>
       bblock_t *block = cfg.blocks[b];<br>
<br>
       int movs;<br>
-      fs_inst *if_inst, *endif_inst;<br>
+      fs_inst *if_inst, *else_inst, *endif_inst;<br>
       fs_inst *start;<br>
       fs_inst *else_mov[MAX_MOVS] = { NULL };<br>
       fs_inst *then_mov[MAX_MOVS] = { NULL };<br>
@@ -145,14 +191,17 @@ fs_visitor::opt_peephole_sel()<br>
        */<br>
       start = (fs_inst *) block->end;<br>
       if (start->opcode == BRW_OPCODE_ENDIF) {<br>
-         fs_inst *match = endif_inst = start;<br>
+         endif_inst = start;<br>
+<br>
+         /* Find the associated IF and ELSE instructions for our ENDIF. */<br>
+         if (!find_if_else_from_endif(&cfg, b, &if_inst, &else_inst))<br>
+            continue;<br>
<br>
          /* Find MOVs to a common destination. */<br>
-         movs = match_movs_from_endif(then_mov, else_mov, &match);<br>
+         movs = match_movs_from_endif(then_mov, else_mov, start, else_inst);<br>
+<br>
          if (movs == 0)<br>
             continue;<br>
-<br>
-         if_inst = match;<br>
       } else {<br>
          continue;<br>
       }<br>
@@ -171,7 +220,7 @@ fs_visitor::opt_peephole_sel()<br>
          if (!then_mov[i]->dst.equals(else_mov[i]->dst) ||<br>
              then_mov[i]->is_partial_write() ||<br>
              else_mov[i]->is_partial_write()) {<br>
-            bb_progress = false;<br>
+            movs = i; <br></blockquote>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
             break;<br>
          }<br>
<span><font color="#888888"><br>
--<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>