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