js/src/jit/RegisterAllocator.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/js/src/jit/RegisterAllocator.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,513 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99:
     1.6 + * This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +#include "jit/RegisterAllocator.h"
    1.11 +
    1.12 +using namespace js;
    1.13 +using namespace js::jit;
    1.14 +
    1.15 +bool
    1.16 +AllocationIntegrityState::record()
    1.17 +{
    1.18 +    // Ignore repeated record() calls.
    1.19 +    if (!instructions.empty())
    1.20 +        return true;
    1.21 +
    1.22 +    if (!instructions.appendN(InstructionInfo(), graph.numInstructions()))
    1.23 +        return false;
    1.24 +
    1.25 +    if (!virtualRegisters.appendN((LDefinition *)nullptr, graph.numVirtualRegisters()))
    1.26 +        return false;
    1.27 +
    1.28 +    if (!blocks.reserve(graph.numBlocks()))
    1.29 +        return false;
    1.30 +    for (size_t i = 0; i < graph.numBlocks(); i++) {
    1.31 +        blocks.infallibleAppend(BlockInfo());
    1.32 +        LBlock *block = graph.getBlock(i);
    1.33 +        JS_ASSERT(block->mir()->id() == i);
    1.34 +
    1.35 +        BlockInfo &blockInfo = blocks[i];
    1.36 +        if (!blockInfo.phis.reserve(block->numPhis()))
    1.37 +            return false;
    1.38 +
    1.39 +        for (size_t j = 0; j < block->numPhis(); j++) {
    1.40 +            blockInfo.phis.infallibleAppend(InstructionInfo());
    1.41 +            InstructionInfo &info = blockInfo.phis[j];
    1.42 +            LPhi *phi = block->getPhi(j);
    1.43 +            JS_ASSERT(phi->numDefs() == 1);
    1.44 +            uint32_t vreg = phi->getDef(0)->virtualRegister();
    1.45 +            virtualRegisters[vreg] = phi->getDef(0);
    1.46 +            if (!info.outputs.append(*phi->getDef(0)))
    1.47 +                return false;
    1.48 +            for (size_t k = 0, kend = phi->numOperands(); k < kend; k++) {
    1.49 +                if (!info.inputs.append(*phi->getOperand(k)))
    1.50 +                    return false;
    1.51 +            }
    1.52 +        }
    1.53 +
    1.54 +        for (LInstructionIterator iter = block->begin(); iter != block->end(); iter++) {
    1.55 +            LInstruction *ins = *iter;
    1.56 +            InstructionInfo &info = instructions[ins->id()];
    1.57 +
    1.58 +            for (size_t k = 0; k < ins->numTemps(); k++) {
    1.59 +                uint32_t vreg = ins->getTemp(k)->virtualRegister();
    1.60 +                virtualRegisters[vreg] = ins->getTemp(k);
    1.61 +                if (!info.temps.append(*ins->getTemp(k)))
    1.62 +                    return false;
    1.63 +            }
    1.64 +            for (size_t k = 0; k < ins->numDefs(); k++) {
    1.65 +                uint32_t vreg = ins->getDef(k)->virtualRegister();
    1.66 +                virtualRegisters[vreg] = ins->getDef(k);
    1.67 +                if (!info.outputs.append(*ins->getDef(k)))
    1.68 +                    return false;
    1.69 +            }
    1.70 +            for (LInstruction::InputIterator alloc(*ins); alloc.more(); alloc.next()) {
    1.71 +                if (!info.inputs.append(**alloc))
    1.72 +                    return false;
    1.73 +            }
    1.74 +        }
    1.75 +    }
    1.76 +
    1.77 +    return seen.init();
    1.78 +}
    1.79 +
    1.80 +bool
    1.81 +AllocationIntegrityState::check(bool populateSafepoints)
    1.82 +{
    1.83 +    JS_ASSERT(!instructions.empty());
    1.84 +
    1.85 +#ifdef DEBUG
    1.86 +    if (IonSpewEnabled(IonSpew_RegAlloc))
    1.87 +        dump();
    1.88 +
    1.89 +    for (size_t blockIndex = 0; blockIndex < graph.numBlocks(); blockIndex++) {
    1.90 +        LBlock *block = graph.getBlock(blockIndex);
    1.91 +
    1.92 +        // Check that all instruction inputs and outputs have been assigned an allocation.
    1.93 +        for (LInstructionIterator iter = block->begin(); iter != block->end(); iter++) {
    1.94 +            LInstruction *ins = *iter;
    1.95 +
    1.96 +            for (LInstruction::InputIterator alloc(*ins); alloc.more(); alloc.next())
    1.97 +                JS_ASSERT(!alloc->isUse());
    1.98 +
    1.99 +            for (size_t i = 0; i < ins->numDefs(); i++) {
   1.100 +                LDefinition *def = ins->getDef(i);
   1.101 +                JS_ASSERT_IF(def->policy() != LDefinition::PASSTHROUGH, !def->output()->isUse());
   1.102 +
   1.103 +                LDefinition oldDef = instructions[ins->id()].outputs[i];
   1.104 +                JS_ASSERT_IF(oldDef.policy() == LDefinition::MUST_REUSE_INPUT,
   1.105 +                             *def->output() == *ins->getOperand(oldDef.getReusedInput()));
   1.106 +            }
   1.107 +
   1.108 +            for (size_t i = 0; i < ins->numTemps(); i++) {
   1.109 +                LDefinition *temp = ins->getTemp(i);
   1.110 +                JS_ASSERT_IF(!temp->isBogusTemp(), temp->output()->isRegister());
   1.111 +
   1.112 +                LDefinition oldTemp = instructions[ins->id()].temps[i];
   1.113 +                JS_ASSERT_IF(oldTemp.policy() == LDefinition::MUST_REUSE_INPUT,
   1.114 +                             *temp->output() == *ins->getOperand(oldTemp.getReusedInput()));
   1.115 +            }
   1.116 +        }
   1.117 +    }
   1.118 +#endif
   1.119 +
   1.120 +    // Check that the register assignment and move groups preserve the original
   1.121 +    // semantics of the virtual registers. Each virtual register has a single
   1.122 +    // write (owing to the SSA representation), but the allocation may move the
   1.123 +    // written value around between registers and memory locations along
   1.124 +    // different paths through the script.
   1.125 +    //
   1.126 +    // For each use of an allocation, follow the physical value which is read
   1.127 +    // backward through the script, along all paths to the value's virtual
   1.128 +    // register's definition.
   1.129 +    for (size_t blockIndex = 0; blockIndex < graph.numBlocks(); blockIndex++) {
   1.130 +        LBlock *block = graph.getBlock(blockIndex);
   1.131 +        for (LInstructionIterator iter = block->begin(); iter != block->end(); iter++) {
   1.132 +            LInstruction *ins = *iter;
   1.133 +            const InstructionInfo &info = instructions[ins->id()];
   1.134 +
   1.135 +            LSafepoint *safepoint = ins->safepoint();
   1.136 +            if (safepoint) {
   1.137 +                for (size_t i = 0; i < ins->numTemps(); i++) {
   1.138 +                    uint32_t vreg = info.temps[i].virtualRegister();
   1.139 +                    LAllocation *alloc = ins->getTemp(i)->output();
   1.140 +                    if (!checkSafepointAllocation(ins, vreg, *alloc, populateSafepoints))
   1.141 +                        return false;
   1.142 +                }
   1.143 +                JS_ASSERT_IF(ins->isCall() && !populateSafepoints,
   1.144 +                             safepoint->liveRegs().empty(true) &&
   1.145 +                             safepoint->liveRegs().empty(false));
   1.146 +            }
   1.147 +
   1.148 +            size_t inputIndex = 0;
   1.149 +            for (LInstruction::InputIterator alloc(*ins); alloc.more(); alloc.next()) {
   1.150 +                LAllocation oldInput = info.inputs[inputIndex++];
   1.151 +                if (!oldInput.isUse())
   1.152 +                    continue;
   1.153 +
   1.154 +                uint32_t vreg = oldInput.toUse()->virtualRegister();
   1.155 +
   1.156 +                if (safepoint && !oldInput.toUse()->usedAtStart()) {
   1.157 +                    if (!checkSafepointAllocation(ins, vreg, **alloc, populateSafepoints))
   1.158 +                        return false;
   1.159 +                }
   1.160 +
   1.161 +                // Start checking at the previous instruction, in case this
   1.162 +                // instruction reuses its input register for an output.
   1.163 +                LInstructionReverseIterator riter = block->rbegin(ins);
   1.164 +                riter++;
   1.165 +                checkIntegrity(block, *riter, vreg, **alloc, populateSafepoints);
   1.166 +
   1.167 +                while (!worklist.empty()) {
   1.168 +                    IntegrityItem item = worklist.popCopy();
   1.169 +                    checkIntegrity(item.block, *item.block->rbegin(), item.vreg, item.alloc, populateSafepoints);
   1.170 +                }
   1.171 +            }
   1.172 +        }
   1.173 +    }
   1.174 +
   1.175 +    return true;
   1.176 +}
   1.177 +
   1.178 +bool
   1.179 +AllocationIntegrityState::checkIntegrity(LBlock *block, LInstruction *ins,
   1.180 +                                         uint32_t vreg, LAllocation alloc, bool populateSafepoints)
   1.181 +{
   1.182 +    for (LInstructionReverseIterator iter(block->rbegin(ins)); iter != block->rend(); iter++) {
   1.183 +        ins = *iter;
   1.184 +
   1.185 +        // Follow values through assignments in move groups. All assignments in
   1.186 +        // a move group are considered to happen simultaneously, so stop after
   1.187 +        // the first matching move is found.
   1.188 +        if (ins->isMoveGroup()) {
   1.189 +            LMoveGroup *group = ins->toMoveGroup();
   1.190 +            for (int i = group->numMoves() - 1; i >= 0; i--) {
   1.191 +                if (*group->getMove(i).to() == alloc) {
   1.192 +                    alloc = *group->getMove(i).from();
   1.193 +                    break;
   1.194 +                }
   1.195 +            }
   1.196 +        }
   1.197 +
   1.198 +        const InstructionInfo &info = instructions[ins->id()];
   1.199 +
   1.200 +        // Make sure the physical location being tracked is not clobbered by
   1.201 +        // another instruction, and that if the originating vreg definition is
   1.202 +        // found that it is writing to the tracked location.
   1.203 +
   1.204 +        for (size_t i = 0; i < ins->numDefs(); i++) {
   1.205 +            LDefinition *def = ins->getDef(i);
   1.206 +            if (def->policy() == LDefinition::PASSTHROUGH)
   1.207 +                continue;
   1.208 +            if (info.outputs[i].virtualRegister() == vreg) {
   1.209 +                JS_ASSERT(*def->output() == alloc);
   1.210 +
   1.211 +                // Found the original definition, done scanning.
   1.212 +                return true;
   1.213 +            } else {
   1.214 +                JS_ASSERT(*def->output() != alloc);
   1.215 +            }
   1.216 +        }
   1.217 +
   1.218 +        for (size_t i = 0; i < ins->numTemps(); i++) {
   1.219 +            LDefinition *temp = ins->getTemp(i);
   1.220 +            if (!temp->isBogusTemp())
   1.221 +                JS_ASSERT(*temp->output() != alloc);
   1.222 +        }
   1.223 +
   1.224 +        if (ins->safepoint()) {
   1.225 +            if (!checkSafepointAllocation(ins, vreg, alloc, populateSafepoints))
   1.226 +                return false;
   1.227 +        }
   1.228 +    }
   1.229 +
   1.230 +    // Phis are effectless, but change the vreg we are tracking. Check if there
   1.231 +    // is one which produced this vreg. We need to follow back through the phi
   1.232 +    // inputs as it is not guaranteed the register allocator filled in physical
   1.233 +    // allocations for the inputs and outputs of the phis.
   1.234 +    for (size_t i = 0; i < block->numPhis(); i++) {
   1.235 +        const InstructionInfo &info = blocks[block->mir()->id()].phis[i];
   1.236 +        LPhi *phi = block->getPhi(i);
   1.237 +        if (info.outputs[0].virtualRegister() == vreg) {
   1.238 +            for (size_t j = 0, jend = phi->numOperands(); j < jend; j++) {
   1.239 +                uint32_t newvreg = info.inputs[j].toUse()->virtualRegister();
   1.240 +                LBlock *predecessor = graph.getBlock(block->mir()->getPredecessor(j)->id());
   1.241 +                if (!addPredecessor(predecessor, newvreg, alloc))
   1.242 +                    return false;
   1.243 +            }
   1.244 +            return true;
   1.245 +        }
   1.246 +    }
   1.247 +
   1.248 +    // No phi which defined the vreg we are tracking, follow back through all
   1.249 +    // predecessors with the existing vreg.
   1.250 +    for (size_t i = 0, iend = block->mir()->numPredecessors(); i < iend; i++) {
   1.251 +        LBlock *predecessor = graph.getBlock(block->mir()->getPredecessor(i)->id());
   1.252 +        if (!addPredecessor(predecessor, vreg, alloc))
   1.253 +            return false;
   1.254 +    }
   1.255 +
   1.256 +    return true;
   1.257 +}
   1.258 +
   1.259 +bool
   1.260 +AllocationIntegrityState::checkSafepointAllocation(LInstruction *ins,
   1.261 +                                                   uint32_t vreg, LAllocation alloc,
   1.262 +                                                   bool populateSafepoints)
   1.263 +{
   1.264 +    LSafepoint *safepoint = ins->safepoint();
   1.265 +    JS_ASSERT(safepoint);
   1.266 +
   1.267 +    if (ins->isCall() && alloc.isRegister())
   1.268 +        return true;
   1.269 +
   1.270 +    if (alloc.isRegister()) {
   1.271 +        AnyRegister reg = alloc.toRegister();
   1.272 +        if (populateSafepoints)
   1.273 +            safepoint->addLiveRegister(reg);
   1.274 +        JS_ASSERT(safepoint->liveRegs().has(reg));
   1.275 +    }
   1.276 +
   1.277 +    LDefinition::Type type = virtualRegisters[vreg]
   1.278 +                             ? virtualRegisters[vreg]->type()
   1.279 +                             : LDefinition::GENERAL;
   1.280 +
   1.281 +    switch (type) {
   1.282 +      case LDefinition::OBJECT:
   1.283 +        if (populateSafepoints) {
   1.284 +            IonSpew(IonSpew_RegAlloc, "Safepoint object v%u i%u %s",
   1.285 +                    vreg, ins->id(), alloc.toString());
   1.286 +            if (!safepoint->addGcPointer(alloc))
   1.287 +                return false;
   1.288 +        }
   1.289 +        JS_ASSERT(safepoint->hasGcPointer(alloc));
   1.290 +        break;
   1.291 +      case LDefinition::SLOTS:
   1.292 +        if (populateSafepoints) {
   1.293 +            IonSpew(IonSpew_RegAlloc, "Safepoint slots v%u i%u %s",
   1.294 +                    vreg, ins->id(), alloc.toString());
   1.295 +            if (!safepoint->addSlotsOrElementsPointer(alloc))
   1.296 +                return false;
   1.297 +        }
   1.298 +        JS_ASSERT(safepoint->hasSlotsOrElementsPointer(alloc));
   1.299 +        break;
   1.300 +#ifdef JS_NUNBOX32
   1.301 +      // Do not assert that safepoint information for nunbox types is complete,
   1.302 +      // as if a vreg for a value's components are copied in multiple places
   1.303 +      // then the safepoint information may not reflect all copies. All copies
   1.304 +      // of payloads must be reflected, however, for generational GC.
   1.305 +      case LDefinition::TYPE:
   1.306 +        if (populateSafepoints) {
   1.307 +            IonSpew(IonSpew_RegAlloc, "Safepoint type v%u i%u %s",
   1.308 +                    vreg, ins->id(), alloc.toString());
   1.309 +            if (!safepoint->addNunboxType(vreg, alloc))
   1.310 +                return false;
   1.311 +        }
   1.312 +        break;
   1.313 +      case LDefinition::PAYLOAD:
   1.314 +        if (populateSafepoints) {
   1.315 +            IonSpew(IonSpew_RegAlloc, "Safepoint payload v%u i%u %s",
   1.316 +                    vreg, ins->id(), alloc.toString());
   1.317 +            if (!safepoint->addNunboxPayload(vreg, alloc))
   1.318 +                return false;
   1.319 +        }
   1.320 +        JS_ASSERT(safepoint->hasNunboxPayload(alloc));
   1.321 +        break;
   1.322 +#else
   1.323 +      case LDefinition::BOX:
   1.324 +        if (populateSafepoints) {
   1.325 +            IonSpew(IonSpew_RegAlloc, "Safepoint boxed value v%u i%u %s",
   1.326 +                    vreg, ins->id(), alloc.toString());
   1.327 +            if (!safepoint->addBoxedValue(alloc))
   1.328 +                return false;
   1.329 +        }
   1.330 +        JS_ASSERT(safepoint->hasBoxedValue(alloc));
   1.331 +        break;
   1.332 +#endif
   1.333 +      default:
   1.334 +        break;
   1.335 +    }
   1.336 +
   1.337 +    return true;
   1.338 +}
   1.339 +
   1.340 +bool
   1.341 +AllocationIntegrityState::addPredecessor(LBlock *block, uint32_t vreg, LAllocation alloc)
   1.342 +{
   1.343 +    // There is no need to reanalyze if we have already seen this predecessor.
   1.344 +    // We share the seen allocations across analysis of each use, as there will
   1.345 +    // likely be common ground between different uses of the same vreg.
   1.346 +    IntegrityItem item;
   1.347 +    item.block = block;
   1.348 +    item.vreg = vreg;
   1.349 +    item.alloc = alloc;
   1.350 +    item.index = seen.count();
   1.351 +
   1.352 +    IntegrityItemSet::AddPtr p = seen.lookupForAdd(item);
   1.353 +    if (p)
   1.354 +        return true;
   1.355 +    if (!seen.add(p, item))
   1.356 +        return false;
   1.357 +
   1.358 +    return worklist.append(item);
   1.359 +}
   1.360 +
   1.361 +void
   1.362 +AllocationIntegrityState::dump()
   1.363 +{
   1.364 +#ifdef DEBUG
   1.365 +    fprintf(stderr, "Register Allocation:\n");
   1.366 +
   1.367 +    for (size_t blockIndex = 0; blockIndex < graph.numBlocks(); blockIndex++) {
   1.368 +        LBlock *block = graph.getBlock(blockIndex);
   1.369 +        MBasicBlock *mir = block->mir();
   1.370 +
   1.371 +        fprintf(stderr, "\nBlock %lu", static_cast<unsigned long>(blockIndex));
   1.372 +        for (size_t i = 0; i < mir->numSuccessors(); i++)
   1.373 +            fprintf(stderr, " [successor %u]", mir->getSuccessor(i)->id());
   1.374 +        fprintf(stderr, "\n");
   1.375 +
   1.376 +        for (size_t i = 0; i < block->numPhis(); i++) {
   1.377 +            const InstructionInfo &info = blocks[blockIndex].phis[i];
   1.378 +            LPhi *phi = block->getPhi(i);
   1.379 +            CodePosition output(phi->id(), CodePosition::OUTPUT);
   1.380 +
   1.381 +            // Don't print the inputOf for phi nodes, since it's never used.
   1.382 +            fprintf(stderr, "[,%u Phi [def v%u %s] <-",
   1.383 +                    output.pos(),
   1.384 +                    info.outputs[0].virtualRegister(),
   1.385 +                    phi->getDef(0)->output()->toString());
   1.386 +            for (size_t j = 0; j < phi->numOperands(); j++)
   1.387 +                fprintf(stderr, " %s", info.inputs[j].toString());
   1.388 +            fprintf(stderr, "]\n");
   1.389 +        }
   1.390 +
   1.391 +        for (LInstructionIterator iter = block->begin(); iter != block->end(); iter++) {
   1.392 +            LInstruction *ins = *iter;
   1.393 +            const InstructionInfo &info = instructions[ins->id()];
   1.394 +
   1.395 +            CodePosition input(ins->id(), CodePosition::INPUT);
   1.396 +            CodePosition output(ins->id(), CodePosition::OUTPUT);
   1.397 +
   1.398 +            fprintf(stderr, "[");
   1.399 +            if (input != CodePosition::MIN)
   1.400 +                fprintf(stderr, "%u,%u ", input.pos(), output.pos());
   1.401 +            fprintf(stderr, "%s]", ins->opName());
   1.402 +
   1.403 +            if (ins->isMoveGroup()) {
   1.404 +                LMoveGroup *group = ins->toMoveGroup();
   1.405 +                for (int i = group->numMoves() - 1; i >= 0; i--) {
   1.406 +                    // Use two printfs, as LAllocation::toString is not reentant.
   1.407 +                    fprintf(stderr, " [%s", group->getMove(i).from()->toString());
   1.408 +                    fprintf(stderr, " -> %s]", group->getMove(i).to()->toString());
   1.409 +                }
   1.410 +                fprintf(stderr, "\n");
   1.411 +                continue;
   1.412 +            }
   1.413 +
   1.414 +            for (size_t i = 0; i < ins->numTemps(); i++) {
   1.415 +                LDefinition *temp = ins->getTemp(i);
   1.416 +                if (!temp->isBogusTemp())
   1.417 +                    fprintf(stderr, " [temp v%u %s]", info.temps[i].virtualRegister(),
   1.418 +                           temp->output()->toString());
   1.419 +            }
   1.420 +
   1.421 +            for (size_t i = 0; i < ins->numDefs(); i++) {
   1.422 +                LDefinition *def = ins->getDef(i);
   1.423 +                fprintf(stderr, " [def v%u %s]", info.outputs[i].virtualRegister(),
   1.424 +                       def->output()->toString());
   1.425 +            }
   1.426 +
   1.427 +            size_t index = 0;
   1.428 +            for (LInstruction::InputIterator alloc(*ins); alloc.more(); alloc.next()) {
   1.429 +                fprintf(stderr, " [use %s", info.inputs[index++].toString());
   1.430 +                fprintf(stderr, " %s]", alloc->toString());
   1.431 +            }
   1.432 +
   1.433 +            fprintf(stderr, "\n");
   1.434 +        }
   1.435 +    }
   1.436 +
   1.437 +    fprintf(stderr, "\nIntermediate Allocations:\n\n");
   1.438 +
   1.439 +    // Print discovered allocations at the ends of blocks, in the order they
   1.440 +    // were discovered.
   1.441 +
   1.442 +    Vector<IntegrityItem, 20, SystemAllocPolicy> seenOrdered;
   1.443 +    seenOrdered.appendN(IntegrityItem(), seen.count());
   1.444 +
   1.445 +    for (IntegrityItemSet::Enum iter(seen); !iter.empty(); iter.popFront()) {
   1.446 +        IntegrityItem item = iter.front();
   1.447 +        seenOrdered[item.index] = item;
   1.448 +    }
   1.449 +
   1.450 +    for (size_t i = 0; i < seenOrdered.length(); i++) {
   1.451 +        IntegrityItem item = seenOrdered[i];
   1.452 +        fprintf(stderr, "block %u reg v%u alloc %s\n",
   1.453 +               item.block->mir()->id(), item.vreg, item.alloc.toString());
   1.454 +    }
   1.455 +
   1.456 +    fprintf(stderr, "\n");
   1.457 +#endif
   1.458 +}
   1.459 +
   1.460 +const CodePosition CodePosition::MAX(UINT_MAX);
   1.461 +const CodePosition CodePosition::MIN(0);
   1.462 +
   1.463 +bool
   1.464 +RegisterAllocator::init()
   1.465 +{
   1.466 +    if (!insData.init(mir, graph.numInstructions()))
   1.467 +        return false;
   1.468 +
   1.469 +    for (size_t i = 0; i < graph.numBlocks(); i++) {
   1.470 +        LBlock *block = graph.getBlock(i);
   1.471 +        for (LInstructionIterator ins = block->begin(); ins != block->end(); ins++)
   1.472 +            insData[*ins].init(*ins, block);
   1.473 +        for (size_t j = 0; j < block->numPhis(); j++) {
   1.474 +            LPhi *phi = block->getPhi(j);
   1.475 +            insData[phi].init(phi, block);
   1.476 +        }
   1.477 +    }
   1.478 +
   1.479 +    return true;
   1.480 +}
   1.481 +
   1.482 +LMoveGroup *
   1.483 +RegisterAllocator::getInputMoveGroup(uint32_t ins)
   1.484 +{
   1.485 +    InstructionData *data = &insData[ins];
   1.486 +    JS_ASSERT(!data->ins()->isPhi());
   1.487 +    JS_ASSERT(!data->ins()->isLabel());
   1.488 +
   1.489 +    if (data->inputMoves())
   1.490 +        return data->inputMoves();
   1.491 +
   1.492 +    LMoveGroup *moves = LMoveGroup::New(alloc());
   1.493 +    data->setInputMoves(moves);
   1.494 +    data->block()->insertBefore(data->ins(), moves);
   1.495 +
   1.496 +    return moves;
   1.497 +}
   1.498 +
   1.499 +LMoveGroup *
   1.500 +RegisterAllocator::getMoveGroupAfter(uint32_t ins)
   1.501 +{
   1.502 +    InstructionData *data = &insData[ins];
   1.503 +    JS_ASSERT(!data->ins()->isPhi());
   1.504 +
   1.505 +    if (data->movesAfter())
   1.506 +        return data->movesAfter();
   1.507 +
   1.508 +    LMoveGroup *moves = LMoveGroup::New(alloc());
   1.509 +    data->setMovesAfter(moves);
   1.510 +
   1.511 +    if (data->ins()->isLabel())
   1.512 +        data->block()->insertAfter(data->block()->getEntryMoveGroup(alloc()), moves);
   1.513 +    else
   1.514 +        data->block()->insertAfter(data->ins(), moves);
   1.515 +    return moves;
   1.516 +}

mercurial