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