[Nouveau] [RFC PATCH v2] nv50/ir: allow spilling of def values for constrained MERGES/UNIONS

Tobias Klausmann tobias.johannes.klausmann at mni.thm.de
Tue Aug 1 22:39:42 UTC 2017


This lets us spill more values and compile a Civilization 6 shader with many
local vars. As a precation, only spill those vars as a fallback option if all
other spillable vars are already spilled!

shader-db run shows:
total instructions in shared programs : 4427020 -> 4427388 (0.01%)
total gprs used in shared programs    : 522836 -> 522871 (0.01%)
total local used in shared programs   : 17128 -> 17464 (1.96%)

                local        gpr       inst      bytes
    helped           0           0           0           0
      hurt           0           0           0           0

The additional instructions (+368) gprs (+35) and local (+336) are contained in
the Civilization 6 shader:

90.shader_test - type: 0, local: 336, gpr: 35, inst: 368, bytes: 3928

Signed-off-by: Tobias Klausmann <tobias.johannes.klausmann at mni.thm.de>
---
 src/gallium/drivers/nouveau/codegen/nv50_ir.cpp    |  2 ++
 src/gallium/drivers/nouveau/codegen/nv50_ir.h      |  3 ++
 src/gallium/drivers/nouveau/codegen/nv50_ir_ra.cpp | 39 ++++++++++++++++------
 3 files changed, 34 insertions(+), 10 deletions(-)

diff --git a/src/gallium/drivers/nouveau/codegen/nv50_ir.cpp b/src/gallium/drivers/nouveau/codegen/nv50_ir.cpp
index 08181b790f..2fa8c22e33 100644
--- a/src/gallium/drivers/nouveau/codegen/nv50_ir.cpp
+++ b/src/gallium/drivers/nouveau/codegen/nv50_ir.cpp
@@ -233,6 +233,7 @@ LValue::LValue(Function *fn, DataFile file)
    ssa = 0;
    fixedReg = 0;
    noSpill = 0;
+   softNoSpill = 0;
 
    fn->add(this, this->id);
 }
@@ -250,6 +251,7 @@ LValue::LValue(Function *fn, LValue *lval)
    ssa = 0;
    fixedReg = 0;
    noSpill = 0;
+   softNoSpill = 0;
 
    fn->add(this, this->id);
 }
diff --git a/src/gallium/drivers/nouveau/codegen/nv50_ir.h b/src/gallium/drivers/nouveau/codegen/nv50_ir.h
index bc15992df0..ca5bcb5362 100644
--- a/src/gallium/drivers/nouveau/codegen/nv50_ir.h
+++ b/src/gallium/drivers/nouveau/codegen/nv50_ir.h
@@ -704,6 +704,9 @@ public:
    unsigned ssa      : 1;
    unsigned fixedReg : 1; // set & used by RA, earlier just use (id < 0)
    unsigned noSpill  : 1; // do not spill (e.g. if spill temporary already)
+   unsigned softNoSpill : 1; /* only spill these values if all other values are
+                              * spilled already!
+                              */
 };
 
 class Symbol : public Value
diff --git a/src/gallium/drivers/nouveau/codegen/nv50_ir_ra.cpp b/src/gallium/drivers/nouveau/codegen/nv50_ir_ra.cpp
index b33d7b4010..9d70ec3c9c 100644
--- a/src/gallium/drivers/nouveau/codegen/nv50_ir_ra.cpp
+++ b/src/gallium/drivers/nouveau/codegen/nv50_ir_ra.cpp
@@ -769,7 +769,7 @@ private:
    bool coalesce(ArrayList&);
    bool doCoalesce(ArrayList&, unsigned int mask);
    void calculateSpillWeights();
-   bool simplify();
+   bool simplify(bool useSoftNoSpill);
    bool selectRegisters();
    void cleanup(const bool success);
 
@@ -1242,7 +1242,7 @@ GCRA::calculateSpillWeights()
       }
       LValue *val = nodes[i].getValue();
 
-      if (!val->noSpill) {
+      if (!val->noSpill || val->softNoSpill) {
          int rc = 0;
          for (Value::DefIterator it = val->defs.begin();
               it != val->defs.end();
@@ -1304,7 +1304,7 @@ GCRA::simplifyNode(RIG_Node *node)
 }
 
 bool
-GCRA::simplify()
+GCRA::simplify(bool useSoftNoSpill)
 {
    for (;;) {
       if (!DLLIST_EMPTY(&lo[0])) {
@@ -1317,17 +1317,32 @@ GCRA::simplify()
       } else
       if (!DLLIST_EMPTY(&hi)) {
          RIG_Node *best = hi.next;
-         float bestScore = best->weight / (float)best->degree;
+         bool spillable = false;
+         if (best->getValue()->noSpill && best->getValue()->softNoSpill &&
+               useSoftNoSpill)
+            spillable = true;
+         float bestScore = INFINITY;
+         if (!best->getValue()->noSpill || spillable)
+              bestScore = best->weight / (float)best->degree;
          // spill candidate
          for (RIG_Node *it = best->next; it != &hi; it = it->next) {
-            float score = it->weight / (float)it->degree;
+            float score = INFINITY;
+            bool spillable = false;
+            if (it->getValue()->noSpill && it->getValue()->softNoSpill &&
+                  useSoftNoSpill)
+               spillable = true;
+            if (!it->getValue()->noSpill || spillable) {
+               score = it->weight / (float)it->degree;
+            }
             if (score < bestScore) {
                best = it;
                bestScore = score;
             }
          }
          if (isinf(bestScore)) {
-            ERROR("no viable spill candidates left\n");
+            if (useSoftNoSpill)
+               ERROR("no viable spill candidates left\n");
+
             return false;
          }
          simplifyNode(best);
@@ -1491,9 +1506,12 @@ GCRA::allocateRegisters(ArrayList& insns)
 
    buildRIG(insns);
    calculateSpillWeights();
-   ret = simplify();
-   if (!ret)
-      goto out;
+   ret = simplify(false);
+   if (!ret) {
+      ret = simplify(true);
+      if (!ret)
+         goto out;
+   }
 
    ret = selectRegisters();
    if (!ret) {
@@ -2344,7 +2362,8 @@ RegAlloc::InsertConstraintsPass::insertConstraintMoves()
             cst->setSrc(s, mov->getDef(0));
             cst->bb->insertBefore(cst, mov);
 
-            cst->getDef(0)->asLValue()->noSpill = 1; // doesn't help
+            cst->getDef(0)->asLValue()->softNoSpill = 1;
+            cst->getDef(0)->asLValue()->noSpill = 1; // a precaution
 
             if (cst->op == OP_UNION)
                mov->setPredicate(defi->cc, defi->getPredicate());
-- 
2.13.3



More information about the Nouveau mailing list