code_generator_arm.cc revision 351dddf4025f07477161209e374741f089d97cb4
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::VisitCondition(HCondition* cond) {
1622  LocationSummary* locations =
1623      new (GetGraph()->GetArena()) LocationSummary(cond, LocationSummary::kNoCall);
1624  // Handle the long/FP comparisons made in instruction simplification.
1625  switch (cond->InputAt(0)->GetType()) {
1626    case Primitive::kPrimLong:
1627      locations->SetInAt(0, Location::RequiresRegister());
1628      locations->SetInAt(1, Location::RegisterOrConstant(cond->InputAt(1)));
1629      if (cond->NeedsMaterialization()) {
1630        locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
1631      }
1632      break;
1633
1634    case Primitive::kPrimFloat:
1635    case Primitive::kPrimDouble:
1636      locations->SetInAt(0, Location::RequiresFpuRegister());
1637      locations->SetInAt(1, Location::RequiresFpuRegister());
1638      if (cond->NeedsMaterialization()) {
1639        locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1640      }
1641      break;
1642
1643    default:
1644      locations->SetInAt(0, Location::RequiresRegister());
1645      locations->SetInAt(1, Location::RegisterOrConstant(cond->InputAt(1)));
1646      if (cond->NeedsMaterialization()) {
1647        locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1648      }
1649  }
1650}
1651
1652void InstructionCodeGeneratorARM::VisitCondition(HCondition* cond) {
1653  if (!cond->NeedsMaterialization()) {
1654    return;
1655  }
1656
1657  LocationSummary* locations = cond->GetLocations();
1658  Location left = locations->InAt(0);
1659  Location right = locations->InAt(1);
1660  Register out = locations->Out().AsRegister<Register>();
1661  Label true_label, false_label;
1662
1663  switch (cond->InputAt(0)->GetType()) {
1664    default: {
1665      // Integer case.
1666      if (right.IsRegister()) {
1667        __ cmp(left.AsRegister<Register>(), ShifterOperand(right.AsRegister<Register>()));
1668      } else {
1669        DCHECK(right.IsConstant());
1670        GenerateCompareWithImmediate(left.AsRegister<Register>(),
1671                                     CodeGenerator::GetInt32ValueOf(right.GetConstant()));
1672      }
1673      __ it(ARMCondition(cond->GetCondition()), kItElse);
1674      __ mov(locations->Out().AsRegister<Register>(), ShifterOperand(1),
1675             ARMCondition(cond->GetCondition()));
1676      __ mov(locations->Out().AsRegister<Register>(), ShifterOperand(0),
1677             ARMCondition(cond->GetOppositeCondition()));
1678      return;
1679    }
1680    case Primitive::kPrimLong:
1681      GenerateLongComparesAndJumps(cond, &true_label, &false_label);
1682      break;
1683    case Primitive::kPrimFloat:
1684      __ vcmps(left.AsFpuRegister<SRegister>(), right.AsFpuRegister<SRegister>());
1685      GenerateFPJumps(cond, &true_label, &false_label);
1686      break;
1687    case Primitive::kPrimDouble:
1688      __ vcmpd(FromLowSToD(left.AsFpuRegisterPairLow<SRegister>()),
1689               FromLowSToD(right.AsFpuRegisterPairLow<SRegister>()));
1690      GenerateFPJumps(cond, &true_label, &false_label);
1691      break;
1692  }
1693
1694  // Convert the jumps into the result.
1695  Label done_label;
1696
1697  // False case: result = 0.
1698  __ Bind(&false_label);
1699  __ LoadImmediate(out, 0);
1700  __ b(&done_label);
1701
1702  // True case: result = 1.
1703  __ Bind(&true_label);
1704  __ LoadImmediate(out, 1);
1705  __ Bind(&done_label);
1706}
1707
1708void LocationsBuilderARM::VisitEqual(HEqual* comp) {
1709  VisitCondition(comp);
1710}
1711
1712void InstructionCodeGeneratorARM::VisitEqual(HEqual* comp) {
1713  VisitCondition(comp);
1714}
1715
1716void LocationsBuilderARM::VisitNotEqual(HNotEqual* comp) {
1717  VisitCondition(comp);
1718}
1719
1720void InstructionCodeGeneratorARM::VisitNotEqual(HNotEqual* comp) {
1721  VisitCondition(comp);
1722}
1723
1724void LocationsBuilderARM::VisitLessThan(HLessThan* comp) {
1725  VisitCondition(comp);
1726}
1727
1728void InstructionCodeGeneratorARM::VisitLessThan(HLessThan* comp) {
1729  VisitCondition(comp);
1730}
1731
1732void LocationsBuilderARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1733  VisitCondition(comp);
1734}
1735
1736void InstructionCodeGeneratorARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1737  VisitCondition(comp);
1738}
1739
1740void LocationsBuilderARM::VisitGreaterThan(HGreaterThan* comp) {
1741  VisitCondition(comp);
1742}
1743
1744void InstructionCodeGeneratorARM::VisitGreaterThan(HGreaterThan* comp) {
1745  VisitCondition(comp);
1746}
1747
1748void LocationsBuilderARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1749  VisitCondition(comp);
1750}
1751
1752void InstructionCodeGeneratorARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1753  VisitCondition(comp);
1754}
1755
1756void LocationsBuilderARM::VisitBelow(HBelow* comp) {
1757  VisitCondition(comp);
1758}
1759
1760void InstructionCodeGeneratorARM::VisitBelow(HBelow* comp) {
1761  VisitCondition(comp);
1762}
1763
1764void LocationsBuilderARM::VisitBelowOrEqual(HBelowOrEqual* comp) {
1765  VisitCondition(comp);
1766}
1767
1768void InstructionCodeGeneratorARM::VisitBelowOrEqual(HBelowOrEqual* comp) {
1769  VisitCondition(comp);
1770}
1771
1772void LocationsBuilderARM::VisitAbove(HAbove* comp) {
1773  VisitCondition(comp);
1774}
1775
1776void InstructionCodeGeneratorARM::VisitAbove(HAbove* comp) {
1777  VisitCondition(comp);
1778}
1779
1780void LocationsBuilderARM::VisitAboveOrEqual(HAboveOrEqual* comp) {
1781  VisitCondition(comp);
1782}
1783
1784void InstructionCodeGeneratorARM::VisitAboveOrEqual(HAboveOrEqual* comp) {
1785  VisitCondition(comp);
1786}
1787
1788void LocationsBuilderARM::VisitLocal(HLocal* local) {
1789  local->SetLocations(nullptr);
1790}
1791
1792void InstructionCodeGeneratorARM::VisitLocal(HLocal* local) {
1793  DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
1794}
1795
1796void LocationsBuilderARM::VisitLoadLocal(HLoadLocal* load) {
1797  load->SetLocations(nullptr);
1798}
1799
1800void InstructionCodeGeneratorARM::VisitLoadLocal(HLoadLocal* load ATTRIBUTE_UNUSED) {
1801  // Nothing to do, this is driven by the code generator.
1802}
1803
1804void LocationsBuilderARM::VisitStoreLocal(HStoreLocal* store) {
1805  LocationSummary* locations =
1806      new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
1807  switch (store->InputAt(1)->GetType()) {
1808    case Primitive::kPrimBoolean:
1809    case Primitive::kPrimByte:
1810    case Primitive::kPrimChar:
1811    case Primitive::kPrimShort:
1812    case Primitive::kPrimInt:
1813    case Primitive::kPrimNot:
1814    case Primitive::kPrimFloat:
1815      locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
1816      break;
1817
1818    case Primitive::kPrimLong:
1819    case Primitive::kPrimDouble:
1820      locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
1821      break;
1822
1823    default:
1824      LOG(FATAL) << "Unexpected local type " << store->InputAt(1)->GetType();
1825  }
1826}
1827
1828void InstructionCodeGeneratorARM::VisitStoreLocal(HStoreLocal* store ATTRIBUTE_UNUSED) {
1829}
1830
1831void LocationsBuilderARM::VisitIntConstant(HIntConstant* constant) {
1832  LocationSummary* locations =
1833      new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1834  locations->SetOut(Location::ConstantLocation(constant));
1835}
1836
1837void InstructionCodeGeneratorARM::VisitIntConstant(HIntConstant* constant ATTRIBUTE_UNUSED) {
1838  // Will be generated at use site.
1839}
1840
1841void LocationsBuilderARM::VisitNullConstant(HNullConstant* constant) {
1842  LocationSummary* locations =
1843      new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1844  locations->SetOut(Location::ConstantLocation(constant));
1845}
1846
1847void InstructionCodeGeneratorARM::VisitNullConstant(HNullConstant* constant ATTRIBUTE_UNUSED) {
1848  // Will be generated at use site.
1849}
1850
1851void LocationsBuilderARM::VisitLongConstant(HLongConstant* constant) {
1852  LocationSummary* locations =
1853      new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1854  locations->SetOut(Location::ConstantLocation(constant));
1855}
1856
1857void InstructionCodeGeneratorARM::VisitLongConstant(HLongConstant* constant ATTRIBUTE_UNUSED) {
1858  // Will be generated at use site.
1859}
1860
1861void LocationsBuilderARM::VisitFloatConstant(HFloatConstant* constant) {
1862  LocationSummary* locations =
1863      new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1864  locations->SetOut(Location::ConstantLocation(constant));
1865}
1866
1867void InstructionCodeGeneratorARM::VisitFloatConstant(HFloatConstant* constant ATTRIBUTE_UNUSED) {
1868  // Will be generated at use site.
1869}
1870
1871void LocationsBuilderARM::VisitDoubleConstant(HDoubleConstant* constant) {
1872  LocationSummary* locations =
1873      new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1874  locations->SetOut(Location::ConstantLocation(constant));
1875}
1876
1877void InstructionCodeGeneratorARM::VisitDoubleConstant(HDoubleConstant* constant ATTRIBUTE_UNUSED) {
1878  // Will be generated at use site.
1879}
1880
1881void LocationsBuilderARM::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
1882  memory_barrier->SetLocations(nullptr);
1883}
1884
1885void InstructionCodeGeneratorARM::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
1886  GenerateMemoryBarrier(memory_barrier->GetBarrierKind());
1887}
1888
1889void LocationsBuilderARM::VisitReturnVoid(HReturnVoid* ret) {
1890  ret->SetLocations(nullptr);
1891}
1892
1893void InstructionCodeGeneratorARM::VisitReturnVoid(HReturnVoid* ret ATTRIBUTE_UNUSED) {
1894  codegen_->GenerateFrameExit();
1895}
1896
1897void LocationsBuilderARM::VisitReturn(HReturn* ret) {
1898  LocationSummary* locations =
1899      new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
1900  locations->SetInAt(0, parameter_visitor_.GetReturnLocation(ret->InputAt(0)->GetType()));
1901}
1902
1903void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret ATTRIBUTE_UNUSED) {
1904  codegen_->GenerateFrameExit();
1905}
1906
1907void LocationsBuilderARM::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
1908  // The trampoline uses the same calling convention as dex calling conventions,
1909  // except instead of loading arg0/r0 with the target Method*, arg0/r0 will contain
1910  // the method_idx.
1911  HandleInvoke(invoke);
1912}
1913
1914void InstructionCodeGeneratorARM::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
1915  codegen_->GenerateInvokeUnresolvedRuntimeCall(invoke);
1916}
1917
1918void LocationsBuilderARM::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
1919  // When we do not run baseline, explicit clinit checks triggered by static
1920  // invokes must have been pruned by art::PrepareForRegisterAllocation.
1921  DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck());
1922
1923  IntrinsicLocationsBuilderARM intrinsic(GetGraph()->GetArena(),
1924                                         codegen_->GetAssembler(),
1925                                         codegen_->GetInstructionSetFeatures());
1926  if (intrinsic.TryDispatch(invoke)) {
1927    if (invoke->GetLocations()->CanCall() && invoke->HasPcRelativeDexCache()) {
1928      invoke->GetLocations()->SetInAt(invoke->GetSpecialInputIndex(), Location::Any());
1929    }
1930    return;
1931  }
1932
1933  HandleInvoke(invoke);
1934
1935  // For PC-relative dex cache the invoke has an extra input, the PC-relative address base.
1936  if (invoke->HasPcRelativeDexCache()) {
1937    invoke->GetLocations()->SetInAt(invoke->GetSpecialInputIndex(), Location::RequiresRegister());
1938  }
1939}
1940
1941static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorARM* codegen) {
1942  if (invoke->GetLocations()->Intrinsified()) {
1943    IntrinsicCodeGeneratorARM intrinsic(codegen);
1944    intrinsic.Dispatch(invoke);
1945    return true;
1946  }
1947  return false;
1948}
1949
1950void InstructionCodeGeneratorARM::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
1951  // When we do not run baseline, explicit clinit checks triggered by static
1952  // invokes must have been pruned by art::PrepareForRegisterAllocation.
1953  DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck());
1954
1955  if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1956    return;
1957  }
1958
1959  LocationSummary* locations = invoke->GetLocations();
1960  codegen_->GenerateStaticOrDirectCall(
1961      invoke, locations->HasTemps() ? locations->GetTemp(0) : Location::NoLocation());
1962  codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1963}
1964
1965void LocationsBuilderARM::HandleInvoke(HInvoke* invoke) {
1966  InvokeDexCallingConventionVisitorARM calling_convention_visitor;
1967  CodeGenerator::CreateCommonInvokeLocationSummary(invoke, &calling_convention_visitor);
1968}
1969
1970void LocationsBuilderARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
1971  IntrinsicLocationsBuilderARM intrinsic(GetGraph()->GetArena(),
1972                                         codegen_->GetAssembler(),
1973                                         codegen_->GetInstructionSetFeatures());
1974  if (intrinsic.TryDispatch(invoke)) {
1975    return;
1976  }
1977
1978  HandleInvoke(invoke);
1979}
1980
1981void InstructionCodeGeneratorARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
1982  if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1983    return;
1984  }
1985
1986  codegen_->GenerateVirtualCall(invoke, invoke->GetLocations()->GetTemp(0));
1987  DCHECK(!codegen_->IsLeafMethod());
1988  codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1989}
1990
1991void LocationsBuilderARM::VisitInvokeInterface(HInvokeInterface* invoke) {
1992  HandleInvoke(invoke);
1993  // Add the hidden argument.
1994  invoke->GetLocations()->AddTemp(Location::RegisterLocation(R12));
1995}
1996
1997void InstructionCodeGeneratorARM::VisitInvokeInterface(HInvokeInterface* invoke) {
1998  // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
1999  LocationSummary* locations = invoke->GetLocations();
2000  Register temp = locations->GetTemp(0).AsRegister<Register>();
2001  Register hidden_reg = locations->GetTemp(1).AsRegister<Register>();
2002  uint32_t method_offset = mirror::Class::EmbeddedImTableEntryOffset(
2003      invoke->GetImtIndex() % mirror::Class::kImtSize, kArmPointerSize).Uint32Value();
2004  Location receiver = locations->InAt(0);
2005  uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
2006
2007  // Set the hidden argument. This is safe to do this here, as R12
2008  // won't be modified thereafter, before the `blx` (call) instruction.
2009  DCHECK_EQ(R12, hidden_reg);
2010  __ LoadImmediate(hidden_reg, invoke->GetDexMethodIndex());
2011
2012  if (receiver.IsStackSlot()) {
2013    __ LoadFromOffset(kLoadWord, temp, SP, receiver.GetStackIndex());
2014    // /* HeapReference<Class> */ temp = temp->klass_
2015    __ LoadFromOffset(kLoadWord, temp, temp, class_offset);
2016  } else {
2017    // /* HeapReference<Class> */ temp = receiver->klass_
2018    __ LoadFromOffset(kLoadWord, temp, receiver.AsRegister<Register>(), class_offset);
2019  }
2020  codegen_->MaybeRecordImplicitNullCheck(invoke);
2021  // Instead of simply (possibly) unpoisoning `temp` here, we should
2022  // emit a read barrier for the previous class reference load.
2023  // However this is not required in practice, as this is an
2024  // intermediate/temporary reference and because the current
2025  // concurrent copying collector keeps the from-space memory
2026  // intact/accessible until the end of the marking phase (the
2027  // concurrent copying collector may not in the future).
2028  __ MaybeUnpoisonHeapReference(temp);
2029  // temp = temp->GetImtEntryAt(method_offset);
2030  uint32_t entry_point =
2031      ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArmWordSize).Int32Value();
2032  __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
2033  // LR = temp->GetEntryPoint();
2034  __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
2035  // LR();
2036  __ blx(LR);
2037  DCHECK(!codegen_->IsLeafMethod());
2038  codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
2039}
2040
2041void LocationsBuilderARM::VisitNeg(HNeg* neg) {
2042  LocationSummary* locations =
2043      new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
2044  switch (neg->GetResultType()) {
2045    case Primitive::kPrimInt: {
2046      locations->SetInAt(0, Location::RequiresRegister());
2047      locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2048      break;
2049    }
2050    case Primitive::kPrimLong: {
2051      locations->SetInAt(0, Location::RequiresRegister());
2052      locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
2053      break;
2054    }
2055
2056    case Primitive::kPrimFloat:
2057    case Primitive::kPrimDouble:
2058      locations->SetInAt(0, Location::RequiresFpuRegister());
2059      locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
2060      break;
2061
2062    default:
2063      LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
2064  }
2065}
2066
2067void InstructionCodeGeneratorARM::VisitNeg(HNeg* neg) {
2068  LocationSummary* locations = neg->GetLocations();
2069  Location out = locations->Out();
2070  Location in = locations->InAt(0);
2071  switch (neg->GetResultType()) {
2072    case Primitive::kPrimInt:
2073      DCHECK(in.IsRegister());
2074      __ rsb(out.AsRegister<Register>(), in.AsRegister<Register>(), ShifterOperand(0));
2075      break;
2076
2077    case Primitive::kPrimLong:
2078      DCHECK(in.IsRegisterPair());
2079      // out.lo = 0 - in.lo (and update the carry/borrow (C) flag)
2080      __ rsbs(out.AsRegisterPairLow<Register>(),
2081              in.AsRegisterPairLow<Register>(),
2082              ShifterOperand(0));
2083      // We cannot emit an RSC (Reverse Subtract with Carry)
2084      // instruction here, as it does not exist in the Thumb-2
2085      // instruction set.  We use the following approach
2086      // using SBC and SUB instead.
2087      //
2088      // out.hi = -C
2089      __ sbc(out.AsRegisterPairHigh<Register>(),
2090             out.AsRegisterPairHigh<Register>(),
2091             ShifterOperand(out.AsRegisterPairHigh<Register>()));
2092      // out.hi = out.hi - in.hi
2093      __ sub(out.AsRegisterPairHigh<Register>(),
2094             out.AsRegisterPairHigh<Register>(),
2095             ShifterOperand(in.AsRegisterPairHigh<Register>()));
2096      break;
2097
2098    case Primitive::kPrimFloat:
2099      DCHECK(in.IsFpuRegister());
2100      __ vnegs(out.AsFpuRegister<SRegister>(), in.AsFpuRegister<SRegister>());
2101      break;
2102
2103    case Primitive::kPrimDouble:
2104      DCHECK(in.IsFpuRegisterPair());
2105      __ vnegd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2106               FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
2107      break;
2108
2109    default:
2110      LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
2111  }
2112}
2113
2114void LocationsBuilderARM::VisitTypeConversion(HTypeConversion* conversion) {
2115  Primitive::Type result_type = conversion->GetResultType();
2116  Primitive::Type input_type = conversion->GetInputType();
2117  DCHECK_NE(result_type, input_type);
2118
2119  // The float-to-long, double-to-long and long-to-float type conversions
2120  // rely on a call to the runtime.
2121  LocationSummary::CallKind call_kind =
2122      (((input_type == Primitive::kPrimFloat || input_type == Primitive::kPrimDouble)
2123        && result_type == Primitive::kPrimLong)
2124       || (input_type == Primitive::kPrimLong && result_type == Primitive::kPrimFloat))
2125      ? LocationSummary::kCall
2126      : LocationSummary::kNoCall;
2127  LocationSummary* locations =
2128      new (GetGraph()->GetArena()) LocationSummary(conversion, call_kind);
2129
2130  // The Java language does not allow treating boolean as an integral type but
2131  // our bit representation makes it safe.
2132
2133  switch (result_type) {
2134    case Primitive::kPrimByte:
2135      switch (input_type) {
2136        case Primitive::kPrimBoolean:
2137          // Boolean input is a result of code transformations.
2138        case Primitive::kPrimShort:
2139        case Primitive::kPrimInt:
2140        case Primitive::kPrimChar:
2141          // Processing a Dex `int-to-byte' instruction.
2142          locations->SetInAt(0, Location::RequiresRegister());
2143          locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2144          break;
2145
2146        default:
2147          LOG(FATAL) << "Unexpected type conversion from " << input_type
2148                     << " to " << result_type;
2149      }
2150      break;
2151
2152    case Primitive::kPrimShort:
2153      switch (input_type) {
2154        case Primitive::kPrimBoolean:
2155          // Boolean input is a result of code transformations.
2156        case Primitive::kPrimByte:
2157        case Primitive::kPrimInt:
2158        case Primitive::kPrimChar:
2159          // Processing a Dex `int-to-short' instruction.
2160          locations->SetInAt(0, Location::RequiresRegister());
2161          locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2162          break;
2163
2164        default:
2165          LOG(FATAL) << "Unexpected type conversion from " << input_type
2166                     << " to " << result_type;
2167      }
2168      break;
2169
2170    case Primitive::kPrimInt:
2171      switch (input_type) {
2172        case Primitive::kPrimLong:
2173          // Processing a Dex `long-to-int' instruction.
2174          locations->SetInAt(0, Location::Any());
2175          locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2176          break;
2177
2178        case Primitive::kPrimFloat:
2179          // Processing a Dex `float-to-int' instruction.
2180          locations->SetInAt(0, Location::RequiresFpuRegister());
2181          locations->SetOut(Location::RequiresRegister());
2182          locations->AddTemp(Location::RequiresFpuRegister());
2183          break;
2184
2185        case Primitive::kPrimDouble:
2186          // Processing a Dex `double-to-int' instruction.
2187          locations->SetInAt(0, Location::RequiresFpuRegister());
2188          locations->SetOut(Location::RequiresRegister());
2189          locations->AddTemp(Location::RequiresFpuRegister());
2190          break;
2191
2192        default:
2193          LOG(FATAL) << "Unexpected type conversion from " << input_type
2194                     << " to " << result_type;
2195      }
2196      break;
2197
2198    case Primitive::kPrimLong:
2199      switch (input_type) {
2200        case Primitive::kPrimBoolean:
2201          // Boolean input is a result of code transformations.
2202        case Primitive::kPrimByte:
2203        case Primitive::kPrimShort:
2204        case Primitive::kPrimInt:
2205        case Primitive::kPrimChar:
2206          // Processing a Dex `int-to-long' instruction.
2207          locations->SetInAt(0, Location::RequiresRegister());
2208          locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2209          break;
2210
2211        case Primitive::kPrimFloat: {
2212          // Processing a Dex `float-to-long' instruction.
2213          InvokeRuntimeCallingConvention calling_convention;
2214          locations->SetInAt(0, Location::FpuRegisterLocation(
2215              calling_convention.GetFpuRegisterAt(0)));
2216          locations->SetOut(Location::RegisterPairLocation(R0, R1));
2217          break;
2218        }
2219
2220        case Primitive::kPrimDouble: {
2221          // Processing a Dex `double-to-long' instruction.
2222          InvokeRuntimeCallingConvention calling_convention;
2223          locations->SetInAt(0, Location::FpuRegisterPairLocation(
2224              calling_convention.GetFpuRegisterAt(0),
2225              calling_convention.GetFpuRegisterAt(1)));
2226          locations->SetOut(Location::RegisterPairLocation(R0, R1));
2227          break;
2228        }
2229
2230        default:
2231          LOG(FATAL) << "Unexpected type conversion from " << input_type
2232                     << " to " << result_type;
2233      }
2234      break;
2235
2236    case Primitive::kPrimChar:
2237      switch (input_type) {
2238        case Primitive::kPrimBoolean:
2239          // Boolean input is a result of code transformations.
2240        case Primitive::kPrimByte:
2241        case Primitive::kPrimShort:
2242        case Primitive::kPrimInt:
2243          // Processing a Dex `int-to-char' instruction.
2244          locations->SetInAt(0, Location::RequiresRegister());
2245          locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2246          break;
2247
2248        default:
2249          LOG(FATAL) << "Unexpected type conversion from " << input_type
2250                     << " to " << result_type;
2251      }
2252      break;
2253
2254    case Primitive::kPrimFloat:
2255      switch (input_type) {
2256        case Primitive::kPrimBoolean:
2257          // Boolean input is a result of code transformations.
2258        case Primitive::kPrimByte:
2259        case Primitive::kPrimShort:
2260        case Primitive::kPrimInt:
2261        case Primitive::kPrimChar:
2262          // Processing a Dex `int-to-float' instruction.
2263          locations->SetInAt(0, Location::RequiresRegister());
2264          locations->SetOut(Location::RequiresFpuRegister());
2265          break;
2266
2267        case Primitive::kPrimLong: {
2268          // Processing a Dex `long-to-float' instruction.
2269          InvokeRuntimeCallingConvention calling_convention;
2270          locations->SetInAt(0, Location::RegisterPairLocation(
2271              calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
2272          locations->SetOut(Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
2273          break;
2274        }
2275
2276        case Primitive::kPrimDouble:
2277          // Processing a Dex `double-to-float' instruction.
2278          locations->SetInAt(0, Location::RequiresFpuRegister());
2279          locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
2280          break;
2281
2282        default:
2283          LOG(FATAL) << "Unexpected type conversion from " << input_type
2284                     << " to " << result_type;
2285      };
2286      break;
2287
2288    case Primitive::kPrimDouble:
2289      switch (input_type) {
2290        case Primitive::kPrimBoolean:
2291          // Boolean input is a result of code transformations.
2292        case Primitive::kPrimByte:
2293        case Primitive::kPrimShort:
2294        case Primitive::kPrimInt:
2295        case Primitive::kPrimChar:
2296          // Processing a Dex `int-to-double' instruction.
2297          locations->SetInAt(0, Location::RequiresRegister());
2298          locations->SetOut(Location::RequiresFpuRegister());
2299          break;
2300
2301        case Primitive::kPrimLong:
2302          // Processing a Dex `long-to-double' instruction.
2303          locations->SetInAt(0, Location::RequiresRegister());
2304          locations->SetOut(Location::RequiresFpuRegister());
2305          locations->AddTemp(Location::RequiresFpuRegister());
2306          locations->AddTemp(Location::RequiresFpuRegister());
2307          break;
2308
2309        case Primitive::kPrimFloat:
2310          // Processing a Dex `float-to-double' instruction.
2311          locations->SetInAt(0, Location::RequiresFpuRegister());
2312          locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
2313          break;
2314
2315        default:
2316          LOG(FATAL) << "Unexpected type conversion from " << input_type
2317                     << " to " << result_type;
2318      };
2319      break;
2320
2321    default:
2322      LOG(FATAL) << "Unexpected type conversion from " << input_type
2323                 << " to " << result_type;
2324  }
2325}
2326
2327void InstructionCodeGeneratorARM::VisitTypeConversion(HTypeConversion* conversion) {
2328  LocationSummary* locations = conversion->GetLocations();
2329  Location out = locations->Out();
2330  Location in = locations->InAt(0);
2331  Primitive::Type result_type = conversion->GetResultType();
2332  Primitive::Type input_type = conversion->GetInputType();
2333  DCHECK_NE(result_type, input_type);
2334  switch (result_type) {
2335    case Primitive::kPrimByte:
2336      switch (input_type) {
2337        case Primitive::kPrimBoolean:
2338          // Boolean input is a result of code transformations.
2339        case Primitive::kPrimShort:
2340        case Primitive::kPrimInt:
2341        case Primitive::kPrimChar:
2342          // Processing a Dex `int-to-byte' instruction.
2343          __ sbfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 8);
2344          break;
2345
2346        default:
2347          LOG(FATAL) << "Unexpected type conversion from " << input_type
2348                     << " to " << result_type;
2349      }
2350      break;
2351
2352    case Primitive::kPrimShort:
2353      switch (input_type) {
2354        case Primitive::kPrimBoolean:
2355          // Boolean input is a result of code transformations.
2356        case Primitive::kPrimByte:
2357        case Primitive::kPrimInt:
2358        case Primitive::kPrimChar:
2359          // Processing a Dex `int-to-short' instruction.
2360          __ sbfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 16);
2361          break;
2362
2363        default:
2364          LOG(FATAL) << "Unexpected type conversion from " << input_type
2365                     << " to " << result_type;
2366      }
2367      break;
2368
2369    case Primitive::kPrimInt:
2370      switch (input_type) {
2371        case Primitive::kPrimLong:
2372          // Processing a Dex `long-to-int' instruction.
2373          DCHECK(out.IsRegister());
2374          if (in.IsRegisterPair()) {
2375            __ Mov(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>());
2376          } else if (in.IsDoubleStackSlot()) {
2377            __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), SP, in.GetStackIndex());
2378          } else {
2379            DCHECK(in.IsConstant());
2380            DCHECK(in.GetConstant()->IsLongConstant());
2381            int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
2382            __ LoadImmediate(out.AsRegister<Register>(), static_cast<int32_t>(value));
2383          }
2384          break;
2385
2386        case Primitive::kPrimFloat: {
2387          // Processing a Dex `float-to-int' instruction.
2388          SRegister temp = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
2389          __ vmovs(temp, in.AsFpuRegister<SRegister>());
2390          __ vcvtis(temp, temp);
2391          __ vmovrs(out.AsRegister<Register>(), temp);
2392          break;
2393        }
2394
2395        case Primitive::kPrimDouble: {
2396          // Processing a Dex `double-to-int' instruction.
2397          SRegister temp_s = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
2398          DRegister temp_d = FromLowSToD(temp_s);
2399          __ vmovd(temp_d, FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
2400          __ vcvtid(temp_s, temp_d);
2401          __ vmovrs(out.AsRegister<Register>(), temp_s);
2402          break;
2403        }
2404
2405        default:
2406          LOG(FATAL) << "Unexpected type conversion from " << input_type
2407                     << " to " << result_type;
2408      }
2409      break;
2410
2411    case Primitive::kPrimLong:
2412      switch (input_type) {
2413        case Primitive::kPrimBoolean:
2414          // Boolean input is a result of code transformations.
2415        case Primitive::kPrimByte:
2416        case Primitive::kPrimShort:
2417        case Primitive::kPrimInt:
2418        case Primitive::kPrimChar:
2419          // Processing a Dex `int-to-long' instruction.
2420          DCHECK(out.IsRegisterPair());
2421          DCHECK(in.IsRegister());
2422          __ Mov(out.AsRegisterPairLow<Register>(), in.AsRegister<Register>());
2423          // Sign extension.
2424          __ Asr(out.AsRegisterPairHigh<Register>(),
2425                 out.AsRegisterPairLow<Register>(),
2426                 31);
2427          break;
2428
2429        case Primitive::kPrimFloat:
2430          // Processing a Dex `float-to-long' instruction.
2431          codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pF2l),
2432                                  conversion,
2433                                  conversion->GetDexPc(),
2434                                  nullptr);
2435          CheckEntrypointTypes<kQuickF2l, int64_t, float>();
2436          break;
2437
2438        case Primitive::kPrimDouble:
2439          // Processing a Dex `double-to-long' instruction.
2440          codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pD2l),
2441                                  conversion,
2442                                  conversion->GetDexPc(),
2443                                  nullptr);
2444          CheckEntrypointTypes<kQuickD2l, int64_t, double>();
2445          break;
2446
2447        default:
2448          LOG(FATAL) << "Unexpected type conversion from " << input_type
2449                     << " to " << result_type;
2450      }
2451      break;
2452
2453    case Primitive::kPrimChar:
2454      switch (input_type) {
2455        case Primitive::kPrimBoolean:
2456          // Boolean input is a result of code transformations.
2457        case Primitive::kPrimByte:
2458        case Primitive::kPrimShort:
2459        case Primitive::kPrimInt:
2460          // Processing a Dex `int-to-char' instruction.
2461          __ ubfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 16);
2462          break;
2463
2464        default:
2465          LOG(FATAL) << "Unexpected type conversion from " << input_type
2466                     << " to " << result_type;
2467      }
2468      break;
2469
2470    case Primitive::kPrimFloat:
2471      switch (input_type) {
2472        case Primitive::kPrimBoolean:
2473          // Boolean input is a result of code transformations.
2474        case Primitive::kPrimByte:
2475        case Primitive::kPrimShort:
2476        case Primitive::kPrimInt:
2477        case Primitive::kPrimChar: {
2478          // Processing a Dex `int-to-float' instruction.
2479          __ vmovsr(out.AsFpuRegister<SRegister>(), in.AsRegister<Register>());
2480          __ vcvtsi(out.AsFpuRegister<SRegister>(), out.AsFpuRegister<SRegister>());
2481          break;
2482        }
2483
2484        case Primitive::kPrimLong:
2485          // Processing a Dex `long-to-float' instruction.
2486          codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pL2f),
2487                                  conversion,
2488                                  conversion->GetDexPc(),
2489                                  nullptr);
2490          CheckEntrypointTypes<kQuickL2f, float, int64_t>();
2491          break;
2492
2493        case Primitive::kPrimDouble:
2494          // Processing a Dex `double-to-float' instruction.
2495          __ vcvtsd(out.AsFpuRegister<SRegister>(),
2496                    FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
2497          break;
2498
2499        default:
2500          LOG(FATAL) << "Unexpected type conversion from " << input_type
2501                     << " to " << result_type;
2502      };
2503      break;
2504
2505    case Primitive::kPrimDouble:
2506      switch (input_type) {
2507        case Primitive::kPrimBoolean:
2508          // Boolean input is a result of code transformations.
2509        case Primitive::kPrimByte:
2510        case Primitive::kPrimShort:
2511        case Primitive::kPrimInt:
2512        case Primitive::kPrimChar: {
2513          // Processing a Dex `int-to-double' instruction.
2514          __ vmovsr(out.AsFpuRegisterPairLow<SRegister>(), in.AsRegister<Register>());
2515          __ vcvtdi(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2516                    out.AsFpuRegisterPairLow<SRegister>());
2517          break;
2518        }
2519
2520        case Primitive::kPrimLong: {
2521          // Processing a Dex `long-to-double' instruction.
2522          Register low = in.AsRegisterPairLow<Register>();
2523          Register high = in.AsRegisterPairHigh<Register>();
2524          SRegister out_s = out.AsFpuRegisterPairLow<SRegister>();
2525          DRegister out_d = FromLowSToD(out_s);
2526          SRegister temp_s = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
2527          DRegister temp_d = FromLowSToD(temp_s);
2528          SRegister constant_s = locations->GetTemp(1).AsFpuRegisterPairLow<SRegister>();
2529          DRegister constant_d = FromLowSToD(constant_s);
2530
2531          // temp_d = int-to-double(high)
2532          __ vmovsr(temp_s, high);
2533          __ vcvtdi(temp_d, temp_s);
2534          // constant_d = k2Pow32EncodingForDouble
2535          __ LoadDImmediate(constant_d, bit_cast<double, int64_t>(k2Pow32EncodingForDouble));
2536          // out_d = unsigned-to-double(low)
2537          __ vmovsr(out_s, low);
2538          __ vcvtdu(out_d, out_s);
2539          // out_d += temp_d * constant_d
2540          __ vmlad(out_d, temp_d, constant_d);
2541          break;
2542        }
2543
2544        case Primitive::kPrimFloat:
2545          // Processing a Dex `float-to-double' instruction.
2546          __ vcvtds(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2547                    in.AsFpuRegister<SRegister>());
2548          break;
2549
2550        default:
2551          LOG(FATAL) << "Unexpected type conversion from " << input_type
2552                     << " to " << result_type;
2553      };
2554      break;
2555
2556    default:
2557      LOG(FATAL) << "Unexpected type conversion from " << input_type
2558                 << " to " << result_type;
2559  }
2560}
2561
2562void LocationsBuilderARM::VisitAdd(HAdd* add) {
2563  LocationSummary* locations =
2564      new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
2565  switch (add->GetResultType()) {
2566    case Primitive::kPrimInt: {
2567      locations->SetInAt(0, Location::RequiresRegister());
2568      locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
2569      locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2570      break;
2571    }
2572
2573    case Primitive::kPrimLong: {
2574      locations->SetInAt(0, Location::RequiresRegister());
2575      locations->SetInAt(1, Location::RequiresRegister());
2576      locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2577      break;
2578    }
2579
2580    case Primitive::kPrimFloat:
2581    case Primitive::kPrimDouble: {
2582      locations->SetInAt(0, Location::RequiresFpuRegister());
2583      locations->SetInAt(1, Location::RequiresFpuRegister());
2584      locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
2585      break;
2586    }
2587
2588    default:
2589      LOG(FATAL) << "Unexpected add type " << add->GetResultType();
2590  }
2591}
2592
2593void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) {
2594  LocationSummary* locations = add->GetLocations();
2595  Location out = locations->Out();
2596  Location first = locations->InAt(0);
2597  Location second = locations->InAt(1);
2598  switch (add->GetResultType()) {
2599    case Primitive::kPrimInt:
2600      if (second.IsRegister()) {
2601        __ add(out.AsRegister<Register>(),
2602               first.AsRegister<Register>(),
2603               ShifterOperand(second.AsRegister<Register>()));
2604      } else {
2605        __ AddConstant(out.AsRegister<Register>(),
2606                       first.AsRegister<Register>(),
2607                       second.GetConstant()->AsIntConstant()->GetValue());
2608      }
2609      break;
2610
2611    case Primitive::kPrimLong: {
2612      DCHECK(second.IsRegisterPair());
2613      __ adds(out.AsRegisterPairLow<Register>(),
2614              first.AsRegisterPairLow<Register>(),
2615              ShifterOperand(second.AsRegisterPairLow<Register>()));
2616      __ adc(out.AsRegisterPairHigh<Register>(),
2617             first.AsRegisterPairHigh<Register>(),
2618             ShifterOperand(second.AsRegisterPairHigh<Register>()));
2619      break;
2620    }
2621
2622    case Primitive::kPrimFloat:
2623      __ vadds(out.AsFpuRegister<SRegister>(),
2624               first.AsFpuRegister<SRegister>(),
2625               second.AsFpuRegister<SRegister>());
2626      break;
2627
2628    case Primitive::kPrimDouble:
2629      __ vaddd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2630               FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2631               FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
2632      break;
2633
2634    default:
2635      LOG(FATAL) << "Unexpected add type " << add->GetResultType();
2636  }
2637}
2638
2639void LocationsBuilderARM::VisitSub(HSub* sub) {
2640  LocationSummary* locations =
2641      new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
2642  switch (sub->GetResultType()) {
2643    case Primitive::kPrimInt: {
2644      locations->SetInAt(0, Location::RequiresRegister());
2645      locations->SetInAt(1, Location::RegisterOrConstant(sub->InputAt(1)));
2646      locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2647      break;
2648    }
2649
2650    case Primitive::kPrimLong: {
2651      locations->SetInAt(0, Location::RequiresRegister());
2652      locations->SetInAt(1, Location::RequiresRegister());
2653      locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2654      break;
2655    }
2656    case Primitive::kPrimFloat:
2657    case Primitive::kPrimDouble: {
2658      locations->SetInAt(0, Location::RequiresFpuRegister());
2659      locations->SetInAt(1, Location::RequiresFpuRegister());
2660      locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
2661      break;
2662    }
2663    default:
2664      LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
2665  }
2666}
2667
2668void InstructionCodeGeneratorARM::VisitSub(HSub* sub) {
2669  LocationSummary* locations = sub->GetLocations();
2670  Location out = locations->Out();
2671  Location first = locations->InAt(0);
2672  Location second = locations->InAt(1);
2673  switch (sub->GetResultType()) {
2674    case Primitive::kPrimInt: {
2675      if (second.IsRegister()) {
2676        __ sub(out.AsRegister<Register>(),
2677               first.AsRegister<Register>(),
2678               ShifterOperand(second.AsRegister<Register>()));
2679      } else {
2680        __ AddConstant(out.AsRegister<Register>(),
2681                       first.AsRegister<Register>(),
2682                       -second.GetConstant()->AsIntConstant()->GetValue());
2683      }
2684      break;
2685    }
2686
2687    case Primitive::kPrimLong: {
2688      DCHECK(second.IsRegisterPair());
2689      __ subs(out.AsRegisterPairLow<Register>(),
2690              first.AsRegisterPairLow<Register>(),
2691              ShifterOperand(second.AsRegisterPairLow<Register>()));
2692      __ sbc(out.AsRegisterPairHigh<Register>(),
2693             first.AsRegisterPairHigh<Register>(),
2694             ShifterOperand(second.AsRegisterPairHigh<Register>()));
2695      break;
2696    }
2697
2698    case Primitive::kPrimFloat: {
2699      __ vsubs(out.AsFpuRegister<SRegister>(),
2700               first.AsFpuRegister<SRegister>(),
2701               second.AsFpuRegister<SRegister>());
2702      break;
2703    }
2704
2705    case Primitive::kPrimDouble: {
2706      __ vsubd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2707               FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2708               FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
2709      break;
2710    }
2711
2712
2713    default:
2714      LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
2715  }
2716}
2717
2718void LocationsBuilderARM::VisitMul(HMul* mul) {
2719  LocationSummary* locations =
2720      new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
2721  switch (mul->GetResultType()) {
2722    case Primitive::kPrimInt:
2723    case Primitive::kPrimLong:  {
2724      locations->SetInAt(0, Location::RequiresRegister());
2725      locations->SetInAt(1, Location::RequiresRegister());
2726      locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2727      break;
2728    }
2729
2730    case Primitive::kPrimFloat:
2731    case Primitive::kPrimDouble: {
2732      locations->SetInAt(0, Location::RequiresFpuRegister());
2733      locations->SetInAt(1, Location::RequiresFpuRegister());
2734      locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
2735      break;
2736    }
2737
2738    default:
2739      LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
2740  }
2741}
2742
2743void InstructionCodeGeneratorARM::VisitMul(HMul* mul) {
2744  LocationSummary* locations = mul->GetLocations();
2745  Location out = locations->Out();
2746  Location first = locations->InAt(0);
2747  Location second = locations->InAt(1);
2748  switch (mul->GetResultType()) {
2749    case Primitive::kPrimInt: {
2750      __ mul(out.AsRegister<Register>(),
2751             first.AsRegister<Register>(),
2752             second.AsRegister<Register>());
2753      break;
2754    }
2755    case Primitive::kPrimLong: {
2756      Register out_hi = out.AsRegisterPairHigh<Register>();
2757      Register out_lo = out.AsRegisterPairLow<Register>();
2758      Register in1_hi = first.AsRegisterPairHigh<Register>();
2759      Register in1_lo = first.AsRegisterPairLow<Register>();
2760      Register in2_hi = second.AsRegisterPairHigh<Register>();
2761      Register in2_lo = second.AsRegisterPairLow<Register>();
2762
2763      // Extra checks to protect caused by the existence of R1_R2.
2764      // The algorithm is wrong if out.hi is either in1.lo or in2.lo:
2765      // (e.g. in1=r0_r1, in2=r2_r3 and out=r1_r2);
2766      DCHECK_NE(out_hi, in1_lo);
2767      DCHECK_NE(out_hi, in2_lo);
2768
2769      // input: in1 - 64 bits, in2 - 64 bits
2770      // output: out
2771      // formula: out.hi : out.lo = (in1.lo * in2.hi + in1.hi * in2.lo)* 2^32 + in1.lo * in2.lo
2772      // parts: out.hi = in1.lo * in2.hi + in1.hi * in2.lo + (in1.lo * in2.lo)[63:32]
2773      // parts: out.lo = (in1.lo * in2.lo)[31:0]
2774
2775      // IP <- in1.lo * in2.hi
2776      __ mul(IP, in1_lo, in2_hi);
2777      // out.hi <- in1.lo * in2.hi + in1.hi * in2.lo
2778      __ mla(out_hi, in1_hi, in2_lo, IP);
2779      // out.lo <- (in1.lo * in2.lo)[31:0];
2780      __ umull(out_lo, IP, in1_lo, in2_lo);
2781      // out.hi <- in2.hi * in1.lo +  in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
2782      __ add(out_hi, out_hi, ShifterOperand(IP));
2783      break;
2784    }
2785
2786    case Primitive::kPrimFloat: {
2787      __ vmuls(out.AsFpuRegister<SRegister>(),
2788               first.AsFpuRegister<SRegister>(),
2789               second.AsFpuRegister<SRegister>());
2790      break;
2791    }
2792
2793    case Primitive::kPrimDouble: {
2794      __ vmuld(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2795               FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2796               FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
2797      break;
2798    }
2799
2800    default:
2801      LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
2802  }
2803}
2804
2805void InstructionCodeGeneratorARM::DivRemOneOrMinusOne(HBinaryOperation* instruction) {
2806  DCHECK(instruction->IsDiv() || instruction->IsRem());
2807  DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
2808
2809  LocationSummary* locations = instruction->GetLocations();
2810  Location second = locations->InAt(1);
2811  DCHECK(second.IsConstant());
2812
2813  Register out = locations->Out().AsRegister<Register>();
2814  Register dividend = locations->InAt(0).AsRegister<Register>();
2815  int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
2816  DCHECK(imm == 1 || imm == -1);
2817
2818  if (instruction->IsRem()) {
2819    __ LoadImmediate(out, 0);
2820  } else {
2821    if (imm == 1) {
2822      __ Mov(out, dividend);
2823    } else {
2824      __ rsb(out, dividend, ShifterOperand(0));
2825    }
2826  }
2827}
2828
2829void InstructionCodeGeneratorARM::DivRemByPowerOfTwo(HBinaryOperation* instruction) {
2830  DCHECK(instruction->IsDiv() || instruction->IsRem());
2831  DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
2832
2833  LocationSummary* locations = instruction->GetLocations();
2834  Location second = locations->InAt(1);
2835  DCHECK(second.IsConstant());
2836
2837  Register out = locations->Out().AsRegister<Register>();
2838  Register dividend = locations->InAt(0).AsRegister<Register>();
2839  Register temp = locations->GetTemp(0).AsRegister<Register>();
2840  int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
2841  uint32_t abs_imm = static_cast<uint32_t>(std::abs(imm));
2842  DCHECK(IsPowerOfTwo(abs_imm));
2843  int ctz_imm = CTZ(abs_imm);
2844
2845  if (ctz_imm == 1) {
2846    __ Lsr(temp, dividend, 32 - ctz_imm);
2847  } else {
2848    __ Asr(temp, dividend, 31);
2849    __ Lsr(temp, temp, 32 - ctz_imm);
2850  }
2851  __ add(out, temp, ShifterOperand(dividend));
2852
2853  if (instruction->IsDiv()) {
2854    __ Asr(out, out, ctz_imm);
2855    if (imm < 0) {
2856      __ rsb(out, out, ShifterOperand(0));
2857    }
2858  } else {
2859    __ ubfx(out, out, 0, ctz_imm);
2860    __ sub(out, out, ShifterOperand(temp));
2861  }
2862}
2863
2864void InstructionCodeGeneratorARM::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) {
2865  DCHECK(instruction->IsDiv() || instruction->IsRem());
2866  DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
2867
2868  LocationSummary* locations = instruction->GetLocations();
2869  Location second = locations->InAt(1);
2870  DCHECK(second.IsConstant());
2871
2872  Register out = locations->Out().AsRegister<Register>();
2873  Register dividend = locations->InAt(0).AsRegister<Register>();
2874  Register temp1 = locations->GetTemp(0).AsRegister<Register>();
2875  Register temp2 = locations->GetTemp(1).AsRegister<Register>();
2876  int64_t imm = second.GetConstant()->AsIntConstant()->GetValue();
2877
2878  int64_t magic;
2879  int shift;
2880  CalculateMagicAndShiftForDivRem(imm, false /* is_long */, &magic, &shift);
2881
2882  __ LoadImmediate(temp1, magic);
2883  __ smull(temp2, temp1, dividend, temp1);
2884
2885  if (imm > 0 && magic < 0) {
2886    __ add(temp1, temp1, ShifterOperand(dividend));
2887  } else if (imm < 0 && magic > 0) {
2888    __ sub(temp1, temp1, ShifterOperand(dividend));
2889  }
2890
2891  if (shift != 0) {
2892    __ Asr(temp1, temp1, shift);
2893  }
2894
2895  if (instruction->IsDiv()) {
2896    __ sub(out, temp1, ShifterOperand(temp1, ASR, 31));
2897  } else {
2898    __ sub(temp1, temp1, ShifterOperand(temp1, ASR, 31));
2899    // TODO: Strength reduction for mls.
2900    __ LoadImmediate(temp2, imm);
2901    __ mls(out, temp1, temp2, dividend);
2902  }
2903}
2904
2905void InstructionCodeGeneratorARM::GenerateDivRemConstantIntegral(HBinaryOperation* instruction) {
2906  DCHECK(instruction->IsDiv() || instruction->IsRem());
2907  DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
2908
2909  LocationSummary* locations = instruction->GetLocations();
2910  Location second = locations->InAt(1);
2911  DCHECK(second.IsConstant());
2912
2913  int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
2914  if (imm == 0) {
2915    // Do not generate anything. DivZeroCheck would prevent any code to be executed.
2916  } else if (imm == 1 || imm == -1) {
2917    DivRemOneOrMinusOne(instruction);
2918  } else if (IsPowerOfTwo(std::abs(imm))) {
2919    DivRemByPowerOfTwo(instruction);
2920  } else {
2921    DCHECK(imm <= -2 || imm >= 2);
2922    GenerateDivRemWithAnyConstant(instruction);
2923  }
2924}
2925
2926void LocationsBuilderARM::VisitDiv(HDiv* div) {
2927  LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
2928  if (div->GetResultType() == Primitive::kPrimLong) {
2929    // pLdiv runtime call.
2930    call_kind = LocationSummary::kCall;
2931  } else if (div->GetResultType() == Primitive::kPrimInt && div->InputAt(1)->IsConstant()) {
2932    // sdiv will be replaced by other instruction sequence.
2933  } else if (div->GetResultType() == Primitive::kPrimInt &&
2934             !codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
2935    // pIdivmod runtime call.
2936    call_kind = LocationSummary::kCall;
2937  }
2938
2939  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(div, call_kind);
2940
2941  switch (div->GetResultType()) {
2942    case Primitive::kPrimInt: {
2943      if (div->InputAt(1)->IsConstant()) {
2944        locations->SetInAt(0, Location::RequiresRegister());
2945        locations->SetInAt(1, Location::ConstantLocation(div->InputAt(1)->AsConstant()));
2946        locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2947        int32_t abs_imm = std::abs(div->InputAt(1)->AsIntConstant()->GetValue());
2948        if (abs_imm <= 1) {
2949          // No temp register required.
2950        } else {
2951          locations->AddTemp(Location::RequiresRegister());
2952          if (!IsPowerOfTwo(abs_imm)) {
2953            locations->AddTemp(Location::RequiresRegister());
2954          }
2955        }
2956      } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
2957        locations->SetInAt(0, Location::RequiresRegister());
2958        locations->SetInAt(1, Location::RequiresRegister());
2959        locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2960      } else {
2961        InvokeRuntimeCallingConvention calling_convention;
2962        locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2963        locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
2964        // Note: divrem will compute both the quotient and the remainder as the pair R0 and R1, but
2965        //       we only need the former.
2966        locations->SetOut(Location::RegisterLocation(R0));
2967      }
2968      break;
2969    }
2970    case Primitive::kPrimLong: {
2971      InvokeRuntimeCallingConvention calling_convention;
2972      locations->SetInAt(0, Location::RegisterPairLocation(
2973          calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
2974      locations->SetInAt(1, Location::RegisterPairLocation(
2975          calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
2976      locations->SetOut(Location::RegisterPairLocation(R0, R1));
2977      break;
2978    }
2979    case Primitive::kPrimFloat:
2980    case Primitive::kPrimDouble: {
2981      locations->SetInAt(0, Location::RequiresFpuRegister());
2982      locations->SetInAt(1, Location::RequiresFpuRegister());
2983      locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
2984      break;
2985    }
2986
2987    default:
2988      LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2989  }
2990}
2991
2992void InstructionCodeGeneratorARM::VisitDiv(HDiv* div) {
2993  LocationSummary* locations = div->GetLocations();
2994  Location out = locations->Out();
2995  Location first = locations->InAt(0);
2996  Location second = locations->InAt(1);
2997
2998  switch (div->GetResultType()) {
2999    case Primitive::kPrimInt: {
3000      if (second.IsConstant()) {
3001        GenerateDivRemConstantIntegral(div);
3002      } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
3003        __ sdiv(out.AsRegister<Register>(),
3004                first.AsRegister<Register>(),
3005                second.AsRegister<Register>());
3006      } else {
3007        InvokeRuntimeCallingConvention calling_convention;
3008        DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegister<Register>());
3009        DCHECK_EQ(calling_convention.GetRegisterAt(1), second.AsRegister<Register>());
3010        DCHECK_EQ(R0, out.AsRegister<Register>());
3011
3012        codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pIdivmod), div, div->GetDexPc(), nullptr);
3013        CheckEntrypointTypes<kQuickIdivmod, int32_t, int32_t, int32_t>();
3014      }
3015      break;
3016    }
3017
3018    case Primitive::kPrimLong: {
3019      InvokeRuntimeCallingConvention calling_convention;
3020      DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegisterPairLow<Register>());
3021      DCHECK_EQ(calling_convention.GetRegisterAt(1), first.AsRegisterPairHigh<Register>());
3022      DCHECK_EQ(calling_convention.GetRegisterAt(2), second.AsRegisterPairLow<Register>());
3023      DCHECK_EQ(calling_convention.GetRegisterAt(3), second.AsRegisterPairHigh<Register>());
3024      DCHECK_EQ(R0, out.AsRegisterPairLow<Register>());
3025      DCHECK_EQ(R1, out.AsRegisterPairHigh<Register>());
3026
3027      codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLdiv), div, div->GetDexPc(), nullptr);
3028      CheckEntrypointTypes<kQuickLdiv, int64_t, int64_t, int64_t>();
3029      break;
3030    }
3031
3032    case Primitive::kPrimFloat: {
3033      __ vdivs(out.AsFpuRegister<SRegister>(),
3034               first.AsFpuRegister<SRegister>(),
3035               second.AsFpuRegister<SRegister>());
3036      break;
3037    }
3038
3039    case Primitive::kPrimDouble: {
3040      __ vdivd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
3041               FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
3042               FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
3043      break;
3044    }
3045
3046    default:
3047      LOG(FATAL) << "Unexpected div type " << div->GetResultType();
3048  }
3049}
3050
3051void LocationsBuilderARM::VisitRem(HRem* rem) {
3052  Primitive::Type type = rem->GetResultType();
3053
3054  // Most remainders are implemented in the runtime.
3055  LocationSummary::CallKind call_kind = LocationSummary::kCall;
3056  if (rem->GetResultType() == Primitive::kPrimInt && rem->InputAt(1)->IsConstant()) {
3057    // sdiv will be replaced by other instruction sequence.
3058    call_kind = LocationSummary::kNoCall;
3059  } else if ((rem->GetResultType() == Primitive::kPrimInt)
3060             && codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
3061    // Have hardware divide instruction for int, do it with three instructions.
3062    call_kind = LocationSummary::kNoCall;
3063  }
3064
3065  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind);
3066
3067  switch (type) {
3068    case Primitive::kPrimInt: {
3069      if (rem->InputAt(1)->IsConstant()) {
3070        locations->SetInAt(0, Location::RequiresRegister());
3071        locations->SetInAt(1, Location::ConstantLocation(rem->InputAt(1)->AsConstant()));
3072        locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3073        int32_t abs_imm = std::abs(rem->InputAt(1)->AsIntConstant()->GetValue());
3074        if (abs_imm <= 1) {
3075          // No temp register required.
3076        } else {
3077          locations->AddTemp(Location::RequiresRegister());
3078          if (!IsPowerOfTwo(abs_imm)) {
3079            locations->AddTemp(Location::RequiresRegister());
3080          }
3081        }
3082      } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
3083        locations->SetInAt(0, Location::RequiresRegister());
3084        locations->SetInAt(1, Location::RequiresRegister());
3085        locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3086        locations->AddTemp(Location::RequiresRegister());
3087      } else {
3088        InvokeRuntimeCallingConvention calling_convention;
3089        locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3090        locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
3091        // Note: divrem will compute both the quotient and the remainder as the pair R0 and R1, but
3092        //       we only need the latter.
3093        locations->SetOut(Location::RegisterLocation(R1));
3094      }
3095      break;
3096    }
3097    case Primitive::kPrimLong: {
3098      InvokeRuntimeCallingConvention calling_convention;
3099      locations->SetInAt(0, Location::RegisterPairLocation(
3100          calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
3101      locations->SetInAt(1, Location::RegisterPairLocation(
3102          calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
3103      // The runtime helper puts the output in R2,R3.
3104      locations->SetOut(Location::RegisterPairLocation(R2, R3));
3105      break;
3106    }
3107    case Primitive::kPrimFloat: {
3108      InvokeRuntimeCallingConvention calling_convention;
3109      locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
3110      locations->SetInAt(1, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(1)));
3111      locations->SetOut(Location::FpuRegisterLocation(S0));
3112      break;
3113    }
3114
3115    case Primitive::kPrimDouble: {
3116      InvokeRuntimeCallingConvention calling_convention;
3117      locations->SetInAt(0, Location::FpuRegisterPairLocation(
3118          calling_convention.GetFpuRegisterAt(0), calling_convention.GetFpuRegisterAt(1)));
3119      locations->SetInAt(1, Location::FpuRegisterPairLocation(
3120          calling_convention.GetFpuRegisterAt(2), calling_convention.GetFpuRegisterAt(3)));
3121      locations->SetOut(Location::Location::FpuRegisterPairLocation(S0, S1));
3122      break;
3123    }
3124
3125    default:
3126      LOG(FATAL) << "Unexpected rem type " << type;
3127  }
3128}
3129
3130void InstructionCodeGeneratorARM::VisitRem(HRem* rem) {
3131  LocationSummary* locations = rem->GetLocations();
3132  Location out = locations->Out();
3133  Location first = locations->InAt(0);
3134  Location second = locations->InAt(1);
3135
3136  Primitive::Type type = rem->GetResultType();
3137  switch (type) {
3138    case Primitive::kPrimInt: {
3139        if (second.IsConstant()) {
3140          GenerateDivRemConstantIntegral(rem);
3141        } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
3142        Register reg1 = first.AsRegister<Register>();
3143        Register reg2 = second.AsRegister<Register>();
3144        Register temp = locations->GetTemp(0).AsRegister<Register>();
3145
3146        // temp = reg1 / reg2  (integer division)
3147        // dest = reg1 - temp * reg2
3148        __ sdiv(temp, reg1, reg2);
3149        __ mls(out.AsRegister<Register>(), temp, reg2, reg1);
3150      } else {
3151        InvokeRuntimeCallingConvention calling_convention;
3152        DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegister<Register>());
3153        DCHECK_EQ(calling_convention.GetRegisterAt(1), second.AsRegister<Register>());
3154        DCHECK_EQ(R1, out.AsRegister<Register>());
3155
3156        codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pIdivmod), rem, rem->GetDexPc(), nullptr);
3157        CheckEntrypointTypes<kQuickIdivmod, int32_t, int32_t, int32_t>();
3158      }
3159      break;
3160    }
3161
3162    case Primitive::kPrimLong: {
3163      codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLmod), rem, rem->GetDexPc(), nullptr);
3164        CheckEntrypointTypes<kQuickLmod, int64_t, int64_t, int64_t>();
3165      break;
3166    }
3167
3168    case Primitive::kPrimFloat: {
3169      codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pFmodf), rem, rem->GetDexPc(), nullptr);
3170      CheckEntrypointTypes<kQuickFmodf, float, float, float>();
3171      break;
3172    }
3173
3174    case Primitive::kPrimDouble: {
3175      codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pFmod), rem, rem->GetDexPc(), nullptr);
3176      CheckEntrypointTypes<kQuickFmod, double, double, double>();
3177      break;
3178    }
3179
3180    default:
3181      LOG(FATAL) << "Unexpected rem type " << type;
3182  }
3183}
3184
3185void LocationsBuilderARM::VisitDivZeroCheck(HDivZeroCheck* instruction) {
3186  LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
3187      ? LocationSummary::kCallOnSlowPath
3188      : LocationSummary::kNoCall;
3189  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
3190  locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
3191  if (instruction->HasUses()) {
3192    locations->SetOut(Location::SameAsFirstInput());
3193  }
3194}
3195
3196void InstructionCodeGeneratorARM::VisitDivZeroCheck(HDivZeroCheck* instruction) {
3197  SlowPathCode* slow_path = new (GetGraph()->GetArena()) DivZeroCheckSlowPathARM(instruction);
3198  codegen_->AddSlowPath(slow_path);
3199
3200  LocationSummary* locations = instruction->GetLocations();
3201  Location value = locations->InAt(0);
3202
3203  switch (instruction->GetType()) {
3204    case Primitive::kPrimByte:
3205    case Primitive::kPrimChar:
3206    case Primitive::kPrimShort:
3207    case Primitive::kPrimInt: {
3208      if (value.IsRegister()) {
3209        __ CompareAndBranchIfZero(value.AsRegister<Register>(), slow_path->GetEntryLabel());
3210      } else {
3211        DCHECK(value.IsConstant()) << value;
3212        if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
3213          __ b(slow_path->GetEntryLabel());
3214        }
3215      }
3216      break;
3217    }
3218    case Primitive::kPrimLong: {
3219      if (value.IsRegisterPair()) {
3220        __ orrs(IP,
3221                value.AsRegisterPairLow<Register>(),
3222                ShifterOperand(value.AsRegisterPairHigh<Register>()));
3223        __ b(slow_path->GetEntryLabel(), EQ);
3224      } else {
3225        DCHECK(value.IsConstant()) << value;
3226        if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
3227          __ b(slow_path->GetEntryLabel());
3228        }
3229      }
3230      break;
3231    default:
3232      LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
3233    }
3234  }
3235}
3236
3237void InstructionCodeGeneratorARM::HandleIntegerRotate(LocationSummary* locations) {
3238  Register in = locations->InAt(0).AsRegister<Register>();
3239  Location rhs = locations->InAt(1);
3240  Register out = locations->Out().AsRegister<Register>();
3241
3242  if (rhs.IsConstant()) {
3243    // Arm32 and Thumb2 assemblers require a rotation on the interval [1,31],
3244    // so map all rotations to a +ve. equivalent in that range.
3245    // (e.g. left *or* right by -2 bits == 30 bits in the same direction.)
3246    uint32_t rot = CodeGenerator::GetInt32ValueOf(rhs.GetConstant()) & 0x1F;
3247    if (rot) {
3248      // Rotate, mapping left rotations to right equivalents if necessary.
3249      // (e.g. left by 2 bits == right by 30.)
3250      __ Ror(out, in, rot);
3251    } else if (out != in) {
3252      __ Mov(out, in);
3253    }
3254  } else {
3255    __ Ror(out, in, rhs.AsRegister<Register>());
3256  }
3257}
3258
3259// Gain some speed by mapping all Long rotates onto equivalent pairs of Integer
3260// rotates by swapping input regs (effectively rotating by the first 32-bits of
3261// a larger rotation) or flipping direction (thus treating larger right/left
3262// rotations as sub-word sized rotations in the other direction) as appropriate.
3263void InstructionCodeGeneratorARM::HandleLongRotate(LocationSummary* locations) {
3264  Register in_reg_lo = locations->InAt(0).AsRegisterPairLow<Register>();
3265  Register in_reg_hi = locations->InAt(0).AsRegisterPairHigh<Register>();
3266  Location rhs = locations->InAt(1);
3267  Register out_reg_lo = locations->Out().AsRegisterPairLow<Register>();
3268  Register out_reg_hi = locations->Out().AsRegisterPairHigh<Register>();
3269
3270  if (rhs.IsConstant()) {
3271    uint64_t rot = CodeGenerator::GetInt64ValueOf(rhs.GetConstant());
3272    // Map all rotations to +ve. equivalents on the interval [0,63].
3273    rot &= kMaxLongShiftValue;
3274    // For rotates over a word in size, 'pre-rotate' by 32-bits to keep rotate
3275    // logic below to a simple pair of binary orr.
3276    // (e.g. 34 bits == in_reg swap + 2 bits right.)
3277    if (rot >= kArmBitsPerWord) {
3278      rot -= kArmBitsPerWord;
3279      std::swap(in_reg_hi, in_reg_lo);
3280    }
3281    // Rotate, or mov to out for zero or word size rotations.
3282    if (rot != 0u) {
3283      __ Lsr(out_reg_hi, in_reg_hi, rot);
3284      __ orr(out_reg_hi, out_reg_hi, ShifterOperand(in_reg_lo, arm::LSL, kArmBitsPerWord - rot));
3285      __ Lsr(out_reg_lo, in_reg_lo, rot);
3286      __ orr(out_reg_lo, out_reg_lo, ShifterOperand(in_reg_hi, arm::LSL, kArmBitsPerWord - rot));
3287    } else {
3288      __ Mov(out_reg_lo, in_reg_lo);
3289      __ Mov(out_reg_hi, in_reg_hi);
3290    }
3291  } else {
3292    Register shift_right = locations->GetTemp(0).AsRegister<Register>();
3293    Register shift_left = locations->GetTemp(1).AsRegister<Register>();
3294    Label end;
3295    Label shift_by_32_plus_shift_right;
3296
3297    __ and_(shift_right, rhs.AsRegister<Register>(), ShifterOperand(0x1F));
3298    __ Lsrs(shift_left, rhs.AsRegister<Register>(), 6);
3299    __ rsb(shift_left, shift_right, ShifterOperand(kArmBitsPerWord), AL, kCcKeep);
3300    __ b(&shift_by_32_plus_shift_right, CC);
3301
3302    // out_reg_hi = (reg_hi << shift_left) | (reg_lo >> shift_right).
3303    // out_reg_lo = (reg_lo << shift_left) | (reg_hi >> shift_right).
3304    __ Lsl(out_reg_hi, in_reg_hi, shift_left);
3305    __ Lsr(out_reg_lo, in_reg_lo, shift_right);
3306    __ add(out_reg_hi, out_reg_hi, ShifterOperand(out_reg_lo));
3307    __ Lsl(out_reg_lo, in_reg_lo, shift_left);
3308    __ Lsr(shift_left, in_reg_hi, shift_right);
3309    __ add(out_reg_lo, out_reg_lo, ShifterOperand(shift_left));
3310    __ b(&end);
3311
3312    __ Bind(&shift_by_32_plus_shift_right);  // Shift by 32+shift_right.
3313    // out_reg_hi = (reg_hi >> shift_right) | (reg_lo << shift_left).
3314    // out_reg_lo = (reg_lo >> shift_right) | (reg_hi << shift_left).
3315    __ Lsr(out_reg_hi, in_reg_hi, shift_right);
3316    __ Lsl(out_reg_lo, in_reg_lo, shift_left);
3317    __ add(out_reg_hi, out_reg_hi, ShifterOperand(out_reg_lo));
3318    __ Lsr(out_reg_lo, in_reg_lo, shift_right);
3319    __ Lsl(shift_right, in_reg_hi, shift_left);
3320    __ add(out_reg_lo, out_reg_lo, ShifterOperand(shift_right));
3321
3322    __ Bind(&end);
3323  }
3324}
3325void LocationsBuilderARM::HandleRotate(HRor* ror) {
3326  LocationSummary* locations =
3327      new (GetGraph()->GetArena()) LocationSummary(ror, LocationSummary::kNoCall);
3328  switch (ror->GetResultType()) {
3329    case Primitive::kPrimInt: {
3330      locations->SetInAt(0, Location::RequiresRegister());
3331      locations->SetInAt(1, Location::RegisterOrConstant(ror->InputAt(1)));
3332      locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3333      break;
3334    }
3335    case Primitive::kPrimLong: {
3336      locations->SetInAt(0, Location::RequiresRegister());
3337      if (ror->InputAt(1)->IsConstant()) {
3338        locations->SetInAt(1, Location::ConstantLocation(ror->InputAt(1)->AsConstant()));
3339      } else {
3340        locations->SetInAt(1, Location::RequiresRegister());
3341        locations->AddTemp(Location::RequiresRegister());
3342        locations->AddTemp(Location::RequiresRegister());
3343      }
3344      locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
3345      break;
3346    }
3347    default:
3348      LOG(FATAL) << "Unexpected operation type " << ror->GetResultType();
3349  }
3350}
3351
3352void InstructionCodeGeneratorARM::HandleRotate(HRor* ror) {
3353  LocationSummary* locations = ror->GetLocations();
3354  Primitive::Type type = ror->GetResultType();
3355  switch (type) {
3356    case Primitive::kPrimInt: {
3357      HandleIntegerRotate(locations);
3358      break;
3359    }
3360    case Primitive::kPrimLong: {
3361      HandleLongRotate(locations);
3362      break;
3363    }
3364    default:
3365      LOG(FATAL) << "Unexpected operation type " << type;
3366      UNREACHABLE();
3367  }
3368}
3369
3370void LocationsBuilderARM::VisitRor(HRor* op) {
3371  HandleRotate(op);
3372}
3373
3374void InstructionCodeGeneratorARM::VisitRor(HRor* op) {
3375  HandleRotate(op);
3376}
3377
3378void LocationsBuilderARM::HandleShift(HBinaryOperation* op) {
3379  DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
3380
3381  LocationSummary* locations =
3382      new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
3383
3384  switch (op->GetResultType()) {
3385    case Primitive::kPrimInt: {
3386      locations->SetInAt(0, Location::RequiresRegister());
3387      if (op->InputAt(1)->IsConstant()) {
3388        locations->SetInAt(1, Location::ConstantLocation(op->InputAt(1)->AsConstant()));
3389        locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3390      } else {
3391        locations->SetInAt(1, Location::RequiresRegister());
3392        // Make the output overlap, as it will be used to hold the masked
3393        // second input.
3394        locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
3395      }
3396      break;
3397    }
3398    case Primitive::kPrimLong: {
3399      locations->SetInAt(0, Location::RequiresRegister());
3400      if (op->InputAt(1)->IsConstant()) {
3401        locations->SetInAt(1, Location::ConstantLocation(op->InputAt(1)->AsConstant()));
3402        // For simplicity, use kOutputOverlap even though we only require that low registers
3403        // don't clash with high registers which the register allocator currently guarantees.
3404        locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
3405      } else {
3406        locations->SetInAt(1, Location::RequiresRegister());
3407        locations->AddTemp(Location::RequiresRegister());
3408        locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
3409      }
3410      break;
3411    }
3412    default:
3413      LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
3414  }
3415}
3416
3417void InstructionCodeGeneratorARM::HandleShift(HBinaryOperation* op) {
3418  DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
3419
3420  LocationSummary* locations = op->GetLocations();
3421  Location out = locations->Out();
3422  Location first = locations->InAt(0);
3423  Location second = locations->InAt(1);
3424
3425  Primitive::Type type = op->GetResultType();
3426  switch (type) {
3427    case Primitive::kPrimInt: {
3428      Register out_reg = out.AsRegister<Register>();
3429      Register first_reg = first.AsRegister<Register>();
3430      if (second.IsRegister()) {
3431        Register second_reg = second.AsRegister<Register>();
3432        // Arm doesn't mask the shift count so we need to do it ourselves.
3433        __ and_(out_reg, second_reg, ShifterOperand(kMaxIntShiftValue));
3434        if (op->IsShl()) {
3435          __ Lsl(out_reg, first_reg, out_reg);
3436        } else if (op->IsShr()) {
3437          __ Asr(out_reg, first_reg, out_reg);
3438        } else {
3439          __ Lsr(out_reg, first_reg, out_reg);
3440        }
3441      } else {
3442        int32_t cst = second.GetConstant()->AsIntConstant()->GetValue();
3443        uint32_t shift_value = static_cast<uint32_t>(cst & kMaxIntShiftValue);
3444        if (shift_value == 0) {  // arm does not support shifting with 0 immediate.
3445          __ Mov(out_reg, first_reg);
3446        } else if (op->IsShl()) {
3447          __ Lsl(out_reg, first_reg, shift_value);
3448        } else if (op->IsShr()) {
3449          __ Asr(out_reg, first_reg, shift_value);
3450        } else {
3451          __ Lsr(out_reg, first_reg, shift_value);
3452        }
3453      }
3454      break;
3455    }
3456    case Primitive::kPrimLong: {
3457      Register o_h = out.AsRegisterPairHigh<Register>();
3458      Register o_l = out.AsRegisterPairLow<Register>();
3459
3460      Register high = first.AsRegisterPairHigh<Register>();
3461      Register low = first.AsRegisterPairLow<Register>();
3462
3463      if (second.IsRegister()) {
3464        Register temp = locations->GetTemp(0).AsRegister<Register>();
3465
3466        Register second_reg = second.AsRegister<Register>();
3467
3468        if (op->IsShl()) {
3469          __ and_(o_l, second_reg, ShifterOperand(kMaxLongShiftValue));
3470          // Shift the high part
3471          __ Lsl(o_h, high, o_l);
3472          // Shift the low part and `or` what overflew on the high part
3473          __ rsb(temp, o_l, ShifterOperand(kArmBitsPerWord));
3474          __ Lsr(temp, low, temp);
3475          __ orr(o_h, o_h, ShifterOperand(temp));
3476          // If the shift is > 32 bits, override the high part
3477          __ subs(temp, o_l, ShifterOperand(kArmBitsPerWord));
3478          __ it(PL);
3479          __ Lsl(o_h, low, temp, PL);
3480          // Shift the low part
3481          __ Lsl(o_l, low, o_l);
3482        } else if (op->IsShr()) {
3483          __ and_(o_h, second_reg, ShifterOperand(kMaxLongShiftValue));
3484          // Shift the low part
3485          __ Lsr(o_l, low, o_h);
3486          // Shift the high part and `or` what underflew on the low part
3487          __ rsb(temp, o_h, ShifterOperand(kArmBitsPerWord));
3488          __ Lsl(temp, high, temp);
3489          __ orr(o_l, o_l, ShifterOperand(temp));
3490          // If the shift is > 32 bits, override the low part
3491          __ subs(temp, o_h, ShifterOperand(kArmBitsPerWord));
3492          __ it(PL);
3493          __ Asr(o_l, high, temp, PL);
3494          // Shift the high part
3495          __ Asr(o_h, high, o_h);
3496        } else {
3497          __ and_(o_h, second_reg, ShifterOperand(kMaxLongShiftValue));
3498          // same as Shr except we use `Lsr`s and not `Asr`s
3499          __ Lsr(o_l, low, o_h);
3500          __ rsb(temp, o_h, ShifterOperand(kArmBitsPerWord));
3501          __ Lsl(temp, high, temp);
3502          __ orr(o_l, o_l, ShifterOperand(temp));
3503          __ subs(temp, o_h, ShifterOperand(kArmBitsPerWord));
3504          __ it(PL);
3505          __ Lsr(o_l, high, temp, PL);
3506          __ Lsr(o_h, high, o_h);
3507        }
3508      } else {
3509        // Register allocator doesn't create partial overlap.
3510        DCHECK_NE(o_l, high);
3511        DCHECK_NE(o_h, low);
3512        int32_t cst = second.GetConstant()->AsIntConstant()->GetValue();
3513        uint32_t shift_value = static_cast<uint32_t>(cst & kMaxLongShiftValue);
3514        if (shift_value > 32) {
3515          if (op->IsShl()) {
3516            __ Lsl(o_h, low, shift_value - 32);
3517            __ LoadImmediate(o_l, 0);
3518          } else if (op->IsShr()) {
3519            __ Asr(o_l, high, shift_value - 32);
3520            __ Asr(o_h, high, 31);
3521          } else {
3522            __ Lsr(o_l, high, shift_value - 32);
3523            __ LoadImmediate(o_h, 0);
3524          }
3525        } else if (shift_value == 32) {
3526          if (op->IsShl()) {
3527            __ mov(o_h, ShifterOperand(low));
3528            __ LoadImmediate(o_l, 0);
3529          } else if (op->IsShr()) {
3530            __ mov(o_l, ShifterOperand(high));
3531            __ Asr(o_h, high, 31);
3532          } else {
3533            __ mov(o_l, ShifterOperand(high));
3534            __ LoadImmediate(o_h, 0);
3535          }
3536        } else if (shift_value == 1) {
3537          if (op->IsShl()) {
3538            __ Lsls(o_l, low, 1);
3539            __ adc(o_h, high, ShifterOperand(high));
3540          } else if (op->IsShr()) {
3541            __ Asrs(o_h, high, 1);
3542            __ Rrx(o_l, low);
3543          } else {
3544            __ Lsrs(o_h, high, 1);
3545            __ Rrx(o_l, low);
3546          }
3547        } else {
3548          DCHECK(2 <= shift_value && shift_value < 32) << shift_value;
3549          if (op->IsShl()) {
3550            __ Lsl(o_h, high, shift_value);
3551            __ orr(o_h, o_h, ShifterOperand(low, LSR, 32 - shift_value));
3552            __ Lsl(o_l, low, shift_value);
3553          } else if (op->IsShr()) {
3554            __ Lsr(o_l, low, shift_value);
3555            __ orr(o_l, o_l, ShifterOperand(high, LSL, 32 - shift_value));
3556            __ Asr(o_h, high, shift_value);
3557          } else {
3558            __ Lsr(o_l, low, shift_value);
3559            __ orr(o_l, o_l, ShifterOperand(high, LSL, 32 - shift_value));
3560            __ Lsr(o_h, high, shift_value);
3561          }
3562        }
3563      }
3564      break;
3565    }
3566    default:
3567      LOG(FATAL) << "Unexpected operation type " << type;
3568      UNREACHABLE();
3569  }
3570}
3571
3572void LocationsBuilderARM::VisitShl(HShl* shl) {
3573  HandleShift(shl);
3574}
3575
3576void InstructionCodeGeneratorARM::VisitShl(HShl* shl) {
3577  HandleShift(shl);
3578}
3579
3580void LocationsBuilderARM::VisitShr(HShr* shr) {
3581  HandleShift(shr);
3582}
3583
3584void InstructionCodeGeneratorARM::VisitShr(HShr* shr) {
3585  HandleShift(shr);
3586}
3587
3588void LocationsBuilderARM::VisitUShr(HUShr* ushr) {
3589  HandleShift(ushr);
3590}
3591
3592void InstructionCodeGeneratorARM::VisitUShr(HUShr* ushr) {
3593  HandleShift(ushr);
3594}
3595
3596void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) {
3597  LocationSummary* locations =
3598      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
3599  InvokeRuntimeCallingConvention calling_convention;
3600  locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3601  locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
3602  locations->SetOut(Location::RegisterLocation(R0));
3603}
3604
3605void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) {
3606  // Note: if heap poisoning is enabled, the entry point takes cares
3607  // of poisoning the reference.
3608  codegen_->InvokeRuntime(instruction->GetEntrypoint(),
3609                          instruction,
3610                          instruction->GetDexPc(),
3611                          nullptr);
3612  CheckEntrypointTypes<kQuickAllocObjectWithAccessCheck, void*, uint32_t, ArtMethod*>();
3613}
3614
3615void LocationsBuilderARM::VisitNewArray(HNewArray* instruction) {
3616  LocationSummary* locations =
3617      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
3618  InvokeRuntimeCallingConvention calling_convention;
3619  locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3620  locations->SetOut(Location::RegisterLocation(R0));
3621  locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
3622  locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
3623}
3624
3625void InstructionCodeGeneratorARM::VisitNewArray(HNewArray* instruction) {
3626  InvokeRuntimeCallingConvention calling_convention;
3627  __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
3628  // Note: if heap poisoning is enabled, the entry point takes cares
3629  // of poisoning the reference.
3630  codegen_->InvokeRuntime(instruction->GetEntrypoint(),
3631                          instruction,
3632                          instruction->GetDexPc(),
3633                          nullptr);
3634  CheckEntrypointTypes<kQuickAllocArrayWithAccessCheck, void*, uint32_t, int32_t, ArtMethod*>();
3635}
3636
3637void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) {
3638  LocationSummary* locations =
3639      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3640  Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
3641  if (location.IsStackSlot()) {
3642    location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
3643  } else if (location.IsDoubleStackSlot()) {
3644    location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
3645  }
3646  locations->SetOut(location);
3647}
3648
3649void InstructionCodeGeneratorARM::VisitParameterValue(
3650    HParameterValue* instruction ATTRIBUTE_UNUSED) {
3651  // Nothing to do, the parameter is already at its location.
3652}
3653
3654void LocationsBuilderARM::VisitCurrentMethod(HCurrentMethod* instruction) {
3655  LocationSummary* locations =
3656      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3657  locations->SetOut(Location::RegisterLocation(kMethodRegisterArgument));
3658}
3659
3660void InstructionCodeGeneratorARM::VisitCurrentMethod(HCurrentMethod* instruction ATTRIBUTE_UNUSED) {
3661  // Nothing to do, the method is already at its location.
3662}
3663
3664void LocationsBuilderARM::VisitNot(HNot* not_) {
3665  LocationSummary* locations =
3666      new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
3667  locations->SetInAt(0, Location::RequiresRegister());
3668  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3669}
3670
3671void InstructionCodeGeneratorARM::VisitNot(HNot* not_) {
3672  LocationSummary* locations = not_->GetLocations();
3673  Location out = locations->Out();
3674  Location in = locations->InAt(0);
3675  switch (not_->GetResultType()) {
3676    case Primitive::kPrimInt:
3677      __ mvn(out.AsRegister<Register>(), ShifterOperand(in.AsRegister<Register>()));
3678      break;
3679
3680    case Primitive::kPrimLong:
3681      __ mvn(out.AsRegisterPairLow<Register>(),
3682             ShifterOperand(in.AsRegisterPairLow<Register>()));
3683      __ mvn(out.AsRegisterPairHigh<Register>(),
3684             ShifterOperand(in.AsRegisterPairHigh<Register>()));
3685      break;
3686
3687    default:
3688      LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
3689  }
3690}
3691
3692void LocationsBuilderARM::VisitBooleanNot(HBooleanNot* bool_not) {
3693  LocationSummary* locations =
3694      new (GetGraph()->GetArena()) LocationSummary(bool_not, LocationSummary::kNoCall);
3695  locations->SetInAt(0, Location::RequiresRegister());
3696  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3697}
3698
3699void InstructionCodeGeneratorARM::VisitBooleanNot(HBooleanNot* bool_not) {
3700  LocationSummary* locations = bool_not->GetLocations();
3701  Location out = locations->Out();
3702  Location in = locations->InAt(0);
3703  __ eor(out.AsRegister<Register>(), in.AsRegister<Register>(), ShifterOperand(1));
3704}
3705
3706void LocationsBuilderARM::VisitCompare(HCompare* compare) {
3707  LocationSummary* locations =
3708      new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
3709  switch (compare->InputAt(0)->GetType()) {
3710    case Primitive::kPrimLong: {
3711      locations->SetInAt(0, Location::RequiresRegister());
3712      locations->SetInAt(1, Location::RequiresRegister());
3713      // Output overlaps because it is written before doing the low comparison.
3714      locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
3715      break;
3716    }
3717    case Primitive::kPrimFloat:
3718    case Primitive::kPrimDouble: {
3719      locations->SetInAt(0, Location::RequiresFpuRegister());
3720      locations->SetInAt(1, Location::RequiresFpuRegister());
3721      locations->SetOut(Location::RequiresRegister());
3722      break;
3723    }
3724    default:
3725      LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
3726  }
3727}
3728
3729void InstructionCodeGeneratorARM::VisitCompare(HCompare* compare) {
3730  LocationSummary* locations = compare->GetLocations();
3731  Register out = locations->Out().AsRegister<Register>();
3732  Location left = locations->InAt(0);
3733  Location right = locations->InAt(1);
3734
3735  Label less, greater, done;
3736  Primitive::Type type = compare->InputAt(0)->GetType();
3737  switch (type) {
3738    case Primitive::kPrimLong: {
3739      __ cmp(left.AsRegisterPairHigh<Register>(),
3740             ShifterOperand(right.AsRegisterPairHigh<Register>()));  // Signed compare.
3741      __ b(&less, LT);
3742      __ b(&greater, GT);
3743      // Do LoadImmediate before the last `cmp`, as LoadImmediate might affect the status flags.
3744      __ LoadImmediate(out, 0);
3745      __ cmp(left.AsRegisterPairLow<Register>(),
3746             ShifterOperand(right.AsRegisterPairLow<Register>()));  // Unsigned compare.
3747      break;
3748    }
3749    case Primitive::kPrimFloat:
3750    case Primitive::kPrimDouble: {
3751      __ LoadImmediate(out, 0);
3752      if (type == Primitive::kPrimFloat) {
3753        __ vcmps(left.AsFpuRegister<SRegister>(), right.AsFpuRegister<SRegister>());
3754      } else {
3755        __ vcmpd(FromLowSToD(left.AsFpuRegisterPairLow<SRegister>()),
3756                 FromLowSToD(right.AsFpuRegisterPairLow<SRegister>()));
3757      }
3758      __ vmstat();  // transfer FP status register to ARM APSR.
3759      __ b(compare->IsGtBias() ? &greater : &less, VS);  // VS for unordered.
3760      break;
3761    }
3762    default:
3763      LOG(FATAL) << "Unexpected compare type " << type;
3764  }
3765  __ b(&done, EQ);
3766  __ b(&less, LO);  // LO is for both: unsigned compare for longs and 'less than' for floats.
3767
3768  __ Bind(&greater);
3769  __ LoadImmediate(out, 1);
3770  __ b(&done);
3771
3772  __ Bind(&less);
3773  __ LoadImmediate(out, -1);
3774
3775  __ Bind(&done);
3776}
3777
3778void LocationsBuilderARM::VisitPhi(HPhi* instruction) {
3779  LocationSummary* locations =
3780      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3781  for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
3782    locations->SetInAt(i, Location::Any());
3783  }
3784  locations->SetOut(Location::Any());
3785}
3786
3787void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction ATTRIBUTE_UNUSED) {
3788  LOG(FATAL) << "Unreachable";
3789}
3790
3791void InstructionCodeGeneratorARM::GenerateMemoryBarrier(MemBarrierKind kind) {
3792  // TODO (ported from quick): revisit Arm barrier kinds
3793  DmbOptions flavor = DmbOptions::ISH;  // quiet c++ warnings
3794  switch (kind) {
3795    case MemBarrierKind::kAnyStore:
3796    case MemBarrierKind::kLoadAny:
3797    case MemBarrierKind::kAnyAny: {
3798      flavor = DmbOptions::ISH;
3799      break;
3800    }
3801    case MemBarrierKind::kStoreStore: {
3802      flavor = DmbOptions::ISHST;
3803      break;
3804    }
3805    default:
3806      LOG(FATAL) << "Unexpected memory barrier " << kind;
3807  }
3808  __ dmb(flavor);
3809}
3810
3811void InstructionCodeGeneratorARM::GenerateWideAtomicLoad(Register addr,
3812                                                         uint32_t offset,
3813                                                         Register out_lo,
3814                                                         Register out_hi) {
3815  if (offset != 0) {
3816    // Ensure `out_lo` is different from `addr`, so that loading
3817    // `offset` into `out_lo` does not clutter `addr`.
3818    DCHECK_NE(out_lo, addr);
3819    __ LoadImmediate(out_lo, offset);
3820    __ add(IP, addr, ShifterOperand(out_lo));
3821    addr = IP;
3822  }
3823  __ ldrexd(out_lo, out_hi, addr);
3824}
3825
3826void InstructionCodeGeneratorARM::GenerateWideAtomicStore(Register addr,
3827                                                          uint32_t offset,
3828                                                          Register value_lo,
3829                                                          Register value_hi,
3830                                                          Register temp1,
3831                                                          Register temp2,
3832                                                          HInstruction* instruction) {
3833  Label fail;
3834  if (offset != 0) {
3835    __ LoadImmediate(temp1, offset);
3836    __ add(IP, addr, ShifterOperand(temp1));
3837    addr = IP;
3838  }
3839  __ Bind(&fail);
3840  // We need a load followed by store. (The address used in a STREX instruction must
3841  // be the same as the address in the most recently executed LDREX instruction.)
3842  __ ldrexd(temp1, temp2, addr);
3843  codegen_->MaybeRecordImplicitNullCheck(instruction);
3844  __ strexd(temp1, value_lo, value_hi, addr);
3845  __ CompareAndBranchIfNonZero(temp1, &fail);
3846}
3847
3848void LocationsBuilderARM::HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info) {
3849  DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3850
3851  LocationSummary* locations =
3852      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3853  locations->SetInAt(0, Location::RequiresRegister());
3854
3855  Primitive::Type field_type = field_info.GetFieldType();
3856  if (Primitive::IsFloatingPointType(field_type)) {
3857    locations->SetInAt(1, Location::RequiresFpuRegister());
3858  } else {
3859    locations->SetInAt(1, Location::RequiresRegister());
3860  }
3861
3862  bool is_wide = field_type == Primitive::kPrimLong || field_type == Primitive::kPrimDouble;
3863  bool generate_volatile = field_info.IsVolatile()
3864      && is_wide
3865      && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
3866  bool needs_write_barrier =
3867      CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
3868  // Temporary registers for the write barrier.
3869  // TODO: consider renaming StoreNeedsWriteBarrier to StoreNeedsGCMark.
3870  if (needs_write_barrier) {
3871    locations->AddTemp(Location::RequiresRegister());  // Possibly used for reference poisoning too.
3872    locations->AddTemp(Location::RequiresRegister());
3873  } else if (generate_volatile) {
3874    // Arm encoding have some additional constraints for ldrexd/strexd:
3875    // - registers need to be consecutive
3876    // - the first register should be even but not R14.
3877    // We don't test for Arm yet, and the assertion makes sure that we revisit this if we ever
3878    // enable Arm encoding.
3879    DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
3880
3881    locations->AddTemp(Location::RequiresRegister());
3882    locations->AddTemp(Location::RequiresRegister());
3883    if (field_type == Primitive::kPrimDouble) {
3884      // For doubles we need two more registers to copy the value.
3885      locations->AddTemp(Location::RegisterLocation(R2));
3886      locations->AddTemp(Location::RegisterLocation(R3));
3887    }
3888  }
3889}
3890
3891void InstructionCodeGeneratorARM::HandleFieldSet(HInstruction* instruction,
3892                                                 const FieldInfo& field_info,
3893                                                 bool value_can_be_null) {
3894  DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3895
3896  LocationSummary* locations = instruction->GetLocations();
3897  Register base = locations->InAt(0).AsRegister<Register>();
3898  Location value = locations->InAt(1);
3899
3900  bool is_volatile = field_info.IsVolatile();
3901  bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
3902  Primitive::Type field_type = field_info.GetFieldType();
3903  uint32_t offset = field_info.GetFieldOffset().Uint32Value();
3904  bool needs_write_barrier =
3905      CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
3906
3907  if (is_volatile) {
3908    GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
3909  }
3910
3911  switch (field_type) {
3912    case Primitive::kPrimBoolean:
3913    case Primitive::kPrimByte: {
3914      __ StoreToOffset(kStoreByte, value.AsRegister<Register>(), base, offset);
3915      break;
3916    }
3917
3918    case Primitive::kPrimShort:
3919    case Primitive::kPrimChar: {
3920      __ StoreToOffset(kStoreHalfword, value.AsRegister<Register>(), base, offset);
3921      break;
3922    }
3923
3924    case Primitive::kPrimInt:
3925    case Primitive::kPrimNot: {
3926      if (kPoisonHeapReferences && needs_write_barrier) {
3927        // Note that in the case where `value` is a null reference,
3928        // we do not enter this block, as a null reference does not
3929        // need poisoning.
3930        DCHECK_EQ(field_type, Primitive::kPrimNot);
3931        Register temp = locations->GetTemp(0).AsRegister<Register>();
3932        __ Mov(temp, value.AsRegister<Register>());
3933        __ PoisonHeapReference(temp);
3934        __ StoreToOffset(kStoreWord, temp, base, offset);
3935      } else {
3936        __ StoreToOffset(kStoreWord, value.AsRegister<Register>(), base, offset);
3937      }
3938      break;
3939    }
3940
3941    case Primitive::kPrimLong: {
3942      if (is_volatile && !atomic_ldrd_strd) {
3943        GenerateWideAtomicStore(base, offset,
3944                                value.AsRegisterPairLow<Register>(),
3945                                value.AsRegisterPairHigh<Register>(),
3946                                locations->GetTemp(0).AsRegister<Register>(),
3947                                locations->GetTemp(1).AsRegister<Register>(),
3948                                instruction);
3949      } else {
3950        __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), base, offset);
3951        codegen_->MaybeRecordImplicitNullCheck(instruction);
3952      }
3953      break;
3954    }
3955
3956    case Primitive::kPrimFloat: {
3957      __ StoreSToOffset(value.AsFpuRegister<SRegister>(), base, offset);
3958      break;
3959    }
3960
3961    case Primitive::kPrimDouble: {
3962      DRegister value_reg = FromLowSToD(value.AsFpuRegisterPairLow<SRegister>());
3963      if (is_volatile && !atomic_ldrd_strd) {
3964        Register value_reg_lo = locations->GetTemp(0).AsRegister<Register>();
3965        Register value_reg_hi = locations->GetTemp(1).AsRegister<Register>();
3966
3967        __ vmovrrd(value_reg_lo, value_reg_hi, value_reg);
3968
3969        GenerateWideAtomicStore(base, offset,
3970                                value_reg_lo,
3971                                value_reg_hi,
3972                                locations->GetTemp(2).AsRegister<Register>(),
3973                                locations->GetTemp(3).AsRegister<Register>(),
3974                                instruction);
3975      } else {
3976        __ StoreDToOffset(value_reg, base, offset);
3977        codegen_->MaybeRecordImplicitNullCheck(instruction);
3978      }
3979      break;
3980    }
3981
3982    case Primitive::kPrimVoid:
3983      LOG(FATAL) << "Unreachable type " << field_type;
3984      UNREACHABLE();
3985  }
3986
3987  // Longs and doubles are handled in the switch.
3988  if (field_type != Primitive::kPrimLong && field_type != Primitive::kPrimDouble) {
3989    codegen_->MaybeRecordImplicitNullCheck(instruction);
3990  }
3991
3992  if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
3993    Register temp = locations->GetTemp(0).AsRegister<Register>();
3994    Register card = locations->GetTemp(1).AsRegister<Register>();
3995    codegen_->MarkGCCard(
3996        temp, card, base, value.AsRegister<Register>(), value_can_be_null);
3997  }
3998
3999  if (is_volatile) {
4000    GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
4001  }
4002}
4003
4004void LocationsBuilderARM::HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info) {
4005  DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
4006
4007  bool object_field_get_with_read_barrier =
4008      kEmitCompilerReadBarrier && (field_info.GetFieldType() == Primitive::kPrimNot);
4009  LocationSummary* locations =
4010      new (GetGraph()->GetArena()) LocationSummary(instruction,
4011                                                   object_field_get_with_read_barrier ?
4012                                                       LocationSummary::kCallOnSlowPath :
4013                                                       LocationSummary::kNoCall);
4014  locations->SetInAt(0, Location::RequiresRegister());
4015
4016  bool volatile_for_double = field_info.IsVolatile()
4017      && (field_info.GetFieldType() == Primitive::kPrimDouble)
4018      && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
4019  // The output overlaps in case of volatile long: we don't want the
4020  // code generated by GenerateWideAtomicLoad to overwrite the
4021  // object's location.  Likewise, in the case of an object field get
4022  // with read barriers enabled, we do not want the load to overwrite
4023  // the object's location, as we need it to emit the read barrier.
4024  bool overlap = (field_info.IsVolatile() && (field_info.GetFieldType() == Primitive::kPrimLong)) ||
4025      object_field_get_with_read_barrier;
4026
4027  if (Primitive::IsFloatingPointType(instruction->GetType())) {
4028    locations->SetOut(Location::RequiresFpuRegister());
4029  } else {
4030    locations->SetOut(Location::RequiresRegister(),
4031                      (overlap ? Location::kOutputOverlap : Location::kNoOutputOverlap));
4032  }
4033  if (volatile_for_double) {
4034    // Arm encoding have some additional constraints for ldrexd/strexd:
4035    // - registers need to be consecutive
4036    // - the first register should be even but not R14.
4037    // We don't test for Arm yet, and the assertion makes sure that we revisit this if we ever
4038    // enable Arm encoding.
4039    DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
4040    locations->AddTemp(Location::RequiresRegister());
4041    locations->AddTemp(Location::RequiresRegister());
4042  }
4043}
4044
4045Location LocationsBuilderARM::ArmEncodableConstantOrRegister(HInstruction* constant,
4046                                                             Opcode opcode) {
4047  DCHECK(!Primitive::IsFloatingPointType(constant->GetType()));
4048  if (constant->IsConstant() &&
4049      CanEncodeConstantAsImmediate(constant->AsConstant(), opcode)) {
4050    return Location::ConstantLocation(constant->AsConstant());
4051  }
4052  return Location::RequiresRegister();
4053}
4054
4055bool LocationsBuilderARM::CanEncodeConstantAsImmediate(HConstant* input_cst,
4056                                                       Opcode opcode) {
4057  uint64_t value = static_cast<uint64_t>(Int64FromConstant(input_cst));
4058  if (Primitive::Is64BitType(input_cst->GetType())) {
4059    return CanEncodeConstantAsImmediate(Low32Bits(value), opcode) &&
4060        CanEncodeConstantAsImmediate(High32Bits(value), opcode);
4061  } else {
4062    return CanEncodeConstantAsImmediate(Low32Bits(value), opcode);
4063  }
4064}
4065
4066bool LocationsBuilderARM::CanEncodeConstantAsImmediate(uint32_t value, Opcode opcode) {
4067  ShifterOperand so;
4068  ArmAssembler* assembler = codegen_->GetAssembler();
4069  if (assembler->ShifterOperandCanHold(kNoRegister, kNoRegister, opcode, value, &so)) {
4070    return true;
4071  }
4072  Opcode neg_opcode = kNoOperand;
4073  switch (opcode) {
4074    case AND:
4075      neg_opcode = BIC;
4076      break;
4077    case ORR:
4078      neg_opcode = ORN;
4079      break;
4080    default:
4081      return false;
4082  }
4083  return assembler->ShifterOperandCanHold(kNoRegister, kNoRegister, neg_opcode, ~value, &so);
4084}
4085
4086void InstructionCodeGeneratorARM::HandleFieldGet(HInstruction* instruction,
4087                                                 const FieldInfo& field_info) {
4088  DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
4089
4090  LocationSummary* locations = instruction->GetLocations();
4091  Location base_loc = locations->InAt(0);
4092  Register base = base_loc.AsRegister<Register>();
4093  Location out = locations->Out();
4094  bool is_volatile = field_info.IsVolatile();
4095  bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
4096  Primitive::Type field_type = field_info.GetFieldType();
4097  uint32_t offset = field_info.GetFieldOffset().Uint32Value();
4098
4099  switch (field_type) {
4100    case Primitive::kPrimBoolean: {
4101      __ LoadFromOffset(kLoadUnsignedByte, out.AsRegister<Register>(), base, offset);
4102      break;
4103    }
4104
4105    case Primitive::kPrimByte: {
4106      __ LoadFromOffset(kLoadSignedByte, out.AsRegister<Register>(), base, offset);
4107      break;
4108    }
4109
4110    case Primitive::kPrimShort: {
4111      __ LoadFromOffset(kLoadSignedHalfword, out.AsRegister<Register>(), base, offset);
4112      break;
4113    }
4114
4115    case Primitive::kPrimChar: {
4116      __ LoadFromOffset(kLoadUnsignedHalfword, out.AsRegister<Register>(), base, offset);
4117      break;
4118    }
4119
4120    case Primitive::kPrimInt:
4121    case Primitive::kPrimNot: {
4122      __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), base, offset);
4123      break;
4124    }
4125
4126    case Primitive::kPrimLong: {
4127      if (is_volatile && !atomic_ldrd_strd) {
4128        GenerateWideAtomicLoad(base, offset,
4129                               out.AsRegisterPairLow<Register>(),
4130                               out.AsRegisterPairHigh<Register>());
4131      } else {
4132        __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), base, offset);
4133      }
4134      break;
4135    }
4136
4137    case Primitive::kPrimFloat: {
4138      __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), base, offset);
4139      break;
4140    }
4141
4142    case Primitive::kPrimDouble: {
4143      DRegister out_reg = FromLowSToD(out.AsFpuRegisterPairLow<SRegister>());
4144      if (is_volatile && !atomic_ldrd_strd) {
4145        Register lo = locations->GetTemp(0).AsRegister<Register>();
4146        Register hi = locations->GetTemp(1).AsRegister<Register>();
4147        GenerateWideAtomicLoad(base, offset, lo, hi);
4148        codegen_->MaybeRecordImplicitNullCheck(instruction);
4149        __ vmovdrr(out_reg, lo, hi);
4150      } else {
4151        __ LoadDFromOffset(out_reg, base, offset);
4152        codegen_->MaybeRecordImplicitNullCheck(instruction);
4153      }
4154      break;
4155    }
4156
4157    case Primitive::kPrimVoid:
4158      LOG(FATAL) << "Unreachable type " << field_type;
4159      UNREACHABLE();
4160  }
4161
4162  // Doubles are handled in the switch.
4163  if (field_type != Primitive::kPrimDouble) {
4164    codegen_->MaybeRecordImplicitNullCheck(instruction);
4165  }
4166
4167  if (is_volatile) {
4168    GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
4169  }
4170
4171  if (field_type == Primitive::kPrimNot) {
4172    codegen_->MaybeGenerateReadBarrier(instruction, out, out, base_loc, offset);
4173  }
4174}
4175
4176void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
4177  HandleFieldSet(instruction, instruction->GetFieldInfo());
4178}
4179
4180void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
4181  HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
4182}
4183
4184void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
4185  HandleFieldGet(instruction, instruction->GetFieldInfo());
4186}
4187
4188void InstructionCodeGeneratorARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
4189  HandleFieldGet(instruction, instruction->GetFieldInfo());
4190}
4191
4192void LocationsBuilderARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
4193  HandleFieldGet(instruction, instruction->GetFieldInfo());
4194}
4195
4196void InstructionCodeGeneratorARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
4197  HandleFieldGet(instruction, instruction->GetFieldInfo());
4198}
4199
4200void LocationsBuilderARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
4201  HandleFieldSet(instruction, instruction->GetFieldInfo());
4202}
4203
4204void InstructionCodeGeneratorARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
4205  HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
4206}
4207
4208void LocationsBuilderARM::VisitUnresolvedInstanceFieldGet(
4209    HUnresolvedInstanceFieldGet* instruction) {
4210  FieldAccessCallingConventionARM calling_convention;
4211  codegen_->CreateUnresolvedFieldLocationSummary(
4212      instruction, instruction->GetFieldType(), calling_convention);
4213}
4214
4215void InstructionCodeGeneratorARM::VisitUnresolvedInstanceFieldGet(
4216    HUnresolvedInstanceFieldGet* instruction) {
4217  FieldAccessCallingConventionARM calling_convention;
4218  codegen_->GenerateUnresolvedFieldAccess(instruction,
4219                                          instruction->GetFieldType(),
4220                                          instruction->GetFieldIndex(),
4221                                          instruction->GetDexPc(),
4222                                          calling_convention);
4223}
4224
4225void LocationsBuilderARM::VisitUnresolvedInstanceFieldSet(
4226    HUnresolvedInstanceFieldSet* instruction) {
4227  FieldAccessCallingConventionARM calling_convention;
4228  codegen_->CreateUnresolvedFieldLocationSummary(
4229      instruction, instruction->GetFieldType(), calling_convention);
4230}
4231
4232void InstructionCodeGeneratorARM::VisitUnresolvedInstanceFieldSet(
4233    HUnresolvedInstanceFieldSet* instruction) {
4234  FieldAccessCallingConventionARM calling_convention;
4235  codegen_->GenerateUnresolvedFieldAccess(instruction,
4236                                          instruction->GetFieldType(),
4237                                          instruction->GetFieldIndex(),
4238                                          instruction->GetDexPc(),
4239                                          calling_convention);
4240}
4241
4242void LocationsBuilderARM::VisitUnresolvedStaticFieldGet(
4243    HUnresolvedStaticFieldGet* instruction) {
4244  FieldAccessCallingConventionARM calling_convention;
4245  codegen_->CreateUnresolvedFieldLocationSummary(
4246      instruction, instruction->GetFieldType(), calling_convention);
4247}
4248
4249void InstructionCodeGeneratorARM::VisitUnresolvedStaticFieldGet(
4250    HUnresolvedStaticFieldGet* instruction) {
4251  FieldAccessCallingConventionARM calling_convention;
4252  codegen_->GenerateUnresolvedFieldAccess(instruction,
4253                                          instruction->GetFieldType(),
4254                                          instruction->GetFieldIndex(),
4255                                          instruction->GetDexPc(),
4256                                          calling_convention);
4257}
4258
4259void LocationsBuilderARM::VisitUnresolvedStaticFieldSet(
4260    HUnresolvedStaticFieldSet* instruction) {
4261  FieldAccessCallingConventionARM calling_convention;
4262  codegen_->CreateUnresolvedFieldLocationSummary(
4263      instruction, instruction->GetFieldType(), calling_convention);
4264}
4265
4266void InstructionCodeGeneratorARM::VisitUnresolvedStaticFieldSet(
4267    HUnresolvedStaticFieldSet* instruction) {
4268  FieldAccessCallingConventionARM calling_convention;
4269  codegen_->GenerateUnresolvedFieldAccess(instruction,
4270                                          instruction->GetFieldType(),
4271                                          instruction->GetFieldIndex(),
4272                                          instruction->GetDexPc(),
4273                                          calling_convention);
4274}
4275
4276void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) {
4277  LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
4278      ? LocationSummary::kCallOnSlowPath
4279      : LocationSummary::kNoCall;
4280  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
4281  locations->SetInAt(0, Location::RequiresRegister());
4282  if (instruction->HasUses()) {
4283    locations->SetOut(Location::SameAsFirstInput());
4284  }
4285}
4286
4287void InstructionCodeGeneratorARM::GenerateImplicitNullCheck(HNullCheck* instruction) {
4288  if (codegen_->CanMoveNullCheckToUser(instruction)) {
4289    return;
4290  }
4291  Location obj = instruction->GetLocations()->InAt(0);
4292
4293  __ LoadFromOffset(kLoadWord, IP, obj.AsRegister<Register>(), 0);
4294  codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
4295}
4296
4297void InstructionCodeGeneratorARM::GenerateExplicitNullCheck(HNullCheck* instruction) {
4298  SlowPathCode* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction);
4299  codegen_->AddSlowPath(slow_path);
4300
4301  LocationSummary* locations = instruction->GetLocations();
4302  Location obj = locations->InAt(0);
4303
4304  __ CompareAndBranchIfZero(obj.AsRegister<Register>(), slow_path->GetEntryLabel());
4305}
4306
4307void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) {
4308  if (codegen_->IsImplicitNullCheckAllowed(instruction)) {
4309    GenerateImplicitNullCheck(instruction);
4310  } else {
4311    GenerateExplicitNullCheck(instruction);
4312  }
4313}
4314
4315void LocationsBuilderARM::VisitArrayGet(HArrayGet* instruction) {
4316  bool object_array_get_with_read_barrier =
4317      kEmitCompilerReadBarrier && (instruction->GetType() == Primitive::kPrimNot);
4318  LocationSummary* locations =
4319      new (GetGraph()->GetArena()) LocationSummary(instruction,
4320                                                   object_array_get_with_read_barrier ?
4321                                                       LocationSummary::kCallOnSlowPath :
4322                                                       LocationSummary::kNoCall);
4323  locations->SetInAt(0, Location::RequiresRegister());
4324  locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
4325  if (Primitive::IsFloatingPointType(instruction->GetType())) {
4326    locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
4327  } else {
4328    // The output overlaps in the case of an object array get with
4329    // read barriers enabled: we do not want the move to overwrite the
4330    // array's location, as we need it to emit the read barrier.
4331    locations->SetOut(
4332        Location::RequiresRegister(),
4333        object_array_get_with_read_barrier ? Location::kOutputOverlap : Location::kNoOutputOverlap);
4334  }
4335}
4336
4337void InstructionCodeGeneratorARM::VisitArrayGet(HArrayGet* instruction) {
4338  LocationSummary* locations = instruction->GetLocations();
4339  Location obj_loc = locations->InAt(0);
4340  Register obj = obj_loc.AsRegister<Register>();
4341  Location index = locations->InAt(1);
4342  Primitive::Type type = instruction->GetType();
4343
4344  switch (type) {
4345    case Primitive::kPrimBoolean: {
4346      uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
4347      Register out = locations->Out().AsRegister<Register>();
4348      if (index.IsConstant()) {
4349        size_t offset =
4350            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
4351        __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset);
4352      } else {
4353        __ add(IP, obj, ShifterOperand(index.AsRegister<Register>()));
4354        __ LoadFromOffset(kLoadUnsignedByte, out, IP, data_offset);
4355      }
4356      break;
4357    }
4358
4359    case Primitive::kPrimByte: {
4360      uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
4361      Register out = locations->Out().AsRegister<Register>();
4362      if (index.IsConstant()) {
4363        size_t offset =
4364            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
4365        __ LoadFromOffset(kLoadSignedByte, out, obj, offset);
4366      } else {
4367        __ add(IP, obj, ShifterOperand(index.AsRegister<Register>()));
4368        __ LoadFromOffset(kLoadSignedByte, out, IP, data_offset);
4369      }
4370      break;
4371    }
4372
4373    case Primitive::kPrimShort: {
4374      uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
4375      Register out = locations->Out().AsRegister<Register>();
4376      if (index.IsConstant()) {
4377        size_t offset =
4378            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
4379        __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset);
4380      } else {
4381        __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
4382        __ LoadFromOffset(kLoadSignedHalfword, out, IP, data_offset);
4383      }
4384      break;
4385    }
4386
4387    case Primitive::kPrimChar: {
4388      uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
4389      Register out = locations->Out().AsRegister<Register>();
4390      if (index.IsConstant()) {
4391        size_t offset =
4392            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
4393        __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset);
4394      } else {
4395        __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
4396        __ LoadFromOffset(kLoadUnsignedHalfword, out, IP, data_offset);
4397      }
4398      break;
4399    }
4400
4401    case Primitive::kPrimInt:
4402    case Primitive::kPrimNot: {
4403      static_assert(
4404          sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
4405          "art::mirror::HeapReference<mirror::Object> and int32_t have different sizes.");
4406      uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
4407      Register out = locations->Out().AsRegister<Register>();
4408      if (index.IsConstant()) {
4409        size_t offset =
4410            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4411        __ LoadFromOffset(kLoadWord, out, obj, offset);
4412      } else {
4413        __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
4414        __ LoadFromOffset(kLoadWord, out, IP, data_offset);
4415      }
4416      break;
4417    }
4418
4419    case Primitive::kPrimLong: {
4420      uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
4421      Location out = locations->Out();
4422      if (index.IsConstant()) {
4423        size_t offset =
4424            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
4425        __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), obj, offset);
4426      } else {
4427        __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
4428        __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), IP, data_offset);
4429      }
4430      break;
4431    }
4432
4433    case Primitive::kPrimFloat: {
4434      uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
4435      Location out = locations->Out();
4436      DCHECK(out.IsFpuRegister());
4437      if (index.IsConstant()) {
4438        size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4439        __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), obj, offset);
4440      } else {
4441        __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
4442        __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), IP, data_offset);
4443      }
4444      break;
4445    }
4446
4447    case Primitive::kPrimDouble: {
4448      uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
4449      Location out = locations->Out();
4450      DCHECK(out.IsFpuRegisterPair());
4451      if (index.IsConstant()) {
4452        size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
4453        __ LoadDFromOffset(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()), obj, offset);
4454      } else {
4455        __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
4456        __ LoadDFromOffset(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()), IP, data_offset);
4457      }
4458      break;
4459    }
4460
4461    case Primitive::kPrimVoid:
4462      LOG(FATAL) << "Unreachable type " << type;
4463      UNREACHABLE();
4464  }
4465  codegen_->MaybeRecordImplicitNullCheck(instruction);
4466
4467  if (type == Primitive::kPrimNot) {
4468    static_assert(
4469        sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
4470        "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
4471    uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
4472    Location out = locations->Out();
4473    if (index.IsConstant()) {
4474      uint32_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4475      codegen_->MaybeGenerateReadBarrier(instruction, out, out, obj_loc, offset);
4476    } else {
4477      codegen_->MaybeGenerateReadBarrier(instruction, out, out, obj_loc, data_offset, index);
4478    }
4479  }
4480}
4481
4482void LocationsBuilderARM::VisitArraySet(HArraySet* instruction) {
4483  Primitive::Type value_type = instruction->GetComponentType();
4484
4485  bool needs_write_barrier =
4486      CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
4487  bool may_need_runtime_call_for_type_check = instruction->NeedsTypeCheck();
4488  bool object_array_set_with_read_barrier =
4489      kEmitCompilerReadBarrier && (value_type == Primitive::kPrimNot);
4490
4491  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
4492      instruction,
4493      (may_need_runtime_call_for_type_check || object_array_set_with_read_barrier) ?
4494          LocationSummary::kCallOnSlowPath :
4495          LocationSummary::kNoCall);
4496
4497  locations->SetInAt(0, Location::RequiresRegister());
4498  locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
4499  if (Primitive::IsFloatingPointType(value_type)) {
4500    locations->SetInAt(2, Location::RequiresFpuRegister());
4501  } else {
4502    locations->SetInAt(2, Location::RequiresRegister());
4503  }
4504  if (needs_write_barrier) {
4505    // Temporary registers for the write barrier.
4506    locations->AddTemp(Location::RequiresRegister());  // Possibly used for ref. poisoning too.
4507    locations->AddTemp(Location::RequiresRegister());
4508  }
4509}
4510
4511void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) {
4512  LocationSummary* locations = instruction->GetLocations();
4513  Location array_loc = locations->InAt(0);
4514  Register array = array_loc.AsRegister<Register>();
4515  Location index = locations->InAt(1);
4516  Primitive::Type value_type = instruction->GetComponentType();
4517  bool may_need_runtime_call_for_type_check = instruction->NeedsTypeCheck();
4518  bool needs_write_barrier =
4519      CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
4520
4521  switch (value_type) {
4522    case Primitive::kPrimBoolean:
4523    case Primitive::kPrimByte: {
4524      uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
4525      Register value = locations->InAt(2).AsRegister<Register>();
4526      if (index.IsConstant()) {
4527        size_t offset =
4528            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
4529        __ StoreToOffset(kStoreByte, value, array, offset);
4530      } else {
4531        __ add(IP, array, ShifterOperand(index.AsRegister<Register>()));
4532        __ StoreToOffset(kStoreByte, value, IP, data_offset);
4533      }
4534      break;
4535    }
4536
4537    case Primitive::kPrimShort:
4538    case Primitive::kPrimChar: {
4539      uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
4540      Register value = locations->InAt(2).AsRegister<Register>();
4541      if (index.IsConstant()) {
4542        size_t offset =
4543            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
4544        __ StoreToOffset(kStoreHalfword, value, array, offset);
4545      } else {
4546        __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
4547        __ StoreToOffset(kStoreHalfword, value, IP, data_offset);
4548      }
4549      break;
4550    }
4551
4552    case Primitive::kPrimNot: {
4553      uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
4554      Location value_loc = locations->InAt(2);
4555      Register value = value_loc.AsRegister<Register>();
4556      Register source = value;
4557
4558      if (instruction->InputAt(2)->IsNullConstant()) {
4559        // Just setting null.
4560        if (index.IsConstant()) {
4561          size_t offset =
4562              (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4563          __ StoreToOffset(kStoreWord, source, array, offset);
4564        } else {
4565          DCHECK(index.IsRegister()) << index;
4566          __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
4567          __ StoreToOffset(kStoreWord, source, IP, data_offset);
4568        }
4569        DCHECK(!needs_write_barrier);
4570        DCHECK(!may_need_runtime_call_for_type_check);
4571        break;
4572      }
4573
4574      DCHECK(needs_write_barrier);
4575      Register temp1 = locations->GetTemp(0).AsRegister<Register>();
4576      Register temp2 = locations->GetTemp(1).AsRegister<Register>();
4577      uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
4578      uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
4579      uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
4580      Label done;
4581      SlowPathCode* slow_path = nullptr;
4582
4583      if (may_need_runtime_call_for_type_check) {
4584        slow_path = new (GetGraph()->GetArena()) ArraySetSlowPathARM(instruction);
4585        codegen_->AddSlowPath(slow_path);
4586        if (instruction->GetValueCanBeNull()) {
4587          Label non_zero;
4588          __ CompareAndBranchIfNonZero(value, &non_zero);
4589          if (index.IsConstant()) {
4590            size_t offset =
4591               (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4592            __ StoreToOffset(kStoreWord, value, array, offset);
4593          } else {
4594            DCHECK(index.IsRegister()) << index;
4595            __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
4596            __ StoreToOffset(kStoreWord, value, IP, data_offset);
4597          }
4598          codegen_->MaybeRecordImplicitNullCheck(instruction);
4599          __ b(&done);
4600          __ Bind(&non_zero);
4601        }
4602
4603        if (kEmitCompilerReadBarrier) {
4604          // When read barriers are enabled, the type checking
4605          // instrumentation requires two read barriers:
4606          //
4607          //   __ Mov(temp2, temp1);
4608          //   // /* HeapReference<Class> */ temp1 = temp1->component_type_
4609          //   __ LoadFromOffset(kLoadWord, temp1, temp1, component_offset);
4610          //   codegen_->GenerateReadBarrier(
4611          //       instruction, temp1_loc, temp1_loc, temp2_loc, component_offset);
4612          //
4613          //   // /* HeapReference<Class> */ temp2 = value->klass_
4614          //   __ LoadFromOffset(kLoadWord, temp2, value, class_offset);
4615          //   codegen_->GenerateReadBarrier(
4616          //       instruction, temp2_loc, temp2_loc, value_loc, class_offset, temp1_loc);
4617          //
4618          //   __ cmp(temp1, ShifterOperand(temp2));
4619          //
4620          // However, the second read barrier may trash `temp`, as it
4621          // is a temporary register, and as such would not be saved
4622          // along with live registers before calling the runtime (nor
4623          // restored afterwards).  So in this case, we bail out and
4624          // delegate the work to the array set slow path.
4625          //
4626          // TODO: Extend the register allocator to support a new
4627          // "(locally) live temp" location so as to avoid always
4628          // going into the slow path when read barriers are enabled.
4629          __ b(slow_path->GetEntryLabel());
4630        } else {
4631          // /* HeapReference<Class> */ temp1 = array->klass_
4632          __ LoadFromOffset(kLoadWord, temp1, array, class_offset);
4633          codegen_->MaybeRecordImplicitNullCheck(instruction);
4634          __ MaybeUnpoisonHeapReference(temp1);
4635
4636          // /* HeapReference<Class> */ temp1 = temp1->component_type_
4637          __ LoadFromOffset(kLoadWord, temp1, temp1, component_offset);
4638          // /* HeapReference<Class> */ temp2 = value->klass_
4639          __ LoadFromOffset(kLoadWord, temp2, value, class_offset);
4640          // If heap poisoning is enabled, no need to unpoison `temp1`
4641          // nor `temp2`, as we are comparing two poisoned references.
4642          __ cmp(temp1, ShifterOperand(temp2));
4643
4644          if (instruction->StaticTypeOfArrayIsObjectArray()) {
4645            Label do_put;
4646            __ b(&do_put, EQ);
4647            // If heap poisoning is enabled, the `temp1` reference has
4648            // not been unpoisoned yet; unpoison it now.
4649            __ MaybeUnpoisonHeapReference(temp1);
4650
4651            // /* HeapReference<Class> */ temp1 = temp1->super_class_
4652            __ LoadFromOffset(kLoadWord, temp1, temp1, super_offset);
4653            // If heap poisoning is enabled, no need to unpoison
4654            // `temp1`, as we are comparing against null below.
4655            __ CompareAndBranchIfNonZero(temp1, slow_path->GetEntryLabel());
4656            __ Bind(&do_put);
4657          } else {
4658            __ b(slow_path->GetEntryLabel(), NE);
4659          }
4660        }
4661      }
4662
4663      if (kPoisonHeapReferences) {
4664        // Note that in the case where `value` is a null reference,
4665        // we do not enter this block, as a null reference does not
4666        // need poisoning.
4667        DCHECK_EQ(value_type, Primitive::kPrimNot);
4668        __ Mov(temp1, value);
4669        __ PoisonHeapReference(temp1);
4670        source = temp1;
4671      }
4672
4673      if (index.IsConstant()) {
4674        size_t offset =
4675            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4676        __ StoreToOffset(kStoreWord, source, array, offset);
4677      } else {
4678        DCHECK(index.IsRegister()) << index;
4679        __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
4680        __ StoreToOffset(kStoreWord, source, IP, data_offset);
4681      }
4682
4683      if (!may_need_runtime_call_for_type_check) {
4684        codegen_->MaybeRecordImplicitNullCheck(instruction);
4685      }
4686
4687      codegen_->MarkGCCard(temp1, temp2, array, value, instruction->GetValueCanBeNull());
4688
4689      if (done.IsLinked()) {
4690        __ Bind(&done);
4691      }
4692
4693      if (slow_path != nullptr) {
4694        __ Bind(slow_path->GetExitLabel());
4695      }
4696
4697      break;
4698    }
4699
4700    case Primitive::kPrimInt: {
4701      uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
4702      Register value = locations->InAt(2).AsRegister<Register>();
4703      if (index.IsConstant()) {
4704        size_t offset =
4705            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4706        __ StoreToOffset(kStoreWord, value, array, offset);
4707      } else {
4708        DCHECK(index.IsRegister()) << index;
4709        __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
4710        __ StoreToOffset(kStoreWord, value, IP, data_offset);
4711      }
4712
4713      codegen_->MaybeRecordImplicitNullCheck(instruction);
4714      break;
4715    }
4716
4717    case Primitive::kPrimLong: {
4718      uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
4719      Location value = locations->InAt(2);
4720      if (index.IsConstant()) {
4721        size_t offset =
4722            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
4723        __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), array, offset);
4724      } else {
4725        __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
4726        __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), IP, data_offset);
4727      }
4728      break;
4729    }
4730
4731    case Primitive::kPrimFloat: {
4732      uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
4733      Location value = locations->InAt(2);
4734      DCHECK(value.IsFpuRegister());
4735      if (index.IsConstant()) {
4736        size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4737        __ StoreSToOffset(value.AsFpuRegister<SRegister>(), array, offset);
4738      } else {
4739        __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
4740        __ StoreSToOffset(value.AsFpuRegister<SRegister>(), IP, data_offset);
4741      }
4742      break;
4743    }
4744
4745    case Primitive::kPrimDouble: {
4746      uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
4747      Location value = locations->InAt(2);
4748      DCHECK(value.IsFpuRegisterPair());
4749      if (index.IsConstant()) {
4750        size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
4751        __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), array, offset);
4752      } else {
4753        __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
4754        __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), IP, data_offset);
4755      }
4756
4757      break;
4758    }
4759
4760    case Primitive::kPrimVoid:
4761      LOG(FATAL) << "Unreachable type " << value_type;
4762      UNREACHABLE();
4763  }
4764
4765  // Ints and objects are handled in the switch.
4766  if (value_type != Primitive::kPrimInt && value_type != Primitive::kPrimNot) {
4767    codegen_->MaybeRecordImplicitNullCheck(instruction);
4768  }
4769}
4770
4771void LocationsBuilderARM::VisitArrayLength(HArrayLength* instruction) {
4772  LocationSummary* locations =
4773      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
4774  locations->SetInAt(0, Location::RequiresRegister());
4775  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
4776}
4777
4778void InstructionCodeGeneratorARM::VisitArrayLength(HArrayLength* instruction) {
4779  LocationSummary* locations = instruction->GetLocations();
4780  uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
4781  Register obj = locations->InAt(0).AsRegister<Register>();
4782  Register out = locations->Out().AsRegister<Register>();
4783  __ LoadFromOffset(kLoadWord, out, obj, offset);
4784  codegen_->MaybeRecordImplicitNullCheck(instruction);
4785}
4786
4787void LocationsBuilderARM::VisitBoundsCheck(HBoundsCheck* instruction) {
4788  LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
4789      ? LocationSummary::kCallOnSlowPath
4790      : LocationSummary::kNoCall;
4791  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
4792  locations->SetInAt(0, Location::RequiresRegister());
4793  locations->SetInAt(1, Location::RequiresRegister());
4794  if (instruction->HasUses()) {
4795    locations->SetOut(Location::SameAsFirstInput());
4796  }
4797}
4798
4799void InstructionCodeGeneratorARM::VisitBoundsCheck(HBoundsCheck* instruction) {
4800  LocationSummary* locations = instruction->GetLocations();
4801  SlowPathCode* slow_path =
4802      new (GetGraph()->GetArena()) BoundsCheckSlowPathARM(instruction);
4803  codegen_->AddSlowPath(slow_path);
4804
4805  Register index = locations->InAt(0).AsRegister<Register>();
4806  Register length = locations->InAt(1).AsRegister<Register>();
4807
4808  __ cmp(index, ShifterOperand(length));
4809  __ b(slow_path->GetEntryLabel(), HS);
4810}
4811
4812void CodeGeneratorARM::MarkGCCard(Register temp,
4813                                  Register card,
4814                                  Register object,
4815                                  Register value,
4816                                  bool can_be_null) {
4817  Label is_null;
4818  if (can_be_null) {
4819    __ CompareAndBranchIfZero(value, &is_null);
4820  }
4821  __ LoadFromOffset(kLoadWord, card, TR, Thread::CardTableOffset<kArmWordSize>().Int32Value());
4822  __ Lsr(temp, object, gc::accounting::CardTable::kCardShift);
4823  __ strb(card, Address(card, temp));
4824  if (can_be_null) {
4825    __ Bind(&is_null);
4826  }
4827}
4828
4829void LocationsBuilderARM::VisitTemporary(HTemporary* temp) {
4830  temp->SetLocations(nullptr);
4831}
4832
4833void InstructionCodeGeneratorARM::VisitTemporary(HTemporary* temp ATTRIBUTE_UNUSED) {
4834  // Nothing to do, this is driven by the code generator.
4835}
4836
4837void LocationsBuilderARM::VisitParallelMove(HParallelMove* instruction ATTRIBUTE_UNUSED) {
4838  LOG(FATAL) << "Unreachable";
4839}
4840
4841void InstructionCodeGeneratorARM::VisitParallelMove(HParallelMove* instruction) {
4842  codegen_->GetMoveResolver()->EmitNativeCode(instruction);
4843}
4844
4845void LocationsBuilderARM::VisitSuspendCheck(HSuspendCheck* instruction) {
4846  new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
4847}
4848
4849void InstructionCodeGeneratorARM::VisitSuspendCheck(HSuspendCheck* instruction) {
4850  HBasicBlock* block = instruction->GetBlock();
4851  if (block->GetLoopInformation() != nullptr) {
4852    DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
4853    // The back edge will generate the suspend check.
4854    return;
4855  }
4856  if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
4857    // The goto will generate the suspend check.
4858    return;
4859  }
4860  GenerateSuspendCheck(instruction, nullptr);
4861}
4862
4863void InstructionCodeGeneratorARM::GenerateSuspendCheck(HSuspendCheck* instruction,
4864                                                       HBasicBlock* successor) {
4865  SuspendCheckSlowPathARM* slow_path =
4866      down_cast<SuspendCheckSlowPathARM*>(instruction->GetSlowPath());
4867  if (slow_path == nullptr) {
4868    slow_path = new (GetGraph()->GetArena()) SuspendCheckSlowPathARM(instruction, successor);
4869    instruction->SetSlowPath(slow_path);
4870    codegen_->AddSlowPath(slow_path);
4871    if (successor != nullptr) {
4872      DCHECK(successor->IsLoopHeader());
4873      codegen_->ClearSpillSlotsFromLoopPhisInStackMap(instruction);
4874    }
4875  } else {
4876    DCHECK_EQ(slow_path->GetSuccessor(), successor);
4877  }
4878
4879  __ LoadFromOffset(
4880      kLoadUnsignedHalfword, IP, TR, Thread::ThreadFlagsOffset<kArmWordSize>().Int32Value());
4881  if (successor == nullptr) {
4882    __ CompareAndBranchIfNonZero(IP, slow_path->GetEntryLabel());
4883    __ Bind(slow_path->GetReturnLabel());
4884  } else {
4885    __ CompareAndBranchIfZero(IP, codegen_->GetLabelOf(successor));
4886    __ b(slow_path->GetEntryLabel());
4887  }
4888}
4889
4890ArmAssembler* ParallelMoveResolverARM::GetAssembler() const {
4891  return codegen_->GetAssembler();
4892}
4893
4894void ParallelMoveResolverARM::EmitMove(size_t index) {
4895  MoveOperands* move = moves_[index];
4896  Location source = move->GetSource();
4897  Location destination = move->GetDestination();
4898
4899  if (source.IsRegister()) {
4900    if (destination.IsRegister()) {
4901      __ Mov(destination.AsRegister<Register>(), source.AsRegister<Register>());
4902    } else {
4903      DCHECK(destination.IsStackSlot());
4904      __ StoreToOffset(kStoreWord, source.AsRegister<Register>(),
4905                       SP, destination.GetStackIndex());
4906    }
4907  } else if (source.IsStackSlot()) {
4908    if (destination.IsRegister()) {
4909      __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(),
4910                        SP, source.GetStackIndex());
4911    } else if (destination.IsFpuRegister()) {
4912      __ LoadSFromOffset(destination.AsFpuRegister<SRegister>(), SP, source.GetStackIndex());
4913    } else {
4914      DCHECK(destination.IsStackSlot());
4915      __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
4916      __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4917    }
4918  } else if (source.IsFpuRegister()) {
4919    if (destination.IsFpuRegister()) {
4920      __ vmovs(destination.AsFpuRegister<SRegister>(), source.AsFpuRegister<SRegister>());
4921    } else {
4922      DCHECK(destination.IsStackSlot());
4923      __ StoreSToOffset(source.AsFpuRegister<SRegister>(), SP, destination.GetStackIndex());
4924    }
4925  } else if (source.IsDoubleStackSlot()) {
4926    if (destination.IsDoubleStackSlot()) {
4927      __ LoadDFromOffset(DTMP, SP, source.GetStackIndex());
4928      __ StoreDToOffset(DTMP, SP, destination.GetStackIndex());
4929    } else if (destination.IsRegisterPair()) {
4930      DCHECK(ExpectedPairLayout(destination));
4931      __ LoadFromOffset(
4932          kLoadWordPair, destination.AsRegisterPairLow<Register>(), SP, source.GetStackIndex());
4933    } else {
4934      DCHECK(destination.IsFpuRegisterPair()) << destination;
4935      __ LoadDFromOffset(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
4936                         SP,
4937                         source.GetStackIndex());
4938    }
4939  } else if (source.IsRegisterPair()) {
4940    if (destination.IsRegisterPair()) {
4941      __ Mov(destination.AsRegisterPairLow<Register>(), source.AsRegisterPairLow<Register>());
4942      __ Mov(destination.AsRegisterPairHigh<Register>(), source.AsRegisterPairHigh<Register>());
4943    } else {
4944      DCHECK(destination.IsDoubleStackSlot()) << destination;
4945      DCHECK(ExpectedPairLayout(source));
4946      __ StoreToOffset(
4947          kStoreWordPair, source.AsRegisterPairLow<Register>(), SP, destination.GetStackIndex());
4948    }
4949  } else if (source.IsFpuRegisterPair()) {
4950    if (destination.IsFpuRegisterPair()) {
4951      __ vmovd(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
4952               FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()));
4953    } else {
4954      DCHECK(destination.IsDoubleStackSlot()) << destination;
4955      __ StoreDToOffset(FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()),
4956                        SP,
4957                        destination.GetStackIndex());
4958    }
4959  } else {
4960    DCHECK(source.IsConstant()) << source;
4961    HConstant* constant = source.GetConstant();
4962    if (constant->IsIntConstant() || constant->IsNullConstant()) {
4963      int32_t value = CodeGenerator::GetInt32ValueOf(constant);
4964      if (destination.IsRegister()) {
4965        __ LoadImmediate(destination.AsRegister<Register>(), value);
4966      } else {
4967        DCHECK(destination.IsStackSlot());
4968        __ LoadImmediate(IP, value);
4969        __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4970      }
4971    } else if (constant->IsLongConstant()) {
4972      int64_t value = constant->AsLongConstant()->GetValue();
4973      if (destination.IsRegisterPair()) {
4974        __ LoadImmediate(destination.AsRegisterPairLow<Register>(), Low32Bits(value));
4975        __ LoadImmediate(destination.AsRegisterPairHigh<Register>(), High32Bits(value));
4976      } else {
4977        DCHECK(destination.IsDoubleStackSlot()) << destination;
4978        __ LoadImmediate(IP, Low32Bits(value));
4979        __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4980        __ LoadImmediate(IP, High32Bits(value));
4981        __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
4982      }
4983    } else if (constant->IsDoubleConstant()) {
4984      double value = constant->AsDoubleConstant()->GetValue();
4985      if (destination.IsFpuRegisterPair()) {
4986        __ LoadDImmediate(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()), value);
4987      } else {
4988        DCHECK(destination.IsDoubleStackSlot()) << destination;
4989        uint64_t int_value = bit_cast<uint64_t, double>(value);
4990        __ LoadImmediate(IP, Low32Bits(int_value));
4991        __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4992        __ LoadImmediate(IP, High32Bits(int_value));
4993        __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
4994      }
4995    } else {
4996      DCHECK(constant->IsFloatConstant()) << constant->DebugName();
4997      float value = constant->AsFloatConstant()->GetValue();
4998      if (destination.IsFpuRegister()) {
4999        __ LoadSImmediate(destination.AsFpuRegister<SRegister>(), value);
5000      } else {
5001        DCHECK(destination.IsStackSlot());
5002        __ LoadImmediate(IP, bit_cast<int32_t, float>(value));
5003        __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
5004      }
5005    }
5006  }
5007}
5008
5009void ParallelMoveResolverARM::Exchange(Register reg, int mem) {
5010  __ Mov(IP, reg);
5011  __ LoadFromOffset(kLoadWord, reg, SP, mem);
5012  __ StoreToOffset(kStoreWord, IP, SP, mem);
5013}
5014
5015void ParallelMoveResolverARM::Exchange(int mem1, int mem2) {
5016  ScratchRegisterScope ensure_scratch(this, IP, R0, codegen_->GetNumberOfCoreRegisters());
5017  int stack_offset = ensure_scratch.IsSpilled() ? kArmWordSize : 0;
5018  __ LoadFromOffset(kLoadWord, static_cast<Register>(ensure_scratch.GetRegister()),
5019                    SP, mem1 + stack_offset);
5020  __ LoadFromOffset(kLoadWord, IP, SP, mem2 + stack_offset);
5021  __ StoreToOffset(kStoreWord, static_cast<Register>(ensure_scratch.GetRegister()),
5022                   SP, mem2 + stack_offset);
5023  __ StoreToOffset(kStoreWord, IP, SP, mem1 + stack_offset);
5024}
5025
5026void ParallelMoveResolverARM::EmitSwap(size_t index) {
5027  MoveOperands* move = moves_[index];
5028  Location source = move->GetSource();
5029  Location destination = move->GetDestination();
5030
5031  if (source.IsRegister() && destination.IsRegister()) {
5032    DCHECK_NE(source.AsRegister<Register>(), IP);
5033    DCHECK_NE(destination.AsRegister<Register>(), IP);
5034    __ Mov(IP, source.AsRegister<Register>());
5035    __ Mov(source.AsRegister<Register>(), destination.AsRegister<Register>());
5036    __ Mov(destination.AsRegister<Register>(), IP);
5037  } else if (source.IsRegister() && destination.IsStackSlot()) {
5038    Exchange(source.AsRegister<Register>(), destination.GetStackIndex());
5039  } else if (source.IsStackSlot() && destination.IsRegister()) {
5040    Exchange(destination.AsRegister<Register>(), source.GetStackIndex());
5041  } else if (source.IsStackSlot() && destination.IsStackSlot()) {
5042    Exchange(source.GetStackIndex(), destination.GetStackIndex());
5043  } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
5044    __ vmovrs(IP, source.AsFpuRegister<SRegister>());
5045    __ vmovs(source.AsFpuRegister<SRegister>(), destination.AsFpuRegister<SRegister>());
5046    __ vmovsr(destination.AsFpuRegister<SRegister>(), IP);
5047  } else if (source.IsRegisterPair() && destination.IsRegisterPair()) {
5048    __ vmovdrr(DTMP, source.AsRegisterPairLow<Register>(), source.AsRegisterPairHigh<Register>());
5049    __ Mov(source.AsRegisterPairLow<Register>(), destination.AsRegisterPairLow<Register>());
5050    __ Mov(source.AsRegisterPairHigh<Register>(), destination.AsRegisterPairHigh<Register>());
5051    __ vmovrrd(destination.AsRegisterPairLow<Register>(),
5052               destination.AsRegisterPairHigh<Register>(),
5053               DTMP);
5054  } else if (source.IsRegisterPair() || destination.IsRegisterPair()) {
5055    Register low_reg = source.IsRegisterPair()
5056        ? source.AsRegisterPairLow<Register>()
5057        : destination.AsRegisterPairLow<Register>();
5058    int mem = source.IsRegisterPair()
5059        ? destination.GetStackIndex()
5060        : source.GetStackIndex();
5061    DCHECK(ExpectedPairLayout(source.IsRegisterPair() ? source : destination));
5062    __ vmovdrr(DTMP, low_reg, static_cast<Register>(low_reg + 1));
5063    __ LoadFromOffset(kLoadWordPair, low_reg, SP, mem);
5064    __ StoreDToOffset(DTMP, SP, mem);
5065  } else if (source.IsFpuRegisterPair() && destination.IsFpuRegisterPair()) {
5066    DRegister first = FromLowSToD(source.AsFpuRegisterPairLow<SRegister>());
5067    DRegister second = FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>());
5068    __ vmovd(DTMP, first);
5069    __ vmovd(first, second);
5070    __ vmovd(second, DTMP);
5071  } else if (source.IsFpuRegisterPair() || destination.IsFpuRegisterPair()) {
5072    DRegister reg = source.IsFpuRegisterPair()
5073        ? FromLowSToD(source.AsFpuRegisterPairLow<SRegister>())
5074        : FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>());
5075    int mem = source.IsFpuRegisterPair()
5076        ? destination.GetStackIndex()
5077        : source.GetStackIndex();
5078    __ vmovd(DTMP, reg);
5079    __ LoadDFromOffset(reg, SP, mem);
5080    __ StoreDToOffset(DTMP, SP, mem);
5081  } else if (source.IsFpuRegister() || destination.IsFpuRegister()) {
5082    SRegister reg = source.IsFpuRegister() ? source.AsFpuRegister<SRegister>()
5083                                           : destination.AsFpuRegister<SRegister>();
5084    int mem = source.IsFpuRegister()
5085        ? destination.GetStackIndex()
5086        : source.GetStackIndex();
5087
5088    __ vmovrs(IP, reg);
5089    __ LoadSFromOffset(reg, SP, mem);
5090    __ StoreToOffset(kStoreWord, IP, SP, mem);
5091  } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
5092    Exchange(source.GetStackIndex(), destination.GetStackIndex());
5093    Exchange(source.GetHighStackIndex(kArmWordSize), destination.GetHighStackIndex(kArmWordSize));
5094  } else {
5095    LOG(FATAL) << "Unimplemented" << source << " <-> " << destination;
5096  }
5097}
5098
5099void ParallelMoveResolverARM::SpillScratch(int reg) {
5100  __ Push(static_cast<Register>(reg));
5101}
5102
5103void ParallelMoveResolverARM::RestoreScratch(int reg) {
5104  __ Pop(static_cast<Register>(reg));
5105}
5106
5107void LocationsBuilderARM::VisitLoadClass(HLoadClass* cls) {
5108  InvokeRuntimeCallingConvention calling_convention;
5109  CodeGenerator::CreateLoadClassLocationSummary(
5110      cls,
5111      Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
5112      Location::RegisterLocation(R0),
5113      /* code_generator_supports_read_barrier */ true);
5114}
5115
5116void InstructionCodeGeneratorARM::VisitLoadClass(HLoadClass* cls) {
5117  LocationSummary* locations = cls->GetLocations();
5118  if (cls->NeedsAccessCheck()) {
5119    codegen_->MoveConstant(locations->GetTemp(0), cls->GetTypeIndex());
5120    codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pInitializeTypeAndVerifyAccess),
5121                            cls,
5122                            cls->GetDexPc(),
5123                            nullptr);
5124    CheckEntrypointTypes<kQuickInitializeTypeAndVerifyAccess, void*, uint32_t>();
5125    return;
5126  }
5127
5128  Location out_loc = locations->Out();
5129  Register out = out_loc.AsRegister<Register>();
5130  Register current_method = locations->InAt(0).AsRegister<Register>();
5131
5132  if (cls->IsReferrersClass()) {
5133    DCHECK(!cls->CanCallRuntime());
5134    DCHECK(!cls->MustGenerateClinitCheck());
5135    uint32_t declaring_class_offset = ArtMethod::DeclaringClassOffset().Int32Value();
5136    if (kEmitCompilerReadBarrier) {
5137      // /* GcRoot<mirror::Class>* */ out = &(current_method->declaring_class_)
5138      __ AddConstant(out, current_method, declaring_class_offset);
5139      // /* mirror::Class* */ out = out->Read()
5140      codegen_->GenerateReadBarrierForRoot(cls, out_loc, out_loc);
5141    } else {
5142      // /* GcRoot<mirror::Class> */ out = current_method->declaring_class_
5143      __ LoadFromOffset(kLoadWord, out, current_method, declaring_class_offset);
5144    }
5145  } else {
5146    // /* GcRoot<mirror::Class>[] */ out =
5147    //        current_method.ptr_sized_fields_->dex_cache_resolved_types_
5148    __ LoadFromOffset(kLoadWord,
5149                      out,
5150                      current_method,
5151                      ArtMethod::DexCacheResolvedTypesOffset(kArmPointerSize).Int32Value());
5152
5153    size_t cache_offset = CodeGenerator::GetCacheOffset(cls->GetTypeIndex());
5154    if (kEmitCompilerReadBarrier) {
5155      // /* GcRoot<mirror::Class>* */ out = &out[type_index]
5156      __ AddConstant(out, out, cache_offset);
5157      // /* mirror::Class* */ out = out->Read()
5158      codegen_->GenerateReadBarrierForRoot(cls, out_loc, out_loc);
5159    } else {
5160      // /* GcRoot<mirror::Class> */ out = out[type_index]
5161      __ LoadFromOffset(kLoadWord, out, out, cache_offset);
5162    }
5163
5164    if (!cls->IsInDexCache() || cls->MustGenerateClinitCheck()) {
5165      DCHECK(cls->CanCallRuntime());
5166      SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
5167          cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
5168      codegen_->AddSlowPath(slow_path);
5169      if (!cls->IsInDexCache()) {
5170        __ CompareAndBranchIfZero(out, slow_path->GetEntryLabel());
5171      }
5172      if (cls->MustGenerateClinitCheck()) {
5173        GenerateClassInitializationCheck(slow_path, out);
5174      } else {
5175        __ Bind(slow_path->GetExitLabel());
5176      }
5177    }
5178  }
5179}
5180
5181void LocationsBuilderARM::VisitClinitCheck(HClinitCheck* check) {
5182  LocationSummary* locations =
5183      new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
5184  locations->SetInAt(0, Location::RequiresRegister());
5185  if (check->HasUses()) {
5186    locations->SetOut(Location::SameAsFirstInput());
5187  }
5188}
5189
5190void InstructionCodeGeneratorARM::VisitClinitCheck(HClinitCheck* check) {
5191  // We assume the class is not null.
5192  SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
5193      check->GetLoadClass(), check, check->GetDexPc(), true);
5194  codegen_->AddSlowPath(slow_path);
5195  GenerateClassInitializationCheck(slow_path,
5196                                   check->GetLocations()->InAt(0).AsRegister<Register>());
5197}
5198
5199void InstructionCodeGeneratorARM::GenerateClassInitializationCheck(
5200    SlowPathCode* slow_path, Register class_reg) {
5201  __ LoadFromOffset(kLoadWord, IP, class_reg, mirror::Class::StatusOffset().Int32Value());
5202  __ cmp(IP, ShifterOperand(mirror::Class::kStatusInitialized));
5203  __ b(slow_path->GetEntryLabel(), LT);
5204  // Even if the initialized flag is set, we may be in a situation where caches are not synced
5205  // properly. Therefore, we do a memory fence.
5206  __ dmb(ISH);
5207  __ Bind(slow_path->GetExitLabel());
5208}
5209
5210void LocationsBuilderARM::VisitLoadString(HLoadString* load) {
5211  LocationSummary::CallKind call_kind = (!load->IsInDexCache() || kEmitCompilerReadBarrier)
5212      ? LocationSummary::kCallOnSlowPath
5213      : LocationSummary::kNoCall;
5214  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(load, call_kind);
5215  locations->SetInAt(0, Location::RequiresRegister());
5216  locations->SetOut(Location::RequiresRegister());
5217}
5218
5219void InstructionCodeGeneratorARM::VisitLoadString(HLoadString* load) {
5220  LocationSummary* locations = load->GetLocations();
5221  Location out_loc = locations->Out();
5222  Register out = out_loc.AsRegister<Register>();
5223  Register current_method = locations->InAt(0).AsRegister<Register>();
5224
5225  uint32_t declaring_class_offset = ArtMethod::DeclaringClassOffset().Int32Value();
5226  if (kEmitCompilerReadBarrier) {
5227    // /* GcRoot<mirror::Class>* */ out = &(current_method->declaring_class_)
5228    __ AddConstant(out, current_method, declaring_class_offset);
5229    // /* mirror::Class* */ out = out->Read()
5230    codegen_->GenerateReadBarrierForRoot(load, out_loc, out_loc);
5231  } else {
5232    // /* GcRoot<mirror::Class> */ out = current_method->declaring_class_
5233    __ LoadFromOffset(kLoadWord, out, current_method, declaring_class_offset);
5234  }
5235
5236  // /* GcRoot<mirror::String>[] */ out = out->dex_cache_strings_
5237  __ LoadFromOffset(kLoadWord, out, out, mirror::Class::DexCacheStringsOffset().Int32Value());
5238
5239  size_t cache_offset = CodeGenerator::GetCacheOffset(load->GetStringIndex());
5240  if (kEmitCompilerReadBarrier) {
5241    // /* GcRoot<mirror::String>* */ out = &out[string_index]
5242    __ AddConstant(out, out, cache_offset);
5243    // /* mirror::String* */ out = out->Read()
5244    codegen_->GenerateReadBarrierForRoot(load, out_loc, out_loc);
5245  } else {
5246    // /* GcRoot<mirror::String> */ out = out[string_index]
5247    __ LoadFromOffset(kLoadWord, out, out, cache_offset);
5248  }
5249
5250  if (!load->IsInDexCache()) {
5251    SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathARM(load);
5252    codegen_->AddSlowPath(slow_path);
5253    __ CompareAndBranchIfZero(out, slow_path->GetEntryLabel());
5254    __ Bind(slow_path->GetExitLabel());
5255  }
5256}
5257
5258static int32_t GetExceptionTlsOffset() {
5259  return Thread::ExceptionOffset<kArmWordSize>().Int32Value();
5260}
5261
5262void LocationsBuilderARM::VisitLoadException(HLoadException* load) {
5263  LocationSummary* locations =
5264      new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
5265  locations->SetOut(Location::RequiresRegister());
5266}
5267
5268void InstructionCodeGeneratorARM::VisitLoadException(HLoadException* load) {
5269  Register out = load->GetLocations()->Out().AsRegister<Register>();
5270  __ LoadFromOffset(kLoadWord, out, TR, GetExceptionTlsOffset());
5271}
5272
5273void LocationsBuilderARM::VisitClearException(HClearException* clear) {
5274  new (GetGraph()->GetArena()) LocationSummary(clear, LocationSummary::kNoCall);
5275}
5276
5277void InstructionCodeGeneratorARM::VisitClearException(HClearException* clear ATTRIBUTE_UNUSED) {
5278  __ LoadImmediate(IP, 0);
5279  __ StoreToOffset(kStoreWord, IP, TR, GetExceptionTlsOffset());
5280}
5281
5282void LocationsBuilderARM::VisitThrow(HThrow* instruction) {
5283  LocationSummary* locations =
5284      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
5285  InvokeRuntimeCallingConvention calling_convention;
5286  locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5287}
5288
5289void InstructionCodeGeneratorARM::VisitThrow(HThrow* instruction) {
5290  codegen_->InvokeRuntime(
5291      QUICK_ENTRY_POINT(pDeliverException), instruction, instruction->GetDexPc(), nullptr);
5292  CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>();
5293}
5294
5295void LocationsBuilderARM::VisitInstanceOf(HInstanceOf* instruction) {
5296  LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
5297  TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
5298  switch (type_check_kind) {
5299    case TypeCheckKind::kExactCheck:
5300    case TypeCheckKind::kAbstractClassCheck:
5301    case TypeCheckKind::kClassHierarchyCheck:
5302    case TypeCheckKind::kArrayObjectCheck:
5303      call_kind =
5304          kEmitCompilerReadBarrier ? LocationSummary::kCallOnSlowPath : LocationSummary::kNoCall;
5305      break;
5306    case TypeCheckKind::kArrayCheck:
5307    case TypeCheckKind::kUnresolvedCheck:
5308    case TypeCheckKind::kInterfaceCheck:
5309      call_kind = LocationSummary::kCallOnSlowPath;
5310      break;
5311  }
5312
5313  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
5314  locations->SetInAt(0, Location::RequiresRegister());
5315  locations->SetInAt(1, Location::RequiresRegister());
5316  // The "out" register is used as a temporary, so it overlaps with the inputs.
5317  // Note that TypeCheckSlowPathARM uses this register too.
5318  locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
5319  // When read barriers are enabled, we need a temporary register for
5320  // some cases.
5321  if (kEmitCompilerReadBarrier &&
5322      (type_check_kind == TypeCheckKind::kAbstractClassCheck ||
5323       type_check_kind == TypeCheckKind::kClassHierarchyCheck ||
5324       type_check_kind == TypeCheckKind::kArrayObjectCheck)) {
5325    locations->AddTemp(Location::RequiresRegister());
5326  }
5327}
5328
5329void InstructionCodeGeneratorARM::VisitInstanceOf(HInstanceOf* instruction) {
5330  LocationSummary* locations = instruction->GetLocations();
5331  Location obj_loc = locations->InAt(0);
5332  Register obj = obj_loc.AsRegister<Register>();
5333  Register cls = locations->InAt(1).AsRegister<Register>();
5334  Location out_loc = locations->Out();
5335  Register out = out_loc.AsRegister<Register>();
5336  uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
5337  uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
5338  uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
5339  uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
5340  Label done, zero;
5341  SlowPathCode* slow_path = nullptr;
5342
5343  // Return 0 if `obj` is null.
5344  // avoid null check if we know obj is not null.
5345  if (instruction->MustDoNullCheck()) {
5346    __ CompareAndBranchIfZero(obj, &zero);
5347  }
5348
5349  // /* HeapReference<Class> */ out = obj->klass_
5350  __ LoadFromOffset(kLoadWord, out, obj, class_offset);
5351  codegen_->MaybeGenerateReadBarrier(instruction, out_loc, out_loc, obj_loc, class_offset);
5352
5353  switch (instruction->GetTypeCheckKind()) {
5354    case TypeCheckKind::kExactCheck: {
5355      __ cmp(out, ShifterOperand(cls));
5356      // Classes must be equal for the instanceof to succeed.
5357      __ b(&zero, NE);
5358      __ LoadImmediate(out, 1);
5359      __ b(&done);
5360      break;
5361    }
5362
5363    case TypeCheckKind::kAbstractClassCheck: {
5364      // If the class is abstract, we eagerly fetch the super class of the
5365      // object to avoid doing a comparison we know will fail.
5366      Label loop;
5367      __ Bind(&loop);
5368      Location temp_loc = kEmitCompilerReadBarrier ? locations->GetTemp(0) : Location::NoLocation();
5369      if (kEmitCompilerReadBarrier) {
5370        // Save the value of `out` into `temp` before overwriting it
5371        // in the following move operation, as we will need it for the
5372        // read barrier below.
5373        Register temp = temp_loc.AsRegister<Register>();
5374        __ Mov(temp, out);
5375      }
5376      // /* HeapReference<Class> */ out = out->super_class_
5377      __ LoadFromOffset(kLoadWord, out, out, super_offset);
5378      codegen_->MaybeGenerateReadBarrier(instruction, out_loc, out_loc, temp_loc, super_offset);
5379      // If `out` is null, we use it for the result, and jump to `done`.
5380      __ CompareAndBranchIfZero(out, &done);
5381      __ cmp(out, ShifterOperand(cls));
5382      __ b(&loop, NE);
5383      __ LoadImmediate(out, 1);
5384      if (zero.IsLinked()) {
5385        __ b(&done);
5386      }
5387      break;
5388    }
5389
5390    case TypeCheckKind::kClassHierarchyCheck: {
5391      // Walk over the class hierarchy to find a match.
5392      Label loop, success;
5393      __ Bind(&loop);
5394      __ cmp(out, ShifterOperand(cls));
5395      __ b(&success, EQ);
5396      Location temp_loc = kEmitCompilerReadBarrier ? locations->GetTemp(0) : Location::NoLocation();
5397      if (kEmitCompilerReadBarrier) {
5398        // Save the value of `out` into `temp` before overwriting it
5399        // in the following move operation, as we will need it for the
5400        // read barrier below.
5401        Register temp = temp_loc.AsRegister<Register>();
5402        __ Mov(temp, out);
5403      }
5404      // /* HeapReference<Class> */ out = out->super_class_
5405      __ LoadFromOffset(kLoadWord, out, out, super_offset);
5406      codegen_->MaybeGenerateReadBarrier(instruction, out_loc, out_loc, temp_loc, super_offset);
5407      __ CompareAndBranchIfNonZero(out, &loop);
5408      // If `out` is null, we use it for the result, and jump to `done`.
5409      __ b(&done);
5410      __ Bind(&success);
5411      __ LoadImmediate(out, 1);
5412      if (zero.IsLinked()) {
5413        __ b(&done);
5414      }
5415      break;
5416    }
5417
5418    case TypeCheckKind::kArrayObjectCheck: {
5419      // Do an exact check.
5420      Label exact_check;
5421      __ cmp(out, ShifterOperand(cls));
5422      __ b(&exact_check, EQ);
5423      // Otherwise, we need to check that the object's class is a non-primitive array.
5424      Location temp_loc = kEmitCompilerReadBarrier ? locations->GetTemp(0) : Location::NoLocation();
5425      if (kEmitCompilerReadBarrier) {
5426        // Save the value of `out` into `temp` before overwriting it
5427        // in the following move operation, as we will need it for the
5428        // read barrier below.
5429        Register temp = temp_loc.AsRegister<Register>();
5430        __ Mov(temp, out);
5431      }
5432      // /* HeapReference<Class> */ out = out->component_type_
5433      __ LoadFromOffset(kLoadWord, out, out, component_offset);
5434      codegen_->MaybeGenerateReadBarrier(instruction, out_loc, out_loc, temp_loc, component_offset);
5435      // If `out` is null, we use it for the result, and jump to `done`.
5436      __ CompareAndBranchIfZero(out, &done);
5437      __ LoadFromOffset(kLoadUnsignedHalfword, out, out, primitive_offset);
5438      static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot");
5439      __ CompareAndBranchIfNonZero(out, &zero);
5440      __ Bind(&exact_check);
5441      __ LoadImmediate(out, 1);
5442      __ b(&done);
5443      break;
5444    }
5445
5446    case TypeCheckKind::kArrayCheck: {
5447      __ cmp(out, ShifterOperand(cls));
5448      DCHECK(locations->OnlyCallsOnSlowPath());
5449      slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(instruction,
5450                                                                    /* is_fatal */ false);
5451      codegen_->AddSlowPath(slow_path);
5452      __ b(slow_path->GetEntryLabel(), NE);
5453      __ LoadImmediate(out, 1);
5454      if (zero.IsLinked()) {
5455        __ b(&done);
5456      }
5457      break;
5458    }
5459
5460    case TypeCheckKind::kUnresolvedCheck:
5461    case TypeCheckKind::kInterfaceCheck: {
5462      // Note that we indeed only call on slow path, but we always go
5463      // into the slow path for the unresolved & interface check
5464      // cases.
5465      //
5466      // We cannot directly call the InstanceofNonTrivial runtime
5467      // entry point without resorting to a type checking slow path
5468      // here (i.e. by calling InvokeRuntime directly), as it would
5469      // require to assign fixed registers for the inputs of this
5470      // HInstanceOf instruction (following the runtime calling
5471      // convention), which might be cluttered by the potential first
5472      // read barrier emission at the beginning of this method.
5473      DCHECK(locations->OnlyCallsOnSlowPath());
5474      slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(instruction,
5475                                                                    /* is_fatal */ false);
5476      codegen_->AddSlowPath(slow_path);
5477      __ b(slow_path->GetEntryLabel());
5478      if (zero.IsLinked()) {
5479        __ b(&done);
5480      }
5481      break;
5482    }
5483  }
5484
5485  if (zero.IsLinked()) {
5486    __ Bind(&zero);
5487    __ LoadImmediate(out, 0);
5488  }
5489
5490  if (done.IsLinked()) {
5491    __ Bind(&done);
5492  }
5493
5494  if (slow_path != nullptr) {
5495    __ Bind(slow_path->GetExitLabel());
5496  }
5497}
5498
5499void LocationsBuilderARM::VisitCheckCast(HCheckCast* instruction) {
5500  LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
5501  bool throws_into_catch = instruction->CanThrowIntoCatchBlock();
5502
5503  TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
5504  switch (type_check_kind) {
5505    case TypeCheckKind::kExactCheck:
5506    case TypeCheckKind::kAbstractClassCheck:
5507    case TypeCheckKind::kClassHierarchyCheck:
5508    case TypeCheckKind::kArrayObjectCheck:
5509      call_kind = (throws_into_catch || kEmitCompilerReadBarrier) ?
5510          LocationSummary::kCallOnSlowPath :
5511          LocationSummary::kNoCall;  // In fact, call on a fatal (non-returning) slow path.
5512      break;
5513    case TypeCheckKind::kArrayCheck:
5514    case TypeCheckKind::kUnresolvedCheck:
5515    case TypeCheckKind::kInterfaceCheck:
5516      call_kind = LocationSummary::kCallOnSlowPath;
5517      break;
5518  }
5519
5520  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
5521  locations->SetInAt(0, Location::RequiresRegister());
5522  locations->SetInAt(1, Location::RequiresRegister());
5523  // Note that TypeCheckSlowPathARM uses this "temp" register too.
5524  locations->AddTemp(Location::RequiresRegister());
5525  // When read barriers are enabled, we need an additional temporary
5526  // register for some cases.
5527  if (kEmitCompilerReadBarrier &&
5528      (type_check_kind == TypeCheckKind::kAbstractClassCheck ||
5529       type_check_kind == TypeCheckKind::kClassHierarchyCheck ||
5530       type_check_kind == TypeCheckKind::kArrayObjectCheck)) {
5531    locations->AddTemp(Location::RequiresRegister());
5532  }
5533}
5534
5535void InstructionCodeGeneratorARM::VisitCheckCast(HCheckCast* instruction) {
5536  LocationSummary* locations = instruction->GetLocations();
5537  Location obj_loc = locations->InAt(0);
5538  Register obj = obj_loc.AsRegister<Register>();
5539  Register cls = locations->InAt(1).AsRegister<Register>();
5540  Location temp_loc = locations->GetTemp(0);
5541  Register temp = temp_loc.AsRegister<Register>();
5542  uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
5543  uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
5544  uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
5545  uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
5546
5547  TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
5548  bool is_type_check_slow_path_fatal =
5549      (type_check_kind == TypeCheckKind::kExactCheck ||
5550       type_check_kind == TypeCheckKind::kAbstractClassCheck ||
5551       type_check_kind == TypeCheckKind::kClassHierarchyCheck ||
5552       type_check_kind == TypeCheckKind::kArrayObjectCheck) &&
5553      !instruction->CanThrowIntoCatchBlock();
5554  SlowPathCode* type_check_slow_path =
5555      new (GetGraph()->GetArena()) TypeCheckSlowPathARM(instruction,
5556                                                        is_type_check_slow_path_fatal);
5557  codegen_->AddSlowPath(type_check_slow_path);
5558
5559  Label done;
5560  // Avoid null check if we know obj is not null.
5561  if (instruction->MustDoNullCheck()) {
5562    __ CompareAndBranchIfZero(obj, &done);
5563  }
5564
5565  // /* HeapReference<Class> */ temp = obj->klass_
5566  __ LoadFromOffset(kLoadWord, temp, obj, class_offset);
5567  codegen_->MaybeGenerateReadBarrier(instruction, temp_loc, temp_loc, obj_loc, class_offset);
5568
5569  switch (type_check_kind) {
5570    case TypeCheckKind::kExactCheck:
5571    case TypeCheckKind::kArrayCheck: {
5572      __ cmp(temp, ShifterOperand(cls));
5573      // Jump to slow path for throwing the exception or doing a
5574      // more involved array check.
5575      __ b(type_check_slow_path->GetEntryLabel(), NE);
5576      break;
5577    }
5578
5579    case TypeCheckKind::kAbstractClassCheck: {
5580      // If the class is abstract, we eagerly fetch the super class of the
5581      // object to avoid doing a comparison we know will fail.
5582      Label loop, compare_classes;
5583      __ Bind(&loop);
5584      Location temp2_loc =
5585          kEmitCompilerReadBarrier ? locations->GetTemp(1) : Location::NoLocation();
5586      if (kEmitCompilerReadBarrier) {
5587        // Save the value of `temp` into `temp2` before overwriting it
5588        // in the following move operation, as we will need it for the
5589        // read barrier below.
5590        Register temp2 = temp2_loc.AsRegister<Register>();
5591        __ Mov(temp2, temp);
5592      }
5593      // /* HeapReference<Class> */ temp = temp->super_class_
5594      __ LoadFromOffset(kLoadWord, temp, temp, super_offset);
5595      codegen_->MaybeGenerateReadBarrier(instruction, temp_loc, temp_loc, temp2_loc, super_offset);
5596
5597      // If the class reference currently in `temp` is not null, jump
5598      // to the `compare_classes` label to compare it with the checked
5599      // class.
5600      __ CompareAndBranchIfNonZero(temp, &compare_classes);
5601      // Otherwise, jump to the slow path to throw the exception.
5602      //
5603      // But before, move back the object's class into `temp` before
5604      // going into the slow path, as it has been overwritten in the
5605      // meantime.
5606      // /* HeapReference<Class> */ temp = obj->klass_
5607      __ LoadFromOffset(kLoadWord, temp, obj, class_offset);
5608      codegen_->MaybeGenerateReadBarrier(instruction, temp_loc, temp_loc, obj_loc, class_offset);
5609      __ b(type_check_slow_path->GetEntryLabel());
5610
5611      __ Bind(&compare_classes);
5612      __ cmp(temp, ShifterOperand(cls));
5613      __ b(&loop, NE);
5614      break;
5615    }
5616
5617    case TypeCheckKind::kClassHierarchyCheck: {
5618      // Walk over the class hierarchy to find a match.
5619      Label loop;
5620      __ Bind(&loop);
5621      __ cmp(temp, ShifterOperand(cls));
5622      __ b(&done, EQ);
5623
5624      Location temp2_loc =
5625          kEmitCompilerReadBarrier ? locations->GetTemp(1) : Location::NoLocation();
5626      if (kEmitCompilerReadBarrier) {
5627        // Save the value of `temp` into `temp2` before overwriting it
5628        // in the following move operation, as we will need it for the
5629        // read barrier below.
5630        Register temp2 = temp2_loc.AsRegister<Register>();
5631        __ Mov(temp2, temp);
5632      }
5633      // /* HeapReference<Class> */ temp = temp->super_class_
5634      __ LoadFromOffset(kLoadWord, temp, temp, super_offset);
5635      codegen_->MaybeGenerateReadBarrier(instruction, temp_loc, temp_loc, temp2_loc, super_offset);
5636
5637      // If the class reference currently in `temp` is not null, jump
5638      // back at the beginning of the loop.
5639      __ CompareAndBranchIfNonZero(temp, &loop);
5640      // Otherwise, jump to the slow path to throw the exception.
5641      //
5642      // But before, move back the object's class into `temp` before
5643      // going into the slow path, as it has been overwritten in the
5644      // meantime.
5645      // /* HeapReference<Class> */ temp = obj->klass_
5646      __ LoadFromOffset(kLoadWord, temp, obj, class_offset);
5647      codegen_->MaybeGenerateReadBarrier(instruction, temp_loc, temp_loc, obj_loc, class_offset);
5648      __ b(type_check_slow_path->GetEntryLabel());
5649      break;
5650    }
5651
5652    case TypeCheckKind::kArrayObjectCheck: {
5653      // Do an exact check.
5654      Label check_non_primitive_component_type;
5655      __ cmp(temp, ShifterOperand(cls));
5656      __ b(&done, EQ);
5657
5658      // Otherwise, we need to check that the object's class is a non-primitive array.
5659      Location temp2_loc =
5660          kEmitCompilerReadBarrier ? locations->GetTemp(1) : Location::NoLocation();
5661      if (kEmitCompilerReadBarrier) {
5662        // Save the value of `temp` into `temp2` before overwriting it
5663        // in the following move operation, as we will need it for the
5664        // read barrier below.
5665        Register temp2 = temp2_loc.AsRegister<Register>();
5666        __ Mov(temp2, temp);
5667      }
5668      // /* HeapReference<Class> */ temp = temp->component_type_
5669      __ LoadFromOffset(kLoadWord, temp, temp, component_offset);
5670      codegen_->MaybeGenerateReadBarrier(
5671          instruction, temp_loc, temp_loc, temp2_loc, component_offset);
5672
5673      // If the component type is not null (i.e. the object is indeed
5674      // an array), jump to label `check_non_primitive_component_type`
5675      // to further check that this component type is not a primitive
5676      // type.
5677      __ CompareAndBranchIfNonZero(temp, &check_non_primitive_component_type);
5678      // Otherwise, jump to the slow path to throw the exception.
5679      //
5680      // But before, move back the object's class into `temp` before
5681      // going into the slow path, as it has been overwritten in the
5682      // meantime.
5683      // /* HeapReference<Class> */ temp = obj->klass_
5684      __ LoadFromOffset(kLoadWord, temp, obj, class_offset);
5685      codegen_->MaybeGenerateReadBarrier(instruction, temp_loc, temp_loc, obj_loc, class_offset);
5686      __ b(type_check_slow_path->GetEntryLabel());
5687
5688      __ Bind(&check_non_primitive_component_type);
5689      __ LoadFromOffset(kLoadUnsignedHalfword, temp, temp, primitive_offset);
5690      static_assert(Primitive::kPrimNot == 0, "Expected 0 for art::Primitive::kPrimNot");
5691      __ CompareAndBranchIfZero(temp, &done);
5692      // Same comment as above regarding `temp` and the slow path.
5693      // /* HeapReference<Class> */ temp = obj->klass_
5694      __ LoadFromOffset(kLoadWord, temp, obj, class_offset);
5695      codegen_->MaybeGenerateReadBarrier(instruction, temp_loc, temp_loc, obj_loc, class_offset);
5696      __ b(type_check_slow_path->GetEntryLabel());
5697      break;
5698    }
5699
5700    case TypeCheckKind::kUnresolvedCheck:
5701    case TypeCheckKind::kInterfaceCheck:
5702      // We always go into the type check slow path for the unresolved &
5703      // interface check cases.
5704      //
5705      // We cannot directly call the CheckCast runtime entry point
5706      // without resorting to a type checking slow path here (i.e. by
5707      // calling InvokeRuntime directly), as it would require to
5708      // assign fixed registers for the inputs of this HInstanceOf
5709      // instruction (following the runtime calling convention), which
5710      // might be cluttered by the potential first read barrier
5711      // emission at the beginning of this method.
5712      __ b(type_check_slow_path->GetEntryLabel());
5713      break;
5714  }
5715  __ Bind(&done);
5716
5717  __ Bind(type_check_slow_path->GetExitLabel());
5718}
5719
5720void LocationsBuilderARM::VisitMonitorOperation(HMonitorOperation* instruction) {
5721  LocationSummary* locations =
5722      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
5723  InvokeRuntimeCallingConvention calling_convention;
5724  locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5725}
5726
5727void InstructionCodeGeneratorARM::VisitMonitorOperation(HMonitorOperation* instruction) {
5728  codegen_->InvokeRuntime(instruction->IsEnter()
5729        ? QUICK_ENTRY_POINT(pLockObject) : QUICK_ENTRY_POINT(pUnlockObject),
5730      instruction,
5731      instruction->GetDexPc(),
5732      nullptr);
5733  if (instruction->IsEnter()) {
5734    CheckEntrypointTypes<kQuickLockObject, void, mirror::Object*>();
5735  } else {
5736    CheckEntrypointTypes<kQuickUnlockObject, void, mirror::Object*>();
5737  }
5738}
5739
5740void LocationsBuilderARM::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction, AND); }
5741void LocationsBuilderARM::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction, ORR); }
5742void LocationsBuilderARM::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction, EOR); }
5743
5744void LocationsBuilderARM::HandleBitwiseOperation(HBinaryOperation* instruction, Opcode opcode) {
5745  LocationSummary* locations =
5746      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
5747  DCHECK(instruction->GetResultType() == Primitive::kPrimInt
5748         || instruction->GetResultType() == Primitive::kPrimLong);
5749  // Note: GVN reorders commutative operations to have the constant on the right hand side.
5750  locations->SetInAt(0, Location::RequiresRegister());
5751  locations->SetInAt(1, ArmEncodableConstantOrRegister(instruction->InputAt(1), opcode));
5752  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
5753}
5754
5755void InstructionCodeGeneratorARM::VisitAnd(HAnd* instruction) {
5756  HandleBitwiseOperation(instruction);
5757}
5758
5759void InstructionCodeGeneratorARM::VisitOr(HOr* instruction) {
5760  HandleBitwiseOperation(instruction);
5761}
5762
5763void InstructionCodeGeneratorARM::VisitXor(HXor* instruction) {
5764  HandleBitwiseOperation(instruction);
5765}
5766
5767void InstructionCodeGeneratorARM::GenerateAndConst(Register out, Register first, uint32_t value) {
5768  // Optimize special cases for individual halfs of `and-long` (`and` is simplified earlier).
5769  if (value == 0xffffffffu) {
5770    if (out != first) {
5771      __ mov(out, ShifterOperand(first));
5772    }
5773    return;
5774  }
5775  if (value == 0u) {
5776    __ mov(out, ShifterOperand(0));
5777    return;
5778  }
5779  ShifterOperand so;
5780  if (__ ShifterOperandCanHold(kNoRegister, kNoRegister, AND, value, &so)) {
5781    __ and_(out, first, so);
5782  } else {
5783    DCHECK(__ ShifterOperandCanHold(kNoRegister, kNoRegister, BIC, ~value, &so));
5784    __ bic(out, first, ShifterOperand(~value));
5785  }
5786}
5787
5788void InstructionCodeGeneratorARM::GenerateOrrConst(Register out, Register first, uint32_t value) {
5789  // Optimize special cases for individual halfs of `or-long` (`or` is simplified earlier).
5790  if (value == 0u) {
5791    if (out != first) {
5792      __ mov(out, ShifterOperand(first));
5793    }
5794    return;
5795  }
5796  if (value == 0xffffffffu) {
5797    __ mvn(out, ShifterOperand(0));
5798    return;
5799  }
5800  ShifterOperand so;
5801  if (__ ShifterOperandCanHold(kNoRegister, kNoRegister, ORR, value, &so)) {
5802    __ orr(out, first, so);
5803  } else {
5804    DCHECK(__ ShifterOperandCanHold(kNoRegister, kNoRegister, ORN, ~value, &so));
5805    __ orn(out, first, ShifterOperand(~value));
5806  }
5807}
5808
5809void InstructionCodeGeneratorARM::GenerateEorConst(Register out, Register first, uint32_t value) {
5810  // Optimize special case for individual halfs of `xor-long` (`xor` is simplified earlier).
5811  if (value == 0u) {
5812    if (out != first) {
5813      __ mov(out, ShifterOperand(first));
5814    }
5815    return;
5816  }
5817  __ eor(out, first, ShifterOperand(value));
5818}
5819
5820void InstructionCodeGeneratorARM::HandleBitwiseOperation(HBinaryOperation* instruction) {
5821  LocationSummary* locations = instruction->GetLocations();
5822  Location first = locations->InAt(0);
5823  Location second = locations->InAt(1);
5824  Location out = locations->Out();
5825
5826  if (second.IsConstant()) {
5827    uint64_t value = static_cast<uint64_t>(Int64FromConstant(second.GetConstant()));
5828    uint32_t value_low = Low32Bits(value);
5829    if (instruction->GetResultType() == Primitive::kPrimInt) {
5830      Register first_reg = first.AsRegister<Register>();
5831      Register out_reg = out.AsRegister<Register>();
5832      if (instruction->IsAnd()) {
5833        GenerateAndConst(out_reg, first_reg, value_low);
5834      } else if (instruction->IsOr()) {
5835        GenerateOrrConst(out_reg, first_reg, value_low);
5836      } else {
5837        DCHECK(instruction->IsXor());
5838        GenerateEorConst(out_reg, first_reg, value_low);
5839      }
5840    } else {
5841      DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
5842      uint32_t value_high = High32Bits(value);
5843      Register first_low = first.AsRegisterPairLow<Register>();
5844      Register first_high = first.AsRegisterPairHigh<Register>();
5845      Register out_low = out.AsRegisterPairLow<Register>();
5846      Register out_high = out.AsRegisterPairHigh<Register>();
5847      if (instruction->IsAnd()) {
5848        GenerateAndConst(out_low, first_low, value_low);
5849        GenerateAndConst(out_high, first_high, value_high);
5850      } else if (instruction->IsOr()) {
5851        GenerateOrrConst(out_low, first_low, value_low);
5852        GenerateOrrConst(out_high, first_high, value_high);
5853      } else {
5854        DCHECK(instruction->IsXor());
5855        GenerateEorConst(out_low, first_low, value_low);
5856        GenerateEorConst(out_high, first_high, value_high);
5857      }
5858    }
5859    return;
5860  }
5861
5862  if (instruction->GetResultType() == Primitive::kPrimInt) {
5863    Register first_reg = first.AsRegister<Register>();
5864    ShifterOperand second_reg(second.AsRegister<Register>());
5865    Register out_reg = out.AsRegister<Register>();
5866    if (instruction->IsAnd()) {
5867      __ and_(out_reg, first_reg, second_reg);
5868    } else if (instruction->IsOr()) {
5869      __ orr(out_reg, first_reg, second_reg);
5870    } else {
5871      DCHECK(instruction->IsXor());
5872      __ eor(out_reg, first_reg, second_reg);
5873    }
5874  } else {
5875    DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
5876    Register first_low = first.AsRegisterPairLow<Register>();
5877    Register first_high = first.AsRegisterPairHigh<Register>();
5878    ShifterOperand second_low(second.AsRegisterPairLow<Register>());
5879    ShifterOperand second_high(second.AsRegisterPairHigh<Register>());
5880    Register out_low = out.AsRegisterPairLow<Register>();
5881    Register out_high = out.AsRegisterPairHigh<Register>();
5882    if (instruction->IsAnd()) {
5883      __ and_(out_low, first_low, second_low);
5884      __ and_(out_high, first_high, second_high);
5885    } else if (instruction->IsOr()) {
5886      __ orr(out_low, first_low, second_low);
5887      __ orr(out_high, first_high, second_high);
5888    } else {
5889      DCHECK(instruction->IsXor());
5890      __ eor(out_low, first_low, second_low);
5891      __ eor(out_high, first_high, second_high);
5892    }
5893  }
5894}
5895
5896void CodeGeneratorARM::GenerateReadBarrier(HInstruction* instruction,
5897                                           Location out,
5898                                           Location ref,
5899                                           Location obj,
5900                                           uint32_t offset,
5901                                           Location index) {
5902  DCHECK(kEmitCompilerReadBarrier);
5903
5904  // If heap poisoning is enabled, the unpoisoning of the loaded
5905  // reference will be carried out by the runtime within the slow
5906  // path.
5907  //
5908  // Note that `ref` currently does not get unpoisoned (when heap
5909  // poisoning is enabled), which is alright as the `ref` argument is
5910  // not used by the artReadBarrierSlow entry point.
5911  //
5912  // TODO: Unpoison `ref` when it is used by artReadBarrierSlow.
5913  SlowPathCode* slow_path = new (GetGraph()->GetArena())
5914      ReadBarrierForHeapReferenceSlowPathARM(instruction, out, ref, obj, offset, index);
5915  AddSlowPath(slow_path);
5916
5917  // TODO: When read barrier has a fast path, add it here.
5918  /* Currently the read barrier call is inserted after the original load.
5919   * However, if we have a fast path, we need to perform the load of obj.LockWord *before* the
5920   * original load. This load-load ordering is required by the read barrier.
5921   * The fast path/slow path (for Baker's algorithm) should look like:
5922   *
5923   * bool isGray = obj.LockWord & kReadBarrierMask;
5924   * lfence;  // load fence or artificial data dependence to prevent load-load reordering
5925   * ref = obj.field;    // this is the original load
5926   * if (isGray) {
5927   *   ref = Mark(ref);  // ideally the slow path just does Mark(ref)
5928   * }
5929   */
5930
5931  __ b(slow_path->GetEntryLabel());
5932  __ Bind(slow_path->GetExitLabel());
5933}
5934
5935void CodeGeneratorARM::MaybeGenerateReadBarrier(HInstruction* instruction,
5936                                                Location out,
5937                                                Location ref,
5938                                                Location obj,
5939                                                uint32_t offset,
5940                                                Location index) {
5941  if (kEmitCompilerReadBarrier) {
5942    // If heap poisoning is enabled, unpoisoning will be taken care of
5943    // by the runtime within the slow path.
5944    GenerateReadBarrier(instruction, out, ref, obj, offset, index);
5945  } else if (kPoisonHeapReferences) {
5946    __ UnpoisonHeapReference(out.AsRegister<Register>());
5947  }
5948}
5949
5950void CodeGeneratorARM::GenerateReadBarrierForRoot(HInstruction* instruction,
5951                                                  Location out,
5952                                                  Location root) {
5953  DCHECK(kEmitCompilerReadBarrier);
5954
5955  // Note that GC roots are not affected by heap poisoning, so we do
5956  // not need to do anything special for this here.
5957  SlowPathCode* slow_path =
5958      new (GetGraph()->GetArena()) ReadBarrierForRootSlowPathARM(instruction, out, root);
5959  AddSlowPath(slow_path);
5960
5961  // TODO: Implement a fast path for ReadBarrierForRoot, performing
5962  // the following operation (for Baker's algorithm):
5963  //
5964  //   if (thread.tls32_.is_gc_marking) {
5965  //     root = Mark(root);
5966  //   }
5967
5968  __ b(slow_path->GetEntryLabel());
5969  __ Bind(slow_path->GetExitLabel());
5970}
5971
5972HInvokeStaticOrDirect::DispatchInfo CodeGeneratorARM::GetSupportedInvokeStaticOrDirectDispatch(
5973      const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
5974      MethodReference target_method) {
5975  if (desired_dispatch_info.code_ptr_location ==
5976      HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative) {
5977    const DexFile& outer_dex_file = GetGraph()->GetDexFile();
5978    if (&outer_dex_file != target_method.dex_file) {
5979      // Calls across dex files are more likely to exceed the available BL range,
5980      // so use absolute patch with fixup if available and kCallArtMethod otherwise.
5981      HInvokeStaticOrDirect::CodePtrLocation code_ptr_location =
5982          (desired_dispatch_info.method_load_kind ==
5983           HInvokeStaticOrDirect::MethodLoadKind::kDirectAddressWithFixup)
5984          ? HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup
5985          : HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod;
5986      return HInvokeStaticOrDirect::DispatchInfo {
5987        desired_dispatch_info.method_load_kind,
5988        code_ptr_location,
5989        desired_dispatch_info.method_load_data,
5990        0u
5991      };
5992    }
5993  }
5994  return desired_dispatch_info;
5995}
5996
5997Register CodeGeneratorARM::GetInvokeStaticOrDirectExtraParameter(HInvokeStaticOrDirect* invoke,
5998                                                                 Register temp) {
5999  DCHECK_EQ(invoke->InputCount(), invoke->GetNumberOfArguments() + 1u);
6000  Location location = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
6001  if (!invoke->GetLocations()->Intrinsified()) {
6002    return location.AsRegister<Register>();
6003  }
6004  // For intrinsics we allow any location, so it may be on the stack.
6005  if (!location.IsRegister()) {
6006    __ LoadFromOffset(kLoadWord, temp, SP, location.GetStackIndex());
6007    return temp;
6008  }
6009  // For register locations, check if the register was saved. If so, get it from the stack.
6010  // Note: There is a chance that the register was saved but not overwritten, so we could
6011  // save one load. However, since this is just an intrinsic slow path we prefer this
6012  // simple and more robust approach rather that trying to determine if that's the case.
6013  SlowPathCode* slow_path = GetCurrentSlowPath();
6014  DCHECK(slow_path != nullptr);  // For intrinsified invokes the call is emitted on the slow path.
6015  if (slow_path->IsCoreRegisterSaved(location.AsRegister<Register>())) {
6016    int stack_offset = slow_path->GetStackOffsetOfCoreRegister(location.AsRegister<Register>());
6017    __ LoadFromOffset(kLoadWord, temp, SP, stack_offset);
6018    return temp;
6019  }
6020  return location.AsRegister<Register>();
6021}
6022
6023void CodeGeneratorARM::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) {
6024  // For better instruction scheduling we load the direct code pointer before the method pointer.
6025  switch (invoke->GetCodePtrLocation()) {
6026    case HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup:
6027      // LR = code address from literal pool with link-time patch.
6028      __ LoadLiteral(LR, DeduplicateMethodCodeLiteral(invoke->GetTargetMethod()));
6029      break;
6030    case HInvokeStaticOrDirect::CodePtrLocation::kCallDirect:
6031      // LR = invoke->GetDirectCodePtr();
6032      __ LoadImmediate(LR, invoke->GetDirectCodePtr());
6033      break;
6034    default:
6035      break;
6036  }
6037
6038  Location callee_method = temp;  // For all kinds except kRecursive, callee will be in temp.
6039  switch (invoke->GetMethodLoadKind()) {
6040    case HInvokeStaticOrDirect::MethodLoadKind::kStringInit:
6041      // temp = thread->string_init_entrypoint
6042      __ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), TR, invoke->GetStringInitOffset());
6043      break;
6044    case HInvokeStaticOrDirect::MethodLoadKind::kRecursive:
6045      callee_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
6046      break;
6047    case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress:
6048      __ LoadImmediate(temp.AsRegister<Register>(), invoke->GetMethodAddress());
6049      break;
6050    case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddressWithFixup:
6051      __ LoadLiteral(temp.AsRegister<Register>(),
6052                     DeduplicateMethodAddressLiteral(invoke->GetTargetMethod()));
6053      break;
6054    case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative: {
6055      HArmDexCacheArraysBase* base =
6056          invoke->InputAt(invoke->GetSpecialInputIndex())->AsArmDexCacheArraysBase();
6057      Register base_reg = GetInvokeStaticOrDirectExtraParameter(invoke,
6058                                                                temp.AsRegister<Register>());
6059      int32_t offset = invoke->GetDexCacheArrayOffset() - base->GetElementOffset();
6060      __ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), base_reg, offset);
6061      break;
6062    }
6063    case HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod: {
6064      Location current_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
6065      Register method_reg;
6066      Register reg = temp.AsRegister<Register>();
6067      if (current_method.IsRegister()) {
6068        method_reg = current_method.AsRegister<Register>();
6069      } else {
6070        DCHECK(invoke->GetLocations()->Intrinsified());
6071        DCHECK(!current_method.IsValid());
6072        method_reg = reg;
6073        __ LoadFromOffset(kLoadWord, reg, SP, kCurrentMethodStackOffset);
6074      }
6075      // /* ArtMethod*[] */ temp = temp.ptr_sized_fields_->dex_cache_resolved_methods_;
6076      __ LoadFromOffset(kLoadWord,
6077                        reg,
6078                        method_reg,
6079                        ArtMethod::DexCacheResolvedMethodsOffset(kArmPointerSize).Int32Value());
6080      // temp = temp[index_in_cache]
6081      uint32_t index_in_cache = invoke->GetTargetMethod().dex_method_index;
6082      __ LoadFromOffset(kLoadWord, reg, reg, CodeGenerator::GetCachePointerOffset(index_in_cache));
6083      break;
6084    }
6085  }
6086
6087  switch (invoke->GetCodePtrLocation()) {
6088    case HInvokeStaticOrDirect::CodePtrLocation::kCallSelf:
6089      __ bl(GetFrameEntryLabel());
6090      break;
6091    case HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative:
6092      relative_call_patches_.emplace_back(invoke->GetTargetMethod());
6093      __ BindTrackedLabel(&relative_call_patches_.back().label);
6094      // Arbitrarily branch to the BL itself, override at link time.
6095      __ bl(&relative_call_patches_.back().label);
6096      break;
6097    case HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup:
6098    case HInvokeStaticOrDirect::CodePtrLocation::kCallDirect:
6099      // LR prepared above for better instruction scheduling.
6100      // LR()
6101      __ blx(LR);
6102      break;
6103    case HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod:
6104      // LR = callee_method->entry_point_from_quick_compiled_code_
6105      __ LoadFromOffset(
6106          kLoadWord, LR, callee_method.AsRegister<Register>(),
6107          ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArmWordSize).Int32Value());
6108      // LR()
6109      __ blx(LR);
6110      break;
6111  }
6112
6113  DCHECK(!IsLeafMethod());
6114}
6115
6116void CodeGeneratorARM::GenerateVirtualCall(HInvokeVirtual* invoke, Location temp_location) {
6117  Register temp = temp_location.AsRegister<Register>();
6118  uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
6119      invoke->GetVTableIndex(), kArmPointerSize).Uint32Value();
6120
6121  // Use the calling convention instead of the location of the receiver, as
6122  // intrinsics may have put the receiver in a different register. In the intrinsics
6123  // slow path, the arguments have been moved to the right place, so here we are
6124  // guaranteed that the receiver is the first register of the calling convention.
6125  InvokeDexCallingConvention calling_convention;
6126  Register receiver = calling_convention.GetRegisterAt(0);
6127  uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
6128  // /* HeapReference<Class> */ temp = receiver->klass_
6129  __ LoadFromOffset(kLoadWord, temp, receiver, class_offset);
6130  MaybeRecordImplicitNullCheck(invoke);
6131  // Instead of simply (possibly) unpoisoning `temp` here, we should
6132  // emit a read barrier for the previous class reference load.
6133  // However this is not required in practice, as this is an
6134  // intermediate/temporary reference and because the current
6135  // concurrent copying collector keeps the from-space memory
6136  // intact/accessible until the end of the marking phase (the
6137  // concurrent copying collector may not in the future).
6138  __ MaybeUnpoisonHeapReference(temp);
6139  // temp = temp->GetMethodAt(method_offset);
6140  uint32_t entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(
6141      kArmWordSize).Int32Value();
6142  __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
6143  // LR = temp->GetEntryPoint();
6144  __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
6145  // LR();
6146  __ blx(LR);
6147}
6148
6149void CodeGeneratorARM::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
6150  DCHECK(linker_patches->empty());
6151  size_t size =
6152      method_patches_.size() +
6153      call_patches_.size() +
6154      relative_call_patches_.size() +
6155      /* MOVW+MOVT for each base */ 2u * dex_cache_arrays_base_labels_.size();
6156  linker_patches->reserve(size);
6157  for (const auto& entry : method_patches_) {
6158    const MethodReference& target_method = entry.first;
6159    Literal* literal = entry.second;
6160    DCHECK(literal->GetLabel()->IsBound());
6161    uint32_t literal_offset = literal->GetLabel()->Position();
6162    linker_patches->push_back(LinkerPatch::MethodPatch(literal_offset,
6163                                                       target_method.dex_file,
6164                                                       target_method.dex_method_index));
6165  }
6166  for (const auto& entry : call_patches_) {
6167    const MethodReference& target_method = entry.first;
6168    Literal* literal = entry.second;
6169    DCHECK(literal->GetLabel()->IsBound());
6170    uint32_t literal_offset = literal->GetLabel()->Position();
6171    linker_patches->push_back(LinkerPatch::CodePatch(literal_offset,
6172                                                     target_method.dex_file,
6173                                                     target_method.dex_method_index));
6174  }
6175  for (const MethodPatchInfo<Label>& info : relative_call_patches_) {
6176    uint32_t literal_offset = info.label.Position();
6177    linker_patches->push_back(LinkerPatch::RelativeCodePatch(literal_offset,
6178                                                             info.target_method.dex_file,
6179                                                             info.target_method.dex_method_index));
6180  }
6181  for (const auto& pair : dex_cache_arrays_base_labels_) {
6182    HArmDexCacheArraysBase* base = pair.first;
6183    const DexCacheArraysBaseLabels* labels = &pair.second;
6184    const DexFile& dex_file = base->GetDexFile();
6185    size_t base_element_offset = base->GetElementOffset();
6186    DCHECK(labels->add_pc_label.IsBound());
6187    uint32_t add_pc_offset = dchecked_integral_cast<uint32_t>(labels->add_pc_label.Position());
6188    // Add MOVW patch.
6189    DCHECK(labels->movw_label.IsBound());
6190    uint32_t movw_offset = dchecked_integral_cast<uint32_t>(labels->movw_label.Position());
6191    linker_patches->push_back(LinkerPatch::DexCacheArrayPatch(movw_offset,
6192                                                              &dex_file,
6193                                                              add_pc_offset,
6194                                                              base_element_offset));
6195    // Add MOVT patch.
6196    DCHECK(labels->movt_label.IsBound());
6197    uint32_t movt_offset = dchecked_integral_cast<uint32_t>(labels->movt_label.Position());
6198    linker_patches->push_back(LinkerPatch::DexCacheArrayPatch(movt_offset,
6199                                                              &dex_file,
6200                                                              add_pc_offset,
6201                                                              base_element_offset));
6202  }
6203}
6204
6205Literal* CodeGeneratorARM::DeduplicateMethodLiteral(MethodReference target_method,
6206                                                    MethodToLiteralMap* map) {
6207  // Look up the literal for target_method.
6208  auto lb = map->lower_bound(target_method);
6209  if (lb != map->end() && !map->key_comp()(target_method, lb->first)) {
6210    return lb->second;
6211  }
6212  // We don't have a literal for this method yet, insert a new one.
6213  Literal* literal = __ NewLiteral<uint32_t>(0u);
6214  map->PutBefore(lb, target_method, literal);
6215  return literal;
6216}
6217
6218Literal* CodeGeneratorARM::DeduplicateMethodAddressLiteral(MethodReference target_method) {
6219  return DeduplicateMethodLiteral(target_method, &method_patches_);
6220}
6221
6222Literal* CodeGeneratorARM::DeduplicateMethodCodeLiteral(MethodReference target_method) {
6223  return DeduplicateMethodLiteral(target_method, &call_patches_);
6224}
6225
6226void LocationsBuilderARM::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
6227  // Nothing to do, this should be removed during prepare for register allocator.
6228  LOG(FATAL) << "Unreachable";
6229}
6230
6231void InstructionCodeGeneratorARM::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
6232  // Nothing to do, this should be removed during prepare for register allocator.
6233  LOG(FATAL) << "Unreachable";
6234}
6235
6236void LocationsBuilderARM::VisitFakeString(HFakeString* instruction) {
6237  DCHECK(codegen_->IsBaseline());
6238  LocationSummary* locations =
6239      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
6240  locations->SetOut(Location::ConstantLocation(GetGraph()->GetNullConstant()));
6241}
6242
6243void InstructionCodeGeneratorARM::VisitFakeString(HFakeString* instruction ATTRIBUTE_UNUSED) {
6244  DCHECK(codegen_->IsBaseline());
6245  // Will be generated at use site.
6246}
6247
6248// Simple implementation of packed switch - generate cascaded compare/jumps.
6249void LocationsBuilderARM::VisitPackedSwitch(HPackedSwitch* switch_instr) {
6250  LocationSummary* locations =
6251      new (GetGraph()->GetArena()) LocationSummary(switch_instr, LocationSummary::kNoCall);
6252  locations->SetInAt(0, Location::RequiresRegister());
6253  if (switch_instr->GetNumEntries() > kPackedSwitchCompareJumpThreshold &&
6254      codegen_->GetAssembler()->IsThumb()) {
6255    locations->AddTemp(Location::RequiresRegister());  // We need a temp for the table base.
6256    if (switch_instr->GetStartValue() != 0) {
6257      locations->AddTemp(Location::RequiresRegister());  // We need a temp for the bias.
6258    }
6259  }
6260}
6261
6262void InstructionCodeGeneratorARM::VisitPackedSwitch(HPackedSwitch* switch_instr) {
6263  int32_t lower_bound = switch_instr->GetStartValue();
6264  uint32_t num_entries = switch_instr->GetNumEntries();
6265  LocationSummary* locations = switch_instr->GetLocations();
6266  Register value_reg = locations->InAt(0).AsRegister<Register>();
6267  HBasicBlock* default_block = switch_instr->GetDefaultBlock();
6268
6269  if (num_entries <= kPackedSwitchCompareJumpThreshold || !codegen_->GetAssembler()->IsThumb()) {
6270    // Create a series of compare/jumps.
6271    Register temp_reg = IP;
6272    // Note: It is fine for the below AddConstantSetFlags() using IP register to temporarily store
6273    // the immediate, because IP is used as the destination register. For the other
6274    // AddConstantSetFlags() and GenerateCompareWithImmediate(), the immediate values are constant,
6275    // and they can be encoded in the instruction without making use of IP register.
6276    __ AddConstantSetFlags(temp_reg, value_reg, -lower_bound);
6277
6278    const ArenaVector<HBasicBlock*>& successors = switch_instr->GetBlock()->GetSuccessors();
6279    // Jump to successors[0] if value == lower_bound.
6280    __ b(codegen_->GetLabelOf(successors[0]), EQ);
6281    int32_t last_index = 0;
6282    for (; num_entries - last_index > 2; last_index += 2) {
6283      __ AddConstantSetFlags(temp_reg, temp_reg, -2);
6284      // Jump to successors[last_index + 1] if value < case_value[last_index + 2].
6285      __ b(codegen_->GetLabelOf(successors[last_index + 1]), LO);
6286      // Jump to successors[last_index + 2] if value == case_value[last_index + 2].
6287      __ b(codegen_->GetLabelOf(successors[last_index + 2]), EQ);
6288    }
6289    if (num_entries - last_index == 2) {
6290      // The last missing case_value.
6291      GenerateCompareWithImmediate(temp_reg, 1);
6292      __ b(codegen_->GetLabelOf(successors[last_index + 1]), EQ);
6293    }
6294
6295    // And the default for any other value.
6296    if (!codegen_->GoesToNextBlock(switch_instr->GetBlock(), default_block)) {
6297      __ b(codegen_->GetLabelOf(default_block));
6298    }
6299  } else {
6300    // Create a table lookup.
6301    Register temp_reg = locations->GetTemp(0).AsRegister<Register>();
6302
6303    // Materialize a pointer to the switch table
6304    std::vector<Label*> labels(num_entries);
6305    const ArenaVector<HBasicBlock*>& successors = switch_instr->GetBlock()->GetSuccessors();
6306    for (uint32_t i = 0; i < num_entries; i++) {
6307      labels[i] = codegen_->GetLabelOf(successors[i]);
6308    }
6309    JumpTable* table = __ CreateJumpTable(std::move(labels), temp_reg);
6310
6311    // Remove the bias.
6312    Register key_reg;
6313    if (lower_bound != 0) {
6314      key_reg = locations->GetTemp(1).AsRegister<Register>();
6315      __ AddConstant(key_reg, value_reg, -lower_bound);
6316    } else {
6317      key_reg = value_reg;
6318    }
6319
6320    // Check whether the value is in the table, jump to default block if not.
6321    __ CmpConstant(key_reg, num_entries - 1);
6322    __ b(codegen_->GetLabelOf(default_block), Condition::HI);
6323
6324    // Load the displacement from the table.
6325    __ ldr(temp_reg, Address(temp_reg, key_reg, Shift::LSL, 2));
6326
6327    // Dispatch is a direct add to the PC (for Thumb2).
6328    __ EmitJumpTableDispatch(table, temp_reg);
6329  }
6330}
6331
6332void LocationsBuilderARM::VisitArmDexCacheArraysBase(HArmDexCacheArraysBase* base) {
6333  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(base);
6334  locations->SetOut(Location::RequiresRegister());
6335  codegen_->AddDexCacheArraysBase(base);
6336}
6337
6338void InstructionCodeGeneratorARM::VisitArmDexCacheArraysBase(HArmDexCacheArraysBase* base) {
6339  Register base_reg = base->GetLocations()->Out().AsRegister<Register>();
6340  CodeGeneratorARM::DexCacheArraysBaseLabels* labels = codegen_->GetDexCacheArraysBaseLabels(base);
6341  __ BindTrackedLabel(&labels->movw_label);
6342  __ movw(base_reg, 0u);
6343  __ BindTrackedLabel(&labels->movt_label);
6344  __ movt(base_reg, 0u);
6345  __ BindTrackedLabel(&labels->add_pc_label);
6346  __ add(base_reg, base_reg, ShifterOperand(PC));
6347}
6348
6349void CodeGeneratorARM::MoveFromReturnRegister(Location trg, Primitive::Type type) {
6350  if (!trg.IsValid()) {
6351    DCHECK(type == Primitive::kPrimVoid);
6352    return;
6353  }
6354
6355  DCHECK_NE(type, Primitive::kPrimVoid);
6356
6357  Location return_loc = InvokeDexCallingConventionVisitorARM().GetReturnLocation(type);
6358  if (return_loc.Equals(trg)) {
6359    return;
6360  }
6361
6362  // TODO: Consider pairs in the parallel move resolver, then this could be nicely merged
6363  //       with the last branch.
6364  if (type == Primitive::kPrimLong) {
6365    HParallelMove parallel_move(GetGraph()->GetArena());
6366    parallel_move.AddMove(return_loc.ToLow(), trg.ToLow(), Primitive::kPrimInt, nullptr);
6367    parallel_move.AddMove(return_loc.ToHigh(), trg.ToHigh(), Primitive::kPrimInt, nullptr);
6368    GetMoveResolver()->EmitNativeCode(&parallel_move);
6369  } else if (type == Primitive::kPrimDouble) {
6370    HParallelMove parallel_move(GetGraph()->GetArena());
6371    parallel_move.AddMove(return_loc.ToLow(), trg.ToLow(), Primitive::kPrimFloat, nullptr);
6372    parallel_move.AddMove(return_loc.ToHigh(), trg.ToHigh(), Primitive::kPrimFloat, nullptr);
6373    GetMoveResolver()->EmitNativeCode(&parallel_move);
6374  } else {
6375    // Let the parallel move resolver take care of all of this.
6376    HParallelMove parallel_move(GetGraph()->GetArena());
6377    parallel_move.AddMove(return_loc, trg, type, nullptr);
6378    GetMoveResolver()->EmitNativeCode(&parallel_move);
6379  }
6380}
6381
6382#undef __
6383#undef QUICK_ENTRY_POINT
6384
6385}  // namespace arm
6386}  // namespace art
6387