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