utility_mips.cc revision 468532ea115657709bc32ee498e701a4c71762d4
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::LoadConstantWide(int r_dest_lo, int r_dest_hi, int64_t value) { 329 LIR *res; 330 res = LoadConstantNoClobber(r_dest_lo, Low32Bits(value)); 331 LoadConstantNoClobber(r_dest_hi, High32Bits(value)); 332 return res; 333} 334 335/* Load value from base + scaled index. */ 336LIR* MipsMir2Lir::LoadBaseIndexed(int rBase, int r_index, int r_dest, 337 int scale, OpSize size) { 338 LIR *first = NULL; 339 LIR *res; 340 MipsOpCode opcode = kMipsNop; 341 int t_reg = AllocTemp(); 342 343 if (MIPS_FPREG(r_dest)) { 344 DCHECK(MIPS_SINGLEREG(r_dest)); 345 DCHECK((size == kWord) || (size == kSingle)); 346 size = kSingle; 347 } else { 348 if (size == kSingle) 349 size = kWord; 350 } 351 352 if (!scale) { 353 first = NewLIR3(kMipsAddu, t_reg , rBase, r_index); 354 } else { 355 first = OpRegRegImm(kOpLsl, t_reg, r_index, scale); 356 NewLIR3(kMipsAddu, t_reg , rBase, t_reg); 357 } 358 359 switch (size) { 360 case kSingle: 361 opcode = kMipsFlwc1; 362 break; 363 case kWord: 364 opcode = kMipsLw; 365 break; 366 case kUnsignedHalf: 367 opcode = kMipsLhu; 368 break; 369 case kSignedHalf: 370 opcode = kMipsLh; 371 break; 372 case kUnsignedByte: 373 opcode = kMipsLbu; 374 break; 375 case kSignedByte: 376 opcode = kMipsLb; 377 break; 378 default: 379 LOG(FATAL) << "Bad case in LoadBaseIndexed"; 380 } 381 382 res = NewLIR3(opcode, r_dest, 0, t_reg); 383 FreeTemp(t_reg); 384 return (first) ? first : res; 385} 386 387/* store value base base + scaled index. */ 388LIR* MipsMir2Lir::StoreBaseIndexed(int rBase, int r_index, int r_src, 389 int scale, OpSize size) { 390 LIR *first = NULL; 391 MipsOpCode opcode = kMipsNop; 392 int r_new_index = r_index; 393 int t_reg = AllocTemp(); 394 395 if (MIPS_FPREG(r_src)) { 396 DCHECK(MIPS_SINGLEREG(r_src)); 397 DCHECK((size == kWord) || (size == kSingle)); 398 size = kSingle; 399 } else { 400 if (size == kSingle) 401 size = kWord; 402 } 403 404 if (!scale) { 405 first = NewLIR3(kMipsAddu, t_reg , rBase, r_index); 406 } else { 407 first = OpRegRegImm(kOpLsl, t_reg, r_index, scale); 408 NewLIR3(kMipsAddu, t_reg , rBase, t_reg); 409 } 410 411 switch (size) { 412 case kSingle: 413 opcode = kMipsFswc1; 414 break; 415 case kWord: 416 opcode = kMipsSw; 417 break; 418 case kUnsignedHalf: 419 case kSignedHalf: 420 opcode = kMipsSh; 421 break; 422 case kUnsignedByte: 423 case kSignedByte: 424 opcode = kMipsSb; 425 break; 426 default: 427 LOG(FATAL) << "Bad case in StoreBaseIndexed"; 428 } 429 NewLIR3(opcode, r_src, 0, t_reg); 430 FreeTemp(r_new_index); 431 return first; 432} 433 434LIR* MipsMir2Lir::LoadBaseDispBody(int rBase, int displacement, int r_dest, 435 int r_dest_hi, OpSize size, int s_reg) { 436/* 437 * Load value from base + displacement. Optionally perform null check 438 * on base (which must have an associated s_reg and MIR). If not 439 * performing null check, incoming MIR can be null. IMPORTANT: this 440 * code must not allocate any new temps. If a new register is needed 441 * and base and dest are the same, spill some other register to 442 * rlp and then restore. 443 */ 444 LIR *res; 445 LIR *load = NULL; 446 LIR *load2 = NULL; 447 MipsOpCode opcode = kMipsNop; 448 bool short_form = IS_SIMM16(displacement); 449 bool pair = false; 450 451 switch (size) { 452 case kLong: 453 case kDouble: 454 pair = true; 455 opcode = kMipsLw; 456 if (MIPS_FPREG(r_dest)) { 457 opcode = kMipsFlwc1; 458 if (MIPS_DOUBLEREG(r_dest)) { 459 r_dest = r_dest - MIPS_FP_DOUBLE; 460 } else { 461 DCHECK(MIPS_FPREG(r_dest_hi)); 462 DCHECK(r_dest == (r_dest_hi - 1)); 463 } 464 r_dest_hi = r_dest + 1; 465 } 466 short_form = IS_SIMM16_2WORD(displacement); 467 DCHECK_EQ((displacement & 0x3), 0); 468 break; 469 case kWord: 470 case kSingle: 471 opcode = kMipsLw; 472 if (MIPS_FPREG(r_dest)) { 473 opcode = kMipsFlwc1; 474 DCHECK(MIPS_SINGLEREG(r_dest)); 475 } 476 DCHECK_EQ((displacement & 0x3), 0); 477 break; 478 case kUnsignedHalf: 479 opcode = kMipsLhu; 480 DCHECK_EQ((displacement & 0x1), 0); 481 break; 482 case kSignedHalf: 483 opcode = kMipsLh; 484 DCHECK_EQ((displacement & 0x1), 0); 485 break; 486 case kUnsignedByte: 487 opcode = kMipsLbu; 488 break; 489 case kSignedByte: 490 opcode = kMipsLb; 491 break; 492 default: 493 LOG(FATAL) << "Bad case in LoadBaseIndexedBody"; 494 } 495 496 if (short_form) { 497 if (!pair) { 498 load = res = NewLIR3(opcode, r_dest, displacement, rBase); 499 } else { 500 load = res = NewLIR3(opcode, r_dest, 501 displacement + LOWORD_OFFSET, rBase); 502 load2 = NewLIR3(opcode, r_dest_hi, 503 displacement + HIWORD_OFFSET, rBase); 504 } 505 } else { 506 if (pair) { 507 int r_tmp = AllocFreeTemp(); 508 res = OpRegRegImm(kOpAdd, r_tmp, rBase, displacement); 509 load = NewLIR3(opcode, r_dest, LOWORD_OFFSET, r_tmp); 510 load2 = NewLIR3(opcode, r_dest_hi, HIWORD_OFFSET, r_tmp); 511 FreeTemp(r_tmp); 512 } else { 513 int r_tmp = (rBase == r_dest) ? AllocFreeTemp() : r_dest; 514 res = OpRegRegImm(kOpAdd, r_tmp, rBase, displacement); 515 load = NewLIR3(opcode, r_dest, 0, r_tmp); 516 if (r_tmp != r_dest) 517 FreeTemp(r_tmp); 518 } 519 } 520 521 if (rBase == rMIPS_SP) { 522 AnnotateDalvikRegAccess(load, (displacement + (pair ? LOWORD_OFFSET : 0)) >> 2, 523 true /* is_load */, pair /* is64bit */); 524 if (pair) { 525 AnnotateDalvikRegAccess(load2, (displacement + HIWORD_OFFSET) >> 2, 526 true /* is_load */, pair /* is64bit */); 527 } 528 } 529 return load; 530} 531 532LIR* MipsMir2Lir::LoadBaseDisp(int rBase, int displacement, int r_dest, 533 OpSize size, int s_reg) { 534 return LoadBaseDispBody(rBase, displacement, r_dest, -1, 535 size, s_reg); 536} 537 538LIR* MipsMir2Lir::LoadBaseDispWide(int rBase, int displacement, 539 int r_dest_lo, int r_dest_hi, int s_reg) { 540 return LoadBaseDispBody(rBase, displacement, r_dest_lo, r_dest_hi, kLong, s_reg); 541} 542 543LIR* MipsMir2Lir::StoreBaseDispBody(int rBase, int displacement, 544 int r_src, int r_src_hi, OpSize size) { 545 LIR *res; 546 LIR *store = NULL; 547 LIR *store2 = NULL; 548 MipsOpCode opcode = kMipsNop; 549 bool short_form = IS_SIMM16(displacement); 550 bool pair = false; 551 552 switch (size) { 553 case kLong: 554 case kDouble: 555 pair = true; 556 opcode = kMipsSw; 557 if (MIPS_FPREG(r_src)) { 558 opcode = kMipsFswc1; 559 if (MIPS_DOUBLEREG(r_src)) { 560 r_src = r_src - MIPS_FP_DOUBLE; 561 } else { 562 DCHECK(MIPS_FPREG(r_src_hi)); 563 DCHECK_EQ(r_src, (r_src_hi - 1)); 564 } 565 r_src_hi = r_src + 1; 566 } 567 short_form = IS_SIMM16_2WORD(displacement); 568 DCHECK_EQ((displacement & 0x3), 0); 569 break; 570 case kWord: 571 case kSingle: 572 opcode = kMipsSw; 573 if (MIPS_FPREG(r_src)) { 574 opcode = kMipsFswc1; 575 DCHECK(MIPS_SINGLEREG(r_src)); 576 } 577 DCHECK_EQ((displacement & 0x3), 0); 578 break; 579 case kUnsignedHalf: 580 case kSignedHalf: 581 opcode = kMipsSh; 582 DCHECK_EQ((displacement & 0x1), 0); 583 break; 584 case kUnsignedByte: 585 case kSignedByte: 586 opcode = kMipsSb; 587 break; 588 default: 589 LOG(FATAL) << "Bad case in StoreBaseIndexedBody"; 590 } 591 592 if (short_form) { 593 if (!pair) { 594 store = res = NewLIR3(opcode, r_src, displacement, rBase); 595 } else { 596 store = res = NewLIR3(opcode, r_src, displacement + LOWORD_OFFSET, 597 rBase); 598 store2 = NewLIR3(opcode, r_src_hi, displacement + HIWORD_OFFSET, 599 rBase); 600 } 601 } else { 602 int r_scratch = AllocTemp(); 603 res = OpRegRegImm(kOpAdd, r_scratch, rBase, displacement); 604 if (!pair) { 605 store = NewLIR3(opcode, r_src, 0, r_scratch); 606 } else { 607 store = NewLIR3(opcode, r_src, LOWORD_OFFSET, r_scratch); 608 store2 = NewLIR3(opcode, r_src_hi, HIWORD_OFFSET, r_scratch); 609 } 610 FreeTemp(r_scratch); 611 } 612 613 if (rBase == rMIPS_SP) { 614 AnnotateDalvikRegAccess(store, (displacement + (pair ? LOWORD_OFFSET : 0)) >> 2, 615 false /* is_load */, pair /* is64bit */); 616 if (pair) { 617 AnnotateDalvikRegAccess(store2, (displacement + HIWORD_OFFSET) >> 2, 618 false /* is_load */, pair /* is64bit */); 619 } 620 } 621 622 return res; 623} 624 625LIR* MipsMir2Lir::StoreBaseDisp(int rBase, int displacement, int r_src, 626 OpSize size) { 627 return StoreBaseDispBody(rBase, displacement, r_src, -1, size); 628} 629 630LIR* MipsMir2Lir::StoreBaseDispWide(int rBase, int displacement, 631 int r_src_lo, int r_src_hi) { 632 return StoreBaseDispBody(rBase, displacement, r_src_lo, r_src_hi, kLong); 633} 634 635LIR* MipsMir2Lir::OpThreadMem(OpKind op, ThreadOffset thread_offset) { 636 LOG(FATAL) << "Unexpected use of OpThreadMem for MIPS"; 637 return NULL; 638} 639 640LIR* MipsMir2Lir::OpMem(OpKind op, int rBase, int disp) { 641 LOG(FATAL) << "Unexpected use of OpMem for MIPS"; 642 return NULL; 643} 644 645LIR* MipsMir2Lir::StoreBaseIndexedDisp(int rBase, int r_index, int scale, int displacement, 646 int r_src, int r_src_hi, OpSize size, int s_reg) { 647 LOG(FATAL) << "Unexpected use of StoreBaseIndexedDisp for MIPS"; 648 return NULL; 649} 650 651LIR* MipsMir2Lir::OpRegMem(OpKind op, int r_dest, int rBase, 652 int offset) { 653 LOG(FATAL) << "Unexpected use of OpRegMem for MIPS"; 654 return NULL; 655} 656 657LIR* MipsMir2Lir::LoadBaseIndexedDisp(int rBase, int r_index, int scale, int displacement, 658 int r_dest, int r_dest_hi, OpSize size, int s_reg) { 659 LOG(FATAL) << "Unexpected use of LoadBaseIndexedDisp for MIPS"; 660 return NULL; 661} 662 663LIR* MipsMir2Lir::OpCondBranch(ConditionCode cc, LIR* target) { 664 LOG(FATAL) << "Unexpected use of OpCondBranch for MIPS"; 665 return NULL; 666} 667 668} // namespace art 669