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