int_mips.cc revision 091cc408e9dc87e60fb64c61e186bea568fc3d3a
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 RegStorage t0 = AllocTemp(); 48 RegStorage t1 = AllocTemp(); 49 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); 50 NewLIR3(kMipsSlt, t0.GetReg(), rl_src1.reg.GetHighReg(), rl_src2.reg.GetHighReg()); 51 NewLIR3(kMipsSlt, t1.GetReg(), rl_src2.reg.GetHighReg(), rl_src1.reg.GetHighReg()); 52 NewLIR3(kMipsSubu, rl_result.reg.GetReg(), t1.GetReg(), t0.GetReg()); 53 LIR* branch = OpCmpImmBranch(kCondNe, rl_result.reg, 0, NULL); 54 NewLIR3(kMipsSltu, t0.GetReg(), rl_src1.reg.GetLowReg(), rl_src2.reg.GetLowReg()); 55 NewLIR3(kMipsSltu, t1.GetReg(), rl_src2.reg.GetLowReg(), rl_src1.reg.GetLowReg()); 56 NewLIR3(kMipsSubu, rl_result.reg.GetReg(), t1.GetReg(), t0.GetReg()); 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, RegStorage src1, RegStorage src2, LIR* target) { 65 LIR* branch; 66 MipsOpCode slt_op; 67 MipsOpCode br_op; 68 bool cmp_zero = false; 69 bool swapped = false; 70 switch (cond) { 71 case kCondEq: 72 br_op = kMipsBeq; 73 cmp_zero = true; 74 break; 75 case kCondNe: 76 br_op = kMipsBne; 77 cmp_zero = true; 78 break; 79 case kCondUlt: 80 slt_op = kMipsSltu; 81 br_op = kMipsBnez; 82 break; 83 case kCondUge: 84 slt_op = kMipsSltu; 85 br_op = kMipsBeqz; 86 break; 87 case kCondGe: 88 slt_op = kMipsSlt; 89 br_op = kMipsBeqz; 90 break; 91 case kCondGt: 92 slt_op = kMipsSlt; 93 br_op = kMipsBnez; 94 swapped = true; 95 break; 96 case kCondLe: 97 slt_op = kMipsSlt; 98 br_op = kMipsBeqz; 99 swapped = true; 100 break; 101 case kCondLt: 102 slt_op = kMipsSlt; 103 br_op = kMipsBnez; 104 break; 105 case kCondHi: // Gtu 106 slt_op = kMipsSltu; 107 br_op = kMipsBnez; 108 swapped = true; 109 break; 110 default: 111 LOG(FATAL) << "No support for ConditionCode: " << cond; 112 return NULL; 113 } 114 if (cmp_zero) { 115 branch = NewLIR2(br_op, src1.GetReg(), src2.GetReg()); 116 } else { 117 RegStorage t_reg = AllocTemp(); 118 if (swapped) { 119 NewLIR3(slt_op, t_reg.GetReg(), src2.GetReg(), src1.GetReg()); 120 } else { 121 NewLIR3(slt_op, t_reg.GetReg(), src1.GetReg(), src2.GetReg()); 122 } 123 branch = NewLIR1(br_op, t_reg.GetReg()); 124 FreeTemp(t_reg); 125 } 126 branch->target = target; 127 return branch; 128} 129 130LIR* MipsMir2Lir::OpCmpImmBranch(ConditionCode cond, RegStorage reg, int check_value, LIR* target) { 131 LIR* branch; 132 if (check_value != 0) { 133 // TUNING: handle s16 & kCondLt/Mi case using slti 134 RegStorage t_reg = AllocTemp(); 135 LoadConstant(t_reg, check_value); 136 branch = OpCmpBranch(cond, reg, t_reg, target); 137 FreeTemp(t_reg); 138 return branch; 139 } 140 MipsOpCode opc; 141 switch (cond) { 142 case kCondEq: opc = kMipsBeqz; break; 143 case kCondGe: opc = kMipsBgez; break; 144 case kCondGt: opc = kMipsBgtz; break; 145 case kCondLe: opc = kMipsBlez; break; 146 // case KCondMi: 147 case kCondLt: opc = kMipsBltz; break; 148 case kCondNe: opc = kMipsBnez; break; 149 default: 150 // Tuning: use slti when applicable 151 RegStorage t_reg = AllocTemp(); 152 LoadConstant(t_reg, check_value); 153 branch = OpCmpBranch(cond, reg, t_reg, target); 154 FreeTemp(t_reg); 155 return branch; 156 } 157 branch = NewLIR1(opc, reg.GetReg()); 158 branch->target = target; 159 return branch; 160} 161 162LIR* MipsMir2Lir::OpRegCopyNoInsert(RegStorage r_dest, RegStorage r_src) { 163 // If src or dest is a pair, we'll be using low reg. 164 if (r_dest.IsPair()) { 165 r_dest = r_dest.GetLow(); 166 } 167 if (r_src.IsPair()) { 168 r_src = r_src.GetLow(); 169 } 170 if (r_dest.IsFloat() || r_src.IsFloat()) 171 return OpFpRegCopy(r_dest, r_src); 172 LIR* res = RawLIR(current_dalvik_offset_, kMipsMove, 173 r_dest.GetReg(), r_src.GetReg()); 174 if (!(cu_->disable_opt & (1 << kSafeOptimizations)) && r_dest == r_src) { 175 res->flags.is_nop = true; 176 } 177 return res; 178} 179 180void MipsMir2Lir::OpRegCopy(RegStorage r_dest, RegStorage r_src) { 181 if (r_dest != r_src) { 182 LIR *res = OpRegCopyNoInsert(r_dest, r_src); 183 AppendLIR(res); 184 } 185} 186 187void MipsMir2Lir::OpRegCopyWide(RegStorage r_dest, RegStorage r_src) { 188 if (r_dest != r_src) { 189 bool dest_fp = r_dest.IsFloat(); 190 bool src_fp = r_src.IsFloat(); 191 if (dest_fp) { 192 if (src_fp) { 193 OpRegCopy(r_dest, r_src); 194 } else { 195 /* note the operands are swapped for the mtc1 instr */ 196 NewLIR2(kMipsMtc1, r_src.GetLowReg(), r_dest.GetLowReg()); 197 NewLIR2(kMipsMtc1, r_src.GetHighReg(), r_dest.GetHighReg()); 198 } 199 } else { 200 if (src_fp) { 201 NewLIR2(kMipsMfc1, r_dest.GetLowReg(), r_src.GetLowReg()); 202 NewLIR2(kMipsMfc1, r_dest.GetHighReg(), r_src.GetHighReg()); 203 } else { 204 // Handle overlap 205 if (r_src.GetHighReg() == r_dest.GetLowReg()) { 206 OpRegCopy(r_dest.GetHigh(), r_src.GetHigh()); 207 OpRegCopy(r_dest.GetLow(), r_src.GetLow()); 208 } else { 209 OpRegCopy(r_dest.GetLow(), r_src.GetLow()); 210 OpRegCopy(r_dest.GetHigh(), r_src.GetHigh()); 211 } 212 } 213 } 214 } 215} 216 217void MipsMir2Lir::GenSelect(BasicBlock* bb, MIR* mir) { 218 UNIMPLEMENTED(FATAL) << "Need codegen for select"; 219} 220 221void MipsMir2Lir::GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir) { 222 UNIMPLEMENTED(FATAL) << "Need codegen for fused long cmp branch"; 223} 224 225RegLocation MipsMir2Lir::GenDivRem(RegLocation rl_dest, RegStorage reg1, RegStorage reg2, 226 bool is_div) { 227 NewLIR2(kMipsDiv, reg1.GetReg(), reg2.GetReg()); 228 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); 229 if (is_div) { 230 NewLIR1(kMipsMflo, rl_result.reg.GetReg()); 231 } else { 232 NewLIR1(kMipsMfhi, rl_result.reg.GetReg()); 233 } 234 return rl_result; 235} 236 237RegLocation MipsMir2Lir::GenDivRemLit(RegLocation rl_dest, RegStorage reg1, int lit, 238 bool is_div) { 239 RegStorage t_reg = AllocTemp(); 240 NewLIR3(kMipsAddiu, t_reg.GetReg(), rZERO, lit); 241 NewLIR2(kMipsDiv, reg1.GetReg(), t_reg.GetReg()); 242 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); 243 if (is_div) { 244 NewLIR1(kMipsMflo, rl_result.reg.GetReg()); 245 } else { 246 NewLIR1(kMipsMfhi, rl_result.reg.GetReg()); 247 } 248 FreeTemp(t_reg); 249 return rl_result; 250} 251 252RegLocation MipsMir2Lir::GenDivRem(RegLocation rl_dest, RegLocation rl_src1, 253 RegLocation rl_src2, bool is_div, bool check_zero) { 254 LOG(FATAL) << "Unexpected use of GenDivRem for Mips"; 255 return rl_dest; 256} 257 258RegLocation MipsMir2Lir::GenDivRemLit(RegLocation rl_dest, RegLocation rl_src1, int lit, bool is_div) { 259 LOG(FATAL) << "Unexpected use of GenDivRemLit for Mips"; 260 return rl_dest; 261} 262 263void MipsMir2Lir::OpLea(RegStorage r_base, RegStorage reg1, RegStorage reg2, int scale, 264 int offset) { 265 LOG(FATAL) << "Unexpected use of OpLea for Arm"; 266} 267 268void MipsMir2Lir::OpTlsCmp(ThreadOffset<4> offset, int val) { 269 LOG(FATAL) << "Unexpected use of OpTlsCmp for Arm"; 270} 271 272bool MipsMir2Lir::GenInlinedCas(CallInfo* info, bool is_long, bool is_object) { 273 DCHECK_NE(cu_->instruction_set, kThumb2); 274 return false; 275} 276 277bool MipsMir2Lir::GenInlinedSqrt(CallInfo* info) { 278 DCHECK_NE(cu_->instruction_set, kThumb2); 279 return false; 280} 281 282bool MipsMir2Lir::GenInlinedPeek(CallInfo* info, OpSize size) { 283 if (size != kSignedByte) { 284 // MIPS supports only aligned access. Defer unaligned access to JNI implementation. 285 return false; 286 } 287 RegLocation rl_src_address = info->args[0]; // long address 288 rl_src_address = NarrowRegLoc(rl_src_address); // ignore high half in info->args[1] 289 RegLocation rl_dest = InlineTarget(info); 290 RegLocation rl_address = LoadValue(rl_src_address, kCoreReg); 291 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); 292 DCHECK(size == kSignedByte); 293 LoadBaseDisp(rl_address.reg, 0, rl_result.reg, size, INVALID_SREG); 294 StoreValue(rl_dest, rl_result); 295 return true; 296} 297 298bool MipsMir2Lir::GenInlinedPoke(CallInfo* info, OpSize size) { 299 if (size != kSignedByte) { 300 // MIPS supports only aligned access. Defer unaligned access to JNI implementation. 301 return false; 302 } 303 RegLocation rl_src_address = info->args[0]; // long address 304 rl_src_address = NarrowRegLoc(rl_src_address); // ignore high half in info->args[1] 305 RegLocation rl_src_value = info->args[2]; // [size] value 306 RegLocation rl_address = LoadValue(rl_src_address, kCoreReg); 307 DCHECK(size == kSignedByte); 308 RegLocation rl_value = LoadValue(rl_src_value, kCoreReg); 309 StoreBaseDisp(rl_address.reg, 0, rl_value.reg, size); 310 return true; 311} 312 313LIR* MipsMir2Lir::OpPcRelLoad(RegStorage reg, LIR* target) { 314 LOG(FATAL) << "Unexpected use of OpPcRelLoad for Mips"; 315 return NULL; 316} 317 318LIR* MipsMir2Lir::OpVldm(RegStorage r_base, int count) { 319 LOG(FATAL) << "Unexpected use of OpVldm for Mips"; 320 return NULL; 321} 322 323LIR* MipsMir2Lir::OpVstm(RegStorage r_base, int count) { 324 LOG(FATAL) << "Unexpected use of OpVstm for Mips"; 325 return NULL; 326} 327 328void MipsMir2Lir::GenMultiplyByTwoBitMultiplier(RegLocation rl_src, 329 RegLocation rl_result, int lit, 330 int first_bit, int second_bit) { 331 RegStorage t_reg = AllocTemp(); 332 OpRegRegImm(kOpLsl, t_reg, rl_src.reg, second_bit - first_bit); 333 OpRegRegReg(kOpAdd, rl_result.reg, rl_src.reg, t_reg); 334 FreeTemp(t_reg); 335 if (first_bit != 0) { 336 OpRegRegImm(kOpLsl, rl_result.reg, rl_result.reg, first_bit); 337 } 338} 339 340void MipsMir2Lir::GenDivZeroCheckWide(RegStorage reg) { 341 DCHECK(reg.IsPair()); // TODO: support k64BitSolo. 342 RegStorage t_reg = AllocTemp(); 343 OpRegRegReg(kOpOr, t_reg, reg.GetLow(), reg.GetHigh()); 344 GenDivZeroCheck(t_reg); 345 FreeTemp(t_reg); 346} 347 348// Test suspend flag, return target of taken suspend branch 349LIR* MipsMir2Lir::OpTestSuspend(LIR* target) { 350 OpRegImm(kOpSub, rs_rMIPS_SUSPEND, 1); 351 return OpCmpImmBranch((target == NULL) ? kCondEq : kCondNe, rs_rMIPS_SUSPEND, 0, target); 352} 353 354// Decrement register and branch on condition 355LIR* MipsMir2Lir::OpDecAndBranch(ConditionCode c_code, RegStorage reg, LIR* target) { 356 OpRegImm(kOpSub, reg, 1); 357 return OpCmpImmBranch(c_code, reg, 0, target); 358} 359 360bool MipsMir2Lir::SmallLiteralDivRem(Instruction::Code dalvik_opcode, bool is_div, 361 RegLocation rl_src, RegLocation rl_dest, int lit) { 362 LOG(FATAL) << "Unexpected use of smallLiteralDive in Mips"; 363 return false; 364} 365 366bool MipsMir2Lir::EasyMultiply(RegLocation rl_src, RegLocation rl_dest, int lit) { 367 LOG(FATAL) << "Unexpected use of easyMultiply in Mips"; 368 return false; 369} 370 371LIR* MipsMir2Lir::OpIT(ConditionCode cond, const char* guide) { 372 LOG(FATAL) << "Unexpected use of OpIT in Mips"; 373 return NULL; 374} 375 376void MipsMir2Lir::OpEndIT(LIR* it) { 377 LOG(FATAL) << "Unexpected use of OpEndIT in Mips"; 378} 379 380 381void MipsMir2Lir::GenMulLong(Instruction::Code opcode, RegLocation rl_dest, 382 RegLocation rl_src1, RegLocation rl_src2) { 383 LOG(FATAL) << "Unexpected use of GenMulLong for Mips"; 384} 385 386void MipsMir2Lir::GenAddLong(Instruction::Code opcode, RegLocation rl_dest, 387 RegLocation rl_src1, RegLocation rl_src2) { 388 rl_src1 = LoadValueWide(rl_src1, kCoreReg); 389 rl_src2 = LoadValueWide(rl_src2, kCoreReg); 390 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); 391 /* 392 * [v1 v0] = [a1 a0] + [a3 a2]; 393 * addu v0,a2,a0 394 * addu t1,a3,a1 395 * sltu v1,v0,a2 396 * addu v1,v1,t1 397 */ 398 399 OpRegRegReg(kOpAdd, rl_result.reg.GetLow(), rl_src2.reg.GetLow(), rl_src1.reg.GetLow()); 400 RegStorage t_reg = AllocTemp(); 401 OpRegRegReg(kOpAdd, t_reg, rl_src2.reg.GetHigh(), rl_src1.reg.GetHigh()); 402 NewLIR3(kMipsSltu, rl_result.reg.GetHighReg(), rl_result.reg.GetLowReg(), rl_src2.reg.GetLowReg()); 403 OpRegRegReg(kOpAdd, rl_result.reg.GetHigh(), rl_result.reg.GetHigh(), t_reg); 404 FreeTemp(t_reg); 405 StoreValueWide(rl_dest, rl_result); 406} 407 408void MipsMir2Lir::GenSubLong(Instruction::Code opcode, RegLocation rl_dest, 409 RegLocation rl_src1, RegLocation rl_src2) { 410 rl_src1 = LoadValueWide(rl_src1, kCoreReg); 411 rl_src2 = LoadValueWide(rl_src2, kCoreReg); 412 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); 413 /* 414 * [v1 v0] = [a1 a0] - [a3 a2]; 415 * sltu t1,a0,a2 416 * subu v0,a0,a2 417 * subu v1,a1,a3 418 * subu v1,v1,t1 419 */ 420 421 RegStorage t_reg = AllocTemp(); 422 NewLIR3(kMipsSltu, t_reg.GetReg(), rl_src1.reg.GetLowReg(), rl_src2.reg.GetLowReg()); 423 OpRegRegReg(kOpSub, rl_result.reg.GetLow(), rl_src1.reg.GetLow(), rl_src2.reg.GetLow()); 424 OpRegRegReg(kOpSub, rl_result.reg.GetHigh(), rl_src1.reg.GetHigh(), rl_src2.reg.GetHigh()); 425 OpRegRegReg(kOpSub, rl_result.reg.GetHigh(), rl_result.reg.GetHigh(), t_reg); 426 FreeTemp(t_reg); 427 StoreValueWide(rl_dest, rl_result); 428} 429 430void MipsMir2Lir::GenNegLong(RegLocation rl_dest, RegLocation rl_src) { 431 rl_src = LoadValueWide(rl_src, kCoreReg); 432 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); 433 /* 434 * [v1 v0] = -[a1 a0] 435 * negu v0,a0 436 * negu v1,a1 437 * sltu t1,r_zero 438 * subu v1,v1,t1 439 */ 440 441 OpRegReg(kOpNeg, rl_result.reg.GetLow(), rl_src.reg.GetLow()); 442 OpRegReg(kOpNeg, rl_result.reg.GetHigh(), rl_src.reg.GetHigh()); 443 RegStorage t_reg = AllocTemp(); 444 NewLIR3(kMipsSltu, t_reg.GetReg(), rZERO, rl_result.reg.GetLowReg()); 445 OpRegRegReg(kOpSub, rl_result.reg.GetHigh(), rl_result.reg.GetHigh(), t_reg); 446 FreeTemp(t_reg); 447 StoreValueWide(rl_dest, rl_result); 448} 449 450void MipsMir2Lir::GenAndLong(Instruction::Code opcode, RegLocation rl_dest, 451 RegLocation rl_src1, 452 RegLocation rl_src2) { 453 LOG(FATAL) << "Unexpected use of GenAndLong for Mips"; 454} 455 456void MipsMir2Lir::GenOrLong(Instruction::Code opcode, RegLocation rl_dest, 457 RegLocation rl_src1, RegLocation rl_src2) { 458 LOG(FATAL) << "Unexpected use of GenOrLong for Mips"; 459} 460 461void MipsMir2Lir::GenXorLong(Instruction::Code opcode, RegLocation rl_dest, 462 RegLocation rl_src1, RegLocation rl_src2) { 463 LOG(FATAL) << "Unexpected use of GenXorLong for Mips"; 464} 465 466/* 467 * Generate array load 468 */ 469void MipsMir2Lir::GenArrayGet(int opt_flags, OpSize size, RegLocation rl_array, 470 RegLocation rl_index, RegLocation rl_dest, int scale) { 471 RegisterClass reg_class = RegClassBySize(size); 472 int len_offset = mirror::Array::LengthOffset().Int32Value(); 473 int data_offset; 474 RegLocation rl_result; 475 rl_array = LoadValue(rl_array, kCoreReg); 476 rl_index = LoadValue(rl_index, kCoreReg); 477 478 if (size == k64 || size == kDouble) { 479 data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Int32Value(); 480 } else { 481 data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Int32Value(); 482 } 483 484 /* null object? */ 485 GenNullCheck(rl_array.reg, opt_flags); 486 487 RegStorage reg_ptr = AllocTemp(); 488 bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK)); 489 RegStorage reg_len; 490 if (needs_range_check) { 491 reg_len = AllocTemp(); 492 /* Get len */ 493 Load32Disp(rl_array.reg, len_offset, reg_len); 494 } 495 /* reg_ptr -> array data */ 496 OpRegRegImm(kOpAdd, reg_ptr, rl_array.reg, data_offset); 497 FreeTemp(rl_array.reg); 498 if ((size == k64) || (size == kDouble)) { 499 if (scale) { 500 RegStorage r_new_index = AllocTemp(); 501 OpRegRegImm(kOpLsl, r_new_index, rl_index.reg, scale); 502 OpRegReg(kOpAdd, reg_ptr, r_new_index); 503 FreeTemp(r_new_index); 504 } else { 505 OpRegReg(kOpAdd, reg_ptr, rl_index.reg); 506 } 507 FreeTemp(rl_index.reg); 508 rl_result = EvalLoc(rl_dest, reg_class, true); 509 510 if (needs_range_check) { 511 GenArrayBoundsCheck(rl_index.reg, reg_len); 512 FreeTemp(reg_len); 513 } 514 LoadBaseDispWide(reg_ptr, 0, rl_result.reg, INVALID_SREG); 515 516 FreeTemp(reg_ptr); 517 StoreValueWide(rl_dest, rl_result); 518 } else { 519 rl_result = EvalLoc(rl_dest, reg_class, true); 520 521 if (needs_range_check) { 522 GenArrayBoundsCheck(rl_index.reg, reg_len); 523 FreeTemp(reg_len); 524 } 525 LoadBaseIndexed(reg_ptr, rl_index.reg, rl_result.reg, scale, size); 526 527 FreeTemp(reg_ptr); 528 StoreValue(rl_dest, rl_result); 529 } 530} 531 532/* 533 * Generate array store 534 * 535 */ 536void MipsMir2Lir::GenArrayPut(int opt_flags, OpSize size, RegLocation rl_array, 537 RegLocation rl_index, RegLocation rl_src, int scale, bool card_mark) { 538 RegisterClass reg_class = RegClassBySize(size); 539 int len_offset = mirror::Array::LengthOffset().Int32Value(); 540 int data_offset; 541 542 if (size == k64 || size == kDouble) { 543 data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Int32Value(); 544 } else { 545 data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Int32Value(); 546 } 547 548 rl_array = LoadValue(rl_array, kCoreReg); 549 rl_index = LoadValue(rl_index, kCoreReg); 550 RegStorage reg_ptr; 551 bool allocated_reg_ptr_temp = false; 552 if (IsTemp(rl_array.reg) && !card_mark) { 553 Clobber(rl_array.reg); 554 reg_ptr = rl_array.reg; 555 } else { 556 reg_ptr = AllocTemp(); 557 OpRegCopy(reg_ptr, rl_array.reg); 558 allocated_reg_ptr_temp = true; 559 } 560 561 /* null object? */ 562 GenNullCheck(rl_array.reg, opt_flags); 563 564 bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK)); 565 RegStorage reg_len; 566 if (needs_range_check) { 567 reg_len = AllocTemp(); 568 // NOTE: max live temps(4) here. 569 /* Get len */ 570 Load32Disp(rl_array.reg, len_offset, reg_len); 571 } 572 /* reg_ptr -> array data */ 573 OpRegImm(kOpAdd, reg_ptr, data_offset); 574 /* at this point, reg_ptr points to array, 2 live temps */ 575 if ((size == k64) || (size == kDouble)) { 576 // TUNING: specific wide routine that can handle fp regs 577 if (scale) { 578 RegStorage r_new_index = AllocTemp(); 579 OpRegRegImm(kOpLsl, r_new_index, rl_index.reg, scale); 580 OpRegReg(kOpAdd, reg_ptr, r_new_index); 581 FreeTemp(r_new_index); 582 } else { 583 OpRegReg(kOpAdd, reg_ptr, rl_index.reg); 584 } 585 rl_src = LoadValueWide(rl_src, reg_class); 586 587 if (needs_range_check) { 588 GenArrayBoundsCheck(rl_index.reg, reg_len); 589 FreeTemp(reg_len); 590 } 591 592 StoreBaseDispWide(reg_ptr, 0, rl_src.reg); 593 } else { 594 rl_src = LoadValue(rl_src, reg_class); 595 if (needs_range_check) { 596 GenArrayBoundsCheck(rl_index.reg, reg_len); 597 FreeTemp(reg_len); 598 } 599 StoreBaseIndexed(reg_ptr, rl_index.reg, rl_src.reg, scale, size); 600 } 601 if (allocated_reg_ptr_temp) { 602 FreeTemp(reg_ptr); 603 } 604 if (card_mark) { 605 MarkGCCard(rl_src.reg, rl_array.reg); 606 } 607} 608 609void MipsMir2Lir::GenShiftImmOpLong(Instruction::Code opcode, RegLocation rl_dest, 610 RegLocation rl_src1, RegLocation rl_shift) { 611 // Default implementation is just to ignore the constant case. 612 GenShiftOpLong(opcode, rl_dest, rl_src1, rl_shift); 613} 614 615void MipsMir2Lir::GenArithImmOpLong(Instruction::Code opcode, 616 RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2) { 617 // Default - bail to non-const handler. 618 GenArithOpLong(opcode, rl_dest, rl_src1, rl_src2); 619} 620 621} // namespace art 622