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