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