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)
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)
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()
// @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; }
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;
class ValueRef
{
public:
- ValueRef();
+ ValueRef(Value * = NULL);
ValueRef(const ValueRef&);
~ValueRef();
class ValueDef
{
public:
- ValueDef();
+ ValueDef(Value * = NULL);
ValueDef(const ValueDef&);
~ValueDef();
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; }
}
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
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;
}
}
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:
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 {
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;