return Modifier(a | c);
}
-ValueRef::ValueRef() : value(0), insn(0), next(this), prev(this)
+ValueRef::ValueRef() : value(NULL), insn(NULL)
{
indirect[0] = -1;
indirect[1] = -1;
usedAsPtr = false;
}
+ValueRef::ValueRef(const ValueRef& ref) : value(NULL), insn(ref.insn)
+{
+ set(ref);
+ usedAsPtr = ref.usedAsPtr;
+}
+
ValueRef::~ValueRef()
{
this->set(NULL);
return NULL;
}
-ValueDef::ValueDef() : value(0), insn(0), next(this), prev(this)
+ValueDef::ValueDef() : value(NULL), insn(NULL)
{
// nothing to do
}
+ValueDef::ValueDef(const ValueDef& def) : value(NULL), insn(NULL)
+{
+ set(def.get());
+}
+
ValueDef::~ValueDef()
{
this->set(NULL);
{
if (value == refVal)
return;
- if (value) {
- if (value->uses == this)
- value->uses = (next == this) ? NULL : next;
- value->unref();
- DLLIST_DEL(this);
- }
+ if (value)
+ value->uses.remove(this);
+ if (refVal)
+ refVal->uses.push_back(this);
- if (refVal) {
- if (refVal->uses)
- DLLIST_ADDTAIL(refVal->uses, this);
- else
- refVal->uses = this;
- refVal->ref();
- }
value = refVal;
}
void
ValueDef::set(Value *defVal)
{
- assert(next != this || prev == this); // check that SSA hack isn't active
-
if (value == defVal)
return;
- if (value) {
- if (value->defs == this)
- value->defs = (next == this) ? NULL : next;
- DLLIST_DEL(this);
- }
+ if (value)
+ value->defs.remove(this);
+ if (defVal)
+ defVal->defs.push_back(this);
- if (defVal) {
- if (defVal->defs)
- DLLIST_ADDTAIL(defVal->defs, this);
- else
- defVal->defs = this;
- }
value = defVal;
}
-// TODO: make me faster by using a safe iterator
void
ValueDef::replace(Value *repVal, bool doSet)
{
- ValueRef **refs = new ValueRef * [value->refCount()];
- int n = 0;
+ if (value == repVal)
+ return;
- if (!refs && value->refCount())
- FATAL("memory allocation failed");
-
- for (ValueRef::Iterator iter = value->uses->iterator(); !iter.end();
- iter.next()) {
- assert(n < value->refCount());
- refs[n++] = iter.get();
- }
- while (n)
- refs[--n]->set(repVal);
+ while (value->refCount())
+ value->uses.front()->set(repVal);
if (doSet)
- this->set(repVal);
-
- if (refs)
- delete[] refs;
-}
-
-void
-ValueDef::mergeDefs(ValueDef *join)
-{
- DLLIST_MERGE(this, join, ValueDef *);
+ set(repVal);
}
Value::Value()
{
- refCnt = 0;
- uses = NULL;
- defs = NULL;
join = this;
-
memset(®, 0, sizeof(reg));
reg.size = 4;
}
}
// need to check all fixed register values of the program for overlap
- Function *func = defs->getInsn()->bb->getFunction();
+ Function *func = defs.front()->getInsn()->bb->getFunction();
// TODO: put values in by register-id bins per function
ArrayList::Iterator iter = func->allLValues.iterator();
INFO("NOTE: forced coalescing with live range overlap\n");
}
- ValueDef::Iterator iter = jrep->defs->iterator();
- for (; !iter.end(); iter.next())
- iter.get()->get()->join = repr;
+ for (DefIterator it = jrep->defs.begin(); it != jrep->defs.end(); ++it)
+ (*it)->get()->join = repr;
- repr->defs->mergeDefs(jrep->defs);
+ repr->defs.insert(repr->defs.end(),
+ jrep->defs.begin(), jrep->defs.end());
repr->livei.unify(jrep->livei);
assert(repr->join == repr && jval->join == repr);
postFactor = 0;
- for (int p = 0; p < NV50_IR_MAX_DEFS; ++p)
- def[p].setInsn(this);
- for (int p = 0; p < NV50_IR_MAX_SRCS; ++p)
- src[p].setInsn(this);
-
predSrc = -1;
flagsDef = -1;
flagsSrc = -1;
}
void
-Instruction::setSrc(int s, ValueRef& ref)
+Instruction::setDef(int i, Value *val)
+{
+ int size = def.size();
+ if (i >= size) {
+ def.resize(i + 1);
+ while (size <= i)
+ def[size++].setInsn(this);
+ }
+ def[i].set(val);
+}
+
+void
+Instruction::setSrc(int s, Value *val)
+{
+ int size = src.size();
+ if (s >= size) {
+ src.resize(s + 1);
+ while (size <= s)
+ src[size++].setInsn(this);
+ }
+ src[s].set(val);
+}
+
+void
+Instruction::setSrc(int s, const ValueRef& ref)
{
setSrc(s, ref.get());
src[s].mod = ref.mod;
}
for (int s = 0; this->srcExists(s); ++s)
- insn->src[s].set(this->src[s]);
+ insn->setSrc(s, this->src[s]);
insn->predSrc = this->predSrc;
insn->flagsDef = this->flagsDef;
bool
Instruction::setIndirect(int s, int dim, Value *value)
{
- int p = src[s].indirect[dim];
-
assert(this->srcExists(s));
+
+ int p = src[s].indirect[dim];
if (p < 0) {
if (!value)
return true;
- for (p = s + 1; this->srcExists(p); ++p);
+ p = src.size();
}
- assert(p < NV50_IR_MAX_SRCS);
-
- src[p] = value;
+ setSrc(p, value);
src[p].usedAsPtr = (value != 0);
src[s].indirect[dim] = value ? p : -1;
return true;
return true;
}
- if (predSrc < 0) {
- int s;
- for (s = 0; this->srcExists(s); ++s)
- assert(s < NV50_IR_MAX_SRCS);
- predSrc = s;
- }
- src[predSrc] = value;
+ if (predSrc < 0)
+ predSrc = src.size();
+
+ setSrc(predSrc, value);
return true;
}
bool
Instruction::writesPredicate() const
{
- for (int d = 0; d < 2 && def[d].exists(); ++d)
- if (def[d].exists() &&
- (getDef(d)->inFile(FILE_PREDICATE) || getDef(d)->inFile(FILE_FLAGS)))
+ for (int d = 0; defExists(d); ++d)
+ if (getDef(d)->inFile(FILE_PREDICATE) || getDef(d)->inFile(FILE_FLAGS))
return true;
return false;
}
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
+#include <deque>
+#include <list>
+#include <vector>
#include "nv50_ir_util.h"
#include "nv50_ir_graph.h"
{
public:
ValueRef();
+ ValueRef(const ValueRef&);
~ValueRef();
inline ValueRef& operator=(Value *val) { this->set(val); return *this; }
// SSA: return eventual (traverse MOVs) literal value, if it exists
ImmediateValue *getImmediate() const;
- class Iterator
- {
- public:
- Iterator(ValueRef *ref) : pos(ref), ini(ref) { }
-
- inline ValueRef *get() const { return pos; }
- inline bool end() const { return pos == NULL; }
- inline void next() { pos = (pos->next != ini) ? pos->next : 0; }
-
- private:
- ValueRef *pos, *ini;
- };
-
- inline Iterator iterator() { return Iterator(this); }
-
public:
Modifier mod;
int8_t indirect[2]; // >= 0 if relative to lvalue in insn->src[indirect[i]]
private:
Value *value;
Instruction *insn;
- ValueRef *next; // to link uses of the value
- ValueRef *prev;
};
class ValueDef
{
public:
ValueDef();
+ ValueDef(const ValueDef&);
~ValueDef();
inline ValueDef& operator=(Value *val) { this->set(val); return *this; }
inline DataFile getFile() const;
inline unsigned getSize() const;
- // HACK: save the pre-SSA value in 'prev', in SSA we don't need the def list
- // but we'll use it again for coalescing in register allocation
inline void setSSA(LValue *);
inline const LValue *preSSA() const;
- inline void restoreDefList(); // after having been abused for SSA hack
- void mergeDefs(ValueDef *);
-
- class Iterator
- {
- public:
- Iterator(ValueDef *def) : pos(def), ini(def) { }
-
- inline ValueDef *get() const { return pos; }
- inline bool end() const { return pos == NULL; }
- inline void next() { pos = (pos->next != ini) ? pos->next : NULL; }
-
- private:
- ValueDef *pos, *ini;
- };
-
- inline Iterator iterator() { return Iterator(this); }
private:
Value *value; // should make this LValue * ...
+ LValue *origin; // pre SSA value
Instruction *insn;
- ValueDef *next; // circular list of all definitions of the same value
- ValueDef *prev;
};
class Value
inline Instruction *getUniqueInsn() const;
inline Instruction *getInsn() const; // use when uniqueness is certain
- inline int refCount() { return refCnt; }
- inline int ref() { return ++refCnt; }
- inline int unref() { --refCnt; assert(refCnt >= 0); return refCnt; }
+ inline int refCount() { return uses.size(); }
inline LValue *asLValue();
inline Symbol *asSym();
static inline Value *get(Iterator&);
-protected:
- int refCnt;
-
- friend class ValueDef;
- friend class ValueRef;
+ std::list<ValueRef *> uses;
+ std::list<ValueDef *> defs;
+ typedef std::list<ValueRef *>::iterator UseIterator;
+ typedef std::list<ValueRef *>::const_iterator UseCIterator;
+ typedef std::list<ValueDef *>::iterator DefIterator;
+ typedef std::list<ValueDef *>::const_iterator DefCIterator;
-public:
int id;
- ValueRef *uses;
- ValueDef *defs;
Storage reg;
// TODO: these should be in LValue:
virtual int print(char *, size_t, DataType ty = TYPE_NONE) const;
};
-
-#define NV50_IR_MAX_DEFS 4
-#define NV50_IR_MAX_SRCS 8
-
class Instruction
{
public:
virtual Instruction *clone(bool deep) const;
- inline void setDef(int i, Value *val) { def[i].set(val); }
- inline void setSrc(int s, Value *val) { src[s].set(val); }
- void setSrc(int s, ValueRef&);
+ void setDef(int i, Value *);
+ void setSrc(int s, Value *);
+ void setSrc(int s, const ValueRef&);
void swapSources(int a, int b);
bool setIndirect(int s, int dim, Value *);
inline Value *getSrc(int s) const { return src[s].get(); }
inline Value *getIndirect(int s, int dim) const;
- inline bool defExists(int d) const { return d < 4 && def[d].exists(); }
- inline bool srcExists(int s) const { return s < 8 && src[s].exists(); }
+ inline bool defExists(unsigned d) const
+ {
+ return d < def.size() && def[d].exists();
+ }
+ inline bool srcExists(unsigned s) const
+ {
+ return s < src.size() && src[s].exists();
+ }
- inline bool constrainedDefs() const { return def[1].exists(); }
+ inline bool constrainedDefs() const { return defExists(1); }
bool setPredicate(CondCode ccode, Value *);
inline Value *getPredicate() const;
int8_t flagsDef;
int8_t flagsSrc;
- // NOTE: should make these pointers, saves space and work on shuffling
- ValueDef def[NV50_IR_MAX_DEFS]; // no gaps !
- ValueRef src[NV50_IR_MAX_SRCS]; // no gaps !
+ std::deque<ValueDef> def; // no gaps !
+ std::deque<ValueRef> src; // no gaps !
BasicBlock *bb;
void ValueDef::setSSA(LValue *lval)
{
- Value *save = value;
-
- this->set(NULL);
- prev = reinterpret_cast<ValueDef *>(save);
- value = lval;
- lval->defs = this;
-}
-
-void ValueDef::restoreDefList()
-{
- if (next == this)
- prev = this;
+ origin = value->asLValue();
+ set(lval);
}
const LValue *ValueDef::preSSA() const
{
- return reinterpret_cast<LValue *>(prev);
+ return origin;
}
Instruction *Value::getInsn() const
{
- assert(!defs || getUniqueInsn());
- return defs ? defs->getInsn() : NULL;
+ return defs.empty() ? NULL : defs.front()->getInsn();
}
Instruction *Value::getUniqueInsn() const
{
- if (defs) {
- if (join != this) {
- ValueDef::Iterator it = defs->iterator();
- while (!it.end() && it.get()->get() != this)
- it.next();
- assert(it.get()->get() == this);
- return it.get()->getInsn();
- }
+ if (defs.empty())
+ return NULL;
- // after regalloc, the definitions of coalesced values are linked
- if (reg.data.id < 0) {
- ValueDef::Iterator it = defs->iterator();
- int nDef;
- for (nDef = 0; !it.end() && nDef < 2; it.next())
- if (it.get()->get() == this) // don't count joined values
- ++nDef;
- if (nDef > 1)
- WARN("value %%%i not uniquely defined\n", id); // return NULL ?
- }
-
- assert(defs->get() == this);
- return defs->getInsn();
+ // after regalloc, the definitions of coalesced values are linked
+ if (join != this) {
+ for (DefCIterator it = defs.begin(); it != defs.end(); ++it)
+ if ((*it)->get() == this)
+ return (*it)->getInsn();
+ // should be unreachable and trigger assertion at the end
}
- return NULL;
+#ifdef DEBUG
+ if (reg.data.id < 0) {
+ int n = 0;
+ for (DefCIterator it = defs.begin(); n < 2 && it != defs.end(); ++it)
+ if ((*it)->get() == this) // don't count joined values
+ ++n;
+ if (n > 1)
+ WARN("value %%%i not uniquely defined\n", id); // return NULL ?
+ }
+#endif
+ assert(defs.front()->get() == this);
+ return defs.front()->getInsn();
}
Value *Instruction::getIndirect(int s, int dim) const
if (!fixed && op == OP_NOP)
return true;
- if (def[0].exists() && def[0].rep()->reg.data.id < 0) {
+ if (defExists(0) && def[0].rep()->reg.data.id < 0) {
for (int d = 1; defExists(d); ++d)
if (def[d].rep()->reg.data.id >= 0)
WARN("part of vector result is unused !\n");
if (i->op == OP_MOV) // continue early, MOV appears frequently
continue;
- ImmediateValue *src0 = i->src[0].getImmediate();
- ImmediateValue *src1 = i->src[1].getImmediate();
+ ImmediateValue *src0 = i->srcExists(0) ? i->src[0].getImmediate() : NULL;
+ ImmediateValue *src1 = i->srcExists(1) ? i->src[1].getImmediate() : NULL;
if (src0 && src1)
expr(i, src0, src1);
// b = mul a, imm
// d = mul b, c -> d = mul_x_imm a, c
int s2, t2;
- insn = mul2->getDef(0)->uses->getInsn();
+ insn = mul2->getDef(0)->uses.front()->getInsn();
if (!insn)
return;
mul1 = mul2;
src = ir->getSrc(s);
if (src) {
- for (ValueRef::Iterator refs = src->uses->iterator(); !refs.end();
- refs.next()) {
- Instruction *ik = refs.get()->getInsn();
- if (ik->serial < ir->serial && ik->bb == ir->bb)
+ for (Value::UseIterator it = src->uses.begin();
+ it != src->uses.end(); ++it) {
+ Instruction *ik = (*it)->getInsn();
+ if (ik && ik->serial < ir->serial && ik->bb == ir->bb)
if (tryReplace(&ir, ik))
break;
}
if (rnd != ROUND_N)
PRINT(" %s", RoundModeStr[rnd]);
- if (def[1].exists())
+ if (defExists(1))
PRINT(" {");
for (d = 0; defExists(d); ++d) {
SPACE();
for (Instruction *i = out->getPhi(); i && i->op == OP_PHI; i = i->next) {
bb->liveSet.clr(i->getDef(0)->id);
- for (int s = 0; s < NV50_IR_MAX_SRCS && i->src[s].exists(); ++s) {
+ for (int s = 0; i->srcExists(s); ++s) {
assert(i->src[s].getInsn());
if (i->getSrc(s)->getUniqueInsn()->bb == bb) // XXX: reachableBy ?
bb->liveSet.set(i->getSrc(s)->id);
case OP_MOV:
if (!(mask & JOIN_MASK_MOV))
break;
- i = insn->getDef(0)->uses ? insn->getDef(0)->uses->getInsn() : NULL;
+ i = NULL;
+ if (!insn->getDef(0)->uses.empty())
+ i = insn->getDef(0)->uses.front()->getInsn();
// if this is a contraint-move there will only be a single use
if (i && i->op == OP_CONSTRAINT)
break;
bool
RegAlloc::InsertConstraintsPass::detectConflict(Instruction *cst, int s)
{
+ Value *v = cst->getSrc(s);
+
// current register allocation can't handle it if a value participates in
// multiple constraints
- for (ValueRef::Iterator it = cst->src[s].iterator(); !it.end(); it.next()) {
- Instruction *insn = it.get()->getInsn();
- if (insn != cst)
+ for (Value::UseIterator it = v->uses.begin(); it != v->uses.end(); ++it) {
+ if (cst != (*it)->getInsn())
return true;
}
// can start at s + 1 because detectConflict is called on all sources
for (int c = s + 1; cst->srcExists(c); ++c)
- if (cst->getSrc(c) == cst->getSrc(s))
+ if (v == cst->getSrc(c))
return true;
- Instruction *defi = cst->getSrc(s)->getInsn();
+ Instruction *defi = v->getInsn();
return (!defi || defi->constrainedDefs());
}
if (!allLValues.get(var))
continue;
lval = reinterpret_cast<Value *>(allLValues.get(var))->asLValue();
- if (!lval || !lval->defs)
+ if (!lval || lval->defs.empty())
continue;
++iterCount;
// the BB they're defined in
// gather blocks with assignments to lval in workList
- for (ValueDef::Iterator d = lval->defs->iterator(); !d.end(); d.next()) {
- bb = d.get()->getInsn()->bb;
+ for (Value::DefIterator d = lval->defs.begin();
+ d != lval->defs.end(); ++d) {
+ bb = (*d)->getInsn()->bb;
if (!bb)
continue; // instruction likely been removed but not XXX deleted
if (!dfBB->liveSet.test(lval->id))
continue;
- // TODO: use dedicated PhiInstruction to lift this limit
- assert(dfBB->cfg.incidentCount() <= NV50_IR_MAX_SRCS);
-
phi = new_Instruction(this, OP_PHI, typeOfSize(lval->reg.size));
dfBB->insertTail(phi);
return false;
search(BasicBlock::get(func->domTree->getRoot()));
- ArrayList::Iterator iter = func->allInsns.iterator();
- for (; !iter.end(); iter.next()) {
- Instruction *insn = reinterpret_cast<Instruction *>(iter.get());
- for (int d = 0; insn->defExists(d); ++d)
- insn->def[d].restoreDefList();
- }
-
return true;
}