int_mips.cc revision 848871b4d8481229c32e0d048a9856e5a9a17ef9
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/* This file contains codegen for the Mips ISA */ 18 19#include "codegen_mips.h" 20#include "dex/quick/mir_to_lir-inl.h" 21#include "entrypoints/quick/quick_entrypoints.h" 22#include "mips_lir.h" 23#include "mirror/array.h" 24 25namespace art { 26 27/* 28 * Compare two 64-bit values 29 * x = y return 0 30 * x < y return -1 31 * x > y return 1 32 * 33 * slt t0, x.hi, y.hi; # (x.hi < y.hi) ? 1:0 34 * sgt t1, x.hi, y.hi; # (y.hi > x.hi) ? 1:0 35 * subu res, t0, t1 # res = -1:1:0 for [ < > = ] 36 * bnez res, finish 37 * sltu t0, x.lo, y.lo 38 * sgtu r1, x.lo, y.lo 39 * subu res, t0, t1 40 * finish: 41 * 42 */ 43void MipsMir2Lir::GenCmpLong(RegLocation rl_dest, RegLocation rl_src1, 44 RegLocation rl_src2) { 45 rl_src1 = LoadValueWide(rl_src1, kCoreReg); 46 rl_src2 = LoadValueWide(rl_src2, kCoreReg); 47 int t0 = AllocTemp(); 48 int t1 = AllocTemp(); 49 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); 50 NewLIR3(kMipsSlt, t0, rl_src1.high_reg, rl_src2.high_reg); 51 NewLIR3(kMipsSlt, t1, rl_src2.high_reg, rl_src1.high_reg); 52 NewLIR3(kMipsSubu, rl_result.low_reg, t1, t0); 53 LIR* branch = OpCmpImmBranch(kCondNe, rl_result.low_reg, 0, NULL); 54 NewLIR3(kMipsSltu, t0, rl_src1.low_reg, rl_src2.low_reg); 55 NewLIR3(kMipsSltu, t1, rl_src2.low_reg, rl_src1.low_reg); 56 NewLIR3(kMipsSubu, rl_result.low_reg, t1, t0); 57 FreeTemp(t0); 58 FreeTemp(t1); 59 LIR* target = NewLIR0(kPseudoTargetLabel); 60 branch->target = target; 61 StoreValue(rl_dest, rl_result); 62} 63 64LIR* MipsMir2Lir::OpCmpBranch(ConditionCode cond, int src1, int src2, 65 LIR* target) { 66 LIR* branch; 67 MipsOpCode slt_op; 68 MipsOpCode br_op; 69 bool cmp_zero = false; 70 bool swapped = false; 71 switch (cond) { 72 case kCondEq: 73 br_op = kMipsBeq; 74 cmp_zero = true; 75 break; 76 case kCondNe: 77 br_op = kMipsBne; 78 cmp_zero = true; 79 break; 80 case kCondCc: 81 slt_op = kMipsSltu; 82 br_op = kMipsBnez; 83 break; 84 case kCondCs: 85 slt_op = kMipsSltu; 86 br_op = kMipsBeqz; 87 break; 88 case kCondGe: 89 slt_op = kMipsSlt; 90 br_op = kMipsBeqz; 91 break; 92 case kCondGt: 93 slt_op = kMipsSlt; 94 br_op = kMipsBnez; 95 swapped = true; 96 break; 97 case kCondLe: 98 slt_op = kMipsSlt; 99 br_op = kMipsBeqz; 100 swapped = true; 101 break; 102 case kCondLt: 103 slt_op = kMipsSlt; 104 br_op = kMipsBnez; 105 break; 106 case kCondHi: // Gtu 107 slt_op = kMipsSltu; 108 br_op = kMipsBnez; 109 swapped = true; 110 break; 111 default: 112 LOG(FATAL) << "No support for ConditionCode: " << cond; 113 return NULL; 114 } 115 if (cmp_zero) { 116 branch = NewLIR2(br_op, src1, src2); 117 } else { 118 int t_reg = AllocTemp(); 119 if (swapped) { 120 NewLIR3(slt_op, t_reg, src2, src1); 121 } else { 122 NewLIR3(slt_op, t_reg, src1, src2); 123 } 124 branch = NewLIR1(br_op, t_reg); 125 FreeTemp(t_reg); 126 } 127 branch->target = target; 128 return branch; 129} 130 131LIR* MipsMir2Lir::OpCmpImmBranch(ConditionCode cond, int reg, 132 int check_value, LIR* target) { 133 LIR* branch; 134 if (check_value != 0) { 135 // TUNING: handle s16 & kCondLt/Mi case using slti 136 int t_reg = AllocTemp(); 137 LoadConstant(t_reg, check_value); 138 branch = OpCmpBranch(cond, reg, t_reg, target); 139 FreeTemp(t_reg); 140 return branch; 141 } 142 MipsOpCode opc; 143 switch (cond) { 144 case kCondEq: opc = kMipsBeqz; break; 145 case kCondGe: opc = kMipsBgez; break; 146 case kCondGt: opc = kMipsBgtz; break; 147 case kCondLe: opc = kMipsBlez; break; 148 // case KCondMi: 149 case kCondLt: opc = kMipsBltz; break; 150 case kCondNe: opc = kMipsBnez; break; 151 default: 152 // Tuning: use slti when applicable 153 int t_reg = AllocTemp(); 154 LoadConstant(t_reg, check_value); 155 branch = OpCmpBranch(cond, reg, t_reg, target); 156 FreeTemp(t_reg); 157 return branch; 158 } 159 branch = NewLIR1(opc, reg); 160 branch->target = target; 161 return branch; 162} 163 164LIR* MipsMir2Lir::OpRegCopyNoInsert(int r_dest, int r_src) { 165 if (MIPS_FPREG(r_dest) || MIPS_FPREG(r_src)) 166 return OpFpRegCopy(r_dest, r_src); 167 LIR* res = RawLIR(current_dalvik_offset_, kMipsMove, 168 r_dest, r_src); 169 if (!(cu_->disable_opt & (1 << kSafeOptimizations)) && r_dest == r_src) { 170 res->flags.is_nop = true; 171 } 172 return res; 173} 174 175LIR* MipsMir2Lir::OpRegCopy(int r_dest, int r_src) { 176 LIR *res = OpRegCopyNoInsert(r_dest, r_src); 177 AppendLIR(res); 178 return res; 179} 180 181void MipsMir2Lir::OpRegCopyWide(int dest_lo, int dest_hi, int src_lo, 182 int src_hi) { 183 bool dest_fp = MIPS_FPREG(dest_lo) && MIPS_FPREG(dest_hi); 184 bool src_fp = MIPS_FPREG(src_lo) && MIPS_FPREG(src_hi); 185 assert(MIPS_FPREG(src_lo) == MIPS_FPREG(src_hi)); 186 assert(MIPS_FPREG(dest_lo) == MIPS_FPREG(dest_hi)); 187 if (dest_fp) { 188 if (src_fp) { 189 OpRegCopy(S2d(dest_lo, dest_hi), S2d(src_lo, src_hi)); 190 } else { 191 /* note the operands are swapped for the mtc1 instr */ 192 NewLIR2(kMipsMtc1, src_lo, dest_lo); 193 NewLIR2(kMipsMtc1, src_hi, dest_hi); 194 } 195 } else { 196 if (src_fp) { 197 NewLIR2(kMipsMfc1, dest_lo, src_lo); 198 NewLIR2(kMipsMfc1, dest_hi, src_hi); 199 } else { 200 // Handle overlap 201 if (src_hi == dest_lo) { 202 OpRegCopy(dest_hi, src_hi); 203 OpRegCopy(dest_lo, src_lo); 204 } else { 205 OpRegCopy(dest_lo, src_lo); 206 OpRegCopy(dest_hi, src_hi); 207 } 208 } 209 } 210} 211 212void MipsMir2Lir::GenSelect(BasicBlock* bb, MIR* mir) { 213 UNIMPLEMENTED(FATAL) << "Need codegen for select"; 214} 215 216void MipsMir2Lir::GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir) { 217 UNIMPLEMENTED(FATAL) << "Need codegen for fused long cmp branch"; 218} 219 220LIR* MipsMir2Lir::GenRegMemCheck(ConditionCode c_code, 221 int reg1, int base, int offset, ThrowKind kind) { 222 LOG(FATAL) << "Unexpected use of GenRegMemCheck for Arm"; 223 return NULL; 224} 225 226RegLocation MipsMir2Lir::GenDivRem(RegLocation rl_dest, int reg1, int reg2, 227 bool is_div) { 228 NewLIR4(kMipsDiv, r_HI, r_LO, reg1, reg2); 229 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); 230 if (is_div) { 231 NewLIR2(kMipsMflo, rl_result.low_reg, r_LO); 232 } else { 233 NewLIR2(kMipsMfhi, rl_result.low_reg, r_HI); 234 } 235 return rl_result; 236} 237 238RegLocation MipsMir2Lir::GenDivRemLit(RegLocation rl_dest, int reg1, int lit, 239 bool is_div) { 240 int t_reg = AllocTemp(); 241 NewLIR3(kMipsAddiu, t_reg, r_ZERO, lit); 242 NewLIR4(kMipsDiv, r_HI, r_LO, reg1, t_reg); 243 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); 244 if (is_div) { 245 NewLIR2(kMipsMflo, rl_result.low_reg, r_LO); 246 } else { 247 NewLIR2(kMipsMfhi, rl_result.low_reg, r_HI); 248 } 249 FreeTemp(t_reg); 250 return rl_result; 251} 252 253void MipsMir2Lir::OpLea(int rBase, int reg1, int reg2, int scale, int offset) { 254 LOG(FATAL) << "Unexpected use of OpLea for Arm"; 255} 256 257void MipsMir2Lir::OpTlsCmp(ThreadOffset offset, int val) { 258 LOG(FATAL) << "Unexpected use of OpTlsCmp for Arm"; 259} 260 261bool MipsMir2Lir::GenInlinedCas32(CallInfo* info, bool need_write_barrier) { 262 DCHECK_NE(cu_->instruction_set, kThumb2); 263 return false; 264} 265 266bool MipsMir2Lir::GenInlinedSqrt(CallInfo* info) { 267 DCHECK_NE(cu_->instruction_set, kThumb2); 268 return false; 269} 270 271LIR* MipsMir2Lir::OpPcRelLoad(int reg, LIR* target) { 272 LOG(FATAL) << "Unexpected use of OpPcRelLoad for Mips"; 273 return NULL; 274} 275 276LIR* MipsMir2Lir::OpVldm(int rBase, int count) { 277 LOG(FATAL) << "Unexpected use of OpVldm for Mips"; 278 return NULL; 279} 280 281LIR* MipsMir2Lir::OpVstm(int rBase, int count) { 282 LOG(FATAL) << "Unexpected use of OpVstm for Mips"; 283 return NULL; 284} 285 286void MipsMir2Lir::GenMultiplyByTwoBitMultiplier(RegLocation rl_src, 287 RegLocation rl_result, int lit, 288 int first_bit, int second_bit) { 289 int t_reg = AllocTemp(); 290 OpRegRegImm(kOpLsl, t_reg, rl_src.low_reg, second_bit - first_bit); 291 OpRegRegReg(kOpAdd, rl_result.low_reg, rl_src.low_reg, t_reg); 292 FreeTemp(t_reg); 293 if (first_bit != 0) { 294 OpRegRegImm(kOpLsl, rl_result.low_reg, rl_result.low_reg, first_bit); 295 } 296} 297 298void MipsMir2Lir::GenDivZeroCheck(int reg_lo, int reg_hi) { 299 int t_reg = AllocTemp(); 300 OpRegRegReg(kOpOr, t_reg, reg_lo, reg_hi); 301 GenImmedCheck(kCondEq, t_reg, 0, kThrowDivZero); 302 FreeTemp(t_reg); 303} 304 305// Test suspend flag, return target of taken suspend branch 306LIR* MipsMir2Lir::OpTestSuspend(LIR* target) { 307 OpRegImm(kOpSub, rMIPS_SUSPEND, 1); 308 return OpCmpImmBranch((target == NULL) ? kCondEq : kCondNe, rMIPS_SUSPEND, 0, target); 309} 310 311// Decrement register and branch on condition 312LIR* MipsMir2Lir::OpDecAndBranch(ConditionCode c_code, int reg, LIR* target) { 313 OpRegImm(kOpSub, reg, 1); 314 return OpCmpImmBranch(c_code, reg, 0, target); 315} 316 317bool MipsMir2Lir::SmallLiteralDivide(Instruction::Code dalvik_opcode, 318 RegLocation rl_src, RegLocation rl_dest, int lit) { 319 LOG(FATAL) << "Unexpected use of smallLiteralDive in Mips"; 320 return false; 321} 322 323LIR* MipsMir2Lir::OpIT(ConditionCode cond, const char* guide) { 324 LOG(FATAL) << "Unexpected use of OpIT in Mips"; 325 return NULL; 326} 327 328void MipsMir2Lir::GenMulLong(RegLocation rl_dest, RegLocation rl_src1, 329 RegLocation rl_src2) { 330 LOG(FATAL) << "Unexpected use of GenMulLong for Mips"; 331} 332 333void MipsMir2Lir::GenAddLong(RegLocation rl_dest, RegLocation rl_src1, 334 RegLocation rl_src2) { 335 rl_src1 = LoadValueWide(rl_src1, kCoreReg); 336 rl_src2 = LoadValueWide(rl_src2, kCoreReg); 337 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); 338 /* 339 * [v1 v0] = [a1 a0] + [a3 a2]; 340 * addu v0,a2,a0 341 * addu t1,a3,a1 342 * sltu v1,v0,a2 343 * addu v1,v1,t1 344 */ 345 346 OpRegRegReg(kOpAdd, rl_result.low_reg, rl_src2.low_reg, rl_src1.low_reg); 347 int t_reg = AllocTemp(); 348 OpRegRegReg(kOpAdd, t_reg, rl_src2.high_reg, rl_src1.high_reg); 349 NewLIR3(kMipsSltu, rl_result.high_reg, rl_result.low_reg, rl_src2.low_reg); 350 OpRegRegReg(kOpAdd, rl_result.high_reg, rl_result.high_reg, t_reg); 351 FreeTemp(t_reg); 352 StoreValueWide(rl_dest, rl_result); 353} 354 355void MipsMir2Lir::GenSubLong(RegLocation rl_dest, RegLocation rl_src1, 356 RegLocation rl_src2) { 357 rl_src1 = LoadValueWide(rl_src1, kCoreReg); 358 rl_src2 = LoadValueWide(rl_src2, kCoreReg); 359 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); 360 /* 361 * [v1 v0] = [a1 a0] - [a3 a2]; 362 * sltu t1,a0,a2 363 * subu v0,a0,a2 364 * subu v1,a1,a3 365 * subu v1,v1,t1 366 */ 367 368 int t_reg = AllocTemp(); 369 NewLIR3(kMipsSltu, t_reg, rl_src1.low_reg, rl_src2.low_reg); 370 OpRegRegReg(kOpSub, rl_result.low_reg, rl_src1.low_reg, rl_src2.low_reg); 371 OpRegRegReg(kOpSub, rl_result.high_reg, rl_src1.high_reg, rl_src2.high_reg); 372 OpRegRegReg(kOpSub, rl_result.high_reg, rl_result.high_reg, t_reg); 373 FreeTemp(t_reg); 374 StoreValueWide(rl_dest, rl_result); 375} 376 377void MipsMir2Lir::GenNegLong(RegLocation rl_dest, RegLocation rl_src) { 378 rl_src = LoadValueWide(rl_src, kCoreReg); 379 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); 380 /* 381 * [v1 v0] = -[a1 a0] 382 * negu v0,a0 383 * negu v1,a1 384 * sltu t1,r_zero 385 * subu v1,v1,t1 386 */ 387 388 OpRegReg(kOpNeg, rl_result.low_reg, rl_src.low_reg); 389 OpRegReg(kOpNeg, rl_result.high_reg, rl_src.high_reg); 390 int t_reg = AllocTemp(); 391 NewLIR3(kMipsSltu, t_reg, r_ZERO, rl_result.low_reg); 392 OpRegRegReg(kOpSub, rl_result.high_reg, rl_result.high_reg, t_reg); 393 FreeTemp(t_reg); 394 StoreValueWide(rl_dest, rl_result); 395} 396 397void MipsMir2Lir::GenAndLong(RegLocation rl_dest, RegLocation rl_src1, 398 RegLocation rl_src2) { 399 LOG(FATAL) << "Unexpected use of GenAndLong for Mips"; 400} 401 402void MipsMir2Lir::GenOrLong(RegLocation rl_dest, RegLocation rl_src1, 403 RegLocation rl_src2) { 404 LOG(FATAL) << "Unexpected use of GenOrLong for Mips"; 405} 406 407void MipsMir2Lir::GenXorLong(RegLocation rl_dest, RegLocation rl_src1, 408 RegLocation rl_src2) { 409 LOG(FATAL) << "Unexpected use of GenXorLong for Mips"; 410} 411 412/* 413 * Generate array load 414 */ 415void MipsMir2Lir::GenArrayGet(int opt_flags, OpSize size, RegLocation rl_array, 416 RegLocation rl_index, RegLocation rl_dest, int scale) { 417 RegisterClass reg_class = oat_reg_class_by_size(size); 418 int len_offset = mirror::Array::LengthOffset().Int32Value(); 419 int data_offset; 420 RegLocation rl_result; 421 rl_array = LoadValue(rl_array, kCoreReg); 422 rl_index = LoadValue(rl_index, kCoreReg); 423 424 if (size == kLong || size == kDouble) { 425 data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Int32Value(); 426 } else { 427 data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Int32Value(); 428 } 429 430 /* null object? */ 431 GenNullCheck(rl_array.s_reg_low, rl_array.low_reg, opt_flags); 432 433 int reg_ptr = AllocTemp(); 434 bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK)); 435 int reg_len = INVALID_REG; 436 if (needs_range_check) { 437 reg_len = AllocTemp(); 438 /* Get len */ 439 LoadWordDisp(rl_array.low_reg, len_offset, reg_len); 440 } 441 /* reg_ptr -> array data */ 442 OpRegRegImm(kOpAdd, reg_ptr, rl_array.low_reg, data_offset); 443 FreeTemp(rl_array.low_reg); 444 if ((size == kLong) || (size == kDouble)) { 445 if (scale) { 446 int r_new_index = AllocTemp(); 447 OpRegRegImm(kOpLsl, r_new_index, rl_index.low_reg, scale); 448 OpRegReg(kOpAdd, reg_ptr, r_new_index); 449 FreeTemp(r_new_index); 450 } else { 451 OpRegReg(kOpAdd, reg_ptr, rl_index.low_reg); 452 } 453 FreeTemp(rl_index.low_reg); 454 rl_result = EvalLoc(rl_dest, reg_class, true); 455 456 if (needs_range_check) { 457 // TODO: change kCondCS to a more meaningful name, is the sense of 458 // carry-set/clear flipped? 459 GenRegRegCheck(kCondCs, rl_index.low_reg, reg_len, kThrowArrayBounds); 460 FreeTemp(reg_len); 461 } 462 LoadBaseDispWide(reg_ptr, 0, rl_result.low_reg, rl_result.high_reg, INVALID_SREG); 463 464 FreeTemp(reg_ptr); 465 StoreValueWide(rl_dest, rl_result); 466 } else { 467 rl_result = EvalLoc(rl_dest, reg_class, true); 468 469 if (needs_range_check) { 470 // TODO: change kCondCS to a more meaningful name, is the sense of 471 // carry-set/clear flipped? 472 GenRegRegCheck(kCondCs, rl_index.low_reg, reg_len, kThrowArrayBounds); 473 FreeTemp(reg_len); 474 } 475 LoadBaseIndexed(reg_ptr, rl_index.low_reg, rl_result.low_reg, scale, size); 476 477 FreeTemp(reg_ptr); 478 StoreValue(rl_dest, rl_result); 479 } 480} 481 482/* 483 * Generate array store 484 * 485 */ 486void MipsMir2Lir::GenArrayPut(int opt_flags, OpSize size, RegLocation rl_array, 487 RegLocation rl_index, RegLocation rl_src, int scale) { 488 RegisterClass reg_class = oat_reg_class_by_size(size); 489 int len_offset = mirror::Array::LengthOffset().Int32Value(); 490 int data_offset; 491 492 if (size == kLong || size == kDouble) { 493 data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Int32Value(); 494 } else { 495 data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Int32Value(); 496 } 497 498 rl_array = LoadValue(rl_array, kCoreReg); 499 rl_index = LoadValue(rl_index, kCoreReg); 500 int reg_ptr = INVALID_REG; 501 if (IsTemp(rl_array.low_reg)) { 502 Clobber(rl_array.low_reg); 503 reg_ptr = rl_array.low_reg; 504 } else { 505 reg_ptr = AllocTemp(); 506 OpRegCopy(reg_ptr, rl_array.low_reg); 507 } 508 509 /* null object? */ 510 GenNullCheck(rl_array.s_reg_low, rl_array.low_reg, opt_flags); 511 512 bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK)); 513 int reg_len = INVALID_REG; 514 if (needs_range_check) { 515 reg_len = AllocTemp(); 516 // NOTE: max live temps(4) here. 517 /* Get len */ 518 LoadWordDisp(rl_array.low_reg, len_offset, reg_len); 519 } 520 /* reg_ptr -> array data */ 521 OpRegImm(kOpAdd, reg_ptr, data_offset); 522 /* at this point, reg_ptr points to array, 2 live temps */ 523 if ((size == kLong) || (size == kDouble)) { 524 // TUNING: specific wide routine that can handle fp regs 525 if (scale) { 526 int r_new_index = AllocTemp(); 527 OpRegRegImm(kOpLsl, r_new_index, rl_index.low_reg, scale); 528 OpRegReg(kOpAdd, reg_ptr, r_new_index); 529 FreeTemp(r_new_index); 530 } else { 531 OpRegReg(kOpAdd, reg_ptr, rl_index.low_reg); 532 } 533 rl_src = LoadValueWide(rl_src, reg_class); 534 535 if (needs_range_check) { 536 GenRegRegCheck(kCondCs, rl_index.low_reg, reg_len, kThrowArrayBounds); 537 FreeTemp(reg_len); 538 } 539 540 StoreBaseDispWide(reg_ptr, 0, rl_src.low_reg, rl_src.high_reg); 541 542 FreeTemp(reg_ptr); 543 } else { 544 rl_src = LoadValue(rl_src, reg_class); 545 if (needs_range_check) { 546 GenRegRegCheck(kCondCs, rl_index.low_reg, reg_len, kThrowArrayBounds); 547 FreeTemp(reg_len); 548 } 549 StoreBaseIndexed(reg_ptr, rl_index.low_reg, rl_src.low_reg, 550 scale, size); 551 } 552} 553 554/* 555 * Generate array store 556 * 557 */ 558void MipsMir2Lir::GenArrayObjPut(int opt_flags, RegLocation rl_array, 559 RegLocation rl_index, RegLocation rl_src, int scale) { 560 int len_offset = mirror::Array::LengthOffset().Int32Value(); 561 int data_offset = mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value(); 562 563 FlushAllRegs(); // Use explicit registers 564 LockCallTemps(); 565 566 int r_value = TargetReg(kArg0); // Register holding value 567 int r_array_class = TargetReg(kArg1); // Register holding array's Class 568 int r_array = TargetReg(kArg2); // Register holding array 569 int r_index = TargetReg(kArg3); // Register holding index into array 570 571 LoadValueDirectFixed(rl_array, r_array); // Grab array 572 LoadValueDirectFixed(rl_src, r_value); // Grab value 573 LoadValueDirectFixed(rl_index, r_index); // Grab index 574 575 GenNullCheck(rl_array.s_reg_low, r_array, opt_flags); // NPE? 576 577 // Store of null? 578 LIR* null_value_check = OpCmpImmBranch(kCondEq, r_value, 0, NULL); 579 580 // Get the array's class. 581 LoadWordDisp(r_array, mirror::Object::ClassOffset().Int32Value(), r_array_class); 582 CallRuntimeHelperRegReg(QUICK_ENTRYPOINT_OFFSET(pCanPutArrayElement), r_value, 583 r_array_class, true); 584 // Redo LoadValues in case they didn't survive the call. 585 LoadValueDirectFixed(rl_array, r_array); // Reload array 586 LoadValueDirectFixed(rl_index, r_index); // Reload index 587 LoadValueDirectFixed(rl_src, r_value); // Reload value 588 r_array_class = INVALID_REG; 589 590 // Branch here if value to be stored == null 591 LIR* target = NewLIR0(kPseudoTargetLabel); 592 null_value_check->target = target; 593 594 bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK)); 595 int reg_len = INVALID_REG; 596 if (needs_range_check) { 597 reg_len = TargetReg(kArg1); 598 LoadWordDisp(r_array, len_offset, reg_len); // Get len 599 } 600 /* r_ptr -> array data */ 601 int r_ptr = AllocTemp(); 602 OpRegRegImm(kOpAdd, r_ptr, r_array, data_offset); 603 if (needs_range_check) { 604 GenRegRegCheck(kCondCs, r_index, reg_len, kThrowArrayBounds); 605 } 606 StoreBaseIndexed(r_ptr, r_index, r_value, scale, kWord); 607 FreeTemp(r_ptr); 608 FreeTemp(r_index); 609 if (!mir_graph_->IsConstantNullRef(rl_src)) { 610 MarkGCCard(r_value, r_array); 611 } 612} 613 614void MipsMir2Lir::GenShiftImmOpLong(Instruction::Code opcode, RegLocation rl_dest, 615 RegLocation rl_src1, RegLocation rl_shift) { 616 // Default implementation is just to ignore the constant case. 617 GenShiftOpLong(opcode, rl_dest, rl_src1, rl_shift); 618} 619 620void MipsMir2Lir::GenArithImmOpLong(Instruction::Code opcode, 621 RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2) { 622 // Default - bail to non-const handler. 623 GenArithOpLong(opcode, rl_dest, rl_src1, rl_src2); 624} 625 626} // namespace art 627