blob: 73c2d483209aa70160c723dfb2794b9d0dda65ac [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
Nicolas Geoffrayab032bc2014-07-15 12:55:21 +0100102size_t CodeGeneratorARM::FrameEntrySpillSize() const {
103 return kNumberOfPushedRegistersAtEntry * kArmWordSize;
104}
105
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100106static bool* GetBlockedRegisterPairs(bool* blocked_registers) {
107 return blocked_registers + kNumberOfAllocIds;
108}
109
110ManagedRegister CodeGeneratorARM::AllocateFreeRegister(Primitive::Type type,
111 bool* blocked_registers) const {
112 switch (type) {
113 case Primitive::kPrimLong: {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100114 bool* blocked_register_pairs = GetBlockedRegisterPairs(blocked_registers);
115 size_t reg = AllocateFreeRegisterInternal(blocked_register_pairs, kNumberOfRegisterPairs);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100116 ArmManagedRegister pair =
117 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(reg));
118 blocked_registers[pair.AsRegisterPairLow()] = true;
119 blocked_registers[pair.AsRegisterPairHigh()] = true;
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100120 // Block all other register pairs that share a register with `pair`.
121 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
122 ArmManagedRegister current =
123 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
124 if (current.AsRegisterPairLow() == pair.AsRegisterPairLow()
125 || current.AsRegisterPairLow() == pair.AsRegisterPairHigh()
126 || current.AsRegisterPairHigh() == pair.AsRegisterPairLow()
127 || current.AsRegisterPairHigh() == pair.AsRegisterPairHigh()) {
128 blocked_register_pairs[i] = true;
129 }
130 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100131 return pair;
132 }
133
134 case Primitive::kPrimByte:
135 case Primitive::kPrimBoolean:
136 case Primitive::kPrimChar:
137 case Primitive::kPrimShort:
138 case Primitive::kPrimInt:
139 case Primitive::kPrimNot: {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100140 int reg = AllocateFreeRegisterInternal(blocked_registers, kNumberOfCoreRegisters);
141 // Block all register pairs that contain `reg`.
142 bool* blocked_register_pairs = GetBlockedRegisterPairs(blocked_registers);
143 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
144 ArmManagedRegister current =
145 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
146 if (current.AsRegisterPairLow() == reg || current.AsRegisterPairHigh() == reg) {
147 blocked_register_pairs[i] = true;
148 }
149 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100150 return ArmManagedRegister::FromCoreRegister(static_cast<Register>(reg));
151 }
152
153 case Primitive::kPrimFloat:
154 case Primitive::kPrimDouble:
155 LOG(FATAL) << "Unimplemented register type " << type;
156
157 case Primitive::kPrimVoid:
158 LOG(FATAL) << "Unreachable type " << type;
159 }
160
161 return ManagedRegister::NoRegister();
162}
163
164void CodeGeneratorARM::SetupBlockedRegisters(bool* blocked_registers) const {
165 bool* blocked_register_pairs = GetBlockedRegisterPairs(blocked_registers);
166
167 // Don't allocate the dalvik style register pair passing.
168 blocked_register_pairs[R1_R2] = true;
169
170 // Stack register, LR and PC are always reserved.
171 blocked_registers[SP] = true;
172 blocked_registers[LR] = true;
173 blocked_registers[PC] = true;
174
175 // Reserve R4 for suspend check.
176 blocked_registers[R4] = true;
177 blocked_register_pairs[R4_R5] = true;
178
179 // Reserve thread register.
180 blocked_registers[TR] = true;
181
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100182 // Reserve temp register.
183 blocked_registers[IP] = true;
184
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100185 // TODO: We currently don't use Quick's callee saved registers.
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100186 // We always save and restore R6 and R7 to make sure we can use three
187 // register pairs for long operations.
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100188 blocked_registers[R5] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100189 blocked_registers[R8] = true;
190 blocked_registers[R10] = true;
191 blocked_registers[R11] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100192}
193
194size_t CodeGeneratorARM::GetNumberOfRegisters() const {
195 return kNumberOfRegIds;
196}
197
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100198static Location ArmCoreLocation(Register reg) {
199 return Location::RegisterLocation(ArmManagedRegister::FromCoreRegister(reg));
200}
201
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100202InstructionCodeGeneratorARM::InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen)
203 : HGraphVisitor(graph),
204 assembler_(codegen->GetAssembler()),
205 codegen_(codegen) {}
206
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000207void CodeGeneratorARM::GenerateFrameEntry() {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100208 core_spill_mask_ |= (1 << LR | 1 << R6 | 1 << R7);
209 __ PushList(1 << LR | 1 << R6 | 1 << R7);
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000210
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100211 // The return PC has already been pushed on the stack.
Nicolas Geoffray707c8092014-04-04 10:50:14 +0100212 __ AddConstant(SP, -(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kArmWordSize));
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000213 __ str(R0, Address(SP, 0));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000214}
215
216void CodeGeneratorARM::GenerateFrameExit() {
Nicolas Geoffray707c8092014-04-04 10:50:14 +0100217 __ AddConstant(SP, GetFrameSize() - kNumberOfPushedRegistersAtEntry * kArmWordSize);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100218 __ PopList(1 << PC | 1 << R6 | 1 << R7);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000219}
220
221void CodeGeneratorARM::Bind(Label* label) {
222 __ Bind(label);
223}
224
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100225Location CodeGeneratorARM::GetStackLocation(HLoadLocal* load) const {
226 switch (load->GetType()) {
227 case Primitive::kPrimLong:
228 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
229 break;
230
231 case Primitive::kPrimInt:
232 case Primitive::kPrimNot:
233 return Location::StackSlot(GetStackSlot(load->GetLocal()));
234
235 case Primitive::kPrimFloat:
236 case Primitive::kPrimDouble:
237 LOG(FATAL) << "Unimplemented type " << load->GetType();
238
239 case Primitive::kPrimBoolean:
240 case Primitive::kPrimByte:
241 case Primitive::kPrimChar:
242 case Primitive::kPrimShort:
243 case Primitive::kPrimVoid:
244 LOG(FATAL) << "Unexpected type " << load->GetType();
245 }
246
247 LOG(FATAL) << "Unreachable";
248 return Location();
249}
250
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100251Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) {
252 switch (type) {
253 case Primitive::kPrimBoolean:
254 case Primitive::kPrimByte:
255 case Primitive::kPrimChar:
256 case Primitive::kPrimShort:
257 case Primitive::kPrimInt:
258 case Primitive::kPrimNot: {
259 uint32_t index = gp_index_++;
260 if (index < calling_convention.GetNumberOfRegisters()) {
261 return ArmCoreLocation(calling_convention.GetRegisterAt(index));
262 } else {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100263 return Location::StackSlot(calling_convention.GetStackOffsetOf(index));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100264 }
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100265 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100266
267 case Primitive::kPrimLong: {
268 uint32_t index = gp_index_;
269 gp_index_ += 2;
270 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
271 return Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(
272 calling_convention.GetRegisterPairAt(index)));
273 } else if (index + 1 == calling_convention.GetNumberOfRegisters()) {
274 return Location::QuickParameter(index);
275 } else {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100276 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100277 }
278 }
279
280 case Primitive::kPrimDouble:
281 case Primitive::kPrimFloat:
282 LOG(FATAL) << "Unimplemented parameter type " << type;
283 break;
284
285 case Primitive::kPrimVoid:
286 LOG(FATAL) << "Unexpected parameter type " << type;
287 break;
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100288 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100289 return Location();
290}
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100291
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100292void CodeGeneratorARM::Move32(Location destination, Location source) {
293 if (source.Equals(destination)) {
294 return;
295 }
296 if (destination.IsRegister()) {
297 if (source.IsRegister()) {
298 __ Mov(destination.AsArm().AsCoreRegister(), source.AsArm().AsCoreRegister());
299 } else {
300 __ ldr(destination.AsArm().AsCoreRegister(), Address(SP, source.GetStackIndex()));
301 }
302 } else {
303 DCHECK(destination.IsStackSlot());
304 if (source.IsRegister()) {
305 __ str(source.AsArm().AsCoreRegister(), Address(SP, destination.GetStackIndex()));
306 } else {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100307 __ ldr(IP, Address(SP, source.GetStackIndex()));
308 __ str(IP, Address(SP, destination.GetStackIndex()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100309 }
310 }
311}
312
313void CodeGeneratorARM::Move64(Location destination, Location source) {
314 if (source.Equals(destination)) {
315 return;
316 }
317 if (destination.IsRegister()) {
318 if (source.IsRegister()) {
319 __ Mov(destination.AsArm().AsRegisterPairLow(), source.AsArm().AsRegisterPairLow());
320 __ Mov(destination.AsArm().AsRegisterPairHigh(), source.AsArm().AsRegisterPairHigh());
321 } else if (source.IsQuickParameter()) {
322 uint32_t argument_index = source.GetQuickParameterIndex();
323 InvokeDexCallingConvention calling_convention;
324 __ Mov(destination.AsArm().AsRegisterPairLow(),
325 calling_convention.GetRegisterAt(argument_index));
326 __ ldr(destination.AsArm().AsRegisterPairHigh(),
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100327 Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1) + GetFrameSize()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100328 } else {
329 DCHECK(source.IsDoubleStackSlot());
330 if (destination.AsArm().AsRegisterPair() == R1_R2) {
331 __ ldr(R1, Address(SP, source.GetStackIndex()));
332 __ ldr(R2, Address(SP, source.GetHighStackIndex(kArmWordSize)));
333 } else {
334 __ LoadFromOffset(kLoadWordPair, destination.AsArm().AsRegisterPairLow(),
335 SP, source.GetStackIndex());
336 }
337 }
338 } else if (destination.IsQuickParameter()) {
339 InvokeDexCallingConvention calling_convention;
340 uint32_t argument_index = destination.GetQuickParameterIndex();
341 if (source.IsRegister()) {
342 __ Mov(calling_convention.GetRegisterAt(argument_index), source.AsArm().AsRegisterPairLow());
343 __ str(source.AsArm().AsRegisterPairHigh(),
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100344 Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100345 } else {
346 DCHECK(source.IsDoubleStackSlot());
347 __ ldr(calling_convention.GetRegisterAt(argument_index), Address(SP, source.GetStackIndex()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100348 __ ldr(R0, Address(SP, source.GetHighStackIndex(kArmWordSize)));
349 __ str(R0, Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100350 }
351 } else {
352 DCHECK(destination.IsDoubleStackSlot());
353 if (source.IsRegister()) {
354 if (source.AsArm().AsRegisterPair() == R1_R2) {
355 __ str(R1, Address(SP, destination.GetStackIndex()));
356 __ str(R2, Address(SP, destination.GetHighStackIndex(kArmWordSize)));
357 } else {
358 __ StoreToOffset(kStoreWordPair, source.AsArm().AsRegisterPairLow(),
359 SP, destination.GetStackIndex());
360 }
361 } else if (source.IsQuickParameter()) {
362 InvokeDexCallingConvention calling_convention;
363 uint32_t argument_index = source.GetQuickParameterIndex();
364 __ str(calling_convention.GetRegisterAt(argument_index),
365 Address(SP, destination.GetStackIndex()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100366 __ ldr(R0,
367 Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1) + GetFrameSize()));
368 __ str(R0, Address(SP, destination.GetHighStackIndex(kArmWordSize)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100369 } else {
370 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100371 __ ldr(IP, Address(SP, source.GetStackIndex()));
372 __ str(IP, Address(SP, destination.GetStackIndex()));
373 __ ldr(IP, Address(SP, source.GetHighStackIndex(kArmWordSize)));
374 __ str(IP, Address(SP, destination.GetHighStackIndex(kArmWordSize)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100375 }
376 }
377}
378
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100379void CodeGeneratorARM::Move(HInstruction* instruction, Location location, HInstruction* move_for) {
380 if (instruction->AsIntConstant() != nullptr) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100381 int32_t value = instruction->AsIntConstant()->GetValue();
382 if (location.IsRegister()) {
383 __ LoadImmediate(location.AsArm().AsCoreRegister(), value);
384 } else {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100385 __ LoadImmediate(IP, value);
386 __ str(IP, Address(SP, location.GetStackIndex()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100387 }
388 } else if (instruction->AsLongConstant() != nullptr) {
389 int64_t value = instruction->AsLongConstant()->GetValue();
390 if (location.IsRegister()) {
391 __ LoadImmediate(location.AsArm().AsRegisterPairLow(), Low32Bits(value));
392 __ LoadImmediate(location.AsArm().AsRegisterPairHigh(), High32Bits(value));
393 } else {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100394 __ LoadImmediate(IP, Low32Bits(value));
395 __ str(IP, Address(SP, location.GetStackIndex()));
396 __ LoadImmediate(IP, High32Bits(value));
397 __ str(IP, Address(SP, location.GetHighStackIndex(kArmWordSize)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100398 }
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100399 } else if (instruction->AsLoadLocal() != nullptr) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100400 uint32_t stack_slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
401 switch (instruction->GetType()) {
402 case Primitive::kPrimBoolean:
403 case Primitive::kPrimByte:
404 case Primitive::kPrimChar:
405 case Primitive::kPrimShort:
406 case Primitive::kPrimInt:
407 case Primitive::kPrimNot:
408 Move32(location, Location::StackSlot(stack_slot));
409 break;
410
411 case Primitive::kPrimLong:
412 Move64(location, Location::DoubleStackSlot(stack_slot));
413 break;
414
415 default:
416 LOG(FATAL) << "Unimplemented type " << instruction->GetType();
417 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000418 } else {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100419 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100420 switch (instruction->GetType()) {
421 case Primitive::kPrimBoolean:
422 case Primitive::kPrimByte:
423 case Primitive::kPrimChar:
424 case Primitive::kPrimShort:
425 case Primitive::kPrimNot:
426 case Primitive::kPrimInt:
427 Move32(location, instruction->GetLocations()->Out());
428 break;
429
430 case Primitive::kPrimLong:
431 Move64(location, instruction->GetLocations()->Out());
432 break;
433
434 default:
435 LOG(FATAL) << "Unimplemented type " << instruction->GetType();
436 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000437 }
438}
439
440void LocationsBuilderARM::VisitGoto(HGoto* got) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000441 got->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000442}
443
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000444void InstructionCodeGeneratorARM::VisitGoto(HGoto* got) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000445 HBasicBlock* successor = got->GetSuccessor();
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000446 if (GetGraph()->GetExitBlock() == successor) {
447 codegen_->GenerateFrameExit();
448 } else if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
449 __ b(codegen_->GetLabelOf(successor));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000450 }
451}
452
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000453void LocationsBuilderARM::VisitExit(HExit* exit) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000454 exit->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000455}
456
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000457void InstructionCodeGeneratorARM::VisitExit(HExit* exit) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000458 if (kIsDebugBuild) {
459 __ Comment("Unreachable");
460 __ bkpt(0);
461 }
462}
463
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000464void LocationsBuilderARM::VisitIf(HIf* if_instr) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000465 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100466 HInstruction* cond = if_instr->InputAt(0);
467 DCHECK(cond->IsCondition());
468 HCondition* condition = cond->AsCondition();
469 if (condition->NeedsMaterialization()) {
470 locations->SetInAt(0, Location::Any());
471 }
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000472 if_instr->SetLocations(locations);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000473}
474
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000475void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) {
Dave Allison20dfc792014-06-16 20:44:29 -0700476 HInstruction* cond = if_instr->InputAt(0);
477 DCHECK(cond->IsCondition());
478 HCondition* condition = cond->AsCondition();
479 if (condition->NeedsMaterialization()) {
480 // Condition has been materialized, compare the output to 0
481 if (!if_instr->GetLocations()->InAt(0).IsRegister()) {
482 LOG(FATAL) << "Materialized condition is not in an ARM register";
483 }
484 __ cmp(if_instr->GetLocations()->InAt(0).AsArm().AsCoreRegister(),
485 ShifterOperand(0));
486 __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()), EQ);
487 } else {
488 // Condition has not been materialized, use its inputs as the comparison and its
489 // condition as the branch condition.
490 __ cmp(condition->GetLocations()->InAt(0).AsArm().AsCoreRegister(),
491 ShifterOperand(condition->GetLocations()->InAt(1).AsArm().AsCoreRegister()));
492 __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()),
493 ARMCondition(condition->GetCondition()));
494 }
495 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfFalseSuccessor())) {
496 __ b(codegen_->GetLabelOf(if_instr->IfFalseSuccessor()));
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000497 }
498}
499
Dave Allison20dfc792014-06-16 20:44:29 -0700500
501void LocationsBuilderARM::VisitCondition(HCondition* comp) {
502 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(comp);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100503 locations->SetInAt(0, Location::RequiresRegister());
504 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100505 if (comp->NeedsMaterialization()) {
506 locations->SetOut(Location::RequiresRegister());
507 }
Dave Allison20dfc792014-06-16 20:44:29 -0700508 comp->SetLocations(locations);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000509}
510
Dave Allison20dfc792014-06-16 20:44:29 -0700511void InstructionCodeGeneratorARM::VisitCondition(HCondition* comp) {
512 if (comp->NeedsMaterialization()) {
513 LocationSummary* locations = comp->GetLocations();
514 __ cmp(locations->InAt(0).AsArm().AsCoreRegister(),
515 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
516 __ it(ARMCondition(comp->GetCondition()), kItElse);
517 __ mov(locations->Out().AsArm().AsCoreRegister(), ShifterOperand(1),
518 ARMCondition(comp->GetCondition()));
519 __ mov(locations->Out().AsArm().AsCoreRegister(), ShifterOperand(0),
520 ARMOppositeCondition(comp->GetCondition()));
521 }
522}
523
524void LocationsBuilderARM::VisitEqual(HEqual* comp) {
525 VisitCondition(comp);
526}
527
528void InstructionCodeGeneratorARM::VisitEqual(HEqual* comp) {
529 VisitCondition(comp);
530}
531
532void LocationsBuilderARM::VisitNotEqual(HNotEqual* comp) {
533 VisitCondition(comp);
534}
535
536void InstructionCodeGeneratorARM::VisitNotEqual(HNotEqual* comp) {
537 VisitCondition(comp);
538}
539
540void LocationsBuilderARM::VisitLessThan(HLessThan* comp) {
541 VisitCondition(comp);
542}
543
544void InstructionCodeGeneratorARM::VisitLessThan(HLessThan* comp) {
545 VisitCondition(comp);
546}
547
548void LocationsBuilderARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
549 VisitCondition(comp);
550}
551
552void InstructionCodeGeneratorARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
553 VisitCondition(comp);
554}
555
556void LocationsBuilderARM::VisitGreaterThan(HGreaterThan* comp) {
557 VisitCondition(comp);
558}
559
560void InstructionCodeGeneratorARM::VisitGreaterThan(HGreaterThan* comp) {
561 VisitCondition(comp);
562}
563
564void LocationsBuilderARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
565 VisitCondition(comp);
566}
567
568void InstructionCodeGeneratorARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
569 VisitCondition(comp);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000570}
571
572void LocationsBuilderARM::VisitLocal(HLocal* local) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000573 local->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000574}
575
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000576void InstructionCodeGeneratorARM::VisitLocal(HLocal* local) {
577 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000578}
579
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000580void LocationsBuilderARM::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100581 load->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000582}
583
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000584void InstructionCodeGeneratorARM::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100585 // Nothing to do, this is driven by the code generator.
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000586}
587
588void LocationsBuilderARM::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000589 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(store);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100590 switch (store->InputAt(1)->GetType()) {
591 case Primitive::kPrimBoolean:
592 case Primitive::kPrimByte:
593 case Primitive::kPrimChar:
594 case Primitive::kPrimShort:
595 case Primitive::kPrimInt:
596 case Primitive::kPrimNot:
597 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
598 break;
599
600 case Primitive::kPrimLong:
601 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
602 break;
603
604 default:
605 LOG(FATAL) << "Unimplemented local type " << store->InputAt(1)->GetType();
606 }
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000607 store->SetLocations(locations);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000608}
609
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000610void InstructionCodeGeneratorARM::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000611}
612
613void LocationsBuilderARM::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100614 // TODO: Support constant locations.
615 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
616 locations->SetOut(Location::RequiresRegister());
617 constant->SetLocations(locations);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000618}
619
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000620void InstructionCodeGeneratorARM::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100621 codegen_->Move(constant, constant->GetLocations()->Out(), nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000622}
623
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100624void LocationsBuilderARM::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100625 // TODO: Support constant locations.
626 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
627 locations->SetOut(Location::RequiresRegister());
628 constant->SetLocations(locations);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100629}
630
631void InstructionCodeGeneratorARM::VisitLongConstant(HLongConstant* constant) {
632 // Will be generated at use site.
633}
634
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000635void LocationsBuilderARM::VisitReturnVoid(HReturnVoid* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000636 ret->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000637}
638
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000639void InstructionCodeGeneratorARM::VisitReturnVoid(HReturnVoid* ret) {
640 codegen_->GenerateFrameExit();
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000641}
642
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000643void LocationsBuilderARM::VisitReturn(HReturn* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000644 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(ret);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100645 switch (ret->InputAt(0)->GetType()) {
646 case Primitive::kPrimBoolean:
647 case Primitive::kPrimByte:
648 case Primitive::kPrimChar:
649 case Primitive::kPrimShort:
650 case Primitive::kPrimInt:
651 case Primitive::kPrimNot:
652 locations->SetInAt(0, ArmCoreLocation(R0));
653 break;
654
655 case Primitive::kPrimLong:
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100656 locations->SetInAt(
657 0, Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(R0_R1)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100658 break;
659
660 default:
661 LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
662 }
663
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000664 ret->SetLocations(locations);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000665}
666
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000667void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100668 if (kIsDebugBuild) {
669 switch (ret->InputAt(0)->GetType()) {
670 case Primitive::kPrimBoolean:
671 case Primitive::kPrimByte:
672 case Primitive::kPrimChar:
673 case Primitive::kPrimShort:
674 case Primitive::kPrimInt:
675 case Primitive::kPrimNot:
676 DCHECK_EQ(ret->GetLocations()->InAt(0).AsArm().AsCoreRegister(), R0);
677 break;
678
679 case Primitive::kPrimLong:
680 DCHECK_EQ(ret->GetLocations()->InAt(0).AsArm().AsRegisterPair(), R0_R1);
681 break;
682
683 default:
684 LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
685 }
686 }
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000687 codegen_->GenerateFrameExit();
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000688}
689
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000690void LocationsBuilderARM::VisitInvokeStatic(HInvokeStatic* invoke) {
691 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(invoke);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100692 locations->AddTemp(ArmCoreLocation(R0));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100693
694 InvokeDexCallingConventionVisitor calling_convention_visitor;
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100695 for (size_t i = 0; i < invoke->InputCount(); i++) {
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100696 HInstruction* input = invoke->InputAt(i);
697 locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
698 }
699
700 switch (invoke->GetType()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100701 case Primitive::kPrimBoolean:
702 case Primitive::kPrimByte:
703 case Primitive::kPrimChar:
704 case Primitive::kPrimShort:
705 case Primitive::kPrimInt:
706 case Primitive::kPrimNot:
707 locations->SetOut(ArmCoreLocation(R0));
708 break;
709
710 case Primitive::kPrimLong:
711 locations->SetOut(Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(R0_R1)));
712 break;
713
714 case Primitive::kPrimVoid:
715 break;
716
717 case Primitive::kPrimDouble:
718 case Primitive::kPrimFloat:
719 LOG(FATAL) << "Unimplemented return type " << invoke->GetType();
720 break;
721 }
722
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000723 invoke->SetLocations(locations);
724}
725
726void InstructionCodeGeneratorARM::LoadCurrentMethod(Register reg) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100727 __ ldr(reg, Address(SP, kCurrentMethodStackOffset));
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000728}
729
730void InstructionCodeGeneratorARM::VisitInvokeStatic(HInvokeStatic* invoke) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100731 Register temp = invoke->GetLocations()->GetTemp(0).AsArm().AsCoreRegister();
Nicolas Geoffrayf61b5372014-06-25 14:35:34 +0100732 uint32_t heap_reference_size = sizeof(mirror::HeapReference<mirror::Object>);
733 size_t index_in_cache = mirror::Array::DataOffset(heap_reference_size).Int32Value() +
Nicolas Geoffray707c8092014-04-04 10:50:14 +0100734 invoke->GetIndexInDexCache() * kArmWordSize;
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000735
736 // TODO: Implement all kinds of calls:
737 // 1) boot -> boot
738 // 2) app -> boot
739 // 3) app -> app
740 //
741 // Currently we implement the app -> app logic, which looks up in the resolve cache.
742
743 // temp = method;
744 LoadCurrentMethod(temp);
745 // temp = temp->dex_cache_resolved_methods_;
746 __ ldr(temp, Address(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value()));
747 // temp = temp[index_in_cache]
748 __ ldr(temp, Address(temp, index_in_cache));
749 // LR = temp[offset_of_quick_compiled_code]
750 __ ldr(LR, Address(temp,
751 mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value()));
752 // LR()
753 __ blx(LR);
754
755 codegen_->RecordPcInfo(invoke->GetDexPc());
756}
757
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000758void LocationsBuilderARM::VisitAdd(HAdd* add) {
759 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(add);
760 switch (add->GetResultType()) {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100761 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100762 case Primitive::kPrimLong: {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100763 locations->SetInAt(0, Location::RequiresRegister());
764 locations->SetInAt(1, Location::RequiresRegister());
765 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100766 break;
767 }
768
769 case Primitive::kPrimBoolean:
770 case Primitive::kPrimByte:
771 case Primitive::kPrimChar:
772 case Primitive::kPrimShort:
773 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
774 break;
775
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000776 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100777 LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000778 }
779 add->SetLocations(locations);
780}
781
782void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) {
783 LocationSummary* locations = add->GetLocations();
784 switch (add->GetResultType()) {
785 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100786 __ add(locations->Out().AsArm().AsCoreRegister(),
787 locations->InAt(0).AsArm().AsCoreRegister(),
788 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000789 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100790
791 case Primitive::kPrimLong:
792 __ adds(locations->Out().AsArm().AsRegisterPairLow(),
793 locations->InAt(0).AsArm().AsRegisterPairLow(),
794 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairLow()));
795 __ adc(locations->Out().AsArm().AsRegisterPairHigh(),
796 locations->InAt(0).AsArm().AsRegisterPairHigh(),
797 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairHigh()));
798 break;
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}
811
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100812void LocationsBuilderARM::VisitSub(HSub* sub) {
813 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(sub);
814 switch (sub->GetResultType()) {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100815 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100816 case Primitive::kPrimLong: {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100817 locations->SetInAt(0, Location::RequiresRegister());
818 locations->SetInAt(1, Location::RequiresRegister());
819 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100820 break;
821 }
822
823 case Primitive::kPrimBoolean:
824 case Primitive::kPrimByte:
825 case Primitive::kPrimChar:
826 case Primitive::kPrimShort:
827 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
828 break;
829
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100830 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100831 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100832 }
833 sub->SetLocations(locations);
834}
835
836void InstructionCodeGeneratorARM::VisitSub(HSub* sub) {
837 LocationSummary* locations = sub->GetLocations();
838 switch (sub->GetResultType()) {
839 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100840 __ sub(locations->Out().AsArm().AsCoreRegister(),
841 locations->InAt(0).AsArm().AsCoreRegister(),
842 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100843 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100844
845 case Primitive::kPrimLong:
846 __ subs(locations->Out().AsArm().AsRegisterPairLow(),
847 locations->InAt(0).AsArm().AsRegisterPairLow(),
848 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairLow()));
849 __ sbc(locations->Out().AsArm().AsRegisterPairHigh(),
850 locations->InAt(0).AsArm().AsRegisterPairHigh(),
851 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairHigh()));
852 break;
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}
865
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +0100866static constexpr Register kRuntimeParameterCoreRegisters[] = { R0, R1 };
867static constexpr size_t kRuntimeParameterCoreRegistersLength =
868 arraysize(kRuntimeParameterCoreRegisters);
869
870class InvokeRuntimeCallingConvention : public CallingConvention<Register> {
871 public:
872 InvokeRuntimeCallingConvention()
873 : CallingConvention(kRuntimeParameterCoreRegisters,
874 kRuntimeParameterCoreRegistersLength) {}
875
876 private:
877 DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention);
878};
879
880void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) {
881 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100882 InvokeRuntimeCallingConvention calling_convention;
883 locations->AddTemp(ArmCoreLocation(calling_convention.GetRegisterAt(0)));
884 locations->AddTemp(ArmCoreLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100885 locations->SetOut(ArmCoreLocation(R0));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +0100886 instruction->SetLocations(locations);
887}
888
889void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) {
890 InvokeRuntimeCallingConvention calling_convention;
891 LoadCurrentMethod(calling_convention.GetRegisterAt(1));
892 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
893
Nicolas Geoffray707c8092014-04-04 10:50:14 +0100894 int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAllocObjectWithAccessCheck).Int32Value();
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +0100895 __ ldr(LR, Address(TR, offset));
896 __ blx(LR);
897
898 codegen_->RecordPcInfo(instruction->GetDexPc());
899}
900
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100901void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) {
902 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100903 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
904 if (location.IsStackSlot()) {
905 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
906 } else if (location.IsDoubleStackSlot()) {
907 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100908 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100909 locations->SetOut(location);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100910 instruction->SetLocations(locations);
911}
912
913void InstructionCodeGeneratorARM::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100914 // Nothing to do, the parameter is already at its location.
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100915}
916
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +0100917void LocationsBuilderARM::VisitNot(HNot* instruction) {
918 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100919 locations->SetInAt(0, Location::RequiresRegister());
920 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +0100921 instruction->SetLocations(locations);
922}
923
924void InstructionCodeGeneratorARM::VisitNot(HNot* instruction) {
925 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100926 __ eor(locations->Out().AsArm().AsCoreRegister(),
927 locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(1));
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +0100928}
929
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100930void LocationsBuilderARM::VisitCompare(HCompare* compare) {
931 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(compare);
932 locations->SetInAt(0, Location::RequiresRegister());
933 locations->SetInAt(1, Location::RequiresRegister());
934 locations->SetOut(Location::RequiresRegister());
935 compare->SetLocations(locations);
936}
937
938void InstructionCodeGeneratorARM::VisitCompare(HCompare* compare) {
939 Label greater, done;
940 LocationSummary* locations = compare->GetLocations();
941 switch (compare->InputAt(0)->GetType()) {
942 case Primitive::kPrimLong: {
943 Register output = locations->Out().AsArm().AsCoreRegister();
944 ArmManagedRegister left = locations->InAt(0).AsArm();
945 ArmManagedRegister right = locations->InAt(1).AsArm();
946 Label less, greater, done;
947 __ cmp(left.AsRegisterPairHigh(),
948 ShifterOperand(right.AsRegisterPairHigh())); // Signed compare.
949 __ b(&less, LT);
950 __ b(&greater, GT);
951 __ cmp(left.AsRegisterPairLow(),
952 ShifterOperand(right.AsRegisterPairLow())); // Unsigned compare.
953 __ LoadImmediate(output, 0);
954 __ b(&done, EQ);
955 __ b(&less, CC);
956
957 __ Bind(&greater);
958 __ LoadImmediate(output, 1);
959 __ b(&done);
960
961 __ Bind(&less);
962 __ LoadImmediate(output, -1);
963
964 __ Bind(&done);
965 break;
966 }
967 default:
968 LOG(FATAL) << "Unimplemented compare type " << compare->InputAt(0)->GetType();
969 }
970}
971
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100972void LocationsBuilderARM::VisitPhi(HPhi* instruction) {
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100973 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
974 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
975 locations->SetInAt(i, Location::Any());
976 }
977 locations->SetOut(Location::Any());
978 instruction->SetLocations(locations);
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100979}
980
981void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100982 LOG(FATAL) << "Unreachable";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100983}
984
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100985void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
986 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
987 locations->SetInAt(0, Location::RequiresRegister());
988 locations->SetInAt(1, Location::RequiresRegister());
989 instruction->SetLocations(locations);
990}
991
992void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
993 LocationSummary* locations = instruction->GetLocations();
994 Register obj = locations->InAt(0).AsArm().AsCoreRegister();
995 uint32_t offset = instruction->GetFieldOffset().Uint32Value();
996 Primitive::Type field_type = instruction->InputAt(1)->GetType();
997
998 switch (field_type) {
999 case Primitive::kPrimBoolean:
1000 case Primitive::kPrimByte: {
1001 Register value = locations->InAt(1).AsArm().AsCoreRegister();
1002 __ StoreToOffset(kStoreByte, value, obj, offset);
1003 break;
1004 }
1005
1006 case Primitive::kPrimShort:
1007 case Primitive::kPrimChar: {
1008 Register value = locations->InAt(1).AsArm().AsCoreRegister();
1009 __ StoreToOffset(kStoreHalfword, value, obj, offset);
1010 break;
1011 }
1012
1013 case Primitive::kPrimInt:
1014 case Primitive::kPrimNot: {
1015 Register value = locations->InAt(1).AsArm().AsCoreRegister();
1016 __ StoreToOffset(kStoreWord, value, obj, offset);
1017 break;
1018 }
1019
1020 case Primitive::kPrimLong: {
1021 ArmManagedRegister value = locations->InAt(1).AsArm();
1022 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow(), obj, offset);
1023 break;
1024 }
1025
1026 case Primitive::kPrimFloat:
1027 case Primitive::kPrimDouble:
1028 LOG(FATAL) << "Unimplemented register type " << field_type;
1029
1030 case Primitive::kPrimVoid:
1031 LOG(FATAL) << "Unreachable type " << field_type;
1032 }
1033}
1034
1035void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
1036 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1037 locations->SetInAt(0, Location::RequiresRegister());
1038 locations->SetOut(Location::RequiresRegister());
1039 instruction->SetLocations(locations);
1040}
1041
1042void InstructionCodeGeneratorARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
1043 LocationSummary* locations = instruction->GetLocations();
1044 Register obj = locations->InAt(0).AsArm().AsCoreRegister();
1045 uint32_t offset = instruction->GetFieldOffset().Uint32Value();
1046
1047 switch (instruction->GetType()) {
1048 case Primitive::kPrimBoolean: {
1049 Register out = locations->Out().AsArm().AsCoreRegister();
1050 __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset);
1051 break;
1052 }
1053
1054 case Primitive::kPrimByte: {
1055 Register out = locations->Out().AsArm().AsCoreRegister();
1056 __ LoadFromOffset(kLoadSignedByte, out, obj, offset);
1057 break;
1058 }
1059
1060 case Primitive::kPrimShort: {
1061 Register out = locations->Out().AsArm().AsCoreRegister();
1062 __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset);
1063 break;
1064 }
1065
1066 case Primitive::kPrimChar: {
1067 Register out = locations->Out().AsArm().AsCoreRegister();
1068 __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset);
1069 break;
1070 }
1071
1072 case Primitive::kPrimInt:
1073 case Primitive::kPrimNot: {
1074 Register out = locations->Out().AsArm().AsCoreRegister();
1075 __ LoadFromOffset(kLoadWord, out, obj, offset);
1076 break;
1077 }
1078
1079 case Primitive::kPrimLong: {
1080 // TODO: support volatile.
1081 ArmManagedRegister out = locations->Out().AsArm();
1082 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow(), obj, offset);
1083 break;
1084 }
1085
1086 case Primitive::kPrimFloat:
1087 case Primitive::kPrimDouble:
1088 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1089
1090 case Primitive::kPrimVoid:
1091 LOG(FATAL) << "Unreachable type " << instruction->GetType();
1092 }
1093}
1094
1095void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) {
1096 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1097 locations->SetInAt(0, Location::RequiresRegister());
1098 // TODO: Have a normalization phase that makes this instruction never used.
1099 locations->SetOut(Location::SameAsFirstInput());
1100 instruction->SetLocations(locations);
1101}
1102
1103void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) {
1104 SlowPathCode* slow_path =
1105 new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction->GetDexPc());
1106 codegen_->AddSlowPath(slow_path);
1107
1108 LocationSummary* locations = instruction->GetLocations();
1109 Location obj = locations->InAt(0);
1110 DCHECK(obj.Equals(locations->Out()));
1111
1112 if (obj.IsRegister()) {
1113 __ cmp(obj.AsArm().AsCoreRegister(), ShifterOperand(0));
1114 }
1115 __ b(slow_path->GetEntryLabel(), EQ);
1116}
1117
1118void LocationsBuilderARM::VisitTemporary(HTemporary* temp) {
1119 temp->SetLocations(nullptr);
1120}
1121
1122void InstructionCodeGeneratorARM::VisitTemporary(HTemporary* temp) {
1123 // Nothing to do, this is driven by the code generator.
1124}
1125
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01001126void LocationsBuilderARM::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001127 LOG(FATAL) << "Unreachable";
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01001128}
1129
1130void InstructionCodeGeneratorARM::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001131 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
1132}
1133
1134ArmAssembler* ParallelMoveResolverARM::GetAssembler() const {
1135 return codegen_->GetAssembler();
1136}
1137
1138void ParallelMoveResolverARM::EmitMove(size_t index) {
1139 MoveOperands* move = moves_.Get(index);
1140 Location source = move->GetSource();
1141 Location destination = move->GetDestination();
1142
1143 if (source.IsRegister()) {
1144 if (destination.IsRegister()) {
1145 __ Mov(destination.AsArm().AsCoreRegister(), source.AsArm().AsCoreRegister());
1146 } else {
1147 DCHECK(destination.IsStackSlot());
1148 __ StoreToOffset(kStoreWord, source.AsArm().AsCoreRegister(),
1149 SP, destination.GetStackIndex());
1150 }
1151 } else if (source.IsStackSlot()) {
1152 if (destination.IsRegister()) {
1153 __ LoadFromOffset(kLoadWord, destination.AsArm().AsCoreRegister(),
1154 SP, source.GetStackIndex());
1155 } else {
1156 DCHECK(destination.IsStackSlot());
1157 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
1158 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
1159 }
1160 } else {
1161 LOG(FATAL) << "Unimplemented";
1162 }
1163}
1164
1165void ParallelMoveResolverARM::Exchange(Register reg, int mem) {
1166 __ Mov(IP, reg);
1167 __ LoadFromOffset(kLoadWord, reg, SP, mem);
1168 __ StoreToOffset(kStoreWord, IP, SP, mem);
1169}
1170
1171void ParallelMoveResolverARM::Exchange(int mem1, int mem2) {
1172 ScratchRegisterScope ensure_scratch(this, IP, R0, codegen_->GetNumberOfCoreRegisters());
1173 int stack_offset = ensure_scratch.IsSpilled() ? kArmWordSize : 0;
1174 __ LoadFromOffset(kLoadWord, static_cast<Register>(ensure_scratch.GetRegister()),
1175 SP, mem1 + stack_offset);
1176 __ LoadFromOffset(kLoadWord, IP, SP, mem2 + stack_offset);
1177 __ StoreToOffset(kStoreWord, static_cast<Register>(ensure_scratch.GetRegister()),
1178 SP, mem2 + stack_offset);
1179 __ StoreToOffset(kStoreWord, IP, SP, mem1 + stack_offset);
1180}
1181
1182void ParallelMoveResolverARM::EmitSwap(size_t index) {
1183 MoveOperands* move = moves_.Get(index);
1184 Location source = move->GetSource();
1185 Location destination = move->GetDestination();
1186
1187 if (source.IsRegister() && destination.IsRegister()) {
1188 DCHECK_NE(source.AsArm().AsCoreRegister(), IP);
1189 DCHECK_NE(destination.AsArm().AsCoreRegister(), IP);
1190 __ Mov(IP, source.AsArm().AsCoreRegister());
1191 __ Mov(source.AsArm().AsCoreRegister(), destination.AsArm().AsCoreRegister());
1192 __ Mov(destination.AsArm().AsCoreRegister(), IP);
1193 } else if (source.IsRegister() && destination.IsStackSlot()) {
1194 Exchange(source.AsArm().AsCoreRegister(), destination.GetStackIndex());
1195 } else if (source.IsStackSlot() && destination.IsRegister()) {
1196 Exchange(destination.AsArm().AsCoreRegister(), source.GetStackIndex());
1197 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
1198 Exchange(source.GetStackIndex(), destination.GetStackIndex());
1199 } else {
1200 LOG(FATAL) << "Unimplemented";
1201 }
1202}
1203
1204void ParallelMoveResolverARM::SpillScratch(int reg) {
1205 __ Push(static_cast<Register>(reg));
1206}
1207
1208void ParallelMoveResolverARM::RestoreScratch(int reg) {
1209 __ Pop(static_cast<Register>(reg));
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01001210}
1211
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001212} // namespace arm
1213} // namespace art