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 */ 71extern 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 */ 83extern 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 96static 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 108static 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 130static 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 149static 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 */ 161static 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. */ 190void 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 199static 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 */ 212extern 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 220static 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. 258extern 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 */ 306extern int dvmCompilerAllocFreeTemp(CompilationUnit *cUnit) 307{ 308 return allocTempBody(cUnit, cUnit->regPool->coreTemps, 309 cUnit->regPool->numCoreTemps, 310 &cUnit->regPool->nextCoreTemp, true); 311} 312 313extern int dvmCompilerAllocTemp(CompilationUnit *cUnit) 314{ 315 return allocTempBody(cUnit, cUnit->regPool->coreTemps, 316 cUnit->regPool->numCoreTemps, 317 &cUnit->regPool->nextCoreTemp, true); 318} 319 320extern int dvmCompilerAllocTempFloat(CompilationUnit *cUnit) 321{ 322 return allocTempBody(cUnit, cUnit->regPool->FPTemps, 323 cUnit->regPool->numFPTemps, 324 &cUnit->regPool->nextFPTemp, true); 325} 326 327static 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 341static 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 367extern 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 */ 396extern 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 416extern 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 */ 441extern 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/* Clobber all regs that might be used by an external C call */ 467extern void dvmCompilerClobberCallRegs(CompilationUnit *cUnit) 468{ 469 dvmCompilerClobber(cUnit, r0); 470 dvmCompilerClobber(cUnit, r1); 471 dvmCompilerClobber(cUnit, r2); 472 dvmCompilerClobber(cUnit, r3); 473 dvmCompilerClobber(cUnit, r9); // Need to do this?, be conservative 474 dvmCompilerClobber(cUnit, r11); 475 dvmCompilerClobber(cUnit, r12); 476 dvmCompilerClobber(cUnit, rlr); 477} 478 479/* Clobber all of the temps that might be used by a handler. */ 480extern void dvmCompilerClobberHandlerRegs(CompilationUnit *cUnit) 481{ 482 //TUNING: reduce the set of regs used by handlers. Only a few need lots. 483 dvmCompilerClobberCallRegs(cUnit); 484 dvmCompilerClobber(cUnit, r4PC); 485 dvmCompilerClobber(cUnit, r7); 486 dvmCompilerClobber(cUnit, r8); 487 dvmCompilerClobber(cUnit, r9); 488 dvmCompilerClobber(cUnit, r10); 489} 490 491extern void dvmCompilerResetDef(CompilationUnit *cUnit, int reg) 492{ 493 RegisterInfo *p = getRegInfo(cUnit, reg); 494 p->defStart = NULL; 495 p->defEnd = NULL; 496} 497 498static void nullifyRange(CompilationUnit *cUnit, LIR *start, LIR *finish, 499 int sReg1, int sReg2) 500{ 501 if (start && finish) { 502 LIR *p; 503 assert(sReg1 == sReg2); 504 for (p = start; ;p = p->next) { 505 ((ArmLIR *)p)->isNop = true; 506 if (p == finish) 507 break; 508 } 509 } 510} 511 512/* 513 * Mark the beginning and end LIR of a def sequence. Note that 514 * on entry start points to the LIR prior to the beginning of the 515 * sequence. 516 */ 517extern void dvmCompilerMarkDef(CompilationUnit *cUnit, RegLocation rl, 518 LIR *start, LIR *finish) 519{ 520 assert(!rl.wide); 521 assert(start && start->next); 522 assert(finish); 523 RegisterInfo *p = getRegInfo(cUnit, rl.lowReg); 524 p->defStart = start->next; 525 p->defEnd = finish; 526} 527 528/* 529 * Mark the beginning and end LIR of a def sequence. Note that 530 * on entry start points to the LIR prior to the beginning of the 531 * sequence. 532 */ 533extern void dvmCompilerMarkDefWide(CompilationUnit *cUnit, RegLocation rl, 534 LIR *start, LIR *finish) 535{ 536 assert(rl.wide); 537 assert(start && start->next); 538 assert(finish); 539 RegisterInfo *p = getRegInfo(cUnit, rl.lowReg); 540 dvmCompilerResetDef(cUnit, rl.highReg); // Only track low of pair 541 p->defStart = start->next; 542 p->defEnd = finish; 543} 544 545extern RegLocation dvmCompilerWideToNarrow(CompilationUnit *cUnit, 546 RegLocation rl) 547{ 548 assert(rl.wide); 549 if (rl.location == kLocPhysReg) { 550 RegisterInfo *infoLo = getRegInfo(cUnit, rl.lowReg); 551 RegisterInfo *infoHi = getRegInfo(cUnit, rl.highReg); 552 if (!infoLo->pair) { 553 dumpRegPool(cUnit->regPool->coreTemps, 554 cUnit->regPool->numCoreTemps); 555 assert(infoLo->pair); 556 } 557 if (!infoHi->pair) { 558 dumpRegPool(cUnit->regPool->coreTemps, 559 cUnit->regPool->numCoreTemps); 560 assert(infoHi->pair); 561 } 562 assert(infoLo->pair); 563 assert(infoHi->pair); 564 assert(infoLo->partner == infoHi->reg); 565 assert(infoHi->partner == infoLo->reg); 566 infoLo->pair = false; 567 infoHi->pair = false; 568 infoLo->defStart = NULL; 569 infoLo->defEnd = NULL; 570 infoHi->defStart = NULL; 571 infoHi->defEnd = NULL; 572 } 573 rl.wide = false; 574 return rl; 575} 576 577extern void dvmCompilerResetDefLoc(CompilationUnit *cUnit, RegLocation rl) 578{ 579 assert(!rl.wide); 580 if (!(gDvmJit.disableOpt & (1 << kSuppressLoads))) { 581 RegisterInfo *p = getRegInfo(cUnit, rl.lowReg); 582 assert(!p->pair); 583 nullifyRange(cUnit, p->defStart, p->defEnd, 584 p->sReg, rl.sRegLow); 585 } 586 dvmCompilerResetDef(cUnit, rl.lowReg); 587} 588 589extern void dvmCompilerResetDefLocWide(CompilationUnit *cUnit, RegLocation rl) 590{ 591 assert(rl.wide); 592 if (!(gDvmJit.disableOpt & (1 << kSuppressLoads))) { 593 RegisterInfo *p = getRegInfo(cUnit, rl.lowReg); 594 assert(p->pair); 595 nullifyRange(cUnit, p->defStart, p->defEnd, 596 p->sReg, rl.sRegLow); 597 } 598 dvmCompilerResetDef(cUnit, rl.lowReg); 599 dvmCompilerResetDef(cUnit, rl.highReg); 600} 601 602extern void dvmCompilerResetDefTracking(CompilationUnit *cUnit) 603{ 604 int i; 605 for (i=0; i< cUnit->regPool->numCoreTemps; i++) { 606 dvmCompilerResetDef(cUnit, cUnit->regPool->coreTemps[i].reg); 607 } 608 for (i=0; i< cUnit->regPool->numFPTemps; i++) { 609 dvmCompilerResetDef(cUnit, cUnit->regPool->FPTemps[i].reg); 610 } 611} 612 613extern void dvmCompilerClobberAllRegs(CompilationUnit *cUnit) 614{ 615 int i; 616 for (i=0; i< cUnit->regPool->numCoreTemps; i++) { 617 dvmCompilerClobber(cUnit, cUnit->regPool->coreTemps[i].reg); 618 } 619 for (i=0; i< cUnit->regPool->numFPTemps; i++) { 620 dvmCompilerClobber(cUnit, cUnit->regPool->FPTemps[i].reg); 621 } 622} 623 624/* To be used when explicitly managing register use */ 625extern void dvmCompilerLockAllTemps(CompilationUnit *cUnit) 626{ 627 int i; 628 for (i=0; i< cUnit->regPool->numCoreTemps; i++) { 629 dvmCompilerLockTemp(cUnit, cUnit->regPool->coreTemps[i].reg); 630 } 631} 632 633// Make sure nothing is live and dirty 634static void flushAllRegsBody(CompilationUnit *cUnit, RegisterInfo *info, 635 int numRegs) 636{ 637 int i; 638 for (i=0; i < numRegs; i++) { 639 if (info[i].live && info[i].dirty) { 640 if (info[i].pair) { 641 flushRegWide(cUnit, info[i].reg, info[i].partner); 642 } else { 643 flushReg(cUnit, info[i].reg); 644 } 645 } 646 } 647} 648 649extern void dvmCompilerFlushAllRegs(CompilationUnit *cUnit) 650{ 651 flushAllRegsBody(cUnit, cUnit->regPool->coreTemps, 652 cUnit->regPool->numCoreTemps); 653 flushAllRegsBody(cUnit, cUnit->regPool->FPTemps, 654 cUnit->regPool->numFPTemps); 655 dvmCompilerClobberAllRegs(cUnit); 656} 657 658 659//TUNING: rewrite all of this reg stuff. Probably use an attribute table 660static bool regClassMatches(int regClass, int reg) 661{ 662 if (regClass == kAnyReg) { 663 return true; 664 } else if (regClass == kCoreReg) { 665 return !FPREG(reg); 666 } else { 667 return FPREG(reg); 668 } 669} 670 671extern void dvmCompilerMarkLive(CompilationUnit *cUnit, int reg, int sReg) 672{ 673 RegisterInfo *info = getRegInfo(cUnit, reg); 674 if ((info->reg == reg) && (info->sReg == sReg) && info->live) { 675 return; /* already live */ 676 } else if (sReg != INVALID_SREG) { 677 dvmCompilerClobberSReg(cUnit, sReg); 678 info->live = true; 679 } else { 680 /* Can't be live if no associated sReg */ 681 info->live = false; 682 } 683 info->sReg = sReg; 684} 685 686extern void dvmCompilerMarkPair(CompilationUnit *cUnit, int lowReg, int highReg) 687{ 688 RegisterInfo *infoLo = getRegInfo(cUnit, lowReg); 689 RegisterInfo *infoHi = getRegInfo(cUnit, highReg); 690 infoLo->pair = infoHi->pair = true; 691 infoLo->partner = highReg; 692 infoHi->partner = lowReg; 693} 694 695extern void dvmCompilerMarkClean(CompilationUnit *cUnit, int reg) 696{ 697 RegisterInfo *info = getRegInfo(cUnit, reg); 698 info->dirty = false; 699} 700 701extern void dvmCompilerMarkDirty(CompilationUnit *cUnit, int reg) 702{ 703 RegisterInfo *info = getRegInfo(cUnit, reg); 704 info->dirty = true; 705} 706 707extern void dvmCompilerMarkInUse(CompilationUnit *cUnit, int reg) 708{ 709 RegisterInfo *info = getRegInfo(cUnit, reg); 710 info->inUse = true; 711} 712 713void copyRegInfo(CompilationUnit *cUnit, int newReg, int oldReg) 714{ 715 RegisterInfo *newInfo = getRegInfo(cUnit, newReg); 716 RegisterInfo *oldInfo = getRegInfo(cUnit, oldReg); 717 *newInfo = *oldInfo; 718 newInfo->reg = newReg; 719} 720 721/* 722 * Return an updated location record with current in-register status. 723 * If the value lives in live temps, reflect that fact. No code 724 * is generated. The the live value is part of an older pair, 725 * clobber both low and high. 726 * TUNING: clobbering both is a bit heavy-handed, but the alternative 727 * is a bit complex when dealing with FP regs. Examine code to see 728 * if it's worthwhile trying to be more clever here. 729 */ 730extern RegLocation dvmCompilerUpdateLoc(CompilationUnit *cUnit, RegLocation loc) 731{ 732 assert(!loc.wide); 733 if (loc.location == kLocDalvikFrame) { 734 RegisterInfo *infoLo = allocLive(cUnit, loc.sRegLow, kAnyReg); 735 if (infoLo) { 736 if (infoLo->pair) { 737 dvmCompilerClobber(cUnit, infoLo->reg); 738 dvmCompilerClobber(cUnit, infoLo->partner); 739 } else { 740 loc.lowReg = infoLo->reg; 741 loc.location = kLocPhysReg; 742 } 743 } 744 } 745 746 return loc; 747} 748 749/* see comments for updateLoc */ 750extern RegLocation dvmCompilerUpdateLocWide(CompilationUnit *cUnit, 751 RegLocation loc) 752{ 753 assert(loc.wide); 754 if (loc.location == kLocDalvikFrame) { 755 // Are the dalvik regs already live in physical registers? 756 RegisterInfo *infoLo = allocLive(cUnit, loc.sRegLow, kAnyReg); 757 RegisterInfo *infoHi = allocLive(cUnit, 758 dvmCompilerSRegHi(loc.sRegLow), kAnyReg); 759 bool match = true; 760 match = match && (infoLo != NULL); 761 match = match && (infoHi != NULL); 762 // Are they both core or both FP? 763 match = match && (FPREG(infoLo->reg) == FPREG(infoHi->reg)); 764 // If a pair of floating point singles, are they properly aligned? 765 if (match && FPREG(infoLo->reg)) { 766 match &= ((infoLo->reg & 0x1) == 0); 767 match &= ((infoHi->reg - infoLo->reg) == 1); 768 } 769 // If previously used as a pair, it is the same pair? 770 if (match && (infoLo->pair || infoHi->pair)) { 771 match = (infoLo->pair == infoHi->pair); 772 match &= ((infoLo->reg == infoHi->partner) && 773 (infoHi->reg == infoLo->partner)); 774 } 775 if (match) { 776 // Can reuse - update the register usage info 777 loc.lowReg = infoLo->reg; 778 loc.highReg = infoHi->reg; 779 loc.location = kLocPhysReg; 780 dvmCompilerMarkPair(cUnit, loc.lowReg, loc.highReg); 781 assert(!FPREG(loc.lowReg) || ((loc.lowReg & 0x1) == 0)); 782 return loc; 783 } 784 // Can't easily reuse - clobber any overlaps 785 if (infoLo) { 786 dvmCompilerClobber(cUnit, infoLo->reg); 787 if (infoLo->pair) 788 dvmCompilerClobber(cUnit, infoLo->partner); 789 } 790 if (infoHi) { 791 dvmCompilerClobber(cUnit, infoHi->reg); 792 if (infoHi->pair) 793 dvmCompilerClobber(cUnit, infoHi->partner); 794 } 795 } 796 797 return loc; 798} 799 800static RegLocation evalLocWide(CompilationUnit *cUnit, RegLocation loc, 801 int regClass, bool update) 802{ 803 assert(loc.wide); 804 int newRegs; 805 int lowReg; 806 int highReg; 807 808 loc = dvmCompilerUpdateLocWide(cUnit, loc); 809 810 /* If already in registers, we can assume proper form. Right reg class? */ 811 if (loc.location == kLocPhysReg) { 812 assert(FPREG(loc.lowReg) == FPREG(loc.highReg)); 813 assert(!FPREG(loc.lowReg) || ((loc.lowReg & 0x1) == 0)); 814 if (!regClassMatches(regClass, loc.lowReg)) { 815 /* Wrong register class. Reallocate and copy */ 816 newRegs = dvmCompilerAllocTypedTempPair(cUnit, loc.fp, regClass); 817 lowReg = newRegs & 0xff; 818 highReg = (newRegs >> 8) & 0xff; 819 dvmCompilerRegCopyWide(cUnit, lowReg, highReg, loc.lowReg, 820 loc.highReg); 821 copyRegInfo(cUnit, lowReg, loc.lowReg); 822 copyRegInfo(cUnit, highReg, loc.highReg); 823 dvmCompilerClobber(cUnit, loc.lowReg); 824 dvmCompilerClobber(cUnit, loc.highReg); 825 loc.lowReg = lowReg; 826 loc.highReg = highReg; 827 dvmCompilerMarkPair(cUnit, loc.lowReg, loc.highReg); 828 assert(!FPREG(loc.lowReg) || ((loc.lowReg & 0x1) == 0)); 829 } 830 return loc; 831 } 832 833 assert((loc.location != kLocRetval) || (loc.sRegLow == INVALID_SREG)); 834 assert((loc.location != kLocRetval) || 835 (dvmCompilerSRegHi(loc.sRegLow) == INVALID_SREG)); 836 837 newRegs = dvmCompilerAllocTypedTempPair(cUnit, loc.fp, regClass); 838 loc.lowReg = newRegs & 0xff; 839 loc.highReg = (newRegs >> 8) & 0xff; 840 841 dvmCompilerMarkPair(cUnit, loc.lowReg, loc.highReg); 842 if (update) { 843 loc.location = kLocPhysReg; 844 dvmCompilerMarkLive(cUnit, loc.lowReg, loc.sRegLow); 845 dvmCompilerMarkLive(cUnit, loc.highReg, dvmCompilerSRegHi(loc.sRegLow)); 846 } 847 assert(!FPREG(loc.lowReg) || ((loc.lowReg & 0x1) == 0)); 848 return loc; 849} 850 851extern RegLocation dvmCompilerEvalLoc(CompilationUnit *cUnit, RegLocation loc, 852 int regClass, bool update) 853{ 854 int newReg; 855 if (loc.wide) 856 return evalLocWide(cUnit, loc, regClass, update); 857 loc = dvmCompilerUpdateLoc(cUnit, loc); 858 859 if (loc.location == kLocPhysReg) { 860 if (!regClassMatches(regClass, loc.lowReg)) { 861 /* Wrong register class. Realloc, copy and transfer ownership */ 862 newReg = dvmCompilerAllocTypedTemp(cUnit, loc.fp, regClass); 863 dvmCompilerRegCopy(cUnit, newReg, loc.lowReg); 864 copyRegInfo(cUnit, newReg, loc.lowReg); 865 dvmCompilerClobber(cUnit, loc.lowReg); 866 loc.lowReg = newReg; 867 } 868 return loc; 869 } 870 871 assert((loc.location != kLocRetval) || (loc.sRegLow == INVALID_SREG)); 872 873 newReg = dvmCompilerAllocTypedTemp(cUnit, loc.fp, regClass); 874 loc.lowReg = newReg; 875 876 if (update) { 877 loc.location = kLocPhysReg; 878 dvmCompilerMarkLive(cUnit, loc.lowReg, loc.sRegLow); 879 } 880 return loc; 881} 882 883static inline int getDestSSAName(MIR *mir, int num) 884{ 885 assert(mir->ssaRep->numDefs > num); 886 return mir->ssaRep->defs[num]; 887} 888 889// Get the LocRecord associated with an SSA name use. 890extern RegLocation dvmCompilerGetSrc(CompilationUnit *cUnit, MIR *mir, int num) 891{ 892 RegLocation loc = cUnit->regLocation[ 893 SREG(cUnit, dvmCompilerSSASrc(mir, num))]; 894 loc.fp = cUnit->regLocation[dvmCompilerSSASrc(mir, num)].fp; 895 loc.wide = false; 896 return loc; 897} 898 899// Get the LocRecord associated with an SSA name def. 900extern RegLocation dvmCompilerGetDest(CompilationUnit *cUnit, MIR *mir, 901 int num) 902{ 903 RegLocation loc = cUnit->regLocation[SREG(cUnit, getDestSSAName(mir, num))]; 904 loc.fp = cUnit->regLocation[getDestSSAName(mir, num)].fp; 905 loc.wide = false; 906 return loc; 907} 908 909static RegLocation getLocWide(CompilationUnit *cUnit, MIR *mir, 910 int low, int high, bool isSrc) 911{ 912 RegLocation lowLoc; 913 RegLocation highLoc; 914 /* Copy loc record for low word and patch in data from high word */ 915 if (isSrc) { 916 lowLoc = dvmCompilerGetSrc(cUnit, mir, low); 917 highLoc = dvmCompilerGetSrc(cUnit, mir, high); 918 } else { 919 lowLoc = dvmCompilerGetDest(cUnit, mir, low); 920 highLoc = dvmCompilerGetDest(cUnit, mir, high); 921 } 922 /* Avoid this case by either promoting both or neither. */ 923 assert(lowLoc.location == highLoc.location); 924 if (lowLoc.location == kLocPhysReg) { 925 /* This case shouldn't happen if we've named correctly */ 926 assert(lowLoc.fp == highLoc.fp); 927 } 928 lowLoc.wide = true; 929 lowLoc.highReg = highLoc.lowReg; 930 return lowLoc; 931} 932 933extern RegLocation dvmCompilerGetDestWide(CompilationUnit *cUnit, MIR *mir, 934 int low, int high) 935{ 936 return getLocWide(cUnit, mir, low, high, false); 937} 938 939extern RegLocation dvmCompilerGetSrcWide(CompilationUnit *cUnit, MIR *mir, 940 int low, int high) 941{ 942 return getLocWide(cUnit, mir, low, high, true); 943} 944 945extern RegLocation dvmCompilerGetReturnWide(CompilationUnit *cUnit) 946{ 947 RegLocation res = LOC_C_RETURN_WIDE; 948 dvmCompilerClobber(cUnit, r0); 949 dvmCompilerClobber(cUnit, r1); 950 dvmCompilerMarkInUse(cUnit, r0); 951 dvmCompilerMarkInUse(cUnit, r1); 952 dvmCompilerMarkPair(cUnit, res.lowReg, res.highReg); 953 return res; 954} 955 956extern RegLocation dvmCompilerGetReturnWideAlt(CompilationUnit *cUnit) 957{ 958 RegLocation res = LOC_C_RETURN_WIDE; 959 res.lowReg = r2; 960 res.highReg = r3; 961 dvmCompilerClobber(cUnit, r2); 962 dvmCompilerClobber(cUnit, r3); 963 dvmCompilerMarkInUse(cUnit, r2); 964 dvmCompilerMarkInUse(cUnit, r3); 965 dvmCompilerMarkPair(cUnit, res.lowReg, res.highReg); 966 return res; 967} 968 969extern RegLocation dvmCompilerGetReturn(CompilationUnit *cUnit) 970{ 971 RegLocation res = LOC_C_RETURN; 972 dvmCompilerClobber(cUnit, r0); 973 dvmCompilerMarkInUse(cUnit, r0); 974 return res; 975} 976 977extern RegLocation dvmCompilerGetReturnAlt(CompilationUnit *cUnit) 978{ 979 RegLocation res = LOC_C_RETURN; 980 res.lowReg = r1; 981 dvmCompilerClobber(cUnit, r1); 982 dvmCompilerMarkInUse(cUnit, r1); 983 return res; 984} 985 986/* Kill the corresponding bit in the null-checked register list */ 987extern void dvmCompilerKillNullCheckedLoc(CompilationUnit *cUnit, 988 RegLocation loc) 989{ 990 if (loc.location != kLocRetval) { 991 assert(loc.sRegLow != INVALID_SREG); 992 dvmClearBit(cUnit->regPool->nullCheckedRegs, loc.sRegLow); 993 if (loc.wide) { 994 assert(dvmCompilerSRegHi(loc.sRegLow) != INVALID_SREG); 995 dvmClearBit(cUnit->regPool->nullCheckedRegs, 996 dvmCompilerSRegHi(loc.sRegLow)); 997 } 998 } 999} 1000 1001extern void dvmCompilerFlushRegWideForV5TEVFP(CompilationUnit *cUnit, 1002 int reg1, int reg2) 1003{ 1004 flushRegWide(cUnit, reg1, reg2); 1005} 1006 1007extern void dvmCompilerFlushRegForV5TEVFP(CompilationUnit *cUnit, int reg) 1008{ 1009 flushReg(cUnit, reg); 1010} 1011