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