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 #if 0 90 /* Debugging routines */ 91 static void dumpConstants(CompilationUnit *cUnit) 92 { 93 int i; 94 for (i = 0; i < cUnit->numSSARegs; i++) { 95 if (dvmIsBitSet(cUnit->isConstantV, i)) { 96 int subNReg = dvmConvertSSARegToDalvik(cUnit, i); 97 LOGE("s%d(v%d_%d) has %d", i, 98 DECODE_REG(subNReg), DECODE_SUB(subNReg), 99 cUnit->constantValues[i]); 100 } 101 } 102 } 103 104 static void dumpIVList(CompilationUnit *cUnit) 105 { 106 unsigned int i; 107 GrowableList *ivList = cUnit->loopAnalysis->ivList; 108 int *ssaToDalvikMap = (int *) cUnit->ssaToDalvikMap->elemList; 109 110 for (i = 0; i < ivList->numUsed; i++) { 111 InductionVariableInfo *ivInfo = ivList->elemList[i]; 112 /* Basic IV */ 113 if (ivInfo->ssaReg == ivInfo->basicSSAReg) { 114 LOGE("BIV %d: s%d(v%d) + %d", i, 115 ivInfo->ssaReg, 116 ssaToDalvikMap[ivInfo->ssaReg] & 0xffff, 117 ivInfo->inc); 118 /* Dependent IV */ 119 } else { 120 LOGE("DIV %d: s%d(v%d) = %d * s%d(v%d) + %d", i, 121 ivInfo->ssaReg, 122 ssaToDalvikMap[ivInfo->ssaReg] & 0xffff, 123 ivInfo->m, 124 ivInfo->basicSSAReg, 125 ssaToDalvikMap[ivInfo->basicSSAReg] & 0xffff, 126 ivInfo->c); 127 } 128 } 129 } 130 131 static void dumpHoistedChecks(CompilationUnit *cUnit) 132 { 133 LoopAnalysis *loopAnalysis = cUnit->loopAnalysis; 134 unsigned int i; 135 136 for (i = 0; i < loopAnalysis->arrayAccessInfo->numUsed; i++) { 137 ArrayAccessInfo *arrayAccessInfo = 138 GET_ELEM_N(loopAnalysis->arrayAccessInfo, 139 ArrayAccessInfo*, i); 140 int arrayReg = DECODE_REG( 141 dvmConvertSSARegToDalvik(cUnit, arrayAccessInfo->arrayReg)); 142 int idxReg = DECODE_REG( 143 dvmConvertSSARegToDalvik(cUnit, arrayAccessInfo->ivReg)); 144 LOGE("Array access %d", i); 145 LOGE(" arrayReg %d", arrayReg); 146 LOGE(" idxReg %d", idxReg); 147 LOGE(" endReg %d", loopAnalysis->endConditionReg); 148 LOGE(" maxC %d", arrayAccessInfo->maxC); 149 LOGE(" minC %d", arrayAccessInfo->minC); 150 LOGE(" opcode %d", loopAnalysis->loopBranchOpcode); 151 } 152 } 153 154 #endif 155 156 /* 157 * A loop is considered optimizable if: 158 * 1) It has one basic induction variable 159 * 2) The loop back branch compares the BIV with a constant 160 * 3) If it is a count-up loop, the condition is GE/GT, or LE/LT/LEZ/LTZ for 161 * a count-down loop. 162 * 163 * Return false if the loop is not optimizable. 164 */ 165 static bool isLoopOptimizable(CompilationUnit *cUnit) 166 { 167 unsigned int i; 168 BasicBlock *loopBranch = cUnit->blockList[2]; 169 LoopAnalysis *loopAnalysis = cUnit->loopAnalysis; 170 171 if (loopAnalysis->numBasicIV != 1) return false; 172 for (i = 0; i < loopAnalysis->ivList->numUsed; i++) { 173 InductionVariableInfo *ivInfo; 174 175 ivInfo = GET_ELEM_N(loopAnalysis->ivList, InductionVariableInfo*, i); 176 /* Count up or down loop? */ 177 if (ivInfo->ssaReg == ivInfo->basicSSAReg) { 178 /* Infinite loop */ 179 if (ivInfo->inc == 0) { 180 return false; 181 } 182 loopAnalysis->isCountUpLoop = ivInfo->inc > 0; 183 break; 184 } 185 } 186 187 MIR *branch = loopBranch->lastMIRInsn; 188 OpCode opCode = branch->dalvikInsn.opCode; 189 190 /* 191 * If the instruction is not accessing the IV as the first operand, return 192 * false. 193 */ 194 if (branch->ssaRep->numUses == 0 || branch->ssaRep->numDefs != 0) { 195 return false; 196 } 197 198 /* 199 * If the first operand of the comparison is not the basic induction 200 * variable, return false. 201 */ 202 if (branch->ssaRep->uses[0] != loopAnalysis->ssaBIV) { 203 return false; 204 } 205 206 if (loopAnalysis->isCountUpLoop) { 207 /* 208 * If the condition op is not > or >=, this is not an optimization 209 * candidate. 210 */ 211 if (opCode != OP_IF_GT && opCode != OP_IF_GE) { 212 return false; 213 } 214 /* 215 * If the comparison is not between the BIV and a loop invariant, 216 * return false. endReg is loop invariant if one of the following is 217 * true: 218 * - It is not defined in the loop (ie DECODE_SUB returns 0) 219 * - It is reloaded with a constant 220 */ 221 int endReg = dvmConvertSSARegToDalvik(cUnit, branch->ssaRep->uses[1]); 222 if (DECODE_SUB(endReg) != 0 && 223 !dvmIsBitSet(cUnit->isConstantV, branch->ssaRep->uses[1])) { 224 return false; 225 } 226 loopAnalysis->endConditionReg = DECODE_REG(endReg); 227 } else { 228 /* 229 * If the condition op is not < or <=, this is not an optimization 230 * candidate. 231 */ 232 if (opCode == OP_IF_LT || opCode == OP_IF_LE) { 233 /* 234 * If the comparison is not between the BIV and a loop invariant, 235 * return false. 236 */ 237 int endReg = dvmConvertSSARegToDalvik(cUnit, 238 branch->ssaRep->uses[1]); 239 240 if (DECODE_SUB(endReg) != 0) { 241 return false; 242 } 243 loopAnalysis->endConditionReg = DECODE_REG(endReg); 244 } else if (opCode != OP_IF_LTZ && opCode != OP_IF_LEZ) { 245 return false; 246 } 247 } 248 loopAnalysis->loopBranchOpcode = opCode; 249 return true; 250 } 251 252 /* 253 * Record the upper and lower bound information for range checks for each 254 * induction variable. If array A is accessed by index "i+5", the upper and 255 * lower bound will be len(A)-5 and -5, respectively. 256 */ 257 static void updateRangeCheckInfo(CompilationUnit *cUnit, int arrayReg, 258 int idxReg) 259 { 260 InductionVariableInfo *ivInfo; 261 LoopAnalysis *loopAnalysis = cUnit->loopAnalysis; 262 unsigned int i, j; 263 264 for (i = 0; i < loopAnalysis->ivList->numUsed; i++) { 265 ivInfo = GET_ELEM_N(loopAnalysis->ivList, InductionVariableInfo*, i); 266 if (ivInfo->ssaReg == idxReg) { 267 ArrayAccessInfo *arrayAccessInfo = NULL; 268 for (j = 0; j < loopAnalysis->arrayAccessInfo->numUsed; j++) { 269 ArrayAccessInfo *existingArrayAccessInfo = 270 GET_ELEM_N(loopAnalysis->arrayAccessInfo, 271 ArrayAccessInfo*, 272 j); 273 if (existingArrayAccessInfo->arrayReg == arrayReg) { 274 if (ivInfo->c > existingArrayAccessInfo->maxC) { 275 existingArrayAccessInfo->maxC = ivInfo->c; 276 } 277 if (ivInfo->c < existingArrayAccessInfo->minC) { 278 existingArrayAccessInfo->minC = ivInfo->c; 279 } 280 arrayAccessInfo = existingArrayAccessInfo; 281 break; 282 } 283 } 284 if (arrayAccessInfo == NULL) { 285 arrayAccessInfo = 286 dvmCompilerNew(sizeof(ArrayAccessInfo), false); 287 arrayAccessInfo->ivReg = ivInfo->basicSSAReg; 288 arrayAccessInfo->arrayReg = arrayReg; 289 arrayAccessInfo->maxC = (ivInfo->c > 0) ? ivInfo->c : 0; 290 arrayAccessInfo->minC = (ivInfo->c < 0) ? ivInfo->c : 0; 291 dvmInsertGrowableList(loopAnalysis->arrayAccessInfo, 292 arrayAccessInfo); 293 } 294 break; 295 } 296 } 297 } 298 299 /* Returns true if the loop body cannot throw any exceptions */ 300 static bool doLoopBodyCodeMotion(CompilationUnit *cUnit) 301 { 302 BasicBlock *loopBody = cUnit->blockList[1]; 303 MIR *mir; 304 bool loopBodyCanThrow = false; 305 306 for (mir = loopBody->firstMIRInsn; mir; mir = mir->next) { 307 DecodedInstruction *dInsn = &mir->dalvikInsn; 308 int dfAttributes = 309 dvmCompilerDataFlowAttributes[mir->dalvikInsn.opCode]; 310 311 /* Skip extended MIR instructions */ 312 if (dInsn->opCode > 255) continue; 313 314 int instrFlags = dexGetInstrFlags(gDvm.instrFlags, dInsn->opCode); 315 316 /* Instruction is clean */ 317 if ((instrFlags & kInstrCanThrow) == 0) continue; 318 319 /* 320 * Currently we can only optimize away null and range checks. Punt on 321 * instructions that can throw due to other exceptions. 322 */ 323 if (!(dfAttributes & DF_HAS_NR_CHECKS)) { 324 loopBodyCanThrow = true; 325 continue; 326 } 327 328 /* 329 * This comparison is redundant now, but we will have more than one 330 * group of flags to check soon. 331 */ 332 if (dfAttributes & DF_HAS_NR_CHECKS) { 333 /* 334 * Check if the null check is applied on a loop invariant register? 335 * If the register's SSA id is less than the number of Dalvik 336 * registers, then it is loop invariant. 337 */ 338 int refIdx; 339 switch (dfAttributes & DF_HAS_NR_CHECKS) { 340 case DF_NULL_N_RANGE_CHECK_0: 341 refIdx = 0; 342 break; 343 case DF_NULL_N_RANGE_CHECK_1: 344 refIdx = 1; 345 break; 346 case DF_NULL_N_RANGE_CHECK_2: 347 refIdx = 2; 348 break; 349 default: 350 refIdx = 0; 351 LOGE("Jit: bad case in doLoopBodyCodeMotion"); 352 dvmCompilerAbort(cUnit); 353 } 354 355 int useIdx = refIdx + 1; 356 int subNRegArray = 357 dvmConvertSSARegToDalvik(cUnit, mir->ssaRep->uses[refIdx]); 358 int arraySub = DECODE_SUB(subNRegArray); 359 360 /* 361 * If the register is never updated in the loop (ie subscript == 0), 362 * it is an optimization candidate. 363 */ 364 if (arraySub != 0) { 365 loopBodyCanThrow = true; 366 continue; 367 } 368 369 /* 370 * Then check if the range check can be hoisted out of the loop if 371 * it is basic or dependent induction variable. 372 */ 373 if (dvmIsBitSet(cUnit->loopAnalysis->isIndVarV, 374 mir->ssaRep->uses[useIdx])) { 375 mir->OptimizationFlags |= 376 MIR_IGNORE_RANGE_CHECK | MIR_IGNORE_NULL_CHECK; 377 updateRangeCheckInfo(cUnit, mir->ssaRep->uses[refIdx], 378 mir->ssaRep->uses[useIdx]); 379 } 380 } 381 } 382 383 return !loopBodyCanThrow; 384 } 385 386 static void genHoistedChecks(CompilationUnit *cUnit) 387 { 388 unsigned int i; 389 BasicBlock *entry = cUnit->blockList[0]; 390 LoopAnalysis *loopAnalysis = cUnit->loopAnalysis; 391 int globalMaxC = 0; 392 int globalMinC = 0; 393 /* Should be loop invariant */ 394 int idxReg = 0; 395 396 for (i = 0; i < loopAnalysis->arrayAccessInfo->numUsed; i++) { 397 ArrayAccessInfo *arrayAccessInfo = 398 GET_ELEM_N(loopAnalysis->arrayAccessInfo, 399 ArrayAccessInfo*, i); 400 int arrayReg = DECODE_REG( 401 dvmConvertSSARegToDalvik(cUnit, arrayAccessInfo->arrayReg)); 402 idxReg = DECODE_REG( 403 dvmConvertSSARegToDalvik(cUnit, arrayAccessInfo->ivReg)); 404 405 MIR *rangeCheckMIR = dvmCompilerNew(sizeof(MIR), true); 406 rangeCheckMIR->dalvikInsn.opCode = (loopAnalysis->isCountUpLoop) ? 407 kMirOpNullNRangeUpCheck : kMirOpNullNRangeDownCheck; 408 rangeCheckMIR->dalvikInsn.vA = arrayReg; 409 rangeCheckMIR->dalvikInsn.vB = idxReg; 410 rangeCheckMIR->dalvikInsn.vC = loopAnalysis->endConditionReg; 411 rangeCheckMIR->dalvikInsn.arg[0] = arrayAccessInfo->maxC; 412 rangeCheckMIR->dalvikInsn.arg[1] = arrayAccessInfo->minC; 413 rangeCheckMIR->dalvikInsn.arg[2] = loopAnalysis->loopBranchOpcode; 414 dvmCompilerAppendMIR(entry, rangeCheckMIR); 415 if (arrayAccessInfo->maxC > globalMaxC) { 416 globalMaxC = arrayAccessInfo->maxC; 417 } 418 if (arrayAccessInfo->minC < globalMinC) { 419 globalMinC = arrayAccessInfo->minC; 420 } 421 } 422 423 if (loopAnalysis->arrayAccessInfo->numUsed != 0) { 424 if (loopAnalysis->isCountUpLoop) { 425 MIR *boundCheckMIR = dvmCompilerNew(sizeof(MIR), true); 426 boundCheckMIR->dalvikInsn.opCode = kMirOpLowerBound; 427 boundCheckMIR->dalvikInsn.vA = idxReg; 428 boundCheckMIR->dalvikInsn.vB = globalMinC; 429 dvmCompilerAppendMIR(entry, boundCheckMIR); 430 } else { 431 if (loopAnalysis->loopBranchOpcode == OP_IF_LT || 432 loopAnalysis->loopBranchOpcode == OP_IF_LE) { 433 MIR *boundCheckMIR = dvmCompilerNew(sizeof(MIR), true); 434 boundCheckMIR->dalvikInsn.opCode = kMirOpLowerBound; 435 boundCheckMIR->dalvikInsn.vA = loopAnalysis->endConditionReg; 436 boundCheckMIR->dalvikInsn.vB = globalMinC; 437 /* 438 * If the end condition is ">" in the source, the check in the 439 * Dalvik bytecode is OP_IF_LE. In this case add 1 back to the 440 * constant field to reflect the fact that the smallest index 441 * value is "endValue + constant + 1". 442 */ 443 if (loopAnalysis->loopBranchOpcode == OP_IF_LE) { 444 boundCheckMIR->dalvikInsn.vB++; 445 } 446 dvmCompilerAppendMIR(entry, boundCheckMIR); 447 } else if (loopAnalysis->loopBranchOpcode == OP_IF_LTZ) { 448 /* Array index will fall below 0 */ 449 if (globalMinC < 0) { 450 MIR *boundCheckMIR = dvmCompilerNew(sizeof(MIR), true); 451 boundCheckMIR->dalvikInsn.opCode = kMirOpPunt; 452 dvmCompilerAppendMIR(entry, boundCheckMIR); 453 } 454 } else if (loopAnalysis->loopBranchOpcode == OP_IF_LEZ) { 455 /* Array index will fall below 0 */ 456 if (globalMinC < -1) { 457 MIR *boundCheckMIR = dvmCompilerNew(sizeof(MIR), true); 458 boundCheckMIR->dalvikInsn.opCode = kMirOpPunt; 459 dvmCompilerAppendMIR(entry, boundCheckMIR); 460 } 461 } else { 462 LOGE("Jit: bad case in genHoistedChecks"); 463 dvmCompilerAbort(cUnit); 464 } 465 } 466 467 } 468 } 469 470 /* 471 * Main entry point to do loop optimization. 472 * Return false if sanity checks for loop formation/optimization failed. 473 */ 474 bool dvmCompilerLoopOpt(CompilationUnit *cUnit) 475 { 476 LoopAnalysis *loopAnalysis = dvmCompilerNew(sizeof(LoopAnalysis), true); 477 478 assert(cUnit->blockList[0]->blockType == kTraceEntryBlock); 479 assert(cUnit->blockList[2]->blockType == kDalvikByteCode); 480 assert(cUnit->blockList[3]->blockType == kTraceExitBlock); 481 482 cUnit->loopAnalysis = loopAnalysis; 483 /* 484 * Find live-in variables to the loop body so that we can fake their 485 * definitions in the entry block. 486 */ 487 dvmCompilerDataFlowAnalysisDispatcher(cUnit, dvmCompilerFindLiveIn); 488 489 /* Insert phi nodes to the loop body */ 490 handlePhiPlacement(cUnit); 491 492 dvmCompilerDataFlowAnalysisDispatcher(cUnit, dvmCompilerDoSSAConversion); 493 fillPhiNodeContents(cUnit); 494 495 /* Constant propagation */ 496 cUnit->isConstantV = dvmAllocBitVector(cUnit->numSSARegs, false); 497 cUnit->constantValues = dvmCompilerNew(sizeof(int) * cUnit->numSSARegs, 498 true); 499 dvmCompilerDataFlowAnalysisDispatcher(cUnit, 500 dvmCompilerDoConstantPropagation); 501 DEBUG_LOOP(dumpConstants(cUnit);) 502 503 /* Find induction variables - basic and dependent */ 504 loopAnalysis->ivList = dvmCompilerNew(sizeof(GrowableList), true); 505 dvmInitGrowableList(loopAnalysis->ivList, 4); 506 loopAnalysis->isIndVarV = dvmAllocBitVector(cUnit->numSSARegs, false); 507 dvmCompilerDataFlowAnalysisDispatcher(cUnit, 508 dvmCompilerFindInductionVariables); 509 DEBUG_LOOP(dumpIVList(cUnit);) 510 511 /* If the loop turns out to be non-optimizable, return early */ 512 if (!isLoopOptimizable(cUnit)) 513 return false; 514 515 loopAnalysis->arrayAccessInfo = dvmCompilerNew(sizeof(GrowableList), true); 516 dvmInitGrowableList(loopAnalysis->arrayAccessInfo, 4); 517 loopAnalysis->bodyIsClean = doLoopBodyCodeMotion(cUnit); 518 DEBUG_LOOP(dumpHoistedChecks(cUnit);) 519 520 /* 521 * Convert the array access information into extended MIR code in the loop 522 * header. 523 */ 524 genHoistedChecks(cUnit); 525 return true; 526 } 527