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