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 "entrypoints/quick/quick_entrypoints.h"
20 #include "gc/accounting/card_table.h"
21 #include "mirror/array.h"
22 #include "mirror/art_method.h"
23 #include "thread.h"
24 #include "utils/assembler.h"
25 #include "utils/arm/assembler_arm.h"
26 #include "utils/arm/managed_register_arm.h"
27 #include "utils/stack_checks.h"
28 
29 namespace art {
30 
AsArm() const31 arm::ArmManagedRegister Location::AsArm() const {
32   return reg().AsArm();
33 }
34 
35 namespace arm {
36 
37 static constexpr bool kExplicitStackOverflowCheck = false;
38 
39 static constexpr int kNumberOfPushedRegistersAtEntry = 1 + 2;  // LR, R6, R7
40 static constexpr int kCurrentMethodStackOffset = 0;
41 
ArmCoreLocation(Register reg)42 static Location ArmCoreLocation(Register reg) {
43   return Location::RegisterLocation(ArmManagedRegister::FromCoreRegister(reg));
44 }
45 
46 static constexpr Register kRuntimeParameterCoreRegisters[] = { R0, R1, R2 };
47 static constexpr size_t kRuntimeParameterCoreRegistersLength =
48     arraysize(kRuntimeParameterCoreRegisters);
49 
50 class InvokeRuntimeCallingConvention : public CallingConvention<Register> {
51  public:
InvokeRuntimeCallingConvention()52   InvokeRuntimeCallingConvention()
53       : CallingConvention(kRuntimeParameterCoreRegisters,
54                           kRuntimeParameterCoreRegistersLength) {}
55 
56  private:
57   DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention);
58 };
59 
60 #define __ reinterpret_cast<ArmAssembler*>(codegen->GetAssembler())->
61 
62 class NullCheckSlowPathARM : public SlowPathCode {
63  public:
NullCheckSlowPathARM(uint32_t dex_pc)64   explicit NullCheckSlowPathARM(uint32_t dex_pc) : dex_pc_(dex_pc) {}
65 
EmitNativeCode(CodeGenerator * codegen)66   virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
67     __ Bind(GetEntryLabel());
68     int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pThrowNullPointer).Int32Value();
69     __ ldr(LR, Address(TR, offset));
70     __ blx(LR);
71     codegen->RecordPcInfo(dex_pc_);
72   }
73 
74  private:
75   const uint32_t dex_pc_;
76   DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathARM);
77 };
78 
79 class StackOverflowCheckSlowPathARM : public SlowPathCode {
80  public:
StackOverflowCheckSlowPathARM()81   StackOverflowCheckSlowPathARM() {}
82 
EmitNativeCode(CodeGenerator * codegen)83   virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
84     __ Bind(GetEntryLabel());
85     __ LoadFromOffset(kLoadWord, PC, TR,
86         QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pThrowStackOverflow).Int32Value());
87   }
88 
89  private:
90   DISALLOW_COPY_AND_ASSIGN(StackOverflowCheckSlowPathARM);
91 };
92 
93 class BoundsCheckSlowPathARM : public SlowPathCode {
94  public:
BoundsCheckSlowPathARM(uint32_t dex_pc,Location index_location,Location length_location)95   explicit BoundsCheckSlowPathARM(uint32_t dex_pc,
96                                   Location index_location,
97                                   Location length_location)
98       : dex_pc_(dex_pc), index_location_(index_location), length_location_(length_location) {}
99 
EmitNativeCode(CodeGenerator * codegen)100   virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
101     CodeGeneratorARM* arm_codegen = reinterpret_cast<CodeGeneratorARM*>(codegen);
102     __ Bind(GetEntryLabel());
103     InvokeRuntimeCallingConvention calling_convention;
104     arm_codegen->Move32(ArmCoreLocation(calling_convention.GetRegisterAt(0)), index_location_);
105     arm_codegen->Move32(ArmCoreLocation(calling_convention.GetRegisterAt(1)), length_location_);
106     int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pThrowArrayBounds).Int32Value();
107     __ ldr(LR, Address(TR, offset));
108     __ blx(LR);
109     codegen->RecordPcInfo(dex_pc_);
110   }
111 
112  private:
113   const uint32_t dex_pc_;
114   const Location index_location_;
115   const Location length_location_;
116 
117   DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathARM);
118 };
119 
120 #undef __
121 #define __ reinterpret_cast<ArmAssembler*>(GetAssembler())->
122 
ARMCondition(IfCondition cond)123 inline Condition ARMCondition(IfCondition cond) {
124   switch (cond) {
125     case kCondEQ: return EQ;
126     case kCondNE: return NE;
127     case kCondLT: return LT;
128     case kCondLE: return LE;
129     case kCondGT: return GT;
130     case kCondGE: return GE;
131     default:
132       LOG(FATAL) << "Unknown if condition";
133   }
134   return EQ;        // Unreachable.
135 }
136 
ARMOppositeCondition(IfCondition cond)137 inline Condition ARMOppositeCondition(IfCondition cond) {
138   switch (cond) {
139     case kCondEQ: return NE;
140     case kCondNE: return EQ;
141     case kCondLT: return GE;
142     case kCondLE: return GT;
143     case kCondGT: return LE;
144     case kCondGE: return LT;
145     default:
146       LOG(FATAL) << "Unknown if condition";
147   }
148   return EQ;        // Unreachable.
149 }
150 
DumpCoreRegister(std::ostream & stream,int reg) const151 void CodeGeneratorARM::DumpCoreRegister(std::ostream& stream, int reg) const {
152   stream << ArmManagedRegister::FromCoreRegister(Register(reg));
153 }
154 
DumpFloatingPointRegister(std::ostream & stream,int reg) const155 void CodeGeneratorARM::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
156   stream << ArmManagedRegister::FromDRegister(DRegister(reg));
157 }
158 
CodeGeneratorARM(HGraph * graph)159 CodeGeneratorARM::CodeGeneratorARM(HGraph* graph)
160     : CodeGenerator(graph, kNumberOfRegIds),
161       location_builder_(graph, this),
162       instruction_visitor_(graph, this),
163       move_resolver_(graph->GetArena(), this),
164       assembler_(true) {}
165 
FrameEntrySpillSize() const166 size_t CodeGeneratorARM::FrameEntrySpillSize() const {
167   return kNumberOfPushedRegistersAtEntry * kArmWordSize;
168 }
169 
GetBlockedRegisterPairs(bool * blocked_registers)170 static bool* GetBlockedRegisterPairs(bool* blocked_registers) {
171   return blocked_registers + kNumberOfAllocIds;
172 }
173 
AllocateFreeRegister(Primitive::Type type,bool * blocked_registers) const174 ManagedRegister CodeGeneratorARM::AllocateFreeRegister(Primitive::Type type,
175                                                        bool* blocked_registers) const {
176   switch (type) {
177     case Primitive::kPrimLong: {
178       bool* blocked_register_pairs = GetBlockedRegisterPairs(blocked_registers);
179       size_t reg = AllocateFreeRegisterInternal(blocked_register_pairs, kNumberOfRegisterPairs);
180       ArmManagedRegister pair =
181           ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(reg));
182       blocked_registers[pair.AsRegisterPairLow()] = true;
183       blocked_registers[pair.AsRegisterPairHigh()] = true;
184        // Block all other register pairs that share a register with `pair`.
185       for (int i = 0; i < kNumberOfRegisterPairs; i++) {
186         ArmManagedRegister current =
187             ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
188         if (current.AsRegisterPairLow() == pair.AsRegisterPairLow()
189             || current.AsRegisterPairLow() == pair.AsRegisterPairHigh()
190             || current.AsRegisterPairHigh() == pair.AsRegisterPairLow()
191             || current.AsRegisterPairHigh() == pair.AsRegisterPairHigh()) {
192           blocked_register_pairs[i] = true;
193         }
194       }
195       return pair;
196     }
197 
198     case Primitive::kPrimByte:
199     case Primitive::kPrimBoolean:
200     case Primitive::kPrimChar:
201     case Primitive::kPrimShort:
202     case Primitive::kPrimInt:
203     case Primitive::kPrimNot: {
204       int reg = AllocateFreeRegisterInternal(blocked_registers, kNumberOfCoreRegisters);
205       // Block all register pairs that contain `reg`.
206       bool* blocked_register_pairs = GetBlockedRegisterPairs(blocked_registers);
207       for (int i = 0; i < kNumberOfRegisterPairs; i++) {
208         ArmManagedRegister current =
209             ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
210         if (current.AsRegisterPairLow() == reg || current.AsRegisterPairHigh() == reg) {
211           blocked_register_pairs[i] = true;
212         }
213       }
214       return ArmManagedRegister::FromCoreRegister(static_cast<Register>(reg));
215     }
216 
217     case Primitive::kPrimFloat:
218     case Primitive::kPrimDouble:
219       LOG(FATAL) << "Unimplemented register type " << type;
220 
221     case Primitive::kPrimVoid:
222       LOG(FATAL) << "Unreachable type " << type;
223   }
224 
225   return ManagedRegister::NoRegister();
226 }
227 
SetupBlockedRegisters(bool * blocked_registers) const228 void CodeGeneratorARM::SetupBlockedRegisters(bool* blocked_registers) const {
229   bool* blocked_register_pairs = GetBlockedRegisterPairs(blocked_registers);
230 
231   // Don't allocate the dalvik style register pair passing.
232   blocked_register_pairs[R1_R2] = true;
233 
234   // Stack register, LR and PC are always reserved.
235   blocked_registers[SP] = true;
236   blocked_registers[LR] = true;
237   blocked_registers[PC] = true;
238 
239   // Reserve R4 for suspend check.
240   blocked_registers[R4] = true;
241   blocked_register_pairs[R4_R5] = true;
242 
243   // Reserve thread register.
244   blocked_registers[TR] = true;
245 
246   // Reserve temp register.
247   blocked_registers[IP] = true;
248 
249   // TODO: We currently don't use Quick's callee saved registers.
250   // We always save and restore R6 and R7 to make sure we can use three
251   // register pairs for long operations.
252   blocked_registers[R5] = true;
253   blocked_registers[R8] = true;
254   blocked_registers[R10] = true;
255   blocked_registers[R11] = true;
256 }
257 
GetNumberOfRegisters() const258 size_t CodeGeneratorARM::GetNumberOfRegisters() const {
259   return kNumberOfRegIds;
260 }
261 
InstructionCodeGeneratorARM(HGraph * graph,CodeGeneratorARM * codegen)262 InstructionCodeGeneratorARM::InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen)
263       : HGraphVisitor(graph),
264         assembler_(codegen->GetAssembler()),
265         codegen_(codegen) {}
266 
GenerateFrameEntry()267 void CodeGeneratorARM::GenerateFrameEntry() {
268   bool skip_overflow_check = IsLeafMethod() && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kArm);
269   if (!skip_overflow_check) {
270     if (kExplicitStackOverflowCheck) {
271       SlowPathCode* slow_path = new (GetGraph()->GetArena()) StackOverflowCheckSlowPathARM();
272       AddSlowPath(slow_path);
273 
274       __ LoadFromOffset(kLoadWord, IP, TR, Thread::StackEndOffset<kArmWordSize>().Int32Value());
275       __ cmp(SP, ShifterOperand(IP));
276       __ b(slow_path->GetEntryLabel(), CC);
277     } else {
278       __ AddConstant(IP, SP, -static_cast<int32_t>(GetStackOverflowReservedBytes(kArm)));
279       __ ldr(IP, Address(IP, 0));
280       RecordPcInfo(0);
281     }
282   }
283 
284   core_spill_mask_ |= (1 << LR | 1 << R6 | 1 << R7);
285   __ PushList(1 << LR | 1 << R6 | 1 << R7);
286 
287   // The return PC has already been pushed on the stack.
288   __ AddConstant(SP, -(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kArmWordSize));
289   __ str(R0, Address(SP, 0));
290 }
291 
GenerateFrameExit()292 void CodeGeneratorARM::GenerateFrameExit() {
293   __ AddConstant(SP, GetFrameSize() - kNumberOfPushedRegistersAtEntry * kArmWordSize);
294   __ PopList(1 << PC | 1 << R6 | 1 << R7);
295 }
296 
Bind(Label * label)297 void CodeGeneratorARM::Bind(Label* label) {
298   __ Bind(label);
299 }
300 
GetStackLocation(HLoadLocal * load) const301 Location CodeGeneratorARM::GetStackLocation(HLoadLocal* load) const {
302   switch (load->GetType()) {
303     case Primitive::kPrimLong:
304       return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
305       break;
306 
307     case Primitive::kPrimInt:
308     case Primitive::kPrimNot:
309       return Location::StackSlot(GetStackSlot(load->GetLocal()));
310 
311     case Primitive::kPrimFloat:
312     case Primitive::kPrimDouble:
313       LOG(FATAL) << "Unimplemented type " << load->GetType();
314 
315     case Primitive::kPrimBoolean:
316     case Primitive::kPrimByte:
317     case Primitive::kPrimChar:
318     case Primitive::kPrimShort:
319     case Primitive::kPrimVoid:
320       LOG(FATAL) << "Unexpected type " << load->GetType();
321   }
322 
323   LOG(FATAL) << "Unreachable";
324   return Location();
325 }
326 
GetNextLocation(Primitive::Type type)327 Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) {
328   switch (type) {
329     case Primitive::kPrimBoolean:
330     case Primitive::kPrimByte:
331     case Primitive::kPrimChar:
332     case Primitive::kPrimShort:
333     case Primitive::kPrimInt:
334     case Primitive::kPrimNot: {
335       uint32_t index = gp_index_++;
336       if (index < calling_convention.GetNumberOfRegisters()) {
337         return ArmCoreLocation(calling_convention.GetRegisterAt(index));
338       } else {
339         return Location::StackSlot(calling_convention.GetStackOffsetOf(index));
340       }
341     }
342 
343     case Primitive::kPrimLong: {
344       uint32_t index = gp_index_;
345       gp_index_ += 2;
346       if (index + 1 < calling_convention.GetNumberOfRegisters()) {
347         return Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(
348             calling_convention.GetRegisterPairAt(index)));
349       } else if (index + 1 == calling_convention.GetNumberOfRegisters()) {
350         return Location::QuickParameter(index);
351       } else {
352         return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(index));
353       }
354     }
355 
356     case Primitive::kPrimDouble:
357     case Primitive::kPrimFloat:
358       LOG(FATAL) << "Unimplemented parameter type " << type;
359       break;
360 
361     case Primitive::kPrimVoid:
362       LOG(FATAL) << "Unexpected parameter type " << type;
363       break;
364   }
365   return Location();
366 }
367 
Move32(Location destination,Location source)368 void CodeGeneratorARM::Move32(Location destination, Location source) {
369   if (source.Equals(destination)) {
370     return;
371   }
372   if (destination.IsRegister()) {
373     if (source.IsRegister()) {
374       __ Mov(destination.AsArm().AsCoreRegister(), source.AsArm().AsCoreRegister());
375     } else {
376       __ ldr(destination.AsArm().AsCoreRegister(), Address(SP, source.GetStackIndex()));
377     }
378   } else {
379     DCHECK(destination.IsStackSlot());
380     if (source.IsRegister()) {
381       __ str(source.AsArm().AsCoreRegister(), Address(SP, destination.GetStackIndex()));
382     } else {
383       __ ldr(IP, Address(SP, source.GetStackIndex()));
384       __ str(IP, Address(SP, destination.GetStackIndex()));
385     }
386   }
387 }
388 
Move64(Location destination,Location source)389 void CodeGeneratorARM::Move64(Location destination, Location source) {
390   if (source.Equals(destination)) {
391     return;
392   }
393   if (destination.IsRegister()) {
394     if (source.IsRegister()) {
395       __ Mov(destination.AsArm().AsRegisterPairLow(), source.AsArm().AsRegisterPairLow());
396       __ Mov(destination.AsArm().AsRegisterPairHigh(), source.AsArm().AsRegisterPairHigh());
397     } else if (source.IsQuickParameter()) {
398       uint32_t argument_index = source.GetQuickParameterIndex();
399       InvokeDexCallingConvention calling_convention;
400       __ Mov(destination.AsArm().AsRegisterPairLow(),
401              calling_convention.GetRegisterAt(argument_index));
402       __ ldr(destination.AsArm().AsRegisterPairHigh(),
403              Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1) + GetFrameSize()));
404     } else {
405       DCHECK(source.IsDoubleStackSlot());
406       if (destination.AsArm().AsRegisterPair() == R1_R2) {
407         __ ldr(R1, Address(SP, source.GetStackIndex()));
408         __ ldr(R2, Address(SP, source.GetHighStackIndex(kArmWordSize)));
409       } else {
410         __ LoadFromOffset(kLoadWordPair, destination.AsArm().AsRegisterPairLow(),
411                           SP, source.GetStackIndex());
412       }
413     }
414   } else if (destination.IsQuickParameter()) {
415     InvokeDexCallingConvention calling_convention;
416     uint32_t argument_index = destination.GetQuickParameterIndex();
417     if (source.IsRegister()) {
418       __ Mov(calling_convention.GetRegisterAt(argument_index), source.AsArm().AsRegisterPairLow());
419       __ str(source.AsArm().AsRegisterPairHigh(),
420              Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1)));
421     } else {
422       DCHECK(source.IsDoubleStackSlot());
423       __ ldr(calling_convention.GetRegisterAt(argument_index), Address(SP, source.GetStackIndex()));
424       __ ldr(R0, Address(SP, source.GetHighStackIndex(kArmWordSize)));
425       __ str(R0, Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1)));
426     }
427   } else {
428     DCHECK(destination.IsDoubleStackSlot());
429     if (source.IsRegister()) {
430       if (source.AsArm().AsRegisterPair() == R1_R2) {
431         __ str(R1, Address(SP, destination.GetStackIndex()));
432         __ str(R2, Address(SP, destination.GetHighStackIndex(kArmWordSize)));
433       } else {
434         __ StoreToOffset(kStoreWordPair, source.AsArm().AsRegisterPairLow(),
435                          SP, destination.GetStackIndex());
436       }
437     } else if (source.IsQuickParameter()) {
438       InvokeDexCallingConvention calling_convention;
439       uint32_t argument_index = source.GetQuickParameterIndex();
440       __ str(calling_convention.GetRegisterAt(argument_index),
441              Address(SP, destination.GetStackIndex()));
442       __ ldr(R0,
443              Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1) + GetFrameSize()));
444       __ str(R0, Address(SP, destination.GetHighStackIndex(kArmWordSize)));
445     } else {
446       DCHECK(source.IsDoubleStackSlot());
447       __ ldr(IP, Address(SP, source.GetStackIndex()));
448       __ str(IP, Address(SP, destination.GetStackIndex()));
449       __ ldr(IP, Address(SP, source.GetHighStackIndex(kArmWordSize)));
450       __ str(IP, Address(SP, destination.GetHighStackIndex(kArmWordSize)));
451     }
452   }
453 }
454 
Move(HInstruction * instruction,Location location,HInstruction * move_for)455 void CodeGeneratorARM::Move(HInstruction* instruction, Location location, HInstruction* move_for) {
456   LocationSummary* locations = instruction->GetLocations();
457   if (locations != nullptr && locations->Out().Equals(location)) {
458     return;
459   }
460 
461   if (instruction->AsIntConstant() != nullptr) {
462     int32_t value = instruction->AsIntConstant()->GetValue();
463     if (location.IsRegister()) {
464       __ LoadImmediate(location.AsArm().AsCoreRegister(), value);
465     } else {
466       DCHECK(location.IsStackSlot());
467       __ LoadImmediate(IP, value);
468       __ str(IP, Address(SP, location.GetStackIndex()));
469     }
470   } else if (instruction->AsLongConstant() != nullptr) {
471     int64_t value = instruction->AsLongConstant()->GetValue();
472     if (location.IsRegister()) {
473       __ LoadImmediate(location.AsArm().AsRegisterPairLow(), Low32Bits(value));
474       __ LoadImmediate(location.AsArm().AsRegisterPairHigh(), High32Bits(value));
475     } else {
476       DCHECK(location.IsDoubleStackSlot());
477       __ LoadImmediate(IP, Low32Bits(value));
478       __ str(IP, Address(SP, location.GetStackIndex()));
479       __ LoadImmediate(IP, High32Bits(value));
480       __ str(IP, Address(SP, location.GetHighStackIndex(kArmWordSize)));
481     }
482   } else if (instruction->AsLoadLocal() != nullptr) {
483     uint32_t stack_slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
484     switch (instruction->GetType()) {
485       case Primitive::kPrimBoolean:
486       case Primitive::kPrimByte:
487       case Primitive::kPrimChar:
488       case Primitive::kPrimShort:
489       case Primitive::kPrimInt:
490       case Primitive::kPrimNot:
491         Move32(location, Location::StackSlot(stack_slot));
492         break;
493 
494       case Primitive::kPrimLong:
495         Move64(location, Location::DoubleStackSlot(stack_slot));
496         break;
497 
498       default:
499         LOG(FATAL) << "Unimplemented type " << instruction->GetType();
500     }
501   } else {
502     DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
503     switch (instruction->GetType()) {
504       case Primitive::kPrimBoolean:
505       case Primitive::kPrimByte:
506       case Primitive::kPrimChar:
507       case Primitive::kPrimShort:
508       case Primitive::kPrimNot:
509       case Primitive::kPrimInt:
510         Move32(location, locations->Out());
511         break;
512 
513       case Primitive::kPrimLong:
514         Move64(location, locations->Out());
515         break;
516 
517       default:
518         LOG(FATAL) << "Unimplemented type " << instruction->GetType();
519     }
520   }
521 }
522 
VisitGoto(HGoto * got)523 void LocationsBuilderARM::VisitGoto(HGoto* got) {
524   got->SetLocations(nullptr);
525 }
526 
VisitGoto(HGoto * got)527 void InstructionCodeGeneratorARM::VisitGoto(HGoto* got) {
528   HBasicBlock* successor = got->GetSuccessor();
529   if (GetGraph()->GetExitBlock() == successor) {
530     codegen_->GenerateFrameExit();
531   } else if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
532     __ b(codegen_->GetLabelOf(successor));
533   }
534 }
535 
VisitExit(HExit * exit)536 void LocationsBuilderARM::VisitExit(HExit* exit) {
537   exit->SetLocations(nullptr);
538 }
539 
VisitExit(HExit * exit)540 void InstructionCodeGeneratorARM::VisitExit(HExit* exit) {
541   if (kIsDebugBuild) {
542     __ Comment("Unreachable");
543     __ bkpt(0);
544   }
545 }
546 
VisitIf(HIf * if_instr)547 void LocationsBuilderARM::VisitIf(HIf* if_instr) {
548   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr);
549   HInstruction* cond = if_instr->InputAt(0);
550   DCHECK(cond->IsCondition());
551   HCondition* condition = cond->AsCondition();
552   if (condition->NeedsMaterialization()) {
553     locations->SetInAt(0, Location::Any());
554   }
555   if_instr->SetLocations(locations);
556 }
557 
VisitIf(HIf * if_instr)558 void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) {
559   HInstruction* cond = if_instr->InputAt(0);
560   DCHECK(cond->IsCondition());
561   HCondition* condition = cond->AsCondition();
562   if (condition->NeedsMaterialization()) {
563     // Condition has been materialized, compare the output to 0
564     DCHECK(if_instr->GetLocations()->InAt(0).IsRegister());
565     __ cmp(if_instr->GetLocations()->InAt(0).AsArm().AsCoreRegister(),
566            ShifterOperand(0));
567     __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()), EQ);
568   } else {
569     // Condition has not been materialized, use its inputs as the comparison and its
570     // condition as the branch condition.
571     LocationSummary* locations = condition->GetLocations();
572     if (locations->InAt(1).IsRegister()) {
573       __ cmp(locations->InAt(0).AsArm().AsCoreRegister(),
574              ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
575     } else {
576       DCHECK(locations->InAt(1).IsConstant());
577       int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
578       ShifterOperand operand;
579       if (ShifterOperand::CanHoldArm(value, &operand)) {
580         __ cmp(locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(value));
581       } else {
582         Register temp = IP;
583         __ LoadImmediate(temp, value);
584         __ cmp(locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(temp));
585       }
586     }
587     __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()),
588          ARMCondition(condition->GetCondition()));
589   }
590 
591   if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfFalseSuccessor())) {
592     __ b(codegen_->GetLabelOf(if_instr->IfFalseSuccessor()));
593   }
594 }
595 
596 
VisitCondition(HCondition * comp)597 void LocationsBuilderARM::VisitCondition(HCondition* comp) {
598   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(comp);
599   locations->SetInAt(0, Location::RequiresRegister());
600   locations->SetInAt(1, Location::RegisterOrConstant(comp->InputAt(1)));
601   if (comp->NeedsMaterialization()) {
602     locations->SetOut(Location::RequiresRegister());
603   }
604   comp->SetLocations(locations);
605 }
606 
VisitCondition(HCondition * comp)607 void InstructionCodeGeneratorARM::VisitCondition(HCondition* comp) {
608   if (!comp->NeedsMaterialization()) return;
609 
610   LocationSummary* locations = comp->GetLocations();
611   if (locations->InAt(1).IsRegister()) {
612     __ cmp(locations->InAt(0).AsArm().AsCoreRegister(),
613            ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
614   } else {
615     DCHECK(locations->InAt(1).IsConstant());
616     int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
617     ShifterOperand operand;
618     if (ShifterOperand::CanHoldArm(value, &operand)) {
619       __ cmp(locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(value));
620     } else {
621       Register temp = IP;
622       __ LoadImmediate(temp, value);
623       __ cmp(locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(temp));
624     }
625   }
626   __ it(ARMCondition(comp->GetCondition()), kItElse);
627   __ mov(locations->Out().AsArm().AsCoreRegister(), ShifterOperand(1),
628          ARMCondition(comp->GetCondition()));
629   __ mov(locations->Out().AsArm().AsCoreRegister(), ShifterOperand(0),
630          ARMOppositeCondition(comp->GetCondition()));
631 }
632 
VisitEqual(HEqual * comp)633 void LocationsBuilderARM::VisitEqual(HEqual* comp) {
634   VisitCondition(comp);
635 }
636 
VisitEqual(HEqual * comp)637 void InstructionCodeGeneratorARM::VisitEqual(HEqual* comp) {
638   VisitCondition(comp);
639 }
640 
VisitNotEqual(HNotEqual * comp)641 void LocationsBuilderARM::VisitNotEqual(HNotEqual* comp) {
642   VisitCondition(comp);
643 }
644 
VisitNotEqual(HNotEqual * comp)645 void InstructionCodeGeneratorARM::VisitNotEqual(HNotEqual* comp) {
646   VisitCondition(comp);
647 }
648 
VisitLessThan(HLessThan * comp)649 void LocationsBuilderARM::VisitLessThan(HLessThan* comp) {
650   VisitCondition(comp);
651 }
652 
VisitLessThan(HLessThan * comp)653 void InstructionCodeGeneratorARM::VisitLessThan(HLessThan* comp) {
654   VisitCondition(comp);
655 }
656 
VisitLessThanOrEqual(HLessThanOrEqual * comp)657 void LocationsBuilderARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
658   VisitCondition(comp);
659 }
660 
VisitLessThanOrEqual(HLessThanOrEqual * comp)661 void InstructionCodeGeneratorARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
662   VisitCondition(comp);
663 }
664 
VisitGreaterThan(HGreaterThan * comp)665 void LocationsBuilderARM::VisitGreaterThan(HGreaterThan* comp) {
666   VisitCondition(comp);
667 }
668 
VisitGreaterThan(HGreaterThan * comp)669 void InstructionCodeGeneratorARM::VisitGreaterThan(HGreaterThan* comp) {
670   VisitCondition(comp);
671 }
672 
VisitGreaterThanOrEqual(HGreaterThanOrEqual * comp)673 void LocationsBuilderARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
674   VisitCondition(comp);
675 }
676 
VisitGreaterThanOrEqual(HGreaterThanOrEqual * comp)677 void InstructionCodeGeneratorARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
678   VisitCondition(comp);
679 }
680 
VisitLocal(HLocal * local)681 void LocationsBuilderARM::VisitLocal(HLocal* local) {
682   local->SetLocations(nullptr);
683 }
684 
VisitLocal(HLocal * local)685 void InstructionCodeGeneratorARM::VisitLocal(HLocal* local) {
686   DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
687 }
688 
VisitLoadLocal(HLoadLocal * load)689 void LocationsBuilderARM::VisitLoadLocal(HLoadLocal* load) {
690   load->SetLocations(nullptr);
691 }
692 
VisitLoadLocal(HLoadLocal * load)693 void InstructionCodeGeneratorARM::VisitLoadLocal(HLoadLocal* load) {
694   // Nothing to do, this is driven by the code generator.
695 }
696 
VisitStoreLocal(HStoreLocal * store)697 void LocationsBuilderARM::VisitStoreLocal(HStoreLocal* store) {
698   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(store);
699   switch (store->InputAt(1)->GetType()) {
700     case Primitive::kPrimBoolean:
701     case Primitive::kPrimByte:
702     case Primitive::kPrimChar:
703     case Primitive::kPrimShort:
704     case Primitive::kPrimInt:
705     case Primitive::kPrimNot:
706       locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
707       break;
708 
709     case Primitive::kPrimLong:
710       locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
711       break;
712 
713     default:
714       LOG(FATAL) << "Unimplemented local type " << store->InputAt(1)->GetType();
715   }
716   store->SetLocations(locations);
717 }
718 
VisitStoreLocal(HStoreLocal * store)719 void InstructionCodeGeneratorARM::VisitStoreLocal(HStoreLocal* store) {
720 }
721 
VisitIntConstant(HIntConstant * constant)722 void LocationsBuilderARM::VisitIntConstant(HIntConstant* constant) {
723   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
724   locations->SetOut(Location::ConstantLocation(constant));
725   constant->SetLocations(locations);
726 }
727 
VisitIntConstant(HIntConstant * constant)728 void InstructionCodeGeneratorARM::VisitIntConstant(HIntConstant* constant) {
729 }
730 
VisitLongConstant(HLongConstant * constant)731 void LocationsBuilderARM::VisitLongConstant(HLongConstant* constant) {
732   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
733   locations->SetOut(Location::ConstantLocation(constant));
734   constant->SetLocations(locations);
735 }
736 
VisitLongConstant(HLongConstant * constant)737 void InstructionCodeGeneratorARM::VisitLongConstant(HLongConstant* constant) {
738   // Will be generated at use site.
739 }
740 
VisitReturnVoid(HReturnVoid * ret)741 void LocationsBuilderARM::VisitReturnVoid(HReturnVoid* ret) {
742   ret->SetLocations(nullptr);
743 }
744 
VisitReturnVoid(HReturnVoid * ret)745 void InstructionCodeGeneratorARM::VisitReturnVoid(HReturnVoid* ret) {
746   codegen_->GenerateFrameExit();
747 }
748 
VisitReturn(HReturn * ret)749 void LocationsBuilderARM::VisitReturn(HReturn* ret) {
750   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(ret);
751   switch (ret->InputAt(0)->GetType()) {
752     case Primitive::kPrimBoolean:
753     case Primitive::kPrimByte:
754     case Primitive::kPrimChar:
755     case Primitive::kPrimShort:
756     case Primitive::kPrimInt:
757     case Primitive::kPrimNot:
758       locations->SetInAt(0, ArmCoreLocation(R0));
759       break;
760 
761     case Primitive::kPrimLong:
762       locations->SetInAt(
763           0, Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(R0_R1)));
764       break;
765 
766     default:
767       LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
768   }
769 
770   ret->SetLocations(locations);
771 }
772 
VisitReturn(HReturn * ret)773 void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret) {
774   if (kIsDebugBuild) {
775     switch (ret->InputAt(0)->GetType()) {
776       case Primitive::kPrimBoolean:
777       case Primitive::kPrimByte:
778       case Primitive::kPrimChar:
779       case Primitive::kPrimShort:
780       case Primitive::kPrimInt:
781       case Primitive::kPrimNot:
782         DCHECK_EQ(ret->GetLocations()->InAt(0).AsArm().AsCoreRegister(), R0);
783         break;
784 
785       case Primitive::kPrimLong:
786         DCHECK_EQ(ret->GetLocations()->InAt(0).AsArm().AsRegisterPair(), R0_R1);
787         break;
788 
789       default:
790         LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
791     }
792   }
793   codegen_->GenerateFrameExit();
794 }
795 
VisitInvokeStatic(HInvokeStatic * invoke)796 void LocationsBuilderARM::VisitInvokeStatic(HInvokeStatic* invoke) {
797   codegen_->MarkNotLeaf();
798   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(invoke);
799   locations->AddTemp(ArmCoreLocation(R0));
800 
801   InvokeDexCallingConventionVisitor calling_convention_visitor;
802   for (size_t i = 0; i < invoke->InputCount(); i++) {
803     HInstruction* input = invoke->InputAt(i);
804     locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
805   }
806 
807   switch (invoke->GetType()) {
808     case Primitive::kPrimBoolean:
809     case Primitive::kPrimByte:
810     case Primitive::kPrimChar:
811     case Primitive::kPrimShort:
812     case Primitive::kPrimInt:
813     case Primitive::kPrimNot:
814       locations->SetOut(ArmCoreLocation(R0));
815       break;
816 
817     case Primitive::kPrimLong:
818       locations->SetOut(Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(R0_R1)));
819       break;
820 
821     case Primitive::kPrimVoid:
822       break;
823 
824     case Primitive::kPrimDouble:
825     case Primitive::kPrimFloat:
826       LOG(FATAL) << "Unimplemented return type " << invoke->GetType();
827       break;
828   }
829 
830   invoke->SetLocations(locations);
831 }
832 
LoadCurrentMethod(Register reg)833 void InstructionCodeGeneratorARM::LoadCurrentMethod(Register reg) {
834   __ ldr(reg, Address(SP, kCurrentMethodStackOffset));
835 }
836 
VisitInvokeStatic(HInvokeStatic * invoke)837 void InstructionCodeGeneratorARM::VisitInvokeStatic(HInvokeStatic* invoke) {
838   Register temp = invoke->GetLocations()->GetTemp(0).AsArm().AsCoreRegister();
839   uint32_t heap_reference_size = sizeof(mirror::HeapReference<mirror::Object>);
840   size_t index_in_cache = mirror::Array::DataOffset(heap_reference_size).Int32Value() +
841       invoke->GetIndexInDexCache() * kArmWordSize;
842 
843   // TODO: Implement all kinds of calls:
844   // 1) boot -> boot
845   // 2) app -> boot
846   // 3) app -> app
847   //
848   // Currently we implement the app -> app logic, which looks up in the resolve cache.
849 
850   // temp = method;
851   LoadCurrentMethod(temp);
852   // temp = temp->dex_cache_resolved_methods_;
853   __ ldr(temp, Address(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value()));
854   // temp = temp[index_in_cache]
855   __ ldr(temp, Address(temp, index_in_cache));
856   // LR = temp[offset_of_quick_compiled_code]
857   __ ldr(LR, Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(
858       kArmPointerSize).Int32Value()));
859   // LR()
860   __ blx(LR);
861 
862   codegen_->RecordPcInfo(invoke->GetDexPc());
863   DCHECK(!codegen_->IsLeafMethod());
864 }
865 
VisitAdd(HAdd * add)866 void LocationsBuilderARM::VisitAdd(HAdd* add) {
867   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(add);
868   switch (add->GetResultType()) {
869     case Primitive::kPrimInt:
870     case Primitive::kPrimLong: {
871       locations->SetInAt(0, Location::RequiresRegister());
872       locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
873       locations->SetOut(Location::RequiresRegister());
874       break;
875     }
876 
877     case Primitive::kPrimBoolean:
878     case Primitive::kPrimByte:
879     case Primitive::kPrimChar:
880     case Primitive::kPrimShort:
881       LOG(FATAL) << "Unexpected add type " << add->GetResultType();
882       break;
883 
884     default:
885       LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
886   }
887   add->SetLocations(locations);
888 }
889 
VisitAdd(HAdd * add)890 void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) {
891   LocationSummary* locations = add->GetLocations();
892   switch (add->GetResultType()) {
893     case Primitive::kPrimInt:
894       if (locations->InAt(1).IsRegister()) {
895         __ add(locations->Out().AsArm().AsCoreRegister(),
896                locations->InAt(0).AsArm().AsCoreRegister(),
897                ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
898       } else {
899         __ AddConstant(locations->Out().AsArm().AsCoreRegister(),
900                        locations->InAt(0).AsArm().AsCoreRegister(),
901                        locations->InAt(1).GetConstant()->AsIntConstant()->GetValue());
902       }
903       break;
904 
905     case Primitive::kPrimLong:
906       __ adds(locations->Out().AsArm().AsRegisterPairLow(),
907               locations->InAt(0).AsArm().AsRegisterPairLow(),
908               ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairLow()));
909       __ adc(locations->Out().AsArm().AsRegisterPairHigh(),
910              locations->InAt(0).AsArm().AsRegisterPairHigh(),
911              ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairHigh()));
912       break;
913 
914     case Primitive::kPrimBoolean:
915     case Primitive::kPrimByte:
916     case Primitive::kPrimChar:
917     case Primitive::kPrimShort:
918       LOG(FATAL) << "Unexpected add type " << add->GetResultType();
919       break;
920 
921     default:
922       LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
923   }
924 }
925 
VisitSub(HSub * sub)926 void LocationsBuilderARM::VisitSub(HSub* sub) {
927   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(sub);
928   switch (sub->GetResultType()) {
929     case Primitive::kPrimInt:
930     case Primitive::kPrimLong: {
931       locations->SetInAt(0, Location::RequiresRegister());
932       locations->SetInAt(1, Location::RegisterOrConstant(sub->InputAt(1)));
933       locations->SetOut(Location::RequiresRegister());
934       break;
935     }
936 
937     case Primitive::kPrimBoolean:
938     case Primitive::kPrimByte:
939     case Primitive::kPrimChar:
940     case Primitive::kPrimShort:
941       LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
942       break;
943 
944     default:
945       LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
946   }
947   sub->SetLocations(locations);
948 }
949 
VisitSub(HSub * sub)950 void InstructionCodeGeneratorARM::VisitSub(HSub* sub) {
951   LocationSummary* locations = sub->GetLocations();
952   switch (sub->GetResultType()) {
953     case Primitive::kPrimInt: {
954       if (locations->InAt(1).IsRegister()) {
955         __ sub(locations->Out().AsArm().AsCoreRegister(),
956                locations->InAt(0).AsArm().AsCoreRegister(),
957                ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
958       } else {
959         __ AddConstant(locations->Out().AsArm().AsCoreRegister(),
960                        locations->InAt(0).AsArm().AsCoreRegister(),
961                        -locations->InAt(1).GetConstant()->AsIntConstant()->GetValue());
962       }
963       break;
964     }
965 
966     case Primitive::kPrimLong:
967       __ subs(locations->Out().AsArm().AsRegisterPairLow(),
968               locations->InAt(0).AsArm().AsRegisterPairLow(),
969               ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairLow()));
970       __ sbc(locations->Out().AsArm().AsRegisterPairHigh(),
971              locations->InAt(0).AsArm().AsRegisterPairHigh(),
972              ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairHigh()));
973       break;
974 
975     case Primitive::kPrimBoolean:
976     case Primitive::kPrimByte:
977     case Primitive::kPrimChar:
978     case Primitive::kPrimShort:
979       LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
980       break;
981 
982     default:
983       LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
984   }
985 }
986 
VisitNewInstance(HNewInstance * instruction)987 void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) {
988   codegen_->MarkNotLeaf();
989   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
990   InvokeRuntimeCallingConvention calling_convention;
991   locations->AddTemp(ArmCoreLocation(calling_convention.GetRegisterAt(0)));
992   locations->AddTemp(ArmCoreLocation(calling_convention.GetRegisterAt(1)));
993   locations->SetOut(ArmCoreLocation(R0));
994   instruction->SetLocations(locations);
995 }
996 
VisitNewInstance(HNewInstance * instruction)997 void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) {
998   InvokeRuntimeCallingConvention calling_convention;
999   LoadCurrentMethod(calling_convention.GetRegisterAt(1));
1000   __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
1001 
1002   int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAllocObjectWithAccessCheck).Int32Value();
1003   __ ldr(LR, Address(TR, offset));
1004   __ blx(LR);
1005 
1006   codegen_->RecordPcInfo(instruction->GetDexPc());
1007   DCHECK(!codegen_->IsLeafMethod());
1008 }
1009 
VisitParameterValue(HParameterValue * instruction)1010 void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) {
1011   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1012   Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
1013   if (location.IsStackSlot()) {
1014     location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
1015   } else if (location.IsDoubleStackSlot()) {
1016     location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
1017   }
1018   locations->SetOut(location);
1019   instruction->SetLocations(locations);
1020 }
1021 
VisitParameterValue(HParameterValue * instruction)1022 void InstructionCodeGeneratorARM::VisitParameterValue(HParameterValue* instruction) {
1023   // Nothing to do, the parameter is already at its location.
1024 }
1025 
VisitNot(HNot * instruction)1026 void LocationsBuilderARM::VisitNot(HNot* instruction) {
1027   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1028   locations->SetInAt(0, Location::RequiresRegister());
1029   locations->SetOut(Location::RequiresRegister());
1030   instruction->SetLocations(locations);
1031 }
1032 
VisitNot(HNot * instruction)1033 void InstructionCodeGeneratorARM::VisitNot(HNot* instruction) {
1034   LocationSummary* locations = instruction->GetLocations();
1035   __ eor(locations->Out().AsArm().AsCoreRegister(),
1036          locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(1));
1037 }
1038 
VisitCompare(HCompare * compare)1039 void LocationsBuilderARM::VisitCompare(HCompare* compare) {
1040   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(compare);
1041   locations->SetInAt(0, Location::RequiresRegister());
1042   locations->SetInAt(1, Location::RequiresRegister());
1043   locations->SetOut(Location::RequiresRegister());
1044   compare->SetLocations(locations);
1045 }
1046 
VisitCompare(HCompare * compare)1047 void InstructionCodeGeneratorARM::VisitCompare(HCompare* compare) {
1048   Label greater, done;
1049   LocationSummary* locations = compare->GetLocations();
1050   switch (compare->InputAt(0)->GetType()) {
1051     case Primitive::kPrimLong: {
1052       Register output = locations->Out().AsArm().AsCoreRegister();
1053       ArmManagedRegister left = locations->InAt(0).AsArm();
1054       ArmManagedRegister right = locations->InAt(1).AsArm();
1055       Label less, greater, done;
1056       __ cmp(left.AsRegisterPairHigh(),
1057              ShifterOperand(right.AsRegisterPairHigh()));  // Signed compare.
1058       __ b(&less, LT);
1059       __ b(&greater, GT);
1060       // Do LoadImmediate before any `cmp`, as LoadImmediate might affect
1061       // the status flags.
1062       __ LoadImmediate(output, 0);
1063       __ cmp(left.AsRegisterPairLow(),
1064              ShifterOperand(right.AsRegisterPairLow()));  // Unsigned compare.
1065       __ b(&done, EQ);
1066       __ b(&less, CC);
1067 
1068       __ Bind(&greater);
1069       __ LoadImmediate(output, 1);
1070       __ b(&done);
1071 
1072       __ Bind(&less);
1073       __ LoadImmediate(output, -1);
1074 
1075       __ Bind(&done);
1076       break;
1077     }
1078     default:
1079       LOG(FATAL) << "Unimplemented compare type " << compare->InputAt(0)->GetType();
1080   }
1081 }
1082 
VisitPhi(HPhi * instruction)1083 void LocationsBuilderARM::VisitPhi(HPhi* instruction) {
1084   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1085   for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
1086     locations->SetInAt(i, Location::Any());
1087   }
1088   locations->SetOut(Location::Any());
1089   instruction->SetLocations(locations);
1090 }
1091 
VisitPhi(HPhi * instruction)1092 void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction) {
1093   LOG(FATAL) << "Unreachable";
1094 }
1095 
VisitInstanceFieldSet(HInstanceFieldSet * instruction)1096 void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
1097   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1098   locations->SetInAt(0, Location::RequiresRegister());
1099   locations->SetInAt(1, Location::RequiresRegister());
1100   // Temporary registers for the write barrier.
1101   if (instruction->InputAt(1)->GetType() == Primitive::kPrimNot) {
1102     locations->AddTemp(Location::RequiresRegister());
1103     locations->AddTemp(Location::RequiresRegister());
1104   }
1105   instruction->SetLocations(locations);
1106 }
1107 
VisitInstanceFieldSet(HInstanceFieldSet * instruction)1108 void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
1109   LocationSummary* locations = instruction->GetLocations();
1110   Register obj = locations->InAt(0).AsArm().AsCoreRegister();
1111   uint32_t offset = instruction->GetFieldOffset().Uint32Value();
1112   Primitive::Type field_type = instruction->InputAt(1)->GetType();
1113 
1114   switch (field_type) {
1115     case Primitive::kPrimBoolean:
1116     case Primitive::kPrimByte: {
1117       Register value = locations->InAt(1).AsArm().AsCoreRegister();
1118       __ StoreToOffset(kStoreByte, value, obj, offset);
1119       break;
1120     }
1121 
1122     case Primitive::kPrimShort:
1123     case Primitive::kPrimChar: {
1124       Register value = locations->InAt(1).AsArm().AsCoreRegister();
1125       __ StoreToOffset(kStoreHalfword, value, obj, offset);
1126       break;
1127     }
1128 
1129     case Primitive::kPrimInt:
1130     case Primitive::kPrimNot: {
1131       Register value = locations->InAt(1).AsArm().AsCoreRegister();
1132       __ StoreToOffset(kStoreWord, value, obj, offset);
1133       if (field_type == Primitive::kPrimNot) {
1134         Register temp = locations->GetTemp(0).AsArm().AsCoreRegister();
1135         Register card = locations->GetTemp(1).AsArm().AsCoreRegister();
1136         codegen_->MarkGCCard(temp, card, obj, value);
1137       }
1138       break;
1139     }
1140 
1141     case Primitive::kPrimLong: {
1142       ArmManagedRegister value = locations->InAt(1).AsArm();
1143       __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow(), obj, offset);
1144       break;
1145     }
1146 
1147     case Primitive::kPrimFloat:
1148     case Primitive::kPrimDouble:
1149       LOG(FATAL) << "Unimplemented register type " << field_type;
1150 
1151     case Primitive::kPrimVoid:
1152       LOG(FATAL) << "Unreachable type " << field_type;
1153   }
1154 }
1155 
VisitInstanceFieldGet(HInstanceFieldGet * instruction)1156 void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
1157   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1158   locations->SetInAt(0, Location::RequiresRegister());
1159   locations->SetOut(Location::RequiresRegister());
1160   instruction->SetLocations(locations);
1161 }
1162 
VisitInstanceFieldGet(HInstanceFieldGet * instruction)1163 void InstructionCodeGeneratorARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
1164   LocationSummary* locations = instruction->GetLocations();
1165   Register obj = locations->InAt(0).AsArm().AsCoreRegister();
1166   uint32_t offset = instruction->GetFieldOffset().Uint32Value();
1167 
1168   switch (instruction->GetType()) {
1169     case Primitive::kPrimBoolean: {
1170       Register out = locations->Out().AsArm().AsCoreRegister();
1171       __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset);
1172       break;
1173     }
1174 
1175     case Primitive::kPrimByte: {
1176       Register out = locations->Out().AsArm().AsCoreRegister();
1177       __ LoadFromOffset(kLoadSignedByte, out, obj, offset);
1178       break;
1179     }
1180 
1181     case Primitive::kPrimShort: {
1182       Register out = locations->Out().AsArm().AsCoreRegister();
1183       __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset);
1184       break;
1185     }
1186 
1187     case Primitive::kPrimChar: {
1188       Register out = locations->Out().AsArm().AsCoreRegister();
1189       __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset);
1190       break;
1191     }
1192 
1193     case Primitive::kPrimInt:
1194     case Primitive::kPrimNot: {
1195       Register out = locations->Out().AsArm().AsCoreRegister();
1196       __ LoadFromOffset(kLoadWord, out, obj, offset);
1197       break;
1198     }
1199 
1200     case Primitive::kPrimLong: {
1201       // TODO: support volatile.
1202       ArmManagedRegister out = locations->Out().AsArm();
1203       __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow(), obj, offset);
1204       break;
1205     }
1206 
1207     case Primitive::kPrimFloat:
1208     case Primitive::kPrimDouble:
1209       LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1210 
1211     case Primitive::kPrimVoid:
1212       LOG(FATAL) << "Unreachable type " << instruction->GetType();
1213   }
1214 }
1215 
VisitNullCheck(HNullCheck * instruction)1216 void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) {
1217   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1218   locations->SetInAt(0, Location::RequiresRegister());
1219   // TODO: Have a normalization phase that makes this instruction never used.
1220   locations->SetOut(Location::SameAsFirstInput());
1221   instruction->SetLocations(locations);
1222 }
1223 
VisitNullCheck(HNullCheck * instruction)1224 void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) {
1225   SlowPathCode* slow_path =
1226       new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction->GetDexPc());
1227   codegen_->AddSlowPath(slow_path);
1228 
1229   LocationSummary* locations = instruction->GetLocations();
1230   Location obj = locations->InAt(0);
1231   DCHECK(obj.Equals(locations->Out()));
1232 
1233   if (obj.IsRegister()) {
1234     __ cmp(obj.AsArm().AsCoreRegister(), ShifterOperand(0));
1235   }
1236   __ b(slow_path->GetEntryLabel(), EQ);
1237 }
1238 
VisitArrayGet(HArrayGet * instruction)1239 void LocationsBuilderARM::VisitArrayGet(HArrayGet* instruction) {
1240   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1241   locations->SetInAt(0, Location::RequiresRegister());
1242   locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
1243   locations->SetOut(Location::RequiresRegister());
1244   instruction->SetLocations(locations);
1245 }
1246 
VisitArrayGet(HArrayGet * instruction)1247 void InstructionCodeGeneratorARM::VisitArrayGet(HArrayGet* instruction) {
1248   LocationSummary* locations = instruction->GetLocations();
1249   Register obj = locations->InAt(0).AsArm().AsCoreRegister();
1250   Location index = locations->InAt(1);
1251 
1252   switch (instruction->GetType()) {
1253     case Primitive::kPrimBoolean: {
1254       uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
1255       Register out = locations->Out().AsArm().AsCoreRegister();
1256       if (index.IsConstant()) {
1257         size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
1258         __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset);
1259       } else {
1260         __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister()));
1261         __ LoadFromOffset(kLoadUnsignedByte, out, IP, data_offset);
1262       }
1263       break;
1264     }
1265 
1266     case Primitive::kPrimByte: {
1267       uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
1268       Register out = locations->Out().AsArm().AsCoreRegister();
1269       if (index.IsConstant()) {
1270         size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
1271         __ LoadFromOffset(kLoadSignedByte, out, obj, offset);
1272       } else {
1273         __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister()));
1274         __ LoadFromOffset(kLoadSignedByte, out, IP, data_offset);
1275       }
1276       break;
1277     }
1278 
1279     case Primitive::kPrimShort: {
1280       uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
1281       Register out = locations->Out().AsArm().AsCoreRegister();
1282       if (index.IsConstant()) {
1283         size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
1284         __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset);
1285       } else {
1286         __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_2));
1287         __ LoadFromOffset(kLoadSignedHalfword, out, IP, data_offset);
1288       }
1289       break;
1290     }
1291 
1292     case Primitive::kPrimChar: {
1293       uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
1294       Register out = locations->Out().AsArm().AsCoreRegister();
1295       if (index.IsConstant()) {
1296         size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
1297         __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset);
1298       } else {
1299         __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_2));
1300         __ LoadFromOffset(kLoadUnsignedHalfword, out, IP, data_offset);
1301       }
1302       break;
1303     }
1304 
1305     case Primitive::kPrimInt:
1306     case Primitive::kPrimNot: {
1307       DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t));
1308       uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
1309       Register out = locations->Out().AsArm().AsCoreRegister();
1310       if (index.IsConstant()) {
1311         size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
1312         __ LoadFromOffset(kLoadWord, out, obj, offset);
1313       } else {
1314         __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_4));
1315         __ LoadFromOffset(kLoadWord, out, IP, data_offset);
1316       }
1317       break;
1318     }
1319 
1320     case Primitive::kPrimLong: {
1321       uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
1322       ArmManagedRegister out = locations->Out().AsArm();
1323       if (index.IsConstant()) {
1324         size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
1325         __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow(), obj, offset);
1326       } else {
1327         __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_8));
1328         __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow(), IP, data_offset);
1329       }
1330       break;
1331     }
1332 
1333     case Primitive::kPrimFloat:
1334     case Primitive::kPrimDouble:
1335       LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1336 
1337     case Primitive::kPrimVoid:
1338       LOG(FATAL) << "Unreachable type " << instruction->GetType();
1339   }
1340 }
1341 
VisitArraySet(HArraySet * instruction)1342 void LocationsBuilderARM::VisitArraySet(HArraySet* instruction) {
1343   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1344   Primitive::Type value_type = instruction->InputAt(2)->GetType();
1345   if (value_type == Primitive::kPrimNot) {
1346     InvokeRuntimeCallingConvention calling_convention;
1347     locations->SetInAt(0, ArmCoreLocation(calling_convention.GetRegisterAt(0)));
1348     locations->SetInAt(1, ArmCoreLocation(calling_convention.GetRegisterAt(1)));
1349     locations->SetInAt(2, ArmCoreLocation(calling_convention.GetRegisterAt(2)));
1350     codegen_->MarkNotLeaf();
1351   } else {
1352     locations->SetInAt(0, Location::RequiresRegister());
1353     locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
1354     locations->SetInAt(2, Location::RequiresRegister());
1355   }
1356   instruction->SetLocations(locations);
1357 }
1358 
VisitArraySet(HArraySet * instruction)1359 void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) {
1360   LocationSummary* locations = instruction->GetLocations();
1361   Register obj = locations->InAt(0).AsArm().AsCoreRegister();
1362   Location index = locations->InAt(1);
1363   Primitive::Type value_type = instruction->InputAt(2)->GetType();
1364 
1365   switch (value_type) {
1366     case Primitive::kPrimBoolean:
1367     case Primitive::kPrimByte: {
1368       uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
1369       Register value = locations->InAt(2).AsArm().AsCoreRegister();
1370       if (index.IsConstant()) {
1371         size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
1372         __ StoreToOffset(kStoreByte, value, obj, offset);
1373       } else {
1374         __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister()));
1375         __ StoreToOffset(kStoreByte, value, IP, data_offset);
1376       }
1377       break;
1378     }
1379 
1380     case Primitive::kPrimShort:
1381     case Primitive::kPrimChar: {
1382       uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
1383       Register value = locations->InAt(2).AsArm().AsCoreRegister();
1384       if (index.IsConstant()) {
1385         size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
1386         __ StoreToOffset(kStoreHalfword, value, obj, offset);
1387       } else {
1388         __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_2));
1389         __ StoreToOffset(kStoreHalfword, value, IP, data_offset);
1390       }
1391       break;
1392     }
1393 
1394     case Primitive::kPrimInt: {
1395       uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
1396       Register value = locations->InAt(2).AsArm().AsCoreRegister();
1397       if (index.IsConstant()) {
1398         size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
1399         __ StoreToOffset(kStoreWord, value, obj, offset);
1400       } else {
1401         __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_4));
1402         __ StoreToOffset(kStoreWord, value, IP, data_offset);
1403       }
1404       break;
1405     }
1406 
1407     case Primitive::kPrimNot: {
1408       int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAputObject).Int32Value();
1409       __ ldr(LR, Address(TR, offset));
1410       __ blx(LR);
1411       codegen_->RecordPcInfo(instruction->GetDexPc());
1412       DCHECK(!codegen_->IsLeafMethod());
1413       break;
1414     }
1415 
1416     case Primitive::kPrimLong: {
1417       uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
1418       ArmManagedRegister value = locations->InAt(2).AsArm();
1419       if (index.IsConstant()) {
1420         size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
1421         __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow(), obj, offset);
1422       } else {
1423         __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_8));
1424         __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow(), IP, data_offset);
1425       }
1426       break;
1427     }
1428 
1429     case Primitive::kPrimFloat:
1430     case Primitive::kPrimDouble:
1431       LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1432 
1433     case Primitive::kPrimVoid:
1434       LOG(FATAL) << "Unreachable type " << instruction->GetType();
1435   }
1436 }
1437 
VisitArrayLength(HArrayLength * instruction)1438 void LocationsBuilderARM::VisitArrayLength(HArrayLength* instruction) {
1439   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1440   locations->SetInAt(0, Location::RequiresRegister());
1441   locations->SetOut(Location::RequiresRegister());
1442   instruction->SetLocations(locations);
1443 }
1444 
VisitArrayLength(HArrayLength * instruction)1445 void InstructionCodeGeneratorARM::VisitArrayLength(HArrayLength* instruction) {
1446   LocationSummary* locations = instruction->GetLocations();
1447   uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
1448   Register obj = locations->InAt(0).AsArm().AsCoreRegister();
1449   Register out = locations->Out().AsArm().AsCoreRegister();
1450   __ LoadFromOffset(kLoadWord, out, obj, offset);
1451 }
1452 
VisitBoundsCheck(HBoundsCheck * instruction)1453 void LocationsBuilderARM::VisitBoundsCheck(HBoundsCheck* instruction) {
1454   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1455   locations->SetInAt(0, Location::RequiresRegister());
1456   locations->SetInAt(1, Location::RequiresRegister());
1457   // TODO: Have a normalization phase that makes this instruction never used.
1458   locations->SetOut(Location::SameAsFirstInput());
1459   instruction->SetLocations(locations);
1460 }
1461 
VisitBoundsCheck(HBoundsCheck * instruction)1462 void InstructionCodeGeneratorARM::VisitBoundsCheck(HBoundsCheck* instruction) {
1463   LocationSummary* locations = instruction->GetLocations();
1464   SlowPathCode* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathARM(
1465       instruction->GetDexPc(), locations->InAt(0), locations->InAt(1));
1466   codegen_->AddSlowPath(slow_path);
1467 
1468   Register index = locations->InAt(0).AsArm().AsCoreRegister();
1469   Register length = locations->InAt(1).AsArm().AsCoreRegister();
1470 
1471   __ cmp(index, ShifterOperand(length));
1472   __ b(slow_path->GetEntryLabel(), CS);
1473 }
1474 
MarkGCCard(Register temp,Register card,Register object,Register value)1475 void CodeGeneratorARM::MarkGCCard(Register temp, Register card, Register object, Register value) {
1476   Label is_null;
1477   __ CompareAndBranchIfZero(value, &is_null);
1478   __ LoadFromOffset(kLoadWord, card, TR, Thread::CardTableOffset<kArmWordSize>().Int32Value());
1479   __ Lsr(temp, object, gc::accounting::CardTable::kCardShift);
1480   __ strb(card, Address(card, temp));
1481   __ Bind(&is_null);
1482 }
1483 
VisitTemporary(HTemporary * temp)1484 void LocationsBuilderARM::VisitTemporary(HTemporary* temp) {
1485   temp->SetLocations(nullptr);
1486 }
1487 
VisitTemporary(HTemporary * temp)1488 void InstructionCodeGeneratorARM::VisitTemporary(HTemporary* temp) {
1489   // Nothing to do, this is driven by the code generator.
1490 }
1491 
VisitParallelMove(HParallelMove * instruction)1492 void LocationsBuilderARM::VisitParallelMove(HParallelMove* instruction) {
1493   LOG(FATAL) << "Unreachable";
1494 }
1495 
VisitParallelMove(HParallelMove * instruction)1496 void InstructionCodeGeneratorARM::VisitParallelMove(HParallelMove* instruction) {
1497   codegen_->GetMoveResolver()->EmitNativeCode(instruction);
1498 }
1499 
GetAssembler() const1500 ArmAssembler* ParallelMoveResolverARM::GetAssembler() const {
1501   return codegen_->GetAssembler();
1502 }
1503 
EmitMove(size_t index)1504 void ParallelMoveResolverARM::EmitMove(size_t index) {
1505   MoveOperands* move = moves_.Get(index);
1506   Location source = move->GetSource();
1507   Location destination = move->GetDestination();
1508 
1509   if (source.IsRegister()) {
1510     if (destination.IsRegister()) {
1511       __ Mov(destination.AsArm().AsCoreRegister(), source.AsArm().AsCoreRegister());
1512     } else {
1513       DCHECK(destination.IsStackSlot());
1514       __ StoreToOffset(kStoreWord, source.AsArm().AsCoreRegister(),
1515                        SP, destination.GetStackIndex());
1516     }
1517   } else if (source.IsStackSlot()) {
1518     if (destination.IsRegister()) {
1519       __ LoadFromOffset(kLoadWord, destination.AsArm().AsCoreRegister(),
1520                         SP, source.GetStackIndex());
1521     } else {
1522       DCHECK(destination.IsStackSlot());
1523       __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
1524       __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
1525     }
1526   } else {
1527     DCHECK(source.IsConstant());
1528     DCHECK(source.GetConstant()->AsIntConstant() != nullptr);
1529     int32_t value = source.GetConstant()->AsIntConstant()->GetValue();
1530     if (destination.IsRegister()) {
1531       __ LoadImmediate(destination.AsArm().AsCoreRegister(), value);
1532     } else {
1533       DCHECK(destination.IsStackSlot());
1534       __ LoadImmediate(IP, value);
1535       __ str(IP, Address(SP, destination.GetStackIndex()));
1536     }
1537   }
1538 }
1539 
Exchange(Register reg,int mem)1540 void ParallelMoveResolverARM::Exchange(Register reg, int mem) {
1541   __ Mov(IP, reg);
1542   __ LoadFromOffset(kLoadWord, reg, SP, mem);
1543   __ StoreToOffset(kStoreWord, IP, SP, mem);
1544 }
1545 
Exchange(int mem1,int mem2)1546 void ParallelMoveResolverARM::Exchange(int mem1, int mem2) {
1547   ScratchRegisterScope ensure_scratch(this, IP, R0, codegen_->GetNumberOfCoreRegisters());
1548   int stack_offset = ensure_scratch.IsSpilled() ? kArmWordSize : 0;
1549   __ LoadFromOffset(kLoadWord, static_cast<Register>(ensure_scratch.GetRegister()),
1550                     SP, mem1 + stack_offset);
1551   __ LoadFromOffset(kLoadWord, IP, SP, mem2 + stack_offset);
1552   __ StoreToOffset(kStoreWord, static_cast<Register>(ensure_scratch.GetRegister()),
1553                    SP, mem2 + stack_offset);
1554   __ StoreToOffset(kStoreWord, IP, SP, mem1 + stack_offset);
1555 }
1556 
EmitSwap(size_t index)1557 void ParallelMoveResolverARM::EmitSwap(size_t index) {
1558   MoveOperands* move = moves_.Get(index);
1559   Location source = move->GetSource();
1560   Location destination = move->GetDestination();
1561 
1562   if (source.IsRegister() && destination.IsRegister()) {
1563     DCHECK_NE(source.AsArm().AsCoreRegister(), IP);
1564     DCHECK_NE(destination.AsArm().AsCoreRegister(), IP);
1565     __ Mov(IP, source.AsArm().AsCoreRegister());
1566     __ Mov(source.AsArm().AsCoreRegister(), destination.AsArm().AsCoreRegister());
1567     __ Mov(destination.AsArm().AsCoreRegister(), IP);
1568   } else if (source.IsRegister() && destination.IsStackSlot()) {
1569     Exchange(source.AsArm().AsCoreRegister(), destination.GetStackIndex());
1570   } else if (source.IsStackSlot() && destination.IsRegister()) {
1571     Exchange(destination.AsArm().AsCoreRegister(), source.GetStackIndex());
1572   } else if (source.IsStackSlot() && destination.IsStackSlot()) {
1573     Exchange(source.GetStackIndex(), destination.GetStackIndex());
1574   } else {
1575     LOG(FATAL) << "Unimplemented";
1576   }
1577 }
1578 
SpillScratch(int reg)1579 void ParallelMoveResolverARM::SpillScratch(int reg) {
1580   __ Push(static_cast<Register>(reg));
1581 }
1582 
RestoreScratch(int reg)1583 void ParallelMoveResolverARM::RestoreScratch(int reg) {
1584   __ Pop(static_cast<Register>(reg));
1585 }
1586 
1587 }  // namespace arm
1588 }  // namespace art
1589