[Mesa-dev] [PATCH 40/95] i965/vec4: add a SIMD lowering pass

Iago Toral Quiroga itoral at igalia.com
Tue Jul 19 10:40:37 UTC 2016


Generally, instructions in Align16 mode only ever write to a single
register and don't need anny form of SIMD splitting, that's why we
have never had a SIMD splitting pass in the vec4 backend. However,
double-precision instructions typically write 2 registers and in
some cases they run into certain hardware bugs and limitations
that we need to work around by splitting the instructions so we only
write to 1 register at a time.

This patch implements a basic SIMD splitting pass for this purpose.
Notice that it does not attempt to be as flexible and generic as the
FS version, because as I explain above, the cases where this needs
to act are more limited, so we take advantage of that to simplify
the implementation.

Because we only use double-precision instructions in Align16 mode
in gen7 (gen8+ is fully scalar and gens < 7 do not implement fp64)
the pass is restricted to act on gen7 hardware only.

For now the pass only handles the gen7 restriction where any
instruction that writes 2 registers also needs to read 2 registers.
This affects double-precision instructions reading uniforms, for
example. Later patches will extend the lowering pass adding a few
more cases.
---
 src/mesa/drivers/dri/i965/brw_ir_vec4.h |   1 +
 src/mesa/drivers/dri/i965/brw_vec4.cpp  | 100 +++++++++++++++++++++++++++++++-
 src/mesa/drivers/dri/i965/brw_vec4.h    |   2 +
 3 files changed, 102 insertions(+), 1 deletion(-)

diff --git a/src/mesa/drivers/dri/i965/brw_ir_vec4.h b/src/mesa/drivers/dri/i965/brw_ir_vec4.h
index 721772e..f66c093 100644
--- a/src/mesa/drivers/dri/i965/brw_ir_vec4.h
+++ b/src/mesa/drivers/dri/i965/brw_ir_vec4.h
@@ -167,6 +167,7 @@ public:
    unsigned sol_vertex; /**< gen6: used for setting dst index in SVB header */
 
    uint8_t exec_size;
+   uint8_t group;
 
    bool is_send_from_grf();
    unsigned regs_read(unsigned arg) const;
diff --git a/src/mesa/drivers/dri/i965/brw_vec4.cpp b/src/mesa/drivers/dri/i965/brw_vec4.cpp
index 8316691..829b7d3 100644
--- a/src/mesa/drivers/dri/i965/brw_vec4.cpp
+++ b/src/mesa/drivers/dri/i965/brw_vec4.cpp
@@ -1947,6 +1947,101 @@ vec4_visitor::convert_to_hw_regs()
    }
 }
 
+/**
+ * Get the closest native SIMD width supported by the hardware for instruction
+ * \p inst.  The instruction will be left untouched by
+ * vec4_visitor::lower_simd_width() if the returned value matches the
+ * instruction's original execution size.
+ */
+static unsigned
+get_lowered_simd_width(const struct brw_device_info *devinfo,
+                       const vec4_instruction *inst)
+{
+   /* For now we only need to split some cases of double-precision instructions
+    * that write 2 registers. We only need to care about this in gen7 because
+    * that is the only hardware that implements fp64 in Align16.
+    */
+   if (devinfo->gen != 7 || inst->regs_written < 2)
+      return inst->exec_size;
+
+   unsigned lowered_width = MIN2(8, inst->exec_size);
+
+   /* HSW PRM, 3D Media GPGPU Engine, Region Alignment Rules for Direct
+    * Register Addressing:
+    *
+    *    "When destination spans two registers, the source MUST span two
+    *     registers."
+    */
+   for (unsigned i = 0; i < 3; i++) {
+      if (inst->src[i].file == BAD_FILE)
+         continue;
+      if (inst->regs_read(i) < 2)
+         lowered_width = MIN2(lowered_width, 4);
+   }
+
+   return lowered_width;
+}
+
+bool
+vec4_visitor::lower_simd_width()
+{
+   bool progress = false;
+
+   foreach_block_and_inst_safe(block, vec4_instruction, inst, cfg) {
+      const unsigned lowered_width = get_lowered_simd_width(devinfo, inst);
+      assert(lowered_width <= inst->exec_size);
+      if (lowered_width == inst->exec_size)
+         continue;
+
+      /* For now we only support splitting 8-wide instructions into 4-wide */
+      assert(inst->exec_size == 8 && lowered_width == 4);
+
+      /* We always split so that each lowered instruction writes exactly to
+       * one register.
+       */
+      assert(inst->regs_written == inst->exec_size / lowered_width);
+
+      for (unsigned n = 0; n < inst->exec_size / lowered_width; n++)  {
+         dst_reg dst = offset(inst->dst, n);
+
+         src_reg srcs[3];
+         for (int i = 0; i < 3; i++) {
+            srcs[i] = inst->src[i];
+
+            if (srcs[i].file == BAD_FILE)
+               continue;
+
+            if (!is_uniform(srcs[i])) {
+               if (type_sz(srcs[i].type) == 8) {
+                  srcs[i] = offset(srcs[i], n);
+               } else {
+                  assert(lowered_width * n < 8);
+                  srcs[i].subnr += lowered_width * n;
+               }
+            }
+         }
+
+         vec4_instruction *linst = new(mem_ctx)
+            vec4_instruction(inst->opcode, dst, srcs[0], srcs[1], srcs[2]);
+         linst->exec_size = lowered_width;
+         linst->group = lowered_width * n;
+         linst->regs_written = 1;
+         linst->conditional_mod = inst->conditional_mod;
+         linst->predicate = inst->predicate;
+         linst->saturate = inst->saturate;
+         inst->insert_before(block, linst);
+      }
+
+      inst->remove(block);
+      progress = true;
+   }
+
+   if (progress)
+      invalidate_live_intervals();
+
+   return progress;
+}
+
 bool
 vec4_visitor::run()
 {
@@ -2002,9 +2097,12 @@ vec4_visitor::run()
       backend_shader::dump_instructions(filename);
    }
 
-   bool progress;
+   bool progress = false;
    int iteration = 0;
    int pass_num = 0;
+
+   OPT(lower_simd_width);
+
    do {
       progress = false;
       pass_num = 0;
diff --git a/src/mesa/drivers/dri/i965/brw_vec4.h b/src/mesa/drivers/dri/i965/brw_vec4.h
index cf7cdab..e4c4e91 100644
--- a/src/mesa/drivers/dri/i965/brw_vec4.h
+++ b/src/mesa/drivers/dri/i965/brw_vec4.h
@@ -160,6 +160,8 @@ public:
    void opt_schedule_instructions();
    void convert_to_hw_regs();
 
+   bool lower_simd_width();
+
    vec4_instruction *emit(vec4_instruction *inst);
 
    vec4_instruction *emit(enum opcode opcode);
-- 
2.7.4



More information about the mesa-dev mailing list