blob: e70240783a215b02db97bbd93328fc372f71a178 [file] [log] [blame]
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001/*
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"
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000018
Ian Rogersb0fa5dc2014-04-28 16:47:08 -070019#include "entrypoints/quick/quick_entrypoints.h"
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +000020#include "mirror/array.h"
21#include "mirror/art_method.h"
Ian Rogersb0fa5dc2014-04-28 16:47:08 -070022#include "thread.h"
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010023#include "utils/assembler.h"
24#include "utils/arm/assembler_arm.h"
25#include "utils/arm/managed_register_arm.h"
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +000026
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000027namespace art {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +010028
29arm::ArmManagedRegister Location::AsArm() const {
30 return reg().AsArm();
31}
32
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000033namespace arm {
34
Nicolas Geoffraye5038322014-07-04 09:41:32 +010035#define __ reinterpret_cast<ArmAssembler*>(codegen->GetAssembler())->
36
37class NullCheckSlowPathARM : public SlowPathCode {
38 public:
39 explicit NullCheckSlowPathARM(uint32_t dex_pc) : dex_pc_(dex_pc) {}
40
41 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
42 __ Bind(GetEntryLabel());
43 int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pThrowNullPointer).Int32Value();
44 __ ldr(LR, Address(TR, offset));
45 __ blx(LR);
46 codegen->RecordPcInfo(dex_pc_);
47 }
48
49 private:
50 const uint32_t dex_pc_;
51 DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathARM);
52};
53
54#undef __
55#define __ reinterpret_cast<ArmAssembler*>(GetAssembler())->
Dave Allison20dfc792014-06-16 20:44:29 -070056
57inline Condition ARMCondition(IfCondition cond) {
58 switch (cond) {
59 case kCondEQ: return EQ;
60 case kCondNE: return NE;
61 case kCondLT: return LT;
62 case kCondLE: return LE;
63 case kCondGT: return GT;
64 case kCondGE: return GE;
65 default:
66 LOG(FATAL) << "Unknown if condition";
67 }
68 return EQ; // Unreachable.
69}
70
71inline Condition ARMOppositeCondition(IfCondition cond) {
72 switch (cond) {
73 case kCondEQ: return NE;
74 case kCondNE: return EQ;
75 case kCondLT: return GE;
76 case kCondLE: return GT;
77 case kCondGT: return LE;
78 case kCondGE: return LT;
79 default:
80 LOG(FATAL) << "Unknown if condition";
81 }
82 return EQ; // Unreachable.
83}
84
Nicolas Geoffraye5038322014-07-04 09:41:32 +010085static constexpr int kNumberOfPushedRegistersAtEntry = 1 + 2; // LR, R6, R7
Nicolas Geoffray4a34a422014-04-03 10:38:37 +010086static constexpr int kCurrentMethodStackOffset = 0;
87
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010088void CodeGeneratorARM::DumpCoreRegister(std::ostream& stream, int reg) const {
89 stream << ArmManagedRegister::FromCoreRegister(Register(reg));
90}
91
92void CodeGeneratorARM::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
93 stream << ArmManagedRegister::FromDRegister(DRegister(reg));
94}
95
Nicolas Geoffraya7aca372014-04-28 17:47:12 +010096CodeGeneratorARM::CodeGeneratorARM(HGraph* graph)
97 : CodeGenerator(graph, kNumberOfRegIds),
98 location_builder_(graph, this),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +010099 instruction_visitor_(graph, this),
100 move_resolver_(graph->GetArena(), this) {}
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100101
102static bool* GetBlockedRegisterPairs(bool* blocked_registers) {
103 return blocked_registers + kNumberOfAllocIds;
104}
105
106ManagedRegister CodeGeneratorARM::AllocateFreeRegister(Primitive::Type type,
107 bool* blocked_registers) const {
108 switch (type) {
109 case Primitive::kPrimLong: {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100110 bool* blocked_register_pairs = GetBlockedRegisterPairs(blocked_registers);
111 size_t reg = AllocateFreeRegisterInternal(blocked_register_pairs, kNumberOfRegisterPairs);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100112 ArmManagedRegister pair =
113 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(reg));
114 blocked_registers[pair.AsRegisterPairLow()] = true;
115 blocked_registers[pair.AsRegisterPairHigh()] = true;
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100116 // Block all other register pairs that share a register with `pair`.
117 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
118 ArmManagedRegister current =
119 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
120 if (current.AsRegisterPairLow() == pair.AsRegisterPairLow()
121 || current.AsRegisterPairLow() == pair.AsRegisterPairHigh()
122 || current.AsRegisterPairHigh() == pair.AsRegisterPairLow()
123 || current.AsRegisterPairHigh() == pair.AsRegisterPairHigh()) {
124 blocked_register_pairs[i] = true;
125 }
126 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100127 return pair;
128 }
129
130 case Primitive::kPrimByte:
131 case Primitive::kPrimBoolean:
132 case Primitive::kPrimChar:
133 case Primitive::kPrimShort:
134 case Primitive::kPrimInt:
135 case Primitive::kPrimNot: {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100136 int reg = AllocateFreeRegisterInternal(blocked_registers, kNumberOfCoreRegisters);
137 // Block all register pairs that contain `reg`.
138 bool* blocked_register_pairs = GetBlockedRegisterPairs(blocked_registers);
139 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
140 ArmManagedRegister current =
141 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
142 if (current.AsRegisterPairLow() == reg || current.AsRegisterPairHigh() == reg) {
143 blocked_register_pairs[i] = true;
144 }
145 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100146 return ArmManagedRegister::FromCoreRegister(static_cast<Register>(reg));
147 }
148
149 case Primitive::kPrimFloat:
150 case Primitive::kPrimDouble:
151 LOG(FATAL) << "Unimplemented register type " << type;
152
153 case Primitive::kPrimVoid:
154 LOG(FATAL) << "Unreachable type " << type;
155 }
156
157 return ManagedRegister::NoRegister();
158}
159
160void CodeGeneratorARM::SetupBlockedRegisters(bool* blocked_registers) const {
161 bool* blocked_register_pairs = GetBlockedRegisterPairs(blocked_registers);
162
163 // Don't allocate the dalvik style register pair passing.
164 blocked_register_pairs[R1_R2] = true;
165
166 // Stack register, LR and PC are always reserved.
167 blocked_registers[SP] = true;
168 blocked_registers[LR] = true;
169 blocked_registers[PC] = true;
170
171 // Reserve R4 for suspend check.
172 blocked_registers[R4] = true;
173 blocked_register_pairs[R4_R5] = true;
174
175 // Reserve thread register.
176 blocked_registers[TR] = true;
177
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100178 // Reserve temp register.
179 blocked_registers[IP] = true;
180
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100181 // TODO: We currently don't use Quick's callee saved registers.
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100182 // We always save and restore R6 and R7 to make sure we can use three
183 // register pairs for long operations.
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100184 blocked_registers[R5] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100185 blocked_registers[R8] = true;
186 blocked_registers[R10] = true;
187 blocked_registers[R11] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100188}
189
190size_t CodeGeneratorARM::GetNumberOfRegisters() const {
191 return kNumberOfRegIds;
192}
193
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100194static Location ArmCoreLocation(Register reg) {
195 return Location::RegisterLocation(ArmManagedRegister::FromCoreRegister(reg));
196}
197
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100198InstructionCodeGeneratorARM::InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen)
199 : HGraphVisitor(graph),
200 assembler_(codegen->GetAssembler()),
201 codegen_(codegen) {}
202
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100203void CodeGeneratorARM::ComputeFrameSize(size_t number_of_spill_slots) {
204 SetFrameSize(RoundUp(
205 number_of_spill_slots * kVRegSize
206 + kVRegSize // Art method
207 + kNumberOfPushedRegistersAtEntry * kArmWordSize,
208 kStackAlignment));
209}
210
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000211void CodeGeneratorARM::GenerateFrameEntry() {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100212 core_spill_mask_ |= (1 << LR | 1 << R6 | 1 << R7);
213 __ PushList(1 << LR | 1 << R6 | 1 << R7);
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000214
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100215 // The return PC has already been pushed on the stack.
Nicolas Geoffray707c8092014-04-04 10:50:14 +0100216 __ AddConstant(SP, -(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kArmWordSize));
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000217 __ str(R0, Address(SP, 0));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000218}
219
220void CodeGeneratorARM::GenerateFrameExit() {
Nicolas Geoffray707c8092014-04-04 10:50:14 +0100221 __ AddConstant(SP, GetFrameSize() - kNumberOfPushedRegistersAtEntry * kArmWordSize);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100222 __ PopList(1 << PC | 1 << R6 | 1 << R7);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000223}
224
225void CodeGeneratorARM::Bind(Label* label) {
226 __ Bind(label);
227}
228
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100229Location CodeGeneratorARM::GetTemporaryLocation(HTemporary* temp) const {
230 uint16_t number_of_vregs = GetGraph()->GetNumberOfVRegs();
231 // Use the temporary region (right below the dex registers).
232 int32_t slot = GetFrameSize() - (kNumberOfPushedRegistersAtEntry * kArmWordSize)
233 - kVRegSize // filler
234 - (number_of_vregs * kVRegSize)
235 - ((1 + temp->GetIndex()) * kVRegSize);
236 return Location::StackSlot(slot);
237}
238
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100239int32_t CodeGeneratorARM::GetStackSlot(HLocal* local) const {
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100240 uint16_t reg_number = local->GetRegNumber();
241 uint16_t number_of_vregs = GetGraph()->GetNumberOfVRegs();
242 uint16_t number_of_in_vregs = GetGraph()->GetNumberOfInVRegs();
243 if (reg_number >= number_of_vregs - number_of_in_vregs) {
244 // Local is a parameter of the method. It is stored in the caller's frame.
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100245 return GetFrameSize() + kVRegSize // ART method
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100246 + (reg_number - number_of_vregs + number_of_in_vregs) * kVRegSize;
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100247 } else {
248 // Local is a temporary in this method. It is stored in this method's frame.
249 return GetFrameSize() - (kNumberOfPushedRegistersAtEntry * kArmWordSize)
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100250 - kVRegSize // filler.
251 - (number_of_vregs * kVRegSize)
252 + (reg_number * kVRegSize);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100253 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000254}
255
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100256Location CodeGeneratorARM::GetStackLocation(HLoadLocal* load) const {
257 switch (load->GetType()) {
258 case Primitive::kPrimLong:
259 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
260 break;
261
262 case Primitive::kPrimInt:
263 case Primitive::kPrimNot:
264 return Location::StackSlot(GetStackSlot(load->GetLocal()));
265
266 case Primitive::kPrimFloat:
267 case Primitive::kPrimDouble:
268 LOG(FATAL) << "Unimplemented type " << load->GetType();
269
270 case Primitive::kPrimBoolean:
271 case Primitive::kPrimByte:
272 case Primitive::kPrimChar:
273 case Primitive::kPrimShort:
274 case Primitive::kPrimVoid:
275 LOG(FATAL) << "Unexpected type " << load->GetType();
276 }
277
278 LOG(FATAL) << "Unreachable";
279 return Location();
280}
281
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100282Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) {
283 switch (type) {
284 case Primitive::kPrimBoolean:
285 case Primitive::kPrimByte:
286 case Primitive::kPrimChar:
287 case Primitive::kPrimShort:
288 case Primitive::kPrimInt:
289 case Primitive::kPrimNot: {
290 uint32_t index = gp_index_++;
291 if (index < calling_convention.GetNumberOfRegisters()) {
292 return ArmCoreLocation(calling_convention.GetRegisterAt(index));
293 } else {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100294 return Location::StackSlot(calling_convention.GetStackOffsetOf(index));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100295 }
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100296 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100297
298 case Primitive::kPrimLong: {
299 uint32_t index = gp_index_;
300 gp_index_ += 2;
301 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
302 return Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(
303 calling_convention.GetRegisterPairAt(index)));
304 } else if (index + 1 == calling_convention.GetNumberOfRegisters()) {
305 return Location::QuickParameter(index);
306 } else {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100307 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100308 }
309 }
310
311 case Primitive::kPrimDouble:
312 case Primitive::kPrimFloat:
313 LOG(FATAL) << "Unimplemented parameter type " << type;
314 break;
315
316 case Primitive::kPrimVoid:
317 LOG(FATAL) << "Unexpected parameter type " << type;
318 break;
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100319 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100320 return Location();
321}
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100322
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100323void CodeGeneratorARM::Move32(Location destination, Location source) {
324 if (source.Equals(destination)) {
325 return;
326 }
327 if (destination.IsRegister()) {
328 if (source.IsRegister()) {
329 __ Mov(destination.AsArm().AsCoreRegister(), source.AsArm().AsCoreRegister());
330 } else {
331 __ ldr(destination.AsArm().AsCoreRegister(), Address(SP, source.GetStackIndex()));
332 }
333 } else {
334 DCHECK(destination.IsStackSlot());
335 if (source.IsRegister()) {
336 __ str(source.AsArm().AsCoreRegister(), Address(SP, destination.GetStackIndex()));
337 } else {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100338 __ ldr(IP, Address(SP, source.GetStackIndex()));
339 __ str(IP, Address(SP, destination.GetStackIndex()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100340 }
341 }
342}
343
344void CodeGeneratorARM::Move64(Location destination, Location source) {
345 if (source.Equals(destination)) {
346 return;
347 }
348 if (destination.IsRegister()) {
349 if (source.IsRegister()) {
350 __ Mov(destination.AsArm().AsRegisterPairLow(), source.AsArm().AsRegisterPairLow());
351 __ Mov(destination.AsArm().AsRegisterPairHigh(), source.AsArm().AsRegisterPairHigh());
352 } else if (source.IsQuickParameter()) {
353 uint32_t argument_index = source.GetQuickParameterIndex();
354 InvokeDexCallingConvention calling_convention;
355 __ Mov(destination.AsArm().AsRegisterPairLow(),
356 calling_convention.GetRegisterAt(argument_index));
357 __ ldr(destination.AsArm().AsRegisterPairHigh(),
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100358 Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1) + GetFrameSize()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100359 } else {
360 DCHECK(source.IsDoubleStackSlot());
361 if (destination.AsArm().AsRegisterPair() == R1_R2) {
362 __ ldr(R1, Address(SP, source.GetStackIndex()));
363 __ ldr(R2, Address(SP, source.GetHighStackIndex(kArmWordSize)));
364 } else {
365 __ LoadFromOffset(kLoadWordPair, destination.AsArm().AsRegisterPairLow(),
366 SP, source.GetStackIndex());
367 }
368 }
369 } else if (destination.IsQuickParameter()) {
370 InvokeDexCallingConvention calling_convention;
371 uint32_t argument_index = destination.GetQuickParameterIndex();
372 if (source.IsRegister()) {
373 __ Mov(calling_convention.GetRegisterAt(argument_index), source.AsArm().AsRegisterPairLow());
374 __ str(source.AsArm().AsRegisterPairHigh(),
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100375 Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100376 } else {
377 DCHECK(source.IsDoubleStackSlot());
378 __ ldr(calling_convention.GetRegisterAt(argument_index), Address(SP, source.GetStackIndex()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100379 __ ldr(R0, Address(SP, source.GetHighStackIndex(kArmWordSize)));
380 __ str(R0, Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100381 }
382 } else {
383 DCHECK(destination.IsDoubleStackSlot());
384 if (source.IsRegister()) {
385 if (source.AsArm().AsRegisterPair() == R1_R2) {
386 __ str(R1, Address(SP, destination.GetStackIndex()));
387 __ str(R2, Address(SP, destination.GetHighStackIndex(kArmWordSize)));
388 } else {
389 __ StoreToOffset(kStoreWordPair, source.AsArm().AsRegisterPairLow(),
390 SP, destination.GetStackIndex());
391 }
392 } else if (source.IsQuickParameter()) {
393 InvokeDexCallingConvention calling_convention;
394 uint32_t argument_index = source.GetQuickParameterIndex();
395 __ str(calling_convention.GetRegisterAt(argument_index),
396 Address(SP, destination.GetStackIndex()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100397 __ ldr(R0,
398 Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1) + GetFrameSize()));
399 __ str(R0, Address(SP, destination.GetHighStackIndex(kArmWordSize)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100400 } else {
401 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100402 __ ldr(IP, Address(SP, source.GetStackIndex()));
403 __ str(IP, Address(SP, destination.GetStackIndex()));
404 __ ldr(IP, Address(SP, source.GetHighStackIndex(kArmWordSize)));
405 __ str(IP, Address(SP, destination.GetHighStackIndex(kArmWordSize)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100406 }
407 }
408}
409
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100410void CodeGeneratorARM::Move(HInstruction* instruction, Location location, HInstruction* move_for) {
411 if (instruction->AsIntConstant() != nullptr) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100412 int32_t value = instruction->AsIntConstant()->GetValue();
413 if (location.IsRegister()) {
414 __ LoadImmediate(location.AsArm().AsCoreRegister(), value);
415 } else {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100416 __ LoadImmediate(IP, value);
417 __ str(IP, Address(SP, location.GetStackIndex()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100418 }
419 } else if (instruction->AsLongConstant() != nullptr) {
420 int64_t value = instruction->AsLongConstant()->GetValue();
421 if (location.IsRegister()) {
422 __ LoadImmediate(location.AsArm().AsRegisterPairLow(), Low32Bits(value));
423 __ LoadImmediate(location.AsArm().AsRegisterPairHigh(), High32Bits(value));
424 } else {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100425 __ LoadImmediate(IP, Low32Bits(value));
426 __ str(IP, Address(SP, location.GetStackIndex()));
427 __ LoadImmediate(IP, High32Bits(value));
428 __ str(IP, Address(SP, location.GetHighStackIndex(kArmWordSize)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100429 }
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100430 } else if (instruction->AsLoadLocal() != nullptr) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100431 uint32_t stack_slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
432 switch (instruction->GetType()) {
433 case Primitive::kPrimBoolean:
434 case Primitive::kPrimByte:
435 case Primitive::kPrimChar:
436 case Primitive::kPrimShort:
437 case Primitive::kPrimInt:
438 case Primitive::kPrimNot:
439 Move32(location, Location::StackSlot(stack_slot));
440 break;
441
442 case Primitive::kPrimLong:
443 Move64(location, Location::DoubleStackSlot(stack_slot));
444 break;
445
446 default:
447 LOG(FATAL) << "Unimplemented type " << instruction->GetType();
448 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000449 } else {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100450 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100451 switch (instruction->GetType()) {
452 case Primitive::kPrimBoolean:
453 case Primitive::kPrimByte:
454 case Primitive::kPrimChar:
455 case Primitive::kPrimShort:
456 case Primitive::kPrimNot:
457 case Primitive::kPrimInt:
458 Move32(location, instruction->GetLocations()->Out());
459 break;
460
461 case Primitive::kPrimLong:
462 Move64(location, instruction->GetLocations()->Out());
463 break;
464
465 default:
466 LOG(FATAL) << "Unimplemented type " << instruction->GetType();
467 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000468 }
469}
470
471void LocationsBuilderARM::VisitGoto(HGoto* got) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000472 got->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000473}
474
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000475void InstructionCodeGeneratorARM::VisitGoto(HGoto* got) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000476 HBasicBlock* successor = got->GetSuccessor();
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000477 if (GetGraph()->GetExitBlock() == successor) {
478 codegen_->GenerateFrameExit();
479 } else if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
480 __ b(codegen_->GetLabelOf(successor));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000481 }
482}
483
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000484void LocationsBuilderARM::VisitExit(HExit* exit) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000485 exit->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000486}
487
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000488void InstructionCodeGeneratorARM::VisitExit(HExit* exit) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000489 if (kIsDebugBuild) {
490 __ Comment("Unreachable");
491 __ bkpt(0);
492 }
493}
494
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000495void LocationsBuilderARM::VisitIf(HIf* if_instr) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000496 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100497 HInstruction* cond = if_instr->InputAt(0);
498 DCHECK(cond->IsCondition());
499 HCondition* condition = cond->AsCondition();
500 if (condition->NeedsMaterialization()) {
501 locations->SetInAt(0, Location::Any());
502 }
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000503 if_instr->SetLocations(locations);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000504}
505
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000506void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) {
Dave Allison20dfc792014-06-16 20:44:29 -0700507 HInstruction* cond = if_instr->InputAt(0);
508 DCHECK(cond->IsCondition());
509 HCondition* condition = cond->AsCondition();
510 if (condition->NeedsMaterialization()) {
511 // Condition has been materialized, compare the output to 0
512 if (!if_instr->GetLocations()->InAt(0).IsRegister()) {
513 LOG(FATAL) << "Materialized condition is not in an ARM register";
514 }
515 __ cmp(if_instr->GetLocations()->InAt(0).AsArm().AsCoreRegister(),
516 ShifterOperand(0));
517 __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()), EQ);
518 } else {
519 // Condition has not been materialized, use its inputs as the comparison and its
520 // condition as the branch condition.
521 __ cmp(condition->GetLocations()->InAt(0).AsArm().AsCoreRegister(),
522 ShifterOperand(condition->GetLocations()->InAt(1).AsArm().AsCoreRegister()));
523 __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()),
524 ARMCondition(condition->GetCondition()));
525 }
526 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfFalseSuccessor())) {
527 __ b(codegen_->GetLabelOf(if_instr->IfFalseSuccessor()));
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000528 }
529}
530
Dave Allison20dfc792014-06-16 20:44:29 -0700531
532void LocationsBuilderARM::VisitCondition(HCondition* comp) {
533 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(comp);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100534 locations->SetInAt(0, Location::RequiresRegister());
535 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100536 if (comp->NeedsMaterialization()) {
537 locations->SetOut(Location::RequiresRegister());
538 }
Dave Allison20dfc792014-06-16 20:44:29 -0700539 comp->SetLocations(locations);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000540}
541
Dave Allison20dfc792014-06-16 20:44:29 -0700542void InstructionCodeGeneratorARM::VisitCondition(HCondition* comp) {
543 if (comp->NeedsMaterialization()) {
544 LocationSummary* locations = comp->GetLocations();
545 __ cmp(locations->InAt(0).AsArm().AsCoreRegister(),
546 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
547 __ it(ARMCondition(comp->GetCondition()), kItElse);
548 __ mov(locations->Out().AsArm().AsCoreRegister(), ShifterOperand(1),
549 ARMCondition(comp->GetCondition()));
550 __ mov(locations->Out().AsArm().AsCoreRegister(), ShifterOperand(0),
551 ARMOppositeCondition(comp->GetCondition()));
552 }
553}
554
555void LocationsBuilderARM::VisitEqual(HEqual* comp) {
556 VisitCondition(comp);
557}
558
559void InstructionCodeGeneratorARM::VisitEqual(HEqual* comp) {
560 VisitCondition(comp);
561}
562
563void LocationsBuilderARM::VisitNotEqual(HNotEqual* comp) {
564 VisitCondition(comp);
565}
566
567void InstructionCodeGeneratorARM::VisitNotEqual(HNotEqual* comp) {
568 VisitCondition(comp);
569}
570
571void LocationsBuilderARM::VisitLessThan(HLessThan* comp) {
572 VisitCondition(comp);
573}
574
575void InstructionCodeGeneratorARM::VisitLessThan(HLessThan* comp) {
576 VisitCondition(comp);
577}
578
579void LocationsBuilderARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
580 VisitCondition(comp);
581}
582
583void InstructionCodeGeneratorARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
584 VisitCondition(comp);
585}
586
587void LocationsBuilderARM::VisitGreaterThan(HGreaterThan* comp) {
588 VisitCondition(comp);
589}
590
591void InstructionCodeGeneratorARM::VisitGreaterThan(HGreaterThan* comp) {
592 VisitCondition(comp);
593}
594
595void LocationsBuilderARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
596 VisitCondition(comp);
597}
598
599void InstructionCodeGeneratorARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
600 VisitCondition(comp);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000601}
602
603void LocationsBuilderARM::VisitLocal(HLocal* local) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000604 local->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000605}
606
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000607void InstructionCodeGeneratorARM::VisitLocal(HLocal* local) {
608 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000609}
610
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000611void LocationsBuilderARM::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100612 load->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000613}
614
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000615void InstructionCodeGeneratorARM::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100616 // Nothing to do, this is driven by the code generator.
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000617}
618
619void LocationsBuilderARM::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000620 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(store);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100621 switch (store->InputAt(1)->GetType()) {
622 case Primitive::kPrimBoolean:
623 case Primitive::kPrimByte:
624 case Primitive::kPrimChar:
625 case Primitive::kPrimShort:
626 case Primitive::kPrimInt:
627 case Primitive::kPrimNot:
628 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
629 break;
630
631 case Primitive::kPrimLong:
632 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
633 break;
634
635 default:
636 LOG(FATAL) << "Unimplemented local type " << store->InputAt(1)->GetType();
637 }
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000638 store->SetLocations(locations);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000639}
640
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000641void InstructionCodeGeneratorARM::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000642}
643
644void LocationsBuilderARM::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100645 // TODO: Support constant locations.
646 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
647 locations->SetOut(Location::RequiresRegister());
648 constant->SetLocations(locations);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000649}
650
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000651void InstructionCodeGeneratorARM::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100652 codegen_->Move(constant, constant->GetLocations()->Out(), nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000653}
654
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100655void LocationsBuilderARM::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100656 // TODO: Support constant locations.
657 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
658 locations->SetOut(Location::RequiresRegister());
659 constant->SetLocations(locations);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100660}
661
662void InstructionCodeGeneratorARM::VisitLongConstant(HLongConstant* constant) {
663 // Will be generated at use site.
664}
665
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000666void LocationsBuilderARM::VisitReturnVoid(HReturnVoid* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000667 ret->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000668}
669
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000670void InstructionCodeGeneratorARM::VisitReturnVoid(HReturnVoid* ret) {
671 codegen_->GenerateFrameExit();
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000672}
673
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000674void LocationsBuilderARM::VisitReturn(HReturn* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000675 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(ret);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100676 switch (ret->InputAt(0)->GetType()) {
677 case Primitive::kPrimBoolean:
678 case Primitive::kPrimByte:
679 case Primitive::kPrimChar:
680 case Primitive::kPrimShort:
681 case Primitive::kPrimInt:
682 case Primitive::kPrimNot:
683 locations->SetInAt(0, ArmCoreLocation(R0));
684 break;
685
686 case Primitive::kPrimLong:
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100687 locations->SetInAt(
688 0, Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(R0_R1)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100689 break;
690
691 default:
692 LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
693 }
694
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000695 ret->SetLocations(locations);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000696}
697
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000698void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100699 if (kIsDebugBuild) {
700 switch (ret->InputAt(0)->GetType()) {
701 case Primitive::kPrimBoolean:
702 case Primitive::kPrimByte:
703 case Primitive::kPrimChar:
704 case Primitive::kPrimShort:
705 case Primitive::kPrimInt:
706 case Primitive::kPrimNot:
707 DCHECK_EQ(ret->GetLocations()->InAt(0).AsArm().AsCoreRegister(), R0);
708 break;
709
710 case Primitive::kPrimLong:
711 DCHECK_EQ(ret->GetLocations()->InAt(0).AsArm().AsRegisterPair(), R0_R1);
712 break;
713
714 default:
715 LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
716 }
717 }
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000718 codegen_->GenerateFrameExit();
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000719}
720
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000721void LocationsBuilderARM::VisitInvokeStatic(HInvokeStatic* invoke) {
722 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(invoke);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100723 locations->AddTemp(ArmCoreLocation(R0));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100724
725 InvokeDexCallingConventionVisitor calling_convention_visitor;
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100726 for (size_t i = 0; i < invoke->InputCount(); i++) {
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100727 HInstruction* input = invoke->InputAt(i);
728 locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
729 }
730
731 switch (invoke->GetType()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100732 case Primitive::kPrimBoolean:
733 case Primitive::kPrimByte:
734 case Primitive::kPrimChar:
735 case Primitive::kPrimShort:
736 case Primitive::kPrimInt:
737 case Primitive::kPrimNot:
738 locations->SetOut(ArmCoreLocation(R0));
739 break;
740
741 case Primitive::kPrimLong:
742 locations->SetOut(Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(R0_R1)));
743 break;
744
745 case Primitive::kPrimVoid:
746 break;
747
748 case Primitive::kPrimDouble:
749 case Primitive::kPrimFloat:
750 LOG(FATAL) << "Unimplemented return type " << invoke->GetType();
751 break;
752 }
753
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000754 invoke->SetLocations(locations);
755}
756
757void InstructionCodeGeneratorARM::LoadCurrentMethod(Register reg) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100758 __ ldr(reg, Address(SP, kCurrentMethodStackOffset));
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000759}
760
761void InstructionCodeGeneratorARM::VisitInvokeStatic(HInvokeStatic* invoke) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100762 Register temp = invoke->GetLocations()->GetTemp(0).AsArm().AsCoreRegister();
Nicolas Geoffrayf61b5372014-06-25 14:35:34 +0100763 uint32_t heap_reference_size = sizeof(mirror::HeapReference<mirror::Object>);
764 size_t index_in_cache = mirror::Array::DataOffset(heap_reference_size).Int32Value() +
Nicolas Geoffray707c8092014-04-04 10:50:14 +0100765 invoke->GetIndexInDexCache() * kArmWordSize;
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000766
767 // TODO: Implement all kinds of calls:
768 // 1) boot -> boot
769 // 2) app -> boot
770 // 3) app -> app
771 //
772 // Currently we implement the app -> app logic, which looks up in the resolve cache.
773
774 // temp = method;
775 LoadCurrentMethod(temp);
776 // temp = temp->dex_cache_resolved_methods_;
777 __ ldr(temp, Address(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value()));
778 // temp = temp[index_in_cache]
779 __ ldr(temp, Address(temp, index_in_cache));
780 // LR = temp[offset_of_quick_compiled_code]
781 __ ldr(LR, Address(temp,
782 mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value()));
783 // LR()
784 __ blx(LR);
785
786 codegen_->RecordPcInfo(invoke->GetDexPc());
787}
788
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000789void LocationsBuilderARM::VisitAdd(HAdd* add) {
790 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(add);
791 switch (add->GetResultType()) {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100792 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100793 case Primitive::kPrimLong: {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100794 locations->SetInAt(0, Location::RequiresRegister());
795 locations->SetInAt(1, Location::RequiresRegister());
796 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100797 break;
798 }
799
800 case Primitive::kPrimBoolean:
801 case Primitive::kPrimByte:
802 case Primitive::kPrimChar:
803 case Primitive::kPrimShort:
804 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
805 break;
806
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000807 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100808 LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000809 }
810 add->SetLocations(locations);
811}
812
813void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) {
814 LocationSummary* locations = add->GetLocations();
815 switch (add->GetResultType()) {
816 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100817 __ add(locations->Out().AsArm().AsCoreRegister(),
818 locations->InAt(0).AsArm().AsCoreRegister(),
819 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000820 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100821
822 case Primitive::kPrimLong:
823 __ adds(locations->Out().AsArm().AsRegisterPairLow(),
824 locations->InAt(0).AsArm().AsRegisterPairLow(),
825 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairLow()));
826 __ adc(locations->Out().AsArm().AsRegisterPairHigh(),
827 locations->InAt(0).AsArm().AsRegisterPairHigh(),
828 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairHigh()));
829 break;
830
831 case Primitive::kPrimBoolean:
832 case Primitive::kPrimByte:
833 case Primitive::kPrimChar:
834 case Primitive::kPrimShort:
835 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
836 break;
837
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000838 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100839 LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000840 }
841}
842
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100843void LocationsBuilderARM::VisitSub(HSub* sub) {
844 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(sub);
845 switch (sub->GetResultType()) {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100846 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100847 case Primitive::kPrimLong: {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100848 locations->SetInAt(0, Location::RequiresRegister());
849 locations->SetInAt(1, Location::RequiresRegister());
850 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100851 break;
852 }
853
854 case Primitive::kPrimBoolean:
855 case Primitive::kPrimByte:
856 case Primitive::kPrimChar:
857 case Primitive::kPrimShort:
858 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
859 break;
860
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100861 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100862 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100863 }
864 sub->SetLocations(locations);
865}
866
867void InstructionCodeGeneratorARM::VisitSub(HSub* sub) {
868 LocationSummary* locations = sub->GetLocations();
869 switch (sub->GetResultType()) {
870 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100871 __ sub(locations->Out().AsArm().AsCoreRegister(),
872 locations->InAt(0).AsArm().AsCoreRegister(),
873 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100874 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100875
876 case Primitive::kPrimLong:
877 __ subs(locations->Out().AsArm().AsRegisterPairLow(),
878 locations->InAt(0).AsArm().AsRegisterPairLow(),
879 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairLow()));
880 __ sbc(locations->Out().AsArm().AsRegisterPairHigh(),
881 locations->InAt(0).AsArm().AsRegisterPairHigh(),
882 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairHigh()));
883 break;
884
885 case Primitive::kPrimBoolean:
886 case Primitive::kPrimByte:
887 case Primitive::kPrimChar:
888 case Primitive::kPrimShort:
889 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
890 break;
891
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100892 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100893 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100894 }
895}
896
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +0100897static constexpr Register kRuntimeParameterCoreRegisters[] = { R0, R1 };
898static constexpr size_t kRuntimeParameterCoreRegistersLength =
899 arraysize(kRuntimeParameterCoreRegisters);
900
901class InvokeRuntimeCallingConvention : public CallingConvention<Register> {
902 public:
903 InvokeRuntimeCallingConvention()
904 : CallingConvention(kRuntimeParameterCoreRegisters,
905 kRuntimeParameterCoreRegistersLength) {}
906
907 private:
908 DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention);
909};
910
911void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) {
912 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100913 InvokeRuntimeCallingConvention calling_convention;
914 locations->AddTemp(ArmCoreLocation(calling_convention.GetRegisterAt(0)));
915 locations->AddTemp(ArmCoreLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100916 locations->SetOut(ArmCoreLocation(R0));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +0100917 instruction->SetLocations(locations);
918}
919
920void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) {
921 InvokeRuntimeCallingConvention calling_convention;
922 LoadCurrentMethod(calling_convention.GetRegisterAt(1));
923 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
924
Nicolas Geoffray707c8092014-04-04 10:50:14 +0100925 int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAllocObjectWithAccessCheck).Int32Value();
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +0100926 __ ldr(LR, Address(TR, offset));
927 __ blx(LR);
928
929 codegen_->RecordPcInfo(instruction->GetDexPc());
930}
931
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100932void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) {
933 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100934 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
935 if (location.IsStackSlot()) {
936 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
937 } else if (location.IsDoubleStackSlot()) {
938 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100939 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100940 locations->SetOut(location);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100941 instruction->SetLocations(locations);
942}
943
944void InstructionCodeGeneratorARM::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100945 // Nothing to do, the parameter is already at its location.
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100946}
947
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +0100948void LocationsBuilderARM::VisitNot(HNot* instruction) {
949 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100950 locations->SetInAt(0, Location::RequiresRegister());
951 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +0100952 instruction->SetLocations(locations);
953}
954
955void InstructionCodeGeneratorARM::VisitNot(HNot* instruction) {
956 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100957 __ eor(locations->Out().AsArm().AsCoreRegister(),
958 locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(1));
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +0100959}
960
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100961void LocationsBuilderARM::VisitCompare(HCompare* compare) {
962 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(compare);
963 locations->SetInAt(0, Location::RequiresRegister());
964 locations->SetInAt(1, Location::RequiresRegister());
965 locations->SetOut(Location::RequiresRegister());
966 compare->SetLocations(locations);
967}
968
969void InstructionCodeGeneratorARM::VisitCompare(HCompare* compare) {
970 Label greater, done;
971 LocationSummary* locations = compare->GetLocations();
972 switch (compare->InputAt(0)->GetType()) {
973 case Primitive::kPrimLong: {
974 Register output = locations->Out().AsArm().AsCoreRegister();
975 ArmManagedRegister left = locations->InAt(0).AsArm();
976 ArmManagedRegister right = locations->InAt(1).AsArm();
977 Label less, greater, done;
978 __ cmp(left.AsRegisterPairHigh(),
979 ShifterOperand(right.AsRegisterPairHigh())); // Signed compare.
980 __ b(&less, LT);
981 __ b(&greater, GT);
982 __ cmp(left.AsRegisterPairLow(),
983 ShifterOperand(right.AsRegisterPairLow())); // Unsigned compare.
984 __ LoadImmediate(output, 0);
985 __ b(&done, EQ);
986 __ b(&less, CC);
987
988 __ Bind(&greater);
989 __ LoadImmediate(output, 1);
990 __ b(&done);
991
992 __ Bind(&less);
993 __ LoadImmediate(output, -1);
994
995 __ Bind(&done);
996 break;
997 }
998 default:
999 LOG(FATAL) << "Unimplemented compare type " << compare->InputAt(0)->GetType();
1000 }
1001}
1002
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01001003void LocationsBuilderARM::VisitPhi(HPhi* instruction) {
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01001004 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1005 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
1006 locations->SetInAt(i, Location::Any());
1007 }
1008 locations->SetOut(Location::Any());
1009 instruction->SetLocations(locations);
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01001010}
1011
1012void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001013 LOG(FATAL) << "Unreachable";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01001014}
1015
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001016void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
1017 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1018 locations->SetInAt(0, Location::RequiresRegister());
1019 locations->SetInAt(1, Location::RequiresRegister());
1020 instruction->SetLocations(locations);
1021}
1022
1023void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
1024 LocationSummary* locations = instruction->GetLocations();
1025 Register obj = locations->InAt(0).AsArm().AsCoreRegister();
1026 uint32_t offset = instruction->GetFieldOffset().Uint32Value();
1027 Primitive::Type field_type = instruction->InputAt(1)->GetType();
1028
1029 switch (field_type) {
1030 case Primitive::kPrimBoolean:
1031 case Primitive::kPrimByte: {
1032 Register value = locations->InAt(1).AsArm().AsCoreRegister();
1033 __ StoreToOffset(kStoreByte, value, obj, offset);
1034 break;
1035 }
1036
1037 case Primitive::kPrimShort:
1038 case Primitive::kPrimChar: {
1039 Register value = locations->InAt(1).AsArm().AsCoreRegister();
1040 __ StoreToOffset(kStoreHalfword, value, obj, offset);
1041 break;
1042 }
1043
1044 case Primitive::kPrimInt:
1045 case Primitive::kPrimNot: {
1046 Register value = locations->InAt(1).AsArm().AsCoreRegister();
1047 __ StoreToOffset(kStoreWord, value, obj, offset);
1048 break;
1049 }
1050
1051 case Primitive::kPrimLong: {
1052 ArmManagedRegister value = locations->InAt(1).AsArm();
1053 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow(), obj, offset);
1054 break;
1055 }
1056
1057 case Primitive::kPrimFloat:
1058 case Primitive::kPrimDouble:
1059 LOG(FATAL) << "Unimplemented register type " << field_type;
1060
1061 case Primitive::kPrimVoid:
1062 LOG(FATAL) << "Unreachable type " << field_type;
1063 }
1064}
1065
1066void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
1067 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1068 locations->SetInAt(0, Location::RequiresRegister());
1069 locations->SetOut(Location::RequiresRegister());
1070 instruction->SetLocations(locations);
1071}
1072
1073void InstructionCodeGeneratorARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
1074 LocationSummary* locations = instruction->GetLocations();
1075 Register obj = locations->InAt(0).AsArm().AsCoreRegister();
1076 uint32_t offset = instruction->GetFieldOffset().Uint32Value();
1077
1078 switch (instruction->GetType()) {
1079 case Primitive::kPrimBoolean: {
1080 Register out = locations->Out().AsArm().AsCoreRegister();
1081 __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset);
1082 break;
1083 }
1084
1085 case Primitive::kPrimByte: {
1086 Register out = locations->Out().AsArm().AsCoreRegister();
1087 __ LoadFromOffset(kLoadSignedByte, out, obj, offset);
1088 break;
1089 }
1090
1091 case Primitive::kPrimShort: {
1092 Register out = locations->Out().AsArm().AsCoreRegister();
1093 __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset);
1094 break;
1095 }
1096
1097 case Primitive::kPrimChar: {
1098 Register out = locations->Out().AsArm().AsCoreRegister();
1099 __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset);
1100 break;
1101 }
1102
1103 case Primitive::kPrimInt:
1104 case Primitive::kPrimNot: {
1105 Register out = locations->Out().AsArm().AsCoreRegister();
1106 __ LoadFromOffset(kLoadWord, out, obj, offset);
1107 break;
1108 }
1109
1110 case Primitive::kPrimLong: {
1111 // TODO: support volatile.
1112 ArmManagedRegister out = locations->Out().AsArm();
1113 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow(), obj, offset);
1114 break;
1115 }
1116
1117 case Primitive::kPrimFloat:
1118 case Primitive::kPrimDouble:
1119 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1120
1121 case Primitive::kPrimVoid:
1122 LOG(FATAL) << "Unreachable type " << instruction->GetType();
1123 }
1124}
1125
1126void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) {
1127 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1128 locations->SetInAt(0, Location::RequiresRegister());
1129 // TODO: Have a normalization phase that makes this instruction never used.
1130 locations->SetOut(Location::SameAsFirstInput());
1131 instruction->SetLocations(locations);
1132}
1133
1134void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) {
1135 SlowPathCode* slow_path =
1136 new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction->GetDexPc());
1137 codegen_->AddSlowPath(slow_path);
1138
1139 LocationSummary* locations = instruction->GetLocations();
1140 Location obj = locations->InAt(0);
1141 DCHECK(obj.Equals(locations->Out()));
1142
1143 if (obj.IsRegister()) {
1144 __ cmp(obj.AsArm().AsCoreRegister(), ShifterOperand(0));
1145 }
1146 __ b(slow_path->GetEntryLabel(), EQ);
1147}
1148
1149void LocationsBuilderARM::VisitTemporary(HTemporary* temp) {
1150 temp->SetLocations(nullptr);
1151}
1152
1153void InstructionCodeGeneratorARM::VisitTemporary(HTemporary* temp) {
1154 // Nothing to do, this is driven by the code generator.
1155}
1156
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01001157void LocationsBuilderARM::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001158 LOG(FATAL) << "Unreachable";
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01001159}
1160
1161void InstructionCodeGeneratorARM::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001162 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
1163}
1164
1165ArmAssembler* ParallelMoveResolverARM::GetAssembler() const {
1166 return codegen_->GetAssembler();
1167}
1168
1169void ParallelMoveResolverARM::EmitMove(size_t index) {
1170 MoveOperands* move = moves_.Get(index);
1171 Location source = move->GetSource();
1172 Location destination = move->GetDestination();
1173
1174 if (source.IsRegister()) {
1175 if (destination.IsRegister()) {
1176 __ Mov(destination.AsArm().AsCoreRegister(), source.AsArm().AsCoreRegister());
1177 } else {
1178 DCHECK(destination.IsStackSlot());
1179 __ StoreToOffset(kStoreWord, source.AsArm().AsCoreRegister(),
1180 SP, destination.GetStackIndex());
1181 }
1182 } else if (source.IsStackSlot()) {
1183 if (destination.IsRegister()) {
1184 __ LoadFromOffset(kLoadWord, destination.AsArm().AsCoreRegister(),
1185 SP, source.GetStackIndex());
1186 } else {
1187 DCHECK(destination.IsStackSlot());
1188 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
1189 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
1190 }
1191 } else {
1192 LOG(FATAL) << "Unimplemented";
1193 }
1194}
1195
1196void ParallelMoveResolverARM::Exchange(Register reg, int mem) {
1197 __ Mov(IP, reg);
1198 __ LoadFromOffset(kLoadWord, reg, SP, mem);
1199 __ StoreToOffset(kStoreWord, IP, SP, mem);
1200}
1201
1202void ParallelMoveResolverARM::Exchange(int mem1, int mem2) {
1203 ScratchRegisterScope ensure_scratch(this, IP, R0, codegen_->GetNumberOfCoreRegisters());
1204 int stack_offset = ensure_scratch.IsSpilled() ? kArmWordSize : 0;
1205 __ LoadFromOffset(kLoadWord, static_cast<Register>(ensure_scratch.GetRegister()),
1206 SP, mem1 + stack_offset);
1207 __ LoadFromOffset(kLoadWord, IP, SP, mem2 + stack_offset);
1208 __ StoreToOffset(kStoreWord, static_cast<Register>(ensure_scratch.GetRegister()),
1209 SP, mem2 + stack_offset);
1210 __ StoreToOffset(kStoreWord, IP, SP, mem1 + stack_offset);
1211}
1212
1213void ParallelMoveResolverARM::EmitSwap(size_t index) {
1214 MoveOperands* move = moves_.Get(index);
1215 Location source = move->GetSource();
1216 Location destination = move->GetDestination();
1217
1218 if (source.IsRegister() && destination.IsRegister()) {
1219 DCHECK_NE(source.AsArm().AsCoreRegister(), IP);
1220 DCHECK_NE(destination.AsArm().AsCoreRegister(), IP);
1221 __ Mov(IP, source.AsArm().AsCoreRegister());
1222 __ Mov(source.AsArm().AsCoreRegister(), destination.AsArm().AsCoreRegister());
1223 __ Mov(destination.AsArm().AsCoreRegister(), IP);
1224 } else if (source.IsRegister() && destination.IsStackSlot()) {
1225 Exchange(source.AsArm().AsCoreRegister(), destination.GetStackIndex());
1226 } else if (source.IsStackSlot() && destination.IsRegister()) {
1227 Exchange(destination.AsArm().AsCoreRegister(), source.GetStackIndex());
1228 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
1229 Exchange(source.GetStackIndex(), destination.GetStackIndex());
1230 } else {
1231 LOG(FATAL) << "Unimplemented";
1232 }
1233}
1234
1235void ParallelMoveResolverARM::SpillScratch(int reg) {
1236 __ Push(static_cast<Register>(reg));
1237}
1238
1239void ParallelMoveResolverARM::RestoreScratch(int reg) {
1240 __ Pop(static_cast<Register>(reg));
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01001241}
1242
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001243} // namespace arm
1244} // namespace art