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