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