summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/gallium/drivers/nv50/codegen/nv50_ir.cpp58
-rw-r--r--src/gallium/drivers/nv50/codegen/nv50_ir.h10
-rw-r--r--src/gallium/drivers/nv50/codegen/nv50_ir_peephole.cpp22
3 files changed, 66 insertions, 24 deletions
diff --git a/src/gallium/drivers/nv50/codegen/nv50_ir.cpp b/src/gallium/drivers/nv50/codegen/nv50_ir.cpp
index 8e7fc31eced..862293e39b2 100644
--- a/src/gallium/drivers/nv50/codegen/nv50_ir.cpp
+++ b/src/gallium/drivers/nv50/codegen/nv50_ir.cpp
@@ -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()
diff --git a/src/gallium/drivers/nv50/codegen/nv50_ir.h b/src/gallium/drivers/nv50/codegen/nv50_ir.h
index 3f063b0ae29..07392b30627 100644
--- a/src/gallium/drivers/nv50/codegen/nv50_ir.h
+++ b/src/gallium/drivers/nv50/codegen/nv50_ir.h
@@ -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; }
diff --git a/src/gallium/drivers/nv50/codegen/nv50_ir_peephole.cpp b/src/gallium/drivers/nv50/codegen/nv50_ir_peephole.cpp
index 8bb49c28a4e..ceb11883101 100644
--- a/src/gallium/drivers/nv50/codegen/nv50_ir_peephole.cpp
+++ b/src/gallium/drivers/nv50/codegen/nv50_ir_peephole.cpp
@@ -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;