Bug 1058095 - IonMonkey: Move fields from InstructionData into LInstruction r=bhackett
authorDan Gohman <sunfish@mozilla.com>
Fri, 10 Oct 2014 21:21:35 -0700
changeset 209956 bd25766ac048d86c68a01896f827d5effce193b5
parent 209955 7deba8fa4e1993409c2b1464ec430debd8608ac8
child 209957 8843395921bfeaf27453e7215301de90c95c536d
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersbhackett
bugs1058095
milestone35.0a1
Bug 1058095 - IonMonkey: Move fields from InstructionData into LInstruction r=bhackett
js/src/jit/BacktrackingAllocator.cpp
js/src/jit/LIR.cpp
js/src/jit/LIR.h
js/src/jit/LinearScan.cpp
js/src/jit/RegisterAllocator.cpp
js/src/jit/RegisterAllocator.h
--- a/js/src/jit/BacktrackingAllocator.cpp
+++ b/js/src/jit/BacktrackingAllocator.cpp
@@ -244,31 +244,31 @@ BacktrackingAllocator::tryGroupReusedReg
     // instruction. Handle this splitting eagerly.
 
     if (usedReg.numIntervals() != 1 ||
         (usedReg.def()->isFixed() && !usedReg.def()->output()->isRegister())) {
         reg.setMustCopyInput();
         return true;
     }
     LiveInterval *interval = usedReg.getInterval(0);
-    LBlock *block = insData[reg.ins()].block();
+    LBlock *block = reg.ins()->block();
 
     // The input's lifetime must end within the same block as the definition,
     // otherwise it could live on in phis elsewhere.
     if (interval->end() > exitOf(block)) {
         reg.setMustCopyInput();
         return true;
     }
 
     for (UsePositionIterator iter = interval->usesBegin(); iter != interval->usesEnd(); iter++) {
         if (iter->pos <= inputOf(reg.ins()))
             continue;
 
         LUse *use = iter->use;
-        if (FindReusingDefinition(insData[iter->pos].ins(), use)) {
+        if (FindReusingDefinition(insData[iter->pos], use)) {
             reg.setMustCopyInput();
             return true;
         }
         if (use->policy() != LUse::ANY && use->policy() != LUse::KEEPALIVE) {
             reg.setMustCopyInput();
             return true;
         }
     }
@@ -953,26 +953,26 @@ BacktrackingAllocator::resolveControlFlo
                     skip = true;
                     break;
                 }
             }
             if (skip)
                 continue;
 
             CodePosition start = interval->start();
-            InstructionData *data = &insData[start];
-            if (interval->start() > entryOf(data->block())) {
-                MOZ_ASSERT(start == inputOf(data->ins()) || start == outputOf(data->ins()));
+            LInstruction *ins = insData[start];
+            if (interval->start() > entryOf(ins->block())) {
+                MOZ_ASSERT(start == inputOf(ins) || start == outputOf(ins));
 
                 LiveInterval *prevInterval = reg->intervalFor(start.previous());
                 if (start.subpos() == CodePosition::INPUT) {
-                    if (!moveInput(inputOf(data->ins()), prevInterval, interval, reg->type()))
+                    if (!moveInput(inputOf(ins), prevInterval, interval, reg->type()))
                         return false;
                 } else {
-                    if (!moveAfter(outputOf(data->ins()), prevInterval, interval, reg->type()))
+                    if (!moveAfter(outputOf(ins), prevInterval, interval, reg->type()))
                         return false;
                 }
             }
         }
     }
 
     JitSpew(JitSpew_RegAlloc, "Resolving control flow (block loop)");
 
@@ -1114,17 +1114,17 @@ BacktrackingAllocator::reifyAllocations(
                  iter != interval->usesEnd();
                  iter++)
             {
                 LAllocation *alloc = iter->use;
                 *alloc = *interval->getAllocation();
 
                 // For any uses which feed into MUST_REUSE_INPUT definitions,
                 // add copies if the use and def have different allocations.
-                LInstruction *ins = insData[iter->pos].ins();
+                LInstruction *ins = insData[iter->pos];
                 if (LDefinition *def = FindReusingDefinition(ins, alloc)) {
                     LiveInterval *outputInterval =
                         vregs[def->virtualRegister()].intervalFor(outputOf(ins));
                     LAllocation *res = outputInterval->getAllocation();
                     LAllocation *sourceAlloc = interval->getAllocation();
 
                     if (*res != *alloc) {
                         LMoveGroup *group = getInputMoveGroup(inputOf(ins));
@@ -1398,22 +1398,22 @@ BacktrackingAllocator::minimalInterval(c
     for (UsePositionIterator iter = interval->usesBegin(); iter != interval->usesEnd(); iter++) {
         LUse *use = iter->use;
 
         switch (use->policy()) {
           case LUse::FIXED:
             if (fixed)
                 return false;
             fixed = true;
-            if (minimalUse(interval, insData[iter->pos].ins()))
+            if (minimalUse(interval, insData[iter->pos]))
                 minimal = true;
             break;
 
           case LUse::REGISTER:
-            if (minimalUse(interval, insData[iter->pos].ins()))
+            if (minimalUse(interval, insData[iter->pos]))
                 minimal = true;
             break;
 
           default:
             break;
         }
     }
 
@@ -1535,29 +1535,29 @@ BacktrackingAllocator::trySplitAfterLast
     // split it after the last use which does require a register. If conflict
     // is specified, only consider register uses before the conflict starts.
 
     CodePosition lastRegisterFrom, lastRegisterTo, lastUse;
 
     // If the definition of the interval is in a register, consider that a
     // register use too for our purposes here.
     if (isRegisterDefinition(interval)) {
-        CodePosition spillStart = minimalDefEnd(insData[interval->start()].ins()).next();
+        CodePosition spillStart = minimalDefEnd(insData[interval->start()]).next();
         if (!conflict || spillStart < conflict->start()) {
             lastUse = lastRegisterFrom = interval->start();
             lastRegisterTo = spillStart;
         }
     }
 
     for (UsePositionIterator iter(interval->usesBegin());
          iter != interval->usesEnd();
          iter++)
     {
         LUse *use = iter->use;
-        LInstruction *ins = insData[iter->pos].ins();
+        LInstruction *ins = insData[iter->pos];
 
         // Uses in the interval should be sorted.
         MOZ_ASSERT(iter->pos >= lastUse);
         lastUse = inputOf(ins);
 
         if (!conflict || outputOf(ins) < conflict->start()) {
             if (isRegisterUse(use, ins, /* considerCopy = */ true)) {
                 lastRegisterFrom = inputOf(ins);
@@ -1604,17 +1604,17 @@ BacktrackingAllocator::trySplitBeforeFir
 
     CodePosition firstRegisterFrom;
 
     for (UsePositionIterator iter(interval->usesBegin());
          iter != interval->usesEnd();
          iter++)
     {
         LUse *use = iter->use;
-        LInstruction *ins = insData[iter->pos].ins();
+        LInstruction *ins = insData[iter->pos];
 
         if (!conflict || outputOf(ins) >= conflict->end()) {
             if (isRegisterUse(use, ins, /* considerCopy = */ true)) {
                 firstRegisterFrom = inputOf(ins);
                 break;
             }
         }
     }
@@ -1656,17 +1656,17 @@ BacktrackingAllocator::splitAtAllRegiste
         spillIntervalIsNew = true;
     }
 
     CodePosition spillStart = interval->start();
     if (isRegisterDefinition(interval)) {
         // Treat the definition of the interval as a register use so that it
         // can be split and spilled ASAP.
         CodePosition from = interval->start();
-        CodePosition to = minimalDefEnd(insData[from].ins()).next();
+        CodePosition to = minimalDefEnd(insData[from]).next();
         if (!addLiveInterval(newIntervals, vreg, spillInterval, from, to))
             return false;
         spillStart = to;
     }
 
     if (spillIntervalIsNew) {
         for (size_t i = 0; i < interval->numRanges(); i++) {
             const LiveInterval::Range *range = interval->getRange(i);
@@ -1675,17 +1675,17 @@ BacktrackingAllocator::splitAtAllRegiste
                 return false;
         }
     }
 
     for (UsePositionIterator iter(interval->usesBegin());
          iter != interval->usesEnd();
          iter++)
     {
-        LInstruction *ins = insData[iter->pos].ins();
+        LInstruction *ins = insData[iter->pos];
         if (iter->pos < spillStart) {
             newIntervals.back()->addUseAtEnd(new(alloc()) UsePosition(iter->use, iter->pos));
         } else if (isRegisterUse(iter->use, ins)) {
             // For register uses which are not useRegisterAtStart, pick an
             // interval that covers both the instruction's input and output, so
             // that the register is not reused for an output.
             CodePosition from = inputOf(ins);
             CodePosition to = iter->pos.next();
@@ -1743,17 +1743,17 @@ BacktrackingAllocator::splitAt(LiveInter
     // splitPositions should be non-empty and sorted.
     MOZ_ASSERT(!splitPositions.empty());
     for (size_t i = 1; i < splitPositions.length(); ++i)
         MOZ_ASSERT(splitPositions[i-1] < splitPositions[i]);
 
     // Don't spill the interval until after the end of its definition.
     CodePosition spillStart = interval->start();
     if (isRegisterDefinition(interval))
-        spillStart = minimalDefEnd(insData[interval->start()].ins()).next();
+        spillStart = minimalDefEnd(insData[interval->start()]).next();
 
     uint32_t vreg = interval->vreg();
 
     // If this LiveInterval is the result of an earlier split which created a
     // spill interval, that spill interval covers the whole range, so we don't
     // need to create a new one.
     bool spillIntervalIsNew = false;
     LiveInterval *spillInterval = interval->spillInterval();
@@ -1777,17 +1777,17 @@ BacktrackingAllocator::splitAt(LiveInter
         newInterval->setSpillInterval(spillInterval);
         if (!newIntervals.append(newInterval))
             return false;
         lastRegisterUse = interval->start();
     }
 
     size_t activeSplitPosition = NextSplitPosition(0, splitPositions, interval->start());
     for (UsePositionIterator iter(interval->usesBegin()); iter != interval->usesEnd(); iter++) {
-        LInstruction *ins = insData[iter->pos].ins();
+        LInstruction *ins = insData[iter->pos];
         if (iter->pos < spillStart) {
             newIntervals.back()->addUseAtEnd(new(alloc()) UsePosition(iter->use, iter->pos));
             activeSplitPosition = NextSplitPosition(activeSplitPosition, splitPositions, iter->pos);
         } else if (isRegisterUse(iter->use, ins)) {
             if (lastRegisterUse.bits() == 0 ||
                 SplitHere(activeSplitPosition, splitPositions, iter->pos))
             {
                 // Place this register use into a different interval from the
@@ -1815,17 +1815,17 @@ BacktrackingAllocator::splitAt(LiveInter
         CodePosition start, end;
         if (i == 0 && spillStart != interval->start()) {
             start = interval->start();
             if (newInterval->usesEmpty())
                 end = spillStart;
             else
                 end = newInterval->usesBack()->pos.next();
         } else {
-            start = inputOf(insData[newInterval->usesBegin()->pos].ins());
+            start = inputOf(insData[newInterval->usesBegin()->pos]);
             end = newInterval->usesBack()->pos.next();
         }
         for (; activeRange > 0; --activeRange) {
             const LiveInterval::Range *range = interval->getRange(activeRange - 1);
             if (range->to <= start)
                 continue;
             if (range->from >= end)
                 break;
--- a/js/src/jit/LIR.cpp
+++ b/js/src/jit/LIR.cpp
@@ -105,17 +105,18 @@ LBlock::init(TempAllocator &alloc)
 
         int numPhis = (phi->type() == MIRType_Value) ? BOX_PIECES : 1;
         for (int i = 0; i < numPhis; i++) {
             void *array = alloc.allocateArray<sizeof(LAllocation)>(numPreds);
             LAllocation *inputs = static_cast<LAllocation *>(array);
             if (!inputs)
                 return false;
 
-            new (&phis_[phiIndex++]) LPhi(phi, inputs);
+            LPhi *lphi = new (&phis_[phiIndex++]) LPhi(phi, inputs);
+            lphi->setBlock(this);
         }
     }
     return true;
 }
 
 uint32_t
 LBlock::firstId() const
 {
--- a/js/src/jit/LIR.h
+++ b/js/src/jit/LIR.h
@@ -606,23 +606,30 @@ class LInstruction
     // This snapshot could be set after a ResumePoint.  It is used to restart
     // from the resume point pc.
     LSnapshot *snapshot_;
 
     // Structure capturing the set of stack slots and registers which are known
     // to hold either gcthings or Values.
     LSafepoint *safepoint_;
 
+    LBlock *block_;
+    LMoveGroup *inputMoves_;
+    LMoveGroup *movesAfter_;
+
   protected:
     MDefinition *mir_;
 
     LInstruction()
       : id_(0),
         snapshot_(nullptr),
         safepoint_(nullptr),
+        block_(nullptr),
+        inputMoves_(nullptr),
+        movesAfter_(nullptr),
         mir_(nullptr)
     { }
 
   public:
     class InputIterator;
     enum Opcode {
 #   define LIROP(name) LOp_##name,
         LIR_OPCODE_LIST(LIROP)
@@ -692,16 +699,34 @@ class LInstruction
     }
     void setMir(MDefinition *mir) {
         mir_ = mir;
     }
     MDefinition *mirRaw() const {
         /* Untyped MIR for this op. Prefer mir() methods in subclasses. */
         return mir_;
     }
+    LBlock *block() const {
+        return block_;
+    }
+    void setBlock(LBlock *block) {
+        block_ = block;
+    }
+    LMoveGroup *inputMoves() const {
+        return inputMoves_;
+    }
+    void setInputMoves(LMoveGroup *moves) {
+        inputMoves_ = moves;
+    }
+    LMoveGroup *movesAfter() const {
+        return movesAfter_;
+    }
+    void setMovesAfter(LMoveGroup *moves) {
+        movesAfter_ = moves;
+    }
     void assignSnapshot(LSnapshot *snapshot);
     void initSafepoint(TempAllocator &alloc);
 
     // For an instruction which has a MUST_REUSE_INPUT output, whether that
     // output register will be restored to its original value when bailing out.
     virtual bool recoversInput() const {
         return false;
     }
@@ -773,16 +798,17 @@ class LBlock
     LMoveGroup *exitMoveGroup_;
     Label label_;
 
   public:
     explicit LBlock(MBasicBlock *block);
     bool init(TempAllocator &alloc);
 
     void add(LInstruction *ins) {
+        ins->setBlock(this);
         instructions_.pushBack(ins);
     }
     size_t numPhis() const {
         return phis_.length();
     }
     LPhi *getPhi(size_t index) {
         return &phis_[index];
     }
--- a/js/src/jit/LinearScan.cpp
+++ b/js/src/jit/LinearScan.cpp
@@ -415,42 +415,42 @@ LinearScanAllocator::reifyAllocations()
                 // Insert a spill after this instruction (or after any OsiPoint
                 // or Nop instructions). Note that we explicitly ignore phis,
                 // which should have been handled in resolveControlFlow().
                 LMoveGroup *moves = getMoveGroupAfter(defEnd);
                 if (!moves->add(spillFrom, reg->canonicalSpill(), def->type()))
                     return false;
             }
         }
-        else if (interval->start() > entryOf(insData[interval->start()].block()) &&
+        else if (interval->start() > entryOf(insData[interval->start()]->block()) &&
                  (!reg->canonicalSpill() ||
                   (reg->canonicalSpill() == interval->getAllocation() &&
                    !reg->mustSpillAtDefinition()) ||
                   *reg->canonicalSpill() != *interval->getAllocation()))
         {
             // If this virtual register has no canonical spill location, this
             // is the first spill to that location, or this is a move to somewhere
             // completely different, we have to emit a move for this interval.
             // Don't do this if the interval starts at the first instruction of the
             // block; this case should have been handled by resolveControlFlow().
             //
             // If the interval starts at the output half of an instruction, we have to
             // emit the move *after* this instruction, to prevent clobbering an input
             // register.
             LiveInterval *prevInterval = reg->getInterval(interval->index() - 1);
             CodePosition start = interval->start();
-            InstructionData *data = &insData[start];
+            LInstruction *ins = insData[start];
 
-            MOZ_ASSERT(start == inputOf(data->ins()) || start == outputOf(data->ins()));
+            MOZ_ASSERT(start == inputOf(ins) || start == outputOf(ins));
 
             if (start.subpos() == CodePosition::INPUT) {
-                if (!moveInput(inputOf(data->ins()), prevInterval, interval, reg->type()))
+                if (!moveInput(inputOf(ins), prevInterval, interval, reg->type()))
                     return false;
             } else {
-                if (!moveAfter(outputOf(data->ins()), prevInterval, interval, reg->type()))
+                if (!moveAfter(outputOf(ins), prevInterval, interval, reg->type()))
                     return false;
             }
 
             // Mark this interval's spill position, if needed.
             if (reg->canonicalSpill() == interval->getAllocation() &&
                 !reg->mustSpillAtDefinition())
             {
                 reg->setSpillPosition(interval->start());
@@ -784,17 +784,17 @@ LinearScanAllocator::assign(LAllocation 
             // This interval is spilled more than once, so just always spill
             // it at its definition.
             reg->setSpillAtDefinition(outputOf(reg->ins()));
         } else {
             reg->setCanonicalSpill(current->getAllocation());
 
             // If this spill is inside a loop, and the definition is outside
             // the loop, instead move the spill to outside the loop.
-            InstructionData *other = &insData[current->start()];
+            LInstruction *other = insData[current->start()];
             uint32_t loopDepthAtDef = reg->block()->mir()->loopDepth();
             uint32_t loopDepthAtSpill = other->block()->mir()->loopDepth();
             if (loopDepthAtSpill > loopDepthAtDef)
                 reg->setSpillAtDefinition(outputOf(reg->ins()));
         }
     }
 
     active.pushBack(current);
--- a/js/src/jit/RegisterAllocator.cpp
+++ b/js/src/jit/RegisterAllocator.cpp
@@ -469,59 +469,59 @@ bool
 RegisterAllocator::init()
 {
     if (!insData.init(mir, graph.numInstructions()))
         return false;
 
     for (size_t i = 0; i < graph.numBlocks(); i++) {
         LBlock *block = graph.getBlock(i);
         for (LInstructionIterator ins = block->begin(); ins != block->end(); ins++)
-            insData[*ins].init(*ins, block);
+            insData[ins->id()] = *ins;
         for (size_t j = 0; j < block->numPhis(); j++) {
             LPhi *phi = block->getPhi(j);
-            insData[phi].init(phi, block);
+            insData[phi->id()] = phi;
         }
     }
 
     return true;
 }
 
 LMoveGroup *
-RegisterAllocator::getInputMoveGroup(uint32_t ins)
+RegisterAllocator::getInputMoveGroup(uint32_t id)
 {
-    InstructionData *data = &insData[ins];
-    MOZ_ASSERT(!data->ins()->isPhi());
-    MOZ_ASSERT(!data->ins()->isLabel());
+    LInstruction *ins = insData[id];
+    MOZ_ASSERT(!ins->isPhi());
+    MOZ_ASSERT(!ins->isLabel());
 
-    if (data->inputMoves())
-        return data->inputMoves();
+    if (ins->inputMoves())
+        return ins->inputMoves();
 
     LMoveGroup *moves = LMoveGroup::New(alloc());
-    data->setInputMoves(moves);
-    data->block()->insertBefore(data->ins(), moves);
+    ins->setInputMoves(moves);
+    ins->block()->insertBefore(ins, moves);
 
     return moves;
 }
 
 LMoveGroup *
-RegisterAllocator::getMoveGroupAfter(uint32_t ins)
+RegisterAllocator::getMoveGroupAfter(uint32_t id)
 {
-    InstructionData *data = &insData[ins];
-    MOZ_ASSERT(!data->ins()->isPhi());
+    LInstruction *ins = insData[id];
+    MOZ_ASSERT(!ins->isPhi());
 
-    if (data->movesAfter())
-        return data->movesAfter();
+    if (ins->movesAfter())
+        return ins->movesAfter();
 
     LMoveGroup *moves = LMoveGroup::New(alloc());
-    data->setMovesAfter(moves);
+    ins->setMovesAfter(moves);
 
-    if (data->ins()->isLabel())
-        data->block()->insertAfter(data->block()->getEntryMoveGroup(alloc()), moves);
+    if (ins->isLabel())
+        ins->block()->insertAfter(ins->block()->getEntryMoveGroup(alloc()), moves);
     else
-        data->block()->insertAfter(data->ins(), moves);
+        ins->block()->insertAfter(ins, moves);
     return moves;
 }
 
 void
 RegisterAllocator::dumpInstructions()
 {
 #ifdef DEBUG
     fprintf(stderr, "Instructions:\n");
--- a/js/src/jit/RegisterAllocator.h
+++ b/js/src/jit/RegisterAllocator.h
@@ -212,84 +212,43 @@ class CodePosition
         return CodePosition(bits_ - 1);
     }
     CodePosition next() const {
         MOZ_ASSERT(*this != MAX);
         return CodePosition(bits_ + 1);
     }
 };
 
-// Structure to track moves inserted before or after an instruction.
-class InstructionData
-{
-    LInstruction *ins_;
-    LBlock *block_;
-    LMoveGroup *inputMoves_;
-    LMoveGroup *movesAfter_;
-
-  public:
-    void init(LInstruction *ins, LBlock *block) {
-        MOZ_ASSERT(!ins_);
-        MOZ_ASSERT(!block_);
-        ins_ = ins;
-        block_ = block;
-    }
-    LInstruction *ins() const {
-        return ins_;
-    }
-    LBlock *block() const {
-        return block_;
-    }
-    void setInputMoves(LMoveGroup *moves) {
-        inputMoves_ = moves;
-    }
-    LMoveGroup *inputMoves() const {
-        return inputMoves_;
-    }
-    void setMovesAfter(LMoveGroup *moves) {
-        movesAfter_ = moves;
-    }
-    LMoveGroup *movesAfter() const {
-        return movesAfter_;
-    }
-};
-
 // Structure to track all moves inserted next to instructions in a graph.
 class InstructionDataMap
 {
-    FixedList<InstructionData> insData_;
+    FixedList<LInstruction *> insData_;
 
   public:
     InstructionDataMap()
       : insData_()
     { }
 
     bool init(MIRGenerator *gen, uint32_t numInstructions) {
         if (!insData_.init(gen->alloc(), numInstructions))
             return false;
-        memset(&insData_[0], 0, sizeof(InstructionData) * numInstructions);
+        memset(&insData_[0], 0, sizeof(LInstruction *) * numInstructions);
         return true;
     }
 
-    InstructionData &operator[](CodePosition pos) {
-        return operator[](pos.ins());
-    }
-    const InstructionData &operator[](CodePosition pos) const {
+    LInstruction *&operator[](CodePosition pos) {
         return operator[](pos.ins());
     }
-    InstructionData &operator[](LInstruction *ins) {
-        return operator[](ins->id());
+    LInstruction *const &operator[](CodePosition pos) const {
+        return operator[](pos.ins());
     }
-    const InstructionData &operator[](LInstruction *ins) const {
-        return operator[](ins->id());
-    }
-    InstructionData &operator[](uint32_t ins) {
+    LInstruction *&operator[](uint32_t ins) {
         return insData_[ins];
     }
-    const InstructionData &operator[](uint32_t ins) const {
+    LInstruction *const &operator[](uint32_t ins) const {
         return insData_[ins];
     }
 };
 
 // Common superclass for register allocators.
 class RegisterAllocator
 {
     void operator=(const RegisterAllocator &) MOZ_DELETE;
@@ -331,62 +290,62 @@ class RegisterAllocator
     TempAllocator &alloc() const {
         return mir->alloc();
     }
 
     CodePosition outputOf(uint32_t pos) const {
         // All phis in a block write their outputs after all of them have
         // read their inputs. Consequently, it doesn't make sense to talk
         // about code positions in the middle of a series of phis.
-        if (insData[pos].ins()->isPhi()) {
-            while (insData[pos + 1].ins()->isPhi())
+        if (insData[pos]->isPhi()) {
+            while (insData[pos + 1]->isPhi())
                 ++pos;
         }
         return CodePosition(pos, CodePosition::OUTPUT);
     }
     CodePosition outputOf(const LInstruction *ins) const {
         return outputOf(ins->id());
     }
     CodePosition inputOf(uint32_t pos) const {
         // All phis in a block read their inputs before any of them write their
         // outputs. Consequently, it doesn't make sense to talk about code
         // positions in the middle of a series of phis.
-        if (insData[pos].ins()->isPhi()) {
-            while (pos > 0 && insData[pos - 1].ins()->isPhi())
+        if (insData[pos]->isPhi()) {
+            while (pos > 0 && insData[pos - 1]->isPhi())
                 --pos;
         }
         return CodePosition(pos, CodePosition::INPUT);
     }
     CodePosition inputOf(const LInstruction *ins) const {
         return inputOf(ins->id());
     }
     CodePosition entryOf(const LBlock *block) {
         return inputOf(block->firstId());
     }
     CodePosition exitOf(const LBlock *block) {
         return outputOf(block->lastId());
     }
 
-    LMoveGroup *getInputMoveGroup(uint32_t ins);
-    LMoveGroup *getMoveGroupAfter(uint32_t ins);
+    LMoveGroup *getInputMoveGroup(uint32_t id);
+    LMoveGroup *getMoveGroupAfter(uint32_t id);
 
     LMoveGroup *getInputMoveGroup(CodePosition pos) {
         return getInputMoveGroup(pos.ins());
     }
     LMoveGroup *getMoveGroupAfter(CodePosition pos) {
         return getMoveGroupAfter(pos.ins());
     }
 
     CodePosition minimalDefEnd(LInstruction *ins) {
         // Compute the shortest interval that captures vregs defined by ins.
         // Watch for instructions that are followed by an OSI point and/or Nop.
         // If moves are introduced between the instruction and the OSI point then
         // safepoint information for the instruction may be incorrect.
         while (true) {
-            LInstruction *next = insData[outputOf(ins).next()].ins();
+            LInstruction *next = insData[ins->id() + 1];
             if (!next->isNop() && !next->isOsiPoint())
                 break;
             ins = next;
         }
 
         return outputOf(ins);
     }