blob: e0e0c797c6c921f9272c29a4e4f1bae88162b71f [file] [log] [blame]
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001/*
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_x86_64.h"
18
19#include "entrypoints/quick/quick_entrypoints.h"
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +010020#include "gc/accounting/card_table.h"
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010021#include "mirror/array.h"
22#include "mirror/art_method.h"
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +010023#include "mirror/class.h"
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010024#include "mirror/object_reference.h"
25#include "thread.h"
26#include "utils/assembler.h"
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010027#include "utils/stack_checks.h"
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010028#include "utils/x86_64/assembler_x86_64.h"
29#include "utils/x86_64/managed_register_x86_64.h"
30
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010031namespace art {
32
33x86_64::X86_64ManagedRegister Location::AsX86_64() const {
34 return reg().AsX86_64();
35}
36
37namespace x86_64 {
38
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +010039static constexpr bool kExplicitStackOverflowCheck = false;
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010040
41// Some x86_64 instructions require a register to be available as temp.
42static constexpr Register TMP = R11;
43
44static constexpr int kNumberOfPushedRegistersAtEntry = 1;
45static constexpr int kCurrentMethodStackOffset = 0;
46
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010047static Location X86_64CpuLocation(Register reg) {
48 return Location::RegisterLocation(X86_64ManagedRegister::FromCpuRegister(reg));
49}
50
51static constexpr Register kRuntimeParameterCoreRegisters[] = { RDI, RSI, RDX };
52static constexpr size_t kRuntimeParameterCoreRegistersLength =
53 arraysize(kRuntimeParameterCoreRegisters);
54
55class InvokeRuntimeCallingConvention : public CallingConvention<Register> {
56 public:
57 InvokeRuntimeCallingConvention()
58 : CallingConvention(kRuntimeParameterCoreRegisters,
59 kRuntimeParameterCoreRegistersLength) {}
60
61 private:
62 DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention);
63};
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010064
Nicolas Geoffraye5038322014-07-04 09:41:32 +010065#define __ reinterpret_cast<X86_64Assembler*>(codegen->GetAssembler())->
66
67class NullCheckSlowPathX86_64 : public SlowPathCode {
68 public:
Nicolas Geoffray39468442014-09-02 15:17:15 +010069 explicit NullCheckSlowPathX86_64(HNullCheck* instruction) : instruction_(instruction) {}
Nicolas Geoffraye5038322014-07-04 09:41:32 +010070
71 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
72 __ Bind(GetEntryLabel());
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010073 __ gs()->call(
74 Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pThrowNullPointer), true));
Nicolas Geoffray39468442014-09-02 15:17:15 +010075 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
Nicolas Geoffraye5038322014-07-04 09:41:32 +010076 }
77
78 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +010079 HNullCheck* const instruction_;
Nicolas Geoffraye5038322014-07-04 09:41:32 +010080 DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathX86_64);
81};
82
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010083class StackOverflowCheckSlowPathX86_64 : public SlowPathCode {
84 public:
85 StackOverflowCheckSlowPathX86_64() {}
86
87 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
88 __ Bind(GetEntryLabel());
89 __ addq(CpuRegister(RSP),
90 Immediate(codegen->GetFrameSize() - kNumberOfPushedRegistersAtEntry * kX86_64WordSize));
91 __ gs()->jmp(
92 Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pThrowStackOverflow), true));
93 }
94
95 private:
96 DISALLOW_COPY_AND_ASSIGN(StackOverflowCheckSlowPathX86_64);
97};
98
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +000099class SuspendCheckSlowPathX86_64 : public SlowPathCode {
100 public:
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100101 explicit SuspendCheckSlowPathX86_64(HSuspendCheck* instruction, HBasicBlock* successor)
102 : instruction_(instruction), successor_(successor) {}
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000103
104 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
105 __ Bind(GetEntryLabel());
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100106 codegen->SaveLiveRegisters(instruction_->GetLocations());
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000107 __ gs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pTestSuspend), true));
108 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100109 codegen->RestoreLiveRegisters(instruction_->GetLocations());
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100110 if (successor_ == nullptr) {
111 __ jmp(GetReturnLabel());
112 } else {
113 __ jmp(codegen->GetLabelOf(successor_));
114 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000115 }
116
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100117 Label* GetReturnLabel() {
118 DCHECK(successor_ == nullptr);
119 return &return_label_;
120 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000121
122 private:
123 HSuspendCheck* const instruction_;
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100124 HBasicBlock* const successor_;
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000125 Label return_label_;
126
127 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathX86_64);
128};
129
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100130class BoundsCheckSlowPathX86_64 : public SlowPathCode {
131 public:
Roland Levillain5799fc02014-09-25 12:15:20 +0100132 BoundsCheckSlowPathX86_64(HBoundsCheck* instruction,
133 Location index_location,
134 Location length_location)
Nicolas Geoffray39468442014-09-02 15:17:15 +0100135 : instruction_(instruction),
136 index_location_(index_location),
137 length_location_(length_location) {}
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100138
139 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
140 CodeGeneratorX86_64* x64_codegen = reinterpret_cast<CodeGeneratorX86_64*>(codegen);
141 __ Bind(GetEntryLabel());
142 InvokeRuntimeCallingConvention calling_convention;
143 x64_codegen->Move(X86_64CpuLocation(calling_convention.GetRegisterAt(0)), index_location_);
144 x64_codegen->Move(X86_64CpuLocation(calling_convention.GetRegisterAt(1)), length_location_);
145 __ gs()->call(Address::Absolute(
146 QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pThrowArrayBounds), true));
Nicolas Geoffray39468442014-09-02 15:17:15 +0100147 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100148 }
149
150 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100151 HBoundsCheck* const instruction_;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100152 const Location index_location_;
153 const Location length_location_;
154
155 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathX86_64);
156};
157
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100158#undef __
159#define __ reinterpret_cast<X86_64Assembler*>(GetAssembler())->
160
Dave Allison20dfc792014-06-16 20:44:29 -0700161inline Condition X86_64Condition(IfCondition cond) {
162 switch (cond) {
163 case kCondEQ: return kEqual;
164 case kCondNE: return kNotEqual;
165 case kCondLT: return kLess;
166 case kCondLE: return kLessEqual;
167 case kCondGT: return kGreater;
168 case kCondGE: return kGreaterEqual;
169 default:
170 LOG(FATAL) << "Unknown if condition";
171 }
172 return kEqual;
173}
174
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100175void CodeGeneratorX86_64::DumpCoreRegister(std::ostream& stream, int reg) const {
176 stream << X86_64ManagedRegister::FromCpuRegister(Register(reg));
177}
178
179void CodeGeneratorX86_64::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
180 stream << X86_64ManagedRegister::FromXmmRegister(FloatRegister(reg));
181}
182
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100183void CodeGeneratorX86_64::SaveCoreRegister(Location stack_location, uint32_t reg_id) {
184 __ movq(Address(CpuRegister(RSP), stack_location.GetStackIndex()), CpuRegister(reg_id));
185}
186
187void CodeGeneratorX86_64::RestoreCoreRegister(Location stack_location, uint32_t reg_id) {
188 __ movq(CpuRegister(reg_id), Address(CpuRegister(RSP), stack_location.GetStackIndex()));
189}
190
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100191CodeGeneratorX86_64::CodeGeneratorX86_64(HGraph* graph)
192 : CodeGenerator(graph, kNumberOfRegIds),
193 location_builder_(graph, this),
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000194 instruction_visitor_(graph, this),
195 move_resolver_(graph->GetArena(), this) {}
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100196
Nicolas Geoffrayab032bc2014-07-15 12:55:21 +0100197size_t CodeGeneratorX86_64::FrameEntrySpillSize() const {
198 return kNumberOfPushedRegistersAtEntry * kX86_64WordSize;
199}
200
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100201InstructionCodeGeneratorX86_64::InstructionCodeGeneratorX86_64(HGraph* graph,
202 CodeGeneratorX86_64* codegen)
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100203 : HGraphVisitor(graph),
204 assembler_(codegen->GetAssembler()),
205 codegen_(codegen) {}
206
207ManagedRegister CodeGeneratorX86_64::AllocateFreeRegister(Primitive::Type type,
208 bool* blocked_registers) const {
209 switch (type) {
210 case Primitive::kPrimLong:
211 case Primitive::kPrimByte:
212 case Primitive::kPrimBoolean:
213 case Primitive::kPrimChar:
214 case Primitive::kPrimShort:
215 case Primitive::kPrimInt:
216 case Primitive::kPrimNot: {
217 size_t reg = AllocateFreeRegisterInternal(blocked_registers, kNumberOfCpuRegisters);
218 return X86_64ManagedRegister::FromCpuRegister(static_cast<Register>(reg));
219 }
220
221 case Primitive::kPrimFloat:
222 case Primitive::kPrimDouble:
223 LOG(FATAL) << "Unimplemented register type " << type;
224
225 case Primitive::kPrimVoid:
226 LOG(FATAL) << "Unreachable type " << type;
227 }
228
229 return ManagedRegister::NoRegister();
230}
231
232void CodeGeneratorX86_64::SetupBlockedRegisters(bool* blocked_registers) const {
233 // Stack register is always reserved.
234 blocked_registers[RSP] = true;
235
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000236 // Block the register used as TMP.
237 blocked_registers[TMP] = true;
238
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100239 // TODO: We currently don't use Quick's callee saved registers.
240 blocked_registers[RBX] = true;
241 blocked_registers[RBP] = true;
242 blocked_registers[R12] = true;
243 blocked_registers[R13] = true;
244 blocked_registers[R14] = true;
245 blocked_registers[R15] = true;
246}
247
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100248void CodeGeneratorX86_64::GenerateFrameEntry() {
249 // Create a fake register to mimic Quick.
250 static const int kFakeReturnRegister = 16;
251 core_spill_mask_ |= (1 << kFakeReturnRegister);
252
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100253 bool skip_overflow_check = IsLeafMethod()
Dave Allison648d7112014-07-25 16:15:27 -0700254 && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kX86_64);
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100255
256 if (!skip_overflow_check && !kExplicitStackOverflowCheck) {
257 __ testq(CpuRegister(RAX), Address(
258 CpuRegister(RSP), -static_cast<int32_t>(GetStackOverflowReservedBytes(kX86_64))));
Nicolas Geoffray39468442014-09-02 15:17:15 +0100259 RecordPcInfo(nullptr, 0);
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100260 }
261
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100262 // The return PC has already been pushed on the stack.
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100263 __ subq(CpuRegister(RSP),
264 Immediate(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kX86_64WordSize));
265
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100266 if (!skip_overflow_check && kExplicitStackOverflowCheck) {
267 SlowPathCode* slow_path = new (GetGraph()->GetArena()) StackOverflowCheckSlowPathX86_64();
268 AddSlowPath(slow_path);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100269
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100270 __ gs()->cmpq(CpuRegister(RSP),
271 Address::Absolute(Thread::StackEndOffset<kX86_64WordSize>(), true));
272 __ j(kLess, slow_path->GetEntryLabel());
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100273 }
274
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100275 __ movl(Address(CpuRegister(RSP), kCurrentMethodStackOffset), CpuRegister(RDI));
276}
277
278void CodeGeneratorX86_64::GenerateFrameExit() {
279 __ addq(CpuRegister(RSP),
280 Immediate(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kX86_64WordSize));
281}
282
283void CodeGeneratorX86_64::Bind(Label* label) {
284 __ Bind(label);
285}
286
287void InstructionCodeGeneratorX86_64::LoadCurrentMethod(CpuRegister reg) {
288 __ movl(reg, Address(CpuRegister(RSP), kCurrentMethodStackOffset));
289}
290
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100291Location CodeGeneratorX86_64::GetStackLocation(HLoadLocal* load) const {
292 switch (load->GetType()) {
293 case Primitive::kPrimLong:
294 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
295 break;
296
297 case Primitive::kPrimInt:
298 case Primitive::kPrimNot:
299 return Location::StackSlot(GetStackSlot(load->GetLocal()));
300
301 case Primitive::kPrimFloat:
302 case Primitive::kPrimDouble:
303 LOG(FATAL) << "Unimplemented type " << load->GetType();
304
305 case Primitive::kPrimBoolean:
306 case Primitive::kPrimByte:
307 case Primitive::kPrimChar:
308 case Primitive::kPrimShort:
309 case Primitive::kPrimVoid:
310 LOG(FATAL) << "Unexpected type " << load->GetType();
311 }
312
313 LOG(FATAL) << "Unreachable";
314 return Location();
315}
316
317void CodeGeneratorX86_64::Move(Location destination, Location source) {
318 if (source.Equals(destination)) {
319 return;
320 }
321 if (destination.IsRegister()) {
322 if (source.IsRegister()) {
323 __ movq(destination.AsX86_64().AsCpuRegister(), source.AsX86_64().AsCpuRegister());
324 } else if (source.IsStackSlot()) {
325 __ movl(destination.AsX86_64().AsCpuRegister(), Address(CpuRegister(RSP), source.GetStackIndex()));
326 } else {
327 DCHECK(source.IsDoubleStackSlot());
328 __ movq(destination.AsX86_64().AsCpuRegister(), Address(CpuRegister(RSP), source.GetStackIndex()));
329 }
330 } else if (destination.IsStackSlot()) {
331 if (source.IsRegister()) {
332 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), source.AsX86_64().AsCpuRegister());
333 } else {
334 DCHECK(source.IsStackSlot());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000335 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
336 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100337 }
338 } else {
339 DCHECK(destination.IsDoubleStackSlot());
340 if (source.IsRegister()) {
341 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), source.AsX86_64().AsCpuRegister());
342 } else {
343 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000344 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
345 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100346 }
347 }
348}
349
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100350void CodeGeneratorX86_64::Move(HInstruction* instruction,
351 Location location,
352 HInstruction* move_for) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100353 if (instruction->AsIntConstant() != nullptr) {
354 Immediate imm(instruction->AsIntConstant()->GetValue());
355 if (location.IsRegister()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000356 __ movl(location.AsX86_64().AsCpuRegister(), imm);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100357 } else {
358 __ movl(Address(CpuRegister(RSP), location.GetStackIndex()), imm);
359 }
360 } else if (instruction->AsLongConstant() != nullptr) {
361 int64_t value = instruction->AsLongConstant()->GetValue();
362 if (location.IsRegister()) {
363 __ movq(location.AsX86_64().AsCpuRegister(), Immediate(value));
364 } else {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000365 __ movq(CpuRegister(TMP), Immediate(value));
366 __ movq(Address(CpuRegister(RSP), location.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100367 }
368 } else if (instruction->AsLoadLocal() != nullptr) {
369 switch (instruction->GetType()) {
370 case Primitive::kPrimBoolean:
371 case Primitive::kPrimByte:
372 case Primitive::kPrimChar:
373 case Primitive::kPrimShort:
374 case Primitive::kPrimInt:
375 case Primitive::kPrimNot:
376 Move(location, Location::StackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
377 break;
378
379 case Primitive::kPrimLong:
380 Move(location, Location::DoubleStackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
381 break;
382
383 default:
384 LOG(FATAL) << "Unimplemented local type " << instruction->GetType();
385 }
386 } else {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100387 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100388 switch (instruction->GetType()) {
389 case Primitive::kPrimBoolean:
390 case Primitive::kPrimByte:
391 case Primitive::kPrimChar:
392 case Primitive::kPrimShort:
393 case Primitive::kPrimInt:
394 case Primitive::kPrimNot:
395 case Primitive::kPrimLong:
396 Move(location, instruction->GetLocations()->Out());
397 break;
398
399 default:
400 LOG(FATAL) << "Unimplemented type " << instruction->GetType();
401 }
402 }
403}
404
405void LocationsBuilderX86_64::VisitGoto(HGoto* got) {
406 got->SetLocations(nullptr);
407}
408
409void InstructionCodeGeneratorX86_64::VisitGoto(HGoto* got) {
410 HBasicBlock* successor = got->GetSuccessor();
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100411 DCHECK(!successor->IsExitBlock());
412
413 HBasicBlock* block = got->GetBlock();
414 HInstruction* previous = got->GetPrevious();
415
416 HLoopInformation* info = block->GetLoopInformation();
417 if (info != nullptr && info->IsBackEdge(block) && info->HasSuspendCheck()) {
418 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck());
419 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
420 return;
421 }
422
423 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
424 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
425 }
426 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100427 __ jmp(codegen_->GetLabelOf(successor));
428 }
429}
430
431void LocationsBuilderX86_64::VisitExit(HExit* exit) {
432 exit->SetLocations(nullptr);
433}
434
435void InstructionCodeGeneratorX86_64::VisitExit(HExit* exit) {
436 if (kIsDebugBuild) {
437 __ Comment("Unreachable");
438 __ int3();
439 }
440}
441
442void LocationsBuilderX86_64::VisitIf(HIf* if_instr) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100443 LocationSummary* locations =
444 new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100445 HInstruction* cond = if_instr->InputAt(0);
446 DCHECK(cond->IsCondition());
447 HCondition* condition = cond->AsCondition();
448 if (condition->NeedsMaterialization()) {
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +0100449 locations->SetInAt(0, Location::Any(), Location::kDiesAtEntry);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100450 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100451}
452
453void InstructionCodeGeneratorX86_64::VisitIf(HIf* if_instr) {
Dave Allison20dfc792014-06-16 20:44:29 -0700454 HInstruction* cond = if_instr->InputAt(0);
455 DCHECK(cond->IsCondition());
456 HCondition* condition = cond->AsCondition();
457 if (condition->NeedsMaterialization()) {
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100458 // Moves do not affect the eflags register, so if the condition is evaluated
459 // just before the if, we don't need to evaluate it again.
460 if (!condition->IsBeforeWhenDisregardMoves(if_instr)) {
461 // Materialized condition, compare against 0.
462 Location lhs = if_instr->GetLocations()->InAt(0);
463 if (lhs.IsRegister()) {
464 __ cmpl(lhs.AsX86_64().AsCpuRegister(), Immediate(0));
465 } else {
466 __ cmpl(Address(CpuRegister(RSP), lhs.GetStackIndex()), Immediate(0));
467 }
Dave Allison20dfc792014-06-16 20:44:29 -0700468 }
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100469 __ j(kNotEqual, codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
Dave Allison20dfc792014-06-16 20:44:29 -0700470 } else {
471 Location lhs = condition->GetLocations()->InAt(0);
472 Location rhs = condition->GetLocations()->InAt(1);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100473 if (rhs.IsRegister()) {
474 __ cmpl(lhs.AsX86_64().AsCpuRegister(), rhs.AsX86_64().AsCpuRegister());
475 } else if (rhs.IsConstant()) {
476 __ cmpl(lhs.AsX86_64().AsCpuRegister(),
477 Immediate(rhs.GetConstant()->AsIntConstant()->GetValue()));
478 } else {
479 __ cmpl(lhs.AsX86_64().AsCpuRegister(), Address(CpuRegister(RSP), rhs.GetStackIndex()));
480 }
Dave Allison20dfc792014-06-16 20:44:29 -0700481 __ j(X86_64Condition(condition->GetCondition()),
482 codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
483 }
484 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfFalseSuccessor())) {
485 __ jmp(codegen_->GetLabelOf(if_instr->IfFalseSuccessor()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100486 }
487}
488
489void LocationsBuilderX86_64::VisitLocal(HLocal* local) {
490 local->SetLocations(nullptr);
491}
492
493void InstructionCodeGeneratorX86_64::VisitLocal(HLocal* local) {
494 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
495}
496
497void LocationsBuilderX86_64::VisitLoadLocal(HLoadLocal* local) {
498 local->SetLocations(nullptr);
499}
500
501void InstructionCodeGeneratorX86_64::VisitLoadLocal(HLoadLocal* load) {
502 // Nothing to do, this is driven by the code generator.
503}
504
505void LocationsBuilderX86_64::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100506 LocationSummary* locations =
507 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100508 switch (store->InputAt(1)->GetType()) {
509 case Primitive::kPrimBoolean:
510 case Primitive::kPrimByte:
511 case Primitive::kPrimChar:
512 case Primitive::kPrimShort:
513 case Primitive::kPrimInt:
514 case Primitive::kPrimNot:
515 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
516 break;
517
518 case Primitive::kPrimLong:
519 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
520 break;
521
522 default:
523 LOG(FATAL) << "Unimplemented local type " << store->InputAt(1)->GetType();
524 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100525}
526
527void InstructionCodeGeneratorX86_64::VisitStoreLocal(HStoreLocal* store) {
528}
529
Dave Allison20dfc792014-06-16 20:44:29 -0700530void LocationsBuilderX86_64::VisitCondition(HCondition* comp) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100531 LocationSummary* locations =
532 new (GetGraph()->GetArena()) LocationSummary(comp, LocationSummary::kNoCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +0100533 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
534 locations->SetInAt(1, Location::Any(), Location::kDiesAtEntry);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100535 if (comp->NeedsMaterialization()) {
536 locations->SetOut(Location::RequiresRegister());
537 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100538}
539
Dave Allison20dfc792014-06-16 20:44:29 -0700540void InstructionCodeGeneratorX86_64::VisitCondition(HCondition* comp) {
541 if (comp->NeedsMaterialization()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100542 LocationSummary* locations = comp->GetLocations();
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100543 CpuRegister reg = locations->Out().AsX86_64().AsCpuRegister();
544 // Clear register: setcc only sets the low byte.
545 __ xorq(reg, reg);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100546 if (locations->InAt(1).IsRegister()) {
547 __ cmpq(locations->InAt(0).AsX86_64().AsCpuRegister(),
548 locations->InAt(1).AsX86_64().AsCpuRegister());
549 } else if (locations->InAt(1).IsConstant()) {
550 __ cmpq(locations->InAt(0).AsX86_64().AsCpuRegister(),
551 Immediate(locations->InAt(1).GetConstant()->AsIntConstant()->GetValue()));
552 } else {
553 __ cmpq(locations->InAt(0).AsX86_64().AsCpuRegister(),
554 Address(CpuRegister(RSP), locations->InAt(1).GetStackIndex()));
555 }
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100556 __ setcc(X86_64Condition(comp->GetCondition()), reg);
Dave Allison20dfc792014-06-16 20:44:29 -0700557 }
558}
559
560void LocationsBuilderX86_64::VisitEqual(HEqual* comp) {
561 VisitCondition(comp);
562}
563
564void InstructionCodeGeneratorX86_64::VisitEqual(HEqual* comp) {
565 VisitCondition(comp);
566}
567
568void LocationsBuilderX86_64::VisitNotEqual(HNotEqual* comp) {
569 VisitCondition(comp);
570}
571
572void InstructionCodeGeneratorX86_64::VisitNotEqual(HNotEqual* comp) {
573 VisitCondition(comp);
574}
575
576void LocationsBuilderX86_64::VisitLessThan(HLessThan* comp) {
577 VisitCondition(comp);
578}
579
580void InstructionCodeGeneratorX86_64::VisitLessThan(HLessThan* comp) {
581 VisitCondition(comp);
582}
583
584void LocationsBuilderX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
585 VisitCondition(comp);
586}
587
588void InstructionCodeGeneratorX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
589 VisitCondition(comp);
590}
591
592void LocationsBuilderX86_64::VisitGreaterThan(HGreaterThan* comp) {
593 VisitCondition(comp);
594}
595
596void InstructionCodeGeneratorX86_64::VisitGreaterThan(HGreaterThan* comp) {
597 VisitCondition(comp);
598}
599
600void LocationsBuilderX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
601 VisitCondition(comp);
602}
603
604void InstructionCodeGeneratorX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
605 VisitCondition(comp);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100606}
607
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100608void LocationsBuilderX86_64::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100609 LocationSummary* locations =
610 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +0100611 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
612 locations->SetInAt(1, Location::RequiresRegister(), Location::kDiesAtEntry);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100613 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100614}
615
616void InstructionCodeGeneratorX86_64::VisitCompare(HCompare* compare) {
617 Label greater, done;
618 LocationSummary* locations = compare->GetLocations();
619 switch (compare->InputAt(0)->GetType()) {
620 case Primitive::kPrimLong:
621 __ cmpq(locations->InAt(0).AsX86_64().AsCpuRegister(),
622 locations->InAt(1).AsX86_64().AsCpuRegister());
623 break;
624 default:
625 LOG(FATAL) << "Unimplemented compare type " << compare->InputAt(0)->GetType();
626 }
627
628 __ movl(locations->Out().AsX86_64().AsCpuRegister(), Immediate(0));
629 __ j(kEqual, &done);
630 __ j(kGreater, &greater);
631
632 __ movl(locations->Out().AsX86_64().AsCpuRegister(), Immediate(-1));
633 __ jmp(&done);
634
635 __ Bind(&greater);
636 __ movl(locations->Out().AsX86_64().AsCpuRegister(), Immediate(1));
637
638 __ Bind(&done);
639}
640
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100641void LocationsBuilderX86_64::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100642 LocationSummary* locations =
643 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100644 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100645}
646
647void InstructionCodeGeneratorX86_64::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100648}
649
650void LocationsBuilderX86_64::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100651 LocationSummary* locations =
652 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100653 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100654}
655
656void InstructionCodeGeneratorX86_64::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100657}
658
659void LocationsBuilderX86_64::VisitReturnVoid(HReturnVoid* ret) {
660 ret->SetLocations(nullptr);
661}
662
663void InstructionCodeGeneratorX86_64::VisitReturnVoid(HReturnVoid* ret) {
664 codegen_->GenerateFrameExit();
665 __ ret();
666}
667
668void LocationsBuilderX86_64::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100669 LocationSummary* locations =
670 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100671 switch (ret->InputAt(0)->GetType()) {
672 case Primitive::kPrimBoolean:
673 case Primitive::kPrimByte:
674 case Primitive::kPrimChar:
675 case Primitive::kPrimShort:
676 case Primitive::kPrimInt:
677 case Primitive::kPrimNot:
678 case Primitive::kPrimLong:
679 locations->SetInAt(0, X86_64CpuLocation(RAX));
680 break;
681
682 default:
683 LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
684 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100685}
686
687void InstructionCodeGeneratorX86_64::VisitReturn(HReturn* ret) {
688 if (kIsDebugBuild) {
689 switch (ret->InputAt(0)->GetType()) {
690 case Primitive::kPrimBoolean:
691 case Primitive::kPrimByte:
692 case Primitive::kPrimChar:
693 case Primitive::kPrimShort:
694 case Primitive::kPrimInt:
695 case Primitive::kPrimNot:
696 case Primitive::kPrimLong:
697 DCHECK_EQ(ret->GetLocations()->InAt(0).AsX86_64().AsCpuRegister().AsRegister(), RAX);
698 break;
699
700 default:
701 LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
702 }
703 }
704 codegen_->GenerateFrameExit();
705 __ ret();
706}
707
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100708Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) {
709 switch (type) {
710 case Primitive::kPrimBoolean:
711 case Primitive::kPrimByte:
712 case Primitive::kPrimChar:
713 case Primitive::kPrimShort:
714 case Primitive::kPrimInt:
715 case Primitive::kPrimNot: {
716 uint32_t index = gp_index_++;
717 stack_index_++;
718 if (index < calling_convention.GetNumberOfRegisters()) {
719 return X86_64CpuLocation(calling_convention.GetRegisterAt(index));
720 } else {
721 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
722 }
723 }
724
725 case Primitive::kPrimLong: {
726 uint32_t index = gp_index_;
727 stack_index_ += 2;
728 if (index < calling_convention.GetNumberOfRegisters()) {
729 gp_index_ += 1;
730 return X86_64CpuLocation(calling_convention.GetRegisterAt(index));
731 } else {
732 gp_index_ += 2;
733 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
734 }
735 }
736
737 case Primitive::kPrimDouble:
738 case Primitive::kPrimFloat:
739 LOG(FATAL) << "Unimplemented parameter type " << type;
740 break;
741
742 case Primitive::kPrimVoid:
743 LOG(FATAL) << "Unexpected parameter type " << type;
744 break;
745 }
746 return Location();
747}
748
749void LocationsBuilderX86_64::VisitInvokeStatic(HInvokeStatic* invoke) {
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100750 HandleInvoke(invoke);
751}
752
753void InstructionCodeGeneratorX86_64::VisitInvokeStatic(HInvokeStatic* invoke) {
754 CpuRegister temp = invoke->GetLocations()->GetTemp(0).AsX86_64().AsCpuRegister();
755 uint32_t heap_reference_size = sizeof(mirror::HeapReference<mirror::Object>);
756 size_t index_in_cache = mirror::Array::DataOffset(heap_reference_size).SizeValue() +
757 invoke->GetIndexInDexCache() * heap_reference_size;
758
759 // TODO: Implement all kinds of calls:
760 // 1) boot -> boot
761 // 2) app -> boot
762 // 3) app -> app
763 //
764 // Currently we implement the app -> app logic, which looks up in the resolve cache.
765
766 // temp = method;
767 LoadCurrentMethod(temp);
768 // temp = temp->dex_cache_resolved_methods_;
769 __ movl(temp, Address(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().SizeValue()));
770 // temp = temp[index_in_cache]
771 __ movl(temp, Address(temp, index_in_cache));
772 // (temp + offset_of_quick_compiled_code)()
773 __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().SizeValue()));
774
775 DCHECK(!codegen_->IsLeafMethod());
776 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
777}
778
779void LocationsBuilderX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
780 HandleInvoke(invoke);
781}
782
783void LocationsBuilderX86_64::HandleInvoke(HInvoke* invoke) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100784 LocationSummary* locations =
785 new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100786 locations->AddTemp(X86_64CpuLocation(RDI));
787
788 InvokeDexCallingConventionVisitor calling_convention_visitor;
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100789 for (size_t i = 0; i < invoke->InputCount(); i++) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100790 HInstruction* input = invoke->InputAt(i);
791 locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
792 }
793
794 switch (invoke->GetType()) {
795 case Primitive::kPrimBoolean:
796 case Primitive::kPrimByte:
797 case Primitive::kPrimChar:
798 case Primitive::kPrimShort:
799 case Primitive::kPrimInt:
800 case Primitive::kPrimNot:
801 case Primitive::kPrimLong:
802 locations->SetOut(X86_64CpuLocation(RAX));
803 break;
804
805 case Primitive::kPrimVoid:
806 break;
807
808 case Primitive::kPrimDouble:
809 case Primitive::kPrimFloat:
810 LOG(FATAL) << "Unimplemented return type " << invoke->GetType();
811 break;
812 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100813}
814
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100815void InstructionCodeGeneratorX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100816 CpuRegister temp = invoke->GetLocations()->GetTemp(0).AsX86_64().AsCpuRegister();
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100817 size_t method_offset = mirror::Class::EmbeddedVTableOffset().SizeValue() +
818 invoke->GetVTableIndex() * sizeof(mirror::Class::VTableEntry);
819 LocationSummary* locations = invoke->GetLocations();
820 Location receiver = locations->InAt(0);
821 size_t class_offset = mirror::Object::ClassOffset().SizeValue();
822 // temp = object->GetClass();
823 if (receiver.IsStackSlot()) {
824 __ movq(temp, Address(CpuRegister(RSP), receiver.GetStackIndex()));
825 __ movq(temp, Address(temp, class_offset));
826 } else {
827 __ movq(temp, Address(receiver.AsX86_64().AsCpuRegister(), class_offset));
828 }
829 // temp = temp->GetMethodAt(method_offset);
830 __ movl(temp, Address(temp, method_offset));
831 // call temp->GetEntryPoint();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100832 __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().SizeValue()));
833
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100834 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray39468442014-09-02 15:17:15 +0100835 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100836}
837
838void LocationsBuilderX86_64::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100839 LocationSummary* locations =
840 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100841 switch (add->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100842 case Primitive::kPrimInt: {
843 locations->SetInAt(0, Location::RequiresRegister());
844 locations->SetInAt(1, Location::Any());
845 locations->SetOut(Location::SameAsFirstInput());
846 break;
847 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100848 case Primitive::kPrimLong: {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000849 locations->SetInAt(0, Location::RequiresRegister());
850 locations->SetInAt(1, Location::RequiresRegister());
851 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100852 break;
853 }
854
855 case Primitive::kPrimBoolean:
856 case Primitive::kPrimByte:
857 case Primitive::kPrimChar:
858 case Primitive::kPrimShort:
859 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
860 break;
861
862 default:
863 LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
864 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100865}
866
867void InstructionCodeGeneratorX86_64::VisitAdd(HAdd* add) {
868 LocationSummary* locations = add->GetLocations();
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000869 DCHECK_EQ(locations->InAt(0).AsX86_64().AsCpuRegister().AsRegister(),
870 locations->Out().AsX86_64().AsCpuRegister().AsRegister());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100871 switch (add->GetResultType()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000872 case Primitive::kPrimInt: {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100873 if (locations->InAt(1).IsRegister()) {
874 __ addl(locations->InAt(0).AsX86_64().AsCpuRegister(),
875 locations->InAt(1).AsX86_64().AsCpuRegister());
876 } else if (locations->InAt(1).IsConstant()) {
877 HConstant* instruction = locations->InAt(1).GetConstant();
878 Immediate imm(instruction->AsIntConstant()->GetValue());
879 __ addl(locations->InAt(0).AsX86_64().AsCpuRegister(), imm);
880 } else {
881 __ addl(locations->InAt(0).AsX86_64().AsCpuRegister(),
882 Address(CpuRegister(RSP), locations->InAt(1).GetStackIndex()));
883 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000884 break;
885 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100886 case Primitive::kPrimLong: {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100887 __ addq(locations->InAt(0).AsX86_64().AsCpuRegister(),
888 locations->InAt(1).AsX86_64().AsCpuRegister());
889 break;
890 }
891
892 case Primitive::kPrimBoolean:
893 case Primitive::kPrimByte:
894 case Primitive::kPrimChar:
895 case Primitive::kPrimShort:
896 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
897 break;
898
899 default:
900 LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
901 }
902}
903
904void LocationsBuilderX86_64::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100905 LocationSummary* locations =
906 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100907 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100908 case Primitive::kPrimInt: {
909 locations->SetInAt(0, Location::RequiresRegister());
910 locations->SetInAt(1, Location::Any());
911 locations->SetOut(Location::SameAsFirstInput());
912 break;
913 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100914 case Primitive::kPrimLong: {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000915 locations->SetInAt(0, Location::RequiresRegister());
916 locations->SetInAt(1, Location::RequiresRegister());
917 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100918 break;
919 }
920
921 case Primitive::kPrimBoolean:
922 case Primitive::kPrimByte:
923 case Primitive::kPrimChar:
924 case Primitive::kPrimShort:
925 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
926 break;
927
928 default:
929 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
930 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100931}
932
933void InstructionCodeGeneratorX86_64::VisitSub(HSub* sub) {
934 LocationSummary* locations = sub->GetLocations();
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000935 DCHECK_EQ(locations->InAt(0).AsX86_64().AsCpuRegister().AsRegister(),
936 locations->Out().AsX86_64().AsCpuRegister().AsRegister());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100937 switch (sub->GetResultType()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000938 case Primitive::kPrimInt: {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100939 if (locations->InAt(1).IsRegister()) {
940 __ subl(locations->InAt(0).AsX86_64().AsCpuRegister(),
941 locations->InAt(1).AsX86_64().AsCpuRegister());
942 } else if (locations->InAt(1).IsConstant()) {
943 HConstant* instruction = locations->InAt(1).GetConstant();
944 Immediate imm(instruction->AsIntConstant()->GetValue());
945 __ subl(locations->InAt(0).AsX86_64().AsCpuRegister(), imm);
946 } else {
947 __ subl(locations->InAt(0).AsX86_64().AsCpuRegister(),
948 Address(CpuRegister(RSP), locations->InAt(1).GetStackIndex()));
949 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000950 break;
951 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100952 case Primitive::kPrimLong: {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100953 __ subq(locations->InAt(0).AsX86_64().AsCpuRegister(),
954 locations->InAt(1).AsX86_64().AsCpuRegister());
955 break;
956 }
957
958 case Primitive::kPrimBoolean:
959 case Primitive::kPrimByte:
960 case Primitive::kPrimChar:
961 case Primitive::kPrimShort:
962 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
963 break;
964
965 default:
966 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
967 }
968}
969
970void LocationsBuilderX86_64::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100971 LocationSummary* locations =
972 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +0100973 InvokeRuntimeCallingConvention calling_convention;
974 locations->AddTemp(X86_64CpuLocation(calling_convention.GetRegisterAt(0)));
975 locations->AddTemp(X86_64CpuLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100976 locations->SetOut(X86_64CpuLocation(RAX));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100977}
978
979void InstructionCodeGeneratorX86_64::VisitNewInstance(HNewInstance* instruction) {
980 InvokeRuntimeCallingConvention calling_convention;
981 LoadCurrentMethod(CpuRegister(calling_convention.GetRegisterAt(1)));
982 __ movq(CpuRegister(calling_convention.GetRegisterAt(0)), Immediate(instruction->GetTypeIndex()));
983
984 __ gs()->call(Address::Absolute(
985 QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pAllocObjectWithAccessCheck), true));
986
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100987 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray39468442014-09-02 15:17:15 +0100988 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100989}
990
991void LocationsBuilderX86_64::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100992 LocationSummary* locations =
993 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100994 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
995 if (location.IsStackSlot()) {
996 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
997 } else if (location.IsDoubleStackSlot()) {
998 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
999 }
1000 locations->SetOut(location);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001001}
1002
1003void InstructionCodeGeneratorX86_64::VisitParameterValue(HParameterValue* instruction) {
1004 // Nothing to do, the parameter is already at its location.
1005}
1006
1007void LocationsBuilderX86_64::VisitNot(HNot* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001008 LocationSummary* locations =
1009 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001010 locations->SetInAt(0, Location::RequiresRegister());
1011 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001012}
1013
1014void InstructionCodeGeneratorX86_64::VisitNot(HNot* instruction) {
1015 LocationSummary* locations = instruction->GetLocations();
1016 DCHECK_EQ(locations->InAt(0).AsX86_64().AsCpuRegister().AsRegister(),
1017 locations->Out().AsX86_64().AsCpuRegister().AsRegister());
1018 __ xorq(locations->Out().AsX86_64().AsCpuRegister(), Immediate(1));
1019}
1020
1021void LocationsBuilderX86_64::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001022 LocationSummary* locations =
1023 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001024 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
1025 locations->SetInAt(i, Location::Any());
1026 }
1027 locations->SetOut(Location::Any());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001028}
1029
1030void InstructionCodeGeneratorX86_64::VisitPhi(HPhi* instruction) {
1031 LOG(FATAL) << "Unimplemented";
1032}
1033
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001034void LocationsBuilderX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001035 LocationSummary* locations =
1036 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001037 Primitive::Type field_type = instruction->GetFieldType();
1038 bool is_object_type = field_type == Primitive::kPrimNot;
1039 bool dies_at_entry = !is_object_type;
1040 locations->SetInAt(0, Location::RequiresRegister(), dies_at_entry);
1041 locations->SetInAt(1, Location::RequiresRegister(), dies_at_entry);
1042 if (is_object_type) {
1043 // Temporary registers for the write barrier.
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001044 locations->AddTemp(Location::RequiresRegister());
1045 locations->AddTemp(Location::RequiresRegister());
1046 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001047}
1048
1049void InstructionCodeGeneratorX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
1050 LocationSummary* locations = instruction->GetLocations();
1051 CpuRegister obj = locations->InAt(0).AsX86_64().AsCpuRegister();
1052 CpuRegister value = locations->InAt(1).AsX86_64().AsCpuRegister();
1053 size_t offset = instruction->GetFieldOffset().SizeValue();
Nicolas Geoffray39468442014-09-02 15:17:15 +01001054 Primitive::Type field_type = instruction->GetFieldType();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001055
1056 switch (field_type) {
1057 case Primitive::kPrimBoolean:
1058 case Primitive::kPrimByte: {
1059 __ movb(Address(obj, offset), value);
1060 break;
1061 }
1062
1063 case Primitive::kPrimShort:
1064 case Primitive::kPrimChar: {
1065 __ movw(Address(obj, offset), value);
1066 break;
1067 }
1068
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001069 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001070 case Primitive::kPrimNot: {
1071 __ movl(Address(obj, offset), value);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001072 if (field_type == Primitive::kPrimNot) {
1073 CpuRegister temp = locations->GetTemp(0).AsX86_64().AsCpuRegister();
1074 CpuRegister card = locations->GetTemp(1).AsX86_64().AsCpuRegister();
1075 codegen_->MarkGCCard(temp, card, obj, value);
1076 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001077 break;
1078 }
1079
1080 case Primitive::kPrimLong: {
1081 __ movq(Address(obj, offset), value);
1082 break;
1083 }
1084
1085 case Primitive::kPrimFloat:
1086 case Primitive::kPrimDouble:
1087 LOG(FATAL) << "Unimplemented register type " << field_type;
1088
1089 case Primitive::kPrimVoid:
1090 LOG(FATAL) << "Unreachable type " << field_type;
1091 }
1092}
1093
1094void LocationsBuilderX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001095 LocationSummary* locations =
1096 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001097 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001098 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001099}
1100
1101void InstructionCodeGeneratorX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
1102 LocationSummary* locations = instruction->GetLocations();
1103 CpuRegister obj = locations->InAt(0).AsX86_64().AsCpuRegister();
1104 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1105 size_t offset = instruction->GetFieldOffset().SizeValue();
1106
1107 switch (instruction->GetType()) {
1108 case Primitive::kPrimBoolean: {
1109 __ movzxb(out, Address(obj, offset));
1110 break;
1111 }
1112
1113 case Primitive::kPrimByte: {
1114 __ movsxb(out, Address(obj, offset));
1115 break;
1116 }
1117
1118 case Primitive::kPrimShort: {
1119 __ movsxw(out, Address(obj, offset));
1120 break;
1121 }
1122
1123 case Primitive::kPrimChar: {
1124 __ movzxw(out, Address(obj, offset));
1125 break;
1126 }
1127
1128 case Primitive::kPrimInt:
1129 case Primitive::kPrimNot: {
1130 __ movl(out, Address(obj, offset));
1131 break;
1132 }
1133
1134 case Primitive::kPrimLong: {
1135 __ movq(out, Address(obj, offset));
1136 break;
1137 }
1138
1139 case Primitive::kPrimFloat:
1140 case Primitive::kPrimDouble:
1141 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1142
1143 case Primitive::kPrimVoid:
1144 LOG(FATAL) << "Unreachable type " << instruction->GetType();
1145 }
1146}
1147
1148void LocationsBuilderX86_64::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001149 LocationSummary* locations =
1150 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001151 locations->SetInAt(0, Location::Any());
1152 // TODO: Have a normalization phase that makes this instruction never used.
1153 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001154}
1155
1156void InstructionCodeGeneratorX86_64::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001157 SlowPathCode* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathX86_64(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001158 codegen_->AddSlowPath(slow_path);
1159
1160 LocationSummary* locations = instruction->GetLocations();
1161 Location obj = locations->InAt(0);
1162 DCHECK(obj.Equals(locations->Out()));
1163
1164 if (obj.IsRegister()) {
1165 __ cmpl(obj.AsX86_64().AsCpuRegister(), Immediate(0));
1166 } else {
1167 DCHECK(locations->InAt(0).IsStackSlot());
1168 __ cmpl(Address(CpuRegister(RSP), obj.GetStackIndex()), Immediate(0));
1169 }
1170 __ j(kEqual, slow_path->GetEntryLabel());
1171}
1172
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001173void LocationsBuilderX86_64::VisitArrayGet(HArrayGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001174 LocationSummary* locations =
1175 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001176 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
1177 locations->SetInAt(
1178 1, Location::RegisterOrConstant(instruction->InputAt(1)), Location::kDiesAtEntry);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001179 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001180}
1181
1182void InstructionCodeGeneratorX86_64::VisitArrayGet(HArrayGet* instruction) {
1183 LocationSummary* locations = instruction->GetLocations();
1184 CpuRegister obj = locations->InAt(0).AsX86_64().AsCpuRegister();
1185 Location index = locations->InAt(1);
1186
1187 switch (instruction->GetType()) {
1188 case Primitive::kPrimBoolean: {
1189 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
1190 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1191 if (index.IsConstant()) {
1192 __ movzxb(out, Address(obj,
1193 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
1194 } else {
1195 __ movzxb(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_1, data_offset));
1196 }
1197 break;
1198 }
1199
1200 case Primitive::kPrimByte: {
1201 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
1202 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1203 if (index.IsConstant()) {
1204 __ movsxb(out, Address(obj,
1205 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
1206 } else {
1207 __ movsxb(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_1, data_offset));
1208 }
1209 break;
1210 }
1211
1212 case Primitive::kPrimShort: {
1213 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
1214 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1215 if (index.IsConstant()) {
1216 __ movsxw(out, Address(obj,
1217 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
1218 } else {
1219 __ movsxw(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_2, data_offset));
1220 }
1221 break;
1222 }
1223
1224 case Primitive::kPrimChar: {
1225 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
1226 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1227 if (index.IsConstant()) {
1228 __ movzxw(out, Address(obj,
1229 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
1230 } else {
1231 __ movzxw(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_2, data_offset));
1232 }
1233 break;
1234 }
1235
1236 case Primitive::kPrimInt:
1237 case Primitive::kPrimNot: {
1238 DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t));
1239 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
1240 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1241 if (index.IsConstant()) {
1242 __ movl(out, Address(obj,
1243 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
1244 } else {
1245 __ movl(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_4, data_offset));
1246 }
1247 break;
1248 }
1249
1250 case Primitive::kPrimLong: {
1251 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
1252 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1253 if (index.IsConstant()) {
1254 __ movq(out, Address(obj,
1255 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
1256 } else {
1257 __ movq(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_8, data_offset));
1258 }
1259 break;
1260 }
1261
1262 case Primitive::kPrimFloat:
1263 case Primitive::kPrimDouble:
1264 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1265
1266 case Primitive::kPrimVoid:
1267 LOG(FATAL) << "Unreachable type " << instruction->GetType();
1268 }
1269}
1270
1271void LocationsBuilderX86_64::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001272 Primitive::Type value_type = instruction->GetComponentType();
1273 bool is_object = value_type == Primitive::kPrimNot;
1274 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
1275 instruction, is_object ? LocationSummary::kCall : LocationSummary::kNoCall);
1276 if (is_object) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001277 InvokeRuntimeCallingConvention calling_convention;
1278 locations->SetInAt(0, X86_64CpuLocation(calling_convention.GetRegisterAt(0)));
1279 locations->SetInAt(1, X86_64CpuLocation(calling_convention.GetRegisterAt(1)));
1280 locations->SetInAt(2, X86_64CpuLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001281 } else {
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001282 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
1283 locations->SetInAt(
1284 1, Location::RegisterOrConstant(instruction->InputAt(1)), Location::kDiesAtEntry);
1285 locations->SetInAt(2, Location::RequiresRegister(), Location::kDiesAtEntry);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001286 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001287}
1288
1289void InstructionCodeGeneratorX86_64::VisitArraySet(HArraySet* instruction) {
1290 LocationSummary* locations = instruction->GetLocations();
1291 CpuRegister obj = locations->InAt(0).AsX86_64().AsCpuRegister();
1292 Location index = locations->InAt(1);
Nicolas Geoffray39468442014-09-02 15:17:15 +01001293 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001294
1295 switch (value_type) {
1296 case Primitive::kPrimBoolean:
1297 case Primitive::kPrimByte: {
1298 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
1299 CpuRegister value = locations->InAt(2).AsX86_64().AsCpuRegister();
1300 if (index.IsConstant()) {
1301 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
1302 __ movb(Address(obj, offset), value);
1303 } else {
1304 __ movb(Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_1, data_offset), value);
1305 }
1306 break;
1307 }
1308
1309 case Primitive::kPrimShort:
1310 case Primitive::kPrimChar: {
1311 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
1312 CpuRegister value = locations->InAt(2).AsX86_64().AsCpuRegister();
1313 if (index.IsConstant()) {
1314 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
1315 __ movw(Address(obj, offset), value);
1316 } else {
1317 __ movw(Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_2, data_offset), value);
1318 }
1319 break;
1320 }
1321
1322 case Primitive::kPrimInt: {
1323 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
1324 CpuRegister value = locations->InAt(2).AsX86_64().AsCpuRegister();
1325 if (index.IsConstant()) {
1326 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
1327 __ movl(Address(obj, offset), value);
1328 } else {
1329 __ movl(Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_4, data_offset), value);
1330 }
1331 break;
1332 }
1333
1334 case Primitive::kPrimNot: {
1335 __ gs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pAputObject), true));
1336 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray39468442014-09-02 15:17:15 +01001337 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001338 break;
1339 }
1340
1341 case Primitive::kPrimLong: {
1342 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
1343 CpuRegister value = locations->InAt(2).AsX86_64().AsCpuRegister();
1344 if (index.IsConstant()) {
1345 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
1346 __ movq(Address(obj, offset), value);
1347 } else {
1348 __ movq(Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_8, data_offset), value);
1349 }
1350 break;
1351 }
1352
1353 case Primitive::kPrimFloat:
1354 case Primitive::kPrimDouble:
1355 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1356
1357 case Primitive::kPrimVoid:
1358 LOG(FATAL) << "Unreachable type " << instruction->GetType();
1359 }
1360}
1361
1362void LocationsBuilderX86_64::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001363 LocationSummary* locations =
1364 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001365 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001366 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001367}
1368
1369void InstructionCodeGeneratorX86_64::VisitArrayLength(HArrayLength* instruction) {
1370 LocationSummary* locations = instruction->GetLocations();
1371 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
1372 CpuRegister obj = locations->InAt(0).AsX86_64().AsCpuRegister();
1373 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1374 __ movl(out, Address(obj, offset));
1375}
1376
1377void LocationsBuilderX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001378 LocationSummary* locations =
1379 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001380 locations->SetInAt(0, Location::RequiresRegister());
1381 locations->SetInAt(1, Location::RequiresRegister());
1382 // TODO: Have a normalization phase that makes this instruction never used.
1383 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001384}
1385
1386void InstructionCodeGeneratorX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
1387 LocationSummary* locations = instruction->GetLocations();
1388 SlowPathCode* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathX86_64(
Nicolas Geoffray39468442014-09-02 15:17:15 +01001389 instruction, locations->InAt(0), locations->InAt(1));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001390 codegen_->AddSlowPath(slow_path);
1391
1392 CpuRegister index = locations->InAt(0).AsX86_64().AsCpuRegister();
1393 CpuRegister length = locations->InAt(1).AsX86_64().AsCpuRegister();
1394
1395 __ cmpl(index, length);
1396 __ j(kAboveEqual, slow_path->GetEntryLabel());
1397}
1398
1399void CodeGeneratorX86_64::MarkGCCard(CpuRegister temp,
1400 CpuRegister card,
1401 CpuRegister object,
1402 CpuRegister value) {
1403 Label is_null;
1404 __ testl(value, value);
1405 __ j(kEqual, &is_null);
1406 __ gs()->movq(card, Address::Absolute(
1407 Thread::CardTableOffset<kX86_64WordSize>().Int32Value(), true));
1408 __ movq(temp, object);
1409 __ shrq(temp, Immediate(gc::accounting::CardTable::kCardShift));
1410 __ movb(Address(temp, card, TIMES_1, 0), card);
1411 __ Bind(&is_null);
1412}
1413
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001414void LocationsBuilderX86_64::VisitTemporary(HTemporary* temp) {
1415 temp->SetLocations(nullptr);
1416}
1417
1418void InstructionCodeGeneratorX86_64::VisitTemporary(HTemporary* temp) {
1419 // Nothing to do, this is driven by the code generator.
1420}
1421
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001422void LocationsBuilderX86_64::VisitParallelMove(HParallelMove* instruction) {
1423 LOG(FATAL) << "Unimplemented";
1424}
1425
1426void InstructionCodeGeneratorX86_64::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001427 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
1428}
1429
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00001430void LocationsBuilderX86_64::VisitSuspendCheck(HSuspendCheck* instruction) {
1431 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
1432}
1433
1434void InstructionCodeGeneratorX86_64::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001435 HBasicBlock* block = instruction->GetBlock();
1436 if (block->GetLoopInformation() != nullptr) {
1437 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
1438 // The back edge will generate the suspend check.
1439 return;
1440 }
1441 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
1442 // The goto will generate the suspend check.
1443 return;
1444 }
1445 GenerateSuspendCheck(instruction, nullptr);
1446}
1447
1448void InstructionCodeGeneratorX86_64::GenerateSuspendCheck(HSuspendCheck* instruction,
1449 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00001450 SuspendCheckSlowPathX86_64* slow_path =
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001451 new (GetGraph()->GetArena()) SuspendCheckSlowPathX86_64(instruction, successor);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00001452 codegen_->AddSlowPath(slow_path);
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001453 __ gs()->cmpw(Address::Absolute(
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00001454 Thread::ThreadFlagsOffset<kX86_64WordSize>().Int32Value(), true), Immediate(0));
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001455 if (successor == nullptr) {
1456 __ j(kNotEqual, slow_path->GetEntryLabel());
1457 __ Bind(slow_path->GetReturnLabel());
1458 } else {
1459 __ j(kEqual, codegen_->GetLabelOf(successor));
1460 __ jmp(slow_path->GetEntryLabel());
1461 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00001462}
1463
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001464X86_64Assembler* ParallelMoveResolverX86_64::GetAssembler() const {
1465 return codegen_->GetAssembler();
1466}
1467
1468void ParallelMoveResolverX86_64::EmitMove(size_t index) {
1469 MoveOperands* move = moves_.Get(index);
1470 Location source = move->GetSource();
1471 Location destination = move->GetDestination();
1472
1473 if (source.IsRegister()) {
1474 if (destination.IsRegister()) {
1475 __ movq(destination.AsX86_64().AsCpuRegister(), source.AsX86_64().AsCpuRegister());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001476 } else if (destination.IsStackSlot()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001477 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()),
1478 source.AsX86_64().AsCpuRegister());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001479 } else {
1480 DCHECK(destination.IsDoubleStackSlot());
1481 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()),
1482 source.AsX86_64().AsCpuRegister());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001483 }
1484 } else if (source.IsStackSlot()) {
1485 if (destination.IsRegister()) {
1486 __ movl(destination.AsX86_64().AsX86_64().AsCpuRegister(),
1487 Address(CpuRegister(RSP), source.GetStackIndex()));
1488 } else {
1489 DCHECK(destination.IsStackSlot());
1490 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
1491 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
1492 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001493 } else if (source.IsDoubleStackSlot()) {
1494 if (destination.IsRegister()) {
1495 __ movq(destination.AsX86_64().AsX86_64().AsCpuRegister(),
1496 Address(CpuRegister(RSP), source.GetStackIndex()));
1497 } else {
1498 DCHECK(destination.IsDoubleStackSlot());
1499 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
1500 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
1501 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001502 } else if (source.IsConstant()) {
1503 HConstant* constant = source.GetConstant();
1504 if (constant->IsIntConstant()) {
1505 Immediate imm(constant->AsIntConstant()->GetValue());
1506 if (destination.IsRegister()) {
1507 __ movl(destination.AsX86_64().AsCpuRegister(), imm);
1508 } else {
1509 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), imm);
1510 }
1511 } else if (constant->IsLongConstant()) {
1512 int64_t value = constant->AsLongConstant()->GetValue();
1513 if (destination.IsRegister()) {
1514 __ movq(destination.AsX86_64().AsCpuRegister(), Immediate(value));
1515 } else {
1516 __ movq(CpuRegister(TMP), Immediate(value));
1517 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
1518 }
1519 } else {
1520 LOG(FATAL) << "Unimplemented constant type";
1521 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001522 } else {
1523 LOG(FATAL) << "Unimplemented";
1524 }
1525}
1526
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001527void ParallelMoveResolverX86_64::Exchange32(CpuRegister reg, int mem) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001528 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001529 __ movl(Address(CpuRegister(RSP), mem), reg);
1530 __ movl(reg, CpuRegister(TMP));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001531}
1532
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001533void ParallelMoveResolverX86_64::Exchange32(int mem1, int mem2) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001534 ScratchRegisterScope ensure_scratch(
1535 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
1536
1537 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
1538 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
1539 __ movl(CpuRegister(ensure_scratch.GetRegister()),
1540 Address(CpuRegister(RSP), mem2 + stack_offset));
1541 __ movl(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
1542 __ movl(Address(CpuRegister(RSP), mem1 + stack_offset),
1543 CpuRegister(ensure_scratch.GetRegister()));
1544}
1545
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001546void ParallelMoveResolverX86_64::Exchange64(CpuRegister reg, int mem) {
1547 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
1548 __ movq(Address(CpuRegister(RSP), mem), reg);
1549 __ movq(reg, CpuRegister(TMP));
1550}
1551
1552void ParallelMoveResolverX86_64::Exchange64(int mem1, int mem2) {
1553 ScratchRegisterScope ensure_scratch(
1554 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
1555
1556 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
1557 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
1558 __ movq(CpuRegister(ensure_scratch.GetRegister()),
1559 Address(CpuRegister(RSP), mem2 + stack_offset));
1560 __ movq(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
1561 __ movq(Address(CpuRegister(RSP), mem1 + stack_offset),
1562 CpuRegister(ensure_scratch.GetRegister()));
1563}
1564
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001565void ParallelMoveResolverX86_64::EmitSwap(size_t index) {
1566 MoveOperands* move = moves_.Get(index);
1567 Location source = move->GetSource();
1568 Location destination = move->GetDestination();
1569
1570 if (source.IsRegister() && destination.IsRegister()) {
1571 __ xchgq(destination.AsX86_64().AsCpuRegister(), source.AsX86_64().AsCpuRegister());
1572 } else if (source.IsRegister() && destination.IsStackSlot()) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001573 Exchange32(source.AsX86_64().AsCpuRegister(), destination.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001574 } else if (source.IsStackSlot() && destination.IsRegister()) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001575 Exchange32(destination.AsX86_64().AsCpuRegister(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001576 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001577 Exchange32(destination.GetStackIndex(), source.GetStackIndex());
1578 } else if (source.IsRegister() && destination.IsDoubleStackSlot()) {
1579 Exchange64(source.AsX86_64().AsCpuRegister(), destination.GetStackIndex());
1580 } else if (source.IsDoubleStackSlot() && destination.IsRegister()) {
1581 Exchange64(destination.AsX86_64().AsCpuRegister(), source.GetStackIndex());
1582 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
1583 Exchange64(destination.GetStackIndex(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001584 } else {
1585 LOG(FATAL) << "Unimplemented";
1586 }
1587}
1588
1589
1590void ParallelMoveResolverX86_64::SpillScratch(int reg) {
1591 __ pushq(CpuRegister(reg));
1592}
1593
1594
1595void ParallelMoveResolverX86_64::RestoreScratch(int reg) {
1596 __ popq(CpuRegister(reg));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001597}
1598
1599} // namespace x86_64
1600} // namespace art