i965/fs: Replace fs_reg::subreg_offset with fs_reg::offset expressed in bytes.
[mesa.git] / src / mesa / drivers / dri / i965 / brw_vec4_dead_code_eliminate.cpp
index b8370ba63ec7d2a42c69d4cb4c7264f304a25eca..c643212494b24b841772aef4d7443996431dd4ee 100644 (file)
 
 using namespace brw;
 
-static bool
-can_do_writemask(const struct brw_context *brw,
-                 const vec4_instruction *inst)
-{
-   switch (inst->opcode) {
-   case SHADER_OPCODE_GEN4_SCRATCH_READ:
-   case VS_OPCODE_PULL_CONSTANT_LOAD:
-   case VS_OPCODE_PULL_CONSTANT_LOAD_GEN7:
-      return false;
-   default:
-      /* The MATH instruction on Gen6 only executes in align1 mode, which does
-       * not support writemasking.
-       */
-      if (brw->gen == 6 && inst->is_math())
-         return false;
-
-      if (inst->is_tex())
-         return false;
-
-      return true;
-   }
-}
-
 bool
 vec4_visitor::dead_code_eliminate()
 {
@@ -70,25 +47,32 @@ vec4_visitor::dead_code_eliminate()
    BITSET_WORD *live = ralloc_array(NULL, BITSET_WORD, BITSET_WORDS(num_vars));
    BITSET_WORD *flag_live = ralloc_array(NULL, BITSET_WORD, 1);
 
-   foreach_block(block, cfg) {
+   foreach_block_reverse_safe(block, cfg) {
       memcpy(live, live_intervals->block_data[block->num].liveout,
              sizeof(BITSET_WORD) * BITSET_WORDS(num_vars));
       memcpy(flag_live, live_intervals->block_data[block->num].flag_liveout,
              sizeof(BITSET_WORD));
 
-      foreach_inst_in_block_reverse(vec4_instruction, inst, block) {
-         if (inst->dst.file == GRF && !inst->has_side_effects()) {
+      foreach_inst_in_block_reverse_safe(vec4_instruction, inst, block) {
+         if ((inst->dst.file == VGRF && !inst->has_side_effects()) ||
+             (inst->dst.is_null() && inst->writes_flag())){
             bool result_live[4] = { false };
 
-            for (int c = 0; c < 4; c++) {
-               int var = inst->dst.reg * 4 + c;
-               result_live[c] = BITSET_TEST(live, var);
+            if (inst->dst.file == VGRF) {
+               for (unsigned i = 0; i < inst->regs_written; i++) {
+                  for (int c = 0; c < 4; c++)
+                     result_live[c] |= BITSET_TEST(
+                        live, var_from_reg(alloc, offset(inst->dst, i), c));
+               }
+            } else {
+               for (unsigned c = 0; c < 4; c++)
+                  result_live[c] = BITSET_TEST(flag_live, c);
             }
 
             /* If the instruction can't do writemasking, then it's all or
              * nothing.
              */
-            if (!can_do_writemask(brw, inst)) {
+            if (!inst->can_do_writemask(devinfo)) {
                bool result = result_live[0] | result_live[1] |
                              result_live[2] | result_live[3];
                result_live[0] = result;
@@ -103,11 +87,11 @@ vec4_visitor::dead_code_eliminate()
                   progress = true;
 
                   if (inst->dst.writemask == 0) {
-                     if (inst->writes_accumulator) {
+                     if (inst->writes_accumulator || inst->writes_flag()) {
                         inst->dst = dst_reg(retype(brw_null_reg(), inst->dst.type));
                      } else {
                         inst->opcode = BRW_OPCODE_NOP;
-                        continue;
+                        break;
                      }
                   }
                }
@@ -115,39 +99,52 @@ vec4_visitor::dead_code_eliminate()
          }
 
          if (inst->dst.is_null() && inst->writes_flag()) {
-            if (!BITSET_TEST(flag_live, 0)) {
+            bool combined_live = false;
+            for (unsigned c = 0; c < 4; c++)
+               combined_live |= BITSET_TEST(flag_live, c);
+
+            if (!combined_live) {
                inst->opcode = BRW_OPCODE_NOP;
                progress = true;
-               continue;
             }
          }
 
-         if (inst->dst.file == GRF && !inst->predicate) {
-            for (int c = 0; c < 4; c++) {
-               if (inst->dst.writemask & (1 << c)) {
-                  int var = inst->dst.reg * 4 + c;
-                  BITSET_CLEAR(live, var);
+         if (inst->dst.file == VGRF && !inst->predicate) {
+            for (unsigned i = 0; i < inst->regs_written; i++) {
+               for (int c = 0; c < 4; c++) {
+                  if (inst->dst.writemask & (1 << c)) {
+                     BITSET_CLEAR(live, var_from_reg(alloc,
+                                                     offset(inst->dst, i), c));
+                  }
                }
             }
          }
 
-         if (inst->writes_flag()) {
-            BITSET_CLEAR(flag_live, 0);
+         if (inst->writes_flag() && !inst->predicate) {
+            for (unsigned c = 0; c < 4; c++)
+               BITSET_CLEAR(flag_live, c);
          }
 
-         for (int i = 0; i < 3; i++) {
-            if (inst->src[i].file == GRF) {
-               for (int c = 0; c < 4; c++) {
-                  int swiz = BRW_GET_SWZ(inst->src[i].swizzle, c);
-                  int var = inst->src[i].reg * 4 + swiz;
+         if (inst->opcode == BRW_OPCODE_NOP) {
+            inst->remove(block);
+            continue;
+         }
 
-                  BITSET_SET(live, var);
+         for (int i = 0; i < 3; i++) {
+            if (inst->src[i].file == VGRF) {
+               for (unsigned j = 0; j < inst->regs_read(i); j++) {
+                  for (int c = 0; c < 4; c++) {
+                     BITSET_SET(live, var_from_reg(alloc,
+                                                   offset(inst->src[i], j), c));
+                  }
                }
             }
          }
 
-         if (inst->reads_flag()) {
-            BITSET_SET(flag_live, 0);
+         for (unsigned c = 0; c < 4; c++) {
+            if (inst->reads_flag(c)) {
+               BITSET_SET(flag_live, c);
+            }
          }
       }
    }
@@ -155,15 +152,8 @@ vec4_visitor::dead_code_eliminate()
    ralloc_free(live);
    ralloc_free(flag_live);
 
-   if (progress) {
-      foreach_block_and_inst_safe(block, backend_instruction, inst, cfg) {
-         if (inst->opcode == BRW_OPCODE_NOP) {
-            inst->remove(block);
-         }
-      }
-
+   if (progress)
       invalidate_live_intervals();
-   }
 
    return progress;
 }