int_mips.cc revision 4289456fa265b833434c2a8eee9e7a16da31c524
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().GetReg(); 48 int t1 = AllocTemp().GetReg(); 49 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); 50 NewLIR3(kMipsSlt, t0, rl_src1.reg.GetHighReg(), rl_src2.reg.GetHighReg()); 51 NewLIR3(kMipsSlt, t1, rl_src2.reg.GetHighReg(), rl_src1.reg.GetHighReg()); 52 NewLIR3(kMipsSubu, rl_result.reg.GetReg(), t1, t0); 53 LIR* branch = OpCmpImmBranch(kCondNe, rl_result.reg, 0, NULL); 54 NewLIR3(kMipsSltu, t0, rl_src1.reg.GetLowReg(), rl_src2.reg.GetLowReg()); 55 NewLIR3(kMipsSltu, t1, rl_src2.reg.GetLowReg(), rl_src1.reg.GetLowReg()); 56 NewLIR3(kMipsSubu, rl_result.reg.GetReg(), 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, 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 int t_reg = AllocTemp().GetReg(); 118 if (swapped) { 119 NewLIR3(slt_op, t_reg, src2.GetReg(), src1.GetReg()); 120 } else { 121 NewLIR3(slt_op, t_reg, src1.GetReg(), src2.GetReg()); 122 } 123 branch = NewLIR1(br_op, t_reg); 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 (MIPS_FPREG(r_dest.GetReg()) || MIPS_FPREG(r_src.GetReg())) 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 180LIR* MipsMir2Lir::OpRegCopy(RegStorage r_dest, RegStorage r_src) { 181 LIR *res = OpRegCopyNoInsert(r_dest, r_src); 182 AppendLIR(res); 183 return res; 184} 185 186void MipsMir2Lir::OpRegCopyWide(RegStorage r_dest, RegStorage r_src) { 187 bool dest_fp = MIPS_FPREG(r_dest.GetLowReg()); 188 bool src_fp = MIPS_FPREG(r_src.GetLowReg()); 189 if (dest_fp) { 190 if (src_fp) { 191 // FIXME: handle this here - reserve OpRegCopy for 32-bit copies. 192 OpRegCopy(RegStorage::Solo64(S2d(r_dest.GetLowReg(), r_dest.GetHighReg())), 193 RegStorage::Solo64(S2d(r_src.GetLowReg(), r_src.GetHighReg()))); 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 216void MipsMir2Lir::GenSelect(BasicBlock* bb, MIR* mir) { 217 UNIMPLEMENTED(FATAL) << "Need codegen for select"; 218} 219 220void MipsMir2Lir::GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir) { 221 UNIMPLEMENTED(FATAL) << "Need codegen for fused long cmp branch"; 222} 223 224LIR* MipsMir2Lir::GenRegMemCheck(ConditionCode c_code, RegStorage reg1, RegStorage base, 225 int offset, ThrowKind kind) { 226 LOG(FATAL) << "Unexpected use of GenRegMemCheck for Arm"; 227 return NULL; 228} 229 230RegLocation MipsMir2Lir::GenDivRem(RegLocation rl_dest, RegStorage reg1, RegStorage reg2, 231 bool is_div) { 232 NewLIR2(kMipsDiv, reg1.GetReg(), reg2.GetReg()); 233 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); 234 if (is_div) { 235 NewLIR1(kMipsMflo, rl_result.reg.GetReg()); 236 } else { 237 NewLIR1(kMipsMfhi, rl_result.reg.GetReg()); 238 } 239 return rl_result; 240} 241 242RegLocation MipsMir2Lir::GenDivRemLit(RegLocation rl_dest, RegStorage reg1, int lit, 243 bool is_div) { 244 int t_reg = AllocTemp().GetReg(); 245 NewLIR3(kMipsAddiu, t_reg, rZERO, lit); 246 NewLIR2(kMipsDiv, reg1.GetReg(), t_reg); 247 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); 248 if (is_div) { 249 NewLIR1(kMipsMflo, rl_result.reg.GetReg()); 250 } else { 251 NewLIR1(kMipsMfhi, rl_result.reg.GetReg()); 252 } 253 FreeTemp(t_reg); 254 return rl_result; 255} 256 257RegLocation MipsMir2Lir::GenDivRem(RegLocation rl_dest, RegLocation rl_src1, 258 RegLocation rl_src2, bool is_div, bool check_zero) { 259 LOG(FATAL) << "Unexpected use of GenDivRem for Mips"; 260 return rl_dest; 261} 262 263RegLocation MipsMir2Lir::GenDivRemLit(RegLocation rl_dest, RegLocation rl_src1, int lit, bool is_div) { 264 LOG(FATAL) << "Unexpected use of GenDivRemLit for Mips"; 265 return rl_dest; 266} 267 268void MipsMir2Lir::OpLea(RegStorage r_base, RegStorage reg1, RegStorage reg2, int scale, 269 int offset) { 270 LOG(FATAL) << "Unexpected use of OpLea for Arm"; 271} 272 273void MipsMir2Lir::OpTlsCmp(ThreadOffset<4> offset, int val) { 274 LOG(FATAL) << "Unexpected use of OpTlsCmp for Arm"; 275} 276 277bool MipsMir2Lir::GenInlinedCas(CallInfo* info, bool is_long, bool is_object) { 278 DCHECK_NE(cu_->instruction_set, kThumb2); 279 return false; 280} 281 282bool MipsMir2Lir::GenInlinedSqrt(CallInfo* info) { 283 DCHECK_NE(cu_->instruction_set, kThumb2); 284 return false; 285} 286 287bool MipsMir2Lir::GenInlinedPeek(CallInfo* info, OpSize size) { 288 if (size != kSignedByte) { 289 // MIPS supports only aligned access. Defer unaligned access to JNI implementation. 290 return false; 291 } 292 RegLocation rl_src_address = info->args[0]; // long address 293 rl_src_address = NarrowRegLoc(rl_src_address); // ignore high half in info->args[1] 294 RegLocation rl_dest = InlineTarget(info); 295 RegLocation rl_address = LoadValue(rl_src_address, kCoreReg); 296 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); 297 DCHECK(size == kSignedByte); 298 LoadBaseDisp(rl_address.reg, 0, rl_result.reg, size, INVALID_SREG); 299 StoreValue(rl_dest, rl_result); 300 return true; 301} 302 303bool MipsMir2Lir::GenInlinedPoke(CallInfo* info, OpSize size) { 304 if (size != kSignedByte) { 305 // MIPS supports only aligned access. Defer unaligned access to JNI implementation. 306 return false; 307 } 308 RegLocation rl_src_address = info->args[0]; // long address 309 rl_src_address = NarrowRegLoc(rl_src_address); // ignore high half in info->args[1] 310 RegLocation rl_src_value = info->args[2]; // [size] value 311 RegLocation rl_address = LoadValue(rl_src_address, kCoreReg); 312 DCHECK(size == kSignedByte); 313 RegLocation rl_value = LoadValue(rl_src_value, kCoreReg); 314 StoreBaseDisp(rl_address.reg, 0, rl_value.reg, size); 315 return true; 316} 317 318LIR* MipsMir2Lir::OpPcRelLoad(RegStorage reg, LIR* target) { 319 LOG(FATAL) << "Unexpected use of OpPcRelLoad for Mips"; 320 return NULL; 321} 322 323LIR* MipsMir2Lir::OpVldm(RegStorage r_base, int count) { 324 LOG(FATAL) << "Unexpected use of OpVldm for Mips"; 325 return NULL; 326} 327 328LIR* MipsMir2Lir::OpVstm(RegStorage r_base, int count) { 329 LOG(FATAL) << "Unexpected use of OpVstm for Mips"; 330 return NULL; 331} 332 333void MipsMir2Lir::GenMultiplyByTwoBitMultiplier(RegLocation rl_src, 334 RegLocation rl_result, int lit, 335 int first_bit, int second_bit) { 336 RegStorage t_reg = AllocTemp(); 337 OpRegRegImm(kOpLsl, t_reg, rl_src.reg, second_bit - first_bit); 338 OpRegRegReg(kOpAdd, rl_result.reg, rl_src.reg, t_reg); 339 FreeTemp(t_reg); 340 if (first_bit != 0) { 341 OpRegRegImm(kOpLsl, rl_result.reg, rl_result.reg, first_bit); 342 } 343} 344 345void MipsMir2Lir::GenDivZeroCheck(RegStorage reg) { 346 DCHECK(reg.IsPair()); // TODO: support k64BitSolo. 347 RegStorage t_reg = AllocTemp(); 348 OpRegRegReg(kOpOr, t_reg, reg.GetLow(), reg.GetHigh()); 349 AddDivZeroSlowPath(kCondEq, t_reg, 0); 350 FreeTemp(t_reg); 351} 352 353// Test suspend flag, return target of taken suspend branch 354LIR* MipsMir2Lir::OpTestSuspend(LIR* target) { 355 OpRegImm(kOpSub, rs_rMIPS_SUSPEND, 1); 356 return OpCmpImmBranch((target == NULL) ? kCondEq : kCondNe, rs_rMIPS_SUSPEND, 0, target); 357} 358 359// Decrement register and branch on condition 360LIR* MipsMir2Lir::OpDecAndBranch(ConditionCode c_code, RegStorage reg, LIR* target) { 361 OpRegImm(kOpSub, reg, 1); 362 return OpCmpImmBranch(c_code, reg, 0, target); 363} 364 365bool MipsMir2Lir::SmallLiteralDivRem(Instruction::Code dalvik_opcode, bool is_div, 366 RegLocation rl_src, RegLocation rl_dest, int lit) { 367 LOG(FATAL) << "Unexpected use of smallLiteralDive in Mips"; 368 return false; 369} 370 371bool MipsMir2Lir::EasyMultiply(RegLocation rl_src, RegLocation rl_dest, int lit) { 372 LOG(FATAL) << "Unexpected use of easyMultiply in Mips"; 373 return false; 374} 375 376LIR* MipsMir2Lir::OpIT(ConditionCode cond, const char* guide) { 377 LOG(FATAL) << "Unexpected use of OpIT in Mips"; 378 return NULL; 379} 380 381void MipsMir2Lir::OpEndIT(LIR* it) { 382 LOG(FATAL) << "Unexpected use of OpEndIT in Mips"; 383} 384 385 386void MipsMir2Lir::GenMulLong(Instruction::Code opcode, RegLocation rl_dest, 387 RegLocation rl_src1, RegLocation rl_src2) { 388 LOG(FATAL) << "Unexpected use of GenMulLong for Mips"; 389} 390 391void MipsMir2Lir::GenAddLong(Instruction::Code opcode, RegLocation rl_dest, 392 RegLocation rl_src1, RegLocation rl_src2) { 393 rl_src1 = LoadValueWide(rl_src1, kCoreReg); 394 rl_src2 = LoadValueWide(rl_src2, kCoreReg); 395 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); 396 /* 397 * [v1 v0] = [a1 a0] + [a3 a2]; 398 * addu v0,a2,a0 399 * addu t1,a3,a1 400 * sltu v1,v0,a2 401 * addu v1,v1,t1 402 */ 403 404 OpRegRegReg(kOpAdd, rl_result.reg.GetLow(), rl_src2.reg.GetLow(), rl_src1.reg.GetLow()); 405 RegStorage t_reg = AllocTemp(); 406 OpRegRegReg(kOpAdd, t_reg, rl_src2.reg.GetHigh(), rl_src1.reg.GetHigh()); 407 NewLIR3(kMipsSltu, rl_result.reg.GetHighReg(), rl_result.reg.GetLowReg(), rl_src2.reg.GetLowReg()); 408 OpRegRegReg(kOpAdd, rl_result.reg.GetHigh(), rl_result.reg.GetHigh(), t_reg); 409 FreeTemp(t_reg); 410 StoreValueWide(rl_dest, rl_result); 411} 412 413void MipsMir2Lir::GenSubLong(Instruction::Code opcode, RegLocation rl_dest, 414 RegLocation rl_src1, RegLocation rl_src2) { 415 rl_src1 = LoadValueWide(rl_src1, kCoreReg); 416 rl_src2 = LoadValueWide(rl_src2, kCoreReg); 417 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); 418 /* 419 * [v1 v0] = [a1 a0] - [a3 a2]; 420 * sltu t1,a0,a2 421 * subu v0,a0,a2 422 * subu v1,a1,a3 423 * subu v1,v1,t1 424 */ 425 426 RegStorage t_reg = AllocTemp(); 427 NewLIR3(kMipsSltu, t_reg.GetReg(), rl_src1.reg.GetLowReg(), rl_src2.reg.GetLowReg()); 428 OpRegRegReg(kOpSub, rl_result.reg.GetLow(), rl_src1.reg.GetLow(), rl_src2.reg.GetLow()); 429 OpRegRegReg(kOpSub, rl_result.reg.GetHigh(), rl_src1.reg.GetHigh(), rl_src2.reg.GetHigh()); 430 OpRegRegReg(kOpSub, rl_result.reg.GetHigh(), rl_result.reg.GetHigh(), t_reg); 431 FreeTemp(t_reg); 432 StoreValueWide(rl_dest, rl_result); 433} 434 435void MipsMir2Lir::GenNegLong(RegLocation rl_dest, RegLocation rl_src) { 436 rl_src = LoadValueWide(rl_src, kCoreReg); 437 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); 438 /* 439 * [v1 v0] = -[a1 a0] 440 * negu v0,a0 441 * negu v1,a1 442 * sltu t1,r_zero 443 * subu v1,v1,t1 444 */ 445 446 OpRegReg(kOpNeg, rl_result.reg.GetLow(), rl_src.reg.GetLow()); 447 OpRegReg(kOpNeg, rl_result.reg.GetHigh(), rl_src.reg.GetHigh()); 448 RegStorage t_reg = AllocTemp(); 449 NewLIR3(kMipsSltu, t_reg.GetReg(), rZERO, rl_result.reg.GetLowReg()); 450 OpRegRegReg(kOpSub, rl_result.reg.GetHigh(), rl_result.reg.GetHigh(), t_reg); 451 FreeTemp(t_reg); 452 StoreValueWide(rl_dest, rl_result); 453} 454 455void MipsMir2Lir::GenAndLong(Instruction::Code opcode, RegLocation rl_dest, 456 RegLocation rl_src1, 457 RegLocation rl_src2) { 458 LOG(FATAL) << "Unexpected use of GenAndLong for Mips"; 459} 460 461void MipsMir2Lir::GenOrLong(Instruction::Code opcode, RegLocation rl_dest, 462 RegLocation rl_src1, RegLocation rl_src2) { 463 LOG(FATAL) << "Unexpected use of GenOrLong for Mips"; 464} 465 466void MipsMir2Lir::GenXorLong(Instruction::Code opcode, RegLocation rl_dest, 467 RegLocation rl_src1, RegLocation rl_src2) { 468 LOG(FATAL) << "Unexpected use of GenXorLong for Mips"; 469} 470 471/* 472 * Generate array load 473 */ 474void MipsMir2Lir::GenArrayGet(int opt_flags, OpSize size, RegLocation rl_array, 475 RegLocation rl_index, RegLocation rl_dest, int scale) { 476 RegisterClass reg_class = oat_reg_class_by_size(size); 477 int len_offset = mirror::Array::LengthOffset().Int32Value(); 478 int data_offset; 479 RegLocation rl_result; 480 rl_array = LoadValue(rl_array, kCoreReg); 481 rl_index = LoadValue(rl_index, kCoreReg); 482 483 if (size == kLong || size == kDouble) { 484 data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Int32Value(); 485 } else { 486 data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Int32Value(); 487 } 488 489 /* null object? */ 490 GenNullCheck(rl_array.reg, opt_flags); 491 492 RegStorage reg_ptr = AllocTemp(); 493 bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK)); 494 RegStorage reg_len; 495 if (needs_range_check) { 496 reg_len = AllocTemp(); 497 /* Get len */ 498 LoadWordDisp(rl_array.reg, len_offset, reg_len); 499 } 500 /* reg_ptr -> array data */ 501 OpRegRegImm(kOpAdd, reg_ptr, rl_array.reg, data_offset); 502 FreeTemp(rl_array.reg.GetReg()); 503 if ((size == kLong) || (size == kDouble)) { 504 if (scale) { 505 RegStorage r_new_index = AllocTemp(); 506 OpRegRegImm(kOpLsl, r_new_index, rl_index.reg, scale); 507 OpRegReg(kOpAdd, reg_ptr, r_new_index); 508 FreeTemp(r_new_index); 509 } else { 510 OpRegReg(kOpAdd, reg_ptr, rl_index.reg); 511 } 512 FreeTemp(rl_index.reg); 513 rl_result = EvalLoc(rl_dest, reg_class, true); 514 515 if (needs_range_check) { 516 GenRegRegCheck(kCondUge, rl_index.reg, reg_len, kThrowArrayBounds); 517 FreeTemp(reg_len); 518 } 519 LoadBaseDispWide(reg_ptr, 0, rl_result.reg, INVALID_SREG); 520 521 FreeTemp(reg_ptr); 522 StoreValueWide(rl_dest, rl_result); 523 } else { 524 rl_result = EvalLoc(rl_dest, reg_class, true); 525 526 if (needs_range_check) { 527 GenRegRegCheck(kCondUge, rl_index.reg, reg_len, kThrowArrayBounds); 528 FreeTemp(reg_len); 529 } 530 LoadBaseIndexed(reg_ptr, rl_index.reg, rl_result.reg, scale, size); 531 532 FreeTemp(reg_ptr); 533 StoreValue(rl_dest, rl_result); 534 } 535} 536 537/* 538 * Generate array store 539 * 540 */ 541void MipsMir2Lir::GenArrayPut(int opt_flags, OpSize size, RegLocation rl_array, 542 RegLocation rl_index, RegLocation rl_src, int scale, bool card_mark) { 543 RegisterClass reg_class = oat_reg_class_by_size(size); 544 int len_offset = mirror::Array::LengthOffset().Int32Value(); 545 int data_offset; 546 547 if (size == kLong || size == kDouble) { 548 data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Int32Value(); 549 } else { 550 data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Int32Value(); 551 } 552 553 rl_array = LoadValue(rl_array, kCoreReg); 554 rl_index = LoadValue(rl_index, kCoreReg); 555 RegStorage reg_ptr; 556 bool allocated_reg_ptr_temp = false; 557 if (IsTemp(rl_array.reg.GetReg()) && !card_mark) { 558 Clobber(rl_array.reg.GetReg()); 559 reg_ptr = rl_array.reg; 560 } else { 561 reg_ptr = AllocTemp(); 562 OpRegCopy(reg_ptr, rl_array.reg); 563 allocated_reg_ptr_temp = true; 564 } 565 566 /* null object? */ 567 GenNullCheck(rl_array.reg, opt_flags); 568 569 bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK)); 570 RegStorage reg_len; 571 if (needs_range_check) { 572 reg_len = AllocTemp(); 573 // NOTE: max live temps(4) here. 574 /* Get len */ 575 LoadWordDisp(rl_array.reg, len_offset, reg_len); 576 } 577 /* reg_ptr -> array data */ 578 OpRegImm(kOpAdd, reg_ptr, data_offset); 579 /* at this point, reg_ptr points to array, 2 live temps */ 580 if ((size == kLong) || (size == kDouble)) { 581 // TUNING: specific wide routine that can handle fp regs 582 if (scale) { 583 RegStorage r_new_index = AllocTemp(); 584 OpRegRegImm(kOpLsl, r_new_index, rl_index.reg, scale); 585 OpRegReg(kOpAdd, reg_ptr, r_new_index); 586 FreeTemp(r_new_index); 587 } else { 588 OpRegReg(kOpAdd, reg_ptr, rl_index.reg); 589 } 590 rl_src = LoadValueWide(rl_src, reg_class); 591 592 if (needs_range_check) { 593 GenRegRegCheck(kCondUge, rl_index.reg, reg_len, kThrowArrayBounds); 594 FreeTemp(reg_len); 595 } 596 597 StoreBaseDispWide(reg_ptr, 0, rl_src.reg); 598 } else { 599 rl_src = LoadValue(rl_src, reg_class); 600 if (needs_range_check) { 601 GenRegRegCheck(kCondUge, rl_index.reg, reg_len, kThrowArrayBounds); 602 FreeTemp(reg_len); 603 } 604 StoreBaseIndexed(reg_ptr, rl_index.reg, rl_src.reg, scale, size); 605 } 606 if (allocated_reg_ptr_temp) { 607 FreeTemp(reg_ptr); 608 } 609 if (card_mark) { 610 MarkGCCard(rl_src.reg, rl_array.reg); 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