utility_mips.cc revision bd288c2c1206bc99fafebfb9120a83f13cf9723b
1/* 2 * Copyright (C) 2012 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#include "codegen_mips.h" 18#include "dex/quick/mir_to_lir-inl.h" 19#include "mips_lir.h" 20 21namespace art { 22 23/* This file contains codegen for the MIPS32 ISA. */ 24LIR* MipsMir2Lir::OpFpRegCopy(int r_dest, int r_src) { 25 int opcode; 26 /* must be both DOUBLE or both not DOUBLE */ 27 DCHECK_EQ(MIPS_DOUBLEREG(r_dest), MIPS_DOUBLEREG(r_src)); 28 if (MIPS_DOUBLEREG(r_dest)) { 29 opcode = kMipsFmovd; 30 } else { 31 if (MIPS_SINGLEREG(r_dest)) { 32 if (MIPS_SINGLEREG(r_src)) { 33 opcode = kMipsFmovs; 34 } else { 35 /* note the operands are swapped for the mtc1 instr */ 36 int t_opnd = r_src; 37 r_src = r_dest; 38 r_dest = t_opnd; 39 opcode = kMipsMtc1; 40 } 41 } else { 42 DCHECK(MIPS_SINGLEREG(r_src)); 43 opcode = kMipsMfc1; 44 } 45 } 46 LIR* res = RawLIR(current_dalvik_offset_, opcode, r_src, r_dest); 47 if (!(cu_->disable_opt & (1 << kSafeOptimizations)) && r_dest == r_src) { 48 res->flags.is_nop = true; 49 } 50 return res; 51} 52 53bool MipsMir2Lir::InexpensiveConstantInt(int32_t value) { 54 return ((value == 0) || IsUint(16, value) || ((value < 0) && (value >= -32768))); 55} 56 57bool MipsMir2Lir::InexpensiveConstantFloat(int32_t value) { 58 return false; // TUNING 59} 60 61bool MipsMir2Lir::InexpensiveConstantLong(int64_t value) { 62 return false; // TUNING 63} 64 65bool MipsMir2Lir::InexpensiveConstantDouble(int64_t value) { 66 return false; // TUNING 67} 68 69/* 70 * Load a immediate using a shortcut if possible; otherwise 71 * grab from the per-translation literal pool. If target is 72 * a high register, build constant into a low register and copy. 73 * 74 * No additional register clobbering operation performed. Use this version when 75 * 1) r_dest is freshly returned from AllocTemp or 76 * 2) The codegen is under fixed register usage 77 */ 78LIR* MipsMir2Lir::LoadConstantNoClobber(int r_dest, int value) { 79 LIR *res; 80 81 int r_dest_save = r_dest; 82 int is_fp_reg = MIPS_FPREG(r_dest); 83 if (is_fp_reg) { 84 DCHECK(MIPS_SINGLEREG(r_dest)); 85 r_dest = AllocTemp(); 86 } 87 88 /* See if the value can be constructed cheaply */ 89 if (value == 0) { 90 res = NewLIR2(kMipsMove, r_dest, r_ZERO); 91 } else if ((value > 0) && (value <= 65535)) { 92 res = NewLIR3(kMipsOri, r_dest, r_ZERO, value); 93 } else if ((value < 0) && (value >= -32768)) { 94 res = NewLIR3(kMipsAddiu, r_dest, r_ZERO, value); 95 } else { 96 res = NewLIR2(kMipsLui, r_dest, value >> 16); 97 if (value & 0xffff) 98 NewLIR3(kMipsOri, r_dest, r_dest, value); 99 } 100 101 if (is_fp_reg) { 102 NewLIR2(kMipsMtc1, r_dest, r_dest_save); 103 FreeTemp(r_dest); 104 } 105 106 return res; 107} 108 109LIR* MipsMir2Lir::OpUnconditionalBranch(LIR* target) { 110 LIR* res = NewLIR1(kMipsB, 0 /* offset to be patched during assembly*/); 111 res->target = target; 112 return res; 113} 114 115LIR* MipsMir2Lir::OpReg(OpKind op, int r_dest_src) { 116 MipsOpCode opcode = kMipsNop; 117 switch (op) { 118 case kOpBlx: 119 opcode = kMipsJalr; 120 break; 121 case kOpBx: 122 return NewLIR1(kMipsJr, r_dest_src); 123 break; 124 default: 125 LOG(FATAL) << "Bad case in OpReg"; 126 } 127 return NewLIR2(opcode, r_RA, r_dest_src); 128} 129 130LIR* MipsMir2Lir::OpRegImm(OpKind op, int r_dest_src1, 131 int value) { 132 LIR *res; 133 bool neg = (value < 0); 134 int abs_value = (neg) ? -value : value; 135 bool short_form = (abs_value & 0xff) == abs_value; 136 MipsOpCode opcode = kMipsNop; 137 switch (op) { 138 case kOpAdd: 139 return OpRegRegImm(op, r_dest_src1, r_dest_src1, value); 140 break; 141 case kOpSub: 142 return OpRegRegImm(op, r_dest_src1, r_dest_src1, value); 143 break; 144 default: 145 LOG(FATAL) << "Bad case in OpRegImm"; 146 break; 147 } 148 if (short_form) { 149 res = NewLIR2(opcode, r_dest_src1, abs_value); 150 } else { 151 int r_scratch = AllocTemp(); 152 res = LoadConstant(r_scratch, value); 153 if (op == kOpCmp) 154 NewLIR2(opcode, r_dest_src1, r_scratch); 155 else 156 NewLIR3(opcode, r_dest_src1, r_dest_src1, r_scratch); 157 } 158 return res; 159} 160 161LIR* MipsMir2Lir::OpRegRegReg(OpKind op, int r_dest, int r_src1, int r_src2) { 162 MipsOpCode opcode = kMipsNop; 163 switch (op) { 164 case kOpAdd: 165 opcode = kMipsAddu; 166 break; 167 case kOpSub: 168 opcode = kMipsSubu; 169 break; 170 case kOpAnd: 171 opcode = kMipsAnd; 172 break; 173 case kOpMul: 174 opcode = kMipsMul; 175 break; 176 case kOpOr: 177 opcode = kMipsOr; 178 break; 179 case kOpXor: 180 opcode = kMipsXor; 181 break; 182 case kOpLsl: 183 opcode = kMipsSllv; 184 break; 185 case kOpLsr: 186 opcode = kMipsSrlv; 187 break; 188 case kOpAsr: 189 opcode = kMipsSrav; 190 break; 191 case kOpAdc: 192 case kOpSbc: 193 LOG(FATAL) << "No carry bit on MIPS"; 194 break; 195 default: 196 LOG(FATAL) << "bad case in OpRegRegReg"; 197 break; 198 } 199 return NewLIR3(opcode, r_dest, r_src1, r_src2); 200} 201 202LIR* MipsMir2Lir::OpRegRegImm(OpKind op, int r_dest, int r_src1, int value) { 203 LIR *res; 204 MipsOpCode opcode = kMipsNop; 205 bool short_form = true; 206 207 switch (op) { 208 case kOpAdd: 209 if (IS_SIMM16(value)) { 210 opcode = kMipsAddiu; 211 } else { 212 short_form = false; 213 opcode = kMipsAddu; 214 } 215 break; 216 case kOpSub: 217 if (IS_SIMM16((-value))) { 218 value = -value; 219 opcode = kMipsAddiu; 220 } else { 221 short_form = false; 222 opcode = kMipsSubu; 223 } 224 break; 225 case kOpLsl: 226 DCHECK(value >= 0 && value <= 31); 227 opcode = kMipsSll; 228 break; 229 case kOpLsr: 230 DCHECK(value >= 0 && value <= 31); 231 opcode = kMipsSrl; 232 break; 233 case kOpAsr: 234 DCHECK(value >= 0 && value <= 31); 235 opcode = kMipsSra; 236 break; 237 case kOpAnd: 238 if (IS_UIMM16((value))) { 239 opcode = kMipsAndi; 240 } else { 241 short_form = false; 242 opcode = kMipsAnd; 243 } 244 break; 245 case kOpOr: 246 if (IS_UIMM16((value))) { 247 opcode = kMipsOri; 248 } else { 249 short_form = false; 250 opcode = kMipsOr; 251 } 252 break; 253 case kOpXor: 254 if (IS_UIMM16((value))) { 255 opcode = kMipsXori; 256 } else { 257 short_form = false; 258 opcode = kMipsXor; 259 } 260 break; 261 case kOpMul: 262 short_form = false; 263 opcode = kMipsMul; 264 break; 265 default: 266 LOG(FATAL) << "Bad case in OpRegRegImm"; 267 break; 268 } 269 270 if (short_form) { 271 res = NewLIR3(opcode, r_dest, r_src1, value); 272 } else { 273 if (r_dest != r_src1) { 274 res = LoadConstant(r_dest, value); 275 NewLIR3(opcode, r_dest, r_src1, r_dest); 276 } else { 277 int r_scratch = AllocTemp(); 278 res = LoadConstant(r_scratch, value); 279 NewLIR3(opcode, r_dest, r_src1, r_scratch); 280 } 281 } 282 return res; 283} 284 285LIR* MipsMir2Lir::OpRegReg(OpKind op, int r_dest_src1, int r_src2) { 286 MipsOpCode opcode = kMipsNop; 287 LIR *res; 288 switch (op) { 289 case kOpMov: 290 opcode = kMipsMove; 291 break; 292 case kOpMvn: 293 return NewLIR3(kMipsNor, r_dest_src1, r_src2, r_ZERO); 294 case kOpNeg: 295 return NewLIR3(kMipsSubu, r_dest_src1, r_ZERO, r_src2); 296 case kOpAdd: 297 case kOpAnd: 298 case kOpMul: 299 case kOpOr: 300 case kOpSub: 301 case kOpXor: 302 return OpRegRegReg(op, r_dest_src1, r_dest_src1, r_src2); 303 case kOp2Byte: 304#if __mips_isa_rev >= 2 305 res = NewLIR2(kMipsSeb, r_dest_src1, r_src2); 306#else 307 res = OpRegRegImm(kOpLsl, r_dest_src1, r_src2, 24); 308 OpRegRegImm(kOpAsr, r_dest_src1, r_dest_src1, 24); 309#endif 310 return res; 311 case kOp2Short: 312#if __mips_isa_rev >= 2 313 res = NewLIR2(kMipsSeh, r_dest_src1, r_src2); 314#else 315 res = OpRegRegImm(kOpLsl, r_dest_src1, r_src2, 16); 316 OpRegRegImm(kOpAsr, r_dest_src1, r_dest_src1, 16); 317#endif 318 return res; 319 case kOp2Char: 320 return NewLIR3(kMipsAndi, r_dest_src1, r_src2, 0xFFFF); 321 default: 322 LOG(FATAL) << "Bad case in OpRegReg"; 323 break; 324 } 325 return NewLIR2(opcode, r_dest_src1, r_src2); 326} 327 328LIR* MipsMir2Lir::OpCondRegReg(OpKind op, ConditionCode cc, int r_dest, int r_src) { 329 LOG(FATAL) << "Unexpected use of OpCondRegReg for MIPS"; 330 return NULL; 331} 332 333LIR* MipsMir2Lir::LoadConstantWide(int r_dest_lo, int r_dest_hi, int64_t value) { 334 LIR *res; 335 res = LoadConstantNoClobber(r_dest_lo, Low32Bits(value)); 336 LoadConstantNoClobber(r_dest_hi, High32Bits(value)); 337 return res; 338} 339 340/* Load value from base + scaled index. */ 341LIR* MipsMir2Lir::LoadBaseIndexed(int rBase, int r_index, int r_dest, 342 int scale, OpSize size) { 343 LIR *first = NULL; 344 LIR *res; 345 MipsOpCode opcode = kMipsNop; 346 int t_reg = AllocTemp(); 347 348 if (MIPS_FPREG(r_dest)) { 349 DCHECK(MIPS_SINGLEREG(r_dest)); 350 DCHECK((size == kWord) || (size == kSingle)); 351 size = kSingle; 352 } else { 353 if (size == kSingle) 354 size = kWord; 355 } 356 357 if (!scale) { 358 first = NewLIR3(kMipsAddu, t_reg , rBase, r_index); 359 } else { 360 first = OpRegRegImm(kOpLsl, t_reg, r_index, scale); 361 NewLIR3(kMipsAddu, t_reg , rBase, t_reg); 362 } 363 364 switch (size) { 365 case kSingle: 366 opcode = kMipsFlwc1; 367 break; 368 case kWord: 369 opcode = kMipsLw; 370 break; 371 case kUnsignedHalf: 372 opcode = kMipsLhu; 373 break; 374 case kSignedHalf: 375 opcode = kMipsLh; 376 break; 377 case kUnsignedByte: 378 opcode = kMipsLbu; 379 break; 380 case kSignedByte: 381 opcode = kMipsLb; 382 break; 383 default: 384 LOG(FATAL) << "Bad case in LoadBaseIndexed"; 385 } 386 387 res = NewLIR3(opcode, r_dest, 0, t_reg); 388 FreeTemp(t_reg); 389 return (first) ? first : res; 390} 391 392/* store value base base + scaled index. */ 393LIR* MipsMir2Lir::StoreBaseIndexed(int rBase, int r_index, int r_src, 394 int scale, OpSize size) { 395 LIR *first = NULL; 396 MipsOpCode opcode = kMipsNop; 397 int r_new_index = r_index; 398 int t_reg = AllocTemp(); 399 400 if (MIPS_FPREG(r_src)) { 401 DCHECK(MIPS_SINGLEREG(r_src)); 402 DCHECK((size == kWord) || (size == kSingle)); 403 size = kSingle; 404 } else { 405 if (size == kSingle) 406 size = kWord; 407 } 408 409 if (!scale) { 410 first = NewLIR3(kMipsAddu, t_reg , rBase, r_index); 411 } else { 412 first = OpRegRegImm(kOpLsl, t_reg, r_index, scale); 413 NewLIR3(kMipsAddu, t_reg , rBase, t_reg); 414 } 415 416 switch (size) { 417 case kSingle: 418 opcode = kMipsFswc1; 419 break; 420 case kWord: 421 opcode = kMipsSw; 422 break; 423 case kUnsignedHalf: 424 case kSignedHalf: 425 opcode = kMipsSh; 426 break; 427 case kUnsignedByte: 428 case kSignedByte: 429 opcode = kMipsSb; 430 break; 431 default: 432 LOG(FATAL) << "Bad case in StoreBaseIndexed"; 433 } 434 NewLIR3(opcode, r_src, 0, t_reg); 435 FreeTemp(r_new_index); 436 return first; 437} 438 439LIR* MipsMir2Lir::LoadBaseDispBody(int rBase, int displacement, int r_dest, 440 int r_dest_hi, OpSize size, int s_reg) { 441/* 442 * Load value from base + displacement. Optionally perform null check 443 * on base (which must have an associated s_reg and MIR). If not 444 * performing null check, incoming MIR can be null. IMPORTANT: this 445 * code must not allocate any new temps. If a new register is needed 446 * and base and dest are the same, spill some other register to 447 * rlp and then restore. 448 */ 449 LIR *res; 450 LIR *load = NULL; 451 LIR *load2 = NULL; 452 MipsOpCode opcode = kMipsNop; 453 bool short_form = IS_SIMM16(displacement); 454 bool pair = false; 455 456 switch (size) { 457 case kLong: 458 case kDouble: 459 pair = true; 460 opcode = kMipsLw; 461 if (MIPS_FPREG(r_dest)) { 462 opcode = kMipsFlwc1; 463 if (MIPS_DOUBLEREG(r_dest)) { 464 r_dest = r_dest - MIPS_FP_DOUBLE; 465 } else { 466 DCHECK(MIPS_FPREG(r_dest_hi)); 467 DCHECK(r_dest == (r_dest_hi - 1)); 468 } 469 r_dest_hi = r_dest + 1; 470 } 471 short_form = IS_SIMM16_2WORD(displacement); 472 DCHECK_EQ((displacement & 0x3), 0); 473 break; 474 case kWord: 475 case kSingle: 476 opcode = kMipsLw; 477 if (MIPS_FPREG(r_dest)) { 478 opcode = kMipsFlwc1; 479 DCHECK(MIPS_SINGLEREG(r_dest)); 480 } 481 DCHECK_EQ((displacement & 0x3), 0); 482 break; 483 case kUnsignedHalf: 484 opcode = kMipsLhu; 485 DCHECK_EQ((displacement & 0x1), 0); 486 break; 487 case kSignedHalf: 488 opcode = kMipsLh; 489 DCHECK_EQ((displacement & 0x1), 0); 490 break; 491 case kUnsignedByte: 492 opcode = kMipsLbu; 493 break; 494 case kSignedByte: 495 opcode = kMipsLb; 496 break; 497 default: 498 LOG(FATAL) << "Bad case in LoadBaseIndexedBody"; 499 } 500 501 if (short_form) { 502 if (!pair) { 503 load = res = NewLIR3(opcode, r_dest, displacement, rBase); 504 } else { 505 load = res = NewLIR3(opcode, r_dest, 506 displacement + LOWORD_OFFSET, rBase); 507 load2 = NewLIR3(opcode, r_dest_hi, 508 displacement + HIWORD_OFFSET, rBase); 509 } 510 } else { 511 if (pair) { 512 int r_tmp = AllocTemp(); 513 res = OpRegRegImm(kOpAdd, r_tmp, rBase, displacement); 514 load = NewLIR3(opcode, r_dest, LOWORD_OFFSET, r_tmp); 515 load2 = NewLIR3(opcode, r_dest_hi, HIWORD_OFFSET, r_tmp); 516 FreeTemp(r_tmp); 517 } else { 518 int r_tmp = (rBase == r_dest) ? AllocTemp() : r_dest; 519 res = OpRegRegImm(kOpAdd, r_tmp, rBase, displacement); 520 load = NewLIR3(opcode, r_dest, 0, r_tmp); 521 if (r_tmp != r_dest) 522 FreeTemp(r_tmp); 523 } 524 } 525 526 if (rBase == rMIPS_SP) { 527 AnnotateDalvikRegAccess(load, (displacement + (pair ? LOWORD_OFFSET : 0)) >> 2, 528 true /* is_load */, pair /* is64bit */); 529 if (pair) { 530 AnnotateDalvikRegAccess(load2, (displacement + HIWORD_OFFSET) >> 2, 531 true /* is_load */, pair /* is64bit */); 532 } 533 } 534 return load; 535} 536 537LIR* MipsMir2Lir::LoadBaseDisp(int rBase, int displacement, int r_dest, 538 OpSize size, int s_reg) { 539 return LoadBaseDispBody(rBase, displacement, r_dest, -1, 540 size, s_reg); 541} 542 543LIR* MipsMir2Lir::LoadBaseDispWide(int rBase, int displacement, 544 int r_dest_lo, int r_dest_hi, int s_reg) { 545 return LoadBaseDispBody(rBase, displacement, r_dest_lo, r_dest_hi, kLong, s_reg); 546} 547 548LIR* MipsMir2Lir::StoreBaseDispBody(int rBase, int displacement, 549 int r_src, int r_src_hi, OpSize size) { 550 LIR *res; 551 LIR *store = NULL; 552 LIR *store2 = NULL; 553 MipsOpCode opcode = kMipsNop; 554 bool short_form = IS_SIMM16(displacement); 555 bool pair = false; 556 557 switch (size) { 558 case kLong: 559 case kDouble: 560 pair = true; 561 opcode = kMipsSw; 562 if (MIPS_FPREG(r_src)) { 563 opcode = kMipsFswc1; 564 if (MIPS_DOUBLEREG(r_src)) { 565 r_src = r_src - MIPS_FP_DOUBLE; 566 } else { 567 DCHECK(MIPS_FPREG(r_src_hi)); 568 DCHECK_EQ(r_src, (r_src_hi - 1)); 569 } 570 r_src_hi = r_src + 1; 571 } 572 short_form = IS_SIMM16_2WORD(displacement); 573 DCHECK_EQ((displacement & 0x3), 0); 574 break; 575 case kWord: 576 case kSingle: 577 opcode = kMipsSw; 578 if (MIPS_FPREG(r_src)) { 579 opcode = kMipsFswc1; 580 DCHECK(MIPS_SINGLEREG(r_src)); 581 } 582 DCHECK_EQ((displacement & 0x3), 0); 583 break; 584 case kUnsignedHalf: 585 case kSignedHalf: 586 opcode = kMipsSh; 587 DCHECK_EQ((displacement & 0x1), 0); 588 break; 589 case kUnsignedByte: 590 case kSignedByte: 591 opcode = kMipsSb; 592 break; 593 default: 594 LOG(FATAL) << "Bad case in StoreBaseIndexedBody"; 595 } 596 597 if (short_form) { 598 if (!pair) { 599 store = res = NewLIR3(opcode, r_src, displacement, rBase); 600 } else { 601 store = res = NewLIR3(opcode, r_src, displacement + LOWORD_OFFSET, 602 rBase); 603 store2 = NewLIR3(opcode, r_src_hi, displacement + HIWORD_OFFSET, 604 rBase); 605 } 606 } else { 607 int r_scratch = AllocTemp(); 608 res = OpRegRegImm(kOpAdd, r_scratch, rBase, displacement); 609 if (!pair) { 610 store = NewLIR3(opcode, r_src, 0, r_scratch); 611 } else { 612 store = NewLIR3(opcode, r_src, LOWORD_OFFSET, r_scratch); 613 store2 = NewLIR3(opcode, r_src_hi, HIWORD_OFFSET, r_scratch); 614 } 615 FreeTemp(r_scratch); 616 } 617 618 if (rBase == rMIPS_SP) { 619 AnnotateDalvikRegAccess(store, (displacement + (pair ? LOWORD_OFFSET : 0)) >> 2, 620 false /* is_load */, pair /* is64bit */); 621 if (pair) { 622 AnnotateDalvikRegAccess(store2, (displacement + HIWORD_OFFSET) >> 2, 623 false /* is_load */, pair /* is64bit */); 624 } 625 } 626 627 return res; 628} 629 630LIR* MipsMir2Lir::StoreBaseDisp(int rBase, int displacement, int r_src, 631 OpSize size) { 632 return StoreBaseDispBody(rBase, displacement, r_src, -1, size); 633} 634 635LIR* MipsMir2Lir::StoreBaseDispWide(int rBase, int displacement, 636 int r_src_lo, int r_src_hi) { 637 return StoreBaseDispBody(rBase, displacement, r_src_lo, r_src_hi, kLong); 638} 639 640LIR* MipsMir2Lir::OpThreadMem(OpKind op, ThreadOffset thread_offset) { 641 LOG(FATAL) << "Unexpected use of OpThreadMem for MIPS"; 642 return NULL; 643} 644 645LIR* MipsMir2Lir::OpMem(OpKind op, int rBase, int disp) { 646 LOG(FATAL) << "Unexpected use of OpMem for MIPS"; 647 return NULL; 648} 649 650LIR* MipsMir2Lir::StoreBaseIndexedDisp(int rBase, int r_index, int scale, int displacement, 651 int r_src, int r_src_hi, OpSize size, int s_reg) { 652 LOG(FATAL) << "Unexpected use of StoreBaseIndexedDisp for MIPS"; 653 return NULL; 654} 655 656LIR* MipsMir2Lir::OpRegMem(OpKind op, int r_dest, int rBase, 657 int offset) { 658 LOG(FATAL) << "Unexpected use of OpRegMem for MIPS"; 659 return NULL; 660} 661 662LIR* MipsMir2Lir::LoadBaseIndexedDisp(int rBase, int r_index, int scale, int displacement, 663 int r_dest, int r_dest_hi, OpSize size, int s_reg) { 664 LOG(FATAL) << "Unexpected use of LoadBaseIndexedDisp for MIPS"; 665 return NULL; 666} 667 668LIR* MipsMir2Lir::OpCondBranch(ConditionCode cc, LIR* target) { 669 LOG(FATAL) << "Unexpected use of OpCondBranch for MIPS"; 670 return NULL; 671} 672 673} // namespace art 674