intel/fs: Add an UNDEF instruction to avoid excess live ranges
authorJason Ekstrand <jason@jlekstrand.net>
Wed, 29 May 2019 22:46:55 +0000 (17:46 -0500)
committerJason Ekstrand <jason@jlekstrand.net>
Tue, 4 Jun 2019 19:27:30 +0000 (14:27 -0500)
With 8 and 16-bit types and anything where we have to use non-trivial
strides registersto deal with restrictions, we end up with things that
look like partial writes even though we don't care about any values in
the register except those written by that instruction.  This is
particularly important when dealing with loops because liveness sees
is_partial_write and the fact that an old version from a previous loop
iteration may be valid at that point and extends all purely partially
written values to the entire loop.

This commit adds a new UNDEF instruction which does nothing (the
generator doesn't emit anything) but which does a fake write to the
register.  This informs liveness that we don't care about any values
before that point so it won't consider those registers to be falsely
live.  We can safely emit UNDEF instructions for all SSA values that
come in from NIR and nearly all temporaries generated by various stages
of the compiler.  In particular, we need to insert UNDEF instructions
when we handle region restrictions because the newly allocated registers
are almost guaranteed to be partially written.

No shader-db changes.

Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=110432
Reviewed-by: Matt Turner <mattst88@gmail.com>
src/intel/compiler/brw_eu_defines.h
src/intel/compiler/brw_fs_builder.h
src/intel/compiler/brw_fs_generator.cpp
src/intel/compiler/brw_fs_lower_regioning.cpp
src/intel/compiler/brw_fs_nir.cpp
src/intel/compiler/brw_shader.cpp

index 66e6c53c2b7bc06840e98dc2ca7f9b4d1b405ae0..933037c4df3519aef8ce63ce26aa074d108a2aa3 100644 (file)
@@ -322,6 +322,14 @@ enum opcode {
     */
    SHADER_OPCODE_SEND,
 
+   /**
+    * An "undefined" write which does nothing but indicates to liveness that
+    * we don't care about any values in the register which predate this
+    * instruction.  Used to prevent partial writes from causing issues with
+    * live ranges.
+    */
+   SHADER_OPCODE_UNDEF,
+
    /**
     * Texture sampling opcodes.
     *
index a69e3c6ae807db3aff818117926c5e7d563937fa..9655c2ef55477625e3710d4526f98882f7b8adc7 100644 (file)
@@ -706,6 +706,17 @@ namespace brw {
          return inst;
       }
 
+      instruction *
+      UNDEF(const dst_reg &dst) const
+      {
+         assert(dst.file == VGRF);
+         instruction *inst = emit(SHADER_OPCODE_UNDEF,
+                                  retype(dst, BRW_REGISTER_TYPE_UD));
+         inst->size_written = shader->alloc.sizes[dst.nr] * REG_SIZE;
+
+         return inst;
+      }
+
       backend_shader *shader;
 
    private:
index f91c857678a3408e9cc67f07de14a869f25a6cfb..7adc8a7938b8325baaaf0e2f600ae16087e86109 100644 (file)
@@ -1653,6 +1653,9 @@ fs_generator::generate_code(const cfg_t *cfg, int dispatch_width)
    struct disasm_info *disasm_info = disasm_initialize(devinfo, cfg);
 
    foreach_block_and_inst (block, fs_inst, inst, cfg) {
+      if (inst->opcode == SHADER_OPCODE_UNDEF)
+         continue;
+
       struct brw_reg src[4], dst;
       unsigned int last_insn_offset = p->next_insn_offset;
       bool multiple_instructions_emitted = false;
index a76fd262a10059601eca9789e049ae8b4ebcf9cf..98699c38d840cc69df8911e7cb33a82fdab18d23 100644 (file)
@@ -288,7 +288,9 @@ namespace {
       const unsigned stride =
          type_sz(inst->dst.type) * inst->dst.stride <= type_sz(type) ? 1 :
          type_sz(inst->dst.type) * inst->dst.stride / type_sz(type);
-      const fs_reg tmp = horiz_stride(ibld.vgrf(type, stride), stride);
+      fs_reg tmp = ibld.vgrf(type, stride);
+      ibld.UNDEF(tmp);
+      tmp = horiz_stride(tmp, stride);
 
       /* Emit a MOV taking care of all the destination modifiers. */
       fs_inst *mov = ibld.at(block, inst->next).MOV(inst->dst, tmp);
@@ -329,8 +331,9 @@ namespace {
       const unsigned stride = type_sz(inst->dst.type) * inst->dst.stride /
                               type_sz(inst->src[i].type);
       assert(stride > 0);
-      const fs_reg tmp = horiz_stride(ibld.vgrf(inst->src[i].type, stride),
-                                      stride);
+      fs_reg tmp = ibld.vgrf(inst->src[i].type, stride);
+      ibld.UNDEF(tmp);
+      tmp = horiz_stride(tmp, stride);
 
       /* Emit a series of 32-bit integer copies with any source modifiers
        * cleaned up (because their semantics are dependent on the type).
@@ -377,8 +380,9 @@ namespace {
       const unsigned stride = required_dst_byte_stride(inst) /
                               type_sz(inst->dst.type);
       assert(stride > 0);
-      const fs_reg tmp = horiz_stride(ibld.vgrf(inst->dst.type, stride),
-                                      stride);
+      fs_reg tmp = ibld.vgrf(inst->dst.type, stride);
+      ibld.UNDEF(tmp);
+      tmp = horiz_stride(tmp, stride);
 
       /* Emit a series of 32-bit integer copies from the temporary into the
        * original destination.
index 77b131272ca0869696696809a46c8d3a6e09f3d7..eef21294d07029d43293f95231e9db6f6dc912ea 100644 (file)
@@ -1951,6 +1951,7 @@ fs_visitor::get_nir_dest(const nir_dest &dest)
                                     BRW_REGISTER_TYPE_F);
       nir_ssa_values[dest.ssa.index] =
          bld.vgrf(reg_type, dest.ssa.num_components);
+      bld.UNDEF(nir_ssa_values[dest.ssa.index]);
       return nir_ssa_values[dest.ssa.index];
    } else {
       /* We don't handle indirects on locals */
index 1f98bd082240e3e2e961bd09b474cbb0a52050c5..2061afc1c240b39fb25889e1469b82a54ee4a252 100644 (file)
@@ -217,6 +217,9 @@ brw_instruction_name(const struct gen_device_info *devinfo, enum opcode op)
    case SHADER_OPCODE_SEND:
       return "send";
 
+   case SHADER_OPCODE_UNDEF:
+      return "undef";
+
    case SHADER_OPCODE_TEX:
       return "tex";
    case SHADER_OPCODE_TEX_LOGICAL: