blob: 90b7bdaac31241b9db112ae1b0089ce2245a1653 [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"
Andreas Gampe71fb52f2014-12-29 17:43:08 -080021#include "intrinsics.h"
22#include "intrinsics_x86_64.h"
Ian Rogers7e70b002014-10-08 11:47:24 -070023#include "mirror/array-inl.h"
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010024#include "mirror/art_method.h"
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +010025#include "mirror/class.h"
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010026#include "mirror/object_reference.h"
27#include "thread.h"
28#include "utils/assembler.h"
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010029#include "utils/stack_checks.h"
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010030#include "utils/x86_64/assembler_x86_64.h"
31#include "utils/x86_64/managed_register_x86_64.h"
32
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010033namespace art {
34
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010035namespace x86_64 {
36
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010037// Some x86_64 instructions require a register to be available as temp.
38static constexpr Register TMP = R11;
39
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010040static constexpr int kCurrentMethodStackOffset = 0;
41
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010042static constexpr Register kRuntimeParameterCoreRegisters[] = { RDI, RSI, RDX };
43static constexpr size_t kRuntimeParameterCoreRegistersLength =
44 arraysize(kRuntimeParameterCoreRegisters);
Calin Juravled2ec87d2014-12-08 14:24:46 +000045static constexpr FloatRegister kRuntimeParameterFpuRegisters[] = { XMM0, XMM1 };
46static constexpr size_t kRuntimeParameterFpuRegistersLength =
47 arraysize(kRuntimeParameterFpuRegisters);
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +000048static constexpr Register kCoreCalleeSaves[] = { RBX, RBP, R12, R13, R14, R15 };
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +000049static constexpr FloatRegister kFpuCalleeSaves[] = { XMM12, XMM13, XMM14, XMM15 };
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010050
Mark Mendell24f2dfa2015-01-14 19:51:45 -050051static constexpr int kC2ConditionMask = 0x400;
52
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +010053class InvokeRuntimeCallingConvention : public CallingConvention<Register, FloatRegister> {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010054 public:
55 InvokeRuntimeCallingConvention()
56 : CallingConvention(kRuntimeParameterCoreRegisters,
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +010057 kRuntimeParameterCoreRegistersLength,
58 kRuntimeParameterFpuRegisters,
59 kRuntimeParameterFpuRegistersLength) {}
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010060
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
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +010067class NullCheckSlowPathX86_64 : public SlowPathCodeX86_64 {
Nicolas Geoffraye5038322014-07-04 09:41:32 +010068 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
Calin Juravled0d48522014-11-04 16:40:20 +000083class DivZeroCheckSlowPathX86_64 : public SlowPathCodeX86_64 {
84 public:
85 explicit DivZeroCheckSlowPathX86_64(HDivZeroCheck* instruction) : instruction_(instruction) {}
86
87 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
88 __ Bind(GetEntryLabel());
89 __ gs()->call(
90 Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pThrowDivZero), true));
91 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
92 }
93
94 private:
95 HDivZeroCheck* const instruction_;
96 DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathX86_64);
97};
98
Calin Juravlebacfec32014-11-14 15:54:36 +000099class DivRemMinusOneSlowPathX86_64 : public SlowPathCodeX86_64 {
Calin Juravled0d48522014-11-04 16:40:20 +0000100 public:
Calin Juravlebacfec32014-11-14 15:54:36 +0000101 explicit DivRemMinusOneSlowPathX86_64(Register reg, Primitive::Type type, bool is_div)
102 : cpu_reg_(CpuRegister(reg)), type_(type), is_div_(is_div) {}
Calin Juravled0d48522014-11-04 16:40:20 +0000103
104 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
105 __ Bind(GetEntryLabel());
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000106 if (type_ == Primitive::kPrimInt) {
Calin Juravlebacfec32014-11-14 15:54:36 +0000107 if (is_div_) {
108 __ negl(cpu_reg_);
109 } else {
110 __ movl(cpu_reg_, Immediate(0));
111 }
112
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000113 } else {
114 DCHECK_EQ(Primitive::kPrimLong, type_);
Calin Juravlebacfec32014-11-14 15:54:36 +0000115 if (is_div_) {
116 __ negq(cpu_reg_);
117 } else {
118 __ movq(cpu_reg_, Immediate(0));
119 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000120 }
Calin Juravled0d48522014-11-04 16:40:20 +0000121 __ jmp(GetExitLabel());
122 }
123
124 private:
Calin Juravlebacfec32014-11-14 15:54:36 +0000125 const CpuRegister cpu_reg_;
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000126 const Primitive::Type type_;
Calin Juravlebacfec32014-11-14 15:54:36 +0000127 const bool is_div_;
128 DISALLOW_COPY_AND_ASSIGN(DivRemMinusOneSlowPathX86_64);
Calin Juravled0d48522014-11-04 16:40:20 +0000129};
130
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100131class SuspendCheckSlowPathX86_64 : public SlowPathCodeX86_64 {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000132 public:
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100133 explicit SuspendCheckSlowPathX86_64(HSuspendCheck* instruction, HBasicBlock* successor)
134 : instruction_(instruction), successor_(successor) {}
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000135
136 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100137 CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000138 __ Bind(GetEntryLabel());
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100139 codegen->SaveLiveRegisters(instruction_->GetLocations());
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000140 __ gs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pTestSuspend), true));
141 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100142 codegen->RestoreLiveRegisters(instruction_->GetLocations());
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100143 if (successor_ == nullptr) {
144 __ jmp(GetReturnLabel());
145 } else {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100146 __ jmp(x64_codegen->GetLabelOf(successor_));
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100147 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000148 }
149
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100150 Label* GetReturnLabel() {
151 DCHECK(successor_ == nullptr);
152 return &return_label_;
153 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000154
155 private:
156 HSuspendCheck* const instruction_;
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100157 HBasicBlock* const successor_;
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000158 Label return_label_;
159
160 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathX86_64);
161};
162
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100163class BoundsCheckSlowPathX86_64 : public SlowPathCodeX86_64 {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100164 public:
Roland Levillain5799fc02014-09-25 12:15:20 +0100165 BoundsCheckSlowPathX86_64(HBoundsCheck* instruction,
166 Location index_location,
167 Location length_location)
Nicolas Geoffray39468442014-09-02 15:17:15 +0100168 : instruction_(instruction),
169 index_location_(index_location),
170 length_location_(length_location) {}
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100171
172 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100173 __ Bind(GetEntryLabel());
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000174 // We're moving two locations to locations that could overlap, so we need a parallel
175 // move resolver.
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100176 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000177 codegen->EmitParallelMoves(
178 index_location_,
179 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
180 length_location_,
181 Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100182 __ gs()->call(Address::Absolute(
183 QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pThrowArrayBounds), true));
Nicolas Geoffray39468442014-09-02 15:17:15 +0100184 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100185 }
186
187 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100188 HBoundsCheck* const instruction_;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100189 const Location index_location_;
190 const Location length_location_;
191
192 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathX86_64);
193};
194
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000195class LoadClassSlowPathX86_64 : public SlowPathCodeX86_64 {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100196 public:
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000197 LoadClassSlowPathX86_64(HLoadClass* cls,
198 HInstruction* at,
199 uint32_t dex_pc,
200 bool do_clinit)
201 : cls_(cls), at_(at), dex_pc_(dex_pc), do_clinit_(do_clinit) {
202 DCHECK(at->IsLoadClass() || at->IsClinitCheck());
203 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100204
205 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000206 LocationSummary* locations = at_->GetLocations();
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100207 CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
208 __ Bind(GetEntryLabel());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100209
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000210 codegen->SaveLiveRegisters(locations);
211
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100212 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000213 __ movl(CpuRegister(calling_convention.GetRegisterAt(0)), Immediate(cls_->GetTypeIndex()));
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100214 x64_codegen->LoadCurrentMethod(CpuRegister(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000215 __ gs()->call(Address::Absolute((do_clinit_
216 ? QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pInitializeStaticStorage)
217 : QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pInitializeType)) , true));
218 codegen->RecordPcInfo(at_, dex_pc_);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100219
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000220 Location out = locations->Out();
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000221 // Move the class to the desired location.
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000222 if (out.IsValid()) {
223 DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
224 x64_codegen->Move(out, Location::RegisterLocation(RAX));
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000225 }
226
227 codegen->RestoreLiveRegisters(locations);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100228 __ jmp(GetExitLabel());
229 }
230
231 private:
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000232 // The class this slow path will load.
233 HLoadClass* const cls_;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100234
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000235 // The instruction where this slow path is happening.
236 // (Might be the load class or an initialization check).
237 HInstruction* const at_;
238
239 // The dex PC of `at_`.
240 const uint32_t dex_pc_;
241
242 // Whether to initialize the class.
243 const bool do_clinit_;
244
245 DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathX86_64);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100246};
247
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000248class LoadStringSlowPathX86_64 : public SlowPathCodeX86_64 {
249 public:
250 explicit LoadStringSlowPathX86_64(HLoadString* instruction) : instruction_(instruction) {}
251
252 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
253 LocationSummary* locations = instruction_->GetLocations();
254 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
255
256 CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
257 __ Bind(GetEntryLabel());
258 codegen->SaveLiveRegisters(locations);
259
260 InvokeRuntimeCallingConvention calling_convention;
Andreas Gampe1cc7dba2014-12-17 18:43:01 -0800261 x64_codegen->LoadCurrentMethod(CpuRegister(calling_convention.GetRegisterAt(1)));
262 __ movl(CpuRegister(calling_convention.GetRegisterAt(0)),
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000263 Immediate(instruction_->GetStringIndex()));
264 __ gs()->call(Address::Absolute(
265 QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pResolveString), true));
266 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
267 x64_codegen->Move(locations->Out(), Location::RegisterLocation(RAX));
268 codegen->RestoreLiveRegisters(locations);
269 __ jmp(GetExitLabel());
270 }
271
272 private:
273 HLoadString* const instruction_;
274
275 DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathX86_64);
276};
277
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000278class TypeCheckSlowPathX86_64 : public SlowPathCodeX86_64 {
279 public:
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000280 TypeCheckSlowPathX86_64(HInstruction* instruction,
281 Location class_to_check,
282 Location object_class,
283 uint32_t dex_pc)
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000284 : instruction_(instruction),
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000285 class_to_check_(class_to_check),
286 object_class_(object_class),
287 dex_pc_(dex_pc) {}
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000288
289 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
290 LocationSummary* locations = instruction_->GetLocations();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000291 DCHECK(instruction_->IsCheckCast()
292 || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000293
294 CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
295 __ Bind(GetEntryLabel());
296 codegen->SaveLiveRegisters(locations);
297
298 // We're moving two locations to locations that could overlap, so we need a parallel
299 // move resolver.
300 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000301 codegen->EmitParallelMoves(
302 class_to_check_,
303 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
304 object_class_,
305 Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000306
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000307 if (instruction_->IsInstanceOf()) {
308 __ gs()->call(
309 Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pInstanceofNonTrivial), true));
310 } else {
311 DCHECK(instruction_->IsCheckCast());
312 __ gs()->call(
313 Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pCheckCast), true));
314 }
315 codegen->RecordPcInfo(instruction_, dex_pc_);
316
317 if (instruction_->IsInstanceOf()) {
318 x64_codegen->Move(locations->Out(), Location::RegisterLocation(RAX));
319 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000320
321 codegen->RestoreLiveRegisters(locations);
322 __ jmp(GetExitLabel());
323 }
324
325 private:
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000326 HInstruction* const instruction_;
327 const Location class_to_check_;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000328 const Location object_class_;
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000329 const uint32_t dex_pc_;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000330
331 DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathX86_64);
332};
333
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100334#undef __
335#define __ reinterpret_cast<X86_64Assembler*>(GetAssembler())->
336
Dave Allison20dfc792014-06-16 20:44:29 -0700337inline Condition X86_64Condition(IfCondition cond) {
338 switch (cond) {
339 case kCondEQ: return kEqual;
340 case kCondNE: return kNotEqual;
341 case kCondLT: return kLess;
342 case kCondLE: return kLessEqual;
343 case kCondGT: return kGreater;
344 case kCondGE: return kGreaterEqual;
345 default:
346 LOG(FATAL) << "Unknown if condition";
347 }
348 return kEqual;
349}
350
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800351void CodeGeneratorX86_64::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke,
352 CpuRegister temp) {
353 // All registers are assumed to be correctly set up.
354
355 // TODO: Implement all kinds of calls:
356 // 1) boot -> boot
357 // 2) app -> boot
358 // 3) app -> app
359 //
360 // Currently we implement the app -> app logic, which looks up in the resolve cache.
361
362 // temp = method;
363 LoadCurrentMethod(temp);
Nicolas Geoffray1cf95282014-12-12 19:22:03 +0000364 if (!invoke->IsRecursive()) {
365 // temp = temp->dex_cache_resolved_methods_;
366 __ movl(temp, Address(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().SizeValue()));
367 // temp = temp[index_in_cache]
368 __ movl(temp, Address(temp, CodeGenerator::GetCacheOffset(invoke->GetDexMethodIndex())));
369 // (temp + offset_of_quick_compiled_code)()
370 __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(
371 kX86_64WordSize).SizeValue()));
372 } else {
373 __ call(&frame_entry_label_);
374 }
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800375
376 DCHECK(!IsLeafMethod());
377 RecordPcInfo(invoke, invoke->GetDexPc());
378}
379
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100380void CodeGeneratorX86_64::DumpCoreRegister(std::ostream& stream, int reg) const {
381 stream << X86_64ManagedRegister::FromCpuRegister(Register(reg));
382}
383
384void CodeGeneratorX86_64::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
385 stream << X86_64ManagedRegister::FromXmmRegister(FloatRegister(reg));
386}
387
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100388size_t CodeGeneratorX86_64::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
389 __ movq(Address(CpuRegister(RSP), stack_index), CpuRegister(reg_id));
390 return kX86_64WordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100391}
392
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100393size_t CodeGeneratorX86_64::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
394 __ movq(CpuRegister(reg_id), Address(CpuRegister(RSP), stack_index));
395 return kX86_64WordSize;
396}
397
398size_t CodeGeneratorX86_64::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
399 __ movsd(Address(CpuRegister(RSP), stack_index), XmmRegister(reg_id));
400 return kX86_64WordSize;
401}
402
403size_t CodeGeneratorX86_64::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
404 __ movsd(XmmRegister(reg_id), Address(CpuRegister(RSP), stack_index));
405 return kX86_64WordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100406}
407
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000408static constexpr int kNumberOfCpuRegisterPairs = 0;
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +0000409// Use a fake return address register to mimic Quick.
410static constexpr Register kFakeReturnRegister = Register(kLastCpuRegister + 1);
Calin Juravlecd6dffe2015-01-08 17:35:35 +0000411CodeGeneratorX86_64::CodeGeneratorX86_64(HGraph* graph, const CompilerOptions& compiler_options)
Nicolas Geoffray98893962015-01-21 12:32:32 +0000412 : CodeGenerator(graph,
413 kNumberOfCpuRegisters,
414 kNumberOfFloatRegisters,
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000415 kNumberOfCpuRegisterPairs,
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000416 ComputeRegisterMask(reinterpret_cast<const int*>(kCoreCalleeSaves),
417 arraysize(kCoreCalleeSaves))
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +0000418 | (1 << kFakeReturnRegister),
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000419 ComputeRegisterMask(reinterpret_cast<const int*>(kFpuCalleeSaves),
420 arraysize(kFpuCalleeSaves)),
Nicolas Geoffray98893962015-01-21 12:32:32 +0000421 compiler_options),
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100422 block_labels_(graph->GetArena(), 0),
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100423 location_builder_(graph, this),
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000424 instruction_visitor_(graph, this),
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000425 move_resolver_(graph->GetArena(), this) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000426 AddAllocatedRegister(Location::RegisterLocation(kFakeReturnRegister));
427}
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100428
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100429InstructionCodeGeneratorX86_64::InstructionCodeGeneratorX86_64(HGraph* graph,
430 CodeGeneratorX86_64* codegen)
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100431 : HGraphVisitor(graph),
432 assembler_(codegen->GetAssembler()),
433 codegen_(codegen) {}
434
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100435Location CodeGeneratorX86_64::AllocateFreeRegister(Primitive::Type type) const {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100436 switch (type) {
437 case Primitive::kPrimLong:
438 case Primitive::kPrimByte:
439 case Primitive::kPrimBoolean:
440 case Primitive::kPrimChar:
441 case Primitive::kPrimShort:
442 case Primitive::kPrimInt:
443 case Primitive::kPrimNot: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100444 size_t reg = FindFreeEntry(blocked_core_registers_, kNumberOfCpuRegisters);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100445 return Location::RegisterLocation(reg);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100446 }
447
448 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100449 case Primitive::kPrimDouble: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100450 size_t reg = FindFreeEntry(blocked_fpu_registers_, kNumberOfFloatRegisters);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100451 return Location::FpuRegisterLocation(reg);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100452 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100453
454 case Primitive::kPrimVoid:
455 LOG(FATAL) << "Unreachable type " << type;
456 }
457
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100458 return Location();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100459}
460
Nicolas Geoffray98893962015-01-21 12:32:32 +0000461void CodeGeneratorX86_64::SetupBlockedRegisters(bool is_baseline) const {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100462 // Stack register is always reserved.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100463 blocked_core_registers_[RSP] = true;
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100464
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000465 // Block the register used as TMP.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100466 blocked_core_registers_[TMP] = true;
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000467
Nicolas Geoffray98893962015-01-21 12:32:32 +0000468 if (is_baseline) {
469 for (size_t i = 0; i < arraysize(kCoreCalleeSaves); ++i) {
470 blocked_core_registers_[kCoreCalleeSaves[i]] = true;
471 }
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000472 for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
473 blocked_fpu_registers_[kFpuCalleeSaves[i]] = true;
474 }
Nicolas Geoffray98893962015-01-21 12:32:32 +0000475 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100476}
477
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100478void CodeGeneratorX86_64::GenerateFrameEntry() {
Nicolas Geoffray1cf95282014-12-12 19:22:03 +0000479 __ Bind(&frame_entry_label_);
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100480 bool skip_overflow_check = IsLeafMethod()
Dave Allison648d7112014-07-25 16:15:27 -0700481 && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kX86_64);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000482 DCHECK(GetCompilerOptions().GetImplicitStackOverflowChecks());
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100483
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000484 if (!skip_overflow_check) {
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100485 __ testq(CpuRegister(RAX), Address(
486 CpuRegister(RSP), -static_cast<int32_t>(GetStackOverflowReservedBytes(kX86_64))));
Nicolas Geoffray39468442014-09-02 15:17:15 +0100487 RecordPcInfo(nullptr, 0);
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100488 }
Nicolas Geoffraya26369a2015-01-22 08:46:05 +0000489
Nicolas Geoffray98893962015-01-21 12:32:32 +0000490 for (int i = arraysize(kCoreCalleeSaves) - 1; i >= 0; --i) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000491 Register reg = kCoreCalleeSaves[i];
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +0000492 if (allocated_registers_.ContainsCoreRegister(reg)) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000493 __ pushq(CpuRegister(reg));
Nicolas Geoffray98893962015-01-21 12:32:32 +0000494 }
495 }
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100496
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000497 __ subq(CpuRegister(RSP), Immediate(GetFrameSize() - GetCoreSpillSize()));
498 uint32_t xmm_spill_location = GetFpuSpillStart();
499 size_t xmm_spill_slot_size = GetFloatingPointSpillSlotSize();
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100500
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000501 for (int i = arraysize(kFpuCalleeSaves) - 1; i >= 0; --i) {
502 if (allocated_registers_.ContainsFloatingPointRegister(kFpuCalleeSaves[i])) {
503 __ movsd(Address(CpuRegister(RSP), xmm_spill_location + (xmm_spill_slot_size * i)),
504 XmmRegister(kFpuCalleeSaves[i]));
505 }
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100506 }
507
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100508 __ movl(Address(CpuRegister(RSP), kCurrentMethodStackOffset), CpuRegister(RDI));
509}
510
511void CodeGeneratorX86_64::GenerateFrameExit() {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000512 uint32_t xmm_spill_location = GetFpuSpillStart();
513 size_t xmm_spill_slot_size = GetFloatingPointSpillSlotSize();
514 for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
515 if (allocated_registers_.ContainsFloatingPointRegister(kFpuCalleeSaves[i])) {
516 __ movsd(XmmRegister(kFpuCalleeSaves[i]),
517 Address(CpuRegister(RSP), xmm_spill_location + (xmm_spill_slot_size * i)));
518 }
519 }
520
521 __ addq(CpuRegister(RSP), Immediate(GetFrameSize() - GetCoreSpillSize()));
Nicolas Geoffray98893962015-01-21 12:32:32 +0000522
523 for (size_t i = 0; i < arraysize(kCoreCalleeSaves); ++i) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000524 Register reg = kCoreCalleeSaves[i];
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +0000525 if (allocated_registers_.ContainsCoreRegister(reg)) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000526 __ popq(CpuRegister(reg));
Nicolas Geoffray98893962015-01-21 12:32:32 +0000527 }
528 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100529}
530
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100531void CodeGeneratorX86_64::Bind(HBasicBlock* block) {
532 __ Bind(GetLabelOf(block));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100533}
534
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100535void CodeGeneratorX86_64::LoadCurrentMethod(CpuRegister reg) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100536 __ movl(reg, Address(CpuRegister(RSP), kCurrentMethodStackOffset));
537}
538
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100539Location CodeGeneratorX86_64::GetStackLocation(HLoadLocal* load) const {
540 switch (load->GetType()) {
541 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100542 case Primitive::kPrimDouble:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100543 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
544 break;
545
546 case Primitive::kPrimInt:
547 case Primitive::kPrimNot:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100548 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100549 return Location::StackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100550
551 case Primitive::kPrimBoolean:
552 case Primitive::kPrimByte:
553 case Primitive::kPrimChar:
554 case Primitive::kPrimShort:
555 case Primitive::kPrimVoid:
556 LOG(FATAL) << "Unexpected type " << load->GetType();
557 }
558
559 LOG(FATAL) << "Unreachable";
560 return Location();
561}
562
563void CodeGeneratorX86_64::Move(Location destination, Location source) {
564 if (source.Equals(destination)) {
565 return;
566 }
567 if (destination.IsRegister()) {
568 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000569 __ movq(destination.AsRegister<CpuRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100570 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000571 __ movd(destination.AsRegister<CpuRegister>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100572 } else if (source.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000573 __ movl(destination.AsRegister<CpuRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100574 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100575 } else {
576 DCHECK(source.IsDoubleStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +0000577 __ movq(destination.AsRegister<CpuRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100578 Address(CpuRegister(RSP), source.GetStackIndex()));
579 }
580 } else if (destination.IsFpuRegister()) {
581 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000582 __ movd(destination.AsFpuRegister<XmmRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100583 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000584 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100585 } else if (source.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000586 __ movss(destination.AsFpuRegister<XmmRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100587 Address(CpuRegister(RSP), source.GetStackIndex()));
588 } else {
589 DCHECK(source.IsDoubleStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +0000590 __ movsd(destination.AsFpuRegister<XmmRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100591 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100592 }
593 } else if (destination.IsStackSlot()) {
594 if (source.IsRegister()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100595 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +0000596 source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100597 } else if (source.IsFpuRegister()) {
598 __ movss(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +0000599 source.AsFpuRegister<XmmRegister>());
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500600 } else if (source.IsConstant()) {
601 HConstant* constant = source.GetConstant();
602 int32_t value;
603 if (constant->IsFloatConstant()) {
604 value = bit_cast<float, int32_t>(constant->AsFloatConstant()->GetValue());
605 } else {
606 DCHECK(constant->IsIntConstant());
607 value = constant->AsIntConstant()->GetValue();
608 }
609 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), Immediate(value));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100610 } else {
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500611 DCHECK(source.IsStackSlot()) << source;
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000612 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
613 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100614 }
615 } else {
616 DCHECK(destination.IsDoubleStackSlot());
617 if (source.IsRegister()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100618 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +0000619 source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100620 } else if (source.IsFpuRegister()) {
621 __ movsd(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +0000622 source.AsFpuRegister<XmmRegister>());
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500623 } else if (source.IsConstant()) {
624 HConstant* constant = source.GetConstant();
625 int64_t value = constant->AsLongConstant()->GetValue();
626 if (constant->IsDoubleConstant()) {
627 value = bit_cast<double, int64_t>(constant->AsDoubleConstant()->GetValue());
628 } else {
629 DCHECK(constant->IsLongConstant());
630 value = constant->AsLongConstant()->GetValue();
631 }
632 __ movq(CpuRegister(TMP), Immediate(value));
633 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100634 } else {
635 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000636 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
637 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100638 }
639 }
640}
641
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100642void CodeGeneratorX86_64::Move(HInstruction* instruction,
643 Location location,
644 HInstruction* move_for) {
Calin Juravlea21f5982014-11-13 15:53:04 +0000645 LocationSummary* locations = instruction->GetLocations();
646 if (locations != nullptr && locations->Out().Equals(location)) {
647 return;
648 }
649
650 if (locations != nullptr && locations->Out().IsConstant()) {
651 HConstant* const_to_move = locations->Out().GetConstant();
652 if (const_to_move->IsIntConstant()) {
653 Immediate imm(const_to_move->AsIntConstant()->GetValue());
654 if (location.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000655 __ movl(location.AsRegister<CpuRegister>(), imm);
Calin Juravlea21f5982014-11-13 15:53:04 +0000656 } else if (location.IsStackSlot()) {
657 __ movl(Address(CpuRegister(RSP), location.GetStackIndex()), imm);
658 } else {
659 DCHECK(location.IsConstant());
660 DCHECK_EQ(location.GetConstant(), const_to_move);
661 }
662 } else if (const_to_move->IsLongConstant()) {
663 int64_t value = const_to_move->AsLongConstant()->GetValue();
664 if (location.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000665 __ movq(location.AsRegister<CpuRegister>(), Immediate(value));
Calin Juravlea21f5982014-11-13 15:53:04 +0000666 } else if (location.IsDoubleStackSlot()) {
667 __ movq(CpuRegister(TMP), Immediate(value));
668 __ movq(Address(CpuRegister(RSP), location.GetStackIndex()), CpuRegister(TMP));
669 } else {
670 DCHECK(location.IsConstant());
671 DCHECK_EQ(location.GetConstant(), const_to_move);
672 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100673 }
Roland Levillain476df552014-10-09 17:51:36 +0100674 } else if (instruction->IsLoadLocal()) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100675 switch (instruction->GetType()) {
676 case Primitive::kPrimBoolean:
677 case Primitive::kPrimByte:
678 case Primitive::kPrimChar:
679 case Primitive::kPrimShort:
680 case Primitive::kPrimInt:
681 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100682 case Primitive::kPrimFloat:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100683 Move(location, Location::StackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
684 break;
685
686 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100687 case Primitive::kPrimDouble:
Roland Levillain199f3362014-11-27 17:15:16 +0000688 Move(location,
689 Location::DoubleStackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100690 break;
691
692 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100693 LOG(FATAL) << "Unexpected local type " << instruction->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100694 }
Nicolas Geoffrayf43083d2014-11-07 10:48:10 +0000695 } else if (instruction->IsTemporary()) {
696 Location temp_location = GetTemporaryLocation(instruction->AsTemporary());
697 Move(location, temp_location);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100698 } else {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100699 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100700 switch (instruction->GetType()) {
701 case Primitive::kPrimBoolean:
702 case Primitive::kPrimByte:
703 case Primitive::kPrimChar:
704 case Primitive::kPrimShort:
705 case Primitive::kPrimInt:
706 case Primitive::kPrimNot:
707 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100708 case Primitive::kPrimFloat:
709 case Primitive::kPrimDouble:
Calin Juravlea21f5982014-11-13 15:53:04 +0000710 Move(location, locations->Out());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100711 break;
712
713 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100714 LOG(FATAL) << "Unexpected type " << instruction->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100715 }
716 }
717}
718
719void LocationsBuilderX86_64::VisitGoto(HGoto* got) {
720 got->SetLocations(nullptr);
721}
722
723void InstructionCodeGeneratorX86_64::VisitGoto(HGoto* got) {
724 HBasicBlock* successor = got->GetSuccessor();
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100725 DCHECK(!successor->IsExitBlock());
726
727 HBasicBlock* block = got->GetBlock();
728 HInstruction* previous = got->GetPrevious();
729
730 HLoopInformation* info = block->GetLoopInformation();
731 if (info != nullptr && info->IsBackEdge(block) && info->HasSuspendCheck()) {
732 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck());
733 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
734 return;
735 }
736
737 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
738 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
739 }
740 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100741 __ jmp(codegen_->GetLabelOf(successor));
742 }
743}
744
745void LocationsBuilderX86_64::VisitExit(HExit* exit) {
746 exit->SetLocations(nullptr);
747}
748
749void InstructionCodeGeneratorX86_64::VisitExit(HExit* exit) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700750 UNUSED(exit);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100751 if (kIsDebugBuild) {
752 __ Comment("Unreachable");
753 __ int3();
754 }
755}
756
757void LocationsBuilderX86_64::VisitIf(HIf* if_instr) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100758 LocationSummary* locations =
759 new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100760 HInstruction* cond = if_instr->InputAt(0);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100761 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +0100762 locations->SetInAt(0, Location::Any());
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100763 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100764}
765
766void InstructionCodeGeneratorX86_64::VisitIf(HIf* if_instr) {
Dave Allison20dfc792014-06-16 20:44:29 -0700767 HInstruction* cond = if_instr->InputAt(0);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100768 if (cond->IsIntConstant()) {
769 // Constant condition, statically compared against 1.
770 int32_t cond_value = cond->AsIntConstant()->GetValue();
771 if (cond_value == 1) {
772 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(),
773 if_instr->IfTrueSuccessor())) {
774 __ jmp(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100775 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100776 return;
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100777 } else {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100778 DCHECK_EQ(cond_value, 0);
779 }
780 } else {
781 bool materialized =
782 !cond->IsCondition() || cond->AsCondition()->NeedsMaterialization();
783 // Moves do not affect the eflags register, so if the condition is
784 // evaluated just before the if, we don't need to evaluate it
785 // again.
786 bool eflags_set = cond->IsCondition()
787 && cond->AsCondition()->IsBeforeWhenDisregardMoves(if_instr);
788 if (materialized) {
789 if (!eflags_set) {
790 // Materialized condition, compare against 0.
791 Location lhs = if_instr->GetLocations()->InAt(0);
792 if (lhs.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000793 __ cmpl(lhs.AsRegister<CpuRegister>(), Immediate(0));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100794 } else {
795 __ cmpl(Address(CpuRegister(RSP), lhs.GetStackIndex()),
796 Immediate(0));
797 }
798 __ j(kNotEqual, codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
799 } else {
800 __ j(X86_64Condition(cond->AsCondition()->GetCondition()),
801 codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
802 }
803 } else {
804 Location lhs = cond->GetLocations()->InAt(0);
805 Location rhs = cond->GetLocations()->InAt(1);
806 if (rhs.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000807 __ cmpl(lhs.AsRegister<CpuRegister>(), rhs.AsRegister<CpuRegister>());
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100808 } else if (rhs.IsConstant()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000809 __ cmpl(lhs.AsRegister<CpuRegister>(),
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100810 Immediate(rhs.GetConstant()->AsIntConstant()->GetValue()));
811 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000812 __ cmpl(lhs.AsRegister<CpuRegister>(),
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100813 Address(CpuRegister(RSP), rhs.GetStackIndex()));
814 }
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100815 __ j(X86_64Condition(cond->AsCondition()->GetCondition()),
816 codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
Dave Allison20dfc792014-06-16 20:44:29 -0700817 }
Dave Allison20dfc792014-06-16 20:44:29 -0700818 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100819 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(),
820 if_instr->IfFalseSuccessor())) {
Dave Allison20dfc792014-06-16 20:44:29 -0700821 __ jmp(codegen_->GetLabelOf(if_instr->IfFalseSuccessor()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100822 }
823}
824
825void LocationsBuilderX86_64::VisitLocal(HLocal* local) {
826 local->SetLocations(nullptr);
827}
828
829void InstructionCodeGeneratorX86_64::VisitLocal(HLocal* local) {
830 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
831}
832
833void LocationsBuilderX86_64::VisitLoadLocal(HLoadLocal* local) {
834 local->SetLocations(nullptr);
835}
836
837void InstructionCodeGeneratorX86_64::VisitLoadLocal(HLoadLocal* load) {
838 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700839 UNUSED(load);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100840}
841
842void LocationsBuilderX86_64::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100843 LocationSummary* locations =
844 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100845 switch (store->InputAt(1)->GetType()) {
846 case Primitive::kPrimBoolean:
847 case Primitive::kPrimByte:
848 case Primitive::kPrimChar:
849 case Primitive::kPrimShort:
850 case Primitive::kPrimInt:
851 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100852 case Primitive::kPrimFloat:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100853 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
854 break;
855
856 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100857 case Primitive::kPrimDouble:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100858 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
859 break;
860
861 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100862 LOG(FATAL) << "Unexpected local type " << store->InputAt(1)->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100863 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100864}
865
866void InstructionCodeGeneratorX86_64::VisitStoreLocal(HStoreLocal* store) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700867 UNUSED(store);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100868}
869
Dave Allison20dfc792014-06-16 20:44:29 -0700870void LocationsBuilderX86_64::VisitCondition(HCondition* comp) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100871 LocationSummary* locations =
872 new (GetGraph()->GetArena()) LocationSummary(comp, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +0100873 locations->SetInAt(0, Location::RequiresRegister());
874 locations->SetInAt(1, Location::Any());
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100875 if (comp->NeedsMaterialization()) {
876 locations->SetOut(Location::RequiresRegister());
877 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100878}
879
Dave Allison20dfc792014-06-16 20:44:29 -0700880void InstructionCodeGeneratorX86_64::VisitCondition(HCondition* comp) {
881 if (comp->NeedsMaterialization()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100882 LocationSummary* locations = comp->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +0000883 CpuRegister reg = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100884 // Clear register: setcc only sets the low byte.
885 __ xorq(reg, reg);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100886 if (locations->InAt(1).IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000887 __ cmpl(locations->InAt(0).AsRegister<CpuRegister>(),
888 locations->InAt(1).AsRegister<CpuRegister>());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100889 } else if (locations->InAt(1).IsConstant()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000890 __ cmpl(locations->InAt(0).AsRegister<CpuRegister>(),
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100891 Immediate(locations->InAt(1).GetConstant()->AsIntConstant()->GetValue()));
892 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000893 __ cmpl(locations->InAt(0).AsRegister<CpuRegister>(),
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100894 Address(CpuRegister(RSP), locations->InAt(1).GetStackIndex()));
895 }
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100896 __ setcc(X86_64Condition(comp->GetCondition()), reg);
Dave Allison20dfc792014-06-16 20:44:29 -0700897 }
898}
899
900void LocationsBuilderX86_64::VisitEqual(HEqual* comp) {
901 VisitCondition(comp);
902}
903
904void InstructionCodeGeneratorX86_64::VisitEqual(HEqual* comp) {
905 VisitCondition(comp);
906}
907
908void LocationsBuilderX86_64::VisitNotEqual(HNotEqual* comp) {
909 VisitCondition(comp);
910}
911
912void InstructionCodeGeneratorX86_64::VisitNotEqual(HNotEqual* comp) {
913 VisitCondition(comp);
914}
915
916void LocationsBuilderX86_64::VisitLessThan(HLessThan* comp) {
917 VisitCondition(comp);
918}
919
920void InstructionCodeGeneratorX86_64::VisitLessThan(HLessThan* comp) {
921 VisitCondition(comp);
922}
923
924void LocationsBuilderX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
925 VisitCondition(comp);
926}
927
928void InstructionCodeGeneratorX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
929 VisitCondition(comp);
930}
931
932void LocationsBuilderX86_64::VisitGreaterThan(HGreaterThan* comp) {
933 VisitCondition(comp);
934}
935
936void InstructionCodeGeneratorX86_64::VisitGreaterThan(HGreaterThan* comp) {
937 VisitCondition(comp);
938}
939
940void LocationsBuilderX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
941 VisitCondition(comp);
942}
943
944void InstructionCodeGeneratorX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
945 VisitCondition(comp);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100946}
947
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100948void LocationsBuilderX86_64::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100949 LocationSummary* locations =
950 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Calin Juravleddb7df22014-11-25 20:56:51 +0000951 switch (compare->InputAt(0)->GetType()) {
952 case Primitive::kPrimLong: {
953 locations->SetInAt(0, Location::RequiresRegister());
954 locations->SetInAt(1, Location::RequiresRegister());
955 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
956 break;
957 }
958 case Primitive::kPrimFloat:
959 case Primitive::kPrimDouble: {
960 locations->SetInAt(0, Location::RequiresFpuRegister());
961 locations->SetInAt(1, Location::RequiresFpuRegister());
962 locations->SetOut(Location::RequiresRegister());
963 break;
964 }
965 default:
966 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
967 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100968}
969
970void InstructionCodeGeneratorX86_64::VisitCompare(HCompare* compare) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100971 LocationSummary* locations = compare->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +0000972 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Calin Juravleddb7df22014-11-25 20:56:51 +0000973 Location left = locations->InAt(0);
974 Location right = locations->InAt(1);
975
976 Label less, greater, done;
977 Primitive::Type type = compare->InputAt(0)->GetType();
978 switch (type) {
979 case Primitive::kPrimLong: {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000980 __ cmpq(left.AsRegister<CpuRegister>(), right.AsRegister<CpuRegister>());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100981 break;
Calin Juravleddb7df22014-11-25 20:56:51 +0000982 }
983 case Primitive::kPrimFloat: {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000984 __ ucomiss(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
Calin Juravleddb7df22014-11-25 20:56:51 +0000985 __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
986 break;
987 }
988 case Primitive::kPrimDouble: {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000989 __ ucomisd(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
Calin Juravleddb7df22014-11-25 20:56:51 +0000990 __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
991 break;
992 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100993 default:
Calin Juravleddb7df22014-11-25 20:56:51 +0000994 LOG(FATAL) << "Unexpected compare type " << type;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100995 }
Calin Juravleddb7df22014-11-25 20:56:51 +0000996 __ movl(out, Immediate(0));
Calin Juravle91debbc2014-11-26 19:01:09 +0000997 __ j(kEqual, &done);
Calin Juravleddb7df22014-11-25 20:56:51 +0000998 __ j(type == Primitive::kPrimLong ? kLess : kBelow, &less); // ucomis{s,d} sets CF (kBelow)
Calin Juravlefd861242014-11-25 20:56:51 +0000999
Calin Juravle91debbc2014-11-26 19:01:09 +00001000 __ Bind(&greater);
Calin Juravleddb7df22014-11-25 20:56:51 +00001001 __ movl(out, Immediate(1));
1002 __ jmp(&done);
1003
1004 __ Bind(&less);
1005 __ movl(out, Immediate(-1));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001006
1007 __ Bind(&done);
1008}
1009
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001010void LocationsBuilderX86_64::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001011 LocationSummary* locations =
1012 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001013 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001014}
1015
1016void InstructionCodeGeneratorX86_64::VisitIntConstant(HIntConstant* constant) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001017 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001018 UNUSED(constant);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001019}
1020
1021void LocationsBuilderX86_64::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001022 LocationSummary* locations =
1023 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001024 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001025}
1026
1027void InstructionCodeGeneratorX86_64::VisitLongConstant(HLongConstant* constant) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001028 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001029 UNUSED(constant);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001030}
1031
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001032void LocationsBuilderX86_64::VisitFloatConstant(HFloatConstant* constant) {
1033 LocationSummary* locations =
1034 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1035 locations->SetOut(Location::ConstantLocation(constant));
1036}
1037
1038void InstructionCodeGeneratorX86_64::VisitFloatConstant(HFloatConstant* constant) {
1039 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001040 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001041}
1042
1043void LocationsBuilderX86_64::VisitDoubleConstant(HDoubleConstant* constant) {
1044 LocationSummary* locations =
1045 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1046 locations->SetOut(Location::ConstantLocation(constant));
1047}
1048
1049void InstructionCodeGeneratorX86_64::VisitDoubleConstant(HDoubleConstant* constant) {
1050 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001051 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001052}
1053
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001054void LocationsBuilderX86_64::VisitReturnVoid(HReturnVoid* ret) {
1055 ret->SetLocations(nullptr);
1056}
1057
1058void InstructionCodeGeneratorX86_64::VisitReturnVoid(HReturnVoid* ret) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001059 UNUSED(ret);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001060 codegen_->GenerateFrameExit();
1061 __ ret();
1062}
1063
1064void LocationsBuilderX86_64::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001065 LocationSummary* locations =
1066 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001067 switch (ret->InputAt(0)->GetType()) {
1068 case Primitive::kPrimBoolean:
1069 case Primitive::kPrimByte:
1070 case Primitive::kPrimChar:
1071 case Primitive::kPrimShort:
1072 case Primitive::kPrimInt:
1073 case Primitive::kPrimNot:
1074 case Primitive::kPrimLong:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001075 locations->SetInAt(0, Location::RegisterLocation(RAX));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001076 break;
1077
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001078 case Primitive::kPrimFloat:
1079 case Primitive::kPrimDouble:
1080 locations->SetInAt(0,
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001081 Location::FpuRegisterLocation(XMM0));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001082 break;
1083
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001084 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001085 LOG(FATAL) << "Unexpected return type " << ret->InputAt(0)->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001086 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001087}
1088
1089void InstructionCodeGeneratorX86_64::VisitReturn(HReturn* ret) {
1090 if (kIsDebugBuild) {
1091 switch (ret->InputAt(0)->GetType()) {
1092 case Primitive::kPrimBoolean:
1093 case Primitive::kPrimByte:
1094 case Primitive::kPrimChar:
1095 case Primitive::kPrimShort:
1096 case Primitive::kPrimInt:
1097 case Primitive::kPrimNot:
1098 case Primitive::kPrimLong:
Roland Levillain271ab9c2014-11-27 15:23:57 +00001099 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegister<CpuRegister>().AsRegister(), RAX);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001100 break;
1101
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001102 case Primitive::kPrimFloat:
1103 case Primitive::kPrimDouble:
Roland Levillain271ab9c2014-11-27 15:23:57 +00001104 DCHECK_EQ(ret->GetLocations()->InAt(0).AsFpuRegister<XmmRegister>().AsFloatRegister(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001105 XMM0);
1106 break;
1107
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001108 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001109 LOG(FATAL) << "Unexpected return type " << ret->InputAt(0)->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001110 }
1111 }
1112 codegen_->GenerateFrameExit();
1113 __ ret();
1114}
1115
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001116Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) {
1117 switch (type) {
1118 case Primitive::kPrimBoolean:
1119 case Primitive::kPrimByte:
1120 case Primitive::kPrimChar:
1121 case Primitive::kPrimShort:
1122 case Primitive::kPrimInt:
1123 case Primitive::kPrimNot: {
1124 uint32_t index = gp_index_++;
1125 stack_index_++;
1126 if (index < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001127 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001128 } else {
1129 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
1130 }
1131 }
1132
1133 case Primitive::kPrimLong: {
1134 uint32_t index = gp_index_;
1135 stack_index_ += 2;
1136 if (index < calling_convention.GetNumberOfRegisters()) {
1137 gp_index_ += 1;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001138 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001139 } else {
1140 gp_index_ += 2;
1141 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
1142 }
1143 }
1144
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001145 case Primitive::kPrimFloat: {
1146 uint32_t index = fp_index_++;
1147 stack_index_++;
1148 if (index < calling_convention.GetNumberOfFpuRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001149 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001150 } else {
1151 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
1152 }
1153 }
1154
1155 case Primitive::kPrimDouble: {
1156 uint32_t index = fp_index_++;
1157 stack_index_ += 2;
1158 if (index < calling_convention.GetNumberOfFpuRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001159 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001160 } else {
1161 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
1162 }
1163 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001164
1165 case Primitive::kPrimVoid:
1166 LOG(FATAL) << "Unexpected parameter type " << type;
1167 break;
1168 }
1169 return Location();
1170}
1171
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001172void LocationsBuilderX86_64::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001173 IntrinsicLocationsBuilderX86_64 intrinsic(GetGraph()->GetArena());
1174 if (intrinsic.TryDispatch(invoke)) {
1175 return;
1176 }
1177
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001178 HandleInvoke(invoke);
1179}
1180
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001181static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorX86_64* codegen) {
1182 if (invoke->GetLocations()->Intrinsified()) {
1183 IntrinsicCodeGeneratorX86_64 intrinsic(codegen);
1184 intrinsic.Dispatch(invoke);
1185 return true;
1186 }
1187 return false;
1188}
1189
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001190void InstructionCodeGeneratorX86_64::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001191 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1192 return;
1193 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001194
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001195 codegen_->GenerateStaticOrDirectCall(
1196 invoke,
1197 invoke->GetLocations()->GetTemp(0).AsRegister<CpuRegister>());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001198}
1199
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001200void LocationsBuilderX86_64::HandleInvoke(HInvoke* invoke) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001201 LocationSummary* locations =
1202 new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001203 locations->AddTemp(Location::RegisterLocation(RDI));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001204
1205 InvokeDexCallingConventionVisitor calling_convention_visitor;
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001206 for (size_t i = 0; i < invoke->InputCount(); i++) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001207 HInstruction* input = invoke->InputAt(i);
1208 locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
1209 }
1210
1211 switch (invoke->GetType()) {
1212 case Primitive::kPrimBoolean:
1213 case Primitive::kPrimByte:
1214 case Primitive::kPrimChar:
1215 case Primitive::kPrimShort:
1216 case Primitive::kPrimInt:
1217 case Primitive::kPrimNot:
1218 case Primitive::kPrimLong:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001219 locations->SetOut(Location::RegisterLocation(RAX));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001220 break;
1221
1222 case Primitive::kPrimVoid:
1223 break;
1224
1225 case Primitive::kPrimDouble:
1226 case Primitive::kPrimFloat:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001227 locations->SetOut(Location::FpuRegisterLocation(XMM0));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001228 break;
1229 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001230}
1231
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001232void LocationsBuilderX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001233 IntrinsicLocationsBuilderX86_64 intrinsic(GetGraph()->GetArena());
1234 if (intrinsic.TryDispatch(invoke)) {
1235 return;
1236 }
1237
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001238 HandleInvoke(invoke);
1239}
1240
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001241void InstructionCodeGeneratorX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001242 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1243 return;
1244 }
1245
Roland Levillain271ab9c2014-11-27 15:23:57 +00001246 CpuRegister temp = invoke->GetLocations()->GetTemp(0).AsRegister<CpuRegister>();
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001247 size_t method_offset = mirror::Class::EmbeddedVTableOffset().SizeValue() +
1248 invoke->GetVTableIndex() * sizeof(mirror::Class::VTableEntry);
1249 LocationSummary* locations = invoke->GetLocations();
1250 Location receiver = locations->InAt(0);
1251 size_t class_offset = mirror::Object::ClassOffset().SizeValue();
1252 // temp = object->GetClass();
1253 if (receiver.IsStackSlot()) {
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001254 __ movl(temp, Address(CpuRegister(RSP), receiver.GetStackIndex()));
1255 __ movl(temp, Address(temp, class_offset));
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001256 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001257 __ movl(temp, Address(receiver.AsRegister<CpuRegister>(), class_offset));
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001258 }
Calin Juravle77520bc2015-01-12 18:45:46 +00001259 codegen_->MaybeRecordImplicitNullCheck(invoke);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001260 // temp = temp->GetMethodAt(method_offset);
1261 __ movl(temp, Address(temp, method_offset));
1262 // call temp->GetEntryPoint();
Mathieu Chartier2d721012014-11-10 11:08:06 -08001263 __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001264 kX86_64WordSize).SizeValue()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001265
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001266 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray39468442014-09-02 15:17:15 +01001267 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001268}
1269
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001270void LocationsBuilderX86_64::VisitInvokeInterface(HInvokeInterface* invoke) {
1271 HandleInvoke(invoke);
1272 // Add the hidden argument.
1273 invoke->GetLocations()->AddTemp(Location::RegisterLocation(RAX));
1274}
1275
1276void InstructionCodeGeneratorX86_64::VisitInvokeInterface(HInvokeInterface* invoke) {
1277 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001278 CpuRegister temp = invoke->GetLocations()->GetTemp(0).AsRegister<CpuRegister>();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001279 uint32_t method_offset = mirror::Class::EmbeddedImTableOffset().Uint32Value() +
1280 (invoke->GetImtIndex() % mirror::Class::kImtSize) * sizeof(mirror::Class::ImTableEntry);
1281 LocationSummary* locations = invoke->GetLocations();
1282 Location receiver = locations->InAt(0);
1283 size_t class_offset = mirror::Object::ClassOffset().SizeValue();
1284
1285 // Set the hidden argument.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001286 __ movq(invoke->GetLocations()->GetTemp(1).AsRegister<CpuRegister>(),
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001287 Immediate(invoke->GetDexMethodIndex()));
1288
1289 // temp = object->GetClass();
1290 if (receiver.IsStackSlot()) {
1291 __ movl(temp, Address(CpuRegister(RSP), receiver.GetStackIndex()));
1292 __ movl(temp, Address(temp, class_offset));
1293 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001294 __ movl(temp, Address(receiver.AsRegister<CpuRegister>(), class_offset));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001295 }
Calin Juravle77520bc2015-01-12 18:45:46 +00001296 codegen_->MaybeRecordImplicitNullCheck(invoke);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001297 // temp = temp->GetImtEntryAt(method_offset);
1298 __ movl(temp, Address(temp, method_offset));
1299 // call temp->GetEntryPoint();
Mathieu Chartier2d721012014-11-10 11:08:06 -08001300 __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001301 kX86_64WordSize).SizeValue()));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001302
1303 DCHECK(!codegen_->IsLeafMethod());
1304 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1305}
1306
Roland Levillain88cb1752014-10-20 16:36:47 +01001307void LocationsBuilderX86_64::VisitNeg(HNeg* neg) {
1308 LocationSummary* locations =
1309 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
1310 switch (neg->GetResultType()) {
1311 case Primitive::kPrimInt:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001312 case Primitive::kPrimLong:
Roland Levillain88cb1752014-10-20 16:36:47 +01001313 locations->SetInAt(0, Location::RequiresRegister());
1314 locations->SetOut(Location::SameAsFirstInput());
1315 break;
1316
Roland Levillain88cb1752014-10-20 16:36:47 +01001317 case Primitive::kPrimFloat:
1318 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001319 locations->SetInAt(0, Location::RequiresFpuRegister());
Roland Levillain5368c212014-11-27 15:03:41 +00001320 locations->SetOut(Location::SameAsFirstInput());
1321 locations->AddTemp(Location::RequiresRegister());
1322 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain88cb1752014-10-20 16:36:47 +01001323 break;
1324
1325 default:
1326 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1327 }
1328}
1329
1330void InstructionCodeGeneratorX86_64::VisitNeg(HNeg* neg) {
1331 LocationSummary* locations = neg->GetLocations();
1332 Location out = locations->Out();
1333 Location in = locations->InAt(0);
1334 switch (neg->GetResultType()) {
1335 case Primitive::kPrimInt:
1336 DCHECK(in.IsRegister());
Roland Levillain3dbcb382014-10-28 17:30:07 +00001337 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001338 __ negl(out.AsRegister<CpuRegister>());
Roland Levillain88cb1752014-10-20 16:36:47 +01001339 break;
1340
1341 case Primitive::kPrimLong:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001342 DCHECK(in.IsRegister());
Roland Levillain3dbcb382014-10-28 17:30:07 +00001343 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001344 __ negq(out.AsRegister<CpuRegister>());
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001345 break;
1346
Roland Levillain5368c212014-11-27 15:03:41 +00001347 case Primitive::kPrimFloat: {
1348 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001349 CpuRegister constant = locations->GetTemp(0).AsRegister<CpuRegister>();
1350 XmmRegister mask = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
Roland Levillain5368c212014-11-27 15:03:41 +00001351 // Implement float negation with an exclusive or with value
1352 // 0x80000000 (mask for bit 31, representing the sign of a
1353 // single-precision floating-point number).
1354 __ movq(constant, Immediate(INT64_C(0x80000000)));
1355 __ movd(mask, constant);
Roland Levillain271ab9c2014-11-27 15:23:57 +00001356 __ xorps(out.AsFpuRegister<XmmRegister>(), mask);
Roland Levillain3dbcb382014-10-28 17:30:07 +00001357 break;
Roland Levillain5368c212014-11-27 15:03:41 +00001358 }
Roland Levillain3dbcb382014-10-28 17:30:07 +00001359
Roland Levillain5368c212014-11-27 15:03:41 +00001360 case Primitive::kPrimDouble: {
1361 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001362 CpuRegister constant = locations->GetTemp(0).AsRegister<CpuRegister>();
1363 XmmRegister mask = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
Roland Levillain5368c212014-11-27 15:03:41 +00001364 // Implement double negation with an exclusive or with value
Roland Levillain3dbcb382014-10-28 17:30:07 +00001365 // 0x8000000000000000 (mask for bit 63, representing the sign of
Roland Levillain5368c212014-11-27 15:03:41 +00001366 // a double-precision floating-point number).
1367 __ movq(constant, Immediate(INT64_C(0x8000000000000000)));
1368 __ movd(mask, constant);
Roland Levillain271ab9c2014-11-27 15:23:57 +00001369 __ xorpd(out.AsFpuRegister<XmmRegister>(), mask);
Roland Levillain88cb1752014-10-20 16:36:47 +01001370 break;
Roland Levillain5368c212014-11-27 15:03:41 +00001371 }
Roland Levillain88cb1752014-10-20 16:36:47 +01001372
1373 default:
1374 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1375 }
1376}
1377
Roland Levillaindff1f282014-11-05 14:15:05 +00001378void LocationsBuilderX86_64::VisitTypeConversion(HTypeConversion* conversion) {
1379 LocationSummary* locations =
1380 new (GetGraph()->GetArena()) LocationSummary(conversion, LocationSummary::kNoCall);
1381 Primitive::Type result_type = conversion->GetResultType();
1382 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00001383 DCHECK_NE(result_type, input_type);
Roland Levillaindff1f282014-11-05 14:15:05 +00001384 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00001385 case Primitive::kPrimByte:
1386 switch (input_type) {
1387 case Primitive::kPrimShort:
1388 case Primitive::kPrimInt:
1389 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001390 // Processing a Dex `int-to-byte' instruction.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001391 locations->SetInAt(0, Location::Any());
1392 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1393 break;
1394
1395 default:
1396 LOG(FATAL) << "Unexpected type conversion from " << input_type
1397 << " to " << result_type;
1398 }
1399 break;
1400
Roland Levillain01a8d712014-11-14 16:27:39 +00001401 case Primitive::kPrimShort:
1402 switch (input_type) {
1403 case Primitive::kPrimByte:
1404 case Primitive::kPrimInt:
1405 case Primitive::kPrimChar:
1406 // Processing a Dex `int-to-short' instruction.
1407 locations->SetInAt(0, Location::Any());
1408 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1409 break;
1410
1411 default:
1412 LOG(FATAL) << "Unexpected type conversion from " << input_type
1413 << " to " << result_type;
1414 }
1415 break;
1416
Roland Levillain946e1432014-11-11 17:35:19 +00001417 case Primitive::kPrimInt:
1418 switch (input_type) {
1419 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00001420 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00001421 locations->SetInAt(0, Location::Any());
1422 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1423 break;
1424
1425 case Primitive::kPrimFloat:
Roland Levillain3f8f9362014-12-02 17:45:01 +00001426 // Processing a Dex `float-to-int' instruction.
1427 locations->SetInAt(0, Location::RequiresFpuRegister());
1428 locations->SetOut(Location::RequiresRegister());
1429 locations->AddTemp(Location::RequiresFpuRegister());
1430 break;
1431
Roland Levillain946e1432014-11-11 17:35:19 +00001432 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001433 // Processing a Dex `double-to-int' instruction.
1434 locations->SetInAt(0, Location::RequiresFpuRegister());
1435 locations->SetOut(Location::RequiresRegister());
1436 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain946e1432014-11-11 17:35:19 +00001437 break;
1438
1439 default:
1440 LOG(FATAL) << "Unexpected type conversion from " << input_type
1441 << " to " << result_type;
1442 }
1443 break;
1444
Roland Levillaindff1f282014-11-05 14:15:05 +00001445 case Primitive::kPrimLong:
1446 switch (input_type) {
1447 case Primitive::kPrimByte:
1448 case Primitive::kPrimShort:
1449 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00001450 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001451 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00001452 // TODO: We would benefit from a (to-be-implemented)
1453 // Location::RegisterOrStackSlot requirement for this input.
1454 locations->SetInAt(0, Location::RequiresRegister());
1455 locations->SetOut(Location::RequiresRegister());
1456 break;
1457
1458 case Primitive::kPrimFloat:
Roland Levillain624279f2014-12-04 11:54:28 +00001459 // Processing a Dex `float-to-long' instruction.
1460 locations->SetInAt(0, Location::RequiresFpuRegister());
1461 locations->SetOut(Location::RequiresRegister());
1462 locations->AddTemp(Location::RequiresFpuRegister());
1463 break;
1464
Roland Levillaindff1f282014-11-05 14:15:05 +00001465 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001466 // Processing a Dex `double-to-long' instruction.
1467 locations->SetInAt(0, Location::RequiresFpuRegister());
1468 locations->SetOut(Location::RequiresRegister());
1469 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillaindff1f282014-11-05 14:15:05 +00001470 break;
1471
1472 default:
1473 LOG(FATAL) << "Unexpected type conversion from " << input_type
1474 << " to " << result_type;
1475 }
1476 break;
1477
Roland Levillain981e4542014-11-14 11:47:14 +00001478 case Primitive::kPrimChar:
1479 switch (input_type) {
1480 case Primitive::kPrimByte:
1481 case Primitive::kPrimShort:
1482 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00001483 // Processing a Dex `int-to-char' instruction.
1484 locations->SetInAt(0, Location::Any());
1485 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1486 break;
1487
1488 default:
1489 LOG(FATAL) << "Unexpected type conversion from " << input_type
1490 << " to " << result_type;
1491 }
1492 break;
1493
Roland Levillaindff1f282014-11-05 14:15:05 +00001494 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00001495 switch (input_type) {
1496 case Primitive::kPrimByte:
1497 case Primitive::kPrimShort:
1498 case Primitive::kPrimInt:
1499 case Primitive::kPrimChar:
1500 // Processing a Dex `int-to-float' instruction.
1501 locations->SetInAt(0, Location::RequiresRegister());
1502 locations->SetOut(Location::RequiresFpuRegister());
1503 break;
1504
1505 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00001506 // Processing a Dex `long-to-float' instruction.
1507 locations->SetInAt(0, Location::RequiresRegister());
1508 locations->SetOut(Location::RequiresFpuRegister());
1509 break;
1510
Roland Levillaincff13742014-11-17 14:32:17 +00001511 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001512 // Processing a Dex `double-to-float' instruction.
1513 locations->SetInAt(0, Location::RequiresFpuRegister());
1514 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00001515 break;
1516
1517 default:
1518 LOG(FATAL) << "Unexpected type conversion from " << input_type
1519 << " to " << result_type;
1520 };
1521 break;
1522
Roland Levillaindff1f282014-11-05 14:15:05 +00001523 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00001524 switch (input_type) {
1525 case Primitive::kPrimByte:
1526 case Primitive::kPrimShort:
1527 case Primitive::kPrimInt:
1528 case Primitive::kPrimChar:
1529 // Processing a Dex `int-to-double' instruction.
1530 locations->SetInAt(0, Location::RequiresRegister());
1531 locations->SetOut(Location::RequiresFpuRegister());
1532 break;
1533
1534 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00001535 // Processing a Dex `long-to-double' instruction.
1536 locations->SetInAt(0, Location::RequiresRegister());
1537 locations->SetOut(Location::RequiresFpuRegister());
1538 break;
1539
Roland Levillaincff13742014-11-17 14:32:17 +00001540 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001541 // Processing a Dex `float-to-double' instruction.
1542 locations->SetInAt(0, Location::RequiresFpuRegister());
1543 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00001544 break;
1545
1546 default:
1547 LOG(FATAL) << "Unexpected type conversion from " << input_type
1548 << " to " << result_type;
1549 }
Roland Levillaindff1f282014-11-05 14:15:05 +00001550 break;
1551
1552 default:
1553 LOG(FATAL) << "Unexpected type conversion from " << input_type
1554 << " to " << result_type;
1555 }
1556}
1557
1558void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conversion) {
1559 LocationSummary* locations = conversion->GetLocations();
1560 Location out = locations->Out();
1561 Location in = locations->InAt(0);
1562 Primitive::Type result_type = conversion->GetResultType();
1563 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00001564 DCHECK_NE(result_type, input_type);
Roland Levillaindff1f282014-11-05 14:15:05 +00001565 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00001566 case Primitive::kPrimByte:
1567 switch (input_type) {
1568 case Primitive::kPrimShort:
1569 case Primitive::kPrimInt:
1570 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001571 // Processing a Dex `int-to-byte' instruction.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001572 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001573 __ movsxb(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain51d3fc42014-11-13 14:11:42 +00001574 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001575 __ movsxb(out.AsRegister<CpuRegister>(),
Roland Levillain51d3fc42014-11-13 14:11:42 +00001576 Address(CpuRegister(RSP), in.GetStackIndex()));
1577 } else {
1578 DCHECK(in.GetConstant()->IsIntConstant());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001579 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain51d3fc42014-11-13 14:11:42 +00001580 Immediate(static_cast<int8_t>(in.GetConstant()->AsIntConstant()->GetValue())));
1581 }
1582 break;
1583
1584 default:
1585 LOG(FATAL) << "Unexpected type conversion from " << input_type
1586 << " to " << result_type;
1587 }
1588 break;
1589
Roland Levillain01a8d712014-11-14 16:27:39 +00001590 case Primitive::kPrimShort:
1591 switch (input_type) {
1592 case Primitive::kPrimByte:
1593 case Primitive::kPrimInt:
1594 case Primitive::kPrimChar:
1595 // Processing a Dex `int-to-short' instruction.
1596 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001597 __ movsxw(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain01a8d712014-11-14 16:27:39 +00001598 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001599 __ movsxw(out.AsRegister<CpuRegister>(),
Roland Levillain01a8d712014-11-14 16:27:39 +00001600 Address(CpuRegister(RSP), in.GetStackIndex()));
1601 } else {
1602 DCHECK(in.GetConstant()->IsIntConstant());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001603 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain01a8d712014-11-14 16:27:39 +00001604 Immediate(static_cast<int16_t>(in.GetConstant()->AsIntConstant()->GetValue())));
1605 }
1606 break;
1607
1608 default:
1609 LOG(FATAL) << "Unexpected type conversion from " << input_type
1610 << " to " << result_type;
1611 }
1612 break;
1613
Roland Levillain946e1432014-11-11 17:35:19 +00001614 case Primitive::kPrimInt:
1615 switch (input_type) {
1616 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00001617 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00001618 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001619 __ movl(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain946e1432014-11-11 17:35:19 +00001620 } else if (in.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001621 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain946e1432014-11-11 17:35:19 +00001622 Address(CpuRegister(RSP), in.GetStackIndex()));
1623 } else {
1624 DCHECK(in.IsConstant());
1625 DCHECK(in.GetConstant()->IsLongConstant());
1626 int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00001627 __ movl(out.AsRegister<CpuRegister>(), Immediate(static_cast<int32_t>(value)));
Roland Levillain946e1432014-11-11 17:35:19 +00001628 }
1629 break;
1630
Roland Levillain3f8f9362014-12-02 17:45:01 +00001631 case Primitive::kPrimFloat: {
1632 // Processing a Dex `float-to-int' instruction.
1633 XmmRegister input = in.AsFpuRegister<XmmRegister>();
1634 CpuRegister output = out.AsRegister<CpuRegister>();
1635 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
1636 Label done, nan;
1637
1638 __ movl(output, Immediate(kPrimIntMax));
1639 // temp = int-to-float(output)
Roland Levillain624279f2014-12-04 11:54:28 +00001640 __ cvtsi2ss(temp, output, false);
Roland Levillain3f8f9362014-12-02 17:45:01 +00001641 // if input >= temp goto done
1642 __ comiss(input, temp);
1643 __ j(kAboveEqual, &done);
1644 // if input == NaN goto nan
1645 __ j(kUnordered, &nan);
1646 // output = float-to-int-truncate(input)
Roland Levillain624279f2014-12-04 11:54:28 +00001647 __ cvttss2si(output, input, false);
Roland Levillain3f8f9362014-12-02 17:45:01 +00001648 __ jmp(&done);
1649 __ Bind(&nan);
1650 // output = 0
1651 __ xorl(output, output);
1652 __ Bind(&done);
1653 break;
1654 }
1655
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001656 case Primitive::kPrimDouble: {
1657 // Processing a Dex `double-to-int' instruction.
1658 XmmRegister input = in.AsFpuRegister<XmmRegister>();
1659 CpuRegister output = out.AsRegister<CpuRegister>();
1660 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
1661 Label done, nan;
1662
1663 __ movl(output, Immediate(kPrimIntMax));
1664 // temp = int-to-double(output)
1665 __ cvtsi2sd(temp, output);
1666 // if input >= temp goto done
1667 __ comisd(input, temp);
1668 __ j(kAboveEqual, &done);
1669 // if input == NaN goto nan
1670 __ j(kUnordered, &nan);
1671 // output = double-to-int-truncate(input)
1672 __ cvttsd2si(output, input);
1673 __ jmp(&done);
1674 __ Bind(&nan);
1675 // output = 0
1676 __ xorl(output, output);
1677 __ Bind(&done);
Roland Levillain946e1432014-11-11 17:35:19 +00001678 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001679 }
Roland Levillain946e1432014-11-11 17:35:19 +00001680
1681 default:
1682 LOG(FATAL) << "Unexpected type conversion from " << input_type
1683 << " to " << result_type;
1684 }
1685 break;
1686
Roland Levillaindff1f282014-11-05 14:15:05 +00001687 case Primitive::kPrimLong:
1688 switch (input_type) {
1689 DCHECK(out.IsRegister());
1690 case Primitive::kPrimByte:
1691 case Primitive::kPrimShort:
1692 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00001693 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001694 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00001695 DCHECK(in.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001696 __ movsxd(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillaindff1f282014-11-05 14:15:05 +00001697 break;
1698
Roland Levillain624279f2014-12-04 11:54:28 +00001699 case Primitive::kPrimFloat: {
1700 // Processing a Dex `float-to-long' instruction.
1701 XmmRegister input = in.AsFpuRegister<XmmRegister>();
1702 CpuRegister output = out.AsRegister<CpuRegister>();
1703 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
1704 Label done, nan;
1705
1706 __ movq(output, Immediate(kPrimLongMax));
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001707 // temp = long-to-float(output)
Roland Levillain624279f2014-12-04 11:54:28 +00001708 __ cvtsi2ss(temp, output, true);
1709 // if input >= temp goto done
1710 __ comiss(input, temp);
1711 __ j(kAboveEqual, &done);
1712 // if input == NaN goto nan
1713 __ j(kUnordered, &nan);
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001714 // output = float-to-long-truncate(input)
Roland Levillain624279f2014-12-04 11:54:28 +00001715 __ cvttss2si(output, input, true);
1716 __ jmp(&done);
1717 __ Bind(&nan);
1718 // output = 0
1719 __ xorq(output, output);
1720 __ Bind(&done);
1721 break;
1722 }
1723
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001724 case Primitive::kPrimDouble: {
1725 // Processing a Dex `double-to-long' instruction.
1726 XmmRegister input = in.AsFpuRegister<XmmRegister>();
1727 CpuRegister output = out.AsRegister<CpuRegister>();
1728 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
1729 Label done, nan;
1730
1731 __ movq(output, Immediate(kPrimLongMax));
1732 // temp = long-to-double(output)
1733 __ cvtsi2sd(temp, output, true);
1734 // if input >= temp goto done
1735 __ comisd(input, temp);
1736 __ j(kAboveEqual, &done);
1737 // if input == NaN goto nan
1738 __ j(kUnordered, &nan);
1739 // output = double-to-long-truncate(input)
1740 __ cvttsd2si(output, input, true);
1741 __ jmp(&done);
1742 __ Bind(&nan);
1743 // output = 0
1744 __ xorq(output, output);
1745 __ Bind(&done);
Roland Levillaindff1f282014-11-05 14:15:05 +00001746 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001747 }
Roland Levillaindff1f282014-11-05 14:15:05 +00001748
1749 default:
1750 LOG(FATAL) << "Unexpected type conversion from " << input_type
1751 << " to " << result_type;
1752 }
1753 break;
1754
Roland Levillain981e4542014-11-14 11:47:14 +00001755 case Primitive::kPrimChar:
1756 switch (input_type) {
1757 case Primitive::kPrimByte:
1758 case Primitive::kPrimShort:
1759 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00001760 // Processing a Dex `int-to-char' instruction.
1761 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001762 __ movzxw(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain981e4542014-11-14 11:47:14 +00001763 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001764 __ movzxw(out.AsRegister<CpuRegister>(),
Roland Levillain981e4542014-11-14 11:47:14 +00001765 Address(CpuRegister(RSP), in.GetStackIndex()));
1766 } else {
1767 DCHECK(in.GetConstant()->IsIntConstant());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001768 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain981e4542014-11-14 11:47:14 +00001769 Immediate(static_cast<uint16_t>(in.GetConstant()->AsIntConstant()->GetValue())));
1770 }
1771 break;
1772
1773 default:
1774 LOG(FATAL) << "Unexpected type conversion from " << input_type
1775 << " to " << result_type;
1776 }
1777 break;
1778
Roland Levillaindff1f282014-11-05 14:15:05 +00001779 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00001780 switch (input_type) {
Roland Levillaincff13742014-11-17 14:32:17 +00001781 case Primitive::kPrimByte:
1782 case Primitive::kPrimShort:
1783 case Primitive::kPrimInt:
1784 case Primitive::kPrimChar:
Roland Levillain6d0e4832014-11-27 18:31:21 +00001785 // Processing a Dex `int-to-float' instruction.
1786 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), false);
Roland Levillaincff13742014-11-17 14:32:17 +00001787 break;
1788
1789 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00001790 // Processing a Dex `long-to-float' instruction.
1791 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), true);
1792 break;
1793
Roland Levillaincff13742014-11-17 14:32:17 +00001794 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001795 // Processing a Dex `double-to-float' instruction.
1796 __ cvtsd2ss(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00001797 break;
1798
1799 default:
1800 LOG(FATAL) << "Unexpected type conversion from " << input_type
1801 << " to " << result_type;
1802 };
1803 break;
1804
Roland Levillaindff1f282014-11-05 14:15:05 +00001805 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00001806 switch (input_type) {
Roland Levillaincff13742014-11-17 14:32:17 +00001807 case Primitive::kPrimByte:
1808 case Primitive::kPrimShort:
1809 case Primitive::kPrimInt:
1810 case Primitive::kPrimChar:
Roland Levillain6d0e4832014-11-27 18:31:21 +00001811 // Processing a Dex `int-to-double' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001812 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), false);
Roland Levillaincff13742014-11-17 14:32:17 +00001813 break;
1814
1815 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00001816 // Processing a Dex `long-to-double' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001817 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), true);
Roland Levillain647b9ed2014-11-27 12:06:00 +00001818 break;
1819
Roland Levillaincff13742014-11-17 14:32:17 +00001820 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001821 // Processing a Dex `float-to-double' instruction.
1822 __ cvtss2sd(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00001823 break;
1824
1825 default:
1826 LOG(FATAL) << "Unexpected type conversion from " << input_type
1827 << " to " << result_type;
1828 };
Roland Levillaindff1f282014-11-05 14:15:05 +00001829 break;
1830
1831 default:
1832 LOG(FATAL) << "Unexpected type conversion from " << input_type
1833 << " to " << result_type;
1834 }
1835}
1836
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001837void LocationsBuilderX86_64::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001838 LocationSummary* locations =
1839 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001840 switch (add->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001841 case Primitive::kPrimInt: {
1842 locations->SetInAt(0, Location::RequiresRegister());
1843 locations->SetInAt(1, Location::Any());
1844 locations->SetOut(Location::SameAsFirstInput());
1845 break;
1846 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001847
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001848 case Primitive::kPrimLong: {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001849 locations->SetInAt(0, Location::RequiresRegister());
1850 locations->SetInAt(1, Location::RequiresRegister());
1851 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001852 break;
1853 }
1854
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001855 case Primitive::kPrimDouble:
1856 case Primitive::kPrimFloat: {
1857 locations->SetInAt(0, Location::RequiresFpuRegister());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001858 locations->SetInAt(1, Location::RequiresFpuRegister());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001859 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001860 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001861 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001862
1863 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001864 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001865 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001866}
1867
1868void InstructionCodeGeneratorX86_64::VisitAdd(HAdd* add) {
1869 LocationSummary* locations = add->GetLocations();
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001870 Location first = locations->InAt(0);
1871 Location second = locations->InAt(1);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001872 DCHECK(first.Equals(locations->Out()));
Calin Juravle11351682014-10-23 15:38:15 +01001873
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001874 switch (add->GetResultType()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001875 case Primitive::kPrimInt: {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001876 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001877 __ addl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001878 } else if (second.IsConstant()) {
Calin Juravle11351682014-10-23 15:38:15 +01001879 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001880 __ addl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001881 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001882 __ addl(first.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), second.GetStackIndex()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001883 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001884 break;
1885 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001886
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001887 case Primitive::kPrimLong: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001888 __ addq(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001889 break;
1890 }
1891
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001892 case Primitive::kPrimFloat: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001893 __ addss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001894 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001895 }
1896
1897 case Primitive::kPrimDouble: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001898 __ addsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001899 break;
1900 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001901
1902 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001903 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001904 }
1905}
1906
1907void LocationsBuilderX86_64::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001908 LocationSummary* locations =
1909 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001910 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001911 case Primitive::kPrimInt: {
1912 locations->SetInAt(0, Location::RequiresRegister());
1913 locations->SetInAt(1, Location::Any());
1914 locations->SetOut(Location::SameAsFirstInput());
1915 break;
1916 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001917 case Primitive::kPrimLong: {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001918 locations->SetInAt(0, Location::RequiresRegister());
1919 locations->SetInAt(1, Location::RequiresRegister());
1920 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001921 break;
1922 }
Calin Juravle11351682014-10-23 15:38:15 +01001923 case Primitive::kPrimFloat:
1924 case Primitive::kPrimDouble: {
1925 locations->SetInAt(0, Location::RequiresFpuRegister());
1926 locations->SetInAt(1, Location::RequiresFpuRegister());
1927 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001928 break;
Calin Juravle11351682014-10-23 15:38:15 +01001929 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001930 default:
Calin Juravle11351682014-10-23 15:38:15 +01001931 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001932 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001933}
1934
1935void InstructionCodeGeneratorX86_64::VisitSub(HSub* sub) {
1936 LocationSummary* locations = sub->GetLocations();
Calin Juravle11351682014-10-23 15:38:15 +01001937 Location first = locations->InAt(0);
1938 Location second = locations->InAt(1);
1939 DCHECK(first.Equals(locations->Out()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001940 switch (sub->GetResultType()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001941 case Primitive::kPrimInt: {
Calin Juravle11351682014-10-23 15:38:15 +01001942 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001943 __ subl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Calin Juravle11351682014-10-23 15:38:15 +01001944 } else if (second.IsConstant()) {
1945 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001946 __ subl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001947 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001948 __ subl(first.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), second.GetStackIndex()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001949 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001950 break;
1951 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001952 case Primitive::kPrimLong: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001953 __ subq(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001954 break;
1955 }
1956
Calin Juravle11351682014-10-23 15:38:15 +01001957 case Primitive::kPrimFloat: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001958 __ subss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001959 break;
Calin Juravle11351682014-10-23 15:38:15 +01001960 }
1961
1962 case Primitive::kPrimDouble: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001963 __ subsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Calin Juravle11351682014-10-23 15:38:15 +01001964 break;
1965 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001966
1967 default:
Calin Juravle11351682014-10-23 15:38:15 +01001968 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001969 }
1970}
1971
Calin Juravle34bacdf2014-10-07 20:23:36 +01001972void LocationsBuilderX86_64::VisitMul(HMul* mul) {
1973 LocationSummary* locations =
1974 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
1975 switch (mul->GetResultType()) {
1976 case Primitive::kPrimInt: {
1977 locations->SetInAt(0, Location::RequiresRegister());
1978 locations->SetInAt(1, Location::Any());
1979 locations->SetOut(Location::SameAsFirstInput());
1980 break;
1981 }
1982 case Primitive::kPrimLong: {
1983 locations->SetInAt(0, Location::RequiresRegister());
1984 locations->SetInAt(1, Location::RequiresRegister());
1985 locations->SetOut(Location::SameAsFirstInput());
1986 break;
1987 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01001988 case Primitive::kPrimFloat:
1989 case Primitive::kPrimDouble: {
1990 locations->SetInAt(0, Location::RequiresFpuRegister());
1991 locations->SetInAt(1, Location::RequiresFpuRegister());
1992 locations->SetOut(Location::SameAsFirstInput());
Calin Juravle34bacdf2014-10-07 20:23:36 +01001993 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01001994 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01001995
1996 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01001997 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01001998 }
1999}
2000
2001void InstructionCodeGeneratorX86_64::VisitMul(HMul* mul) {
2002 LocationSummary* locations = mul->GetLocations();
2003 Location first = locations->InAt(0);
2004 Location second = locations->InAt(1);
2005 DCHECK(first.Equals(locations->Out()));
2006 switch (mul->GetResultType()) {
2007 case Primitive::kPrimInt: {
2008 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002009 __ imull(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002010 } else if (second.IsConstant()) {
2011 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002012 __ imull(first.AsRegister<CpuRegister>(), imm);
Calin Juravle34bacdf2014-10-07 20:23:36 +01002013 } else {
2014 DCHECK(second.IsStackSlot());
Roland Levillain199f3362014-11-27 17:15:16 +00002015 __ imull(first.AsRegister<CpuRegister>(),
2016 Address(CpuRegister(RSP), second.GetStackIndex()));
Calin Juravle34bacdf2014-10-07 20:23:36 +01002017 }
2018 break;
2019 }
2020 case Primitive::kPrimLong: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002021 __ imulq(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002022 break;
2023 }
2024
Calin Juravleb5bfa962014-10-21 18:02:24 +01002025 case Primitive::kPrimFloat: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002026 __ mulss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002027 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002028 }
2029
2030 case Primitive::kPrimDouble: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002031 __ mulsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Calin Juravleb5bfa962014-10-21 18:02:24 +01002032 break;
2033 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002034
2035 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002036 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002037 }
2038}
2039
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002040void InstructionCodeGeneratorX86_64::PushOntoFPStack(Location source, uint32_t temp_offset,
2041 uint32_t stack_adjustment, bool is_float) {
2042 if (source.IsStackSlot()) {
2043 DCHECK(is_float);
2044 __ flds(Address(CpuRegister(RSP), source.GetStackIndex() + stack_adjustment));
2045 } else if (source.IsDoubleStackSlot()) {
2046 DCHECK(!is_float);
2047 __ fldl(Address(CpuRegister(RSP), source.GetStackIndex() + stack_adjustment));
2048 } else {
2049 // Write the value to the temporary location on the stack and load to FP stack.
2050 if (is_float) {
2051 Location stack_temp = Location::StackSlot(temp_offset);
2052 codegen_->Move(stack_temp, source);
2053 __ flds(Address(CpuRegister(RSP), temp_offset));
2054 } else {
2055 Location stack_temp = Location::DoubleStackSlot(temp_offset);
2056 codegen_->Move(stack_temp, source);
2057 __ fldl(Address(CpuRegister(RSP), temp_offset));
2058 }
2059 }
2060}
2061
2062void InstructionCodeGeneratorX86_64::GenerateRemFP(HRem *rem) {
2063 Primitive::Type type = rem->GetResultType();
2064 bool is_float = type == Primitive::kPrimFloat;
2065 size_t elem_size = Primitive::ComponentSize(type);
2066 LocationSummary* locations = rem->GetLocations();
2067 Location first = locations->InAt(0);
2068 Location second = locations->InAt(1);
2069 Location out = locations->Out();
2070
2071 // Create stack space for 2 elements.
2072 // TODO: enhance register allocator to ask for stack temporaries.
2073 __ subq(CpuRegister(RSP), Immediate(2 * elem_size));
2074
2075 // Load the values to the FP stack in reverse order, using temporaries if needed.
2076 PushOntoFPStack(second, elem_size, 2 * elem_size, is_float);
2077 PushOntoFPStack(first, 0, 2 * elem_size, is_float);
2078
2079 // Loop doing FPREM until we stabilize.
2080 Label retry;
2081 __ Bind(&retry);
2082 __ fprem();
2083
2084 // Move FP status to AX.
2085 __ fstsw();
2086
2087 // And see if the argument reduction is complete. This is signaled by the
2088 // C2 FPU flag bit set to 0.
2089 __ andl(CpuRegister(RAX), Immediate(kC2ConditionMask));
2090 __ j(kNotEqual, &retry);
2091
2092 // We have settled on the final value. Retrieve it into an XMM register.
2093 // Store FP top of stack to real stack.
2094 if (is_float) {
2095 __ fsts(Address(CpuRegister(RSP), 0));
2096 } else {
2097 __ fstl(Address(CpuRegister(RSP), 0));
2098 }
2099
2100 // Pop the 2 items from the FP stack.
2101 __ fucompp();
2102
2103 // Load the value from the stack into an XMM register.
2104 DCHECK(out.IsFpuRegister()) << out;
2105 if (is_float) {
2106 __ movss(out.AsFpuRegister<XmmRegister>(), Address(CpuRegister(RSP), 0));
2107 } else {
2108 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(CpuRegister(RSP), 0));
2109 }
2110
2111 // And remove the temporary stack space we allocated.
2112 __ addq(CpuRegister(RSP), Immediate(2 * elem_size));
2113}
2114
Calin Juravlebacfec32014-11-14 15:54:36 +00002115void InstructionCodeGeneratorX86_64::GenerateDivRemIntegral(HBinaryOperation* instruction) {
2116 DCHECK(instruction->IsDiv() || instruction->IsRem());
2117 Primitive::Type type = instruction->GetResultType();
2118 DCHECK(type == Primitive::kPrimInt || Primitive::kPrimLong);
2119
2120 bool is_div = instruction->IsDiv();
2121 LocationSummary* locations = instruction->GetLocations();
2122
Roland Levillain271ab9c2014-11-27 15:23:57 +00002123 CpuRegister out_reg = locations->Out().AsRegister<CpuRegister>();
2124 CpuRegister second_reg = locations->InAt(1).AsRegister<CpuRegister>();
Calin Juravlebacfec32014-11-14 15:54:36 +00002125
Roland Levillain271ab9c2014-11-27 15:23:57 +00002126 DCHECK_EQ(RAX, locations->InAt(0).AsRegister<CpuRegister>().AsRegister());
Calin Juravlebacfec32014-11-14 15:54:36 +00002127 DCHECK_EQ(is_div ? RAX : RDX, out_reg.AsRegister());
2128
2129 SlowPathCodeX86_64* slow_path =
2130 new (GetGraph()->GetArena()) DivRemMinusOneSlowPathX86_64(
2131 out_reg.AsRegister(), type, is_div);
2132 codegen_->AddSlowPath(slow_path);
2133
2134 // 0x80000000(00000000)/-1 triggers an arithmetic exception!
2135 // Dividing by -1 is actually negation and -0x800000000(00000000) = 0x80000000(00000000)
2136 // so it's safe to just use negl instead of more complex comparisons.
Calin Juravlebacfec32014-11-14 15:54:36 +00002137 if (type == Primitive::kPrimInt) {
Calin Juravled2ec87d2014-12-08 14:24:46 +00002138 __ cmpl(second_reg, Immediate(-1));
2139 __ j(kEqual, slow_path->GetEntryLabel());
Calin Juravlebacfec32014-11-14 15:54:36 +00002140 // edx:eax <- sign-extended of eax
2141 __ cdq();
2142 // eax = quotient, edx = remainder
2143 __ idivl(second_reg);
2144 } else {
Calin Juravled2ec87d2014-12-08 14:24:46 +00002145 __ cmpq(second_reg, Immediate(-1));
2146 __ j(kEqual, slow_path->GetEntryLabel());
Calin Juravlebacfec32014-11-14 15:54:36 +00002147 // rdx:rax <- sign-extended of rax
2148 __ cqo();
2149 // rax = quotient, rdx = remainder
2150 __ idivq(second_reg);
2151 }
2152
2153 __ Bind(slow_path->GetExitLabel());
2154}
2155
Calin Juravle7c4954d2014-10-28 16:57:40 +00002156void LocationsBuilderX86_64::VisitDiv(HDiv* div) {
2157 LocationSummary* locations =
2158 new (GetGraph()->GetArena()) LocationSummary(div, LocationSummary::kNoCall);
2159 switch (div->GetResultType()) {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002160 case Primitive::kPrimInt:
2161 case Primitive::kPrimLong: {
Calin Juravled0d48522014-11-04 16:40:20 +00002162 locations->SetInAt(0, Location::RegisterLocation(RAX));
2163 locations->SetInAt(1, Location::RequiresRegister());
2164 locations->SetOut(Location::SameAsFirstInput());
2165 // Intel uses edx:eax as the dividend.
2166 locations->AddTemp(Location::RegisterLocation(RDX));
2167 break;
2168 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002169
Calin Juravle7c4954d2014-10-28 16:57:40 +00002170 case Primitive::kPrimFloat:
2171 case Primitive::kPrimDouble: {
2172 locations->SetInAt(0, Location::RequiresFpuRegister());
2173 locations->SetInAt(1, Location::RequiresFpuRegister());
2174 locations->SetOut(Location::SameAsFirstInput());
2175 break;
2176 }
2177
2178 default:
2179 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2180 }
2181}
2182
2183void InstructionCodeGeneratorX86_64::VisitDiv(HDiv* div) {
2184 LocationSummary* locations = div->GetLocations();
2185 Location first = locations->InAt(0);
2186 Location second = locations->InAt(1);
2187 DCHECK(first.Equals(locations->Out()));
2188
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002189 Primitive::Type type = div->GetResultType();
2190 switch (type) {
2191 case Primitive::kPrimInt:
2192 case Primitive::kPrimLong: {
Calin Juravlebacfec32014-11-14 15:54:36 +00002193 GenerateDivRemIntegral(div);
Calin Juravled0d48522014-11-04 16:40:20 +00002194 break;
2195 }
2196
Calin Juravle7c4954d2014-10-28 16:57:40 +00002197 case Primitive::kPrimFloat: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002198 __ divss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002199 break;
2200 }
2201
2202 case Primitive::kPrimDouble: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002203 __ divsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002204 break;
2205 }
2206
2207 default:
2208 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2209 }
2210}
2211
Calin Juravlebacfec32014-11-14 15:54:36 +00002212void LocationsBuilderX86_64::VisitRem(HRem* rem) {
Calin Juravled2ec87d2014-12-08 14:24:46 +00002213 Primitive::Type type = rem->GetResultType();
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002214 LocationSummary* locations =
2215 new (GetGraph()->GetArena()) LocationSummary(rem, LocationSummary::kNoCall);
Calin Juravled2ec87d2014-12-08 14:24:46 +00002216
2217 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00002218 case Primitive::kPrimInt:
2219 case Primitive::kPrimLong: {
2220 locations->SetInAt(0, Location::RegisterLocation(RAX));
2221 locations->SetInAt(1, Location::RequiresRegister());
2222 // Intel uses rdx:rax as the dividend and puts the remainder in rdx
2223 locations->SetOut(Location::RegisterLocation(RDX));
2224 break;
2225 }
2226
2227 case Primitive::kPrimFloat:
2228 case Primitive::kPrimDouble: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002229 locations->SetInAt(0, Location::Any());
2230 locations->SetInAt(1, Location::Any());
2231 locations->SetOut(Location::RequiresFpuRegister());
2232 locations->AddTemp(Location::RegisterLocation(RAX));
Calin Juravlebacfec32014-11-14 15:54:36 +00002233 break;
2234 }
2235
2236 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00002237 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00002238 }
2239}
2240
2241void InstructionCodeGeneratorX86_64::VisitRem(HRem* rem) {
2242 Primitive::Type type = rem->GetResultType();
2243 switch (type) {
2244 case Primitive::kPrimInt:
2245 case Primitive::kPrimLong: {
2246 GenerateDivRemIntegral(rem);
2247 break;
2248 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002249 case Primitive::kPrimFloat:
Calin Juravled2ec87d2014-12-08 14:24:46 +00002250 case Primitive::kPrimDouble: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002251 GenerateRemFP(rem);
Calin Juravled2ec87d2014-12-08 14:24:46 +00002252 break;
2253 }
Calin Juravlebacfec32014-11-14 15:54:36 +00002254 default:
2255 LOG(FATAL) << "Unexpected rem type " << rem->GetResultType();
2256 }
2257}
2258
Calin Juravled0d48522014-11-04 16:40:20 +00002259void LocationsBuilderX86_64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
2260 LocationSummary* locations =
2261 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
2262 locations->SetInAt(0, Location::Any());
2263 if (instruction->HasUses()) {
2264 locations->SetOut(Location::SameAsFirstInput());
2265 }
2266}
2267
2268void InstructionCodeGeneratorX86_64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
2269 SlowPathCodeX86_64* slow_path =
2270 new (GetGraph()->GetArena()) DivZeroCheckSlowPathX86_64(instruction);
2271 codegen_->AddSlowPath(slow_path);
2272
2273 LocationSummary* locations = instruction->GetLocations();
2274 Location value = locations->InAt(0);
2275
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002276 switch (instruction->GetType()) {
2277 case Primitive::kPrimInt: {
2278 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002279 __ testl(value.AsRegister<CpuRegister>(), value.AsRegister<CpuRegister>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002280 __ j(kEqual, slow_path->GetEntryLabel());
2281 } else if (value.IsStackSlot()) {
2282 __ cmpl(Address(CpuRegister(RSP), value.GetStackIndex()), Immediate(0));
2283 __ j(kEqual, slow_path->GetEntryLabel());
2284 } else {
2285 DCHECK(value.IsConstant()) << value;
2286 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
2287 __ jmp(slow_path->GetEntryLabel());
2288 }
2289 }
2290 break;
Calin Juravled0d48522014-11-04 16:40:20 +00002291 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002292 case Primitive::kPrimLong: {
2293 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002294 __ testq(value.AsRegister<CpuRegister>(), value.AsRegister<CpuRegister>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002295 __ j(kEqual, slow_path->GetEntryLabel());
2296 } else if (value.IsDoubleStackSlot()) {
2297 __ cmpq(Address(CpuRegister(RSP), value.GetStackIndex()), Immediate(0));
2298 __ j(kEqual, slow_path->GetEntryLabel());
2299 } else {
2300 DCHECK(value.IsConstant()) << value;
2301 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
2302 __ jmp(slow_path->GetEntryLabel());
2303 }
2304 }
2305 break;
2306 }
2307 default:
2308 LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
Calin Juravled0d48522014-11-04 16:40:20 +00002309 }
Calin Juravled0d48522014-11-04 16:40:20 +00002310}
2311
Calin Juravle9aec02f2014-11-18 23:06:35 +00002312void LocationsBuilderX86_64::HandleShift(HBinaryOperation* op) {
2313 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
2314
2315 LocationSummary* locations =
2316 new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
2317
2318 switch (op->GetResultType()) {
2319 case Primitive::kPrimInt:
2320 case Primitive::kPrimLong: {
2321 locations->SetInAt(0, Location::RequiresRegister());
2322 // The shift count needs to be in CL.
2323 locations->SetInAt(1, Location::ByteRegisterOrConstant(RCX, op->InputAt(1)));
2324 locations->SetOut(Location::SameAsFirstInput());
2325 break;
2326 }
2327 default:
2328 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
2329 }
2330}
2331
2332void InstructionCodeGeneratorX86_64::HandleShift(HBinaryOperation* op) {
2333 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
2334
2335 LocationSummary* locations = op->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002336 CpuRegister first_reg = locations->InAt(0).AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002337 Location second = locations->InAt(1);
2338
2339 switch (op->GetResultType()) {
2340 case Primitive::kPrimInt: {
2341 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002342 CpuRegister second_reg = second.AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002343 if (op->IsShl()) {
2344 __ shll(first_reg, second_reg);
2345 } else if (op->IsShr()) {
2346 __ sarl(first_reg, second_reg);
2347 } else {
2348 __ shrl(first_reg, second_reg);
2349 }
2350 } else {
Nicolas Geoffray486cc192014-12-08 18:00:55 +00002351 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxIntShiftValue);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002352 if (op->IsShl()) {
2353 __ shll(first_reg, imm);
2354 } else if (op->IsShr()) {
2355 __ sarl(first_reg, imm);
2356 } else {
2357 __ shrl(first_reg, imm);
2358 }
2359 }
2360 break;
2361 }
2362 case Primitive::kPrimLong: {
2363 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002364 CpuRegister second_reg = second.AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002365 if (op->IsShl()) {
2366 __ shlq(first_reg, second_reg);
2367 } else if (op->IsShr()) {
2368 __ sarq(first_reg, second_reg);
2369 } else {
2370 __ shrq(first_reg, second_reg);
2371 }
2372 } else {
Nicolas Geoffray486cc192014-12-08 18:00:55 +00002373 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxLongShiftValue);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002374 if (op->IsShl()) {
2375 __ shlq(first_reg, imm);
2376 } else if (op->IsShr()) {
2377 __ sarq(first_reg, imm);
2378 } else {
2379 __ shrq(first_reg, imm);
2380 }
2381 }
2382 break;
2383 }
2384 default:
2385 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
2386 }
2387}
2388
2389void LocationsBuilderX86_64::VisitShl(HShl* shl) {
2390 HandleShift(shl);
2391}
2392
2393void InstructionCodeGeneratorX86_64::VisitShl(HShl* shl) {
2394 HandleShift(shl);
2395}
2396
2397void LocationsBuilderX86_64::VisitShr(HShr* shr) {
2398 HandleShift(shr);
2399}
2400
2401void InstructionCodeGeneratorX86_64::VisitShr(HShr* shr) {
2402 HandleShift(shr);
2403}
2404
2405void LocationsBuilderX86_64::VisitUShr(HUShr* ushr) {
2406 HandleShift(ushr);
2407}
2408
2409void InstructionCodeGeneratorX86_64::VisitUShr(HUShr* ushr) {
2410 HandleShift(ushr);
2411}
2412
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002413void LocationsBuilderX86_64::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002414 LocationSummary* locations =
2415 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01002416 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002417 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2418 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
2419 locations->SetOut(Location::RegisterLocation(RAX));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002420}
2421
2422void InstructionCodeGeneratorX86_64::VisitNewInstance(HNewInstance* instruction) {
2423 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002424 codegen_->LoadCurrentMethod(CpuRegister(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002425 __ movq(CpuRegister(calling_convention.GetRegisterAt(0)), Immediate(instruction->GetTypeIndex()));
2426
2427 __ gs()->call(Address::Absolute(
2428 QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pAllocObjectWithAccessCheck), true));
2429
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01002430 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray39468442014-09-02 15:17:15 +01002431 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002432}
2433
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002434void LocationsBuilderX86_64::VisitNewArray(HNewArray* instruction) {
2435 LocationSummary* locations =
2436 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
2437 InvokeRuntimeCallingConvention calling_convention;
2438 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002439 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002440 locations->SetOut(Location::RegisterLocation(RAX));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002441 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002442}
2443
2444void InstructionCodeGeneratorX86_64::VisitNewArray(HNewArray* instruction) {
2445 InvokeRuntimeCallingConvention calling_convention;
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002446 codegen_->LoadCurrentMethod(CpuRegister(calling_convention.GetRegisterAt(2)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002447 __ movq(CpuRegister(calling_convention.GetRegisterAt(0)), Immediate(instruction->GetTypeIndex()));
2448
2449 __ gs()->call(Address::Absolute(
2450 QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pAllocArrayWithAccessCheck), true));
2451
2452 DCHECK(!codegen_->IsLeafMethod());
2453 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
2454}
2455
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002456void LocationsBuilderX86_64::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002457 LocationSummary* locations =
2458 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002459 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
2460 if (location.IsStackSlot()) {
2461 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
2462 } else if (location.IsDoubleStackSlot()) {
2463 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
2464 }
2465 locations->SetOut(location);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002466}
2467
2468void InstructionCodeGeneratorX86_64::VisitParameterValue(HParameterValue* instruction) {
2469 // Nothing to do, the parameter is already at its location.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07002470 UNUSED(instruction);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002471}
2472
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002473void LocationsBuilderX86_64::VisitNot(HNot* not_) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002474 LocationSummary* locations =
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002475 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002476 locations->SetInAt(0, Location::RequiresRegister());
2477 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002478}
2479
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002480void InstructionCodeGeneratorX86_64::VisitNot(HNot* not_) {
2481 LocationSummary* locations = not_->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002482 DCHECK_EQ(locations->InAt(0).AsRegister<CpuRegister>().AsRegister(),
2483 locations->Out().AsRegister<CpuRegister>().AsRegister());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002484 Location out = locations->Out();
2485 switch (not_->InputAt(0)->GetType()) {
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002486 case Primitive::kPrimInt:
Roland Levillain271ab9c2014-11-27 15:23:57 +00002487 __ notl(out.AsRegister<CpuRegister>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002488 break;
2489
2490 case Primitive::kPrimLong:
Roland Levillain271ab9c2014-11-27 15:23:57 +00002491 __ notq(out.AsRegister<CpuRegister>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002492 break;
2493
2494 default:
2495 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
2496 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002497}
2498
2499void LocationsBuilderX86_64::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002500 LocationSummary* locations =
2501 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002502 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
2503 locations->SetInAt(i, Location::Any());
2504 }
2505 locations->SetOut(Location::Any());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002506}
2507
2508void InstructionCodeGeneratorX86_64::VisitPhi(HPhi* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07002509 UNUSED(instruction);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002510 LOG(FATAL) << "Unimplemented";
2511}
2512
Calin Juravle52c48962014-12-16 17:02:57 +00002513void InstructionCodeGeneratorX86_64::GenerateMemoryBarrier(MemBarrierKind kind) {
2514 /*
2515 * According to the JSR-133 Cookbook, for x86 only StoreLoad/AnyAny barriers need memory fence.
2516 * All other barriers (LoadAny, AnyStore, StoreStore) are nops due to the x86 memory model.
2517 * For those cases, all we need to ensure is that there is a scheduling barrier in place.
2518 */
2519 switch (kind) {
2520 case MemBarrierKind::kAnyAny: {
2521 __ mfence();
2522 break;
2523 }
2524 case MemBarrierKind::kAnyStore:
2525 case MemBarrierKind::kLoadAny:
2526 case MemBarrierKind::kStoreStore: {
2527 // nop
2528 break;
2529 }
2530 default:
2531 LOG(FATAL) << "Unexpected memory barier " << kind;
2532 }
2533}
2534
2535void LocationsBuilderX86_64::HandleFieldGet(HInstruction* instruction) {
2536 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
2537
Nicolas Geoffray39468442014-09-02 15:17:15 +01002538 LocationSummary* locations =
2539 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Calin Juravle52c48962014-12-16 17:02:57 +00002540 locations->SetInAt(0, Location::RequiresRegister());
2541 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2542}
2543
2544void InstructionCodeGeneratorX86_64::HandleFieldGet(HInstruction* instruction,
2545 const FieldInfo& field_info) {
2546 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
2547
2548 LocationSummary* locations = instruction->GetLocations();
2549 CpuRegister base = locations->InAt(0).AsRegister<CpuRegister>();
2550 Location out = locations->Out();
2551 bool is_volatile = field_info.IsVolatile();
2552 Primitive::Type field_type = field_info.GetFieldType();
2553 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
2554
2555 switch (field_type) {
2556 case Primitive::kPrimBoolean: {
2557 __ movzxb(out.AsRegister<CpuRegister>(), Address(base, offset));
2558 break;
2559 }
2560
2561 case Primitive::kPrimByte: {
2562 __ movsxb(out.AsRegister<CpuRegister>(), Address(base, offset));
2563 break;
2564 }
2565
2566 case Primitive::kPrimShort: {
2567 __ movsxw(out.AsRegister<CpuRegister>(), Address(base, offset));
2568 break;
2569 }
2570
2571 case Primitive::kPrimChar: {
2572 __ movzxw(out.AsRegister<CpuRegister>(), Address(base, offset));
2573 break;
2574 }
2575
2576 case Primitive::kPrimInt:
2577 case Primitive::kPrimNot: {
2578 __ movl(out.AsRegister<CpuRegister>(), Address(base, offset));
2579 break;
2580 }
2581
2582 case Primitive::kPrimLong: {
2583 __ movq(out.AsRegister<CpuRegister>(), Address(base, offset));
2584 break;
2585 }
2586
2587 case Primitive::kPrimFloat: {
2588 __ movss(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
2589 break;
2590 }
2591
2592 case Primitive::kPrimDouble: {
2593 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
2594 break;
2595 }
2596
2597 case Primitive::kPrimVoid:
2598 LOG(FATAL) << "Unreachable type " << field_type;
2599 UNREACHABLE();
2600 }
2601
Calin Juravle77520bc2015-01-12 18:45:46 +00002602 codegen_->MaybeRecordImplicitNullCheck(instruction);
2603
Calin Juravle52c48962014-12-16 17:02:57 +00002604 if (is_volatile) {
2605 GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
2606 }
2607}
2608
2609void LocationsBuilderX86_64::HandleFieldSet(HInstruction* instruction,
2610 const FieldInfo& field_info) {
2611 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
2612
2613 LocationSummary* locations =
2614 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00002615 bool needs_write_barrier =
Calin Juravle52c48962014-12-16 17:02:57 +00002616 CodeGenerator::StoreNeedsWriteBarrier(field_info.GetFieldType(), instruction->InputAt(1));
2617
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002618 locations->SetInAt(0, Location::RequiresRegister());
2619 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00002620 if (needs_write_barrier) {
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01002621 // Temporary registers for the write barrier.
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01002622 locations->AddTemp(Location::RequiresRegister());
2623 locations->AddTemp(Location::RequiresRegister());
2624 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002625}
2626
Calin Juravle52c48962014-12-16 17:02:57 +00002627void InstructionCodeGeneratorX86_64::HandleFieldSet(HInstruction* instruction,
2628 const FieldInfo& field_info) {
2629 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
2630
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002631 LocationSummary* locations = instruction->GetLocations();
Calin Juravle52c48962014-12-16 17:02:57 +00002632 CpuRegister base = locations->InAt(0).AsRegister<CpuRegister>();
2633 Location value = locations->InAt(1);
2634 bool is_volatile = field_info.IsVolatile();
2635 Primitive::Type field_type = field_info.GetFieldType();
2636 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
2637
2638 if (is_volatile) {
2639 GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
2640 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002641
2642 switch (field_type) {
2643 case Primitive::kPrimBoolean:
2644 case Primitive::kPrimByte: {
Calin Juravle52c48962014-12-16 17:02:57 +00002645 __ movb(Address(base, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002646 break;
2647 }
2648
2649 case Primitive::kPrimShort:
2650 case Primitive::kPrimChar: {
Calin Juravle52c48962014-12-16 17:02:57 +00002651 __ movw(Address(base, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002652 break;
2653 }
2654
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002655 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002656 case Primitive::kPrimNot: {
Calin Juravle52c48962014-12-16 17:02:57 +00002657 __ movl(Address(base, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002658 break;
2659 }
2660
2661 case Primitive::kPrimLong: {
Calin Juravle52c48962014-12-16 17:02:57 +00002662 __ movq(Address(base, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002663 break;
2664 }
2665
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00002666 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00002667 __ movss(Address(base, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00002668 break;
2669 }
2670
2671 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00002672 __ movsd(Address(base, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00002673 break;
2674 }
2675
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002676 case Primitive::kPrimVoid:
2677 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07002678 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002679 }
Calin Juravle52c48962014-12-16 17:02:57 +00002680
Calin Juravle77520bc2015-01-12 18:45:46 +00002681 codegen_->MaybeRecordImplicitNullCheck(instruction);
2682
2683 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
2684 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
2685 CpuRegister card = locations->GetTemp(1).AsRegister<CpuRegister>();
2686 codegen_->MarkGCCard(temp, card, base, value.AsRegister<CpuRegister>());
2687 }
2688
Calin Juravle52c48962014-12-16 17:02:57 +00002689 if (is_volatile) {
2690 GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
2691 }
2692}
2693
2694void LocationsBuilderX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
2695 HandleFieldSet(instruction, instruction->GetFieldInfo());
2696}
2697
2698void InstructionCodeGeneratorX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
2699 HandleFieldSet(instruction, instruction->GetFieldInfo());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002700}
2701
2702void LocationsBuilderX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Calin Juravle52c48962014-12-16 17:02:57 +00002703 HandleFieldGet(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002704}
2705
2706void InstructionCodeGeneratorX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Calin Juravle52c48962014-12-16 17:02:57 +00002707 HandleFieldGet(instruction, instruction->GetFieldInfo());
2708}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002709
Calin Juravle52c48962014-12-16 17:02:57 +00002710void LocationsBuilderX86_64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
2711 HandleFieldGet(instruction);
2712}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002713
Calin Juravle52c48962014-12-16 17:02:57 +00002714void InstructionCodeGeneratorX86_64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
2715 HandleFieldGet(instruction, instruction->GetFieldInfo());
2716}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002717
Calin Juravle52c48962014-12-16 17:02:57 +00002718void LocationsBuilderX86_64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
2719 HandleFieldSet(instruction, instruction->GetFieldInfo());
2720}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002721
Calin Juravle52c48962014-12-16 17:02:57 +00002722void InstructionCodeGeneratorX86_64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
2723 HandleFieldSet(instruction, instruction->GetFieldInfo());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002724}
2725
2726void LocationsBuilderX86_64::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002727 LocationSummary* locations =
2728 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Calin Juravlecd6dffe2015-01-08 17:35:35 +00002729 Location loc = codegen_->GetCompilerOptions().GetImplicitNullChecks()
2730 ? Location::RequiresRegister()
2731 : Location::Any();
2732 locations->SetInAt(0, loc);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002733 if (instruction->HasUses()) {
2734 locations->SetOut(Location::SameAsFirstInput());
2735 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002736}
2737
Calin Juravlecd6dffe2015-01-08 17:35:35 +00002738void InstructionCodeGeneratorX86_64::GenerateImplicitNullCheck(HNullCheck* instruction) {
Calin Juravle77520bc2015-01-12 18:45:46 +00002739 if (codegen_->CanMoveNullCheckToUser(instruction)) {
2740 return;
2741 }
Calin Juravlecd6dffe2015-01-08 17:35:35 +00002742 LocationSummary* locations = instruction->GetLocations();
2743 Location obj = locations->InAt(0);
2744
2745 __ testl(CpuRegister(RAX), Address(obj.AsRegister<CpuRegister>(), 0));
2746 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
2747}
2748
2749void InstructionCodeGeneratorX86_64::GenerateExplicitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +01002750 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathX86_64(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002751 codegen_->AddSlowPath(slow_path);
2752
2753 LocationSummary* locations = instruction->GetLocations();
2754 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002755
2756 if (obj.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002757 __ cmpl(obj.AsRegister<CpuRegister>(), Immediate(0));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002758 } else if (obj.IsStackSlot()) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002759 __ cmpl(Address(CpuRegister(RSP), obj.GetStackIndex()), Immediate(0));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002760 } else {
2761 DCHECK(obj.IsConstant()) << obj;
2762 DCHECK_EQ(obj.GetConstant()->AsIntConstant()->GetValue(), 0);
2763 __ jmp(slow_path->GetEntryLabel());
2764 return;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002765 }
2766 __ j(kEqual, slow_path->GetEntryLabel());
2767}
2768
Calin Juravlecd6dffe2015-01-08 17:35:35 +00002769void InstructionCodeGeneratorX86_64::VisitNullCheck(HNullCheck* instruction) {
2770 if (codegen_->GetCompilerOptions().GetImplicitNullChecks()) {
2771 GenerateImplicitNullCheck(instruction);
2772 } else {
2773 GenerateExplicitNullCheck(instruction);
2774 }
2775}
2776
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002777void LocationsBuilderX86_64::VisitArrayGet(HArrayGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002778 LocationSummary* locations =
2779 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002780 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01002781 locations->SetInAt(
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002782 1, Location::RegisterOrConstant(instruction->InputAt(1)));
2783 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002784}
2785
2786void InstructionCodeGeneratorX86_64::VisitArrayGet(HArrayGet* instruction) {
2787 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002788 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002789 Location index = locations->InAt(1);
2790
2791 switch (instruction->GetType()) {
2792 case Primitive::kPrimBoolean: {
2793 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002794 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002795 if (index.IsConstant()) {
2796 __ movzxb(out, Address(obj,
2797 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
2798 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002799 __ movzxb(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002800 }
2801 break;
2802 }
2803
2804 case Primitive::kPrimByte: {
2805 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002806 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002807 if (index.IsConstant()) {
2808 __ movsxb(out, Address(obj,
2809 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
2810 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002811 __ movsxb(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002812 }
2813 break;
2814 }
2815
2816 case Primitive::kPrimShort: {
2817 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002818 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002819 if (index.IsConstant()) {
2820 __ movsxw(out, Address(obj,
2821 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
2822 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002823 __ movsxw(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002824 }
2825 break;
2826 }
2827
2828 case Primitive::kPrimChar: {
2829 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002830 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002831 if (index.IsConstant()) {
2832 __ movzxw(out, Address(obj,
2833 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
2834 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002835 __ movzxw(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002836 }
2837 break;
2838 }
2839
2840 case Primitive::kPrimInt:
2841 case Primitive::kPrimNot: {
2842 DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t));
2843 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002844 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002845 if (index.IsConstant()) {
2846 __ movl(out, Address(obj,
2847 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
2848 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002849 __ movl(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002850 }
2851 break;
2852 }
2853
2854 case Primitive::kPrimLong: {
2855 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002856 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002857 if (index.IsConstant()) {
2858 __ movq(out, Address(obj,
2859 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
2860 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002861 __ movq(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002862 }
2863 break;
2864 }
2865
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01002866 case Primitive::kPrimFloat: {
2867 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002868 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01002869 if (index.IsConstant()) {
2870 __ movss(out, Address(obj,
2871 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
2872 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002873 __ movss(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01002874 }
2875 break;
2876 }
2877
2878 case Primitive::kPrimDouble: {
2879 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002880 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01002881 if (index.IsConstant()) {
2882 __ movsd(out, Address(obj,
2883 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
2884 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002885 __ movsd(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01002886 }
2887 break;
2888 }
2889
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002890 case Primitive::kPrimVoid:
2891 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07002892 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002893 }
Calin Juravle77520bc2015-01-12 18:45:46 +00002894 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002895}
2896
2897void LocationsBuilderX86_64::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002898 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00002899
2900 bool needs_write_barrier =
2901 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
2902 bool needs_runtime_call = instruction->NeedsTypeCheck();
2903
Nicolas Geoffray39468442014-09-02 15:17:15 +01002904 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00002905 instruction, needs_runtime_call ? LocationSummary::kCall : LocationSummary::kNoCall);
2906 if (needs_runtime_call) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002907 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002908 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2909 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
2910 locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002911 } else {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002912 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01002913 locations->SetInAt(
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002914 1, Location::RegisterOrConstant(instruction->InputAt(1)));
2915 locations->SetInAt(2, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002916 if (value_type == Primitive::kPrimLong) {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002917 locations->SetInAt(2, Location::RequiresRegister());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01002918 } else if (value_type == Primitive::kPrimFloat || value_type == Primitive::kPrimDouble) {
2919 locations->SetInAt(2, Location::RequiresFpuRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002920 } else {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002921 locations->SetInAt(2, Location::RegisterOrConstant(instruction->InputAt(2)));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002922 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00002923
2924 if (needs_write_barrier) {
2925 // Temporary registers for the write barrier.
2926 locations->AddTemp(Location::RequiresRegister());
2927 locations->AddTemp(Location::RequiresRegister());
2928 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002929 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002930}
2931
2932void InstructionCodeGeneratorX86_64::VisitArraySet(HArraySet* instruction) {
2933 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002934 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002935 Location index = locations->InAt(1);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002936 Location value = locations->InAt(2);
Nicolas Geoffray39468442014-09-02 15:17:15 +01002937 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00002938 bool needs_runtime_call = locations->WillCall();
2939 bool needs_write_barrier =
2940 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002941
2942 switch (value_type) {
2943 case Primitive::kPrimBoolean:
2944 case Primitive::kPrimByte: {
2945 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002946 if (index.IsConstant()) {
2947 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002948 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002949 __ movb(Address(obj, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002950 } else {
Roland Levillain199f3362014-11-27 17:15:16 +00002951 __ movb(Address(obj, offset),
2952 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002953 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002954 } else {
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002955 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002956 __ movb(Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset),
2957 value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002958 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002959 __ movb(Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002960 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
2961 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002962 }
Calin Juravle77520bc2015-01-12 18:45:46 +00002963 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002964 break;
2965 }
2966
2967 case Primitive::kPrimShort:
2968 case Primitive::kPrimChar: {
2969 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002970 if (index.IsConstant()) {
2971 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002972 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002973 __ movw(Address(obj, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002974 } else {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00002975 DCHECK(value.IsConstant()) << value;
Roland Levillain199f3362014-11-27 17:15:16 +00002976 __ movw(Address(obj, offset),
2977 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002978 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002979 } else {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00002980 DCHECK(index.IsRegister()) << index;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002981 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002982 __ movw(Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset),
2983 value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002984 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01002985 DCHECK(value.IsConstant()) << value;
Roland Levillain271ab9c2014-11-27 15:23:57 +00002986 __ movw(Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002987 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
2988 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002989 }
Calin Juravle77520bc2015-01-12 18:45:46 +00002990 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002991 break;
2992 }
2993
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00002994 case Primitive::kPrimInt:
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002995 case Primitive::kPrimNot: {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00002996 if (!needs_runtime_call) {
2997 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
2998 if (index.IsConstant()) {
2999 size_t offset =
3000 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
3001 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003002 __ movl(Address(obj, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003003 } else {
3004 DCHECK(value.IsConstant()) << value;
3005 __ movl(Address(obj, offset),
3006 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3007 }
3008 } else {
3009 DCHECK(index.IsRegister()) << index;
3010 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003011 __ movl(Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset),
3012 value.AsRegister<CpuRegister>());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003013 } else {
3014 DCHECK(value.IsConstant()) << value;
Roland Levillain271ab9c2014-11-27 15:23:57 +00003015 __ movl(Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset),
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003016 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3017 }
3018 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003019 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003020 if (needs_write_barrier) {
3021 DCHECK_EQ(value_type, Primitive::kPrimNot);
Roland Levillain271ab9c2014-11-27 15:23:57 +00003022 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
3023 CpuRegister card = locations->GetTemp(1).AsRegister<CpuRegister>();
3024 codegen_->MarkGCCard(temp, card, obj, value.AsRegister<CpuRegister>());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003025 }
3026 } else {
3027 DCHECK_EQ(value_type, Primitive::kPrimNot);
Roland Levillain199f3362014-11-27 17:15:16 +00003028 __ gs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pAputObject),
3029 true));
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003030 DCHECK(!codegen_->IsLeafMethod());
3031 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3032 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003033 break;
3034 }
3035
3036 case Primitive::kPrimLong: {
3037 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003038 if (index.IsConstant()) {
3039 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003040 DCHECK(value.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003041 __ movq(Address(obj, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003042 } else {
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003043 DCHECK(value.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003044 __ movq(Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset),
3045 value.AsRegister<CpuRegister>());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003046 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003047 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003048 break;
3049 }
3050
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003051 case Primitive::kPrimFloat: {
3052 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
3053 if (index.IsConstant()) {
3054 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
3055 DCHECK(value.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003056 __ movss(Address(obj, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003057 } else {
3058 DCHECK(value.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003059 __ movss(Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset),
3060 value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003061 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003062 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003063 break;
3064 }
3065
3066 case Primitive::kPrimDouble: {
3067 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
3068 if (index.IsConstant()) {
3069 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
3070 DCHECK(value.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003071 __ movsd(Address(obj, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003072 } else {
3073 DCHECK(value.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003074 __ movsd(Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset),
3075 value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003076 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003077 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003078 break;
3079 }
3080
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003081 case Primitive::kPrimVoid:
3082 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07003083 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003084 }
3085}
3086
3087void LocationsBuilderX86_64::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003088 LocationSummary* locations =
3089 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003090 locations->SetInAt(0, Location::RequiresRegister());
3091 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003092}
3093
3094void InstructionCodeGeneratorX86_64::VisitArrayLength(HArrayLength* instruction) {
3095 LocationSummary* locations = instruction->GetLocations();
3096 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003097 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
3098 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003099 __ movl(out, Address(obj, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00003100 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003101}
3102
3103void LocationsBuilderX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003104 LocationSummary* locations =
3105 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003106 locations->SetInAt(0, Location::RequiresRegister());
3107 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003108 if (instruction->HasUses()) {
3109 locations->SetOut(Location::SameAsFirstInput());
3110 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003111}
3112
3113void InstructionCodeGeneratorX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
3114 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +01003115 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathX86_64(
Nicolas Geoffray39468442014-09-02 15:17:15 +01003116 instruction, locations->InAt(0), locations->InAt(1));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003117 codegen_->AddSlowPath(slow_path);
3118
Roland Levillain271ab9c2014-11-27 15:23:57 +00003119 CpuRegister index = locations->InAt(0).AsRegister<CpuRegister>();
3120 CpuRegister length = locations->InAt(1).AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003121
3122 __ cmpl(index, length);
3123 __ j(kAboveEqual, slow_path->GetEntryLabel());
3124}
3125
3126void CodeGeneratorX86_64::MarkGCCard(CpuRegister temp,
3127 CpuRegister card,
3128 CpuRegister object,
3129 CpuRegister value) {
3130 Label is_null;
3131 __ testl(value, value);
3132 __ j(kEqual, &is_null);
3133 __ gs()->movq(card, Address::Absolute(
3134 Thread::CardTableOffset<kX86_64WordSize>().Int32Value(), true));
3135 __ movq(temp, object);
3136 __ shrq(temp, Immediate(gc::accounting::CardTable::kCardShift));
3137 __ movb(Address(temp, card, TIMES_1, 0), card);
3138 __ Bind(&is_null);
3139}
3140
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003141void LocationsBuilderX86_64::VisitTemporary(HTemporary* temp) {
3142 temp->SetLocations(nullptr);
3143}
3144
3145void InstructionCodeGeneratorX86_64::VisitTemporary(HTemporary* temp) {
3146 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003147 UNUSED(temp);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003148}
3149
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003150void LocationsBuilderX86_64::VisitParallelMove(HParallelMove* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003151 UNUSED(instruction);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003152 LOG(FATAL) << "Unimplemented";
3153}
3154
3155void InstructionCodeGeneratorX86_64::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003156 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
3157}
3158
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003159void LocationsBuilderX86_64::VisitSuspendCheck(HSuspendCheck* instruction) {
3160 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
3161}
3162
3163void InstructionCodeGeneratorX86_64::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003164 HBasicBlock* block = instruction->GetBlock();
3165 if (block->GetLoopInformation() != nullptr) {
3166 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
3167 // The back edge will generate the suspend check.
3168 return;
3169 }
3170 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
3171 // The goto will generate the suspend check.
3172 return;
3173 }
3174 GenerateSuspendCheck(instruction, nullptr);
3175}
3176
3177void InstructionCodeGeneratorX86_64::GenerateSuspendCheck(HSuspendCheck* instruction,
3178 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003179 SuspendCheckSlowPathX86_64* slow_path =
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003180 new (GetGraph()->GetArena()) SuspendCheckSlowPathX86_64(instruction, successor);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003181 codegen_->AddSlowPath(slow_path);
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003182 __ gs()->cmpw(Address::Absolute(
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003183 Thread::ThreadFlagsOffset<kX86_64WordSize>().Int32Value(), true), Immediate(0));
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003184 if (successor == nullptr) {
3185 __ j(kNotEqual, slow_path->GetEntryLabel());
3186 __ Bind(slow_path->GetReturnLabel());
3187 } else {
3188 __ j(kEqual, codegen_->GetLabelOf(successor));
3189 __ jmp(slow_path->GetEntryLabel());
3190 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003191}
3192
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003193X86_64Assembler* ParallelMoveResolverX86_64::GetAssembler() const {
3194 return codegen_->GetAssembler();
3195}
3196
3197void ParallelMoveResolverX86_64::EmitMove(size_t index) {
3198 MoveOperands* move = moves_.Get(index);
3199 Location source = move->GetSource();
3200 Location destination = move->GetDestination();
3201
3202 if (source.IsRegister()) {
3203 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003204 __ movq(destination.AsRegister<CpuRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003205 } else if (destination.IsStackSlot()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003206 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00003207 source.AsRegister<CpuRegister>());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003208 } else {
3209 DCHECK(destination.IsDoubleStackSlot());
3210 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00003211 source.AsRegister<CpuRegister>());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003212 }
3213 } else if (source.IsStackSlot()) {
3214 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003215 __ movl(destination.AsRegister<CpuRegister>(),
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003216 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003217 } else if (destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003218 __ movss(destination.AsFpuRegister<XmmRegister>(),
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003219 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003220 } else {
3221 DCHECK(destination.IsStackSlot());
3222 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
3223 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
3224 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003225 } else if (source.IsDoubleStackSlot()) {
3226 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003227 __ movq(destination.AsRegister<CpuRegister>(),
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003228 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003229 } else if (destination.IsFpuRegister()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003230 __ movsd(destination.AsFpuRegister<XmmRegister>(),
3231 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003232 } else {
Nicolas Geoffrayc8147a72014-10-21 16:06:20 +01003233 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003234 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
3235 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
3236 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003237 } else if (source.IsConstant()) {
3238 HConstant* constant = source.GetConstant();
3239 if (constant->IsIntConstant()) {
3240 Immediate imm(constant->AsIntConstant()->GetValue());
3241 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003242 __ movl(destination.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003243 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003244 DCHECK(destination.IsStackSlot()) << destination;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003245 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), imm);
3246 }
3247 } else if (constant->IsLongConstant()) {
3248 int64_t value = constant->AsLongConstant()->GetValue();
3249 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003250 __ movq(destination.AsRegister<CpuRegister>(), Immediate(value));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003251 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003252 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003253 __ movq(CpuRegister(TMP), Immediate(value));
3254 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
3255 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003256 } else if (constant->IsFloatConstant()) {
3257 Immediate imm(bit_cast<float, int32_t>(constant->AsFloatConstant()->GetValue()));
3258 if (destination.IsFpuRegister()) {
3259 __ movl(CpuRegister(TMP), imm);
Roland Levillain271ab9c2014-11-27 15:23:57 +00003260 __ movd(destination.AsFpuRegister<XmmRegister>(), CpuRegister(TMP));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003261 } else {
3262 DCHECK(destination.IsStackSlot()) << destination;
3263 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), imm);
3264 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003265 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003266 DCHECK(constant->IsDoubleConstant()) << constant->DebugName();
3267 Immediate imm(bit_cast<double, int64_t>(constant->AsDoubleConstant()->GetValue()));
3268 if (destination.IsFpuRegister()) {
3269 __ movq(CpuRegister(TMP), imm);
Roland Levillain271ab9c2014-11-27 15:23:57 +00003270 __ movd(destination.AsFpuRegister<XmmRegister>(), CpuRegister(TMP));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003271 } else {
3272 DCHECK(destination.IsDoubleStackSlot()) << destination;
3273 __ movq(CpuRegister(TMP), imm);
3274 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
3275 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003276 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003277 } else if (source.IsFpuRegister()) {
3278 if (destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003279 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003280 } else if (destination.IsStackSlot()) {
3281 __ movss(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00003282 source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003283 } else {
Nicolas Geoffray31596742014-11-24 15:28:45 +00003284 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003285 __ movsd(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00003286 source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003287 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003288 }
3289}
3290
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003291void ParallelMoveResolverX86_64::Exchange32(CpuRegister reg, int mem) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003292 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003293 __ movl(Address(CpuRegister(RSP), mem), reg);
3294 __ movl(reg, CpuRegister(TMP));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003295}
3296
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003297void ParallelMoveResolverX86_64::Exchange32(int mem1, int mem2) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003298 ScratchRegisterScope ensure_scratch(
3299 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
3300
3301 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
3302 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
3303 __ movl(CpuRegister(ensure_scratch.GetRegister()),
3304 Address(CpuRegister(RSP), mem2 + stack_offset));
3305 __ movl(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
3306 __ movl(Address(CpuRegister(RSP), mem1 + stack_offset),
3307 CpuRegister(ensure_scratch.GetRegister()));
3308}
3309
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003310void ParallelMoveResolverX86_64::Exchange64(CpuRegister reg, int mem) {
3311 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
3312 __ movq(Address(CpuRegister(RSP), mem), reg);
3313 __ movq(reg, CpuRegister(TMP));
3314}
3315
3316void ParallelMoveResolverX86_64::Exchange64(int mem1, int mem2) {
3317 ScratchRegisterScope ensure_scratch(
3318 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
3319
3320 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
3321 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
3322 __ movq(CpuRegister(ensure_scratch.GetRegister()),
3323 Address(CpuRegister(RSP), mem2 + stack_offset));
3324 __ movq(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
3325 __ movq(Address(CpuRegister(RSP), mem1 + stack_offset),
3326 CpuRegister(ensure_scratch.GetRegister()));
3327}
3328
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003329void ParallelMoveResolverX86_64::Exchange32(XmmRegister reg, int mem) {
3330 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
3331 __ movss(Address(CpuRegister(RSP), mem), reg);
3332 __ movd(reg, CpuRegister(TMP));
3333}
3334
3335void ParallelMoveResolverX86_64::Exchange64(XmmRegister reg, int mem) {
3336 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
3337 __ movsd(Address(CpuRegister(RSP), mem), reg);
3338 __ movd(reg, CpuRegister(TMP));
3339}
3340
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003341void ParallelMoveResolverX86_64::EmitSwap(size_t index) {
3342 MoveOperands* move = moves_.Get(index);
3343 Location source = move->GetSource();
3344 Location destination = move->GetDestination();
3345
3346 if (source.IsRegister() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003347 __ xchgq(destination.AsRegister<CpuRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003348 } else if (source.IsRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003349 Exchange32(source.AsRegister<CpuRegister>(), destination.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003350 } else if (source.IsStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003351 Exchange32(destination.AsRegister<CpuRegister>(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003352 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003353 Exchange32(destination.GetStackIndex(), source.GetStackIndex());
3354 } else if (source.IsRegister() && destination.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003355 Exchange64(source.AsRegister<CpuRegister>(), destination.GetStackIndex());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003356 } else if (source.IsDoubleStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003357 Exchange64(destination.AsRegister<CpuRegister>(), source.GetStackIndex());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003358 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
3359 Exchange64(destination.GetStackIndex(), source.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003360 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003361 __ movd(CpuRegister(TMP), source.AsFpuRegister<XmmRegister>());
3362 __ movaps(source.AsFpuRegister<XmmRegister>(), destination.AsFpuRegister<XmmRegister>());
3363 __ movd(destination.AsFpuRegister<XmmRegister>(), CpuRegister(TMP));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003364 } else if (source.IsFpuRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003365 Exchange32(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003366 } else if (source.IsStackSlot() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003367 Exchange32(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003368 } else if (source.IsFpuRegister() && destination.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003369 Exchange64(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003370 } else if (source.IsDoubleStackSlot() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003371 Exchange64(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003372 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003373 LOG(FATAL) << "Unimplemented swap between " << source << " and " << destination;
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003374 }
3375}
3376
3377
3378void ParallelMoveResolverX86_64::SpillScratch(int reg) {
3379 __ pushq(CpuRegister(reg));
3380}
3381
3382
3383void ParallelMoveResolverX86_64::RestoreScratch(int reg) {
3384 __ popq(CpuRegister(reg));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003385}
3386
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003387void InstructionCodeGeneratorX86_64::GenerateClassInitializationCheck(
3388 SlowPathCodeX86_64* slow_path, CpuRegister class_reg) {
3389 __ cmpl(Address(class_reg, mirror::Class::StatusOffset().Int32Value()),
3390 Immediate(mirror::Class::kStatusInitialized));
3391 __ j(kLess, slow_path->GetEntryLabel());
3392 __ Bind(slow_path->GetExitLabel());
3393 // No need for memory fence, thanks to the X86_64 memory model.
3394}
3395
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003396void LocationsBuilderX86_64::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003397 LocationSummary::CallKind call_kind = cls->CanCallRuntime()
3398 ? LocationSummary::kCallOnSlowPath
3399 : LocationSummary::kNoCall;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003400 LocationSummary* locations =
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003401 new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003402 locations->SetOut(Location::RequiresRegister());
3403}
3404
3405void InstructionCodeGeneratorX86_64::VisitLoadClass(HLoadClass* cls) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003406 CpuRegister out = cls->GetLocations()->Out().AsRegister<CpuRegister>();
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003407 if (cls->IsReferrersClass()) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003408 DCHECK(!cls->CanCallRuntime());
3409 DCHECK(!cls->MustGenerateClinitCheck());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003410 codegen_->LoadCurrentMethod(out);
3411 __ movl(out, Address(out, mirror::ArtMethod::DeclaringClassOffset().Int32Value()));
3412 } else {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003413 DCHECK(cls->CanCallRuntime());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003414 codegen_->LoadCurrentMethod(out);
3415 __ movl(out, Address(out, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value()));
3416 __ movl(out, Address(out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex())));
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003417 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86_64(
3418 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
3419 codegen_->AddSlowPath(slow_path);
3420 __ testl(out, out);
3421 __ j(kEqual, slow_path->GetEntryLabel());
3422 if (cls->MustGenerateClinitCheck()) {
3423 GenerateClassInitializationCheck(slow_path, out);
3424 } else {
3425 __ Bind(slow_path->GetExitLabel());
3426 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003427 }
3428}
3429
3430void LocationsBuilderX86_64::VisitClinitCheck(HClinitCheck* check) {
3431 LocationSummary* locations =
3432 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
3433 locations->SetInAt(0, Location::RequiresRegister());
3434 if (check->HasUses()) {
3435 locations->SetOut(Location::SameAsFirstInput());
3436 }
3437}
3438
3439void InstructionCodeGeneratorX86_64::VisitClinitCheck(HClinitCheck* check) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003440 // We assume the class to not be null.
3441 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86_64(
3442 check->GetLoadClass(), check, check->GetDexPc(), true);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003443 codegen_->AddSlowPath(slow_path);
Roland Levillain199f3362014-11-27 17:15:16 +00003444 GenerateClassInitializationCheck(slow_path,
3445 check->GetLocations()->InAt(0).AsRegister<CpuRegister>());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003446}
3447
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00003448void LocationsBuilderX86_64::VisitLoadString(HLoadString* load) {
3449 LocationSummary* locations =
3450 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
3451 locations->SetOut(Location::RequiresRegister());
3452}
3453
3454void InstructionCodeGeneratorX86_64::VisitLoadString(HLoadString* load) {
3455 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathX86_64(load);
3456 codegen_->AddSlowPath(slow_path);
3457
Roland Levillain271ab9c2014-11-27 15:23:57 +00003458 CpuRegister out = load->GetLocations()->Out().AsRegister<CpuRegister>();
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00003459 codegen_->LoadCurrentMethod(CpuRegister(out));
Mathieu Chartiereace4582014-11-24 18:29:54 -08003460 __ movl(out, Address(out, mirror::ArtMethod::DeclaringClassOffset().Int32Value()));
3461 __ movl(out, Address(out, mirror::Class::DexCacheStringsOffset().Int32Value()));
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00003462 __ movl(out, Address(out, CodeGenerator::GetCacheOffset(load->GetStringIndex())));
3463 __ testl(out, out);
3464 __ j(kEqual, slow_path->GetEntryLabel());
3465 __ Bind(slow_path->GetExitLabel());
3466}
3467
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00003468void LocationsBuilderX86_64::VisitLoadException(HLoadException* load) {
3469 LocationSummary* locations =
3470 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
3471 locations->SetOut(Location::RequiresRegister());
3472}
3473
3474void InstructionCodeGeneratorX86_64::VisitLoadException(HLoadException* load) {
3475 Address address = Address::Absolute(
3476 Thread::ExceptionOffset<kX86_64WordSize>().Int32Value(), true);
Roland Levillain271ab9c2014-11-27 15:23:57 +00003477 __ gs()->movl(load->GetLocations()->Out().AsRegister<CpuRegister>(), address);
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00003478 __ gs()->movl(address, Immediate(0));
3479}
3480
3481void LocationsBuilderX86_64::VisitThrow(HThrow* instruction) {
3482 LocationSummary* locations =
3483 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
3484 InvokeRuntimeCallingConvention calling_convention;
3485 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3486}
3487
3488void InstructionCodeGeneratorX86_64::VisitThrow(HThrow* instruction) {
3489 __ gs()->call(
3490 Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pDeliverException), true));
3491 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3492}
3493
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003494void LocationsBuilderX86_64::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003495 LocationSummary::CallKind call_kind = instruction->IsClassFinal()
3496 ? LocationSummary::kNoCall
3497 : LocationSummary::kCallOnSlowPath;
3498 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
3499 locations->SetInAt(0, Location::RequiresRegister());
3500 locations->SetInAt(1, Location::Any());
3501 locations->SetOut(Location::RequiresRegister());
3502}
3503
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003504void InstructionCodeGeneratorX86_64::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003505 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003506 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003507 Location cls = locations->InAt(1);
Roland Levillain271ab9c2014-11-27 15:23:57 +00003508 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003509 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
3510 Label done, zero;
3511 SlowPathCodeX86_64* slow_path = nullptr;
3512
3513 // Return 0 if `obj` is null.
3514 // TODO: avoid this check if we know obj is not null.
3515 __ testl(obj, obj);
3516 __ j(kEqual, &zero);
3517 // Compare the class of `obj` with `cls`.
3518 __ movl(out, Address(obj, class_offset));
3519 if (cls.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003520 __ cmpl(out, cls.AsRegister<CpuRegister>());
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003521 } else {
3522 DCHECK(cls.IsStackSlot()) << cls;
3523 __ cmpl(out, Address(CpuRegister(RSP), cls.GetStackIndex()));
3524 }
3525 if (instruction->IsClassFinal()) {
3526 // Classes must be equal for the instanceof to succeed.
3527 __ j(kNotEqual, &zero);
3528 __ movl(out, Immediate(1));
3529 __ jmp(&done);
3530 } else {
3531 // If the classes are not equal, we go into a slow path.
3532 DCHECK(locations->OnlyCallsOnSlowPath());
3533 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86_64(
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003534 instruction, locations->InAt(1), locations->Out(), instruction->GetDexPc());
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003535 codegen_->AddSlowPath(slow_path);
3536 __ j(kNotEqual, slow_path->GetEntryLabel());
3537 __ movl(out, Immediate(1));
3538 __ jmp(&done);
3539 }
3540 __ Bind(&zero);
3541 __ movl(out, Immediate(0));
3542 if (slow_path != nullptr) {
3543 __ Bind(slow_path->GetExitLabel());
3544 }
3545 __ Bind(&done);
3546}
3547
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003548void LocationsBuilderX86_64::VisitCheckCast(HCheckCast* instruction) {
3549 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
3550 instruction, LocationSummary::kCallOnSlowPath);
3551 locations->SetInAt(0, Location::RequiresRegister());
3552 locations->SetInAt(1, Location::Any());
3553 locations->AddTemp(Location::RequiresRegister());
3554}
3555
3556void InstructionCodeGeneratorX86_64::VisitCheckCast(HCheckCast* instruction) {
3557 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003558 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003559 Location cls = locations->InAt(1);
Roland Levillain271ab9c2014-11-27 15:23:57 +00003560 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003561 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
3562 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86_64(
3563 instruction, locations->InAt(1), locations->GetTemp(0), instruction->GetDexPc());
3564 codegen_->AddSlowPath(slow_path);
3565
3566 // TODO: avoid this check if we know obj is not null.
3567 __ testl(obj, obj);
3568 __ j(kEqual, slow_path->GetExitLabel());
3569 // Compare the class of `obj` with `cls`.
3570 __ movl(temp, Address(obj, class_offset));
3571 if (cls.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003572 __ cmpl(temp, cls.AsRegister<CpuRegister>());
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003573 } else {
3574 DCHECK(cls.IsStackSlot()) << cls;
3575 __ cmpl(temp, Address(CpuRegister(RSP), cls.GetStackIndex()));
3576 }
3577 // Classes must be equal for the checkcast to succeed.
3578 __ j(kNotEqual, slow_path->GetEntryLabel());
3579 __ Bind(slow_path->GetExitLabel());
3580}
3581
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00003582void LocationsBuilderX86_64::VisitMonitorOperation(HMonitorOperation* instruction) {
3583 LocationSummary* locations =
3584 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
3585 InvokeRuntimeCallingConvention calling_convention;
3586 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3587}
3588
3589void InstructionCodeGeneratorX86_64::VisitMonitorOperation(HMonitorOperation* instruction) {
3590 __ gs()->call(Address::Absolute(instruction->IsEnter()
3591 ? QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pLockObject)
3592 : QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pUnlockObject),
3593 true));
3594 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3595}
3596
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003597void LocationsBuilderX86_64::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); }
3598void LocationsBuilderX86_64::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); }
3599void LocationsBuilderX86_64::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); }
3600
3601void LocationsBuilderX86_64::HandleBitwiseOperation(HBinaryOperation* instruction) {
3602 LocationSummary* locations =
3603 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3604 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
3605 || instruction->GetResultType() == Primitive::kPrimLong);
3606 locations->SetInAt(0, Location::RequiresRegister());
3607 if (instruction->GetType() == Primitive::kPrimInt) {
3608 locations->SetInAt(1, Location::Any());
3609 } else {
3610 // Request a register to avoid loading a 64bits constant.
3611 locations->SetInAt(1, Location::RequiresRegister());
3612 }
3613 locations->SetOut(Location::SameAsFirstInput());
3614}
3615
3616void InstructionCodeGeneratorX86_64::VisitAnd(HAnd* instruction) {
3617 HandleBitwiseOperation(instruction);
3618}
3619
3620void InstructionCodeGeneratorX86_64::VisitOr(HOr* instruction) {
3621 HandleBitwiseOperation(instruction);
3622}
3623
3624void InstructionCodeGeneratorX86_64::VisitXor(HXor* instruction) {
3625 HandleBitwiseOperation(instruction);
3626}
3627
3628void InstructionCodeGeneratorX86_64::HandleBitwiseOperation(HBinaryOperation* instruction) {
3629 LocationSummary* locations = instruction->GetLocations();
3630 Location first = locations->InAt(0);
3631 Location second = locations->InAt(1);
3632 DCHECK(first.Equals(locations->Out()));
3633
3634 if (instruction->GetResultType() == Primitive::kPrimInt) {
3635 if (second.IsRegister()) {
3636 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003637 __ andl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003638 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003639 __ orl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003640 } else {
3641 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003642 __ xorl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003643 }
3644 } else if (second.IsConstant()) {
3645 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
3646 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003647 __ andl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003648 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003649 __ orl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003650 } else {
3651 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003652 __ xorl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003653 }
3654 } else {
3655 Address address(CpuRegister(RSP), second.GetStackIndex());
3656 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003657 __ andl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003658 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003659 __ orl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003660 } else {
3661 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003662 __ xorl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003663 }
3664 }
3665 } else {
3666 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
3667 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003668 __ andq(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003669 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003670 __ orq(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003671 } else {
3672 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003673 __ xorq(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003674 }
3675 }
3676}
3677
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003678} // namespace x86_64
3679} // namespace art