blob: fe8a96fb8422338f9878395bfc568c2036a154f9 [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 Geoffray1a43dd72014-07-17 15:15:34 +010020#include "gc/accounting/card_table.h"
Ian Rogers7e70b002014-10-08 11:47:24 -070021#include "mirror/array-inl.h"
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +000022#include "mirror/art_method.h"
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +010023#include "mirror/class.h"
Ian Rogersb0fa5dc2014-04-28 16:47:08 -070024#include "thread.h"
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010025#include "utils/assembler.h"
26#include "utils/arm/assembler_arm.h"
27#include "utils/arm/managed_register_arm.h"
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010028#include "utils/stack_checks.h"
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +000029
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000030namespace art {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +010031
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000032namespace arm {
33
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +000034static DRegister FromLowSToD(SRegister reg) {
35 DCHECK_EQ(reg % 2, 0);
36 return static_cast<DRegister>(reg / 2);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +010037}
38
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010039static constexpr bool kExplicitStackOverflowCheck = false;
40
41static constexpr int kNumberOfPushedRegistersAtEntry = 1 + 2; // LR, R6, R7
42static constexpr int kCurrentMethodStackOffset = 0;
43
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010044static constexpr Register kRuntimeParameterCoreRegisters[] = { R0, R1, R2 };
45static constexpr size_t kRuntimeParameterCoreRegistersLength =
46 arraysize(kRuntimeParameterCoreRegisters);
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +000047static constexpr SRegister kRuntimeParameterFpuRegisters[] = { };
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +010048static constexpr size_t kRuntimeParameterFpuRegistersLength = 0;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010049
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +000050class InvokeRuntimeCallingConvention : public CallingConvention<Register, SRegister> {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010051 public:
52 InvokeRuntimeCallingConvention()
53 : CallingConvention(kRuntimeParameterCoreRegisters,
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +010054 kRuntimeParameterCoreRegistersLength,
55 kRuntimeParameterFpuRegisters,
56 kRuntimeParameterFpuRegistersLength) {}
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010057
58 private:
59 DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention);
60};
61
Nicolas Geoffraye5038322014-07-04 09:41:32 +010062#define __ reinterpret_cast<ArmAssembler*>(codegen->GetAssembler())->
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +010063#define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kArmWordSize, x).Int32Value()
Nicolas Geoffraye5038322014-07-04 09:41:32 +010064
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +010065class SlowPathCodeARM : public SlowPathCode {
66 public:
67 SlowPathCodeARM() : entry_label_(), exit_label_() {}
68
69 Label* GetEntryLabel() { return &entry_label_; }
70 Label* GetExitLabel() { return &exit_label_; }
71
72 private:
73 Label entry_label_;
74 Label exit_label_;
75
76 DISALLOW_COPY_AND_ASSIGN(SlowPathCodeARM);
77};
78
79class NullCheckSlowPathARM : public SlowPathCodeARM {
Nicolas Geoffraye5038322014-07-04 09:41:32 +010080 public:
Nicolas Geoffray39468442014-09-02 15:17:15 +010081 explicit NullCheckSlowPathARM(HNullCheck* instruction) : instruction_(instruction) {}
Nicolas Geoffraye5038322014-07-04 09:41:32 +010082
83 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +010084 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
Nicolas Geoffraye5038322014-07-04 09:41:32 +010085 __ Bind(GetEntryLabel());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +010086 arm_codegen->InvokeRuntime(
87 QUICK_ENTRY_POINT(pThrowNullPointer), instruction_, instruction_->GetDexPc());
Nicolas Geoffraye5038322014-07-04 09:41:32 +010088 }
89
90 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +010091 HNullCheck* const instruction_;
Nicolas Geoffraye5038322014-07-04 09:41:32 +010092 DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathARM);
93};
94
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +010095class StackOverflowCheckSlowPathARM : public SlowPathCodeARM {
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010096 public:
97 StackOverflowCheckSlowPathARM() {}
98
99 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
100 __ Bind(GetEntryLabel());
101 __ LoadFromOffset(kLoadWord, PC, TR,
102 QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pThrowStackOverflow).Int32Value());
103 }
104
105 private:
106 DISALLOW_COPY_AND_ASSIGN(StackOverflowCheckSlowPathARM);
107};
108
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100109class SuspendCheckSlowPathARM : public SlowPathCodeARM {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000110 public:
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100111 explicit SuspendCheckSlowPathARM(HSuspendCheck* instruction, HBasicBlock* successor)
112 : instruction_(instruction), successor_(successor) {}
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000113
114 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100115 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000116 __ Bind(GetEntryLabel());
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100117 codegen->SaveLiveRegisters(instruction_->GetLocations());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100118 arm_codegen->InvokeRuntime(
119 QUICK_ENTRY_POINT(pTestSuspend), instruction_, instruction_->GetDexPc());
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100120 codegen->RestoreLiveRegisters(instruction_->GetLocations());
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100121 if (successor_ == nullptr) {
122 __ b(GetReturnLabel());
123 } else {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100124 __ b(arm_codegen->GetLabelOf(successor_));
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100125 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000126 }
127
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100128 Label* GetReturnLabel() {
129 DCHECK(successor_ == nullptr);
130 return &return_label_;
131 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000132
133 private:
134 HSuspendCheck* const instruction_;
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100135 // If not null, the block to branch to after the suspend check.
136 HBasicBlock* const successor_;
137
138 // If `successor_` is null, the label to branch to after the suspend check.
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000139 Label return_label_;
140
141 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathARM);
142};
143
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100144class BoundsCheckSlowPathARM : public SlowPathCodeARM {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100145 public:
Roland Levillain5799fc02014-09-25 12:15:20 +0100146 BoundsCheckSlowPathARM(HBoundsCheck* instruction,
147 Location index_location,
148 Location length_location)
Nicolas Geoffray39468442014-09-02 15:17:15 +0100149 : instruction_(instruction),
150 index_location_(index_location),
151 length_location_(length_location) {}
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100152
153 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100154 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100155 __ Bind(GetEntryLabel());
156 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100157 arm_codegen->Move32(
158 Location::RegisterLocation(calling_convention.GetRegisterAt(0)), index_location_);
159 arm_codegen->Move32(
160 Location::RegisterLocation(calling_convention.GetRegisterAt(1)), length_location_);
161 arm_codegen->InvokeRuntime(
162 QUICK_ENTRY_POINT(pThrowArrayBounds), instruction_, instruction_->GetDexPc());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100163 }
164
165 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100166 HBoundsCheck* const instruction_;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100167 const Location index_location_;
168 const Location length_location_;
169
170 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathARM);
171};
172
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000173class LoadClassSlowPathARM : public SlowPathCodeARM {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100174 public:
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000175 LoadClassSlowPathARM(HLoadClass* cls,
176 HInstruction* at,
177 uint32_t dex_pc,
178 bool do_clinit)
179 : cls_(cls), at_(at), dex_pc_(dex_pc), do_clinit_(do_clinit) {
180 DCHECK(at->IsLoadClass() || at->IsClinitCheck());
181 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100182
183 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000184 LocationSummary* locations = at_->GetLocations();
185
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100186 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
187 __ Bind(GetEntryLabel());
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000188 codegen->SaveLiveRegisters(locations);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100189
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100190 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000191 __ LoadImmediate(calling_convention.GetRegisterAt(0), cls_->GetTypeIndex());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100192 arm_codegen->LoadCurrentMethod(calling_convention.GetRegisterAt(1));
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000193 int32_t entry_point_offset = do_clinit_
194 ? QUICK_ENTRY_POINT(pInitializeStaticStorage)
195 : QUICK_ENTRY_POINT(pInitializeType);
196 arm_codegen->InvokeRuntime(entry_point_offset, at_, dex_pc_);
197
198 // Move the class to the desired location.
199 if (locations->Out().IsValid()) {
200 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
201 arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0));
202 }
203 codegen->RestoreLiveRegisters(locations);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100204 __ b(GetExitLabel());
205 }
206
207 private:
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000208 // The class this slow path will load.
209 HLoadClass* const cls_;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100210
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000211 // The instruction where this slow path is happening.
212 // (Might be the load class or an initialization check).
213 HInstruction* const at_;
214
215 // The dex PC of `at_`.
216 const uint32_t dex_pc_;
217
218 // Whether to initialize the class.
219 const bool do_clinit_;
220
221 DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathARM);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100222};
223
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000224class LoadStringSlowPathARM : public SlowPathCodeARM {
225 public:
226 explicit LoadStringSlowPathARM(HLoadString* instruction) : instruction_(instruction) {}
227
228 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
229 LocationSummary* locations = instruction_->GetLocations();
230 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
231
232 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
233 __ Bind(GetEntryLabel());
234 codegen->SaveLiveRegisters(locations);
235
236 InvokeRuntimeCallingConvention calling_convention;
237 arm_codegen->LoadCurrentMethod(calling_convention.GetRegisterAt(0));
238 __ LoadImmediate(calling_convention.GetRegisterAt(1), instruction_->GetStringIndex());
239 arm_codegen->InvokeRuntime(
240 QUICK_ENTRY_POINT(pResolveString), instruction_, instruction_->GetDexPc());
241 arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0));
242
243 codegen->RestoreLiveRegisters(locations);
244 __ b(GetExitLabel());
245 }
246
247 private:
248 HLoadString* const instruction_;
249
250 DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathARM);
251};
252
253#undef __
254
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100255#undef __
256#define __ reinterpret_cast<ArmAssembler*>(GetAssembler())->
Dave Allison20dfc792014-06-16 20:44:29 -0700257
258inline Condition ARMCondition(IfCondition cond) {
259 switch (cond) {
260 case kCondEQ: return EQ;
261 case kCondNE: return NE;
262 case kCondLT: return LT;
263 case kCondLE: return LE;
264 case kCondGT: return GT;
265 case kCondGE: return GE;
266 default:
267 LOG(FATAL) << "Unknown if condition";
268 }
269 return EQ; // Unreachable.
270}
271
272inline Condition ARMOppositeCondition(IfCondition cond) {
273 switch (cond) {
274 case kCondEQ: return NE;
275 case kCondNE: return EQ;
276 case kCondLT: return GE;
277 case kCondLE: return GT;
278 case kCondGT: return LE;
279 case kCondGE: return LT;
280 default:
281 LOG(FATAL) << "Unknown if condition";
282 }
283 return EQ; // Unreachable.
284}
285
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100286void CodeGeneratorARM::DumpCoreRegister(std::ostream& stream, int reg) const {
287 stream << ArmManagedRegister::FromCoreRegister(Register(reg));
288}
289
290void CodeGeneratorARM::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000291 stream << ArmManagedRegister::FromSRegister(SRegister(reg));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100292}
293
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100294size_t CodeGeneratorARM::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
295 __ StoreToOffset(kStoreWord, static_cast<Register>(reg_id), SP, stack_index);
296 return kArmWordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100297}
298
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100299size_t CodeGeneratorARM::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
300 __ LoadFromOffset(kLoadWord, static_cast<Register>(reg_id), SP, stack_index);
301 return kArmWordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100302}
303
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100304CodeGeneratorARM::CodeGeneratorARM(HGraph* graph)
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000305 : CodeGenerator(graph, kNumberOfCoreRegisters, kNumberOfSRegisters, kNumberOfRegisterPairs),
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100306 block_labels_(graph->GetArena(), 0),
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100307 location_builder_(graph, this),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100308 instruction_visitor_(graph, this),
Nicolas Geoffray8d486732014-07-16 16:23:40 +0100309 move_resolver_(graph->GetArena(), this),
310 assembler_(true) {}
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100311
Nicolas Geoffrayab032bc2014-07-15 12:55:21 +0100312size_t CodeGeneratorARM::FrameEntrySpillSize() const {
313 return kNumberOfPushedRegistersAtEntry * kArmWordSize;
314}
315
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100316Location CodeGeneratorARM::AllocateFreeRegister(Primitive::Type type) const {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100317 switch (type) {
318 case Primitive::kPrimLong: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100319 size_t reg = FindFreeEntry(blocked_register_pairs_, kNumberOfRegisterPairs);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100320 ArmManagedRegister pair =
321 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(reg));
Calin Juravle34bacdf2014-10-07 20:23:36 +0100322 DCHECK(!blocked_core_registers_[pair.AsRegisterPairLow()]);
323 DCHECK(!blocked_core_registers_[pair.AsRegisterPairHigh()]);
324
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100325 blocked_core_registers_[pair.AsRegisterPairLow()] = true;
326 blocked_core_registers_[pair.AsRegisterPairHigh()] = true;
Calin Juravle34bacdf2014-10-07 20:23:36 +0100327 UpdateBlockedPairRegisters();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100328 return Location::RegisterPairLocation(pair.AsRegisterPairLow(), pair.AsRegisterPairHigh());
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100329 }
330
331 case Primitive::kPrimByte:
332 case Primitive::kPrimBoolean:
333 case Primitive::kPrimChar:
334 case Primitive::kPrimShort:
335 case Primitive::kPrimInt:
336 case Primitive::kPrimNot: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100337 int reg = FindFreeEntry(blocked_core_registers_, kNumberOfCoreRegisters);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100338 // Block all register pairs that contain `reg`.
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100339 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
340 ArmManagedRegister current =
341 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
342 if (current.AsRegisterPairLow() == reg || current.AsRegisterPairHigh() == reg) {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100343 blocked_register_pairs_[i] = true;
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100344 }
345 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100346 return Location::RegisterLocation(reg);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100347 }
348
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000349 case Primitive::kPrimFloat: {
350 int reg = FindFreeEntry(blocked_fpu_registers_, kNumberOfSRegisters);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100351 return Location::FpuRegisterLocation(reg);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100352 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100353
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000354 case Primitive::kPrimDouble: {
Nicolas Geoffray3c035032014-10-28 10:46:40 +0000355 int reg = FindTwoFreeConsecutiveAlignedEntries(blocked_fpu_registers_, kNumberOfSRegisters);
356 DCHECK_EQ(reg % 2, 0);
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000357 return Location::FpuRegisterPairLocation(reg, reg + 1);
358 }
359
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100360 case Primitive::kPrimVoid:
361 LOG(FATAL) << "Unreachable type " << type;
362 }
363
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100364 return Location();
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100365}
366
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100367void CodeGeneratorARM::SetupBlockedRegisters() const {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100368 // Don't allocate the dalvik style register pair passing.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100369 blocked_register_pairs_[R1_R2] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100370
371 // Stack register, LR and PC are always reserved.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100372 blocked_core_registers_[SP] = true;
373 blocked_core_registers_[LR] = true;
374 blocked_core_registers_[PC] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100375
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100376 // Reserve thread register.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100377 blocked_core_registers_[TR] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100378
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100379 // Reserve temp register.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100380 blocked_core_registers_[IP] = true;
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100381
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100382 // TODO: We currently don't use Quick's callee saved registers.
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100383 // We always save and restore R6 and R7 to make sure we can use three
384 // register pairs for long operations.
Nicolas Geoffray44b819e2014-11-06 12:00:54 +0000385 blocked_core_registers_[R4] = true;
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100386 blocked_core_registers_[R5] = true;
387 blocked_core_registers_[R8] = true;
388 blocked_core_registers_[R10] = true;
389 blocked_core_registers_[R11] = true;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100390
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000391 blocked_fpu_registers_[S16] = true;
392 blocked_fpu_registers_[S17] = true;
393 blocked_fpu_registers_[S18] = true;
394 blocked_fpu_registers_[S19] = true;
395 blocked_fpu_registers_[S20] = true;
396 blocked_fpu_registers_[S21] = true;
397 blocked_fpu_registers_[S22] = true;
398 blocked_fpu_registers_[S23] = true;
Nicolas Geoffray3c035032014-10-28 10:46:40 +0000399 blocked_fpu_registers_[S24] = true;
400 blocked_fpu_registers_[S25] = true;
401 blocked_fpu_registers_[S26] = true;
402 blocked_fpu_registers_[S27] = true;
403 blocked_fpu_registers_[S28] = true;
404 blocked_fpu_registers_[S29] = true;
405 blocked_fpu_registers_[S30] = true;
406 blocked_fpu_registers_[S31] = true;
Calin Juravle34bacdf2014-10-07 20:23:36 +0100407
408 UpdateBlockedPairRegisters();
409}
410
411void CodeGeneratorARM::UpdateBlockedPairRegisters() const {
412 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
413 ArmManagedRegister current =
414 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
415 if (blocked_core_registers_[current.AsRegisterPairLow()]
416 || blocked_core_registers_[current.AsRegisterPairHigh()]) {
417 blocked_register_pairs_[i] = true;
418 }
419 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100420}
421
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100422InstructionCodeGeneratorARM::InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen)
423 : HGraphVisitor(graph),
424 assembler_(codegen->GetAssembler()),
425 codegen_(codegen) {}
426
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000427void CodeGeneratorARM::GenerateFrameEntry() {
Dave Allison648d7112014-07-25 16:15:27 -0700428 bool skip_overflow_check = IsLeafMethod() && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kArm);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100429 if (!skip_overflow_check) {
430 if (kExplicitStackOverflowCheck) {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100431 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) StackOverflowCheckSlowPathARM();
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100432 AddSlowPath(slow_path);
433
434 __ LoadFromOffset(kLoadWord, IP, TR, Thread::StackEndOffset<kArmWordSize>().Int32Value());
435 __ cmp(SP, ShifterOperand(IP));
436 __ b(slow_path->GetEntryLabel(), CC);
437 } else {
438 __ AddConstant(IP, SP, -static_cast<int32_t>(GetStackOverflowReservedBytes(kArm)));
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100439 __ LoadFromOffset(kLoadWord, IP, IP, 0);
Nicolas Geoffray39468442014-09-02 15:17:15 +0100440 RecordPcInfo(nullptr, 0);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100441 }
442 }
443
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100444 core_spill_mask_ |= (1 << LR | 1 << R6 | 1 << R7);
445 __ PushList(1 << LR | 1 << R6 | 1 << R7);
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000446
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100447 // The return PC has already been pushed on the stack.
Nicolas Geoffray707c8092014-04-04 10:50:14 +0100448 __ AddConstant(SP, -(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kArmWordSize));
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100449 __ StoreToOffset(kStoreWord, R0, SP, 0);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000450}
451
452void CodeGeneratorARM::GenerateFrameExit() {
Nicolas Geoffray707c8092014-04-04 10:50:14 +0100453 __ AddConstant(SP, GetFrameSize() - kNumberOfPushedRegistersAtEntry * kArmWordSize);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100454 __ PopList(1 << PC | 1 << R6 | 1 << R7);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000455}
456
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100457void CodeGeneratorARM::Bind(HBasicBlock* block) {
458 __ Bind(GetLabelOf(block));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000459}
460
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100461Location CodeGeneratorARM::GetStackLocation(HLoadLocal* load) const {
462 switch (load->GetType()) {
463 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100464 case Primitive::kPrimDouble:
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100465 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
466 break;
467
468 case Primitive::kPrimInt:
469 case Primitive::kPrimNot:
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100470 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100471 return Location::StackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100472
473 case Primitive::kPrimBoolean:
474 case Primitive::kPrimByte:
475 case Primitive::kPrimChar:
476 case Primitive::kPrimShort:
477 case Primitive::kPrimVoid:
478 LOG(FATAL) << "Unexpected type " << load->GetType();
479 }
480
481 LOG(FATAL) << "Unreachable";
482 return Location();
483}
484
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100485Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) {
486 switch (type) {
487 case Primitive::kPrimBoolean:
488 case Primitive::kPrimByte:
489 case Primitive::kPrimChar:
490 case Primitive::kPrimShort:
491 case Primitive::kPrimInt:
492 case Primitive::kPrimNot: {
493 uint32_t index = gp_index_++;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000494 uint32_t stack_index = stack_index_++;
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100495 if (index < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100496 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100497 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000498 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100499 }
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100500 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100501
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000502 case Primitive::kPrimLong: {
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100503 uint32_t index = gp_index_;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000504 uint32_t stack_index = stack_index_;
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100505 gp_index_ += 2;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000506 stack_index_ += 2;
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100507 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100508 ArmManagedRegister pair = ArmManagedRegister::FromRegisterPair(
509 calling_convention.GetRegisterPairAt(index));
510 return Location::RegisterPairLocation(pair.AsRegisterPairLow(), pair.AsRegisterPairHigh());
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100511 } else if (index + 1 == calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray0a6c4592014-10-30 16:37:57 +0000512 return Location::QuickParameter(index, stack_index);
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100513 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000514 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index));
515 }
516 }
517
518 case Primitive::kPrimFloat: {
519 uint32_t stack_index = stack_index_++;
520 if (float_index_ % 2 == 0) {
521 float_index_ = std::max(double_index_, float_index_);
522 }
523 if (float_index_ < calling_convention.GetNumberOfFpuRegisters()) {
524 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(float_index_++));
525 } else {
526 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index));
527 }
528 }
529
530 case Primitive::kPrimDouble: {
531 double_index_ = std::max(double_index_, RoundUp(float_index_, 2));
532 uint32_t stack_index = stack_index_;
533 stack_index_ += 2;
534 if (double_index_ + 1 < calling_convention.GetNumberOfFpuRegisters()) {
535 uint32_t index = double_index_;
536 double_index_ += 2;
537 return Location::FpuRegisterPairLocation(
538 calling_convention.GetFpuRegisterAt(index),
539 calling_convention.GetFpuRegisterAt(index + 1));
540 } else {
541 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100542 }
543 }
544
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100545 case Primitive::kPrimVoid:
546 LOG(FATAL) << "Unexpected parameter type " << type;
547 break;
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100548 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100549 return Location();
550}
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100551
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000552Location InvokeDexCallingConventionVisitor::GetReturnLocation(Primitive::Type type) {
553 switch (type) {
554 case Primitive::kPrimBoolean:
555 case Primitive::kPrimByte:
556 case Primitive::kPrimChar:
557 case Primitive::kPrimShort:
558 case Primitive::kPrimInt:
559 case Primitive::kPrimNot: {
560 return Location::RegisterLocation(R0);
561 }
562
563 case Primitive::kPrimFloat: {
564 return Location::FpuRegisterLocation(S0);
565 }
566
567 case Primitive::kPrimLong: {
568 return Location::RegisterPairLocation(R0, R1);
569 }
570
571 case Primitive::kPrimDouble: {
572 return Location::FpuRegisterPairLocation(S0, S1);
573 }
574
575 case Primitive::kPrimVoid:
576 return Location();
577 }
578 UNREACHABLE();
579 return Location();
580}
581
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100582void CodeGeneratorARM::Move32(Location destination, Location source) {
583 if (source.Equals(destination)) {
584 return;
585 }
586 if (destination.IsRegister()) {
587 if (source.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100588 __ Mov(destination.As<Register>(), source.As<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100589 } else if (source.IsFpuRegister()) {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000590 __ vmovrs(destination.As<Register>(), source.As<SRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100591 } else {
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100592 __ LoadFromOffset(kLoadWord, destination.As<Register>(), SP, source.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100593 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100594 } else if (destination.IsFpuRegister()) {
595 if (source.IsRegister()) {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000596 __ vmovsr(destination.As<SRegister>(), source.As<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100597 } else if (source.IsFpuRegister()) {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000598 __ vmovs(destination.As<SRegister>(), source.As<SRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100599 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000600 __ LoadSFromOffset(destination.As<SRegister>(), SP, source.GetStackIndex());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100601 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100602 } else {
603 DCHECK(destination.IsStackSlot());
604 if (source.IsRegister()) {
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100605 __ StoreToOffset(kStoreWord, source.As<Register>(), SP, destination.GetStackIndex());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100606 } else if (source.IsFpuRegister()) {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000607 __ StoreSToOffset(source.As<SRegister>(), SP, destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100608 } else {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100609 DCHECK(source.IsStackSlot());
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100610 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
611 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100612 }
613 }
614}
615
616void CodeGeneratorARM::Move64(Location destination, Location source) {
617 if (source.Equals(destination)) {
618 return;
619 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100620 if (destination.IsRegisterPair()) {
621 if (source.IsRegisterPair()) {
622 __ Mov(destination.AsRegisterPairLow<Register>(), source.AsRegisterPairLow<Register>());
623 __ Mov(destination.AsRegisterPairHigh<Register>(), source.AsRegisterPairHigh<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100624 } else if (source.IsFpuRegister()) {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000625 UNIMPLEMENTED(FATAL);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100626 } else if (source.IsQuickParameter()) {
Nicolas Geoffray0a6c4592014-10-30 16:37:57 +0000627 uint16_t register_index = source.GetQuickParameterRegisterIndex();
628 uint16_t stack_index = source.GetQuickParameterStackIndex();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100629 InvokeDexCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100630 __ Mov(destination.AsRegisterPairLow<Register>(),
Nicolas Geoffray0a6c4592014-10-30 16:37:57 +0000631 calling_convention.GetRegisterAt(register_index));
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100632 __ LoadFromOffset(kLoadWord, destination.AsRegisterPairHigh<Register>(),
Nicolas Geoffray0a6c4592014-10-30 16:37:57 +0000633 SP, calling_convention.GetStackOffsetOf(stack_index + 1) + GetFrameSize());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100634 } else {
635 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100636 if (destination.AsRegisterPairLow<Register>() == R1) {
637 DCHECK_EQ(destination.AsRegisterPairHigh<Register>(), R2);
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100638 __ LoadFromOffset(kLoadWord, R1, SP, source.GetStackIndex());
639 __ LoadFromOffset(kLoadWord, R2, SP, source.GetHighStackIndex(kArmWordSize));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100640 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100641 __ LoadFromOffset(kLoadWordPair, destination.AsRegisterPairLow<Register>(),
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100642 SP, source.GetStackIndex());
643 }
644 }
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000645 } else if (destination.IsFpuRegisterPair()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100646 if (source.IsDoubleStackSlot()) {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000647 __ LoadDFromOffset(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
648 SP,
649 source.GetStackIndex());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100650 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000651 UNIMPLEMENTED(FATAL);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100652 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100653 } else if (destination.IsQuickParameter()) {
654 InvokeDexCallingConvention calling_convention;
Nicolas Geoffray0a6c4592014-10-30 16:37:57 +0000655 uint16_t register_index = destination.GetQuickParameterRegisterIndex();
656 uint16_t stack_index = destination.GetQuickParameterStackIndex();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100657 if (source.IsRegisterPair()) {
Nicolas Geoffray0a6c4592014-10-30 16:37:57 +0000658 __ Mov(calling_convention.GetRegisterAt(register_index),
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100659 source.AsRegisterPairLow<Register>());
660 __ StoreToOffset(kStoreWord, source.AsRegisterPairHigh<Register>(),
Nicolas Geoffray0a6c4592014-10-30 16:37:57 +0000661 SP, calling_convention.GetStackOffsetOf(stack_index + 1));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100662 } else if (source.IsFpuRegister()) {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000663 UNIMPLEMENTED(FATAL);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100664 } else {
665 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000666 __ LoadFromOffset(
Nicolas Geoffray0a6c4592014-10-30 16:37:57 +0000667 kLoadWord, calling_convention.GetRegisterAt(register_index), SP, source.GetStackIndex());
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100668 __ LoadFromOffset(kLoadWord, R0, SP, source.GetHighStackIndex(kArmWordSize));
Nicolas Geoffray0a6c4592014-10-30 16:37:57 +0000669 __ StoreToOffset(kStoreWord, R0, SP, calling_convention.GetStackOffsetOf(stack_index + 1));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100670 }
671 } else {
672 DCHECK(destination.IsDoubleStackSlot());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100673 if (source.IsRegisterPair()) {
674 if (source.AsRegisterPairLow<Register>() == R1) {
675 DCHECK_EQ(source.AsRegisterPairHigh<Register>(), R2);
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100676 __ StoreToOffset(kStoreWord, R1, SP, destination.GetStackIndex());
677 __ StoreToOffset(kStoreWord, R2, SP, destination.GetHighStackIndex(kArmWordSize));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100678 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100679 __ StoreToOffset(kStoreWordPair, source.AsRegisterPairLow<Register>(),
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100680 SP, destination.GetStackIndex());
681 }
682 } else if (source.IsQuickParameter()) {
683 InvokeDexCallingConvention calling_convention;
Nicolas Geoffray0a6c4592014-10-30 16:37:57 +0000684 uint16_t register_index = source.GetQuickParameterRegisterIndex();
685 uint16_t stack_index = source.GetQuickParameterStackIndex();
686 __ StoreToOffset(kStoreWord, calling_convention.GetRegisterAt(register_index),
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100687 SP, destination.GetStackIndex());
688 __ LoadFromOffset(kLoadWord, R0,
Nicolas Geoffray0a6c4592014-10-30 16:37:57 +0000689 SP, calling_convention.GetStackOffsetOf(stack_index + 1) + GetFrameSize());
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100690 __ StoreToOffset(kStoreWord, R0, SP, destination.GetHighStackIndex(kArmWordSize));
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000691 } else if (source.IsFpuRegisterPair()) {
692 __ StoreDToOffset(FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()),
693 SP,
694 destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100695 } else {
696 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100697 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
698 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
699 __ LoadFromOffset(kLoadWord, IP, SP, source.GetHighStackIndex(kArmWordSize));
700 __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100701 }
702 }
703}
704
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100705void CodeGeneratorARM::Move(HInstruction* instruction, Location location, HInstruction* move_for) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100706 LocationSummary* locations = instruction->GetLocations();
707 if (locations != nullptr && locations->Out().Equals(location)) {
708 return;
709 }
710
Roland Levillain476df552014-10-09 17:51:36 +0100711 if (instruction->IsIntConstant()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100712 int32_t value = instruction->AsIntConstant()->GetValue();
713 if (location.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100714 __ LoadImmediate(location.As<Register>(), value);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100715 } else {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100716 DCHECK(location.IsStackSlot());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100717 __ LoadImmediate(IP, value);
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100718 __ StoreToOffset(kStoreWord, IP, SP, location.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100719 }
Roland Levillain476df552014-10-09 17:51:36 +0100720 } else if (instruction->IsLongConstant()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100721 int64_t value = instruction->AsLongConstant()->GetValue();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100722 if (location.IsRegisterPair()) {
723 __ LoadImmediate(location.AsRegisterPairLow<Register>(), Low32Bits(value));
724 __ LoadImmediate(location.AsRegisterPairHigh<Register>(), High32Bits(value));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100725 } else {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100726 DCHECK(location.IsDoubleStackSlot());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100727 __ LoadImmediate(IP, Low32Bits(value));
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100728 __ StoreToOffset(kStoreWord, IP, SP, location.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100729 __ LoadImmediate(IP, High32Bits(value));
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100730 __ StoreToOffset(kStoreWord, IP, SP, location.GetHighStackIndex(kArmWordSize));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100731 }
Roland Levillain476df552014-10-09 17:51:36 +0100732 } else if (instruction->IsLoadLocal()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100733 uint32_t stack_slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
734 switch (instruction->GetType()) {
735 case Primitive::kPrimBoolean:
736 case Primitive::kPrimByte:
737 case Primitive::kPrimChar:
738 case Primitive::kPrimShort:
739 case Primitive::kPrimInt:
740 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100741 case Primitive::kPrimFloat:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100742 Move32(location, Location::StackSlot(stack_slot));
743 break;
744
745 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100746 case Primitive::kPrimDouble:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100747 Move64(location, Location::DoubleStackSlot(stack_slot));
748 break;
749
750 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100751 LOG(FATAL) << "Unexpected type " << instruction->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100752 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000753 } else {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100754 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100755 switch (instruction->GetType()) {
756 case Primitive::kPrimBoolean:
757 case Primitive::kPrimByte:
758 case Primitive::kPrimChar:
759 case Primitive::kPrimShort:
760 case Primitive::kPrimNot:
761 case Primitive::kPrimInt:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100762 case Primitive::kPrimFloat:
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100763 Move32(location, locations->Out());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100764 break;
765
766 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100767 case Primitive::kPrimDouble:
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100768 Move64(location, locations->Out());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100769 break;
770
771 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100772 LOG(FATAL) << "Unexpected type " << instruction->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100773 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000774 }
775}
776
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100777void CodeGeneratorARM::InvokeRuntime(int32_t entry_point_offset,
778 HInstruction* instruction,
779 uint32_t dex_pc) {
780 __ LoadFromOffset(kLoadWord, LR, TR, entry_point_offset);
781 __ blx(LR);
782 RecordPcInfo(instruction, dex_pc);
783 DCHECK(instruction->IsSuspendCheck()
784 || instruction->IsBoundsCheck()
785 || instruction->IsNullCheck()
786 || !IsLeafMethod());
787}
788
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000789void LocationsBuilderARM::VisitGoto(HGoto* got) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000790 got->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000791}
792
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000793void InstructionCodeGeneratorARM::VisitGoto(HGoto* got) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000794 HBasicBlock* successor = got->GetSuccessor();
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100795 DCHECK(!successor->IsExitBlock());
796
797 HBasicBlock* block = got->GetBlock();
798 HInstruction* previous = got->GetPrevious();
799
800 HLoopInformation* info = block->GetLoopInformation();
801 if (info != nullptr && info->IsBackEdge(block) && info->HasSuspendCheck()) {
802 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck());
803 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
804 return;
805 }
806
807 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
808 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
809 }
810 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000811 __ b(codegen_->GetLabelOf(successor));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000812 }
813}
814
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000815void LocationsBuilderARM::VisitExit(HExit* exit) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000816 exit->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000817}
818
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000819void InstructionCodeGeneratorARM::VisitExit(HExit* exit) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700820 UNUSED(exit);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000821 if (kIsDebugBuild) {
822 __ Comment("Unreachable");
823 __ bkpt(0);
824 }
825}
826
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000827void LocationsBuilderARM::VisitIf(HIf* if_instr) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100828 LocationSummary* locations =
829 new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100830 HInstruction* cond = if_instr->InputAt(0);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100831 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +0100832 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100833 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000834}
835
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000836void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) {
Dave Allison20dfc792014-06-16 20:44:29 -0700837 HInstruction* cond = if_instr->InputAt(0);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100838 if (cond->IsIntConstant()) {
839 // Constant condition, statically compared against 1.
840 int32_t cond_value = cond->AsIntConstant()->GetValue();
841 if (cond_value == 1) {
842 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(),
843 if_instr->IfTrueSuccessor())) {
844 __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100845 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100846 return;
847 } else {
848 DCHECK_EQ(cond_value, 0);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100849 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100850 } else {
851 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
852 // Condition has been materialized, compare the output to 0
853 DCHECK(if_instr->GetLocations()->InAt(0).IsRegister());
854 __ cmp(if_instr->GetLocations()->InAt(0).As<Register>(),
855 ShifterOperand(0));
856 __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()), NE);
857 } else {
858 // Condition has not been materialized, use its inputs as the
859 // comparison and its condition as the branch condition.
860 LocationSummary* locations = cond->GetLocations();
861 if (locations->InAt(1).IsRegister()) {
862 __ cmp(locations->InAt(0).As<Register>(),
863 ShifterOperand(locations->InAt(1).As<Register>()));
864 } else {
865 DCHECK(locations->InAt(1).IsConstant());
866 int32_t value =
867 locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
868 ShifterOperand operand;
869 if (ShifterOperand::CanHoldArm(value, &operand)) {
870 __ cmp(locations->InAt(0).As<Register>(), ShifterOperand(value));
871 } else {
872 Register temp = IP;
873 __ LoadImmediate(temp, value);
874 __ cmp(locations->InAt(0).As<Register>(), ShifterOperand(temp));
875 }
876 }
877 __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()),
878 ARMCondition(cond->AsCondition()->GetCondition()));
879 }
Dave Allison20dfc792014-06-16 20:44:29 -0700880 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100881 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(),
882 if_instr->IfFalseSuccessor())) {
Dave Allison20dfc792014-06-16 20:44:29 -0700883 __ b(codegen_->GetLabelOf(if_instr->IfFalseSuccessor()));
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000884 }
885}
886
Dave Allison20dfc792014-06-16 20:44:29 -0700887
888void LocationsBuilderARM::VisitCondition(HCondition* comp) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100889 LocationSummary* locations =
890 new (GetGraph()->GetArena()) LocationSummary(comp, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +0100891 locations->SetInAt(0, Location::RequiresRegister());
892 locations->SetInAt(1, Location::RegisterOrConstant(comp->InputAt(1)));
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100893 if (comp->NeedsMaterialization()) {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +0100894 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100895 }
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000896}
897
Dave Allison20dfc792014-06-16 20:44:29 -0700898void InstructionCodeGeneratorARM::VisitCondition(HCondition* comp) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100899 if (!comp->NeedsMaterialization()) return;
900
901 LocationSummary* locations = comp->GetLocations();
902 if (locations->InAt(1).IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100903 __ cmp(locations->InAt(0).As<Register>(),
904 ShifterOperand(locations->InAt(1).As<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100905 } else {
906 DCHECK(locations->InAt(1).IsConstant());
907 int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
908 ShifterOperand operand;
909 if (ShifterOperand::CanHoldArm(value, &operand)) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100910 __ cmp(locations->InAt(0).As<Register>(), ShifterOperand(value));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100911 } else {
912 Register temp = IP;
913 __ LoadImmediate(temp, value);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100914 __ cmp(locations->InAt(0).As<Register>(), ShifterOperand(temp));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100915 }
Dave Allison20dfc792014-06-16 20:44:29 -0700916 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100917 __ it(ARMCondition(comp->GetCondition()), kItElse);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100918 __ mov(locations->Out().As<Register>(), ShifterOperand(1),
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100919 ARMCondition(comp->GetCondition()));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100920 __ mov(locations->Out().As<Register>(), ShifterOperand(0),
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100921 ARMOppositeCondition(comp->GetCondition()));
Dave Allison20dfc792014-06-16 20:44:29 -0700922}
923
924void LocationsBuilderARM::VisitEqual(HEqual* comp) {
925 VisitCondition(comp);
926}
927
928void InstructionCodeGeneratorARM::VisitEqual(HEqual* comp) {
929 VisitCondition(comp);
930}
931
932void LocationsBuilderARM::VisitNotEqual(HNotEqual* comp) {
933 VisitCondition(comp);
934}
935
936void InstructionCodeGeneratorARM::VisitNotEqual(HNotEqual* comp) {
937 VisitCondition(comp);
938}
939
940void LocationsBuilderARM::VisitLessThan(HLessThan* comp) {
941 VisitCondition(comp);
942}
943
944void InstructionCodeGeneratorARM::VisitLessThan(HLessThan* comp) {
945 VisitCondition(comp);
946}
947
948void LocationsBuilderARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
949 VisitCondition(comp);
950}
951
952void InstructionCodeGeneratorARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
953 VisitCondition(comp);
954}
955
956void LocationsBuilderARM::VisitGreaterThan(HGreaterThan* comp) {
957 VisitCondition(comp);
958}
959
960void InstructionCodeGeneratorARM::VisitGreaterThan(HGreaterThan* comp) {
961 VisitCondition(comp);
962}
963
964void LocationsBuilderARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
965 VisitCondition(comp);
966}
967
968void InstructionCodeGeneratorARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
969 VisitCondition(comp);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000970}
971
972void LocationsBuilderARM::VisitLocal(HLocal* local) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000973 local->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000974}
975
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000976void InstructionCodeGeneratorARM::VisitLocal(HLocal* local) {
977 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000978}
979
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000980void LocationsBuilderARM::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100981 load->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000982}
983
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000984void InstructionCodeGeneratorARM::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100985 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700986 UNUSED(load);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000987}
988
989void LocationsBuilderARM::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100990 LocationSummary* locations =
991 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100992 switch (store->InputAt(1)->GetType()) {
993 case Primitive::kPrimBoolean:
994 case Primitive::kPrimByte:
995 case Primitive::kPrimChar:
996 case Primitive::kPrimShort:
997 case Primitive::kPrimInt:
998 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100999 case Primitive::kPrimFloat:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001000 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
1001 break;
1002
1003 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001004 case Primitive::kPrimDouble:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001005 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
1006 break;
1007
1008 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001009 LOG(FATAL) << "Unexpected local type " << store->InputAt(1)->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001010 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001011}
1012
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001013void InstructionCodeGeneratorARM::VisitStoreLocal(HStoreLocal* store) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001014 UNUSED(store);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001015}
1016
1017void LocationsBuilderARM::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001018 LocationSummary* locations =
1019 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001020 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001021}
1022
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001023void InstructionCodeGeneratorARM::VisitIntConstant(HIntConstant* constant) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001024 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001025 UNUSED(constant);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001026}
1027
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001028void LocationsBuilderARM::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001029 LocationSummary* locations =
1030 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001031 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001032}
1033
1034void InstructionCodeGeneratorARM::VisitLongConstant(HLongConstant* constant) {
1035 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001036 UNUSED(constant);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001037}
1038
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001039void LocationsBuilderARM::VisitFloatConstant(HFloatConstant* constant) {
1040 LocationSummary* locations =
1041 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1042 locations->SetOut(Location::ConstantLocation(constant));
1043}
1044
1045void InstructionCodeGeneratorARM::VisitFloatConstant(HFloatConstant* constant) {
1046 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001047 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001048}
1049
1050void LocationsBuilderARM::VisitDoubleConstant(HDoubleConstant* constant) {
1051 LocationSummary* locations =
1052 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1053 locations->SetOut(Location::ConstantLocation(constant));
1054}
1055
1056void InstructionCodeGeneratorARM::VisitDoubleConstant(HDoubleConstant* constant) {
1057 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001058 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001059}
1060
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001061void LocationsBuilderARM::VisitReturnVoid(HReturnVoid* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001062 ret->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001063}
1064
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001065void InstructionCodeGeneratorARM::VisitReturnVoid(HReturnVoid* ret) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001066 UNUSED(ret);
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001067 codegen_->GenerateFrameExit();
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001068}
1069
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001070void LocationsBuilderARM::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001071 LocationSummary* locations =
1072 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001073 locations->SetInAt(0, parameter_visitor_.GetReturnLocation(ret->InputAt(0)->GetType()));
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001074}
1075
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001076void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001077 UNUSED(ret);
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001078 codegen_->GenerateFrameExit();
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001079}
1080
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001081void LocationsBuilderARM::VisitInvokeStatic(HInvokeStatic* invoke) {
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001082 HandleInvoke(invoke);
1083}
1084
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01001085void CodeGeneratorARM::LoadCurrentMethod(Register reg) {
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001086 __ LoadFromOffset(kLoadWord, reg, SP, kCurrentMethodStackOffset);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001087}
1088
1089void InstructionCodeGeneratorARM::VisitInvokeStatic(HInvokeStatic* invoke) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001090 Register temp = invoke->GetLocations()->GetTemp(0).As<Register>();
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001091
1092 // TODO: Implement all kinds of calls:
1093 // 1) boot -> boot
1094 // 2) app -> boot
1095 // 3) app -> app
1096 //
1097 // Currently we implement the app -> app logic, which looks up in the resolve cache.
1098
1099 // temp = method;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01001100 codegen_->LoadCurrentMethod(temp);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001101 // temp = temp->dex_cache_resolved_methods_;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01001102 __ LoadFromOffset(
1103 kLoadWord, temp, temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001104 // temp = temp[index_in_cache]
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01001105 __ LoadFromOffset(
1106 kLoadWord, temp, temp, CodeGenerator::GetCacheOffset(invoke->GetIndexInDexCache()));
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001107 // LR = temp[offset_of_quick_compiled_code]
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001108 __ LoadFromOffset(kLoadWord, LR, temp,
1109 mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001110 // LR()
1111 __ blx(LR);
1112
1113 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1114 DCHECK(!codegen_->IsLeafMethod());
1115}
1116
1117void LocationsBuilderARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
1118 HandleInvoke(invoke);
1119}
1120
1121void LocationsBuilderARM::HandleInvoke(HInvoke* invoke) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001122 LocationSummary* locations =
1123 new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001124 locations->AddTemp(Location::RegisterLocation(R0));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +01001125
1126 InvokeDexCallingConventionVisitor calling_convention_visitor;
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01001127 for (size_t i = 0; i < invoke->InputCount(); i++) {
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +01001128 HInstruction* input = invoke->InputAt(i);
1129 locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
1130 }
1131
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001132 locations->SetOut(calling_convention_visitor.GetReturnLocation(invoke->GetType()));
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001133}
1134
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001135
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001136void InstructionCodeGeneratorARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001137 Register temp = invoke->GetLocations()->GetTemp(0).As<Register>();
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001138 uint32_t method_offset = mirror::Class::EmbeddedVTableOffset().Uint32Value() +
1139 invoke->GetVTableIndex() * sizeof(mirror::Class::VTableEntry);
1140 LocationSummary* locations = invoke->GetLocations();
1141 Location receiver = locations->InAt(0);
1142 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
1143 // temp = object->GetClass();
1144 if (receiver.IsStackSlot()) {
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001145 __ LoadFromOffset(kLoadWord, temp, SP, receiver.GetStackIndex());
1146 __ LoadFromOffset(kLoadWord, temp, temp, class_offset);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001147 } else {
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001148 __ LoadFromOffset(kLoadWord, temp, receiver.As<Register>(), class_offset);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001149 }
1150 // temp = temp->GetMethodAt(method_offset);
1151 uint32_t entry_point = mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value();
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001152 __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001153 // LR = temp->GetEntryPoint();
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001154 __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001155 // LR();
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001156 __ blx(LR);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001157 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001158 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001159}
1160
Roland Levillain88cb1752014-10-20 16:36:47 +01001161void LocationsBuilderARM::VisitNeg(HNeg* neg) {
1162 LocationSummary* locations =
1163 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
1164 switch (neg->GetResultType()) {
1165 case Primitive::kPrimInt:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001166 case Primitive::kPrimLong: {
1167 bool output_overlaps = (neg->GetResultType() == Primitive::kPrimLong);
Roland Levillain88cb1752014-10-20 16:36:47 +01001168 locations->SetInAt(0, Location::RequiresRegister());
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001169 locations->SetOut(Location::RequiresRegister(), output_overlaps);
Roland Levillain88cb1752014-10-20 16:36:47 +01001170 break;
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001171 }
Roland Levillain88cb1752014-10-20 16:36:47 +01001172
Roland Levillain88cb1752014-10-20 16:36:47 +01001173 case Primitive::kPrimFloat:
1174 case Primitive::kPrimDouble:
1175 LOG(FATAL) << "Not yet implemented neg type " << neg->GetResultType();
1176 break;
1177
1178 default:
1179 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1180 }
1181}
1182
1183void InstructionCodeGeneratorARM::VisitNeg(HNeg* neg) {
1184 LocationSummary* locations = neg->GetLocations();
1185 Location out = locations->Out();
1186 Location in = locations->InAt(0);
1187 switch (neg->GetResultType()) {
1188 case Primitive::kPrimInt:
1189 DCHECK(in.IsRegister());
Roland Levillainb762d2e2014-10-22 10:11:06 +01001190 __ rsb(out.As<Register>(), in.As<Register>(), ShifterOperand(0));
Roland Levillain88cb1752014-10-20 16:36:47 +01001191 break;
1192
1193 case Primitive::kPrimLong:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001194 DCHECK(in.IsRegisterPair());
1195 // out.lo = 0 - in.lo (and update the carry/borrow (C) flag)
1196 __ rsbs(out.AsRegisterPairLow<Register>(),
1197 in.AsRegisterPairLow<Register>(),
1198 ShifterOperand(0));
1199 // We cannot emit an RSC (Reverse Subtract with Carry)
1200 // instruction here, as it does not exist in the Thumb-2
1201 // instruction set. We use the following approach
1202 // using SBC and SUB instead.
1203 //
1204 // out.hi = -C
1205 __ sbc(out.AsRegisterPairHigh<Register>(),
1206 out.AsRegisterPairHigh<Register>(),
1207 ShifterOperand(out.AsRegisterPairHigh<Register>()));
1208 // out.hi = out.hi - in.hi
1209 __ sub(out.AsRegisterPairHigh<Register>(),
1210 out.AsRegisterPairHigh<Register>(),
1211 ShifterOperand(in.AsRegisterPairHigh<Register>()));
1212 break;
1213
Roland Levillain88cb1752014-10-20 16:36:47 +01001214 case Primitive::kPrimFloat:
1215 case Primitive::kPrimDouble:
1216 LOG(FATAL) << "Not yet implemented neg type " << neg->GetResultType();
1217 break;
1218
1219 default:
1220 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1221 }
1222}
1223
Roland Levillaindff1f282014-11-05 14:15:05 +00001224void LocationsBuilderARM::VisitTypeConversion(HTypeConversion* conversion) {
1225 LocationSummary* locations =
1226 new (GetGraph()->GetArena()) LocationSummary(conversion, LocationSummary::kNoCall);
1227 Primitive::Type result_type = conversion->GetResultType();
1228 Primitive::Type input_type = conversion->GetInputType();
1229 switch (result_type) {
1230 case Primitive::kPrimLong:
1231 switch (input_type) {
1232 case Primitive::kPrimByte:
1233 case Primitive::kPrimShort:
1234 case Primitive::kPrimInt:
1235 // int-to-long conversion.
1236 locations->SetInAt(0, Location::RequiresRegister());
1237 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1238 break;
1239
1240 case Primitive::kPrimFloat:
1241 case Primitive::kPrimDouble:
1242 LOG(FATAL) << "Type conversion from " << input_type << " to "
1243 << result_type << " not yet implemented";
1244 break;
1245
1246 default:
1247 LOG(FATAL) << "Unexpected type conversion from " << input_type
1248 << " to " << result_type;
1249 }
1250 break;
1251
1252 case Primitive::kPrimInt:
1253 case Primitive::kPrimFloat:
1254 case Primitive::kPrimDouble:
1255 LOG(FATAL) << "Type conversion from " << input_type
1256 << " to " << result_type << " not yet implemented";
1257 break;
1258
1259 default:
1260 LOG(FATAL) << "Unexpected type conversion from " << input_type
1261 << " to " << result_type;
1262 }
1263}
1264
1265void InstructionCodeGeneratorARM::VisitTypeConversion(HTypeConversion* conversion) {
1266 LocationSummary* locations = conversion->GetLocations();
1267 Location out = locations->Out();
1268 Location in = locations->InAt(0);
1269 Primitive::Type result_type = conversion->GetResultType();
1270 Primitive::Type input_type = conversion->GetInputType();
1271 switch (result_type) {
1272 case Primitive::kPrimLong:
1273 switch (input_type) {
1274 case Primitive::kPrimByte:
1275 case Primitive::kPrimShort:
1276 case Primitive::kPrimInt:
1277 // int-to-long conversion.
1278 DCHECK(out.IsRegisterPair());
1279 DCHECK(in.IsRegister());
1280 __ Mov(out.AsRegisterPairLow<Register>(), in.As<Register>());
1281 // Sign extension.
1282 __ Asr(out.AsRegisterPairHigh<Register>(),
1283 out.AsRegisterPairLow<Register>(),
1284 31);
1285 break;
1286
1287 case Primitive::kPrimFloat:
1288 case Primitive::kPrimDouble:
1289 LOG(FATAL) << "Type conversion from " << input_type << " to "
1290 << result_type << " not yet implemented";
1291 break;
1292
1293 default:
1294 LOG(FATAL) << "Unexpected type conversion from " << input_type
1295 << " to " << result_type;
1296 }
1297 break;
1298
1299 case Primitive::kPrimInt:
1300 case Primitive::kPrimFloat:
1301 case Primitive::kPrimDouble:
1302 LOG(FATAL) << "Type conversion from " << input_type
1303 << " to " << result_type << " not yet implemented";
1304 break;
1305
1306 default:
1307 LOG(FATAL) << "Unexpected type conversion from " << input_type
1308 << " to " << result_type;
1309 }
1310}
1311
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001312void LocationsBuilderARM::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001313 LocationSummary* locations =
1314 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001315 switch (add->GetResultType()) {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001316 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001317 case Primitive::kPrimLong: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01001318 bool output_overlaps = (add->GetResultType() == Primitive::kPrimLong);
1319 locations->SetInAt(0, Location::RequiresRegister());
1320 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
1321 locations->SetOut(Location::RequiresRegister(), output_overlaps);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001322 break;
1323 }
1324
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001325 case Primitive::kPrimFloat:
1326 case Primitive::kPrimDouble: {
1327 locations->SetInAt(0, Location::RequiresFpuRegister());
1328 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00001329 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001330 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001331 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001332
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001333 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001334 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001335 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001336}
1337
1338void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) {
1339 LocationSummary* locations = add->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001340 Location out = locations->Out();
1341 Location first = locations->InAt(0);
1342 Location second = locations->InAt(1);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001343 switch (add->GetResultType()) {
1344 case Primitive::kPrimInt:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001345 if (second.IsRegister()) {
1346 __ add(out.As<Register>(), first.As<Register>(), ShifterOperand(second.As<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001347 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001348 __ AddConstant(out.As<Register>(),
1349 first.As<Register>(),
1350 second.GetConstant()->AsIntConstant()->GetValue());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001351 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001352 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001353
1354 case Primitive::kPrimLong:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001355 __ adds(out.AsRegisterPairLow<Register>(),
1356 first.AsRegisterPairLow<Register>(),
1357 ShifterOperand(second.AsRegisterPairLow<Register>()));
1358 __ adc(out.AsRegisterPairHigh<Register>(),
1359 first.AsRegisterPairHigh<Register>(),
1360 ShifterOperand(second.AsRegisterPairHigh<Register>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001361 break;
1362
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001363 case Primitive::kPrimFloat:
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001364 __ vadds(out.As<SRegister>(), first.As<SRegister>(), second.As<SRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001365 break;
1366
1367 case Primitive::kPrimDouble:
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001368 __ vaddd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
1369 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
1370 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001371 break;
1372
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001373 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001374 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001375 }
1376}
1377
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001378void LocationsBuilderARM::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001379 LocationSummary* locations =
1380 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001381 switch (sub->GetResultType()) {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001382 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001383 case Primitive::kPrimLong: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01001384 bool output_overlaps = (sub->GetResultType() == Primitive::kPrimLong);
1385 locations->SetInAt(0, Location::RequiresRegister());
1386 locations->SetInAt(1, Location::RegisterOrConstant(sub->InputAt(1)));
1387 locations->SetOut(Location::RequiresRegister(), output_overlaps);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001388 break;
1389 }
Calin Juravle11351682014-10-23 15:38:15 +01001390 case Primitive::kPrimFloat:
1391 case Primitive::kPrimDouble: {
1392 locations->SetInAt(0, Location::RequiresFpuRegister());
1393 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00001394 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001395 break;
Calin Juravle11351682014-10-23 15:38:15 +01001396 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001397 default:
Calin Juravle11351682014-10-23 15:38:15 +01001398 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001399 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001400}
1401
1402void InstructionCodeGeneratorARM::VisitSub(HSub* sub) {
1403 LocationSummary* locations = sub->GetLocations();
Calin Juravle11351682014-10-23 15:38:15 +01001404 Location out = locations->Out();
1405 Location first = locations->InAt(0);
1406 Location second = locations->InAt(1);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001407 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001408 case Primitive::kPrimInt: {
Calin Juravle11351682014-10-23 15:38:15 +01001409 if (second.IsRegister()) {
1410 __ sub(out.As<Register>(), first.As<Register>(), ShifterOperand(second.As<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001411 } else {
Calin Juravle11351682014-10-23 15:38:15 +01001412 __ AddConstant(out.As<Register>(),
1413 first.As<Register>(),
1414 -second.GetConstant()->AsIntConstant()->GetValue());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001415 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001416 break;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001417 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001418
Calin Juravle11351682014-10-23 15:38:15 +01001419 case Primitive::kPrimLong: {
1420 __ subs(out.AsRegisterPairLow<Register>(),
1421 first.AsRegisterPairLow<Register>(),
1422 ShifterOperand(second.AsRegisterPairLow<Register>()));
1423 __ sbc(out.AsRegisterPairHigh<Register>(),
1424 first.AsRegisterPairHigh<Register>(),
1425 ShifterOperand(second.AsRegisterPairHigh<Register>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001426 break;
Calin Juravle11351682014-10-23 15:38:15 +01001427 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001428
Calin Juravle11351682014-10-23 15:38:15 +01001429 case Primitive::kPrimFloat: {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001430 __ vsubs(out.As<SRegister>(), first.As<SRegister>(), second.As<SRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001431 break;
Calin Juravle11351682014-10-23 15:38:15 +01001432 }
1433
1434 case Primitive::kPrimDouble: {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001435 __ vsubd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
1436 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
1437 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Calin Juravle11351682014-10-23 15:38:15 +01001438 break;
1439 }
1440
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001441
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001442 default:
Calin Juravle11351682014-10-23 15:38:15 +01001443 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001444 }
1445}
1446
Calin Juravle34bacdf2014-10-07 20:23:36 +01001447void LocationsBuilderARM::VisitMul(HMul* mul) {
1448 LocationSummary* locations =
1449 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
1450 switch (mul->GetResultType()) {
1451 case Primitive::kPrimInt:
1452 case Primitive::kPrimLong: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01001453 locations->SetInAt(0, Location::RequiresRegister());
1454 locations->SetInAt(1, Location::RequiresRegister());
1455 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Calin Juravle34bacdf2014-10-07 20:23:36 +01001456 break;
1457 }
1458
Calin Juravleb5bfa962014-10-21 18:02:24 +01001459 case Primitive::kPrimFloat:
1460 case Primitive::kPrimDouble: {
1461 locations->SetInAt(0, Location::RequiresFpuRegister());
1462 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00001463 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Calin Juravle34bacdf2014-10-07 20:23:36 +01001464 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01001465 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01001466
1467 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01001468 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01001469 }
1470}
1471
1472void InstructionCodeGeneratorARM::VisitMul(HMul* mul) {
1473 LocationSummary* locations = mul->GetLocations();
1474 Location out = locations->Out();
1475 Location first = locations->InAt(0);
1476 Location second = locations->InAt(1);
1477 switch (mul->GetResultType()) {
1478 case Primitive::kPrimInt: {
1479 __ mul(out.As<Register>(), first.As<Register>(), second.As<Register>());
1480 break;
1481 }
1482 case Primitive::kPrimLong: {
1483 Register out_hi = out.AsRegisterPairHigh<Register>();
1484 Register out_lo = out.AsRegisterPairLow<Register>();
1485 Register in1_hi = first.AsRegisterPairHigh<Register>();
1486 Register in1_lo = first.AsRegisterPairLow<Register>();
1487 Register in2_hi = second.AsRegisterPairHigh<Register>();
1488 Register in2_lo = second.AsRegisterPairLow<Register>();
1489
1490 // Extra checks to protect caused by the existence of R1_R2.
1491 // The algorithm is wrong if out.hi is either in1.lo or in2.lo:
1492 // (e.g. in1=r0_r1, in2=r2_r3 and out=r1_r2);
1493 DCHECK_NE(out_hi, in1_lo);
1494 DCHECK_NE(out_hi, in2_lo);
1495
1496 // input: in1 - 64 bits, in2 - 64 bits
1497 // output: out
1498 // formula: out.hi : out.lo = (in1.lo * in2.hi + in1.hi * in2.lo)* 2^32 + in1.lo * in2.lo
1499 // parts: out.hi = in1.lo * in2.hi + in1.hi * in2.lo + (in1.lo * in2.lo)[63:32]
1500 // parts: out.lo = (in1.lo * in2.lo)[31:0]
1501
1502 // IP <- in1.lo * in2.hi
1503 __ mul(IP, in1_lo, in2_hi);
1504 // out.hi <- in1.lo * in2.hi + in1.hi * in2.lo
1505 __ mla(out_hi, in1_hi, in2_lo, IP);
1506 // out.lo <- (in1.lo * in2.lo)[31:0];
1507 __ umull(out_lo, IP, in1_lo, in2_lo);
1508 // out.hi <- in2.hi * in1.lo + in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
1509 __ add(out_hi, out_hi, ShifterOperand(IP));
1510 break;
1511 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01001512
1513 case Primitive::kPrimFloat: {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001514 __ vmuls(out.As<SRegister>(), first.As<SRegister>(), second.As<SRegister>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01001515 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01001516 }
1517
1518 case Primitive::kPrimDouble: {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001519 __ vmuld(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
1520 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
1521 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Calin Juravleb5bfa962014-10-21 18:02:24 +01001522 break;
1523 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01001524
1525 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01001526 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01001527 }
1528}
1529
Calin Juravle7c4954d2014-10-28 16:57:40 +00001530void LocationsBuilderARM::VisitDiv(HDiv* div) {
1531 LocationSummary* locations =
1532 new (GetGraph()->GetArena()) LocationSummary(div, LocationSummary::kNoCall);
1533 switch (div->GetResultType()) {
1534 case Primitive::kPrimInt:
1535 case Primitive::kPrimLong: {
1536 LOG(FATAL) << "Not implemented div type" << div->GetResultType();
1537 break;
1538 }
1539 case Primitive::kPrimFloat:
1540 case Primitive::kPrimDouble: {
1541 locations->SetInAt(0, Location::RequiresFpuRegister());
1542 locations->SetInAt(1, Location::RequiresFpuRegister());
1543 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
1544 break;
1545 }
1546
1547 default:
1548 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
1549 }
1550}
1551
1552void InstructionCodeGeneratorARM::VisitDiv(HDiv* div) {
1553 LocationSummary* locations = div->GetLocations();
1554 Location out = locations->Out();
1555 Location first = locations->InAt(0);
1556 Location second = locations->InAt(1);
1557
1558 switch (div->GetResultType()) {
1559 case Primitive::kPrimInt:
1560 case Primitive::kPrimLong: {
1561 LOG(FATAL) << "Not implemented div type" << div->GetResultType();
1562 break;
1563 }
1564
1565 case Primitive::kPrimFloat: {
1566 __ vdivs(out.As<SRegister>(), first.As<SRegister>(), second.As<SRegister>());
1567 break;
1568 }
1569
1570 case Primitive::kPrimDouble: {
1571 __ vdivd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
1572 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
1573 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
1574 break;
1575 }
1576
1577 default:
1578 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
1579 }
1580}
1581
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01001582void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001583 LocationSummary* locations =
1584 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001585 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001586 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
1587 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
1588 locations->SetOut(Location::RegisterLocation(R0));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01001589}
1590
1591void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) {
1592 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01001593 codegen_->LoadCurrentMethod(calling_convention.GetRegisterAt(1));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01001594 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01001595 codegen_->InvokeRuntime(
1596 QUICK_ENTRY_POINT(pAllocObjectWithAccessCheck), instruction, instruction->GetDexPc());
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01001597}
1598
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01001599void LocationsBuilderARM::VisitNewArray(HNewArray* instruction) {
1600 LocationSummary* locations =
1601 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
1602 InvokeRuntimeCallingConvention calling_convention;
1603 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
1604 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
1605 locations->SetOut(Location::RegisterLocation(R0));
1606 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
1607}
1608
1609void InstructionCodeGeneratorARM::VisitNewArray(HNewArray* instruction) {
1610 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01001611 codegen_->LoadCurrentMethod(calling_convention.GetRegisterAt(1));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01001612 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01001613 codegen_->InvokeRuntime(
1614 QUICK_ENTRY_POINT(pAllocArrayWithAccessCheck), instruction, instruction->GetDexPc());
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01001615}
1616
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001617void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001618 LocationSummary* locations =
1619 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001620 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
1621 if (location.IsStackSlot()) {
1622 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
1623 } else if (location.IsDoubleStackSlot()) {
1624 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001625 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001626 locations->SetOut(location);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001627}
1628
1629void InstructionCodeGeneratorARM::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001630 // Nothing to do, the parameter is already at its location.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001631 UNUSED(instruction);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001632}
1633
Roland Levillain1cc5f2512014-10-22 18:06:21 +01001634void LocationsBuilderARM::VisitNot(HNot* not_) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001635 LocationSummary* locations =
Roland Levillain1cc5f2512014-10-22 18:06:21 +01001636 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01001637 locations->SetInAt(0, Location::RequiresRegister());
1638 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01001639}
1640
Roland Levillain1cc5f2512014-10-22 18:06:21 +01001641void InstructionCodeGeneratorARM::VisitNot(HNot* not_) {
1642 LocationSummary* locations = not_->GetLocations();
1643 Location out = locations->Out();
1644 Location in = locations->InAt(0);
1645 switch (not_->InputAt(0)->GetType()) {
1646 case Primitive::kPrimBoolean:
1647 __ eor(out.As<Register>(), in.As<Register>(), ShifterOperand(1));
1648 break;
1649
1650 case Primitive::kPrimInt:
1651 __ mvn(out.As<Register>(), ShifterOperand(in.As<Register>()));
1652 break;
1653
1654 case Primitive::kPrimLong:
Roland Levillain70566432014-10-24 16:20:17 +01001655 __ mvn(out.AsRegisterPairLow<Register>(),
1656 ShifterOperand(in.AsRegisterPairLow<Register>()));
1657 __ mvn(out.AsRegisterPairHigh<Register>(),
1658 ShifterOperand(in.AsRegisterPairHigh<Register>()));
Roland Levillain1cc5f2512014-10-22 18:06:21 +01001659 break;
1660
1661 default:
1662 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
1663 }
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01001664}
1665
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001666void LocationsBuilderARM::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001667 LocationSummary* locations =
1668 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01001669 locations->SetInAt(0, Location::RequiresRegister());
1670 locations->SetInAt(1, Location::RequiresRegister());
1671 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001672}
1673
1674void InstructionCodeGeneratorARM::VisitCompare(HCompare* compare) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001675 LocationSummary* locations = compare->GetLocations();
1676 switch (compare->InputAt(0)->GetType()) {
1677 case Primitive::kPrimLong: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001678 Register output = locations->Out().As<Register>();
1679 Location left = locations->InAt(0);
1680 Location right = locations->InAt(1);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001681 Label less, greater, done;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001682 __ cmp(left.AsRegisterPairHigh<Register>(),
1683 ShifterOperand(right.AsRegisterPairHigh<Register>())); // Signed compare.
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001684 __ b(&less, LT);
1685 __ b(&greater, GT);
Nicolas Geoffray8d486732014-07-16 16:23:40 +01001686 // Do LoadImmediate before any `cmp`, as LoadImmediate might affect
1687 // the status flags.
1688 __ LoadImmediate(output, 0);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001689 __ cmp(left.AsRegisterPairLow<Register>(),
1690 ShifterOperand(right.AsRegisterPairLow<Register>())); // Unsigned compare.
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001691 __ b(&done, EQ);
1692 __ b(&less, CC);
1693
1694 __ Bind(&greater);
1695 __ LoadImmediate(output, 1);
1696 __ b(&done);
1697
1698 __ Bind(&less);
1699 __ LoadImmediate(output, -1);
1700
1701 __ Bind(&done);
1702 break;
1703 }
1704 default:
1705 LOG(FATAL) << "Unimplemented compare type " << compare->InputAt(0)->GetType();
1706 }
1707}
1708
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01001709void LocationsBuilderARM::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001710 LocationSummary* locations =
1711 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01001712 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
1713 locations->SetInAt(i, Location::Any());
1714 }
1715 locations->SetOut(Location::Any());
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01001716}
1717
1718void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001719 UNUSED(instruction);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001720 LOG(FATAL) << "Unreachable";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01001721}
1722
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001723void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001724 LocationSummary* locations =
1725 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001726 bool is_object_type = instruction->GetFieldType() == Primitive::kPrimNot;
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01001727 locations->SetInAt(0, Location::RequiresRegister());
1728 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001729 // Temporary registers for the write barrier.
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001730 if (is_object_type) {
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001731 locations->AddTemp(Location::RequiresRegister());
1732 locations->AddTemp(Location::RequiresRegister());
1733 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001734}
1735
1736void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
1737 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001738 Register obj = locations->InAt(0).As<Register>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001739 uint32_t offset = instruction->GetFieldOffset().Uint32Value();
Nicolas Geoffray39468442014-09-02 15:17:15 +01001740 Primitive::Type field_type = instruction->GetFieldType();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001741
1742 switch (field_type) {
1743 case Primitive::kPrimBoolean:
1744 case Primitive::kPrimByte: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001745 Register value = locations->InAt(1).As<Register>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001746 __ StoreToOffset(kStoreByte, value, obj, offset);
1747 break;
1748 }
1749
1750 case Primitive::kPrimShort:
1751 case Primitive::kPrimChar: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001752 Register value = locations->InAt(1).As<Register>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001753 __ StoreToOffset(kStoreHalfword, value, obj, offset);
1754 break;
1755 }
1756
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001757 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001758 case Primitive::kPrimNot: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001759 Register value = locations->InAt(1).As<Register>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001760 __ StoreToOffset(kStoreWord, value, obj, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001761 if (field_type == Primitive::kPrimNot) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001762 Register temp = locations->GetTemp(0).As<Register>();
1763 Register card = locations->GetTemp(1).As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001764 codegen_->MarkGCCard(temp, card, obj, value);
1765 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001766 break;
1767 }
1768
1769 case Primitive::kPrimLong: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001770 Location value = locations->InAt(1);
1771 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), obj, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001772 break;
1773 }
1774
1775 case Primitive::kPrimFloat:
1776 case Primitive::kPrimDouble:
1777 LOG(FATAL) << "Unimplemented register type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07001778 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001779 case Primitive::kPrimVoid:
1780 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07001781 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001782 }
1783}
1784
1785void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001786 LocationSummary* locations =
1787 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01001788 locations->SetInAt(0, Location::RequiresRegister());
1789 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001790}
1791
1792void InstructionCodeGeneratorARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
1793 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001794 Register obj = locations->InAt(0).As<Register>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001795 uint32_t offset = instruction->GetFieldOffset().Uint32Value();
1796
1797 switch (instruction->GetType()) {
1798 case Primitive::kPrimBoolean: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001799 Register out = locations->Out().As<Register>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001800 __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset);
1801 break;
1802 }
1803
1804 case Primitive::kPrimByte: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001805 Register out = locations->Out().As<Register>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001806 __ LoadFromOffset(kLoadSignedByte, out, obj, offset);
1807 break;
1808 }
1809
1810 case Primitive::kPrimShort: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001811 Register out = locations->Out().As<Register>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001812 __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset);
1813 break;
1814 }
1815
1816 case Primitive::kPrimChar: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001817 Register out = locations->Out().As<Register>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001818 __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset);
1819 break;
1820 }
1821
1822 case Primitive::kPrimInt:
1823 case Primitive::kPrimNot: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001824 Register out = locations->Out().As<Register>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001825 __ LoadFromOffset(kLoadWord, out, obj, offset);
1826 break;
1827 }
1828
1829 case Primitive::kPrimLong: {
1830 // TODO: support volatile.
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001831 Location out = locations->Out();
1832 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), obj, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001833 break;
1834 }
1835
1836 case Primitive::kPrimFloat:
1837 case Primitive::kPrimDouble:
1838 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07001839 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001840 case Primitive::kPrimVoid:
1841 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07001842 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001843 }
1844}
1845
1846void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001847 LocationSummary* locations =
1848 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001849 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001850 if (instruction->HasUses()) {
1851 locations->SetOut(Location::SameAsFirstInput());
1852 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001853}
1854
1855void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +01001856 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001857 codegen_->AddSlowPath(slow_path);
1858
1859 LocationSummary* locations = instruction->GetLocations();
1860 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001861
1862 if (obj.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001863 __ cmp(obj.As<Register>(), ShifterOperand(0));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001864 __ b(slow_path->GetEntryLabel(), EQ);
1865 } else {
1866 DCHECK(obj.IsConstant()) << obj;
1867 DCHECK_EQ(obj.GetConstant()->AsIntConstant()->GetValue(), 0);
1868 __ b(slow_path->GetEntryLabel());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001869 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001870}
1871
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001872void LocationsBuilderARM::VisitArrayGet(HArrayGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001873 LocationSummary* locations =
1874 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01001875 locations->SetInAt(0, Location::RequiresRegister());
1876 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
1877 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001878}
1879
1880void InstructionCodeGeneratorARM::VisitArrayGet(HArrayGet* instruction) {
1881 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001882 Register obj = locations->InAt(0).As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001883 Location index = locations->InAt(1);
1884
1885 switch (instruction->GetType()) {
1886 case Primitive::kPrimBoolean: {
1887 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001888 Register out = locations->Out().As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001889 if (index.IsConstant()) {
1890 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
1891 __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset);
1892 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001893 __ add(IP, obj, ShifterOperand(index.As<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001894 __ LoadFromOffset(kLoadUnsignedByte, out, IP, data_offset);
1895 }
1896 break;
1897 }
1898
1899 case Primitive::kPrimByte: {
1900 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001901 Register out = locations->Out().As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001902 if (index.IsConstant()) {
1903 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
1904 __ LoadFromOffset(kLoadSignedByte, out, obj, offset);
1905 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001906 __ add(IP, obj, ShifterOperand(index.As<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001907 __ LoadFromOffset(kLoadSignedByte, out, IP, data_offset);
1908 }
1909 break;
1910 }
1911
1912 case Primitive::kPrimShort: {
1913 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001914 Register out = locations->Out().As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001915 if (index.IsConstant()) {
1916 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
1917 __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset);
1918 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001919 __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001920 __ LoadFromOffset(kLoadSignedHalfword, out, IP, data_offset);
1921 }
1922 break;
1923 }
1924
1925 case Primitive::kPrimChar: {
1926 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001927 Register out = locations->Out().As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001928 if (index.IsConstant()) {
1929 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
1930 __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset);
1931 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001932 __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001933 __ LoadFromOffset(kLoadUnsignedHalfword, out, IP, data_offset);
1934 }
1935 break;
1936 }
1937
1938 case Primitive::kPrimInt:
1939 case Primitive::kPrimNot: {
1940 DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t));
1941 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001942 Register out = locations->Out().As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001943 if (index.IsConstant()) {
1944 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
1945 __ LoadFromOffset(kLoadWord, out, obj, offset);
1946 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001947 __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_4));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001948 __ LoadFromOffset(kLoadWord, out, IP, data_offset);
1949 }
1950 break;
1951 }
1952
1953 case Primitive::kPrimLong: {
1954 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001955 Location out = locations->Out();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001956 if (index.IsConstant()) {
1957 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001958 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), obj, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001959 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001960 __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_8));
1961 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), IP, data_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001962 }
1963 break;
1964 }
1965
1966 case Primitive::kPrimFloat:
1967 case Primitive::kPrimDouble:
1968 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07001969 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001970 case Primitive::kPrimVoid:
1971 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07001972 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001973 }
1974}
1975
1976void LocationsBuilderARM::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001977 Primitive::Type value_type = instruction->GetComponentType();
1978 bool is_object = value_type == Primitive::kPrimNot;
1979 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
1980 instruction, is_object ? LocationSummary::kCall : LocationSummary::kNoCall);
1981 if (is_object) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001982 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001983 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
1984 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
1985 locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001986 } else {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01001987 locations->SetInAt(0, Location::RequiresRegister());
1988 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
1989 locations->SetInAt(2, Location::RequiresRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001990 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001991}
1992
1993void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) {
1994 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001995 Register obj = locations->InAt(0).As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001996 Location index = locations->InAt(1);
Nicolas Geoffray39468442014-09-02 15:17:15 +01001997 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001998
1999 switch (value_type) {
2000 case Primitive::kPrimBoolean:
2001 case Primitive::kPrimByte: {
2002 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002003 Register value = locations->InAt(2).As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002004 if (index.IsConstant()) {
2005 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
2006 __ StoreToOffset(kStoreByte, value, obj, offset);
2007 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002008 __ add(IP, obj, ShifterOperand(index.As<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002009 __ StoreToOffset(kStoreByte, value, IP, data_offset);
2010 }
2011 break;
2012 }
2013
2014 case Primitive::kPrimShort:
2015 case Primitive::kPrimChar: {
2016 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002017 Register value = locations->InAt(2).As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002018 if (index.IsConstant()) {
2019 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
2020 __ StoreToOffset(kStoreHalfword, value, obj, offset);
2021 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002022 __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002023 __ StoreToOffset(kStoreHalfword, value, IP, data_offset);
2024 }
2025 break;
2026 }
2027
2028 case Primitive::kPrimInt: {
2029 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002030 Register value = locations->InAt(2).As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002031 if (index.IsConstant()) {
2032 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
2033 __ StoreToOffset(kStoreWord, value, obj, offset);
2034 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002035 __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_4));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002036 __ StoreToOffset(kStoreWord, value, IP, data_offset);
2037 }
2038 break;
2039 }
2040
2041 case Primitive::kPrimNot: {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002042 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pAputObject), instruction, instruction->GetDexPc());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002043 break;
2044 }
2045
2046 case Primitive::kPrimLong: {
2047 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002048 Location value = locations->InAt(2);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002049 if (index.IsConstant()) {
2050 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002051 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), obj, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002052 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002053 __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_8));
2054 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), IP, data_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002055 }
2056 break;
2057 }
2058
2059 case Primitive::kPrimFloat:
2060 case Primitive::kPrimDouble:
2061 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07002062 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002063 case Primitive::kPrimVoid:
2064 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07002065 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002066 }
2067}
2068
2069void LocationsBuilderARM::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002070 LocationSummary* locations =
2071 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002072 locations->SetInAt(0, Location::RequiresRegister());
2073 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002074}
2075
2076void InstructionCodeGeneratorARM::VisitArrayLength(HArrayLength* instruction) {
2077 LocationSummary* locations = instruction->GetLocations();
2078 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002079 Register obj = locations->InAt(0).As<Register>();
2080 Register out = locations->Out().As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002081 __ LoadFromOffset(kLoadWord, out, obj, offset);
2082}
2083
2084void LocationsBuilderARM::VisitBoundsCheck(HBoundsCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002085 LocationSummary* locations =
2086 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002087 locations->SetInAt(0, Location::RequiresRegister());
2088 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002089 if (instruction->HasUses()) {
2090 locations->SetOut(Location::SameAsFirstInput());
2091 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002092}
2093
2094void InstructionCodeGeneratorARM::VisitBoundsCheck(HBoundsCheck* instruction) {
2095 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +01002096 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathARM(
Nicolas Geoffray39468442014-09-02 15:17:15 +01002097 instruction, locations->InAt(0), locations->InAt(1));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002098 codegen_->AddSlowPath(slow_path);
2099
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002100 Register index = locations->InAt(0).As<Register>();
2101 Register length = locations->InAt(1).As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002102
2103 __ cmp(index, ShifterOperand(length));
2104 __ b(slow_path->GetEntryLabel(), CS);
2105}
2106
2107void CodeGeneratorARM::MarkGCCard(Register temp, Register card, Register object, Register value) {
2108 Label is_null;
2109 __ CompareAndBranchIfZero(value, &is_null);
2110 __ LoadFromOffset(kLoadWord, card, TR, Thread::CardTableOffset<kArmWordSize>().Int32Value());
2111 __ Lsr(temp, object, gc::accounting::CardTable::kCardShift);
2112 __ strb(card, Address(card, temp));
2113 __ Bind(&is_null);
2114}
2115
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002116void LocationsBuilderARM::VisitTemporary(HTemporary* temp) {
2117 temp->SetLocations(nullptr);
2118}
2119
2120void InstructionCodeGeneratorARM::VisitTemporary(HTemporary* temp) {
2121 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07002122 UNUSED(temp);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002123}
2124
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01002125void LocationsBuilderARM::VisitParallelMove(HParallelMove* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07002126 UNUSED(instruction);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01002127 LOG(FATAL) << "Unreachable";
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01002128}
2129
2130void InstructionCodeGeneratorARM::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01002131 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
2132}
2133
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00002134void LocationsBuilderARM::VisitSuspendCheck(HSuspendCheck* instruction) {
2135 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
2136}
2137
2138void InstructionCodeGeneratorARM::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01002139 HBasicBlock* block = instruction->GetBlock();
2140 if (block->GetLoopInformation() != nullptr) {
2141 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
2142 // The back edge will generate the suspend check.
2143 return;
2144 }
2145 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
2146 // The goto will generate the suspend check.
2147 return;
2148 }
2149 GenerateSuspendCheck(instruction, nullptr);
2150}
2151
2152void InstructionCodeGeneratorARM::GenerateSuspendCheck(HSuspendCheck* instruction,
2153 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00002154 SuspendCheckSlowPathARM* slow_path =
Nicolas Geoffray3c049742014-09-24 18:10:46 +01002155 new (GetGraph()->GetArena()) SuspendCheckSlowPathARM(instruction, successor);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00002156 codegen_->AddSlowPath(slow_path);
2157
Nicolas Geoffray44b819e2014-11-06 12:00:54 +00002158 __ LoadFromOffset(
2159 kLoadUnsignedHalfword, IP, TR, Thread::ThreadFlagsOffset<kArmWordSize>().Int32Value());
2160 __ cmp(IP, ShifterOperand(0));
2161 // TODO: Figure out the branch offsets and use cbz/cbnz.
Nicolas Geoffray3c049742014-09-24 18:10:46 +01002162 if (successor == nullptr) {
Nicolas Geoffray44b819e2014-11-06 12:00:54 +00002163 __ b(slow_path->GetEntryLabel(), NE);
Nicolas Geoffray3c049742014-09-24 18:10:46 +01002164 __ Bind(slow_path->GetReturnLabel());
2165 } else {
Nicolas Geoffray44b819e2014-11-06 12:00:54 +00002166 __ b(codegen_->GetLabelOf(successor), EQ);
Nicolas Geoffray3c049742014-09-24 18:10:46 +01002167 __ b(slow_path->GetEntryLabel());
2168 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00002169}
2170
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01002171ArmAssembler* ParallelMoveResolverARM::GetAssembler() const {
2172 return codegen_->GetAssembler();
2173}
2174
2175void ParallelMoveResolverARM::EmitMove(size_t index) {
2176 MoveOperands* move = moves_.Get(index);
2177 Location source = move->GetSource();
2178 Location destination = move->GetDestination();
2179
2180 if (source.IsRegister()) {
2181 if (destination.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002182 __ Mov(destination.As<Register>(), source.As<Register>());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01002183 } else {
2184 DCHECK(destination.IsStackSlot());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002185 __ StoreToOffset(kStoreWord, source.As<Register>(),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01002186 SP, destination.GetStackIndex());
2187 }
2188 } else if (source.IsStackSlot()) {
2189 if (destination.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002190 __ LoadFromOffset(kLoadWord, destination.As<Register>(),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01002191 SP, source.GetStackIndex());
2192 } else {
2193 DCHECK(destination.IsStackSlot());
2194 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
2195 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
2196 }
2197 } else {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002198 DCHECK(source.IsConstant());
Roland Levillain476df552014-10-09 17:51:36 +01002199 DCHECK(source.GetConstant()->IsIntConstant());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002200 int32_t value = source.GetConstant()->AsIntConstant()->GetValue();
2201 if (destination.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002202 __ LoadImmediate(destination.As<Register>(), value);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002203 } else {
2204 DCHECK(destination.IsStackSlot());
2205 __ LoadImmediate(IP, value);
Nicolas Geoffray360231a2014-10-08 21:07:48 +01002206 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002207 }
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01002208 }
2209}
2210
2211void ParallelMoveResolverARM::Exchange(Register reg, int mem) {
2212 __ Mov(IP, reg);
2213 __ LoadFromOffset(kLoadWord, reg, SP, mem);
2214 __ StoreToOffset(kStoreWord, IP, SP, mem);
2215}
2216
2217void ParallelMoveResolverARM::Exchange(int mem1, int mem2) {
2218 ScratchRegisterScope ensure_scratch(this, IP, R0, codegen_->GetNumberOfCoreRegisters());
2219 int stack_offset = ensure_scratch.IsSpilled() ? kArmWordSize : 0;
2220 __ LoadFromOffset(kLoadWord, static_cast<Register>(ensure_scratch.GetRegister()),
2221 SP, mem1 + stack_offset);
2222 __ LoadFromOffset(kLoadWord, IP, SP, mem2 + stack_offset);
2223 __ StoreToOffset(kStoreWord, static_cast<Register>(ensure_scratch.GetRegister()),
2224 SP, mem2 + stack_offset);
2225 __ StoreToOffset(kStoreWord, IP, SP, mem1 + stack_offset);
2226}
2227
2228void ParallelMoveResolverARM::EmitSwap(size_t index) {
2229 MoveOperands* move = moves_.Get(index);
2230 Location source = move->GetSource();
2231 Location destination = move->GetDestination();
2232
2233 if (source.IsRegister() && destination.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002234 DCHECK_NE(source.As<Register>(), IP);
2235 DCHECK_NE(destination.As<Register>(), IP);
2236 __ Mov(IP, source.As<Register>());
2237 __ Mov(source.As<Register>(), destination.As<Register>());
2238 __ Mov(destination.As<Register>(), IP);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01002239 } else if (source.IsRegister() && destination.IsStackSlot()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002240 Exchange(source.As<Register>(), destination.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01002241 } else if (source.IsStackSlot() && destination.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002242 Exchange(destination.As<Register>(), source.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01002243 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
2244 Exchange(source.GetStackIndex(), destination.GetStackIndex());
2245 } else {
2246 LOG(FATAL) << "Unimplemented";
2247 }
2248}
2249
2250void ParallelMoveResolverARM::SpillScratch(int reg) {
2251 __ Push(static_cast<Register>(reg));
2252}
2253
2254void ParallelMoveResolverARM::RestoreScratch(int reg) {
2255 __ Pop(static_cast<Register>(reg));
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01002256}
2257
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002258void LocationsBuilderARM::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00002259 LocationSummary::CallKind call_kind = cls->CanCallRuntime()
2260 ? LocationSummary::kCallOnSlowPath
2261 : LocationSummary::kNoCall;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002262 LocationSummary* locations =
Nicolas Geoffray424f6762014-11-03 14:51:25 +00002263 new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002264 locations->SetOut(Location::RequiresRegister());
2265}
2266
2267void InstructionCodeGeneratorARM::VisitLoadClass(HLoadClass* cls) {
2268 Register out = cls->GetLocations()->Out().As<Register>();
2269 if (cls->IsReferrersClass()) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00002270 DCHECK(!cls->CanCallRuntime());
2271 DCHECK(!cls->MustGenerateClinitCheck());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002272 codegen_->LoadCurrentMethod(out);
2273 __ LoadFromOffset(kLoadWord, out, out, mirror::ArtMethod::DeclaringClassOffset().Int32Value());
2274 } else {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00002275 DCHECK(cls->CanCallRuntime());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002276 codegen_->LoadCurrentMethod(out);
2277 __ LoadFromOffset(
2278 kLoadWord, out, out, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value());
2279 __ LoadFromOffset(kLoadWord, out, out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex()));
Nicolas Geoffray424f6762014-11-03 14:51:25 +00002280
2281 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
2282 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
2283 codegen_->AddSlowPath(slow_path);
2284 __ cmp(out, ShifterOperand(0));
2285 __ b(slow_path->GetEntryLabel(), EQ);
2286 if (cls->MustGenerateClinitCheck()) {
2287 GenerateClassInitializationCheck(slow_path, out);
2288 } else {
2289 __ Bind(slow_path->GetExitLabel());
2290 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002291 }
2292}
2293
2294void LocationsBuilderARM::VisitClinitCheck(HClinitCheck* check) {
2295 LocationSummary* locations =
2296 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
2297 locations->SetInAt(0, Location::RequiresRegister());
2298 if (check->HasUses()) {
2299 locations->SetOut(Location::SameAsFirstInput());
2300 }
2301}
2302
2303void InstructionCodeGeneratorARM::VisitClinitCheck(HClinitCheck* check) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00002304 // We assume the class is not null.
2305 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
2306 check->GetLoadClass(), check, check->GetDexPc(), true);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002307 codegen_->AddSlowPath(slow_path);
Nicolas Geoffray424f6762014-11-03 14:51:25 +00002308 GenerateClassInitializationCheck(slow_path, check->GetLocations()->InAt(0).As<Register>());
2309}
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002310
Nicolas Geoffray424f6762014-11-03 14:51:25 +00002311void InstructionCodeGeneratorARM::GenerateClassInitializationCheck(
2312 SlowPathCodeARM* slow_path, Register class_reg) {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002313 __ LoadFromOffset(kLoadWord, IP, class_reg, mirror::Class::StatusOffset().Int32Value());
2314 __ cmp(IP, ShifterOperand(mirror::Class::kStatusInitialized));
2315 __ b(slow_path->GetEntryLabel(), LT);
2316 // Even if the initialized flag is set, we may be in a situation where caches are not synced
2317 // properly. Therefore, we do a memory fence.
2318 __ dmb(ISH);
2319 __ Bind(slow_path->GetExitLabel());
2320}
2321
2322void LocationsBuilderARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
2323 LocationSummary* locations =
2324 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
2325 locations->SetInAt(0, Location::RequiresRegister());
2326 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2327}
2328
2329void InstructionCodeGeneratorARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
2330 LocationSummary* locations = instruction->GetLocations();
2331 Register cls = locations->InAt(0).As<Register>();
2332 uint32_t offset = instruction->GetFieldOffset().Uint32Value();
2333
2334 switch (instruction->GetType()) {
2335 case Primitive::kPrimBoolean: {
2336 Register out = locations->Out().As<Register>();
2337 __ LoadFromOffset(kLoadUnsignedByte, out, cls, offset);
2338 break;
2339 }
2340
2341 case Primitive::kPrimByte: {
2342 Register out = locations->Out().As<Register>();
2343 __ LoadFromOffset(kLoadSignedByte, out, cls, offset);
2344 break;
2345 }
2346
2347 case Primitive::kPrimShort: {
2348 Register out = locations->Out().As<Register>();
2349 __ LoadFromOffset(kLoadSignedHalfword, out, cls, offset);
2350 break;
2351 }
2352
2353 case Primitive::kPrimChar: {
2354 Register out = locations->Out().As<Register>();
2355 __ LoadFromOffset(kLoadUnsignedHalfword, out, cls, offset);
2356 break;
2357 }
2358
2359 case Primitive::kPrimInt:
2360 case Primitive::kPrimNot: {
2361 Register out = locations->Out().As<Register>();
2362 __ LoadFromOffset(kLoadWord, out, cls, offset);
2363 break;
2364 }
2365
2366 case Primitive::kPrimLong: {
2367 // TODO: support volatile.
2368 Location out = locations->Out();
2369 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), cls, offset);
2370 break;
2371 }
2372
2373 case Primitive::kPrimFloat:
2374 case Primitive::kPrimDouble:
2375 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
2376 UNREACHABLE();
2377 case Primitive::kPrimVoid:
2378 LOG(FATAL) << "Unreachable type " << instruction->GetType();
2379 UNREACHABLE();
2380 }
2381}
2382
2383void LocationsBuilderARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
2384 LocationSummary* locations =
2385 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
2386 bool is_object_type = instruction->GetFieldType() == Primitive::kPrimNot;
2387 locations->SetInAt(0, Location::RequiresRegister());
2388 locations->SetInAt(1, Location::RequiresRegister());
2389 // Temporary registers for the write barrier.
2390 if (is_object_type) {
2391 locations->AddTemp(Location::RequiresRegister());
2392 locations->AddTemp(Location::RequiresRegister());
2393 }
2394}
2395
2396void InstructionCodeGeneratorARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
2397 LocationSummary* locations = instruction->GetLocations();
2398 Register cls = locations->InAt(0).As<Register>();
2399 uint32_t offset = instruction->GetFieldOffset().Uint32Value();
2400 Primitive::Type field_type = instruction->GetFieldType();
2401
2402 switch (field_type) {
2403 case Primitive::kPrimBoolean:
2404 case Primitive::kPrimByte: {
2405 Register value = locations->InAt(1).As<Register>();
2406 __ StoreToOffset(kStoreByte, value, cls, offset);
2407 break;
2408 }
2409
2410 case Primitive::kPrimShort:
2411 case Primitive::kPrimChar: {
2412 Register value = locations->InAt(1).As<Register>();
2413 __ StoreToOffset(kStoreHalfword, value, cls, offset);
2414 break;
2415 }
2416
2417 case Primitive::kPrimInt:
2418 case Primitive::kPrimNot: {
2419 Register value = locations->InAt(1).As<Register>();
2420 __ StoreToOffset(kStoreWord, value, cls, offset);
2421 if (field_type == Primitive::kPrimNot) {
2422 Register temp = locations->GetTemp(0).As<Register>();
2423 Register card = locations->GetTemp(1).As<Register>();
2424 codegen_->MarkGCCard(temp, card, cls, value);
2425 }
2426 break;
2427 }
2428
2429 case Primitive::kPrimLong: {
2430 Location value = locations->InAt(1);
2431 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), cls, offset);
2432 break;
2433 }
2434
2435 case Primitive::kPrimFloat:
2436 case Primitive::kPrimDouble:
2437 LOG(FATAL) << "Unimplemented register type " << field_type;
2438 UNREACHABLE();
2439 case Primitive::kPrimVoid:
2440 LOG(FATAL) << "Unreachable type " << field_type;
2441 UNREACHABLE();
2442 }
2443}
2444
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00002445void LocationsBuilderARM::VisitLoadString(HLoadString* load) {
2446 LocationSummary* locations =
2447 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
2448 locations->SetOut(Location::RequiresRegister());
2449}
2450
2451void InstructionCodeGeneratorARM::VisitLoadString(HLoadString* load) {
2452 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathARM(load);
2453 codegen_->AddSlowPath(slow_path);
2454
2455 Register out = load->GetLocations()->Out().As<Register>();
2456 codegen_->LoadCurrentMethod(out);
2457 __ LoadFromOffset(
2458 kLoadWord, out, out, mirror::ArtMethod::DexCacheStringsOffset().Int32Value());
2459 __ LoadFromOffset(kLoadWord, out, out, CodeGenerator::GetCacheOffset(load->GetStringIndex()));
2460 __ cmp(out, ShifterOperand(0));
2461 __ b(slow_path->GetEntryLabel(), EQ);
2462 __ Bind(slow_path->GetExitLabel());
2463}
2464
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00002465} // namespace arm
2466} // namespace art