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