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 codegen for the Thumb ISA and is intended to be 19 * includes by: 20 * 21 * Codegen-$(TARGET_ARCH_VARIANT).c 22 * 23 */ 24 25static int coreTemps[] = {r_V0, r_V1, r_A0, r_A1, r_A2, r_A3, r_T0, r_T1, r_T2, 26 r_T3, r_T4, r_T5, r_T6, r_T7, r_T8, r_T9, r_S0, r_S4}; 27#ifdef __mips_hard_float 28static int fpTemps[] = {r_F0, r_F1, r_F2, r_F3, r_F4, r_F5, r_F6, r_F7, 29 r_F8, r_F9, r_F10, r_F11, r_F12, r_F13, r_F14, r_F15}; 30#endif 31 32static void storePair(CompilationUnit *cUnit, int base, int lowReg, 33 int highReg); 34static void loadPair(CompilationUnit *cUnit, int base, int lowReg, int highReg); 35static MipsLIR *loadWordDisp(CompilationUnit *cUnit, int rBase, int displacement, 36 int rDest); 37static MipsLIR *storeWordDisp(CompilationUnit *cUnit, int rBase, 38 int displacement, int rSrc); 39static MipsLIR *genRegRegCheck(CompilationUnit *cUnit, 40 MipsConditionCode cond, 41 int reg1, int reg2, int dOffset, 42 MipsLIR *pcrLabel); 43static MipsLIR *loadConstant(CompilationUnit *cUnit, int rDest, int value); 44 45#ifdef __mips_hard_float 46static MipsLIR *fpRegCopy(CompilationUnit *cUnit, int rDest, int rSrc) 47{ 48 MipsLIR* res = (MipsLIR *) dvmCompilerNew(sizeof(MipsLIR), true); 49 res->operands[0] = rDest; 50 res->operands[1] = rSrc; 51 if (rDest == rSrc) { 52 res->flags.isNop = true; 53 } else { 54 /* must be both DOUBLE or both not DOUBLE */ 55 assert(DOUBLEREG(rDest) == DOUBLEREG(rSrc)); 56 if (DOUBLEREG(rDest)) { 57 res->opcode = kMipsFmovd; 58 } else { 59 if (SINGLEREG(rDest)) { 60 if (SINGLEREG(rSrc)) { 61 res->opcode = kMipsFmovs; 62 } else { 63 /* note the operands are swapped for the mtc1 instr */ 64 res->opcode = kMipsMtc1; 65 res->operands[0] = rSrc; 66 res->operands[1] = rDest; 67 } 68 } else { 69 assert(SINGLEREG(rSrc)); 70 res->opcode = kMipsMfc1; 71 } 72 } 73 } 74 setupResourceMasks(res); 75 return res; 76} 77#endif 78 79/* 80 * Load a immediate using a shortcut if possible; otherwise 81 * grab from the per-translation literal pool. If target is 82 * a high register, build constant into a low register and copy. 83 * 84 * No additional register clobbering operation performed. Use this version when 85 * 1) rDest is freshly returned from dvmCompilerAllocTemp or 86 * 2) The codegen is under fixed register usage 87 */ 88static MipsLIR *loadConstantNoClobber(CompilationUnit *cUnit, int rDest, 89 int value) 90{ 91 MipsLIR *res; 92 93#ifdef __mips_hard_float 94 int rDestSave = rDest; 95 int isFpReg = FPREG(rDest); 96 if (isFpReg) { 97 assert(SINGLEREG(rDest)); 98 rDest = dvmCompilerAllocTemp(cUnit); 99 } 100#endif 101 102 /* See if the value can be constructed cheaply */ 103 if (value == 0) { 104 res = newLIR2(cUnit, kMipsMove, rDest, r_ZERO); 105 } else if ((value > 0) && (value <= 65535)) { 106 res = newLIR3(cUnit, kMipsOri, rDest, r_ZERO, value); 107 } else if ((value < 0) && (value >= -32768)) { 108 res = newLIR3(cUnit, kMipsAddiu, rDest, r_ZERO, value); 109 } else { 110 res = newLIR2(cUnit, kMipsLui, rDest, value>>16); 111 if (value & 0xffff) 112 newLIR3(cUnit, kMipsOri, rDest, rDest, value); 113 } 114 115#ifdef __mips_hard_float 116 if (isFpReg) { 117 newLIR2(cUnit, kMipsMtc1, rDest, rDestSave); 118 dvmCompilerFreeTemp(cUnit, rDest); 119 } 120#endif 121 122 return res; 123} 124 125/* 126 * Load an immediate value into a fixed or temp register. Target 127 * register is clobbered, and marked inUse. 128 */ 129static MipsLIR *loadConstant(CompilationUnit *cUnit, int rDest, int value) 130{ 131 if (dvmCompilerIsTemp(cUnit, rDest)) { 132 dvmCompilerClobber(cUnit, rDest); 133 dvmCompilerMarkInUse(cUnit, rDest); 134 } 135 return loadConstantNoClobber(cUnit, rDest, value); 136} 137 138/* 139 * Load a class pointer value into a fixed or temp register. Target 140 * register is clobbered, and marked inUse. 141 */ 142static MipsLIR *loadClassPointer(CompilationUnit *cUnit, int rDest, int value) 143{ 144 MipsLIR *res; 145 if (dvmCompilerIsTemp(cUnit, rDest)) { 146 dvmCompilerClobber(cUnit, rDest); 147 dvmCompilerMarkInUse(cUnit, rDest); 148 } 149 res = newLIR2(cUnit, kMipsLui, rDest, value>>16); 150 if (value & 0xffff) 151 newLIR3(cUnit, kMipsOri, rDest, rDest, value); 152 return res; 153} 154 155static MipsLIR *opNone(CompilationUnit *cUnit, OpKind op) 156{ 157 MipsLIR *res; 158 MipsOpCode opcode = kMipsNop; 159 switch (op) { 160 case kOpUncondBr: 161 opcode = kMipsB; 162 break; 163 default: 164 ALOGE("Jit: bad case in opNone"); 165 dvmCompilerAbort(cUnit); 166 } 167 res = newLIR0(cUnit, opcode); 168 return res; 169} 170 171static MipsLIR *opCompareBranch(CompilationUnit *cUnit, MipsOpCode opc, int rs, int rt) 172{ 173 MipsLIR *res; 174 if (rt < 0) { 175 assert(opc >= kMipsBeqz && opc <= kMipsBnez); 176 res = newLIR1(cUnit, opc, rs); 177 } else { 178 assert(opc == kMipsBeq || opc == kMipsBne); 179 res = newLIR2(cUnit, opc, rs, rt); 180 } 181 return res; 182} 183 184static MipsLIR *loadMultiple(CompilationUnit *cUnit, int rBase, int rMask); 185 186static MipsLIR *opReg(CompilationUnit *cUnit, OpKind op, int rDestSrc) 187{ 188 MipsOpCode opcode = kMipsNop; 189 switch (op) { 190 case kOpBlx: 191 opcode = kMipsJalr; 192 break; 193 default: 194 assert(0); 195 } 196 return newLIR2(cUnit, opcode, r_RA, rDestSrc); 197} 198 199static MipsLIR *opRegRegImm(CompilationUnit *cUnit, OpKind op, int rDest, 200 int rSrc1, int value); 201static MipsLIR *opRegImm(CompilationUnit *cUnit, OpKind op, int rDestSrc1, 202 int value) 203{ 204 MipsLIR *res; 205 bool neg = (value < 0); 206 int absValue = (neg) ? -value : value; 207 bool shortForm = (absValue & 0xff) == absValue; 208 MipsOpCode opcode = kMipsNop; 209 switch (op) { 210 case kOpAdd: 211 return opRegRegImm(cUnit, op, rDestSrc1, rDestSrc1, value); 212 break; 213 case kOpSub: 214 return opRegRegImm(cUnit, op, rDestSrc1, rDestSrc1, value); 215 break; 216 default: 217 ALOGE("Jit: bad case in opRegImm"); 218 dvmCompilerAbort(cUnit); 219 break; 220 } 221 if (shortForm) 222 res = newLIR2(cUnit, opcode, rDestSrc1, absValue); 223 else { 224 int rScratch = dvmCompilerAllocTemp(cUnit); 225 res = loadConstant(cUnit, rScratch, value); 226 if (op == kOpCmp) 227 newLIR2(cUnit, opcode, rDestSrc1, rScratch); 228 else 229 newLIR3(cUnit, opcode, rDestSrc1, rDestSrc1, rScratch); 230 } 231 return res; 232} 233 234static MipsLIR *opRegRegReg(CompilationUnit *cUnit, OpKind op, int rDest, 235 int rSrc1, int rSrc2) 236{ 237 MipsOpCode opcode = kMipsNop; 238 switch (op) { 239 case kOpAdd: 240 opcode = kMipsAddu; 241 break; 242 case kOpSub: 243 opcode = kMipsSubu; 244 break; 245 case kOpAnd: 246 opcode = kMipsAnd; 247 break; 248 case kOpMul: 249 opcode = kMipsMul; 250 break; 251 case kOpOr: 252 opcode = kMipsOr; 253 break; 254 case kOpXor: 255 opcode = kMipsXor; 256 break; 257 case kOpLsl: 258 opcode = kMipsSllv; 259 break; 260 case kOpLsr: 261 opcode = kMipsSrlv; 262 break; 263 case kOpAsr: 264 opcode = kMipsSrav; 265 break; 266 default: 267 ALOGE("Jit: bad case in opRegRegReg"); 268 dvmCompilerAbort(cUnit); 269 break; 270 } 271 return newLIR3(cUnit, opcode, rDest, rSrc1, rSrc2); 272} 273 274static MipsLIR *opRegRegImm(CompilationUnit *cUnit, OpKind op, int rDest, 275 int rSrc1, int value) 276{ 277 MipsLIR *res; 278 MipsOpCode opcode = kMipsNop; 279 bool shortForm = true; 280 281 switch(op) { 282 case kOpAdd: 283 if (IS_SIMM16(value)) { 284 opcode = kMipsAddiu; 285 } 286 else { 287 shortForm = false; 288 opcode = kMipsAddu; 289 } 290 break; 291 case kOpSub: 292 if (IS_SIMM16((-value))) { 293 value = -value; 294 opcode = kMipsAddiu; 295 } 296 else { 297 shortForm = false; 298 opcode = kMipsSubu; 299 } 300 break; 301 case kOpLsl: 302 assert(value >= 0 && value <= 31); 303 opcode = kMipsSll; 304 break; 305 case kOpLsr: 306 assert(value >= 0 && value <= 31); 307 opcode = kMipsSrl; 308 break; 309 case kOpAsr: 310 assert(value >= 0 && value <= 31); 311 opcode = kMipsSra; 312 break; 313 case kOpAnd: 314 if (IS_UIMM16((value))) { 315 opcode = kMipsAndi; 316 } 317 else { 318 shortForm = false; 319 opcode = kMipsAnd; 320 } 321 break; 322 case kOpOr: 323 if (IS_UIMM16((value))) { 324 opcode = kMipsOri; 325 } 326 else { 327 shortForm = false; 328 opcode = kMipsOr; 329 } 330 break; 331 case kOpXor: 332 if (IS_UIMM16((value))) { 333 opcode = kMipsXori; 334 } 335 else { 336 shortForm = false; 337 opcode = kMipsXor; 338 } 339 break; 340 case kOpMul: 341 shortForm = false; 342 opcode = kMipsMul; 343 break; 344 default: 345 ALOGE("Jit: bad case in opRegRegImm"); 346 dvmCompilerAbort(cUnit); 347 break; 348 } 349 350 if (shortForm) 351 res = newLIR3(cUnit, opcode, rDest, rSrc1, value); 352 else { 353 if (rDest != rSrc1) { 354 res = loadConstant(cUnit, rDest, value); 355 newLIR3(cUnit, opcode, rDest, rSrc1, rDest); 356 } else { 357 int rScratch = dvmCompilerAllocTemp(cUnit); 358 res = loadConstant(cUnit, rScratch, value); 359 newLIR3(cUnit, opcode, rDest, rSrc1, rScratch); 360 } 361 } 362 return res; 363} 364 365static MipsLIR *opRegReg(CompilationUnit *cUnit, OpKind op, int rDestSrc1, 366 int rSrc2) 367{ 368 MipsOpCode opcode = kMipsNop; 369 MipsLIR *res; 370 switch (op) { 371 case kOpMov: 372 opcode = kMipsMove; 373 break; 374 case kOpMvn: 375 return newLIR3(cUnit, kMipsNor, rDestSrc1, rSrc2, r_ZERO); 376 case kOpNeg: 377 return newLIR3(cUnit, kMipsSubu, rDestSrc1, r_ZERO, rSrc2); 378 case kOpAdd: 379 case kOpAnd: 380 case kOpMul: 381 case kOpOr: 382 case kOpSub: 383 case kOpXor: 384 return opRegRegReg(cUnit, op, rDestSrc1, rDestSrc1, rSrc2); 385 case kOp2Byte: 386#if __mips_isa_rev>=2 387 res = newLIR2(cUnit, kMipsSeb, rDestSrc1, rSrc2); 388#else 389 res = opRegRegImm(cUnit, kOpLsl, rDestSrc1, rSrc2, 24); 390 opRegRegImm(cUnit, kOpAsr, rDestSrc1, rDestSrc1, 24); 391#endif 392 return res; 393 case kOp2Short: 394#if __mips_isa_rev>=2 395 res = newLIR2(cUnit, kMipsSeh, rDestSrc1, rSrc2); 396#else 397 res = opRegRegImm(cUnit, kOpLsl, rDestSrc1, rSrc2, 16); 398 opRegRegImm(cUnit, kOpAsr, rDestSrc1, rDestSrc1, 16); 399#endif 400 return res; 401 case kOp2Char: 402 return newLIR3(cUnit, kMipsAndi, rDestSrc1, rSrc2, 0xFFFF); 403 default: 404 ALOGE("Jit: bad case in opRegReg"); 405 dvmCompilerAbort(cUnit); 406 break; 407 } 408 return newLIR2(cUnit, opcode, rDestSrc1, rSrc2); 409} 410 411static MipsLIR *loadConstantValueWide(CompilationUnit *cUnit, int rDestLo, 412 int rDestHi, int valLo, int valHi) 413{ 414 MipsLIR *res; 415 res = loadConstantNoClobber(cUnit, rDestLo, valLo); 416 loadConstantNoClobber(cUnit, rDestHi, valHi); 417 return res; 418} 419 420/* Load value from base + scaled index. */ 421static MipsLIR *loadBaseIndexed(CompilationUnit *cUnit, int rBase, 422 int rIndex, int rDest, int scale, OpSize size) 423{ 424 MipsLIR *first = NULL; 425 MipsLIR *res; 426 MipsOpCode opcode = kMipsNop; 427 int tReg = dvmCompilerAllocTemp(cUnit); 428 429#ifdef __mips_hard_float 430 if (FPREG(rDest)) { 431 assert(SINGLEREG(rDest)); 432 assert((size == kWord) || (size == kSingle)); 433 size = kSingle; 434 } else { 435 if (size == kSingle) 436 size = kWord; 437 } 438#endif 439 440 if (!scale) { 441 first = newLIR3(cUnit, kMipsAddu, tReg , rBase, rIndex); 442 } else { 443 first = opRegRegImm(cUnit, kOpLsl, tReg, rIndex, scale); 444 newLIR3(cUnit, kMipsAddu, tReg , rBase, tReg); 445 } 446 447 switch (size) { 448#ifdef __mips_hard_float 449 case kSingle: 450 opcode = kMipsFlwc1; 451 break; 452#endif 453 case kWord: 454 opcode = kMipsLw; 455 break; 456 case kUnsignedHalf: 457 opcode = kMipsLhu; 458 break; 459 case kSignedHalf: 460 opcode = kMipsLh; 461 break; 462 case kUnsignedByte: 463 opcode = kMipsLbu; 464 break; 465 case kSignedByte: 466 opcode = kMipsLb; 467 break; 468 default: 469 ALOGE("Jit: bad case in loadBaseIndexed"); 470 dvmCompilerAbort(cUnit); 471 } 472 473 res = newLIR3(cUnit, opcode, rDest, 0, tReg); 474#if defined(WITH_SELF_VERIFICATION) 475 if (cUnit->heapMemOp) 476 res->flags.insertWrapper = true; 477#endif 478 dvmCompilerFreeTemp(cUnit, tReg); 479 return (first) ? first : res; 480} 481 482/* store value base base + scaled index. */ 483static MipsLIR *storeBaseIndexed(CompilationUnit *cUnit, int rBase, 484 int rIndex, int rSrc, int scale, OpSize size) 485{ 486 MipsLIR *first = NULL; 487 MipsLIR *res; 488 MipsOpCode opcode = kMipsNop; 489 int rNewIndex = rIndex; 490 int tReg = dvmCompilerAllocTemp(cUnit); 491 492#ifdef __mips_hard_float 493 if (FPREG(rSrc)) { 494 assert(SINGLEREG(rSrc)); 495 assert((size == kWord) || (size == kSingle)); 496 size = kSingle; 497 } else { 498 if (size == kSingle) 499 size = kWord; 500 } 501#endif 502 503 if (!scale) { 504 first = newLIR3(cUnit, kMipsAddu, tReg , rBase, rIndex); 505 } else { 506 first = opRegRegImm(cUnit, kOpLsl, tReg, rIndex, scale); 507 newLIR3(cUnit, kMipsAddu, tReg , rBase, tReg); 508 } 509 510 switch (size) { 511#ifdef __mips_hard_float 512 case kSingle: 513 opcode = kMipsFswc1; 514 break; 515#endif 516 case kWord: 517 opcode = kMipsSw; 518 break; 519 case kUnsignedHalf: 520 case kSignedHalf: 521 opcode = kMipsSh; 522 break; 523 case kUnsignedByte: 524 case kSignedByte: 525 opcode = kMipsSb; 526 break; 527 default: 528 ALOGE("Jit: bad case in storeBaseIndexed"); 529 dvmCompilerAbort(cUnit); 530 } 531 res = newLIR3(cUnit, opcode, rSrc, 0, tReg); 532#if defined(WITH_SELF_VERIFICATION) 533 if (cUnit->heapMemOp) 534 res->flags.insertWrapper = true; 535#endif 536 dvmCompilerFreeTemp(cUnit, rNewIndex); 537 return first; 538} 539 540static MipsLIR *loadMultiple(CompilationUnit *cUnit, int rBase, int rMask) 541{ 542 int i; 543 int loadCnt = 0; 544 MipsLIR *res = NULL ; 545 genBarrier(cUnit); 546 547 for (i = 0; i < 8; i++, rMask >>= 1) { 548 if (rMask & 0x1) { /* map r0 to MIPS r_A0 */ 549 newLIR3(cUnit, kMipsLw, i+r_A0, loadCnt*4, rBase); 550 loadCnt++; 551 } 552 } 553 554 if (loadCnt) {/* increment after */ 555 newLIR3(cUnit, kMipsAddiu, rBase, rBase, loadCnt*4); 556 } 557 558#if defined(WITH_SELF_VERIFICATION) 559 if (cUnit->heapMemOp) 560 res->flags.insertWrapper = true; 561#endif 562 genBarrier(cUnit); 563 return res; /* NULL always returned which should be ok since no callers use it */ 564} 565 566static MipsLIR *storeMultiple(CompilationUnit *cUnit, int rBase, int rMask) 567{ 568 int i; 569 int storeCnt = 0; 570 MipsLIR *res = NULL ; 571 genBarrier(cUnit); 572 573 for (i = 0; i < 8; i++, rMask >>= 1) { 574 if (rMask & 0x1) { /* map r0 to MIPS r_A0 */ 575 newLIR3(cUnit, kMipsSw, i+r_A0, storeCnt*4, rBase); 576 storeCnt++; 577 } 578 } 579 580 if (storeCnt) { /* increment after */ 581 newLIR3(cUnit, kMipsAddiu, rBase, rBase, storeCnt*4); 582 } 583 584#if defined(WITH_SELF_VERIFICATION) 585 if (cUnit->heapMemOp) 586 res->flags.insertWrapper = true; 587#endif 588 genBarrier(cUnit); 589 return res; /* NULL always returned which should be ok since no callers use it */ 590} 591 592static MipsLIR *loadBaseDispBody(CompilationUnit *cUnit, MIR *mir, int rBase, 593 int displacement, int rDest, int rDestHi, 594 OpSize size, int sReg) 595/* 596 * Load value from base + displacement. Optionally perform null check 597 * on base (which must have an associated sReg and MIR). If not 598 * performing null check, incoming MIR can be null. IMPORTANT: this 599 * code must not allocate any new temps. If a new register is needed 600 * and base and dest are the same, spill some other register to 601 * rlp and then restore. 602 */ 603{ 604 MipsLIR *res; 605 MipsLIR *load = NULL; 606 MipsLIR *load2 = NULL; 607 MipsOpCode opcode = kMipsNop; 608 bool shortForm = IS_SIMM16(displacement); 609 bool pair = false; 610 611 switch (size) { 612 case kLong: 613 case kDouble: 614 pair = true; 615 opcode = kMipsLw; 616#ifdef __mips_hard_float 617 if (FPREG(rDest)) { 618 opcode = kMipsFlwc1; 619 if (DOUBLEREG(rDest)) { 620 rDest = rDest - FP_DOUBLE; 621 } else { 622 assert(FPREG(rDestHi)); 623 assert(rDest == (rDestHi - 1)); 624 } 625 rDestHi = rDest + 1; 626 } 627#endif 628 shortForm = IS_SIMM16_2WORD(displacement); 629 assert((displacement & 0x3) == 0); 630 break; 631 case kWord: 632 case kSingle: 633 opcode = kMipsLw; 634#ifdef __mips_hard_float 635 if (FPREG(rDest)) { 636 opcode = kMipsFlwc1; 637 assert(SINGLEREG(rDest)); 638 } 639#endif 640 assert((displacement & 0x3) == 0); 641 break; 642 case kUnsignedHalf: 643 opcode = kMipsLhu; 644 assert((displacement & 0x1) == 0); 645 break; 646 case kSignedHalf: 647 opcode = kMipsLh; 648 assert((displacement & 0x1) == 0); 649 break; 650 case kUnsignedByte: 651 opcode = kMipsLbu; 652 break; 653 case kSignedByte: 654 opcode = kMipsLb; 655 break; 656 default: 657 ALOGE("Jit: bad case in loadBaseIndexedBody"); 658 dvmCompilerAbort(cUnit); 659 } 660 661 if (shortForm) { 662 if (!pair) { 663 load = res = newLIR3(cUnit, opcode, rDest, displacement, rBase); 664 } else { 665 load = res = newLIR3(cUnit, opcode, rDest, displacement + LOWORD_OFFSET, rBase); 666 load2 = newLIR3(cUnit, opcode, rDestHi, displacement + HIWORD_OFFSET, rBase); 667 } 668 } else { 669 if (pair) { 670 int rTmp = dvmCompilerAllocFreeTemp(cUnit); 671 res = opRegRegImm(cUnit, kOpAdd, rTmp, rBase, displacement); 672 load = newLIR3(cUnit, opcode, rDest, LOWORD_OFFSET, rTmp); 673 load2 = newLIR3(cUnit, opcode, rDestHi, HIWORD_OFFSET, rTmp); 674 dvmCompilerFreeTemp(cUnit, rTmp); 675 } else { 676 int rTmp = (rBase == rDest) ? dvmCompilerAllocFreeTemp(cUnit) 677 : rDest; 678 res = loadConstant(cUnit, rTmp, displacement); 679 load = newLIR3(cUnit, opcode, rDest, rBase, rTmp); 680 if (rTmp != rDest) 681 dvmCompilerFreeTemp(cUnit, rTmp); 682 } 683 } 684 685 if (rBase == rFP) { 686 if (load != NULL) 687 annotateDalvikRegAccess(load, (displacement + (pair ? LOWORD_OFFSET : 0)) >> 2, 688 true /* isLoad */); 689 if (load2 != NULL) 690 annotateDalvikRegAccess(load2, (displacement + HIWORD_OFFSET) >> 2, 691 true /* isLoad */); 692 } 693#if defined(WITH_SELF_VERIFICATION) 694 if (load != NULL && cUnit->heapMemOp) 695 load->flags.insertWrapper = true; 696 if (load2 != NULL && cUnit->heapMemOp) 697 load2->flags.insertWrapper = true; 698#endif 699 return load; 700} 701 702static MipsLIR *loadBaseDisp(CompilationUnit *cUnit, MIR *mir, int rBase, 703 int displacement, int rDest, OpSize size, 704 int sReg) 705{ 706 return loadBaseDispBody(cUnit, mir, rBase, displacement, rDest, -1, 707 size, sReg); 708} 709 710static MipsLIR *loadBaseDispWide(CompilationUnit *cUnit, MIR *mir, int rBase, 711 int displacement, int rDestLo, int rDestHi, 712 int sReg) 713{ 714 return loadBaseDispBody(cUnit, mir, rBase, displacement, rDestLo, rDestHi, 715 kLong, sReg); 716} 717 718static MipsLIR *storeBaseDispBody(CompilationUnit *cUnit, int rBase, 719 int displacement, int rSrc, int rSrcHi, 720 OpSize size) 721{ 722 MipsLIR *res; 723 MipsLIR *store = NULL; 724 MipsLIR *store2 = NULL; 725 MipsOpCode opcode = kMipsNop; 726 bool shortForm = IS_SIMM16(displacement); 727 bool pair = false; 728 729 switch (size) { 730 case kLong: 731 case kDouble: 732 pair = true; 733 opcode = kMipsSw; 734#ifdef __mips_hard_float 735 if (FPREG(rSrc)) { 736 opcode = kMipsFswc1; 737 if (DOUBLEREG(rSrc)) { 738 rSrc = rSrc - FP_DOUBLE; 739 } else { 740 assert(FPREG(rSrcHi)); 741 assert(rSrc == (rSrcHi - 1)); 742 } 743 rSrcHi = rSrc + 1; 744 } 745#endif 746 shortForm = IS_SIMM16_2WORD(displacement); 747 assert((displacement & 0x3) == 0); 748 break; 749 case kWord: 750 case kSingle: 751 opcode = kMipsSw; 752#ifdef __mips_hard_float 753 if (FPREG(rSrc)) { 754 opcode = kMipsFswc1; 755 assert(SINGLEREG(rSrc)); 756 } 757#endif 758 assert((displacement & 0x3) == 0); 759 break; 760 case kUnsignedHalf: 761 case kSignedHalf: 762 opcode = kMipsSh; 763 assert((displacement & 0x1) == 0); 764 break; 765 case kUnsignedByte: 766 case kSignedByte: 767 opcode = kMipsSb; 768 break; 769 default: 770 ALOGE("Jit: bad case in storeBaseIndexedBody"); 771 dvmCompilerAbort(cUnit); 772 } 773 774 if (shortForm) { 775 if (!pair) { 776 store = res = newLIR3(cUnit, opcode, rSrc, displacement, rBase); 777 } else { 778 store = res = newLIR3(cUnit, opcode, rSrc, displacement + LOWORD_OFFSET, rBase); 779 store2 = newLIR3(cUnit, opcode, rSrcHi, displacement + HIWORD_OFFSET, rBase); 780 } 781 } else { 782 int rScratch = dvmCompilerAllocTemp(cUnit); 783 res = opRegRegImm(cUnit, kOpAdd, rScratch, rBase, displacement); 784 if (!pair) { 785 store = newLIR3(cUnit, opcode, rSrc, 0, rScratch); 786 } else { 787 store = newLIR3(cUnit, opcode, rSrc, LOWORD_OFFSET, rScratch); 788 store2 = newLIR3(cUnit, opcode, rSrcHi, HIWORD_OFFSET, rScratch); 789 } 790 dvmCompilerFreeTemp(cUnit, rScratch); 791 } 792 793 if (rBase == rFP) { 794 if (store != NULL) 795 annotateDalvikRegAccess(store, (displacement + (pair ? LOWORD_OFFSET : 0)) >> 2, 796 false /* isLoad */); 797 if (store2 != NULL) 798 annotateDalvikRegAccess(store2, (displacement + HIWORD_OFFSET) >> 2, 799 false /* isLoad */); 800 } 801 802#if defined(WITH_SELF_VERIFICATION) 803 if (store != NULL && cUnit->heapMemOp) 804 store->flags.insertWrapper = true; 805 if (store2 != NULL && cUnit->heapMemOp) 806 store2->flags.insertWrapper = true; 807#endif 808 return res; 809} 810 811static MipsLIR *storeBaseDisp(CompilationUnit *cUnit, int rBase, 812 int displacement, int rSrc, OpSize size) 813{ 814 return storeBaseDispBody(cUnit, rBase, displacement, rSrc, -1, size); 815} 816 817static MipsLIR *storeBaseDispWide(CompilationUnit *cUnit, int rBase, 818 int displacement, int rSrcLo, int rSrcHi) 819{ 820 return storeBaseDispBody(cUnit, rBase, displacement, rSrcLo, rSrcHi, kLong); 821} 822 823static void storePair(CompilationUnit *cUnit, int base, int lowReg, int highReg) 824{ 825 storeWordDisp(cUnit, base, LOWORD_OFFSET, lowReg); 826 storeWordDisp(cUnit, base, HIWORD_OFFSET, highReg); 827} 828 829static void loadPair(CompilationUnit *cUnit, int base, int lowReg, int highReg) 830{ 831 loadWordDisp(cUnit, base, LOWORD_OFFSET , lowReg); 832 loadWordDisp(cUnit, base, HIWORD_OFFSET , highReg); 833} 834 835static MipsLIR* genRegCopyNoInsert(CompilationUnit *cUnit, int rDest, int rSrc) 836{ 837 MipsLIR* res; 838 MipsOpCode opcode; 839#ifdef __mips_hard_float 840 if (FPREG(rDest) || FPREG(rSrc)) 841 return fpRegCopy(cUnit, rDest, rSrc); 842#endif 843 res = (MipsLIR *) dvmCompilerNew(sizeof(MipsLIR), true); 844 opcode = kMipsMove; 845 assert(LOWREG(rDest) && LOWREG(rSrc)); 846 res->operands[0] = rDest; 847 res->operands[1] = rSrc; 848 res->opcode = opcode; 849 setupResourceMasks(res); 850 if (rDest == rSrc) { 851 res->flags.isNop = true; 852 } 853 return res; 854} 855 856static MipsLIR* genRegCopy(CompilationUnit *cUnit, int rDest, int rSrc) 857{ 858 MipsLIR *res = genRegCopyNoInsert(cUnit, rDest, rSrc); 859 dvmCompilerAppendLIR(cUnit, (LIR*)res); 860 return res; 861} 862 863static void genRegCopyWide(CompilationUnit *cUnit, int destLo, int destHi, 864 int srcLo, int srcHi) 865{ 866#ifdef __mips_hard_float 867 bool destFP = FPREG(destLo) && FPREG(destHi); 868 bool srcFP = FPREG(srcLo) && FPREG(srcHi); 869 assert(FPREG(srcLo) == FPREG(srcHi)); 870 assert(FPREG(destLo) == FPREG(destHi)); 871 if (destFP) { 872 if (srcFP) { 873 genRegCopy(cUnit, S2D(destLo, destHi), S2D(srcLo, srcHi)); 874 } else { 875 /* note the operands are swapped for the mtc1 instr */ 876 newLIR2(cUnit, kMipsMtc1, srcLo, destLo); 877 newLIR2(cUnit, kMipsMtc1, srcHi, destHi); 878 } 879 } else { 880 if (srcFP) { 881 newLIR2(cUnit, kMipsMfc1, destLo, srcLo); 882 newLIR2(cUnit, kMipsMfc1, destHi, srcHi); 883 } else { 884 // Handle overlap 885 if (srcHi == destLo) { 886 genRegCopy(cUnit, destHi, srcHi); 887 genRegCopy(cUnit, destLo, srcLo); 888 } else { 889 genRegCopy(cUnit, destLo, srcLo); 890 genRegCopy(cUnit, destHi, srcHi); 891 } 892 } 893 } 894#else 895 // Handle overlap 896 if (srcHi == destLo) { 897 genRegCopy(cUnit, destHi, srcHi); 898 genRegCopy(cUnit, destLo, srcLo); 899 } else { 900 genRegCopy(cUnit, destLo, srcLo); 901 genRegCopy(cUnit, destHi, srcHi); 902 } 903#endif 904} 905 906static inline MipsLIR *genRegImmCheck(CompilationUnit *cUnit, 907 MipsConditionCode cond, int reg, 908 int checkValue, int dOffset, 909 MipsLIR *pcrLabel) 910{ 911 MipsLIR *branch = NULL; 912 913 if (checkValue == 0) { 914 MipsOpCode opc = kMipsNop; 915 if (cond == kMipsCondEq) { 916 opc = kMipsBeqz; 917 } else if (cond == kMipsCondNe) { 918 opc = kMipsBnez; 919 } else if (cond == kMipsCondLt || cond == kMipsCondMi) { 920 opc = kMipsBltz; 921 } else if (cond == kMipsCondLe) { 922 opc = kMipsBlez; 923 } else if (cond == kMipsCondGt) { 924 opc = kMipsBgtz; 925 } else if (cond == kMipsCondGe) { 926 opc = kMipsBgez; 927 } else { 928 ALOGE("Jit: bad case in genRegImmCheck"); 929 dvmCompilerAbort(cUnit); 930 } 931 branch = opCompareBranch(cUnit, opc, reg, -1); 932 } else if (IS_SIMM16(checkValue)) { 933 if (cond == kMipsCondLt) { 934 int tReg = dvmCompilerAllocTemp(cUnit); 935 newLIR3(cUnit, kMipsSlti, tReg, reg, checkValue); 936 branch = opCompareBranch(cUnit, kMipsBne, tReg, r_ZERO); 937 dvmCompilerFreeTemp(cUnit, tReg); 938 } else { 939 ALOGE("Jit: bad case in genRegImmCheck"); 940 dvmCompilerAbort(cUnit); 941 } 942 } else { 943 ALOGE("Jit: bad case in genRegImmCheck"); 944 dvmCompilerAbort(cUnit); 945 } 946 947 if (cUnit->jitMode == kJitMethod) { 948 BasicBlock *bb = cUnit->curBlock; 949 if (bb->taken) { 950 MipsLIR *exceptionLabel = (MipsLIR *) cUnit->blockLabelList; 951 exceptionLabel += bb->taken->id; 952 branch->generic.target = (LIR *) exceptionLabel; 953 return exceptionLabel; 954 } else { 955 ALOGE("Catch blocks not handled yet"); 956 dvmAbort(); 957 return NULL; 958 } 959 } else { 960 return genCheckCommon(cUnit, dOffset, branch, pcrLabel); 961 } 962} 963 964#if defined(WITH_SELF_VERIFICATION) 965static void genSelfVerificationPreBranch(CompilationUnit *cUnit, 966 MipsLIR *origLIR) { 967// DOUGLAS - this still needs to be implemented for MIPS. 968#if 0 969 /* 970 * We need two separate pushes, since we want r5 to be pushed first. 971 * Store multiple will push LR first. 972 */ 973 MipsLIR *pushFP = (MipsLIR *) dvmCompilerNew(sizeof(MipsLIR), true); 974 pushFP->opcode = kThumbPush; 975 pushFP->operands[0] = 1 << r5FP; 976 setupResourceMasks(pushFP); 977 dvmCompilerInsertLIRBefore((LIR *) origLIR, (LIR *) pushFP); 978 979 MipsLIR *pushLR = (MipsLIR *) dvmCompilerNew(sizeof(MipsLIR), true); 980 pushLR->opcode = kThumbPush; 981 /* Thumb push can handle LR, but is encoded differently at bit 8 */ 982 pushLR->operands[0] = 1 << 8; 983 setupResourceMasks(pushLR); 984 dvmCompilerInsertLIRBefore((LIR *) origLIR, (LIR *) pushLR); 985#endif 986} 987 988static void genSelfVerificationPostBranch(CompilationUnit *cUnit, 989 MipsLIR *origLIR) { 990// DOUGLAS - this still needs to be implemented for MIPS. 991#if 0 992 /* 993 * Since Thumb cannot pop memory content into LR, we have to pop LR 994 * to a temp first (r5 in this case). Then we move r5 to LR, then pop the 995 * original r5 from stack. 996 */ 997 /* Pop memory content(LR) into r5 first */ 998 MipsLIR *popForLR = (MipsLIR *) dvmCompilerNew(sizeof(MipsLIR), true); 999 popForLR->opcode = kThumbPop; 1000 popForLR->operands[0] = 1 << r5FP; 1001 setupResourceMasks(popForLR); 1002 dvmCompilerInsertLIRAfter((LIR *) origLIR, (LIR *) popForLR); 1003 1004 MipsLIR *copy = genRegCopyNoInsert(cUnit, r14lr, r5FP); 1005 dvmCompilerInsertLIRAfter((LIR *) popForLR, (LIR *) copy); 1006 1007 /* Now restore the original r5 */ 1008 MipsLIR *popFP = (MipsLIR *) dvmCompilerNew(sizeof(MipsLIR), true); 1009 popFP->opcode = kThumbPop; 1010 popFP->operands[0] = 1 << r5FP; 1011 setupResourceMasks(popFP); 1012 dvmCompilerInsertLIRAfter((LIR *) copy, (LIR *) popFP); 1013#endif 1014} 1015#endif 1016