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