typedef std::pair<Value *, Value *> ValuePair;
 
+class MergedDefs
+{
+private:
+   std::list<ValueDef *>& entry(Value *val) {
+      auto it = defs.find(val);
+
+      if (it == defs.end()) {
+         std::list<ValueDef *> &res = defs[val];
+         res = val->defs;
+         return res;
+      } else {
+         return (*it).second;
+      }
+   }
+
+   std::unordered_map<Value *, std::list<ValueDef *> > defs;
+
+public:
+   std::list<ValueDef *>& operator()(Value *val) {
+      return entry(val);
+   }
+
+   void add(Value *val, const std::list<ValueDef *> &vals) {
+      assert(val);
+      std::list<ValueDef *> &valdefs = entry(val);
+      valdefs.insert(valdefs.end(), vals.begin(), vals.end());
+   }
+
+   void removeDefsOfInstruction(Instruction *insn) {
+      for (int d = 0; insn->defExists(d); ++d) {
+         ValueDef *def = &insn->def(d);
+         defs.erase(def->get());
+         for (auto &p : defs)
+            p.second.remove(def);
+      }
+   }
+
+   void merge() {
+      for (auto &p : defs)
+         p.first->defs = p.second;
+   }
+};
+
 class SpillCodeInserter
 {
 public:
-   SpillCodeInserter(Function *fn) : func(fn), stackSize(0), stackBase(0) { }
+   SpillCodeInserter(Function *fn, MergedDefs &mergedDefs) : func(fn), mergedDefs(mergedDefs), stackSize(0), stackBase(0) { }
 
    bool run(const std::list<ValuePair>&);
 
 
 private:
    Function *func;
+   MergedDefs &mergedDefs;
 
    struct SpillSlot
    {
 class GCRA
 {
 public:
-   GCRA(Function *, SpillCodeInserter&);
+   GCRA(Function *, SpillCodeInserter&, MergedDefs&);
    ~GCRA();
 
    bool allocateRegisters(ArrayList& insns);
 
    SpillCodeInserter& spill;
    std::list<ValuePair> mustSpill;
+
+   MergedDefs &mergedDefs;
 };
 
 const GCRA::RelDegree GCRA::relDegree;
             rep->id, rep->reg.data.id, val->id);
 
    // set join pointer of all values joined with val
-   for (ValueDef *def : val->defs)
+   const std::list<ValueDef *> &defs = mergedDefs(val);
+   for (ValueDef *def : defs)
       def->get()->join = rep;
    assert(rep->join == rep && val->join == rep);
 
    // add val's definitions to rep and extend the live interval of its RIG node
-   rep->defs.insert(rep->defs.end(), val->defs.begin(), val->defs.end());
+   mergedDefs.add(rep, defs);
    nRep->livei.unify(nVal->livei);
    nRep->degreeLimit = MIN2(nRep->degreeLimit, nVal->degreeLimit);
    nRep->maxReg = MIN2(nRep->maxReg, nVal->maxReg);
    prefRegs.push_back(node);
 }
 
-GCRA::GCRA(Function *fn, SpillCodeInserter& spill) :
+GCRA::GCRA(Function *fn, SpillCodeInserter& spill, MergedDefs& mergedDefs) :
    func(fn),
    regs(fn->getProgram()->getTarget()),
-   spill(spill)
+   spill(spill),
+   mergedDefs(mergedDefs)
 {
    prog = func->getProgram();
 }
 
       if (!val->noSpill) {
          int rc = 0;
-         for (ValueDef *def : val->defs)
+         for (ValueDef *def : mergedDefs(val))
             rc += def->get()->refCount();
 
          nodes[i].weight =
 
    if (intf->reg < 0)
       return;
-   const LValue *vA = node->getValue();
-   const LValue *vB = intf->getValue();
+   LValue *vA = node->getValue();
+   LValue *vB = intf->getValue();
 
    const uint8_t intfMask = ((1 << intf->colors) - 1) << (intf->reg & 7);
 
    if (vA->compound | vB->compound) {
       // NOTE: this only works for >aligned< register tuples !
-      for (const ValueDef *D : vA->defs) {
-      for (const ValueDef *d : vB->defs) {
+      for (const ValueDef *D : mergedDefs(vA)) {
+      for (const ValueDef *d : mergedDefs(vB)) {
          const LValue *vD = D->get()->asLValue();
          const LValue *vd = d->get()->asLValue();
 
       if (prog->dbgFlags & NV50_IR_DEBUG_REG_ALLOC)
          func->print();
    } else {
+      mergedDefs.merge();
       prog->maxGPR = std::max(prog->maxGPR, regs.getMaxAssigned(FILE_GPR));
    }
 
       if (lval->join == lval)
          continue;
 
-      if (success) {
+      if (success)
          lval->reg.data.id = lval->join->reg.data.id;
-      } else {
-         for (Value::DefIterator d = lval->defs.begin(); d != lval->defs.end();
-              ++d)
-            lval->join->defs.remove(*d);
+      else
          lval->join = lval;
-      }
    }
 
    if (success)
       // multiple destinations that all need to be spilled (like OP_SPLIT).
       unordered_set<Instruction *> to_del;
 
-      for (Value::DefIterator d = lval->defs.begin(); d != lval->defs.end();
+      std::list<ValueDef *> &defs = mergedDefs(lval);
+      for (Value::DefIterator d = defs.begin(); d != defs.end();
            ++d) {
          Value *slot = mem ?
             static_cast<Value *>(mem) : new_LValue(func, FILE_GPR);
 
          assert(defi);
          if (defi->isPseudo()) {
-            d = lval->defs.erase(d);
+            d = defs.erase(d);
             --d;
             if (slot->reg.file == FILE_MEMORY_LOCAL)
                to_del.insert(defi);
       }
 
       for (unordered_set<Instruction *>::const_iterator it = to_del.begin();
-           it != to_del.end(); ++it)
+           it != to_del.end(); ++it) {
+         mergedDefs.removeDefsOfInstruction(*it);
          delete_Instruction(func->getProgram(), *it);
+      }
    }
 
    // TODO: We're not trying to reuse old slots in a potential next iteration.
 bool
 RegAlloc::execFunc()
 {
+   MergedDefs mergedDefs;
    InsertConstraintsPass insertConstr;
    PhiMovesPass insertPhiMoves;
    ArgumentMovesPass insertArgMoves;
    BuildIntervalsPass buildIntervals;
-   SpillCodeInserter insertSpills(func);
+   SpillCodeInserter insertSpills(func, mergedDefs);
 
-   GCRA gcra(func, insertSpills);
+   GCRA gcra(func, insertSpills, mergedDefs);
 
    unsigned int i, retries;
    bool ret;