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