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