/* Write the numbers in the literal pool to the codegen stream */
static void installDataContent(CompilationUnit *cUnit)
{
    int *dataPtr = (int *) ((char *) cUnit->baseAddr + cUnit->dataOffset);
    ArmLIR *dataLIR = (ArmLIR *) cUnit->wordList;
    while (dataLIR) {
        *dataPtr++ = dataLIR->operands[0];
        dataLIR = NEXT_LIR(dataLIR);
    }
}
/*
 * Identify unconditional branches that jump to the immediate successor of the
 * branch itself.
 */
static void applyRedundantBranchElimination(CompilationUnit *cUnit)
{
    ArmLIR *thisLIR;

    for (thisLIR = (ArmLIR *) cUnit->firstLIRInsn;
         thisLIR != (ArmLIR *) cUnit->lastLIRInsn;
         thisLIR = NEXT_LIR(thisLIR)) {

        /* Branch to the next instruction */
        if (thisLIR->opcode == kThumbBUncond) {
            ArmLIR *nextLIR = thisLIR;

            while (true) {
                nextLIR = NEXT_LIR(nextLIR);

                /*
                 * Is the branch target the next instruction?
                 */
                if (nextLIR == (ArmLIR *) thisLIR->generic.target) {
                    thisLIR->flags.isNop = true;
                    break;
                }

                /*
                 * Found real useful stuff between the branch and the target.
                 * Need to explicitly check the lastLIRInsn here since with
                 * method-based JIT the branch might be the last real
                 * instruction.
                 */
                if (!isPseudoOpcode(nextLIR->opcode) ||
                    (nextLIR == (ArmLIR *) cUnit->lastLIRInsn))
                    break;
            }
        }
    }
}
/* Return TRUE if error happens */
static bool assembleInstructions(CompilationUnit *cUnit, intptr_t startAddr)
{
    short *bufferAddr = (short *) cUnit->codeBuffer;
    ArmLIR *lir;

    for (lir = (ArmLIR *) cUnit->firstLIRInsn; lir; lir = NEXT_LIR(lir)) {
        if (lir->opCode < 0) {
            if ((lir->opCode == ARM_PSEUDO_ALIGN4) &&
                /* 1 means padding is needed */
                (lir->operands[0] == 1)) {
                *bufferAddr++ = PADDING_MOV_R0_R0;
            }
            continue;
        }

        if (lir->isNop) {
            continue;
        }

        if (lir->opCode == THUMB_LDR_PC_REL ||
            lir->opCode == THUMB_ADD_PC_REL) {
            ArmLIR *lirTarget = (ArmLIR *) lir->generic.target;
            intptr_t pc = (lir->generic.offset + 4) & ~3;
            /*
             * Allow an offset (stored in operands[2] to be added to the
             * PC-relative target. Useful to get to a fixed field inside a
             * chaining cell.
             */
            intptr_t target = lirTarget->generic.offset + lir->operands[2];
            int delta = target - pc;
            if (delta & 0x3) {
                LOGE("PC-rel distance is not multiples of 4: %d\n", delta);
                dvmAbort();
            }
            if (delta > 1023) {
                return true;
            }
            lir->operands[1] = delta >> 2;
        } else if (lir->opCode == THUMB2_CBNZ || lir->opCode == THUMB2_CBZ) {
Exemple #4
0
/*
 * Perform a pass of top-down walk, from the second-last instruction in the
 * superblock, to eliminate redundant loads and stores.
 *
 * An earlier load can eliminate a later load iff
 *   1) They are must-aliases
 *   2) The native register is not clobbered in between
 *   3) The memory location is not written to in between
 *
 * An earlier store can eliminate a later load iff
 *   1) They are must-aliases
 *   2) The native register is not clobbered in between
 *   3) The memory location is not written to in between
 *
 * A later store can be eliminated by an earlier store iff
 *   1) They are must-aliases
 *   2) The memory location is not written to in between
 */
static void applyLoadStoreElimination(CompilationUnit *cUnit,
                                      MipsLIR *headLIR,
                                      MipsLIR *tailLIR)
{
    MipsLIR *thisLIR;

    if (headLIR == tailLIR) return;

    for (thisLIR = PREV_LIR(tailLIR);
         thisLIR != headLIR;
         thisLIR = PREV_LIR(thisLIR)) {
        int sinkDistance = 0;

        /* Skip non-interesting instructions */
        if ((thisLIR->flags.isNop == true) ||
            isPseudoOpCode(thisLIR->opcode) ||
            !(EncodingMap[thisLIR->opcode].flags & (IS_LOAD | IS_STORE))) {
            continue;
        }

        int nativeRegId = thisLIR->operands[0];
        bool isThisLIRLoad = EncodingMap[thisLIR->opcode].flags & IS_LOAD;
        MipsLIR *checkLIR;
        /* Use the mem mask to determine the rough memory location */
        u8 thisMemMask = (thisLIR->useMask | thisLIR->defMask) & ENCODE_MEM;

        /*
         * Currently only eliminate redundant ld/st for constant and Dalvik
         * register accesses.
         */
        if (!(thisMemMask & (ENCODE_LITERAL | ENCODE_DALVIK_REG))) continue;

        /*
         * Add r15 (pc) to the resource mask to prevent this instruction
         * from sinking past branch instructions. Also take out the memory
         * region bits since stopMask is used to check data/control
         * dependencies.
         */
        u8 stopUseRegMask = (ENCODE_REG_PC | thisLIR->useMask) &
                            ~ENCODE_MEM;
        u8 stopDefRegMask = thisLIR->defMask & ~ENCODE_MEM;

        for (checkLIR = NEXT_LIR(thisLIR);
             checkLIR != tailLIR;
             checkLIR = NEXT_LIR(checkLIR)) {

            /*
             * Skip already dead instructions (whose dataflow information is
             * outdated and misleading).
             */
            if (checkLIR->flags.isNop) continue;

            u8 checkMemMask = (checkLIR->useMask | checkLIR->defMask) &
                              ENCODE_MEM;
            u8 aliasCondition = thisMemMask & checkMemMask;
            bool stopHere = false;

            /*
             * Potential aliases seen - check the alias relations
             */
            if (checkMemMask != ENCODE_MEM && aliasCondition != 0) {
                bool isCheckLIRLoad = EncodingMap[checkLIR->opcode].flags &
                                      IS_LOAD;
                if  (aliasCondition == ENCODE_LITERAL) {
                    /*
                     * Should only see literal loads in the instruction
                     * stream.
                     */
                    assert(!(EncodingMap[checkLIR->opcode].flags &
                             IS_STORE));
                    /* Same value && same register type */
                    if (checkLIR->aliasInfo == thisLIR->aliasInfo &&
                        REGTYPE(checkLIR->operands[0]) == REGTYPE(nativeRegId)){
                        /*
                         * Different destination register - insert
                         * a move
                         */
                        if (checkLIR->operands[0] != nativeRegId) {
                            convertMemOpIntoMove(cUnit, checkLIR,
                                                 checkLIR->operands[0],
                                                 nativeRegId);
                        }
                        checkLIR->flags.isNop = true;
                    }
                } else if (aliasCondition == ENCODE_DALVIK_REG) {
                    /* Must alias */
                    if (checkLIR->aliasInfo == thisLIR->aliasInfo) {
                        /* Only optimize compatible registers */
                        bool regCompatible =
                            REGTYPE(checkLIR->operands[0]) ==
                            REGTYPE(nativeRegId);
                        if ((isThisLIRLoad && isCheckLIRLoad) ||
                            (!isThisLIRLoad && isCheckLIRLoad)) {
                            /* RAR or RAW */
                            if (regCompatible) {
                                /*
                                 * Different destination register -
                                 * insert a move
                                 */
                                if (checkLIR->operands[0] !=
                                    nativeRegId) {
                                    convertMemOpIntoMove(cUnit,
                                                 checkLIR,
                                                 checkLIR->operands[0],
                                                 nativeRegId);
                                }
                                checkLIR->flags.isNop = true;
                            } else {
                                /*
                                 * Destinaions are of different types -
                                 * something complicated going on so
                                 * stop looking now.
                                 */
                                stopHere = true;
                            }
                        } else if (isThisLIRLoad && !isCheckLIRLoad) {
                            /* WAR - register value is killed */
                            stopHere = true;
                        } else if (!isThisLIRLoad && !isCheckLIRLoad) {
                            /* WAW - nuke the earlier store */
                            thisLIR->flags.isNop = true;
                            stopHere = true;
                        }
                    /* Partial overlap */
                    } else if (isDalvikRegisterClobbered(thisLIR, checkLIR)) {
                        /*
                         * It is actually ok to continue if checkLIR
                         * is a read. But it is hard to make a test
                         * case for this so we just stop here to be
                         * conservative.
                         */
                        stopHere = true;
                    }
                }
                /* Memory content may be updated. Stop looking now. */
                if (stopHere) {
                    break;
                /* The checkLIR has been transformed - check the next one */
                } else if (checkLIR->flags.isNop) {
                    continue;
                }
            }


            /*
             * this and check LIRs have no memory dependency. Now check if
             * their register operands have any RAW, WAR, and WAW
             * dependencies. If so, stop looking.
             */
            if (stopHere == false) {
                stopHere = CHECK_REG_DEP(stopUseRegMask, stopDefRegMask,
                                         checkLIR);
            }

            if (stopHere == true) {
                DEBUG_OPT(dumpDependentInsnPair(thisLIR, checkLIR,
                                                "REG CLOBBERED"));
                /* Only sink store instructions */
                if (sinkDistance && !isThisLIRLoad) {
                    MipsLIR *newStoreLIR =
                        (MipsLIR *) dvmCompilerNew(sizeof(MipsLIR), true);
                    *newStoreLIR = *thisLIR;
                    /*
                     * Stop point found - insert *before* the checkLIR
                     * since the instruction list is scanned in the
                     * top-down order.
                     */
                    dvmCompilerInsertLIRBefore((LIR *) checkLIR,
                                               (LIR *) newStoreLIR);
                    thisLIR->flags.isNop = true;
                }
                break;
            } else if (!checkLIR->flags.isNop) {
                sinkDistance++;
            }
        }
    }
}
Exemple #5
0
/*
 * Perform a pass of bottom-up walk, from the second instruction in the
 * superblock, to try to hoist loads to earlier slots.
 */
static void applyLoadHoisting(CompilationUnit *cUnit,
                              MipsLIR *headLIR,
                              MipsLIR *tailLIR)
{
    MipsLIR *thisLIR, *checkLIR;
    /*
     * Store the list of independent instructions that can be hoisted past.
     * Will decide the best place to insert later.
     */
    MipsLIR *prevInstList[MAX_HOIST_DISTANCE];

    /* Empty block */
    if (headLIR == tailLIR) return;

    /* Start from the second instruction */
    for (thisLIR = NEXT_LIR(headLIR);
         thisLIR != tailLIR;
         thisLIR = NEXT_LIR(thisLIR)) {

        /* Skip non-interesting instructions */
        if ((thisLIR->flags.isNop == true) ||
            isPseudoOpCode(thisLIR->opcode) ||
            !(EncodingMap[thisLIR->opcode].flags & IS_LOAD)) {
            continue;
        }

        u8 stopUseAllMask = thisLIR->useMask;

        /*
         * Branches for null/range checks are marked with the true resource
         * bits, and loads to Dalvik registers, constant pools, and non-alias
         * locations are safe to be hoisted. So only mark the heap references
         * conservatively here.
         */
        if (stopUseAllMask & ENCODE_HEAP_REF) {
            stopUseAllMask |= ENCODE_REG_PC;
        }

        /* Similar as above, but just check for pure register dependency */
        u8 stopUseRegMask = stopUseAllMask & ~ENCODE_MEM;
        u8 stopDefRegMask = thisLIR->defMask & ~ENCODE_MEM;

        int nextSlot = 0;
        bool stopHere = false;

        /* Try to hoist the load to a good spot */
        for (checkLIR = PREV_LIR(thisLIR);
             checkLIR != headLIR;
             checkLIR = PREV_LIR(checkLIR)) {

            /*
             * Skip already dead instructions (whose dataflow information is
             * outdated and misleading).
             */
            if (checkLIR->flags.isNop) continue;

            u8 checkMemMask = checkLIR->defMask & ENCODE_MEM;
            u8 aliasCondition = stopUseAllMask & checkMemMask;
            stopHere = false;

            /* Potential WAR alias seen - check the exact relation */
            if (checkMemMask != ENCODE_MEM && aliasCondition != 0) {
                /* We can fully disambiguate Dalvik references */
                if (aliasCondition == ENCODE_DALVIK_REG) {
                    /* Must alias or partually overlap */
                    if ((checkLIR->aliasInfo == thisLIR->aliasInfo) ||
                        isDalvikRegisterClobbered(thisLIR, checkLIR)) {
                        stopHere = true;
                    }
                /* Conservatively treat all heap refs as may-alias */
                } else {
                    assert(aliasCondition == ENCODE_HEAP_REF);
                    stopHere = true;
                }
                /* Memory content may be updated. Stop looking now. */
                if (stopHere) {
                    prevInstList[nextSlot++] = checkLIR;
                    break;
                }
            }

            if (stopHere == false) {
                stopHere = CHECK_REG_DEP(stopUseRegMask, stopDefRegMask,
                                         checkLIR);
            }

            /*
             * Store the dependent or non-pseudo/indepedent instruction to the
             * list.
             */
            if (stopHere || !isPseudoOpCode(checkLIR->opcode)) {
                prevInstList[nextSlot++] = checkLIR;
                if (nextSlot == MAX_HOIST_DISTANCE) break;
            }

            /* Found a new place to put the load - move it here */
            if (stopHere == true) {
                DEBUG_OPT(dumpDependentInsnPair(checkLIR, thisLIR
                                                "HOIST STOP"));
                break;
            }
        }

        /*
         * Reached the top - use headLIR as the dependent marker as all labels
         * are barriers.
         */
        if (stopHere == false && nextSlot < MAX_HOIST_DISTANCE) {
            prevInstList[nextSlot++] = headLIR;
        }

        /*
         * At least one independent instruction is found. Scan in the reversed
         * direction to find a beneficial slot.
         */
        if (nextSlot >= 2) {
            int firstSlot = nextSlot - 2;
            int slot;
            MipsLIR *depLIR = prevInstList[nextSlot-1];
            /* If there is ld-ld dependency, wait LDLD_DISTANCE cycles */
            if (!isPseudoOpCode(depLIR->opcode) &&
                (EncodingMap[depLIR->opcode].flags & IS_LOAD)) {
                firstSlot -= LDLD_DISTANCE;
            }
            /*
             * Make sure we check slot >= 0 since firstSlot may be negative
             * when the loop is first entered.
             */
            for (slot = firstSlot; slot >= 0; slot--) {
                MipsLIR *curLIR = prevInstList[slot];
                MipsLIR *prevLIR = prevInstList[slot+1];

                /*
                 * Check the highest instruction.
                 * ENCODE_ALL represents a scheduling barrier.
                 */
                if (prevLIR->defMask == ENCODE_ALL) {
                    /*
                     * If the first instruction is a load, don't hoist anything
                     * above it since it is unlikely to be beneficial.
                     */
                    if (EncodingMap[curLIR->opcode].flags & IS_LOAD) continue;
                    /*
                     * Need to unconditionally break here even if the hoisted
                     * distance is greater than LD_LATENCY (ie more than enough
                     * cycles are inserted to hide the load latency) since theu
                     * subsequent code doesn't expect to compare against a
                     * pseudo opcode (whose opcode value is negative).
                     */
                    break;
                }

                /*
                 * NOTE: now prevLIR is guaranteed to be a non-pseudo
                 * instruction (ie accessing EncodingMap[prevLIR->opcode] is
                 * safe).
                 *
                 * Try to find two instructions with load/use dependency until
                 * the remaining instructions are less than LD_LATENCY.
                 */
                if (((curLIR->useMask & prevLIR->defMask) &&
                     (EncodingMap[prevLIR->opcode].flags & IS_LOAD)) ||
                    (slot < LD_LATENCY)) {
                    break;
                }
            }

            /* Found a slot to hoist to */
            if (slot >= 0) {
                MipsLIR *curLIR = prevInstList[slot];
                MipsLIR *newLoadLIR = (MipsLIR *) dvmCompilerNew(sizeof(MipsLIR),
                                                               true);
                *newLoadLIR = *thisLIR;
                /*
                 * Insertion is guaranteed to succeed since checkLIR
                 * is never the first LIR on the list
                 */
                dvmCompilerInsertLIRBefore((LIR *) curLIR,
                                           (LIR *) newLoadLIR);
                thisLIR->flags.isNop = true;
            }
        }
    }
}
/*
 * Perform a pass of top-down walk to
 * 1) Eliminate redundant loads and stores
 * 2) Sink stores to latest possible slot
 */
static void applyLoadStoreElimination(CompilationUnit *cUnit,
                                      ArmLIR *headLIR,
                                      ArmLIR *tailLIR)
{
    ArmLIR *thisLIR;

    cUnit->optRound++;
    for (thisLIR = headLIR;
         thisLIR != tailLIR;
         thisLIR = NEXT_LIR(thisLIR)) {
        /* Skip newly added instructions */
        if (thisLIR->age >= cUnit->optRound) {
            continue;
        }
        if (isDalvikStore(thisLIR)) {
            int dRegId = DECODE_ALIAS_INFO_REG(thisLIR->aliasInfo);
            int dRegIdHi = dRegId + DECODE_ALIAS_INFO_WIDE(thisLIR->aliasInfo);
            int nativeRegId = thisLIR->operands[0];
            ArmLIR *checkLIR;
            int sinkDistance = 0;
            /*
             * Add r15 (pc) to the mask to prevent this instruction
             * from sinking past branch instructions. Unset the Dalvik register
             * bit when checking with native resource constraints.
             */
            u8 stopMask = (ENCODE_REG_PC | thisLIR->useMask) &
                          ~ENCODE_DALVIK_REG;

            for (checkLIR = NEXT_LIR(thisLIR);
                 checkLIR != tailLIR;
                 checkLIR = NEXT_LIR(checkLIR)) {

                /* Check if a Dalvik register load is redundant */
                if (isDalvikLoad(checkLIR) &&
                    (checkLIR->aliasInfo == thisLIR->aliasInfo) &&
                    (REGTYPE(checkLIR->operands[0]) == REGTYPE(nativeRegId))) {
                    /* Insert a move to replace the load */
                    if (checkLIR->operands[0] != nativeRegId) {
                        ArmLIR *moveLIR;
                        moveLIR = dvmCompilerRegCopyNoInsert(
                                    cUnit, checkLIR->operands[0], nativeRegId);
                        /*
                         * Insert the converted checkLIR instruction after the
                         * the original checkLIR since the optimization is
                         * scannng in the top-down order and the new instruction
                         * will need to be checked.
                         */
                        dvmCompilerInsertLIRAfter((LIR *) checkLIR,
                                                  (LIR *) moveLIR);
                    }
                    checkLIR->isNop = true;
                    continue;

                /*
                 * Found a true output dependency - nuke the previous store.
                 * The register type doesn't matter here.
                 */
                } else if (isDalvikStore(checkLIR) &&
                           (checkLIR->aliasInfo == thisLIR->aliasInfo)) {
                    thisLIR->isNop = true;
                    break;
                /* Find out the latest slot that the store can be sunk into */
                } else {
                    /* Last instruction reached */
                    bool stopHere = (NEXT_LIR(checkLIR) == tailLIR);

                    /* Store data is clobbered */
                    stopHere |= ((stopMask & checkLIR->defMask) != 0);

                    /* Store data partially clobbers the Dalvik register */
                    if (stopHere == false &&
                        ((checkLIR->useMask | checkLIR->defMask) &
                         ENCODE_DALVIK_REG)) {
                        stopHere = isDalvikRegisterClobbered(thisLIR, checkLIR);
                    }

                    /* Found a new place to put the store - move it here */
                    if (stopHere == true) {
                        DEBUG_OPT(dumpDependentInsnPair(thisLIR, checkLIR,
                                                        "SINK STORE"));
                        /* The store can be sunk for at least one cycle */
                        if (sinkDistance != 0) {
                            ArmLIR *newStoreLIR =
                                dvmCompilerNew(sizeof(ArmLIR), true);
                            *newStoreLIR = *thisLIR;
                            newStoreLIR->age = cUnit->optRound;
                            /*
                             * Stop point found - insert *before* the checkLIR
                             * since the instruction list is scanned in the
                             * top-down order.
                             */
                            dvmCompilerInsertLIRBefore((LIR *) checkLIR,
                                                       (LIR *) newStoreLIR);
                            thisLIR->isNop = true;
                        }
                        break;
                    }

                    /*
                     * Saw a real instruction that the store can be sunk after
                     */
                    if (!isPseudoOpCode(checkLIR->opCode)) {
                        sinkDistance++;
                    }
                }
            }
        }
    }
}
static void applyLoadHoisting(CompilationUnit *cUnit,
                              ArmLIR *headLIR,
                              ArmLIR *tailLIR)
{
    ArmLIR *thisLIR;
    /*
     * Don't want to hoist in front of first load following a barrier (or
     * first instruction of the block.
     */
    bool firstLoad = true;
    int maxHoist = dvmCompilerTargetOptHint(kMaxHoistDistance);

    cUnit->optRound++;
    for (thisLIR = headLIR;
         thisLIR != tailLIR;
         thisLIR = NEXT_LIR(thisLIR)) {
        /* Skip newly added instructions */
        if (thisLIR->age >= cUnit->optRound ||
            thisLIR->isNop == true) {
            continue;
        }

        if (firstLoad && (EncodingMap[thisLIR->opCode].flags & IS_LOAD)) {
            /*
             * Ensure nothing will be hoisted in front of this load because
             * it's result will likely be needed soon.
             */
            thisLIR->defMask |= ENCODE_MEM_USE;
            firstLoad = false;
        }

        firstLoad |= (thisLIR->defMask == ENCODE_ALL);

        if (isDalvikLoad(thisLIR)) {
            int dRegId = DECODE_ALIAS_INFO_REG(thisLIR->aliasInfo);
            int dRegIdHi = dRegId + DECODE_ALIAS_INFO_WIDE(thisLIR->aliasInfo);
            int nativeRegId = thisLIR->operands[0];
            ArmLIR *checkLIR;
            int hoistDistance = 0;
            u8 stopUseMask = (ENCODE_REG_PC | thisLIR->useMask);
            u8 stopDefMask = thisLIR->defMask;
            u8 checkResult;

            /* First check if the load can be completely elinimated */
            for (checkLIR = PREV_LIR(thisLIR);
                 checkLIR != headLIR;
                 checkLIR = PREV_LIR(checkLIR)) {

                if (checkLIR->isNop) continue;

                /*
                 * Check if the Dalvik register is previously accessed
                 * with exactly the same type.
                 */
                if ((isDalvikLoad(checkLIR) || isDalvikStore(checkLIR)) &&
                    (checkLIR->aliasInfo == thisLIR->aliasInfo) &&
                    (checkLIR->operands[0] == nativeRegId)) {
                    /*
                     * If it is previously accessed but with a different type,
                     * the search will terminate later at the point checking
                     * for partially overlapping stores.
                     */
                    thisLIR->isNop = true;
                    break;
                }

                /*
                 * No earlier use/def can reach this load if:
                 * 1) Head instruction is reached
                 */
                if (checkLIR == headLIR) {
                    break;
                }

                checkResult = (stopUseMask | stopDefMask) & checkLIR->defMask;

                /*
                 * If both instructions are verified Dalvik accesses, clear the
                 * may- and must-alias bits to detect true resource
                 * dependencies.
                 */
                if (checkResult & ENCODE_DALVIK_REG) {
                    checkResult &= ~(ENCODE_DALVIK_REG | ENCODE_FRAME_REF);
                }

                /*
                 * 2) load target register is clobbered
                 * 3) A branch is seen (stopUseMask has the PC bit set).
                 */
                if (checkResult) {
                    break;
                }

                /* Store data partially clobbers the Dalvik register */
                if (isDalvikStore(checkLIR) &&
                    isDalvikRegisterClobbered(thisLIR, checkLIR)) {
                    break;
                }
            }

            /* The load has been eliminated */
            if (thisLIR->isNop) continue;

            /*
             * The load cannot be eliminated. See if it can be hoisted to an
             * earlier spot.
             */
            for (checkLIR = PREV_LIR(thisLIR);
                 /* empty by intention */;
                 checkLIR = PREV_LIR(checkLIR)) {

                if (checkLIR->isNop) continue;

                /*
                 * Check if the "thisLIR" load is redundant
                 * NOTE: At one point, we also triggered if the checkLIR
                 * instruction was a load.  However, that tended to insert
                 * a load/use dependency because the full scheduler is
                 * not yet complete.  When it is, we chould also trigger
                 * on loads.
                 */
                if (isDalvikStore(checkLIR) &&
                    (checkLIR->aliasInfo == thisLIR->aliasInfo) &&
                    (REGTYPE(checkLIR->operands[0]) == REGTYPE(nativeRegId))) {
                    /* Insert a move to replace the load */
                    if (checkLIR->operands[0] != nativeRegId) {
                        ArmLIR *moveLIR;
                        moveLIR = dvmCompilerRegCopyNoInsert(
                                    cUnit, nativeRegId, checkLIR->operands[0]);
                        /*
                         * Convert *thisLIR* load into a move
                         */
                        dvmCompilerInsertLIRAfter((LIR *) checkLIR,
                                                  (LIR *) moveLIR);
                    }
                    thisLIR->isNop = true;
                    break;

                /* Find out if the load can be yanked past the checkLIR */
                } else {
                    /* Last instruction reached */
                    bool stopHere = (checkLIR == headLIR);

                    /* Base address is clobbered by checkLIR */
                    checkResult = stopUseMask & checkLIR->defMask;
                    if (checkResult & ENCODE_DALVIK_REG) {
                        checkResult &= ~(ENCODE_DALVIK_REG | ENCODE_FRAME_REF);
                    }
                    stopHere |= (checkResult != 0);

                    /* Load target clobbers use/def in checkLIR */
                    checkResult = stopDefMask &
                                  (checkLIR->useMask | checkLIR->defMask);
                    if (checkResult & ENCODE_DALVIK_REG) {
                        checkResult &= ~(ENCODE_DALVIK_REG | ENCODE_FRAME_REF);
                    }
                    stopHere |= (checkResult != 0);

                    /* Store data partially clobbers the Dalvik register */
                    if (stopHere == false &&
                        (checkLIR->defMask & ENCODE_DALVIK_REG)) {
                        stopHere = isDalvikRegisterClobbered(thisLIR, checkLIR);
                    }

                    /*
                     * Stop at an earlier Dalvik load if the offset of checkLIR
                     * is not less than thisLIR
                     *
                     * Experiments show that doing
                     *
                     * ldr     r1, [r5, #16]
                     * ldr     r0, [r5, #20]
                     *
                     * is much faster than
                     *
                     * ldr     r0, [r5, #20]
                     * ldr     r1, [r5, #16]
                     */
                    if (isDalvikLoad(checkLIR)) {
                        int dRegId2 =
                            DECODE_ALIAS_INFO_REG(checkLIR->aliasInfo);
                        if (dRegId2 <= dRegId) {
                            stopHere = true;
                        }
                    }

                    /* Don't go too far */
                    stopHere |= (hoistDistance >= maxHoist);

                    /* Found a new place to put the load - move it here */
                    if (stopHere == true) {
                        DEBUG_OPT(dumpDependentInsnPair(thisLIR, checkLIR,
                                                        "HOIST LOAD"));
                        /* The load can be hoisted for at least one cycle */
                        if (hoistDistance != 0) {
                            ArmLIR *newLoadLIR =
                                dvmCompilerNew(sizeof(ArmLIR), true);
                            *newLoadLIR = *thisLIR;
                            newLoadLIR->age = cUnit->optRound;
                            /*
                             * Stop point found - insert *after* the checkLIR
                             * since the instruction list is scanned in the
                             * bottom-up order.
                             */
                            dvmCompilerInsertLIRAfter((LIR *) checkLIR,
                                                      (LIR *) newLoadLIR);
                            thisLIR->isNop = true;
                        }
                        break;
                    }

                    /*
                     * Saw a real instruction that hosting the load is
                     * beneficial
                     */
                    if (!isPseudoOpCode(checkLIR->opCode)) {
                        hoistDistance++;
                    }
                }
            }
        } else if (isLiteralLoad(thisLIR)) {
            int litVal = thisLIR->aliasInfo;
            int nativeRegId = thisLIR->operands[0];
            ArmLIR *checkLIR;
            int hoistDistance = 0;
            u8 stopUseMask = (ENCODE_REG_PC | thisLIR->useMask) &
                             ~ENCODE_LITPOOL_REF;
            u8 stopDefMask = thisLIR->defMask & ~ENCODE_LITPOOL_REF;

            /* First check if the load can be completely elinimated */
            for (checkLIR = PREV_LIR(thisLIR);
                 checkLIR != headLIR;
                 checkLIR = PREV_LIR(checkLIR)) {

                if (checkLIR->isNop) continue;

                /* Reloading same literal into same tgt reg? Eliminate if so */
                if (isLiteralLoad(checkLIR) &&
                    (checkLIR->aliasInfo == litVal) &&
                    (checkLIR->operands[0] == nativeRegId)) {
                    thisLIR->isNop = true;
                    break;
                }

                /*
                 * No earlier use/def can reach this load if:
                 * 1) Head instruction is reached
                 * 2) load target register is clobbered
                 * 3) A branch is seen (stopUseMask has the PC bit set).
                 */
                if ((checkLIR == headLIR) ||
                    (stopUseMask | stopDefMask) & checkLIR->defMask) {
                    break;
                }
            }

            /* The load has been eliminated */
            if (thisLIR->isNop) continue;

            /*
             * The load cannot be eliminated. See if it can be hoisted to an
             * earlier spot.
             */
            for (checkLIR = PREV_LIR(thisLIR);
                 /* empty by intention */;
                 checkLIR = PREV_LIR(checkLIR)) {

                if (checkLIR->isNop) continue;

                /*
                 * TUNING: once a full scheduler exists, check here
                 * for conversion of a redundant load into a copy similar
                 * to the way redundant loads are handled above.
                 */

                /* Find out if the load can be yanked past the checkLIR */

                /* Last instruction reached */
                bool stopHere = (checkLIR == headLIR);

                /* Base address is clobbered by checkLIR */
                stopHere |= ((stopUseMask & checkLIR->defMask) != 0);

                /* Load target clobbers use/def in checkLIR */
                stopHere |= ((stopDefMask &
                             (checkLIR->useMask | checkLIR->defMask)) != 0);

                /* Avoid re-ordering literal pool loads */
                stopHere |= isLiteralLoad(checkLIR);

                /* Don't go too far */
                stopHere |= (hoistDistance >= maxHoist);

                /* Found a new place to put the load - move it here */
                if (stopHere == true) {
                    DEBUG_OPT(dumpDependentInsnPair(thisLIR, checkLIR,
                                                    "HOIST LOAD"));
                    /* The store can be hoisted for at least one cycle */
                    if (hoistDistance != 0) {
                        ArmLIR *newLoadLIR =
                            dvmCompilerNew(sizeof(ArmLIR), true);
                        *newLoadLIR = *thisLIR;
                        newLoadLIR->age = cUnit->optRound;
                        /*
                         * Insertion is guaranteed to succeed since checkLIR
                         * is never the first LIR on the list
                         */
                        dvmCompilerInsertLIRAfter((LIR *) checkLIR,
                                                  (LIR *) newLoadLIR);
                        thisLIR->isNop = true;
                    }
                    break;
                }

                /*
                 * Saw a real instruction that hosting the load is
                 * beneficial
                 */
                if (!isPseudoOpCode(checkLIR->opCode)) {
                    hoistDistance++;
                }
            }
        }
    }
}
/*
 * Find all lsl/lsr and add that can be replaced with a
 * combined lsl/lsr + add
 */
static void applyShiftArithmeticOpts(CompilationUnit *cUnit,
                                     ArmLIR *headLIR,
                                     ArmLIR *tailLIR) {
    ArmLIR *thisLIR = NULL;

    for (thisLIR = headLIR;
         thisLIR != tailLIR;
         thisLIR = NEXT_LIR(thisLIR)) {

        if(thisLIR->flags.isNop) {
            continue;
        }

        if(thisLIR->opcode == kThumb2LslRRI5 || thisLIR->opcode == kThumb2LsrRRI5 ||
           thisLIR->opcode == kThumbLslRRI5 || thisLIR->opcode == kThumbLsrRRI5) {

            /* Find next that is not nop and not pseudo code */
            ArmLIR *nextLIR = NULL;
            for(nextLIR = NEXT_LIR(thisLIR);
                nextLIR != tailLIR;
                nextLIR = NEXT_LIR(nextLIR)) {
                if (!nextLIR->flags.isNop && !isPseudoOpcode(nextLIR->opcode)) {
                    break;
                }
            }

            if(nextLIR == tailLIR) {
                return;
            }

            if(nextLIR->opcode == kThumb2AddRRR &&
               nextLIR->operands[3] == 0 &&
               (nextLIR->operands[1] == thisLIR->operands[0] ||
                nextLIR->operands[2] == thisLIR->operands[0])) {

                bool applyOpt = true;
                if(!(thisLIR->operands[0] == nextLIR->operands[0])) {
                    /* Check that shift dest reg is not used after
                     * the addition. */
                    ArmLIR* tmpLIR = NULL;
                    for(tmpLIR = NEXT_LIR(nextLIR);
                        tmpLIR != tailLIR;
                        tmpLIR = NEXT_LIR(tmpLIR)) {

                        if (!tmpLIR->flags.isNop &&
                            !(EncodingMap[tmpLIR->opcode].flags & IS_BRANCH) &&
                            (tmpLIR->defMask | tmpLIR->useMask) & thisLIR->defMask) {
                            if(tmpLIR->useMask & thisLIR->defMask) {
                                /* Shift dest reg is used for src, skip opt. */
                                applyOpt = false;
                            }
                            break;
                        }
                    }
                }

                if(applyOpt) {

                    /*
                     *  Found lsl/lsr & add, use barrel shifter for add instead
                     *
                     *   (1) Normal case
                     *   [lsl/lsr] r9, r1, #x
                     *   [add]     r0, r2, r9
                     *
                     *   (2) Changing place of args for add
                     *   [lsl/lsr] r9, r1, #x
                     *   [add]     r0, r9, r2
                     *
                     *   (3) Using r1 and r1 shifted as args for add
                     *   [lsl/lsr] r9, r1, #x
                     *   [add]     r0, r1, r9
                     *
                     *   (4) Using r1 and r1 shifted as args for add, variant 2
                     *   [lsl/lsr] r9, r1, #x
                     *   [add]     r0, r9, r1
                     *
                     *   Result:
                     *   [add]     rDest, rSrc1, rSrc2, [lsl/lsr] x
                     */

                    int type = kArmLsl;
                    if(thisLIR->opcode == kThumb2LsrRRI5 || thisLIR->opcode == kThumbLsrRRI5) {
                        type = kArmLsr;
                    }

                    /* For most cases keep original rSrc1 */
                    int rSrc1 = nextLIR->operands[1];

                    if(thisLIR->operands[0] == nextLIR->operands[1]) {
                        /* Case 2 & 4: move original rSrc2 to rScr1 since
                           reg to be shifted need to be in rSrc2 */
                        rSrc1 = nextLIR->operands[2];
                    }

                    /* Reg to be shifted need to be in rSrc2 */
                    int rSrc2 = thisLIR->operands[1];

                    /* Encode type of shift and amount */
                    int shift = ((thisLIR->operands[2] & 0x1f) << 2) | type;

                    /* Keep rDest, but change rSrc1, rSrc2 and use shift */
                    ArmLIR* newLIR = (ArmLIR *)dvmCompilerNew(sizeof(ArmLIR), true);
                    newLIR->opcode = nextLIR->opcode;
                    newLIR->operands[0] = nextLIR->operands[0];
                    newLIR->operands[1] = rSrc1;
                    newLIR->operands[2] = rSrc2;
                    newLIR->operands[3] = shift;
                    dvmCompilerSetupResourceMasks(newLIR);
                    dvmCompilerInsertLIRBefore((LIR *) nextLIR, (LIR *) newLIR);

                    thisLIR->flags.isNop = true;
                    nextLIR->flags.isNop = true;
                }

                /*
                 * Avoid looping through nops already identified.
                 * Continue directly after the updated instruction
                 * instead.
                 */
                thisLIR = nextLIR;
            }
        }
    }
}
/*
 * Perform a pass to hoist all frame pointer load instructions that
 * are independent, outside the loop.
 */
static void applyLoopLoadHoisting(CompilationUnit *cUnit)
{
    ArmLIR *thisLIR, *labelLIR, *lastLIR, *insertLIR;
    ArmLIR *loadLIR[MAX_LOAD_HOISTS];
    ArmLIR *regLIR[MAX_REGISTER_OPS];
    u8 defLoadMask = 0;
    u8 defMask = 0;
    u8 masterDefMask = ~((1ULL << kRegEnd) - 1);
    bool isValidLoop = false;
    int loadCount = 0;
    int regCount = 0;
    int loadindex;
    int hoistCount = 0;

#ifdef LOOP_LOAD_HOIST_VERBOSE
    ALOGD("GlobalOpts LoopLoadHoisting applied on '%s'", cUnit->method->name);
    cUnit->printMe = true;
#endif

    labelLIR = (ArmLIR *) cUnit->firstLIRInsn;
    lastLIR = (ArmLIR *) cUnit->lastLIRInsn;
    insertLIR = NULL;

    /* Find the insert point */
    while ((labelLIR != lastLIR) &&
           (labelLIR->flags.isNop ||
            (labelLIR->opcode != kArmPseudoNormalBlockLabel))) {
        if ((cUnit->loopAnalysis->branchesAdded) &&
            (labelLIR->opcode == kThumbBUncond) &&
            (insertLIR == NULL) && (!labelLIR->flags.isNop))
            insertLIR = labelLIR;

        labelLIR = NEXT_LIR(labelLIR);
    }

    if (labelLIR->opcode != kArmPseudoNormalBlockLabel) {
#ifdef LOOP_LOAD_HOIST_VERBOSE
        ALOGD("Can't hoist - no loop label found!");
#endif
        return;
    }

    if (insertLIR == NULL) {
        insertLIR = labelLIR;
    }
    else if ((ArmLIR *) insertLIR->generic.target != labelLIR) {
#ifdef LOOP_LOAD_HOIST_VERBOSE
        ALOGD("Can't hoist - branch target does not match!");
#endif
        return;
    }

    /* Search for eligible load instructions to hoist */
    for (thisLIR = labelLIR;
         thisLIR != lastLIR;
         thisLIR = NEXT_LIR(thisLIR)) {
        bool handled = false;
        int flags;

        /* Skip non-interesting instructions */
        if (thisLIR->flags.isNop || isPseudoOpcode(thisLIR->opcode))
            continue;

        flags = EncodingMap[thisLIR->opcode].flags;

        /* If it's a load instruction, check if it's a hoist candidate. */
        if (((flags & IS_LOAD) != 0) &&
            ((thisLIR->useMask & ENCODE_DALVIK_REG) != 0)) {
            if (regCount >= MAX_REGISTER_OPS) {
#ifdef LOOP_LOAD_HOIST_VERBOSE
                ALOGD("Out of register list space!");
#endif
                return;
            }
            regLIR[regCount++] = thisLIR;

            if ((((defLoadMask | defMask) & thisLIR->defMask) == 0) &&
                (loadCount < MAX_LOAD_HOISTS)) {
                defLoadMask |= thisLIR->defMask;
                loadLIR[loadCount++] = thisLIR;
                handled = true;
            } else {
                masterDefMask |= thisLIR->defMask;
            }
        /* If it's a store instruction, check if it matches a previous
           hoistable load instruction. If so, reset the global def-flag to
           indicate that the load is still hoistable. */
        } else if (((flags & IS_STORE) != 0) &&
                   ((thisLIR->defMask & ENCODE_DALVIK_REG) != 0)) {
            if (regCount >= MAX_REGISTER_OPS) {
#ifdef LOOP_LOAD_HOIST_VERBOSE
                ALOGD("Out of register list space!");
#endif
                return;
            }
            regLIR[regCount++] = thisLIR;

            if ((thisLIR->useMask & defLoadMask) != 0) {
                handled = true;
                for (int i = loadCount - 1; i >= 0; i--) {
                    if ((thisLIR->aliasInfo == loadLIR[i]->aliasInfo) &&
                        (thisLIR->operands[0] == loadLIR[i]->operands[0])) {
                        defMask &= ~(loadLIR[i]->defMask);
                        break;
                    }
                }
            }
        /* If it's a branch instruction, check if it's the loop branch.
           If it matches the label, mark it as a valid loop. */
        } else if ((flags & IS_BRANCH) != 0) {
            handled = true;
            if (labelLIR == (ArmLIR *) thisLIR->generic.target) {
                isValidLoop = true;
            } else if ((thisLIR->opcode >= kThumbBlx1) &&
                       (thisLIR->opcode <= kThumbBlxR))
            {
#ifdef LOOP_LOAD_HOIST_VERBOSE
                ALOGD("Trace contains branch to subroutine!");
#endif
                return;
            }
        } else if (thisLIR->opcode == kThumbUndefined) {
            break;
        }

        /* If it's not a 'special' instruction, accumulate into def-flags. */
        if (!handled)
            defMask |= thisLIR->defMask;
    }

    defLoadMask &= ~(defMask | masterDefMask);
    if (!isValidLoop || (defLoadMask == 0)) {
#ifdef LOOP_LOAD_HOIST_VERBOSE
        ALOGD("Loop not valid, or defLoadMask (0x%llx) was zero!", defLoadMask);
#endif
        return;
    }

#ifdef LOOP_LOAD_HOIST_VERBOSE
    ALOGD("Masks: masterDef: 0x%llx, def: 0x%llx, final defLoad: 0x%llx",
          masterDefMask, defMask, defLoadMask);
#endif

    /* Try to hoist the load operations */
    for (loadindex = 0; loadindex < loadCount; loadindex++) {
        thisLIR = loadLIR[loadindex];

        /* Host this load? */
        if ((thisLIR->defMask & defLoadMask) == thisLIR->defMask) {
            int i;
            bool foundAlias = false;
            for (i = 0; i < regCount; i++) {
                if ((thisLIR->aliasInfo == regLIR[i]->aliasInfo) &&
                    (thisLIR->operands[0] != regLIR[i]->operands[0])) {
                    foundAlias = true;
                    for (int k = loadindex; k < loadCount; k++) {
                        if (loadLIR[k] == regLIR[i]) {
                            loadLIR[k]->defMask = -1;
                            break;
                        }
                    }
#ifdef LOOP_LOAD_HOIST_VERBOSE
                    ALOGD("Register alias found between these two load ops:");
                    dvmDumpLIRInsn((LIR*)thisLIR, NULL);
                    dvmDumpLIRInsn((LIR*)regLIR[i], NULL);
#endif
                    break;
                }
            }

            if (!foundAlias) {
#ifdef LOOP_LOAD_HOIST_VERBOSE
                ALOGD("Hoisting this load op:");
                dvmDumpLIRInsn((LIR*)thisLIR, NULL);
#endif
                ArmLIR *newLoadLIR = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR),
                                                               true);
                *newLoadLIR = *thisLIR;
                dvmCompilerInsertLIRBefore((LIR *) insertLIR,
                                           (LIR *) newLoadLIR);
                thisLIR->flags.isNop = true;
                hoistCount++;
            }
        }
    }

    if (cUnit->printMe)
        ALOGD("GlobalOpt LoopLoadHoist hoisted %d load ops.", hoistCount);
}