gm107/ir: prevent WaW hazards in instruction scheduling
authorRhys Perry <pendingchaos02@gmail.com>
Sat, 19 May 2018 21:03:39 +0000 (22:03 +0100)
committerIlia Mirkin <imirkin@alum.mit.edu>
Mon, 28 May 2018 17:59:56 +0000 (13:59 -0400)
Previously, findFirstUse() only considered reads "uses". This fixes that
by making it check both an instruction's sources and definitions. It
also shortens both findFistUse() and findFirstDef() along the way.

Reviewed-by: Ilia Mirkin <imirkin@alum.mit.edu>
src/gallium/drivers/nouveau/codegen/nv50_ir_emit_gm107.cpp

index 1f6189890c40a522e8adb16e9e8263ee7b702b7c..26826d6360639fd90acec27b282a6825c2d51b8b 100644 (file)
@@ -3618,6 +3618,7 @@ private:
 
    bool insertBarriers(BasicBlock *);
 
+   bool doesInsnWriteTo(const Instruction *insn, const Value *val) const;
    Instruction *findFirstUse(const Instruction *) const;
    Instruction *findFirstDef(const Instruction *) const;
 
@@ -3948,8 +3949,48 @@ SchedDataCalculatorGM107::needWrDepBar(const Instruction *insn) const
    return false;
 }
 
-// Find the next instruction inside the same basic block which uses the output
-// of the given instruction in order to avoid RaW hazards.
+// Helper function for findFirstUse() and findFirstDef()
+bool
+SchedDataCalculatorGM107::doesInsnWriteTo(const Instruction *insn,
+                                          const Value *val) const
+{
+   if (val->reg.file != FILE_GPR &&
+       val->reg.file != FILE_PREDICATE &&
+       val->reg.file != FILE_FLAGS)
+      return false;
+
+   for (int d = 0; insn->defExists(d); ++d) {
+      const Value* def = insn->getDef(d);
+      int minGPR = def->reg.data.id;
+      int maxGPR = minGPR + def->reg.size / 4 - 1;
+
+      if (def->reg.file != val->reg.file)
+         continue;
+
+      if (def->reg.file == FILE_GPR) {
+         if (val->reg.data.id + val->reg.size / 4 - 1 < minGPR ||
+             val->reg.data.id > maxGPR)
+            continue;
+         return true;
+      } else
+      if (def->reg.file == FILE_PREDICATE) {
+         if (val->reg.data.id != minGPR)
+            continue;
+         return true;
+      } else
+      if (def->reg.file == FILE_FLAGS) {
+         if (val->reg.data.id != minGPR)
+            continue;
+         return true;
+      }
+   }
+
+   return false;
+}
+
+// Find the next instruction inside the same basic block which uses (reads or
+// writes from) the output of the given instruction in order to avoid RaW and
+// WaW hazards.
 Instruction *
 SchedDataCalculatorGM107::findFirstUse(const Instruction *bari) const
 {
@@ -3961,34 +4002,13 @@ SchedDataCalculatorGM107::findFirstUse(const Instruction *bari) const
    for (insn = bari->next; insn != NULL; insn = next) {
       next = insn->next;
 
-      for (int s = 0; insn->srcExists(s); ++s) {
-         const Value *src = insn->src(s).rep();
-         for (int d = 0; bari->defExists(d); ++d) {
-            const ValueDef &def = bari->def(d);
-            int minGPR = def.rep()->reg.data.id;
-            int maxGPR = minGPR + def.rep()->reg.size / 4 - 1;
-
-            if (def.getFile() == FILE_GPR) {
-               if (insn->src(s).getFile() != FILE_GPR ||
-                   src->reg.data.id + src->reg.size / 4 - 1 < minGPR ||
-                   src->reg.data.id > maxGPR)
-                  continue;
-               return insn;
-            } else
-            if (def.getFile() == FILE_PREDICATE) {
-               if (insn->src(s).getFile() != FILE_PREDICATE ||
-                   src->reg.data.id != minGPR)
-                  continue;
-               return insn;
-            }
-            if (def.getFile() == FILE_FLAGS) {
-               if (insn->src(s).getFile() != FILE_FLAGS ||
-                   src->reg.data.id != minGPR)
-                  continue;
-               return insn;
-            }
-         }
-      }
+      for (int s = 0; insn->srcExists(s); ++s)
+         if (doesInsnWriteTo(bari, insn->getSrc(s)))
+            return insn;
+
+      for (int d = 0; insn->defExists(d); ++d)
+         if (doesInsnWriteTo(bari, insn->getDef(d)))
+            return insn;
    }
    return NULL;
 }
@@ -3999,34 +4019,16 @@ Instruction *
 SchedDataCalculatorGM107::findFirstDef(const Instruction *bari) const
 {
    Instruction *insn, *next;
-   int minGPR, maxGPR;
+
+   if (!bari->srcExists(0))
+      return NULL;
 
    for (insn = bari->next; insn != NULL; insn = next) {
       next = insn->next;
 
-      for (int d = 0; insn->defExists(d); ++d) {
-         const Value *def = insn->def(d).rep();
-         if (insn->def(d).getFile() != FILE_GPR &&
-             insn->def(d).getFile() != FILE_FLAGS)
-            continue;
-
-         minGPR = def->reg.data.id;
-         maxGPR = minGPR + def->reg.size / 4 - 1;
-
-         for (int s = 0; bari->srcExists(s); ++s) {
-            const Value *src = bari->src(s).rep();
-            if (bari->src(s).getFile() == FILE_FLAGS &&
-                insn->def(d).getFile() == FILE_FLAGS &&
-                src->reg.data.id == minGPR)
-               return insn;
-            if (bari->src(s).getFile() != FILE_GPR ||
-                insn->def(d).getFile() != FILE_GPR ||
-                src->reg.data.id + src->reg.size / 4 - 1 < minGPR ||
-                src->reg.data.id > maxGPR)
-               continue;
+      for (int s = 0; bari->srcExists(s); ++s)
+         if (doesInsnWriteTo(insn, bari->getSrc(s)))
             return insn;
-         }
-      }
    }
    return NULL;
 }
@@ -4084,7 +4086,8 @@ SchedDataCalculatorGM107::insertBarriers(BasicBlock *bb)
       if (need_wr_bar) {
          // When the instruction requires to emit a write dependency barrier
          // (all which write something at a variable latency), find the next
-         // instruction which reads the outputs.
+         // instruction which reads the outputs (or writes to them, potentially
+         // completing before this insn.
          usei = findFirstUse(insn);
 
          // Allocate and emit a new barrier.