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 "common_arm.h"
23 #include "compiled_method.h"
24 #include "entrypoints/quick/quick_entrypoints.h"
25 #include "gc/accounting/card_table.h"
26 #include "intrinsics.h"
27 #include "intrinsics_arm.h"
28 #include "mirror/array-inl.h"
29 #include "mirror/class-inl.h"
30 #include "thread.h"
31 #include "utils/arm/assembler_arm.h"
32 #include "utils/arm/managed_register_arm.h"
33 #include "utils/assembler.h"
34 #include "utils/stack_checks.h"
35 
36 namespace art {
37 
38 template<class MirrorType>
39 class GcRoot;
40 
41 namespace arm {
42 
ExpectedPairLayout(Location location)43 static bool ExpectedPairLayout(Location location) {
44   // We expected this for both core and fpu register pairs.
45   return ((location.low() & 1) == 0) && (location.low() + 1 == location.high());
46 }
47 
48 static constexpr int kCurrentMethodStackOffset = 0;
49 static constexpr Register kMethodRegisterArgument = R0;
50 
51 static constexpr Register kCoreAlwaysSpillRegister = R5;
52 static constexpr Register kCoreCalleeSaves[] =
53     { R5, R6, R7, R8, R10, R11, LR };
54 static constexpr SRegister kFpuCalleeSaves[] =
55     { S16, S17, S18, S19, S20, S21, S22, S23, S24, S25, S26, S27, S28, S29, S30, S31 };
56 
57 // D31 cannot be split into two S registers, and the register allocator only works on
58 // S registers. Therefore there is no need to block it.
59 static constexpr DRegister DTMP = D31;
60 
61 static constexpr uint32_t kPackedSwitchCompareJumpThreshold = 7;
62 
63 // NOLINT on __ macro to suppress wrong warning/fix (misc-macro-parentheses) from clang-tidy.
64 #define __ down_cast<ArmAssembler*>(codegen->GetAssembler())->  // NOLINT
65 #define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kArmPointerSize, x).Int32Value()
66 
67 static constexpr int kRegListThreshold = 4;
68 
69 // SaveLiveRegisters and RestoreLiveRegisters from SlowPathCodeARM operate on sets of S registers,
70 // for each live D registers they treat two corresponding S registers as live ones.
71 //
72 // Two following functions (SaveContiguousSRegisterList, RestoreContiguousSRegisterList) build
73 // from a list of contiguous S registers a list of contiguous D registers (processing first/last
74 // S registers corner cases) and save/restore this new list treating them as D registers.
75 // - decreasing code size
76 // - avoiding hazards on Cortex-A57, when a pair of S registers for an actual live D register is
77 //   restored and then used in regular non SlowPath code as D register.
78 //
79 // For the following example (v means the S register is live):
80 //   D names: |    D0   |    D1   |    D2   |    D4   | ...
81 //   S names: | S0 | S1 | S2 | S3 | S4 | S5 | S6 | S7 | ...
82 //   Live?    |    |  v |  v |  v |  v |  v |  v |    | ...
83 //
84 // S1 and S6 will be saved/restored independently; D registers list (D1, D2) will be processed
85 // as D registers.
SaveContiguousSRegisterList(size_t first,size_t last,CodeGenerator * codegen,size_t stack_offset)86 static size_t SaveContiguousSRegisterList(size_t first,
87                                           size_t last,
88                                           CodeGenerator* codegen,
89                                           size_t stack_offset) {
90   DCHECK_LE(first, last);
91   if ((first == last) && (first == 0)) {
92     stack_offset += codegen->SaveFloatingPointRegister(stack_offset, first);
93     return stack_offset;
94   }
95   if (first % 2 == 1) {
96     stack_offset += codegen->SaveFloatingPointRegister(stack_offset, first++);
97   }
98 
99   bool save_last = false;
100   if (last % 2 == 0) {
101     save_last = true;
102     --last;
103   }
104 
105   if (first < last) {
106     DRegister d_reg = static_cast<DRegister>(first / 2);
107     DCHECK_EQ((last - first + 1) % 2, 0u);
108     size_t number_of_d_regs = (last - first + 1) / 2;
109 
110     if (number_of_d_regs == 1) {
111       __ StoreDToOffset(d_reg, SP, stack_offset);
112     } else if (number_of_d_regs > 1) {
113       __ add(IP, SP, ShifterOperand(stack_offset));
114       __ vstmiad(IP, d_reg, number_of_d_regs);
115     }
116     stack_offset += number_of_d_regs * kArmWordSize * 2;
117   }
118 
119   if (save_last) {
120     stack_offset += codegen->SaveFloatingPointRegister(stack_offset, last + 1);
121   }
122 
123   return stack_offset;
124 }
125 
RestoreContiguousSRegisterList(size_t first,size_t last,CodeGenerator * codegen,size_t stack_offset)126 static size_t RestoreContiguousSRegisterList(size_t first,
127                                              size_t last,
128                                              CodeGenerator* codegen,
129                                              size_t stack_offset) {
130   DCHECK_LE(first, last);
131   if ((first == last) && (first == 0)) {
132     stack_offset += codegen->RestoreFloatingPointRegister(stack_offset, first);
133     return stack_offset;
134   }
135   if (first % 2 == 1) {
136     stack_offset += codegen->RestoreFloatingPointRegister(stack_offset, first++);
137   }
138 
139   bool restore_last = false;
140   if (last % 2 == 0) {
141     restore_last = true;
142     --last;
143   }
144 
145   if (first < last) {
146     DRegister d_reg = static_cast<DRegister>(first / 2);
147     DCHECK_EQ((last - first + 1) % 2, 0u);
148     size_t number_of_d_regs = (last - first + 1) / 2;
149     if (number_of_d_regs == 1) {
150       __ LoadDFromOffset(d_reg, SP, stack_offset);
151     } else if (number_of_d_regs > 1) {
152       __ add(IP, SP, ShifterOperand(stack_offset));
153       __ vldmiad(IP, d_reg, number_of_d_regs);
154     }
155     stack_offset += number_of_d_regs * kArmWordSize * 2;
156   }
157 
158   if (restore_last) {
159     stack_offset += codegen->RestoreFloatingPointRegister(stack_offset, last + 1);
160   }
161 
162   return stack_offset;
163 }
164 
SaveLiveRegisters(CodeGenerator * codegen,LocationSummary * locations)165 void SlowPathCodeARM::SaveLiveRegisters(CodeGenerator* codegen, LocationSummary* locations) {
166   size_t stack_offset = codegen->GetFirstRegisterSlotInSlowPath();
167   size_t orig_offset = stack_offset;
168 
169   const uint32_t core_spills = codegen->GetSlowPathSpills(locations, /* core_registers */ true);
170   for (uint32_t i : LowToHighBits(core_spills)) {
171     // If the register holds an object, update the stack mask.
172     if (locations->RegisterContainsObject(i)) {
173       locations->SetStackBit(stack_offset / kVRegSize);
174     }
175     DCHECK_LT(stack_offset, codegen->GetFrameSize() - codegen->FrameEntrySpillSize());
176     DCHECK_LT(i, kMaximumNumberOfExpectedRegisters);
177     saved_core_stack_offsets_[i] = stack_offset;
178     stack_offset += kArmWordSize;
179   }
180 
181   int reg_num = POPCOUNT(core_spills);
182   if (reg_num != 0) {
183     if (reg_num > kRegListThreshold) {
184       __ StoreList(RegList(core_spills), orig_offset);
185     } else {
186       stack_offset = orig_offset;
187       for (uint32_t i : LowToHighBits(core_spills)) {
188         stack_offset += codegen->SaveCoreRegister(stack_offset, i);
189       }
190     }
191   }
192 
193   uint32_t fp_spills = codegen->GetSlowPathSpills(locations, /* core_registers */ false);
194   orig_offset = stack_offset;
195   for (uint32_t i : LowToHighBits(fp_spills)) {
196     DCHECK_LT(i, kMaximumNumberOfExpectedRegisters);
197     saved_fpu_stack_offsets_[i] = stack_offset;
198     stack_offset += kArmWordSize;
199   }
200 
201   stack_offset = orig_offset;
202   while (fp_spills != 0u) {
203     uint32_t begin = CTZ(fp_spills);
204     uint32_t tmp = fp_spills + (1u << begin);
205     fp_spills &= tmp;  // Clear the contiguous range of 1s.
206     uint32_t end = (tmp == 0u) ? 32u : CTZ(tmp);  // CTZ(0) is undefined.
207     stack_offset = SaveContiguousSRegisterList(begin, end - 1, codegen, stack_offset);
208   }
209   DCHECK_LE(stack_offset, codegen->GetFrameSize() - codegen->FrameEntrySpillSize());
210 }
211 
RestoreLiveRegisters(CodeGenerator * codegen,LocationSummary * locations)212 void SlowPathCodeARM::RestoreLiveRegisters(CodeGenerator* codegen, LocationSummary* locations) {
213   size_t stack_offset = codegen->GetFirstRegisterSlotInSlowPath();
214   size_t orig_offset = stack_offset;
215 
216   const uint32_t core_spills = codegen->GetSlowPathSpills(locations, /* core_registers */ true);
217   for (uint32_t i : LowToHighBits(core_spills)) {
218     DCHECK_LT(stack_offset, codegen->GetFrameSize() - codegen->FrameEntrySpillSize());
219     DCHECK_LT(i, kMaximumNumberOfExpectedRegisters);
220     stack_offset += kArmWordSize;
221   }
222 
223   int reg_num = POPCOUNT(core_spills);
224   if (reg_num != 0) {
225     if (reg_num > kRegListThreshold) {
226       __ LoadList(RegList(core_spills), orig_offset);
227     } else {
228       stack_offset = orig_offset;
229       for (uint32_t i : LowToHighBits(core_spills)) {
230         stack_offset += codegen->RestoreCoreRegister(stack_offset, i);
231       }
232     }
233   }
234 
235   uint32_t fp_spills = codegen->GetSlowPathSpills(locations, /* core_registers */ false);
236   while (fp_spills != 0u) {
237     uint32_t begin = CTZ(fp_spills);
238     uint32_t tmp = fp_spills + (1u << begin);
239     fp_spills &= tmp;  // Clear the contiguous range of 1s.
240     uint32_t end = (tmp == 0u) ? 32u : CTZ(tmp);  // CTZ(0) is undefined.
241     stack_offset = RestoreContiguousSRegisterList(begin, end - 1, codegen, stack_offset);
242   }
243   DCHECK_LE(stack_offset, codegen->GetFrameSize() - codegen->FrameEntrySpillSize());
244 }
245 
246 class NullCheckSlowPathARM : public SlowPathCodeARM {
247  public:
NullCheckSlowPathARM(HNullCheck * instruction)248   explicit NullCheckSlowPathARM(HNullCheck* instruction) : SlowPathCodeARM(instruction) {}
249 
EmitNativeCode(CodeGenerator * codegen)250   void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
251     CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
252     __ Bind(GetEntryLabel());
253     if (instruction_->CanThrowIntoCatchBlock()) {
254       // Live registers will be restored in the catch block if caught.
255       SaveLiveRegisters(codegen, instruction_->GetLocations());
256     }
257     arm_codegen->InvokeRuntime(kQuickThrowNullPointer,
258                                instruction_,
259                                instruction_->GetDexPc(),
260                                this);
261     CheckEntrypointTypes<kQuickThrowNullPointer, void, void>();
262   }
263 
IsFatal() const264   bool IsFatal() const OVERRIDE { return true; }
265 
GetDescription() const266   const char* GetDescription() const OVERRIDE { return "NullCheckSlowPathARM"; }
267 
268  private:
269   DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathARM);
270 };
271 
272 class DivZeroCheckSlowPathARM : public SlowPathCodeARM {
273  public:
DivZeroCheckSlowPathARM(HDivZeroCheck * instruction)274   explicit DivZeroCheckSlowPathARM(HDivZeroCheck* instruction) : SlowPathCodeARM(instruction) {}
275 
EmitNativeCode(CodeGenerator * codegen)276   void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
277     CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
278     __ Bind(GetEntryLabel());
279     arm_codegen->InvokeRuntime(kQuickThrowDivZero, instruction_, instruction_->GetDexPc(), this);
280     CheckEntrypointTypes<kQuickThrowDivZero, void, void>();
281   }
282 
IsFatal() const283   bool IsFatal() const OVERRIDE { return true; }
284 
GetDescription() const285   const char* GetDescription() const OVERRIDE { return "DivZeroCheckSlowPathARM"; }
286 
287  private:
288   DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathARM);
289 };
290 
291 class SuspendCheckSlowPathARM : public SlowPathCodeARM {
292  public:
SuspendCheckSlowPathARM(HSuspendCheck * instruction,HBasicBlock * successor)293   SuspendCheckSlowPathARM(HSuspendCheck* instruction, HBasicBlock* successor)
294       : SlowPathCodeARM(instruction), successor_(successor) {}
295 
EmitNativeCode(CodeGenerator * codegen)296   void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
297     CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
298     __ Bind(GetEntryLabel());
299     arm_codegen->InvokeRuntime(kQuickTestSuspend, instruction_, instruction_->GetDexPc(), this);
300     CheckEntrypointTypes<kQuickTestSuspend, void, void>();
301     if (successor_ == nullptr) {
302       __ b(GetReturnLabel());
303     } else {
304       __ b(arm_codegen->GetLabelOf(successor_));
305     }
306   }
307 
GetReturnLabel()308   Label* GetReturnLabel() {
309     DCHECK(successor_ == nullptr);
310     return &return_label_;
311   }
312 
GetSuccessor() const313   HBasicBlock* GetSuccessor() const {
314     return successor_;
315   }
316 
GetDescription() const317   const char* GetDescription() const OVERRIDE { return "SuspendCheckSlowPathARM"; }
318 
319  private:
320   // If not null, the block to branch to after the suspend check.
321   HBasicBlock* const successor_;
322 
323   // If `successor_` is null, the label to branch to after the suspend check.
324   Label return_label_;
325 
326   DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathARM);
327 };
328 
329 class BoundsCheckSlowPathARM : public SlowPathCodeARM {
330  public:
BoundsCheckSlowPathARM(HBoundsCheck * instruction)331   explicit BoundsCheckSlowPathARM(HBoundsCheck* instruction)
332       : SlowPathCodeARM(instruction) {}
333 
EmitNativeCode(CodeGenerator * codegen)334   void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
335     CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
336     LocationSummary* locations = instruction_->GetLocations();
337 
338     __ Bind(GetEntryLabel());
339     if (instruction_->CanThrowIntoCatchBlock()) {
340       // Live registers will be restored in the catch block if caught.
341       SaveLiveRegisters(codegen, instruction_->GetLocations());
342     }
343     // We're moving two locations to locations that could overlap, so we need a parallel
344     // move resolver.
345     InvokeRuntimeCallingConvention calling_convention;
346     codegen->EmitParallelMoves(
347         locations->InAt(0),
348         Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
349         Primitive::kPrimInt,
350         locations->InAt(1),
351         Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
352         Primitive::kPrimInt);
353     QuickEntrypointEnum entrypoint = instruction_->AsBoundsCheck()->IsStringCharAt()
354         ? kQuickThrowStringBounds
355         : kQuickThrowArrayBounds;
356     arm_codegen->InvokeRuntime(entrypoint, instruction_, instruction_->GetDexPc(), this);
357     CheckEntrypointTypes<kQuickThrowStringBounds, void, int32_t, int32_t>();
358     CheckEntrypointTypes<kQuickThrowArrayBounds, void, int32_t, int32_t>();
359   }
360 
IsFatal() const361   bool IsFatal() const OVERRIDE { return true; }
362 
GetDescription() const363   const char* GetDescription() const OVERRIDE { return "BoundsCheckSlowPathARM"; }
364 
365  private:
366   DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathARM);
367 };
368 
369 class LoadClassSlowPathARM : public SlowPathCodeARM {
370  public:
LoadClassSlowPathARM(HLoadClass * cls,HInstruction * at,uint32_t dex_pc,bool do_clinit)371   LoadClassSlowPathARM(HLoadClass* cls, HInstruction* at, uint32_t dex_pc, bool do_clinit)
372       : SlowPathCodeARM(at), cls_(cls), dex_pc_(dex_pc), do_clinit_(do_clinit) {
373     DCHECK(at->IsLoadClass() || at->IsClinitCheck());
374   }
375 
EmitNativeCode(CodeGenerator * codegen)376   void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
377     LocationSummary* locations = instruction_->GetLocations();
378     Location out = locations->Out();
379     constexpr bool call_saves_everything_except_r0 = (!kUseReadBarrier || kUseBakerReadBarrier);
380 
381     CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
382     __ Bind(GetEntryLabel());
383     SaveLiveRegisters(codegen, locations);
384 
385     InvokeRuntimeCallingConvention calling_convention;
386     // For HLoadClass/kBssEntry/kSaveEverything, make sure we preserve the address of the entry.
387     DCHECK_EQ(instruction_->IsLoadClass(), cls_ == instruction_);
388     bool is_load_class_bss_entry =
389         (cls_ == instruction_) && (cls_->GetLoadKind() == HLoadClass::LoadKind::kBssEntry);
390     Register entry_address = kNoRegister;
391     if (is_load_class_bss_entry && call_saves_everything_except_r0) {
392       Register temp = locations->GetTemp(0).AsRegister<Register>();
393       // In the unlucky case that the `temp` is R0, we preserve the address in `out` across
394       // the kSaveEverything call.
395       bool temp_is_r0 = (temp == calling_convention.GetRegisterAt(0));
396       entry_address = temp_is_r0 ? out.AsRegister<Register>() : temp;
397       DCHECK_NE(entry_address, calling_convention.GetRegisterAt(0));
398       if (temp_is_r0) {
399         __ mov(entry_address, ShifterOperand(temp));
400       }
401     }
402     dex::TypeIndex type_index = cls_->GetTypeIndex();
403     __ LoadImmediate(calling_convention.GetRegisterAt(0), type_index.index_);
404     QuickEntrypointEnum entrypoint = do_clinit_ ? kQuickInitializeStaticStorage
405                                                 : kQuickInitializeType;
406     arm_codegen->InvokeRuntime(entrypoint, instruction_, dex_pc_, this);
407     if (do_clinit_) {
408       CheckEntrypointTypes<kQuickInitializeStaticStorage, void*, uint32_t>();
409     } else {
410       CheckEntrypointTypes<kQuickInitializeType, void*, uint32_t>();
411     }
412 
413     // For HLoadClass/kBssEntry, store the resolved Class to the BSS entry.
414     if (is_load_class_bss_entry) {
415       if (call_saves_everything_except_r0) {
416         // The class entry address was preserved in `entry_address` thanks to kSaveEverything.
417         __ str(R0, Address(entry_address));
418       } else {
419         // For non-Baker read barrier, we need to re-calculate the address of the string entry.
420         Register temp = IP;
421         CodeGeneratorARM::PcRelativePatchInfo* labels =
422             arm_codegen->NewTypeBssEntryPatch(cls_->GetDexFile(), type_index);
423         __ BindTrackedLabel(&labels->movw_label);
424         __ movw(temp, /* placeholder */ 0u);
425         __ BindTrackedLabel(&labels->movt_label);
426         __ movt(temp, /* placeholder */ 0u);
427         __ BindTrackedLabel(&labels->add_pc_label);
428         __ add(temp, temp, ShifterOperand(PC));
429         __ str(R0, Address(temp));
430       }
431     }
432     // Move the class to the desired location.
433     if (out.IsValid()) {
434       DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
435       arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0));
436     }
437     RestoreLiveRegisters(codegen, locations);
438     __ b(GetExitLabel());
439   }
440 
GetDescription() const441   const char* GetDescription() const OVERRIDE { return "LoadClassSlowPathARM"; }
442 
443  private:
444   // The class this slow path will load.
445   HLoadClass* const cls_;
446 
447   // The dex PC of `at_`.
448   const uint32_t dex_pc_;
449 
450   // Whether to initialize the class.
451   const bool do_clinit_;
452 
453   DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathARM);
454 };
455 
456 class LoadStringSlowPathARM : public SlowPathCodeARM {
457  public:
LoadStringSlowPathARM(HLoadString * instruction)458   explicit LoadStringSlowPathARM(HLoadString* instruction) : SlowPathCodeARM(instruction) {}
459 
EmitNativeCode(CodeGenerator * codegen)460   void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
461     DCHECK(instruction_->IsLoadString());
462     DCHECK_EQ(instruction_->AsLoadString()->GetLoadKind(), HLoadString::LoadKind::kBssEntry);
463     LocationSummary* locations = instruction_->GetLocations();
464     DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
465     HLoadString* load = instruction_->AsLoadString();
466     const dex::StringIndex string_index = load->GetStringIndex();
467     Register out = locations->Out().AsRegister<Register>();
468     constexpr bool call_saves_everything_except_r0 = (!kUseReadBarrier || kUseBakerReadBarrier);
469 
470     CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
471     __ Bind(GetEntryLabel());
472     SaveLiveRegisters(codegen, locations);
473 
474     InvokeRuntimeCallingConvention calling_convention;
475     // In the unlucky case that the `temp` is R0, we preserve the address in `out` across
476     // the kSaveEverything call.
477     Register entry_address = kNoRegister;
478     if (call_saves_everything_except_r0) {
479       Register temp = locations->GetTemp(0).AsRegister<Register>();
480       bool temp_is_r0 = (temp == calling_convention.GetRegisterAt(0));
481       entry_address = temp_is_r0 ? out : temp;
482       DCHECK_NE(entry_address, calling_convention.GetRegisterAt(0));
483       if (temp_is_r0) {
484         __ mov(entry_address, ShifterOperand(temp));
485       }
486     }
487 
488     __ LoadImmediate(calling_convention.GetRegisterAt(0), string_index.index_);
489     arm_codegen->InvokeRuntime(kQuickResolveString, instruction_, instruction_->GetDexPc(), this);
490     CheckEntrypointTypes<kQuickResolveString, void*, uint32_t>();
491 
492     // Store the resolved String to the .bss entry.
493     if (call_saves_everything_except_r0) {
494       // The string entry address was preserved in `entry_address` thanks to kSaveEverything.
495       __ str(R0, Address(entry_address));
496     } else {
497       // For non-Baker read barrier, we need to re-calculate the address of the string entry.
498       Register temp = IP;
499       CodeGeneratorARM::PcRelativePatchInfo* labels =
500           arm_codegen->NewPcRelativeStringPatch(load->GetDexFile(), string_index);
501       __ BindTrackedLabel(&labels->movw_label);
502       __ movw(temp, /* placeholder */ 0u);
503       __ BindTrackedLabel(&labels->movt_label);
504       __ movt(temp, /* placeholder */ 0u);
505       __ BindTrackedLabel(&labels->add_pc_label);
506       __ add(temp, temp, ShifterOperand(PC));
507       __ str(R0, Address(temp));
508     }
509 
510     arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0));
511     RestoreLiveRegisters(codegen, locations);
512 
513     __ b(GetExitLabel());
514   }
515 
GetDescription() const516   const char* GetDescription() const OVERRIDE { return "LoadStringSlowPathARM"; }
517 
518  private:
519   DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathARM);
520 };
521 
522 class TypeCheckSlowPathARM : public SlowPathCodeARM {
523  public:
TypeCheckSlowPathARM(HInstruction * instruction,bool is_fatal)524   TypeCheckSlowPathARM(HInstruction* instruction, bool is_fatal)
525       : SlowPathCodeARM(instruction), is_fatal_(is_fatal) {}
526 
EmitNativeCode(CodeGenerator * codegen)527   void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
528     LocationSummary* locations = instruction_->GetLocations();
529     DCHECK(instruction_->IsCheckCast()
530            || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
531 
532     CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
533     __ Bind(GetEntryLabel());
534 
535     if (!is_fatal_) {
536       SaveLiveRegisters(codegen, locations);
537     }
538 
539     // We're moving two locations to locations that could overlap, so we need a parallel
540     // move resolver.
541     InvokeRuntimeCallingConvention calling_convention;
542     codegen->EmitParallelMoves(locations->InAt(0),
543                                Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
544                                Primitive::kPrimNot,
545                                locations->InAt(1),
546                                Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
547                                Primitive::kPrimNot);
548     if (instruction_->IsInstanceOf()) {
549       arm_codegen->InvokeRuntime(kQuickInstanceofNonTrivial,
550                                  instruction_,
551                                  instruction_->GetDexPc(),
552                                  this);
553       CheckEntrypointTypes<kQuickInstanceofNonTrivial, size_t, mirror::Object*, mirror::Class*>();
554       arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0));
555     } else {
556       DCHECK(instruction_->IsCheckCast());
557       arm_codegen->InvokeRuntime(kQuickCheckInstanceOf,
558                                  instruction_,
559                                  instruction_->GetDexPc(),
560                                  this);
561       CheckEntrypointTypes<kQuickCheckInstanceOf, void, mirror::Object*, mirror::Class*>();
562     }
563 
564     if (!is_fatal_) {
565       RestoreLiveRegisters(codegen, locations);
566       __ b(GetExitLabel());
567     }
568   }
569 
GetDescription() const570   const char* GetDescription() const OVERRIDE { return "TypeCheckSlowPathARM"; }
571 
IsFatal() const572   bool IsFatal() const OVERRIDE { return is_fatal_; }
573 
574  private:
575   const bool is_fatal_;
576 
577   DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathARM);
578 };
579 
580 class DeoptimizationSlowPathARM : public SlowPathCodeARM {
581  public:
DeoptimizationSlowPathARM(HDeoptimize * instruction)582   explicit DeoptimizationSlowPathARM(HDeoptimize* instruction)
583     : SlowPathCodeARM(instruction) {}
584 
EmitNativeCode(CodeGenerator * codegen)585   void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
586     CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
587     __ Bind(GetEntryLabel());
588     LocationSummary* locations = instruction_->GetLocations();
589     SaveLiveRegisters(codegen, locations);
590     InvokeRuntimeCallingConvention calling_convention;
591     __ LoadImmediate(calling_convention.GetRegisterAt(0),
592                      static_cast<uint32_t>(instruction_->AsDeoptimize()->GetDeoptimizationKind()));
593     arm_codegen->InvokeRuntime(kQuickDeoptimize, instruction_, instruction_->GetDexPc(), this);
594     CheckEntrypointTypes<kQuickDeoptimize, void, DeoptimizationKind>();
595   }
596 
GetDescription() const597   const char* GetDescription() const OVERRIDE { return "DeoptimizationSlowPathARM"; }
598 
599  private:
600   DISALLOW_COPY_AND_ASSIGN(DeoptimizationSlowPathARM);
601 };
602 
603 class ArraySetSlowPathARM : public SlowPathCodeARM {
604  public:
ArraySetSlowPathARM(HInstruction * instruction)605   explicit ArraySetSlowPathARM(HInstruction* instruction) : SlowPathCodeARM(instruction) {}
606 
EmitNativeCode(CodeGenerator * codegen)607   void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
608     LocationSummary* locations = instruction_->GetLocations();
609     __ Bind(GetEntryLabel());
610     SaveLiveRegisters(codegen, locations);
611 
612     InvokeRuntimeCallingConvention calling_convention;
613     HParallelMove parallel_move(codegen->GetGraph()->GetArena());
614     parallel_move.AddMove(
615         locations->InAt(0),
616         Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
617         Primitive::kPrimNot,
618         nullptr);
619     parallel_move.AddMove(
620         locations->InAt(1),
621         Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
622         Primitive::kPrimInt,
623         nullptr);
624     parallel_move.AddMove(
625         locations->InAt(2),
626         Location::RegisterLocation(calling_convention.GetRegisterAt(2)),
627         Primitive::kPrimNot,
628         nullptr);
629     codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
630 
631     CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
632     arm_codegen->InvokeRuntime(kQuickAputObject, instruction_, instruction_->GetDexPc(), this);
633     CheckEntrypointTypes<kQuickAputObject, void, mirror::Array*, int32_t, mirror::Object*>();
634     RestoreLiveRegisters(codegen, locations);
635     __ b(GetExitLabel());
636   }
637 
GetDescription() const638   const char* GetDescription() const OVERRIDE { return "ArraySetSlowPathARM"; }
639 
640  private:
641   DISALLOW_COPY_AND_ASSIGN(ArraySetSlowPathARM);
642 };
643 
644 // Abstract base class for read barrier slow paths marking a reference
645 // `ref`.
646 //
647 // Argument `entrypoint` must be a register location holding the read
648 // barrier marking runtime entry point to be invoked.
649 class ReadBarrierMarkSlowPathBaseARM : public SlowPathCodeARM {
650  protected:
ReadBarrierMarkSlowPathBaseARM(HInstruction * instruction,Location ref,Location entrypoint)651   ReadBarrierMarkSlowPathBaseARM(HInstruction* instruction, Location ref, Location entrypoint)
652       : SlowPathCodeARM(instruction), ref_(ref), entrypoint_(entrypoint) {
653     DCHECK(kEmitCompilerReadBarrier);
654   }
655 
GetDescription() const656   const char* GetDescription() const OVERRIDE { return "ReadBarrierMarkSlowPathBaseARM"; }
657 
658   // Generate assembly code calling the read barrier marking runtime
659   // entry point (ReadBarrierMarkRegX).
GenerateReadBarrierMarkRuntimeCall(CodeGenerator * codegen)660   void GenerateReadBarrierMarkRuntimeCall(CodeGenerator* codegen) {
661     Register ref_reg = ref_.AsRegister<Register>();
662 
663     // No need to save live registers; it's taken care of by the
664     // entrypoint. Also, there is no need to update the stack mask,
665     // as this runtime call will not trigger a garbage collection.
666     CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
667     DCHECK_NE(ref_reg, SP);
668     DCHECK_NE(ref_reg, LR);
669     DCHECK_NE(ref_reg, PC);
670     // IP is used internally by the ReadBarrierMarkRegX entry point
671     // as a temporary, it cannot be the entry point's input/output.
672     DCHECK_NE(ref_reg, IP);
673     DCHECK(0 <= ref_reg && ref_reg < kNumberOfCoreRegisters) << ref_reg;
674     // "Compact" slow path, saving two moves.
675     //
676     // Instead of using the standard runtime calling convention (input
677     // and output in R0):
678     //
679     //   R0 <- ref
680     //   R0 <- ReadBarrierMark(R0)
681     //   ref <- R0
682     //
683     // we just use rX (the register containing `ref`) as input and output
684     // of a dedicated entrypoint:
685     //
686     //   rX <- ReadBarrierMarkRegX(rX)
687     //
688     if (entrypoint_.IsValid()) {
689       arm_codegen->ValidateInvokeRuntimeWithoutRecordingPcInfo(instruction_, this);
690       __ blx(entrypoint_.AsRegister<Register>());
691     } else {
692       // Entrypoint is not already loaded, load from the thread.
693       int32_t entry_point_offset =
694           CodeGenerator::GetReadBarrierMarkEntryPointsOffset<kArmPointerSize>(ref_reg);
695       // This runtime call does not require a stack map.
696       arm_codegen->InvokeRuntimeWithoutRecordingPcInfo(entry_point_offset, instruction_, this);
697     }
698   }
699 
700   // The location (register) of the marked object reference.
701   const Location ref_;
702 
703   // The location of the entrypoint if it is already loaded.
704   const Location entrypoint_;
705 
706  private:
707   DISALLOW_COPY_AND_ASSIGN(ReadBarrierMarkSlowPathBaseARM);
708 };
709 
710 // Slow path marking an object reference `ref` during a read
711 // barrier. The field `obj.field` in the object `obj` holding this
712 // reference does not get updated by this slow path after marking.
713 //
714 // This means that after the execution of this slow path, `ref` will
715 // always be up-to-date, but `obj.field` may not; i.e., after the
716 // flip, `ref` will be a to-space reference, but `obj.field` will
717 // probably still be a from-space reference (unless it gets updated by
718 // another thread, or if another thread installed another object
719 // reference (different from `ref`) in `obj.field`).
720 //
721 // If `entrypoint` is a valid location it is assumed to already be
722 // holding the entrypoint. The case where the entrypoint is passed in
723 // is when the decision to mark is based on whether the GC is marking.
724 class ReadBarrierMarkSlowPathARM : public ReadBarrierMarkSlowPathBaseARM {
725  public:
ReadBarrierMarkSlowPathARM(HInstruction * instruction,Location ref,Location entrypoint=Location::NoLocation ())726   ReadBarrierMarkSlowPathARM(HInstruction* instruction,
727                              Location ref,
728                              Location entrypoint = Location::NoLocation())
729       : ReadBarrierMarkSlowPathBaseARM(instruction, ref, entrypoint) {
730     DCHECK(kEmitCompilerReadBarrier);
731   }
732 
GetDescription() const733   const char* GetDescription() const OVERRIDE { return "ReadBarrierMarkSlowPathARM"; }
734 
EmitNativeCode(CodeGenerator * codegen)735   void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
736     LocationSummary* locations = instruction_->GetLocations();
737     DCHECK(locations->CanCall());
738     if (kIsDebugBuild) {
739       Register ref_reg = ref_.AsRegister<Register>();
740       DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(ref_reg)) << ref_reg;
741     }
742     DCHECK(instruction_->IsLoadClass() || instruction_->IsLoadString())
743         << "Unexpected instruction in read barrier marking slow path: "
744         << instruction_->DebugName();
745 
746     __ Bind(GetEntryLabel());
747     GenerateReadBarrierMarkRuntimeCall(codegen);
748     __ b(GetExitLabel());
749   }
750 
751  private:
752   DISALLOW_COPY_AND_ASSIGN(ReadBarrierMarkSlowPathARM);
753 };
754 
755 // Slow path loading `obj`'s lock word, loading a reference from
756 // object `*(obj + offset + (index << scale_factor))` into `ref`, and
757 // marking `ref` if `obj` is gray according to the lock word (Baker
758 // read barrier). The field `obj.field` in the object `obj` holding
759 // this reference does not get updated by this slow path after marking
760 // (see LoadReferenceWithBakerReadBarrierAndUpdateFieldSlowPathARM
761 // below for that).
762 //
763 // This means that after the execution of this slow path, `ref` will
764 // always be up-to-date, but `obj.field` may not; i.e., after the
765 // flip, `ref` will be a to-space reference, but `obj.field` will
766 // probably still be a from-space reference (unless it gets updated by
767 // another thread, or if another thread installed another object
768 // reference (different from `ref`) in `obj.field`).
769 //
770 // Argument `entrypoint` must be a register location holding the read
771 // barrier marking runtime entry point to be invoked.
772 class LoadReferenceWithBakerReadBarrierSlowPathARM : public ReadBarrierMarkSlowPathBaseARM {
773  public:
LoadReferenceWithBakerReadBarrierSlowPathARM(HInstruction * instruction,Location ref,Register obj,uint32_t offset,Location index,ScaleFactor scale_factor,bool needs_null_check,Register temp,Location entrypoint)774   LoadReferenceWithBakerReadBarrierSlowPathARM(HInstruction* instruction,
775                                                Location ref,
776                                                Register obj,
777                                                uint32_t offset,
778                                                Location index,
779                                                ScaleFactor scale_factor,
780                                                bool needs_null_check,
781                                                Register temp,
782                                                Location entrypoint)
783       : ReadBarrierMarkSlowPathBaseARM(instruction, ref, entrypoint),
784         obj_(obj),
785         offset_(offset),
786         index_(index),
787         scale_factor_(scale_factor),
788         needs_null_check_(needs_null_check),
789         temp_(temp) {
790     DCHECK(kEmitCompilerReadBarrier);
791     DCHECK(kUseBakerReadBarrier);
792   }
793 
GetDescription() const794   const char* GetDescription() const OVERRIDE {
795     return "LoadReferenceWithBakerReadBarrierSlowPathARM";
796   }
797 
EmitNativeCode(CodeGenerator * codegen)798   void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
799     LocationSummary* locations = instruction_->GetLocations();
800     Register ref_reg = ref_.AsRegister<Register>();
801     DCHECK(locations->CanCall());
802     DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(ref_reg)) << ref_reg;
803     DCHECK_NE(ref_reg, temp_);
804     DCHECK(instruction_->IsInstanceFieldGet() ||
805            instruction_->IsStaticFieldGet() ||
806            instruction_->IsArrayGet() ||
807            instruction_->IsArraySet() ||
808            instruction_->IsInstanceOf() ||
809            instruction_->IsCheckCast() ||
810            (instruction_->IsInvokeVirtual() && instruction_->GetLocations()->Intrinsified()) ||
811            (instruction_->IsInvokeStaticOrDirect() && instruction_->GetLocations()->Intrinsified()))
812         << "Unexpected instruction in read barrier marking slow path: "
813         << instruction_->DebugName();
814     // The read barrier instrumentation of object ArrayGet
815     // instructions does not support the HIntermediateAddress
816     // instruction.
817     DCHECK(!(instruction_->IsArrayGet() &&
818              instruction_->AsArrayGet()->GetArray()->IsIntermediateAddress()));
819 
820     __ Bind(GetEntryLabel());
821 
822     // When using MaybeGenerateReadBarrierSlow, the read barrier call is
823     // inserted after the original load. However, in fast path based
824     // Baker's read barriers, we need to perform the load of
825     // mirror::Object::monitor_ *before* the original reference load.
826     // This load-load ordering is required by the read barrier.
827     // The fast path/slow path (for Baker's algorithm) should look like:
828     //
829     //   uint32_t rb_state = Lockword(obj->monitor_).ReadBarrierState();
830     //   lfence;  // Load fence or artificial data dependency to prevent load-load reordering
831     //   HeapReference<mirror::Object> ref = *src;  // Original reference load.
832     //   bool is_gray = (rb_state == ReadBarrier::GrayState());
833     //   if (is_gray) {
834     //     ref = entrypoint(ref);  // ref = ReadBarrier::Mark(ref);  // Runtime entry point call.
835     //   }
836     //
837     // Note: the original implementation in ReadBarrier::Barrier is
838     // slightly more complex as it performs additional checks that we do
839     // not do here for performance reasons.
840 
841     // /* int32_t */ monitor = obj->monitor_
842     uint32_t monitor_offset = mirror::Object::MonitorOffset().Int32Value();
843     __ LoadFromOffset(kLoadWord, temp_, obj_, monitor_offset);
844     if (needs_null_check_) {
845       codegen->MaybeRecordImplicitNullCheck(instruction_);
846     }
847     // /* LockWord */ lock_word = LockWord(monitor)
848     static_assert(sizeof(LockWord) == sizeof(int32_t),
849                   "art::LockWord and int32_t have different sizes.");
850 
851     // Introduce a dependency on the lock_word including the rb_state,
852     // which shall prevent load-load reordering without using
853     // a memory barrier (which would be more expensive).
854     // `obj` is unchanged by this operation, but its value now depends
855     // on `temp`.
856     __ add(obj_, obj_, ShifterOperand(temp_, LSR, 32));
857 
858     // The actual reference load.
859     // A possible implicit null check has already been handled above.
860     CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
861     arm_codegen->GenerateRawReferenceLoad(
862         instruction_, ref_, obj_, offset_, index_, scale_factor_, /* needs_null_check */ false);
863 
864     // Mark the object `ref` when `obj` is gray.
865     //
866     // if (rb_state == ReadBarrier::GrayState())
867     //   ref = ReadBarrier::Mark(ref);
868     //
869     // Given the numeric representation, it's enough to check the low bit of the
870     // rb_state. We do that by shifting the bit out of the lock word with LSRS
871     // which can be a 16-bit instruction unlike the TST immediate.
872     static_assert(ReadBarrier::WhiteState() == 0, "Expecting white to have value 0");
873     static_assert(ReadBarrier::GrayState() == 1, "Expecting gray to have value 1");
874     __ Lsrs(temp_, temp_, LockWord::kReadBarrierStateShift + 1);
875     __ b(GetExitLabel(), CC);  // Carry flag is the last bit shifted out by LSRS.
876     GenerateReadBarrierMarkRuntimeCall(codegen);
877 
878     __ b(GetExitLabel());
879   }
880 
881  private:
882   // The register containing the object holding the marked object reference field.
883   Register obj_;
884   // The offset, index and scale factor to access the reference in `obj_`.
885   uint32_t offset_;
886   Location index_;
887   ScaleFactor scale_factor_;
888   // Is a null check required?
889   bool needs_null_check_;
890   // A temporary register used to hold the lock word of `obj_`.
891   Register temp_;
892 
893   DISALLOW_COPY_AND_ASSIGN(LoadReferenceWithBakerReadBarrierSlowPathARM);
894 };
895 
896 // Slow path loading `obj`'s lock word, loading a reference from
897 // object `*(obj + offset + (index << scale_factor))` into `ref`, and
898 // marking `ref` if `obj` is gray according to the lock word (Baker
899 // read barrier). If needed, this slow path also atomically updates
900 // the field `obj.field` in the object `obj` holding this reference
901 // after marking (contrary to
902 // LoadReferenceWithBakerReadBarrierSlowPathARM above, which never
903 // tries to update `obj.field`).
904 //
905 // This means that after the execution of this slow path, both `ref`
906 // and `obj.field` will be up-to-date; i.e., after the flip, both will
907 // hold the same to-space reference (unless another thread installed
908 // another object reference (different from `ref`) in `obj.field`).
909 //
910 // Argument `entrypoint` must be a register location holding the read
911 // barrier marking runtime entry point to be invoked.
912 class LoadReferenceWithBakerReadBarrierAndUpdateFieldSlowPathARM
913     : public ReadBarrierMarkSlowPathBaseARM {
914  public:
LoadReferenceWithBakerReadBarrierAndUpdateFieldSlowPathARM(HInstruction * instruction,Location ref,Register obj,uint32_t offset,Location index,ScaleFactor scale_factor,bool needs_null_check,Register temp1,Register temp2,Location entrypoint)915   LoadReferenceWithBakerReadBarrierAndUpdateFieldSlowPathARM(HInstruction* instruction,
916                                                              Location ref,
917                                                              Register obj,
918                                                              uint32_t offset,
919                                                              Location index,
920                                                              ScaleFactor scale_factor,
921                                                              bool needs_null_check,
922                                                              Register temp1,
923                                                              Register temp2,
924                                                              Location entrypoint)
925       : ReadBarrierMarkSlowPathBaseARM(instruction, ref, entrypoint),
926         obj_(obj),
927         offset_(offset),
928         index_(index),
929         scale_factor_(scale_factor),
930         needs_null_check_(needs_null_check),
931         temp1_(temp1),
932         temp2_(temp2) {
933     DCHECK(kEmitCompilerReadBarrier);
934     DCHECK(kUseBakerReadBarrier);
935   }
936 
GetDescription() const937   const char* GetDescription() const OVERRIDE {
938     return "LoadReferenceWithBakerReadBarrierAndUpdateFieldSlowPathARM";
939   }
940 
EmitNativeCode(CodeGenerator * codegen)941   void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
942     LocationSummary* locations = instruction_->GetLocations();
943     Register ref_reg = ref_.AsRegister<Register>();
944     DCHECK(locations->CanCall());
945     DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(ref_reg)) << ref_reg;
946     DCHECK_NE(ref_reg, temp1_);
947 
948     // This slow path is only used by the UnsafeCASObject intrinsic at the moment.
949     DCHECK((instruction_->IsInvokeVirtual() && instruction_->GetLocations()->Intrinsified()))
950         << "Unexpected instruction in read barrier marking and field updating slow path: "
951         << instruction_->DebugName();
952     DCHECK(instruction_->GetLocations()->Intrinsified());
953     DCHECK_EQ(instruction_->AsInvoke()->GetIntrinsic(), Intrinsics::kUnsafeCASObject);
954     DCHECK_EQ(offset_, 0u);
955     DCHECK_EQ(scale_factor_, ScaleFactor::TIMES_1);
956     // The location of the offset of the marked reference field within `obj_`.
957     Location field_offset = index_;
958     DCHECK(field_offset.IsRegisterPair()) << field_offset;
959 
960     __ Bind(GetEntryLabel());
961 
962     // /* int32_t */ monitor = obj->monitor_
963     uint32_t monitor_offset = mirror::Object::MonitorOffset().Int32Value();
964     __ LoadFromOffset(kLoadWord, temp1_, obj_, monitor_offset);
965     if (needs_null_check_) {
966       codegen->MaybeRecordImplicitNullCheck(instruction_);
967     }
968     // /* LockWord */ lock_word = LockWord(monitor)
969     static_assert(sizeof(LockWord) == sizeof(int32_t),
970                   "art::LockWord and int32_t have different sizes.");
971 
972     // Introduce a dependency on the lock_word including the rb_state,
973     // which shall prevent load-load reordering without using
974     // a memory barrier (which would be more expensive).
975     // `obj` is unchanged by this operation, but its value now depends
976     // on `temp1`.
977     __ add(obj_, obj_, ShifterOperand(temp1_, LSR, 32));
978 
979     // The actual reference load.
980     // A possible implicit null check has already been handled above.
981     CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
982     arm_codegen->GenerateRawReferenceLoad(
983         instruction_, ref_, obj_, offset_, index_, scale_factor_, /* needs_null_check */ false);
984 
985     // Mark the object `ref` when `obj` is gray.
986     //
987     // if (rb_state == ReadBarrier::GrayState())
988     //   ref = ReadBarrier::Mark(ref);
989     //
990     // Given the numeric representation, it's enough to check the low bit of the
991     // rb_state. We do that by shifting the bit out of the lock word with LSRS
992     // which can be a 16-bit instruction unlike the TST immediate.
993     static_assert(ReadBarrier::WhiteState() == 0, "Expecting white to have value 0");
994     static_assert(ReadBarrier::GrayState() == 1, "Expecting gray to have value 1");
995     __ Lsrs(temp1_, temp1_, LockWord::kReadBarrierStateShift + 1);
996     __ b(GetExitLabel(), CC);  // Carry flag is the last bit shifted out by LSRS.
997 
998     // Save the old value of the reference before marking it.
999     // Note that we cannot use IP to save the old reference, as IP is
1000     // used internally by the ReadBarrierMarkRegX entry point, and we
1001     // need the old reference after the call to that entry point.
1002     DCHECK_NE(temp1_, IP);
1003     __ Mov(temp1_, ref_reg);
1004 
1005     GenerateReadBarrierMarkRuntimeCall(codegen);
1006 
1007     // If the new reference is different from the old reference,
1008     // update the field in the holder (`*(obj_ + field_offset)`).
1009     //
1010     // Note that this field could also hold a different object, if
1011     // another thread had concurrently changed it. In that case, the
1012     // LDREX/SUBS/ITNE sequence of instructions in the compare-and-set
1013     // (CAS) operation below would abort the CAS, leaving the field
1014     // as-is.
1015     __ cmp(temp1_, ShifterOperand(ref_reg));
1016     __ b(GetExitLabel(), EQ);
1017 
1018     // Update the the holder's field atomically.  This may fail if
1019     // mutator updates before us, but it's OK.  This is achieved
1020     // using a strong compare-and-set (CAS) operation with relaxed
1021     // memory synchronization ordering, where the expected value is
1022     // the old reference and the desired value is the new reference.
1023 
1024     // Convenience aliases.
1025     Register base = obj_;
1026     // The UnsafeCASObject intrinsic uses a register pair as field
1027     // offset ("long offset"), of which only the low part contains
1028     // data.
1029     Register offset = field_offset.AsRegisterPairLow<Register>();
1030     Register expected = temp1_;
1031     Register value = ref_reg;
1032     Register tmp_ptr = IP;       // Pointer to actual memory.
1033     Register tmp = temp2_;       // Value in memory.
1034 
1035     __ add(tmp_ptr, base, ShifterOperand(offset));
1036 
1037     if (kPoisonHeapReferences) {
1038       __ PoisonHeapReference(expected);
1039       if (value == expected) {
1040         // Do not poison `value`, as it is the same register as
1041         // `expected`, which has just been poisoned.
1042       } else {
1043         __ PoisonHeapReference(value);
1044       }
1045     }
1046 
1047     // do {
1048     //   tmp = [r_ptr] - expected;
1049     // } while (tmp == 0 && failure([r_ptr] <- r_new_value));
1050 
1051     Label loop_head, exit_loop;
1052     __ Bind(&loop_head);
1053 
1054     __ ldrex(tmp, tmp_ptr);
1055 
1056     __ subs(tmp, tmp, ShifterOperand(expected));
1057 
1058     __ it(NE);
1059     __ clrex(NE);
1060 
1061     __ b(&exit_loop, NE);
1062 
1063     __ strex(tmp, value, tmp_ptr);
1064     __ cmp(tmp, ShifterOperand(1));
1065     __ b(&loop_head, EQ);
1066 
1067     __ Bind(&exit_loop);
1068 
1069     if (kPoisonHeapReferences) {
1070       __ UnpoisonHeapReference(expected);
1071       if (value == expected) {
1072         // Do not unpoison `value`, as it is the same register as
1073         // `expected`, which has just been unpoisoned.
1074       } else {
1075         __ UnpoisonHeapReference(value);
1076       }
1077     }
1078 
1079     __ b(GetExitLabel());
1080   }
1081 
1082  private:
1083   // The register containing the object holding the marked object reference field.
1084   const Register obj_;
1085   // The offset, index and scale factor to access the reference in `obj_`.
1086   uint32_t offset_;
1087   Location index_;
1088   ScaleFactor scale_factor_;
1089   // Is a null check required?
1090   bool needs_null_check_;
1091   // A temporary register used to hold the lock word of `obj_`; and
1092   // also to hold the original reference value, when the reference is
1093   // marked.
1094   const Register temp1_;
1095   // A temporary register used in the implementation of the CAS, to
1096   // update the object's reference field.
1097   const Register temp2_;
1098 
1099   DISALLOW_COPY_AND_ASSIGN(LoadReferenceWithBakerReadBarrierAndUpdateFieldSlowPathARM);
1100 };
1101 
1102 // Slow path generating a read barrier for a heap reference.
1103 class ReadBarrierForHeapReferenceSlowPathARM : public SlowPathCodeARM {
1104  public:
ReadBarrierForHeapReferenceSlowPathARM(HInstruction * instruction,Location out,Location ref,Location obj,uint32_t offset,Location index)1105   ReadBarrierForHeapReferenceSlowPathARM(HInstruction* instruction,
1106                                          Location out,
1107                                          Location ref,
1108                                          Location obj,
1109                                          uint32_t offset,
1110                                          Location index)
1111       : SlowPathCodeARM(instruction),
1112         out_(out),
1113         ref_(ref),
1114         obj_(obj),
1115         offset_(offset),
1116         index_(index) {
1117     DCHECK(kEmitCompilerReadBarrier);
1118     // If `obj` is equal to `out` or `ref`, it means the initial object
1119     // has been overwritten by (or after) the heap object reference load
1120     // to be instrumented, e.g.:
1121     //
1122     //   __ LoadFromOffset(kLoadWord, out, out, offset);
1123     //   codegen_->GenerateReadBarrierSlow(instruction, out_loc, out_loc, out_loc, offset);
1124     //
1125     // In that case, we have lost the information about the original
1126     // object, and the emitted read barrier cannot work properly.
1127     DCHECK(!obj.Equals(out)) << "obj=" << obj << " out=" << out;
1128     DCHECK(!obj.Equals(ref)) << "obj=" << obj << " ref=" << ref;
1129   }
1130 
EmitNativeCode(CodeGenerator * codegen)1131   void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
1132     CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
1133     LocationSummary* locations = instruction_->GetLocations();
1134     Register reg_out = out_.AsRegister<Register>();
1135     DCHECK(locations->CanCall());
1136     DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(reg_out));
1137     DCHECK(instruction_->IsInstanceFieldGet() ||
1138            instruction_->IsStaticFieldGet() ||
1139            instruction_->IsArrayGet() ||
1140            instruction_->IsInstanceOf() ||
1141            instruction_->IsCheckCast() ||
1142            (instruction_->IsInvokeVirtual() && instruction_->GetLocations()->Intrinsified()))
1143         << "Unexpected instruction in read barrier for heap reference slow path: "
1144         << instruction_->DebugName();
1145     // The read barrier instrumentation of object ArrayGet
1146     // instructions does not support the HIntermediateAddress
1147     // instruction.
1148     DCHECK(!(instruction_->IsArrayGet() &&
1149              instruction_->AsArrayGet()->GetArray()->IsIntermediateAddress()));
1150 
1151     __ Bind(GetEntryLabel());
1152     SaveLiveRegisters(codegen, locations);
1153 
1154     // We may have to change the index's value, but as `index_` is a
1155     // constant member (like other "inputs" of this slow path),
1156     // introduce a copy of it, `index`.
1157     Location index = index_;
1158     if (index_.IsValid()) {
1159       // Handle `index_` for HArrayGet and UnsafeGetObject/UnsafeGetObjectVolatile intrinsics.
1160       if (instruction_->IsArrayGet()) {
1161         // Compute the actual memory offset and store it in `index`.
1162         Register index_reg = index_.AsRegister<Register>();
1163         DCHECK(locations->GetLiveRegisters()->ContainsCoreRegister(index_reg));
1164         if (codegen->IsCoreCalleeSaveRegister(index_reg)) {
1165           // We are about to change the value of `index_reg` (see the
1166           // calls to art::arm::Thumb2Assembler::Lsl and
1167           // art::arm::Thumb2Assembler::AddConstant below), but it has
1168           // not been saved by the previous call to
1169           // art::SlowPathCode::SaveLiveRegisters, as it is a
1170           // callee-save register --
1171           // art::SlowPathCode::SaveLiveRegisters does not consider
1172           // callee-save registers, as it has been designed with the
1173           // assumption that callee-save registers are supposed to be
1174           // handled by the called function.  So, as a callee-save
1175           // register, `index_reg` _would_ eventually be saved onto
1176           // the stack, but it would be too late: we would have
1177           // changed its value earlier.  Therefore, we manually save
1178           // it here into another freely available register,
1179           // `free_reg`, chosen of course among the caller-save
1180           // registers (as a callee-save `free_reg` register would
1181           // exhibit the same problem).
1182           //
1183           // Note we could have requested a temporary register from
1184           // the register allocator instead; but we prefer not to, as
1185           // this is a slow path, and we know we can find a
1186           // caller-save register that is available.
1187           Register free_reg = FindAvailableCallerSaveRegister(codegen);
1188           __ Mov(free_reg, index_reg);
1189           index_reg = free_reg;
1190           index = Location::RegisterLocation(index_reg);
1191         } else {
1192           // The initial register stored in `index_` has already been
1193           // saved in the call to art::SlowPathCode::SaveLiveRegisters
1194           // (as it is not a callee-save register), so we can freely
1195           // use it.
1196         }
1197         // Shifting the index value contained in `index_reg` by the scale
1198         // factor (2) cannot overflow in practice, as the runtime is
1199         // unable to allocate object arrays with a size larger than
1200         // 2^26 - 1 (that is, 2^28 - 4 bytes).
1201         __ Lsl(index_reg, index_reg, TIMES_4);
1202         static_assert(
1203             sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
1204             "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
1205         __ AddConstant(index_reg, index_reg, offset_);
1206       } else {
1207         // In the case of the UnsafeGetObject/UnsafeGetObjectVolatile
1208         // intrinsics, `index_` is not shifted by a scale factor of 2
1209         // (as in the case of ArrayGet), as it is actually an offset
1210         // to an object field within an object.
1211         DCHECK(instruction_->IsInvoke()) << instruction_->DebugName();
1212         DCHECK(instruction_->GetLocations()->Intrinsified());
1213         DCHECK((instruction_->AsInvoke()->GetIntrinsic() == Intrinsics::kUnsafeGetObject) ||
1214                (instruction_->AsInvoke()->GetIntrinsic() == Intrinsics::kUnsafeGetObjectVolatile))
1215             << instruction_->AsInvoke()->GetIntrinsic();
1216         DCHECK_EQ(offset_, 0U);
1217         DCHECK(index_.IsRegisterPair());
1218         // UnsafeGet's offset location is a register pair, the low
1219         // part contains the correct offset.
1220         index = index_.ToLow();
1221       }
1222     }
1223 
1224     // We're moving two or three locations to locations that could
1225     // overlap, so we need a parallel move resolver.
1226     InvokeRuntimeCallingConvention calling_convention;
1227     HParallelMove parallel_move(codegen->GetGraph()->GetArena());
1228     parallel_move.AddMove(ref_,
1229                           Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
1230                           Primitive::kPrimNot,
1231                           nullptr);
1232     parallel_move.AddMove(obj_,
1233                           Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
1234                           Primitive::kPrimNot,
1235                           nullptr);
1236     if (index.IsValid()) {
1237       parallel_move.AddMove(index,
1238                             Location::RegisterLocation(calling_convention.GetRegisterAt(2)),
1239                             Primitive::kPrimInt,
1240                             nullptr);
1241       codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
1242     } else {
1243       codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
1244       __ LoadImmediate(calling_convention.GetRegisterAt(2), offset_);
1245     }
1246     arm_codegen->InvokeRuntime(kQuickReadBarrierSlow, instruction_, instruction_->GetDexPc(), this);
1247     CheckEntrypointTypes<
1248         kQuickReadBarrierSlow, mirror::Object*, mirror::Object*, mirror::Object*, uint32_t>();
1249     arm_codegen->Move32(out_, Location::RegisterLocation(R0));
1250 
1251     RestoreLiveRegisters(codegen, locations);
1252     __ b(GetExitLabel());
1253   }
1254 
GetDescription() const1255   const char* GetDescription() const OVERRIDE { return "ReadBarrierForHeapReferenceSlowPathARM"; }
1256 
1257  private:
FindAvailableCallerSaveRegister(CodeGenerator * codegen)1258   Register FindAvailableCallerSaveRegister(CodeGenerator* codegen) {
1259     size_t ref = static_cast<int>(ref_.AsRegister<Register>());
1260     size_t obj = static_cast<int>(obj_.AsRegister<Register>());
1261     for (size_t i = 0, e = codegen->GetNumberOfCoreRegisters(); i < e; ++i) {
1262       if (i != ref && i != obj && !codegen->IsCoreCalleeSaveRegister(i)) {
1263         return static_cast<Register>(i);
1264       }
1265     }
1266     // We shall never fail to find a free caller-save register, as
1267     // there are more than two core caller-save registers on ARM
1268     // (meaning it is possible to find one which is different from
1269     // `ref` and `obj`).
1270     DCHECK_GT(codegen->GetNumberOfCoreCallerSaveRegisters(), 2u);
1271     LOG(FATAL) << "Could not find a free caller-save register";
1272     UNREACHABLE();
1273   }
1274 
1275   const Location out_;
1276   const Location ref_;
1277   const Location obj_;
1278   const uint32_t offset_;
1279   // An additional location containing an index to an array.
1280   // Only used for HArrayGet and the UnsafeGetObject &
1281   // UnsafeGetObjectVolatile intrinsics.
1282   const Location index_;
1283 
1284   DISALLOW_COPY_AND_ASSIGN(ReadBarrierForHeapReferenceSlowPathARM);
1285 };
1286 
1287 // Slow path generating a read barrier for a GC root.
1288 class ReadBarrierForRootSlowPathARM : public SlowPathCodeARM {
1289  public:
ReadBarrierForRootSlowPathARM(HInstruction * instruction,Location out,Location root)1290   ReadBarrierForRootSlowPathARM(HInstruction* instruction, Location out, Location root)
1291       : SlowPathCodeARM(instruction), out_(out), root_(root) {
1292     DCHECK(kEmitCompilerReadBarrier);
1293   }
1294 
EmitNativeCode(CodeGenerator * codegen)1295   void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
1296     LocationSummary* locations = instruction_->GetLocations();
1297     Register reg_out = out_.AsRegister<Register>();
1298     DCHECK(locations->CanCall());
1299     DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(reg_out));
1300     DCHECK(instruction_->IsLoadClass() || instruction_->IsLoadString())
1301         << "Unexpected instruction in read barrier for GC root slow path: "
1302         << instruction_->DebugName();
1303 
1304     __ Bind(GetEntryLabel());
1305     SaveLiveRegisters(codegen, locations);
1306 
1307     InvokeRuntimeCallingConvention calling_convention;
1308     CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
1309     arm_codegen->Move32(Location::RegisterLocation(calling_convention.GetRegisterAt(0)), root_);
1310     arm_codegen->InvokeRuntime(kQuickReadBarrierForRootSlow,
1311                                instruction_,
1312                                instruction_->GetDexPc(),
1313                                this);
1314     CheckEntrypointTypes<kQuickReadBarrierForRootSlow, mirror::Object*, GcRoot<mirror::Object>*>();
1315     arm_codegen->Move32(out_, Location::RegisterLocation(R0));
1316 
1317     RestoreLiveRegisters(codegen, locations);
1318     __ b(GetExitLabel());
1319   }
1320 
GetDescription() const1321   const char* GetDescription() const OVERRIDE { return "ReadBarrierForRootSlowPathARM"; }
1322 
1323  private:
1324   const Location out_;
1325   const Location root_;
1326 
1327   DISALLOW_COPY_AND_ASSIGN(ReadBarrierForRootSlowPathARM);
1328 };
1329 
ARMCondition(IfCondition cond)1330 inline Condition ARMCondition(IfCondition cond) {
1331   switch (cond) {
1332     case kCondEQ: return EQ;
1333     case kCondNE: return NE;
1334     case kCondLT: return LT;
1335     case kCondLE: return LE;
1336     case kCondGT: return GT;
1337     case kCondGE: return GE;
1338     case kCondB:  return LO;
1339     case kCondBE: return LS;
1340     case kCondA:  return HI;
1341     case kCondAE: return HS;
1342   }
1343   LOG(FATAL) << "Unreachable";
1344   UNREACHABLE();
1345 }
1346 
1347 // Maps signed condition to unsigned condition.
ARMUnsignedCondition(IfCondition cond)1348 inline Condition ARMUnsignedCondition(IfCondition cond) {
1349   switch (cond) {
1350     case kCondEQ: return EQ;
1351     case kCondNE: return NE;
1352     // Signed to unsigned.
1353     case kCondLT: return LO;
1354     case kCondLE: return LS;
1355     case kCondGT: return HI;
1356     case kCondGE: return HS;
1357     // Unsigned remain unchanged.
1358     case kCondB:  return LO;
1359     case kCondBE: return LS;
1360     case kCondA:  return HI;
1361     case kCondAE: return HS;
1362   }
1363   LOG(FATAL) << "Unreachable";
1364   UNREACHABLE();
1365 }
1366 
ARMFPCondition(IfCondition cond,bool gt_bias)1367 inline Condition ARMFPCondition(IfCondition cond, bool gt_bias) {
1368   // The ARM condition codes can express all the necessary branches, see the
1369   // "Meaning (floating-point)" column in the table A8-1 of the ARMv7 reference manual.
1370   // There is no dex instruction or HIR that would need the missing conditions
1371   // "equal or unordered" or "not equal".
1372   switch (cond) {
1373     case kCondEQ: return EQ;
1374     case kCondNE: return NE /* unordered */;
1375     case kCondLT: return gt_bias ? CC : LT /* unordered */;
1376     case kCondLE: return gt_bias ? LS : LE /* unordered */;
1377     case kCondGT: return gt_bias ? HI /* unordered */ : GT;
1378     case kCondGE: return gt_bias ? CS /* unordered */ : GE;
1379     default:
1380       LOG(FATAL) << "UNREACHABLE";
1381       UNREACHABLE();
1382   }
1383 }
1384 
ShiftFromOpKind(HDataProcWithShifterOp::OpKind op_kind)1385 inline Shift ShiftFromOpKind(HDataProcWithShifterOp::OpKind op_kind) {
1386   switch (op_kind) {
1387     case HDataProcWithShifterOp::kASR: return ASR;
1388     case HDataProcWithShifterOp::kLSL: return LSL;
1389     case HDataProcWithShifterOp::kLSR: return LSR;
1390     default:
1391       LOG(FATAL) << "Unexpected op kind " << op_kind;
1392       UNREACHABLE();
1393   }
1394 }
1395 
GenerateDataProcInstruction(HInstruction::InstructionKind kind,Register out,Register first,const ShifterOperand & second,CodeGeneratorARM * codegen)1396 static void GenerateDataProcInstruction(HInstruction::InstructionKind kind,
1397                                         Register out,
1398                                         Register first,
1399                                         const ShifterOperand& second,
1400                                         CodeGeneratorARM* codegen) {
1401   if (second.IsImmediate() && second.GetImmediate() == 0) {
1402     const ShifterOperand in = kind == HInstruction::kAnd
1403         ? ShifterOperand(0)
1404         : ShifterOperand(first);
1405 
1406     __ mov(out, in);
1407   } else {
1408     switch (kind) {
1409       case HInstruction::kAdd:
1410         __ add(out, first, second);
1411         break;
1412       case HInstruction::kAnd:
1413         __ and_(out, first, second);
1414         break;
1415       case HInstruction::kOr:
1416         __ orr(out, first, second);
1417         break;
1418       case HInstruction::kSub:
1419         __ sub(out, first, second);
1420         break;
1421       case HInstruction::kXor:
1422         __ eor(out, first, second);
1423         break;
1424       default:
1425         LOG(FATAL) << "Unexpected instruction kind: " << kind;
1426         UNREACHABLE();
1427     }
1428   }
1429 }
1430 
GenerateDataProc(HInstruction::InstructionKind kind,const Location & out,const Location & first,const ShifterOperand & second_lo,const ShifterOperand & second_hi,CodeGeneratorARM * codegen)1431 static void GenerateDataProc(HInstruction::InstructionKind kind,
1432                              const Location& out,
1433                              const Location& first,
1434                              const ShifterOperand& second_lo,
1435                              const ShifterOperand& second_hi,
1436                              CodeGeneratorARM* codegen) {
1437   const Register first_hi = first.AsRegisterPairHigh<Register>();
1438   const Register first_lo = first.AsRegisterPairLow<Register>();
1439   const Register out_hi = out.AsRegisterPairHigh<Register>();
1440   const Register out_lo = out.AsRegisterPairLow<Register>();
1441 
1442   if (kind == HInstruction::kAdd) {
1443     __ adds(out_lo, first_lo, second_lo);
1444     __ adc(out_hi, first_hi, second_hi);
1445   } else if (kind == HInstruction::kSub) {
1446     __ subs(out_lo, first_lo, second_lo);
1447     __ sbc(out_hi, first_hi, second_hi);
1448   } else {
1449     GenerateDataProcInstruction(kind, out_lo, first_lo, second_lo, codegen);
1450     GenerateDataProcInstruction(kind, out_hi, first_hi, second_hi, codegen);
1451   }
1452 }
1453 
GetShifterOperand(Register rm,Shift shift,uint32_t shift_imm)1454 static ShifterOperand GetShifterOperand(Register rm, Shift shift, uint32_t shift_imm) {
1455   return shift_imm == 0 ? ShifterOperand(rm) : ShifterOperand(rm, shift, shift_imm);
1456 }
1457 
GenerateLongDataProc(HDataProcWithShifterOp * instruction,CodeGeneratorARM * codegen)1458 static void GenerateLongDataProc(HDataProcWithShifterOp* instruction, CodeGeneratorARM* codegen) {
1459   DCHECK_EQ(instruction->GetType(), Primitive::kPrimLong);
1460   DCHECK(HDataProcWithShifterOp::IsShiftOp(instruction->GetOpKind()));
1461 
1462   const LocationSummary* const locations = instruction->GetLocations();
1463   const uint32_t shift_value = instruction->GetShiftAmount();
1464   const HInstruction::InstructionKind kind = instruction->GetInstrKind();
1465   const Location first = locations->InAt(0);
1466   const Location second = locations->InAt(1);
1467   const Location out = locations->Out();
1468   const Register first_hi = first.AsRegisterPairHigh<Register>();
1469   const Register first_lo = first.AsRegisterPairLow<Register>();
1470   const Register out_hi = out.AsRegisterPairHigh<Register>();
1471   const Register out_lo = out.AsRegisterPairLow<Register>();
1472   const Register second_hi = second.AsRegisterPairHigh<Register>();
1473   const Register second_lo = second.AsRegisterPairLow<Register>();
1474   const Shift shift = ShiftFromOpKind(instruction->GetOpKind());
1475 
1476   if (shift_value >= 32) {
1477     if (shift == LSL) {
1478       GenerateDataProcInstruction(kind,
1479                                   out_hi,
1480                                   first_hi,
1481                                   ShifterOperand(second_lo, LSL, shift_value - 32),
1482                                   codegen);
1483       GenerateDataProcInstruction(kind,
1484                                   out_lo,
1485                                   first_lo,
1486                                   ShifterOperand(0),
1487                                   codegen);
1488     } else if (shift == ASR) {
1489       GenerateDataProc(kind,
1490                        out,
1491                        first,
1492                        GetShifterOperand(second_hi, ASR, shift_value - 32),
1493                        ShifterOperand(second_hi, ASR, 31),
1494                        codegen);
1495     } else {
1496       DCHECK_EQ(shift, LSR);
1497       GenerateDataProc(kind,
1498                        out,
1499                        first,
1500                        GetShifterOperand(second_hi, LSR, shift_value - 32),
1501                        ShifterOperand(0),
1502                        codegen);
1503     }
1504   } else {
1505     DCHECK_GT(shift_value, 1U);
1506     DCHECK_LT(shift_value, 32U);
1507 
1508     if (shift == LSL) {
1509       // We are not doing this for HInstruction::kAdd because the output will require
1510       // Location::kOutputOverlap; not applicable to other cases.
1511       if (kind == HInstruction::kOr || kind == HInstruction::kXor) {
1512         GenerateDataProcInstruction(kind,
1513                                     out_hi,
1514                                     first_hi,
1515                                     ShifterOperand(second_hi, LSL, shift_value),
1516                                     codegen);
1517         GenerateDataProcInstruction(kind,
1518                                     out_hi,
1519                                     out_hi,
1520                                     ShifterOperand(second_lo, LSR, 32 - shift_value),
1521                                     codegen);
1522         GenerateDataProcInstruction(kind,
1523                                     out_lo,
1524                                     first_lo,
1525                                     ShifterOperand(second_lo, LSL, shift_value),
1526                                     codegen);
1527       } else {
1528         __ Lsl(IP, second_hi, shift_value);
1529         __ orr(IP, IP, ShifterOperand(second_lo, LSR, 32 - shift_value));
1530         GenerateDataProc(kind,
1531                          out,
1532                          first,
1533                          ShifterOperand(second_lo, LSL, shift_value),
1534                          ShifterOperand(IP),
1535                          codegen);
1536       }
1537     } else {
1538       DCHECK(shift == ASR || shift == LSR);
1539 
1540       // We are not doing this for HInstruction::kAdd because the output will require
1541       // Location::kOutputOverlap; not applicable to other cases.
1542       if (kind == HInstruction::kOr || kind == HInstruction::kXor) {
1543         GenerateDataProcInstruction(kind,
1544                                     out_lo,
1545                                     first_lo,
1546                                     ShifterOperand(second_lo, LSR, shift_value),
1547                                     codegen);
1548         GenerateDataProcInstruction(kind,
1549                                     out_lo,
1550                                     out_lo,
1551                                     ShifterOperand(second_hi, LSL, 32 - shift_value),
1552                                     codegen);
1553         GenerateDataProcInstruction(kind,
1554                                     out_hi,
1555                                     first_hi,
1556                                     ShifterOperand(second_hi, shift, shift_value),
1557                                     codegen);
1558       } else {
1559         __ Lsr(IP, second_lo, shift_value);
1560         __ orr(IP, IP, ShifterOperand(second_hi, LSL, 32 - shift_value));
1561         GenerateDataProc(kind,
1562                          out,
1563                          first,
1564                          ShifterOperand(IP),
1565                          ShifterOperand(second_hi, shift, shift_value),
1566                          codegen);
1567       }
1568     }
1569   }
1570 }
1571 
GenerateVcmp(HInstruction * instruction,CodeGeneratorARM * codegen)1572 static void GenerateVcmp(HInstruction* instruction, CodeGeneratorARM* codegen) {
1573   Primitive::Type type = instruction->InputAt(0)->GetType();
1574   Location lhs_loc = instruction->GetLocations()->InAt(0);
1575   Location rhs_loc = instruction->GetLocations()->InAt(1);
1576   if (rhs_loc.IsConstant()) {
1577     // 0.0 is the only immediate that can be encoded directly in
1578     // a VCMP instruction.
1579     //
1580     // Both the JLS (section 15.20.1) and the JVMS (section 6.5)
1581     // specify that in a floating-point comparison, positive zero
1582     // and negative zero are considered equal, so we can use the
1583     // literal 0.0 for both cases here.
1584     //
1585     // Note however that some methods (Float.equal, Float.compare,
1586     // Float.compareTo, Double.equal, Double.compare,
1587     // Double.compareTo, Math.max, Math.min, StrictMath.max,
1588     // StrictMath.min) consider 0.0 to be (strictly) greater than
1589     // -0.0. So if we ever translate calls to these methods into a
1590     // HCompare instruction, we must handle the -0.0 case with
1591     // care here.
1592     DCHECK(rhs_loc.GetConstant()->IsArithmeticZero());
1593     if (type == Primitive::kPrimFloat) {
1594       __ vcmpsz(lhs_loc.AsFpuRegister<SRegister>());
1595     } else {
1596       DCHECK_EQ(type, Primitive::kPrimDouble);
1597       __ vcmpdz(FromLowSToD(lhs_loc.AsFpuRegisterPairLow<SRegister>()));
1598     }
1599   } else {
1600     if (type == Primitive::kPrimFloat) {
1601       __ vcmps(lhs_loc.AsFpuRegister<SRegister>(), rhs_loc.AsFpuRegister<SRegister>());
1602     } else {
1603       DCHECK_EQ(type, Primitive::kPrimDouble);
1604       __ vcmpd(FromLowSToD(lhs_loc.AsFpuRegisterPairLow<SRegister>()),
1605                FromLowSToD(rhs_loc.AsFpuRegisterPairLow<SRegister>()));
1606     }
1607   }
1608 }
1609 
GenerateLongTestConstant(HCondition * condition,bool invert,CodeGeneratorARM * codegen)1610 static std::pair<Condition, Condition> GenerateLongTestConstant(HCondition* condition,
1611                                                                 bool invert,
1612                                                                 CodeGeneratorARM* codegen) {
1613   DCHECK_EQ(condition->GetLeft()->GetType(), Primitive::kPrimLong);
1614 
1615   const LocationSummary* const locations = condition->GetLocations();
1616   IfCondition cond = condition->GetCondition();
1617   IfCondition opposite = condition->GetOppositeCondition();
1618 
1619   if (invert) {
1620     std::swap(cond, opposite);
1621   }
1622 
1623   std::pair<Condition, Condition> ret;
1624   const Location left = locations->InAt(0);
1625   const Location right = locations->InAt(1);
1626 
1627   DCHECK(right.IsConstant());
1628 
1629   const Register left_high = left.AsRegisterPairHigh<Register>();
1630   const Register left_low = left.AsRegisterPairLow<Register>();
1631   int64_t value = right.GetConstant()->AsLongConstant()->GetValue();
1632 
1633   switch (cond) {
1634     case kCondEQ:
1635     case kCondNE:
1636     case kCondB:
1637     case kCondBE:
1638     case kCondA:
1639     case kCondAE:
1640       __ CmpConstant(left_high, High32Bits(value));
1641       __ it(EQ);
1642       __ cmp(left_low, ShifterOperand(Low32Bits(value)), EQ);
1643       ret = std::make_pair(ARMUnsignedCondition(cond), ARMUnsignedCondition(opposite));
1644       break;
1645     case kCondLE:
1646     case kCondGT:
1647       // Trivially true or false.
1648       if (value == std::numeric_limits<int64_t>::max()) {
1649         __ cmp(left_low, ShifterOperand(left_low));
1650         ret = cond == kCondLE ? std::make_pair(EQ, NE) : std::make_pair(NE, EQ);
1651         break;
1652       }
1653 
1654       if (cond == kCondLE) {
1655         DCHECK_EQ(opposite, kCondGT);
1656         cond = kCondLT;
1657         opposite = kCondGE;
1658       } else {
1659         DCHECK_EQ(cond, kCondGT);
1660         DCHECK_EQ(opposite, kCondLE);
1661         cond = kCondGE;
1662         opposite = kCondLT;
1663       }
1664 
1665       value++;
1666       FALLTHROUGH_INTENDED;
1667     case kCondGE:
1668     case kCondLT:
1669       __ CmpConstant(left_low, Low32Bits(value));
1670       __ sbcs(IP, left_high, ShifterOperand(High32Bits(value)));
1671       ret = std::make_pair(ARMCondition(cond), ARMCondition(opposite));
1672       break;
1673     default:
1674       LOG(FATAL) << "Unreachable";
1675       UNREACHABLE();
1676   }
1677 
1678   return ret;
1679 }
1680 
GenerateLongTest(HCondition * condition,bool invert,CodeGeneratorARM * codegen)1681 static std::pair<Condition, Condition> GenerateLongTest(HCondition* condition,
1682                                                         bool invert,
1683                                                         CodeGeneratorARM* codegen) {
1684   DCHECK_EQ(condition->GetLeft()->GetType(), Primitive::kPrimLong);
1685 
1686   const LocationSummary* const locations = condition->GetLocations();
1687   IfCondition cond = condition->GetCondition();
1688   IfCondition opposite = condition->GetOppositeCondition();
1689 
1690   if (invert) {
1691     std::swap(cond, opposite);
1692   }
1693 
1694   std::pair<Condition, Condition> ret;
1695   Location left = locations->InAt(0);
1696   Location right = locations->InAt(1);
1697 
1698   DCHECK(right.IsRegisterPair());
1699 
1700   switch (cond) {
1701     case kCondEQ:
1702     case kCondNE:
1703     case kCondB:
1704     case kCondBE:
1705     case kCondA:
1706     case kCondAE:
1707       __ cmp(left.AsRegisterPairHigh<Register>(),
1708              ShifterOperand(right.AsRegisterPairHigh<Register>()));
1709       __ it(EQ);
1710       __ cmp(left.AsRegisterPairLow<Register>(),
1711              ShifterOperand(right.AsRegisterPairLow<Register>()),
1712              EQ);
1713       ret = std::make_pair(ARMUnsignedCondition(cond), ARMUnsignedCondition(opposite));
1714       break;
1715     case kCondLE:
1716     case kCondGT:
1717       if (cond == kCondLE) {
1718         DCHECK_EQ(opposite, kCondGT);
1719         cond = kCondGE;
1720         opposite = kCondLT;
1721       } else {
1722         DCHECK_EQ(cond, kCondGT);
1723         DCHECK_EQ(opposite, kCondLE);
1724         cond = kCondLT;
1725         opposite = kCondGE;
1726       }
1727 
1728       std::swap(left, right);
1729       FALLTHROUGH_INTENDED;
1730     case kCondGE:
1731     case kCondLT:
1732       __ cmp(left.AsRegisterPairLow<Register>(),
1733              ShifterOperand(right.AsRegisterPairLow<Register>()));
1734       __ sbcs(IP,
1735               left.AsRegisterPairHigh<Register>(),
1736               ShifterOperand(right.AsRegisterPairHigh<Register>()));
1737       ret = std::make_pair(ARMCondition(cond), ARMCondition(opposite));
1738       break;
1739     default:
1740       LOG(FATAL) << "Unreachable";
1741       UNREACHABLE();
1742   }
1743 
1744   return ret;
1745 }
1746 
GenerateTest(HCondition * condition,bool invert,CodeGeneratorARM * codegen)1747 static std::pair<Condition, Condition> GenerateTest(HCondition* condition,
1748                                                     bool invert,
1749                                                     CodeGeneratorARM* codegen) {
1750   const LocationSummary* const locations = condition->GetLocations();
1751   const Primitive::Type type = condition->GetLeft()->GetType();
1752   IfCondition cond = condition->GetCondition();
1753   IfCondition opposite = condition->GetOppositeCondition();
1754   std::pair<Condition, Condition> ret;
1755   const Location right = locations->InAt(1);
1756 
1757   if (invert) {
1758     std::swap(cond, opposite);
1759   }
1760 
1761   if (type == Primitive::kPrimLong) {
1762     ret = locations->InAt(1).IsConstant()
1763         ? GenerateLongTestConstant(condition, invert, codegen)
1764         : GenerateLongTest(condition, invert, codegen);
1765   } else if (Primitive::IsFloatingPointType(type)) {
1766     GenerateVcmp(condition, codegen);
1767     __ vmstat();
1768     ret = std::make_pair(ARMFPCondition(cond, condition->IsGtBias()),
1769                          ARMFPCondition(opposite, condition->IsGtBias()));
1770   } else {
1771     DCHECK(Primitive::IsIntegralType(type) || type == Primitive::kPrimNot) << type;
1772 
1773     const Register left = locations->InAt(0).AsRegister<Register>();
1774 
1775     if (right.IsRegister()) {
1776       __ cmp(left, ShifterOperand(right.AsRegister<Register>()));
1777     } else {
1778       DCHECK(right.IsConstant());
1779       __ CmpConstant(left, CodeGenerator::GetInt32ValueOf(right.GetConstant()));
1780     }
1781 
1782     ret = std::make_pair(ARMCondition(cond), ARMCondition(opposite));
1783   }
1784 
1785   return ret;
1786 }
1787 
CanGenerateTest(HCondition * condition,ArmAssembler * assembler)1788 static bool CanGenerateTest(HCondition* condition, ArmAssembler* assembler) {
1789   if (condition->GetLeft()->GetType() == Primitive::kPrimLong) {
1790     const LocationSummary* const locations = condition->GetLocations();
1791     const IfCondition c = condition->GetCondition();
1792 
1793     if (locations->InAt(1).IsConstant()) {
1794       const int64_t value = locations->InAt(1).GetConstant()->AsLongConstant()->GetValue();
1795       ShifterOperand so;
1796 
1797       if (c < kCondLT || c > kCondGE) {
1798         // Since IT blocks longer than a 16-bit instruction are deprecated by ARMv8,
1799         // we check that the least significant half of the first input to be compared
1800         // is in a low register (the other half is read outside an IT block), and
1801         // the constant fits in an 8-bit unsigned integer, so that a 16-bit CMP
1802         // encoding can be used.
1803         if (!ArmAssembler::IsLowRegister(locations->InAt(0).AsRegisterPairLow<Register>()) ||
1804             !IsUint<8>(Low32Bits(value))) {
1805           return false;
1806         }
1807       } else if (c == kCondLE || c == kCondGT) {
1808         if (value < std::numeric_limits<int64_t>::max() &&
1809             !assembler->ShifterOperandCanHold(kNoRegister,
1810                                               kNoRegister,
1811                                               SBC,
1812                                               High32Bits(value + 1),
1813                                               kCcSet,
1814                                               &so)) {
1815           return false;
1816         }
1817       } else if (!assembler->ShifterOperandCanHold(kNoRegister,
1818                                                    kNoRegister,
1819                                                    SBC,
1820                                                    High32Bits(value),
1821                                                    kCcSet,
1822                                                    &so)) {
1823         return false;
1824       }
1825     }
1826   }
1827 
1828   return true;
1829 }
1830 
CanEncodeConstantAs8BitImmediate(HConstant * constant)1831 static bool CanEncodeConstantAs8BitImmediate(HConstant* constant) {
1832   const Primitive::Type type = constant->GetType();
1833   bool ret = false;
1834 
1835   DCHECK(Primitive::IsIntegralType(type) || type == Primitive::kPrimNot) << type;
1836 
1837   if (type == Primitive::kPrimLong) {
1838     const uint64_t value = constant->AsLongConstant()->GetValueAsUint64();
1839 
1840     ret = IsUint<8>(Low32Bits(value)) && IsUint<8>(High32Bits(value));
1841   } else {
1842     ret = IsUint<8>(CodeGenerator::GetInt32ValueOf(constant));
1843   }
1844 
1845   return ret;
1846 }
1847 
Arm8BitEncodableConstantOrRegister(HInstruction * constant)1848 static Location Arm8BitEncodableConstantOrRegister(HInstruction* constant) {
1849   DCHECK(!Primitive::IsFloatingPointType(constant->GetType()));
1850 
1851   if (constant->IsConstant() && CanEncodeConstantAs8BitImmediate(constant->AsConstant())) {
1852     return Location::ConstantLocation(constant->AsConstant());
1853   }
1854 
1855   return Location::RequiresRegister();
1856 }
1857 
CanGenerateConditionalMove(const Location & out,const Location & src)1858 static bool CanGenerateConditionalMove(const Location& out, const Location& src) {
1859   // Since IT blocks longer than a 16-bit instruction are deprecated by ARMv8,
1860   // we check that we are not dealing with floating-point output (there is no
1861   // 16-bit VMOV encoding).
1862   if (!out.IsRegister() && !out.IsRegisterPair()) {
1863     return false;
1864   }
1865 
1866   // For constants, we also check that the output is in one or two low registers,
1867   // and that the constants fit in an 8-bit unsigned integer, so that a 16-bit
1868   // MOV encoding can be used.
1869   if (src.IsConstant()) {
1870     if (!CanEncodeConstantAs8BitImmediate(src.GetConstant())) {
1871       return false;
1872     }
1873 
1874     if (out.IsRegister()) {
1875       if (!ArmAssembler::IsLowRegister(out.AsRegister<Register>())) {
1876         return false;
1877       }
1878     } else {
1879       DCHECK(out.IsRegisterPair());
1880 
1881       if (!ArmAssembler::IsLowRegister(out.AsRegisterPairHigh<Register>())) {
1882         return false;
1883       }
1884     }
1885   }
1886 
1887   return true;
1888 }
1889 
1890 #undef __
1891 // NOLINT on __ macro to suppress wrong warning/fix (misc-macro-parentheses) from clang-tidy.
1892 #define __ down_cast<ArmAssembler*>(GetAssembler())->  // NOLINT
1893 
GetFinalLabel(HInstruction * instruction,Label * final_label)1894 Label* CodeGeneratorARM::GetFinalLabel(HInstruction* instruction, Label* final_label) {
1895   DCHECK(!instruction->IsControlFlow() && !instruction->IsSuspendCheck());
1896   DCHECK(!instruction->IsInvoke() || !instruction->GetLocations()->CanCall());
1897 
1898   const HBasicBlock* const block = instruction->GetBlock();
1899   const HLoopInformation* const info = block->GetLoopInformation();
1900   HInstruction* const next = instruction->GetNext();
1901 
1902   // Avoid a branch to a branch.
1903   if (next->IsGoto() && (info == nullptr ||
1904                          !info->IsBackEdge(*block) ||
1905                          !info->HasSuspendCheck())) {
1906     final_label = GetLabelOf(next->AsGoto()->GetSuccessor());
1907   }
1908 
1909   return final_label;
1910 }
1911 
DumpCoreRegister(std::ostream & stream,int reg) const1912 void CodeGeneratorARM::DumpCoreRegister(std::ostream& stream, int reg) const {
1913   stream << Register(reg);
1914 }
1915 
DumpFloatingPointRegister(std::ostream & stream,int reg) const1916 void CodeGeneratorARM::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
1917   stream << SRegister(reg);
1918 }
1919 
SaveCoreRegister(size_t stack_index,uint32_t reg_id)1920 size_t CodeGeneratorARM::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
1921   __ StoreToOffset(kStoreWord, static_cast<Register>(reg_id), SP, stack_index);
1922   return kArmWordSize;
1923 }
1924 
RestoreCoreRegister(size_t stack_index,uint32_t reg_id)1925 size_t CodeGeneratorARM::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
1926   __ LoadFromOffset(kLoadWord, static_cast<Register>(reg_id), SP, stack_index);
1927   return kArmWordSize;
1928 }
1929 
SaveFloatingPointRegister(size_t stack_index,uint32_t reg_id)1930 size_t CodeGeneratorARM::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
1931   __ StoreSToOffset(static_cast<SRegister>(reg_id), SP, stack_index);
1932   return kArmWordSize;
1933 }
1934 
RestoreFloatingPointRegister(size_t stack_index,uint32_t reg_id)1935 size_t CodeGeneratorARM::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
1936   __ LoadSFromOffset(static_cast<SRegister>(reg_id), SP, stack_index);
1937   return kArmWordSize;
1938 }
1939 
CodeGeneratorARM(HGraph * graph,const ArmInstructionSetFeatures & isa_features,const CompilerOptions & compiler_options,OptimizingCompilerStats * stats)1940 CodeGeneratorARM::CodeGeneratorARM(HGraph* graph,
1941                                    const ArmInstructionSetFeatures& isa_features,
1942                                    const CompilerOptions& compiler_options,
1943                                    OptimizingCompilerStats* stats)
1944     : CodeGenerator(graph,
1945                     kNumberOfCoreRegisters,
1946                     kNumberOfSRegisters,
1947                     kNumberOfRegisterPairs,
1948                     ComputeRegisterMask(reinterpret_cast<const int*>(kCoreCalleeSaves),
1949                                         arraysize(kCoreCalleeSaves)),
1950                     ComputeRegisterMask(reinterpret_cast<const int*>(kFpuCalleeSaves),
1951                                         arraysize(kFpuCalleeSaves)),
1952                     compiler_options,
1953                     stats),
1954       block_labels_(nullptr),
1955       location_builder_(graph, this),
1956       instruction_visitor_(graph, this),
1957       move_resolver_(graph->GetArena(), this),
1958       assembler_(graph->GetArena()),
1959       isa_features_(isa_features),
1960       uint32_literals_(std::less<uint32_t>(),
1961                        graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
1962       pc_relative_dex_cache_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
1963       boot_image_string_patches_(StringReferenceValueComparator(),
1964                                  graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
1965       pc_relative_string_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
1966       boot_image_type_patches_(TypeReferenceValueComparator(),
1967                                graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
1968       pc_relative_type_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
1969       type_bss_entry_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
1970       jit_string_patches_(StringReferenceValueComparator(),
1971                           graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
1972       jit_class_patches_(TypeReferenceValueComparator(),
1973                          graph->GetArena()->Adapter(kArenaAllocCodeGenerator)) {
1974   // Always save the LR register to mimic Quick.
1975   AddAllocatedRegister(Location::RegisterLocation(LR));
1976 }
1977 
Finalize(CodeAllocator * allocator)1978 void CodeGeneratorARM::Finalize(CodeAllocator* allocator) {
1979   // Ensure that we fix up branches and literal loads and emit the literal pool.
1980   __ FinalizeCode();
1981 
1982   // Adjust native pc offsets in stack maps.
1983   for (size_t i = 0, num = stack_map_stream_.GetNumberOfStackMaps(); i != num; ++i) {
1984     uint32_t old_position =
1985         stack_map_stream_.GetStackMap(i).native_pc_code_offset.Uint32Value(kThumb2);
1986     uint32_t new_position = __ GetAdjustedPosition(old_position);
1987     stack_map_stream_.SetStackMapNativePcOffset(i, new_position);
1988   }
1989   // Adjust pc offsets for the disassembly information.
1990   if (disasm_info_ != nullptr) {
1991     GeneratedCodeInterval* frame_entry_interval = disasm_info_->GetFrameEntryInterval();
1992     frame_entry_interval->start = __ GetAdjustedPosition(frame_entry_interval->start);
1993     frame_entry_interval->end = __ GetAdjustedPosition(frame_entry_interval->end);
1994     for (auto& it : *disasm_info_->GetInstructionIntervals()) {
1995       it.second.start = __ GetAdjustedPosition(it.second.start);
1996       it.second.end = __ GetAdjustedPosition(it.second.end);
1997     }
1998     for (auto& it : *disasm_info_->GetSlowPathIntervals()) {
1999       it.code_interval.start = __ GetAdjustedPosition(it.code_interval.start);
2000       it.code_interval.end = __ GetAdjustedPosition(it.code_interval.end);
2001     }
2002   }
2003 
2004   CodeGenerator::Finalize(allocator);
2005 }
2006 
SetupBlockedRegisters() const2007 void CodeGeneratorARM::SetupBlockedRegisters() const {
2008   // Stack register, LR and PC are always reserved.
2009   blocked_core_registers_[SP] = true;
2010   blocked_core_registers_[LR] = true;
2011   blocked_core_registers_[PC] = true;
2012 
2013   // Reserve thread register.
2014   blocked_core_registers_[TR] = true;
2015 
2016   // Reserve temp register.
2017   blocked_core_registers_[IP] = true;
2018 
2019   if (GetGraph()->IsDebuggable()) {
2020     // Stubs do not save callee-save floating point registers. If the graph
2021     // is debuggable, we need to deal with these registers differently. For
2022     // now, just block them.
2023     for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
2024       blocked_fpu_registers_[kFpuCalleeSaves[i]] = true;
2025     }
2026   }
2027 }
2028 
InstructionCodeGeneratorARM(HGraph * graph,CodeGeneratorARM * codegen)2029 InstructionCodeGeneratorARM::InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen)
2030       : InstructionCodeGenerator(graph, codegen),
2031         assembler_(codegen->GetAssembler()),
2032         codegen_(codegen) {}
2033 
ComputeSpillMask()2034 void CodeGeneratorARM::ComputeSpillMask() {
2035   core_spill_mask_ = allocated_registers_.GetCoreRegisters() & core_callee_save_mask_;
2036   DCHECK_NE(core_spill_mask_, 0u) << "At least the return address register must be saved";
2037   // There is no easy instruction to restore just the PC on thumb2. We spill and
2038   // restore another arbitrary register.
2039   core_spill_mask_ |= (1 << kCoreAlwaysSpillRegister);
2040   fpu_spill_mask_ = allocated_registers_.GetFloatingPointRegisters() & fpu_callee_save_mask_;
2041   // We use vpush and vpop for saving and restoring floating point registers, which take
2042   // a SRegister and the number of registers to save/restore after that SRegister. We
2043   // therefore update the `fpu_spill_mask_` to also contain those registers not allocated,
2044   // but in the range.
2045   if (fpu_spill_mask_ != 0) {
2046     uint32_t least_significant_bit = LeastSignificantBit(fpu_spill_mask_);
2047     uint32_t most_significant_bit = MostSignificantBit(fpu_spill_mask_);
2048     for (uint32_t i = least_significant_bit + 1 ; i < most_significant_bit; ++i) {
2049       fpu_spill_mask_ |= (1 << i);
2050     }
2051   }
2052 }
2053 
DWARFReg(Register reg)2054 static dwarf::Reg DWARFReg(Register reg) {
2055   return dwarf::Reg::ArmCore(static_cast<int>(reg));
2056 }
2057 
DWARFReg(SRegister reg)2058 static dwarf::Reg DWARFReg(SRegister reg) {
2059   return dwarf::Reg::ArmFp(static_cast<int>(reg));
2060 }
2061 
GenerateFrameEntry()2062 void CodeGeneratorARM::GenerateFrameEntry() {
2063   bool skip_overflow_check =
2064       IsLeafMethod() && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kArm);
2065   DCHECK(GetCompilerOptions().GetImplicitStackOverflowChecks());
2066   __ Bind(&frame_entry_label_);
2067 
2068   if (HasEmptyFrame()) {
2069     return;
2070   }
2071 
2072   if (!skip_overflow_check) {
2073     __ AddConstant(IP, SP, -static_cast<int32_t>(GetStackOverflowReservedBytes(kArm)));
2074     __ LoadFromOffset(kLoadWord, IP, IP, 0);
2075     RecordPcInfo(nullptr, 0);
2076   }
2077 
2078   __ PushList(core_spill_mask_);
2079   __ cfi().AdjustCFAOffset(kArmWordSize * POPCOUNT(core_spill_mask_));
2080   __ cfi().RelOffsetForMany(DWARFReg(kMethodRegisterArgument), 0, core_spill_mask_, kArmWordSize);
2081   if (fpu_spill_mask_ != 0) {
2082     SRegister start_register = SRegister(LeastSignificantBit(fpu_spill_mask_));
2083     __ vpushs(start_register, POPCOUNT(fpu_spill_mask_));
2084     __ cfi().AdjustCFAOffset(kArmWordSize * POPCOUNT(fpu_spill_mask_));
2085     __ cfi().RelOffsetForMany(DWARFReg(S0), 0, fpu_spill_mask_, kArmWordSize);
2086   }
2087 
2088   if (GetGraph()->HasShouldDeoptimizeFlag()) {
2089     // Initialize should_deoptimize flag to 0.
2090     __ mov(IP, ShifterOperand(0));
2091     __ StoreToOffset(kStoreWord, IP, SP, -kShouldDeoptimizeFlagSize);
2092   }
2093 
2094   int adjust = GetFrameSize() - FrameEntrySpillSize();
2095   __ AddConstant(SP, -adjust);
2096   __ cfi().AdjustCFAOffset(adjust);
2097 
2098   // Save the current method if we need it. Note that we do not
2099   // do this in HCurrentMethod, as the instruction might have been removed
2100   // in the SSA graph.
2101   if (RequiresCurrentMethod()) {
2102     __ StoreToOffset(kStoreWord, kMethodRegisterArgument, SP, 0);
2103   }
2104 }
2105 
GenerateFrameExit()2106 void CodeGeneratorARM::GenerateFrameExit() {
2107   if (HasEmptyFrame()) {
2108     __ bx(LR);
2109     return;
2110   }
2111   __ cfi().RememberState();
2112   int adjust = GetFrameSize() - FrameEntrySpillSize();
2113   __ AddConstant(SP, adjust);
2114   __ cfi().AdjustCFAOffset(-adjust);
2115   if (fpu_spill_mask_ != 0) {
2116     SRegister start_register = SRegister(LeastSignificantBit(fpu_spill_mask_));
2117     __ vpops(start_register, POPCOUNT(fpu_spill_mask_));
2118     __ cfi().AdjustCFAOffset(-static_cast<int>(kArmPointerSize) * POPCOUNT(fpu_spill_mask_));
2119     __ cfi().RestoreMany(DWARFReg(SRegister(0)), fpu_spill_mask_);
2120   }
2121   // Pop LR into PC to return.
2122   DCHECK_NE(core_spill_mask_ & (1 << LR), 0U);
2123   uint32_t pop_mask = (core_spill_mask_ & (~(1 << LR))) | 1 << PC;
2124   __ PopList(pop_mask);
2125   __ cfi().RestoreState();
2126   __ cfi().DefCFAOffset(GetFrameSize());
2127 }
2128 
Bind(HBasicBlock * block)2129 void CodeGeneratorARM::Bind(HBasicBlock* block) {
2130   Label* label = GetLabelOf(block);
2131   __ BindTrackedLabel(label);
2132 }
2133 
GetNextLocation(Primitive::Type type)2134 Location InvokeDexCallingConventionVisitorARM::GetNextLocation(Primitive::Type type) {
2135   switch (type) {
2136     case Primitive::kPrimBoolean:
2137     case Primitive::kPrimByte:
2138     case Primitive::kPrimChar:
2139     case Primitive::kPrimShort:
2140     case Primitive::kPrimInt:
2141     case Primitive::kPrimNot: {
2142       uint32_t index = gp_index_++;
2143       uint32_t stack_index = stack_index_++;
2144       if (index < calling_convention.GetNumberOfRegisters()) {
2145         return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
2146       } else {
2147         return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index));
2148       }
2149     }
2150 
2151     case Primitive::kPrimLong: {
2152       uint32_t index = gp_index_;
2153       uint32_t stack_index = stack_index_;
2154       gp_index_ += 2;
2155       stack_index_ += 2;
2156       if (index + 1 < calling_convention.GetNumberOfRegisters()) {
2157         if (calling_convention.GetRegisterAt(index) == R1) {
2158           // Skip R1, and use R2_R3 instead.
2159           gp_index_++;
2160           index++;
2161         }
2162       }
2163       if (index + 1 < calling_convention.GetNumberOfRegisters()) {
2164         DCHECK_EQ(calling_convention.GetRegisterAt(index) + 1,
2165                   calling_convention.GetRegisterAt(index + 1));
2166 
2167         return Location::RegisterPairLocation(calling_convention.GetRegisterAt(index),
2168                                               calling_convention.GetRegisterAt(index + 1));
2169       } else {
2170         return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index));
2171       }
2172     }
2173 
2174     case Primitive::kPrimFloat: {
2175       uint32_t stack_index = stack_index_++;
2176       if (float_index_ % 2 == 0) {
2177         float_index_ = std::max(double_index_, float_index_);
2178       }
2179       if (float_index_ < calling_convention.GetNumberOfFpuRegisters()) {
2180         return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(float_index_++));
2181       } else {
2182         return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index));
2183       }
2184     }
2185 
2186     case Primitive::kPrimDouble: {
2187       double_index_ = std::max(double_index_, RoundUp(float_index_, 2));
2188       uint32_t stack_index = stack_index_;
2189       stack_index_ += 2;
2190       if (double_index_ + 1 < calling_convention.GetNumberOfFpuRegisters()) {
2191         uint32_t index = double_index_;
2192         double_index_ += 2;
2193         Location result = Location::FpuRegisterPairLocation(
2194           calling_convention.GetFpuRegisterAt(index),
2195           calling_convention.GetFpuRegisterAt(index + 1));
2196         DCHECK(ExpectedPairLayout(result));
2197         return result;
2198       } else {
2199         return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index));
2200       }
2201     }
2202 
2203     case Primitive::kPrimVoid:
2204       LOG(FATAL) << "Unexpected parameter type " << type;
2205       break;
2206   }
2207   return Location::NoLocation();
2208 }
2209 
GetReturnLocation(Primitive::Type type) const2210 Location InvokeDexCallingConventionVisitorARM::GetReturnLocation(Primitive::Type type) const {
2211   switch (type) {
2212     case Primitive::kPrimBoolean:
2213     case Primitive::kPrimByte:
2214     case Primitive::kPrimChar:
2215     case Primitive::kPrimShort:
2216     case Primitive::kPrimInt:
2217     case Primitive::kPrimNot: {
2218       return Location::RegisterLocation(R0);
2219     }
2220 
2221     case Primitive::kPrimFloat: {
2222       return Location::FpuRegisterLocation(S0);
2223     }
2224 
2225     case Primitive::kPrimLong: {
2226       return Location::RegisterPairLocation(R0, R1);
2227     }
2228 
2229     case Primitive::kPrimDouble: {
2230       return Location::FpuRegisterPairLocation(S0, S1);
2231     }
2232 
2233     case Primitive::kPrimVoid:
2234       return Location::NoLocation();
2235   }
2236 
2237   UNREACHABLE();
2238 }
2239 
GetMethodLocation() const2240 Location InvokeDexCallingConventionVisitorARM::GetMethodLocation() const {
2241   return Location::RegisterLocation(kMethodRegisterArgument);
2242 }
2243 
Move32(Location destination,Location source)2244 void CodeGeneratorARM::Move32(Location destination, Location source) {
2245   if (source.Equals(destination)) {
2246     return;
2247   }
2248   if (destination.IsRegister()) {
2249     if (source.IsRegister()) {
2250       __ Mov(destination.AsRegister<Register>(), source.AsRegister<Register>());
2251     } else if (source.IsFpuRegister()) {
2252       __ vmovrs(destination.AsRegister<Register>(), source.AsFpuRegister<SRegister>());
2253     } else {
2254       __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(), SP, source.GetStackIndex());
2255     }
2256   } else if (destination.IsFpuRegister()) {
2257     if (source.IsRegister()) {
2258       __ vmovsr(destination.AsFpuRegister<SRegister>(), source.AsRegister<Register>());
2259     } else if (source.IsFpuRegister()) {
2260       __ vmovs(destination.AsFpuRegister<SRegister>(), source.AsFpuRegister<SRegister>());
2261     } else {
2262       __ LoadSFromOffset(destination.AsFpuRegister<SRegister>(), SP, source.GetStackIndex());
2263     }
2264   } else {
2265     DCHECK(destination.IsStackSlot()) << destination;
2266     if (source.IsRegister()) {
2267       __ StoreToOffset(kStoreWord, source.AsRegister<Register>(), SP, destination.GetStackIndex());
2268     } else if (source.IsFpuRegister()) {
2269       __ StoreSToOffset(source.AsFpuRegister<SRegister>(), SP, destination.GetStackIndex());
2270     } else {
2271       DCHECK(source.IsStackSlot()) << source;
2272       __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
2273       __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
2274     }
2275   }
2276 }
2277 
Move64(Location destination,Location source)2278 void CodeGeneratorARM::Move64(Location destination, Location source) {
2279   if (source.Equals(destination)) {
2280     return;
2281   }
2282   if (destination.IsRegisterPair()) {
2283     if (source.IsRegisterPair()) {
2284       EmitParallelMoves(
2285           Location::RegisterLocation(source.AsRegisterPairHigh<Register>()),
2286           Location::RegisterLocation(destination.AsRegisterPairHigh<Register>()),
2287           Primitive::kPrimInt,
2288           Location::RegisterLocation(source.AsRegisterPairLow<Register>()),
2289           Location::RegisterLocation(destination.AsRegisterPairLow<Register>()),
2290           Primitive::kPrimInt);
2291     } else if (source.IsFpuRegister()) {
2292       UNIMPLEMENTED(FATAL);
2293     } else if (source.IsFpuRegisterPair()) {
2294       __ vmovrrd(destination.AsRegisterPairLow<Register>(),
2295                  destination.AsRegisterPairHigh<Register>(),
2296                  FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()));
2297     } else {
2298       DCHECK(source.IsDoubleStackSlot());
2299       DCHECK(ExpectedPairLayout(destination));
2300       __ LoadFromOffset(kLoadWordPair, destination.AsRegisterPairLow<Register>(),
2301                         SP, source.GetStackIndex());
2302     }
2303   } else if (destination.IsFpuRegisterPair()) {
2304     if (source.IsDoubleStackSlot()) {
2305       __ LoadDFromOffset(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
2306                          SP,
2307                          source.GetStackIndex());
2308     } else if (source.IsRegisterPair()) {
2309       __ vmovdrr(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
2310                  source.AsRegisterPairLow<Register>(),
2311                  source.AsRegisterPairHigh<Register>());
2312     } else {
2313       UNIMPLEMENTED(FATAL);
2314     }
2315   } else {
2316     DCHECK(destination.IsDoubleStackSlot());
2317     if (source.IsRegisterPair()) {
2318       // No conflict possible, so just do the moves.
2319       if (source.AsRegisterPairLow<Register>() == R1) {
2320         DCHECK_EQ(source.AsRegisterPairHigh<Register>(), R2);
2321         __ StoreToOffset(kStoreWord, R1, SP, destination.GetStackIndex());
2322         __ StoreToOffset(kStoreWord, R2, SP, destination.GetHighStackIndex(kArmWordSize));
2323       } else {
2324         __ StoreToOffset(kStoreWordPair, source.AsRegisterPairLow<Register>(),
2325                          SP, destination.GetStackIndex());
2326       }
2327     } else if (source.IsFpuRegisterPair()) {
2328       __ StoreDToOffset(FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()),
2329                         SP,
2330                         destination.GetStackIndex());
2331     } else {
2332       DCHECK(source.IsDoubleStackSlot());
2333       EmitParallelMoves(
2334           Location::StackSlot(source.GetStackIndex()),
2335           Location::StackSlot(destination.GetStackIndex()),
2336           Primitive::kPrimInt,
2337           Location::StackSlot(source.GetHighStackIndex(kArmWordSize)),
2338           Location::StackSlot(destination.GetHighStackIndex(kArmWordSize)),
2339           Primitive::kPrimInt);
2340     }
2341   }
2342 }
2343 
MoveConstant(Location location,int32_t value)2344 void CodeGeneratorARM::MoveConstant(Location location, int32_t value) {
2345   DCHECK(location.IsRegister());
2346   __ LoadImmediate(location.AsRegister<Register>(), value);
2347 }
2348 
MoveLocation(Location dst,Location src,Primitive::Type dst_type)2349 void CodeGeneratorARM::MoveLocation(Location dst, Location src, Primitive::Type dst_type) {
2350   HParallelMove move(GetGraph()->GetArena());
2351   move.AddMove(src, dst, dst_type, nullptr);
2352   GetMoveResolver()->EmitNativeCode(&move);
2353 }
2354 
AddLocationAsTemp(Location location,LocationSummary * locations)2355 void CodeGeneratorARM::AddLocationAsTemp(Location location, LocationSummary* locations) {
2356   if (location.IsRegister()) {
2357     locations->AddTemp(location);
2358   } else if (location.IsRegisterPair()) {
2359     locations->AddTemp(Location::RegisterLocation(location.AsRegisterPairLow<Register>()));
2360     locations->AddTemp(Location::RegisterLocation(location.AsRegisterPairHigh<Register>()));
2361   } else {
2362     UNIMPLEMENTED(FATAL) << "AddLocationAsTemp not implemented for location " << location;
2363   }
2364 }
2365 
InvokeRuntime(QuickEntrypointEnum entrypoint,HInstruction * instruction,uint32_t dex_pc,SlowPathCode * slow_path)2366 void CodeGeneratorARM::InvokeRuntime(QuickEntrypointEnum entrypoint,
2367                                      HInstruction* instruction,
2368                                      uint32_t dex_pc,
2369                                      SlowPathCode* slow_path) {
2370   ValidateInvokeRuntime(entrypoint, instruction, slow_path);
2371   GenerateInvokeRuntime(GetThreadOffset<kArmPointerSize>(entrypoint).Int32Value());
2372   if (EntrypointRequiresStackMap(entrypoint)) {
2373     RecordPcInfo(instruction, dex_pc, slow_path);
2374   }
2375 }
2376 
InvokeRuntimeWithoutRecordingPcInfo(int32_t entry_point_offset,HInstruction * instruction,SlowPathCode * slow_path)2377 void CodeGeneratorARM::InvokeRuntimeWithoutRecordingPcInfo(int32_t entry_point_offset,
2378                                                            HInstruction* instruction,
2379                                                            SlowPathCode* slow_path) {
2380   ValidateInvokeRuntimeWithoutRecordingPcInfo(instruction, slow_path);
2381   GenerateInvokeRuntime(entry_point_offset);
2382 }
2383 
GenerateInvokeRuntime(int32_t entry_point_offset)2384 void CodeGeneratorARM::GenerateInvokeRuntime(int32_t entry_point_offset) {
2385   __ LoadFromOffset(kLoadWord, LR, TR, entry_point_offset);
2386   __ blx(LR);
2387 }
2388 
HandleGoto(HInstruction * got,HBasicBlock * successor)2389 void InstructionCodeGeneratorARM::HandleGoto(HInstruction* got, HBasicBlock* successor) {
2390   DCHECK(!successor->IsExitBlock());
2391 
2392   HBasicBlock* block = got->GetBlock();
2393   HInstruction* previous = got->GetPrevious();
2394 
2395   HLoopInformation* info = block->GetLoopInformation();
2396   if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
2397     codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck());
2398     GenerateSuspendCheck(info->GetSuspendCheck(), successor);
2399     return;
2400   }
2401 
2402   if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
2403     GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
2404   }
2405   if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
2406     __ b(codegen_->GetLabelOf(successor));
2407   }
2408 }
2409 
VisitGoto(HGoto * got)2410 void LocationsBuilderARM::VisitGoto(HGoto* got) {
2411   got->SetLocations(nullptr);
2412 }
2413 
VisitGoto(HGoto * got)2414 void InstructionCodeGeneratorARM::VisitGoto(HGoto* got) {
2415   HandleGoto(got, got->GetSuccessor());
2416 }
2417 
VisitTryBoundary(HTryBoundary * try_boundary)2418 void LocationsBuilderARM::VisitTryBoundary(HTryBoundary* try_boundary) {
2419   try_boundary->SetLocations(nullptr);
2420 }
2421 
VisitTryBoundary(HTryBoundary * try_boundary)2422 void InstructionCodeGeneratorARM::VisitTryBoundary(HTryBoundary* try_boundary) {
2423   HBasicBlock* successor = try_boundary->GetNormalFlowSuccessor();
2424   if (!successor->IsExitBlock()) {
2425     HandleGoto(try_boundary, successor);
2426   }
2427 }
2428 
VisitExit(HExit * exit)2429 void LocationsBuilderARM::VisitExit(HExit* exit) {
2430   exit->SetLocations(nullptr);
2431 }
2432 
VisitExit(HExit * exit ATTRIBUTE_UNUSED)2433 void InstructionCodeGeneratorARM::VisitExit(HExit* exit ATTRIBUTE_UNUSED) {
2434 }
2435 
GenerateLongComparesAndJumps(HCondition * cond,Label * true_label,Label * false_label)2436 void InstructionCodeGeneratorARM::GenerateLongComparesAndJumps(HCondition* cond,
2437                                                                Label* true_label,
2438                                                                Label* false_label) {
2439   LocationSummary* locations = cond->GetLocations();
2440   Location left = locations->InAt(0);
2441   Location right = locations->InAt(1);
2442   IfCondition if_cond = cond->GetCondition();
2443 
2444   Register left_high = left.AsRegisterPairHigh<Register>();
2445   Register left_low = left.AsRegisterPairLow<Register>();
2446   IfCondition true_high_cond = if_cond;
2447   IfCondition false_high_cond = cond->GetOppositeCondition();
2448   Condition final_condition = ARMUnsignedCondition(if_cond);  // unsigned on lower part
2449 
2450   // Set the conditions for the test, remembering that == needs to be
2451   // decided using the low words.
2452   switch (if_cond) {
2453     case kCondEQ:
2454     case kCondNE:
2455       // Nothing to do.
2456       break;
2457     case kCondLT:
2458       false_high_cond = kCondGT;
2459       break;
2460     case kCondLE:
2461       true_high_cond = kCondLT;
2462       break;
2463     case kCondGT:
2464       false_high_cond = kCondLT;
2465       break;
2466     case kCondGE:
2467       true_high_cond = kCondGT;
2468       break;
2469     case kCondB:
2470       false_high_cond = kCondA;
2471       break;
2472     case kCondBE:
2473       true_high_cond = kCondB;
2474       break;
2475     case kCondA:
2476       false_high_cond = kCondB;
2477       break;
2478     case kCondAE:
2479       true_high_cond = kCondA;
2480       break;
2481   }
2482   if (right.IsConstant()) {
2483     int64_t value = right.GetConstant()->AsLongConstant()->GetValue();
2484     int32_t val_low = Low32Bits(value);
2485     int32_t val_high = High32Bits(value);
2486 
2487     __ CmpConstant(left_high, val_high);
2488     if (if_cond == kCondNE) {
2489       __ b(true_label, ARMCondition(true_high_cond));
2490     } else if (if_cond == kCondEQ) {
2491       __ b(false_label, ARMCondition(false_high_cond));
2492     } else {
2493       __ b(true_label, ARMCondition(true_high_cond));
2494       __ b(false_label, ARMCondition(false_high_cond));
2495     }
2496     // Must be equal high, so compare the lows.
2497     __ CmpConstant(left_low, val_low);
2498   } else {
2499     Register right_high = right.AsRegisterPairHigh<Register>();
2500     Register right_low = right.AsRegisterPairLow<Register>();
2501 
2502     __ cmp(left_high, ShifterOperand(right_high));
2503     if (if_cond == kCondNE) {
2504       __ b(true_label, ARMCondition(true_high_cond));
2505     } else if (if_cond == kCondEQ) {
2506       __ b(false_label, ARMCondition(false_high_cond));
2507     } else {
2508       __ b(true_label, ARMCondition(true_high_cond));
2509       __ b(false_label, ARMCondition(false_high_cond));
2510     }
2511     // Must be equal high, so compare the lows.
2512     __ cmp(left_low, ShifterOperand(right_low));
2513   }
2514   // The last comparison might be unsigned.
2515   // TODO: optimize cases where this is always true/false
2516   __ b(true_label, final_condition);
2517 }
2518 
GenerateCompareTestAndBranch(HCondition * condition,Label * true_target_in,Label * false_target_in)2519 void InstructionCodeGeneratorARM::GenerateCompareTestAndBranch(HCondition* condition,
2520                                                                Label* true_target_in,
2521                                                                Label* false_target_in) {
2522   if (CanGenerateTest(condition, codegen_->GetAssembler())) {
2523     Label* non_fallthrough_target;
2524     bool invert;
2525     bool emit_both_branches;
2526 
2527     if (true_target_in == nullptr) {
2528       // The true target is fallthrough.
2529       DCHECK(false_target_in != nullptr);
2530       non_fallthrough_target = false_target_in;
2531       invert = true;
2532       emit_both_branches = false;
2533     } else {
2534       // Either the false target is fallthrough, or there is no fallthrough
2535       // and both branches must be emitted.
2536       non_fallthrough_target = true_target_in;
2537       invert = false;
2538       emit_both_branches = (false_target_in != nullptr);
2539     }
2540 
2541     const auto cond = GenerateTest(condition, invert, codegen_);
2542 
2543     __ b(non_fallthrough_target, cond.first);
2544 
2545     if (emit_both_branches) {
2546       // No target falls through, we need to branch.
2547       __ b(false_target_in);
2548     }
2549 
2550     return;
2551   }
2552 
2553   // Generated branching requires both targets to be explicit. If either of the
2554   // targets is nullptr (fallthrough) use and bind `fallthrough_target` instead.
2555   Label fallthrough_target;
2556   Label* true_target = true_target_in == nullptr ? &fallthrough_target : true_target_in;
2557   Label* false_target = false_target_in == nullptr ? &fallthrough_target : false_target_in;
2558 
2559   DCHECK_EQ(condition->InputAt(0)->GetType(), Primitive::kPrimLong);
2560   GenerateLongComparesAndJumps(condition, true_target, false_target);
2561 
2562   if (false_target != &fallthrough_target) {
2563     __ b(false_target);
2564   }
2565 
2566   if (fallthrough_target.IsLinked()) {
2567     __ Bind(&fallthrough_target);
2568   }
2569 }
2570 
GenerateTestAndBranch(HInstruction * instruction,size_t condition_input_index,Label * true_target,Label * false_target)2571 void InstructionCodeGeneratorARM::GenerateTestAndBranch(HInstruction* instruction,
2572                                                         size_t condition_input_index,
2573                                                         Label* true_target,
2574                                                         Label* false_target) {
2575   HInstruction* cond = instruction->InputAt(condition_input_index);
2576 
2577   if (true_target == nullptr && false_target == nullptr) {
2578     // Nothing to do. The code always falls through.
2579     return;
2580   } else if (cond->IsIntConstant()) {
2581     // Constant condition, statically compared against "true" (integer value 1).
2582     if (cond->AsIntConstant()->IsTrue()) {
2583       if (true_target != nullptr) {
2584         __ b(true_target);
2585       }
2586     } else {
2587       DCHECK(cond->AsIntConstant()->IsFalse()) << cond->AsIntConstant()->GetValue();
2588       if (false_target != nullptr) {
2589         __ b(false_target);
2590       }
2591     }
2592     return;
2593   }
2594 
2595   // The following code generates these patterns:
2596   //  (1) true_target == nullptr && false_target != nullptr
2597   //        - opposite condition true => branch to false_target
2598   //  (2) true_target != nullptr && false_target == nullptr
2599   //        - condition true => branch to true_target
2600   //  (3) true_target != nullptr && false_target != nullptr
2601   //        - condition true => branch to true_target
2602   //        - branch to false_target
2603   if (IsBooleanValueOrMaterializedCondition(cond)) {
2604     // Condition has been materialized, compare the output to 0.
2605     Location cond_val = instruction->GetLocations()->InAt(condition_input_index);
2606     DCHECK(cond_val.IsRegister());
2607     if (true_target == nullptr) {
2608       __ CompareAndBranchIfZero(cond_val.AsRegister<Register>(), false_target);
2609     } else {
2610       __ CompareAndBranchIfNonZero(cond_val.AsRegister<Register>(), true_target);
2611     }
2612   } else {
2613     // Condition has not been materialized. Use its inputs as the comparison and
2614     // its condition as the branch condition.
2615     HCondition* condition = cond->AsCondition();
2616 
2617     // If this is a long or FP comparison that has been folded into
2618     // the HCondition, generate the comparison directly.
2619     Primitive::Type type = condition->InputAt(0)->GetType();
2620     if (type == Primitive::kPrimLong || Primitive::IsFloatingPointType(type)) {
2621       GenerateCompareTestAndBranch(condition, true_target, false_target);
2622       return;
2623     }
2624 
2625     Label* non_fallthrough_target;
2626     Condition arm_cond;
2627     LocationSummary* locations = cond->GetLocations();
2628     DCHECK(locations->InAt(0).IsRegister());
2629     Register left = locations->InAt(0).AsRegister<Register>();
2630     Location right = locations->InAt(1);
2631 
2632     if (true_target == nullptr) {
2633       arm_cond = ARMCondition(condition->GetOppositeCondition());
2634       non_fallthrough_target = false_target;
2635     } else {
2636       arm_cond = ARMCondition(condition->GetCondition());
2637       non_fallthrough_target = true_target;
2638     }
2639 
2640     if (right.IsConstant() && (arm_cond == NE || arm_cond == EQ) &&
2641         CodeGenerator::GetInt32ValueOf(right.GetConstant()) == 0) {
2642       if (arm_cond == EQ) {
2643         __ CompareAndBranchIfZero(left, non_fallthrough_target);
2644       } else {
2645         DCHECK_EQ(arm_cond, NE);
2646         __ CompareAndBranchIfNonZero(left, non_fallthrough_target);
2647       }
2648     } else {
2649       if (right.IsRegister()) {
2650         __ cmp(left, ShifterOperand(right.AsRegister<Register>()));
2651       } else {
2652         DCHECK(right.IsConstant());
2653         __ CmpConstant(left, CodeGenerator::GetInt32ValueOf(right.GetConstant()));
2654       }
2655 
2656       __ b(non_fallthrough_target, arm_cond);
2657     }
2658   }
2659 
2660   // If neither branch falls through (case 3), the conditional branch to `true_target`
2661   // was already emitted (case 2) and we need to emit a jump to `false_target`.
2662   if (true_target != nullptr && false_target != nullptr) {
2663     __ b(false_target);
2664   }
2665 }
2666 
VisitIf(HIf * if_instr)2667 void LocationsBuilderARM::VisitIf(HIf* if_instr) {
2668   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr);
2669   if (IsBooleanValueOrMaterializedCondition(if_instr->InputAt(0))) {
2670     locations->SetInAt(0, Location::RequiresRegister());
2671   }
2672 }
2673 
VisitIf(HIf * if_instr)2674 void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) {
2675   HBasicBlock* true_successor = if_instr->IfTrueSuccessor();
2676   HBasicBlock* false_successor = if_instr->IfFalseSuccessor();
2677   Label* true_target = codegen_->GoesToNextBlock(if_instr->GetBlock(), true_successor) ?
2678       nullptr : codegen_->GetLabelOf(true_successor);
2679   Label* false_target = codegen_->GoesToNextBlock(if_instr->GetBlock(), false_successor) ?
2680       nullptr : codegen_->GetLabelOf(false_successor);
2681   GenerateTestAndBranch(if_instr, /* condition_input_index */ 0, true_target, false_target);
2682 }
2683 
VisitDeoptimize(HDeoptimize * deoptimize)2684 void LocationsBuilderARM::VisitDeoptimize(HDeoptimize* deoptimize) {
2685   LocationSummary* locations = new (GetGraph()->GetArena())
2686       LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
2687   InvokeRuntimeCallingConvention calling_convention;
2688   RegisterSet caller_saves = RegisterSet::Empty();
2689   caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2690   locations->SetCustomSlowPathCallerSaves(caller_saves);
2691   if (IsBooleanValueOrMaterializedCondition(deoptimize->InputAt(0))) {
2692     locations->SetInAt(0, Location::RequiresRegister());
2693   }
2694 }
2695 
VisitDeoptimize(HDeoptimize * deoptimize)2696 void InstructionCodeGeneratorARM::VisitDeoptimize(HDeoptimize* deoptimize) {
2697   SlowPathCodeARM* slow_path = deopt_slow_paths_.NewSlowPath<DeoptimizationSlowPathARM>(deoptimize);
2698   GenerateTestAndBranch(deoptimize,
2699                         /* condition_input_index */ 0,
2700                         slow_path->GetEntryLabel(),
2701                         /* false_target */ nullptr);
2702 }
2703 
VisitShouldDeoptimizeFlag(HShouldDeoptimizeFlag * flag)2704 void LocationsBuilderARM::VisitShouldDeoptimizeFlag(HShouldDeoptimizeFlag* flag) {
2705   LocationSummary* locations = new (GetGraph()->GetArena())
2706       LocationSummary(flag, LocationSummary::kNoCall);
2707   locations->SetOut(Location::RequiresRegister());
2708 }
2709 
VisitShouldDeoptimizeFlag(HShouldDeoptimizeFlag * flag)2710 void InstructionCodeGeneratorARM::VisitShouldDeoptimizeFlag(HShouldDeoptimizeFlag* flag) {
2711   __ LoadFromOffset(kLoadWord,
2712                     flag->GetLocations()->Out().AsRegister<Register>(),
2713                     SP,
2714                     codegen_->GetStackOffsetOfShouldDeoptimizeFlag());
2715 }
2716 
VisitSelect(HSelect * select)2717 void LocationsBuilderARM::VisitSelect(HSelect* select) {
2718   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(select);
2719   const bool is_floating_point = Primitive::IsFloatingPointType(select->GetType());
2720 
2721   if (is_floating_point) {
2722     locations->SetInAt(0, Location::RequiresFpuRegister());
2723     locations->SetInAt(1, Location::FpuRegisterOrConstant(select->GetTrueValue()));
2724   } else {
2725     locations->SetInAt(0, Location::RequiresRegister());
2726     locations->SetInAt(1, Arm8BitEncodableConstantOrRegister(select->GetTrueValue()));
2727   }
2728 
2729   if (IsBooleanValueOrMaterializedCondition(select->GetCondition())) {
2730     locations->SetInAt(2, Location::RegisterOrConstant(select->GetCondition()));
2731     // The code generator handles overlap with the values, but not with the condition.
2732     locations->SetOut(Location::SameAsFirstInput());
2733   } else if (is_floating_point) {
2734     locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
2735   } else {
2736     if (!locations->InAt(1).IsConstant()) {
2737       locations->SetInAt(0, Arm8BitEncodableConstantOrRegister(select->GetFalseValue()));
2738     }
2739 
2740     locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2741   }
2742 }
2743 
VisitSelect(HSelect * select)2744 void InstructionCodeGeneratorARM::VisitSelect(HSelect* select) {
2745   HInstruction* const condition = select->GetCondition();
2746   const LocationSummary* const locations = select->GetLocations();
2747   const Primitive::Type type = select->GetType();
2748   const Location first = locations->InAt(0);
2749   const Location out = locations->Out();
2750   const Location second = locations->InAt(1);
2751   Location src;
2752 
2753   if (condition->IsIntConstant()) {
2754     if (condition->AsIntConstant()->IsFalse()) {
2755       src = first;
2756     } else {
2757       src = second;
2758     }
2759 
2760     codegen_->MoveLocation(out, src, type);
2761     return;
2762   }
2763 
2764   if (!Primitive::IsFloatingPointType(type) &&
2765       (IsBooleanValueOrMaterializedCondition(condition) ||
2766        CanGenerateTest(condition->AsCondition(), codegen_->GetAssembler()))) {
2767     bool invert = false;
2768 
2769     if (out.Equals(second)) {
2770       src = first;
2771       invert = true;
2772     } else if (out.Equals(first)) {
2773       src = second;
2774     } else if (second.IsConstant()) {
2775       DCHECK(CanEncodeConstantAs8BitImmediate(second.GetConstant()));
2776       src = second;
2777     } else if (first.IsConstant()) {
2778       DCHECK(CanEncodeConstantAs8BitImmediate(first.GetConstant()));
2779       src = first;
2780       invert = true;
2781     } else {
2782       src = second;
2783     }
2784 
2785     if (CanGenerateConditionalMove(out, src)) {
2786       if (!out.Equals(first) && !out.Equals(second)) {
2787         codegen_->MoveLocation(out, src.Equals(first) ? second : first, type);
2788       }
2789 
2790       std::pair<Condition, Condition> cond;
2791 
2792       if (IsBooleanValueOrMaterializedCondition(condition)) {
2793         __ CmpConstant(locations->InAt(2).AsRegister<Register>(), 0);
2794         cond = invert ? std::make_pair(EQ, NE) : std::make_pair(NE, EQ);
2795       } else {
2796         cond = GenerateTest(condition->AsCondition(), invert, codegen_);
2797       }
2798 
2799       if (out.IsRegister()) {
2800         ShifterOperand operand;
2801 
2802         if (src.IsConstant()) {
2803           operand = ShifterOperand(CodeGenerator::GetInt32ValueOf(src.GetConstant()));
2804         } else {
2805           DCHECK(src.IsRegister());
2806           operand = ShifterOperand(src.AsRegister<Register>());
2807         }
2808 
2809         __ it(cond.first);
2810         __ mov(out.AsRegister<Register>(), operand, cond.first);
2811       } else {
2812         DCHECK(out.IsRegisterPair());
2813 
2814         ShifterOperand operand_high;
2815         ShifterOperand operand_low;
2816 
2817         if (src.IsConstant()) {
2818           const int64_t value = src.GetConstant()->AsLongConstant()->GetValue();
2819 
2820           operand_high = ShifterOperand(High32Bits(value));
2821           operand_low = ShifterOperand(Low32Bits(value));
2822         } else {
2823           DCHECK(src.IsRegisterPair());
2824           operand_high = ShifterOperand(src.AsRegisterPairHigh<Register>());
2825           operand_low = ShifterOperand(src.AsRegisterPairLow<Register>());
2826         }
2827 
2828         __ it(cond.first);
2829         __ mov(out.AsRegisterPairLow<Register>(), operand_low, cond.first);
2830         __ it(cond.first);
2831         __ mov(out.AsRegisterPairHigh<Register>(), operand_high, cond.first);
2832       }
2833 
2834       return;
2835     }
2836   }
2837 
2838   Label* false_target = nullptr;
2839   Label* true_target = nullptr;
2840   Label select_end;
2841   Label* target = codegen_->GetFinalLabel(select, &select_end);
2842 
2843   if (out.Equals(second)) {
2844     true_target = target;
2845     src = first;
2846   } else {
2847     false_target = target;
2848     src = second;
2849 
2850     if (!out.Equals(first)) {
2851       codegen_->MoveLocation(out, first, type);
2852     }
2853   }
2854 
2855   GenerateTestAndBranch(select, 2, true_target, false_target);
2856   codegen_->MoveLocation(out, src, type);
2857 
2858   if (select_end.IsLinked()) {
2859     __ Bind(&select_end);
2860   }
2861 }
2862 
VisitNativeDebugInfo(HNativeDebugInfo * info)2863 void LocationsBuilderARM::VisitNativeDebugInfo(HNativeDebugInfo* info) {
2864   new (GetGraph()->GetArena()) LocationSummary(info);
2865 }
2866 
VisitNativeDebugInfo(HNativeDebugInfo *)2867 void InstructionCodeGeneratorARM::VisitNativeDebugInfo(HNativeDebugInfo*) {
2868   // MaybeRecordNativeDebugInfo is already called implicitly in CodeGenerator::Compile.
2869 }
2870 
GenerateNop()2871 void CodeGeneratorARM::GenerateNop() {
2872   __ nop();
2873 }
2874 
HandleCondition(HCondition * cond)2875 void LocationsBuilderARM::HandleCondition(HCondition* cond) {
2876   LocationSummary* locations =
2877       new (GetGraph()->GetArena()) LocationSummary(cond, LocationSummary::kNoCall);
2878   // Handle the long/FP comparisons made in instruction simplification.
2879   switch (cond->InputAt(0)->GetType()) {
2880     case Primitive::kPrimLong:
2881       locations->SetInAt(0, Location::RequiresRegister());
2882       locations->SetInAt(1, Location::RegisterOrConstant(cond->InputAt(1)));
2883       if (!cond->IsEmittedAtUseSite()) {
2884         locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2885       }
2886       break;
2887 
2888     case Primitive::kPrimFloat:
2889     case Primitive::kPrimDouble:
2890       locations->SetInAt(0, Location::RequiresFpuRegister());
2891       locations->SetInAt(1, ArithmeticZeroOrFpuRegister(cond->InputAt(1)));
2892       if (!cond->IsEmittedAtUseSite()) {
2893         locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2894       }
2895       break;
2896 
2897     default:
2898       locations->SetInAt(0, Location::RequiresRegister());
2899       locations->SetInAt(1, Location::RegisterOrConstant(cond->InputAt(1)));
2900       if (!cond->IsEmittedAtUseSite()) {
2901         locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2902       }
2903   }
2904 }
2905 
HandleCondition(HCondition * cond)2906 void InstructionCodeGeneratorARM::HandleCondition(HCondition* cond) {
2907   if (cond->IsEmittedAtUseSite()) {
2908     return;
2909   }
2910 
2911   const Register out = cond->GetLocations()->Out().AsRegister<Register>();
2912 
2913   if (ArmAssembler::IsLowRegister(out) && CanGenerateTest(cond, codegen_->GetAssembler())) {
2914     const auto condition = GenerateTest(cond, false, codegen_);
2915 
2916     __ it(condition.first);
2917     __ mov(out, ShifterOperand(1), condition.first);
2918     __ it(condition.second);
2919     __ mov(out, ShifterOperand(0), condition.second);
2920     return;
2921   }
2922 
2923   // Convert the jumps into the result.
2924   Label done_label;
2925   Label* const final_label = codegen_->GetFinalLabel(cond, &done_label);
2926 
2927   if (cond->InputAt(0)->GetType() == Primitive::kPrimLong) {
2928     Label true_label, false_label;
2929 
2930     GenerateLongComparesAndJumps(cond, &true_label, &false_label);
2931 
2932     // False case: result = 0.
2933     __ Bind(&false_label);
2934     __ LoadImmediate(out, 0);
2935     __ b(final_label);
2936 
2937     // True case: result = 1.
2938     __ Bind(&true_label);
2939     __ LoadImmediate(out, 1);
2940   } else {
2941     DCHECK(CanGenerateTest(cond, codegen_->GetAssembler()));
2942 
2943     const auto condition = GenerateTest(cond, false, codegen_);
2944 
2945     __ mov(out, ShifterOperand(0), AL, kCcKeep);
2946     __ b(final_label, condition.second);
2947     __ LoadImmediate(out, 1);
2948   }
2949 
2950   if (done_label.IsLinked()) {
2951     __ Bind(&done_label);
2952   }
2953 }
2954 
VisitEqual(HEqual * comp)2955 void LocationsBuilderARM::VisitEqual(HEqual* comp) {
2956   HandleCondition(comp);
2957 }
2958 
VisitEqual(HEqual * comp)2959 void InstructionCodeGeneratorARM::VisitEqual(HEqual* comp) {
2960   HandleCondition(comp);
2961 }
2962 
VisitNotEqual(HNotEqual * comp)2963 void LocationsBuilderARM::VisitNotEqual(HNotEqual* comp) {
2964   HandleCondition(comp);
2965 }
2966 
VisitNotEqual(HNotEqual * comp)2967 void InstructionCodeGeneratorARM::VisitNotEqual(HNotEqual* comp) {
2968   HandleCondition(comp);
2969 }
2970 
VisitLessThan(HLessThan * comp)2971 void LocationsBuilderARM::VisitLessThan(HLessThan* comp) {
2972   HandleCondition(comp);
2973 }
2974 
VisitLessThan(HLessThan * comp)2975 void InstructionCodeGeneratorARM::VisitLessThan(HLessThan* comp) {
2976   HandleCondition(comp);
2977 }
2978 
VisitLessThanOrEqual(HLessThanOrEqual * comp)2979 void LocationsBuilderARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
2980   HandleCondition(comp);
2981 }
2982 
VisitLessThanOrEqual(HLessThanOrEqual * comp)2983 void InstructionCodeGeneratorARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
2984   HandleCondition(comp);
2985 }
2986 
VisitGreaterThan(HGreaterThan * comp)2987 void LocationsBuilderARM::VisitGreaterThan(HGreaterThan* comp) {
2988   HandleCondition(comp);
2989 }
2990 
VisitGreaterThan(HGreaterThan * comp)2991 void InstructionCodeGeneratorARM::VisitGreaterThan(HGreaterThan* comp) {
2992   HandleCondition(comp);
2993 }
2994 
VisitGreaterThanOrEqual(HGreaterThanOrEqual * comp)2995 void LocationsBuilderARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
2996   HandleCondition(comp);
2997 }
2998 
VisitGreaterThanOrEqual(HGreaterThanOrEqual * comp)2999 void InstructionCodeGeneratorARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
3000   HandleCondition(comp);
3001 }
3002 
VisitBelow(HBelow * comp)3003 void LocationsBuilderARM::VisitBelow(HBelow* comp) {
3004   HandleCondition(comp);
3005 }
3006 
VisitBelow(HBelow * comp)3007 void InstructionCodeGeneratorARM::VisitBelow(HBelow* comp) {
3008   HandleCondition(comp);
3009 }
3010 
VisitBelowOrEqual(HBelowOrEqual * comp)3011 void LocationsBuilderARM::VisitBelowOrEqual(HBelowOrEqual* comp) {
3012   HandleCondition(comp);
3013 }
3014 
VisitBelowOrEqual(HBelowOrEqual * comp)3015 void InstructionCodeGeneratorARM::VisitBelowOrEqual(HBelowOrEqual* comp) {
3016   HandleCondition(comp);
3017 }
3018 
VisitAbove(HAbove * comp)3019 void LocationsBuilderARM::VisitAbove(HAbove* comp) {
3020   HandleCondition(comp);
3021 }
3022 
VisitAbove(HAbove * comp)3023 void InstructionCodeGeneratorARM::VisitAbove(HAbove* comp) {
3024   HandleCondition(comp);
3025 }
3026 
VisitAboveOrEqual(HAboveOrEqual * comp)3027 void LocationsBuilderARM::VisitAboveOrEqual(HAboveOrEqual* comp) {
3028   HandleCondition(comp);
3029 }
3030 
VisitAboveOrEqual(HAboveOrEqual * comp)3031 void InstructionCodeGeneratorARM::VisitAboveOrEqual(HAboveOrEqual* comp) {
3032   HandleCondition(comp);
3033 }
3034 
VisitIntConstant(HIntConstant * constant)3035 void LocationsBuilderARM::VisitIntConstant(HIntConstant* constant) {
3036   LocationSummary* locations =
3037       new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
3038   locations->SetOut(Location::ConstantLocation(constant));
3039 }
3040 
VisitIntConstant(HIntConstant * constant ATTRIBUTE_UNUSED)3041 void InstructionCodeGeneratorARM::VisitIntConstant(HIntConstant* constant ATTRIBUTE_UNUSED) {
3042   // Will be generated at use site.
3043 }
3044 
VisitNullConstant(HNullConstant * constant)3045 void LocationsBuilderARM::VisitNullConstant(HNullConstant* constant) {
3046   LocationSummary* locations =
3047       new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
3048   locations->SetOut(Location::ConstantLocation(constant));
3049 }
3050 
VisitNullConstant(HNullConstant * constant ATTRIBUTE_UNUSED)3051 void InstructionCodeGeneratorARM::VisitNullConstant(HNullConstant* constant ATTRIBUTE_UNUSED) {
3052   // Will be generated at use site.
3053 }
3054 
VisitLongConstant(HLongConstant * constant)3055 void LocationsBuilderARM::VisitLongConstant(HLongConstant* constant) {
3056   LocationSummary* locations =
3057       new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
3058   locations->SetOut(Location::ConstantLocation(constant));
3059 }
3060 
VisitLongConstant(HLongConstant * constant ATTRIBUTE_UNUSED)3061 void InstructionCodeGeneratorARM::VisitLongConstant(HLongConstant* constant ATTRIBUTE_UNUSED) {
3062   // Will be generated at use site.
3063 }
3064 
VisitFloatConstant(HFloatConstant * constant)3065 void LocationsBuilderARM::VisitFloatConstant(HFloatConstant* constant) {
3066   LocationSummary* locations =
3067       new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
3068   locations->SetOut(Location::ConstantLocation(constant));
3069 }
3070 
VisitFloatConstant(HFloatConstant * constant ATTRIBUTE_UNUSED)3071 void InstructionCodeGeneratorARM::VisitFloatConstant(HFloatConstant* constant ATTRIBUTE_UNUSED) {
3072   // Will be generated at use site.
3073 }
3074 
VisitDoubleConstant(HDoubleConstant * constant)3075 void LocationsBuilderARM::VisitDoubleConstant(HDoubleConstant* constant) {
3076   LocationSummary* locations =
3077       new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
3078   locations->SetOut(Location::ConstantLocation(constant));
3079 }
3080 
VisitDoubleConstant(HDoubleConstant * constant ATTRIBUTE_UNUSED)3081 void InstructionCodeGeneratorARM::VisitDoubleConstant(HDoubleConstant* constant ATTRIBUTE_UNUSED) {
3082   // Will be generated at use site.
3083 }
3084 
VisitMemoryBarrier(HMemoryBarrier * memory_barrier)3085 void LocationsBuilderARM::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
3086   memory_barrier->SetLocations(nullptr);
3087 }
3088 
VisitMemoryBarrier(HMemoryBarrier * memory_barrier)3089 void InstructionCodeGeneratorARM::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
3090   codegen_->GenerateMemoryBarrier(memory_barrier->GetBarrierKind());
3091 }
3092 
VisitReturnVoid(HReturnVoid * ret)3093 void LocationsBuilderARM::VisitReturnVoid(HReturnVoid* ret) {
3094   ret->SetLocations(nullptr);
3095 }
3096 
VisitReturnVoid(HReturnVoid * ret ATTRIBUTE_UNUSED)3097 void InstructionCodeGeneratorARM::VisitReturnVoid(HReturnVoid* ret ATTRIBUTE_UNUSED) {
3098   codegen_->GenerateFrameExit();
3099 }
3100 
VisitReturn(HReturn * ret)3101 void LocationsBuilderARM::VisitReturn(HReturn* ret) {
3102   LocationSummary* locations =
3103       new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
3104   locations->SetInAt(0, parameter_visitor_.GetReturnLocation(ret->InputAt(0)->GetType()));
3105 }
3106 
VisitReturn(HReturn * ret ATTRIBUTE_UNUSED)3107 void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret ATTRIBUTE_UNUSED) {
3108   codegen_->GenerateFrameExit();
3109 }
3110 
VisitInvokeUnresolved(HInvokeUnresolved * invoke)3111 void LocationsBuilderARM::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
3112   // The trampoline uses the same calling convention as dex calling conventions,
3113   // except instead of loading arg0/r0 with the target Method*, arg0/r0 will contain
3114   // the method_idx.
3115   HandleInvoke(invoke);
3116 }
3117 
VisitInvokeUnresolved(HInvokeUnresolved * invoke)3118 void InstructionCodeGeneratorARM::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
3119   codegen_->GenerateInvokeUnresolvedRuntimeCall(invoke);
3120 }
3121 
VisitInvokeStaticOrDirect(HInvokeStaticOrDirect * invoke)3122 void LocationsBuilderARM::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
3123   // Explicit clinit checks triggered by static invokes must have been pruned by
3124   // art::PrepareForRegisterAllocation.
3125   DCHECK(!invoke->IsStaticWithExplicitClinitCheck());
3126 
3127   IntrinsicLocationsBuilderARM intrinsic(codegen_);
3128   if (intrinsic.TryDispatch(invoke)) {
3129     if (invoke->GetLocations()->CanCall() && invoke->HasPcRelativeDexCache()) {
3130       invoke->GetLocations()->SetInAt(invoke->GetSpecialInputIndex(), Location::Any());
3131     }
3132     return;
3133   }
3134 
3135   HandleInvoke(invoke);
3136 
3137   // For PC-relative dex cache the invoke has an extra input, the PC-relative address base.
3138   if (invoke->HasPcRelativeDexCache()) {
3139     invoke->GetLocations()->SetInAt(invoke->GetSpecialInputIndex(), Location::RequiresRegister());
3140   }
3141 }
3142 
TryGenerateIntrinsicCode(HInvoke * invoke,CodeGeneratorARM * codegen)3143 static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorARM* codegen) {
3144   if (invoke->GetLocations()->Intrinsified()) {
3145     IntrinsicCodeGeneratorARM intrinsic(codegen);
3146     intrinsic.Dispatch(invoke);
3147     return true;
3148   }
3149   return false;
3150 }
3151 
VisitInvokeStaticOrDirect(HInvokeStaticOrDirect * invoke)3152 void InstructionCodeGeneratorARM::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
3153   // Explicit clinit checks triggered by static invokes must have been pruned by
3154   // art::PrepareForRegisterAllocation.
3155   DCHECK(!invoke->IsStaticWithExplicitClinitCheck());
3156 
3157   if (TryGenerateIntrinsicCode(invoke, codegen_)) {
3158     return;
3159   }
3160 
3161   LocationSummary* locations = invoke->GetLocations();
3162   codegen_->GenerateStaticOrDirectCall(
3163       invoke, locations->HasTemps() ? locations->GetTemp(0) : Location::NoLocation());
3164   codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
3165 }
3166 
HandleInvoke(HInvoke * invoke)3167 void LocationsBuilderARM::HandleInvoke(HInvoke* invoke) {
3168   InvokeDexCallingConventionVisitorARM calling_convention_visitor;
3169   CodeGenerator::CreateCommonInvokeLocationSummary(invoke, &calling_convention_visitor);
3170 }
3171 
VisitInvokeVirtual(HInvokeVirtual * invoke)3172 void LocationsBuilderARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
3173   IntrinsicLocationsBuilderARM intrinsic(codegen_);
3174   if (intrinsic.TryDispatch(invoke)) {
3175     return;
3176   }
3177 
3178   HandleInvoke(invoke);
3179 }
3180 
VisitInvokeVirtual(HInvokeVirtual * invoke)3181 void InstructionCodeGeneratorARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
3182   if (TryGenerateIntrinsicCode(invoke, codegen_)) {
3183     return;
3184   }
3185 
3186   codegen_->GenerateVirtualCall(invoke, invoke->GetLocations()->GetTemp(0));
3187   DCHECK(!codegen_->IsLeafMethod());
3188   codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
3189 }
3190 
VisitInvokeInterface(HInvokeInterface * invoke)3191 void LocationsBuilderARM::VisitInvokeInterface(HInvokeInterface* invoke) {
3192   HandleInvoke(invoke);
3193   // Add the hidden argument.
3194   invoke->GetLocations()->AddTemp(Location::RegisterLocation(R12));
3195 }
3196 
VisitInvokeInterface(HInvokeInterface * invoke)3197 void InstructionCodeGeneratorARM::VisitInvokeInterface(HInvokeInterface* invoke) {
3198   // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
3199   LocationSummary* locations = invoke->GetLocations();
3200   Register temp = locations->GetTemp(0).AsRegister<Register>();
3201   Register hidden_reg = locations->GetTemp(1).AsRegister<Register>();
3202   Location receiver = locations->InAt(0);
3203   uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
3204 
3205   // Set the hidden argument. This is safe to do this here, as R12
3206   // won't be modified thereafter, before the `blx` (call) instruction.
3207   DCHECK_EQ(R12, hidden_reg);
3208   __ LoadImmediate(hidden_reg, invoke->GetDexMethodIndex());
3209 
3210   if (receiver.IsStackSlot()) {
3211     __ LoadFromOffset(kLoadWord, temp, SP, receiver.GetStackIndex());
3212     // /* HeapReference<Class> */ temp = temp->klass_
3213     __ LoadFromOffset(kLoadWord, temp, temp, class_offset);
3214   } else {
3215     // /* HeapReference<Class> */ temp = receiver->klass_
3216     __ LoadFromOffset(kLoadWord, temp, receiver.AsRegister<Register>(), class_offset);
3217   }
3218   codegen_->MaybeRecordImplicitNullCheck(invoke);
3219   // Instead of simply (possibly) unpoisoning `temp` here, we should
3220   // emit a read barrier for the previous class reference load.
3221   // However this is not required in practice, as this is an
3222   // intermediate/temporary reference and because the current
3223   // concurrent copying collector keeps the from-space memory
3224   // intact/accessible until the end of the marking phase (the
3225   // concurrent copying collector may not in the future).
3226   __ MaybeUnpoisonHeapReference(temp);
3227   __ LoadFromOffset(kLoadWord, temp, temp,
3228         mirror::Class::ImtPtrOffset(kArmPointerSize).Uint32Value());
3229   uint32_t method_offset = static_cast<uint32_t>(ImTable::OffsetOfElement(
3230       invoke->GetImtIndex(), kArmPointerSize));
3231   // temp = temp->GetImtEntryAt(method_offset);
3232   __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
3233   uint32_t entry_point =
3234       ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArmPointerSize).Int32Value();
3235   // LR = temp->GetEntryPoint();
3236   __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
3237   // LR();
3238   __ blx(LR);
3239   DCHECK(!codegen_->IsLeafMethod());
3240   codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
3241 }
3242 
VisitInvokePolymorphic(HInvokePolymorphic * invoke)3243 void LocationsBuilderARM::VisitInvokePolymorphic(HInvokePolymorphic* invoke) {
3244   HandleInvoke(invoke);
3245 }
3246 
VisitInvokePolymorphic(HInvokePolymorphic * invoke)3247 void InstructionCodeGeneratorARM::VisitInvokePolymorphic(HInvokePolymorphic* invoke) {
3248   codegen_->GenerateInvokePolymorphicCall(invoke);
3249 }
3250 
VisitNeg(HNeg * neg)3251 void LocationsBuilderARM::VisitNeg(HNeg* neg) {
3252   LocationSummary* locations =
3253       new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
3254   switch (neg->GetResultType()) {
3255     case Primitive::kPrimInt: {
3256       locations->SetInAt(0, Location::RequiresRegister());
3257       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3258       break;
3259     }
3260     case Primitive::kPrimLong: {
3261       locations->SetInAt(0, Location::RequiresRegister());
3262       locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
3263       break;
3264     }
3265 
3266     case Primitive::kPrimFloat:
3267     case Primitive::kPrimDouble:
3268       locations->SetInAt(0, Location::RequiresFpuRegister());
3269       locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
3270       break;
3271 
3272     default:
3273       LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
3274   }
3275 }
3276 
VisitNeg(HNeg * neg)3277 void InstructionCodeGeneratorARM::VisitNeg(HNeg* neg) {
3278   LocationSummary* locations = neg->GetLocations();
3279   Location out = locations->Out();
3280   Location in = locations->InAt(0);
3281   switch (neg->GetResultType()) {
3282     case Primitive::kPrimInt:
3283       DCHECK(in.IsRegister());
3284       __ rsb(out.AsRegister<Register>(), in.AsRegister<Register>(), ShifterOperand(0));
3285       break;
3286 
3287     case Primitive::kPrimLong:
3288       DCHECK(in.IsRegisterPair());
3289       // out.lo = 0 - in.lo (and update the carry/borrow (C) flag)
3290       __ rsbs(out.AsRegisterPairLow<Register>(),
3291               in.AsRegisterPairLow<Register>(),
3292               ShifterOperand(0));
3293       // We cannot emit an RSC (Reverse Subtract with Carry)
3294       // instruction here, as it does not exist in the Thumb-2
3295       // instruction set.  We use the following approach
3296       // using SBC and SUB instead.
3297       //
3298       // out.hi = -C
3299       __ sbc(out.AsRegisterPairHigh<Register>(),
3300              out.AsRegisterPairHigh<Register>(),
3301              ShifterOperand(out.AsRegisterPairHigh<Register>()));
3302       // out.hi = out.hi - in.hi
3303       __ sub(out.AsRegisterPairHigh<Register>(),
3304              out.AsRegisterPairHigh<Register>(),
3305              ShifterOperand(in.AsRegisterPairHigh<Register>()));
3306       break;
3307 
3308     case Primitive::kPrimFloat:
3309       DCHECK(in.IsFpuRegister());
3310       __ vnegs(out.AsFpuRegister<SRegister>(), in.AsFpuRegister<SRegister>());
3311       break;
3312 
3313     case Primitive::kPrimDouble:
3314       DCHECK(in.IsFpuRegisterPair());
3315       __ vnegd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
3316                FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
3317       break;
3318 
3319     default:
3320       LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
3321   }
3322 }
3323 
VisitTypeConversion(HTypeConversion * conversion)3324 void LocationsBuilderARM::VisitTypeConversion(HTypeConversion* conversion) {
3325   Primitive::Type result_type = conversion->GetResultType();
3326   Primitive::Type input_type = conversion->GetInputType();
3327   DCHECK_NE(result_type, input_type);
3328 
3329   // The float-to-long, double-to-long and long-to-float type conversions
3330   // rely on a call to the runtime.
3331   LocationSummary::CallKind call_kind =
3332       (((input_type == Primitive::kPrimFloat || input_type == Primitive::kPrimDouble)
3333         && result_type == Primitive::kPrimLong)
3334        || (input_type == Primitive::kPrimLong && result_type == Primitive::kPrimFloat))
3335       ? LocationSummary::kCallOnMainOnly
3336       : LocationSummary::kNoCall;
3337   LocationSummary* locations =
3338       new (GetGraph()->GetArena()) LocationSummary(conversion, call_kind);
3339 
3340   // The Java language does not allow treating boolean as an integral type but
3341   // our bit representation makes it safe.
3342 
3343   switch (result_type) {
3344     case Primitive::kPrimByte:
3345       switch (input_type) {
3346         case Primitive::kPrimLong:
3347           // Type conversion from long to byte is a result of code transformations.
3348         case Primitive::kPrimBoolean:
3349           // Boolean input is a result of code transformations.
3350         case Primitive::kPrimShort:
3351         case Primitive::kPrimInt:
3352         case Primitive::kPrimChar:
3353           // Processing a Dex `int-to-byte' instruction.
3354           locations->SetInAt(0, Location::RequiresRegister());
3355           locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3356           break;
3357 
3358         default:
3359           LOG(FATAL) << "Unexpected type conversion from " << input_type
3360                      << " to " << result_type;
3361       }
3362       break;
3363 
3364     case Primitive::kPrimShort:
3365       switch (input_type) {
3366         case Primitive::kPrimLong:
3367           // Type conversion from long to short is a result of code transformations.
3368         case Primitive::kPrimBoolean:
3369           // Boolean input is a result of code transformations.
3370         case Primitive::kPrimByte:
3371         case Primitive::kPrimInt:
3372         case Primitive::kPrimChar:
3373           // Processing a Dex `int-to-short' instruction.
3374           locations->SetInAt(0, Location::RequiresRegister());
3375           locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3376           break;
3377 
3378         default:
3379           LOG(FATAL) << "Unexpected type conversion from " << input_type
3380                      << " to " << result_type;
3381       }
3382       break;
3383 
3384     case Primitive::kPrimInt:
3385       switch (input_type) {
3386         case Primitive::kPrimLong:
3387           // Processing a Dex `long-to-int' instruction.
3388           locations->SetInAt(0, Location::Any());
3389           locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3390           break;
3391 
3392         case Primitive::kPrimFloat:
3393           // Processing a Dex `float-to-int' instruction.
3394           locations->SetInAt(0, Location::RequiresFpuRegister());
3395           locations->SetOut(Location::RequiresRegister());
3396           locations->AddTemp(Location::RequiresFpuRegister());
3397           break;
3398 
3399         case Primitive::kPrimDouble:
3400           // Processing a Dex `double-to-int' instruction.
3401           locations->SetInAt(0, Location::RequiresFpuRegister());
3402           locations->SetOut(Location::RequiresRegister());
3403           locations->AddTemp(Location::RequiresFpuRegister());
3404           break;
3405 
3406         default:
3407           LOG(FATAL) << "Unexpected type conversion from " << input_type
3408                      << " to " << result_type;
3409       }
3410       break;
3411 
3412     case Primitive::kPrimLong:
3413       switch (input_type) {
3414         case Primitive::kPrimBoolean:
3415           // Boolean input is a result of code transformations.
3416         case Primitive::kPrimByte:
3417         case Primitive::kPrimShort:
3418         case Primitive::kPrimInt:
3419         case Primitive::kPrimChar:
3420           // Processing a Dex `int-to-long' instruction.
3421           locations->SetInAt(0, Location::RequiresRegister());
3422           locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3423           break;
3424 
3425         case Primitive::kPrimFloat: {
3426           // Processing a Dex `float-to-long' instruction.
3427           InvokeRuntimeCallingConvention calling_convention;
3428           locations->SetInAt(0, Location::FpuRegisterLocation(
3429               calling_convention.GetFpuRegisterAt(0)));
3430           locations->SetOut(Location::RegisterPairLocation(R0, R1));
3431           break;
3432         }
3433 
3434         case Primitive::kPrimDouble: {
3435           // Processing a Dex `double-to-long' instruction.
3436           InvokeRuntimeCallingConvention calling_convention;
3437           locations->SetInAt(0, Location::FpuRegisterPairLocation(
3438               calling_convention.GetFpuRegisterAt(0),
3439               calling_convention.GetFpuRegisterAt(1)));
3440           locations->SetOut(Location::RegisterPairLocation(R0, R1));
3441           break;
3442         }
3443 
3444         default:
3445           LOG(FATAL) << "Unexpected type conversion from " << input_type
3446                      << " to " << result_type;
3447       }
3448       break;
3449 
3450     case Primitive::kPrimChar:
3451       switch (input_type) {
3452         case Primitive::kPrimLong:
3453           // Type conversion from long to char is a result of code transformations.
3454         case Primitive::kPrimBoolean:
3455           // Boolean input is a result of code transformations.
3456         case Primitive::kPrimByte:
3457         case Primitive::kPrimShort:
3458         case Primitive::kPrimInt:
3459           // Processing a Dex `int-to-char' instruction.
3460           locations->SetInAt(0, Location::RequiresRegister());
3461           locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3462           break;
3463 
3464         default:
3465           LOG(FATAL) << "Unexpected type conversion from " << input_type
3466                      << " to " << result_type;
3467       }
3468       break;
3469 
3470     case Primitive::kPrimFloat:
3471       switch (input_type) {
3472         case Primitive::kPrimBoolean:
3473           // Boolean input is a result of code transformations.
3474         case Primitive::kPrimByte:
3475         case Primitive::kPrimShort:
3476         case Primitive::kPrimInt:
3477         case Primitive::kPrimChar:
3478           // Processing a Dex `int-to-float' instruction.
3479           locations->SetInAt(0, Location::RequiresRegister());
3480           locations->SetOut(Location::RequiresFpuRegister());
3481           break;
3482 
3483         case Primitive::kPrimLong: {
3484           // Processing a Dex `long-to-float' instruction.
3485           InvokeRuntimeCallingConvention calling_convention;
3486           locations->SetInAt(0, Location::RegisterPairLocation(
3487               calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
3488           locations->SetOut(Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
3489           break;
3490         }
3491 
3492         case Primitive::kPrimDouble:
3493           // Processing a Dex `double-to-float' instruction.
3494           locations->SetInAt(0, Location::RequiresFpuRegister());
3495           locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
3496           break;
3497 
3498         default:
3499           LOG(FATAL) << "Unexpected type conversion from " << input_type
3500                      << " to " << result_type;
3501       };
3502       break;
3503 
3504     case Primitive::kPrimDouble:
3505       switch (input_type) {
3506         case Primitive::kPrimBoolean:
3507           // Boolean input is a result of code transformations.
3508         case Primitive::kPrimByte:
3509         case Primitive::kPrimShort:
3510         case Primitive::kPrimInt:
3511         case Primitive::kPrimChar:
3512           // Processing a Dex `int-to-double' instruction.
3513           locations->SetInAt(0, Location::RequiresRegister());
3514           locations->SetOut(Location::RequiresFpuRegister());
3515           break;
3516 
3517         case Primitive::kPrimLong:
3518           // Processing a Dex `long-to-double' instruction.
3519           locations->SetInAt(0, Location::RequiresRegister());
3520           locations->SetOut(Location::RequiresFpuRegister());
3521           locations->AddTemp(Location::RequiresFpuRegister());
3522           locations->AddTemp(Location::RequiresFpuRegister());
3523           break;
3524 
3525         case Primitive::kPrimFloat:
3526           // Processing a Dex `float-to-double' instruction.
3527           locations->SetInAt(0, Location::RequiresFpuRegister());
3528           locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
3529           break;
3530 
3531         default:
3532           LOG(FATAL) << "Unexpected type conversion from " << input_type
3533                      << " to " << result_type;
3534       };
3535       break;
3536 
3537     default:
3538       LOG(FATAL) << "Unexpected type conversion from " << input_type
3539                  << " to " << result_type;
3540   }
3541 }
3542 
VisitTypeConversion(HTypeConversion * conversion)3543 void InstructionCodeGeneratorARM::VisitTypeConversion(HTypeConversion* conversion) {
3544   LocationSummary* locations = conversion->GetLocations();
3545   Location out = locations->Out();
3546   Location in = locations->InAt(0);
3547   Primitive::Type result_type = conversion->GetResultType();
3548   Primitive::Type input_type = conversion->GetInputType();
3549   DCHECK_NE(result_type, input_type);
3550   switch (result_type) {
3551     case Primitive::kPrimByte:
3552       switch (input_type) {
3553         case Primitive::kPrimLong:
3554           // Type conversion from long to byte is a result of code transformations.
3555           __ sbfx(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>(), 0, 8);
3556           break;
3557         case Primitive::kPrimBoolean:
3558           // Boolean input is a result of code transformations.
3559         case Primitive::kPrimShort:
3560         case Primitive::kPrimInt:
3561         case Primitive::kPrimChar:
3562           // Processing a Dex `int-to-byte' instruction.
3563           __ sbfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 8);
3564           break;
3565 
3566         default:
3567           LOG(FATAL) << "Unexpected type conversion from " << input_type
3568                      << " to " << result_type;
3569       }
3570       break;
3571 
3572     case Primitive::kPrimShort:
3573       switch (input_type) {
3574         case Primitive::kPrimLong:
3575           // Type conversion from long to short is a result of code transformations.
3576           __ sbfx(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>(), 0, 16);
3577           break;
3578         case Primitive::kPrimBoolean:
3579           // Boolean input is a result of code transformations.
3580         case Primitive::kPrimByte:
3581         case Primitive::kPrimInt:
3582         case Primitive::kPrimChar:
3583           // Processing a Dex `int-to-short' instruction.
3584           __ sbfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 16);
3585           break;
3586 
3587         default:
3588           LOG(FATAL) << "Unexpected type conversion from " << input_type
3589                      << " to " << result_type;
3590       }
3591       break;
3592 
3593     case Primitive::kPrimInt:
3594       switch (input_type) {
3595         case Primitive::kPrimLong:
3596           // Processing a Dex `long-to-int' instruction.
3597           DCHECK(out.IsRegister());
3598           if (in.IsRegisterPair()) {
3599             __ Mov(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>());
3600           } else if (in.IsDoubleStackSlot()) {
3601             __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), SP, in.GetStackIndex());
3602           } else {
3603             DCHECK(in.IsConstant());
3604             DCHECK(in.GetConstant()->IsLongConstant());
3605             int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
3606             __ LoadImmediate(out.AsRegister<Register>(), static_cast<int32_t>(value));
3607           }
3608           break;
3609 
3610         case Primitive::kPrimFloat: {
3611           // Processing a Dex `float-to-int' instruction.
3612           SRegister temp = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
3613           __ vcvtis(temp, in.AsFpuRegister<SRegister>());
3614           __ vmovrs(out.AsRegister<Register>(), temp);
3615           break;
3616         }
3617 
3618         case Primitive::kPrimDouble: {
3619           // Processing a Dex `double-to-int' instruction.
3620           SRegister temp_s = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
3621           __ vcvtid(temp_s, FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
3622           __ vmovrs(out.AsRegister<Register>(), temp_s);
3623           break;
3624         }
3625 
3626         default:
3627           LOG(FATAL) << "Unexpected type conversion from " << input_type
3628                      << " to " << result_type;
3629       }
3630       break;
3631 
3632     case Primitive::kPrimLong:
3633       switch (input_type) {
3634         case Primitive::kPrimBoolean:
3635           // Boolean input is a result of code transformations.
3636         case Primitive::kPrimByte:
3637         case Primitive::kPrimShort:
3638         case Primitive::kPrimInt:
3639         case Primitive::kPrimChar:
3640           // Processing a Dex `int-to-long' instruction.
3641           DCHECK(out.IsRegisterPair());
3642           DCHECK(in.IsRegister());
3643           __ Mov(out.AsRegisterPairLow<Register>(), in.AsRegister<Register>());
3644           // Sign extension.
3645           __ Asr(out.AsRegisterPairHigh<Register>(),
3646                  out.AsRegisterPairLow<Register>(),
3647                  31);
3648           break;
3649 
3650         case Primitive::kPrimFloat:
3651           // Processing a Dex `float-to-long' instruction.
3652           codegen_->InvokeRuntime(kQuickF2l, conversion, conversion->GetDexPc());
3653           CheckEntrypointTypes<kQuickF2l, int64_t, float>();
3654           break;
3655 
3656         case Primitive::kPrimDouble:
3657           // Processing a Dex `double-to-long' instruction.
3658           codegen_->InvokeRuntime(kQuickD2l, conversion, conversion->GetDexPc());
3659           CheckEntrypointTypes<kQuickD2l, int64_t, double>();
3660           break;
3661 
3662         default:
3663           LOG(FATAL) << "Unexpected type conversion from " << input_type
3664                      << " to " << result_type;
3665       }
3666       break;
3667 
3668     case Primitive::kPrimChar:
3669       switch (input_type) {
3670         case Primitive::kPrimLong:
3671           // Type conversion from long to char is a result of code transformations.
3672           __ ubfx(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>(), 0, 16);
3673           break;
3674         case Primitive::kPrimBoolean:
3675           // Boolean input is a result of code transformations.
3676         case Primitive::kPrimByte:
3677         case Primitive::kPrimShort:
3678         case Primitive::kPrimInt:
3679           // Processing a Dex `int-to-char' instruction.
3680           __ ubfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 16);
3681           break;
3682 
3683         default:
3684           LOG(FATAL) << "Unexpected type conversion from " << input_type
3685                      << " to " << result_type;
3686       }
3687       break;
3688 
3689     case Primitive::kPrimFloat:
3690       switch (input_type) {
3691         case Primitive::kPrimBoolean:
3692           // Boolean input is a result of code transformations.
3693         case Primitive::kPrimByte:
3694         case Primitive::kPrimShort:
3695         case Primitive::kPrimInt:
3696         case Primitive::kPrimChar: {
3697           // Processing a Dex `int-to-float' instruction.
3698           __ vmovsr(out.AsFpuRegister<SRegister>(), in.AsRegister<Register>());
3699           __ vcvtsi(out.AsFpuRegister<SRegister>(), out.AsFpuRegister<SRegister>());
3700           break;
3701         }
3702 
3703         case Primitive::kPrimLong:
3704           // Processing a Dex `long-to-float' instruction.
3705           codegen_->InvokeRuntime(kQuickL2f, conversion, conversion->GetDexPc());
3706           CheckEntrypointTypes<kQuickL2f, float, int64_t>();
3707           break;
3708 
3709         case Primitive::kPrimDouble:
3710           // Processing a Dex `double-to-float' instruction.
3711           __ vcvtsd(out.AsFpuRegister<SRegister>(),
3712                     FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
3713           break;
3714 
3715         default:
3716           LOG(FATAL) << "Unexpected type conversion from " << input_type
3717                      << " to " << result_type;
3718       };
3719       break;
3720 
3721     case Primitive::kPrimDouble:
3722       switch (input_type) {
3723         case Primitive::kPrimBoolean:
3724           // Boolean input is a result of code transformations.
3725         case Primitive::kPrimByte:
3726         case Primitive::kPrimShort:
3727         case Primitive::kPrimInt:
3728         case Primitive::kPrimChar: {
3729           // Processing a Dex `int-to-double' instruction.
3730           __ vmovsr(out.AsFpuRegisterPairLow<SRegister>(), in.AsRegister<Register>());
3731           __ vcvtdi(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
3732                     out.AsFpuRegisterPairLow<SRegister>());
3733           break;
3734         }
3735 
3736         case Primitive::kPrimLong: {
3737           // Processing a Dex `long-to-double' instruction.
3738           Register low = in.AsRegisterPairLow<Register>();
3739           Register high = in.AsRegisterPairHigh<Register>();
3740           SRegister out_s = out.AsFpuRegisterPairLow<SRegister>();
3741           DRegister out_d = FromLowSToD(out_s);
3742           SRegister temp_s = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
3743           DRegister temp_d = FromLowSToD(temp_s);
3744           SRegister constant_s = locations->GetTemp(1).AsFpuRegisterPairLow<SRegister>();
3745           DRegister constant_d = FromLowSToD(constant_s);
3746 
3747           // temp_d = int-to-double(high)
3748           __ vmovsr(temp_s, high);
3749           __ vcvtdi(temp_d, temp_s);
3750           // constant_d = k2Pow32EncodingForDouble
3751           __ LoadDImmediate(constant_d, bit_cast<double, int64_t>(k2Pow32EncodingForDouble));
3752           // out_d = unsigned-to-double(low)
3753           __ vmovsr(out_s, low);
3754           __ vcvtdu(out_d, out_s);
3755           // out_d += temp_d * constant_d
3756           __ vmlad(out_d, temp_d, constant_d);
3757           break;
3758         }
3759 
3760         case Primitive::kPrimFloat:
3761           // Processing a Dex `float-to-double' instruction.
3762           __ vcvtds(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
3763                     in.AsFpuRegister<SRegister>());
3764           break;
3765 
3766         default:
3767           LOG(FATAL) << "Unexpected type conversion from " << input_type
3768                      << " to " << result_type;
3769       };
3770       break;
3771 
3772     default:
3773       LOG(FATAL) << "Unexpected type conversion from " << input_type
3774                  << " to " << result_type;
3775   }
3776 }
3777 
VisitAdd(HAdd * add)3778 void LocationsBuilderARM::VisitAdd(HAdd* add) {
3779   LocationSummary* locations =
3780       new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
3781   switch (add->GetResultType()) {
3782     case Primitive::kPrimInt: {
3783       locations->SetInAt(0, Location::RequiresRegister());
3784       locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
3785       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3786       break;
3787     }
3788 
3789     case Primitive::kPrimLong: {
3790       locations->SetInAt(0, Location::RequiresRegister());
3791       locations->SetInAt(1, ArmEncodableConstantOrRegister(add->InputAt(1), ADD));
3792       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3793       break;
3794     }
3795 
3796     case Primitive::kPrimFloat:
3797     case Primitive::kPrimDouble: {
3798       locations->SetInAt(0, Location::RequiresFpuRegister());
3799       locations->SetInAt(1, Location::RequiresFpuRegister());
3800       locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
3801       break;
3802     }
3803 
3804     default:
3805       LOG(FATAL) << "Unexpected add type " << add->GetResultType();
3806   }
3807 }
3808 
VisitAdd(HAdd * add)3809 void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) {
3810   LocationSummary* locations = add->GetLocations();
3811   Location out = locations->Out();
3812   Location first = locations->InAt(0);
3813   Location second = locations->InAt(1);
3814   switch (add->GetResultType()) {
3815     case Primitive::kPrimInt:
3816       if (second.IsRegister()) {
3817         __ add(out.AsRegister<Register>(),
3818                first.AsRegister<Register>(),
3819                ShifterOperand(second.AsRegister<Register>()));
3820       } else {
3821         __ AddConstant(out.AsRegister<Register>(),
3822                        first.AsRegister<Register>(),
3823                        second.GetConstant()->AsIntConstant()->GetValue());
3824       }
3825       break;
3826 
3827     case Primitive::kPrimLong: {
3828       if (second.IsConstant()) {
3829         uint64_t value = static_cast<uint64_t>(Int64FromConstant(second.GetConstant()));
3830         GenerateAddLongConst(out, first, value);
3831       } else {
3832         DCHECK(second.IsRegisterPair());
3833         __ adds(out.AsRegisterPairLow<Register>(),
3834                 first.AsRegisterPairLow<Register>(),
3835                 ShifterOperand(second.AsRegisterPairLow<Register>()));
3836         __ adc(out.AsRegisterPairHigh<Register>(),
3837                first.AsRegisterPairHigh<Register>(),
3838                ShifterOperand(second.AsRegisterPairHigh<Register>()));
3839       }
3840       break;
3841     }
3842 
3843     case Primitive::kPrimFloat:
3844       __ vadds(out.AsFpuRegister<SRegister>(),
3845                first.AsFpuRegister<SRegister>(),
3846                second.AsFpuRegister<SRegister>());
3847       break;
3848 
3849     case Primitive::kPrimDouble:
3850       __ vaddd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
3851                FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
3852                FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
3853       break;
3854 
3855     default:
3856       LOG(FATAL) << "Unexpected add type " << add->GetResultType();
3857   }
3858 }
3859 
VisitSub(HSub * sub)3860 void LocationsBuilderARM::VisitSub(HSub* sub) {
3861   LocationSummary* locations =
3862       new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
3863   switch (sub->GetResultType()) {
3864     case Primitive::kPrimInt: {
3865       locations->SetInAt(0, Location::RequiresRegister());
3866       locations->SetInAt(1, Location::RegisterOrConstant(sub->InputAt(1)));
3867       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3868       break;
3869     }
3870 
3871     case Primitive::kPrimLong: {
3872       locations->SetInAt(0, Location::RequiresRegister());
3873       locations->SetInAt(1, ArmEncodableConstantOrRegister(sub->InputAt(1), SUB));
3874       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3875       break;
3876     }
3877     case Primitive::kPrimFloat:
3878     case Primitive::kPrimDouble: {
3879       locations->SetInAt(0, Location::RequiresFpuRegister());
3880       locations->SetInAt(1, Location::RequiresFpuRegister());
3881       locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
3882       break;
3883     }
3884     default:
3885       LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
3886   }
3887 }
3888 
VisitSub(HSub * sub)3889 void InstructionCodeGeneratorARM::VisitSub(HSub* sub) {
3890   LocationSummary* locations = sub->GetLocations();
3891   Location out = locations->Out();
3892   Location first = locations->InAt(0);
3893   Location second = locations->InAt(1);
3894   switch (sub->GetResultType()) {
3895     case Primitive::kPrimInt: {
3896       if (second.IsRegister()) {
3897         __ sub(out.AsRegister<Register>(),
3898                first.AsRegister<Register>(),
3899                ShifterOperand(second.AsRegister<Register>()));
3900       } else {
3901         __ AddConstant(out.AsRegister<Register>(),
3902                        first.AsRegister<Register>(),
3903                        -second.GetConstant()->AsIntConstant()->GetValue());
3904       }
3905       break;
3906     }
3907 
3908     case Primitive::kPrimLong: {
3909       if (second.IsConstant()) {
3910         uint64_t value = static_cast<uint64_t>(Int64FromConstant(second.GetConstant()));
3911         GenerateAddLongConst(out, first, -value);
3912       } else {
3913         DCHECK(second.IsRegisterPair());
3914         __ subs(out.AsRegisterPairLow<Register>(),
3915                 first.AsRegisterPairLow<Register>(),
3916                 ShifterOperand(second.AsRegisterPairLow<Register>()));
3917         __ sbc(out.AsRegisterPairHigh<Register>(),
3918                first.AsRegisterPairHigh<Register>(),
3919                ShifterOperand(second.AsRegisterPairHigh<Register>()));
3920       }
3921       break;
3922     }
3923 
3924     case Primitive::kPrimFloat: {
3925       __ vsubs(out.AsFpuRegister<SRegister>(),
3926                first.AsFpuRegister<SRegister>(),
3927                second.AsFpuRegister<SRegister>());
3928       break;
3929     }
3930 
3931     case Primitive::kPrimDouble: {
3932       __ vsubd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
3933                FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
3934                FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
3935       break;
3936     }
3937 
3938 
3939     default:
3940       LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
3941   }
3942 }
3943 
VisitMul(HMul * mul)3944 void LocationsBuilderARM::VisitMul(HMul* mul) {
3945   LocationSummary* locations =
3946       new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
3947   switch (mul->GetResultType()) {
3948     case Primitive::kPrimInt:
3949     case Primitive::kPrimLong:  {
3950       locations->SetInAt(0, Location::RequiresRegister());
3951       locations->SetInAt(1, Location::RequiresRegister());
3952       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3953       break;
3954     }
3955 
3956     case Primitive::kPrimFloat:
3957     case Primitive::kPrimDouble: {
3958       locations->SetInAt(0, Location::RequiresFpuRegister());
3959       locations->SetInAt(1, Location::RequiresFpuRegister());
3960       locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
3961       break;
3962     }
3963 
3964     default:
3965       LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
3966   }
3967 }
3968 
VisitMul(HMul * mul)3969 void InstructionCodeGeneratorARM::VisitMul(HMul* mul) {
3970   LocationSummary* locations = mul->GetLocations();
3971   Location out = locations->Out();
3972   Location first = locations->InAt(0);
3973   Location second = locations->InAt(1);
3974   switch (mul->GetResultType()) {
3975     case Primitive::kPrimInt: {
3976       __ mul(out.AsRegister<Register>(),
3977              first.AsRegister<Register>(),
3978              second.AsRegister<Register>());
3979       break;
3980     }
3981     case Primitive::kPrimLong: {
3982       Register out_hi = out.AsRegisterPairHigh<Register>();
3983       Register out_lo = out.AsRegisterPairLow<Register>();
3984       Register in1_hi = first.AsRegisterPairHigh<Register>();
3985       Register in1_lo = first.AsRegisterPairLow<Register>();
3986       Register in2_hi = second.AsRegisterPairHigh<Register>();
3987       Register in2_lo = second.AsRegisterPairLow<Register>();
3988 
3989       // Extra checks to protect caused by the existence of R1_R2.
3990       // The algorithm is wrong if out.hi is either in1.lo or in2.lo:
3991       // (e.g. in1=r0_r1, in2=r2_r3 and out=r1_r2);
3992       DCHECK_NE(out_hi, in1_lo);
3993       DCHECK_NE(out_hi, in2_lo);
3994 
3995       // input: in1 - 64 bits, in2 - 64 bits
3996       // output: out
3997       // formula: out.hi : out.lo = (in1.lo * in2.hi + in1.hi * in2.lo)* 2^32 + in1.lo * in2.lo
3998       // parts: out.hi = in1.lo * in2.hi + in1.hi * in2.lo + (in1.lo * in2.lo)[63:32]
3999       // parts: out.lo = (in1.lo * in2.lo)[31:0]
4000 
4001       // IP <- in1.lo * in2.hi
4002       __ mul(IP, in1_lo, in2_hi);
4003       // out.hi <- in1.lo * in2.hi + in1.hi * in2.lo
4004       __ mla(out_hi, in1_hi, in2_lo, IP);
4005       // out.lo <- (in1.lo * in2.lo)[31:0];
4006       __ umull(out_lo, IP, in1_lo, in2_lo);
4007       // out.hi <- in2.hi * in1.lo +  in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
4008       __ add(out_hi, out_hi, ShifterOperand(IP));
4009       break;
4010     }
4011 
4012     case Primitive::kPrimFloat: {
4013       __ vmuls(out.AsFpuRegister<SRegister>(),
4014                first.AsFpuRegister<SRegister>(),
4015                second.AsFpuRegister<SRegister>());
4016       break;
4017     }
4018 
4019     case Primitive::kPrimDouble: {
4020       __ vmuld(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
4021                FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
4022                FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
4023       break;
4024     }
4025 
4026     default:
4027       LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
4028   }
4029 }
4030 
DivRemOneOrMinusOne(HBinaryOperation * instruction)4031 void InstructionCodeGeneratorARM::DivRemOneOrMinusOne(HBinaryOperation* instruction) {
4032   DCHECK(instruction->IsDiv() || instruction->IsRem());
4033   DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
4034 
4035   LocationSummary* locations = instruction->GetLocations();
4036   Location second = locations->InAt(1);
4037   DCHECK(second.IsConstant());
4038 
4039   Register out = locations->Out().AsRegister<Register>();
4040   Register dividend = locations->InAt(0).AsRegister<Register>();
4041   int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
4042   DCHECK(imm == 1 || imm == -1);
4043 
4044   if (instruction->IsRem()) {
4045     __ LoadImmediate(out, 0);
4046   } else {
4047     if (imm == 1) {
4048       __ Mov(out, dividend);
4049     } else {
4050       __ rsb(out, dividend, ShifterOperand(0));
4051     }
4052   }
4053 }
4054 
DivRemByPowerOfTwo(HBinaryOperation * instruction)4055 void InstructionCodeGeneratorARM::DivRemByPowerOfTwo(HBinaryOperation* instruction) {
4056   DCHECK(instruction->IsDiv() || instruction->IsRem());
4057   DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
4058 
4059   LocationSummary* locations = instruction->GetLocations();
4060   Location second = locations->InAt(1);
4061   DCHECK(second.IsConstant());
4062 
4063   Register out = locations->Out().AsRegister<Register>();
4064   Register dividend = locations->InAt(0).AsRegister<Register>();
4065   Register temp = locations->GetTemp(0).AsRegister<Register>();
4066   int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
4067   uint32_t abs_imm = static_cast<uint32_t>(AbsOrMin(imm));
4068   int ctz_imm = CTZ(abs_imm);
4069 
4070   if (ctz_imm == 1) {
4071     __ Lsr(temp, dividend, 32 - ctz_imm);
4072   } else {
4073     __ Asr(temp, dividend, 31);
4074     __ Lsr(temp, temp, 32 - ctz_imm);
4075   }
4076   __ add(out, temp, ShifterOperand(dividend));
4077 
4078   if (instruction->IsDiv()) {
4079     __ Asr(out, out, ctz_imm);
4080     if (imm < 0) {
4081       __ rsb(out, out, ShifterOperand(0));
4082     }
4083   } else {
4084     __ ubfx(out, out, 0, ctz_imm);
4085     __ sub(out, out, ShifterOperand(temp));
4086   }
4087 }
4088 
GenerateDivRemWithAnyConstant(HBinaryOperation * instruction)4089 void InstructionCodeGeneratorARM::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) {
4090   DCHECK(instruction->IsDiv() || instruction->IsRem());
4091   DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
4092 
4093   LocationSummary* locations = instruction->GetLocations();
4094   Location second = locations->InAt(1);
4095   DCHECK(second.IsConstant());
4096 
4097   Register out = locations->Out().AsRegister<Register>();
4098   Register dividend = locations->InAt(0).AsRegister<Register>();
4099   Register temp1 = locations->GetTemp(0).AsRegister<Register>();
4100   Register temp2 = locations->GetTemp(1).AsRegister<Register>();
4101   int64_t imm = second.GetConstant()->AsIntConstant()->GetValue();
4102 
4103   int64_t magic;
4104   int shift;
4105   CalculateMagicAndShiftForDivRem(imm, false /* is_long */, &magic, &shift);
4106 
4107   __ LoadImmediate(temp1, magic);
4108   __ smull(temp2, temp1, dividend, temp1);
4109 
4110   if (imm > 0 && magic < 0) {
4111     __ add(temp1, temp1, ShifterOperand(dividend));
4112   } else if (imm < 0 && magic > 0) {
4113     __ sub(temp1, temp1, ShifterOperand(dividend));
4114   }
4115 
4116   if (shift != 0) {
4117     __ Asr(temp1, temp1, shift);
4118   }
4119 
4120   if (instruction->IsDiv()) {
4121     __ sub(out, temp1, ShifterOperand(temp1, ASR, 31));
4122   } else {
4123     __ sub(temp1, temp1, ShifterOperand(temp1, ASR, 31));
4124     // TODO: Strength reduction for mls.
4125     __ LoadImmediate(temp2, imm);
4126     __ mls(out, temp1, temp2, dividend);
4127   }
4128 }
4129 
GenerateDivRemConstantIntegral(HBinaryOperation * instruction)4130 void InstructionCodeGeneratorARM::GenerateDivRemConstantIntegral(HBinaryOperation* instruction) {
4131   DCHECK(instruction->IsDiv() || instruction->IsRem());
4132   DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
4133 
4134   LocationSummary* locations = instruction->GetLocations();
4135   Location second = locations->InAt(1);
4136   DCHECK(second.IsConstant());
4137 
4138   int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
4139   if (imm == 0) {
4140     // Do not generate anything. DivZeroCheck would prevent any code to be executed.
4141   } else if (imm == 1 || imm == -1) {
4142     DivRemOneOrMinusOne(instruction);
4143   } else if (IsPowerOfTwo(AbsOrMin(imm))) {
4144     DivRemByPowerOfTwo(instruction);
4145   } else {
4146     DCHECK(imm <= -2 || imm >= 2);
4147     GenerateDivRemWithAnyConstant(instruction);
4148   }
4149 }
4150 
VisitDiv(HDiv * div)4151 void LocationsBuilderARM::VisitDiv(HDiv* div) {
4152   LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
4153   if (div->GetResultType() == Primitive::kPrimLong) {
4154     // pLdiv runtime call.
4155     call_kind = LocationSummary::kCallOnMainOnly;
4156   } else if (div->GetResultType() == Primitive::kPrimInt && div->InputAt(1)->IsConstant()) {
4157     // sdiv will be replaced by other instruction sequence.
4158   } else if (div->GetResultType() == Primitive::kPrimInt &&
4159              !codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
4160     // pIdivmod runtime call.
4161     call_kind = LocationSummary::kCallOnMainOnly;
4162   }
4163 
4164   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(div, call_kind);
4165 
4166   switch (div->GetResultType()) {
4167     case Primitive::kPrimInt: {
4168       if (div->InputAt(1)->IsConstant()) {
4169         locations->SetInAt(0, Location::RequiresRegister());
4170         locations->SetInAt(1, Location::ConstantLocation(div->InputAt(1)->AsConstant()));
4171         locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
4172         int32_t value = div->InputAt(1)->AsIntConstant()->GetValue();
4173         if (value == 1 || value == 0 || value == -1) {
4174           // No temp register required.
4175         } else {
4176           locations->AddTemp(Location::RequiresRegister());
4177           if (!IsPowerOfTwo(AbsOrMin(value))) {
4178             locations->AddTemp(Location::RequiresRegister());
4179           }
4180         }
4181       } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
4182         locations->SetInAt(0, Location::RequiresRegister());
4183         locations->SetInAt(1, Location::RequiresRegister());
4184         locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
4185       } else {
4186         InvokeRuntimeCallingConvention calling_convention;
4187         locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4188         locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
4189         // Note: divmod will compute both the quotient and the remainder as the pair R0 and R1, but
4190         //       we only need the former.
4191         locations->SetOut(Location::RegisterLocation(R0));
4192       }
4193       break;
4194     }
4195     case Primitive::kPrimLong: {
4196       InvokeRuntimeCallingConvention calling_convention;
4197       locations->SetInAt(0, Location::RegisterPairLocation(
4198           calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
4199       locations->SetInAt(1, Location::RegisterPairLocation(
4200           calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
4201       locations->SetOut(Location::RegisterPairLocation(R0, R1));
4202       break;
4203     }
4204     case Primitive::kPrimFloat:
4205     case Primitive::kPrimDouble: {
4206       locations->SetInAt(0, Location::RequiresFpuRegister());
4207       locations->SetInAt(1, Location::RequiresFpuRegister());
4208       locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
4209       break;
4210     }
4211 
4212     default:
4213       LOG(FATAL) << "Unexpected div type " << div->GetResultType();
4214   }
4215 }
4216 
VisitDiv(HDiv * div)4217 void InstructionCodeGeneratorARM::VisitDiv(HDiv* div) {
4218   LocationSummary* locations = div->GetLocations();
4219   Location out = locations->Out();
4220   Location first = locations->InAt(0);
4221   Location second = locations->InAt(1);
4222 
4223   switch (div->GetResultType()) {
4224     case Primitive::kPrimInt: {
4225       if (second.IsConstant()) {
4226         GenerateDivRemConstantIntegral(div);
4227       } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
4228         __ sdiv(out.AsRegister<Register>(),
4229                 first.AsRegister<Register>(),
4230                 second.AsRegister<Register>());
4231       } else {
4232         InvokeRuntimeCallingConvention calling_convention;
4233         DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegister<Register>());
4234         DCHECK_EQ(calling_convention.GetRegisterAt(1), second.AsRegister<Register>());
4235         DCHECK_EQ(R0, out.AsRegister<Register>());
4236 
4237         codegen_->InvokeRuntime(kQuickIdivmod, div, div->GetDexPc());
4238         CheckEntrypointTypes<kQuickIdivmod, int32_t, int32_t, int32_t>();
4239       }
4240       break;
4241     }
4242 
4243     case Primitive::kPrimLong: {
4244       InvokeRuntimeCallingConvention calling_convention;
4245       DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegisterPairLow<Register>());
4246       DCHECK_EQ(calling_convention.GetRegisterAt(1), first.AsRegisterPairHigh<Register>());
4247       DCHECK_EQ(calling_convention.GetRegisterAt(2), second.AsRegisterPairLow<Register>());
4248       DCHECK_EQ(calling_convention.GetRegisterAt(3), second.AsRegisterPairHigh<Register>());
4249       DCHECK_EQ(R0, out.AsRegisterPairLow<Register>());
4250       DCHECK_EQ(R1, out.AsRegisterPairHigh<Register>());
4251 
4252       codegen_->InvokeRuntime(kQuickLdiv, div, div->GetDexPc());
4253       CheckEntrypointTypes<kQuickLdiv, int64_t, int64_t, int64_t>();
4254       break;
4255     }
4256 
4257     case Primitive::kPrimFloat: {
4258       __ vdivs(out.AsFpuRegister<SRegister>(),
4259                first.AsFpuRegister<SRegister>(),
4260                second.AsFpuRegister<SRegister>());
4261       break;
4262     }
4263 
4264     case Primitive::kPrimDouble: {
4265       __ vdivd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
4266                FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
4267                FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
4268       break;
4269     }
4270 
4271     default:
4272       LOG(FATAL) << "Unexpected div type " << div->GetResultType();
4273   }
4274 }
4275 
VisitRem(HRem * rem)4276 void LocationsBuilderARM::VisitRem(HRem* rem) {
4277   Primitive::Type type = rem->GetResultType();
4278 
4279   // Most remainders are implemented in the runtime.
4280   LocationSummary::CallKind call_kind = LocationSummary::kCallOnMainOnly;
4281   if (rem->GetResultType() == Primitive::kPrimInt && rem->InputAt(1)->IsConstant()) {
4282     // sdiv will be replaced by other instruction sequence.
4283     call_kind = LocationSummary::kNoCall;
4284   } else if ((rem->GetResultType() == Primitive::kPrimInt)
4285              && codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
4286     // Have hardware divide instruction for int, do it with three instructions.
4287     call_kind = LocationSummary::kNoCall;
4288   }
4289 
4290   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind);
4291 
4292   switch (type) {
4293     case Primitive::kPrimInt: {
4294       if (rem->InputAt(1)->IsConstant()) {
4295         locations->SetInAt(0, Location::RequiresRegister());
4296         locations->SetInAt(1, Location::ConstantLocation(rem->InputAt(1)->AsConstant()));
4297         locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
4298         int32_t value = rem->InputAt(1)->AsIntConstant()->GetValue();
4299         if (value == 1 || value == 0 || value == -1) {
4300           // No temp register required.
4301         } else {
4302           locations->AddTemp(Location::RequiresRegister());
4303           if (!IsPowerOfTwo(AbsOrMin(value))) {
4304             locations->AddTemp(Location::RequiresRegister());
4305           }
4306         }
4307       } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
4308         locations->SetInAt(0, Location::RequiresRegister());
4309         locations->SetInAt(1, Location::RequiresRegister());
4310         locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
4311         locations->AddTemp(Location::RequiresRegister());
4312       } else {
4313         InvokeRuntimeCallingConvention calling_convention;
4314         locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4315         locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
4316         // Note: divmod will compute both the quotient and the remainder as the pair R0 and R1, but
4317         //       we only need the latter.
4318         locations->SetOut(Location::RegisterLocation(R1));
4319       }
4320       break;
4321     }
4322     case Primitive::kPrimLong: {
4323       InvokeRuntimeCallingConvention calling_convention;
4324       locations->SetInAt(0, Location::RegisterPairLocation(
4325           calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
4326       locations->SetInAt(1, Location::RegisterPairLocation(
4327           calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
4328       // The runtime helper puts the output in R2,R3.
4329       locations->SetOut(Location::RegisterPairLocation(R2, R3));
4330       break;
4331     }
4332     case Primitive::kPrimFloat: {
4333       InvokeRuntimeCallingConvention calling_convention;
4334       locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
4335       locations->SetInAt(1, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(1)));
4336       locations->SetOut(Location::FpuRegisterLocation(S0));
4337       break;
4338     }
4339 
4340     case Primitive::kPrimDouble: {
4341       InvokeRuntimeCallingConvention calling_convention;
4342       locations->SetInAt(0, Location::FpuRegisterPairLocation(
4343           calling_convention.GetFpuRegisterAt(0), calling_convention.GetFpuRegisterAt(1)));
4344       locations->SetInAt(1, Location::FpuRegisterPairLocation(
4345           calling_convention.GetFpuRegisterAt(2), calling_convention.GetFpuRegisterAt(3)));
4346       locations->SetOut(Location::Location::FpuRegisterPairLocation(S0, S1));
4347       break;
4348     }
4349 
4350     default:
4351       LOG(FATAL) << "Unexpected rem type " << type;
4352   }
4353 }
4354 
VisitRem(HRem * rem)4355 void InstructionCodeGeneratorARM::VisitRem(HRem* rem) {
4356   LocationSummary* locations = rem->GetLocations();
4357   Location out = locations->Out();
4358   Location first = locations->InAt(0);
4359   Location second = locations->InAt(1);
4360 
4361   Primitive::Type type = rem->GetResultType();
4362   switch (type) {
4363     case Primitive::kPrimInt: {
4364         if (second.IsConstant()) {
4365           GenerateDivRemConstantIntegral(rem);
4366         } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
4367         Register reg1 = first.AsRegister<Register>();
4368         Register reg2 = second.AsRegister<Register>();
4369         Register temp = locations->GetTemp(0).AsRegister<Register>();
4370 
4371         // temp = reg1 / reg2  (integer division)
4372         // dest = reg1 - temp * reg2
4373         __ sdiv(temp, reg1, reg2);
4374         __ mls(out.AsRegister<Register>(), temp, reg2, reg1);
4375       } else {
4376         InvokeRuntimeCallingConvention calling_convention;
4377         DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegister<Register>());
4378         DCHECK_EQ(calling_convention.GetRegisterAt(1), second.AsRegister<Register>());
4379         DCHECK_EQ(R1, out.AsRegister<Register>());
4380 
4381         codegen_->InvokeRuntime(kQuickIdivmod, rem, rem->GetDexPc());
4382         CheckEntrypointTypes<kQuickIdivmod, int32_t, int32_t, int32_t>();
4383       }
4384       break;
4385     }
4386 
4387     case Primitive::kPrimLong: {
4388       codegen_->InvokeRuntime(kQuickLmod, rem, rem->GetDexPc());
4389         CheckEntrypointTypes<kQuickLmod, int64_t, int64_t, int64_t>();
4390       break;
4391     }
4392 
4393     case Primitive::kPrimFloat: {
4394       codegen_->InvokeRuntime(kQuickFmodf, rem, rem->GetDexPc());
4395       CheckEntrypointTypes<kQuickFmodf, float, float, float>();
4396       break;
4397     }
4398 
4399     case Primitive::kPrimDouble: {
4400       codegen_->InvokeRuntime(kQuickFmod, rem, rem->GetDexPc());
4401       CheckEntrypointTypes<kQuickFmod, double, double, double>();
4402       break;
4403     }
4404 
4405     default:
4406       LOG(FATAL) << "Unexpected rem type " << type;
4407   }
4408 }
4409 
VisitDivZeroCheck(HDivZeroCheck * instruction)4410 void LocationsBuilderARM::VisitDivZeroCheck(HDivZeroCheck* instruction) {
4411   LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction);
4412   locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
4413 }
4414 
VisitDivZeroCheck(HDivZeroCheck * instruction)4415 void InstructionCodeGeneratorARM::VisitDivZeroCheck(HDivZeroCheck* instruction) {
4416   SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) DivZeroCheckSlowPathARM(instruction);
4417   codegen_->AddSlowPath(slow_path);
4418 
4419   LocationSummary* locations = instruction->GetLocations();
4420   Location value = locations->InAt(0);
4421 
4422   switch (instruction->GetType()) {
4423     case Primitive::kPrimBoolean:
4424     case Primitive::kPrimByte:
4425     case Primitive::kPrimChar:
4426     case Primitive::kPrimShort:
4427     case Primitive::kPrimInt: {
4428       if (value.IsRegister()) {
4429         __ CompareAndBranchIfZero(value.AsRegister<Register>(), slow_path->GetEntryLabel());
4430       } else {
4431         DCHECK(value.IsConstant()) << value;
4432         if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
4433           __ b(slow_path->GetEntryLabel());
4434         }
4435       }
4436       break;
4437     }
4438     case Primitive::kPrimLong: {
4439       if (value.IsRegisterPair()) {
4440         __ orrs(IP,
4441                 value.AsRegisterPairLow<Register>(),
4442                 ShifterOperand(value.AsRegisterPairHigh<Register>()));
4443         __ b(slow_path->GetEntryLabel(), EQ);
4444       } else {
4445         DCHECK(value.IsConstant()) << value;
4446         if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
4447           __ b(slow_path->GetEntryLabel());
4448         }
4449       }
4450       break;
4451     default:
4452       LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
4453     }
4454   }
4455 }
4456 
HandleIntegerRotate(LocationSummary * locations)4457 void InstructionCodeGeneratorARM::HandleIntegerRotate(LocationSummary* locations) {
4458   Register in = locations->InAt(0).AsRegister<Register>();
4459   Location rhs = locations->InAt(1);
4460   Register out = locations->Out().AsRegister<Register>();
4461 
4462   if (rhs.IsConstant()) {
4463     // Arm32 and Thumb2 assemblers require a rotation on the interval [1,31],
4464     // so map all rotations to a +ve. equivalent in that range.
4465     // (e.g. left *or* right by -2 bits == 30 bits in the same direction.)
4466     uint32_t rot = CodeGenerator::GetInt32ValueOf(rhs.GetConstant()) & 0x1F;
4467     if (rot) {
4468       // Rotate, mapping left rotations to right equivalents if necessary.
4469       // (e.g. left by 2 bits == right by 30.)
4470       __ Ror(out, in, rot);
4471     } else if (out != in) {
4472       __ Mov(out, in);
4473     }
4474   } else {
4475     __ Ror(out, in, rhs.AsRegister<Register>());
4476   }
4477 }
4478 
4479 // Gain some speed by mapping all Long rotates onto equivalent pairs of Integer
4480 // rotates by swapping input regs (effectively rotating by the first 32-bits of
4481 // a larger rotation) or flipping direction (thus treating larger right/left
4482 // rotations as sub-word sized rotations in the other direction) as appropriate.
HandleLongRotate(HRor * ror)4483 void InstructionCodeGeneratorARM::HandleLongRotate(HRor* ror) {
4484   LocationSummary* locations = ror->GetLocations();
4485   Register in_reg_lo = locations->InAt(0).AsRegisterPairLow<Register>();
4486   Register in_reg_hi = locations->InAt(0).AsRegisterPairHigh<Register>();
4487   Location rhs = locations->InAt(1);
4488   Register out_reg_lo = locations->Out().AsRegisterPairLow<Register>();
4489   Register out_reg_hi = locations->Out().AsRegisterPairHigh<Register>();
4490 
4491   if (rhs.IsConstant()) {
4492     uint64_t rot = CodeGenerator::GetInt64ValueOf(rhs.GetConstant());
4493     // Map all rotations to +ve. equivalents on the interval [0,63].
4494     rot &= kMaxLongShiftDistance;
4495     // For rotates over a word in size, 'pre-rotate' by 32-bits to keep rotate
4496     // logic below to a simple pair of binary orr.
4497     // (e.g. 34 bits == in_reg swap + 2 bits right.)
4498     if (rot >= kArmBitsPerWord) {
4499       rot -= kArmBitsPerWord;
4500       std::swap(in_reg_hi, in_reg_lo);
4501     }
4502     // Rotate, or mov to out for zero or word size rotations.
4503     if (rot != 0u) {
4504       __ Lsr(out_reg_hi, in_reg_hi, rot);
4505       __ orr(out_reg_hi, out_reg_hi, ShifterOperand(in_reg_lo, arm::LSL, kArmBitsPerWord - rot));
4506       __ Lsr(out_reg_lo, in_reg_lo, rot);
4507       __ orr(out_reg_lo, out_reg_lo, ShifterOperand(in_reg_hi, arm::LSL, kArmBitsPerWord - rot));
4508     } else {
4509       __ Mov(out_reg_lo, in_reg_lo);
4510       __ Mov(out_reg_hi, in_reg_hi);
4511     }
4512   } else {
4513     Register shift_right = locations->GetTemp(0).AsRegister<Register>();
4514     Register shift_left = locations->GetTemp(1).AsRegister<Register>();
4515     Label end;
4516     Label shift_by_32_plus_shift_right;
4517     Label* final_label = codegen_->GetFinalLabel(ror, &end);
4518 
4519     __ and_(shift_right, rhs.AsRegister<Register>(), ShifterOperand(0x1F));
4520     __ Lsrs(shift_left, rhs.AsRegister<Register>(), 6);
4521     __ rsb(shift_left, shift_right, ShifterOperand(kArmBitsPerWord), AL, kCcKeep);
4522     __ b(&shift_by_32_plus_shift_right, CC);
4523 
4524     // out_reg_hi = (reg_hi << shift_left) | (reg_lo >> shift_right).
4525     // out_reg_lo = (reg_lo << shift_left) | (reg_hi >> shift_right).
4526     __ Lsl(out_reg_hi, in_reg_hi, shift_left);
4527     __ Lsr(out_reg_lo, in_reg_lo, shift_right);
4528     __ add(out_reg_hi, out_reg_hi, ShifterOperand(out_reg_lo));
4529     __ Lsl(out_reg_lo, in_reg_lo, shift_left);
4530     __ Lsr(shift_left, in_reg_hi, shift_right);
4531     __ add(out_reg_lo, out_reg_lo, ShifterOperand(shift_left));
4532     __ b(final_label);
4533 
4534     __ Bind(&shift_by_32_plus_shift_right);  // Shift by 32+shift_right.
4535     // out_reg_hi = (reg_hi >> shift_right) | (reg_lo << shift_left).
4536     // out_reg_lo = (reg_lo >> shift_right) | (reg_hi << shift_left).
4537     __ Lsr(out_reg_hi, in_reg_hi, shift_right);
4538     __ Lsl(out_reg_lo, in_reg_lo, shift_left);
4539     __ add(out_reg_hi, out_reg_hi, ShifterOperand(out_reg_lo));
4540     __ Lsr(out_reg_lo, in_reg_lo, shift_right);
4541     __ Lsl(shift_right, in_reg_hi, shift_left);
4542     __ add(out_reg_lo, out_reg_lo, ShifterOperand(shift_right));
4543 
4544     if (end.IsLinked()) {
4545       __ Bind(&end);
4546     }
4547   }
4548 }
4549 
VisitRor(HRor * ror)4550 void LocationsBuilderARM::VisitRor(HRor* ror) {
4551   LocationSummary* locations =
4552       new (GetGraph()->GetArena()) LocationSummary(ror, LocationSummary::kNoCall);
4553   switch (ror->GetResultType()) {
4554     case Primitive::kPrimInt: {
4555       locations->SetInAt(0, Location::RequiresRegister());
4556       locations->SetInAt(1, Location::RegisterOrConstant(ror->InputAt(1)));
4557       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
4558       break;
4559     }
4560     case Primitive::kPrimLong: {
4561       locations->SetInAt(0, Location::RequiresRegister());
4562       if (ror->InputAt(1)->IsConstant()) {
4563         locations->SetInAt(1, Location::ConstantLocation(ror->InputAt(1)->AsConstant()));
4564       } else {
4565         locations->SetInAt(1, Location::RequiresRegister());
4566         locations->AddTemp(Location::RequiresRegister());
4567         locations->AddTemp(Location::RequiresRegister());
4568       }
4569       locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
4570       break;
4571     }
4572     default:
4573       LOG(FATAL) << "Unexpected operation type " << ror->GetResultType();
4574   }
4575 }
4576 
VisitRor(HRor * ror)4577 void InstructionCodeGeneratorARM::VisitRor(HRor* ror) {
4578   LocationSummary* locations = ror->GetLocations();
4579   Primitive::Type type = ror->GetResultType();
4580   switch (type) {
4581     case Primitive::kPrimInt: {
4582       HandleIntegerRotate(locations);
4583       break;
4584     }
4585     case Primitive::kPrimLong: {
4586       HandleLongRotate(ror);
4587       break;
4588     }
4589     default:
4590       LOG(FATAL) << "Unexpected operation type " << type;
4591       UNREACHABLE();
4592   }
4593 }
4594 
HandleShift(HBinaryOperation * op)4595 void LocationsBuilderARM::HandleShift(HBinaryOperation* op) {
4596   DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
4597 
4598   LocationSummary* locations =
4599       new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
4600 
4601   switch (op->GetResultType()) {
4602     case Primitive::kPrimInt: {
4603       locations->SetInAt(0, Location::RequiresRegister());
4604       if (op->InputAt(1)->IsConstant()) {
4605         locations->SetInAt(1, Location::ConstantLocation(op->InputAt(1)->AsConstant()));
4606         locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
4607       } else {
4608         locations->SetInAt(1, Location::RequiresRegister());
4609         // Make the output overlap, as it will be used to hold the masked
4610         // second input.
4611         locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
4612       }
4613       break;
4614     }
4615     case Primitive::kPrimLong: {
4616       locations->SetInAt(0, Location::RequiresRegister());
4617       if (op->InputAt(1)->IsConstant()) {
4618         locations->SetInAt(1, Location::ConstantLocation(op->InputAt(1)->AsConstant()));
4619         // For simplicity, use kOutputOverlap even though we only require that low registers
4620         // don't clash with high registers which the register allocator currently guarantees.
4621         locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
4622       } else {
4623         locations->SetInAt(1, Location::RequiresRegister());
4624         locations->AddTemp(Location::RequiresRegister());
4625         locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
4626       }
4627       break;
4628     }
4629     default:
4630       LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
4631   }
4632 }
4633 
HandleShift(HBinaryOperation * op)4634 void InstructionCodeGeneratorARM::HandleShift(HBinaryOperation* op) {
4635   DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
4636 
4637   LocationSummary* locations = op->GetLocations();
4638   Location out = locations->Out();
4639   Location first = locations->InAt(0);
4640   Location second = locations->InAt(1);
4641 
4642   Primitive::Type type = op->GetResultType();
4643   switch (type) {
4644     case Primitive::kPrimInt: {
4645       Register out_reg = out.AsRegister<Register>();
4646       Register first_reg = first.AsRegister<Register>();
4647       if (second.IsRegister()) {
4648         Register second_reg = second.AsRegister<Register>();
4649         // ARM doesn't mask the shift count so we need to do it ourselves.
4650         __ and_(out_reg, second_reg, ShifterOperand(kMaxIntShiftDistance));
4651         if (op->IsShl()) {
4652           __ Lsl(out_reg, first_reg, out_reg);
4653         } else if (op->IsShr()) {
4654           __ Asr(out_reg, first_reg, out_reg);
4655         } else {
4656           __ Lsr(out_reg, first_reg, out_reg);
4657         }
4658       } else {
4659         int32_t cst = second.GetConstant()->AsIntConstant()->GetValue();
4660         uint32_t shift_value = cst & kMaxIntShiftDistance;
4661         if (shift_value == 0) {  // ARM does not support shifting with 0 immediate.
4662           __ Mov(out_reg, first_reg);
4663         } else if (op->IsShl()) {
4664           __ Lsl(out_reg, first_reg, shift_value);
4665         } else if (op->IsShr()) {
4666           __ Asr(out_reg, first_reg, shift_value);
4667         } else {
4668           __ Lsr(out_reg, first_reg, shift_value);
4669         }
4670       }
4671       break;
4672     }
4673     case Primitive::kPrimLong: {
4674       Register o_h = out.AsRegisterPairHigh<Register>();
4675       Register o_l = out.AsRegisterPairLow<Register>();
4676 
4677       Register high = first.AsRegisterPairHigh<Register>();
4678       Register low = first.AsRegisterPairLow<Register>();
4679 
4680       if (second.IsRegister()) {
4681         Register temp = locations->GetTemp(0).AsRegister<Register>();
4682 
4683         Register second_reg = second.AsRegister<Register>();
4684 
4685         if (op->IsShl()) {
4686           __ and_(o_l, second_reg, ShifterOperand(kMaxLongShiftDistance));
4687           // Shift the high part
4688           __ Lsl(o_h, high, o_l);
4689           // Shift the low part and `or` what overflew on the high part
4690           __ rsb(temp, o_l, ShifterOperand(kArmBitsPerWord));
4691           __ Lsr(temp, low, temp);
4692           __ orr(o_h, o_h, ShifterOperand(temp));
4693           // If the shift is > 32 bits, override the high part
4694           __ subs(temp, o_l, ShifterOperand(kArmBitsPerWord));
4695           __ it(PL);
4696           __ Lsl(o_h, low, temp, PL);
4697           // Shift the low part
4698           __ Lsl(o_l, low, o_l);
4699         } else if (op->IsShr()) {
4700           __ and_(o_h, second_reg, ShifterOperand(kMaxLongShiftDistance));
4701           // Shift the low part
4702           __ Lsr(o_l, low, o_h);
4703           // Shift the high part and `or` what underflew on the low part
4704           __ rsb(temp, o_h, ShifterOperand(kArmBitsPerWord));
4705           __ Lsl(temp, high, temp);
4706           __ orr(o_l, o_l, ShifterOperand(temp));
4707           // If the shift is > 32 bits, override the low part
4708           __ subs(temp, o_h, ShifterOperand(kArmBitsPerWord));
4709           __ it(PL);
4710           __ Asr(o_l, high, temp, PL);
4711           // Shift the high part
4712           __ Asr(o_h, high, o_h);
4713         } else {
4714           __ and_(o_h, second_reg, ShifterOperand(kMaxLongShiftDistance));
4715           // same as Shr except we use `Lsr`s and not `Asr`s
4716           __ Lsr(o_l, low, o_h);
4717           __ rsb(temp, o_h, ShifterOperand(kArmBitsPerWord));
4718           __ Lsl(temp, high, temp);
4719           __ orr(o_l, o_l, ShifterOperand(temp));
4720           __ subs(temp, o_h, ShifterOperand(kArmBitsPerWord));
4721           __ it(PL);
4722           __ Lsr(o_l, high, temp, PL);
4723           __ Lsr(o_h, high, o_h);
4724         }
4725       } else {
4726         // Register allocator doesn't create partial overlap.
4727         DCHECK_NE(o_l, high);
4728         DCHECK_NE(o_h, low);
4729         int32_t cst = second.GetConstant()->AsIntConstant()->GetValue();
4730         uint32_t shift_value = cst & kMaxLongShiftDistance;
4731         if (shift_value > 32) {
4732           if (op->IsShl()) {
4733             __ Lsl(o_h, low, shift_value - 32);
4734             __ LoadImmediate(o_l, 0);
4735           } else if (op->IsShr()) {
4736             __ Asr(o_l, high, shift_value - 32);
4737             __ Asr(o_h, high, 31);
4738           } else {
4739             __ Lsr(o_l, high, shift_value - 32);
4740             __ LoadImmediate(o_h, 0);
4741           }
4742         } else if (shift_value == 32) {
4743           if (op->IsShl()) {
4744             __ mov(o_h, ShifterOperand(low));
4745             __ LoadImmediate(o_l, 0);
4746           } else if (op->IsShr()) {
4747             __ mov(o_l, ShifterOperand(high));
4748             __ Asr(o_h, high, 31);
4749           } else {
4750             __ mov(o_l, ShifterOperand(high));
4751             __ LoadImmediate(o_h, 0);
4752           }
4753         } else if (shift_value == 1) {
4754           if (op->IsShl()) {
4755             __ Lsls(o_l, low, 1);
4756             __ adc(o_h, high, ShifterOperand(high));
4757           } else if (op->IsShr()) {
4758             __ Asrs(o_h, high, 1);
4759             __ Rrx(o_l, low);
4760           } else {
4761             __ Lsrs(o_h, high, 1);
4762             __ Rrx(o_l, low);
4763           }
4764         } else {
4765           DCHECK(2 <= shift_value && shift_value < 32) << shift_value;
4766           if (op->IsShl()) {
4767             __ Lsl(o_h, high, shift_value);
4768             __ orr(o_h, o_h, ShifterOperand(low, LSR, 32 - shift_value));
4769             __ Lsl(o_l, low, shift_value);
4770           } else if (op->IsShr()) {
4771             __ Lsr(o_l, low, shift_value);
4772             __ orr(o_l, o_l, ShifterOperand(high, LSL, 32 - shift_value));
4773             __ Asr(o_h, high, shift_value);
4774           } else {
4775             __ Lsr(o_l, low, shift_value);
4776             __ orr(o_l, o_l, ShifterOperand(high, LSL, 32 - shift_value));
4777             __ Lsr(o_h, high, shift_value);
4778           }
4779         }
4780       }
4781       break;
4782     }
4783     default:
4784       LOG(FATAL) << "Unexpected operation type " << type;
4785       UNREACHABLE();
4786   }
4787 }
4788 
VisitShl(HShl * shl)4789 void LocationsBuilderARM::VisitShl(HShl* shl) {
4790   HandleShift(shl);
4791 }
4792 
VisitShl(HShl * shl)4793 void InstructionCodeGeneratorARM::VisitShl(HShl* shl) {
4794   HandleShift(shl);
4795 }
4796 
VisitShr(HShr * shr)4797 void LocationsBuilderARM::VisitShr(HShr* shr) {
4798   HandleShift(shr);
4799 }
4800 
VisitShr(HShr * shr)4801 void InstructionCodeGeneratorARM::VisitShr(HShr* shr) {
4802   HandleShift(shr);
4803 }
4804 
VisitUShr(HUShr * ushr)4805 void LocationsBuilderARM::VisitUShr(HUShr* ushr) {
4806   HandleShift(ushr);
4807 }
4808 
VisitUShr(HUShr * ushr)4809 void InstructionCodeGeneratorARM::VisitUShr(HUShr* ushr) {
4810   HandleShift(ushr);
4811 }
4812 
VisitNewInstance(HNewInstance * instruction)4813 void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) {
4814   LocationSummary* locations =
4815       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
4816   if (instruction->IsStringAlloc()) {
4817     locations->AddTemp(Location::RegisterLocation(kMethodRegisterArgument));
4818   } else {
4819     InvokeRuntimeCallingConvention calling_convention;
4820     locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4821   }
4822   locations->SetOut(Location::RegisterLocation(R0));
4823 }
4824 
VisitNewInstance(HNewInstance * instruction)4825 void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) {
4826   // Note: if heap poisoning is enabled, the entry point takes cares
4827   // of poisoning the reference.
4828   if (instruction->IsStringAlloc()) {
4829     // String is allocated through StringFactory. Call NewEmptyString entry point.
4830     Register temp = instruction->GetLocations()->GetTemp(0).AsRegister<Register>();
4831     MemberOffset code_offset = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArmPointerSize);
4832     __ LoadFromOffset(kLoadWord, temp, TR, QUICK_ENTRY_POINT(pNewEmptyString));
4833     __ LoadFromOffset(kLoadWord, LR, temp, code_offset.Int32Value());
4834     __ blx(LR);
4835     codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
4836   } else {
4837     codegen_->InvokeRuntime(instruction->GetEntrypoint(), instruction, instruction->GetDexPc());
4838     CheckEntrypointTypes<kQuickAllocObjectWithChecks, void*, mirror::Class*>();
4839   }
4840 }
4841 
VisitNewArray(HNewArray * instruction)4842 void LocationsBuilderARM::VisitNewArray(HNewArray* instruction) {
4843   LocationSummary* locations =
4844       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
4845   InvokeRuntimeCallingConvention calling_convention;
4846   locations->SetOut(Location::RegisterLocation(R0));
4847   locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4848   locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
4849 }
4850 
VisitNewArray(HNewArray * instruction)4851 void InstructionCodeGeneratorARM::VisitNewArray(HNewArray* instruction) {
4852   // Note: if heap poisoning is enabled, the entry point takes cares
4853   // of poisoning the reference.
4854   QuickEntrypointEnum entrypoint =
4855       CodeGenerator::GetArrayAllocationEntrypoint(instruction->GetLoadClass()->GetClass());
4856   codegen_->InvokeRuntime(entrypoint, instruction, instruction->GetDexPc());
4857   CheckEntrypointTypes<kQuickAllocArrayResolved, void*, mirror::Class*, int32_t>();
4858   DCHECK(!codegen_->IsLeafMethod());
4859 }
4860 
VisitParameterValue(HParameterValue * instruction)4861 void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) {
4862   LocationSummary* locations =
4863       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
4864   Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
4865   if (location.IsStackSlot()) {
4866     location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
4867   } else if (location.IsDoubleStackSlot()) {
4868     location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
4869   }
4870   locations->SetOut(location);
4871 }
4872 
VisitParameterValue(HParameterValue * instruction ATTRIBUTE_UNUSED)4873 void InstructionCodeGeneratorARM::VisitParameterValue(
4874     HParameterValue* instruction ATTRIBUTE_UNUSED) {
4875   // Nothing to do, the parameter is already at its location.
4876 }
4877 
VisitCurrentMethod(HCurrentMethod * instruction)4878 void LocationsBuilderARM::VisitCurrentMethod(HCurrentMethod* instruction) {
4879   LocationSummary* locations =
4880       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
4881   locations->SetOut(Location::RegisterLocation(kMethodRegisterArgument));
4882 }
4883 
VisitCurrentMethod(HCurrentMethod * instruction ATTRIBUTE_UNUSED)4884 void InstructionCodeGeneratorARM::VisitCurrentMethod(HCurrentMethod* instruction ATTRIBUTE_UNUSED) {
4885   // Nothing to do, the method is already at its location.
4886 }
4887 
VisitNot(HNot * not_)4888 void LocationsBuilderARM::VisitNot(HNot* not_) {
4889   LocationSummary* locations =
4890       new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
4891   locations->SetInAt(0, Location::RequiresRegister());
4892   locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
4893 }
4894 
VisitNot(HNot * not_)4895 void InstructionCodeGeneratorARM::VisitNot(HNot* not_) {
4896   LocationSummary* locations = not_->GetLocations();
4897   Location out = locations->Out();
4898   Location in = locations->InAt(0);
4899   switch (not_->GetResultType()) {
4900     case Primitive::kPrimInt:
4901       __ mvn(out.AsRegister<Register>(), ShifterOperand(in.AsRegister<Register>()));
4902       break;
4903 
4904     case Primitive::kPrimLong:
4905       __ mvn(out.AsRegisterPairLow<Register>(),
4906              ShifterOperand(in.AsRegisterPairLow<Register>()));
4907       __ mvn(out.AsRegisterPairHigh<Register>(),
4908              ShifterOperand(in.AsRegisterPairHigh<Register>()));
4909       break;
4910 
4911     default:
4912       LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
4913   }
4914 }
4915 
VisitBooleanNot(HBooleanNot * bool_not)4916 void LocationsBuilderARM::VisitBooleanNot(HBooleanNot* bool_not) {
4917   LocationSummary* locations =
4918       new (GetGraph()->GetArena()) LocationSummary(bool_not, LocationSummary::kNoCall);
4919   locations->SetInAt(0, Location::RequiresRegister());
4920   locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
4921 }
4922 
VisitBooleanNot(HBooleanNot * bool_not)4923 void InstructionCodeGeneratorARM::VisitBooleanNot(HBooleanNot* bool_not) {
4924   LocationSummary* locations = bool_not->GetLocations();
4925   Location out = locations->Out();
4926   Location in = locations->InAt(0);
4927   __ eor(out.AsRegister<Register>(), in.AsRegister<Register>(), ShifterOperand(1));
4928 }
4929 
VisitCompare(HCompare * compare)4930 void LocationsBuilderARM::VisitCompare(HCompare* compare) {
4931   LocationSummary* locations =
4932       new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
4933   switch (compare->InputAt(0)->GetType()) {
4934     case Primitive::kPrimBoolean:
4935     case Primitive::kPrimByte:
4936     case Primitive::kPrimShort:
4937     case Primitive::kPrimChar:
4938     case Primitive::kPrimInt:
4939     case Primitive::kPrimLong: {
4940       locations->SetInAt(0, Location::RequiresRegister());
4941       locations->SetInAt(1, Location::RequiresRegister());
4942       // Output overlaps because it is written before doing the low comparison.
4943       locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
4944       break;
4945     }
4946     case Primitive::kPrimFloat:
4947     case Primitive::kPrimDouble: {
4948       locations->SetInAt(0, Location::RequiresFpuRegister());
4949       locations->SetInAt(1, ArithmeticZeroOrFpuRegister(compare->InputAt(1)));
4950       locations->SetOut(Location::RequiresRegister());
4951       break;
4952     }
4953     default:
4954       LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
4955   }
4956 }
4957 
VisitCompare(HCompare * compare)4958 void InstructionCodeGeneratorARM::VisitCompare(HCompare* compare) {
4959   LocationSummary* locations = compare->GetLocations();
4960   Register out = locations->Out().AsRegister<Register>();
4961   Location left = locations->InAt(0);
4962   Location right = locations->InAt(1);
4963 
4964   Label less, greater, done;
4965   Label* final_label = codegen_->GetFinalLabel(compare, &done);
4966   Primitive::Type type = compare->InputAt(0)->GetType();
4967   Condition less_cond;
4968   switch (type) {
4969     case Primitive::kPrimBoolean:
4970     case Primitive::kPrimByte:
4971     case Primitive::kPrimShort:
4972     case Primitive::kPrimChar:
4973     case Primitive::kPrimInt: {
4974       __ LoadImmediate(out, 0);
4975       __ cmp(left.AsRegister<Register>(),
4976              ShifterOperand(right.AsRegister<Register>()));  // Signed compare.
4977       less_cond = LT;
4978       break;
4979     }
4980     case Primitive::kPrimLong: {
4981       __ cmp(left.AsRegisterPairHigh<Register>(),
4982              ShifterOperand(right.AsRegisterPairHigh<Register>()));  // Signed compare.
4983       __ b(&less, LT);
4984       __ b(&greater, GT);
4985       // Do LoadImmediate before the last `cmp`, as LoadImmediate might affect the status flags.
4986       __ LoadImmediate(out, 0);
4987       __ cmp(left.AsRegisterPairLow<Register>(),
4988              ShifterOperand(right.AsRegisterPairLow<Register>()));  // Unsigned compare.
4989       less_cond = LO;
4990       break;
4991     }
4992     case Primitive::kPrimFloat:
4993     case Primitive::kPrimDouble: {
4994       __ LoadImmediate(out, 0);
4995       GenerateVcmp(compare, codegen_);
4996       __ vmstat();  // transfer FP status register to ARM APSR.
4997       less_cond = ARMFPCondition(kCondLT, compare->IsGtBias());
4998       break;
4999     }
5000     default:
5001       LOG(FATAL) << "Unexpected compare type " << type;
5002       UNREACHABLE();
5003   }
5004 
5005   __ b(final_label, EQ);
5006   __ b(&less, less_cond);
5007 
5008   __ Bind(&greater);
5009   __ LoadImmediate(out, 1);
5010   __ b(final_label);
5011 
5012   __ Bind(&less);
5013   __ LoadImmediate(out, -1);
5014 
5015   if (done.IsLinked()) {
5016     __ Bind(&done);
5017   }
5018 }
5019 
VisitPhi(HPhi * instruction)5020 void LocationsBuilderARM::VisitPhi(HPhi* instruction) {
5021   LocationSummary* locations =
5022       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
5023   for (size_t i = 0, e = locations->GetInputCount(); i < e; ++i) {
5024     locations->SetInAt(i, Location::Any());
5025   }
5026   locations->SetOut(Location::Any());
5027 }
5028 
VisitPhi(HPhi * instruction ATTRIBUTE_UNUSED)5029 void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction ATTRIBUTE_UNUSED) {
5030   LOG(FATAL) << "Unreachable";
5031 }
5032 
GenerateMemoryBarrier(MemBarrierKind kind)5033 void CodeGeneratorARM::GenerateMemoryBarrier(MemBarrierKind kind) {
5034   // TODO (ported from quick): revisit ARM barrier kinds.
5035   DmbOptions flavor = DmbOptions::ISH;  // Quiet C++ warnings.
5036   switch (kind) {
5037     case MemBarrierKind::kAnyStore:
5038     case MemBarrierKind::kLoadAny:
5039     case MemBarrierKind::kAnyAny: {
5040       flavor = DmbOptions::ISH;
5041       break;
5042     }
5043     case MemBarrierKind::kStoreStore: {
5044       flavor = DmbOptions::ISHST;
5045       break;
5046     }
5047     default:
5048       LOG(FATAL) << "Unexpected memory barrier " << kind;
5049   }
5050   __ dmb(flavor);
5051 }
5052 
GenerateWideAtomicLoad(Register addr,uint32_t offset,Register out_lo,Register out_hi)5053 void InstructionCodeGeneratorARM::GenerateWideAtomicLoad(Register addr,
5054                                                          uint32_t offset,
5055                                                          Register out_lo,
5056                                                          Register out_hi) {
5057   if (offset != 0) {
5058     // Ensure `out_lo` is different from `addr`, so that loading
5059     // `offset` into `out_lo` does not clutter `addr`.
5060     DCHECK_NE(out_lo, addr);
5061     __ LoadImmediate(out_lo, offset);
5062     __ add(IP, addr, ShifterOperand(out_lo));
5063     addr = IP;
5064   }
5065   __ ldrexd(out_lo, out_hi, addr);
5066 }
5067 
GenerateWideAtomicStore(Register addr,uint32_t offset,Register value_lo,Register value_hi,Register temp1,Register temp2,HInstruction * instruction)5068 void InstructionCodeGeneratorARM::GenerateWideAtomicStore(Register addr,
5069                                                           uint32_t offset,
5070                                                           Register value_lo,
5071                                                           Register value_hi,
5072                                                           Register temp1,
5073                                                           Register temp2,
5074                                                           HInstruction* instruction) {
5075   Label fail;
5076   if (offset != 0) {
5077     __ LoadImmediate(temp1, offset);
5078     __ add(IP, addr, ShifterOperand(temp1));
5079     addr = IP;
5080   }
5081   __ Bind(&fail);
5082   // We need a load followed by store. (The address used in a STREX instruction must
5083   // be the same as the address in the most recently executed LDREX instruction.)
5084   __ ldrexd(temp1, temp2, addr);
5085   codegen_->MaybeRecordImplicitNullCheck(instruction);
5086   __ strexd(temp1, value_lo, value_hi, addr);
5087   __ CompareAndBranchIfNonZero(temp1, &fail);
5088 }
5089 
HandleFieldSet(HInstruction * instruction,const FieldInfo & field_info)5090 void LocationsBuilderARM::HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info) {
5091   DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
5092 
5093   LocationSummary* locations =
5094       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
5095   locations->SetInAt(0, Location::RequiresRegister());
5096 
5097   Primitive::Type field_type = field_info.GetFieldType();
5098   if (Primitive::IsFloatingPointType(field_type)) {
5099     locations->SetInAt(1, Location::RequiresFpuRegister());
5100   } else {
5101     locations->SetInAt(1, Location::RequiresRegister());
5102   }
5103 
5104   bool is_wide = field_type == Primitive::kPrimLong || field_type == Primitive::kPrimDouble;
5105   bool generate_volatile = field_info.IsVolatile()
5106       && is_wide
5107       && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
5108   bool needs_write_barrier =
5109       CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
5110   // Temporary registers for the write barrier.
5111   // TODO: consider renaming StoreNeedsWriteBarrier to StoreNeedsGCMark.
5112   if (needs_write_barrier) {
5113     locations->AddTemp(Location::RequiresRegister());  // Possibly used for reference poisoning too.
5114     locations->AddTemp(Location::RequiresRegister());
5115   } else if (generate_volatile) {
5116     // ARM encoding have some additional constraints for ldrexd/strexd:
5117     // - registers need to be consecutive
5118     // - the first register should be even but not R14.
5119     // We don't test for ARM yet, and the assertion makes sure that we
5120     // revisit this if we ever enable ARM encoding.
5121     DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
5122 
5123     locations->AddTemp(Location::RequiresRegister());
5124     locations->AddTemp(Location::RequiresRegister());
5125     if (field_type == Primitive::kPrimDouble) {
5126       // For doubles we need two more registers to copy the value.
5127       locations->AddTemp(Location::RegisterLocation(R2));
5128       locations->AddTemp(Location::RegisterLocation(R3));
5129     }
5130   }
5131 }
5132 
HandleFieldSet(HInstruction * instruction,const FieldInfo & field_info,bool value_can_be_null)5133 void InstructionCodeGeneratorARM::HandleFieldSet(HInstruction* instruction,
5134                                                  const FieldInfo& field_info,
5135                                                  bool value_can_be_null) {
5136   DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
5137 
5138   LocationSummary* locations = instruction->GetLocations();
5139   Register base = locations->InAt(0).AsRegister<Register>();
5140   Location value = locations->InAt(1);
5141 
5142   bool is_volatile = field_info.IsVolatile();
5143   bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
5144   Primitive::Type field_type = field_info.GetFieldType();
5145   uint32_t offset = field_info.GetFieldOffset().Uint32Value();
5146   bool needs_write_barrier =
5147       CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
5148 
5149   if (is_volatile) {
5150     codegen_->GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
5151   }
5152 
5153   switch (field_type) {
5154     case Primitive::kPrimBoolean:
5155     case Primitive::kPrimByte: {
5156       __ StoreToOffset(kStoreByte, value.AsRegister<Register>(), base, offset);
5157       break;
5158     }
5159 
5160     case Primitive::kPrimShort:
5161     case Primitive::kPrimChar: {
5162       __ StoreToOffset(kStoreHalfword, value.AsRegister<Register>(), base, offset);
5163       break;
5164     }
5165 
5166     case Primitive::kPrimInt:
5167     case Primitive::kPrimNot: {
5168       if (kPoisonHeapReferences && needs_write_barrier) {
5169         // Note that in the case where `value` is a null reference,
5170         // we do not enter this block, as a null reference does not
5171         // need poisoning.
5172         DCHECK_EQ(field_type, Primitive::kPrimNot);
5173         Register temp = locations->GetTemp(0).AsRegister<Register>();
5174         __ Mov(temp, value.AsRegister<Register>());
5175         __ PoisonHeapReference(temp);
5176         __ StoreToOffset(kStoreWord, temp, base, offset);
5177       } else {
5178         __ StoreToOffset(kStoreWord, value.AsRegister<Register>(), base, offset);
5179       }
5180       break;
5181     }
5182 
5183     case Primitive::kPrimLong: {
5184       if (is_volatile && !atomic_ldrd_strd) {
5185         GenerateWideAtomicStore(base, offset,
5186                                 value.AsRegisterPairLow<Register>(),
5187                                 value.AsRegisterPairHigh<Register>(),
5188                                 locations->GetTemp(0).AsRegister<Register>(),
5189                                 locations->GetTemp(1).AsRegister<Register>(),
5190                                 instruction);
5191       } else {
5192         __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), base, offset);
5193         codegen_->MaybeRecordImplicitNullCheck(instruction);
5194       }
5195       break;
5196     }
5197 
5198     case Primitive::kPrimFloat: {
5199       __ StoreSToOffset(value.AsFpuRegister<SRegister>(), base, offset);
5200       break;
5201     }
5202 
5203     case Primitive::kPrimDouble: {
5204       DRegister value_reg = FromLowSToD(value.AsFpuRegisterPairLow<SRegister>());
5205       if (is_volatile && !atomic_ldrd_strd) {
5206         Register value_reg_lo = locations->GetTemp(0).AsRegister<Register>();
5207         Register value_reg_hi = locations->GetTemp(1).AsRegister<Register>();
5208 
5209         __ vmovrrd(value_reg_lo, value_reg_hi, value_reg);
5210 
5211         GenerateWideAtomicStore(base, offset,
5212                                 value_reg_lo,
5213                                 value_reg_hi,
5214                                 locations->GetTemp(2).AsRegister<Register>(),
5215                                 locations->GetTemp(3).AsRegister<Register>(),
5216                                 instruction);
5217       } else {
5218         __ StoreDToOffset(value_reg, base, offset);
5219         codegen_->MaybeRecordImplicitNullCheck(instruction);
5220       }
5221       break;
5222     }
5223 
5224     case Primitive::kPrimVoid:
5225       LOG(FATAL) << "Unreachable type " << field_type;
5226       UNREACHABLE();
5227   }
5228 
5229   // Longs and doubles are handled in the switch.
5230   if (field_type != Primitive::kPrimLong && field_type != Primitive::kPrimDouble) {
5231     codegen_->MaybeRecordImplicitNullCheck(instruction);
5232   }
5233 
5234   if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
5235     Register temp = locations->GetTemp(0).AsRegister<Register>();
5236     Register card = locations->GetTemp(1).AsRegister<Register>();
5237     codegen_->MarkGCCard(
5238         temp, card, base, value.AsRegister<Register>(), value_can_be_null);
5239   }
5240 
5241   if (is_volatile) {
5242     codegen_->GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
5243   }
5244 }
5245 
HandleFieldGet(HInstruction * instruction,const FieldInfo & field_info)5246 void LocationsBuilderARM::HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info) {
5247   DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
5248 
5249   bool object_field_get_with_read_barrier =
5250       kEmitCompilerReadBarrier && (field_info.GetFieldType() == Primitive::kPrimNot);
5251   LocationSummary* locations =
5252       new (GetGraph()->GetArena()) LocationSummary(instruction,
5253                                                    object_field_get_with_read_barrier ?
5254                                                        LocationSummary::kCallOnSlowPath :
5255                                                        LocationSummary::kNoCall);
5256   if (object_field_get_with_read_barrier && kUseBakerReadBarrier) {
5257     locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty());  // No caller-save registers.
5258   }
5259   locations->SetInAt(0, Location::RequiresRegister());
5260 
5261   bool volatile_for_double = field_info.IsVolatile()
5262       && (field_info.GetFieldType() == Primitive::kPrimDouble)
5263       && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
5264   // The output overlaps in case of volatile long: we don't want the
5265   // code generated by GenerateWideAtomicLoad to overwrite the
5266   // object's location.  Likewise, in the case of an object field get
5267   // with read barriers enabled, we do not want the load to overwrite
5268   // the object's location, as we need it to emit the read barrier.
5269   bool overlap = (field_info.IsVolatile() && (field_info.GetFieldType() == Primitive::kPrimLong)) ||
5270       object_field_get_with_read_barrier;
5271 
5272   if (Primitive::IsFloatingPointType(instruction->GetType())) {
5273     locations->SetOut(Location::RequiresFpuRegister());
5274   } else {
5275     locations->SetOut(Location::RequiresRegister(),
5276                       (overlap ? Location::kOutputOverlap : Location::kNoOutputOverlap));
5277   }
5278   if (volatile_for_double) {
5279     // ARM encoding have some additional constraints for ldrexd/strexd:
5280     // - registers need to be consecutive
5281     // - the first register should be even but not R14.
5282     // We don't test for ARM yet, and the assertion makes sure that we
5283     // revisit this if we ever enable ARM encoding.
5284     DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
5285     locations->AddTemp(Location::RequiresRegister());
5286     locations->AddTemp(Location::RequiresRegister());
5287   } else if (object_field_get_with_read_barrier && kUseBakerReadBarrier) {
5288     // We need a temporary register for the read barrier marking slow
5289     // path in CodeGeneratorARM::GenerateFieldLoadWithBakerReadBarrier.
5290     locations->AddTemp(Location::RequiresRegister());
5291   }
5292 }
5293 
ArithmeticZeroOrFpuRegister(HInstruction * input)5294 Location LocationsBuilderARM::ArithmeticZeroOrFpuRegister(HInstruction* input) {
5295   DCHECK(input->GetType() == Primitive::kPrimDouble || input->GetType() == Primitive::kPrimFloat)
5296       << input->GetType();
5297   if ((input->IsFloatConstant() && (input->AsFloatConstant()->IsArithmeticZero())) ||
5298       (input->IsDoubleConstant() && (input->AsDoubleConstant()->IsArithmeticZero()))) {
5299     return Location::ConstantLocation(input->AsConstant());
5300   } else {
5301     return Location::RequiresFpuRegister();
5302   }
5303 }
5304 
ArmEncodableConstantOrRegister(HInstruction * constant,Opcode opcode)5305 Location LocationsBuilderARM::ArmEncodableConstantOrRegister(HInstruction* constant,
5306                                                              Opcode opcode) {
5307   DCHECK(!Primitive::IsFloatingPointType(constant->GetType()));
5308   if (constant->IsConstant() &&
5309       CanEncodeConstantAsImmediate(constant->AsConstant(), opcode)) {
5310     return Location::ConstantLocation(constant->AsConstant());
5311   }
5312   return Location::RequiresRegister();
5313 }
5314 
CanEncodeConstantAsImmediate(HConstant * input_cst,Opcode opcode)5315 bool LocationsBuilderARM::CanEncodeConstantAsImmediate(HConstant* input_cst,
5316                                                        Opcode opcode) {
5317   uint64_t value = static_cast<uint64_t>(Int64FromConstant(input_cst));
5318   if (Primitive::Is64BitType(input_cst->GetType())) {
5319     Opcode high_opcode = opcode;
5320     SetCc low_set_cc = kCcDontCare;
5321     switch (opcode) {
5322       case SUB:
5323         // Flip the operation to an ADD.
5324         value = -value;
5325         opcode = ADD;
5326         FALLTHROUGH_INTENDED;
5327       case ADD:
5328         if (Low32Bits(value) == 0u) {
5329           return CanEncodeConstantAsImmediate(High32Bits(value), opcode, kCcDontCare);
5330         }
5331         high_opcode = ADC;
5332         low_set_cc = kCcSet;
5333         break;
5334       default:
5335         break;
5336     }
5337     return CanEncodeConstantAsImmediate(Low32Bits(value), opcode, low_set_cc) &&
5338         CanEncodeConstantAsImmediate(High32Bits(value), high_opcode, kCcDontCare);
5339   } else {
5340     return CanEncodeConstantAsImmediate(Low32Bits(value), opcode);
5341   }
5342 }
5343 
CanEncodeConstantAsImmediate(uint32_t value,Opcode opcode,SetCc set_cc)5344 bool LocationsBuilderARM::CanEncodeConstantAsImmediate(uint32_t value,
5345                                                        Opcode opcode,
5346                                                        SetCc set_cc) {
5347   ShifterOperand so;
5348   ArmAssembler* assembler = codegen_->GetAssembler();
5349   if (assembler->ShifterOperandCanHold(kNoRegister, kNoRegister, opcode, value, set_cc, &so)) {
5350     return true;
5351   }
5352   Opcode neg_opcode = kNoOperand;
5353   uint32_t neg_value = 0;
5354   switch (opcode) {
5355     case AND: neg_opcode = BIC; neg_value = ~value; break;
5356     case ORR: neg_opcode = ORN; neg_value = ~value; break;
5357     case ADD: neg_opcode = SUB; neg_value = -value; break;
5358     case ADC: neg_opcode = SBC; neg_value = ~value; break;
5359     case SUB: neg_opcode = ADD; neg_value = -value; break;
5360     case SBC: neg_opcode = ADC; neg_value = ~value; break;
5361     case MOV: neg_opcode = MVN; neg_value = ~value; break;
5362     default:
5363       return false;
5364   }
5365 
5366   if (assembler->ShifterOperandCanHold(kNoRegister,
5367                                        kNoRegister,
5368                                        neg_opcode,
5369                                        neg_value,
5370                                        set_cc,
5371                                        &so)) {
5372     return true;
5373   }
5374 
5375   return opcode == AND && IsPowerOfTwo(value + 1);
5376 }
5377 
HandleFieldGet(HInstruction * instruction,const FieldInfo & field_info)5378 void InstructionCodeGeneratorARM::HandleFieldGet(HInstruction* instruction,
5379                                                  const FieldInfo& field_info) {
5380   DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
5381 
5382   LocationSummary* locations = instruction->GetLocations();
5383   Location base_loc = locations->InAt(0);
5384   Register base = base_loc.AsRegister<Register>();
5385   Location out = locations->Out();
5386   bool is_volatile = field_info.IsVolatile();
5387   bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
5388   Primitive::Type field_type = field_info.GetFieldType();
5389   uint32_t offset = field_info.GetFieldOffset().Uint32Value();
5390 
5391   switch (field_type) {
5392     case Primitive::kPrimBoolean:
5393       __ LoadFromOffset(kLoadUnsignedByte, out.AsRegister<Register>(), base, offset);
5394       break;
5395 
5396     case Primitive::kPrimByte:
5397       __ LoadFromOffset(kLoadSignedByte, out.AsRegister<Register>(), base, offset);
5398       break;
5399 
5400     case Primitive::kPrimShort:
5401       __ LoadFromOffset(kLoadSignedHalfword, out.AsRegister<Register>(), base, offset);
5402       break;
5403 
5404     case Primitive::kPrimChar:
5405       __ LoadFromOffset(kLoadUnsignedHalfword, out.AsRegister<Register>(), base, offset);
5406       break;
5407 
5408     case Primitive::kPrimInt:
5409       __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), base, offset);
5410       break;
5411 
5412     case Primitive::kPrimNot: {
5413       // /* HeapReference<Object> */ out = *(base + offset)
5414       if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
5415         Location temp_loc = locations->GetTemp(0);
5416         // Note that a potential implicit null check is handled in this
5417         // CodeGeneratorARM::GenerateFieldLoadWithBakerReadBarrier call.
5418         codegen_->GenerateFieldLoadWithBakerReadBarrier(
5419             instruction, out, base, offset, temp_loc, /* needs_null_check */ true);
5420         if (is_volatile) {
5421           codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
5422         }
5423       } else {
5424         __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), base, offset);
5425         codegen_->MaybeRecordImplicitNullCheck(instruction);
5426         if (is_volatile) {
5427           codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
5428         }
5429         // If read barriers are enabled, emit read barriers other than
5430         // Baker's using a slow path (and also unpoison the loaded
5431         // reference, if heap poisoning is enabled).
5432         codegen_->MaybeGenerateReadBarrierSlow(instruction, out, out, base_loc, offset);
5433       }
5434       break;
5435     }
5436 
5437     case Primitive::kPrimLong:
5438       if (is_volatile && !atomic_ldrd_strd) {
5439         GenerateWideAtomicLoad(base, offset,
5440                                out.AsRegisterPairLow<Register>(),
5441                                out.AsRegisterPairHigh<Register>());
5442       } else {
5443         __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), base, offset);
5444       }
5445       break;
5446 
5447     case Primitive::kPrimFloat:
5448       __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), base, offset);
5449       break;
5450 
5451     case Primitive::kPrimDouble: {
5452       DRegister out_reg = FromLowSToD(out.AsFpuRegisterPairLow<SRegister>());
5453       if (is_volatile && !atomic_ldrd_strd) {
5454         Register lo = locations->GetTemp(0).AsRegister<Register>();
5455         Register hi = locations->GetTemp(1).AsRegister<Register>();
5456         GenerateWideAtomicLoad(base, offset, lo, hi);
5457         codegen_->MaybeRecordImplicitNullCheck(instruction);
5458         __ vmovdrr(out_reg, lo, hi);
5459       } else {
5460         __ LoadDFromOffset(out_reg, base, offset);
5461         codegen_->MaybeRecordImplicitNullCheck(instruction);
5462       }
5463       break;
5464     }
5465 
5466     case Primitive::kPrimVoid:
5467       LOG(FATAL) << "Unreachable type " << field_type;
5468       UNREACHABLE();
5469   }
5470 
5471   if (field_type == Primitive::kPrimNot || field_type == Primitive::kPrimDouble) {
5472     // Potential implicit null checks, in the case of reference or
5473     // double fields, are handled in the previous switch statement.
5474   } else {
5475     codegen_->MaybeRecordImplicitNullCheck(instruction);
5476   }
5477 
5478   if (is_volatile) {
5479     if (field_type == Primitive::kPrimNot) {
5480       // Memory barriers, in the case of references, are also handled
5481       // in the previous switch statement.
5482     } else {
5483       codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
5484     }
5485   }
5486 }
5487 
VisitInstanceFieldSet(HInstanceFieldSet * instruction)5488 void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
5489   HandleFieldSet(instruction, instruction->GetFieldInfo());
5490 }
5491 
VisitInstanceFieldSet(HInstanceFieldSet * instruction)5492 void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
5493   HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
5494 }
5495 
VisitInstanceFieldGet(HInstanceFieldGet * instruction)5496 void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
5497   HandleFieldGet(instruction, instruction->GetFieldInfo());
5498 }
5499 
VisitInstanceFieldGet(HInstanceFieldGet * instruction)5500 void InstructionCodeGeneratorARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
5501   HandleFieldGet(instruction, instruction->GetFieldInfo());
5502 }
5503 
VisitStaticFieldGet(HStaticFieldGet * instruction)5504 void LocationsBuilderARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
5505   HandleFieldGet(instruction, instruction->GetFieldInfo());
5506 }
5507 
VisitStaticFieldGet(HStaticFieldGet * instruction)5508 void InstructionCodeGeneratorARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
5509   HandleFieldGet(instruction, instruction->GetFieldInfo());
5510 }
5511 
VisitStaticFieldSet(HStaticFieldSet * instruction)5512 void LocationsBuilderARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
5513   HandleFieldSet(instruction, instruction->GetFieldInfo());
5514 }
5515 
VisitStaticFieldSet(HStaticFieldSet * instruction)5516 void InstructionCodeGeneratorARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
5517   HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
5518 }
5519 
VisitUnresolvedInstanceFieldGet(HUnresolvedInstanceFieldGet * instruction)5520 void LocationsBuilderARM::VisitUnresolvedInstanceFieldGet(
5521     HUnresolvedInstanceFieldGet* instruction) {
5522   FieldAccessCallingConventionARM calling_convention;
5523   codegen_->CreateUnresolvedFieldLocationSummary(
5524       instruction, instruction->GetFieldType(), calling_convention);
5525 }
5526 
VisitUnresolvedInstanceFieldGet(HUnresolvedInstanceFieldGet * instruction)5527 void InstructionCodeGeneratorARM::VisitUnresolvedInstanceFieldGet(
5528     HUnresolvedInstanceFieldGet* instruction) {
5529   FieldAccessCallingConventionARM calling_convention;
5530   codegen_->GenerateUnresolvedFieldAccess(instruction,
5531                                           instruction->GetFieldType(),
5532                                           instruction->GetFieldIndex(),
5533                                           instruction->GetDexPc(),
5534                                           calling_convention);
5535 }
5536 
VisitUnresolvedInstanceFieldSet(HUnresolvedInstanceFieldSet * instruction)5537 void LocationsBuilderARM::VisitUnresolvedInstanceFieldSet(
5538     HUnresolvedInstanceFieldSet* instruction) {
5539   FieldAccessCallingConventionARM calling_convention;
5540   codegen_->CreateUnresolvedFieldLocationSummary(
5541       instruction, instruction->GetFieldType(), calling_convention);
5542 }
5543 
VisitUnresolvedInstanceFieldSet(HUnresolvedInstanceFieldSet * instruction)5544 void InstructionCodeGeneratorARM::VisitUnresolvedInstanceFieldSet(
5545     HUnresolvedInstanceFieldSet* instruction) {
5546   FieldAccessCallingConventionARM calling_convention;
5547   codegen_->GenerateUnresolvedFieldAccess(instruction,
5548                                           instruction->GetFieldType(),
5549                                           instruction->GetFieldIndex(),
5550                                           instruction->GetDexPc(),
5551                                           calling_convention);
5552 }
5553 
VisitUnresolvedStaticFieldGet(HUnresolvedStaticFieldGet * instruction)5554 void LocationsBuilderARM::VisitUnresolvedStaticFieldGet(
5555     HUnresolvedStaticFieldGet* instruction) {
5556   FieldAccessCallingConventionARM calling_convention;
5557   codegen_->CreateUnresolvedFieldLocationSummary(
5558       instruction, instruction->GetFieldType(), calling_convention);
5559 }
5560 
VisitUnresolvedStaticFieldGet(HUnresolvedStaticFieldGet * instruction)5561 void InstructionCodeGeneratorARM::VisitUnresolvedStaticFieldGet(
5562     HUnresolvedStaticFieldGet* instruction) {
5563   FieldAccessCallingConventionARM calling_convention;
5564   codegen_->GenerateUnresolvedFieldAccess(instruction,
5565                                           instruction->GetFieldType(),
5566                                           instruction->GetFieldIndex(),
5567                                           instruction->GetDexPc(),
5568                                           calling_convention);
5569 }
5570 
VisitUnresolvedStaticFieldSet(HUnresolvedStaticFieldSet * instruction)5571 void LocationsBuilderARM::VisitUnresolvedStaticFieldSet(
5572     HUnresolvedStaticFieldSet* instruction) {
5573   FieldAccessCallingConventionARM calling_convention;
5574   codegen_->CreateUnresolvedFieldLocationSummary(
5575       instruction, instruction->GetFieldType(), calling_convention);
5576 }
5577 
VisitUnresolvedStaticFieldSet(HUnresolvedStaticFieldSet * instruction)5578 void InstructionCodeGeneratorARM::VisitUnresolvedStaticFieldSet(
5579     HUnresolvedStaticFieldSet* instruction) {
5580   FieldAccessCallingConventionARM calling_convention;
5581   codegen_->GenerateUnresolvedFieldAccess(instruction,
5582                                           instruction->GetFieldType(),
5583                                           instruction->GetFieldIndex(),
5584                                           instruction->GetDexPc(),
5585                                           calling_convention);
5586 }
5587 
VisitNullCheck(HNullCheck * instruction)5588 void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) {
5589   LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction);
5590   locations->SetInAt(0, Location::RequiresRegister());
5591 }
5592 
GenerateImplicitNullCheck(HNullCheck * instruction)5593 void CodeGeneratorARM::GenerateImplicitNullCheck(HNullCheck* instruction) {
5594   if (CanMoveNullCheckToUser(instruction)) {
5595     return;
5596   }
5597   Location obj = instruction->GetLocations()->InAt(0);
5598 
5599   __ LoadFromOffset(kLoadWord, IP, obj.AsRegister<Register>(), 0);
5600   RecordPcInfo(instruction, instruction->GetDexPc());
5601 }
5602 
GenerateExplicitNullCheck(HNullCheck * instruction)5603 void CodeGeneratorARM::GenerateExplicitNullCheck(HNullCheck* instruction) {
5604   SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction);
5605   AddSlowPath(slow_path);
5606 
5607   LocationSummary* locations = instruction->GetLocations();
5608   Location obj = locations->InAt(0);
5609 
5610   __ CompareAndBranchIfZero(obj.AsRegister<Register>(), slow_path->GetEntryLabel());
5611 }
5612 
VisitNullCheck(HNullCheck * instruction)5613 void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) {
5614   codegen_->GenerateNullCheck(instruction);
5615 }
5616 
GetLoadOperandType(Primitive::Type type)5617 static LoadOperandType GetLoadOperandType(Primitive::Type type) {
5618   switch (type) {
5619     case Primitive::kPrimNot:
5620       return kLoadWord;
5621     case Primitive::kPrimBoolean:
5622       return kLoadUnsignedByte;
5623     case Primitive::kPrimByte:
5624       return kLoadSignedByte;
5625     case Primitive::kPrimChar:
5626       return kLoadUnsignedHalfword;
5627     case Primitive::kPrimShort:
5628       return kLoadSignedHalfword;
5629     case Primitive::kPrimInt:
5630       return kLoadWord;
5631     case Primitive::kPrimLong:
5632       return kLoadWordPair;
5633     case Primitive::kPrimFloat:
5634       return kLoadSWord;
5635     case Primitive::kPrimDouble:
5636       return kLoadDWord;
5637     default:
5638       LOG(FATAL) << "Unreachable type " << type;
5639       UNREACHABLE();
5640   }
5641 }
5642 
GetStoreOperandType(Primitive::Type type)5643 static StoreOperandType GetStoreOperandType(Primitive::Type type) {
5644   switch (type) {
5645     case Primitive::kPrimNot:
5646       return kStoreWord;
5647     case Primitive::kPrimBoolean:
5648     case Primitive::kPrimByte:
5649       return kStoreByte;
5650     case Primitive::kPrimChar:
5651     case Primitive::kPrimShort:
5652       return kStoreHalfword;
5653     case Primitive::kPrimInt:
5654       return kStoreWord;
5655     case Primitive::kPrimLong:
5656       return kStoreWordPair;
5657     case Primitive::kPrimFloat:
5658       return kStoreSWord;
5659     case Primitive::kPrimDouble:
5660       return kStoreDWord;
5661     default:
5662       LOG(FATAL) << "Unreachable type " << type;
5663       UNREACHABLE();
5664   }
5665 }
5666 
LoadFromShiftedRegOffset(Primitive::Type type,Location out_loc,Register base,Register reg_offset,Condition cond)5667 void CodeGeneratorARM::LoadFromShiftedRegOffset(Primitive::Type type,
5668                                                 Location out_loc,
5669                                                 Register base,
5670                                                 Register reg_offset,
5671                                                 Condition cond) {
5672   uint32_t shift_count = Primitive::ComponentSizeShift(type);
5673   Address mem_address(base, reg_offset, Shift::LSL, shift_count);
5674 
5675   switch (type) {
5676     case Primitive::kPrimByte:
5677       __ ldrsb(out_loc.AsRegister<Register>(), mem_address, cond);
5678       break;
5679     case Primitive::kPrimBoolean:
5680       __ ldrb(out_loc.AsRegister<Register>(), mem_address, cond);
5681       break;
5682     case Primitive::kPrimShort:
5683       __ ldrsh(out_loc.AsRegister<Register>(), mem_address, cond);
5684       break;
5685     case Primitive::kPrimChar:
5686       __ ldrh(out_loc.AsRegister<Register>(), mem_address, cond);
5687       break;
5688     case Primitive::kPrimNot:
5689     case Primitive::kPrimInt:
5690       __ ldr(out_loc.AsRegister<Register>(), mem_address, cond);
5691       break;
5692     // T32 doesn't support LoadFromShiftedRegOffset mem address mode for these types.
5693     case Primitive::kPrimLong:
5694     case Primitive::kPrimFloat:
5695     case Primitive::kPrimDouble:
5696     default:
5697       LOG(FATAL) << "Unreachable type " << type;
5698       UNREACHABLE();
5699   }
5700 }
5701 
StoreToShiftedRegOffset(Primitive::Type type,Location loc,Register base,Register reg_offset,Condition cond)5702 void CodeGeneratorARM::StoreToShiftedRegOffset(Primitive::Type type,
5703                                                Location loc,
5704                                                Register base,
5705                                                Register reg_offset,
5706                                                Condition cond) {
5707   uint32_t shift_count = Primitive::ComponentSizeShift(type);
5708   Address mem_address(base, reg_offset, Shift::LSL, shift_count);
5709 
5710   switch (type) {
5711     case Primitive::kPrimByte:
5712     case Primitive::kPrimBoolean:
5713       __ strb(loc.AsRegister<Register>(), mem_address, cond);
5714       break;
5715     case Primitive::kPrimShort:
5716     case Primitive::kPrimChar:
5717       __ strh(loc.AsRegister<Register>(), mem_address, cond);
5718       break;
5719     case Primitive::kPrimNot:
5720     case Primitive::kPrimInt:
5721       __ str(loc.AsRegister<Register>(), mem_address, cond);
5722       break;
5723     // T32 doesn't support StoreToShiftedRegOffset mem address mode for these types.
5724     case Primitive::kPrimLong:
5725     case Primitive::kPrimFloat:
5726     case Primitive::kPrimDouble:
5727     default:
5728       LOG(FATAL) << "Unreachable type " << type;
5729       UNREACHABLE();
5730   }
5731 }
5732 
VisitArrayGet(HArrayGet * instruction)5733 void LocationsBuilderARM::VisitArrayGet(HArrayGet* instruction) {
5734   bool object_array_get_with_read_barrier =
5735       kEmitCompilerReadBarrier && (instruction->GetType() == Primitive::kPrimNot);
5736   LocationSummary* locations =
5737       new (GetGraph()->GetArena()) LocationSummary(instruction,
5738                                                    object_array_get_with_read_barrier ?
5739                                                        LocationSummary::kCallOnSlowPath :
5740                                                        LocationSummary::kNoCall);
5741   if (object_array_get_with_read_barrier && kUseBakerReadBarrier) {
5742     locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty());  // No caller-save registers.
5743   }
5744   locations->SetInAt(0, Location::RequiresRegister());
5745   locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
5746   if (Primitive::IsFloatingPointType(instruction->GetType())) {
5747     locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
5748   } else {
5749     // The output overlaps in the case of an object array get with
5750     // read barriers enabled: we do not want the move to overwrite the
5751     // array's location, as we need it to emit the read barrier.
5752     locations->SetOut(
5753         Location::RequiresRegister(),
5754         object_array_get_with_read_barrier ? Location::kOutputOverlap : Location::kNoOutputOverlap);
5755   }
5756   // We need a temporary register for the read barrier marking slow
5757   // path in CodeGeneratorARM::GenerateArrayLoadWithBakerReadBarrier.
5758   // Also need for String compression feature.
5759   if ((object_array_get_with_read_barrier && kUseBakerReadBarrier)
5760       || (mirror::kUseStringCompression && instruction->IsStringCharAt())) {
5761     locations->AddTemp(Location::RequiresRegister());
5762   }
5763 }
5764 
VisitArrayGet(HArrayGet * instruction)5765 void InstructionCodeGeneratorARM::VisitArrayGet(HArrayGet* instruction) {
5766   LocationSummary* locations = instruction->GetLocations();
5767   Location obj_loc = locations->InAt(0);
5768   Register obj = obj_loc.AsRegister<Register>();
5769   Location index = locations->InAt(1);
5770   Location out_loc = locations->Out();
5771   uint32_t data_offset = CodeGenerator::GetArrayDataOffset(instruction);
5772   Primitive::Type type = instruction->GetType();
5773   const bool maybe_compressed_char_at = mirror::kUseStringCompression &&
5774                                         instruction->IsStringCharAt();
5775   HInstruction* array_instr = instruction->GetArray();
5776   bool has_intermediate_address = array_instr->IsIntermediateAddress();
5777 
5778   switch (type) {
5779     case Primitive::kPrimBoolean:
5780     case Primitive::kPrimByte:
5781     case Primitive::kPrimShort:
5782     case Primitive::kPrimChar:
5783     case Primitive::kPrimInt: {
5784       Register length;
5785       if (maybe_compressed_char_at) {
5786         length = locations->GetTemp(0).AsRegister<Register>();
5787         uint32_t count_offset = mirror::String::CountOffset().Uint32Value();
5788         __ LoadFromOffset(kLoadWord, length, obj, count_offset);
5789         codegen_->MaybeRecordImplicitNullCheck(instruction);
5790       }
5791       if (index.IsConstant()) {
5792         int32_t const_index = index.GetConstant()->AsIntConstant()->GetValue();
5793         if (maybe_compressed_char_at) {
5794           Label uncompressed_load, done;
5795           Label* final_label = codegen_->GetFinalLabel(instruction, &done);
5796           __ Lsrs(length, length, 1u);  // LSRS has a 16-bit encoding, TST (immediate) does not.
5797           static_assert(static_cast<uint32_t>(mirror::StringCompressionFlag::kCompressed) == 0u,
5798                         "Expecting 0=compressed, 1=uncompressed");
5799           __ b(&uncompressed_load, CS);
5800           __ LoadFromOffset(kLoadUnsignedByte,
5801                             out_loc.AsRegister<Register>(),
5802                             obj,
5803                             data_offset + const_index);
5804           __ b(final_label);
5805           __ Bind(&uncompressed_load);
5806           __ LoadFromOffset(GetLoadOperandType(Primitive::kPrimChar),
5807                             out_loc.AsRegister<Register>(),
5808                             obj,
5809                             data_offset + (const_index << 1));
5810           if (done.IsLinked()) {
5811             __ Bind(&done);
5812           }
5813         } else {
5814           uint32_t full_offset = data_offset + (const_index << Primitive::ComponentSizeShift(type));
5815 
5816           LoadOperandType load_type = GetLoadOperandType(type);
5817           __ LoadFromOffset(load_type, out_loc.AsRegister<Register>(), obj, full_offset);
5818         }
5819       } else {
5820         Register temp = IP;
5821 
5822         if (has_intermediate_address) {
5823           // We do not need to compute the intermediate address from the array: the
5824           // input instruction has done it already. See the comment in
5825           // `TryExtractArrayAccessAddress()`.
5826           if (kIsDebugBuild) {
5827             HIntermediateAddress* tmp = array_instr->AsIntermediateAddress();
5828             DCHECK_EQ(tmp->GetOffset()->AsIntConstant()->GetValueAsUint64(), data_offset);
5829           }
5830           temp = obj;
5831         } else {
5832           __ add(temp, obj, ShifterOperand(data_offset));
5833         }
5834         if (maybe_compressed_char_at) {
5835           Label uncompressed_load, done;
5836           Label* final_label = codegen_->GetFinalLabel(instruction, &done);
5837           __ Lsrs(length, length, 1u);  // LSRS has a 16-bit encoding, TST (immediate) does not.
5838           static_assert(static_cast<uint32_t>(mirror::StringCompressionFlag::kCompressed) == 0u,
5839                         "Expecting 0=compressed, 1=uncompressed");
5840           __ b(&uncompressed_load, CS);
5841           __ ldrb(out_loc.AsRegister<Register>(),
5842                   Address(temp, index.AsRegister<Register>(), Shift::LSL, 0));
5843           __ b(final_label);
5844           __ Bind(&uncompressed_load);
5845           __ ldrh(out_loc.AsRegister<Register>(),
5846                   Address(temp, index.AsRegister<Register>(), Shift::LSL, 1));
5847           if (done.IsLinked()) {
5848             __ Bind(&done);
5849           }
5850         } else {
5851           codegen_->LoadFromShiftedRegOffset(type, out_loc, temp, index.AsRegister<Register>());
5852         }
5853       }
5854       break;
5855     }
5856 
5857     case Primitive::kPrimNot: {
5858       // The read barrier instrumentation of object ArrayGet
5859       // instructions does not support the HIntermediateAddress
5860       // instruction.
5861       DCHECK(!(has_intermediate_address && kEmitCompilerReadBarrier));
5862 
5863       static_assert(
5864           sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
5865           "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
5866       // /* HeapReference<Object> */ out =
5867       //     *(obj + data_offset + index * sizeof(HeapReference<Object>))
5868       if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
5869         Location temp = locations->GetTemp(0);
5870         // Note that a potential implicit null check is handled in this
5871         // CodeGeneratorARM::GenerateArrayLoadWithBakerReadBarrier call.
5872         codegen_->GenerateArrayLoadWithBakerReadBarrier(
5873             instruction, out_loc, obj, data_offset, index, temp, /* needs_null_check */ true);
5874       } else {
5875         Register out = out_loc.AsRegister<Register>();
5876         if (index.IsConstant()) {
5877           size_t offset =
5878               (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
5879           __ LoadFromOffset(kLoadWord, out, obj, offset);
5880           codegen_->MaybeRecordImplicitNullCheck(instruction);
5881           // If read barriers are enabled, emit read barriers other than
5882           // Baker's using a slow path (and also unpoison the loaded
5883           // reference, if heap poisoning is enabled).
5884           codegen_->MaybeGenerateReadBarrierSlow(instruction, out_loc, out_loc, obj_loc, offset);
5885         } else {
5886           Register temp = IP;
5887 
5888           if (has_intermediate_address) {
5889             // We do not need to compute the intermediate address from the array: the
5890             // input instruction has done it already. See the comment in
5891             // `TryExtractArrayAccessAddress()`.
5892             if (kIsDebugBuild) {
5893               HIntermediateAddress* tmp = array_instr->AsIntermediateAddress();
5894               DCHECK_EQ(tmp->GetOffset()->AsIntConstant()->GetValueAsUint64(), data_offset);
5895             }
5896             temp = obj;
5897           } else {
5898             __ add(temp, obj, ShifterOperand(data_offset));
5899           }
5900           codegen_->LoadFromShiftedRegOffset(type, out_loc, temp, index.AsRegister<Register>());
5901 
5902           codegen_->MaybeRecordImplicitNullCheck(instruction);
5903           // If read barriers are enabled, emit read barriers other than
5904           // Baker's using a slow path (and also unpoison the loaded
5905           // reference, if heap poisoning is enabled).
5906           codegen_->MaybeGenerateReadBarrierSlow(
5907               instruction, out_loc, out_loc, obj_loc, data_offset, index);
5908         }
5909       }
5910       break;
5911     }
5912 
5913     case Primitive::kPrimLong: {
5914       if (index.IsConstant()) {
5915         size_t offset =
5916             (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
5917         __ LoadFromOffset(kLoadWordPair, out_loc.AsRegisterPairLow<Register>(), obj, offset);
5918       } else {
5919         __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
5920         __ LoadFromOffset(kLoadWordPair, out_loc.AsRegisterPairLow<Register>(), IP, data_offset);
5921       }
5922       break;
5923     }
5924 
5925     case Primitive::kPrimFloat: {
5926       SRegister out = out_loc.AsFpuRegister<SRegister>();
5927       if (index.IsConstant()) {
5928         size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
5929         __ LoadSFromOffset(out, obj, offset);
5930       } else {
5931         __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
5932         __ LoadSFromOffset(out, IP, data_offset);
5933       }
5934       break;
5935     }
5936 
5937     case Primitive::kPrimDouble: {
5938       SRegister out = out_loc.AsFpuRegisterPairLow<SRegister>();
5939       if (index.IsConstant()) {
5940         size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
5941         __ LoadDFromOffset(FromLowSToD(out), obj, offset);
5942       } else {
5943         __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
5944         __ LoadDFromOffset(FromLowSToD(out), IP, data_offset);
5945       }
5946       break;
5947     }
5948 
5949     case Primitive::kPrimVoid:
5950       LOG(FATAL) << "Unreachable type " << type;
5951       UNREACHABLE();
5952   }
5953 
5954   if (type == Primitive::kPrimNot) {
5955     // Potential implicit null checks, in the case of reference
5956     // arrays, are handled in the previous switch statement.
5957   } else if (!maybe_compressed_char_at) {
5958     codegen_->MaybeRecordImplicitNullCheck(instruction);
5959   }
5960 }
5961 
VisitArraySet(HArraySet * instruction)5962 void LocationsBuilderARM::VisitArraySet(HArraySet* instruction) {
5963   Primitive::Type value_type = instruction->GetComponentType();
5964 
5965   bool needs_write_barrier =
5966       CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
5967   bool may_need_runtime_call_for_type_check = instruction->NeedsTypeCheck();
5968 
5969   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
5970       instruction,
5971       may_need_runtime_call_for_type_check ?
5972           LocationSummary::kCallOnSlowPath :
5973           LocationSummary::kNoCall);
5974 
5975   locations->SetInAt(0, Location::RequiresRegister());
5976   locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
5977   if (Primitive::IsFloatingPointType(value_type)) {
5978     locations->SetInAt(2, Location::RequiresFpuRegister());
5979   } else {
5980     locations->SetInAt(2, Location::RequiresRegister());
5981   }
5982   if (needs_write_barrier) {
5983     // Temporary registers for the write barrier.
5984     locations->AddTemp(Location::RequiresRegister());  // Possibly used for ref. poisoning too.
5985     locations->AddTemp(Location::RequiresRegister());
5986   }
5987 }
5988 
VisitArraySet(HArraySet * instruction)5989 void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) {
5990   LocationSummary* locations = instruction->GetLocations();
5991   Location array_loc = locations->InAt(0);
5992   Register array = array_loc.AsRegister<Register>();
5993   Location index = locations->InAt(1);
5994   Primitive::Type value_type = instruction->GetComponentType();
5995   bool may_need_runtime_call_for_type_check = instruction->NeedsTypeCheck();
5996   bool needs_write_barrier =
5997       CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
5998   uint32_t data_offset =
5999       mirror::Array::DataOffset(Primitive::ComponentSize(value_type)).Uint32Value();
6000   Location value_loc = locations->InAt(2);
6001   HInstruction* array_instr = instruction->GetArray();
6002   bool has_intermediate_address = array_instr->IsIntermediateAddress();
6003 
6004   switch (value_type) {
6005     case Primitive::kPrimBoolean:
6006     case Primitive::kPrimByte:
6007     case Primitive::kPrimShort:
6008     case Primitive::kPrimChar:
6009     case Primitive::kPrimInt: {
6010       if (index.IsConstant()) {
6011         int32_t const_index = index.GetConstant()->AsIntConstant()->GetValue();
6012         uint32_t full_offset =
6013             data_offset + (const_index << Primitive::ComponentSizeShift(value_type));
6014         StoreOperandType store_type = GetStoreOperandType(value_type);
6015         __ StoreToOffset(store_type, value_loc.AsRegister<Register>(), array, full_offset);
6016       } else {
6017         Register temp = IP;
6018 
6019         if (has_intermediate_address) {
6020           // We do not need to compute the intermediate address from the array: the
6021           // input instruction has done it already. See the comment in
6022           // `TryExtractArrayAccessAddress()`.
6023           if (kIsDebugBuild) {
6024             HIntermediateAddress* tmp = array_instr->AsIntermediateAddress();
6025             DCHECK(tmp->GetOffset()->AsIntConstant()->GetValueAsUint64() == data_offset);
6026           }
6027           temp = array;
6028         } else {
6029           __ add(temp, array, ShifterOperand(data_offset));
6030         }
6031         codegen_->StoreToShiftedRegOffset(value_type,
6032                                           value_loc,
6033                                           temp,
6034                                           index.AsRegister<Register>());
6035       }
6036       break;
6037     }
6038 
6039     case Primitive::kPrimNot: {
6040       Register value = value_loc.AsRegister<Register>();
6041       // TryExtractArrayAccessAddress optimization is never applied for non-primitive ArraySet.
6042       // See the comment in instruction_simplifier_shared.cc.
6043       DCHECK(!has_intermediate_address);
6044 
6045       if (instruction->InputAt(2)->IsNullConstant()) {
6046         // Just setting null.
6047         if (index.IsConstant()) {
6048           size_t offset =
6049               (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
6050           __ StoreToOffset(kStoreWord, value, array, offset);
6051         } else {
6052           DCHECK(index.IsRegister()) << index;
6053           __ add(IP, array, ShifterOperand(data_offset));
6054           codegen_->StoreToShiftedRegOffset(value_type,
6055                                             value_loc,
6056                                             IP,
6057                                             index.AsRegister<Register>());
6058         }
6059         codegen_->MaybeRecordImplicitNullCheck(instruction);
6060         DCHECK(!needs_write_barrier);
6061         DCHECK(!may_need_runtime_call_for_type_check);
6062         break;
6063       }
6064 
6065       DCHECK(needs_write_barrier);
6066       Location temp1_loc = locations->GetTemp(0);
6067       Register temp1 = temp1_loc.AsRegister<Register>();
6068       Location temp2_loc = locations->GetTemp(1);
6069       Register temp2 = temp2_loc.AsRegister<Register>();
6070       uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
6071       uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
6072       uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
6073       Label done;
6074       Label* final_label = codegen_->GetFinalLabel(instruction, &done);
6075       SlowPathCodeARM* slow_path = nullptr;
6076 
6077       if (may_need_runtime_call_for_type_check) {
6078         slow_path = new (GetGraph()->GetArena()) ArraySetSlowPathARM(instruction);
6079         codegen_->AddSlowPath(slow_path);
6080         if (instruction->GetValueCanBeNull()) {
6081           Label non_zero;
6082           __ CompareAndBranchIfNonZero(value, &non_zero);
6083           if (index.IsConstant()) {
6084             size_t offset =
6085                (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
6086             __ StoreToOffset(kStoreWord, value, array, offset);
6087           } else {
6088             DCHECK(index.IsRegister()) << index;
6089             __ add(IP, array, ShifterOperand(data_offset));
6090             codegen_->StoreToShiftedRegOffset(value_type,
6091                                               value_loc,
6092                                               IP,
6093                                               index.AsRegister<Register>());
6094           }
6095           codegen_->MaybeRecordImplicitNullCheck(instruction);
6096           __ b(final_label);
6097           __ Bind(&non_zero);
6098         }
6099 
6100         // Note that when read barriers are enabled, the type checks
6101         // are performed without read barriers.  This is fine, even in
6102         // the case where a class object is in the from-space after
6103         // the flip, as a comparison involving such a type would not
6104         // produce a false positive; it may of course produce a false
6105         // negative, in which case we would take the ArraySet slow
6106         // path.
6107 
6108         // /* HeapReference<Class> */ temp1 = array->klass_
6109         __ LoadFromOffset(kLoadWord, temp1, array, class_offset);
6110         codegen_->MaybeRecordImplicitNullCheck(instruction);
6111         __ MaybeUnpoisonHeapReference(temp1);
6112 
6113         // /* HeapReference<Class> */ temp1 = temp1->component_type_
6114         __ LoadFromOffset(kLoadWord, temp1, temp1, component_offset);
6115         // /* HeapReference<Class> */ temp2 = value->klass_
6116         __ LoadFromOffset(kLoadWord, temp2, value, class_offset);
6117         // If heap poisoning is enabled, no need to unpoison `temp1`
6118         // nor `temp2`, as we are comparing two poisoned references.
6119         __ cmp(temp1, ShifterOperand(temp2));
6120 
6121         if (instruction->StaticTypeOfArrayIsObjectArray()) {
6122           Label do_put;
6123           __ b(&do_put, EQ);
6124           // If heap poisoning is enabled, the `temp1` reference has
6125           // not been unpoisoned yet; unpoison it now.
6126           __ MaybeUnpoisonHeapReference(temp1);
6127 
6128           // /* HeapReference<Class> */ temp1 = temp1->super_class_
6129           __ LoadFromOffset(kLoadWord, temp1, temp1, super_offset);
6130           // If heap poisoning is enabled, no need to unpoison
6131           // `temp1`, as we are comparing against null below.
6132           __ CompareAndBranchIfNonZero(temp1, slow_path->GetEntryLabel());
6133           __ Bind(&do_put);
6134         } else {
6135           __ b(slow_path->GetEntryLabel(), NE);
6136         }
6137       }
6138 
6139       Register source = value;
6140       if (kPoisonHeapReferences) {
6141         // Note that in the case where `value` is a null reference,
6142         // we do not enter this block, as a null reference does not
6143         // need poisoning.
6144         DCHECK_EQ(value_type, Primitive::kPrimNot);
6145         __ Mov(temp1, value);
6146         __ PoisonHeapReference(temp1);
6147         source = temp1;
6148       }
6149 
6150       if (index.IsConstant()) {
6151         size_t offset =
6152             (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
6153         __ StoreToOffset(kStoreWord, source, array, offset);
6154       } else {
6155         DCHECK(index.IsRegister()) << index;
6156 
6157         __ add(IP, array, ShifterOperand(data_offset));
6158         codegen_->StoreToShiftedRegOffset(value_type,
6159                                           Location::RegisterLocation(source),
6160                                           IP,
6161                                           index.AsRegister<Register>());
6162       }
6163 
6164       if (!may_need_runtime_call_for_type_check) {
6165         codegen_->MaybeRecordImplicitNullCheck(instruction);
6166       }
6167 
6168       codegen_->MarkGCCard(temp1, temp2, array, value, instruction->GetValueCanBeNull());
6169 
6170       if (done.IsLinked()) {
6171         __ Bind(&done);
6172       }
6173 
6174       if (slow_path != nullptr) {
6175         __ Bind(slow_path->GetExitLabel());
6176       }
6177 
6178       break;
6179     }
6180 
6181     case Primitive::kPrimLong: {
6182       Location value = locations->InAt(2);
6183       if (index.IsConstant()) {
6184         size_t offset =
6185             (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
6186         __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), array, offset);
6187       } else {
6188         __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
6189         __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), IP, data_offset);
6190       }
6191       break;
6192     }
6193 
6194     case Primitive::kPrimFloat: {
6195       Location value = locations->InAt(2);
6196       DCHECK(value.IsFpuRegister());
6197       if (index.IsConstant()) {
6198         size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
6199         __ StoreSToOffset(value.AsFpuRegister<SRegister>(), array, offset);
6200       } else {
6201         __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
6202         __ StoreSToOffset(value.AsFpuRegister<SRegister>(), IP, data_offset);
6203       }
6204       break;
6205     }
6206 
6207     case Primitive::kPrimDouble: {
6208       Location value = locations->InAt(2);
6209       DCHECK(value.IsFpuRegisterPair());
6210       if (index.IsConstant()) {
6211         size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
6212         __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), array, offset);
6213       } else {
6214         __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
6215         __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), IP, data_offset);
6216       }
6217 
6218       break;
6219     }
6220 
6221     case Primitive::kPrimVoid:
6222       LOG(FATAL) << "Unreachable type " << value_type;
6223       UNREACHABLE();
6224   }
6225 
6226   // Objects are handled in the switch.
6227   if (value_type != Primitive::kPrimNot) {
6228     codegen_->MaybeRecordImplicitNullCheck(instruction);
6229   }
6230 }
6231 
VisitArrayLength(HArrayLength * instruction)6232 void LocationsBuilderARM::VisitArrayLength(HArrayLength* instruction) {
6233   LocationSummary* locations =
6234       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
6235   locations->SetInAt(0, Location::RequiresRegister());
6236   locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
6237 }
6238 
VisitArrayLength(HArrayLength * instruction)6239 void InstructionCodeGeneratorARM::VisitArrayLength(HArrayLength* instruction) {
6240   LocationSummary* locations = instruction->GetLocations();
6241   uint32_t offset = CodeGenerator::GetArrayLengthOffset(instruction);
6242   Register obj = locations->InAt(0).AsRegister<Register>();
6243   Register out = locations->Out().AsRegister<Register>();
6244   __ LoadFromOffset(kLoadWord, out, obj, offset);
6245   codegen_->MaybeRecordImplicitNullCheck(instruction);
6246   // Mask out compression flag from String's array length.
6247   if (mirror::kUseStringCompression && instruction->IsStringLength()) {
6248     __ Lsr(out, out, 1u);
6249   }
6250 }
6251 
VisitIntermediateAddress(HIntermediateAddress * instruction)6252 void LocationsBuilderARM::VisitIntermediateAddress(HIntermediateAddress* instruction) {
6253   LocationSummary* locations =
6254       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
6255 
6256   locations->SetInAt(0, Location::RequiresRegister());
6257   locations->SetInAt(1, Location::RegisterOrConstant(instruction->GetOffset()));
6258   locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
6259 }
6260 
VisitIntermediateAddress(HIntermediateAddress * instruction)6261 void InstructionCodeGeneratorARM::VisitIntermediateAddress(HIntermediateAddress* instruction) {
6262   LocationSummary* locations = instruction->GetLocations();
6263   Location out = locations->Out();
6264   Location first = locations->InAt(0);
6265   Location second = locations->InAt(1);
6266 
6267   if (second.IsRegister()) {
6268     __ add(out.AsRegister<Register>(),
6269            first.AsRegister<Register>(),
6270            ShifterOperand(second.AsRegister<Register>()));
6271   } else {
6272     __ AddConstant(out.AsRegister<Register>(),
6273                    first.AsRegister<Register>(),
6274                    second.GetConstant()->AsIntConstant()->GetValue());
6275   }
6276 }
6277 
VisitBoundsCheck(HBoundsCheck * instruction)6278 void LocationsBuilderARM::VisitBoundsCheck(HBoundsCheck* instruction) {
6279   RegisterSet caller_saves = RegisterSet::Empty();
6280   InvokeRuntimeCallingConvention calling_convention;
6281   caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
6282   caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
6283   LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction, caller_saves);
6284 
6285   HInstruction* index = instruction->InputAt(0);
6286   HInstruction* length = instruction->InputAt(1);
6287   // If both index and length are constants we can statically check the bounds. But if at least one
6288   // of them is not encodable ArmEncodableConstantOrRegister will create
6289   // Location::RequiresRegister() which is not desired to happen. Instead we create constant
6290   // locations.
6291   bool both_const = index->IsConstant() && length->IsConstant();
6292   locations->SetInAt(0, both_const
6293       ? Location::ConstantLocation(index->AsConstant())
6294       : ArmEncodableConstantOrRegister(index, CMP));
6295   locations->SetInAt(1, both_const
6296       ? Location::ConstantLocation(length->AsConstant())
6297       : ArmEncodableConstantOrRegister(length, CMP));
6298 }
6299 
VisitBoundsCheck(HBoundsCheck * instruction)6300 void InstructionCodeGeneratorARM::VisitBoundsCheck(HBoundsCheck* instruction) {
6301   LocationSummary* locations = instruction->GetLocations();
6302   Location index_loc = locations->InAt(0);
6303   Location length_loc = locations->InAt(1);
6304 
6305   if (length_loc.IsConstant()) {
6306     int32_t length = helpers::Int32ConstantFrom(length_loc);
6307     if (index_loc.IsConstant()) {
6308       // BCE will remove the bounds check if we are guaranteed to pass.
6309       int32_t index = helpers::Int32ConstantFrom(index_loc);
6310       if (index < 0 || index >= length) {
6311         SlowPathCodeARM* slow_path =
6312             new (GetGraph()->GetArena()) BoundsCheckSlowPathARM(instruction);
6313         codegen_->AddSlowPath(slow_path);
6314         __ b(slow_path->GetEntryLabel());
6315       } else {
6316         // Some optimization after BCE may have generated this, and we should not
6317         // generate a bounds check if it is a valid range.
6318       }
6319       return;
6320     }
6321 
6322     SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathARM(instruction);
6323     __ cmp(index_loc.AsRegister<Register>(), ShifterOperand(length));
6324     codegen_->AddSlowPath(slow_path);
6325     __ b(slow_path->GetEntryLabel(), HS);
6326   } else {
6327     SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathARM(instruction);
6328     if (index_loc.IsConstant()) {
6329       int32_t index = helpers::Int32ConstantFrom(index_loc);
6330       __ cmp(length_loc.AsRegister<Register>(), ShifterOperand(index));
6331     } else {
6332       __ cmp(length_loc.AsRegister<Register>(), ShifterOperand(index_loc.AsRegister<Register>()));
6333     }
6334     codegen_->AddSlowPath(slow_path);
6335     __ b(slow_path->GetEntryLabel(), LS);
6336   }
6337 }
6338 
MarkGCCard(Register temp,Register card,Register object,Register value,bool can_be_null)6339 void CodeGeneratorARM::MarkGCCard(Register temp,
6340                                   Register card,
6341                                   Register object,
6342                                   Register value,
6343                                   bool can_be_null) {
6344   Label is_null;
6345   if (can_be_null) {
6346     __ CompareAndBranchIfZero(value, &is_null);
6347   }
6348   __ LoadFromOffset(kLoadWord, card, TR, Thread::CardTableOffset<kArmPointerSize>().Int32Value());
6349   __ Lsr(temp, object, gc::accounting::CardTable::kCardShift);
6350   __ strb(card, Address(card, temp));
6351   if (can_be_null) {
6352     __ Bind(&is_null);
6353   }
6354 }
6355 
VisitParallelMove(HParallelMove * instruction ATTRIBUTE_UNUSED)6356 void LocationsBuilderARM::VisitParallelMove(HParallelMove* instruction ATTRIBUTE_UNUSED) {
6357   LOG(FATAL) << "Unreachable";
6358 }
6359 
VisitParallelMove(HParallelMove * instruction)6360 void InstructionCodeGeneratorARM::VisitParallelMove(HParallelMove* instruction) {
6361   codegen_->GetMoveResolver()->EmitNativeCode(instruction);
6362 }
6363 
VisitSuspendCheck(HSuspendCheck * instruction)6364 void LocationsBuilderARM::VisitSuspendCheck(HSuspendCheck* instruction) {
6365   LocationSummary* locations =
6366       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
6367   locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty());  // No caller-save registers.
6368 }
6369 
VisitSuspendCheck(HSuspendCheck * instruction)6370 void InstructionCodeGeneratorARM::VisitSuspendCheck(HSuspendCheck* instruction) {
6371   HBasicBlock* block = instruction->GetBlock();
6372   if (block->GetLoopInformation() != nullptr) {
6373     DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
6374     // The back edge will generate the suspend check.
6375     return;
6376   }
6377   if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
6378     // The goto will generate the suspend check.
6379     return;
6380   }
6381   GenerateSuspendCheck(instruction, nullptr);
6382 }
6383 
GenerateSuspendCheck(HSuspendCheck * instruction,HBasicBlock * successor)6384 void InstructionCodeGeneratorARM::GenerateSuspendCheck(HSuspendCheck* instruction,
6385                                                        HBasicBlock* successor) {
6386   SuspendCheckSlowPathARM* slow_path =
6387       down_cast<SuspendCheckSlowPathARM*>(instruction->GetSlowPath());
6388   if (slow_path == nullptr) {
6389     slow_path = new (GetGraph()->GetArena()) SuspendCheckSlowPathARM(instruction, successor);
6390     instruction->SetSlowPath(slow_path);
6391     codegen_->AddSlowPath(slow_path);
6392     if (successor != nullptr) {
6393       DCHECK(successor->IsLoopHeader());
6394       codegen_->ClearSpillSlotsFromLoopPhisInStackMap(instruction);
6395     }
6396   } else {
6397     DCHECK_EQ(slow_path->GetSuccessor(), successor);
6398   }
6399 
6400   __ LoadFromOffset(
6401       kLoadUnsignedHalfword, IP, TR, Thread::ThreadFlagsOffset<kArmPointerSize>().Int32Value());
6402   if (successor == nullptr) {
6403     __ CompareAndBranchIfNonZero(IP, slow_path->GetEntryLabel());
6404     __ Bind(slow_path->GetReturnLabel());
6405   } else {
6406     __ CompareAndBranchIfZero(IP, codegen_->GetLabelOf(successor));
6407     __ b(slow_path->GetEntryLabel());
6408   }
6409 }
6410 
GetAssembler() const6411 ArmAssembler* ParallelMoveResolverARM::GetAssembler() const {
6412   return codegen_->GetAssembler();
6413 }
6414 
EmitMove(size_t index)6415 void ParallelMoveResolverARM::EmitMove(size_t index) {
6416   MoveOperands* move = moves_[index];
6417   Location source = move->GetSource();
6418   Location destination = move->GetDestination();
6419 
6420   if (source.IsRegister()) {
6421     if (destination.IsRegister()) {
6422       __ Mov(destination.AsRegister<Register>(), source.AsRegister<Register>());
6423     } else if (destination.IsFpuRegister()) {
6424       __ vmovsr(destination.AsFpuRegister<SRegister>(), source.AsRegister<Register>());
6425     } else {
6426       DCHECK(destination.IsStackSlot());
6427       __ StoreToOffset(kStoreWord, source.AsRegister<Register>(),
6428                        SP, destination.GetStackIndex());
6429     }
6430   } else if (source.IsStackSlot()) {
6431     if (destination.IsRegister()) {
6432       __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(),
6433                         SP, source.GetStackIndex());
6434     } else if (destination.IsFpuRegister()) {
6435       __ LoadSFromOffset(destination.AsFpuRegister<SRegister>(), SP, source.GetStackIndex());
6436     } else {
6437       DCHECK(destination.IsStackSlot());
6438       __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
6439       __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
6440     }
6441   } else if (source.IsFpuRegister()) {
6442     if (destination.IsRegister()) {
6443       __ vmovrs(destination.AsRegister<Register>(), source.AsFpuRegister<SRegister>());
6444     } else if (destination.IsFpuRegister()) {
6445       __ vmovs(destination.AsFpuRegister<SRegister>(), source.AsFpuRegister<SRegister>());
6446     } else {
6447       DCHECK(destination.IsStackSlot());
6448       __ StoreSToOffset(source.AsFpuRegister<SRegister>(), SP, destination.GetStackIndex());
6449     }
6450   } else if (source.IsDoubleStackSlot()) {
6451     if (destination.IsDoubleStackSlot()) {
6452       __ LoadDFromOffset(DTMP, SP, source.GetStackIndex());
6453       __ StoreDToOffset(DTMP, SP, destination.GetStackIndex());
6454     } else if (destination.IsRegisterPair()) {
6455       DCHECK(ExpectedPairLayout(destination));
6456       __ LoadFromOffset(
6457           kLoadWordPair, destination.AsRegisterPairLow<Register>(), SP, source.GetStackIndex());
6458     } else {
6459       DCHECK(destination.IsFpuRegisterPair()) << destination;
6460       __ LoadDFromOffset(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
6461                          SP,
6462                          source.GetStackIndex());
6463     }
6464   } else if (source.IsRegisterPair()) {
6465     if (destination.IsRegisterPair()) {
6466       __ Mov(destination.AsRegisterPairLow<Register>(), source.AsRegisterPairLow<Register>());
6467       __ Mov(destination.AsRegisterPairHigh<Register>(), source.AsRegisterPairHigh<Register>());
6468     } else if (destination.IsFpuRegisterPair()) {
6469       __ vmovdrr(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
6470                  source.AsRegisterPairLow<Register>(),
6471                  source.AsRegisterPairHigh<Register>());
6472     } else {
6473       DCHECK(destination.IsDoubleStackSlot()) << destination;
6474       DCHECK(ExpectedPairLayout(source));
6475       __ StoreToOffset(
6476           kStoreWordPair, source.AsRegisterPairLow<Register>(), SP, destination.GetStackIndex());
6477     }
6478   } else if (source.IsFpuRegisterPair()) {
6479     if (destination.IsRegisterPair()) {
6480       __ vmovrrd(destination.AsRegisterPairLow<Register>(),
6481                  destination.AsRegisterPairHigh<Register>(),
6482                  FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()));
6483     } else if (destination.IsFpuRegisterPair()) {
6484       __ vmovd(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
6485                FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()));
6486     } else {
6487       DCHECK(destination.IsDoubleStackSlot()) << destination;
6488       __ StoreDToOffset(FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()),
6489                         SP,
6490                         destination.GetStackIndex());
6491     }
6492   } else {
6493     DCHECK(source.IsConstant()) << source;
6494     HConstant* constant = source.GetConstant();
6495     if (constant->IsIntConstant() || constant->IsNullConstant()) {
6496       int32_t value = CodeGenerator::GetInt32ValueOf(constant);
6497       if (destination.IsRegister()) {
6498         __ LoadImmediate(destination.AsRegister<Register>(), value);
6499       } else {
6500         DCHECK(destination.IsStackSlot());
6501         __ LoadImmediate(IP, value);
6502         __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
6503       }
6504     } else if (constant->IsLongConstant()) {
6505       int64_t value = constant->AsLongConstant()->GetValue();
6506       if (destination.IsRegisterPair()) {
6507         __ LoadImmediate(destination.AsRegisterPairLow<Register>(), Low32Bits(value));
6508         __ LoadImmediate(destination.AsRegisterPairHigh<Register>(), High32Bits(value));
6509       } else {
6510         DCHECK(destination.IsDoubleStackSlot()) << destination;
6511         __ LoadImmediate(IP, Low32Bits(value));
6512         __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
6513         __ LoadImmediate(IP, High32Bits(value));
6514         __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
6515       }
6516     } else if (constant->IsDoubleConstant()) {
6517       double value = constant->AsDoubleConstant()->GetValue();
6518       if (destination.IsFpuRegisterPair()) {
6519         __ LoadDImmediate(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()), value);
6520       } else {
6521         DCHECK(destination.IsDoubleStackSlot()) << destination;
6522         uint64_t int_value = bit_cast<uint64_t, double>(value);
6523         __ LoadImmediate(IP, Low32Bits(int_value));
6524         __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
6525         __ LoadImmediate(IP, High32Bits(int_value));
6526         __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
6527       }
6528     } else {
6529       DCHECK(constant->IsFloatConstant()) << constant->DebugName();
6530       float value = constant->AsFloatConstant()->GetValue();
6531       if (destination.IsFpuRegister()) {
6532         __ LoadSImmediate(destination.AsFpuRegister<SRegister>(), value);
6533       } else {
6534         DCHECK(destination.IsStackSlot());
6535         __ LoadImmediate(IP, bit_cast<int32_t, float>(value));
6536         __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
6537       }
6538     }
6539   }
6540 }
6541 
Exchange(Register reg,int mem)6542 void ParallelMoveResolverARM::Exchange(Register reg, int mem) {
6543   __ Mov(IP, reg);
6544   __ LoadFromOffset(kLoadWord, reg, SP, mem);
6545   __ StoreToOffset(kStoreWord, IP, SP, mem);
6546 }
6547 
Exchange(int mem1,int mem2)6548 void ParallelMoveResolverARM::Exchange(int mem1, int mem2) {
6549   ScratchRegisterScope ensure_scratch(this, IP, R0, codegen_->GetNumberOfCoreRegisters());
6550   int stack_offset = ensure_scratch.IsSpilled() ? kArmWordSize : 0;
6551   __ LoadFromOffset(kLoadWord, static_cast<Register>(ensure_scratch.GetRegister()),
6552                     SP, mem1 + stack_offset);
6553   __ LoadFromOffset(kLoadWord, IP, SP, mem2 + stack_offset);
6554   __ StoreToOffset(kStoreWord, static_cast<Register>(ensure_scratch.GetRegister()),
6555                    SP, mem2 + stack_offset);
6556   __ StoreToOffset(kStoreWord, IP, SP, mem1 + stack_offset);
6557 }
6558 
EmitSwap(size_t index)6559 void ParallelMoveResolverARM::EmitSwap(size_t index) {
6560   MoveOperands* move = moves_[index];
6561   Location source = move->GetSource();
6562   Location destination = move->GetDestination();
6563 
6564   if (source.IsRegister() && destination.IsRegister()) {
6565     DCHECK_NE(source.AsRegister<Register>(), IP);
6566     DCHECK_NE(destination.AsRegister<Register>(), IP);
6567     __ Mov(IP, source.AsRegister<Register>());
6568     __ Mov(source.AsRegister<Register>(), destination.AsRegister<Register>());
6569     __ Mov(destination.AsRegister<Register>(), IP);
6570   } else if (source.IsRegister() && destination.IsStackSlot()) {
6571     Exchange(source.AsRegister<Register>(), destination.GetStackIndex());
6572   } else if (source.IsStackSlot() && destination.IsRegister()) {
6573     Exchange(destination.AsRegister<Register>(), source.GetStackIndex());
6574   } else if (source.IsStackSlot() && destination.IsStackSlot()) {
6575     Exchange(source.GetStackIndex(), destination.GetStackIndex());
6576   } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
6577     __ vmovrs(IP, source.AsFpuRegister<SRegister>());
6578     __ vmovs(source.AsFpuRegister<SRegister>(), destination.AsFpuRegister<SRegister>());
6579     __ vmovsr(destination.AsFpuRegister<SRegister>(), IP);
6580   } else if (source.IsRegisterPair() && destination.IsRegisterPair()) {
6581     __ vmovdrr(DTMP, source.AsRegisterPairLow<Register>(), source.AsRegisterPairHigh<Register>());
6582     __ Mov(source.AsRegisterPairLow<Register>(), destination.AsRegisterPairLow<Register>());
6583     __ Mov(source.AsRegisterPairHigh<Register>(), destination.AsRegisterPairHigh<Register>());
6584     __ vmovrrd(destination.AsRegisterPairLow<Register>(),
6585                destination.AsRegisterPairHigh<Register>(),
6586                DTMP);
6587   } else if (source.IsRegisterPair() || destination.IsRegisterPair()) {
6588     Register low_reg = source.IsRegisterPair()
6589         ? source.AsRegisterPairLow<Register>()
6590         : destination.AsRegisterPairLow<Register>();
6591     int mem = source.IsRegisterPair()
6592         ? destination.GetStackIndex()
6593         : source.GetStackIndex();
6594     DCHECK(ExpectedPairLayout(source.IsRegisterPair() ? source : destination));
6595     __ vmovdrr(DTMP, low_reg, static_cast<Register>(low_reg + 1));
6596     __ LoadFromOffset(kLoadWordPair, low_reg, SP, mem);
6597     __ StoreDToOffset(DTMP, SP, mem);
6598   } else if (source.IsFpuRegisterPair() && destination.IsFpuRegisterPair()) {
6599     DRegister first = FromLowSToD(source.AsFpuRegisterPairLow<SRegister>());
6600     DRegister second = FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>());
6601     __ vmovd(DTMP, first);
6602     __ vmovd(first, second);
6603     __ vmovd(second, DTMP);
6604   } else if (source.IsFpuRegisterPair() || destination.IsFpuRegisterPair()) {
6605     DRegister reg = source.IsFpuRegisterPair()
6606         ? FromLowSToD(source.AsFpuRegisterPairLow<SRegister>())
6607         : FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>());
6608     int mem = source.IsFpuRegisterPair()
6609         ? destination.GetStackIndex()
6610         : source.GetStackIndex();
6611     __ vmovd(DTMP, reg);
6612     __ LoadDFromOffset(reg, SP, mem);
6613     __ StoreDToOffset(DTMP, SP, mem);
6614   } else if (source.IsFpuRegister() || destination.IsFpuRegister()) {
6615     SRegister reg = source.IsFpuRegister() ? source.AsFpuRegister<SRegister>()
6616                                            : destination.AsFpuRegister<SRegister>();
6617     int mem = source.IsFpuRegister()
6618         ? destination.GetStackIndex()
6619         : source.GetStackIndex();
6620 
6621     __ vmovrs(IP, reg);
6622     __ LoadSFromOffset(reg, SP, mem);
6623     __ StoreToOffset(kStoreWord, IP, SP, mem);
6624   } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
6625     Exchange(source.GetStackIndex(), destination.GetStackIndex());
6626     Exchange(source.GetHighStackIndex(kArmWordSize), destination.GetHighStackIndex(kArmWordSize));
6627   } else {
6628     LOG(FATAL) << "Unimplemented" << source << " <-> " << destination;
6629   }
6630 }
6631 
SpillScratch(int reg)6632 void ParallelMoveResolverARM::SpillScratch(int reg) {
6633   __ Push(static_cast<Register>(reg));
6634 }
6635 
RestoreScratch(int reg)6636 void ParallelMoveResolverARM::RestoreScratch(int reg) {
6637   __ Pop(static_cast<Register>(reg));
6638 }
6639 
GetSupportedLoadClassKind(HLoadClass::LoadKind desired_class_load_kind)6640 HLoadClass::LoadKind CodeGeneratorARM::GetSupportedLoadClassKind(
6641     HLoadClass::LoadKind desired_class_load_kind) {
6642   switch (desired_class_load_kind) {
6643     case HLoadClass::LoadKind::kInvalid:
6644       LOG(FATAL) << "UNREACHABLE";
6645       UNREACHABLE();
6646     case HLoadClass::LoadKind::kReferrersClass:
6647       break;
6648     case HLoadClass::LoadKind::kBootImageLinkTimeAddress:
6649       DCHECK(!GetCompilerOptions().GetCompilePic());
6650       break;
6651     case HLoadClass::LoadKind::kBootImageLinkTimePcRelative:
6652       DCHECK(GetCompilerOptions().GetCompilePic());
6653       break;
6654     case HLoadClass::LoadKind::kBootImageAddress:
6655       break;
6656     case HLoadClass::LoadKind::kBssEntry:
6657       DCHECK(!Runtime::Current()->UseJitCompilation());
6658       break;
6659     case HLoadClass::LoadKind::kJitTableAddress:
6660       DCHECK(Runtime::Current()->UseJitCompilation());
6661       break;
6662     case HLoadClass::LoadKind::kDexCacheViaMethod:
6663       break;
6664   }
6665   return desired_class_load_kind;
6666 }
6667 
VisitLoadClass(HLoadClass * cls)6668 void LocationsBuilderARM::VisitLoadClass(HLoadClass* cls) {
6669   HLoadClass::LoadKind load_kind = cls->GetLoadKind();
6670   if (load_kind == HLoadClass::LoadKind::kDexCacheViaMethod) {
6671     InvokeRuntimeCallingConvention calling_convention;
6672     CodeGenerator::CreateLoadClassRuntimeCallLocationSummary(
6673         cls,
6674         Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
6675         Location::RegisterLocation(R0));
6676     DCHECK_EQ(calling_convention.GetRegisterAt(0), R0);
6677     return;
6678   }
6679   DCHECK(!cls->NeedsAccessCheck());
6680 
6681   const bool requires_read_barrier = kEmitCompilerReadBarrier && !cls->IsInBootImage();
6682   LocationSummary::CallKind call_kind = (cls->NeedsEnvironment() || requires_read_barrier)
6683       ? LocationSummary::kCallOnSlowPath
6684       : LocationSummary::kNoCall;
6685   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
6686   if (kUseBakerReadBarrier && requires_read_barrier && !cls->NeedsEnvironment()) {
6687     locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty());  // No caller-save registers.
6688   }
6689 
6690   if (load_kind == HLoadClass::LoadKind::kReferrersClass) {
6691     locations->SetInAt(0, Location::RequiresRegister());
6692   }
6693   locations->SetOut(Location::RequiresRegister());
6694   if (load_kind == HLoadClass::LoadKind::kBssEntry) {
6695     if (!kUseReadBarrier || kUseBakerReadBarrier) {
6696       // Rely on the type resolution or initialization and marking to save everything we need.
6697       // Note that IP may be clobbered by saving/restoring the live register (only one thanks
6698       // to the custom calling convention) or by marking, so we request a different temp.
6699       locations->AddTemp(Location::RequiresRegister());
6700       RegisterSet caller_saves = RegisterSet::Empty();
6701       InvokeRuntimeCallingConvention calling_convention;
6702       caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
6703       // TODO: Add GetReturnLocation() to the calling convention so that we can DCHECK()
6704       // that the the kPrimNot result register is the same as the first argument register.
6705       locations->SetCustomSlowPathCallerSaves(caller_saves);
6706     } else {
6707       // For non-Baker read barrier we have a temp-clobbering call.
6708     }
6709   }
6710 }
6711 
6712 // NO_THREAD_SAFETY_ANALYSIS as we manipulate handles whose internal object we know does not
6713 // move.
VisitLoadClass(HLoadClass * cls)6714 void InstructionCodeGeneratorARM::VisitLoadClass(HLoadClass* cls) NO_THREAD_SAFETY_ANALYSIS {
6715   HLoadClass::LoadKind load_kind = cls->GetLoadKind();
6716   if (load_kind == HLoadClass::LoadKind::kDexCacheViaMethod) {
6717     codegen_->GenerateLoadClassRuntimeCall(cls);
6718     return;
6719   }
6720   DCHECK(!cls->NeedsAccessCheck());
6721 
6722   LocationSummary* locations = cls->GetLocations();
6723   Location out_loc = locations->Out();
6724   Register out = out_loc.AsRegister<Register>();
6725 
6726   const ReadBarrierOption read_barrier_option = cls->IsInBootImage()
6727       ? kWithoutReadBarrier
6728       : kCompilerReadBarrierOption;
6729   bool generate_null_check = false;
6730   switch (load_kind) {
6731     case HLoadClass::LoadKind::kReferrersClass: {
6732       DCHECK(!cls->CanCallRuntime());
6733       DCHECK(!cls->MustGenerateClinitCheck());
6734       // /* GcRoot<mirror::Class> */ out = current_method->declaring_class_
6735       Register current_method = locations->InAt(0).AsRegister<Register>();
6736       GenerateGcRootFieldLoad(cls,
6737                               out_loc,
6738                               current_method,
6739                               ArtMethod::DeclaringClassOffset().Int32Value(),
6740                               read_barrier_option);
6741       break;
6742     }
6743     case HLoadClass::LoadKind::kBootImageLinkTimeAddress: {
6744       DCHECK(codegen_->GetCompilerOptions().IsBootImage());
6745       DCHECK_EQ(read_barrier_option, kWithoutReadBarrier);
6746       __ LoadLiteral(out, codegen_->DeduplicateBootImageTypeLiteral(cls->GetDexFile(),
6747                                                                     cls->GetTypeIndex()));
6748       break;
6749     }
6750     case HLoadClass::LoadKind::kBootImageLinkTimePcRelative: {
6751       DCHECK(codegen_->GetCompilerOptions().IsBootImage());
6752       DCHECK_EQ(read_barrier_option, kWithoutReadBarrier);
6753       CodeGeneratorARM::PcRelativePatchInfo* labels =
6754           codegen_->NewPcRelativeTypePatch(cls->GetDexFile(), cls->GetTypeIndex());
6755       __ BindTrackedLabel(&labels->movw_label);
6756       __ movw(out, /* placeholder */ 0u);
6757       __ BindTrackedLabel(&labels->movt_label);
6758       __ movt(out, /* placeholder */ 0u);
6759       __ BindTrackedLabel(&labels->add_pc_label);
6760       __ add(out, out, ShifterOperand(PC));
6761       break;
6762     }
6763     case HLoadClass::LoadKind::kBootImageAddress: {
6764       DCHECK_EQ(read_barrier_option, kWithoutReadBarrier);
6765       uint32_t address = dchecked_integral_cast<uint32_t>(
6766           reinterpret_cast<uintptr_t>(cls->GetClass().Get()));
6767       DCHECK_NE(address, 0u);
6768       __ LoadLiteral(out, codegen_->DeduplicateBootImageAddressLiteral(address));
6769       break;
6770     }
6771     case HLoadClass::LoadKind::kBssEntry: {
6772       Register temp = (!kUseReadBarrier || kUseBakerReadBarrier)
6773           ? locations->GetTemp(0).AsRegister<Register>()
6774           : out;
6775       CodeGeneratorARM::PcRelativePatchInfo* labels =
6776           codegen_->NewTypeBssEntryPatch(cls->GetDexFile(), cls->GetTypeIndex());
6777       __ BindTrackedLabel(&labels->movw_label);
6778       __ movw(temp, /* placeholder */ 0u);
6779       __ BindTrackedLabel(&labels->movt_label);
6780       __ movt(temp, /* placeholder */ 0u);
6781       __ BindTrackedLabel(&labels->add_pc_label);
6782       __ add(temp, temp, ShifterOperand(PC));
6783       GenerateGcRootFieldLoad(cls, out_loc, temp, /* offset */ 0, read_barrier_option);
6784       generate_null_check = true;
6785       break;
6786     }
6787     case HLoadClass::LoadKind::kJitTableAddress: {
6788       __ LoadLiteral(out, codegen_->DeduplicateJitClassLiteral(cls->GetDexFile(),
6789                                                                cls->GetTypeIndex(),
6790                                                                cls->GetClass()));
6791       // /* GcRoot<mirror::Class> */ out = *out
6792       GenerateGcRootFieldLoad(cls, out_loc, out, /* offset */ 0, read_barrier_option);
6793       break;
6794     }
6795     case HLoadClass::LoadKind::kDexCacheViaMethod:
6796     case HLoadClass::LoadKind::kInvalid:
6797       LOG(FATAL) << "UNREACHABLE";
6798       UNREACHABLE();
6799   }
6800 
6801   if (generate_null_check || cls->MustGenerateClinitCheck()) {
6802     DCHECK(cls->CanCallRuntime());
6803     SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
6804         cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
6805     codegen_->AddSlowPath(slow_path);
6806     if (generate_null_check) {
6807       __ CompareAndBranchIfZero(out, slow_path->GetEntryLabel());
6808     }
6809     if (cls->MustGenerateClinitCheck()) {
6810       GenerateClassInitializationCheck(slow_path, out);
6811     } else {
6812       __ Bind(slow_path->GetExitLabel());
6813     }
6814   }
6815 }
6816 
VisitClinitCheck(HClinitCheck * check)6817 void LocationsBuilderARM::VisitClinitCheck(HClinitCheck* check) {
6818   LocationSummary* locations =
6819       new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
6820   locations->SetInAt(0, Location::RequiresRegister());
6821   if (check->HasUses()) {
6822     locations->SetOut(Location::SameAsFirstInput());
6823   }
6824 }
6825 
VisitClinitCheck(HClinitCheck * check)6826 void InstructionCodeGeneratorARM::VisitClinitCheck(HClinitCheck* check) {
6827   // We assume the class is not null.
6828   SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
6829       check->GetLoadClass(), check, check->GetDexPc(), true);
6830   codegen_->AddSlowPath(slow_path);
6831   GenerateClassInitializationCheck(slow_path,
6832                                    check->GetLocations()->InAt(0).AsRegister<Register>());
6833 }
6834 
GenerateClassInitializationCheck(SlowPathCodeARM * slow_path,Register class_reg)6835 void InstructionCodeGeneratorARM::GenerateClassInitializationCheck(
6836     SlowPathCodeARM* slow_path, Register class_reg) {
6837   __ LoadFromOffset(kLoadWord, IP, class_reg, mirror::Class::StatusOffset().Int32Value());
6838   __ cmp(IP, ShifterOperand(mirror::Class::kStatusInitialized));
6839   __ b(slow_path->GetEntryLabel(), LT);
6840   // Even if the initialized flag is set, we may be in a situation where caches are not synced
6841   // properly. Therefore, we do a memory fence.
6842   __ dmb(ISH);
6843   __ Bind(slow_path->GetExitLabel());
6844 }
6845 
GetSupportedLoadStringKind(HLoadString::LoadKind desired_string_load_kind)6846 HLoadString::LoadKind CodeGeneratorARM::GetSupportedLoadStringKind(
6847     HLoadString::LoadKind desired_string_load_kind) {
6848   switch (desired_string_load_kind) {
6849     case HLoadString::LoadKind::kBootImageLinkTimeAddress:
6850       DCHECK(!GetCompilerOptions().GetCompilePic());
6851       break;
6852     case HLoadString::LoadKind::kBootImageLinkTimePcRelative:
6853       DCHECK(GetCompilerOptions().GetCompilePic());
6854       break;
6855     case HLoadString::LoadKind::kBootImageAddress:
6856       break;
6857     case HLoadString::LoadKind::kBssEntry:
6858       DCHECK(!Runtime::Current()->UseJitCompilation());
6859       break;
6860     case HLoadString::LoadKind::kJitTableAddress:
6861       DCHECK(Runtime::Current()->UseJitCompilation());
6862       break;
6863     case HLoadString::LoadKind::kDexCacheViaMethod:
6864       break;
6865   }
6866   return desired_string_load_kind;
6867 }
6868 
VisitLoadString(HLoadString * load)6869 void LocationsBuilderARM::VisitLoadString(HLoadString* load) {
6870   LocationSummary::CallKind call_kind = CodeGenerator::GetLoadStringCallKind(load);
6871   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(load, call_kind);
6872   HLoadString::LoadKind load_kind = load->GetLoadKind();
6873   if (load_kind == HLoadString::LoadKind::kDexCacheViaMethod) {
6874     locations->SetOut(Location::RegisterLocation(R0));
6875   } else {
6876     locations->SetOut(Location::RequiresRegister());
6877     if (load_kind == HLoadString::LoadKind::kBssEntry) {
6878       if (!kUseReadBarrier || kUseBakerReadBarrier) {
6879         // Rely on the pResolveString and marking to save everything we need, including temps.
6880         // Note that IP may be clobbered by saving/restoring the live register (only one thanks
6881         // to the custom calling convention) or by marking, so we request a different temp.
6882         locations->AddTemp(Location::RequiresRegister());
6883         RegisterSet caller_saves = RegisterSet::Empty();
6884         InvokeRuntimeCallingConvention calling_convention;
6885         caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
6886         // TODO: Add GetReturnLocation() to the calling convention so that we can DCHECK()
6887         // that the the kPrimNot result register is the same as the first argument register.
6888         locations->SetCustomSlowPathCallerSaves(caller_saves);
6889       } else {
6890         // For non-Baker read barrier we have a temp-clobbering call.
6891       }
6892     }
6893   }
6894 }
6895 
6896 // NO_THREAD_SAFETY_ANALYSIS as we manipulate handles whose internal object we know does not
6897 // move.
VisitLoadString(HLoadString * load)6898 void InstructionCodeGeneratorARM::VisitLoadString(HLoadString* load) NO_THREAD_SAFETY_ANALYSIS {
6899   LocationSummary* locations = load->GetLocations();
6900   Location out_loc = locations->Out();
6901   Register out = out_loc.AsRegister<Register>();
6902   HLoadString::LoadKind load_kind = load->GetLoadKind();
6903 
6904   switch (load_kind) {
6905     case HLoadString::LoadKind::kBootImageLinkTimeAddress: {
6906       DCHECK(codegen_->GetCompilerOptions().IsBootImage());
6907       __ LoadLiteral(out, codegen_->DeduplicateBootImageStringLiteral(load->GetDexFile(),
6908                                                                       load->GetStringIndex()));
6909       return;  // No dex cache slow path.
6910     }
6911     case HLoadString::LoadKind::kBootImageLinkTimePcRelative: {
6912       DCHECK(codegen_->GetCompilerOptions().IsBootImage());
6913       CodeGeneratorARM::PcRelativePatchInfo* labels =
6914           codegen_->NewPcRelativeStringPatch(load->GetDexFile(), load->GetStringIndex());
6915       __ BindTrackedLabel(&labels->movw_label);
6916       __ movw(out, /* placeholder */ 0u);
6917       __ BindTrackedLabel(&labels->movt_label);
6918       __ movt(out, /* placeholder */ 0u);
6919       __ BindTrackedLabel(&labels->add_pc_label);
6920       __ add(out, out, ShifterOperand(PC));
6921       return;  // No dex cache slow path.
6922     }
6923     case HLoadString::LoadKind::kBootImageAddress: {
6924       uint32_t address = dchecked_integral_cast<uint32_t>(
6925           reinterpret_cast<uintptr_t>(load->GetString().Get()));
6926       DCHECK_NE(address, 0u);
6927       __ LoadLiteral(out, codegen_->DeduplicateBootImageAddressLiteral(address));
6928       return;  // No dex cache slow path.
6929     }
6930     case HLoadString::LoadKind::kBssEntry: {
6931       DCHECK(!codegen_->GetCompilerOptions().IsBootImage());
6932       Register temp = (!kUseReadBarrier || kUseBakerReadBarrier)
6933           ? locations->GetTemp(0).AsRegister<Register>()
6934           : out;
6935       CodeGeneratorARM::PcRelativePatchInfo* labels =
6936           codegen_->NewPcRelativeStringPatch(load->GetDexFile(), load->GetStringIndex());
6937       __ BindTrackedLabel(&labels->movw_label);
6938       __ movw(temp, /* placeholder */ 0u);
6939       __ BindTrackedLabel(&labels->movt_label);
6940       __ movt(temp, /* placeholder */ 0u);
6941       __ BindTrackedLabel(&labels->add_pc_label);
6942       __ add(temp, temp, ShifterOperand(PC));
6943       GenerateGcRootFieldLoad(load, out_loc, temp, /* offset */ 0, kCompilerReadBarrierOption);
6944       SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathARM(load);
6945       codegen_->AddSlowPath(slow_path);
6946       __ CompareAndBranchIfZero(out, slow_path->GetEntryLabel());
6947       __ Bind(slow_path->GetExitLabel());
6948       return;
6949     }
6950     case HLoadString::LoadKind::kJitTableAddress: {
6951       __ LoadLiteral(out, codegen_->DeduplicateJitStringLiteral(load->GetDexFile(),
6952                                                                 load->GetStringIndex(),
6953                                                                 load->GetString()));
6954       // /* GcRoot<mirror::String> */ out = *out
6955       GenerateGcRootFieldLoad(load, out_loc, out, /* offset */ 0, kCompilerReadBarrierOption);
6956       return;
6957     }
6958     default:
6959       break;
6960   }
6961 
6962   // TODO: Consider re-adding the compiler code to do string dex cache lookup again.
6963   DCHECK(load_kind == HLoadString::LoadKind::kDexCacheViaMethod);
6964   InvokeRuntimeCallingConvention calling_convention;
6965   DCHECK_EQ(calling_convention.GetRegisterAt(0), out);
6966   __ LoadImmediate(calling_convention.GetRegisterAt(0), load->GetStringIndex().index_);
6967   codegen_->InvokeRuntime(kQuickResolveString, load, load->GetDexPc());
6968   CheckEntrypointTypes<kQuickResolveString, void*, uint32_t>();
6969 }
6970 
GetExceptionTlsOffset()6971 static int32_t GetExceptionTlsOffset() {
6972   return Thread::ExceptionOffset<kArmPointerSize>().Int32Value();
6973 }
6974 
VisitLoadException(HLoadException * load)6975 void LocationsBuilderARM::VisitLoadException(HLoadException* load) {
6976   LocationSummary* locations =
6977       new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
6978   locations->SetOut(Location::RequiresRegister());
6979 }
6980 
VisitLoadException(HLoadException * load)6981 void InstructionCodeGeneratorARM::VisitLoadException(HLoadException* load) {
6982   Register out = load->GetLocations()->Out().AsRegister<Register>();
6983   __ LoadFromOffset(kLoadWord, out, TR, GetExceptionTlsOffset());
6984 }
6985 
VisitClearException(HClearException * clear)6986 void LocationsBuilderARM::VisitClearException(HClearException* clear) {
6987   new (GetGraph()->GetArena()) LocationSummary(clear, LocationSummary::kNoCall);
6988 }
6989 
VisitClearException(HClearException * clear ATTRIBUTE_UNUSED)6990 void InstructionCodeGeneratorARM::VisitClearException(HClearException* clear ATTRIBUTE_UNUSED) {
6991   __ LoadImmediate(IP, 0);
6992   __ StoreToOffset(kStoreWord, IP, TR, GetExceptionTlsOffset());
6993 }
6994 
VisitThrow(HThrow * instruction)6995 void LocationsBuilderARM::VisitThrow(HThrow* instruction) {
6996   LocationSummary* locations =
6997       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
6998   InvokeRuntimeCallingConvention calling_convention;
6999   locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
7000 }
7001 
VisitThrow(HThrow * instruction)7002 void InstructionCodeGeneratorARM::VisitThrow(HThrow* instruction) {
7003   codegen_->InvokeRuntime(kQuickDeliverException, instruction, instruction->GetDexPc());
7004   CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>();
7005 }
7006 
7007 // Temp is used for read barrier.
NumberOfInstanceOfTemps(TypeCheckKind type_check_kind)7008 static size_t NumberOfInstanceOfTemps(TypeCheckKind type_check_kind) {
7009   if (kEmitCompilerReadBarrier &&
7010        (kUseBakerReadBarrier ||
7011           type_check_kind == TypeCheckKind::kAbstractClassCheck ||
7012           type_check_kind == TypeCheckKind::kClassHierarchyCheck ||
7013           type_check_kind == TypeCheckKind::kArrayObjectCheck)) {
7014     return 1;
7015   }
7016   return 0;
7017 }
7018 
7019 // Interface case has 3 temps, one for holding the number of interfaces, one for the current
7020 // interface pointer, one for loading the current interface.
7021 // The other checks have one temp for loading the object's class.
NumberOfCheckCastTemps(TypeCheckKind type_check_kind)7022 static size_t NumberOfCheckCastTemps(TypeCheckKind type_check_kind) {
7023   if (type_check_kind == TypeCheckKind::kInterfaceCheck) {
7024     return 3;
7025   }
7026   return 1 + NumberOfInstanceOfTemps(type_check_kind);
7027 }
7028 
VisitInstanceOf(HInstanceOf * instruction)7029 void LocationsBuilderARM::VisitInstanceOf(HInstanceOf* instruction) {
7030   LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
7031   TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
7032   bool baker_read_barrier_slow_path = false;
7033   switch (type_check_kind) {
7034     case TypeCheckKind::kExactCheck:
7035     case TypeCheckKind::kAbstractClassCheck:
7036     case TypeCheckKind::kClassHierarchyCheck:
7037     case TypeCheckKind::kArrayObjectCheck:
7038       call_kind =
7039           kEmitCompilerReadBarrier ? LocationSummary::kCallOnSlowPath : LocationSummary::kNoCall;
7040       baker_read_barrier_slow_path = kUseBakerReadBarrier;
7041       break;
7042     case TypeCheckKind::kArrayCheck:
7043     case TypeCheckKind::kUnresolvedCheck:
7044     case TypeCheckKind::kInterfaceCheck:
7045       call_kind = LocationSummary::kCallOnSlowPath;
7046       break;
7047   }
7048 
7049   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
7050   if (baker_read_barrier_slow_path) {
7051     locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty());  // No caller-save registers.
7052   }
7053   locations->SetInAt(0, Location::RequiresRegister());
7054   locations->SetInAt(1, Location::RequiresRegister());
7055   // The "out" register is used as a temporary, so it overlaps with the inputs.
7056   // Note that TypeCheckSlowPathARM uses this register too.
7057   locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
7058   locations->AddRegisterTemps(NumberOfInstanceOfTemps(type_check_kind));
7059 }
7060 
VisitInstanceOf(HInstanceOf * instruction)7061 void InstructionCodeGeneratorARM::VisitInstanceOf(HInstanceOf* instruction) {
7062   TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
7063   LocationSummary* locations = instruction->GetLocations();
7064   Location obj_loc = locations->InAt(0);
7065   Register obj = obj_loc.AsRegister<Register>();
7066   Register cls = locations->InAt(1).AsRegister<Register>();
7067   Location out_loc = locations->Out();
7068   Register out = out_loc.AsRegister<Register>();
7069   const size_t num_temps = NumberOfInstanceOfTemps(type_check_kind);
7070   DCHECK_LE(num_temps, 1u);
7071   Location maybe_temp_loc = (num_temps >= 1) ? locations->GetTemp(0) : Location::NoLocation();
7072   uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
7073   uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
7074   uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
7075   uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
7076   Label done;
7077   Label* const final_label = codegen_->GetFinalLabel(instruction, &done);
7078   SlowPathCodeARM* slow_path = nullptr;
7079 
7080   // Return 0 if `obj` is null.
7081   // avoid null check if we know obj is not null.
7082   if (instruction->MustDoNullCheck()) {
7083     DCHECK_NE(out, obj);
7084     __ LoadImmediate(out, 0);
7085     __ CompareAndBranchIfZero(obj, final_label);
7086   }
7087 
7088   switch (type_check_kind) {
7089     case TypeCheckKind::kExactCheck: {
7090       // /* HeapReference<Class> */ out = obj->klass_
7091       GenerateReferenceLoadTwoRegisters(instruction,
7092                                         out_loc,
7093                                         obj_loc,
7094                                         class_offset,
7095                                         maybe_temp_loc,
7096                                         kCompilerReadBarrierOption);
7097       // Classes must be equal for the instanceof to succeed.
7098       __ cmp(out, ShifterOperand(cls));
7099       // We speculatively set the result to false without changing the condition
7100       // flags, which allows us to avoid some branching later.
7101       __ mov(out, ShifterOperand(0), AL, kCcKeep);
7102 
7103       // Since IT blocks longer than a 16-bit instruction are deprecated by ARMv8,
7104       // we check that the output is in a low register, so that a 16-bit MOV
7105       // encoding can be used.
7106       if (ArmAssembler::IsLowRegister(out)) {
7107         __ it(EQ);
7108         __ mov(out, ShifterOperand(1), EQ);
7109       } else {
7110         __ b(final_label, NE);
7111         __ LoadImmediate(out, 1);
7112       }
7113 
7114       break;
7115     }
7116 
7117     case TypeCheckKind::kAbstractClassCheck: {
7118       // /* HeapReference<Class> */ out = obj->klass_
7119       GenerateReferenceLoadTwoRegisters(instruction,
7120                                         out_loc,
7121                                         obj_loc,
7122                                         class_offset,
7123                                         maybe_temp_loc,
7124                                         kCompilerReadBarrierOption);
7125       // If the class is abstract, we eagerly fetch the super class of the
7126       // object to avoid doing a comparison we know will fail.
7127       Label loop;
7128       __ Bind(&loop);
7129       // /* HeapReference<Class> */ out = out->super_class_
7130       GenerateReferenceLoadOneRegister(instruction,
7131                                        out_loc,
7132                                        super_offset,
7133                                        maybe_temp_loc,
7134                                        kCompilerReadBarrierOption);
7135       // If `out` is null, we use it for the result, and jump to the final label.
7136       __ CompareAndBranchIfZero(out, final_label);
7137       __ cmp(out, ShifterOperand(cls));
7138       __ b(&loop, NE);
7139       __ LoadImmediate(out, 1);
7140       break;
7141     }
7142 
7143     case TypeCheckKind::kClassHierarchyCheck: {
7144       // /* HeapReference<Class> */ out = obj->klass_
7145       GenerateReferenceLoadTwoRegisters(instruction,
7146                                         out_loc,
7147                                         obj_loc,
7148                                         class_offset,
7149                                         maybe_temp_loc,
7150                                         kCompilerReadBarrierOption);
7151       // Walk over the class hierarchy to find a match.
7152       Label loop, success;
7153       __ Bind(&loop);
7154       __ cmp(out, ShifterOperand(cls));
7155       __ b(&success, EQ);
7156       // /* HeapReference<Class> */ out = out->super_class_
7157       GenerateReferenceLoadOneRegister(instruction,
7158                                        out_loc,
7159                                        super_offset,
7160                                        maybe_temp_loc,
7161                                        kCompilerReadBarrierOption);
7162       // This is essentially a null check, but it sets the condition flags to the
7163       // proper value for the code that follows the loop, i.e. not `EQ`.
7164       __ cmp(out, ShifterOperand(1));
7165       __ b(&loop, HS);
7166 
7167       // Since IT blocks longer than a 16-bit instruction are deprecated by ARMv8,
7168       // we check that the output is in a low register, so that a 16-bit MOV
7169       // encoding can be used.
7170       if (ArmAssembler::IsLowRegister(out)) {
7171         // If `out` is null, we use it for the result, and the condition flags
7172         // have already been set to `NE`, so the IT block that comes afterwards
7173         // (and which handles the successful case) turns into a NOP (instead of
7174         // overwriting `out`).
7175         __ Bind(&success);
7176         // There is only one branch to the `success` label (which is bound to this
7177         // IT block), and it has the same condition, `EQ`, so in that case the MOV
7178         // is executed.
7179         __ it(EQ);
7180         __ mov(out, ShifterOperand(1), EQ);
7181       } else {
7182         // If `out` is null, we use it for the result, and jump to the final label.
7183         __ b(final_label);
7184         __ Bind(&success);
7185         __ LoadImmediate(out, 1);
7186       }
7187 
7188       break;
7189     }
7190 
7191     case TypeCheckKind::kArrayObjectCheck: {
7192       // /* HeapReference<Class> */ out = obj->klass_
7193       GenerateReferenceLoadTwoRegisters(instruction,
7194                                         out_loc,
7195                                         obj_loc,
7196                                         class_offset,
7197                                         maybe_temp_loc,
7198                                         kCompilerReadBarrierOption);
7199       // Do an exact check.
7200       Label exact_check;
7201       __ cmp(out, ShifterOperand(cls));
7202       __ b(&exact_check, EQ);
7203       // Otherwise, we need to check that the object's class is a non-primitive array.
7204       // /* HeapReference<Class> */ out = out->component_type_
7205       GenerateReferenceLoadOneRegister(instruction,
7206                                        out_loc,
7207                                        component_offset,
7208                                        maybe_temp_loc,
7209                                        kCompilerReadBarrierOption);
7210       // If `out` is null, we use it for the result, and jump to the final label.
7211       __ CompareAndBranchIfZero(out, final_label);
7212       __ LoadFromOffset(kLoadUnsignedHalfword, out, out, primitive_offset);
7213       static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot");
7214       __ cmp(out, ShifterOperand(0));
7215       // We speculatively set the result to false without changing the condition
7216       // flags, which allows us to avoid some branching later.
7217       __ mov(out, ShifterOperand(0), AL, kCcKeep);
7218 
7219       // Since IT blocks longer than a 16-bit instruction are deprecated by ARMv8,
7220       // we check that the output is in a low register, so that a 16-bit MOV
7221       // encoding can be used.
7222       if (ArmAssembler::IsLowRegister(out)) {
7223         __ Bind(&exact_check);
7224         __ it(EQ);
7225         __ mov(out, ShifterOperand(1), EQ);
7226       } else {
7227         __ b(final_label, NE);
7228         __ Bind(&exact_check);
7229         __ LoadImmediate(out, 1);
7230       }
7231 
7232       break;
7233     }
7234 
7235     case TypeCheckKind::kArrayCheck: {
7236       // No read barrier since the slow path will retry upon failure.
7237       // /* HeapReference<Class> */ out = obj->klass_
7238       GenerateReferenceLoadTwoRegisters(instruction,
7239                                         out_loc,
7240                                         obj_loc,
7241                                         class_offset,
7242                                         maybe_temp_loc,
7243                                         kWithoutReadBarrier);
7244       __ cmp(out, ShifterOperand(cls));
7245       DCHECK(locations->OnlyCallsOnSlowPath());
7246       slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(instruction,
7247                                                                     /* is_fatal */ false);
7248       codegen_->AddSlowPath(slow_path);
7249       __ b(slow_path->GetEntryLabel(), NE);
7250       __ LoadImmediate(out, 1);
7251       break;
7252     }
7253 
7254     case TypeCheckKind::kUnresolvedCheck:
7255     case TypeCheckKind::kInterfaceCheck: {
7256       // Note that we indeed only call on slow path, but we always go
7257       // into the slow path for the unresolved and interface check
7258       // cases.
7259       //
7260       // We cannot directly call the InstanceofNonTrivial runtime
7261       // entry point without resorting to a type checking slow path
7262       // here (i.e. by calling InvokeRuntime directly), as it would
7263       // require to assign fixed registers for the inputs of this
7264       // HInstanceOf instruction (following the runtime calling
7265       // convention), which might be cluttered by the potential first
7266       // read barrier emission at the beginning of this method.
7267       //
7268       // TODO: Introduce a new runtime entry point taking the object
7269       // to test (instead of its class) as argument, and let it deal
7270       // with the read barrier issues. This will let us refactor this
7271       // case of the `switch` code as it was previously (with a direct
7272       // call to the runtime not using a type checking slow path).
7273       // This should also be beneficial for the other cases above.
7274       DCHECK(locations->OnlyCallsOnSlowPath());
7275       slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(instruction,
7276                                                                     /* is_fatal */ false);
7277       codegen_->AddSlowPath(slow_path);
7278       __ b(slow_path->GetEntryLabel());
7279       break;
7280     }
7281   }
7282 
7283   if (done.IsLinked()) {
7284     __ Bind(&done);
7285   }
7286 
7287   if (slow_path != nullptr) {
7288     __ Bind(slow_path->GetExitLabel());
7289   }
7290 }
7291 
VisitCheckCast(HCheckCast * instruction)7292 void LocationsBuilderARM::VisitCheckCast(HCheckCast* instruction) {
7293   LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
7294   bool throws_into_catch = instruction->CanThrowIntoCatchBlock();
7295 
7296   TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
7297   switch (type_check_kind) {
7298     case TypeCheckKind::kExactCheck:
7299     case TypeCheckKind::kAbstractClassCheck:
7300     case TypeCheckKind::kClassHierarchyCheck:
7301     case TypeCheckKind::kArrayObjectCheck:
7302       call_kind = (throws_into_catch || kEmitCompilerReadBarrier) ?
7303           LocationSummary::kCallOnSlowPath :
7304           LocationSummary::kNoCall;  // In fact, call on a fatal (non-returning) slow path.
7305       break;
7306     case TypeCheckKind::kArrayCheck:
7307     case TypeCheckKind::kUnresolvedCheck:
7308     case TypeCheckKind::kInterfaceCheck:
7309       call_kind = LocationSummary::kCallOnSlowPath;
7310       break;
7311   }
7312 
7313   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
7314   locations->SetInAt(0, Location::RequiresRegister());
7315   locations->SetInAt(1, Location::RequiresRegister());
7316   locations->AddRegisterTemps(NumberOfCheckCastTemps(type_check_kind));
7317 }
7318 
VisitCheckCast(HCheckCast * instruction)7319 void InstructionCodeGeneratorARM::VisitCheckCast(HCheckCast* instruction) {
7320   TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
7321   LocationSummary* locations = instruction->GetLocations();
7322   Location obj_loc = locations->InAt(0);
7323   Register obj = obj_loc.AsRegister<Register>();
7324   Register cls = locations->InAt(1).AsRegister<Register>();
7325   Location temp_loc = locations->GetTemp(0);
7326   Register temp = temp_loc.AsRegister<Register>();
7327   const size_t num_temps = NumberOfCheckCastTemps(type_check_kind);
7328   DCHECK_LE(num_temps, 3u);
7329   Location maybe_temp2_loc = (num_temps >= 2) ? locations->GetTemp(1) : Location::NoLocation();
7330   Location maybe_temp3_loc = (num_temps >= 3) ? locations->GetTemp(2) : Location::NoLocation();
7331   const uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
7332   const uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
7333   const uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
7334   const uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
7335   const uint32_t iftable_offset = mirror::Class::IfTableOffset().Uint32Value();
7336   const uint32_t array_length_offset = mirror::Array::LengthOffset().Uint32Value();
7337   const uint32_t object_array_data_offset =
7338       mirror::Array::DataOffset(kHeapReferenceSize).Uint32Value();
7339 
7340   // Always false for read barriers since we may need to go to the entrypoint for non-fatal cases
7341   // from false negatives. The false negatives may come from avoiding read barriers below. Avoiding
7342   // read barriers is done for performance and code size reasons.
7343   bool is_type_check_slow_path_fatal = false;
7344   if (!kEmitCompilerReadBarrier) {
7345     is_type_check_slow_path_fatal =
7346         (type_check_kind == TypeCheckKind::kExactCheck ||
7347          type_check_kind == TypeCheckKind::kAbstractClassCheck ||
7348          type_check_kind == TypeCheckKind::kClassHierarchyCheck ||
7349          type_check_kind == TypeCheckKind::kArrayObjectCheck) &&
7350         !instruction->CanThrowIntoCatchBlock();
7351   }
7352   SlowPathCodeARM* type_check_slow_path =
7353       new (GetGraph()->GetArena()) TypeCheckSlowPathARM(instruction,
7354                                                         is_type_check_slow_path_fatal);
7355   codegen_->AddSlowPath(type_check_slow_path);
7356 
7357   Label done;
7358   Label* final_label = codegen_->GetFinalLabel(instruction, &done);
7359   // Avoid null check if we know obj is not null.
7360   if (instruction->MustDoNullCheck()) {
7361     __ CompareAndBranchIfZero(obj, final_label);
7362   }
7363 
7364   switch (type_check_kind) {
7365     case TypeCheckKind::kExactCheck:
7366     case TypeCheckKind::kArrayCheck: {
7367       // /* HeapReference<Class> */ temp = obj->klass_
7368       GenerateReferenceLoadTwoRegisters(instruction,
7369                                         temp_loc,
7370                                         obj_loc,
7371                                         class_offset,
7372                                         maybe_temp2_loc,
7373                                         kWithoutReadBarrier);
7374 
7375       __ cmp(temp, ShifterOperand(cls));
7376       // Jump to slow path for throwing the exception or doing a
7377       // more involved array check.
7378       __ b(type_check_slow_path->GetEntryLabel(), NE);
7379       break;
7380     }
7381 
7382     case TypeCheckKind::kAbstractClassCheck: {
7383       // /* HeapReference<Class> */ temp = obj->klass_
7384       GenerateReferenceLoadTwoRegisters(instruction,
7385                                         temp_loc,
7386                                         obj_loc,
7387                                         class_offset,
7388                                         maybe_temp2_loc,
7389                                         kWithoutReadBarrier);
7390 
7391       // If the class is abstract, we eagerly fetch the super class of the
7392       // object to avoid doing a comparison we know will fail.
7393       Label loop;
7394       __ Bind(&loop);
7395       // /* HeapReference<Class> */ temp = temp->super_class_
7396       GenerateReferenceLoadOneRegister(instruction,
7397                                        temp_loc,
7398                                        super_offset,
7399                                        maybe_temp2_loc,
7400                                        kWithoutReadBarrier);
7401 
7402       // If the class reference currently in `temp` is null, jump to the slow path to throw the
7403       // exception.
7404       __ CompareAndBranchIfZero(temp, type_check_slow_path->GetEntryLabel());
7405 
7406       // Otherwise, compare the classes.
7407       __ cmp(temp, ShifterOperand(cls));
7408       __ b(&loop, NE);
7409       break;
7410     }
7411 
7412     case TypeCheckKind::kClassHierarchyCheck: {
7413       // /* HeapReference<Class> */ temp = obj->klass_
7414       GenerateReferenceLoadTwoRegisters(instruction,
7415                                         temp_loc,
7416                                         obj_loc,
7417                                         class_offset,
7418                                         maybe_temp2_loc,
7419                                         kWithoutReadBarrier);
7420 
7421       // Walk over the class hierarchy to find a match.
7422       Label loop;
7423       __ Bind(&loop);
7424       __ cmp(temp, ShifterOperand(cls));
7425       __ b(final_label, EQ);
7426 
7427       // /* HeapReference<Class> */ temp = temp->super_class_
7428       GenerateReferenceLoadOneRegister(instruction,
7429                                        temp_loc,
7430                                        super_offset,
7431                                        maybe_temp2_loc,
7432                                        kWithoutReadBarrier);
7433 
7434       // If the class reference currently in `temp` is null, jump to the slow path to throw the
7435       // exception.
7436       __ CompareAndBranchIfZero(temp, type_check_slow_path->GetEntryLabel());
7437       // Otherwise, jump to the beginning of the loop.
7438       __ b(&loop);
7439       break;
7440     }
7441 
7442     case TypeCheckKind::kArrayObjectCheck: {
7443       // /* HeapReference<Class> */ temp = obj->klass_
7444       GenerateReferenceLoadTwoRegisters(instruction,
7445                                         temp_loc,
7446                                         obj_loc,
7447                                         class_offset,
7448                                         maybe_temp2_loc,
7449                                         kWithoutReadBarrier);
7450 
7451       // Do an exact check.
7452       __ cmp(temp, ShifterOperand(cls));
7453       __ b(final_label, EQ);
7454 
7455       // Otherwise, we need to check that the object's class is a non-primitive array.
7456       // /* HeapReference<Class> */ temp = temp->component_type_
7457       GenerateReferenceLoadOneRegister(instruction,
7458                                        temp_loc,
7459                                        component_offset,
7460                                        maybe_temp2_loc,
7461                                        kWithoutReadBarrier);
7462       // If the component type is null, jump to the slow path to throw the exception.
7463       __ CompareAndBranchIfZero(temp, type_check_slow_path->GetEntryLabel());
7464       // Otherwise,the object is indeed an array, jump to label `check_non_primitive_component_type`
7465       // to further check that this component type is not a primitive type.
7466       __ LoadFromOffset(kLoadUnsignedHalfword, temp, temp, primitive_offset);
7467       static_assert(Primitive::kPrimNot == 0, "Expected 0 for art::Primitive::kPrimNot");
7468       __ CompareAndBranchIfNonZero(temp, type_check_slow_path->GetEntryLabel());
7469       break;
7470     }
7471 
7472     case TypeCheckKind::kUnresolvedCheck:
7473       // We always go into the type check slow path for the unresolved check case.
7474       // We cannot directly call the CheckCast runtime entry point
7475       // without resorting to a type checking slow path here (i.e. by
7476       // calling InvokeRuntime directly), as it would require to
7477       // assign fixed registers for the inputs of this HInstanceOf
7478       // instruction (following the runtime calling convention), which
7479       // might be cluttered by the potential first read barrier
7480       // emission at the beginning of this method.
7481 
7482       __ b(type_check_slow_path->GetEntryLabel());
7483       break;
7484 
7485     case TypeCheckKind::kInterfaceCheck: {
7486       // Avoid read barriers to improve performance of the fast path. We can not get false
7487       // positives by doing this.
7488       // /* HeapReference<Class> */ temp = obj->klass_
7489       GenerateReferenceLoadTwoRegisters(instruction,
7490                                         temp_loc,
7491                                         obj_loc,
7492                                         class_offset,
7493                                         maybe_temp2_loc,
7494                                         kWithoutReadBarrier);
7495 
7496       // /* HeapReference<Class> */ temp = temp->iftable_
7497       GenerateReferenceLoadTwoRegisters(instruction,
7498                                         temp_loc,
7499                                         temp_loc,
7500                                         iftable_offset,
7501                                         maybe_temp2_loc,
7502                                         kWithoutReadBarrier);
7503       // Iftable is never null.
7504       __ ldr(maybe_temp2_loc.AsRegister<Register>(), Address(temp, array_length_offset));
7505       // Loop through the iftable and check if any class matches.
7506       Label start_loop;
7507       __ Bind(&start_loop);
7508       __ CompareAndBranchIfZero(maybe_temp2_loc.AsRegister<Register>(),
7509                                 type_check_slow_path->GetEntryLabel());
7510       __ ldr(maybe_temp3_loc.AsRegister<Register>(), Address(temp, object_array_data_offset));
7511       __ MaybeUnpoisonHeapReference(maybe_temp3_loc.AsRegister<Register>());
7512       // Go to next interface.
7513       __ add(temp, temp, ShifterOperand(2 * kHeapReferenceSize));
7514       __ sub(maybe_temp2_loc.AsRegister<Register>(),
7515              maybe_temp2_loc.AsRegister<Register>(),
7516              ShifterOperand(2));
7517       // Compare the classes and continue the loop if they do not match.
7518       __ cmp(cls, ShifterOperand(maybe_temp3_loc.AsRegister<Register>()));
7519       __ b(&start_loop, NE);
7520       break;
7521     }
7522   }
7523 
7524   if (done.IsLinked()) {
7525     __ Bind(&done);
7526   }
7527 
7528   __ Bind(type_check_slow_path->GetExitLabel());
7529 }
7530 
VisitMonitorOperation(HMonitorOperation * instruction)7531 void LocationsBuilderARM::VisitMonitorOperation(HMonitorOperation* instruction) {
7532   LocationSummary* locations =
7533       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
7534   InvokeRuntimeCallingConvention calling_convention;
7535   locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
7536 }
7537 
VisitMonitorOperation(HMonitorOperation * instruction)7538 void InstructionCodeGeneratorARM::VisitMonitorOperation(HMonitorOperation* instruction) {
7539   codegen_->InvokeRuntime(instruction->IsEnter() ? kQuickLockObject : kQuickUnlockObject,
7540                           instruction,
7541                           instruction->GetDexPc());
7542   if (instruction->IsEnter()) {
7543     CheckEntrypointTypes<kQuickLockObject, void, mirror::Object*>();
7544   } else {
7545     CheckEntrypointTypes<kQuickUnlockObject, void, mirror::Object*>();
7546   }
7547 }
7548 
VisitAnd(HAnd * instruction)7549 void LocationsBuilderARM::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction, AND); }
VisitOr(HOr * instruction)7550 void LocationsBuilderARM::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction, ORR); }
VisitXor(HXor * instruction)7551 void LocationsBuilderARM::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction, EOR); }
7552 
HandleBitwiseOperation(HBinaryOperation * instruction,Opcode opcode)7553 void LocationsBuilderARM::HandleBitwiseOperation(HBinaryOperation* instruction, Opcode opcode) {
7554   LocationSummary* locations =
7555       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
7556   DCHECK(instruction->GetResultType() == Primitive::kPrimInt
7557          || instruction->GetResultType() == Primitive::kPrimLong);
7558   // Note: GVN reorders commutative operations to have the constant on the right hand side.
7559   locations->SetInAt(0, Location::RequiresRegister());
7560   locations->SetInAt(1, ArmEncodableConstantOrRegister(instruction->InputAt(1), opcode));
7561   locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
7562 }
7563 
VisitAnd(HAnd * instruction)7564 void InstructionCodeGeneratorARM::VisitAnd(HAnd* instruction) {
7565   HandleBitwiseOperation(instruction);
7566 }
7567 
VisitOr(HOr * instruction)7568 void InstructionCodeGeneratorARM::VisitOr(HOr* instruction) {
7569   HandleBitwiseOperation(instruction);
7570 }
7571 
VisitXor(HXor * instruction)7572 void InstructionCodeGeneratorARM::VisitXor(HXor* instruction) {
7573   HandleBitwiseOperation(instruction);
7574 }
7575 
7576 
VisitBitwiseNegatedRight(HBitwiseNegatedRight * instruction)7577 void LocationsBuilderARM::VisitBitwiseNegatedRight(HBitwiseNegatedRight* instruction) {
7578   LocationSummary* locations =
7579       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
7580   DCHECK(instruction->GetResultType() == Primitive::kPrimInt
7581          || instruction->GetResultType() == Primitive::kPrimLong);
7582 
7583   locations->SetInAt(0, Location::RequiresRegister());
7584   locations->SetInAt(1, Location::RequiresRegister());
7585   locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
7586 }
7587 
VisitBitwiseNegatedRight(HBitwiseNegatedRight * instruction)7588 void InstructionCodeGeneratorARM::VisitBitwiseNegatedRight(HBitwiseNegatedRight* instruction) {
7589   LocationSummary* locations = instruction->GetLocations();
7590   Location first = locations->InAt(0);
7591   Location second = locations->InAt(1);
7592   Location out = locations->Out();
7593 
7594   if (instruction->GetResultType() == Primitive::kPrimInt) {
7595     Register first_reg = first.AsRegister<Register>();
7596     ShifterOperand second_reg(second.AsRegister<Register>());
7597     Register out_reg = out.AsRegister<Register>();
7598 
7599     switch (instruction->GetOpKind()) {
7600       case HInstruction::kAnd:
7601         __ bic(out_reg, first_reg, second_reg);
7602         break;
7603       case HInstruction::kOr:
7604         __ orn(out_reg, first_reg, second_reg);
7605         break;
7606       // There is no EON on arm.
7607       case HInstruction::kXor:
7608       default:
7609         LOG(FATAL) << "Unexpected instruction " << instruction->DebugName();
7610         UNREACHABLE();
7611     }
7612     return;
7613 
7614   } else {
7615     DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
7616     Register first_low = first.AsRegisterPairLow<Register>();
7617     Register first_high = first.AsRegisterPairHigh<Register>();
7618     ShifterOperand second_low(second.AsRegisterPairLow<Register>());
7619     ShifterOperand second_high(second.AsRegisterPairHigh<Register>());
7620     Register out_low = out.AsRegisterPairLow<Register>();
7621     Register out_high = out.AsRegisterPairHigh<Register>();
7622 
7623     switch (instruction->GetOpKind()) {
7624       case HInstruction::kAnd:
7625         __ bic(out_low, first_low, second_low);
7626         __ bic(out_high, first_high, second_high);
7627         break;
7628       case HInstruction::kOr:
7629         __ orn(out_low, first_low, second_low);
7630         __ orn(out_high, first_high, second_high);
7631         break;
7632       // There is no EON on arm.
7633       case HInstruction::kXor:
7634       default:
7635         LOG(FATAL) << "Unexpected instruction " << instruction->DebugName();
7636         UNREACHABLE();
7637     }
7638   }
7639 }
7640 
VisitDataProcWithShifterOp(HDataProcWithShifterOp * instruction)7641 void LocationsBuilderARM::VisitDataProcWithShifterOp(
7642     HDataProcWithShifterOp* instruction) {
7643   DCHECK(instruction->GetType() == Primitive::kPrimInt ||
7644          instruction->GetType() == Primitive::kPrimLong);
7645   LocationSummary* locations =
7646       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
7647   const bool overlap = instruction->GetType() == Primitive::kPrimLong &&
7648                        HDataProcWithShifterOp::IsExtensionOp(instruction->GetOpKind());
7649 
7650   locations->SetInAt(0, Location::RequiresRegister());
7651   locations->SetInAt(1, Location::RequiresRegister());
7652   locations->SetOut(Location::RequiresRegister(),
7653                     overlap ? Location::kOutputOverlap : Location::kNoOutputOverlap);
7654 }
7655 
VisitDataProcWithShifterOp(HDataProcWithShifterOp * instruction)7656 void InstructionCodeGeneratorARM::VisitDataProcWithShifterOp(
7657     HDataProcWithShifterOp* instruction) {
7658   const LocationSummary* const locations = instruction->GetLocations();
7659   const HInstruction::InstructionKind kind = instruction->GetInstrKind();
7660   const HDataProcWithShifterOp::OpKind op_kind = instruction->GetOpKind();
7661   const Location left = locations->InAt(0);
7662   const Location right = locations->InAt(1);
7663   const Location out = locations->Out();
7664 
7665   if (instruction->GetType() == Primitive::kPrimInt) {
7666     DCHECK(!HDataProcWithShifterOp::IsExtensionOp(op_kind));
7667 
7668     const Register second = instruction->InputAt(1)->GetType() == Primitive::kPrimLong
7669         ? right.AsRegisterPairLow<Register>()
7670         : right.AsRegister<Register>();
7671 
7672     GenerateDataProcInstruction(kind,
7673                                 out.AsRegister<Register>(),
7674                                 left.AsRegister<Register>(),
7675                                 ShifterOperand(second,
7676                                                ShiftFromOpKind(op_kind),
7677                                                instruction->GetShiftAmount()),
7678                                 codegen_);
7679   } else {
7680     DCHECK_EQ(instruction->GetType(), Primitive::kPrimLong);
7681 
7682     if (HDataProcWithShifterOp::IsExtensionOp(op_kind)) {
7683       const Register second = right.AsRegister<Register>();
7684 
7685       DCHECK_NE(out.AsRegisterPairLow<Register>(), second);
7686       GenerateDataProc(kind,
7687                        out,
7688                        left,
7689                        ShifterOperand(second),
7690                        ShifterOperand(second, ASR, 31),
7691                        codegen_);
7692     } else {
7693       GenerateLongDataProc(instruction, codegen_);
7694     }
7695   }
7696 }
7697 
GenerateAndConst(Register out,Register first,uint32_t value)7698 void InstructionCodeGeneratorARM::GenerateAndConst(Register out, Register first, uint32_t value) {
7699   // Optimize special cases for individual halfs of `and-long` (`and` is simplified earlier).
7700   if (value == 0xffffffffu) {
7701     if (out != first) {
7702       __ mov(out, ShifterOperand(first));
7703     }
7704     return;
7705   }
7706   if (value == 0u) {
7707     __ mov(out, ShifterOperand(0));
7708     return;
7709   }
7710   ShifterOperand so;
7711   if (__ ShifterOperandCanHold(kNoRegister, kNoRegister, AND, value, &so)) {
7712     __ and_(out, first, so);
7713   } else if (__ ShifterOperandCanHold(kNoRegister, kNoRegister, BIC, ~value, &so)) {
7714     __ bic(out, first, ShifterOperand(~value));
7715   } else {
7716     DCHECK(IsPowerOfTwo(value + 1));
7717     __ ubfx(out, first, 0, WhichPowerOf2(value + 1));
7718   }
7719 }
7720 
GenerateOrrConst(Register out,Register first,uint32_t value)7721 void InstructionCodeGeneratorARM::GenerateOrrConst(Register out, Register first, uint32_t value) {
7722   // Optimize special cases for individual halfs of `or-long` (`or` is simplified earlier).
7723   if (value == 0u) {
7724     if (out != first) {
7725       __ mov(out, ShifterOperand(first));
7726     }
7727     return;
7728   }
7729   if (value == 0xffffffffu) {
7730     __ mvn(out, ShifterOperand(0));
7731     return;
7732   }
7733   ShifterOperand so;
7734   if (__ ShifterOperandCanHold(kNoRegister, kNoRegister, ORR, value, &so)) {
7735     __ orr(out, first, so);
7736   } else {
7737     DCHECK(__ ShifterOperandCanHold(kNoRegister, kNoRegister, ORN, ~value, &so));
7738     __ orn(out, first, ShifterOperand(~value));
7739   }
7740 }
7741 
GenerateEorConst(Register out,Register first,uint32_t value)7742 void InstructionCodeGeneratorARM::GenerateEorConst(Register out, Register first, uint32_t value) {
7743   // Optimize special case for individual halfs of `xor-long` (`xor` is simplified earlier).
7744   if (value == 0u) {
7745     if (out != first) {
7746       __ mov(out, ShifterOperand(first));
7747     }
7748     return;
7749   }
7750   __ eor(out, first, ShifterOperand(value));
7751 }
7752 
GenerateAddLongConst(Location out,Location first,uint64_t value)7753 void InstructionCodeGeneratorARM::GenerateAddLongConst(Location out,
7754                                                        Location first,
7755                                                        uint64_t value) {
7756   Register out_low = out.AsRegisterPairLow<Register>();
7757   Register out_high = out.AsRegisterPairHigh<Register>();
7758   Register first_low = first.AsRegisterPairLow<Register>();
7759   Register first_high = first.AsRegisterPairHigh<Register>();
7760   uint32_t value_low = Low32Bits(value);
7761   uint32_t value_high = High32Bits(value);
7762   if (value_low == 0u) {
7763     if (out_low != first_low) {
7764       __ mov(out_low, ShifterOperand(first_low));
7765     }
7766     __ AddConstant(out_high, first_high, value_high);
7767     return;
7768   }
7769   __ AddConstantSetFlags(out_low, first_low, value_low);
7770   ShifterOperand so;
7771   if (__ ShifterOperandCanHold(out_high, first_high, ADC, value_high, kCcDontCare, &so)) {
7772     __ adc(out_high, first_high, so);
7773   } else if (__ ShifterOperandCanHold(out_low, first_low, SBC, ~value_high, kCcDontCare, &so)) {
7774     __ sbc(out_high, first_high, so);
7775   } else {
7776     LOG(FATAL) << "Unexpected constant " << value_high;
7777     UNREACHABLE();
7778   }
7779 }
7780 
HandleBitwiseOperation(HBinaryOperation * instruction)7781 void InstructionCodeGeneratorARM::HandleBitwiseOperation(HBinaryOperation* instruction) {
7782   LocationSummary* locations = instruction->GetLocations();
7783   Location first = locations->InAt(0);
7784   Location second = locations->InAt(1);
7785   Location out = locations->Out();
7786 
7787   if (second.IsConstant()) {
7788     uint64_t value = static_cast<uint64_t>(Int64FromConstant(second.GetConstant()));
7789     uint32_t value_low = Low32Bits(value);
7790     if (instruction->GetResultType() == Primitive::kPrimInt) {
7791       Register first_reg = first.AsRegister<Register>();
7792       Register out_reg = out.AsRegister<Register>();
7793       if (instruction->IsAnd()) {
7794         GenerateAndConst(out_reg, first_reg, value_low);
7795       } else if (instruction->IsOr()) {
7796         GenerateOrrConst(out_reg, first_reg, value_low);
7797       } else {
7798         DCHECK(instruction->IsXor());
7799         GenerateEorConst(out_reg, first_reg, value_low);
7800       }
7801     } else {
7802       DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
7803       uint32_t value_high = High32Bits(value);
7804       Register first_low = first.AsRegisterPairLow<Register>();
7805       Register first_high = first.AsRegisterPairHigh<Register>();
7806       Register out_low = out.AsRegisterPairLow<Register>();
7807       Register out_high = out.AsRegisterPairHigh<Register>();
7808       if (instruction->IsAnd()) {
7809         GenerateAndConst(out_low, first_low, value_low);
7810         GenerateAndConst(out_high, first_high, value_high);
7811       } else if (instruction->IsOr()) {
7812         GenerateOrrConst(out_low, first_low, value_low);
7813         GenerateOrrConst(out_high, first_high, value_high);
7814       } else {
7815         DCHECK(instruction->IsXor());
7816         GenerateEorConst(out_low, first_low, value_low);
7817         GenerateEorConst(out_high, first_high, value_high);
7818       }
7819     }
7820     return;
7821   }
7822 
7823   if (instruction->GetResultType() == Primitive::kPrimInt) {
7824     Register first_reg = first.AsRegister<Register>();
7825     ShifterOperand second_reg(second.AsRegister<Register>());
7826     Register out_reg = out.AsRegister<Register>();
7827     if (instruction->IsAnd()) {
7828       __ and_(out_reg, first_reg, second_reg);
7829     } else if (instruction->IsOr()) {
7830       __ orr(out_reg, first_reg, second_reg);
7831     } else {
7832       DCHECK(instruction->IsXor());
7833       __ eor(out_reg, first_reg, second_reg);
7834     }
7835   } else {
7836     DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
7837     Register first_low = first.AsRegisterPairLow<Register>();
7838     Register first_high = first.AsRegisterPairHigh<Register>();
7839     ShifterOperand second_low(second.AsRegisterPairLow<Register>());
7840     ShifterOperand second_high(second.AsRegisterPairHigh<Register>());
7841     Register out_low = out.AsRegisterPairLow<Register>();
7842     Register out_high = out.AsRegisterPairHigh<Register>();
7843     if (instruction->IsAnd()) {
7844       __ and_(out_low, first_low, second_low);
7845       __ and_(out_high, first_high, second_high);
7846     } else if (instruction->IsOr()) {
7847       __ orr(out_low, first_low, second_low);
7848       __ orr(out_high, first_high, second_high);
7849     } else {
7850       DCHECK(instruction->IsXor());
7851       __ eor(out_low, first_low, second_low);
7852       __ eor(out_high, first_high, second_high);
7853     }
7854   }
7855 }
7856 
GenerateReferenceLoadOneRegister(HInstruction * instruction,Location out,uint32_t offset,Location maybe_temp,ReadBarrierOption read_barrier_option)7857 void InstructionCodeGeneratorARM::GenerateReferenceLoadOneRegister(
7858     HInstruction* instruction,
7859     Location out,
7860     uint32_t offset,
7861     Location maybe_temp,
7862     ReadBarrierOption read_barrier_option) {
7863   Register out_reg = out.AsRegister<Register>();
7864   if (read_barrier_option == kWithReadBarrier) {
7865     CHECK(kEmitCompilerReadBarrier);
7866     DCHECK(maybe_temp.IsRegister()) << maybe_temp;
7867     if (kUseBakerReadBarrier) {
7868       // Load with fast path based Baker's read barrier.
7869       // /* HeapReference<Object> */ out = *(out + offset)
7870       codegen_->GenerateFieldLoadWithBakerReadBarrier(
7871           instruction, out, out_reg, offset, maybe_temp, /* needs_null_check */ false);
7872     } else {
7873       // Load with slow path based read barrier.
7874       // Save the value of `out` into `maybe_temp` before overwriting it
7875       // in the following move operation, as we will need it for the
7876       // read barrier below.
7877       __ Mov(maybe_temp.AsRegister<Register>(), out_reg);
7878       // /* HeapReference<Object> */ out = *(out + offset)
7879       __ LoadFromOffset(kLoadWord, out_reg, out_reg, offset);
7880       codegen_->GenerateReadBarrierSlow(instruction, out, out, maybe_temp, offset);
7881     }
7882   } else {
7883     // Plain load with no read barrier.
7884     // /* HeapReference<Object> */ out = *(out + offset)
7885     __ LoadFromOffset(kLoadWord, out_reg, out_reg, offset);
7886     __ MaybeUnpoisonHeapReference(out_reg);
7887   }
7888 }
7889 
GenerateReferenceLoadTwoRegisters(HInstruction * instruction,Location out,Location obj,uint32_t offset,Location maybe_temp,ReadBarrierOption read_barrier_option)7890 void InstructionCodeGeneratorARM::GenerateReferenceLoadTwoRegisters(
7891     HInstruction* instruction,
7892     Location out,
7893     Location obj,
7894     uint32_t offset,
7895     Location maybe_temp,
7896     ReadBarrierOption read_barrier_option) {
7897   Register out_reg = out.AsRegister<Register>();
7898   Register obj_reg = obj.AsRegister<Register>();
7899   if (read_barrier_option == kWithReadBarrier) {
7900     CHECK(kEmitCompilerReadBarrier);
7901     if (kUseBakerReadBarrier) {
7902       DCHECK(maybe_temp.IsRegister()) << maybe_temp;
7903       // Load with fast path based Baker's read barrier.
7904       // /* HeapReference<Object> */ out = *(obj + offset)
7905       codegen_->GenerateFieldLoadWithBakerReadBarrier(
7906           instruction, out, obj_reg, offset, maybe_temp, /* needs_null_check */ false);
7907     } else {
7908       // Load with slow path based read barrier.
7909       // /* HeapReference<Object> */ out = *(obj + offset)
7910       __ LoadFromOffset(kLoadWord, out_reg, obj_reg, offset);
7911       codegen_->GenerateReadBarrierSlow(instruction, out, out, obj, offset);
7912     }
7913   } else {
7914     // Plain load with no read barrier.
7915     // /* HeapReference<Object> */ out = *(obj + offset)
7916     __ LoadFromOffset(kLoadWord, out_reg, obj_reg, offset);
7917     __ MaybeUnpoisonHeapReference(out_reg);
7918   }
7919 }
7920 
GenerateGcRootFieldLoad(HInstruction * instruction,Location root,Register obj,uint32_t offset,ReadBarrierOption read_barrier_option)7921 void InstructionCodeGeneratorARM::GenerateGcRootFieldLoad(HInstruction* instruction,
7922                                                           Location root,
7923                                                           Register obj,
7924                                                           uint32_t offset,
7925                                                           ReadBarrierOption read_barrier_option) {
7926   Register root_reg = root.AsRegister<Register>();
7927   if (read_barrier_option == kWithReadBarrier) {
7928     DCHECK(kEmitCompilerReadBarrier);
7929     if (kUseBakerReadBarrier) {
7930       // Fast path implementation of art::ReadBarrier::BarrierForRoot when
7931       // Baker's read barrier are used.
7932       //
7933       // Note that we do not actually check the value of
7934       // `GetIsGcMarking()` to decide whether to mark the loaded GC
7935       // root or not.  Instead, we load into `temp` the read barrier
7936       // mark entry point corresponding to register `root`. If `temp`
7937       // is null, it means that `GetIsGcMarking()` is false, and vice
7938       // versa.
7939       //
7940       //   temp = Thread::Current()->pReadBarrierMarkReg ## root.reg()
7941       //   GcRoot<mirror::Object> root = *(obj+offset);  // Original reference load.
7942       //   if (temp != nullptr) {  // <=> Thread::Current()->GetIsGcMarking()
7943       //     // Slow path.
7944       //     root = temp(root);  // root = ReadBarrier::Mark(root);  // Runtime entry point call.
7945       //   }
7946 
7947       // Slow path marking the GC root `root`. The entrypoint will already be loaded in `temp`.
7948       Location temp = Location::RegisterLocation(LR);
7949       SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) ReadBarrierMarkSlowPathARM(
7950           instruction, root, /* entrypoint */ temp);
7951       codegen_->AddSlowPath(slow_path);
7952 
7953       // temp = Thread::Current()->pReadBarrierMarkReg ## root.reg()
7954       const int32_t entry_point_offset =
7955           CodeGenerator::GetReadBarrierMarkEntryPointsOffset<kArmPointerSize>(root.reg());
7956       // Loading the entrypoint does not require a load acquire since it is only changed when
7957       // threads are suspended or running a checkpoint.
7958       __ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), TR, entry_point_offset);
7959 
7960       // /* GcRoot<mirror::Object> */ root = *(obj + offset)
7961       __ LoadFromOffset(kLoadWord, root_reg, obj, offset);
7962       static_assert(
7963           sizeof(mirror::CompressedReference<mirror::Object>) == sizeof(GcRoot<mirror::Object>),
7964           "art::mirror::CompressedReference<mirror::Object> and art::GcRoot<mirror::Object> "
7965           "have different sizes.");
7966       static_assert(sizeof(mirror::CompressedReference<mirror::Object>) == sizeof(int32_t),
7967                     "art::mirror::CompressedReference<mirror::Object> and int32_t "
7968                     "have different sizes.");
7969 
7970       // The entrypoint is null when the GC is not marking, this prevents one load compared to
7971       // checking GetIsGcMarking.
7972       __ CompareAndBranchIfNonZero(temp.AsRegister<Register>(), slow_path->GetEntryLabel());
7973       __ Bind(slow_path->GetExitLabel());
7974     } else {
7975       // GC root loaded through a slow path for read barriers other
7976       // than Baker's.
7977       // /* GcRoot<mirror::Object>* */ root = obj + offset
7978       __ AddConstant(root_reg, obj, offset);
7979       // /* mirror::Object* */ root = root->Read()
7980       codegen_->GenerateReadBarrierForRootSlow(instruction, root, root);
7981     }
7982   } else {
7983     // Plain GC root load with no read barrier.
7984     // /* GcRoot<mirror::Object> */ root = *(obj + offset)
7985     __ LoadFromOffset(kLoadWord, root_reg, obj, offset);
7986     // Note that GC roots are not affected by heap poisoning, thus we
7987     // do not have to unpoison `root_reg` here.
7988   }
7989 }
7990 
GenerateFieldLoadWithBakerReadBarrier(HInstruction * instruction,Location ref,Register obj,uint32_t offset,Location temp,bool needs_null_check)7991 void CodeGeneratorARM::GenerateFieldLoadWithBakerReadBarrier(HInstruction* instruction,
7992                                                              Location ref,
7993                                                              Register obj,
7994                                                              uint32_t offset,
7995                                                              Location temp,
7996                                                              bool needs_null_check) {
7997   DCHECK(kEmitCompilerReadBarrier);
7998   DCHECK(kUseBakerReadBarrier);
7999 
8000   // /* HeapReference<Object> */ ref = *(obj + offset)
8001   Location no_index = Location::NoLocation();
8002   ScaleFactor no_scale_factor = TIMES_1;
8003   GenerateReferenceLoadWithBakerReadBarrier(
8004       instruction, ref, obj, offset, no_index, no_scale_factor, temp, needs_null_check);
8005 }
8006 
GenerateArrayLoadWithBakerReadBarrier(HInstruction * instruction,Location ref,Register obj,uint32_t data_offset,Location index,Location temp,bool needs_null_check)8007 void CodeGeneratorARM::GenerateArrayLoadWithBakerReadBarrier(HInstruction* instruction,
8008                                                              Location ref,
8009                                                              Register obj,
8010                                                              uint32_t data_offset,
8011                                                              Location index,
8012                                                              Location temp,
8013                                                              bool needs_null_check) {
8014   DCHECK(kEmitCompilerReadBarrier);
8015   DCHECK(kUseBakerReadBarrier);
8016 
8017   static_assert(
8018       sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
8019       "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
8020   // /* HeapReference<Object> */ ref =
8021   //     *(obj + data_offset + index * sizeof(HeapReference<Object>))
8022   ScaleFactor scale_factor = TIMES_4;
8023   GenerateReferenceLoadWithBakerReadBarrier(
8024       instruction, ref, obj, data_offset, index, scale_factor, temp, needs_null_check);
8025 }
8026 
GenerateReferenceLoadWithBakerReadBarrier(HInstruction * instruction,Location ref,Register obj,uint32_t offset,Location index,ScaleFactor scale_factor,Location temp,bool needs_null_check,bool always_update_field,Register * temp2)8027 void CodeGeneratorARM::GenerateReferenceLoadWithBakerReadBarrier(HInstruction* instruction,
8028                                                                  Location ref,
8029                                                                  Register obj,
8030                                                                  uint32_t offset,
8031                                                                  Location index,
8032                                                                  ScaleFactor scale_factor,
8033                                                                  Location temp,
8034                                                                  bool needs_null_check,
8035                                                                  bool always_update_field,
8036                                                                  Register* temp2) {
8037   DCHECK(kEmitCompilerReadBarrier);
8038   DCHECK(kUseBakerReadBarrier);
8039 
8040   // Query `art::Thread::Current()->GetIsGcMarking()` to decide
8041   // whether we need to enter the slow path to mark the reference.
8042   // Then, in the slow path, check the gray bit in the lock word of
8043   // the reference's holder (`obj`) to decide whether to mark `ref` or
8044   // not.
8045   //
8046   // Note that we do not actually check the value of `GetIsGcMarking()`;
8047   // instead, we load into `temp3` the read barrier mark entry point
8048   // corresponding to register `ref`. If `temp3` is null, it means
8049   // that `GetIsGcMarking()` is false, and vice versa.
8050   //
8051   //   temp3 = Thread::Current()->pReadBarrierMarkReg ## root.reg()
8052   //   if (temp3 != nullptr) {  // <=> Thread::Current()->GetIsGcMarking()
8053   //     // Slow path.
8054   //     uint32_t rb_state = Lockword(obj->monitor_).ReadBarrierState();
8055   //     lfence;  // Load fence or artificial data dependency to prevent load-load reordering
8056   //     HeapReference<mirror::Object> ref = *src;  // Original reference load.
8057   //     bool is_gray = (rb_state == ReadBarrier::GrayState());
8058   //     if (is_gray) {
8059   //       ref = temp3(ref);  // ref = ReadBarrier::Mark(ref);  // Runtime entry point call.
8060   //     }
8061   //   } else {
8062   //     HeapReference<mirror::Object> ref = *src;  // Original reference load.
8063   //   }
8064 
8065   Register temp_reg = temp.AsRegister<Register>();
8066 
8067   // Slow path marking the object `ref` when the GC is marking. The
8068   // entrypoint will already be loaded in `temp3`.
8069   Location temp3 = Location::RegisterLocation(LR);
8070   SlowPathCodeARM* slow_path;
8071   if (always_update_field) {
8072     DCHECK(temp2 != nullptr);
8073     // LoadReferenceWithBakerReadBarrierAndUpdateFieldSlowPathARM only
8074     // supports address of the form `obj + field_offset`, where `obj`
8075     // is a register and `field_offset` is a register pair (of which
8076     // only the lower half is used). Thus `offset` and `scale_factor`
8077     // above are expected to be null in this code path.
8078     DCHECK_EQ(offset, 0u);
8079     DCHECK_EQ(scale_factor, ScaleFactor::TIMES_1);
8080     Location field_offset = index;
8081     slow_path =
8082         new (GetGraph()->GetArena()) LoadReferenceWithBakerReadBarrierAndUpdateFieldSlowPathARM(
8083             instruction,
8084             ref,
8085             obj,
8086             offset,
8087             /* index */ field_offset,
8088             scale_factor,
8089             needs_null_check,
8090             temp_reg,
8091             *temp2,
8092             /* entrypoint */ temp3);
8093   } else {
8094     slow_path = new (GetGraph()->GetArena()) LoadReferenceWithBakerReadBarrierSlowPathARM(
8095         instruction,
8096         ref,
8097         obj,
8098         offset,
8099         index,
8100         scale_factor,
8101         needs_null_check,
8102         temp_reg,
8103         /* entrypoint */ temp3);
8104   }
8105   AddSlowPath(slow_path);
8106 
8107   // temp3 = Thread::Current()->pReadBarrierMarkReg ## ref.reg()
8108   const int32_t entry_point_offset =
8109       CodeGenerator::GetReadBarrierMarkEntryPointsOffset<kArmPointerSize>(ref.reg());
8110   // Loading the entrypoint does not require a load acquire since it is only changed when
8111   // threads are suspended or running a checkpoint.
8112   __ LoadFromOffset(kLoadWord, temp3.AsRegister<Register>(), TR, entry_point_offset);
8113   // The entrypoint is null when the GC is not marking, this prevents one load compared to
8114   // checking GetIsGcMarking.
8115   __ CompareAndBranchIfNonZero(temp3.AsRegister<Register>(), slow_path->GetEntryLabel());
8116   // Fast path: just load the reference.
8117   GenerateRawReferenceLoad(instruction, ref, obj, offset, index, scale_factor, needs_null_check);
8118   __ Bind(slow_path->GetExitLabel());
8119 }
8120 
GenerateRawReferenceLoad(HInstruction * instruction,Location ref,Register obj,uint32_t offset,Location index,ScaleFactor scale_factor,bool needs_null_check)8121 void CodeGeneratorARM::GenerateRawReferenceLoad(HInstruction* instruction,
8122                                                 Location ref,
8123                                                 Register obj,
8124                                                 uint32_t offset,
8125                                                 Location index,
8126                                                 ScaleFactor scale_factor,
8127                                                 bool needs_null_check) {
8128   Register ref_reg = ref.AsRegister<Register>();
8129 
8130   if (index.IsValid()) {
8131     // Load types involving an "index": ArrayGet,
8132     // UnsafeGetObject/UnsafeGetObjectVolatile and UnsafeCASObject
8133     // intrinsics.
8134     // /* HeapReference<mirror::Object> */ ref = *(obj + offset + (index << scale_factor))
8135     if (index.IsConstant()) {
8136       size_t computed_offset =
8137           (index.GetConstant()->AsIntConstant()->GetValue() << scale_factor) + offset;
8138       __ LoadFromOffset(kLoadWord, ref_reg, obj, computed_offset);
8139     } else {
8140       // Handle the special case of the
8141       // UnsafeGetObject/UnsafeGetObjectVolatile and UnsafeCASObject
8142       // intrinsics, which use a register pair as index ("long
8143       // offset"), of which only the low part contains data.
8144       Register index_reg = index.IsRegisterPair()
8145           ? index.AsRegisterPairLow<Register>()
8146           : index.AsRegister<Register>();
8147       __ add(IP, obj, ShifterOperand(index_reg, LSL, scale_factor));
8148       __ LoadFromOffset(kLoadWord, ref_reg, IP, offset);
8149     }
8150   } else {
8151     // /* HeapReference<mirror::Object> */ ref = *(obj + offset)
8152     __ LoadFromOffset(kLoadWord, ref_reg, obj, offset);
8153   }
8154 
8155   if (needs_null_check) {
8156     MaybeRecordImplicitNullCheck(instruction);
8157   }
8158 
8159   // Object* ref = ref_addr->AsMirrorPtr()
8160   __ MaybeUnpoisonHeapReference(ref_reg);
8161 }
8162 
GenerateReadBarrierSlow(HInstruction * instruction,Location out,Location ref,Location obj,uint32_t offset,Location index)8163 void CodeGeneratorARM::GenerateReadBarrierSlow(HInstruction* instruction,
8164                                                Location out,
8165                                                Location ref,
8166                                                Location obj,
8167                                                uint32_t offset,
8168                                                Location index) {
8169   DCHECK(kEmitCompilerReadBarrier);
8170 
8171   // Insert a slow path based read barrier *after* the reference load.
8172   //
8173   // If heap poisoning is enabled, the unpoisoning of the loaded
8174   // reference will be carried out by the runtime within the slow
8175   // path.
8176   //
8177   // Note that `ref` currently does not get unpoisoned (when heap
8178   // poisoning is enabled), which is alright as the `ref` argument is
8179   // not used by the artReadBarrierSlow entry point.
8180   //
8181   // TODO: Unpoison `ref` when it is used by artReadBarrierSlow.
8182   SlowPathCodeARM* slow_path = new (GetGraph()->GetArena())
8183       ReadBarrierForHeapReferenceSlowPathARM(instruction, out, ref, obj, offset, index);
8184   AddSlowPath(slow_path);
8185 
8186   __ b(slow_path->GetEntryLabel());
8187   __ Bind(slow_path->GetExitLabel());
8188 }
8189 
MaybeGenerateReadBarrierSlow(HInstruction * instruction,Location out,Location ref,Location obj,uint32_t offset,Location index)8190 void CodeGeneratorARM::MaybeGenerateReadBarrierSlow(HInstruction* instruction,
8191                                                     Location out,
8192                                                     Location ref,
8193                                                     Location obj,
8194                                                     uint32_t offset,
8195                                                     Location index) {
8196   if (kEmitCompilerReadBarrier) {
8197     // Baker's read barriers shall be handled by the fast path
8198     // (CodeGeneratorARM::GenerateReferenceLoadWithBakerReadBarrier).
8199     DCHECK(!kUseBakerReadBarrier);
8200     // If heap poisoning is enabled, unpoisoning will be taken care of
8201     // by the runtime within the slow path.
8202     GenerateReadBarrierSlow(instruction, out, ref, obj, offset, index);
8203   } else if (kPoisonHeapReferences) {
8204     __ UnpoisonHeapReference(out.AsRegister<Register>());
8205   }
8206 }
8207 
GenerateReadBarrierForRootSlow(HInstruction * instruction,Location out,Location root)8208 void CodeGeneratorARM::GenerateReadBarrierForRootSlow(HInstruction* instruction,
8209                                                       Location out,
8210                                                       Location root) {
8211   DCHECK(kEmitCompilerReadBarrier);
8212 
8213   // Insert a slow path based read barrier *after* the GC root load.
8214   //
8215   // Note that GC roots are not affected by heap poisoning, so we do
8216   // not need to do anything special for this here.
8217   SlowPathCodeARM* slow_path =
8218       new (GetGraph()->GetArena()) ReadBarrierForRootSlowPathARM(instruction, out, root);
8219   AddSlowPath(slow_path);
8220 
8221   __ b(slow_path->GetEntryLabel());
8222   __ Bind(slow_path->GetExitLabel());
8223 }
8224 
GetSupportedInvokeStaticOrDirectDispatch(const HInvokeStaticOrDirect::DispatchInfo & desired_dispatch_info,HInvokeStaticOrDirect * invoke ATTRIBUTE_UNUSED)8225 HInvokeStaticOrDirect::DispatchInfo CodeGeneratorARM::GetSupportedInvokeStaticOrDirectDispatch(
8226       const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
8227       HInvokeStaticOrDirect* invoke ATTRIBUTE_UNUSED) {
8228   return desired_dispatch_info;
8229 }
8230 
GetInvokeStaticOrDirectExtraParameter(HInvokeStaticOrDirect * invoke,Register temp)8231 Register CodeGeneratorARM::GetInvokeStaticOrDirectExtraParameter(HInvokeStaticOrDirect* invoke,
8232                                                                  Register temp) {
8233   DCHECK_EQ(invoke->InputCount(), invoke->GetNumberOfArguments() + 1u);
8234   Location location = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
8235   if (!invoke->GetLocations()->Intrinsified()) {
8236     return location.AsRegister<Register>();
8237   }
8238   // For intrinsics we allow any location, so it may be on the stack.
8239   if (!location.IsRegister()) {
8240     __ LoadFromOffset(kLoadWord, temp, SP, location.GetStackIndex());
8241     return temp;
8242   }
8243   // For register locations, check if the register was saved. If so, get it from the stack.
8244   // Note: There is a chance that the register was saved but not overwritten, so we could
8245   // save one load. However, since this is just an intrinsic slow path we prefer this
8246   // simple and more robust approach rather that trying to determine if that's the case.
8247   SlowPathCode* slow_path = GetCurrentSlowPath();
8248   if (slow_path != nullptr && slow_path->IsCoreRegisterSaved(location.AsRegister<Register>())) {
8249     int stack_offset = slow_path->GetStackOffsetOfCoreRegister(location.AsRegister<Register>());
8250     __ LoadFromOffset(kLoadWord, temp, SP, stack_offset);
8251     return temp;
8252   }
8253   return location.AsRegister<Register>();
8254 }
8255 
GenerateCalleeMethodStaticOrDirectCall(HInvokeStaticOrDirect * invoke,Location temp)8256 Location CodeGeneratorARM::GenerateCalleeMethodStaticOrDirectCall(HInvokeStaticOrDirect* invoke,
8257                                                                   Location temp) {
8258   Location callee_method = temp;  // For all kinds except kRecursive, callee will be in temp.
8259   switch (invoke->GetMethodLoadKind()) {
8260     case HInvokeStaticOrDirect::MethodLoadKind::kStringInit: {
8261       uint32_t offset =
8262           GetThreadOffset<kArmPointerSize>(invoke->GetStringInitEntryPoint()).Int32Value();
8263       // temp = thread->string_init_entrypoint
8264       __ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), TR, offset);
8265       break;
8266     }
8267     case HInvokeStaticOrDirect::MethodLoadKind::kRecursive:
8268       callee_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
8269       break;
8270     case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress:
8271       __ LoadImmediate(temp.AsRegister<Register>(), invoke->GetMethodAddress());
8272       break;
8273     case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative: {
8274       HArmDexCacheArraysBase* base =
8275           invoke->InputAt(invoke->GetSpecialInputIndex())->AsArmDexCacheArraysBase();
8276       Register base_reg = GetInvokeStaticOrDirectExtraParameter(invoke,
8277                                                                 temp.AsRegister<Register>());
8278       int32_t offset = invoke->GetDexCacheArrayOffset() - base->GetElementOffset();
8279       __ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), base_reg, offset);
8280       break;
8281     }
8282     case HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod: {
8283       Location current_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
8284       Register method_reg;
8285       Register reg = temp.AsRegister<Register>();
8286       if (current_method.IsRegister()) {
8287         method_reg = current_method.AsRegister<Register>();
8288       } else {
8289         DCHECK(invoke->GetLocations()->Intrinsified());
8290         DCHECK(!current_method.IsValid());
8291         method_reg = reg;
8292         __ LoadFromOffset(kLoadWord, reg, SP, kCurrentMethodStackOffset);
8293       }
8294       // /* ArtMethod*[] */ temp = temp.ptr_sized_fields_->dex_cache_resolved_methods_;
8295       __ LoadFromOffset(kLoadWord,
8296                         reg,
8297                         method_reg,
8298                         ArtMethod::DexCacheResolvedMethodsOffset(kArmPointerSize).Int32Value());
8299       // temp = temp[index_in_cache];
8300       // Note: Don't use invoke->GetTargetMethod() as it may point to a different dex file.
8301       uint32_t index_in_cache = invoke->GetDexMethodIndex();
8302       __ LoadFromOffset(kLoadWord, reg, reg, CodeGenerator::GetCachePointerOffset(index_in_cache));
8303       break;
8304     }
8305   }
8306   return callee_method;
8307 }
8308 
GenerateStaticOrDirectCall(HInvokeStaticOrDirect * invoke,Location temp)8309 void CodeGeneratorARM::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) {
8310   Location callee_method = GenerateCalleeMethodStaticOrDirectCall(invoke, temp);
8311 
8312   switch (invoke->GetCodePtrLocation()) {
8313     case HInvokeStaticOrDirect::CodePtrLocation::kCallSelf:
8314       __ bl(GetFrameEntryLabel());
8315       break;
8316     case HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod:
8317       // LR = callee_method->entry_point_from_quick_compiled_code_
8318       __ LoadFromOffset(
8319           kLoadWord, LR, callee_method.AsRegister<Register>(),
8320           ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArmPointerSize).Int32Value());
8321       // LR()
8322       __ blx(LR);
8323       break;
8324   }
8325 
8326   DCHECK(!IsLeafMethod());
8327 }
8328 
GenerateVirtualCall(HInvokeVirtual * invoke,Location temp_location)8329 void CodeGeneratorARM::GenerateVirtualCall(HInvokeVirtual* invoke, Location temp_location) {
8330   Register temp = temp_location.AsRegister<Register>();
8331   uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
8332       invoke->GetVTableIndex(), kArmPointerSize).Uint32Value();
8333 
8334   // Use the calling convention instead of the location of the receiver, as
8335   // intrinsics may have put the receiver in a different register. In the intrinsics
8336   // slow path, the arguments have been moved to the right place, so here we are
8337   // guaranteed that the receiver is the first register of the calling convention.
8338   InvokeDexCallingConvention calling_convention;
8339   Register receiver = calling_convention.GetRegisterAt(0);
8340   uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
8341   // /* HeapReference<Class> */ temp = receiver->klass_
8342   __ LoadFromOffset(kLoadWord, temp, receiver, class_offset);
8343   MaybeRecordImplicitNullCheck(invoke);
8344   // Instead of simply (possibly) unpoisoning `temp` here, we should
8345   // emit a read barrier for the previous class reference load.
8346   // However this is not required in practice, as this is an
8347   // intermediate/temporary reference and because the current
8348   // concurrent copying collector keeps the from-space memory
8349   // intact/accessible until the end of the marking phase (the
8350   // concurrent copying collector may not in the future).
8351   __ MaybeUnpoisonHeapReference(temp);
8352   // temp = temp->GetMethodAt(method_offset);
8353   uint32_t entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(
8354       kArmPointerSize).Int32Value();
8355   __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
8356   // LR = temp->GetEntryPoint();
8357   __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
8358   // LR();
8359   __ blx(LR);
8360 }
8361 
NewPcRelativeStringPatch(const DexFile & dex_file,dex::StringIndex string_index)8362 CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativeStringPatch(
8363     const DexFile& dex_file, dex::StringIndex string_index) {
8364   return NewPcRelativePatch(dex_file, string_index.index_, &pc_relative_string_patches_);
8365 }
8366 
NewPcRelativeTypePatch(const DexFile & dex_file,dex::TypeIndex type_index)8367 CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativeTypePatch(
8368     const DexFile& dex_file, dex::TypeIndex type_index) {
8369   return NewPcRelativePatch(dex_file, type_index.index_, &pc_relative_type_patches_);
8370 }
8371 
NewTypeBssEntryPatch(const DexFile & dex_file,dex::TypeIndex type_index)8372 CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewTypeBssEntryPatch(
8373     const DexFile& dex_file, dex::TypeIndex type_index) {
8374   return NewPcRelativePatch(dex_file, type_index.index_, &type_bss_entry_patches_);
8375 }
8376 
NewPcRelativeDexCacheArrayPatch(const DexFile & dex_file,uint32_t element_offset)8377 CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativeDexCacheArrayPatch(
8378     const DexFile& dex_file, uint32_t element_offset) {
8379   return NewPcRelativePatch(dex_file, element_offset, &pc_relative_dex_cache_patches_);
8380 }
8381 
NewPcRelativePatch(const DexFile & dex_file,uint32_t offset_or_index,ArenaDeque<PcRelativePatchInfo> * patches)8382 CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativePatch(
8383     const DexFile& dex_file, uint32_t offset_or_index, ArenaDeque<PcRelativePatchInfo>* patches) {
8384   patches->emplace_back(dex_file, offset_or_index);
8385   return &patches->back();
8386 }
8387 
DeduplicateBootImageStringLiteral(const DexFile & dex_file,dex::StringIndex string_index)8388 Literal* CodeGeneratorARM::DeduplicateBootImageStringLiteral(const DexFile& dex_file,
8389                                                              dex::StringIndex string_index) {
8390   return boot_image_string_patches_.GetOrCreate(
8391       StringReference(&dex_file, string_index),
8392       [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
8393 }
8394 
DeduplicateBootImageTypeLiteral(const DexFile & dex_file,dex::TypeIndex type_index)8395 Literal* CodeGeneratorARM::DeduplicateBootImageTypeLiteral(const DexFile& dex_file,
8396                                                            dex::TypeIndex type_index) {
8397   return boot_image_type_patches_.GetOrCreate(
8398       TypeReference(&dex_file, type_index),
8399       [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
8400 }
8401 
DeduplicateBootImageAddressLiteral(uint32_t address)8402 Literal* CodeGeneratorARM::DeduplicateBootImageAddressLiteral(uint32_t address) {
8403   return DeduplicateUint32Literal(dchecked_integral_cast<uint32_t>(address), &uint32_literals_);
8404 }
8405 
DeduplicateJitStringLiteral(const DexFile & dex_file,dex::StringIndex string_index,Handle<mirror::String> handle)8406 Literal* CodeGeneratorARM::DeduplicateJitStringLiteral(const DexFile& dex_file,
8407                                                        dex::StringIndex string_index,
8408                                                        Handle<mirror::String> handle) {
8409   jit_string_roots_.Overwrite(StringReference(&dex_file, string_index),
8410                               reinterpret_cast64<uint64_t>(handle.GetReference()));
8411   return jit_string_patches_.GetOrCreate(
8412       StringReference(&dex_file, string_index),
8413       [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
8414 }
8415 
DeduplicateJitClassLiteral(const DexFile & dex_file,dex::TypeIndex type_index,Handle<mirror::Class> handle)8416 Literal* CodeGeneratorARM::DeduplicateJitClassLiteral(const DexFile& dex_file,
8417                                                       dex::TypeIndex type_index,
8418                                                       Handle<mirror::Class> handle) {
8419   jit_class_roots_.Overwrite(TypeReference(&dex_file, type_index),
8420                              reinterpret_cast64<uint64_t>(handle.GetReference()));
8421   return jit_class_patches_.GetOrCreate(
8422       TypeReference(&dex_file, type_index),
8423       [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
8424 }
8425 
8426 template <LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)>
EmitPcRelativeLinkerPatches(const ArenaDeque<PcRelativePatchInfo> & infos,ArenaVector<LinkerPatch> * linker_patches)8427 inline void CodeGeneratorARM::EmitPcRelativeLinkerPatches(
8428     const ArenaDeque<PcRelativePatchInfo>& infos,
8429     ArenaVector<LinkerPatch>* linker_patches) {
8430   for (const PcRelativePatchInfo& info : infos) {
8431     const DexFile& dex_file = info.target_dex_file;
8432     size_t offset_or_index = info.offset_or_index;
8433     DCHECK(info.add_pc_label.IsBound());
8434     uint32_t add_pc_offset = dchecked_integral_cast<uint32_t>(info.add_pc_label.Position());
8435     // Add MOVW patch.
8436     DCHECK(info.movw_label.IsBound());
8437     uint32_t movw_offset = dchecked_integral_cast<uint32_t>(info.movw_label.Position());
8438     linker_patches->push_back(Factory(movw_offset, &dex_file, add_pc_offset, offset_or_index));
8439     // Add MOVT patch.
8440     DCHECK(info.movt_label.IsBound());
8441     uint32_t movt_offset = dchecked_integral_cast<uint32_t>(info.movt_label.Position());
8442     linker_patches->push_back(Factory(movt_offset, &dex_file, add_pc_offset, offset_or_index));
8443   }
8444 }
8445 
EmitLinkerPatches(ArenaVector<LinkerPatch> * linker_patches)8446 void CodeGeneratorARM::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
8447   DCHECK(linker_patches->empty());
8448   size_t size =
8449       /* MOVW+MOVT for each entry */ 2u * pc_relative_dex_cache_patches_.size() +
8450       boot_image_string_patches_.size() +
8451       /* MOVW+MOVT for each entry */ 2u * pc_relative_string_patches_.size() +
8452       boot_image_type_patches_.size() +
8453       /* MOVW+MOVT for each entry */ 2u * pc_relative_type_patches_.size() +
8454       /* MOVW+MOVT for each entry */ 2u * type_bss_entry_patches_.size();
8455   linker_patches->reserve(size);
8456   EmitPcRelativeLinkerPatches<LinkerPatch::DexCacheArrayPatch>(pc_relative_dex_cache_patches_,
8457                                                                linker_patches);
8458   for (const auto& entry : boot_image_string_patches_) {
8459     const StringReference& target_string = entry.first;
8460     Literal* literal = entry.second;
8461     DCHECK(literal->GetLabel()->IsBound());
8462     uint32_t literal_offset = literal->GetLabel()->Position();
8463     linker_patches->push_back(LinkerPatch::StringPatch(literal_offset,
8464                                                        target_string.dex_file,
8465                                                        target_string.string_index.index_));
8466   }
8467   if (!GetCompilerOptions().IsBootImage()) {
8468     DCHECK(pc_relative_type_patches_.empty());
8469     EmitPcRelativeLinkerPatches<LinkerPatch::StringBssEntryPatch>(pc_relative_string_patches_,
8470                                                                   linker_patches);
8471   } else {
8472     EmitPcRelativeLinkerPatches<LinkerPatch::RelativeTypePatch>(pc_relative_type_patches_,
8473                                                                 linker_patches);
8474     EmitPcRelativeLinkerPatches<LinkerPatch::RelativeStringPatch>(pc_relative_string_patches_,
8475                                                                   linker_patches);
8476   }
8477   EmitPcRelativeLinkerPatches<LinkerPatch::TypeBssEntryPatch>(type_bss_entry_patches_,
8478                                                               linker_patches);
8479   for (const auto& entry : boot_image_type_patches_) {
8480     const TypeReference& target_type = entry.first;
8481     Literal* literal = entry.second;
8482     DCHECK(literal->GetLabel()->IsBound());
8483     uint32_t literal_offset = literal->GetLabel()->Position();
8484     linker_patches->push_back(LinkerPatch::TypePatch(literal_offset,
8485                                                      target_type.dex_file,
8486                                                      target_type.type_index.index_));
8487   }
8488   DCHECK_EQ(size, linker_patches->size());
8489 }
8490 
DeduplicateUint32Literal(uint32_t value,Uint32ToLiteralMap * map)8491 Literal* CodeGeneratorARM::DeduplicateUint32Literal(uint32_t value, Uint32ToLiteralMap* map) {
8492   return map->GetOrCreate(
8493       value,
8494       [this, value]() { return __ NewLiteral<uint32_t>(value); });
8495 }
8496 
DeduplicateMethodLiteral(MethodReference target_method,MethodToLiteralMap * map)8497 Literal* CodeGeneratorARM::DeduplicateMethodLiteral(MethodReference target_method,
8498                                                     MethodToLiteralMap* map) {
8499   return map->GetOrCreate(
8500       target_method,
8501       [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
8502 }
8503 
VisitMultiplyAccumulate(HMultiplyAccumulate * instr)8504 void LocationsBuilderARM::VisitMultiplyAccumulate(HMultiplyAccumulate* instr) {
8505   LocationSummary* locations =
8506       new (GetGraph()->GetArena()) LocationSummary(instr, LocationSummary::kNoCall);
8507   locations->SetInAt(HMultiplyAccumulate::kInputAccumulatorIndex,
8508                      Location::RequiresRegister());
8509   locations->SetInAt(HMultiplyAccumulate::kInputMulLeftIndex, Location::RequiresRegister());
8510   locations->SetInAt(HMultiplyAccumulate::kInputMulRightIndex, Location::RequiresRegister());
8511   locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
8512 }
8513 
VisitMultiplyAccumulate(HMultiplyAccumulate * instr)8514 void InstructionCodeGeneratorARM::VisitMultiplyAccumulate(HMultiplyAccumulate* instr) {
8515   LocationSummary* locations = instr->GetLocations();
8516   Register res = locations->Out().AsRegister<Register>();
8517   Register accumulator =
8518       locations->InAt(HMultiplyAccumulate::kInputAccumulatorIndex).AsRegister<Register>();
8519   Register mul_left =
8520       locations->InAt(HMultiplyAccumulate::kInputMulLeftIndex).AsRegister<Register>();
8521   Register mul_right =
8522       locations->InAt(HMultiplyAccumulate::kInputMulRightIndex).AsRegister<Register>();
8523 
8524   if (instr->GetOpKind() == HInstruction::kAdd) {
8525     __ mla(res, mul_left, mul_right, accumulator);
8526   } else {
8527     __ mls(res, mul_left, mul_right, accumulator);
8528   }
8529 }
8530 
VisitBoundType(HBoundType * instruction ATTRIBUTE_UNUSED)8531 void LocationsBuilderARM::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
8532   // Nothing to do, this should be removed during prepare for register allocator.
8533   LOG(FATAL) << "Unreachable";
8534 }
8535 
VisitBoundType(HBoundType * instruction ATTRIBUTE_UNUSED)8536 void InstructionCodeGeneratorARM::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
8537   // Nothing to do, this should be removed during prepare for register allocator.
8538   LOG(FATAL) << "Unreachable";
8539 }
8540 
8541 // Simple implementation of packed switch - generate cascaded compare/jumps.
VisitPackedSwitch(HPackedSwitch * switch_instr)8542 void LocationsBuilderARM::VisitPackedSwitch(HPackedSwitch* switch_instr) {
8543   LocationSummary* locations =
8544       new (GetGraph()->GetArena()) LocationSummary(switch_instr, LocationSummary::kNoCall);
8545   locations->SetInAt(0, Location::RequiresRegister());
8546   if (switch_instr->GetNumEntries() > kPackedSwitchCompareJumpThreshold &&
8547       codegen_->GetAssembler()->IsThumb()) {
8548     locations->AddTemp(Location::RequiresRegister());  // We need a temp for the table base.
8549     if (switch_instr->GetStartValue() != 0) {
8550       locations->AddTemp(Location::RequiresRegister());  // We need a temp for the bias.
8551     }
8552   }
8553 }
8554 
VisitPackedSwitch(HPackedSwitch * switch_instr)8555 void InstructionCodeGeneratorARM::VisitPackedSwitch(HPackedSwitch* switch_instr) {
8556   int32_t lower_bound = switch_instr->GetStartValue();
8557   uint32_t num_entries = switch_instr->GetNumEntries();
8558   LocationSummary* locations = switch_instr->GetLocations();
8559   Register value_reg = locations->InAt(0).AsRegister<Register>();
8560   HBasicBlock* default_block = switch_instr->GetDefaultBlock();
8561 
8562   if (num_entries <= kPackedSwitchCompareJumpThreshold || !codegen_->GetAssembler()->IsThumb()) {
8563     // Create a series of compare/jumps.
8564     Register temp_reg = IP;
8565     // Note: It is fine for the below AddConstantSetFlags() using IP register to temporarily store
8566     // the immediate, because IP is used as the destination register. For the other
8567     // AddConstantSetFlags() and GenerateCompareWithImmediate(), the immediate values are constant,
8568     // and they can be encoded in the instruction without making use of IP register.
8569     __ AddConstantSetFlags(temp_reg, value_reg, -lower_bound);
8570 
8571     const ArenaVector<HBasicBlock*>& successors = switch_instr->GetBlock()->GetSuccessors();
8572     // Jump to successors[0] if value == lower_bound.
8573     __ b(codegen_->GetLabelOf(successors[0]), EQ);
8574     int32_t last_index = 0;
8575     for (; num_entries - last_index > 2; last_index += 2) {
8576       __ AddConstantSetFlags(temp_reg, temp_reg, -2);
8577       // Jump to successors[last_index + 1] if value < case_value[last_index + 2].
8578       __ b(codegen_->GetLabelOf(successors[last_index + 1]), LO);
8579       // Jump to successors[last_index + 2] if value == case_value[last_index + 2].
8580       __ b(codegen_->GetLabelOf(successors[last_index + 2]), EQ);
8581     }
8582     if (num_entries - last_index == 2) {
8583       // The last missing case_value.
8584       __ CmpConstant(temp_reg, 1);
8585       __ b(codegen_->GetLabelOf(successors[last_index + 1]), EQ);
8586     }
8587 
8588     // And the default for any other value.
8589     if (!codegen_->GoesToNextBlock(switch_instr->GetBlock(), default_block)) {
8590       __ b(codegen_->GetLabelOf(default_block));
8591     }
8592   } else {
8593     // Create a table lookup.
8594     Register temp_reg = locations->GetTemp(0).AsRegister<Register>();
8595 
8596     // Materialize a pointer to the switch table
8597     std::vector<Label*> labels(num_entries);
8598     const ArenaVector<HBasicBlock*>& successors = switch_instr->GetBlock()->GetSuccessors();
8599     for (uint32_t i = 0; i < num_entries; i++) {
8600       labels[i] = codegen_->GetLabelOf(successors[i]);
8601     }
8602     JumpTable* table = __ CreateJumpTable(std::move(labels), temp_reg);
8603 
8604     // Remove the bias.
8605     Register key_reg;
8606     if (lower_bound != 0) {
8607       key_reg = locations->GetTemp(1).AsRegister<Register>();
8608       __ AddConstant(key_reg, value_reg, -lower_bound);
8609     } else {
8610       key_reg = value_reg;
8611     }
8612 
8613     // Check whether the value is in the table, jump to default block if not.
8614     __ CmpConstant(key_reg, num_entries - 1);
8615     __ b(codegen_->GetLabelOf(default_block), Condition::HI);
8616 
8617     // Load the displacement from the table.
8618     __ ldr(temp_reg, Address(temp_reg, key_reg, Shift::LSL, 2));
8619 
8620     // Dispatch is a direct add to the PC (for Thumb2).
8621     __ EmitJumpTableDispatch(table, temp_reg);
8622   }
8623 }
8624 
VisitArmDexCacheArraysBase(HArmDexCacheArraysBase * base)8625 void LocationsBuilderARM::VisitArmDexCacheArraysBase(HArmDexCacheArraysBase* base) {
8626   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(base);
8627   locations->SetOut(Location::RequiresRegister());
8628 }
8629 
VisitArmDexCacheArraysBase(HArmDexCacheArraysBase * base)8630 void InstructionCodeGeneratorARM::VisitArmDexCacheArraysBase(HArmDexCacheArraysBase* base) {
8631   Register base_reg = base->GetLocations()->Out().AsRegister<Register>();
8632   CodeGeneratorARM::PcRelativePatchInfo* labels =
8633       codegen_->NewPcRelativeDexCacheArrayPatch(base->GetDexFile(), base->GetElementOffset());
8634   __ BindTrackedLabel(&labels->movw_label);
8635   __ movw(base_reg, /* placeholder */ 0u);
8636   __ BindTrackedLabel(&labels->movt_label);
8637   __ movt(base_reg, /* placeholder */ 0u);
8638   __ BindTrackedLabel(&labels->add_pc_label);
8639   __ add(base_reg, base_reg, ShifterOperand(PC));
8640 }
8641 
MoveFromReturnRegister(Location trg,Primitive::Type type)8642 void CodeGeneratorARM::MoveFromReturnRegister(Location trg, Primitive::Type type) {
8643   if (!trg.IsValid()) {
8644     DCHECK_EQ(type, Primitive::kPrimVoid);
8645     return;
8646   }
8647 
8648   DCHECK_NE(type, Primitive::kPrimVoid);
8649 
8650   Location return_loc = InvokeDexCallingConventionVisitorARM().GetReturnLocation(type);
8651   if (return_loc.Equals(trg)) {
8652     return;
8653   }
8654 
8655   // TODO: Consider pairs in the parallel move resolver, then this could be nicely merged
8656   //       with the last branch.
8657   if (type == Primitive::kPrimLong) {
8658     HParallelMove parallel_move(GetGraph()->GetArena());
8659     parallel_move.AddMove(return_loc.ToLow(), trg.ToLow(), Primitive::kPrimInt, nullptr);
8660     parallel_move.AddMove(return_loc.ToHigh(), trg.ToHigh(), Primitive::kPrimInt, nullptr);
8661     GetMoveResolver()->EmitNativeCode(&parallel_move);
8662   } else if (type == Primitive::kPrimDouble) {
8663     HParallelMove parallel_move(GetGraph()->GetArena());
8664     parallel_move.AddMove(return_loc.ToLow(), trg.ToLow(), Primitive::kPrimFloat, nullptr);
8665     parallel_move.AddMove(return_loc.ToHigh(), trg.ToHigh(), Primitive::kPrimFloat, nullptr);
8666     GetMoveResolver()->EmitNativeCode(&parallel_move);
8667   } else {
8668     // Let the parallel move resolver take care of all of this.
8669     HParallelMove parallel_move(GetGraph()->GetArena());
8670     parallel_move.AddMove(return_loc, trg, type, nullptr);
8671     GetMoveResolver()->EmitNativeCode(&parallel_move);
8672   }
8673 }
8674 
VisitClassTableGet(HClassTableGet * instruction)8675 void LocationsBuilderARM::VisitClassTableGet(HClassTableGet* instruction) {
8676   LocationSummary* locations =
8677       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
8678   locations->SetInAt(0, Location::RequiresRegister());
8679   locations->SetOut(Location::RequiresRegister());
8680 }
8681 
VisitClassTableGet(HClassTableGet * instruction)8682 void InstructionCodeGeneratorARM::VisitClassTableGet(HClassTableGet* instruction) {
8683   LocationSummary* locations = instruction->GetLocations();
8684   if (instruction->GetTableKind() == HClassTableGet::TableKind::kVTable) {
8685     uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
8686         instruction->GetIndex(), kArmPointerSize).SizeValue();
8687     __ LoadFromOffset(kLoadWord,
8688                       locations->Out().AsRegister<Register>(),
8689                       locations->InAt(0).AsRegister<Register>(),
8690                       method_offset);
8691   } else {
8692     uint32_t method_offset = static_cast<uint32_t>(ImTable::OffsetOfElement(
8693         instruction->GetIndex(), kArmPointerSize));
8694     __ LoadFromOffset(kLoadWord,
8695                       locations->Out().AsRegister<Register>(),
8696                       locations->InAt(0).AsRegister<Register>(),
8697                       mirror::Class::ImtPtrOffset(kArmPointerSize).Uint32Value());
8698     __ LoadFromOffset(kLoadWord,
8699                       locations->Out().AsRegister<Register>(),
8700                       locations->Out().AsRegister<Register>(),
8701                       method_offset);
8702   }
8703 }
8704 
PatchJitRootUse(uint8_t * code,const uint8_t * roots_data,Literal * literal,uint64_t index_in_table)8705 static void PatchJitRootUse(uint8_t* code,
8706                             const uint8_t* roots_data,
8707                             Literal* literal,
8708                             uint64_t index_in_table) {
8709   DCHECK(literal->GetLabel()->IsBound());
8710   uint32_t literal_offset = literal->GetLabel()->Position();
8711   uintptr_t address =
8712       reinterpret_cast<uintptr_t>(roots_data) + index_in_table * sizeof(GcRoot<mirror::Object>);
8713   uint8_t* data = code + literal_offset;
8714   reinterpret_cast<uint32_t*>(data)[0] = dchecked_integral_cast<uint32_t>(address);
8715 }
8716 
EmitJitRootPatches(uint8_t * code,const uint8_t * roots_data)8717 void CodeGeneratorARM::EmitJitRootPatches(uint8_t* code, const uint8_t* roots_data) {
8718   for (const auto& entry : jit_string_patches_) {
8719     const auto& it = jit_string_roots_.find(entry.first);
8720     DCHECK(it != jit_string_roots_.end());
8721     PatchJitRootUse(code, roots_data, entry.second, it->second);
8722   }
8723   for (const auto& entry : jit_class_patches_) {
8724     const auto& it = jit_class_roots_.find(entry.first);
8725     DCHECK(it != jit_class_roots_.end());
8726     PatchJitRootUse(code, roots_data, entry.second, it->second);
8727   }
8728 }
8729 
8730 #undef __
8731 #undef QUICK_ENTRY_POINT
8732 
8733 }  // namespace arm
8734 }  // namespace art
8735