int_mips.cc revision a9a8254c920ce8e22210abfc16c9842ce0aea28f
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();
48  int t1 = AllocTemp();
49  RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
50  NewLIR3(kMipsSlt, t0, rl_src1.high_reg, rl_src2.high_reg);
51  NewLIR3(kMipsSlt, t1, rl_src2.high_reg, rl_src1.high_reg);
52  NewLIR3(kMipsSubu, rl_result.low_reg, t1, t0);
53  LIR* branch = OpCmpImmBranch(kCondNe, rl_result.low_reg, 0, NULL);
54  NewLIR3(kMipsSltu, t0, rl_src1.low_reg, rl_src2.low_reg);
55  NewLIR3(kMipsSltu, t1, rl_src2.low_reg, rl_src1.low_reg);
56  NewLIR3(kMipsSubu, rl_result.low_reg, 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, int src1, int src2,
65                              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 kCondCc:
81      slt_op = kMipsSltu;
82      br_op = kMipsBnez;
83      break;
84    case kCondCs:
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, src2);
117  } else {
118    int t_reg = AllocTemp();
119    if (swapped) {
120      NewLIR3(slt_op, t_reg, src2, src1);
121    } else {
122      NewLIR3(slt_op, t_reg, src1, src2);
123    }
124    branch = NewLIR1(br_op, t_reg);
125    FreeTemp(t_reg);
126  }
127  branch->target = target;
128  return branch;
129}
130
131LIR* MipsMir2Lir::OpCmpImmBranch(ConditionCode cond, int reg,
132                                 int check_value, LIR* target) {
133  LIR* branch;
134  if (check_value != 0) {
135    // TUNING: handle s16 & kCondLt/Mi case using slti
136    int t_reg = AllocTemp();
137    LoadConstant(t_reg, check_value);
138    branch = OpCmpBranch(cond, reg, t_reg, target);
139    FreeTemp(t_reg);
140    return branch;
141  }
142  MipsOpCode opc;
143  switch (cond) {
144    case kCondEq: opc = kMipsBeqz; break;
145    case kCondGe: opc = kMipsBgez; break;
146    case kCondGt: opc = kMipsBgtz; break;
147    case kCondLe: opc = kMipsBlez; break;
148    // case KCondMi:
149    case kCondLt: opc = kMipsBltz; break;
150    case kCondNe: opc = kMipsBnez; break;
151    default:
152      // Tuning: use slti when applicable
153      int t_reg = AllocTemp();
154      LoadConstant(t_reg, check_value);
155      branch = OpCmpBranch(cond, reg, t_reg, target);
156      FreeTemp(t_reg);
157      return branch;
158  }
159  branch = NewLIR1(opc, reg);
160  branch->target = target;
161  return branch;
162}
163
164LIR* MipsMir2Lir::OpRegCopyNoInsert(int r_dest, int r_src) {
165  if (MIPS_FPREG(r_dest) || MIPS_FPREG(r_src))
166    return OpFpRegCopy(r_dest, r_src);
167  LIR* res = RawLIR(current_dalvik_offset_, kMipsMove,
168            r_dest, r_src);
169  if (!(cu_->disable_opt & (1 << kSafeOptimizations)) && r_dest == r_src) {
170    res->flags.is_nop = true;
171  }
172  return res;
173}
174
175LIR* MipsMir2Lir::OpRegCopy(int r_dest, int r_src) {
176  LIR *res = OpRegCopyNoInsert(r_dest, r_src);
177  AppendLIR(res);
178  return res;
179}
180
181void MipsMir2Lir::OpRegCopyWide(int dest_lo, int dest_hi, int src_lo,
182                                int src_hi) {
183  bool dest_fp = MIPS_FPREG(dest_lo) && MIPS_FPREG(dest_hi);
184  bool src_fp = MIPS_FPREG(src_lo) && MIPS_FPREG(src_hi);
185  assert(MIPS_FPREG(src_lo) == MIPS_FPREG(src_hi));
186  assert(MIPS_FPREG(dest_lo) == MIPS_FPREG(dest_hi));
187  if (dest_fp) {
188    if (src_fp) {
189      OpRegCopy(S2d(dest_lo, dest_hi), S2d(src_lo, src_hi));
190    } else {
191       /* note the operands are swapped for the mtc1 instr */
192      NewLIR2(kMipsMtc1, src_lo, dest_lo);
193      NewLIR2(kMipsMtc1, src_hi, dest_hi);
194    }
195  } else {
196    if (src_fp) {
197      NewLIR2(kMipsMfc1, dest_lo, src_lo);
198      NewLIR2(kMipsMfc1, dest_hi, src_hi);
199    } else {
200      // Handle overlap
201      if (src_hi == dest_lo) {
202        OpRegCopy(dest_hi, src_hi);
203        OpRegCopy(dest_lo, src_lo);
204      } else {
205        OpRegCopy(dest_lo, src_lo);
206        OpRegCopy(dest_hi, src_hi);
207      }
208    }
209  }
210}
211
212void MipsMir2Lir::GenSelect(BasicBlock* bb, MIR* mir) {
213  UNIMPLEMENTED(FATAL) << "Need codegen for select";
214}
215
216void MipsMir2Lir::GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir) {
217  UNIMPLEMENTED(FATAL) << "Need codegen for fused long cmp branch";
218}
219
220LIR* MipsMir2Lir::GenRegMemCheck(ConditionCode c_code,
221                    int reg1, int base, int offset, ThrowKind kind) {
222  LOG(FATAL) << "Unexpected use of GenRegMemCheck for Arm";
223  return NULL;
224}
225
226RegLocation MipsMir2Lir::GenDivRem(RegLocation rl_dest, int reg1, int reg2,
227                                    bool is_div) {
228  NewLIR4(kMipsDiv, r_HI, r_LO, reg1, reg2);
229  RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
230  if (is_div) {
231    NewLIR2(kMipsMflo, rl_result.low_reg, r_LO);
232  } else {
233    NewLIR2(kMipsMfhi, rl_result.low_reg, r_HI);
234  }
235  return rl_result;
236}
237
238RegLocation MipsMir2Lir::GenDivRemLit(RegLocation rl_dest, int reg1, int lit,
239                                       bool is_div) {
240  int t_reg = AllocTemp();
241  NewLIR3(kMipsAddiu, t_reg, r_ZERO, lit);
242  NewLIR4(kMipsDiv, r_HI, r_LO, reg1, t_reg);
243  RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
244  if (is_div) {
245    NewLIR2(kMipsMflo, rl_result.low_reg, r_LO);
246  } else {
247    NewLIR2(kMipsMfhi, rl_result.low_reg, r_HI);
248  }
249  FreeTemp(t_reg);
250  return rl_result;
251}
252
253void MipsMir2Lir::OpLea(int rBase, int reg1, int reg2, int scale, int offset) {
254  LOG(FATAL) << "Unexpected use of OpLea for Arm";
255}
256
257void MipsMir2Lir::OpTlsCmp(ThreadOffset offset, int val) {
258  LOG(FATAL) << "Unexpected use of OpTlsCmp for Arm";
259}
260
261bool MipsMir2Lir::GenInlinedCas32(CallInfo* info, bool need_write_barrier) {
262  DCHECK_NE(cu_->instruction_set, kThumb2);
263  return false;
264}
265
266bool MipsMir2Lir::GenInlinedSqrt(CallInfo* info) {
267  DCHECK_NE(cu_->instruction_set, kThumb2);
268  return false;
269}
270
271LIR* MipsMir2Lir::OpPcRelLoad(int reg, LIR* target) {
272  LOG(FATAL) << "Unexpected use of OpPcRelLoad for Mips";
273  return NULL;
274}
275
276LIR* MipsMir2Lir::OpVldm(int rBase, int count) {
277  LOG(FATAL) << "Unexpected use of OpVldm for Mips";
278  return NULL;
279}
280
281LIR* MipsMir2Lir::OpVstm(int rBase, int count) {
282  LOG(FATAL) << "Unexpected use of OpVstm for Mips";
283  return NULL;
284}
285
286void MipsMir2Lir::GenMultiplyByTwoBitMultiplier(RegLocation rl_src,
287                                                RegLocation rl_result, int lit,
288                                                int first_bit, int second_bit) {
289  int t_reg = AllocTemp();
290  OpRegRegImm(kOpLsl, t_reg, rl_src.low_reg, second_bit - first_bit);
291  OpRegRegReg(kOpAdd, rl_result.low_reg, rl_src.low_reg, t_reg);
292  FreeTemp(t_reg);
293  if (first_bit != 0) {
294    OpRegRegImm(kOpLsl, rl_result.low_reg, rl_result.low_reg, first_bit);
295  }
296}
297
298void MipsMir2Lir::GenDivZeroCheck(int reg_lo, int reg_hi) {
299  int t_reg = AllocTemp();
300  OpRegRegReg(kOpOr, t_reg, reg_lo, reg_hi);
301  GenImmedCheck(kCondEq, t_reg, 0, kThrowDivZero);
302  FreeTemp(t_reg);
303}
304
305// Test suspend flag, return target of taken suspend branch
306LIR* MipsMir2Lir::OpTestSuspend(LIR* target) {
307  OpRegImm(kOpSub, rMIPS_SUSPEND, 1);
308  return OpCmpImmBranch((target == NULL) ? kCondEq : kCondNe, rMIPS_SUSPEND, 0, target);
309}
310
311// Decrement register and branch on condition
312LIR* MipsMir2Lir::OpDecAndBranch(ConditionCode c_code, int reg, LIR* target) {
313  OpRegImm(kOpSub, reg, 1);
314  return OpCmpImmBranch(c_code, reg, 0, target);
315}
316
317bool MipsMir2Lir::SmallLiteralDivRem(Instruction::Code dalvik_opcode, bool is_div,
318                                     RegLocation rl_src, RegLocation rl_dest, int lit) {
319  LOG(FATAL) << "Unexpected use of smallLiteralDive in Mips";
320  return false;
321}
322
323LIR* MipsMir2Lir::OpIT(ConditionCode cond, const char* guide) {
324  LOG(FATAL) << "Unexpected use of OpIT in Mips";
325  return NULL;
326}
327
328void MipsMir2Lir::GenMulLong(RegLocation rl_dest, RegLocation rl_src1,
329                             RegLocation rl_src2) {
330  LOG(FATAL) << "Unexpected use of GenMulLong for Mips";
331}
332
333void MipsMir2Lir::GenAddLong(RegLocation rl_dest, RegLocation rl_src1,
334                             RegLocation rl_src2) {
335  rl_src1 = LoadValueWide(rl_src1, kCoreReg);
336  rl_src2 = LoadValueWide(rl_src2, kCoreReg);
337  RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
338  /*
339   *  [v1 v0] =  [a1 a0] + [a3 a2];
340   *  addu v0,a2,a0
341   *  addu t1,a3,a1
342   *  sltu v1,v0,a2
343   *  addu v1,v1,t1
344   */
345
346  OpRegRegReg(kOpAdd, rl_result.low_reg, rl_src2.low_reg, rl_src1.low_reg);
347  int t_reg = AllocTemp();
348  OpRegRegReg(kOpAdd, t_reg, rl_src2.high_reg, rl_src1.high_reg);
349  NewLIR3(kMipsSltu, rl_result.high_reg, rl_result.low_reg, rl_src2.low_reg);
350  OpRegRegReg(kOpAdd, rl_result.high_reg, rl_result.high_reg, t_reg);
351  FreeTemp(t_reg);
352  StoreValueWide(rl_dest, rl_result);
353}
354
355void MipsMir2Lir::GenSubLong(RegLocation rl_dest, RegLocation rl_src1,
356                             RegLocation rl_src2) {
357  rl_src1 = LoadValueWide(rl_src1, kCoreReg);
358  rl_src2 = LoadValueWide(rl_src2, kCoreReg);
359  RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
360  /*
361   *  [v1 v0] =  [a1 a0] - [a3 a2];
362   *  sltu  t1,a0,a2
363   *  subu  v0,a0,a2
364   *  subu  v1,a1,a3
365   *  subu  v1,v1,t1
366   */
367
368  int t_reg = AllocTemp();
369  NewLIR3(kMipsSltu, t_reg, rl_src1.low_reg, rl_src2.low_reg);
370  OpRegRegReg(kOpSub, rl_result.low_reg, rl_src1.low_reg, rl_src2.low_reg);
371  OpRegRegReg(kOpSub, rl_result.high_reg, rl_src1.high_reg, rl_src2.high_reg);
372  OpRegRegReg(kOpSub, rl_result.high_reg, rl_result.high_reg, t_reg);
373  FreeTemp(t_reg);
374  StoreValueWide(rl_dest, rl_result);
375}
376
377void MipsMir2Lir::GenNegLong(RegLocation rl_dest, RegLocation rl_src) {
378  rl_src = LoadValueWide(rl_src, kCoreReg);
379  RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
380  /*
381   *  [v1 v0] =  -[a1 a0]
382   *  negu  v0,a0
383   *  negu  v1,a1
384   *  sltu  t1,r_zero
385   *  subu  v1,v1,t1
386   */
387
388  OpRegReg(kOpNeg, rl_result.low_reg, rl_src.low_reg);
389  OpRegReg(kOpNeg, rl_result.high_reg, rl_src.high_reg);
390  int t_reg = AllocTemp();
391  NewLIR3(kMipsSltu, t_reg, r_ZERO, rl_result.low_reg);
392  OpRegRegReg(kOpSub, rl_result.high_reg, rl_result.high_reg, t_reg);
393  FreeTemp(t_reg);
394  StoreValueWide(rl_dest, rl_result);
395}
396
397void MipsMir2Lir::GenAndLong(RegLocation rl_dest, RegLocation rl_src1,
398                             RegLocation rl_src2) {
399  LOG(FATAL) << "Unexpected use of GenAndLong for Mips";
400}
401
402void MipsMir2Lir::GenOrLong(RegLocation rl_dest, RegLocation rl_src1,
403                            RegLocation rl_src2) {
404  LOG(FATAL) << "Unexpected use of GenOrLong for Mips";
405}
406
407void MipsMir2Lir::GenXorLong(RegLocation rl_dest, RegLocation rl_src1,
408                             RegLocation rl_src2) {
409  LOG(FATAL) << "Unexpected use of GenXorLong for Mips";
410}
411
412/*
413 * Generate array load
414 */
415void MipsMir2Lir::GenArrayGet(int opt_flags, OpSize size, RegLocation rl_array,
416                          RegLocation rl_index, RegLocation rl_dest, int scale) {
417  RegisterClass reg_class = oat_reg_class_by_size(size);
418  int len_offset = mirror::Array::LengthOffset().Int32Value();
419  int data_offset;
420  RegLocation rl_result;
421  rl_array = LoadValue(rl_array, kCoreReg);
422  rl_index = LoadValue(rl_index, kCoreReg);
423
424  if (size == kLong || size == kDouble) {
425    data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Int32Value();
426  } else {
427    data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Int32Value();
428  }
429
430  /* null object? */
431  GenNullCheck(rl_array.s_reg_low, rl_array.low_reg, opt_flags);
432
433  int reg_ptr = AllocTemp();
434  bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK));
435  int reg_len = INVALID_REG;
436  if (needs_range_check) {
437    reg_len = AllocTemp();
438    /* Get len */
439    LoadWordDisp(rl_array.low_reg, len_offset, reg_len);
440  }
441  /* reg_ptr -> array data */
442  OpRegRegImm(kOpAdd, reg_ptr, rl_array.low_reg, data_offset);
443  FreeTemp(rl_array.low_reg);
444  if ((size == kLong) || (size == kDouble)) {
445    if (scale) {
446      int r_new_index = AllocTemp();
447      OpRegRegImm(kOpLsl, r_new_index, rl_index.low_reg, scale);
448      OpRegReg(kOpAdd, reg_ptr, r_new_index);
449      FreeTemp(r_new_index);
450    } else {
451      OpRegReg(kOpAdd, reg_ptr, rl_index.low_reg);
452    }
453    FreeTemp(rl_index.low_reg);
454    rl_result = EvalLoc(rl_dest, reg_class, true);
455
456    if (needs_range_check) {
457      // TODO: change kCondCS to a more meaningful name, is the sense of
458      // carry-set/clear flipped?
459      GenRegRegCheck(kCondCs, rl_index.low_reg, reg_len, kThrowArrayBounds);
460      FreeTemp(reg_len);
461    }
462    LoadBaseDispWide(reg_ptr, 0, rl_result.low_reg, rl_result.high_reg, INVALID_SREG);
463
464    FreeTemp(reg_ptr);
465    StoreValueWide(rl_dest, rl_result);
466  } else {
467    rl_result = EvalLoc(rl_dest, reg_class, true);
468
469    if (needs_range_check) {
470      // TODO: change kCondCS to a more meaningful name, is the sense of
471      // carry-set/clear flipped?
472      GenRegRegCheck(kCondCs, rl_index.low_reg, reg_len, kThrowArrayBounds);
473      FreeTemp(reg_len);
474    }
475    LoadBaseIndexed(reg_ptr, rl_index.low_reg, rl_result.low_reg, scale, size);
476
477    FreeTemp(reg_ptr);
478    StoreValue(rl_dest, rl_result);
479  }
480}
481
482/*
483 * Generate array store
484 *
485 */
486void MipsMir2Lir::GenArrayPut(int opt_flags, OpSize size, RegLocation rl_array,
487                          RegLocation rl_index, RegLocation rl_src, int scale, bool card_mark) {
488  RegisterClass reg_class = oat_reg_class_by_size(size);
489  int len_offset = mirror::Array::LengthOffset().Int32Value();
490  int data_offset;
491
492  if (size == kLong || size == kDouble) {
493    data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Int32Value();
494  } else {
495    data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Int32Value();
496  }
497
498  rl_array = LoadValue(rl_array, kCoreReg);
499  rl_index = LoadValue(rl_index, kCoreReg);
500  int reg_ptr = INVALID_REG;
501  if (IsTemp(rl_array.low_reg)) {
502    Clobber(rl_array.low_reg);
503    reg_ptr = rl_array.low_reg;
504  } else {
505    reg_ptr = AllocTemp();
506    OpRegCopy(reg_ptr, rl_array.low_reg);
507  }
508
509  /* null object? */
510  GenNullCheck(rl_array.s_reg_low, rl_array.low_reg, opt_flags);
511
512  bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK));
513  int reg_len = INVALID_REG;
514  if (needs_range_check) {
515    reg_len = AllocTemp();
516    // NOTE: max live temps(4) here.
517    /* Get len */
518    LoadWordDisp(rl_array.low_reg, len_offset, reg_len);
519  }
520  /* reg_ptr -> array data */
521  OpRegImm(kOpAdd, reg_ptr, data_offset);
522  /* at this point, reg_ptr points to array, 2 live temps */
523  if ((size == kLong) || (size == kDouble)) {
524    // TUNING: specific wide routine that can handle fp regs
525    if (scale) {
526      int r_new_index = AllocTemp();
527      OpRegRegImm(kOpLsl, r_new_index, rl_index.low_reg, scale);
528      OpRegReg(kOpAdd, reg_ptr, r_new_index);
529      FreeTemp(r_new_index);
530    } else {
531      OpRegReg(kOpAdd, reg_ptr, rl_index.low_reg);
532    }
533    rl_src = LoadValueWide(rl_src, reg_class);
534
535    if (needs_range_check) {
536      GenRegRegCheck(kCondCs, rl_index.low_reg, reg_len, kThrowArrayBounds);
537      FreeTemp(reg_len);
538    }
539
540    StoreBaseDispWide(reg_ptr, 0, rl_src.low_reg, rl_src.high_reg);
541
542    FreeTemp(reg_ptr);
543  } else {
544    rl_src = LoadValue(rl_src, reg_class);
545    if (needs_range_check) {
546      GenRegRegCheck(kCondCs, rl_index.low_reg, reg_len, kThrowArrayBounds);
547      FreeTemp(reg_len);
548    }
549    StoreBaseIndexed(reg_ptr, rl_index.low_reg, rl_src.low_reg,
550                     scale, size);
551  }
552  if (card_mark) {
553    MarkGCCard(rl_src.low_reg, rl_array.low_reg);
554  }
555}
556
557void MipsMir2Lir::GenShiftImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
558                                    RegLocation rl_src1, RegLocation rl_shift) {
559  // Default implementation is just to ignore the constant case.
560  GenShiftOpLong(opcode, rl_dest, rl_src1, rl_shift);
561}
562
563void MipsMir2Lir::GenArithImmOpLong(Instruction::Code opcode,
564                                    RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2) {
565  // Default - bail to non-const handler.
566  GenArithOpLong(opcode, rl_dest, rl_src1, rl_src2);
567}
568
569}  // namespace art
570