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 /* 18 * This file contains register alloction support and is intended to be 19 * included by: 20 * 21 * Codegen-$(TARGET_ARCH_VARIANT).c 22 * 23 */ 24 25 #include "compiler/CompilerUtility.h" 26 #include "compiler/CompilerIR.h" 27 #include "compiler/Dataflow.h" 28 #include "ArmLIR.h" 29 #include "Codegen.h" 30 #include "Ralloc.h" 31 32 /* 33 * Register usage for 16-bit Thumb systems: 34 * r0-r3: Temp/argument 35 * lr(r14): Temp for translations, return address for handlers 36 * rGLUE(r6): Pointer to InterpState 37 * rFP(r5): Dalvik frame pointer 38 * r4, r7: Temp for translations 39 * r8, r9, r10: Temp preserved across C calls 40 * r11, ip(r12): Temp not preserved across C calls 41 * 42 * Register usage for 32-bit Thumb systems: 43 * r0-r3: Temp/argument 44 * lr(r14): Temp for translations, return address for handlers 45 * rGLUE(r6): Pointer to InterpState 46 * rFP(r5): Dalvik frame pointer 47 * r4, r7: Temp for translations 48 * r8, r9, r10 Temp preserved across C calls 49 * r11, ip(r12): Temp not preserved across C calls 50 * fp0-fp15: Hot temps, not preserved across C calls 51 * fp16-fp31: Promotion pool 52 * 53 */ 54 55 #define SREG(c, s) ((c)->regLocation[(s)].sRegLow) 56 /* 57 * Get the "real" sreg number associated with an sReg slot. In general, 58 * sReg values passed through codegen are the SSA names created by 59 * dataflow analysis and refer to slot numbers in the cUnit->regLocation 60 * array. However, renaming is accomplished by simply replacing RegLocation 61 * entries in the cUnit->reglocation[] array. Therefore, when location 62 * records for operands are first created, we need to ask the locRecord 63 * identified by the dataflow pass what it's new name is. 64 */ 65 66 /* 67 * Free all allocated temps in the temp pools. Note that this does 68 * not affect the "liveness" of a temp register, which will stay 69 * live until it is either explicitly killed or reallocated. 70 */ 71 extern void dvmCompilerResetRegPool(CompilationUnit *cUnit) 72 { 73 int i; 74 for (i=0; i < cUnit->regPool->numCoreTemps; i++) { 75 cUnit->regPool->coreTemps[i].inUse = false; 76 } 77 for (i=0; i < cUnit->regPool->numFPTemps; i++) { 78 cUnit->regPool->FPTemps[i].inUse = false; 79 } 80 } 81 82 /* Set up temp & preserved register pools specialized by target */ 83 extern void dvmCompilerInitPool(RegisterInfo *regs, int *regNums, int num) 84 { 85 int i; 86 for (i=0; i < num; i++) { 87 regs[i].reg = regNums[i]; 88 regs[i].inUse = false; 89 regs[i].pair = false; 90 regs[i].live = false; 91 regs[i].dirty = false; 92 regs[i].sReg = INVALID_SREG; 93 } 94 } 95 96 static void dumpRegPool(RegisterInfo *p, int numRegs) 97 { 98 int i; 99 LOGE("================================================"); 100 for (i=0; i < numRegs; i++ ){ 101 LOGE("R[%d]: U:%d, P:%d, part:%d, LV:%d, D:%d, SR:%d, ST:%x, EN:%x", 102 p[i].reg, p[i].inUse, p[i].pair, p[i].partner, p[i].live, 103 p[i].dirty, p[i].sReg,(int)p[i].defStart, (int)p[i].defEnd); 104 } 105 LOGE("================================================"); 106 } 107 108 static RegisterInfo *getRegInfo(CompilationUnit *cUnit, int reg) 109 { 110 int numTemps = cUnit->regPool->numCoreTemps; 111 RegisterInfo *p = cUnit->regPool->coreTemps; 112 int i; 113 for (i=0; i< numTemps; i++) { 114 if (p[i].reg == reg) { 115 return &p[i]; 116 } 117 } 118 p = cUnit->regPool->FPTemps; 119 numTemps = cUnit->regPool->numFPTemps; 120 for (i=0; i< numTemps; i++) { 121 if (p[i].reg == reg) { 122 return &p[i]; 123 } 124 } 125 LOGE("Tried to get info on a non-existant temp: r%d",reg); 126 dvmCompilerAbort(cUnit); 127 return NULL; 128 } 129 130 static void flushRegWide(CompilationUnit *cUnit, int reg1, int reg2) 131 { 132 RegisterInfo *info1 = getRegInfo(cUnit, reg1); 133 RegisterInfo *info2 = getRegInfo(cUnit, reg2); 134 assert(info1 && info2 && info1->pair && info2->pair && 135 (info1->partner == info2->reg) && 136 (info2->partner == info1->reg)); 137 if ((info1->live && info1->dirty) || (info2->live && info2->dirty)) { 138 info1->dirty = false; 139 info2->dirty = false; 140 if (dvmCompilerS2VReg(cUnit, info2->sReg) < 141 dvmCompilerS2VReg(cUnit, info1->sReg)) 142 info1 = info2; 143 dvmCompilerFlushRegWideImpl(cUnit, rFP, 144 dvmCompilerS2VReg(cUnit, info1->sReg) << 2, 145 info1->reg, info1->partner); 146 } 147 } 148 149 static void flushReg(CompilationUnit *cUnit, int reg) 150 { 151 RegisterInfo *info = getRegInfo(cUnit, reg); 152 if (info->live && info->dirty) { 153 info->dirty = false; 154 dvmCompilerFlushRegImpl(cUnit, rFP, 155 dvmCompilerS2VReg(cUnit, info->sReg) << 2, 156 reg, kWord); 157 } 158 } 159 160 /* return true if found reg to clobber */ 161 static bool clobberRegBody(CompilationUnit *cUnit, RegisterInfo *p, 162 int numTemps, int reg) 163 { 164 int i; 165 for (i=0; i< numTemps; i++) { 166 if (p[i].reg == reg) { 167 if (p[i].live && p[i].dirty) { 168 if (p[i].pair) { 169 flushRegWide(cUnit, p[i].reg, p[i].partner); 170 } else { 171 flushReg(cUnit, p[i].reg); 172 } 173 } 174 p[i].live = false; 175 p[i].sReg = INVALID_SREG; 176 p[i].defStart = NULL; 177 p[i].defEnd = NULL; 178 if (p[i].pair) { 179 p[i].pair = false; 180 /* partners should be in same pool */ 181 clobberRegBody(cUnit, p, numTemps, p[i].partner); 182 } 183 return true; 184 } 185 } 186 return false; 187 } 188 189 /* Mark a temp register as dead. Does not affect allocation state. */ 190 void dvmCompilerClobber(CompilationUnit *cUnit, int reg) 191 { 192 if (!clobberRegBody(cUnit, cUnit->regPool->coreTemps, 193 cUnit->regPool->numCoreTemps, reg)) { 194 clobberRegBody(cUnit, cUnit->regPool->FPTemps, 195 cUnit->regPool->numFPTemps, reg); 196 } 197 } 198 199 static void clobberSRegBody(RegisterInfo *p, int numTemps, int sReg) 200 { 201 int i; 202 for (i=0; i< numTemps; i++) { 203 if (p[i].sReg == sReg) { 204 p[i].live = false; 205 p[i].defStart = NULL; 206 p[i].defEnd = NULL; 207 } 208 } 209 } 210 211 /* Clobber any temp associated with an sReg. Could be in either class */ 212 extern void dvmCompilerClobberSReg(CompilationUnit *cUnit, int sReg) 213 { 214 clobberSRegBody(cUnit->regPool->coreTemps, cUnit->regPool->numCoreTemps, 215 sReg); 216 clobberSRegBody(cUnit->regPool->FPTemps, cUnit->regPool->numFPTemps, 217 sReg); 218 } 219 220 static int allocTempBody(CompilationUnit *cUnit, RegisterInfo *p, int numTemps, 221 int *nextTemp, bool required) 222 { 223 int i; 224 int next = *nextTemp; 225 for (i=0; i< numTemps; i++) { 226 if (next >= numTemps) 227 next = 0; 228 if (!p[next].inUse && !p[next].live) { 229 dvmCompilerClobber(cUnit, p[next].reg); 230 p[next].inUse = true; 231 p[next].pair = false; 232 *nextTemp = next + 1; 233 return p[next].reg; 234 } 235 next++; 236 } 237 next = *nextTemp; 238 for (i=0; i< numTemps; i++) { 239 if (next >= numTemps) 240 next = 0; 241 if (!p[next].inUse) { 242 dvmCompilerClobber(cUnit, p[next].reg); 243 p[next].inUse = true; 244 p[next].pair = false; 245 *nextTemp = next + 1; 246 return p[next].reg; 247 } 248 next++; 249 } 250 if (required) { 251 LOGE("No free temp registers"); 252 dvmCompilerAbort(cUnit); 253 } 254 return -1; // No register available 255 } 256 257 //REDO: too many assumptions. 258 extern int dvmCompilerAllocTempDouble(CompilationUnit *cUnit) 259 { 260 RegisterInfo *p = cUnit->regPool->FPTemps; 261 int numTemps = cUnit->regPool->numFPTemps; 262 int next = cUnit->regPool->nextFPTemp; 263 int i; 264 265 for (i=0; i < numTemps; i+=2) { 266 /* Cleanup - not all targets need aligned regs */ 267 if (next & 1) 268 next++; 269 if (next >= numTemps) 270 next = 0; 271 if ((!p[next].inUse && !p[next].live) && 272 (!p[next+1].inUse && !p[next+1].live)) { 273 dvmCompilerClobber(cUnit, p[next].reg); 274 dvmCompilerClobber(cUnit, p[next+1].reg); 275 p[next].inUse = true; 276 p[next+1].inUse = true; 277 assert((p[next].reg+1) == p[next+1].reg); 278 assert((p[next].reg & 0x1) == 0); 279 cUnit->regPool->nextFPTemp += 2; 280 return p[next].reg; 281 } 282 next += 2; 283 } 284 next = cUnit->regPool->nextFPTemp; 285 for (i=0; i < numTemps; i+=2) { 286 if (next >= numTemps) 287 next = 0; 288 if (!p[next].inUse && !p[next+1].inUse) { 289 dvmCompilerClobber(cUnit, p[next].reg); 290 dvmCompilerClobber(cUnit, p[next+1].reg); 291 p[next].inUse = true; 292 p[next+1].inUse = true; 293 assert((p[next].reg+1) == p[next+1].reg); 294 assert((p[next].reg & 0x1) == 0); 295 cUnit->regPool->nextFPTemp += 2; 296 return p[next].reg; 297 } 298 next += 2; 299 } 300 LOGE("No free temp registers"); 301 dvmCompilerAbort(cUnit); 302 return -1; 303 } 304 305 /* Return a temp if one is available, -1 otherwise */ 306 extern int dvmCompilerAllocFreeTemp(CompilationUnit *cUnit) 307 { 308 return allocTempBody(cUnit, cUnit->regPool->coreTemps, 309 cUnit->regPool->numCoreTemps, 310 &cUnit->regPool->nextCoreTemp, true); 311 } 312 313 extern int dvmCompilerAllocTemp(CompilationUnit *cUnit) 314 { 315 return allocTempBody(cUnit, cUnit->regPool->coreTemps, 316 cUnit->regPool->numCoreTemps, 317 &cUnit->regPool->nextCoreTemp, true); 318 } 319 320 extern int dvmCompilerAllocTempFloat(CompilationUnit *cUnit) 321 { 322 return allocTempBody(cUnit, cUnit->regPool->FPTemps, 323 cUnit->regPool->numFPTemps, 324 &cUnit->regPool->nextFPTemp, true); 325 } 326 327 static RegisterInfo *allocLiveBody(RegisterInfo *p, int numTemps, int sReg) 328 { 329 int i; 330 if (sReg == -1) 331 return NULL; 332 for (i=0; i < numTemps; i++) { 333 if (p[i].live && (p[i].sReg == sReg)) { 334 p[i].inUse = true; 335 return &p[i]; 336 } 337 } 338 return NULL; 339 } 340 341 static RegisterInfo *allocLive(CompilationUnit *cUnit, int sReg, 342 int regClass) 343 { 344 RegisterInfo *res = NULL; 345 switch(regClass) { 346 case kAnyReg: 347 res = allocLiveBody(cUnit->regPool->FPTemps, 348 cUnit->regPool->numFPTemps, sReg); 349 if (res) 350 break; 351 /* Intentional fallthrough */ 352 case kCoreReg: 353 res = allocLiveBody(cUnit->regPool->coreTemps, 354 cUnit->regPool->numCoreTemps, sReg); 355 break; 356 case kFPReg: 357 res = allocLiveBody(cUnit->regPool->FPTemps, 358 cUnit->regPool->numFPTemps, sReg); 359 break; 360 default: 361 LOGE("Invalid register type"); 362 dvmCompilerAbort(cUnit); 363 } 364 return res; 365 } 366 367 extern void dvmCompilerFreeTemp(CompilationUnit *cUnit, int reg) 368 { 369 RegisterInfo *p = cUnit->regPool->coreTemps; 370 int numTemps = cUnit->regPool->numCoreTemps; 371 int i; 372 for (i=0; i< numTemps; i++) { 373 if (p[i].reg == reg) { 374 p[i].inUse = false; 375 p[i].pair = false; 376 return; 377 } 378 } 379 p = cUnit->regPool->FPTemps; 380 numTemps = cUnit->regPool->numFPTemps; 381 for (i=0; i< numTemps; i++) { 382 if (p[i].reg == reg) { 383 p[i].inUse = false; 384 p[i].pair = false; 385 return; 386 } 387 } 388 LOGE("Tried to free a non-existant temp: r%d",reg); 389 dvmCompilerAbort(cUnit); 390 } 391 392 /* 393 * FIXME - this needs to also check the preserved pool once we start 394 * start using preserved registers. 395 */ 396 extern RegisterInfo *dvmCompilerIsLive(CompilationUnit *cUnit, int reg) 397 { 398 RegisterInfo *p = cUnit->regPool->coreTemps; 399 int numTemps = cUnit->regPool->numCoreTemps; 400 int i; 401 for (i=0; i< numTemps; i++) { 402 if (p[i].reg == reg) { 403 return p[i].live ? &p[i] : NULL; 404 } 405 } 406 p = cUnit->regPool->FPTemps; 407 numTemps = cUnit->regPool->numFPTemps; 408 for (i=0; i< numTemps; i++) { 409 if (p[i].reg == reg) { 410 return p[i].live ? &p[i] : NULL; 411 } 412 } 413 return NULL; 414 } 415 416 extern RegisterInfo *dvmCompilerIsTemp(CompilationUnit *cUnit, int reg) 417 { 418 RegisterInfo *p = cUnit->regPool->coreTemps; 419 int numTemps = cUnit->regPool->numCoreTemps; 420 int i; 421 for (i=0; i< numTemps; i++) { 422 if (p[i].reg == reg) { 423 return &p[i]; 424 } 425 } 426 p = cUnit->regPool->FPTemps; 427 numTemps = cUnit->regPool->numFPTemps; 428 for (i=0; i< numTemps; i++) { 429 if (p[i].reg == reg) { 430 return &p[i]; 431 } 432 } 433 return NULL; 434 } 435 436 /* 437 * Similar to dvmCompilerAllocTemp(), but forces the allocation of a specific 438 * register. No check is made to see if the register was previously 439 * allocated. Use with caution. 440 */ 441 extern void dvmCompilerLockTemp(CompilationUnit *cUnit, int reg) 442 { 443 RegisterInfo *p = cUnit->regPool->coreTemps; 444 int numTemps = cUnit->regPool->numCoreTemps; 445 int i; 446 for (i=0; i< numTemps; i++) { 447 if (p[i].reg == reg) { 448 p[i].inUse = true; 449 p[i].live = false; 450 return; 451 } 452 } 453 p = cUnit->regPool->FPTemps; 454 numTemps = cUnit->regPool->numFPTemps; 455 for (i=0; i< numTemps; i++) { 456 if (p[i].reg == reg) { 457 p[i].inUse = true; 458 p[i].live = false; 459 return; 460 } 461 } 462 LOGE("Tried to lock a non-existant temp: r%d",reg); 463 dvmCompilerAbort(cUnit); 464 } 465 466 static void lockArgRegs(CompilationUnit *cUnit) 467 { 468 dvmCompilerLockTemp(cUnit, r0); 469 dvmCompilerLockTemp(cUnit, r1); 470 dvmCompilerLockTemp(cUnit, r2); 471 dvmCompilerLockTemp(cUnit, r3); 472 } 473 474 /* Clobber all regs that might be used by an external C call */ 475 extern void dvmCompilerClobberCallRegs(CompilationUnit *cUnit) 476 { 477 dvmCompilerClobber(cUnit, r0); 478 dvmCompilerClobber(cUnit, r1); 479 dvmCompilerClobber(cUnit, r2); 480 dvmCompilerClobber(cUnit, r3); 481 dvmCompilerClobber(cUnit, r9); // Need to do this?, be conservative 482 dvmCompilerClobber(cUnit, r11); 483 dvmCompilerClobber(cUnit, r12); 484 dvmCompilerClobber(cUnit, rlr); 485 } 486 487 /* Clobber all of the temps that might be used by a handler. */ 488 extern void dvmCompilerClobberHandlerRegs(CompilationUnit *cUnit) 489 { 490 //TUNING: reduce the set of regs used by handlers. Only a few need lots. 491 dvmCompilerClobberCallRegs(cUnit); 492 dvmCompilerClobber(cUnit, r4PC); 493 dvmCompilerClobber(cUnit, r7); 494 dvmCompilerClobber(cUnit, r8); 495 dvmCompilerClobber(cUnit, r9); 496 dvmCompilerClobber(cUnit, r10); 497 } 498 499 extern void dvmCompilerResetDef(CompilationUnit *cUnit, int reg) 500 { 501 RegisterInfo *p = getRegInfo(cUnit, reg); 502 p->defStart = NULL; 503 p->defEnd = NULL; 504 } 505 506 static void nullifyRange(CompilationUnit *cUnit, LIR *start, LIR *finish, 507 int sReg1, int sReg2) 508 { 509 if (start && finish) { 510 LIR *p; 511 assert(sReg1 == sReg2); 512 for (p = start; ;p = p->next) { 513 ((ArmLIR *)p)->isNop = true; 514 if (p == finish) 515 break; 516 } 517 } 518 } 519 520 /* 521 * Mark the beginning and end LIR of a def sequence. Note that 522 * on entry start points to the LIR prior to the beginning of the 523 * sequence. 524 */ 525 extern void dvmCompilerMarkDef(CompilationUnit *cUnit, RegLocation rl, 526 LIR *start, LIR *finish) 527 { 528 assert(!rl.wide); 529 assert(start && start->next); 530 assert(finish); 531 RegisterInfo *p = getRegInfo(cUnit, rl.lowReg); 532 p->defStart = start->next; 533 p->defEnd = finish; 534 } 535 536 /* 537 * Mark the beginning and end LIR of a def sequence. Note that 538 * on entry start points to the LIR prior to the beginning of the 539 * sequence. 540 */ 541 extern void dvmCompilerMarkDefWide(CompilationUnit *cUnit, RegLocation rl, 542 LIR *start, LIR *finish) 543 { 544 assert(rl.wide); 545 assert(start && start->next); 546 assert(finish); 547 RegisterInfo *p = getRegInfo(cUnit, rl.lowReg); 548 dvmCompilerResetDef(cUnit, rl.highReg); // Only track low of pair 549 p->defStart = start->next; 550 p->defEnd = finish; 551 } 552 553 extern RegLocation dvmCompilerWideToNarrow(CompilationUnit *cUnit, 554 RegLocation rl) 555 { 556 assert(rl.wide); 557 if (rl.location == kLocPhysReg) { 558 RegisterInfo *infoLo = getRegInfo(cUnit, rl.lowReg); 559 RegisterInfo *infoHi = getRegInfo(cUnit, rl.highReg); 560 if (!infoLo->pair) { 561 dumpRegPool(cUnit->regPool->coreTemps, 562 cUnit->regPool->numCoreTemps); 563 assert(infoLo->pair); 564 } 565 if (!infoHi->pair) { 566 dumpRegPool(cUnit->regPool->coreTemps, 567 cUnit->regPool->numCoreTemps); 568 assert(infoHi->pair); 569 } 570 assert(infoLo->pair); 571 assert(infoHi->pair); 572 assert(infoLo->partner == infoHi->reg); 573 assert(infoHi->partner == infoLo->reg); 574 infoLo->pair = false; 575 infoHi->pair = false; 576 infoLo->defStart = NULL; 577 infoLo->defEnd = NULL; 578 infoHi->defStart = NULL; 579 infoHi->defEnd = NULL; 580 } 581 rl.wide = false; 582 return rl; 583 } 584 585 extern void dvmCompilerResetDefLoc(CompilationUnit *cUnit, RegLocation rl) 586 { 587 assert(!rl.wide); 588 if (!(gDvmJit.disableOpt & (1 << kSuppressLoads))) { 589 RegisterInfo *p = getRegInfo(cUnit, rl.lowReg); 590 assert(!p->pair); 591 nullifyRange(cUnit, p->defStart, p->defEnd, 592 p->sReg, rl.sRegLow); 593 } 594 dvmCompilerResetDef(cUnit, rl.lowReg); 595 } 596 597 extern void dvmCompilerResetDefLocWide(CompilationUnit *cUnit, RegLocation rl) 598 { 599 assert(rl.wide); 600 if (!(gDvmJit.disableOpt & (1 << kSuppressLoads))) { 601 RegisterInfo *p = getRegInfo(cUnit, rl.lowReg); 602 assert(p->pair); 603 nullifyRange(cUnit, p->defStart, p->defEnd, 604 p->sReg, rl.sRegLow); 605 } 606 dvmCompilerResetDef(cUnit, rl.lowReg); 607 dvmCompilerResetDef(cUnit, rl.highReg); 608 } 609 610 extern void dvmCompilerResetDefTracking(CompilationUnit *cUnit) 611 { 612 int i; 613 for (i=0; i< cUnit->regPool->numCoreTemps; i++) { 614 dvmCompilerResetDef(cUnit, cUnit->regPool->coreTemps[i].reg); 615 } 616 for (i=0; i< cUnit->regPool->numFPTemps; i++) { 617 dvmCompilerResetDef(cUnit, cUnit->regPool->FPTemps[i].reg); 618 } 619 } 620 621 extern void dvmCompilerClobberAllRegs(CompilationUnit *cUnit) 622 { 623 int i; 624 for (i=0; i< cUnit->regPool->numCoreTemps; i++) { 625 dvmCompilerClobber(cUnit, cUnit->regPool->coreTemps[i].reg); 626 } 627 for (i=0; i< cUnit->regPool->numFPTemps; i++) { 628 dvmCompilerClobber(cUnit, cUnit->regPool->FPTemps[i].reg); 629 } 630 } 631 632 /* To be used when explicitly managing register use */ 633 extern void dvmCompilerLockAllTemps(CompilationUnit *cUnit) 634 { 635 int i; 636 for (i=0; i< cUnit->regPool->numCoreTemps; i++) { 637 dvmCompilerLockTemp(cUnit, cUnit->regPool->coreTemps[i].reg); 638 } 639 } 640 641 // Make sure nothing is live and dirty 642 static void flushAllRegsBody(CompilationUnit *cUnit, RegisterInfo *info, 643 int numRegs) 644 { 645 int i; 646 for (i=0; i < numRegs; i++) { 647 if (info[i].live && info[i].dirty) { 648 if (info[i].pair) { 649 flushRegWide(cUnit, info[i].reg, info[i].partner); 650 } else { 651 flushReg(cUnit, info[i].reg); 652 } 653 } 654 } 655 } 656 657 extern void dvmCompilerFlushAllRegs(CompilationUnit *cUnit) 658 { 659 flushAllRegsBody(cUnit, cUnit->regPool->coreTemps, 660 cUnit->regPool->numCoreTemps); 661 flushAllRegsBody(cUnit, cUnit->regPool->FPTemps, 662 cUnit->regPool->numFPTemps); 663 dvmCompilerClobberAllRegs(cUnit); 664 } 665 666 667 //TUNING: rewrite all of this reg stuff. Probably use an attribute table 668 static bool regClassMatches(int regClass, int reg) 669 { 670 if (regClass == kAnyReg) { 671 return true; 672 } else if (regClass == kCoreReg) { 673 return !FPREG(reg); 674 } else { 675 return FPREG(reg); 676 } 677 } 678 679 extern void dvmCompilerMarkLive(CompilationUnit *cUnit, int reg, int sReg) 680 { 681 RegisterInfo *info = getRegInfo(cUnit, reg); 682 if ((info->reg == reg) && (info->sReg == sReg) && info->live) { 683 return; /* already live */ 684 } else if (sReg != INVALID_SREG) { 685 dvmCompilerClobberSReg(cUnit, sReg); 686 info->live = true; 687 } else { 688 /* Can't be live if no associated sReg */ 689 info->live = false; 690 } 691 info->sReg = sReg; 692 } 693 694 extern void dvmCompilerMarkPair(CompilationUnit *cUnit, int lowReg, int highReg) 695 { 696 RegisterInfo *infoLo = getRegInfo(cUnit, lowReg); 697 RegisterInfo *infoHi = getRegInfo(cUnit, highReg); 698 infoLo->pair = infoHi->pair = true; 699 infoLo->partner = highReg; 700 infoHi->partner = lowReg; 701 } 702 703 static void markRegSingle(CompilationUnit *cUnit, int reg) 704 { 705 RegisterInfo *info = getRegInfo(cUnit, reg); 706 info->pair = false; 707 } 708 709 extern void dvmCompilerMarkClean(CompilationUnit *cUnit, int reg) 710 { 711 RegisterInfo *info = getRegInfo(cUnit, reg); 712 info->dirty = false; 713 } 714 715 extern void dvmCompilerMarkDirty(CompilationUnit *cUnit, int reg) 716 { 717 RegisterInfo *info = getRegInfo(cUnit, reg); 718 info->dirty = true; 719 } 720 721 extern void dvmCompilerMarkInUse(CompilationUnit *cUnit, int reg) 722 { 723 RegisterInfo *info = getRegInfo(cUnit, reg); 724 info->inUse = true; 725 } 726 727 /* Return true if live & dirty */ 728 static bool isDirty(CompilationUnit *cUnit, int reg) 729 { 730 RegisterInfo *info = getRegInfo(cUnit, reg); 731 return (info && info->live && info->dirty); 732 } 733 734 void copyRegInfo(CompilationUnit *cUnit, int newReg, int oldReg) 735 { 736 RegisterInfo *newInfo = getRegInfo(cUnit, newReg); 737 RegisterInfo *oldInfo = getRegInfo(cUnit, oldReg); 738 *newInfo = *oldInfo; 739 newInfo->reg = newReg; 740 } 741 742 /* 743 * Return an updated location record with current in-register status. 744 * If the value lives in live temps, reflect that fact. No code 745 * is generated. The the live value is part of an older pair, 746 * clobber both low and high. 747 * TUNING: clobbering both is a bit heavy-handed, but the alternative 748 * is a bit complex when dealing with FP regs. Examine code to see 749 * if it's worthwhile trying to be more clever here. 750 */ 751 extern RegLocation dvmCompilerUpdateLoc(CompilationUnit *cUnit, RegLocation loc) 752 { 753 assert(!loc.wide); 754 if (loc.location == kLocDalvikFrame) { 755 RegisterInfo *infoLo = allocLive(cUnit, loc.sRegLow, kAnyReg); 756 if (infoLo) { 757 if (infoLo->pair) { 758 dvmCompilerClobber(cUnit, infoLo->reg); 759 dvmCompilerClobber(cUnit, infoLo->partner); 760 } else { 761 loc.lowReg = infoLo->reg; 762 loc.location = kLocPhysReg; 763 } 764 } 765 } 766 767 return loc; 768 } 769 770 /* see comments for updateLoc */ 771 extern RegLocation dvmCompilerUpdateLocWide(CompilationUnit *cUnit, 772 RegLocation loc) 773 { 774 assert(loc.wide); 775 if (loc.location == kLocDalvikFrame) { 776 // Are the dalvik regs already live in physical registers? 777 RegisterInfo *infoLo = allocLive(cUnit, loc.sRegLow, kAnyReg); 778 RegisterInfo *infoHi = allocLive(cUnit, 779 dvmCompilerSRegHi(loc.sRegLow), kAnyReg); 780 bool match = true; 781 match = match && (infoLo != NULL); 782 match = match && (infoHi != NULL); 783 // Are they both core or both FP? 784 match = match && (FPREG(infoLo->reg) == FPREG(infoHi->reg)); 785 // If a pair of floating point singles, are they properly aligned? 786 if (match && FPREG(infoLo->reg)) { 787 match &= ((infoLo->reg & 0x1) == 0); 788 match &= ((infoHi->reg - infoLo->reg) == 1); 789 } 790 // If previously used as a pair, it is the same pair? 791 if (match && (infoLo->pair || infoHi->pair)) { 792 match = (infoLo->pair == infoHi->pair); 793 match &= ((infoLo->reg == infoHi->partner) && 794 (infoHi->reg == infoLo->partner)); 795 } 796 if (match) { 797 // Can reuse - update the register usage info 798 loc.lowReg = infoLo->reg; 799 loc.highReg = infoHi->reg; 800 loc.location = kLocPhysReg; 801 dvmCompilerMarkPair(cUnit, loc.lowReg, loc.highReg); 802 assert(!FPREG(loc.lowReg) || ((loc.lowReg & 0x1) == 0)); 803 return loc; 804 } 805 // Can't easily reuse - clobber any overlaps 806 if (infoLo) { 807 dvmCompilerClobber(cUnit, infoLo->reg); 808 if (infoLo->pair) 809 dvmCompilerClobber(cUnit, infoLo->partner); 810 } 811 if (infoHi) { 812 dvmCompilerClobber(cUnit, infoHi->reg); 813 if (infoHi->pair) 814 dvmCompilerClobber(cUnit, infoHi->partner); 815 } 816 } 817 818 return loc; 819 } 820 821 static RegLocation evalLocWide(CompilationUnit *cUnit, RegLocation loc, 822 int regClass, bool update) 823 { 824 assert(loc.wide); 825 int newRegs; 826 int lowReg; 827 int highReg; 828 829 loc = dvmCompilerUpdateLocWide(cUnit, loc); 830 831 /* If already in registers, we can assume proper form. Right reg class? */ 832 if (loc.location == kLocPhysReg) { 833 assert(FPREG(loc.lowReg) == FPREG(loc.highReg)); 834 assert(!FPREG(loc.lowReg) || ((loc.lowReg & 0x1) == 0)); 835 if (!regClassMatches(regClass, loc.lowReg)) { 836 /* Wrong register class. Reallocate and copy */ 837 newRegs = dvmCompilerAllocTypedTempPair(cUnit, loc.fp, regClass); 838 lowReg = newRegs & 0xff; 839 highReg = (newRegs >> 8) & 0xff; 840 dvmCompilerRegCopyWide(cUnit, lowReg, highReg, loc.lowReg, 841 loc.highReg); 842 copyRegInfo(cUnit, lowReg, loc.lowReg); 843 copyRegInfo(cUnit, highReg, loc.highReg); 844 dvmCompilerClobber(cUnit, loc.lowReg); 845 dvmCompilerClobber(cUnit, loc.highReg); 846 loc.lowReg = lowReg; 847 loc.highReg = highReg; 848 dvmCompilerMarkPair(cUnit, loc.lowReg, loc.highReg); 849 assert(!FPREG(loc.lowReg) || ((loc.lowReg & 0x1) == 0)); 850 } 851 return loc; 852 } 853 854 assert((loc.location != kLocRetval) || (loc.sRegLow == INVALID_SREG)); 855 assert((loc.location != kLocRetval) || 856 (dvmCompilerSRegHi(loc.sRegLow) == INVALID_SREG)); 857 858 newRegs = dvmCompilerAllocTypedTempPair(cUnit, loc.fp, regClass); 859 loc.lowReg = newRegs & 0xff; 860 loc.highReg = (newRegs >> 8) & 0xff; 861 862 dvmCompilerMarkPair(cUnit, loc.lowReg, loc.highReg); 863 if (update) { 864 loc.location = kLocPhysReg; 865 dvmCompilerMarkLive(cUnit, loc.lowReg, loc.sRegLow); 866 dvmCompilerMarkLive(cUnit, loc.highReg, dvmCompilerSRegHi(loc.sRegLow)); 867 } 868 assert(!FPREG(loc.lowReg) || ((loc.lowReg & 0x1) == 0)); 869 return loc; 870 } 871 872 extern RegLocation dvmCompilerEvalLoc(CompilationUnit *cUnit, RegLocation loc, 873 int regClass, bool update) 874 { 875 RegisterInfo *infoLo = NULL; 876 int newReg; 877 if (loc.wide) 878 return evalLocWide(cUnit, loc, regClass, update); 879 loc = dvmCompilerUpdateLoc(cUnit, loc); 880 881 if (loc.location == kLocPhysReg) { 882 if (!regClassMatches(regClass, loc.lowReg)) { 883 /* Wrong register class. Realloc, copy and transfer ownership */ 884 newReg = dvmCompilerAllocTypedTemp(cUnit, loc.fp, regClass); 885 dvmCompilerRegCopy(cUnit, newReg, loc.lowReg); 886 copyRegInfo(cUnit, newReg, loc.lowReg); 887 dvmCompilerClobber(cUnit, loc.lowReg); 888 loc.lowReg = newReg; 889 } 890 return loc; 891 } 892 893 assert((loc.location != kLocRetval) || (loc.sRegLow == INVALID_SREG)); 894 895 newReg = dvmCompilerAllocTypedTemp(cUnit, loc.fp, regClass); 896 loc.lowReg = newReg; 897 898 if (update) { 899 loc.location = kLocPhysReg; 900 dvmCompilerMarkLive(cUnit, loc.lowReg, loc.sRegLow); 901 } 902 return loc; 903 } 904 905 static inline int getDestSSAName(MIR *mir, int num) 906 { 907 assert(mir->ssaRep->numDefs > num); 908 return mir->ssaRep->defs[num]; 909 } 910 911 // Get the LocRecord associated with an SSA name use. 912 extern RegLocation dvmCompilerGetSrc(CompilationUnit *cUnit, MIR *mir, int num) 913 { 914 RegLocation loc = cUnit->regLocation[ 915 SREG(cUnit, dvmCompilerSSASrc(mir, num))]; 916 loc.fp = cUnit->regLocation[dvmCompilerSSASrc(mir, num)].fp; 917 loc.wide = false; 918 return loc; 919 } 920 921 // Get the LocRecord associated with an SSA name def. 922 extern RegLocation dvmCompilerGetDest(CompilationUnit *cUnit, MIR *mir, 923 int num) 924 { 925 RegLocation loc = cUnit->regLocation[SREG(cUnit, getDestSSAName(mir, num))]; 926 loc.fp = cUnit->regLocation[getDestSSAName(mir, num)].fp; 927 loc.wide = false; 928 return loc; 929 } 930 931 static RegLocation getLocWide(CompilationUnit *cUnit, MIR *mir, 932 int low, int high, bool isSrc) 933 { 934 RegLocation lowLoc; 935 RegLocation highLoc; 936 /* Copy loc record for low word and patch in data from high word */ 937 if (isSrc) { 938 lowLoc = dvmCompilerGetSrc(cUnit, mir, low); 939 highLoc = dvmCompilerGetSrc(cUnit, mir, high); 940 } else { 941 lowLoc = dvmCompilerGetDest(cUnit, mir, low); 942 highLoc = dvmCompilerGetDest(cUnit, mir, high); 943 } 944 /* Avoid this case by either promoting both or neither. */ 945 assert(lowLoc.location == highLoc.location); 946 if (lowLoc.location == kLocPhysReg) { 947 /* This case shouldn't happen if we've named correctly */ 948 assert(lowLoc.fp == highLoc.fp); 949 } 950 lowLoc.wide = true; 951 lowLoc.highReg = highLoc.lowReg; 952 return lowLoc; 953 } 954 955 extern RegLocation dvmCompilerGetDestWide(CompilationUnit *cUnit, MIR *mir, 956 int low, int high) 957 { 958 return getLocWide(cUnit, mir, low, high, false); 959 } 960 961 extern RegLocation dvmCompilerGetSrcWide(CompilationUnit *cUnit, MIR *mir, 962 int low, int high) 963 { 964 return getLocWide(cUnit, mir, low, high, true); 965 } 966 967 extern RegLocation dvmCompilerGetReturnWide(CompilationUnit *cUnit) 968 { 969 RegLocation res = LOC_C_RETURN_WIDE; 970 dvmCompilerClobber(cUnit, r0); 971 dvmCompilerClobber(cUnit, r1); 972 dvmCompilerMarkInUse(cUnit, r0); 973 dvmCompilerMarkInUse(cUnit, r1); 974 dvmCompilerMarkPair(cUnit, res.lowReg, res.highReg); 975 return res; 976 } 977 978 extern RegLocation dvmCompilerGetReturnWideAlt(CompilationUnit *cUnit) 979 { 980 RegLocation res = LOC_C_RETURN_WIDE; 981 res.lowReg = r2; 982 res.highReg = r3; 983 dvmCompilerClobber(cUnit, r2); 984 dvmCompilerClobber(cUnit, r3); 985 dvmCompilerMarkInUse(cUnit, r2); 986 dvmCompilerMarkInUse(cUnit, r3); 987 dvmCompilerMarkPair(cUnit, res.lowReg, res.highReg); 988 return res; 989 } 990 991 extern RegLocation dvmCompilerGetReturn(CompilationUnit *cUnit) 992 { 993 RegLocation res = LOC_C_RETURN; 994 dvmCompilerClobber(cUnit, r0); 995 dvmCompilerMarkInUse(cUnit, r0); 996 return res; 997 } 998 999 extern RegLocation dvmCompilerGetReturnAlt(CompilationUnit *cUnit) 1000 { 1001 RegLocation res = LOC_C_RETURN; 1002 res.lowReg = r1; 1003 dvmCompilerClobber(cUnit, r1); 1004 dvmCompilerMarkInUse(cUnit, r1); 1005 return res; 1006 } 1007 1008 /* Kill the corresponding bit in the null-checked register list */ 1009 extern void dvmCompilerKillNullCheckedLoc(CompilationUnit *cUnit, 1010 RegLocation loc) 1011 { 1012 if (loc.location != kLocRetval) { 1013 assert(loc.sRegLow != INVALID_SREG); 1014 dvmClearBit(cUnit->regPool->nullCheckedRegs, loc.sRegLow); 1015 if (loc.wide) { 1016 assert(dvmCompilerSRegHi(loc.sRegLow) != INVALID_SREG); 1017 dvmClearBit(cUnit->regPool->nullCheckedRegs, 1018 dvmCompilerSRegHi(loc.sRegLow)); 1019 } 1020 } 1021 } 1022 1023 extern void dvmCompilerFlushRegWideForV5TEVFP(CompilationUnit *cUnit, 1024 int reg1, int reg2) 1025 { 1026 flushRegWide(cUnit, reg1, reg2); 1027 } 1028 1029 extern void dvmCompilerFlushRegForV5TEVFP(CompilationUnit *cUnit, int reg) 1030 { 1031 flushReg(cUnit, reg); 1032 } 1033