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