Loop.c revision 1465db5ee2d3c4c4dcc8e017a294172e858765cb
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 */ 39static 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 67static 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 89static 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 102static 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 */ 136static 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 */ 221static 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 */ 264static 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 dvmAbort(); 318 } 319 320 int useIdx = refIdx + 1; 321 int subNRegArray = 322 dvmConvertSSARegToDalvik(cUnit, mir->ssaRep->uses[refIdx]); 323 int arrayReg = DECODE_REG(subNRegArray); 324 int arraySub = DECODE_SUB(subNRegArray); 325 326 /* 327 * If the register is never updated in the loop (ie subscript == 0), 328 * it is an optimization candidate. 329 */ 330 if (arraySub != 0) { 331 loopBodyCanThrow = true; 332 continue; 333 } 334 335 /* 336 * Then check if the range check can be hoisted out of the loop if 337 * it is basic or dependent induction variable. 338 */ 339 if (dvmIsBitSet(cUnit->loopAnalysis->isIndVarV, 340 mir->ssaRep->uses[useIdx])) { 341 mir->OptimizationFlags |= 342 MIR_IGNORE_RANGE_CHECK | MIR_IGNORE_NULL_CHECK; 343 updateRangeCheckInfo(cUnit, mir->ssaRep->uses[refIdx], 344 mir->ssaRep->uses[useIdx]); 345 } 346 } 347 } 348 349 return !loopBodyCanThrow; 350} 351 352static void dumpHoistedChecks(CompilationUnit *cUnit) 353{ 354 ArrayAccessInfo *arrayAccessInfo; 355 LoopAnalysis *loopAnalysis = cUnit->loopAnalysis; 356 unsigned int i; 357 358 for (i = 0; i < loopAnalysis->arrayAccessInfo->numUsed; i++) { 359 ArrayAccessInfo *arrayAccessInfo = 360 GET_ELEM_N(loopAnalysis->arrayAccessInfo, 361 ArrayAccessInfo*, i); 362 int arrayReg = DECODE_REG( 363 dvmConvertSSARegToDalvik(cUnit, arrayAccessInfo->arrayReg)); 364 int idxReg = DECODE_REG( 365 dvmConvertSSARegToDalvik(cUnit, arrayAccessInfo->ivReg)); 366 LOGE("Array access %d", i); 367 LOGE(" arrayReg %d", arrayReg); 368 LOGE(" idxReg %d", idxReg); 369 LOGE(" endReg %d", loopAnalysis->endConditionReg); 370 LOGE(" maxC %d", arrayAccessInfo->maxC); 371 LOGE(" minC %d", arrayAccessInfo->minC); 372 LOGE(" opcode %d", loopAnalysis->loopBranchOpcode); 373 } 374} 375 376static void genHoistedChecks(CompilationUnit *cUnit) 377{ 378 unsigned int i; 379 BasicBlock *entry = cUnit->blockList[0]; 380 LoopAnalysis *loopAnalysis = cUnit->loopAnalysis; 381 ArrayAccessInfo *arrayAccessInfo; 382 int globalMaxC = 0; 383 int globalMinC = 0; 384 /* Should be loop invariant */ 385 int idxReg = 0; 386 387 for (i = 0; i < loopAnalysis->arrayAccessInfo->numUsed; i++) { 388 ArrayAccessInfo *arrayAccessInfo = 389 GET_ELEM_N(loopAnalysis->arrayAccessInfo, 390 ArrayAccessInfo*, i); 391 int arrayReg = DECODE_REG( 392 dvmConvertSSARegToDalvik(cUnit, arrayAccessInfo->arrayReg)); 393 idxReg = DECODE_REG( 394 dvmConvertSSARegToDalvik(cUnit, arrayAccessInfo->ivReg)); 395 396 MIR *rangeCheckMIR = dvmCompilerNew(sizeof(MIR), true); 397 rangeCheckMIR->dalvikInsn.opCode = (loopAnalysis->isCountUpLoop) ? 398 kMirOpNullNRangeUpCheck : kMirOpNullNRangeDownCheck; 399 rangeCheckMIR->dalvikInsn.vA = arrayReg; 400 rangeCheckMIR->dalvikInsn.vB = idxReg; 401 rangeCheckMIR->dalvikInsn.vC = loopAnalysis->endConditionReg; 402 rangeCheckMIR->dalvikInsn.arg[0] = arrayAccessInfo->maxC; 403 rangeCheckMIR->dalvikInsn.arg[1] = arrayAccessInfo->minC; 404 rangeCheckMIR->dalvikInsn.arg[2] = loopAnalysis->loopBranchOpcode; 405 dvmCompilerAppendMIR(entry, rangeCheckMIR); 406 if (arrayAccessInfo->maxC > globalMaxC) { 407 globalMaxC = arrayAccessInfo->maxC; 408 } 409 if (arrayAccessInfo->minC < globalMinC) { 410 globalMinC = arrayAccessInfo->minC; 411 } 412 } 413 414 if (loopAnalysis->arrayAccessInfo->numUsed != 0) { 415 if (loopAnalysis->isCountUpLoop) { 416 MIR *boundCheckMIR = dvmCompilerNew(sizeof(MIR), true); 417 boundCheckMIR->dalvikInsn.opCode = kMirOpLowerBound; 418 boundCheckMIR->dalvikInsn.vA = idxReg; 419 boundCheckMIR->dalvikInsn.vB = globalMinC; 420 dvmCompilerAppendMIR(entry, boundCheckMIR); 421 } else { 422 if (loopAnalysis->loopBranchOpcode == OP_IF_LT || 423 loopAnalysis->loopBranchOpcode == OP_IF_LE) { 424 MIR *boundCheckMIR = dvmCompilerNew(sizeof(MIR), true); 425 boundCheckMIR->dalvikInsn.opCode = kMirOpLowerBound; 426 boundCheckMIR->dalvikInsn.vA = loopAnalysis->endConditionReg; 427 boundCheckMIR->dalvikInsn.vB = globalMinC; 428 /* 429 * If the end condition is ">", add 1 back to the constant field 430 * to reflect the fact that the smallest index value is 431 * "endValue + constant + 1". 432 */ 433 if (loopAnalysis->loopBranchOpcode == OP_IF_LT) { 434 boundCheckMIR->dalvikInsn.vB++; 435 } 436 dvmCompilerAppendMIR(entry, boundCheckMIR); 437 } else if (loopAnalysis->loopBranchOpcode == OP_IF_LTZ) { 438 /* Array index will fall below 0 */ 439 if (globalMinC < 0) { 440 MIR *boundCheckMIR = dvmCompilerNew(sizeof(MIR), true); 441 boundCheckMIR->dalvikInsn.opCode = kMirOpPunt; 442 dvmCompilerAppendMIR(entry, boundCheckMIR); 443 } 444 } else if (loopAnalysis->loopBranchOpcode == OP_IF_LEZ) { 445 /* Array index will fall below 0 */ 446 if (globalMinC < -1) { 447 MIR *boundCheckMIR = dvmCompilerNew(sizeof(MIR), true); 448 boundCheckMIR->dalvikInsn.opCode = kMirOpPunt; 449 dvmCompilerAppendMIR(entry, boundCheckMIR); 450 } 451 } else { 452 dvmAbort(); 453 } 454 } 455 456 } 457} 458 459/* Main entry point to do loop optimization */ 460void dvmCompilerLoopOpt(CompilationUnit *cUnit) 461{ 462 int numDalvikReg = cUnit->method->registersSize; 463 LoopAnalysis *loopAnalysis = dvmCompilerNew(sizeof(LoopAnalysis), true); 464 465 assert(cUnit->blockList[0]->blockType == kEntryBlock); 466 assert(cUnit->blockList[2]->blockType == kDalvikByteCode); 467 assert(cUnit->blockList[3]->blockType == kExitBlock); 468 469 cUnit->loopAnalysis = loopAnalysis; 470 /* 471 * Find live-in variables to the loop body so that we can fake their 472 * definitions in the entry block. 473 */ 474 dvmCompilerDataFlowAnalysisDispatcher(cUnit, dvmCompilerFindLiveIn); 475 476 /* Insert phi nodes to the loop body */ 477 handlePhiPlacement(cUnit); 478 479 dvmCompilerDataFlowAnalysisDispatcher(cUnit, dvmCompilerDoSSAConversion); 480 fillPhiNodeContents(cUnit); 481 482 /* Constant propagation */ 483 cUnit->isConstantV = dvmAllocBitVector(cUnit->numSSARegs, false); 484 cUnit->constantValues = dvmCompilerNew(sizeof(int) * cUnit->numSSARegs, 485 true); 486 dvmCompilerDataFlowAnalysisDispatcher(cUnit, 487 dvmCompilerDoConstantPropagation); 488 DEBUG_LOOP(dumpConstants(cUnit);) 489 490 /* Find induction variables - basic and dependent */ 491 loopAnalysis->ivList = dvmCompilerNew(sizeof(GrowableList), true); 492 dvmInitGrowableList(loopAnalysis->ivList, 4); 493 loopAnalysis->isIndVarV = dvmAllocBitVector(cUnit->numSSARegs, false); 494 dvmCompilerDataFlowAnalysisDispatcher(cUnit, 495 dvmCompilerFindInductionVariables); 496 DEBUG_LOOP(dumpIVList(cUnit);) 497 498 /* If the loop turns out to be non-optimizable, return early */ 499 if (!isLoopOptimizable(cUnit)) 500 return; 501 502 loopAnalysis->arrayAccessInfo = dvmCompilerNew(sizeof(GrowableList), true); 503 dvmInitGrowableList(loopAnalysis->arrayAccessInfo, 4); 504 loopAnalysis->bodyIsClean = doLoopBodyCodeMotion(cUnit); 505 DEBUG_LOOP(dumpHoistedChecks(cUnit);) 506 507 /* 508 * Convert the array access information into extended MIR code in the loop 509 * header. 510 */ 511 genHoistedChecks(cUnit); 512} 513