blob: e64540be43f5a6686e2a5b7e6048275102a46ff7 [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
Mathieu Chartiere401d142015-04-22 13:56:20 -070019#include "art_method.h"
Guillaume Sanchez0f88e872015-03-30 17:55:45 +010020#include "code_generator_utils.h"
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010021#include "entrypoints/quick/quick_entrypoints.h"
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +010022#include "gc/accounting/card_table.h"
Andreas Gampe71fb52f2014-12-29 17:43:08 -080023#include "intrinsics.h"
24#include "intrinsics_x86_64.h"
Ian Rogers7e70b002014-10-08 11:47:24 -070025#include "mirror/array-inl.h"
Mathieu Chartiere401d142015-04-22 13:56:20 -070026#include "mirror/class-inl.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;
Nicolas Geoffray76b1e172015-05-27 17:18:33 +010042static constexpr Register kMethodRegisterArgument = RDI;
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010043
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +000044static constexpr Register kCoreCalleeSaves[] = { RBX, RBP, R12, R13, R14, R15 };
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +000045static constexpr FloatRegister kFpuCalleeSaves[] = { XMM12, XMM13, XMM14, XMM15 };
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010046
Mark Mendell24f2dfa2015-01-14 19:51:45 -050047static constexpr int kC2ConditionMask = 0x400;
48
Roland Levillain62a46b22015-06-01 18:24:13 +010049#define __ down_cast<X86_64Assembler*>(codegen->GetAssembler())->
Nicolas Geoffraye5038322014-07-04 09:41:32 +010050
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
Alexandre Rames9931f312015-06-19 14:47:01 +010062 const char* GetDescription() const OVERRIDE { return "NullCheckSlowPathX86_64"; }
63
Nicolas Geoffraye5038322014-07-04 09:41:32 +010064 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +010065 HNullCheck* const instruction_;
Nicolas Geoffraye5038322014-07-04 09:41:32 +010066 DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathX86_64);
67};
68
Calin Juravled0d48522014-11-04 16:40:20 +000069class DivZeroCheckSlowPathX86_64 : public SlowPathCodeX86_64 {
70 public:
71 explicit DivZeroCheckSlowPathX86_64(HDivZeroCheck* instruction) : instruction_(instruction) {}
72
Alexandre Rames2ed20af2015-03-06 13:55:35 +000073 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Calin Juravled0d48522014-11-04 16:40:20 +000074 __ Bind(GetEntryLabel());
75 __ gs()->call(
76 Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pThrowDivZero), true));
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +000077 RecordPcInfo(codegen, instruction_, instruction_->GetDexPc());
Calin Juravled0d48522014-11-04 16:40:20 +000078 }
79
Alexandre Rames9931f312015-06-19 14:47:01 +010080 const char* GetDescription() const OVERRIDE { return "DivZeroCheckSlowPathX86_64"; }
81
Calin Juravled0d48522014-11-04 16:40:20 +000082 private:
83 HDivZeroCheck* const instruction_;
84 DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathX86_64);
85};
86
Calin Juravlebacfec32014-11-14 15:54:36 +000087class DivRemMinusOneSlowPathX86_64 : public SlowPathCodeX86_64 {
Calin Juravled0d48522014-11-04 16:40:20 +000088 public:
Calin Juravlebacfec32014-11-14 15:54:36 +000089 explicit DivRemMinusOneSlowPathX86_64(Register reg, Primitive::Type type, bool is_div)
90 : cpu_reg_(CpuRegister(reg)), type_(type), is_div_(is_div) {}
Calin Juravled0d48522014-11-04 16:40:20 +000091
Alexandre Rames2ed20af2015-03-06 13:55:35 +000092 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Calin Juravled0d48522014-11-04 16:40:20 +000093 __ Bind(GetEntryLabel());
Calin Juravled6fb6cf2014-11-11 19:07:44 +000094 if (type_ == Primitive::kPrimInt) {
Calin Juravlebacfec32014-11-14 15:54:36 +000095 if (is_div_) {
96 __ negl(cpu_reg_);
97 } else {
98 __ movl(cpu_reg_, Immediate(0));
99 }
100
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000101 } else {
102 DCHECK_EQ(Primitive::kPrimLong, type_);
Calin Juravlebacfec32014-11-14 15:54:36 +0000103 if (is_div_) {
104 __ negq(cpu_reg_);
105 } else {
Mark Mendell92e83bf2015-05-07 11:25:03 -0400106 __ xorl(cpu_reg_, cpu_reg_);
Calin Juravlebacfec32014-11-14 15:54:36 +0000107 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000108 }
Calin Juravled0d48522014-11-04 16:40:20 +0000109 __ jmp(GetExitLabel());
110 }
111
Alexandre Rames9931f312015-06-19 14:47:01 +0100112 const char* GetDescription() const OVERRIDE { return "DivRemMinusOneSlowPathX86_64"; }
113
Calin Juravled0d48522014-11-04 16:40:20 +0000114 private:
Calin Juravlebacfec32014-11-14 15:54:36 +0000115 const CpuRegister cpu_reg_;
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000116 const Primitive::Type type_;
Calin Juravlebacfec32014-11-14 15:54:36 +0000117 const bool is_div_;
118 DISALLOW_COPY_AND_ASSIGN(DivRemMinusOneSlowPathX86_64);
Calin Juravled0d48522014-11-04 16:40:20 +0000119};
120
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100121class SuspendCheckSlowPathX86_64 : public SlowPathCodeX86_64 {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000122 public:
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100123 explicit SuspendCheckSlowPathX86_64(HSuspendCheck* instruction, HBasicBlock* successor)
124 : instruction_(instruction), successor_(successor) {}
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000125
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000126 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100127 CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000128 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000129 SaveLiveRegisters(codegen, instruction_->GetLocations());
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000130 __ gs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pTestSuspend), true));
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000131 RecordPcInfo(codegen, instruction_, instruction_->GetDexPc());
132 RestoreLiveRegisters(codegen, instruction_->GetLocations());
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100133 if (successor_ == nullptr) {
134 __ jmp(GetReturnLabel());
135 } else {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100136 __ jmp(x64_codegen->GetLabelOf(successor_));
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100137 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000138 }
139
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100140 Label* GetReturnLabel() {
141 DCHECK(successor_ == nullptr);
142 return &return_label_;
143 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000144
Nicolas Geoffraydb216f42015-05-05 17:02:20 +0100145 HBasicBlock* GetSuccessor() const {
146 return successor_;
147 }
148
Alexandre Rames9931f312015-06-19 14:47:01 +0100149 const char* GetDescription() const OVERRIDE { return "SuspendCheckSlowPathX86_64"; }
150
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000151 private:
152 HSuspendCheck* const instruction_;
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100153 HBasicBlock* const successor_;
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000154 Label return_label_;
155
156 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathX86_64);
157};
158
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100159class BoundsCheckSlowPathX86_64 : public SlowPathCodeX86_64 {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100160 public:
Roland Levillain5799fc02014-09-25 12:15:20 +0100161 BoundsCheckSlowPathX86_64(HBoundsCheck* instruction,
162 Location index_location,
163 Location length_location)
Nicolas Geoffray39468442014-09-02 15:17:15 +0100164 : instruction_(instruction),
165 index_location_(index_location),
166 length_location_(length_location) {}
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100167
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000168 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100169 __ Bind(GetEntryLabel());
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000170 // We're moving two locations to locations that could overlap, so we need a parallel
171 // move resolver.
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100172 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000173 codegen->EmitParallelMoves(
174 index_location_,
175 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100176 Primitive::kPrimInt,
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000177 length_location_,
Nicolas Geoffray90218252015-04-15 11:56:51 +0100178 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
179 Primitive::kPrimInt);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100180 __ gs()->call(Address::Absolute(
181 QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pThrowArrayBounds), true));
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000182 RecordPcInfo(codegen, instruction_, instruction_->GetDexPc());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100183 }
184
Alexandre Rames9931f312015-06-19 14:47:01 +0100185 const char* GetDescription() const OVERRIDE { return "BoundsCheckSlowPathX86_64"; }
186
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100187 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100188 HBoundsCheck* const instruction_;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100189 const Location index_location_;
190 const Location length_location_;
191
192 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathX86_64);
193};
194
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000195class LoadClassSlowPathX86_64 : public SlowPathCodeX86_64 {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100196 public:
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000197 LoadClassSlowPathX86_64(HLoadClass* cls,
198 HInstruction* at,
199 uint32_t dex_pc,
200 bool do_clinit)
201 : cls_(cls), at_(at), dex_pc_(dex_pc), do_clinit_(do_clinit) {
202 DCHECK(at->IsLoadClass() || at->IsClinitCheck());
203 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100204
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000205 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000206 LocationSummary* locations = at_->GetLocations();
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100207 CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
208 __ Bind(GetEntryLabel());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100209
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000210 SaveLiveRegisters(codegen, locations);
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000211
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100212 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000213 __ movl(CpuRegister(calling_convention.GetRegisterAt(0)), Immediate(cls_->GetTypeIndex()));
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000214 __ gs()->call(Address::Absolute((do_clinit_
215 ? QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pInitializeStaticStorage)
216 : QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pInitializeType)) , true));
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000217 RecordPcInfo(codegen, at_, dex_pc_);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100218
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000219 Location out = locations->Out();
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000220 // Move the class to the desired location.
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000221 if (out.IsValid()) {
222 DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
223 x64_codegen->Move(out, Location::RegisterLocation(RAX));
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000224 }
225
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000226 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100227 __ jmp(GetExitLabel());
228 }
229
Alexandre Rames9931f312015-06-19 14:47:01 +0100230 const char* GetDescription() const OVERRIDE { return "LoadClassSlowPathX86_64"; }
231
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100232 private:
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000233 // The class this slow path will load.
234 HLoadClass* const cls_;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100235
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000236 // The instruction where this slow path is happening.
237 // (Might be the load class or an initialization check).
238 HInstruction* const at_;
239
240 // The dex PC of `at_`.
241 const uint32_t dex_pc_;
242
243 // Whether to initialize the class.
244 const bool do_clinit_;
245
246 DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathX86_64);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100247};
248
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000249class LoadStringSlowPathX86_64 : public SlowPathCodeX86_64 {
250 public:
251 explicit LoadStringSlowPathX86_64(HLoadString* instruction) : instruction_(instruction) {}
252
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000253 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000254 LocationSummary* locations = instruction_->GetLocations();
255 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
256
257 CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
258 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000259 SaveLiveRegisters(codegen, locations);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000260
261 InvokeRuntimeCallingConvention calling_convention;
Andreas Gampe1cc7dba2014-12-17 18:43:01 -0800262 __ movl(CpuRegister(calling_convention.GetRegisterAt(0)),
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000263 Immediate(instruction_->GetStringIndex()));
264 __ gs()->call(Address::Absolute(
265 QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pResolveString), true));
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000266 RecordPcInfo(codegen, instruction_, instruction_->GetDexPc());
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000267 x64_codegen->Move(locations->Out(), Location::RegisterLocation(RAX));
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000268 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000269 __ jmp(GetExitLabel());
270 }
271
Alexandre Rames9931f312015-06-19 14:47:01 +0100272 const char* GetDescription() const OVERRIDE { return "LoadStringSlowPathX86_64"; }
273
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000274 private:
275 HLoadString* const instruction_;
276
277 DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathX86_64);
278};
279
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000280class TypeCheckSlowPathX86_64 : public SlowPathCodeX86_64 {
281 public:
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000282 TypeCheckSlowPathX86_64(HInstruction* instruction,
283 Location class_to_check,
284 Location object_class,
285 uint32_t dex_pc)
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000286 : instruction_(instruction),
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000287 class_to_check_(class_to_check),
288 object_class_(object_class),
289 dex_pc_(dex_pc) {}
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000290
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000291 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000292 LocationSummary* locations = instruction_->GetLocations();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000293 DCHECK(instruction_->IsCheckCast()
294 || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000295
296 CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
297 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000298 SaveLiveRegisters(codegen, locations);
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000299
300 // We're moving two locations to locations that could overlap, so we need a parallel
301 // move resolver.
302 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000303 codegen->EmitParallelMoves(
304 class_to_check_,
305 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100306 Primitive::kPrimNot,
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000307 object_class_,
Nicolas Geoffray90218252015-04-15 11:56:51 +0100308 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
309 Primitive::kPrimNot);
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000310
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000311 if (instruction_->IsInstanceOf()) {
312 __ gs()->call(
313 Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pInstanceofNonTrivial), true));
314 } else {
315 DCHECK(instruction_->IsCheckCast());
316 __ gs()->call(
317 Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pCheckCast), true));
318 }
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000319 RecordPcInfo(codegen, instruction_, dex_pc_);
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000320
321 if (instruction_->IsInstanceOf()) {
322 x64_codegen->Move(locations->Out(), Location::RegisterLocation(RAX));
323 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000324
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000325 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000326 __ jmp(GetExitLabel());
327 }
328
Alexandre Rames9931f312015-06-19 14:47:01 +0100329 const char* GetDescription() const OVERRIDE { return "TypeCheckSlowPathX86_64"; }
330
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000331 private:
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000332 HInstruction* const instruction_;
333 const Location class_to_check_;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000334 const Location object_class_;
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000335 const uint32_t dex_pc_;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000336
337 DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathX86_64);
338};
339
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700340class DeoptimizationSlowPathX86_64 : public SlowPathCodeX86_64 {
341 public:
342 explicit DeoptimizationSlowPathX86_64(HInstruction* instruction)
343 : instruction_(instruction) {}
344
345 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
346 __ Bind(GetEntryLabel());
347 SaveLiveRegisters(codegen, instruction_->GetLocations());
348 __ gs()->call(
349 Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pDeoptimize), true));
350 DCHECK(instruction_->IsDeoptimize());
351 HDeoptimize* deoptimize = instruction_->AsDeoptimize();
352 uint32_t dex_pc = deoptimize->GetDexPc();
353 codegen->RecordPcInfo(instruction_, dex_pc, this);
354 }
355
Alexandre Rames9931f312015-06-19 14:47:01 +0100356 const char* GetDescription() const OVERRIDE { return "DeoptimizationSlowPathX86_64"; }
357
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700358 private:
359 HInstruction* const instruction_;
360 DISALLOW_COPY_AND_ASSIGN(DeoptimizationSlowPathX86_64);
361};
362
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100363#undef __
Roland Levillain62a46b22015-06-01 18:24:13 +0100364#define __ down_cast<X86_64Assembler*>(GetAssembler())->
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100365
Dave Allison20dfc792014-06-16 20:44:29 -0700366inline Condition X86_64Condition(IfCondition cond) {
367 switch (cond) {
368 case kCondEQ: return kEqual;
369 case kCondNE: return kNotEqual;
370 case kCondLT: return kLess;
371 case kCondLE: return kLessEqual;
372 case kCondGT: return kGreater;
373 case kCondGE: return kGreaterEqual;
374 default:
375 LOG(FATAL) << "Unknown if condition";
376 }
377 return kEqual;
378}
379
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800380void CodeGeneratorX86_64::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke,
Nicolas Geoffray38207af2015-06-01 15:46:22 +0100381 Location temp) {
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800382 // All registers are assumed to be correctly set up.
383
384 // TODO: Implement all kinds of calls:
385 // 1) boot -> boot
386 // 2) app -> boot
387 // 3) app -> app
388 //
389 // Currently we implement the app -> app logic, which looks up in the resolve cache.
390
Jeff Hao848f70a2014-01-15 13:49:50 -0800391 if (invoke->IsStringInit()) {
Nicolas Geoffray38207af2015-06-01 15:46:22 +0100392 CpuRegister reg = temp.AsRegister<CpuRegister>();
Jeff Hao848f70a2014-01-15 13:49:50 -0800393 // temp = thread->string_init_entrypoint
Nicolas Geoffray38207af2015-06-01 15:46:22 +0100394 __ gs()->movl(reg, Address::Absolute(invoke->GetStringInitOffset()));
Nicolas Geoffray1cf95282014-12-12 19:22:03 +0000395 // (temp + offset_of_quick_compiled_code)()
Nicolas Geoffray38207af2015-06-01 15:46:22 +0100396 __ call(Address(reg, ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Nicolas Geoffray1cf95282014-12-12 19:22:03 +0000397 kX86_64WordSize).SizeValue()));
Nicolas Geoffray38207af2015-06-01 15:46:22 +0100398 } else if (invoke->IsRecursive()) {
399 __ call(&frame_entry_label_);
Nicolas Geoffray1cf95282014-12-12 19:22:03 +0000400 } else {
Nicolas Geoffray38207af2015-06-01 15:46:22 +0100401 CpuRegister reg = temp.AsRegister<CpuRegister>();
Nicolas Geoffrayae71a052015-06-09 14:12:28 +0100402 Location current_method = invoke->GetLocations()->InAt(invoke->GetCurrentMethodInputIndex());
403 Register method_reg;
404 if (current_method.IsRegister()) {
405 method_reg = current_method.AsRegister<Register>();
406 } else {
407 DCHECK(invoke->GetLocations()->Intrinsified());
408 DCHECK(!current_method.IsValid());
409 method_reg = reg.AsRegister();
410 __ movq(reg, Address(CpuRegister(RSP), kCurrentMethodStackOffset));
411 }
Nicolas Geoffray38207af2015-06-01 15:46:22 +0100412 // temp = temp->dex_cache_resolved_methods_;
Nicolas Geoffrayae71a052015-06-09 14:12:28 +0100413 __ movl(reg, Address(CpuRegister(method_reg),
414 ArtMethod::DexCacheResolvedMethodsOffset().SizeValue()));
Nicolas Geoffray38207af2015-06-01 15:46:22 +0100415 // temp = temp[index_in_cache]
416 __ movq(reg, Address(
417 reg, CodeGenerator::GetCachePointerOffset(invoke->GetDexMethodIndex())));
418 // (temp + offset_of_quick_compiled_code)()
419 __ call(Address(reg, ArtMethod::EntryPointFromQuickCompiledCodeOffset(
420 kX86_64WordSize).SizeValue()));
Nicolas Geoffray1cf95282014-12-12 19:22:03 +0000421 }
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800422
423 DCHECK(!IsLeafMethod());
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800424}
425
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100426void CodeGeneratorX86_64::DumpCoreRegister(std::ostream& stream, int reg) const {
David Brazdilc74652862015-05-13 17:50:09 +0100427 stream << Register(reg);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100428}
429
430void CodeGeneratorX86_64::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
David Brazdilc74652862015-05-13 17:50:09 +0100431 stream << FloatRegister(reg);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100432}
433
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100434size_t CodeGeneratorX86_64::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
435 __ movq(Address(CpuRegister(RSP), stack_index), CpuRegister(reg_id));
436 return kX86_64WordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100437}
438
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100439size_t CodeGeneratorX86_64::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
440 __ movq(CpuRegister(reg_id), Address(CpuRegister(RSP), stack_index));
441 return kX86_64WordSize;
442}
443
444size_t CodeGeneratorX86_64::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
445 __ movsd(Address(CpuRegister(RSP), stack_index), XmmRegister(reg_id));
446 return kX86_64WordSize;
447}
448
449size_t CodeGeneratorX86_64::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
450 __ movsd(XmmRegister(reg_id), Address(CpuRegister(RSP), stack_index));
451 return kX86_64WordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100452}
453
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000454static constexpr int kNumberOfCpuRegisterPairs = 0;
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +0000455// Use a fake return address register to mimic Quick.
456static constexpr Register kFakeReturnRegister = Register(kLastCpuRegister + 1);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400457CodeGeneratorX86_64::CodeGeneratorX86_64(HGraph* graph,
458 const X86_64InstructionSetFeatures& isa_features,
459 const CompilerOptions& compiler_options)
Nicolas Geoffray98893962015-01-21 12:32:32 +0000460 : CodeGenerator(graph,
461 kNumberOfCpuRegisters,
462 kNumberOfFloatRegisters,
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000463 kNumberOfCpuRegisterPairs,
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000464 ComputeRegisterMask(reinterpret_cast<const int*>(kCoreCalleeSaves),
465 arraysize(kCoreCalleeSaves))
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +0000466 | (1 << kFakeReturnRegister),
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000467 ComputeRegisterMask(reinterpret_cast<const int*>(kFpuCalleeSaves),
468 arraysize(kFpuCalleeSaves)),
Nicolas Geoffray98893962015-01-21 12:32:32 +0000469 compiler_options),
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100470 block_labels_(graph->GetArena(), 0),
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100471 location_builder_(graph, this),
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000472 instruction_visitor_(graph, this),
Mark Mendellfb8d2792015-03-31 22:16:59 -0400473 move_resolver_(graph->GetArena(), this),
Mark Mendellf55c3e02015-03-26 21:07:46 -0400474 isa_features_(isa_features),
475 constant_area_start_(0) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000476 AddAllocatedRegister(Location::RegisterLocation(kFakeReturnRegister));
477}
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100478
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100479InstructionCodeGeneratorX86_64::InstructionCodeGeneratorX86_64(HGraph* graph,
480 CodeGeneratorX86_64* codegen)
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100481 : HGraphVisitor(graph),
482 assembler_(codegen->GetAssembler()),
483 codegen_(codegen) {}
484
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100485Location CodeGeneratorX86_64::AllocateFreeRegister(Primitive::Type type) const {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100486 switch (type) {
487 case Primitive::kPrimLong:
488 case Primitive::kPrimByte:
489 case Primitive::kPrimBoolean:
490 case Primitive::kPrimChar:
491 case Primitive::kPrimShort:
492 case Primitive::kPrimInt:
493 case Primitive::kPrimNot: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100494 size_t reg = FindFreeEntry(blocked_core_registers_, kNumberOfCpuRegisters);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100495 return Location::RegisterLocation(reg);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100496 }
497
498 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100499 case Primitive::kPrimDouble: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100500 size_t reg = FindFreeEntry(blocked_fpu_registers_, kNumberOfFloatRegisters);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100501 return Location::FpuRegisterLocation(reg);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100502 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100503
504 case Primitive::kPrimVoid:
505 LOG(FATAL) << "Unreachable type " << type;
506 }
507
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100508 return Location();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100509}
510
Nicolas Geoffray98893962015-01-21 12:32:32 +0000511void CodeGeneratorX86_64::SetupBlockedRegisters(bool is_baseline) const {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100512 // Stack register is always reserved.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100513 blocked_core_registers_[RSP] = true;
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100514
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000515 // Block the register used as TMP.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100516 blocked_core_registers_[TMP] = true;
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000517
Nicolas Geoffray98893962015-01-21 12:32:32 +0000518 if (is_baseline) {
519 for (size_t i = 0; i < arraysize(kCoreCalleeSaves); ++i) {
520 blocked_core_registers_[kCoreCalleeSaves[i]] = true;
521 }
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000522 for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
523 blocked_fpu_registers_[kFpuCalleeSaves[i]] = true;
524 }
Nicolas Geoffray98893962015-01-21 12:32:32 +0000525 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100526}
527
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100528static dwarf::Reg DWARFReg(Register reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +0100529 return dwarf::Reg::X86_64Core(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100530}
David Srbecky9d8606d2015-04-12 09:35:32 +0100531
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100532static dwarf::Reg DWARFReg(FloatRegister reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +0100533 return dwarf::Reg::X86_64Fp(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100534}
535
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100536void CodeGeneratorX86_64::GenerateFrameEntry() {
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100537 __ cfi().SetCurrentCFAOffset(kX86_64WordSize); // return address
Nicolas Geoffray1cf95282014-12-12 19:22:03 +0000538 __ Bind(&frame_entry_label_);
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100539 bool skip_overflow_check = IsLeafMethod()
Dave Allison648d7112014-07-25 16:15:27 -0700540 && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kX86_64);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000541 DCHECK(GetCompilerOptions().GetImplicitStackOverflowChecks());
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100542
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000543 if (!skip_overflow_check) {
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100544 __ testq(CpuRegister(RAX), Address(
545 CpuRegister(RSP), -static_cast<int32_t>(GetStackOverflowReservedBytes(kX86_64))));
Nicolas Geoffray39468442014-09-02 15:17:15 +0100546 RecordPcInfo(nullptr, 0);
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100547 }
Nicolas Geoffraya26369a2015-01-22 08:46:05 +0000548
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000549 if (HasEmptyFrame()) {
550 return;
551 }
552
Nicolas Geoffray98893962015-01-21 12:32:32 +0000553 for (int i = arraysize(kCoreCalleeSaves) - 1; i >= 0; --i) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000554 Register reg = kCoreCalleeSaves[i];
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +0000555 if (allocated_registers_.ContainsCoreRegister(reg)) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000556 __ pushq(CpuRegister(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100557 __ cfi().AdjustCFAOffset(kX86_64WordSize);
558 __ cfi().RelOffset(DWARFReg(reg), 0);
Nicolas Geoffray98893962015-01-21 12:32:32 +0000559 }
560 }
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100561
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100562 int adjust = GetFrameSize() - GetCoreSpillSize();
563 __ subq(CpuRegister(RSP), Immediate(adjust));
564 __ cfi().AdjustCFAOffset(adjust);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000565 uint32_t xmm_spill_location = GetFpuSpillStart();
566 size_t xmm_spill_slot_size = GetFloatingPointSpillSlotSize();
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100567
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000568 for (int i = arraysize(kFpuCalleeSaves) - 1; i >= 0; --i) {
569 if (allocated_registers_.ContainsFloatingPointRegister(kFpuCalleeSaves[i])) {
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100570 int offset = xmm_spill_location + (xmm_spill_slot_size * i);
571 __ movsd(Address(CpuRegister(RSP), offset), XmmRegister(kFpuCalleeSaves[i]));
572 __ cfi().RelOffset(DWARFReg(kFpuCalleeSaves[i]), offset);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000573 }
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100574 }
575
Mathieu Chartiere401d142015-04-22 13:56:20 -0700576 __ movq(Address(CpuRegister(RSP), kCurrentMethodStackOffset),
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100577 CpuRegister(kMethodRegisterArgument));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100578}
579
580void CodeGeneratorX86_64::GenerateFrameExit() {
David Srbeckyc34dc932015-04-12 09:27:43 +0100581 __ cfi().RememberState();
582 if (!HasEmptyFrame()) {
583 uint32_t xmm_spill_location = GetFpuSpillStart();
584 size_t xmm_spill_slot_size = GetFloatingPointSpillSlotSize();
585 for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
586 if (allocated_registers_.ContainsFloatingPointRegister(kFpuCalleeSaves[i])) {
587 int offset = xmm_spill_location + (xmm_spill_slot_size * i);
588 __ movsd(XmmRegister(kFpuCalleeSaves[i]), Address(CpuRegister(RSP), offset));
589 __ cfi().Restore(DWARFReg(kFpuCalleeSaves[i]));
590 }
591 }
592
593 int adjust = GetFrameSize() - GetCoreSpillSize();
594 __ addq(CpuRegister(RSP), Immediate(adjust));
595 __ cfi().AdjustCFAOffset(-adjust);
596
597 for (size_t i = 0; i < arraysize(kCoreCalleeSaves); ++i) {
598 Register reg = kCoreCalleeSaves[i];
599 if (allocated_registers_.ContainsCoreRegister(reg)) {
600 __ popq(CpuRegister(reg));
601 __ cfi().AdjustCFAOffset(-static_cast<int>(kX86_64WordSize));
602 __ cfi().Restore(DWARFReg(reg));
603 }
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000604 }
605 }
David Srbeckyc34dc932015-04-12 09:27:43 +0100606 __ ret();
607 __ cfi().RestoreState();
608 __ cfi().DefCFAOffset(GetFrameSize());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100609}
610
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100611void CodeGeneratorX86_64::Bind(HBasicBlock* block) {
612 __ Bind(GetLabelOf(block));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100613}
614
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100615Location CodeGeneratorX86_64::GetStackLocation(HLoadLocal* load) const {
616 switch (load->GetType()) {
617 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100618 case Primitive::kPrimDouble:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100619 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100620
621 case Primitive::kPrimInt:
622 case Primitive::kPrimNot:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100623 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100624 return Location::StackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100625
626 case Primitive::kPrimBoolean:
627 case Primitive::kPrimByte:
628 case Primitive::kPrimChar:
629 case Primitive::kPrimShort:
630 case Primitive::kPrimVoid:
631 LOG(FATAL) << "Unexpected type " << load->GetType();
Andreas Gampe65b798e2015-04-06 09:35:22 -0700632 UNREACHABLE();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100633 }
634
635 LOG(FATAL) << "Unreachable";
Andreas Gampe65b798e2015-04-06 09:35:22 -0700636 UNREACHABLE();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100637}
638
639void CodeGeneratorX86_64::Move(Location destination, Location source) {
640 if (source.Equals(destination)) {
641 return;
642 }
643 if (destination.IsRegister()) {
644 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000645 __ movq(destination.AsRegister<CpuRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100646 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000647 __ movd(destination.AsRegister<CpuRegister>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100648 } else if (source.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000649 __ movl(destination.AsRegister<CpuRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100650 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100651 } else {
652 DCHECK(source.IsDoubleStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +0000653 __ movq(destination.AsRegister<CpuRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100654 Address(CpuRegister(RSP), source.GetStackIndex()));
655 }
656 } else if (destination.IsFpuRegister()) {
657 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000658 __ movd(destination.AsFpuRegister<XmmRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100659 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000660 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100661 } else if (source.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000662 __ movss(destination.AsFpuRegister<XmmRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100663 Address(CpuRegister(RSP), source.GetStackIndex()));
664 } else {
665 DCHECK(source.IsDoubleStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +0000666 __ movsd(destination.AsFpuRegister<XmmRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100667 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100668 }
669 } else if (destination.IsStackSlot()) {
670 if (source.IsRegister()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100671 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +0000672 source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100673 } else if (source.IsFpuRegister()) {
674 __ movss(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +0000675 source.AsFpuRegister<XmmRegister>());
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500676 } else if (source.IsConstant()) {
677 HConstant* constant = source.GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000678 int32_t value = GetInt32ValueOf(constant);
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500679 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), Immediate(value));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100680 } else {
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500681 DCHECK(source.IsStackSlot()) << source;
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000682 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
683 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100684 }
685 } else {
686 DCHECK(destination.IsDoubleStackSlot());
687 if (source.IsRegister()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100688 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +0000689 source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100690 } else if (source.IsFpuRegister()) {
691 __ movsd(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +0000692 source.AsFpuRegister<XmmRegister>());
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500693 } else if (source.IsConstant()) {
694 HConstant* constant = source.GetConstant();
Zheng Xu12bca972015-03-30 19:35:50 +0800695 int64_t value;
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500696 if (constant->IsDoubleConstant()) {
Roland Levillainda4d79b2015-03-24 14:36:11 +0000697 value = bit_cast<int64_t, double>(constant->AsDoubleConstant()->GetValue());
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500698 } else {
699 DCHECK(constant->IsLongConstant());
700 value = constant->AsLongConstant()->GetValue();
701 }
Mark Mendell92e83bf2015-05-07 11:25:03 -0400702 Load64BitValue(CpuRegister(TMP), value);
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500703 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100704 } else {
705 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000706 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
707 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100708 }
709 }
710}
711
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100712void CodeGeneratorX86_64::Move(HInstruction* instruction,
713 Location location,
714 HInstruction* move_for) {
Calin Juravlea21f5982014-11-13 15:53:04 +0000715 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100716 if (instruction->IsCurrentMethod()) {
Mathieu Chartiere3b034a2015-05-31 14:29:23 -0700717 Move(location, Location::DoubleStackSlot(kCurrentMethodStackOffset));
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100718 } else if (locations != nullptr && locations->Out().Equals(location)) {
Calin Juravlea21f5982014-11-13 15:53:04 +0000719 return;
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100720 } else if (locations != nullptr && locations->Out().IsConstant()) {
Calin Juravlea21f5982014-11-13 15:53:04 +0000721 HConstant* const_to_move = locations->Out().GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000722 if (const_to_move->IsIntConstant() || const_to_move->IsNullConstant()) {
723 Immediate imm(GetInt32ValueOf(const_to_move));
Calin Juravlea21f5982014-11-13 15:53:04 +0000724 if (location.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000725 __ movl(location.AsRegister<CpuRegister>(), imm);
Calin Juravlea21f5982014-11-13 15:53:04 +0000726 } else if (location.IsStackSlot()) {
727 __ movl(Address(CpuRegister(RSP), location.GetStackIndex()), imm);
728 } else {
729 DCHECK(location.IsConstant());
730 DCHECK_EQ(location.GetConstant(), const_to_move);
731 }
732 } else if (const_to_move->IsLongConstant()) {
733 int64_t value = const_to_move->AsLongConstant()->GetValue();
734 if (location.IsRegister()) {
Mark Mendell92e83bf2015-05-07 11:25:03 -0400735 Load64BitValue(location.AsRegister<CpuRegister>(), value);
Calin Juravlea21f5982014-11-13 15:53:04 +0000736 } else if (location.IsDoubleStackSlot()) {
Mark Mendell92e83bf2015-05-07 11:25:03 -0400737 Load64BitValue(CpuRegister(TMP), value);
Calin Juravlea21f5982014-11-13 15:53:04 +0000738 __ movq(Address(CpuRegister(RSP), location.GetStackIndex()), CpuRegister(TMP));
739 } else {
740 DCHECK(location.IsConstant());
741 DCHECK_EQ(location.GetConstant(), const_to_move);
742 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100743 }
Roland Levillain476df552014-10-09 17:51:36 +0100744 } else if (instruction->IsLoadLocal()) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100745 switch (instruction->GetType()) {
746 case Primitive::kPrimBoolean:
747 case Primitive::kPrimByte:
748 case Primitive::kPrimChar:
749 case Primitive::kPrimShort:
750 case Primitive::kPrimInt:
751 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100752 case Primitive::kPrimFloat:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100753 Move(location, Location::StackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
754 break;
755
756 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100757 case Primitive::kPrimDouble:
Roland Levillain199f3362014-11-27 17:15:16 +0000758 Move(location,
759 Location::DoubleStackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100760 break;
761
762 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100763 LOG(FATAL) << "Unexpected local type " << instruction->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100764 }
Nicolas Geoffrayf43083d2014-11-07 10:48:10 +0000765 } else if (instruction->IsTemporary()) {
766 Location temp_location = GetTemporaryLocation(instruction->AsTemporary());
767 Move(location, temp_location);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100768 } else {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100769 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100770 switch (instruction->GetType()) {
771 case Primitive::kPrimBoolean:
772 case Primitive::kPrimByte:
773 case Primitive::kPrimChar:
774 case Primitive::kPrimShort:
775 case Primitive::kPrimInt:
776 case Primitive::kPrimNot:
777 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100778 case Primitive::kPrimFloat:
779 case Primitive::kPrimDouble:
Calin Juravlea21f5982014-11-13 15:53:04 +0000780 Move(location, locations->Out());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100781 break;
782
783 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100784 LOG(FATAL) << "Unexpected type " << instruction->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100785 }
786 }
787}
788
789void LocationsBuilderX86_64::VisitGoto(HGoto* got) {
790 got->SetLocations(nullptr);
791}
792
793void InstructionCodeGeneratorX86_64::VisitGoto(HGoto* got) {
794 HBasicBlock* successor = got->GetSuccessor();
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100795 DCHECK(!successor->IsExitBlock());
796
797 HBasicBlock* block = got->GetBlock();
798 HInstruction* previous = got->GetPrevious();
799
800 HLoopInformation* info = block->GetLoopInformation();
David Brazdil46e2a392015-03-16 17:31:52 +0000801 if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100802 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
803 return;
804 }
805
806 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
807 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
808 }
809 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100810 __ jmp(codegen_->GetLabelOf(successor));
811 }
812}
813
814void LocationsBuilderX86_64::VisitExit(HExit* exit) {
815 exit->SetLocations(nullptr);
816}
817
818void InstructionCodeGeneratorX86_64::VisitExit(HExit* exit) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700819 UNUSED(exit);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100820}
821
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700822void InstructionCodeGeneratorX86_64::GenerateTestAndBranch(HInstruction* instruction,
823 Label* true_target,
824 Label* false_target,
825 Label* always_true_target) {
826 HInstruction* cond = instruction->InputAt(0);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100827 if (cond->IsIntConstant()) {
828 // Constant condition, statically compared against 1.
829 int32_t cond_value = cond->AsIntConstant()->GetValue();
830 if (cond_value == 1) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700831 if (always_true_target != nullptr) {
832 __ jmp(always_true_target);
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100833 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100834 return;
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100835 } else {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100836 DCHECK_EQ(cond_value, 0);
837 }
838 } else {
839 bool materialized =
840 !cond->IsCondition() || cond->AsCondition()->NeedsMaterialization();
841 // Moves do not affect the eflags register, so if the condition is
842 // evaluated just before the if, we don't need to evaluate it
843 // again.
844 bool eflags_set = cond->IsCondition()
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700845 && cond->AsCondition()->IsBeforeWhenDisregardMoves(instruction);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100846 if (materialized) {
847 if (!eflags_set) {
848 // Materialized condition, compare against 0.
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700849 Location lhs = instruction->GetLocations()->InAt(0);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100850 if (lhs.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +0000851 __ testl(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>());
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100852 } else {
853 __ cmpl(Address(CpuRegister(RSP), lhs.GetStackIndex()),
854 Immediate(0));
855 }
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700856 __ j(kNotEqual, true_target);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100857 } else {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700858 __ j(X86_64Condition(cond->AsCondition()->GetCondition()), true_target);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100859 }
860 } else {
861 Location lhs = cond->GetLocations()->InAt(0);
862 Location rhs = cond->GetLocations()->InAt(1);
863 if (rhs.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000864 __ cmpl(lhs.AsRegister<CpuRegister>(), rhs.AsRegister<CpuRegister>());
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100865 } else if (rhs.IsConstant()) {
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000866 int32_t constant = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
Nicolas Geoffray748f1402015-01-27 08:17:54 +0000867 if (constant == 0) {
868 __ testl(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>());
869 } else {
870 __ cmpl(lhs.AsRegister<CpuRegister>(), Immediate(constant));
871 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100872 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000873 __ cmpl(lhs.AsRegister<CpuRegister>(),
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100874 Address(CpuRegister(RSP), rhs.GetStackIndex()));
875 }
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700876 __ j(X86_64Condition(cond->AsCondition()->GetCondition()), true_target);
Dave Allison20dfc792014-06-16 20:44:29 -0700877 }
Dave Allison20dfc792014-06-16 20:44:29 -0700878 }
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700879 if (false_target != nullptr) {
880 __ jmp(false_target);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100881 }
882}
883
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700884void LocationsBuilderX86_64::VisitIf(HIf* if_instr) {
885 LocationSummary* locations =
886 new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall);
887 HInstruction* cond = if_instr->InputAt(0);
888 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
889 locations->SetInAt(0, Location::Any());
890 }
891}
892
893void InstructionCodeGeneratorX86_64::VisitIf(HIf* if_instr) {
894 Label* true_target = codegen_->GetLabelOf(if_instr->IfTrueSuccessor());
895 Label* false_target = codegen_->GetLabelOf(if_instr->IfFalseSuccessor());
896 Label* always_true_target = true_target;
897 if (codegen_->GoesToNextBlock(if_instr->GetBlock(),
898 if_instr->IfTrueSuccessor())) {
899 always_true_target = nullptr;
900 }
901 if (codegen_->GoesToNextBlock(if_instr->GetBlock(),
902 if_instr->IfFalseSuccessor())) {
903 false_target = nullptr;
904 }
905 GenerateTestAndBranch(if_instr, true_target, false_target, always_true_target);
906}
907
908void LocationsBuilderX86_64::VisitDeoptimize(HDeoptimize* deoptimize) {
909 LocationSummary* locations = new (GetGraph()->GetArena())
910 LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
911 HInstruction* cond = deoptimize->InputAt(0);
912 DCHECK(cond->IsCondition());
913 if (cond->AsCondition()->NeedsMaterialization()) {
914 locations->SetInAt(0, Location::Any());
915 }
916}
917
918void InstructionCodeGeneratorX86_64::VisitDeoptimize(HDeoptimize* deoptimize) {
919 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena())
920 DeoptimizationSlowPathX86_64(deoptimize);
921 codegen_->AddSlowPath(slow_path);
922 Label* slow_path_entry = slow_path->GetEntryLabel();
923 GenerateTestAndBranch(deoptimize, slow_path_entry, nullptr, slow_path_entry);
924}
925
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100926void LocationsBuilderX86_64::VisitLocal(HLocal* local) {
927 local->SetLocations(nullptr);
928}
929
930void InstructionCodeGeneratorX86_64::VisitLocal(HLocal* local) {
931 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
932}
933
934void LocationsBuilderX86_64::VisitLoadLocal(HLoadLocal* local) {
935 local->SetLocations(nullptr);
936}
937
938void InstructionCodeGeneratorX86_64::VisitLoadLocal(HLoadLocal* load) {
939 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700940 UNUSED(load);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100941}
942
943void LocationsBuilderX86_64::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100944 LocationSummary* locations =
945 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100946 switch (store->InputAt(1)->GetType()) {
947 case Primitive::kPrimBoolean:
948 case Primitive::kPrimByte:
949 case Primitive::kPrimChar:
950 case Primitive::kPrimShort:
951 case Primitive::kPrimInt:
952 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100953 case Primitive::kPrimFloat:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100954 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
955 break;
956
957 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100958 case Primitive::kPrimDouble:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100959 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
960 break;
961
962 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100963 LOG(FATAL) << "Unexpected local type " << store->InputAt(1)->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100964 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100965}
966
967void InstructionCodeGeneratorX86_64::VisitStoreLocal(HStoreLocal* store) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700968 UNUSED(store);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100969}
970
Roland Levillain0d37cd02015-05-27 16:39:19 +0100971void LocationsBuilderX86_64::VisitCondition(HCondition* cond) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100972 LocationSummary* locations =
Roland Levillain0d37cd02015-05-27 16:39:19 +0100973 new (GetGraph()->GetArena()) LocationSummary(cond, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +0100974 locations->SetInAt(0, Location::RequiresRegister());
975 locations->SetInAt(1, Location::Any());
Roland Levillain0d37cd02015-05-27 16:39:19 +0100976 if (cond->NeedsMaterialization()) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100977 locations->SetOut(Location::RequiresRegister());
978 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100979}
980
Roland Levillain0d37cd02015-05-27 16:39:19 +0100981void InstructionCodeGeneratorX86_64::VisitCondition(HCondition* cond) {
982 if (cond->NeedsMaterialization()) {
983 LocationSummary* locations = cond->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +0000984 CpuRegister reg = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100985 // Clear register: setcc only sets the low byte.
Mark Mendell92e83bf2015-05-07 11:25:03 -0400986 __ xorl(reg, reg);
Nicolas Geoffray748f1402015-01-27 08:17:54 +0000987 Location lhs = locations->InAt(0);
988 Location rhs = locations->InAt(1);
989 if (rhs.IsRegister()) {
990 __ cmpl(lhs.AsRegister<CpuRegister>(), rhs.AsRegister<CpuRegister>());
991 } else if (rhs.IsConstant()) {
Mingyao Yangdc5ac732015-02-25 11:28:05 -0800992 int32_t constant = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
Nicolas Geoffray748f1402015-01-27 08:17:54 +0000993 if (constant == 0) {
994 __ testl(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>());
995 } else {
996 __ cmpl(lhs.AsRegister<CpuRegister>(), Immediate(constant));
997 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100998 } else {
Nicolas Geoffray748f1402015-01-27 08:17:54 +0000999 __ cmpl(lhs.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), rhs.GetStackIndex()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001000 }
Roland Levillain0d37cd02015-05-27 16:39:19 +01001001 __ setcc(X86_64Condition(cond->GetCondition()), reg);
Dave Allison20dfc792014-06-16 20:44:29 -07001002 }
1003}
1004
1005void LocationsBuilderX86_64::VisitEqual(HEqual* comp) {
1006 VisitCondition(comp);
1007}
1008
1009void InstructionCodeGeneratorX86_64::VisitEqual(HEqual* comp) {
1010 VisitCondition(comp);
1011}
1012
1013void LocationsBuilderX86_64::VisitNotEqual(HNotEqual* comp) {
1014 VisitCondition(comp);
1015}
1016
1017void InstructionCodeGeneratorX86_64::VisitNotEqual(HNotEqual* comp) {
1018 VisitCondition(comp);
1019}
1020
1021void LocationsBuilderX86_64::VisitLessThan(HLessThan* comp) {
1022 VisitCondition(comp);
1023}
1024
1025void InstructionCodeGeneratorX86_64::VisitLessThan(HLessThan* comp) {
1026 VisitCondition(comp);
1027}
1028
1029void LocationsBuilderX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1030 VisitCondition(comp);
1031}
1032
1033void InstructionCodeGeneratorX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1034 VisitCondition(comp);
1035}
1036
1037void LocationsBuilderX86_64::VisitGreaterThan(HGreaterThan* comp) {
1038 VisitCondition(comp);
1039}
1040
1041void InstructionCodeGeneratorX86_64::VisitGreaterThan(HGreaterThan* comp) {
1042 VisitCondition(comp);
1043}
1044
1045void LocationsBuilderX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1046 VisitCondition(comp);
1047}
1048
1049void InstructionCodeGeneratorX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1050 VisitCondition(comp);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001051}
1052
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001053void LocationsBuilderX86_64::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001054 LocationSummary* locations =
1055 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Calin Juravleddb7df22014-11-25 20:56:51 +00001056 switch (compare->InputAt(0)->GetType()) {
1057 case Primitive::kPrimLong: {
1058 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell40741f32015-04-20 22:10:34 -04001059 locations->SetInAt(1, Location::Any());
Calin Juravleddb7df22014-11-25 20:56:51 +00001060 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1061 break;
1062 }
1063 case Primitive::kPrimFloat:
1064 case Primitive::kPrimDouble: {
1065 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendell40741f32015-04-20 22:10:34 -04001066 locations->SetInAt(1, Location::Any());
Calin Juravleddb7df22014-11-25 20:56:51 +00001067 locations->SetOut(Location::RequiresRegister());
1068 break;
1069 }
1070 default:
1071 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
1072 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001073}
1074
1075void InstructionCodeGeneratorX86_64::VisitCompare(HCompare* compare) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001076 LocationSummary* locations = compare->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00001077 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Calin Juravleddb7df22014-11-25 20:56:51 +00001078 Location left = locations->InAt(0);
1079 Location right = locations->InAt(1);
1080
1081 Label less, greater, done;
1082 Primitive::Type type = compare->InputAt(0)->GetType();
1083 switch (type) {
1084 case Primitive::kPrimLong: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04001085 CpuRegister left_reg = left.AsRegister<CpuRegister>();
1086 if (right.IsConstant()) {
1087 int64_t value = right.GetConstant()->AsLongConstant()->GetValue();
Mark Mendell40741f32015-04-20 22:10:34 -04001088 if (IsInt<32>(value)) {
1089 if (value == 0) {
1090 __ testq(left_reg, left_reg);
1091 } else {
1092 __ cmpq(left_reg, Immediate(static_cast<int32_t>(value)));
1093 }
Mark Mendell3f6c7f62015-03-13 13:47:53 -04001094 } else {
Mark Mendell40741f32015-04-20 22:10:34 -04001095 // Value won't fit in an int.
1096 __ cmpq(left_reg, codegen_->LiteralInt64Address(value));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04001097 }
Mark Mendell40741f32015-04-20 22:10:34 -04001098 } else if (right.IsDoubleStackSlot()) {
1099 __ cmpq(left_reg, Address(CpuRegister(RSP), right.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04001100 } else {
1101 __ cmpq(left_reg, right.AsRegister<CpuRegister>());
1102 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001103 break;
Calin Juravleddb7df22014-11-25 20:56:51 +00001104 }
1105 case Primitive::kPrimFloat: {
Mark Mendell40741f32015-04-20 22:10:34 -04001106 XmmRegister left_reg = left.AsFpuRegister<XmmRegister>();
1107 if (right.IsConstant()) {
1108 float value = right.GetConstant()->AsFloatConstant()->GetValue();
1109 __ ucomiss(left_reg, codegen_->LiteralFloatAddress(value));
1110 } else if (right.IsStackSlot()) {
1111 __ ucomiss(left_reg, Address(CpuRegister(RSP), right.GetStackIndex()));
1112 } else {
1113 __ ucomiss(left_reg, right.AsFpuRegister<XmmRegister>());
1114 }
Calin Juravleddb7df22014-11-25 20:56:51 +00001115 __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
1116 break;
1117 }
1118 case Primitive::kPrimDouble: {
Mark Mendell40741f32015-04-20 22:10:34 -04001119 XmmRegister left_reg = left.AsFpuRegister<XmmRegister>();
1120 if (right.IsConstant()) {
1121 double value = right.GetConstant()->AsDoubleConstant()->GetValue();
1122 __ ucomisd(left_reg, codegen_->LiteralDoubleAddress(value));
1123 } else if (right.IsDoubleStackSlot()) {
1124 __ ucomisd(left_reg, Address(CpuRegister(RSP), right.GetStackIndex()));
1125 } else {
1126 __ ucomisd(left_reg, right.AsFpuRegister<XmmRegister>());
1127 }
Calin Juravleddb7df22014-11-25 20:56:51 +00001128 __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
1129 break;
1130 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001131 default:
Calin Juravleddb7df22014-11-25 20:56:51 +00001132 LOG(FATAL) << "Unexpected compare type " << type;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001133 }
Calin Juravleddb7df22014-11-25 20:56:51 +00001134 __ movl(out, Immediate(0));
Calin Juravle91debbc2014-11-26 19:01:09 +00001135 __ j(kEqual, &done);
Calin Juravleddb7df22014-11-25 20:56:51 +00001136 __ j(type == Primitive::kPrimLong ? kLess : kBelow, &less); // ucomis{s,d} sets CF (kBelow)
Calin Juravlefd861242014-11-25 20:56:51 +00001137
Calin Juravle91debbc2014-11-26 19:01:09 +00001138 __ Bind(&greater);
Calin Juravleddb7df22014-11-25 20:56:51 +00001139 __ movl(out, Immediate(1));
1140 __ jmp(&done);
1141
1142 __ Bind(&less);
1143 __ movl(out, Immediate(-1));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001144
1145 __ Bind(&done);
1146}
1147
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001148void LocationsBuilderX86_64::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001149 LocationSummary* locations =
1150 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001151 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001152}
1153
1154void InstructionCodeGeneratorX86_64::VisitIntConstant(HIntConstant* constant) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001155 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001156 UNUSED(constant);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001157}
1158
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001159void LocationsBuilderX86_64::VisitNullConstant(HNullConstant* constant) {
1160 LocationSummary* locations =
1161 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1162 locations->SetOut(Location::ConstantLocation(constant));
1163}
1164
1165void InstructionCodeGeneratorX86_64::VisitNullConstant(HNullConstant* constant) {
1166 // Will be generated at use site.
1167 UNUSED(constant);
1168}
1169
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001170void LocationsBuilderX86_64::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001171 LocationSummary* locations =
1172 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001173 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001174}
1175
1176void InstructionCodeGeneratorX86_64::VisitLongConstant(HLongConstant* constant) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001177 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001178 UNUSED(constant);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001179}
1180
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001181void LocationsBuilderX86_64::VisitFloatConstant(HFloatConstant* constant) {
1182 LocationSummary* locations =
1183 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1184 locations->SetOut(Location::ConstantLocation(constant));
1185}
1186
1187void InstructionCodeGeneratorX86_64::VisitFloatConstant(HFloatConstant* constant) {
1188 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001189 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001190}
1191
1192void LocationsBuilderX86_64::VisitDoubleConstant(HDoubleConstant* constant) {
1193 LocationSummary* locations =
1194 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1195 locations->SetOut(Location::ConstantLocation(constant));
1196}
1197
1198void InstructionCodeGeneratorX86_64::VisitDoubleConstant(HDoubleConstant* constant) {
1199 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001200 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001201}
1202
Calin Juravle27df7582015-04-17 19:12:31 +01001203void LocationsBuilderX86_64::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
1204 memory_barrier->SetLocations(nullptr);
1205}
1206
1207void InstructionCodeGeneratorX86_64::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
1208 GenerateMemoryBarrier(memory_barrier->GetBarrierKind());
1209}
1210
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001211void LocationsBuilderX86_64::VisitReturnVoid(HReturnVoid* ret) {
1212 ret->SetLocations(nullptr);
1213}
1214
1215void InstructionCodeGeneratorX86_64::VisitReturnVoid(HReturnVoid* ret) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001216 UNUSED(ret);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001217 codegen_->GenerateFrameExit();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001218}
1219
1220void LocationsBuilderX86_64::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001221 LocationSummary* locations =
1222 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001223 switch (ret->InputAt(0)->GetType()) {
1224 case Primitive::kPrimBoolean:
1225 case Primitive::kPrimByte:
1226 case Primitive::kPrimChar:
1227 case Primitive::kPrimShort:
1228 case Primitive::kPrimInt:
1229 case Primitive::kPrimNot:
1230 case Primitive::kPrimLong:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001231 locations->SetInAt(0, Location::RegisterLocation(RAX));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001232 break;
1233
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001234 case Primitive::kPrimFloat:
1235 case Primitive::kPrimDouble:
Mark Mendell40741f32015-04-20 22:10:34 -04001236 locations->SetInAt(0, Location::FpuRegisterLocation(XMM0));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001237 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 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001242}
1243
1244void InstructionCodeGeneratorX86_64::VisitReturn(HReturn* ret) {
1245 if (kIsDebugBuild) {
1246 switch (ret->InputAt(0)->GetType()) {
1247 case Primitive::kPrimBoolean:
1248 case Primitive::kPrimByte:
1249 case Primitive::kPrimChar:
1250 case Primitive::kPrimShort:
1251 case Primitive::kPrimInt:
1252 case Primitive::kPrimNot:
1253 case Primitive::kPrimLong:
Roland Levillain271ab9c2014-11-27 15:23:57 +00001254 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegister<CpuRegister>().AsRegister(), RAX);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001255 break;
1256
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001257 case Primitive::kPrimFloat:
1258 case Primitive::kPrimDouble:
Roland Levillain271ab9c2014-11-27 15:23:57 +00001259 DCHECK_EQ(ret->GetLocations()->InAt(0).AsFpuRegister<XmmRegister>().AsFloatRegister(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001260 XMM0);
1261 break;
1262
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001263 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001264 LOG(FATAL) << "Unexpected return type " << ret->InputAt(0)->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001265 }
1266 }
1267 codegen_->GenerateFrameExit();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001268}
1269
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01001270Location InvokeDexCallingConventionVisitorX86_64::GetReturnLocation(Primitive::Type type) const {
1271 switch (type) {
1272 case Primitive::kPrimBoolean:
1273 case Primitive::kPrimByte:
1274 case Primitive::kPrimChar:
1275 case Primitive::kPrimShort:
1276 case Primitive::kPrimInt:
1277 case Primitive::kPrimNot:
1278 case Primitive::kPrimLong:
1279 return Location::RegisterLocation(RAX);
1280
1281 case Primitive::kPrimVoid:
1282 return Location::NoLocation();
1283
1284 case Primitive::kPrimDouble:
1285 case Primitive::kPrimFloat:
1286 return Location::FpuRegisterLocation(XMM0);
1287 }
Nicolas Geoffray0d1652e2015-06-03 12:12:19 +01001288
1289 UNREACHABLE();
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01001290}
1291
1292Location InvokeDexCallingConventionVisitorX86_64::GetMethodLocation() const {
1293 return Location::RegisterLocation(kMethodRegisterArgument);
1294}
1295
Roland Levillain2d27c8e2015-04-28 15:48:45 +01001296Location InvokeDexCallingConventionVisitorX86_64::GetNextLocation(Primitive::Type type) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001297 switch (type) {
1298 case Primitive::kPrimBoolean:
1299 case Primitive::kPrimByte:
1300 case Primitive::kPrimChar:
1301 case Primitive::kPrimShort:
1302 case Primitive::kPrimInt:
1303 case Primitive::kPrimNot: {
1304 uint32_t index = gp_index_++;
1305 stack_index_++;
1306 if (index < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001307 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001308 } else {
1309 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
1310 }
1311 }
1312
1313 case Primitive::kPrimLong: {
1314 uint32_t index = gp_index_;
1315 stack_index_ += 2;
1316 if (index < calling_convention.GetNumberOfRegisters()) {
1317 gp_index_ += 1;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001318 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001319 } else {
1320 gp_index_ += 2;
1321 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
1322 }
1323 }
1324
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001325 case Primitive::kPrimFloat: {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01001326 uint32_t index = float_index_++;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001327 stack_index_++;
1328 if (index < calling_convention.GetNumberOfFpuRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001329 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001330 } else {
1331 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
1332 }
1333 }
1334
1335 case Primitive::kPrimDouble: {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01001336 uint32_t index = float_index_++;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001337 stack_index_ += 2;
1338 if (index < calling_convention.GetNumberOfFpuRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001339 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001340 } else {
1341 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
1342 }
1343 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001344
1345 case Primitive::kPrimVoid:
1346 LOG(FATAL) << "Unexpected parameter type " << type;
1347 break;
1348 }
1349 return Location();
1350}
1351
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001352void LocationsBuilderX86_64::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Roland Levillain3e3d7332015-04-28 11:00:54 +01001353 // When we do not run baseline, explicit clinit checks triggered by static
1354 // invokes must have been pruned by art::PrepareForRegisterAllocation.
1355 DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01001356
Mark Mendellfb8d2792015-03-31 22:16:59 -04001357 IntrinsicLocationsBuilderX86_64 intrinsic(codegen_);
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001358 if (intrinsic.TryDispatch(invoke)) {
1359 return;
1360 }
1361
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001362 HandleInvoke(invoke);
1363}
1364
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001365static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorX86_64* codegen) {
1366 if (invoke->GetLocations()->Intrinsified()) {
1367 IntrinsicCodeGeneratorX86_64 intrinsic(codegen);
1368 intrinsic.Dispatch(invoke);
1369 return true;
1370 }
1371 return false;
1372}
1373
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001374void InstructionCodeGeneratorX86_64::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Roland Levillain3e3d7332015-04-28 11:00:54 +01001375 // When we do not run baseline, explicit clinit checks triggered by static
1376 // invokes must have been pruned by art::PrepareForRegisterAllocation.
1377 DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01001378
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001379 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1380 return;
1381 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001382
Nicolas Geoffray38207af2015-06-01 15:46:22 +01001383 LocationSummary* locations = invoke->GetLocations();
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001384 codegen_->GenerateStaticOrDirectCall(
Nicolas Geoffray38207af2015-06-01 15:46:22 +01001385 invoke, locations->HasTemps() ? locations->GetTemp(0) : Location::NoLocation());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +00001386 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001387}
1388
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001389void LocationsBuilderX86_64::HandleInvoke(HInvoke* invoke) {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01001390 InvokeDexCallingConventionVisitorX86_64 calling_convention_visitor;
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01001391 CodeGenerator::CreateCommonInvokeLocationSummary(invoke, &calling_convention_visitor);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001392}
1393
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001394void LocationsBuilderX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Mark Mendellfb8d2792015-03-31 22:16:59 -04001395 IntrinsicLocationsBuilderX86_64 intrinsic(codegen_);
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001396 if (intrinsic.TryDispatch(invoke)) {
1397 return;
1398 }
1399
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001400 HandleInvoke(invoke);
1401}
1402
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001403void InstructionCodeGeneratorX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001404 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1405 return;
1406 }
1407
Roland Levillain271ab9c2014-11-27 15:23:57 +00001408 CpuRegister temp = invoke->GetLocations()->GetTemp(0).AsRegister<CpuRegister>();
Mathieu Chartiere401d142015-04-22 13:56:20 -07001409 size_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
1410 invoke->GetVTableIndex(), kX86_64PointerSize).SizeValue();
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001411 LocationSummary* locations = invoke->GetLocations();
1412 Location receiver = locations->InAt(0);
1413 size_t class_offset = mirror::Object::ClassOffset().SizeValue();
1414 // temp = object->GetClass();
Nicolas Geoffray38207af2015-06-01 15:46:22 +01001415 DCHECK(receiver.IsRegister());
1416 __ movl(temp, Address(receiver.AsRegister<CpuRegister>(), class_offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00001417 codegen_->MaybeRecordImplicitNullCheck(invoke);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001418 // temp = temp->GetMethodAt(method_offset);
Mathieu Chartiere401d142015-04-22 13:56:20 -07001419 __ movq(temp, Address(temp, method_offset));
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001420 // call temp->GetEntryPoint();
Mathieu Chartiere401d142015-04-22 13:56:20 -07001421 __ call(Address(temp, ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001422 kX86_64WordSize).SizeValue()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001423
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001424 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray39468442014-09-02 15:17:15 +01001425 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001426}
1427
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001428void LocationsBuilderX86_64::VisitInvokeInterface(HInvokeInterface* invoke) {
1429 HandleInvoke(invoke);
1430 // Add the hidden argument.
1431 invoke->GetLocations()->AddTemp(Location::RegisterLocation(RAX));
1432}
1433
1434void InstructionCodeGeneratorX86_64::VisitInvokeInterface(HInvokeInterface* invoke) {
1435 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001436 CpuRegister temp = invoke->GetLocations()->GetTemp(0).AsRegister<CpuRegister>();
Mathieu Chartiere401d142015-04-22 13:56:20 -07001437 uint32_t method_offset = mirror::Class::EmbeddedImTableEntryOffset(
1438 invoke->GetImtIndex() % mirror::Class::kImtSize, kX86_64PointerSize).Uint32Value();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001439 LocationSummary* locations = invoke->GetLocations();
1440 Location receiver = locations->InAt(0);
1441 size_t class_offset = mirror::Object::ClassOffset().SizeValue();
1442
1443 // Set the hidden argument.
Mark Mendell92e83bf2015-05-07 11:25:03 -04001444 CpuRegister hidden_reg = invoke->GetLocations()->GetTemp(1).AsRegister<CpuRegister>();
1445 codegen_->Load64BitValue(hidden_reg, invoke->GetDexMethodIndex());
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001446
1447 // temp = object->GetClass();
1448 if (receiver.IsStackSlot()) {
1449 __ movl(temp, Address(CpuRegister(RSP), receiver.GetStackIndex()));
1450 __ movl(temp, Address(temp, class_offset));
1451 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001452 __ movl(temp, Address(receiver.AsRegister<CpuRegister>(), class_offset));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001453 }
Calin Juravle77520bc2015-01-12 18:45:46 +00001454 codegen_->MaybeRecordImplicitNullCheck(invoke);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001455 // temp = temp->GetImtEntryAt(method_offset);
Mathieu Chartiere401d142015-04-22 13:56:20 -07001456 __ movq(temp, Address(temp, method_offset));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001457 // call temp->GetEntryPoint();
Mathieu Chartiere401d142015-04-22 13:56:20 -07001458 __ call(Address(temp, ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001459 kX86_64WordSize).SizeValue()));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001460
1461 DCHECK(!codegen_->IsLeafMethod());
1462 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1463}
1464
Roland Levillain88cb1752014-10-20 16:36:47 +01001465void LocationsBuilderX86_64::VisitNeg(HNeg* neg) {
1466 LocationSummary* locations =
1467 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
1468 switch (neg->GetResultType()) {
1469 case Primitive::kPrimInt:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001470 case Primitive::kPrimLong:
Roland Levillain88cb1752014-10-20 16:36:47 +01001471 locations->SetInAt(0, Location::RequiresRegister());
1472 locations->SetOut(Location::SameAsFirstInput());
1473 break;
1474
Roland Levillain88cb1752014-10-20 16:36:47 +01001475 case Primitive::kPrimFloat:
1476 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001477 locations->SetInAt(0, Location::RequiresFpuRegister());
Roland Levillain5368c212014-11-27 15:03:41 +00001478 locations->SetOut(Location::SameAsFirstInput());
Roland Levillain5368c212014-11-27 15:03:41 +00001479 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain88cb1752014-10-20 16:36:47 +01001480 break;
1481
1482 default:
1483 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1484 }
1485}
1486
1487void InstructionCodeGeneratorX86_64::VisitNeg(HNeg* neg) {
1488 LocationSummary* locations = neg->GetLocations();
1489 Location out = locations->Out();
1490 Location in = locations->InAt(0);
1491 switch (neg->GetResultType()) {
1492 case Primitive::kPrimInt:
1493 DCHECK(in.IsRegister());
Roland Levillain3dbcb382014-10-28 17:30:07 +00001494 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001495 __ negl(out.AsRegister<CpuRegister>());
Roland Levillain88cb1752014-10-20 16:36:47 +01001496 break;
1497
1498 case Primitive::kPrimLong:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001499 DCHECK(in.IsRegister());
Roland Levillain3dbcb382014-10-28 17:30:07 +00001500 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001501 __ negq(out.AsRegister<CpuRegister>());
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001502 break;
1503
Roland Levillain5368c212014-11-27 15:03:41 +00001504 case Primitive::kPrimFloat: {
1505 DCHECK(in.Equals(out));
Mark Mendell40741f32015-04-20 22:10:34 -04001506 XmmRegister mask = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
Roland Levillain5368c212014-11-27 15:03:41 +00001507 // Implement float negation with an exclusive or with value
1508 // 0x80000000 (mask for bit 31, representing the sign of a
1509 // single-precision floating-point number).
Mark Mendell40741f32015-04-20 22:10:34 -04001510 __ movss(mask, codegen_->LiteralInt32Address(0x80000000));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001511 __ xorps(out.AsFpuRegister<XmmRegister>(), mask);
Roland Levillain3dbcb382014-10-28 17:30:07 +00001512 break;
Roland Levillain5368c212014-11-27 15:03:41 +00001513 }
Roland Levillain3dbcb382014-10-28 17:30:07 +00001514
Roland Levillain5368c212014-11-27 15:03:41 +00001515 case Primitive::kPrimDouble: {
1516 DCHECK(in.Equals(out));
Mark Mendell40741f32015-04-20 22:10:34 -04001517 XmmRegister mask = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
Roland Levillain5368c212014-11-27 15:03:41 +00001518 // Implement double negation with an exclusive or with value
Roland Levillain3dbcb382014-10-28 17:30:07 +00001519 // 0x8000000000000000 (mask for bit 63, representing the sign of
Roland Levillain5368c212014-11-27 15:03:41 +00001520 // a double-precision floating-point number).
Mark Mendell40741f32015-04-20 22:10:34 -04001521 __ movsd(mask, codegen_->LiteralInt64Address(INT64_C(0x8000000000000000)));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001522 __ xorpd(out.AsFpuRegister<XmmRegister>(), mask);
Roland Levillain88cb1752014-10-20 16:36:47 +01001523 break;
Roland Levillain5368c212014-11-27 15:03:41 +00001524 }
Roland Levillain88cb1752014-10-20 16:36:47 +01001525
1526 default:
1527 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1528 }
1529}
1530
Roland Levillaindff1f282014-11-05 14:15:05 +00001531void LocationsBuilderX86_64::VisitTypeConversion(HTypeConversion* conversion) {
1532 LocationSummary* locations =
1533 new (GetGraph()->GetArena()) LocationSummary(conversion, LocationSummary::kNoCall);
1534 Primitive::Type result_type = conversion->GetResultType();
1535 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00001536 DCHECK_NE(result_type, input_type);
David Brazdil46e2a392015-03-16 17:31:52 +00001537
David Brazdilb2bd1c52015-03-25 11:17:37 +00001538 // The Java language does not allow treating boolean as an integral type but
1539 // our bit representation makes it safe.
David Brazdil46e2a392015-03-16 17:31:52 +00001540
Roland Levillaindff1f282014-11-05 14:15:05 +00001541 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00001542 case Primitive::kPrimByte:
1543 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001544 case Primitive::kPrimBoolean:
1545 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001546 case Primitive::kPrimShort:
1547 case Primitive::kPrimInt:
1548 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001549 // Processing a Dex `int-to-byte' instruction.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001550 locations->SetInAt(0, Location::Any());
1551 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1552 break;
1553
1554 default:
1555 LOG(FATAL) << "Unexpected type conversion from " << input_type
1556 << " to " << result_type;
1557 }
1558 break;
1559
Roland Levillain01a8d712014-11-14 16:27:39 +00001560 case Primitive::kPrimShort:
1561 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001562 case Primitive::kPrimBoolean:
1563 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00001564 case Primitive::kPrimByte:
1565 case Primitive::kPrimInt:
1566 case Primitive::kPrimChar:
1567 // Processing a Dex `int-to-short' instruction.
1568 locations->SetInAt(0, Location::Any());
1569 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1570 break;
1571
1572 default:
1573 LOG(FATAL) << "Unexpected type conversion from " << input_type
1574 << " to " << result_type;
1575 }
1576 break;
1577
Roland Levillain946e1432014-11-11 17:35:19 +00001578 case Primitive::kPrimInt:
1579 switch (input_type) {
1580 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00001581 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00001582 locations->SetInAt(0, Location::Any());
1583 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1584 break;
1585
1586 case Primitive::kPrimFloat:
Roland Levillain3f8f9362014-12-02 17:45:01 +00001587 // Processing a Dex `float-to-int' instruction.
1588 locations->SetInAt(0, Location::RequiresFpuRegister());
1589 locations->SetOut(Location::RequiresRegister());
1590 locations->AddTemp(Location::RequiresFpuRegister());
1591 break;
1592
Roland Levillain946e1432014-11-11 17:35:19 +00001593 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001594 // Processing a Dex `double-to-int' instruction.
1595 locations->SetInAt(0, Location::RequiresFpuRegister());
1596 locations->SetOut(Location::RequiresRegister());
1597 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain946e1432014-11-11 17:35:19 +00001598 break;
1599
1600 default:
1601 LOG(FATAL) << "Unexpected type conversion from " << input_type
1602 << " to " << result_type;
1603 }
1604 break;
1605
Roland Levillaindff1f282014-11-05 14:15:05 +00001606 case Primitive::kPrimLong:
1607 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001608 case Primitive::kPrimBoolean:
1609 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00001610 case Primitive::kPrimByte:
1611 case Primitive::kPrimShort:
1612 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00001613 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001614 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00001615 // TODO: We would benefit from a (to-be-implemented)
1616 // Location::RegisterOrStackSlot requirement for this input.
1617 locations->SetInAt(0, Location::RequiresRegister());
1618 locations->SetOut(Location::RequiresRegister());
1619 break;
1620
1621 case Primitive::kPrimFloat:
Roland Levillain624279f2014-12-04 11:54:28 +00001622 // Processing a Dex `float-to-long' instruction.
1623 locations->SetInAt(0, Location::RequiresFpuRegister());
1624 locations->SetOut(Location::RequiresRegister());
1625 locations->AddTemp(Location::RequiresFpuRegister());
1626 break;
1627
Roland Levillaindff1f282014-11-05 14:15:05 +00001628 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001629 // Processing a Dex `double-to-long' instruction.
1630 locations->SetInAt(0, Location::RequiresFpuRegister());
1631 locations->SetOut(Location::RequiresRegister());
1632 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillaindff1f282014-11-05 14:15:05 +00001633 break;
1634
1635 default:
1636 LOG(FATAL) << "Unexpected type conversion from " << input_type
1637 << " to " << result_type;
1638 }
1639 break;
1640
Roland Levillain981e4542014-11-14 11:47:14 +00001641 case Primitive::kPrimChar:
1642 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001643 case Primitive::kPrimBoolean:
1644 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00001645 case Primitive::kPrimByte:
1646 case Primitive::kPrimShort:
1647 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00001648 // Processing a Dex `int-to-char' instruction.
1649 locations->SetInAt(0, Location::Any());
1650 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1651 break;
1652
1653 default:
1654 LOG(FATAL) << "Unexpected type conversion from " << input_type
1655 << " to " << result_type;
1656 }
1657 break;
1658
Roland Levillaindff1f282014-11-05 14:15:05 +00001659 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00001660 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001661 case Primitive::kPrimBoolean:
1662 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001663 case Primitive::kPrimByte:
1664 case Primitive::kPrimShort:
1665 case Primitive::kPrimInt:
1666 case Primitive::kPrimChar:
1667 // Processing a Dex `int-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04001668 locations->SetInAt(0, Location::Any());
Roland Levillaincff13742014-11-17 14:32:17 +00001669 locations->SetOut(Location::RequiresFpuRegister());
1670 break;
1671
1672 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00001673 // Processing a Dex `long-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04001674 locations->SetInAt(0, Location::Any());
Roland Levillain6d0e4832014-11-27 18:31:21 +00001675 locations->SetOut(Location::RequiresFpuRegister());
1676 break;
1677
Roland Levillaincff13742014-11-17 14:32:17 +00001678 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001679 // Processing a Dex `double-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04001680 locations->SetInAt(0, Location::Any());
Roland Levillain8964e2b2014-12-04 12:10:50 +00001681 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00001682 break;
1683
1684 default:
1685 LOG(FATAL) << "Unexpected type conversion from " << input_type
1686 << " to " << result_type;
1687 };
1688 break;
1689
Roland Levillaindff1f282014-11-05 14:15:05 +00001690 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00001691 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001692 case Primitive::kPrimBoolean:
1693 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001694 case Primitive::kPrimByte:
1695 case Primitive::kPrimShort:
1696 case Primitive::kPrimInt:
1697 case Primitive::kPrimChar:
1698 // Processing a Dex `int-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04001699 locations->SetInAt(0, Location::Any());
Roland Levillaincff13742014-11-17 14:32:17 +00001700 locations->SetOut(Location::RequiresFpuRegister());
1701 break;
1702
1703 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00001704 // Processing a Dex `long-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04001705 locations->SetInAt(0, Location::Any());
Roland Levillain647b9ed2014-11-27 12:06:00 +00001706 locations->SetOut(Location::RequiresFpuRegister());
1707 break;
1708
Roland Levillaincff13742014-11-17 14:32:17 +00001709 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001710 // Processing a Dex `float-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04001711 locations->SetInAt(0, Location::Any());
Roland Levillain8964e2b2014-12-04 12:10:50 +00001712 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00001713 break;
1714
1715 default:
1716 LOG(FATAL) << "Unexpected type conversion from " << input_type
1717 << " to " << result_type;
1718 }
Roland Levillaindff1f282014-11-05 14:15:05 +00001719 break;
1720
1721 default:
1722 LOG(FATAL) << "Unexpected type conversion from " << input_type
1723 << " to " << result_type;
1724 }
1725}
1726
1727void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conversion) {
1728 LocationSummary* locations = conversion->GetLocations();
1729 Location out = locations->Out();
1730 Location in = locations->InAt(0);
1731 Primitive::Type result_type = conversion->GetResultType();
1732 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00001733 DCHECK_NE(result_type, input_type);
Roland Levillaindff1f282014-11-05 14:15:05 +00001734 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00001735 case Primitive::kPrimByte:
1736 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001737 case Primitive::kPrimBoolean:
1738 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001739 case Primitive::kPrimShort:
1740 case Primitive::kPrimInt:
1741 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001742 // Processing a Dex `int-to-byte' instruction.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001743 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001744 __ movsxb(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain51d3fc42014-11-13 14:11:42 +00001745 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001746 __ movsxb(out.AsRegister<CpuRegister>(),
Roland Levillain51d3fc42014-11-13 14:11:42 +00001747 Address(CpuRegister(RSP), in.GetStackIndex()));
1748 } else {
1749 DCHECK(in.GetConstant()->IsIntConstant());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001750 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain51d3fc42014-11-13 14:11:42 +00001751 Immediate(static_cast<int8_t>(in.GetConstant()->AsIntConstant()->GetValue())));
1752 }
1753 break;
1754
1755 default:
1756 LOG(FATAL) << "Unexpected type conversion from " << input_type
1757 << " to " << result_type;
1758 }
1759 break;
1760
Roland Levillain01a8d712014-11-14 16:27:39 +00001761 case Primitive::kPrimShort:
1762 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001763 case Primitive::kPrimBoolean:
1764 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00001765 case Primitive::kPrimByte:
1766 case Primitive::kPrimInt:
1767 case Primitive::kPrimChar:
1768 // Processing a Dex `int-to-short' instruction.
1769 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001770 __ movsxw(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain01a8d712014-11-14 16:27:39 +00001771 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001772 __ movsxw(out.AsRegister<CpuRegister>(),
Roland Levillain01a8d712014-11-14 16:27:39 +00001773 Address(CpuRegister(RSP), in.GetStackIndex()));
1774 } else {
1775 DCHECK(in.GetConstant()->IsIntConstant());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001776 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain01a8d712014-11-14 16:27:39 +00001777 Immediate(static_cast<int16_t>(in.GetConstant()->AsIntConstant()->GetValue())));
1778 }
1779 break;
1780
1781 default:
1782 LOG(FATAL) << "Unexpected type conversion from " << input_type
1783 << " to " << result_type;
1784 }
1785 break;
1786
Roland Levillain946e1432014-11-11 17:35:19 +00001787 case Primitive::kPrimInt:
1788 switch (input_type) {
1789 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00001790 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00001791 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001792 __ movl(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain946e1432014-11-11 17:35:19 +00001793 } else if (in.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001794 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain946e1432014-11-11 17:35:19 +00001795 Address(CpuRegister(RSP), in.GetStackIndex()));
1796 } else {
1797 DCHECK(in.IsConstant());
1798 DCHECK(in.GetConstant()->IsLongConstant());
1799 int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00001800 __ movl(out.AsRegister<CpuRegister>(), Immediate(static_cast<int32_t>(value)));
Roland Levillain946e1432014-11-11 17:35:19 +00001801 }
1802 break;
1803
Roland Levillain3f8f9362014-12-02 17:45:01 +00001804 case Primitive::kPrimFloat: {
1805 // Processing a Dex `float-to-int' instruction.
1806 XmmRegister input = in.AsFpuRegister<XmmRegister>();
1807 CpuRegister output = out.AsRegister<CpuRegister>();
1808 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
1809 Label done, nan;
1810
1811 __ movl(output, Immediate(kPrimIntMax));
1812 // temp = int-to-float(output)
Roland Levillain624279f2014-12-04 11:54:28 +00001813 __ cvtsi2ss(temp, output, false);
Roland Levillain3f8f9362014-12-02 17:45:01 +00001814 // if input >= temp goto done
1815 __ comiss(input, temp);
1816 __ j(kAboveEqual, &done);
1817 // if input == NaN goto nan
1818 __ j(kUnordered, &nan);
1819 // output = float-to-int-truncate(input)
Roland Levillain624279f2014-12-04 11:54:28 +00001820 __ cvttss2si(output, input, false);
Roland Levillain3f8f9362014-12-02 17:45:01 +00001821 __ jmp(&done);
1822 __ Bind(&nan);
1823 // output = 0
1824 __ xorl(output, output);
1825 __ Bind(&done);
1826 break;
1827 }
1828
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001829 case Primitive::kPrimDouble: {
1830 // Processing a Dex `double-to-int' instruction.
1831 XmmRegister input = in.AsFpuRegister<XmmRegister>();
1832 CpuRegister output = out.AsRegister<CpuRegister>();
1833 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
1834 Label done, nan;
1835
1836 __ movl(output, Immediate(kPrimIntMax));
1837 // temp = int-to-double(output)
1838 __ cvtsi2sd(temp, output);
1839 // if input >= temp goto done
1840 __ comisd(input, temp);
1841 __ j(kAboveEqual, &done);
1842 // if input == NaN goto nan
1843 __ j(kUnordered, &nan);
1844 // output = double-to-int-truncate(input)
1845 __ cvttsd2si(output, input);
1846 __ jmp(&done);
1847 __ Bind(&nan);
1848 // output = 0
1849 __ xorl(output, output);
1850 __ Bind(&done);
Roland Levillain946e1432014-11-11 17:35:19 +00001851 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001852 }
Roland Levillain946e1432014-11-11 17:35:19 +00001853
1854 default:
1855 LOG(FATAL) << "Unexpected type conversion from " << input_type
1856 << " to " << result_type;
1857 }
1858 break;
1859
Roland Levillaindff1f282014-11-05 14:15:05 +00001860 case Primitive::kPrimLong:
1861 switch (input_type) {
1862 DCHECK(out.IsRegister());
David Brazdil46e2a392015-03-16 17:31:52 +00001863 case Primitive::kPrimBoolean:
1864 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00001865 case Primitive::kPrimByte:
1866 case Primitive::kPrimShort:
1867 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00001868 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001869 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00001870 DCHECK(in.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001871 __ movsxd(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillaindff1f282014-11-05 14:15:05 +00001872 break;
1873
Roland Levillain624279f2014-12-04 11:54:28 +00001874 case Primitive::kPrimFloat: {
1875 // Processing a Dex `float-to-long' instruction.
1876 XmmRegister input = in.AsFpuRegister<XmmRegister>();
1877 CpuRegister output = out.AsRegister<CpuRegister>();
1878 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
1879 Label done, nan;
1880
Mark Mendell92e83bf2015-05-07 11:25:03 -04001881 codegen_->Load64BitValue(output, kPrimLongMax);
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001882 // temp = long-to-float(output)
Roland Levillain624279f2014-12-04 11:54:28 +00001883 __ cvtsi2ss(temp, output, true);
1884 // if input >= temp goto done
1885 __ comiss(input, temp);
1886 __ j(kAboveEqual, &done);
1887 // if input == NaN goto nan
1888 __ j(kUnordered, &nan);
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001889 // output = float-to-long-truncate(input)
Roland Levillain624279f2014-12-04 11:54:28 +00001890 __ cvttss2si(output, input, true);
1891 __ jmp(&done);
1892 __ Bind(&nan);
1893 // output = 0
Mark Mendell92e83bf2015-05-07 11:25:03 -04001894 __ xorl(output, output);
Roland Levillain624279f2014-12-04 11:54:28 +00001895 __ Bind(&done);
1896 break;
1897 }
1898
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001899 case Primitive::kPrimDouble: {
1900 // Processing a Dex `double-to-long' instruction.
1901 XmmRegister input = in.AsFpuRegister<XmmRegister>();
1902 CpuRegister output = out.AsRegister<CpuRegister>();
1903 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
1904 Label done, nan;
1905
Mark Mendell92e83bf2015-05-07 11:25:03 -04001906 codegen_->Load64BitValue(output, kPrimLongMax);
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001907 // temp = long-to-double(output)
1908 __ cvtsi2sd(temp, output, true);
1909 // if input >= temp goto done
1910 __ comisd(input, temp);
1911 __ j(kAboveEqual, &done);
1912 // if input == NaN goto nan
1913 __ j(kUnordered, &nan);
1914 // output = double-to-long-truncate(input)
1915 __ cvttsd2si(output, input, true);
1916 __ jmp(&done);
1917 __ Bind(&nan);
1918 // output = 0
Mark Mendell92e83bf2015-05-07 11:25:03 -04001919 __ xorl(output, output);
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001920 __ Bind(&done);
Roland Levillaindff1f282014-11-05 14:15:05 +00001921 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001922 }
Roland Levillaindff1f282014-11-05 14:15:05 +00001923
1924 default:
1925 LOG(FATAL) << "Unexpected type conversion from " << input_type
1926 << " to " << result_type;
1927 }
1928 break;
1929
Roland Levillain981e4542014-11-14 11:47:14 +00001930 case Primitive::kPrimChar:
1931 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001932 case Primitive::kPrimBoolean:
1933 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00001934 case Primitive::kPrimByte:
1935 case Primitive::kPrimShort:
1936 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00001937 // Processing a Dex `int-to-char' instruction.
1938 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001939 __ movzxw(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain981e4542014-11-14 11:47:14 +00001940 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001941 __ movzxw(out.AsRegister<CpuRegister>(),
Roland Levillain981e4542014-11-14 11:47:14 +00001942 Address(CpuRegister(RSP), in.GetStackIndex()));
1943 } else {
1944 DCHECK(in.GetConstant()->IsIntConstant());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001945 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain981e4542014-11-14 11:47:14 +00001946 Immediate(static_cast<uint16_t>(in.GetConstant()->AsIntConstant()->GetValue())));
1947 }
1948 break;
1949
1950 default:
1951 LOG(FATAL) << "Unexpected type conversion from " << input_type
1952 << " to " << result_type;
1953 }
1954 break;
1955
Roland Levillaindff1f282014-11-05 14:15:05 +00001956 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00001957 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001958 case Primitive::kPrimBoolean:
1959 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001960 case Primitive::kPrimByte:
1961 case Primitive::kPrimShort:
1962 case Primitive::kPrimInt:
1963 case Primitive::kPrimChar:
Roland Levillain6d0e4832014-11-27 18:31:21 +00001964 // Processing a Dex `int-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04001965 if (in.IsRegister()) {
1966 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), false);
1967 } else if (in.IsConstant()) {
1968 int32_t v = in.GetConstant()->AsIntConstant()->GetValue();
1969 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
1970 if (v == 0) {
1971 __ xorps(dest, dest);
1972 } else {
1973 __ movss(dest, codegen_->LiteralFloatAddress(static_cast<float>(v)));
1974 }
1975 } else {
1976 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(),
1977 Address(CpuRegister(RSP), in.GetStackIndex()), false);
1978 }
Roland Levillaincff13742014-11-17 14:32:17 +00001979 break;
1980
1981 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00001982 // Processing a Dex `long-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04001983 if (in.IsRegister()) {
1984 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), true);
1985 } else if (in.IsConstant()) {
1986 int64_t v = in.GetConstant()->AsLongConstant()->GetValue();
1987 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
1988 if (v == 0) {
1989 __ xorps(dest, dest);
1990 } else {
1991 __ movss(dest, codegen_->LiteralFloatAddress(static_cast<float>(v)));
1992 }
1993 } else {
1994 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(),
1995 Address(CpuRegister(RSP), in.GetStackIndex()), true);
1996 }
Roland Levillain6d0e4832014-11-27 18:31:21 +00001997 break;
1998
Roland Levillaincff13742014-11-17 14:32:17 +00001999 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002000 // Processing a Dex `double-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002001 if (in.IsFpuRegister()) {
2002 __ cvtsd2ss(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
2003 } else if (in.IsConstant()) {
2004 double v = in.GetConstant()->AsDoubleConstant()->GetValue();
2005 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
2006 if (bit_cast<int64_t, double>(v) == 0) {
2007 __ xorps(dest, dest);
2008 } else {
2009 __ movss(dest, codegen_->LiteralFloatAddress(static_cast<float>(v)));
2010 }
2011 } else {
2012 __ cvtsd2ss(out.AsFpuRegister<XmmRegister>(),
2013 Address(CpuRegister(RSP), in.GetStackIndex()));
2014 }
Roland Levillaincff13742014-11-17 14:32:17 +00002015 break;
2016
2017 default:
2018 LOG(FATAL) << "Unexpected type conversion from " << input_type
2019 << " to " << result_type;
2020 };
2021 break;
2022
Roland Levillaindff1f282014-11-05 14:15:05 +00002023 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00002024 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002025 case Primitive::kPrimBoolean:
2026 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002027 case Primitive::kPrimByte:
2028 case Primitive::kPrimShort:
2029 case Primitive::kPrimInt:
2030 case Primitive::kPrimChar:
Roland Levillain6d0e4832014-11-27 18:31:21 +00002031 // Processing a Dex `int-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002032 if (in.IsRegister()) {
2033 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), false);
2034 } else if (in.IsConstant()) {
2035 int32_t v = in.GetConstant()->AsIntConstant()->GetValue();
2036 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
2037 if (v == 0) {
2038 __ xorpd(dest, dest);
2039 } else {
2040 __ movsd(dest, codegen_->LiteralDoubleAddress(static_cast<double>(v)));
2041 }
2042 } else {
2043 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(),
2044 Address(CpuRegister(RSP), in.GetStackIndex()), false);
2045 }
Roland Levillaincff13742014-11-17 14:32:17 +00002046 break;
2047
2048 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00002049 // Processing a Dex `long-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002050 if (in.IsRegister()) {
2051 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), true);
2052 } else if (in.IsConstant()) {
2053 int64_t v = in.GetConstant()->AsLongConstant()->GetValue();
2054 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
2055 if (v == 0) {
2056 __ xorpd(dest, dest);
2057 } else {
2058 __ movsd(dest, codegen_->LiteralDoubleAddress(static_cast<double>(v)));
2059 }
2060 } else {
2061 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(),
2062 Address(CpuRegister(RSP), in.GetStackIndex()), true);
2063 }
Roland Levillain647b9ed2014-11-27 12:06:00 +00002064 break;
2065
Roland Levillaincff13742014-11-17 14:32:17 +00002066 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002067 // Processing a Dex `float-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002068 if (in.IsFpuRegister()) {
2069 __ cvtss2sd(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
2070 } else if (in.IsConstant()) {
2071 float v = in.GetConstant()->AsFloatConstant()->GetValue();
2072 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
2073 if (bit_cast<int32_t, float>(v) == 0) {
2074 __ xorpd(dest, dest);
2075 } else {
2076 __ movsd(dest, codegen_->LiteralDoubleAddress(static_cast<double>(v)));
2077 }
2078 } else {
2079 __ cvtss2sd(out.AsFpuRegister<XmmRegister>(),
2080 Address(CpuRegister(RSP), in.GetStackIndex()));
2081 }
Roland Levillaincff13742014-11-17 14:32:17 +00002082 break;
2083
2084 default:
2085 LOG(FATAL) << "Unexpected type conversion from " << input_type
2086 << " to " << result_type;
2087 };
Roland Levillaindff1f282014-11-05 14:15:05 +00002088 break;
2089
2090 default:
2091 LOG(FATAL) << "Unexpected type conversion from " << input_type
2092 << " to " << result_type;
2093 }
2094}
2095
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002096void LocationsBuilderX86_64::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002097 LocationSummary* locations =
2098 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002099 switch (add->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002100 case Primitive::kPrimInt: {
2101 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002102 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
2103 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002104 break;
2105 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002106
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002107 case Primitive::kPrimLong: {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002108 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell09b84632015-02-13 17:48:38 -05002109 // We can use a leaq or addq if the constant can fit in an immediate.
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002110 locations->SetInAt(1, Location::RegisterOrInt32LongConstant(add->InputAt(1)));
Mark Mendell09b84632015-02-13 17:48:38 -05002111 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002112 break;
2113 }
2114
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002115 case Primitive::kPrimDouble:
2116 case Primitive::kPrimFloat: {
2117 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendellf55c3e02015-03-26 21:07:46 -04002118 locations->SetInAt(1, Location::Any());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002119 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002120 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002121 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002122
2123 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002124 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002125 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002126}
2127
2128void InstructionCodeGeneratorX86_64::VisitAdd(HAdd* add) {
2129 LocationSummary* locations = add->GetLocations();
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002130 Location first = locations->InAt(0);
2131 Location second = locations->InAt(1);
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002132 Location out = locations->Out();
Calin Juravle11351682014-10-23 15:38:15 +01002133
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002134 switch (add->GetResultType()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002135 case Primitive::kPrimInt: {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002136 if (second.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002137 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
2138 __ addl(out.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Mark Mendell33bf2452015-05-27 10:08:24 -04002139 } else if (out.AsRegister<Register>() == second.AsRegister<Register>()) {
2140 __ addl(out.AsRegister<CpuRegister>(), first.AsRegister<CpuRegister>());
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002141 } else {
2142 __ leal(out.AsRegister<CpuRegister>(), Address(
2143 first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>(), TIMES_1, 0));
2144 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002145 } else if (second.IsConstant()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002146 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
2147 __ addl(out.AsRegister<CpuRegister>(),
2148 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
2149 } else {
2150 __ leal(out.AsRegister<CpuRegister>(), Address(
2151 first.AsRegister<CpuRegister>(), second.GetConstant()->AsIntConstant()->GetValue()));
2152 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002153 } else {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002154 DCHECK(first.Equals(locations->Out()));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002155 __ addl(first.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), second.GetStackIndex()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002156 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002157 break;
2158 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002159
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002160 case Primitive::kPrimLong: {
Mark Mendell09b84632015-02-13 17:48:38 -05002161 if (second.IsRegister()) {
2162 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
2163 __ addq(out.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Mark Mendell33bf2452015-05-27 10:08:24 -04002164 } else if (out.AsRegister<Register>() == second.AsRegister<Register>()) {
2165 __ addq(out.AsRegister<CpuRegister>(), first.AsRegister<CpuRegister>());
Mark Mendell09b84632015-02-13 17:48:38 -05002166 } else {
2167 __ leaq(out.AsRegister<CpuRegister>(), Address(
2168 first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>(), TIMES_1, 0));
2169 }
2170 } else {
2171 DCHECK(second.IsConstant());
2172 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
2173 int32_t int32_value = Low32Bits(value);
2174 DCHECK_EQ(int32_value, value);
2175 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
2176 __ addq(out.AsRegister<CpuRegister>(), Immediate(int32_value));
2177 } else {
2178 __ leaq(out.AsRegister<CpuRegister>(), Address(
2179 first.AsRegister<CpuRegister>(), int32_value));
2180 }
2181 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002182 break;
2183 }
2184
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002185 case Primitive::kPrimFloat: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04002186 if (second.IsFpuRegister()) {
2187 __ addss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2188 } else if (second.IsConstant()) {
2189 __ addss(first.AsFpuRegister<XmmRegister>(),
2190 codegen_->LiteralFloatAddress(second.GetConstant()->AsFloatConstant()->GetValue()));
2191 } else {
2192 DCHECK(second.IsStackSlot());
2193 __ addss(first.AsFpuRegister<XmmRegister>(),
2194 Address(CpuRegister(RSP), second.GetStackIndex()));
2195 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002196 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002197 }
2198
2199 case Primitive::kPrimDouble: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04002200 if (second.IsFpuRegister()) {
2201 __ addsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2202 } else if (second.IsConstant()) {
2203 __ addsd(first.AsFpuRegister<XmmRegister>(),
2204 codegen_->LiteralDoubleAddress(second.GetConstant()->AsDoubleConstant()->GetValue()));
2205 } else {
2206 DCHECK(second.IsDoubleStackSlot());
2207 __ addsd(first.AsFpuRegister<XmmRegister>(),
2208 Address(CpuRegister(RSP), second.GetStackIndex()));
2209 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002210 break;
2211 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002212
2213 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002214 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002215 }
2216}
2217
2218void LocationsBuilderX86_64::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002219 LocationSummary* locations =
2220 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002221 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002222 case Primitive::kPrimInt: {
2223 locations->SetInAt(0, Location::RequiresRegister());
2224 locations->SetInAt(1, Location::Any());
2225 locations->SetOut(Location::SameAsFirstInput());
2226 break;
2227 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002228 case Primitive::kPrimLong: {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002229 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002230 locations->SetInAt(1, Location::RegisterOrInt32LongConstant(sub->InputAt(1)));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002231 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002232 break;
2233 }
Calin Juravle11351682014-10-23 15:38:15 +01002234 case Primitive::kPrimFloat:
2235 case Primitive::kPrimDouble: {
2236 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendellf55c3e02015-03-26 21:07:46 -04002237 locations->SetInAt(1, Location::Any());
Calin Juravle11351682014-10-23 15:38:15 +01002238 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002239 break;
Calin Juravle11351682014-10-23 15:38:15 +01002240 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002241 default:
Calin Juravle11351682014-10-23 15:38:15 +01002242 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002243 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002244}
2245
2246void InstructionCodeGeneratorX86_64::VisitSub(HSub* sub) {
2247 LocationSummary* locations = sub->GetLocations();
Calin Juravle11351682014-10-23 15:38:15 +01002248 Location first = locations->InAt(0);
2249 Location second = locations->InAt(1);
2250 DCHECK(first.Equals(locations->Out()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002251 switch (sub->GetResultType()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002252 case Primitive::kPrimInt: {
Calin Juravle11351682014-10-23 15:38:15 +01002253 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002254 __ subl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Calin Juravle11351682014-10-23 15:38:15 +01002255 } else if (second.IsConstant()) {
2256 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002257 __ subl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002258 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002259 __ subl(first.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), second.GetStackIndex()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002260 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002261 break;
2262 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002263 case Primitive::kPrimLong: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002264 if (second.IsConstant()) {
2265 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
2266 DCHECK(IsInt<32>(value));
2267 __ subq(first.AsRegister<CpuRegister>(), Immediate(static_cast<int32_t>(value)));
2268 } else {
2269 __ subq(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
2270 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002271 break;
2272 }
2273
Calin Juravle11351682014-10-23 15:38:15 +01002274 case Primitive::kPrimFloat: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04002275 if (second.IsFpuRegister()) {
2276 __ subss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2277 } else if (second.IsConstant()) {
2278 __ subss(first.AsFpuRegister<XmmRegister>(),
2279 codegen_->LiteralFloatAddress(second.GetConstant()->AsFloatConstant()->GetValue()));
2280 } else {
2281 DCHECK(second.IsStackSlot());
2282 __ subss(first.AsFpuRegister<XmmRegister>(),
2283 Address(CpuRegister(RSP), second.GetStackIndex()));
2284 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002285 break;
Calin Juravle11351682014-10-23 15:38:15 +01002286 }
2287
2288 case Primitive::kPrimDouble: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04002289 if (second.IsFpuRegister()) {
2290 __ subsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2291 } else if (second.IsConstant()) {
2292 __ subsd(first.AsFpuRegister<XmmRegister>(),
2293 codegen_->LiteralDoubleAddress(second.GetConstant()->AsDoubleConstant()->GetValue()));
2294 } else {
2295 DCHECK(second.IsDoubleStackSlot());
2296 __ subsd(first.AsFpuRegister<XmmRegister>(),
2297 Address(CpuRegister(RSP), second.GetStackIndex()));
2298 }
Calin Juravle11351682014-10-23 15:38:15 +01002299 break;
2300 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002301
2302 default:
Calin Juravle11351682014-10-23 15:38:15 +01002303 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002304 }
2305}
2306
Calin Juravle34bacdf2014-10-07 20:23:36 +01002307void LocationsBuilderX86_64::VisitMul(HMul* mul) {
2308 LocationSummary* locations =
2309 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
2310 switch (mul->GetResultType()) {
2311 case Primitive::kPrimInt: {
2312 locations->SetInAt(0, Location::RequiresRegister());
2313 locations->SetInAt(1, Location::Any());
2314 locations->SetOut(Location::SameAsFirstInput());
2315 break;
2316 }
2317 case Primitive::kPrimLong: {
2318 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002319 locations->SetInAt(1, Location::RegisterOrInt32LongConstant(mul->InputAt(1)));
2320 if (locations->InAt(1).IsConstant()) {
2321 // Can use 3 operand multiply.
2322 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2323 } else {
2324 locations->SetOut(Location::SameAsFirstInput());
2325 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002326 break;
2327 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01002328 case Primitive::kPrimFloat:
2329 case Primitive::kPrimDouble: {
2330 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendellf55c3e02015-03-26 21:07:46 -04002331 locations->SetInAt(1, Location::Any());
Calin Juravleb5bfa962014-10-21 18:02:24 +01002332 locations->SetOut(Location::SameAsFirstInput());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002333 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002334 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002335
2336 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002337 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002338 }
2339}
2340
2341void InstructionCodeGeneratorX86_64::VisitMul(HMul* mul) {
2342 LocationSummary* locations = mul->GetLocations();
2343 Location first = locations->InAt(0);
2344 Location second = locations->InAt(1);
Calin Juravle34bacdf2014-10-07 20:23:36 +01002345 switch (mul->GetResultType()) {
2346 case Primitive::kPrimInt: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002347 DCHECK(first.Equals(locations->Out()));
Calin Juravle34bacdf2014-10-07 20:23:36 +01002348 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002349 __ imull(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002350 } else if (second.IsConstant()) {
2351 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002352 __ imull(first.AsRegister<CpuRegister>(), imm);
Calin Juravle34bacdf2014-10-07 20:23:36 +01002353 } else {
2354 DCHECK(second.IsStackSlot());
Roland Levillain199f3362014-11-27 17:15:16 +00002355 __ imull(first.AsRegister<CpuRegister>(),
2356 Address(CpuRegister(RSP), second.GetStackIndex()));
Calin Juravle34bacdf2014-10-07 20:23:36 +01002357 }
2358 break;
2359 }
2360 case Primitive::kPrimLong: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002361 if (second.IsConstant()) {
2362 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
2363 DCHECK(IsInt<32>(value));
2364 __ imulq(locations->Out().AsRegister<CpuRegister>(),
2365 first.AsRegister<CpuRegister>(),
2366 Immediate(static_cast<int32_t>(value)));
2367 } else {
2368 DCHECK(first.Equals(locations->Out()));
2369 __ imulq(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
2370 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002371 break;
2372 }
2373
Calin Juravleb5bfa962014-10-21 18:02:24 +01002374 case Primitive::kPrimFloat: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002375 DCHECK(first.Equals(locations->Out()));
Mark Mendellf55c3e02015-03-26 21:07:46 -04002376 if (second.IsFpuRegister()) {
2377 __ mulss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2378 } else if (second.IsConstant()) {
2379 __ mulss(first.AsFpuRegister<XmmRegister>(),
2380 codegen_->LiteralFloatAddress(second.GetConstant()->AsFloatConstant()->GetValue()));
2381 } else {
2382 DCHECK(second.IsStackSlot());
2383 __ mulss(first.AsFpuRegister<XmmRegister>(),
2384 Address(CpuRegister(RSP), second.GetStackIndex()));
2385 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002386 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002387 }
2388
2389 case Primitive::kPrimDouble: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002390 DCHECK(first.Equals(locations->Out()));
Mark Mendellf55c3e02015-03-26 21:07:46 -04002391 if (second.IsFpuRegister()) {
2392 __ mulsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2393 } else if (second.IsConstant()) {
2394 __ mulsd(first.AsFpuRegister<XmmRegister>(),
2395 codegen_->LiteralDoubleAddress(second.GetConstant()->AsDoubleConstant()->GetValue()));
2396 } else {
2397 DCHECK(second.IsDoubleStackSlot());
2398 __ mulsd(first.AsFpuRegister<XmmRegister>(),
2399 Address(CpuRegister(RSP), second.GetStackIndex()));
2400 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01002401 break;
2402 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002403
2404 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002405 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002406 }
2407}
2408
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002409void InstructionCodeGeneratorX86_64::PushOntoFPStack(Location source, uint32_t temp_offset,
2410 uint32_t stack_adjustment, bool is_float) {
2411 if (source.IsStackSlot()) {
2412 DCHECK(is_float);
2413 __ flds(Address(CpuRegister(RSP), source.GetStackIndex() + stack_adjustment));
2414 } else if (source.IsDoubleStackSlot()) {
2415 DCHECK(!is_float);
2416 __ fldl(Address(CpuRegister(RSP), source.GetStackIndex() + stack_adjustment));
2417 } else {
2418 // Write the value to the temporary location on the stack and load to FP stack.
2419 if (is_float) {
2420 Location stack_temp = Location::StackSlot(temp_offset);
2421 codegen_->Move(stack_temp, source);
2422 __ flds(Address(CpuRegister(RSP), temp_offset));
2423 } else {
2424 Location stack_temp = Location::DoubleStackSlot(temp_offset);
2425 codegen_->Move(stack_temp, source);
2426 __ fldl(Address(CpuRegister(RSP), temp_offset));
2427 }
2428 }
2429}
2430
2431void InstructionCodeGeneratorX86_64::GenerateRemFP(HRem *rem) {
2432 Primitive::Type type = rem->GetResultType();
2433 bool is_float = type == Primitive::kPrimFloat;
2434 size_t elem_size = Primitive::ComponentSize(type);
2435 LocationSummary* locations = rem->GetLocations();
2436 Location first = locations->InAt(0);
2437 Location second = locations->InAt(1);
2438 Location out = locations->Out();
2439
2440 // Create stack space for 2 elements.
2441 // TODO: enhance register allocator to ask for stack temporaries.
2442 __ subq(CpuRegister(RSP), Immediate(2 * elem_size));
2443
2444 // Load the values to the FP stack in reverse order, using temporaries if needed.
2445 PushOntoFPStack(second, elem_size, 2 * elem_size, is_float);
2446 PushOntoFPStack(first, 0, 2 * elem_size, is_float);
2447
2448 // Loop doing FPREM until we stabilize.
2449 Label retry;
2450 __ Bind(&retry);
2451 __ fprem();
2452
2453 // Move FP status to AX.
2454 __ fstsw();
2455
2456 // And see if the argument reduction is complete. This is signaled by the
2457 // C2 FPU flag bit set to 0.
2458 __ andl(CpuRegister(RAX), Immediate(kC2ConditionMask));
2459 __ j(kNotEqual, &retry);
2460
2461 // We have settled on the final value. Retrieve it into an XMM register.
2462 // Store FP top of stack to real stack.
2463 if (is_float) {
2464 __ fsts(Address(CpuRegister(RSP), 0));
2465 } else {
2466 __ fstl(Address(CpuRegister(RSP), 0));
2467 }
2468
2469 // Pop the 2 items from the FP stack.
2470 __ fucompp();
2471
2472 // Load the value from the stack into an XMM register.
2473 DCHECK(out.IsFpuRegister()) << out;
2474 if (is_float) {
2475 __ movss(out.AsFpuRegister<XmmRegister>(), Address(CpuRegister(RSP), 0));
2476 } else {
2477 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(CpuRegister(RSP), 0));
2478 }
2479
2480 // And remove the temporary stack space we allocated.
2481 __ addq(CpuRegister(RSP), Immediate(2 * elem_size));
2482}
2483
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002484void InstructionCodeGeneratorX86_64::DivRemOneOrMinusOne(HBinaryOperation* instruction) {
2485 DCHECK(instruction->IsDiv() || instruction->IsRem());
2486
2487 LocationSummary* locations = instruction->GetLocations();
2488 Location second = locations->InAt(1);
2489 DCHECK(second.IsConstant());
2490
2491 CpuRegister output_register = locations->Out().AsRegister<CpuRegister>();
2492 CpuRegister input_register = locations->InAt(0).AsRegister<CpuRegister>();
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002493 int64_t imm = Int64FromConstant(second.GetConstant());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002494
2495 DCHECK(imm == 1 || imm == -1);
2496
2497 switch (instruction->GetResultType()) {
2498 case Primitive::kPrimInt: {
2499 if (instruction->IsRem()) {
2500 __ xorl(output_register, output_register);
2501 } else {
2502 __ movl(output_register, input_register);
2503 if (imm == -1) {
2504 __ negl(output_register);
2505 }
2506 }
2507 break;
2508 }
2509
2510 case Primitive::kPrimLong: {
2511 if (instruction->IsRem()) {
Mark Mendell92e83bf2015-05-07 11:25:03 -04002512 __ xorl(output_register, output_register);
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002513 } else {
2514 __ movq(output_register, input_register);
2515 if (imm == -1) {
2516 __ negq(output_register);
2517 }
2518 }
2519 break;
2520 }
2521
2522 default:
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002523 LOG(FATAL) << "Unexpected type for div by (-)1 " << instruction->GetResultType();
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002524 }
2525}
2526
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002527void InstructionCodeGeneratorX86_64::DivByPowerOfTwo(HDiv* instruction) {
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002528 LocationSummary* locations = instruction->GetLocations();
2529 Location second = locations->InAt(1);
2530
2531 CpuRegister output_register = locations->Out().AsRegister<CpuRegister>();
2532 CpuRegister numerator = locations->InAt(0).AsRegister<CpuRegister>();
2533
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002534 int64_t imm = Int64FromConstant(second.GetConstant());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002535
2536 DCHECK(IsPowerOfTwo(std::abs(imm)));
2537
2538 CpuRegister tmp = locations->GetTemp(0).AsRegister<CpuRegister>();
2539
2540 if (instruction->GetResultType() == Primitive::kPrimInt) {
2541 __ leal(tmp, Address(numerator, std::abs(imm) - 1));
2542 __ testl(numerator, numerator);
2543 __ cmov(kGreaterEqual, tmp, numerator);
2544 int shift = CTZ(imm);
2545 __ sarl(tmp, Immediate(shift));
2546
2547 if (imm < 0) {
2548 __ negl(tmp);
2549 }
2550
2551 __ movl(output_register, tmp);
2552 } else {
2553 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
2554 CpuRegister rdx = locations->GetTemp(0).AsRegister<CpuRegister>();
2555
Mark Mendell92e83bf2015-05-07 11:25:03 -04002556 codegen_->Load64BitValue(rdx, std::abs(imm) - 1);
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002557 __ addq(rdx, numerator);
2558 __ testq(numerator, numerator);
2559 __ cmov(kGreaterEqual, rdx, numerator);
2560 int shift = CTZ(imm);
2561 __ sarq(rdx, Immediate(shift));
2562
2563 if (imm < 0) {
2564 __ negq(rdx);
2565 }
2566
2567 __ movq(output_register, rdx);
2568 }
2569}
2570
2571void InstructionCodeGeneratorX86_64::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) {
2572 DCHECK(instruction->IsDiv() || instruction->IsRem());
2573
2574 LocationSummary* locations = instruction->GetLocations();
2575 Location second = locations->InAt(1);
2576
2577 CpuRegister numerator = instruction->IsDiv() ? locations->GetTemp(1).AsRegister<CpuRegister>()
2578 : locations->GetTemp(0).AsRegister<CpuRegister>();
2579 CpuRegister eax = locations->InAt(0).AsRegister<CpuRegister>();
2580 CpuRegister edx = instruction->IsDiv() ? locations->GetTemp(0).AsRegister<CpuRegister>()
2581 : locations->Out().AsRegister<CpuRegister>();
2582 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
2583
2584 DCHECK_EQ(RAX, eax.AsRegister());
2585 DCHECK_EQ(RDX, edx.AsRegister());
2586 if (instruction->IsDiv()) {
2587 DCHECK_EQ(RAX, out.AsRegister());
2588 } else {
2589 DCHECK_EQ(RDX, out.AsRegister());
2590 }
2591
2592 int64_t magic;
2593 int shift;
2594
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002595 // TODO: can these branches be written as one?
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002596 if (instruction->GetResultType() == Primitive::kPrimInt) {
2597 int imm = second.GetConstant()->AsIntConstant()->GetValue();
2598
2599 CalculateMagicAndShiftForDivRem(imm, false /* is_long */, &magic, &shift);
2600
2601 __ movl(numerator, eax);
2602
2603 Label no_div;
2604 Label end;
2605 __ testl(eax, eax);
2606 __ j(kNotEqual, &no_div);
2607
2608 __ xorl(out, out);
2609 __ jmp(&end);
2610
2611 __ Bind(&no_div);
2612
2613 __ movl(eax, Immediate(magic));
2614 __ imull(numerator);
2615
2616 if (imm > 0 && magic < 0) {
2617 __ addl(edx, numerator);
2618 } else if (imm < 0 && magic > 0) {
2619 __ subl(edx, numerator);
2620 }
2621
2622 if (shift != 0) {
2623 __ sarl(edx, Immediate(shift));
2624 }
2625
2626 __ movl(eax, edx);
2627 __ shrl(edx, Immediate(31));
2628 __ addl(edx, eax);
2629
2630 if (instruction->IsRem()) {
2631 __ movl(eax, numerator);
2632 __ imull(edx, Immediate(imm));
2633 __ subl(eax, edx);
2634 __ movl(edx, eax);
2635 } else {
2636 __ movl(eax, edx);
2637 }
2638 __ Bind(&end);
2639 } else {
2640 int64_t imm = second.GetConstant()->AsLongConstant()->GetValue();
2641
2642 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
2643
2644 CpuRegister rax = eax;
2645 CpuRegister rdx = edx;
2646
2647 CalculateMagicAndShiftForDivRem(imm, true /* is_long */, &magic, &shift);
2648
2649 // Save the numerator.
2650 __ movq(numerator, rax);
2651
2652 // RAX = magic
Mark Mendell92e83bf2015-05-07 11:25:03 -04002653 codegen_->Load64BitValue(rax, magic);
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002654
2655 // RDX:RAX = magic * numerator
2656 __ imulq(numerator);
2657
2658 if (imm > 0 && magic < 0) {
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002659 // RDX += numerator
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002660 __ addq(rdx, numerator);
2661 } else if (imm < 0 && magic > 0) {
2662 // RDX -= numerator
2663 __ subq(rdx, numerator);
2664 }
2665
2666 // Shift if needed.
2667 if (shift != 0) {
2668 __ sarq(rdx, Immediate(shift));
2669 }
2670
2671 // RDX += 1 if RDX < 0
2672 __ movq(rax, rdx);
2673 __ shrq(rdx, Immediate(63));
2674 __ addq(rdx, rax);
2675
2676 if (instruction->IsRem()) {
2677 __ movq(rax, numerator);
2678
2679 if (IsInt<32>(imm)) {
2680 __ imulq(rdx, Immediate(static_cast<int32_t>(imm)));
2681 } else {
Mark Mendell92e83bf2015-05-07 11:25:03 -04002682 __ imulq(rdx, codegen_->LiteralInt64Address(imm));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002683 }
2684
2685 __ subq(rax, rdx);
2686 __ movq(rdx, rax);
2687 } else {
2688 __ movq(rax, rdx);
2689 }
2690 }
2691}
2692
Calin Juravlebacfec32014-11-14 15:54:36 +00002693void InstructionCodeGeneratorX86_64::GenerateDivRemIntegral(HBinaryOperation* instruction) {
2694 DCHECK(instruction->IsDiv() || instruction->IsRem());
2695 Primitive::Type type = instruction->GetResultType();
2696 DCHECK(type == Primitive::kPrimInt || Primitive::kPrimLong);
2697
2698 bool is_div = instruction->IsDiv();
2699 LocationSummary* locations = instruction->GetLocations();
2700
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002701 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
2702 Location second = locations->InAt(1);
Calin Juravlebacfec32014-11-14 15:54:36 +00002703
Roland Levillain271ab9c2014-11-27 15:23:57 +00002704 DCHECK_EQ(RAX, locations->InAt(0).AsRegister<CpuRegister>().AsRegister());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002705 DCHECK_EQ(is_div ? RAX : RDX, out.AsRegister());
Calin Juravlebacfec32014-11-14 15:54:36 +00002706
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002707 if (second.IsConstant()) {
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002708 int64_t imm = Int64FromConstant(second.GetConstant());
Calin Juravlebacfec32014-11-14 15:54:36 +00002709
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002710 if (imm == 0) {
2711 // Do not generate anything. DivZeroCheck would prevent any code to be executed.
2712 } else if (imm == 1 || imm == -1) {
2713 DivRemOneOrMinusOne(instruction);
2714 } else if (instruction->IsDiv() && IsPowerOfTwo(std::abs(imm))) {
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002715 DivByPowerOfTwo(instruction->AsDiv());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002716 } else {
2717 DCHECK(imm <= -2 || imm >= 2);
2718 GenerateDivRemWithAnyConstant(instruction);
2719 }
Calin Juravlebacfec32014-11-14 15:54:36 +00002720 } else {
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002721 SlowPathCodeX86_64* slow_path =
2722 new (GetGraph()->GetArena()) DivRemMinusOneSlowPathX86_64(
2723 out.AsRegister(), type, is_div);
2724 codegen_->AddSlowPath(slow_path);
Calin Juravlebacfec32014-11-14 15:54:36 +00002725
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002726 CpuRegister second_reg = second.AsRegister<CpuRegister>();
2727 // 0x80000000(00000000)/-1 triggers an arithmetic exception!
2728 // Dividing by -1 is actually negation and -0x800000000(00000000) = 0x80000000(00000000)
2729 // so it's safe to just use negl instead of more complex comparisons.
2730 if (type == Primitive::kPrimInt) {
2731 __ cmpl(second_reg, Immediate(-1));
2732 __ j(kEqual, slow_path->GetEntryLabel());
2733 // edx:eax <- sign-extended of eax
2734 __ cdq();
2735 // eax = quotient, edx = remainder
2736 __ idivl(second_reg);
2737 } else {
2738 __ cmpq(second_reg, Immediate(-1));
2739 __ j(kEqual, slow_path->GetEntryLabel());
2740 // rdx:rax <- sign-extended of rax
2741 __ cqo();
2742 // rax = quotient, rdx = remainder
2743 __ idivq(second_reg);
2744 }
2745 __ Bind(slow_path->GetExitLabel());
2746 }
Calin Juravlebacfec32014-11-14 15:54:36 +00002747}
2748
Calin Juravle7c4954d2014-10-28 16:57:40 +00002749void LocationsBuilderX86_64::VisitDiv(HDiv* div) {
2750 LocationSummary* locations =
2751 new (GetGraph()->GetArena()) LocationSummary(div, LocationSummary::kNoCall);
2752 switch (div->GetResultType()) {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002753 case Primitive::kPrimInt:
2754 case Primitive::kPrimLong: {
Calin Juravled0d48522014-11-04 16:40:20 +00002755 locations->SetInAt(0, Location::RegisterLocation(RAX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002756 locations->SetInAt(1, Location::RegisterOrConstant(div->InputAt(1)));
Calin Juravled0d48522014-11-04 16:40:20 +00002757 locations->SetOut(Location::SameAsFirstInput());
2758 // Intel uses edx:eax as the dividend.
2759 locations->AddTemp(Location::RegisterLocation(RDX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002760 // We need to save the numerator while we tweak rax and rdx. As we are using imul in a way
2761 // which enforces results to be in RAX and RDX, things are simpler if we use RDX also as
2762 // output and request another temp.
2763 if (div->InputAt(1)->IsConstant()) {
2764 locations->AddTemp(Location::RequiresRegister());
2765 }
Calin Juravled0d48522014-11-04 16:40:20 +00002766 break;
2767 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002768
Calin Juravle7c4954d2014-10-28 16:57:40 +00002769 case Primitive::kPrimFloat:
2770 case Primitive::kPrimDouble: {
2771 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendellf55c3e02015-03-26 21:07:46 -04002772 locations->SetInAt(1, Location::Any());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002773 locations->SetOut(Location::SameAsFirstInput());
2774 break;
2775 }
2776
2777 default:
2778 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2779 }
2780}
2781
2782void InstructionCodeGeneratorX86_64::VisitDiv(HDiv* div) {
2783 LocationSummary* locations = div->GetLocations();
2784 Location first = locations->InAt(0);
2785 Location second = locations->InAt(1);
2786 DCHECK(first.Equals(locations->Out()));
2787
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002788 Primitive::Type type = div->GetResultType();
2789 switch (type) {
2790 case Primitive::kPrimInt:
2791 case Primitive::kPrimLong: {
Calin Juravlebacfec32014-11-14 15:54:36 +00002792 GenerateDivRemIntegral(div);
Calin Juravled0d48522014-11-04 16:40:20 +00002793 break;
2794 }
2795
Calin Juravle7c4954d2014-10-28 16:57:40 +00002796 case Primitive::kPrimFloat: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04002797 if (second.IsFpuRegister()) {
2798 __ divss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2799 } else if (second.IsConstant()) {
2800 __ divss(first.AsFpuRegister<XmmRegister>(),
2801 codegen_->LiteralFloatAddress(second.GetConstant()->AsFloatConstant()->GetValue()));
2802 } else {
2803 DCHECK(second.IsStackSlot());
2804 __ divss(first.AsFpuRegister<XmmRegister>(),
2805 Address(CpuRegister(RSP), second.GetStackIndex()));
2806 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00002807 break;
2808 }
2809
2810 case Primitive::kPrimDouble: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04002811 if (second.IsFpuRegister()) {
2812 __ divsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2813 } else if (second.IsConstant()) {
2814 __ divsd(first.AsFpuRegister<XmmRegister>(),
2815 codegen_->LiteralDoubleAddress(second.GetConstant()->AsDoubleConstant()->GetValue()));
2816 } else {
2817 DCHECK(second.IsDoubleStackSlot());
2818 __ divsd(first.AsFpuRegister<XmmRegister>(),
2819 Address(CpuRegister(RSP), second.GetStackIndex()));
2820 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00002821 break;
2822 }
2823
2824 default:
2825 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2826 }
2827}
2828
Calin Juravlebacfec32014-11-14 15:54:36 +00002829void LocationsBuilderX86_64::VisitRem(HRem* rem) {
Calin Juravled2ec87d2014-12-08 14:24:46 +00002830 Primitive::Type type = rem->GetResultType();
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002831 LocationSummary* locations =
2832 new (GetGraph()->GetArena()) LocationSummary(rem, LocationSummary::kNoCall);
Calin Juravled2ec87d2014-12-08 14:24:46 +00002833
2834 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00002835 case Primitive::kPrimInt:
2836 case Primitive::kPrimLong: {
2837 locations->SetInAt(0, Location::RegisterLocation(RAX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002838 locations->SetInAt(1, Location::RegisterOrConstant(rem->InputAt(1)));
Calin Juravlebacfec32014-11-14 15:54:36 +00002839 // Intel uses rdx:rax as the dividend and puts the remainder in rdx
2840 locations->SetOut(Location::RegisterLocation(RDX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002841 // We need to save the numerator while we tweak eax and edx. As we are using imul in a way
2842 // which enforces results to be in RAX and RDX, things are simpler if we use EAX also as
2843 // output and request another temp.
2844 if (rem->InputAt(1)->IsConstant()) {
2845 locations->AddTemp(Location::RequiresRegister());
2846 }
Calin Juravlebacfec32014-11-14 15:54:36 +00002847 break;
2848 }
2849
2850 case Primitive::kPrimFloat:
2851 case Primitive::kPrimDouble: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002852 locations->SetInAt(0, Location::Any());
2853 locations->SetInAt(1, Location::Any());
2854 locations->SetOut(Location::RequiresFpuRegister());
2855 locations->AddTemp(Location::RegisterLocation(RAX));
Calin Juravlebacfec32014-11-14 15:54:36 +00002856 break;
2857 }
2858
2859 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00002860 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00002861 }
2862}
2863
2864void InstructionCodeGeneratorX86_64::VisitRem(HRem* rem) {
2865 Primitive::Type type = rem->GetResultType();
2866 switch (type) {
2867 case Primitive::kPrimInt:
2868 case Primitive::kPrimLong: {
2869 GenerateDivRemIntegral(rem);
2870 break;
2871 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002872 case Primitive::kPrimFloat:
Calin Juravled2ec87d2014-12-08 14:24:46 +00002873 case Primitive::kPrimDouble: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002874 GenerateRemFP(rem);
Calin Juravled2ec87d2014-12-08 14:24:46 +00002875 break;
2876 }
Calin Juravlebacfec32014-11-14 15:54:36 +00002877 default:
2878 LOG(FATAL) << "Unexpected rem type " << rem->GetResultType();
2879 }
2880}
2881
Calin Juravled0d48522014-11-04 16:40:20 +00002882void LocationsBuilderX86_64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
2883 LocationSummary* locations =
2884 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
2885 locations->SetInAt(0, Location::Any());
2886 if (instruction->HasUses()) {
2887 locations->SetOut(Location::SameAsFirstInput());
2888 }
2889}
2890
2891void InstructionCodeGeneratorX86_64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
2892 SlowPathCodeX86_64* slow_path =
2893 new (GetGraph()->GetArena()) DivZeroCheckSlowPathX86_64(instruction);
2894 codegen_->AddSlowPath(slow_path);
2895
2896 LocationSummary* locations = instruction->GetLocations();
2897 Location value = locations->InAt(0);
2898
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002899 switch (instruction->GetType()) {
2900 case Primitive::kPrimInt: {
2901 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002902 __ testl(value.AsRegister<CpuRegister>(), value.AsRegister<CpuRegister>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002903 __ j(kEqual, slow_path->GetEntryLabel());
2904 } else if (value.IsStackSlot()) {
2905 __ cmpl(Address(CpuRegister(RSP), value.GetStackIndex()), Immediate(0));
2906 __ j(kEqual, slow_path->GetEntryLabel());
2907 } else {
2908 DCHECK(value.IsConstant()) << value;
2909 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
2910 __ jmp(slow_path->GetEntryLabel());
2911 }
2912 }
2913 break;
Calin Juravled0d48522014-11-04 16:40:20 +00002914 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002915 case Primitive::kPrimLong: {
2916 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002917 __ testq(value.AsRegister<CpuRegister>(), value.AsRegister<CpuRegister>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002918 __ j(kEqual, slow_path->GetEntryLabel());
2919 } else if (value.IsDoubleStackSlot()) {
2920 __ cmpq(Address(CpuRegister(RSP), value.GetStackIndex()), Immediate(0));
2921 __ j(kEqual, slow_path->GetEntryLabel());
2922 } else {
2923 DCHECK(value.IsConstant()) << value;
2924 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
2925 __ jmp(slow_path->GetEntryLabel());
2926 }
2927 }
2928 break;
2929 }
2930 default:
2931 LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
Calin Juravled0d48522014-11-04 16:40:20 +00002932 }
Calin Juravled0d48522014-11-04 16:40:20 +00002933}
2934
Calin Juravle9aec02f2014-11-18 23:06:35 +00002935void LocationsBuilderX86_64::HandleShift(HBinaryOperation* op) {
2936 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
2937
2938 LocationSummary* locations =
2939 new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
2940
2941 switch (op->GetResultType()) {
2942 case Primitive::kPrimInt:
2943 case Primitive::kPrimLong: {
2944 locations->SetInAt(0, Location::RequiresRegister());
2945 // The shift count needs to be in CL.
2946 locations->SetInAt(1, Location::ByteRegisterOrConstant(RCX, op->InputAt(1)));
2947 locations->SetOut(Location::SameAsFirstInput());
2948 break;
2949 }
2950 default:
2951 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
2952 }
2953}
2954
2955void InstructionCodeGeneratorX86_64::HandleShift(HBinaryOperation* op) {
2956 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
2957
2958 LocationSummary* locations = op->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002959 CpuRegister first_reg = locations->InAt(0).AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002960 Location second = locations->InAt(1);
2961
2962 switch (op->GetResultType()) {
2963 case Primitive::kPrimInt: {
2964 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002965 CpuRegister second_reg = second.AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002966 if (op->IsShl()) {
2967 __ shll(first_reg, second_reg);
2968 } else if (op->IsShr()) {
2969 __ sarl(first_reg, second_reg);
2970 } else {
2971 __ shrl(first_reg, second_reg);
2972 }
2973 } else {
Nicolas Geoffray486cc192014-12-08 18:00:55 +00002974 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxIntShiftValue);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002975 if (op->IsShl()) {
2976 __ shll(first_reg, imm);
2977 } else if (op->IsShr()) {
2978 __ sarl(first_reg, imm);
2979 } else {
2980 __ shrl(first_reg, imm);
2981 }
2982 }
2983 break;
2984 }
2985 case Primitive::kPrimLong: {
2986 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002987 CpuRegister second_reg = second.AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002988 if (op->IsShl()) {
2989 __ shlq(first_reg, second_reg);
2990 } else if (op->IsShr()) {
2991 __ sarq(first_reg, second_reg);
2992 } else {
2993 __ shrq(first_reg, second_reg);
2994 }
2995 } else {
Nicolas Geoffray486cc192014-12-08 18:00:55 +00002996 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxLongShiftValue);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002997 if (op->IsShl()) {
2998 __ shlq(first_reg, imm);
2999 } else if (op->IsShr()) {
3000 __ sarq(first_reg, imm);
3001 } else {
3002 __ shrq(first_reg, imm);
3003 }
3004 }
3005 break;
3006 }
3007 default:
3008 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
3009 }
3010}
3011
3012void LocationsBuilderX86_64::VisitShl(HShl* shl) {
3013 HandleShift(shl);
3014}
3015
3016void InstructionCodeGeneratorX86_64::VisitShl(HShl* shl) {
3017 HandleShift(shl);
3018}
3019
3020void LocationsBuilderX86_64::VisitShr(HShr* shr) {
3021 HandleShift(shr);
3022}
3023
3024void InstructionCodeGeneratorX86_64::VisitShr(HShr* shr) {
3025 HandleShift(shr);
3026}
3027
3028void LocationsBuilderX86_64::VisitUShr(HUShr* ushr) {
3029 HandleShift(ushr);
3030}
3031
3032void InstructionCodeGeneratorX86_64::VisitUShr(HUShr* ushr) {
3033 HandleShift(ushr);
3034}
3035
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003036void LocationsBuilderX86_64::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003037 LocationSummary* locations =
3038 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01003039 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003040 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Nicolas Geoffray69aa6012015-06-09 10:34:25 +01003041 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003042 locations->SetOut(Location::RegisterLocation(RAX));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003043}
3044
3045void InstructionCodeGeneratorX86_64::VisitNewInstance(HNewInstance* instruction) {
3046 InvokeRuntimeCallingConvention calling_convention;
Mark Mendell92e83bf2015-05-07 11:25:03 -04003047 codegen_->Load64BitValue(CpuRegister(calling_convention.GetRegisterAt(0)),
3048 instruction->GetTypeIndex());
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +00003049 __ gs()->call(
3050 Address::Absolute(GetThreadOffset<kX86_64WordSize>(instruction->GetEntrypoint()), true));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003051
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01003052 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray39468442014-09-02 15:17:15 +01003053 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003054}
3055
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003056void LocationsBuilderX86_64::VisitNewArray(HNewArray* instruction) {
3057 LocationSummary* locations =
3058 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
3059 InvokeRuntimeCallingConvention calling_convention;
3060 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003061 locations->SetOut(Location::RegisterLocation(RAX));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08003062 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray69aa6012015-06-09 10:34:25 +01003063 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003064}
3065
3066void InstructionCodeGeneratorX86_64::VisitNewArray(HNewArray* instruction) {
3067 InvokeRuntimeCallingConvention calling_convention;
Mark Mendell92e83bf2015-05-07 11:25:03 -04003068 codegen_->Load64BitValue(CpuRegister(calling_convention.GetRegisterAt(0)),
3069 instruction->GetTypeIndex());
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003070
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +00003071 __ gs()->call(
3072 Address::Absolute(GetThreadOffset<kX86_64WordSize>(instruction->GetEntrypoint()), true));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003073
3074 DCHECK(!codegen_->IsLeafMethod());
3075 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3076}
3077
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003078void LocationsBuilderX86_64::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003079 LocationSummary* locations =
3080 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003081 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
3082 if (location.IsStackSlot()) {
3083 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
3084 } else if (location.IsDoubleStackSlot()) {
3085 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
3086 }
3087 locations->SetOut(location);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003088}
3089
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01003090void InstructionCodeGeneratorX86_64::VisitParameterValue(
3091 HParameterValue* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003092 // Nothing to do, the parameter is already at its location.
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01003093}
3094
3095void LocationsBuilderX86_64::VisitCurrentMethod(HCurrentMethod* instruction) {
3096 LocationSummary* locations =
3097 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3098 locations->SetOut(Location::RegisterLocation(kMethodRegisterArgument));
3099}
3100
3101void InstructionCodeGeneratorX86_64::VisitCurrentMethod(
3102 HCurrentMethod* instruction ATTRIBUTE_UNUSED) {
3103 // Nothing to do, the method is already at its location.
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003104}
3105
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003106void LocationsBuilderX86_64::VisitNot(HNot* not_) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003107 LocationSummary* locations =
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003108 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003109 locations->SetInAt(0, Location::RequiresRegister());
3110 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003111}
3112
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003113void InstructionCodeGeneratorX86_64::VisitNot(HNot* not_) {
3114 LocationSummary* locations = not_->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003115 DCHECK_EQ(locations->InAt(0).AsRegister<CpuRegister>().AsRegister(),
3116 locations->Out().AsRegister<CpuRegister>().AsRegister());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003117 Location out = locations->Out();
Nicolas Geoffrayd8ef2e92015-02-24 16:02:06 +00003118 switch (not_->GetResultType()) {
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003119 case Primitive::kPrimInt:
Roland Levillain271ab9c2014-11-27 15:23:57 +00003120 __ notl(out.AsRegister<CpuRegister>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003121 break;
3122
3123 case Primitive::kPrimLong:
Roland Levillain271ab9c2014-11-27 15:23:57 +00003124 __ notq(out.AsRegister<CpuRegister>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003125 break;
3126
3127 default:
3128 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
3129 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003130}
3131
David Brazdil66d126e2015-04-03 16:02:44 +01003132void LocationsBuilderX86_64::VisitBooleanNot(HBooleanNot* bool_not) {
3133 LocationSummary* locations =
3134 new (GetGraph()->GetArena()) LocationSummary(bool_not, LocationSummary::kNoCall);
3135 locations->SetInAt(0, Location::RequiresRegister());
3136 locations->SetOut(Location::SameAsFirstInput());
3137}
3138
3139void InstructionCodeGeneratorX86_64::VisitBooleanNot(HBooleanNot* bool_not) {
David Brazdil66d126e2015-04-03 16:02:44 +01003140 LocationSummary* locations = bool_not->GetLocations();
3141 DCHECK_EQ(locations->InAt(0).AsRegister<CpuRegister>().AsRegister(),
3142 locations->Out().AsRegister<CpuRegister>().AsRegister());
3143 Location out = locations->Out();
3144 __ xorl(out.AsRegister<CpuRegister>(), Immediate(1));
3145}
3146
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003147void LocationsBuilderX86_64::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003148 LocationSummary* locations =
3149 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003150 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
3151 locations->SetInAt(i, Location::Any());
3152 }
3153 locations->SetOut(Location::Any());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003154}
3155
3156void InstructionCodeGeneratorX86_64::VisitPhi(HPhi* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003157 UNUSED(instruction);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003158 LOG(FATAL) << "Unimplemented";
3159}
3160
Calin Juravle52c48962014-12-16 17:02:57 +00003161void InstructionCodeGeneratorX86_64::GenerateMemoryBarrier(MemBarrierKind kind) {
3162 /*
3163 * According to the JSR-133 Cookbook, for x86 only StoreLoad/AnyAny barriers need memory fence.
3164 * All other barriers (LoadAny, AnyStore, StoreStore) are nops due to the x86 memory model.
3165 * For those cases, all we need to ensure is that there is a scheduling barrier in place.
3166 */
3167 switch (kind) {
3168 case MemBarrierKind::kAnyAny: {
3169 __ mfence();
3170 break;
3171 }
3172 case MemBarrierKind::kAnyStore:
3173 case MemBarrierKind::kLoadAny:
3174 case MemBarrierKind::kStoreStore: {
3175 // nop
3176 break;
3177 }
3178 default:
3179 LOG(FATAL) << "Unexpected memory barier " << kind;
3180 }
3181}
3182
3183void LocationsBuilderX86_64::HandleFieldGet(HInstruction* instruction) {
3184 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
3185
Nicolas Geoffray39468442014-09-02 15:17:15 +01003186 LocationSummary* locations =
3187 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Calin Juravle52c48962014-12-16 17:02:57 +00003188 locations->SetInAt(0, Location::RequiresRegister());
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003189 if (Primitive::IsFloatingPointType(instruction->GetType())) {
3190 locations->SetOut(Location::RequiresFpuRegister());
3191 } else {
3192 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3193 }
Calin Juravle52c48962014-12-16 17:02:57 +00003194}
3195
3196void InstructionCodeGeneratorX86_64::HandleFieldGet(HInstruction* instruction,
3197 const FieldInfo& field_info) {
3198 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
3199
3200 LocationSummary* locations = instruction->GetLocations();
3201 CpuRegister base = locations->InAt(0).AsRegister<CpuRegister>();
3202 Location out = locations->Out();
3203 bool is_volatile = field_info.IsVolatile();
3204 Primitive::Type field_type = field_info.GetFieldType();
3205 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
3206
3207 switch (field_type) {
3208 case Primitive::kPrimBoolean: {
3209 __ movzxb(out.AsRegister<CpuRegister>(), Address(base, offset));
3210 break;
3211 }
3212
3213 case Primitive::kPrimByte: {
3214 __ movsxb(out.AsRegister<CpuRegister>(), Address(base, offset));
3215 break;
3216 }
3217
3218 case Primitive::kPrimShort: {
3219 __ movsxw(out.AsRegister<CpuRegister>(), Address(base, offset));
3220 break;
3221 }
3222
3223 case Primitive::kPrimChar: {
3224 __ movzxw(out.AsRegister<CpuRegister>(), Address(base, offset));
3225 break;
3226 }
3227
3228 case Primitive::kPrimInt:
3229 case Primitive::kPrimNot: {
3230 __ movl(out.AsRegister<CpuRegister>(), Address(base, offset));
3231 break;
3232 }
3233
3234 case Primitive::kPrimLong: {
3235 __ movq(out.AsRegister<CpuRegister>(), Address(base, offset));
3236 break;
3237 }
3238
3239 case Primitive::kPrimFloat: {
3240 __ movss(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
3241 break;
3242 }
3243
3244 case Primitive::kPrimDouble: {
3245 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
3246 break;
3247 }
3248
3249 case Primitive::kPrimVoid:
3250 LOG(FATAL) << "Unreachable type " << field_type;
3251 UNREACHABLE();
3252 }
3253
Calin Juravle77520bc2015-01-12 18:45:46 +00003254 codegen_->MaybeRecordImplicitNullCheck(instruction);
3255
Calin Juravle52c48962014-12-16 17:02:57 +00003256 if (is_volatile) {
3257 GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
3258 }
3259}
3260
3261void LocationsBuilderX86_64::HandleFieldSet(HInstruction* instruction,
3262 const FieldInfo& field_info) {
3263 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3264
3265 LocationSummary* locations =
3266 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003267 bool needs_write_barrier =
Calin Juravle52c48962014-12-16 17:02:57 +00003268 CodeGenerator::StoreNeedsWriteBarrier(field_info.GetFieldType(), instruction->InputAt(1));
3269
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003270 locations->SetInAt(0, Location::RequiresRegister());
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003271 if (Primitive::IsFloatingPointType(instruction->InputAt(1)->GetType())) {
3272 locations->SetInAt(1, Location::RequiresFpuRegister());
3273 } else {
Mark Mendell40741f32015-04-20 22:10:34 -04003274 locations->SetInAt(1, Location::RegisterOrInt32LongConstant(instruction->InputAt(1)));
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003275 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003276 if (needs_write_barrier) {
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01003277 // Temporary registers for the write barrier.
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003278 locations->AddTemp(Location::RequiresRegister());
3279 locations->AddTemp(Location::RequiresRegister());
3280 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003281}
3282
Calin Juravle52c48962014-12-16 17:02:57 +00003283void InstructionCodeGeneratorX86_64::HandleFieldSet(HInstruction* instruction,
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003284 const FieldInfo& field_info,
3285 bool value_can_be_null) {
Calin Juravle52c48962014-12-16 17:02:57 +00003286 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3287
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003288 LocationSummary* locations = instruction->GetLocations();
Calin Juravle52c48962014-12-16 17:02:57 +00003289 CpuRegister base = locations->InAt(0).AsRegister<CpuRegister>();
3290 Location value = locations->InAt(1);
3291 bool is_volatile = field_info.IsVolatile();
3292 Primitive::Type field_type = field_info.GetFieldType();
3293 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
3294
3295 if (is_volatile) {
3296 GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
3297 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003298
3299 switch (field_type) {
3300 case Primitive::kPrimBoolean:
3301 case Primitive::kPrimByte: {
Mark Mendell40741f32015-04-20 22:10:34 -04003302 if (value.IsConstant()) {
3303 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
3304 __ movb(Address(base, offset), Immediate(v));
3305 } else {
3306 __ movb(Address(base, offset), value.AsRegister<CpuRegister>());
3307 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003308 break;
3309 }
3310
3311 case Primitive::kPrimShort:
3312 case Primitive::kPrimChar: {
Mark Mendell40741f32015-04-20 22:10:34 -04003313 if (value.IsConstant()) {
3314 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
3315 __ movw(Address(base, offset), Immediate(v));
3316 } else {
3317 __ movw(Address(base, offset), value.AsRegister<CpuRegister>());
3318 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003319 break;
3320 }
3321
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003322 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003323 case Primitive::kPrimNot: {
Mark Mendell40741f32015-04-20 22:10:34 -04003324 if (value.IsConstant()) {
3325 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
3326 __ movw(Address(base, offset), Immediate(v));
3327 } else {
3328 __ movl(Address(base, offset), value.AsRegister<CpuRegister>());
3329 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003330 break;
3331 }
3332
3333 case Primitive::kPrimLong: {
Mark Mendell40741f32015-04-20 22:10:34 -04003334 if (value.IsConstant()) {
3335 int64_t v = value.GetConstant()->AsLongConstant()->GetValue();
3336 DCHECK(IsInt<32>(v));
3337 int32_t v_32 = v;
3338 __ movq(Address(base, offset), Immediate(v_32));
3339 } else {
3340 __ movq(Address(base, offset), value.AsRegister<CpuRegister>());
3341 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003342 break;
3343 }
3344
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003345 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00003346 __ movss(Address(base, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003347 break;
3348 }
3349
3350 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00003351 __ movsd(Address(base, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003352 break;
3353 }
3354
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003355 case Primitive::kPrimVoid:
3356 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003357 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003358 }
Calin Juravle52c48962014-12-16 17:02:57 +00003359
Calin Juravle77520bc2015-01-12 18:45:46 +00003360 codegen_->MaybeRecordImplicitNullCheck(instruction);
3361
3362 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
3363 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
3364 CpuRegister card = locations->GetTemp(1).AsRegister<CpuRegister>();
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003365 codegen_->MarkGCCard(temp, card, base, value.AsRegister<CpuRegister>(), value_can_be_null);
Calin Juravle77520bc2015-01-12 18:45:46 +00003366 }
3367
Calin Juravle52c48962014-12-16 17:02:57 +00003368 if (is_volatile) {
3369 GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
3370 }
3371}
3372
3373void LocationsBuilderX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
3374 HandleFieldSet(instruction, instruction->GetFieldInfo());
3375}
3376
3377void InstructionCodeGeneratorX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003378 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003379}
3380
3381void LocationsBuilderX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Calin Juravle52c48962014-12-16 17:02:57 +00003382 HandleFieldGet(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003383}
3384
3385void InstructionCodeGeneratorX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Calin Juravle52c48962014-12-16 17:02:57 +00003386 HandleFieldGet(instruction, instruction->GetFieldInfo());
3387}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003388
Calin Juravle52c48962014-12-16 17:02:57 +00003389void LocationsBuilderX86_64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
3390 HandleFieldGet(instruction);
3391}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003392
Calin Juravle52c48962014-12-16 17:02:57 +00003393void InstructionCodeGeneratorX86_64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
3394 HandleFieldGet(instruction, instruction->GetFieldInfo());
3395}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003396
Calin Juravle52c48962014-12-16 17:02:57 +00003397void LocationsBuilderX86_64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
3398 HandleFieldSet(instruction, instruction->GetFieldInfo());
3399}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003400
Calin Juravle52c48962014-12-16 17:02:57 +00003401void InstructionCodeGeneratorX86_64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003402 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003403}
3404
3405void LocationsBuilderX86_64::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003406 LocationSummary* locations =
3407 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003408 Location loc = codegen_->GetCompilerOptions().GetImplicitNullChecks()
3409 ? Location::RequiresRegister()
3410 : Location::Any();
3411 locations->SetInAt(0, loc);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003412 if (instruction->HasUses()) {
3413 locations->SetOut(Location::SameAsFirstInput());
3414 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003415}
3416
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003417void InstructionCodeGeneratorX86_64::GenerateImplicitNullCheck(HNullCheck* instruction) {
Calin Juravle77520bc2015-01-12 18:45:46 +00003418 if (codegen_->CanMoveNullCheckToUser(instruction)) {
3419 return;
3420 }
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003421 LocationSummary* locations = instruction->GetLocations();
3422 Location obj = locations->InAt(0);
3423
3424 __ testl(CpuRegister(RAX), Address(obj.AsRegister<CpuRegister>(), 0));
3425 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3426}
3427
3428void InstructionCodeGeneratorX86_64::GenerateExplicitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +01003429 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathX86_64(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003430 codegen_->AddSlowPath(slow_path);
3431
3432 LocationSummary* locations = instruction->GetLocations();
3433 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003434
3435 if (obj.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00003436 __ testl(obj.AsRegister<CpuRegister>(), obj.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003437 } else if (obj.IsStackSlot()) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003438 __ cmpl(Address(CpuRegister(RSP), obj.GetStackIndex()), Immediate(0));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003439 } else {
3440 DCHECK(obj.IsConstant()) << obj;
3441 DCHECK_EQ(obj.GetConstant()->AsIntConstant()->GetValue(), 0);
3442 __ jmp(slow_path->GetEntryLabel());
3443 return;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003444 }
3445 __ j(kEqual, slow_path->GetEntryLabel());
3446}
3447
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003448void InstructionCodeGeneratorX86_64::VisitNullCheck(HNullCheck* instruction) {
3449 if (codegen_->GetCompilerOptions().GetImplicitNullChecks()) {
3450 GenerateImplicitNullCheck(instruction);
3451 } else {
3452 GenerateExplicitNullCheck(instruction);
3453 }
3454}
3455
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003456void LocationsBuilderX86_64::VisitArrayGet(HArrayGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003457 LocationSummary* locations =
3458 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003459 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell40741f32015-04-20 22:10:34 -04003460 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003461 if (Primitive::IsFloatingPointType(instruction->GetType())) {
3462 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
3463 } else {
3464 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3465 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003466}
3467
3468void InstructionCodeGeneratorX86_64::VisitArrayGet(HArrayGet* instruction) {
3469 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003470 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003471 Location index = locations->InAt(1);
3472
3473 switch (instruction->GetType()) {
3474 case Primitive::kPrimBoolean: {
3475 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003476 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003477 if (index.IsConstant()) {
3478 __ movzxb(out, Address(obj,
3479 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
3480 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003481 __ movzxb(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003482 }
3483 break;
3484 }
3485
3486 case Primitive::kPrimByte: {
3487 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003488 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003489 if (index.IsConstant()) {
3490 __ movsxb(out, Address(obj,
3491 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
3492 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003493 __ movsxb(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003494 }
3495 break;
3496 }
3497
3498 case Primitive::kPrimShort: {
3499 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003500 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003501 if (index.IsConstant()) {
3502 __ movsxw(out, Address(obj,
3503 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
3504 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003505 __ movsxw(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003506 }
3507 break;
3508 }
3509
3510 case Primitive::kPrimChar: {
3511 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003512 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003513 if (index.IsConstant()) {
3514 __ movzxw(out, Address(obj,
3515 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
3516 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003517 __ movzxw(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003518 }
3519 break;
3520 }
3521
3522 case Primitive::kPrimInt:
3523 case Primitive::kPrimNot: {
3524 DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t));
3525 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003526 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003527 if (index.IsConstant()) {
3528 __ movl(out, Address(obj,
3529 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
3530 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003531 __ movl(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003532 }
3533 break;
3534 }
3535
3536 case Primitive::kPrimLong: {
3537 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003538 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003539 if (index.IsConstant()) {
3540 __ movq(out, Address(obj,
3541 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
3542 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003543 __ movq(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003544 }
3545 break;
3546 }
3547
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003548 case Primitive::kPrimFloat: {
3549 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003550 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003551 if (index.IsConstant()) {
3552 __ movss(out, Address(obj,
3553 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
3554 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003555 __ movss(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003556 }
3557 break;
3558 }
3559
3560 case Primitive::kPrimDouble: {
3561 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003562 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003563 if (index.IsConstant()) {
3564 __ movsd(out, Address(obj,
3565 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
3566 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003567 __ movsd(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003568 }
3569 break;
3570 }
3571
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003572 case Primitive::kPrimVoid:
3573 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07003574 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003575 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003576 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003577}
3578
3579void LocationsBuilderX86_64::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003580 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003581
3582 bool needs_write_barrier =
3583 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
3584 bool needs_runtime_call = instruction->NeedsTypeCheck();
3585
Nicolas Geoffray39468442014-09-02 15:17:15 +01003586 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003587 instruction, needs_runtime_call ? LocationSummary::kCall : LocationSummary::kNoCall);
3588 if (needs_runtime_call) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003589 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003590 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3591 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
3592 locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003593 } else {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003594 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01003595 locations->SetInAt(
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003596 1, Location::RegisterOrConstant(instruction->InputAt(1)));
3597 locations->SetInAt(2, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003598 if (value_type == Primitive::kPrimLong) {
Mark Mendell40741f32015-04-20 22:10:34 -04003599 locations->SetInAt(2, Location::RegisterOrInt32LongConstant(instruction->InputAt(2)));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003600 } else if (value_type == Primitive::kPrimFloat || value_type == Primitive::kPrimDouble) {
3601 locations->SetInAt(2, Location::RequiresFpuRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003602 } else {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003603 locations->SetInAt(2, Location::RegisterOrConstant(instruction->InputAt(2)));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003604 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003605
3606 if (needs_write_barrier) {
3607 // Temporary registers for the write barrier.
3608 locations->AddTemp(Location::RequiresRegister());
3609 locations->AddTemp(Location::RequiresRegister());
3610 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003611 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003612}
3613
3614void InstructionCodeGeneratorX86_64::VisitArraySet(HArraySet* instruction) {
3615 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003616 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003617 Location index = locations->InAt(1);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003618 Location value = locations->InAt(2);
Nicolas Geoffray39468442014-09-02 15:17:15 +01003619 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003620 bool needs_runtime_call = locations->WillCall();
3621 bool needs_write_barrier =
3622 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003623
3624 switch (value_type) {
3625 case Primitive::kPrimBoolean:
3626 case Primitive::kPrimByte: {
3627 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003628 if (index.IsConstant()) {
3629 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003630 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003631 __ movb(Address(obj, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003632 } else {
Roland Levillain199f3362014-11-27 17:15:16 +00003633 __ movb(Address(obj, offset),
3634 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003635 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003636 } else {
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003637 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003638 __ movb(Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset),
3639 value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003640 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003641 __ movb(Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003642 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3643 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003644 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003645 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003646 break;
3647 }
3648
3649 case Primitive::kPrimShort:
3650 case Primitive::kPrimChar: {
3651 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003652 if (index.IsConstant()) {
3653 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003654 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003655 __ movw(Address(obj, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003656 } else {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003657 DCHECK(value.IsConstant()) << value;
Roland Levillain199f3362014-11-27 17:15:16 +00003658 __ movw(Address(obj, offset),
3659 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003660 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003661 } else {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003662 DCHECK(index.IsRegister()) << index;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003663 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003664 __ movw(Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset),
3665 value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003666 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003667 DCHECK(value.IsConstant()) << value;
Roland Levillain271ab9c2014-11-27 15:23:57 +00003668 __ movw(Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003669 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3670 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003671 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003672 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003673 break;
3674 }
3675
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003676 case Primitive::kPrimInt:
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003677 case Primitive::kPrimNot: {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003678 if (!needs_runtime_call) {
3679 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
3680 if (index.IsConstant()) {
3681 size_t offset =
3682 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
3683 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003684 __ movl(Address(obj, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003685 } else {
3686 DCHECK(value.IsConstant()) << value;
Mark Mendell40741f32015-04-20 22:10:34 -04003687 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
3688 __ movl(Address(obj, offset), Immediate(v));
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003689 }
3690 } else {
3691 DCHECK(index.IsRegister()) << index;
3692 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003693 __ movl(Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset),
3694 value.AsRegister<CpuRegister>());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003695 } else {
3696 DCHECK(value.IsConstant()) << value;
Mark Mendell40741f32015-04-20 22:10:34 -04003697 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003698 __ movl(Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset),
Mark Mendell40741f32015-04-20 22:10:34 -04003699 Immediate(v));
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003700 }
3701 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003702 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003703 if (needs_write_barrier) {
3704 DCHECK_EQ(value_type, Primitive::kPrimNot);
Roland Levillain271ab9c2014-11-27 15:23:57 +00003705 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
3706 CpuRegister card = locations->GetTemp(1).AsRegister<CpuRegister>();
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003707 codegen_->MarkGCCard(
3708 temp, card, obj, value.AsRegister<CpuRegister>(), instruction->GetValueCanBeNull());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003709 }
3710 } else {
3711 DCHECK_EQ(value_type, Primitive::kPrimNot);
Roland Levillain199f3362014-11-27 17:15:16 +00003712 __ gs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pAputObject),
3713 true));
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003714 DCHECK(!codegen_->IsLeafMethod());
3715 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3716 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003717 break;
3718 }
3719
3720 case Primitive::kPrimLong: {
3721 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003722 if (index.IsConstant()) {
3723 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Mark Mendell40741f32015-04-20 22:10:34 -04003724 if (value.IsRegister()) {
3725 __ movq(Address(obj, offset), value.AsRegister<CpuRegister>());
3726 } else {
3727 int64_t v = value.GetConstant()->AsLongConstant()->GetValue();
3728 DCHECK(IsInt<32>(v));
3729 int32_t v_32 = v;
3730 __ movq(Address(obj, offset), Immediate(v_32));
3731 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003732 } else {
Mark Mendell40741f32015-04-20 22:10:34 -04003733 if (value.IsRegister()) {
3734 __ movq(Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset),
3735 value.AsRegister<CpuRegister>());
3736 } else {
3737 int64_t v = value.GetConstant()->AsLongConstant()->GetValue();
3738 DCHECK(IsInt<32>(v));
3739 int32_t v_32 = v;
3740 __ movq(Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset),
3741 Immediate(v_32));
3742 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003743 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003744 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003745 break;
3746 }
3747
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003748 case Primitive::kPrimFloat: {
3749 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
3750 if (index.IsConstant()) {
3751 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
3752 DCHECK(value.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003753 __ movss(Address(obj, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003754 } else {
3755 DCHECK(value.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003756 __ movss(Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset),
3757 value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003758 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003759 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003760 break;
3761 }
3762
3763 case Primitive::kPrimDouble: {
3764 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
3765 if (index.IsConstant()) {
3766 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
3767 DCHECK(value.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003768 __ movsd(Address(obj, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003769 } else {
3770 DCHECK(value.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003771 __ movsd(Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset),
3772 value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003773 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003774 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003775 break;
3776 }
3777
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003778 case Primitive::kPrimVoid:
3779 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07003780 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003781 }
3782}
3783
3784void LocationsBuilderX86_64::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003785 LocationSummary* locations =
3786 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003787 locations->SetInAt(0, Location::RequiresRegister());
3788 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003789}
3790
3791void InstructionCodeGeneratorX86_64::VisitArrayLength(HArrayLength* instruction) {
3792 LocationSummary* locations = instruction->GetLocations();
3793 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003794 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
3795 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003796 __ movl(out, Address(obj, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00003797 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003798}
3799
3800void LocationsBuilderX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003801 LocationSummary* locations =
3802 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Mark Mendellf60c90b2015-03-04 15:12:59 -05003803 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
Mark Mendell99dbd682015-04-22 16:18:52 -04003804 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003805 if (instruction->HasUses()) {
3806 locations->SetOut(Location::SameAsFirstInput());
3807 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003808}
3809
3810void InstructionCodeGeneratorX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
3811 LocationSummary* locations = instruction->GetLocations();
Mark Mendellf60c90b2015-03-04 15:12:59 -05003812 Location index_loc = locations->InAt(0);
3813 Location length_loc = locations->InAt(1);
3814 SlowPathCodeX86_64* slow_path =
3815 new (GetGraph()->GetArena()) BoundsCheckSlowPathX86_64(instruction, index_loc, length_loc);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003816
Mark Mendell99dbd682015-04-22 16:18:52 -04003817 if (length_loc.IsConstant()) {
3818 int32_t length = CodeGenerator::GetInt32ValueOf(length_loc.GetConstant());
3819 if (index_loc.IsConstant()) {
3820 // BCE will remove the bounds check if we are guarenteed to pass.
3821 int32_t index = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
3822 if (index < 0 || index >= length) {
3823 codegen_->AddSlowPath(slow_path);
3824 __ jmp(slow_path->GetEntryLabel());
3825 } else {
3826 // Some optimization after BCE may have generated this, and we should not
3827 // generate a bounds check if it is a valid range.
3828 }
3829 return;
3830 }
3831
3832 // We have to reverse the jump condition because the length is the constant.
3833 CpuRegister index_reg = index_loc.AsRegister<CpuRegister>();
3834 __ cmpl(index_reg, Immediate(length));
3835 codegen_->AddSlowPath(slow_path);
3836 __ j(kAboveEqual, slow_path->GetEntryLabel());
Mark Mendellf60c90b2015-03-04 15:12:59 -05003837 } else {
Mark Mendell99dbd682015-04-22 16:18:52 -04003838 CpuRegister length = length_loc.AsRegister<CpuRegister>();
3839 if (index_loc.IsConstant()) {
3840 int32_t value = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
3841 __ cmpl(length, Immediate(value));
3842 } else {
3843 __ cmpl(length, index_loc.AsRegister<CpuRegister>());
3844 }
3845 codegen_->AddSlowPath(slow_path);
3846 __ j(kBelowEqual, slow_path->GetEntryLabel());
Mark Mendellf60c90b2015-03-04 15:12:59 -05003847 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003848}
3849
3850void CodeGeneratorX86_64::MarkGCCard(CpuRegister temp,
3851 CpuRegister card,
3852 CpuRegister object,
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003853 CpuRegister value,
3854 bool value_can_be_null) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003855 Label is_null;
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003856 if (value_can_be_null) {
3857 __ testl(value, value);
3858 __ j(kEqual, &is_null);
3859 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003860 __ gs()->movq(card, Address::Absolute(
3861 Thread::CardTableOffset<kX86_64WordSize>().Int32Value(), true));
3862 __ movq(temp, object);
3863 __ shrq(temp, Immediate(gc::accounting::CardTable::kCardShift));
3864 __ movb(Address(temp, card, TIMES_1, 0), card);
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003865 if (value_can_be_null) {
3866 __ Bind(&is_null);
3867 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003868}
3869
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003870void LocationsBuilderX86_64::VisitTemporary(HTemporary* temp) {
3871 temp->SetLocations(nullptr);
3872}
3873
3874void InstructionCodeGeneratorX86_64::VisitTemporary(HTemporary* temp) {
3875 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003876 UNUSED(temp);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003877}
3878
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003879void LocationsBuilderX86_64::VisitParallelMove(HParallelMove* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003880 UNUSED(instruction);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003881 LOG(FATAL) << "Unimplemented";
3882}
3883
3884void InstructionCodeGeneratorX86_64::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003885 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
3886}
3887
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003888void LocationsBuilderX86_64::VisitSuspendCheck(HSuspendCheck* instruction) {
3889 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
3890}
3891
3892void InstructionCodeGeneratorX86_64::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003893 HBasicBlock* block = instruction->GetBlock();
3894 if (block->GetLoopInformation() != nullptr) {
3895 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
3896 // The back edge will generate the suspend check.
3897 return;
3898 }
3899 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
3900 // The goto will generate the suspend check.
3901 return;
3902 }
3903 GenerateSuspendCheck(instruction, nullptr);
3904}
3905
3906void InstructionCodeGeneratorX86_64::GenerateSuspendCheck(HSuspendCheck* instruction,
3907 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003908 SuspendCheckSlowPathX86_64* slow_path =
Nicolas Geoffraydb216f42015-05-05 17:02:20 +01003909 down_cast<SuspendCheckSlowPathX86_64*>(instruction->GetSlowPath());
3910 if (slow_path == nullptr) {
3911 slow_path = new (GetGraph()->GetArena()) SuspendCheckSlowPathX86_64(instruction, successor);
3912 instruction->SetSlowPath(slow_path);
3913 codegen_->AddSlowPath(slow_path);
3914 if (successor != nullptr) {
3915 DCHECK(successor->IsLoopHeader());
3916 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(instruction);
3917 }
3918 } else {
3919 DCHECK_EQ(slow_path->GetSuccessor(), successor);
3920 }
3921
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003922 __ gs()->cmpw(Address::Absolute(
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003923 Thread::ThreadFlagsOffset<kX86_64WordSize>().Int32Value(), true), Immediate(0));
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003924 if (successor == nullptr) {
3925 __ j(kNotEqual, slow_path->GetEntryLabel());
3926 __ Bind(slow_path->GetReturnLabel());
3927 } else {
3928 __ j(kEqual, codegen_->GetLabelOf(successor));
3929 __ jmp(slow_path->GetEntryLabel());
3930 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003931}
3932
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003933X86_64Assembler* ParallelMoveResolverX86_64::GetAssembler() const {
3934 return codegen_->GetAssembler();
3935}
3936
3937void ParallelMoveResolverX86_64::EmitMove(size_t index) {
3938 MoveOperands* move = moves_.Get(index);
3939 Location source = move->GetSource();
3940 Location destination = move->GetDestination();
3941
3942 if (source.IsRegister()) {
3943 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003944 __ movq(destination.AsRegister<CpuRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003945 } else if (destination.IsStackSlot()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003946 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00003947 source.AsRegister<CpuRegister>());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003948 } else {
3949 DCHECK(destination.IsDoubleStackSlot());
3950 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00003951 source.AsRegister<CpuRegister>());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003952 }
3953 } else if (source.IsStackSlot()) {
3954 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003955 __ movl(destination.AsRegister<CpuRegister>(),
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003956 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003957 } else if (destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003958 __ movss(destination.AsFpuRegister<XmmRegister>(),
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003959 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003960 } else {
3961 DCHECK(destination.IsStackSlot());
3962 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
3963 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
3964 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003965 } else if (source.IsDoubleStackSlot()) {
3966 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003967 __ movq(destination.AsRegister<CpuRegister>(),
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003968 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003969 } else if (destination.IsFpuRegister()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003970 __ movsd(destination.AsFpuRegister<XmmRegister>(),
3971 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003972 } else {
Nicolas Geoffrayc8147a72014-10-21 16:06:20 +01003973 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003974 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
3975 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
3976 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003977 } else if (source.IsConstant()) {
3978 HConstant* constant = source.GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00003979 if (constant->IsIntConstant() || constant->IsNullConstant()) {
3980 int32_t value = CodeGenerator::GetInt32ValueOf(constant);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003981 if (destination.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00003982 if (value == 0) {
3983 __ xorl(destination.AsRegister<CpuRegister>(), destination.AsRegister<CpuRegister>());
3984 } else {
3985 __ movl(destination.AsRegister<CpuRegister>(), Immediate(value));
3986 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003987 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003988 DCHECK(destination.IsStackSlot()) << destination;
Nicolas Geoffray748f1402015-01-27 08:17:54 +00003989 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), Immediate(value));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003990 }
3991 } else if (constant->IsLongConstant()) {
3992 int64_t value = constant->AsLongConstant()->GetValue();
3993 if (destination.IsRegister()) {
Mark Mendell92e83bf2015-05-07 11:25:03 -04003994 codegen_->Load64BitValue(destination.AsRegister<CpuRegister>(), value);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003995 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003996 DCHECK(destination.IsDoubleStackSlot()) << destination;
Mark Mendell92e83bf2015-05-07 11:25:03 -04003997 codegen_->Load64BitValue(CpuRegister(TMP), value);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003998 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
3999 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004000 } else if (constant->IsFloatConstant()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004001 float fp_value = constant->AsFloatConstant()->GetValue();
Roland Levillainda4d79b2015-03-24 14:36:11 +00004002 int32_t value = bit_cast<int32_t, float>(fp_value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004003 if (destination.IsFpuRegister()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004004 XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
4005 if (value == 0) {
4006 // easy FP 0.0.
4007 __ xorps(dest, dest);
4008 } else {
Mark Mendell92e83bf2015-05-07 11:25:03 -04004009 __ movss(dest, codegen_->LiteralFloatAddress(fp_value));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004010 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004011 } else {
4012 DCHECK(destination.IsStackSlot()) << destination;
Mark Mendell92e83bf2015-05-07 11:25:03 -04004013 Immediate imm(value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004014 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), imm);
4015 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004016 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004017 DCHECK(constant->IsDoubleConstant()) << constant->DebugName();
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004018 double fp_value = constant->AsDoubleConstant()->GetValue();
Roland Levillainda4d79b2015-03-24 14:36:11 +00004019 int64_t value = bit_cast<int64_t, double>(fp_value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004020 if (destination.IsFpuRegister()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004021 XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
4022 if (value == 0) {
4023 __ xorpd(dest, dest);
4024 } else {
Mark Mendell92e83bf2015-05-07 11:25:03 -04004025 __ movsd(dest, codegen_->LiteralDoubleAddress(fp_value));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004026 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004027 } else {
4028 DCHECK(destination.IsDoubleStackSlot()) << destination;
Mark Mendell92e83bf2015-05-07 11:25:03 -04004029 codegen_->Load64BitValue(CpuRegister(TMP), value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004030 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
4031 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004032 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004033 } else if (source.IsFpuRegister()) {
4034 if (destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004035 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004036 } else if (destination.IsStackSlot()) {
4037 __ movss(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00004038 source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004039 } else {
Nicolas Geoffray31596742014-11-24 15:28:45 +00004040 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004041 __ movsd(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00004042 source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004043 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004044 }
4045}
4046
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004047void ParallelMoveResolverX86_64::Exchange32(CpuRegister reg, int mem) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004048 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004049 __ movl(Address(CpuRegister(RSP), mem), reg);
4050 __ movl(reg, CpuRegister(TMP));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004051}
4052
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004053void ParallelMoveResolverX86_64::Exchange32(int mem1, int mem2) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004054 ScratchRegisterScope ensure_scratch(
4055 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
4056
4057 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
4058 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
4059 __ movl(CpuRegister(ensure_scratch.GetRegister()),
4060 Address(CpuRegister(RSP), mem2 + stack_offset));
4061 __ movl(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
4062 __ movl(Address(CpuRegister(RSP), mem1 + stack_offset),
4063 CpuRegister(ensure_scratch.GetRegister()));
4064}
4065
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004066void ParallelMoveResolverX86_64::Exchange64(CpuRegister reg, int mem) {
4067 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
4068 __ movq(Address(CpuRegister(RSP), mem), reg);
4069 __ movq(reg, CpuRegister(TMP));
4070}
4071
4072void ParallelMoveResolverX86_64::Exchange64(int mem1, int mem2) {
4073 ScratchRegisterScope ensure_scratch(
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004074 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004075
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004076 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
4077 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
4078 __ movq(CpuRegister(ensure_scratch.GetRegister()),
4079 Address(CpuRegister(RSP), mem2 + stack_offset));
4080 __ movq(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
4081 __ movq(Address(CpuRegister(RSP), mem1 + stack_offset),
4082 CpuRegister(ensure_scratch.GetRegister()));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004083}
4084
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004085void ParallelMoveResolverX86_64::Exchange32(XmmRegister reg, int mem) {
4086 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
4087 __ movss(Address(CpuRegister(RSP), mem), reg);
4088 __ movd(reg, CpuRegister(TMP));
4089}
4090
4091void ParallelMoveResolverX86_64::Exchange64(XmmRegister reg, int mem) {
4092 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
4093 __ movsd(Address(CpuRegister(RSP), mem), reg);
4094 __ movd(reg, CpuRegister(TMP));
4095}
4096
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004097void ParallelMoveResolverX86_64::EmitSwap(size_t index) {
4098 MoveOperands* move = moves_.Get(index);
4099 Location source = move->GetSource();
4100 Location destination = move->GetDestination();
4101
4102 if (source.IsRegister() && destination.IsRegister()) {
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004103 __ xchgq(destination.AsRegister<CpuRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004104 } else if (source.IsRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004105 Exchange32(source.AsRegister<CpuRegister>(), destination.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004106 } else if (source.IsStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004107 Exchange32(destination.AsRegister<CpuRegister>(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004108 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004109 Exchange32(destination.GetStackIndex(), source.GetStackIndex());
4110 } else if (source.IsRegister() && destination.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004111 Exchange64(source.AsRegister<CpuRegister>(), destination.GetStackIndex());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004112 } else if (source.IsDoubleStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004113 Exchange64(destination.AsRegister<CpuRegister>(), source.GetStackIndex());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004114 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
4115 Exchange64(destination.GetStackIndex(), source.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004116 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004117 __ movd(CpuRegister(TMP), source.AsFpuRegister<XmmRegister>());
4118 __ movaps(source.AsFpuRegister<XmmRegister>(), destination.AsFpuRegister<XmmRegister>());
4119 __ movd(destination.AsFpuRegister<XmmRegister>(), CpuRegister(TMP));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004120 } else if (source.IsFpuRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004121 Exchange32(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004122 } else if (source.IsStackSlot() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004123 Exchange32(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004124 } else if (source.IsFpuRegister() && destination.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004125 Exchange64(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004126 } else if (source.IsDoubleStackSlot() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004127 Exchange64(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004128 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004129 LOG(FATAL) << "Unimplemented swap between " << source << " and " << destination;
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004130 }
4131}
4132
4133
4134void ParallelMoveResolverX86_64::SpillScratch(int reg) {
4135 __ pushq(CpuRegister(reg));
4136}
4137
4138
4139void ParallelMoveResolverX86_64::RestoreScratch(int reg) {
4140 __ popq(CpuRegister(reg));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004141}
4142
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004143void InstructionCodeGeneratorX86_64::GenerateClassInitializationCheck(
4144 SlowPathCodeX86_64* slow_path, CpuRegister class_reg) {
4145 __ cmpl(Address(class_reg, mirror::Class::StatusOffset().Int32Value()),
4146 Immediate(mirror::Class::kStatusInitialized));
4147 __ j(kLess, slow_path->GetEntryLabel());
4148 __ Bind(slow_path->GetExitLabel());
4149 // No need for memory fence, thanks to the X86_64 memory model.
4150}
4151
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004152void LocationsBuilderX86_64::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004153 LocationSummary::CallKind call_kind = cls->CanCallRuntime()
4154 ? LocationSummary::kCallOnSlowPath
4155 : LocationSummary::kNoCall;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004156 LocationSummary* locations =
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004157 new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004158 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004159 locations->SetOut(Location::RequiresRegister());
4160}
4161
4162void InstructionCodeGeneratorX86_64::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004163 LocationSummary* locations = cls->GetLocations();
4164 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
4165 CpuRegister current_method = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004166 if (cls->IsReferrersClass()) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004167 DCHECK(!cls->CanCallRuntime());
4168 DCHECK(!cls->MustGenerateClinitCheck());
Mathieu Chartiere401d142015-04-22 13:56:20 -07004169 __ movl(out, Address(current_method, ArtMethod::DeclaringClassOffset().Int32Value()));
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004170 } else {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004171 DCHECK(cls->CanCallRuntime());
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004172 __ movl(out, Address(
Mathieu Chartiere401d142015-04-22 13:56:20 -07004173 current_method, ArtMethod::DexCacheResolvedTypesOffset().Int32Value()));
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004174 __ movl(out, Address(out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex())));
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004175 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86_64(
4176 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
4177 codegen_->AddSlowPath(slow_path);
4178 __ testl(out, out);
4179 __ j(kEqual, slow_path->GetEntryLabel());
4180 if (cls->MustGenerateClinitCheck()) {
4181 GenerateClassInitializationCheck(slow_path, out);
4182 } else {
4183 __ Bind(slow_path->GetExitLabel());
4184 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004185 }
4186}
4187
4188void LocationsBuilderX86_64::VisitClinitCheck(HClinitCheck* check) {
4189 LocationSummary* locations =
4190 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
4191 locations->SetInAt(0, Location::RequiresRegister());
4192 if (check->HasUses()) {
4193 locations->SetOut(Location::SameAsFirstInput());
4194 }
4195}
4196
4197void InstructionCodeGeneratorX86_64::VisitClinitCheck(HClinitCheck* check) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004198 // We assume the class to not be null.
4199 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86_64(
4200 check->GetLoadClass(), check, check->GetDexPc(), true);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004201 codegen_->AddSlowPath(slow_path);
Roland Levillain199f3362014-11-27 17:15:16 +00004202 GenerateClassInitializationCheck(slow_path,
4203 check->GetLocations()->InAt(0).AsRegister<CpuRegister>());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004204}
4205
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004206void LocationsBuilderX86_64::VisitLoadString(HLoadString* load) {
4207 LocationSummary* locations =
4208 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01004209 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004210 locations->SetOut(Location::RequiresRegister());
4211}
4212
4213void InstructionCodeGeneratorX86_64::VisitLoadString(HLoadString* load) {
4214 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathX86_64(load);
4215 codegen_->AddSlowPath(slow_path);
4216
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01004217 LocationSummary* locations = load->GetLocations();
4218 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
4219 CpuRegister current_method = locations->InAt(0).AsRegister<CpuRegister>();
Mathieu Chartiere401d142015-04-22 13:56:20 -07004220 __ movl(out, Address(current_method, ArtMethod::DeclaringClassOffset().Int32Value()));
Mathieu Chartiereace4582014-11-24 18:29:54 -08004221 __ movl(out, Address(out, mirror::Class::DexCacheStringsOffset().Int32Value()));
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004222 __ movl(out, Address(out, CodeGenerator::GetCacheOffset(load->GetStringIndex())));
4223 __ testl(out, out);
4224 __ j(kEqual, slow_path->GetEntryLabel());
4225 __ Bind(slow_path->GetExitLabel());
4226}
4227
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004228void LocationsBuilderX86_64::VisitLoadException(HLoadException* load) {
4229 LocationSummary* locations =
4230 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
4231 locations->SetOut(Location::RequiresRegister());
4232}
4233
4234void InstructionCodeGeneratorX86_64::VisitLoadException(HLoadException* load) {
4235 Address address = Address::Absolute(
4236 Thread::ExceptionOffset<kX86_64WordSize>().Int32Value(), true);
Roland Levillain271ab9c2014-11-27 15:23:57 +00004237 __ gs()->movl(load->GetLocations()->Out().AsRegister<CpuRegister>(), address);
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004238 __ gs()->movl(address, Immediate(0));
4239}
4240
4241void LocationsBuilderX86_64::VisitThrow(HThrow* instruction) {
4242 LocationSummary* locations =
4243 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
4244 InvokeRuntimeCallingConvention calling_convention;
4245 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4246}
4247
4248void InstructionCodeGeneratorX86_64::VisitThrow(HThrow* instruction) {
4249 __ gs()->call(
4250 Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pDeliverException), true));
4251 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
4252}
4253
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004254void LocationsBuilderX86_64::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004255 LocationSummary::CallKind call_kind = instruction->IsClassFinal()
4256 ? LocationSummary::kNoCall
4257 : LocationSummary::kCallOnSlowPath;
4258 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
4259 locations->SetInAt(0, Location::RequiresRegister());
4260 locations->SetInAt(1, Location::Any());
4261 locations->SetOut(Location::RequiresRegister());
4262}
4263
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004264void InstructionCodeGeneratorX86_64::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004265 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004266 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004267 Location cls = locations->InAt(1);
Roland Levillain271ab9c2014-11-27 15:23:57 +00004268 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004269 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
4270 Label done, zero;
4271 SlowPathCodeX86_64* slow_path = nullptr;
4272
4273 // Return 0 if `obj` is null.
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004274 // Avoid null check if we know obj is not null.
4275 if (instruction->MustDoNullCheck()) {
4276 __ testl(obj, obj);
4277 __ j(kEqual, &zero);
4278 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004279 // Compare the class of `obj` with `cls`.
4280 __ movl(out, Address(obj, class_offset));
4281 if (cls.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004282 __ cmpl(out, cls.AsRegister<CpuRegister>());
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004283 } else {
4284 DCHECK(cls.IsStackSlot()) << cls;
4285 __ cmpl(out, Address(CpuRegister(RSP), cls.GetStackIndex()));
4286 }
4287 if (instruction->IsClassFinal()) {
4288 // Classes must be equal for the instanceof to succeed.
4289 __ j(kNotEqual, &zero);
4290 __ movl(out, Immediate(1));
4291 __ jmp(&done);
4292 } else {
4293 // If the classes are not equal, we go into a slow path.
4294 DCHECK(locations->OnlyCallsOnSlowPath());
4295 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86_64(
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004296 instruction, locations->InAt(1), locations->Out(), instruction->GetDexPc());
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004297 codegen_->AddSlowPath(slow_path);
4298 __ j(kNotEqual, slow_path->GetEntryLabel());
4299 __ movl(out, Immediate(1));
4300 __ jmp(&done);
4301 }
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004302
4303 if (instruction->MustDoNullCheck() || instruction->IsClassFinal()) {
4304 __ Bind(&zero);
4305 __ movl(out, Immediate(0));
4306 }
4307
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004308 if (slow_path != nullptr) {
4309 __ Bind(slow_path->GetExitLabel());
4310 }
4311 __ Bind(&done);
4312}
4313
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004314void LocationsBuilderX86_64::VisitCheckCast(HCheckCast* instruction) {
4315 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
4316 instruction, LocationSummary::kCallOnSlowPath);
4317 locations->SetInAt(0, Location::RequiresRegister());
4318 locations->SetInAt(1, Location::Any());
4319 locations->AddTemp(Location::RequiresRegister());
4320}
4321
4322void InstructionCodeGeneratorX86_64::VisitCheckCast(HCheckCast* instruction) {
4323 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004324 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004325 Location cls = locations->InAt(1);
Roland Levillain271ab9c2014-11-27 15:23:57 +00004326 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004327 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
4328 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86_64(
4329 instruction, locations->InAt(1), locations->GetTemp(0), instruction->GetDexPc());
4330 codegen_->AddSlowPath(slow_path);
4331
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004332 // Avoid null check if we know obj is not null.
4333 if (instruction->MustDoNullCheck()) {
4334 __ testl(obj, obj);
4335 __ j(kEqual, slow_path->GetExitLabel());
4336 }
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004337 // Compare the class of `obj` with `cls`.
4338 __ movl(temp, Address(obj, class_offset));
4339 if (cls.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004340 __ cmpl(temp, cls.AsRegister<CpuRegister>());
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004341 } else {
4342 DCHECK(cls.IsStackSlot()) << cls;
4343 __ cmpl(temp, Address(CpuRegister(RSP), cls.GetStackIndex()));
4344 }
4345 // Classes must be equal for the checkcast to succeed.
4346 __ j(kNotEqual, slow_path->GetEntryLabel());
4347 __ Bind(slow_path->GetExitLabel());
4348}
4349
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00004350void LocationsBuilderX86_64::VisitMonitorOperation(HMonitorOperation* instruction) {
4351 LocationSummary* locations =
4352 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
4353 InvokeRuntimeCallingConvention calling_convention;
4354 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4355}
4356
4357void InstructionCodeGeneratorX86_64::VisitMonitorOperation(HMonitorOperation* instruction) {
4358 __ gs()->call(Address::Absolute(instruction->IsEnter()
4359 ? QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pLockObject)
4360 : QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pUnlockObject),
4361 true));
4362 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
4363}
4364
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004365void LocationsBuilderX86_64::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); }
4366void LocationsBuilderX86_64::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); }
4367void LocationsBuilderX86_64::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); }
4368
4369void LocationsBuilderX86_64::HandleBitwiseOperation(HBinaryOperation* instruction) {
4370 LocationSummary* locations =
4371 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
4372 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
4373 || instruction->GetResultType() == Primitive::kPrimLong);
4374 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell40741f32015-04-20 22:10:34 -04004375 locations->SetInAt(1, Location::Any());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004376 locations->SetOut(Location::SameAsFirstInput());
4377}
4378
4379void InstructionCodeGeneratorX86_64::VisitAnd(HAnd* instruction) {
4380 HandleBitwiseOperation(instruction);
4381}
4382
4383void InstructionCodeGeneratorX86_64::VisitOr(HOr* instruction) {
4384 HandleBitwiseOperation(instruction);
4385}
4386
4387void InstructionCodeGeneratorX86_64::VisitXor(HXor* instruction) {
4388 HandleBitwiseOperation(instruction);
4389}
4390
4391void InstructionCodeGeneratorX86_64::HandleBitwiseOperation(HBinaryOperation* instruction) {
4392 LocationSummary* locations = instruction->GetLocations();
4393 Location first = locations->InAt(0);
4394 Location second = locations->InAt(1);
4395 DCHECK(first.Equals(locations->Out()));
4396
4397 if (instruction->GetResultType() == Primitive::kPrimInt) {
4398 if (second.IsRegister()) {
4399 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004400 __ andl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004401 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004402 __ orl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004403 } else {
4404 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004405 __ xorl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004406 }
4407 } else if (second.IsConstant()) {
4408 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
4409 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004410 __ andl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004411 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004412 __ orl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004413 } else {
4414 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004415 __ xorl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004416 }
4417 } else {
4418 Address address(CpuRegister(RSP), second.GetStackIndex());
4419 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004420 __ andl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004421 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004422 __ orl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004423 } else {
4424 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004425 __ xorl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004426 }
4427 }
4428 } else {
4429 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004430 CpuRegister first_reg = first.AsRegister<CpuRegister>();
4431 bool second_is_constant = false;
4432 int64_t value = 0;
4433 if (second.IsConstant()) {
4434 second_is_constant = true;
4435 value = second.GetConstant()->AsLongConstant()->GetValue();
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004436 }
Mark Mendell40741f32015-04-20 22:10:34 -04004437 bool is_int32_value = IsInt<32>(value);
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004438
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004439 if (instruction->IsAnd()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004440 if (second_is_constant) {
Mark Mendell40741f32015-04-20 22:10:34 -04004441 if (is_int32_value) {
4442 __ andq(first_reg, Immediate(static_cast<int32_t>(value)));
4443 } else {
4444 __ andq(first_reg, codegen_->LiteralInt64Address(value));
4445 }
4446 } else if (second.IsDoubleStackSlot()) {
4447 __ andq(first_reg, Address(CpuRegister(RSP), second.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004448 } else {
4449 __ andq(first_reg, second.AsRegister<CpuRegister>());
4450 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004451 } else if (instruction->IsOr()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004452 if (second_is_constant) {
Mark Mendell40741f32015-04-20 22:10:34 -04004453 if (is_int32_value) {
4454 __ orq(first_reg, Immediate(static_cast<int32_t>(value)));
4455 } else {
4456 __ orq(first_reg, codegen_->LiteralInt64Address(value));
4457 }
4458 } else if (second.IsDoubleStackSlot()) {
4459 __ orq(first_reg, Address(CpuRegister(RSP), second.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004460 } else {
4461 __ orq(first_reg, second.AsRegister<CpuRegister>());
4462 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004463 } else {
4464 DCHECK(instruction->IsXor());
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004465 if (second_is_constant) {
Mark Mendell40741f32015-04-20 22:10:34 -04004466 if (is_int32_value) {
4467 __ xorq(first_reg, Immediate(static_cast<int32_t>(value)));
4468 } else {
4469 __ xorq(first_reg, codegen_->LiteralInt64Address(value));
4470 }
4471 } else if (second.IsDoubleStackSlot()) {
4472 __ xorq(first_reg, Address(CpuRegister(RSP), second.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004473 } else {
4474 __ xorq(first_reg, second.AsRegister<CpuRegister>());
4475 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004476 }
4477 }
4478}
4479
Calin Juravleb1498f62015-02-16 13:13:29 +00004480void LocationsBuilderX86_64::VisitBoundType(HBoundType* instruction) {
4481 // Nothing to do, this should be removed during prepare for register allocator.
4482 UNUSED(instruction);
4483 LOG(FATAL) << "Unreachable";
4484}
4485
4486void InstructionCodeGeneratorX86_64::VisitBoundType(HBoundType* instruction) {
4487 // Nothing to do, this should be removed during prepare for register allocator.
4488 UNUSED(instruction);
4489 LOG(FATAL) << "Unreachable";
4490}
4491
Mark Mendell92e83bf2015-05-07 11:25:03 -04004492void CodeGeneratorX86_64::Load64BitValue(CpuRegister dest, int64_t value) {
4493 if (value == 0) {
4494 __ xorl(dest, dest);
4495 } else if (value > 0 && IsInt<32>(value)) {
4496 // We can use a 32 bit move, as it will zero-extend and is one byte shorter.
4497 __ movl(dest, Immediate(static_cast<int32_t>(value)));
4498 } else {
4499 __ movq(dest, Immediate(value));
4500 }
4501}
4502
Mark Mendellf55c3e02015-03-26 21:07:46 -04004503void CodeGeneratorX86_64::Finalize(CodeAllocator* allocator) {
4504 // Generate the constant area if needed.
Mark Mendell39dcf552015-04-09 20:42:42 -04004505 X86_64Assembler* assembler = GetAssembler();
4506 if (!assembler->IsConstantAreaEmpty()) {
Mark Mendellf55c3e02015-03-26 21:07:46 -04004507 // Align to 4 byte boundary to reduce cache misses, as the data is 4 and 8
4508 // byte values. If used for vectors at a later time, this will need to be
4509 // updated to 16 bytes with the appropriate offset.
Mark Mendell39dcf552015-04-09 20:42:42 -04004510 assembler->Align(4, 0);
4511 constant_area_start_ = assembler->CodeSize();
4512 assembler->AddConstantArea();
Mark Mendellf55c3e02015-03-26 21:07:46 -04004513 }
4514
4515 // And finish up.
4516 CodeGenerator::Finalize(allocator);
4517}
4518
4519/**
4520 * Class to handle late fixup of offsets into constant area.
4521 */
4522class RIPFixup : public AssemblerFixup, public ArenaObject<kArenaAllocMisc> {
4523 public:
Mark Mendell39dcf552015-04-09 20:42:42 -04004524 RIPFixup(const CodeGeneratorX86_64& codegen, int offset)
Mark Mendellf55c3e02015-03-26 21:07:46 -04004525 : codegen_(codegen), offset_into_constant_area_(offset) {}
4526
4527 private:
4528 void Process(const MemoryRegion& region, int pos) OVERRIDE {
4529 // Patch the correct offset for the instruction. We use the address of the
4530 // 'next' instruction, which is 'pos' (patch the 4 bytes before).
4531 int constant_offset = codegen_.ConstantAreaStart() + offset_into_constant_area_;
4532 int relative_position = constant_offset - pos;
4533
4534 // Patch in the right value.
4535 region.StoreUnaligned<int32_t>(pos - 4, relative_position);
4536 }
4537
Mark Mendell39dcf552015-04-09 20:42:42 -04004538 const CodeGeneratorX86_64& codegen_;
Mark Mendellf55c3e02015-03-26 21:07:46 -04004539
4540 // Location in constant area that the fixup refers to.
4541 int offset_into_constant_area_;
4542};
4543
4544Address CodeGeneratorX86_64::LiteralDoubleAddress(double v) {
4545 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddDouble(v));
4546 return Address::RIP(fixup);
4547}
4548
4549Address CodeGeneratorX86_64::LiteralFloatAddress(float v) {
4550 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddFloat(v));
4551 return Address::RIP(fixup);
4552}
4553
4554Address CodeGeneratorX86_64::LiteralInt32Address(int32_t v) {
4555 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddInt32(v));
4556 return Address::RIP(fixup);
4557}
4558
4559Address CodeGeneratorX86_64::LiteralInt64Address(int64_t v) {
4560 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddInt64(v));
4561 return Address::RIP(fixup);
4562}
4563
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004564} // namespace x86_64
4565} // namespace art