From: Francisco Jerez Date: Tue, 20 Mar 2012 23:39:00 +0000 (+0100) Subject: nv50/ir/opt: Improve modifier handling. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=14d5f975a65c57830077dabf2f95261afbc51773;p=mesa.git nv50/ir/opt: Improve modifier handling. --- 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;