Mesa (master): nvc0/ir: fix texture barrier insertion to prevent WAW hazards

Christoph Bumiller chrisbmr at kemper.freedesktop.org
Tue May 29 15:02:07 UTC 2012


Module: Mesa
Branch: master
Commit: 40c224a573f2b763046001e622aafca90f68c693
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=40c224a573f2b763046001e622aafca90f68c693

Author: Christoph Bumiller <e0425955 at student.tuwien.ac.at>
Date:   Fri May 25 17:27:03 2012 +0200

nvc0/ir: fix texture barrier insertion to prevent WAW hazards

Fixes, for instance, object highlighting in Diablo 3 (wine).

---

 src/gallium/drivers/nv50/codegen/nv50_ir.h         |    2 +-
 src/gallium/drivers/nv50/codegen/nv50_ir_graph.cpp |   12 ++-
 src/gallium/drivers/nv50/codegen/nv50_ir_graph.h   |    2 +-
 src/gallium/drivers/nv50/codegen/nv50_ir_inlines.h |    2 +-
 .../drivers/nvc0/codegen/nv50_ir_emit_nvc0.cpp     |    2 +-
 .../drivers/nvc0/codegen/nv50_ir_lowering_nvc0.cpp |   97 ++++++++++++++++----
 6 files changed, 88 insertions(+), 29 deletions(-)

diff --git a/src/gallium/drivers/nv50/codegen/nv50_ir.h b/src/gallium/drivers/nv50/codegen/nv50_ir.h
index 9b47e3e..0b47c32 100644
--- a/src/gallium/drivers/nv50/codegen/nv50_ir.h
+++ b/src/gallium/drivers/nv50/codegen/nv50_ir.h
@@ -864,7 +864,7 @@ public:
    inline bool isTerminated() const { return exit && exit->terminator; }
 
    bool dominatedBy(BasicBlock *bb);
-   inline bool reachableBy(BasicBlock *by, BasicBlock *term);
+   inline bool reachableBy(const BasicBlock *by, const BasicBlock *term);
 
    // returns mask of conditional out blocks
    // e.g. 3 for IF { .. } ELSE { .. } ENDIF, 1 for IF { .. } ENDIF
diff --git a/src/gallium/drivers/nv50/codegen/nv50_ir_graph.cpp b/src/gallium/drivers/nv50/codegen/nv50_ir_graph.cpp
index f1bff97..33e35ee 100644
--- a/src/gallium/drivers/nv50/codegen/nv50_ir_graph.cpp
+++ b/src/gallium/drivers/nv50/codegen/nv50_ir_graph.cpp
@@ -23,6 +23,7 @@
 #include "nv50_ir_graph.h"
 #include <limits>
 #include <list>
+#include <stack>
 #include "nv50_ir.h"
 
 namespace nv50_ir {
@@ -165,16 +166,17 @@ Graph::Edge::Edge(Node *org, Node *tgt, Type kind)
 }
 
 bool
-Graph::Node::reachableBy(Node *node, Node *term)
+Graph::Node::reachableBy(const Node *node, const Node *term) const
 {
-   Stack stack;
-   Node *pos;
+   std::stack<const Node *> stack;
+   const Node *pos = NULL;
    const int seq = graph->nextSequence();
 
    stack.push(node);
 
-   while (stack.getSize()) {
-      pos = reinterpret_cast<Node *>(stack.pop().u.p);
+   while (!stack.empty()) {
+      pos = stack.top();
+      stack.pop();
 
       if (pos == this)
          return true;
diff --git a/src/gallium/drivers/nv50/codegen/nv50_ir_graph.h b/src/gallium/drivers/nv50/codegen/nv50_ir_graph.h
index 9ef317f..3bf84ba 100644
--- a/src/gallium/drivers/nv50/codegen/nv50_ir_graph.h
+++ b/src/gallium/drivers/nv50/codegen/nv50_ir_graph.h
@@ -117,7 +117,7 @@ public:
 
       inline Node *parent() const; // returns NULL if count(incident edges) != 1
 
-      bool reachableBy(Node *node, Node *term);
+      bool reachableBy(const Node *node, const Node *term) const;
 
       inline bool visit(int);
       inline int  getSequence() const;
diff --git a/src/gallium/drivers/nv50/codegen/nv50_ir_inlines.h b/src/gallium/drivers/nv50/codegen/nv50_ir_inlines.h
index b62431f..ab4c98f 100644
--- a/src/gallium/drivers/nv50/codegen/nv50_ir_inlines.h
+++ b/src/gallium/drivers/nv50/codegen/nv50_ir_inlines.h
@@ -359,7 +359,7 @@ Value *Value::get(Iterator &it)
    return reinterpret_cast<Value *>(it.get());
 }
 
-bool BasicBlock::reachableBy(BasicBlock *by, BasicBlock *term)
+bool BasicBlock::reachableBy(const BasicBlock *by, const BasicBlock *term)
 {
    return cfg.reachableBy(&by->cfg, &term->cfg);
 }
diff --git a/src/gallium/drivers/nvc0/codegen/nv50_ir_emit_nvc0.cpp b/src/gallium/drivers/nvc0/codegen/nv50_ir_emit_nvc0.cpp
index fbd1aa5..57d5d72 100644
--- a/src/gallium/drivers/nvc0/codegen/nv50_ir_emit_nvc0.cpp
+++ b/src/gallium/drivers/nvc0/codegen/nv50_ir_emit_nvc0.cpp
@@ -960,7 +960,7 @@ void CodeEmitterNVC0::emitTEXBAR(const Instruction *i)
    code[0] = 0x00000006 | (i->subOp << 26);
    code[1] = 0xf0000000;
    emitPredicate(i);
-   emitCondCode(i->predSrc >= 0 ? i->cc : CC_ALWAYS, 5);
+   emitCondCode(i->flagsSrc >= 0 ? i->cc : CC_ALWAYS, 5);
 }
 
 void CodeEmitterNVC0::emitTEXCSAA(const TexInstruction *i)
diff --git a/src/gallium/drivers/nvc0/codegen/nv50_ir_lowering_nvc0.cpp b/src/gallium/drivers/nvc0/codegen/nv50_ir_lowering_nvc0.cpp
index 8fd4541..efb5124 100644
--- a/src/gallium/drivers/nvc0/codegen/nv50_ir_lowering_nvc0.cpp
+++ b/src/gallium/drivers/nvc0/codegen/nv50_ir_lowering_nvc0.cpp
@@ -148,7 +148,13 @@ private:
    };
    bool insertTextureBarriers(Function *);
    inline bool insnDominatedBy(const Instruction *, const Instruction *) const;
-   void findFirstUses(const Instruction *, std::list<TexUse>&);
+   void findFirstUses(const Instruction *tex, const Instruction *def,
+                      std::list<TexUse>&);
+   void findOverwritingDefs(const Instruction *tex, Instruction *insn,
+                            const BasicBlock *term,
+                            std::list<TexUse>&);
+   void addTexUse(std::list<TexUse>&, Instruction *, const Instruction *);
+   const Instruction *recurseDef(const Instruction *);
 
 private:
    LValue *r63;
@@ -170,37 +176,88 @@ NVC0LegalizePostRA::insnDominatedBy(const Instruction *later,
 }
 
 void
-NVC0LegalizePostRA::findFirstUses(const Instruction *insn,
+NVC0LegalizePostRA::addTexUse(std::list<TexUse> &uses,
+                              Instruction *usei, const Instruction *insn)
+{
+   bool add = true;
+   for (std::list<TexUse>::iterator it = uses.begin();
+        it != uses.end();) {
+      if (insnDominatedBy(usei, it->insn)) {
+         add = false;
+         break;
+      }
+      if (insnDominatedBy(it->insn, usei))
+         it = uses.erase(it);
+      else
+         ++it;
+   }
+   if (add)
+      uses.push_back(TexUse(usei, insn));
+}
+
+void
+NVC0LegalizePostRA::findOverwritingDefs(const Instruction *texi,
+                                        Instruction *insn,
+                                        const BasicBlock *term,
+                                        std::list<TexUse> &uses)
+{
+   while (insn->op == OP_MOV && insn->getDef(0)->equals(insn->getSrc(0)))
+      insn = insn->getSrc(0)->getUniqueInsn();
+
+   if (!insn || !insn->bb->reachableBy(texi->bb, term))
+      return;
+
+   switch (insn->op) {
+   /* Values not connected to the tex's definition through any of these should
+    * not be conflicting.
+    */
+   case OP_SPLIT:
+   case OP_MERGE:
+   case OP_PHI:
+   case OP_UNION:
+      /* recurse again */
+      for (int s = 0; insn->srcExists(s); ++s)
+         findOverwritingDefs(texi, insn->getSrc(s)->getUniqueInsn(), term,
+                             uses);
+      break;
+   default:
+      // if (!isTextureOp(insn->op)) // TODO: are TEXes always ordered ?
+      addTexUse(uses, insn, texi);
+      break;
+   }
+}
+
+void
+NVC0LegalizePostRA::findFirstUses(const Instruction *texi,
+                                  const Instruction *insn,
                                   std::list<TexUse> &uses)
 {
    for (int d = 0; insn->defExists(d); ++d) {
       Value *v = insn->getDef(d);
       for (Value::UseIterator u = v->uses.begin(); u != v->uses.end(); ++u) {
          Instruction *usei = (*u)->getInsn();
+
+         if (usei->op == OP_PHI || usei->op == OP_UNION) {
+            // need a barrier before WAW cases
+            for (int s = 0; usei->srcExists(s); ++s) {
+               Instruction *defi = usei->getSrc(s)->getUniqueInsn();
+               if (defi && &usei->src(s) != *u)
+                  findOverwritingDefs(texi, defi, usei->bb, uses);
+            }
+         }
+
          if (usei->op == OP_SPLIT ||
+             usei->op == OP_MERGE ||
              usei->op == OP_PHI ||
              usei->op == OP_UNION) {
             // these uses don't manifest in the machine code
-            findFirstUses(usei, uses);
+            findFirstUses(texi, usei, uses);
          } else
          if (usei->op == OP_MOV && usei->getDef(0)->equals(usei->getSrc(0)) &&
              usei->subOp != NV50_IR_SUBOP_MOV_FINAL) {
-            findFirstUses(usei, uses);
+            findFirstUses(texi, usei, uses);
          } else {
-            bool add = true;
-            for (std::list<TexUse>::iterator it = uses.begin();
-                 it != uses.end();) {
-               if (insnDominatedBy(usei, it->insn)) {
-                  add = false;
-                  break;
-               }
-               if (insnDominatedBy(it->insn, usei))
-                  it = uses.erase(it);
-               else
-                  ++it;
-            }
-            if (add)
-               uses.push_back(TexUse(usei, insn));
+            addTexUse(uses, usei, insn);
          }
       }
    }
@@ -255,7 +312,7 @@ NVC0LegalizePostRA::insertTextureBarriers(Function *fn)
    if (!uses)
       return false;
    for (size_t i = 0; i < texes.size(); ++i)
-      findFirstUses(texes[i], uses[i]);
+      findFirstUses(texes[i], texes[i], uses[i]);
 
    // determine the barrier level at each use
    for (size_t i = 0; i < texes.size(); ++i) {
@@ -324,7 +381,7 @@ NVC0LegalizePostRA::insertTextureBarriers(Function *fn)
    limitS.resize(fn->allBBlocks.getSize());
 
    // cull unneeded barriers (should do that earlier, but for simplicity)
-   IteratorRef bi = fn->cfg.iteratorDFS(true);
+   IteratorRef bi = fn->cfg.iteratorCFG();
    // first calculate min/max outstanding TEXes for each BB
    for (bi->reset(); !bi->end(); bi->next()) {
       Graph::Node *n = reinterpret_cast<Graph::Node *>(bi->get());




More information about the mesa-commit mailing list