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