code_generator_arm.cc revision 5b5b9319ff970979ed47d41a41283e4faeffb602
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*) {
1547  // MaybeRecordNativeDebugInfo is already called implicitly in CodeGenerator::Compile.
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::kPrimBoolean:
3155    case Primitive::kPrimByte:
3156    case Primitive::kPrimChar:
3157    case Primitive::kPrimShort:
3158    case Primitive::kPrimInt: {
3159      if (value.IsRegister()) {
3160        __ CompareAndBranchIfZero(value.AsRegister<Register>(), slow_path->GetEntryLabel());
3161      } else {
3162        DCHECK(value.IsConstant()) << value;
3163        if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
3164          __ b(slow_path->GetEntryLabel());
3165        }
3166      }
3167      break;
3168    }
3169    case Primitive::kPrimLong: {
3170      if (value.IsRegisterPair()) {
3171        __ orrs(IP,
3172                value.AsRegisterPairLow<Register>(),
3173                ShifterOperand(value.AsRegisterPairHigh<Register>()));
3174        __ b(slow_path->GetEntryLabel(), EQ);
3175      } else {
3176        DCHECK(value.IsConstant()) << value;
3177        if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
3178          __ b(slow_path->GetEntryLabel());
3179        }
3180      }
3181      break;
3182    default:
3183      LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
3184    }
3185  }
3186}
3187
3188void InstructionCodeGeneratorARM::HandleIntegerRotate(LocationSummary* locations) {
3189  Register in = locations->InAt(0).AsRegister<Register>();
3190  Location rhs = locations->InAt(1);
3191  Register out = locations->Out().AsRegister<Register>();
3192
3193  if (rhs.IsConstant()) {
3194    // Arm32 and Thumb2 assemblers require a rotation on the interval [1,31],
3195    // so map all rotations to a +ve. equivalent in that range.
3196    // (e.g. left *or* right by -2 bits == 30 bits in the same direction.)
3197    uint32_t rot = CodeGenerator::GetInt32ValueOf(rhs.GetConstant()) & 0x1F;
3198    if (rot) {
3199      // Rotate, mapping left rotations to right equivalents if necessary.
3200      // (e.g. left by 2 bits == right by 30.)
3201      __ Ror(out, in, rot);
3202    } else if (out != in) {
3203      __ Mov(out, in);
3204    }
3205  } else {
3206    __ Ror(out, in, rhs.AsRegister<Register>());
3207  }
3208}
3209
3210// Gain some speed by mapping all Long rotates onto equivalent pairs of Integer
3211// rotates by swapping input regs (effectively rotating by the first 32-bits of
3212// a larger rotation) or flipping direction (thus treating larger right/left
3213// rotations as sub-word sized rotations in the other direction) as appropriate.
3214void InstructionCodeGeneratorARM::HandleLongRotate(LocationSummary* locations) {
3215  Register in_reg_lo = locations->InAt(0).AsRegisterPairLow<Register>();
3216  Register in_reg_hi = locations->InAt(0).AsRegisterPairHigh<Register>();
3217  Location rhs = locations->InAt(1);
3218  Register out_reg_lo = locations->Out().AsRegisterPairLow<Register>();
3219  Register out_reg_hi = locations->Out().AsRegisterPairHigh<Register>();
3220
3221  if (rhs.IsConstant()) {
3222    uint64_t rot = CodeGenerator::GetInt64ValueOf(rhs.GetConstant());
3223    // Map all rotations to +ve. equivalents on the interval [0,63].
3224    rot &= kMaxLongShiftDistance;
3225    // For rotates over a word in size, 'pre-rotate' by 32-bits to keep rotate
3226    // logic below to a simple pair of binary orr.
3227    // (e.g. 34 bits == in_reg swap + 2 bits right.)
3228    if (rot >= kArmBitsPerWord) {
3229      rot -= kArmBitsPerWord;
3230      std::swap(in_reg_hi, in_reg_lo);
3231    }
3232    // Rotate, or mov to out for zero or word size rotations.
3233    if (rot != 0u) {
3234      __ Lsr(out_reg_hi, in_reg_hi, rot);
3235      __ orr(out_reg_hi, out_reg_hi, ShifterOperand(in_reg_lo, arm::LSL, kArmBitsPerWord - rot));
3236      __ Lsr(out_reg_lo, in_reg_lo, rot);
3237      __ orr(out_reg_lo, out_reg_lo, ShifterOperand(in_reg_hi, arm::LSL, kArmBitsPerWord - rot));
3238    } else {
3239      __ Mov(out_reg_lo, in_reg_lo);
3240      __ Mov(out_reg_hi, in_reg_hi);
3241    }
3242  } else {
3243    Register shift_right = locations->GetTemp(0).AsRegister<Register>();
3244    Register shift_left = locations->GetTemp(1).AsRegister<Register>();
3245    Label end;
3246    Label shift_by_32_plus_shift_right;
3247
3248    __ and_(shift_right, rhs.AsRegister<Register>(), ShifterOperand(0x1F));
3249    __ Lsrs(shift_left, rhs.AsRegister<Register>(), 6);
3250    __ rsb(shift_left, shift_right, ShifterOperand(kArmBitsPerWord), AL, kCcKeep);
3251    __ b(&shift_by_32_plus_shift_right, CC);
3252
3253    // out_reg_hi = (reg_hi << shift_left) | (reg_lo >> shift_right).
3254    // out_reg_lo = (reg_lo << shift_left) | (reg_hi >> shift_right).
3255    __ Lsl(out_reg_hi, in_reg_hi, shift_left);
3256    __ Lsr(out_reg_lo, in_reg_lo, shift_right);
3257    __ add(out_reg_hi, out_reg_hi, ShifterOperand(out_reg_lo));
3258    __ Lsl(out_reg_lo, in_reg_lo, shift_left);
3259    __ Lsr(shift_left, in_reg_hi, shift_right);
3260    __ add(out_reg_lo, out_reg_lo, ShifterOperand(shift_left));
3261    __ b(&end);
3262
3263    __ Bind(&shift_by_32_plus_shift_right);  // Shift by 32+shift_right.
3264    // out_reg_hi = (reg_hi >> shift_right) | (reg_lo << shift_left).
3265    // out_reg_lo = (reg_lo >> shift_right) | (reg_hi << shift_left).
3266    __ Lsr(out_reg_hi, in_reg_hi, shift_right);
3267    __ Lsl(out_reg_lo, in_reg_lo, shift_left);
3268    __ add(out_reg_hi, out_reg_hi, ShifterOperand(out_reg_lo));
3269    __ Lsr(out_reg_lo, in_reg_lo, shift_right);
3270    __ Lsl(shift_right, in_reg_hi, shift_left);
3271    __ add(out_reg_lo, out_reg_lo, ShifterOperand(shift_right));
3272
3273    __ Bind(&end);
3274  }
3275}
3276
3277void LocationsBuilderARM::VisitRor(HRor* ror) {
3278  LocationSummary* locations =
3279      new (GetGraph()->GetArena()) LocationSummary(ror, LocationSummary::kNoCall);
3280  switch (ror->GetResultType()) {
3281    case Primitive::kPrimInt: {
3282      locations->SetInAt(0, Location::RequiresRegister());
3283      locations->SetInAt(1, Location::RegisterOrConstant(ror->InputAt(1)));
3284      locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3285      break;
3286    }
3287    case Primitive::kPrimLong: {
3288      locations->SetInAt(0, Location::RequiresRegister());
3289      if (ror->InputAt(1)->IsConstant()) {
3290        locations->SetInAt(1, Location::ConstantLocation(ror->InputAt(1)->AsConstant()));
3291      } else {
3292        locations->SetInAt(1, Location::RequiresRegister());
3293        locations->AddTemp(Location::RequiresRegister());
3294        locations->AddTemp(Location::RequiresRegister());
3295      }
3296      locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
3297      break;
3298    }
3299    default:
3300      LOG(FATAL) << "Unexpected operation type " << ror->GetResultType();
3301  }
3302}
3303
3304void InstructionCodeGeneratorARM::VisitRor(HRor* ror) {
3305  LocationSummary* locations = ror->GetLocations();
3306  Primitive::Type type = ror->GetResultType();
3307  switch (type) {
3308    case Primitive::kPrimInt: {
3309      HandleIntegerRotate(locations);
3310      break;
3311    }
3312    case Primitive::kPrimLong: {
3313      HandleLongRotate(locations);
3314      break;
3315    }
3316    default:
3317      LOG(FATAL) << "Unexpected operation type " << type;
3318      UNREACHABLE();
3319  }
3320}
3321
3322void LocationsBuilderARM::HandleShift(HBinaryOperation* op) {
3323  DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
3324
3325  LocationSummary* locations =
3326      new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
3327
3328  switch (op->GetResultType()) {
3329    case Primitive::kPrimInt: {
3330      locations->SetInAt(0, Location::RequiresRegister());
3331      if (op->InputAt(1)->IsConstant()) {
3332        locations->SetInAt(1, Location::ConstantLocation(op->InputAt(1)->AsConstant()));
3333        locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3334      } else {
3335        locations->SetInAt(1, Location::RequiresRegister());
3336        // Make the output overlap, as it will be used to hold the masked
3337        // second input.
3338        locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
3339      }
3340      break;
3341    }
3342    case Primitive::kPrimLong: {
3343      locations->SetInAt(0, Location::RequiresRegister());
3344      if (op->InputAt(1)->IsConstant()) {
3345        locations->SetInAt(1, Location::ConstantLocation(op->InputAt(1)->AsConstant()));
3346        // For simplicity, use kOutputOverlap even though we only require that low registers
3347        // don't clash with high registers which the register allocator currently guarantees.
3348        locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
3349      } else {
3350        locations->SetInAt(1, Location::RequiresRegister());
3351        locations->AddTemp(Location::RequiresRegister());
3352        locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
3353      }
3354      break;
3355    }
3356    default:
3357      LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
3358  }
3359}
3360
3361void InstructionCodeGeneratorARM::HandleShift(HBinaryOperation* op) {
3362  DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
3363
3364  LocationSummary* locations = op->GetLocations();
3365  Location out = locations->Out();
3366  Location first = locations->InAt(0);
3367  Location second = locations->InAt(1);
3368
3369  Primitive::Type type = op->GetResultType();
3370  switch (type) {
3371    case Primitive::kPrimInt: {
3372      Register out_reg = out.AsRegister<Register>();
3373      Register first_reg = first.AsRegister<Register>();
3374      if (second.IsRegister()) {
3375        Register second_reg = second.AsRegister<Register>();
3376        // ARM doesn't mask the shift count so we need to do it ourselves.
3377        __ and_(out_reg, second_reg, ShifterOperand(kMaxIntShiftDistance));
3378        if (op->IsShl()) {
3379          __ Lsl(out_reg, first_reg, out_reg);
3380        } else if (op->IsShr()) {
3381          __ Asr(out_reg, first_reg, out_reg);
3382        } else {
3383          __ Lsr(out_reg, first_reg, out_reg);
3384        }
3385      } else {
3386        int32_t cst = second.GetConstant()->AsIntConstant()->GetValue();
3387        uint32_t shift_value = cst & kMaxIntShiftDistance;
3388        if (shift_value == 0) {  // ARM does not support shifting with 0 immediate.
3389          __ Mov(out_reg, first_reg);
3390        } else if (op->IsShl()) {
3391          __ Lsl(out_reg, first_reg, shift_value);
3392        } else if (op->IsShr()) {
3393          __ Asr(out_reg, first_reg, shift_value);
3394        } else {
3395          __ Lsr(out_reg, first_reg, shift_value);
3396        }
3397      }
3398      break;
3399    }
3400    case Primitive::kPrimLong: {
3401      Register o_h = out.AsRegisterPairHigh<Register>();
3402      Register o_l = out.AsRegisterPairLow<Register>();
3403
3404      Register high = first.AsRegisterPairHigh<Register>();
3405      Register low = first.AsRegisterPairLow<Register>();
3406
3407      if (second.IsRegister()) {
3408        Register temp = locations->GetTemp(0).AsRegister<Register>();
3409
3410        Register second_reg = second.AsRegister<Register>();
3411
3412        if (op->IsShl()) {
3413          __ and_(o_l, second_reg, ShifterOperand(kMaxLongShiftDistance));
3414          // Shift the high part
3415          __ Lsl(o_h, high, o_l);
3416          // Shift the low part and `or` what overflew on the high part
3417          __ rsb(temp, o_l, ShifterOperand(kArmBitsPerWord));
3418          __ Lsr(temp, low, temp);
3419          __ orr(o_h, o_h, ShifterOperand(temp));
3420          // If the shift is > 32 bits, override the high part
3421          __ subs(temp, o_l, ShifterOperand(kArmBitsPerWord));
3422          __ it(PL);
3423          __ Lsl(o_h, low, temp, PL);
3424          // Shift the low part
3425          __ Lsl(o_l, low, o_l);
3426        } else if (op->IsShr()) {
3427          __ and_(o_h, second_reg, ShifterOperand(kMaxLongShiftDistance));
3428          // Shift the low part
3429          __ Lsr(o_l, low, o_h);
3430          // Shift the high part and `or` what underflew on the low part
3431          __ rsb(temp, o_h, ShifterOperand(kArmBitsPerWord));
3432          __ Lsl(temp, high, temp);
3433          __ orr(o_l, o_l, ShifterOperand(temp));
3434          // If the shift is > 32 bits, override the low part
3435          __ subs(temp, o_h, ShifterOperand(kArmBitsPerWord));
3436          __ it(PL);
3437          __ Asr(o_l, high, temp, PL);
3438          // Shift the high part
3439          __ Asr(o_h, high, o_h);
3440        } else {
3441          __ and_(o_h, second_reg, ShifterOperand(kMaxLongShiftDistance));
3442          // same as Shr except we use `Lsr`s and not `Asr`s
3443          __ Lsr(o_l, low, o_h);
3444          __ rsb(temp, o_h, ShifterOperand(kArmBitsPerWord));
3445          __ Lsl(temp, high, temp);
3446          __ orr(o_l, o_l, ShifterOperand(temp));
3447          __ subs(temp, o_h, ShifterOperand(kArmBitsPerWord));
3448          __ it(PL);
3449          __ Lsr(o_l, high, temp, PL);
3450          __ Lsr(o_h, high, o_h);
3451        }
3452      } else {
3453        // Register allocator doesn't create partial overlap.
3454        DCHECK_NE(o_l, high);
3455        DCHECK_NE(o_h, low);
3456        int32_t cst = second.GetConstant()->AsIntConstant()->GetValue();
3457        uint32_t shift_value = cst & kMaxLongShiftDistance;
3458        if (shift_value > 32) {
3459          if (op->IsShl()) {
3460            __ Lsl(o_h, low, shift_value - 32);
3461            __ LoadImmediate(o_l, 0);
3462          } else if (op->IsShr()) {
3463            __ Asr(o_l, high, shift_value - 32);
3464            __ Asr(o_h, high, 31);
3465          } else {
3466            __ Lsr(o_l, high, shift_value - 32);
3467            __ LoadImmediate(o_h, 0);
3468          }
3469        } else if (shift_value == 32) {
3470          if (op->IsShl()) {
3471            __ mov(o_h, ShifterOperand(low));
3472            __ LoadImmediate(o_l, 0);
3473          } else if (op->IsShr()) {
3474            __ mov(o_l, ShifterOperand(high));
3475            __ Asr(o_h, high, 31);
3476          } else {
3477            __ mov(o_l, ShifterOperand(high));
3478            __ LoadImmediate(o_h, 0);
3479          }
3480        } else if (shift_value == 1) {
3481          if (op->IsShl()) {
3482            __ Lsls(o_l, low, 1);
3483            __ adc(o_h, high, ShifterOperand(high));
3484          } else if (op->IsShr()) {
3485            __ Asrs(o_h, high, 1);
3486            __ Rrx(o_l, low);
3487          } else {
3488            __ Lsrs(o_h, high, 1);
3489            __ Rrx(o_l, low);
3490          }
3491        } else {
3492          DCHECK(2 <= shift_value && shift_value < 32) << shift_value;
3493          if (op->IsShl()) {
3494            __ Lsl(o_h, high, shift_value);
3495            __ orr(o_h, o_h, ShifterOperand(low, LSR, 32 - shift_value));
3496            __ Lsl(o_l, low, shift_value);
3497          } else if (op->IsShr()) {
3498            __ Lsr(o_l, low, shift_value);
3499            __ orr(o_l, o_l, ShifterOperand(high, LSL, 32 - shift_value));
3500            __ Asr(o_h, high, shift_value);
3501          } else {
3502            __ Lsr(o_l, low, shift_value);
3503            __ orr(o_l, o_l, ShifterOperand(high, LSL, 32 - shift_value));
3504            __ Lsr(o_h, high, shift_value);
3505          }
3506        }
3507      }
3508      break;
3509    }
3510    default:
3511      LOG(FATAL) << "Unexpected operation type " << type;
3512      UNREACHABLE();
3513  }
3514}
3515
3516void LocationsBuilderARM::VisitShl(HShl* shl) {
3517  HandleShift(shl);
3518}
3519
3520void InstructionCodeGeneratorARM::VisitShl(HShl* shl) {
3521  HandleShift(shl);
3522}
3523
3524void LocationsBuilderARM::VisitShr(HShr* shr) {
3525  HandleShift(shr);
3526}
3527
3528void InstructionCodeGeneratorARM::VisitShr(HShr* shr) {
3529  HandleShift(shr);
3530}
3531
3532void LocationsBuilderARM::VisitUShr(HUShr* ushr) {
3533  HandleShift(ushr);
3534}
3535
3536void InstructionCodeGeneratorARM::VisitUShr(HUShr* ushr) {
3537  HandleShift(ushr);
3538}
3539
3540void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) {
3541  LocationSummary* locations =
3542      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
3543  if (instruction->IsStringAlloc()) {
3544    locations->AddTemp(Location::RegisterLocation(kMethodRegisterArgument));
3545  } else {
3546    InvokeRuntimeCallingConvention calling_convention;
3547    locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3548    locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
3549  }
3550  locations->SetOut(Location::RegisterLocation(R0));
3551}
3552
3553void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) {
3554  // Note: if heap poisoning is enabled, the entry point takes cares
3555  // of poisoning the reference.
3556  if (instruction->IsStringAlloc()) {
3557    // String is allocated through StringFactory. Call NewEmptyString entry point.
3558    Register temp = instruction->GetLocations()->GetTemp(0).AsRegister<Register>();
3559    MemberOffset code_offset = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArmWordSize);
3560    __ LoadFromOffset(kLoadWord, temp, TR, QUICK_ENTRY_POINT(pNewEmptyString));
3561    __ LoadFromOffset(kLoadWord, LR, temp, code_offset.Int32Value());
3562    __ blx(LR);
3563    codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3564  } else {
3565    codegen_->InvokeRuntime(instruction->GetEntrypoint(),
3566                            instruction,
3567                            instruction->GetDexPc(),
3568                            nullptr);
3569    CheckEntrypointTypes<kQuickAllocObjectWithAccessCheck, void*, uint32_t, ArtMethod*>();
3570  }
3571}
3572
3573void LocationsBuilderARM::VisitNewArray(HNewArray* instruction) {
3574  LocationSummary* locations =
3575      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
3576  InvokeRuntimeCallingConvention calling_convention;
3577  locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3578  locations->SetOut(Location::RegisterLocation(R0));
3579  locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
3580  locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
3581}
3582
3583void InstructionCodeGeneratorARM::VisitNewArray(HNewArray* instruction) {
3584  InvokeRuntimeCallingConvention calling_convention;
3585  __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
3586  // Note: if heap poisoning is enabled, the entry point takes cares
3587  // of poisoning the reference.
3588  codegen_->InvokeRuntime(instruction->GetEntrypoint(),
3589                          instruction,
3590                          instruction->GetDexPc(),
3591                          nullptr);
3592  CheckEntrypointTypes<kQuickAllocArrayWithAccessCheck, void*, uint32_t, int32_t, ArtMethod*>();
3593}
3594
3595void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) {
3596  LocationSummary* locations =
3597      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3598  Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
3599  if (location.IsStackSlot()) {
3600    location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
3601  } else if (location.IsDoubleStackSlot()) {
3602    location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
3603  }
3604  locations->SetOut(location);
3605}
3606
3607void InstructionCodeGeneratorARM::VisitParameterValue(
3608    HParameterValue* instruction ATTRIBUTE_UNUSED) {
3609  // Nothing to do, the parameter is already at its location.
3610}
3611
3612void LocationsBuilderARM::VisitCurrentMethod(HCurrentMethod* instruction) {
3613  LocationSummary* locations =
3614      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3615  locations->SetOut(Location::RegisterLocation(kMethodRegisterArgument));
3616}
3617
3618void InstructionCodeGeneratorARM::VisitCurrentMethod(HCurrentMethod* instruction ATTRIBUTE_UNUSED) {
3619  // Nothing to do, the method is already at its location.
3620}
3621
3622void LocationsBuilderARM::VisitNot(HNot* not_) {
3623  LocationSummary* locations =
3624      new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
3625  locations->SetInAt(0, Location::RequiresRegister());
3626  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3627}
3628
3629void InstructionCodeGeneratorARM::VisitNot(HNot* not_) {
3630  LocationSummary* locations = not_->GetLocations();
3631  Location out = locations->Out();
3632  Location in = locations->InAt(0);
3633  switch (not_->GetResultType()) {
3634    case Primitive::kPrimInt:
3635      __ mvn(out.AsRegister<Register>(), ShifterOperand(in.AsRegister<Register>()));
3636      break;
3637
3638    case Primitive::kPrimLong:
3639      __ mvn(out.AsRegisterPairLow<Register>(),
3640             ShifterOperand(in.AsRegisterPairLow<Register>()));
3641      __ mvn(out.AsRegisterPairHigh<Register>(),
3642             ShifterOperand(in.AsRegisterPairHigh<Register>()));
3643      break;
3644
3645    default:
3646      LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
3647  }
3648}
3649
3650void LocationsBuilderARM::VisitBooleanNot(HBooleanNot* bool_not) {
3651  LocationSummary* locations =
3652      new (GetGraph()->GetArena()) LocationSummary(bool_not, LocationSummary::kNoCall);
3653  locations->SetInAt(0, Location::RequiresRegister());
3654  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3655}
3656
3657void InstructionCodeGeneratorARM::VisitBooleanNot(HBooleanNot* bool_not) {
3658  LocationSummary* locations = bool_not->GetLocations();
3659  Location out = locations->Out();
3660  Location in = locations->InAt(0);
3661  __ eor(out.AsRegister<Register>(), in.AsRegister<Register>(), ShifterOperand(1));
3662}
3663
3664void LocationsBuilderARM::VisitCompare(HCompare* compare) {
3665  LocationSummary* locations =
3666      new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
3667  switch (compare->InputAt(0)->GetType()) {
3668    case Primitive::kPrimBoolean:
3669    case Primitive::kPrimByte:
3670    case Primitive::kPrimShort:
3671    case Primitive::kPrimChar:
3672    case Primitive::kPrimInt:
3673    case Primitive::kPrimLong: {
3674      locations->SetInAt(0, Location::RequiresRegister());
3675      locations->SetInAt(1, Location::RequiresRegister());
3676      // Output overlaps because it is written before doing the low comparison.
3677      locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
3678      break;
3679    }
3680    case Primitive::kPrimFloat:
3681    case Primitive::kPrimDouble: {
3682      locations->SetInAt(0, Location::RequiresFpuRegister());
3683      locations->SetInAt(1, Location::RequiresFpuRegister());
3684      locations->SetOut(Location::RequiresRegister());
3685      break;
3686    }
3687    default:
3688      LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
3689  }
3690}
3691
3692void InstructionCodeGeneratorARM::VisitCompare(HCompare* compare) {
3693  LocationSummary* locations = compare->GetLocations();
3694  Register out = locations->Out().AsRegister<Register>();
3695  Location left = locations->InAt(0);
3696  Location right = locations->InAt(1);
3697
3698  Label less, greater, done;
3699  Primitive::Type type = compare->InputAt(0)->GetType();
3700  Condition less_cond;
3701  switch (type) {
3702    case Primitive::kPrimBoolean:
3703    case Primitive::kPrimByte:
3704    case Primitive::kPrimShort:
3705    case Primitive::kPrimChar:
3706    case Primitive::kPrimInt: {
3707      __ LoadImmediate(out, 0);
3708      __ cmp(left.AsRegister<Register>(),
3709             ShifterOperand(right.AsRegister<Register>()));  // Signed compare.
3710      less_cond = LT;
3711      break;
3712    }
3713    case Primitive::kPrimLong: {
3714      __ cmp(left.AsRegisterPairHigh<Register>(),
3715             ShifterOperand(right.AsRegisterPairHigh<Register>()));  // Signed compare.
3716      __ b(&less, LT);
3717      __ b(&greater, GT);
3718      // Do LoadImmediate before the last `cmp`, as LoadImmediate might affect the status flags.
3719      __ LoadImmediate(out, 0);
3720      __ cmp(left.AsRegisterPairLow<Register>(),
3721             ShifterOperand(right.AsRegisterPairLow<Register>()));  // Unsigned compare.
3722      less_cond = LO;
3723      break;
3724    }
3725    case Primitive::kPrimFloat:
3726    case Primitive::kPrimDouble: {
3727      __ LoadImmediate(out, 0);
3728      if (type == Primitive::kPrimFloat) {
3729        __ vcmps(left.AsFpuRegister<SRegister>(), right.AsFpuRegister<SRegister>());
3730      } else {
3731        __ vcmpd(FromLowSToD(left.AsFpuRegisterPairLow<SRegister>()),
3732                 FromLowSToD(right.AsFpuRegisterPairLow<SRegister>()));
3733      }
3734      __ vmstat();  // transfer FP status register to ARM APSR.
3735      less_cond = ARMFPCondition(kCondLT, compare->IsGtBias());
3736      break;
3737    }
3738    default:
3739      LOG(FATAL) << "Unexpected compare type " << type;
3740      UNREACHABLE();
3741  }
3742
3743  __ b(&done, EQ);
3744  __ b(&less, less_cond);
3745
3746  __ Bind(&greater);
3747  __ LoadImmediate(out, 1);
3748  __ b(&done);
3749
3750  __ Bind(&less);
3751  __ LoadImmediate(out, -1);
3752
3753  __ Bind(&done);
3754}
3755
3756void LocationsBuilderARM::VisitPhi(HPhi* instruction) {
3757  LocationSummary* locations =
3758      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3759  for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
3760    locations->SetInAt(i, Location::Any());
3761  }
3762  locations->SetOut(Location::Any());
3763}
3764
3765void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction ATTRIBUTE_UNUSED) {
3766  LOG(FATAL) << "Unreachable";
3767}
3768
3769void CodeGeneratorARM::GenerateMemoryBarrier(MemBarrierKind kind) {
3770  // TODO (ported from quick): revisit ARM barrier kinds.
3771  DmbOptions flavor = DmbOptions::ISH;  // Quiet C++ warnings.
3772  switch (kind) {
3773    case MemBarrierKind::kAnyStore:
3774    case MemBarrierKind::kLoadAny:
3775    case MemBarrierKind::kAnyAny: {
3776      flavor = DmbOptions::ISH;
3777      break;
3778    }
3779    case MemBarrierKind::kStoreStore: {
3780      flavor = DmbOptions::ISHST;
3781      break;
3782    }
3783    default:
3784      LOG(FATAL) << "Unexpected memory barrier " << kind;
3785  }
3786  __ dmb(flavor);
3787}
3788
3789void InstructionCodeGeneratorARM::GenerateWideAtomicLoad(Register addr,
3790                                                         uint32_t offset,
3791                                                         Register out_lo,
3792                                                         Register out_hi) {
3793  if (offset != 0) {
3794    // Ensure `out_lo` is different from `addr`, so that loading
3795    // `offset` into `out_lo` does not clutter `addr`.
3796    DCHECK_NE(out_lo, addr);
3797    __ LoadImmediate(out_lo, offset);
3798    __ add(IP, addr, ShifterOperand(out_lo));
3799    addr = IP;
3800  }
3801  __ ldrexd(out_lo, out_hi, addr);
3802}
3803
3804void InstructionCodeGeneratorARM::GenerateWideAtomicStore(Register addr,
3805                                                          uint32_t offset,
3806                                                          Register value_lo,
3807                                                          Register value_hi,
3808                                                          Register temp1,
3809                                                          Register temp2,
3810                                                          HInstruction* instruction) {
3811  Label fail;
3812  if (offset != 0) {
3813    __ LoadImmediate(temp1, offset);
3814    __ add(IP, addr, ShifterOperand(temp1));
3815    addr = IP;
3816  }
3817  __ Bind(&fail);
3818  // We need a load followed by store. (The address used in a STREX instruction must
3819  // be the same as the address in the most recently executed LDREX instruction.)
3820  __ ldrexd(temp1, temp2, addr);
3821  codegen_->MaybeRecordImplicitNullCheck(instruction);
3822  __ strexd(temp1, value_lo, value_hi, addr);
3823  __ CompareAndBranchIfNonZero(temp1, &fail);
3824}
3825
3826void LocationsBuilderARM::HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info) {
3827  DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3828
3829  LocationSummary* locations =
3830      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3831  locations->SetInAt(0, Location::RequiresRegister());
3832
3833  Primitive::Type field_type = field_info.GetFieldType();
3834  if (Primitive::IsFloatingPointType(field_type)) {
3835    locations->SetInAt(1, Location::RequiresFpuRegister());
3836  } else {
3837    locations->SetInAt(1, Location::RequiresRegister());
3838  }
3839
3840  bool is_wide = field_type == Primitive::kPrimLong || field_type == Primitive::kPrimDouble;
3841  bool generate_volatile = field_info.IsVolatile()
3842      && is_wide
3843      && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
3844  bool needs_write_barrier =
3845      CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
3846  // Temporary registers for the write barrier.
3847  // TODO: consider renaming StoreNeedsWriteBarrier to StoreNeedsGCMark.
3848  if (needs_write_barrier) {
3849    locations->AddTemp(Location::RequiresRegister());  // Possibly used for reference poisoning too.
3850    locations->AddTemp(Location::RequiresRegister());
3851  } else if (generate_volatile) {
3852    // ARM encoding have some additional constraints for ldrexd/strexd:
3853    // - registers need to be consecutive
3854    // - the first register should be even but not R14.
3855    // We don't test for ARM yet, and the assertion makes sure that we
3856    // revisit this if we ever enable ARM encoding.
3857    DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
3858
3859    locations->AddTemp(Location::RequiresRegister());
3860    locations->AddTemp(Location::RequiresRegister());
3861    if (field_type == Primitive::kPrimDouble) {
3862      // For doubles we need two more registers to copy the value.
3863      locations->AddTemp(Location::RegisterLocation(R2));
3864      locations->AddTemp(Location::RegisterLocation(R3));
3865    }
3866  }
3867}
3868
3869void InstructionCodeGeneratorARM::HandleFieldSet(HInstruction* instruction,
3870                                                 const FieldInfo& field_info,
3871                                                 bool value_can_be_null) {
3872  DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3873
3874  LocationSummary* locations = instruction->GetLocations();
3875  Register base = locations->InAt(0).AsRegister<Register>();
3876  Location value = locations->InAt(1);
3877
3878  bool is_volatile = field_info.IsVolatile();
3879  bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
3880  Primitive::Type field_type = field_info.GetFieldType();
3881  uint32_t offset = field_info.GetFieldOffset().Uint32Value();
3882  bool needs_write_barrier =
3883      CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
3884
3885  if (is_volatile) {
3886    codegen_->GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
3887  }
3888
3889  switch (field_type) {
3890    case Primitive::kPrimBoolean:
3891    case Primitive::kPrimByte: {
3892      __ StoreToOffset(kStoreByte, value.AsRegister<Register>(), base, offset);
3893      break;
3894    }
3895
3896    case Primitive::kPrimShort:
3897    case Primitive::kPrimChar: {
3898      __ StoreToOffset(kStoreHalfword, value.AsRegister<Register>(), base, offset);
3899      break;
3900    }
3901
3902    case Primitive::kPrimInt:
3903    case Primitive::kPrimNot: {
3904      if (kPoisonHeapReferences && needs_write_barrier) {
3905        // Note that in the case where `value` is a null reference,
3906        // we do not enter this block, as a null reference does not
3907        // need poisoning.
3908        DCHECK_EQ(field_type, Primitive::kPrimNot);
3909        Register temp = locations->GetTemp(0).AsRegister<Register>();
3910        __ Mov(temp, value.AsRegister<Register>());
3911        __ PoisonHeapReference(temp);
3912        __ StoreToOffset(kStoreWord, temp, base, offset);
3913      } else {
3914        __ StoreToOffset(kStoreWord, value.AsRegister<Register>(), base, offset);
3915      }
3916      break;
3917    }
3918
3919    case Primitive::kPrimLong: {
3920      if (is_volatile && !atomic_ldrd_strd) {
3921        GenerateWideAtomicStore(base, offset,
3922                                value.AsRegisterPairLow<Register>(),
3923                                value.AsRegisterPairHigh<Register>(),
3924                                locations->GetTemp(0).AsRegister<Register>(),
3925                                locations->GetTemp(1).AsRegister<Register>(),
3926                                instruction);
3927      } else {
3928        __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), base, offset);
3929        codegen_->MaybeRecordImplicitNullCheck(instruction);
3930      }
3931      break;
3932    }
3933
3934    case Primitive::kPrimFloat: {
3935      __ StoreSToOffset(value.AsFpuRegister<SRegister>(), base, offset);
3936      break;
3937    }
3938
3939    case Primitive::kPrimDouble: {
3940      DRegister value_reg = FromLowSToD(value.AsFpuRegisterPairLow<SRegister>());
3941      if (is_volatile && !atomic_ldrd_strd) {
3942        Register value_reg_lo = locations->GetTemp(0).AsRegister<Register>();
3943        Register value_reg_hi = locations->GetTemp(1).AsRegister<Register>();
3944
3945        __ vmovrrd(value_reg_lo, value_reg_hi, value_reg);
3946
3947        GenerateWideAtomicStore(base, offset,
3948                                value_reg_lo,
3949                                value_reg_hi,
3950                                locations->GetTemp(2).AsRegister<Register>(),
3951                                locations->GetTemp(3).AsRegister<Register>(),
3952                                instruction);
3953      } else {
3954        __ StoreDToOffset(value_reg, base, offset);
3955        codegen_->MaybeRecordImplicitNullCheck(instruction);
3956      }
3957      break;
3958    }
3959
3960    case Primitive::kPrimVoid:
3961      LOG(FATAL) << "Unreachable type " << field_type;
3962      UNREACHABLE();
3963  }
3964
3965  // Longs and doubles are handled in the switch.
3966  if (field_type != Primitive::kPrimLong && field_type != Primitive::kPrimDouble) {
3967    codegen_->MaybeRecordImplicitNullCheck(instruction);
3968  }
3969
3970  if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
3971    Register temp = locations->GetTemp(0).AsRegister<Register>();
3972    Register card = locations->GetTemp(1).AsRegister<Register>();
3973    codegen_->MarkGCCard(
3974        temp, card, base, value.AsRegister<Register>(), value_can_be_null);
3975  }
3976
3977  if (is_volatile) {
3978    codegen_->GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
3979  }
3980}
3981
3982void LocationsBuilderARM::HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info) {
3983  DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
3984
3985  bool object_field_get_with_read_barrier =
3986      kEmitCompilerReadBarrier && (field_info.GetFieldType() == Primitive::kPrimNot);
3987  LocationSummary* locations =
3988      new (GetGraph()->GetArena()) LocationSummary(instruction,
3989                                                   object_field_get_with_read_barrier ?
3990                                                       LocationSummary::kCallOnSlowPath :
3991                                                       LocationSummary::kNoCall);
3992  locations->SetInAt(0, Location::RequiresRegister());
3993
3994  bool volatile_for_double = field_info.IsVolatile()
3995      && (field_info.GetFieldType() == Primitive::kPrimDouble)
3996      && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
3997  // The output overlaps in case of volatile long: we don't want the
3998  // code generated by GenerateWideAtomicLoad to overwrite the
3999  // object's location.  Likewise, in the case of an object field get
4000  // with read barriers enabled, we do not want the load to overwrite
4001  // the object's location, as we need it to emit the read barrier.
4002  bool overlap = (field_info.IsVolatile() && (field_info.GetFieldType() == Primitive::kPrimLong)) ||
4003      object_field_get_with_read_barrier;
4004
4005  if (Primitive::IsFloatingPointType(instruction->GetType())) {
4006    locations->SetOut(Location::RequiresFpuRegister());
4007  } else {
4008    locations->SetOut(Location::RequiresRegister(),
4009                      (overlap ? Location::kOutputOverlap : Location::kNoOutputOverlap));
4010  }
4011  if (volatile_for_double) {
4012    // ARM encoding have some additional constraints for ldrexd/strexd:
4013    // - registers need to be consecutive
4014    // - the first register should be even but not R14.
4015    // We don't test for ARM yet, and the assertion makes sure that we
4016    // revisit this if we ever enable ARM encoding.
4017    DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
4018    locations->AddTemp(Location::RequiresRegister());
4019    locations->AddTemp(Location::RequiresRegister());
4020  } else if (object_field_get_with_read_barrier && kUseBakerReadBarrier) {
4021    // We need a temporary register for the read barrier marking slow
4022    // path in CodeGeneratorARM::GenerateFieldLoadWithBakerReadBarrier.
4023    locations->AddTemp(Location::RequiresRegister());
4024  }
4025}
4026
4027Location LocationsBuilderARM::ArmEncodableConstantOrRegister(HInstruction* constant,
4028                                                             Opcode opcode) {
4029  DCHECK(!Primitive::IsFloatingPointType(constant->GetType()));
4030  if (constant->IsConstant() &&
4031      CanEncodeConstantAsImmediate(constant->AsConstant(), opcode)) {
4032    return Location::ConstantLocation(constant->AsConstant());
4033  }
4034  return Location::RequiresRegister();
4035}
4036
4037bool LocationsBuilderARM::CanEncodeConstantAsImmediate(HConstant* input_cst,
4038                                                       Opcode opcode) {
4039  uint64_t value = static_cast<uint64_t>(Int64FromConstant(input_cst));
4040  if (Primitive::Is64BitType(input_cst->GetType())) {
4041    return CanEncodeConstantAsImmediate(Low32Bits(value), opcode) &&
4042        CanEncodeConstantAsImmediate(High32Bits(value), opcode);
4043  } else {
4044    return CanEncodeConstantAsImmediate(Low32Bits(value), opcode);
4045  }
4046}
4047
4048bool LocationsBuilderARM::CanEncodeConstantAsImmediate(uint32_t value, Opcode opcode) {
4049  ShifterOperand so;
4050  ArmAssembler* assembler = codegen_->GetAssembler();
4051  if (assembler->ShifterOperandCanHold(kNoRegister, kNoRegister, opcode, value, &so)) {
4052    return true;
4053  }
4054  Opcode neg_opcode = kNoOperand;
4055  switch (opcode) {
4056    case AND:
4057      neg_opcode = BIC;
4058      break;
4059    case ORR:
4060      neg_opcode = ORN;
4061      break;
4062    default:
4063      return false;
4064  }
4065  return assembler->ShifterOperandCanHold(kNoRegister, kNoRegister, neg_opcode, ~value, &so);
4066}
4067
4068void InstructionCodeGeneratorARM::HandleFieldGet(HInstruction* instruction,
4069                                                 const FieldInfo& field_info) {
4070  DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
4071
4072  LocationSummary* locations = instruction->GetLocations();
4073  Location base_loc = locations->InAt(0);
4074  Register base = base_loc.AsRegister<Register>();
4075  Location out = locations->Out();
4076  bool is_volatile = field_info.IsVolatile();
4077  bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
4078  Primitive::Type field_type = field_info.GetFieldType();
4079  uint32_t offset = field_info.GetFieldOffset().Uint32Value();
4080
4081  switch (field_type) {
4082    case Primitive::kPrimBoolean:
4083      __ LoadFromOffset(kLoadUnsignedByte, out.AsRegister<Register>(), base, offset);
4084      break;
4085
4086    case Primitive::kPrimByte:
4087      __ LoadFromOffset(kLoadSignedByte, out.AsRegister<Register>(), base, offset);
4088      break;
4089
4090    case Primitive::kPrimShort:
4091      __ LoadFromOffset(kLoadSignedHalfword, out.AsRegister<Register>(), base, offset);
4092      break;
4093
4094    case Primitive::kPrimChar:
4095      __ LoadFromOffset(kLoadUnsignedHalfword, out.AsRegister<Register>(), base, offset);
4096      break;
4097
4098    case Primitive::kPrimInt:
4099      __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), base, offset);
4100      break;
4101
4102    case Primitive::kPrimNot: {
4103      // /* HeapReference<Object> */ out = *(base + offset)
4104      if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
4105        Location temp_loc = locations->GetTemp(0);
4106        // Note that a potential implicit null check is handled in this
4107        // CodeGeneratorARM::GenerateFieldLoadWithBakerReadBarrier call.
4108        codegen_->GenerateFieldLoadWithBakerReadBarrier(
4109            instruction, out, base, offset, temp_loc, /* needs_null_check */ true);
4110        if (is_volatile) {
4111          codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
4112        }
4113      } else {
4114        __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), base, offset);
4115        codegen_->MaybeRecordImplicitNullCheck(instruction);
4116        if (is_volatile) {
4117          codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
4118        }
4119        // If read barriers are enabled, emit read barriers other than
4120        // Baker's using a slow path (and also unpoison the loaded
4121        // reference, if heap poisoning is enabled).
4122        codegen_->MaybeGenerateReadBarrierSlow(instruction, out, out, base_loc, offset);
4123      }
4124      break;
4125    }
4126
4127    case Primitive::kPrimLong:
4128      if (is_volatile && !atomic_ldrd_strd) {
4129        GenerateWideAtomicLoad(base, offset,
4130                               out.AsRegisterPairLow<Register>(),
4131                               out.AsRegisterPairHigh<Register>());
4132      } else {
4133        __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), base, offset);
4134      }
4135      break;
4136
4137    case Primitive::kPrimFloat:
4138      __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), base, offset);
4139      break;
4140
4141    case Primitive::kPrimDouble: {
4142      DRegister out_reg = FromLowSToD(out.AsFpuRegisterPairLow<SRegister>());
4143      if (is_volatile && !atomic_ldrd_strd) {
4144        Register lo = locations->GetTemp(0).AsRegister<Register>();
4145        Register hi = locations->GetTemp(1).AsRegister<Register>();
4146        GenerateWideAtomicLoad(base, offset, lo, hi);
4147        codegen_->MaybeRecordImplicitNullCheck(instruction);
4148        __ vmovdrr(out_reg, lo, hi);
4149      } else {
4150        __ LoadDFromOffset(out_reg, base, offset);
4151        codegen_->MaybeRecordImplicitNullCheck(instruction);
4152      }
4153      break;
4154    }
4155
4156    case Primitive::kPrimVoid:
4157      LOG(FATAL) << "Unreachable type " << field_type;
4158      UNREACHABLE();
4159  }
4160
4161  if (field_type == Primitive::kPrimNot || field_type == Primitive::kPrimDouble) {
4162    // Potential implicit null checks, in the case of reference or
4163    // double fields, are handled in the previous switch statement.
4164  } else {
4165    codegen_->MaybeRecordImplicitNullCheck(instruction);
4166  }
4167
4168  if (is_volatile) {
4169    if (field_type == Primitive::kPrimNot) {
4170      // Memory barriers, in the case of references, are also handled
4171      // in the previous switch statement.
4172    } else {
4173      codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
4174    }
4175  }
4176}
4177
4178void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
4179  HandleFieldSet(instruction, instruction->GetFieldInfo());
4180}
4181
4182void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
4183  HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
4184}
4185
4186void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
4187  HandleFieldGet(instruction, instruction->GetFieldInfo());
4188}
4189
4190void InstructionCodeGeneratorARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
4191  HandleFieldGet(instruction, instruction->GetFieldInfo());
4192}
4193
4194void LocationsBuilderARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
4195  HandleFieldGet(instruction, instruction->GetFieldInfo());
4196}
4197
4198void InstructionCodeGeneratorARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
4199  HandleFieldGet(instruction, instruction->GetFieldInfo());
4200}
4201
4202void LocationsBuilderARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
4203  HandleFieldSet(instruction, instruction->GetFieldInfo());
4204}
4205
4206void InstructionCodeGeneratorARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
4207  HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
4208}
4209
4210void LocationsBuilderARM::VisitUnresolvedInstanceFieldGet(
4211    HUnresolvedInstanceFieldGet* instruction) {
4212  FieldAccessCallingConventionARM calling_convention;
4213  codegen_->CreateUnresolvedFieldLocationSummary(
4214      instruction, instruction->GetFieldType(), calling_convention);
4215}
4216
4217void InstructionCodeGeneratorARM::VisitUnresolvedInstanceFieldGet(
4218    HUnresolvedInstanceFieldGet* instruction) {
4219  FieldAccessCallingConventionARM calling_convention;
4220  codegen_->GenerateUnresolvedFieldAccess(instruction,
4221                                          instruction->GetFieldType(),
4222                                          instruction->GetFieldIndex(),
4223                                          instruction->GetDexPc(),
4224                                          calling_convention);
4225}
4226
4227void LocationsBuilderARM::VisitUnresolvedInstanceFieldSet(
4228    HUnresolvedInstanceFieldSet* instruction) {
4229  FieldAccessCallingConventionARM calling_convention;
4230  codegen_->CreateUnresolvedFieldLocationSummary(
4231      instruction, instruction->GetFieldType(), calling_convention);
4232}
4233
4234void InstructionCodeGeneratorARM::VisitUnresolvedInstanceFieldSet(
4235    HUnresolvedInstanceFieldSet* instruction) {
4236  FieldAccessCallingConventionARM calling_convention;
4237  codegen_->GenerateUnresolvedFieldAccess(instruction,
4238                                          instruction->GetFieldType(),
4239                                          instruction->GetFieldIndex(),
4240                                          instruction->GetDexPc(),
4241                                          calling_convention);
4242}
4243
4244void LocationsBuilderARM::VisitUnresolvedStaticFieldGet(
4245    HUnresolvedStaticFieldGet* instruction) {
4246  FieldAccessCallingConventionARM calling_convention;
4247  codegen_->CreateUnresolvedFieldLocationSummary(
4248      instruction, instruction->GetFieldType(), calling_convention);
4249}
4250
4251void InstructionCodeGeneratorARM::VisitUnresolvedStaticFieldGet(
4252    HUnresolvedStaticFieldGet* instruction) {
4253  FieldAccessCallingConventionARM calling_convention;
4254  codegen_->GenerateUnresolvedFieldAccess(instruction,
4255                                          instruction->GetFieldType(),
4256                                          instruction->GetFieldIndex(),
4257                                          instruction->GetDexPc(),
4258                                          calling_convention);
4259}
4260
4261void LocationsBuilderARM::VisitUnresolvedStaticFieldSet(
4262    HUnresolvedStaticFieldSet* instruction) {
4263  FieldAccessCallingConventionARM calling_convention;
4264  codegen_->CreateUnresolvedFieldLocationSummary(
4265      instruction, instruction->GetFieldType(), calling_convention);
4266}
4267
4268void InstructionCodeGeneratorARM::VisitUnresolvedStaticFieldSet(
4269    HUnresolvedStaticFieldSet* instruction) {
4270  FieldAccessCallingConventionARM calling_convention;
4271  codegen_->GenerateUnresolvedFieldAccess(instruction,
4272                                          instruction->GetFieldType(),
4273                                          instruction->GetFieldIndex(),
4274                                          instruction->GetDexPc(),
4275                                          calling_convention);
4276}
4277
4278void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) {
4279  LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
4280      ? LocationSummary::kCallOnSlowPath
4281      : LocationSummary::kNoCall;
4282  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
4283  locations->SetInAt(0, Location::RequiresRegister());
4284  if (instruction->HasUses()) {
4285    locations->SetOut(Location::SameAsFirstInput());
4286  }
4287}
4288
4289void CodeGeneratorARM::GenerateImplicitNullCheck(HNullCheck* instruction) {
4290  if (CanMoveNullCheckToUser(instruction)) {
4291    return;
4292  }
4293  Location obj = instruction->GetLocations()->InAt(0);
4294
4295  __ LoadFromOffset(kLoadWord, IP, obj.AsRegister<Register>(), 0);
4296  RecordPcInfo(instruction, instruction->GetDexPc());
4297}
4298
4299void CodeGeneratorARM::GenerateExplicitNullCheck(HNullCheck* instruction) {
4300  SlowPathCode* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction);
4301  AddSlowPath(slow_path);
4302
4303  LocationSummary* locations = instruction->GetLocations();
4304  Location obj = locations->InAt(0);
4305
4306  __ CompareAndBranchIfZero(obj.AsRegister<Register>(), slow_path->GetEntryLabel());
4307}
4308
4309void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) {
4310  codegen_->GenerateNullCheck(instruction);
4311}
4312
4313void LocationsBuilderARM::VisitArrayGet(HArrayGet* instruction) {
4314  bool object_array_get_with_read_barrier =
4315      kEmitCompilerReadBarrier && (instruction->GetType() == Primitive::kPrimNot);
4316  LocationSummary* locations =
4317      new (GetGraph()->GetArena()) LocationSummary(instruction,
4318                                                   object_array_get_with_read_barrier ?
4319                                                       LocationSummary::kCallOnSlowPath :
4320                                                       LocationSummary::kNoCall);
4321  locations->SetInAt(0, Location::RequiresRegister());
4322  locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
4323  if (Primitive::IsFloatingPointType(instruction->GetType())) {
4324    locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
4325  } else {
4326    // The output overlaps in the case of an object array get with
4327    // read barriers enabled: we do not want the move to overwrite the
4328    // array's location, as we need it to emit the read barrier.
4329    locations->SetOut(
4330        Location::RequiresRegister(),
4331        object_array_get_with_read_barrier ? Location::kOutputOverlap : Location::kNoOutputOverlap);
4332  }
4333  // We need a temporary register for the read barrier marking slow
4334  // path in CodeGeneratorARM::GenerateArrayLoadWithBakerReadBarrier.
4335  if (object_array_get_with_read_barrier && kUseBakerReadBarrier) {
4336    locations->AddTemp(Location::RequiresRegister());
4337  }
4338}
4339
4340void InstructionCodeGeneratorARM::VisitArrayGet(HArrayGet* instruction) {
4341  LocationSummary* locations = instruction->GetLocations();
4342  Location obj_loc = locations->InAt(0);
4343  Register obj = obj_loc.AsRegister<Register>();
4344  Location index = locations->InAt(1);
4345  Location out_loc = locations->Out();
4346
4347  Primitive::Type type = instruction->GetType();
4348  switch (type) {
4349    case Primitive::kPrimBoolean: {
4350      uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
4351      Register out = out_loc.AsRegister<Register>();
4352      if (index.IsConstant()) {
4353        size_t offset =
4354            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
4355        __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset);
4356      } else {
4357        __ add(IP, obj, ShifterOperand(index.AsRegister<Register>()));
4358        __ LoadFromOffset(kLoadUnsignedByte, out, IP, data_offset);
4359      }
4360      break;
4361    }
4362
4363    case Primitive::kPrimByte: {
4364      uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
4365      Register out = out_loc.AsRegister<Register>();
4366      if (index.IsConstant()) {
4367        size_t offset =
4368            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
4369        __ LoadFromOffset(kLoadSignedByte, out, obj, offset);
4370      } else {
4371        __ add(IP, obj, ShifterOperand(index.AsRegister<Register>()));
4372        __ LoadFromOffset(kLoadSignedByte, out, IP, data_offset);
4373      }
4374      break;
4375    }
4376
4377    case Primitive::kPrimShort: {
4378      uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
4379      Register out = out_loc.AsRegister<Register>();
4380      if (index.IsConstant()) {
4381        size_t offset =
4382            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
4383        __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset);
4384      } else {
4385        __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
4386        __ LoadFromOffset(kLoadSignedHalfword, out, IP, data_offset);
4387      }
4388      break;
4389    }
4390
4391    case Primitive::kPrimChar: {
4392      uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
4393      Register out = out_loc.AsRegister<Register>();
4394      if (index.IsConstant()) {
4395        size_t offset =
4396            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
4397        __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset);
4398      } else {
4399        __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
4400        __ LoadFromOffset(kLoadUnsignedHalfword, out, IP, data_offset);
4401      }
4402      break;
4403    }
4404
4405    case Primitive::kPrimInt: {
4406      uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
4407      Register out = out_loc.AsRegister<Register>();
4408      if (index.IsConstant()) {
4409        size_t offset =
4410            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4411        __ LoadFromOffset(kLoadWord, out, obj, offset);
4412      } else {
4413        __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
4414        __ LoadFromOffset(kLoadWord, out, IP, data_offset);
4415      }
4416      break;
4417    }
4418
4419    case Primitive::kPrimNot: {
4420      static_assert(
4421          sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
4422          "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
4423      uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
4424      // /* HeapReference<Object> */ out =
4425      //     *(obj + data_offset + index * sizeof(HeapReference<Object>))
4426      if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
4427        Location temp = locations->GetTemp(0);
4428        // Note that a potential implicit null check is handled in this
4429        // CodeGeneratorARM::GenerateArrayLoadWithBakerReadBarrier call.
4430        codegen_->GenerateArrayLoadWithBakerReadBarrier(
4431            instruction, out_loc, obj, data_offset, index, temp, /* needs_null_check */ true);
4432      } else {
4433        Register out = out_loc.AsRegister<Register>();
4434        if (index.IsConstant()) {
4435          size_t offset =
4436              (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4437          __ LoadFromOffset(kLoadWord, out, obj, offset);
4438          codegen_->MaybeRecordImplicitNullCheck(instruction);
4439          // If read barriers are enabled, emit read barriers other than
4440          // Baker's using a slow path (and also unpoison the loaded
4441          // reference, if heap poisoning is enabled).
4442          codegen_->MaybeGenerateReadBarrierSlow(instruction, out_loc, out_loc, obj_loc, offset);
4443        } else {
4444          __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
4445          __ LoadFromOffset(kLoadWord, out, IP, data_offset);
4446          codegen_->MaybeRecordImplicitNullCheck(instruction);
4447          // If read barriers are enabled, emit read barriers other than
4448          // Baker's using a slow path (and also unpoison the loaded
4449          // reference, if heap poisoning is enabled).
4450          codegen_->MaybeGenerateReadBarrierSlow(
4451              instruction, out_loc, out_loc, obj_loc, data_offset, index);
4452        }
4453      }
4454      break;
4455    }
4456
4457    case Primitive::kPrimLong: {
4458      uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
4459      if (index.IsConstant()) {
4460        size_t offset =
4461            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
4462        __ LoadFromOffset(kLoadWordPair, out_loc.AsRegisterPairLow<Register>(), obj, offset);
4463      } else {
4464        __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
4465        __ LoadFromOffset(kLoadWordPair, out_loc.AsRegisterPairLow<Register>(), IP, data_offset);
4466      }
4467      break;
4468    }
4469
4470    case Primitive::kPrimFloat: {
4471      uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
4472      SRegister out = out_loc.AsFpuRegister<SRegister>();
4473      if (index.IsConstant()) {
4474        size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4475        __ LoadSFromOffset(out, obj, offset);
4476      } else {
4477        __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
4478        __ LoadSFromOffset(out, IP, data_offset);
4479      }
4480      break;
4481    }
4482
4483    case Primitive::kPrimDouble: {
4484      uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
4485      SRegister out = out_loc.AsFpuRegisterPairLow<SRegister>();
4486      if (index.IsConstant()) {
4487        size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
4488        __ LoadDFromOffset(FromLowSToD(out), obj, offset);
4489      } else {
4490        __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
4491        __ LoadDFromOffset(FromLowSToD(out), IP, data_offset);
4492      }
4493      break;
4494    }
4495
4496    case Primitive::kPrimVoid:
4497      LOG(FATAL) << "Unreachable type " << type;
4498      UNREACHABLE();
4499  }
4500
4501  if (type == Primitive::kPrimNot) {
4502    // Potential implicit null checks, in the case of reference
4503    // arrays, are handled in the previous switch statement.
4504  } else {
4505    codegen_->MaybeRecordImplicitNullCheck(instruction);
4506  }
4507}
4508
4509void LocationsBuilderARM::VisitArraySet(HArraySet* instruction) {
4510  Primitive::Type value_type = instruction->GetComponentType();
4511
4512  bool needs_write_barrier =
4513      CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
4514  bool may_need_runtime_call_for_type_check = instruction->NeedsTypeCheck();
4515  bool object_array_set_with_read_barrier =
4516      kEmitCompilerReadBarrier && (value_type == Primitive::kPrimNot);
4517
4518  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
4519      instruction,
4520      (may_need_runtime_call_for_type_check || object_array_set_with_read_barrier) ?
4521          LocationSummary::kCallOnSlowPath :
4522          LocationSummary::kNoCall);
4523
4524  locations->SetInAt(0, Location::RequiresRegister());
4525  locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
4526  if (Primitive::IsFloatingPointType(value_type)) {
4527    locations->SetInAt(2, Location::RequiresFpuRegister());
4528  } else {
4529    locations->SetInAt(2, Location::RequiresRegister());
4530  }
4531  if (needs_write_barrier) {
4532    // Temporary registers for the write barrier.
4533    locations->AddTemp(Location::RequiresRegister());  // Possibly used for ref. poisoning too.
4534    locations->AddTemp(Location::RequiresRegister());
4535  }
4536}
4537
4538void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) {
4539  LocationSummary* locations = instruction->GetLocations();
4540  Location array_loc = locations->InAt(0);
4541  Register array = array_loc.AsRegister<Register>();
4542  Location index = locations->InAt(1);
4543  Primitive::Type value_type = instruction->GetComponentType();
4544  bool may_need_runtime_call_for_type_check = instruction->NeedsTypeCheck();
4545  bool needs_write_barrier =
4546      CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
4547
4548  switch (value_type) {
4549    case Primitive::kPrimBoolean:
4550    case Primitive::kPrimByte: {
4551      uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
4552      Register value = locations->InAt(2).AsRegister<Register>();
4553      if (index.IsConstant()) {
4554        size_t offset =
4555            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
4556        __ StoreToOffset(kStoreByte, value, array, offset);
4557      } else {
4558        __ add(IP, array, ShifterOperand(index.AsRegister<Register>()));
4559        __ StoreToOffset(kStoreByte, value, IP, data_offset);
4560      }
4561      break;
4562    }
4563
4564    case Primitive::kPrimShort:
4565    case Primitive::kPrimChar: {
4566      uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
4567      Register value = locations->InAt(2).AsRegister<Register>();
4568      if (index.IsConstant()) {
4569        size_t offset =
4570            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
4571        __ StoreToOffset(kStoreHalfword, value, array, offset);
4572      } else {
4573        __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
4574        __ StoreToOffset(kStoreHalfword, value, IP, data_offset);
4575      }
4576      break;
4577    }
4578
4579    case Primitive::kPrimNot: {
4580      uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
4581      Location value_loc = locations->InAt(2);
4582      Register value = value_loc.AsRegister<Register>();
4583      Register source = value;
4584
4585      if (instruction->InputAt(2)->IsNullConstant()) {
4586        // Just setting null.
4587        if (index.IsConstant()) {
4588          size_t offset =
4589              (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4590          __ StoreToOffset(kStoreWord, source, array, offset);
4591        } else {
4592          DCHECK(index.IsRegister()) << index;
4593          __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
4594          __ StoreToOffset(kStoreWord, source, IP, data_offset);
4595        }
4596        codegen_->MaybeRecordImplicitNullCheck(instruction);
4597        DCHECK(!needs_write_barrier);
4598        DCHECK(!may_need_runtime_call_for_type_check);
4599        break;
4600      }
4601
4602      DCHECK(needs_write_barrier);
4603      Register temp1 = locations->GetTemp(0).AsRegister<Register>();
4604      Register temp2 = locations->GetTemp(1).AsRegister<Register>();
4605      uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
4606      uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
4607      uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
4608      Label done;
4609      SlowPathCode* slow_path = nullptr;
4610
4611      if (may_need_runtime_call_for_type_check) {
4612        slow_path = new (GetGraph()->GetArena()) ArraySetSlowPathARM(instruction);
4613        codegen_->AddSlowPath(slow_path);
4614        if (instruction->GetValueCanBeNull()) {
4615          Label non_zero;
4616          __ CompareAndBranchIfNonZero(value, &non_zero);
4617          if (index.IsConstant()) {
4618            size_t offset =
4619               (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4620            __ StoreToOffset(kStoreWord, value, array, offset);
4621          } else {
4622            DCHECK(index.IsRegister()) << index;
4623            __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
4624            __ StoreToOffset(kStoreWord, value, IP, data_offset);
4625          }
4626          codegen_->MaybeRecordImplicitNullCheck(instruction);
4627          __ b(&done);
4628          __ Bind(&non_zero);
4629        }
4630
4631        if (kEmitCompilerReadBarrier) {
4632          // When read barriers are enabled, the type checking
4633          // instrumentation requires two read barriers:
4634          //
4635          //   __ Mov(temp2, temp1);
4636          //   // /* HeapReference<Class> */ temp1 = temp1->component_type_
4637          //   __ LoadFromOffset(kLoadWord, temp1, temp1, component_offset);
4638          //   codegen_->GenerateReadBarrierSlow(
4639          //       instruction, temp1_loc, temp1_loc, temp2_loc, component_offset);
4640          //
4641          //   // /* HeapReference<Class> */ temp2 = value->klass_
4642          //   __ LoadFromOffset(kLoadWord, temp2, value, class_offset);
4643          //   codegen_->GenerateReadBarrierSlow(
4644          //       instruction, temp2_loc, temp2_loc, value_loc, class_offset, temp1_loc);
4645          //
4646          //   __ cmp(temp1, ShifterOperand(temp2));
4647          //
4648          // However, the second read barrier may trash `temp`, as it
4649          // is a temporary register, and as such would not be saved
4650          // along with live registers before calling the runtime (nor
4651          // restored afterwards).  So in this case, we bail out and
4652          // delegate the work to the array set slow path.
4653          //
4654          // TODO: Extend the register allocator to support a new
4655          // "(locally) live temp" location so as to avoid always
4656          // going into the slow path when read barriers are enabled.
4657          __ b(slow_path->GetEntryLabel());
4658        } else {
4659          // /* HeapReference<Class> */ temp1 = array->klass_
4660          __ LoadFromOffset(kLoadWord, temp1, array, class_offset);
4661          codegen_->MaybeRecordImplicitNullCheck(instruction);
4662          __ MaybeUnpoisonHeapReference(temp1);
4663
4664          // /* HeapReference<Class> */ temp1 = temp1->component_type_
4665          __ LoadFromOffset(kLoadWord, temp1, temp1, component_offset);
4666          // /* HeapReference<Class> */ temp2 = value->klass_
4667          __ LoadFromOffset(kLoadWord, temp2, value, class_offset);
4668          // If heap poisoning is enabled, no need to unpoison `temp1`
4669          // nor `temp2`, as we are comparing two poisoned references.
4670          __ cmp(temp1, ShifterOperand(temp2));
4671
4672          if (instruction->StaticTypeOfArrayIsObjectArray()) {
4673            Label do_put;
4674            __ b(&do_put, EQ);
4675            // If heap poisoning is enabled, the `temp1` reference has
4676            // not been unpoisoned yet; unpoison it now.
4677            __ MaybeUnpoisonHeapReference(temp1);
4678
4679            // /* HeapReference<Class> */ temp1 = temp1->super_class_
4680            __ LoadFromOffset(kLoadWord, temp1, temp1, super_offset);
4681            // If heap poisoning is enabled, no need to unpoison
4682            // `temp1`, as we are comparing against null below.
4683            __ CompareAndBranchIfNonZero(temp1, slow_path->GetEntryLabel());
4684            __ Bind(&do_put);
4685          } else {
4686            __ b(slow_path->GetEntryLabel(), NE);
4687          }
4688        }
4689      }
4690
4691      if (kPoisonHeapReferences) {
4692        // Note that in the case where `value` is a null reference,
4693        // we do not enter this block, as a null reference does not
4694        // need poisoning.
4695        DCHECK_EQ(value_type, Primitive::kPrimNot);
4696        __ Mov(temp1, value);
4697        __ PoisonHeapReference(temp1);
4698        source = temp1;
4699      }
4700
4701      if (index.IsConstant()) {
4702        size_t offset =
4703            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4704        __ StoreToOffset(kStoreWord, source, array, offset);
4705      } else {
4706        DCHECK(index.IsRegister()) << index;
4707        __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
4708        __ StoreToOffset(kStoreWord, source, IP, data_offset);
4709      }
4710
4711      if (!may_need_runtime_call_for_type_check) {
4712        codegen_->MaybeRecordImplicitNullCheck(instruction);
4713      }
4714
4715      codegen_->MarkGCCard(temp1, temp2, array, value, instruction->GetValueCanBeNull());
4716
4717      if (done.IsLinked()) {
4718        __ Bind(&done);
4719      }
4720
4721      if (slow_path != nullptr) {
4722        __ Bind(slow_path->GetExitLabel());
4723      }
4724
4725      break;
4726    }
4727
4728    case Primitive::kPrimInt: {
4729      uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
4730      Register value = locations->InAt(2).AsRegister<Register>();
4731      if (index.IsConstant()) {
4732        size_t offset =
4733            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4734        __ StoreToOffset(kStoreWord, value, array, offset);
4735      } else {
4736        DCHECK(index.IsRegister()) << index;
4737        __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
4738        __ StoreToOffset(kStoreWord, value, IP, data_offset);
4739      }
4740      break;
4741    }
4742
4743    case Primitive::kPrimLong: {
4744      uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
4745      Location value = locations->InAt(2);
4746      if (index.IsConstant()) {
4747        size_t offset =
4748            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
4749        __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), array, offset);
4750      } else {
4751        __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
4752        __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), IP, data_offset);
4753      }
4754      break;
4755    }
4756
4757    case Primitive::kPrimFloat: {
4758      uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
4759      Location value = locations->InAt(2);
4760      DCHECK(value.IsFpuRegister());
4761      if (index.IsConstant()) {
4762        size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4763        __ StoreSToOffset(value.AsFpuRegister<SRegister>(), array, offset);
4764      } else {
4765        __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
4766        __ StoreSToOffset(value.AsFpuRegister<SRegister>(), IP, data_offset);
4767      }
4768      break;
4769    }
4770
4771    case Primitive::kPrimDouble: {
4772      uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
4773      Location value = locations->InAt(2);
4774      DCHECK(value.IsFpuRegisterPair());
4775      if (index.IsConstant()) {
4776        size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
4777        __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), array, offset);
4778      } else {
4779        __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
4780        __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), IP, data_offset);
4781      }
4782
4783      break;
4784    }
4785
4786    case Primitive::kPrimVoid:
4787      LOG(FATAL) << "Unreachable type " << value_type;
4788      UNREACHABLE();
4789  }
4790
4791  // Objects are handled in the switch.
4792  if (value_type != Primitive::kPrimNot) {
4793    codegen_->MaybeRecordImplicitNullCheck(instruction);
4794  }
4795}
4796
4797void LocationsBuilderARM::VisitArrayLength(HArrayLength* instruction) {
4798  LocationSummary* locations =
4799      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
4800  locations->SetInAt(0, Location::RequiresRegister());
4801  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
4802}
4803
4804void InstructionCodeGeneratorARM::VisitArrayLength(HArrayLength* instruction) {
4805  LocationSummary* locations = instruction->GetLocations();
4806  uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
4807  Register obj = locations->InAt(0).AsRegister<Register>();
4808  Register out = locations->Out().AsRegister<Register>();
4809  __ LoadFromOffset(kLoadWord, out, obj, offset);
4810  codegen_->MaybeRecordImplicitNullCheck(instruction);
4811}
4812
4813void LocationsBuilderARM::VisitBoundsCheck(HBoundsCheck* instruction) {
4814  LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
4815      ? LocationSummary::kCallOnSlowPath
4816      : LocationSummary::kNoCall;
4817  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
4818  locations->SetInAt(0, Location::RequiresRegister());
4819  locations->SetInAt(1, Location::RequiresRegister());
4820  if (instruction->HasUses()) {
4821    locations->SetOut(Location::SameAsFirstInput());
4822  }
4823}
4824
4825void InstructionCodeGeneratorARM::VisitBoundsCheck(HBoundsCheck* instruction) {
4826  LocationSummary* locations = instruction->GetLocations();
4827  SlowPathCode* slow_path =
4828      new (GetGraph()->GetArena()) BoundsCheckSlowPathARM(instruction);
4829  codegen_->AddSlowPath(slow_path);
4830
4831  Register index = locations->InAt(0).AsRegister<Register>();
4832  Register length = locations->InAt(1).AsRegister<Register>();
4833
4834  __ cmp(index, ShifterOperand(length));
4835  __ b(slow_path->GetEntryLabel(), HS);
4836}
4837
4838void CodeGeneratorARM::MarkGCCard(Register temp,
4839                                  Register card,
4840                                  Register object,
4841                                  Register value,
4842                                  bool can_be_null) {
4843  Label is_null;
4844  if (can_be_null) {
4845    __ CompareAndBranchIfZero(value, &is_null);
4846  }
4847  __ LoadFromOffset(kLoadWord, card, TR, Thread::CardTableOffset<kArmWordSize>().Int32Value());
4848  __ Lsr(temp, object, gc::accounting::CardTable::kCardShift);
4849  __ strb(card, Address(card, temp));
4850  if (can_be_null) {
4851    __ Bind(&is_null);
4852  }
4853}
4854
4855void LocationsBuilderARM::VisitParallelMove(HParallelMove* instruction ATTRIBUTE_UNUSED) {
4856  LOG(FATAL) << "Unreachable";
4857}
4858
4859void InstructionCodeGeneratorARM::VisitParallelMove(HParallelMove* instruction) {
4860  codegen_->GetMoveResolver()->EmitNativeCode(instruction);
4861}
4862
4863void LocationsBuilderARM::VisitSuspendCheck(HSuspendCheck* instruction) {
4864  new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
4865}
4866
4867void InstructionCodeGeneratorARM::VisitSuspendCheck(HSuspendCheck* instruction) {
4868  HBasicBlock* block = instruction->GetBlock();
4869  if (block->GetLoopInformation() != nullptr) {
4870    DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
4871    // The back edge will generate the suspend check.
4872    return;
4873  }
4874  if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
4875    // The goto will generate the suspend check.
4876    return;
4877  }
4878  GenerateSuspendCheck(instruction, nullptr);
4879}
4880
4881void InstructionCodeGeneratorARM::GenerateSuspendCheck(HSuspendCheck* instruction,
4882                                                       HBasicBlock* successor) {
4883  SuspendCheckSlowPathARM* slow_path =
4884      down_cast<SuspendCheckSlowPathARM*>(instruction->GetSlowPath());
4885  if (slow_path == nullptr) {
4886    slow_path = new (GetGraph()->GetArena()) SuspendCheckSlowPathARM(instruction, successor);
4887    instruction->SetSlowPath(slow_path);
4888    codegen_->AddSlowPath(slow_path);
4889    if (successor != nullptr) {
4890      DCHECK(successor->IsLoopHeader());
4891      codegen_->ClearSpillSlotsFromLoopPhisInStackMap(instruction);
4892    }
4893  } else {
4894    DCHECK_EQ(slow_path->GetSuccessor(), successor);
4895  }
4896
4897  __ LoadFromOffset(
4898      kLoadUnsignedHalfword, IP, TR, Thread::ThreadFlagsOffset<kArmWordSize>().Int32Value());
4899  if (successor == nullptr) {
4900    __ CompareAndBranchIfNonZero(IP, slow_path->GetEntryLabel());
4901    __ Bind(slow_path->GetReturnLabel());
4902  } else {
4903    __ CompareAndBranchIfZero(IP, codegen_->GetLabelOf(successor));
4904    __ b(slow_path->GetEntryLabel());
4905  }
4906}
4907
4908ArmAssembler* ParallelMoveResolverARM::GetAssembler() const {
4909  return codegen_->GetAssembler();
4910}
4911
4912void ParallelMoveResolverARM::EmitMove(size_t index) {
4913  MoveOperands* move = moves_[index];
4914  Location source = move->GetSource();
4915  Location destination = move->GetDestination();
4916
4917  if (source.IsRegister()) {
4918    if (destination.IsRegister()) {
4919      __ Mov(destination.AsRegister<Register>(), source.AsRegister<Register>());
4920    } else if (destination.IsFpuRegister()) {
4921      __ vmovsr(destination.AsFpuRegister<SRegister>(), source.AsRegister<Register>());
4922    } else {
4923      DCHECK(destination.IsStackSlot());
4924      __ StoreToOffset(kStoreWord, source.AsRegister<Register>(),
4925                       SP, destination.GetStackIndex());
4926    }
4927  } else if (source.IsStackSlot()) {
4928    if (destination.IsRegister()) {
4929      __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(),
4930                        SP, source.GetStackIndex());
4931    } else if (destination.IsFpuRegister()) {
4932      __ LoadSFromOffset(destination.AsFpuRegister<SRegister>(), SP, source.GetStackIndex());
4933    } else {
4934      DCHECK(destination.IsStackSlot());
4935      __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
4936      __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4937    }
4938  } else if (source.IsFpuRegister()) {
4939    if (destination.IsRegister()) {
4940      __ vmovrs(destination.AsRegister<Register>(), source.AsFpuRegister<SRegister>());
4941    } else if (destination.IsFpuRegister()) {
4942      __ vmovs(destination.AsFpuRegister<SRegister>(), source.AsFpuRegister<SRegister>());
4943    } else {
4944      DCHECK(destination.IsStackSlot());
4945      __ StoreSToOffset(source.AsFpuRegister<SRegister>(), SP, destination.GetStackIndex());
4946    }
4947  } else if (source.IsDoubleStackSlot()) {
4948    if (destination.IsDoubleStackSlot()) {
4949      __ LoadDFromOffset(DTMP, SP, source.GetStackIndex());
4950      __ StoreDToOffset(DTMP, SP, destination.GetStackIndex());
4951    } else if (destination.IsRegisterPair()) {
4952      DCHECK(ExpectedPairLayout(destination));
4953      __ LoadFromOffset(
4954          kLoadWordPair, destination.AsRegisterPairLow<Register>(), SP, source.GetStackIndex());
4955    } else {
4956      DCHECK(destination.IsFpuRegisterPair()) << destination;
4957      __ LoadDFromOffset(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
4958                         SP,
4959                         source.GetStackIndex());
4960    }
4961  } else if (source.IsRegisterPair()) {
4962    if (destination.IsRegisterPair()) {
4963      __ Mov(destination.AsRegisterPairLow<Register>(), source.AsRegisterPairLow<Register>());
4964      __ Mov(destination.AsRegisterPairHigh<Register>(), source.AsRegisterPairHigh<Register>());
4965    } else if (destination.IsFpuRegisterPair()) {
4966      __ vmovdrr(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
4967                 source.AsRegisterPairLow<Register>(),
4968                 source.AsRegisterPairHigh<Register>());
4969    } else {
4970      DCHECK(destination.IsDoubleStackSlot()) << destination;
4971      DCHECK(ExpectedPairLayout(source));
4972      __ StoreToOffset(
4973          kStoreWordPair, source.AsRegisterPairLow<Register>(), SP, destination.GetStackIndex());
4974    }
4975  } else if (source.IsFpuRegisterPair()) {
4976    if (destination.IsRegisterPair()) {
4977      __ vmovrrd(destination.AsRegisterPairLow<Register>(),
4978                 destination.AsRegisterPairHigh<Register>(),
4979                 FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()));
4980    } else if (destination.IsFpuRegisterPair()) {
4981      __ vmovd(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
4982               FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()));
4983    } else {
4984      DCHECK(destination.IsDoubleStackSlot()) << destination;
4985      __ StoreDToOffset(FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()),
4986                        SP,
4987                        destination.GetStackIndex());
4988    }
4989  } else {
4990    DCHECK(source.IsConstant()) << source;
4991    HConstant* constant = source.GetConstant();
4992    if (constant->IsIntConstant() || constant->IsNullConstant()) {
4993      int32_t value = CodeGenerator::GetInt32ValueOf(constant);
4994      if (destination.IsRegister()) {
4995        __ LoadImmediate(destination.AsRegister<Register>(), value);
4996      } else {
4997        DCHECK(destination.IsStackSlot());
4998        __ LoadImmediate(IP, value);
4999        __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
5000      }
5001    } else if (constant->IsLongConstant()) {
5002      int64_t value = constant->AsLongConstant()->GetValue();
5003      if (destination.IsRegisterPair()) {
5004        __ LoadImmediate(destination.AsRegisterPairLow<Register>(), Low32Bits(value));
5005        __ LoadImmediate(destination.AsRegisterPairHigh<Register>(), High32Bits(value));
5006      } else {
5007        DCHECK(destination.IsDoubleStackSlot()) << destination;
5008        __ LoadImmediate(IP, Low32Bits(value));
5009        __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
5010        __ LoadImmediate(IP, High32Bits(value));
5011        __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
5012      }
5013    } else if (constant->IsDoubleConstant()) {
5014      double value = constant->AsDoubleConstant()->GetValue();
5015      if (destination.IsFpuRegisterPair()) {
5016        __ LoadDImmediate(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()), value);
5017      } else {
5018        DCHECK(destination.IsDoubleStackSlot()) << destination;
5019        uint64_t int_value = bit_cast<uint64_t, double>(value);
5020        __ LoadImmediate(IP, Low32Bits(int_value));
5021        __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
5022        __ LoadImmediate(IP, High32Bits(int_value));
5023        __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
5024      }
5025    } else {
5026      DCHECK(constant->IsFloatConstant()) << constant->DebugName();
5027      float value = constant->AsFloatConstant()->GetValue();
5028      if (destination.IsFpuRegister()) {
5029        __ LoadSImmediate(destination.AsFpuRegister<SRegister>(), value);
5030      } else {
5031        DCHECK(destination.IsStackSlot());
5032        __ LoadImmediate(IP, bit_cast<int32_t, float>(value));
5033        __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
5034      }
5035    }
5036  }
5037}
5038
5039void ParallelMoveResolverARM::Exchange(Register reg, int mem) {
5040  __ Mov(IP, reg);
5041  __ LoadFromOffset(kLoadWord, reg, SP, mem);
5042  __ StoreToOffset(kStoreWord, IP, SP, mem);
5043}
5044
5045void ParallelMoveResolverARM::Exchange(int mem1, int mem2) {
5046  ScratchRegisterScope ensure_scratch(this, IP, R0, codegen_->GetNumberOfCoreRegisters());
5047  int stack_offset = ensure_scratch.IsSpilled() ? kArmWordSize : 0;
5048  __ LoadFromOffset(kLoadWord, static_cast<Register>(ensure_scratch.GetRegister()),
5049                    SP, mem1 + stack_offset);
5050  __ LoadFromOffset(kLoadWord, IP, SP, mem2 + stack_offset);
5051  __ StoreToOffset(kStoreWord, static_cast<Register>(ensure_scratch.GetRegister()),
5052                   SP, mem2 + stack_offset);
5053  __ StoreToOffset(kStoreWord, IP, SP, mem1 + stack_offset);
5054}
5055
5056void ParallelMoveResolverARM::EmitSwap(size_t index) {
5057  MoveOperands* move = moves_[index];
5058  Location source = move->GetSource();
5059  Location destination = move->GetDestination();
5060
5061  if (source.IsRegister() && destination.IsRegister()) {
5062    DCHECK_NE(source.AsRegister<Register>(), IP);
5063    DCHECK_NE(destination.AsRegister<Register>(), IP);
5064    __ Mov(IP, source.AsRegister<Register>());
5065    __ Mov(source.AsRegister<Register>(), destination.AsRegister<Register>());
5066    __ Mov(destination.AsRegister<Register>(), IP);
5067  } else if (source.IsRegister() && destination.IsStackSlot()) {
5068    Exchange(source.AsRegister<Register>(), destination.GetStackIndex());
5069  } else if (source.IsStackSlot() && destination.IsRegister()) {
5070    Exchange(destination.AsRegister<Register>(), source.GetStackIndex());
5071  } else if (source.IsStackSlot() && destination.IsStackSlot()) {
5072    Exchange(source.GetStackIndex(), destination.GetStackIndex());
5073  } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
5074    __ vmovrs(IP, source.AsFpuRegister<SRegister>());
5075    __ vmovs(source.AsFpuRegister<SRegister>(), destination.AsFpuRegister<SRegister>());
5076    __ vmovsr(destination.AsFpuRegister<SRegister>(), IP);
5077  } else if (source.IsRegisterPair() && destination.IsRegisterPair()) {
5078    __ vmovdrr(DTMP, source.AsRegisterPairLow<Register>(), source.AsRegisterPairHigh<Register>());
5079    __ Mov(source.AsRegisterPairLow<Register>(), destination.AsRegisterPairLow<Register>());
5080    __ Mov(source.AsRegisterPairHigh<Register>(), destination.AsRegisterPairHigh<Register>());
5081    __ vmovrrd(destination.AsRegisterPairLow<Register>(),
5082               destination.AsRegisterPairHigh<Register>(),
5083               DTMP);
5084  } else if (source.IsRegisterPair() || destination.IsRegisterPair()) {
5085    Register low_reg = source.IsRegisterPair()
5086        ? source.AsRegisterPairLow<Register>()
5087        : destination.AsRegisterPairLow<Register>();
5088    int mem = source.IsRegisterPair()
5089        ? destination.GetStackIndex()
5090        : source.GetStackIndex();
5091    DCHECK(ExpectedPairLayout(source.IsRegisterPair() ? source : destination));
5092    __ vmovdrr(DTMP, low_reg, static_cast<Register>(low_reg + 1));
5093    __ LoadFromOffset(kLoadWordPair, low_reg, SP, mem);
5094    __ StoreDToOffset(DTMP, SP, mem);
5095  } else if (source.IsFpuRegisterPair() && destination.IsFpuRegisterPair()) {
5096    DRegister first = FromLowSToD(source.AsFpuRegisterPairLow<SRegister>());
5097    DRegister second = FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>());
5098    __ vmovd(DTMP, first);
5099    __ vmovd(first, second);
5100    __ vmovd(second, DTMP);
5101  } else if (source.IsFpuRegisterPair() || destination.IsFpuRegisterPair()) {
5102    DRegister reg = source.IsFpuRegisterPair()
5103        ? FromLowSToD(source.AsFpuRegisterPairLow<SRegister>())
5104        : FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>());
5105    int mem = source.IsFpuRegisterPair()
5106        ? destination.GetStackIndex()
5107        : source.GetStackIndex();
5108    __ vmovd(DTMP, reg);
5109    __ LoadDFromOffset(reg, SP, mem);
5110    __ StoreDToOffset(DTMP, SP, mem);
5111  } else if (source.IsFpuRegister() || destination.IsFpuRegister()) {
5112    SRegister reg = source.IsFpuRegister() ? source.AsFpuRegister<SRegister>()
5113                                           : destination.AsFpuRegister<SRegister>();
5114    int mem = source.IsFpuRegister()
5115        ? destination.GetStackIndex()
5116        : source.GetStackIndex();
5117
5118    __ vmovrs(IP, reg);
5119    __ LoadSFromOffset(reg, SP, mem);
5120    __ StoreToOffset(kStoreWord, IP, SP, mem);
5121  } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
5122    Exchange(source.GetStackIndex(), destination.GetStackIndex());
5123    Exchange(source.GetHighStackIndex(kArmWordSize), destination.GetHighStackIndex(kArmWordSize));
5124  } else {
5125    LOG(FATAL) << "Unimplemented" << source << " <-> " << destination;
5126  }
5127}
5128
5129void ParallelMoveResolverARM::SpillScratch(int reg) {
5130  __ Push(static_cast<Register>(reg));
5131}
5132
5133void ParallelMoveResolverARM::RestoreScratch(int reg) {
5134  __ Pop(static_cast<Register>(reg));
5135}
5136
5137void LocationsBuilderARM::VisitLoadClass(HLoadClass* cls) {
5138  InvokeRuntimeCallingConvention calling_convention;
5139  CodeGenerator::CreateLoadClassLocationSummary(
5140      cls,
5141      Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
5142      Location::RegisterLocation(R0),
5143      /* code_generator_supports_read_barrier */ true);
5144}
5145
5146void InstructionCodeGeneratorARM::VisitLoadClass(HLoadClass* cls) {
5147  LocationSummary* locations = cls->GetLocations();
5148  if (cls->NeedsAccessCheck()) {
5149    codegen_->MoveConstant(locations->GetTemp(0), cls->GetTypeIndex());
5150    codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pInitializeTypeAndVerifyAccess),
5151                            cls,
5152                            cls->GetDexPc(),
5153                            nullptr);
5154    CheckEntrypointTypes<kQuickInitializeTypeAndVerifyAccess, void*, uint32_t>();
5155    return;
5156  }
5157
5158  Location out_loc = locations->Out();
5159  Register out = out_loc.AsRegister<Register>();
5160  Register current_method = locations->InAt(0).AsRegister<Register>();
5161
5162  if (cls->IsReferrersClass()) {
5163    DCHECK(!cls->CanCallRuntime());
5164    DCHECK(!cls->MustGenerateClinitCheck());
5165    // /* GcRoot<mirror::Class> */ out = current_method->declaring_class_
5166    GenerateGcRootFieldLoad(
5167        cls, out_loc, current_method, ArtMethod::DeclaringClassOffset().Int32Value());
5168  } else {
5169    // /* GcRoot<mirror::Class>[] */ out =
5170    //        current_method.ptr_sized_fields_->dex_cache_resolved_types_
5171    __ LoadFromOffset(kLoadWord,
5172                      out,
5173                      current_method,
5174                      ArtMethod::DexCacheResolvedTypesOffset(kArmPointerSize).Int32Value());
5175    // /* GcRoot<mirror::Class> */ out = out[type_index]
5176    GenerateGcRootFieldLoad(cls, out_loc, out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex()));
5177
5178    if (!cls->IsInDexCache() || cls->MustGenerateClinitCheck()) {
5179      DCHECK(cls->CanCallRuntime());
5180      SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
5181          cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
5182      codegen_->AddSlowPath(slow_path);
5183      if (!cls->IsInDexCache()) {
5184        __ CompareAndBranchIfZero(out, slow_path->GetEntryLabel());
5185      }
5186      if (cls->MustGenerateClinitCheck()) {
5187        GenerateClassInitializationCheck(slow_path, out);
5188      } else {
5189        __ Bind(slow_path->GetExitLabel());
5190      }
5191    }
5192  }
5193}
5194
5195void LocationsBuilderARM::VisitClinitCheck(HClinitCheck* check) {
5196  LocationSummary* locations =
5197      new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
5198  locations->SetInAt(0, Location::RequiresRegister());
5199  if (check->HasUses()) {
5200    locations->SetOut(Location::SameAsFirstInput());
5201  }
5202}
5203
5204void InstructionCodeGeneratorARM::VisitClinitCheck(HClinitCheck* check) {
5205  // We assume the class is not null.
5206  SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
5207      check->GetLoadClass(), check, check->GetDexPc(), true);
5208  codegen_->AddSlowPath(slow_path);
5209  GenerateClassInitializationCheck(slow_path,
5210                                   check->GetLocations()->InAt(0).AsRegister<Register>());
5211}
5212
5213void InstructionCodeGeneratorARM::GenerateClassInitializationCheck(
5214    SlowPathCode* slow_path, Register class_reg) {
5215  __ LoadFromOffset(kLoadWord, IP, class_reg, mirror::Class::StatusOffset().Int32Value());
5216  __ cmp(IP, ShifterOperand(mirror::Class::kStatusInitialized));
5217  __ b(slow_path->GetEntryLabel(), LT);
5218  // Even if the initialized flag is set, we may be in a situation where caches are not synced
5219  // properly. Therefore, we do a memory fence.
5220  __ dmb(ISH);
5221  __ Bind(slow_path->GetExitLabel());
5222}
5223
5224void LocationsBuilderARM::VisitLoadString(HLoadString* load) {
5225  LocationSummary::CallKind call_kind = (!load->IsInDexCache() || kEmitCompilerReadBarrier)
5226      ? LocationSummary::kCallOnSlowPath
5227      : LocationSummary::kNoCall;
5228  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(load, call_kind);
5229  locations->SetInAt(0, Location::RequiresRegister());
5230  locations->SetOut(Location::RequiresRegister());
5231}
5232
5233void InstructionCodeGeneratorARM::VisitLoadString(HLoadString* load) {
5234  LocationSummary* locations = load->GetLocations();
5235  Location out_loc = locations->Out();
5236  Register out = out_loc.AsRegister<Register>();
5237  Register current_method = locations->InAt(0).AsRegister<Register>();
5238
5239  // /* GcRoot<mirror::Class> */ out = current_method->declaring_class_
5240  GenerateGcRootFieldLoad(
5241      load, out_loc, current_method, ArtMethod::DeclaringClassOffset().Int32Value());
5242  // /* GcRoot<mirror::String>[] */ out = out->dex_cache_strings_
5243  __ LoadFromOffset(kLoadWord, out, out, mirror::Class::DexCacheStringsOffset().Int32Value());
5244  // /* GcRoot<mirror::String> */ out = out[string_index]
5245  GenerateGcRootFieldLoad(
5246      load, out_loc, out, CodeGenerator::GetCacheOffset(load->GetStringIndex()));
5247
5248  if (!load->IsInDexCache()) {
5249    SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathARM(load);
5250    codegen_->AddSlowPath(slow_path);
5251    __ CompareAndBranchIfZero(out, slow_path->GetEntryLabel());
5252    __ Bind(slow_path->GetExitLabel());
5253  }
5254}
5255
5256static int32_t GetExceptionTlsOffset() {
5257  return Thread::ExceptionOffset<kArmWordSize>().Int32Value();
5258}
5259
5260void LocationsBuilderARM::VisitLoadException(HLoadException* load) {
5261  LocationSummary* locations =
5262      new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
5263  locations->SetOut(Location::RequiresRegister());
5264}
5265
5266void InstructionCodeGeneratorARM::VisitLoadException(HLoadException* load) {
5267  Register out = load->GetLocations()->Out().AsRegister<Register>();
5268  __ LoadFromOffset(kLoadWord, out, TR, GetExceptionTlsOffset());
5269}
5270
5271void LocationsBuilderARM::VisitClearException(HClearException* clear) {
5272  new (GetGraph()->GetArena()) LocationSummary(clear, LocationSummary::kNoCall);
5273}
5274
5275void InstructionCodeGeneratorARM::VisitClearException(HClearException* clear ATTRIBUTE_UNUSED) {
5276  __ LoadImmediate(IP, 0);
5277  __ StoreToOffset(kStoreWord, IP, TR, GetExceptionTlsOffset());
5278}
5279
5280void LocationsBuilderARM::VisitThrow(HThrow* instruction) {
5281  LocationSummary* locations =
5282      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
5283  InvokeRuntimeCallingConvention calling_convention;
5284  locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5285}
5286
5287void InstructionCodeGeneratorARM::VisitThrow(HThrow* instruction) {
5288  codegen_->InvokeRuntime(
5289      QUICK_ENTRY_POINT(pDeliverException), instruction, instruction->GetDexPc(), nullptr);
5290  CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>();
5291}
5292
5293static bool TypeCheckNeedsATemporary(TypeCheckKind type_check_kind) {
5294  return kEmitCompilerReadBarrier &&
5295      (kUseBakerReadBarrier ||
5296       type_check_kind == TypeCheckKind::kAbstractClassCheck ||
5297       type_check_kind == TypeCheckKind::kClassHierarchyCheck ||
5298       type_check_kind == TypeCheckKind::kArrayObjectCheck);
5299}
5300
5301void LocationsBuilderARM::VisitInstanceOf(HInstanceOf* instruction) {
5302  LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
5303  TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
5304  switch (type_check_kind) {
5305    case TypeCheckKind::kExactCheck:
5306    case TypeCheckKind::kAbstractClassCheck:
5307    case TypeCheckKind::kClassHierarchyCheck:
5308    case TypeCheckKind::kArrayObjectCheck:
5309      call_kind =
5310          kEmitCompilerReadBarrier ? LocationSummary::kCallOnSlowPath : LocationSummary::kNoCall;
5311      break;
5312    case TypeCheckKind::kArrayCheck:
5313    case TypeCheckKind::kUnresolvedCheck:
5314    case TypeCheckKind::kInterfaceCheck:
5315      call_kind = LocationSummary::kCallOnSlowPath;
5316      break;
5317  }
5318
5319  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
5320  locations->SetInAt(0, Location::RequiresRegister());
5321  locations->SetInAt(1, Location::RequiresRegister());
5322  // The "out" register is used as a temporary, so it overlaps with the inputs.
5323  // Note that TypeCheckSlowPathARM uses this register too.
5324  locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
5325  // When read barriers are enabled, we need a temporary register for
5326  // some cases.
5327  if (TypeCheckNeedsATemporary(type_check_kind)) {
5328    locations->AddTemp(Location::RequiresRegister());
5329  }
5330}
5331
5332void InstructionCodeGeneratorARM::VisitInstanceOf(HInstanceOf* instruction) {
5333  TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
5334  LocationSummary* locations = instruction->GetLocations();
5335  Location obj_loc = locations->InAt(0);
5336  Register obj = obj_loc.AsRegister<Register>();
5337  Register cls = locations->InAt(1).AsRegister<Register>();
5338  Location out_loc = locations->Out();
5339  Register out = out_loc.AsRegister<Register>();
5340  Location maybe_temp_loc = TypeCheckNeedsATemporary(type_check_kind) ?
5341      locations->GetTemp(0) :
5342      Location::NoLocation();
5343  uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
5344  uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
5345  uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
5346  uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
5347  Label done, zero;
5348  SlowPathCode* slow_path = nullptr;
5349
5350  // Return 0 if `obj` is null.
5351  // avoid null check if we know obj is not null.
5352  if (instruction->MustDoNullCheck()) {
5353    __ CompareAndBranchIfZero(obj, &zero);
5354  }
5355
5356  // /* HeapReference<Class> */ out = obj->klass_
5357  GenerateReferenceLoadTwoRegisters(instruction, out_loc, obj_loc, class_offset, maybe_temp_loc);
5358
5359  switch (type_check_kind) {
5360    case TypeCheckKind::kExactCheck: {
5361      __ cmp(out, ShifterOperand(cls));
5362      // Classes must be equal for the instanceof to succeed.
5363      __ b(&zero, NE);
5364      __ LoadImmediate(out, 1);
5365      __ b(&done);
5366      break;
5367    }
5368
5369    case TypeCheckKind::kAbstractClassCheck: {
5370      // If the class is abstract, we eagerly fetch the super class of the
5371      // object to avoid doing a comparison we know will fail.
5372      Label loop;
5373      __ Bind(&loop);
5374      // /* HeapReference<Class> */ out = out->super_class_
5375      GenerateReferenceLoadOneRegister(instruction, out_loc, super_offset, maybe_temp_loc);
5376      // If `out` is null, we use it for the result, and jump to `done`.
5377      __ CompareAndBranchIfZero(out, &done);
5378      __ cmp(out, ShifterOperand(cls));
5379      __ b(&loop, NE);
5380      __ LoadImmediate(out, 1);
5381      if (zero.IsLinked()) {
5382        __ b(&done);
5383      }
5384      break;
5385    }
5386
5387    case TypeCheckKind::kClassHierarchyCheck: {
5388      // Walk over the class hierarchy to find a match.
5389      Label loop, success;
5390      __ Bind(&loop);
5391      __ cmp(out, ShifterOperand(cls));
5392      __ b(&success, EQ);
5393      // /* HeapReference<Class> */ out = out->super_class_
5394      GenerateReferenceLoadOneRegister(instruction, out_loc, super_offset, maybe_temp_loc);
5395      __ CompareAndBranchIfNonZero(out, &loop);
5396      // If `out` is null, we use it for the result, and jump to `done`.
5397      __ b(&done);
5398      __ Bind(&success);
5399      __ LoadImmediate(out, 1);
5400      if (zero.IsLinked()) {
5401        __ b(&done);
5402      }
5403      break;
5404    }
5405
5406    case TypeCheckKind::kArrayObjectCheck: {
5407      // Do an exact check.
5408      Label exact_check;
5409      __ cmp(out, ShifterOperand(cls));
5410      __ b(&exact_check, EQ);
5411      // Otherwise, we need to check that the object's class is a non-primitive array.
5412      // /* HeapReference<Class> */ out = out->component_type_
5413      GenerateReferenceLoadOneRegister(instruction, out_loc, component_offset, maybe_temp_loc);
5414      // If `out` is null, we use it for the result, and jump to `done`.
5415      __ CompareAndBranchIfZero(out, &done);
5416      __ LoadFromOffset(kLoadUnsignedHalfword, out, out, primitive_offset);
5417      static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot");
5418      __ CompareAndBranchIfNonZero(out, &zero);
5419      __ Bind(&exact_check);
5420      __ LoadImmediate(out, 1);
5421      __ b(&done);
5422      break;
5423    }
5424
5425    case TypeCheckKind::kArrayCheck: {
5426      __ cmp(out, ShifterOperand(cls));
5427      DCHECK(locations->OnlyCallsOnSlowPath());
5428      slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(instruction,
5429                                                                    /* is_fatal */ false);
5430      codegen_->AddSlowPath(slow_path);
5431      __ b(slow_path->GetEntryLabel(), NE);
5432      __ LoadImmediate(out, 1);
5433      if (zero.IsLinked()) {
5434        __ b(&done);
5435      }
5436      break;
5437    }
5438
5439    case TypeCheckKind::kUnresolvedCheck:
5440    case TypeCheckKind::kInterfaceCheck: {
5441      // Note that we indeed only call on slow path, but we always go
5442      // into the slow path for the unresolved and interface check
5443      // cases.
5444      //
5445      // We cannot directly call the InstanceofNonTrivial runtime
5446      // entry point without resorting to a type checking slow path
5447      // here (i.e. by calling InvokeRuntime directly), as it would
5448      // require to assign fixed registers for the inputs of this
5449      // HInstanceOf instruction (following the runtime calling
5450      // convention), which might be cluttered by the potential first
5451      // read barrier emission at the beginning of this method.
5452      //
5453      // TODO: Introduce a new runtime entry point taking the object
5454      // to test (instead of its class) as argument, and let it deal
5455      // with the read barrier issues. This will let us refactor this
5456      // case of the `switch` code as it was previously (with a direct
5457      // call to the runtime not using a type checking slow path).
5458      // This should also be beneficial for the other cases above.
5459      DCHECK(locations->OnlyCallsOnSlowPath());
5460      slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(instruction,
5461                                                                    /* is_fatal */ false);
5462      codegen_->AddSlowPath(slow_path);
5463      __ b(slow_path->GetEntryLabel());
5464      if (zero.IsLinked()) {
5465        __ b(&done);
5466      }
5467      break;
5468    }
5469  }
5470
5471  if (zero.IsLinked()) {
5472    __ Bind(&zero);
5473    __ LoadImmediate(out, 0);
5474  }
5475
5476  if (done.IsLinked()) {
5477    __ Bind(&done);
5478  }
5479
5480  if (slow_path != nullptr) {
5481    __ Bind(slow_path->GetExitLabel());
5482  }
5483}
5484
5485void LocationsBuilderARM::VisitCheckCast(HCheckCast* instruction) {
5486  LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
5487  bool throws_into_catch = instruction->CanThrowIntoCatchBlock();
5488
5489  TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
5490  switch (type_check_kind) {
5491    case TypeCheckKind::kExactCheck:
5492    case TypeCheckKind::kAbstractClassCheck:
5493    case TypeCheckKind::kClassHierarchyCheck:
5494    case TypeCheckKind::kArrayObjectCheck:
5495      call_kind = (throws_into_catch || kEmitCompilerReadBarrier) ?
5496          LocationSummary::kCallOnSlowPath :
5497          LocationSummary::kNoCall;  // In fact, call on a fatal (non-returning) slow path.
5498      break;
5499    case TypeCheckKind::kArrayCheck:
5500    case TypeCheckKind::kUnresolvedCheck:
5501    case TypeCheckKind::kInterfaceCheck:
5502      call_kind = LocationSummary::kCallOnSlowPath;
5503      break;
5504  }
5505
5506  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
5507  locations->SetInAt(0, Location::RequiresRegister());
5508  locations->SetInAt(1, Location::RequiresRegister());
5509  // Note that TypeCheckSlowPathARM uses this "temp" register too.
5510  locations->AddTemp(Location::RequiresRegister());
5511  // When read barriers are enabled, we need an additional temporary
5512  // register for some cases.
5513  if (TypeCheckNeedsATemporary(type_check_kind)) {
5514    locations->AddTemp(Location::RequiresRegister());
5515  }
5516}
5517
5518void InstructionCodeGeneratorARM::VisitCheckCast(HCheckCast* instruction) {
5519  TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
5520  LocationSummary* locations = instruction->GetLocations();
5521  Location obj_loc = locations->InAt(0);
5522  Register obj = obj_loc.AsRegister<Register>();
5523  Register cls = locations->InAt(1).AsRegister<Register>();
5524  Location temp_loc = locations->GetTemp(0);
5525  Register temp = temp_loc.AsRegister<Register>();
5526  Location maybe_temp2_loc = TypeCheckNeedsATemporary(type_check_kind) ?
5527      locations->GetTemp(1) :
5528      Location::NoLocation();
5529  uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
5530  uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
5531  uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
5532  uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
5533
5534  bool is_type_check_slow_path_fatal =
5535      (type_check_kind == TypeCheckKind::kExactCheck ||
5536       type_check_kind == TypeCheckKind::kAbstractClassCheck ||
5537       type_check_kind == TypeCheckKind::kClassHierarchyCheck ||
5538       type_check_kind == TypeCheckKind::kArrayObjectCheck) &&
5539      !instruction->CanThrowIntoCatchBlock();
5540  SlowPathCode* type_check_slow_path =
5541      new (GetGraph()->GetArena()) TypeCheckSlowPathARM(instruction,
5542                                                        is_type_check_slow_path_fatal);
5543  codegen_->AddSlowPath(type_check_slow_path);
5544
5545  Label done;
5546  // Avoid null check if we know obj is not null.
5547  if (instruction->MustDoNullCheck()) {
5548    __ CompareAndBranchIfZero(obj, &done);
5549  }
5550
5551  // /* HeapReference<Class> */ temp = obj->klass_
5552  GenerateReferenceLoadTwoRegisters(instruction, temp_loc, obj_loc, class_offset, maybe_temp2_loc);
5553
5554  switch (type_check_kind) {
5555    case TypeCheckKind::kExactCheck:
5556    case TypeCheckKind::kArrayCheck: {
5557      __ cmp(temp, ShifterOperand(cls));
5558      // Jump to slow path for throwing the exception or doing a
5559      // more involved array check.
5560      __ b(type_check_slow_path->GetEntryLabel(), NE);
5561      break;
5562    }
5563
5564    case TypeCheckKind::kAbstractClassCheck: {
5565      // If the class is abstract, we eagerly fetch the super class of the
5566      // object to avoid doing a comparison we know will fail.
5567      Label loop, compare_classes;
5568      __ Bind(&loop);
5569      // /* HeapReference<Class> */ temp = temp->super_class_
5570      GenerateReferenceLoadOneRegister(instruction, temp_loc, super_offset, maybe_temp2_loc);
5571
5572      // If the class reference currently in `temp` is not null, jump
5573      // to the `compare_classes` label to compare it with the checked
5574      // class.
5575      __ CompareAndBranchIfNonZero(temp, &compare_classes);
5576      // Otherwise, jump to the slow path to throw the exception.
5577      //
5578      // But before, move back the object's class into `temp` before
5579      // going into the slow path, as it has been overwritten in the
5580      // meantime.
5581      // /* HeapReference<Class> */ temp = obj->klass_
5582      GenerateReferenceLoadTwoRegisters(
5583          instruction, temp_loc, obj_loc, class_offset, maybe_temp2_loc);
5584      __ b(type_check_slow_path->GetEntryLabel());
5585
5586      __ Bind(&compare_classes);
5587      __ cmp(temp, ShifterOperand(cls));
5588      __ b(&loop, NE);
5589      break;
5590    }
5591
5592    case TypeCheckKind::kClassHierarchyCheck: {
5593      // Walk over the class hierarchy to find a match.
5594      Label loop;
5595      __ Bind(&loop);
5596      __ cmp(temp, ShifterOperand(cls));
5597      __ b(&done, EQ);
5598
5599      // /* HeapReference<Class> */ temp = temp->super_class_
5600      GenerateReferenceLoadOneRegister(instruction, temp_loc, super_offset, maybe_temp2_loc);
5601
5602      // If the class reference currently in `temp` is not null, jump
5603      // back at the beginning of the loop.
5604      __ CompareAndBranchIfNonZero(temp, &loop);
5605      // Otherwise, jump to the slow path to throw the exception.
5606      //
5607      // But before, move back the object's class into `temp` before
5608      // going into the slow path, as it has been overwritten in the
5609      // meantime.
5610      // /* HeapReference<Class> */ temp = obj->klass_
5611      GenerateReferenceLoadTwoRegisters(
5612          instruction, temp_loc, obj_loc, class_offset, maybe_temp2_loc);
5613      __ b(type_check_slow_path->GetEntryLabel());
5614      break;
5615    }
5616
5617    case TypeCheckKind::kArrayObjectCheck: {
5618      // Do an exact check.
5619      Label check_non_primitive_component_type;
5620      __ cmp(temp, ShifterOperand(cls));
5621      __ b(&done, EQ);
5622
5623      // Otherwise, we need to check that the object's class is a non-primitive array.
5624      // /* HeapReference<Class> */ temp = temp->component_type_
5625      GenerateReferenceLoadOneRegister(instruction, temp_loc, component_offset, maybe_temp2_loc);
5626
5627      // If the component type is not null (i.e. the object is indeed
5628      // an array), jump to label `check_non_primitive_component_type`
5629      // to further check that this component type is not a primitive
5630      // type.
5631      __ CompareAndBranchIfNonZero(temp, &check_non_primitive_component_type);
5632      // Otherwise, jump to the slow path to throw the exception.
5633      //
5634      // But before, move back the object's class into `temp` before
5635      // going into the slow path, as it has been overwritten in the
5636      // meantime.
5637      // /* HeapReference<Class> */ temp = obj->klass_
5638      GenerateReferenceLoadTwoRegisters(
5639          instruction, temp_loc, obj_loc, class_offset, maybe_temp2_loc);
5640      __ b(type_check_slow_path->GetEntryLabel());
5641
5642      __ Bind(&check_non_primitive_component_type);
5643      __ LoadFromOffset(kLoadUnsignedHalfword, temp, temp, primitive_offset);
5644      static_assert(Primitive::kPrimNot == 0, "Expected 0 for art::Primitive::kPrimNot");
5645      __ CompareAndBranchIfZero(temp, &done);
5646      // Same comment as above regarding `temp` and the slow path.
5647      // /* HeapReference<Class> */ temp = obj->klass_
5648      GenerateReferenceLoadTwoRegisters(
5649          instruction, temp_loc, obj_loc, class_offset, maybe_temp2_loc);
5650      __ b(type_check_slow_path->GetEntryLabel());
5651      break;
5652    }
5653
5654    case TypeCheckKind::kUnresolvedCheck:
5655    case TypeCheckKind::kInterfaceCheck:
5656      // We always go into the type check slow path for the unresolved
5657      // and interface check cases.
5658      //
5659      // We cannot directly call the CheckCast runtime entry point
5660      // without resorting to a type checking slow path here (i.e. by
5661      // calling InvokeRuntime directly), as it would require to
5662      // assign fixed registers for the inputs of this HInstanceOf
5663      // instruction (following the runtime calling convention), which
5664      // might be cluttered by the potential first read barrier
5665      // emission at the beginning of this method.
5666      //
5667      // TODO: Introduce a new runtime entry point taking the object
5668      // to test (instead of its class) as argument, and let it deal
5669      // with the read barrier issues. This will let us refactor this
5670      // case of the `switch` code as it was previously (with a direct
5671      // call to the runtime not using a type checking slow path).
5672      // This should also be beneficial for the other cases above.
5673      __ b(type_check_slow_path->GetEntryLabel());
5674      break;
5675  }
5676  __ Bind(&done);
5677
5678  __ Bind(type_check_slow_path->GetExitLabel());
5679}
5680
5681void LocationsBuilderARM::VisitMonitorOperation(HMonitorOperation* instruction) {
5682  LocationSummary* locations =
5683      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
5684  InvokeRuntimeCallingConvention calling_convention;
5685  locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5686}
5687
5688void InstructionCodeGeneratorARM::VisitMonitorOperation(HMonitorOperation* instruction) {
5689  codegen_->InvokeRuntime(instruction->IsEnter()
5690        ? QUICK_ENTRY_POINT(pLockObject) : QUICK_ENTRY_POINT(pUnlockObject),
5691      instruction,
5692      instruction->GetDexPc(),
5693      nullptr);
5694  if (instruction->IsEnter()) {
5695    CheckEntrypointTypes<kQuickLockObject, void, mirror::Object*>();
5696  } else {
5697    CheckEntrypointTypes<kQuickUnlockObject, void, mirror::Object*>();
5698  }
5699}
5700
5701void LocationsBuilderARM::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction, AND); }
5702void LocationsBuilderARM::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction, ORR); }
5703void LocationsBuilderARM::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction, EOR); }
5704
5705void LocationsBuilderARM::HandleBitwiseOperation(HBinaryOperation* instruction, Opcode opcode) {
5706  LocationSummary* locations =
5707      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
5708  DCHECK(instruction->GetResultType() == Primitive::kPrimInt
5709         || instruction->GetResultType() == Primitive::kPrimLong);
5710  // Note: GVN reorders commutative operations to have the constant on the right hand side.
5711  locations->SetInAt(0, Location::RequiresRegister());
5712  locations->SetInAt(1, ArmEncodableConstantOrRegister(instruction->InputAt(1), opcode));
5713  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
5714}
5715
5716void InstructionCodeGeneratorARM::VisitAnd(HAnd* instruction) {
5717  HandleBitwiseOperation(instruction);
5718}
5719
5720void InstructionCodeGeneratorARM::VisitOr(HOr* instruction) {
5721  HandleBitwiseOperation(instruction);
5722}
5723
5724void InstructionCodeGeneratorARM::VisitXor(HXor* instruction) {
5725  HandleBitwiseOperation(instruction);
5726}
5727
5728
5729void LocationsBuilderARM::VisitBitwiseNegatedRight(HBitwiseNegatedRight* instruction) {
5730  LocationSummary* locations =
5731      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
5732  DCHECK(instruction->GetResultType() == Primitive::kPrimInt
5733         || instruction->GetResultType() == Primitive::kPrimLong);
5734
5735  locations->SetInAt(0, Location::RequiresRegister());
5736  locations->SetInAt(1, Location::RequiresRegister());
5737  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
5738}
5739
5740void InstructionCodeGeneratorARM::VisitBitwiseNegatedRight(HBitwiseNegatedRight* instruction) {
5741  LocationSummary* locations = instruction->GetLocations();
5742  Location first = locations->InAt(0);
5743  Location second = locations->InAt(1);
5744  Location out = locations->Out();
5745
5746  if (instruction->GetResultType() == Primitive::kPrimInt) {
5747    Register first_reg = first.AsRegister<Register>();
5748    ShifterOperand second_reg(second.AsRegister<Register>());
5749    Register out_reg = out.AsRegister<Register>();
5750
5751    switch (instruction->GetOpKind()) {
5752      case HInstruction::kAnd:
5753        __ bic(out_reg, first_reg, second_reg);
5754        break;
5755      case HInstruction::kOr:
5756        __ orn(out_reg, first_reg, second_reg);
5757        break;
5758      // There is no EON on arm.
5759      case HInstruction::kXor:
5760      default:
5761        LOG(FATAL) << "Unexpected instruction " << instruction->DebugName();
5762        UNREACHABLE();
5763    }
5764    return;
5765
5766  } else {
5767    DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
5768    Register first_low = first.AsRegisterPairLow<Register>();
5769    Register first_high = first.AsRegisterPairHigh<Register>();
5770    ShifterOperand second_low(second.AsRegisterPairLow<Register>());
5771    ShifterOperand second_high(second.AsRegisterPairHigh<Register>());
5772    Register out_low = out.AsRegisterPairLow<Register>();
5773    Register out_high = out.AsRegisterPairHigh<Register>();
5774
5775    switch (instruction->GetOpKind()) {
5776      case HInstruction::kAnd:
5777        __ bic(out_low, first_low, second_low);
5778        __ bic(out_high, first_high, second_high);
5779        break;
5780      case HInstruction::kOr:
5781        __ orn(out_low, first_low, second_low);
5782        __ orn(out_high, first_high, second_high);
5783        break;
5784      // There is no EON on arm.
5785      case HInstruction::kXor:
5786      default:
5787        LOG(FATAL) << "Unexpected instruction " << instruction->DebugName();
5788        UNREACHABLE();
5789    }
5790  }
5791}
5792
5793void InstructionCodeGeneratorARM::GenerateAndConst(Register out, Register first, uint32_t value) {
5794  // Optimize special cases for individual halfs of `and-long` (`and` is simplified earlier).
5795  if (value == 0xffffffffu) {
5796    if (out != first) {
5797      __ mov(out, ShifterOperand(first));
5798    }
5799    return;
5800  }
5801  if (value == 0u) {
5802    __ mov(out, ShifterOperand(0));
5803    return;
5804  }
5805  ShifterOperand so;
5806  if (__ ShifterOperandCanHold(kNoRegister, kNoRegister, AND, value, &so)) {
5807    __ and_(out, first, so);
5808  } else {
5809    DCHECK(__ ShifterOperandCanHold(kNoRegister, kNoRegister, BIC, ~value, &so));
5810    __ bic(out, first, ShifterOperand(~value));
5811  }
5812}
5813
5814void InstructionCodeGeneratorARM::GenerateOrrConst(Register out, Register first, uint32_t value) {
5815  // Optimize special cases for individual halfs of `or-long` (`or` is simplified earlier).
5816  if (value == 0u) {
5817    if (out != first) {
5818      __ mov(out, ShifterOperand(first));
5819    }
5820    return;
5821  }
5822  if (value == 0xffffffffu) {
5823    __ mvn(out, ShifterOperand(0));
5824    return;
5825  }
5826  ShifterOperand so;
5827  if (__ ShifterOperandCanHold(kNoRegister, kNoRegister, ORR, value, &so)) {
5828    __ orr(out, first, so);
5829  } else {
5830    DCHECK(__ ShifterOperandCanHold(kNoRegister, kNoRegister, ORN, ~value, &so));
5831    __ orn(out, first, ShifterOperand(~value));
5832  }
5833}
5834
5835void InstructionCodeGeneratorARM::GenerateEorConst(Register out, Register first, uint32_t value) {
5836  // Optimize special case for individual halfs of `xor-long` (`xor` is simplified earlier).
5837  if (value == 0u) {
5838    if (out != first) {
5839      __ mov(out, ShifterOperand(first));
5840    }
5841    return;
5842  }
5843  __ eor(out, first, ShifterOperand(value));
5844}
5845
5846void InstructionCodeGeneratorARM::HandleBitwiseOperation(HBinaryOperation* instruction) {
5847  LocationSummary* locations = instruction->GetLocations();
5848  Location first = locations->InAt(0);
5849  Location second = locations->InAt(1);
5850  Location out = locations->Out();
5851
5852  if (second.IsConstant()) {
5853    uint64_t value = static_cast<uint64_t>(Int64FromConstant(second.GetConstant()));
5854    uint32_t value_low = Low32Bits(value);
5855    if (instruction->GetResultType() == Primitive::kPrimInt) {
5856      Register first_reg = first.AsRegister<Register>();
5857      Register out_reg = out.AsRegister<Register>();
5858      if (instruction->IsAnd()) {
5859        GenerateAndConst(out_reg, first_reg, value_low);
5860      } else if (instruction->IsOr()) {
5861        GenerateOrrConst(out_reg, first_reg, value_low);
5862      } else {
5863        DCHECK(instruction->IsXor());
5864        GenerateEorConst(out_reg, first_reg, value_low);
5865      }
5866    } else {
5867      DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
5868      uint32_t value_high = High32Bits(value);
5869      Register first_low = first.AsRegisterPairLow<Register>();
5870      Register first_high = first.AsRegisterPairHigh<Register>();
5871      Register out_low = out.AsRegisterPairLow<Register>();
5872      Register out_high = out.AsRegisterPairHigh<Register>();
5873      if (instruction->IsAnd()) {
5874        GenerateAndConst(out_low, first_low, value_low);
5875        GenerateAndConst(out_high, first_high, value_high);
5876      } else if (instruction->IsOr()) {
5877        GenerateOrrConst(out_low, first_low, value_low);
5878        GenerateOrrConst(out_high, first_high, value_high);
5879      } else {
5880        DCHECK(instruction->IsXor());
5881        GenerateEorConst(out_low, first_low, value_low);
5882        GenerateEorConst(out_high, first_high, value_high);
5883      }
5884    }
5885    return;
5886  }
5887
5888  if (instruction->GetResultType() == Primitive::kPrimInt) {
5889    Register first_reg = first.AsRegister<Register>();
5890    ShifterOperand second_reg(second.AsRegister<Register>());
5891    Register out_reg = out.AsRegister<Register>();
5892    if (instruction->IsAnd()) {
5893      __ and_(out_reg, first_reg, second_reg);
5894    } else if (instruction->IsOr()) {
5895      __ orr(out_reg, first_reg, second_reg);
5896    } else {
5897      DCHECK(instruction->IsXor());
5898      __ eor(out_reg, first_reg, second_reg);
5899    }
5900  } else {
5901    DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
5902    Register first_low = first.AsRegisterPairLow<Register>();
5903    Register first_high = first.AsRegisterPairHigh<Register>();
5904    ShifterOperand second_low(second.AsRegisterPairLow<Register>());
5905    ShifterOperand second_high(second.AsRegisterPairHigh<Register>());
5906    Register out_low = out.AsRegisterPairLow<Register>();
5907    Register out_high = out.AsRegisterPairHigh<Register>();
5908    if (instruction->IsAnd()) {
5909      __ and_(out_low, first_low, second_low);
5910      __ and_(out_high, first_high, second_high);
5911    } else if (instruction->IsOr()) {
5912      __ orr(out_low, first_low, second_low);
5913      __ orr(out_high, first_high, second_high);
5914    } else {
5915      DCHECK(instruction->IsXor());
5916      __ eor(out_low, first_low, second_low);
5917      __ eor(out_high, first_high, second_high);
5918    }
5919  }
5920}
5921
5922void InstructionCodeGeneratorARM::GenerateReferenceLoadOneRegister(HInstruction* instruction,
5923                                                                   Location out,
5924                                                                   uint32_t offset,
5925                                                                   Location maybe_temp) {
5926  Register out_reg = out.AsRegister<Register>();
5927  if (kEmitCompilerReadBarrier) {
5928    DCHECK(maybe_temp.IsRegister()) << maybe_temp;
5929    if (kUseBakerReadBarrier) {
5930      // Load with fast path based Baker's read barrier.
5931      // /* HeapReference<Object> */ out = *(out + offset)
5932      codegen_->GenerateFieldLoadWithBakerReadBarrier(
5933          instruction, out, out_reg, offset, maybe_temp, /* needs_null_check */ false);
5934    } else {
5935      // Load with slow path based read barrier.
5936      // Save the value of `out` into `maybe_temp` before overwriting it
5937      // in the following move operation, as we will need it for the
5938      // read barrier below.
5939      __ Mov(maybe_temp.AsRegister<Register>(), out_reg);
5940      // /* HeapReference<Object> */ out = *(out + offset)
5941      __ LoadFromOffset(kLoadWord, out_reg, out_reg, offset);
5942      codegen_->GenerateReadBarrierSlow(instruction, out, out, maybe_temp, offset);
5943    }
5944  } else {
5945    // Plain load with no read barrier.
5946    // /* HeapReference<Object> */ out = *(out + offset)
5947    __ LoadFromOffset(kLoadWord, out_reg, out_reg, offset);
5948    __ MaybeUnpoisonHeapReference(out_reg);
5949  }
5950}
5951
5952void InstructionCodeGeneratorARM::GenerateReferenceLoadTwoRegisters(HInstruction* instruction,
5953                                                                    Location out,
5954                                                                    Location obj,
5955                                                                    uint32_t offset,
5956                                                                    Location maybe_temp) {
5957  Register out_reg = out.AsRegister<Register>();
5958  Register obj_reg = obj.AsRegister<Register>();
5959  if (kEmitCompilerReadBarrier) {
5960    if (kUseBakerReadBarrier) {
5961      DCHECK(maybe_temp.IsRegister()) << maybe_temp;
5962      // Load with fast path based Baker's read barrier.
5963      // /* HeapReference<Object> */ out = *(obj + offset)
5964      codegen_->GenerateFieldLoadWithBakerReadBarrier(
5965          instruction, out, obj_reg, offset, maybe_temp, /* needs_null_check */ false);
5966    } else {
5967      // Load with slow path based read barrier.
5968      // /* HeapReference<Object> */ out = *(obj + offset)
5969      __ LoadFromOffset(kLoadWord, out_reg, obj_reg, offset);
5970      codegen_->GenerateReadBarrierSlow(instruction, out, out, obj, offset);
5971    }
5972  } else {
5973    // Plain load with no read barrier.
5974    // /* HeapReference<Object> */ out = *(obj + offset)
5975    __ LoadFromOffset(kLoadWord, out_reg, obj_reg, offset);
5976    __ MaybeUnpoisonHeapReference(out_reg);
5977  }
5978}
5979
5980void InstructionCodeGeneratorARM::GenerateGcRootFieldLoad(HInstruction* instruction,
5981                                                          Location root,
5982                                                          Register obj,
5983                                                          uint32_t offset) {
5984  Register root_reg = root.AsRegister<Register>();
5985  if (kEmitCompilerReadBarrier) {
5986    if (kUseBakerReadBarrier) {
5987      // Fast path implementation of art::ReadBarrier::BarrierForRoot when
5988      // Baker's read barrier are used:
5989      //
5990      //   root = obj.field;
5991      //   if (Thread::Current()->GetIsGcMarking()) {
5992      //     root = ReadBarrier::Mark(root)
5993      //   }
5994
5995      // /* GcRoot<mirror::Object> */ root = *(obj + offset)
5996      __ LoadFromOffset(kLoadWord, root_reg, obj, offset);
5997      static_assert(
5998          sizeof(mirror::CompressedReference<mirror::Object>) == sizeof(GcRoot<mirror::Object>),
5999          "art::mirror::CompressedReference<mirror::Object> and art::GcRoot<mirror::Object> "
6000          "have different sizes.");
6001      static_assert(sizeof(mirror::CompressedReference<mirror::Object>) == sizeof(int32_t),
6002                    "art::mirror::CompressedReference<mirror::Object> and int32_t "
6003                    "have different sizes.");
6004
6005      // Slow path used to mark the GC root `root`.
6006      SlowPathCode* slow_path =
6007          new (GetGraph()->GetArena()) ReadBarrierMarkSlowPathARM(instruction, root, root);
6008      codegen_->AddSlowPath(slow_path);
6009
6010      // IP = Thread::Current()->GetIsGcMarking()
6011      __ LoadFromOffset(
6012          kLoadWord, IP, TR, Thread::IsGcMarkingOffset<kArmWordSize>().Int32Value());
6013      __ CompareAndBranchIfNonZero(IP, slow_path->GetEntryLabel());
6014      __ Bind(slow_path->GetExitLabel());
6015    } else {
6016      // GC root loaded through a slow path for read barriers other
6017      // than Baker's.
6018      // /* GcRoot<mirror::Object>* */ root = obj + offset
6019      __ AddConstant(root_reg, obj, offset);
6020      // /* mirror::Object* */ root = root->Read()
6021      codegen_->GenerateReadBarrierForRootSlow(instruction, root, root);
6022    }
6023  } else {
6024    // Plain GC root load with no read barrier.
6025    // /* GcRoot<mirror::Object> */ root = *(obj + offset)
6026    __ LoadFromOffset(kLoadWord, root_reg, obj, offset);
6027    // Note that GC roots are not affected by heap poisoning, thus we
6028    // do not have to unpoison `root_reg` here.
6029  }
6030}
6031
6032void CodeGeneratorARM::GenerateFieldLoadWithBakerReadBarrier(HInstruction* instruction,
6033                                                             Location ref,
6034                                                             Register obj,
6035                                                             uint32_t offset,
6036                                                             Location temp,
6037                                                             bool needs_null_check) {
6038  DCHECK(kEmitCompilerReadBarrier);
6039  DCHECK(kUseBakerReadBarrier);
6040
6041  // /* HeapReference<Object> */ ref = *(obj + offset)
6042  Location no_index = Location::NoLocation();
6043  GenerateReferenceLoadWithBakerReadBarrier(
6044      instruction, ref, obj, offset, no_index, temp, needs_null_check);
6045}
6046
6047void CodeGeneratorARM::GenerateArrayLoadWithBakerReadBarrier(HInstruction* instruction,
6048                                                             Location ref,
6049                                                             Register obj,
6050                                                             uint32_t data_offset,
6051                                                             Location index,
6052                                                             Location temp,
6053                                                             bool needs_null_check) {
6054  DCHECK(kEmitCompilerReadBarrier);
6055  DCHECK(kUseBakerReadBarrier);
6056
6057  // /* HeapReference<Object> */ ref =
6058  //     *(obj + data_offset + index * sizeof(HeapReference<Object>))
6059  GenerateReferenceLoadWithBakerReadBarrier(
6060      instruction, ref, obj, data_offset, index, temp, needs_null_check);
6061}
6062
6063void CodeGeneratorARM::GenerateReferenceLoadWithBakerReadBarrier(HInstruction* instruction,
6064                                                                 Location ref,
6065                                                                 Register obj,
6066                                                                 uint32_t offset,
6067                                                                 Location index,
6068                                                                 Location temp,
6069                                                                 bool needs_null_check) {
6070  DCHECK(kEmitCompilerReadBarrier);
6071  DCHECK(kUseBakerReadBarrier);
6072
6073  // In slow path based read barriers, the read barrier call is
6074  // inserted after the original load. However, in fast path based
6075  // Baker's read barriers, we need to perform the load of
6076  // mirror::Object::monitor_ *before* the original reference load.
6077  // This load-load ordering is required by the read barrier.
6078  // The fast path/slow path (for Baker's algorithm) should look like:
6079  //
6080  //   uint32_t rb_state = Lockword(obj->monitor_).ReadBarrierState();
6081  //   lfence;  // Load fence or artificial data dependency to prevent load-load reordering
6082  //   HeapReference<Object> ref = *src;  // Original reference load.
6083  //   bool is_gray = (rb_state == ReadBarrier::gray_ptr_);
6084  //   if (is_gray) {
6085  //     ref = ReadBarrier::Mark(ref);  // Performed by runtime entrypoint slow path.
6086  //   }
6087  //
6088  // Note: the original implementation in ReadBarrier::Barrier is
6089  // slightly more complex as it performs additional checks that we do
6090  // not do here for performance reasons.
6091
6092  Register ref_reg = ref.AsRegister<Register>();
6093  Register temp_reg = temp.AsRegister<Register>();
6094  uint32_t monitor_offset = mirror::Object::MonitorOffset().Int32Value();
6095
6096  // /* int32_t */ monitor = obj->monitor_
6097  __ LoadFromOffset(kLoadWord, temp_reg, obj, monitor_offset);
6098  if (needs_null_check) {
6099    MaybeRecordImplicitNullCheck(instruction);
6100  }
6101  // /* LockWord */ lock_word = LockWord(monitor)
6102  static_assert(sizeof(LockWord) == sizeof(int32_t),
6103                "art::LockWord and int32_t have different sizes.");
6104  // /* uint32_t */ rb_state = lock_word.ReadBarrierState()
6105  __ Lsr(temp_reg, temp_reg, LockWord::kReadBarrierStateShift);
6106  __ and_(temp_reg, temp_reg, ShifterOperand(LockWord::kReadBarrierStateMask));
6107  static_assert(
6108      LockWord::kReadBarrierStateMask == ReadBarrier::rb_ptr_mask_,
6109      "art::LockWord::kReadBarrierStateMask is not equal to art::ReadBarrier::rb_ptr_mask_.");
6110
6111  // Introduce a dependency on the high bits of rb_state, which shall
6112  // be all zeroes, to prevent load-load reordering, and without using
6113  // a memory barrier (which would be more expensive).
6114  // IP = rb_state & ~LockWord::kReadBarrierStateMask = 0
6115  __ bic(IP, temp_reg, ShifterOperand(LockWord::kReadBarrierStateMask));
6116  // obj is unchanged by this operation, but its value now depends on
6117  // IP, which depends on temp_reg.
6118  __ add(obj, obj, ShifterOperand(IP));
6119
6120  // The actual reference load.
6121  if (index.IsValid()) {
6122    static_assert(
6123        sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
6124        "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
6125    // /* HeapReference<Object> */ ref =
6126    //     *(obj + offset + index * sizeof(HeapReference<Object>))
6127    if (index.IsConstant()) {
6128      size_t computed_offset =
6129          (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + offset;
6130      __ LoadFromOffset(kLoadWord, ref_reg, obj, computed_offset);
6131    } else {
6132      __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
6133      __ LoadFromOffset(kLoadWord, ref_reg, IP, offset);
6134    }
6135  } else {
6136    // /* HeapReference<Object> */ ref = *(obj + offset)
6137    __ LoadFromOffset(kLoadWord, ref_reg, obj, offset);
6138  }
6139
6140  // Object* ref = ref_addr->AsMirrorPtr()
6141  __ MaybeUnpoisonHeapReference(ref_reg);
6142
6143  // Slow path used to mark the object `ref` when it is gray.
6144  SlowPathCode* slow_path =
6145      new (GetGraph()->GetArena()) ReadBarrierMarkSlowPathARM(instruction, ref, ref);
6146  AddSlowPath(slow_path);
6147
6148  // if (rb_state == ReadBarrier::gray_ptr_)
6149  //   ref = ReadBarrier::Mark(ref);
6150  __ cmp(temp_reg, ShifterOperand(ReadBarrier::gray_ptr_));
6151  __ b(slow_path->GetEntryLabel(), EQ);
6152  __ Bind(slow_path->GetExitLabel());
6153}
6154
6155void CodeGeneratorARM::GenerateReadBarrierSlow(HInstruction* instruction,
6156                                               Location out,
6157                                               Location ref,
6158                                               Location obj,
6159                                               uint32_t offset,
6160                                               Location index) {
6161  DCHECK(kEmitCompilerReadBarrier);
6162
6163  // Insert a slow path based read barrier *after* the reference load.
6164  //
6165  // If heap poisoning is enabled, the unpoisoning of the loaded
6166  // reference will be carried out by the runtime within the slow
6167  // path.
6168  //
6169  // Note that `ref` currently does not get unpoisoned (when heap
6170  // poisoning is enabled), which is alright as the `ref` argument is
6171  // not used by the artReadBarrierSlow entry point.
6172  //
6173  // TODO: Unpoison `ref` when it is used by artReadBarrierSlow.
6174  SlowPathCode* slow_path = new (GetGraph()->GetArena())
6175      ReadBarrierForHeapReferenceSlowPathARM(instruction, out, ref, obj, offset, index);
6176  AddSlowPath(slow_path);
6177
6178  __ b(slow_path->GetEntryLabel());
6179  __ Bind(slow_path->GetExitLabel());
6180}
6181
6182void CodeGeneratorARM::MaybeGenerateReadBarrierSlow(HInstruction* instruction,
6183                                                    Location out,
6184                                                    Location ref,
6185                                                    Location obj,
6186                                                    uint32_t offset,
6187                                                    Location index) {
6188  if (kEmitCompilerReadBarrier) {
6189    // Baker's read barriers shall be handled by the fast path
6190    // (CodeGeneratorARM::GenerateReferenceLoadWithBakerReadBarrier).
6191    DCHECK(!kUseBakerReadBarrier);
6192    // If heap poisoning is enabled, unpoisoning will be taken care of
6193    // by the runtime within the slow path.
6194    GenerateReadBarrierSlow(instruction, out, ref, obj, offset, index);
6195  } else if (kPoisonHeapReferences) {
6196    __ UnpoisonHeapReference(out.AsRegister<Register>());
6197  }
6198}
6199
6200void CodeGeneratorARM::GenerateReadBarrierForRootSlow(HInstruction* instruction,
6201                                                      Location out,
6202                                                      Location root) {
6203  DCHECK(kEmitCompilerReadBarrier);
6204
6205  // Insert a slow path based read barrier *after* the GC root load.
6206  //
6207  // Note that GC roots are not affected by heap poisoning, so we do
6208  // not need to do anything special for this here.
6209  SlowPathCode* slow_path =
6210      new (GetGraph()->GetArena()) ReadBarrierForRootSlowPathARM(instruction, out, root);
6211  AddSlowPath(slow_path);
6212
6213  __ b(slow_path->GetEntryLabel());
6214  __ Bind(slow_path->GetExitLabel());
6215}
6216
6217HInvokeStaticOrDirect::DispatchInfo CodeGeneratorARM::GetSupportedInvokeStaticOrDirectDispatch(
6218      const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
6219      MethodReference target_method) {
6220  HInvokeStaticOrDirect::DispatchInfo dispatch_info = desired_dispatch_info;
6221  // We disable pc-relative load when there is an irreducible loop, as the optimization
6222  // is incompatible with it.
6223  if (GetGraph()->HasIrreducibleLoops() &&
6224      (dispatch_info.method_load_kind ==
6225          HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative)) {
6226    dispatch_info.method_load_kind = HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod;
6227  }
6228
6229  if (dispatch_info.code_ptr_location == HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative) {
6230    const DexFile& outer_dex_file = GetGraph()->GetDexFile();
6231    if (&outer_dex_file != target_method.dex_file) {
6232      // Calls across dex files are more likely to exceed the available BL range,
6233      // so use absolute patch with fixup if available and kCallArtMethod otherwise.
6234      HInvokeStaticOrDirect::CodePtrLocation code_ptr_location =
6235          (desired_dispatch_info.method_load_kind ==
6236           HInvokeStaticOrDirect::MethodLoadKind::kDirectAddressWithFixup)
6237          ? HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup
6238          : HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod;
6239      return HInvokeStaticOrDirect::DispatchInfo {
6240        dispatch_info.method_load_kind,
6241        code_ptr_location,
6242        dispatch_info.method_load_data,
6243        0u
6244      };
6245    }
6246  }
6247  return dispatch_info;
6248}
6249
6250Register CodeGeneratorARM::GetInvokeStaticOrDirectExtraParameter(HInvokeStaticOrDirect* invoke,
6251                                                                 Register temp) {
6252  DCHECK_EQ(invoke->InputCount(), invoke->GetNumberOfArguments() + 1u);
6253  Location location = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
6254  if (!invoke->GetLocations()->Intrinsified()) {
6255    return location.AsRegister<Register>();
6256  }
6257  // For intrinsics we allow any location, so it may be on the stack.
6258  if (!location.IsRegister()) {
6259    __ LoadFromOffset(kLoadWord, temp, SP, location.GetStackIndex());
6260    return temp;
6261  }
6262  // For register locations, check if the register was saved. If so, get it from the stack.
6263  // Note: There is a chance that the register was saved but not overwritten, so we could
6264  // save one load. However, since this is just an intrinsic slow path we prefer this
6265  // simple and more robust approach rather that trying to determine if that's the case.
6266  SlowPathCode* slow_path = GetCurrentSlowPath();
6267  DCHECK(slow_path != nullptr);  // For intrinsified invokes the call is emitted on the slow path.
6268  if (slow_path->IsCoreRegisterSaved(location.AsRegister<Register>())) {
6269    int stack_offset = slow_path->GetStackOffsetOfCoreRegister(location.AsRegister<Register>());
6270    __ LoadFromOffset(kLoadWord, temp, SP, stack_offset);
6271    return temp;
6272  }
6273  return location.AsRegister<Register>();
6274}
6275
6276void CodeGeneratorARM::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) {
6277  // For better instruction scheduling we load the direct code pointer before the method pointer.
6278  switch (invoke->GetCodePtrLocation()) {
6279    case HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup:
6280      // LR = code address from literal pool with link-time patch.
6281      __ LoadLiteral(LR, DeduplicateMethodCodeLiteral(invoke->GetTargetMethod()));
6282      break;
6283    case HInvokeStaticOrDirect::CodePtrLocation::kCallDirect:
6284      // LR = invoke->GetDirectCodePtr();
6285      __ LoadImmediate(LR, invoke->GetDirectCodePtr());
6286      break;
6287    default:
6288      break;
6289  }
6290
6291  Location callee_method = temp;  // For all kinds except kRecursive, callee will be in temp.
6292  switch (invoke->GetMethodLoadKind()) {
6293    case HInvokeStaticOrDirect::MethodLoadKind::kStringInit:
6294      // temp = thread->string_init_entrypoint
6295      __ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), TR, invoke->GetStringInitOffset());
6296      break;
6297    case HInvokeStaticOrDirect::MethodLoadKind::kRecursive:
6298      callee_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
6299      break;
6300    case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress:
6301      __ LoadImmediate(temp.AsRegister<Register>(), invoke->GetMethodAddress());
6302      break;
6303    case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddressWithFixup:
6304      __ LoadLiteral(temp.AsRegister<Register>(),
6305                     DeduplicateMethodAddressLiteral(invoke->GetTargetMethod()));
6306      break;
6307    case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative: {
6308      HArmDexCacheArraysBase* base =
6309          invoke->InputAt(invoke->GetSpecialInputIndex())->AsArmDexCacheArraysBase();
6310      Register base_reg = GetInvokeStaticOrDirectExtraParameter(invoke,
6311                                                                temp.AsRegister<Register>());
6312      int32_t offset = invoke->GetDexCacheArrayOffset() - base->GetElementOffset();
6313      __ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), base_reg, offset);
6314      break;
6315    }
6316    case HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod: {
6317      Location current_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
6318      Register method_reg;
6319      Register reg = temp.AsRegister<Register>();
6320      if (current_method.IsRegister()) {
6321        method_reg = current_method.AsRegister<Register>();
6322      } else {
6323        DCHECK(invoke->GetLocations()->Intrinsified());
6324        DCHECK(!current_method.IsValid());
6325        method_reg = reg;
6326        __ LoadFromOffset(kLoadWord, reg, SP, kCurrentMethodStackOffset);
6327      }
6328      // /* ArtMethod*[] */ temp = temp.ptr_sized_fields_->dex_cache_resolved_methods_;
6329      __ LoadFromOffset(kLoadWord,
6330                        reg,
6331                        method_reg,
6332                        ArtMethod::DexCacheResolvedMethodsOffset(kArmPointerSize).Int32Value());
6333      // temp = temp[index_in_cache]
6334      uint32_t index_in_cache = invoke->GetTargetMethod().dex_method_index;
6335      __ LoadFromOffset(kLoadWord, reg, reg, CodeGenerator::GetCachePointerOffset(index_in_cache));
6336      break;
6337    }
6338  }
6339
6340  switch (invoke->GetCodePtrLocation()) {
6341    case HInvokeStaticOrDirect::CodePtrLocation::kCallSelf:
6342      __ bl(GetFrameEntryLabel());
6343      break;
6344    case HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative:
6345      relative_call_patches_.emplace_back(invoke->GetTargetMethod());
6346      __ BindTrackedLabel(&relative_call_patches_.back().label);
6347      // Arbitrarily branch to the BL itself, override at link time.
6348      __ bl(&relative_call_patches_.back().label);
6349      break;
6350    case HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup:
6351    case HInvokeStaticOrDirect::CodePtrLocation::kCallDirect:
6352      // LR prepared above for better instruction scheduling.
6353      // LR()
6354      __ blx(LR);
6355      break;
6356    case HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod:
6357      // LR = callee_method->entry_point_from_quick_compiled_code_
6358      __ LoadFromOffset(
6359          kLoadWord, LR, callee_method.AsRegister<Register>(),
6360          ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArmWordSize).Int32Value());
6361      // LR()
6362      __ blx(LR);
6363      break;
6364  }
6365
6366  DCHECK(!IsLeafMethod());
6367}
6368
6369void CodeGeneratorARM::GenerateVirtualCall(HInvokeVirtual* invoke, Location temp_location) {
6370  Register temp = temp_location.AsRegister<Register>();
6371  uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
6372      invoke->GetVTableIndex(), kArmPointerSize).Uint32Value();
6373
6374  // Use the calling convention instead of the location of the receiver, as
6375  // intrinsics may have put the receiver in a different register. In the intrinsics
6376  // slow path, the arguments have been moved to the right place, so here we are
6377  // guaranteed that the receiver is the first register of the calling convention.
6378  InvokeDexCallingConvention calling_convention;
6379  Register receiver = calling_convention.GetRegisterAt(0);
6380  uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
6381  // /* HeapReference<Class> */ temp = receiver->klass_
6382  __ LoadFromOffset(kLoadWord, temp, receiver, class_offset);
6383  MaybeRecordImplicitNullCheck(invoke);
6384  // Instead of simply (possibly) unpoisoning `temp` here, we should
6385  // emit a read barrier for the previous class reference load.
6386  // However this is not required in practice, as this is an
6387  // intermediate/temporary reference and because the current
6388  // concurrent copying collector keeps the from-space memory
6389  // intact/accessible until the end of the marking phase (the
6390  // concurrent copying collector may not in the future).
6391  __ MaybeUnpoisonHeapReference(temp);
6392  // temp = temp->GetMethodAt(method_offset);
6393  uint32_t entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(
6394      kArmWordSize).Int32Value();
6395  __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
6396  // LR = temp->GetEntryPoint();
6397  __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
6398  // LR();
6399  __ blx(LR);
6400}
6401
6402void CodeGeneratorARM::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
6403  DCHECK(linker_patches->empty());
6404  size_t size =
6405      method_patches_.size() +
6406      call_patches_.size() +
6407      relative_call_patches_.size() +
6408      /* MOVW+MOVT for each base */ 2u * dex_cache_arrays_base_labels_.size();
6409  linker_patches->reserve(size);
6410  for (const auto& entry : method_patches_) {
6411    const MethodReference& target_method = entry.first;
6412    Literal* literal = entry.second;
6413    DCHECK(literal->GetLabel()->IsBound());
6414    uint32_t literal_offset = literal->GetLabel()->Position();
6415    linker_patches->push_back(LinkerPatch::MethodPatch(literal_offset,
6416                                                       target_method.dex_file,
6417                                                       target_method.dex_method_index));
6418  }
6419  for (const auto& entry : call_patches_) {
6420    const MethodReference& target_method = entry.first;
6421    Literal* literal = entry.second;
6422    DCHECK(literal->GetLabel()->IsBound());
6423    uint32_t literal_offset = literal->GetLabel()->Position();
6424    linker_patches->push_back(LinkerPatch::CodePatch(literal_offset,
6425                                                     target_method.dex_file,
6426                                                     target_method.dex_method_index));
6427  }
6428  for (const MethodPatchInfo<Label>& info : relative_call_patches_) {
6429    uint32_t literal_offset = info.label.Position();
6430    linker_patches->push_back(LinkerPatch::RelativeCodePatch(literal_offset,
6431                                                             info.target_method.dex_file,
6432                                                             info.target_method.dex_method_index));
6433  }
6434  for (const auto& pair : dex_cache_arrays_base_labels_) {
6435    HArmDexCacheArraysBase* base = pair.first;
6436    const DexCacheArraysBaseLabels* labels = &pair.second;
6437    const DexFile& dex_file = base->GetDexFile();
6438    size_t base_element_offset = base->GetElementOffset();
6439    DCHECK(labels->add_pc_label.IsBound());
6440    uint32_t add_pc_offset = dchecked_integral_cast<uint32_t>(labels->add_pc_label.Position());
6441    // Add MOVW patch.
6442    DCHECK(labels->movw_label.IsBound());
6443    uint32_t movw_offset = dchecked_integral_cast<uint32_t>(labels->movw_label.Position());
6444    linker_patches->push_back(LinkerPatch::DexCacheArrayPatch(movw_offset,
6445                                                              &dex_file,
6446                                                              add_pc_offset,
6447                                                              base_element_offset));
6448    // Add MOVT patch.
6449    DCHECK(labels->movt_label.IsBound());
6450    uint32_t movt_offset = dchecked_integral_cast<uint32_t>(labels->movt_label.Position());
6451    linker_patches->push_back(LinkerPatch::DexCacheArrayPatch(movt_offset,
6452                                                              &dex_file,
6453                                                              add_pc_offset,
6454                                                              base_element_offset));
6455  }
6456}
6457
6458Literal* CodeGeneratorARM::DeduplicateMethodLiteral(MethodReference target_method,
6459                                                    MethodToLiteralMap* map) {
6460  // Look up the literal for target_method.
6461  auto lb = map->lower_bound(target_method);
6462  if (lb != map->end() && !map->key_comp()(target_method, lb->first)) {
6463    return lb->second;
6464  }
6465  // We don't have a literal for this method yet, insert a new one.
6466  Literal* literal = __ NewLiteral<uint32_t>(0u);
6467  map->PutBefore(lb, target_method, literal);
6468  return literal;
6469}
6470
6471Literal* CodeGeneratorARM::DeduplicateMethodAddressLiteral(MethodReference target_method) {
6472  return DeduplicateMethodLiteral(target_method, &method_patches_);
6473}
6474
6475Literal* CodeGeneratorARM::DeduplicateMethodCodeLiteral(MethodReference target_method) {
6476  return DeduplicateMethodLiteral(target_method, &call_patches_);
6477}
6478
6479void LocationsBuilderARM::VisitMultiplyAccumulate(HMultiplyAccumulate* instr) {
6480  LocationSummary* locations =
6481      new (GetGraph()->GetArena()) LocationSummary(instr, LocationSummary::kNoCall);
6482  locations->SetInAt(HMultiplyAccumulate::kInputAccumulatorIndex,
6483                     Location::RequiresRegister());
6484  locations->SetInAt(HMultiplyAccumulate::kInputMulLeftIndex, Location::RequiresRegister());
6485  locations->SetInAt(HMultiplyAccumulate::kInputMulRightIndex, Location::RequiresRegister());
6486  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
6487}
6488
6489void InstructionCodeGeneratorARM::VisitMultiplyAccumulate(HMultiplyAccumulate* instr) {
6490  LocationSummary* locations = instr->GetLocations();
6491  Register res = locations->Out().AsRegister<Register>();
6492  Register accumulator =
6493      locations->InAt(HMultiplyAccumulate::kInputAccumulatorIndex).AsRegister<Register>();
6494  Register mul_left =
6495      locations->InAt(HMultiplyAccumulate::kInputMulLeftIndex).AsRegister<Register>();
6496  Register mul_right =
6497      locations->InAt(HMultiplyAccumulate::kInputMulRightIndex).AsRegister<Register>();
6498
6499  if (instr->GetOpKind() == HInstruction::kAdd) {
6500    __ mla(res, mul_left, mul_right, accumulator);
6501  } else {
6502    __ mls(res, mul_left, mul_right, accumulator);
6503  }
6504}
6505
6506void LocationsBuilderARM::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
6507  // Nothing to do, this should be removed during prepare for register allocator.
6508  LOG(FATAL) << "Unreachable";
6509}
6510
6511void InstructionCodeGeneratorARM::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
6512  // Nothing to do, this should be removed during prepare for register allocator.
6513  LOG(FATAL) << "Unreachable";
6514}
6515
6516// Simple implementation of packed switch - generate cascaded compare/jumps.
6517void LocationsBuilderARM::VisitPackedSwitch(HPackedSwitch* switch_instr) {
6518  LocationSummary* locations =
6519      new (GetGraph()->GetArena()) LocationSummary(switch_instr, LocationSummary::kNoCall);
6520  locations->SetInAt(0, Location::RequiresRegister());
6521  if (switch_instr->GetNumEntries() > kPackedSwitchCompareJumpThreshold &&
6522      codegen_->GetAssembler()->IsThumb()) {
6523    locations->AddTemp(Location::RequiresRegister());  // We need a temp for the table base.
6524    if (switch_instr->GetStartValue() != 0) {
6525      locations->AddTemp(Location::RequiresRegister());  // We need a temp for the bias.
6526    }
6527  }
6528}
6529
6530void InstructionCodeGeneratorARM::VisitPackedSwitch(HPackedSwitch* switch_instr) {
6531  int32_t lower_bound = switch_instr->GetStartValue();
6532  uint32_t num_entries = switch_instr->GetNumEntries();
6533  LocationSummary* locations = switch_instr->GetLocations();
6534  Register value_reg = locations->InAt(0).AsRegister<Register>();
6535  HBasicBlock* default_block = switch_instr->GetDefaultBlock();
6536
6537  if (num_entries <= kPackedSwitchCompareJumpThreshold || !codegen_->GetAssembler()->IsThumb()) {
6538    // Create a series of compare/jumps.
6539    Register temp_reg = IP;
6540    // Note: It is fine for the below AddConstantSetFlags() using IP register to temporarily store
6541    // the immediate, because IP is used as the destination register. For the other
6542    // AddConstantSetFlags() and GenerateCompareWithImmediate(), the immediate values are constant,
6543    // and they can be encoded in the instruction without making use of IP register.
6544    __ AddConstantSetFlags(temp_reg, value_reg, -lower_bound);
6545
6546    const ArenaVector<HBasicBlock*>& successors = switch_instr->GetBlock()->GetSuccessors();
6547    // Jump to successors[0] if value == lower_bound.
6548    __ b(codegen_->GetLabelOf(successors[0]), EQ);
6549    int32_t last_index = 0;
6550    for (; num_entries - last_index > 2; last_index += 2) {
6551      __ AddConstantSetFlags(temp_reg, temp_reg, -2);
6552      // Jump to successors[last_index + 1] if value < case_value[last_index + 2].
6553      __ b(codegen_->GetLabelOf(successors[last_index + 1]), LO);
6554      // Jump to successors[last_index + 2] if value == case_value[last_index + 2].
6555      __ b(codegen_->GetLabelOf(successors[last_index + 2]), EQ);
6556    }
6557    if (num_entries - last_index == 2) {
6558      // The last missing case_value.
6559      __ CmpConstant(temp_reg, 1);
6560      __ b(codegen_->GetLabelOf(successors[last_index + 1]), EQ);
6561    }
6562
6563    // And the default for any other value.
6564    if (!codegen_->GoesToNextBlock(switch_instr->GetBlock(), default_block)) {
6565      __ b(codegen_->GetLabelOf(default_block));
6566    }
6567  } else {
6568    // Create a table lookup.
6569    Register temp_reg = locations->GetTemp(0).AsRegister<Register>();
6570
6571    // Materialize a pointer to the switch table
6572    std::vector<Label*> labels(num_entries);
6573    const ArenaVector<HBasicBlock*>& successors = switch_instr->GetBlock()->GetSuccessors();
6574    for (uint32_t i = 0; i < num_entries; i++) {
6575      labels[i] = codegen_->GetLabelOf(successors[i]);
6576    }
6577    JumpTable* table = __ CreateJumpTable(std::move(labels), temp_reg);
6578
6579    // Remove the bias.
6580    Register key_reg;
6581    if (lower_bound != 0) {
6582      key_reg = locations->GetTemp(1).AsRegister<Register>();
6583      __ AddConstant(key_reg, value_reg, -lower_bound);
6584    } else {
6585      key_reg = value_reg;
6586    }
6587
6588    // Check whether the value is in the table, jump to default block if not.
6589    __ CmpConstant(key_reg, num_entries - 1);
6590    __ b(codegen_->GetLabelOf(default_block), Condition::HI);
6591
6592    // Load the displacement from the table.
6593    __ ldr(temp_reg, Address(temp_reg, key_reg, Shift::LSL, 2));
6594
6595    // Dispatch is a direct add to the PC (for Thumb2).
6596    __ EmitJumpTableDispatch(table, temp_reg);
6597  }
6598}
6599
6600void LocationsBuilderARM::VisitArmDexCacheArraysBase(HArmDexCacheArraysBase* base) {
6601  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(base);
6602  locations->SetOut(Location::RequiresRegister());
6603  codegen_->AddDexCacheArraysBase(base);
6604}
6605
6606void InstructionCodeGeneratorARM::VisitArmDexCacheArraysBase(HArmDexCacheArraysBase* base) {
6607  Register base_reg = base->GetLocations()->Out().AsRegister<Register>();
6608  CodeGeneratorARM::DexCacheArraysBaseLabels* labels = codegen_->GetDexCacheArraysBaseLabels(base);
6609  __ BindTrackedLabel(&labels->movw_label);
6610  __ movw(base_reg, 0u);
6611  __ BindTrackedLabel(&labels->movt_label);
6612  __ movt(base_reg, 0u);
6613  __ BindTrackedLabel(&labels->add_pc_label);
6614  __ add(base_reg, base_reg, ShifterOperand(PC));
6615}
6616
6617void CodeGeneratorARM::MoveFromReturnRegister(Location trg, Primitive::Type type) {
6618  if (!trg.IsValid()) {
6619    DCHECK_EQ(type, Primitive::kPrimVoid);
6620    return;
6621  }
6622
6623  DCHECK_NE(type, Primitive::kPrimVoid);
6624
6625  Location return_loc = InvokeDexCallingConventionVisitorARM().GetReturnLocation(type);
6626  if (return_loc.Equals(trg)) {
6627    return;
6628  }
6629
6630  // TODO: Consider pairs in the parallel move resolver, then this could be nicely merged
6631  //       with the last branch.
6632  if (type == Primitive::kPrimLong) {
6633    HParallelMove parallel_move(GetGraph()->GetArena());
6634    parallel_move.AddMove(return_loc.ToLow(), trg.ToLow(), Primitive::kPrimInt, nullptr);
6635    parallel_move.AddMove(return_loc.ToHigh(), trg.ToHigh(), Primitive::kPrimInt, nullptr);
6636    GetMoveResolver()->EmitNativeCode(&parallel_move);
6637  } else if (type == Primitive::kPrimDouble) {
6638    HParallelMove parallel_move(GetGraph()->GetArena());
6639    parallel_move.AddMove(return_loc.ToLow(), trg.ToLow(), Primitive::kPrimFloat, nullptr);
6640    parallel_move.AddMove(return_loc.ToHigh(), trg.ToHigh(), Primitive::kPrimFloat, nullptr);
6641    GetMoveResolver()->EmitNativeCode(&parallel_move);
6642  } else {
6643    // Let the parallel move resolver take care of all of this.
6644    HParallelMove parallel_move(GetGraph()->GetArena());
6645    parallel_move.AddMove(return_loc, trg, type, nullptr);
6646    GetMoveResolver()->EmitNativeCode(&parallel_move);
6647  }
6648}
6649
6650void LocationsBuilderARM::VisitClassTableGet(HClassTableGet* instruction) {
6651  LocationSummary* locations =
6652      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
6653  locations->SetInAt(0, Location::RequiresRegister());
6654  locations->SetOut(Location::RequiresRegister());
6655}
6656
6657void InstructionCodeGeneratorARM::VisitClassTableGet(HClassTableGet* instruction) {
6658  LocationSummary* locations = instruction->GetLocations();
6659  uint32_t method_offset = 0;
6660  if (instruction->GetTableKind() == HClassTableGet::TableKind::kVTable) {
6661    method_offset = mirror::Class::EmbeddedVTableEntryOffset(
6662        instruction->GetIndex(), kArmPointerSize).SizeValue();
6663  } else {
6664    method_offset = mirror::Class::EmbeddedImTableEntryOffset(
6665        instruction->GetIndex() % mirror::Class::kImtSize, kArmPointerSize).Uint32Value();
6666  }
6667  __ LoadFromOffset(kLoadWord,
6668                    locations->Out().AsRegister<Register>(),
6669                    locations->InAt(0).AsRegister<Register>(),
6670                    method_offset);
6671}
6672
6673#undef __
6674#undef QUICK_ENTRY_POINT
6675
6676}  // namespace arm
6677}  // namespace art
6678