nv50/ir/opt: Improve modifier handling.
authorFrancisco Jerez <currojerez@riseup.net>
Tue, 20 Mar 2012 23:39:00 +0000 (00:39 +0100)
committerChristoph Bumiller <e0425955@student.tuwien.ac.at>
Sat, 14 Apr 2012 19:54:01 +0000 (21:54 +0200)
src/gallium/drivers/nv50/codegen/nv50_ir.cpp
src/gallium/drivers/nv50/codegen/nv50_ir.h
src/gallium/drivers/nv50/codegen/nv50_ir_peephole.cpp

index 8e7fc31eced5c34f423f333fccd035c13b5e290b..862293e39b2960ce8160e645d14b2248403ba42a 100644 (file)
@@ -58,11 +58,12 @@ Modifier Modifier::operator*(const Modifier m) const
    return Modifier(a | c);
 }
 
-ValueRef::ValueRef() : value(NULL), insn(NULL)
+ValueRef::ValueRef(Value *v) : value(NULL), insn(NULL)
 {
    indirect[0] = -1;
    indirect[1] = -1;
    usedAsPtr = false;
+   set(v);
 }
 
 ValueRef::ValueRef(const ValueRef& ref) : value(NULL), insn(ref.insn)
@@ -91,9 +92,9 @@ ImmediateValue *ValueRef::getImmediate() const
    return NULL;
 }
 
-ValueDef::ValueDef() : value(NULL), insn(NULL)
+ValueDef::ValueDef(Value *v) : value(NULL), insn(NULL)
 {
-   // nothing to do
+   set(v);
 }
 
 ValueDef::ValueDef(const ValueDef& def) : value(NULL), insn(NULL)
@@ -141,17 +142,58 @@ ValueDef::set(Value *defVal)
    value = defVal;
 }
 
+// Check if we can replace this definition's value by the value in @rep,
+// including the source modifiers, i.e. make sure that all uses support
+// @rep.mod.
+bool
+ValueDef::mayReplace(const ValueRef &rep)
+{
+   if (!rep.mod)
+      return true;
+
+   if (!insn || !insn->bb) // Unbound instruction ?
+      return false;
+
+   const Target *target = insn->bb->getProgram()->getTarget();
+
+   for (Value::UseIterator it = value->uses.begin(); it != value->uses.end();
+        ++it) {
+      Instruction *insn = (*it)->getInsn();
+      int s = -1;
+
+      for (int i = 0; insn->srcExists(i); ++i) {
+         if (insn->src(i).get() == value) {
+            // If there are multiple references to us we'd have to check if the
+            // combination of mods is still supported, but just bail for now.
+            if (&insn->src(i) != (*it))
+               return false;
+            s = i;
+         }
+      }
+      assert(s >= 0); // integrity of uses list
+
+      if (!target->isModSupported(insn, s, rep.mod))
+         return false;
+   }
+   return true;
+}
+
 void
-ValueDef::replace(Value *repVal, bool doSet)
+ValueDef::replace(const ValueRef &repVal, bool doSet)
 {
-   if (value == repVal)
+   assert(mayReplace(repVal));
+
+   if (value == repVal.get())
       return;
 
-   while (value->refCount())
-      value->uses.front()->set(repVal);
+   while (!value->uses.empty()) {
+      ValueRef *ref = value->uses.front();
+      ref->set(repVal.get());
+      ref->mod *= repVal.mod;
+   }
 
    if (doSet)
-      set(repVal);
+      set(repVal.get());
 }
 
 Value::Value()
index 3f063b0ae2920b3fd08521c7fe0942f44b96ef2b..07392b306271c369ec222426e31d63e9df3e3c1b 100644 (file)
@@ -356,6 +356,7 @@ public:
 
    // @return new Modifier applying a after b (asserts if unrepresentable)
    Modifier operator*(const Modifier) const;
+   Modifier operator*=(const Modifier m) { *this = *this * m; return *this; }
    Modifier operator==(const Modifier m) const { return m.bits == bits; }
    Modifier operator!=(const Modifier m) const { return m.bits != bits; }
 
@@ -368,7 +369,7 @@ public:
    inline int neg() const { return (bits & NV50_IR_MOD_NEG) ? 1 : 0; }
    inline int abs() const { return (bits & NV50_IR_MOD_ABS) ? 1 : 0; }
 
-   inline operator bool() { return bits ? true : false; }
+   inline operator bool() const { return bits ? true : false; }
 
    void applyTo(ImmediateValue &imm) const;
 
@@ -381,7 +382,7 @@ private:
 class ValueRef
 {
 public:
-   ValueRef();
+   ValueRef(Value * = NULL);
    ValueRef(const ValueRef&);
    ~ValueRef();
 
@@ -419,7 +420,7 @@ private:
 class ValueDef
 {
 public:
-   ValueDef();
+   ValueDef(Value * = NULL);
    ValueDef(const ValueDef&);
    ~ValueDef();
 
@@ -428,7 +429,8 @@ public:
    inline Value *get() const { return value; }
    inline Value *rep() const;
    void set(Value *);
-   void replace(Value *, bool doSet); // replace all uses of the old value
+   bool mayReplace(const ValueRef &);
+   void replace(const ValueRef &, bool doSet); // replace all uses of the old value
 
    inline Instruction *getInsn() const { return insn; }
    inline void setInsn(Instruction *inst) { insn = inst; }
index 8bb49c28a4eb8f7ea667da9f3ed753a5c2ffe3f1..ceb118831017eaf769bd9b82c30dbb86c8c984b4 100644 (file)
@@ -853,7 +853,7 @@ ModifierFolding::visit(BasicBlock *bb)
          }
          if ((mod = Modifier(mi->op)) == Modifier(0))
             continue;
-         mod = mod * mi->src(0).mod;
+         mod *= mi->src(0).mod;
 
          if ((i->op == OP_ABS) || i->src(s).mod.abs()) {
             // abs neg [abs] = abs
@@ -872,7 +872,7 @@ ModifierFolding::visit(BasicBlock *bb)
 
          if (target->isModSupported(i, s, mod)) {
             i->setSrc(s, mi->getSrc(0));
-            i->src(s).mod = i->src(s).mod * mod;
+            i->src(s).mod *= mod;
          }
       }
 
@@ -972,12 +972,12 @@ AlgebraicOpt::handleMINMAX(Instruction *minmax)
    if (src0 != src1 || src0->reg.file != FILE_GPR)
       return;
    if (minmax->src(0).mod == minmax->src(1).mod) {
-      if (minmax->src(0).mod) {
+      if (minmax->def(0).mayReplace(minmax->src(0))) {
+         minmax->def(0).replace(minmax->src(0), false);
+         minmax->bb->remove(minmax);
+      } else {
          minmax->op = OP_CVT;
          minmax->setSrc(1, NULL);
-      } else {
-         minmax->def(0).replace(minmax->getSrc(0), false);
-         minmax->bb->remove(minmax);
       }
    } else {
       // TODO:
@@ -1027,11 +1027,9 @@ AlgebraicOpt::handleLOGOP(Instruction *logop)
       return;
 
    if (src0 == src1) {
-      if (logop->src(0).mod != Modifier(0) ||
-          logop->src(1).mod != Modifier(0))
-         return;
-      if (logop->op == OP_AND || logop->op == OP_OR) {
-         logop->def(0).replace(logop->getSrc(0), false);
+      if ((logop->op == OP_AND || logop->op == OP_OR) &&
+          logop->def(0).mayReplace(logop->src(0))) {
+         logop->def(0).replace(logop->src(0), false);
          delete_Instruction(prog, logop);
       }
    } else {
@@ -1457,7 +1455,7 @@ MemoryOpt::replaceLdFromSt(Instruction *ld, Record *rec)
          return false;
       if (st->getSrc(s)->reg.file != FILE_GPR)
          return false;
-      ld->def(d).replace(st->getSrc(s), false);
+      ld->def(d).replace(st->src(s), false);
    }
    ld->bb->remove(ld);
    return true;