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[] = {r0, r1, r2, r3, r4PC, r7}; 26 27static void storePair(CompilationUnit *cUnit, int base, int lowReg, 28 int highReg); 29static void loadPair(CompilationUnit *cUnit, int base, int lowReg, int highReg); 30static ArmLIR *loadWordDisp(CompilationUnit *cUnit, int rBase, int displacement, 31 int rDest); 32static ArmLIR *storeWordDisp(CompilationUnit *cUnit, int rBase, 33 int displacement, int rSrc); 34static ArmLIR *genRegRegCheck(CompilationUnit *cUnit, 35 ArmConditionCode cond, 36 int reg1, int reg2, int dOffset, 37 ArmLIR *pcrLabel); 38 39 40/* 41 * Load a immediate using a shortcut if possible; otherwise 42 * grab from the per-translation literal pool. If target is 43 * a high register, build constant into a low register and copy. 44 * 45 * No additional register clobbering operation performed. Use this version when 46 * 1) rDest is freshly returned from dvmCompilerAllocTemp or 47 * 2) The codegen is under fixed register usage 48 */ 49static ArmLIR *loadConstantNoClobber(CompilationUnit *cUnit, int rDest, 50 int value) 51{ 52 ArmLIR *res; 53 int tDest = LOWREG(rDest) ? rDest : dvmCompilerAllocTemp(cUnit); 54 /* See if the value can be constructed cheaply */ 55 if ((value >= 0) && (value <= 255)) { 56 res = newLIR2(cUnit, kThumbMovImm, tDest, value); 57 if (rDest != tDest) { 58 opRegReg(cUnit, kOpMov, rDest, tDest); 59 dvmCompilerFreeTemp(cUnit, tDest); 60 } 61 return res; 62 } else if ((value & 0xFFFFFF00) == 0xFFFFFF00) { 63 res = newLIR2(cUnit, kThumbMovImm, tDest, ~value); 64 newLIR2(cUnit, kThumbMvn, tDest, tDest); 65 if (rDest != tDest) { 66 opRegReg(cUnit, kOpMov, rDest, tDest); 67 dvmCompilerFreeTemp(cUnit, tDest); 68 } 69 return res; 70 } 71 /* No shortcut - go ahead and use literal pool */ 72 ArmLIR *dataTarget = scanLiteralPool(cUnit, value, 255); 73 if (dataTarget == NULL) { 74 dataTarget = addWordData(cUnit, value, false); 75 } 76 ArmLIR *loadPcRel = dvmCompilerNew(sizeof(ArmLIR), true); 77 loadPcRel->opCode = kThumbLdrPcRel; 78 loadPcRel->generic.target = (LIR *) dataTarget; 79 loadPcRel->operands[0] = tDest; 80 setupResourceMasks(loadPcRel); 81 /* 82 * Special case for literal loads with a link register target. 83 * Self-cosim mode will insert calls prior to heap references 84 * after optimization, and those will destroy r14. The easy 85 * workaround is to treat literal loads into r14 as heap references 86 * to prevent them from being hoisted. Use of r14 in this manner 87 * is currently rare. Revist if that changes. 88 */ 89 if (rDest != rlr) 90 setMemRefType(loadPcRel, true, kLiteral); 91 loadPcRel->aliasInfo = dataTarget->operands[0]; 92 res = loadPcRel; 93 dvmCompilerAppendLIR(cUnit, (LIR *) loadPcRel); 94 95 /* 96 * To save space in the constant pool, we use the ADD_RRI8 instruction to 97 * add up to 255 to an existing constant value. 98 */ 99 if (dataTarget->operands[0] != value) { 100 newLIR2(cUnit, kThumbAddRI8, tDest, value - dataTarget->operands[0]); 101 } 102 if (rDest != tDest) { 103 opRegReg(cUnit, kOpMov, rDest, tDest); 104 dvmCompilerFreeTemp(cUnit, tDest); 105 } 106 return res; 107} 108 109/* 110 * Load an immediate value into a fixed or temp register. Target 111 * register is clobbered, and marked inUse. 112 */ 113static ArmLIR *loadConstant(CompilationUnit *cUnit, int rDest, int value) 114{ 115 if (dvmCompilerIsTemp(cUnit, rDest)) { 116 dvmCompilerClobber(cUnit, rDest); 117 dvmCompilerMarkInUse(cUnit, rDest); 118 } 119 return loadConstantNoClobber(cUnit, rDest, value); 120} 121 122static ArmLIR *opNone(CompilationUnit *cUnit, OpKind op) 123{ 124 ArmOpCode opCode = kThumbBkpt; 125 switch (op) { 126 case kOpUncondBr: 127 opCode = kThumbBUncond; 128 break; 129 default: 130 LOGE("Jit: bad case in opNone"); 131 dvmCompilerAbort(cUnit); 132 } 133 return newLIR0(cUnit, opCode); 134} 135 136static ArmLIR *opCondBranch(CompilationUnit *cUnit, ArmConditionCode cc) 137{ 138 return newLIR2(cUnit, kThumbBCond, 0 /* offset to be patched */, cc); 139} 140 141static ArmLIR *opImm(CompilationUnit *cUnit, OpKind op, int value) 142{ 143 ArmOpCode opCode = kThumbBkpt; 144 switch (op) { 145 case kOpPush: 146 opCode = kThumbPush; 147 break; 148 case kOpPop: 149 opCode = kThumbPop; 150 break; 151 default: 152 LOGE("Jit: bad case in opCondBranch"); 153 dvmCompilerAbort(cUnit); 154 } 155 return newLIR1(cUnit, opCode, value); 156} 157 158static ArmLIR *opReg(CompilationUnit *cUnit, OpKind op, int rDestSrc) 159{ 160 ArmOpCode opCode = kThumbBkpt; 161 switch (op) { 162 case kOpBlx: 163 opCode = kThumbBlxR; 164 break; 165 default: 166 LOGE("Jit: bad case in opReg"); 167 dvmCompilerAbort(cUnit); 168 } 169 return newLIR1(cUnit, opCode, rDestSrc); 170} 171 172static ArmLIR *opRegImm(CompilationUnit *cUnit, OpKind op, int rDestSrc1, 173 int value) 174{ 175 ArmLIR *res; 176 bool neg = (value < 0); 177 int absValue = (neg) ? -value : value; 178 bool shortForm = (absValue & 0xff) == absValue; 179 ArmOpCode opCode = kThumbBkpt; 180 switch (op) { 181 case kOpAdd: 182 if ( !neg && (rDestSrc1 == 13) && (value <= 508)) { /* sp */ 183 assert((value & 0x3) == 0); 184 return newLIR1(cUnit, kThumbAddSpI7, value >> 2); 185 } else if (shortForm) { 186 opCode = (neg) ? kThumbSubRI8 : kThumbAddRI8; 187 } else 188 opCode = kThumbAddRRR; 189 break; 190 case kOpSub: 191 if (!neg && (rDestSrc1 == 13) && (value <= 508)) { /* sp */ 192 assert((value & 0x3) == 0); 193 return newLIR1(cUnit, kThumbSubSpI7, value >> 2); 194 } else if (shortForm) { 195 opCode = (neg) ? kThumbAddRI8 : kThumbSubRI8; 196 } else 197 opCode = kThumbSubRRR; 198 break; 199 case kOpCmp: 200 if (neg) 201 shortForm = false; 202 if (LOWREG(rDestSrc1) && shortForm) { 203 opCode = kThumbCmpRI8; 204 } else if (LOWREG(rDestSrc1)) { 205 opCode = kThumbCmpRR; 206 } else { 207 shortForm = false; 208 opCode = kThumbCmpHL; 209 } 210 break; 211 default: 212 LOGE("Jit: bad case in opRegImm"); 213 dvmCompilerAbort(cUnit); 214 break; 215 } 216 if (shortForm) 217 res = newLIR2(cUnit, opCode, rDestSrc1, absValue); 218 else { 219 int rScratch = dvmCompilerAllocTemp(cUnit); 220 res = loadConstant(cUnit, rScratch, value); 221 if (op == kOpCmp) 222 newLIR2(cUnit, opCode, rDestSrc1, rScratch); 223 else 224 newLIR3(cUnit, opCode, rDestSrc1, rDestSrc1, rScratch); 225 } 226 return res; 227} 228 229static ArmLIR *opRegRegReg(CompilationUnit *cUnit, OpKind op, int rDest, 230 int rSrc1, int rSrc2) 231{ 232 ArmOpCode opCode = kThumbBkpt; 233 switch (op) { 234 case kOpAdd: 235 opCode = kThumbAddRRR; 236 break; 237 case kOpSub: 238 opCode = kThumbSubRRR; 239 break; 240 default: 241 if (rDest == rSrc1) { 242 return opRegReg(cUnit, op, rDest, rSrc2); 243 } else if (rDest == rSrc2) { 244 assert(dvmCompilerIsTemp(cUnit, rSrc1)); 245 dvmCompilerClobber(cUnit, rSrc1); 246 opRegReg(cUnit, op, rSrc1, rSrc2); 247 return opRegReg(cUnit, kOpMov, rDest, rSrc1); 248 } else { 249 opRegReg(cUnit, kOpMov, rDest, rSrc1); 250 return opRegReg(cUnit, op, rDest, rSrc2); 251 } 252 break; 253 } 254 return newLIR3(cUnit, opCode, rDest, rSrc1, rSrc2); 255} 256 257static ArmLIR *opRegRegImm(CompilationUnit *cUnit, OpKind op, int rDest, 258 int rSrc1, int value) 259{ 260 ArmLIR *res; 261 bool neg = (value < 0); 262 int absValue = (neg) ? -value : value; 263 ArmOpCode opCode = kThumbBkpt; 264 bool shortForm = (absValue & 0x7) == absValue; 265 switch(op) { 266 case kOpAdd: 267 if (rDest == rSrc1) 268 return opRegImm(cUnit, op, rDest, value); 269 if ((rSrc1 == 13) && (value <= 1020)) { /* sp */ 270 assert((value & 0x3) == 0); 271 shortForm = true; 272 opCode = kThumbAddSpRel; 273 value >>= 2; 274 } else if ((rSrc1 == 15) && (value <= 1020)) { /* pc */ 275 assert((value & 0x3) == 0); 276 shortForm = true; 277 opCode = kThumbAddPcRel; 278 value >>= 2; 279 } else if (shortForm) { 280 opCode = (neg) ? kThumbSubRRI3 : kThumbAddRRI3; 281 } else if ((absValue > 0) && (absValue <= (255 + 7))) { 282 /* Two shots - 1st handle the 7 */ 283 opCode = (neg) ? kThumbSubRRI3 : kThumbAddRRI3; 284 res = newLIR3(cUnit, opCode, rDest, rSrc1, 7); 285 opCode = (neg) ? kThumbSubRI8 : kThumbAddRI8; 286 newLIR2(cUnit, opCode, rDest, absValue - 7); 287 return res; 288 } else 289 opCode = kThumbAddRRR; 290 break; 291 292 case kOpSub: 293 if (rDest == rSrc1) 294 return opRegImm(cUnit, op, rDest, value); 295 if (shortForm) { 296 opCode = (neg) ? kThumbAddRRI3 : kThumbSubRRI3; 297 } else if ((absValue > 0) && (absValue <= (255 + 7))) { 298 /* Two shots - 1st handle the 7 */ 299 opCode = (neg) ? kThumbAddRRI3 : kThumbSubRRI3; 300 res = newLIR3(cUnit, opCode, rDest, rSrc1, 7); 301 opCode = (neg) ? kThumbAddRI8 : kThumbSubRI8; 302 newLIR2(cUnit, opCode, rDest, absValue - 7); 303 return res; 304 } else 305 opCode = kThumbSubRRR; 306 break; 307 case kOpLsl: 308 shortForm = (!neg && value <= 31); 309 opCode = kThumbLslRRI5; 310 break; 311 case kOpLsr: 312 shortForm = (!neg && value <= 31); 313 opCode = kThumbLsrRRI5; 314 break; 315 case kOpAsr: 316 shortForm = (!neg && value <= 31); 317 opCode = kThumbAsrRRI5; 318 break; 319 case kOpMul: 320 case kOpAnd: 321 case kOpOr: 322 case kOpXor: 323 if (rDest == rSrc1) { 324 int rScratch = dvmCompilerAllocTemp(cUnit); 325 res = loadConstant(cUnit, rScratch, value); 326 opRegReg(cUnit, op, rDest, rScratch); 327 } else { 328 res = loadConstant(cUnit, rDest, value); 329 opRegReg(cUnit, op, rDest, rSrc1); 330 } 331 return res; 332 default: 333 LOGE("Jit: bad case in opRegRegImm"); 334 dvmCompilerAbort(cUnit); 335 break; 336 } 337 if (shortForm) 338 res = newLIR3(cUnit, opCode, rDest, rSrc1, absValue); 339 else { 340 if (rDest != rSrc1) { 341 res = loadConstant(cUnit, rDest, value); 342 newLIR3(cUnit, opCode, rDest, rSrc1, rDest); 343 } else { 344 int rScratch = dvmCompilerAllocTemp(cUnit); 345 res = loadConstant(cUnit, rScratch, value); 346 newLIR3(cUnit, opCode, rDest, rSrc1, rScratch); 347 } 348 } 349 return res; 350} 351 352static ArmLIR *opRegReg(CompilationUnit *cUnit, OpKind op, int rDestSrc1, 353 int rSrc2) 354{ 355 ArmLIR *res; 356 ArmOpCode opCode = kThumbBkpt; 357 switch (op) { 358 case kOpAdc: 359 opCode = kThumbAdcRR; 360 break; 361 case kOpAnd: 362 opCode = kThumbAndRR; 363 break; 364 case kOpBic: 365 opCode = kThumbBicRR; 366 break; 367 case kOpCmn: 368 opCode = kThumbCmnRR; 369 break; 370 case kOpCmp: 371 opCode = kThumbCmpRR; 372 break; 373 case kOpXor: 374 opCode = kThumbEorRR; 375 break; 376 case kOpMov: 377 if (LOWREG(rDestSrc1) && LOWREG(rSrc2)) 378 opCode = kThumbMovRR; 379 else if (!LOWREG(rDestSrc1) && !LOWREG(rSrc2)) 380 opCode = kThumbMovRR_H2H; 381 else if (LOWREG(rDestSrc1)) 382 opCode = kThumbMovRR_H2L; 383 else 384 opCode = kThumbMovRR_L2H; 385 break; 386 case kOpMul: 387 opCode = kThumbMul; 388 break; 389 case kOpMvn: 390 opCode = kThumbMvn; 391 break; 392 case kOpNeg: 393 opCode = kThumbNeg; 394 break; 395 case kOpOr: 396 opCode = kThumbOrr; 397 break; 398 case kOpSbc: 399 opCode = kThumbSbc; 400 break; 401 case kOpTst: 402 opCode = kThumbTst; 403 break; 404 case kOpLsl: 405 opCode = kThumbLslRR; 406 break; 407 case kOpLsr: 408 opCode = kThumbLsrRR; 409 break; 410 case kOpAsr: 411 opCode = kThumbAsrRR; 412 break; 413 case kOpRor: 414 opCode = kThumbRorRR; 415 case kOpAdd: 416 case kOpSub: 417 return opRegRegReg(cUnit, op, rDestSrc1, rDestSrc1, rSrc2); 418 case kOp2Byte: 419 res = opRegRegImm(cUnit, kOpLsl, rDestSrc1, rSrc2, 24); 420 opRegRegImm(cUnit, kOpAsr, rDestSrc1, rDestSrc1, 24); 421 return res; 422 case kOp2Short: 423 res = opRegRegImm(cUnit, kOpLsl, rDestSrc1, rSrc2, 16); 424 opRegRegImm(cUnit, kOpAsr, rDestSrc1, rDestSrc1, 16); 425 return res; 426 case kOp2Char: 427 res = opRegRegImm(cUnit, kOpLsl, rDestSrc1, rSrc2, 16); 428 opRegRegImm(cUnit, kOpLsr, rDestSrc1, rDestSrc1, 16); 429 return res; 430 default: 431 LOGE("Jit: bad case in opRegReg"); 432 dvmCompilerAbort(cUnit); 433 break; 434 } 435 return newLIR2(cUnit, opCode, rDestSrc1, rSrc2); 436} 437 438static ArmLIR *loadConstantValueWide(CompilationUnit *cUnit, int rDestLo, 439 int rDestHi, int valLo, int valHi) 440{ 441 ArmLIR *res; 442 res = loadConstantNoClobber(cUnit, rDestLo, valLo); 443 loadConstantNoClobber(cUnit, rDestHi, valHi); 444 return res; 445} 446 447/* Load value from base + scaled index. */ 448static ArmLIR *loadBaseIndexed(CompilationUnit *cUnit, int rBase, 449 int rIndex, int rDest, int scale, OpSize size) 450{ 451 ArmLIR *first = NULL; 452 ArmLIR *res; 453 ArmOpCode opCode = kThumbBkpt; 454 int rNewIndex = rIndex; 455 if (scale) { 456 // Scale the index, but can't trash the original. 457 rNewIndex = dvmCompilerAllocTemp(cUnit); 458 first = opRegRegImm(cUnit, kOpLsl, rNewIndex, rIndex, scale); 459 } 460 switch (size) { 461 case kWord: 462 opCode = kThumbLdrRRR; 463 break; 464 case kUnsignedHalf: 465 opCode = kThumbLdrhRRR; 466 break; 467 case kSignedHalf: 468 opCode = kThumbLdrshRRR; 469 break; 470 case kUnsignedByte: 471 opCode = kThumbLdrbRRR; 472 break; 473 case kSignedByte: 474 opCode = kThumbLdrsbRRR; 475 break; 476 default: 477 LOGE("Jit: bad case in loadBaseIndexed"); 478 dvmCompilerAbort(cUnit); 479 } 480 res = newLIR3(cUnit, opCode, rDest, rBase, rNewIndex); 481#if defined(WITH_SELF_VERIFICATION) 482 if (cUnit->heapMemOp) 483 res->branchInsertSV = true; 484#endif 485 if (scale) 486 dvmCompilerFreeTemp(cUnit, rNewIndex); 487 return (first) ? first : res; 488} 489 490/* store value base base + scaled index. */ 491static ArmLIR *storeBaseIndexed(CompilationUnit *cUnit, int rBase, 492 int rIndex, int rSrc, int scale, OpSize size) 493{ 494 ArmLIR *first = NULL; 495 ArmLIR *res; 496 ArmOpCode opCode = kThumbBkpt; 497 int rNewIndex = rIndex; 498 if (scale) { 499 rNewIndex = dvmCompilerAllocTemp(cUnit); 500 first = opRegRegImm(cUnit, kOpLsl, rNewIndex, rIndex, scale); 501 } 502 switch (size) { 503 case kWord: 504 opCode = kThumbStrRRR; 505 break; 506 case kUnsignedHalf: 507 case kSignedHalf: 508 opCode = kThumbStrhRRR; 509 break; 510 case kUnsignedByte: 511 case kSignedByte: 512 opCode = kThumbStrbRRR; 513 break; 514 default: 515 LOGE("Jit: bad case in storeBaseIndexed"); 516 dvmCompilerAbort(cUnit); 517 } 518 res = newLIR3(cUnit, opCode, rSrc, rBase, rNewIndex); 519#if defined(WITH_SELF_VERIFICATION) 520 if (cUnit->heapMemOp) 521 res->branchInsertSV = true; 522#endif 523 if (scale) 524 dvmCompilerFreeTemp(cUnit, rNewIndex); 525 return (first) ? first : res; 526} 527 528static ArmLIR *loadMultiple(CompilationUnit *cUnit, int rBase, int rMask) 529{ 530 ArmLIR *res; 531 genBarrier(cUnit); 532 res = newLIR2(cUnit, kThumbLdmia, rBase, rMask); 533#if defined(WITH_SELF_VERIFICATION) 534 if (cUnit->heapMemOp) 535 res->branchInsertSV = true; 536#endif 537 genBarrier(cUnit); 538 return res; 539} 540 541static ArmLIR *storeMultiple(CompilationUnit *cUnit, int rBase, int rMask) 542{ 543 ArmLIR *res; 544 genBarrier(cUnit); 545 res = newLIR2(cUnit, kThumbStmia, rBase, rMask); 546#if defined(WITH_SELF_VERIFICATION) 547 if (cUnit->heapMemOp) 548 res->branchInsertSV = true; 549#endif 550 genBarrier(cUnit); 551 return res; 552} 553 554static ArmLIR *loadBaseDispBody(CompilationUnit *cUnit, MIR *mir, int rBase, 555 int displacement, int rDest, int rDestHi, 556 OpSize size, int sReg) 557/* 558 * Load value from base + displacement. Optionally perform null check 559 * on base (which must have an associated sReg and MIR). If not 560 * performing null check, incoming MIR can be null. IMPORTANT: this 561 * code must not allocate any new temps. If a new register is needed 562 * and base and dest are the same, spill some other register to 563 * rlp and then restore. 564 */ 565{ 566 ArmLIR *res; 567 ArmLIR *load = NULL; 568 ArmLIR *load2 = NULL; 569 ArmOpCode opCode = kThumbBkpt; 570 bool shortForm = false; 571 int encodedDisp = displacement; 572 bool pair = false; 573 574 switch (size) { 575 case kLong: 576 case kDouble: 577 pair = true; 578 if ((displacement < 124) && (displacement >= 0)) { 579 assert((displacement & 0x3) == 0); 580 shortForm = true; 581 encodedDisp >>= 2; 582 opCode = kThumbLdrRRI5; 583 } else { 584 opCode = kThumbLdrRRR; 585 } 586 break; 587 case kWord: 588 if (LOWREG(rDest) && (rBase == rpc) && 589 (displacement <= 1020) && (displacement >= 0)) { 590 shortForm = true; 591 encodedDisp >>= 2; 592 opCode = kThumbLdrPcRel; 593 } else if (LOWREG(rDest) && (rBase == r13) && 594 (displacement <= 1020) && (displacement >= 0)) { 595 shortForm = true; 596 encodedDisp >>= 2; 597 opCode = kThumbLdrSpRel; 598 } else if (displacement < 128 && displacement >= 0) { 599 assert((displacement & 0x3) == 0); 600 shortForm = true; 601 encodedDisp >>= 2; 602 opCode = kThumbLdrRRI5; 603 } else { 604 opCode = kThumbLdrRRR; 605 } 606 break; 607 case kUnsignedHalf: 608 if (displacement < 64 && displacement >= 0) { 609 assert((displacement & 0x1) == 0); 610 shortForm = true; 611 encodedDisp >>= 1; 612 opCode = kThumbLdrhRRI5; 613 } else { 614 opCode = kThumbLdrhRRR; 615 } 616 break; 617 case kSignedHalf: 618 opCode = kThumbLdrshRRR; 619 break; 620 case kUnsignedByte: 621 if (displacement < 32 && displacement >= 0) { 622 shortForm = true; 623 opCode = kThumbLdrbRRI5; 624 } else { 625 opCode = kThumbLdrbRRR; 626 } 627 break; 628 case kSignedByte: 629 opCode = kThumbLdrsbRRR; 630 break; 631 default: 632 LOGE("Jit: bad case in loadBaseIndexedBody"); 633 dvmCompilerAbort(cUnit); 634 } 635 if (shortForm) { 636 load = res = newLIR3(cUnit, opCode, rDest, rBase, encodedDisp); 637 if (pair) { 638 load2 = newLIR3(cUnit, opCode, rDestHi, rBase, encodedDisp+1); 639 } 640 } else { 641 if (pair) { 642 int rTmp = dvmCompilerAllocFreeTemp(cUnit); 643 res = opRegRegImm(cUnit, kOpAdd, rTmp, rBase, displacement); 644 load = newLIR3(cUnit, kThumbLdrRRI5, rDest, rTmp, 0); 645 load2 = newLIR3(cUnit, kThumbLdrRRI5, rDestHi, rTmp, 1); 646 dvmCompilerFreeTemp(cUnit, rTmp); 647 } else { 648 int rTmp = (rBase == rDest) ? dvmCompilerAllocFreeTemp(cUnit) 649 : rDest; 650 res = loadConstant(cUnit, rTmp, displacement); 651 load = newLIR3(cUnit, opCode, rDest, rBase, rTmp); 652 if (rBase == rFP) 653 annotateDalvikRegAccess(load, displacement >> 2, 654 true /* isLoad */); 655 if (rTmp != rDest) 656 dvmCompilerFreeTemp(cUnit, rTmp); 657 } 658 } 659 if (rBase == rFP) { 660 if (load != NULL) 661 annotateDalvikRegAccess(load, displacement >> 2, 662 true /* isLoad */); 663 if (load2 != NULL) 664 annotateDalvikRegAccess(load2, (displacement >> 2) + 1, 665 true /* isLoad */); 666 } 667#if defined(WITH_SELF_VERIFICATION) 668 if (load != NULL && cUnit->heapMemOp) 669 load->branchInsertSV = true; 670 if (load2 != NULL && cUnit->heapMemOp) 671 load2->branchInsertSV = true; 672#endif 673 return res; 674} 675 676static ArmLIR *loadBaseDisp(CompilationUnit *cUnit, MIR *mir, int rBase, 677 int displacement, int rDest, OpSize size, 678 int sReg) 679{ 680 return loadBaseDispBody(cUnit, mir, rBase, displacement, rDest, -1, 681 size, sReg); 682} 683 684static ArmLIR *loadBaseDispWide(CompilationUnit *cUnit, MIR *mir, int rBase, 685 int displacement, int rDestLo, int rDestHi, 686 int sReg) 687{ 688 return loadBaseDispBody(cUnit, mir, rBase, displacement, rDestLo, rDestHi, 689 kLong, sReg); 690} 691 692static ArmLIR *storeBaseDispBody(CompilationUnit *cUnit, int rBase, 693 int displacement, int rSrc, int rSrcHi, 694 OpSize size) 695{ 696 ArmLIR *res; 697 ArmLIR *store = NULL; 698 ArmLIR *store2 = NULL; 699 ArmOpCode opCode = kThumbBkpt; 700 bool shortForm = false; 701 int encodedDisp = displacement; 702 bool pair = false; 703 704 switch (size) { 705 case kLong: 706 case kDouble: 707 pair = true; 708 if ((displacement < 124) && (displacement >= 0)) { 709 assert((displacement & 0x3) == 0); 710 pair = true; 711 shortForm = true; 712 encodedDisp >>= 2; 713 opCode = kThumbStrRRI5; 714 } else { 715 opCode = kThumbStrRRR; 716 } 717 break; 718 case kWord: 719 if (displacement < 128 && displacement >= 0) { 720 assert((displacement & 0x3) == 0); 721 shortForm = true; 722 encodedDisp >>= 2; 723 opCode = kThumbStrRRI5; 724 } else { 725 opCode = kThumbStrRRR; 726 } 727 break; 728 case kUnsignedHalf: 729 case kSignedHalf: 730 if (displacement < 64 && displacement >= 0) { 731 assert((displacement & 0x1) == 0); 732 shortForm = true; 733 encodedDisp >>= 1; 734 opCode = kThumbStrhRRI5; 735 } else { 736 opCode = kThumbStrhRRR; 737 } 738 break; 739 case kUnsignedByte: 740 case kSignedByte: 741 if (displacement < 32 && displacement >= 0) { 742 shortForm = true; 743 opCode = kThumbStrbRRI5; 744 } else { 745 opCode = kThumbStrbRRR; 746 } 747 break; 748 default: 749 LOGE("Jit: bad case in storeBaseIndexedBody"); 750 dvmCompilerAbort(cUnit); 751 } 752 if (shortForm) { 753 store = res = newLIR3(cUnit, opCode, rSrc, rBase, encodedDisp); 754 if (pair) { 755 store2 = newLIR3(cUnit, opCode, rSrcHi, rBase, encodedDisp + 1); 756 } 757 } else { 758 int rScratch = dvmCompilerAllocTemp(cUnit); 759 if (pair) { 760 res = opRegRegImm(cUnit, kOpAdd, rScratch, rBase, displacement); 761 store = newLIR3(cUnit, kThumbStrRRI5, rSrc, rScratch, 0); 762 store2 = newLIR3(cUnit, kThumbStrRRI5, rSrcHi, rScratch, 1); 763 } else { 764 res = loadConstant(cUnit, rScratch, displacement); 765 store = newLIR3(cUnit, opCode, rSrc, rBase, rScratch); 766 } 767 dvmCompilerFreeTemp(cUnit, rScratch); 768 } 769 if (rBase == rFP) { 770 if (store != NULL) 771 annotateDalvikRegAccess(store, displacement >> 2, 772 false /* isLoad */); 773 if (store2 != NULL) 774 annotateDalvikRegAccess(store2, (displacement >> 2) + 1, 775 false /* isLoad */); 776 } 777#if defined(WITH_SELF_VERIFICATION) 778 if (store != NULL && cUnit->heapMemOp) 779 store->branchInsertSV = true; 780 if (store2 != NULL && cUnit->heapMemOp) 781 store2->branchInsertSV = true; 782#endif 783 return res; 784} 785 786static ArmLIR *storeBaseDisp(CompilationUnit *cUnit, int rBase, 787 int displacement, int rSrc, OpSize size) 788{ 789 return storeBaseDispBody(cUnit, rBase, displacement, rSrc, -1, size); 790} 791 792static ArmLIR *storeBaseDispWide(CompilationUnit *cUnit, int rBase, 793 int displacement, int rSrcLo, int rSrcHi) 794{ 795 return storeBaseDispBody(cUnit, rBase, displacement, rSrcLo, rSrcHi, kLong); 796} 797 798static void storePair(CompilationUnit *cUnit, int base, int lowReg, int highReg) 799{ 800 if (lowReg < highReg) { 801 storeMultiple(cUnit, base, (1 << lowReg) | (1 << highReg)); 802 } else { 803 storeWordDisp(cUnit, base, 0, lowReg); 804 storeWordDisp(cUnit, base, 4, highReg); 805 } 806} 807 808static void loadPair(CompilationUnit *cUnit, int base, int lowReg, int highReg) 809{ 810 if (lowReg < highReg) { 811 loadMultiple(cUnit, base, (1 << lowReg) | (1 << highReg)); 812 } else { 813 loadWordDisp(cUnit, base, 0 , lowReg); 814 loadWordDisp(cUnit, base, 4 , highReg); 815 } 816} 817 818static ArmLIR* genRegCopyNoInsert(CompilationUnit *cUnit, int rDest, int rSrc) 819{ 820 ArmLIR* res; 821 ArmOpCode opCode; 822 res = dvmCompilerNew(sizeof(ArmLIR), true); 823 if (LOWREG(rDest) && LOWREG(rSrc)) 824 opCode = kThumbMovRR; 825 else if (!LOWREG(rDest) && !LOWREG(rSrc)) 826 opCode = kThumbMovRR_H2H; 827 else if (LOWREG(rDest)) 828 opCode = kThumbMovRR_H2L; 829 else 830 opCode = kThumbMovRR_L2H; 831 832 res->operands[0] = rDest; 833 res->operands[1] = rSrc; 834 res->opCode = opCode; 835 setupResourceMasks(res); 836 if (rDest == rSrc) { 837 res->isNop = true; 838 } 839 return res; 840} 841 842static ArmLIR* genRegCopy(CompilationUnit *cUnit, int rDest, int rSrc) 843{ 844 ArmLIR *res = genRegCopyNoInsert(cUnit, rDest, rSrc); 845 dvmCompilerAppendLIR(cUnit, (LIR*)res); 846 return res; 847} 848 849static void genRegCopyWide(CompilationUnit *cUnit, int destLo, int destHi, 850 int srcLo, int srcHi) 851{ 852 // Handle overlap 853 if (srcHi == destLo) { 854 genRegCopy(cUnit, destHi, srcHi); 855 genRegCopy(cUnit, destLo, srcLo); 856 } else { 857 genRegCopy(cUnit, destLo, srcLo); 858 genRegCopy(cUnit, destHi, srcHi); 859 } 860} 861 862static inline ArmLIR *genRegImmCheck(CompilationUnit *cUnit, 863 ArmConditionCode cond, int reg, 864 int checkValue, int dOffset, 865 ArmLIR *pcrLabel) 866{ 867 int tReg; 868 ArmLIR *res; 869 if ((checkValue & 0xff) != checkValue) { 870 tReg = dvmCompilerAllocTemp(cUnit); 871 loadConstant(cUnit, tReg, checkValue); 872 res = genRegRegCheck(cUnit, cond, reg, tReg, dOffset, pcrLabel); 873 dvmCompilerFreeTemp(cUnit, tReg); 874 return res; 875 } 876 newLIR2(cUnit, kThumbCmpRI8, reg, checkValue); 877 ArmLIR *branch = newLIR2(cUnit, kThumbBCond, 0, cond); 878 return genCheckCommon(cUnit, dOffset, branch, pcrLabel); 879} 880