int_mips.cc revision bebee4fd10e5db6cb07f59bc0f73297c900ea5f0
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::GenSelectConst32(RegStorage left_op, RegStorage right_op, ConditionCode code, 219 int32_t true_val, int32_t false_val, RegStorage rs_dest, 220 int dest_reg_class) { 221 // Implement as a branch-over. 222 // TODO: Conditional move? 223 LoadConstant(rs_dest, false_val); // Favors false. 224 LIR* ne_branchover = OpCmpBranch(code, left_op, right_op, NULL); 225 LoadConstant(rs_dest, true_val); 226 LIR* target_label = NewLIR0(kPseudoTargetLabel); 227 ne_branchover->target = target_label; 228} 229 230void MipsMir2Lir::GenSelect(BasicBlock* bb, MIR* mir) { 231 UNIMPLEMENTED(FATAL) << "Need codegen for select"; 232} 233 234void MipsMir2Lir::GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir) { 235 UNIMPLEMENTED(FATAL) << "Need codegen for fused long cmp branch"; 236} 237 238RegLocation MipsMir2Lir::GenDivRem(RegLocation rl_dest, RegStorage reg1, RegStorage reg2, 239 bool is_div) { 240 NewLIR2(kMipsDiv, reg1.GetReg(), reg2.GetReg()); 241 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); 242 if (is_div) { 243 NewLIR1(kMipsMflo, rl_result.reg.GetReg()); 244 } else { 245 NewLIR1(kMipsMfhi, rl_result.reg.GetReg()); 246 } 247 return rl_result; 248} 249 250RegLocation MipsMir2Lir::GenDivRemLit(RegLocation rl_dest, RegStorage reg1, int lit, 251 bool is_div) { 252 RegStorage t_reg = AllocTemp(); 253 NewLIR3(kMipsAddiu, t_reg.GetReg(), rZERO, lit); 254 NewLIR2(kMipsDiv, reg1.GetReg(), t_reg.GetReg()); 255 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); 256 if (is_div) { 257 NewLIR1(kMipsMflo, rl_result.reg.GetReg()); 258 } else { 259 NewLIR1(kMipsMfhi, rl_result.reg.GetReg()); 260 } 261 FreeTemp(t_reg); 262 return rl_result; 263} 264 265RegLocation MipsMir2Lir::GenDivRem(RegLocation rl_dest, RegLocation rl_src1, 266 RegLocation rl_src2, bool is_div, bool check_zero) { 267 LOG(FATAL) << "Unexpected use of GenDivRem for Mips"; 268 return rl_dest; 269} 270 271RegLocation MipsMir2Lir::GenDivRemLit(RegLocation rl_dest, RegLocation rl_src1, int lit, bool is_div) { 272 LOG(FATAL) << "Unexpected use of GenDivRemLit for Mips"; 273 return rl_dest; 274} 275 276void MipsMir2Lir::OpLea(RegStorage r_base, RegStorage reg1, RegStorage reg2, int scale, 277 int offset) { 278 LOG(FATAL) << "Unexpected use of OpLea for Arm"; 279} 280 281void MipsMir2Lir::OpTlsCmp(ThreadOffset<4> offset, int val) { 282 LOG(FATAL) << "Unexpected use of OpTlsCmp for Arm"; 283} 284 285void MipsMir2Lir::OpTlsCmp(ThreadOffset<8> offset, int val) { 286 UNIMPLEMENTED(FATAL) << "Should not be called."; 287} 288 289bool MipsMir2Lir::GenInlinedCas(CallInfo* info, bool is_long, bool is_object) { 290 DCHECK_NE(cu_->instruction_set, kThumb2); 291 return false; 292} 293 294bool MipsMir2Lir::GenInlinedAbsFloat(CallInfo* info) { 295 // TODO - add Mips implementation 296 return false; 297} 298 299bool MipsMir2Lir::GenInlinedAbsDouble(CallInfo* info) { 300 // TODO - add Mips implementation 301 return false; 302} 303 304bool MipsMir2Lir::GenInlinedSqrt(CallInfo* info) { 305 DCHECK_NE(cu_->instruction_set, kThumb2); 306 return false; 307} 308 309bool MipsMir2Lir::GenInlinedPeek(CallInfo* info, OpSize size) { 310 if (size != kSignedByte) { 311 // MIPS supports only aligned access. Defer unaligned access to JNI implementation. 312 return false; 313 } 314 RegLocation rl_src_address = info->args[0]; // long address 315 rl_src_address = NarrowRegLoc(rl_src_address); // ignore high half in info->args[1] 316 RegLocation rl_dest = InlineTarget(info); 317 RegLocation rl_address = LoadValue(rl_src_address, kCoreReg); 318 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); 319 DCHECK(size == kSignedByte); 320 LoadBaseDisp(rl_address.reg, 0, rl_result.reg, size, kNotVolatile); 321 StoreValue(rl_dest, rl_result); 322 return true; 323} 324 325bool MipsMir2Lir::GenInlinedPoke(CallInfo* info, OpSize size) { 326 if (size != kSignedByte) { 327 // MIPS supports only aligned access. Defer unaligned access to JNI implementation. 328 return false; 329 } 330 RegLocation rl_src_address = info->args[0]; // long address 331 rl_src_address = NarrowRegLoc(rl_src_address); // ignore high half in info->args[1] 332 RegLocation rl_src_value = info->args[2]; // [size] value 333 RegLocation rl_address = LoadValue(rl_src_address, kCoreReg); 334 DCHECK(size == kSignedByte); 335 RegLocation rl_value = LoadValue(rl_src_value, kCoreReg); 336 StoreBaseDisp(rl_address.reg, 0, rl_value.reg, size, kNotVolatile); 337 return true; 338} 339 340LIR* MipsMir2Lir::OpPcRelLoad(RegStorage reg, LIR* target) { 341 LOG(FATAL) << "Unexpected use of OpPcRelLoad for Mips"; 342 return NULL; 343} 344 345LIR* MipsMir2Lir::OpVldm(RegStorage r_base, int count) { 346 LOG(FATAL) << "Unexpected use of OpVldm for Mips"; 347 return NULL; 348} 349 350LIR* MipsMir2Lir::OpVstm(RegStorage r_base, int count) { 351 LOG(FATAL) << "Unexpected use of OpVstm for Mips"; 352 return NULL; 353} 354 355void MipsMir2Lir::GenMultiplyByTwoBitMultiplier(RegLocation rl_src, 356 RegLocation rl_result, int lit, 357 int first_bit, int second_bit) { 358 RegStorage t_reg = AllocTemp(); 359 OpRegRegImm(kOpLsl, t_reg, rl_src.reg, second_bit - first_bit); 360 OpRegRegReg(kOpAdd, rl_result.reg, rl_src.reg, t_reg); 361 FreeTemp(t_reg); 362 if (first_bit != 0) { 363 OpRegRegImm(kOpLsl, rl_result.reg, rl_result.reg, first_bit); 364 } 365} 366 367void MipsMir2Lir::GenDivZeroCheckWide(RegStorage reg) { 368 DCHECK(reg.IsPair()); // TODO: support k64BitSolo. 369 RegStorage t_reg = AllocTemp(); 370 OpRegRegReg(kOpOr, t_reg, reg.GetLow(), reg.GetHigh()); 371 GenDivZeroCheck(t_reg); 372 FreeTemp(t_reg); 373} 374 375// Test suspend flag, return target of taken suspend branch 376LIR* MipsMir2Lir::OpTestSuspend(LIR* target) { 377 OpRegImm(kOpSub, rs_rMIPS_SUSPEND, 1); 378 return OpCmpImmBranch((target == NULL) ? kCondEq : kCondNe, rs_rMIPS_SUSPEND, 0, target); 379} 380 381// Decrement register and branch on condition 382LIR* MipsMir2Lir::OpDecAndBranch(ConditionCode c_code, RegStorage reg, LIR* target) { 383 OpRegImm(kOpSub, reg, 1); 384 return OpCmpImmBranch(c_code, reg, 0, target); 385} 386 387bool MipsMir2Lir::SmallLiteralDivRem(Instruction::Code dalvik_opcode, bool is_div, 388 RegLocation rl_src, RegLocation rl_dest, int lit) { 389 LOG(FATAL) << "Unexpected use of smallLiteralDive in Mips"; 390 return false; 391} 392 393bool MipsMir2Lir::EasyMultiply(RegLocation rl_src, RegLocation rl_dest, int lit) { 394 LOG(FATAL) << "Unexpected use of easyMultiply in Mips"; 395 return false; 396} 397 398LIR* MipsMir2Lir::OpIT(ConditionCode cond, const char* guide) { 399 LOG(FATAL) << "Unexpected use of OpIT in Mips"; 400 return NULL; 401} 402 403void MipsMir2Lir::OpEndIT(LIR* it) { 404 LOG(FATAL) << "Unexpected use of OpEndIT in Mips"; 405} 406 407 408void MipsMir2Lir::GenMulLong(Instruction::Code opcode, RegLocation rl_dest, 409 RegLocation rl_src1, RegLocation rl_src2) { 410 LOG(FATAL) << "Unexpected use of GenMulLong for Mips"; 411} 412 413void MipsMir2Lir::GenAddLong(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 * addu v0,a2,a0 421 * addu t1,a3,a1 422 * sltu v1,v0,a2 423 * addu v1,v1,t1 424 */ 425 426 OpRegRegReg(kOpAdd, rl_result.reg.GetLow(), rl_src2.reg.GetLow(), rl_src1.reg.GetLow()); 427 RegStorage t_reg = AllocTemp(); 428 OpRegRegReg(kOpAdd, t_reg, rl_src2.reg.GetHigh(), rl_src1.reg.GetHigh()); 429 NewLIR3(kMipsSltu, rl_result.reg.GetHighReg(), rl_result.reg.GetLowReg(), rl_src2.reg.GetLowReg()); 430 OpRegRegReg(kOpAdd, rl_result.reg.GetHigh(), rl_result.reg.GetHigh(), t_reg); 431 FreeTemp(t_reg); 432 StoreValueWide(rl_dest, rl_result); 433} 434 435void MipsMir2Lir::GenSubLong(Instruction::Code opcode, RegLocation rl_dest, 436 RegLocation rl_src1, RegLocation rl_src2) { 437 rl_src1 = LoadValueWide(rl_src1, kCoreReg); 438 rl_src2 = LoadValueWide(rl_src2, kCoreReg); 439 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); 440 /* 441 * [v1 v0] = [a1 a0] - [a3 a2]; 442 * sltu t1,a0,a2 443 * subu v0,a0,a2 444 * subu v1,a1,a3 445 * subu v1,v1,t1 446 */ 447 448 RegStorage t_reg = AllocTemp(); 449 NewLIR3(kMipsSltu, t_reg.GetReg(), rl_src1.reg.GetLowReg(), rl_src2.reg.GetLowReg()); 450 OpRegRegReg(kOpSub, rl_result.reg.GetLow(), rl_src1.reg.GetLow(), rl_src2.reg.GetLow()); 451 OpRegRegReg(kOpSub, rl_result.reg.GetHigh(), rl_src1.reg.GetHigh(), rl_src2.reg.GetHigh()); 452 OpRegRegReg(kOpSub, rl_result.reg.GetHigh(), rl_result.reg.GetHigh(), t_reg); 453 FreeTemp(t_reg); 454 StoreValueWide(rl_dest, rl_result); 455} 456 457void MipsMir2Lir::GenNotLong(RegLocation rl_dest, RegLocation rl_src) { 458 LOG(FATAL) << "Unexpected use GenNotLong()"; 459} 460 461void MipsMir2Lir::GenDivRemLong(Instruction::Code, RegLocation rl_dest, RegLocation rl_src1, 462 RegLocation rl_src2, bool is_div) { 463 LOG(FATAL) << "Unexpected use GenDivRemLong()"; 464} 465 466void MipsMir2Lir::GenNegLong(RegLocation rl_dest, RegLocation rl_src) { 467 rl_src = LoadValueWide(rl_src, kCoreReg); 468 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); 469 /* 470 * [v1 v0] = -[a1 a0] 471 * negu v0,a0 472 * negu v1,a1 473 * sltu t1,r_zero 474 * subu v1,v1,t1 475 */ 476 477 OpRegReg(kOpNeg, rl_result.reg.GetLow(), rl_src.reg.GetLow()); 478 OpRegReg(kOpNeg, rl_result.reg.GetHigh(), rl_src.reg.GetHigh()); 479 RegStorage t_reg = AllocTemp(); 480 NewLIR3(kMipsSltu, t_reg.GetReg(), rZERO, rl_result.reg.GetLowReg()); 481 OpRegRegReg(kOpSub, rl_result.reg.GetHigh(), rl_result.reg.GetHigh(), t_reg); 482 FreeTemp(t_reg); 483 StoreValueWide(rl_dest, rl_result); 484} 485 486void MipsMir2Lir::GenAndLong(Instruction::Code opcode, RegLocation rl_dest, 487 RegLocation rl_src1, 488 RegLocation rl_src2) { 489 LOG(FATAL) << "Unexpected use of GenAndLong for Mips"; 490} 491 492void MipsMir2Lir::GenOrLong(Instruction::Code opcode, RegLocation rl_dest, 493 RegLocation rl_src1, RegLocation rl_src2) { 494 LOG(FATAL) << "Unexpected use of GenOrLong for Mips"; 495} 496 497void MipsMir2Lir::GenXorLong(Instruction::Code opcode, RegLocation rl_dest, 498 RegLocation rl_src1, RegLocation rl_src2) { 499 LOG(FATAL) << "Unexpected use of GenXorLong for Mips"; 500} 501 502/* 503 * Generate array load 504 */ 505void MipsMir2Lir::GenArrayGet(int opt_flags, OpSize size, RegLocation rl_array, 506 RegLocation rl_index, RegLocation rl_dest, int scale) { 507 RegisterClass reg_class = RegClassBySize(size); 508 int len_offset = mirror::Array::LengthOffset().Int32Value(); 509 int data_offset; 510 RegLocation rl_result; 511 rl_array = LoadValue(rl_array, kRefReg); 512 rl_index = LoadValue(rl_index, kCoreReg); 513 514 // FIXME: need to add support for rl_index.is_const. 515 516 if (size == k64 || size == kDouble) { 517 data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Int32Value(); 518 } else { 519 data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Int32Value(); 520 } 521 522 /* null object? */ 523 GenNullCheck(rl_array.reg, opt_flags); 524 525 RegStorage reg_ptr = AllocTemp(); 526 bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK)); 527 RegStorage reg_len; 528 if (needs_range_check) { 529 reg_len = AllocTemp(); 530 /* Get len */ 531 Load32Disp(rl_array.reg, len_offset, reg_len); 532 } 533 /* reg_ptr -> array data */ 534 OpRegRegImm(kOpAdd, reg_ptr, rl_array.reg, data_offset); 535 FreeTemp(rl_array.reg); 536 if ((size == k64) || (size == kDouble)) { 537 if (scale) { 538 RegStorage r_new_index = AllocTemp(); 539 OpRegRegImm(kOpLsl, r_new_index, rl_index.reg, scale); 540 OpRegReg(kOpAdd, reg_ptr, r_new_index); 541 FreeTemp(r_new_index); 542 } else { 543 OpRegReg(kOpAdd, reg_ptr, rl_index.reg); 544 } 545 FreeTemp(rl_index.reg); 546 rl_result = EvalLoc(rl_dest, reg_class, true); 547 548 if (needs_range_check) { 549 GenArrayBoundsCheck(rl_index.reg, reg_len); 550 FreeTemp(reg_len); 551 } 552 LoadBaseDisp(reg_ptr, 0, rl_result.reg, size, kNotVolatile); 553 554 FreeTemp(reg_ptr); 555 StoreValueWide(rl_dest, rl_result); 556 } else { 557 rl_result = EvalLoc(rl_dest, reg_class, true); 558 559 if (needs_range_check) { 560 GenArrayBoundsCheck(rl_index.reg, reg_len); 561 FreeTemp(reg_len); 562 } 563 LoadBaseIndexed(reg_ptr, rl_index.reg, rl_result.reg, scale, size); 564 565 FreeTemp(reg_ptr); 566 StoreValue(rl_dest, rl_result); 567 } 568} 569 570/* 571 * Generate array store 572 * 573 */ 574void MipsMir2Lir::GenArrayPut(int opt_flags, OpSize size, RegLocation rl_array, 575 RegLocation rl_index, RegLocation rl_src, int scale, bool card_mark) { 576 RegisterClass reg_class = RegClassBySize(size); 577 int len_offset = mirror::Array::LengthOffset().Int32Value(); 578 int data_offset; 579 580 if (size == k64 || size == kDouble) { 581 data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Int32Value(); 582 } else { 583 data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Int32Value(); 584 } 585 586 rl_array = LoadValue(rl_array, kRefReg); 587 rl_index = LoadValue(rl_index, kCoreReg); 588 589 // FIXME: need to add support for rl_index.is_const. 590 591 RegStorage reg_ptr; 592 bool allocated_reg_ptr_temp = false; 593 if (IsTemp(rl_array.reg) && !card_mark) { 594 Clobber(rl_array.reg); 595 reg_ptr = rl_array.reg; 596 } else { 597 reg_ptr = AllocTemp(); 598 OpRegCopy(reg_ptr, rl_array.reg); 599 allocated_reg_ptr_temp = true; 600 } 601 602 /* null object? */ 603 GenNullCheck(rl_array.reg, opt_flags); 604 605 bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK)); 606 RegStorage reg_len; 607 if (needs_range_check) { 608 reg_len = AllocTemp(); 609 // NOTE: max live temps(4) here. 610 /* Get len */ 611 Load32Disp(rl_array.reg, len_offset, reg_len); 612 } 613 /* reg_ptr -> array data */ 614 OpRegImm(kOpAdd, reg_ptr, data_offset); 615 /* at this point, reg_ptr points to array, 2 live temps */ 616 if ((size == k64) || (size == kDouble)) { 617 // TUNING: specific wide routine that can handle fp regs 618 if (scale) { 619 RegStorage r_new_index = AllocTemp(); 620 OpRegRegImm(kOpLsl, r_new_index, rl_index.reg, scale); 621 OpRegReg(kOpAdd, reg_ptr, r_new_index); 622 FreeTemp(r_new_index); 623 } else { 624 OpRegReg(kOpAdd, reg_ptr, rl_index.reg); 625 } 626 rl_src = LoadValueWide(rl_src, reg_class); 627 628 if (needs_range_check) { 629 GenArrayBoundsCheck(rl_index.reg, reg_len); 630 FreeTemp(reg_len); 631 } 632 633 StoreBaseDisp(reg_ptr, 0, rl_src.reg, size, kNotVolatile); 634 } else { 635 rl_src = LoadValue(rl_src, reg_class); 636 if (needs_range_check) { 637 GenArrayBoundsCheck(rl_index.reg, reg_len); 638 FreeTemp(reg_len); 639 } 640 StoreBaseIndexed(reg_ptr, rl_index.reg, rl_src.reg, scale, size); 641 } 642 if (allocated_reg_ptr_temp) { 643 FreeTemp(reg_ptr); 644 } 645 if (card_mark) { 646 MarkGCCard(rl_src.reg, rl_array.reg); 647 } 648} 649 650void MipsMir2Lir::GenShiftImmOpLong(Instruction::Code opcode, RegLocation rl_dest, 651 RegLocation rl_src1, RegLocation rl_shift) { 652 // Default implementation is just to ignore the constant case. 653 GenShiftOpLong(opcode, rl_dest, rl_src1, rl_shift); 654} 655 656void MipsMir2Lir::GenArithImmOpLong(Instruction::Code opcode, 657 RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2) { 658 // Default - bail to non-const handler. 659 GenArithOpLong(opcode, rl_dest, rl_src1, rl_src2); 660} 661 662} // namespace art 663