Home | History | Annotate | Download | only in compiler
      1 /*
      2  * Copyright (C) 2009 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "Dalvik.h"
     18 #include "CompilerInternals.h"
     19 #include "Dataflow.h"
     20 #include "Loop.h"
     21 
     22 #define DEBUG_LOOP(X)
     23 
     24 /*
     25  * Given the current simple natural loops, the phi node placement can be
     26  * determined in the following fashion:
     27  *                    entry (B0)
     28  *              +---v   v
     29  *              |  loop body (B1)
     30  *              |       v
     31  *              |  loop back (B2)
     32  *              +---+   v
     33  *                     exit (B3)
     34  *
     35  *  1) Add live-ins of B1 to B0 as defs
     36  *  2) The intersect of defs(B0)/defs(B1) and defs(B2)/def(B0) are the variables
     37  *     that need PHI nodes in B1.
     38  */
     39 static void handlePhiPlacement(CompilationUnit *cUnit)
     40 {
     41     BasicBlock *entry = cUnit->blockList[0];
     42     BasicBlock *loopBody = cUnit->blockList[1];
     43     BasicBlock *loopBranch = cUnit->blockList[2];
     44     dvmCopyBitVector(entry->dataFlowInfo->defV,
     45                      loopBody->dataFlowInfo->liveInV);
     46 
     47     BitVector *phiV = dvmCompilerAllocBitVector(cUnit->method->registersSize,
     48                                                 false);
     49     dvmIntersectBitVectors(phiV, entry->dataFlowInfo->defV,
     50                            loopBody->dataFlowInfo->defV);
     51     dvmIntersectBitVectors(phiV, entry->dataFlowInfo->defV,
     52                            loopBranch->dataFlowInfo->defV);
     53 
     54     /* Insert the PHI MIRs */
     55     int i;
     56     for (i = 0; i < cUnit->method->registersSize; i++) {
     57         if (!dvmIsBitSet(phiV, i)) {
     58             continue;
     59         }
     60         MIR *phi = dvmCompilerNew(sizeof(MIR), true);
     61         phi->dalvikInsn.opCode = kMirOpPhi;
     62         phi->dalvikInsn.vA = i;
     63         dvmCompilerPrependMIR(loopBody, phi);
     64     }
     65 }
     66 
     67 static void fillPhiNodeContents(CompilationUnit *cUnit)
     68 {
     69     BasicBlock *entry = cUnit->blockList[0];
     70     BasicBlock *loopBody = cUnit->blockList[1];
     71     BasicBlock *loopBranch = cUnit->blockList[2];
     72     MIR *mir;
     73 
     74     for (mir = loopBody->firstMIRInsn; mir; mir = mir->next) {
     75         if (mir->dalvikInsn.opCode != kMirOpPhi) break;
     76         int dalvikReg = mir->dalvikInsn.vA;
     77 
     78         mir->ssaRep->numUses = 2;
     79         mir->ssaRep->uses = dvmCompilerNew(sizeof(int) * 2, false);
     80         mir->ssaRep->uses[0] =
     81             DECODE_REG(entry->dataFlowInfo->dalvikToSSAMap[dalvikReg]);
     82         mir->ssaRep->uses[1] =
     83             DECODE_REG(loopBranch->dataFlowInfo->dalvikToSSAMap[dalvikReg]);
     84     }
     85 
     86 
     87 }
     88 
     89 static void dumpConstants(CompilationUnit *cUnit)
     90 {
     91     int i;
     92     for (i = 0; i < cUnit->numSSARegs; i++) {
     93         if (dvmIsBitSet(cUnit->isConstantV, i)) {
     94             int subNReg = dvmConvertSSARegToDalvik(cUnit, i);
     95             LOGE("s%d(v%d_%d) has %d", i,
     96                  DECODE_REG(subNReg), DECODE_SUB(subNReg),
     97                  cUnit->constantValues[i]);
     98         }
     99     }
    100 }
    101 
    102 static void dumpIVList(CompilationUnit *cUnit)
    103 {
    104     unsigned int i;
    105     GrowableList *ivList = cUnit->loopAnalysis->ivList;
    106     int *ssaToDalvikMap = (int *) cUnit->ssaToDalvikMap->elemList;
    107 
    108     for (i = 0; i < ivList->numUsed; i++) {
    109         InductionVariableInfo *ivInfo = ivList->elemList[i];
    110         /* Basic IV */
    111         if (ivInfo->ssaReg == ivInfo->basicSSAReg) {
    112             LOGE("BIV %d: s%d(v%d) + %d", i,
    113                  ivInfo->ssaReg,
    114                  ssaToDalvikMap[ivInfo->ssaReg] & 0xffff,
    115                  ivInfo->inc);
    116         /* Dependent IV */
    117         } else {
    118             LOGE("DIV %d: s%d(v%d) = %d * s%d(v%d) + %d", i,
    119                  ivInfo->ssaReg,
    120                  ssaToDalvikMap[ivInfo->ssaReg] & 0xffff,
    121                  ivInfo->m,
    122                  ivInfo->basicSSAReg,
    123                  ssaToDalvikMap[ivInfo->basicSSAReg] & 0xffff,
    124                  ivInfo->c);
    125         }
    126     }
    127 }
    128 
    129 /*
    130  * A loop is considered optimizable if:
    131  * 1) It has one basic induction variable
    132  * 2) The loop back branch compares the BIV with a constant
    133  * 3) If it is a count-up loop, the condition is GE/GT, or LE/LT/LEZ/LTZ for
    134  *    a count-down loop.
    135  */
    136 static bool isLoopOptimizable(CompilationUnit *cUnit)
    137 {
    138     unsigned int i;
    139     BasicBlock *loopBranch = cUnit->blockList[2];
    140     LoopAnalysis *loopAnalysis = cUnit->loopAnalysis;
    141 
    142     if (loopAnalysis->numBasicIV != 1) return false;
    143     for (i = 0; i < loopAnalysis->ivList->numUsed; i++) {
    144         InductionVariableInfo *ivInfo;
    145 
    146         ivInfo = GET_ELEM_N(loopAnalysis->ivList, InductionVariableInfo*, i);
    147         /* Count up or down loop? */
    148         if (ivInfo->ssaReg == ivInfo->basicSSAReg) {
    149             loopAnalysis->isCountUpLoop = ivInfo->inc > 0;
    150             break;
    151         }
    152     }
    153 
    154     MIR *branch = loopBranch->lastMIRInsn;
    155     OpCode opCode = branch->dalvikInsn.opCode;
    156 
    157     /*
    158      * If the instruction is not accessing the IV as the first operand, return
    159      * false.
    160      */
    161     if (branch->ssaRep->numUses == 0 || branch->ssaRep->numDefs != 0) {
    162         return false;
    163     }
    164 
    165     /*
    166      * If the first operand of the comparison is not the basic induction
    167      * variable, return false.
    168      */
    169     if (branch->ssaRep->uses[0] != loopAnalysis->ssaBIV) {
    170         return false;
    171     }
    172 
    173     if (loopAnalysis->isCountUpLoop) {
    174         /*
    175          * If the condition op is not > or >=, this is not an optimization
    176          * candidate.
    177          */
    178         if (opCode != OP_IF_GT && opCode != OP_IF_GE) {
    179             return false;
    180         }
    181         /*
    182          * If the comparison is not between the BIV and a loop invariant,
    183          * return false.
    184          */
    185         int endReg = dvmConvertSSARegToDalvik(cUnit, branch->ssaRep->uses[1]);
    186 
    187         if (DECODE_SUB(endReg) != 0) {
    188             return false;
    189         }
    190         loopAnalysis->endConditionReg = DECODE_REG(endReg);
    191     } else  {
    192         /*
    193          * If the condition op is not < or <=, this is not an optimization
    194          * candidate.
    195          */
    196         if (opCode == OP_IF_LT || opCode == OP_IF_LE) {
    197             /*
    198              * If the comparison is not between the BIV and a loop invariant,
    199              * return false.
    200              */
    201             int endReg = dvmConvertSSARegToDalvik(cUnit,
    202                                                   branch->ssaRep->uses[1]);
    203 
    204             if (DECODE_SUB(endReg) != 0) {
    205                 return false;
    206             }
    207             loopAnalysis->endConditionReg = DECODE_REG(endReg);
    208         } else if (opCode != OP_IF_LTZ && opCode != OP_IF_LEZ) {
    209             return false;
    210         }
    211     }
    212     loopAnalysis->loopBranchOpcode = opCode;
    213     return true;
    214 }
    215 
    216 /*
    217  * Record the upper and lower bound information for range checks for each
    218  * induction variable. If array A is accessed by index "i+5", the upper and
    219  * lower bound will be len(A)-5 and -5, respectively.
    220  */
    221 static void updateRangeCheckInfo(CompilationUnit *cUnit, int arrayReg,
    222                                  int idxReg)
    223 {
    224     InductionVariableInfo *ivInfo;
    225     LoopAnalysis *loopAnalysis = cUnit->loopAnalysis;
    226     unsigned int i, j;
    227 
    228     for (i = 0; i < loopAnalysis->ivList->numUsed; i++) {
    229         ivInfo = GET_ELEM_N(loopAnalysis->ivList, InductionVariableInfo*, i);
    230         if (ivInfo->ssaReg == idxReg) {
    231             ArrayAccessInfo *arrayAccessInfo = NULL;
    232             for (j = 0; j < loopAnalysis->arrayAccessInfo->numUsed; j++) {
    233                 ArrayAccessInfo *existingArrayAccessInfo =
    234                     GET_ELEM_N(loopAnalysis->arrayAccessInfo,
    235                                ArrayAccessInfo*,
    236                                j);
    237                 if (existingArrayAccessInfo->arrayReg == arrayReg) {
    238                     if (ivInfo->c > existingArrayAccessInfo->maxC) {
    239                         existingArrayAccessInfo->maxC = ivInfo->c;
    240                     }
    241                     if (ivInfo->c < existingArrayAccessInfo->minC) {
    242                         existingArrayAccessInfo->minC = ivInfo->c;
    243                     }
    244                     arrayAccessInfo = existingArrayAccessInfo;
    245                     break;
    246                 }
    247             }
    248             if (arrayAccessInfo == NULL) {
    249                 arrayAccessInfo =
    250                     dvmCompilerNew(sizeof(ArrayAccessInfo), false);
    251                 arrayAccessInfo->ivReg = ivInfo->basicSSAReg;
    252                 arrayAccessInfo->arrayReg = arrayReg;
    253                 arrayAccessInfo->maxC = (ivInfo->c > 0) ? ivInfo->c : 0;
    254                 arrayAccessInfo->minC = (ivInfo->c < 0) ? ivInfo->c : 0;
    255                 dvmInsertGrowableList(loopAnalysis->arrayAccessInfo,
    256                                       arrayAccessInfo);
    257             }
    258             break;
    259         }
    260     }
    261 }
    262 
    263 /* Returns true if the loop body cannot throw any exceptions */
    264 static bool doLoopBodyCodeMotion(CompilationUnit *cUnit)
    265 {
    266     BasicBlock *entry = cUnit->blockList[0];
    267     BasicBlock *loopBody = cUnit->blockList[1];
    268     MIR *mir;
    269     bool loopBodyCanThrow = false;
    270     int numDalvikRegs = cUnit->method->registersSize;
    271 
    272     for (mir = loopBody->firstMIRInsn; mir; mir = mir->next) {
    273         DecodedInstruction *dInsn = &mir->dalvikInsn;
    274         int dfAttributes =
    275             dvmCompilerDataFlowAttributes[mir->dalvikInsn.opCode];
    276 
    277         /* Skip extended MIR instructions */
    278         if (dInsn->opCode > 255) continue;
    279 
    280         int instrFlags = dexGetInstrFlags(gDvm.instrFlags, dInsn->opCode);
    281 
    282         /* Instruction is clean */
    283         if ((instrFlags & kInstrCanThrow) == 0) continue;
    284 
    285         /*
    286          * Currently we can only optimize away null and range checks. Punt on
    287          * instructions that can throw due to other exceptions.
    288          */
    289         if (!(dfAttributes & DF_HAS_NR_CHECKS)) {
    290             loopBodyCanThrow = true;
    291             continue;
    292         }
    293 
    294         /*
    295          * This comparison is redundant now, but we will have more than one
    296          * group of flags to check soon.
    297          */
    298         if (dfAttributes & DF_HAS_NR_CHECKS) {
    299             /*
    300              * Check if the null check is applied on a loop invariant register?
    301              * If the register's SSA id is less than the number of Dalvik
    302              * registers, then it is loop invariant.
    303              */
    304             int refIdx;
    305             switch (dfAttributes & DF_HAS_NR_CHECKS) {
    306                 case DF_NULL_N_RANGE_CHECK_0:
    307                     refIdx = 0;
    308                     break;
    309                 case DF_NULL_N_RANGE_CHECK_1:
    310                     refIdx = 1;
    311                     break;
    312                 case DF_NULL_N_RANGE_CHECK_2:
    313                     refIdx = 2;
    314                     break;
    315                 default:
    316                     refIdx = 0;
    317                     LOGE("Jit: bad case in doLoopBodyCodeMotion");
    318                     dvmCompilerAbort(cUnit);
    319             }
    320 
    321             int useIdx = refIdx + 1;
    322             int subNRegArray =
    323                 dvmConvertSSARegToDalvik(cUnit, mir->ssaRep->uses[refIdx]);
    324             int arrayReg = DECODE_REG(subNRegArray);
    325             int arraySub = DECODE_SUB(subNRegArray);
    326 
    327             /*
    328              * If the register is never updated in the loop (ie subscript == 0),
    329              * it is an optimization candidate.
    330              */
    331             if (arraySub != 0) {
    332                 loopBodyCanThrow = true;
    333                 continue;
    334             }
    335 
    336             /*
    337              * Then check if the range check can be hoisted out of the loop if
    338              * it is basic or dependent induction variable.
    339              */
    340             if (dvmIsBitSet(cUnit->loopAnalysis->isIndVarV,
    341                             mir->ssaRep->uses[useIdx])) {
    342                 mir->OptimizationFlags |=
    343                     MIR_IGNORE_RANGE_CHECK |  MIR_IGNORE_NULL_CHECK;
    344                 updateRangeCheckInfo(cUnit, mir->ssaRep->uses[refIdx],
    345                                      mir->ssaRep->uses[useIdx]);
    346             }
    347         }
    348     }
    349 
    350     return !loopBodyCanThrow;
    351 }
    352 
    353 static void dumpHoistedChecks(CompilationUnit *cUnit)
    354 {
    355     ArrayAccessInfo *arrayAccessInfo;
    356     LoopAnalysis *loopAnalysis = cUnit->loopAnalysis;
    357     unsigned int i;
    358 
    359     for (i = 0; i < loopAnalysis->arrayAccessInfo->numUsed; i++) {
    360         ArrayAccessInfo *arrayAccessInfo =
    361             GET_ELEM_N(loopAnalysis->arrayAccessInfo,
    362                        ArrayAccessInfo*, i);
    363         int arrayReg = DECODE_REG(
    364             dvmConvertSSARegToDalvik(cUnit, arrayAccessInfo->arrayReg));
    365         int idxReg = DECODE_REG(
    366             dvmConvertSSARegToDalvik(cUnit, arrayAccessInfo->ivReg));
    367         LOGE("Array access %d", i);
    368         LOGE("  arrayReg %d", arrayReg);
    369         LOGE("  idxReg %d", idxReg);
    370         LOGE("  endReg %d", loopAnalysis->endConditionReg);
    371         LOGE("  maxC %d", arrayAccessInfo->maxC);
    372         LOGE("  minC %d", arrayAccessInfo->minC);
    373         LOGE("  opcode %d", loopAnalysis->loopBranchOpcode);
    374     }
    375 }
    376 
    377 static void genHoistedChecks(CompilationUnit *cUnit)
    378 {
    379     unsigned int i;
    380     BasicBlock *entry = cUnit->blockList[0];
    381     LoopAnalysis *loopAnalysis = cUnit->loopAnalysis;
    382     ArrayAccessInfo *arrayAccessInfo;
    383     int globalMaxC = 0;
    384     int globalMinC = 0;
    385     /* Should be loop invariant */
    386     int idxReg = 0;
    387 
    388     for (i = 0; i < loopAnalysis->arrayAccessInfo->numUsed; i++) {
    389         ArrayAccessInfo *arrayAccessInfo =
    390             GET_ELEM_N(loopAnalysis->arrayAccessInfo,
    391                        ArrayAccessInfo*, i);
    392         int arrayReg = DECODE_REG(
    393             dvmConvertSSARegToDalvik(cUnit, arrayAccessInfo->arrayReg));
    394         idxReg = DECODE_REG(
    395             dvmConvertSSARegToDalvik(cUnit, arrayAccessInfo->ivReg));
    396 
    397         MIR *rangeCheckMIR = dvmCompilerNew(sizeof(MIR), true);
    398         rangeCheckMIR->dalvikInsn.opCode = (loopAnalysis->isCountUpLoop) ?
    399             kMirOpNullNRangeUpCheck : kMirOpNullNRangeDownCheck;
    400         rangeCheckMIR->dalvikInsn.vA = arrayReg;
    401         rangeCheckMIR->dalvikInsn.vB = idxReg;
    402         rangeCheckMIR->dalvikInsn.vC = loopAnalysis->endConditionReg;
    403         rangeCheckMIR->dalvikInsn.arg[0] = arrayAccessInfo->maxC;
    404         rangeCheckMIR->dalvikInsn.arg[1] = arrayAccessInfo->minC;
    405         rangeCheckMIR->dalvikInsn.arg[2] = loopAnalysis->loopBranchOpcode;
    406         dvmCompilerAppendMIR(entry, rangeCheckMIR);
    407         if (arrayAccessInfo->maxC > globalMaxC) {
    408             globalMaxC = arrayAccessInfo->maxC;
    409         }
    410         if (arrayAccessInfo->minC < globalMinC) {
    411             globalMinC = arrayAccessInfo->minC;
    412         }
    413     }
    414 
    415     if (loopAnalysis->arrayAccessInfo->numUsed != 0) {
    416         if (loopAnalysis->isCountUpLoop) {
    417             MIR *boundCheckMIR = dvmCompilerNew(sizeof(MIR), true);
    418             boundCheckMIR->dalvikInsn.opCode = kMirOpLowerBound;
    419             boundCheckMIR->dalvikInsn.vA = idxReg;
    420             boundCheckMIR->dalvikInsn.vB = globalMinC;
    421             dvmCompilerAppendMIR(entry, boundCheckMIR);
    422         } else {
    423             if (loopAnalysis->loopBranchOpcode == OP_IF_LT ||
    424                 loopAnalysis->loopBranchOpcode == OP_IF_LE) {
    425                 MIR *boundCheckMIR = dvmCompilerNew(sizeof(MIR), true);
    426                 boundCheckMIR->dalvikInsn.opCode = kMirOpLowerBound;
    427                 boundCheckMIR->dalvikInsn.vA = loopAnalysis->endConditionReg;
    428                 boundCheckMIR->dalvikInsn.vB = globalMinC;
    429                 /*
    430                  * If the end condition is ">", add 1 back to the constant field
    431                  * to reflect the fact that the smallest index value is
    432                  * "endValue + constant + 1".
    433                  */
    434                 if (loopAnalysis->loopBranchOpcode == OP_IF_LT) {
    435                     boundCheckMIR->dalvikInsn.vB++;
    436                 }
    437                 dvmCompilerAppendMIR(entry, boundCheckMIR);
    438             } else if (loopAnalysis->loopBranchOpcode == OP_IF_LTZ) {
    439                 /* Array index will fall below 0 */
    440                 if (globalMinC < 0) {
    441                     MIR *boundCheckMIR = dvmCompilerNew(sizeof(MIR), true);
    442                     boundCheckMIR->dalvikInsn.opCode = kMirOpPunt;
    443                     dvmCompilerAppendMIR(entry, boundCheckMIR);
    444                 }
    445             } else if (loopAnalysis->loopBranchOpcode == OP_IF_LEZ) {
    446                 /* Array index will fall below 0 */
    447                 if (globalMinC < -1) {
    448                     MIR *boundCheckMIR = dvmCompilerNew(sizeof(MIR), true);
    449                     boundCheckMIR->dalvikInsn.opCode = kMirOpPunt;
    450                     dvmCompilerAppendMIR(entry, boundCheckMIR);
    451                 }
    452             } else {
    453                 LOGE("Jit: bad case in genHoistedChecks");
    454                 dvmCompilerAbort(cUnit);
    455             }
    456         }
    457 
    458     }
    459 }
    460 
    461 /* Main entry point to do loop optimization */
    462 void dvmCompilerLoopOpt(CompilationUnit *cUnit)
    463 {
    464     int numDalvikReg = cUnit->method->registersSize;
    465     LoopAnalysis *loopAnalysis = dvmCompilerNew(sizeof(LoopAnalysis), true);
    466 
    467     assert(cUnit->blockList[0]->blockType == kEntryBlock);
    468     assert(cUnit->blockList[2]->blockType == kDalvikByteCode);
    469     assert(cUnit->blockList[3]->blockType == kExitBlock);
    470 
    471     cUnit->loopAnalysis = loopAnalysis;
    472     /*
    473      * Find live-in variables to the loop body so that we can fake their
    474      * definitions in the entry block.
    475      */
    476     dvmCompilerDataFlowAnalysisDispatcher(cUnit, dvmCompilerFindLiveIn);
    477 
    478     /* Insert phi nodes to the loop body */
    479     handlePhiPlacement(cUnit);
    480 
    481     dvmCompilerDataFlowAnalysisDispatcher(cUnit, dvmCompilerDoSSAConversion);
    482     fillPhiNodeContents(cUnit);
    483 
    484     /* Constant propagation */
    485     cUnit->isConstantV = dvmAllocBitVector(cUnit->numSSARegs, false);
    486     cUnit->constantValues = dvmCompilerNew(sizeof(int) * cUnit->numSSARegs,
    487                                            true);
    488     dvmCompilerDataFlowAnalysisDispatcher(cUnit,
    489                                           dvmCompilerDoConstantPropagation);
    490     DEBUG_LOOP(dumpConstants(cUnit);)
    491 
    492     /* Find induction variables - basic and dependent */
    493     loopAnalysis->ivList = dvmCompilerNew(sizeof(GrowableList), true);
    494     dvmInitGrowableList(loopAnalysis->ivList, 4);
    495     loopAnalysis->isIndVarV = dvmAllocBitVector(cUnit->numSSARegs, false);
    496     dvmCompilerDataFlowAnalysisDispatcher(cUnit,
    497                                           dvmCompilerFindInductionVariables);
    498     DEBUG_LOOP(dumpIVList(cUnit);)
    499 
    500     /* If the loop turns out to be non-optimizable, return early */
    501     if (!isLoopOptimizable(cUnit))
    502         return;
    503 
    504     loopAnalysis->arrayAccessInfo = dvmCompilerNew(sizeof(GrowableList), true);
    505     dvmInitGrowableList(loopAnalysis->arrayAccessInfo, 4);
    506     loopAnalysis->bodyIsClean = doLoopBodyCodeMotion(cUnit);
    507     DEBUG_LOOP(dumpHoistedChecks(cUnit);)
    508 
    509     /*
    510      * Convert the array access information into extended MIR code in the loop
    511      * header.
    512      */
    513     genHoistedChecks(cUnit);
    514 }
    515