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