blob: 7491aa25d0873523a36fd2ff956c15bfcfc12f69 [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
Roland Levillain0d37cd02015-05-27 16:39:19 +0100947void LocationsBuilderX86_64::VisitCondition(HCondition* cond) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100948 LocationSummary* locations =
Roland Levillain0d37cd02015-05-27 16:39:19 +0100949 new (GetGraph()->GetArena()) LocationSummary(cond, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +0100950 locations->SetInAt(0, Location::RequiresRegister());
951 locations->SetInAt(1, Location::Any());
Roland Levillain0d37cd02015-05-27 16:39:19 +0100952 if (cond->NeedsMaterialization()) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100953 locations->SetOut(Location::RequiresRegister());
954 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100955}
956
Roland Levillain0d37cd02015-05-27 16:39:19 +0100957void InstructionCodeGeneratorX86_64::VisitCondition(HCondition* cond) {
958 if (cond->NeedsMaterialization()) {
959 LocationSummary* locations = cond->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 }
Roland Levillain0d37cd02015-05-27 16:39:19 +0100977 __ setcc(X86_64Condition(cond->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>());
Mark Mendell33bf2452015-05-27 10:08:24 -04002120 } else if (out.AsRegister<Register>() == second.AsRegister<Register>()) {
2121 __ addl(out.AsRegister<CpuRegister>(), first.AsRegister<CpuRegister>());
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002122 } else {
2123 __ leal(out.AsRegister<CpuRegister>(), Address(
2124 first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>(), TIMES_1, 0));
2125 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002126 } else if (second.IsConstant()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002127 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
2128 __ addl(out.AsRegister<CpuRegister>(),
2129 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
2130 } else {
2131 __ leal(out.AsRegister<CpuRegister>(), Address(
2132 first.AsRegister<CpuRegister>(), second.GetConstant()->AsIntConstant()->GetValue()));
2133 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002134 } else {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002135 DCHECK(first.Equals(locations->Out()));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002136 __ addl(first.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), second.GetStackIndex()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002137 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002138 break;
2139 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002140
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002141 case Primitive::kPrimLong: {
Mark Mendell09b84632015-02-13 17:48:38 -05002142 if (second.IsRegister()) {
2143 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
2144 __ addq(out.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Mark Mendell33bf2452015-05-27 10:08:24 -04002145 } else if (out.AsRegister<Register>() == second.AsRegister<Register>()) {
2146 __ addq(out.AsRegister<CpuRegister>(), first.AsRegister<CpuRegister>());
Mark Mendell09b84632015-02-13 17:48:38 -05002147 } else {
2148 __ leaq(out.AsRegister<CpuRegister>(), Address(
2149 first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>(), TIMES_1, 0));
2150 }
2151 } else {
2152 DCHECK(second.IsConstant());
2153 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
2154 int32_t int32_value = Low32Bits(value);
2155 DCHECK_EQ(int32_value, value);
2156 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
2157 __ addq(out.AsRegister<CpuRegister>(), Immediate(int32_value));
2158 } else {
2159 __ leaq(out.AsRegister<CpuRegister>(), Address(
2160 first.AsRegister<CpuRegister>(), int32_value));
2161 }
2162 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002163 break;
2164 }
2165
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002166 case Primitive::kPrimFloat: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04002167 if (second.IsFpuRegister()) {
2168 __ addss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2169 } else if (second.IsConstant()) {
2170 __ addss(first.AsFpuRegister<XmmRegister>(),
2171 codegen_->LiteralFloatAddress(second.GetConstant()->AsFloatConstant()->GetValue()));
2172 } else {
2173 DCHECK(second.IsStackSlot());
2174 __ addss(first.AsFpuRegister<XmmRegister>(),
2175 Address(CpuRegister(RSP), second.GetStackIndex()));
2176 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002177 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002178 }
2179
2180 case Primitive::kPrimDouble: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04002181 if (second.IsFpuRegister()) {
2182 __ addsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2183 } else if (second.IsConstant()) {
2184 __ addsd(first.AsFpuRegister<XmmRegister>(),
2185 codegen_->LiteralDoubleAddress(second.GetConstant()->AsDoubleConstant()->GetValue()));
2186 } else {
2187 DCHECK(second.IsDoubleStackSlot());
2188 __ addsd(first.AsFpuRegister<XmmRegister>(),
2189 Address(CpuRegister(RSP), second.GetStackIndex()));
2190 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002191 break;
2192 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002193
2194 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002195 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002196 }
2197}
2198
2199void LocationsBuilderX86_64::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002200 LocationSummary* locations =
2201 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002202 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002203 case Primitive::kPrimInt: {
2204 locations->SetInAt(0, Location::RequiresRegister());
2205 locations->SetInAt(1, Location::Any());
2206 locations->SetOut(Location::SameAsFirstInput());
2207 break;
2208 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002209 case Primitive::kPrimLong: {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002210 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002211 locations->SetInAt(1, Location::RegisterOrInt32LongConstant(sub->InputAt(1)));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002212 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002213 break;
2214 }
Calin Juravle11351682014-10-23 15:38:15 +01002215 case Primitive::kPrimFloat:
2216 case Primitive::kPrimDouble: {
2217 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendellf55c3e02015-03-26 21:07:46 -04002218 locations->SetInAt(1, Location::Any());
Calin Juravle11351682014-10-23 15:38:15 +01002219 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002220 break;
Calin Juravle11351682014-10-23 15:38:15 +01002221 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002222 default:
Calin Juravle11351682014-10-23 15:38:15 +01002223 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002224 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002225}
2226
2227void InstructionCodeGeneratorX86_64::VisitSub(HSub* sub) {
2228 LocationSummary* locations = sub->GetLocations();
Calin Juravle11351682014-10-23 15:38:15 +01002229 Location first = locations->InAt(0);
2230 Location second = locations->InAt(1);
2231 DCHECK(first.Equals(locations->Out()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002232 switch (sub->GetResultType()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002233 case Primitive::kPrimInt: {
Calin Juravle11351682014-10-23 15:38:15 +01002234 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002235 __ subl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Calin Juravle11351682014-10-23 15:38:15 +01002236 } else if (second.IsConstant()) {
2237 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002238 __ subl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002239 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002240 __ subl(first.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), second.GetStackIndex()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002241 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002242 break;
2243 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002244 case Primitive::kPrimLong: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002245 if (second.IsConstant()) {
2246 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
2247 DCHECK(IsInt<32>(value));
2248 __ subq(first.AsRegister<CpuRegister>(), Immediate(static_cast<int32_t>(value)));
2249 } else {
2250 __ subq(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
2251 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002252 break;
2253 }
2254
Calin Juravle11351682014-10-23 15:38:15 +01002255 case Primitive::kPrimFloat: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04002256 if (second.IsFpuRegister()) {
2257 __ subss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2258 } else if (second.IsConstant()) {
2259 __ subss(first.AsFpuRegister<XmmRegister>(),
2260 codegen_->LiteralFloatAddress(second.GetConstant()->AsFloatConstant()->GetValue()));
2261 } else {
2262 DCHECK(second.IsStackSlot());
2263 __ subss(first.AsFpuRegister<XmmRegister>(),
2264 Address(CpuRegister(RSP), second.GetStackIndex()));
2265 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002266 break;
Calin Juravle11351682014-10-23 15:38:15 +01002267 }
2268
2269 case Primitive::kPrimDouble: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04002270 if (second.IsFpuRegister()) {
2271 __ subsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2272 } else if (second.IsConstant()) {
2273 __ subsd(first.AsFpuRegister<XmmRegister>(),
2274 codegen_->LiteralDoubleAddress(second.GetConstant()->AsDoubleConstant()->GetValue()));
2275 } else {
2276 DCHECK(second.IsDoubleStackSlot());
2277 __ subsd(first.AsFpuRegister<XmmRegister>(),
2278 Address(CpuRegister(RSP), second.GetStackIndex()));
2279 }
Calin Juravle11351682014-10-23 15:38:15 +01002280 break;
2281 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002282
2283 default:
Calin Juravle11351682014-10-23 15:38:15 +01002284 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002285 }
2286}
2287
Calin Juravle34bacdf2014-10-07 20:23:36 +01002288void LocationsBuilderX86_64::VisitMul(HMul* mul) {
2289 LocationSummary* locations =
2290 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
2291 switch (mul->GetResultType()) {
2292 case Primitive::kPrimInt: {
2293 locations->SetInAt(0, Location::RequiresRegister());
2294 locations->SetInAt(1, Location::Any());
2295 locations->SetOut(Location::SameAsFirstInput());
2296 break;
2297 }
2298 case Primitive::kPrimLong: {
2299 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002300 locations->SetInAt(1, Location::RegisterOrInt32LongConstant(mul->InputAt(1)));
2301 if (locations->InAt(1).IsConstant()) {
2302 // Can use 3 operand multiply.
2303 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2304 } else {
2305 locations->SetOut(Location::SameAsFirstInput());
2306 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002307 break;
2308 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01002309 case Primitive::kPrimFloat:
2310 case Primitive::kPrimDouble: {
2311 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendellf55c3e02015-03-26 21:07:46 -04002312 locations->SetInAt(1, Location::Any());
Calin Juravleb5bfa962014-10-21 18:02:24 +01002313 locations->SetOut(Location::SameAsFirstInput());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002314 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002315 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002316
2317 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002318 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002319 }
2320}
2321
2322void InstructionCodeGeneratorX86_64::VisitMul(HMul* mul) {
2323 LocationSummary* locations = mul->GetLocations();
2324 Location first = locations->InAt(0);
2325 Location second = locations->InAt(1);
Calin Juravle34bacdf2014-10-07 20:23:36 +01002326 switch (mul->GetResultType()) {
2327 case Primitive::kPrimInt: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002328 DCHECK(first.Equals(locations->Out()));
Calin Juravle34bacdf2014-10-07 20:23:36 +01002329 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002330 __ imull(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002331 } else if (second.IsConstant()) {
2332 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002333 __ imull(first.AsRegister<CpuRegister>(), imm);
Calin Juravle34bacdf2014-10-07 20:23:36 +01002334 } else {
2335 DCHECK(second.IsStackSlot());
Roland Levillain199f3362014-11-27 17:15:16 +00002336 __ imull(first.AsRegister<CpuRegister>(),
2337 Address(CpuRegister(RSP), second.GetStackIndex()));
Calin Juravle34bacdf2014-10-07 20:23:36 +01002338 }
2339 break;
2340 }
2341 case Primitive::kPrimLong: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002342 if (second.IsConstant()) {
2343 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
2344 DCHECK(IsInt<32>(value));
2345 __ imulq(locations->Out().AsRegister<CpuRegister>(),
2346 first.AsRegister<CpuRegister>(),
2347 Immediate(static_cast<int32_t>(value)));
2348 } else {
2349 DCHECK(first.Equals(locations->Out()));
2350 __ imulq(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
2351 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002352 break;
2353 }
2354
Calin Juravleb5bfa962014-10-21 18:02:24 +01002355 case Primitive::kPrimFloat: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002356 DCHECK(first.Equals(locations->Out()));
Mark Mendellf55c3e02015-03-26 21:07:46 -04002357 if (second.IsFpuRegister()) {
2358 __ mulss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2359 } else if (second.IsConstant()) {
2360 __ mulss(first.AsFpuRegister<XmmRegister>(),
2361 codegen_->LiteralFloatAddress(second.GetConstant()->AsFloatConstant()->GetValue()));
2362 } else {
2363 DCHECK(second.IsStackSlot());
2364 __ mulss(first.AsFpuRegister<XmmRegister>(),
2365 Address(CpuRegister(RSP), second.GetStackIndex()));
2366 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002367 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002368 }
2369
2370 case Primitive::kPrimDouble: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002371 DCHECK(first.Equals(locations->Out()));
Mark Mendellf55c3e02015-03-26 21:07:46 -04002372 if (second.IsFpuRegister()) {
2373 __ mulsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2374 } else if (second.IsConstant()) {
2375 __ mulsd(first.AsFpuRegister<XmmRegister>(),
2376 codegen_->LiteralDoubleAddress(second.GetConstant()->AsDoubleConstant()->GetValue()));
2377 } else {
2378 DCHECK(second.IsDoubleStackSlot());
2379 __ mulsd(first.AsFpuRegister<XmmRegister>(),
2380 Address(CpuRegister(RSP), second.GetStackIndex()));
2381 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01002382 break;
2383 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002384
2385 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002386 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002387 }
2388}
2389
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002390void InstructionCodeGeneratorX86_64::PushOntoFPStack(Location source, uint32_t temp_offset,
2391 uint32_t stack_adjustment, bool is_float) {
2392 if (source.IsStackSlot()) {
2393 DCHECK(is_float);
2394 __ flds(Address(CpuRegister(RSP), source.GetStackIndex() + stack_adjustment));
2395 } else if (source.IsDoubleStackSlot()) {
2396 DCHECK(!is_float);
2397 __ fldl(Address(CpuRegister(RSP), source.GetStackIndex() + stack_adjustment));
2398 } else {
2399 // Write the value to the temporary location on the stack and load to FP stack.
2400 if (is_float) {
2401 Location stack_temp = Location::StackSlot(temp_offset);
2402 codegen_->Move(stack_temp, source);
2403 __ flds(Address(CpuRegister(RSP), temp_offset));
2404 } else {
2405 Location stack_temp = Location::DoubleStackSlot(temp_offset);
2406 codegen_->Move(stack_temp, source);
2407 __ fldl(Address(CpuRegister(RSP), temp_offset));
2408 }
2409 }
2410}
2411
2412void InstructionCodeGeneratorX86_64::GenerateRemFP(HRem *rem) {
2413 Primitive::Type type = rem->GetResultType();
2414 bool is_float = type == Primitive::kPrimFloat;
2415 size_t elem_size = Primitive::ComponentSize(type);
2416 LocationSummary* locations = rem->GetLocations();
2417 Location first = locations->InAt(0);
2418 Location second = locations->InAt(1);
2419 Location out = locations->Out();
2420
2421 // Create stack space for 2 elements.
2422 // TODO: enhance register allocator to ask for stack temporaries.
2423 __ subq(CpuRegister(RSP), Immediate(2 * elem_size));
2424
2425 // Load the values to the FP stack in reverse order, using temporaries if needed.
2426 PushOntoFPStack(second, elem_size, 2 * elem_size, is_float);
2427 PushOntoFPStack(first, 0, 2 * elem_size, is_float);
2428
2429 // Loop doing FPREM until we stabilize.
2430 Label retry;
2431 __ Bind(&retry);
2432 __ fprem();
2433
2434 // Move FP status to AX.
2435 __ fstsw();
2436
2437 // And see if the argument reduction is complete. This is signaled by the
2438 // C2 FPU flag bit set to 0.
2439 __ andl(CpuRegister(RAX), Immediate(kC2ConditionMask));
2440 __ j(kNotEqual, &retry);
2441
2442 // We have settled on the final value. Retrieve it into an XMM register.
2443 // Store FP top of stack to real stack.
2444 if (is_float) {
2445 __ fsts(Address(CpuRegister(RSP), 0));
2446 } else {
2447 __ fstl(Address(CpuRegister(RSP), 0));
2448 }
2449
2450 // Pop the 2 items from the FP stack.
2451 __ fucompp();
2452
2453 // Load the value from the stack into an XMM register.
2454 DCHECK(out.IsFpuRegister()) << out;
2455 if (is_float) {
2456 __ movss(out.AsFpuRegister<XmmRegister>(), Address(CpuRegister(RSP), 0));
2457 } else {
2458 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(CpuRegister(RSP), 0));
2459 }
2460
2461 // And remove the temporary stack space we allocated.
2462 __ addq(CpuRegister(RSP), Immediate(2 * elem_size));
2463}
2464
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002465void InstructionCodeGeneratorX86_64::DivRemOneOrMinusOne(HBinaryOperation* instruction) {
2466 DCHECK(instruction->IsDiv() || instruction->IsRem());
2467
2468 LocationSummary* locations = instruction->GetLocations();
2469 Location second = locations->InAt(1);
2470 DCHECK(second.IsConstant());
2471
2472 CpuRegister output_register = locations->Out().AsRegister<CpuRegister>();
2473 CpuRegister input_register = locations->InAt(0).AsRegister<CpuRegister>();
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002474 int64_t imm = Int64FromConstant(second.GetConstant());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002475
2476 DCHECK(imm == 1 || imm == -1);
2477
2478 switch (instruction->GetResultType()) {
2479 case Primitive::kPrimInt: {
2480 if (instruction->IsRem()) {
2481 __ xorl(output_register, output_register);
2482 } else {
2483 __ movl(output_register, input_register);
2484 if (imm == -1) {
2485 __ negl(output_register);
2486 }
2487 }
2488 break;
2489 }
2490
2491 case Primitive::kPrimLong: {
2492 if (instruction->IsRem()) {
Mark Mendell92e83bf2015-05-07 11:25:03 -04002493 __ xorl(output_register, output_register);
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002494 } else {
2495 __ movq(output_register, input_register);
2496 if (imm == -1) {
2497 __ negq(output_register);
2498 }
2499 }
2500 break;
2501 }
2502
2503 default:
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002504 LOG(FATAL) << "Unexpected type for div by (-)1 " << instruction->GetResultType();
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002505 }
2506}
2507
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002508void InstructionCodeGeneratorX86_64::DivByPowerOfTwo(HDiv* instruction) {
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002509 LocationSummary* locations = instruction->GetLocations();
2510 Location second = locations->InAt(1);
2511
2512 CpuRegister output_register = locations->Out().AsRegister<CpuRegister>();
2513 CpuRegister numerator = locations->InAt(0).AsRegister<CpuRegister>();
2514
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002515 int64_t imm = Int64FromConstant(second.GetConstant());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002516
2517 DCHECK(IsPowerOfTwo(std::abs(imm)));
2518
2519 CpuRegister tmp = locations->GetTemp(0).AsRegister<CpuRegister>();
2520
2521 if (instruction->GetResultType() == Primitive::kPrimInt) {
2522 __ leal(tmp, Address(numerator, std::abs(imm) - 1));
2523 __ testl(numerator, numerator);
2524 __ cmov(kGreaterEqual, tmp, numerator);
2525 int shift = CTZ(imm);
2526 __ sarl(tmp, Immediate(shift));
2527
2528 if (imm < 0) {
2529 __ negl(tmp);
2530 }
2531
2532 __ movl(output_register, tmp);
2533 } else {
2534 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
2535 CpuRegister rdx = locations->GetTemp(0).AsRegister<CpuRegister>();
2536
Mark Mendell92e83bf2015-05-07 11:25:03 -04002537 codegen_->Load64BitValue(rdx, std::abs(imm) - 1);
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002538 __ addq(rdx, numerator);
2539 __ testq(numerator, numerator);
2540 __ cmov(kGreaterEqual, rdx, numerator);
2541 int shift = CTZ(imm);
2542 __ sarq(rdx, Immediate(shift));
2543
2544 if (imm < 0) {
2545 __ negq(rdx);
2546 }
2547
2548 __ movq(output_register, rdx);
2549 }
2550}
2551
2552void InstructionCodeGeneratorX86_64::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) {
2553 DCHECK(instruction->IsDiv() || instruction->IsRem());
2554
2555 LocationSummary* locations = instruction->GetLocations();
2556 Location second = locations->InAt(1);
2557
2558 CpuRegister numerator = instruction->IsDiv() ? locations->GetTemp(1).AsRegister<CpuRegister>()
2559 : locations->GetTemp(0).AsRegister<CpuRegister>();
2560 CpuRegister eax = locations->InAt(0).AsRegister<CpuRegister>();
2561 CpuRegister edx = instruction->IsDiv() ? locations->GetTemp(0).AsRegister<CpuRegister>()
2562 : locations->Out().AsRegister<CpuRegister>();
2563 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
2564
2565 DCHECK_EQ(RAX, eax.AsRegister());
2566 DCHECK_EQ(RDX, edx.AsRegister());
2567 if (instruction->IsDiv()) {
2568 DCHECK_EQ(RAX, out.AsRegister());
2569 } else {
2570 DCHECK_EQ(RDX, out.AsRegister());
2571 }
2572
2573 int64_t magic;
2574 int shift;
2575
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002576 // TODO: can these branches be written as one?
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002577 if (instruction->GetResultType() == Primitive::kPrimInt) {
2578 int imm = second.GetConstant()->AsIntConstant()->GetValue();
2579
2580 CalculateMagicAndShiftForDivRem(imm, false /* is_long */, &magic, &shift);
2581
2582 __ movl(numerator, eax);
2583
2584 Label no_div;
2585 Label end;
2586 __ testl(eax, eax);
2587 __ j(kNotEqual, &no_div);
2588
2589 __ xorl(out, out);
2590 __ jmp(&end);
2591
2592 __ Bind(&no_div);
2593
2594 __ movl(eax, Immediate(magic));
2595 __ imull(numerator);
2596
2597 if (imm > 0 && magic < 0) {
2598 __ addl(edx, numerator);
2599 } else if (imm < 0 && magic > 0) {
2600 __ subl(edx, numerator);
2601 }
2602
2603 if (shift != 0) {
2604 __ sarl(edx, Immediate(shift));
2605 }
2606
2607 __ movl(eax, edx);
2608 __ shrl(edx, Immediate(31));
2609 __ addl(edx, eax);
2610
2611 if (instruction->IsRem()) {
2612 __ movl(eax, numerator);
2613 __ imull(edx, Immediate(imm));
2614 __ subl(eax, edx);
2615 __ movl(edx, eax);
2616 } else {
2617 __ movl(eax, edx);
2618 }
2619 __ Bind(&end);
2620 } else {
2621 int64_t imm = second.GetConstant()->AsLongConstant()->GetValue();
2622
2623 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
2624
2625 CpuRegister rax = eax;
2626 CpuRegister rdx = edx;
2627
2628 CalculateMagicAndShiftForDivRem(imm, true /* is_long */, &magic, &shift);
2629
2630 // Save the numerator.
2631 __ movq(numerator, rax);
2632
2633 // RAX = magic
Mark Mendell92e83bf2015-05-07 11:25:03 -04002634 codegen_->Load64BitValue(rax, magic);
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002635
2636 // RDX:RAX = magic * numerator
2637 __ imulq(numerator);
2638
2639 if (imm > 0 && magic < 0) {
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002640 // RDX += numerator
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002641 __ addq(rdx, numerator);
2642 } else if (imm < 0 && magic > 0) {
2643 // RDX -= numerator
2644 __ subq(rdx, numerator);
2645 }
2646
2647 // Shift if needed.
2648 if (shift != 0) {
2649 __ sarq(rdx, Immediate(shift));
2650 }
2651
2652 // RDX += 1 if RDX < 0
2653 __ movq(rax, rdx);
2654 __ shrq(rdx, Immediate(63));
2655 __ addq(rdx, rax);
2656
2657 if (instruction->IsRem()) {
2658 __ movq(rax, numerator);
2659
2660 if (IsInt<32>(imm)) {
2661 __ imulq(rdx, Immediate(static_cast<int32_t>(imm)));
2662 } else {
Mark Mendell92e83bf2015-05-07 11:25:03 -04002663 __ imulq(rdx, codegen_->LiteralInt64Address(imm));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002664 }
2665
2666 __ subq(rax, rdx);
2667 __ movq(rdx, rax);
2668 } else {
2669 __ movq(rax, rdx);
2670 }
2671 }
2672}
2673
Calin Juravlebacfec32014-11-14 15:54:36 +00002674void InstructionCodeGeneratorX86_64::GenerateDivRemIntegral(HBinaryOperation* instruction) {
2675 DCHECK(instruction->IsDiv() || instruction->IsRem());
2676 Primitive::Type type = instruction->GetResultType();
2677 DCHECK(type == Primitive::kPrimInt || Primitive::kPrimLong);
2678
2679 bool is_div = instruction->IsDiv();
2680 LocationSummary* locations = instruction->GetLocations();
2681
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002682 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
2683 Location second = locations->InAt(1);
Calin Juravlebacfec32014-11-14 15:54:36 +00002684
Roland Levillain271ab9c2014-11-27 15:23:57 +00002685 DCHECK_EQ(RAX, locations->InAt(0).AsRegister<CpuRegister>().AsRegister());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002686 DCHECK_EQ(is_div ? RAX : RDX, out.AsRegister());
Calin Juravlebacfec32014-11-14 15:54:36 +00002687
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002688 if (second.IsConstant()) {
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002689 int64_t imm = Int64FromConstant(second.GetConstant());
Calin Juravlebacfec32014-11-14 15:54:36 +00002690
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002691 if (imm == 0) {
2692 // Do not generate anything. DivZeroCheck would prevent any code to be executed.
2693 } else if (imm == 1 || imm == -1) {
2694 DivRemOneOrMinusOne(instruction);
2695 } else if (instruction->IsDiv() && IsPowerOfTwo(std::abs(imm))) {
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002696 DivByPowerOfTwo(instruction->AsDiv());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002697 } else {
2698 DCHECK(imm <= -2 || imm >= 2);
2699 GenerateDivRemWithAnyConstant(instruction);
2700 }
Calin Juravlebacfec32014-11-14 15:54:36 +00002701 } else {
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002702 SlowPathCodeX86_64* slow_path =
2703 new (GetGraph()->GetArena()) DivRemMinusOneSlowPathX86_64(
2704 out.AsRegister(), type, is_div);
2705 codegen_->AddSlowPath(slow_path);
Calin Juravlebacfec32014-11-14 15:54:36 +00002706
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002707 CpuRegister second_reg = second.AsRegister<CpuRegister>();
2708 // 0x80000000(00000000)/-1 triggers an arithmetic exception!
2709 // Dividing by -1 is actually negation and -0x800000000(00000000) = 0x80000000(00000000)
2710 // so it's safe to just use negl instead of more complex comparisons.
2711 if (type == Primitive::kPrimInt) {
2712 __ cmpl(second_reg, Immediate(-1));
2713 __ j(kEqual, slow_path->GetEntryLabel());
2714 // edx:eax <- sign-extended of eax
2715 __ cdq();
2716 // eax = quotient, edx = remainder
2717 __ idivl(second_reg);
2718 } else {
2719 __ cmpq(second_reg, Immediate(-1));
2720 __ j(kEqual, slow_path->GetEntryLabel());
2721 // rdx:rax <- sign-extended of rax
2722 __ cqo();
2723 // rax = quotient, rdx = remainder
2724 __ idivq(second_reg);
2725 }
2726 __ Bind(slow_path->GetExitLabel());
2727 }
Calin Juravlebacfec32014-11-14 15:54:36 +00002728}
2729
Calin Juravle7c4954d2014-10-28 16:57:40 +00002730void LocationsBuilderX86_64::VisitDiv(HDiv* div) {
2731 LocationSummary* locations =
2732 new (GetGraph()->GetArena()) LocationSummary(div, LocationSummary::kNoCall);
2733 switch (div->GetResultType()) {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002734 case Primitive::kPrimInt:
2735 case Primitive::kPrimLong: {
Calin Juravled0d48522014-11-04 16:40:20 +00002736 locations->SetInAt(0, Location::RegisterLocation(RAX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002737 locations->SetInAt(1, Location::RegisterOrConstant(div->InputAt(1)));
Calin Juravled0d48522014-11-04 16:40:20 +00002738 locations->SetOut(Location::SameAsFirstInput());
2739 // Intel uses edx:eax as the dividend.
2740 locations->AddTemp(Location::RegisterLocation(RDX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002741 // We need to save the numerator while we tweak rax and rdx. As we are using imul in a way
2742 // which enforces results to be in RAX and RDX, things are simpler if we use RDX also as
2743 // output and request another temp.
2744 if (div->InputAt(1)->IsConstant()) {
2745 locations->AddTemp(Location::RequiresRegister());
2746 }
Calin Juravled0d48522014-11-04 16:40:20 +00002747 break;
2748 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002749
Calin Juravle7c4954d2014-10-28 16:57:40 +00002750 case Primitive::kPrimFloat:
2751 case Primitive::kPrimDouble: {
2752 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendellf55c3e02015-03-26 21:07:46 -04002753 locations->SetInAt(1, Location::Any());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002754 locations->SetOut(Location::SameAsFirstInput());
2755 break;
2756 }
2757
2758 default:
2759 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2760 }
2761}
2762
2763void InstructionCodeGeneratorX86_64::VisitDiv(HDiv* div) {
2764 LocationSummary* locations = div->GetLocations();
2765 Location first = locations->InAt(0);
2766 Location second = locations->InAt(1);
2767 DCHECK(first.Equals(locations->Out()));
2768
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002769 Primitive::Type type = div->GetResultType();
2770 switch (type) {
2771 case Primitive::kPrimInt:
2772 case Primitive::kPrimLong: {
Calin Juravlebacfec32014-11-14 15:54:36 +00002773 GenerateDivRemIntegral(div);
Calin Juravled0d48522014-11-04 16:40:20 +00002774 break;
2775 }
2776
Calin Juravle7c4954d2014-10-28 16:57:40 +00002777 case Primitive::kPrimFloat: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04002778 if (second.IsFpuRegister()) {
2779 __ divss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2780 } else if (second.IsConstant()) {
2781 __ divss(first.AsFpuRegister<XmmRegister>(),
2782 codegen_->LiteralFloatAddress(second.GetConstant()->AsFloatConstant()->GetValue()));
2783 } else {
2784 DCHECK(second.IsStackSlot());
2785 __ divss(first.AsFpuRegister<XmmRegister>(),
2786 Address(CpuRegister(RSP), second.GetStackIndex()));
2787 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00002788 break;
2789 }
2790
2791 case Primitive::kPrimDouble: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04002792 if (second.IsFpuRegister()) {
2793 __ divsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2794 } else if (second.IsConstant()) {
2795 __ divsd(first.AsFpuRegister<XmmRegister>(),
2796 codegen_->LiteralDoubleAddress(second.GetConstant()->AsDoubleConstant()->GetValue()));
2797 } else {
2798 DCHECK(second.IsDoubleStackSlot());
2799 __ divsd(first.AsFpuRegister<XmmRegister>(),
2800 Address(CpuRegister(RSP), second.GetStackIndex()));
2801 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00002802 break;
2803 }
2804
2805 default:
2806 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2807 }
2808}
2809
Calin Juravlebacfec32014-11-14 15:54:36 +00002810void LocationsBuilderX86_64::VisitRem(HRem* rem) {
Calin Juravled2ec87d2014-12-08 14:24:46 +00002811 Primitive::Type type = rem->GetResultType();
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002812 LocationSummary* locations =
2813 new (GetGraph()->GetArena()) LocationSummary(rem, LocationSummary::kNoCall);
Calin Juravled2ec87d2014-12-08 14:24:46 +00002814
2815 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00002816 case Primitive::kPrimInt:
2817 case Primitive::kPrimLong: {
2818 locations->SetInAt(0, Location::RegisterLocation(RAX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002819 locations->SetInAt(1, Location::RegisterOrConstant(rem->InputAt(1)));
Calin Juravlebacfec32014-11-14 15:54:36 +00002820 // Intel uses rdx:rax as the dividend and puts the remainder in rdx
2821 locations->SetOut(Location::RegisterLocation(RDX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002822 // We need to save the numerator while we tweak eax and edx. As we are using imul in a way
2823 // which enforces results to be in RAX and RDX, things are simpler if we use EAX also as
2824 // output and request another temp.
2825 if (rem->InputAt(1)->IsConstant()) {
2826 locations->AddTemp(Location::RequiresRegister());
2827 }
Calin Juravlebacfec32014-11-14 15:54:36 +00002828 break;
2829 }
2830
2831 case Primitive::kPrimFloat:
2832 case Primitive::kPrimDouble: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002833 locations->SetInAt(0, Location::Any());
2834 locations->SetInAt(1, Location::Any());
2835 locations->SetOut(Location::RequiresFpuRegister());
2836 locations->AddTemp(Location::RegisterLocation(RAX));
Calin Juravlebacfec32014-11-14 15:54:36 +00002837 break;
2838 }
2839
2840 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00002841 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00002842 }
2843}
2844
2845void InstructionCodeGeneratorX86_64::VisitRem(HRem* rem) {
2846 Primitive::Type type = rem->GetResultType();
2847 switch (type) {
2848 case Primitive::kPrimInt:
2849 case Primitive::kPrimLong: {
2850 GenerateDivRemIntegral(rem);
2851 break;
2852 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002853 case Primitive::kPrimFloat:
Calin Juravled2ec87d2014-12-08 14:24:46 +00002854 case Primitive::kPrimDouble: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002855 GenerateRemFP(rem);
Calin Juravled2ec87d2014-12-08 14:24:46 +00002856 break;
2857 }
Calin Juravlebacfec32014-11-14 15:54:36 +00002858 default:
2859 LOG(FATAL) << "Unexpected rem type " << rem->GetResultType();
2860 }
2861}
2862
Calin Juravled0d48522014-11-04 16:40:20 +00002863void LocationsBuilderX86_64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
2864 LocationSummary* locations =
2865 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
2866 locations->SetInAt(0, Location::Any());
2867 if (instruction->HasUses()) {
2868 locations->SetOut(Location::SameAsFirstInput());
2869 }
2870}
2871
2872void InstructionCodeGeneratorX86_64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
2873 SlowPathCodeX86_64* slow_path =
2874 new (GetGraph()->GetArena()) DivZeroCheckSlowPathX86_64(instruction);
2875 codegen_->AddSlowPath(slow_path);
2876
2877 LocationSummary* locations = instruction->GetLocations();
2878 Location value = locations->InAt(0);
2879
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002880 switch (instruction->GetType()) {
2881 case Primitive::kPrimInt: {
2882 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002883 __ testl(value.AsRegister<CpuRegister>(), value.AsRegister<CpuRegister>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002884 __ j(kEqual, slow_path->GetEntryLabel());
2885 } else if (value.IsStackSlot()) {
2886 __ cmpl(Address(CpuRegister(RSP), value.GetStackIndex()), Immediate(0));
2887 __ j(kEqual, slow_path->GetEntryLabel());
2888 } else {
2889 DCHECK(value.IsConstant()) << value;
2890 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
2891 __ jmp(slow_path->GetEntryLabel());
2892 }
2893 }
2894 break;
Calin Juravled0d48522014-11-04 16:40:20 +00002895 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002896 case Primitive::kPrimLong: {
2897 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002898 __ testq(value.AsRegister<CpuRegister>(), value.AsRegister<CpuRegister>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002899 __ j(kEqual, slow_path->GetEntryLabel());
2900 } else if (value.IsDoubleStackSlot()) {
2901 __ cmpq(Address(CpuRegister(RSP), value.GetStackIndex()), Immediate(0));
2902 __ j(kEqual, slow_path->GetEntryLabel());
2903 } else {
2904 DCHECK(value.IsConstant()) << value;
2905 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
2906 __ jmp(slow_path->GetEntryLabel());
2907 }
2908 }
2909 break;
2910 }
2911 default:
2912 LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
Calin Juravled0d48522014-11-04 16:40:20 +00002913 }
Calin Juravled0d48522014-11-04 16:40:20 +00002914}
2915
Calin Juravle9aec02f2014-11-18 23:06:35 +00002916void LocationsBuilderX86_64::HandleShift(HBinaryOperation* op) {
2917 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
2918
2919 LocationSummary* locations =
2920 new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
2921
2922 switch (op->GetResultType()) {
2923 case Primitive::kPrimInt:
2924 case Primitive::kPrimLong: {
2925 locations->SetInAt(0, Location::RequiresRegister());
2926 // The shift count needs to be in CL.
2927 locations->SetInAt(1, Location::ByteRegisterOrConstant(RCX, op->InputAt(1)));
2928 locations->SetOut(Location::SameAsFirstInput());
2929 break;
2930 }
2931 default:
2932 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
2933 }
2934}
2935
2936void InstructionCodeGeneratorX86_64::HandleShift(HBinaryOperation* op) {
2937 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
2938
2939 LocationSummary* locations = op->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002940 CpuRegister first_reg = locations->InAt(0).AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002941 Location second = locations->InAt(1);
2942
2943 switch (op->GetResultType()) {
2944 case Primitive::kPrimInt: {
2945 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002946 CpuRegister second_reg = second.AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002947 if (op->IsShl()) {
2948 __ shll(first_reg, second_reg);
2949 } else if (op->IsShr()) {
2950 __ sarl(first_reg, second_reg);
2951 } else {
2952 __ shrl(first_reg, second_reg);
2953 }
2954 } else {
Nicolas Geoffray486cc192014-12-08 18:00:55 +00002955 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxIntShiftValue);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002956 if (op->IsShl()) {
2957 __ shll(first_reg, imm);
2958 } else if (op->IsShr()) {
2959 __ sarl(first_reg, imm);
2960 } else {
2961 __ shrl(first_reg, imm);
2962 }
2963 }
2964 break;
2965 }
2966 case Primitive::kPrimLong: {
2967 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002968 CpuRegister second_reg = second.AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002969 if (op->IsShl()) {
2970 __ shlq(first_reg, second_reg);
2971 } else if (op->IsShr()) {
2972 __ sarq(first_reg, second_reg);
2973 } else {
2974 __ shrq(first_reg, second_reg);
2975 }
2976 } else {
Nicolas Geoffray486cc192014-12-08 18:00:55 +00002977 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxLongShiftValue);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002978 if (op->IsShl()) {
2979 __ shlq(first_reg, imm);
2980 } else if (op->IsShr()) {
2981 __ sarq(first_reg, imm);
2982 } else {
2983 __ shrq(first_reg, imm);
2984 }
2985 }
2986 break;
2987 }
2988 default:
2989 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
2990 }
2991}
2992
2993void LocationsBuilderX86_64::VisitShl(HShl* shl) {
2994 HandleShift(shl);
2995}
2996
2997void InstructionCodeGeneratorX86_64::VisitShl(HShl* shl) {
2998 HandleShift(shl);
2999}
3000
3001void LocationsBuilderX86_64::VisitShr(HShr* shr) {
3002 HandleShift(shr);
3003}
3004
3005void InstructionCodeGeneratorX86_64::VisitShr(HShr* shr) {
3006 HandleShift(shr);
3007}
3008
3009void LocationsBuilderX86_64::VisitUShr(HUShr* ushr) {
3010 HandleShift(ushr);
3011}
3012
3013void InstructionCodeGeneratorX86_64::VisitUShr(HUShr* ushr) {
3014 HandleShift(ushr);
3015}
3016
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003017void LocationsBuilderX86_64::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003018 LocationSummary* locations =
3019 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01003020 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003021 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3022 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
3023 locations->SetOut(Location::RegisterLocation(RAX));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003024}
3025
3026void InstructionCodeGeneratorX86_64::VisitNewInstance(HNewInstance* instruction) {
3027 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003028 codegen_->LoadCurrentMethod(CpuRegister(calling_convention.GetRegisterAt(1)));
Mark Mendell92e83bf2015-05-07 11:25:03 -04003029 codegen_->Load64BitValue(CpuRegister(calling_convention.GetRegisterAt(0)),
3030 instruction->GetTypeIndex());
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +00003031 __ gs()->call(
3032 Address::Absolute(GetThreadOffset<kX86_64WordSize>(instruction->GetEntrypoint()), true));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003033
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01003034 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray39468442014-09-02 15:17:15 +01003035 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003036}
3037
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003038void LocationsBuilderX86_64::VisitNewArray(HNewArray* instruction) {
3039 LocationSummary* locations =
3040 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
3041 InvokeRuntimeCallingConvention calling_convention;
3042 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08003043 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003044 locations->SetOut(Location::RegisterLocation(RAX));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08003045 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003046}
3047
3048void InstructionCodeGeneratorX86_64::VisitNewArray(HNewArray* instruction) {
3049 InvokeRuntimeCallingConvention calling_convention;
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08003050 codegen_->LoadCurrentMethod(CpuRegister(calling_convention.GetRegisterAt(2)));
Mark Mendell92e83bf2015-05-07 11:25:03 -04003051 codegen_->Load64BitValue(CpuRegister(calling_convention.GetRegisterAt(0)),
3052 instruction->GetTypeIndex());
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003053
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +00003054 __ gs()->call(
3055 Address::Absolute(GetThreadOffset<kX86_64WordSize>(instruction->GetEntrypoint()), true));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003056
3057 DCHECK(!codegen_->IsLeafMethod());
3058 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3059}
3060
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003061void LocationsBuilderX86_64::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003062 LocationSummary* locations =
3063 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003064 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
3065 if (location.IsStackSlot()) {
3066 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
3067 } else if (location.IsDoubleStackSlot()) {
3068 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
3069 }
3070 locations->SetOut(location);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003071}
3072
3073void InstructionCodeGeneratorX86_64::VisitParameterValue(HParameterValue* instruction) {
3074 // Nothing to do, the parameter is already at its location.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003075 UNUSED(instruction);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003076}
3077
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003078void LocationsBuilderX86_64::VisitNot(HNot* not_) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003079 LocationSummary* locations =
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003080 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003081 locations->SetInAt(0, Location::RequiresRegister());
3082 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003083}
3084
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003085void InstructionCodeGeneratorX86_64::VisitNot(HNot* not_) {
3086 LocationSummary* locations = not_->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003087 DCHECK_EQ(locations->InAt(0).AsRegister<CpuRegister>().AsRegister(),
3088 locations->Out().AsRegister<CpuRegister>().AsRegister());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003089 Location out = locations->Out();
Nicolas Geoffrayd8ef2e92015-02-24 16:02:06 +00003090 switch (not_->GetResultType()) {
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003091 case Primitive::kPrimInt:
Roland Levillain271ab9c2014-11-27 15:23:57 +00003092 __ notl(out.AsRegister<CpuRegister>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003093 break;
3094
3095 case Primitive::kPrimLong:
Roland Levillain271ab9c2014-11-27 15:23:57 +00003096 __ notq(out.AsRegister<CpuRegister>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003097 break;
3098
3099 default:
3100 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
3101 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003102}
3103
David Brazdil66d126e2015-04-03 16:02:44 +01003104void LocationsBuilderX86_64::VisitBooleanNot(HBooleanNot* bool_not) {
3105 LocationSummary* locations =
3106 new (GetGraph()->GetArena()) LocationSummary(bool_not, LocationSummary::kNoCall);
3107 locations->SetInAt(0, Location::RequiresRegister());
3108 locations->SetOut(Location::SameAsFirstInput());
3109}
3110
3111void InstructionCodeGeneratorX86_64::VisitBooleanNot(HBooleanNot* bool_not) {
David Brazdil66d126e2015-04-03 16:02:44 +01003112 LocationSummary* locations = bool_not->GetLocations();
3113 DCHECK_EQ(locations->InAt(0).AsRegister<CpuRegister>().AsRegister(),
3114 locations->Out().AsRegister<CpuRegister>().AsRegister());
3115 Location out = locations->Out();
3116 __ xorl(out.AsRegister<CpuRegister>(), Immediate(1));
3117}
3118
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003119void LocationsBuilderX86_64::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003120 LocationSummary* locations =
3121 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003122 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
3123 locations->SetInAt(i, Location::Any());
3124 }
3125 locations->SetOut(Location::Any());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003126}
3127
3128void InstructionCodeGeneratorX86_64::VisitPhi(HPhi* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003129 UNUSED(instruction);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003130 LOG(FATAL) << "Unimplemented";
3131}
3132
Calin Juravle52c48962014-12-16 17:02:57 +00003133void InstructionCodeGeneratorX86_64::GenerateMemoryBarrier(MemBarrierKind kind) {
3134 /*
3135 * According to the JSR-133 Cookbook, for x86 only StoreLoad/AnyAny barriers need memory fence.
3136 * All other barriers (LoadAny, AnyStore, StoreStore) are nops due to the x86 memory model.
3137 * For those cases, all we need to ensure is that there is a scheduling barrier in place.
3138 */
3139 switch (kind) {
3140 case MemBarrierKind::kAnyAny: {
3141 __ mfence();
3142 break;
3143 }
3144 case MemBarrierKind::kAnyStore:
3145 case MemBarrierKind::kLoadAny:
3146 case MemBarrierKind::kStoreStore: {
3147 // nop
3148 break;
3149 }
3150 default:
3151 LOG(FATAL) << "Unexpected memory barier " << kind;
3152 }
3153}
3154
3155void LocationsBuilderX86_64::HandleFieldGet(HInstruction* instruction) {
3156 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
3157
Nicolas Geoffray39468442014-09-02 15:17:15 +01003158 LocationSummary* locations =
3159 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Calin Juravle52c48962014-12-16 17:02:57 +00003160 locations->SetInAt(0, Location::RequiresRegister());
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003161 if (Primitive::IsFloatingPointType(instruction->GetType())) {
3162 locations->SetOut(Location::RequiresFpuRegister());
3163 } else {
3164 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3165 }
Calin Juravle52c48962014-12-16 17:02:57 +00003166}
3167
3168void InstructionCodeGeneratorX86_64::HandleFieldGet(HInstruction* instruction,
3169 const FieldInfo& field_info) {
3170 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
3171
3172 LocationSummary* locations = instruction->GetLocations();
3173 CpuRegister base = locations->InAt(0).AsRegister<CpuRegister>();
3174 Location out = locations->Out();
3175 bool is_volatile = field_info.IsVolatile();
3176 Primitive::Type field_type = field_info.GetFieldType();
3177 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
3178
3179 switch (field_type) {
3180 case Primitive::kPrimBoolean: {
3181 __ movzxb(out.AsRegister<CpuRegister>(), Address(base, offset));
3182 break;
3183 }
3184
3185 case Primitive::kPrimByte: {
3186 __ movsxb(out.AsRegister<CpuRegister>(), Address(base, offset));
3187 break;
3188 }
3189
3190 case Primitive::kPrimShort: {
3191 __ movsxw(out.AsRegister<CpuRegister>(), Address(base, offset));
3192 break;
3193 }
3194
3195 case Primitive::kPrimChar: {
3196 __ movzxw(out.AsRegister<CpuRegister>(), Address(base, offset));
3197 break;
3198 }
3199
3200 case Primitive::kPrimInt:
3201 case Primitive::kPrimNot: {
3202 __ movl(out.AsRegister<CpuRegister>(), Address(base, offset));
3203 break;
3204 }
3205
3206 case Primitive::kPrimLong: {
3207 __ movq(out.AsRegister<CpuRegister>(), Address(base, offset));
3208 break;
3209 }
3210
3211 case Primitive::kPrimFloat: {
3212 __ movss(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
3213 break;
3214 }
3215
3216 case Primitive::kPrimDouble: {
3217 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
3218 break;
3219 }
3220
3221 case Primitive::kPrimVoid:
3222 LOG(FATAL) << "Unreachable type " << field_type;
3223 UNREACHABLE();
3224 }
3225
Calin Juravle77520bc2015-01-12 18:45:46 +00003226 codegen_->MaybeRecordImplicitNullCheck(instruction);
3227
Calin Juravle52c48962014-12-16 17:02:57 +00003228 if (is_volatile) {
3229 GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
3230 }
3231}
3232
3233void LocationsBuilderX86_64::HandleFieldSet(HInstruction* instruction,
3234 const FieldInfo& field_info) {
3235 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3236
3237 LocationSummary* locations =
3238 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003239 bool needs_write_barrier =
Calin Juravle52c48962014-12-16 17:02:57 +00003240 CodeGenerator::StoreNeedsWriteBarrier(field_info.GetFieldType(), instruction->InputAt(1));
3241
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003242 locations->SetInAt(0, Location::RequiresRegister());
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003243 if (Primitive::IsFloatingPointType(instruction->InputAt(1)->GetType())) {
3244 locations->SetInAt(1, Location::RequiresFpuRegister());
3245 } else {
Mark Mendell40741f32015-04-20 22:10:34 -04003246 locations->SetInAt(1, Location::RegisterOrInt32LongConstant(instruction->InputAt(1)));
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003247 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003248 if (needs_write_barrier) {
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01003249 // Temporary registers for the write barrier.
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003250 locations->AddTemp(Location::RequiresRegister());
3251 locations->AddTemp(Location::RequiresRegister());
3252 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003253}
3254
Calin Juravle52c48962014-12-16 17:02:57 +00003255void InstructionCodeGeneratorX86_64::HandleFieldSet(HInstruction* instruction,
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003256 const FieldInfo& field_info,
3257 bool value_can_be_null) {
Calin Juravle52c48962014-12-16 17:02:57 +00003258 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3259
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003260 LocationSummary* locations = instruction->GetLocations();
Calin Juravle52c48962014-12-16 17:02:57 +00003261 CpuRegister base = locations->InAt(0).AsRegister<CpuRegister>();
3262 Location value = locations->InAt(1);
3263 bool is_volatile = field_info.IsVolatile();
3264 Primitive::Type field_type = field_info.GetFieldType();
3265 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
3266
3267 if (is_volatile) {
3268 GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
3269 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003270
3271 switch (field_type) {
3272 case Primitive::kPrimBoolean:
3273 case Primitive::kPrimByte: {
Mark Mendell40741f32015-04-20 22:10:34 -04003274 if (value.IsConstant()) {
3275 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
3276 __ movb(Address(base, offset), Immediate(v));
3277 } else {
3278 __ movb(Address(base, offset), value.AsRegister<CpuRegister>());
3279 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003280 break;
3281 }
3282
3283 case Primitive::kPrimShort:
3284 case Primitive::kPrimChar: {
Mark Mendell40741f32015-04-20 22:10:34 -04003285 if (value.IsConstant()) {
3286 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
3287 __ movw(Address(base, offset), Immediate(v));
3288 } else {
3289 __ movw(Address(base, offset), value.AsRegister<CpuRegister>());
3290 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003291 break;
3292 }
3293
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003294 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003295 case Primitive::kPrimNot: {
Mark Mendell40741f32015-04-20 22:10:34 -04003296 if (value.IsConstant()) {
3297 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
3298 __ movw(Address(base, offset), Immediate(v));
3299 } else {
3300 __ movl(Address(base, offset), value.AsRegister<CpuRegister>());
3301 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003302 break;
3303 }
3304
3305 case Primitive::kPrimLong: {
Mark Mendell40741f32015-04-20 22:10:34 -04003306 if (value.IsConstant()) {
3307 int64_t v = value.GetConstant()->AsLongConstant()->GetValue();
3308 DCHECK(IsInt<32>(v));
3309 int32_t v_32 = v;
3310 __ movq(Address(base, offset), Immediate(v_32));
3311 } else {
3312 __ movq(Address(base, offset), value.AsRegister<CpuRegister>());
3313 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003314 break;
3315 }
3316
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003317 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00003318 __ movss(Address(base, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003319 break;
3320 }
3321
3322 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00003323 __ movsd(Address(base, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003324 break;
3325 }
3326
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003327 case Primitive::kPrimVoid:
3328 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003329 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003330 }
Calin Juravle52c48962014-12-16 17:02:57 +00003331
Calin Juravle77520bc2015-01-12 18:45:46 +00003332 codegen_->MaybeRecordImplicitNullCheck(instruction);
3333
3334 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
3335 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
3336 CpuRegister card = locations->GetTemp(1).AsRegister<CpuRegister>();
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003337 codegen_->MarkGCCard(temp, card, base, value.AsRegister<CpuRegister>(), value_can_be_null);
Calin Juravle77520bc2015-01-12 18:45:46 +00003338 }
3339
Calin Juravle52c48962014-12-16 17:02:57 +00003340 if (is_volatile) {
3341 GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
3342 }
3343}
3344
3345void LocationsBuilderX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
3346 HandleFieldSet(instruction, instruction->GetFieldInfo());
3347}
3348
3349void InstructionCodeGeneratorX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003350 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003351}
3352
3353void LocationsBuilderX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Calin Juravle52c48962014-12-16 17:02:57 +00003354 HandleFieldGet(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003355}
3356
3357void InstructionCodeGeneratorX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Calin Juravle52c48962014-12-16 17:02:57 +00003358 HandleFieldGet(instruction, instruction->GetFieldInfo());
3359}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003360
Calin Juravle52c48962014-12-16 17:02:57 +00003361void LocationsBuilderX86_64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
3362 HandleFieldGet(instruction);
3363}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003364
Calin Juravle52c48962014-12-16 17:02:57 +00003365void InstructionCodeGeneratorX86_64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
3366 HandleFieldGet(instruction, instruction->GetFieldInfo());
3367}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003368
Calin Juravle52c48962014-12-16 17:02:57 +00003369void LocationsBuilderX86_64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
3370 HandleFieldSet(instruction, instruction->GetFieldInfo());
3371}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003372
Calin Juravle52c48962014-12-16 17:02:57 +00003373void InstructionCodeGeneratorX86_64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003374 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003375}
3376
3377void LocationsBuilderX86_64::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003378 LocationSummary* locations =
3379 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003380 Location loc = codegen_->GetCompilerOptions().GetImplicitNullChecks()
3381 ? Location::RequiresRegister()
3382 : Location::Any();
3383 locations->SetInAt(0, loc);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003384 if (instruction->HasUses()) {
3385 locations->SetOut(Location::SameAsFirstInput());
3386 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003387}
3388
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003389void InstructionCodeGeneratorX86_64::GenerateImplicitNullCheck(HNullCheck* instruction) {
Calin Juravle77520bc2015-01-12 18:45:46 +00003390 if (codegen_->CanMoveNullCheckToUser(instruction)) {
3391 return;
3392 }
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003393 LocationSummary* locations = instruction->GetLocations();
3394 Location obj = locations->InAt(0);
3395
3396 __ testl(CpuRegister(RAX), Address(obj.AsRegister<CpuRegister>(), 0));
3397 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3398}
3399
3400void InstructionCodeGeneratorX86_64::GenerateExplicitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +01003401 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathX86_64(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003402 codegen_->AddSlowPath(slow_path);
3403
3404 LocationSummary* locations = instruction->GetLocations();
3405 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003406
3407 if (obj.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00003408 __ testl(obj.AsRegister<CpuRegister>(), obj.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003409 } else if (obj.IsStackSlot()) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003410 __ cmpl(Address(CpuRegister(RSP), obj.GetStackIndex()), Immediate(0));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003411 } else {
3412 DCHECK(obj.IsConstant()) << obj;
3413 DCHECK_EQ(obj.GetConstant()->AsIntConstant()->GetValue(), 0);
3414 __ jmp(slow_path->GetEntryLabel());
3415 return;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003416 }
3417 __ j(kEqual, slow_path->GetEntryLabel());
3418}
3419
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003420void InstructionCodeGeneratorX86_64::VisitNullCheck(HNullCheck* instruction) {
3421 if (codegen_->GetCompilerOptions().GetImplicitNullChecks()) {
3422 GenerateImplicitNullCheck(instruction);
3423 } else {
3424 GenerateExplicitNullCheck(instruction);
3425 }
3426}
3427
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003428void LocationsBuilderX86_64::VisitArrayGet(HArrayGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003429 LocationSummary* locations =
3430 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003431 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell40741f32015-04-20 22:10:34 -04003432 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003433 if (Primitive::IsFloatingPointType(instruction->GetType())) {
3434 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
3435 } else {
3436 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3437 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003438}
3439
3440void InstructionCodeGeneratorX86_64::VisitArrayGet(HArrayGet* instruction) {
3441 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003442 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003443 Location index = locations->InAt(1);
3444
3445 switch (instruction->GetType()) {
3446 case Primitive::kPrimBoolean: {
3447 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003448 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003449 if (index.IsConstant()) {
3450 __ movzxb(out, Address(obj,
3451 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
3452 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003453 __ movzxb(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003454 }
3455 break;
3456 }
3457
3458 case Primitive::kPrimByte: {
3459 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003460 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003461 if (index.IsConstant()) {
3462 __ movsxb(out, Address(obj,
3463 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
3464 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003465 __ movsxb(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003466 }
3467 break;
3468 }
3469
3470 case Primitive::kPrimShort: {
3471 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003472 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003473 if (index.IsConstant()) {
3474 __ movsxw(out, Address(obj,
3475 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
3476 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003477 __ movsxw(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003478 }
3479 break;
3480 }
3481
3482 case Primitive::kPrimChar: {
3483 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003484 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003485 if (index.IsConstant()) {
3486 __ movzxw(out, Address(obj,
3487 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
3488 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003489 __ movzxw(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003490 }
3491 break;
3492 }
3493
3494 case Primitive::kPrimInt:
3495 case Primitive::kPrimNot: {
3496 DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t));
3497 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003498 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003499 if (index.IsConstant()) {
3500 __ movl(out, Address(obj,
3501 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
3502 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003503 __ movl(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003504 }
3505 break;
3506 }
3507
3508 case Primitive::kPrimLong: {
3509 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003510 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003511 if (index.IsConstant()) {
3512 __ movq(out, Address(obj,
3513 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
3514 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003515 __ movq(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003516 }
3517 break;
3518 }
3519
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003520 case Primitive::kPrimFloat: {
3521 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003522 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003523 if (index.IsConstant()) {
3524 __ movss(out, Address(obj,
3525 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
3526 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003527 __ movss(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003528 }
3529 break;
3530 }
3531
3532 case Primitive::kPrimDouble: {
3533 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003534 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003535 if (index.IsConstant()) {
3536 __ movsd(out, Address(obj,
3537 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
3538 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003539 __ movsd(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003540 }
3541 break;
3542 }
3543
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003544 case Primitive::kPrimVoid:
3545 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07003546 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003547 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003548 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003549}
3550
3551void LocationsBuilderX86_64::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003552 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003553
3554 bool needs_write_barrier =
3555 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
3556 bool needs_runtime_call = instruction->NeedsTypeCheck();
3557
Nicolas Geoffray39468442014-09-02 15:17:15 +01003558 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003559 instruction, needs_runtime_call ? LocationSummary::kCall : LocationSummary::kNoCall);
3560 if (needs_runtime_call) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003561 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003562 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3563 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
3564 locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003565 } else {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003566 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01003567 locations->SetInAt(
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003568 1, Location::RegisterOrConstant(instruction->InputAt(1)));
3569 locations->SetInAt(2, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003570 if (value_type == Primitive::kPrimLong) {
Mark Mendell40741f32015-04-20 22:10:34 -04003571 locations->SetInAt(2, Location::RegisterOrInt32LongConstant(instruction->InputAt(2)));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003572 } else if (value_type == Primitive::kPrimFloat || value_type == Primitive::kPrimDouble) {
3573 locations->SetInAt(2, Location::RequiresFpuRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003574 } else {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003575 locations->SetInAt(2, Location::RegisterOrConstant(instruction->InputAt(2)));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003576 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003577
3578 if (needs_write_barrier) {
3579 // Temporary registers for the write barrier.
3580 locations->AddTemp(Location::RequiresRegister());
3581 locations->AddTemp(Location::RequiresRegister());
3582 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003583 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003584}
3585
3586void InstructionCodeGeneratorX86_64::VisitArraySet(HArraySet* instruction) {
3587 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003588 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003589 Location index = locations->InAt(1);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003590 Location value = locations->InAt(2);
Nicolas Geoffray39468442014-09-02 15:17:15 +01003591 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003592 bool needs_runtime_call = locations->WillCall();
3593 bool needs_write_barrier =
3594 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003595
3596 switch (value_type) {
3597 case Primitive::kPrimBoolean:
3598 case Primitive::kPrimByte: {
3599 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003600 if (index.IsConstant()) {
3601 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003602 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003603 __ movb(Address(obj, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003604 } else {
Roland Levillain199f3362014-11-27 17:15:16 +00003605 __ movb(Address(obj, offset),
3606 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003607 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003608 } else {
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003609 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003610 __ movb(Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset),
3611 value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003612 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003613 __ movb(Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003614 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3615 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003616 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003617 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003618 break;
3619 }
3620
3621 case Primitive::kPrimShort:
3622 case Primitive::kPrimChar: {
3623 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003624 if (index.IsConstant()) {
3625 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003626 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003627 __ movw(Address(obj, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003628 } else {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003629 DCHECK(value.IsConstant()) << value;
Roland Levillain199f3362014-11-27 17:15:16 +00003630 __ movw(Address(obj, offset),
3631 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003632 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003633 } else {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003634 DCHECK(index.IsRegister()) << index;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003635 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003636 __ movw(Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset),
3637 value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003638 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003639 DCHECK(value.IsConstant()) << value;
Roland Levillain271ab9c2014-11-27 15:23:57 +00003640 __ movw(Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003641 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3642 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003643 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003644 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003645 break;
3646 }
3647
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003648 case Primitive::kPrimInt:
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003649 case Primitive::kPrimNot: {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003650 if (!needs_runtime_call) {
3651 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
3652 if (index.IsConstant()) {
3653 size_t offset =
3654 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
3655 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003656 __ movl(Address(obj, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003657 } else {
3658 DCHECK(value.IsConstant()) << value;
Mark Mendell40741f32015-04-20 22:10:34 -04003659 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
3660 __ movl(Address(obj, offset), Immediate(v));
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003661 }
3662 } else {
3663 DCHECK(index.IsRegister()) << index;
3664 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003665 __ movl(Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset),
3666 value.AsRegister<CpuRegister>());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003667 } else {
3668 DCHECK(value.IsConstant()) << value;
Mark Mendell40741f32015-04-20 22:10:34 -04003669 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003670 __ movl(Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset),
Mark Mendell40741f32015-04-20 22:10:34 -04003671 Immediate(v));
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003672 }
3673 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003674 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003675 if (needs_write_barrier) {
3676 DCHECK_EQ(value_type, Primitive::kPrimNot);
Roland Levillain271ab9c2014-11-27 15:23:57 +00003677 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
3678 CpuRegister card = locations->GetTemp(1).AsRegister<CpuRegister>();
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003679 codegen_->MarkGCCard(
3680 temp, card, obj, value.AsRegister<CpuRegister>(), instruction->GetValueCanBeNull());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003681 }
3682 } else {
3683 DCHECK_EQ(value_type, Primitive::kPrimNot);
Roland Levillain199f3362014-11-27 17:15:16 +00003684 __ gs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pAputObject),
3685 true));
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003686 DCHECK(!codegen_->IsLeafMethod());
3687 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3688 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003689 break;
3690 }
3691
3692 case Primitive::kPrimLong: {
3693 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003694 if (index.IsConstant()) {
3695 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Mark Mendell40741f32015-04-20 22:10:34 -04003696 if (value.IsRegister()) {
3697 __ movq(Address(obj, offset), value.AsRegister<CpuRegister>());
3698 } else {
3699 int64_t v = value.GetConstant()->AsLongConstant()->GetValue();
3700 DCHECK(IsInt<32>(v));
3701 int32_t v_32 = v;
3702 __ movq(Address(obj, offset), Immediate(v_32));
3703 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003704 } else {
Mark Mendell40741f32015-04-20 22:10:34 -04003705 if (value.IsRegister()) {
3706 __ movq(Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset),
3707 value.AsRegister<CpuRegister>());
3708 } else {
3709 int64_t v = value.GetConstant()->AsLongConstant()->GetValue();
3710 DCHECK(IsInt<32>(v));
3711 int32_t v_32 = v;
3712 __ movq(Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset),
3713 Immediate(v_32));
3714 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003715 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003716 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003717 break;
3718 }
3719
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003720 case Primitive::kPrimFloat: {
3721 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
3722 if (index.IsConstant()) {
3723 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
3724 DCHECK(value.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003725 __ movss(Address(obj, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003726 } else {
3727 DCHECK(value.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003728 __ movss(Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset),
3729 value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003730 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003731 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003732 break;
3733 }
3734
3735 case Primitive::kPrimDouble: {
3736 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
3737 if (index.IsConstant()) {
3738 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
3739 DCHECK(value.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003740 __ movsd(Address(obj, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003741 } else {
3742 DCHECK(value.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003743 __ movsd(Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset),
3744 value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003745 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003746 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003747 break;
3748 }
3749
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003750 case Primitive::kPrimVoid:
3751 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07003752 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003753 }
3754}
3755
3756void LocationsBuilderX86_64::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003757 LocationSummary* locations =
3758 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003759 locations->SetInAt(0, Location::RequiresRegister());
3760 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003761}
3762
3763void InstructionCodeGeneratorX86_64::VisitArrayLength(HArrayLength* instruction) {
3764 LocationSummary* locations = instruction->GetLocations();
3765 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003766 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
3767 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003768 __ movl(out, Address(obj, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00003769 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003770}
3771
3772void LocationsBuilderX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003773 LocationSummary* locations =
3774 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Mark Mendellf60c90b2015-03-04 15:12:59 -05003775 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
Mark Mendell99dbd682015-04-22 16:18:52 -04003776 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003777 if (instruction->HasUses()) {
3778 locations->SetOut(Location::SameAsFirstInput());
3779 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003780}
3781
3782void InstructionCodeGeneratorX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
3783 LocationSummary* locations = instruction->GetLocations();
Mark Mendellf60c90b2015-03-04 15:12:59 -05003784 Location index_loc = locations->InAt(0);
3785 Location length_loc = locations->InAt(1);
3786 SlowPathCodeX86_64* slow_path =
3787 new (GetGraph()->GetArena()) BoundsCheckSlowPathX86_64(instruction, index_loc, length_loc);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003788
Mark Mendell99dbd682015-04-22 16:18:52 -04003789 if (length_loc.IsConstant()) {
3790 int32_t length = CodeGenerator::GetInt32ValueOf(length_loc.GetConstant());
3791 if (index_loc.IsConstant()) {
3792 // BCE will remove the bounds check if we are guarenteed to pass.
3793 int32_t index = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
3794 if (index < 0 || index >= length) {
3795 codegen_->AddSlowPath(slow_path);
3796 __ jmp(slow_path->GetEntryLabel());
3797 } else {
3798 // Some optimization after BCE may have generated this, and we should not
3799 // generate a bounds check if it is a valid range.
3800 }
3801 return;
3802 }
3803
3804 // We have to reverse the jump condition because the length is the constant.
3805 CpuRegister index_reg = index_loc.AsRegister<CpuRegister>();
3806 __ cmpl(index_reg, Immediate(length));
3807 codegen_->AddSlowPath(slow_path);
3808 __ j(kAboveEqual, slow_path->GetEntryLabel());
Mark Mendellf60c90b2015-03-04 15:12:59 -05003809 } else {
Mark Mendell99dbd682015-04-22 16:18:52 -04003810 CpuRegister length = length_loc.AsRegister<CpuRegister>();
3811 if (index_loc.IsConstant()) {
3812 int32_t value = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
3813 __ cmpl(length, Immediate(value));
3814 } else {
3815 __ cmpl(length, index_loc.AsRegister<CpuRegister>());
3816 }
3817 codegen_->AddSlowPath(slow_path);
3818 __ j(kBelowEqual, slow_path->GetEntryLabel());
Mark Mendellf60c90b2015-03-04 15:12:59 -05003819 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003820}
3821
3822void CodeGeneratorX86_64::MarkGCCard(CpuRegister temp,
3823 CpuRegister card,
3824 CpuRegister object,
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003825 CpuRegister value,
3826 bool value_can_be_null) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003827 Label is_null;
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003828 if (value_can_be_null) {
3829 __ testl(value, value);
3830 __ j(kEqual, &is_null);
3831 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003832 __ gs()->movq(card, Address::Absolute(
3833 Thread::CardTableOffset<kX86_64WordSize>().Int32Value(), true));
3834 __ movq(temp, object);
3835 __ shrq(temp, Immediate(gc::accounting::CardTable::kCardShift));
3836 __ movb(Address(temp, card, TIMES_1, 0), card);
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003837 if (value_can_be_null) {
3838 __ Bind(&is_null);
3839 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003840}
3841
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003842void LocationsBuilderX86_64::VisitTemporary(HTemporary* temp) {
3843 temp->SetLocations(nullptr);
3844}
3845
3846void InstructionCodeGeneratorX86_64::VisitTemporary(HTemporary* temp) {
3847 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003848 UNUSED(temp);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003849}
3850
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003851void LocationsBuilderX86_64::VisitParallelMove(HParallelMove* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003852 UNUSED(instruction);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003853 LOG(FATAL) << "Unimplemented";
3854}
3855
3856void InstructionCodeGeneratorX86_64::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003857 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
3858}
3859
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003860void LocationsBuilderX86_64::VisitSuspendCheck(HSuspendCheck* instruction) {
3861 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
3862}
3863
3864void InstructionCodeGeneratorX86_64::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003865 HBasicBlock* block = instruction->GetBlock();
3866 if (block->GetLoopInformation() != nullptr) {
3867 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
3868 // The back edge will generate the suspend check.
3869 return;
3870 }
3871 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
3872 // The goto will generate the suspend check.
3873 return;
3874 }
3875 GenerateSuspendCheck(instruction, nullptr);
3876}
3877
3878void InstructionCodeGeneratorX86_64::GenerateSuspendCheck(HSuspendCheck* instruction,
3879 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003880 SuspendCheckSlowPathX86_64* slow_path =
Nicolas Geoffraydb216f42015-05-05 17:02:20 +01003881 down_cast<SuspendCheckSlowPathX86_64*>(instruction->GetSlowPath());
3882 if (slow_path == nullptr) {
3883 slow_path = new (GetGraph()->GetArena()) SuspendCheckSlowPathX86_64(instruction, successor);
3884 instruction->SetSlowPath(slow_path);
3885 codegen_->AddSlowPath(slow_path);
3886 if (successor != nullptr) {
3887 DCHECK(successor->IsLoopHeader());
3888 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(instruction);
3889 }
3890 } else {
3891 DCHECK_EQ(slow_path->GetSuccessor(), successor);
3892 }
3893
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003894 __ gs()->cmpw(Address::Absolute(
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003895 Thread::ThreadFlagsOffset<kX86_64WordSize>().Int32Value(), true), Immediate(0));
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003896 if (successor == nullptr) {
3897 __ j(kNotEqual, slow_path->GetEntryLabel());
3898 __ Bind(slow_path->GetReturnLabel());
3899 } else {
3900 __ j(kEqual, codegen_->GetLabelOf(successor));
3901 __ jmp(slow_path->GetEntryLabel());
3902 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003903}
3904
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003905X86_64Assembler* ParallelMoveResolverX86_64::GetAssembler() const {
3906 return codegen_->GetAssembler();
3907}
3908
3909void ParallelMoveResolverX86_64::EmitMove(size_t index) {
3910 MoveOperands* move = moves_.Get(index);
3911 Location source = move->GetSource();
3912 Location destination = move->GetDestination();
3913
3914 if (source.IsRegister()) {
3915 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003916 __ movq(destination.AsRegister<CpuRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003917 } else if (destination.IsStackSlot()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003918 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00003919 source.AsRegister<CpuRegister>());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003920 } else {
3921 DCHECK(destination.IsDoubleStackSlot());
3922 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00003923 source.AsRegister<CpuRegister>());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003924 }
3925 } else if (source.IsStackSlot()) {
3926 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003927 __ movl(destination.AsRegister<CpuRegister>(),
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003928 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003929 } else if (destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003930 __ movss(destination.AsFpuRegister<XmmRegister>(),
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003931 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003932 } else {
3933 DCHECK(destination.IsStackSlot());
3934 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
3935 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
3936 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003937 } else if (source.IsDoubleStackSlot()) {
3938 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003939 __ movq(destination.AsRegister<CpuRegister>(),
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003940 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003941 } else if (destination.IsFpuRegister()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003942 __ movsd(destination.AsFpuRegister<XmmRegister>(),
3943 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003944 } else {
Nicolas Geoffrayc8147a72014-10-21 16:06:20 +01003945 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003946 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
3947 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
3948 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003949 } else if (source.IsConstant()) {
3950 HConstant* constant = source.GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00003951 if (constant->IsIntConstant() || constant->IsNullConstant()) {
3952 int32_t value = CodeGenerator::GetInt32ValueOf(constant);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003953 if (destination.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00003954 if (value == 0) {
3955 __ xorl(destination.AsRegister<CpuRegister>(), destination.AsRegister<CpuRegister>());
3956 } else {
3957 __ movl(destination.AsRegister<CpuRegister>(), Immediate(value));
3958 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003959 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003960 DCHECK(destination.IsStackSlot()) << destination;
Nicolas Geoffray748f1402015-01-27 08:17:54 +00003961 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), Immediate(value));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003962 }
3963 } else if (constant->IsLongConstant()) {
3964 int64_t value = constant->AsLongConstant()->GetValue();
3965 if (destination.IsRegister()) {
Mark Mendell92e83bf2015-05-07 11:25:03 -04003966 codegen_->Load64BitValue(destination.AsRegister<CpuRegister>(), value);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003967 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003968 DCHECK(destination.IsDoubleStackSlot()) << destination;
Mark Mendell92e83bf2015-05-07 11:25:03 -04003969 codegen_->Load64BitValue(CpuRegister(TMP), value);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003970 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
3971 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003972 } else if (constant->IsFloatConstant()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003973 float fp_value = constant->AsFloatConstant()->GetValue();
Roland Levillainda4d79b2015-03-24 14:36:11 +00003974 int32_t value = bit_cast<int32_t, float>(fp_value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003975 if (destination.IsFpuRegister()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003976 XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
3977 if (value == 0) {
3978 // easy FP 0.0.
3979 __ xorps(dest, dest);
3980 } else {
Mark Mendell92e83bf2015-05-07 11:25:03 -04003981 __ movss(dest, codegen_->LiteralFloatAddress(fp_value));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003982 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003983 } else {
3984 DCHECK(destination.IsStackSlot()) << destination;
Mark Mendell92e83bf2015-05-07 11:25:03 -04003985 Immediate imm(value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003986 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), imm);
3987 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003988 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003989 DCHECK(constant->IsDoubleConstant()) << constant->DebugName();
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003990 double fp_value = constant->AsDoubleConstant()->GetValue();
Roland Levillainda4d79b2015-03-24 14:36:11 +00003991 int64_t value = bit_cast<int64_t, double>(fp_value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003992 if (destination.IsFpuRegister()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003993 XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
3994 if (value == 0) {
3995 __ xorpd(dest, dest);
3996 } else {
Mark Mendell92e83bf2015-05-07 11:25:03 -04003997 __ movsd(dest, codegen_->LiteralDoubleAddress(fp_value));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003998 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003999 } else {
4000 DCHECK(destination.IsDoubleStackSlot()) << destination;
Mark Mendell92e83bf2015-05-07 11:25:03 -04004001 codegen_->Load64BitValue(CpuRegister(TMP), value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004002 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
4003 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004004 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004005 } else if (source.IsFpuRegister()) {
4006 if (destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004007 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004008 } else if (destination.IsStackSlot()) {
4009 __ movss(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00004010 source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004011 } else {
Nicolas Geoffray31596742014-11-24 15:28:45 +00004012 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004013 __ movsd(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00004014 source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004015 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004016 }
4017}
4018
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004019void ParallelMoveResolverX86_64::Exchange32(CpuRegister reg, int mem) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004020 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004021 __ movl(Address(CpuRegister(RSP), mem), reg);
4022 __ movl(reg, CpuRegister(TMP));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004023}
4024
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004025void ParallelMoveResolverX86_64::Exchange32(int mem1, int mem2) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004026 ScratchRegisterScope ensure_scratch(
4027 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
4028
4029 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
4030 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
4031 __ movl(CpuRegister(ensure_scratch.GetRegister()),
4032 Address(CpuRegister(RSP), mem2 + stack_offset));
4033 __ movl(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
4034 __ movl(Address(CpuRegister(RSP), mem1 + stack_offset),
4035 CpuRegister(ensure_scratch.GetRegister()));
4036}
4037
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004038void ParallelMoveResolverX86_64::Exchange64(CpuRegister reg, int mem) {
4039 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
4040 __ movq(Address(CpuRegister(RSP), mem), reg);
4041 __ movq(reg, CpuRegister(TMP));
4042}
4043
4044void ParallelMoveResolverX86_64::Exchange64(int mem1, int mem2) {
4045 ScratchRegisterScope ensure_scratch(
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004046 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004047
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004048 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
4049 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
4050 __ movq(CpuRegister(ensure_scratch.GetRegister()),
4051 Address(CpuRegister(RSP), mem2 + stack_offset));
4052 __ movq(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
4053 __ movq(Address(CpuRegister(RSP), mem1 + stack_offset),
4054 CpuRegister(ensure_scratch.GetRegister()));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004055}
4056
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004057void ParallelMoveResolverX86_64::Exchange32(XmmRegister reg, int mem) {
4058 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
4059 __ movss(Address(CpuRegister(RSP), mem), reg);
4060 __ movd(reg, CpuRegister(TMP));
4061}
4062
4063void ParallelMoveResolverX86_64::Exchange64(XmmRegister reg, int mem) {
4064 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
4065 __ movsd(Address(CpuRegister(RSP), mem), reg);
4066 __ movd(reg, CpuRegister(TMP));
4067}
4068
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004069void ParallelMoveResolverX86_64::EmitSwap(size_t index) {
4070 MoveOperands* move = moves_.Get(index);
4071 Location source = move->GetSource();
4072 Location destination = move->GetDestination();
4073
4074 if (source.IsRegister() && destination.IsRegister()) {
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004075 __ xchgq(destination.AsRegister<CpuRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004076 } else if (source.IsRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004077 Exchange32(source.AsRegister<CpuRegister>(), destination.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004078 } else if (source.IsStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004079 Exchange32(destination.AsRegister<CpuRegister>(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004080 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004081 Exchange32(destination.GetStackIndex(), source.GetStackIndex());
4082 } else if (source.IsRegister() && destination.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004083 Exchange64(source.AsRegister<CpuRegister>(), destination.GetStackIndex());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004084 } else if (source.IsDoubleStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004085 Exchange64(destination.AsRegister<CpuRegister>(), source.GetStackIndex());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004086 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
4087 Exchange64(destination.GetStackIndex(), source.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004088 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004089 __ movd(CpuRegister(TMP), source.AsFpuRegister<XmmRegister>());
4090 __ movaps(source.AsFpuRegister<XmmRegister>(), destination.AsFpuRegister<XmmRegister>());
4091 __ movd(destination.AsFpuRegister<XmmRegister>(), CpuRegister(TMP));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004092 } else if (source.IsFpuRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004093 Exchange32(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004094 } else if (source.IsStackSlot() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004095 Exchange32(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004096 } else if (source.IsFpuRegister() && destination.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004097 Exchange64(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004098 } else if (source.IsDoubleStackSlot() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004099 Exchange64(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004100 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004101 LOG(FATAL) << "Unimplemented swap between " << source << " and " << destination;
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004102 }
4103}
4104
4105
4106void ParallelMoveResolverX86_64::SpillScratch(int reg) {
4107 __ pushq(CpuRegister(reg));
4108}
4109
4110
4111void ParallelMoveResolverX86_64::RestoreScratch(int reg) {
4112 __ popq(CpuRegister(reg));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004113}
4114
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004115void InstructionCodeGeneratorX86_64::GenerateClassInitializationCheck(
4116 SlowPathCodeX86_64* slow_path, CpuRegister class_reg) {
4117 __ cmpl(Address(class_reg, mirror::Class::StatusOffset().Int32Value()),
4118 Immediate(mirror::Class::kStatusInitialized));
4119 __ j(kLess, slow_path->GetEntryLabel());
4120 __ Bind(slow_path->GetExitLabel());
4121 // No need for memory fence, thanks to the X86_64 memory model.
4122}
4123
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004124void LocationsBuilderX86_64::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004125 LocationSummary::CallKind call_kind = cls->CanCallRuntime()
4126 ? LocationSummary::kCallOnSlowPath
4127 : LocationSummary::kNoCall;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004128 LocationSummary* locations =
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004129 new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004130 locations->SetOut(Location::RequiresRegister());
4131}
4132
4133void InstructionCodeGeneratorX86_64::VisitLoadClass(HLoadClass* cls) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004134 CpuRegister out = cls->GetLocations()->Out().AsRegister<CpuRegister>();
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004135 if (cls->IsReferrersClass()) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004136 DCHECK(!cls->CanCallRuntime());
4137 DCHECK(!cls->MustGenerateClinitCheck());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004138 codegen_->LoadCurrentMethod(out);
4139 __ movl(out, Address(out, mirror::ArtMethod::DeclaringClassOffset().Int32Value()));
4140 } else {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004141 DCHECK(cls->CanCallRuntime());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004142 codegen_->LoadCurrentMethod(out);
4143 __ movl(out, Address(out, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value()));
4144 __ movl(out, Address(out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex())));
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004145 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86_64(
4146 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
4147 codegen_->AddSlowPath(slow_path);
4148 __ testl(out, out);
4149 __ j(kEqual, slow_path->GetEntryLabel());
4150 if (cls->MustGenerateClinitCheck()) {
4151 GenerateClassInitializationCheck(slow_path, out);
4152 } else {
4153 __ Bind(slow_path->GetExitLabel());
4154 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004155 }
4156}
4157
4158void LocationsBuilderX86_64::VisitClinitCheck(HClinitCheck* check) {
4159 LocationSummary* locations =
4160 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
4161 locations->SetInAt(0, Location::RequiresRegister());
4162 if (check->HasUses()) {
4163 locations->SetOut(Location::SameAsFirstInput());
4164 }
4165}
4166
4167void InstructionCodeGeneratorX86_64::VisitClinitCheck(HClinitCheck* check) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004168 // We assume the class to not be null.
4169 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86_64(
4170 check->GetLoadClass(), check, check->GetDexPc(), true);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004171 codegen_->AddSlowPath(slow_path);
Roland Levillain199f3362014-11-27 17:15:16 +00004172 GenerateClassInitializationCheck(slow_path,
4173 check->GetLocations()->InAt(0).AsRegister<CpuRegister>());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004174}
4175
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004176void LocationsBuilderX86_64::VisitLoadString(HLoadString* load) {
4177 LocationSummary* locations =
4178 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
4179 locations->SetOut(Location::RequiresRegister());
4180}
4181
4182void InstructionCodeGeneratorX86_64::VisitLoadString(HLoadString* load) {
4183 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathX86_64(load);
4184 codegen_->AddSlowPath(slow_path);
4185
Roland Levillain271ab9c2014-11-27 15:23:57 +00004186 CpuRegister out = load->GetLocations()->Out().AsRegister<CpuRegister>();
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004187 codegen_->LoadCurrentMethod(CpuRegister(out));
Mathieu Chartiereace4582014-11-24 18:29:54 -08004188 __ movl(out, Address(out, mirror::ArtMethod::DeclaringClassOffset().Int32Value()));
4189 __ movl(out, Address(out, mirror::Class::DexCacheStringsOffset().Int32Value()));
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004190 __ movl(out, Address(out, CodeGenerator::GetCacheOffset(load->GetStringIndex())));
4191 __ testl(out, out);
4192 __ j(kEqual, slow_path->GetEntryLabel());
4193 __ Bind(slow_path->GetExitLabel());
4194}
4195
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004196void LocationsBuilderX86_64::VisitLoadException(HLoadException* load) {
4197 LocationSummary* locations =
4198 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
4199 locations->SetOut(Location::RequiresRegister());
4200}
4201
4202void InstructionCodeGeneratorX86_64::VisitLoadException(HLoadException* load) {
4203 Address address = Address::Absolute(
4204 Thread::ExceptionOffset<kX86_64WordSize>().Int32Value(), true);
Roland Levillain271ab9c2014-11-27 15:23:57 +00004205 __ gs()->movl(load->GetLocations()->Out().AsRegister<CpuRegister>(), address);
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004206 __ gs()->movl(address, Immediate(0));
4207}
4208
4209void LocationsBuilderX86_64::VisitThrow(HThrow* instruction) {
4210 LocationSummary* locations =
4211 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
4212 InvokeRuntimeCallingConvention calling_convention;
4213 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4214}
4215
4216void InstructionCodeGeneratorX86_64::VisitThrow(HThrow* instruction) {
4217 __ gs()->call(
4218 Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pDeliverException), true));
4219 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
4220}
4221
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004222void LocationsBuilderX86_64::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004223 LocationSummary::CallKind call_kind = instruction->IsClassFinal()
4224 ? LocationSummary::kNoCall
4225 : LocationSummary::kCallOnSlowPath;
4226 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
4227 locations->SetInAt(0, Location::RequiresRegister());
4228 locations->SetInAt(1, Location::Any());
4229 locations->SetOut(Location::RequiresRegister());
4230}
4231
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004232void InstructionCodeGeneratorX86_64::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004233 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004234 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004235 Location cls = locations->InAt(1);
Roland Levillain271ab9c2014-11-27 15:23:57 +00004236 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004237 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
4238 Label done, zero;
4239 SlowPathCodeX86_64* slow_path = nullptr;
4240
4241 // Return 0 if `obj` is null.
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004242 // Avoid null check if we know obj is not null.
4243 if (instruction->MustDoNullCheck()) {
4244 __ testl(obj, obj);
4245 __ j(kEqual, &zero);
4246 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004247 // Compare the class of `obj` with `cls`.
4248 __ movl(out, Address(obj, class_offset));
4249 if (cls.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004250 __ cmpl(out, cls.AsRegister<CpuRegister>());
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004251 } else {
4252 DCHECK(cls.IsStackSlot()) << cls;
4253 __ cmpl(out, Address(CpuRegister(RSP), cls.GetStackIndex()));
4254 }
4255 if (instruction->IsClassFinal()) {
4256 // Classes must be equal for the instanceof to succeed.
4257 __ j(kNotEqual, &zero);
4258 __ movl(out, Immediate(1));
4259 __ jmp(&done);
4260 } else {
4261 // If the classes are not equal, we go into a slow path.
4262 DCHECK(locations->OnlyCallsOnSlowPath());
4263 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86_64(
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004264 instruction, locations->InAt(1), locations->Out(), instruction->GetDexPc());
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004265 codegen_->AddSlowPath(slow_path);
4266 __ j(kNotEqual, slow_path->GetEntryLabel());
4267 __ movl(out, Immediate(1));
4268 __ jmp(&done);
4269 }
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004270
4271 if (instruction->MustDoNullCheck() || instruction->IsClassFinal()) {
4272 __ Bind(&zero);
4273 __ movl(out, Immediate(0));
4274 }
4275
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004276 if (slow_path != nullptr) {
4277 __ Bind(slow_path->GetExitLabel());
4278 }
4279 __ Bind(&done);
4280}
4281
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004282void LocationsBuilderX86_64::VisitCheckCast(HCheckCast* instruction) {
4283 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
4284 instruction, LocationSummary::kCallOnSlowPath);
4285 locations->SetInAt(0, Location::RequiresRegister());
4286 locations->SetInAt(1, Location::Any());
4287 locations->AddTemp(Location::RequiresRegister());
4288}
4289
4290void InstructionCodeGeneratorX86_64::VisitCheckCast(HCheckCast* instruction) {
4291 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004292 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004293 Location cls = locations->InAt(1);
Roland Levillain271ab9c2014-11-27 15:23:57 +00004294 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004295 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
4296 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86_64(
4297 instruction, locations->InAt(1), locations->GetTemp(0), instruction->GetDexPc());
4298 codegen_->AddSlowPath(slow_path);
4299
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004300 // Avoid null check if we know obj is not null.
4301 if (instruction->MustDoNullCheck()) {
4302 __ testl(obj, obj);
4303 __ j(kEqual, slow_path->GetExitLabel());
4304 }
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004305 // Compare the class of `obj` with `cls`.
4306 __ movl(temp, Address(obj, class_offset));
4307 if (cls.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004308 __ cmpl(temp, cls.AsRegister<CpuRegister>());
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004309 } else {
4310 DCHECK(cls.IsStackSlot()) << cls;
4311 __ cmpl(temp, Address(CpuRegister(RSP), cls.GetStackIndex()));
4312 }
4313 // Classes must be equal for the checkcast to succeed.
4314 __ j(kNotEqual, slow_path->GetEntryLabel());
4315 __ Bind(slow_path->GetExitLabel());
4316}
4317
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00004318void LocationsBuilderX86_64::VisitMonitorOperation(HMonitorOperation* instruction) {
4319 LocationSummary* locations =
4320 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
4321 InvokeRuntimeCallingConvention calling_convention;
4322 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4323}
4324
4325void InstructionCodeGeneratorX86_64::VisitMonitorOperation(HMonitorOperation* instruction) {
4326 __ gs()->call(Address::Absolute(instruction->IsEnter()
4327 ? QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pLockObject)
4328 : QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pUnlockObject),
4329 true));
4330 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
4331}
4332
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004333void LocationsBuilderX86_64::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); }
4334void LocationsBuilderX86_64::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); }
4335void LocationsBuilderX86_64::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); }
4336
4337void LocationsBuilderX86_64::HandleBitwiseOperation(HBinaryOperation* instruction) {
4338 LocationSummary* locations =
4339 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
4340 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
4341 || instruction->GetResultType() == Primitive::kPrimLong);
4342 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell40741f32015-04-20 22:10:34 -04004343 locations->SetInAt(1, Location::Any());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004344 locations->SetOut(Location::SameAsFirstInput());
4345}
4346
4347void InstructionCodeGeneratorX86_64::VisitAnd(HAnd* instruction) {
4348 HandleBitwiseOperation(instruction);
4349}
4350
4351void InstructionCodeGeneratorX86_64::VisitOr(HOr* instruction) {
4352 HandleBitwiseOperation(instruction);
4353}
4354
4355void InstructionCodeGeneratorX86_64::VisitXor(HXor* instruction) {
4356 HandleBitwiseOperation(instruction);
4357}
4358
4359void InstructionCodeGeneratorX86_64::HandleBitwiseOperation(HBinaryOperation* instruction) {
4360 LocationSummary* locations = instruction->GetLocations();
4361 Location first = locations->InAt(0);
4362 Location second = locations->InAt(1);
4363 DCHECK(first.Equals(locations->Out()));
4364
4365 if (instruction->GetResultType() == Primitive::kPrimInt) {
4366 if (second.IsRegister()) {
4367 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004368 __ andl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004369 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004370 __ orl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004371 } else {
4372 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004373 __ xorl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004374 }
4375 } else if (second.IsConstant()) {
4376 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
4377 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004378 __ andl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004379 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004380 __ orl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004381 } else {
4382 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004383 __ xorl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004384 }
4385 } else {
4386 Address address(CpuRegister(RSP), second.GetStackIndex());
4387 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004388 __ andl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004389 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004390 __ orl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004391 } else {
4392 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004393 __ xorl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004394 }
4395 }
4396 } else {
4397 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004398 CpuRegister first_reg = first.AsRegister<CpuRegister>();
4399 bool second_is_constant = false;
4400 int64_t value = 0;
4401 if (second.IsConstant()) {
4402 second_is_constant = true;
4403 value = second.GetConstant()->AsLongConstant()->GetValue();
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004404 }
Mark Mendell40741f32015-04-20 22:10:34 -04004405 bool is_int32_value = IsInt<32>(value);
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004406
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004407 if (instruction->IsAnd()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004408 if (second_is_constant) {
Mark Mendell40741f32015-04-20 22:10:34 -04004409 if (is_int32_value) {
4410 __ andq(first_reg, Immediate(static_cast<int32_t>(value)));
4411 } else {
4412 __ andq(first_reg, codegen_->LiteralInt64Address(value));
4413 }
4414 } else if (second.IsDoubleStackSlot()) {
4415 __ andq(first_reg, Address(CpuRegister(RSP), second.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004416 } else {
4417 __ andq(first_reg, second.AsRegister<CpuRegister>());
4418 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004419 } else if (instruction->IsOr()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004420 if (second_is_constant) {
Mark Mendell40741f32015-04-20 22:10:34 -04004421 if (is_int32_value) {
4422 __ orq(first_reg, Immediate(static_cast<int32_t>(value)));
4423 } else {
4424 __ orq(first_reg, codegen_->LiteralInt64Address(value));
4425 }
4426 } else if (second.IsDoubleStackSlot()) {
4427 __ orq(first_reg, Address(CpuRegister(RSP), second.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004428 } else {
4429 __ orq(first_reg, second.AsRegister<CpuRegister>());
4430 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004431 } else {
4432 DCHECK(instruction->IsXor());
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004433 if (second_is_constant) {
Mark Mendell40741f32015-04-20 22:10:34 -04004434 if (is_int32_value) {
4435 __ xorq(first_reg, Immediate(static_cast<int32_t>(value)));
4436 } else {
4437 __ xorq(first_reg, codegen_->LiteralInt64Address(value));
4438 }
4439 } else if (second.IsDoubleStackSlot()) {
4440 __ xorq(first_reg, Address(CpuRegister(RSP), second.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004441 } else {
4442 __ xorq(first_reg, second.AsRegister<CpuRegister>());
4443 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004444 }
4445 }
4446}
4447
Calin Juravleb1498f62015-02-16 13:13:29 +00004448void LocationsBuilderX86_64::VisitBoundType(HBoundType* instruction) {
4449 // Nothing to do, this should be removed during prepare for register allocator.
4450 UNUSED(instruction);
4451 LOG(FATAL) << "Unreachable";
4452}
4453
4454void InstructionCodeGeneratorX86_64::VisitBoundType(HBoundType* instruction) {
4455 // Nothing to do, this should be removed during prepare for register allocator.
4456 UNUSED(instruction);
4457 LOG(FATAL) << "Unreachable";
4458}
4459
Mark Mendell92e83bf2015-05-07 11:25:03 -04004460void CodeGeneratorX86_64::Load64BitValue(CpuRegister dest, int64_t value) {
4461 if (value == 0) {
4462 __ xorl(dest, dest);
4463 } else if (value > 0 && IsInt<32>(value)) {
4464 // We can use a 32 bit move, as it will zero-extend and is one byte shorter.
4465 __ movl(dest, Immediate(static_cast<int32_t>(value)));
4466 } else {
4467 __ movq(dest, Immediate(value));
4468 }
4469}
4470
Mark Mendellf55c3e02015-03-26 21:07:46 -04004471void CodeGeneratorX86_64::Finalize(CodeAllocator* allocator) {
4472 // Generate the constant area if needed.
Mark Mendell39dcf552015-04-09 20:42:42 -04004473 X86_64Assembler* assembler = GetAssembler();
4474 if (!assembler->IsConstantAreaEmpty()) {
Mark Mendellf55c3e02015-03-26 21:07:46 -04004475 // Align to 4 byte boundary to reduce cache misses, as the data is 4 and 8
4476 // byte values. If used for vectors at a later time, this will need to be
4477 // updated to 16 bytes with the appropriate offset.
Mark Mendell39dcf552015-04-09 20:42:42 -04004478 assembler->Align(4, 0);
4479 constant_area_start_ = assembler->CodeSize();
4480 assembler->AddConstantArea();
Mark Mendellf55c3e02015-03-26 21:07:46 -04004481 }
4482
4483 // And finish up.
4484 CodeGenerator::Finalize(allocator);
4485}
4486
4487/**
4488 * Class to handle late fixup of offsets into constant area.
4489 */
4490class RIPFixup : public AssemblerFixup, public ArenaObject<kArenaAllocMisc> {
4491 public:
Mark Mendell39dcf552015-04-09 20:42:42 -04004492 RIPFixup(const CodeGeneratorX86_64& codegen, int offset)
Mark Mendellf55c3e02015-03-26 21:07:46 -04004493 : codegen_(codegen), offset_into_constant_area_(offset) {}
4494
4495 private:
4496 void Process(const MemoryRegion& region, int pos) OVERRIDE {
4497 // Patch the correct offset for the instruction. We use the address of the
4498 // 'next' instruction, which is 'pos' (patch the 4 bytes before).
4499 int constant_offset = codegen_.ConstantAreaStart() + offset_into_constant_area_;
4500 int relative_position = constant_offset - pos;
4501
4502 // Patch in the right value.
4503 region.StoreUnaligned<int32_t>(pos - 4, relative_position);
4504 }
4505
Mark Mendell39dcf552015-04-09 20:42:42 -04004506 const CodeGeneratorX86_64& codegen_;
Mark Mendellf55c3e02015-03-26 21:07:46 -04004507
4508 // Location in constant area that the fixup refers to.
4509 int offset_into_constant_area_;
4510};
4511
4512Address CodeGeneratorX86_64::LiteralDoubleAddress(double v) {
4513 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddDouble(v));
4514 return Address::RIP(fixup);
4515}
4516
4517Address CodeGeneratorX86_64::LiteralFloatAddress(float v) {
4518 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddFloat(v));
4519 return Address::RIP(fixup);
4520}
4521
4522Address CodeGeneratorX86_64::LiteralInt32Address(int32_t v) {
4523 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddInt32(v));
4524 return Address::RIP(fixup);
4525}
4526
4527Address CodeGeneratorX86_64::LiteralInt64Address(int64_t v) {
4528 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddInt64(v));
4529 return Address::RIP(fixup);
4530}
4531
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004532} // namespace x86_64
4533} // namespace art