code_generator_arm.cc revision 15bd22849ee6a1ffb3fb3630f686c2870bdf1bbc
1/*
2 * Copyright (C) 2014 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 "code_generator_arm.h"
18
19#include "arch/arm/instruction_set_features_arm.h"
20#include "art_method.h"
21#include "code_generator_utils.h"
22#include "compiled_method.h"
23#include "entrypoints/quick/quick_entrypoints.h"
24#include "gc/accounting/card_table.h"
25#include "intrinsics.h"
26#include "intrinsics_arm.h"
27#include "mirror/array-inl.h"
28#include "mirror/class-inl.h"
29#include "thread.h"
30#include "utils/arm/assembler_arm.h"
31#include "utils/arm/managed_register_arm.h"
32#include "utils/assembler.h"
33#include "utils/stack_checks.h"
34
35namespace art {
36
37template<class MirrorType>
38class GcRoot;
39
40namespace arm {
41
42static bool ExpectedPairLayout(Location location) {
43  // We expected this for both core and fpu register pairs.
44  return ((location.low() & 1) == 0) && (location.low() + 1 == location.high());
45}
46
47static constexpr int kCurrentMethodStackOffset = 0;
48static constexpr Register kMethodRegisterArgument = R0;
49
50// We unconditionally allocate R5 to ensure we can do long operations
51// with baseline.
52static constexpr Register kCoreSavedRegisterForBaseline = R5;
53static constexpr Register kCoreCalleeSaves[] =
54    { R5, R6, R7, R8, R10, R11, LR };
55static constexpr SRegister kFpuCalleeSaves[] =
56    { S16, S17, S18, S19, S20, S21, S22, S23, S24, S25, S26, S27, S28, S29, S30, S31 };
57
58// D31 cannot be split into two S registers, and the register allocator only works on
59// S registers. Therefore there is no need to block it.
60static constexpr DRegister DTMP = D31;
61
62static constexpr uint32_t kPackedSwitchCompareJumpThreshold = 7;
63
64#define __ down_cast<ArmAssembler*>(codegen->GetAssembler())->
65#define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kArmWordSize, x).Int32Value()
66
67class NullCheckSlowPathARM : public SlowPathCode {
68 public:
69  explicit NullCheckSlowPathARM(HNullCheck* instruction) : instruction_(instruction) {}
70
71  void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
72    CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
73    __ Bind(GetEntryLabel());
74    if (instruction_->CanThrowIntoCatchBlock()) {
75      // Live registers will be restored in the catch block if caught.
76      SaveLiveRegisters(codegen, instruction_->GetLocations());
77    }
78    arm_codegen->InvokeRuntime(
79        QUICK_ENTRY_POINT(pThrowNullPointer), instruction_, instruction_->GetDexPc(), this);
80    CheckEntrypointTypes<kQuickThrowNullPointer, void, void>();
81  }
82
83  bool IsFatal() const OVERRIDE { return true; }
84
85  const char* GetDescription() const OVERRIDE { return "NullCheckSlowPathARM"; }
86
87 private:
88  HNullCheck* const instruction_;
89  DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathARM);
90};
91
92class DivZeroCheckSlowPathARM : public SlowPathCode {
93 public:
94  explicit DivZeroCheckSlowPathARM(HDivZeroCheck* instruction) : instruction_(instruction) {}
95
96  void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
97    CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
98    __ Bind(GetEntryLabel());
99    if (instruction_->CanThrowIntoCatchBlock()) {
100      // Live registers will be restored in the catch block if caught.
101      SaveLiveRegisters(codegen, instruction_->GetLocations());
102    }
103    arm_codegen->InvokeRuntime(
104        QUICK_ENTRY_POINT(pThrowDivZero), instruction_, instruction_->GetDexPc(), this);
105    CheckEntrypointTypes<kQuickThrowDivZero, void, void>();
106  }
107
108  bool IsFatal() const OVERRIDE { return true; }
109
110  const char* GetDescription() const OVERRIDE { return "DivZeroCheckSlowPathARM"; }
111
112 private:
113  HDivZeroCheck* const instruction_;
114  DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathARM);
115};
116
117class SuspendCheckSlowPathARM : public SlowPathCode {
118 public:
119  SuspendCheckSlowPathARM(HSuspendCheck* instruction, HBasicBlock* successor)
120      : instruction_(instruction), successor_(successor) {}
121
122  void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
123    CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
124    __ Bind(GetEntryLabel());
125    SaveLiveRegisters(codegen, instruction_->GetLocations());
126    arm_codegen->InvokeRuntime(
127        QUICK_ENTRY_POINT(pTestSuspend), instruction_, instruction_->GetDexPc(), this);
128    CheckEntrypointTypes<kQuickTestSuspend, void, void>();
129    RestoreLiveRegisters(codegen, instruction_->GetLocations());
130    if (successor_ == nullptr) {
131      __ b(GetReturnLabel());
132    } else {
133      __ b(arm_codegen->GetLabelOf(successor_));
134    }
135  }
136
137  Label* GetReturnLabel() {
138    DCHECK(successor_ == nullptr);
139    return &return_label_;
140  }
141
142  HBasicBlock* GetSuccessor() const {
143    return successor_;
144  }
145
146  const char* GetDescription() const OVERRIDE { return "SuspendCheckSlowPathARM"; }
147
148 private:
149  HSuspendCheck* const instruction_;
150  // If not null, the block to branch to after the suspend check.
151  HBasicBlock* const successor_;
152
153  // If `successor_` is null, the label to branch to after the suspend check.
154  Label return_label_;
155
156  DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathARM);
157};
158
159class BoundsCheckSlowPathARM : public SlowPathCode {
160 public:
161  explicit BoundsCheckSlowPathARM(HBoundsCheck* instruction)
162      : instruction_(instruction) {}
163
164  void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
165    CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
166    LocationSummary* locations = instruction_->GetLocations();
167
168    __ Bind(GetEntryLabel());
169    if (instruction_->CanThrowIntoCatchBlock()) {
170      // Live registers will be restored in the catch block if caught.
171      SaveLiveRegisters(codegen, instruction_->GetLocations());
172    }
173    // We're moving two locations to locations that could overlap, so we need a parallel
174    // move resolver.
175    InvokeRuntimeCallingConvention calling_convention;
176    codegen->EmitParallelMoves(
177        locations->InAt(0),
178        Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
179        Primitive::kPrimInt,
180        locations->InAt(1),
181        Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
182        Primitive::kPrimInt);
183    arm_codegen->InvokeRuntime(
184        QUICK_ENTRY_POINT(pThrowArrayBounds), instruction_, instruction_->GetDexPc(), this);
185    CheckEntrypointTypes<kQuickThrowArrayBounds, void, int32_t, int32_t>();
186  }
187
188  bool IsFatal() const OVERRIDE { return true; }
189
190  const char* GetDescription() const OVERRIDE { return "BoundsCheckSlowPathARM"; }
191
192 private:
193  HBoundsCheck* const instruction_;
194
195  DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathARM);
196};
197
198class LoadClassSlowPathARM : public SlowPathCode {
199 public:
200  LoadClassSlowPathARM(HLoadClass* cls,
201                       HInstruction* at,
202                       uint32_t dex_pc,
203                       bool do_clinit)
204      : cls_(cls), at_(at), dex_pc_(dex_pc), do_clinit_(do_clinit) {
205    DCHECK(at->IsLoadClass() || at->IsClinitCheck());
206  }
207
208  void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
209    LocationSummary* locations = at_->GetLocations();
210
211    CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
212    __ Bind(GetEntryLabel());
213    SaveLiveRegisters(codegen, locations);
214
215    InvokeRuntimeCallingConvention calling_convention;
216    __ LoadImmediate(calling_convention.GetRegisterAt(0), cls_->GetTypeIndex());
217    int32_t entry_point_offset = do_clinit_
218        ? QUICK_ENTRY_POINT(pInitializeStaticStorage)
219        : QUICK_ENTRY_POINT(pInitializeType);
220    arm_codegen->InvokeRuntime(entry_point_offset, at_, dex_pc_, this);
221    if (do_clinit_) {
222      CheckEntrypointTypes<kQuickInitializeStaticStorage, void*, uint32_t>();
223    } else {
224      CheckEntrypointTypes<kQuickInitializeType, void*, uint32_t>();
225    }
226
227    // Move the class to the desired location.
228    Location out = locations->Out();
229    if (out.IsValid()) {
230      DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
231      arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0));
232    }
233    RestoreLiveRegisters(codegen, locations);
234    __ b(GetExitLabel());
235  }
236
237  const char* GetDescription() const OVERRIDE { return "LoadClassSlowPathARM"; }
238
239 private:
240  // The class this slow path will load.
241  HLoadClass* const cls_;
242
243  // The instruction where this slow path is happening.
244  // (Might be the load class or an initialization check).
245  HInstruction* const at_;
246
247  // The dex PC of `at_`.
248  const uint32_t dex_pc_;
249
250  // Whether to initialize the class.
251  const bool do_clinit_;
252
253  DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathARM);
254};
255
256class LoadStringSlowPathARM : public SlowPathCode {
257 public:
258  explicit LoadStringSlowPathARM(HLoadString* instruction) : instruction_(instruction) {}
259
260  void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
261    LocationSummary* locations = instruction_->GetLocations();
262    DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
263
264    CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
265    __ Bind(GetEntryLabel());
266    SaveLiveRegisters(codegen, locations);
267
268    InvokeRuntimeCallingConvention calling_convention;
269    __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction_->GetStringIndex());
270    arm_codegen->InvokeRuntime(
271        QUICK_ENTRY_POINT(pResolveString), instruction_, instruction_->GetDexPc(), this);
272    CheckEntrypointTypes<kQuickResolveString, void*, uint32_t>();
273    arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0));
274
275    RestoreLiveRegisters(codegen, locations);
276    __ b(GetExitLabel());
277  }
278
279  const char* GetDescription() const OVERRIDE { return "LoadStringSlowPathARM"; }
280
281 private:
282  HLoadString* const instruction_;
283
284  DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathARM);
285};
286
287class TypeCheckSlowPathARM : public SlowPathCode {
288 public:
289  TypeCheckSlowPathARM(HInstruction* instruction, bool is_fatal)
290      : instruction_(instruction), is_fatal_(is_fatal) {}
291
292  void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
293    LocationSummary* locations = instruction_->GetLocations();
294    Location object_class = instruction_->IsCheckCast() ? locations->GetTemp(0)
295                                                        : locations->Out();
296    DCHECK(instruction_->IsCheckCast()
297           || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
298
299    CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
300    __ Bind(GetEntryLabel());
301
302    if (!is_fatal_) {
303      SaveLiveRegisters(codegen, locations);
304    }
305
306    // We're moving two locations to locations that could overlap, so we need a parallel
307    // move resolver.
308    InvokeRuntimeCallingConvention calling_convention;
309    codegen->EmitParallelMoves(
310        locations->InAt(1),
311        Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
312        Primitive::kPrimNot,
313        object_class,
314        Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
315        Primitive::kPrimNot);
316
317    if (instruction_->IsInstanceOf()) {
318      arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pInstanceofNonTrivial),
319                                 instruction_,
320                                 instruction_->GetDexPc(),
321                                 this);
322      CheckEntrypointTypes<
323          kQuickInstanceofNonTrivial, uint32_t, const mirror::Class*, const mirror::Class*>();
324      arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0));
325    } else {
326      DCHECK(instruction_->IsCheckCast());
327      arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pCheckCast),
328                                 instruction_,
329                                 instruction_->GetDexPc(),
330                                 this);
331      CheckEntrypointTypes<kQuickCheckCast, void, const mirror::Class*, const mirror::Class*>();
332    }
333
334    if (!is_fatal_) {
335      RestoreLiveRegisters(codegen, locations);
336      __ b(GetExitLabel());
337    }
338  }
339
340  const char* GetDescription() const OVERRIDE { return "TypeCheckSlowPathARM"; }
341
342  bool IsFatal() const OVERRIDE { return is_fatal_; }
343
344 private:
345  HInstruction* const instruction_;
346  const bool is_fatal_;
347
348  DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathARM);
349};
350
351class DeoptimizationSlowPathARM : public SlowPathCode {
352 public:
353  explicit DeoptimizationSlowPathARM(HInstruction* instruction)
354    : instruction_(instruction) {}
355
356  void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
357    __ Bind(GetEntryLabel());
358    SaveLiveRegisters(codegen, instruction_->GetLocations());
359    DCHECK(instruction_->IsDeoptimize());
360    HDeoptimize* deoptimize = instruction_->AsDeoptimize();
361    uint32_t dex_pc = deoptimize->GetDexPc();
362    CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
363    arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pDeoptimize), instruction_, dex_pc, this);
364    CheckEntrypointTypes<kQuickDeoptimize, void, void>();
365  }
366
367  const char* GetDescription() const OVERRIDE { return "DeoptimizationSlowPathARM"; }
368
369 private:
370  HInstruction* const instruction_;
371  DISALLOW_COPY_AND_ASSIGN(DeoptimizationSlowPathARM);
372};
373
374class ArraySetSlowPathARM : public SlowPathCode {
375 public:
376  explicit ArraySetSlowPathARM(HInstruction* instruction) : instruction_(instruction) {}
377
378  void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
379    LocationSummary* locations = instruction_->GetLocations();
380    __ Bind(GetEntryLabel());
381    SaveLiveRegisters(codegen, locations);
382
383    InvokeRuntimeCallingConvention calling_convention;
384    HParallelMove parallel_move(codegen->GetGraph()->GetArena());
385    parallel_move.AddMove(
386        locations->InAt(0),
387        Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
388        Primitive::kPrimNot,
389        nullptr);
390    parallel_move.AddMove(
391        locations->InAt(1),
392        Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
393        Primitive::kPrimInt,
394        nullptr);
395    parallel_move.AddMove(
396        locations->InAt(2),
397        Location::RegisterLocation(calling_convention.GetRegisterAt(2)),
398        Primitive::kPrimNot,
399        nullptr);
400    codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
401
402    CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
403    arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pAputObject),
404                               instruction_,
405                               instruction_->GetDexPc(),
406                               this);
407    CheckEntrypointTypes<kQuickAputObject, void, mirror::Array*, int32_t, mirror::Object*>();
408    RestoreLiveRegisters(codegen, locations);
409    __ b(GetExitLabel());
410  }
411
412  const char* GetDescription() const OVERRIDE { return "ArraySetSlowPathARM"; }
413
414 private:
415  HInstruction* const instruction_;
416
417  DISALLOW_COPY_AND_ASSIGN(ArraySetSlowPathARM);
418};
419
420// Slow path generating a read barrier for a heap reference.
421class ReadBarrierForHeapReferenceSlowPathARM : public SlowPathCode {
422 public:
423  ReadBarrierForHeapReferenceSlowPathARM(HInstruction* instruction,
424                                         Location out,
425                                         Location ref,
426                                         Location obj,
427                                         uint32_t offset,
428                                         Location index)
429      : instruction_(instruction),
430        out_(out),
431        ref_(ref),
432        obj_(obj),
433        offset_(offset),
434        index_(index) {
435    DCHECK(kEmitCompilerReadBarrier);
436    // If `obj` is equal to `out` or `ref`, it means the initial object
437    // has been overwritten by (or after) the heap object reference load
438    // to be instrumented, e.g.:
439    //
440    //   __ LoadFromOffset(kLoadWord, out, out, offset);
441    //   codegen_->GenerateReadBarrier(instruction, out_loc, out_loc, out_loc, offset);
442    //
443    // In that case, we have lost the information about the original
444    // object, and the emitted read barrier cannot work properly.
445    DCHECK(!obj.Equals(out)) << "obj=" << obj << " out=" << out;
446    DCHECK(!obj.Equals(ref)) << "obj=" << obj << " ref=" << ref;
447  }
448
449  void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
450    CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
451    LocationSummary* locations = instruction_->GetLocations();
452    Register reg_out = out_.AsRegister<Register>();
453    DCHECK(locations->CanCall());
454    DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(reg_out));
455    DCHECK(!instruction_->IsInvoke() ||
456           (instruction_->IsInvokeStaticOrDirect() &&
457            instruction_->GetLocations()->Intrinsified()));
458
459    __ Bind(GetEntryLabel());
460    SaveLiveRegisters(codegen, locations);
461
462    // We may have to change the index's value, but as `index_` is a
463    // constant member (like other "inputs" of this slow path),
464    // introduce a copy of it, `index`.
465    Location index = index_;
466    if (index_.IsValid()) {
467      // Handle `index_` for HArrayGet and intrinsic UnsafeGetObject.
468      if (instruction_->IsArrayGet()) {
469        // Compute the actual memory offset and store it in `index`.
470        Register index_reg = index_.AsRegister<Register>();
471        DCHECK(locations->GetLiveRegisters()->ContainsCoreRegister(index_reg));
472        if (codegen->IsCoreCalleeSaveRegister(index_reg)) {
473          // We are about to change the value of `index_reg` (see the
474          // calls to art::arm::Thumb2Assembler::Lsl and
475          // art::arm::Thumb2Assembler::AddConstant below), but it has
476          // not been saved by the previous call to
477          // art::SlowPathCode::SaveLiveRegisters, as it is a
478          // callee-save register --
479          // art::SlowPathCode::SaveLiveRegisters does not consider
480          // callee-save registers, as it has been designed with the
481          // assumption that callee-save registers are supposed to be
482          // handled by the called function.  So, as a callee-save
483          // register, `index_reg` _would_ eventually be saved onto
484          // the stack, but it would be too late: we would have
485          // changed its value earlier.  Therefore, we manually save
486          // it here into another freely available register,
487          // `free_reg`, chosen of course among the caller-save
488          // registers (as a callee-save `free_reg` register would
489          // exhibit the same problem).
490          //
491          // Note we could have requested a temporary register from
492          // the register allocator instead; but we prefer not to, as
493          // this is a slow path, and we know we can find a
494          // caller-save register that is available.
495          Register free_reg = FindAvailableCallerSaveRegister(codegen);
496          __ Mov(free_reg, index_reg);
497          index_reg = free_reg;
498          index = Location::RegisterLocation(index_reg);
499        } else {
500          // The initial register stored in `index_` has already been
501          // saved in the call to art::SlowPathCode::SaveLiveRegisters
502          // (as it is not a callee-save register), so we can freely
503          // use it.
504        }
505        // Shifting the index value contained in `index_reg` by the scale
506        // factor (2) cannot overflow in practice, as the runtime is
507        // unable to allocate object arrays with a size larger than
508        // 2^26 - 1 (that is, 2^28 - 4 bytes).
509        __ Lsl(index_reg, index_reg, TIMES_4);
510        static_assert(
511            sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
512            "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
513        __ AddConstant(index_reg, index_reg, offset_);
514      } else {
515        DCHECK(instruction_->IsInvoke());
516        DCHECK(instruction_->GetLocations()->Intrinsified());
517        DCHECK((instruction_->AsInvoke()->GetIntrinsic() == Intrinsics::kUnsafeGetObject) ||
518               (instruction_->AsInvoke()->GetIntrinsic() == Intrinsics::kUnsafeGetObjectVolatile))
519            << instruction_->AsInvoke()->GetIntrinsic();
520        DCHECK_EQ(offset_, 0U);
521        DCHECK(index_.IsRegisterPair());
522        // UnsafeGet's offset location is a register pair, the low
523        // part contains the correct offset.
524        index = index_.ToLow();
525      }
526    }
527
528    // We're moving two or three locations to locations that could
529    // overlap, so we need a parallel move resolver.
530    InvokeRuntimeCallingConvention calling_convention;
531    HParallelMove parallel_move(codegen->GetGraph()->GetArena());
532    parallel_move.AddMove(ref_,
533                          Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
534                          Primitive::kPrimNot,
535                          nullptr);
536    parallel_move.AddMove(obj_,
537                          Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
538                          Primitive::kPrimNot,
539                          nullptr);
540    if (index.IsValid()) {
541      parallel_move.AddMove(index,
542                            Location::RegisterLocation(calling_convention.GetRegisterAt(2)),
543                            Primitive::kPrimInt,
544                            nullptr);
545      codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
546    } else {
547      codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
548      __ LoadImmediate(calling_convention.GetRegisterAt(2), offset_);
549    }
550    arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pReadBarrierSlow),
551                               instruction_,
552                               instruction_->GetDexPc(),
553                               this);
554    CheckEntrypointTypes<
555        kQuickReadBarrierSlow, mirror::Object*, mirror::Object*, mirror::Object*, uint32_t>();
556    arm_codegen->Move32(out_, Location::RegisterLocation(R0));
557
558    RestoreLiveRegisters(codegen, locations);
559    __ b(GetExitLabel());
560  }
561
562  const char* GetDescription() const OVERRIDE { return "ReadBarrierForHeapReferenceSlowPathARM"; }
563
564 private:
565  Register FindAvailableCallerSaveRegister(CodeGenerator* codegen) {
566    size_t ref = static_cast<int>(ref_.AsRegister<Register>());
567    size_t obj = static_cast<int>(obj_.AsRegister<Register>());
568    for (size_t i = 0, e = codegen->GetNumberOfCoreRegisters(); i < e; ++i) {
569      if (i != ref && i != obj && !codegen->IsCoreCalleeSaveRegister(i)) {
570        return static_cast<Register>(i);
571      }
572    }
573    // We shall never fail to find a free caller-save register, as
574    // there are more than two core caller-save registers on ARM
575    // (meaning it is possible to find one which is different from
576    // `ref` and `obj`).
577    DCHECK_GT(codegen->GetNumberOfCoreCallerSaveRegisters(), 2u);
578    LOG(FATAL) << "Could not find a free caller-save register";
579    UNREACHABLE();
580  }
581
582  HInstruction* const instruction_;
583  const Location out_;
584  const Location ref_;
585  const Location obj_;
586  const uint32_t offset_;
587  // An additional location containing an index to an array.
588  // Only used for HArrayGet and the UnsafeGetObject &
589  // UnsafeGetObjectVolatile intrinsics.
590  const Location index_;
591
592  DISALLOW_COPY_AND_ASSIGN(ReadBarrierForHeapReferenceSlowPathARM);
593};
594
595// Slow path generating a read barrier for a GC root.
596class ReadBarrierForRootSlowPathARM : public SlowPathCode {
597 public:
598  ReadBarrierForRootSlowPathARM(HInstruction* instruction, Location out, Location root)
599      : instruction_(instruction), out_(out), root_(root) {}
600
601  void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
602    LocationSummary* locations = instruction_->GetLocations();
603    Register reg_out = out_.AsRegister<Register>();
604    DCHECK(locations->CanCall());
605    DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(reg_out));
606    DCHECK(instruction_->IsLoadClass() || instruction_->IsLoadString());
607
608    __ Bind(GetEntryLabel());
609    SaveLiveRegisters(codegen, locations);
610
611    InvokeRuntimeCallingConvention calling_convention;
612    CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
613    arm_codegen->Move32(Location::RegisterLocation(calling_convention.GetRegisterAt(0)), root_);
614    arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pReadBarrierForRootSlow),
615                               instruction_,
616                               instruction_->GetDexPc(),
617                               this);
618    CheckEntrypointTypes<kQuickReadBarrierForRootSlow, mirror::Object*, GcRoot<mirror::Object>*>();
619    arm_codegen->Move32(out_, Location::RegisterLocation(R0));
620
621    RestoreLiveRegisters(codegen, locations);
622    __ b(GetExitLabel());
623  }
624
625  const char* GetDescription() const OVERRIDE { return "ReadBarrierForRootSlowPathARM"; }
626
627 private:
628  HInstruction* const instruction_;
629  const Location out_;
630  const Location root_;
631
632  DISALLOW_COPY_AND_ASSIGN(ReadBarrierForRootSlowPathARM);
633};
634
635#undef __
636#define __ down_cast<ArmAssembler*>(GetAssembler())->
637
638inline Condition ARMCondition(IfCondition cond) {
639  switch (cond) {
640    case kCondEQ: return EQ;
641    case kCondNE: return NE;
642    case kCondLT: return LT;
643    case kCondLE: return LE;
644    case kCondGT: return GT;
645    case kCondGE: return GE;
646    case kCondB:  return LO;
647    case kCondBE: return LS;
648    case kCondA:  return HI;
649    case kCondAE: return HS;
650  }
651  LOG(FATAL) << "Unreachable";
652  UNREACHABLE();
653}
654
655// Maps signed condition to unsigned condition.
656inline Condition ARMUnsignedCondition(IfCondition cond) {
657  switch (cond) {
658    case kCondEQ: return EQ;
659    case kCondNE: return NE;
660    // Signed to unsigned.
661    case kCondLT: return LO;
662    case kCondLE: return LS;
663    case kCondGT: return HI;
664    case kCondGE: return HS;
665    // Unsigned remain unchanged.
666    case kCondB:  return LO;
667    case kCondBE: return LS;
668    case kCondA:  return HI;
669    case kCondAE: return HS;
670  }
671  LOG(FATAL) << "Unreachable";
672  UNREACHABLE();
673}
674
675void CodeGeneratorARM::DumpCoreRegister(std::ostream& stream, int reg) const {
676  stream << Register(reg);
677}
678
679void CodeGeneratorARM::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
680  stream << SRegister(reg);
681}
682
683size_t CodeGeneratorARM::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
684  __ StoreToOffset(kStoreWord, static_cast<Register>(reg_id), SP, stack_index);
685  return kArmWordSize;
686}
687
688size_t CodeGeneratorARM::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
689  __ LoadFromOffset(kLoadWord, static_cast<Register>(reg_id), SP, stack_index);
690  return kArmWordSize;
691}
692
693size_t CodeGeneratorARM::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
694  __ StoreSToOffset(static_cast<SRegister>(reg_id), SP, stack_index);
695  return kArmWordSize;
696}
697
698size_t CodeGeneratorARM::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
699  __ LoadSFromOffset(static_cast<SRegister>(reg_id), SP, stack_index);
700  return kArmWordSize;
701}
702
703CodeGeneratorARM::CodeGeneratorARM(HGraph* graph,
704                                   const ArmInstructionSetFeatures& isa_features,
705                                   const CompilerOptions& compiler_options,
706                                   OptimizingCompilerStats* stats)
707    : CodeGenerator(graph,
708                    kNumberOfCoreRegisters,
709                    kNumberOfSRegisters,
710                    kNumberOfRegisterPairs,
711                    ComputeRegisterMask(reinterpret_cast<const int*>(kCoreCalleeSaves),
712                                        arraysize(kCoreCalleeSaves)),
713                    ComputeRegisterMask(reinterpret_cast<const int*>(kFpuCalleeSaves),
714                                        arraysize(kFpuCalleeSaves)),
715                    compiler_options,
716                    stats),
717      block_labels_(nullptr),
718      location_builder_(graph, this),
719      instruction_visitor_(graph, this),
720      move_resolver_(graph->GetArena(), this),
721      assembler_(),
722      isa_features_(isa_features),
723      method_patches_(MethodReferenceComparator(),
724                      graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
725      call_patches_(MethodReferenceComparator(),
726                    graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
727      relative_call_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
728      dex_cache_arrays_base_labels_(std::less<HArmDexCacheArraysBase*>(),
729                                    graph->GetArena()->Adapter(kArenaAllocCodeGenerator)) {
730  // Always save the LR register to mimic Quick.
731  AddAllocatedRegister(Location::RegisterLocation(LR));
732}
733
734void CodeGeneratorARM::Finalize(CodeAllocator* allocator) {
735  // Ensure that we fix up branches and literal loads and emit the literal pool.
736  __ FinalizeCode();
737
738  // Adjust native pc offsets in stack maps.
739  for (size_t i = 0, num = stack_map_stream_.GetNumberOfStackMaps(); i != num; ++i) {
740    uint32_t old_position = stack_map_stream_.GetStackMap(i).native_pc_offset;
741    uint32_t new_position = __ GetAdjustedPosition(old_position);
742    stack_map_stream_.SetStackMapNativePcOffset(i, new_position);
743  }
744  // Adjust pc offsets for the disassembly information.
745  if (disasm_info_ != nullptr) {
746    GeneratedCodeInterval* frame_entry_interval = disasm_info_->GetFrameEntryInterval();
747    frame_entry_interval->start = __ GetAdjustedPosition(frame_entry_interval->start);
748    frame_entry_interval->end = __ GetAdjustedPosition(frame_entry_interval->end);
749    for (auto& it : *disasm_info_->GetInstructionIntervals()) {
750      it.second.start = __ GetAdjustedPosition(it.second.start);
751      it.second.end = __ GetAdjustedPosition(it.second.end);
752    }
753    for (auto& it : *disasm_info_->GetSlowPathIntervals()) {
754      it.code_interval.start = __ GetAdjustedPosition(it.code_interval.start);
755      it.code_interval.end = __ GetAdjustedPosition(it.code_interval.end);
756    }
757  }
758
759  CodeGenerator::Finalize(allocator);
760}
761
762Location CodeGeneratorARM::AllocateFreeRegister(Primitive::Type type) const {
763  switch (type) {
764    case Primitive::kPrimLong: {
765      size_t reg = FindFreeEntry(blocked_register_pairs_, kNumberOfRegisterPairs);
766      ArmManagedRegister pair =
767          ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(reg));
768      DCHECK(!blocked_core_registers_[pair.AsRegisterPairLow()]);
769      DCHECK(!blocked_core_registers_[pair.AsRegisterPairHigh()]);
770
771      blocked_core_registers_[pair.AsRegisterPairLow()] = true;
772      blocked_core_registers_[pair.AsRegisterPairHigh()] = true;
773      UpdateBlockedPairRegisters();
774      return Location::RegisterPairLocation(pair.AsRegisterPairLow(), pair.AsRegisterPairHigh());
775    }
776
777    case Primitive::kPrimByte:
778    case Primitive::kPrimBoolean:
779    case Primitive::kPrimChar:
780    case Primitive::kPrimShort:
781    case Primitive::kPrimInt:
782    case Primitive::kPrimNot: {
783      int reg = FindFreeEntry(blocked_core_registers_, kNumberOfCoreRegisters);
784      // Block all register pairs that contain `reg`.
785      for (int i = 0; i < kNumberOfRegisterPairs; i++) {
786        ArmManagedRegister current =
787            ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
788        if (current.AsRegisterPairLow() == reg || current.AsRegisterPairHigh() == reg) {
789          blocked_register_pairs_[i] = true;
790        }
791      }
792      return Location::RegisterLocation(reg);
793    }
794
795    case Primitive::kPrimFloat: {
796      int reg = FindFreeEntry(blocked_fpu_registers_, kNumberOfSRegisters);
797      return Location::FpuRegisterLocation(reg);
798    }
799
800    case Primitive::kPrimDouble: {
801      int reg = FindTwoFreeConsecutiveAlignedEntries(blocked_fpu_registers_, kNumberOfSRegisters);
802      DCHECK_EQ(reg % 2, 0);
803      return Location::FpuRegisterPairLocation(reg, reg + 1);
804    }
805
806    case Primitive::kPrimVoid:
807      LOG(FATAL) << "Unreachable type " << type;
808  }
809
810  return Location::NoLocation();
811}
812
813void CodeGeneratorARM::SetupBlockedRegisters(bool is_baseline) const {
814  // Don't allocate the dalvik style register pair passing.
815  blocked_register_pairs_[R1_R2] = true;
816
817  // Stack register, LR and PC are always reserved.
818  blocked_core_registers_[SP] = true;
819  blocked_core_registers_[LR] = true;
820  blocked_core_registers_[PC] = true;
821
822  // Reserve thread register.
823  blocked_core_registers_[TR] = true;
824
825  // Reserve temp register.
826  blocked_core_registers_[IP] = true;
827
828  if (is_baseline) {
829    for (size_t i = 0; i < arraysize(kCoreCalleeSaves); ++i) {
830      blocked_core_registers_[kCoreCalleeSaves[i]] = true;
831    }
832
833    blocked_core_registers_[kCoreSavedRegisterForBaseline] = false;
834  }
835
836  if (is_baseline || GetGraph()->IsDebuggable()) {
837    // Stubs do not save callee-save floating point registers. If the graph
838    // is debuggable, we need to deal with these registers differently. For
839    // now, just block them.
840    for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
841      blocked_fpu_registers_[kFpuCalleeSaves[i]] = true;
842    }
843  }
844
845  UpdateBlockedPairRegisters();
846}
847
848void CodeGeneratorARM::UpdateBlockedPairRegisters() const {
849  for (int i = 0; i < kNumberOfRegisterPairs; i++) {
850    ArmManagedRegister current =
851        ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
852    if (blocked_core_registers_[current.AsRegisterPairLow()]
853        || blocked_core_registers_[current.AsRegisterPairHigh()]) {
854      blocked_register_pairs_[i] = true;
855    }
856  }
857}
858
859InstructionCodeGeneratorARM::InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen)
860      : HGraphVisitor(graph),
861        assembler_(codegen->GetAssembler()),
862        codegen_(codegen) {}
863
864void CodeGeneratorARM::ComputeSpillMask() {
865  core_spill_mask_ = allocated_registers_.GetCoreRegisters() & core_callee_save_mask_;
866  // Save one extra register for baseline. Note that on thumb2, there is no easy
867  // instruction to restore just the PC, so this actually helps both baseline
868  // and non-baseline to save and restore at least two registers at entry and exit.
869  core_spill_mask_ |= (1 << kCoreSavedRegisterForBaseline);
870  DCHECK_NE(core_spill_mask_, 0u) << "At least the return address register must be saved";
871  fpu_spill_mask_ = allocated_registers_.GetFloatingPointRegisters() & fpu_callee_save_mask_;
872  // We use vpush and vpop for saving and restoring floating point registers, which take
873  // a SRegister and the number of registers to save/restore after that SRegister. We
874  // therefore update the `fpu_spill_mask_` to also contain those registers not allocated,
875  // but in the range.
876  if (fpu_spill_mask_ != 0) {
877    uint32_t least_significant_bit = LeastSignificantBit(fpu_spill_mask_);
878    uint32_t most_significant_bit = MostSignificantBit(fpu_spill_mask_);
879    for (uint32_t i = least_significant_bit + 1 ; i < most_significant_bit; ++i) {
880      fpu_spill_mask_ |= (1 << i);
881    }
882  }
883}
884
885static dwarf::Reg DWARFReg(Register reg) {
886  return dwarf::Reg::ArmCore(static_cast<int>(reg));
887}
888
889static dwarf::Reg DWARFReg(SRegister reg) {
890  return dwarf::Reg::ArmFp(static_cast<int>(reg));
891}
892
893void CodeGeneratorARM::GenerateFrameEntry() {
894  bool skip_overflow_check =
895      IsLeafMethod() && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kArm);
896  DCHECK(GetCompilerOptions().GetImplicitStackOverflowChecks());
897  __ Bind(&frame_entry_label_);
898
899  if (HasEmptyFrame()) {
900    return;
901  }
902
903  if (!skip_overflow_check) {
904    __ AddConstant(IP, SP, -static_cast<int32_t>(GetStackOverflowReservedBytes(kArm)));
905    __ LoadFromOffset(kLoadWord, IP, IP, 0);
906    RecordPcInfo(nullptr, 0);
907  }
908
909  __ PushList(core_spill_mask_);
910  __ cfi().AdjustCFAOffset(kArmWordSize * POPCOUNT(core_spill_mask_));
911  __ cfi().RelOffsetForMany(DWARFReg(kMethodRegisterArgument), 0, core_spill_mask_, kArmWordSize);
912  if (fpu_spill_mask_ != 0) {
913    SRegister start_register = SRegister(LeastSignificantBit(fpu_spill_mask_));
914    __ vpushs(start_register, POPCOUNT(fpu_spill_mask_));
915    __ cfi().AdjustCFAOffset(kArmWordSize * POPCOUNT(fpu_spill_mask_));
916    __ cfi().RelOffsetForMany(DWARFReg(S0), 0, fpu_spill_mask_, kArmWordSize);
917  }
918  int adjust = GetFrameSize() - FrameEntrySpillSize();
919  __ AddConstant(SP, -adjust);
920  __ cfi().AdjustCFAOffset(adjust);
921  __ StoreToOffset(kStoreWord, kMethodRegisterArgument, SP, 0);
922}
923
924void CodeGeneratorARM::GenerateFrameExit() {
925  if (HasEmptyFrame()) {
926    __ bx(LR);
927    return;
928  }
929  __ cfi().RememberState();
930  int adjust = GetFrameSize() - FrameEntrySpillSize();
931  __ AddConstant(SP, adjust);
932  __ cfi().AdjustCFAOffset(-adjust);
933  if (fpu_spill_mask_ != 0) {
934    SRegister start_register = SRegister(LeastSignificantBit(fpu_spill_mask_));
935    __ vpops(start_register, POPCOUNT(fpu_spill_mask_));
936    __ cfi().AdjustCFAOffset(-kArmPointerSize * POPCOUNT(fpu_spill_mask_));
937    __ cfi().RestoreMany(DWARFReg(SRegister(0)), fpu_spill_mask_);
938  }
939  // Pop LR into PC to return.
940  DCHECK_NE(core_spill_mask_ & (1 << LR), 0U);
941  uint32_t pop_mask = (core_spill_mask_ & (~(1 << LR))) | 1 << PC;
942  __ PopList(pop_mask);
943  __ cfi().RestoreState();
944  __ cfi().DefCFAOffset(GetFrameSize());
945}
946
947void CodeGeneratorARM::Bind(HBasicBlock* block) {
948  Label* label = GetLabelOf(block);
949  __ BindTrackedLabel(label);
950}
951
952Location CodeGeneratorARM::GetStackLocation(HLoadLocal* load) const {
953  switch (load->GetType()) {
954    case Primitive::kPrimLong:
955    case Primitive::kPrimDouble:
956      return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
957
958    case Primitive::kPrimInt:
959    case Primitive::kPrimNot:
960    case Primitive::kPrimFloat:
961      return Location::StackSlot(GetStackSlot(load->GetLocal()));
962
963    case Primitive::kPrimBoolean:
964    case Primitive::kPrimByte:
965    case Primitive::kPrimChar:
966    case Primitive::kPrimShort:
967    case Primitive::kPrimVoid:
968      LOG(FATAL) << "Unexpected type " << load->GetType();
969      UNREACHABLE();
970  }
971
972  LOG(FATAL) << "Unreachable";
973  UNREACHABLE();
974}
975
976Location InvokeDexCallingConventionVisitorARM::GetNextLocation(Primitive::Type type) {
977  switch (type) {
978    case Primitive::kPrimBoolean:
979    case Primitive::kPrimByte:
980    case Primitive::kPrimChar:
981    case Primitive::kPrimShort:
982    case Primitive::kPrimInt:
983    case Primitive::kPrimNot: {
984      uint32_t index = gp_index_++;
985      uint32_t stack_index = stack_index_++;
986      if (index < calling_convention.GetNumberOfRegisters()) {
987        return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
988      } else {
989        return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index));
990      }
991    }
992
993    case Primitive::kPrimLong: {
994      uint32_t index = gp_index_;
995      uint32_t stack_index = stack_index_;
996      gp_index_ += 2;
997      stack_index_ += 2;
998      if (index + 1 < calling_convention.GetNumberOfRegisters()) {
999        if (calling_convention.GetRegisterAt(index) == R1) {
1000          // Skip R1, and use R2_R3 instead.
1001          gp_index_++;
1002          index++;
1003        }
1004      }
1005      if (index + 1 < calling_convention.GetNumberOfRegisters()) {
1006        DCHECK_EQ(calling_convention.GetRegisterAt(index) + 1,
1007                  calling_convention.GetRegisterAt(index + 1));
1008
1009        return Location::RegisterPairLocation(calling_convention.GetRegisterAt(index),
1010                                              calling_convention.GetRegisterAt(index + 1));
1011      } else {
1012        return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index));
1013      }
1014    }
1015
1016    case Primitive::kPrimFloat: {
1017      uint32_t stack_index = stack_index_++;
1018      if (float_index_ % 2 == 0) {
1019        float_index_ = std::max(double_index_, float_index_);
1020      }
1021      if (float_index_ < calling_convention.GetNumberOfFpuRegisters()) {
1022        return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(float_index_++));
1023      } else {
1024        return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index));
1025      }
1026    }
1027
1028    case Primitive::kPrimDouble: {
1029      double_index_ = std::max(double_index_, RoundUp(float_index_, 2));
1030      uint32_t stack_index = stack_index_;
1031      stack_index_ += 2;
1032      if (double_index_ + 1 < calling_convention.GetNumberOfFpuRegisters()) {
1033        uint32_t index = double_index_;
1034        double_index_ += 2;
1035        Location result = Location::FpuRegisterPairLocation(
1036          calling_convention.GetFpuRegisterAt(index),
1037          calling_convention.GetFpuRegisterAt(index + 1));
1038        DCHECK(ExpectedPairLayout(result));
1039        return result;
1040      } else {
1041        return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index));
1042      }
1043    }
1044
1045    case Primitive::kPrimVoid:
1046      LOG(FATAL) << "Unexpected parameter type " << type;
1047      break;
1048  }
1049  return Location::NoLocation();
1050}
1051
1052Location InvokeDexCallingConventionVisitorARM::GetReturnLocation(Primitive::Type type) const {
1053  switch (type) {
1054    case Primitive::kPrimBoolean:
1055    case Primitive::kPrimByte:
1056    case Primitive::kPrimChar:
1057    case Primitive::kPrimShort:
1058    case Primitive::kPrimInt:
1059    case Primitive::kPrimNot: {
1060      return Location::RegisterLocation(R0);
1061    }
1062
1063    case Primitive::kPrimFloat: {
1064      return Location::FpuRegisterLocation(S0);
1065    }
1066
1067    case Primitive::kPrimLong: {
1068      return Location::RegisterPairLocation(R0, R1);
1069    }
1070
1071    case Primitive::kPrimDouble: {
1072      return Location::FpuRegisterPairLocation(S0, S1);
1073    }
1074
1075    case Primitive::kPrimVoid:
1076      return Location::NoLocation();
1077  }
1078
1079  UNREACHABLE();
1080}
1081
1082Location InvokeDexCallingConventionVisitorARM::GetMethodLocation() const {
1083  return Location::RegisterLocation(kMethodRegisterArgument);
1084}
1085
1086void CodeGeneratorARM::Move32(Location destination, Location source) {
1087  if (source.Equals(destination)) {
1088    return;
1089  }
1090  if (destination.IsRegister()) {
1091    if (source.IsRegister()) {
1092      __ Mov(destination.AsRegister<Register>(), source.AsRegister<Register>());
1093    } else if (source.IsFpuRegister()) {
1094      __ vmovrs(destination.AsRegister<Register>(), source.AsFpuRegister<SRegister>());
1095    } else {
1096      __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(), SP, source.GetStackIndex());
1097    }
1098  } else if (destination.IsFpuRegister()) {
1099    if (source.IsRegister()) {
1100      __ vmovsr(destination.AsFpuRegister<SRegister>(), source.AsRegister<Register>());
1101    } else if (source.IsFpuRegister()) {
1102      __ vmovs(destination.AsFpuRegister<SRegister>(), source.AsFpuRegister<SRegister>());
1103    } else {
1104      __ LoadSFromOffset(destination.AsFpuRegister<SRegister>(), SP, source.GetStackIndex());
1105    }
1106  } else {
1107    DCHECK(destination.IsStackSlot()) << destination;
1108    if (source.IsRegister()) {
1109      __ StoreToOffset(kStoreWord, source.AsRegister<Register>(), SP, destination.GetStackIndex());
1110    } else if (source.IsFpuRegister()) {
1111      __ StoreSToOffset(source.AsFpuRegister<SRegister>(), SP, destination.GetStackIndex());
1112    } else {
1113      DCHECK(source.IsStackSlot()) << source;
1114      __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
1115      __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
1116    }
1117  }
1118}
1119
1120void CodeGeneratorARM::Move64(Location destination, Location source) {
1121  if (source.Equals(destination)) {
1122    return;
1123  }
1124  if (destination.IsRegisterPair()) {
1125    if (source.IsRegisterPair()) {
1126      EmitParallelMoves(
1127          Location::RegisterLocation(source.AsRegisterPairHigh<Register>()),
1128          Location::RegisterLocation(destination.AsRegisterPairHigh<Register>()),
1129          Primitive::kPrimInt,
1130          Location::RegisterLocation(source.AsRegisterPairLow<Register>()),
1131          Location::RegisterLocation(destination.AsRegisterPairLow<Register>()),
1132          Primitive::kPrimInt);
1133    } else if (source.IsFpuRegister()) {
1134      UNIMPLEMENTED(FATAL);
1135    } else if (source.IsFpuRegisterPair()) {
1136      __ vmovrrd(destination.AsRegisterPairLow<Register>(),
1137                 destination.AsRegisterPairHigh<Register>(),
1138                 FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()));
1139    } else {
1140      DCHECK(source.IsDoubleStackSlot());
1141      DCHECK(ExpectedPairLayout(destination));
1142      __ LoadFromOffset(kLoadWordPair, destination.AsRegisterPairLow<Register>(),
1143                        SP, source.GetStackIndex());
1144    }
1145  } else if (destination.IsFpuRegisterPair()) {
1146    if (source.IsDoubleStackSlot()) {
1147      __ LoadDFromOffset(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
1148                         SP,
1149                         source.GetStackIndex());
1150    } else if (source.IsRegisterPair()) {
1151      __ vmovdrr(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
1152                 source.AsRegisterPairLow<Register>(),
1153                 source.AsRegisterPairHigh<Register>());
1154    } else {
1155      UNIMPLEMENTED(FATAL);
1156    }
1157  } else {
1158    DCHECK(destination.IsDoubleStackSlot());
1159    if (source.IsRegisterPair()) {
1160      // No conflict possible, so just do the moves.
1161      if (source.AsRegisterPairLow<Register>() == R1) {
1162        DCHECK_EQ(source.AsRegisterPairHigh<Register>(), R2);
1163        __ StoreToOffset(kStoreWord, R1, SP, destination.GetStackIndex());
1164        __ StoreToOffset(kStoreWord, R2, SP, destination.GetHighStackIndex(kArmWordSize));
1165      } else {
1166        __ StoreToOffset(kStoreWordPair, source.AsRegisterPairLow<Register>(),
1167                         SP, destination.GetStackIndex());
1168      }
1169    } else if (source.IsFpuRegisterPair()) {
1170      __ StoreDToOffset(FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()),
1171                        SP,
1172                        destination.GetStackIndex());
1173    } else {
1174      DCHECK(source.IsDoubleStackSlot());
1175      EmitParallelMoves(
1176          Location::StackSlot(source.GetStackIndex()),
1177          Location::StackSlot(destination.GetStackIndex()),
1178          Primitive::kPrimInt,
1179          Location::StackSlot(source.GetHighStackIndex(kArmWordSize)),
1180          Location::StackSlot(destination.GetHighStackIndex(kArmWordSize)),
1181          Primitive::kPrimInt);
1182    }
1183  }
1184}
1185
1186void CodeGeneratorARM::Move(HInstruction* instruction, Location location, HInstruction* move_for) {
1187  LocationSummary* locations = instruction->GetLocations();
1188  if (instruction->IsCurrentMethod()) {
1189    Move32(location, Location::StackSlot(kCurrentMethodStackOffset));
1190  } else if (locations != nullptr && locations->Out().Equals(location)) {
1191    return;
1192  } else if (locations != nullptr && locations->Out().IsConstant()) {
1193    HConstant* const_to_move = locations->Out().GetConstant();
1194    if (const_to_move->IsIntConstant() || const_to_move->IsNullConstant()) {
1195      int32_t value = GetInt32ValueOf(const_to_move);
1196      if (location.IsRegister()) {
1197        __ LoadImmediate(location.AsRegister<Register>(), value);
1198      } else {
1199        DCHECK(location.IsStackSlot());
1200        __ LoadImmediate(IP, value);
1201        __ StoreToOffset(kStoreWord, IP, SP, location.GetStackIndex());
1202      }
1203    } else {
1204      DCHECK(const_to_move->IsLongConstant()) << const_to_move->DebugName();
1205      int64_t value = const_to_move->AsLongConstant()->GetValue();
1206      if (location.IsRegisterPair()) {
1207        __ LoadImmediate(location.AsRegisterPairLow<Register>(), Low32Bits(value));
1208        __ LoadImmediate(location.AsRegisterPairHigh<Register>(), High32Bits(value));
1209      } else {
1210        DCHECK(location.IsDoubleStackSlot());
1211        __ LoadImmediate(IP, Low32Bits(value));
1212        __ StoreToOffset(kStoreWord, IP, SP, location.GetStackIndex());
1213        __ LoadImmediate(IP, High32Bits(value));
1214        __ StoreToOffset(kStoreWord, IP, SP, location.GetHighStackIndex(kArmWordSize));
1215      }
1216    }
1217  } else if (instruction->IsLoadLocal()) {
1218    uint32_t stack_slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
1219    switch (instruction->GetType()) {
1220      case Primitive::kPrimBoolean:
1221      case Primitive::kPrimByte:
1222      case Primitive::kPrimChar:
1223      case Primitive::kPrimShort:
1224      case Primitive::kPrimInt:
1225      case Primitive::kPrimNot:
1226      case Primitive::kPrimFloat:
1227        Move32(location, Location::StackSlot(stack_slot));
1228        break;
1229
1230      case Primitive::kPrimLong:
1231      case Primitive::kPrimDouble:
1232        Move64(location, Location::DoubleStackSlot(stack_slot));
1233        break;
1234
1235      default:
1236        LOG(FATAL) << "Unexpected type " << instruction->GetType();
1237    }
1238  } else if (instruction->IsTemporary()) {
1239    Location temp_location = GetTemporaryLocation(instruction->AsTemporary());
1240    if (temp_location.IsStackSlot()) {
1241      Move32(location, temp_location);
1242    } else {
1243      DCHECK(temp_location.IsDoubleStackSlot());
1244      Move64(location, temp_location);
1245    }
1246  } else {
1247    DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
1248    switch (instruction->GetType()) {
1249      case Primitive::kPrimBoolean:
1250      case Primitive::kPrimByte:
1251      case Primitive::kPrimChar:
1252      case Primitive::kPrimShort:
1253      case Primitive::kPrimNot:
1254      case Primitive::kPrimInt:
1255      case Primitive::kPrimFloat:
1256        Move32(location, locations->Out());
1257        break;
1258
1259      case Primitive::kPrimLong:
1260      case Primitive::kPrimDouble:
1261        Move64(location, locations->Out());
1262        break;
1263
1264      default:
1265        LOG(FATAL) << "Unexpected type " << instruction->GetType();
1266    }
1267  }
1268}
1269
1270void CodeGeneratorARM::MoveConstant(Location location, int32_t value) {
1271  DCHECK(location.IsRegister());
1272  __ LoadImmediate(location.AsRegister<Register>(), value);
1273}
1274
1275void CodeGeneratorARM::MoveLocation(Location dst, Location src, Primitive::Type dst_type) {
1276  if (Primitive::Is64BitType(dst_type)) {
1277    Move64(dst, src);
1278  } else {
1279    Move32(dst, src);
1280  }
1281}
1282
1283void CodeGeneratorARM::AddLocationAsTemp(Location location, LocationSummary* locations) {
1284  if (location.IsRegister()) {
1285    locations->AddTemp(location);
1286  } else if (location.IsRegisterPair()) {
1287    locations->AddTemp(Location::RegisterLocation(location.AsRegisterPairLow<Register>()));
1288    locations->AddTemp(Location::RegisterLocation(location.AsRegisterPairHigh<Register>()));
1289  } else {
1290    UNIMPLEMENTED(FATAL) << "AddLocationAsTemp not implemented for location " << location;
1291  }
1292}
1293
1294void CodeGeneratorARM::InvokeRuntime(QuickEntrypointEnum entrypoint,
1295                                     HInstruction* instruction,
1296                                     uint32_t dex_pc,
1297                                     SlowPathCode* slow_path) {
1298  InvokeRuntime(GetThreadOffset<kArmWordSize>(entrypoint).Int32Value(),
1299                instruction,
1300                dex_pc,
1301                slow_path);
1302}
1303
1304void CodeGeneratorARM::InvokeRuntime(int32_t entry_point_offset,
1305                                     HInstruction* instruction,
1306                                     uint32_t dex_pc,
1307                                     SlowPathCode* slow_path) {
1308  ValidateInvokeRuntime(instruction, slow_path);
1309  __ LoadFromOffset(kLoadWord, LR, TR, entry_point_offset);
1310  __ blx(LR);
1311  RecordPcInfo(instruction, dex_pc, slow_path);
1312}
1313
1314void InstructionCodeGeneratorARM::HandleGoto(HInstruction* got, HBasicBlock* successor) {
1315  DCHECK(!successor->IsExitBlock());
1316
1317  HBasicBlock* block = got->GetBlock();
1318  HInstruction* previous = got->GetPrevious();
1319
1320  HLoopInformation* info = block->GetLoopInformation();
1321  if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
1322    codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck());
1323    GenerateSuspendCheck(info->GetSuspendCheck(), successor);
1324    return;
1325  }
1326
1327  if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
1328    GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
1329  }
1330  if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
1331    __ b(codegen_->GetLabelOf(successor));
1332  }
1333}
1334
1335void LocationsBuilderARM::VisitGoto(HGoto* got) {
1336  got->SetLocations(nullptr);
1337}
1338
1339void InstructionCodeGeneratorARM::VisitGoto(HGoto* got) {
1340  HandleGoto(got, got->GetSuccessor());
1341}
1342
1343void LocationsBuilderARM::VisitTryBoundary(HTryBoundary* try_boundary) {
1344  try_boundary->SetLocations(nullptr);
1345}
1346
1347void InstructionCodeGeneratorARM::VisitTryBoundary(HTryBoundary* try_boundary) {
1348  HBasicBlock* successor = try_boundary->GetNormalFlowSuccessor();
1349  if (!successor->IsExitBlock()) {
1350    HandleGoto(try_boundary, successor);
1351  }
1352}
1353
1354void LocationsBuilderARM::VisitExit(HExit* exit) {
1355  exit->SetLocations(nullptr);
1356}
1357
1358void InstructionCodeGeneratorARM::VisitExit(HExit* exit ATTRIBUTE_UNUSED) {
1359}
1360
1361void InstructionCodeGeneratorARM::GenerateCompareWithImmediate(Register left, int32_t right) {
1362  ShifterOperand operand;
1363  if (GetAssembler()->ShifterOperandCanHold(R0, left, CMP, right, &operand)) {
1364    __ cmp(left, operand);
1365  } else {
1366    Register temp = IP;
1367    __ LoadImmediate(temp, right);
1368    __ cmp(left, ShifterOperand(temp));
1369  }
1370}
1371
1372void InstructionCodeGeneratorARM::GenerateFPJumps(HCondition* cond,
1373                                                  Label* true_label,
1374                                                  Label* false_label) {
1375  __ vmstat();  // transfer FP status register to ARM APSR.
1376  // TODO: merge into a single branch (except "equal or unordered" and "not equal")
1377  if (cond->IsFPConditionTrueIfNaN()) {
1378    __ b(true_label, VS);  // VS for unordered.
1379  } else if (cond->IsFPConditionFalseIfNaN()) {
1380    __ b(false_label, VS);  // VS for unordered.
1381  }
1382  __ b(true_label, ARMCondition(cond->GetCondition()));
1383}
1384
1385void InstructionCodeGeneratorARM::GenerateLongComparesAndJumps(HCondition* cond,
1386                                                               Label* true_label,
1387                                                               Label* false_label) {
1388  LocationSummary* locations = cond->GetLocations();
1389  Location left = locations->InAt(0);
1390  Location right = locations->InAt(1);
1391  IfCondition if_cond = cond->GetCondition();
1392
1393  Register left_high = left.AsRegisterPairHigh<Register>();
1394  Register left_low = left.AsRegisterPairLow<Register>();
1395  IfCondition true_high_cond = if_cond;
1396  IfCondition false_high_cond = cond->GetOppositeCondition();
1397  Condition final_condition = ARMUnsignedCondition(if_cond);  // unsigned on lower part
1398
1399  // Set the conditions for the test, remembering that == needs to be
1400  // decided using the low words.
1401  // TODO: consider avoiding jumps with temporary and CMP low+SBC high
1402  switch (if_cond) {
1403    case kCondEQ:
1404    case kCondNE:
1405      // Nothing to do.
1406      break;
1407    case kCondLT:
1408      false_high_cond = kCondGT;
1409      break;
1410    case kCondLE:
1411      true_high_cond = kCondLT;
1412      break;
1413    case kCondGT:
1414      false_high_cond = kCondLT;
1415      break;
1416    case kCondGE:
1417      true_high_cond = kCondGT;
1418      break;
1419    case kCondB:
1420      false_high_cond = kCondA;
1421      break;
1422    case kCondBE:
1423      true_high_cond = kCondB;
1424      break;
1425    case kCondA:
1426      false_high_cond = kCondB;
1427      break;
1428    case kCondAE:
1429      true_high_cond = kCondA;
1430      break;
1431  }
1432  if (right.IsConstant()) {
1433    int64_t value = right.GetConstant()->AsLongConstant()->GetValue();
1434    int32_t val_low = Low32Bits(value);
1435    int32_t val_high = High32Bits(value);
1436
1437    GenerateCompareWithImmediate(left_high, val_high);
1438    if (if_cond == kCondNE) {
1439      __ b(true_label, ARMCondition(true_high_cond));
1440    } else if (if_cond == kCondEQ) {
1441      __ b(false_label, ARMCondition(false_high_cond));
1442    } else {
1443      __ b(true_label, ARMCondition(true_high_cond));
1444      __ b(false_label, ARMCondition(false_high_cond));
1445    }
1446    // Must be equal high, so compare the lows.
1447    GenerateCompareWithImmediate(left_low, val_low);
1448  } else {
1449    Register right_high = right.AsRegisterPairHigh<Register>();
1450    Register right_low = right.AsRegisterPairLow<Register>();
1451
1452    __ cmp(left_high, ShifterOperand(right_high));
1453    if (if_cond == kCondNE) {
1454      __ b(true_label, ARMCondition(true_high_cond));
1455    } else if (if_cond == kCondEQ) {
1456      __ b(false_label, ARMCondition(false_high_cond));
1457    } else {
1458      __ b(true_label, ARMCondition(true_high_cond));
1459      __ b(false_label, ARMCondition(false_high_cond));
1460    }
1461    // Must be equal high, so compare the lows.
1462    __ cmp(left_low, ShifterOperand(right_low));
1463  }
1464  // The last comparison might be unsigned.
1465  // TODO: optimize cases where this is always true/false
1466  __ b(true_label, final_condition);
1467}
1468
1469void InstructionCodeGeneratorARM::GenerateCompareTestAndBranch(HCondition* condition,
1470                                                               Label* true_target_in,
1471                                                               Label* false_target_in) {
1472  // Generated branching requires both targets to be explicit. If either of the
1473  // targets is nullptr (fallthrough) use and bind `fallthrough_target` instead.
1474  Label fallthrough_target;
1475  Label* true_target = true_target_in == nullptr ? &fallthrough_target : true_target_in;
1476  Label* false_target = false_target_in == nullptr ? &fallthrough_target : false_target_in;
1477
1478  LocationSummary* locations = condition->GetLocations();
1479  Location left = locations->InAt(0);
1480  Location right = locations->InAt(1);
1481
1482  Primitive::Type type = condition->InputAt(0)->GetType();
1483  switch (type) {
1484    case Primitive::kPrimLong:
1485      GenerateLongComparesAndJumps(condition, true_target, false_target);
1486      break;
1487    case Primitive::kPrimFloat:
1488      __ vcmps(left.AsFpuRegister<SRegister>(), right.AsFpuRegister<SRegister>());
1489      GenerateFPJumps(condition, true_target, false_target);
1490      break;
1491    case Primitive::kPrimDouble:
1492      __ vcmpd(FromLowSToD(left.AsFpuRegisterPairLow<SRegister>()),
1493               FromLowSToD(right.AsFpuRegisterPairLow<SRegister>()));
1494      GenerateFPJumps(condition, true_target, false_target);
1495      break;
1496    default:
1497      LOG(FATAL) << "Unexpected compare type " << type;
1498  }
1499
1500  if (false_target != &fallthrough_target) {
1501    __ b(false_target);
1502  }
1503
1504  if (fallthrough_target.IsLinked()) {
1505    __ Bind(&fallthrough_target);
1506  }
1507}
1508
1509void InstructionCodeGeneratorARM::GenerateTestAndBranch(HInstruction* instruction,
1510                                                        size_t condition_input_index,
1511                                                        Label* true_target,
1512                                                        Label* false_target) {
1513  HInstruction* cond = instruction->InputAt(condition_input_index);
1514
1515  if (true_target == nullptr && false_target == nullptr) {
1516    // Nothing to do. The code always falls through.
1517    return;
1518  } else if (cond->IsIntConstant()) {
1519    // Constant condition, statically compared against 1.
1520    if (cond->AsIntConstant()->IsOne()) {
1521      if (true_target != nullptr) {
1522        __ b(true_target);
1523      }
1524    } else {
1525      DCHECK(cond->AsIntConstant()->IsZero());
1526      if (false_target != nullptr) {
1527        __ b(false_target);
1528      }
1529    }
1530    return;
1531  }
1532
1533  // The following code generates these patterns:
1534  //  (1) true_target == nullptr && false_target != nullptr
1535  //        - opposite condition true => branch to false_target
1536  //  (2) true_target != nullptr && false_target == nullptr
1537  //        - condition true => branch to true_target
1538  //  (3) true_target != nullptr && false_target != nullptr
1539  //        - condition true => branch to true_target
1540  //        - branch to false_target
1541  if (IsBooleanValueOrMaterializedCondition(cond)) {
1542    // Condition has been materialized, compare the output to 0.
1543    Location cond_val = instruction->GetLocations()->InAt(condition_input_index);
1544    DCHECK(cond_val.IsRegister());
1545    if (true_target == nullptr) {
1546      __ CompareAndBranchIfZero(cond_val.AsRegister<Register>(), false_target);
1547    } else {
1548      __ CompareAndBranchIfNonZero(cond_val.AsRegister<Register>(), true_target);
1549    }
1550  } else {
1551    // Condition has not been materialized. Use its inputs as the comparison and
1552    // its condition as the branch condition.
1553    HCondition* condition = cond->AsCondition();
1554
1555    // If this is a long or FP comparison that has been folded into
1556    // the HCondition, generate the comparison directly.
1557    Primitive::Type type = condition->InputAt(0)->GetType();
1558    if (type == Primitive::kPrimLong || Primitive::IsFloatingPointType(type)) {
1559      GenerateCompareTestAndBranch(condition, true_target, false_target);
1560      return;
1561    }
1562
1563    LocationSummary* locations = cond->GetLocations();
1564    DCHECK(locations->InAt(0).IsRegister());
1565    Register left = locations->InAt(0).AsRegister<Register>();
1566    Location right = locations->InAt(1);
1567    if (right.IsRegister()) {
1568      __ cmp(left, ShifterOperand(right.AsRegister<Register>()));
1569    } else {
1570      DCHECK(right.IsConstant());
1571      GenerateCompareWithImmediate(left, CodeGenerator::GetInt32ValueOf(right.GetConstant()));
1572    }
1573    if (true_target == nullptr) {
1574      __ b(false_target, ARMCondition(condition->GetOppositeCondition()));
1575    } else {
1576      __ b(true_target, ARMCondition(condition->GetCondition()));
1577    }
1578  }
1579
1580  // If neither branch falls through (case 3), the conditional branch to `true_target`
1581  // was already emitted (case 2) and we need to emit a jump to `false_target`.
1582  if (true_target != nullptr && false_target != nullptr) {
1583    __ b(false_target);
1584  }
1585}
1586
1587void LocationsBuilderARM::VisitIf(HIf* if_instr) {
1588  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr);
1589  if (IsBooleanValueOrMaterializedCondition(if_instr->InputAt(0))) {
1590    locations->SetInAt(0, Location::RequiresRegister());
1591  }
1592}
1593
1594void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) {
1595  HBasicBlock* true_successor = if_instr->IfTrueSuccessor();
1596  HBasicBlock* false_successor = if_instr->IfFalseSuccessor();
1597  Label* true_target = codegen_->GoesToNextBlock(if_instr->GetBlock(), true_successor) ?
1598      nullptr : codegen_->GetLabelOf(true_successor);
1599  Label* false_target = codegen_->GoesToNextBlock(if_instr->GetBlock(), false_successor) ?
1600      nullptr : codegen_->GetLabelOf(false_successor);
1601  GenerateTestAndBranch(if_instr, /* condition_input_index */ 0, true_target, false_target);
1602}
1603
1604void LocationsBuilderARM::VisitDeoptimize(HDeoptimize* deoptimize) {
1605  LocationSummary* locations = new (GetGraph()->GetArena())
1606      LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
1607  if (IsBooleanValueOrMaterializedCondition(deoptimize->InputAt(0))) {
1608    locations->SetInAt(0, Location::RequiresRegister());
1609  }
1610}
1611
1612void InstructionCodeGeneratorARM::VisitDeoptimize(HDeoptimize* deoptimize) {
1613  SlowPathCode* slow_path = new (GetGraph()->GetArena()) DeoptimizationSlowPathARM(deoptimize);
1614  codegen_->AddSlowPath(slow_path);
1615  GenerateTestAndBranch(deoptimize,
1616                        /* condition_input_index */ 0,
1617                        slow_path->GetEntryLabel(),
1618                        /* false_target */ nullptr);
1619}
1620
1621void LocationsBuilderARM::VisitNativeDebugInfo(HNativeDebugInfo* info) {
1622  new (GetGraph()->GetArena()) LocationSummary(info);
1623}
1624
1625void InstructionCodeGeneratorARM::VisitNativeDebugInfo(HNativeDebugInfo* info) {
1626  codegen_->RecordPcInfo(info, info->GetDexPc());
1627}
1628
1629void LocationsBuilderARM::HandleCondition(HCondition* cond) {
1630  LocationSummary* locations =
1631      new (GetGraph()->GetArena()) LocationSummary(cond, LocationSummary::kNoCall);
1632  // Handle the long/FP comparisons made in instruction simplification.
1633  switch (cond->InputAt(0)->GetType()) {
1634    case Primitive::kPrimLong:
1635      locations->SetInAt(0, Location::RequiresRegister());
1636      locations->SetInAt(1, Location::RegisterOrConstant(cond->InputAt(1)));
1637      if (cond->NeedsMaterialization()) {
1638        locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
1639      }
1640      break;
1641
1642    case Primitive::kPrimFloat:
1643    case Primitive::kPrimDouble:
1644      locations->SetInAt(0, Location::RequiresFpuRegister());
1645      locations->SetInAt(1, Location::RequiresFpuRegister());
1646      if (cond->NeedsMaterialization()) {
1647        locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1648      }
1649      break;
1650
1651    default:
1652      locations->SetInAt(0, Location::RequiresRegister());
1653      locations->SetInAt(1, Location::RegisterOrConstant(cond->InputAt(1)));
1654      if (cond->NeedsMaterialization()) {
1655        locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1656      }
1657  }
1658}
1659
1660void InstructionCodeGeneratorARM::HandleCondition(HCondition* cond) {
1661  if (!cond->NeedsMaterialization()) {
1662    return;
1663  }
1664
1665  LocationSummary* locations = cond->GetLocations();
1666  Location left = locations->InAt(0);
1667  Location right = locations->InAt(1);
1668  Register out = locations->Out().AsRegister<Register>();
1669  Label true_label, false_label;
1670
1671  switch (cond->InputAt(0)->GetType()) {
1672    default: {
1673      // Integer case.
1674      if (right.IsRegister()) {
1675        __ cmp(left.AsRegister<Register>(), ShifterOperand(right.AsRegister<Register>()));
1676      } else {
1677        DCHECK(right.IsConstant());
1678        GenerateCompareWithImmediate(left.AsRegister<Register>(),
1679                                     CodeGenerator::GetInt32ValueOf(right.GetConstant()));
1680      }
1681      __ it(ARMCondition(cond->GetCondition()), kItElse);
1682      __ mov(locations->Out().AsRegister<Register>(), ShifterOperand(1),
1683             ARMCondition(cond->GetCondition()));
1684      __ mov(locations->Out().AsRegister<Register>(), ShifterOperand(0),
1685             ARMCondition(cond->GetOppositeCondition()));
1686      return;
1687    }
1688    case Primitive::kPrimLong:
1689      GenerateLongComparesAndJumps(cond, &true_label, &false_label);
1690      break;
1691    case Primitive::kPrimFloat:
1692      __ vcmps(left.AsFpuRegister<SRegister>(), right.AsFpuRegister<SRegister>());
1693      GenerateFPJumps(cond, &true_label, &false_label);
1694      break;
1695    case Primitive::kPrimDouble:
1696      __ vcmpd(FromLowSToD(left.AsFpuRegisterPairLow<SRegister>()),
1697               FromLowSToD(right.AsFpuRegisterPairLow<SRegister>()));
1698      GenerateFPJumps(cond, &true_label, &false_label);
1699      break;
1700  }
1701
1702  // Convert the jumps into the result.
1703  Label done_label;
1704
1705  // False case: result = 0.
1706  __ Bind(&false_label);
1707  __ LoadImmediate(out, 0);
1708  __ b(&done_label);
1709
1710  // True case: result = 1.
1711  __ Bind(&true_label);
1712  __ LoadImmediate(out, 1);
1713  __ Bind(&done_label);
1714}
1715
1716void LocationsBuilderARM::VisitEqual(HEqual* comp) {
1717  HandleCondition(comp);
1718}
1719
1720void InstructionCodeGeneratorARM::VisitEqual(HEqual* comp) {
1721  HandleCondition(comp);
1722}
1723
1724void LocationsBuilderARM::VisitNotEqual(HNotEqual* comp) {
1725  HandleCondition(comp);
1726}
1727
1728void InstructionCodeGeneratorARM::VisitNotEqual(HNotEqual* comp) {
1729  HandleCondition(comp);
1730}
1731
1732void LocationsBuilderARM::VisitLessThan(HLessThan* comp) {
1733  HandleCondition(comp);
1734}
1735
1736void InstructionCodeGeneratorARM::VisitLessThan(HLessThan* comp) {
1737  HandleCondition(comp);
1738}
1739
1740void LocationsBuilderARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1741  HandleCondition(comp);
1742}
1743
1744void InstructionCodeGeneratorARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1745  HandleCondition(comp);
1746}
1747
1748void LocationsBuilderARM::VisitGreaterThan(HGreaterThan* comp) {
1749  HandleCondition(comp);
1750}
1751
1752void InstructionCodeGeneratorARM::VisitGreaterThan(HGreaterThan* comp) {
1753  HandleCondition(comp);
1754}
1755
1756void LocationsBuilderARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1757  HandleCondition(comp);
1758}
1759
1760void InstructionCodeGeneratorARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1761  HandleCondition(comp);
1762}
1763
1764void LocationsBuilderARM::VisitBelow(HBelow* comp) {
1765  HandleCondition(comp);
1766}
1767
1768void InstructionCodeGeneratorARM::VisitBelow(HBelow* comp) {
1769  HandleCondition(comp);
1770}
1771
1772void LocationsBuilderARM::VisitBelowOrEqual(HBelowOrEqual* comp) {
1773  HandleCondition(comp);
1774}
1775
1776void InstructionCodeGeneratorARM::VisitBelowOrEqual(HBelowOrEqual* comp) {
1777  HandleCondition(comp);
1778}
1779
1780void LocationsBuilderARM::VisitAbove(HAbove* comp) {
1781  HandleCondition(comp);
1782}
1783
1784void InstructionCodeGeneratorARM::VisitAbove(HAbove* comp) {
1785  HandleCondition(comp);
1786}
1787
1788void LocationsBuilderARM::VisitAboveOrEqual(HAboveOrEqual* comp) {
1789  HandleCondition(comp);
1790}
1791
1792void InstructionCodeGeneratorARM::VisitAboveOrEqual(HAboveOrEqual* comp) {
1793  HandleCondition(comp);
1794}
1795
1796void LocationsBuilderARM::VisitLocal(HLocal* local) {
1797  local->SetLocations(nullptr);
1798}
1799
1800void InstructionCodeGeneratorARM::VisitLocal(HLocal* local) {
1801  DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
1802}
1803
1804void LocationsBuilderARM::VisitLoadLocal(HLoadLocal* load) {
1805  load->SetLocations(nullptr);
1806}
1807
1808void InstructionCodeGeneratorARM::VisitLoadLocal(HLoadLocal* load ATTRIBUTE_UNUSED) {
1809  // Nothing to do, this is driven by the code generator.
1810}
1811
1812void LocationsBuilderARM::VisitStoreLocal(HStoreLocal* store) {
1813  LocationSummary* locations =
1814      new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
1815  switch (store->InputAt(1)->GetType()) {
1816    case Primitive::kPrimBoolean:
1817    case Primitive::kPrimByte:
1818    case Primitive::kPrimChar:
1819    case Primitive::kPrimShort:
1820    case Primitive::kPrimInt:
1821    case Primitive::kPrimNot:
1822    case Primitive::kPrimFloat:
1823      locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
1824      break;
1825
1826    case Primitive::kPrimLong:
1827    case Primitive::kPrimDouble:
1828      locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
1829      break;
1830
1831    default:
1832      LOG(FATAL) << "Unexpected local type " << store->InputAt(1)->GetType();
1833  }
1834}
1835
1836void InstructionCodeGeneratorARM::VisitStoreLocal(HStoreLocal* store ATTRIBUTE_UNUSED) {
1837}
1838
1839void LocationsBuilderARM::VisitIntConstant(HIntConstant* constant) {
1840  LocationSummary* locations =
1841      new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1842  locations->SetOut(Location::ConstantLocation(constant));
1843}
1844
1845void InstructionCodeGeneratorARM::VisitIntConstant(HIntConstant* constant ATTRIBUTE_UNUSED) {
1846  // Will be generated at use site.
1847}
1848
1849void LocationsBuilderARM::VisitNullConstant(HNullConstant* constant) {
1850  LocationSummary* locations =
1851      new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1852  locations->SetOut(Location::ConstantLocation(constant));
1853}
1854
1855void InstructionCodeGeneratorARM::VisitNullConstant(HNullConstant* constant ATTRIBUTE_UNUSED) {
1856  // Will be generated at use site.
1857}
1858
1859void LocationsBuilderARM::VisitLongConstant(HLongConstant* constant) {
1860  LocationSummary* locations =
1861      new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1862  locations->SetOut(Location::ConstantLocation(constant));
1863}
1864
1865void InstructionCodeGeneratorARM::VisitLongConstant(HLongConstant* constant ATTRIBUTE_UNUSED) {
1866  // Will be generated at use site.
1867}
1868
1869void LocationsBuilderARM::VisitFloatConstant(HFloatConstant* constant) {
1870  LocationSummary* locations =
1871      new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1872  locations->SetOut(Location::ConstantLocation(constant));
1873}
1874
1875void InstructionCodeGeneratorARM::VisitFloatConstant(HFloatConstant* constant ATTRIBUTE_UNUSED) {
1876  // Will be generated at use site.
1877}
1878
1879void LocationsBuilderARM::VisitDoubleConstant(HDoubleConstant* constant) {
1880  LocationSummary* locations =
1881      new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1882  locations->SetOut(Location::ConstantLocation(constant));
1883}
1884
1885void InstructionCodeGeneratorARM::VisitDoubleConstant(HDoubleConstant* constant ATTRIBUTE_UNUSED) {
1886  // Will be generated at use site.
1887}
1888
1889void LocationsBuilderARM::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
1890  memory_barrier->SetLocations(nullptr);
1891}
1892
1893void InstructionCodeGeneratorARM::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
1894  GenerateMemoryBarrier(memory_barrier->GetBarrierKind());
1895}
1896
1897void LocationsBuilderARM::VisitReturnVoid(HReturnVoid* ret) {
1898  ret->SetLocations(nullptr);
1899}
1900
1901void InstructionCodeGeneratorARM::VisitReturnVoid(HReturnVoid* ret ATTRIBUTE_UNUSED) {
1902  codegen_->GenerateFrameExit();
1903}
1904
1905void LocationsBuilderARM::VisitReturn(HReturn* ret) {
1906  LocationSummary* locations =
1907      new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
1908  locations->SetInAt(0, parameter_visitor_.GetReturnLocation(ret->InputAt(0)->GetType()));
1909}
1910
1911void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret ATTRIBUTE_UNUSED) {
1912  codegen_->GenerateFrameExit();
1913}
1914
1915void LocationsBuilderARM::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
1916  // The trampoline uses the same calling convention as dex calling conventions,
1917  // except instead of loading arg0/r0 with the target Method*, arg0/r0 will contain
1918  // the method_idx.
1919  HandleInvoke(invoke);
1920}
1921
1922void InstructionCodeGeneratorARM::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
1923  codegen_->GenerateInvokeUnresolvedRuntimeCall(invoke);
1924}
1925
1926void LocationsBuilderARM::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
1927  // When we do not run baseline, explicit clinit checks triggered by static
1928  // invokes must have been pruned by art::PrepareForRegisterAllocation.
1929  DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck());
1930
1931  IntrinsicLocationsBuilderARM intrinsic(GetGraph()->GetArena(),
1932                                         codegen_->GetAssembler(),
1933                                         codegen_->GetInstructionSetFeatures());
1934  if (intrinsic.TryDispatch(invoke)) {
1935    if (invoke->GetLocations()->CanCall() && invoke->HasPcRelativeDexCache()) {
1936      invoke->GetLocations()->SetInAt(invoke->GetSpecialInputIndex(), Location::Any());
1937    }
1938    return;
1939  }
1940
1941  HandleInvoke(invoke);
1942
1943  // For PC-relative dex cache the invoke has an extra input, the PC-relative address base.
1944  if (invoke->HasPcRelativeDexCache()) {
1945    invoke->GetLocations()->SetInAt(invoke->GetSpecialInputIndex(), Location::RequiresRegister());
1946  }
1947}
1948
1949static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorARM* codegen) {
1950  if (invoke->GetLocations()->Intrinsified()) {
1951    IntrinsicCodeGeneratorARM intrinsic(codegen);
1952    intrinsic.Dispatch(invoke);
1953    return true;
1954  }
1955  return false;
1956}
1957
1958void InstructionCodeGeneratorARM::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
1959  // When we do not run baseline, explicit clinit checks triggered by static
1960  // invokes must have been pruned by art::PrepareForRegisterAllocation.
1961  DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck());
1962
1963  if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1964    return;
1965  }
1966
1967  LocationSummary* locations = invoke->GetLocations();
1968  codegen_->GenerateStaticOrDirectCall(
1969      invoke, locations->HasTemps() ? locations->GetTemp(0) : Location::NoLocation());
1970  codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1971}
1972
1973void LocationsBuilderARM::HandleInvoke(HInvoke* invoke) {
1974  InvokeDexCallingConventionVisitorARM calling_convention_visitor;
1975  CodeGenerator::CreateCommonInvokeLocationSummary(invoke, &calling_convention_visitor);
1976}
1977
1978void LocationsBuilderARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
1979  IntrinsicLocationsBuilderARM intrinsic(GetGraph()->GetArena(),
1980                                         codegen_->GetAssembler(),
1981                                         codegen_->GetInstructionSetFeatures());
1982  if (intrinsic.TryDispatch(invoke)) {
1983    return;
1984  }
1985
1986  HandleInvoke(invoke);
1987}
1988
1989void InstructionCodeGeneratorARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
1990  if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1991    return;
1992  }
1993
1994  codegen_->GenerateVirtualCall(invoke, invoke->GetLocations()->GetTemp(0));
1995  DCHECK(!codegen_->IsLeafMethod());
1996  codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1997}
1998
1999void LocationsBuilderARM::VisitInvokeInterface(HInvokeInterface* invoke) {
2000  HandleInvoke(invoke);
2001  // Add the hidden argument.
2002  invoke->GetLocations()->AddTemp(Location::RegisterLocation(R12));
2003}
2004
2005void InstructionCodeGeneratorARM::VisitInvokeInterface(HInvokeInterface* invoke) {
2006  // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
2007  LocationSummary* locations = invoke->GetLocations();
2008  Register temp = locations->GetTemp(0).AsRegister<Register>();
2009  Register hidden_reg = locations->GetTemp(1).AsRegister<Register>();
2010  uint32_t method_offset = mirror::Class::EmbeddedImTableEntryOffset(
2011      invoke->GetImtIndex() % mirror::Class::kImtSize, kArmPointerSize).Uint32Value();
2012  Location receiver = locations->InAt(0);
2013  uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
2014
2015  // Set the hidden argument. This is safe to do this here, as R12
2016  // won't be modified thereafter, before the `blx` (call) instruction.
2017  DCHECK_EQ(R12, hidden_reg);
2018  __ LoadImmediate(hidden_reg, invoke->GetDexMethodIndex());
2019
2020  if (receiver.IsStackSlot()) {
2021    __ LoadFromOffset(kLoadWord, temp, SP, receiver.GetStackIndex());
2022    // /* HeapReference<Class> */ temp = temp->klass_
2023    __ LoadFromOffset(kLoadWord, temp, temp, class_offset);
2024  } else {
2025    // /* HeapReference<Class> */ temp = receiver->klass_
2026    __ LoadFromOffset(kLoadWord, temp, receiver.AsRegister<Register>(), class_offset);
2027  }
2028  codegen_->MaybeRecordImplicitNullCheck(invoke);
2029  // Instead of simply (possibly) unpoisoning `temp` here, we should
2030  // emit a read barrier for the previous class reference load.
2031  // However this is not required in practice, as this is an
2032  // intermediate/temporary reference and because the current
2033  // concurrent copying collector keeps the from-space memory
2034  // intact/accessible until the end of the marking phase (the
2035  // concurrent copying collector may not in the future).
2036  __ MaybeUnpoisonHeapReference(temp);
2037  // temp = temp->GetImtEntryAt(method_offset);
2038  uint32_t entry_point =
2039      ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArmWordSize).Int32Value();
2040  __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
2041  // LR = temp->GetEntryPoint();
2042  __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
2043  // LR();
2044  __ blx(LR);
2045  DCHECK(!codegen_->IsLeafMethod());
2046  codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
2047}
2048
2049void LocationsBuilderARM::VisitNeg(HNeg* neg) {
2050  LocationSummary* locations =
2051      new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
2052  switch (neg->GetResultType()) {
2053    case Primitive::kPrimInt: {
2054      locations->SetInAt(0, Location::RequiresRegister());
2055      locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2056      break;
2057    }
2058    case Primitive::kPrimLong: {
2059      locations->SetInAt(0, Location::RequiresRegister());
2060      locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
2061      break;
2062    }
2063
2064    case Primitive::kPrimFloat:
2065    case Primitive::kPrimDouble:
2066      locations->SetInAt(0, Location::RequiresFpuRegister());
2067      locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
2068      break;
2069
2070    default:
2071      LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
2072  }
2073}
2074
2075void InstructionCodeGeneratorARM::VisitNeg(HNeg* neg) {
2076  LocationSummary* locations = neg->GetLocations();
2077  Location out = locations->Out();
2078  Location in = locations->InAt(0);
2079  switch (neg->GetResultType()) {
2080    case Primitive::kPrimInt:
2081      DCHECK(in.IsRegister());
2082      __ rsb(out.AsRegister<Register>(), in.AsRegister<Register>(), ShifterOperand(0));
2083      break;
2084
2085    case Primitive::kPrimLong:
2086      DCHECK(in.IsRegisterPair());
2087      // out.lo = 0 - in.lo (and update the carry/borrow (C) flag)
2088      __ rsbs(out.AsRegisterPairLow<Register>(),
2089              in.AsRegisterPairLow<Register>(),
2090              ShifterOperand(0));
2091      // We cannot emit an RSC (Reverse Subtract with Carry)
2092      // instruction here, as it does not exist in the Thumb-2
2093      // instruction set.  We use the following approach
2094      // using SBC and SUB instead.
2095      //
2096      // out.hi = -C
2097      __ sbc(out.AsRegisterPairHigh<Register>(),
2098             out.AsRegisterPairHigh<Register>(),
2099             ShifterOperand(out.AsRegisterPairHigh<Register>()));
2100      // out.hi = out.hi - in.hi
2101      __ sub(out.AsRegisterPairHigh<Register>(),
2102             out.AsRegisterPairHigh<Register>(),
2103             ShifterOperand(in.AsRegisterPairHigh<Register>()));
2104      break;
2105
2106    case Primitive::kPrimFloat:
2107      DCHECK(in.IsFpuRegister());
2108      __ vnegs(out.AsFpuRegister<SRegister>(), in.AsFpuRegister<SRegister>());
2109      break;
2110
2111    case Primitive::kPrimDouble:
2112      DCHECK(in.IsFpuRegisterPair());
2113      __ vnegd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2114               FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
2115      break;
2116
2117    default:
2118      LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
2119  }
2120}
2121
2122void LocationsBuilderARM::VisitTypeConversion(HTypeConversion* conversion) {
2123  Primitive::Type result_type = conversion->GetResultType();
2124  Primitive::Type input_type = conversion->GetInputType();
2125  DCHECK_NE(result_type, input_type);
2126
2127  // The float-to-long, double-to-long and long-to-float type conversions
2128  // rely on a call to the runtime.
2129  LocationSummary::CallKind call_kind =
2130      (((input_type == Primitive::kPrimFloat || input_type == Primitive::kPrimDouble)
2131        && result_type == Primitive::kPrimLong)
2132       || (input_type == Primitive::kPrimLong && result_type == Primitive::kPrimFloat))
2133      ? LocationSummary::kCall
2134      : LocationSummary::kNoCall;
2135  LocationSummary* locations =
2136      new (GetGraph()->GetArena()) LocationSummary(conversion, call_kind);
2137
2138  // The Java language does not allow treating boolean as an integral type but
2139  // our bit representation makes it safe.
2140
2141  switch (result_type) {
2142    case Primitive::kPrimByte:
2143      switch (input_type) {
2144        case Primitive::kPrimBoolean:
2145          // Boolean input is a result of code transformations.
2146        case Primitive::kPrimShort:
2147        case Primitive::kPrimInt:
2148        case Primitive::kPrimChar:
2149          // Processing a Dex `int-to-byte' instruction.
2150          locations->SetInAt(0, Location::RequiresRegister());
2151          locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2152          break;
2153
2154        default:
2155          LOG(FATAL) << "Unexpected type conversion from " << input_type
2156                     << " to " << result_type;
2157      }
2158      break;
2159
2160    case Primitive::kPrimShort:
2161      switch (input_type) {
2162        case Primitive::kPrimBoolean:
2163          // Boolean input is a result of code transformations.
2164        case Primitive::kPrimByte:
2165        case Primitive::kPrimInt:
2166        case Primitive::kPrimChar:
2167          // Processing a Dex `int-to-short' instruction.
2168          locations->SetInAt(0, Location::RequiresRegister());
2169          locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2170          break;
2171
2172        default:
2173          LOG(FATAL) << "Unexpected type conversion from " << input_type
2174                     << " to " << result_type;
2175      }
2176      break;
2177
2178    case Primitive::kPrimInt:
2179      switch (input_type) {
2180        case Primitive::kPrimLong:
2181          // Processing a Dex `long-to-int' instruction.
2182          locations->SetInAt(0, Location::Any());
2183          locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2184          break;
2185
2186        case Primitive::kPrimFloat:
2187          // Processing a Dex `float-to-int' instruction.
2188          locations->SetInAt(0, Location::RequiresFpuRegister());
2189          locations->SetOut(Location::RequiresRegister());
2190          locations->AddTemp(Location::RequiresFpuRegister());
2191          break;
2192
2193        case Primitive::kPrimDouble:
2194          // Processing a Dex `double-to-int' instruction.
2195          locations->SetInAt(0, Location::RequiresFpuRegister());
2196          locations->SetOut(Location::RequiresRegister());
2197          locations->AddTemp(Location::RequiresFpuRegister());
2198          break;
2199
2200        default:
2201          LOG(FATAL) << "Unexpected type conversion from " << input_type
2202                     << " to " << result_type;
2203      }
2204      break;
2205
2206    case Primitive::kPrimLong:
2207      switch (input_type) {
2208        case Primitive::kPrimBoolean:
2209          // Boolean input is a result of code transformations.
2210        case Primitive::kPrimByte:
2211        case Primitive::kPrimShort:
2212        case Primitive::kPrimInt:
2213        case Primitive::kPrimChar:
2214          // Processing a Dex `int-to-long' instruction.
2215          locations->SetInAt(0, Location::RequiresRegister());
2216          locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2217          break;
2218
2219        case Primitive::kPrimFloat: {
2220          // Processing a Dex `float-to-long' instruction.
2221          InvokeRuntimeCallingConvention calling_convention;
2222          locations->SetInAt(0, Location::FpuRegisterLocation(
2223              calling_convention.GetFpuRegisterAt(0)));
2224          locations->SetOut(Location::RegisterPairLocation(R0, R1));
2225          break;
2226        }
2227
2228        case Primitive::kPrimDouble: {
2229          // Processing a Dex `double-to-long' instruction.
2230          InvokeRuntimeCallingConvention calling_convention;
2231          locations->SetInAt(0, Location::FpuRegisterPairLocation(
2232              calling_convention.GetFpuRegisterAt(0),
2233              calling_convention.GetFpuRegisterAt(1)));
2234          locations->SetOut(Location::RegisterPairLocation(R0, R1));
2235          break;
2236        }
2237
2238        default:
2239          LOG(FATAL) << "Unexpected type conversion from " << input_type
2240                     << " to " << result_type;
2241      }
2242      break;
2243
2244    case Primitive::kPrimChar:
2245      switch (input_type) {
2246        case Primitive::kPrimBoolean:
2247          // Boolean input is a result of code transformations.
2248        case Primitive::kPrimByte:
2249        case Primitive::kPrimShort:
2250        case Primitive::kPrimInt:
2251          // Processing a Dex `int-to-char' instruction.
2252          locations->SetInAt(0, Location::RequiresRegister());
2253          locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2254          break;
2255
2256        default:
2257          LOG(FATAL) << "Unexpected type conversion from " << input_type
2258                     << " to " << result_type;
2259      }
2260      break;
2261
2262    case Primitive::kPrimFloat:
2263      switch (input_type) {
2264        case Primitive::kPrimBoolean:
2265          // Boolean input is a result of code transformations.
2266        case Primitive::kPrimByte:
2267        case Primitive::kPrimShort:
2268        case Primitive::kPrimInt:
2269        case Primitive::kPrimChar:
2270          // Processing a Dex `int-to-float' instruction.
2271          locations->SetInAt(0, Location::RequiresRegister());
2272          locations->SetOut(Location::RequiresFpuRegister());
2273          break;
2274
2275        case Primitive::kPrimLong: {
2276          // Processing a Dex `long-to-float' instruction.
2277          InvokeRuntimeCallingConvention calling_convention;
2278          locations->SetInAt(0, Location::RegisterPairLocation(
2279              calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
2280          locations->SetOut(Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
2281          break;
2282        }
2283
2284        case Primitive::kPrimDouble:
2285          // Processing a Dex `double-to-float' instruction.
2286          locations->SetInAt(0, Location::RequiresFpuRegister());
2287          locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
2288          break;
2289
2290        default:
2291          LOG(FATAL) << "Unexpected type conversion from " << input_type
2292                     << " to " << result_type;
2293      };
2294      break;
2295
2296    case Primitive::kPrimDouble:
2297      switch (input_type) {
2298        case Primitive::kPrimBoolean:
2299          // Boolean input is a result of code transformations.
2300        case Primitive::kPrimByte:
2301        case Primitive::kPrimShort:
2302        case Primitive::kPrimInt:
2303        case Primitive::kPrimChar:
2304          // Processing a Dex `int-to-double' instruction.
2305          locations->SetInAt(0, Location::RequiresRegister());
2306          locations->SetOut(Location::RequiresFpuRegister());
2307          break;
2308
2309        case Primitive::kPrimLong:
2310          // Processing a Dex `long-to-double' instruction.
2311          locations->SetInAt(0, Location::RequiresRegister());
2312          locations->SetOut(Location::RequiresFpuRegister());
2313          locations->AddTemp(Location::RequiresFpuRegister());
2314          locations->AddTemp(Location::RequiresFpuRegister());
2315          break;
2316
2317        case Primitive::kPrimFloat:
2318          // Processing a Dex `float-to-double' instruction.
2319          locations->SetInAt(0, Location::RequiresFpuRegister());
2320          locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
2321          break;
2322
2323        default:
2324          LOG(FATAL) << "Unexpected type conversion from " << input_type
2325                     << " to " << result_type;
2326      };
2327      break;
2328
2329    default:
2330      LOG(FATAL) << "Unexpected type conversion from " << input_type
2331                 << " to " << result_type;
2332  }
2333}
2334
2335void InstructionCodeGeneratorARM::VisitTypeConversion(HTypeConversion* conversion) {
2336  LocationSummary* locations = conversion->GetLocations();
2337  Location out = locations->Out();
2338  Location in = locations->InAt(0);
2339  Primitive::Type result_type = conversion->GetResultType();
2340  Primitive::Type input_type = conversion->GetInputType();
2341  DCHECK_NE(result_type, input_type);
2342  switch (result_type) {
2343    case Primitive::kPrimByte:
2344      switch (input_type) {
2345        case Primitive::kPrimBoolean:
2346          // Boolean input is a result of code transformations.
2347        case Primitive::kPrimShort:
2348        case Primitive::kPrimInt:
2349        case Primitive::kPrimChar:
2350          // Processing a Dex `int-to-byte' instruction.
2351          __ sbfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 8);
2352          break;
2353
2354        default:
2355          LOG(FATAL) << "Unexpected type conversion from " << input_type
2356                     << " to " << result_type;
2357      }
2358      break;
2359
2360    case Primitive::kPrimShort:
2361      switch (input_type) {
2362        case Primitive::kPrimBoolean:
2363          // Boolean input is a result of code transformations.
2364        case Primitive::kPrimByte:
2365        case Primitive::kPrimInt:
2366        case Primitive::kPrimChar:
2367          // Processing a Dex `int-to-short' instruction.
2368          __ sbfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 16);
2369          break;
2370
2371        default:
2372          LOG(FATAL) << "Unexpected type conversion from " << input_type
2373                     << " to " << result_type;
2374      }
2375      break;
2376
2377    case Primitive::kPrimInt:
2378      switch (input_type) {
2379        case Primitive::kPrimLong:
2380          // Processing a Dex `long-to-int' instruction.
2381          DCHECK(out.IsRegister());
2382          if (in.IsRegisterPair()) {
2383            __ Mov(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>());
2384          } else if (in.IsDoubleStackSlot()) {
2385            __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), SP, in.GetStackIndex());
2386          } else {
2387            DCHECK(in.IsConstant());
2388            DCHECK(in.GetConstant()->IsLongConstant());
2389            int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
2390            __ LoadImmediate(out.AsRegister<Register>(), static_cast<int32_t>(value));
2391          }
2392          break;
2393
2394        case Primitive::kPrimFloat: {
2395          // Processing a Dex `float-to-int' instruction.
2396          SRegister temp = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
2397          __ vmovs(temp, in.AsFpuRegister<SRegister>());
2398          __ vcvtis(temp, temp);
2399          __ vmovrs(out.AsRegister<Register>(), temp);
2400          break;
2401        }
2402
2403        case Primitive::kPrimDouble: {
2404          // Processing a Dex `double-to-int' instruction.
2405          SRegister temp_s = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
2406          DRegister temp_d = FromLowSToD(temp_s);
2407          __ vmovd(temp_d, FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
2408          __ vcvtid(temp_s, temp_d);
2409          __ vmovrs(out.AsRegister<Register>(), temp_s);
2410          break;
2411        }
2412
2413        default:
2414          LOG(FATAL) << "Unexpected type conversion from " << input_type
2415                     << " to " << result_type;
2416      }
2417      break;
2418
2419    case Primitive::kPrimLong:
2420      switch (input_type) {
2421        case Primitive::kPrimBoolean:
2422          // Boolean input is a result of code transformations.
2423        case Primitive::kPrimByte:
2424        case Primitive::kPrimShort:
2425        case Primitive::kPrimInt:
2426        case Primitive::kPrimChar:
2427          // Processing a Dex `int-to-long' instruction.
2428          DCHECK(out.IsRegisterPair());
2429          DCHECK(in.IsRegister());
2430          __ Mov(out.AsRegisterPairLow<Register>(), in.AsRegister<Register>());
2431          // Sign extension.
2432          __ Asr(out.AsRegisterPairHigh<Register>(),
2433                 out.AsRegisterPairLow<Register>(),
2434                 31);
2435          break;
2436
2437        case Primitive::kPrimFloat:
2438          // Processing a Dex `float-to-long' instruction.
2439          codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pF2l),
2440                                  conversion,
2441                                  conversion->GetDexPc(),
2442                                  nullptr);
2443          CheckEntrypointTypes<kQuickF2l, int64_t, float>();
2444          break;
2445
2446        case Primitive::kPrimDouble:
2447          // Processing a Dex `double-to-long' instruction.
2448          codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pD2l),
2449                                  conversion,
2450                                  conversion->GetDexPc(),
2451                                  nullptr);
2452          CheckEntrypointTypes<kQuickD2l, int64_t, double>();
2453          break;
2454
2455        default:
2456          LOG(FATAL) << "Unexpected type conversion from " << input_type
2457                     << " to " << result_type;
2458      }
2459      break;
2460
2461    case Primitive::kPrimChar:
2462      switch (input_type) {
2463        case Primitive::kPrimBoolean:
2464          // Boolean input is a result of code transformations.
2465        case Primitive::kPrimByte:
2466        case Primitive::kPrimShort:
2467        case Primitive::kPrimInt:
2468          // Processing a Dex `int-to-char' instruction.
2469          __ ubfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 16);
2470          break;
2471
2472        default:
2473          LOG(FATAL) << "Unexpected type conversion from " << input_type
2474                     << " to " << result_type;
2475      }
2476      break;
2477
2478    case Primitive::kPrimFloat:
2479      switch (input_type) {
2480        case Primitive::kPrimBoolean:
2481          // Boolean input is a result of code transformations.
2482        case Primitive::kPrimByte:
2483        case Primitive::kPrimShort:
2484        case Primitive::kPrimInt:
2485        case Primitive::kPrimChar: {
2486          // Processing a Dex `int-to-float' instruction.
2487          __ vmovsr(out.AsFpuRegister<SRegister>(), in.AsRegister<Register>());
2488          __ vcvtsi(out.AsFpuRegister<SRegister>(), out.AsFpuRegister<SRegister>());
2489          break;
2490        }
2491
2492        case Primitive::kPrimLong:
2493          // Processing a Dex `long-to-float' instruction.
2494          codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pL2f),
2495                                  conversion,
2496                                  conversion->GetDexPc(),
2497                                  nullptr);
2498          CheckEntrypointTypes<kQuickL2f, float, int64_t>();
2499          break;
2500
2501        case Primitive::kPrimDouble:
2502          // Processing a Dex `double-to-float' instruction.
2503          __ vcvtsd(out.AsFpuRegister<SRegister>(),
2504                    FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
2505          break;
2506
2507        default:
2508          LOG(FATAL) << "Unexpected type conversion from " << input_type
2509                     << " to " << result_type;
2510      };
2511      break;
2512
2513    case Primitive::kPrimDouble:
2514      switch (input_type) {
2515        case Primitive::kPrimBoolean:
2516          // Boolean input is a result of code transformations.
2517        case Primitive::kPrimByte:
2518        case Primitive::kPrimShort:
2519        case Primitive::kPrimInt:
2520        case Primitive::kPrimChar: {
2521          // Processing a Dex `int-to-double' instruction.
2522          __ vmovsr(out.AsFpuRegisterPairLow<SRegister>(), in.AsRegister<Register>());
2523          __ vcvtdi(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2524                    out.AsFpuRegisterPairLow<SRegister>());
2525          break;
2526        }
2527
2528        case Primitive::kPrimLong: {
2529          // Processing a Dex `long-to-double' instruction.
2530          Register low = in.AsRegisterPairLow<Register>();
2531          Register high = in.AsRegisterPairHigh<Register>();
2532          SRegister out_s = out.AsFpuRegisterPairLow<SRegister>();
2533          DRegister out_d = FromLowSToD(out_s);
2534          SRegister temp_s = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
2535          DRegister temp_d = FromLowSToD(temp_s);
2536          SRegister constant_s = locations->GetTemp(1).AsFpuRegisterPairLow<SRegister>();
2537          DRegister constant_d = FromLowSToD(constant_s);
2538
2539          // temp_d = int-to-double(high)
2540          __ vmovsr(temp_s, high);
2541          __ vcvtdi(temp_d, temp_s);
2542          // constant_d = k2Pow32EncodingForDouble
2543          __ LoadDImmediate(constant_d, bit_cast<double, int64_t>(k2Pow32EncodingForDouble));
2544          // out_d = unsigned-to-double(low)
2545          __ vmovsr(out_s, low);
2546          __ vcvtdu(out_d, out_s);
2547          // out_d += temp_d * constant_d
2548          __ vmlad(out_d, temp_d, constant_d);
2549          break;
2550        }
2551
2552        case Primitive::kPrimFloat:
2553          // Processing a Dex `float-to-double' instruction.
2554          __ vcvtds(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2555                    in.AsFpuRegister<SRegister>());
2556          break;
2557
2558        default:
2559          LOG(FATAL) << "Unexpected type conversion from " << input_type
2560                     << " to " << result_type;
2561      };
2562      break;
2563
2564    default:
2565      LOG(FATAL) << "Unexpected type conversion from " << input_type
2566                 << " to " << result_type;
2567  }
2568}
2569
2570void LocationsBuilderARM::VisitAdd(HAdd* add) {
2571  LocationSummary* locations =
2572      new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
2573  switch (add->GetResultType()) {
2574    case Primitive::kPrimInt: {
2575      locations->SetInAt(0, Location::RequiresRegister());
2576      locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
2577      locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2578      break;
2579    }
2580
2581    case Primitive::kPrimLong: {
2582      locations->SetInAt(0, Location::RequiresRegister());
2583      locations->SetInAt(1, Location::RequiresRegister());
2584      locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2585      break;
2586    }
2587
2588    case Primitive::kPrimFloat:
2589    case Primitive::kPrimDouble: {
2590      locations->SetInAt(0, Location::RequiresFpuRegister());
2591      locations->SetInAt(1, Location::RequiresFpuRegister());
2592      locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
2593      break;
2594    }
2595
2596    default:
2597      LOG(FATAL) << "Unexpected add type " << add->GetResultType();
2598  }
2599}
2600
2601void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) {
2602  LocationSummary* locations = add->GetLocations();
2603  Location out = locations->Out();
2604  Location first = locations->InAt(0);
2605  Location second = locations->InAt(1);
2606  switch (add->GetResultType()) {
2607    case Primitive::kPrimInt:
2608      if (second.IsRegister()) {
2609        __ add(out.AsRegister<Register>(),
2610               first.AsRegister<Register>(),
2611               ShifterOperand(second.AsRegister<Register>()));
2612      } else {
2613        __ AddConstant(out.AsRegister<Register>(),
2614                       first.AsRegister<Register>(),
2615                       second.GetConstant()->AsIntConstant()->GetValue());
2616      }
2617      break;
2618
2619    case Primitive::kPrimLong: {
2620      DCHECK(second.IsRegisterPair());
2621      __ adds(out.AsRegisterPairLow<Register>(),
2622              first.AsRegisterPairLow<Register>(),
2623              ShifterOperand(second.AsRegisterPairLow<Register>()));
2624      __ adc(out.AsRegisterPairHigh<Register>(),
2625             first.AsRegisterPairHigh<Register>(),
2626             ShifterOperand(second.AsRegisterPairHigh<Register>()));
2627      break;
2628    }
2629
2630    case Primitive::kPrimFloat:
2631      __ vadds(out.AsFpuRegister<SRegister>(),
2632               first.AsFpuRegister<SRegister>(),
2633               second.AsFpuRegister<SRegister>());
2634      break;
2635
2636    case Primitive::kPrimDouble:
2637      __ vaddd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2638               FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2639               FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
2640      break;
2641
2642    default:
2643      LOG(FATAL) << "Unexpected add type " << add->GetResultType();
2644  }
2645}
2646
2647void LocationsBuilderARM::VisitSub(HSub* sub) {
2648  LocationSummary* locations =
2649      new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
2650  switch (sub->GetResultType()) {
2651    case Primitive::kPrimInt: {
2652      locations->SetInAt(0, Location::RequiresRegister());
2653      locations->SetInAt(1, Location::RegisterOrConstant(sub->InputAt(1)));
2654      locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2655      break;
2656    }
2657
2658    case Primitive::kPrimLong: {
2659      locations->SetInAt(0, Location::RequiresRegister());
2660      locations->SetInAt(1, Location::RequiresRegister());
2661      locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2662      break;
2663    }
2664    case Primitive::kPrimFloat:
2665    case Primitive::kPrimDouble: {
2666      locations->SetInAt(0, Location::RequiresFpuRegister());
2667      locations->SetInAt(1, Location::RequiresFpuRegister());
2668      locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
2669      break;
2670    }
2671    default:
2672      LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
2673  }
2674}
2675
2676void InstructionCodeGeneratorARM::VisitSub(HSub* sub) {
2677  LocationSummary* locations = sub->GetLocations();
2678  Location out = locations->Out();
2679  Location first = locations->InAt(0);
2680  Location second = locations->InAt(1);
2681  switch (sub->GetResultType()) {
2682    case Primitive::kPrimInt: {
2683      if (second.IsRegister()) {
2684        __ sub(out.AsRegister<Register>(),
2685               first.AsRegister<Register>(),
2686               ShifterOperand(second.AsRegister<Register>()));
2687      } else {
2688        __ AddConstant(out.AsRegister<Register>(),
2689                       first.AsRegister<Register>(),
2690                       -second.GetConstant()->AsIntConstant()->GetValue());
2691      }
2692      break;
2693    }
2694
2695    case Primitive::kPrimLong: {
2696      DCHECK(second.IsRegisterPair());
2697      __ subs(out.AsRegisterPairLow<Register>(),
2698              first.AsRegisterPairLow<Register>(),
2699              ShifterOperand(second.AsRegisterPairLow<Register>()));
2700      __ sbc(out.AsRegisterPairHigh<Register>(),
2701             first.AsRegisterPairHigh<Register>(),
2702             ShifterOperand(second.AsRegisterPairHigh<Register>()));
2703      break;
2704    }
2705
2706    case Primitive::kPrimFloat: {
2707      __ vsubs(out.AsFpuRegister<SRegister>(),
2708               first.AsFpuRegister<SRegister>(),
2709               second.AsFpuRegister<SRegister>());
2710      break;
2711    }
2712
2713    case Primitive::kPrimDouble: {
2714      __ vsubd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2715               FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2716               FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
2717      break;
2718    }
2719
2720
2721    default:
2722      LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
2723  }
2724}
2725
2726void LocationsBuilderARM::VisitMul(HMul* mul) {
2727  LocationSummary* locations =
2728      new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
2729  switch (mul->GetResultType()) {
2730    case Primitive::kPrimInt:
2731    case Primitive::kPrimLong:  {
2732      locations->SetInAt(0, Location::RequiresRegister());
2733      locations->SetInAt(1, Location::RequiresRegister());
2734      locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2735      break;
2736    }
2737
2738    case Primitive::kPrimFloat:
2739    case Primitive::kPrimDouble: {
2740      locations->SetInAt(0, Location::RequiresFpuRegister());
2741      locations->SetInAt(1, Location::RequiresFpuRegister());
2742      locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
2743      break;
2744    }
2745
2746    default:
2747      LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
2748  }
2749}
2750
2751void InstructionCodeGeneratorARM::VisitMul(HMul* mul) {
2752  LocationSummary* locations = mul->GetLocations();
2753  Location out = locations->Out();
2754  Location first = locations->InAt(0);
2755  Location second = locations->InAt(1);
2756  switch (mul->GetResultType()) {
2757    case Primitive::kPrimInt: {
2758      __ mul(out.AsRegister<Register>(),
2759             first.AsRegister<Register>(),
2760             second.AsRegister<Register>());
2761      break;
2762    }
2763    case Primitive::kPrimLong: {
2764      Register out_hi = out.AsRegisterPairHigh<Register>();
2765      Register out_lo = out.AsRegisterPairLow<Register>();
2766      Register in1_hi = first.AsRegisterPairHigh<Register>();
2767      Register in1_lo = first.AsRegisterPairLow<Register>();
2768      Register in2_hi = second.AsRegisterPairHigh<Register>();
2769      Register in2_lo = second.AsRegisterPairLow<Register>();
2770
2771      // Extra checks to protect caused by the existence of R1_R2.
2772      // The algorithm is wrong if out.hi is either in1.lo or in2.lo:
2773      // (e.g. in1=r0_r1, in2=r2_r3 and out=r1_r2);
2774      DCHECK_NE(out_hi, in1_lo);
2775      DCHECK_NE(out_hi, in2_lo);
2776
2777      // input: in1 - 64 bits, in2 - 64 bits
2778      // output: out
2779      // formula: out.hi : out.lo = (in1.lo * in2.hi + in1.hi * in2.lo)* 2^32 + in1.lo * in2.lo
2780      // parts: out.hi = in1.lo * in2.hi + in1.hi * in2.lo + (in1.lo * in2.lo)[63:32]
2781      // parts: out.lo = (in1.lo * in2.lo)[31:0]
2782
2783      // IP <- in1.lo * in2.hi
2784      __ mul(IP, in1_lo, in2_hi);
2785      // out.hi <- in1.lo * in2.hi + in1.hi * in2.lo
2786      __ mla(out_hi, in1_hi, in2_lo, IP);
2787      // out.lo <- (in1.lo * in2.lo)[31:0];
2788      __ umull(out_lo, IP, in1_lo, in2_lo);
2789      // out.hi <- in2.hi * in1.lo +  in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
2790      __ add(out_hi, out_hi, ShifterOperand(IP));
2791      break;
2792    }
2793
2794    case Primitive::kPrimFloat: {
2795      __ vmuls(out.AsFpuRegister<SRegister>(),
2796               first.AsFpuRegister<SRegister>(),
2797               second.AsFpuRegister<SRegister>());
2798      break;
2799    }
2800
2801    case Primitive::kPrimDouble: {
2802      __ vmuld(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2803               FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2804               FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
2805      break;
2806    }
2807
2808    default:
2809      LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
2810  }
2811}
2812
2813void InstructionCodeGeneratorARM::DivRemOneOrMinusOne(HBinaryOperation* instruction) {
2814  DCHECK(instruction->IsDiv() || instruction->IsRem());
2815  DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
2816
2817  LocationSummary* locations = instruction->GetLocations();
2818  Location second = locations->InAt(1);
2819  DCHECK(second.IsConstant());
2820
2821  Register out = locations->Out().AsRegister<Register>();
2822  Register dividend = locations->InAt(0).AsRegister<Register>();
2823  int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
2824  DCHECK(imm == 1 || imm == -1);
2825
2826  if (instruction->IsRem()) {
2827    __ LoadImmediate(out, 0);
2828  } else {
2829    if (imm == 1) {
2830      __ Mov(out, dividend);
2831    } else {
2832      __ rsb(out, dividend, ShifterOperand(0));
2833    }
2834  }
2835}
2836
2837void InstructionCodeGeneratorARM::DivRemByPowerOfTwo(HBinaryOperation* instruction) {
2838  DCHECK(instruction->IsDiv() || instruction->IsRem());
2839  DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
2840
2841  LocationSummary* locations = instruction->GetLocations();
2842  Location second = locations->InAt(1);
2843  DCHECK(second.IsConstant());
2844
2845  Register out = locations->Out().AsRegister<Register>();
2846  Register dividend = locations->InAt(0).AsRegister<Register>();
2847  Register temp = locations->GetTemp(0).AsRegister<Register>();
2848  int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
2849  uint32_t abs_imm = static_cast<uint32_t>(std::abs(imm));
2850  DCHECK(IsPowerOfTwo(abs_imm));
2851  int ctz_imm = CTZ(abs_imm);
2852
2853  if (ctz_imm == 1) {
2854    __ Lsr(temp, dividend, 32 - ctz_imm);
2855  } else {
2856    __ Asr(temp, dividend, 31);
2857    __ Lsr(temp, temp, 32 - ctz_imm);
2858  }
2859  __ add(out, temp, ShifterOperand(dividend));
2860
2861  if (instruction->IsDiv()) {
2862    __ Asr(out, out, ctz_imm);
2863    if (imm < 0) {
2864      __ rsb(out, out, ShifterOperand(0));
2865    }
2866  } else {
2867    __ ubfx(out, out, 0, ctz_imm);
2868    __ sub(out, out, ShifterOperand(temp));
2869  }
2870}
2871
2872void InstructionCodeGeneratorARM::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) {
2873  DCHECK(instruction->IsDiv() || instruction->IsRem());
2874  DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
2875
2876  LocationSummary* locations = instruction->GetLocations();
2877  Location second = locations->InAt(1);
2878  DCHECK(second.IsConstant());
2879
2880  Register out = locations->Out().AsRegister<Register>();
2881  Register dividend = locations->InAt(0).AsRegister<Register>();
2882  Register temp1 = locations->GetTemp(0).AsRegister<Register>();
2883  Register temp2 = locations->GetTemp(1).AsRegister<Register>();
2884  int64_t imm = second.GetConstant()->AsIntConstant()->GetValue();
2885
2886  int64_t magic;
2887  int shift;
2888  CalculateMagicAndShiftForDivRem(imm, false /* is_long */, &magic, &shift);
2889
2890  __ LoadImmediate(temp1, magic);
2891  __ smull(temp2, temp1, dividend, temp1);
2892
2893  if (imm > 0 && magic < 0) {
2894    __ add(temp1, temp1, ShifterOperand(dividend));
2895  } else if (imm < 0 && magic > 0) {
2896    __ sub(temp1, temp1, ShifterOperand(dividend));
2897  }
2898
2899  if (shift != 0) {
2900    __ Asr(temp1, temp1, shift);
2901  }
2902
2903  if (instruction->IsDiv()) {
2904    __ sub(out, temp1, ShifterOperand(temp1, ASR, 31));
2905  } else {
2906    __ sub(temp1, temp1, ShifterOperand(temp1, ASR, 31));
2907    // TODO: Strength reduction for mls.
2908    __ LoadImmediate(temp2, imm);
2909    __ mls(out, temp1, temp2, dividend);
2910  }
2911}
2912
2913void InstructionCodeGeneratorARM::GenerateDivRemConstantIntegral(HBinaryOperation* instruction) {
2914  DCHECK(instruction->IsDiv() || instruction->IsRem());
2915  DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
2916
2917  LocationSummary* locations = instruction->GetLocations();
2918  Location second = locations->InAt(1);
2919  DCHECK(second.IsConstant());
2920
2921  int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
2922  if (imm == 0) {
2923    // Do not generate anything. DivZeroCheck would prevent any code to be executed.
2924  } else if (imm == 1 || imm == -1) {
2925    DivRemOneOrMinusOne(instruction);
2926  } else if (IsPowerOfTwo(std::abs(imm))) {
2927    DivRemByPowerOfTwo(instruction);
2928  } else {
2929    DCHECK(imm <= -2 || imm >= 2);
2930    GenerateDivRemWithAnyConstant(instruction);
2931  }
2932}
2933
2934void LocationsBuilderARM::VisitDiv(HDiv* div) {
2935  LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
2936  if (div->GetResultType() == Primitive::kPrimLong) {
2937    // pLdiv runtime call.
2938    call_kind = LocationSummary::kCall;
2939  } else if (div->GetResultType() == Primitive::kPrimInt && div->InputAt(1)->IsConstant()) {
2940    // sdiv will be replaced by other instruction sequence.
2941  } else if (div->GetResultType() == Primitive::kPrimInt &&
2942             !codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
2943    // pIdivmod runtime call.
2944    call_kind = LocationSummary::kCall;
2945  }
2946
2947  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(div, call_kind);
2948
2949  switch (div->GetResultType()) {
2950    case Primitive::kPrimInt: {
2951      if (div->InputAt(1)->IsConstant()) {
2952        locations->SetInAt(0, Location::RequiresRegister());
2953        locations->SetInAt(1, Location::ConstantLocation(div->InputAt(1)->AsConstant()));
2954        locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2955        int32_t abs_imm = std::abs(div->InputAt(1)->AsIntConstant()->GetValue());
2956        if (abs_imm <= 1) {
2957          // No temp register required.
2958        } else {
2959          locations->AddTemp(Location::RequiresRegister());
2960          if (!IsPowerOfTwo(abs_imm)) {
2961            locations->AddTemp(Location::RequiresRegister());
2962          }
2963        }
2964      } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
2965        locations->SetInAt(0, Location::RequiresRegister());
2966        locations->SetInAt(1, Location::RequiresRegister());
2967        locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2968      } else {
2969        InvokeRuntimeCallingConvention calling_convention;
2970        locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2971        locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
2972        // Note: divrem will compute both the quotient and the remainder as the pair R0 and R1, but
2973        //       we only need the former.
2974        locations->SetOut(Location::RegisterLocation(R0));
2975      }
2976      break;
2977    }
2978    case Primitive::kPrimLong: {
2979      InvokeRuntimeCallingConvention calling_convention;
2980      locations->SetInAt(0, Location::RegisterPairLocation(
2981          calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
2982      locations->SetInAt(1, Location::RegisterPairLocation(
2983          calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
2984      locations->SetOut(Location::RegisterPairLocation(R0, R1));
2985      break;
2986    }
2987    case Primitive::kPrimFloat:
2988    case Primitive::kPrimDouble: {
2989      locations->SetInAt(0, Location::RequiresFpuRegister());
2990      locations->SetInAt(1, Location::RequiresFpuRegister());
2991      locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
2992      break;
2993    }
2994
2995    default:
2996      LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2997  }
2998}
2999
3000void InstructionCodeGeneratorARM::VisitDiv(HDiv* div) {
3001  LocationSummary* locations = div->GetLocations();
3002  Location out = locations->Out();
3003  Location first = locations->InAt(0);
3004  Location second = locations->InAt(1);
3005
3006  switch (div->GetResultType()) {
3007    case Primitive::kPrimInt: {
3008      if (second.IsConstant()) {
3009        GenerateDivRemConstantIntegral(div);
3010      } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
3011        __ sdiv(out.AsRegister<Register>(),
3012                first.AsRegister<Register>(),
3013                second.AsRegister<Register>());
3014      } else {
3015        InvokeRuntimeCallingConvention calling_convention;
3016        DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegister<Register>());
3017        DCHECK_EQ(calling_convention.GetRegisterAt(1), second.AsRegister<Register>());
3018        DCHECK_EQ(R0, out.AsRegister<Register>());
3019
3020        codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pIdivmod), div, div->GetDexPc(), nullptr);
3021        CheckEntrypointTypes<kQuickIdivmod, int32_t, int32_t, int32_t>();
3022      }
3023      break;
3024    }
3025
3026    case Primitive::kPrimLong: {
3027      InvokeRuntimeCallingConvention calling_convention;
3028      DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegisterPairLow<Register>());
3029      DCHECK_EQ(calling_convention.GetRegisterAt(1), first.AsRegisterPairHigh<Register>());
3030      DCHECK_EQ(calling_convention.GetRegisterAt(2), second.AsRegisterPairLow<Register>());
3031      DCHECK_EQ(calling_convention.GetRegisterAt(3), second.AsRegisterPairHigh<Register>());
3032      DCHECK_EQ(R0, out.AsRegisterPairLow<Register>());
3033      DCHECK_EQ(R1, out.AsRegisterPairHigh<Register>());
3034
3035      codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLdiv), div, div->GetDexPc(), nullptr);
3036      CheckEntrypointTypes<kQuickLdiv, int64_t, int64_t, int64_t>();
3037      break;
3038    }
3039
3040    case Primitive::kPrimFloat: {
3041      __ vdivs(out.AsFpuRegister<SRegister>(),
3042               first.AsFpuRegister<SRegister>(),
3043               second.AsFpuRegister<SRegister>());
3044      break;
3045    }
3046
3047    case Primitive::kPrimDouble: {
3048      __ vdivd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
3049               FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
3050               FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
3051      break;
3052    }
3053
3054    default:
3055      LOG(FATAL) << "Unexpected div type " << div->GetResultType();
3056  }
3057}
3058
3059void LocationsBuilderARM::VisitRem(HRem* rem) {
3060  Primitive::Type type = rem->GetResultType();
3061
3062  // Most remainders are implemented in the runtime.
3063  LocationSummary::CallKind call_kind = LocationSummary::kCall;
3064  if (rem->GetResultType() == Primitive::kPrimInt && rem->InputAt(1)->IsConstant()) {
3065    // sdiv will be replaced by other instruction sequence.
3066    call_kind = LocationSummary::kNoCall;
3067  } else if ((rem->GetResultType() == Primitive::kPrimInt)
3068             && codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
3069    // Have hardware divide instruction for int, do it with three instructions.
3070    call_kind = LocationSummary::kNoCall;
3071  }
3072
3073  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind);
3074
3075  switch (type) {
3076    case Primitive::kPrimInt: {
3077      if (rem->InputAt(1)->IsConstant()) {
3078        locations->SetInAt(0, Location::RequiresRegister());
3079        locations->SetInAt(1, Location::ConstantLocation(rem->InputAt(1)->AsConstant()));
3080        locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3081        int32_t abs_imm = std::abs(rem->InputAt(1)->AsIntConstant()->GetValue());
3082        if (abs_imm <= 1) {
3083          // No temp register required.
3084        } else {
3085          locations->AddTemp(Location::RequiresRegister());
3086          if (!IsPowerOfTwo(abs_imm)) {
3087            locations->AddTemp(Location::RequiresRegister());
3088          }
3089        }
3090      } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
3091        locations->SetInAt(0, Location::RequiresRegister());
3092        locations->SetInAt(1, Location::RequiresRegister());
3093        locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3094        locations->AddTemp(Location::RequiresRegister());
3095      } else {
3096        InvokeRuntimeCallingConvention calling_convention;
3097        locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3098        locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
3099        // Note: divrem will compute both the quotient and the remainder as the pair R0 and R1, but
3100        //       we only need the latter.
3101        locations->SetOut(Location::RegisterLocation(R1));
3102      }
3103      break;
3104    }
3105    case Primitive::kPrimLong: {
3106      InvokeRuntimeCallingConvention calling_convention;
3107      locations->SetInAt(0, Location::RegisterPairLocation(
3108          calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
3109      locations->SetInAt(1, Location::RegisterPairLocation(
3110          calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
3111      // The runtime helper puts the output in R2,R3.
3112      locations->SetOut(Location::RegisterPairLocation(R2, R3));
3113      break;
3114    }
3115    case Primitive::kPrimFloat: {
3116      InvokeRuntimeCallingConvention calling_convention;
3117      locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
3118      locations->SetInAt(1, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(1)));
3119      locations->SetOut(Location::FpuRegisterLocation(S0));
3120      break;
3121    }
3122
3123    case Primitive::kPrimDouble: {
3124      InvokeRuntimeCallingConvention calling_convention;
3125      locations->SetInAt(0, Location::FpuRegisterPairLocation(
3126          calling_convention.GetFpuRegisterAt(0), calling_convention.GetFpuRegisterAt(1)));
3127      locations->SetInAt(1, Location::FpuRegisterPairLocation(
3128          calling_convention.GetFpuRegisterAt(2), calling_convention.GetFpuRegisterAt(3)));
3129      locations->SetOut(Location::Location::FpuRegisterPairLocation(S0, S1));
3130      break;
3131    }
3132
3133    default:
3134      LOG(FATAL) << "Unexpected rem type " << type;
3135  }
3136}
3137
3138void InstructionCodeGeneratorARM::VisitRem(HRem* rem) {
3139  LocationSummary* locations = rem->GetLocations();
3140  Location out = locations->Out();
3141  Location first = locations->InAt(0);
3142  Location second = locations->InAt(1);
3143
3144  Primitive::Type type = rem->GetResultType();
3145  switch (type) {
3146    case Primitive::kPrimInt: {
3147        if (second.IsConstant()) {
3148          GenerateDivRemConstantIntegral(rem);
3149        } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
3150        Register reg1 = first.AsRegister<Register>();
3151        Register reg2 = second.AsRegister<Register>();
3152        Register temp = locations->GetTemp(0).AsRegister<Register>();
3153
3154        // temp = reg1 / reg2  (integer division)
3155        // dest = reg1 - temp * reg2
3156        __ sdiv(temp, reg1, reg2);
3157        __ mls(out.AsRegister<Register>(), temp, reg2, reg1);
3158      } else {
3159        InvokeRuntimeCallingConvention calling_convention;
3160        DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegister<Register>());
3161        DCHECK_EQ(calling_convention.GetRegisterAt(1), second.AsRegister<Register>());
3162        DCHECK_EQ(R1, out.AsRegister<Register>());
3163
3164        codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pIdivmod), rem, rem->GetDexPc(), nullptr);
3165        CheckEntrypointTypes<kQuickIdivmod, int32_t, int32_t, int32_t>();
3166      }
3167      break;
3168    }
3169
3170    case Primitive::kPrimLong: {
3171      codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLmod), rem, rem->GetDexPc(), nullptr);
3172        CheckEntrypointTypes<kQuickLmod, int64_t, int64_t, int64_t>();
3173      break;
3174    }
3175
3176    case Primitive::kPrimFloat: {
3177      codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pFmodf), rem, rem->GetDexPc(), nullptr);
3178      CheckEntrypointTypes<kQuickFmodf, float, float, float>();
3179      break;
3180    }
3181
3182    case Primitive::kPrimDouble: {
3183      codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pFmod), rem, rem->GetDexPc(), nullptr);
3184      CheckEntrypointTypes<kQuickFmod, double, double, double>();
3185      break;
3186    }
3187
3188    default:
3189      LOG(FATAL) << "Unexpected rem type " << type;
3190  }
3191}
3192
3193void LocationsBuilderARM::VisitDivZeroCheck(HDivZeroCheck* instruction) {
3194  LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
3195      ? LocationSummary::kCallOnSlowPath
3196      : LocationSummary::kNoCall;
3197  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
3198  locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
3199  if (instruction->HasUses()) {
3200    locations->SetOut(Location::SameAsFirstInput());
3201  }
3202}
3203
3204void InstructionCodeGeneratorARM::VisitDivZeroCheck(HDivZeroCheck* instruction) {
3205  SlowPathCode* slow_path = new (GetGraph()->GetArena()) DivZeroCheckSlowPathARM(instruction);
3206  codegen_->AddSlowPath(slow_path);
3207
3208  LocationSummary* locations = instruction->GetLocations();
3209  Location value = locations->InAt(0);
3210
3211  switch (instruction->GetType()) {
3212    case Primitive::kPrimByte:
3213    case Primitive::kPrimChar:
3214    case Primitive::kPrimShort:
3215    case Primitive::kPrimInt: {
3216      if (value.IsRegister()) {
3217        __ CompareAndBranchIfZero(value.AsRegister<Register>(), slow_path->GetEntryLabel());
3218      } else {
3219        DCHECK(value.IsConstant()) << value;
3220        if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
3221          __ b(slow_path->GetEntryLabel());
3222        }
3223      }
3224      break;
3225    }
3226    case Primitive::kPrimLong: {
3227      if (value.IsRegisterPair()) {
3228        __ orrs(IP,
3229                value.AsRegisterPairLow<Register>(),
3230                ShifterOperand(value.AsRegisterPairHigh<Register>()));
3231        __ b(slow_path->GetEntryLabel(), EQ);
3232      } else {
3233        DCHECK(value.IsConstant()) << value;
3234        if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
3235          __ b(slow_path->GetEntryLabel());
3236        }
3237      }
3238      break;
3239    default:
3240      LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
3241    }
3242  }
3243}
3244
3245void InstructionCodeGeneratorARM::HandleIntegerRotate(LocationSummary* locations) {
3246  Register in = locations->InAt(0).AsRegister<Register>();
3247  Location rhs = locations->InAt(1);
3248  Register out = locations->Out().AsRegister<Register>();
3249
3250  if (rhs.IsConstant()) {
3251    // Arm32 and Thumb2 assemblers require a rotation on the interval [1,31],
3252    // so map all rotations to a +ve. equivalent in that range.
3253    // (e.g. left *or* right by -2 bits == 30 bits in the same direction.)
3254    uint32_t rot = CodeGenerator::GetInt32ValueOf(rhs.GetConstant()) & 0x1F;
3255    if (rot) {
3256      // Rotate, mapping left rotations to right equivalents if necessary.
3257      // (e.g. left by 2 bits == right by 30.)
3258      __ Ror(out, in, rot);
3259    } else if (out != in) {
3260      __ Mov(out, in);
3261    }
3262  } else {
3263    __ Ror(out, in, rhs.AsRegister<Register>());
3264  }
3265}
3266
3267// Gain some speed by mapping all Long rotates onto equivalent pairs of Integer
3268// rotates by swapping input regs (effectively rotating by the first 32-bits of
3269// a larger rotation) or flipping direction (thus treating larger right/left
3270// rotations as sub-word sized rotations in the other direction) as appropriate.
3271void InstructionCodeGeneratorARM::HandleLongRotate(LocationSummary* locations) {
3272  Register in_reg_lo = locations->InAt(0).AsRegisterPairLow<Register>();
3273  Register in_reg_hi = locations->InAt(0).AsRegisterPairHigh<Register>();
3274  Location rhs = locations->InAt(1);
3275  Register out_reg_lo = locations->Out().AsRegisterPairLow<Register>();
3276  Register out_reg_hi = locations->Out().AsRegisterPairHigh<Register>();
3277
3278  if (rhs.IsConstant()) {
3279    uint64_t rot = CodeGenerator::GetInt64ValueOf(rhs.GetConstant());
3280    // Map all rotations to +ve. equivalents on the interval [0,63].
3281    rot &= kMaxLongShiftValue;
3282    // For rotates over a word in size, 'pre-rotate' by 32-bits to keep rotate
3283    // logic below to a simple pair of binary orr.
3284    // (e.g. 34 bits == in_reg swap + 2 bits right.)
3285    if (rot >= kArmBitsPerWord) {
3286      rot -= kArmBitsPerWord;
3287      std::swap(in_reg_hi, in_reg_lo);
3288    }
3289    // Rotate, or mov to out for zero or word size rotations.
3290    if (rot != 0u) {
3291      __ Lsr(out_reg_hi, in_reg_hi, rot);
3292      __ orr(out_reg_hi, out_reg_hi, ShifterOperand(in_reg_lo, arm::LSL, kArmBitsPerWord - rot));
3293      __ Lsr(out_reg_lo, in_reg_lo, rot);
3294      __ orr(out_reg_lo, out_reg_lo, ShifterOperand(in_reg_hi, arm::LSL, kArmBitsPerWord - rot));
3295    } else {
3296      __ Mov(out_reg_lo, in_reg_lo);
3297      __ Mov(out_reg_hi, in_reg_hi);
3298    }
3299  } else {
3300    Register shift_right = locations->GetTemp(0).AsRegister<Register>();
3301    Register shift_left = locations->GetTemp(1).AsRegister<Register>();
3302    Label end;
3303    Label shift_by_32_plus_shift_right;
3304
3305    __ and_(shift_right, rhs.AsRegister<Register>(), ShifterOperand(0x1F));
3306    __ Lsrs(shift_left, rhs.AsRegister<Register>(), 6);
3307    __ rsb(shift_left, shift_right, ShifterOperand(kArmBitsPerWord), AL, kCcKeep);
3308    __ b(&shift_by_32_plus_shift_right, CC);
3309
3310    // out_reg_hi = (reg_hi << shift_left) | (reg_lo >> shift_right).
3311    // out_reg_lo = (reg_lo << shift_left) | (reg_hi >> shift_right).
3312    __ Lsl(out_reg_hi, in_reg_hi, shift_left);
3313    __ Lsr(out_reg_lo, in_reg_lo, shift_right);
3314    __ add(out_reg_hi, out_reg_hi, ShifterOperand(out_reg_lo));
3315    __ Lsl(out_reg_lo, in_reg_lo, shift_left);
3316    __ Lsr(shift_left, in_reg_hi, shift_right);
3317    __ add(out_reg_lo, out_reg_lo, ShifterOperand(shift_left));
3318    __ b(&end);
3319
3320    __ Bind(&shift_by_32_plus_shift_right);  // Shift by 32+shift_right.
3321    // out_reg_hi = (reg_hi >> shift_right) | (reg_lo << shift_left).
3322    // out_reg_lo = (reg_lo >> shift_right) | (reg_hi << shift_left).
3323    __ Lsr(out_reg_hi, in_reg_hi, shift_right);
3324    __ Lsl(out_reg_lo, in_reg_lo, shift_left);
3325    __ add(out_reg_hi, out_reg_hi, ShifterOperand(out_reg_lo));
3326    __ Lsr(out_reg_lo, in_reg_lo, shift_right);
3327    __ Lsl(shift_right, in_reg_hi, shift_left);
3328    __ add(out_reg_lo, out_reg_lo, ShifterOperand(shift_right));
3329
3330    __ Bind(&end);
3331  }
3332}
3333void LocationsBuilderARM::HandleRotate(HRor* ror) {
3334  LocationSummary* locations =
3335      new (GetGraph()->GetArena()) LocationSummary(ror, LocationSummary::kNoCall);
3336  switch (ror->GetResultType()) {
3337    case Primitive::kPrimInt: {
3338      locations->SetInAt(0, Location::RequiresRegister());
3339      locations->SetInAt(1, Location::RegisterOrConstant(ror->InputAt(1)));
3340      locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3341      break;
3342    }
3343    case Primitive::kPrimLong: {
3344      locations->SetInAt(0, Location::RequiresRegister());
3345      if (ror->InputAt(1)->IsConstant()) {
3346        locations->SetInAt(1, Location::ConstantLocation(ror->InputAt(1)->AsConstant()));
3347      } else {
3348        locations->SetInAt(1, Location::RequiresRegister());
3349        locations->AddTemp(Location::RequiresRegister());
3350        locations->AddTemp(Location::RequiresRegister());
3351      }
3352      locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
3353      break;
3354    }
3355    default:
3356      LOG(FATAL) << "Unexpected operation type " << ror->GetResultType();
3357  }
3358}
3359
3360void InstructionCodeGeneratorARM::HandleRotate(HRor* ror) {
3361  LocationSummary* locations = ror->GetLocations();
3362  Primitive::Type type = ror->GetResultType();
3363  switch (type) {
3364    case Primitive::kPrimInt: {
3365      HandleIntegerRotate(locations);
3366      break;
3367    }
3368    case Primitive::kPrimLong: {
3369      HandleLongRotate(locations);
3370      break;
3371    }
3372    default:
3373      LOG(FATAL) << "Unexpected operation type " << type;
3374      UNREACHABLE();
3375  }
3376}
3377
3378void LocationsBuilderARM::VisitRor(HRor* op) {
3379  HandleRotate(op);
3380}
3381
3382void InstructionCodeGeneratorARM::VisitRor(HRor* op) {
3383  HandleRotate(op);
3384}
3385
3386void LocationsBuilderARM::HandleShift(HBinaryOperation* op) {
3387  DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
3388
3389  LocationSummary* locations =
3390      new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
3391
3392  switch (op->GetResultType()) {
3393    case Primitive::kPrimInt: {
3394      locations->SetInAt(0, Location::RequiresRegister());
3395      if (op->InputAt(1)->IsConstant()) {
3396        locations->SetInAt(1, Location::ConstantLocation(op->InputAt(1)->AsConstant()));
3397        locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3398      } else {
3399        locations->SetInAt(1, Location::RequiresRegister());
3400        // Make the output overlap, as it will be used to hold the masked
3401        // second input.
3402        locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
3403      }
3404      break;
3405    }
3406    case Primitive::kPrimLong: {
3407      locations->SetInAt(0, Location::RequiresRegister());
3408      if (op->InputAt(1)->IsConstant()) {
3409        locations->SetInAt(1, Location::ConstantLocation(op->InputAt(1)->AsConstant()));
3410        // For simplicity, use kOutputOverlap even though we only require that low registers
3411        // don't clash with high registers which the register allocator currently guarantees.
3412        locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
3413      } else {
3414        locations->SetInAt(1, Location::RequiresRegister());
3415        locations->AddTemp(Location::RequiresRegister());
3416        locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
3417      }
3418      break;
3419    }
3420    default:
3421      LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
3422  }
3423}
3424
3425void InstructionCodeGeneratorARM::HandleShift(HBinaryOperation* op) {
3426  DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
3427
3428  LocationSummary* locations = op->GetLocations();
3429  Location out = locations->Out();
3430  Location first = locations->InAt(0);
3431  Location second = locations->InAt(1);
3432
3433  Primitive::Type type = op->GetResultType();
3434  switch (type) {
3435    case Primitive::kPrimInt: {
3436      Register out_reg = out.AsRegister<Register>();
3437      Register first_reg = first.AsRegister<Register>();
3438      if (second.IsRegister()) {
3439        Register second_reg = second.AsRegister<Register>();
3440        // Arm doesn't mask the shift count so we need to do it ourselves.
3441        __ and_(out_reg, second_reg, ShifterOperand(kMaxIntShiftValue));
3442        if (op->IsShl()) {
3443          __ Lsl(out_reg, first_reg, out_reg);
3444        } else if (op->IsShr()) {
3445          __ Asr(out_reg, first_reg, out_reg);
3446        } else {
3447          __ Lsr(out_reg, first_reg, out_reg);
3448        }
3449      } else {
3450        int32_t cst = second.GetConstant()->AsIntConstant()->GetValue();
3451        uint32_t shift_value = static_cast<uint32_t>(cst & kMaxIntShiftValue);
3452        if (shift_value == 0) {  // arm does not support shifting with 0 immediate.
3453          __ Mov(out_reg, first_reg);
3454        } else if (op->IsShl()) {
3455          __ Lsl(out_reg, first_reg, shift_value);
3456        } else if (op->IsShr()) {
3457          __ Asr(out_reg, first_reg, shift_value);
3458        } else {
3459          __ Lsr(out_reg, first_reg, shift_value);
3460        }
3461      }
3462      break;
3463    }
3464    case Primitive::kPrimLong: {
3465      Register o_h = out.AsRegisterPairHigh<Register>();
3466      Register o_l = out.AsRegisterPairLow<Register>();
3467
3468      Register high = first.AsRegisterPairHigh<Register>();
3469      Register low = first.AsRegisterPairLow<Register>();
3470
3471      if (second.IsRegister()) {
3472        Register temp = locations->GetTemp(0).AsRegister<Register>();
3473
3474        Register second_reg = second.AsRegister<Register>();
3475
3476        if (op->IsShl()) {
3477          __ and_(o_l, second_reg, ShifterOperand(kMaxLongShiftValue));
3478          // Shift the high part
3479          __ Lsl(o_h, high, o_l);
3480          // Shift the low part and `or` what overflew on the high part
3481          __ rsb(temp, o_l, ShifterOperand(kArmBitsPerWord));
3482          __ Lsr(temp, low, temp);
3483          __ orr(o_h, o_h, ShifterOperand(temp));
3484          // If the shift is > 32 bits, override the high part
3485          __ subs(temp, o_l, ShifterOperand(kArmBitsPerWord));
3486          __ it(PL);
3487          __ Lsl(o_h, low, temp, PL);
3488          // Shift the low part
3489          __ Lsl(o_l, low, o_l);
3490        } else if (op->IsShr()) {
3491          __ and_(o_h, second_reg, ShifterOperand(kMaxLongShiftValue));
3492          // Shift the low part
3493          __ Lsr(o_l, low, o_h);
3494          // Shift the high part and `or` what underflew on the low part
3495          __ rsb(temp, o_h, ShifterOperand(kArmBitsPerWord));
3496          __ Lsl(temp, high, temp);
3497          __ orr(o_l, o_l, ShifterOperand(temp));
3498          // If the shift is > 32 bits, override the low part
3499          __ subs(temp, o_h, ShifterOperand(kArmBitsPerWord));
3500          __ it(PL);
3501          __ Asr(o_l, high, temp, PL);
3502          // Shift the high part
3503          __ Asr(o_h, high, o_h);
3504        } else {
3505          __ and_(o_h, second_reg, ShifterOperand(kMaxLongShiftValue));
3506          // same as Shr except we use `Lsr`s and not `Asr`s
3507          __ Lsr(o_l, low, o_h);
3508          __ rsb(temp, o_h, ShifterOperand(kArmBitsPerWord));
3509          __ Lsl(temp, high, temp);
3510          __ orr(o_l, o_l, ShifterOperand(temp));
3511          __ subs(temp, o_h, ShifterOperand(kArmBitsPerWord));
3512          __ it(PL);
3513          __ Lsr(o_l, high, temp, PL);
3514          __ Lsr(o_h, high, o_h);
3515        }
3516      } else {
3517        // Register allocator doesn't create partial overlap.
3518        DCHECK_NE(o_l, high);
3519        DCHECK_NE(o_h, low);
3520        int32_t cst = second.GetConstant()->AsIntConstant()->GetValue();
3521        uint32_t shift_value = static_cast<uint32_t>(cst & kMaxLongShiftValue);
3522        if (shift_value > 32) {
3523          if (op->IsShl()) {
3524            __ Lsl(o_h, low, shift_value - 32);
3525            __ LoadImmediate(o_l, 0);
3526          } else if (op->IsShr()) {
3527            __ Asr(o_l, high, shift_value - 32);
3528            __ Asr(o_h, high, 31);
3529          } else {
3530            __ Lsr(o_l, high, shift_value - 32);
3531            __ LoadImmediate(o_h, 0);
3532          }
3533        } else if (shift_value == 32) {
3534          if (op->IsShl()) {
3535            __ mov(o_h, ShifterOperand(low));
3536            __ LoadImmediate(o_l, 0);
3537          } else if (op->IsShr()) {
3538            __ mov(o_l, ShifterOperand(high));
3539            __ Asr(o_h, high, 31);
3540          } else {
3541            __ mov(o_l, ShifterOperand(high));
3542            __ LoadImmediate(o_h, 0);
3543          }
3544        } else if (shift_value == 1) {
3545          if (op->IsShl()) {
3546            __ Lsls(o_l, low, 1);
3547            __ adc(o_h, high, ShifterOperand(high));
3548          } else if (op->IsShr()) {
3549            __ Asrs(o_h, high, 1);
3550            __ Rrx(o_l, low);
3551          } else {
3552            __ Lsrs(o_h, high, 1);
3553            __ Rrx(o_l, low);
3554          }
3555        } else {
3556          DCHECK(2 <= shift_value && shift_value < 32) << shift_value;
3557          if (op->IsShl()) {
3558            __ Lsl(o_h, high, shift_value);
3559            __ orr(o_h, o_h, ShifterOperand(low, LSR, 32 - shift_value));
3560            __ Lsl(o_l, low, shift_value);
3561          } else if (op->IsShr()) {
3562            __ Lsr(o_l, low, shift_value);
3563            __ orr(o_l, o_l, ShifterOperand(high, LSL, 32 - shift_value));
3564            __ Asr(o_h, high, shift_value);
3565          } else {
3566            __ Lsr(o_l, low, shift_value);
3567            __ orr(o_l, o_l, ShifterOperand(high, LSL, 32 - shift_value));
3568            __ Lsr(o_h, high, shift_value);
3569          }
3570        }
3571      }
3572      break;
3573    }
3574    default:
3575      LOG(FATAL) << "Unexpected operation type " << type;
3576      UNREACHABLE();
3577  }
3578}
3579
3580void LocationsBuilderARM::VisitShl(HShl* shl) {
3581  HandleShift(shl);
3582}
3583
3584void InstructionCodeGeneratorARM::VisitShl(HShl* shl) {
3585  HandleShift(shl);
3586}
3587
3588void LocationsBuilderARM::VisitShr(HShr* shr) {
3589  HandleShift(shr);
3590}
3591
3592void InstructionCodeGeneratorARM::VisitShr(HShr* shr) {
3593  HandleShift(shr);
3594}
3595
3596void LocationsBuilderARM::VisitUShr(HUShr* ushr) {
3597  HandleShift(ushr);
3598}
3599
3600void InstructionCodeGeneratorARM::VisitUShr(HUShr* ushr) {
3601  HandleShift(ushr);
3602}
3603
3604void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) {
3605  LocationSummary* locations =
3606      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
3607  InvokeRuntimeCallingConvention calling_convention;
3608  locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3609  locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
3610  locations->SetOut(Location::RegisterLocation(R0));
3611}
3612
3613void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) {
3614  // Note: if heap poisoning is enabled, the entry point takes cares
3615  // of poisoning the reference.
3616  codegen_->InvokeRuntime(instruction->GetEntrypoint(),
3617                          instruction,
3618                          instruction->GetDexPc(),
3619                          nullptr);
3620  CheckEntrypointTypes<kQuickAllocObjectWithAccessCheck, void*, uint32_t, ArtMethod*>();
3621}
3622
3623void LocationsBuilderARM::VisitNewArray(HNewArray* instruction) {
3624  LocationSummary* locations =
3625      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
3626  InvokeRuntimeCallingConvention calling_convention;
3627  locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3628  locations->SetOut(Location::RegisterLocation(R0));
3629  locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
3630  locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
3631}
3632
3633void InstructionCodeGeneratorARM::VisitNewArray(HNewArray* instruction) {
3634  InvokeRuntimeCallingConvention calling_convention;
3635  __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
3636  // Note: if heap poisoning is enabled, the entry point takes cares
3637  // of poisoning the reference.
3638  codegen_->InvokeRuntime(instruction->GetEntrypoint(),
3639                          instruction,
3640                          instruction->GetDexPc(),
3641                          nullptr);
3642  CheckEntrypointTypes<kQuickAllocArrayWithAccessCheck, void*, uint32_t, int32_t, ArtMethod*>();
3643}
3644
3645void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) {
3646  LocationSummary* locations =
3647      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3648  Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
3649  if (location.IsStackSlot()) {
3650    location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
3651  } else if (location.IsDoubleStackSlot()) {
3652    location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
3653  }
3654  locations->SetOut(location);
3655}
3656
3657void InstructionCodeGeneratorARM::VisitParameterValue(
3658    HParameterValue* instruction ATTRIBUTE_UNUSED) {
3659  // Nothing to do, the parameter is already at its location.
3660}
3661
3662void LocationsBuilderARM::VisitCurrentMethod(HCurrentMethod* instruction) {
3663  LocationSummary* locations =
3664      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3665  locations->SetOut(Location::RegisterLocation(kMethodRegisterArgument));
3666}
3667
3668void InstructionCodeGeneratorARM::VisitCurrentMethod(HCurrentMethod* instruction ATTRIBUTE_UNUSED) {
3669  // Nothing to do, the method is already at its location.
3670}
3671
3672void LocationsBuilderARM::VisitNot(HNot* not_) {
3673  LocationSummary* locations =
3674      new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
3675  locations->SetInAt(0, Location::RequiresRegister());
3676  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3677}
3678
3679void InstructionCodeGeneratorARM::VisitNot(HNot* not_) {
3680  LocationSummary* locations = not_->GetLocations();
3681  Location out = locations->Out();
3682  Location in = locations->InAt(0);
3683  switch (not_->GetResultType()) {
3684    case Primitive::kPrimInt:
3685      __ mvn(out.AsRegister<Register>(), ShifterOperand(in.AsRegister<Register>()));
3686      break;
3687
3688    case Primitive::kPrimLong:
3689      __ mvn(out.AsRegisterPairLow<Register>(),
3690             ShifterOperand(in.AsRegisterPairLow<Register>()));
3691      __ mvn(out.AsRegisterPairHigh<Register>(),
3692             ShifterOperand(in.AsRegisterPairHigh<Register>()));
3693      break;
3694
3695    default:
3696      LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
3697  }
3698}
3699
3700void LocationsBuilderARM::VisitBooleanNot(HBooleanNot* bool_not) {
3701  LocationSummary* locations =
3702      new (GetGraph()->GetArena()) LocationSummary(bool_not, LocationSummary::kNoCall);
3703  locations->SetInAt(0, Location::RequiresRegister());
3704  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3705}
3706
3707void InstructionCodeGeneratorARM::VisitBooleanNot(HBooleanNot* bool_not) {
3708  LocationSummary* locations = bool_not->GetLocations();
3709  Location out = locations->Out();
3710  Location in = locations->InAt(0);
3711  __ eor(out.AsRegister<Register>(), in.AsRegister<Register>(), ShifterOperand(1));
3712}
3713
3714void LocationsBuilderARM::VisitCompare(HCompare* compare) {
3715  LocationSummary* locations =
3716      new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
3717  switch (compare->InputAt(0)->GetType()) {
3718    case Primitive::kPrimLong: {
3719      locations->SetInAt(0, Location::RequiresRegister());
3720      locations->SetInAt(1, Location::RequiresRegister());
3721      // Output overlaps because it is written before doing the low comparison.
3722      locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
3723      break;
3724    }
3725    case Primitive::kPrimFloat:
3726    case Primitive::kPrimDouble: {
3727      locations->SetInAt(0, Location::RequiresFpuRegister());
3728      locations->SetInAt(1, Location::RequiresFpuRegister());
3729      locations->SetOut(Location::RequiresRegister());
3730      break;
3731    }
3732    default:
3733      LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
3734  }
3735}
3736
3737void InstructionCodeGeneratorARM::VisitCompare(HCompare* compare) {
3738  LocationSummary* locations = compare->GetLocations();
3739  Register out = locations->Out().AsRegister<Register>();
3740  Location left = locations->InAt(0);
3741  Location right = locations->InAt(1);
3742
3743  Label less, greater, done;
3744  Primitive::Type type = compare->InputAt(0)->GetType();
3745  switch (type) {
3746    case Primitive::kPrimLong: {
3747      __ cmp(left.AsRegisterPairHigh<Register>(),
3748             ShifterOperand(right.AsRegisterPairHigh<Register>()));  // Signed compare.
3749      __ b(&less, LT);
3750      __ b(&greater, GT);
3751      // Do LoadImmediate before the last `cmp`, as LoadImmediate might affect the status flags.
3752      __ LoadImmediate(out, 0);
3753      __ cmp(left.AsRegisterPairLow<Register>(),
3754             ShifterOperand(right.AsRegisterPairLow<Register>()));  // Unsigned compare.
3755      break;
3756    }
3757    case Primitive::kPrimFloat:
3758    case Primitive::kPrimDouble: {
3759      __ LoadImmediate(out, 0);
3760      if (type == Primitive::kPrimFloat) {
3761        __ vcmps(left.AsFpuRegister<SRegister>(), right.AsFpuRegister<SRegister>());
3762      } else {
3763        __ vcmpd(FromLowSToD(left.AsFpuRegisterPairLow<SRegister>()),
3764                 FromLowSToD(right.AsFpuRegisterPairLow<SRegister>()));
3765      }
3766      __ vmstat();  // transfer FP status register to ARM APSR.
3767      __ b(compare->IsGtBias() ? &greater : &less, VS);  // VS for unordered.
3768      break;
3769    }
3770    default:
3771      LOG(FATAL) << "Unexpected compare type " << type;
3772  }
3773  __ b(&done, EQ);
3774  __ b(&less, LO);  // LO is for both: unsigned compare for longs and 'less than' for floats.
3775
3776  __ Bind(&greater);
3777  __ LoadImmediate(out, 1);
3778  __ b(&done);
3779
3780  __ Bind(&less);
3781  __ LoadImmediate(out, -1);
3782
3783  __ Bind(&done);
3784}
3785
3786void LocationsBuilderARM::VisitPhi(HPhi* instruction) {
3787  LocationSummary* locations =
3788      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3789  for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
3790    locations->SetInAt(i, Location::Any());
3791  }
3792  locations->SetOut(Location::Any());
3793}
3794
3795void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction ATTRIBUTE_UNUSED) {
3796  LOG(FATAL) << "Unreachable";
3797}
3798
3799void InstructionCodeGeneratorARM::GenerateMemoryBarrier(MemBarrierKind kind) {
3800  // TODO (ported from quick): revisit Arm barrier kinds
3801  DmbOptions flavor = DmbOptions::ISH;  // quiet c++ warnings
3802  switch (kind) {
3803    case MemBarrierKind::kAnyStore:
3804    case MemBarrierKind::kLoadAny:
3805    case MemBarrierKind::kAnyAny: {
3806      flavor = DmbOptions::ISH;
3807      break;
3808    }
3809    case MemBarrierKind::kStoreStore: {
3810      flavor = DmbOptions::ISHST;
3811      break;
3812    }
3813    default:
3814      LOG(FATAL) << "Unexpected memory barrier " << kind;
3815  }
3816  __ dmb(flavor);
3817}
3818
3819void InstructionCodeGeneratorARM::GenerateWideAtomicLoad(Register addr,
3820                                                         uint32_t offset,
3821                                                         Register out_lo,
3822                                                         Register out_hi) {
3823  if (offset != 0) {
3824    // Ensure `out_lo` is different from `addr`, so that loading
3825    // `offset` into `out_lo` does not clutter `addr`.
3826    DCHECK_NE(out_lo, addr);
3827    __ LoadImmediate(out_lo, offset);
3828    __ add(IP, addr, ShifterOperand(out_lo));
3829    addr = IP;
3830  }
3831  __ ldrexd(out_lo, out_hi, addr);
3832}
3833
3834void InstructionCodeGeneratorARM::GenerateWideAtomicStore(Register addr,
3835                                                          uint32_t offset,
3836                                                          Register value_lo,
3837                                                          Register value_hi,
3838                                                          Register temp1,
3839                                                          Register temp2,
3840                                                          HInstruction* instruction) {
3841  Label fail;
3842  if (offset != 0) {
3843    __ LoadImmediate(temp1, offset);
3844    __ add(IP, addr, ShifterOperand(temp1));
3845    addr = IP;
3846  }
3847  __ Bind(&fail);
3848  // We need a load followed by store. (The address used in a STREX instruction must
3849  // be the same as the address in the most recently executed LDREX instruction.)
3850  __ ldrexd(temp1, temp2, addr);
3851  codegen_->MaybeRecordImplicitNullCheck(instruction);
3852  __ strexd(temp1, value_lo, value_hi, addr);
3853  __ CompareAndBranchIfNonZero(temp1, &fail);
3854}
3855
3856void LocationsBuilderARM::HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info) {
3857  DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3858
3859  LocationSummary* locations =
3860      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3861  locations->SetInAt(0, Location::RequiresRegister());
3862
3863  Primitive::Type field_type = field_info.GetFieldType();
3864  if (Primitive::IsFloatingPointType(field_type)) {
3865    locations->SetInAt(1, Location::RequiresFpuRegister());
3866  } else {
3867    locations->SetInAt(1, Location::RequiresRegister());
3868  }
3869
3870  bool is_wide = field_type == Primitive::kPrimLong || field_type == Primitive::kPrimDouble;
3871  bool generate_volatile = field_info.IsVolatile()
3872      && is_wide
3873      && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
3874  bool needs_write_barrier =
3875      CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
3876  // Temporary registers for the write barrier.
3877  // TODO: consider renaming StoreNeedsWriteBarrier to StoreNeedsGCMark.
3878  if (needs_write_barrier) {
3879    locations->AddTemp(Location::RequiresRegister());  // Possibly used for reference poisoning too.
3880    locations->AddTemp(Location::RequiresRegister());
3881  } else if (generate_volatile) {
3882    // Arm encoding have some additional constraints for ldrexd/strexd:
3883    // - registers need to be consecutive
3884    // - the first register should be even but not R14.
3885    // We don't test for Arm yet, and the assertion makes sure that we revisit this if we ever
3886    // enable Arm encoding.
3887    DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
3888
3889    locations->AddTemp(Location::RequiresRegister());
3890    locations->AddTemp(Location::RequiresRegister());
3891    if (field_type == Primitive::kPrimDouble) {
3892      // For doubles we need two more registers to copy the value.
3893      locations->AddTemp(Location::RegisterLocation(R2));
3894      locations->AddTemp(Location::RegisterLocation(R3));
3895    }
3896  }
3897}
3898
3899void InstructionCodeGeneratorARM::HandleFieldSet(HInstruction* instruction,
3900                                                 const FieldInfo& field_info,
3901                                                 bool value_can_be_null) {
3902  DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3903
3904  LocationSummary* locations = instruction->GetLocations();
3905  Register base = locations->InAt(0).AsRegister<Register>();
3906  Location value = locations->InAt(1);
3907
3908  bool is_volatile = field_info.IsVolatile();
3909  bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
3910  Primitive::Type field_type = field_info.GetFieldType();
3911  uint32_t offset = field_info.GetFieldOffset().Uint32Value();
3912  bool needs_write_barrier =
3913      CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
3914
3915  if (is_volatile) {
3916    GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
3917  }
3918
3919  switch (field_type) {
3920    case Primitive::kPrimBoolean:
3921    case Primitive::kPrimByte: {
3922      __ StoreToOffset(kStoreByte, value.AsRegister<Register>(), base, offset);
3923      break;
3924    }
3925
3926    case Primitive::kPrimShort:
3927    case Primitive::kPrimChar: {
3928      __ StoreToOffset(kStoreHalfword, value.AsRegister<Register>(), base, offset);
3929      break;
3930    }
3931
3932    case Primitive::kPrimInt:
3933    case Primitive::kPrimNot: {
3934      if (kPoisonHeapReferences && needs_write_barrier) {
3935        // Note that in the case where `value` is a null reference,
3936        // we do not enter this block, as a null reference does not
3937        // need poisoning.
3938        DCHECK_EQ(field_type, Primitive::kPrimNot);
3939        Register temp = locations->GetTemp(0).AsRegister<Register>();
3940        __ Mov(temp, value.AsRegister<Register>());
3941        __ PoisonHeapReference(temp);
3942        __ StoreToOffset(kStoreWord, temp, base, offset);
3943      } else {
3944        __ StoreToOffset(kStoreWord, value.AsRegister<Register>(), base, offset);
3945      }
3946      break;
3947    }
3948
3949    case Primitive::kPrimLong: {
3950      if (is_volatile && !atomic_ldrd_strd) {
3951        GenerateWideAtomicStore(base, offset,
3952                                value.AsRegisterPairLow<Register>(),
3953                                value.AsRegisterPairHigh<Register>(),
3954                                locations->GetTemp(0).AsRegister<Register>(),
3955                                locations->GetTemp(1).AsRegister<Register>(),
3956                                instruction);
3957      } else {
3958        __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), base, offset);
3959        codegen_->MaybeRecordImplicitNullCheck(instruction);
3960      }
3961      break;
3962    }
3963
3964    case Primitive::kPrimFloat: {
3965      __ StoreSToOffset(value.AsFpuRegister<SRegister>(), base, offset);
3966      break;
3967    }
3968
3969    case Primitive::kPrimDouble: {
3970      DRegister value_reg = FromLowSToD(value.AsFpuRegisterPairLow<SRegister>());
3971      if (is_volatile && !atomic_ldrd_strd) {
3972        Register value_reg_lo = locations->GetTemp(0).AsRegister<Register>();
3973        Register value_reg_hi = locations->GetTemp(1).AsRegister<Register>();
3974
3975        __ vmovrrd(value_reg_lo, value_reg_hi, value_reg);
3976
3977        GenerateWideAtomicStore(base, offset,
3978                                value_reg_lo,
3979                                value_reg_hi,
3980                                locations->GetTemp(2).AsRegister<Register>(),
3981                                locations->GetTemp(3).AsRegister<Register>(),
3982                                instruction);
3983      } else {
3984        __ StoreDToOffset(value_reg, base, offset);
3985        codegen_->MaybeRecordImplicitNullCheck(instruction);
3986      }
3987      break;
3988    }
3989
3990    case Primitive::kPrimVoid:
3991      LOG(FATAL) << "Unreachable type " << field_type;
3992      UNREACHABLE();
3993  }
3994
3995  // Longs and doubles are handled in the switch.
3996  if (field_type != Primitive::kPrimLong && field_type != Primitive::kPrimDouble) {
3997    codegen_->MaybeRecordImplicitNullCheck(instruction);
3998  }
3999
4000  if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
4001    Register temp = locations->GetTemp(0).AsRegister<Register>();
4002    Register card = locations->GetTemp(1).AsRegister<Register>();
4003    codegen_->MarkGCCard(
4004        temp, card, base, value.AsRegister<Register>(), value_can_be_null);
4005  }
4006
4007  if (is_volatile) {
4008    GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
4009  }
4010}
4011
4012void LocationsBuilderARM::HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info) {
4013  DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
4014
4015  bool object_field_get_with_read_barrier =
4016      kEmitCompilerReadBarrier && (field_info.GetFieldType() == Primitive::kPrimNot);
4017  LocationSummary* locations =
4018      new (GetGraph()->GetArena()) LocationSummary(instruction,
4019                                                   object_field_get_with_read_barrier ?
4020                                                       LocationSummary::kCallOnSlowPath :
4021                                                       LocationSummary::kNoCall);
4022  locations->SetInAt(0, Location::RequiresRegister());
4023
4024  bool volatile_for_double = field_info.IsVolatile()
4025      && (field_info.GetFieldType() == Primitive::kPrimDouble)
4026      && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
4027  // The output overlaps in case of volatile long: we don't want the
4028  // code generated by GenerateWideAtomicLoad to overwrite the
4029  // object's location.  Likewise, in the case of an object field get
4030  // with read barriers enabled, we do not want the load to overwrite
4031  // the object's location, as we need it to emit the read barrier.
4032  bool overlap = (field_info.IsVolatile() && (field_info.GetFieldType() == Primitive::kPrimLong)) ||
4033      object_field_get_with_read_barrier;
4034
4035  if (Primitive::IsFloatingPointType(instruction->GetType())) {
4036    locations->SetOut(Location::RequiresFpuRegister());
4037  } else {
4038    locations->SetOut(Location::RequiresRegister(),
4039                      (overlap ? Location::kOutputOverlap : Location::kNoOutputOverlap));
4040  }
4041  if (volatile_for_double) {
4042    // Arm encoding have some additional constraints for ldrexd/strexd:
4043    // - registers need to be consecutive
4044    // - the first register should be even but not R14.
4045    // We don't test for Arm yet, and the assertion makes sure that we revisit this if we ever
4046    // enable Arm encoding.
4047    DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
4048    locations->AddTemp(Location::RequiresRegister());
4049    locations->AddTemp(Location::RequiresRegister());
4050  }
4051}
4052
4053Location LocationsBuilderARM::ArmEncodableConstantOrRegister(HInstruction* constant,
4054                                                             Opcode opcode) {
4055  DCHECK(!Primitive::IsFloatingPointType(constant->GetType()));
4056  if (constant->IsConstant() &&
4057      CanEncodeConstantAsImmediate(constant->AsConstant(), opcode)) {
4058    return Location::ConstantLocation(constant->AsConstant());
4059  }
4060  return Location::RequiresRegister();
4061}
4062
4063bool LocationsBuilderARM::CanEncodeConstantAsImmediate(HConstant* input_cst,
4064                                                       Opcode opcode) {
4065  uint64_t value = static_cast<uint64_t>(Int64FromConstant(input_cst));
4066  if (Primitive::Is64BitType(input_cst->GetType())) {
4067    return CanEncodeConstantAsImmediate(Low32Bits(value), opcode) &&
4068        CanEncodeConstantAsImmediate(High32Bits(value), opcode);
4069  } else {
4070    return CanEncodeConstantAsImmediate(Low32Bits(value), opcode);
4071  }
4072}
4073
4074bool LocationsBuilderARM::CanEncodeConstantAsImmediate(uint32_t value, Opcode opcode) {
4075  ShifterOperand so;
4076  ArmAssembler* assembler = codegen_->GetAssembler();
4077  if (assembler->ShifterOperandCanHold(kNoRegister, kNoRegister, opcode, value, &so)) {
4078    return true;
4079  }
4080  Opcode neg_opcode = kNoOperand;
4081  switch (opcode) {
4082    case AND:
4083      neg_opcode = BIC;
4084      break;
4085    case ORR:
4086      neg_opcode = ORN;
4087      break;
4088    default:
4089      return false;
4090  }
4091  return assembler->ShifterOperandCanHold(kNoRegister, kNoRegister, neg_opcode, ~value, &so);
4092}
4093
4094void InstructionCodeGeneratorARM::HandleFieldGet(HInstruction* instruction,
4095                                                 const FieldInfo& field_info) {
4096  DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
4097
4098  LocationSummary* locations = instruction->GetLocations();
4099  Location base_loc = locations->InAt(0);
4100  Register base = base_loc.AsRegister<Register>();
4101  Location out = locations->Out();
4102  bool is_volatile = field_info.IsVolatile();
4103  bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
4104  Primitive::Type field_type = field_info.GetFieldType();
4105  uint32_t offset = field_info.GetFieldOffset().Uint32Value();
4106
4107  switch (field_type) {
4108    case Primitive::kPrimBoolean: {
4109      __ LoadFromOffset(kLoadUnsignedByte, out.AsRegister<Register>(), base, offset);
4110      break;
4111    }
4112
4113    case Primitive::kPrimByte: {
4114      __ LoadFromOffset(kLoadSignedByte, out.AsRegister<Register>(), base, offset);
4115      break;
4116    }
4117
4118    case Primitive::kPrimShort: {
4119      __ LoadFromOffset(kLoadSignedHalfword, out.AsRegister<Register>(), base, offset);
4120      break;
4121    }
4122
4123    case Primitive::kPrimChar: {
4124      __ LoadFromOffset(kLoadUnsignedHalfword, out.AsRegister<Register>(), base, offset);
4125      break;
4126    }
4127
4128    case Primitive::kPrimInt:
4129    case Primitive::kPrimNot: {
4130      __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), base, offset);
4131      break;
4132    }
4133
4134    case Primitive::kPrimLong: {
4135      if (is_volatile && !atomic_ldrd_strd) {
4136        GenerateWideAtomicLoad(base, offset,
4137                               out.AsRegisterPairLow<Register>(),
4138                               out.AsRegisterPairHigh<Register>());
4139      } else {
4140        __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), base, offset);
4141      }
4142      break;
4143    }
4144
4145    case Primitive::kPrimFloat: {
4146      __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), base, offset);
4147      break;
4148    }
4149
4150    case Primitive::kPrimDouble: {
4151      DRegister out_reg = FromLowSToD(out.AsFpuRegisterPairLow<SRegister>());
4152      if (is_volatile && !atomic_ldrd_strd) {
4153        Register lo = locations->GetTemp(0).AsRegister<Register>();
4154        Register hi = locations->GetTemp(1).AsRegister<Register>();
4155        GenerateWideAtomicLoad(base, offset, lo, hi);
4156        codegen_->MaybeRecordImplicitNullCheck(instruction);
4157        __ vmovdrr(out_reg, lo, hi);
4158      } else {
4159        __ LoadDFromOffset(out_reg, base, offset);
4160        codegen_->MaybeRecordImplicitNullCheck(instruction);
4161      }
4162      break;
4163    }
4164
4165    case Primitive::kPrimVoid:
4166      LOG(FATAL) << "Unreachable type " << field_type;
4167      UNREACHABLE();
4168  }
4169
4170  // Doubles are handled in the switch.
4171  if (field_type != Primitive::kPrimDouble) {
4172    codegen_->MaybeRecordImplicitNullCheck(instruction);
4173  }
4174
4175  if (is_volatile) {
4176    GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
4177  }
4178
4179  if (field_type == Primitive::kPrimNot) {
4180    codegen_->MaybeGenerateReadBarrier(instruction, out, out, base_loc, offset);
4181  }
4182}
4183
4184void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
4185  HandleFieldSet(instruction, instruction->GetFieldInfo());
4186}
4187
4188void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
4189  HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
4190}
4191
4192void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
4193  HandleFieldGet(instruction, instruction->GetFieldInfo());
4194}
4195
4196void InstructionCodeGeneratorARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
4197  HandleFieldGet(instruction, instruction->GetFieldInfo());
4198}
4199
4200void LocationsBuilderARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
4201  HandleFieldGet(instruction, instruction->GetFieldInfo());
4202}
4203
4204void InstructionCodeGeneratorARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
4205  HandleFieldGet(instruction, instruction->GetFieldInfo());
4206}
4207
4208void LocationsBuilderARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
4209  HandleFieldSet(instruction, instruction->GetFieldInfo());
4210}
4211
4212void InstructionCodeGeneratorARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
4213  HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
4214}
4215
4216void LocationsBuilderARM::VisitUnresolvedInstanceFieldGet(
4217    HUnresolvedInstanceFieldGet* instruction) {
4218  FieldAccessCallingConventionARM calling_convention;
4219  codegen_->CreateUnresolvedFieldLocationSummary(
4220      instruction, instruction->GetFieldType(), calling_convention);
4221}
4222
4223void InstructionCodeGeneratorARM::VisitUnresolvedInstanceFieldGet(
4224    HUnresolvedInstanceFieldGet* instruction) {
4225  FieldAccessCallingConventionARM calling_convention;
4226  codegen_->GenerateUnresolvedFieldAccess(instruction,
4227                                          instruction->GetFieldType(),
4228                                          instruction->GetFieldIndex(),
4229                                          instruction->GetDexPc(),
4230                                          calling_convention);
4231}
4232
4233void LocationsBuilderARM::VisitUnresolvedInstanceFieldSet(
4234    HUnresolvedInstanceFieldSet* instruction) {
4235  FieldAccessCallingConventionARM calling_convention;
4236  codegen_->CreateUnresolvedFieldLocationSummary(
4237      instruction, instruction->GetFieldType(), calling_convention);
4238}
4239
4240void InstructionCodeGeneratorARM::VisitUnresolvedInstanceFieldSet(
4241    HUnresolvedInstanceFieldSet* instruction) {
4242  FieldAccessCallingConventionARM calling_convention;
4243  codegen_->GenerateUnresolvedFieldAccess(instruction,
4244                                          instruction->GetFieldType(),
4245                                          instruction->GetFieldIndex(),
4246                                          instruction->GetDexPc(),
4247                                          calling_convention);
4248}
4249
4250void LocationsBuilderARM::VisitUnresolvedStaticFieldGet(
4251    HUnresolvedStaticFieldGet* instruction) {
4252  FieldAccessCallingConventionARM calling_convention;
4253  codegen_->CreateUnresolvedFieldLocationSummary(
4254      instruction, instruction->GetFieldType(), calling_convention);
4255}
4256
4257void InstructionCodeGeneratorARM::VisitUnresolvedStaticFieldGet(
4258    HUnresolvedStaticFieldGet* instruction) {
4259  FieldAccessCallingConventionARM calling_convention;
4260  codegen_->GenerateUnresolvedFieldAccess(instruction,
4261                                          instruction->GetFieldType(),
4262                                          instruction->GetFieldIndex(),
4263                                          instruction->GetDexPc(),
4264                                          calling_convention);
4265}
4266
4267void LocationsBuilderARM::VisitUnresolvedStaticFieldSet(
4268    HUnresolvedStaticFieldSet* instruction) {
4269  FieldAccessCallingConventionARM calling_convention;
4270  codegen_->CreateUnresolvedFieldLocationSummary(
4271      instruction, instruction->GetFieldType(), calling_convention);
4272}
4273
4274void InstructionCodeGeneratorARM::VisitUnresolvedStaticFieldSet(
4275    HUnresolvedStaticFieldSet* instruction) {
4276  FieldAccessCallingConventionARM calling_convention;
4277  codegen_->GenerateUnresolvedFieldAccess(instruction,
4278                                          instruction->GetFieldType(),
4279                                          instruction->GetFieldIndex(),
4280                                          instruction->GetDexPc(),
4281                                          calling_convention);
4282}
4283
4284void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) {
4285  LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
4286      ? LocationSummary::kCallOnSlowPath
4287      : LocationSummary::kNoCall;
4288  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
4289  locations->SetInAt(0, Location::RequiresRegister());
4290  if (instruction->HasUses()) {
4291    locations->SetOut(Location::SameAsFirstInput());
4292  }
4293}
4294
4295void InstructionCodeGeneratorARM::GenerateImplicitNullCheck(HNullCheck* instruction) {
4296  if (codegen_->CanMoveNullCheckToUser(instruction)) {
4297    return;
4298  }
4299  Location obj = instruction->GetLocations()->InAt(0);
4300
4301  __ LoadFromOffset(kLoadWord, IP, obj.AsRegister<Register>(), 0);
4302  codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
4303}
4304
4305void InstructionCodeGeneratorARM::GenerateExplicitNullCheck(HNullCheck* instruction) {
4306  SlowPathCode* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction);
4307  codegen_->AddSlowPath(slow_path);
4308
4309  LocationSummary* locations = instruction->GetLocations();
4310  Location obj = locations->InAt(0);
4311
4312  __ CompareAndBranchIfZero(obj.AsRegister<Register>(), slow_path->GetEntryLabel());
4313}
4314
4315void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) {
4316  if (codegen_->IsImplicitNullCheckAllowed(instruction)) {
4317    GenerateImplicitNullCheck(instruction);
4318  } else {
4319    GenerateExplicitNullCheck(instruction);
4320  }
4321}
4322
4323void LocationsBuilderARM::VisitArrayGet(HArrayGet* instruction) {
4324  bool object_array_get_with_read_barrier =
4325      kEmitCompilerReadBarrier && (instruction->GetType() == Primitive::kPrimNot);
4326  LocationSummary* locations =
4327      new (GetGraph()->GetArena()) LocationSummary(instruction,
4328                                                   object_array_get_with_read_barrier ?
4329                                                       LocationSummary::kCallOnSlowPath :
4330                                                       LocationSummary::kNoCall);
4331  locations->SetInAt(0, Location::RequiresRegister());
4332  locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
4333  if (Primitive::IsFloatingPointType(instruction->GetType())) {
4334    locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
4335  } else {
4336    // The output overlaps in the case of an object array get with
4337    // read barriers enabled: we do not want the move to overwrite the
4338    // array's location, as we need it to emit the read barrier.
4339    locations->SetOut(
4340        Location::RequiresRegister(),
4341        object_array_get_with_read_barrier ? Location::kOutputOverlap : Location::kNoOutputOverlap);
4342  }
4343}
4344
4345void InstructionCodeGeneratorARM::VisitArrayGet(HArrayGet* instruction) {
4346  LocationSummary* locations = instruction->GetLocations();
4347  Location obj_loc = locations->InAt(0);
4348  Register obj = obj_loc.AsRegister<Register>();
4349  Location index = locations->InAt(1);
4350  Primitive::Type type = instruction->GetType();
4351
4352  switch (type) {
4353    case Primitive::kPrimBoolean: {
4354      uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
4355      Register out = locations->Out().AsRegister<Register>();
4356      if (index.IsConstant()) {
4357        size_t offset =
4358            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
4359        __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset);
4360      } else {
4361        __ add(IP, obj, ShifterOperand(index.AsRegister<Register>()));
4362        __ LoadFromOffset(kLoadUnsignedByte, out, IP, data_offset);
4363      }
4364      break;
4365    }
4366
4367    case Primitive::kPrimByte: {
4368      uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
4369      Register out = locations->Out().AsRegister<Register>();
4370      if (index.IsConstant()) {
4371        size_t offset =
4372            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
4373        __ LoadFromOffset(kLoadSignedByte, out, obj, offset);
4374      } else {
4375        __ add(IP, obj, ShifterOperand(index.AsRegister<Register>()));
4376        __ LoadFromOffset(kLoadSignedByte, out, IP, data_offset);
4377      }
4378      break;
4379    }
4380
4381    case Primitive::kPrimShort: {
4382      uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
4383      Register out = locations->Out().AsRegister<Register>();
4384      if (index.IsConstant()) {
4385        size_t offset =
4386            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
4387        __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset);
4388      } else {
4389        __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
4390        __ LoadFromOffset(kLoadSignedHalfword, out, IP, data_offset);
4391      }
4392      break;
4393    }
4394
4395    case Primitive::kPrimChar: {
4396      uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
4397      Register out = locations->Out().AsRegister<Register>();
4398      if (index.IsConstant()) {
4399        size_t offset =
4400            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
4401        __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset);
4402      } else {
4403        __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
4404        __ LoadFromOffset(kLoadUnsignedHalfword, out, IP, data_offset);
4405      }
4406      break;
4407    }
4408
4409    case Primitive::kPrimInt:
4410    case Primitive::kPrimNot: {
4411      static_assert(
4412          sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
4413          "art::mirror::HeapReference<mirror::Object> and int32_t have different sizes.");
4414      uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
4415      Register out = locations->Out().AsRegister<Register>();
4416      if (index.IsConstant()) {
4417        size_t offset =
4418            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4419        __ LoadFromOffset(kLoadWord, out, obj, offset);
4420      } else {
4421        __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
4422        __ LoadFromOffset(kLoadWord, out, IP, data_offset);
4423      }
4424      break;
4425    }
4426
4427    case Primitive::kPrimLong: {
4428      uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
4429      Location out = locations->Out();
4430      if (index.IsConstant()) {
4431        size_t offset =
4432            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
4433        __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), obj, offset);
4434      } else {
4435        __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
4436        __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), IP, data_offset);
4437      }
4438      break;
4439    }
4440
4441    case Primitive::kPrimFloat: {
4442      uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
4443      Location out = locations->Out();
4444      DCHECK(out.IsFpuRegister());
4445      if (index.IsConstant()) {
4446        size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4447        __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), obj, offset);
4448      } else {
4449        __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
4450        __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), IP, data_offset);
4451      }
4452      break;
4453    }
4454
4455    case Primitive::kPrimDouble: {
4456      uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
4457      Location out = locations->Out();
4458      DCHECK(out.IsFpuRegisterPair());
4459      if (index.IsConstant()) {
4460        size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
4461        __ LoadDFromOffset(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()), obj, offset);
4462      } else {
4463        __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
4464        __ LoadDFromOffset(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()), IP, data_offset);
4465      }
4466      break;
4467    }
4468
4469    case Primitive::kPrimVoid:
4470      LOG(FATAL) << "Unreachable type " << type;
4471      UNREACHABLE();
4472  }
4473  codegen_->MaybeRecordImplicitNullCheck(instruction);
4474
4475  if (type == Primitive::kPrimNot) {
4476    static_assert(
4477        sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
4478        "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
4479    uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
4480    Location out = locations->Out();
4481    if (index.IsConstant()) {
4482      uint32_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4483      codegen_->MaybeGenerateReadBarrier(instruction, out, out, obj_loc, offset);
4484    } else {
4485      codegen_->MaybeGenerateReadBarrier(instruction, out, out, obj_loc, data_offset, index);
4486    }
4487  }
4488}
4489
4490void LocationsBuilderARM::VisitArraySet(HArraySet* instruction) {
4491  Primitive::Type value_type = instruction->GetComponentType();
4492
4493  bool needs_write_barrier =
4494      CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
4495  bool may_need_runtime_call_for_type_check = instruction->NeedsTypeCheck();
4496  bool object_array_set_with_read_barrier =
4497      kEmitCompilerReadBarrier && (value_type == Primitive::kPrimNot);
4498
4499  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
4500      instruction,
4501      (may_need_runtime_call_for_type_check || object_array_set_with_read_barrier) ?
4502          LocationSummary::kCallOnSlowPath :
4503          LocationSummary::kNoCall);
4504
4505  locations->SetInAt(0, Location::RequiresRegister());
4506  locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
4507  if (Primitive::IsFloatingPointType(value_type)) {
4508    locations->SetInAt(2, Location::RequiresFpuRegister());
4509  } else {
4510    locations->SetInAt(2, Location::RequiresRegister());
4511  }
4512  if (needs_write_barrier) {
4513    // Temporary registers for the write barrier.
4514    locations->AddTemp(Location::RequiresRegister());  // Possibly used for ref. poisoning too.
4515    locations->AddTemp(Location::RequiresRegister());
4516  }
4517}
4518
4519void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) {
4520  LocationSummary* locations = instruction->GetLocations();
4521  Location array_loc = locations->InAt(0);
4522  Register array = array_loc.AsRegister<Register>();
4523  Location index = locations->InAt(1);
4524  Primitive::Type value_type = instruction->GetComponentType();
4525  bool may_need_runtime_call_for_type_check = instruction->NeedsTypeCheck();
4526  bool needs_write_barrier =
4527      CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
4528
4529  switch (value_type) {
4530    case Primitive::kPrimBoolean:
4531    case Primitive::kPrimByte: {
4532      uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
4533      Register value = locations->InAt(2).AsRegister<Register>();
4534      if (index.IsConstant()) {
4535        size_t offset =
4536            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
4537        __ StoreToOffset(kStoreByte, value, array, offset);
4538      } else {
4539        __ add(IP, array, ShifterOperand(index.AsRegister<Register>()));
4540        __ StoreToOffset(kStoreByte, value, IP, data_offset);
4541      }
4542      break;
4543    }
4544
4545    case Primitive::kPrimShort:
4546    case Primitive::kPrimChar: {
4547      uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
4548      Register value = locations->InAt(2).AsRegister<Register>();
4549      if (index.IsConstant()) {
4550        size_t offset =
4551            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
4552        __ StoreToOffset(kStoreHalfword, value, array, offset);
4553      } else {
4554        __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
4555        __ StoreToOffset(kStoreHalfword, value, IP, data_offset);
4556      }
4557      break;
4558    }
4559
4560    case Primitive::kPrimNot: {
4561      uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
4562      Location value_loc = locations->InAt(2);
4563      Register value = value_loc.AsRegister<Register>();
4564      Register source = value;
4565
4566      if (instruction->InputAt(2)->IsNullConstant()) {
4567        // Just setting null.
4568        if (index.IsConstant()) {
4569          size_t offset =
4570              (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4571          __ StoreToOffset(kStoreWord, source, array, offset);
4572        } else {
4573          DCHECK(index.IsRegister()) << index;
4574          __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
4575          __ StoreToOffset(kStoreWord, source, IP, data_offset);
4576        }
4577        DCHECK(!needs_write_barrier);
4578        DCHECK(!may_need_runtime_call_for_type_check);
4579        break;
4580      }
4581
4582      DCHECK(needs_write_barrier);
4583      Register temp1 = locations->GetTemp(0).AsRegister<Register>();
4584      Register temp2 = locations->GetTemp(1).AsRegister<Register>();
4585      uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
4586      uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
4587      uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
4588      Label done;
4589      SlowPathCode* slow_path = nullptr;
4590
4591      if (may_need_runtime_call_for_type_check) {
4592        slow_path = new (GetGraph()->GetArena()) ArraySetSlowPathARM(instruction);
4593        codegen_->AddSlowPath(slow_path);
4594        if (instruction->GetValueCanBeNull()) {
4595          Label non_zero;
4596          __ CompareAndBranchIfNonZero(value, &non_zero);
4597          if (index.IsConstant()) {
4598            size_t offset =
4599               (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4600            __ StoreToOffset(kStoreWord, value, array, offset);
4601          } else {
4602            DCHECK(index.IsRegister()) << index;
4603            __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
4604            __ StoreToOffset(kStoreWord, value, IP, data_offset);
4605          }
4606          codegen_->MaybeRecordImplicitNullCheck(instruction);
4607          __ b(&done);
4608          __ Bind(&non_zero);
4609        }
4610
4611        if (kEmitCompilerReadBarrier) {
4612          // When read barriers are enabled, the type checking
4613          // instrumentation requires two read barriers:
4614          //
4615          //   __ Mov(temp2, temp1);
4616          //   // /* HeapReference<Class> */ temp1 = temp1->component_type_
4617          //   __ LoadFromOffset(kLoadWord, temp1, temp1, component_offset);
4618          //   codegen_->GenerateReadBarrier(
4619          //       instruction, temp1_loc, temp1_loc, temp2_loc, component_offset);
4620          //
4621          //   // /* HeapReference<Class> */ temp2 = value->klass_
4622          //   __ LoadFromOffset(kLoadWord, temp2, value, class_offset);
4623          //   codegen_->GenerateReadBarrier(
4624          //       instruction, temp2_loc, temp2_loc, value_loc, class_offset, temp1_loc);
4625          //
4626          //   __ cmp(temp1, ShifterOperand(temp2));
4627          //
4628          // However, the second read barrier may trash `temp`, as it
4629          // is a temporary register, and as such would not be saved
4630          // along with live registers before calling the runtime (nor
4631          // restored afterwards).  So in this case, we bail out and
4632          // delegate the work to the array set slow path.
4633          //
4634          // TODO: Extend the register allocator to support a new
4635          // "(locally) live temp" location so as to avoid always
4636          // going into the slow path when read barriers are enabled.
4637          __ b(slow_path->GetEntryLabel());
4638        } else {
4639          // /* HeapReference<Class> */ temp1 = array->klass_
4640          __ LoadFromOffset(kLoadWord, temp1, array, class_offset);
4641          codegen_->MaybeRecordImplicitNullCheck(instruction);
4642          __ MaybeUnpoisonHeapReference(temp1);
4643
4644          // /* HeapReference<Class> */ temp1 = temp1->component_type_
4645          __ LoadFromOffset(kLoadWord, temp1, temp1, component_offset);
4646          // /* HeapReference<Class> */ temp2 = value->klass_
4647          __ LoadFromOffset(kLoadWord, temp2, value, class_offset);
4648          // If heap poisoning is enabled, no need to unpoison `temp1`
4649          // nor `temp2`, as we are comparing two poisoned references.
4650          __ cmp(temp1, ShifterOperand(temp2));
4651
4652          if (instruction->StaticTypeOfArrayIsObjectArray()) {
4653            Label do_put;
4654            __ b(&do_put, EQ);
4655            // If heap poisoning is enabled, the `temp1` reference has
4656            // not been unpoisoned yet; unpoison it now.
4657            __ MaybeUnpoisonHeapReference(temp1);
4658
4659            // /* HeapReference<Class> */ temp1 = temp1->super_class_
4660            __ LoadFromOffset(kLoadWord, temp1, temp1, super_offset);
4661            // If heap poisoning is enabled, no need to unpoison
4662            // `temp1`, as we are comparing against null below.
4663            __ CompareAndBranchIfNonZero(temp1, slow_path->GetEntryLabel());
4664            __ Bind(&do_put);
4665          } else {
4666            __ b(slow_path->GetEntryLabel(), NE);
4667          }
4668        }
4669      }
4670
4671      if (kPoisonHeapReferences) {
4672        // Note that in the case where `value` is a null reference,
4673        // we do not enter this block, as a null reference does not
4674        // need poisoning.
4675        DCHECK_EQ(value_type, Primitive::kPrimNot);
4676        __ Mov(temp1, value);
4677        __ PoisonHeapReference(temp1);
4678        source = temp1;
4679      }
4680
4681      if (index.IsConstant()) {
4682        size_t offset =
4683            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4684        __ StoreToOffset(kStoreWord, source, array, offset);
4685      } else {
4686        DCHECK(index.IsRegister()) << index;
4687        __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
4688        __ StoreToOffset(kStoreWord, source, IP, data_offset);
4689      }
4690
4691      if (!may_need_runtime_call_for_type_check) {
4692        codegen_->MaybeRecordImplicitNullCheck(instruction);
4693      }
4694
4695      codegen_->MarkGCCard(temp1, temp2, array, value, instruction->GetValueCanBeNull());
4696
4697      if (done.IsLinked()) {
4698        __ Bind(&done);
4699      }
4700
4701      if (slow_path != nullptr) {
4702        __ Bind(slow_path->GetExitLabel());
4703      }
4704
4705      break;
4706    }
4707
4708    case Primitive::kPrimInt: {
4709      uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
4710      Register value = locations->InAt(2).AsRegister<Register>();
4711      if (index.IsConstant()) {
4712        size_t offset =
4713            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4714        __ StoreToOffset(kStoreWord, value, array, offset);
4715      } else {
4716        DCHECK(index.IsRegister()) << index;
4717        __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
4718        __ StoreToOffset(kStoreWord, value, IP, data_offset);
4719      }
4720
4721      codegen_->MaybeRecordImplicitNullCheck(instruction);
4722      break;
4723    }
4724
4725    case Primitive::kPrimLong: {
4726      uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
4727      Location value = locations->InAt(2);
4728      if (index.IsConstant()) {
4729        size_t offset =
4730            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
4731        __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), array, offset);
4732      } else {
4733        __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
4734        __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), IP, data_offset);
4735      }
4736      break;
4737    }
4738
4739    case Primitive::kPrimFloat: {
4740      uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
4741      Location value = locations->InAt(2);
4742      DCHECK(value.IsFpuRegister());
4743      if (index.IsConstant()) {
4744        size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4745        __ StoreSToOffset(value.AsFpuRegister<SRegister>(), array, offset);
4746      } else {
4747        __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
4748        __ StoreSToOffset(value.AsFpuRegister<SRegister>(), IP, data_offset);
4749      }
4750      break;
4751    }
4752
4753    case Primitive::kPrimDouble: {
4754      uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
4755      Location value = locations->InAt(2);
4756      DCHECK(value.IsFpuRegisterPair());
4757      if (index.IsConstant()) {
4758        size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
4759        __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), array, offset);
4760      } else {
4761        __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
4762        __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), IP, data_offset);
4763      }
4764
4765      break;
4766    }
4767
4768    case Primitive::kPrimVoid:
4769      LOG(FATAL) << "Unreachable type " << value_type;
4770      UNREACHABLE();
4771  }
4772
4773  // Ints and objects are handled in the switch.
4774  if (value_type != Primitive::kPrimInt && value_type != Primitive::kPrimNot) {
4775    codegen_->MaybeRecordImplicitNullCheck(instruction);
4776  }
4777}
4778
4779void LocationsBuilderARM::VisitArrayLength(HArrayLength* instruction) {
4780  LocationSummary* locations =
4781      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
4782  locations->SetInAt(0, Location::RequiresRegister());
4783  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
4784}
4785
4786void InstructionCodeGeneratorARM::VisitArrayLength(HArrayLength* instruction) {
4787  LocationSummary* locations = instruction->GetLocations();
4788  uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
4789  Register obj = locations->InAt(0).AsRegister<Register>();
4790  Register out = locations->Out().AsRegister<Register>();
4791  __ LoadFromOffset(kLoadWord, out, obj, offset);
4792  codegen_->MaybeRecordImplicitNullCheck(instruction);
4793}
4794
4795void LocationsBuilderARM::VisitBoundsCheck(HBoundsCheck* instruction) {
4796  LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
4797      ? LocationSummary::kCallOnSlowPath
4798      : LocationSummary::kNoCall;
4799  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
4800  locations->SetInAt(0, Location::RequiresRegister());
4801  locations->SetInAt(1, Location::RequiresRegister());
4802  if (instruction->HasUses()) {
4803    locations->SetOut(Location::SameAsFirstInput());
4804  }
4805}
4806
4807void InstructionCodeGeneratorARM::VisitBoundsCheck(HBoundsCheck* instruction) {
4808  LocationSummary* locations = instruction->GetLocations();
4809  SlowPathCode* slow_path =
4810      new (GetGraph()->GetArena()) BoundsCheckSlowPathARM(instruction);
4811  codegen_->AddSlowPath(slow_path);
4812
4813  Register index = locations->InAt(0).AsRegister<Register>();
4814  Register length = locations->InAt(1).AsRegister<Register>();
4815
4816  __ cmp(index, ShifterOperand(length));
4817  __ b(slow_path->GetEntryLabel(), HS);
4818}
4819
4820void CodeGeneratorARM::MarkGCCard(Register temp,
4821                                  Register card,
4822                                  Register object,
4823                                  Register value,
4824                                  bool can_be_null) {
4825  Label is_null;
4826  if (can_be_null) {
4827    __ CompareAndBranchIfZero(value, &is_null);
4828  }
4829  __ LoadFromOffset(kLoadWord, card, TR, Thread::CardTableOffset<kArmWordSize>().Int32Value());
4830  __ Lsr(temp, object, gc::accounting::CardTable::kCardShift);
4831  __ strb(card, Address(card, temp));
4832  if (can_be_null) {
4833    __ Bind(&is_null);
4834  }
4835}
4836
4837void LocationsBuilderARM::VisitTemporary(HTemporary* temp) {
4838  temp->SetLocations(nullptr);
4839}
4840
4841void InstructionCodeGeneratorARM::VisitTemporary(HTemporary* temp ATTRIBUTE_UNUSED) {
4842  // Nothing to do, this is driven by the code generator.
4843}
4844
4845void LocationsBuilderARM::VisitParallelMove(HParallelMove* instruction ATTRIBUTE_UNUSED) {
4846  LOG(FATAL) << "Unreachable";
4847}
4848
4849void InstructionCodeGeneratorARM::VisitParallelMove(HParallelMove* instruction) {
4850  codegen_->GetMoveResolver()->EmitNativeCode(instruction);
4851}
4852
4853void LocationsBuilderARM::VisitSuspendCheck(HSuspendCheck* instruction) {
4854  new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
4855}
4856
4857void InstructionCodeGeneratorARM::VisitSuspendCheck(HSuspendCheck* instruction) {
4858  HBasicBlock* block = instruction->GetBlock();
4859  if (block->GetLoopInformation() != nullptr) {
4860    DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
4861    // The back edge will generate the suspend check.
4862    return;
4863  }
4864  if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
4865    // The goto will generate the suspend check.
4866    return;
4867  }
4868  GenerateSuspendCheck(instruction, nullptr);
4869}
4870
4871void InstructionCodeGeneratorARM::GenerateSuspendCheck(HSuspendCheck* instruction,
4872                                                       HBasicBlock* successor) {
4873  SuspendCheckSlowPathARM* slow_path =
4874      down_cast<SuspendCheckSlowPathARM*>(instruction->GetSlowPath());
4875  if (slow_path == nullptr) {
4876    slow_path = new (GetGraph()->GetArena()) SuspendCheckSlowPathARM(instruction, successor);
4877    instruction->SetSlowPath(slow_path);
4878    codegen_->AddSlowPath(slow_path);
4879    if (successor != nullptr) {
4880      DCHECK(successor->IsLoopHeader());
4881      codegen_->ClearSpillSlotsFromLoopPhisInStackMap(instruction);
4882    }
4883  } else {
4884    DCHECK_EQ(slow_path->GetSuccessor(), successor);
4885  }
4886
4887  __ LoadFromOffset(
4888      kLoadUnsignedHalfword, IP, TR, Thread::ThreadFlagsOffset<kArmWordSize>().Int32Value());
4889  if (successor == nullptr) {
4890    __ CompareAndBranchIfNonZero(IP, slow_path->GetEntryLabel());
4891    __ Bind(slow_path->GetReturnLabel());
4892  } else {
4893    __ CompareAndBranchIfZero(IP, codegen_->GetLabelOf(successor));
4894    __ b(slow_path->GetEntryLabel());
4895  }
4896}
4897
4898ArmAssembler* ParallelMoveResolverARM::GetAssembler() const {
4899  return codegen_->GetAssembler();
4900}
4901
4902void ParallelMoveResolverARM::EmitMove(size_t index) {
4903  MoveOperands* move = moves_[index];
4904  Location source = move->GetSource();
4905  Location destination = move->GetDestination();
4906
4907  if (source.IsRegister()) {
4908    if (destination.IsRegister()) {
4909      __ Mov(destination.AsRegister<Register>(), source.AsRegister<Register>());
4910    } else {
4911      DCHECK(destination.IsStackSlot());
4912      __ StoreToOffset(kStoreWord, source.AsRegister<Register>(),
4913                       SP, destination.GetStackIndex());
4914    }
4915  } else if (source.IsStackSlot()) {
4916    if (destination.IsRegister()) {
4917      __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(),
4918                        SP, source.GetStackIndex());
4919    } else if (destination.IsFpuRegister()) {
4920      __ LoadSFromOffset(destination.AsFpuRegister<SRegister>(), SP, source.GetStackIndex());
4921    } else {
4922      DCHECK(destination.IsStackSlot());
4923      __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
4924      __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4925    }
4926  } else if (source.IsFpuRegister()) {
4927    if (destination.IsFpuRegister()) {
4928      __ vmovs(destination.AsFpuRegister<SRegister>(), source.AsFpuRegister<SRegister>());
4929    } else {
4930      DCHECK(destination.IsStackSlot());
4931      __ StoreSToOffset(source.AsFpuRegister<SRegister>(), SP, destination.GetStackIndex());
4932    }
4933  } else if (source.IsDoubleStackSlot()) {
4934    if (destination.IsDoubleStackSlot()) {
4935      __ LoadDFromOffset(DTMP, SP, source.GetStackIndex());
4936      __ StoreDToOffset(DTMP, SP, destination.GetStackIndex());
4937    } else if (destination.IsRegisterPair()) {
4938      DCHECK(ExpectedPairLayout(destination));
4939      __ LoadFromOffset(
4940          kLoadWordPair, destination.AsRegisterPairLow<Register>(), SP, source.GetStackIndex());
4941    } else {
4942      DCHECK(destination.IsFpuRegisterPair()) << destination;
4943      __ LoadDFromOffset(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
4944                         SP,
4945                         source.GetStackIndex());
4946    }
4947  } else if (source.IsRegisterPair()) {
4948    if (destination.IsRegisterPair()) {
4949      __ Mov(destination.AsRegisterPairLow<Register>(), source.AsRegisterPairLow<Register>());
4950      __ Mov(destination.AsRegisterPairHigh<Register>(), source.AsRegisterPairHigh<Register>());
4951    } else {
4952      DCHECK(destination.IsDoubleStackSlot()) << destination;
4953      DCHECK(ExpectedPairLayout(source));
4954      __ StoreToOffset(
4955          kStoreWordPair, source.AsRegisterPairLow<Register>(), SP, destination.GetStackIndex());
4956    }
4957  } else if (source.IsFpuRegisterPair()) {
4958    if (destination.IsFpuRegisterPair()) {
4959      __ vmovd(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
4960               FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()));
4961    } else {
4962      DCHECK(destination.IsDoubleStackSlot()) << destination;
4963      __ StoreDToOffset(FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()),
4964                        SP,
4965                        destination.GetStackIndex());
4966    }
4967  } else {
4968    DCHECK(source.IsConstant()) << source;
4969    HConstant* constant = source.GetConstant();
4970    if (constant->IsIntConstant() || constant->IsNullConstant()) {
4971      int32_t value = CodeGenerator::GetInt32ValueOf(constant);
4972      if (destination.IsRegister()) {
4973        __ LoadImmediate(destination.AsRegister<Register>(), value);
4974      } else {
4975        DCHECK(destination.IsStackSlot());
4976        __ LoadImmediate(IP, value);
4977        __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4978      }
4979    } else if (constant->IsLongConstant()) {
4980      int64_t value = constant->AsLongConstant()->GetValue();
4981      if (destination.IsRegisterPair()) {
4982        __ LoadImmediate(destination.AsRegisterPairLow<Register>(), Low32Bits(value));
4983        __ LoadImmediate(destination.AsRegisterPairHigh<Register>(), High32Bits(value));
4984      } else {
4985        DCHECK(destination.IsDoubleStackSlot()) << destination;
4986        __ LoadImmediate(IP, Low32Bits(value));
4987        __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4988        __ LoadImmediate(IP, High32Bits(value));
4989        __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
4990      }
4991    } else if (constant->IsDoubleConstant()) {
4992      double value = constant->AsDoubleConstant()->GetValue();
4993      if (destination.IsFpuRegisterPair()) {
4994        __ LoadDImmediate(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()), value);
4995      } else {
4996        DCHECK(destination.IsDoubleStackSlot()) << destination;
4997        uint64_t int_value = bit_cast<uint64_t, double>(value);
4998        __ LoadImmediate(IP, Low32Bits(int_value));
4999        __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
5000        __ LoadImmediate(IP, High32Bits(int_value));
5001        __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
5002      }
5003    } else {
5004      DCHECK(constant->IsFloatConstant()) << constant->DebugName();
5005      float value = constant->AsFloatConstant()->GetValue();
5006      if (destination.IsFpuRegister()) {
5007        __ LoadSImmediate(destination.AsFpuRegister<SRegister>(), value);
5008      } else {
5009        DCHECK(destination.IsStackSlot());
5010        __ LoadImmediate(IP, bit_cast<int32_t, float>(value));
5011        __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
5012      }
5013    }
5014  }
5015}
5016
5017void ParallelMoveResolverARM::Exchange(Register reg, int mem) {
5018  __ Mov(IP, reg);
5019  __ LoadFromOffset(kLoadWord, reg, SP, mem);
5020  __ StoreToOffset(kStoreWord, IP, SP, mem);
5021}
5022
5023void ParallelMoveResolverARM::Exchange(int mem1, int mem2) {
5024  ScratchRegisterScope ensure_scratch(this, IP, R0, codegen_->GetNumberOfCoreRegisters());
5025  int stack_offset = ensure_scratch.IsSpilled() ? kArmWordSize : 0;
5026  __ LoadFromOffset(kLoadWord, static_cast<Register>(ensure_scratch.GetRegister()),
5027                    SP, mem1 + stack_offset);
5028  __ LoadFromOffset(kLoadWord, IP, SP, mem2 + stack_offset);
5029  __ StoreToOffset(kStoreWord, static_cast<Register>(ensure_scratch.GetRegister()),
5030                   SP, mem2 + stack_offset);
5031  __ StoreToOffset(kStoreWord, IP, SP, mem1 + stack_offset);
5032}
5033
5034void ParallelMoveResolverARM::EmitSwap(size_t index) {
5035  MoveOperands* move = moves_[index];
5036  Location source = move->GetSource();
5037  Location destination = move->GetDestination();
5038
5039  if (source.IsRegister() && destination.IsRegister()) {
5040    DCHECK_NE(source.AsRegister<Register>(), IP);
5041    DCHECK_NE(destination.AsRegister<Register>(), IP);
5042    __ Mov(IP, source.AsRegister<Register>());
5043    __ Mov(source.AsRegister<Register>(), destination.AsRegister<Register>());
5044    __ Mov(destination.AsRegister<Register>(), IP);
5045  } else if (source.IsRegister() && destination.IsStackSlot()) {
5046    Exchange(source.AsRegister<Register>(), destination.GetStackIndex());
5047  } else if (source.IsStackSlot() && destination.IsRegister()) {
5048    Exchange(destination.AsRegister<Register>(), source.GetStackIndex());
5049  } else if (source.IsStackSlot() && destination.IsStackSlot()) {
5050    Exchange(source.GetStackIndex(), destination.GetStackIndex());
5051  } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
5052    __ vmovrs(IP, source.AsFpuRegister<SRegister>());
5053    __ vmovs(source.AsFpuRegister<SRegister>(), destination.AsFpuRegister<SRegister>());
5054    __ vmovsr(destination.AsFpuRegister<SRegister>(), IP);
5055  } else if (source.IsRegisterPair() && destination.IsRegisterPair()) {
5056    __ vmovdrr(DTMP, source.AsRegisterPairLow<Register>(), source.AsRegisterPairHigh<Register>());
5057    __ Mov(source.AsRegisterPairLow<Register>(), destination.AsRegisterPairLow<Register>());
5058    __ Mov(source.AsRegisterPairHigh<Register>(), destination.AsRegisterPairHigh<Register>());
5059    __ vmovrrd(destination.AsRegisterPairLow<Register>(),
5060               destination.AsRegisterPairHigh<Register>(),
5061               DTMP);
5062  } else if (source.IsRegisterPair() || destination.IsRegisterPair()) {
5063    Register low_reg = source.IsRegisterPair()
5064        ? source.AsRegisterPairLow<Register>()
5065        : destination.AsRegisterPairLow<Register>();
5066    int mem = source.IsRegisterPair()
5067        ? destination.GetStackIndex()
5068        : source.GetStackIndex();
5069    DCHECK(ExpectedPairLayout(source.IsRegisterPair() ? source : destination));
5070    __ vmovdrr(DTMP, low_reg, static_cast<Register>(low_reg + 1));
5071    __ LoadFromOffset(kLoadWordPair, low_reg, SP, mem);
5072    __ StoreDToOffset(DTMP, SP, mem);
5073  } else if (source.IsFpuRegisterPair() && destination.IsFpuRegisterPair()) {
5074    DRegister first = FromLowSToD(source.AsFpuRegisterPairLow<SRegister>());
5075    DRegister second = FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>());
5076    __ vmovd(DTMP, first);
5077    __ vmovd(first, second);
5078    __ vmovd(second, DTMP);
5079  } else if (source.IsFpuRegisterPair() || destination.IsFpuRegisterPair()) {
5080    DRegister reg = source.IsFpuRegisterPair()
5081        ? FromLowSToD(source.AsFpuRegisterPairLow<SRegister>())
5082        : FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>());
5083    int mem = source.IsFpuRegisterPair()
5084        ? destination.GetStackIndex()
5085        : source.GetStackIndex();
5086    __ vmovd(DTMP, reg);
5087    __ LoadDFromOffset(reg, SP, mem);
5088    __ StoreDToOffset(DTMP, SP, mem);
5089  } else if (source.IsFpuRegister() || destination.IsFpuRegister()) {
5090    SRegister reg = source.IsFpuRegister() ? source.AsFpuRegister<SRegister>()
5091                                           : destination.AsFpuRegister<SRegister>();
5092    int mem = source.IsFpuRegister()
5093        ? destination.GetStackIndex()
5094        : source.GetStackIndex();
5095
5096    __ vmovrs(IP, reg);
5097    __ LoadSFromOffset(reg, SP, mem);
5098    __ StoreToOffset(kStoreWord, IP, SP, mem);
5099  } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
5100    Exchange(source.GetStackIndex(), destination.GetStackIndex());
5101    Exchange(source.GetHighStackIndex(kArmWordSize), destination.GetHighStackIndex(kArmWordSize));
5102  } else {
5103    LOG(FATAL) << "Unimplemented" << source << " <-> " << destination;
5104  }
5105}
5106
5107void ParallelMoveResolverARM::SpillScratch(int reg) {
5108  __ Push(static_cast<Register>(reg));
5109}
5110
5111void ParallelMoveResolverARM::RestoreScratch(int reg) {
5112  __ Pop(static_cast<Register>(reg));
5113}
5114
5115void LocationsBuilderARM::VisitLoadClass(HLoadClass* cls) {
5116  InvokeRuntimeCallingConvention calling_convention;
5117  CodeGenerator::CreateLoadClassLocationSummary(
5118      cls,
5119      Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
5120      Location::RegisterLocation(R0),
5121      /* code_generator_supports_read_barrier */ true);
5122}
5123
5124void InstructionCodeGeneratorARM::VisitLoadClass(HLoadClass* cls) {
5125  LocationSummary* locations = cls->GetLocations();
5126  if (cls->NeedsAccessCheck()) {
5127    codegen_->MoveConstant(locations->GetTemp(0), cls->GetTypeIndex());
5128    codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pInitializeTypeAndVerifyAccess),
5129                            cls,
5130                            cls->GetDexPc(),
5131                            nullptr);
5132    CheckEntrypointTypes<kQuickInitializeTypeAndVerifyAccess, void*, uint32_t>();
5133    return;
5134  }
5135
5136  Location out_loc = locations->Out();
5137  Register out = out_loc.AsRegister<Register>();
5138  Register current_method = locations->InAt(0).AsRegister<Register>();
5139
5140  if (cls->IsReferrersClass()) {
5141    DCHECK(!cls->CanCallRuntime());
5142    DCHECK(!cls->MustGenerateClinitCheck());
5143    uint32_t declaring_class_offset = ArtMethod::DeclaringClassOffset().Int32Value();
5144    if (kEmitCompilerReadBarrier) {
5145      // /* GcRoot<mirror::Class>* */ out = &(current_method->declaring_class_)
5146      __ AddConstant(out, current_method, declaring_class_offset);
5147      // /* mirror::Class* */ out = out->Read()
5148      codegen_->GenerateReadBarrierForRoot(cls, out_loc, out_loc);
5149    } else {
5150      // /* GcRoot<mirror::Class> */ out = current_method->declaring_class_
5151      __ LoadFromOffset(kLoadWord, out, current_method, declaring_class_offset);
5152    }
5153  } else {
5154    // /* GcRoot<mirror::Class>[] */ out =
5155    //        current_method.ptr_sized_fields_->dex_cache_resolved_types_
5156    __ LoadFromOffset(kLoadWord,
5157                      out,
5158                      current_method,
5159                      ArtMethod::DexCacheResolvedTypesOffset(kArmPointerSize).Int32Value());
5160
5161    size_t cache_offset = CodeGenerator::GetCacheOffset(cls->GetTypeIndex());
5162    if (kEmitCompilerReadBarrier) {
5163      // /* GcRoot<mirror::Class>* */ out = &out[type_index]
5164      __ AddConstant(out, out, cache_offset);
5165      // /* mirror::Class* */ out = out->Read()
5166      codegen_->GenerateReadBarrierForRoot(cls, out_loc, out_loc);
5167    } else {
5168      // /* GcRoot<mirror::Class> */ out = out[type_index]
5169      __ LoadFromOffset(kLoadWord, out, out, cache_offset);
5170    }
5171
5172    if (!cls->IsInDexCache() || cls->MustGenerateClinitCheck()) {
5173      DCHECK(cls->CanCallRuntime());
5174      SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
5175          cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
5176      codegen_->AddSlowPath(slow_path);
5177      if (!cls->IsInDexCache()) {
5178        __ CompareAndBranchIfZero(out, slow_path->GetEntryLabel());
5179      }
5180      if (cls->MustGenerateClinitCheck()) {
5181        GenerateClassInitializationCheck(slow_path, out);
5182      } else {
5183        __ Bind(slow_path->GetExitLabel());
5184      }
5185    }
5186  }
5187}
5188
5189void LocationsBuilderARM::VisitClinitCheck(HClinitCheck* check) {
5190  LocationSummary* locations =
5191      new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
5192  locations->SetInAt(0, Location::RequiresRegister());
5193  if (check->HasUses()) {
5194    locations->SetOut(Location::SameAsFirstInput());
5195  }
5196}
5197
5198void InstructionCodeGeneratorARM::VisitClinitCheck(HClinitCheck* check) {
5199  // We assume the class is not null.
5200  SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
5201      check->GetLoadClass(), check, check->GetDexPc(), true);
5202  codegen_->AddSlowPath(slow_path);
5203  GenerateClassInitializationCheck(slow_path,
5204                                   check->GetLocations()->InAt(0).AsRegister<Register>());
5205}
5206
5207void InstructionCodeGeneratorARM::GenerateClassInitializationCheck(
5208    SlowPathCode* slow_path, Register class_reg) {
5209  __ LoadFromOffset(kLoadWord, IP, class_reg, mirror::Class::StatusOffset().Int32Value());
5210  __ cmp(IP, ShifterOperand(mirror::Class::kStatusInitialized));
5211  __ b(slow_path->GetEntryLabel(), LT);
5212  // Even if the initialized flag is set, we may be in a situation where caches are not synced
5213  // properly. Therefore, we do a memory fence.
5214  __ dmb(ISH);
5215  __ Bind(slow_path->GetExitLabel());
5216}
5217
5218void LocationsBuilderARM::VisitLoadString(HLoadString* load) {
5219  LocationSummary::CallKind call_kind = (!load->IsInDexCache() || kEmitCompilerReadBarrier)
5220      ? LocationSummary::kCallOnSlowPath
5221      : LocationSummary::kNoCall;
5222  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(load, call_kind);
5223  locations->SetInAt(0, Location::RequiresRegister());
5224  locations->SetOut(Location::RequiresRegister());
5225}
5226
5227void InstructionCodeGeneratorARM::VisitLoadString(HLoadString* load) {
5228  LocationSummary* locations = load->GetLocations();
5229  Location out_loc = locations->Out();
5230  Register out = out_loc.AsRegister<Register>();
5231  Register current_method = locations->InAt(0).AsRegister<Register>();
5232
5233  uint32_t declaring_class_offset = ArtMethod::DeclaringClassOffset().Int32Value();
5234  if (kEmitCompilerReadBarrier) {
5235    // /* GcRoot<mirror::Class>* */ out = &(current_method->declaring_class_)
5236    __ AddConstant(out, current_method, declaring_class_offset);
5237    // /* mirror::Class* */ out = out->Read()
5238    codegen_->GenerateReadBarrierForRoot(load, out_loc, out_loc);
5239  } else {
5240    // /* GcRoot<mirror::Class> */ out = current_method->declaring_class_
5241    __ LoadFromOffset(kLoadWord, out, current_method, declaring_class_offset);
5242  }
5243
5244  // /* GcRoot<mirror::String>[] */ out = out->dex_cache_strings_
5245  __ LoadFromOffset(kLoadWord, out, out, mirror::Class::DexCacheStringsOffset().Int32Value());
5246
5247  size_t cache_offset = CodeGenerator::GetCacheOffset(load->GetStringIndex());
5248  if (kEmitCompilerReadBarrier) {
5249    // /* GcRoot<mirror::String>* */ out = &out[string_index]
5250    __ AddConstant(out, out, cache_offset);
5251    // /* mirror::String* */ out = out->Read()
5252    codegen_->GenerateReadBarrierForRoot(load, out_loc, out_loc);
5253  } else {
5254    // /* GcRoot<mirror::String> */ out = out[string_index]
5255    __ LoadFromOffset(kLoadWord, out, out, cache_offset);
5256  }
5257
5258  if (!load->IsInDexCache()) {
5259    SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathARM(load);
5260    codegen_->AddSlowPath(slow_path);
5261    __ CompareAndBranchIfZero(out, slow_path->GetEntryLabel());
5262    __ Bind(slow_path->GetExitLabel());
5263  }
5264}
5265
5266static int32_t GetExceptionTlsOffset() {
5267  return Thread::ExceptionOffset<kArmWordSize>().Int32Value();
5268}
5269
5270void LocationsBuilderARM::VisitLoadException(HLoadException* load) {
5271  LocationSummary* locations =
5272      new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
5273  locations->SetOut(Location::RequiresRegister());
5274}
5275
5276void InstructionCodeGeneratorARM::VisitLoadException(HLoadException* load) {
5277  Register out = load->GetLocations()->Out().AsRegister<Register>();
5278  __ LoadFromOffset(kLoadWord, out, TR, GetExceptionTlsOffset());
5279}
5280
5281void LocationsBuilderARM::VisitClearException(HClearException* clear) {
5282  new (GetGraph()->GetArena()) LocationSummary(clear, LocationSummary::kNoCall);
5283}
5284
5285void InstructionCodeGeneratorARM::VisitClearException(HClearException* clear ATTRIBUTE_UNUSED) {
5286  __ LoadImmediate(IP, 0);
5287  __ StoreToOffset(kStoreWord, IP, TR, GetExceptionTlsOffset());
5288}
5289
5290void LocationsBuilderARM::VisitThrow(HThrow* instruction) {
5291  LocationSummary* locations =
5292      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
5293  InvokeRuntimeCallingConvention calling_convention;
5294  locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5295}
5296
5297void InstructionCodeGeneratorARM::VisitThrow(HThrow* instruction) {
5298  codegen_->InvokeRuntime(
5299      QUICK_ENTRY_POINT(pDeliverException), instruction, instruction->GetDexPc(), nullptr);
5300  CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>();
5301}
5302
5303void LocationsBuilderARM::VisitInstanceOf(HInstanceOf* instruction) {
5304  LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
5305  TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
5306  switch (type_check_kind) {
5307    case TypeCheckKind::kExactCheck:
5308    case TypeCheckKind::kAbstractClassCheck:
5309    case TypeCheckKind::kClassHierarchyCheck:
5310    case TypeCheckKind::kArrayObjectCheck:
5311      call_kind =
5312          kEmitCompilerReadBarrier ? LocationSummary::kCallOnSlowPath : LocationSummary::kNoCall;
5313      break;
5314    case TypeCheckKind::kArrayCheck:
5315    case TypeCheckKind::kUnresolvedCheck:
5316    case TypeCheckKind::kInterfaceCheck:
5317      call_kind = LocationSummary::kCallOnSlowPath;
5318      break;
5319  }
5320
5321  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
5322  locations->SetInAt(0, Location::RequiresRegister());
5323  locations->SetInAt(1, Location::RequiresRegister());
5324  // The "out" register is used as a temporary, so it overlaps with the inputs.
5325  // Note that TypeCheckSlowPathARM uses this register too.
5326  locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
5327  // When read barriers are enabled, we need a temporary register for
5328  // some cases.
5329  if (kEmitCompilerReadBarrier &&
5330      (type_check_kind == TypeCheckKind::kAbstractClassCheck ||
5331       type_check_kind == TypeCheckKind::kClassHierarchyCheck ||
5332       type_check_kind == TypeCheckKind::kArrayObjectCheck)) {
5333    locations->AddTemp(Location::RequiresRegister());
5334  }
5335}
5336
5337void InstructionCodeGeneratorARM::VisitInstanceOf(HInstanceOf* instruction) {
5338  LocationSummary* locations = instruction->GetLocations();
5339  Location obj_loc = locations->InAt(0);
5340  Register obj = obj_loc.AsRegister<Register>();
5341  Register cls = locations->InAt(1).AsRegister<Register>();
5342  Location out_loc = locations->Out();
5343  Register out = out_loc.AsRegister<Register>();
5344  uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
5345  uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
5346  uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
5347  uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
5348  Label done, zero;
5349  SlowPathCode* slow_path = nullptr;
5350
5351  // Return 0 if `obj` is null.
5352  // avoid null check if we know obj is not null.
5353  if (instruction->MustDoNullCheck()) {
5354    __ CompareAndBranchIfZero(obj, &zero);
5355  }
5356
5357  // /* HeapReference<Class> */ out = obj->klass_
5358  __ LoadFromOffset(kLoadWord, out, obj, class_offset);
5359  codegen_->MaybeGenerateReadBarrier(instruction, out_loc, out_loc, obj_loc, class_offset);
5360
5361  switch (instruction->GetTypeCheckKind()) {
5362    case TypeCheckKind::kExactCheck: {
5363      __ cmp(out, ShifterOperand(cls));
5364      // Classes must be equal for the instanceof to succeed.
5365      __ b(&zero, NE);
5366      __ LoadImmediate(out, 1);
5367      __ b(&done);
5368      break;
5369    }
5370
5371    case TypeCheckKind::kAbstractClassCheck: {
5372      // If the class is abstract, we eagerly fetch the super class of the
5373      // object to avoid doing a comparison we know will fail.
5374      Label loop;
5375      __ Bind(&loop);
5376      Location temp_loc = kEmitCompilerReadBarrier ? locations->GetTemp(0) : Location::NoLocation();
5377      if (kEmitCompilerReadBarrier) {
5378        // Save the value of `out` into `temp` before overwriting it
5379        // in the following move operation, as we will need it for the
5380        // read barrier below.
5381        Register temp = temp_loc.AsRegister<Register>();
5382        __ Mov(temp, out);
5383      }
5384      // /* HeapReference<Class> */ out = out->super_class_
5385      __ LoadFromOffset(kLoadWord, out, out, super_offset);
5386      codegen_->MaybeGenerateReadBarrier(instruction, out_loc, out_loc, temp_loc, super_offset);
5387      // If `out` is null, we use it for the result, and jump to `done`.
5388      __ CompareAndBranchIfZero(out, &done);
5389      __ cmp(out, ShifterOperand(cls));
5390      __ b(&loop, NE);
5391      __ LoadImmediate(out, 1);
5392      if (zero.IsLinked()) {
5393        __ b(&done);
5394      }
5395      break;
5396    }
5397
5398    case TypeCheckKind::kClassHierarchyCheck: {
5399      // Walk over the class hierarchy to find a match.
5400      Label loop, success;
5401      __ Bind(&loop);
5402      __ cmp(out, ShifterOperand(cls));
5403      __ b(&success, EQ);
5404      Location temp_loc = kEmitCompilerReadBarrier ? locations->GetTemp(0) : Location::NoLocation();
5405      if (kEmitCompilerReadBarrier) {
5406        // Save the value of `out` into `temp` before overwriting it
5407        // in the following move operation, as we will need it for the
5408        // read barrier below.
5409        Register temp = temp_loc.AsRegister<Register>();
5410        __ Mov(temp, out);
5411      }
5412      // /* HeapReference<Class> */ out = out->super_class_
5413      __ LoadFromOffset(kLoadWord, out, out, super_offset);
5414      codegen_->MaybeGenerateReadBarrier(instruction, out_loc, out_loc, temp_loc, super_offset);
5415      __ CompareAndBranchIfNonZero(out, &loop);
5416      // If `out` is null, we use it for the result, and jump to `done`.
5417      __ b(&done);
5418      __ Bind(&success);
5419      __ LoadImmediate(out, 1);
5420      if (zero.IsLinked()) {
5421        __ b(&done);
5422      }
5423      break;
5424    }
5425
5426    case TypeCheckKind::kArrayObjectCheck: {
5427      // Do an exact check.
5428      Label exact_check;
5429      __ cmp(out, ShifterOperand(cls));
5430      __ b(&exact_check, EQ);
5431      // Otherwise, we need to check that the object's class is a non-primitive array.
5432      Location temp_loc = kEmitCompilerReadBarrier ? locations->GetTemp(0) : Location::NoLocation();
5433      if (kEmitCompilerReadBarrier) {
5434        // Save the value of `out` into `temp` before overwriting it
5435        // in the following move operation, as we will need it for the
5436        // read barrier below.
5437        Register temp = temp_loc.AsRegister<Register>();
5438        __ Mov(temp, out);
5439      }
5440      // /* HeapReference<Class> */ out = out->component_type_
5441      __ LoadFromOffset(kLoadWord, out, out, component_offset);
5442      codegen_->MaybeGenerateReadBarrier(instruction, out_loc, out_loc, temp_loc, component_offset);
5443      // If `out` is null, we use it for the result, and jump to `done`.
5444      __ CompareAndBranchIfZero(out, &done);
5445      __ LoadFromOffset(kLoadUnsignedHalfword, out, out, primitive_offset);
5446      static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot");
5447      __ CompareAndBranchIfNonZero(out, &zero);
5448      __ Bind(&exact_check);
5449      __ LoadImmediate(out, 1);
5450      __ b(&done);
5451      break;
5452    }
5453
5454    case TypeCheckKind::kArrayCheck: {
5455      __ cmp(out, ShifterOperand(cls));
5456      DCHECK(locations->OnlyCallsOnSlowPath());
5457      slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(instruction,
5458                                                                    /* is_fatal */ false);
5459      codegen_->AddSlowPath(slow_path);
5460      __ b(slow_path->GetEntryLabel(), NE);
5461      __ LoadImmediate(out, 1);
5462      if (zero.IsLinked()) {
5463        __ b(&done);
5464      }
5465      break;
5466    }
5467
5468    case TypeCheckKind::kUnresolvedCheck:
5469    case TypeCheckKind::kInterfaceCheck: {
5470      // Note that we indeed only call on slow path, but we always go
5471      // into the slow path for the unresolved & interface check
5472      // cases.
5473      //
5474      // We cannot directly call the InstanceofNonTrivial runtime
5475      // entry point without resorting to a type checking slow path
5476      // here (i.e. by calling InvokeRuntime directly), as it would
5477      // require to assign fixed registers for the inputs of this
5478      // HInstanceOf instruction (following the runtime calling
5479      // convention), which might be cluttered by the potential first
5480      // read barrier emission at the beginning of this method.
5481      DCHECK(locations->OnlyCallsOnSlowPath());
5482      slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(instruction,
5483                                                                    /* is_fatal */ false);
5484      codegen_->AddSlowPath(slow_path);
5485      __ b(slow_path->GetEntryLabel());
5486      if (zero.IsLinked()) {
5487        __ b(&done);
5488      }
5489      break;
5490    }
5491  }
5492
5493  if (zero.IsLinked()) {
5494    __ Bind(&zero);
5495    __ LoadImmediate(out, 0);
5496  }
5497
5498  if (done.IsLinked()) {
5499    __ Bind(&done);
5500  }
5501
5502  if (slow_path != nullptr) {
5503    __ Bind(slow_path->GetExitLabel());
5504  }
5505}
5506
5507void LocationsBuilderARM::VisitCheckCast(HCheckCast* instruction) {
5508  LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
5509  bool throws_into_catch = instruction->CanThrowIntoCatchBlock();
5510
5511  TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
5512  switch (type_check_kind) {
5513    case TypeCheckKind::kExactCheck:
5514    case TypeCheckKind::kAbstractClassCheck:
5515    case TypeCheckKind::kClassHierarchyCheck:
5516    case TypeCheckKind::kArrayObjectCheck:
5517      call_kind = (throws_into_catch || kEmitCompilerReadBarrier) ?
5518          LocationSummary::kCallOnSlowPath :
5519          LocationSummary::kNoCall;  // In fact, call on a fatal (non-returning) slow path.
5520      break;
5521    case TypeCheckKind::kArrayCheck:
5522    case TypeCheckKind::kUnresolvedCheck:
5523    case TypeCheckKind::kInterfaceCheck:
5524      call_kind = LocationSummary::kCallOnSlowPath;
5525      break;
5526  }
5527
5528  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
5529  locations->SetInAt(0, Location::RequiresRegister());
5530  locations->SetInAt(1, Location::RequiresRegister());
5531  // Note that TypeCheckSlowPathARM uses this "temp" register too.
5532  locations->AddTemp(Location::RequiresRegister());
5533  // When read barriers are enabled, we need an additional temporary
5534  // register for some cases.
5535  if (kEmitCompilerReadBarrier &&
5536      (type_check_kind == TypeCheckKind::kAbstractClassCheck ||
5537       type_check_kind == TypeCheckKind::kClassHierarchyCheck ||
5538       type_check_kind == TypeCheckKind::kArrayObjectCheck)) {
5539    locations->AddTemp(Location::RequiresRegister());
5540  }
5541}
5542
5543void InstructionCodeGeneratorARM::VisitCheckCast(HCheckCast* instruction) {
5544  LocationSummary* locations = instruction->GetLocations();
5545  Location obj_loc = locations->InAt(0);
5546  Register obj = obj_loc.AsRegister<Register>();
5547  Register cls = locations->InAt(1).AsRegister<Register>();
5548  Location temp_loc = locations->GetTemp(0);
5549  Register temp = temp_loc.AsRegister<Register>();
5550  uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
5551  uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
5552  uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
5553  uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
5554
5555  TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
5556  bool is_type_check_slow_path_fatal =
5557      (type_check_kind == TypeCheckKind::kExactCheck ||
5558       type_check_kind == TypeCheckKind::kAbstractClassCheck ||
5559       type_check_kind == TypeCheckKind::kClassHierarchyCheck ||
5560       type_check_kind == TypeCheckKind::kArrayObjectCheck) &&
5561      !instruction->CanThrowIntoCatchBlock();
5562  SlowPathCode* type_check_slow_path =
5563      new (GetGraph()->GetArena()) TypeCheckSlowPathARM(instruction,
5564                                                        is_type_check_slow_path_fatal);
5565  codegen_->AddSlowPath(type_check_slow_path);
5566
5567  Label done;
5568  // Avoid null check if we know obj is not null.
5569  if (instruction->MustDoNullCheck()) {
5570    __ CompareAndBranchIfZero(obj, &done);
5571  }
5572
5573  // /* HeapReference<Class> */ temp = obj->klass_
5574  __ LoadFromOffset(kLoadWord, temp, obj, class_offset);
5575  codegen_->MaybeGenerateReadBarrier(instruction, temp_loc, temp_loc, obj_loc, class_offset);
5576
5577  switch (type_check_kind) {
5578    case TypeCheckKind::kExactCheck:
5579    case TypeCheckKind::kArrayCheck: {
5580      __ cmp(temp, ShifterOperand(cls));
5581      // Jump to slow path for throwing the exception or doing a
5582      // more involved array check.
5583      __ b(type_check_slow_path->GetEntryLabel(), NE);
5584      break;
5585    }
5586
5587    case TypeCheckKind::kAbstractClassCheck: {
5588      // If the class is abstract, we eagerly fetch the super class of the
5589      // object to avoid doing a comparison we know will fail.
5590      Label loop, compare_classes;
5591      __ Bind(&loop);
5592      Location temp2_loc =
5593          kEmitCompilerReadBarrier ? locations->GetTemp(1) : Location::NoLocation();
5594      if (kEmitCompilerReadBarrier) {
5595        // Save the value of `temp` into `temp2` before overwriting it
5596        // in the following move operation, as we will need it for the
5597        // read barrier below.
5598        Register temp2 = temp2_loc.AsRegister<Register>();
5599        __ Mov(temp2, temp);
5600      }
5601      // /* HeapReference<Class> */ temp = temp->super_class_
5602      __ LoadFromOffset(kLoadWord, temp, temp, super_offset);
5603      codegen_->MaybeGenerateReadBarrier(instruction, temp_loc, temp_loc, temp2_loc, super_offset);
5604
5605      // If the class reference currently in `temp` is not null, jump
5606      // to the `compare_classes` label to compare it with the checked
5607      // class.
5608      __ CompareAndBranchIfNonZero(temp, &compare_classes);
5609      // Otherwise, jump to the slow path to throw the exception.
5610      //
5611      // But before, move back the object's class into `temp` before
5612      // going into the slow path, as it has been overwritten in the
5613      // meantime.
5614      // /* HeapReference<Class> */ temp = obj->klass_
5615      __ LoadFromOffset(kLoadWord, temp, obj, class_offset);
5616      codegen_->MaybeGenerateReadBarrier(instruction, temp_loc, temp_loc, obj_loc, class_offset);
5617      __ b(type_check_slow_path->GetEntryLabel());
5618
5619      __ Bind(&compare_classes);
5620      __ cmp(temp, ShifterOperand(cls));
5621      __ b(&loop, NE);
5622      break;
5623    }
5624
5625    case TypeCheckKind::kClassHierarchyCheck: {
5626      // Walk over the class hierarchy to find a match.
5627      Label loop;
5628      __ Bind(&loop);
5629      __ cmp(temp, ShifterOperand(cls));
5630      __ b(&done, EQ);
5631
5632      Location temp2_loc =
5633          kEmitCompilerReadBarrier ? locations->GetTemp(1) : Location::NoLocation();
5634      if (kEmitCompilerReadBarrier) {
5635        // Save the value of `temp` into `temp2` before overwriting it
5636        // in the following move operation, as we will need it for the
5637        // read barrier below.
5638        Register temp2 = temp2_loc.AsRegister<Register>();
5639        __ Mov(temp2, temp);
5640      }
5641      // /* HeapReference<Class> */ temp = temp->super_class_
5642      __ LoadFromOffset(kLoadWord, temp, temp, super_offset);
5643      codegen_->MaybeGenerateReadBarrier(instruction, temp_loc, temp_loc, temp2_loc, super_offset);
5644
5645      // If the class reference currently in `temp` is not null, jump
5646      // back at the beginning of the loop.
5647      __ CompareAndBranchIfNonZero(temp, &loop);
5648      // Otherwise, jump to the slow path to throw the exception.
5649      //
5650      // But before, move back the object's class into `temp` before
5651      // going into the slow path, as it has been overwritten in the
5652      // meantime.
5653      // /* HeapReference<Class> */ temp = obj->klass_
5654      __ LoadFromOffset(kLoadWord, temp, obj, class_offset);
5655      codegen_->MaybeGenerateReadBarrier(instruction, temp_loc, temp_loc, obj_loc, class_offset);
5656      __ b(type_check_slow_path->GetEntryLabel());
5657      break;
5658    }
5659
5660    case TypeCheckKind::kArrayObjectCheck: {
5661      // Do an exact check.
5662      Label check_non_primitive_component_type;
5663      __ cmp(temp, ShifterOperand(cls));
5664      __ b(&done, EQ);
5665
5666      // Otherwise, we need to check that the object's class is a non-primitive array.
5667      Location temp2_loc =
5668          kEmitCompilerReadBarrier ? locations->GetTemp(1) : Location::NoLocation();
5669      if (kEmitCompilerReadBarrier) {
5670        // Save the value of `temp` into `temp2` before overwriting it
5671        // in the following move operation, as we will need it for the
5672        // read barrier below.
5673        Register temp2 = temp2_loc.AsRegister<Register>();
5674        __ Mov(temp2, temp);
5675      }
5676      // /* HeapReference<Class> */ temp = temp->component_type_
5677      __ LoadFromOffset(kLoadWord, temp, temp, component_offset);
5678      codegen_->MaybeGenerateReadBarrier(
5679          instruction, temp_loc, temp_loc, temp2_loc, component_offset);
5680
5681      // If the component type is not null (i.e. the object is indeed
5682      // an array), jump to label `check_non_primitive_component_type`
5683      // to further check that this component type is not a primitive
5684      // type.
5685      __ CompareAndBranchIfNonZero(temp, &check_non_primitive_component_type);
5686      // Otherwise, jump to the slow path to throw the exception.
5687      //
5688      // But before, move back the object's class into `temp` before
5689      // going into the slow path, as it has been overwritten in the
5690      // meantime.
5691      // /* HeapReference<Class> */ temp = obj->klass_
5692      __ LoadFromOffset(kLoadWord, temp, obj, class_offset);
5693      codegen_->MaybeGenerateReadBarrier(instruction, temp_loc, temp_loc, obj_loc, class_offset);
5694      __ b(type_check_slow_path->GetEntryLabel());
5695
5696      __ Bind(&check_non_primitive_component_type);
5697      __ LoadFromOffset(kLoadUnsignedHalfword, temp, temp, primitive_offset);
5698      static_assert(Primitive::kPrimNot == 0, "Expected 0 for art::Primitive::kPrimNot");
5699      __ CompareAndBranchIfZero(temp, &done);
5700      // Same comment as above regarding `temp` and the slow path.
5701      // /* HeapReference<Class> */ temp = obj->klass_
5702      __ LoadFromOffset(kLoadWord, temp, obj, class_offset);
5703      codegen_->MaybeGenerateReadBarrier(instruction, temp_loc, temp_loc, obj_loc, class_offset);
5704      __ b(type_check_slow_path->GetEntryLabel());
5705      break;
5706    }
5707
5708    case TypeCheckKind::kUnresolvedCheck:
5709    case TypeCheckKind::kInterfaceCheck:
5710      // We always go into the type check slow path for the unresolved &
5711      // interface check cases.
5712      //
5713      // We cannot directly call the CheckCast runtime entry point
5714      // without resorting to a type checking slow path here (i.e. by
5715      // calling InvokeRuntime directly), as it would require to
5716      // assign fixed registers for the inputs of this HInstanceOf
5717      // instruction (following the runtime calling convention), which
5718      // might be cluttered by the potential first read barrier
5719      // emission at the beginning of this method.
5720      __ b(type_check_slow_path->GetEntryLabel());
5721      break;
5722  }
5723  __ Bind(&done);
5724
5725  __ Bind(type_check_slow_path->GetExitLabel());
5726}
5727
5728void LocationsBuilderARM::VisitMonitorOperation(HMonitorOperation* instruction) {
5729  LocationSummary* locations =
5730      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
5731  InvokeRuntimeCallingConvention calling_convention;
5732  locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5733}
5734
5735void InstructionCodeGeneratorARM::VisitMonitorOperation(HMonitorOperation* instruction) {
5736  codegen_->InvokeRuntime(instruction->IsEnter()
5737        ? QUICK_ENTRY_POINT(pLockObject) : QUICK_ENTRY_POINT(pUnlockObject),
5738      instruction,
5739      instruction->GetDexPc(),
5740      nullptr);
5741  if (instruction->IsEnter()) {
5742    CheckEntrypointTypes<kQuickLockObject, void, mirror::Object*>();
5743  } else {
5744    CheckEntrypointTypes<kQuickUnlockObject, void, mirror::Object*>();
5745  }
5746}
5747
5748void LocationsBuilderARM::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction, AND); }
5749void LocationsBuilderARM::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction, ORR); }
5750void LocationsBuilderARM::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction, EOR); }
5751
5752void LocationsBuilderARM::HandleBitwiseOperation(HBinaryOperation* instruction, Opcode opcode) {
5753  LocationSummary* locations =
5754      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
5755  DCHECK(instruction->GetResultType() == Primitive::kPrimInt
5756         || instruction->GetResultType() == Primitive::kPrimLong);
5757  // Note: GVN reorders commutative operations to have the constant on the right hand side.
5758  locations->SetInAt(0, Location::RequiresRegister());
5759  locations->SetInAt(1, ArmEncodableConstantOrRegister(instruction->InputAt(1), opcode));
5760  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
5761}
5762
5763void InstructionCodeGeneratorARM::VisitAnd(HAnd* instruction) {
5764  HandleBitwiseOperation(instruction);
5765}
5766
5767void InstructionCodeGeneratorARM::VisitOr(HOr* instruction) {
5768  HandleBitwiseOperation(instruction);
5769}
5770
5771void InstructionCodeGeneratorARM::VisitXor(HXor* instruction) {
5772  HandleBitwiseOperation(instruction);
5773}
5774
5775void InstructionCodeGeneratorARM::GenerateAndConst(Register out, Register first, uint32_t value) {
5776  // Optimize special cases for individual halfs of `and-long` (`and` is simplified earlier).
5777  if (value == 0xffffffffu) {
5778    if (out != first) {
5779      __ mov(out, ShifterOperand(first));
5780    }
5781    return;
5782  }
5783  if (value == 0u) {
5784    __ mov(out, ShifterOperand(0));
5785    return;
5786  }
5787  ShifterOperand so;
5788  if (__ ShifterOperandCanHold(kNoRegister, kNoRegister, AND, value, &so)) {
5789    __ and_(out, first, so);
5790  } else {
5791    DCHECK(__ ShifterOperandCanHold(kNoRegister, kNoRegister, BIC, ~value, &so));
5792    __ bic(out, first, ShifterOperand(~value));
5793  }
5794}
5795
5796void InstructionCodeGeneratorARM::GenerateOrrConst(Register out, Register first, uint32_t value) {
5797  // Optimize special cases for individual halfs of `or-long` (`or` is simplified earlier).
5798  if (value == 0u) {
5799    if (out != first) {
5800      __ mov(out, ShifterOperand(first));
5801    }
5802    return;
5803  }
5804  if (value == 0xffffffffu) {
5805    __ mvn(out, ShifterOperand(0));
5806    return;
5807  }
5808  ShifterOperand so;
5809  if (__ ShifterOperandCanHold(kNoRegister, kNoRegister, ORR, value, &so)) {
5810    __ orr(out, first, so);
5811  } else {
5812    DCHECK(__ ShifterOperandCanHold(kNoRegister, kNoRegister, ORN, ~value, &so));
5813    __ orn(out, first, ShifterOperand(~value));
5814  }
5815}
5816
5817void InstructionCodeGeneratorARM::GenerateEorConst(Register out, Register first, uint32_t value) {
5818  // Optimize special case for individual halfs of `xor-long` (`xor` is simplified earlier).
5819  if (value == 0u) {
5820    if (out != first) {
5821      __ mov(out, ShifterOperand(first));
5822    }
5823    return;
5824  }
5825  __ eor(out, first, ShifterOperand(value));
5826}
5827
5828void InstructionCodeGeneratorARM::HandleBitwiseOperation(HBinaryOperation* instruction) {
5829  LocationSummary* locations = instruction->GetLocations();
5830  Location first = locations->InAt(0);
5831  Location second = locations->InAt(1);
5832  Location out = locations->Out();
5833
5834  if (second.IsConstant()) {
5835    uint64_t value = static_cast<uint64_t>(Int64FromConstant(second.GetConstant()));
5836    uint32_t value_low = Low32Bits(value);
5837    if (instruction->GetResultType() == Primitive::kPrimInt) {
5838      Register first_reg = first.AsRegister<Register>();
5839      Register out_reg = out.AsRegister<Register>();
5840      if (instruction->IsAnd()) {
5841        GenerateAndConst(out_reg, first_reg, value_low);
5842      } else if (instruction->IsOr()) {
5843        GenerateOrrConst(out_reg, first_reg, value_low);
5844      } else {
5845        DCHECK(instruction->IsXor());
5846        GenerateEorConst(out_reg, first_reg, value_low);
5847      }
5848    } else {
5849      DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
5850      uint32_t value_high = High32Bits(value);
5851      Register first_low = first.AsRegisterPairLow<Register>();
5852      Register first_high = first.AsRegisterPairHigh<Register>();
5853      Register out_low = out.AsRegisterPairLow<Register>();
5854      Register out_high = out.AsRegisterPairHigh<Register>();
5855      if (instruction->IsAnd()) {
5856        GenerateAndConst(out_low, first_low, value_low);
5857        GenerateAndConst(out_high, first_high, value_high);
5858      } else if (instruction->IsOr()) {
5859        GenerateOrrConst(out_low, first_low, value_low);
5860        GenerateOrrConst(out_high, first_high, value_high);
5861      } else {
5862        DCHECK(instruction->IsXor());
5863        GenerateEorConst(out_low, first_low, value_low);
5864        GenerateEorConst(out_high, first_high, value_high);
5865      }
5866    }
5867    return;
5868  }
5869
5870  if (instruction->GetResultType() == Primitive::kPrimInt) {
5871    Register first_reg = first.AsRegister<Register>();
5872    ShifterOperand second_reg(second.AsRegister<Register>());
5873    Register out_reg = out.AsRegister<Register>();
5874    if (instruction->IsAnd()) {
5875      __ and_(out_reg, first_reg, second_reg);
5876    } else if (instruction->IsOr()) {
5877      __ orr(out_reg, first_reg, second_reg);
5878    } else {
5879      DCHECK(instruction->IsXor());
5880      __ eor(out_reg, first_reg, second_reg);
5881    }
5882  } else {
5883    DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
5884    Register first_low = first.AsRegisterPairLow<Register>();
5885    Register first_high = first.AsRegisterPairHigh<Register>();
5886    ShifterOperand second_low(second.AsRegisterPairLow<Register>());
5887    ShifterOperand second_high(second.AsRegisterPairHigh<Register>());
5888    Register out_low = out.AsRegisterPairLow<Register>();
5889    Register out_high = out.AsRegisterPairHigh<Register>();
5890    if (instruction->IsAnd()) {
5891      __ and_(out_low, first_low, second_low);
5892      __ and_(out_high, first_high, second_high);
5893    } else if (instruction->IsOr()) {
5894      __ orr(out_low, first_low, second_low);
5895      __ orr(out_high, first_high, second_high);
5896    } else {
5897      DCHECK(instruction->IsXor());
5898      __ eor(out_low, first_low, second_low);
5899      __ eor(out_high, first_high, second_high);
5900    }
5901  }
5902}
5903
5904void CodeGeneratorARM::GenerateReadBarrier(HInstruction* instruction,
5905                                           Location out,
5906                                           Location ref,
5907                                           Location obj,
5908                                           uint32_t offset,
5909                                           Location index) {
5910  DCHECK(kEmitCompilerReadBarrier);
5911
5912  // If heap poisoning is enabled, the unpoisoning of the loaded
5913  // reference will be carried out by the runtime within the slow
5914  // path.
5915  //
5916  // Note that `ref` currently does not get unpoisoned (when heap
5917  // poisoning is enabled), which is alright as the `ref` argument is
5918  // not used by the artReadBarrierSlow entry point.
5919  //
5920  // TODO: Unpoison `ref` when it is used by artReadBarrierSlow.
5921  SlowPathCode* slow_path = new (GetGraph()->GetArena())
5922      ReadBarrierForHeapReferenceSlowPathARM(instruction, out, ref, obj, offset, index);
5923  AddSlowPath(slow_path);
5924
5925  // TODO: When read barrier has a fast path, add it here.
5926  /* Currently the read barrier call is inserted after the original load.
5927   * However, if we have a fast path, we need to perform the load of obj.LockWord *before* the
5928   * original load. This load-load ordering is required by the read barrier.
5929   * The fast path/slow path (for Baker's algorithm) should look like:
5930   *
5931   * bool isGray = obj.LockWord & kReadBarrierMask;
5932   * lfence;  // load fence or artificial data dependence to prevent load-load reordering
5933   * ref = obj.field;    // this is the original load
5934   * if (isGray) {
5935   *   ref = Mark(ref);  // ideally the slow path just does Mark(ref)
5936   * }
5937   */
5938
5939  __ b(slow_path->GetEntryLabel());
5940  __ Bind(slow_path->GetExitLabel());
5941}
5942
5943void CodeGeneratorARM::MaybeGenerateReadBarrier(HInstruction* instruction,
5944                                                Location out,
5945                                                Location ref,
5946                                                Location obj,
5947                                                uint32_t offset,
5948                                                Location index) {
5949  if (kEmitCompilerReadBarrier) {
5950    // If heap poisoning is enabled, unpoisoning will be taken care of
5951    // by the runtime within the slow path.
5952    GenerateReadBarrier(instruction, out, ref, obj, offset, index);
5953  } else if (kPoisonHeapReferences) {
5954    __ UnpoisonHeapReference(out.AsRegister<Register>());
5955  }
5956}
5957
5958void CodeGeneratorARM::GenerateReadBarrierForRoot(HInstruction* instruction,
5959                                                  Location out,
5960                                                  Location root) {
5961  DCHECK(kEmitCompilerReadBarrier);
5962
5963  // Note that GC roots are not affected by heap poisoning, so we do
5964  // not need to do anything special for this here.
5965  SlowPathCode* slow_path =
5966      new (GetGraph()->GetArena()) ReadBarrierForRootSlowPathARM(instruction, out, root);
5967  AddSlowPath(slow_path);
5968
5969  // TODO: Implement a fast path for ReadBarrierForRoot, performing
5970  // the following operation (for Baker's algorithm):
5971  //
5972  //   if (thread.tls32_.is_gc_marking) {
5973  //     root = Mark(root);
5974  //   }
5975
5976  __ b(slow_path->GetEntryLabel());
5977  __ Bind(slow_path->GetExitLabel());
5978}
5979
5980HInvokeStaticOrDirect::DispatchInfo CodeGeneratorARM::GetSupportedInvokeStaticOrDirectDispatch(
5981      const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
5982      MethodReference target_method) {
5983  HInvokeStaticOrDirect::DispatchInfo dispatch_info = desired_dispatch_info;
5984  // We disable pc-relative load when there is an irreducible loop, as the optimization
5985  // is incompatible with it.
5986  if (GetGraph()->HasIrreducibleLoops() &&
5987      (dispatch_info.method_load_kind ==
5988          HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative)) {
5989    dispatch_info.method_load_kind = HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod;
5990  }
5991
5992  if (dispatch_info.code_ptr_location == HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative) {
5993    const DexFile& outer_dex_file = GetGraph()->GetDexFile();
5994    if (&outer_dex_file != target_method.dex_file) {
5995      // Calls across dex files are more likely to exceed the available BL range,
5996      // so use absolute patch with fixup if available and kCallArtMethod otherwise.
5997      HInvokeStaticOrDirect::CodePtrLocation code_ptr_location =
5998          (desired_dispatch_info.method_load_kind ==
5999           HInvokeStaticOrDirect::MethodLoadKind::kDirectAddressWithFixup)
6000          ? HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup
6001          : HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod;
6002      return HInvokeStaticOrDirect::DispatchInfo {
6003        dispatch_info.method_load_kind,
6004        code_ptr_location,
6005        dispatch_info.method_load_data,
6006        0u
6007      };
6008    }
6009  }
6010  return dispatch_info;
6011}
6012
6013Register CodeGeneratorARM::GetInvokeStaticOrDirectExtraParameter(HInvokeStaticOrDirect* invoke,
6014                                                                 Register temp) {
6015  DCHECK_EQ(invoke->InputCount(), invoke->GetNumberOfArguments() + 1u);
6016  Location location = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
6017  if (!invoke->GetLocations()->Intrinsified()) {
6018    return location.AsRegister<Register>();
6019  }
6020  // For intrinsics we allow any location, so it may be on the stack.
6021  if (!location.IsRegister()) {
6022    __ LoadFromOffset(kLoadWord, temp, SP, location.GetStackIndex());
6023    return temp;
6024  }
6025  // For register locations, check if the register was saved. If so, get it from the stack.
6026  // Note: There is a chance that the register was saved but not overwritten, so we could
6027  // save one load. However, since this is just an intrinsic slow path we prefer this
6028  // simple and more robust approach rather that trying to determine if that's the case.
6029  SlowPathCode* slow_path = GetCurrentSlowPath();
6030  DCHECK(slow_path != nullptr);  // For intrinsified invokes the call is emitted on the slow path.
6031  if (slow_path->IsCoreRegisterSaved(location.AsRegister<Register>())) {
6032    int stack_offset = slow_path->GetStackOffsetOfCoreRegister(location.AsRegister<Register>());
6033    __ LoadFromOffset(kLoadWord, temp, SP, stack_offset);
6034    return temp;
6035  }
6036  return location.AsRegister<Register>();
6037}
6038
6039void CodeGeneratorARM::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) {
6040  // For better instruction scheduling we load the direct code pointer before the method pointer.
6041  switch (invoke->GetCodePtrLocation()) {
6042    case HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup:
6043      // LR = code address from literal pool with link-time patch.
6044      __ LoadLiteral(LR, DeduplicateMethodCodeLiteral(invoke->GetTargetMethod()));
6045      break;
6046    case HInvokeStaticOrDirect::CodePtrLocation::kCallDirect:
6047      // LR = invoke->GetDirectCodePtr();
6048      __ LoadImmediate(LR, invoke->GetDirectCodePtr());
6049      break;
6050    default:
6051      break;
6052  }
6053
6054  Location callee_method = temp;  // For all kinds except kRecursive, callee will be in temp.
6055  switch (invoke->GetMethodLoadKind()) {
6056    case HInvokeStaticOrDirect::MethodLoadKind::kStringInit:
6057      // temp = thread->string_init_entrypoint
6058      __ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), TR, invoke->GetStringInitOffset());
6059      break;
6060    case HInvokeStaticOrDirect::MethodLoadKind::kRecursive:
6061      callee_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
6062      break;
6063    case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress:
6064      __ LoadImmediate(temp.AsRegister<Register>(), invoke->GetMethodAddress());
6065      break;
6066    case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddressWithFixup:
6067      __ LoadLiteral(temp.AsRegister<Register>(),
6068                     DeduplicateMethodAddressLiteral(invoke->GetTargetMethod()));
6069      break;
6070    case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative: {
6071      HArmDexCacheArraysBase* base =
6072          invoke->InputAt(invoke->GetSpecialInputIndex())->AsArmDexCacheArraysBase();
6073      Register base_reg = GetInvokeStaticOrDirectExtraParameter(invoke,
6074                                                                temp.AsRegister<Register>());
6075      int32_t offset = invoke->GetDexCacheArrayOffset() - base->GetElementOffset();
6076      __ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), base_reg, offset);
6077      break;
6078    }
6079    case HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod: {
6080      Location current_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
6081      Register method_reg;
6082      Register reg = temp.AsRegister<Register>();
6083      if (current_method.IsRegister()) {
6084        method_reg = current_method.AsRegister<Register>();
6085      } else {
6086        DCHECK(invoke->GetLocations()->Intrinsified());
6087        DCHECK(!current_method.IsValid());
6088        method_reg = reg;
6089        __ LoadFromOffset(kLoadWord, reg, SP, kCurrentMethodStackOffset);
6090      }
6091      // /* ArtMethod*[] */ temp = temp.ptr_sized_fields_->dex_cache_resolved_methods_;
6092      __ LoadFromOffset(kLoadWord,
6093                        reg,
6094                        method_reg,
6095                        ArtMethod::DexCacheResolvedMethodsOffset(kArmPointerSize).Int32Value());
6096      // temp = temp[index_in_cache]
6097      uint32_t index_in_cache = invoke->GetTargetMethod().dex_method_index;
6098      __ LoadFromOffset(kLoadWord, reg, reg, CodeGenerator::GetCachePointerOffset(index_in_cache));
6099      break;
6100    }
6101  }
6102
6103  switch (invoke->GetCodePtrLocation()) {
6104    case HInvokeStaticOrDirect::CodePtrLocation::kCallSelf:
6105      __ bl(GetFrameEntryLabel());
6106      break;
6107    case HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative:
6108      relative_call_patches_.emplace_back(invoke->GetTargetMethod());
6109      __ BindTrackedLabel(&relative_call_patches_.back().label);
6110      // Arbitrarily branch to the BL itself, override at link time.
6111      __ bl(&relative_call_patches_.back().label);
6112      break;
6113    case HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup:
6114    case HInvokeStaticOrDirect::CodePtrLocation::kCallDirect:
6115      // LR prepared above for better instruction scheduling.
6116      // LR()
6117      __ blx(LR);
6118      break;
6119    case HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod:
6120      // LR = callee_method->entry_point_from_quick_compiled_code_
6121      __ LoadFromOffset(
6122          kLoadWord, LR, callee_method.AsRegister<Register>(),
6123          ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArmWordSize).Int32Value());
6124      // LR()
6125      __ blx(LR);
6126      break;
6127  }
6128
6129  DCHECK(!IsLeafMethod());
6130}
6131
6132void CodeGeneratorARM::GenerateVirtualCall(HInvokeVirtual* invoke, Location temp_location) {
6133  Register temp = temp_location.AsRegister<Register>();
6134  uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
6135      invoke->GetVTableIndex(), kArmPointerSize).Uint32Value();
6136
6137  // Use the calling convention instead of the location of the receiver, as
6138  // intrinsics may have put the receiver in a different register. In the intrinsics
6139  // slow path, the arguments have been moved to the right place, so here we are
6140  // guaranteed that the receiver is the first register of the calling convention.
6141  InvokeDexCallingConvention calling_convention;
6142  Register receiver = calling_convention.GetRegisterAt(0);
6143  uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
6144  // /* HeapReference<Class> */ temp = receiver->klass_
6145  __ LoadFromOffset(kLoadWord, temp, receiver, class_offset);
6146  MaybeRecordImplicitNullCheck(invoke);
6147  // Instead of simply (possibly) unpoisoning `temp` here, we should
6148  // emit a read barrier for the previous class reference load.
6149  // However this is not required in practice, as this is an
6150  // intermediate/temporary reference and because the current
6151  // concurrent copying collector keeps the from-space memory
6152  // intact/accessible until the end of the marking phase (the
6153  // concurrent copying collector may not in the future).
6154  __ MaybeUnpoisonHeapReference(temp);
6155  // temp = temp->GetMethodAt(method_offset);
6156  uint32_t entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(
6157      kArmWordSize).Int32Value();
6158  __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
6159  // LR = temp->GetEntryPoint();
6160  __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
6161  // LR();
6162  __ blx(LR);
6163}
6164
6165void CodeGeneratorARM::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
6166  DCHECK(linker_patches->empty());
6167  size_t size =
6168      method_patches_.size() +
6169      call_patches_.size() +
6170      relative_call_patches_.size() +
6171      /* MOVW+MOVT for each base */ 2u * dex_cache_arrays_base_labels_.size();
6172  linker_patches->reserve(size);
6173  for (const auto& entry : method_patches_) {
6174    const MethodReference& target_method = entry.first;
6175    Literal* literal = entry.second;
6176    DCHECK(literal->GetLabel()->IsBound());
6177    uint32_t literal_offset = literal->GetLabel()->Position();
6178    linker_patches->push_back(LinkerPatch::MethodPatch(literal_offset,
6179                                                       target_method.dex_file,
6180                                                       target_method.dex_method_index));
6181  }
6182  for (const auto& entry : call_patches_) {
6183    const MethodReference& target_method = entry.first;
6184    Literal* literal = entry.second;
6185    DCHECK(literal->GetLabel()->IsBound());
6186    uint32_t literal_offset = literal->GetLabel()->Position();
6187    linker_patches->push_back(LinkerPatch::CodePatch(literal_offset,
6188                                                     target_method.dex_file,
6189                                                     target_method.dex_method_index));
6190  }
6191  for (const MethodPatchInfo<Label>& info : relative_call_patches_) {
6192    uint32_t literal_offset = info.label.Position();
6193    linker_patches->push_back(LinkerPatch::RelativeCodePatch(literal_offset,
6194                                                             info.target_method.dex_file,
6195                                                             info.target_method.dex_method_index));
6196  }
6197  for (const auto& pair : dex_cache_arrays_base_labels_) {
6198    HArmDexCacheArraysBase* base = pair.first;
6199    const DexCacheArraysBaseLabels* labels = &pair.second;
6200    const DexFile& dex_file = base->GetDexFile();
6201    size_t base_element_offset = base->GetElementOffset();
6202    DCHECK(labels->add_pc_label.IsBound());
6203    uint32_t add_pc_offset = dchecked_integral_cast<uint32_t>(labels->add_pc_label.Position());
6204    // Add MOVW patch.
6205    DCHECK(labels->movw_label.IsBound());
6206    uint32_t movw_offset = dchecked_integral_cast<uint32_t>(labels->movw_label.Position());
6207    linker_patches->push_back(LinkerPatch::DexCacheArrayPatch(movw_offset,
6208                                                              &dex_file,
6209                                                              add_pc_offset,
6210                                                              base_element_offset));
6211    // Add MOVT patch.
6212    DCHECK(labels->movt_label.IsBound());
6213    uint32_t movt_offset = dchecked_integral_cast<uint32_t>(labels->movt_label.Position());
6214    linker_patches->push_back(LinkerPatch::DexCacheArrayPatch(movt_offset,
6215                                                              &dex_file,
6216                                                              add_pc_offset,
6217                                                              base_element_offset));
6218  }
6219}
6220
6221Literal* CodeGeneratorARM::DeduplicateMethodLiteral(MethodReference target_method,
6222                                                    MethodToLiteralMap* map) {
6223  // Look up the literal for target_method.
6224  auto lb = map->lower_bound(target_method);
6225  if (lb != map->end() && !map->key_comp()(target_method, lb->first)) {
6226    return lb->second;
6227  }
6228  // We don't have a literal for this method yet, insert a new one.
6229  Literal* literal = __ NewLiteral<uint32_t>(0u);
6230  map->PutBefore(lb, target_method, literal);
6231  return literal;
6232}
6233
6234Literal* CodeGeneratorARM::DeduplicateMethodAddressLiteral(MethodReference target_method) {
6235  return DeduplicateMethodLiteral(target_method, &method_patches_);
6236}
6237
6238Literal* CodeGeneratorARM::DeduplicateMethodCodeLiteral(MethodReference target_method) {
6239  return DeduplicateMethodLiteral(target_method, &call_patches_);
6240}
6241
6242void LocationsBuilderARM::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
6243  // Nothing to do, this should be removed during prepare for register allocator.
6244  LOG(FATAL) << "Unreachable";
6245}
6246
6247void InstructionCodeGeneratorARM::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
6248  // Nothing to do, this should be removed during prepare for register allocator.
6249  LOG(FATAL) << "Unreachable";
6250}
6251
6252void LocationsBuilderARM::VisitFakeString(HFakeString* instruction) {
6253  DCHECK(codegen_->IsBaseline());
6254  LocationSummary* locations =
6255      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
6256  locations->SetOut(Location::ConstantLocation(GetGraph()->GetNullConstant()));
6257}
6258
6259void InstructionCodeGeneratorARM::VisitFakeString(HFakeString* instruction ATTRIBUTE_UNUSED) {
6260  DCHECK(codegen_->IsBaseline());
6261  // Will be generated at use site.
6262}
6263
6264// Simple implementation of packed switch - generate cascaded compare/jumps.
6265void LocationsBuilderARM::VisitPackedSwitch(HPackedSwitch* switch_instr) {
6266  LocationSummary* locations =
6267      new (GetGraph()->GetArena()) LocationSummary(switch_instr, LocationSummary::kNoCall);
6268  locations->SetInAt(0, Location::RequiresRegister());
6269  if (switch_instr->GetNumEntries() > kPackedSwitchCompareJumpThreshold &&
6270      codegen_->GetAssembler()->IsThumb()) {
6271    locations->AddTemp(Location::RequiresRegister());  // We need a temp for the table base.
6272    if (switch_instr->GetStartValue() != 0) {
6273      locations->AddTemp(Location::RequiresRegister());  // We need a temp for the bias.
6274    }
6275  }
6276}
6277
6278void InstructionCodeGeneratorARM::VisitPackedSwitch(HPackedSwitch* switch_instr) {
6279  int32_t lower_bound = switch_instr->GetStartValue();
6280  uint32_t num_entries = switch_instr->GetNumEntries();
6281  LocationSummary* locations = switch_instr->GetLocations();
6282  Register value_reg = locations->InAt(0).AsRegister<Register>();
6283  HBasicBlock* default_block = switch_instr->GetDefaultBlock();
6284
6285  if (num_entries <= kPackedSwitchCompareJumpThreshold || !codegen_->GetAssembler()->IsThumb()) {
6286    // Create a series of compare/jumps.
6287    Register temp_reg = IP;
6288    // Note: It is fine for the below AddConstantSetFlags() using IP register to temporarily store
6289    // the immediate, because IP is used as the destination register. For the other
6290    // AddConstantSetFlags() and GenerateCompareWithImmediate(), the immediate values are constant,
6291    // and they can be encoded in the instruction without making use of IP register.
6292    __ AddConstantSetFlags(temp_reg, value_reg, -lower_bound);
6293
6294    const ArenaVector<HBasicBlock*>& successors = switch_instr->GetBlock()->GetSuccessors();
6295    // Jump to successors[0] if value == lower_bound.
6296    __ b(codegen_->GetLabelOf(successors[0]), EQ);
6297    int32_t last_index = 0;
6298    for (; num_entries - last_index > 2; last_index += 2) {
6299      __ AddConstantSetFlags(temp_reg, temp_reg, -2);
6300      // Jump to successors[last_index + 1] if value < case_value[last_index + 2].
6301      __ b(codegen_->GetLabelOf(successors[last_index + 1]), LO);
6302      // Jump to successors[last_index + 2] if value == case_value[last_index + 2].
6303      __ b(codegen_->GetLabelOf(successors[last_index + 2]), EQ);
6304    }
6305    if (num_entries - last_index == 2) {
6306      // The last missing case_value.
6307      GenerateCompareWithImmediate(temp_reg, 1);
6308      __ b(codegen_->GetLabelOf(successors[last_index + 1]), EQ);
6309    }
6310
6311    // And the default for any other value.
6312    if (!codegen_->GoesToNextBlock(switch_instr->GetBlock(), default_block)) {
6313      __ b(codegen_->GetLabelOf(default_block));
6314    }
6315  } else {
6316    // Create a table lookup.
6317    Register temp_reg = locations->GetTemp(0).AsRegister<Register>();
6318
6319    // Materialize a pointer to the switch table
6320    std::vector<Label*> labels(num_entries);
6321    const ArenaVector<HBasicBlock*>& successors = switch_instr->GetBlock()->GetSuccessors();
6322    for (uint32_t i = 0; i < num_entries; i++) {
6323      labels[i] = codegen_->GetLabelOf(successors[i]);
6324    }
6325    JumpTable* table = __ CreateJumpTable(std::move(labels), temp_reg);
6326
6327    // Remove the bias.
6328    Register key_reg;
6329    if (lower_bound != 0) {
6330      key_reg = locations->GetTemp(1).AsRegister<Register>();
6331      __ AddConstant(key_reg, value_reg, -lower_bound);
6332    } else {
6333      key_reg = value_reg;
6334    }
6335
6336    // Check whether the value is in the table, jump to default block if not.
6337    __ CmpConstant(key_reg, num_entries - 1);
6338    __ b(codegen_->GetLabelOf(default_block), Condition::HI);
6339
6340    // Load the displacement from the table.
6341    __ ldr(temp_reg, Address(temp_reg, key_reg, Shift::LSL, 2));
6342
6343    // Dispatch is a direct add to the PC (for Thumb2).
6344    __ EmitJumpTableDispatch(table, temp_reg);
6345  }
6346}
6347
6348void LocationsBuilderARM::VisitArmDexCacheArraysBase(HArmDexCacheArraysBase* base) {
6349  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(base);
6350  locations->SetOut(Location::RequiresRegister());
6351  codegen_->AddDexCacheArraysBase(base);
6352}
6353
6354void InstructionCodeGeneratorARM::VisitArmDexCacheArraysBase(HArmDexCacheArraysBase* base) {
6355  Register base_reg = base->GetLocations()->Out().AsRegister<Register>();
6356  CodeGeneratorARM::DexCacheArraysBaseLabels* labels = codegen_->GetDexCacheArraysBaseLabels(base);
6357  __ BindTrackedLabel(&labels->movw_label);
6358  __ movw(base_reg, 0u);
6359  __ BindTrackedLabel(&labels->movt_label);
6360  __ movt(base_reg, 0u);
6361  __ BindTrackedLabel(&labels->add_pc_label);
6362  __ add(base_reg, base_reg, ShifterOperand(PC));
6363}
6364
6365void CodeGeneratorARM::MoveFromReturnRegister(Location trg, Primitive::Type type) {
6366  if (!trg.IsValid()) {
6367    DCHECK(type == Primitive::kPrimVoid);
6368    return;
6369  }
6370
6371  DCHECK_NE(type, Primitive::kPrimVoid);
6372
6373  Location return_loc = InvokeDexCallingConventionVisitorARM().GetReturnLocation(type);
6374  if (return_loc.Equals(trg)) {
6375    return;
6376  }
6377
6378  // TODO: Consider pairs in the parallel move resolver, then this could be nicely merged
6379  //       with the last branch.
6380  if (type == Primitive::kPrimLong) {
6381    HParallelMove parallel_move(GetGraph()->GetArena());
6382    parallel_move.AddMove(return_loc.ToLow(), trg.ToLow(), Primitive::kPrimInt, nullptr);
6383    parallel_move.AddMove(return_loc.ToHigh(), trg.ToHigh(), Primitive::kPrimInt, nullptr);
6384    GetMoveResolver()->EmitNativeCode(&parallel_move);
6385  } else if (type == Primitive::kPrimDouble) {
6386    HParallelMove parallel_move(GetGraph()->GetArena());
6387    parallel_move.AddMove(return_loc.ToLow(), trg.ToLow(), Primitive::kPrimFloat, nullptr);
6388    parallel_move.AddMove(return_loc.ToHigh(), trg.ToHigh(), Primitive::kPrimFloat, nullptr);
6389    GetMoveResolver()->EmitNativeCode(&parallel_move);
6390  } else {
6391    // Let the parallel move resolver take care of all of this.
6392    HParallelMove parallel_move(GetGraph()->GetArena());
6393    parallel_move.AddMove(return_loc, trg, type, nullptr);
6394    GetMoveResolver()->EmitNativeCode(&parallel_move);
6395  }
6396}
6397
6398#undef __
6399#undef QUICK_ENTRY_POINT
6400
6401}  // namespace arm
6402}  // namespace art
6403