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#include "dex/compiler_ir.h"
18#include "dex/compiler_internals.h"
19#include "dex/quick/arm/arm_lir.h"
20#include "dex/quick/mir_to_lir-inl.h"
21#include "entrypoints/quick/quick_entrypoints.h"
22#include "mirror/array.h"
23#include "verifier/method_verifier.h"
24
25namespace art {
26
27/*
28 * This source files contains "gen" codegen routines that should
29 * be applicable to most targets.  Only mid-level support utilities
30 * and "op" calls may be used here.
31 */
32
33/*
34 * Generate an kPseudoBarrier marker to indicate the boundary of special
35 * blocks.
36 */
37void Mir2Lir::GenBarrier() {
38  LIR* barrier = NewLIR0(kPseudoBarrier);
39  /* Mark all resources as being clobbered */
40  barrier->def_mask = -1;
41}
42
43// FIXME: need to do some work to split out targets with
44// condition codes and those without
45LIR* Mir2Lir::GenCheck(ConditionCode c_code, ThrowKind kind) {
46  DCHECK_NE(cu_->instruction_set, kMips);
47  LIR* tgt = RawLIR(0, kPseudoThrowTarget, kind, current_dalvik_offset_);
48  LIR* branch = OpCondBranch(c_code, tgt);
49  // Remember branch target - will process later
50  throw_launchpads_.Insert(tgt);
51  return branch;
52}
53
54LIR* Mir2Lir::GenImmedCheck(ConditionCode c_code, int reg, int imm_val, ThrowKind kind) {
55  LIR* tgt = RawLIR(0, kPseudoThrowTarget, kind, current_dalvik_offset_, reg, imm_val);
56  LIR* branch;
57  if (c_code == kCondAl) {
58    branch = OpUnconditionalBranch(tgt);
59  } else {
60    branch = OpCmpImmBranch(c_code, reg, imm_val, tgt);
61  }
62  // Remember branch target - will process later
63  throw_launchpads_.Insert(tgt);
64  return branch;
65}
66
67/* Perform null-check on a register.  */
68LIR* Mir2Lir::GenNullCheck(int s_reg, int m_reg, int opt_flags) {
69  if (!(cu_->disable_opt & (1 << kNullCheckElimination)) &&
70    opt_flags & MIR_IGNORE_NULL_CHECK) {
71    return NULL;
72  }
73  return GenImmedCheck(kCondEq, m_reg, 0, kThrowNullPointer);
74}
75
76/* Perform check on two registers */
77LIR* Mir2Lir::GenRegRegCheck(ConditionCode c_code, int reg1, int reg2,
78                             ThrowKind kind) {
79  LIR* tgt = RawLIR(0, kPseudoThrowTarget, kind, current_dalvik_offset_, reg1, reg2);
80  LIR* branch = OpCmpBranch(c_code, reg1, reg2, tgt);
81  // Remember branch target - will process later
82  throw_launchpads_.Insert(tgt);
83  return branch;
84}
85
86void Mir2Lir::GenCompareAndBranch(Instruction::Code opcode, RegLocation rl_src1,
87                                  RegLocation rl_src2, LIR* taken,
88                                  LIR* fall_through) {
89  ConditionCode cond;
90  switch (opcode) {
91    case Instruction::IF_EQ:
92      cond = kCondEq;
93      break;
94    case Instruction::IF_NE:
95      cond = kCondNe;
96      break;
97    case Instruction::IF_LT:
98      cond = kCondLt;
99      break;
100    case Instruction::IF_GE:
101      cond = kCondGe;
102      break;
103    case Instruction::IF_GT:
104      cond = kCondGt;
105      break;
106    case Instruction::IF_LE:
107      cond = kCondLe;
108      break;
109    default:
110      cond = static_cast<ConditionCode>(0);
111      LOG(FATAL) << "Unexpected opcode " << opcode;
112  }
113
114  // Normalize such that if either operand is constant, src2 will be constant
115  if (rl_src1.is_const) {
116    RegLocation rl_temp = rl_src1;
117    rl_src1 = rl_src2;
118    rl_src2 = rl_temp;
119    cond = FlipComparisonOrder(cond);
120  }
121
122  rl_src1 = LoadValue(rl_src1, kCoreReg);
123  // Is this really an immediate comparison?
124  if (rl_src2.is_const) {
125    // If it's already live in a register or not easily materialized, just keep going
126    RegLocation rl_temp = UpdateLoc(rl_src2);
127    if ((rl_temp.location == kLocDalvikFrame) &&
128        InexpensiveConstantInt(mir_graph_->ConstantValue(rl_src2))) {
129      // OK - convert this to a compare immediate and branch
130      OpCmpImmBranch(cond, rl_src1.low_reg, mir_graph_->ConstantValue(rl_src2), taken);
131      OpUnconditionalBranch(fall_through);
132      return;
133    }
134  }
135  rl_src2 = LoadValue(rl_src2, kCoreReg);
136  OpCmpBranch(cond, rl_src1.low_reg, rl_src2.low_reg, taken);
137  OpUnconditionalBranch(fall_through);
138}
139
140void Mir2Lir::GenCompareZeroAndBranch(Instruction::Code opcode, RegLocation rl_src, LIR* taken,
141                                      LIR* fall_through) {
142  ConditionCode cond;
143  rl_src = LoadValue(rl_src, kCoreReg);
144  switch (opcode) {
145    case Instruction::IF_EQZ:
146      cond = kCondEq;
147      break;
148    case Instruction::IF_NEZ:
149      cond = kCondNe;
150      break;
151    case Instruction::IF_LTZ:
152      cond = kCondLt;
153      break;
154    case Instruction::IF_GEZ:
155      cond = kCondGe;
156      break;
157    case Instruction::IF_GTZ:
158      cond = kCondGt;
159      break;
160    case Instruction::IF_LEZ:
161      cond = kCondLe;
162      break;
163    default:
164      cond = static_cast<ConditionCode>(0);
165      LOG(FATAL) << "Unexpected opcode " << opcode;
166  }
167  OpCmpImmBranch(cond, rl_src.low_reg, 0, taken);
168  OpUnconditionalBranch(fall_through);
169}
170
171void Mir2Lir::GenIntToLong(RegLocation rl_dest, RegLocation rl_src) {
172  RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
173  if (rl_src.location == kLocPhysReg) {
174    OpRegCopy(rl_result.low_reg, rl_src.low_reg);
175  } else {
176    LoadValueDirect(rl_src, rl_result.low_reg);
177  }
178  OpRegRegImm(kOpAsr, rl_result.high_reg, rl_result.low_reg, 31);
179  StoreValueWide(rl_dest, rl_result);
180}
181
182void Mir2Lir::GenIntNarrowing(Instruction::Code opcode, RegLocation rl_dest,
183                              RegLocation rl_src) {
184  rl_src = LoadValue(rl_src, kCoreReg);
185  RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
186  OpKind op = kOpInvalid;
187  switch (opcode) {
188    case Instruction::INT_TO_BYTE:
189      op = kOp2Byte;
190      break;
191    case Instruction::INT_TO_SHORT:
192       op = kOp2Short;
193       break;
194    case Instruction::INT_TO_CHAR:
195       op = kOp2Char;
196       break;
197    default:
198      LOG(ERROR) << "Bad int conversion type";
199  }
200  OpRegReg(op, rl_result.low_reg, rl_src.low_reg);
201  StoreValue(rl_dest, rl_result);
202}
203
204/*
205 * Let helper function take care of everything.  Will call
206 * Array::AllocFromCode(type_idx, method, count);
207 * Note: AllocFromCode will handle checks for errNegativeArraySize.
208 */
209void Mir2Lir::GenNewArray(uint32_t type_idx, RegLocation rl_dest,
210                          RegLocation rl_src) {
211  FlushAllRegs();  /* Everything to home location */
212  ThreadOffset func_offset(-1);
213  if (cu_->compiler_driver->CanAccessTypeWithoutChecks(cu_->method_idx, *cu_->dex_file,
214                                                       type_idx)) {
215    func_offset = QUICK_ENTRYPOINT_OFFSET(pAllocArray);
216  } else {
217    func_offset= QUICK_ENTRYPOINT_OFFSET(pAllocArrayWithAccessCheck);
218  }
219  CallRuntimeHelperImmMethodRegLocation(func_offset, type_idx, rl_src, true);
220  RegLocation rl_result = GetReturn(false);
221  StoreValue(rl_dest, rl_result);
222}
223
224/*
225 * Similar to GenNewArray, but with post-allocation initialization.
226 * Verifier guarantees we're dealing with an array class.  Current
227 * code throws runtime exception "bad Filled array req" for 'D' and 'J'.
228 * Current code also throws internal unimp if not 'L', '[' or 'I'.
229 */
230void Mir2Lir::GenFilledNewArray(CallInfo* info) {
231  int elems = info->num_arg_words;
232  int type_idx = info->index;
233  FlushAllRegs();  /* Everything to home location */
234  ThreadOffset func_offset(-1);
235  if (cu_->compiler_driver->CanAccessTypeWithoutChecks(cu_->method_idx, *cu_->dex_file,
236                                                       type_idx)) {
237    func_offset = QUICK_ENTRYPOINT_OFFSET(pCheckAndAllocArray);
238  } else {
239    func_offset = QUICK_ENTRYPOINT_OFFSET(pCheckAndAllocArrayWithAccessCheck);
240  }
241  CallRuntimeHelperImmMethodImm(func_offset, type_idx, elems, true);
242  FreeTemp(TargetReg(kArg2));
243  FreeTemp(TargetReg(kArg1));
244  /*
245   * NOTE: the implicit target for Instruction::FILLED_NEW_ARRAY is the
246   * return region.  Because AllocFromCode placed the new array
247   * in kRet0, we'll just lock it into place.  When debugger support is
248   * added, it may be necessary to additionally copy all return
249   * values to a home location in thread-local storage
250   */
251  LockTemp(TargetReg(kRet0));
252
253  // TODO: use the correct component size, currently all supported types
254  // share array alignment with ints (see comment at head of function)
255  size_t component_size = sizeof(int32_t);
256
257  // Having a range of 0 is legal
258  if (info->is_range && (elems > 0)) {
259    /*
260     * Bit of ugliness here.  We're going generate a mem copy loop
261     * on the register range, but it is possible that some regs
262     * in the range have been promoted.  This is unlikely, but
263     * before generating the copy, we'll just force a flush
264     * of any regs in the source range that have been promoted to
265     * home location.
266     */
267    for (int i = 0; i < elems; i++) {
268      RegLocation loc = UpdateLoc(info->args[i]);
269      if (loc.location == kLocPhysReg) {
270        StoreBaseDisp(TargetReg(kSp), SRegOffset(loc.s_reg_low),
271                      loc.low_reg, kWord);
272      }
273    }
274    /*
275     * TUNING note: generated code here could be much improved, but
276     * this is an uncommon operation and isn't especially performance
277     * critical.
278     */
279    int r_src = AllocTemp();
280    int r_dst = AllocTemp();
281    int r_idx = AllocTemp();
282    int r_val = INVALID_REG;
283    switch (cu_->instruction_set) {
284      case kThumb2:
285        r_val = TargetReg(kLr);
286        break;
287      case kX86:
288        FreeTemp(TargetReg(kRet0));
289        r_val = AllocTemp();
290        break;
291      case kMips:
292        r_val = AllocTemp();
293        break;
294      default: LOG(FATAL) << "Unexpected instruction set: " << cu_->instruction_set;
295    }
296    // Set up source pointer
297    RegLocation rl_first = info->args[0];
298    OpRegRegImm(kOpAdd, r_src, TargetReg(kSp), SRegOffset(rl_first.s_reg_low));
299    // Set up the target pointer
300    OpRegRegImm(kOpAdd, r_dst, TargetReg(kRet0),
301                mirror::Array::DataOffset(component_size).Int32Value());
302    // Set up the loop counter (known to be > 0)
303    LoadConstant(r_idx, elems - 1);
304    // Generate the copy loop.  Going backwards for convenience
305    LIR* target = NewLIR0(kPseudoTargetLabel);
306    // Copy next element
307    LoadBaseIndexed(r_src, r_idx, r_val, 2, kWord);
308    StoreBaseIndexed(r_dst, r_idx, r_val, 2, kWord);
309    FreeTemp(r_val);
310    OpDecAndBranch(kCondGe, r_idx, target);
311    if (cu_->instruction_set == kX86) {
312      // Restore the target pointer
313      OpRegRegImm(kOpAdd, TargetReg(kRet0), r_dst,
314                  -mirror::Array::DataOffset(component_size).Int32Value());
315    }
316  } else if (!info->is_range) {
317    // TUNING: interleave
318    for (int i = 0; i < elems; i++) {
319      RegLocation rl_arg = LoadValue(info->args[i], kCoreReg);
320      StoreBaseDisp(TargetReg(kRet0),
321                    mirror::Array::DataOffset(component_size).Int32Value() +
322                    i * 4, rl_arg.low_reg, kWord);
323      // If the LoadValue caused a temp to be allocated, free it
324      if (IsTemp(rl_arg.low_reg)) {
325        FreeTemp(rl_arg.low_reg);
326      }
327    }
328  }
329  if (info->result.location != kLocInvalid) {
330    StoreValue(info->result, GetReturn(false /* not fp */));
331  }
332}
333
334void Mir2Lir::GenSput(uint32_t field_idx, RegLocation rl_src, bool is_long_or_double,
335                      bool is_object) {
336  int field_offset;
337  int ssb_index;
338  bool is_volatile;
339  bool is_referrers_class;
340  bool fast_path = cu_->compiler_driver->ComputeStaticFieldInfo(
341      field_idx, mir_graph_->GetCurrentDexCompilationUnit(), field_offset, ssb_index,
342      is_referrers_class, is_volatile, true);
343  if (fast_path && !SLOW_FIELD_PATH) {
344    DCHECK_GE(field_offset, 0);
345    int rBase;
346    if (is_referrers_class) {
347      // Fast path, static storage base is this method's class
348      RegLocation rl_method  = LoadCurrMethod();
349      rBase = AllocTemp();
350      LoadWordDisp(rl_method.low_reg,
351                   mirror::ArtMethod::DeclaringClassOffset().Int32Value(), rBase);
352      if (IsTemp(rl_method.low_reg)) {
353        FreeTemp(rl_method.low_reg);
354      }
355    } else {
356      // Medium path, static storage base in a different class which requires checks that the other
357      // class is initialized.
358      // TODO: remove initialized check now that we are initializing classes in the compiler driver.
359      DCHECK_GE(ssb_index, 0);
360      // May do runtime call so everything to home locations.
361      FlushAllRegs();
362      // Using fixed register to sync with possible call to runtime support.
363      int r_method = TargetReg(kArg1);
364      LockTemp(r_method);
365      LoadCurrMethodDirect(r_method);
366      rBase = TargetReg(kArg0);
367      LockTemp(rBase);
368      LoadWordDisp(r_method,
369                   mirror::ArtMethod::DexCacheInitializedStaticStorageOffset().Int32Value(),
370                   rBase);
371      LoadWordDisp(rBase,
372                   mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value() +
373                   sizeof(int32_t*) * ssb_index, rBase);
374      // rBase now points at appropriate static storage base (Class*)
375      // or NULL if not initialized. Check for NULL and call helper if NULL.
376      // TUNING: fast path should fall through
377      LIR* branch_over = OpCmpImmBranch(kCondNe, rBase, 0, NULL);
378      LoadConstant(TargetReg(kArg0), ssb_index);
379      CallRuntimeHelperImm(QUICK_ENTRYPOINT_OFFSET(pInitializeStaticStorage), ssb_index, true);
380      if (cu_->instruction_set == kMips) {
381        // For Arm, kRet0 = kArg0 = rBase, for Mips, we need to copy
382        OpRegCopy(rBase, TargetReg(kRet0));
383      }
384      LIR* skip_target = NewLIR0(kPseudoTargetLabel);
385      branch_over->target = skip_target;
386      FreeTemp(r_method);
387    }
388    // rBase now holds static storage base
389    if (is_long_or_double) {
390      rl_src = LoadValueWide(rl_src, kAnyReg);
391    } else {
392      rl_src = LoadValue(rl_src, kAnyReg);
393    }
394    if (is_volatile) {
395      GenMemBarrier(kStoreStore);
396    }
397    if (is_long_or_double) {
398      StoreBaseDispWide(rBase, field_offset, rl_src.low_reg,
399                        rl_src.high_reg);
400    } else {
401      StoreWordDisp(rBase, field_offset, rl_src.low_reg);
402    }
403    if (is_volatile) {
404      GenMemBarrier(kStoreLoad);
405    }
406    if (is_object && !mir_graph_->IsConstantNullRef(rl_src)) {
407      MarkGCCard(rl_src.low_reg, rBase);
408    }
409    FreeTemp(rBase);
410  } else {
411    FlushAllRegs();  // Everything to home locations
412    ThreadOffset setter_offset =
413        is_long_or_double ? QUICK_ENTRYPOINT_OFFSET(pSet64Static)
414                          : (is_object ? QUICK_ENTRYPOINT_OFFSET(pSetObjStatic)
415                                       : QUICK_ENTRYPOINT_OFFSET(pSet32Static));
416    CallRuntimeHelperImmRegLocation(setter_offset, field_idx, rl_src, true);
417  }
418}
419
420void Mir2Lir::GenSget(uint32_t field_idx, RegLocation rl_dest,
421                      bool is_long_or_double, bool is_object) {
422  int field_offset;
423  int ssb_index;
424  bool is_volatile;
425  bool is_referrers_class;
426  bool fast_path = cu_->compiler_driver->ComputeStaticFieldInfo(
427      field_idx, mir_graph_->GetCurrentDexCompilationUnit(), field_offset, ssb_index,
428      is_referrers_class, is_volatile, false);
429  if (fast_path && !SLOW_FIELD_PATH) {
430    DCHECK_GE(field_offset, 0);
431    int rBase;
432    if (is_referrers_class) {
433      // Fast path, static storage base is this method's class
434      RegLocation rl_method  = LoadCurrMethod();
435      rBase = AllocTemp();
436      LoadWordDisp(rl_method.low_reg,
437                   mirror::ArtMethod::DeclaringClassOffset().Int32Value(), rBase);
438    } else {
439      // Medium path, static storage base in a different class which requires checks that the other
440      // class is initialized
441      // TODO: remove initialized check now that we are initializing classes in the compiler driver.
442      DCHECK_GE(ssb_index, 0);
443      // May do runtime call so everything to home locations.
444      FlushAllRegs();
445      // Using fixed register to sync with possible call to runtime support.
446      int r_method = TargetReg(kArg1);
447      LockTemp(r_method);
448      LoadCurrMethodDirect(r_method);
449      rBase = TargetReg(kArg0);
450      LockTemp(rBase);
451      LoadWordDisp(r_method,
452                   mirror::ArtMethod::DexCacheInitializedStaticStorageOffset().Int32Value(),
453                   rBase);
454      LoadWordDisp(rBase, mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value() +
455                   sizeof(int32_t*) * ssb_index, rBase);
456      // rBase now points at appropriate static storage base (Class*)
457      // or NULL if not initialized. Check for NULL and call helper if NULL.
458      // TUNING: fast path should fall through
459      LIR* branch_over = OpCmpImmBranch(kCondNe, rBase, 0, NULL);
460      CallRuntimeHelperImm(QUICK_ENTRYPOINT_OFFSET(pInitializeStaticStorage), ssb_index, true);
461      if (cu_->instruction_set == kMips) {
462        // For Arm, kRet0 = kArg0 = rBase, for Mips, we need to copy
463        OpRegCopy(rBase, TargetReg(kRet0));
464      }
465      LIR* skip_target = NewLIR0(kPseudoTargetLabel);
466      branch_over->target = skip_target;
467      FreeTemp(r_method);
468    }
469    // rBase now holds static storage base
470    RegLocation rl_result = EvalLoc(rl_dest, kAnyReg, true);
471    if (is_volatile) {
472      GenMemBarrier(kLoadLoad);
473    }
474    if (is_long_or_double) {
475      LoadBaseDispWide(rBase, field_offset, rl_result.low_reg,
476                       rl_result.high_reg, INVALID_SREG);
477    } else {
478      LoadWordDisp(rBase, field_offset, rl_result.low_reg);
479    }
480    FreeTemp(rBase);
481    if (is_long_or_double) {
482      StoreValueWide(rl_dest, rl_result);
483    } else {
484      StoreValue(rl_dest, rl_result);
485    }
486  } else {
487    FlushAllRegs();  // Everything to home locations
488    ThreadOffset getterOffset =
489        is_long_or_double ? QUICK_ENTRYPOINT_OFFSET(pGet64Static)
490                          :(is_object ? QUICK_ENTRYPOINT_OFFSET(pGetObjStatic)
491                                      : QUICK_ENTRYPOINT_OFFSET(pGet32Static));
492    CallRuntimeHelperImm(getterOffset, field_idx, true);
493    if (is_long_or_double) {
494      RegLocation rl_result = GetReturnWide(rl_dest.fp);
495      StoreValueWide(rl_dest, rl_result);
496    } else {
497      RegLocation rl_result = GetReturn(rl_dest.fp);
498      StoreValue(rl_dest, rl_result);
499    }
500  }
501}
502
503void Mir2Lir::HandleSuspendLaunchPads() {
504  int num_elems = suspend_launchpads_.Size();
505  ThreadOffset helper_offset = QUICK_ENTRYPOINT_OFFSET(pTestSuspend);
506  for (int i = 0; i < num_elems; i++) {
507    ResetRegPool();
508    ResetDefTracking();
509    LIR* lab = suspend_launchpads_.Get(i);
510    LIR* resume_lab = reinterpret_cast<LIR*>(lab->operands[0]);
511    current_dalvik_offset_ = lab->operands[1];
512    AppendLIR(lab);
513    int r_tgt = CallHelperSetup(helper_offset);
514    CallHelper(r_tgt, helper_offset, true /* MarkSafepointPC */);
515    OpUnconditionalBranch(resume_lab);
516  }
517}
518
519void Mir2Lir::HandleIntrinsicLaunchPads() {
520  int num_elems = intrinsic_launchpads_.Size();
521  for (int i = 0; i < num_elems; i++) {
522    ResetRegPool();
523    ResetDefTracking();
524    LIR* lab = intrinsic_launchpads_.Get(i);
525    CallInfo* info = reinterpret_cast<CallInfo*>(lab->operands[0]);
526    current_dalvik_offset_ = info->offset;
527    AppendLIR(lab);
528    // NOTE: GenInvoke handles MarkSafepointPC
529    GenInvoke(info);
530    LIR* resume_lab = reinterpret_cast<LIR*>(lab->operands[2]);
531    if (resume_lab != NULL) {
532      OpUnconditionalBranch(resume_lab);
533    }
534  }
535}
536
537void Mir2Lir::HandleThrowLaunchPads() {
538  int num_elems = throw_launchpads_.Size();
539  for (int i = 0; i < num_elems; i++) {
540    ResetRegPool();
541    ResetDefTracking();
542    LIR* lab = throw_launchpads_.Get(i);
543    current_dalvik_offset_ = lab->operands[1];
544    AppendLIR(lab);
545    ThreadOffset func_offset(-1);
546    int v1 = lab->operands[2];
547    int v2 = lab->operands[3];
548    const bool target_x86 = cu_->instruction_set == kX86;
549    const bool target_arm = cu_->instruction_set == kArm || cu_->instruction_set == kThumb2;
550    const bool target_mips = cu_->instruction_set == kMips;
551    switch (lab->operands[0]) {
552      case kThrowNullPointer:
553        func_offset = QUICK_ENTRYPOINT_OFFSET(pThrowNullPointer);
554        break;
555      case kThrowConstantArrayBounds:  // v1 is length reg (for Arm/Mips), v2 constant index
556        // v1 holds the constant array index.  Mips/Arm uses v2 for length, x86 reloads.
557        if (target_x86) {
558          OpRegMem(kOpMov, TargetReg(kArg1), v1, mirror::Array::LengthOffset().Int32Value());
559        } else {
560          OpRegCopy(TargetReg(kArg1), v1);
561        }
562        // Make sure the following LoadConstant doesn't mess with kArg1.
563        LockTemp(TargetReg(kArg1));
564        LoadConstant(TargetReg(kArg0), v2);
565        func_offset = QUICK_ENTRYPOINT_OFFSET(pThrowArrayBounds);
566        break;
567      case kThrowArrayBounds:
568        // Move v1 (array index) to kArg0 and v2 (array length) to kArg1
569        if (v2 != TargetReg(kArg0)) {
570          OpRegCopy(TargetReg(kArg0), v1);
571          if (target_x86) {
572            // x86 leaves the array pointer in v2, so load the array length that the handler expects
573            OpRegMem(kOpMov, TargetReg(kArg1), v2, mirror::Array::LengthOffset().Int32Value());
574          } else {
575            OpRegCopy(TargetReg(kArg1), v2);
576          }
577        } else {
578          if (v1 == TargetReg(kArg1)) {
579            // Swap v1 and v2, using kArg2 as a temp
580            OpRegCopy(TargetReg(kArg2), v1);
581            if (target_x86) {
582              // x86 leaves the array pointer in v2; load the array length that the handler expects
583              OpRegMem(kOpMov, TargetReg(kArg1), v2, mirror::Array::LengthOffset().Int32Value());
584            } else {
585              OpRegCopy(TargetReg(kArg1), v2);
586            }
587            OpRegCopy(TargetReg(kArg0), TargetReg(kArg2));
588          } else {
589            if (target_x86) {
590              // x86 leaves the array pointer in v2; load the array length that the handler expects
591              OpRegMem(kOpMov, TargetReg(kArg1), v2, mirror::Array::LengthOffset().Int32Value());
592            } else {
593              OpRegCopy(TargetReg(kArg1), v2);
594            }
595            OpRegCopy(TargetReg(kArg0), v1);
596          }
597        }
598        func_offset = QUICK_ENTRYPOINT_OFFSET(pThrowArrayBounds);
599        break;
600      case kThrowDivZero:
601        func_offset = QUICK_ENTRYPOINT_OFFSET(pThrowDivZero);
602        break;
603      case kThrowNoSuchMethod:
604        OpRegCopy(TargetReg(kArg0), v1);
605        func_offset =
606          QUICK_ENTRYPOINT_OFFSET(pThrowNoSuchMethod);
607        break;
608      case kThrowStackOverflow: {
609        func_offset = QUICK_ENTRYPOINT_OFFSET(pThrowStackOverflow);
610        // Restore stack alignment
611        int r_tgt = 0;
612        const int spill_size = (num_core_spills_ + num_fp_spills_) * 4;
613        if (target_x86) {
614          // - 4 to leave link register on stack.
615          OpRegImm(kOpAdd, TargetReg(kSp), frame_size_ - 4);
616          ClobberCalleeSave();
617        } else if (target_arm) {
618          r_tgt = r12;
619          LoadWordDisp(TargetReg(kSp), spill_size - 4, TargetReg(kLr));
620          OpRegImm(kOpAdd, TargetReg(kSp), spill_size);
621          ClobberCalleeSave();
622          LoadWordDisp(rARM_SELF, func_offset.Int32Value(), r_tgt);
623        } else {
624          DCHECK(target_mips);
625          DCHECK_EQ(num_fp_spills_, 0);  // FP spills currently don't happen on mips.
626          // LR is offset 0 since we push in reverse order.
627          LoadWordDisp(TargetReg(kSp), 0, TargetReg(kLr));
628          OpRegImm(kOpAdd, TargetReg(kSp), spill_size);
629          ClobberCalleeSave();
630          r_tgt = CallHelperSetup(func_offset);  // Doesn't clobber LR.
631          DCHECK_NE(r_tgt, TargetReg(kLr));
632        }
633        CallHelper(r_tgt, func_offset, false /* MarkSafepointPC */, false /* UseLink */);
634        continue;
635      }
636      default:
637        LOG(FATAL) << "Unexpected throw kind: " << lab->operands[0];
638    }
639    ClobberCalleeSave();
640    int r_tgt = CallHelperSetup(func_offset);
641    CallHelper(r_tgt, func_offset, true /* MarkSafepointPC */, true /* UseLink */);
642  }
643}
644
645void Mir2Lir::GenIGet(uint32_t field_idx, int opt_flags, OpSize size,
646                      RegLocation rl_dest, RegLocation rl_obj, bool is_long_or_double,
647                      bool is_object) {
648  int field_offset;
649  bool is_volatile;
650
651  bool fast_path = FastInstance(field_idx, field_offset, is_volatile, false);
652
653  if (fast_path && !SLOW_FIELD_PATH) {
654    RegLocation rl_result;
655    RegisterClass reg_class = oat_reg_class_by_size(size);
656    DCHECK_GE(field_offset, 0);
657    rl_obj = LoadValue(rl_obj, kCoreReg);
658    if (is_long_or_double) {
659      DCHECK(rl_dest.wide);
660      GenNullCheck(rl_obj.s_reg_low, rl_obj.low_reg, opt_flags);
661      if (cu_->instruction_set == kX86) {
662        rl_result = EvalLoc(rl_dest, reg_class, true);
663        GenNullCheck(rl_obj.s_reg_low, rl_obj.low_reg, opt_flags);
664        LoadBaseDispWide(rl_obj.low_reg, field_offset, rl_result.low_reg,
665                         rl_result.high_reg, rl_obj.s_reg_low);
666        if (is_volatile) {
667          GenMemBarrier(kLoadLoad);
668        }
669      } else {
670        int reg_ptr = AllocTemp();
671        OpRegRegImm(kOpAdd, reg_ptr, rl_obj.low_reg, field_offset);
672        rl_result = EvalLoc(rl_dest, reg_class, true);
673        LoadBaseDispWide(reg_ptr, 0, rl_result.low_reg, rl_result.high_reg, INVALID_SREG);
674        if (is_volatile) {
675          GenMemBarrier(kLoadLoad);
676        }
677        FreeTemp(reg_ptr);
678      }
679      StoreValueWide(rl_dest, rl_result);
680    } else {
681      rl_result = EvalLoc(rl_dest, reg_class, true);
682      GenNullCheck(rl_obj.s_reg_low, rl_obj.low_reg, opt_flags);
683      LoadBaseDisp(rl_obj.low_reg, field_offset, rl_result.low_reg,
684                   kWord, rl_obj.s_reg_low);
685      if (is_volatile) {
686        GenMemBarrier(kLoadLoad);
687      }
688      StoreValue(rl_dest, rl_result);
689    }
690  } else {
691    ThreadOffset getterOffset =
692        is_long_or_double ? QUICK_ENTRYPOINT_OFFSET(pGet64Instance)
693                          : (is_object ? QUICK_ENTRYPOINT_OFFSET(pGetObjInstance)
694                                       : QUICK_ENTRYPOINT_OFFSET(pGet32Instance));
695    CallRuntimeHelperImmRegLocation(getterOffset, field_idx, rl_obj, true);
696    if (is_long_or_double) {
697      RegLocation rl_result = GetReturnWide(rl_dest.fp);
698      StoreValueWide(rl_dest, rl_result);
699    } else {
700      RegLocation rl_result = GetReturn(rl_dest.fp);
701      StoreValue(rl_dest, rl_result);
702    }
703  }
704}
705
706void Mir2Lir::GenIPut(uint32_t field_idx, int opt_flags, OpSize size,
707                      RegLocation rl_src, RegLocation rl_obj, bool is_long_or_double,
708                      bool is_object) {
709  int field_offset;
710  bool is_volatile;
711
712  bool fast_path = FastInstance(field_idx, field_offset, is_volatile,
713                 true);
714  if (fast_path && !SLOW_FIELD_PATH) {
715    RegisterClass reg_class = oat_reg_class_by_size(size);
716    DCHECK_GE(field_offset, 0);
717    rl_obj = LoadValue(rl_obj, kCoreReg);
718    if (is_long_or_double) {
719      int reg_ptr;
720      rl_src = LoadValueWide(rl_src, kAnyReg);
721      GenNullCheck(rl_obj.s_reg_low, rl_obj.low_reg, opt_flags);
722      reg_ptr = AllocTemp();
723      OpRegRegImm(kOpAdd, reg_ptr, rl_obj.low_reg, field_offset);
724      if (is_volatile) {
725        GenMemBarrier(kStoreStore);
726      }
727      StoreBaseDispWide(reg_ptr, 0, rl_src.low_reg, rl_src.high_reg);
728      if (is_volatile) {
729        GenMemBarrier(kLoadLoad);
730      }
731      FreeTemp(reg_ptr);
732    } else {
733      rl_src = LoadValue(rl_src, reg_class);
734      GenNullCheck(rl_obj.s_reg_low, rl_obj.low_reg, opt_flags);
735      if (is_volatile) {
736        GenMemBarrier(kStoreStore);
737      }
738      StoreBaseDisp(rl_obj.low_reg, field_offset, rl_src.low_reg, kWord);
739      if (is_volatile) {
740        GenMemBarrier(kLoadLoad);
741      }
742      if (is_object && !mir_graph_->IsConstantNullRef(rl_src)) {
743        MarkGCCard(rl_src.low_reg, rl_obj.low_reg);
744      }
745    }
746  } else {
747    ThreadOffset setter_offset =
748        is_long_or_double ? QUICK_ENTRYPOINT_OFFSET(pSet64Instance)
749                          : (is_object ? QUICK_ENTRYPOINT_OFFSET(pSetObjInstance)
750                                       : QUICK_ENTRYPOINT_OFFSET(pSet32Instance));
751    CallRuntimeHelperImmRegLocationRegLocation(setter_offset, field_idx, rl_obj, rl_src, true);
752  }
753}
754
755void Mir2Lir::GenConstClass(uint32_t type_idx, RegLocation rl_dest) {
756  RegLocation rl_method = LoadCurrMethod();
757  int res_reg = AllocTemp();
758  RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
759  if (!cu_->compiler_driver->CanAccessTypeWithoutChecks(cu_->method_idx,
760                                                   *cu_->dex_file,
761                                                   type_idx)) {
762    // Call out to helper which resolves type and verifies access.
763    // Resolved type returned in kRet0.
764    CallRuntimeHelperImmReg(QUICK_ENTRYPOINT_OFFSET(pInitializeTypeAndVerifyAccess),
765                            type_idx, rl_method.low_reg, true);
766    RegLocation rl_result = GetReturn(false);
767    StoreValue(rl_dest, rl_result);
768  } else {
769    // We're don't need access checks, load type from dex cache
770    int32_t dex_cache_offset =
771        mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value();
772    LoadWordDisp(rl_method.low_reg, dex_cache_offset, res_reg);
773    int32_t offset_of_type =
774        mirror::Array::DataOffset(sizeof(mirror::Class*)).Int32Value() + (sizeof(mirror::Class*)
775                          * type_idx);
776    LoadWordDisp(res_reg, offset_of_type, rl_result.low_reg);
777    if (!cu_->compiler_driver->CanAssumeTypeIsPresentInDexCache(*cu_->dex_file,
778        type_idx) || SLOW_TYPE_PATH) {
779      // Slow path, at runtime test if type is null and if so initialize
780      FlushAllRegs();
781      LIR* branch1 = OpCmpImmBranch(kCondEq, rl_result.low_reg, 0, NULL);
782      // Resolved, store and hop over following code
783      StoreValue(rl_dest, rl_result);
784      /*
785       * Because we have stores of the target value on two paths,
786       * clobber temp tracking for the destination using the ssa name
787       */
788      ClobberSReg(rl_dest.s_reg_low);
789      LIR* branch2 = OpUnconditionalBranch(0);
790      // TUNING: move slow path to end & remove unconditional branch
791      LIR* target1 = NewLIR0(kPseudoTargetLabel);
792      // Call out to helper, which will return resolved type in kArg0
793      CallRuntimeHelperImmReg(QUICK_ENTRYPOINT_OFFSET(pInitializeType), type_idx,
794                              rl_method.low_reg, true);
795      RegLocation rl_result = GetReturn(false);
796      StoreValue(rl_dest, rl_result);
797      /*
798       * Because we have stores of the target value on two paths,
799       * clobber temp tracking for the destination using the ssa name
800       */
801      ClobberSReg(rl_dest.s_reg_low);
802      // Rejoin code paths
803      LIR* target2 = NewLIR0(kPseudoTargetLabel);
804      branch1->target = target1;
805      branch2->target = target2;
806    } else {
807      // Fast path, we're done - just store result
808      StoreValue(rl_dest, rl_result);
809    }
810  }
811}
812
813void Mir2Lir::GenConstString(uint32_t string_idx, RegLocation rl_dest) {
814  /* NOTE: Most strings should be available at compile time */
815  int32_t offset_of_string = mirror::Array::DataOffset(sizeof(mirror::String*)).Int32Value() +
816                 (sizeof(mirror::String*) * string_idx);
817  if (!cu_->compiler_driver->CanAssumeStringIsPresentInDexCache(
818      *cu_->dex_file, string_idx) || SLOW_STRING_PATH) {
819    // slow path, resolve string if not in dex cache
820    FlushAllRegs();
821    LockCallTemps();  // Using explicit registers
822    LoadCurrMethodDirect(TargetReg(kArg2));
823    LoadWordDisp(TargetReg(kArg2),
824                 mirror::ArtMethod::DexCacheStringsOffset().Int32Value(), TargetReg(kArg0));
825    // Might call out to helper, which will return resolved string in kRet0
826    int r_tgt = CallHelperSetup(QUICK_ENTRYPOINT_OFFSET(pResolveString));
827    LoadWordDisp(TargetReg(kArg0), offset_of_string, TargetReg(kRet0));
828    LoadConstant(TargetReg(kArg1), string_idx);
829    if (cu_->instruction_set == kThumb2) {
830      OpRegImm(kOpCmp, TargetReg(kRet0), 0);  // Is resolved?
831      GenBarrier();
832      // For testing, always force through helper
833      if (!EXERCISE_SLOWEST_STRING_PATH) {
834        OpIT(kCondEq, "T");
835      }
836      OpRegCopy(TargetReg(kArg0), TargetReg(kArg2));   // .eq
837      LIR* call_inst = OpReg(kOpBlx, r_tgt);    // .eq, helper(Method*, string_idx)
838      MarkSafepointPC(call_inst);
839      FreeTemp(r_tgt);
840    } else if (cu_->instruction_set == kMips) {
841      LIR* branch = OpCmpImmBranch(kCondNe, TargetReg(kRet0), 0, NULL);
842      OpRegCopy(TargetReg(kArg0), TargetReg(kArg2));   // .eq
843      LIR* call_inst = OpReg(kOpBlx, r_tgt);
844      MarkSafepointPC(call_inst);
845      FreeTemp(r_tgt);
846      LIR* target = NewLIR0(kPseudoTargetLabel);
847      branch->target = target;
848    } else {
849      DCHECK_EQ(cu_->instruction_set, kX86);
850      CallRuntimeHelperRegReg(QUICK_ENTRYPOINT_OFFSET(pResolveString), TargetReg(kArg2),
851                              TargetReg(kArg1), true);
852    }
853    GenBarrier();
854    StoreValue(rl_dest, GetReturn(false));
855  } else {
856    RegLocation rl_method = LoadCurrMethod();
857    int res_reg = AllocTemp();
858    RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
859    LoadWordDisp(rl_method.low_reg,
860                 mirror::ArtMethod::DexCacheStringsOffset().Int32Value(), res_reg);
861    LoadWordDisp(res_reg, offset_of_string, rl_result.low_reg);
862    StoreValue(rl_dest, rl_result);
863  }
864}
865
866/*
867 * Let helper function take care of everything.  Will
868 * call Class::NewInstanceFromCode(type_idx, method);
869 */
870void Mir2Lir::GenNewInstance(uint32_t type_idx, RegLocation rl_dest) {
871  FlushAllRegs();  /* Everything to home location */
872  // alloc will always check for resolution, do we also need to verify
873  // access because the verifier was unable to?
874  ThreadOffset func_offset(-1);
875  if (cu_->compiler_driver->CanAccessInstantiableTypeWithoutChecks(
876      cu_->method_idx, *cu_->dex_file, type_idx)) {
877    func_offset = QUICK_ENTRYPOINT_OFFSET(pAllocObject);
878  } else {
879    func_offset = QUICK_ENTRYPOINT_OFFSET(pAllocObjectWithAccessCheck);
880  }
881  CallRuntimeHelperImmMethod(func_offset, type_idx, true);
882  RegLocation rl_result = GetReturn(false);
883  StoreValue(rl_dest, rl_result);
884}
885
886void Mir2Lir::GenThrow(RegLocation rl_src) {
887  FlushAllRegs();
888  CallRuntimeHelperRegLocation(QUICK_ENTRYPOINT_OFFSET(pDeliverException), rl_src, true);
889}
890
891// For final classes there are no sub-classes to check and so we can answer the instance-of
892// question with simple comparisons.
893void Mir2Lir::GenInstanceofFinal(bool use_declaring_class, uint32_t type_idx, RegLocation rl_dest,
894                                 RegLocation rl_src) {
895  RegLocation object = LoadValue(rl_src, kCoreReg);
896  RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
897  int result_reg = rl_result.low_reg;
898  if (result_reg == object.low_reg) {
899    result_reg = AllocTypedTemp(false, kCoreReg);
900  }
901  LoadConstant(result_reg, 0);     // assume false
902  LIR* null_branchover = OpCmpImmBranch(kCondEq, object.low_reg, 0, NULL);
903
904  int check_class = AllocTypedTemp(false, kCoreReg);
905  int object_class = AllocTypedTemp(false, kCoreReg);
906
907  LoadCurrMethodDirect(check_class);
908  if (use_declaring_class) {
909    LoadWordDisp(check_class, mirror::ArtMethod::DeclaringClassOffset().Int32Value(),
910                 check_class);
911    LoadWordDisp(object.low_reg,  mirror::Object::ClassOffset().Int32Value(), object_class);
912  } else {
913    LoadWordDisp(check_class, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value(),
914                 check_class);
915    LoadWordDisp(object.low_reg,  mirror::Object::ClassOffset().Int32Value(), object_class);
916    int32_t offset_of_type =
917      mirror::Array::DataOffset(sizeof(mirror::Class*)).Int32Value() +
918      (sizeof(mirror::Class*) * type_idx);
919    LoadWordDisp(check_class, offset_of_type, check_class);
920  }
921
922  LIR* ne_branchover = NULL;
923  if (cu_->instruction_set == kThumb2) {
924    OpRegReg(kOpCmp, check_class, object_class);  // Same?
925    OpIT(kCondEq, "");   // if-convert the test
926    LoadConstant(result_reg, 1);     // .eq case - load true
927  } else {
928    ne_branchover = OpCmpBranch(kCondNe, check_class, object_class, NULL);
929    LoadConstant(result_reg, 1);     // eq case - load true
930  }
931  LIR* target = NewLIR0(kPseudoTargetLabel);
932  null_branchover->target = target;
933  if (ne_branchover != NULL) {
934    ne_branchover->target = target;
935  }
936  FreeTemp(object_class);
937  FreeTemp(check_class);
938  if (IsTemp(result_reg)) {
939    OpRegCopy(rl_result.low_reg, result_reg);
940    FreeTemp(result_reg);
941  }
942  StoreValue(rl_dest, rl_result);
943}
944
945void Mir2Lir::GenInstanceofCallingHelper(bool needs_access_check, bool type_known_final,
946                                         bool type_known_abstract, bool use_declaring_class,
947                                         bool can_assume_type_is_in_dex_cache,
948                                         uint32_t type_idx, RegLocation rl_dest,
949                                         RegLocation rl_src) {
950  FlushAllRegs();
951  // May generate a call - use explicit registers
952  LockCallTemps();
953  LoadCurrMethodDirect(TargetReg(kArg1));  // kArg1 <= current Method*
954  int class_reg = TargetReg(kArg2);  // kArg2 will hold the Class*
955  if (needs_access_check) {
956    // Check we have access to type_idx and if not throw IllegalAccessError,
957    // returns Class* in kArg0
958    CallRuntimeHelperImm(QUICK_ENTRYPOINT_OFFSET(pInitializeTypeAndVerifyAccess),
959                         type_idx, true);
960    OpRegCopy(class_reg, TargetReg(kRet0));  // Align usage with fast path
961    LoadValueDirectFixed(rl_src, TargetReg(kArg0));  // kArg0 <= ref
962  } else if (use_declaring_class) {
963    LoadValueDirectFixed(rl_src, TargetReg(kArg0));  // kArg0 <= ref
964    LoadWordDisp(TargetReg(kArg1),
965                 mirror::ArtMethod::DeclaringClassOffset().Int32Value(), class_reg);
966  } else {
967    // Load dex cache entry into class_reg (kArg2)
968    LoadValueDirectFixed(rl_src, TargetReg(kArg0));  // kArg0 <= ref
969    LoadWordDisp(TargetReg(kArg1),
970                 mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value(), class_reg);
971    int32_t offset_of_type =
972        mirror::Array::DataOffset(sizeof(mirror::Class*)).Int32Value() + (sizeof(mirror::Class*)
973        * type_idx);
974    LoadWordDisp(class_reg, offset_of_type, class_reg);
975    if (!can_assume_type_is_in_dex_cache) {
976      // Need to test presence of type in dex cache at runtime
977      LIR* hop_branch = OpCmpImmBranch(kCondNe, class_reg, 0, NULL);
978      // Not resolved
979      // Call out to helper, which will return resolved type in kRet0
980      CallRuntimeHelperImm(QUICK_ENTRYPOINT_OFFSET(pInitializeType), type_idx, true);
981      OpRegCopy(TargetReg(kArg2), TargetReg(kRet0));  // Align usage with fast path
982      LoadValueDirectFixed(rl_src, TargetReg(kArg0));  /* reload Ref */
983      // Rejoin code paths
984      LIR* hop_target = NewLIR0(kPseudoTargetLabel);
985      hop_branch->target = hop_target;
986    }
987  }
988  /* kArg0 is ref, kArg2 is class. If ref==null, use directly as bool result */
989  RegLocation rl_result = GetReturn(false);
990  if (cu_->instruction_set == kMips) {
991    // On MIPS rArg0 != rl_result, place false in result if branch is taken.
992    LoadConstant(rl_result.low_reg, 0);
993  }
994  LIR* branch1 = OpCmpImmBranch(kCondEq, TargetReg(kArg0), 0, NULL);
995
996  /* load object->klass_ */
997  DCHECK_EQ(mirror::Object::ClassOffset().Int32Value(), 0);
998  LoadWordDisp(TargetReg(kArg0),  mirror::Object::ClassOffset().Int32Value(), TargetReg(kArg1));
999  /* kArg0 is ref, kArg1 is ref->klass_, kArg2 is class */
1000  LIR* branchover = NULL;
1001  if (type_known_final) {
1002    // rl_result == ref == null == 0.
1003    if (cu_->instruction_set == kThumb2) {
1004      OpRegReg(kOpCmp, TargetReg(kArg1), TargetReg(kArg2));  // Same?
1005      OpIT(kCondEq, "E");   // if-convert the test
1006      LoadConstant(rl_result.low_reg, 1);     // .eq case - load true
1007      LoadConstant(rl_result.low_reg, 0);     // .ne case - load false
1008    } else {
1009      LoadConstant(rl_result.low_reg, 0);     // ne case - load false
1010      branchover = OpCmpBranch(kCondNe, TargetReg(kArg1), TargetReg(kArg2), NULL);
1011      LoadConstant(rl_result.low_reg, 1);     // eq case - load true
1012    }
1013  } else {
1014    if (cu_->instruction_set == kThumb2) {
1015      int r_tgt = LoadHelper(QUICK_ENTRYPOINT_OFFSET(pInstanceofNonTrivial));
1016      if (!type_known_abstract) {
1017      /* Uses conditional nullification */
1018        OpRegReg(kOpCmp, TargetReg(kArg1), TargetReg(kArg2));  // Same?
1019        OpIT(kCondEq, "EE");   // if-convert the test
1020        LoadConstant(TargetReg(kArg0), 1);     // .eq case - load true
1021      }
1022      OpRegCopy(TargetReg(kArg0), TargetReg(kArg2));    // .ne case - arg0 <= class
1023      OpReg(kOpBlx, r_tgt);    // .ne case: helper(class, ref->class)
1024      FreeTemp(r_tgt);
1025    } else {
1026      if (!type_known_abstract) {
1027        /* Uses branchovers */
1028        LoadConstant(rl_result.low_reg, 1);     // assume true
1029        branchover = OpCmpBranch(kCondEq, TargetReg(kArg1), TargetReg(kArg2), NULL);
1030      }
1031      if (cu_->instruction_set != kX86) {
1032        int r_tgt = LoadHelper(QUICK_ENTRYPOINT_OFFSET(pInstanceofNonTrivial));
1033        OpRegCopy(TargetReg(kArg0), TargetReg(kArg2));    // .ne case - arg0 <= class
1034        OpReg(kOpBlx, r_tgt);    // .ne case: helper(class, ref->class)
1035        FreeTemp(r_tgt);
1036      } else {
1037        OpRegCopy(TargetReg(kArg0), TargetReg(kArg2));
1038        OpThreadMem(kOpBlx, QUICK_ENTRYPOINT_OFFSET(pInstanceofNonTrivial));
1039      }
1040    }
1041  }
1042  // TODO: only clobber when type isn't final?
1043  ClobberCalleeSave();
1044  /* branch targets here */
1045  LIR* target = NewLIR0(kPseudoTargetLabel);
1046  StoreValue(rl_dest, rl_result);
1047  branch1->target = target;
1048  if (branchover != NULL) {
1049    branchover->target = target;
1050  }
1051}
1052
1053void Mir2Lir::GenInstanceof(uint32_t type_idx, RegLocation rl_dest, RegLocation rl_src) {
1054  bool type_known_final, type_known_abstract, use_declaring_class;
1055  bool needs_access_check = !cu_->compiler_driver->CanAccessTypeWithoutChecks(cu_->method_idx,
1056                                                                              *cu_->dex_file,
1057                                                                              type_idx,
1058                                                                              &type_known_final,
1059                                                                              &type_known_abstract,
1060                                                                              &use_declaring_class);
1061  bool can_assume_type_is_in_dex_cache = !needs_access_check &&
1062      cu_->compiler_driver->CanAssumeTypeIsPresentInDexCache(*cu_->dex_file, type_idx);
1063
1064  if ((use_declaring_class || can_assume_type_is_in_dex_cache) && type_known_final) {
1065    GenInstanceofFinal(use_declaring_class, type_idx, rl_dest, rl_src);
1066  } else {
1067    GenInstanceofCallingHelper(needs_access_check, type_known_final, type_known_abstract,
1068                               use_declaring_class, can_assume_type_is_in_dex_cache,
1069                               type_idx, rl_dest, rl_src);
1070  }
1071}
1072
1073void Mir2Lir::GenCheckCast(uint32_t insn_idx, uint32_t type_idx, RegLocation rl_src) {
1074  bool type_known_final, type_known_abstract, use_declaring_class;
1075  bool needs_access_check = !cu_->compiler_driver->CanAccessTypeWithoutChecks(cu_->method_idx,
1076                                                                              *cu_->dex_file,
1077                                                                              type_idx,
1078                                                                              &type_known_final,
1079                                                                              &type_known_abstract,
1080                                                                              &use_declaring_class);
1081  // Note: currently type_known_final is unused, as optimizing will only improve the performance
1082  // of the exception throw path.
1083  DexCompilationUnit* cu = mir_graph_->GetCurrentDexCompilationUnit();
1084  const MethodReference mr(cu->GetDexFile(), cu->GetDexMethodIndex());
1085  if (!needs_access_check && cu_->compiler_driver->IsSafeCast(mr, insn_idx)) {
1086    // Verifier type analysis proved this check cast would never cause an exception.
1087    return;
1088  }
1089  FlushAllRegs();
1090  // May generate a call - use explicit registers
1091  LockCallTemps();
1092  LoadCurrMethodDirect(TargetReg(kArg1));  // kArg1 <= current Method*
1093  int class_reg = TargetReg(kArg2);  // kArg2 will hold the Class*
1094  if (needs_access_check) {
1095    // Check we have access to type_idx and if not throw IllegalAccessError,
1096    // returns Class* in kRet0
1097    // InitializeTypeAndVerifyAccess(idx, method)
1098    CallRuntimeHelperImmReg(QUICK_ENTRYPOINT_OFFSET(pInitializeTypeAndVerifyAccess),
1099                            type_idx, TargetReg(kArg1), true);
1100    OpRegCopy(class_reg, TargetReg(kRet0));  // Align usage with fast path
1101  } else if (use_declaring_class) {
1102    LoadWordDisp(TargetReg(kArg1),
1103                 mirror::ArtMethod::DeclaringClassOffset().Int32Value(), class_reg);
1104  } else {
1105    // Load dex cache entry into class_reg (kArg2)
1106    LoadWordDisp(TargetReg(kArg1),
1107                 mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value(), class_reg);
1108    int32_t offset_of_type =
1109        mirror::Array::DataOffset(sizeof(mirror::Class*)).Int32Value() +
1110        (sizeof(mirror::Class*) * type_idx);
1111    LoadWordDisp(class_reg, offset_of_type, class_reg);
1112    if (!cu_->compiler_driver->CanAssumeTypeIsPresentInDexCache(*cu_->dex_file, type_idx)) {
1113      // Need to test presence of type in dex cache at runtime
1114      LIR* hop_branch = OpCmpImmBranch(kCondNe, class_reg, 0, NULL);
1115      // Not resolved
1116      // Call out to helper, which will return resolved type in kArg0
1117      // InitializeTypeFromCode(idx, method)
1118      CallRuntimeHelperImmReg(QUICK_ENTRYPOINT_OFFSET(pInitializeType), type_idx,
1119                              TargetReg(kArg1), true);
1120      OpRegCopy(class_reg, TargetReg(kRet0));  // Align usage with fast path
1121      // Rejoin code paths
1122      LIR* hop_target = NewLIR0(kPseudoTargetLabel);
1123      hop_branch->target = hop_target;
1124    }
1125  }
1126  // At this point, class_reg (kArg2) has class
1127  LoadValueDirectFixed(rl_src, TargetReg(kArg0));  // kArg0 <= ref
1128  /* Null is OK - continue */
1129  LIR* branch1 = OpCmpImmBranch(kCondEq, TargetReg(kArg0), 0, NULL);
1130  /* load object->klass_ */
1131  DCHECK_EQ(mirror::Object::ClassOffset().Int32Value(), 0);
1132  LoadWordDisp(TargetReg(kArg0), mirror::Object::ClassOffset().Int32Value(), TargetReg(kArg1));
1133  /* kArg1 now contains object->klass_ */
1134  LIR* branch2 = NULL;
1135  if (!type_known_abstract) {
1136    branch2 = OpCmpBranch(kCondEq, TargetReg(kArg1), class_reg, NULL);
1137  }
1138  CallRuntimeHelperRegReg(QUICK_ENTRYPOINT_OFFSET(pCheckCast), TargetReg(kArg1),
1139                          TargetReg(kArg2), true);
1140  /* branch target here */
1141  LIR* target = NewLIR0(kPseudoTargetLabel);
1142  branch1->target = target;
1143  if (branch2 != NULL) {
1144    branch2->target = target;
1145  }
1146}
1147
1148void Mir2Lir::GenLong3Addr(OpKind first_op, OpKind second_op, RegLocation rl_dest,
1149                           RegLocation rl_src1, RegLocation rl_src2) {
1150  RegLocation rl_result;
1151  if (cu_->instruction_set == kThumb2) {
1152    /*
1153     * NOTE:  This is the one place in the code in which we might have
1154     * as many as six live temporary registers.  There are 5 in the normal
1155     * set for Arm.  Until we have spill capabilities, temporarily add
1156     * lr to the temp set.  It is safe to do this locally, but note that
1157     * lr is used explicitly elsewhere in the code generator and cannot
1158     * normally be used as a general temp register.
1159     */
1160    MarkTemp(TargetReg(kLr));   // Add lr to the temp pool
1161    FreeTemp(TargetReg(kLr));   // and make it available
1162  }
1163  rl_src1 = LoadValueWide(rl_src1, kCoreReg);
1164  rl_src2 = LoadValueWide(rl_src2, kCoreReg);
1165  rl_result = EvalLoc(rl_dest, kCoreReg, true);
1166  // The longs may overlap - use intermediate temp if so
1167  if ((rl_result.low_reg == rl_src1.high_reg) || (rl_result.low_reg == rl_src2.high_reg)) {
1168    int t_reg = AllocTemp();
1169    OpRegRegReg(first_op, t_reg, rl_src1.low_reg, rl_src2.low_reg);
1170    OpRegRegReg(second_op, rl_result.high_reg, rl_src1.high_reg, rl_src2.high_reg);
1171    OpRegCopy(rl_result.low_reg, t_reg);
1172    FreeTemp(t_reg);
1173  } else {
1174    OpRegRegReg(first_op, rl_result.low_reg, rl_src1.low_reg, rl_src2.low_reg);
1175    OpRegRegReg(second_op, rl_result.high_reg, rl_src1.high_reg,
1176                rl_src2.high_reg);
1177  }
1178  /*
1179   * NOTE: If rl_dest refers to a frame variable in a large frame, the
1180   * following StoreValueWide might need to allocate a temp register.
1181   * To further work around the lack of a spill capability, explicitly
1182   * free any temps from rl_src1 & rl_src2 that aren't still live in rl_result.
1183   * Remove when spill is functional.
1184   */
1185  FreeRegLocTemps(rl_result, rl_src1);
1186  FreeRegLocTemps(rl_result, rl_src2);
1187  StoreValueWide(rl_dest, rl_result);
1188  if (cu_->instruction_set == kThumb2) {
1189    Clobber(TargetReg(kLr));
1190    UnmarkTemp(TargetReg(kLr));  // Remove lr from the temp pool
1191  }
1192}
1193
1194
1195void Mir2Lir::GenShiftOpLong(Instruction::Code opcode, RegLocation rl_dest,
1196                             RegLocation rl_src1, RegLocation rl_shift) {
1197  ThreadOffset func_offset(-1);
1198
1199  switch (opcode) {
1200    case Instruction::SHL_LONG:
1201    case Instruction::SHL_LONG_2ADDR:
1202      func_offset = QUICK_ENTRYPOINT_OFFSET(pShlLong);
1203      break;
1204    case Instruction::SHR_LONG:
1205    case Instruction::SHR_LONG_2ADDR:
1206      func_offset = QUICK_ENTRYPOINT_OFFSET(pShrLong);
1207      break;
1208    case Instruction::USHR_LONG:
1209    case Instruction::USHR_LONG_2ADDR:
1210      func_offset = QUICK_ENTRYPOINT_OFFSET(pUshrLong);
1211      break;
1212    default:
1213      LOG(FATAL) << "Unexpected case";
1214  }
1215  FlushAllRegs();   /* Send everything to home location */
1216  CallRuntimeHelperRegLocationRegLocation(func_offset, rl_src1, rl_shift, false);
1217  RegLocation rl_result = GetReturnWide(false);
1218  StoreValueWide(rl_dest, rl_result);
1219}
1220
1221
1222void Mir2Lir::GenArithOpInt(Instruction::Code opcode, RegLocation rl_dest,
1223                            RegLocation rl_src1, RegLocation rl_src2) {
1224  OpKind op = kOpBkpt;
1225  bool is_div_rem = false;
1226  bool check_zero = false;
1227  bool unary = false;
1228  RegLocation rl_result;
1229  bool shift_op = false;
1230  switch (opcode) {
1231    case Instruction::NEG_INT:
1232      op = kOpNeg;
1233      unary = true;
1234      break;
1235    case Instruction::NOT_INT:
1236      op = kOpMvn;
1237      unary = true;
1238      break;
1239    case Instruction::ADD_INT:
1240    case Instruction::ADD_INT_2ADDR:
1241      op = kOpAdd;
1242      break;
1243    case Instruction::SUB_INT:
1244    case Instruction::SUB_INT_2ADDR:
1245      op = kOpSub;
1246      break;
1247    case Instruction::MUL_INT:
1248    case Instruction::MUL_INT_2ADDR:
1249      op = kOpMul;
1250      break;
1251    case Instruction::DIV_INT:
1252    case Instruction::DIV_INT_2ADDR:
1253      check_zero = true;
1254      op = kOpDiv;
1255      is_div_rem = true;
1256      break;
1257    /* NOTE: returns in kArg1 */
1258    case Instruction::REM_INT:
1259    case Instruction::REM_INT_2ADDR:
1260      check_zero = true;
1261      op = kOpRem;
1262      is_div_rem = true;
1263      break;
1264    case Instruction::AND_INT:
1265    case Instruction::AND_INT_2ADDR:
1266      op = kOpAnd;
1267      break;
1268    case Instruction::OR_INT:
1269    case Instruction::OR_INT_2ADDR:
1270      op = kOpOr;
1271      break;
1272    case Instruction::XOR_INT:
1273    case Instruction::XOR_INT_2ADDR:
1274      op = kOpXor;
1275      break;
1276    case Instruction::SHL_INT:
1277    case Instruction::SHL_INT_2ADDR:
1278      shift_op = true;
1279      op = kOpLsl;
1280      break;
1281    case Instruction::SHR_INT:
1282    case Instruction::SHR_INT_2ADDR:
1283      shift_op = true;
1284      op = kOpAsr;
1285      break;
1286    case Instruction::USHR_INT:
1287    case Instruction::USHR_INT_2ADDR:
1288      shift_op = true;
1289      op = kOpLsr;
1290      break;
1291    default:
1292      LOG(FATAL) << "Invalid word arith op: " << opcode;
1293  }
1294  if (!is_div_rem) {
1295    if (unary) {
1296      rl_src1 = LoadValue(rl_src1, kCoreReg);
1297      rl_result = EvalLoc(rl_dest, kCoreReg, true);
1298      OpRegReg(op, rl_result.low_reg, rl_src1.low_reg);
1299    } else {
1300      if (shift_op) {
1301        int t_reg = INVALID_REG;
1302        if (cu_->instruction_set == kX86) {
1303          // X86 doesn't require masking and must use ECX
1304          t_reg = TargetReg(kCount);  // rCX
1305          LoadValueDirectFixed(rl_src2, t_reg);
1306        } else {
1307          rl_src2 = LoadValue(rl_src2, kCoreReg);
1308          t_reg = AllocTemp();
1309          OpRegRegImm(kOpAnd, t_reg, rl_src2.low_reg, 31);
1310        }
1311        rl_src1 = LoadValue(rl_src1, kCoreReg);
1312        rl_result = EvalLoc(rl_dest, kCoreReg, true);
1313        OpRegRegReg(op, rl_result.low_reg, rl_src1.low_reg, t_reg);
1314        FreeTemp(t_reg);
1315      } else {
1316        rl_src1 = LoadValue(rl_src1, kCoreReg);
1317        rl_src2 = LoadValue(rl_src2, kCoreReg);
1318        rl_result = EvalLoc(rl_dest, kCoreReg, true);
1319        OpRegRegReg(op, rl_result.low_reg, rl_src1.low_reg, rl_src2.low_reg);
1320      }
1321    }
1322    StoreValue(rl_dest, rl_result);
1323  } else {
1324    if (cu_->instruction_set == kMips) {
1325      rl_src1 = LoadValue(rl_src1, kCoreReg);
1326      rl_src2 = LoadValue(rl_src2, kCoreReg);
1327      if (check_zero) {
1328          GenImmedCheck(kCondEq, rl_src2.low_reg, 0, kThrowDivZero);
1329      }
1330      rl_result = GenDivRem(rl_dest, rl_src1.low_reg, rl_src2.low_reg, op == kOpDiv);
1331    } else {
1332      ThreadOffset func_offset = QUICK_ENTRYPOINT_OFFSET(pIdivmod);
1333      FlushAllRegs();   /* Send everything to home location */
1334      LoadValueDirectFixed(rl_src2, TargetReg(kArg1));
1335      int r_tgt = CallHelperSetup(func_offset);
1336      LoadValueDirectFixed(rl_src1, TargetReg(kArg0));
1337      if (check_zero) {
1338        GenImmedCheck(kCondEq, TargetReg(kArg1), 0, kThrowDivZero);
1339      }
1340      // NOTE: callout here is not a safepoint
1341      CallHelper(r_tgt, func_offset, false /* not a safepoint */);
1342      if (op == kOpDiv)
1343        rl_result = GetReturn(false);
1344      else
1345        rl_result = GetReturnAlt();
1346    }
1347    StoreValue(rl_dest, rl_result);
1348  }
1349}
1350
1351/*
1352 * The following are the first-level codegen routines that analyze the format
1353 * of each bytecode then either dispatch special purpose codegen routines
1354 * or produce corresponding Thumb instructions directly.
1355 */
1356
1357static bool IsPowerOfTwo(int x) {
1358  return (x & (x - 1)) == 0;
1359}
1360
1361// Returns true if no more than two bits are set in 'x'.
1362static bool IsPopCountLE2(unsigned int x) {
1363  x &= x - 1;
1364  return (x & (x - 1)) == 0;
1365}
1366
1367// Returns the index of the lowest set bit in 'x'.
1368static int LowestSetBit(unsigned int x) {
1369  int bit_posn = 0;
1370  while ((x & 0xf) == 0) {
1371    bit_posn += 4;
1372    x >>= 4;
1373  }
1374  while ((x & 1) == 0) {
1375    bit_posn++;
1376    x >>= 1;
1377  }
1378  return bit_posn;
1379}
1380
1381// Returns true if it added instructions to 'cu' to divide 'rl_src' by 'lit'
1382// and store the result in 'rl_dest'.
1383bool Mir2Lir::HandleEasyDivRem(Instruction::Code dalvik_opcode, bool is_div,
1384                               RegLocation rl_src, RegLocation rl_dest, int lit) {
1385  if ((lit < 2) || ((cu_->instruction_set != kThumb2) && !IsPowerOfTwo(lit))) {
1386    return false;
1387  }
1388  // No divide instruction for Arm, so check for more special cases
1389  if ((cu_->instruction_set == kThumb2) && !IsPowerOfTwo(lit)) {
1390    return SmallLiteralDivRem(dalvik_opcode, is_div, rl_src, rl_dest, lit);
1391  }
1392  int k = LowestSetBit(lit);
1393  if (k >= 30) {
1394    // Avoid special cases.
1395    return false;
1396  }
1397  rl_src = LoadValue(rl_src, kCoreReg);
1398  RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
1399  if (is_div) {
1400    int t_reg = AllocTemp();
1401    if (lit == 2) {
1402      // Division by 2 is by far the most common division by constant.
1403      OpRegRegImm(kOpLsr, t_reg, rl_src.low_reg, 32 - k);
1404      OpRegRegReg(kOpAdd, t_reg, t_reg, rl_src.low_reg);
1405      OpRegRegImm(kOpAsr, rl_result.low_reg, t_reg, k);
1406    } else {
1407      OpRegRegImm(kOpAsr, t_reg, rl_src.low_reg, 31);
1408      OpRegRegImm(kOpLsr, t_reg, t_reg, 32 - k);
1409      OpRegRegReg(kOpAdd, t_reg, t_reg, rl_src.low_reg);
1410      OpRegRegImm(kOpAsr, rl_result.low_reg, t_reg, k);
1411    }
1412  } else {
1413    int t_reg1 = AllocTemp();
1414    int t_reg2 = AllocTemp();
1415    if (lit == 2) {
1416      OpRegRegImm(kOpLsr, t_reg1, rl_src.low_reg, 32 - k);
1417      OpRegRegReg(kOpAdd, t_reg2, t_reg1, rl_src.low_reg);
1418      OpRegRegImm(kOpAnd, t_reg2, t_reg2, lit -1);
1419      OpRegRegReg(kOpSub, rl_result.low_reg, t_reg2, t_reg1);
1420    } else {
1421      OpRegRegImm(kOpAsr, t_reg1, rl_src.low_reg, 31);
1422      OpRegRegImm(kOpLsr, t_reg1, t_reg1, 32 - k);
1423      OpRegRegReg(kOpAdd, t_reg2, t_reg1, rl_src.low_reg);
1424      OpRegRegImm(kOpAnd, t_reg2, t_reg2, lit - 1);
1425      OpRegRegReg(kOpSub, rl_result.low_reg, t_reg2, t_reg1);
1426    }
1427  }
1428  StoreValue(rl_dest, rl_result);
1429  return true;
1430}
1431
1432// Returns true if it added instructions to 'cu' to multiply 'rl_src' by 'lit'
1433// and store the result in 'rl_dest'.
1434bool Mir2Lir::HandleEasyMultiply(RegLocation rl_src, RegLocation rl_dest, int lit) {
1435  // Can we simplify this multiplication?
1436  bool power_of_two = false;
1437  bool pop_count_le2 = false;
1438  bool power_of_two_minus_one = false;
1439  if (lit < 2) {
1440    // Avoid special cases.
1441    return false;
1442  } else if (IsPowerOfTwo(lit)) {
1443    power_of_two = true;
1444  } else if (IsPopCountLE2(lit)) {
1445    pop_count_le2 = true;
1446  } else if (IsPowerOfTwo(lit + 1)) {
1447    power_of_two_minus_one = true;
1448  } else {
1449    return false;
1450  }
1451  rl_src = LoadValue(rl_src, kCoreReg);
1452  RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
1453  if (power_of_two) {
1454    // Shift.
1455    OpRegRegImm(kOpLsl, rl_result.low_reg, rl_src.low_reg, LowestSetBit(lit));
1456  } else if (pop_count_le2) {
1457    // Shift and add and shift.
1458    int first_bit = LowestSetBit(lit);
1459    int second_bit = LowestSetBit(lit ^ (1 << first_bit));
1460    GenMultiplyByTwoBitMultiplier(rl_src, rl_result, lit, first_bit, second_bit);
1461  } else {
1462    // Reverse subtract: (src << (shift + 1)) - src.
1463    DCHECK(power_of_two_minus_one);
1464    // TUNING: rsb dst, src, src lsl#LowestSetBit(lit + 1)
1465    int t_reg = AllocTemp();
1466    OpRegRegImm(kOpLsl, t_reg, rl_src.low_reg, LowestSetBit(lit + 1));
1467    OpRegRegReg(kOpSub, rl_result.low_reg, t_reg, rl_src.low_reg);
1468  }
1469  StoreValue(rl_dest, rl_result);
1470  return true;
1471}
1472
1473void Mir2Lir::GenArithOpIntLit(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src,
1474                               int lit) {
1475  RegLocation rl_result;
1476  OpKind op = static_cast<OpKind>(0);    /* Make gcc happy */
1477  int shift_op = false;
1478  bool is_div = false;
1479
1480  switch (opcode) {
1481    case Instruction::RSUB_INT_LIT8:
1482    case Instruction::RSUB_INT: {
1483      rl_src = LoadValue(rl_src, kCoreReg);
1484      rl_result = EvalLoc(rl_dest, kCoreReg, true);
1485      if (cu_->instruction_set == kThumb2) {
1486        OpRegRegImm(kOpRsub, rl_result.low_reg, rl_src.low_reg, lit);
1487      } else {
1488        OpRegReg(kOpNeg, rl_result.low_reg, rl_src.low_reg);
1489        OpRegImm(kOpAdd, rl_result.low_reg, lit);
1490      }
1491      StoreValue(rl_dest, rl_result);
1492      return;
1493    }
1494
1495    case Instruction::SUB_INT:
1496    case Instruction::SUB_INT_2ADDR:
1497      lit = -lit;
1498      // Intended fallthrough
1499    case Instruction::ADD_INT:
1500    case Instruction::ADD_INT_2ADDR:
1501    case Instruction::ADD_INT_LIT8:
1502    case Instruction::ADD_INT_LIT16:
1503      op = kOpAdd;
1504      break;
1505    case Instruction::MUL_INT:
1506    case Instruction::MUL_INT_2ADDR:
1507    case Instruction::MUL_INT_LIT8:
1508    case Instruction::MUL_INT_LIT16: {
1509      if (HandleEasyMultiply(rl_src, rl_dest, lit)) {
1510        return;
1511      }
1512      op = kOpMul;
1513      break;
1514    }
1515    case Instruction::AND_INT:
1516    case Instruction::AND_INT_2ADDR:
1517    case Instruction::AND_INT_LIT8:
1518    case Instruction::AND_INT_LIT16:
1519      op = kOpAnd;
1520      break;
1521    case Instruction::OR_INT:
1522    case Instruction::OR_INT_2ADDR:
1523    case Instruction::OR_INT_LIT8:
1524    case Instruction::OR_INT_LIT16:
1525      op = kOpOr;
1526      break;
1527    case Instruction::XOR_INT:
1528    case Instruction::XOR_INT_2ADDR:
1529    case Instruction::XOR_INT_LIT8:
1530    case Instruction::XOR_INT_LIT16:
1531      op = kOpXor;
1532      break;
1533    case Instruction::SHL_INT_LIT8:
1534    case Instruction::SHL_INT:
1535    case Instruction::SHL_INT_2ADDR:
1536      lit &= 31;
1537      shift_op = true;
1538      op = kOpLsl;
1539      break;
1540    case Instruction::SHR_INT_LIT8:
1541    case Instruction::SHR_INT:
1542    case Instruction::SHR_INT_2ADDR:
1543      lit &= 31;
1544      shift_op = true;
1545      op = kOpAsr;
1546      break;
1547    case Instruction::USHR_INT_LIT8:
1548    case Instruction::USHR_INT:
1549    case Instruction::USHR_INT_2ADDR:
1550      lit &= 31;
1551      shift_op = true;
1552      op = kOpLsr;
1553      break;
1554
1555    case Instruction::DIV_INT:
1556    case Instruction::DIV_INT_2ADDR:
1557    case Instruction::DIV_INT_LIT8:
1558    case Instruction::DIV_INT_LIT16:
1559    case Instruction::REM_INT:
1560    case Instruction::REM_INT_2ADDR:
1561    case Instruction::REM_INT_LIT8:
1562    case Instruction::REM_INT_LIT16: {
1563      if (lit == 0) {
1564        GenImmedCheck(kCondAl, 0, 0, kThrowDivZero);
1565        return;
1566      }
1567      if ((opcode == Instruction::DIV_INT) ||
1568          (opcode == Instruction::DIV_INT_2ADDR) ||
1569          (opcode == Instruction::DIV_INT_LIT8) ||
1570          (opcode == Instruction::DIV_INT_LIT16)) {
1571        is_div = true;
1572      } else {
1573        is_div = false;
1574      }
1575      if (HandleEasyDivRem(opcode, is_div, rl_src, rl_dest, lit)) {
1576        return;
1577      }
1578      if (cu_->instruction_set == kMips) {
1579        rl_src = LoadValue(rl_src, kCoreReg);
1580        rl_result = GenDivRemLit(rl_dest, rl_src.low_reg, lit, is_div);
1581      } else {
1582        FlushAllRegs();   /* Everything to home location */
1583        LoadValueDirectFixed(rl_src, TargetReg(kArg0));
1584        Clobber(TargetReg(kArg0));
1585        ThreadOffset func_offset = QUICK_ENTRYPOINT_OFFSET(pIdivmod);
1586        CallRuntimeHelperRegImm(func_offset, TargetReg(kArg0), lit, false);
1587        if (is_div)
1588          rl_result = GetReturn(false);
1589        else
1590          rl_result = GetReturnAlt();
1591      }
1592      StoreValue(rl_dest, rl_result);
1593      return;
1594    }
1595    default:
1596      LOG(FATAL) << "Unexpected opcode " << opcode;
1597  }
1598  rl_src = LoadValue(rl_src, kCoreReg);
1599  rl_result = EvalLoc(rl_dest, kCoreReg, true);
1600  // Avoid shifts by literal 0 - no support in Thumb.  Change to copy
1601  if (shift_op && (lit == 0)) {
1602    OpRegCopy(rl_result.low_reg, rl_src.low_reg);
1603  } else {
1604    OpRegRegImm(op, rl_result.low_reg, rl_src.low_reg, lit);
1605  }
1606  StoreValue(rl_dest, rl_result);
1607}
1608
1609void Mir2Lir::GenArithOpLong(Instruction::Code opcode, RegLocation rl_dest,
1610                             RegLocation rl_src1, RegLocation rl_src2) {
1611  RegLocation rl_result;
1612  OpKind first_op = kOpBkpt;
1613  OpKind second_op = kOpBkpt;
1614  bool call_out = false;
1615  bool check_zero = false;
1616  ThreadOffset func_offset(-1);
1617  int ret_reg = TargetReg(kRet0);
1618
1619  switch (opcode) {
1620    case Instruction::NOT_LONG:
1621      rl_src2 = LoadValueWide(rl_src2, kCoreReg);
1622      rl_result = EvalLoc(rl_dest, kCoreReg, true);
1623      // Check for destructive overlap
1624      if (rl_result.low_reg == rl_src2.high_reg) {
1625        int t_reg = AllocTemp();
1626        OpRegCopy(t_reg, rl_src2.high_reg);
1627        OpRegReg(kOpMvn, rl_result.low_reg, rl_src2.low_reg);
1628        OpRegReg(kOpMvn, rl_result.high_reg, t_reg);
1629        FreeTemp(t_reg);
1630      } else {
1631        OpRegReg(kOpMvn, rl_result.low_reg, rl_src2.low_reg);
1632        OpRegReg(kOpMvn, rl_result.high_reg, rl_src2.high_reg);
1633      }
1634      StoreValueWide(rl_dest, rl_result);
1635      return;
1636    case Instruction::ADD_LONG:
1637    case Instruction::ADD_LONG_2ADDR:
1638      if (cu_->instruction_set != kThumb2) {
1639        GenAddLong(rl_dest, rl_src1, rl_src2);
1640        return;
1641      }
1642      first_op = kOpAdd;
1643      second_op = kOpAdc;
1644      break;
1645    case Instruction::SUB_LONG:
1646    case Instruction::SUB_LONG_2ADDR:
1647      if (cu_->instruction_set != kThumb2) {
1648        GenSubLong(rl_dest, rl_src1, rl_src2);
1649        return;
1650      }
1651      first_op = kOpSub;
1652      second_op = kOpSbc;
1653      break;
1654    case Instruction::MUL_LONG:
1655    case Instruction::MUL_LONG_2ADDR:
1656      if (cu_->instruction_set == kThumb2) {
1657        GenMulLong(rl_dest, rl_src1, rl_src2);
1658        return;
1659      } else {
1660        call_out = true;
1661        ret_reg = TargetReg(kRet0);
1662        func_offset = QUICK_ENTRYPOINT_OFFSET(pLmul);
1663      }
1664      break;
1665    case Instruction::DIV_LONG:
1666    case Instruction::DIV_LONG_2ADDR:
1667      call_out = true;
1668      check_zero = true;
1669      ret_reg = TargetReg(kRet0);
1670      func_offset = QUICK_ENTRYPOINT_OFFSET(pLdiv);
1671      break;
1672    case Instruction::REM_LONG:
1673    case Instruction::REM_LONG_2ADDR:
1674      call_out = true;
1675      check_zero = true;
1676      func_offset = QUICK_ENTRYPOINT_OFFSET(pLdivmod);
1677      /* NOTE - for Arm, result is in kArg2/kArg3 instead of kRet0/kRet1 */
1678      ret_reg = (cu_->instruction_set == kThumb2) ? TargetReg(kArg2) : TargetReg(kRet0);
1679      break;
1680    case Instruction::AND_LONG_2ADDR:
1681    case Instruction::AND_LONG:
1682      if (cu_->instruction_set == kX86) {
1683        return GenAndLong(rl_dest, rl_src1, rl_src2);
1684      }
1685      first_op = kOpAnd;
1686      second_op = kOpAnd;
1687      break;
1688    case Instruction::OR_LONG:
1689    case Instruction::OR_LONG_2ADDR:
1690      if (cu_->instruction_set == kX86) {
1691        GenOrLong(rl_dest, rl_src1, rl_src2);
1692        return;
1693      }
1694      first_op = kOpOr;
1695      second_op = kOpOr;
1696      break;
1697    case Instruction::XOR_LONG:
1698    case Instruction::XOR_LONG_2ADDR:
1699      if (cu_->instruction_set == kX86) {
1700        GenXorLong(rl_dest, rl_src1, rl_src2);
1701        return;
1702      }
1703      first_op = kOpXor;
1704      second_op = kOpXor;
1705      break;
1706    case Instruction::NEG_LONG: {
1707      GenNegLong(rl_dest, rl_src2);
1708      return;
1709    }
1710    default:
1711      LOG(FATAL) << "Invalid long arith op";
1712  }
1713  if (!call_out) {
1714    GenLong3Addr(first_op, second_op, rl_dest, rl_src1, rl_src2);
1715  } else {
1716    FlushAllRegs();   /* Send everything to home location */
1717    if (check_zero) {
1718      LoadValueDirectWideFixed(rl_src2, TargetReg(kArg2), TargetReg(kArg3));
1719      int r_tgt = CallHelperSetup(func_offset);
1720      GenDivZeroCheck(TargetReg(kArg2), TargetReg(kArg3));
1721      LoadValueDirectWideFixed(rl_src1, TargetReg(kArg0), TargetReg(kArg1));
1722      // NOTE: callout here is not a safepoint
1723      CallHelper(r_tgt, func_offset, false /* not safepoint */);
1724    } else {
1725      CallRuntimeHelperRegLocationRegLocation(func_offset, rl_src1, rl_src2, false);
1726    }
1727    // Adjust return regs in to handle case of rem returning kArg2/kArg3
1728    if (ret_reg == TargetReg(kRet0))
1729      rl_result = GetReturnWide(false);
1730    else
1731      rl_result = GetReturnWideAlt();
1732    StoreValueWide(rl_dest, rl_result);
1733  }
1734}
1735
1736void Mir2Lir::GenConversionCall(ThreadOffset func_offset,
1737                                RegLocation rl_dest, RegLocation rl_src) {
1738  /*
1739   * Don't optimize the register usage since it calls out to support
1740   * functions
1741   */
1742  FlushAllRegs();   /* Send everything to home location */
1743  if (rl_src.wide) {
1744    LoadValueDirectWideFixed(rl_src, rl_src.fp ? TargetReg(kFArg0) : TargetReg(kArg0),
1745                             rl_src.fp ? TargetReg(kFArg1) : TargetReg(kArg1));
1746  } else {
1747    LoadValueDirectFixed(rl_src, rl_src.fp ? TargetReg(kFArg0) : TargetReg(kArg0));
1748  }
1749  CallRuntimeHelperRegLocation(func_offset, rl_src, false);
1750  if (rl_dest.wide) {
1751    RegLocation rl_result;
1752    rl_result = GetReturnWide(rl_dest.fp);
1753    StoreValueWide(rl_dest, rl_result);
1754  } else {
1755    RegLocation rl_result;
1756    rl_result = GetReturn(rl_dest.fp);
1757    StoreValue(rl_dest, rl_result);
1758  }
1759}
1760
1761/* Check if we need to check for pending suspend request */
1762void Mir2Lir::GenSuspendTest(int opt_flags) {
1763  if (NO_SUSPEND || (opt_flags & MIR_IGNORE_SUSPEND_CHECK)) {
1764    return;
1765  }
1766  FlushAllRegs();
1767  LIR* branch = OpTestSuspend(NULL);
1768  LIR* ret_lab = NewLIR0(kPseudoTargetLabel);
1769  LIR* target = RawLIR(current_dalvik_offset_, kPseudoSuspendTarget,
1770                       reinterpret_cast<uintptr_t>(ret_lab), current_dalvik_offset_);
1771  branch->target = target;
1772  suspend_launchpads_.Insert(target);
1773}
1774
1775/* Check if we need to check for pending suspend request */
1776void Mir2Lir::GenSuspendTestAndBranch(int opt_flags, LIR* target) {
1777  if (NO_SUSPEND || (opt_flags & MIR_IGNORE_SUSPEND_CHECK)) {
1778    OpUnconditionalBranch(target);
1779    return;
1780  }
1781  OpTestSuspend(target);
1782  LIR* launch_pad =
1783      RawLIR(current_dalvik_offset_, kPseudoSuspendTarget,
1784             reinterpret_cast<uintptr_t>(target), current_dalvik_offset_);
1785  FlushAllRegs();
1786  OpUnconditionalBranch(launch_pad);
1787  suspend_launchpads_.Insert(launch_pad);
1788}
1789
1790}  // namespace art
1791