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, r8, r9, r10, r11, r12}; 26static int fpTemps[] = {fr16, fr17, fr18, fr19, fr20, fr21, fr22, fr23, 27 fr24, fr25, fr26, fr27, fr28, fr29, fr30, fr31}; 28 29static int encodeImmSingle(int value) 30{ 31 int res; 32 int bitA = (value & 0x80000000) >> 31; 33 int notBitB = (value & 0x40000000) >> 30; 34 int bitB = (value & 0x20000000) >> 29; 35 int bSmear = (value & 0x3e000000) >> 25; 36 int slice = (value & 0x01f80000) >> 19; 37 int zeroes = (value & 0x0007ffff); 38 if (zeroes != 0) 39 return -1; 40 if (bitB) { 41 if ((notBitB != 0) || (bSmear != 0x1f)) 42 return -1; 43 } else { 44 if ((notBitB != 1) || (bSmear != 0x0)) 45 return -1; 46 } 47 res = (bitA << 7) | (bitB << 6) | slice; 48 return res; 49} 50 51static ArmLIR *loadFPConstantValue(CompilationUnit *cUnit, int rDest, 52 int value) 53{ 54 int encodedImm = encodeImmSingle(value); 55 assert(SINGLEREG(rDest)); 56 if (encodedImm >= 0) { 57 return newLIR2(cUnit, kThumb2Vmovs_IMM8, rDest, encodedImm); 58 } 59 ArmLIR *dataTarget = scanLiteralPool(cUnit, value, 0); 60 if (dataTarget == NULL) { 61 dataTarget = addWordData(cUnit, value, false); 62 } 63 ArmLIR *loadPcRel = dvmCompilerNew(sizeof(ArmLIR), true); 64 loadPcRel->opCode = kThumb2Vldrs; 65 loadPcRel->generic.target = (LIR *) dataTarget; 66 loadPcRel->operands[0] = rDest; 67 loadPcRel->operands[1] = rpc; 68 setupResourceMasks(loadPcRel); 69 // Self-cosim workaround. 70 if (rDest != rlr) 71 setMemRefType(loadPcRel, true, kLiteral); 72 loadPcRel->aliasInfo = dataTarget->operands[0]; 73 dvmCompilerAppendLIR(cUnit, (LIR *) loadPcRel); 74 return loadPcRel; 75} 76 77static int leadingZeros(u4 val) 78{ 79 u4 alt; 80 int n; 81 int count; 82 83 count = 16; 84 n = 32; 85 do { 86 alt = val >> count; 87 if (alt != 0) { 88 n = n - count; 89 val = alt; 90 } 91 count >>= 1; 92 } while (count); 93 return n - val; 94} 95 96/* 97 * Determine whether value can be encoded as a Thumb2 modified 98 * immediate. If not, return -1. If so, return i:imm3:a:bcdefgh form. 99 */ 100static int modifiedImmediate(u4 value) 101{ 102 int zLeading; 103 int zTrailing; 104 u4 b0 = value & 0xff; 105 106 /* Note: case of value==0 must use 0:000:0:0000000 encoding */ 107 if (value <= 0xFF) 108 return b0; // 0:000:a:bcdefgh 109 if (value == ((b0 << 16) | b0)) 110 return (0x1 << 8) | b0; /* 0:001:a:bcdefgh */ 111 if (value == ((b0 << 24) | (b0 << 16) | (b0 << 8) | b0)) 112 return (0x3 << 8) | b0; /* 0:011:a:bcdefgh */ 113 b0 = (value >> 8) & 0xff; 114 if (value == ((b0 << 24) | (b0 << 8))) 115 return (0x2 << 8) | b0; /* 0:010:a:bcdefgh */ 116 /* Can we do it with rotation? */ 117 zLeading = leadingZeros(value); 118 zTrailing = 32 - leadingZeros(~value & (value - 1)); 119 /* A run of eight or fewer active bits? */ 120 if ((zLeading + zTrailing) < 24) 121 return -1; /* No - bail */ 122 /* left-justify the constant, discarding msb (known to be 1) */ 123 value <<= zLeading + 1; 124 /* Create bcdefgh */ 125 value >>= 25; 126 /* Put it all together */ 127 return value | ((0x8 + zLeading) << 7); /* [01000..11111]:bcdefgh */ 128} 129 130/* 131 * Load a immediate using a shortcut if possible; otherwise 132 * grab from the per-translation literal pool. 133 * 134 * No additional register clobbering operation performed. Use this version when 135 * 1) rDest is freshly returned from dvmCompilerAllocTemp or 136 * 2) The codegen is under fixed register usage 137 */ 138static ArmLIR *loadConstantNoClobber(CompilationUnit *cUnit, int rDest, 139 int value) 140{ 141 ArmLIR *res; 142 int modImm; 143 144 if (FPREG(rDest)) { 145 return loadFPConstantValue(cUnit, rDest, value); 146 } 147 148 /* See if the value can be constructed cheaply */ 149 if (LOWREG(rDest) && (value >= 0) && (value <= 255)) { 150 return newLIR2(cUnit, kThumbMovImm, rDest, value); 151 } 152 /* Check Modified immediate special cases */ 153 modImm = modifiedImmediate(value); 154 if (modImm >= 0) { 155 res = newLIR2(cUnit, kThumb2MovImmShift, rDest, modImm); 156 return res; 157 } 158 modImm = modifiedImmediate(~value); 159 if (modImm >= 0) { 160 res = newLIR2(cUnit, kThumb2MvnImmShift, rDest, modImm); 161 return res; 162 } 163 /* 16-bit immediate? */ 164 if ((value & 0xffff) == value) { 165 res = newLIR2(cUnit, kThumb2MovImm16, rDest, value); 166 return res; 167 } 168 /* No shortcut - go ahead and use literal pool */ 169 ArmLIR *dataTarget = scanLiteralPool(cUnit, value, 0); 170 if (dataTarget == NULL) { 171 dataTarget = addWordData(cUnit, value, false); 172 } 173 ArmLIR *loadPcRel = dvmCompilerNew(sizeof(ArmLIR), true); 174 loadPcRel->opCode = kThumb2LdrPcRel12; 175 loadPcRel->generic.target = (LIR *) dataTarget; 176 loadPcRel->operands[0] = rDest; 177 setupResourceMasks(loadPcRel); 178 /* 179 * Special case for literal loads with a link register target. 180 * Self-cosim mode will insert calls prior to heap references 181 * after optimization, and those will destroy r14. The easy 182 * workaround is to treat literal loads into r14 as heap references 183 * to prevent them from being hoisted. Use of r14 in this manner 184 * is currently rare. Revisit if that changes. 185 */ 186 if (rDest != rlr) 187 setMemRefType(loadPcRel, true, kLiteral); 188 loadPcRel->aliasInfo = dataTarget->operands[0]; 189 res = loadPcRel; 190 dvmCompilerAppendLIR(cUnit, (LIR *) loadPcRel); 191 192 /* 193 * To save space in the constant pool, we use the ADD_RRI8 instruction to 194 * add up to 255 to an existing constant value. 195 */ 196 if (dataTarget->operands[0] != value) { 197 opRegImm(cUnit, kOpAdd, rDest, value - dataTarget->operands[0]); 198 } 199 return res; 200} 201 202/* 203 * Load an immediate value into a fixed or temp register. Target 204 * register is clobbered, and marked inUse. 205 */ 206static ArmLIR *loadConstant(CompilationUnit *cUnit, int rDest, int value) 207{ 208 if (dvmCompilerIsTemp(cUnit, rDest)) { 209 dvmCompilerClobber(cUnit, rDest); 210 dvmCompilerMarkInUse(cUnit, rDest); 211 } 212 return loadConstantNoClobber(cUnit, rDest, value); 213} 214 215static ArmLIR *opNone(CompilationUnit *cUnit, OpKind op) 216{ 217 ArmOpCode opCode = kThumbBkpt; 218 switch (op) { 219 case kOpUncondBr: 220 opCode = kThumbBUncond; 221 break; 222 default: 223 assert(0); 224 } 225 return newLIR0(cUnit, opCode); 226} 227 228static ArmLIR *opCondBranch(CompilationUnit *cUnit, ArmConditionCode cc) 229{ 230 return newLIR2(cUnit, kThumb2BCond, 0 /* offset to be patched */, cc); 231} 232 233static ArmLIR *opImm(CompilationUnit *cUnit, OpKind op, int value) 234{ 235 ArmOpCode opCode = kThumbBkpt; 236 switch (op) { 237 case kOpPush: 238 opCode = ((value & 0xff00) != 0) ? kThumb2Push : kThumbPush; 239 break; 240 case kOpPop: 241 opCode = ((value & 0xff00) != 0) ? kThumb2Pop : kThumbPop; 242 break; 243 default: 244 assert(0); 245 } 246 return newLIR1(cUnit, opCode, value); 247} 248 249static ArmLIR *opReg(CompilationUnit *cUnit, OpKind op, int rDestSrc) 250{ 251 ArmOpCode opCode = kThumbBkpt; 252 switch (op) { 253 case kOpBlx: 254 opCode = kThumbBlxR; 255 break; 256 default: 257 assert(0); 258 } 259 return newLIR1(cUnit, opCode, rDestSrc); 260} 261 262static ArmLIR *opRegRegShift(CompilationUnit *cUnit, OpKind op, int rDestSrc1, 263 int rSrc2, int shift) 264{ 265 bool thumbForm = ((shift == 0) && LOWREG(rDestSrc1) && LOWREG(rSrc2)); 266 ArmOpCode opCode = kThumbBkpt; 267 switch (op) { 268 case kOpAdc: 269 opCode = (thumbForm) ? kThumbAdcRR : kThumb2AdcRRR; 270 break; 271 case kOpAnd: 272 opCode = (thumbForm) ? kThumbAndRR : kThumb2AndRRR; 273 break; 274 case kOpBic: 275 opCode = (thumbForm) ? kThumbBicRR : kThumb2BicRRR; 276 break; 277 case kOpCmn: 278 assert(shift == 0); 279 opCode = (thumbForm) ? kThumbCmnRR : kThumb2CmnRR; 280 break; 281 case kOpCmp: 282 if (thumbForm) 283 opCode = kThumbCmpRR; 284 else if ((shift == 0) && !LOWREG(rDestSrc1) && !LOWREG(rSrc2)) 285 opCode = kThumbCmpHH; 286 else if ((shift == 0) && LOWREG(rDestSrc1)) 287 opCode = kThumbCmpLH; 288 else if (shift == 0) 289 opCode = kThumbCmpHL; 290 else 291 opCode = kThumb2CmpRR; 292 break; 293 case kOpXor: 294 opCode = (thumbForm) ? kThumbEorRR : kThumb2EorRRR; 295 break; 296 case kOpMov: 297 assert(shift == 0); 298 if (LOWREG(rDestSrc1) && LOWREG(rSrc2)) 299 opCode = kThumbMovRR; 300 else if (!LOWREG(rDestSrc1) && !LOWREG(rSrc2)) 301 opCode = kThumbMovRR_H2H; 302 else if (LOWREG(rDestSrc1)) 303 opCode = kThumbMovRR_H2L; 304 else 305 opCode = kThumbMovRR_L2H; 306 break; 307 case kOpMul: 308 assert(shift == 0); 309 opCode = (thumbForm) ? kThumbMul : kThumb2MulRRR; 310 break; 311 case kOpMvn: 312 opCode = (thumbForm) ? kThumbMvn : kThumb2MnvRR; 313 break; 314 case kOpNeg: 315 assert(shift == 0); 316 opCode = (thumbForm) ? kThumbNeg : kThumb2NegRR; 317 break; 318 case kOpOr: 319 opCode = (thumbForm) ? kThumbOrr : kThumb2OrrRRR; 320 break; 321 case kOpSbc: 322 opCode = (thumbForm) ? kThumbSbc : kThumb2SbcRRR; 323 break; 324 case kOpTst: 325 opCode = (thumbForm) ? kThumbTst : kThumb2TstRR; 326 break; 327 case kOpLsl: 328 assert(shift == 0); 329 opCode = (thumbForm) ? kThumbLslRR : kThumb2LslRRR; 330 break; 331 case kOpLsr: 332 assert(shift == 0); 333 opCode = (thumbForm) ? kThumbLsrRR : kThumb2LsrRRR; 334 break; 335 case kOpAsr: 336 assert(shift == 0); 337 opCode = (thumbForm) ? kThumbAsrRR : kThumb2AsrRRR; 338 break; 339 case kOpRor: 340 assert(shift == 0); 341 opCode = (thumbForm) ? kThumbRorRR : kThumb2RorRRR; 342 break; 343 case kOpAdd: 344 opCode = (thumbForm) ? kThumbAddRRR : kThumb2AddRRR; 345 break; 346 case kOpSub: 347 opCode = (thumbForm) ? kThumbSubRRR : kThumb2SubRRR; 348 break; 349 case kOp2Byte: 350 assert(shift == 0); 351 return newLIR4(cUnit, kThumb2Sbfx, rDestSrc1, rSrc2, 0, 8); 352 case kOp2Short: 353 assert(shift == 0); 354 return newLIR4(cUnit, kThumb2Sbfx, rDestSrc1, rSrc2, 0, 16); 355 case kOp2Char: 356 assert(shift == 0); 357 return newLIR4(cUnit, kThumb2Ubfx, rDestSrc1, rSrc2, 0, 16); 358 default: 359 assert(0); 360 break; 361 } 362 assert(opCode >= 0); 363 if (EncodingMap[opCode].flags & IS_BINARY_OP) 364 return newLIR2(cUnit, opCode, rDestSrc1, rSrc2); 365 else if (EncodingMap[opCode].flags & IS_TERTIARY_OP) { 366 if (EncodingMap[opCode].fieldLoc[2].kind == kFmtShift) 367 return newLIR3(cUnit, opCode, rDestSrc1, rSrc2, shift); 368 else 369 return newLIR3(cUnit, opCode, rDestSrc1, rDestSrc1, rSrc2); 370 } else if (EncodingMap[opCode].flags & IS_QUAD_OP) 371 return newLIR4(cUnit, opCode, rDestSrc1, rDestSrc1, rSrc2, shift); 372 else { 373 assert(0); 374 return NULL; 375 } 376} 377 378static ArmLIR *opRegReg(CompilationUnit *cUnit, OpKind op, int rDestSrc1, 379 int rSrc2) 380{ 381 return opRegRegShift(cUnit, op, rDestSrc1, rSrc2, 0); 382} 383 384static ArmLIR *opRegRegRegShift(CompilationUnit *cUnit, OpKind op, 385 int rDest, int rSrc1, int rSrc2, int shift) 386{ 387 ArmOpCode opCode = kThumbBkpt; 388 bool thumbForm = (shift == 0) && LOWREG(rDest) && LOWREG(rSrc1) && 389 LOWREG(rSrc2); 390 switch (op) { 391 case kOpAdd: 392 opCode = (thumbForm) ? kThumbAddRRR : kThumb2AddRRR; 393 break; 394 case kOpSub: 395 opCode = (thumbForm) ? kThumbSubRRR : kThumb2SubRRR; 396 break; 397 case kOpAdc: 398 opCode = kThumb2AdcRRR; 399 break; 400 case kOpAnd: 401 opCode = kThumb2AndRRR; 402 break; 403 case kOpBic: 404 opCode = kThumb2BicRRR; 405 break; 406 case kOpXor: 407 opCode = kThumb2EorRRR; 408 break; 409 case kOpMul: 410 assert(shift == 0); 411 opCode = kThumb2MulRRR; 412 break; 413 case kOpOr: 414 opCode = kThumb2OrrRRR; 415 break; 416 case kOpSbc: 417 opCode = kThumb2SbcRRR; 418 break; 419 case kOpLsl: 420 assert(shift == 0); 421 opCode = kThumb2LslRRR; 422 break; 423 case kOpLsr: 424 assert(shift == 0); 425 opCode = kThumb2LsrRRR; 426 break; 427 case kOpAsr: 428 assert(shift == 0); 429 opCode = kThumb2AsrRRR; 430 break; 431 case kOpRor: 432 assert(shift == 0); 433 opCode = kThumb2RorRRR; 434 break; 435 default: 436 assert(0); 437 break; 438 } 439 assert(opCode >= 0); 440 if (EncodingMap[opCode].flags & IS_QUAD_OP) 441 return newLIR4(cUnit, opCode, rDest, rSrc1, rSrc2, shift); 442 else { 443 assert(EncodingMap[opCode].flags & IS_TERTIARY_OP); 444 return newLIR3(cUnit, opCode, rDest, rSrc1, rSrc2); 445 } 446} 447 448static ArmLIR *opRegRegReg(CompilationUnit *cUnit, OpKind op, int rDest, 449 int rSrc1, int rSrc2) 450{ 451 return opRegRegRegShift(cUnit, op, rDest, rSrc1, rSrc2, 0); 452} 453 454static ArmLIR *opRegRegImm(CompilationUnit *cUnit, OpKind op, int rDest, 455 int rSrc1, int value) 456{ 457 ArmLIR *res; 458 bool neg = (value < 0); 459 int absValue = (neg) ? -value : value; 460 ArmOpCode opCode = kThumbBkpt; 461 ArmOpCode altOpCode = kThumbBkpt; 462 bool allLowRegs = (LOWREG(rDest) && LOWREG(rSrc1)); 463 int modImm = modifiedImmediate(value); 464 int modImmNeg = modifiedImmediate(-value); 465 466 switch(op) { 467 case kOpLsl: 468 if (allLowRegs) 469 return newLIR3(cUnit, kThumbLslRRI5, rDest, rSrc1, value); 470 else 471 return newLIR3(cUnit, kThumb2LslRRI5, rDest, rSrc1, value); 472 case kOpLsr: 473 if (allLowRegs) 474 return newLIR3(cUnit, kThumbLsrRRI5, rDest, rSrc1, value); 475 else 476 return newLIR3(cUnit, kThumb2LsrRRI5, rDest, rSrc1, value); 477 case kOpAsr: 478 if (allLowRegs) 479 return newLIR3(cUnit, kThumbAsrRRI5, rDest, rSrc1, value); 480 else 481 return newLIR3(cUnit, kThumb2AsrRRI5, rDest, rSrc1, value); 482 case kOpRor: 483 return newLIR3(cUnit, kThumb2RorRRI5, rDest, rSrc1, value); 484 case kOpAdd: 485 if (LOWREG(rDest) && (rSrc1 == 13) && 486 (value <= 1020) && ((value & 0x3)==0)) { 487 return newLIR3(cUnit, kThumbAddSpRel, rDest, rSrc1, 488 value >> 2); 489 } else if (LOWREG(rDest) && (rSrc1 == rpc) && 490 (value <= 1020) && ((value & 0x3)==0)) { 491 return newLIR3(cUnit, kThumbAddPcRel, rDest, rSrc1, 492 value >> 2); 493 } 494 opCode = kThumb2AddRRI8; 495 altOpCode = kThumb2AddRRR; 496 // Note: intentional fallthrough 497 case kOpSub: 498 if (allLowRegs && ((absValue & 0x7) == absValue)) { 499 if (op == kOpAdd) 500 opCode = (neg) ? kThumbSubRRI3 : kThumbAddRRI3; 501 else 502 opCode = (neg) ? kThumbAddRRI3 : kThumbSubRRI3; 503 return newLIR3(cUnit, opCode, rDest, rSrc1, absValue); 504 } else if ((absValue & 0xff) == absValue) { 505 if (op == kOpAdd) 506 opCode = (neg) ? kThumb2SubRRI12 : kThumb2AddRRI12; 507 else 508 opCode = (neg) ? kThumb2AddRRI12 : kThumb2SubRRI12; 509 return newLIR3(cUnit, opCode, rDest, rSrc1, absValue); 510 } 511 if (modImmNeg >= 0) { 512 op = (op == kOpAdd) ? kOpSub : kOpAdd; 513 modImm = modImmNeg; 514 } 515 if (op == kOpSub) { 516 opCode = kThumb2SubRRI8; 517 altOpCode = kThumb2SubRRR; 518 } 519 break; 520 case kOpAdc: 521 opCode = kThumb2AdcRRI8; 522 altOpCode = kThumb2AdcRRR; 523 break; 524 case kOpSbc: 525 opCode = kThumb2SbcRRI8; 526 altOpCode = kThumb2SbcRRR; 527 break; 528 case kOpOr: 529 opCode = kThumb2OrrRRI8; 530 altOpCode = kThumb2OrrRRR; 531 break; 532 case kOpAnd: 533 opCode = kThumb2AndRRI8; 534 altOpCode = kThumb2AndRRR; 535 break; 536 case kOpXor: 537 opCode = kThumb2EorRRI8; 538 altOpCode = kThumb2EorRRR; 539 break; 540 case kOpMul: 541 //TUNING: power of 2, shift & add 542 modImm = -1; 543 altOpCode = kThumb2MulRRR; 544 break; 545 case kOpCmp: { 546 int modImm = modifiedImmediate(value); 547 ArmLIR *res; 548 if (modImm >= 0) { 549 res = newLIR2(cUnit, kThumb2CmpRI8, rSrc1, modImm); 550 } else { 551 int rTmp = dvmCompilerAllocTemp(cUnit); 552 res = loadConstant(cUnit, rTmp, value); 553 opRegReg(cUnit, kOpCmp, rSrc1, rTmp); 554 dvmCompilerFreeTemp(cUnit, rTmp); 555 } 556 return res; 557 } 558 default: 559 assert(0); 560 } 561 562 if (modImm >= 0) { 563 return newLIR3(cUnit, opCode, rDest, rSrc1, modImm); 564 } else { 565 int rScratch = dvmCompilerAllocTemp(cUnit); 566 loadConstant(cUnit, rScratch, value); 567 if (EncodingMap[altOpCode].flags & IS_QUAD_OP) 568 res = newLIR4(cUnit, altOpCode, rDest, rSrc1, rScratch, 0); 569 else 570 res = newLIR3(cUnit, altOpCode, rDest, rSrc1, rScratch); 571 dvmCompilerFreeTemp(cUnit, rScratch); 572 return res; 573 } 574} 575 576/* Handle Thumb-only variants here - otherwise punt to opRegRegImm */ 577static ArmLIR *opRegImm(CompilationUnit *cUnit, OpKind op, int rDestSrc1, 578 int value) 579{ 580 bool neg = (value < 0); 581 int absValue = (neg) ? -value : value; 582 bool shortForm = (((absValue & 0xff) == absValue) && LOWREG(rDestSrc1)); 583 ArmOpCode opCode = kThumbBkpt; 584 switch (op) { 585 case kOpAdd: 586 if ( !neg && (rDestSrc1 == 13) && (value <= 508)) { /* sp */ 587 assert((value & 0x3) == 0); 588 return newLIR1(cUnit, kThumbAddSpI7, value >> 2); 589 } else if (shortForm) { 590 opCode = (neg) ? kThumbSubRI8 : kThumbAddRI8; 591 } 592 break; 593 case kOpSub: 594 if (!neg && (rDestSrc1 == 13) && (value <= 508)) { /* sp */ 595 assert((value & 0x3) == 0); 596 return newLIR1(cUnit, kThumbSubSpI7, value >> 2); 597 } else if (shortForm) { 598 opCode = (neg) ? kThumbAddRI8 : kThumbSubRI8; 599 } 600 break; 601 case kOpCmp: 602 if (LOWREG(rDestSrc1) && shortForm) 603 opCode = (shortForm) ? kThumbCmpRI8 : kThumbCmpRR; 604 else if (LOWREG(rDestSrc1)) 605 opCode = kThumbCmpRR; 606 else { 607 shortForm = false; 608 opCode = kThumbCmpHL; 609 } 610 break; 611 default: 612 /* Punt to opRegRegImm - if bad case catch it there */ 613 shortForm = false; 614 break; 615 } 616 if (shortForm) 617 return newLIR2(cUnit, opCode, rDestSrc1, absValue); 618 else { 619 return opRegRegImm(cUnit, op, rDestSrc1, rDestSrc1, value); 620 } 621} 622 623/* 624 * Determine whether value can be encoded as a Thumb2 floating point 625 * immediate. If not, return -1. If so return encoded 8-bit value. 626 */ 627static int encodeImmDoubleHigh(int value) 628{ 629 int res; 630 int bitA = (value & 0x80000000) >> 31; 631 int notBitB = (value & 0x40000000) >> 30; 632 int bitB = (value & 0x20000000) >> 29; 633 int bSmear = (value & 0x3fc00000) >> 22; 634 int slice = (value & 0x003f0000) >> 16; 635 int zeroes = (value & 0x0000ffff); 636 if (zeroes != 0) 637 return -1; 638 if (bitB) { 639 if ((notBitB != 0) || (bSmear != 0x1f)) 640 return -1; 641 } else { 642 if ((notBitB != 1) || (bSmear != 0x0)) 643 return -1; 644 } 645 res = (bitA << 7) | (bitB << 6) | slice; 646 return res; 647} 648 649static int encodeImmDouble(int valLo, int valHi) 650{ 651 int res = -1; 652 if (valLo == 0) 653 res = encodeImmDoubleHigh(valHi); 654 return res; 655} 656 657static ArmLIR *loadConstantValueWide(CompilationUnit *cUnit, int rDestLo, 658 int rDestHi, int valLo, int valHi) 659{ 660 int encodedImm = encodeImmDouble(valLo, valHi); 661 ArmLIR *res; 662 if (FPREG(rDestLo) && (encodedImm >= 0)) { 663 res = newLIR2(cUnit, kThumb2Vmovd_IMM8, S2D(rDestLo, rDestHi), 664 encodedImm); 665 } else { 666 res = loadConstantNoClobber(cUnit, rDestLo, valLo); 667 loadConstantNoClobber(cUnit, rDestHi, valHi); 668 } 669 return res; 670} 671 672static int encodeShift(int code, int amount) { 673 return ((amount & 0x1f) << 2) | code; 674} 675 676static ArmLIR *loadBaseIndexed(CompilationUnit *cUnit, int rBase, 677 int rIndex, int rDest, int scale, OpSize size) 678{ 679 bool allLowRegs = LOWREG(rBase) && LOWREG(rIndex) && LOWREG(rDest); 680 ArmLIR *load; 681 ArmOpCode opCode = kThumbBkpt; 682 bool thumbForm = (allLowRegs && (scale == 0)); 683 int regPtr; 684 685 if (FPREG(rDest)) { 686 assert(SINGLEREG(rDest)); 687 assert((size == kWord) || (size == kSingle)); 688 opCode = kThumb2Vldrs; 689 size = kSingle; 690 } else { 691 if (size == kSingle) 692 size = kWord; 693 } 694 695 switch (size) { 696 case kSingle: 697 regPtr = dvmCompilerAllocTemp(cUnit); 698 if (scale) { 699 newLIR4(cUnit, kThumb2AddRRR, regPtr, rBase, rIndex, 700 encodeShift(kArmLsl, scale)); 701 } else { 702 opRegRegReg(cUnit, kOpAdd, regPtr, rBase, rIndex); 703 } 704 load = newLIR3(cUnit, opCode, rDest, regPtr, 0); 705#if defined(WITH_SELF_VERIFICATION) 706 if (cUnit->heapMemOp) 707 load->branchInsertSV = true; 708#endif 709 return load; 710 case kWord: 711 opCode = (thumbForm) ? kThumbLdrRRR : kThumb2LdrRRR; 712 break; 713 case kUnsignedHalf: 714 opCode = (thumbForm) ? kThumbLdrhRRR : kThumb2LdrhRRR; 715 break; 716 case kSignedHalf: 717 opCode = (thumbForm) ? kThumbLdrshRRR : kThumb2LdrshRRR; 718 break; 719 case kUnsignedByte: 720 opCode = (thumbForm) ? kThumbLdrbRRR : kThumb2LdrbRRR; 721 break; 722 case kSignedByte: 723 opCode = (thumbForm) ? kThumbLdrsbRRR : kThumb2LdrsbRRR; 724 break; 725 default: 726 assert(0); 727 } 728 if (thumbForm) 729 load = newLIR3(cUnit, opCode, rDest, rBase, rIndex); 730 else 731 load = newLIR4(cUnit, opCode, rDest, rBase, rIndex, scale); 732 733#if defined(WITH_SELF_VERIFICATION) 734 if (cUnit->heapMemOp) 735 load->branchInsertSV = true; 736#endif 737 return load; 738} 739 740static ArmLIR *storeBaseIndexed(CompilationUnit *cUnit, int rBase, 741 int rIndex, int rSrc, int scale, OpSize size) 742{ 743 bool allLowRegs = LOWREG(rBase) && LOWREG(rIndex) && LOWREG(rSrc); 744 ArmLIR *store; 745 ArmOpCode opCode = kThumbBkpt; 746 bool thumbForm = (allLowRegs && (scale == 0)); 747 int regPtr; 748 749 if (FPREG(rSrc)) { 750 assert(SINGLEREG(rSrc)); 751 assert((size == kWord) || (size == kSingle)); 752 opCode = kThumb2Vstrs; 753 size = kSingle; 754 } else { 755 if (size == kSingle) 756 size = kWord; 757 } 758 759 switch (size) { 760 case kSingle: 761 regPtr = dvmCompilerAllocTemp(cUnit); 762 if (scale) { 763 newLIR4(cUnit, kThumb2AddRRR, regPtr, rBase, rIndex, 764 encodeShift(kArmLsl, scale)); 765 } else { 766 opRegRegReg(cUnit, kOpAdd, regPtr, rBase, rIndex); 767 } 768 store = newLIR3(cUnit, opCode, rSrc, regPtr, 0); 769#if defined(WITH_SELF_VERIFICATION) 770 if (cUnit->heapMemOp) 771 store->branchInsertSV = true; 772#endif 773 return store; 774 case kWord: 775 opCode = (thumbForm) ? kThumbStrRRR : kThumb2StrRRR; 776 break; 777 case kUnsignedHalf: 778 case kSignedHalf: 779 opCode = (thumbForm) ? kThumbStrhRRR : kThumb2StrhRRR; 780 break; 781 case kUnsignedByte: 782 case kSignedByte: 783 opCode = (thumbForm) ? kThumbStrbRRR : kThumb2StrbRRR; 784 break; 785 default: 786 assert(0); 787 } 788 if (thumbForm) 789 store = newLIR3(cUnit, opCode, rSrc, rBase, rIndex); 790 else 791 store = newLIR4(cUnit, opCode, rSrc, rBase, rIndex, scale); 792 793#if defined(WITH_SELF_VERIFICATION) 794 if (cUnit->heapMemOp) 795 store->branchInsertSV = true; 796#endif 797 return store; 798} 799 800/* 801 * Load value from base + displacement. Optionally perform null check 802 * on base (which must have an associated sReg and MIR). If not 803 * performing null check, incoming MIR can be null. 804 */ 805static ArmLIR *loadBaseDispBody(CompilationUnit *cUnit, MIR *mir, int rBase, 806 int displacement, int rDest, int rDestHi, 807 OpSize size, int sReg) 808{ 809 ArmLIR *res, *load; 810 ArmOpCode opCode = kThumbBkpt; 811 bool shortForm = false; 812 bool thumb2Form = (displacement < 4092 && displacement >= 0); 813 bool allLowRegs = (LOWREG(rBase) && LOWREG(rDest)); 814 int encodedDisp = displacement; 815 816 switch (size) { 817 case kDouble: 818 case kLong: 819 if (FPREG(rDest)) { 820 if (SINGLEREG(rDest)) { 821 assert(FPREG(rDestHi)); 822 rDest = S2D(rDest, rDestHi); 823 } 824 opCode = kThumb2Vldrd; 825 if (displacement <= 1020) { 826 shortForm = true; 827 encodedDisp >>= 2; 828 } 829 break; 830 } else { 831 res = loadBaseDispBody(cUnit, mir, rBase, displacement, rDest, 832 -1, kWord, sReg); 833 loadBaseDispBody(cUnit, NULL, rBase, displacement + 4, rDestHi, 834 -1, kWord, INVALID_SREG); 835 return res; 836 } 837 case kSingle: 838 case kWord: 839 if (FPREG(rDest)) { 840 opCode = kThumb2Vldrs; 841 if (displacement <= 1020) { 842 shortForm = true; 843 encodedDisp >>= 2; 844 } 845 break; 846 } 847 if (LOWREG(rDest) && (rBase == rpc) && 848 (displacement <= 1020) && (displacement >= 0)) { 849 shortForm = true; 850 encodedDisp >>= 2; 851 opCode = kThumbLdrPcRel; 852 } else if (LOWREG(rDest) && (rBase == r13) && 853 (displacement <= 1020) && (displacement >= 0)) { 854 shortForm = true; 855 encodedDisp >>= 2; 856 opCode = kThumbLdrSpRel; 857 } else if (allLowRegs && displacement < 128 && displacement >= 0) { 858 assert((displacement & 0x3) == 0); 859 shortForm = true; 860 encodedDisp >>= 2; 861 opCode = kThumbLdrRRI5; 862 } else if (thumb2Form) { 863 shortForm = true; 864 opCode = kThumb2LdrRRI12; 865 } 866 break; 867 case kUnsignedHalf: 868 if (allLowRegs && displacement < 64 && displacement >= 0) { 869 assert((displacement & 0x1) == 0); 870 shortForm = true; 871 encodedDisp >>= 1; 872 opCode = kThumbLdrhRRI5; 873 } else if (displacement < 4092 && displacement >= 0) { 874 shortForm = true; 875 opCode = kThumb2LdrhRRI12; 876 } 877 break; 878 case kSignedHalf: 879 if (thumb2Form) { 880 shortForm = true; 881 opCode = kThumb2LdrshRRI12; 882 } 883 break; 884 case kUnsignedByte: 885 if (allLowRegs && displacement < 32 && displacement >= 0) { 886 shortForm = true; 887 opCode = kThumbLdrbRRI5; 888 } else if (thumb2Form) { 889 shortForm = true; 890 opCode = kThumb2LdrbRRI12; 891 } 892 break; 893 case kSignedByte: 894 if (thumb2Form) { 895 shortForm = true; 896 opCode = kThumb2LdrsbRRI12; 897 } 898 break; 899 default: 900 assert(0); 901 } 902 903 if (shortForm) { 904 load = res = newLIR3(cUnit, opCode, rDest, rBase, encodedDisp); 905 } else { 906 int regOffset = dvmCompilerAllocTemp(cUnit); 907 res = loadConstant(cUnit, regOffset, encodedDisp); 908 load = loadBaseIndexed(cUnit, rBase, regOffset, rDest, 0, size); 909 dvmCompilerFreeTemp(cUnit, regOffset); 910 } 911 912 if (rBase == rFP) { 913 annotateDalvikRegAccess(load, displacement >> 2, true /* isLoad */); 914 } 915#if defined(WITH_SELF_VERIFICATION) 916 if (cUnit->heapMemOp) 917 load->branchInsertSV = true; 918#endif 919 return res; 920} 921 922static ArmLIR *loadBaseDisp(CompilationUnit *cUnit, MIR *mir, int rBase, 923 int displacement, int rDest, OpSize size, 924 int sReg) 925{ 926 return loadBaseDispBody(cUnit, mir, rBase, displacement, rDest, -1, 927 size, sReg); 928} 929 930static ArmLIR *loadBaseDispWide(CompilationUnit *cUnit, MIR *mir, int rBase, 931 int displacement, int rDestLo, int rDestHi, 932 int sReg) 933{ 934 return loadBaseDispBody(cUnit, mir, rBase, displacement, rDestLo, rDestHi, 935 kLong, sReg); 936} 937 938 939static ArmLIR *storeBaseDispBody(CompilationUnit *cUnit, int rBase, 940 int displacement, int rSrc, int rSrcHi, 941 OpSize size) 942{ 943 ArmLIR *res, *store; 944 ArmOpCode opCode = kThumbBkpt; 945 bool shortForm = false; 946 bool thumb2Form = (displacement < 4092 && displacement >= 0); 947 bool allLowRegs = (LOWREG(rBase) && LOWREG(rSrc)); 948 int encodedDisp = displacement; 949 950 switch (size) { 951 case kLong: 952 case kDouble: 953 if (!FPREG(rSrc)) { 954 res = storeBaseDispBody(cUnit, rBase, displacement, rSrc, 955 -1, kWord); 956 storeBaseDispBody(cUnit, rBase, displacement + 4, rSrcHi, 957 -1, kWord); 958 return res; 959 } 960 if (SINGLEREG(rSrc)) { 961 assert(FPREG(rSrcHi)); 962 rSrc = S2D(rSrc, rSrcHi); 963 } 964 opCode = kThumb2Vstrd; 965 if (displacement <= 1020) { 966 shortForm = true; 967 encodedDisp >>= 2; 968 } 969 break; 970 case kSingle: 971 case kWord: 972 if (FPREG(rSrc)) { 973 assert(SINGLEREG(rSrc)); 974 opCode = kThumb2Vstrs; 975 if (displacement <= 1020) { 976 shortForm = true; 977 encodedDisp >>= 2; 978 } 979 break; 980 } 981 if (allLowRegs && displacement < 128 && displacement >= 0) { 982 assert((displacement & 0x3) == 0); 983 shortForm = true; 984 encodedDisp >>= 2; 985 opCode = kThumbStrRRI5; 986 } else if (thumb2Form) { 987 shortForm = true; 988 opCode = kThumb2StrRRI12; 989 } 990 break; 991 case kUnsignedHalf: 992 case kSignedHalf: 993 if (allLowRegs && displacement < 64 && displacement >= 0) { 994 assert((displacement & 0x1) == 0); 995 shortForm = true; 996 encodedDisp >>= 1; 997 opCode = kThumbStrhRRI5; 998 } else if (thumb2Form) { 999 shortForm = true; 1000 opCode = kThumb2StrhRRI12; 1001 } 1002 break; 1003 case kUnsignedByte: 1004 case kSignedByte: 1005 if (allLowRegs && displacement < 32 && displacement >= 0) { 1006 shortForm = true; 1007 opCode = kThumbStrbRRI5; 1008 } else if (thumb2Form) { 1009 shortForm = true; 1010 opCode = kThumb2StrbRRI12; 1011 } 1012 break; 1013 default: 1014 assert(0); 1015 } 1016 if (shortForm) { 1017 store = res = newLIR3(cUnit, opCode, rSrc, rBase, encodedDisp); 1018 } else { 1019 int rScratch = dvmCompilerAllocTemp(cUnit); 1020 res = loadConstant(cUnit, rScratch, encodedDisp); 1021 store = storeBaseIndexed(cUnit, rBase, rScratch, rSrc, 0, size); 1022 dvmCompilerFreeTemp(cUnit, rScratch); 1023 } 1024 1025 if (rBase == rFP) { 1026 annotateDalvikRegAccess(store, displacement >> 2, false /* isLoad */); 1027 } 1028#if defined(WITH_SELF_VERIFICATION) 1029 if (cUnit->heapMemOp) 1030 store->branchInsertSV = true; 1031#endif 1032 return res; 1033} 1034 1035static ArmLIR *storeBaseDisp(CompilationUnit *cUnit, int rBase, 1036 int displacement, int rSrc, OpSize size) 1037{ 1038 return storeBaseDispBody(cUnit, rBase, displacement, rSrc, -1, size); 1039} 1040 1041static ArmLIR *storeBaseDispWide(CompilationUnit *cUnit, int rBase, 1042 int displacement, int rSrcLo, int rSrcHi) 1043{ 1044 return storeBaseDispBody(cUnit, rBase, displacement, rSrcLo, rSrcHi, kLong); 1045} 1046 1047static ArmLIR *loadMultiple(CompilationUnit *cUnit, int rBase, int rMask) 1048{ 1049 ArmLIR *res; 1050 genBarrier(cUnit); 1051 if (LOWREG(rBase) && ((rMask & 0xff)==rMask)) { 1052 res = newLIR2(cUnit, kThumbLdmia, rBase, rMask); 1053 } else { 1054 res = newLIR2(cUnit, kThumb2Ldmia, rBase, rMask); 1055 } 1056#if defined(WITH_SELF_VERIFICATION) 1057 if (cUnit->heapMemOp) 1058 res->branchInsertSV = true; 1059#endif 1060 genBarrier(cUnit); 1061 return res; 1062} 1063 1064static ArmLIR *storeMultiple(CompilationUnit *cUnit, int rBase, int rMask) 1065{ 1066 ArmLIR *res; 1067 genBarrier(cUnit); 1068 if (LOWREG(rBase) && ((rMask & 0xff)==rMask)) { 1069 res = newLIR2(cUnit, kThumbStmia, rBase, rMask); 1070 } else { 1071 res = newLIR2(cUnit, kThumb2Stmia, rBase, rMask); 1072 } 1073#if defined(WITH_SELF_VERIFICATION) 1074 if (cUnit->heapMemOp) 1075 res->branchInsertSV = true; 1076#endif 1077 genBarrier(cUnit); 1078 return res; 1079} 1080 1081static void storePair(CompilationUnit *cUnit, int base, int lowReg, int highReg) 1082{ 1083 storeBaseDispWide(cUnit, base, 0, lowReg, highReg); 1084} 1085 1086static void loadPair(CompilationUnit *cUnit, int base, int lowReg, int highReg) 1087{ 1088 loadBaseDispWide(cUnit, NULL, base, 0, lowReg, highReg, INVALID_SREG); 1089} 1090 1091 1092/* 1093 * Perform a "reg cmp imm" operation and jump to the PCR region if condition 1094 * satisfies. 1095 */ 1096static ArmLIR *genRegImmCheck(CompilationUnit *cUnit, 1097 ArmConditionCode cond, int reg, 1098 int checkValue, int dOffset, 1099 ArmLIR *pcrLabel) 1100{ 1101 ArmLIR *branch; 1102 int modImm; 1103 if ((LOWREG(reg)) && (checkValue == 0) && 1104 ((cond == kArmCondEq) || (cond == kArmCondNe))) { 1105 branch = newLIR2(cUnit, 1106 (cond == kArmCondEq) ? kThumb2Cbz : kThumb2Cbnz, 1107 reg, 0); 1108 } else { 1109 modImm = modifiedImmediate(checkValue); 1110 if (LOWREG(reg) && ((checkValue & 0xff) == checkValue)) { 1111 newLIR2(cUnit, kThumbCmpRI8, reg, checkValue); 1112 } else if (modImm >= 0) { 1113 newLIR2(cUnit, kThumb2CmpRI8, reg, modImm); 1114 } else { 1115 int tReg = dvmCompilerAllocTemp(cUnit); 1116 loadConstant(cUnit, tReg, checkValue); 1117 opRegReg(cUnit, kOpCmp, reg, tReg); 1118 } 1119 branch = newLIR2(cUnit, kThumbBCond, 0, cond); 1120 } 1121 return genCheckCommon(cUnit, dOffset, branch, pcrLabel); 1122} 1123 1124static ArmLIR *fpRegCopy(CompilationUnit *cUnit, int rDest, int rSrc) 1125{ 1126 ArmLIR* res = dvmCompilerNew(sizeof(ArmLIR), true); 1127 res->operands[0] = rDest; 1128 res->operands[1] = rSrc; 1129 if (rDest == rSrc) { 1130 res->isNop = true; 1131 } else { 1132 assert(DOUBLEREG(rDest) == DOUBLEREG(rSrc)); 1133 if (DOUBLEREG(rDest)) { 1134 res->opCode = kThumb2Vmovd; 1135 } else { 1136 if (SINGLEREG(rDest)) { 1137 res->opCode = SINGLEREG(rSrc) ? kThumb2Vmovs : kThumb2Fmsr; 1138 } else { 1139 assert(SINGLEREG(rSrc)); 1140 res->opCode = kThumb2Fmrs; 1141 } 1142 } 1143 res->operands[0] = rDest; 1144 res->operands[1] = rSrc; 1145 } 1146 setupResourceMasks(res); 1147 return res; 1148} 1149 1150static ArmLIR* genRegCopyNoInsert(CompilationUnit *cUnit, int rDest, int rSrc) 1151{ 1152 ArmLIR* res; 1153 ArmOpCode opCode; 1154 if (FPREG(rDest) || FPREG(rSrc)) 1155 return fpRegCopy(cUnit, rDest, rSrc); 1156 res = dvmCompilerNew(sizeof(ArmLIR), true); 1157 if (LOWREG(rDest) && LOWREG(rSrc)) 1158 opCode = kThumbMovRR; 1159 else if (!LOWREG(rDest) && !LOWREG(rSrc)) 1160 opCode = kThumbMovRR_H2H; 1161 else if (LOWREG(rDest)) 1162 opCode = kThumbMovRR_H2L; 1163 else 1164 opCode = kThumbMovRR_L2H; 1165 1166 res->operands[0] = rDest; 1167 res->operands[1] = rSrc; 1168 res->opCode = opCode; 1169 setupResourceMasks(res); 1170 if (rDest == rSrc) { 1171 res->isNop = true; 1172 } 1173 return res; 1174} 1175 1176static ArmLIR* genRegCopy(CompilationUnit *cUnit, int rDest, int rSrc) 1177{ 1178 ArmLIR *res = genRegCopyNoInsert(cUnit, rDest, rSrc); 1179 dvmCompilerAppendLIR(cUnit, (LIR*)res); 1180 return res; 1181} 1182 1183static void genRegCopyWide(CompilationUnit *cUnit, int destLo, int destHi, 1184 int srcLo, int srcHi) 1185{ 1186 bool destFP = FPREG(destLo) && FPREG(destHi); 1187 bool srcFP = FPREG(srcLo) && FPREG(srcHi); 1188 assert(FPREG(srcLo) == FPREG(srcHi)); 1189 assert(FPREG(destLo) == FPREG(destHi)); 1190 if (destFP) { 1191 if (srcFP) { 1192 genRegCopy(cUnit, S2D(destLo, destHi), S2D(srcLo, srcHi)); 1193 } else { 1194 newLIR3(cUnit, kThumb2Fmdrr, S2D(destLo, destHi), srcLo, srcHi); 1195 } 1196 } else { 1197 if (srcFP) { 1198 newLIR3(cUnit, kThumb2Fmrrd, destLo, destHi, S2D(srcLo, srcHi)); 1199 } else { 1200 // Handle overlap 1201 if (srcHi == destLo) { 1202 genRegCopy(cUnit, destHi, srcHi); 1203 genRegCopy(cUnit, destLo, srcLo); 1204 } else { 1205 genRegCopy(cUnit, destLo, srcLo); 1206 genRegCopy(cUnit, destHi, srcHi); 1207 } 1208 } 1209 } 1210} 1211