[Mesa-dev] [PATCH 1/2] nv50/ir: create PhiInstruction as a sibling of Instruction

Rhys Perry pendingchaos02 at gmail.com
Wed Jul 11 15:58:11 UTC 2018


Signed-off-by: Rhys Perry <pendingchaos02 at gmail.com>
---
 src/gallium/drivers/nouveau/codegen/nv50_ir.cpp    | 140 +++++++----
 src/gallium/drivers/nouveau/codegen/nv50_ir.h      | 184 ++++++++------
 src/gallium/drivers/nouveau/codegen/nv50_ir_bb.cpp |  71 +++---
 .../drivers/nouveau/codegen/nv50_ir_build_util.h   |  12 +-
 .../drivers/nouveau/codegen/nv50_ir_emit_gm107.cpp |  24 +-
 .../drivers/nouveau/codegen/nv50_ir_emit_nv50.cpp  |  24 +-
 .../drivers/nouveau/codegen/nv50_ir_emit_nvc0.cpp  |  10 +-
 .../drivers/nouveau/codegen/nv50_ir_from_tgsi.cpp  |  16 +-
 .../drivers/nouveau/codegen/nv50_ir_inlines.h      |  55 ++++-
 .../nouveau/codegen/nv50_ir_lowering_nv50.cpp      |  24 +-
 .../nouveau/codegen/nv50_ir_lowering_nvc0.cpp      |  54 ++---
 .../nouveau/codegen/nv50_ir_lowering_nvc0.h        |  16 +-
 .../drivers/nouveau/codegen/nv50_ir_peephole.cpp   | 269 +++++++++++----------
 .../drivers/nouveau/codegen/nv50_ir_print.cpp      |  81 ++++---
 src/gallium/drivers/nouveau/codegen/nv50_ir_ra.cpp |  99 ++++----
 .../drivers/nouveau/codegen/nv50_ir_ssa.cpp        |  22 +-
 .../drivers/nouveau/codegen/nv50_ir_target.cpp     |  30 +--
 src/gallium/drivers/nouveau/codegen/nv50_ir_util.h |   2 +
 18 files changed, 652 insertions(+), 481 deletions(-)

diff --git a/src/gallium/drivers/nouveau/codegen/nv50_ir.cpp b/src/gallium/drivers/nouveau/codegen/nv50_ir.cpp
index 49425b98b9..d28022fce5 100644
--- a/src/gallium/drivers/nouveau/codegen/nv50_ir.cpp
+++ b/src/gallium/drivers/nouveau/codegen/nv50_ir.cpp
@@ -98,7 +98,7 @@ bool ValueRef::getImmediate(ImmediateValue &imm) const
          return true;
       }
 
-      Instruction *insn = src->value->getUniqueInsn();
+      BaseInstruction *insn = src->value->getUniqueInsn();
 
       if (insn && insn->op == OP_MOV) {
          src = &insn->src(0);
@@ -177,7 +177,7 @@ ValueDef::mayReplace(const ValueRef &rep)
 
    for (Value::UseIterator it = value->uses.begin(); it != value->uses.end();
         ++it) {
-      Instruction *insn = (*it)->getInsn();
+      BaseInstruction *insn = (*it)->getInsn();
       int s = -1;
 
       for (int i = 0; insn->srcExists(i); ++i) {
@@ -191,7 +191,7 @@ ValueDef::mayReplace(const ValueRef &rep)
       }
       assert(s >= 0); // integrity of uses list
 
-      if (!target->isModSupported(insn, s, rep.mod))
+      if (asInsn(insn) && !target->isModSupported(asInsn(insn), s, rep.mod))
          return false;
    }
    return true;
@@ -273,7 +273,7 @@ LValue::isUniform() const
 {
    if (defs.size() > 1)
       return false;
-   Instruction *insn = getInsn();
+   BaseInstruction *insn = getInsn();
    // let's not try too hard here for now ...
    return !insn->srcExists(1) && insn->getSrc(0)->isUniform();
 }
@@ -558,23 +558,34 @@ Symbol::equals(const Value *that, bool strict) const
    return this->reg.data.offset == that->reg.data.offset;
 }
 
-void Instruction::init()
+BaseInstruction::BaseInstruction(Function *fn, operation opr, DataType ty) 
+   : op(opr), dType(ty), sType(ty)
 {
-   next = prev = 0;
+   next = prev = NULL;
+   fixed = 0;
+   terminator = 0;
+   join = 0;
+
+   if (fn) {
+      fn->add(this, id);
+   } else {
+      id = -1;
+      bb = 0;
+   }
+}
 
+void Instruction::init()
+{
    cc = CC_ALWAYS;
    rnd = ROUND_N;
    cache = CACHE_CA;
    subOp = 0;
 
    saturate = 0;
-   join = 0;
    exit = 0;
-   terminator = 0;
    ftz = 0;
    dnz = 0;
    perPatch = 0;
-   fixed = 0;
    encSize = 0;
    ipa = 0;
    mask = 0;
@@ -589,28 +600,19 @@ void Instruction::init()
    flagsSrc = -1;
 }
 
-Instruction::Instruction()
+Instruction::Instruction() : BaseInstruction(NULL, OP_NOP, TYPE_F32)
 {
    init();
-
-   op = OP_NOP;
-   dType = sType = TYPE_F32;
-
-   id = -1;
-   bb = 0;
 }
 
 Instruction::Instruction(Function *fn, operation opr, DataType ty)
+   : BaseInstruction(fn, opr, ty)
 {
+   assert(opr != OP_PHI);
    init();
-
-   op = opr;
-   dType = sType = ty;
-
-   fn->add(this, id);
 }
 
-Instruction::~Instruction()
+BaseInstruction::~BaseInstruction()
 {
    if (bb) {
       Function *fn = bb->getFunction();
@@ -619,14 +621,14 @@ Instruction::~Instruction()
    }
 
    for (int s = 0; srcExists(s); ++s)
-      setSrc(s, NULL);
+      srcs[s].set(NULL);
    // must unlink defs too since the list pointers will get deallocated
    for (int d = 0; defExists(d); ++d)
-      setDef(d, NULL);
+      defs[d].set(NULL);
 }
 
 void
-Instruction::setDef(int i, Value *val)
+BaseInstruction::setDef(int i, Value *val)
 {
    int size = defs.size();
    if (i >= size) {
@@ -740,18 +742,35 @@ Instruction::putExtraSources(int s, Value *values[3])
       setPredicate(cc, values[2]);
 }
 
+BaseInstruction *
+BaseInstruction::clone(ClonePolicy<Function>& pol, BaseInstruction *i) const
+{
+   assert(i);
+
+   pol.set<BaseInstruction>(this, i);
+
+   i->op = op;
+   i->dType = dType;
+   i->sType = sType;
+
+   for (int d = 0; defExists(d); ++d)
+      i->setDef(d, pol.get(getDef(d)));
+
+   return i;
+}
+
 Instruction *
-Instruction::clone(ClonePolicy<Function>& pol, Instruction *i) const
+Instruction::clone(ClonePolicy<Function>& pol, BaseInstruction *bi) const
 {
-   if (!i)
-      i = new_Instruction(pol.context(), op, dType);
+   if (!bi)
+      bi = new_Instruction(pol.context(), op, dType);
 #ifndef NDEBUG // non-conformant assert, so this is required
-   assert(typeid(*i) == typeid(*this));
+   assert(typeid(*bi) == typeid(*this));
 #endif
 
-   pol.set<Instruction>(this, i);
+   BaseInstruction::clone(pol, bi);
 
-   i->sType = sType;
+   Instruction *i = static_cast<Instruction *>(bi);
 
    i->rnd = rnd;
    i->cache = cache;
@@ -769,9 +788,6 @@ Instruction::clone(ClonePolicy<Function>& pol, Instruction *i) const
 
    i->postFactor = postFactor;
 
-   for (int d = 0; defExists(d); ++d)
-      i->setDef(d, pol.get(getDef(d)));
-
    for (int s = 0; srcExists(s); ++s) {
       i->setSrc(s, pol.get(getSrc(s)));
       i->src(s).mod = src(s).mod;
@@ -786,7 +802,7 @@ Instruction::clone(ClonePolicy<Function>& pol, Instruction *i) const
 }
 
 unsigned int
-Instruction::defCount(unsigned int mask, bool singleFile) const
+BaseInstruction::defCount(unsigned int mask, bool singleFile) const
 {
    unsigned int i, n;
 
@@ -805,7 +821,7 @@ Instruction::defCount(unsigned int mask, bool singleFile) const
 }
 
 unsigned int
-Instruction::srcCount(unsigned int mask, bool singleFile) const
+BaseInstruction::srcCount(unsigned int mask, bool singleFile) const
 {
    unsigned int i, n;
 
@@ -926,7 +942,7 @@ TexInstruction::~TexInstruction()
 }
 
 TexInstruction *
-TexInstruction::clone(ClonePolicy<Function>& pol, Instruction *i) const
+TexInstruction::clone(ClonePolicy<Function>& pol, BaseInstruction *i) const
 {
    TexInstruction *tex = (i ? static_cast<TexInstruction *>(i) :
                           new_TexInstruction(pol.context(), op));
@@ -1051,7 +1067,7 @@ CmpInstruction::CmpInstruction(Function *fn, operation op)
 }
 
 CmpInstruction *
-CmpInstruction::clone(ClonePolicy<Function>& pol, Instruction *i) const
+CmpInstruction::clone(ClonePolicy<Function>& pol, BaseInstruction *i) const
 {
    CmpInstruction *cmp = (i ? static_cast<CmpInstruction *>(i) :
                           new_CmpInstruction(pol.context(), op));
@@ -1081,7 +1097,7 @@ FlowInstruction::FlowInstruction(Function *fn, operation op, void *targ)
 }
 
 FlowInstruction *
-FlowInstruction::clone(ClonePolicy<Function>& pol, Instruction *i) const
+FlowInstruction::clone(ClonePolicy<Function>& pol, BaseInstruction *i) const
 {
    FlowInstruction *flow = (i ? static_cast<FlowInstruction *>(i) :
                             new_FlowInstruction(pol.context(), op, NULL));
@@ -1104,6 +1120,42 @@ FlowInstruction::clone(ClonePolicy<Function>& pol, Instruction *i) const
    return flow;
 }
 
+PhiInstruction::PhiInstruction(Function *fn, DataType ty)
+   : BaseInstruction(fn, OP_PHI, ty) {}
+
+PhiInstruction *
+PhiInstruction::clone(ClonePolicy<Function>& pol, BaseInstruction *i) const
+{
+   assert(op == OP_PHI);
+
+   PhiInstruction *phi = (i ? static_cast<PhiInstruction *>(i) :
+                          new_PhiInstruction(pol.context(), dType));
+
+   BaseInstruction::clone(pol, phi);
+
+   return phi;
+}
+
+void
+PhiInstruction::setSrc(int s, Value *val)
+{
+   int size = srcs.size();
+   if (s >= size) {
+      srcs.resize(s + 1);
+      while (size <= s)
+         srcs[size++].setInsn(this);
+   }
+
+   srcs[s].set(val);
+}
+
+void
+PhiInstruction::setSrc(int s, const ValueRef& ref)
+{
+   setSrc(s, ref.get());
+   srcs[s].mod = ref.mod;
+}
+
 Program::Program(Type type, Target *arch)
    : progType(type),
      target(arch),
@@ -1111,6 +1163,7 @@ Program::Program(Type type, Target *arch)
      mem_CmpInstruction(sizeof(CmpInstruction), 4),
      mem_TexInstruction(sizeof(TexInstruction), 4),
      mem_FlowInstruction(sizeof(FlowInstruction), 4),
+     mem_PhiInstruction(sizeof(PhiInstruction), 4),
      mem_LValue(sizeof(LValue), 8),
      mem_Symbol(sizeof(Symbol), 7),
      mem_ImmediateValue(sizeof(ImmediateValue), 7)
@@ -1138,11 +1191,11 @@ Program::~Program()
       releaseValue(reinterpret_cast<Value *>(it.get()));
 }
 
-void Program::releaseInstruction(Instruction *insn)
+void Program::releaseInstruction(BaseInstruction *insn)
 {
    // TODO: make this not suck so much
 
-   insn->~Instruction();
+   insn->~BaseInstruction();
 
    if (insn->asCmp())
       mem_CmpInstruction.release(insn);
@@ -1153,7 +1206,12 @@ void Program::releaseInstruction(Instruction *insn)
    if (insn->asFlow())
       mem_FlowInstruction.release(insn);
    else
+   if (asPhi(insn))
+      mem_PhiInstruction.release(insn);
+   else if (asInsn(insn))
       mem_Instruction.release(insn);
+   else
+      assert(false);
 }
 
 void Program::releaseValue(Value *value)
diff --git a/src/gallium/drivers/nouveau/codegen/nv50_ir.h b/src/gallium/drivers/nouveau/codegen/nv50_ir.h
index f4f3c70888..b80397a0b9 100644
--- a/src/gallium/drivers/nouveau/codegen/nv50_ir.h
+++ b/src/gallium/drivers/nouveau/codegen/nv50_ir.h
@@ -485,6 +485,8 @@ class BasicBlock;
 
 class Target;
 
+class BaseInstruction;
+class PhiInstruction;
 class Instruction;
 class CmpInstruction;
 class TexInstruction;
@@ -539,6 +541,11 @@ struct Storage
 #define NV50_IR_INTERP_OFFSET      (2 << 2)
 #define NV50_IR_INTERP_SAMPLEID    (3 << 2)
 
+static inline PhiInstruction *asPhi(BaseInstruction *i);
+static inline const PhiInstruction *asPhi(const BaseInstruction *i);
+static inline Instruction *asInsn(BaseInstruction *i);
+static inline const Instruction *asInsn(const BaseInstruction *i);
+
 // do we really want this to be a class ?
 class Modifier
 {
@@ -586,8 +593,8 @@ public:
    inline Value *get() const { return value; }
    inline Value *rep() const;
 
-   inline Instruction *getInsn() const { return insn; }
-   inline void setInsn(Instruction *inst) { insn = inst; }
+   inline BaseInstruction *getInsn() const { return insn; }
+   inline void setInsn(BaseInstruction *inst) { insn = inst; }
 
    inline bool isIndirect(int dim) const { return indirect[dim] >= 0; }
    inline const ValueRef *getIndirect(int dim) const;
@@ -606,7 +613,7 @@ public:
 
 private:
    Value *value;
-   Instruction *insn;
+   BaseInstruction *insn;
 };
 
 class ValueDef
@@ -624,8 +631,8 @@ public:
    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; }
+   inline BaseInstruction *getInsn() const { return insn; }
+   inline void setInsn(BaseInstruction *inst) { insn = inst; }
 
    inline DataFile getFile() const;
    inline unsigned getSize() const;
@@ -636,7 +643,7 @@ public:
 private:
    Value *value;   // should make this LValue * ...
    LValue *origin; // pre SSA value
-   Instruction *insn;
+   BaseInstruction *insn;
 };
 
 class Value
@@ -655,8 +662,8 @@ public:
 
    inline Value *rep() const { return join; }
 
-   inline Instruction *getUniqueInsn() const;
-   inline Instruction *getInsn() const; // use when uniqueness is certain
+   inline BaseInstruction *getUniqueInsn() const;
+   inline BaseInstruction *getInsn() const; // use when uniqueness is certain
 
    inline int refCount() { return uses.size(); }
 
@@ -774,26 +781,18 @@ public:
    virtual int print(char *, size_t, DataType ty = TYPE_NONE) const;
 };
 
-class Instruction
+class BaseInstruction
 {
 public:
-   Instruction();
-   Instruction(Function *, operation, DataType);
-   virtual ~Instruction();
+   virtual ~BaseInstruction();
 
-   virtual Instruction *clone(ClonePolicy<Function>&,
-                              Instruction * = NULL) const;
+   virtual BaseInstruction *clone(ClonePolicy<Function>&,
+                                  BaseInstruction * = NULL) const;
 
    void setDef(int i, Value *);
-   void setSrc(int s, Value *);
-   void setSrc(int s, const ValueRef&);
-   void swapSources(int a, int b);
-   void moveSources(int s, int delta);
-   bool setIndirect(int s, int dim, Value *);
 
-   inline ValueRef& src(int s) { return srcs[s]; }
-   inline ValueDef& def(int s) { return defs[s]; }
    inline const ValueRef& src(int s) const { return srcs[s]; }
+   inline ValueDef& def(int s) { return defs[s]; }
    inline const ValueDef& def(int s) const { return defs[s]; }
 
    inline Value *getDef(int d) const { return defs[d].get(); }
@@ -811,24 +810,11 @@ public:
 
    inline bool constrainedDefs() const;
 
-   bool setPredicate(CondCode ccode, Value *);
-   inline Value *getPredicate() const;
-   bool writesPredicate() const;
-   inline bool isPredicated() const { return predSrc >= 0; }
-
-   inline void setFlagsSrc(int s, Value *);
-   inline void setFlagsDef(int d, Value *);
-   inline bool usesFlags() const { return flagsSrc >= 0; }
-
    unsigned int defCount() const { return defs.size(); };
    unsigned int defCount(unsigned int mask, bool singleFile = false) const;
    unsigned int srcCount() const { return srcs.size(); };
    unsigned int srcCount(unsigned int mask, bool singleFile = false) const;
 
-   // save & remove / set indirect[0,1] and predicate source
-   void takeExtraSources(int s, Value *[3]);
-   void putExtraSources(int s, Value *[3]);
-
    inline void setType(DataType type) { dType = sType = type; }
 
    inline void setType(DataType dtype, DataType stype)
@@ -840,13 +826,8 @@ public:
    inline bool isPseudo() const { return op < OP_MOV; }
    bool isDead() const;
    bool isNop() const;
-   bool isCommutationLegal(const Instruction *) const; // must be adjacent !
-   bool isActionEqual(const Instruction *) const;
-   bool isResultEqual(const Instruction *) const;
-
-   // check whether the defs interfere with srcs and defs of another instruction
-   bool canCommuteDefDef(const Instruction *) const;
-   bool canCommuteDefSrc(const Instruction *) const;
+   bool isActionEqual(const BaseInstruction *) const;
+   bool isResultEqual(const BaseInstruction *) const;
 
    void print() const;
 
@@ -858,14 +839,88 @@ public:
    inline const FlowInstruction *asFlow() const;
 
 public:
-   Instruction *next;
-   Instruction *prev;
+   BaseInstruction *next;
+   BaseInstruction *prev;
    int id;
    int serial; // CFG order
 
    operation op;
    DataType dType; // destination or defining type
    DataType sType; // source or secondary type
+
+   unsigned fixed      : 1; // prevent dead code elimination
+   unsigned terminator : 1; // end of basic block
+   unsigned join       : 1; // converge control flow (use OP_JOIN until end)
+
+   BasicBlock *bb;
+
+protected:
+   BaseInstruction();
+   BaseInstruction(Function *, operation, DataType);
+
+   std::deque<ValueDef> defs; // no gaps !
+   std::deque<ValueRef> srcs; // no gaps !
+};
+
+class PhiInstruction : public BaseInstruction
+{
+public:
+   PhiInstruction(Function *, DataType);
+
+   virtual PhiInstruction *clone(ClonePolicy<Function>&,
+                                 BaseInstruction * = NULL) const;
+
+   void setSrc(int s, Value *);
+   void setSrc(int s, const ValueRef&);
+};
+
+class Instruction : public BaseInstruction
+{
+public:
+   Instruction();
+   Instruction(Function *, operation, DataType);
+
+   virtual Instruction *clone(ClonePolicy<Function>&,
+                              BaseInstruction * = NULL) const;
+
+   void setSrc(int s, Value *);
+   void setSrc(int s, const ValueRef&);
+   void swapSources(int a, int b);
+   void moveSources(int s, int delta);
+   bool setIndirect(int s, int dim, Value *);
+
+   inline const ValueRef& src(int s) const { return srcs[s]; }
+   inline ValueRef& src(int s) { return srcs[s]; }
+
+   bool setPredicate(CondCode ccode, Value *);
+   inline Value *getPredicate() const;
+   bool writesPredicate() const;
+   inline bool isPredicated() const { return predSrc >= 0; }
+
+   inline void setFlagsSrc(int s, Value *);
+   inline void setFlagsDef(int d, Value *);
+   inline bool usesFlags() const { return flagsSrc >= 0; }
+
+   // save & remove / set indirect[0,1] and predicate source
+   void takeExtraSources(int s, Value *[3]);
+   void putExtraSources(int s, Value *[3]);
+
+   bool isCommutationLegal(const Instruction *) const; // must be adjacent !
+
+   // check whether the defs interfere with srcs and defs of another instruction
+   bool canCommuteDefDef(const Instruction *) const;
+   bool canCommuteDefSrc(const Instruction *) const;
+
+   inline Instruction *getPrev() const {
+      return asInsn(prev);
+   }
+
+   inline Instruction *getNext() const {
+      assert(next ? asInsn(next) != NULL : true);
+      return static_cast<Instruction *>(next);
+   }
+
+public:
    CondCode cc;
    RoundMode rnd;
    CacheMode cache;
@@ -874,9 +929,6 @@ public:
 
    unsigned encSize    : 4; // encoding size in bytes
    unsigned saturate   : 1; // to [0.0f, 1.0f]
-   unsigned join       : 1; // converge control flow (use OP_JOIN until end)
-   unsigned fixed      : 1; // prevent dead code elimination
-   unsigned terminator : 1; // end of basic block
    unsigned ftz        : 1; // flush denormal to zero
    unsigned dnz        : 1; // denormals, NaN are zero
    unsigned ipa        : 4; // interpolation mode
@@ -895,12 +947,6 @@ public:
 
    uint32_t sched; // scheduling data (NOTE: maybe move to separate storage)
 
-   BasicBlock *bb;
-
-protected:
-   std::deque<ValueDef> defs; // no gaps !
-   std::deque<ValueRef> srcs; // no gaps !
-
    // instruction specific methods:
    // (don't want to subclass, would need more constructors and memory pools)
 public:
@@ -995,7 +1041,7 @@ public:
    virtual ~TexInstruction();
 
    virtual TexInstruction *clone(ClonePolicy<Function>&,
-                                 Instruction * = NULL) const;
+                                 BaseInstruction * = NULL) const;
 
    inline void setTexture(Target targ, uint8_t r, uint8_t s)
    {
@@ -1044,7 +1090,7 @@ public:
    CmpInstruction(Function *, operation);
 
    virtual CmpInstruction *clone(ClonePolicy<Function>&,
-                                 Instruction * = NULL) const;
+                                 BaseInstruction * = NULL) const;
 
    void setCondition(CondCode cond) { setCond = cond; }
    CondCode getCondition() const { return setCond; }
@@ -1059,7 +1105,7 @@ public:
    FlowInstruction(Function *, operation, void *target);
 
    virtual FlowInstruction *clone(ClonePolicy<Function>&,
-                                  Instruction * = NULL) const;
+                                  BaseInstruction * = NULL) const;
 
 public:
    unsigned allWarp  : 1;
@@ -1099,16 +1145,16 @@ public:
    Program *getProgram() const { return program; }
 
    Instruction *getEntry() const { return entry; } // first non-phi instruction
-   Instruction *getPhi() const { return phi; }
-   Instruction *getFirst() const { return phi ? phi : entry; }
-   Instruction *getExit() const { return exit; }
+   PhiInstruction *getPhi() const { return phi; }
+   BaseInstruction *getFirst() const { return phi ? static_cast<BaseInstruction *>(phi) : static_cast<BaseInstruction *>(entry); }
+   BaseInstruction *getExit() const { return exit; }
 
-   void insertHead(Instruction *);
-   void insertTail(Instruction *);
-   void insertBefore(Instruction *, Instruction *);
-   void insertAfter(Instruction *, Instruction *);
-   void remove(Instruction *);
-   void permuteAdjacent(Instruction *, Instruction *);
+   void insertHead(BaseInstruction *);
+   void insertTail(BaseInstruction *);
+   void insertBefore(BaseInstruction *, BaseInstruction *);
+   void insertAfter(BaseInstruction *, BaseInstruction *);
+   void remove(BaseInstruction *);
+   void permuteAdjacent(BaseInstruction *, BaseInstruction *);
 
    BasicBlock *idom() const;
 
@@ -1140,9 +1186,9 @@ private:
    int id;
    DLList df;
 
-   Instruction *phi;
+   PhiInstruction *phi;
    Instruction *entry;
-   Instruction *exit;
+   BaseInstruction *exit;
 
    unsigned int numInsns;
 
@@ -1176,7 +1222,7 @@ public:
    unsigned int orderInstructions(ArrayList&);
 
    inline void add(BasicBlock *bb, int& id) { allBBlocks.insert(bb, id); }
-   inline void add(Instruction *insn, int& id) { allInsns.insert(insn, id); }
+   inline void add(BaseInstruction *insn, int& id) { allInsns.insert(insn, id); }
    inline void add(LValue *lval, int& id) { allLValues.insert(lval, id); }
 
    inline LValue *getLValue(int id);
@@ -1287,6 +1333,7 @@ public:
    MemoryPool mem_CmpInstruction;
    MemoryPool mem_TexInstruction;
    MemoryPool mem_FlowInstruction;
+   MemoryPool mem_PhiInstruction;
    MemoryPool mem_LValue;
    MemoryPool mem_Symbol;
    MemoryPool mem_ImmediateValue;
@@ -1298,7 +1345,7 @@ public:
 
    const struct nv50_ir_prog_info *driver; // for driver configuration
 
-   void releaseInstruction(Instruction *);
+   void releaseInstruction(BaseInstruction *);
    void releaseValue(Value *);
 };
 
@@ -1313,6 +1360,7 @@ private:
    // return false to continue with next entity on next higher level
    virtual bool visit(Function *) { return true; }
    virtual bool visit(BasicBlock *) { return true; }
+   virtual bool visit(BaseInstruction *i);
    virtual bool visit(Instruction *) { return false; }
 
    bool doRun(Program *, bool ordered, bool skipPhi);
diff --git a/src/gallium/drivers/nouveau/codegen/nv50_ir_bb.cpp b/src/gallium/drivers/nouveau/codegen/nv50_ir_bb.cpp
index 9f0e073332..b3d4d8b856 100644
--- a/src/gallium/drivers/nouveau/codegen/nv50_ir_bb.cpp
+++ b/src/gallium/drivers/nouveau/codegen/nv50_ir_bb.cpp
@@ -62,7 +62,7 @@ Function::~Function()
    outs.clear();
 
    for (ArrayList::Iterator it = allInsns.iterator(); !it.end(); it.next())
-      delete_Instruction(prog, reinterpret_cast<Instruction *>(it.get()));
+      delete_Instruction(prog, reinterpret_cast<BaseInstruction *>(it.get()));
 
    for (ArrayList::Iterator it = allLValues.iterator(); !it.end(); it.next())
       delete_Value(prog, reinterpret_cast<LValue *>(it.get()));
@@ -75,7 +75,9 @@ BasicBlock::BasicBlock(Function *fn) : cfg(this), dom(this), func(fn)
 {
    program = func->getProgram();
 
-   joinAt = phi = entry = exit = NULL;
+   joinAt = entry = NULL;
+   exit = NULL;
+   phi = NULL;
 
    numInsns = 0;
    binPos = 0;
@@ -98,7 +100,7 @@ BasicBlock::clone(ClonePolicy<Function>& pol) const
 
    pol.set(this, bb);
 
-   for (Instruction *i = getFirst(); i; i = i->next)
+   for (BaseInstruction *i = getFirst(); i; i = i->next)
       bb->insertTail(i->clone(pol));
 
    pol.context()->cfg.insert(&bb->cfg);
@@ -119,7 +121,7 @@ BasicBlock::idom() const
 }
 
 void
-BasicBlock::insertHead(Instruction *inst)
+BasicBlock::insertHead(BaseInstruction *inst)
 {
    assert(inst->next == 0 && inst->prev == 0);
 
@@ -131,7 +133,8 @@ BasicBlock::insertHead(Instruction *inst)
             insertBefore(entry, inst);
          } else {
             assert(!exit);
-            phi = exit = inst;
+            phi = asPhi(inst);
+            exit = inst;
             inst->bb = this;
             ++numInsns;
          }
@@ -144,7 +147,8 @@ BasicBlock::insertHead(Instruction *inst)
             insertAfter(exit, inst); // after last phi
          } else {
             assert(!exit);
-            entry = exit = inst;
+            entry = asInsn(inst);
+            exit = inst;
             inst->bb = this;
             ++numInsns;
          }
@@ -153,7 +157,7 @@ BasicBlock::insertHead(Instruction *inst)
 }
 
 void
-BasicBlock::insertTail(Instruction *inst)
+BasicBlock::insertTail(BaseInstruction *inst)
 {
    assert(inst->next == 0 && inst->prev == 0);
 
@@ -166,7 +170,8 @@ BasicBlock::insertTail(Instruction *inst)
          insertAfter(exit, inst);
       } else {
          assert(!phi);
-         phi = exit = inst;
+         phi = asPhi(inst);
+         exit = inst;
          inst->bb = this;
          ++numInsns;
       }
@@ -175,7 +180,8 @@ BasicBlock::insertTail(Instruction *inst)
          insertAfter(exit, inst);
       } else {
          assert(!phi);
-         entry = exit = inst;
+         entry = asInsn(inst);
+         exit = inst;
          inst->bb = this;
          ++numInsns;
       }
@@ -183,7 +189,7 @@ BasicBlock::insertTail(Instruction *inst)
 }
 
 void
-BasicBlock::insertBefore(Instruction *q, Instruction *p)
+BasicBlock::insertBefore(BaseInstruction *q, BaseInstruction *p)
 {
    assert(p && q);
 
@@ -192,14 +198,14 @@ BasicBlock::insertBefore(Instruction *q, Instruction *p)
    if (q == entry) {
       if (p->op == OP_PHI) {
          if (!phi)
-            phi = p;
+            phi = asPhi(p);
       } else {
-         entry = p;
+         entry = asInsn(p);
       }
    } else
    if (q == phi) {
       assert(p->op == OP_PHI);
-      phi = p;
+      phi = asPhi(p);
    }
 
    p->next = q;
@@ -213,7 +219,7 @@ BasicBlock::insertBefore(Instruction *q, Instruction *p)
 }
 
 void
-BasicBlock::insertAfter(Instruction *p, Instruction *q)
+BasicBlock::insertAfter(BaseInstruction *p, BaseInstruction *q)
 {
    assert(p && q);
    assert(q->op != OP_PHI || p->op == OP_PHI);
@@ -223,7 +229,7 @@ BasicBlock::insertAfter(Instruction *p, Instruction *q)
    if (p == exit)
       exit = q;
    if (p->op == OP_PHI && q->op != OP_PHI)
-      entry = q;
+      entry = asInsn(q);
 
    q->prev = p;
    q->next = p->next;
@@ -236,7 +242,7 @@ BasicBlock::insertAfter(Instruction *p, Instruction *q)
 }
 
 void
-BasicBlock::remove(Instruction *insn)
+BasicBlock::remove(BaseInstruction *insn)
 {
    assert(insn->bb == this);
 
@@ -250,16 +256,16 @@ BasicBlock::remove(Instruction *insn)
 
    if (insn == entry) {
       if (insn->next)
-         entry = insn->next;
+         entry = asInsn(insn->next);
       else
       if (insn->prev && insn->prev->op != OP_PHI)
-         entry = insn->prev;
+         entry = asInsn(insn->prev);
       else
          entry = NULL;
    }
 
    if (insn == phi)
-      phi = (insn->next && insn->next->op == OP_PHI) ? insn->next : 0;
+      phi = asPhi(insn->next);
 
    --numInsns;
    insn->bb = NULL;
@@ -267,12 +273,12 @@ BasicBlock::remove(Instruction *insn)
    insn->prev = NULL;
 }
 
-void BasicBlock::permuteAdjacent(Instruction *a, Instruction *b)
+void BasicBlock::permuteAdjacent(BaseInstruction *a, BaseInstruction *b)
 {
    assert(a->bb == b->bb);
 
    if (a->next != b) {
-      Instruction *i = a;
+      BaseInstruction *i = a;
       a = b;
       b = i;
    }
@@ -282,7 +288,7 @@ void BasicBlock::permuteAdjacent(Instruction *a, Instruction *b)
    if (b == exit)
       exit = a;
    if (a == entry)
-      entry = b;
+      entry = asInsn(b);
 
    b->prev = a->prev;
    a->next = b->next;
@@ -316,7 +322,7 @@ BasicBlock::splitCommon(Instruction *insn, BasicBlock *bb, bool attach)
       this->cfg.detach(e->getTarget());
    }
 
-   for (; insn; insn = insn->next) {
+   for (; insn; insn = insn->getNext()) {
       this->numInsns--;
       bb->numInsns++;
       insn->bb = bb;
@@ -348,7 +354,7 @@ BasicBlock::splitAfter(Instruction *insn, bool attach)
    bb->joinAt = joinAt;
    joinAt = NULL;
 
-   splitCommon(insn ? insn->next : NULL, bb, attach);
+   splitCommon(insn ? insn->getNext() : NULL, bb, attach);
    return bb;
 }
 
@@ -422,7 +428,7 @@ Function::orderInstructions(ArrayList &result)
       BasicBlock *bb =
          BasicBlock::get(reinterpret_cast<Graph::Node *>(it->get()));
 
-      for (Instruction *insn = bb->getFirst(); insn; insn = insn->next)
+      for (BaseInstruction *insn = bb->getFirst(); insn; insn = insn->next)
          result.insert(insn, insn->serial);
    }
 
@@ -482,7 +488,7 @@ Pass::doRun(Function *func, bool ordered, bool skipPhi)
 {
    IteratorRef bbIter;
    BasicBlock *bb;
-   Instruction *insn, *next;
+   BaseInstruction *insn, *next;
 
    this->func = func;
    if (!visit(func))
@@ -494,8 +500,9 @@ Pass::doRun(Function *func, bool ordered, bool skipPhi)
       bb = BasicBlock::get(reinterpret_cast<Graph::Node *>(bbIter->get()));
       if (!visit(bb))
          break;
-      for (insn = skipPhi ? bb->getEntry() : bb->getFirst(); insn != NULL;
-           insn = next) {
+      insn = skipPhi ? static_cast<BaseInstruction *>(bb->getEntry()) :
+             bb->getFirst();
+      for (; insn != NULL; insn = next) {
          next = insn->next;
          if (!visit(insn))
             break;
@@ -505,6 +512,14 @@ Pass::doRun(Function *func, bool ordered, bool skipPhi)
    return !err;
 }
 
+bool Pass::visit(BaseInstruction *i)
+{
+   if (asInsn(i))
+      return visit(asInsn(i));
+   else
+      return true;
+}
+
 void
 Function::printCFGraph(const char *filePath)
 {
diff --git a/src/gallium/drivers/nouveau/codegen/nv50_ir_build_util.h b/src/gallium/drivers/nouveau/codegen/nv50_ir_build_util.h
index d171f64d9a..865b4afc98 100644
--- a/src/gallium/drivers/nouveau/codegen/nv50_ir_build_util.h
+++ b/src/gallium/drivers/nouveau/codegen/nv50_ir_build_util.h
@@ -38,12 +38,12 @@ public:
    // keeps inserting at head/tail of block
    inline void setPosition(BasicBlock *, bool tail);
    // position advances only if @after is true
-   inline void setPosition(Instruction *, bool after);
+   inline void setPosition(BaseInstruction *, bool after);
 
    inline BasicBlock *getBB() { return bb; }
 
-   inline void insert(Instruction *);
-   inline void remove(Instruction *i) { assert(i->bb == bb); bb->remove(i); }
+   inline void insert(BaseInstruction *);
+   inline void remove(BaseInstruction *i) { assert(i->bb == bb); bb->remove(i); }
 
    inline LValue *getScratch(int size = 4, DataFile = FILE_GPR);
    // scratch value for a single assignment:
@@ -183,7 +183,7 @@ private:
 protected:
    Program *prog;
    Function *func;
-   Instruction *pos;
+   BaseInstruction *pos;
    BasicBlock *bb;
    bool tail;
 
@@ -214,7 +214,7 @@ BuildUtil::setPosition(BasicBlock *block, bool atTail)
 }
 
 void
-BuildUtil::setPosition(Instruction *i, bool after)
+BuildUtil::setPosition(BaseInstruction *i, bool after)
 {
    bb = i->bb;
    prog = bb->getProgram();
@@ -241,7 +241,7 @@ BuildUtil::getSSA(int size, DataFile f)
    return lval;
 }
 
-void BuildUtil::insert(Instruction *i)
+void BuildUtil::insert(BaseInstruction *i)
 {
    if (!pos) {
       tail ? bb->insertTail(i) : bb->insertHead(i);
diff --git a/src/gallium/drivers/nouveau/codegen/nv50_ir_emit_gm107.cpp b/src/gallium/drivers/nouveau/codegen/nv50_ir_emit_gm107.cpp
index 26826d6360..036329d5e0 100644
--- a/src/gallium/drivers/nouveau/codegen/nv50_ir_emit_gm107.cpp
+++ b/src/gallium/drivers/nouveau/codegen/nv50_ir_emit_gm107.cpp
@@ -3722,7 +3722,7 @@ SchedDataCalculatorGM107::getWtDepBar(const Instruction *insn) const
 void
 SchedDataCalculatorGM107::setReuseFlag(Instruction *insn)
 {
-   Instruction *next = insn->next;
+   Instruction *next = insn->getNext();
    BitSet defs(255, 1);
 
    if (!targ->isReuseSupported(insn))
@@ -3999,8 +3999,8 @@ SchedDataCalculatorGM107::findFirstUse(const Instruction *bari) const
    if (!bari->defExists(0))
       return NULL;
 
-   for (insn = bari->next; insn != NULL; insn = next) {
-      next = insn->next;
+   for (insn = bari->getNext(); insn != NULL; insn = next) {
+      next = insn->getNext();
 
       for (int s = 0; insn->srcExists(s); ++s)
          if (doesInsnWriteTo(bari, insn->getSrc(s)))
@@ -4023,8 +4023,8 @@ SchedDataCalculatorGM107::findFirstDef(const Instruction *bari) const
    if (!bari->srcExists(0))
       return NULL;
 
-   for (insn = bari->next; insn != NULL; insn = next) {
-      next = insn->next;
+   for (insn = bari->getNext(); insn != NULL; insn = next) {
+      next = insn->getNext();
 
       for (int s = 0; bari->srcExists(s); ++s)
          if (doesInsnWriteTo(insn, bari->getSrc(s)))
@@ -4052,7 +4052,7 @@ SchedDataCalculatorGM107::insertBarriers(BasicBlock *bb)
       Instruction *usei = NULL, *defi = NULL;
       bool need_wr_bar, need_rd_bar;
 
-      next = insn->next;
+      next = insn->getNext();
 
       // Expire old barrier uses.
       for (std::list<LiveBarUse>::iterator it = live_uses.begin();
@@ -4125,7 +4125,7 @@ SchedDataCalculatorGM107::insertBarriers(BasicBlock *bb)
    for (insn = bb->getEntry(); insn != NULL; insn = next) {
       int wr, rd, wt;
 
-      next = insn->next;
+      next = insn->getNext();
 
       wr = getWrDepBar(insn);
       rd = getRdDepBar(insn);
@@ -4169,7 +4169,7 @@ SchedDataCalculatorGM107::visit(BasicBlock *bb)
    Instruction *insn, *next = NULL;
    int cycle = 0;
 
-   for (Instruction *insn = bb->getEntry(); insn; insn = insn->next) {
+   for (Instruction *insn = bb->getEntry(); insn; insn = insn->getNext()) {
       /*XXX*/
       insn->sched = 0x7e0;
    }
@@ -4208,8 +4208,8 @@ SchedDataCalculatorGM107::visit(BasicBlock *bb)
          emitWtDepBar(start, b);
    }
 
-   for (insn = bb->getEntry(); insn && insn->next; insn = insn->next) {
-      next = insn->next;
+   for (insn = bb->getEntry(); insn && insn->next; insn = insn->getNext()) {
+      next = insn->getNext();
 
       commitInsn(insn, cycle);
       int delay = calcDelay(next, cycle);
@@ -4258,8 +4258,8 @@ SchedDataCalculatorGM107::visit(BasicBlock *bb)
       } else {
          // Wait until all dependencies are satisfied.
          const int regsFree = score->getLatest();
-         next = out->getFirst();
-         for (int c = cycle; next && c < regsFree; next = next->next) {
+         next = out->getEntry();
+         for (int c = cycle; next && c < regsFree; next = next->getNext()) {
             bbDelay = MAX2(bbDelay, calcDelay(next, c));
             c += getStall(next);
          }
diff --git a/src/gallium/drivers/nouveau/codegen/nv50_ir_emit_nv50.cpp b/src/gallium/drivers/nouveau/codegen/nv50_ir_emit_nv50.cpp
index 139ff4a31d..49b3bc8ec6 100644
--- a/src/gallium/drivers/nouveau/codegen/nv50_ir_emit_nv50.cpp
+++ b/src/gallium/drivers/nouveau/codegen/nv50_ir_emit_nv50.cpp
@@ -2126,15 +2126,15 @@ makeInstructionLong(Instruction *insn)
    int n = 0;
    int adj = 4;
 
-   for (Instruction *i = insn->next; i && i->encSize == 4; ++n, i = i->next);
+   for (Instruction *i = insn->getNext(); i && i->encSize == 4; ++n, i = i->getNext());
 
    if (n & 1) {
       adj = 8;
-      insn->next->encSize = 8;
+      insn->getNext()->encSize = 8;
    } else
-   if (insn->prev && insn->prev->encSize == 4) {
+   if (insn->getPrev() && insn->getPrev()->encSize == 4) {
       adj = 8;
-      insn->prev->encSize = 8;
+      insn->getPrev()->encSize = 8;
    }
    insn->encSize = 8;
 
@@ -2146,7 +2146,7 @@ makeInstructionLong(Instruction *insn)
 }
 
 static bool
-trySetExitModifier(Instruction *insn)
+trySetExitModifier(BaseInstruction *insn)
 {
    if (insn->op == OP_DISCARD ||
        insn->op == OP_QUADON ||
@@ -2158,12 +2158,12 @@ trySetExitModifier(Instruction *insn)
    if (insn->asFlow()) {
       if (insn->op == OP_CALL) // side effects !
          return false;
-      if (insn->getPredicate()) // cannot do conditional exit (or can we ?)
+      if (asInsn(insn)->getPredicate()) // cannot do conditional exit (or can we ?)
          return false;
       insn->op = OP_EXIT;
    }
-   insn->exit = 1;
-   makeInstructionLong(insn);
+   asInsn(insn)->exit = 1;
+   makeInstructionLong(asInsn(insn));
    return true;
 }
 
@@ -2177,22 +2177,22 @@ replaceExitWithModifier(Function *func)
       return;
 
    if (epilogue->getEntry()->op != OP_EXIT) {
-      Instruction *insn = epilogue->getExit()->prev;
+      BaseInstruction *insn = epilogue->getExit();
       if (!insn || !trySetExitModifier(insn))
          return;
-      insn->exit = 1;
+      asInsn(insn)->exit = 1;
    } else {
       for (Graph::EdgeIterator ei = func->cfgExit->incident();
            !ei.end(); ei.next()) {
          BasicBlock *bb = BasicBlock::get(ei.getNode());
-         Instruction *i = bb->getExit();
+         BaseInstruction *i = bb->getExit();
 
          if (!i || !trySetExitModifier(i))
             return;
       }
    }
 
-   int adj = epilogue->getExit()->encSize;
+   int adj = asInsn(epilogue->getExit())->encSize;
    epilogue->binSize -= adj;
    func->binSize -= adj;
    delete_Instruction(func->getProgram(), epilogue->getExit());
diff --git a/src/gallium/drivers/nouveau/codegen/nv50_ir_emit_nvc0.cpp b/src/gallium/drivers/nouveau/codegen/nv50_ir_emit_nvc0.cpp
index d85fdda56f..7fde0f1001 100644
--- a/src/gallium/drivers/nouveau/codegen/nv50_ir_emit_nvc0.cpp
+++ b/src/gallium/drivers/nouveau/codegen/nv50_ir_emit_nvc0.cpp
@@ -3245,7 +3245,7 @@ SchedDataCalculator::visit(BasicBlock *bb)
       BasicBlock *in = BasicBlock::get(ei.getNode());
       if (in->getExit()) {
          if (prevData != 0x04)
-            prevData = in->getExit()->sched;
+            prevData = asInsn(in->getExit())->sched;
          prevOp = in->getExit()->op;
       }
       score->setMax(&scoreBoards.at(in->getId()));
@@ -3258,8 +3258,8 @@ SchedDataCalculator::visit(BasicBlock *bb)
    score->print(cycle);
 #endif
 
-   for (insn = bb->getEntry(); insn && insn->next; insn = insn->next) {
-      next = insn->next;
+   for (insn = bb->getEntry(); insn && insn->next; insn = insn->getNext()) {
+      next = insn->getNext();
 
       commitInsn(insn, cycle);
       int delay = calcDelay(next, cycle);
@@ -3289,8 +3289,8 @@ SchedDataCalculator::visit(BasicBlock *bb)
       } else {
          // wait until all dependencies are satisfied
          const int regsFree = score->getLatest();
-         next = out->getFirst();
-         for (int c = cycle; next && c < regsFree; next = next->next) {
+         next = out->getEntry();
+         for (int c = cycle; next && c < regsFree; next = next->getNext()) {
             bbDelay = MAX2(bbDelay, calcDelay(next, c));
             c += getCycles(next, bbDelay);
          }
diff --git a/src/gallium/drivers/nouveau/codegen/nv50_ir_from_tgsi.cpp b/src/gallium/drivers/nouveau/codegen/nv50_ir_from_tgsi.cpp
index 2f9bcc1f34..854301b644 100644
--- a/src/gallium/drivers/nouveau/codegen/nv50_ir_from_tgsi.cpp
+++ b/src/gallium/drivers/nouveau/codegen/nv50_ir_from_tgsi.cpp
@@ -1987,7 +1987,7 @@ Converter::fetchSrc(int s, int c)
    res = fetchSrc(src, c, ptr);
 
    if (dimRel)
-      res->getInsn()->setIndirect(0, 1, dimRel);
+      asInsn(res->getInsn())->setIndirect(0, 1, dimRel);
 
    return applySrcMod(res, s, c);
 }
@@ -2028,7 +2028,7 @@ Converter::fetchDst(int d, int c)
    res = fetchSrc(src, c, ptr);
 
    if (dimRel)
-      res->getInsn()->setIndirect(0, 1, dimRel);
+      asInsn(res->getInsn())->setIndirect(0, 1, dimRel);
 
    return res;
 }
@@ -2337,7 +2337,7 @@ void
 Converter::loadProjTexCoords(Value *dst[4], Value *src[4], unsigned int mask)
 {
    Value *proj = fetchSrc(0, 3);
-   Instruction *insn = proj->getUniqueInsn();
+   Instruction *insn = asInsn(proj->getUniqueInsn());
    int c;
 
    if (insn->op == OP_PINTERP) {
@@ -2352,7 +2352,7 @@ Converter::loadProjTexCoords(Value *dst[4], Value *src[4], unsigned int mask)
    for (c = 0; c < 4; ++c) {
       if (!(mask & (1 << c)))
          continue;
-      if ((insn = src[c]->getUniqueInsn())->op != OP_PINTERP)
+      if ((insn = asInsn(src[c]->getUniqueInsn()))->op != OP_PINTERP)
          continue;
       mask &= ~(1 << c);
 
@@ -3074,10 +3074,10 @@ Converter::handleINTERP(Value *dst[4])
       FOR_EACH_DST_ENABLED_CHANNEL(0, c, tgsi) {
          Value *val = fetchSrc(0, c);
          assert(val->defs.size() == 1);
-         insn = val->getInsn();
+         insn = asInsn(val->getInsn());
          while (insn->op == OP_MOV) {
             assert(insn->getSrc(0)->defs.size() == 1);
-            insn = insn->getSrc(0)->getInsn();
+            insn = asInsn(insn->getSrc(0)->getInsn());
             if (!insn) {
                ERROR("Miscompiling shader due to unhandled INTERP\n");
                return;
@@ -4375,8 +4375,8 @@ Converter::BindArgumentsPass::visit(Function *f)
 
    for (ArrayList::Iterator bi = f->allBBlocks.iterator();
         !bi.end(); bi.next()) {
-      for (Instruction *i = BasicBlock::get(bi)->getFirst();
-           i; i = i->next) {
+      for (Instruction *i = BasicBlock::get(bi)->getEntry();
+           i; i = i->getNext()) {
          if (i->op == OP_CALL && !i->asFlow()->builtin) {
             updateCallArgs(i, &Instruction::setSrc, &Function::ins);
             updateCallArgs(i, &Instruction::setDef, &Function::outs);
diff --git a/src/gallium/drivers/nouveau/codegen/nv50_ir_inlines.h b/src/gallium/drivers/nouveau/codegen/nv50_ir_inlines.h
index 4cb53ab42e..5d19614d4a 100644
--- a/src/gallium/drivers/nouveau/codegen/nv50_ir_inlines.h
+++ b/src/gallium/drivers/nouveau/codegen/nv50_ir_inlines.h
@@ -205,12 +205,12 @@ const LValue *ValueDef::preSSA() const
    return origin;
 }
 
-Instruction *Value::getInsn() const
+BaseInstruction *Value::getInsn() const
 {
    return defs.empty() ? NULL : defs.front()->getInsn();
 }
 
-Instruction *Value::getUniqueInsn() const
+BaseInstruction *Value::getUniqueInsn() const
 {
    if (defs.empty())
       return NULL;
@@ -236,12 +236,12 @@ Instruction *Value::getUniqueInsn() const
    return defs.front()->getInsn();
 }
 
-inline bool Instruction::constrainedDefs() const
+inline bool BaseInstruction::constrainedDefs() const
 {
    return defExists(1) || op == OP_UNION;
 }
 
-Value *Instruction::getIndirect(int s, int dim) const
+Value *BaseInstruction::getIndirect(int s, int dim) const
 {
    return srcs[s].isIndirect(dim) ? getSrc(srcs[s].indirect[dim]) : NULL;
 }
@@ -281,49 +281,77 @@ Value *TexInstruction::getIndirectS() const
    return tex.rIndirectSrc >= 0 ? getSrc(tex.rIndirectSrc) : NULL;
 }
 
-CmpInstruction *Instruction::asCmp()
+CmpInstruction *BaseInstruction::asCmp()
 {
    if (op >= OP_SET_AND && op <= OP_SLCT && op != OP_SELP)
       return static_cast<CmpInstruction *>(this);
    return NULL;
 }
 
-const CmpInstruction *Instruction::asCmp() const
+const CmpInstruction *BaseInstruction::asCmp() const
 {
    if (op >= OP_SET_AND && op <= OP_SLCT && op != OP_SELP)
       return static_cast<const CmpInstruction *>(this);
    return NULL;
 }
 
-FlowInstruction *Instruction::asFlow()
+FlowInstruction *BaseInstruction::asFlow()
 {
    if (op >= OP_BRA && op <= OP_JOIN)
       return static_cast<FlowInstruction *>(this);
    return NULL;
 }
 
-const FlowInstruction *Instruction::asFlow() const
+const FlowInstruction *BaseInstruction::asFlow() const
 {
    if (op >= OP_BRA && op <= OP_JOIN)
       return static_cast<const FlowInstruction *>(this);
    return NULL;
 }
 
-TexInstruction *Instruction::asTex()
+TexInstruction *BaseInstruction::asTex()
 {
    if ((op >= OP_TEX && op <= OP_SULEA) || op == OP_SUQ)
       return static_cast<TexInstruction *>(this);
    return NULL;
 }
 
-const TexInstruction *Instruction::asTex() const
+const TexInstruction *BaseInstruction::asTex() const
 {
    if ((op >= OP_TEX && op <= OP_SULEA) || op == OP_SUQ)
       return static_cast<const TexInstruction *>(this);
    return NULL;
 }
 
-static inline Instruction *cloneForward(Function *ctx, Instruction *obj)
+static inline PhiInstruction *asPhi(BaseInstruction *i)
+{
+   if (!i)
+      return NULL;
+   return i->op == OP_PHI ? static_cast<PhiInstruction *>(i) : NULL;
+}
+
+static inline const PhiInstruction *asPhi(const BaseInstruction *i)
+{
+   if (!i)
+      return NULL;
+   return i->op == OP_PHI ? static_cast<const PhiInstruction *>(i) : NULL;
+}
+
+static inline Instruction *asInsn(BaseInstruction *i)
+{
+   if (!i)
+      return NULL;
+   return i->op == OP_PHI ? NULL : static_cast<Instruction *>(i);
+}
+
+static inline const Instruction *asInsn(const BaseInstruction *i)
+{
+   if (!i)
+      return NULL;
+   return i->op == OP_PHI ? NULL : static_cast<const Instruction *>(i);
+}
+
+static inline BaseInstruction *cloneForward(Function *ctx, const BaseInstruction *obj)
 {
    DeepClonePolicy<Function> pol(ctx);
 
@@ -333,6 +361,11 @@ static inline Instruction *cloneForward(Function *ctx, Instruction *obj)
    return obj->clone(pol);
 }
 
+static inline Instruction *cloneForward(Function *ctx, const Instruction *obj)
+{
+   return asInsn(cloneForward(ctx, static_cast<const BaseInstruction *>(obj)));
+}
+
 // XXX: use a virtual function so we're really really safe ?
 LValue *Value::asLValue()
 {
diff --git a/src/gallium/drivers/nouveau/codegen/nv50_ir_lowering_nv50.cpp b/src/gallium/drivers/nouveau/codegen/nv50_ir_lowering_nv50.cpp
index 36ab837f6e..e47b36a158 100644
--- a/src/gallium/drivers/nouveau/codegen/nv50_ir_lowering_nv50.cpp
+++ b/src/gallium/drivers/nouveau/codegen/nv50_ir_lowering_nv50.cpp
@@ -294,7 +294,7 @@ NV50LegalizePostRA::handlePRERET(FlowInstruction *pre)
 bool
 NV50LegalizePostRA::visit(BasicBlock *bb)
 {
-   Instruction *i, *next;
+   BaseInstruction *i, *next;
 
    // remove pseudo operations and non-fixed no-ops, split 64 bit operations
    for (i = bb->getFirst(); i; i = next) {
@@ -308,14 +308,14 @@ NV50LegalizePostRA::visit(BasicBlock *bb)
          // TODO: We will want to do this before register allocation,
          // since have to use a $c register for the carry flag.
          if (typeSizeof(i->dType) == 8) {
-            Instruction *hi = BuildUtil::split64BitOpPostRA(func, i, r63, NULL);
+            Instruction *hi = BuildUtil::split64BitOpPostRA(func, asInsn(i), r63, NULL);
             if (hi)
                next = hi;
          }
 
          if (i->op != OP_PFETCH && i->op != OP_BAR &&
              (!i->defExists(0) || i->def(0).getFile() != FILE_ADDRESS))
-            replaceZero(i);
+            replaceZero(asInsn(i));
       }
    }
    if (!bb->getEntry())
@@ -338,7 +338,7 @@ private:
    void handleMUL(Instruction *);
    void handleAddrDef(Instruction *);
 
-   inline bool isARL(const Instruction *) const;
+   inline bool isARL(const BaseInstruction *) const;
 
    BuildUtil bld;
 
@@ -365,7 +365,7 @@ NV50LegalizeSSA::propagateWriteToOutput(Instruction *st)
       return;
 
    // check def instruction can store
-   Instruction *di = st->getSrc(1)->defs.front()->getInsn();
+   BaseInstruction *di = st->getSrc(1)->defs.front()->getInsn();
 
    // TODO: move exports (if beneficial) in common opt pass
    if (di->isPseudo() || isTextureOp(di->op) || di->defCount(0xff, true) > 1)
@@ -381,7 +381,7 @@ NV50LegalizeSSA::propagateWriteToOutput(Instruction *st)
       // that we are propagating to the same output vertex.
       if (di->bb != st->bb)
          return;
-      Instruction *i;
+      BaseInstruction *i;
       for (i = di; i != st; i = i->next) {
          if (i->op == OP_EMIT || i->op == OP_RESTART)
             return;
@@ -396,7 +396,7 @@ NV50LegalizeSSA::propagateWriteToOutput(Instruction *st)
 }
 
 bool
-NV50LegalizeSSA::isARL(const Instruction *i) const
+NV50LegalizeSSA::isARL(const BaseInstruction *i) const
 {
    ImmediateValue imm;
 
@@ -475,7 +475,7 @@ NV50LegalizeSSA::handleMUL(Instruction *mul)
    }
    expandIntegerMUL(&bld, mul);
    if (pred)
-      def->getInsn()->setPredicate(cc, pred);
+      asInsn(def->getInsn())->setPredicate(cc, pred);
 }
 
 // Use f32 division: first compute an approximate result, use it to reduce
@@ -500,8 +500,8 @@ NV50LegalizeSSA::handleDIV(Instruction *div)
    bld.mkCvt(OP_CVT, TYPE_F32, bf, ty, div->getSrc(1));
 
    if (isSignedType(ty)) {
-      af->getInsn()->src(0).mod = Modifier(NV50_IR_MOD_ABS);
-      bf->getInsn()->src(0).mod = Modifier(NV50_IR_MOD_ABS);
+      asInsn(af->getInsn())->src(0).mod = Modifier(NV50_IR_MOD_ABS);
+      asInsn(bf->getInsn())->src(0).mod = Modifier(NV50_IR_MOD_ABS);
       a = bld.getSSA();
       b = bld.getSSA();
       bld.mkOp1(OP_ABS, ty, a, div->getSrc(0));
@@ -566,7 +566,7 @@ NV50LegalizeSSA::handleMOD(Instruction *mod)
    Value *m = bld.getSSA();
 
    bld.mkOp2(OP_DIV, mod->dType, q, mod->getSrc(0), mod->getSrc(1));
-   handleDIV(q->getInsn());
+   handleDIV(asInsn(q->getInsn()));
 
    bld.setPosition(mod, false);
    expandIntegerMUL(&bld, bld.mkOp2(OP_MUL, TYPE_U32, m, q, mod->getSrc(1)));
@@ -581,7 +581,7 @@ NV50LegalizeSSA::visit(BasicBlock *bb)
    Instruction *insn, *next;
    // skipping PHIs (don't pass them to handleAddrDef) !
    for (insn = bb->getEntry(); insn; insn = next) {
-      next = insn->next;
+      next = insn->getNext();
 
       if (insn->defExists(0) && insn->getDef(0)->reg.file == FILE_ADDRESS)
          handleAddrDef(insn);
diff --git a/src/gallium/drivers/nouveau/codegen/nv50_ir_lowering_nvc0.cpp b/src/gallium/drivers/nouveau/codegen/nv50_ir_lowering_nvc0.cpp
index 597dcdffbe..4b76d69405 100644
--- a/src/gallium/drivers/nouveau/codegen/nv50_ir_lowering_nvc0.cpp
+++ b/src/gallium/drivers/nouveau/codegen/nv50_ir_lowering_nvc0.cpp
@@ -50,7 +50,7 @@ NVC0LegalizeSSA::handleDIV(Instruction *i)
 
    // Generate movs to the input regs for the call we want to generate
    for (int s = 0; i->srcExists(s); ++s) {
-      Instruction *ld = i->getSrc(s)->getInsn();
+      BaseInstruction *ld = i->getSrc(s)->getInsn();
       assert(ld->getSrc(0) != NULL);
       // check if we are moving an immediate, propagate it in that case
       if (!ld || ld->fixed || (ld->op != OP_LOAD && ld->op != OP_MOV) ||
@@ -284,7 +284,7 @@ NVC0LegalizeSSA::visit(BasicBlock *bb)
 {
    Instruction *next;
    for (Instruction *i = bb->getEntry(); i; i = next) {
-      next = i->next;
+      next = i->getNext();
 
       if (i->sType == TYPE_F32 && prog->getType() != Program::TYPE_COMPUTE)
          handleFTZ(i);
@@ -333,8 +333,8 @@ NVC0LegalizePostRA::NVC0LegalizePostRA(const Program *prog)
 }
 
 bool
-NVC0LegalizePostRA::insnDominatedBy(const Instruction *later,
-                                    const Instruction *early) const
+NVC0LegalizePostRA::insnDominatedBy(const BaseInstruction *later,
+                                    const BaseInstruction *early) const
 {
    if (early->bb == later->bb)
       return early->serial < later->serial;
@@ -343,7 +343,7 @@ NVC0LegalizePostRA::insnDominatedBy(const Instruction *later,
 
 void
 NVC0LegalizePostRA::addTexUse(std::list<TexUse> &uses,
-                              Instruction *usei, const Instruction *texi)
+                              BaseInstruction *usei, const BaseInstruction *texi)
 {
    bool add = true;
    bool dominated = insnDominatedBy(usei, texi);
@@ -383,7 +383,7 @@ NVC0LegalizePostRA::addTexUse(std::list<TexUse> &uses,
 // instructions looking for ones that reference the registers in question.
 void
 NVC0LegalizePostRA::findFirstUses(
-   Instruction *texi, std::list<TexUse> &uses)
+   BaseInstruction *texi, std::list<TexUse> &uses)
 {
    int minGPR = texi->def(0).rep()->reg.data.id;
    int maxGPR = minGPR + texi->def(0).rep()->reg.size / 4 - 1;
@@ -394,8 +394,8 @@ NVC0LegalizePostRA::findFirstUses(
 
 void
 NVC0LegalizePostRA::findFirstUsesBB(
-   int minGPR, int maxGPR, Instruction *start,
-   const Instruction *texi, std::list<TexUse> &uses,
+   int minGPR, int maxGPR, BaseInstruction *start,
+   const BaseInstruction *texi, std::list<TexUse> &uses,
    unordered_set<const BasicBlock *> &visited)
 {
    const BasicBlock *bb = start->bb;
@@ -410,7 +410,7 @@ NVC0LegalizePostRA::findFirstUsesBB(
       visited.insert(bb);
    }
 
-   for (Instruction *insn = start; insn != bb->getExit(); insn = insn->next) {
+   for (BaseInstruction *insn = start; insn != bb->getExit(); insn = insn->next) {
       if (insn->isNop())
          continue;
 
@@ -529,10 +529,10 @@ NVC0LegalizePostRA::insertTextureBarriers(Function *fn)
 
    // insert the barriers
    for (size_t i = 0; i < useVec.size(); ++i) {
-      Instruction *prev = useVec[i].insn->prev;
       if (useVec[i].level < 0)
          continue;
-      if (prev && prev->op == OP_TEXBAR) {
+      if (useVec[i].insn->prev && useVec[i].insn->prev->op == OP_TEXBAR) {
+         Instruction *prev = asInsn(useVec[i].insn->prev);
          if (prev->subOp > useVec[i].level)
             prev->subOp = useVec[i].level;
          prev->setSrc(prev->srcCount(), useVec[i].tex->getDef(0));
@@ -563,7 +563,7 @@ NVC0LegalizePostRA::insertTextureBarriers(Function *fn)
       BasicBlock *bb = BasicBlock::get(n);
       int min = 0;
       int max = std::numeric_limits<int>::max();
-      for (Instruction *i = bb->getFirst(); i; i = i->next) {
+      for (Instruction *i = bb->getEntry(); i; i = i->getNext()) {
          if (isTextureOp(i->op)) {
             min++;
             if (max < std::numeric_limits<int>::max())
@@ -611,8 +611,8 @@ NVC0LegalizePostRA::insertTextureBarriers(Function *fn)
       Instruction *prev = NULL;
       Instruction *next;
       int max = limitT[bb->getId()].max;
-      for (Instruction *i = bb->getFirst(); i; i = next) {
-         next = i->next;
+      for (Instruction *i = bb->getEntry(); i; i = next) {
+         next = i->getNext();
          if (i->op == OP_TEXBAR) {
             if (i->subOp >= max) {
                delete_Instruction(prog, i);
@@ -687,7 +687,7 @@ NVC0LegalizePostRA::tryReplaceContWithBra(BasicBlock *bb)
    BasicBlock *contBB = BasicBlock::get(ei.getNode());
 
    if (!contBB->getExit() || contBB->getExit()->op != OP_CONT ||
-       contBB->getExit()->getPredicate())
+       asInsn(contBB->getExit())->getPredicate())
       return false;
    contBB->getExit()->op = OP_BRA;
    bb->remove(bb->getEntry()); // delete PRECONT
@@ -705,7 +705,7 @@ NVC0LegalizePostRA::propagateJoin(BasicBlock *bb)
       return;
    for (Graph::EdgeIterator ei = bb->cfg.incident(); !ei.end(); ei.next()) {
       BasicBlock *in = BasicBlock::get(ei.getNode());
-      Instruction *exit = in->getExit();
+      BaseInstruction *exit = in->getExit();
       if (!exit) {
          in->insertTail(new FlowInstruction(func, OP_JOIN, bb));
          // there should always be a terminator instruction
@@ -722,7 +722,7 @@ NVC0LegalizePostRA::propagateJoin(BasicBlock *bb)
 bool
 NVC0LegalizePostRA::visit(BasicBlock *bb)
 {
-   Instruction *i, *next;
+   BaseInstruction *i, *next;
 
    // remove pseudo operations and non-fixed no-ops, split 64 bit operations
    for (i = bb->getFirst(); i; i = next) {
@@ -731,19 +731,19 @@ NVC0LegalizePostRA::visit(BasicBlock *bb)
          if (!i->getDef(0)->refCount())
             i->setDef(0, NULL);
          if (i->src(0).getFile() == FILE_IMMEDIATE)
-            i->setSrc(0, rZero); // initial value must be 0
-         replaceZero(i);
+            asInsn(i)->setSrc(0, rZero); // initial value must be 0
+         replaceZero(asInsn(i));
       } else
       if (i->isNop()) {
          bb->remove(i);
       } else
-      if (i->op == OP_BAR && i->subOp == NV50_IR_SUBOP_BAR_SYNC &&
+      if (i->op == OP_BAR && asInsn(i)->subOp == NV50_IR_SUBOP_BAR_SYNC &&
           prog->getType() != Program::TYPE_COMPUTE) {
          // It seems like barriers are never required for tessellation since
          // the warp size is 32, and there are always at most 32 tcs threads.
          bb->remove(i);
       } else
-      if (i->op == OP_LOAD && i->subOp == NV50_IR_SUBOP_LDC_IS) {
+      if (i->op == OP_LOAD && asInsn(i)->subOp == NV50_IR_SUBOP_LDC_IS) {
          int offset = i->src(0).get()->reg.data.offset;
          if (abs(offset) >= 0x10000)
             i->src(0).get()->reg.fileIndex += offset >> 16;
@@ -753,13 +753,13 @@ NVC0LegalizePostRA::visit(BasicBlock *bb)
          // need the $c register !
          if (typeSizeof(i->sType) == 8 || typeSizeof(i->dType) == 8) {
             Instruction *hi;
-            hi = BuildUtil::split64BitOpPostRA(func, i, rZero, carry);
+            hi = BuildUtil::split64BitOpPostRA(func, asInsn(i), rZero, carry);
             if (hi)
                next = hi;
          }
 
          if (i->op != OP_MOV && i->op != OP_PFETCH)
-            replaceZero(i);
+            replaceZero(asInsn(i));
       }
    }
    if (!bb->getEntry())
@@ -1889,11 +1889,11 @@ NVC0LoweringPass::processSurfaceCoordsNVE4(TexInstruction *su)
 
    // set predicate output
    if (su->tex.target == TEX_TARGET_BUFFER) {
-      src[0]->getInsn()->setFlagsDef(1, pred);
+      asInsn(src[0]->getInsn())->setFlagsDef(1, pred);
    } else
    if (su->tex.target.isArray() || su->tex.target.isCube()) {
       p1 = bld.getSSA(1, FILE_PREDICATE);
-      src[dim]->getInsn()->setFlagsDef(1, p1);
+      asInsn(src[dim]->getInsn())->setFlagsDef(1, p1);
    }
 
    // calculate pixel offset
@@ -2801,7 +2801,7 @@ NVC0LoweringPass::handleEXPORT(Instruction *i)
 bool
 NVC0LoweringPass::handleOUT(Instruction *i)
 {
-   Instruction *prev = i->prev;
+   BaseInstruction *prev = i->prev;
    ImmediateValue stream, prevStream;
 
    // Only merge if the stream ids match. Also, note that the previous
@@ -2810,7 +2810,7 @@ NVC0LoweringPass::handleOUT(Instruction *i)
        i->src(0).getImmediate(stream) &&
        prev->src(1).getImmediate(prevStream) &&
        stream.reg.data.u32 == prevStream.reg.data.u32) {
-      i->prev->subOp = NV50_IR_SUBOP_EMIT_RESTART;
+      asInsn(i->prev)->subOp = NV50_IR_SUBOP_EMIT_RESTART;
       delete_Instruction(prog, i);
    } else {
       assert(gpEmitAddress);
diff --git a/src/gallium/drivers/nouveau/codegen/nv50_ir_lowering_nvc0.h b/src/gallium/drivers/nouveau/codegen/nv50_ir_lowering_nvc0.h
index 8724c09afd..8f590ee050 100644
--- a/src/gallium/drivers/nouveau/codegen/nv50_ir_lowering_nvc0.h
+++ b/src/gallium/drivers/nouveau/codegen/nv50_ir_lowering_nvc0.h
@@ -87,10 +87,10 @@ private:
 
    struct TexUse
    {
-      TexUse(Instruction *use, const Instruction *tex, bool after)
+      TexUse(BaseInstruction *use, const BaseInstruction *tex, bool after)
          : insn(use), tex(tex), after(after), level(-1) { }
-      Instruction *insn;
-      const Instruction *tex; // or split / mov
+      BaseInstruction *insn;
+      const BaseInstruction *tex; // or split / mov
       bool after;
       int level;
    };
@@ -101,12 +101,12 @@ private:
       int min, max;
    };
    bool insertTextureBarriers(Function *);
-   inline bool insnDominatedBy(const Instruction *, const Instruction *) const;
-   void findFirstUses(Instruction *texi, std::list<TexUse> &uses);
-   void findFirstUsesBB(int minGPR, int maxGPR, Instruction *start,
-                        const Instruction *texi, std::list<TexUse> &uses,
+   inline bool insnDominatedBy(const BaseInstruction *, const BaseInstruction *) const;
+   void findFirstUses(BaseInstruction *texi, std::list<TexUse> &uses);
+   void findFirstUsesBB(int minGPR, int maxGPR, BaseInstruction *start,
+                        const BaseInstruction *texi, std::list<TexUse> &uses,
                         unordered_set<const BasicBlock *> &visited);
-   void addTexUse(std::list<TexUse>&, Instruction *, const Instruction *);
+   void addTexUse(std::list<TexUse>&, BaseInstruction *, const BaseInstruction *);
    const Instruction *recurseDef(const Instruction *);
 
 private:
diff --git a/src/gallium/drivers/nouveau/codegen/nv50_ir_peephole.cpp b/src/gallium/drivers/nouveau/codegen/nv50_ir_peephole.cpp
index 39177bd044..0ec8fd1898 100644
--- a/src/gallium/drivers/nouveau/codegen/nv50_ir_peephole.cpp
+++ b/src/gallium/drivers/nouveau/codegen/nv50_ir_peephole.cpp
@@ -31,7 +31,7 @@ extern "C" {
 namespace nv50_ir {
 
 bool
-Instruction::isNop() const
+BaseInstruction::isNop() const
 {
    if (op == OP_PHI || op == OP_SPLIT || op == OP_MERGE || op == OP_CONSTRAINT)
       return true;
@@ -61,7 +61,8 @@ Instruction::isNop() const
    return false;
 }
 
-bool Instruction::isDead() const
+bool
+BaseInstruction::isDead() const
 {
    if (op == OP_STORE ||
        op == OP_EXPORT ||
@@ -96,10 +97,11 @@ private:
 bool
 CopyPropagation::visit(BasicBlock *bb)
 {
-   Instruction *mov, *si, *next;
+   Instruction *mov, *next;
+   BaseInstruction *si;
 
    for (mov = bb->getEntry(); mov; mov = next) {
-      next = mov->next;
+      next = mov->getNext();
       if (mov->op != OP_MOV || mov->fixed || !mov->getSrc(0)->asLValue())
          continue;
       if (mov->getPredicate())
@@ -129,10 +131,11 @@ private:
 bool
 MergeSplits::visit(BasicBlock *bb)
 {
-   Instruction *i, *next, *si;
+   Instruction *i, *next;
+   BaseInstruction *si;
 
    for (i = bb->getEntry(); i; i = next) {
-      next = i->next;
+      next = i->getNext();
       if (i->op != OP_MERGE || typeSizeof(i->dType) != 8)
          continue;
       si = i->getSrc(0)->getInsn();
@@ -154,19 +157,19 @@ private:
 
    void checkSwapSrc01(Instruction *);
 
-   bool isCSpaceLoad(Instruction *);
-   bool isImmdLoad(Instruction *);
-   bool isAttribOrSharedLoad(Instruction *);
+   bool isCSpaceLoad(BaseInstruction *);
+   bool isImmdLoad(BaseInstruction *);
+   bool isAttribOrSharedLoad(BaseInstruction *);
 };
 
 bool
-LoadPropagation::isCSpaceLoad(Instruction *ld)
+LoadPropagation::isCSpaceLoad(BaseInstruction *ld)
 {
    return ld && ld->op == OP_LOAD && ld->src(0).getFile() == FILE_MEMORY_CONST;
 }
 
 bool
-LoadPropagation::isImmdLoad(Instruction *ld)
+LoadPropagation::isImmdLoad(BaseInstruction *ld)
 {
    if (!ld || (ld->op != OP_MOV) ||
        ((typeSizeof(ld->dType) != 4) && (typeSizeof(ld->dType) != 8)))
@@ -178,7 +181,7 @@ LoadPropagation::isImmdLoad(Instruction *ld)
 }
 
 bool
-LoadPropagation::isAttribOrSharedLoad(Instruction *ld)
+LoadPropagation::isAttribOrSharedLoad(BaseInstruction *ld)
 {
    return ld &&
       (ld->op == OP_VFETCH ||
@@ -201,17 +204,17 @@ LoadPropagation::checkSwapSrc01(Instruction *insn)
    if (insn->op == OP_SET && insn->subOp)
       return;
 
-   Instruction *i0 = insn->getSrc(0)->getInsn();
-   Instruction *i1 = insn->getSrc(1)->getInsn();
+   BaseInstruction *i0 = insn->getSrc(0)->getInsn();
+   BaseInstruction *i1 = insn->getSrc(1)->getInsn();
 
    // Swap sources to inline the less frequently used source. That way,
    // optimistically, it will eventually be able to remove the instruction.
    int i0refs = insn->getSrc(0)->refCount();
    int i1refs = insn->getSrc(1)->refCount();
 
-   if ((isCSpaceLoad(i0) || isImmdLoad(i0)) && targ->insnCanLoad(insn, 1, i0)) {
+   if ((isCSpaceLoad(i0) || isImmdLoad(i0)) && targ->insnCanLoad(insn, 1, asInsn(i0))) {
       if ((!isImmdLoad(i1) && !isCSpaceLoad(i1)) ||
-          !targ->insnCanLoad(insn, 1, i1) ||
+          !targ->insnCanLoad(insn, 1, asInsn(i1)) ||
           i0refs < i1refs)
          insn->swapSources(0, 1);
       else
@@ -246,7 +249,7 @@ LoadPropagation::visit(BasicBlock *bb)
    Instruction *next;
 
    for (Instruction *i = bb->getEntry(); i; i = next) {
-      next = i->next;
+      next = i->getNext();
 
       if (i->op == OP_CALL) // calls have args as sources, they must be in regs
          continue;
@@ -258,11 +261,11 @@ LoadPropagation::visit(BasicBlock *bb)
          checkSwapSrc01(i);
 
       for (int s = 0; i->srcExists(s); ++s) {
-         Instruction *ld = i->getSrc(s)->getInsn();
+         BaseInstruction *ld = i->getSrc(s)->getInsn();
 
          if (!ld || ld->fixed || (ld->op != OP_LOAD && ld->op != OP_MOV))
             continue;
-         if (!targ->insnCanLoad(i, s, ld))
+         if (!targ->insnCanLoad(i, s, asInsn(ld)))
             continue;
 
          // propagate !
@@ -292,10 +295,10 @@ IndirectPropagation::visit(BasicBlock *bb)
    Instruction *next;
 
    for (Instruction *i = bb->getEntry(); i; i = next) {
-      next = i->next;
+      next = i->getNext();
 
       for (int s = 0; i->srcExists(s); ++s) {
-         Instruction *insn;
+         BaseInstruction *insn;
          ImmediateValue imm;
          if (!i->src(s).isIndirect(0))
             continue;
@@ -377,7 +380,7 @@ ConstantFolding::visit(BasicBlock *bb)
    Instruction *i, *next;
 
    for (i = bb->getEntry(); i; i = next) {
-      next = i->next;
+      next = i->getNext();
       if (i->op == OP_MOV || i->op == OP_CALL)
          continue;
 
@@ -409,7 +412,7 @@ ConstantFolding::findOriginForTestWithZero(Value *value)
 {
    if (!value)
       return NULL;
-   Instruction *insn = value->getInsn();
+   BaseInstruction *insn = value->getInsn();
    if (!insn)
       return NULL;
 
@@ -841,7 +844,7 @@ ConstantFolding::tryCollapseChainedMULs(Instruction *mul2,
                                         const int s, ImmediateValue& imm2)
 {
    const int t = s ? 0 : 1;
-   Instruction *insn;
+   BaseInstruction *insn;
    Instruction *mul1 = NULL; // mul1 before mul2
    int e = 0;
    float f = imm2.reg.data.f32 * exp2f(mul2->postFactor);
@@ -852,7 +855,7 @@ ConstantFolding::tryCollapseChainedMULs(Instruction *mul2,
    if (mul2->getSrc(t)->refCount() == 1) {
       insn = mul2->getSrc(t)->getInsn();
       if (!mul2->src(t).mod && insn->op == OP_MUL && insn->dType == TYPE_F32)
-         mul1 = insn;
+         mul1 = asInsn(insn);
       if (mul1 && !mul1->saturate) {
          int s1;
 
@@ -891,7 +894,7 @@ ConstantFolding::tryCollapseChainedMULs(Instruction *mul2,
       t2 = s2 ? 0 : 1;
       if (insn->op == OP_MUL && insn->dType == TYPE_F32)
          if (!insn->src(s2).mod && !insn->src(t2).getImmediate(imm1))
-            mul2 = insn;
+            mul2 = asInsn(insn);
       if (mul2 && prog->getTarget()->isPostMultiplySupported(OP_MUL, f, e)) {
          mul2->postFactor = e;
          mul2->setSrc(s2, mul1->src(t));
@@ -1264,7 +1267,7 @@ ConstantFolding::opnd(Instruction *i, ImmediateValue &imm0, int s)
 
    case OP_AND:
    {
-      Instruction *src = i->getSrc(t)->getInsn();
+      BaseInstruction *src = i->getSrc(t)->getInsn();
       ImmediateValue imm1;
       if (imm0.reg.data.u32 == 0) {
          i->op = OP_MOV;
@@ -1331,7 +1334,7 @@ ConstantFolding::opnd(Instruction *i, ImmediateValue &imm0, int s)
       if (s != 1 || i->src(0).mod != Modifier(0))
          break;
       // try to concatenate shifts
-      Instruction *si = i->getSrc(0)->getInsn();
+      BaseInstruction *si = i->getSrc(0)->getInsn();
       if (!si)
          break;
       ImmediateValue imm1;
@@ -1585,7 +1588,7 @@ ModifierFolding::visit(BasicBlock *bb)
    Modifier mod;
 
    for (i = bb->getEntry(); i; i = next) {
-      next = i->next;
+      next = i->getNext();
 
       if (0 && i->op == OP_SUB) {
          // turn "sub" into "add neg" (do we really want this ?)
@@ -1594,7 +1597,7 @@ ModifierFolding::visit(BasicBlock *bb)
       }
 
       for (int s = 0; s < 3 && i->srcExists(s); ++s) {
-         mi = i->getSrc(s)->getInsn();
+         mi = asInsn(i->getSrc(s)->getInsn());
          if (!mi ||
              mi->predSrc >= 0 || mi->getDef(0)->refCount() > 8)
             continue;
@@ -1634,7 +1637,7 @@ ModifierFolding::visit(BasicBlock *bb)
       }
 
       if (i->op == OP_SAT) {
-         mi = i->getSrc(0)->getInsn();
+         mi = asInsn(i->getSrc(0)->getInsn());
          if (mi &&
              mi->getDef(0)->refCount() <= 1 && target->isSatSupported(mi)) {
             mi->saturate = 1;
@@ -1678,7 +1681,7 @@ private:
 void
 AlgebraicOpt::handleABS(Instruction *abs)
 {
-   Instruction *sub = abs->getSrc(0)->getInsn();
+   BaseInstruction *sub = abs->getSrc(0)->getInsn();
    DataType ty;
    if (!sub ||
        !prog->getTarget()->isOpSupported(OP_SAD, abs->dType))
@@ -1700,7 +1703,7 @@ AlgebraicOpt::handleABS(Instruction *abs)
    Value *src1 = sub->getSrc(1);
 
    if (sub->op == OP_ADD) {
-      Instruction *neg = sub->getSrc(1)->getInsn();
+      BaseInstruction *neg = sub->getSrc(1)->getInsn();
       if (neg && neg->op != OP_NEG) {
          neg = sub->getSrc(0)->getInsn();
          src0 = sub->getSrc(1);
@@ -1751,6 +1754,7 @@ AlgebraicOpt::tryADDToMADOrSAD(Instruction *add, operation toOp)
    const operation srcOp = toOp == OP_SAD ? OP_SAD : OP_MUL;
    const Modifier modBad = Modifier(~((toOp == OP_MAD) ? NV50_IR_MOD_NEG : 0));
    Modifier mod[4];
+   Instruction *srcInsn;
 
    if (src0->refCount() == 1 &&
        src0->getUniqueInsn() && src0->getUniqueInsn()->op == srcOp)
@@ -1763,12 +1767,13 @@ AlgebraicOpt::tryADDToMADOrSAD(Instruction *add, operation toOp)
       return false;
 
    src = add->getSrc(s);
+   srcInsn = asInsn(src->getUniqueInsn());
 
-   if (src->getUniqueInsn() && src->getUniqueInsn()->bb != add->bb)
+   if (srcInsn->bb != add->bb)
       return false;
 
-   if (src->getInsn()->saturate || src->getInsn()->postFactor ||
-       src->getInsn()->dnz || src->getInsn()->precise)
+   if (srcInsn->saturate || srcInsn->postFactor ||
+       srcInsn->dnz || srcInsn->precise)
       return false;
 
    if (toOp == OP_SAD) {
@@ -1785,23 +1790,23 @@ AlgebraicOpt::tryADDToMADOrSAD(Instruction *add, operation toOp)
 
    mod[0] = add->src(0).mod;
    mod[1] = add->src(1).mod;
-   mod[2] = src->getUniqueInsn()->src(0).mod;
-   mod[3] = src->getUniqueInsn()->src(1).mod;
+   mod[2] = srcInsn->src(0).mod;
+   mod[3] = srcInsn->src(1).mod;
 
    if (((mod[0] | mod[1]) | (mod[2] | mod[3])) & modBad)
       return false;
 
    add->op = toOp;
-   add->subOp = src->getInsn()->subOp; // potentially mul-high
-   add->dnz = src->getInsn()->dnz;
-   add->dType = src->getInsn()->dType; // sign matters for imad hi
-   add->sType = src->getInsn()->sType;
+   add->subOp = srcInsn->subOp; // potentially mul-high
+   add->dnz = srcInsn->dnz;
+   add->dType = srcInsn->dType; // sign matters for imad hi
+   add->sType = srcInsn->sType;
 
    add->setSrc(2, add->src(s ? 0 : 1));
 
-   add->setSrc(0, src->getInsn()->getSrc(0));
+   add->setSrc(0, srcInsn->getSrc(0));
    add->src(0).mod = mod[2] ^ mod[s];
-   add->setSrc(1, src->getInsn()->getSrc(1));
+   add->setSrc(1, srcInsn->getSrc(1));
    add->src(1).mod = mod[3];
 
    return true;
@@ -1837,7 +1842,7 @@ AlgebraicOpt::handleMINMAX(Instruction *minmax)
 void
 AlgebraicOpt::handleRCP(Instruction *rcp)
 {
-   Instruction *si = rcp->getSrc(0)->getUniqueInsn();
+   BaseInstruction *si = rcp->getSrc(0)->getUniqueInsn();
 
    if (si && si->op == OP_RCP) {
       Modifier mod = rcp->src(0).mod * si->src(0).mod;
@@ -1878,13 +1883,13 @@ AlgebraicOpt::handleLOGOP(Instruction *logop)
       }
    } else {
       // try AND(SET, SET) -> SET_AND(SET)
-      Instruction *set0 = src0->getInsn();
-      Instruction *set1 = src1->getInsn();
+      BaseInstruction *set0 = src0->getInsn();
+      BaseInstruction *set1 = src1->getInsn();
 
       if (!set0 || set0->fixed || !set1 || set1->fixed)
          return;
       if (set1->op != OP_SET) {
-         Instruction *xchg = set0;
+         BaseInstruction *xchg = set0;
          set0 = set1;
          set1 = xchg;
          if (set1->op != OP_SET)
@@ -1902,7 +1907,7 @@ AlgebraicOpt::handleLOGOP(Instruction *logop)
       if (set0->getDef(0)->refCount() > 1 &&
           set1->getDef(0)->refCount() > 1)
          return;
-      if (set0->getPredicate() || set1->getPredicate())
+      if (asInsn(set0)->getPredicate() || asInsn(set1)->getPredicate())
          return;
       // check that they don't source each other
       for (int s = 0; s < 2; ++s)
@@ -1918,7 +1923,7 @@ AlgebraicOpt::handleLOGOP(Instruction *logop)
       set0->dType = TYPE_U8;
       set0->getDef(0)->reg.file = FILE_PREDICATE;
       set0->getDef(0)->reg.size = 1;
-      set1->setSrc(2, set0->getDef(0));
+      asInsn(set1)->setSrc(2, set0->getDef(0));
       set1->op = redOp;
       set1->setDef(0, logop->getDef(0));
       delete_Instruction(prog, logop);
@@ -1931,7 +1936,7 @@ AlgebraicOpt::handleLOGOP(Instruction *logop)
 void
 AlgebraicOpt::handleCVT_NEG(Instruction *cvt)
 {
-   Instruction *insn = cvt->getSrc(0)->getInsn();
+   BaseInstruction *insn = cvt->getSrc(0)->getInsn();
    if (cvt->sType != TYPE_F32 ||
        cvt->dType != TYPE_S32 || cvt->src(0).mod != Modifier(0))
       return;
@@ -1957,7 +1962,7 @@ AlgebraicOpt::handleCVT_NEG(Instruction *cvt)
       return;
    }
 
-   Instruction *bset = cloneShallow(func, insn);
+   Instruction *bset = asInsn(cloneShallow(func, insn));
    bset->dType = TYPE_U32;
    bset->setDef(0, cvt->getDef(0));
    cvt->bb->insertAfter(cvt, bset);
@@ -1971,14 +1976,8 @@ AlgebraicOpt::handleCVT_NEG(Instruction *cvt)
 void
 AlgebraicOpt::handleCVT_CVT(Instruction *cvt)
 {
-   Instruction *insn = cvt->getSrc(0)->getInsn();
-   RoundMode rnd = insn->rnd;
-
-   if (insn->saturate ||
-       insn->subOp ||
-       insn->dType != insn->sType ||
-       insn->dType != cvt->sType)
-      return;
+   BaseInstruction *insn = cvt->getSrc(0)->getInsn();
+   RoundMode rnd;
 
    switch (insn->op) {
    case OP_CEIL:
@@ -1991,11 +1990,18 @@ AlgebraicOpt::handleCVT_CVT(Instruction *cvt)
       rnd = ROUND_ZI;
       break;
    case OP_CVT:
+      rnd = asInsn(insn)->rnd;
       break;
    default:
       return;
    }
 
+   if (asInsn(insn)->saturate ||
+       asInsn(insn)->subOp ||
+       insn->dType != insn->sType ||
+       insn->dType != cvt->sType)
+      return;
+
    if (!isFloatType(cvt->dType) || !isFloatType(insn->sType))
       rnd = (RoundMode)(rnd & 3);
 
@@ -2016,7 +2022,7 @@ AlgebraicOpt::handleCVT_CVT(Instruction *cvt)
 void
 AlgebraicOpt::handleCVT_EXTBF(Instruction *cvt)
 {
-   Instruction *insn = cvt->getSrc(0)->getInsn();
+   BaseInstruction *insn = cvt->getSrc(0)->getInsn();
    ImmediateValue imm;
    Value *arg = NULL;
    unsigned width, offset;
@@ -2050,7 +2056,7 @@ AlgebraicOpt::handleCVT_EXTBF(Instruction *cvt)
          return;
 
       arg = insn->getSrc(!s);
-      Instruction *shift = arg->getInsn();
+      BaseInstruction *shift = arg->getInsn();
       offset = 0;
       if (shift && shift->op == OP_SHR &&
           shift->sType == cvt->sType &&
@@ -2083,7 +2089,7 @@ AlgebraicOpt::handleCVT_EXTBF(Instruction *cvt)
 
    // Irrespective of what came earlier, we can undo a shift on the argument
    // by adjusting the offset.
-   Instruction *shift = arg->getInsn();
+   BaseInstruction *shift = arg->getInsn();
    if (shift && shift->op == OP_SHL &&
        shift->src(1).getImmediate(imm) &&
        ((width == 8 && (imm.reg.data.u32 & 0x7) == 0) ||
@@ -2113,7 +2119,7 @@ AlgebraicOpt::handleSUCLAMP(Instruction *insn)
    ImmediateValue imm;
    int32_t val = insn->getSrc(2)->asImm()->reg.data.s32;
    int s;
-   Instruction *add;
+   BaseInstruction *add;
 
    assert(insn->srcExists(0) && insn->src(0).getFile() == FILE_GPR);
 
@@ -2150,7 +2156,7 @@ AlgebraicOpt::handleSUCLAMP(Instruction *insn)
 // NEG(AND(SET, 1)) -> SET
 void
 AlgebraicOpt::handleNEG(Instruction *i) {
-   Instruction *src = i->getSrc(0)->getInsn();
+   BaseInstruction *src = i->getSrc(0)->getInsn();
    ImmediateValue imm;
    int b;
 
@@ -2167,7 +2173,7 @@ AlgebraicOpt::handleNEG(Instruction *i) {
    if (!imm.isInteger(1))
       return;
 
-   Instruction *set = src->getSrc(b)->getInsn();
+   BaseInstruction *set = src->getSrc(b)->getInsn();
    if ((set->op == OP_SET || set->op == OP_SET_AND ||
        set->op == OP_SET_OR || set->op == OP_SET_XOR) &&
        !isFloatType(set->dType)) {
@@ -2180,7 +2186,7 @@ AlgebraicOpt::visit(BasicBlock *bb)
 {
    Instruction *next;
    for (Instruction *i = bb->getEntry(); i; i = next) {
-      next = i->next;
+      next = i->getNext();
       switch (i->op) {
       case OP_ABS:
          handleABS(i);
@@ -2272,7 +2278,7 @@ LateAlgebraicOpt::tryADDToSHLADD(Instruction *add)
       return false;
 
    src = add->getSrc(s);
-   shl = src->getUniqueInsn();
+   shl = asInsn(src->getUniqueInsn());
 
    if (shl->bb != add->bb || shl->usesFlags() || shl->subOp || shl->src(0).mod)
       return false;
@@ -2326,7 +2332,7 @@ Split64BitOpPreRA::visit(BasicBlock *bb)
    Modifier mod;
 
    for (i = bb->getEntry(); i; i = next) {
-      next = i->next;
+      next = i->getNext();
 
       DataType hTy;
       switch (i->dType) {
@@ -2908,7 +2914,7 @@ MemoryOpt::runOpt(BasicBlock *bb)
    for (ldst = bb->getEntry(); ldst; ldst = next) {
       bool keep = true;
       bool isLoad = true;
-      next = ldst->next;
+      next = ldst->getNext();
 
       if (ldst->op == OP_LOAD || ldst->op == OP_VFETCH) {
          if (ldst->isDead()) {
@@ -3012,7 +3018,7 @@ private:
    void tryPropagateBranch(BasicBlock *);
    inline bool isConstantCondition(Value *pred);
    inline bool mayPredicate(const Instruction *, const Value *pred) const;
-   inline void removeFlow(Instruction *);
+   inline void removeFlow(BaseInstruction *);
 
    uint8_t gpr_unit;
 };
@@ -3020,13 +3026,13 @@ private:
 bool
 FlatteningPass::isConstantCondition(Value *pred)
 {
-   Instruction *insn = pred->getUniqueInsn();
+   BaseInstruction *insn = pred->getUniqueInsn();
    assert(insn);
    if (insn->op != OP_SET || insn->srcExists(2))
       return false;
 
    for (int s = 0; s < 2 && insn->srcExists(s); ++s) {
-      Instruction *ld = insn->getSrc(s)->getUniqueInsn();
+      BaseInstruction *ld = insn->getSrc(s)->getUniqueInsn();
       DataFile file;
       if (ld) {
          if (ld->op != OP_MOV && ld->op != OP_LOAD)
@@ -3053,7 +3059,7 @@ FlatteningPass::isConstantCondition(Value *pred)
 }
 
 void
-FlatteningPass::removeFlow(Instruction *insn)
+FlatteningPass::removeFlow(BaseInstruction *insn)
 {
    FlowInstruction *term = insn ? insn->asFlow() : NULL;
    if (!term)
@@ -3073,7 +3079,7 @@ FlatteningPass::removeFlow(Instruction *insn)
    delete_Instruction(prog, term);
 
    if (pred && pred->refCount() == 0) {
-      Instruction *pSet = pred->getUniqueInsn();
+      BaseInstruction *pSet = pred->getUniqueInsn();
       pred->join->reg.data.id = -1; // deallocate
       if (pSet->isDead())
          delete_Instruction(prog, pSet);
@@ -3083,7 +3089,7 @@ FlatteningPass::removeFlow(Instruction *insn)
 void
 FlatteningPass::predicateInstructions(BasicBlock *bb, Value *pred, CondCode cc)
 {
-   for (Instruction *i = bb->getEntry(); i; i = i->next) {
+   for (Instruction *i = bb->getEntry(); i; i = i->getNext()) {
       if (i->isNop())
          continue;
       assert(!i->getPredicate());
@@ -3122,7 +3128,7 @@ FlatteningPass::mayPredicate(const Instruction *insn, const Value *pred) const
 void
 FlatteningPass::tryPropagateBranch(BasicBlock *bb)
 {
-   for (Instruction *i = bb->getExit(); i && i->op == OP_BRA; i = i->prev) {
+   for (BaseInstruction *i = bb->getExit(); i && i->op == OP_BRA; i = i->prev) {
       BasicBlock *bf = i->asFlow()->target.bb;
 
       if (bf->getInsnCount() != 1)
@@ -3165,10 +3171,11 @@ FlatteningPass::visit(BasicBlock *bb)
 
    // try to attach join to previous instruction
    if (prog->getTarget()->hasJoin) {
-      Instruction *insn = bb->getExit();
-      if (insn && insn->op == OP_JOIN && !insn->getPredicate()) {
+      BaseInstruction *insn = bb->getExit();
+      if (insn && insn->op == OP_JOIN && !asInsn(insn)->getPredicate()) {
          insn = insn->prev;
-         if (insn && !insn->getPredicate() &&
+         if (insn && !insn->isNop() &&
+             !asInsn(insn)->getPredicate() &&
              !insn->asFlow() &&
              insn->op != OP_DISCARD &&
              insn->op != OP_TEXBAR &&
@@ -3177,8 +3184,7 @@ FlatteningPass::visit(BasicBlock *bb)
              insn->op != OP_LINTERP && // probably just nve4
              insn->op != OP_PINTERP && // probably just nve4
              ((insn->op != OP_LOAD && insn->op != OP_STORE && insn->op != OP_ATOM) ||
-              (typeSizeof(insn->dType) <= 4 && !insn->src(0).isIndirect(0))) &&
-             !insn->isNop()) {
+              (typeSizeof(insn->dType) <= 4 && !insn->src(0).isIndirect(0)))) {
             insn->join = 1;
             bb->remove(bb->getExit());
             return true;
@@ -3203,8 +3209,8 @@ FlatteningPass::tryPredicateConditional(BasicBlock *bb)
    if (!mask)
       return false;
 
-   assert(bb->getExit());
-   Value *pred = bb->getExit()->getPredicate();
+   assert(asInsn(bb->getExit()));
+   Value *pred = asInsn(bb->getExit())->getPredicate();
    assert(pred);
 
    if (isConstantCondition(pred))
@@ -3214,7 +3220,7 @@ FlatteningPass::tryPredicateConditional(BasicBlock *bb)
 
    if (mask & 1) {
       bL = BasicBlock::get(ei.getNode());
-      for (insn = bL->getEntry(); insn; insn = insn->next, ++nL)
+      for (insn = bL->getEntry(); insn; insn = insn->getNext(), ++nL)
          if (!mayPredicate(insn, pred))
             return false;
       if (nL > limit)
@@ -3224,7 +3230,7 @@ FlatteningPass::tryPredicateConditional(BasicBlock *bb)
 
    if (mask & 2) {
       bR = BasicBlock::get(ei.getNode());
-      for (insn = bR->getEntry(); insn; insn = insn->next, ++nR)
+      for (insn = bR->getEntry(); insn; insn = insn->getNext(), ++nR)
          if (!mayPredicate(insn, pred))
             return false;
       if (nR > limit)
@@ -3232,9 +3238,9 @@ FlatteningPass::tryPredicateConditional(BasicBlock *bb)
    }
 
    if (bL)
-      predicateInstructions(bL, pred, bb->getExit()->cc);
+      predicateInstructions(bL, pred, asInsn(bb->getExit())->cc);
    if (bR)
-      predicateInstructions(bR, pred, inverseCondCode(bb->getExit()->cc));
+      predicateInstructions(bR, pred, inverseCondCode(asInsn(bb->getExit())->cc));
 
    if (bb->joinAt) {
       bb->remove(bb->joinAt);
@@ -3268,7 +3274,7 @@ private:
 };
 
 static bool
-post_ra_dead(Instruction *i)
+post_ra_dead(BaseInstruction *i)
 {
    for (int d = 0; i->defExists(d); ++d)
       if (i->getDef(d)->refCount())
@@ -3299,7 +3305,7 @@ PostRaLoadPropagation::handleMADforNV50(Instruction *i)
       return;
 
    Value *vtmp;
-   Instruction *def = i->getSrc(1)->getInsn();
+   BaseInstruction *def = i->getSrc(1)->getInsn();
 
    if (def && def->op == OP_SPLIT && typeSizeof(def->sType) == 4)
       def = def->getSrc(0)->getInsn();
@@ -3367,7 +3373,7 @@ PostRaLoadPropagation::handleMADforNVC0(Instruction *i)
    if (s == 1)
       i->swapSources(0, 1);
 
-   Instruction *imm = i->getSrc(1)->getInsn();
+   BaseInstruction *imm = i->getSrc(1)->getInsn();
    i->setSrc(1, imm->getSrc(0));
    if (post_ra_dead(imm))
       delete_Instruction(prog, imm);
@@ -3399,7 +3405,7 @@ class LocalCSE : public Pass
 private:
    virtual bool visit(BasicBlock *);
 
-   inline bool tryReplace(Instruction **, Instruction *);
+   inline bool tryReplace(BaseInstruction **, BaseInstruction *);
 
    DLList ops[OP_LAST + 1];
 };
@@ -3411,13 +3417,13 @@ private:
 };
 
 bool
-Instruction::isActionEqual(const Instruction *that) const
+BaseInstruction::isActionEqual(const BaseInstruction *that) const
 {
    if (this->op != that->op ||
        this->dType != that->dType ||
        this->sType != that->sType)
       return false;
-   if (this->cc != that->cc)
+   if (asInsn(this) && asInsn(this)->cc != asInsn(that)->cc)
       return false;
 
    if (this->asTex()) {
@@ -3432,29 +3438,30 @@ Instruction::isActionEqual(const Instruction *that) const
    } else
    if (this->asFlow()) {
       return false;
-   } else {
-      if (this->ipa != that->ipa ||
-          this->lanes != that->lanes ||
-          this->perPatch != that->perPatch)
-         return false;
-      if (this->postFactor != that->postFactor)
-         return false;
    }
 
-   if (this->subOp != that->subOp ||
-       this->saturate != that->saturate ||
-       this->rnd != that->rnd ||
-       this->ftz != that->ftz ||
-       this->dnz != that->dnz ||
-       this->cache != that->cache ||
-       this->mask != that->mask)
-      return false;
+   if (asInsn(this)) {
+      const Instruction *insnA = asInsn(this);
+      const Instruction *insnB = asInsn(that);
+      if (insnA->ipa != insnB->ipa ||
+          insnA->lanes != insnB->lanes ||
+          insnA->perPatch != insnB->perPatch ||
+          insnA->postFactor != insnB->postFactor ||
+          insnA->subOp != insnB->subOp ||
+          insnA->saturate != insnB->saturate ||
+          insnA->rnd != insnB->rnd ||
+          insnA->ftz != insnB->ftz ||
+          insnA->dnz != insnB->dnz ||
+          insnA->cache != insnB->cache ||
+          insnA->mask != insnB->mask)
+         return false;
+   }
 
    return true;
 }
 
 bool
-Instruction::isResultEqual(const Instruction *that) const
+BaseInstruction::isResultEqual(const BaseInstruction *that) const
 {
    unsigned int d, s;
 
@@ -3465,7 +3472,7 @@ Instruction::isResultEqual(const Instruction *that) const
    if (!isActionEqual(that))
       return false;
 
-   if (this->predSrc != that->predSrc)
+   if (asInsn(this) && asInsn(this)->predSrc != asInsn(that)->predSrc)
       return false;
 
    for (d = 0; this->defExists(d); ++d) {
@@ -3506,13 +3513,14 @@ Instruction::isResultEqual(const Instruction *that) const
 bool
 GlobalCSE::visit(BasicBlock *bb)
 {
-   Instruction *phi, *next, *ik;
+   PhiInstruction *phi, *next;
+   BaseInstruction *ik;
    int s;
 
    // TODO: maybe do this with OP_UNION, too
 
-   for (phi = bb->getPhi(); phi && phi->op == OP_PHI; phi = next) {
-      next = phi->next;
+   for (phi = bb->getPhi(); phi; phi = next) {
+      next = asPhi(phi->next);
       if (phi->getSrc(0)->refCount() > 1)
          continue;
       ik = phi->getSrc(0)->getInsn();
@@ -3543,12 +3551,12 @@ GlobalCSE::visit(BasicBlock *bb)
 }
 
 bool
-LocalCSE::tryReplace(Instruction **ptr, Instruction *i)
+LocalCSE::tryReplace(BaseInstruction **ptr, BaseInstruction *i)
 {
-   Instruction *old = *ptr;
+   BaseInstruction *old = *ptr;
 
    // TODO: maybe relax this later (causes trouble with OP_UNION)
-   if (i->isPredicated())
+   if (asInsn(i) && asInsn(i)->isPredicated())
       return false;
 
    if (!old->isResultEqual(i))
@@ -3567,7 +3575,7 @@ LocalCSE::visit(BasicBlock *bb)
    unsigned int replaced;
 
    do {
-      Instruction *ir, *next;
+      BaseInstruction *ir, *next;
 
       replaced = 0;
 
@@ -3595,7 +3603,7 @@ LocalCSE::visit(BasicBlock *bb)
          if (src) {
             for (Value::UseIterator it = src->uses.begin();
                  it != src->uses.end(); ++it) {
-               Instruction *ik = (*it)->getInsn();
+               BaseInstruction *ik = (*it)->getInsn();
                if (ik && ik->bb == ir->bb && ik->serial < ir->serial)
                   if (tryReplace(&ir, ik))
                      break;
@@ -3603,7 +3611,7 @@ LocalCSE::visit(BasicBlock *bb)
          } else {
             DLLIST_FOR_EACH(&ops[ir->op], iter)
             {
-               Instruction *ik = reinterpret_cast<Instruction *>(iter.get());
+               BaseInstruction *ik = reinterpret_cast<BaseInstruction *>(iter.get());
                if (tryReplace(&ir, ik))
                   break;
             }
@@ -3653,30 +3661,31 @@ DeadCodeElim::buryAll(Program *prog)
 bool
 DeadCodeElim::visit(BasicBlock *bb)
 {
-   Instruction *prev;
+   BaseInstruction *prev;
 
-   for (Instruction *i = bb->getExit(); i; i = prev) {
+   for (BaseInstruction *i = bb->getExit(); i; i = prev) {
       prev = i->prev;
       if (i->isDead()) {
          ++deadCount;
          delete_Instruction(prog, i);
       } else
       if (i->defExists(1) &&
-          i->subOp == 0 &&
-          (i->op == OP_VFETCH || i->op == OP_LOAD)) {
-         checkSplitLoad(i);
+          (i->op == OP_VFETCH || i->op == OP_LOAD) &&
+          asInsn(i)->subOp == 0) {
+         checkSplitLoad(asInsn(i));
       } else
       if (i->defExists(0) && !i->getDef(0)->refCount()) {
          if (i->op == OP_ATOM ||
              i->op == OP_SUREDP ||
              i->op == OP_SUREDB) {
             i->setDef(0, NULL);
-            if (i->op == OP_ATOM && i->subOp == NV50_IR_SUBOP_ATOM_EXCH) {
-               i->cache = CACHE_CV;
-               i->op = OP_STORE;
-               i->subOp = 0;
+            if (i->op == OP_ATOM && asInsn(i)->subOp == NV50_IR_SUBOP_ATOM_EXCH) {
+               Instruction *insn = asInsn(i);
+               insn->cache = CACHE_CV;
+               insn->op = OP_STORE;
+               insn->subOp = 0;
             }
-         } else if (i->op == OP_LOAD && i->subOp == NV50_IR_SUBOP_LOAD_LOCKED) {
+         } else if (i->op == OP_LOAD && asInsn(i)->subOp == NV50_IR_SUBOP_LOAD_LOCKED) {
             i->setDef(0, i->getDef(1));
             i->setDef(1, NULL);
          }
diff --git a/src/gallium/drivers/nouveau/codegen/nv50_ir_print.cpp b/src/gallium/drivers/nouveau/codegen/nv50_ir_print.cpp
index cbb21f5f72..29e45b7ebf 100644
--- a/src/gallium/drivers/nouveau/codegen/nv50_ir_print.cpp
+++ b/src/gallium/drivers/nouveau/codegen/nv50_ir_print.cpp
@@ -531,10 +531,12 @@ int Symbol::print(char *buf, size_t size,
    return pos;
 }
 
-void Instruction::print() const
+void BaseInstruction::print() const
 {
    #define BUFSZ 512
 
+   const Instruction *i = asInsn(this);
+
    const size_t size = BUFSZ;
 
    char buf[BUFSZ];
@@ -546,21 +548,21 @@ void Instruction::print() const
    if (join)
       PRINT("join ");
 
-   if (predSrc >= 0) {
+   if (i && i->predSrc >= 0) {
       const size_t pre = pos;
-      if (getSrc(predSrc)->reg.file == FILE_PREDICATE) {
-         if (cc == CC_NOT_P)
+      if (getSrc(i->predSrc)->reg.file == FILE_PREDICATE) {
+         if (i->cc == CC_NOT_P)
             PRINT("not");
       } else {
-         PRINT("%s", CondCodeStr[cc]);
+         PRINT("%s", CondCodeStr[i->cc]);
       }
       if (pos > pre)
          SPACE();
-      pos += getSrc(predSrc)->print(&buf[pos], BUFSZ - pos);
+      pos += getSrc(i->predSrc)->print(&buf[pos], BUFSZ - pos);
       PRINT(" %s", colour[TXT_INSN]);
    }
 
-   if (saturate)
+   if (i && i->saturate)
       PRINT("sat ");
 
    if (asFlow()) {
@@ -582,66 +584,67 @@ void Instruction::print() const
    } else {
       PRINT("%s ", operationStr[op]);
       if (op == OP_LINTERP || op == OP_PINTERP)
-         PRINT("%s ", interpStr[ipa]);
+         PRINT("%s ", interpStr[i->ipa]);
       switch (op) {
       case OP_SUREDP:
       case OP_SUREDB:
       case OP_ATOM:
-         if (subOp < ARRAY_SIZE(atomSubOpStr))
-            PRINT("%s ", atomSubOpStr[subOp]);
+         if (i->subOp < ARRAY_SIZE(atomSubOpStr))
+            PRINT("%s ", atomSubOpStr[i->subOp]);
          break;
       case OP_LOAD:
       case OP_STORE:
-         if (subOp < ARRAY_SIZE(ldstSubOpStr))
-            PRINT("%s ", ldstSubOpStr[subOp]);
+         if (i->subOp < ARRAY_SIZE(ldstSubOpStr))
+            PRINT("%s ", ldstSubOpStr[i->subOp]);
          break;
       case OP_SUBFM:
-         if (subOp < ARRAY_SIZE(subfmOpStr))
-            PRINT("%s ", subfmOpStr[subOp]);
+         if (i->subOp < ARRAY_SIZE(subfmOpStr))
+            PRINT("%s ", subfmOpStr[i->subOp]);
          break;
       case OP_SHFL:
-         if (subOp < ARRAY_SIZE(shflOpStr))
-            PRINT("%s ", shflOpStr[subOp]);
+         if (i->subOp < ARRAY_SIZE(shflOpStr))
+            PRINT("%s ", shflOpStr[i->subOp]);
          break;
       case OP_PIXLD:
-         if (subOp < ARRAY_SIZE(pixldOpStr))
-            PRINT("%s ", pixldOpStr[subOp]);
+         if (i->subOp < ARRAY_SIZE(pixldOpStr))
+            PRINT("%s ", pixldOpStr[i->subOp]);
          break;
       case OP_RCP:
       case OP_RSQ:
-         if (subOp < ARRAY_SIZE(rcprsqOpStr))
-            PRINT("%s ", rcprsqOpStr[subOp]);
+         if (i->subOp < ARRAY_SIZE(rcprsqOpStr))
+            PRINT("%s ", rcprsqOpStr[i->subOp]);
          break;
       case OP_EMIT:
-         if (subOp < ARRAY_SIZE(emitOpStr))
-            PRINT("%s ", emitOpStr[subOp]);
+         if (i->subOp < ARRAY_SIZE(emitOpStr))
+            PRINT("%s ", emitOpStr[i->subOp]);
          break;
       case OP_CCTL:
-         if (subOp < ARRAY_SIZE(cctlOpStr))
-            PRINT("%s ", cctlOpStr[subOp]);
+         if (i->subOp < ARRAY_SIZE(cctlOpStr))
+            PRINT("%s ", cctlOpStr[i->subOp]);
          break;
       case OP_BAR:
-         if (subOp < ARRAY_SIZE(barOpStr))
-            PRINT("%s ", barOpStr[subOp]);
+         if (i->subOp < ARRAY_SIZE(barOpStr))
+            PRINT("%s ", barOpStr[i->subOp]);
          break;
       default:
-         if (subOp)
-            PRINT("(SUBOP:%u) ", subOp);
+         if (i->subOp)
+            PRINT("(SUBOP:%u) ", i->subOp);
          break;
       }
-      if (perPatch)
+      if (i && i->perPatch)
          PRINT("patch ");
       if (asTex())
          PRINT("%s %s$r%u $s%u %s", asTex()->tex.target.getName(),
                colour[TXT_MEM], asTex()->tex.r, asTex()->tex.s,
                colour[TXT_INSN]);
-      if (postFactor)
-         PRINT("x2^%i ", postFactor);
-      PRINT("%s%s", dnz ? "dnz " : (ftz ? "ftz " : ""),  DataTypeStr[dType]);
+      if (i && i->postFactor)
+         PRINT("x2^%i ", i->postFactor);
+      PRINT("%s%s", i ? (i->dnz ? "dnz " : (i->ftz ? "ftz " : "")) : "", 
+            DataTypeStr[dType]);
    }
 
-   if (rnd != ROUND_N)
-      PRINT(" %s", RoundModeStr[rnd]);
+   if (i && i->rnd != ROUND_N)
+      PRINT(" %s", RoundModeStr[i->rnd]);
 
    if (defExists(1))
       PRINT(" {");
@@ -662,7 +665,7 @@ void Instruction::print() const
       PRINT(" %s%s", colour[TXT_INSN], DataTypeStr[sType]);
 
    for (s = 0; srcExists(s); ++s) {
-      if (s == predSrc || src(s).usedAsPtr)
+      if ((i && s == i->predSrc) || src(s).usedAsPtr)
          continue;
       const size_t pre = pos;
       SPACE();
@@ -676,14 +679,14 @@ void Instruction::print() const
       else
          pos += getSrc(s)->print(&buf[pos], BUFSZ - pos, sType);
    }
-   if (exit)
+   if (i && i->exit)
       PRINT("%s exit", colour[TXT_INSN]);
 
    PRINT("%s", colour[TXT_DEFAULT]);
 
    buf[MIN2(pos, BUFSZ - 1)] = 0;
 
-   INFO("%s (%u)\n", buf, encSize);
+   INFO("%s (%u)\n", buf, i ? i->encSize : 0);
 }
 
 class PrintPass : public Pass
@@ -693,7 +696,7 @@ public:
 
    virtual bool visit(Function *);
    virtual bool visit(BasicBlock *);
-   virtual bool visit(Instruction *);
+   virtual bool visit(BaseInstruction *);
 
 private:
    int serial;
@@ -759,7 +762,7 @@ PrintPass::visit(BasicBlock *bb)
 }
 
 bool
-PrintPass::visit(Instruction *insn)
+PrintPass::visit(BaseInstruction *insn)
 {
    if (omit_serial)
       INFO("     ");
diff --git a/src/gallium/drivers/nouveau/codegen/nv50_ir_ra.cpp b/src/gallium/drivers/nouveau/codegen/nv50_ir_ra.cpp
index b660fec75c..26cbe20fb4 100644
--- a/src/gallium/drivers/nouveau/codegen/nv50_ir_ra.cpp
+++ b/src/gallium/drivers/nouveau/codegen/nv50_ir_ra.cpp
@@ -260,10 +260,10 @@ private:
       void insertConstraintMove(Instruction *, int s);
       bool insertConstraintMoves();
 
-      void condenseDefs(Instruction *);
+      void condenseDefs(BaseInstruction *);
       void condenseSrcs(Instruction *, const int first, const int last);
 
-      void addHazard(Instruction *i, const ValueRef *src);
+      void addHazard(BaseInstruction *i, const ValueRef *src);
       void textureMask(TexInstruction *);
       void addConstraint(Instruction *, int s, int n);
       bool detectConflict(Instruction *, int s);
@@ -319,8 +319,8 @@ private:
    int32_t stackSize;
    int32_t stackBase;
 
-   LValue *unspill(Instruction *usei, LValue *, Value *slot);
-   void spill(Instruction *defi, Value *slot, LValue *);
+   LValue *unspill(BaseInstruction *usei, LValue *, Value *slot);
+   void spill(BaseInstruction *defi, Value *slot, LValue *);
 };
 
 void
@@ -328,7 +328,7 @@ RegAlloc::BuildIntervalsPass::addLiveRange(Value *val,
                                            const BasicBlock *bb,
                                            int end)
 {
-   Instruction *insn = val->getUniqueInsn();
+   BaseInstruction *insn = val->getUniqueInsn();
 
    if (!insn)
       insn = bb->getFirst();
@@ -362,14 +362,14 @@ RegAlloc::PhiMovesPass::needNewElseBlock(BasicBlock *b, BasicBlock *p)
 }
 
 struct PhiMapHash {
-   size_t operator()(const std::pair<Instruction *, BasicBlock *>& val) const {
-      return hash<Instruction*>()(val.first) * 31 +
+   size_t operator()(const std::pair<PhiInstruction *, BasicBlock *>& val) const {
+      return hash<PhiInstruction*>()(val.first) * 31 +
          hash<BasicBlock*>()(val.second);
    }
 };
 
 typedef unordered_map<
-   std::pair<Instruction *, BasicBlock *>, Value *, PhiMapHash> PhiMap;
+   std::pair<PhiInstruction *, BasicBlock *>, Value *, PhiMapHash> PhiMap;
 
 // Critical edges need to be split up so that work can be inserted along
 // specific edge transitions. Unfortunately manipulating incident edges into a
@@ -382,7 +382,7 @@ void
 RegAlloc::PhiMovesPass::splitEdges(BasicBlock *bb)
 {
    BasicBlock *pb, *pn;
-   Instruction *phi;
+   PhiInstruction *phi;
    Graph::EdgeIterator ei;
    std::stack<BasicBlock *> stack;
    int j = 0;
@@ -406,7 +406,7 @@ RegAlloc::PhiMovesPass::splitEdges(BasicBlock *bb)
    j = 0;
    for (ei = bb->cfg.incident(); !ei.end(); ei.next(), j++) {
       pb = BasicBlock::get(ei.getNode());
-      for (phi = bb->getPhi(); phi && phi->op == OP_PHI; phi = phi->next)
+      for (phi = bb->getPhi(); phi; phi = asPhi(phi->next))
          phis.insert(std::make_pair(std::make_pair(phi, pb), phi->getSrc(j)));
    }
 
@@ -423,7 +423,8 @@ RegAlloc::PhiMovesPass::splitEdges(BasicBlock *bb)
       if (pb->getExit()->asFlow()->target.bb == bb)
          pb->getExit()->asFlow()->target.bb = pn;
 
-      for (phi = bb->getPhi(); phi && phi->op == OP_PHI; phi = phi->next) {
+
+      for (phi = bb->getPhi(); phi; phi = asPhi(phi->next)) {
          PhiMap::iterator it = phis.find(std::make_pair(phi, pb));
          assert(it != phis.end());
          phis.insert(std::make_pair(std::make_pair(phi, pn), it->second));
@@ -435,7 +436,7 @@ RegAlloc::PhiMovesPass::splitEdges(BasicBlock *bb)
    j = 0;
    for (ei = bb->cfg.incident(); !ei.end(); ei.next(), j++) {
       pb = BasicBlock::get(ei.getNode());
-      for (phi = bb->getPhi(); phi && phi->op == OP_PHI; phi = phi->next) {
+      for (phi = bb->getPhi(); phi; phi = asPhi(phi->next)) {
          PhiMap::const_iterator it = phis.find(std::make_pair(phi, pb));
          assert(it != phis.end());
 
@@ -455,7 +456,8 @@ RegAlloc::PhiMovesPass::splitEdges(BasicBlock *bb)
 bool
 RegAlloc::PhiMovesPass::visit(BasicBlock *bb)
 {
-   Instruction *phi, *mov;
+   PhiInstruction *phi;
+   Instruction *mov;
 
    splitEdges(bb);
 
@@ -466,7 +468,7 @@ RegAlloc::PhiMovesPass::visit(BasicBlock *bb)
       if (!pb->isTerminated())
          pb->insertTail(new_FlowInstruction(func, OP_BRA, bb));
 
-      for (phi = bb->getPhi(); phi && phi->op == OP_PHI; phi = phi->next) {
+      for (phi = bb->getPhi(); phi; phi = asPhi(phi->next)) {
          LValue *tmp = new_LValue(func, phi->getDef(0)->asLValue());
          mov = new_Instruction(func, OP_MOV, typeOfSize(tmp->reg.size));
 
@@ -488,7 +490,7 @@ RegAlloc::ArgumentMovesPass::visit(BasicBlock *bb)
    // Bind function call inputs/outputs to the same physical register
    // the callee uses, inserting moves as appropriate for the case a
    // conflict arises.
-   for (Instruction *i = bb->getEntry(); i; i = i->next) {
+   for (Instruction *i = bb->getEntry(); i; i = i->getNext()) {
       FlowInstruction *cal = i->asFlow();
       // TODO: Handle indirect calls.
       // Right now they should only be generated for builtins.
@@ -555,7 +557,7 @@ RegAlloc::buildLiveSets(BasicBlock *bb)
 {
    Function *f = bb->getFunction();
    BasicBlock *bn;
-   Instruction *i;
+   BaseInstruction *i;
    unsigned int s, d;
 
    INFO_DBG(prog->dbgFlags, REG_ALLOC, "buildLiveSets(BB:%i)\n", bb->getId());
@@ -651,7 +653,7 @@ RegAlloc::BuildIntervalsPass::visit(BasicBlock *bb)
    for (Graph::EdgeIterator ei = bb->cfg.outgoing(); !ei.end(); ei.next()) {
       BasicBlock *out = BasicBlock::get(ei.getNode());
 
-      for (Instruction *i = out->getPhi(); i && i->op == OP_PHI; i = i->next) {
+      for (BaseInstruction *i = out->getPhi(); i && i->op == OP_PHI; i = i->next) {
          bb->liveSet.clr(i->getDef(0)->id);
 
          for (int s = 0; i->srcExists(s); ++s) {
@@ -671,7 +673,7 @@ RegAlloc::BuildIntervalsPass::visit(BasicBlock *bb)
             addLiveRange(func->getLValue(j), bb, bb->getExit()->serial + 1);
    }
 
-   for (Instruction *i = bb->getExit(); i && i->op != OP_PHI; i = i->prev) {
+   for (BaseInstruction *i = bb->getExit(); i && i->op != OP_PHI; i = i->prev) {
       for (int d = 0; i->defExists(d); ++d) {
          bb->liveSet.clr(i->getDef(d)->id);
          if (i->getDef(d)->reg.data.id >= 0) // add hazard for fixed regs
@@ -779,7 +781,7 @@ private:
 
    bool coalesceValues(Value *, Value *, bool force);
    void resolveSplitsAndMerges();
-   void makeCompound(Instruction *, bool isSplit);
+   void makeCompound(BaseInstruction *, bool isSplit);
 
    inline void checkInterference(const RIG_Node *, Graph::EdgeIterator&);
 
@@ -840,7 +842,7 @@ GCRA::printNodeInfo() const
 }
 
 static bool
-isShortRegOp(Instruction *insn)
+isShortRegOp(BaseInstruction *insn)
 {
    // Immediates are always in src1. Every other situation can be resolved by
    // using a long encoding.
@@ -1017,7 +1019,7 @@ static inline void copyCompound(Value *dst, Value *src)
 }
 
 void
-GCRA::makeCompound(Instruction *insn, bool split)
+GCRA::makeCompound(BaseInstruction *insn, bool split)
 {
    LValue *rep = (split ? insn->getSrc(0) : insn->getDef(0))->asLValue();
 
@@ -1056,8 +1058,8 @@ GCRA::doCoalesce(ArrayList& insns, unsigned int mask)
    int c, n;
 
    for (n = 0; n < insns.getSize(); ++n) {
-      Instruction *i;
-      Instruction *insn = reinterpret_cast<Instruction *>(insns.get(n));
+      BaseInstruction *i;
+      BaseInstruction *insn = reinterpret_cast<BaseInstruction *>(insns.get(n));
 
       switch (insn->op) {
       case OP_PHI:
@@ -1077,7 +1079,7 @@ GCRA::doCoalesce(ArrayList& insns, unsigned int mask)
          for (c = 0; insn->srcExists(c); ++c)
             coalesceValues(insn->getDef(0), insn->getSrc(c), true);
          if (insn->op == OP_MERGE) {
-            merges.push_back(insn);
+            merges.push_back(asInsn(insn));
             if (insn->srcExists(1))
                makeCompound(insn, false);
          }
@@ -1085,7 +1087,7 @@ GCRA::doCoalesce(ArrayList& insns, unsigned int mask)
       case OP_SPLIT:
          if (!(mask & JOIN_MASK_UNION))
             break;
-         splits.push_back(insn);
+         splits.push_back(asInsn(insn));
          for (c = 0; insn->defExists(c); ++c)
             coalesceValues(insn->getSrc(0), insn->getDef(c), true);
          makeCompound(insn, true);
@@ -1117,7 +1119,7 @@ GCRA::doCoalesce(ArrayList& insns, unsigned int mask)
       case OP_TEXPREP:
          if (!(mask & JOIN_MASK_TEX))
             break;
-         for (c = 0; insn->srcExists(c) && c != insn->predSrc; ++c)
+         for (c = 0; insn->srcExists(c) && c != asInsn(insn)->predSrc; ++c)
             coalesceValues(insn->getDef(c), insn->getSrc(c), true);
          break;
       default:
@@ -1468,7 +1470,7 @@ GCRA::allocateRegisters(ArrayList& insns)
          RIG.insert(&nodes[i]);
 
          if (lval->inFile(FILE_GPR) && lval->getInsn() != NULL) {
-            Instruction *insn = lval->getInsn();
+            BaseInstruction *insn = lval->getInsn();
             if (insn->op != OP_MAD && insn->op != OP_FMA && insn->op != OP_SAD)
                continue;
             // For both of the cases below, we only want to add the preference
@@ -1481,7 +1483,7 @@ GCRA::allocateRegisters(ArrayList& insns)
                // Outputting a flag is not supported with short encodings nor
                // with immediate arguments.
                // See handleMADforNV50.
-               if (insn->flagsDef >= 0)
+               if (asInsn(insn)->flagsDef >= 0)
                   continue;
             } else {
                // We can only fold immediate arguments if dst == src2. This
@@ -1635,7 +1637,7 @@ SpillCodeInserter::offsetSlot(Value *base, const LValue *lval)
 }
 
 void
-SpillCodeInserter::spill(Instruction *defi, Value *slot, LValue *lval)
+SpillCodeInserter::spill(BaseInstruction *defi, Value *slot, LValue *lval)
 {
    const DataType ty = typeOfSize(lval->reg.size);
 
@@ -1676,7 +1678,7 @@ SpillCodeInserter::spill(Instruction *defi, Value *slot, LValue *lval)
 }
 
 LValue *
-SpillCodeInserter::unspill(Instruction *usei, LValue *lval, Value *slot)
+SpillCodeInserter::unspill(BaseInstruction *usei, LValue *lval, Value *slot)
 {
    const DataType ty = typeOfSize(lval->reg.size);
 
@@ -1721,7 +1723,7 @@ SpillCodeInserter::unspill(Instruction *usei, LValue *lval, Value *slot)
 
 static bool
 value_cmp(ValueRef *a, ValueRef *b) {
-   Instruction *ai = a->getInsn(), *bi = b->getInsn();
+   BaseInstruction *ai = a->getInsn(), *bi = b->getInsn();
    if (ai->bb != bi->bb)
       return ai->bb->getId() < bi->bb->getId();
    return ai->serial < bi->serial;
@@ -1747,17 +1749,17 @@ SpillCodeInserter::run(const std::list<ValuePair>& lst)
       // Keep track of which instructions to delete later. Deleting them
       // inside the loop is unsafe since a single instruction may have
       // multiple destinations that all need to be spilled (like OP_SPLIT).
-      unordered_set<Instruction *> to_del;
+      unordered_set<BaseInstruction *> to_del;
 
       for (Value::DefIterator d = lval->defs.begin(); d != lval->defs.end();
            ++d) {
          Value *slot = mem ?
             static_cast<Value *>(mem) : new_LValue(func, FILE_GPR);
          Value *tmp = NULL;
-         Instruction *last = NULL;
+         BaseInstruction *last = NULL;
 
          LValue *dval = (*d)->get()->asLValue();
-         Instruction *defi = (*d)->getInsn();
+         BaseInstruction *defi = (*d)->getInsn();
 
          // Sort all the uses by BB/instruction so that we don't unspill
          // multiple times in a row, and also remove a source of
@@ -1770,7 +1772,7 @@ SpillCodeInserter::run(const std::list<ValuePair>& lst)
          for (std::vector<ValueRef*>::const_iterator it = refs.begin();
               it != refs.end(); ++it) {
             ValueRef *u = *it;
-            Instruction *usei = u->getInsn();
+            BaseInstruction *usei = u->getInsn();
             assert(usei);
             if (usei->isPseudo()) {
                tmp = (slot->reg.file == FILE_MEMORY_LOCAL) ? NULL : slot;
@@ -1796,7 +1798,7 @@ SpillCodeInserter::run(const std::list<ValuePair>& lst)
          }
       }
 
-      for (unordered_set<Instruction *>::const_iterator it = to_del.begin();
+      for (unordered_set<BaseInstruction *>::const_iterator it = to_del.begin();
            it != to_del.end(); ++it)
          delete_Instruction(func->getProgram(), *it);
    }
@@ -1922,7 +1924,7 @@ GCRA::resolveSplitsAndMerges()
          // perform the same fixup on that node's sources, since after RA
          // their registers should be identical.
          if (v->getInsn()->op == OP_PHI || v->getInsn()->op == OP_UNION) {
-            Instruction *phi = v->getInsn();
+            BaseInstruction *phi = v->getInsn();
             for (int phis = 0; phi->srcExists(phis); ++phis) {
                phi->getSrc(phis)->join = v;
                phi->getSrc(phis)->reg.data.id = v->reg.data.id;
@@ -1993,7 +1995,7 @@ RegAlloc::InsertConstraintsPass::detectConflict(Instruction *cst, int s)
       if (v == cst->getSrc(c))
          return true;
 
-   Instruction *defi = v->getInsn();
+   BaseInstruction *defi = v->getInsn();
 
    return (!defi || defi->constrainedDefs());
 }
@@ -2036,7 +2038,7 @@ RegAlloc::InsertConstraintsPass::addConstraint(Instruction *i, int s, int n)
 // to prevent it from being assigned a register which overlapping the load's
 // destination, which would produce random corruptions.
 void
-RegAlloc::InsertConstraintsPass::addHazard(Instruction *i, const ValueRef *src)
+RegAlloc::InsertConstraintsPass::addHazard(BaseInstruction *i, const ValueRef *src)
 {
    Instruction *hzd = new_Instruction(func, OP_NOP, TYPE_NONE);
    hzd->setSrc(0, src->get());
@@ -2046,7 +2048,7 @@ RegAlloc::InsertConstraintsPass::addHazard(Instruction *i, const ValueRef *src)
 
 // b32 { %r0 %r1 %r2 %r3 } -> b128 %r0q
 void
-RegAlloc::InsertConstraintsPass::condenseDefs(Instruction *insn)
+RegAlloc::InsertConstraintsPass::condenseDefs(BaseInstruction *insn)
 {
    uint8_t size = 0;
    int n;
@@ -2070,7 +2072,8 @@ RegAlloc::InsertConstraintsPass::condenseDefs(Instruction *insn)
       insn->setDef(d, NULL);
    }
    // carry over predicate if any (mainly for OP_UNION uses)
-   split->setPredicate(insn->cc, insn->getPredicate());
+   if (asInsn(insn))
+      split->setPredicate(asInsn(insn)->cc, asInsn(insn)->getPredicate());
 
    insn->bb->insertAfter(insn, split);
    constrList.push_back(split);
@@ -2253,12 +2256,12 @@ bool
 RegAlloc::InsertConstraintsPass::visit(BasicBlock *bb)
 {
    TexInstruction *tex;
-   Instruction *next;
+   BaseInstruction *next;
    int s, size;
 
    targ = bb->getProgram()->getTarget();
 
-   for (Instruction *i = bb->getEntry(); i; i = next) {
+   for (BaseInstruction *i = bb->getEntry(); i; i = next) {
       next = i->next;
 
       if ((tex = i->asTex())) {
@@ -2292,7 +2295,7 @@ RegAlloc::InsertConstraintsPass::visit(BasicBlock *bb)
             assert(i->srcExists(s));
             size -= i->getSrc(s)->reg.size;
          }
-         condenseSrcs(i, 1, s - 1);
+         condenseSrcs(asInsn(i), 1, s - 1);
       } else
       if (i->op == OP_LOAD || i->op == OP_VFETCH) {
          condenseDefs(i);
@@ -2304,7 +2307,7 @@ RegAlloc::InsertConstraintsPass::visit(BasicBlock *bb)
       if (i->op == OP_UNION ||
           i->op == OP_MERGE ||
           i->op == OP_SPLIT) {
-         constrList.push_back(i);
+         constrList.push_back(asInsn(i));
       }
    }
    return true;
@@ -2317,7 +2320,7 @@ RegAlloc::InsertConstraintsPass::insertConstraintMove(Instruction *cst, int s)
 
    assert(cst->getSrc(s)->defs.size() == 1); // still SSA
 
-   Instruction *defi = cst->getSrc(s)->defs.front()->getInsn();
+   BaseInstruction *defi = cst->getSrc(s)->defs.front()->getInsn();
    bool imm = defi->op == OP_MOV &&
       defi->src(0).getFile() == FILE_IMMEDIATE;
    bool load = defi->op == OP_LOAD &&
@@ -2348,8 +2351,8 @@ RegAlloc::InsertConstraintsPass::insertConstraintMove(Instruction *cst, int s)
       mov->setSrc(0, defi->getSrc(0));
    }
 
-   if (defi->getPredicate())
-      mov->setPredicate(defi->cc, defi->getPredicate());
+   if (asInsn(defi) && asInsn(defi)->getPredicate())
+      mov->setPredicate(asInsn(defi)->cc, asInsn(defi)->getPredicate());
 
    cst->setSrc(s, mov->getDef(0));
    cst->bb->insertBefore(cst, mov);
diff --git a/src/gallium/drivers/nouveau/codegen/nv50_ir_ssa.cpp b/src/gallium/drivers/nouveau/codegen/nv50_ir_ssa.cpp
index 3d25ad928e..e2f7522c74 100644
--- a/src/gallium/drivers/nouveau/codegen/nv50_ir_ssa.cpp
+++ b/src/gallium/drivers/nouveau/codegen/nv50_ir_ssa.cpp
@@ -242,7 +242,7 @@ Function::buildLiveSetsPreSSA(BasicBlock *bb, const int seq)
       bb->liveSet.fill(0);
    bb->liveSet.marker = true;
 
-   for (Instruction *i = bb->getEntry(); i; i = i->next) {
+   for (BaseInstruction *i = bb->getEntry(); i; i = i->next) {
       for (int s = 0; i->srcExists(s); ++s)
          if (i->getSrc(s)->asLValue() && !assigned.test(i->getSrc(s)->id))
             usedBeforeAssigned.set(i->getSrc(s)->id);
@@ -277,7 +277,7 @@ Function::buildDefSetsPreSSA(BasicBlock *bb, const int seq)
       bb->defSet |= in->defSet;
    }
 
-   for (Instruction *i = bb->getEntry(); i; i = i->next) {
+   for (BaseInstruction *i = bb->getEntry(); i; i = i->next) {
       for (int d = 0; i->defExists(d); ++d)
          bb->defSet.set(i->getDef(d)->id);
    }
@@ -371,7 +371,7 @@ Function::convertToSSA()
 
          DLList::Iterator dfIter = bb->getDF().iterator();
          for (; !dfIter.end(); dfIter.next()) {
-            Instruction *phi;
+            PhiInstruction *phi;
             BasicBlock *dfBB = BasicBlock::get(dfIter);
 
             if (hasAlready[dfBB->getId()] >= iterCount)
@@ -382,12 +382,12 @@ Function::convertToSSA()
             if (!dfBB->liveSet.test(lval->id))
                continue;
 
-            phi = new_Instruction(this, OP_PHI, typeOfSize(lval->reg.size));
+            phi = new_PhiInstruction(this, typeOfSize(lval->reg.size));
             dfBB->insertTail(phi);
 
             phi->setDef(0, lval);
-            for (int s = 0; s < dfBB->cfg.incidentCount(); ++s)
-               phi->setSrc(s, lval);
+            for (Graph::EdgeIterator ei = dfBB->cfg.incident(); !ei.end(); ei.next())
+               phi->setSrc(phi->srcCount(), lval);
 
             if (work[dfBB->getId()] < iterCount) {
                work[dfBB->getId()] = iterCount;
@@ -472,7 +472,7 @@ void RenamePass::search(BasicBlock *bb)
       }
    }
 
-   for (Instruction *stmt = bb->getFirst(); stmt; stmt = stmt->next) {
+   for (BaseInstruction *stmt = bb->getFirst(); stmt; stmt = stmt->next) {
       // PHI sources get definitions from the passes through the incident BBs,
       // so skip them here.
       if (stmt->op != OP_PHI) {
@@ -485,7 +485,7 @@ void RenamePass::search(BasicBlock *bb)
             lval = getStackTop(lval);
             if (!lval)
                lval = mkUndefined(stmt->getSrc(s));
-            stmt->setSrc(s, lval);
+            asInsn(stmt)->setSrc(s, lval);
          }
       }
       for (d = 0; stmt->defExists(d); ++d) {
@@ -501,7 +501,7 @@ void RenamePass::search(BasicBlock *bb)
 
    // Update sources of PHI ops corresponding to this BB in outgoing BBs.
    for (Graph::EdgeIterator ei = bb->cfg.outgoing(); !ei.end(); ei.next()) {
-      Instruction *phi;
+      PhiInstruction *phi;
       int p = 0;
       BasicBlock *sb = BasicBlock::get(ei.getNode());
 
@@ -513,7 +513,7 @@ void RenamePass::search(BasicBlock *bb)
       }
       assert(p < sb->cfg.incidentCount());
 
-      for (phi = sb->getPhi(); phi && phi->op == OP_PHI; phi = phi->next) {
+      for (phi = sb->getPhi(); phi; phi = asPhi(phi->next)) {
          lval = getStackTop(phi->getSrc(p));
          if (!lval)
             lval = mkUndefined(phi->getSrc(p));
@@ -542,7 +542,7 @@ void RenamePass::search(BasicBlock *bb)
 
    // Pop the values we created in this block from the stack because we will
    // return to blocks that we do not dominate.
-   for (Instruction *stmt = bb->getFirst(); stmt; stmt = stmt->next) {
+   for (BaseInstruction *stmt = bb->getFirst(); stmt; stmt = stmt->next) {
       if (stmt->op == OP_NOP)
          continue;
       for (d = 0; stmt->defExists(d); ++d)
diff --git a/src/gallium/drivers/nouveau/codegen/nv50_ir_target.cpp b/src/gallium/drivers/nouveau/codegen/nv50_ir_target.cpp
index 298e7c6ef9..0135e720bc 100644
--- a/src/gallium/drivers/nouveau/codegen/nv50_ir_target.cpp
+++ b/src/gallium/drivers/nouveau/codegen/nv50_ir_target.cpp
@@ -262,7 +262,7 @@ CodeEmitter::prepareEmission(BasicBlock *bb)
 
    for (; j >= 0; --j) {
       BasicBlock *in = func->bbArray[j];
-      Instruction *exit = in->getExit();
+      BaseInstruction *exit = in->getExit();
 
       if (exit && exit->op == OP_BRA && exit->asFlow()->target.bb == bb) {
          in->binSize -= 8;
@@ -285,7 +285,7 @@ CodeEmitter::prepareEmission(BasicBlock *bb)
    // determine encoding size, try to group short instructions
    nShort = 0;
    for (i = bb->getEntry(); i; i = next) {
-      next = i->next;
+      next = i->getNext();
 
       if (i->op == OP_MEMBAR && !targ->isOpSupported(OP_MEMBAR, TYPE_NONE)) {
          bb->remove(i);
@@ -297,29 +297,29 @@ CodeEmitter::prepareEmission(BasicBlock *bb)
          ++nShort;
       else
       if ((nShort & 1) && next && getMinEncodingSize(next) == 4) {
-         if (i->isCommutationLegal(i->next)) {
+         if (i->isCommutationLegal(i->getNext())) {
             bb->permuteAdjacent(i, next);
             next->encSize = 4;
             next = i;
-            i = i->prev;
+            i = i->getPrev();
             ++nShort;
          } else
-         if (i->isCommutationLegal(i->prev) && next->next) {
-            bb->permuteAdjacent(i->prev, i);
+         if (i->isCommutationLegal(i->getPrev()) && next->getNext()) {
+            bb->permuteAdjacent(i->getPrev(), i);
             next->encSize = 4;
-            next = next->next;
+            next = next->getNext();
             bb->binSize += 4;
             ++nShort;
          } else {
             i->encSize = 8;
-            i->prev->encSize = 8;
+            i->getPrev()->encSize = 8;
             bb->binSize += 4;
             nShort = 0;
          }
       } else {
          i->encSize = 8;
          if (nShort & 1) {
-            i->prev->encSize = 8;
+            i->getPrev()->encSize = 8;
             bb->binSize += 4;
          }
          nShort = 0;
@@ -327,17 +327,17 @@ CodeEmitter::prepareEmission(BasicBlock *bb)
       bb->binSize += i->encSize;
    }
 
-   if (bb->getExit()->encSize == 4) {
+   if (asInsn(bb->getExit())->encSize == 4) {
       assert(nShort);
-      bb->getExit()->encSize = 8;
+      asInsn(bb->getExit())->encSize = 8;
       bb->binSize += 4;
 
-      if ((bb->getExit()->prev->encSize == 4) && !(nShort & 1)) {
+      if ((asInsn(bb->getExit()->prev)->encSize == 4) && !(nShort & 1)) {
          bb->binSize += 8;
-         bb->getExit()->prev->encSize = 8;
+         asInsn(bb->getExit()->prev)->encSize = 8;
       }
    }
-   assert(!bb->getEntry() || (bb->getExit() && bb->getExit()->encSize == 8));
+   assert(!bb->getEntry() || (bb->getExit() && asInsn(bb->getExit())->encSize == 8));
 
    func->binSize += bb->binSize;
 }
@@ -389,7 +389,7 @@ Program::emitBinary(struct nv50_ir_prog_info *info)
       assert(emit->getCodeSize() == fn->binPos);
 
       for (int b = 0; b < fn->bbCount; ++b) {
-         for (Instruction *i = fn->bbArray[b]->getEntry(); i; i = i->next) {
+         for (Instruction *i = fn->bbArray[b]->getEntry(); i; i = i->getNext()) {
             emit->emitInstruction(i);
             info->bin.instructions++;
             if ((typeSizeof(i->sType) == 8 || typeSizeof(i->dType) == 8) &&
diff --git a/src/gallium/drivers/nouveau/codegen/nv50_ir_util.h b/src/gallium/drivers/nouveau/codegen/nv50_ir_util.h
index c619499046..732ad436ad 100644
--- a/src/gallium/drivers/nouveau/codegen/nv50_ir_util.h
+++ b/src/gallium/drivers/nouveau/codegen/nv50_ir_util.h
@@ -64,6 +64,8 @@
    NV50_IR_FUNC_ALLOC_OBJ_DEF(TexInstruction, f, args)
 #define new_FlowInstruction(f, args...)                  \
    NV50_IR_FUNC_ALLOC_OBJ_DEF(FlowInstruction, f, args)
+#define new_PhiInstruction(f, args...)                   \
+   NV50_IR_FUNC_ALLOC_OBJ_DEF(PhiInstruction, f, args)
 
 #define new_LValue(f, args...)                  \
    NV50_IR_FUNC_ALLOC_OBJ_DEF(LValue, f, args)
-- 
2.14.4



More information about the mesa-dev mailing list