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