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