blob: f49c26db2be09772dde6ad3b1d636a57b99285dc [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 {
Mark Mendell92e83bf2015-05-07 11:25:03 -0400102 __ xorl(cpu_reg_, cpu_reg_);
Calin Juravlebacfec32014-11-14 15:54:36 +0000103 }
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
Nicolas Geoffraydb216f42015-05-05 17:02:20 +0100139 HBasicBlock* GetSuccessor() const {
140 return successor_;
141 }
142
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000143 private:
144 HSuspendCheck* const instruction_;
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100145 HBasicBlock* const successor_;
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000146 Label return_label_;
147
148 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathX86_64);
149};
150
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100151class BoundsCheckSlowPathX86_64 : public SlowPathCodeX86_64 {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100152 public:
Roland Levillain5799fc02014-09-25 12:15:20 +0100153 BoundsCheckSlowPathX86_64(HBoundsCheck* instruction,
154 Location index_location,
155 Location length_location)
Nicolas Geoffray39468442014-09-02 15:17:15 +0100156 : instruction_(instruction),
157 index_location_(index_location),
158 length_location_(length_location) {}
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100159
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000160 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100161 __ Bind(GetEntryLabel());
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000162 // We're moving two locations to locations that could overlap, so we need a parallel
163 // move resolver.
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100164 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000165 codegen->EmitParallelMoves(
166 index_location_,
167 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100168 Primitive::kPrimInt,
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000169 length_location_,
Nicolas Geoffray90218252015-04-15 11:56:51 +0100170 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
171 Primitive::kPrimInt);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100172 __ gs()->call(Address::Absolute(
173 QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pThrowArrayBounds), true));
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000174 RecordPcInfo(codegen, instruction_, instruction_->GetDexPc());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100175 }
176
177 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100178 HBoundsCheck* const instruction_;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100179 const Location index_location_;
180 const Location length_location_;
181
182 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathX86_64);
183};
184
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000185class LoadClassSlowPathX86_64 : public SlowPathCodeX86_64 {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100186 public:
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000187 LoadClassSlowPathX86_64(HLoadClass* cls,
188 HInstruction* at,
189 uint32_t dex_pc,
190 bool do_clinit)
191 : cls_(cls), at_(at), dex_pc_(dex_pc), do_clinit_(do_clinit) {
192 DCHECK(at->IsLoadClass() || at->IsClinitCheck());
193 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100194
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000195 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000196 LocationSummary* locations = at_->GetLocations();
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100197 CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
198 __ Bind(GetEntryLabel());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100199
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000200 SaveLiveRegisters(codegen, locations);
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000201
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100202 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000203 __ movl(CpuRegister(calling_convention.GetRegisterAt(0)), Immediate(cls_->GetTypeIndex()));
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000204 __ gs()->call(Address::Absolute((do_clinit_
205 ? QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pInitializeStaticStorage)
206 : QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pInitializeType)) , true));
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000207 RecordPcInfo(codegen, at_, dex_pc_);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100208
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000209 Location out = locations->Out();
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000210 // Move the class to the desired location.
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000211 if (out.IsValid()) {
212 DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
213 x64_codegen->Move(out, Location::RegisterLocation(RAX));
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000214 }
215
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000216 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100217 __ jmp(GetExitLabel());
218 }
219
220 private:
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000221 // The class this slow path will load.
222 HLoadClass* const cls_;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100223
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000224 // The instruction where this slow path is happening.
225 // (Might be the load class or an initialization check).
226 HInstruction* const at_;
227
228 // The dex PC of `at_`.
229 const uint32_t dex_pc_;
230
231 // Whether to initialize the class.
232 const bool do_clinit_;
233
234 DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathX86_64);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100235};
236
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000237class LoadStringSlowPathX86_64 : public SlowPathCodeX86_64 {
238 public:
239 explicit LoadStringSlowPathX86_64(HLoadString* instruction) : instruction_(instruction) {}
240
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000241 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000242 LocationSummary* locations = instruction_->GetLocations();
243 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
244
245 CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
246 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000247 SaveLiveRegisters(codegen, locations);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000248
249 InvokeRuntimeCallingConvention calling_convention;
Andreas Gampe1cc7dba2014-12-17 18:43:01 -0800250 __ movl(CpuRegister(calling_convention.GetRegisterAt(0)),
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000251 Immediate(instruction_->GetStringIndex()));
252 __ gs()->call(Address::Absolute(
253 QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pResolveString), true));
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000254 RecordPcInfo(codegen, instruction_, instruction_->GetDexPc());
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000255 x64_codegen->Move(locations->Out(), Location::RegisterLocation(RAX));
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000256 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000257 __ jmp(GetExitLabel());
258 }
259
260 private:
261 HLoadString* const instruction_;
262
263 DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathX86_64);
264};
265
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000266class TypeCheckSlowPathX86_64 : public SlowPathCodeX86_64 {
267 public:
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000268 TypeCheckSlowPathX86_64(HInstruction* instruction,
269 Location class_to_check,
270 Location object_class,
271 uint32_t dex_pc)
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000272 : instruction_(instruction),
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000273 class_to_check_(class_to_check),
274 object_class_(object_class),
275 dex_pc_(dex_pc) {}
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000276
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000277 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000278 LocationSummary* locations = instruction_->GetLocations();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000279 DCHECK(instruction_->IsCheckCast()
280 || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000281
282 CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
283 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000284 SaveLiveRegisters(codegen, locations);
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000285
286 // We're moving two locations to locations that could overlap, so we need a parallel
287 // move resolver.
288 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000289 codegen->EmitParallelMoves(
290 class_to_check_,
291 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100292 Primitive::kPrimNot,
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000293 object_class_,
Nicolas Geoffray90218252015-04-15 11:56:51 +0100294 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
295 Primitive::kPrimNot);
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000296
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000297 if (instruction_->IsInstanceOf()) {
298 __ gs()->call(
299 Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pInstanceofNonTrivial), true));
300 } else {
301 DCHECK(instruction_->IsCheckCast());
302 __ gs()->call(
303 Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pCheckCast), true));
304 }
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000305 RecordPcInfo(codegen, instruction_, dex_pc_);
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000306
307 if (instruction_->IsInstanceOf()) {
308 x64_codegen->Move(locations->Out(), Location::RegisterLocation(RAX));
309 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000310
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000311 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000312 __ jmp(GetExitLabel());
313 }
314
315 private:
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000316 HInstruction* const instruction_;
317 const Location class_to_check_;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000318 const Location object_class_;
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000319 const uint32_t dex_pc_;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000320
321 DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathX86_64);
322};
323
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700324class DeoptimizationSlowPathX86_64 : public SlowPathCodeX86_64 {
325 public:
326 explicit DeoptimizationSlowPathX86_64(HInstruction* instruction)
327 : instruction_(instruction) {}
328
329 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
330 __ Bind(GetEntryLabel());
331 SaveLiveRegisters(codegen, instruction_->GetLocations());
332 __ gs()->call(
333 Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pDeoptimize), true));
334 DCHECK(instruction_->IsDeoptimize());
335 HDeoptimize* deoptimize = instruction_->AsDeoptimize();
336 uint32_t dex_pc = deoptimize->GetDexPc();
337 codegen->RecordPcInfo(instruction_, dex_pc, this);
338 }
339
340 private:
341 HInstruction* const instruction_;
342 DISALLOW_COPY_AND_ASSIGN(DeoptimizationSlowPathX86_64);
343};
344
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100345#undef __
346#define __ reinterpret_cast<X86_64Assembler*>(GetAssembler())->
347
Dave Allison20dfc792014-06-16 20:44:29 -0700348inline Condition X86_64Condition(IfCondition cond) {
349 switch (cond) {
350 case kCondEQ: return kEqual;
351 case kCondNE: return kNotEqual;
352 case kCondLT: return kLess;
353 case kCondLE: return kLessEqual;
354 case kCondGT: return kGreater;
355 case kCondGE: return kGreaterEqual;
356 default:
357 LOG(FATAL) << "Unknown if condition";
358 }
359 return kEqual;
360}
361
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800362void CodeGeneratorX86_64::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke,
363 CpuRegister temp) {
364 // All registers are assumed to be correctly set up.
365
366 // TODO: Implement all kinds of calls:
367 // 1) boot -> boot
368 // 2) app -> boot
369 // 3) app -> app
370 //
371 // Currently we implement the app -> app logic, which looks up in the resolve cache.
372
Jeff Hao848f70a2014-01-15 13:49:50 -0800373 if (invoke->IsStringInit()) {
374 // temp = thread->string_init_entrypoint
375 __ gs()->movl(temp, Address::Absolute(invoke->GetStringInitOffset()));
Nicolas Geoffray1cf95282014-12-12 19:22:03 +0000376 // (temp + offset_of_quick_compiled_code)()
377 __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(
378 kX86_64WordSize).SizeValue()));
379 } else {
Jeff Hao848f70a2014-01-15 13:49:50 -0800380 // temp = method;
381 LoadCurrentMethod(temp);
382 if (!invoke->IsRecursive()) {
383 // temp = temp->dex_cache_resolved_methods_;
384 __ movl(temp, Address(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().SizeValue()));
385 // temp = temp[index_in_cache]
386 __ movl(temp, Address(temp, CodeGenerator::GetCacheOffset(invoke->GetDexMethodIndex())));
387 // (temp + offset_of_quick_compiled_code)()
388 __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(
389 kX86_64WordSize).SizeValue()));
390 } else {
391 __ call(&frame_entry_label_);
392 }
Nicolas Geoffray1cf95282014-12-12 19:22:03 +0000393 }
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800394
395 DCHECK(!IsLeafMethod());
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800396}
397
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100398void CodeGeneratorX86_64::DumpCoreRegister(std::ostream& stream, int reg) const {
David Brazdilc74652862015-05-13 17:50:09 +0100399 stream << Register(reg);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100400}
401
402void CodeGeneratorX86_64::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
David Brazdilc74652862015-05-13 17:50:09 +0100403 stream << FloatRegister(reg);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100404}
405
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100406size_t CodeGeneratorX86_64::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
407 __ movq(Address(CpuRegister(RSP), stack_index), CpuRegister(reg_id));
408 return kX86_64WordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100409}
410
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100411size_t CodeGeneratorX86_64::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
412 __ movq(CpuRegister(reg_id), Address(CpuRegister(RSP), stack_index));
413 return kX86_64WordSize;
414}
415
416size_t CodeGeneratorX86_64::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
417 __ movsd(Address(CpuRegister(RSP), stack_index), XmmRegister(reg_id));
418 return kX86_64WordSize;
419}
420
421size_t CodeGeneratorX86_64::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
422 __ movsd(XmmRegister(reg_id), Address(CpuRegister(RSP), stack_index));
423 return kX86_64WordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100424}
425
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000426static constexpr int kNumberOfCpuRegisterPairs = 0;
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +0000427// Use a fake return address register to mimic Quick.
428static constexpr Register kFakeReturnRegister = Register(kLastCpuRegister + 1);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400429CodeGeneratorX86_64::CodeGeneratorX86_64(HGraph* graph,
430 const X86_64InstructionSetFeatures& isa_features,
431 const CompilerOptions& compiler_options)
Nicolas Geoffray98893962015-01-21 12:32:32 +0000432 : CodeGenerator(graph,
433 kNumberOfCpuRegisters,
434 kNumberOfFloatRegisters,
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000435 kNumberOfCpuRegisterPairs,
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000436 ComputeRegisterMask(reinterpret_cast<const int*>(kCoreCalleeSaves),
437 arraysize(kCoreCalleeSaves))
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +0000438 | (1 << kFakeReturnRegister),
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000439 ComputeRegisterMask(reinterpret_cast<const int*>(kFpuCalleeSaves),
440 arraysize(kFpuCalleeSaves)),
Nicolas Geoffray98893962015-01-21 12:32:32 +0000441 compiler_options),
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100442 block_labels_(graph->GetArena(), 0),
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100443 location_builder_(graph, this),
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000444 instruction_visitor_(graph, this),
Mark Mendellfb8d2792015-03-31 22:16:59 -0400445 move_resolver_(graph->GetArena(), this),
Mark Mendellf55c3e02015-03-26 21:07:46 -0400446 isa_features_(isa_features),
447 constant_area_start_(0) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000448 AddAllocatedRegister(Location::RegisterLocation(kFakeReturnRegister));
449}
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100450
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100451InstructionCodeGeneratorX86_64::InstructionCodeGeneratorX86_64(HGraph* graph,
452 CodeGeneratorX86_64* codegen)
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100453 : HGraphVisitor(graph),
454 assembler_(codegen->GetAssembler()),
455 codegen_(codegen) {}
456
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100457Location CodeGeneratorX86_64::AllocateFreeRegister(Primitive::Type type) const {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100458 switch (type) {
459 case Primitive::kPrimLong:
460 case Primitive::kPrimByte:
461 case Primitive::kPrimBoolean:
462 case Primitive::kPrimChar:
463 case Primitive::kPrimShort:
464 case Primitive::kPrimInt:
465 case Primitive::kPrimNot: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100466 size_t reg = FindFreeEntry(blocked_core_registers_, kNumberOfCpuRegisters);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100467 return Location::RegisterLocation(reg);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100468 }
469
470 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100471 case Primitive::kPrimDouble: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100472 size_t reg = FindFreeEntry(blocked_fpu_registers_, kNumberOfFloatRegisters);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100473 return Location::FpuRegisterLocation(reg);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100474 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100475
476 case Primitive::kPrimVoid:
477 LOG(FATAL) << "Unreachable type " << type;
478 }
479
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100480 return Location();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100481}
482
Nicolas Geoffray98893962015-01-21 12:32:32 +0000483void CodeGeneratorX86_64::SetupBlockedRegisters(bool is_baseline) const {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100484 // Stack register is always reserved.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100485 blocked_core_registers_[RSP] = true;
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100486
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000487 // Block the register used as TMP.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100488 blocked_core_registers_[TMP] = true;
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000489
Nicolas Geoffray98893962015-01-21 12:32:32 +0000490 if (is_baseline) {
491 for (size_t i = 0; i < arraysize(kCoreCalleeSaves); ++i) {
492 blocked_core_registers_[kCoreCalleeSaves[i]] = true;
493 }
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000494 for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
495 blocked_fpu_registers_[kFpuCalleeSaves[i]] = true;
496 }
Nicolas Geoffray98893962015-01-21 12:32:32 +0000497 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100498}
499
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100500static dwarf::Reg DWARFReg(Register reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +0100501 return dwarf::Reg::X86_64Core(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100502}
David Srbecky9d8606d2015-04-12 09:35:32 +0100503
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100504static dwarf::Reg DWARFReg(FloatRegister reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +0100505 return dwarf::Reg::X86_64Fp(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100506}
507
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100508void CodeGeneratorX86_64::GenerateFrameEntry() {
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100509 __ cfi().SetCurrentCFAOffset(kX86_64WordSize); // return address
Nicolas Geoffray1cf95282014-12-12 19:22:03 +0000510 __ Bind(&frame_entry_label_);
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100511 bool skip_overflow_check = IsLeafMethod()
Dave Allison648d7112014-07-25 16:15:27 -0700512 && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kX86_64);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000513 DCHECK(GetCompilerOptions().GetImplicitStackOverflowChecks());
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100514
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000515 if (!skip_overflow_check) {
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100516 __ testq(CpuRegister(RAX), Address(
517 CpuRegister(RSP), -static_cast<int32_t>(GetStackOverflowReservedBytes(kX86_64))));
Nicolas Geoffray39468442014-09-02 15:17:15 +0100518 RecordPcInfo(nullptr, 0);
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100519 }
Nicolas Geoffraya26369a2015-01-22 08:46:05 +0000520
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000521 if (HasEmptyFrame()) {
522 return;
523 }
524
Nicolas Geoffray98893962015-01-21 12:32:32 +0000525 for (int i = arraysize(kCoreCalleeSaves) - 1; i >= 0; --i) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000526 Register reg = kCoreCalleeSaves[i];
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +0000527 if (allocated_registers_.ContainsCoreRegister(reg)) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000528 __ pushq(CpuRegister(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100529 __ cfi().AdjustCFAOffset(kX86_64WordSize);
530 __ cfi().RelOffset(DWARFReg(reg), 0);
Nicolas Geoffray98893962015-01-21 12:32:32 +0000531 }
532 }
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100533
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100534 int adjust = GetFrameSize() - GetCoreSpillSize();
535 __ subq(CpuRegister(RSP), Immediate(adjust));
536 __ cfi().AdjustCFAOffset(adjust);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000537 uint32_t xmm_spill_location = GetFpuSpillStart();
538 size_t xmm_spill_slot_size = GetFloatingPointSpillSlotSize();
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100539
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000540 for (int i = arraysize(kFpuCalleeSaves) - 1; i >= 0; --i) {
541 if (allocated_registers_.ContainsFloatingPointRegister(kFpuCalleeSaves[i])) {
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100542 int offset = xmm_spill_location + (xmm_spill_slot_size * i);
543 __ movsd(Address(CpuRegister(RSP), offset), XmmRegister(kFpuCalleeSaves[i]));
544 __ cfi().RelOffset(DWARFReg(kFpuCalleeSaves[i]), offset);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000545 }
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100546 }
547
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100548 __ movl(Address(CpuRegister(RSP), kCurrentMethodStackOffset), CpuRegister(RDI));
549}
550
551void CodeGeneratorX86_64::GenerateFrameExit() {
David Srbeckyc34dc932015-04-12 09:27:43 +0100552 __ cfi().RememberState();
553 if (!HasEmptyFrame()) {
554 uint32_t xmm_spill_location = GetFpuSpillStart();
555 size_t xmm_spill_slot_size = GetFloatingPointSpillSlotSize();
556 for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
557 if (allocated_registers_.ContainsFloatingPointRegister(kFpuCalleeSaves[i])) {
558 int offset = xmm_spill_location + (xmm_spill_slot_size * i);
559 __ movsd(XmmRegister(kFpuCalleeSaves[i]), Address(CpuRegister(RSP), offset));
560 __ cfi().Restore(DWARFReg(kFpuCalleeSaves[i]));
561 }
562 }
563
564 int adjust = GetFrameSize() - GetCoreSpillSize();
565 __ addq(CpuRegister(RSP), Immediate(adjust));
566 __ cfi().AdjustCFAOffset(-adjust);
567
568 for (size_t i = 0; i < arraysize(kCoreCalleeSaves); ++i) {
569 Register reg = kCoreCalleeSaves[i];
570 if (allocated_registers_.ContainsCoreRegister(reg)) {
571 __ popq(CpuRegister(reg));
572 __ cfi().AdjustCFAOffset(-static_cast<int>(kX86_64WordSize));
573 __ cfi().Restore(DWARFReg(reg));
574 }
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000575 }
576 }
David Srbeckyc34dc932015-04-12 09:27:43 +0100577 __ ret();
578 __ cfi().RestoreState();
579 __ cfi().DefCFAOffset(GetFrameSize());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100580}
581
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100582void CodeGeneratorX86_64::Bind(HBasicBlock* block) {
583 __ Bind(GetLabelOf(block));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100584}
585
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100586void CodeGeneratorX86_64::LoadCurrentMethod(CpuRegister reg) {
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000587 DCHECK(RequiresCurrentMethod());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100588 __ movl(reg, Address(CpuRegister(RSP), kCurrentMethodStackOffset));
589}
590
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100591Location CodeGeneratorX86_64::GetStackLocation(HLoadLocal* load) const {
592 switch (load->GetType()) {
593 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100594 case Primitive::kPrimDouble:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100595 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100596
597 case Primitive::kPrimInt:
598 case Primitive::kPrimNot:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100599 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100600 return Location::StackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100601
602 case Primitive::kPrimBoolean:
603 case Primitive::kPrimByte:
604 case Primitive::kPrimChar:
605 case Primitive::kPrimShort:
606 case Primitive::kPrimVoid:
607 LOG(FATAL) << "Unexpected type " << load->GetType();
Andreas Gampe65b798e2015-04-06 09:35:22 -0700608 UNREACHABLE();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100609 }
610
611 LOG(FATAL) << "Unreachable";
Andreas Gampe65b798e2015-04-06 09:35:22 -0700612 UNREACHABLE();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100613}
614
615void CodeGeneratorX86_64::Move(Location destination, Location source) {
616 if (source.Equals(destination)) {
617 return;
618 }
619 if (destination.IsRegister()) {
620 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000621 __ movq(destination.AsRegister<CpuRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100622 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000623 __ movd(destination.AsRegister<CpuRegister>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100624 } else if (source.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000625 __ movl(destination.AsRegister<CpuRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100626 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100627 } else {
628 DCHECK(source.IsDoubleStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +0000629 __ movq(destination.AsRegister<CpuRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100630 Address(CpuRegister(RSP), source.GetStackIndex()));
631 }
632 } else if (destination.IsFpuRegister()) {
633 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000634 __ movd(destination.AsFpuRegister<XmmRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100635 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000636 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100637 } else if (source.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000638 __ movss(destination.AsFpuRegister<XmmRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100639 Address(CpuRegister(RSP), source.GetStackIndex()));
640 } else {
641 DCHECK(source.IsDoubleStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +0000642 __ movsd(destination.AsFpuRegister<XmmRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100643 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100644 }
645 } else if (destination.IsStackSlot()) {
646 if (source.IsRegister()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100647 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +0000648 source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100649 } else if (source.IsFpuRegister()) {
650 __ movss(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +0000651 source.AsFpuRegister<XmmRegister>());
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500652 } else if (source.IsConstant()) {
653 HConstant* constant = source.GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000654 int32_t value = GetInt32ValueOf(constant);
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500655 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), Immediate(value));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100656 } else {
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500657 DCHECK(source.IsStackSlot()) << source;
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000658 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
659 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100660 }
661 } else {
662 DCHECK(destination.IsDoubleStackSlot());
663 if (source.IsRegister()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100664 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +0000665 source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100666 } else if (source.IsFpuRegister()) {
667 __ movsd(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +0000668 source.AsFpuRegister<XmmRegister>());
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500669 } else if (source.IsConstant()) {
670 HConstant* constant = source.GetConstant();
Zheng Xu12bca972015-03-30 19:35:50 +0800671 int64_t value;
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500672 if (constant->IsDoubleConstant()) {
Roland Levillainda4d79b2015-03-24 14:36:11 +0000673 value = bit_cast<int64_t, double>(constant->AsDoubleConstant()->GetValue());
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500674 } else {
675 DCHECK(constant->IsLongConstant());
676 value = constant->AsLongConstant()->GetValue();
677 }
Mark Mendell92e83bf2015-05-07 11:25:03 -0400678 Load64BitValue(CpuRegister(TMP), value);
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500679 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100680 } else {
681 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000682 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
683 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100684 }
685 }
686}
687
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100688void CodeGeneratorX86_64::Move(HInstruction* instruction,
689 Location location,
690 HInstruction* move_for) {
Calin Juravlea21f5982014-11-13 15:53:04 +0000691 LocationSummary* locations = instruction->GetLocations();
692 if (locations != nullptr && locations->Out().Equals(location)) {
693 return;
694 }
695
696 if (locations != nullptr && locations->Out().IsConstant()) {
697 HConstant* const_to_move = locations->Out().GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000698 if (const_to_move->IsIntConstant() || const_to_move->IsNullConstant()) {
699 Immediate imm(GetInt32ValueOf(const_to_move));
Calin Juravlea21f5982014-11-13 15:53:04 +0000700 if (location.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000701 __ movl(location.AsRegister<CpuRegister>(), imm);
Calin Juravlea21f5982014-11-13 15:53:04 +0000702 } else if (location.IsStackSlot()) {
703 __ movl(Address(CpuRegister(RSP), location.GetStackIndex()), imm);
704 } else {
705 DCHECK(location.IsConstant());
706 DCHECK_EQ(location.GetConstant(), const_to_move);
707 }
708 } else if (const_to_move->IsLongConstant()) {
709 int64_t value = const_to_move->AsLongConstant()->GetValue();
710 if (location.IsRegister()) {
Mark Mendell92e83bf2015-05-07 11:25:03 -0400711 Load64BitValue(location.AsRegister<CpuRegister>(), value);
Calin Juravlea21f5982014-11-13 15:53:04 +0000712 } else if (location.IsDoubleStackSlot()) {
Mark Mendell92e83bf2015-05-07 11:25:03 -0400713 Load64BitValue(CpuRegister(TMP), value);
Calin Juravlea21f5982014-11-13 15:53:04 +0000714 __ movq(Address(CpuRegister(RSP), location.GetStackIndex()), CpuRegister(TMP));
715 } else {
716 DCHECK(location.IsConstant());
717 DCHECK_EQ(location.GetConstant(), const_to_move);
718 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100719 }
Roland Levillain476df552014-10-09 17:51:36 +0100720 } else if (instruction->IsLoadLocal()) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100721 switch (instruction->GetType()) {
722 case Primitive::kPrimBoolean:
723 case Primitive::kPrimByte:
724 case Primitive::kPrimChar:
725 case Primitive::kPrimShort:
726 case Primitive::kPrimInt:
727 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100728 case Primitive::kPrimFloat:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100729 Move(location, Location::StackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
730 break;
731
732 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100733 case Primitive::kPrimDouble:
Roland Levillain199f3362014-11-27 17:15:16 +0000734 Move(location,
735 Location::DoubleStackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100736 break;
737
738 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100739 LOG(FATAL) << "Unexpected local type " << instruction->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100740 }
Nicolas Geoffrayf43083d2014-11-07 10:48:10 +0000741 } else if (instruction->IsTemporary()) {
742 Location temp_location = GetTemporaryLocation(instruction->AsTemporary());
743 Move(location, temp_location);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100744 } else {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100745 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100746 switch (instruction->GetType()) {
747 case Primitive::kPrimBoolean:
748 case Primitive::kPrimByte:
749 case Primitive::kPrimChar:
750 case Primitive::kPrimShort:
751 case Primitive::kPrimInt:
752 case Primitive::kPrimNot:
753 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100754 case Primitive::kPrimFloat:
755 case Primitive::kPrimDouble:
Calin Juravlea21f5982014-11-13 15:53:04 +0000756 Move(location, locations->Out());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100757 break;
758
759 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100760 LOG(FATAL) << "Unexpected type " << instruction->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100761 }
762 }
763}
764
765void LocationsBuilderX86_64::VisitGoto(HGoto* got) {
766 got->SetLocations(nullptr);
767}
768
769void InstructionCodeGeneratorX86_64::VisitGoto(HGoto* got) {
770 HBasicBlock* successor = got->GetSuccessor();
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100771 DCHECK(!successor->IsExitBlock());
772
773 HBasicBlock* block = got->GetBlock();
774 HInstruction* previous = got->GetPrevious();
775
776 HLoopInformation* info = block->GetLoopInformation();
David Brazdil46e2a392015-03-16 17:31:52 +0000777 if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100778 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
779 return;
780 }
781
782 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
783 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
784 }
785 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100786 __ jmp(codegen_->GetLabelOf(successor));
787 }
788}
789
790void LocationsBuilderX86_64::VisitExit(HExit* exit) {
791 exit->SetLocations(nullptr);
792}
793
794void InstructionCodeGeneratorX86_64::VisitExit(HExit* exit) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700795 UNUSED(exit);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100796}
797
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700798void InstructionCodeGeneratorX86_64::GenerateTestAndBranch(HInstruction* instruction,
799 Label* true_target,
800 Label* false_target,
801 Label* always_true_target) {
802 HInstruction* cond = instruction->InputAt(0);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100803 if (cond->IsIntConstant()) {
804 // Constant condition, statically compared against 1.
805 int32_t cond_value = cond->AsIntConstant()->GetValue();
806 if (cond_value == 1) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700807 if (always_true_target != nullptr) {
808 __ jmp(always_true_target);
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100809 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100810 return;
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100811 } else {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100812 DCHECK_EQ(cond_value, 0);
813 }
814 } else {
815 bool materialized =
816 !cond->IsCondition() || cond->AsCondition()->NeedsMaterialization();
817 // Moves do not affect the eflags register, so if the condition is
818 // evaluated just before the if, we don't need to evaluate it
819 // again.
820 bool eflags_set = cond->IsCondition()
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700821 && cond->AsCondition()->IsBeforeWhenDisregardMoves(instruction);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100822 if (materialized) {
823 if (!eflags_set) {
824 // Materialized condition, compare against 0.
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700825 Location lhs = instruction->GetLocations()->InAt(0);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100826 if (lhs.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +0000827 __ testl(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>());
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100828 } else {
829 __ cmpl(Address(CpuRegister(RSP), lhs.GetStackIndex()),
830 Immediate(0));
831 }
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700832 __ j(kNotEqual, true_target);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100833 } else {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700834 __ j(X86_64Condition(cond->AsCondition()->GetCondition()), true_target);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100835 }
836 } else {
837 Location lhs = cond->GetLocations()->InAt(0);
838 Location rhs = cond->GetLocations()->InAt(1);
839 if (rhs.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000840 __ cmpl(lhs.AsRegister<CpuRegister>(), rhs.AsRegister<CpuRegister>());
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100841 } else if (rhs.IsConstant()) {
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000842 int32_t constant = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
Nicolas Geoffray748f1402015-01-27 08:17:54 +0000843 if (constant == 0) {
844 __ testl(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>());
845 } else {
846 __ cmpl(lhs.AsRegister<CpuRegister>(), Immediate(constant));
847 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100848 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000849 __ cmpl(lhs.AsRegister<CpuRegister>(),
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100850 Address(CpuRegister(RSP), rhs.GetStackIndex()));
851 }
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700852 __ j(X86_64Condition(cond->AsCondition()->GetCondition()), true_target);
Dave Allison20dfc792014-06-16 20:44:29 -0700853 }
Dave Allison20dfc792014-06-16 20:44:29 -0700854 }
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700855 if (false_target != nullptr) {
856 __ jmp(false_target);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100857 }
858}
859
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700860void LocationsBuilderX86_64::VisitIf(HIf* if_instr) {
861 LocationSummary* locations =
862 new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall);
863 HInstruction* cond = if_instr->InputAt(0);
864 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
865 locations->SetInAt(0, Location::Any());
866 }
867}
868
869void InstructionCodeGeneratorX86_64::VisitIf(HIf* if_instr) {
870 Label* true_target = codegen_->GetLabelOf(if_instr->IfTrueSuccessor());
871 Label* false_target = codegen_->GetLabelOf(if_instr->IfFalseSuccessor());
872 Label* always_true_target = true_target;
873 if (codegen_->GoesToNextBlock(if_instr->GetBlock(),
874 if_instr->IfTrueSuccessor())) {
875 always_true_target = nullptr;
876 }
877 if (codegen_->GoesToNextBlock(if_instr->GetBlock(),
878 if_instr->IfFalseSuccessor())) {
879 false_target = nullptr;
880 }
881 GenerateTestAndBranch(if_instr, true_target, false_target, always_true_target);
882}
883
884void LocationsBuilderX86_64::VisitDeoptimize(HDeoptimize* deoptimize) {
885 LocationSummary* locations = new (GetGraph()->GetArena())
886 LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
887 HInstruction* cond = deoptimize->InputAt(0);
888 DCHECK(cond->IsCondition());
889 if (cond->AsCondition()->NeedsMaterialization()) {
890 locations->SetInAt(0, Location::Any());
891 }
892}
893
894void InstructionCodeGeneratorX86_64::VisitDeoptimize(HDeoptimize* deoptimize) {
895 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena())
896 DeoptimizationSlowPathX86_64(deoptimize);
897 codegen_->AddSlowPath(slow_path);
898 Label* slow_path_entry = slow_path->GetEntryLabel();
899 GenerateTestAndBranch(deoptimize, slow_path_entry, nullptr, slow_path_entry);
900}
901
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100902void LocationsBuilderX86_64::VisitLocal(HLocal* local) {
903 local->SetLocations(nullptr);
904}
905
906void InstructionCodeGeneratorX86_64::VisitLocal(HLocal* local) {
907 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
908}
909
910void LocationsBuilderX86_64::VisitLoadLocal(HLoadLocal* local) {
911 local->SetLocations(nullptr);
912}
913
914void InstructionCodeGeneratorX86_64::VisitLoadLocal(HLoadLocal* load) {
915 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700916 UNUSED(load);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100917}
918
919void LocationsBuilderX86_64::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100920 LocationSummary* locations =
921 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100922 switch (store->InputAt(1)->GetType()) {
923 case Primitive::kPrimBoolean:
924 case Primitive::kPrimByte:
925 case Primitive::kPrimChar:
926 case Primitive::kPrimShort:
927 case Primitive::kPrimInt:
928 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100929 case Primitive::kPrimFloat:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100930 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
931 break;
932
933 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100934 case Primitive::kPrimDouble:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100935 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
936 break;
937
938 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100939 LOG(FATAL) << "Unexpected local type " << store->InputAt(1)->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100940 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100941}
942
943void InstructionCodeGeneratorX86_64::VisitStoreLocal(HStoreLocal* store) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700944 UNUSED(store);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100945}
946
Dave Allison20dfc792014-06-16 20:44:29 -0700947void LocationsBuilderX86_64::VisitCondition(HCondition* comp) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100948 LocationSummary* locations =
949 new (GetGraph()->GetArena()) LocationSummary(comp, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +0100950 locations->SetInAt(0, Location::RequiresRegister());
951 locations->SetInAt(1, Location::Any());
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100952 if (comp->NeedsMaterialization()) {
953 locations->SetOut(Location::RequiresRegister());
954 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100955}
956
Dave Allison20dfc792014-06-16 20:44:29 -0700957void InstructionCodeGeneratorX86_64::VisitCondition(HCondition* comp) {
958 if (comp->NeedsMaterialization()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100959 LocationSummary* locations = comp->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +0000960 CpuRegister reg = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100961 // Clear register: setcc only sets the low byte.
Mark Mendell92e83bf2015-05-07 11:25:03 -0400962 __ xorl(reg, reg);
Nicolas Geoffray748f1402015-01-27 08:17:54 +0000963 Location lhs = locations->InAt(0);
964 Location rhs = locations->InAt(1);
965 if (rhs.IsRegister()) {
966 __ cmpl(lhs.AsRegister<CpuRegister>(), rhs.AsRegister<CpuRegister>());
967 } else if (rhs.IsConstant()) {
Mingyao Yangdc5ac732015-02-25 11:28:05 -0800968 int32_t constant = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
Nicolas Geoffray748f1402015-01-27 08:17:54 +0000969 if (constant == 0) {
970 __ testl(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>());
971 } else {
972 __ cmpl(lhs.AsRegister<CpuRegister>(), Immediate(constant));
973 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100974 } else {
Nicolas Geoffray748f1402015-01-27 08:17:54 +0000975 __ cmpl(lhs.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), rhs.GetStackIndex()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100976 }
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100977 __ setcc(X86_64Condition(comp->GetCondition()), reg);
Dave Allison20dfc792014-06-16 20:44:29 -0700978 }
979}
980
981void LocationsBuilderX86_64::VisitEqual(HEqual* comp) {
982 VisitCondition(comp);
983}
984
985void InstructionCodeGeneratorX86_64::VisitEqual(HEqual* comp) {
986 VisitCondition(comp);
987}
988
989void LocationsBuilderX86_64::VisitNotEqual(HNotEqual* comp) {
990 VisitCondition(comp);
991}
992
993void InstructionCodeGeneratorX86_64::VisitNotEqual(HNotEqual* comp) {
994 VisitCondition(comp);
995}
996
997void LocationsBuilderX86_64::VisitLessThan(HLessThan* comp) {
998 VisitCondition(comp);
999}
1000
1001void InstructionCodeGeneratorX86_64::VisitLessThan(HLessThan* comp) {
1002 VisitCondition(comp);
1003}
1004
1005void LocationsBuilderX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1006 VisitCondition(comp);
1007}
1008
1009void InstructionCodeGeneratorX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1010 VisitCondition(comp);
1011}
1012
1013void LocationsBuilderX86_64::VisitGreaterThan(HGreaterThan* comp) {
1014 VisitCondition(comp);
1015}
1016
1017void InstructionCodeGeneratorX86_64::VisitGreaterThan(HGreaterThan* comp) {
1018 VisitCondition(comp);
1019}
1020
1021void LocationsBuilderX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1022 VisitCondition(comp);
1023}
1024
1025void InstructionCodeGeneratorX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1026 VisitCondition(comp);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001027}
1028
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001029void LocationsBuilderX86_64::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001030 LocationSummary* locations =
1031 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Calin Juravleddb7df22014-11-25 20:56:51 +00001032 switch (compare->InputAt(0)->GetType()) {
1033 case Primitive::kPrimLong: {
1034 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell40741f32015-04-20 22:10:34 -04001035 locations->SetInAt(1, Location::Any());
Calin Juravleddb7df22014-11-25 20:56:51 +00001036 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1037 break;
1038 }
1039 case Primitive::kPrimFloat:
1040 case Primitive::kPrimDouble: {
1041 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendell40741f32015-04-20 22:10:34 -04001042 locations->SetInAt(1, Location::Any());
Calin Juravleddb7df22014-11-25 20:56:51 +00001043 locations->SetOut(Location::RequiresRegister());
1044 break;
1045 }
1046 default:
1047 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
1048 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001049}
1050
1051void InstructionCodeGeneratorX86_64::VisitCompare(HCompare* compare) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001052 LocationSummary* locations = compare->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00001053 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Calin Juravleddb7df22014-11-25 20:56:51 +00001054 Location left = locations->InAt(0);
1055 Location right = locations->InAt(1);
1056
1057 Label less, greater, done;
1058 Primitive::Type type = compare->InputAt(0)->GetType();
1059 switch (type) {
1060 case Primitive::kPrimLong: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04001061 CpuRegister left_reg = left.AsRegister<CpuRegister>();
1062 if (right.IsConstant()) {
1063 int64_t value = right.GetConstant()->AsLongConstant()->GetValue();
Mark Mendell40741f32015-04-20 22:10:34 -04001064 if (IsInt<32>(value)) {
1065 if (value == 0) {
1066 __ testq(left_reg, left_reg);
1067 } else {
1068 __ cmpq(left_reg, Immediate(static_cast<int32_t>(value)));
1069 }
Mark Mendell3f6c7f62015-03-13 13:47:53 -04001070 } else {
Mark Mendell40741f32015-04-20 22:10:34 -04001071 // Value won't fit in an int.
1072 __ cmpq(left_reg, codegen_->LiteralInt64Address(value));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04001073 }
Mark Mendell40741f32015-04-20 22:10:34 -04001074 } else if (right.IsDoubleStackSlot()) {
1075 __ cmpq(left_reg, Address(CpuRegister(RSP), right.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04001076 } else {
1077 __ cmpq(left_reg, right.AsRegister<CpuRegister>());
1078 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001079 break;
Calin Juravleddb7df22014-11-25 20:56:51 +00001080 }
1081 case Primitive::kPrimFloat: {
Mark Mendell40741f32015-04-20 22:10:34 -04001082 XmmRegister left_reg = left.AsFpuRegister<XmmRegister>();
1083 if (right.IsConstant()) {
1084 float value = right.GetConstant()->AsFloatConstant()->GetValue();
1085 __ ucomiss(left_reg, codegen_->LiteralFloatAddress(value));
1086 } else if (right.IsStackSlot()) {
1087 __ ucomiss(left_reg, Address(CpuRegister(RSP), right.GetStackIndex()));
1088 } else {
1089 __ ucomiss(left_reg, right.AsFpuRegister<XmmRegister>());
1090 }
Calin Juravleddb7df22014-11-25 20:56:51 +00001091 __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
1092 break;
1093 }
1094 case Primitive::kPrimDouble: {
Mark Mendell40741f32015-04-20 22:10:34 -04001095 XmmRegister left_reg = left.AsFpuRegister<XmmRegister>();
1096 if (right.IsConstant()) {
1097 double value = right.GetConstant()->AsDoubleConstant()->GetValue();
1098 __ ucomisd(left_reg, codegen_->LiteralDoubleAddress(value));
1099 } else if (right.IsDoubleStackSlot()) {
1100 __ ucomisd(left_reg, Address(CpuRegister(RSP), right.GetStackIndex()));
1101 } else {
1102 __ ucomisd(left_reg, right.AsFpuRegister<XmmRegister>());
1103 }
Calin Juravleddb7df22014-11-25 20:56:51 +00001104 __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
1105 break;
1106 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001107 default:
Calin Juravleddb7df22014-11-25 20:56:51 +00001108 LOG(FATAL) << "Unexpected compare type " << type;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001109 }
Calin Juravleddb7df22014-11-25 20:56:51 +00001110 __ movl(out, Immediate(0));
Calin Juravle91debbc2014-11-26 19:01:09 +00001111 __ j(kEqual, &done);
Calin Juravleddb7df22014-11-25 20:56:51 +00001112 __ j(type == Primitive::kPrimLong ? kLess : kBelow, &less); // ucomis{s,d} sets CF (kBelow)
Calin Juravlefd861242014-11-25 20:56:51 +00001113
Calin Juravle91debbc2014-11-26 19:01:09 +00001114 __ Bind(&greater);
Calin Juravleddb7df22014-11-25 20:56:51 +00001115 __ movl(out, Immediate(1));
1116 __ jmp(&done);
1117
1118 __ Bind(&less);
1119 __ movl(out, Immediate(-1));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001120
1121 __ Bind(&done);
1122}
1123
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001124void LocationsBuilderX86_64::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001125 LocationSummary* locations =
1126 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001127 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001128}
1129
1130void InstructionCodeGeneratorX86_64::VisitIntConstant(HIntConstant* constant) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001131 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001132 UNUSED(constant);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001133}
1134
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001135void LocationsBuilderX86_64::VisitNullConstant(HNullConstant* constant) {
1136 LocationSummary* locations =
1137 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1138 locations->SetOut(Location::ConstantLocation(constant));
1139}
1140
1141void InstructionCodeGeneratorX86_64::VisitNullConstant(HNullConstant* constant) {
1142 // Will be generated at use site.
1143 UNUSED(constant);
1144}
1145
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001146void LocationsBuilderX86_64::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001147 LocationSummary* locations =
1148 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001149 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001150}
1151
1152void InstructionCodeGeneratorX86_64::VisitLongConstant(HLongConstant* constant) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001153 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001154 UNUSED(constant);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001155}
1156
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001157void LocationsBuilderX86_64::VisitFloatConstant(HFloatConstant* constant) {
1158 LocationSummary* locations =
1159 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1160 locations->SetOut(Location::ConstantLocation(constant));
1161}
1162
1163void InstructionCodeGeneratorX86_64::VisitFloatConstant(HFloatConstant* constant) {
1164 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001165 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001166}
1167
1168void LocationsBuilderX86_64::VisitDoubleConstant(HDoubleConstant* constant) {
1169 LocationSummary* locations =
1170 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1171 locations->SetOut(Location::ConstantLocation(constant));
1172}
1173
1174void InstructionCodeGeneratorX86_64::VisitDoubleConstant(HDoubleConstant* constant) {
1175 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001176 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001177}
1178
Calin Juravle27df7582015-04-17 19:12:31 +01001179void LocationsBuilderX86_64::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
1180 memory_barrier->SetLocations(nullptr);
1181}
1182
1183void InstructionCodeGeneratorX86_64::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
1184 GenerateMemoryBarrier(memory_barrier->GetBarrierKind());
1185}
1186
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001187void LocationsBuilderX86_64::VisitReturnVoid(HReturnVoid* ret) {
1188 ret->SetLocations(nullptr);
1189}
1190
1191void InstructionCodeGeneratorX86_64::VisitReturnVoid(HReturnVoid* ret) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001192 UNUSED(ret);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001193 codegen_->GenerateFrameExit();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001194}
1195
1196void LocationsBuilderX86_64::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001197 LocationSummary* locations =
1198 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001199 switch (ret->InputAt(0)->GetType()) {
1200 case Primitive::kPrimBoolean:
1201 case Primitive::kPrimByte:
1202 case Primitive::kPrimChar:
1203 case Primitive::kPrimShort:
1204 case Primitive::kPrimInt:
1205 case Primitive::kPrimNot:
1206 case Primitive::kPrimLong:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001207 locations->SetInAt(0, Location::RegisterLocation(RAX));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001208 break;
1209
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001210 case Primitive::kPrimFloat:
1211 case Primitive::kPrimDouble:
Mark Mendell40741f32015-04-20 22:10:34 -04001212 locations->SetInAt(0, Location::FpuRegisterLocation(XMM0));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001213 break;
1214
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001215 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001216 LOG(FATAL) << "Unexpected return type " << ret->InputAt(0)->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001217 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001218}
1219
1220void InstructionCodeGeneratorX86_64::VisitReturn(HReturn* ret) {
1221 if (kIsDebugBuild) {
1222 switch (ret->InputAt(0)->GetType()) {
1223 case Primitive::kPrimBoolean:
1224 case Primitive::kPrimByte:
1225 case Primitive::kPrimChar:
1226 case Primitive::kPrimShort:
1227 case Primitive::kPrimInt:
1228 case Primitive::kPrimNot:
1229 case Primitive::kPrimLong:
Roland Levillain271ab9c2014-11-27 15:23:57 +00001230 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegister<CpuRegister>().AsRegister(), RAX);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001231 break;
1232
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001233 case Primitive::kPrimFloat:
1234 case Primitive::kPrimDouble:
Roland Levillain271ab9c2014-11-27 15:23:57 +00001235 DCHECK_EQ(ret->GetLocations()->InAt(0).AsFpuRegister<XmmRegister>().AsFloatRegister(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001236 XMM0);
1237 break;
1238
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001239 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001240 LOG(FATAL) << "Unexpected return type " << ret->InputAt(0)->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001241 }
1242 }
1243 codegen_->GenerateFrameExit();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001244}
1245
Roland Levillain2d27c8e2015-04-28 15:48:45 +01001246Location InvokeDexCallingConventionVisitorX86_64::GetNextLocation(Primitive::Type type) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001247 switch (type) {
1248 case Primitive::kPrimBoolean:
1249 case Primitive::kPrimByte:
1250 case Primitive::kPrimChar:
1251 case Primitive::kPrimShort:
1252 case Primitive::kPrimInt:
1253 case Primitive::kPrimNot: {
1254 uint32_t index = gp_index_++;
1255 stack_index_++;
1256 if (index < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001257 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001258 } else {
1259 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
1260 }
1261 }
1262
1263 case Primitive::kPrimLong: {
1264 uint32_t index = gp_index_;
1265 stack_index_ += 2;
1266 if (index < calling_convention.GetNumberOfRegisters()) {
1267 gp_index_ += 1;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001268 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001269 } else {
1270 gp_index_ += 2;
1271 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
1272 }
1273 }
1274
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001275 case Primitive::kPrimFloat: {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01001276 uint32_t index = float_index_++;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001277 stack_index_++;
1278 if (index < calling_convention.GetNumberOfFpuRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001279 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001280 } else {
1281 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
1282 }
1283 }
1284
1285 case Primitive::kPrimDouble: {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01001286 uint32_t index = float_index_++;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001287 stack_index_ += 2;
1288 if (index < calling_convention.GetNumberOfFpuRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001289 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001290 } else {
1291 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
1292 }
1293 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001294
1295 case Primitive::kPrimVoid:
1296 LOG(FATAL) << "Unexpected parameter type " << type;
1297 break;
1298 }
1299 return Location();
1300}
1301
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001302void LocationsBuilderX86_64::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Roland Levillain3e3d7332015-04-28 11:00:54 +01001303 // When we do not run baseline, explicit clinit checks triggered by static
1304 // invokes must have been pruned by art::PrepareForRegisterAllocation.
1305 DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01001306
Mark Mendellfb8d2792015-03-31 22:16:59 -04001307 IntrinsicLocationsBuilderX86_64 intrinsic(codegen_);
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001308 if (intrinsic.TryDispatch(invoke)) {
1309 return;
1310 }
1311
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001312 HandleInvoke(invoke);
1313}
1314
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001315static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorX86_64* codegen) {
1316 if (invoke->GetLocations()->Intrinsified()) {
1317 IntrinsicCodeGeneratorX86_64 intrinsic(codegen);
1318 intrinsic.Dispatch(invoke);
1319 return true;
1320 }
1321 return false;
1322}
1323
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001324void InstructionCodeGeneratorX86_64::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Roland Levillain3e3d7332015-04-28 11:00:54 +01001325 // When we do not run baseline, explicit clinit checks triggered by static
1326 // invokes must have been pruned by art::PrepareForRegisterAllocation.
1327 DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01001328
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001329 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1330 return;
1331 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001332
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001333 codegen_->GenerateStaticOrDirectCall(
1334 invoke,
1335 invoke->GetLocations()->GetTemp(0).AsRegister<CpuRegister>());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +00001336 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001337}
1338
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001339void LocationsBuilderX86_64::HandleInvoke(HInvoke* invoke) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001340 LocationSummary* locations =
1341 new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001342 locations->AddTemp(Location::RegisterLocation(RDI));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001343
Roland Levillain2d27c8e2015-04-28 15:48:45 +01001344 InvokeDexCallingConventionVisitorX86_64 calling_convention_visitor;
Roland Levillain3e3d7332015-04-28 11:00:54 +01001345 for (size_t i = 0; i < invoke->GetNumberOfArguments(); i++) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001346 HInstruction* input = invoke->InputAt(i);
1347 locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
1348 }
1349
1350 switch (invoke->GetType()) {
1351 case Primitive::kPrimBoolean:
1352 case Primitive::kPrimByte:
1353 case Primitive::kPrimChar:
1354 case Primitive::kPrimShort:
1355 case Primitive::kPrimInt:
1356 case Primitive::kPrimNot:
1357 case Primitive::kPrimLong:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001358 locations->SetOut(Location::RegisterLocation(RAX));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001359 break;
1360
1361 case Primitive::kPrimVoid:
1362 break;
1363
1364 case Primitive::kPrimDouble:
1365 case Primitive::kPrimFloat:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001366 locations->SetOut(Location::FpuRegisterLocation(XMM0));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001367 break;
1368 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001369}
1370
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001371void LocationsBuilderX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Mark Mendellfb8d2792015-03-31 22:16:59 -04001372 IntrinsicLocationsBuilderX86_64 intrinsic(codegen_);
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001373 if (intrinsic.TryDispatch(invoke)) {
1374 return;
1375 }
1376
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001377 HandleInvoke(invoke);
1378}
1379
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001380void InstructionCodeGeneratorX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001381 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1382 return;
1383 }
1384
Roland Levillain271ab9c2014-11-27 15:23:57 +00001385 CpuRegister temp = invoke->GetLocations()->GetTemp(0).AsRegister<CpuRegister>();
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001386 size_t method_offset = mirror::Class::EmbeddedVTableOffset().SizeValue() +
1387 invoke->GetVTableIndex() * sizeof(mirror::Class::VTableEntry);
1388 LocationSummary* locations = invoke->GetLocations();
1389 Location receiver = locations->InAt(0);
1390 size_t class_offset = mirror::Object::ClassOffset().SizeValue();
1391 // temp = object->GetClass();
1392 if (receiver.IsStackSlot()) {
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001393 __ movl(temp, Address(CpuRegister(RSP), receiver.GetStackIndex()));
1394 __ movl(temp, Address(temp, class_offset));
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001395 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001396 __ movl(temp, Address(receiver.AsRegister<CpuRegister>(), class_offset));
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001397 }
Calin Juravle77520bc2015-01-12 18:45:46 +00001398 codegen_->MaybeRecordImplicitNullCheck(invoke);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001399 // temp = temp->GetMethodAt(method_offset);
1400 __ movl(temp, Address(temp, method_offset));
1401 // call temp->GetEntryPoint();
Mathieu Chartier2d721012014-11-10 11:08:06 -08001402 __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001403 kX86_64WordSize).SizeValue()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001404
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001405 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray39468442014-09-02 15:17:15 +01001406 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001407}
1408
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001409void LocationsBuilderX86_64::VisitInvokeInterface(HInvokeInterface* invoke) {
1410 HandleInvoke(invoke);
1411 // Add the hidden argument.
1412 invoke->GetLocations()->AddTemp(Location::RegisterLocation(RAX));
1413}
1414
1415void InstructionCodeGeneratorX86_64::VisitInvokeInterface(HInvokeInterface* invoke) {
1416 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001417 CpuRegister temp = invoke->GetLocations()->GetTemp(0).AsRegister<CpuRegister>();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001418 uint32_t method_offset = mirror::Class::EmbeddedImTableOffset().Uint32Value() +
1419 (invoke->GetImtIndex() % mirror::Class::kImtSize) * sizeof(mirror::Class::ImTableEntry);
1420 LocationSummary* locations = invoke->GetLocations();
1421 Location receiver = locations->InAt(0);
1422 size_t class_offset = mirror::Object::ClassOffset().SizeValue();
1423
1424 // Set the hidden argument.
Mark Mendell92e83bf2015-05-07 11:25:03 -04001425 CpuRegister hidden_reg = invoke->GetLocations()->GetTemp(1).AsRegister<CpuRegister>();
1426 codegen_->Load64BitValue(hidden_reg, invoke->GetDexMethodIndex());
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001427
1428 // temp = object->GetClass();
1429 if (receiver.IsStackSlot()) {
1430 __ movl(temp, Address(CpuRegister(RSP), receiver.GetStackIndex()));
1431 __ movl(temp, Address(temp, class_offset));
1432 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001433 __ movl(temp, Address(receiver.AsRegister<CpuRegister>(), class_offset));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001434 }
Calin Juravle77520bc2015-01-12 18:45:46 +00001435 codegen_->MaybeRecordImplicitNullCheck(invoke);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001436 // temp = temp->GetImtEntryAt(method_offset);
1437 __ movl(temp, Address(temp, method_offset));
1438 // call temp->GetEntryPoint();
Mathieu Chartier2d721012014-11-10 11:08:06 -08001439 __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001440 kX86_64WordSize).SizeValue()));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001441
1442 DCHECK(!codegen_->IsLeafMethod());
1443 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1444}
1445
Roland Levillain88cb1752014-10-20 16:36:47 +01001446void LocationsBuilderX86_64::VisitNeg(HNeg* neg) {
1447 LocationSummary* locations =
1448 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
1449 switch (neg->GetResultType()) {
1450 case Primitive::kPrimInt:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001451 case Primitive::kPrimLong:
Roland Levillain88cb1752014-10-20 16:36:47 +01001452 locations->SetInAt(0, Location::RequiresRegister());
1453 locations->SetOut(Location::SameAsFirstInput());
1454 break;
1455
Roland Levillain88cb1752014-10-20 16:36:47 +01001456 case Primitive::kPrimFloat:
1457 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001458 locations->SetInAt(0, Location::RequiresFpuRegister());
Roland Levillain5368c212014-11-27 15:03:41 +00001459 locations->SetOut(Location::SameAsFirstInput());
Roland Levillain5368c212014-11-27 15:03:41 +00001460 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain88cb1752014-10-20 16:36:47 +01001461 break;
1462
1463 default:
1464 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1465 }
1466}
1467
1468void InstructionCodeGeneratorX86_64::VisitNeg(HNeg* neg) {
1469 LocationSummary* locations = neg->GetLocations();
1470 Location out = locations->Out();
1471 Location in = locations->InAt(0);
1472 switch (neg->GetResultType()) {
1473 case Primitive::kPrimInt:
1474 DCHECK(in.IsRegister());
Roland Levillain3dbcb382014-10-28 17:30:07 +00001475 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001476 __ negl(out.AsRegister<CpuRegister>());
Roland Levillain88cb1752014-10-20 16:36:47 +01001477 break;
1478
1479 case Primitive::kPrimLong:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001480 DCHECK(in.IsRegister());
Roland Levillain3dbcb382014-10-28 17:30:07 +00001481 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001482 __ negq(out.AsRegister<CpuRegister>());
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001483 break;
1484
Roland Levillain5368c212014-11-27 15:03:41 +00001485 case Primitive::kPrimFloat: {
1486 DCHECK(in.Equals(out));
Mark Mendell40741f32015-04-20 22:10:34 -04001487 XmmRegister mask = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
Roland Levillain5368c212014-11-27 15:03:41 +00001488 // Implement float negation with an exclusive or with value
1489 // 0x80000000 (mask for bit 31, representing the sign of a
1490 // single-precision floating-point number).
Mark Mendell40741f32015-04-20 22:10:34 -04001491 __ movss(mask, codegen_->LiteralInt32Address(0x80000000));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001492 __ xorps(out.AsFpuRegister<XmmRegister>(), mask);
Roland Levillain3dbcb382014-10-28 17:30:07 +00001493 break;
Roland Levillain5368c212014-11-27 15:03:41 +00001494 }
Roland Levillain3dbcb382014-10-28 17:30:07 +00001495
Roland Levillain5368c212014-11-27 15:03:41 +00001496 case Primitive::kPrimDouble: {
1497 DCHECK(in.Equals(out));
Mark Mendell40741f32015-04-20 22:10:34 -04001498 XmmRegister mask = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
Roland Levillain5368c212014-11-27 15:03:41 +00001499 // Implement double negation with an exclusive or with value
Roland Levillain3dbcb382014-10-28 17:30:07 +00001500 // 0x8000000000000000 (mask for bit 63, representing the sign of
Roland Levillain5368c212014-11-27 15:03:41 +00001501 // a double-precision floating-point number).
Mark Mendell40741f32015-04-20 22:10:34 -04001502 __ movsd(mask, codegen_->LiteralInt64Address(INT64_C(0x8000000000000000)));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001503 __ xorpd(out.AsFpuRegister<XmmRegister>(), mask);
Roland Levillain88cb1752014-10-20 16:36:47 +01001504 break;
Roland Levillain5368c212014-11-27 15:03:41 +00001505 }
Roland Levillain88cb1752014-10-20 16:36:47 +01001506
1507 default:
1508 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1509 }
1510}
1511
Roland Levillaindff1f282014-11-05 14:15:05 +00001512void LocationsBuilderX86_64::VisitTypeConversion(HTypeConversion* conversion) {
1513 LocationSummary* locations =
1514 new (GetGraph()->GetArena()) LocationSummary(conversion, LocationSummary::kNoCall);
1515 Primitive::Type result_type = conversion->GetResultType();
1516 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00001517 DCHECK_NE(result_type, input_type);
David Brazdil46e2a392015-03-16 17:31:52 +00001518
David Brazdilb2bd1c52015-03-25 11:17:37 +00001519 // The Java language does not allow treating boolean as an integral type but
1520 // our bit representation makes it safe.
David Brazdil46e2a392015-03-16 17:31:52 +00001521
Roland Levillaindff1f282014-11-05 14:15:05 +00001522 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00001523 case Primitive::kPrimByte:
1524 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001525 case Primitive::kPrimBoolean:
1526 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001527 case Primitive::kPrimShort:
1528 case Primitive::kPrimInt:
1529 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001530 // Processing a Dex `int-to-byte' instruction.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001531 locations->SetInAt(0, Location::Any());
1532 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1533 break;
1534
1535 default:
1536 LOG(FATAL) << "Unexpected type conversion from " << input_type
1537 << " to " << result_type;
1538 }
1539 break;
1540
Roland Levillain01a8d712014-11-14 16:27:39 +00001541 case Primitive::kPrimShort:
1542 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001543 case Primitive::kPrimBoolean:
1544 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00001545 case Primitive::kPrimByte:
1546 case Primitive::kPrimInt:
1547 case Primitive::kPrimChar:
1548 // Processing a Dex `int-to-short' instruction.
1549 locations->SetInAt(0, Location::Any());
1550 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1551 break;
1552
1553 default:
1554 LOG(FATAL) << "Unexpected type conversion from " << input_type
1555 << " to " << result_type;
1556 }
1557 break;
1558
Roland Levillain946e1432014-11-11 17:35:19 +00001559 case Primitive::kPrimInt:
1560 switch (input_type) {
1561 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00001562 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00001563 locations->SetInAt(0, Location::Any());
1564 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1565 break;
1566
1567 case Primitive::kPrimFloat:
Roland Levillain3f8f9362014-12-02 17:45:01 +00001568 // Processing a Dex `float-to-int' instruction.
1569 locations->SetInAt(0, Location::RequiresFpuRegister());
1570 locations->SetOut(Location::RequiresRegister());
1571 locations->AddTemp(Location::RequiresFpuRegister());
1572 break;
1573
Roland Levillain946e1432014-11-11 17:35:19 +00001574 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001575 // Processing a Dex `double-to-int' instruction.
1576 locations->SetInAt(0, Location::RequiresFpuRegister());
1577 locations->SetOut(Location::RequiresRegister());
1578 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain946e1432014-11-11 17:35:19 +00001579 break;
1580
1581 default:
1582 LOG(FATAL) << "Unexpected type conversion from " << input_type
1583 << " to " << result_type;
1584 }
1585 break;
1586
Roland Levillaindff1f282014-11-05 14:15:05 +00001587 case Primitive::kPrimLong:
1588 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001589 case Primitive::kPrimBoolean:
1590 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00001591 case Primitive::kPrimByte:
1592 case Primitive::kPrimShort:
1593 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00001594 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001595 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00001596 // TODO: We would benefit from a (to-be-implemented)
1597 // Location::RegisterOrStackSlot requirement for this input.
1598 locations->SetInAt(0, Location::RequiresRegister());
1599 locations->SetOut(Location::RequiresRegister());
1600 break;
1601
1602 case Primitive::kPrimFloat:
Roland Levillain624279f2014-12-04 11:54:28 +00001603 // Processing a Dex `float-to-long' instruction.
1604 locations->SetInAt(0, Location::RequiresFpuRegister());
1605 locations->SetOut(Location::RequiresRegister());
1606 locations->AddTemp(Location::RequiresFpuRegister());
1607 break;
1608
Roland Levillaindff1f282014-11-05 14:15:05 +00001609 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001610 // Processing a Dex `double-to-long' instruction.
1611 locations->SetInAt(0, Location::RequiresFpuRegister());
1612 locations->SetOut(Location::RequiresRegister());
1613 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillaindff1f282014-11-05 14:15:05 +00001614 break;
1615
1616 default:
1617 LOG(FATAL) << "Unexpected type conversion from " << input_type
1618 << " to " << result_type;
1619 }
1620 break;
1621
Roland Levillain981e4542014-11-14 11:47:14 +00001622 case Primitive::kPrimChar:
1623 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001624 case Primitive::kPrimBoolean:
1625 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00001626 case Primitive::kPrimByte:
1627 case Primitive::kPrimShort:
1628 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00001629 // Processing a Dex `int-to-char' instruction.
1630 locations->SetInAt(0, Location::Any());
1631 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1632 break;
1633
1634 default:
1635 LOG(FATAL) << "Unexpected type conversion from " << input_type
1636 << " to " << result_type;
1637 }
1638 break;
1639
Roland Levillaindff1f282014-11-05 14:15:05 +00001640 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00001641 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001642 case Primitive::kPrimBoolean:
1643 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001644 case Primitive::kPrimByte:
1645 case Primitive::kPrimShort:
1646 case Primitive::kPrimInt:
1647 case Primitive::kPrimChar:
1648 // Processing a Dex `int-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04001649 locations->SetInAt(0, Location::Any());
Roland Levillaincff13742014-11-17 14:32:17 +00001650 locations->SetOut(Location::RequiresFpuRegister());
1651 break;
1652
1653 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00001654 // Processing a Dex `long-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04001655 locations->SetInAt(0, Location::Any());
Roland Levillain6d0e4832014-11-27 18:31:21 +00001656 locations->SetOut(Location::RequiresFpuRegister());
1657 break;
1658
Roland Levillaincff13742014-11-17 14:32:17 +00001659 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001660 // Processing a Dex `double-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04001661 locations->SetInAt(0, Location::Any());
Roland Levillain8964e2b2014-12-04 12:10:50 +00001662 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00001663 break;
1664
1665 default:
1666 LOG(FATAL) << "Unexpected type conversion from " << input_type
1667 << " to " << result_type;
1668 };
1669 break;
1670
Roland Levillaindff1f282014-11-05 14:15:05 +00001671 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00001672 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001673 case Primitive::kPrimBoolean:
1674 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001675 case Primitive::kPrimByte:
1676 case Primitive::kPrimShort:
1677 case Primitive::kPrimInt:
1678 case Primitive::kPrimChar:
1679 // Processing a Dex `int-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04001680 locations->SetInAt(0, Location::Any());
Roland Levillaincff13742014-11-17 14:32:17 +00001681 locations->SetOut(Location::RequiresFpuRegister());
1682 break;
1683
1684 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00001685 // Processing a Dex `long-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04001686 locations->SetInAt(0, Location::Any());
Roland Levillain647b9ed2014-11-27 12:06:00 +00001687 locations->SetOut(Location::RequiresFpuRegister());
1688 break;
1689
Roland Levillaincff13742014-11-17 14:32:17 +00001690 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001691 // Processing a Dex `float-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04001692 locations->SetInAt(0, Location::Any());
Roland Levillain8964e2b2014-12-04 12:10:50 +00001693 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00001694 break;
1695
1696 default:
1697 LOG(FATAL) << "Unexpected type conversion from " << input_type
1698 << " to " << result_type;
1699 }
Roland Levillaindff1f282014-11-05 14:15:05 +00001700 break;
1701
1702 default:
1703 LOG(FATAL) << "Unexpected type conversion from " << input_type
1704 << " to " << result_type;
1705 }
1706}
1707
1708void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conversion) {
1709 LocationSummary* locations = conversion->GetLocations();
1710 Location out = locations->Out();
1711 Location in = locations->InAt(0);
1712 Primitive::Type result_type = conversion->GetResultType();
1713 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00001714 DCHECK_NE(result_type, input_type);
Roland Levillaindff1f282014-11-05 14:15:05 +00001715 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00001716 case Primitive::kPrimByte:
1717 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001718 case Primitive::kPrimBoolean:
1719 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001720 case Primitive::kPrimShort:
1721 case Primitive::kPrimInt:
1722 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001723 // Processing a Dex `int-to-byte' instruction.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001724 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001725 __ movsxb(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain51d3fc42014-11-13 14:11:42 +00001726 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001727 __ movsxb(out.AsRegister<CpuRegister>(),
Roland Levillain51d3fc42014-11-13 14:11:42 +00001728 Address(CpuRegister(RSP), in.GetStackIndex()));
1729 } else {
1730 DCHECK(in.GetConstant()->IsIntConstant());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001731 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain51d3fc42014-11-13 14:11:42 +00001732 Immediate(static_cast<int8_t>(in.GetConstant()->AsIntConstant()->GetValue())));
1733 }
1734 break;
1735
1736 default:
1737 LOG(FATAL) << "Unexpected type conversion from " << input_type
1738 << " to " << result_type;
1739 }
1740 break;
1741
Roland Levillain01a8d712014-11-14 16:27:39 +00001742 case Primitive::kPrimShort:
1743 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001744 case Primitive::kPrimBoolean:
1745 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00001746 case Primitive::kPrimByte:
1747 case Primitive::kPrimInt:
1748 case Primitive::kPrimChar:
1749 // Processing a Dex `int-to-short' instruction.
1750 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001751 __ movsxw(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain01a8d712014-11-14 16:27:39 +00001752 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001753 __ movsxw(out.AsRegister<CpuRegister>(),
Roland Levillain01a8d712014-11-14 16:27:39 +00001754 Address(CpuRegister(RSP), in.GetStackIndex()));
1755 } else {
1756 DCHECK(in.GetConstant()->IsIntConstant());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001757 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain01a8d712014-11-14 16:27:39 +00001758 Immediate(static_cast<int16_t>(in.GetConstant()->AsIntConstant()->GetValue())));
1759 }
1760 break;
1761
1762 default:
1763 LOG(FATAL) << "Unexpected type conversion from " << input_type
1764 << " to " << result_type;
1765 }
1766 break;
1767
Roland Levillain946e1432014-11-11 17:35:19 +00001768 case Primitive::kPrimInt:
1769 switch (input_type) {
1770 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00001771 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00001772 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001773 __ movl(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain946e1432014-11-11 17:35:19 +00001774 } else if (in.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001775 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain946e1432014-11-11 17:35:19 +00001776 Address(CpuRegister(RSP), in.GetStackIndex()));
1777 } else {
1778 DCHECK(in.IsConstant());
1779 DCHECK(in.GetConstant()->IsLongConstant());
1780 int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00001781 __ movl(out.AsRegister<CpuRegister>(), Immediate(static_cast<int32_t>(value)));
Roland Levillain946e1432014-11-11 17:35:19 +00001782 }
1783 break;
1784
Roland Levillain3f8f9362014-12-02 17:45:01 +00001785 case Primitive::kPrimFloat: {
1786 // Processing a Dex `float-to-int' instruction.
1787 XmmRegister input = in.AsFpuRegister<XmmRegister>();
1788 CpuRegister output = out.AsRegister<CpuRegister>();
1789 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
1790 Label done, nan;
1791
1792 __ movl(output, Immediate(kPrimIntMax));
1793 // temp = int-to-float(output)
Roland Levillain624279f2014-12-04 11:54:28 +00001794 __ cvtsi2ss(temp, output, false);
Roland Levillain3f8f9362014-12-02 17:45:01 +00001795 // if input >= temp goto done
1796 __ comiss(input, temp);
1797 __ j(kAboveEqual, &done);
1798 // if input == NaN goto nan
1799 __ j(kUnordered, &nan);
1800 // output = float-to-int-truncate(input)
Roland Levillain624279f2014-12-04 11:54:28 +00001801 __ cvttss2si(output, input, false);
Roland Levillain3f8f9362014-12-02 17:45:01 +00001802 __ jmp(&done);
1803 __ Bind(&nan);
1804 // output = 0
1805 __ xorl(output, output);
1806 __ Bind(&done);
1807 break;
1808 }
1809
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001810 case Primitive::kPrimDouble: {
1811 // Processing a Dex `double-to-int' instruction.
1812 XmmRegister input = in.AsFpuRegister<XmmRegister>();
1813 CpuRegister output = out.AsRegister<CpuRegister>();
1814 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
1815 Label done, nan;
1816
1817 __ movl(output, Immediate(kPrimIntMax));
1818 // temp = int-to-double(output)
1819 __ cvtsi2sd(temp, output);
1820 // if input >= temp goto done
1821 __ comisd(input, temp);
1822 __ j(kAboveEqual, &done);
1823 // if input == NaN goto nan
1824 __ j(kUnordered, &nan);
1825 // output = double-to-int-truncate(input)
1826 __ cvttsd2si(output, input);
1827 __ jmp(&done);
1828 __ Bind(&nan);
1829 // output = 0
1830 __ xorl(output, output);
1831 __ Bind(&done);
Roland Levillain946e1432014-11-11 17:35:19 +00001832 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001833 }
Roland Levillain946e1432014-11-11 17:35:19 +00001834
1835 default:
1836 LOG(FATAL) << "Unexpected type conversion from " << input_type
1837 << " to " << result_type;
1838 }
1839 break;
1840
Roland Levillaindff1f282014-11-05 14:15:05 +00001841 case Primitive::kPrimLong:
1842 switch (input_type) {
1843 DCHECK(out.IsRegister());
David Brazdil46e2a392015-03-16 17:31:52 +00001844 case Primitive::kPrimBoolean:
1845 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00001846 case Primitive::kPrimByte:
1847 case Primitive::kPrimShort:
1848 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00001849 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001850 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00001851 DCHECK(in.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001852 __ movsxd(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillaindff1f282014-11-05 14:15:05 +00001853 break;
1854
Roland Levillain624279f2014-12-04 11:54:28 +00001855 case Primitive::kPrimFloat: {
1856 // Processing a Dex `float-to-long' instruction.
1857 XmmRegister input = in.AsFpuRegister<XmmRegister>();
1858 CpuRegister output = out.AsRegister<CpuRegister>();
1859 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
1860 Label done, nan;
1861
Mark Mendell92e83bf2015-05-07 11:25:03 -04001862 codegen_->Load64BitValue(output, kPrimLongMax);
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001863 // temp = long-to-float(output)
Roland Levillain624279f2014-12-04 11:54:28 +00001864 __ cvtsi2ss(temp, output, true);
1865 // if input >= temp goto done
1866 __ comiss(input, temp);
1867 __ j(kAboveEqual, &done);
1868 // if input == NaN goto nan
1869 __ j(kUnordered, &nan);
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001870 // output = float-to-long-truncate(input)
Roland Levillain624279f2014-12-04 11:54:28 +00001871 __ cvttss2si(output, input, true);
1872 __ jmp(&done);
1873 __ Bind(&nan);
1874 // output = 0
Mark Mendell92e83bf2015-05-07 11:25:03 -04001875 __ xorl(output, output);
Roland Levillain624279f2014-12-04 11:54:28 +00001876 __ Bind(&done);
1877 break;
1878 }
1879
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001880 case Primitive::kPrimDouble: {
1881 // Processing a Dex `double-to-long' instruction.
1882 XmmRegister input = in.AsFpuRegister<XmmRegister>();
1883 CpuRegister output = out.AsRegister<CpuRegister>();
1884 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
1885 Label done, nan;
1886
Mark Mendell92e83bf2015-05-07 11:25:03 -04001887 codegen_->Load64BitValue(output, kPrimLongMax);
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001888 // temp = long-to-double(output)
1889 __ cvtsi2sd(temp, output, true);
1890 // if input >= temp goto done
1891 __ comisd(input, temp);
1892 __ j(kAboveEqual, &done);
1893 // if input == NaN goto nan
1894 __ j(kUnordered, &nan);
1895 // output = double-to-long-truncate(input)
1896 __ cvttsd2si(output, input, true);
1897 __ jmp(&done);
1898 __ Bind(&nan);
1899 // output = 0
Mark Mendell92e83bf2015-05-07 11:25:03 -04001900 __ xorl(output, output);
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001901 __ Bind(&done);
Roland Levillaindff1f282014-11-05 14:15:05 +00001902 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001903 }
Roland Levillaindff1f282014-11-05 14:15:05 +00001904
1905 default:
1906 LOG(FATAL) << "Unexpected type conversion from " << input_type
1907 << " to " << result_type;
1908 }
1909 break;
1910
Roland Levillain981e4542014-11-14 11:47:14 +00001911 case Primitive::kPrimChar:
1912 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001913 case Primitive::kPrimBoolean:
1914 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00001915 case Primitive::kPrimByte:
1916 case Primitive::kPrimShort:
1917 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00001918 // Processing a Dex `int-to-char' instruction.
1919 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001920 __ movzxw(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain981e4542014-11-14 11:47:14 +00001921 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001922 __ movzxw(out.AsRegister<CpuRegister>(),
Roland Levillain981e4542014-11-14 11:47:14 +00001923 Address(CpuRegister(RSP), in.GetStackIndex()));
1924 } else {
1925 DCHECK(in.GetConstant()->IsIntConstant());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001926 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain981e4542014-11-14 11:47:14 +00001927 Immediate(static_cast<uint16_t>(in.GetConstant()->AsIntConstant()->GetValue())));
1928 }
1929 break;
1930
1931 default:
1932 LOG(FATAL) << "Unexpected type conversion from " << input_type
1933 << " to " << result_type;
1934 }
1935 break;
1936
Roland Levillaindff1f282014-11-05 14:15:05 +00001937 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00001938 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001939 case Primitive::kPrimBoolean:
1940 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001941 case Primitive::kPrimByte:
1942 case Primitive::kPrimShort:
1943 case Primitive::kPrimInt:
1944 case Primitive::kPrimChar:
Roland Levillain6d0e4832014-11-27 18:31:21 +00001945 // Processing a Dex `int-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04001946 if (in.IsRegister()) {
1947 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), false);
1948 } else if (in.IsConstant()) {
1949 int32_t v = in.GetConstant()->AsIntConstant()->GetValue();
1950 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
1951 if (v == 0) {
1952 __ xorps(dest, dest);
1953 } else {
1954 __ movss(dest, codegen_->LiteralFloatAddress(static_cast<float>(v)));
1955 }
1956 } else {
1957 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(),
1958 Address(CpuRegister(RSP), in.GetStackIndex()), false);
1959 }
Roland Levillaincff13742014-11-17 14:32:17 +00001960 break;
1961
1962 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00001963 // Processing a Dex `long-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04001964 if (in.IsRegister()) {
1965 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), true);
1966 } else if (in.IsConstant()) {
1967 int64_t v = in.GetConstant()->AsLongConstant()->GetValue();
1968 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
1969 if (v == 0) {
1970 __ xorps(dest, dest);
1971 } else {
1972 __ movss(dest, codegen_->LiteralFloatAddress(static_cast<float>(v)));
1973 }
1974 } else {
1975 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(),
1976 Address(CpuRegister(RSP), in.GetStackIndex()), true);
1977 }
Roland Levillain6d0e4832014-11-27 18:31:21 +00001978 break;
1979
Roland Levillaincff13742014-11-17 14:32:17 +00001980 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001981 // Processing a Dex `double-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04001982 if (in.IsFpuRegister()) {
1983 __ cvtsd2ss(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
1984 } else if (in.IsConstant()) {
1985 double v = in.GetConstant()->AsDoubleConstant()->GetValue();
1986 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
1987 if (bit_cast<int64_t, double>(v) == 0) {
1988 __ xorps(dest, dest);
1989 } else {
1990 __ movss(dest, codegen_->LiteralFloatAddress(static_cast<float>(v)));
1991 }
1992 } else {
1993 __ cvtsd2ss(out.AsFpuRegister<XmmRegister>(),
1994 Address(CpuRegister(RSP), in.GetStackIndex()));
1995 }
Roland Levillaincff13742014-11-17 14:32:17 +00001996 break;
1997
1998 default:
1999 LOG(FATAL) << "Unexpected type conversion from " << input_type
2000 << " to " << result_type;
2001 };
2002 break;
2003
Roland Levillaindff1f282014-11-05 14:15:05 +00002004 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00002005 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002006 case Primitive::kPrimBoolean:
2007 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002008 case Primitive::kPrimByte:
2009 case Primitive::kPrimShort:
2010 case Primitive::kPrimInt:
2011 case Primitive::kPrimChar:
Roland Levillain6d0e4832014-11-27 18:31:21 +00002012 // Processing a Dex `int-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002013 if (in.IsRegister()) {
2014 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), false);
2015 } else if (in.IsConstant()) {
2016 int32_t v = in.GetConstant()->AsIntConstant()->GetValue();
2017 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
2018 if (v == 0) {
2019 __ xorpd(dest, dest);
2020 } else {
2021 __ movsd(dest, codegen_->LiteralDoubleAddress(static_cast<double>(v)));
2022 }
2023 } else {
2024 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(),
2025 Address(CpuRegister(RSP), in.GetStackIndex()), false);
2026 }
Roland Levillaincff13742014-11-17 14:32:17 +00002027 break;
2028
2029 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00002030 // Processing a Dex `long-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002031 if (in.IsRegister()) {
2032 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), true);
2033 } else if (in.IsConstant()) {
2034 int64_t v = in.GetConstant()->AsLongConstant()->GetValue();
2035 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
2036 if (v == 0) {
2037 __ xorpd(dest, dest);
2038 } else {
2039 __ movsd(dest, codegen_->LiteralDoubleAddress(static_cast<double>(v)));
2040 }
2041 } else {
2042 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(),
2043 Address(CpuRegister(RSP), in.GetStackIndex()), true);
2044 }
Roland Levillain647b9ed2014-11-27 12:06:00 +00002045 break;
2046
Roland Levillaincff13742014-11-17 14:32:17 +00002047 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002048 // Processing a Dex `float-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002049 if (in.IsFpuRegister()) {
2050 __ cvtss2sd(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
2051 } else if (in.IsConstant()) {
2052 float v = in.GetConstant()->AsFloatConstant()->GetValue();
2053 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
2054 if (bit_cast<int32_t, float>(v) == 0) {
2055 __ xorpd(dest, dest);
2056 } else {
2057 __ movsd(dest, codegen_->LiteralDoubleAddress(static_cast<double>(v)));
2058 }
2059 } else {
2060 __ cvtss2sd(out.AsFpuRegister<XmmRegister>(),
2061 Address(CpuRegister(RSP), in.GetStackIndex()));
2062 }
Roland Levillaincff13742014-11-17 14:32:17 +00002063 break;
2064
2065 default:
2066 LOG(FATAL) << "Unexpected type conversion from " << input_type
2067 << " to " << result_type;
2068 };
Roland Levillaindff1f282014-11-05 14:15:05 +00002069 break;
2070
2071 default:
2072 LOG(FATAL) << "Unexpected type conversion from " << input_type
2073 << " to " << result_type;
2074 }
2075}
2076
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002077void LocationsBuilderX86_64::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002078 LocationSummary* locations =
2079 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002080 switch (add->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002081 case Primitive::kPrimInt: {
2082 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002083 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
2084 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002085 break;
2086 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002087
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002088 case Primitive::kPrimLong: {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002089 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell09b84632015-02-13 17:48:38 -05002090 // We can use a leaq or addq if the constant can fit in an immediate.
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002091 locations->SetInAt(1, Location::RegisterOrInt32LongConstant(add->InputAt(1)));
Mark Mendell09b84632015-02-13 17:48:38 -05002092 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002093 break;
2094 }
2095
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002096 case Primitive::kPrimDouble:
2097 case Primitive::kPrimFloat: {
2098 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendellf55c3e02015-03-26 21:07:46 -04002099 locations->SetInAt(1, Location::Any());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002100 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002101 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002102 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002103
2104 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002105 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002106 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002107}
2108
2109void InstructionCodeGeneratorX86_64::VisitAdd(HAdd* add) {
2110 LocationSummary* locations = add->GetLocations();
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002111 Location first = locations->InAt(0);
2112 Location second = locations->InAt(1);
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002113 Location out = locations->Out();
Calin Juravle11351682014-10-23 15:38:15 +01002114
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002115 switch (add->GetResultType()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002116 case Primitive::kPrimInt: {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002117 if (second.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002118 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
2119 __ addl(out.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
2120 } else {
2121 __ leal(out.AsRegister<CpuRegister>(), Address(
2122 first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>(), TIMES_1, 0));
2123 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002124 } else if (second.IsConstant()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002125 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
2126 __ addl(out.AsRegister<CpuRegister>(),
2127 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
2128 } else {
2129 __ leal(out.AsRegister<CpuRegister>(), Address(
2130 first.AsRegister<CpuRegister>(), second.GetConstant()->AsIntConstant()->GetValue()));
2131 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002132 } else {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002133 DCHECK(first.Equals(locations->Out()));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002134 __ addl(first.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), second.GetStackIndex()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002135 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002136 break;
2137 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002138
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002139 case Primitive::kPrimLong: {
Mark Mendell09b84632015-02-13 17:48:38 -05002140 if (second.IsRegister()) {
2141 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
2142 __ addq(out.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
2143 } else {
2144 __ leaq(out.AsRegister<CpuRegister>(), Address(
2145 first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>(), TIMES_1, 0));
2146 }
2147 } else {
2148 DCHECK(second.IsConstant());
2149 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
2150 int32_t int32_value = Low32Bits(value);
2151 DCHECK_EQ(int32_value, value);
2152 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
2153 __ addq(out.AsRegister<CpuRegister>(), Immediate(int32_value));
2154 } else {
2155 __ leaq(out.AsRegister<CpuRegister>(), Address(
2156 first.AsRegister<CpuRegister>(), int32_value));
2157 }
2158 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002159 break;
2160 }
2161
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002162 case Primitive::kPrimFloat: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04002163 if (second.IsFpuRegister()) {
2164 __ addss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2165 } else if (second.IsConstant()) {
2166 __ addss(first.AsFpuRegister<XmmRegister>(),
2167 codegen_->LiteralFloatAddress(second.GetConstant()->AsFloatConstant()->GetValue()));
2168 } else {
2169 DCHECK(second.IsStackSlot());
2170 __ addss(first.AsFpuRegister<XmmRegister>(),
2171 Address(CpuRegister(RSP), second.GetStackIndex()));
2172 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002173 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002174 }
2175
2176 case Primitive::kPrimDouble: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04002177 if (second.IsFpuRegister()) {
2178 __ addsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2179 } else if (second.IsConstant()) {
2180 __ addsd(first.AsFpuRegister<XmmRegister>(),
2181 codegen_->LiteralDoubleAddress(second.GetConstant()->AsDoubleConstant()->GetValue()));
2182 } else {
2183 DCHECK(second.IsDoubleStackSlot());
2184 __ addsd(first.AsFpuRegister<XmmRegister>(),
2185 Address(CpuRegister(RSP), second.GetStackIndex()));
2186 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002187 break;
2188 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002189
2190 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002191 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002192 }
2193}
2194
2195void LocationsBuilderX86_64::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002196 LocationSummary* locations =
2197 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002198 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002199 case Primitive::kPrimInt: {
2200 locations->SetInAt(0, Location::RequiresRegister());
2201 locations->SetInAt(1, Location::Any());
2202 locations->SetOut(Location::SameAsFirstInput());
2203 break;
2204 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002205 case Primitive::kPrimLong: {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002206 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002207 locations->SetInAt(1, Location::RegisterOrInt32LongConstant(sub->InputAt(1)));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002208 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002209 break;
2210 }
Calin Juravle11351682014-10-23 15:38:15 +01002211 case Primitive::kPrimFloat:
2212 case Primitive::kPrimDouble: {
2213 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendellf55c3e02015-03-26 21:07:46 -04002214 locations->SetInAt(1, Location::Any());
Calin Juravle11351682014-10-23 15:38:15 +01002215 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002216 break;
Calin Juravle11351682014-10-23 15:38:15 +01002217 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002218 default:
Calin Juravle11351682014-10-23 15:38:15 +01002219 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002220 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002221}
2222
2223void InstructionCodeGeneratorX86_64::VisitSub(HSub* sub) {
2224 LocationSummary* locations = sub->GetLocations();
Calin Juravle11351682014-10-23 15:38:15 +01002225 Location first = locations->InAt(0);
2226 Location second = locations->InAt(1);
2227 DCHECK(first.Equals(locations->Out()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002228 switch (sub->GetResultType()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002229 case Primitive::kPrimInt: {
Calin Juravle11351682014-10-23 15:38:15 +01002230 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002231 __ subl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Calin Juravle11351682014-10-23 15:38:15 +01002232 } else if (second.IsConstant()) {
2233 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002234 __ subl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002235 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002236 __ subl(first.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), second.GetStackIndex()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002237 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002238 break;
2239 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002240 case Primitive::kPrimLong: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002241 if (second.IsConstant()) {
2242 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
2243 DCHECK(IsInt<32>(value));
2244 __ subq(first.AsRegister<CpuRegister>(), Immediate(static_cast<int32_t>(value)));
2245 } else {
2246 __ subq(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
2247 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002248 break;
2249 }
2250
Calin Juravle11351682014-10-23 15:38:15 +01002251 case Primitive::kPrimFloat: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04002252 if (second.IsFpuRegister()) {
2253 __ subss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2254 } else if (second.IsConstant()) {
2255 __ subss(first.AsFpuRegister<XmmRegister>(),
2256 codegen_->LiteralFloatAddress(second.GetConstant()->AsFloatConstant()->GetValue()));
2257 } else {
2258 DCHECK(second.IsStackSlot());
2259 __ subss(first.AsFpuRegister<XmmRegister>(),
2260 Address(CpuRegister(RSP), second.GetStackIndex()));
2261 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002262 break;
Calin Juravle11351682014-10-23 15:38:15 +01002263 }
2264
2265 case Primitive::kPrimDouble: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04002266 if (second.IsFpuRegister()) {
2267 __ subsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2268 } else if (second.IsConstant()) {
2269 __ subsd(first.AsFpuRegister<XmmRegister>(),
2270 codegen_->LiteralDoubleAddress(second.GetConstant()->AsDoubleConstant()->GetValue()));
2271 } else {
2272 DCHECK(second.IsDoubleStackSlot());
2273 __ subsd(first.AsFpuRegister<XmmRegister>(),
2274 Address(CpuRegister(RSP), second.GetStackIndex()));
2275 }
Calin Juravle11351682014-10-23 15:38:15 +01002276 break;
2277 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002278
2279 default:
Calin Juravle11351682014-10-23 15:38:15 +01002280 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002281 }
2282}
2283
Calin Juravle34bacdf2014-10-07 20:23:36 +01002284void LocationsBuilderX86_64::VisitMul(HMul* mul) {
2285 LocationSummary* locations =
2286 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
2287 switch (mul->GetResultType()) {
2288 case Primitive::kPrimInt: {
2289 locations->SetInAt(0, Location::RequiresRegister());
2290 locations->SetInAt(1, Location::Any());
2291 locations->SetOut(Location::SameAsFirstInput());
2292 break;
2293 }
2294 case Primitive::kPrimLong: {
2295 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002296 locations->SetInAt(1, Location::RegisterOrInt32LongConstant(mul->InputAt(1)));
2297 if (locations->InAt(1).IsConstant()) {
2298 // Can use 3 operand multiply.
2299 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2300 } else {
2301 locations->SetOut(Location::SameAsFirstInput());
2302 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002303 break;
2304 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01002305 case Primitive::kPrimFloat:
2306 case Primitive::kPrimDouble: {
2307 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendellf55c3e02015-03-26 21:07:46 -04002308 locations->SetInAt(1, Location::Any());
Calin Juravleb5bfa962014-10-21 18:02:24 +01002309 locations->SetOut(Location::SameAsFirstInput());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002310 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002311 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002312
2313 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002314 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002315 }
2316}
2317
2318void InstructionCodeGeneratorX86_64::VisitMul(HMul* mul) {
2319 LocationSummary* locations = mul->GetLocations();
2320 Location first = locations->InAt(0);
2321 Location second = locations->InAt(1);
Calin Juravle34bacdf2014-10-07 20:23:36 +01002322 switch (mul->GetResultType()) {
2323 case Primitive::kPrimInt: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002324 DCHECK(first.Equals(locations->Out()));
Calin Juravle34bacdf2014-10-07 20:23:36 +01002325 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002326 __ imull(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002327 } else if (second.IsConstant()) {
2328 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002329 __ imull(first.AsRegister<CpuRegister>(), imm);
Calin Juravle34bacdf2014-10-07 20:23:36 +01002330 } else {
2331 DCHECK(second.IsStackSlot());
Roland Levillain199f3362014-11-27 17:15:16 +00002332 __ imull(first.AsRegister<CpuRegister>(),
2333 Address(CpuRegister(RSP), second.GetStackIndex()));
Calin Juravle34bacdf2014-10-07 20:23:36 +01002334 }
2335 break;
2336 }
2337 case Primitive::kPrimLong: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002338 if (second.IsConstant()) {
2339 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
2340 DCHECK(IsInt<32>(value));
2341 __ imulq(locations->Out().AsRegister<CpuRegister>(),
2342 first.AsRegister<CpuRegister>(),
2343 Immediate(static_cast<int32_t>(value)));
2344 } else {
2345 DCHECK(first.Equals(locations->Out()));
2346 __ imulq(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
2347 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002348 break;
2349 }
2350
Calin Juravleb5bfa962014-10-21 18:02:24 +01002351 case Primitive::kPrimFloat: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002352 DCHECK(first.Equals(locations->Out()));
Mark Mendellf55c3e02015-03-26 21:07:46 -04002353 if (second.IsFpuRegister()) {
2354 __ mulss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2355 } else if (second.IsConstant()) {
2356 __ mulss(first.AsFpuRegister<XmmRegister>(),
2357 codegen_->LiteralFloatAddress(second.GetConstant()->AsFloatConstant()->GetValue()));
2358 } else {
2359 DCHECK(second.IsStackSlot());
2360 __ mulss(first.AsFpuRegister<XmmRegister>(),
2361 Address(CpuRegister(RSP), second.GetStackIndex()));
2362 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002363 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002364 }
2365
2366 case Primitive::kPrimDouble: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002367 DCHECK(first.Equals(locations->Out()));
Mark Mendellf55c3e02015-03-26 21:07:46 -04002368 if (second.IsFpuRegister()) {
2369 __ mulsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2370 } else if (second.IsConstant()) {
2371 __ mulsd(first.AsFpuRegister<XmmRegister>(),
2372 codegen_->LiteralDoubleAddress(second.GetConstant()->AsDoubleConstant()->GetValue()));
2373 } else {
2374 DCHECK(second.IsDoubleStackSlot());
2375 __ mulsd(first.AsFpuRegister<XmmRegister>(),
2376 Address(CpuRegister(RSP), second.GetStackIndex()));
2377 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01002378 break;
2379 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002380
2381 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002382 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002383 }
2384}
2385
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002386void InstructionCodeGeneratorX86_64::PushOntoFPStack(Location source, uint32_t temp_offset,
2387 uint32_t stack_adjustment, bool is_float) {
2388 if (source.IsStackSlot()) {
2389 DCHECK(is_float);
2390 __ flds(Address(CpuRegister(RSP), source.GetStackIndex() + stack_adjustment));
2391 } else if (source.IsDoubleStackSlot()) {
2392 DCHECK(!is_float);
2393 __ fldl(Address(CpuRegister(RSP), source.GetStackIndex() + stack_adjustment));
2394 } else {
2395 // Write the value to the temporary location on the stack and load to FP stack.
2396 if (is_float) {
2397 Location stack_temp = Location::StackSlot(temp_offset);
2398 codegen_->Move(stack_temp, source);
2399 __ flds(Address(CpuRegister(RSP), temp_offset));
2400 } else {
2401 Location stack_temp = Location::DoubleStackSlot(temp_offset);
2402 codegen_->Move(stack_temp, source);
2403 __ fldl(Address(CpuRegister(RSP), temp_offset));
2404 }
2405 }
2406}
2407
2408void InstructionCodeGeneratorX86_64::GenerateRemFP(HRem *rem) {
2409 Primitive::Type type = rem->GetResultType();
2410 bool is_float = type == Primitive::kPrimFloat;
2411 size_t elem_size = Primitive::ComponentSize(type);
2412 LocationSummary* locations = rem->GetLocations();
2413 Location first = locations->InAt(0);
2414 Location second = locations->InAt(1);
2415 Location out = locations->Out();
2416
2417 // Create stack space for 2 elements.
2418 // TODO: enhance register allocator to ask for stack temporaries.
2419 __ subq(CpuRegister(RSP), Immediate(2 * elem_size));
2420
2421 // Load the values to the FP stack in reverse order, using temporaries if needed.
2422 PushOntoFPStack(second, elem_size, 2 * elem_size, is_float);
2423 PushOntoFPStack(first, 0, 2 * elem_size, is_float);
2424
2425 // Loop doing FPREM until we stabilize.
2426 Label retry;
2427 __ Bind(&retry);
2428 __ fprem();
2429
2430 // Move FP status to AX.
2431 __ fstsw();
2432
2433 // And see if the argument reduction is complete. This is signaled by the
2434 // C2 FPU flag bit set to 0.
2435 __ andl(CpuRegister(RAX), Immediate(kC2ConditionMask));
2436 __ j(kNotEqual, &retry);
2437
2438 // We have settled on the final value. Retrieve it into an XMM register.
2439 // Store FP top of stack to real stack.
2440 if (is_float) {
2441 __ fsts(Address(CpuRegister(RSP), 0));
2442 } else {
2443 __ fstl(Address(CpuRegister(RSP), 0));
2444 }
2445
2446 // Pop the 2 items from the FP stack.
2447 __ fucompp();
2448
2449 // Load the value from the stack into an XMM register.
2450 DCHECK(out.IsFpuRegister()) << out;
2451 if (is_float) {
2452 __ movss(out.AsFpuRegister<XmmRegister>(), Address(CpuRegister(RSP), 0));
2453 } else {
2454 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(CpuRegister(RSP), 0));
2455 }
2456
2457 // And remove the temporary stack space we allocated.
2458 __ addq(CpuRegister(RSP), Immediate(2 * elem_size));
2459}
2460
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002461void InstructionCodeGeneratorX86_64::DivRemOneOrMinusOne(HBinaryOperation* instruction) {
2462 DCHECK(instruction->IsDiv() || instruction->IsRem());
2463
2464 LocationSummary* locations = instruction->GetLocations();
2465 Location second = locations->InAt(1);
2466 DCHECK(second.IsConstant());
2467
2468 CpuRegister output_register = locations->Out().AsRegister<CpuRegister>();
2469 CpuRegister input_register = locations->InAt(0).AsRegister<CpuRegister>();
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002470 int64_t imm = Int64FromConstant(second.GetConstant());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002471
2472 DCHECK(imm == 1 || imm == -1);
2473
2474 switch (instruction->GetResultType()) {
2475 case Primitive::kPrimInt: {
2476 if (instruction->IsRem()) {
2477 __ xorl(output_register, output_register);
2478 } else {
2479 __ movl(output_register, input_register);
2480 if (imm == -1) {
2481 __ negl(output_register);
2482 }
2483 }
2484 break;
2485 }
2486
2487 case Primitive::kPrimLong: {
2488 if (instruction->IsRem()) {
Mark Mendell92e83bf2015-05-07 11:25:03 -04002489 __ xorl(output_register, output_register);
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002490 } else {
2491 __ movq(output_register, input_register);
2492 if (imm == -1) {
2493 __ negq(output_register);
2494 }
2495 }
2496 break;
2497 }
2498
2499 default:
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002500 LOG(FATAL) << "Unexpected type for div by (-)1 " << instruction->GetResultType();
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002501 }
2502}
2503
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002504void InstructionCodeGeneratorX86_64::DivByPowerOfTwo(HDiv* instruction) {
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002505 LocationSummary* locations = instruction->GetLocations();
2506 Location second = locations->InAt(1);
2507
2508 CpuRegister output_register = locations->Out().AsRegister<CpuRegister>();
2509 CpuRegister numerator = locations->InAt(0).AsRegister<CpuRegister>();
2510
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002511 int64_t imm = Int64FromConstant(second.GetConstant());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002512
2513 DCHECK(IsPowerOfTwo(std::abs(imm)));
2514
2515 CpuRegister tmp = locations->GetTemp(0).AsRegister<CpuRegister>();
2516
2517 if (instruction->GetResultType() == Primitive::kPrimInt) {
2518 __ leal(tmp, Address(numerator, std::abs(imm) - 1));
2519 __ testl(numerator, numerator);
2520 __ cmov(kGreaterEqual, tmp, numerator);
2521 int shift = CTZ(imm);
2522 __ sarl(tmp, Immediate(shift));
2523
2524 if (imm < 0) {
2525 __ negl(tmp);
2526 }
2527
2528 __ movl(output_register, tmp);
2529 } else {
2530 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
2531 CpuRegister rdx = locations->GetTemp(0).AsRegister<CpuRegister>();
2532
Mark Mendell92e83bf2015-05-07 11:25:03 -04002533 codegen_->Load64BitValue(rdx, std::abs(imm) - 1);
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002534 __ addq(rdx, numerator);
2535 __ testq(numerator, numerator);
2536 __ cmov(kGreaterEqual, rdx, numerator);
2537 int shift = CTZ(imm);
2538 __ sarq(rdx, Immediate(shift));
2539
2540 if (imm < 0) {
2541 __ negq(rdx);
2542 }
2543
2544 __ movq(output_register, rdx);
2545 }
2546}
2547
2548void InstructionCodeGeneratorX86_64::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) {
2549 DCHECK(instruction->IsDiv() || instruction->IsRem());
2550
2551 LocationSummary* locations = instruction->GetLocations();
2552 Location second = locations->InAt(1);
2553
2554 CpuRegister numerator = instruction->IsDiv() ? locations->GetTemp(1).AsRegister<CpuRegister>()
2555 : locations->GetTemp(0).AsRegister<CpuRegister>();
2556 CpuRegister eax = locations->InAt(0).AsRegister<CpuRegister>();
2557 CpuRegister edx = instruction->IsDiv() ? locations->GetTemp(0).AsRegister<CpuRegister>()
2558 : locations->Out().AsRegister<CpuRegister>();
2559 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
2560
2561 DCHECK_EQ(RAX, eax.AsRegister());
2562 DCHECK_EQ(RDX, edx.AsRegister());
2563 if (instruction->IsDiv()) {
2564 DCHECK_EQ(RAX, out.AsRegister());
2565 } else {
2566 DCHECK_EQ(RDX, out.AsRegister());
2567 }
2568
2569 int64_t magic;
2570 int shift;
2571
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002572 // TODO: can these branches be written as one?
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002573 if (instruction->GetResultType() == Primitive::kPrimInt) {
2574 int imm = second.GetConstant()->AsIntConstant()->GetValue();
2575
2576 CalculateMagicAndShiftForDivRem(imm, false /* is_long */, &magic, &shift);
2577
2578 __ movl(numerator, eax);
2579
2580 Label no_div;
2581 Label end;
2582 __ testl(eax, eax);
2583 __ j(kNotEqual, &no_div);
2584
2585 __ xorl(out, out);
2586 __ jmp(&end);
2587
2588 __ Bind(&no_div);
2589
2590 __ movl(eax, Immediate(magic));
2591 __ imull(numerator);
2592
2593 if (imm > 0 && magic < 0) {
2594 __ addl(edx, numerator);
2595 } else if (imm < 0 && magic > 0) {
2596 __ subl(edx, numerator);
2597 }
2598
2599 if (shift != 0) {
2600 __ sarl(edx, Immediate(shift));
2601 }
2602
2603 __ movl(eax, edx);
2604 __ shrl(edx, Immediate(31));
2605 __ addl(edx, eax);
2606
2607 if (instruction->IsRem()) {
2608 __ movl(eax, numerator);
2609 __ imull(edx, Immediate(imm));
2610 __ subl(eax, edx);
2611 __ movl(edx, eax);
2612 } else {
2613 __ movl(eax, edx);
2614 }
2615 __ Bind(&end);
2616 } else {
2617 int64_t imm = second.GetConstant()->AsLongConstant()->GetValue();
2618
2619 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
2620
2621 CpuRegister rax = eax;
2622 CpuRegister rdx = edx;
2623
2624 CalculateMagicAndShiftForDivRem(imm, true /* is_long */, &magic, &shift);
2625
2626 // Save the numerator.
2627 __ movq(numerator, rax);
2628
2629 // RAX = magic
Mark Mendell92e83bf2015-05-07 11:25:03 -04002630 codegen_->Load64BitValue(rax, magic);
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002631
2632 // RDX:RAX = magic * numerator
2633 __ imulq(numerator);
2634
2635 if (imm > 0 && magic < 0) {
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002636 // RDX += numerator
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002637 __ addq(rdx, numerator);
2638 } else if (imm < 0 && magic > 0) {
2639 // RDX -= numerator
2640 __ subq(rdx, numerator);
2641 }
2642
2643 // Shift if needed.
2644 if (shift != 0) {
2645 __ sarq(rdx, Immediate(shift));
2646 }
2647
2648 // RDX += 1 if RDX < 0
2649 __ movq(rax, rdx);
2650 __ shrq(rdx, Immediate(63));
2651 __ addq(rdx, rax);
2652
2653 if (instruction->IsRem()) {
2654 __ movq(rax, numerator);
2655
2656 if (IsInt<32>(imm)) {
2657 __ imulq(rdx, Immediate(static_cast<int32_t>(imm)));
2658 } else {
Mark Mendell92e83bf2015-05-07 11:25:03 -04002659 __ imulq(rdx, codegen_->LiteralInt64Address(imm));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002660 }
2661
2662 __ subq(rax, rdx);
2663 __ movq(rdx, rax);
2664 } else {
2665 __ movq(rax, rdx);
2666 }
2667 }
2668}
2669
Calin Juravlebacfec32014-11-14 15:54:36 +00002670void InstructionCodeGeneratorX86_64::GenerateDivRemIntegral(HBinaryOperation* instruction) {
2671 DCHECK(instruction->IsDiv() || instruction->IsRem());
2672 Primitive::Type type = instruction->GetResultType();
2673 DCHECK(type == Primitive::kPrimInt || Primitive::kPrimLong);
2674
2675 bool is_div = instruction->IsDiv();
2676 LocationSummary* locations = instruction->GetLocations();
2677
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002678 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
2679 Location second = locations->InAt(1);
Calin Juravlebacfec32014-11-14 15:54:36 +00002680
Roland Levillain271ab9c2014-11-27 15:23:57 +00002681 DCHECK_EQ(RAX, locations->InAt(0).AsRegister<CpuRegister>().AsRegister());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002682 DCHECK_EQ(is_div ? RAX : RDX, out.AsRegister());
Calin Juravlebacfec32014-11-14 15:54:36 +00002683
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002684 if (second.IsConstant()) {
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002685 int64_t imm = Int64FromConstant(second.GetConstant());
Calin Juravlebacfec32014-11-14 15:54:36 +00002686
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002687 if (imm == 0) {
2688 // Do not generate anything. DivZeroCheck would prevent any code to be executed.
2689 } else if (imm == 1 || imm == -1) {
2690 DivRemOneOrMinusOne(instruction);
2691 } else if (instruction->IsDiv() && IsPowerOfTwo(std::abs(imm))) {
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002692 DivByPowerOfTwo(instruction->AsDiv());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002693 } else {
2694 DCHECK(imm <= -2 || imm >= 2);
2695 GenerateDivRemWithAnyConstant(instruction);
2696 }
Calin Juravlebacfec32014-11-14 15:54:36 +00002697 } else {
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002698 SlowPathCodeX86_64* slow_path =
2699 new (GetGraph()->GetArena()) DivRemMinusOneSlowPathX86_64(
2700 out.AsRegister(), type, is_div);
2701 codegen_->AddSlowPath(slow_path);
Calin Juravlebacfec32014-11-14 15:54:36 +00002702
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002703 CpuRegister second_reg = second.AsRegister<CpuRegister>();
2704 // 0x80000000(00000000)/-1 triggers an arithmetic exception!
2705 // Dividing by -1 is actually negation and -0x800000000(00000000) = 0x80000000(00000000)
2706 // so it's safe to just use negl instead of more complex comparisons.
2707 if (type == Primitive::kPrimInt) {
2708 __ cmpl(second_reg, Immediate(-1));
2709 __ j(kEqual, slow_path->GetEntryLabel());
2710 // edx:eax <- sign-extended of eax
2711 __ cdq();
2712 // eax = quotient, edx = remainder
2713 __ idivl(second_reg);
2714 } else {
2715 __ cmpq(second_reg, Immediate(-1));
2716 __ j(kEqual, slow_path->GetEntryLabel());
2717 // rdx:rax <- sign-extended of rax
2718 __ cqo();
2719 // rax = quotient, rdx = remainder
2720 __ idivq(second_reg);
2721 }
2722 __ Bind(slow_path->GetExitLabel());
2723 }
Calin Juravlebacfec32014-11-14 15:54:36 +00002724}
2725
Calin Juravle7c4954d2014-10-28 16:57:40 +00002726void LocationsBuilderX86_64::VisitDiv(HDiv* div) {
2727 LocationSummary* locations =
2728 new (GetGraph()->GetArena()) LocationSummary(div, LocationSummary::kNoCall);
2729 switch (div->GetResultType()) {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002730 case Primitive::kPrimInt:
2731 case Primitive::kPrimLong: {
Calin Juravled0d48522014-11-04 16:40:20 +00002732 locations->SetInAt(0, Location::RegisterLocation(RAX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002733 locations->SetInAt(1, Location::RegisterOrConstant(div->InputAt(1)));
Calin Juravled0d48522014-11-04 16:40:20 +00002734 locations->SetOut(Location::SameAsFirstInput());
2735 // Intel uses edx:eax as the dividend.
2736 locations->AddTemp(Location::RegisterLocation(RDX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002737 // We need to save the numerator while we tweak rax and rdx. As we are using imul in a way
2738 // which enforces results to be in RAX and RDX, things are simpler if we use RDX also as
2739 // output and request another temp.
2740 if (div->InputAt(1)->IsConstant()) {
2741 locations->AddTemp(Location::RequiresRegister());
2742 }
Calin Juravled0d48522014-11-04 16:40:20 +00002743 break;
2744 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002745
Calin Juravle7c4954d2014-10-28 16:57:40 +00002746 case Primitive::kPrimFloat:
2747 case Primitive::kPrimDouble: {
2748 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendellf55c3e02015-03-26 21:07:46 -04002749 locations->SetInAt(1, Location::Any());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002750 locations->SetOut(Location::SameAsFirstInput());
2751 break;
2752 }
2753
2754 default:
2755 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2756 }
2757}
2758
2759void InstructionCodeGeneratorX86_64::VisitDiv(HDiv* div) {
2760 LocationSummary* locations = div->GetLocations();
2761 Location first = locations->InAt(0);
2762 Location second = locations->InAt(1);
2763 DCHECK(first.Equals(locations->Out()));
2764
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002765 Primitive::Type type = div->GetResultType();
2766 switch (type) {
2767 case Primitive::kPrimInt:
2768 case Primitive::kPrimLong: {
Calin Juravlebacfec32014-11-14 15:54:36 +00002769 GenerateDivRemIntegral(div);
Calin Juravled0d48522014-11-04 16:40:20 +00002770 break;
2771 }
2772
Calin Juravle7c4954d2014-10-28 16:57:40 +00002773 case Primitive::kPrimFloat: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04002774 if (second.IsFpuRegister()) {
2775 __ divss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2776 } else if (second.IsConstant()) {
2777 __ divss(first.AsFpuRegister<XmmRegister>(),
2778 codegen_->LiteralFloatAddress(second.GetConstant()->AsFloatConstant()->GetValue()));
2779 } else {
2780 DCHECK(second.IsStackSlot());
2781 __ divss(first.AsFpuRegister<XmmRegister>(),
2782 Address(CpuRegister(RSP), second.GetStackIndex()));
2783 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00002784 break;
2785 }
2786
2787 case Primitive::kPrimDouble: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04002788 if (second.IsFpuRegister()) {
2789 __ divsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2790 } else if (second.IsConstant()) {
2791 __ divsd(first.AsFpuRegister<XmmRegister>(),
2792 codegen_->LiteralDoubleAddress(second.GetConstant()->AsDoubleConstant()->GetValue()));
2793 } else {
2794 DCHECK(second.IsDoubleStackSlot());
2795 __ divsd(first.AsFpuRegister<XmmRegister>(),
2796 Address(CpuRegister(RSP), second.GetStackIndex()));
2797 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00002798 break;
2799 }
2800
2801 default:
2802 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2803 }
2804}
2805
Calin Juravlebacfec32014-11-14 15:54:36 +00002806void LocationsBuilderX86_64::VisitRem(HRem* rem) {
Calin Juravled2ec87d2014-12-08 14:24:46 +00002807 Primitive::Type type = rem->GetResultType();
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002808 LocationSummary* locations =
2809 new (GetGraph()->GetArena()) LocationSummary(rem, LocationSummary::kNoCall);
Calin Juravled2ec87d2014-12-08 14:24:46 +00002810
2811 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00002812 case Primitive::kPrimInt:
2813 case Primitive::kPrimLong: {
2814 locations->SetInAt(0, Location::RegisterLocation(RAX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002815 locations->SetInAt(1, Location::RegisterOrConstant(rem->InputAt(1)));
Calin Juravlebacfec32014-11-14 15:54:36 +00002816 // Intel uses rdx:rax as the dividend and puts the remainder in rdx
2817 locations->SetOut(Location::RegisterLocation(RDX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002818 // We need to save the numerator while we tweak eax and edx. As we are using imul in a way
2819 // which enforces results to be in RAX and RDX, things are simpler if we use EAX also as
2820 // output and request another temp.
2821 if (rem->InputAt(1)->IsConstant()) {
2822 locations->AddTemp(Location::RequiresRegister());
2823 }
Calin Juravlebacfec32014-11-14 15:54:36 +00002824 break;
2825 }
2826
2827 case Primitive::kPrimFloat:
2828 case Primitive::kPrimDouble: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002829 locations->SetInAt(0, Location::Any());
2830 locations->SetInAt(1, Location::Any());
2831 locations->SetOut(Location::RequiresFpuRegister());
2832 locations->AddTemp(Location::RegisterLocation(RAX));
Calin Juravlebacfec32014-11-14 15:54:36 +00002833 break;
2834 }
2835
2836 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00002837 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00002838 }
2839}
2840
2841void InstructionCodeGeneratorX86_64::VisitRem(HRem* rem) {
2842 Primitive::Type type = rem->GetResultType();
2843 switch (type) {
2844 case Primitive::kPrimInt:
2845 case Primitive::kPrimLong: {
2846 GenerateDivRemIntegral(rem);
2847 break;
2848 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002849 case Primitive::kPrimFloat:
Calin Juravled2ec87d2014-12-08 14:24:46 +00002850 case Primitive::kPrimDouble: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002851 GenerateRemFP(rem);
Calin Juravled2ec87d2014-12-08 14:24:46 +00002852 break;
2853 }
Calin Juravlebacfec32014-11-14 15:54:36 +00002854 default:
2855 LOG(FATAL) << "Unexpected rem type " << rem->GetResultType();
2856 }
2857}
2858
Calin Juravled0d48522014-11-04 16:40:20 +00002859void LocationsBuilderX86_64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
2860 LocationSummary* locations =
2861 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
2862 locations->SetInAt(0, Location::Any());
2863 if (instruction->HasUses()) {
2864 locations->SetOut(Location::SameAsFirstInput());
2865 }
2866}
2867
2868void InstructionCodeGeneratorX86_64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
2869 SlowPathCodeX86_64* slow_path =
2870 new (GetGraph()->GetArena()) DivZeroCheckSlowPathX86_64(instruction);
2871 codegen_->AddSlowPath(slow_path);
2872
2873 LocationSummary* locations = instruction->GetLocations();
2874 Location value = locations->InAt(0);
2875
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002876 switch (instruction->GetType()) {
2877 case Primitive::kPrimInt: {
2878 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002879 __ testl(value.AsRegister<CpuRegister>(), value.AsRegister<CpuRegister>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002880 __ j(kEqual, slow_path->GetEntryLabel());
2881 } else if (value.IsStackSlot()) {
2882 __ cmpl(Address(CpuRegister(RSP), value.GetStackIndex()), Immediate(0));
2883 __ j(kEqual, slow_path->GetEntryLabel());
2884 } else {
2885 DCHECK(value.IsConstant()) << value;
2886 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
2887 __ jmp(slow_path->GetEntryLabel());
2888 }
2889 }
2890 break;
Calin Juravled0d48522014-11-04 16:40:20 +00002891 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002892 case Primitive::kPrimLong: {
2893 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002894 __ testq(value.AsRegister<CpuRegister>(), value.AsRegister<CpuRegister>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002895 __ j(kEqual, slow_path->GetEntryLabel());
2896 } else if (value.IsDoubleStackSlot()) {
2897 __ cmpq(Address(CpuRegister(RSP), value.GetStackIndex()), Immediate(0));
2898 __ j(kEqual, slow_path->GetEntryLabel());
2899 } else {
2900 DCHECK(value.IsConstant()) << value;
2901 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
2902 __ jmp(slow_path->GetEntryLabel());
2903 }
2904 }
2905 break;
2906 }
2907 default:
2908 LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
Calin Juravled0d48522014-11-04 16:40:20 +00002909 }
Calin Juravled0d48522014-11-04 16:40:20 +00002910}
2911
Calin Juravle9aec02f2014-11-18 23:06:35 +00002912void LocationsBuilderX86_64::HandleShift(HBinaryOperation* op) {
2913 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
2914
2915 LocationSummary* locations =
2916 new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
2917
2918 switch (op->GetResultType()) {
2919 case Primitive::kPrimInt:
2920 case Primitive::kPrimLong: {
2921 locations->SetInAt(0, Location::RequiresRegister());
2922 // The shift count needs to be in CL.
2923 locations->SetInAt(1, Location::ByteRegisterOrConstant(RCX, op->InputAt(1)));
2924 locations->SetOut(Location::SameAsFirstInput());
2925 break;
2926 }
2927 default:
2928 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
2929 }
2930}
2931
2932void InstructionCodeGeneratorX86_64::HandleShift(HBinaryOperation* op) {
2933 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
2934
2935 LocationSummary* locations = op->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002936 CpuRegister first_reg = locations->InAt(0).AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002937 Location second = locations->InAt(1);
2938
2939 switch (op->GetResultType()) {
2940 case Primitive::kPrimInt: {
2941 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002942 CpuRegister second_reg = second.AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002943 if (op->IsShl()) {
2944 __ shll(first_reg, second_reg);
2945 } else if (op->IsShr()) {
2946 __ sarl(first_reg, second_reg);
2947 } else {
2948 __ shrl(first_reg, second_reg);
2949 }
2950 } else {
Nicolas Geoffray486cc192014-12-08 18:00:55 +00002951 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxIntShiftValue);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002952 if (op->IsShl()) {
2953 __ shll(first_reg, imm);
2954 } else if (op->IsShr()) {
2955 __ sarl(first_reg, imm);
2956 } else {
2957 __ shrl(first_reg, imm);
2958 }
2959 }
2960 break;
2961 }
2962 case Primitive::kPrimLong: {
2963 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002964 CpuRegister second_reg = second.AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002965 if (op->IsShl()) {
2966 __ shlq(first_reg, second_reg);
2967 } else if (op->IsShr()) {
2968 __ sarq(first_reg, second_reg);
2969 } else {
2970 __ shrq(first_reg, second_reg);
2971 }
2972 } else {
Nicolas Geoffray486cc192014-12-08 18:00:55 +00002973 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxLongShiftValue);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002974 if (op->IsShl()) {
2975 __ shlq(first_reg, imm);
2976 } else if (op->IsShr()) {
2977 __ sarq(first_reg, imm);
2978 } else {
2979 __ shrq(first_reg, imm);
2980 }
2981 }
2982 break;
2983 }
2984 default:
2985 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
2986 }
2987}
2988
2989void LocationsBuilderX86_64::VisitShl(HShl* shl) {
2990 HandleShift(shl);
2991}
2992
2993void InstructionCodeGeneratorX86_64::VisitShl(HShl* shl) {
2994 HandleShift(shl);
2995}
2996
2997void LocationsBuilderX86_64::VisitShr(HShr* shr) {
2998 HandleShift(shr);
2999}
3000
3001void InstructionCodeGeneratorX86_64::VisitShr(HShr* shr) {
3002 HandleShift(shr);
3003}
3004
3005void LocationsBuilderX86_64::VisitUShr(HUShr* ushr) {
3006 HandleShift(ushr);
3007}
3008
3009void InstructionCodeGeneratorX86_64::VisitUShr(HUShr* ushr) {
3010 HandleShift(ushr);
3011}
3012
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003013void LocationsBuilderX86_64::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003014 LocationSummary* locations =
3015 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01003016 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003017 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3018 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
3019 locations->SetOut(Location::RegisterLocation(RAX));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003020}
3021
3022void InstructionCodeGeneratorX86_64::VisitNewInstance(HNewInstance* instruction) {
3023 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003024 codegen_->LoadCurrentMethod(CpuRegister(calling_convention.GetRegisterAt(1)));
Mark Mendell92e83bf2015-05-07 11:25:03 -04003025 codegen_->Load64BitValue(CpuRegister(calling_convention.GetRegisterAt(0)),
3026 instruction->GetTypeIndex());
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +00003027 __ gs()->call(
3028 Address::Absolute(GetThreadOffset<kX86_64WordSize>(instruction->GetEntrypoint()), true));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003029
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01003030 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray39468442014-09-02 15:17:15 +01003031 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003032}
3033
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003034void LocationsBuilderX86_64::VisitNewArray(HNewArray* instruction) {
3035 LocationSummary* locations =
3036 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
3037 InvokeRuntimeCallingConvention calling_convention;
3038 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08003039 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003040 locations->SetOut(Location::RegisterLocation(RAX));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08003041 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003042}
3043
3044void InstructionCodeGeneratorX86_64::VisitNewArray(HNewArray* instruction) {
3045 InvokeRuntimeCallingConvention calling_convention;
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08003046 codegen_->LoadCurrentMethod(CpuRegister(calling_convention.GetRegisterAt(2)));
Mark Mendell92e83bf2015-05-07 11:25:03 -04003047 codegen_->Load64BitValue(CpuRegister(calling_convention.GetRegisterAt(0)),
3048 instruction->GetTypeIndex());
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003049
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +00003050 __ gs()->call(
3051 Address::Absolute(GetThreadOffset<kX86_64WordSize>(instruction->GetEntrypoint()), true));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003052
3053 DCHECK(!codegen_->IsLeafMethod());
3054 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3055}
3056
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003057void LocationsBuilderX86_64::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003058 LocationSummary* locations =
3059 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003060 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
3061 if (location.IsStackSlot()) {
3062 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
3063 } else if (location.IsDoubleStackSlot()) {
3064 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
3065 }
3066 locations->SetOut(location);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003067}
3068
3069void InstructionCodeGeneratorX86_64::VisitParameterValue(HParameterValue* instruction) {
3070 // Nothing to do, the parameter is already at its location.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003071 UNUSED(instruction);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003072}
3073
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003074void LocationsBuilderX86_64::VisitNot(HNot* not_) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003075 LocationSummary* locations =
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003076 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003077 locations->SetInAt(0, Location::RequiresRegister());
3078 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003079}
3080
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003081void InstructionCodeGeneratorX86_64::VisitNot(HNot* not_) {
3082 LocationSummary* locations = not_->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003083 DCHECK_EQ(locations->InAt(0).AsRegister<CpuRegister>().AsRegister(),
3084 locations->Out().AsRegister<CpuRegister>().AsRegister());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003085 Location out = locations->Out();
Nicolas Geoffrayd8ef2e92015-02-24 16:02:06 +00003086 switch (not_->GetResultType()) {
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003087 case Primitive::kPrimInt:
Roland Levillain271ab9c2014-11-27 15:23:57 +00003088 __ notl(out.AsRegister<CpuRegister>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003089 break;
3090
3091 case Primitive::kPrimLong:
Roland Levillain271ab9c2014-11-27 15:23:57 +00003092 __ notq(out.AsRegister<CpuRegister>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003093 break;
3094
3095 default:
3096 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
3097 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003098}
3099
David Brazdil66d126e2015-04-03 16:02:44 +01003100void LocationsBuilderX86_64::VisitBooleanNot(HBooleanNot* bool_not) {
3101 LocationSummary* locations =
3102 new (GetGraph()->GetArena()) LocationSummary(bool_not, LocationSummary::kNoCall);
3103 locations->SetInAt(0, Location::RequiresRegister());
3104 locations->SetOut(Location::SameAsFirstInput());
3105}
3106
3107void InstructionCodeGeneratorX86_64::VisitBooleanNot(HBooleanNot* bool_not) {
David Brazdil66d126e2015-04-03 16:02:44 +01003108 LocationSummary* locations = bool_not->GetLocations();
3109 DCHECK_EQ(locations->InAt(0).AsRegister<CpuRegister>().AsRegister(),
3110 locations->Out().AsRegister<CpuRegister>().AsRegister());
3111 Location out = locations->Out();
3112 __ xorl(out.AsRegister<CpuRegister>(), Immediate(1));
3113}
3114
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003115void LocationsBuilderX86_64::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003116 LocationSummary* locations =
3117 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003118 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
3119 locations->SetInAt(i, Location::Any());
3120 }
3121 locations->SetOut(Location::Any());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003122}
3123
3124void InstructionCodeGeneratorX86_64::VisitPhi(HPhi* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003125 UNUSED(instruction);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003126 LOG(FATAL) << "Unimplemented";
3127}
3128
Calin Juravle52c48962014-12-16 17:02:57 +00003129void InstructionCodeGeneratorX86_64::GenerateMemoryBarrier(MemBarrierKind kind) {
3130 /*
3131 * According to the JSR-133 Cookbook, for x86 only StoreLoad/AnyAny barriers need memory fence.
3132 * All other barriers (LoadAny, AnyStore, StoreStore) are nops due to the x86 memory model.
3133 * For those cases, all we need to ensure is that there is a scheduling barrier in place.
3134 */
3135 switch (kind) {
3136 case MemBarrierKind::kAnyAny: {
3137 __ mfence();
3138 break;
3139 }
3140 case MemBarrierKind::kAnyStore:
3141 case MemBarrierKind::kLoadAny:
3142 case MemBarrierKind::kStoreStore: {
3143 // nop
3144 break;
3145 }
3146 default:
3147 LOG(FATAL) << "Unexpected memory barier " << kind;
3148 }
3149}
3150
3151void LocationsBuilderX86_64::HandleFieldGet(HInstruction* instruction) {
3152 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
3153
Nicolas Geoffray39468442014-09-02 15:17:15 +01003154 LocationSummary* locations =
3155 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Calin Juravle52c48962014-12-16 17:02:57 +00003156 locations->SetInAt(0, Location::RequiresRegister());
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003157 if (Primitive::IsFloatingPointType(instruction->GetType())) {
3158 locations->SetOut(Location::RequiresFpuRegister());
3159 } else {
3160 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3161 }
Calin Juravle52c48962014-12-16 17:02:57 +00003162}
3163
3164void InstructionCodeGeneratorX86_64::HandleFieldGet(HInstruction* instruction,
3165 const FieldInfo& field_info) {
3166 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
3167
3168 LocationSummary* locations = instruction->GetLocations();
3169 CpuRegister base = locations->InAt(0).AsRegister<CpuRegister>();
3170 Location out = locations->Out();
3171 bool is_volatile = field_info.IsVolatile();
3172 Primitive::Type field_type = field_info.GetFieldType();
3173 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
3174
3175 switch (field_type) {
3176 case Primitive::kPrimBoolean: {
3177 __ movzxb(out.AsRegister<CpuRegister>(), Address(base, offset));
3178 break;
3179 }
3180
3181 case Primitive::kPrimByte: {
3182 __ movsxb(out.AsRegister<CpuRegister>(), Address(base, offset));
3183 break;
3184 }
3185
3186 case Primitive::kPrimShort: {
3187 __ movsxw(out.AsRegister<CpuRegister>(), Address(base, offset));
3188 break;
3189 }
3190
3191 case Primitive::kPrimChar: {
3192 __ movzxw(out.AsRegister<CpuRegister>(), Address(base, offset));
3193 break;
3194 }
3195
3196 case Primitive::kPrimInt:
3197 case Primitive::kPrimNot: {
3198 __ movl(out.AsRegister<CpuRegister>(), Address(base, offset));
3199 break;
3200 }
3201
3202 case Primitive::kPrimLong: {
3203 __ movq(out.AsRegister<CpuRegister>(), Address(base, offset));
3204 break;
3205 }
3206
3207 case Primitive::kPrimFloat: {
3208 __ movss(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
3209 break;
3210 }
3211
3212 case Primitive::kPrimDouble: {
3213 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
3214 break;
3215 }
3216
3217 case Primitive::kPrimVoid:
3218 LOG(FATAL) << "Unreachable type " << field_type;
3219 UNREACHABLE();
3220 }
3221
Calin Juravle77520bc2015-01-12 18:45:46 +00003222 codegen_->MaybeRecordImplicitNullCheck(instruction);
3223
Calin Juravle52c48962014-12-16 17:02:57 +00003224 if (is_volatile) {
3225 GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
3226 }
3227}
3228
3229void LocationsBuilderX86_64::HandleFieldSet(HInstruction* instruction,
3230 const FieldInfo& field_info) {
3231 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3232
3233 LocationSummary* locations =
3234 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003235 bool needs_write_barrier =
Calin Juravle52c48962014-12-16 17:02:57 +00003236 CodeGenerator::StoreNeedsWriteBarrier(field_info.GetFieldType(), instruction->InputAt(1));
3237
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003238 locations->SetInAt(0, Location::RequiresRegister());
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003239 if (Primitive::IsFloatingPointType(instruction->InputAt(1)->GetType())) {
3240 locations->SetInAt(1, Location::RequiresFpuRegister());
3241 } else {
Mark Mendell40741f32015-04-20 22:10:34 -04003242 locations->SetInAt(1, Location::RegisterOrInt32LongConstant(instruction->InputAt(1)));
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003243 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003244 if (needs_write_barrier) {
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01003245 // Temporary registers for the write barrier.
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003246 locations->AddTemp(Location::RequiresRegister());
3247 locations->AddTemp(Location::RequiresRegister());
3248 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003249}
3250
Calin Juravle52c48962014-12-16 17:02:57 +00003251void InstructionCodeGeneratorX86_64::HandleFieldSet(HInstruction* instruction,
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003252 const FieldInfo& field_info,
3253 bool value_can_be_null) {
Calin Juravle52c48962014-12-16 17:02:57 +00003254 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3255
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003256 LocationSummary* locations = instruction->GetLocations();
Calin Juravle52c48962014-12-16 17:02:57 +00003257 CpuRegister base = locations->InAt(0).AsRegister<CpuRegister>();
3258 Location value = locations->InAt(1);
3259 bool is_volatile = field_info.IsVolatile();
3260 Primitive::Type field_type = field_info.GetFieldType();
3261 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
3262
3263 if (is_volatile) {
3264 GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
3265 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003266
3267 switch (field_type) {
3268 case Primitive::kPrimBoolean:
3269 case Primitive::kPrimByte: {
Mark Mendell40741f32015-04-20 22:10:34 -04003270 if (value.IsConstant()) {
3271 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
3272 __ movb(Address(base, offset), Immediate(v));
3273 } else {
3274 __ movb(Address(base, offset), value.AsRegister<CpuRegister>());
3275 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003276 break;
3277 }
3278
3279 case Primitive::kPrimShort:
3280 case Primitive::kPrimChar: {
Mark Mendell40741f32015-04-20 22:10:34 -04003281 if (value.IsConstant()) {
3282 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
3283 __ movw(Address(base, offset), Immediate(v));
3284 } else {
3285 __ movw(Address(base, offset), value.AsRegister<CpuRegister>());
3286 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003287 break;
3288 }
3289
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003290 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003291 case Primitive::kPrimNot: {
Mark Mendell40741f32015-04-20 22:10:34 -04003292 if (value.IsConstant()) {
3293 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
3294 __ movw(Address(base, offset), Immediate(v));
3295 } else {
3296 __ movl(Address(base, offset), value.AsRegister<CpuRegister>());
3297 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003298 break;
3299 }
3300
3301 case Primitive::kPrimLong: {
Mark Mendell40741f32015-04-20 22:10:34 -04003302 if (value.IsConstant()) {
3303 int64_t v = value.GetConstant()->AsLongConstant()->GetValue();
3304 DCHECK(IsInt<32>(v));
3305 int32_t v_32 = v;
3306 __ movq(Address(base, offset), Immediate(v_32));
3307 } else {
3308 __ movq(Address(base, offset), value.AsRegister<CpuRegister>());
3309 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003310 break;
3311 }
3312
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003313 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00003314 __ movss(Address(base, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003315 break;
3316 }
3317
3318 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00003319 __ movsd(Address(base, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003320 break;
3321 }
3322
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003323 case Primitive::kPrimVoid:
3324 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003325 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003326 }
Calin Juravle52c48962014-12-16 17:02:57 +00003327
Calin Juravle77520bc2015-01-12 18:45:46 +00003328 codegen_->MaybeRecordImplicitNullCheck(instruction);
3329
3330 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
3331 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
3332 CpuRegister card = locations->GetTemp(1).AsRegister<CpuRegister>();
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003333 codegen_->MarkGCCard(temp, card, base, value.AsRegister<CpuRegister>(), value_can_be_null);
Calin Juravle77520bc2015-01-12 18:45:46 +00003334 }
3335
Calin Juravle52c48962014-12-16 17:02:57 +00003336 if (is_volatile) {
3337 GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
3338 }
3339}
3340
3341void LocationsBuilderX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
3342 HandleFieldSet(instruction, instruction->GetFieldInfo());
3343}
3344
3345void InstructionCodeGeneratorX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003346 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003347}
3348
3349void LocationsBuilderX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Calin Juravle52c48962014-12-16 17:02:57 +00003350 HandleFieldGet(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003351}
3352
3353void InstructionCodeGeneratorX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Calin Juravle52c48962014-12-16 17:02:57 +00003354 HandleFieldGet(instruction, instruction->GetFieldInfo());
3355}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003356
Calin Juravle52c48962014-12-16 17:02:57 +00003357void LocationsBuilderX86_64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
3358 HandleFieldGet(instruction);
3359}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003360
Calin Juravle52c48962014-12-16 17:02:57 +00003361void InstructionCodeGeneratorX86_64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
3362 HandleFieldGet(instruction, instruction->GetFieldInfo());
3363}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003364
Calin Juravle52c48962014-12-16 17:02:57 +00003365void LocationsBuilderX86_64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
3366 HandleFieldSet(instruction, instruction->GetFieldInfo());
3367}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003368
Calin Juravle52c48962014-12-16 17:02:57 +00003369void InstructionCodeGeneratorX86_64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003370 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003371}
3372
3373void LocationsBuilderX86_64::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003374 LocationSummary* locations =
3375 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003376 Location loc = codegen_->GetCompilerOptions().GetImplicitNullChecks()
3377 ? Location::RequiresRegister()
3378 : Location::Any();
3379 locations->SetInAt(0, loc);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003380 if (instruction->HasUses()) {
3381 locations->SetOut(Location::SameAsFirstInput());
3382 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003383}
3384
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003385void InstructionCodeGeneratorX86_64::GenerateImplicitNullCheck(HNullCheck* instruction) {
Calin Juravle77520bc2015-01-12 18:45:46 +00003386 if (codegen_->CanMoveNullCheckToUser(instruction)) {
3387 return;
3388 }
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003389 LocationSummary* locations = instruction->GetLocations();
3390 Location obj = locations->InAt(0);
3391
3392 __ testl(CpuRegister(RAX), Address(obj.AsRegister<CpuRegister>(), 0));
3393 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3394}
3395
3396void InstructionCodeGeneratorX86_64::GenerateExplicitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +01003397 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathX86_64(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003398 codegen_->AddSlowPath(slow_path);
3399
3400 LocationSummary* locations = instruction->GetLocations();
3401 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003402
3403 if (obj.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00003404 __ testl(obj.AsRegister<CpuRegister>(), obj.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003405 } else if (obj.IsStackSlot()) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003406 __ cmpl(Address(CpuRegister(RSP), obj.GetStackIndex()), Immediate(0));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003407 } else {
3408 DCHECK(obj.IsConstant()) << obj;
3409 DCHECK_EQ(obj.GetConstant()->AsIntConstant()->GetValue(), 0);
3410 __ jmp(slow_path->GetEntryLabel());
3411 return;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003412 }
3413 __ j(kEqual, slow_path->GetEntryLabel());
3414}
3415
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003416void InstructionCodeGeneratorX86_64::VisitNullCheck(HNullCheck* instruction) {
3417 if (codegen_->GetCompilerOptions().GetImplicitNullChecks()) {
3418 GenerateImplicitNullCheck(instruction);
3419 } else {
3420 GenerateExplicitNullCheck(instruction);
3421 }
3422}
3423
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003424void LocationsBuilderX86_64::VisitArrayGet(HArrayGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003425 LocationSummary* locations =
3426 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003427 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell40741f32015-04-20 22:10:34 -04003428 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003429 if (Primitive::IsFloatingPointType(instruction->GetType())) {
3430 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
3431 } else {
3432 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3433 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003434}
3435
3436void InstructionCodeGeneratorX86_64::VisitArrayGet(HArrayGet* instruction) {
3437 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003438 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003439 Location index = locations->InAt(1);
3440
3441 switch (instruction->GetType()) {
3442 case Primitive::kPrimBoolean: {
3443 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003444 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003445 if (index.IsConstant()) {
3446 __ movzxb(out, Address(obj,
3447 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
3448 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003449 __ movzxb(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003450 }
3451 break;
3452 }
3453
3454 case Primitive::kPrimByte: {
3455 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003456 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003457 if (index.IsConstant()) {
3458 __ movsxb(out, Address(obj,
3459 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
3460 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003461 __ movsxb(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003462 }
3463 break;
3464 }
3465
3466 case Primitive::kPrimShort: {
3467 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003468 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003469 if (index.IsConstant()) {
3470 __ movsxw(out, Address(obj,
3471 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
3472 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003473 __ movsxw(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003474 }
3475 break;
3476 }
3477
3478 case Primitive::kPrimChar: {
3479 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003480 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003481 if (index.IsConstant()) {
3482 __ movzxw(out, Address(obj,
3483 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
3484 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003485 __ movzxw(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003486 }
3487 break;
3488 }
3489
3490 case Primitive::kPrimInt:
3491 case Primitive::kPrimNot: {
3492 DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t));
3493 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003494 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003495 if (index.IsConstant()) {
3496 __ movl(out, Address(obj,
3497 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
3498 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003499 __ movl(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003500 }
3501 break;
3502 }
3503
3504 case Primitive::kPrimLong: {
3505 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003506 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003507 if (index.IsConstant()) {
3508 __ movq(out, Address(obj,
3509 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
3510 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003511 __ movq(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003512 }
3513 break;
3514 }
3515
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003516 case Primitive::kPrimFloat: {
3517 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003518 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003519 if (index.IsConstant()) {
3520 __ movss(out, Address(obj,
3521 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
3522 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003523 __ movss(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003524 }
3525 break;
3526 }
3527
3528 case Primitive::kPrimDouble: {
3529 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003530 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003531 if (index.IsConstant()) {
3532 __ movsd(out, Address(obj,
3533 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
3534 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003535 __ movsd(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003536 }
3537 break;
3538 }
3539
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003540 case Primitive::kPrimVoid:
3541 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07003542 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003543 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003544 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003545}
3546
3547void LocationsBuilderX86_64::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003548 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003549
3550 bool needs_write_barrier =
3551 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
3552 bool needs_runtime_call = instruction->NeedsTypeCheck();
3553
Nicolas Geoffray39468442014-09-02 15:17:15 +01003554 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003555 instruction, needs_runtime_call ? LocationSummary::kCall : LocationSummary::kNoCall);
3556 if (needs_runtime_call) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003557 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003558 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3559 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
3560 locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003561 } else {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003562 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01003563 locations->SetInAt(
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003564 1, Location::RegisterOrConstant(instruction->InputAt(1)));
3565 locations->SetInAt(2, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003566 if (value_type == Primitive::kPrimLong) {
Mark Mendell40741f32015-04-20 22:10:34 -04003567 locations->SetInAt(2, Location::RegisterOrInt32LongConstant(instruction->InputAt(2)));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003568 } else if (value_type == Primitive::kPrimFloat || value_type == Primitive::kPrimDouble) {
3569 locations->SetInAt(2, Location::RequiresFpuRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003570 } else {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003571 locations->SetInAt(2, Location::RegisterOrConstant(instruction->InputAt(2)));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003572 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003573
3574 if (needs_write_barrier) {
3575 // Temporary registers for the write barrier.
3576 locations->AddTemp(Location::RequiresRegister());
3577 locations->AddTemp(Location::RequiresRegister());
3578 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003579 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003580}
3581
3582void InstructionCodeGeneratorX86_64::VisitArraySet(HArraySet* instruction) {
3583 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003584 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003585 Location index = locations->InAt(1);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003586 Location value = locations->InAt(2);
Nicolas Geoffray39468442014-09-02 15:17:15 +01003587 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003588 bool needs_runtime_call = locations->WillCall();
3589 bool needs_write_barrier =
3590 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003591
3592 switch (value_type) {
3593 case Primitive::kPrimBoolean:
3594 case Primitive::kPrimByte: {
3595 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003596 if (index.IsConstant()) {
3597 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003598 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003599 __ movb(Address(obj, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003600 } else {
Roland Levillain199f3362014-11-27 17:15:16 +00003601 __ movb(Address(obj, offset),
3602 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003603 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003604 } else {
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003605 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003606 __ movb(Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset),
3607 value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003608 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003609 __ movb(Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003610 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3611 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003612 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003613 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003614 break;
3615 }
3616
3617 case Primitive::kPrimShort:
3618 case Primitive::kPrimChar: {
3619 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003620 if (index.IsConstant()) {
3621 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003622 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003623 __ movw(Address(obj, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003624 } else {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003625 DCHECK(value.IsConstant()) << value;
Roland Levillain199f3362014-11-27 17:15:16 +00003626 __ movw(Address(obj, offset),
3627 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003628 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003629 } else {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003630 DCHECK(index.IsRegister()) << index;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003631 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003632 __ movw(Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset),
3633 value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003634 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003635 DCHECK(value.IsConstant()) << value;
Roland Levillain271ab9c2014-11-27 15:23:57 +00003636 __ movw(Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003637 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3638 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003639 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003640 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003641 break;
3642 }
3643
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003644 case Primitive::kPrimInt:
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003645 case Primitive::kPrimNot: {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003646 if (!needs_runtime_call) {
3647 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
3648 if (index.IsConstant()) {
3649 size_t offset =
3650 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
3651 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003652 __ movl(Address(obj, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003653 } else {
3654 DCHECK(value.IsConstant()) << value;
Mark Mendell40741f32015-04-20 22:10:34 -04003655 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
3656 __ movl(Address(obj, offset), Immediate(v));
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003657 }
3658 } else {
3659 DCHECK(index.IsRegister()) << index;
3660 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003661 __ movl(Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset),
3662 value.AsRegister<CpuRegister>());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003663 } else {
3664 DCHECK(value.IsConstant()) << value;
Mark Mendell40741f32015-04-20 22:10:34 -04003665 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003666 __ movl(Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset),
Mark Mendell40741f32015-04-20 22:10:34 -04003667 Immediate(v));
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003668 }
3669 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003670 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003671 if (needs_write_barrier) {
3672 DCHECK_EQ(value_type, Primitive::kPrimNot);
Roland Levillain271ab9c2014-11-27 15:23:57 +00003673 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
3674 CpuRegister card = locations->GetTemp(1).AsRegister<CpuRegister>();
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003675 codegen_->MarkGCCard(
3676 temp, card, obj, value.AsRegister<CpuRegister>(), instruction->GetValueCanBeNull());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003677 }
3678 } else {
3679 DCHECK_EQ(value_type, Primitive::kPrimNot);
Roland Levillain199f3362014-11-27 17:15:16 +00003680 __ gs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pAputObject),
3681 true));
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003682 DCHECK(!codegen_->IsLeafMethod());
3683 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3684 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003685 break;
3686 }
3687
3688 case Primitive::kPrimLong: {
3689 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003690 if (index.IsConstant()) {
3691 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Mark Mendell40741f32015-04-20 22:10:34 -04003692 if (value.IsRegister()) {
3693 __ movq(Address(obj, offset), value.AsRegister<CpuRegister>());
3694 } else {
3695 int64_t v = value.GetConstant()->AsLongConstant()->GetValue();
3696 DCHECK(IsInt<32>(v));
3697 int32_t v_32 = v;
3698 __ movq(Address(obj, offset), Immediate(v_32));
3699 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003700 } else {
Mark Mendell40741f32015-04-20 22:10:34 -04003701 if (value.IsRegister()) {
3702 __ movq(Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset),
3703 value.AsRegister<CpuRegister>());
3704 } else {
3705 int64_t v = value.GetConstant()->AsLongConstant()->GetValue();
3706 DCHECK(IsInt<32>(v));
3707 int32_t v_32 = v;
3708 __ movq(Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset),
3709 Immediate(v_32));
3710 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003711 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003712 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003713 break;
3714 }
3715
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003716 case Primitive::kPrimFloat: {
3717 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
3718 if (index.IsConstant()) {
3719 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
3720 DCHECK(value.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003721 __ movss(Address(obj, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003722 } else {
3723 DCHECK(value.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003724 __ movss(Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset),
3725 value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003726 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003727 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003728 break;
3729 }
3730
3731 case Primitive::kPrimDouble: {
3732 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
3733 if (index.IsConstant()) {
3734 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
3735 DCHECK(value.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003736 __ movsd(Address(obj, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003737 } else {
3738 DCHECK(value.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003739 __ movsd(Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset),
3740 value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003741 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003742 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003743 break;
3744 }
3745
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003746 case Primitive::kPrimVoid:
3747 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07003748 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003749 }
3750}
3751
3752void LocationsBuilderX86_64::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003753 LocationSummary* locations =
3754 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003755 locations->SetInAt(0, Location::RequiresRegister());
3756 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003757}
3758
3759void InstructionCodeGeneratorX86_64::VisitArrayLength(HArrayLength* instruction) {
3760 LocationSummary* locations = instruction->GetLocations();
3761 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003762 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
3763 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003764 __ movl(out, Address(obj, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00003765 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003766}
3767
3768void LocationsBuilderX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003769 LocationSummary* locations =
3770 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Mark Mendellf60c90b2015-03-04 15:12:59 -05003771 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
Mark Mendell99dbd682015-04-22 16:18:52 -04003772 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003773 if (instruction->HasUses()) {
3774 locations->SetOut(Location::SameAsFirstInput());
3775 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003776}
3777
3778void InstructionCodeGeneratorX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
3779 LocationSummary* locations = instruction->GetLocations();
Mark Mendellf60c90b2015-03-04 15:12:59 -05003780 Location index_loc = locations->InAt(0);
3781 Location length_loc = locations->InAt(1);
3782 SlowPathCodeX86_64* slow_path =
3783 new (GetGraph()->GetArena()) BoundsCheckSlowPathX86_64(instruction, index_loc, length_loc);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003784
Mark Mendell99dbd682015-04-22 16:18:52 -04003785 if (length_loc.IsConstant()) {
3786 int32_t length = CodeGenerator::GetInt32ValueOf(length_loc.GetConstant());
3787 if (index_loc.IsConstant()) {
3788 // BCE will remove the bounds check if we are guarenteed to pass.
3789 int32_t index = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
3790 if (index < 0 || index >= length) {
3791 codegen_->AddSlowPath(slow_path);
3792 __ jmp(slow_path->GetEntryLabel());
3793 } else {
3794 // Some optimization after BCE may have generated this, and we should not
3795 // generate a bounds check if it is a valid range.
3796 }
3797 return;
3798 }
3799
3800 // We have to reverse the jump condition because the length is the constant.
3801 CpuRegister index_reg = index_loc.AsRegister<CpuRegister>();
3802 __ cmpl(index_reg, Immediate(length));
3803 codegen_->AddSlowPath(slow_path);
3804 __ j(kAboveEqual, slow_path->GetEntryLabel());
Mark Mendellf60c90b2015-03-04 15:12:59 -05003805 } else {
Mark Mendell99dbd682015-04-22 16:18:52 -04003806 CpuRegister length = length_loc.AsRegister<CpuRegister>();
3807 if (index_loc.IsConstant()) {
3808 int32_t value = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
3809 __ cmpl(length, Immediate(value));
3810 } else {
3811 __ cmpl(length, index_loc.AsRegister<CpuRegister>());
3812 }
3813 codegen_->AddSlowPath(slow_path);
3814 __ j(kBelowEqual, slow_path->GetEntryLabel());
Mark Mendellf60c90b2015-03-04 15:12:59 -05003815 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003816}
3817
3818void CodeGeneratorX86_64::MarkGCCard(CpuRegister temp,
3819 CpuRegister card,
3820 CpuRegister object,
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003821 CpuRegister value,
3822 bool value_can_be_null) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003823 Label is_null;
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003824 if (value_can_be_null) {
3825 __ testl(value, value);
3826 __ j(kEqual, &is_null);
3827 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003828 __ gs()->movq(card, Address::Absolute(
3829 Thread::CardTableOffset<kX86_64WordSize>().Int32Value(), true));
3830 __ movq(temp, object);
3831 __ shrq(temp, Immediate(gc::accounting::CardTable::kCardShift));
3832 __ movb(Address(temp, card, TIMES_1, 0), card);
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003833 if (value_can_be_null) {
3834 __ Bind(&is_null);
3835 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003836}
3837
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003838void LocationsBuilderX86_64::VisitTemporary(HTemporary* temp) {
3839 temp->SetLocations(nullptr);
3840}
3841
3842void InstructionCodeGeneratorX86_64::VisitTemporary(HTemporary* temp) {
3843 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003844 UNUSED(temp);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003845}
3846
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003847void LocationsBuilderX86_64::VisitParallelMove(HParallelMove* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003848 UNUSED(instruction);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003849 LOG(FATAL) << "Unimplemented";
3850}
3851
3852void InstructionCodeGeneratorX86_64::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003853 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
3854}
3855
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003856void LocationsBuilderX86_64::VisitSuspendCheck(HSuspendCheck* instruction) {
3857 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
3858}
3859
3860void InstructionCodeGeneratorX86_64::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003861 HBasicBlock* block = instruction->GetBlock();
3862 if (block->GetLoopInformation() != nullptr) {
3863 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
3864 // The back edge will generate the suspend check.
3865 return;
3866 }
3867 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
3868 // The goto will generate the suspend check.
3869 return;
3870 }
3871 GenerateSuspendCheck(instruction, nullptr);
3872}
3873
3874void InstructionCodeGeneratorX86_64::GenerateSuspendCheck(HSuspendCheck* instruction,
3875 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003876 SuspendCheckSlowPathX86_64* slow_path =
Nicolas Geoffraydb216f42015-05-05 17:02:20 +01003877 down_cast<SuspendCheckSlowPathX86_64*>(instruction->GetSlowPath());
3878 if (slow_path == nullptr) {
3879 slow_path = new (GetGraph()->GetArena()) SuspendCheckSlowPathX86_64(instruction, successor);
3880 instruction->SetSlowPath(slow_path);
3881 codegen_->AddSlowPath(slow_path);
3882 if (successor != nullptr) {
3883 DCHECK(successor->IsLoopHeader());
3884 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(instruction);
3885 }
3886 } else {
3887 DCHECK_EQ(slow_path->GetSuccessor(), successor);
3888 }
3889
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003890 __ gs()->cmpw(Address::Absolute(
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003891 Thread::ThreadFlagsOffset<kX86_64WordSize>().Int32Value(), true), Immediate(0));
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003892 if (successor == nullptr) {
3893 __ j(kNotEqual, slow_path->GetEntryLabel());
3894 __ Bind(slow_path->GetReturnLabel());
3895 } else {
3896 __ j(kEqual, codegen_->GetLabelOf(successor));
3897 __ jmp(slow_path->GetEntryLabel());
3898 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003899}
3900
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003901X86_64Assembler* ParallelMoveResolverX86_64::GetAssembler() const {
3902 return codegen_->GetAssembler();
3903}
3904
3905void ParallelMoveResolverX86_64::EmitMove(size_t index) {
3906 MoveOperands* move = moves_.Get(index);
3907 Location source = move->GetSource();
3908 Location destination = move->GetDestination();
3909
3910 if (source.IsRegister()) {
3911 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003912 __ movq(destination.AsRegister<CpuRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003913 } else if (destination.IsStackSlot()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003914 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00003915 source.AsRegister<CpuRegister>());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003916 } else {
3917 DCHECK(destination.IsDoubleStackSlot());
3918 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00003919 source.AsRegister<CpuRegister>());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003920 }
3921 } else if (source.IsStackSlot()) {
3922 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003923 __ movl(destination.AsRegister<CpuRegister>(),
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003924 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003925 } else if (destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003926 __ movss(destination.AsFpuRegister<XmmRegister>(),
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003927 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003928 } else {
3929 DCHECK(destination.IsStackSlot());
3930 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
3931 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
3932 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003933 } else if (source.IsDoubleStackSlot()) {
3934 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003935 __ movq(destination.AsRegister<CpuRegister>(),
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003936 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003937 } else if (destination.IsFpuRegister()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003938 __ movsd(destination.AsFpuRegister<XmmRegister>(),
3939 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003940 } else {
Nicolas Geoffrayc8147a72014-10-21 16:06:20 +01003941 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003942 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
3943 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
3944 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003945 } else if (source.IsConstant()) {
3946 HConstant* constant = source.GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00003947 if (constant->IsIntConstant() || constant->IsNullConstant()) {
3948 int32_t value = CodeGenerator::GetInt32ValueOf(constant);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003949 if (destination.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00003950 if (value == 0) {
3951 __ xorl(destination.AsRegister<CpuRegister>(), destination.AsRegister<CpuRegister>());
3952 } else {
3953 __ movl(destination.AsRegister<CpuRegister>(), Immediate(value));
3954 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003955 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003956 DCHECK(destination.IsStackSlot()) << destination;
Nicolas Geoffray748f1402015-01-27 08:17:54 +00003957 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), Immediate(value));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003958 }
3959 } else if (constant->IsLongConstant()) {
3960 int64_t value = constant->AsLongConstant()->GetValue();
3961 if (destination.IsRegister()) {
Mark Mendell92e83bf2015-05-07 11:25:03 -04003962 codegen_->Load64BitValue(destination.AsRegister<CpuRegister>(), value);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003963 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003964 DCHECK(destination.IsDoubleStackSlot()) << destination;
Mark Mendell92e83bf2015-05-07 11:25:03 -04003965 codegen_->Load64BitValue(CpuRegister(TMP), value);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003966 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
3967 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003968 } else if (constant->IsFloatConstant()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003969 float fp_value = constant->AsFloatConstant()->GetValue();
Roland Levillainda4d79b2015-03-24 14:36:11 +00003970 int32_t value = bit_cast<int32_t, float>(fp_value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003971 if (destination.IsFpuRegister()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003972 XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
3973 if (value == 0) {
3974 // easy FP 0.0.
3975 __ xorps(dest, dest);
3976 } else {
Mark Mendell92e83bf2015-05-07 11:25:03 -04003977 __ movss(dest, codegen_->LiteralFloatAddress(fp_value));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003978 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003979 } else {
3980 DCHECK(destination.IsStackSlot()) << destination;
Mark Mendell92e83bf2015-05-07 11:25:03 -04003981 Immediate imm(value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003982 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), imm);
3983 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003984 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003985 DCHECK(constant->IsDoubleConstant()) << constant->DebugName();
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003986 double fp_value = constant->AsDoubleConstant()->GetValue();
Roland Levillainda4d79b2015-03-24 14:36:11 +00003987 int64_t value = bit_cast<int64_t, double>(fp_value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003988 if (destination.IsFpuRegister()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003989 XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
3990 if (value == 0) {
3991 __ xorpd(dest, dest);
3992 } else {
Mark Mendell92e83bf2015-05-07 11:25:03 -04003993 __ movsd(dest, codegen_->LiteralDoubleAddress(fp_value));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003994 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003995 } else {
3996 DCHECK(destination.IsDoubleStackSlot()) << destination;
Mark Mendell92e83bf2015-05-07 11:25:03 -04003997 codegen_->Load64BitValue(CpuRegister(TMP), value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003998 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
3999 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004000 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004001 } else if (source.IsFpuRegister()) {
4002 if (destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004003 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004004 } else if (destination.IsStackSlot()) {
4005 __ movss(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00004006 source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004007 } else {
Nicolas Geoffray31596742014-11-24 15:28:45 +00004008 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004009 __ movsd(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00004010 source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004011 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004012 }
4013}
4014
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004015void ParallelMoveResolverX86_64::Exchange32(CpuRegister reg, int mem) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004016 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004017 __ movl(Address(CpuRegister(RSP), mem), reg);
4018 __ movl(reg, CpuRegister(TMP));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004019}
4020
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004021void ParallelMoveResolverX86_64::Exchange32(int mem1, int mem2) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004022 ScratchRegisterScope ensure_scratch(
4023 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
4024
4025 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
4026 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
4027 __ movl(CpuRegister(ensure_scratch.GetRegister()),
4028 Address(CpuRegister(RSP), mem2 + stack_offset));
4029 __ movl(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
4030 __ movl(Address(CpuRegister(RSP), mem1 + stack_offset),
4031 CpuRegister(ensure_scratch.GetRegister()));
4032}
4033
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004034void ParallelMoveResolverX86_64::Exchange64(CpuRegister reg, int mem) {
4035 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
4036 __ movq(Address(CpuRegister(RSP), mem), reg);
4037 __ movq(reg, CpuRegister(TMP));
4038}
4039
4040void ParallelMoveResolverX86_64::Exchange64(int mem1, int mem2) {
4041 ScratchRegisterScope ensure_scratch(
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004042 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004043
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004044 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
4045 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
4046 __ movq(CpuRegister(ensure_scratch.GetRegister()),
4047 Address(CpuRegister(RSP), mem2 + stack_offset));
4048 __ movq(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
4049 __ movq(Address(CpuRegister(RSP), mem1 + stack_offset),
4050 CpuRegister(ensure_scratch.GetRegister()));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004051}
4052
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004053void ParallelMoveResolverX86_64::Exchange32(XmmRegister reg, int mem) {
4054 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
4055 __ movss(Address(CpuRegister(RSP), mem), reg);
4056 __ movd(reg, CpuRegister(TMP));
4057}
4058
4059void ParallelMoveResolverX86_64::Exchange64(XmmRegister reg, int mem) {
4060 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
4061 __ movsd(Address(CpuRegister(RSP), mem), reg);
4062 __ movd(reg, CpuRegister(TMP));
4063}
4064
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004065void ParallelMoveResolverX86_64::EmitSwap(size_t index) {
4066 MoveOperands* move = moves_.Get(index);
4067 Location source = move->GetSource();
4068 Location destination = move->GetDestination();
4069
4070 if (source.IsRegister() && destination.IsRegister()) {
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004071 __ xchgq(destination.AsRegister<CpuRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004072 } else if (source.IsRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004073 Exchange32(source.AsRegister<CpuRegister>(), destination.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004074 } else if (source.IsStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004075 Exchange32(destination.AsRegister<CpuRegister>(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004076 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004077 Exchange32(destination.GetStackIndex(), source.GetStackIndex());
4078 } else if (source.IsRegister() && destination.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004079 Exchange64(source.AsRegister<CpuRegister>(), destination.GetStackIndex());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004080 } else if (source.IsDoubleStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004081 Exchange64(destination.AsRegister<CpuRegister>(), source.GetStackIndex());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004082 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
4083 Exchange64(destination.GetStackIndex(), source.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004084 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004085 __ movd(CpuRegister(TMP), source.AsFpuRegister<XmmRegister>());
4086 __ movaps(source.AsFpuRegister<XmmRegister>(), destination.AsFpuRegister<XmmRegister>());
4087 __ movd(destination.AsFpuRegister<XmmRegister>(), CpuRegister(TMP));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004088 } else if (source.IsFpuRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004089 Exchange32(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004090 } else if (source.IsStackSlot() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004091 Exchange32(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004092 } else if (source.IsFpuRegister() && destination.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004093 Exchange64(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004094 } else if (source.IsDoubleStackSlot() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004095 Exchange64(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004096 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004097 LOG(FATAL) << "Unimplemented swap between " << source << " and " << destination;
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004098 }
4099}
4100
4101
4102void ParallelMoveResolverX86_64::SpillScratch(int reg) {
4103 __ pushq(CpuRegister(reg));
4104}
4105
4106
4107void ParallelMoveResolverX86_64::RestoreScratch(int reg) {
4108 __ popq(CpuRegister(reg));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004109}
4110
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004111void InstructionCodeGeneratorX86_64::GenerateClassInitializationCheck(
4112 SlowPathCodeX86_64* slow_path, CpuRegister class_reg) {
4113 __ cmpl(Address(class_reg, mirror::Class::StatusOffset().Int32Value()),
4114 Immediate(mirror::Class::kStatusInitialized));
4115 __ j(kLess, slow_path->GetEntryLabel());
4116 __ Bind(slow_path->GetExitLabel());
4117 // No need for memory fence, thanks to the X86_64 memory model.
4118}
4119
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004120void LocationsBuilderX86_64::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004121 LocationSummary::CallKind call_kind = cls->CanCallRuntime()
4122 ? LocationSummary::kCallOnSlowPath
4123 : LocationSummary::kNoCall;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004124 LocationSummary* locations =
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004125 new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004126 locations->SetOut(Location::RequiresRegister());
4127}
4128
4129void InstructionCodeGeneratorX86_64::VisitLoadClass(HLoadClass* cls) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004130 CpuRegister out = cls->GetLocations()->Out().AsRegister<CpuRegister>();
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004131 if (cls->IsReferrersClass()) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004132 DCHECK(!cls->CanCallRuntime());
4133 DCHECK(!cls->MustGenerateClinitCheck());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004134 codegen_->LoadCurrentMethod(out);
4135 __ movl(out, Address(out, mirror::ArtMethod::DeclaringClassOffset().Int32Value()));
4136 } else {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004137 DCHECK(cls->CanCallRuntime());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004138 codegen_->LoadCurrentMethod(out);
4139 __ movl(out, Address(out, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value()));
4140 __ movl(out, Address(out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex())));
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004141 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86_64(
4142 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
4143 codegen_->AddSlowPath(slow_path);
4144 __ testl(out, out);
4145 __ j(kEqual, slow_path->GetEntryLabel());
4146 if (cls->MustGenerateClinitCheck()) {
4147 GenerateClassInitializationCheck(slow_path, out);
4148 } else {
4149 __ Bind(slow_path->GetExitLabel());
4150 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004151 }
4152}
4153
4154void LocationsBuilderX86_64::VisitClinitCheck(HClinitCheck* check) {
4155 LocationSummary* locations =
4156 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
4157 locations->SetInAt(0, Location::RequiresRegister());
4158 if (check->HasUses()) {
4159 locations->SetOut(Location::SameAsFirstInput());
4160 }
4161}
4162
4163void InstructionCodeGeneratorX86_64::VisitClinitCheck(HClinitCheck* check) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004164 // We assume the class to not be null.
4165 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86_64(
4166 check->GetLoadClass(), check, check->GetDexPc(), true);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004167 codegen_->AddSlowPath(slow_path);
Roland Levillain199f3362014-11-27 17:15:16 +00004168 GenerateClassInitializationCheck(slow_path,
4169 check->GetLocations()->InAt(0).AsRegister<CpuRegister>());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004170}
4171
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004172void LocationsBuilderX86_64::VisitLoadString(HLoadString* load) {
4173 LocationSummary* locations =
4174 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
4175 locations->SetOut(Location::RequiresRegister());
4176}
4177
4178void InstructionCodeGeneratorX86_64::VisitLoadString(HLoadString* load) {
4179 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathX86_64(load);
4180 codegen_->AddSlowPath(slow_path);
4181
Roland Levillain271ab9c2014-11-27 15:23:57 +00004182 CpuRegister out = load->GetLocations()->Out().AsRegister<CpuRegister>();
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004183 codegen_->LoadCurrentMethod(CpuRegister(out));
Mathieu Chartiereace4582014-11-24 18:29:54 -08004184 __ movl(out, Address(out, mirror::ArtMethod::DeclaringClassOffset().Int32Value()));
4185 __ movl(out, Address(out, mirror::Class::DexCacheStringsOffset().Int32Value()));
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004186 __ movl(out, Address(out, CodeGenerator::GetCacheOffset(load->GetStringIndex())));
4187 __ testl(out, out);
4188 __ j(kEqual, slow_path->GetEntryLabel());
4189 __ Bind(slow_path->GetExitLabel());
4190}
4191
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004192void LocationsBuilderX86_64::VisitLoadException(HLoadException* load) {
4193 LocationSummary* locations =
4194 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
4195 locations->SetOut(Location::RequiresRegister());
4196}
4197
4198void InstructionCodeGeneratorX86_64::VisitLoadException(HLoadException* load) {
4199 Address address = Address::Absolute(
4200 Thread::ExceptionOffset<kX86_64WordSize>().Int32Value(), true);
Roland Levillain271ab9c2014-11-27 15:23:57 +00004201 __ gs()->movl(load->GetLocations()->Out().AsRegister<CpuRegister>(), address);
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004202 __ gs()->movl(address, Immediate(0));
4203}
4204
4205void LocationsBuilderX86_64::VisitThrow(HThrow* instruction) {
4206 LocationSummary* locations =
4207 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
4208 InvokeRuntimeCallingConvention calling_convention;
4209 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4210}
4211
4212void InstructionCodeGeneratorX86_64::VisitThrow(HThrow* instruction) {
4213 __ gs()->call(
4214 Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pDeliverException), true));
4215 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
4216}
4217
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004218void LocationsBuilderX86_64::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004219 LocationSummary::CallKind call_kind = instruction->IsClassFinal()
4220 ? LocationSummary::kNoCall
4221 : LocationSummary::kCallOnSlowPath;
4222 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
4223 locations->SetInAt(0, Location::RequiresRegister());
4224 locations->SetInAt(1, Location::Any());
4225 locations->SetOut(Location::RequiresRegister());
4226}
4227
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004228void InstructionCodeGeneratorX86_64::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004229 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004230 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004231 Location cls = locations->InAt(1);
Roland Levillain271ab9c2014-11-27 15:23:57 +00004232 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004233 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
4234 Label done, zero;
4235 SlowPathCodeX86_64* slow_path = nullptr;
4236
4237 // Return 0 if `obj` is null.
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004238 // Avoid null check if we know obj is not null.
4239 if (instruction->MustDoNullCheck()) {
4240 __ testl(obj, obj);
4241 __ j(kEqual, &zero);
4242 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004243 // Compare the class of `obj` with `cls`.
4244 __ movl(out, Address(obj, class_offset));
4245 if (cls.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004246 __ cmpl(out, cls.AsRegister<CpuRegister>());
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004247 } else {
4248 DCHECK(cls.IsStackSlot()) << cls;
4249 __ cmpl(out, Address(CpuRegister(RSP), cls.GetStackIndex()));
4250 }
4251 if (instruction->IsClassFinal()) {
4252 // Classes must be equal for the instanceof to succeed.
4253 __ j(kNotEqual, &zero);
4254 __ movl(out, Immediate(1));
4255 __ jmp(&done);
4256 } else {
4257 // If the classes are not equal, we go into a slow path.
4258 DCHECK(locations->OnlyCallsOnSlowPath());
4259 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86_64(
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004260 instruction, locations->InAt(1), locations->Out(), instruction->GetDexPc());
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004261 codegen_->AddSlowPath(slow_path);
4262 __ j(kNotEqual, slow_path->GetEntryLabel());
4263 __ movl(out, Immediate(1));
4264 __ jmp(&done);
4265 }
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004266
4267 if (instruction->MustDoNullCheck() || instruction->IsClassFinal()) {
4268 __ Bind(&zero);
4269 __ movl(out, Immediate(0));
4270 }
4271
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004272 if (slow_path != nullptr) {
4273 __ Bind(slow_path->GetExitLabel());
4274 }
4275 __ Bind(&done);
4276}
4277
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004278void LocationsBuilderX86_64::VisitCheckCast(HCheckCast* instruction) {
4279 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
4280 instruction, LocationSummary::kCallOnSlowPath);
4281 locations->SetInAt(0, Location::RequiresRegister());
4282 locations->SetInAt(1, Location::Any());
4283 locations->AddTemp(Location::RequiresRegister());
4284}
4285
4286void InstructionCodeGeneratorX86_64::VisitCheckCast(HCheckCast* instruction) {
4287 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004288 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004289 Location cls = locations->InAt(1);
Roland Levillain271ab9c2014-11-27 15:23:57 +00004290 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004291 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
4292 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86_64(
4293 instruction, locations->InAt(1), locations->GetTemp(0), instruction->GetDexPc());
4294 codegen_->AddSlowPath(slow_path);
4295
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004296 // Avoid null check if we know obj is not null.
4297 if (instruction->MustDoNullCheck()) {
4298 __ testl(obj, obj);
4299 __ j(kEqual, slow_path->GetExitLabel());
4300 }
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004301 // Compare the class of `obj` with `cls`.
4302 __ movl(temp, Address(obj, class_offset));
4303 if (cls.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004304 __ cmpl(temp, cls.AsRegister<CpuRegister>());
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004305 } else {
4306 DCHECK(cls.IsStackSlot()) << cls;
4307 __ cmpl(temp, Address(CpuRegister(RSP), cls.GetStackIndex()));
4308 }
4309 // Classes must be equal for the checkcast to succeed.
4310 __ j(kNotEqual, slow_path->GetEntryLabel());
4311 __ Bind(slow_path->GetExitLabel());
4312}
4313
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00004314void LocationsBuilderX86_64::VisitMonitorOperation(HMonitorOperation* instruction) {
4315 LocationSummary* locations =
4316 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
4317 InvokeRuntimeCallingConvention calling_convention;
4318 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4319}
4320
4321void InstructionCodeGeneratorX86_64::VisitMonitorOperation(HMonitorOperation* instruction) {
4322 __ gs()->call(Address::Absolute(instruction->IsEnter()
4323 ? QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pLockObject)
4324 : QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pUnlockObject),
4325 true));
4326 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
4327}
4328
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004329void LocationsBuilderX86_64::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); }
4330void LocationsBuilderX86_64::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); }
4331void LocationsBuilderX86_64::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); }
4332
4333void LocationsBuilderX86_64::HandleBitwiseOperation(HBinaryOperation* instruction) {
4334 LocationSummary* locations =
4335 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
4336 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
4337 || instruction->GetResultType() == Primitive::kPrimLong);
4338 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell40741f32015-04-20 22:10:34 -04004339 locations->SetInAt(1, Location::Any());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004340 locations->SetOut(Location::SameAsFirstInput());
4341}
4342
4343void InstructionCodeGeneratorX86_64::VisitAnd(HAnd* instruction) {
4344 HandleBitwiseOperation(instruction);
4345}
4346
4347void InstructionCodeGeneratorX86_64::VisitOr(HOr* instruction) {
4348 HandleBitwiseOperation(instruction);
4349}
4350
4351void InstructionCodeGeneratorX86_64::VisitXor(HXor* instruction) {
4352 HandleBitwiseOperation(instruction);
4353}
4354
4355void InstructionCodeGeneratorX86_64::HandleBitwiseOperation(HBinaryOperation* instruction) {
4356 LocationSummary* locations = instruction->GetLocations();
4357 Location first = locations->InAt(0);
4358 Location second = locations->InAt(1);
4359 DCHECK(first.Equals(locations->Out()));
4360
4361 if (instruction->GetResultType() == Primitive::kPrimInt) {
4362 if (second.IsRegister()) {
4363 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004364 __ andl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004365 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004366 __ orl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004367 } else {
4368 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004369 __ xorl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004370 }
4371 } else if (second.IsConstant()) {
4372 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
4373 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004374 __ andl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004375 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004376 __ orl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004377 } else {
4378 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004379 __ xorl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004380 }
4381 } else {
4382 Address address(CpuRegister(RSP), second.GetStackIndex());
4383 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004384 __ andl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004385 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004386 __ orl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004387 } else {
4388 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004389 __ xorl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004390 }
4391 }
4392 } else {
4393 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004394 CpuRegister first_reg = first.AsRegister<CpuRegister>();
4395 bool second_is_constant = false;
4396 int64_t value = 0;
4397 if (second.IsConstant()) {
4398 second_is_constant = true;
4399 value = second.GetConstant()->AsLongConstant()->GetValue();
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004400 }
Mark Mendell40741f32015-04-20 22:10:34 -04004401 bool is_int32_value = IsInt<32>(value);
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004402
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004403 if (instruction->IsAnd()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004404 if (second_is_constant) {
Mark Mendell40741f32015-04-20 22:10:34 -04004405 if (is_int32_value) {
4406 __ andq(first_reg, Immediate(static_cast<int32_t>(value)));
4407 } else {
4408 __ andq(first_reg, codegen_->LiteralInt64Address(value));
4409 }
4410 } else if (second.IsDoubleStackSlot()) {
4411 __ andq(first_reg, Address(CpuRegister(RSP), second.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004412 } else {
4413 __ andq(first_reg, second.AsRegister<CpuRegister>());
4414 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004415 } else if (instruction->IsOr()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004416 if (second_is_constant) {
Mark Mendell40741f32015-04-20 22:10:34 -04004417 if (is_int32_value) {
4418 __ orq(first_reg, Immediate(static_cast<int32_t>(value)));
4419 } else {
4420 __ orq(first_reg, codegen_->LiteralInt64Address(value));
4421 }
4422 } else if (second.IsDoubleStackSlot()) {
4423 __ orq(first_reg, Address(CpuRegister(RSP), second.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004424 } else {
4425 __ orq(first_reg, second.AsRegister<CpuRegister>());
4426 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004427 } else {
4428 DCHECK(instruction->IsXor());
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004429 if (second_is_constant) {
Mark Mendell40741f32015-04-20 22:10:34 -04004430 if (is_int32_value) {
4431 __ xorq(first_reg, Immediate(static_cast<int32_t>(value)));
4432 } else {
4433 __ xorq(first_reg, codegen_->LiteralInt64Address(value));
4434 }
4435 } else if (second.IsDoubleStackSlot()) {
4436 __ xorq(first_reg, Address(CpuRegister(RSP), second.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004437 } else {
4438 __ xorq(first_reg, second.AsRegister<CpuRegister>());
4439 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004440 }
4441 }
4442}
4443
Calin Juravleb1498f62015-02-16 13:13:29 +00004444void LocationsBuilderX86_64::VisitBoundType(HBoundType* instruction) {
4445 // Nothing to do, this should be removed during prepare for register allocator.
4446 UNUSED(instruction);
4447 LOG(FATAL) << "Unreachable";
4448}
4449
4450void InstructionCodeGeneratorX86_64::VisitBoundType(HBoundType* instruction) {
4451 // Nothing to do, this should be removed during prepare for register allocator.
4452 UNUSED(instruction);
4453 LOG(FATAL) << "Unreachable";
4454}
4455
Mark Mendell92e83bf2015-05-07 11:25:03 -04004456void CodeGeneratorX86_64::Load64BitValue(CpuRegister dest, int64_t value) {
4457 if (value == 0) {
4458 __ xorl(dest, dest);
4459 } else if (value > 0 && IsInt<32>(value)) {
4460 // We can use a 32 bit move, as it will zero-extend and is one byte shorter.
4461 __ movl(dest, Immediate(static_cast<int32_t>(value)));
4462 } else {
4463 __ movq(dest, Immediate(value));
4464 }
4465}
4466
Mark Mendellf55c3e02015-03-26 21:07:46 -04004467void CodeGeneratorX86_64::Finalize(CodeAllocator* allocator) {
4468 // Generate the constant area if needed.
Mark Mendell39dcf552015-04-09 20:42:42 -04004469 X86_64Assembler* assembler = GetAssembler();
4470 if (!assembler->IsConstantAreaEmpty()) {
Mark Mendellf55c3e02015-03-26 21:07:46 -04004471 // Align to 4 byte boundary to reduce cache misses, as the data is 4 and 8
4472 // byte values. If used for vectors at a later time, this will need to be
4473 // updated to 16 bytes with the appropriate offset.
Mark Mendell39dcf552015-04-09 20:42:42 -04004474 assembler->Align(4, 0);
4475 constant_area_start_ = assembler->CodeSize();
4476 assembler->AddConstantArea();
Mark Mendellf55c3e02015-03-26 21:07:46 -04004477 }
4478
4479 // And finish up.
4480 CodeGenerator::Finalize(allocator);
4481}
4482
4483/**
4484 * Class to handle late fixup of offsets into constant area.
4485 */
4486class RIPFixup : public AssemblerFixup, public ArenaObject<kArenaAllocMisc> {
4487 public:
Mark Mendell39dcf552015-04-09 20:42:42 -04004488 RIPFixup(const CodeGeneratorX86_64& codegen, int offset)
Mark Mendellf55c3e02015-03-26 21:07:46 -04004489 : codegen_(codegen), offset_into_constant_area_(offset) {}
4490
4491 private:
4492 void Process(const MemoryRegion& region, int pos) OVERRIDE {
4493 // Patch the correct offset for the instruction. We use the address of the
4494 // 'next' instruction, which is 'pos' (patch the 4 bytes before).
4495 int constant_offset = codegen_.ConstantAreaStart() + offset_into_constant_area_;
4496 int relative_position = constant_offset - pos;
4497
4498 // Patch in the right value.
4499 region.StoreUnaligned<int32_t>(pos - 4, relative_position);
4500 }
4501
Mark Mendell39dcf552015-04-09 20:42:42 -04004502 const CodeGeneratorX86_64& codegen_;
Mark Mendellf55c3e02015-03-26 21:07:46 -04004503
4504 // Location in constant area that the fixup refers to.
4505 int offset_into_constant_area_;
4506};
4507
4508Address CodeGeneratorX86_64::LiteralDoubleAddress(double v) {
4509 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddDouble(v));
4510 return Address::RIP(fixup);
4511}
4512
4513Address CodeGeneratorX86_64::LiteralFloatAddress(float v) {
4514 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddFloat(v));
4515 return Address::RIP(fixup);
4516}
4517
4518Address CodeGeneratorX86_64::LiteralInt32Address(int32_t v) {
4519 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddInt32(v));
4520 return Address::RIP(fixup);
4521}
4522
4523Address CodeGeneratorX86_64::LiteralInt64Address(int64_t v) {
4524 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddInt64(v));
4525 return Address::RIP(fixup);
4526}
4527
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004528} // namespace x86_64
4529} // namespace art