int_mips.cc revision bebee4fd10e5db6cb07f59bc0f73297c900ea5f0
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 "dex/reg_storage_eq.h"
22#include "entrypoints/quick/quick_entrypoints.h"
23#include "mips_lir.h"
24#include "mirror/array.h"
25
26namespace art {
27
28/*
29 * Compare two 64-bit values
30 *    x = y     return  0
31 *    x < y     return -1
32 *    x > y     return  1
33 *
34 *    slt   t0,  x.hi, y.hi;        # (x.hi < y.hi) ? 1:0
35 *    sgt   t1,  x.hi, y.hi;        # (y.hi > x.hi) ? 1:0
36 *    subu  res, t0, t1             # res = -1:1:0 for [ < > = ]
37 *    bnez  res, finish
38 *    sltu  t0, x.lo, y.lo
39 *    sgtu  r1, x.lo, y.lo
40 *    subu  res, t0, t1
41 * finish:
42 *
43 */
44void MipsMir2Lir::GenCmpLong(RegLocation rl_dest, RegLocation rl_src1,
45                             RegLocation rl_src2) {
46  rl_src1 = LoadValueWide(rl_src1, kCoreReg);
47  rl_src2 = LoadValueWide(rl_src2, kCoreReg);
48  RegStorage t0 = AllocTemp();
49  RegStorage t1 = AllocTemp();
50  RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
51  NewLIR3(kMipsSlt, t0.GetReg(), rl_src1.reg.GetHighReg(), rl_src2.reg.GetHighReg());
52  NewLIR3(kMipsSlt, t1.GetReg(), rl_src2.reg.GetHighReg(), rl_src1.reg.GetHighReg());
53  NewLIR3(kMipsSubu, rl_result.reg.GetReg(), t1.GetReg(), t0.GetReg());
54  LIR* branch = OpCmpImmBranch(kCondNe, rl_result.reg, 0, NULL);
55  NewLIR3(kMipsSltu, t0.GetReg(), rl_src1.reg.GetLowReg(), rl_src2.reg.GetLowReg());
56  NewLIR3(kMipsSltu, t1.GetReg(), rl_src2.reg.GetLowReg(), rl_src1.reg.GetLowReg());
57  NewLIR3(kMipsSubu, rl_result.reg.GetReg(), t1.GetReg(), t0.GetReg());
58  FreeTemp(t0);
59  FreeTemp(t1);
60  LIR* target = NewLIR0(kPseudoTargetLabel);
61  branch->target = target;
62  StoreValue(rl_dest, rl_result);
63}
64
65LIR* MipsMir2Lir::OpCmpBranch(ConditionCode cond, RegStorage src1, RegStorage src2, LIR* target) {
66  LIR* branch;
67  MipsOpCode slt_op;
68  MipsOpCode br_op;
69  bool cmp_zero = false;
70  bool swapped = false;
71  switch (cond) {
72    case kCondEq:
73      br_op = kMipsBeq;
74      cmp_zero = true;
75      break;
76    case kCondNe:
77      br_op = kMipsBne;
78      cmp_zero = true;
79      break;
80    case kCondUlt:
81      slt_op = kMipsSltu;
82      br_op = kMipsBnez;
83      break;
84    case kCondUge:
85      slt_op = kMipsSltu;
86      br_op = kMipsBeqz;
87      break;
88    case kCondGe:
89      slt_op = kMipsSlt;
90      br_op = kMipsBeqz;
91      break;
92    case kCondGt:
93      slt_op = kMipsSlt;
94      br_op = kMipsBnez;
95      swapped = true;
96      break;
97    case kCondLe:
98      slt_op = kMipsSlt;
99      br_op = kMipsBeqz;
100      swapped = true;
101      break;
102    case kCondLt:
103      slt_op = kMipsSlt;
104      br_op = kMipsBnez;
105      break;
106    case kCondHi:  // Gtu
107      slt_op = kMipsSltu;
108      br_op = kMipsBnez;
109      swapped = true;
110      break;
111    default:
112      LOG(FATAL) << "No support for ConditionCode: " << cond;
113      return NULL;
114  }
115  if (cmp_zero) {
116    branch = NewLIR2(br_op, src1.GetReg(), src2.GetReg());
117  } else {
118    RegStorage t_reg = AllocTemp();
119    if (swapped) {
120      NewLIR3(slt_op, t_reg.GetReg(), src2.GetReg(), src1.GetReg());
121    } else {
122      NewLIR3(slt_op, t_reg.GetReg(), src1.GetReg(), src2.GetReg());
123    }
124    branch = NewLIR1(br_op, t_reg.GetReg());
125    FreeTemp(t_reg);
126  }
127  branch->target = target;
128  return branch;
129}
130
131LIR* MipsMir2Lir::OpCmpImmBranch(ConditionCode cond, RegStorage reg, int check_value, LIR* target) {
132  LIR* branch;
133  if (check_value != 0) {
134    // TUNING: handle s16 & kCondLt/Mi case using slti
135    RegStorage t_reg = AllocTemp();
136    LoadConstant(t_reg, check_value);
137    branch = OpCmpBranch(cond, reg, t_reg, target);
138    FreeTemp(t_reg);
139    return branch;
140  }
141  MipsOpCode opc;
142  switch (cond) {
143    case kCondEq: opc = kMipsBeqz; break;
144    case kCondGe: opc = kMipsBgez; break;
145    case kCondGt: opc = kMipsBgtz; break;
146    case kCondLe: opc = kMipsBlez; break;
147    // case KCondMi:
148    case kCondLt: opc = kMipsBltz; break;
149    case kCondNe: opc = kMipsBnez; break;
150    default:
151      // Tuning: use slti when applicable
152      RegStorage t_reg = AllocTemp();
153      LoadConstant(t_reg, check_value);
154      branch = OpCmpBranch(cond, reg, t_reg, target);
155      FreeTemp(t_reg);
156      return branch;
157  }
158  branch = NewLIR1(opc, reg.GetReg());
159  branch->target = target;
160  return branch;
161}
162
163LIR* MipsMir2Lir::OpRegCopyNoInsert(RegStorage r_dest, RegStorage r_src) {
164  // If src or dest is a pair, we'll be using low reg.
165  if (r_dest.IsPair()) {
166    r_dest = r_dest.GetLow();
167  }
168  if (r_src.IsPair()) {
169    r_src = r_src.GetLow();
170  }
171  if (r_dest.IsFloat() || r_src.IsFloat())
172    return OpFpRegCopy(r_dest, r_src);
173  LIR* res = RawLIR(current_dalvik_offset_, kMipsMove,
174            r_dest.GetReg(), r_src.GetReg());
175  if (!(cu_->disable_opt & (1 << kSafeOptimizations)) && r_dest == r_src) {
176    res->flags.is_nop = true;
177  }
178  return res;
179}
180
181void MipsMir2Lir::OpRegCopy(RegStorage r_dest, RegStorage r_src) {
182  if (r_dest != r_src) {
183    LIR *res = OpRegCopyNoInsert(r_dest, r_src);
184    AppendLIR(res);
185  }
186}
187
188void MipsMir2Lir::OpRegCopyWide(RegStorage r_dest, RegStorage r_src) {
189  if (r_dest != r_src) {
190    bool dest_fp = r_dest.IsFloat();
191    bool src_fp = r_src.IsFloat();
192    if (dest_fp) {
193      if (src_fp) {
194        OpRegCopy(r_dest, r_src);
195      } else {
196         /* note the operands are swapped for the mtc1 instr */
197        NewLIR2(kMipsMtc1, r_src.GetLowReg(), r_dest.GetLowReg());
198        NewLIR2(kMipsMtc1, r_src.GetHighReg(), r_dest.GetHighReg());
199      }
200    } else {
201      if (src_fp) {
202        NewLIR2(kMipsMfc1, r_dest.GetLowReg(), r_src.GetLowReg());
203        NewLIR2(kMipsMfc1, r_dest.GetHighReg(), r_src.GetHighReg());
204      } else {
205        // Handle overlap
206        if (r_src.GetHighReg() == r_dest.GetLowReg()) {
207          OpRegCopy(r_dest.GetHigh(), r_src.GetHigh());
208          OpRegCopy(r_dest.GetLow(), r_src.GetLow());
209        } else {
210          OpRegCopy(r_dest.GetLow(), r_src.GetLow());
211          OpRegCopy(r_dest.GetHigh(), r_src.GetHigh());
212        }
213      }
214    }
215  }
216}
217
218void MipsMir2Lir::GenSelectConst32(RegStorage left_op, RegStorage right_op, ConditionCode code,
219                                   int32_t true_val, int32_t false_val, RegStorage rs_dest,
220                                   int dest_reg_class) {
221  // Implement as a branch-over.
222  // TODO: Conditional move?
223  LoadConstant(rs_dest, false_val);  // Favors false.
224  LIR* ne_branchover = OpCmpBranch(code, left_op, right_op, NULL);
225  LoadConstant(rs_dest, true_val);
226  LIR* target_label = NewLIR0(kPseudoTargetLabel);
227  ne_branchover->target = target_label;
228}
229
230void MipsMir2Lir::GenSelect(BasicBlock* bb, MIR* mir) {
231  UNIMPLEMENTED(FATAL) << "Need codegen for select";
232}
233
234void MipsMir2Lir::GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir) {
235  UNIMPLEMENTED(FATAL) << "Need codegen for fused long cmp branch";
236}
237
238RegLocation MipsMir2Lir::GenDivRem(RegLocation rl_dest, RegStorage reg1, RegStorage reg2,
239                                    bool is_div) {
240  NewLIR2(kMipsDiv, reg1.GetReg(), reg2.GetReg());
241  RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
242  if (is_div) {
243    NewLIR1(kMipsMflo, rl_result.reg.GetReg());
244  } else {
245    NewLIR1(kMipsMfhi, rl_result.reg.GetReg());
246  }
247  return rl_result;
248}
249
250RegLocation MipsMir2Lir::GenDivRemLit(RegLocation rl_dest, RegStorage reg1, int lit,
251                                       bool is_div) {
252  RegStorage t_reg = AllocTemp();
253  NewLIR3(kMipsAddiu, t_reg.GetReg(), rZERO, lit);
254  NewLIR2(kMipsDiv, reg1.GetReg(), t_reg.GetReg());
255  RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
256  if (is_div) {
257    NewLIR1(kMipsMflo, rl_result.reg.GetReg());
258  } else {
259    NewLIR1(kMipsMfhi, rl_result.reg.GetReg());
260  }
261  FreeTemp(t_reg);
262  return rl_result;
263}
264
265RegLocation MipsMir2Lir::GenDivRem(RegLocation rl_dest, RegLocation rl_src1,
266                      RegLocation rl_src2, bool is_div, bool check_zero) {
267  LOG(FATAL) << "Unexpected use of GenDivRem for Mips";
268  return rl_dest;
269}
270
271RegLocation MipsMir2Lir::GenDivRemLit(RegLocation rl_dest, RegLocation rl_src1, int lit, bool is_div) {
272  LOG(FATAL) << "Unexpected use of GenDivRemLit for Mips";
273  return rl_dest;
274}
275
276void MipsMir2Lir::OpLea(RegStorage r_base, RegStorage reg1, RegStorage reg2, int scale,
277                        int offset) {
278  LOG(FATAL) << "Unexpected use of OpLea for Arm";
279}
280
281void MipsMir2Lir::OpTlsCmp(ThreadOffset<4> offset, int val) {
282  LOG(FATAL) << "Unexpected use of OpTlsCmp for Arm";
283}
284
285void MipsMir2Lir::OpTlsCmp(ThreadOffset<8> offset, int val) {
286  UNIMPLEMENTED(FATAL) << "Should not be called.";
287}
288
289bool MipsMir2Lir::GenInlinedCas(CallInfo* info, bool is_long, bool is_object) {
290  DCHECK_NE(cu_->instruction_set, kThumb2);
291  return false;
292}
293
294bool MipsMir2Lir::GenInlinedAbsFloat(CallInfo* info) {
295  // TODO - add Mips implementation
296  return false;
297}
298
299bool MipsMir2Lir::GenInlinedAbsDouble(CallInfo* info) {
300  // TODO - add Mips implementation
301  return false;
302}
303
304bool MipsMir2Lir::GenInlinedSqrt(CallInfo* info) {
305  DCHECK_NE(cu_->instruction_set, kThumb2);
306  return false;
307}
308
309bool MipsMir2Lir::GenInlinedPeek(CallInfo* info, OpSize size) {
310  if (size != kSignedByte) {
311    // MIPS supports only aligned access. Defer unaligned access to JNI implementation.
312    return false;
313  }
314  RegLocation rl_src_address = info->args[0];  // long address
315  rl_src_address = NarrowRegLoc(rl_src_address);  // ignore high half in info->args[1]
316  RegLocation rl_dest = InlineTarget(info);
317  RegLocation rl_address = LoadValue(rl_src_address, kCoreReg);
318  RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
319  DCHECK(size == kSignedByte);
320  LoadBaseDisp(rl_address.reg, 0, rl_result.reg, size, kNotVolatile);
321  StoreValue(rl_dest, rl_result);
322  return true;
323}
324
325bool MipsMir2Lir::GenInlinedPoke(CallInfo* info, OpSize size) {
326  if (size != kSignedByte) {
327    // MIPS supports only aligned access. Defer unaligned access to JNI implementation.
328    return false;
329  }
330  RegLocation rl_src_address = info->args[0];  // long address
331  rl_src_address = NarrowRegLoc(rl_src_address);  // ignore high half in info->args[1]
332  RegLocation rl_src_value = info->args[2];  // [size] value
333  RegLocation rl_address = LoadValue(rl_src_address, kCoreReg);
334  DCHECK(size == kSignedByte);
335  RegLocation rl_value = LoadValue(rl_src_value, kCoreReg);
336  StoreBaseDisp(rl_address.reg, 0, rl_value.reg, size, kNotVolatile);
337  return true;
338}
339
340LIR* MipsMir2Lir::OpPcRelLoad(RegStorage reg, LIR* target) {
341  LOG(FATAL) << "Unexpected use of OpPcRelLoad for Mips";
342  return NULL;
343}
344
345LIR* MipsMir2Lir::OpVldm(RegStorage r_base, int count) {
346  LOG(FATAL) << "Unexpected use of OpVldm for Mips";
347  return NULL;
348}
349
350LIR* MipsMir2Lir::OpVstm(RegStorage r_base, int count) {
351  LOG(FATAL) << "Unexpected use of OpVstm for Mips";
352  return NULL;
353}
354
355void MipsMir2Lir::GenMultiplyByTwoBitMultiplier(RegLocation rl_src,
356                                                RegLocation rl_result, int lit,
357                                                int first_bit, int second_bit) {
358  RegStorage t_reg = AllocTemp();
359  OpRegRegImm(kOpLsl, t_reg, rl_src.reg, second_bit - first_bit);
360  OpRegRegReg(kOpAdd, rl_result.reg, rl_src.reg, t_reg);
361  FreeTemp(t_reg);
362  if (first_bit != 0) {
363    OpRegRegImm(kOpLsl, rl_result.reg, rl_result.reg, first_bit);
364  }
365}
366
367void MipsMir2Lir::GenDivZeroCheckWide(RegStorage reg) {
368  DCHECK(reg.IsPair());   // TODO: support k64BitSolo.
369  RegStorage t_reg = AllocTemp();
370  OpRegRegReg(kOpOr, t_reg, reg.GetLow(), reg.GetHigh());
371  GenDivZeroCheck(t_reg);
372  FreeTemp(t_reg);
373}
374
375// Test suspend flag, return target of taken suspend branch
376LIR* MipsMir2Lir::OpTestSuspend(LIR* target) {
377  OpRegImm(kOpSub, rs_rMIPS_SUSPEND, 1);
378  return OpCmpImmBranch((target == NULL) ? kCondEq : kCondNe, rs_rMIPS_SUSPEND, 0, target);
379}
380
381// Decrement register and branch on condition
382LIR* MipsMir2Lir::OpDecAndBranch(ConditionCode c_code, RegStorage reg, LIR* target) {
383  OpRegImm(kOpSub, reg, 1);
384  return OpCmpImmBranch(c_code, reg, 0, target);
385}
386
387bool MipsMir2Lir::SmallLiteralDivRem(Instruction::Code dalvik_opcode, bool is_div,
388                                     RegLocation rl_src, RegLocation rl_dest, int lit) {
389  LOG(FATAL) << "Unexpected use of smallLiteralDive in Mips";
390  return false;
391}
392
393bool MipsMir2Lir::EasyMultiply(RegLocation rl_src, RegLocation rl_dest, int lit) {
394  LOG(FATAL) << "Unexpected use of easyMultiply in Mips";
395  return false;
396}
397
398LIR* MipsMir2Lir::OpIT(ConditionCode cond, const char* guide) {
399  LOG(FATAL) << "Unexpected use of OpIT in Mips";
400  return NULL;
401}
402
403void MipsMir2Lir::OpEndIT(LIR* it) {
404  LOG(FATAL) << "Unexpected use of OpEndIT in Mips";
405}
406
407
408void MipsMir2Lir::GenMulLong(Instruction::Code opcode, RegLocation rl_dest,
409                             RegLocation rl_src1, RegLocation rl_src2) {
410  LOG(FATAL) << "Unexpected use of GenMulLong for Mips";
411}
412
413void MipsMir2Lir::GenAddLong(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   *  addu v0,a2,a0
421   *  addu t1,a3,a1
422   *  sltu v1,v0,a2
423   *  addu v1,v1,t1
424   */
425
426  OpRegRegReg(kOpAdd, rl_result.reg.GetLow(), rl_src2.reg.GetLow(), rl_src1.reg.GetLow());
427  RegStorage t_reg = AllocTemp();
428  OpRegRegReg(kOpAdd, t_reg, rl_src2.reg.GetHigh(), rl_src1.reg.GetHigh());
429  NewLIR3(kMipsSltu, rl_result.reg.GetHighReg(), rl_result.reg.GetLowReg(), rl_src2.reg.GetLowReg());
430  OpRegRegReg(kOpAdd, rl_result.reg.GetHigh(), rl_result.reg.GetHigh(), t_reg);
431  FreeTemp(t_reg);
432  StoreValueWide(rl_dest, rl_result);
433}
434
435void MipsMir2Lir::GenSubLong(Instruction::Code opcode, RegLocation rl_dest,
436                             RegLocation rl_src1, RegLocation rl_src2) {
437  rl_src1 = LoadValueWide(rl_src1, kCoreReg);
438  rl_src2 = LoadValueWide(rl_src2, kCoreReg);
439  RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
440  /*
441   *  [v1 v0] =  [a1 a0] - [a3 a2];
442   *  sltu  t1,a0,a2
443   *  subu  v0,a0,a2
444   *  subu  v1,a1,a3
445   *  subu  v1,v1,t1
446   */
447
448  RegStorage t_reg = AllocTemp();
449  NewLIR3(kMipsSltu, t_reg.GetReg(), rl_src1.reg.GetLowReg(), rl_src2.reg.GetLowReg());
450  OpRegRegReg(kOpSub, rl_result.reg.GetLow(), rl_src1.reg.GetLow(), rl_src2.reg.GetLow());
451  OpRegRegReg(kOpSub, rl_result.reg.GetHigh(), rl_src1.reg.GetHigh(), rl_src2.reg.GetHigh());
452  OpRegRegReg(kOpSub, rl_result.reg.GetHigh(), rl_result.reg.GetHigh(), t_reg);
453  FreeTemp(t_reg);
454  StoreValueWide(rl_dest, rl_result);
455}
456
457void MipsMir2Lir::GenNotLong(RegLocation rl_dest, RegLocation rl_src) {
458  LOG(FATAL) << "Unexpected use GenNotLong()";
459}
460
461void MipsMir2Lir::GenDivRemLong(Instruction::Code, RegLocation rl_dest, RegLocation rl_src1,
462                           RegLocation rl_src2, bool is_div) {
463  LOG(FATAL) << "Unexpected use GenDivRemLong()";
464}
465
466void MipsMir2Lir::GenNegLong(RegLocation rl_dest, RegLocation rl_src) {
467  rl_src = LoadValueWide(rl_src, kCoreReg);
468  RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
469  /*
470   *  [v1 v0] =  -[a1 a0]
471   *  negu  v0,a0
472   *  negu  v1,a1
473   *  sltu  t1,r_zero
474   *  subu  v1,v1,t1
475   */
476
477  OpRegReg(kOpNeg, rl_result.reg.GetLow(), rl_src.reg.GetLow());
478  OpRegReg(kOpNeg, rl_result.reg.GetHigh(), rl_src.reg.GetHigh());
479  RegStorage t_reg = AllocTemp();
480  NewLIR3(kMipsSltu, t_reg.GetReg(), rZERO, rl_result.reg.GetLowReg());
481  OpRegRegReg(kOpSub, rl_result.reg.GetHigh(), rl_result.reg.GetHigh(), t_reg);
482  FreeTemp(t_reg);
483  StoreValueWide(rl_dest, rl_result);
484}
485
486void MipsMir2Lir::GenAndLong(Instruction::Code opcode, RegLocation rl_dest,
487                             RegLocation rl_src1,
488                             RegLocation rl_src2) {
489  LOG(FATAL) << "Unexpected use of GenAndLong for Mips";
490}
491
492void MipsMir2Lir::GenOrLong(Instruction::Code opcode, RegLocation rl_dest,
493                            RegLocation rl_src1, RegLocation rl_src2) {
494  LOG(FATAL) << "Unexpected use of GenOrLong for Mips";
495}
496
497void MipsMir2Lir::GenXorLong(Instruction::Code opcode, RegLocation rl_dest,
498                             RegLocation rl_src1, RegLocation rl_src2) {
499  LOG(FATAL) << "Unexpected use of GenXorLong for Mips";
500}
501
502/*
503 * Generate array load
504 */
505void MipsMir2Lir::GenArrayGet(int opt_flags, OpSize size, RegLocation rl_array,
506                          RegLocation rl_index, RegLocation rl_dest, int scale) {
507  RegisterClass reg_class = RegClassBySize(size);
508  int len_offset = mirror::Array::LengthOffset().Int32Value();
509  int data_offset;
510  RegLocation rl_result;
511  rl_array = LoadValue(rl_array, kRefReg);
512  rl_index = LoadValue(rl_index, kCoreReg);
513
514  // FIXME: need to add support for rl_index.is_const.
515
516  if (size == k64 || size == kDouble) {
517    data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Int32Value();
518  } else {
519    data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Int32Value();
520  }
521
522  /* null object? */
523  GenNullCheck(rl_array.reg, opt_flags);
524
525  RegStorage reg_ptr = AllocTemp();
526  bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK));
527  RegStorage reg_len;
528  if (needs_range_check) {
529    reg_len = AllocTemp();
530    /* Get len */
531    Load32Disp(rl_array.reg, len_offset, reg_len);
532  }
533  /* reg_ptr -> array data */
534  OpRegRegImm(kOpAdd, reg_ptr, rl_array.reg, data_offset);
535  FreeTemp(rl_array.reg);
536  if ((size == k64) || (size == kDouble)) {
537    if (scale) {
538      RegStorage r_new_index = AllocTemp();
539      OpRegRegImm(kOpLsl, r_new_index, rl_index.reg, scale);
540      OpRegReg(kOpAdd, reg_ptr, r_new_index);
541      FreeTemp(r_new_index);
542    } else {
543      OpRegReg(kOpAdd, reg_ptr, rl_index.reg);
544    }
545    FreeTemp(rl_index.reg);
546    rl_result = EvalLoc(rl_dest, reg_class, true);
547
548    if (needs_range_check) {
549      GenArrayBoundsCheck(rl_index.reg, reg_len);
550      FreeTemp(reg_len);
551    }
552    LoadBaseDisp(reg_ptr, 0, rl_result.reg, size, kNotVolatile);
553
554    FreeTemp(reg_ptr);
555    StoreValueWide(rl_dest, rl_result);
556  } else {
557    rl_result = EvalLoc(rl_dest, reg_class, true);
558
559    if (needs_range_check) {
560      GenArrayBoundsCheck(rl_index.reg, reg_len);
561      FreeTemp(reg_len);
562    }
563    LoadBaseIndexed(reg_ptr, rl_index.reg, rl_result.reg, scale, size);
564
565    FreeTemp(reg_ptr);
566    StoreValue(rl_dest, rl_result);
567  }
568}
569
570/*
571 * Generate array store
572 *
573 */
574void MipsMir2Lir::GenArrayPut(int opt_flags, OpSize size, RegLocation rl_array,
575                          RegLocation rl_index, RegLocation rl_src, int scale, bool card_mark) {
576  RegisterClass reg_class = RegClassBySize(size);
577  int len_offset = mirror::Array::LengthOffset().Int32Value();
578  int data_offset;
579
580  if (size == k64 || size == kDouble) {
581    data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Int32Value();
582  } else {
583    data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Int32Value();
584  }
585
586  rl_array = LoadValue(rl_array, kRefReg);
587  rl_index = LoadValue(rl_index, kCoreReg);
588
589  // FIXME: need to add support for rl_index.is_const.
590
591  RegStorage reg_ptr;
592  bool allocated_reg_ptr_temp = false;
593  if (IsTemp(rl_array.reg) && !card_mark) {
594    Clobber(rl_array.reg);
595    reg_ptr = rl_array.reg;
596  } else {
597    reg_ptr = AllocTemp();
598    OpRegCopy(reg_ptr, rl_array.reg);
599    allocated_reg_ptr_temp = true;
600  }
601
602  /* null object? */
603  GenNullCheck(rl_array.reg, opt_flags);
604
605  bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK));
606  RegStorage reg_len;
607  if (needs_range_check) {
608    reg_len = AllocTemp();
609    // NOTE: max live temps(4) here.
610    /* Get len */
611    Load32Disp(rl_array.reg, len_offset, reg_len);
612  }
613  /* reg_ptr -> array data */
614  OpRegImm(kOpAdd, reg_ptr, data_offset);
615  /* at this point, reg_ptr points to array, 2 live temps */
616  if ((size == k64) || (size == kDouble)) {
617    // TUNING: specific wide routine that can handle fp regs
618    if (scale) {
619      RegStorage r_new_index = AllocTemp();
620      OpRegRegImm(kOpLsl, r_new_index, rl_index.reg, scale);
621      OpRegReg(kOpAdd, reg_ptr, r_new_index);
622      FreeTemp(r_new_index);
623    } else {
624      OpRegReg(kOpAdd, reg_ptr, rl_index.reg);
625    }
626    rl_src = LoadValueWide(rl_src, reg_class);
627
628    if (needs_range_check) {
629      GenArrayBoundsCheck(rl_index.reg, reg_len);
630      FreeTemp(reg_len);
631    }
632
633    StoreBaseDisp(reg_ptr, 0, rl_src.reg, size, kNotVolatile);
634  } else {
635    rl_src = LoadValue(rl_src, reg_class);
636    if (needs_range_check) {
637       GenArrayBoundsCheck(rl_index.reg, reg_len);
638      FreeTemp(reg_len);
639    }
640    StoreBaseIndexed(reg_ptr, rl_index.reg, rl_src.reg, scale, size);
641  }
642  if (allocated_reg_ptr_temp) {
643    FreeTemp(reg_ptr);
644  }
645  if (card_mark) {
646    MarkGCCard(rl_src.reg, rl_array.reg);
647  }
648}
649
650void MipsMir2Lir::GenShiftImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
651                                    RegLocation rl_src1, RegLocation rl_shift) {
652  // Default implementation is just to ignore the constant case.
653  GenShiftOpLong(opcode, rl_dest, rl_src1, rl_shift);
654}
655
656void MipsMir2Lir::GenArithImmOpLong(Instruction::Code opcode,
657                                    RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2) {
658  // Default - bail to non-const handler.
659  GenArithOpLong(opcode, rl_dest, rl_src1, rl_src2);
660}
661
662}  // namespace art
663