blob: 5710ec57d8fa31684f0e118d3dc49f6d8483dbf3 [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
Guillaume Sanchez0f88e872015-03-30 17:55:45 +010019#include "code_generator_utils.h"
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010020#include "entrypoints/quick/quick_entrypoints.h"
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +010021#include "gc/accounting/card_table.h"
Andreas Gampe71fb52f2014-12-29 17:43:08 -080022#include "intrinsics.h"
23#include "intrinsics_x86_64.h"
Ian Rogers7e70b002014-10-08 11:47:24 -070024#include "mirror/array-inl.h"
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010025#include "mirror/art_method.h"
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +010026#include "mirror/class.h"
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010027#include "mirror/object_reference.h"
28#include "thread.h"
29#include "utils/assembler.h"
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010030#include "utils/stack_checks.h"
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010031#include "utils/x86_64/assembler_x86_64.h"
32#include "utils/x86_64/managed_register_x86_64.h"
33
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010034namespace art {
35
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010036namespace x86_64 {
37
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010038// Some x86_64 instructions require a register to be available as temp.
39static constexpr Register TMP = R11;
40
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010041static constexpr int kCurrentMethodStackOffset = 0;
42
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +000043static constexpr Register kCoreCalleeSaves[] = { RBX, RBP, R12, R13, R14, R15 };
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +000044static constexpr FloatRegister kFpuCalleeSaves[] = { XMM12, XMM13, XMM14, XMM15 };
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010045
Mark Mendell24f2dfa2015-01-14 19:51:45 -050046static constexpr int kC2ConditionMask = 0x400;
47
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010048
Nicolas Geoffraye5038322014-07-04 09:41:32 +010049#define __ reinterpret_cast<X86_64Assembler*>(codegen->GetAssembler())->
50
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +010051class NullCheckSlowPathX86_64 : public SlowPathCodeX86_64 {
Nicolas Geoffraye5038322014-07-04 09:41:32 +010052 public:
Nicolas Geoffray39468442014-09-02 15:17:15 +010053 explicit NullCheckSlowPathX86_64(HNullCheck* instruction) : instruction_(instruction) {}
Nicolas Geoffraye5038322014-07-04 09:41:32 +010054
Alexandre Rames2ed20af2015-03-06 13:55:35 +000055 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffraye5038322014-07-04 09:41:32 +010056 __ Bind(GetEntryLabel());
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010057 __ gs()->call(
58 Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pThrowNullPointer), true));
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +000059 RecordPcInfo(codegen, instruction_, instruction_->GetDexPc());
Nicolas Geoffraye5038322014-07-04 09:41:32 +010060 }
61
62 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +010063 HNullCheck* const instruction_;
Nicolas Geoffraye5038322014-07-04 09:41:32 +010064 DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathX86_64);
65};
66
Calin Juravled0d48522014-11-04 16:40:20 +000067class DivZeroCheckSlowPathX86_64 : public SlowPathCodeX86_64 {
68 public:
69 explicit DivZeroCheckSlowPathX86_64(HDivZeroCheck* instruction) : instruction_(instruction) {}
70
Alexandre Rames2ed20af2015-03-06 13:55:35 +000071 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Calin Juravled0d48522014-11-04 16:40:20 +000072 __ Bind(GetEntryLabel());
73 __ gs()->call(
74 Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pThrowDivZero), true));
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +000075 RecordPcInfo(codegen, instruction_, instruction_->GetDexPc());
Calin Juravled0d48522014-11-04 16:40:20 +000076 }
77
78 private:
79 HDivZeroCheck* const instruction_;
80 DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathX86_64);
81};
82
Calin Juravlebacfec32014-11-14 15:54:36 +000083class DivRemMinusOneSlowPathX86_64 : public SlowPathCodeX86_64 {
Calin Juravled0d48522014-11-04 16:40:20 +000084 public:
Calin Juravlebacfec32014-11-14 15:54:36 +000085 explicit DivRemMinusOneSlowPathX86_64(Register reg, Primitive::Type type, bool is_div)
86 : cpu_reg_(CpuRegister(reg)), type_(type), is_div_(is_div) {}
Calin Juravled0d48522014-11-04 16:40:20 +000087
Alexandre Rames2ed20af2015-03-06 13:55:35 +000088 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Calin Juravled0d48522014-11-04 16:40:20 +000089 __ Bind(GetEntryLabel());
Calin Juravled6fb6cf2014-11-11 19:07:44 +000090 if (type_ == Primitive::kPrimInt) {
Calin Juravlebacfec32014-11-14 15:54:36 +000091 if (is_div_) {
92 __ negl(cpu_reg_);
93 } else {
94 __ movl(cpu_reg_, Immediate(0));
95 }
96
Calin Juravled6fb6cf2014-11-11 19:07:44 +000097 } else {
98 DCHECK_EQ(Primitive::kPrimLong, type_);
Calin Juravlebacfec32014-11-14 15:54:36 +000099 if (is_div_) {
100 __ negq(cpu_reg_);
101 } else {
102 __ movq(cpu_reg_, Immediate(0));
103 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000104 }
Calin Juravled0d48522014-11-04 16:40:20 +0000105 __ jmp(GetExitLabel());
106 }
107
108 private:
Calin Juravlebacfec32014-11-14 15:54:36 +0000109 const CpuRegister cpu_reg_;
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000110 const Primitive::Type type_;
Calin Juravlebacfec32014-11-14 15:54:36 +0000111 const bool is_div_;
112 DISALLOW_COPY_AND_ASSIGN(DivRemMinusOneSlowPathX86_64);
Calin Juravled0d48522014-11-04 16:40:20 +0000113};
114
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100115class SuspendCheckSlowPathX86_64 : public SlowPathCodeX86_64 {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000116 public:
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100117 explicit SuspendCheckSlowPathX86_64(HSuspendCheck* instruction, HBasicBlock* successor)
118 : instruction_(instruction), successor_(successor) {}
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000119
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000120 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100121 CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000122 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000123 SaveLiveRegisters(codegen, instruction_->GetLocations());
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000124 __ gs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pTestSuspend), true));
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000125 RecordPcInfo(codegen, instruction_, instruction_->GetDexPc());
126 RestoreLiveRegisters(codegen, instruction_->GetLocations());
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100127 if (successor_ == nullptr) {
128 __ jmp(GetReturnLabel());
129 } else {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100130 __ jmp(x64_codegen->GetLabelOf(successor_));
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100131 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000132 }
133
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100134 Label* GetReturnLabel() {
135 DCHECK(successor_ == nullptr);
136 return &return_label_;
137 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000138
139 private:
140 HSuspendCheck* const instruction_;
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100141 HBasicBlock* const successor_;
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000142 Label return_label_;
143
144 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathX86_64);
145};
146
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100147class BoundsCheckSlowPathX86_64 : public SlowPathCodeX86_64 {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100148 public:
Roland Levillain5799fc02014-09-25 12:15:20 +0100149 BoundsCheckSlowPathX86_64(HBoundsCheck* instruction,
150 Location index_location,
151 Location length_location)
Nicolas Geoffray39468442014-09-02 15:17:15 +0100152 : instruction_(instruction),
153 index_location_(index_location),
154 length_location_(length_location) {}
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100155
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000156 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100157 __ Bind(GetEntryLabel());
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000158 // We're moving two locations to locations that could overlap, so we need a parallel
159 // move resolver.
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100160 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000161 codegen->EmitParallelMoves(
162 index_location_,
163 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
164 length_location_,
165 Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100166 __ gs()->call(Address::Absolute(
167 QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pThrowArrayBounds), true));
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000168 RecordPcInfo(codegen, instruction_, instruction_->GetDexPc());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100169 }
170
171 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100172 HBoundsCheck* const instruction_;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100173 const Location index_location_;
174 const Location length_location_;
175
176 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathX86_64);
177};
178
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000179class LoadClassSlowPathX86_64 : public SlowPathCodeX86_64 {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100180 public:
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000181 LoadClassSlowPathX86_64(HLoadClass* cls,
182 HInstruction* at,
183 uint32_t dex_pc,
184 bool do_clinit)
185 : cls_(cls), at_(at), dex_pc_(dex_pc), do_clinit_(do_clinit) {
186 DCHECK(at->IsLoadClass() || at->IsClinitCheck());
187 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100188
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000189 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000190 LocationSummary* locations = at_->GetLocations();
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100191 CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
192 __ Bind(GetEntryLabel());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100193
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000194 SaveLiveRegisters(codegen, locations);
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000195
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100196 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000197 __ movl(CpuRegister(calling_convention.GetRegisterAt(0)), Immediate(cls_->GetTypeIndex()));
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100198 x64_codegen->LoadCurrentMethod(CpuRegister(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000199 __ gs()->call(Address::Absolute((do_clinit_
200 ? QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pInitializeStaticStorage)
201 : QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pInitializeType)) , true));
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000202 RecordPcInfo(codegen, at_, dex_pc_);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100203
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000204 Location out = locations->Out();
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000205 // Move the class to the desired location.
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000206 if (out.IsValid()) {
207 DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
208 x64_codegen->Move(out, Location::RegisterLocation(RAX));
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000209 }
210
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000211 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100212 __ jmp(GetExitLabel());
213 }
214
215 private:
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000216 // The class this slow path will load.
217 HLoadClass* const cls_;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100218
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000219 // The instruction where this slow path is happening.
220 // (Might be the load class or an initialization check).
221 HInstruction* const at_;
222
223 // The dex PC of `at_`.
224 const uint32_t dex_pc_;
225
226 // Whether to initialize the class.
227 const bool do_clinit_;
228
229 DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathX86_64);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100230};
231
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000232class LoadStringSlowPathX86_64 : public SlowPathCodeX86_64 {
233 public:
234 explicit LoadStringSlowPathX86_64(HLoadString* instruction) : instruction_(instruction) {}
235
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000236 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000237 LocationSummary* locations = instruction_->GetLocations();
238 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
239
240 CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
241 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000242 SaveLiveRegisters(codegen, locations);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000243
244 InvokeRuntimeCallingConvention calling_convention;
Andreas Gampe1cc7dba2014-12-17 18:43:01 -0800245 x64_codegen->LoadCurrentMethod(CpuRegister(calling_convention.GetRegisterAt(1)));
246 __ movl(CpuRegister(calling_convention.GetRegisterAt(0)),
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000247 Immediate(instruction_->GetStringIndex()));
248 __ gs()->call(Address::Absolute(
249 QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pResolveString), true));
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000250 RecordPcInfo(codegen, instruction_, instruction_->GetDexPc());
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000251 x64_codegen->Move(locations->Out(), Location::RegisterLocation(RAX));
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000252 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000253 __ jmp(GetExitLabel());
254 }
255
256 private:
257 HLoadString* const instruction_;
258
259 DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathX86_64);
260};
261
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000262class TypeCheckSlowPathX86_64 : public SlowPathCodeX86_64 {
263 public:
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000264 TypeCheckSlowPathX86_64(HInstruction* instruction,
265 Location class_to_check,
266 Location object_class,
267 uint32_t dex_pc)
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000268 : instruction_(instruction),
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000269 class_to_check_(class_to_check),
270 object_class_(object_class),
271 dex_pc_(dex_pc) {}
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000272
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000273 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000274 LocationSummary* locations = instruction_->GetLocations();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000275 DCHECK(instruction_->IsCheckCast()
276 || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000277
278 CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
279 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000280 SaveLiveRegisters(codegen, locations);
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000281
282 // We're moving two locations to locations that could overlap, so we need a parallel
283 // move resolver.
284 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000285 codegen->EmitParallelMoves(
286 class_to_check_,
287 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
288 object_class_,
289 Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000290
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000291 if (instruction_->IsInstanceOf()) {
292 __ gs()->call(
293 Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pInstanceofNonTrivial), true));
294 } else {
295 DCHECK(instruction_->IsCheckCast());
296 __ gs()->call(
297 Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pCheckCast), true));
298 }
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000299 RecordPcInfo(codegen, instruction_, dex_pc_);
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000300
301 if (instruction_->IsInstanceOf()) {
302 x64_codegen->Move(locations->Out(), Location::RegisterLocation(RAX));
303 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000304
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000305 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000306 __ jmp(GetExitLabel());
307 }
308
309 private:
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000310 HInstruction* const instruction_;
311 const Location class_to_check_;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000312 const Location object_class_;
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000313 const uint32_t dex_pc_;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000314
315 DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathX86_64);
316};
317
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700318class DeoptimizationSlowPathX86_64 : public SlowPathCodeX86_64 {
319 public:
320 explicit DeoptimizationSlowPathX86_64(HInstruction* instruction)
321 : instruction_(instruction) {}
322
323 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
324 __ Bind(GetEntryLabel());
325 SaveLiveRegisters(codegen, instruction_->GetLocations());
326 __ gs()->call(
327 Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pDeoptimize), true));
328 DCHECK(instruction_->IsDeoptimize());
329 HDeoptimize* deoptimize = instruction_->AsDeoptimize();
330 uint32_t dex_pc = deoptimize->GetDexPc();
331 codegen->RecordPcInfo(instruction_, dex_pc, this);
332 }
333
334 private:
335 HInstruction* const instruction_;
336 DISALLOW_COPY_AND_ASSIGN(DeoptimizationSlowPathX86_64);
337};
338
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100339#undef __
340#define __ reinterpret_cast<X86_64Assembler*>(GetAssembler())->
341
Dave Allison20dfc792014-06-16 20:44:29 -0700342inline Condition X86_64Condition(IfCondition cond) {
343 switch (cond) {
344 case kCondEQ: return kEqual;
345 case kCondNE: return kNotEqual;
346 case kCondLT: return kLess;
347 case kCondLE: return kLessEqual;
348 case kCondGT: return kGreater;
349 case kCondGE: return kGreaterEqual;
350 default:
351 LOG(FATAL) << "Unknown if condition";
352 }
353 return kEqual;
354}
355
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800356void CodeGeneratorX86_64::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke,
357 CpuRegister temp) {
358 // All registers are assumed to be correctly set up.
359
360 // TODO: Implement all kinds of calls:
361 // 1) boot -> boot
362 // 2) app -> boot
363 // 3) app -> app
364 //
365 // Currently we implement the app -> app logic, which looks up in the resolve cache.
366
367 // temp = method;
368 LoadCurrentMethod(temp);
Nicolas Geoffray1cf95282014-12-12 19:22:03 +0000369 if (!invoke->IsRecursive()) {
370 // temp = temp->dex_cache_resolved_methods_;
371 __ movl(temp, Address(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().SizeValue()));
372 // temp = temp[index_in_cache]
373 __ movl(temp, Address(temp, CodeGenerator::GetCacheOffset(invoke->GetDexMethodIndex())));
374 // (temp + offset_of_quick_compiled_code)()
375 __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(
376 kX86_64WordSize).SizeValue()));
377 } else {
378 __ call(&frame_entry_label_);
379 }
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800380
381 DCHECK(!IsLeafMethod());
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800382}
383
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100384void CodeGeneratorX86_64::DumpCoreRegister(std::ostream& stream, int reg) const {
385 stream << X86_64ManagedRegister::FromCpuRegister(Register(reg));
386}
387
388void CodeGeneratorX86_64::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
389 stream << X86_64ManagedRegister::FromXmmRegister(FloatRegister(reg));
390}
391
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100392size_t CodeGeneratorX86_64::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
393 __ movq(Address(CpuRegister(RSP), stack_index), CpuRegister(reg_id));
394 return kX86_64WordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100395}
396
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100397size_t CodeGeneratorX86_64::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
398 __ movq(CpuRegister(reg_id), Address(CpuRegister(RSP), stack_index));
399 return kX86_64WordSize;
400}
401
402size_t CodeGeneratorX86_64::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
403 __ movsd(Address(CpuRegister(RSP), stack_index), XmmRegister(reg_id));
404 return kX86_64WordSize;
405}
406
407size_t CodeGeneratorX86_64::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
408 __ movsd(XmmRegister(reg_id), Address(CpuRegister(RSP), stack_index));
409 return kX86_64WordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100410}
411
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000412static constexpr int kNumberOfCpuRegisterPairs = 0;
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +0000413// Use a fake return address register to mimic Quick.
414static constexpr Register kFakeReturnRegister = Register(kLastCpuRegister + 1);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400415CodeGeneratorX86_64::CodeGeneratorX86_64(HGraph* graph,
416 const X86_64InstructionSetFeatures& isa_features,
417 const CompilerOptions& compiler_options)
Nicolas Geoffray98893962015-01-21 12:32:32 +0000418 : CodeGenerator(graph,
419 kNumberOfCpuRegisters,
420 kNumberOfFloatRegisters,
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000421 kNumberOfCpuRegisterPairs,
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000422 ComputeRegisterMask(reinterpret_cast<const int*>(kCoreCalleeSaves),
423 arraysize(kCoreCalleeSaves))
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +0000424 | (1 << kFakeReturnRegister),
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000425 ComputeRegisterMask(reinterpret_cast<const int*>(kFpuCalleeSaves),
426 arraysize(kFpuCalleeSaves)),
Nicolas Geoffray98893962015-01-21 12:32:32 +0000427 compiler_options),
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100428 block_labels_(graph->GetArena(), 0),
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100429 location_builder_(graph, this),
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000430 instruction_visitor_(graph, this),
Mark Mendellfb8d2792015-03-31 22:16:59 -0400431 move_resolver_(graph->GetArena(), this),
Mark Mendellf55c3e02015-03-26 21:07:46 -0400432 isa_features_(isa_features),
433 constant_area_start_(0) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000434 AddAllocatedRegister(Location::RegisterLocation(kFakeReturnRegister));
435}
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100436
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100437InstructionCodeGeneratorX86_64::InstructionCodeGeneratorX86_64(HGraph* graph,
438 CodeGeneratorX86_64* codegen)
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100439 : HGraphVisitor(graph),
440 assembler_(codegen->GetAssembler()),
441 codegen_(codegen) {}
442
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100443Location CodeGeneratorX86_64::AllocateFreeRegister(Primitive::Type type) const {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100444 switch (type) {
445 case Primitive::kPrimLong:
446 case Primitive::kPrimByte:
447 case Primitive::kPrimBoolean:
448 case Primitive::kPrimChar:
449 case Primitive::kPrimShort:
450 case Primitive::kPrimInt:
451 case Primitive::kPrimNot: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100452 size_t reg = FindFreeEntry(blocked_core_registers_, kNumberOfCpuRegisters);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100453 return Location::RegisterLocation(reg);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100454 }
455
456 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100457 case Primitive::kPrimDouble: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100458 size_t reg = FindFreeEntry(blocked_fpu_registers_, kNumberOfFloatRegisters);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100459 return Location::FpuRegisterLocation(reg);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100460 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100461
462 case Primitive::kPrimVoid:
463 LOG(FATAL) << "Unreachable type " << type;
464 }
465
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100466 return Location();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100467}
468
Nicolas Geoffray98893962015-01-21 12:32:32 +0000469void CodeGeneratorX86_64::SetupBlockedRegisters(bool is_baseline) const {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100470 // Stack register is always reserved.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100471 blocked_core_registers_[RSP] = true;
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100472
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000473 // Block the register used as TMP.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100474 blocked_core_registers_[TMP] = true;
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000475
Nicolas Geoffray98893962015-01-21 12:32:32 +0000476 if (is_baseline) {
477 for (size_t i = 0; i < arraysize(kCoreCalleeSaves); ++i) {
478 blocked_core_registers_[kCoreCalleeSaves[i]] = true;
479 }
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000480 for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
481 blocked_fpu_registers_[kFpuCalleeSaves[i]] = true;
482 }
Nicolas Geoffray98893962015-01-21 12:32:32 +0000483 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100484}
485
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100486static dwarf::Reg DWARFReg(Register reg) {
487 return dwarf::Reg::X86_64Core(static_cast<int>(reg));
488}
489static dwarf::Reg DWARFReg(FloatRegister reg) {
490 return dwarf::Reg::X86_64Fp(static_cast<int>(reg));
491}
492
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100493void CodeGeneratorX86_64::GenerateFrameEntry() {
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100494 __ cfi().SetCurrentCFAOffset(kX86_64WordSize); // return address
Nicolas Geoffray1cf95282014-12-12 19:22:03 +0000495 __ Bind(&frame_entry_label_);
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100496 bool skip_overflow_check = IsLeafMethod()
Dave Allison648d7112014-07-25 16:15:27 -0700497 && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kX86_64);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000498 DCHECK(GetCompilerOptions().GetImplicitStackOverflowChecks());
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100499
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000500 if (!skip_overflow_check) {
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100501 __ testq(CpuRegister(RAX), Address(
502 CpuRegister(RSP), -static_cast<int32_t>(GetStackOverflowReservedBytes(kX86_64))));
Nicolas Geoffray39468442014-09-02 15:17:15 +0100503 RecordPcInfo(nullptr, 0);
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100504 }
Nicolas Geoffraya26369a2015-01-22 08:46:05 +0000505
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000506 if (HasEmptyFrame()) {
507 return;
508 }
509
Nicolas Geoffray98893962015-01-21 12:32:32 +0000510 for (int i = arraysize(kCoreCalleeSaves) - 1; i >= 0; --i) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000511 Register reg = kCoreCalleeSaves[i];
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +0000512 if (allocated_registers_.ContainsCoreRegister(reg)) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000513 __ pushq(CpuRegister(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100514 __ cfi().AdjustCFAOffset(kX86_64WordSize);
515 __ cfi().RelOffset(DWARFReg(reg), 0);
Nicolas Geoffray98893962015-01-21 12:32:32 +0000516 }
517 }
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100518
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100519 int adjust = GetFrameSize() - GetCoreSpillSize();
520 __ subq(CpuRegister(RSP), Immediate(adjust));
521 __ cfi().AdjustCFAOffset(adjust);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000522 uint32_t xmm_spill_location = GetFpuSpillStart();
523 size_t xmm_spill_slot_size = GetFloatingPointSpillSlotSize();
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100524
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000525 for (int i = arraysize(kFpuCalleeSaves) - 1; i >= 0; --i) {
526 if (allocated_registers_.ContainsFloatingPointRegister(kFpuCalleeSaves[i])) {
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100527 int offset = xmm_spill_location + (xmm_spill_slot_size * i);
528 __ movsd(Address(CpuRegister(RSP), offset), XmmRegister(kFpuCalleeSaves[i]));
529 __ cfi().RelOffset(DWARFReg(kFpuCalleeSaves[i]), offset);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000530 }
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100531 }
532
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100533 __ movl(Address(CpuRegister(RSP), kCurrentMethodStackOffset), CpuRegister(RDI));
534}
535
536void CodeGeneratorX86_64::GenerateFrameExit() {
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000537 if (HasEmptyFrame()) {
538 return;
539 }
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000540 uint32_t xmm_spill_location = GetFpuSpillStart();
541 size_t xmm_spill_slot_size = GetFloatingPointSpillSlotSize();
542 for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
543 if (allocated_registers_.ContainsFloatingPointRegister(kFpuCalleeSaves[i])) {
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100544 int offset = xmm_spill_location + (xmm_spill_slot_size * i);
545 __ movsd(XmmRegister(kFpuCalleeSaves[i]), Address(CpuRegister(RSP), offset));
546 __ cfi().Restore(DWARFReg(kFpuCalleeSaves[i]));
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000547 }
548 }
549
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100550 int adjust = GetFrameSize() - GetCoreSpillSize();
551 __ addq(CpuRegister(RSP), Immediate(adjust));
552 __ cfi().AdjustCFAOffset(-adjust);
Nicolas Geoffray98893962015-01-21 12:32:32 +0000553
554 for (size_t i = 0; i < arraysize(kCoreCalleeSaves); ++i) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000555 Register reg = kCoreCalleeSaves[i];
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +0000556 if (allocated_registers_.ContainsCoreRegister(reg)) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000557 __ popq(CpuRegister(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100558 __ cfi().AdjustCFAOffset(-static_cast<int>(kX86_64WordSize));
559 __ cfi().Restore(DWARFReg(reg));
Nicolas Geoffray98893962015-01-21 12:32:32 +0000560 }
561 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100562}
563
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100564void CodeGeneratorX86_64::Bind(HBasicBlock* block) {
565 __ Bind(GetLabelOf(block));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100566}
567
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100568void CodeGeneratorX86_64::LoadCurrentMethod(CpuRegister reg) {
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000569 DCHECK(RequiresCurrentMethod());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100570 __ movl(reg, Address(CpuRegister(RSP), kCurrentMethodStackOffset));
571}
572
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100573Location CodeGeneratorX86_64::GetStackLocation(HLoadLocal* load) const {
574 switch (load->GetType()) {
575 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100576 case Primitive::kPrimDouble:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100577 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100578
579 case Primitive::kPrimInt:
580 case Primitive::kPrimNot:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100581 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100582 return Location::StackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100583
584 case Primitive::kPrimBoolean:
585 case Primitive::kPrimByte:
586 case Primitive::kPrimChar:
587 case Primitive::kPrimShort:
588 case Primitive::kPrimVoid:
589 LOG(FATAL) << "Unexpected type " << load->GetType();
Andreas Gampe65b798e2015-04-06 09:35:22 -0700590 UNREACHABLE();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100591 }
592
593 LOG(FATAL) << "Unreachable";
Andreas Gampe65b798e2015-04-06 09:35:22 -0700594 UNREACHABLE();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100595}
596
597void CodeGeneratorX86_64::Move(Location destination, Location source) {
598 if (source.Equals(destination)) {
599 return;
600 }
601 if (destination.IsRegister()) {
602 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000603 __ movq(destination.AsRegister<CpuRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100604 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000605 __ movd(destination.AsRegister<CpuRegister>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100606 } else if (source.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000607 __ movl(destination.AsRegister<CpuRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100608 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100609 } else {
610 DCHECK(source.IsDoubleStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +0000611 __ movq(destination.AsRegister<CpuRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100612 Address(CpuRegister(RSP), source.GetStackIndex()));
613 }
614 } else if (destination.IsFpuRegister()) {
615 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000616 __ movd(destination.AsFpuRegister<XmmRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100617 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000618 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100619 } else if (source.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000620 __ movss(destination.AsFpuRegister<XmmRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100621 Address(CpuRegister(RSP), source.GetStackIndex()));
622 } else {
623 DCHECK(source.IsDoubleStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +0000624 __ movsd(destination.AsFpuRegister<XmmRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100625 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100626 }
627 } else if (destination.IsStackSlot()) {
628 if (source.IsRegister()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100629 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +0000630 source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100631 } else if (source.IsFpuRegister()) {
632 __ movss(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +0000633 source.AsFpuRegister<XmmRegister>());
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500634 } else if (source.IsConstant()) {
635 HConstant* constant = source.GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000636 int32_t value = GetInt32ValueOf(constant);
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500637 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), Immediate(value));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100638 } else {
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500639 DCHECK(source.IsStackSlot()) << source;
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000640 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
641 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100642 }
643 } else {
644 DCHECK(destination.IsDoubleStackSlot());
645 if (source.IsRegister()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100646 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +0000647 source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100648 } else if (source.IsFpuRegister()) {
649 __ movsd(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +0000650 source.AsFpuRegister<XmmRegister>());
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500651 } else if (source.IsConstant()) {
652 HConstant* constant = source.GetConstant();
Zheng Xu12bca972015-03-30 19:35:50 +0800653 int64_t value;
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500654 if (constant->IsDoubleConstant()) {
Roland Levillainda4d79b2015-03-24 14:36:11 +0000655 value = bit_cast<int64_t, double>(constant->AsDoubleConstant()->GetValue());
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500656 } else {
657 DCHECK(constant->IsLongConstant());
658 value = constant->AsLongConstant()->GetValue();
659 }
660 __ movq(CpuRegister(TMP), Immediate(value));
661 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100662 } else {
663 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000664 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
665 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100666 }
667 }
668}
669
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100670void CodeGeneratorX86_64::Move(HInstruction* instruction,
671 Location location,
672 HInstruction* move_for) {
Calin Juravlea21f5982014-11-13 15:53:04 +0000673 LocationSummary* locations = instruction->GetLocations();
674 if (locations != nullptr && locations->Out().Equals(location)) {
675 return;
676 }
677
678 if (locations != nullptr && locations->Out().IsConstant()) {
679 HConstant* const_to_move = locations->Out().GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000680 if (const_to_move->IsIntConstant() || const_to_move->IsNullConstant()) {
681 Immediate imm(GetInt32ValueOf(const_to_move));
Calin Juravlea21f5982014-11-13 15:53:04 +0000682 if (location.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000683 __ movl(location.AsRegister<CpuRegister>(), imm);
Calin Juravlea21f5982014-11-13 15:53:04 +0000684 } else if (location.IsStackSlot()) {
685 __ movl(Address(CpuRegister(RSP), location.GetStackIndex()), imm);
686 } else {
687 DCHECK(location.IsConstant());
688 DCHECK_EQ(location.GetConstant(), const_to_move);
689 }
690 } else if (const_to_move->IsLongConstant()) {
691 int64_t value = const_to_move->AsLongConstant()->GetValue();
692 if (location.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000693 __ movq(location.AsRegister<CpuRegister>(), Immediate(value));
Calin Juravlea21f5982014-11-13 15:53:04 +0000694 } else if (location.IsDoubleStackSlot()) {
695 __ movq(CpuRegister(TMP), Immediate(value));
696 __ movq(Address(CpuRegister(RSP), location.GetStackIndex()), CpuRegister(TMP));
697 } else {
698 DCHECK(location.IsConstant());
699 DCHECK_EQ(location.GetConstant(), const_to_move);
700 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100701 }
Roland Levillain476df552014-10-09 17:51:36 +0100702 } else if (instruction->IsLoadLocal()) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100703 switch (instruction->GetType()) {
704 case Primitive::kPrimBoolean:
705 case Primitive::kPrimByte:
706 case Primitive::kPrimChar:
707 case Primitive::kPrimShort:
708 case Primitive::kPrimInt:
709 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100710 case Primitive::kPrimFloat:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100711 Move(location, Location::StackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
712 break;
713
714 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100715 case Primitive::kPrimDouble:
Roland Levillain199f3362014-11-27 17:15:16 +0000716 Move(location,
717 Location::DoubleStackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100718 break;
719
720 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100721 LOG(FATAL) << "Unexpected local type " << instruction->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100722 }
Nicolas Geoffrayf43083d2014-11-07 10:48:10 +0000723 } else if (instruction->IsTemporary()) {
724 Location temp_location = GetTemporaryLocation(instruction->AsTemporary());
725 Move(location, temp_location);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100726 } else {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100727 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100728 switch (instruction->GetType()) {
729 case Primitive::kPrimBoolean:
730 case Primitive::kPrimByte:
731 case Primitive::kPrimChar:
732 case Primitive::kPrimShort:
733 case Primitive::kPrimInt:
734 case Primitive::kPrimNot:
735 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100736 case Primitive::kPrimFloat:
737 case Primitive::kPrimDouble:
Calin Juravlea21f5982014-11-13 15:53:04 +0000738 Move(location, locations->Out());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100739 break;
740
741 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100742 LOG(FATAL) << "Unexpected type " << instruction->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100743 }
744 }
745}
746
747void LocationsBuilderX86_64::VisitGoto(HGoto* got) {
748 got->SetLocations(nullptr);
749}
750
751void InstructionCodeGeneratorX86_64::VisitGoto(HGoto* got) {
752 HBasicBlock* successor = got->GetSuccessor();
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100753 DCHECK(!successor->IsExitBlock());
754
755 HBasicBlock* block = got->GetBlock();
756 HInstruction* previous = got->GetPrevious();
757
758 HLoopInformation* info = block->GetLoopInformation();
David Brazdil46e2a392015-03-16 17:31:52 +0000759 if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100760 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck());
761 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
762 return;
763 }
764
765 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
766 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
767 }
768 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100769 __ jmp(codegen_->GetLabelOf(successor));
770 }
771}
772
773void LocationsBuilderX86_64::VisitExit(HExit* exit) {
774 exit->SetLocations(nullptr);
775}
776
777void InstructionCodeGeneratorX86_64::VisitExit(HExit* exit) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700778 UNUSED(exit);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100779}
780
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700781void InstructionCodeGeneratorX86_64::GenerateTestAndBranch(HInstruction* instruction,
782 Label* true_target,
783 Label* false_target,
784 Label* always_true_target) {
785 HInstruction* cond = instruction->InputAt(0);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100786 if (cond->IsIntConstant()) {
787 // Constant condition, statically compared against 1.
788 int32_t cond_value = cond->AsIntConstant()->GetValue();
789 if (cond_value == 1) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700790 if (always_true_target != nullptr) {
791 __ jmp(always_true_target);
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100792 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100793 return;
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100794 } else {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100795 DCHECK_EQ(cond_value, 0);
796 }
797 } else {
798 bool materialized =
799 !cond->IsCondition() || cond->AsCondition()->NeedsMaterialization();
800 // Moves do not affect the eflags register, so if the condition is
801 // evaluated just before the if, we don't need to evaluate it
802 // again.
803 bool eflags_set = cond->IsCondition()
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700804 && cond->AsCondition()->IsBeforeWhenDisregardMoves(instruction);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100805 if (materialized) {
806 if (!eflags_set) {
807 // Materialized condition, compare against 0.
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700808 Location lhs = instruction->GetLocations()->InAt(0);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100809 if (lhs.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +0000810 __ testl(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>());
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100811 } else {
812 __ cmpl(Address(CpuRegister(RSP), lhs.GetStackIndex()),
813 Immediate(0));
814 }
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700815 __ j(kNotEqual, true_target);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100816 } else {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700817 __ j(X86_64Condition(cond->AsCondition()->GetCondition()), true_target);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100818 }
819 } else {
820 Location lhs = cond->GetLocations()->InAt(0);
821 Location rhs = cond->GetLocations()->InAt(1);
822 if (rhs.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000823 __ cmpl(lhs.AsRegister<CpuRegister>(), rhs.AsRegister<CpuRegister>());
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100824 } else if (rhs.IsConstant()) {
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000825 int32_t constant = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
Nicolas Geoffray748f1402015-01-27 08:17:54 +0000826 if (constant == 0) {
827 __ testl(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>());
828 } else {
829 __ cmpl(lhs.AsRegister<CpuRegister>(), Immediate(constant));
830 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100831 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000832 __ cmpl(lhs.AsRegister<CpuRegister>(),
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100833 Address(CpuRegister(RSP), rhs.GetStackIndex()));
834 }
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700835 __ j(X86_64Condition(cond->AsCondition()->GetCondition()), true_target);
Dave Allison20dfc792014-06-16 20:44:29 -0700836 }
Dave Allison20dfc792014-06-16 20:44:29 -0700837 }
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700838 if (false_target != nullptr) {
839 __ jmp(false_target);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100840 }
841}
842
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700843void LocationsBuilderX86_64::VisitIf(HIf* if_instr) {
844 LocationSummary* locations =
845 new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall);
846 HInstruction* cond = if_instr->InputAt(0);
847 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
848 locations->SetInAt(0, Location::Any());
849 }
850}
851
852void InstructionCodeGeneratorX86_64::VisitIf(HIf* if_instr) {
853 Label* true_target = codegen_->GetLabelOf(if_instr->IfTrueSuccessor());
854 Label* false_target = codegen_->GetLabelOf(if_instr->IfFalseSuccessor());
855 Label* always_true_target = true_target;
856 if (codegen_->GoesToNextBlock(if_instr->GetBlock(),
857 if_instr->IfTrueSuccessor())) {
858 always_true_target = nullptr;
859 }
860 if (codegen_->GoesToNextBlock(if_instr->GetBlock(),
861 if_instr->IfFalseSuccessor())) {
862 false_target = nullptr;
863 }
864 GenerateTestAndBranch(if_instr, true_target, false_target, always_true_target);
865}
866
867void LocationsBuilderX86_64::VisitDeoptimize(HDeoptimize* deoptimize) {
868 LocationSummary* locations = new (GetGraph()->GetArena())
869 LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
870 HInstruction* cond = deoptimize->InputAt(0);
871 DCHECK(cond->IsCondition());
872 if (cond->AsCondition()->NeedsMaterialization()) {
873 locations->SetInAt(0, Location::Any());
874 }
875}
876
877void InstructionCodeGeneratorX86_64::VisitDeoptimize(HDeoptimize* deoptimize) {
878 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena())
879 DeoptimizationSlowPathX86_64(deoptimize);
880 codegen_->AddSlowPath(slow_path);
881 Label* slow_path_entry = slow_path->GetEntryLabel();
882 GenerateTestAndBranch(deoptimize, slow_path_entry, nullptr, slow_path_entry);
883}
884
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100885void LocationsBuilderX86_64::VisitLocal(HLocal* local) {
886 local->SetLocations(nullptr);
887}
888
889void InstructionCodeGeneratorX86_64::VisitLocal(HLocal* local) {
890 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
891}
892
893void LocationsBuilderX86_64::VisitLoadLocal(HLoadLocal* local) {
894 local->SetLocations(nullptr);
895}
896
897void InstructionCodeGeneratorX86_64::VisitLoadLocal(HLoadLocal* load) {
898 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700899 UNUSED(load);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100900}
901
902void LocationsBuilderX86_64::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100903 LocationSummary* locations =
904 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100905 switch (store->InputAt(1)->GetType()) {
906 case Primitive::kPrimBoolean:
907 case Primitive::kPrimByte:
908 case Primitive::kPrimChar:
909 case Primitive::kPrimShort:
910 case Primitive::kPrimInt:
911 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100912 case Primitive::kPrimFloat:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100913 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
914 break;
915
916 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100917 case Primitive::kPrimDouble:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100918 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
919 break;
920
921 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100922 LOG(FATAL) << "Unexpected local type " << store->InputAt(1)->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100923 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100924}
925
926void InstructionCodeGeneratorX86_64::VisitStoreLocal(HStoreLocal* store) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700927 UNUSED(store);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100928}
929
Dave Allison20dfc792014-06-16 20:44:29 -0700930void LocationsBuilderX86_64::VisitCondition(HCondition* comp) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100931 LocationSummary* locations =
932 new (GetGraph()->GetArena()) LocationSummary(comp, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +0100933 locations->SetInAt(0, Location::RequiresRegister());
934 locations->SetInAt(1, Location::Any());
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100935 if (comp->NeedsMaterialization()) {
936 locations->SetOut(Location::RequiresRegister());
937 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100938}
939
Dave Allison20dfc792014-06-16 20:44:29 -0700940void InstructionCodeGeneratorX86_64::VisitCondition(HCondition* comp) {
941 if (comp->NeedsMaterialization()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100942 LocationSummary* locations = comp->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +0000943 CpuRegister reg = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100944 // Clear register: setcc only sets the low byte.
945 __ xorq(reg, reg);
Nicolas Geoffray748f1402015-01-27 08:17:54 +0000946 Location lhs = locations->InAt(0);
947 Location rhs = locations->InAt(1);
948 if (rhs.IsRegister()) {
949 __ cmpl(lhs.AsRegister<CpuRegister>(), rhs.AsRegister<CpuRegister>());
950 } else if (rhs.IsConstant()) {
Mingyao Yangdc5ac732015-02-25 11:28:05 -0800951 int32_t constant = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
Nicolas Geoffray748f1402015-01-27 08:17:54 +0000952 if (constant == 0) {
953 __ testl(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>());
954 } else {
955 __ cmpl(lhs.AsRegister<CpuRegister>(), Immediate(constant));
956 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100957 } else {
Nicolas Geoffray748f1402015-01-27 08:17:54 +0000958 __ cmpl(lhs.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), rhs.GetStackIndex()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100959 }
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100960 __ setcc(X86_64Condition(comp->GetCondition()), reg);
Dave Allison20dfc792014-06-16 20:44:29 -0700961 }
962}
963
964void LocationsBuilderX86_64::VisitEqual(HEqual* comp) {
965 VisitCondition(comp);
966}
967
968void InstructionCodeGeneratorX86_64::VisitEqual(HEqual* comp) {
969 VisitCondition(comp);
970}
971
972void LocationsBuilderX86_64::VisitNotEqual(HNotEqual* comp) {
973 VisitCondition(comp);
974}
975
976void InstructionCodeGeneratorX86_64::VisitNotEqual(HNotEqual* comp) {
977 VisitCondition(comp);
978}
979
980void LocationsBuilderX86_64::VisitLessThan(HLessThan* comp) {
981 VisitCondition(comp);
982}
983
984void InstructionCodeGeneratorX86_64::VisitLessThan(HLessThan* comp) {
985 VisitCondition(comp);
986}
987
988void LocationsBuilderX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
989 VisitCondition(comp);
990}
991
992void InstructionCodeGeneratorX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
993 VisitCondition(comp);
994}
995
996void LocationsBuilderX86_64::VisitGreaterThan(HGreaterThan* comp) {
997 VisitCondition(comp);
998}
999
1000void InstructionCodeGeneratorX86_64::VisitGreaterThan(HGreaterThan* comp) {
1001 VisitCondition(comp);
1002}
1003
1004void LocationsBuilderX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1005 VisitCondition(comp);
1006}
1007
1008void InstructionCodeGeneratorX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1009 VisitCondition(comp);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001010}
1011
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001012void LocationsBuilderX86_64::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001013 LocationSummary* locations =
1014 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Calin Juravleddb7df22014-11-25 20:56:51 +00001015 switch (compare->InputAt(0)->GetType()) {
1016 case Primitive::kPrimLong: {
1017 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell3f6c7f62015-03-13 13:47:53 -04001018 locations->SetInAt(1, Location::RegisterOrInt32LongConstant(compare->InputAt(1)));
Calin Juravleddb7df22014-11-25 20:56:51 +00001019 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1020 break;
1021 }
1022 case Primitive::kPrimFloat:
1023 case Primitive::kPrimDouble: {
1024 locations->SetInAt(0, Location::RequiresFpuRegister());
1025 locations->SetInAt(1, Location::RequiresFpuRegister());
1026 locations->SetOut(Location::RequiresRegister());
1027 break;
1028 }
1029 default:
1030 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
1031 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001032}
1033
1034void InstructionCodeGeneratorX86_64::VisitCompare(HCompare* compare) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001035 LocationSummary* locations = compare->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00001036 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Calin Juravleddb7df22014-11-25 20:56:51 +00001037 Location left = locations->InAt(0);
1038 Location right = locations->InAt(1);
1039
1040 Label less, greater, done;
1041 Primitive::Type type = compare->InputAt(0)->GetType();
1042 switch (type) {
1043 case Primitive::kPrimLong: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04001044 CpuRegister left_reg = left.AsRegister<CpuRegister>();
1045 if (right.IsConstant()) {
1046 int64_t value = right.GetConstant()->AsLongConstant()->GetValue();
1047 DCHECK(IsInt<32>(value));
1048 if (value == 0) {
1049 __ testq(left_reg, left_reg);
1050 } else {
1051 __ cmpq(left_reg, Immediate(static_cast<int32_t>(value)));
1052 }
1053 } else {
1054 __ cmpq(left_reg, right.AsRegister<CpuRegister>());
1055 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001056 break;
Calin Juravleddb7df22014-11-25 20:56:51 +00001057 }
1058 case Primitive::kPrimFloat: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001059 __ ucomiss(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
Calin Juravleddb7df22014-11-25 20:56:51 +00001060 __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
1061 break;
1062 }
1063 case Primitive::kPrimDouble: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001064 __ ucomisd(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
Calin Juravleddb7df22014-11-25 20:56:51 +00001065 __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
1066 break;
1067 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001068 default:
Calin Juravleddb7df22014-11-25 20:56:51 +00001069 LOG(FATAL) << "Unexpected compare type " << type;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001070 }
Calin Juravleddb7df22014-11-25 20:56:51 +00001071 __ movl(out, Immediate(0));
Calin Juravle91debbc2014-11-26 19:01:09 +00001072 __ j(kEqual, &done);
Calin Juravleddb7df22014-11-25 20:56:51 +00001073 __ j(type == Primitive::kPrimLong ? kLess : kBelow, &less); // ucomis{s,d} sets CF (kBelow)
Calin Juravlefd861242014-11-25 20:56:51 +00001074
Calin Juravle91debbc2014-11-26 19:01:09 +00001075 __ Bind(&greater);
Calin Juravleddb7df22014-11-25 20:56:51 +00001076 __ movl(out, Immediate(1));
1077 __ jmp(&done);
1078
1079 __ Bind(&less);
1080 __ movl(out, Immediate(-1));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001081
1082 __ Bind(&done);
1083}
1084
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001085void LocationsBuilderX86_64::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001086 LocationSummary* locations =
1087 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001088 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001089}
1090
1091void InstructionCodeGeneratorX86_64::VisitIntConstant(HIntConstant* constant) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001092 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001093 UNUSED(constant);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001094}
1095
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001096void LocationsBuilderX86_64::VisitNullConstant(HNullConstant* constant) {
1097 LocationSummary* locations =
1098 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1099 locations->SetOut(Location::ConstantLocation(constant));
1100}
1101
1102void InstructionCodeGeneratorX86_64::VisitNullConstant(HNullConstant* constant) {
1103 // Will be generated at use site.
1104 UNUSED(constant);
1105}
1106
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001107void LocationsBuilderX86_64::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001108 LocationSummary* locations =
1109 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001110 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001111}
1112
1113void InstructionCodeGeneratorX86_64::VisitLongConstant(HLongConstant* constant) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001114 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001115 UNUSED(constant);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001116}
1117
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001118void LocationsBuilderX86_64::VisitFloatConstant(HFloatConstant* constant) {
1119 LocationSummary* locations =
1120 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1121 locations->SetOut(Location::ConstantLocation(constant));
1122}
1123
1124void InstructionCodeGeneratorX86_64::VisitFloatConstant(HFloatConstant* constant) {
1125 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001126 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001127}
1128
1129void LocationsBuilderX86_64::VisitDoubleConstant(HDoubleConstant* constant) {
1130 LocationSummary* locations =
1131 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1132 locations->SetOut(Location::ConstantLocation(constant));
1133}
1134
1135void InstructionCodeGeneratorX86_64::VisitDoubleConstant(HDoubleConstant* constant) {
1136 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001137 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001138}
1139
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001140void LocationsBuilderX86_64::VisitReturnVoid(HReturnVoid* ret) {
1141 ret->SetLocations(nullptr);
1142}
1143
1144void InstructionCodeGeneratorX86_64::VisitReturnVoid(HReturnVoid* ret) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001145 UNUSED(ret);
David Srbeckyc6b4dd82015-04-07 20:32:43 +01001146 __ cfi().RememberState();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001147 codegen_->GenerateFrameExit();
1148 __ ret();
David Srbeckyc6b4dd82015-04-07 20:32:43 +01001149 __ cfi().RestoreState();
1150 __ cfi().DefCFAOffset(codegen_->GetFrameSize());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001151}
1152
1153void LocationsBuilderX86_64::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001154 LocationSummary* locations =
1155 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001156 switch (ret->InputAt(0)->GetType()) {
1157 case Primitive::kPrimBoolean:
1158 case Primitive::kPrimByte:
1159 case Primitive::kPrimChar:
1160 case Primitive::kPrimShort:
1161 case Primitive::kPrimInt:
1162 case Primitive::kPrimNot:
1163 case Primitive::kPrimLong:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001164 locations->SetInAt(0, Location::RegisterLocation(RAX));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001165 break;
1166
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001167 case Primitive::kPrimFloat:
1168 case Primitive::kPrimDouble:
1169 locations->SetInAt(0,
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001170 Location::FpuRegisterLocation(XMM0));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001171 break;
1172
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001173 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001174 LOG(FATAL) << "Unexpected return type " << ret->InputAt(0)->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001175 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001176}
1177
1178void InstructionCodeGeneratorX86_64::VisitReturn(HReturn* ret) {
1179 if (kIsDebugBuild) {
1180 switch (ret->InputAt(0)->GetType()) {
1181 case Primitive::kPrimBoolean:
1182 case Primitive::kPrimByte:
1183 case Primitive::kPrimChar:
1184 case Primitive::kPrimShort:
1185 case Primitive::kPrimInt:
1186 case Primitive::kPrimNot:
1187 case Primitive::kPrimLong:
Roland Levillain271ab9c2014-11-27 15:23:57 +00001188 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegister<CpuRegister>().AsRegister(), RAX);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001189 break;
1190
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001191 case Primitive::kPrimFloat:
1192 case Primitive::kPrimDouble:
Roland Levillain271ab9c2014-11-27 15:23:57 +00001193 DCHECK_EQ(ret->GetLocations()->InAt(0).AsFpuRegister<XmmRegister>().AsFloatRegister(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001194 XMM0);
1195 break;
1196
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001197 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001198 LOG(FATAL) << "Unexpected return type " << ret->InputAt(0)->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001199 }
1200 }
David Srbeckyc6b4dd82015-04-07 20:32:43 +01001201 __ cfi().RememberState();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001202 codegen_->GenerateFrameExit();
1203 __ ret();
David Srbeckyc6b4dd82015-04-07 20:32:43 +01001204 __ cfi().RestoreState();
1205 __ cfi().DefCFAOffset(codegen_->GetFrameSize());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001206}
1207
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001208Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) {
1209 switch (type) {
1210 case Primitive::kPrimBoolean:
1211 case Primitive::kPrimByte:
1212 case Primitive::kPrimChar:
1213 case Primitive::kPrimShort:
1214 case Primitive::kPrimInt:
1215 case Primitive::kPrimNot: {
1216 uint32_t index = gp_index_++;
1217 stack_index_++;
1218 if (index < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001219 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001220 } else {
1221 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
1222 }
1223 }
1224
1225 case Primitive::kPrimLong: {
1226 uint32_t index = gp_index_;
1227 stack_index_ += 2;
1228 if (index < calling_convention.GetNumberOfRegisters()) {
1229 gp_index_ += 1;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001230 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001231 } else {
1232 gp_index_ += 2;
1233 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
1234 }
1235 }
1236
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001237 case Primitive::kPrimFloat: {
1238 uint32_t index = fp_index_++;
1239 stack_index_++;
1240 if (index < calling_convention.GetNumberOfFpuRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001241 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001242 } else {
1243 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
1244 }
1245 }
1246
1247 case Primitive::kPrimDouble: {
1248 uint32_t index = fp_index_++;
1249 stack_index_ += 2;
1250 if (index < calling_convention.GetNumberOfFpuRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001251 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001252 } else {
1253 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
1254 }
1255 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001256
1257 case Primitive::kPrimVoid:
1258 LOG(FATAL) << "Unexpected parameter type " << type;
1259 break;
1260 }
1261 return Location();
1262}
1263
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001264void LocationsBuilderX86_64::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Mark Mendellfb8d2792015-03-31 22:16:59 -04001265 IntrinsicLocationsBuilderX86_64 intrinsic(codegen_);
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001266 if (intrinsic.TryDispatch(invoke)) {
1267 return;
1268 }
1269
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001270 HandleInvoke(invoke);
1271}
1272
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001273static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorX86_64* codegen) {
1274 if (invoke->GetLocations()->Intrinsified()) {
1275 IntrinsicCodeGeneratorX86_64 intrinsic(codegen);
1276 intrinsic.Dispatch(invoke);
1277 return true;
1278 }
1279 return false;
1280}
1281
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001282void InstructionCodeGeneratorX86_64::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001283 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1284 return;
1285 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001286
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001287 codegen_->GenerateStaticOrDirectCall(
1288 invoke,
1289 invoke->GetLocations()->GetTemp(0).AsRegister<CpuRegister>());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +00001290 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001291}
1292
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001293void LocationsBuilderX86_64::HandleInvoke(HInvoke* invoke) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001294 LocationSummary* locations =
1295 new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001296 locations->AddTemp(Location::RegisterLocation(RDI));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001297
1298 InvokeDexCallingConventionVisitor calling_convention_visitor;
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001299 for (size_t i = 0; i < invoke->InputCount(); i++) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001300 HInstruction* input = invoke->InputAt(i);
1301 locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
1302 }
1303
1304 switch (invoke->GetType()) {
1305 case Primitive::kPrimBoolean:
1306 case Primitive::kPrimByte:
1307 case Primitive::kPrimChar:
1308 case Primitive::kPrimShort:
1309 case Primitive::kPrimInt:
1310 case Primitive::kPrimNot:
1311 case Primitive::kPrimLong:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001312 locations->SetOut(Location::RegisterLocation(RAX));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001313 break;
1314
1315 case Primitive::kPrimVoid:
1316 break;
1317
1318 case Primitive::kPrimDouble:
1319 case Primitive::kPrimFloat:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001320 locations->SetOut(Location::FpuRegisterLocation(XMM0));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001321 break;
1322 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001323}
1324
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001325void LocationsBuilderX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Mark Mendellfb8d2792015-03-31 22:16:59 -04001326 IntrinsicLocationsBuilderX86_64 intrinsic(codegen_);
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001327 if (intrinsic.TryDispatch(invoke)) {
1328 return;
1329 }
1330
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001331 HandleInvoke(invoke);
1332}
1333
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001334void InstructionCodeGeneratorX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001335 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1336 return;
1337 }
1338
Roland Levillain271ab9c2014-11-27 15:23:57 +00001339 CpuRegister temp = invoke->GetLocations()->GetTemp(0).AsRegister<CpuRegister>();
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001340 size_t method_offset = mirror::Class::EmbeddedVTableOffset().SizeValue() +
1341 invoke->GetVTableIndex() * sizeof(mirror::Class::VTableEntry);
1342 LocationSummary* locations = invoke->GetLocations();
1343 Location receiver = locations->InAt(0);
1344 size_t class_offset = mirror::Object::ClassOffset().SizeValue();
1345 // temp = object->GetClass();
1346 if (receiver.IsStackSlot()) {
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001347 __ movl(temp, Address(CpuRegister(RSP), receiver.GetStackIndex()));
1348 __ movl(temp, Address(temp, class_offset));
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001349 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001350 __ movl(temp, Address(receiver.AsRegister<CpuRegister>(), class_offset));
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001351 }
Calin Juravle77520bc2015-01-12 18:45:46 +00001352 codegen_->MaybeRecordImplicitNullCheck(invoke);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001353 // temp = temp->GetMethodAt(method_offset);
1354 __ movl(temp, Address(temp, method_offset));
1355 // call temp->GetEntryPoint();
Mathieu Chartier2d721012014-11-10 11:08:06 -08001356 __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001357 kX86_64WordSize).SizeValue()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001358
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001359 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray39468442014-09-02 15:17:15 +01001360 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001361}
1362
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001363void LocationsBuilderX86_64::VisitInvokeInterface(HInvokeInterface* invoke) {
1364 HandleInvoke(invoke);
1365 // Add the hidden argument.
1366 invoke->GetLocations()->AddTemp(Location::RegisterLocation(RAX));
1367}
1368
1369void InstructionCodeGeneratorX86_64::VisitInvokeInterface(HInvokeInterface* invoke) {
1370 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001371 CpuRegister temp = invoke->GetLocations()->GetTemp(0).AsRegister<CpuRegister>();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001372 uint32_t method_offset = mirror::Class::EmbeddedImTableOffset().Uint32Value() +
1373 (invoke->GetImtIndex() % mirror::Class::kImtSize) * sizeof(mirror::Class::ImTableEntry);
1374 LocationSummary* locations = invoke->GetLocations();
1375 Location receiver = locations->InAt(0);
1376 size_t class_offset = mirror::Object::ClassOffset().SizeValue();
1377
1378 // Set the hidden argument.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001379 __ movq(invoke->GetLocations()->GetTemp(1).AsRegister<CpuRegister>(),
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001380 Immediate(invoke->GetDexMethodIndex()));
1381
1382 // temp = object->GetClass();
1383 if (receiver.IsStackSlot()) {
1384 __ movl(temp, Address(CpuRegister(RSP), receiver.GetStackIndex()));
1385 __ movl(temp, Address(temp, class_offset));
1386 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001387 __ movl(temp, Address(receiver.AsRegister<CpuRegister>(), class_offset));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001388 }
Calin Juravle77520bc2015-01-12 18:45:46 +00001389 codegen_->MaybeRecordImplicitNullCheck(invoke);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001390 // temp = temp->GetImtEntryAt(method_offset);
1391 __ movl(temp, Address(temp, method_offset));
1392 // call temp->GetEntryPoint();
Mathieu Chartier2d721012014-11-10 11:08:06 -08001393 __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001394 kX86_64WordSize).SizeValue()));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001395
1396 DCHECK(!codegen_->IsLeafMethod());
1397 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1398}
1399
Roland Levillain88cb1752014-10-20 16:36:47 +01001400void LocationsBuilderX86_64::VisitNeg(HNeg* neg) {
1401 LocationSummary* locations =
1402 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
1403 switch (neg->GetResultType()) {
1404 case Primitive::kPrimInt:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001405 case Primitive::kPrimLong:
Roland Levillain88cb1752014-10-20 16:36:47 +01001406 locations->SetInAt(0, Location::RequiresRegister());
1407 locations->SetOut(Location::SameAsFirstInput());
1408 break;
1409
Roland Levillain88cb1752014-10-20 16:36:47 +01001410 case Primitive::kPrimFloat:
1411 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001412 locations->SetInAt(0, Location::RequiresFpuRegister());
Roland Levillain5368c212014-11-27 15:03:41 +00001413 locations->SetOut(Location::SameAsFirstInput());
1414 locations->AddTemp(Location::RequiresRegister());
1415 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain88cb1752014-10-20 16:36:47 +01001416 break;
1417
1418 default:
1419 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1420 }
1421}
1422
1423void InstructionCodeGeneratorX86_64::VisitNeg(HNeg* neg) {
1424 LocationSummary* locations = neg->GetLocations();
1425 Location out = locations->Out();
1426 Location in = locations->InAt(0);
1427 switch (neg->GetResultType()) {
1428 case Primitive::kPrimInt:
1429 DCHECK(in.IsRegister());
Roland Levillain3dbcb382014-10-28 17:30:07 +00001430 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001431 __ negl(out.AsRegister<CpuRegister>());
Roland Levillain88cb1752014-10-20 16:36:47 +01001432 break;
1433
1434 case Primitive::kPrimLong:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001435 DCHECK(in.IsRegister());
Roland Levillain3dbcb382014-10-28 17:30:07 +00001436 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001437 __ negq(out.AsRegister<CpuRegister>());
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001438 break;
1439
Roland Levillain5368c212014-11-27 15:03:41 +00001440 case Primitive::kPrimFloat: {
1441 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001442 CpuRegister constant = locations->GetTemp(0).AsRegister<CpuRegister>();
1443 XmmRegister mask = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
Roland Levillain5368c212014-11-27 15:03:41 +00001444 // Implement float negation with an exclusive or with value
1445 // 0x80000000 (mask for bit 31, representing the sign of a
1446 // single-precision floating-point number).
1447 __ movq(constant, Immediate(INT64_C(0x80000000)));
1448 __ movd(mask, constant);
Roland Levillain271ab9c2014-11-27 15:23:57 +00001449 __ xorps(out.AsFpuRegister<XmmRegister>(), mask);
Roland Levillain3dbcb382014-10-28 17:30:07 +00001450 break;
Roland Levillain5368c212014-11-27 15:03:41 +00001451 }
Roland Levillain3dbcb382014-10-28 17:30:07 +00001452
Roland Levillain5368c212014-11-27 15:03:41 +00001453 case Primitive::kPrimDouble: {
1454 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001455 CpuRegister constant = locations->GetTemp(0).AsRegister<CpuRegister>();
1456 XmmRegister mask = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
Roland Levillain5368c212014-11-27 15:03:41 +00001457 // Implement double negation with an exclusive or with value
Roland Levillain3dbcb382014-10-28 17:30:07 +00001458 // 0x8000000000000000 (mask for bit 63, representing the sign of
Roland Levillain5368c212014-11-27 15:03:41 +00001459 // a double-precision floating-point number).
1460 __ movq(constant, Immediate(INT64_C(0x8000000000000000)));
1461 __ movd(mask, constant);
Roland Levillain271ab9c2014-11-27 15:23:57 +00001462 __ xorpd(out.AsFpuRegister<XmmRegister>(), mask);
Roland Levillain88cb1752014-10-20 16:36:47 +01001463 break;
Roland Levillain5368c212014-11-27 15:03:41 +00001464 }
Roland Levillain88cb1752014-10-20 16:36:47 +01001465
1466 default:
1467 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1468 }
1469}
1470
Roland Levillaindff1f282014-11-05 14:15:05 +00001471void LocationsBuilderX86_64::VisitTypeConversion(HTypeConversion* conversion) {
1472 LocationSummary* locations =
1473 new (GetGraph()->GetArena()) LocationSummary(conversion, LocationSummary::kNoCall);
1474 Primitive::Type result_type = conversion->GetResultType();
1475 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00001476 DCHECK_NE(result_type, input_type);
David Brazdil46e2a392015-03-16 17:31:52 +00001477
David Brazdilb2bd1c52015-03-25 11:17:37 +00001478 // The Java language does not allow treating boolean as an integral type but
1479 // our bit representation makes it safe.
David Brazdil46e2a392015-03-16 17:31:52 +00001480
Roland Levillaindff1f282014-11-05 14:15:05 +00001481 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00001482 case Primitive::kPrimByte:
1483 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001484 case Primitive::kPrimBoolean:
1485 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001486 case Primitive::kPrimShort:
1487 case Primitive::kPrimInt:
1488 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001489 // Processing a Dex `int-to-byte' instruction.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001490 locations->SetInAt(0, Location::Any());
1491 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1492 break;
1493
1494 default:
1495 LOG(FATAL) << "Unexpected type conversion from " << input_type
1496 << " to " << result_type;
1497 }
1498 break;
1499
Roland Levillain01a8d712014-11-14 16:27:39 +00001500 case Primitive::kPrimShort:
1501 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001502 case Primitive::kPrimBoolean:
1503 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00001504 case Primitive::kPrimByte:
1505 case Primitive::kPrimInt:
1506 case Primitive::kPrimChar:
1507 // Processing a Dex `int-to-short' instruction.
1508 locations->SetInAt(0, Location::Any());
1509 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1510 break;
1511
1512 default:
1513 LOG(FATAL) << "Unexpected type conversion from " << input_type
1514 << " to " << result_type;
1515 }
1516 break;
1517
Roland Levillain946e1432014-11-11 17:35:19 +00001518 case Primitive::kPrimInt:
1519 switch (input_type) {
1520 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00001521 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00001522 locations->SetInAt(0, Location::Any());
1523 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1524 break;
1525
1526 case Primitive::kPrimFloat:
Roland Levillain3f8f9362014-12-02 17:45:01 +00001527 // Processing a Dex `float-to-int' instruction.
1528 locations->SetInAt(0, Location::RequiresFpuRegister());
1529 locations->SetOut(Location::RequiresRegister());
1530 locations->AddTemp(Location::RequiresFpuRegister());
1531 break;
1532
Roland Levillain946e1432014-11-11 17:35:19 +00001533 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001534 // Processing a Dex `double-to-int' instruction.
1535 locations->SetInAt(0, Location::RequiresFpuRegister());
1536 locations->SetOut(Location::RequiresRegister());
1537 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain946e1432014-11-11 17:35:19 +00001538 break;
1539
1540 default:
1541 LOG(FATAL) << "Unexpected type conversion from " << input_type
1542 << " to " << result_type;
1543 }
1544 break;
1545
Roland Levillaindff1f282014-11-05 14:15:05 +00001546 case Primitive::kPrimLong:
1547 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001548 case Primitive::kPrimBoolean:
1549 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00001550 case Primitive::kPrimByte:
1551 case Primitive::kPrimShort:
1552 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00001553 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001554 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00001555 // TODO: We would benefit from a (to-be-implemented)
1556 // Location::RegisterOrStackSlot requirement for this input.
1557 locations->SetInAt(0, Location::RequiresRegister());
1558 locations->SetOut(Location::RequiresRegister());
1559 break;
1560
1561 case Primitive::kPrimFloat:
Roland Levillain624279f2014-12-04 11:54:28 +00001562 // Processing a Dex `float-to-long' instruction.
1563 locations->SetInAt(0, Location::RequiresFpuRegister());
1564 locations->SetOut(Location::RequiresRegister());
1565 locations->AddTemp(Location::RequiresFpuRegister());
1566 break;
1567
Roland Levillaindff1f282014-11-05 14:15:05 +00001568 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001569 // Processing a Dex `double-to-long' instruction.
1570 locations->SetInAt(0, Location::RequiresFpuRegister());
1571 locations->SetOut(Location::RequiresRegister());
1572 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillaindff1f282014-11-05 14:15:05 +00001573 break;
1574
1575 default:
1576 LOG(FATAL) << "Unexpected type conversion from " << input_type
1577 << " to " << result_type;
1578 }
1579 break;
1580
Roland Levillain981e4542014-11-14 11:47:14 +00001581 case Primitive::kPrimChar:
1582 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001583 case Primitive::kPrimBoolean:
1584 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00001585 case Primitive::kPrimByte:
1586 case Primitive::kPrimShort:
1587 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00001588 // Processing a Dex `int-to-char' instruction.
1589 locations->SetInAt(0, Location::Any());
1590 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1591 break;
1592
1593 default:
1594 LOG(FATAL) << "Unexpected type conversion from " << input_type
1595 << " to " << result_type;
1596 }
1597 break;
1598
Roland Levillaindff1f282014-11-05 14:15:05 +00001599 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00001600 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001601 case Primitive::kPrimBoolean:
1602 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001603 case Primitive::kPrimByte:
1604 case Primitive::kPrimShort:
1605 case Primitive::kPrimInt:
1606 case Primitive::kPrimChar:
1607 // Processing a Dex `int-to-float' instruction.
1608 locations->SetInAt(0, Location::RequiresRegister());
1609 locations->SetOut(Location::RequiresFpuRegister());
1610 break;
1611
1612 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00001613 // Processing a Dex `long-to-float' instruction.
1614 locations->SetInAt(0, Location::RequiresRegister());
1615 locations->SetOut(Location::RequiresFpuRegister());
1616 break;
1617
Roland Levillaincff13742014-11-17 14:32:17 +00001618 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001619 // Processing a Dex `double-to-float' instruction.
1620 locations->SetInAt(0, Location::RequiresFpuRegister());
1621 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00001622 break;
1623
1624 default:
1625 LOG(FATAL) << "Unexpected type conversion from " << input_type
1626 << " to " << result_type;
1627 };
1628 break;
1629
Roland Levillaindff1f282014-11-05 14:15:05 +00001630 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00001631 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001632 case Primitive::kPrimBoolean:
1633 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001634 case Primitive::kPrimByte:
1635 case Primitive::kPrimShort:
1636 case Primitive::kPrimInt:
1637 case Primitive::kPrimChar:
1638 // Processing a Dex `int-to-double' instruction.
1639 locations->SetInAt(0, Location::RequiresRegister());
1640 locations->SetOut(Location::RequiresFpuRegister());
1641 break;
1642
1643 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00001644 // Processing a Dex `long-to-double' instruction.
1645 locations->SetInAt(0, Location::RequiresRegister());
1646 locations->SetOut(Location::RequiresFpuRegister());
1647 break;
1648
Roland Levillaincff13742014-11-17 14:32:17 +00001649 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001650 // Processing a Dex `float-to-double' instruction.
1651 locations->SetInAt(0, Location::RequiresFpuRegister());
1652 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00001653 break;
1654
1655 default:
1656 LOG(FATAL) << "Unexpected type conversion from " << input_type
1657 << " to " << result_type;
1658 }
Roland Levillaindff1f282014-11-05 14:15:05 +00001659 break;
1660
1661 default:
1662 LOG(FATAL) << "Unexpected type conversion from " << input_type
1663 << " to " << result_type;
1664 }
1665}
1666
1667void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conversion) {
1668 LocationSummary* locations = conversion->GetLocations();
1669 Location out = locations->Out();
1670 Location in = locations->InAt(0);
1671 Primitive::Type result_type = conversion->GetResultType();
1672 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00001673 DCHECK_NE(result_type, input_type);
Roland Levillaindff1f282014-11-05 14:15:05 +00001674 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00001675 case Primitive::kPrimByte:
1676 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001677 case Primitive::kPrimBoolean:
1678 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001679 case Primitive::kPrimShort:
1680 case Primitive::kPrimInt:
1681 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001682 // Processing a Dex `int-to-byte' instruction.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001683 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001684 __ movsxb(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain51d3fc42014-11-13 14:11:42 +00001685 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001686 __ movsxb(out.AsRegister<CpuRegister>(),
Roland Levillain51d3fc42014-11-13 14:11:42 +00001687 Address(CpuRegister(RSP), in.GetStackIndex()));
1688 } else {
1689 DCHECK(in.GetConstant()->IsIntConstant());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001690 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain51d3fc42014-11-13 14:11:42 +00001691 Immediate(static_cast<int8_t>(in.GetConstant()->AsIntConstant()->GetValue())));
1692 }
1693 break;
1694
1695 default:
1696 LOG(FATAL) << "Unexpected type conversion from " << input_type
1697 << " to " << result_type;
1698 }
1699 break;
1700
Roland Levillain01a8d712014-11-14 16:27:39 +00001701 case Primitive::kPrimShort:
1702 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001703 case Primitive::kPrimBoolean:
1704 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00001705 case Primitive::kPrimByte:
1706 case Primitive::kPrimInt:
1707 case Primitive::kPrimChar:
1708 // Processing a Dex `int-to-short' instruction.
1709 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001710 __ movsxw(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain01a8d712014-11-14 16:27:39 +00001711 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001712 __ movsxw(out.AsRegister<CpuRegister>(),
Roland Levillain01a8d712014-11-14 16:27:39 +00001713 Address(CpuRegister(RSP), in.GetStackIndex()));
1714 } else {
1715 DCHECK(in.GetConstant()->IsIntConstant());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001716 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain01a8d712014-11-14 16:27:39 +00001717 Immediate(static_cast<int16_t>(in.GetConstant()->AsIntConstant()->GetValue())));
1718 }
1719 break;
1720
1721 default:
1722 LOG(FATAL) << "Unexpected type conversion from " << input_type
1723 << " to " << result_type;
1724 }
1725 break;
1726
Roland Levillain946e1432014-11-11 17:35:19 +00001727 case Primitive::kPrimInt:
1728 switch (input_type) {
1729 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00001730 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00001731 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001732 __ movl(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain946e1432014-11-11 17:35:19 +00001733 } else if (in.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001734 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain946e1432014-11-11 17:35:19 +00001735 Address(CpuRegister(RSP), in.GetStackIndex()));
1736 } else {
1737 DCHECK(in.IsConstant());
1738 DCHECK(in.GetConstant()->IsLongConstant());
1739 int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00001740 __ movl(out.AsRegister<CpuRegister>(), Immediate(static_cast<int32_t>(value)));
Roland Levillain946e1432014-11-11 17:35:19 +00001741 }
1742 break;
1743
Roland Levillain3f8f9362014-12-02 17:45:01 +00001744 case Primitive::kPrimFloat: {
1745 // Processing a Dex `float-to-int' instruction.
1746 XmmRegister input = in.AsFpuRegister<XmmRegister>();
1747 CpuRegister output = out.AsRegister<CpuRegister>();
1748 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
1749 Label done, nan;
1750
1751 __ movl(output, Immediate(kPrimIntMax));
1752 // temp = int-to-float(output)
Roland Levillain624279f2014-12-04 11:54:28 +00001753 __ cvtsi2ss(temp, output, false);
Roland Levillain3f8f9362014-12-02 17:45:01 +00001754 // if input >= temp goto done
1755 __ comiss(input, temp);
1756 __ j(kAboveEqual, &done);
1757 // if input == NaN goto nan
1758 __ j(kUnordered, &nan);
1759 // output = float-to-int-truncate(input)
Roland Levillain624279f2014-12-04 11:54:28 +00001760 __ cvttss2si(output, input, false);
Roland Levillain3f8f9362014-12-02 17:45:01 +00001761 __ jmp(&done);
1762 __ Bind(&nan);
1763 // output = 0
1764 __ xorl(output, output);
1765 __ Bind(&done);
1766 break;
1767 }
1768
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001769 case Primitive::kPrimDouble: {
1770 // Processing a Dex `double-to-int' instruction.
1771 XmmRegister input = in.AsFpuRegister<XmmRegister>();
1772 CpuRegister output = out.AsRegister<CpuRegister>();
1773 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
1774 Label done, nan;
1775
1776 __ movl(output, Immediate(kPrimIntMax));
1777 // temp = int-to-double(output)
1778 __ cvtsi2sd(temp, output);
1779 // if input >= temp goto done
1780 __ comisd(input, temp);
1781 __ j(kAboveEqual, &done);
1782 // if input == NaN goto nan
1783 __ j(kUnordered, &nan);
1784 // output = double-to-int-truncate(input)
1785 __ cvttsd2si(output, input);
1786 __ jmp(&done);
1787 __ Bind(&nan);
1788 // output = 0
1789 __ xorl(output, output);
1790 __ Bind(&done);
Roland Levillain946e1432014-11-11 17:35:19 +00001791 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001792 }
Roland Levillain946e1432014-11-11 17:35:19 +00001793
1794 default:
1795 LOG(FATAL) << "Unexpected type conversion from " << input_type
1796 << " to " << result_type;
1797 }
1798 break;
1799
Roland Levillaindff1f282014-11-05 14:15:05 +00001800 case Primitive::kPrimLong:
1801 switch (input_type) {
1802 DCHECK(out.IsRegister());
David Brazdil46e2a392015-03-16 17:31:52 +00001803 case Primitive::kPrimBoolean:
1804 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00001805 case Primitive::kPrimByte:
1806 case Primitive::kPrimShort:
1807 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00001808 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001809 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00001810 DCHECK(in.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001811 __ movsxd(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillaindff1f282014-11-05 14:15:05 +00001812 break;
1813
Roland Levillain624279f2014-12-04 11:54:28 +00001814 case Primitive::kPrimFloat: {
1815 // Processing a Dex `float-to-long' instruction.
1816 XmmRegister input = in.AsFpuRegister<XmmRegister>();
1817 CpuRegister output = out.AsRegister<CpuRegister>();
1818 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
1819 Label done, nan;
1820
1821 __ movq(output, Immediate(kPrimLongMax));
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001822 // temp = long-to-float(output)
Roland Levillain624279f2014-12-04 11:54:28 +00001823 __ cvtsi2ss(temp, output, true);
1824 // if input >= temp goto done
1825 __ comiss(input, temp);
1826 __ j(kAboveEqual, &done);
1827 // if input == NaN goto nan
1828 __ j(kUnordered, &nan);
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001829 // output = float-to-long-truncate(input)
Roland Levillain624279f2014-12-04 11:54:28 +00001830 __ cvttss2si(output, input, true);
1831 __ jmp(&done);
1832 __ Bind(&nan);
1833 // output = 0
1834 __ xorq(output, output);
1835 __ Bind(&done);
1836 break;
1837 }
1838
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001839 case Primitive::kPrimDouble: {
1840 // Processing a Dex `double-to-long' instruction.
1841 XmmRegister input = in.AsFpuRegister<XmmRegister>();
1842 CpuRegister output = out.AsRegister<CpuRegister>();
1843 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
1844 Label done, nan;
1845
1846 __ movq(output, Immediate(kPrimLongMax));
1847 // temp = long-to-double(output)
1848 __ cvtsi2sd(temp, output, true);
1849 // if input >= temp goto done
1850 __ comisd(input, temp);
1851 __ j(kAboveEqual, &done);
1852 // if input == NaN goto nan
1853 __ j(kUnordered, &nan);
1854 // output = double-to-long-truncate(input)
1855 __ cvttsd2si(output, input, true);
1856 __ jmp(&done);
1857 __ Bind(&nan);
1858 // output = 0
1859 __ xorq(output, output);
1860 __ Bind(&done);
Roland Levillaindff1f282014-11-05 14:15:05 +00001861 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001862 }
Roland Levillaindff1f282014-11-05 14:15:05 +00001863
1864 default:
1865 LOG(FATAL) << "Unexpected type conversion from " << input_type
1866 << " to " << result_type;
1867 }
1868 break;
1869
Roland Levillain981e4542014-11-14 11:47:14 +00001870 case Primitive::kPrimChar:
1871 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001872 case Primitive::kPrimBoolean:
1873 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00001874 case Primitive::kPrimByte:
1875 case Primitive::kPrimShort:
1876 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00001877 // Processing a Dex `int-to-char' instruction.
1878 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001879 __ movzxw(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain981e4542014-11-14 11:47:14 +00001880 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001881 __ movzxw(out.AsRegister<CpuRegister>(),
Roland Levillain981e4542014-11-14 11:47:14 +00001882 Address(CpuRegister(RSP), in.GetStackIndex()));
1883 } else {
1884 DCHECK(in.GetConstant()->IsIntConstant());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001885 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain981e4542014-11-14 11:47:14 +00001886 Immediate(static_cast<uint16_t>(in.GetConstant()->AsIntConstant()->GetValue())));
1887 }
1888 break;
1889
1890 default:
1891 LOG(FATAL) << "Unexpected type conversion from " << input_type
1892 << " to " << result_type;
1893 }
1894 break;
1895
Roland Levillaindff1f282014-11-05 14:15:05 +00001896 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00001897 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001898 case Primitive::kPrimBoolean:
1899 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001900 case Primitive::kPrimByte:
1901 case Primitive::kPrimShort:
1902 case Primitive::kPrimInt:
1903 case Primitive::kPrimChar:
Roland Levillain6d0e4832014-11-27 18:31:21 +00001904 // Processing a Dex `int-to-float' instruction.
1905 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), false);
Roland Levillaincff13742014-11-17 14:32:17 +00001906 break;
1907
1908 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00001909 // Processing a Dex `long-to-float' instruction.
1910 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), true);
1911 break;
1912
Roland Levillaincff13742014-11-17 14:32:17 +00001913 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001914 // Processing a Dex `double-to-float' instruction.
1915 __ cvtsd2ss(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00001916 break;
1917
1918 default:
1919 LOG(FATAL) << "Unexpected type conversion from " << input_type
1920 << " to " << result_type;
1921 };
1922 break;
1923
Roland Levillaindff1f282014-11-05 14:15:05 +00001924 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00001925 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001926 case Primitive::kPrimBoolean:
1927 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001928 case Primitive::kPrimByte:
1929 case Primitive::kPrimShort:
1930 case Primitive::kPrimInt:
1931 case Primitive::kPrimChar:
Roland Levillain6d0e4832014-11-27 18:31:21 +00001932 // Processing a Dex `int-to-double' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001933 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), false);
Roland Levillaincff13742014-11-17 14:32:17 +00001934 break;
1935
1936 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00001937 // Processing a Dex `long-to-double' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001938 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), true);
Roland Levillain647b9ed2014-11-27 12:06:00 +00001939 break;
1940
Roland Levillaincff13742014-11-17 14:32:17 +00001941 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001942 // Processing a Dex `float-to-double' instruction.
1943 __ cvtss2sd(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00001944 break;
1945
1946 default:
1947 LOG(FATAL) << "Unexpected type conversion from " << input_type
1948 << " to " << result_type;
1949 };
Roland Levillaindff1f282014-11-05 14:15:05 +00001950 break;
1951
1952 default:
1953 LOG(FATAL) << "Unexpected type conversion from " << input_type
1954 << " to " << result_type;
1955 }
1956}
1957
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001958void LocationsBuilderX86_64::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001959 LocationSummary* locations =
1960 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001961 switch (add->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001962 case Primitive::kPrimInt: {
1963 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray748f1402015-01-27 08:17:54 +00001964 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
1965 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001966 break;
1967 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001968
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001969 case Primitive::kPrimLong: {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001970 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell09b84632015-02-13 17:48:38 -05001971 // We can use a leaq or addq if the constant can fit in an immediate.
Mark Mendell3f6c7f62015-03-13 13:47:53 -04001972 locations->SetInAt(1, Location::RegisterOrInt32LongConstant(add->InputAt(1)));
Mark Mendell09b84632015-02-13 17:48:38 -05001973 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001974 break;
1975 }
1976
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001977 case Primitive::kPrimDouble:
1978 case Primitive::kPrimFloat: {
1979 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendellf55c3e02015-03-26 21:07:46 -04001980 locations->SetInAt(1, Location::Any());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001981 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001982 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001983 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001984
1985 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001986 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001987 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001988}
1989
1990void InstructionCodeGeneratorX86_64::VisitAdd(HAdd* add) {
1991 LocationSummary* locations = add->GetLocations();
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001992 Location first = locations->InAt(0);
1993 Location second = locations->InAt(1);
Nicolas Geoffray748f1402015-01-27 08:17:54 +00001994 Location out = locations->Out();
Calin Juravle11351682014-10-23 15:38:15 +01001995
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001996 switch (add->GetResultType()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001997 case Primitive::kPrimInt: {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001998 if (second.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00001999 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
2000 __ addl(out.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
2001 } else {
2002 __ leal(out.AsRegister<CpuRegister>(), Address(
2003 first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>(), TIMES_1, 0));
2004 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002005 } else if (second.IsConstant()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002006 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
2007 __ addl(out.AsRegister<CpuRegister>(),
2008 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
2009 } else {
2010 __ leal(out.AsRegister<CpuRegister>(), Address(
2011 first.AsRegister<CpuRegister>(), second.GetConstant()->AsIntConstant()->GetValue()));
2012 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002013 } else {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002014 DCHECK(first.Equals(locations->Out()));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002015 __ addl(first.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), second.GetStackIndex()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002016 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002017 break;
2018 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002019
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002020 case Primitive::kPrimLong: {
Mark Mendell09b84632015-02-13 17:48:38 -05002021 if (second.IsRegister()) {
2022 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
2023 __ addq(out.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
2024 } else {
2025 __ leaq(out.AsRegister<CpuRegister>(), Address(
2026 first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>(), TIMES_1, 0));
2027 }
2028 } else {
2029 DCHECK(second.IsConstant());
2030 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
2031 int32_t int32_value = Low32Bits(value);
2032 DCHECK_EQ(int32_value, value);
2033 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
2034 __ addq(out.AsRegister<CpuRegister>(), Immediate(int32_value));
2035 } else {
2036 __ leaq(out.AsRegister<CpuRegister>(), Address(
2037 first.AsRegister<CpuRegister>(), int32_value));
2038 }
2039 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002040 break;
2041 }
2042
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002043 case Primitive::kPrimFloat: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04002044 if (second.IsFpuRegister()) {
2045 __ addss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2046 } else if (second.IsConstant()) {
2047 __ addss(first.AsFpuRegister<XmmRegister>(),
2048 codegen_->LiteralFloatAddress(second.GetConstant()->AsFloatConstant()->GetValue()));
2049 } else {
2050 DCHECK(second.IsStackSlot());
2051 __ addss(first.AsFpuRegister<XmmRegister>(),
2052 Address(CpuRegister(RSP), second.GetStackIndex()));
2053 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002054 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002055 }
2056
2057 case Primitive::kPrimDouble: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04002058 if (second.IsFpuRegister()) {
2059 __ addsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2060 } else if (second.IsConstant()) {
2061 __ addsd(first.AsFpuRegister<XmmRegister>(),
2062 codegen_->LiteralDoubleAddress(second.GetConstant()->AsDoubleConstant()->GetValue()));
2063 } else {
2064 DCHECK(second.IsDoubleStackSlot());
2065 __ addsd(first.AsFpuRegister<XmmRegister>(),
2066 Address(CpuRegister(RSP), second.GetStackIndex()));
2067 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002068 break;
2069 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002070
2071 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002072 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002073 }
2074}
2075
2076void LocationsBuilderX86_64::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002077 LocationSummary* locations =
2078 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002079 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002080 case Primitive::kPrimInt: {
2081 locations->SetInAt(0, Location::RequiresRegister());
2082 locations->SetInAt(1, Location::Any());
2083 locations->SetOut(Location::SameAsFirstInput());
2084 break;
2085 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002086 case Primitive::kPrimLong: {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002087 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002088 locations->SetInAt(1, Location::RegisterOrInt32LongConstant(sub->InputAt(1)));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002089 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002090 break;
2091 }
Calin Juravle11351682014-10-23 15:38:15 +01002092 case Primitive::kPrimFloat:
2093 case Primitive::kPrimDouble: {
2094 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendellf55c3e02015-03-26 21:07:46 -04002095 locations->SetInAt(1, Location::Any());
Calin Juravle11351682014-10-23 15:38:15 +01002096 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002097 break;
Calin Juravle11351682014-10-23 15:38:15 +01002098 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002099 default:
Calin Juravle11351682014-10-23 15:38:15 +01002100 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002101 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002102}
2103
2104void InstructionCodeGeneratorX86_64::VisitSub(HSub* sub) {
2105 LocationSummary* locations = sub->GetLocations();
Calin Juravle11351682014-10-23 15:38:15 +01002106 Location first = locations->InAt(0);
2107 Location second = locations->InAt(1);
2108 DCHECK(first.Equals(locations->Out()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002109 switch (sub->GetResultType()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002110 case Primitive::kPrimInt: {
Calin Juravle11351682014-10-23 15:38:15 +01002111 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002112 __ subl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Calin Juravle11351682014-10-23 15:38:15 +01002113 } else if (second.IsConstant()) {
2114 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002115 __ subl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002116 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002117 __ subl(first.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), second.GetStackIndex()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002118 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002119 break;
2120 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002121 case Primitive::kPrimLong: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002122 if (second.IsConstant()) {
2123 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
2124 DCHECK(IsInt<32>(value));
2125 __ subq(first.AsRegister<CpuRegister>(), Immediate(static_cast<int32_t>(value)));
2126 } else {
2127 __ subq(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
2128 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002129 break;
2130 }
2131
Calin Juravle11351682014-10-23 15:38:15 +01002132 case Primitive::kPrimFloat: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04002133 if (second.IsFpuRegister()) {
2134 __ subss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2135 } else if (second.IsConstant()) {
2136 __ subss(first.AsFpuRegister<XmmRegister>(),
2137 codegen_->LiteralFloatAddress(second.GetConstant()->AsFloatConstant()->GetValue()));
2138 } else {
2139 DCHECK(second.IsStackSlot());
2140 __ subss(first.AsFpuRegister<XmmRegister>(),
2141 Address(CpuRegister(RSP), second.GetStackIndex()));
2142 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002143 break;
Calin Juravle11351682014-10-23 15:38:15 +01002144 }
2145
2146 case Primitive::kPrimDouble: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04002147 if (second.IsFpuRegister()) {
2148 __ subsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2149 } else if (second.IsConstant()) {
2150 __ subsd(first.AsFpuRegister<XmmRegister>(),
2151 codegen_->LiteralDoubleAddress(second.GetConstant()->AsDoubleConstant()->GetValue()));
2152 } else {
2153 DCHECK(second.IsDoubleStackSlot());
2154 __ subsd(first.AsFpuRegister<XmmRegister>(),
2155 Address(CpuRegister(RSP), second.GetStackIndex()));
2156 }
Calin Juravle11351682014-10-23 15:38:15 +01002157 break;
2158 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002159
2160 default:
Calin Juravle11351682014-10-23 15:38:15 +01002161 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002162 }
2163}
2164
Calin Juravle34bacdf2014-10-07 20:23:36 +01002165void LocationsBuilderX86_64::VisitMul(HMul* mul) {
2166 LocationSummary* locations =
2167 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
2168 switch (mul->GetResultType()) {
2169 case Primitive::kPrimInt: {
2170 locations->SetInAt(0, Location::RequiresRegister());
2171 locations->SetInAt(1, Location::Any());
2172 locations->SetOut(Location::SameAsFirstInput());
2173 break;
2174 }
2175 case Primitive::kPrimLong: {
2176 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002177 locations->SetInAt(1, Location::RegisterOrInt32LongConstant(mul->InputAt(1)));
2178 if (locations->InAt(1).IsConstant()) {
2179 // Can use 3 operand multiply.
2180 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2181 } else {
2182 locations->SetOut(Location::SameAsFirstInput());
2183 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002184 break;
2185 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01002186 case Primitive::kPrimFloat:
2187 case Primitive::kPrimDouble: {
2188 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendellf55c3e02015-03-26 21:07:46 -04002189 locations->SetInAt(1, Location::Any());
Calin Juravleb5bfa962014-10-21 18:02:24 +01002190 locations->SetOut(Location::SameAsFirstInput());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002191 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002192 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002193
2194 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002195 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002196 }
2197}
2198
2199void InstructionCodeGeneratorX86_64::VisitMul(HMul* mul) {
2200 LocationSummary* locations = mul->GetLocations();
2201 Location first = locations->InAt(0);
2202 Location second = locations->InAt(1);
Calin Juravle34bacdf2014-10-07 20:23:36 +01002203 switch (mul->GetResultType()) {
2204 case Primitive::kPrimInt: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002205 DCHECK(first.Equals(locations->Out()));
Calin Juravle34bacdf2014-10-07 20:23:36 +01002206 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002207 __ imull(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002208 } else if (second.IsConstant()) {
2209 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002210 __ imull(first.AsRegister<CpuRegister>(), imm);
Calin Juravle34bacdf2014-10-07 20:23:36 +01002211 } else {
2212 DCHECK(second.IsStackSlot());
Roland Levillain199f3362014-11-27 17:15:16 +00002213 __ imull(first.AsRegister<CpuRegister>(),
2214 Address(CpuRegister(RSP), second.GetStackIndex()));
Calin Juravle34bacdf2014-10-07 20:23:36 +01002215 }
2216 break;
2217 }
2218 case Primitive::kPrimLong: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002219 if (second.IsConstant()) {
2220 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
2221 DCHECK(IsInt<32>(value));
2222 __ imulq(locations->Out().AsRegister<CpuRegister>(),
2223 first.AsRegister<CpuRegister>(),
2224 Immediate(static_cast<int32_t>(value)));
2225 } else {
2226 DCHECK(first.Equals(locations->Out()));
2227 __ imulq(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
2228 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002229 break;
2230 }
2231
Calin Juravleb5bfa962014-10-21 18:02:24 +01002232 case Primitive::kPrimFloat: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002233 DCHECK(first.Equals(locations->Out()));
Mark Mendellf55c3e02015-03-26 21:07:46 -04002234 if (second.IsFpuRegister()) {
2235 __ mulss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2236 } else if (second.IsConstant()) {
2237 __ mulss(first.AsFpuRegister<XmmRegister>(),
2238 codegen_->LiteralFloatAddress(second.GetConstant()->AsFloatConstant()->GetValue()));
2239 } else {
2240 DCHECK(second.IsStackSlot());
2241 __ mulss(first.AsFpuRegister<XmmRegister>(),
2242 Address(CpuRegister(RSP), second.GetStackIndex()));
2243 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002244 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002245 }
2246
2247 case Primitive::kPrimDouble: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002248 DCHECK(first.Equals(locations->Out()));
Mark Mendellf55c3e02015-03-26 21:07:46 -04002249 if (second.IsFpuRegister()) {
2250 __ mulsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2251 } else if (second.IsConstant()) {
2252 __ mulsd(first.AsFpuRegister<XmmRegister>(),
2253 codegen_->LiteralDoubleAddress(second.GetConstant()->AsDoubleConstant()->GetValue()));
2254 } else {
2255 DCHECK(second.IsDoubleStackSlot());
2256 __ mulsd(first.AsFpuRegister<XmmRegister>(),
2257 Address(CpuRegister(RSP), second.GetStackIndex()));
2258 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01002259 break;
2260 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002261
2262 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002263 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002264 }
2265}
2266
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002267void InstructionCodeGeneratorX86_64::PushOntoFPStack(Location source, uint32_t temp_offset,
2268 uint32_t stack_adjustment, bool is_float) {
2269 if (source.IsStackSlot()) {
2270 DCHECK(is_float);
2271 __ flds(Address(CpuRegister(RSP), source.GetStackIndex() + stack_adjustment));
2272 } else if (source.IsDoubleStackSlot()) {
2273 DCHECK(!is_float);
2274 __ fldl(Address(CpuRegister(RSP), source.GetStackIndex() + stack_adjustment));
2275 } else {
2276 // Write the value to the temporary location on the stack and load to FP stack.
2277 if (is_float) {
2278 Location stack_temp = Location::StackSlot(temp_offset);
2279 codegen_->Move(stack_temp, source);
2280 __ flds(Address(CpuRegister(RSP), temp_offset));
2281 } else {
2282 Location stack_temp = Location::DoubleStackSlot(temp_offset);
2283 codegen_->Move(stack_temp, source);
2284 __ fldl(Address(CpuRegister(RSP), temp_offset));
2285 }
2286 }
2287}
2288
2289void InstructionCodeGeneratorX86_64::GenerateRemFP(HRem *rem) {
2290 Primitive::Type type = rem->GetResultType();
2291 bool is_float = type == Primitive::kPrimFloat;
2292 size_t elem_size = Primitive::ComponentSize(type);
2293 LocationSummary* locations = rem->GetLocations();
2294 Location first = locations->InAt(0);
2295 Location second = locations->InAt(1);
2296 Location out = locations->Out();
2297
2298 // Create stack space for 2 elements.
2299 // TODO: enhance register allocator to ask for stack temporaries.
2300 __ subq(CpuRegister(RSP), Immediate(2 * elem_size));
2301
2302 // Load the values to the FP stack in reverse order, using temporaries if needed.
2303 PushOntoFPStack(second, elem_size, 2 * elem_size, is_float);
2304 PushOntoFPStack(first, 0, 2 * elem_size, is_float);
2305
2306 // Loop doing FPREM until we stabilize.
2307 Label retry;
2308 __ Bind(&retry);
2309 __ fprem();
2310
2311 // Move FP status to AX.
2312 __ fstsw();
2313
2314 // And see if the argument reduction is complete. This is signaled by the
2315 // C2 FPU flag bit set to 0.
2316 __ andl(CpuRegister(RAX), Immediate(kC2ConditionMask));
2317 __ j(kNotEqual, &retry);
2318
2319 // We have settled on the final value. Retrieve it into an XMM register.
2320 // Store FP top of stack to real stack.
2321 if (is_float) {
2322 __ fsts(Address(CpuRegister(RSP), 0));
2323 } else {
2324 __ fstl(Address(CpuRegister(RSP), 0));
2325 }
2326
2327 // Pop the 2 items from the FP stack.
2328 __ fucompp();
2329
2330 // Load the value from the stack into an XMM register.
2331 DCHECK(out.IsFpuRegister()) << out;
2332 if (is_float) {
2333 __ movss(out.AsFpuRegister<XmmRegister>(), Address(CpuRegister(RSP), 0));
2334 } else {
2335 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(CpuRegister(RSP), 0));
2336 }
2337
2338 // And remove the temporary stack space we allocated.
2339 __ addq(CpuRegister(RSP), Immediate(2 * elem_size));
2340}
2341
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002342void InstructionCodeGeneratorX86_64::DivRemOneOrMinusOne(HBinaryOperation* instruction) {
2343 DCHECK(instruction->IsDiv() || instruction->IsRem());
2344
2345 LocationSummary* locations = instruction->GetLocations();
2346 Location second = locations->InAt(1);
2347 DCHECK(second.IsConstant());
2348
2349 CpuRegister output_register = locations->Out().AsRegister<CpuRegister>();
2350 CpuRegister input_register = locations->InAt(0).AsRegister<CpuRegister>();
2351 int64_t imm;
2352 if (second.GetConstant()->IsLongConstant()) {
2353 imm = second.GetConstant()->AsLongConstant()->GetValue();
2354 } else {
2355 imm = second.GetConstant()->AsIntConstant()->GetValue();
2356 }
2357
2358 DCHECK(imm == 1 || imm == -1);
2359
2360 switch (instruction->GetResultType()) {
2361 case Primitive::kPrimInt: {
2362 if (instruction->IsRem()) {
2363 __ xorl(output_register, output_register);
2364 } else {
2365 __ movl(output_register, input_register);
2366 if (imm == -1) {
2367 __ negl(output_register);
2368 }
2369 }
2370 break;
2371 }
2372
2373 case Primitive::kPrimLong: {
2374 if (instruction->IsRem()) {
2375 __ xorq(output_register, output_register);
2376 } else {
2377 __ movq(output_register, input_register);
2378 if (imm == -1) {
2379 __ negq(output_register);
2380 }
2381 }
2382 break;
2383 }
2384
2385 default:
2386 LOG(FATAL) << "Unreachable";
2387 }
2388}
2389
2390void InstructionCodeGeneratorX86_64::DivByPowerOfTwo(HBinaryOperation* instruction) {
2391 DCHECK(instruction->IsDiv());
2392
2393 LocationSummary* locations = instruction->GetLocations();
2394 Location second = locations->InAt(1);
2395
2396 CpuRegister output_register = locations->Out().AsRegister<CpuRegister>();
2397 CpuRegister numerator = locations->InAt(0).AsRegister<CpuRegister>();
2398
2399 int64_t imm;
2400 if (instruction->GetResultType() == Primitive::kPrimLong) {
2401 imm = second.GetConstant()->AsLongConstant()->GetValue();
2402 } else {
2403 imm = second.GetConstant()->AsIntConstant()->GetValue();
2404 }
2405
2406 DCHECK(IsPowerOfTwo(std::abs(imm)));
2407
2408 CpuRegister tmp = locations->GetTemp(0).AsRegister<CpuRegister>();
2409
2410 if (instruction->GetResultType() == Primitive::kPrimInt) {
2411 __ leal(tmp, Address(numerator, std::abs(imm) - 1));
2412 __ testl(numerator, numerator);
2413 __ cmov(kGreaterEqual, tmp, numerator);
2414 int shift = CTZ(imm);
2415 __ sarl(tmp, Immediate(shift));
2416
2417 if (imm < 0) {
2418 __ negl(tmp);
2419 }
2420
2421 __ movl(output_register, tmp);
2422 } else {
2423 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
2424 CpuRegister rdx = locations->GetTemp(0).AsRegister<CpuRegister>();
2425
2426 __ movq(rdx, Immediate(std::abs(imm) - 1));
2427 __ addq(rdx, numerator);
2428 __ testq(numerator, numerator);
2429 __ cmov(kGreaterEqual, rdx, numerator);
2430 int shift = CTZ(imm);
2431 __ sarq(rdx, Immediate(shift));
2432
2433 if (imm < 0) {
2434 __ negq(rdx);
2435 }
2436
2437 __ movq(output_register, rdx);
2438 }
2439}
2440
2441void InstructionCodeGeneratorX86_64::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) {
2442 DCHECK(instruction->IsDiv() || instruction->IsRem());
2443
2444 LocationSummary* locations = instruction->GetLocations();
2445 Location second = locations->InAt(1);
2446
2447 CpuRegister numerator = instruction->IsDiv() ? locations->GetTemp(1).AsRegister<CpuRegister>()
2448 : locations->GetTemp(0).AsRegister<CpuRegister>();
2449 CpuRegister eax = locations->InAt(0).AsRegister<CpuRegister>();
2450 CpuRegister edx = instruction->IsDiv() ? locations->GetTemp(0).AsRegister<CpuRegister>()
2451 : locations->Out().AsRegister<CpuRegister>();
2452 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
2453
2454 DCHECK_EQ(RAX, eax.AsRegister());
2455 DCHECK_EQ(RDX, edx.AsRegister());
2456 if (instruction->IsDiv()) {
2457 DCHECK_EQ(RAX, out.AsRegister());
2458 } else {
2459 DCHECK_EQ(RDX, out.AsRegister());
2460 }
2461
2462 int64_t magic;
2463 int shift;
2464
2465 // TODO: can these branch be written as one?
2466 if (instruction->GetResultType() == Primitive::kPrimInt) {
2467 int imm = second.GetConstant()->AsIntConstant()->GetValue();
2468
2469 CalculateMagicAndShiftForDivRem(imm, false /* is_long */, &magic, &shift);
2470
2471 __ movl(numerator, eax);
2472
2473 Label no_div;
2474 Label end;
2475 __ testl(eax, eax);
2476 __ j(kNotEqual, &no_div);
2477
2478 __ xorl(out, out);
2479 __ jmp(&end);
2480
2481 __ Bind(&no_div);
2482
2483 __ movl(eax, Immediate(magic));
2484 __ imull(numerator);
2485
2486 if (imm > 0 && magic < 0) {
2487 __ addl(edx, numerator);
2488 } else if (imm < 0 && magic > 0) {
2489 __ subl(edx, numerator);
2490 }
2491
2492 if (shift != 0) {
2493 __ sarl(edx, Immediate(shift));
2494 }
2495
2496 __ movl(eax, edx);
2497 __ shrl(edx, Immediate(31));
2498 __ addl(edx, eax);
2499
2500 if (instruction->IsRem()) {
2501 __ movl(eax, numerator);
2502 __ imull(edx, Immediate(imm));
2503 __ subl(eax, edx);
2504 __ movl(edx, eax);
2505 } else {
2506 __ movl(eax, edx);
2507 }
2508 __ Bind(&end);
2509 } else {
2510 int64_t imm = second.GetConstant()->AsLongConstant()->GetValue();
2511
2512 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
2513
2514 CpuRegister rax = eax;
2515 CpuRegister rdx = edx;
2516
2517 CalculateMagicAndShiftForDivRem(imm, true /* is_long */, &magic, &shift);
2518
2519 // Save the numerator.
2520 __ movq(numerator, rax);
2521
2522 // RAX = magic
2523 __ movq(rax, Immediate(magic));
2524
2525 // RDX:RAX = magic * numerator
2526 __ imulq(numerator);
2527
2528 if (imm > 0 && magic < 0) {
2529 // RDX += numeratorerator
2530 __ addq(rdx, numerator);
2531 } else if (imm < 0 && magic > 0) {
2532 // RDX -= numerator
2533 __ subq(rdx, numerator);
2534 }
2535
2536 // Shift if needed.
2537 if (shift != 0) {
2538 __ sarq(rdx, Immediate(shift));
2539 }
2540
2541 // RDX += 1 if RDX < 0
2542 __ movq(rax, rdx);
2543 __ shrq(rdx, Immediate(63));
2544 __ addq(rdx, rax);
2545
2546 if (instruction->IsRem()) {
2547 __ movq(rax, numerator);
2548
2549 if (IsInt<32>(imm)) {
2550 __ imulq(rdx, Immediate(static_cast<int32_t>(imm)));
2551 } else {
2552 __ movq(numerator, Immediate(imm));
2553 __ imulq(rdx, numerator);
2554 }
2555
2556 __ subq(rax, rdx);
2557 __ movq(rdx, rax);
2558 } else {
2559 __ movq(rax, rdx);
2560 }
2561 }
2562}
2563
Calin Juravlebacfec32014-11-14 15:54:36 +00002564void InstructionCodeGeneratorX86_64::GenerateDivRemIntegral(HBinaryOperation* instruction) {
2565 DCHECK(instruction->IsDiv() || instruction->IsRem());
2566 Primitive::Type type = instruction->GetResultType();
2567 DCHECK(type == Primitive::kPrimInt || Primitive::kPrimLong);
2568
2569 bool is_div = instruction->IsDiv();
2570 LocationSummary* locations = instruction->GetLocations();
2571
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002572 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
2573 Location second = locations->InAt(1);
Calin Juravlebacfec32014-11-14 15:54:36 +00002574
Roland Levillain271ab9c2014-11-27 15:23:57 +00002575 DCHECK_EQ(RAX, locations->InAt(0).AsRegister<CpuRegister>().AsRegister());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002576 DCHECK_EQ(is_div ? RAX : RDX, out.AsRegister());
Calin Juravlebacfec32014-11-14 15:54:36 +00002577
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002578 if (second.IsConstant()) {
2579 int64_t imm;
2580 if (second.GetConstant()->AsLongConstant()) {
2581 imm = second.GetConstant()->AsLongConstant()->GetValue();
2582 } else {
2583 imm = second.GetConstant()->AsIntConstant()->GetValue();
2584 }
Calin Juravlebacfec32014-11-14 15:54:36 +00002585
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002586 if (imm == 0) {
2587 // Do not generate anything. DivZeroCheck would prevent any code to be executed.
2588 } else if (imm == 1 || imm == -1) {
2589 DivRemOneOrMinusOne(instruction);
2590 } else if (instruction->IsDiv() && IsPowerOfTwo(std::abs(imm))) {
2591 DivByPowerOfTwo(instruction);
2592 } else {
2593 DCHECK(imm <= -2 || imm >= 2);
2594 GenerateDivRemWithAnyConstant(instruction);
2595 }
Calin Juravlebacfec32014-11-14 15:54:36 +00002596 } else {
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002597 SlowPathCodeX86_64* slow_path =
2598 new (GetGraph()->GetArena()) DivRemMinusOneSlowPathX86_64(
2599 out.AsRegister(), type, is_div);
2600 codegen_->AddSlowPath(slow_path);
Calin Juravlebacfec32014-11-14 15:54:36 +00002601
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002602 CpuRegister second_reg = second.AsRegister<CpuRegister>();
2603 // 0x80000000(00000000)/-1 triggers an arithmetic exception!
2604 // Dividing by -1 is actually negation and -0x800000000(00000000) = 0x80000000(00000000)
2605 // so it's safe to just use negl instead of more complex comparisons.
2606 if (type == Primitive::kPrimInt) {
2607 __ cmpl(second_reg, Immediate(-1));
2608 __ j(kEqual, slow_path->GetEntryLabel());
2609 // edx:eax <- sign-extended of eax
2610 __ cdq();
2611 // eax = quotient, edx = remainder
2612 __ idivl(second_reg);
2613 } else {
2614 __ cmpq(second_reg, Immediate(-1));
2615 __ j(kEqual, slow_path->GetEntryLabel());
2616 // rdx:rax <- sign-extended of rax
2617 __ cqo();
2618 // rax = quotient, rdx = remainder
2619 __ idivq(second_reg);
2620 }
2621 __ Bind(slow_path->GetExitLabel());
2622 }
Calin Juravlebacfec32014-11-14 15:54:36 +00002623}
2624
Calin Juravle7c4954d2014-10-28 16:57:40 +00002625void LocationsBuilderX86_64::VisitDiv(HDiv* div) {
2626 LocationSummary* locations =
2627 new (GetGraph()->GetArena()) LocationSummary(div, LocationSummary::kNoCall);
2628 switch (div->GetResultType()) {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002629 case Primitive::kPrimInt:
2630 case Primitive::kPrimLong: {
Calin Juravled0d48522014-11-04 16:40:20 +00002631 locations->SetInAt(0, Location::RegisterLocation(RAX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002632 locations->SetInAt(1, Location::RegisterOrConstant(div->InputAt(1)));
Calin Juravled0d48522014-11-04 16:40:20 +00002633 locations->SetOut(Location::SameAsFirstInput());
2634 // Intel uses edx:eax as the dividend.
2635 locations->AddTemp(Location::RegisterLocation(RDX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002636 // We need to save the numerator while we tweak rax and rdx. As we are using imul in a way
2637 // which enforces results to be in RAX and RDX, things are simpler if we use RDX also as
2638 // output and request another temp.
2639 if (div->InputAt(1)->IsConstant()) {
2640 locations->AddTemp(Location::RequiresRegister());
2641 }
Calin Juravled0d48522014-11-04 16:40:20 +00002642 break;
2643 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002644
Calin Juravle7c4954d2014-10-28 16:57:40 +00002645 case Primitive::kPrimFloat:
2646 case Primitive::kPrimDouble: {
2647 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendellf55c3e02015-03-26 21:07:46 -04002648 locations->SetInAt(1, Location::Any());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002649 locations->SetOut(Location::SameAsFirstInput());
2650 break;
2651 }
2652
2653 default:
2654 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2655 }
2656}
2657
2658void InstructionCodeGeneratorX86_64::VisitDiv(HDiv* div) {
2659 LocationSummary* locations = div->GetLocations();
2660 Location first = locations->InAt(0);
2661 Location second = locations->InAt(1);
2662 DCHECK(first.Equals(locations->Out()));
2663
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002664 Primitive::Type type = div->GetResultType();
2665 switch (type) {
2666 case Primitive::kPrimInt:
2667 case Primitive::kPrimLong: {
Calin Juravlebacfec32014-11-14 15:54:36 +00002668 GenerateDivRemIntegral(div);
Calin Juravled0d48522014-11-04 16:40:20 +00002669 break;
2670 }
2671
Calin Juravle7c4954d2014-10-28 16:57:40 +00002672 case Primitive::kPrimFloat: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04002673 if (second.IsFpuRegister()) {
2674 __ divss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2675 } else if (second.IsConstant()) {
2676 __ divss(first.AsFpuRegister<XmmRegister>(),
2677 codegen_->LiteralFloatAddress(second.GetConstant()->AsFloatConstant()->GetValue()));
2678 } else {
2679 DCHECK(second.IsStackSlot());
2680 __ divss(first.AsFpuRegister<XmmRegister>(),
2681 Address(CpuRegister(RSP), second.GetStackIndex()));
2682 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00002683 break;
2684 }
2685
2686 case Primitive::kPrimDouble: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04002687 if (second.IsFpuRegister()) {
2688 __ divsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2689 } else if (second.IsConstant()) {
2690 __ divsd(first.AsFpuRegister<XmmRegister>(),
2691 codegen_->LiteralDoubleAddress(second.GetConstant()->AsDoubleConstant()->GetValue()));
2692 } else {
2693 DCHECK(second.IsDoubleStackSlot());
2694 __ divsd(first.AsFpuRegister<XmmRegister>(),
2695 Address(CpuRegister(RSP), second.GetStackIndex()));
2696 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00002697 break;
2698 }
2699
2700 default:
2701 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2702 }
2703}
2704
Calin Juravlebacfec32014-11-14 15:54:36 +00002705void LocationsBuilderX86_64::VisitRem(HRem* rem) {
Calin Juravled2ec87d2014-12-08 14:24:46 +00002706 Primitive::Type type = rem->GetResultType();
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002707 LocationSummary* locations =
2708 new (GetGraph()->GetArena()) LocationSummary(rem, LocationSummary::kNoCall);
Calin Juravled2ec87d2014-12-08 14:24:46 +00002709
2710 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00002711 case Primitive::kPrimInt:
2712 case Primitive::kPrimLong: {
2713 locations->SetInAt(0, Location::RegisterLocation(RAX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002714 locations->SetInAt(1, Location::RegisterOrConstant(rem->InputAt(1)));
Calin Juravlebacfec32014-11-14 15:54:36 +00002715 // Intel uses rdx:rax as the dividend and puts the remainder in rdx
2716 locations->SetOut(Location::RegisterLocation(RDX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002717 // We need to save the numerator while we tweak eax and edx. As we are using imul in a way
2718 // which enforces results to be in RAX and RDX, things are simpler if we use EAX also as
2719 // output and request another temp.
2720 if (rem->InputAt(1)->IsConstant()) {
2721 locations->AddTemp(Location::RequiresRegister());
2722 }
Calin Juravlebacfec32014-11-14 15:54:36 +00002723 break;
2724 }
2725
2726 case Primitive::kPrimFloat:
2727 case Primitive::kPrimDouble: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002728 locations->SetInAt(0, Location::Any());
2729 locations->SetInAt(1, Location::Any());
2730 locations->SetOut(Location::RequiresFpuRegister());
2731 locations->AddTemp(Location::RegisterLocation(RAX));
Calin Juravlebacfec32014-11-14 15:54:36 +00002732 break;
2733 }
2734
2735 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00002736 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00002737 }
2738}
2739
2740void InstructionCodeGeneratorX86_64::VisitRem(HRem* rem) {
2741 Primitive::Type type = rem->GetResultType();
2742 switch (type) {
2743 case Primitive::kPrimInt:
2744 case Primitive::kPrimLong: {
2745 GenerateDivRemIntegral(rem);
2746 break;
2747 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002748 case Primitive::kPrimFloat:
Calin Juravled2ec87d2014-12-08 14:24:46 +00002749 case Primitive::kPrimDouble: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002750 GenerateRemFP(rem);
Calin Juravled2ec87d2014-12-08 14:24:46 +00002751 break;
2752 }
Calin Juravlebacfec32014-11-14 15:54:36 +00002753 default:
2754 LOG(FATAL) << "Unexpected rem type " << rem->GetResultType();
2755 }
2756}
2757
Calin Juravled0d48522014-11-04 16:40:20 +00002758void LocationsBuilderX86_64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
2759 LocationSummary* locations =
2760 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
2761 locations->SetInAt(0, Location::Any());
2762 if (instruction->HasUses()) {
2763 locations->SetOut(Location::SameAsFirstInput());
2764 }
2765}
2766
2767void InstructionCodeGeneratorX86_64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
2768 SlowPathCodeX86_64* slow_path =
2769 new (GetGraph()->GetArena()) DivZeroCheckSlowPathX86_64(instruction);
2770 codegen_->AddSlowPath(slow_path);
2771
2772 LocationSummary* locations = instruction->GetLocations();
2773 Location value = locations->InAt(0);
2774
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002775 switch (instruction->GetType()) {
2776 case Primitive::kPrimInt: {
2777 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002778 __ testl(value.AsRegister<CpuRegister>(), value.AsRegister<CpuRegister>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002779 __ j(kEqual, slow_path->GetEntryLabel());
2780 } else if (value.IsStackSlot()) {
2781 __ cmpl(Address(CpuRegister(RSP), value.GetStackIndex()), Immediate(0));
2782 __ j(kEqual, slow_path->GetEntryLabel());
2783 } else {
2784 DCHECK(value.IsConstant()) << value;
2785 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
2786 __ jmp(slow_path->GetEntryLabel());
2787 }
2788 }
2789 break;
Calin Juravled0d48522014-11-04 16:40:20 +00002790 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002791 case Primitive::kPrimLong: {
2792 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002793 __ testq(value.AsRegister<CpuRegister>(), value.AsRegister<CpuRegister>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002794 __ j(kEqual, slow_path->GetEntryLabel());
2795 } else if (value.IsDoubleStackSlot()) {
2796 __ cmpq(Address(CpuRegister(RSP), value.GetStackIndex()), Immediate(0));
2797 __ j(kEqual, slow_path->GetEntryLabel());
2798 } else {
2799 DCHECK(value.IsConstant()) << value;
2800 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
2801 __ jmp(slow_path->GetEntryLabel());
2802 }
2803 }
2804 break;
2805 }
2806 default:
2807 LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
Calin Juravled0d48522014-11-04 16:40:20 +00002808 }
Calin Juravled0d48522014-11-04 16:40:20 +00002809}
2810
Calin Juravle9aec02f2014-11-18 23:06:35 +00002811void LocationsBuilderX86_64::HandleShift(HBinaryOperation* op) {
2812 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
2813
2814 LocationSummary* locations =
2815 new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
2816
2817 switch (op->GetResultType()) {
2818 case Primitive::kPrimInt:
2819 case Primitive::kPrimLong: {
2820 locations->SetInAt(0, Location::RequiresRegister());
2821 // The shift count needs to be in CL.
2822 locations->SetInAt(1, Location::ByteRegisterOrConstant(RCX, op->InputAt(1)));
2823 locations->SetOut(Location::SameAsFirstInput());
2824 break;
2825 }
2826 default:
2827 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
2828 }
2829}
2830
2831void InstructionCodeGeneratorX86_64::HandleShift(HBinaryOperation* op) {
2832 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
2833
2834 LocationSummary* locations = op->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002835 CpuRegister first_reg = locations->InAt(0).AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002836 Location second = locations->InAt(1);
2837
2838 switch (op->GetResultType()) {
2839 case Primitive::kPrimInt: {
2840 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002841 CpuRegister second_reg = second.AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002842 if (op->IsShl()) {
2843 __ shll(first_reg, second_reg);
2844 } else if (op->IsShr()) {
2845 __ sarl(first_reg, second_reg);
2846 } else {
2847 __ shrl(first_reg, second_reg);
2848 }
2849 } else {
Nicolas Geoffray486cc192014-12-08 18:00:55 +00002850 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxIntShiftValue);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002851 if (op->IsShl()) {
2852 __ shll(first_reg, imm);
2853 } else if (op->IsShr()) {
2854 __ sarl(first_reg, imm);
2855 } else {
2856 __ shrl(first_reg, imm);
2857 }
2858 }
2859 break;
2860 }
2861 case Primitive::kPrimLong: {
2862 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002863 CpuRegister second_reg = second.AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002864 if (op->IsShl()) {
2865 __ shlq(first_reg, second_reg);
2866 } else if (op->IsShr()) {
2867 __ sarq(first_reg, second_reg);
2868 } else {
2869 __ shrq(first_reg, second_reg);
2870 }
2871 } else {
Nicolas Geoffray486cc192014-12-08 18:00:55 +00002872 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxLongShiftValue);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002873 if (op->IsShl()) {
2874 __ shlq(first_reg, imm);
2875 } else if (op->IsShr()) {
2876 __ sarq(first_reg, imm);
2877 } else {
2878 __ shrq(first_reg, imm);
2879 }
2880 }
2881 break;
2882 }
2883 default:
2884 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
2885 }
2886}
2887
2888void LocationsBuilderX86_64::VisitShl(HShl* shl) {
2889 HandleShift(shl);
2890}
2891
2892void InstructionCodeGeneratorX86_64::VisitShl(HShl* shl) {
2893 HandleShift(shl);
2894}
2895
2896void LocationsBuilderX86_64::VisitShr(HShr* shr) {
2897 HandleShift(shr);
2898}
2899
2900void InstructionCodeGeneratorX86_64::VisitShr(HShr* shr) {
2901 HandleShift(shr);
2902}
2903
2904void LocationsBuilderX86_64::VisitUShr(HUShr* ushr) {
2905 HandleShift(ushr);
2906}
2907
2908void InstructionCodeGeneratorX86_64::VisitUShr(HUShr* ushr) {
2909 HandleShift(ushr);
2910}
2911
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002912void LocationsBuilderX86_64::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002913 LocationSummary* locations =
2914 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01002915 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002916 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2917 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
2918 locations->SetOut(Location::RegisterLocation(RAX));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002919}
2920
2921void InstructionCodeGeneratorX86_64::VisitNewInstance(HNewInstance* instruction) {
2922 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002923 codegen_->LoadCurrentMethod(CpuRegister(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002924 __ movq(CpuRegister(calling_convention.GetRegisterAt(0)), Immediate(instruction->GetTypeIndex()));
2925
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +00002926 __ gs()->call(
2927 Address::Absolute(GetThreadOffset<kX86_64WordSize>(instruction->GetEntrypoint()), true));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002928
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01002929 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray39468442014-09-02 15:17:15 +01002930 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002931}
2932
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002933void LocationsBuilderX86_64::VisitNewArray(HNewArray* instruction) {
2934 LocationSummary* locations =
2935 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
2936 InvokeRuntimeCallingConvention calling_convention;
2937 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002938 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002939 locations->SetOut(Location::RegisterLocation(RAX));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002940 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002941}
2942
2943void InstructionCodeGeneratorX86_64::VisitNewArray(HNewArray* instruction) {
2944 InvokeRuntimeCallingConvention calling_convention;
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002945 codegen_->LoadCurrentMethod(CpuRegister(calling_convention.GetRegisterAt(2)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002946 __ movq(CpuRegister(calling_convention.GetRegisterAt(0)), Immediate(instruction->GetTypeIndex()));
2947
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +00002948 __ gs()->call(
2949 Address::Absolute(GetThreadOffset<kX86_64WordSize>(instruction->GetEntrypoint()), true));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002950
2951 DCHECK(!codegen_->IsLeafMethod());
2952 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
2953}
2954
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002955void LocationsBuilderX86_64::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002956 LocationSummary* locations =
2957 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002958 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
2959 if (location.IsStackSlot()) {
2960 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
2961 } else if (location.IsDoubleStackSlot()) {
2962 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
2963 }
2964 locations->SetOut(location);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002965}
2966
2967void InstructionCodeGeneratorX86_64::VisitParameterValue(HParameterValue* instruction) {
2968 // Nothing to do, the parameter is already at its location.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07002969 UNUSED(instruction);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002970}
2971
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002972void LocationsBuilderX86_64::VisitNot(HNot* not_) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002973 LocationSummary* locations =
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002974 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002975 locations->SetInAt(0, Location::RequiresRegister());
2976 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002977}
2978
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002979void InstructionCodeGeneratorX86_64::VisitNot(HNot* not_) {
2980 LocationSummary* locations = not_->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002981 DCHECK_EQ(locations->InAt(0).AsRegister<CpuRegister>().AsRegister(),
2982 locations->Out().AsRegister<CpuRegister>().AsRegister());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002983 Location out = locations->Out();
Nicolas Geoffrayd8ef2e92015-02-24 16:02:06 +00002984 switch (not_->GetResultType()) {
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002985 case Primitive::kPrimInt:
Roland Levillain271ab9c2014-11-27 15:23:57 +00002986 __ notl(out.AsRegister<CpuRegister>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002987 break;
2988
2989 case Primitive::kPrimLong:
Roland Levillain271ab9c2014-11-27 15:23:57 +00002990 __ notq(out.AsRegister<CpuRegister>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002991 break;
2992
2993 default:
2994 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
2995 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002996}
2997
2998void LocationsBuilderX86_64::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002999 LocationSummary* locations =
3000 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003001 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
3002 locations->SetInAt(i, Location::Any());
3003 }
3004 locations->SetOut(Location::Any());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003005}
3006
3007void InstructionCodeGeneratorX86_64::VisitPhi(HPhi* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003008 UNUSED(instruction);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003009 LOG(FATAL) << "Unimplemented";
3010}
3011
Calin Juravle52c48962014-12-16 17:02:57 +00003012void InstructionCodeGeneratorX86_64::GenerateMemoryBarrier(MemBarrierKind kind) {
3013 /*
3014 * According to the JSR-133 Cookbook, for x86 only StoreLoad/AnyAny barriers need memory fence.
3015 * All other barriers (LoadAny, AnyStore, StoreStore) are nops due to the x86 memory model.
3016 * For those cases, all we need to ensure is that there is a scheduling barrier in place.
3017 */
3018 switch (kind) {
3019 case MemBarrierKind::kAnyAny: {
3020 __ mfence();
3021 break;
3022 }
3023 case MemBarrierKind::kAnyStore:
3024 case MemBarrierKind::kLoadAny:
3025 case MemBarrierKind::kStoreStore: {
3026 // nop
3027 break;
3028 }
3029 default:
3030 LOG(FATAL) << "Unexpected memory barier " << kind;
3031 }
3032}
3033
3034void LocationsBuilderX86_64::HandleFieldGet(HInstruction* instruction) {
3035 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
3036
Nicolas Geoffray39468442014-09-02 15:17:15 +01003037 LocationSummary* locations =
3038 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Calin Juravle52c48962014-12-16 17:02:57 +00003039 locations->SetInAt(0, Location::RequiresRegister());
3040 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3041}
3042
3043void InstructionCodeGeneratorX86_64::HandleFieldGet(HInstruction* instruction,
3044 const FieldInfo& field_info) {
3045 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
3046
3047 LocationSummary* locations = instruction->GetLocations();
3048 CpuRegister base = locations->InAt(0).AsRegister<CpuRegister>();
3049 Location out = locations->Out();
3050 bool is_volatile = field_info.IsVolatile();
3051 Primitive::Type field_type = field_info.GetFieldType();
3052 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
3053
3054 switch (field_type) {
3055 case Primitive::kPrimBoolean: {
3056 __ movzxb(out.AsRegister<CpuRegister>(), Address(base, offset));
3057 break;
3058 }
3059
3060 case Primitive::kPrimByte: {
3061 __ movsxb(out.AsRegister<CpuRegister>(), Address(base, offset));
3062 break;
3063 }
3064
3065 case Primitive::kPrimShort: {
3066 __ movsxw(out.AsRegister<CpuRegister>(), Address(base, offset));
3067 break;
3068 }
3069
3070 case Primitive::kPrimChar: {
3071 __ movzxw(out.AsRegister<CpuRegister>(), Address(base, offset));
3072 break;
3073 }
3074
3075 case Primitive::kPrimInt:
3076 case Primitive::kPrimNot: {
3077 __ movl(out.AsRegister<CpuRegister>(), Address(base, offset));
3078 break;
3079 }
3080
3081 case Primitive::kPrimLong: {
3082 __ movq(out.AsRegister<CpuRegister>(), Address(base, offset));
3083 break;
3084 }
3085
3086 case Primitive::kPrimFloat: {
3087 __ movss(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
3088 break;
3089 }
3090
3091 case Primitive::kPrimDouble: {
3092 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
3093 break;
3094 }
3095
3096 case Primitive::kPrimVoid:
3097 LOG(FATAL) << "Unreachable type " << field_type;
3098 UNREACHABLE();
3099 }
3100
Calin Juravle77520bc2015-01-12 18:45:46 +00003101 codegen_->MaybeRecordImplicitNullCheck(instruction);
3102
Calin Juravle52c48962014-12-16 17:02:57 +00003103 if (is_volatile) {
3104 GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
3105 }
3106}
3107
3108void LocationsBuilderX86_64::HandleFieldSet(HInstruction* instruction,
3109 const FieldInfo& field_info) {
3110 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3111
3112 LocationSummary* locations =
3113 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003114 bool needs_write_barrier =
Calin Juravle52c48962014-12-16 17:02:57 +00003115 CodeGenerator::StoreNeedsWriteBarrier(field_info.GetFieldType(), instruction->InputAt(1));
3116
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003117 locations->SetInAt(0, Location::RequiresRegister());
3118 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003119 if (needs_write_barrier) {
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01003120 // Temporary registers for the write barrier.
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003121 locations->AddTemp(Location::RequiresRegister());
3122 locations->AddTemp(Location::RequiresRegister());
3123 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003124}
3125
Calin Juravle52c48962014-12-16 17:02:57 +00003126void InstructionCodeGeneratorX86_64::HandleFieldSet(HInstruction* instruction,
3127 const FieldInfo& field_info) {
3128 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3129
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003130 LocationSummary* locations = instruction->GetLocations();
Calin Juravle52c48962014-12-16 17:02:57 +00003131 CpuRegister base = locations->InAt(0).AsRegister<CpuRegister>();
3132 Location value = locations->InAt(1);
3133 bool is_volatile = field_info.IsVolatile();
3134 Primitive::Type field_type = field_info.GetFieldType();
3135 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
3136
3137 if (is_volatile) {
3138 GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
3139 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003140
3141 switch (field_type) {
3142 case Primitive::kPrimBoolean:
3143 case Primitive::kPrimByte: {
Calin Juravle52c48962014-12-16 17:02:57 +00003144 __ movb(Address(base, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003145 break;
3146 }
3147
3148 case Primitive::kPrimShort:
3149 case Primitive::kPrimChar: {
Calin Juravle52c48962014-12-16 17:02:57 +00003150 __ movw(Address(base, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003151 break;
3152 }
3153
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003154 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003155 case Primitive::kPrimNot: {
Calin Juravle52c48962014-12-16 17:02:57 +00003156 __ movl(Address(base, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003157 break;
3158 }
3159
3160 case Primitive::kPrimLong: {
Calin Juravle52c48962014-12-16 17:02:57 +00003161 __ movq(Address(base, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003162 break;
3163 }
3164
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003165 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00003166 __ movss(Address(base, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003167 break;
3168 }
3169
3170 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00003171 __ movsd(Address(base, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003172 break;
3173 }
3174
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003175 case Primitive::kPrimVoid:
3176 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003177 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003178 }
Calin Juravle52c48962014-12-16 17:02:57 +00003179
Calin Juravle77520bc2015-01-12 18:45:46 +00003180 codegen_->MaybeRecordImplicitNullCheck(instruction);
3181
3182 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
3183 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
3184 CpuRegister card = locations->GetTemp(1).AsRegister<CpuRegister>();
3185 codegen_->MarkGCCard(temp, card, base, value.AsRegister<CpuRegister>());
3186 }
3187
Calin Juravle52c48962014-12-16 17:02:57 +00003188 if (is_volatile) {
3189 GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
3190 }
3191}
3192
3193void LocationsBuilderX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
3194 HandleFieldSet(instruction, instruction->GetFieldInfo());
3195}
3196
3197void InstructionCodeGeneratorX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
3198 HandleFieldSet(instruction, instruction->GetFieldInfo());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003199}
3200
3201void LocationsBuilderX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Calin Juravle52c48962014-12-16 17:02:57 +00003202 HandleFieldGet(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003203}
3204
3205void InstructionCodeGeneratorX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Calin Juravle52c48962014-12-16 17:02:57 +00003206 HandleFieldGet(instruction, instruction->GetFieldInfo());
3207}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003208
Calin Juravle52c48962014-12-16 17:02:57 +00003209void LocationsBuilderX86_64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
3210 HandleFieldGet(instruction);
3211}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003212
Calin Juravle52c48962014-12-16 17:02:57 +00003213void InstructionCodeGeneratorX86_64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
3214 HandleFieldGet(instruction, instruction->GetFieldInfo());
3215}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003216
Calin Juravle52c48962014-12-16 17:02:57 +00003217void LocationsBuilderX86_64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
3218 HandleFieldSet(instruction, instruction->GetFieldInfo());
3219}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003220
Calin Juravle52c48962014-12-16 17:02:57 +00003221void InstructionCodeGeneratorX86_64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
3222 HandleFieldSet(instruction, instruction->GetFieldInfo());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003223}
3224
3225void LocationsBuilderX86_64::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003226 LocationSummary* locations =
3227 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003228 Location loc = codegen_->GetCompilerOptions().GetImplicitNullChecks()
3229 ? Location::RequiresRegister()
3230 : Location::Any();
3231 locations->SetInAt(0, loc);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003232 if (instruction->HasUses()) {
3233 locations->SetOut(Location::SameAsFirstInput());
3234 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003235}
3236
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003237void InstructionCodeGeneratorX86_64::GenerateImplicitNullCheck(HNullCheck* instruction) {
Calin Juravle77520bc2015-01-12 18:45:46 +00003238 if (codegen_->CanMoveNullCheckToUser(instruction)) {
3239 return;
3240 }
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003241 LocationSummary* locations = instruction->GetLocations();
3242 Location obj = locations->InAt(0);
3243
3244 __ testl(CpuRegister(RAX), Address(obj.AsRegister<CpuRegister>(), 0));
3245 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3246}
3247
3248void InstructionCodeGeneratorX86_64::GenerateExplicitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +01003249 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathX86_64(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003250 codegen_->AddSlowPath(slow_path);
3251
3252 LocationSummary* locations = instruction->GetLocations();
3253 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003254
3255 if (obj.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00003256 __ testl(obj.AsRegister<CpuRegister>(), obj.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003257 } else if (obj.IsStackSlot()) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003258 __ cmpl(Address(CpuRegister(RSP), obj.GetStackIndex()), Immediate(0));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003259 } else {
3260 DCHECK(obj.IsConstant()) << obj;
3261 DCHECK_EQ(obj.GetConstant()->AsIntConstant()->GetValue(), 0);
3262 __ jmp(slow_path->GetEntryLabel());
3263 return;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003264 }
3265 __ j(kEqual, slow_path->GetEntryLabel());
3266}
3267
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003268void InstructionCodeGeneratorX86_64::VisitNullCheck(HNullCheck* instruction) {
3269 if (codegen_->GetCompilerOptions().GetImplicitNullChecks()) {
3270 GenerateImplicitNullCheck(instruction);
3271 } else {
3272 GenerateExplicitNullCheck(instruction);
3273 }
3274}
3275
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003276void LocationsBuilderX86_64::VisitArrayGet(HArrayGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003277 LocationSummary* locations =
3278 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003279 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01003280 locations->SetInAt(
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003281 1, Location::RegisterOrConstant(instruction->InputAt(1)));
3282 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003283}
3284
3285void InstructionCodeGeneratorX86_64::VisitArrayGet(HArrayGet* instruction) {
3286 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003287 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003288 Location index = locations->InAt(1);
3289
3290 switch (instruction->GetType()) {
3291 case Primitive::kPrimBoolean: {
3292 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003293 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003294 if (index.IsConstant()) {
3295 __ movzxb(out, Address(obj,
3296 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
3297 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003298 __ movzxb(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003299 }
3300 break;
3301 }
3302
3303 case Primitive::kPrimByte: {
3304 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003305 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003306 if (index.IsConstant()) {
3307 __ movsxb(out, Address(obj,
3308 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
3309 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003310 __ movsxb(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003311 }
3312 break;
3313 }
3314
3315 case Primitive::kPrimShort: {
3316 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003317 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003318 if (index.IsConstant()) {
3319 __ movsxw(out, Address(obj,
3320 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
3321 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003322 __ movsxw(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003323 }
3324 break;
3325 }
3326
3327 case Primitive::kPrimChar: {
3328 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003329 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003330 if (index.IsConstant()) {
3331 __ movzxw(out, Address(obj,
3332 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
3333 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003334 __ movzxw(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003335 }
3336 break;
3337 }
3338
3339 case Primitive::kPrimInt:
3340 case Primitive::kPrimNot: {
3341 DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t));
3342 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003343 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003344 if (index.IsConstant()) {
3345 __ movl(out, Address(obj,
3346 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
3347 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003348 __ movl(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003349 }
3350 break;
3351 }
3352
3353 case Primitive::kPrimLong: {
3354 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003355 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003356 if (index.IsConstant()) {
3357 __ movq(out, Address(obj,
3358 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
3359 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003360 __ movq(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003361 }
3362 break;
3363 }
3364
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003365 case Primitive::kPrimFloat: {
3366 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003367 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003368 if (index.IsConstant()) {
3369 __ movss(out, Address(obj,
3370 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
3371 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003372 __ movss(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003373 }
3374 break;
3375 }
3376
3377 case Primitive::kPrimDouble: {
3378 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003379 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003380 if (index.IsConstant()) {
3381 __ movsd(out, Address(obj,
3382 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
3383 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003384 __ movsd(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003385 }
3386 break;
3387 }
3388
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003389 case Primitive::kPrimVoid:
3390 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07003391 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003392 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003393 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003394}
3395
3396void LocationsBuilderX86_64::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003397 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003398
3399 bool needs_write_barrier =
3400 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
3401 bool needs_runtime_call = instruction->NeedsTypeCheck();
3402
Nicolas Geoffray39468442014-09-02 15:17:15 +01003403 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003404 instruction, needs_runtime_call ? LocationSummary::kCall : LocationSummary::kNoCall);
3405 if (needs_runtime_call) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003406 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003407 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3408 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
3409 locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003410 } else {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003411 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01003412 locations->SetInAt(
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003413 1, Location::RegisterOrConstant(instruction->InputAt(1)));
3414 locations->SetInAt(2, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003415 if (value_type == Primitive::kPrimLong) {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003416 locations->SetInAt(2, Location::RequiresRegister());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003417 } else if (value_type == Primitive::kPrimFloat || value_type == Primitive::kPrimDouble) {
3418 locations->SetInAt(2, Location::RequiresFpuRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003419 } else {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003420 locations->SetInAt(2, Location::RegisterOrConstant(instruction->InputAt(2)));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003421 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003422
3423 if (needs_write_barrier) {
3424 // Temporary registers for the write barrier.
3425 locations->AddTemp(Location::RequiresRegister());
3426 locations->AddTemp(Location::RequiresRegister());
3427 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003428 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003429}
3430
3431void InstructionCodeGeneratorX86_64::VisitArraySet(HArraySet* instruction) {
3432 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003433 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003434 Location index = locations->InAt(1);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003435 Location value = locations->InAt(2);
Nicolas Geoffray39468442014-09-02 15:17:15 +01003436 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003437 bool needs_runtime_call = locations->WillCall();
3438 bool needs_write_barrier =
3439 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003440
3441 switch (value_type) {
3442 case Primitive::kPrimBoolean:
3443 case Primitive::kPrimByte: {
3444 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003445 if (index.IsConstant()) {
3446 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003447 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003448 __ movb(Address(obj, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003449 } else {
Roland Levillain199f3362014-11-27 17:15:16 +00003450 __ movb(Address(obj, offset),
3451 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003452 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003453 } else {
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003454 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003455 __ movb(Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset),
3456 value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003457 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003458 __ movb(Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003459 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3460 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003461 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003462 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003463 break;
3464 }
3465
3466 case Primitive::kPrimShort:
3467 case Primitive::kPrimChar: {
3468 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003469 if (index.IsConstant()) {
3470 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003471 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003472 __ movw(Address(obj, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003473 } else {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003474 DCHECK(value.IsConstant()) << value;
Roland Levillain199f3362014-11-27 17:15:16 +00003475 __ movw(Address(obj, offset),
3476 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003477 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003478 } else {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003479 DCHECK(index.IsRegister()) << index;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003480 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003481 __ movw(Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset),
3482 value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003483 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003484 DCHECK(value.IsConstant()) << value;
Roland Levillain271ab9c2014-11-27 15:23:57 +00003485 __ movw(Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003486 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3487 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003488 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003489 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003490 break;
3491 }
3492
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003493 case Primitive::kPrimInt:
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003494 case Primitive::kPrimNot: {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003495 if (!needs_runtime_call) {
3496 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
3497 if (index.IsConstant()) {
3498 size_t offset =
3499 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
3500 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003501 __ movl(Address(obj, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003502 } else {
3503 DCHECK(value.IsConstant()) << value;
3504 __ movl(Address(obj, offset),
3505 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3506 }
3507 } else {
3508 DCHECK(index.IsRegister()) << index;
3509 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003510 __ movl(Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset),
3511 value.AsRegister<CpuRegister>());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003512 } else {
3513 DCHECK(value.IsConstant()) << value;
Roland Levillain271ab9c2014-11-27 15:23:57 +00003514 __ movl(Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset),
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003515 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3516 }
3517 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003518 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003519 if (needs_write_barrier) {
3520 DCHECK_EQ(value_type, Primitive::kPrimNot);
Roland Levillain271ab9c2014-11-27 15:23:57 +00003521 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
3522 CpuRegister card = locations->GetTemp(1).AsRegister<CpuRegister>();
3523 codegen_->MarkGCCard(temp, card, obj, value.AsRegister<CpuRegister>());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003524 }
3525 } else {
3526 DCHECK_EQ(value_type, Primitive::kPrimNot);
Roland Levillain199f3362014-11-27 17:15:16 +00003527 __ gs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pAputObject),
3528 true));
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003529 DCHECK(!codegen_->IsLeafMethod());
3530 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3531 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003532 break;
3533 }
3534
3535 case Primitive::kPrimLong: {
3536 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003537 if (index.IsConstant()) {
3538 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003539 DCHECK(value.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003540 __ movq(Address(obj, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003541 } else {
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003542 DCHECK(value.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003543 __ movq(Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset),
3544 value.AsRegister<CpuRegister>());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003545 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003546 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003547 break;
3548 }
3549
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003550 case Primitive::kPrimFloat: {
3551 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
3552 if (index.IsConstant()) {
3553 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
3554 DCHECK(value.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003555 __ movss(Address(obj, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003556 } else {
3557 DCHECK(value.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003558 __ movss(Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset),
3559 value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003560 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003561 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003562 break;
3563 }
3564
3565 case Primitive::kPrimDouble: {
3566 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
3567 if (index.IsConstant()) {
3568 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
3569 DCHECK(value.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003570 __ movsd(Address(obj, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003571 } else {
3572 DCHECK(value.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003573 __ movsd(Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset),
3574 value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003575 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003576 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003577 break;
3578 }
3579
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003580 case Primitive::kPrimVoid:
3581 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07003582 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003583 }
3584}
3585
3586void LocationsBuilderX86_64::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003587 LocationSummary* locations =
3588 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003589 locations->SetInAt(0, Location::RequiresRegister());
3590 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003591}
3592
3593void InstructionCodeGeneratorX86_64::VisitArrayLength(HArrayLength* instruction) {
3594 LocationSummary* locations = instruction->GetLocations();
3595 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003596 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
3597 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003598 __ movl(out, Address(obj, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00003599 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003600}
3601
3602void LocationsBuilderX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003603 LocationSummary* locations =
3604 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Mark Mendellf60c90b2015-03-04 15:12:59 -05003605 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003606 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003607 if (instruction->HasUses()) {
3608 locations->SetOut(Location::SameAsFirstInput());
3609 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003610}
3611
3612void InstructionCodeGeneratorX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
3613 LocationSummary* locations = instruction->GetLocations();
Mark Mendellf60c90b2015-03-04 15:12:59 -05003614 Location index_loc = locations->InAt(0);
3615 Location length_loc = locations->InAt(1);
3616 SlowPathCodeX86_64* slow_path =
3617 new (GetGraph()->GetArena()) BoundsCheckSlowPathX86_64(instruction, index_loc, length_loc);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003618 codegen_->AddSlowPath(slow_path);
3619
Mark Mendellf60c90b2015-03-04 15:12:59 -05003620 CpuRegister length = length_loc.AsRegister<CpuRegister>();
3621 if (index_loc.IsConstant()) {
3622 int32_t value = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
3623 __ cmpl(length, Immediate(value));
3624 } else {
3625 __ cmpl(length, index_loc.AsRegister<CpuRegister>());
3626 }
3627 __ j(kBelowEqual, slow_path->GetEntryLabel());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003628}
3629
3630void CodeGeneratorX86_64::MarkGCCard(CpuRegister temp,
3631 CpuRegister card,
3632 CpuRegister object,
3633 CpuRegister value) {
3634 Label is_null;
3635 __ testl(value, value);
3636 __ j(kEqual, &is_null);
3637 __ gs()->movq(card, Address::Absolute(
3638 Thread::CardTableOffset<kX86_64WordSize>().Int32Value(), true));
3639 __ movq(temp, object);
3640 __ shrq(temp, Immediate(gc::accounting::CardTable::kCardShift));
3641 __ movb(Address(temp, card, TIMES_1, 0), card);
3642 __ Bind(&is_null);
3643}
3644
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003645void LocationsBuilderX86_64::VisitTemporary(HTemporary* temp) {
3646 temp->SetLocations(nullptr);
3647}
3648
3649void InstructionCodeGeneratorX86_64::VisitTemporary(HTemporary* temp) {
3650 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003651 UNUSED(temp);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003652}
3653
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003654void LocationsBuilderX86_64::VisitParallelMove(HParallelMove* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003655 UNUSED(instruction);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003656 LOG(FATAL) << "Unimplemented";
3657}
3658
3659void InstructionCodeGeneratorX86_64::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003660 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
3661}
3662
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003663void LocationsBuilderX86_64::VisitSuspendCheck(HSuspendCheck* instruction) {
3664 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
3665}
3666
3667void InstructionCodeGeneratorX86_64::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003668 HBasicBlock* block = instruction->GetBlock();
3669 if (block->GetLoopInformation() != nullptr) {
3670 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
3671 // The back edge will generate the suspend check.
3672 return;
3673 }
3674 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
3675 // The goto will generate the suspend check.
3676 return;
3677 }
3678 GenerateSuspendCheck(instruction, nullptr);
3679}
3680
3681void InstructionCodeGeneratorX86_64::GenerateSuspendCheck(HSuspendCheck* instruction,
3682 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003683 SuspendCheckSlowPathX86_64* slow_path =
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003684 new (GetGraph()->GetArena()) SuspendCheckSlowPathX86_64(instruction, successor);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003685 codegen_->AddSlowPath(slow_path);
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003686 __ gs()->cmpw(Address::Absolute(
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003687 Thread::ThreadFlagsOffset<kX86_64WordSize>().Int32Value(), true), Immediate(0));
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003688 if (successor == nullptr) {
3689 __ j(kNotEqual, slow_path->GetEntryLabel());
3690 __ Bind(slow_path->GetReturnLabel());
3691 } else {
3692 __ j(kEqual, codegen_->GetLabelOf(successor));
3693 __ jmp(slow_path->GetEntryLabel());
3694 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003695}
3696
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003697X86_64Assembler* ParallelMoveResolverX86_64::GetAssembler() const {
3698 return codegen_->GetAssembler();
3699}
3700
3701void ParallelMoveResolverX86_64::EmitMove(size_t index) {
3702 MoveOperands* move = moves_.Get(index);
3703 Location source = move->GetSource();
3704 Location destination = move->GetDestination();
3705
3706 if (source.IsRegister()) {
3707 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003708 __ movq(destination.AsRegister<CpuRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003709 } else if (destination.IsStackSlot()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003710 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00003711 source.AsRegister<CpuRegister>());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003712 } else {
3713 DCHECK(destination.IsDoubleStackSlot());
3714 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00003715 source.AsRegister<CpuRegister>());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003716 }
3717 } else if (source.IsStackSlot()) {
3718 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003719 __ movl(destination.AsRegister<CpuRegister>(),
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003720 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003721 } else if (destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003722 __ movss(destination.AsFpuRegister<XmmRegister>(),
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003723 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003724 } else {
3725 DCHECK(destination.IsStackSlot());
3726 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
3727 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
3728 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003729 } else if (source.IsDoubleStackSlot()) {
3730 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003731 __ movq(destination.AsRegister<CpuRegister>(),
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003732 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003733 } else if (destination.IsFpuRegister()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003734 __ movsd(destination.AsFpuRegister<XmmRegister>(),
3735 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003736 } else {
Nicolas Geoffrayc8147a72014-10-21 16:06:20 +01003737 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003738 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
3739 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
3740 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003741 } else if (source.IsConstant()) {
3742 HConstant* constant = source.GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00003743 if (constant->IsIntConstant() || constant->IsNullConstant()) {
3744 int32_t value = CodeGenerator::GetInt32ValueOf(constant);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003745 if (destination.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00003746 if (value == 0) {
3747 __ xorl(destination.AsRegister<CpuRegister>(), destination.AsRegister<CpuRegister>());
3748 } else {
3749 __ movl(destination.AsRegister<CpuRegister>(), Immediate(value));
3750 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003751 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003752 DCHECK(destination.IsStackSlot()) << destination;
Nicolas Geoffray748f1402015-01-27 08:17:54 +00003753 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), Immediate(value));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003754 }
3755 } else if (constant->IsLongConstant()) {
3756 int64_t value = constant->AsLongConstant()->GetValue();
3757 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003758 __ movq(destination.AsRegister<CpuRegister>(), Immediate(value));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003759 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003760 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003761 __ movq(CpuRegister(TMP), Immediate(value));
3762 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
3763 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003764 } else if (constant->IsFloatConstant()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003765 float fp_value = constant->AsFloatConstant()->GetValue();
Roland Levillainda4d79b2015-03-24 14:36:11 +00003766 int32_t value = bit_cast<int32_t, float>(fp_value);
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003767 Immediate imm(value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003768 if (destination.IsFpuRegister()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003769 XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
3770 if (value == 0) {
3771 // easy FP 0.0.
3772 __ xorps(dest, dest);
3773 } else {
3774 __ movl(CpuRegister(TMP), imm);
3775 __ movd(dest, CpuRegister(TMP));
3776 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003777 } else {
3778 DCHECK(destination.IsStackSlot()) << destination;
3779 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), imm);
3780 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003781 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003782 DCHECK(constant->IsDoubleConstant()) << constant->DebugName();
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003783 double fp_value = constant->AsDoubleConstant()->GetValue();
Roland Levillainda4d79b2015-03-24 14:36:11 +00003784 int64_t value = bit_cast<int64_t, double>(fp_value);
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003785 Immediate imm(value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003786 if (destination.IsFpuRegister()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003787 XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
3788 if (value == 0) {
3789 __ xorpd(dest, dest);
3790 } else {
3791 __ movq(CpuRegister(TMP), imm);
3792 __ movd(dest, CpuRegister(TMP));
3793 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003794 } else {
3795 DCHECK(destination.IsDoubleStackSlot()) << destination;
3796 __ movq(CpuRegister(TMP), imm);
3797 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
3798 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003799 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003800 } else if (source.IsFpuRegister()) {
3801 if (destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003802 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003803 } else if (destination.IsStackSlot()) {
3804 __ movss(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00003805 source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003806 } else {
Nicolas Geoffray31596742014-11-24 15:28:45 +00003807 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003808 __ movsd(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00003809 source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003810 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003811 }
3812}
3813
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003814void ParallelMoveResolverX86_64::Exchange32(CpuRegister reg, int mem) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003815 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003816 __ movl(Address(CpuRegister(RSP), mem), reg);
3817 __ movl(reg, CpuRegister(TMP));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003818}
3819
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003820void ParallelMoveResolverX86_64::Exchange32(int mem1, int mem2) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003821 ScratchRegisterScope ensure_scratch(
3822 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
3823
3824 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
3825 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
3826 __ movl(CpuRegister(ensure_scratch.GetRegister()),
3827 Address(CpuRegister(RSP), mem2 + stack_offset));
3828 __ movl(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
3829 __ movl(Address(CpuRegister(RSP), mem1 + stack_offset),
3830 CpuRegister(ensure_scratch.GetRegister()));
3831}
3832
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003833void ParallelMoveResolverX86_64::Exchange64(CpuRegister reg, int mem) {
3834 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
3835 __ movq(Address(CpuRegister(RSP), mem), reg);
3836 __ movq(reg, CpuRegister(TMP));
3837}
3838
3839void ParallelMoveResolverX86_64::Exchange64(int mem1, int mem2) {
3840 ScratchRegisterScope ensure_scratch(
Guillaume Sancheze14590b2015-04-15 18:57:27 +00003841 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003842
Guillaume Sancheze14590b2015-04-15 18:57:27 +00003843 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
3844 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
3845 __ movq(CpuRegister(ensure_scratch.GetRegister()),
3846 Address(CpuRegister(RSP), mem2 + stack_offset));
3847 __ movq(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
3848 __ movq(Address(CpuRegister(RSP), mem1 + stack_offset),
3849 CpuRegister(ensure_scratch.GetRegister()));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003850}
3851
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003852void ParallelMoveResolverX86_64::Exchange32(XmmRegister reg, int mem) {
3853 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
3854 __ movss(Address(CpuRegister(RSP), mem), reg);
3855 __ movd(reg, CpuRegister(TMP));
3856}
3857
3858void ParallelMoveResolverX86_64::Exchange64(XmmRegister reg, int mem) {
3859 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
3860 __ movsd(Address(CpuRegister(RSP), mem), reg);
3861 __ movd(reg, CpuRegister(TMP));
3862}
3863
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003864void ParallelMoveResolverX86_64::EmitSwap(size_t index) {
3865 MoveOperands* move = moves_.Get(index);
3866 Location source = move->GetSource();
3867 Location destination = move->GetDestination();
3868
3869 if (source.IsRegister() && destination.IsRegister()) {
Guillaume Sancheze14590b2015-04-15 18:57:27 +00003870 __ xchgq(destination.AsRegister<CpuRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003871 } else if (source.IsRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003872 Exchange32(source.AsRegister<CpuRegister>(), destination.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003873 } else if (source.IsStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003874 Exchange32(destination.AsRegister<CpuRegister>(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003875 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003876 Exchange32(destination.GetStackIndex(), source.GetStackIndex());
3877 } else if (source.IsRegister() && destination.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003878 Exchange64(source.AsRegister<CpuRegister>(), destination.GetStackIndex());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003879 } else if (source.IsDoubleStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003880 Exchange64(destination.AsRegister<CpuRegister>(), source.GetStackIndex());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003881 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
3882 Exchange64(destination.GetStackIndex(), source.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003883 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003884 __ movd(CpuRegister(TMP), source.AsFpuRegister<XmmRegister>());
3885 __ movaps(source.AsFpuRegister<XmmRegister>(), destination.AsFpuRegister<XmmRegister>());
3886 __ movd(destination.AsFpuRegister<XmmRegister>(), CpuRegister(TMP));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003887 } else if (source.IsFpuRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003888 Exchange32(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003889 } else if (source.IsStackSlot() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003890 Exchange32(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003891 } else if (source.IsFpuRegister() && destination.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003892 Exchange64(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003893 } else if (source.IsDoubleStackSlot() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003894 Exchange64(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003895 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003896 LOG(FATAL) << "Unimplemented swap between " << source << " and " << destination;
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003897 }
3898}
3899
3900
3901void ParallelMoveResolverX86_64::SpillScratch(int reg) {
3902 __ pushq(CpuRegister(reg));
3903}
3904
3905
3906void ParallelMoveResolverX86_64::RestoreScratch(int reg) {
3907 __ popq(CpuRegister(reg));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003908}
3909
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003910void InstructionCodeGeneratorX86_64::GenerateClassInitializationCheck(
3911 SlowPathCodeX86_64* slow_path, CpuRegister class_reg) {
3912 __ cmpl(Address(class_reg, mirror::Class::StatusOffset().Int32Value()),
3913 Immediate(mirror::Class::kStatusInitialized));
3914 __ j(kLess, slow_path->GetEntryLabel());
3915 __ Bind(slow_path->GetExitLabel());
3916 // No need for memory fence, thanks to the X86_64 memory model.
3917}
3918
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003919void LocationsBuilderX86_64::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003920 LocationSummary::CallKind call_kind = cls->CanCallRuntime()
3921 ? LocationSummary::kCallOnSlowPath
3922 : LocationSummary::kNoCall;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003923 LocationSummary* locations =
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003924 new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003925 locations->SetOut(Location::RequiresRegister());
3926}
3927
3928void InstructionCodeGeneratorX86_64::VisitLoadClass(HLoadClass* cls) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003929 CpuRegister out = cls->GetLocations()->Out().AsRegister<CpuRegister>();
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003930 if (cls->IsReferrersClass()) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003931 DCHECK(!cls->CanCallRuntime());
3932 DCHECK(!cls->MustGenerateClinitCheck());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003933 codegen_->LoadCurrentMethod(out);
3934 __ movl(out, Address(out, mirror::ArtMethod::DeclaringClassOffset().Int32Value()));
3935 } else {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003936 DCHECK(cls->CanCallRuntime());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003937 codegen_->LoadCurrentMethod(out);
3938 __ movl(out, Address(out, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value()));
3939 __ movl(out, Address(out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex())));
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003940 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86_64(
3941 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
3942 codegen_->AddSlowPath(slow_path);
3943 __ testl(out, out);
3944 __ j(kEqual, slow_path->GetEntryLabel());
3945 if (cls->MustGenerateClinitCheck()) {
3946 GenerateClassInitializationCheck(slow_path, out);
3947 } else {
3948 __ Bind(slow_path->GetExitLabel());
3949 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003950 }
3951}
3952
3953void LocationsBuilderX86_64::VisitClinitCheck(HClinitCheck* check) {
3954 LocationSummary* locations =
3955 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
3956 locations->SetInAt(0, Location::RequiresRegister());
3957 if (check->HasUses()) {
3958 locations->SetOut(Location::SameAsFirstInput());
3959 }
3960}
3961
3962void InstructionCodeGeneratorX86_64::VisitClinitCheck(HClinitCheck* check) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003963 // We assume the class to not be null.
3964 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86_64(
3965 check->GetLoadClass(), check, check->GetDexPc(), true);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003966 codegen_->AddSlowPath(slow_path);
Roland Levillain199f3362014-11-27 17:15:16 +00003967 GenerateClassInitializationCheck(slow_path,
3968 check->GetLocations()->InAt(0).AsRegister<CpuRegister>());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003969}
3970
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00003971void LocationsBuilderX86_64::VisitLoadString(HLoadString* load) {
3972 LocationSummary* locations =
3973 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
3974 locations->SetOut(Location::RequiresRegister());
3975}
3976
3977void InstructionCodeGeneratorX86_64::VisitLoadString(HLoadString* load) {
3978 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathX86_64(load);
3979 codegen_->AddSlowPath(slow_path);
3980
Roland Levillain271ab9c2014-11-27 15:23:57 +00003981 CpuRegister out = load->GetLocations()->Out().AsRegister<CpuRegister>();
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00003982 codegen_->LoadCurrentMethod(CpuRegister(out));
Mathieu Chartiereace4582014-11-24 18:29:54 -08003983 __ movl(out, Address(out, mirror::ArtMethod::DeclaringClassOffset().Int32Value()));
3984 __ movl(out, Address(out, mirror::Class::DexCacheStringsOffset().Int32Value()));
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00003985 __ movl(out, Address(out, CodeGenerator::GetCacheOffset(load->GetStringIndex())));
3986 __ testl(out, out);
3987 __ j(kEqual, slow_path->GetEntryLabel());
3988 __ Bind(slow_path->GetExitLabel());
3989}
3990
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00003991void LocationsBuilderX86_64::VisitLoadException(HLoadException* load) {
3992 LocationSummary* locations =
3993 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
3994 locations->SetOut(Location::RequiresRegister());
3995}
3996
3997void InstructionCodeGeneratorX86_64::VisitLoadException(HLoadException* load) {
3998 Address address = Address::Absolute(
3999 Thread::ExceptionOffset<kX86_64WordSize>().Int32Value(), true);
Roland Levillain271ab9c2014-11-27 15:23:57 +00004000 __ gs()->movl(load->GetLocations()->Out().AsRegister<CpuRegister>(), address);
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004001 __ gs()->movl(address, Immediate(0));
4002}
4003
4004void LocationsBuilderX86_64::VisitThrow(HThrow* instruction) {
4005 LocationSummary* locations =
4006 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
4007 InvokeRuntimeCallingConvention calling_convention;
4008 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4009}
4010
4011void InstructionCodeGeneratorX86_64::VisitThrow(HThrow* instruction) {
4012 __ gs()->call(
4013 Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pDeliverException), true));
4014 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
4015}
4016
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004017void LocationsBuilderX86_64::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004018 LocationSummary::CallKind call_kind = instruction->IsClassFinal()
4019 ? LocationSummary::kNoCall
4020 : LocationSummary::kCallOnSlowPath;
4021 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
4022 locations->SetInAt(0, Location::RequiresRegister());
4023 locations->SetInAt(1, Location::Any());
4024 locations->SetOut(Location::RequiresRegister());
4025}
4026
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004027void InstructionCodeGeneratorX86_64::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004028 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004029 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004030 Location cls = locations->InAt(1);
Roland Levillain271ab9c2014-11-27 15:23:57 +00004031 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004032 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
4033 Label done, zero;
4034 SlowPathCodeX86_64* slow_path = nullptr;
4035
4036 // Return 0 if `obj` is null.
4037 // TODO: avoid this check if we know obj is not null.
4038 __ testl(obj, obj);
4039 __ j(kEqual, &zero);
4040 // Compare the class of `obj` with `cls`.
4041 __ movl(out, Address(obj, class_offset));
4042 if (cls.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004043 __ cmpl(out, cls.AsRegister<CpuRegister>());
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004044 } else {
4045 DCHECK(cls.IsStackSlot()) << cls;
4046 __ cmpl(out, Address(CpuRegister(RSP), cls.GetStackIndex()));
4047 }
4048 if (instruction->IsClassFinal()) {
4049 // Classes must be equal for the instanceof to succeed.
4050 __ j(kNotEqual, &zero);
4051 __ movl(out, Immediate(1));
4052 __ jmp(&done);
4053 } else {
4054 // If the classes are not equal, we go into a slow path.
4055 DCHECK(locations->OnlyCallsOnSlowPath());
4056 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86_64(
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004057 instruction, locations->InAt(1), locations->Out(), instruction->GetDexPc());
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004058 codegen_->AddSlowPath(slow_path);
4059 __ j(kNotEqual, slow_path->GetEntryLabel());
4060 __ movl(out, Immediate(1));
4061 __ jmp(&done);
4062 }
4063 __ Bind(&zero);
4064 __ movl(out, Immediate(0));
4065 if (slow_path != nullptr) {
4066 __ Bind(slow_path->GetExitLabel());
4067 }
4068 __ Bind(&done);
4069}
4070
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004071void LocationsBuilderX86_64::VisitCheckCast(HCheckCast* instruction) {
4072 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
4073 instruction, LocationSummary::kCallOnSlowPath);
4074 locations->SetInAt(0, Location::RequiresRegister());
4075 locations->SetInAt(1, Location::Any());
4076 locations->AddTemp(Location::RequiresRegister());
4077}
4078
4079void InstructionCodeGeneratorX86_64::VisitCheckCast(HCheckCast* instruction) {
4080 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004081 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004082 Location cls = locations->InAt(1);
Roland Levillain271ab9c2014-11-27 15:23:57 +00004083 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004084 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
4085 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86_64(
4086 instruction, locations->InAt(1), locations->GetTemp(0), instruction->GetDexPc());
4087 codegen_->AddSlowPath(slow_path);
4088
4089 // TODO: avoid this check if we know obj is not null.
4090 __ testl(obj, obj);
4091 __ j(kEqual, slow_path->GetExitLabel());
4092 // Compare the class of `obj` with `cls`.
4093 __ movl(temp, Address(obj, class_offset));
4094 if (cls.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004095 __ cmpl(temp, cls.AsRegister<CpuRegister>());
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004096 } else {
4097 DCHECK(cls.IsStackSlot()) << cls;
4098 __ cmpl(temp, Address(CpuRegister(RSP), cls.GetStackIndex()));
4099 }
4100 // Classes must be equal for the checkcast to succeed.
4101 __ j(kNotEqual, slow_path->GetEntryLabel());
4102 __ Bind(slow_path->GetExitLabel());
4103}
4104
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00004105void LocationsBuilderX86_64::VisitMonitorOperation(HMonitorOperation* instruction) {
4106 LocationSummary* locations =
4107 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
4108 InvokeRuntimeCallingConvention calling_convention;
4109 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4110}
4111
4112void InstructionCodeGeneratorX86_64::VisitMonitorOperation(HMonitorOperation* instruction) {
4113 __ gs()->call(Address::Absolute(instruction->IsEnter()
4114 ? QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pLockObject)
4115 : QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pUnlockObject),
4116 true));
4117 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
4118}
4119
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004120void LocationsBuilderX86_64::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); }
4121void LocationsBuilderX86_64::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); }
4122void LocationsBuilderX86_64::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); }
4123
4124void LocationsBuilderX86_64::HandleBitwiseOperation(HBinaryOperation* instruction) {
4125 LocationSummary* locations =
4126 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
4127 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
4128 || instruction->GetResultType() == Primitive::kPrimLong);
4129 locations->SetInAt(0, Location::RequiresRegister());
4130 if (instruction->GetType() == Primitive::kPrimInt) {
4131 locations->SetInAt(1, Location::Any());
4132 } else {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004133 // We can handle 32 bit constants.
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004134 locations->SetInAt(1, Location::RequiresRegister());
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004135 locations->SetInAt(1, Location::RegisterOrInt32LongConstant(instruction->InputAt(1)));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004136 }
4137 locations->SetOut(Location::SameAsFirstInput());
4138}
4139
4140void InstructionCodeGeneratorX86_64::VisitAnd(HAnd* instruction) {
4141 HandleBitwiseOperation(instruction);
4142}
4143
4144void InstructionCodeGeneratorX86_64::VisitOr(HOr* instruction) {
4145 HandleBitwiseOperation(instruction);
4146}
4147
4148void InstructionCodeGeneratorX86_64::VisitXor(HXor* instruction) {
4149 HandleBitwiseOperation(instruction);
4150}
4151
4152void InstructionCodeGeneratorX86_64::HandleBitwiseOperation(HBinaryOperation* instruction) {
4153 LocationSummary* locations = instruction->GetLocations();
4154 Location first = locations->InAt(0);
4155 Location second = locations->InAt(1);
4156 DCHECK(first.Equals(locations->Out()));
4157
4158 if (instruction->GetResultType() == Primitive::kPrimInt) {
4159 if (second.IsRegister()) {
4160 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004161 __ andl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004162 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004163 __ orl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004164 } else {
4165 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004166 __ xorl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004167 }
4168 } else if (second.IsConstant()) {
4169 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
4170 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004171 __ andl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004172 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004173 __ orl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004174 } else {
4175 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004176 __ xorl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004177 }
4178 } else {
4179 Address address(CpuRegister(RSP), second.GetStackIndex());
4180 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004181 __ andl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004182 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004183 __ orl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004184 } else {
4185 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004186 __ xorl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004187 }
4188 }
4189 } else {
4190 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004191 CpuRegister first_reg = first.AsRegister<CpuRegister>();
4192 bool second_is_constant = false;
4193 int64_t value = 0;
4194 if (second.IsConstant()) {
4195 second_is_constant = true;
4196 value = second.GetConstant()->AsLongConstant()->GetValue();
4197 DCHECK(IsInt<32>(value));
4198 }
4199
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004200 if (instruction->IsAnd()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004201 if (second_is_constant) {
4202 __ andq(first_reg, Immediate(static_cast<int32_t>(value)));
4203 } else {
4204 __ andq(first_reg, second.AsRegister<CpuRegister>());
4205 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004206 } else if (instruction->IsOr()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004207 if (second_is_constant) {
4208 __ orq(first_reg, Immediate(static_cast<int32_t>(value)));
4209 } else {
4210 __ orq(first_reg, second.AsRegister<CpuRegister>());
4211 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004212 } else {
4213 DCHECK(instruction->IsXor());
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004214 if (second_is_constant) {
4215 __ xorq(first_reg, Immediate(static_cast<int32_t>(value)));
4216 } else {
4217 __ xorq(first_reg, second.AsRegister<CpuRegister>());
4218 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004219 }
4220 }
4221}
4222
Calin Juravleb1498f62015-02-16 13:13:29 +00004223void LocationsBuilderX86_64::VisitBoundType(HBoundType* instruction) {
4224 // Nothing to do, this should be removed during prepare for register allocator.
4225 UNUSED(instruction);
4226 LOG(FATAL) << "Unreachable";
4227}
4228
4229void InstructionCodeGeneratorX86_64::VisitBoundType(HBoundType* instruction) {
4230 // Nothing to do, this should be removed during prepare for register allocator.
4231 UNUSED(instruction);
4232 LOG(FATAL) << "Unreachable";
4233}
4234
Mark Mendellf55c3e02015-03-26 21:07:46 -04004235void CodeGeneratorX86_64::Finalize(CodeAllocator* allocator) {
4236 // Generate the constant area if needed.
Mark Mendell39dcf552015-04-09 20:42:42 -04004237 X86_64Assembler* assembler = GetAssembler();
4238 if (!assembler->IsConstantAreaEmpty()) {
Mark Mendellf55c3e02015-03-26 21:07:46 -04004239 // Align to 4 byte boundary to reduce cache misses, as the data is 4 and 8
4240 // byte values. If used for vectors at a later time, this will need to be
4241 // updated to 16 bytes with the appropriate offset.
Mark Mendell39dcf552015-04-09 20:42:42 -04004242 assembler->Align(4, 0);
4243 constant_area_start_ = assembler->CodeSize();
4244 assembler->AddConstantArea();
Mark Mendellf55c3e02015-03-26 21:07:46 -04004245 }
4246
4247 // And finish up.
4248 CodeGenerator::Finalize(allocator);
4249}
4250
4251/**
4252 * Class to handle late fixup of offsets into constant area.
4253 */
4254class RIPFixup : public AssemblerFixup, public ArenaObject<kArenaAllocMisc> {
4255 public:
Mark Mendell39dcf552015-04-09 20:42:42 -04004256 RIPFixup(const CodeGeneratorX86_64& codegen, int offset)
Mark Mendellf55c3e02015-03-26 21:07:46 -04004257 : codegen_(codegen), offset_into_constant_area_(offset) {}
4258
4259 private:
4260 void Process(const MemoryRegion& region, int pos) OVERRIDE {
4261 // Patch the correct offset for the instruction. We use the address of the
4262 // 'next' instruction, which is 'pos' (patch the 4 bytes before).
4263 int constant_offset = codegen_.ConstantAreaStart() + offset_into_constant_area_;
4264 int relative_position = constant_offset - pos;
4265
4266 // Patch in the right value.
4267 region.StoreUnaligned<int32_t>(pos - 4, relative_position);
4268 }
4269
Mark Mendell39dcf552015-04-09 20:42:42 -04004270 const CodeGeneratorX86_64& codegen_;
Mark Mendellf55c3e02015-03-26 21:07:46 -04004271
4272 // Location in constant area that the fixup refers to.
4273 int offset_into_constant_area_;
4274};
4275
4276Address CodeGeneratorX86_64::LiteralDoubleAddress(double v) {
4277 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddDouble(v));
4278 return Address::RIP(fixup);
4279}
4280
4281Address CodeGeneratorX86_64::LiteralFloatAddress(float v) {
4282 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddFloat(v));
4283 return Address::RIP(fixup);
4284}
4285
4286Address CodeGeneratorX86_64::LiteralInt32Address(int32_t v) {
4287 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddInt32(v));
4288 return Address::RIP(fixup);
4289}
4290
4291Address CodeGeneratorX86_64::LiteralInt64Address(int64_t v) {
4292 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddInt64(v));
4293 return Address::RIP(fixup);
4294}
4295
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004296} // namespace x86_64
4297} // namespace art