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