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