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