blob: 22f5d96635403ded2d5fb4b5ba5db0f9535934d0 [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
Jeff Haocad65422015-06-18 21:16:08 -0700394 __ gs()->movq(reg, Address::Absolute(invoke->GetStringInitOffset(), true));
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
David Brazdilfc6a86a2015-06-26 10:33:45 +0000789void InstructionCodeGeneratorX86_64::HandleGoto(HInstruction* got, HBasicBlock* successor) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100790 DCHECK(!successor->IsExitBlock());
791
792 HBasicBlock* block = got->GetBlock();
793 HInstruction* previous = got->GetPrevious();
794
795 HLoopInformation* info = block->GetLoopInformation();
David Brazdil46e2a392015-03-16 17:31:52 +0000796 if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100797 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
798 return;
799 }
800
801 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
802 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
803 }
804 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100805 __ jmp(codegen_->GetLabelOf(successor));
806 }
807}
808
David Brazdilfc6a86a2015-06-26 10:33:45 +0000809void LocationsBuilderX86_64::VisitGoto(HGoto* got) {
810 got->SetLocations(nullptr);
811}
812
813void InstructionCodeGeneratorX86_64::VisitGoto(HGoto* got) {
814 HandleGoto(got, got->GetSuccessor());
815}
816
817void LocationsBuilderX86_64::VisitTryBoundary(HTryBoundary* try_boundary) {
818 try_boundary->SetLocations(nullptr);
819}
820
821void InstructionCodeGeneratorX86_64::VisitTryBoundary(HTryBoundary* try_boundary) {
822 HBasicBlock* successor = try_boundary->GetNormalFlowSuccessor();
823 if (!successor->IsExitBlock()) {
824 HandleGoto(try_boundary, successor);
825 }
826}
827
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100828void LocationsBuilderX86_64::VisitExit(HExit* exit) {
829 exit->SetLocations(nullptr);
830}
831
832void InstructionCodeGeneratorX86_64::VisitExit(HExit* exit) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700833 UNUSED(exit);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100834}
835
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700836void InstructionCodeGeneratorX86_64::GenerateTestAndBranch(HInstruction* instruction,
837 Label* true_target,
838 Label* false_target,
839 Label* always_true_target) {
840 HInstruction* cond = instruction->InputAt(0);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100841 if (cond->IsIntConstant()) {
842 // Constant condition, statically compared against 1.
843 int32_t cond_value = cond->AsIntConstant()->GetValue();
844 if (cond_value == 1) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700845 if (always_true_target != nullptr) {
846 __ jmp(always_true_target);
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100847 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100848 return;
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100849 } else {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100850 DCHECK_EQ(cond_value, 0);
851 }
852 } else {
853 bool materialized =
854 !cond->IsCondition() || cond->AsCondition()->NeedsMaterialization();
855 // Moves do not affect the eflags register, so if the condition is
856 // evaluated just before the if, we don't need to evaluate it
857 // again.
858 bool eflags_set = cond->IsCondition()
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700859 && cond->AsCondition()->IsBeforeWhenDisregardMoves(instruction);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100860 if (materialized) {
861 if (!eflags_set) {
862 // Materialized condition, compare against 0.
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700863 Location lhs = instruction->GetLocations()->InAt(0);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100864 if (lhs.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +0000865 __ testl(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>());
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100866 } else {
867 __ cmpl(Address(CpuRegister(RSP), lhs.GetStackIndex()),
868 Immediate(0));
869 }
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700870 __ j(kNotEqual, true_target);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100871 } else {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700872 __ j(X86_64Condition(cond->AsCondition()->GetCondition()), true_target);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100873 }
874 } else {
875 Location lhs = cond->GetLocations()->InAt(0);
876 Location rhs = cond->GetLocations()->InAt(1);
877 if (rhs.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000878 __ cmpl(lhs.AsRegister<CpuRegister>(), rhs.AsRegister<CpuRegister>());
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100879 } else if (rhs.IsConstant()) {
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000880 int32_t constant = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
Nicolas Geoffray748f1402015-01-27 08:17:54 +0000881 if (constant == 0) {
882 __ testl(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>());
883 } else {
884 __ cmpl(lhs.AsRegister<CpuRegister>(), Immediate(constant));
885 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100886 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000887 __ cmpl(lhs.AsRegister<CpuRegister>(),
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100888 Address(CpuRegister(RSP), rhs.GetStackIndex()));
889 }
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700890 __ j(X86_64Condition(cond->AsCondition()->GetCondition()), true_target);
Dave Allison20dfc792014-06-16 20:44:29 -0700891 }
Dave Allison20dfc792014-06-16 20:44:29 -0700892 }
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700893 if (false_target != nullptr) {
894 __ jmp(false_target);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100895 }
896}
897
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700898void LocationsBuilderX86_64::VisitIf(HIf* if_instr) {
899 LocationSummary* locations =
900 new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall);
901 HInstruction* cond = if_instr->InputAt(0);
902 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
903 locations->SetInAt(0, Location::Any());
904 }
905}
906
907void InstructionCodeGeneratorX86_64::VisitIf(HIf* if_instr) {
908 Label* true_target = codegen_->GetLabelOf(if_instr->IfTrueSuccessor());
909 Label* false_target = codegen_->GetLabelOf(if_instr->IfFalseSuccessor());
910 Label* always_true_target = true_target;
911 if (codegen_->GoesToNextBlock(if_instr->GetBlock(),
912 if_instr->IfTrueSuccessor())) {
913 always_true_target = nullptr;
914 }
915 if (codegen_->GoesToNextBlock(if_instr->GetBlock(),
916 if_instr->IfFalseSuccessor())) {
917 false_target = nullptr;
918 }
919 GenerateTestAndBranch(if_instr, true_target, false_target, always_true_target);
920}
921
922void LocationsBuilderX86_64::VisitDeoptimize(HDeoptimize* deoptimize) {
923 LocationSummary* locations = new (GetGraph()->GetArena())
924 LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
925 HInstruction* cond = deoptimize->InputAt(0);
926 DCHECK(cond->IsCondition());
927 if (cond->AsCondition()->NeedsMaterialization()) {
928 locations->SetInAt(0, Location::Any());
929 }
930}
931
932void InstructionCodeGeneratorX86_64::VisitDeoptimize(HDeoptimize* deoptimize) {
933 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena())
934 DeoptimizationSlowPathX86_64(deoptimize);
935 codegen_->AddSlowPath(slow_path);
936 Label* slow_path_entry = slow_path->GetEntryLabel();
937 GenerateTestAndBranch(deoptimize, slow_path_entry, nullptr, slow_path_entry);
938}
939
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100940void LocationsBuilderX86_64::VisitLocal(HLocal* local) {
941 local->SetLocations(nullptr);
942}
943
944void InstructionCodeGeneratorX86_64::VisitLocal(HLocal* local) {
945 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
946}
947
948void LocationsBuilderX86_64::VisitLoadLocal(HLoadLocal* local) {
949 local->SetLocations(nullptr);
950}
951
952void InstructionCodeGeneratorX86_64::VisitLoadLocal(HLoadLocal* load) {
953 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700954 UNUSED(load);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100955}
956
957void LocationsBuilderX86_64::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100958 LocationSummary* locations =
959 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100960 switch (store->InputAt(1)->GetType()) {
961 case Primitive::kPrimBoolean:
962 case Primitive::kPrimByte:
963 case Primitive::kPrimChar:
964 case Primitive::kPrimShort:
965 case Primitive::kPrimInt:
966 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100967 case Primitive::kPrimFloat:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100968 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
969 break;
970
971 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100972 case Primitive::kPrimDouble:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100973 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
974 break;
975
976 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100977 LOG(FATAL) << "Unexpected local type " << store->InputAt(1)->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100978 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100979}
980
981void InstructionCodeGeneratorX86_64::VisitStoreLocal(HStoreLocal* store) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700982 UNUSED(store);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100983}
984
Roland Levillain0d37cd02015-05-27 16:39:19 +0100985void LocationsBuilderX86_64::VisitCondition(HCondition* cond) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100986 LocationSummary* locations =
Roland Levillain0d37cd02015-05-27 16:39:19 +0100987 new (GetGraph()->GetArena()) LocationSummary(cond, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +0100988 locations->SetInAt(0, Location::RequiresRegister());
989 locations->SetInAt(1, Location::Any());
Roland Levillain0d37cd02015-05-27 16:39:19 +0100990 if (cond->NeedsMaterialization()) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100991 locations->SetOut(Location::RequiresRegister());
992 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100993}
994
Roland Levillain0d37cd02015-05-27 16:39:19 +0100995void InstructionCodeGeneratorX86_64::VisitCondition(HCondition* cond) {
996 if (cond->NeedsMaterialization()) {
997 LocationSummary* locations = cond->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +0000998 CpuRegister reg = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100999 // Clear register: setcc only sets the low byte.
Mark Mendell92e83bf2015-05-07 11:25:03 -04001000 __ xorl(reg, reg);
Nicolas Geoffray748f1402015-01-27 08:17:54 +00001001 Location lhs = locations->InAt(0);
1002 Location rhs = locations->InAt(1);
1003 if (rhs.IsRegister()) {
1004 __ cmpl(lhs.AsRegister<CpuRegister>(), rhs.AsRegister<CpuRegister>());
1005 } else if (rhs.IsConstant()) {
Mingyao Yangdc5ac732015-02-25 11:28:05 -08001006 int32_t constant = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
Nicolas Geoffray748f1402015-01-27 08:17:54 +00001007 if (constant == 0) {
1008 __ testl(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>());
1009 } else {
1010 __ cmpl(lhs.AsRegister<CpuRegister>(), Immediate(constant));
1011 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001012 } else {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00001013 __ cmpl(lhs.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), rhs.GetStackIndex()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001014 }
Roland Levillain0d37cd02015-05-27 16:39:19 +01001015 __ setcc(X86_64Condition(cond->GetCondition()), reg);
Dave Allison20dfc792014-06-16 20:44:29 -07001016 }
1017}
1018
1019void LocationsBuilderX86_64::VisitEqual(HEqual* comp) {
1020 VisitCondition(comp);
1021}
1022
1023void InstructionCodeGeneratorX86_64::VisitEqual(HEqual* comp) {
1024 VisitCondition(comp);
1025}
1026
1027void LocationsBuilderX86_64::VisitNotEqual(HNotEqual* comp) {
1028 VisitCondition(comp);
1029}
1030
1031void InstructionCodeGeneratorX86_64::VisitNotEqual(HNotEqual* comp) {
1032 VisitCondition(comp);
1033}
1034
1035void LocationsBuilderX86_64::VisitLessThan(HLessThan* comp) {
1036 VisitCondition(comp);
1037}
1038
1039void InstructionCodeGeneratorX86_64::VisitLessThan(HLessThan* comp) {
1040 VisitCondition(comp);
1041}
1042
1043void LocationsBuilderX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1044 VisitCondition(comp);
1045}
1046
1047void InstructionCodeGeneratorX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1048 VisitCondition(comp);
1049}
1050
1051void LocationsBuilderX86_64::VisitGreaterThan(HGreaterThan* comp) {
1052 VisitCondition(comp);
1053}
1054
1055void InstructionCodeGeneratorX86_64::VisitGreaterThan(HGreaterThan* comp) {
1056 VisitCondition(comp);
1057}
1058
1059void LocationsBuilderX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1060 VisitCondition(comp);
1061}
1062
1063void InstructionCodeGeneratorX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1064 VisitCondition(comp);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001065}
1066
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001067void LocationsBuilderX86_64::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001068 LocationSummary* locations =
1069 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Calin Juravleddb7df22014-11-25 20:56:51 +00001070 switch (compare->InputAt(0)->GetType()) {
1071 case Primitive::kPrimLong: {
1072 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell40741f32015-04-20 22:10:34 -04001073 locations->SetInAt(1, Location::Any());
Calin Juravleddb7df22014-11-25 20:56:51 +00001074 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1075 break;
1076 }
1077 case Primitive::kPrimFloat:
1078 case Primitive::kPrimDouble: {
1079 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendell40741f32015-04-20 22:10:34 -04001080 locations->SetInAt(1, Location::Any());
Calin Juravleddb7df22014-11-25 20:56:51 +00001081 locations->SetOut(Location::RequiresRegister());
1082 break;
1083 }
1084 default:
1085 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
1086 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001087}
1088
1089void InstructionCodeGeneratorX86_64::VisitCompare(HCompare* compare) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001090 LocationSummary* locations = compare->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00001091 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Calin Juravleddb7df22014-11-25 20:56:51 +00001092 Location left = locations->InAt(0);
1093 Location right = locations->InAt(1);
1094
1095 Label less, greater, done;
1096 Primitive::Type type = compare->InputAt(0)->GetType();
1097 switch (type) {
1098 case Primitive::kPrimLong: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04001099 CpuRegister left_reg = left.AsRegister<CpuRegister>();
1100 if (right.IsConstant()) {
1101 int64_t value = right.GetConstant()->AsLongConstant()->GetValue();
Mark Mendell40741f32015-04-20 22:10:34 -04001102 if (IsInt<32>(value)) {
1103 if (value == 0) {
1104 __ testq(left_reg, left_reg);
1105 } else {
1106 __ cmpq(left_reg, Immediate(static_cast<int32_t>(value)));
1107 }
Mark Mendell3f6c7f62015-03-13 13:47:53 -04001108 } else {
Mark Mendell40741f32015-04-20 22:10:34 -04001109 // Value won't fit in an int.
1110 __ cmpq(left_reg, codegen_->LiteralInt64Address(value));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04001111 }
Mark Mendell40741f32015-04-20 22:10:34 -04001112 } else if (right.IsDoubleStackSlot()) {
1113 __ cmpq(left_reg, Address(CpuRegister(RSP), right.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04001114 } else {
1115 __ cmpq(left_reg, right.AsRegister<CpuRegister>());
1116 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001117 break;
Calin Juravleddb7df22014-11-25 20:56:51 +00001118 }
1119 case Primitive::kPrimFloat: {
Mark Mendell40741f32015-04-20 22:10:34 -04001120 XmmRegister left_reg = left.AsFpuRegister<XmmRegister>();
1121 if (right.IsConstant()) {
1122 float value = right.GetConstant()->AsFloatConstant()->GetValue();
1123 __ ucomiss(left_reg, codegen_->LiteralFloatAddress(value));
1124 } else if (right.IsStackSlot()) {
1125 __ ucomiss(left_reg, Address(CpuRegister(RSP), right.GetStackIndex()));
1126 } else {
1127 __ ucomiss(left_reg, right.AsFpuRegister<XmmRegister>());
1128 }
Calin Juravleddb7df22014-11-25 20:56:51 +00001129 __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
1130 break;
1131 }
1132 case Primitive::kPrimDouble: {
Mark Mendell40741f32015-04-20 22:10:34 -04001133 XmmRegister left_reg = left.AsFpuRegister<XmmRegister>();
1134 if (right.IsConstant()) {
1135 double value = right.GetConstant()->AsDoubleConstant()->GetValue();
1136 __ ucomisd(left_reg, codegen_->LiteralDoubleAddress(value));
1137 } else if (right.IsDoubleStackSlot()) {
1138 __ ucomisd(left_reg, Address(CpuRegister(RSP), right.GetStackIndex()));
1139 } else {
1140 __ ucomisd(left_reg, right.AsFpuRegister<XmmRegister>());
1141 }
Calin Juravleddb7df22014-11-25 20:56:51 +00001142 __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
1143 break;
1144 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001145 default:
Calin Juravleddb7df22014-11-25 20:56:51 +00001146 LOG(FATAL) << "Unexpected compare type " << type;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001147 }
Calin Juravleddb7df22014-11-25 20:56:51 +00001148 __ movl(out, Immediate(0));
Calin Juravle91debbc2014-11-26 19:01:09 +00001149 __ j(kEqual, &done);
Calin Juravleddb7df22014-11-25 20:56:51 +00001150 __ j(type == Primitive::kPrimLong ? kLess : kBelow, &less); // ucomis{s,d} sets CF (kBelow)
Calin Juravlefd861242014-11-25 20:56:51 +00001151
Calin Juravle91debbc2014-11-26 19:01:09 +00001152 __ Bind(&greater);
Calin Juravleddb7df22014-11-25 20:56:51 +00001153 __ movl(out, Immediate(1));
1154 __ jmp(&done);
1155
1156 __ Bind(&less);
1157 __ movl(out, Immediate(-1));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001158
1159 __ Bind(&done);
1160}
1161
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001162void LocationsBuilderX86_64::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001163 LocationSummary* locations =
1164 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001165 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001166}
1167
1168void InstructionCodeGeneratorX86_64::VisitIntConstant(HIntConstant* constant) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001169 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001170 UNUSED(constant);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001171}
1172
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001173void LocationsBuilderX86_64::VisitNullConstant(HNullConstant* constant) {
1174 LocationSummary* locations =
1175 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1176 locations->SetOut(Location::ConstantLocation(constant));
1177}
1178
1179void InstructionCodeGeneratorX86_64::VisitNullConstant(HNullConstant* constant) {
1180 // Will be generated at use site.
1181 UNUSED(constant);
1182}
1183
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001184void LocationsBuilderX86_64::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001185 LocationSummary* locations =
1186 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001187 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001188}
1189
1190void InstructionCodeGeneratorX86_64::VisitLongConstant(HLongConstant* constant) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001191 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001192 UNUSED(constant);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001193}
1194
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001195void LocationsBuilderX86_64::VisitFloatConstant(HFloatConstant* constant) {
1196 LocationSummary* locations =
1197 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1198 locations->SetOut(Location::ConstantLocation(constant));
1199}
1200
1201void InstructionCodeGeneratorX86_64::VisitFloatConstant(HFloatConstant* constant) {
1202 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001203 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001204}
1205
1206void LocationsBuilderX86_64::VisitDoubleConstant(HDoubleConstant* constant) {
1207 LocationSummary* locations =
1208 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1209 locations->SetOut(Location::ConstantLocation(constant));
1210}
1211
1212void InstructionCodeGeneratorX86_64::VisitDoubleConstant(HDoubleConstant* constant) {
1213 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001214 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001215}
1216
Calin Juravle27df7582015-04-17 19:12:31 +01001217void LocationsBuilderX86_64::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
1218 memory_barrier->SetLocations(nullptr);
1219}
1220
1221void InstructionCodeGeneratorX86_64::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
1222 GenerateMemoryBarrier(memory_barrier->GetBarrierKind());
1223}
1224
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001225void LocationsBuilderX86_64::VisitReturnVoid(HReturnVoid* ret) {
1226 ret->SetLocations(nullptr);
1227}
1228
1229void InstructionCodeGeneratorX86_64::VisitReturnVoid(HReturnVoid* ret) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001230 UNUSED(ret);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001231 codegen_->GenerateFrameExit();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001232}
1233
1234void LocationsBuilderX86_64::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001235 LocationSummary* locations =
1236 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001237 switch (ret->InputAt(0)->GetType()) {
1238 case Primitive::kPrimBoolean:
1239 case Primitive::kPrimByte:
1240 case Primitive::kPrimChar:
1241 case Primitive::kPrimShort:
1242 case Primitive::kPrimInt:
1243 case Primitive::kPrimNot:
1244 case Primitive::kPrimLong:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001245 locations->SetInAt(0, Location::RegisterLocation(RAX));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001246 break;
1247
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001248 case Primitive::kPrimFloat:
1249 case Primitive::kPrimDouble:
Mark Mendell40741f32015-04-20 22:10:34 -04001250 locations->SetInAt(0, Location::FpuRegisterLocation(XMM0));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001251 break;
1252
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001253 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001254 LOG(FATAL) << "Unexpected return type " << ret->InputAt(0)->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001255 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001256}
1257
1258void InstructionCodeGeneratorX86_64::VisitReturn(HReturn* ret) {
1259 if (kIsDebugBuild) {
1260 switch (ret->InputAt(0)->GetType()) {
1261 case Primitive::kPrimBoolean:
1262 case Primitive::kPrimByte:
1263 case Primitive::kPrimChar:
1264 case Primitive::kPrimShort:
1265 case Primitive::kPrimInt:
1266 case Primitive::kPrimNot:
1267 case Primitive::kPrimLong:
Roland Levillain271ab9c2014-11-27 15:23:57 +00001268 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegister<CpuRegister>().AsRegister(), RAX);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001269 break;
1270
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001271 case Primitive::kPrimFloat:
1272 case Primitive::kPrimDouble:
Roland Levillain271ab9c2014-11-27 15:23:57 +00001273 DCHECK_EQ(ret->GetLocations()->InAt(0).AsFpuRegister<XmmRegister>().AsFloatRegister(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001274 XMM0);
1275 break;
1276
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001277 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001278 LOG(FATAL) << "Unexpected return type " << ret->InputAt(0)->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001279 }
1280 }
1281 codegen_->GenerateFrameExit();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001282}
1283
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01001284Location InvokeDexCallingConventionVisitorX86_64::GetReturnLocation(Primitive::Type type) const {
1285 switch (type) {
1286 case Primitive::kPrimBoolean:
1287 case Primitive::kPrimByte:
1288 case Primitive::kPrimChar:
1289 case Primitive::kPrimShort:
1290 case Primitive::kPrimInt:
1291 case Primitive::kPrimNot:
1292 case Primitive::kPrimLong:
1293 return Location::RegisterLocation(RAX);
1294
1295 case Primitive::kPrimVoid:
1296 return Location::NoLocation();
1297
1298 case Primitive::kPrimDouble:
1299 case Primitive::kPrimFloat:
1300 return Location::FpuRegisterLocation(XMM0);
1301 }
Nicolas Geoffray0d1652e2015-06-03 12:12:19 +01001302
1303 UNREACHABLE();
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01001304}
1305
1306Location InvokeDexCallingConventionVisitorX86_64::GetMethodLocation() const {
1307 return Location::RegisterLocation(kMethodRegisterArgument);
1308}
1309
Roland Levillain2d27c8e2015-04-28 15:48:45 +01001310Location InvokeDexCallingConventionVisitorX86_64::GetNextLocation(Primitive::Type type) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001311 switch (type) {
1312 case Primitive::kPrimBoolean:
1313 case Primitive::kPrimByte:
1314 case Primitive::kPrimChar:
1315 case Primitive::kPrimShort:
1316 case Primitive::kPrimInt:
1317 case Primitive::kPrimNot: {
1318 uint32_t index = gp_index_++;
1319 stack_index_++;
1320 if (index < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001321 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001322 } else {
1323 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
1324 }
1325 }
1326
1327 case Primitive::kPrimLong: {
1328 uint32_t index = gp_index_;
1329 stack_index_ += 2;
1330 if (index < calling_convention.GetNumberOfRegisters()) {
1331 gp_index_ += 1;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001332 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001333 } else {
1334 gp_index_ += 2;
1335 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
1336 }
1337 }
1338
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001339 case Primitive::kPrimFloat: {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01001340 uint32_t index = float_index_++;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001341 stack_index_++;
1342 if (index < calling_convention.GetNumberOfFpuRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001343 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001344 } else {
1345 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
1346 }
1347 }
1348
1349 case Primitive::kPrimDouble: {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01001350 uint32_t index = float_index_++;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001351 stack_index_ += 2;
1352 if (index < calling_convention.GetNumberOfFpuRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001353 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001354 } else {
1355 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
1356 }
1357 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001358
1359 case Primitive::kPrimVoid:
1360 LOG(FATAL) << "Unexpected parameter type " << type;
1361 break;
1362 }
1363 return Location();
1364}
1365
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001366void LocationsBuilderX86_64::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Roland Levillain3e3d7332015-04-28 11:00:54 +01001367 // When we do not run baseline, explicit clinit checks triggered by static
1368 // invokes must have been pruned by art::PrepareForRegisterAllocation.
1369 DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01001370
Mark Mendellfb8d2792015-03-31 22:16:59 -04001371 IntrinsicLocationsBuilderX86_64 intrinsic(codegen_);
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001372 if (intrinsic.TryDispatch(invoke)) {
1373 return;
1374 }
1375
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001376 HandleInvoke(invoke);
1377}
1378
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001379static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorX86_64* codegen) {
1380 if (invoke->GetLocations()->Intrinsified()) {
1381 IntrinsicCodeGeneratorX86_64 intrinsic(codegen);
1382 intrinsic.Dispatch(invoke);
1383 return true;
1384 }
1385 return false;
1386}
1387
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001388void InstructionCodeGeneratorX86_64::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Roland Levillain3e3d7332015-04-28 11:00:54 +01001389 // When we do not run baseline, explicit clinit checks triggered by static
1390 // invokes must have been pruned by art::PrepareForRegisterAllocation.
1391 DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01001392
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001393 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1394 return;
1395 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001396
Nicolas Geoffray38207af2015-06-01 15:46:22 +01001397 LocationSummary* locations = invoke->GetLocations();
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001398 codegen_->GenerateStaticOrDirectCall(
Nicolas Geoffray38207af2015-06-01 15:46:22 +01001399 invoke, locations->HasTemps() ? locations->GetTemp(0) : Location::NoLocation());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +00001400 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001401}
1402
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001403void LocationsBuilderX86_64::HandleInvoke(HInvoke* invoke) {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01001404 InvokeDexCallingConventionVisitorX86_64 calling_convention_visitor;
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01001405 CodeGenerator::CreateCommonInvokeLocationSummary(invoke, &calling_convention_visitor);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001406}
1407
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001408void LocationsBuilderX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Mark Mendellfb8d2792015-03-31 22:16:59 -04001409 IntrinsicLocationsBuilderX86_64 intrinsic(codegen_);
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001410 if (intrinsic.TryDispatch(invoke)) {
1411 return;
1412 }
1413
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001414 HandleInvoke(invoke);
1415}
1416
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001417void InstructionCodeGeneratorX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001418 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1419 return;
1420 }
1421
Roland Levillain271ab9c2014-11-27 15:23:57 +00001422 CpuRegister temp = invoke->GetLocations()->GetTemp(0).AsRegister<CpuRegister>();
Mathieu Chartiere401d142015-04-22 13:56:20 -07001423 size_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
1424 invoke->GetVTableIndex(), kX86_64PointerSize).SizeValue();
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001425 LocationSummary* locations = invoke->GetLocations();
1426 Location receiver = locations->InAt(0);
1427 size_t class_offset = mirror::Object::ClassOffset().SizeValue();
1428 // temp = object->GetClass();
Nicolas Geoffray38207af2015-06-01 15:46:22 +01001429 DCHECK(receiver.IsRegister());
1430 __ movl(temp, Address(receiver.AsRegister<CpuRegister>(), class_offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00001431 codegen_->MaybeRecordImplicitNullCheck(invoke);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001432 // temp = temp->GetMethodAt(method_offset);
Mathieu Chartiere401d142015-04-22 13:56:20 -07001433 __ movq(temp, Address(temp, method_offset));
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001434 // call temp->GetEntryPoint();
Mathieu Chartiere401d142015-04-22 13:56:20 -07001435 __ call(Address(temp, ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001436 kX86_64WordSize).SizeValue()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001437
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001438 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray39468442014-09-02 15:17:15 +01001439 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001440}
1441
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001442void LocationsBuilderX86_64::VisitInvokeInterface(HInvokeInterface* invoke) {
1443 HandleInvoke(invoke);
1444 // Add the hidden argument.
1445 invoke->GetLocations()->AddTemp(Location::RegisterLocation(RAX));
1446}
1447
1448void InstructionCodeGeneratorX86_64::VisitInvokeInterface(HInvokeInterface* invoke) {
1449 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001450 CpuRegister temp = invoke->GetLocations()->GetTemp(0).AsRegister<CpuRegister>();
Mathieu Chartiere401d142015-04-22 13:56:20 -07001451 uint32_t method_offset = mirror::Class::EmbeddedImTableEntryOffset(
1452 invoke->GetImtIndex() % mirror::Class::kImtSize, kX86_64PointerSize).Uint32Value();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001453 LocationSummary* locations = invoke->GetLocations();
1454 Location receiver = locations->InAt(0);
1455 size_t class_offset = mirror::Object::ClassOffset().SizeValue();
1456
1457 // Set the hidden argument.
Mark Mendell92e83bf2015-05-07 11:25:03 -04001458 CpuRegister hidden_reg = invoke->GetLocations()->GetTemp(1).AsRegister<CpuRegister>();
1459 codegen_->Load64BitValue(hidden_reg, invoke->GetDexMethodIndex());
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001460
1461 // temp = object->GetClass();
1462 if (receiver.IsStackSlot()) {
1463 __ movl(temp, Address(CpuRegister(RSP), receiver.GetStackIndex()));
1464 __ movl(temp, Address(temp, class_offset));
1465 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001466 __ movl(temp, Address(receiver.AsRegister<CpuRegister>(), class_offset));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001467 }
Calin Juravle77520bc2015-01-12 18:45:46 +00001468 codegen_->MaybeRecordImplicitNullCheck(invoke);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001469 // temp = temp->GetImtEntryAt(method_offset);
Mathieu Chartiere401d142015-04-22 13:56:20 -07001470 __ movq(temp, Address(temp, method_offset));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001471 // call temp->GetEntryPoint();
Mathieu Chartiere401d142015-04-22 13:56:20 -07001472 __ call(Address(temp, ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001473 kX86_64WordSize).SizeValue()));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001474
1475 DCHECK(!codegen_->IsLeafMethod());
1476 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1477}
1478
Roland Levillain88cb1752014-10-20 16:36:47 +01001479void LocationsBuilderX86_64::VisitNeg(HNeg* neg) {
1480 LocationSummary* locations =
1481 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
1482 switch (neg->GetResultType()) {
1483 case Primitive::kPrimInt:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001484 case Primitive::kPrimLong:
Roland Levillain88cb1752014-10-20 16:36:47 +01001485 locations->SetInAt(0, Location::RequiresRegister());
1486 locations->SetOut(Location::SameAsFirstInput());
1487 break;
1488
Roland Levillain88cb1752014-10-20 16:36:47 +01001489 case Primitive::kPrimFloat:
1490 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001491 locations->SetInAt(0, Location::RequiresFpuRegister());
Roland Levillain5368c212014-11-27 15:03:41 +00001492 locations->SetOut(Location::SameAsFirstInput());
Roland Levillain5368c212014-11-27 15:03:41 +00001493 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain88cb1752014-10-20 16:36:47 +01001494 break;
1495
1496 default:
1497 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1498 }
1499}
1500
1501void InstructionCodeGeneratorX86_64::VisitNeg(HNeg* neg) {
1502 LocationSummary* locations = neg->GetLocations();
1503 Location out = locations->Out();
1504 Location in = locations->InAt(0);
1505 switch (neg->GetResultType()) {
1506 case Primitive::kPrimInt:
1507 DCHECK(in.IsRegister());
Roland Levillain3dbcb382014-10-28 17:30:07 +00001508 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001509 __ negl(out.AsRegister<CpuRegister>());
Roland Levillain88cb1752014-10-20 16:36:47 +01001510 break;
1511
1512 case Primitive::kPrimLong:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001513 DCHECK(in.IsRegister());
Roland Levillain3dbcb382014-10-28 17:30:07 +00001514 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001515 __ negq(out.AsRegister<CpuRegister>());
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001516 break;
1517
Roland Levillain5368c212014-11-27 15:03:41 +00001518 case Primitive::kPrimFloat: {
1519 DCHECK(in.Equals(out));
Mark Mendell40741f32015-04-20 22:10:34 -04001520 XmmRegister mask = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
Roland Levillain5368c212014-11-27 15:03:41 +00001521 // Implement float negation with an exclusive or with value
1522 // 0x80000000 (mask for bit 31, representing the sign of a
1523 // single-precision floating-point number).
Mark Mendell40741f32015-04-20 22:10:34 -04001524 __ movss(mask, codegen_->LiteralInt32Address(0x80000000));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001525 __ xorps(out.AsFpuRegister<XmmRegister>(), mask);
Roland Levillain3dbcb382014-10-28 17:30:07 +00001526 break;
Roland Levillain5368c212014-11-27 15:03:41 +00001527 }
Roland Levillain3dbcb382014-10-28 17:30:07 +00001528
Roland Levillain5368c212014-11-27 15:03:41 +00001529 case Primitive::kPrimDouble: {
1530 DCHECK(in.Equals(out));
Mark Mendell40741f32015-04-20 22:10:34 -04001531 XmmRegister mask = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
Roland Levillain5368c212014-11-27 15:03:41 +00001532 // Implement double negation with an exclusive or with value
Roland Levillain3dbcb382014-10-28 17:30:07 +00001533 // 0x8000000000000000 (mask for bit 63, representing the sign of
Roland Levillain5368c212014-11-27 15:03:41 +00001534 // a double-precision floating-point number).
Mark Mendell40741f32015-04-20 22:10:34 -04001535 __ movsd(mask, codegen_->LiteralInt64Address(INT64_C(0x8000000000000000)));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001536 __ xorpd(out.AsFpuRegister<XmmRegister>(), mask);
Roland Levillain88cb1752014-10-20 16:36:47 +01001537 break;
Roland Levillain5368c212014-11-27 15:03:41 +00001538 }
Roland Levillain88cb1752014-10-20 16:36:47 +01001539
1540 default:
1541 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1542 }
1543}
1544
Roland Levillaindff1f282014-11-05 14:15:05 +00001545void LocationsBuilderX86_64::VisitTypeConversion(HTypeConversion* conversion) {
1546 LocationSummary* locations =
1547 new (GetGraph()->GetArena()) LocationSummary(conversion, LocationSummary::kNoCall);
1548 Primitive::Type result_type = conversion->GetResultType();
1549 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00001550 DCHECK_NE(result_type, input_type);
David Brazdil46e2a392015-03-16 17:31:52 +00001551
David Brazdilb2bd1c52015-03-25 11:17:37 +00001552 // The Java language does not allow treating boolean as an integral type but
1553 // our bit representation makes it safe.
David Brazdil46e2a392015-03-16 17:31:52 +00001554
Roland Levillaindff1f282014-11-05 14:15:05 +00001555 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00001556 case Primitive::kPrimByte:
1557 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001558 case Primitive::kPrimBoolean:
1559 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001560 case Primitive::kPrimShort:
1561 case Primitive::kPrimInt:
1562 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001563 // Processing a Dex `int-to-byte' instruction.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001564 locations->SetInAt(0, Location::Any());
1565 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1566 break;
1567
1568 default:
1569 LOG(FATAL) << "Unexpected type conversion from " << input_type
1570 << " to " << result_type;
1571 }
1572 break;
1573
Roland Levillain01a8d712014-11-14 16:27:39 +00001574 case Primitive::kPrimShort:
1575 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001576 case Primitive::kPrimBoolean:
1577 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00001578 case Primitive::kPrimByte:
1579 case Primitive::kPrimInt:
1580 case Primitive::kPrimChar:
1581 // Processing a Dex `int-to-short' instruction.
1582 locations->SetInAt(0, Location::Any());
1583 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1584 break;
1585
1586 default:
1587 LOG(FATAL) << "Unexpected type conversion from " << input_type
1588 << " to " << result_type;
1589 }
1590 break;
1591
Roland Levillain946e1432014-11-11 17:35:19 +00001592 case Primitive::kPrimInt:
1593 switch (input_type) {
1594 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00001595 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00001596 locations->SetInAt(0, Location::Any());
1597 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1598 break;
1599
1600 case Primitive::kPrimFloat:
Roland Levillain3f8f9362014-12-02 17:45:01 +00001601 // Processing a Dex `float-to-int' instruction.
1602 locations->SetInAt(0, Location::RequiresFpuRegister());
1603 locations->SetOut(Location::RequiresRegister());
1604 locations->AddTemp(Location::RequiresFpuRegister());
1605 break;
1606
Roland Levillain946e1432014-11-11 17:35:19 +00001607 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001608 // Processing a Dex `double-to-int' instruction.
1609 locations->SetInAt(0, Location::RequiresFpuRegister());
1610 locations->SetOut(Location::RequiresRegister());
1611 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain946e1432014-11-11 17:35:19 +00001612 break;
1613
1614 default:
1615 LOG(FATAL) << "Unexpected type conversion from " << input_type
1616 << " to " << result_type;
1617 }
1618 break;
1619
Roland Levillaindff1f282014-11-05 14:15:05 +00001620 case Primitive::kPrimLong:
1621 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001622 case Primitive::kPrimBoolean:
1623 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00001624 case Primitive::kPrimByte:
1625 case Primitive::kPrimShort:
1626 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00001627 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001628 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00001629 // TODO: We would benefit from a (to-be-implemented)
1630 // Location::RegisterOrStackSlot requirement for this input.
1631 locations->SetInAt(0, Location::RequiresRegister());
1632 locations->SetOut(Location::RequiresRegister());
1633 break;
1634
1635 case Primitive::kPrimFloat:
Roland Levillain624279f2014-12-04 11:54:28 +00001636 // Processing a Dex `float-to-long' instruction.
1637 locations->SetInAt(0, Location::RequiresFpuRegister());
1638 locations->SetOut(Location::RequiresRegister());
1639 locations->AddTemp(Location::RequiresFpuRegister());
1640 break;
1641
Roland Levillaindff1f282014-11-05 14:15:05 +00001642 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001643 // Processing a Dex `double-to-long' instruction.
1644 locations->SetInAt(0, Location::RequiresFpuRegister());
1645 locations->SetOut(Location::RequiresRegister());
1646 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillaindff1f282014-11-05 14:15:05 +00001647 break;
1648
1649 default:
1650 LOG(FATAL) << "Unexpected type conversion from " << input_type
1651 << " to " << result_type;
1652 }
1653 break;
1654
Roland Levillain981e4542014-11-14 11:47:14 +00001655 case Primitive::kPrimChar:
1656 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001657 case Primitive::kPrimBoolean:
1658 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00001659 case Primitive::kPrimByte:
1660 case Primitive::kPrimShort:
1661 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00001662 // Processing a Dex `int-to-char' instruction.
1663 locations->SetInAt(0, Location::Any());
1664 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1665 break;
1666
1667 default:
1668 LOG(FATAL) << "Unexpected type conversion from " << input_type
1669 << " to " << result_type;
1670 }
1671 break;
1672
Roland Levillaindff1f282014-11-05 14:15:05 +00001673 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00001674 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001675 case Primitive::kPrimBoolean:
1676 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001677 case Primitive::kPrimByte:
1678 case Primitive::kPrimShort:
1679 case Primitive::kPrimInt:
1680 case Primitive::kPrimChar:
1681 // Processing a Dex `int-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04001682 locations->SetInAt(0, Location::Any());
Roland Levillaincff13742014-11-17 14:32:17 +00001683 locations->SetOut(Location::RequiresFpuRegister());
1684 break;
1685
1686 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00001687 // Processing a Dex `long-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04001688 locations->SetInAt(0, Location::Any());
Roland Levillain6d0e4832014-11-27 18:31:21 +00001689 locations->SetOut(Location::RequiresFpuRegister());
1690 break;
1691
Roland Levillaincff13742014-11-17 14:32:17 +00001692 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001693 // Processing a Dex `double-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04001694 locations->SetInAt(0, Location::Any());
Roland Levillain8964e2b2014-12-04 12:10:50 +00001695 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00001696 break;
1697
1698 default:
1699 LOG(FATAL) << "Unexpected type conversion from " << input_type
1700 << " to " << result_type;
1701 };
1702 break;
1703
Roland Levillaindff1f282014-11-05 14:15:05 +00001704 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00001705 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001706 case Primitive::kPrimBoolean:
1707 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001708 case Primitive::kPrimByte:
1709 case Primitive::kPrimShort:
1710 case Primitive::kPrimInt:
1711 case Primitive::kPrimChar:
1712 // Processing a Dex `int-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04001713 locations->SetInAt(0, Location::Any());
Roland Levillaincff13742014-11-17 14:32:17 +00001714 locations->SetOut(Location::RequiresFpuRegister());
1715 break;
1716
1717 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00001718 // Processing a Dex `long-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04001719 locations->SetInAt(0, Location::Any());
Roland Levillain647b9ed2014-11-27 12:06:00 +00001720 locations->SetOut(Location::RequiresFpuRegister());
1721 break;
1722
Roland Levillaincff13742014-11-17 14:32:17 +00001723 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001724 // Processing a Dex `float-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04001725 locations->SetInAt(0, Location::Any());
Roland Levillain8964e2b2014-12-04 12:10:50 +00001726 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00001727 break;
1728
1729 default:
1730 LOG(FATAL) << "Unexpected type conversion from " << input_type
1731 << " to " << result_type;
1732 }
Roland Levillaindff1f282014-11-05 14:15:05 +00001733 break;
1734
1735 default:
1736 LOG(FATAL) << "Unexpected type conversion from " << input_type
1737 << " to " << result_type;
1738 }
1739}
1740
1741void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conversion) {
1742 LocationSummary* locations = conversion->GetLocations();
1743 Location out = locations->Out();
1744 Location in = locations->InAt(0);
1745 Primitive::Type result_type = conversion->GetResultType();
1746 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00001747 DCHECK_NE(result_type, input_type);
Roland Levillaindff1f282014-11-05 14:15:05 +00001748 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00001749 case Primitive::kPrimByte:
1750 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001751 case Primitive::kPrimBoolean:
1752 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001753 case Primitive::kPrimShort:
1754 case Primitive::kPrimInt:
1755 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001756 // Processing a Dex `int-to-byte' instruction.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001757 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001758 __ movsxb(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain51d3fc42014-11-13 14:11:42 +00001759 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001760 __ movsxb(out.AsRegister<CpuRegister>(),
Roland Levillain51d3fc42014-11-13 14:11:42 +00001761 Address(CpuRegister(RSP), in.GetStackIndex()));
1762 } else {
1763 DCHECK(in.GetConstant()->IsIntConstant());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001764 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain51d3fc42014-11-13 14:11:42 +00001765 Immediate(static_cast<int8_t>(in.GetConstant()->AsIntConstant()->GetValue())));
1766 }
1767 break;
1768
1769 default:
1770 LOG(FATAL) << "Unexpected type conversion from " << input_type
1771 << " to " << result_type;
1772 }
1773 break;
1774
Roland Levillain01a8d712014-11-14 16:27:39 +00001775 case Primitive::kPrimShort:
1776 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001777 case Primitive::kPrimBoolean:
1778 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00001779 case Primitive::kPrimByte:
1780 case Primitive::kPrimInt:
1781 case Primitive::kPrimChar:
1782 // Processing a Dex `int-to-short' instruction.
1783 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001784 __ movsxw(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain01a8d712014-11-14 16:27:39 +00001785 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001786 __ movsxw(out.AsRegister<CpuRegister>(),
Roland Levillain01a8d712014-11-14 16:27:39 +00001787 Address(CpuRegister(RSP), in.GetStackIndex()));
1788 } else {
1789 DCHECK(in.GetConstant()->IsIntConstant());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001790 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain01a8d712014-11-14 16:27:39 +00001791 Immediate(static_cast<int16_t>(in.GetConstant()->AsIntConstant()->GetValue())));
1792 }
1793 break;
1794
1795 default:
1796 LOG(FATAL) << "Unexpected type conversion from " << input_type
1797 << " to " << result_type;
1798 }
1799 break;
1800
Roland Levillain946e1432014-11-11 17:35:19 +00001801 case Primitive::kPrimInt:
1802 switch (input_type) {
1803 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00001804 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00001805 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001806 __ movl(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain946e1432014-11-11 17:35:19 +00001807 } else if (in.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001808 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain946e1432014-11-11 17:35:19 +00001809 Address(CpuRegister(RSP), in.GetStackIndex()));
1810 } else {
1811 DCHECK(in.IsConstant());
1812 DCHECK(in.GetConstant()->IsLongConstant());
1813 int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00001814 __ movl(out.AsRegister<CpuRegister>(), Immediate(static_cast<int32_t>(value)));
Roland Levillain946e1432014-11-11 17:35:19 +00001815 }
1816 break;
1817
Roland Levillain3f8f9362014-12-02 17:45:01 +00001818 case Primitive::kPrimFloat: {
1819 // Processing a Dex `float-to-int' instruction.
1820 XmmRegister input = in.AsFpuRegister<XmmRegister>();
1821 CpuRegister output = out.AsRegister<CpuRegister>();
1822 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
1823 Label done, nan;
1824
1825 __ movl(output, Immediate(kPrimIntMax));
1826 // temp = int-to-float(output)
Roland Levillain624279f2014-12-04 11:54:28 +00001827 __ cvtsi2ss(temp, output, false);
Roland Levillain3f8f9362014-12-02 17:45:01 +00001828 // if input >= temp goto done
1829 __ comiss(input, temp);
1830 __ j(kAboveEqual, &done);
1831 // if input == NaN goto nan
1832 __ j(kUnordered, &nan);
1833 // output = float-to-int-truncate(input)
Roland Levillain624279f2014-12-04 11:54:28 +00001834 __ cvttss2si(output, input, false);
Roland Levillain3f8f9362014-12-02 17:45:01 +00001835 __ jmp(&done);
1836 __ Bind(&nan);
1837 // output = 0
1838 __ xorl(output, output);
1839 __ Bind(&done);
1840 break;
1841 }
1842
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001843 case Primitive::kPrimDouble: {
1844 // Processing a Dex `double-to-int' instruction.
1845 XmmRegister input = in.AsFpuRegister<XmmRegister>();
1846 CpuRegister output = out.AsRegister<CpuRegister>();
1847 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
1848 Label done, nan;
1849
1850 __ movl(output, Immediate(kPrimIntMax));
1851 // temp = int-to-double(output)
1852 __ cvtsi2sd(temp, output);
1853 // if input >= temp goto done
1854 __ comisd(input, temp);
1855 __ j(kAboveEqual, &done);
1856 // if input == NaN goto nan
1857 __ j(kUnordered, &nan);
1858 // output = double-to-int-truncate(input)
1859 __ cvttsd2si(output, input);
1860 __ jmp(&done);
1861 __ Bind(&nan);
1862 // output = 0
1863 __ xorl(output, output);
1864 __ Bind(&done);
Roland Levillain946e1432014-11-11 17:35:19 +00001865 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001866 }
Roland Levillain946e1432014-11-11 17:35:19 +00001867
1868 default:
1869 LOG(FATAL) << "Unexpected type conversion from " << input_type
1870 << " to " << result_type;
1871 }
1872 break;
1873
Roland Levillaindff1f282014-11-05 14:15:05 +00001874 case Primitive::kPrimLong:
1875 switch (input_type) {
1876 DCHECK(out.IsRegister());
David Brazdil46e2a392015-03-16 17:31:52 +00001877 case Primitive::kPrimBoolean:
1878 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00001879 case Primitive::kPrimByte:
1880 case Primitive::kPrimShort:
1881 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00001882 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001883 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00001884 DCHECK(in.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001885 __ movsxd(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillaindff1f282014-11-05 14:15:05 +00001886 break;
1887
Roland Levillain624279f2014-12-04 11:54:28 +00001888 case Primitive::kPrimFloat: {
1889 // Processing a Dex `float-to-long' instruction.
1890 XmmRegister input = in.AsFpuRegister<XmmRegister>();
1891 CpuRegister output = out.AsRegister<CpuRegister>();
1892 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
1893 Label done, nan;
1894
Mark Mendell92e83bf2015-05-07 11:25:03 -04001895 codegen_->Load64BitValue(output, kPrimLongMax);
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001896 // temp = long-to-float(output)
Roland Levillain624279f2014-12-04 11:54:28 +00001897 __ cvtsi2ss(temp, output, true);
1898 // if input >= temp goto done
1899 __ comiss(input, temp);
1900 __ j(kAboveEqual, &done);
1901 // if input == NaN goto nan
1902 __ j(kUnordered, &nan);
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001903 // output = float-to-long-truncate(input)
Roland Levillain624279f2014-12-04 11:54:28 +00001904 __ cvttss2si(output, input, true);
1905 __ jmp(&done);
1906 __ Bind(&nan);
1907 // output = 0
Mark Mendell92e83bf2015-05-07 11:25:03 -04001908 __ xorl(output, output);
Roland Levillain624279f2014-12-04 11:54:28 +00001909 __ Bind(&done);
1910 break;
1911 }
1912
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001913 case Primitive::kPrimDouble: {
1914 // Processing a Dex `double-to-long' instruction.
1915 XmmRegister input = in.AsFpuRegister<XmmRegister>();
1916 CpuRegister output = out.AsRegister<CpuRegister>();
1917 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
1918 Label done, nan;
1919
Mark Mendell92e83bf2015-05-07 11:25:03 -04001920 codegen_->Load64BitValue(output, kPrimLongMax);
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001921 // temp = long-to-double(output)
1922 __ cvtsi2sd(temp, output, true);
1923 // if input >= temp goto done
1924 __ comisd(input, temp);
1925 __ j(kAboveEqual, &done);
1926 // if input == NaN goto nan
1927 __ j(kUnordered, &nan);
1928 // output = double-to-long-truncate(input)
1929 __ cvttsd2si(output, input, true);
1930 __ jmp(&done);
1931 __ Bind(&nan);
1932 // output = 0
Mark Mendell92e83bf2015-05-07 11:25:03 -04001933 __ xorl(output, output);
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001934 __ Bind(&done);
Roland Levillaindff1f282014-11-05 14:15:05 +00001935 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001936 }
Roland Levillaindff1f282014-11-05 14:15:05 +00001937
1938 default:
1939 LOG(FATAL) << "Unexpected type conversion from " << input_type
1940 << " to " << result_type;
1941 }
1942 break;
1943
Roland Levillain981e4542014-11-14 11:47:14 +00001944 case Primitive::kPrimChar:
1945 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001946 case Primitive::kPrimBoolean:
1947 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00001948 case Primitive::kPrimByte:
1949 case Primitive::kPrimShort:
1950 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00001951 // Processing a Dex `int-to-char' instruction.
1952 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001953 __ movzxw(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain981e4542014-11-14 11:47:14 +00001954 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001955 __ movzxw(out.AsRegister<CpuRegister>(),
Roland Levillain981e4542014-11-14 11:47:14 +00001956 Address(CpuRegister(RSP), in.GetStackIndex()));
1957 } else {
1958 DCHECK(in.GetConstant()->IsIntConstant());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001959 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain981e4542014-11-14 11:47:14 +00001960 Immediate(static_cast<uint16_t>(in.GetConstant()->AsIntConstant()->GetValue())));
1961 }
1962 break;
1963
1964 default:
1965 LOG(FATAL) << "Unexpected type conversion from " << input_type
1966 << " to " << result_type;
1967 }
1968 break;
1969
Roland Levillaindff1f282014-11-05 14:15:05 +00001970 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00001971 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001972 case Primitive::kPrimBoolean:
1973 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001974 case Primitive::kPrimByte:
1975 case Primitive::kPrimShort:
1976 case Primitive::kPrimInt:
1977 case Primitive::kPrimChar:
Roland Levillain6d0e4832014-11-27 18:31:21 +00001978 // Processing a Dex `int-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04001979 if (in.IsRegister()) {
1980 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), false);
1981 } else if (in.IsConstant()) {
1982 int32_t v = in.GetConstant()->AsIntConstant()->GetValue();
1983 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
1984 if (v == 0) {
1985 __ xorps(dest, dest);
1986 } else {
1987 __ movss(dest, codegen_->LiteralFloatAddress(static_cast<float>(v)));
1988 }
1989 } else {
1990 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(),
1991 Address(CpuRegister(RSP), in.GetStackIndex()), false);
1992 }
Roland Levillaincff13742014-11-17 14:32:17 +00001993 break;
1994
1995 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00001996 // Processing a Dex `long-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04001997 if (in.IsRegister()) {
1998 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), true);
1999 } else if (in.IsConstant()) {
2000 int64_t v = in.GetConstant()->AsLongConstant()->GetValue();
2001 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
2002 if (v == 0) {
2003 __ xorps(dest, dest);
2004 } else {
2005 __ movss(dest, codegen_->LiteralFloatAddress(static_cast<float>(v)));
2006 }
2007 } else {
2008 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(),
2009 Address(CpuRegister(RSP), in.GetStackIndex()), true);
2010 }
Roland Levillain6d0e4832014-11-27 18:31:21 +00002011 break;
2012
Roland Levillaincff13742014-11-17 14:32:17 +00002013 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002014 // Processing a Dex `double-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002015 if (in.IsFpuRegister()) {
2016 __ cvtsd2ss(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
2017 } else if (in.IsConstant()) {
2018 double v = in.GetConstant()->AsDoubleConstant()->GetValue();
2019 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
2020 if (bit_cast<int64_t, double>(v) == 0) {
2021 __ xorps(dest, dest);
2022 } else {
2023 __ movss(dest, codegen_->LiteralFloatAddress(static_cast<float>(v)));
2024 }
2025 } else {
2026 __ cvtsd2ss(out.AsFpuRegister<XmmRegister>(),
2027 Address(CpuRegister(RSP), in.GetStackIndex()));
2028 }
Roland Levillaincff13742014-11-17 14:32:17 +00002029 break;
2030
2031 default:
2032 LOG(FATAL) << "Unexpected type conversion from " << input_type
2033 << " to " << result_type;
2034 };
2035 break;
2036
Roland Levillaindff1f282014-11-05 14:15:05 +00002037 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00002038 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002039 case Primitive::kPrimBoolean:
2040 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002041 case Primitive::kPrimByte:
2042 case Primitive::kPrimShort:
2043 case Primitive::kPrimInt:
2044 case Primitive::kPrimChar:
Roland Levillain6d0e4832014-11-27 18:31:21 +00002045 // Processing a Dex `int-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002046 if (in.IsRegister()) {
2047 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), false);
2048 } else if (in.IsConstant()) {
2049 int32_t v = in.GetConstant()->AsIntConstant()->GetValue();
2050 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
2051 if (v == 0) {
2052 __ xorpd(dest, dest);
2053 } else {
2054 __ movsd(dest, codegen_->LiteralDoubleAddress(static_cast<double>(v)));
2055 }
2056 } else {
2057 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(),
2058 Address(CpuRegister(RSP), in.GetStackIndex()), false);
2059 }
Roland Levillaincff13742014-11-17 14:32:17 +00002060 break;
2061
2062 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00002063 // Processing a Dex `long-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002064 if (in.IsRegister()) {
2065 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), true);
2066 } else if (in.IsConstant()) {
2067 int64_t v = in.GetConstant()->AsLongConstant()->GetValue();
2068 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
2069 if (v == 0) {
2070 __ xorpd(dest, dest);
2071 } else {
2072 __ movsd(dest, codegen_->LiteralDoubleAddress(static_cast<double>(v)));
2073 }
2074 } else {
2075 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(),
2076 Address(CpuRegister(RSP), in.GetStackIndex()), true);
2077 }
Roland Levillain647b9ed2014-11-27 12:06:00 +00002078 break;
2079
Roland Levillaincff13742014-11-17 14:32:17 +00002080 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002081 // Processing a Dex `float-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002082 if (in.IsFpuRegister()) {
2083 __ cvtss2sd(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
2084 } else if (in.IsConstant()) {
2085 float v = in.GetConstant()->AsFloatConstant()->GetValue();
2086 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
2087 if (bit_cast<int32_t, float>(v) == 0) {
2088 __ xorpd(dest, dest);
2089 } else {
2090 __ movsd(dest, codegen_->LiteralDoubleAddress(static_cast<double>(v)));
2091 }
2092 } else {
2093 __ cvtss2sd(out.AsFpuRegister<XmmRegister>(),
2094 Address(CpuRegister(RSP), in.GetStackIndex()));
2095 }
Roland Levillaincff13742014-11-17 14:32:17 +00002096 break;
2097
2098 default:
2099 LOG(FATAL) << "Unexpected type conversion from " << input_type
2100 << " to " << result_type;
2101 };
Roland Levillaindff1f282014-11-05 14:15:05 +00002102 break;
2103
2104 default:
2105 LOG(FATAL) << "Unexpected type conversion from " << input_type
2106 << " to " << result_type;
2107 }
2108}
2109
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002110void LocationsBuilderX86_64::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002111 LocationSummary* locations =
2112 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002113 switch (add->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002114 case Primitive::kPrimInt: {
2115 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002116 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
2117 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002118 break;
2119 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002120
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002121 case Primitive::kPrimLong: {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002122 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell09b84632015-02-13 17:48:38 -05002123 // We can use a leaq or addq if the constant can fit in an immediate.
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002124 locations->SetInAt(1, Location::RegisterOrInt32LongConstant(add->InputAt(1)));
Mark Mendell09b84632015-02-13 17:48:38 -05002125 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002126 break;
2127 }
2128
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002129 case Primitive::kPrimDouble:
2130 case Primitive::kPrimFloat: {
2131 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendellf55c3e02015-03-26 21:07:46 -04002132 locations->SetInAt(1, Location::Any());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002133 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002134 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002135 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002136
2137 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002138 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002139 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002140}
2141
2142void InstructionCodeGeneratorX86_64::VisitAdd(HAdd* add) {
2143 LocationSummary* locations = add->GetLocations();
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002144 Location first = locations->InAt(0);
2145 Location second = locations->InAt(1);
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002146 Location out = locations->Out();
Calin Juravle11351682014-10-23 15:38:15 +01002147
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002148 switch (add->GetResultType()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002149 case Primitive::kPrimInt: {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002150 if (second.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002151 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
2152 __ addl(out.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Mark Mendell33bf2452015-05-27 10:08:24 -04002153 } else if (out.AsRegister<Register>() == second.AsRegister<Register>()) {
2154 __ addl(out.AsRegister<CpuRegister>(), first.AsRegister<CpuRegister>());
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002155 } else {
2156 __ leal(out.AsRegister<CpuRegister>(), Address(
2157 first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>(), TIMES_1, 0));
2158 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002159 } else if (second.IsConstant()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002160 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
2161 __ addl(out.AsRegister<CpuRegister>(),
2162 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
2163 } else {
2164 __ leal(out.AsRegister<CpuRegister>(), Address(
2165 first.AsRegister<CpuRegister>(), second.GetConstant()->AsIntConstant()->GetValue()));
2166 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002167 } else {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002168 DCHECK(first.Equals(locations->Out()));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002169 __ addl(first.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), second.GetStackIndex()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002170 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002171 break;
2172 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002173
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002174 case Primitive::kPrimLong: {
Mark Mendell09b84632015-02-13 17:48:38 -05002175 if (second.IsRegister()) {
2176 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
2177 __ addq(out.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Mark Mendell33bf2452015-05-27 10:08:24 -04002178 } else if (out.AsRegister<Register>() == second.AsRegister<Register>()) {
2179 __ addq(out.AsRegister<CpuRegister>(), first.AsRegister<CpuRegister>());
Mark Mendell09b84632015-02-13 17:48:38 -05002180 } else {
2181 __ leaq(out.AsRegister<CpuRegister>(), Address(
2182 first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>(), TIMES_1, 0));
2183 }
2184 } else {
2185 DCHECK(second.IsConstant());
2186 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
2187 int32_t int32_value = Low32Bits(value);
2188 DCHECK_EQ(int32_value, value);
2189 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
2190 __ addq(out.AsRegister<CpuRegister>(), Immediate(int32_value));
2191 } else {
2192 __ leaq(out.AsRegister<CpuRegister>(), Address(
2193 first.AsRegister<CpuRegister>(), int32_value));
2194 }
2195 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002196 break;
2197 }
2198
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002199 case Primitive::kPrimFloat: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04002200 if (second.IsFpuRegister()) {
2201 __ addss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2202 } else if (second.IsConstant()) {
2203 __ addss(first.AsFpuRegister<XmmRegister>(),
2204 codegen_->LiteralFloatAddress(second.GetConstant()->AsFloatConstant()->GetValue()));
2205 } else {
2206 DCHECK(second.IsStackSlot());
2207 __ addss(first.AsFpuRegister<XmmRegister>(),
2208 Address(CpuRegister(RSP), second.GetStackIndex()));
2209 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002210 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002211 }
2212
2213 case Primitive::kPrimDouble: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04002214 if (second.IsFpuRegister()) {
2215 __ addsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2216 } else if (second.IsConstant()) {
2217 __ addsd(first.AsFpuRegister<XmmRegister>(),
2218 codegen_->LiteralDoubleAddress(second.GetConstant()->AsDoubleConstant()->GetValue()));
2219 } else {
2220 DCHECK(second.IsDoubleStackSlot());
2221 __ addsd(first.AsFpuRegister<XmmRegister>(),
2222 Address(CpuRegister(RSP), second.GetStackIndex()));
2223 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002224 break;
2225 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002226
2227 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002228 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002229 }
2230}
2231
2232void LocationsBuilderX86_64::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002233 LocationSummary* locations =
2234 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002235 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002236 case Primitive::kPrimInt: {
2237 locations->SetInAt(0, Location::RequiresRegister());
2238 locations->SetInAt(1, Location::Any());
2239 locations->SetOut(Location::SameAsFirstInput());
2240 break;
2241 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002242 case Primitive::kPrimLong: {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002243 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002244 locations->SetInAt(1, Location::RegisterOrInt32LongConstant(sub->InputAt(1)));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002245 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002246 break;
2247 }
Calin Juravle11351682014-10-23 15:38:15 +01002248 case Primitive::kPrimFloat:
2249 case Primitive::kPrimDouble: {
2250 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendellf55c3e02015-03-26 21:07:46 -04002251 locations->SetInAt(1, Location::Any());
Calin Juravle11351682014-10-23 15:38:15 +01002252 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002253 break;
Calin Juravle11351682014-10-23 15:38:15 +01002254 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002255 default:
Calin Juravle11351682014-10-23 15:38:15 +01002256 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002257 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002258}
2259
2260void InstructionCodeGeneratorX86_64::VisitSub(HSub* sub) {
2261 LocationSummary* locations = sub->GetLocations();
Calin Juravle11351682014-10-23 15:38:15 +01002262 Location first = locations->InAt(0);
2263 Location second = locations->InAt(1);
2264 DCHECK(first.Equals(locations->Out()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002265 switch (sub->GetResultType()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002266 case Primitive::kPrimInt: {
Calin Juravle11351682014-10-23 15:38:15 +01002267 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002268 __ subl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Calin Juravle11351682014-10-23 15:38:15 +01002269 } else if (second.IsConstant()) {
2270 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002271 __ subl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002272 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002273 __ subl(first.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), second.GetStackIndex()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002274 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002275 break;
2276 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002277 case Primitive::kPrimLong: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002278 if (second.IsConstant()) {
2279 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
2280 DCHECK(IsInt<32>(value));
2281 __ subq(first.AsRegister<CpuRegister>(), Immediate(static_cast<int32_t>(value)));
2282 } else {
2283 __ subq(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
2284 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002285 break;
2286 }
2287
Calin Juravle11351682014-10-23 15:38:15 +01002288 case Primitive::kPrimFloat: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04002289 if (second.IsFpuRegister()) {
2290 __ subss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2291 } else if (second.IsConstant()) {
2292 __ subss(first.AsFpuRegister<XmmRegister>(),
2293 codegen_->LiteralFloatAddress(second.GetConstant()->AsFloatConstant()->GetValue()));
2294 } else {
2295 DCHECK(second.IsStackSlot());
2296 __ subss(first.AsFpuRegister<XmmRegister>(),
2297 Address(CpuRegister(RSP), second.GetStackIndex()));
2298 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002299 break;
Calin Juravle11351682014-10-23 15:38:15 +01002300 }
2301
2302 case Primitive::kPrimDouble: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04002303 if (second.IsFpuRegister()) {
2304 __ subsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2305 } else if (second.IsConstant()) {
2306 __ subsd(first.AsFpuRegister<XmmRegister>(),
2307 codegen_->LiteralDoubleAddress(second.GetConstant()->AsDoubleConstant()->GetValue()));
2308 } else {
2309 DCHECK(second.IsDoubleStackSlot());
2310 __ subsd(first.AsFpuRegister<XmmRegister>(),
2311 Address(CpuRegister(RSP), second.GetStackIndex()));
2312 }
Calin Juravle11351682014-10-23 15:38:15 +01002313 break;
2314 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002315
2316 default:
Calin Juravle11351682014-10-23 15:38:15 +01002317 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002318 }
2319}
2320
Calin Juravle34bacdf2014-10-07 20:23:36 +01002321void LocationsBuilderX86_64::VisitMul(HMul* mul) {
2322 LocationSummary* locations =
2323 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
2324 switch (mul->GetResultType()) {
2325 case Primitive::kPrimInt: {
2326 locations->SetInAt(0, Location::RequiresRegister());
2327 locations->SetInAt(1, Location::Any());
2328 locations->SetOut(Location::SameAsFirstInput());
2329 break;
2330 }
2331 case Primitive::kPrimLong: {
2332 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002333 locations->SetInAt(1, Location::RegisterOrInt32LongConstant(mul->InputAt(1)));
2334 if (locations->InAt(1).IsConstant()) {
2335 // Can use 3 operand multiply.
2336 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2337 } else {
2338 locations->SetOut(Location::SameAsFirstInput());
2339 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002340 break;
2341 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01002342 case Primitive::kPrimFloat:
2343 case Primitive::kPrimDouble: {
2344 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendellf55c3e02015-03-26 21:07:46 -04002345 locations->SetInAt(1, Location::Any());
Calin Juravleb5bfa962014-10-21 18:02:24 +01002346 locations->SetOut(Location::SameAsFirstInput());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002347 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002348 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002349
2350 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002351 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002352 }
2353}
2354
2355void InstructionCodeGeneratorX86_64::VisitMul(HMul* mul) {
2356 LocationSummary* locations = mul->GetLocations();
2357 Location first = locations->InAt(0);
2358 Location second = locations->InAt(1);
Calin Juravle34bacdf2014-10-07 20:23:36 +01002359 switch (mul->GetResultType()) {
2360 case Primitive::kPrimInt: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002361 DCHECK(first.Equals(locations->Out()));
Calin Juravle34bacdf2014-10-07 20:23:36 +01002362 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002363 __ imull(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002364 } else if (second.IsConstant()) {
2365 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002366 __ imull(first.AsRegister<CpuRegister>(), imm);
Calin Juravle34bacdf2014-10-07 20:23:36 +01002367 } else {
2368 DCHECK(second.IsStackSlot());
Roland Levillain199f3362014-11-27 17:15:16 +00002369 __ imull(first.AsRegister<CpuRegister>(),
2370 Address(CpuRegister(RSP), second.GetStackIndex()));
Calin Juravle34bacdf2014-10-07 20:23:36 +01002371 }
2372 break;
2373 }
2374 case Primitive::kPrimLong: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002375 if (second.IsConstant()) {
2376 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
2377 DCHECK(IsInt<32>(value));
2378 __ imulq(locations->Out().AsRegister<CpuRegister>(),
2379 first.AsRegister<CpuRegister>(),
2380 Immediate(static_cast<int32_t>(value)));
2381 } else {
2382 DCHECK(first.Equals(locations->Out()));
2383 __ imulq(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
2384 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002385 break;
2386 }
2387
Calin Juravleb5bfa962014-10-21 18:02:24 +01002388 case Primitive::kPrimFloat: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002389 DCHECK(first.Equals(locations->Out()));
Mark Mendellf55c3e02015-03-26 21:07:46 -04002390 if (second.IsFpuRegister()) {
2391 __ mulss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2392 } else if (second.IsConstant()) {
2393 __ mulss(first.AsFpuRegister<XmmRegister>(),
2394 codegen_->LiteralFloatAddress(second.GetConstant()->AsFloatConstant()->GetValue()));
2395 } else {
2396 DCHECK(second.IsStackSlot());
2397 __ mulss(first.AsFpuRegister<XmmRegister>(),
2398 Address(CpuRegister(RSP), second.GetStackIndex()));
2399 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002400 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002401 }
2402
2403 case Primitive::kPrimDouble: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002404 DCHECK(first.Equals(locations->Out()));
Mark Mendellf55c3e02015-03-26 21:07:46 -04002405 if (second.IsFpuRegister()) {
2406 __ mulsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2407 } else if (second.IsConstant()) {
2408 __ mulsd(first.AsFpuRegister<XmmRegister>(),
2409 codegen_->LiteralDoubleAddress(second.GetConstant()->AsDoubleConstant()->GetValue()));
2410 } else {
2411 DCHECK(second.IsDoubleStackSlot());
2412 __ mulsd(first.AsFpuRegister<XmmRegister>(),
2413 Address(CpuRegister(RSP), second.GetStackIndex()));
2414 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01002415 break;
2416 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002417
2418 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002419 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002420 }
2421}
2422
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002423void InstructionCodeGeneratorX86_64::PushOntoFPStack(Location source, uint32_t temp_offset,
2424 uint32_t stack_adjustment, bool is_float) {
2425 if (source.IsStackSlot()) {
2426 DCHECK(is_float);
2427 __ flds(Address(CpuRegister(RSP), source.GetStackIndex() + stack_adjustment));
2428 } else if (source.IsDoubleStackSlot()) {
2429 DCHECK(!is_float);
2430 __ fldl(Address(CpuRegister(RSP), source.GetStackIndex() + stack_adjustment));
2431 } else {
2432 // Write the value to the temporary location on the stack and load to FP stack.
2433 if (is_float) {
2434 Location stack_temp = Location::StackSlot(temp_offset);
2435 codegen_->Move(stack_temp, source);
2436 __ flds(Address(CpuRegister(RSP), temp_offset));
2437 } else {
2438 Location stack_temp = Location::DoubleStackSlot(temp_offset);
2439 codegen_->Move(stack_temp, source);
2440 __ fldl(Address(CpuRegister(RSP), temp_offset));
2441 }
2442 }
2443}
2444
2445void InstructionCodeGeneratorX86_64::GenerateRemFP(HRem *rem) {
2446 Primitive::Type type = rem->GetResultType();
2447 bool is_float = type == Primitive::kPrimFloat;
2448 size_t elem_size = Primitive::ComponentSize(type);
2449 LocationSummary* locations = rem->GetLocations();
2450 Location first = locations->InAt(0);
2451 Location second = locations->InAt(1);
2452 Location out = locations->Out();
2453
2454 // Create stack space for 2 elements.
2455 // TODO: enhance register allocator to ask for stack temporaries.
2456 __ subq(CpuRegister(RSP), Immediate(2 * elem_size));
2457
2458 // Load the values to the FP stack in reverse order, using temporaries if needed.
2459 PushOntoFPStack(second, elem_size, 2 * elem_size, is_float);
2460 PushOntoFPStack(first, 0, 2 * elem_size, is_float);
2461
2462 // Loop doing FPREM until we stabilize.
2463 Label retry;
2464 __ Bind(&retry);
2465 __ fprem();
2466
2467 // Move FP status to AX.
2468 __ fstsw();
2469
2470 // And see if the argument reduction is complete. This is signaled by the
2471 // C2 FPU flag bit set to 0.
2472 __ andl(CpuRegister(RAX), Immediate(kC2ConditionMask));
2473 __ j(kNotEqual, &retry);
2474
2475 // We have settled on the final value. Retrieve it into an XMM register.
2476 // Store FP top of stack to real stack.
2477 if (is_float) {
2478 __ fsts(Address(CpuRegister(RSP), 0));
2479 } else {
2480 __ fstl(Address(CpuRegister(RSP), 0));
2481 }
2482
2483 // Pop the 2 items from the FP stack.
2484 __ fucompp();
2485
2486 // Load the value from the stack into an XMM register.
2487 DCHECK(out.IsFpuRegister()) << out;
2488 if (is_float) {
2489 __ movss(out.AsFpuRegister<XmmRegister>(), Address(CpuRegister(RSP), 0));
2490 } else {
2491 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(CpuRegister(RSP), 0));
2492 }
2493
2494 // And remove the temporary stack space we allocated.
2495 __ addq(CpuRegister(RSP), Immediate(2 * elem_size));
2496}
2497
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002498void InstructionCodeGeneratorX86_64::DivRemOneOrMinusOne(HBinaryOperation* instruction) {
2499 DCHECK(instruction->IsDiv() || instruction->IsRem());
2500
2501 LocationSummary* locations = instruction->GetLocations();
2502 Location second = locations->InAt(1);
2503 DCHECK(second.IsConstant());
2504
2505 CpuRegister output_register = locations->Out().AsRegister<CpuRegister>();
2506 CpuRegister input_register = locations->InAt(0).AsRegister<CpuRegister>();
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002507 int64_t imm = Int64FromConstant(second.GetConstant());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002508
2509 DCHECK(imm == 1 || imm == -1);
2510
2511 switch (instruction->GetResultType()) {
2512 case Primitive::kPrimInt: {
2513 if (instruction->IsRem()) {
2514 __ xorl(output_register, output_register);
2515 } else {
2516 __ movl(output_register, input_register);
2517 if (imm == -1) {
2518 __ negl(output_register);
2519 }
2520 }
2521 break;
2522 }
2523
2524 case Primitive::kPrimLong: {
2525 if (instruction->IsRem()) {
Mark Mendell92e83bf2015-05-07 11:25:03 -04002526 __ xorl(output_register, output_register);
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002527 } else {
2528 __ movq(output_register, input_register);
2529 if (imm == -1) {
2530 __ negq(output_register);
2531 }
2532 }
2533 break;
2534 }
2535
2536 default:
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002537 LOG(FATAL) << "Unexpected type for div by (-)1 " << instruction->GetResultType();
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002538 }
2539}
2540
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002541void InstructionCodeGeneratorX86_64::DivByPowerOfTwo(HDiv* instruction) {
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002542 LocationSummary* locations = instruction->GetLocations();
2543 Location second = locations->InAt(1);
2544
2545 CpuRegister output_register = locations->Out().AsRegister<CpuRegister>();
2546 CpuRegister numerator = locations->InAt(0).AsRegister<CpuRegister>();
2547
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002548 int64_t imm = Int64FromConstant(second.GetConstant());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002549
2550 DCHECK(IsPowerOfTwo(std::abs(imm)));
2551
2552 CpuRegister tmp = locations->GetTemp(0).AsRegister<CpuRegister>();
2553
2554 if (instruction->GetResultType() == Primitive::kPrimInt) {
2555 __ leal(tmp, Address(numerator, std::abs(imm) - 1));
2556 __ testl(numerator, numerator);
2557 __ cmov(kGreaterEqual, tmp, numerator);
2558 int shift = CTZ(imm);
2559 __ sarl(tmp, Immediate(shift));
2560
2561 if (imm < 0) {
2562 __ negl(tmp);
2563 }
2564
2565 __ movl(output_register, tmp);
2566 } else {
2567 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
2568 CpuRegister rdx = locations->GetTemp(0).AsRegister<CpuRegister>();
2569
Mark Mendell92e83bf2015-05-07 11:25:03 -04002570 codegen_->Load64BitValue(rdx, std::abs(imm) - 1);
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002571 __ addq(rdx, numerator);
2572 __ testq(numerator, numerator);
2573 __ cmov(kGreaterEqual, rdx, numerator);
2574 int shift = CTZ(imm);
2575 __ sarq(rdx, Immediate(shift));
2576
2577 if (imm < 0) {
2578 __ negq(rdx);
2579 }
2580
2581 __ movq(output_register, rdx);
2582 }
2583}
2584
2585void InstructionCodeGeneratorX86_64::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) {
2586 DCHECK(instruction->IsDiv() || instruction->IsRem());
2587
2588 LocationSummary* locations = instruction->GetLocations();
2589 Location second = locations->InAt(1);
2590
2591 CpuRegister numerator = instruction->IsDiv() ? locations->GetTemp(1).AsRegister<CpuRegister>()
2592 : locations->GetTemp(0).AsRegister<CpuRegister>();
2593 CpuRegister eax = locations->InAt(0).AsRegister<CpuRegister>();
2594 CpuRegister edx = instruction->IsDiv() ? locations->GetTemp(0).AsRegister<CpuRegister>()
2595 : locations->Out().AsRegister<CpuRegister>();
2596 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
2597
2598 DCHECK_EQ(RAX, eax.AsRegister());
2599 DCHECK_EQ(RDX, edx.AsRegister());
2600 if (instruction->IsDiv()) {
2601 DCHECK_EQ(RAX, out.AsRegister());
2602 } else {
2603 DCHECK_EQ(RDX, out.AsRegister());
2604 }
2605
2606 int64_t magic;
2607 int shift;
2608
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002609 // TODO: can these branches be written as one?
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002610 if (instruction->GetResultType() == Primitive::kPrimInt) {
2611 int imm = second.GetConstant()->AsIntConstant()->GetValue();
2612
2613 CalculateMagicAndShiftForDivRem(imm, false /* is_long */, &magic, &shift);
2614
2615 __ movl(numerator, eax);
2616
2617 Label no_div;
2618 Label end;
2619 __ testl(eax, eax);
2620 __ j(kNotEqual, &no_div);
2621
2622 __ xorl(out, out);
2623 __ jmp(&end);
2624
2625 __ Bind(&no_div);
2626
2627 __ movl(eax, Immediate(magic));
2628 __ imull(numerator);
2629
2630 if (imm > 0 && magic < 0) {
2631 __ addl(edx, numerator);
2632 } else if (imm < 0 && magic > 0) {
2633 __ subl(edx, numerator);
2634 }
2635
2636 if (shift != 0) {
2637 __ sarl(edx, Immediate(shift));
2638 }
2639
2640 __ movl(eax, edx);
2641 __ shrl(edx, Immediate(31));
2642 __ addl(edx, eax);
2643
2644 if (instruction->IsRem()) {
2645 __ movl(eax, numerator);
2646 __ imull(edx, Immediate(imm));
2647 __ subl(eax, edx);
2648 __ movl(edx, eax);
2649 } else {
2650 __ movl(eax, edx);
2651 }
2652 __ Bind(&end);
2653 } else {
2654 int64_t imm = second.GetConstant()->AsLongConstant()->GetValue();
2655
2656 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
2657
2658 CpuRegister rax = eax;
2659 CpuRegister rdx = edx;
2660
2661 CalculateMagicAndShiftForDivRem(imm, true /* is_long */, &magic, &shift);
2662
2663 // Save the numerator.
2664 __ movq(numerator, rax);
2665
2666 // RAX = magic
Mark Mendell92e83bf2015-05-07 11:25:03 -04002667 codegen_->Load64BitValue(rax, magic);
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002668
2669 // RDX:RAX = magic * numerator
2670 __ imulq(numerator);
2671
2672 if (imm > 0 && magic < 0) {
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002673 // RDX += numerator
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002674 __ addq(rdx, numerator);
2675 } else if (imm < 0 && magic > 0) {
2676 // RDX -= numerator
2677 __ subq(rdx, numerator);
2678 }
2679
2680 // Shift if needed.
2681 if (shift != 0) {
2682 __ sarq(rdx, Immediate(shift));
2683 }
2684
2685 // RDX += 1 if RDX < 0
2686 __ movq(rax, rdx);
2687 __ shrq(rdx, Immediate(63));
2688 __ addq(rdx, rax);
2689
2690 if (instruction->IsRem()) {
2691 __ movq(rax, numerator);
2692
2693 if (IsInt<32>(imm)) {
2694 __ imulq(rdx, Immediate(static_cast<int32_t>(imm)));
2695 } else {
Mark Mendell92e83bf2015-05-07 11:25:03 -04002696 __ imulq(rdx, codegen_->LiteralInt64Address(imm));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002697 }
2698
2699 __ subq(rax, rdx);
2700 __ movq(rdx, rax);
2701 } else {
2702 __ movq(rax, rdx);
2703 }
2704 }
2705}
2706
Calin Juravlebacfec32014-11-14 15:54:36 +00002707void InstructionCodeGeneratorX86_64::GenerateDivRemIntegral(HBinaryOperation* instruction) {
2708 DCHECK(instruction->IsDiv() || instruction->IsRem());
2709 Primitive::Type type = instruction->GetResultType();
2710 DCHECK(type == Primitive::kPrimInt || Primitive::kPrimLong);
2711
2712 bool is_div = instruction->IsDiv();
2713 LocationSummary* locations = instruction->GetLocations();
2714
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002715 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
2716 Location second = locations->InAt(1);
Calin Juravlebacfec32014-11-14 15:54:36 +00002717
Roland Levillain271ab9c2014-11-27 15:23:57 +00002718 DCHECK_EQ(RAX, locations->InAt(0).AsRegister<CpuRegister>().AsRegister());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002719 DCHECK_EQ(is_div ? RAX : RDX, out.AsRegister());
Calin Juravlebacfec32014-11-14 15:54:36 +00002720
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002721 if (second.IsConstant()) {
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002722 int64_t imm = Int64FromConstant(second.GetConstant());
Calin Juravlebacfec32014-11-14 15:54:36 +00002723
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002724 if (imm == 0) {
2725 // Do not generate anything. DivZeroCheck would prevent any code to be executed.
2726 } else if (imm == 1 || imm == -1) {
2727 DivRemOneOrMinusOne(instruction);
2728 } else if (instruction->IsDiv() && IsPowerOfTwo(std::abs(imm))) {
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002729 DivByPowerOfTwo(instruction->AsDiv());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002730 } else {
2731 DCHECK(imm <= -2 || imm >= 2);
2732 GenerateDivRemWithAnyConstant(instruction);
2733 }
Calin Juravlebacfec32014-11-14 15:54:36 +00002734 } else {
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002735 SlowPathCodeX86_64* slow_path =
2736 new (GetGraph()->GetArena()) DivRemMinusOneSlowPathX86_64(
2737 out.AsRegister(), type, is_div);
2738 codegen_->AddSlowPath(slow_path);
Calin Juravlebacfec32014-11-14 15:54:36 +00002739
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002740 CpuRegister second_reg = second.AsRegister<CpuRegister>();
2741 // 0x80000000(00000000)/-1 triggers an arithmetic exception!
2742 // Dividing by -1 is actually negation and -0x800000000(00000000) = 0x80000000(00000000)
2743 // so it's safe to just use negl instead of more complex comparisons.
2744 if (type == Primitive::kPrimInt) {
2745 __ cmpl(second_reg, Immediate(-1));
2746 __ j(kEqual, slow_path->GetEntryLabel());
2747 // edx:eax <- sign-extended of eax
2748 __ cdq();
2749 // eax = quotient, edx = remainder
2750 __ idivl(second_reg);
2751 } else {
2752 __ cmpq(second_reg, Immediate(-1));
2753 __ j(kEqual, slow_path->GetEntryLabel());
2754 // rdx:rax <- sign-extended of rax
2755 __ cqo();
2756 // rax = quotient, rdx = remainder
2757 __ idivq(second_reg);
2758 }
2759 __ Bind(slow_path->GetExitLabel());
2760 }
Calin Juravlebacfec32014-11-14 15:54:36 +00002761}
2762
Calin Juravle7c4954d2014-10-28 16:57:40 +00002763void LocationsBuilderX86_64::VisitDiv(HDiv* div) {
2764 LocationSummary* locations =
2765 new (GetGraph()->GetArena()) LocationSummary(div, LocationSummary::kNoCall);
2766 switch (div->GetResultType()) {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002767 case Primitive::kPrimInt:
2768 case Primitive::kPrimLong: {
Calin Juravled0d48522014-11-04 16:40:20 +00002769 locations->SetInAt(0, Location::RegisterLocation(RAX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002770 locations->SetInAt(1, Location::RegisterOrConstant(div->InputAt(1)));
Calin Juravled0d48522014-11-04 16:40:20 +00002771 locations->SetOut(Location::SameAsFirstInput());
2772 // Intel uses edx:eax as the dividend.
2773 locations->AddTemp(Location::RegisterLocation(RDX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002774 // We need to save the numerator while we tweak rax and rdx. As we are using imul in a way
2775 // which enforces results to be in RAX and RDX, things are simpler if we use RDX also as
2776 // output and request another temp.
2777 if (div->InputAt(1)->IsConstant()) {
2778 locations->AddTemp(Location::RequiresRegister());
2779 }
Calin Juravled0d48522014-11-04 16:40:20 +00002780 break;
2781 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002782
Calin Juravle7c4954d2014-10-28 16:57:40 +00002783 case Primitive::kPrimFloat:
2784 case Primitive::kPrimDouble: {
2785 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendellf55c3e02015-03-26 21:07:46 -04002786 locations->SetInAt(1, Location::Any());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002787 locations->SetOut(Location::SameAsFirstInput());
2788 break;
2789 }
2790
2791 default:
2792 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2793 }
2794}
2795
2796void InstructionCodeGeneratorX86_64::VisitDiv(HDiv* div) {
2797 LocationSummary* locations = div->GetLocations();
2798 Location first = locations->InAt(0);
2799 Location second = locations->InAt(1);
2800 DCHECK(first.Equals(locations->Out()));
2801
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002802 Primitive::Type type = div->GetResultType();
2803 switch (type) {
2804 case Primitive::kPrimInt:
2805 case Primitive::kPrimLong: {
Calin Juravlebacfec32014-11-14 15:54:36 +00002806 GenerateDivRemIntegral(div);
Calin Juravled0d48522014-11-04 16:40:20 +00002807 break;
2808 }
2809
Calin Juravle7c4954d2014-10-28 16:57:40 +00002810 case Primitive::kPrimFloat: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04002811 if (second.IsFpuRegister()) {
2812 __ divss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2813 } else if (second.IsConstant()) {
2814 __ divss(first.AsFpuRegister<XmmRegister>(),
2815 codegen_->LiteralFloatAddress(second.GetConstant()->AsFloatConstant()->GetValue()));
2816 } else {
2817 DCHECK(second.IsStackSlot());
2818 __ divss(first.AsFpuRegister<XmmRegister>(),
2819 Address(CpuRegister(RSP), second.GetStackIndex()));
2820 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00002821 break;
2822 }
2823
2824 case Primitive::kPrimDouble: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04002825 if (second.IsFpuRegister()) {
2826 __ divsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2827 } else if (second.IsConstant()) {
2828 __ divsd(first.AsFpuRegister<XmmRegister>(),
2829 codegen_->LiteralDoubleAddress(second.GetConstant()->AsDoubleConstant()->GetValue()));
2830 } else {
2831 DCHECK(second.IsDoubleStackSlot());
2832 __ divsd(first.AsFpuRegister<XmmRegister>(),
2833 Address(CpuRegister(RSP), second.GetStackIndex()));
2834 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00002835 break;
2836 }
2837
2838 default:
2839 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2840 }
2841}
2842
Calin Juravlebacfec32014-11-14 15:54:36 +00002843void LocationsBuilderX86_64::VisitRem(HRem* rem) {
Calin Juravled2ec87d2014-12-08 14:24:46 +00002844 Primitive::Type type = rem->GetResultType();
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002845 LocationSummary* locations =
2846 new (GetGraph()->GetArena()) LocationSummary(rem, LocationSummary::kNoCall);
Calin Juravled2ec87d2014-12-08 14:24:46 +00002847
2848 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00002849 case Primitive::kPrimInt:
2850 case Primitive::kPrimLong: {
2851 locations->SetInAt(0, Location::RegisterLocation(RAX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002852 locations->SetInAt(1, Location::RegisterOrConstant(rem->InputAt(1)));
Calin Juravlebacfec32014-11-14 15:54:36 +00002853 // Intel uses rdx:rax as the dividend and puts the remainder in rdx
2854 locations->SetOut(Location::RegisterLocation(RDX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002855 // We need to save the numerator while we tweak eax and edx. As we are using imul in a way
2856 // which enforces results to be in RAX and RDX, things are simpler if we use EAX also as
2857 // output and request another temp.
2858 if (rem->InputAt(1)->IsConstant()) {
2859 locations->AddTemp(Location::RequiresRegister());
2860 }
Calin Juravlebacfec32014-11-14 15:54:36 +00002861 break;
2862 }
2863
2864 case Primitive::kPrimFloat:
2865 case Primitive::kPrimDouble: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002866 locations->SetInAt(0, Location::Any());
2867 locations->SetInAt(1, Location::Any());
2868 locations->SetOut(Location::RequiresFpuRegister());
2869 locations->AddTemp(Location::RegisterLocation(RAX));
Calin Juravlebacfec32014-11-14 15:54:36 +00002870 break;
2871 }
2872
2873 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00002874 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00002875 }
2876}
2877
2878void InstructionCodeGeneratorX86_64::VisitRem(HRem* rem) {
2879 Primitive::Type type = rem->GetResultType();
2880 switch (type) {
2881 case Primitive::kPrimInt:
2882 case Primitive::kPrimLong: {
2883 GenerateDivRemIntegral(rem);
2884 break;
2885 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002886 case Primitive::kPrimFloat:
Calin Juravled2ec87d2014-12-08 14:24:46 +00002887 case Primitive::kPrimDouble: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002888 GenerateRemFP(rem);
Calin Juravled2ec87d2014-12-08 14:24:46 +00002889 break;
2890 }
Calin Juravlebacfec32014-11-14 15:54:36 +00002891 default:
2892 LOG(FATAL) << "Unexpected rem type " << rem->GetResultType();
2893 }
2894}
2895
Calin Juravled0d48522014-11-04 16:40:20 +00002896void LocationsBuilderX86_64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
2897 LocationSummary* locations =
2898 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
2899 locations->SetInAt(0, Location::Any());
2900 if (instruction->HasUses()) {
2901 locations->SetOut(Location::SameAsFirstInput());
2902 }
2903}
2904
2905void InstructionCodeGeneratorX86_64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
2906 SlowPathCodeX86_64* slow_path =
2907 new (GetGraph()->GetArena()) DivZeroCheckSlowPathX86_64(instruction);
2908 codegen_->AddSlowPath(slow_path);
2909
2910 LocationSummary* locations = instruction->GetLocations();
2911 Location value = locations->InAt(0);
2912
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002913 switch (instruction->GetType()) {
2914 case Primitive::kPrimInt: {
2915 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002916 __ testl(value.AsRegister<CpuRegister>(), value.AsRegister<CpuRegister>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002917 __ j(kEqual, slow_path->GetEntryLabel());
2918 } else if (value.IsStackSlot()) {
2919 __ cmpl(Address(CpuRegister(RSP), value.GetStackIndex()), Immediate(0));
2920 __ j(kEqual, slow_path->GetEntryLabel());
2921 } else {
2922 DCHECK(value.IsConstant()) << value;
2923 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
2924 __ jmp(slow_path->GetEntryLabel());
2925 }
2926 }
2927 break;
Calin Juravled0d48522014-11-04 16:40:20 +00002928 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002929 case Primitive::kPrimLong: {
2930 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002931 __ testq(value.AsRegister<CpuRegister>(), value.AsRegister<CpuRegister>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002932 __ j(kEqual, slow_path->GetEntryLabel());
2933 } else if (value.IsDoubleStackSlot()) {
2934 __ cmpq(Address(CpuRegister(RSP), value.GetStackIndex()), Immediate(0));
2935 __ j(kEqual, slow_path->GetEntryLabel());
2936 } else {
2937 DCHECK(value.IsConstant()) << value;
2938 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
2939 __ jmp(slow_path->GetEntryLabel());
2940 }
2941 }
2942 break;
2943 }
2944 default:
2945 LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
Calin Juravled0d48522014-11-04 16:40:20 +00002946 }
Calin Juravled0d48522014-11-04 16:40:20 +00002947}
2948
Calin Juravle9aec02f2014-11-18 23:06:35 +00002949void LocationsBuilderX86_64::HandleShift(HBinaryOperation* op) {
2950 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
2951
2952 LocationSummary* locations =
2953 new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
2954
2955 switch (op->GetResultType()) {
2956 case Primitive::kPrimInt:
2957 case Primitive::kPrimLong: {
2958 locations->SetInAt(0, Location::RequiresRegister());
2959 // The shift count needs to be in CL.
2960 locations->SetInAt(1, Location::ByteRegisterOrConstant(RCX, op->InputAt(1)));
2961 locations->SetOut(Location::SameAsFirstInput());
2962 break;
2963 }
2964 default:
2965 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
2966 }
2967}
2968
2969void InstructionCodeGeneratorX86_64::HandleShift(HBinaryOperation* op) {
2970 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
2971
2972 LocationSummary* locations = op->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002973 CpuRegister first_reg = locations->InAt(0).AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002974 Location second = locations->InAt(1);
2975
2976 switch (op->GetResultType()) {
2977 case Primitive::kPrimInt: {
2978 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002979 CpuRegister second_reg = second.AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002980 if (op->IsShl()) {
2981 __ shll(first_reg, second_reg);
2982 } else if (op->IsShr()) {
2983 __ sarl(first_reg, second_reg);
2984 } else {
2985 __ shrl(first_reg, second_reg);
2986 }
2987 } else {
Nicolas Geoffray486cc192014-12-08 18:00:55 +00002988 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxIntShiftValue);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002989 if (op->IsShl()) {
2990 __ shll(first_reg, imm);
2991 } else if (op->IsShr()) {
2992 __ sarl(first_reg, imm);
2993 } else {
2994 __ shrl(first_reg, imm);
2995 }
2996 }
2997 break;
2998 }
2999 case Primitive::kPrimLong: {
3000 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003001 CpuRegister second_reg = second.AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003002 if (op->IsShl()) {
3003 __ shlq(first_reg, second_reg);
3004 } else if (op->IsShr()) {
3005 __ sarq(first_reg, second_reg);
3006 } else {
3007 __ shrq(first_reg, second_reg);
3008 }
3009 } else {
Nicolas Geoffray486cc192014-12-08 18:00:55 +00003010 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxLongShiftValue);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003011 if (op->IsShl()) {
3012 __ shlq(first_reg, imm);
3013 } else if (op->IsShr()) {
3014 __ sarq(first_reg, imm);
3015 } else {
3016 __ shrq(first_reg, imm);
3017 }
3018 }
3019 break;
3020 }
3021 default:
3022 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
3023 }
3024}
3025
3026void LocationsBuilderX86_64::VisitShl(HShl* shl) {
3027 HandleShift(shl);
3028}
3029
3030void InstructionCodeGeneratorX86_64::VisitShl(HShl* shl) {
3031 HandleShift(shl);
3032}
3033
3034void LocationsBuilderX86_64::VisitShr(HShr* shr) {
3035 HandleShift(shr);
3036}
3037
3038void InstructionCodeGeneratorX86_64::VisitShr(HShr* shr) {
3039 HandleShift(shr);
3040}
3041
3042void LocationsBuilderX86_64::VisitUShr(HUShr* ushr) {
3043 HandleShift(ushr);
3044}
3045
3046void InstructionCodeGeneratorX86_64::VisitUShr(HUShr* ushr) {
3047 HandleShift(ushr);
3048}
3049
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003050void LocationsBuilderX86_64::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003051 LocationSummary* locations =
3052 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01003053 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003054 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Nicolas Geoffray69aa6012015-06-09 10:34:25 +01003055 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003056 locations->SetOut(Location::RegisterLocation(RAX));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003057}
3058
3059void InstructionCodeGeneratorX86_64::VisitNewInstance(HNewInstance* instruction) {
3060 InvokeRuntimeCallingConvention calling_convention;
Mark Mendell92e83bf2015-05-07 11:25:03 -04003061 codegen_->Load64BitValue(CpuRegister(calling_convention.GetRegisterAt(0)),
3062 instruction->GetTypeIndex());
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +00003063 __ gs()->call(
3064 Address::Absolute(GetThreadOffset<kX86_64WordSize>(instruction->GetEntrypoint()), true));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003065
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01003066 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray39468442014-09-02 15:17:15 +01003067 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003068}
3069
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003070void LocationsBuilderX86_64::VisitNewArray(HNewArray* instruction) {
3071 LocationSummary* locations =
3072 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
3073 InvokeRuntimeCallingConvention calling_convention;
3074 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003075 locations->SetOut(Location::RegisterLocation(RAX));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08003076 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray69aa6012015-06-09 10:34:25 +01003077 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003078}
3079
3080void InstructionCodeGeneratorX86_64::VisitNewArray(HNewArray* instruction) {
3081 InvokeRuntimeCallingConvention calling_convention;
Mark Mendell92e83bf2015-05-07 11:25:03 -04003082 codegen_->Load64BitValue(CpuRegister(calling_convention.GetRegisterAt(0)),
3083 instruction->GetTypeIndex());
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003084
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +00003085 __ gs()->call(
3086 Address::Absolute(GetThreadOffset<kX86_64WordSize>(instruction->GetEntrypoint()), true));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003087
3088 DCHECK(!codegen_->IsLeafMethod());
3089 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3090}
3091
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003092void LocationsBuilderX86_64::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003093 LocationSummary* locations =
3094 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003095 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
3096 if (location.IsStackSlot()) {
3097 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
3098 } else if (location.IsDoubleStackSlot()) {
3099 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
3100 }
3101 locations->SetOut(location);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003102}
3103
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01003104void InstructionCodeGeneratorX86_64::VisitParameterValue(
3105 HParameterValue* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003106 // Nothing to do, the parameter is already at its location.
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01003107}
3108
3109void LocationsBuilderX86_64::VisitCurrentMethod(HCurrentMethod* instruction) {
3110 LocationSummary* locations =
3111 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3112 locations->SetOut(Location::RegisterLocation(kMethodRegisterArgument));
3113}
3114
3115void InstructionCodeGeneratorX86_64::VisitCurrentMethod(
3116 HCurrentMethod* instruction ATTRIBUTE_UNUSED) {
3117 // Nothing to do, the method is already at its location.
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003118}
3119
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003120void LocationsBuilderX86_64::VisitNot(HNot* not_) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003121 LocationSummary* locations =
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003122 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003123 locations->SetInAt(0, Location::RequiresRegister());
3124 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003125}
3126
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003127void InstructionCodeGeneratorX86_64::VisitNot(HNot* not_) {
3128 LocationSummary* locations = not_->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003129 DCHECK_EQ(locations->InAt(0).AsRegister<CpuRegister>().AsRegister(),
3130 locations->Out().AsRegister<CpuRegister>().AsRegister());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003131 Location out = locations->Out();
Nicolas Geoffrayd8ef2e92015-02-24 16:02:06 +00003132 switch (not_->GetResultType()) {
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003133 case Primitive::kPrimInt:
Roland Levillain271ab9c2014-11-27 15:23:57 +00003134 __ notl(out.AsRegister<CpuRegister>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003135 break;
3136
3137 case Primitive::kPrimLong:
Roland Levillain271ab9c2014-11-27 15:23:57 +00003138 __ notq(out.AsRegister<CpuRegister>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003139 break;
3140
3141 default:
3142 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
3143 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003144}
3145
David Brazdil66d126e2015-04-03 16:02:44 +01003146void LocationsBuilderX86_64::VisitBooleanNot(HBooleanNot* bool_not) {
3147 LocationSummary* locations =
3148 new (GetGraph()->GetArena()) LocationSummary(bool_not, LocationSummary::kNoCall);
3149 locations->SetInAt(0, Location::RequiresRegister());
3150 locations->SetOut(Location::SameAsFirstInput());
3151}
3152
3153void InstructionCodeGeneratorX86_64::VisitBooleanNot(HBooleanNot* bool_not) {
David Brazdil66d126e2015-04-03 16:02:44 +01003154 LocationSummary* locations = bool_not->GetLocations();
3155 DCHECK_EQ(locations->InAt(0).AsRegister<CpuRegister>().AsRegister(),
3156 locations->Out().AsRegister<CpuRegister>().AsRegister());
3157 Location out = locations->Out();
3158 __ xorl(out.AsRegister<CpuRegister>(), Immediate(1));
3159}
3160
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003161void LocationsBuilderX86_64::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003162 LocationSummary* locations =
3163 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003164 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
3165 locations->SetInAt(i, Location::Any());
3166 }
3167 locations->SetOut(Location::Any());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003168}
3169
3170void InstructionCodeGeneratorX86_64::VisitPhi(HPhi* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003171 UNUSED(instruction);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003172 LOG(FATAL) << "Unimplemented";
3173}
3174
Calin Juravle52c48962014-12-16 17:02:57 +00003175void InstructionCodeGeneratorX86_64::GenerateMemoryBarrier(MemBarrierKind kind) {
3176 /*
3177 * According to the JSR-133 Cookbook, for x86 only StoreLoad/AnyAny barriers need memory fence.
3178 * All other barriers (LoadAny, AnyStore, StoreStore) are nops due to the x86 memory model.
3179 * For those cases, all we need to ensure is that there is a scheduling barrier in place.
3180 */
3181 switch (kind) {
3182 case MemBarrierKind::kAnyAny: {
3183 __ mfence();
3184 break;
3185 }
3186 case MemBarrierKind::kAnyStore:
3187 case MemBarrierKind::kLoadAny:
3188 case MemBarrierKind::kStoreStore: {
3189 // nop
3190 break;
3191 }
3192 default:
3193 LOG(FATAL) << "Unexpected memory barier " << kind;
3194 }
3195}
3196
3197void LocationsBuilderX86_64::HandleFieldGet(HInstruction* instruction) {
3198 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
3199
Nicolas Geoffray39468442014-09-02 15:17:15 +01003200 LocationSummary* locations =
3201 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Calin Juravle52c48962014-12-16 17:02:57 +00003202 locations->SetInAt(0, Location::RequiresRegister());
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003203 if (Primitive::IsFloatingPointType(instruction->GetType())) {
3204 locations->SetOut(Location::RequiresFpuRegister());
3205 } else {
3206 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3207 }
Calin Juravle52c48962014-12-16 17:02:57 +00003208}
3209
3210void InstructionCodeGeneratorX86_64::HandleFieldGet(HInstruction* instruction,
3211 const FieldInfo& field_info) {
3212 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
3213
3214 LocationSummary* locations = instruction->GetLocations();
3215 CpuRegister base = locations->InAt(0).AsRegister<CpuRegister>();
3216 Location out = locations->Out();
3217 bool is_volatile = field_info.IsVolatile();
3218 Primitive::Type field_type = field_info.GetFieldType();
3219 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
3220
3221 switch (field_type) {
3222 case Primitive::kPrimBoolean: {
3223 __ movzxb(out.AsRegister<CpuRegister>(), Address(base, offset));
3224 break;
3225 }
3226
3227 case Primitive::kPrimByte: {
3228 __ movsxb(out.AsRegister<CpuRegister>(), Address(base, offset));
3229 break;
3230 }
3231
3232 case Primitive::kPrimShort: {
3233 __ movsxw(out.AsRegister<CpuRegister>(), Address(base, offset));
3234 break;
3235 }
3236
3237 case Primitive::kPrimChar: {
3238 __ movzxw(out.AsRegister<CpuRegister>(), Address(base, offset));
3239 break;
3240 }
3241
3242 case Primitive::kPrimInt:
3243 case Primitive::kPrimNot: {
3244 __ movl(out.AsRegister<CpuRegister>(), Address(base, offset));
3245 break;
3246 }
3247
3248 case Primitive::kPrimLong: {
3249 __ movq(out.AsRegister<CpuRegister>(), Address(base, offset));
3250 break;
3251 }
3252
3253 case Primitive::kPrimFloat: {
3254 __ movss(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
3255 break;
3256 }
3257
3258 case Primitive::kPrimDouble: {
3259 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
3260 break;
3261 }
3262
3263 case Primitive::kPrimVoid:
3264 LOG(FATAL) << "Unreachable type " << field_type;
3265 UNREACHABLE();
3266 }
3267
Calin Juravle77520bc2015-01-12 18:45:46 +00003268 codegen_->MaybeRecordImplicitNullCheck(instruction);
3269
Calin Juravle52c48962014-12-16 17:02:57 +00003270 if (is_volatile) {
3271 GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
3272 }
3273}
3274
3275void LocationsBuilderX86_64::HandleFieldSet(HInstruction* instruction,
3276 const FieldInfo& field_info) {
3277 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3278
3279 LocationSummary* locations =
3280 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003281 bool needs_write_barrier =
Calin Juravle52c48962014-12-16 17:02:57 +00003282 CodeGenerator::StoreNeedsWriteBarrier(field_info.GetFieldType(), instruction->InputAt(1));
3283
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003284 locations->SetInAt(0, Location::RequiresRegister());
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003285 if (Primitive::IsFloatingPointType(instruction->InputAt(1)->GetType())) {
3286 locations->SetInAt(1, Location::RequiresFpuRegister());
3287 } else {
Mark Mendell40741f32015-04-20 22:10:34 -04003288 locations->SetInAt(1, Location::RegisterOrInt32LongConstant(instruction->InputAt(1)));
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003289 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003290 if (needs_write_barrier) {
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01003291 // Temporary registers for the write barrier.
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003292 locations->AddTemp(Location::RequiresRegister());
3293 locations->AddTemp(Location::RequiresRegister());
3294 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003295}
3296
Calin Juravle52c48962014-12-16 17:02:57 +00003297void InstructionCodeGeneratorX86_64::HandleFieldSet(HInstruction* instruction,
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003298 const FieldInfo& field_info,
3299 bool value_can_be_null) {
Calin Juravle52c48962014-12-16 17:02:57 +00003300 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3301
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003302 LocationSummary* locations = instruction->GetLocations();
Calin Juravle52c48962014-12-16 17:02:57 +00003303 CpuRegister base = locations->InAt(0).AsRegister<CpuRegister>();
3304 Location value = locations->InAt(1);
3305 bool is_volatile = field_info.IsVolatile();
3306 Primitive::Type field_type = field_info.GetFieldType();
3307 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
3308
3309 if (is_volatile) {
3310 GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
3311 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003312
3313 switch (field_type) {
3314 case Primitive::kPrimBoolean:
3315 case Primitive::kPrimByte: {
Mark Mendell40741f32015-04-20 22:10:34 -04003316 if (value.IsConstant()) {
3317 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
3318 __ movb(Address(base, offset), Immediate(v));
3319 } else {
3320 __ movb(Address(base, offset), value.AsRegister<CpuRegister>());
3321 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003322 break;
3323 }
3324
3325 case Primitive::kPrimShort:
3326 case Primitive::kPrimChar: {
Mark Mendell40741f32015-04-20 22:10:34 -04003327 if (value.IsConstant()) {
3328 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
3329 __ movw(Address(base, offset), Immediate(v));
3330 } else {
3331 __ movw(Address(base, offset), value.AsRegister<CpuRegister>());
3332 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003333 break;
3334 }
3335
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003336 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003337 case Primitive::kPrimNot: {
Mark Mendell40741f32015-04-20 22:10:34 -04003338 if (value.IsConstant()) {
3339 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
3340 __ movw(Address(base, offset), Immediate(v));
3341 } else {
3342 __ movl(Address(base, offset), value.AsRegister<CpuRegister>());
3343 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003344 break;
3345 }
3346
3347 case Primitive::kPrimLong: {
Mark Mendell40741f32015-04-20 22:10:34 -04003348 if (value.IsConstant()) {
3349 int64_t v = value.GetConstant()->AsLongConstant()->GetValue();
3350 DCHECK(IsInt<32>(v));
3351 int32_t v_32 = v;
3352 __ movq(Address(base, offset), Immediate(v_32));
3353 } else {
3354 __ movq(Address(base, offset), value.AsRegister<CpuRegister>());
3355 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003356 break;
3357 }
3358
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003359 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00003360 __ movss(Address(base, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003361 break;
3362 }
3363
3364 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00003365 __ movsd(Address(base, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003366 break;
3367 }
3368
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003369 case Primitive::kPrimVoid:
3370 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003371 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003372 }
Calin Juravle52c48962014-12-16 17:02:57 +00003373
Calin Juravle77520bc2015-01-12 18:45:46 +00003374 codegen_->MaybeRecordImplicitNullCheck(instruction);
3375
3376 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
3377 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
3378 CpuRegister card = locations->GetTemp(1).AsRegister<CpuRegister>();
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003379 codegen_->MarkGCCard(temp, card, base, value.AsRegister<CpuRegister>(), value_can_be_null);
Calin Juravle77520bc2015-01-12 18:45:46 +00003380 }
3381
Calin Juravle52c48962014-12-16 17:02:57 +00003382 if (is_volatile) {
3383 GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
3384 }
3385}
3386
3387void LocationsBuilderX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
3388 HandleFieldSet(instruction, instruction->GetFieldInfo());
3389}
3390
3391void InstructionCodeGeneratorX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003392 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003393}
3394
3395void LocationsBuilderX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Calin Juravle52c48962014-12-16 17:02:57 +00003396 HandleFieldGet(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003397}
3398
3399void InstructionCodeGeneratorX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Calin Juravle52c48962014-12-16 17:02:57 +00003400 HandleFieldGet(instruction, instruction->GetFieldInfo());
3401}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003402
Calin Juravle52c48962014-12-16 17:02:57 +00003403void LocationsBuilderX86_64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
3404 HandleFieldGet(instruction);
3405}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003406
Calin Juravle52c48962014-12-16 17:02:57 +00003407void InstructionCodeGeneratorX86_64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
3408 HandleFieldGet(instruction, instruction->GetFieldInfo());
3409}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003410
Calin Juravle52c48962014-12-16 17:02:57 +00003411void LocationsBuilderX86_64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
3412 HandleFieldSet(instruction, instruction->GetFieldInfo());
3413}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003414
Calin Juravle52c48962014-12-16 17:02:57 +00003415void InstructionCodeGeneratorX86_64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003416 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003417}
3418
3419void LocationsBuilderX86_64::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003420 LocationSummary* locations =
3421 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003422 Location loc = codegen_->GetCompilerOptions().GetImplicitNullChecks()
3423 ? Location::RequiresRegister()
3424 : Location::Any();
3425 locations->SetInAt(0, loc);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003426 if (instruction->HasUses()) {
3427 locations->SetOut(Location::SameAsFirstInput());
3428 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003429}
3430
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003431void InstructionCodeGeneratorX86_64::GenerateImplicitNullCheck(HNullCheck* instruction) {
Calin Juravle77520bc2015-01-12 18:45:46 +00003432 if (codegen_->CanMoveNullCheckToUser(instruction)) {
3433 return;
3434 }
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003435 LocationSummary* locations = instruction->GetLocations();
3436 Location obj = locations->InAt(0);
3437
3438 __ testl(CpuRegister(RAX), Address(obj.AsRegister<CpuRegister>(), 0));
3439 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3440}
3441
3442void InstructionCodeGeneratorX86_64::GenerateExplicitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +01003443 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathX86_64(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003444 codegen_->AddSlowPath(slow_path);
3445
3446 LocationSummary* locations = instruction->GetLocations();
3447 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003448
3449 if (obj.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00003450 __ testl(obj.AsRegister<CpuRegister>(), obj.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003451 } else if (obj.IsStackSlot()) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003452 __ cmpl(Address(CpuRegister(RSP), obj.GetStackIndex()), Immediate(0));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003453 } else {
3454 DCHECK(obj.IsConstant()) << obj;
3455 DCHECK_EQ(obj.GetConstant()->AsIntConstant()->GetValue(), 0);
3456 __ jmp(slow_path->GetEntryLabel());
3457 return;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003458 }
3459 __ j(kEqual, slow_path->GetEntryLabel());
3460}
3461
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003462void InstructionCodeGeneratorX86_64::VisitNullCheck(HNullCheck* instruction) {
3463 if (codegen_->GetCompilerOptions().GetImplicitNullChecks()) {
3464 GenerateImplicitNullCheck(instruction);
3465 } else {
3466 GenerateExplicitNullCheck(instruction);
3467 }
3468}
3469
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003470void LocationsBuilderX86_64::VisitArrayGet(HArrayGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003471 LocationSummary* locations =
3472 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003473 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell40741f32015-04-20 22:10:34 -04003474 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003475 if (Primitive::IsFloatingPointType(instruction->GetType())) {
3476 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
3477 } else {
3478 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3479 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003480}
3481
3482void InstructionCodeGeneratorX86_64::VisitArrayGet(HArrayGet* instruction) {
3483 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003484 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003485 Location index = locations->InAt(1);
3486
3487 switch (instruction->GetType()) {
3488 case Primitive::kPrimBoolean: {
3489 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003490 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003491 if (index.IsConstant()) {
3492 __ movzxb(out, Address(obj,
3493 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
3494 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003495 __ movzxb(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003496 }
3497 break;
3498 }
3499
3500 case Primitive::kPrimByte: {
3501 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003502 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003503 if (index.IsConstant()) {
3504 __ movsxb(out, Address(obj,
3505 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
3506 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003507 __ movsxb(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003508 }
3509 break;
3510 }
3511
3512 case Primitive::kPrimShort: {
3513 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003514 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003515 if (index.IsConstant()) {
3516 __ movsxw(out, Address(obj,
3517 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
3518 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003519 __ movsxw(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003520 }
3521 break;
3522 }
3523
3524 case Primitive::kPrimChar: {
3525 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_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 __ movzxw(out, Address(obj,
3529 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
3530 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003531 __ movzxw(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003532 }
3533 break;
3534 }
3535
3536 case Primitive::kPrimInt:
3537 case Primitive::kPrimNot: {
Roland Levillain33d69032015-06-18 18:20:59 +01003538 static_assert(sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
3539 "art::mirror::HeapReference<mirror::Object> and int32_t have different sizes.");
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003540 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003541 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003542 if (index.IsConstant()) {
3543 __ movl(out, Address(obj,
3544 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
3545 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003546 __ movl(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003547 }
3548 break;
3549 }
3550
3551 case Primitive::kPrimLong: {
3552 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003553 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003554 if (index.IsConstant()) {
3555 __ movq(out, Address(obj,
3556 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
3557 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003558 __ movq(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003559 }
3560 break;
3561 }
3562
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003563 case Primitive::kPrimFloat: {
3564 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003565 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003566 if (index.IsConstant()) {
3567 __ movss(out, Address(obj,
3568 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
3569 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003570 __ movss(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003571 }
3572 break;
3573 }
3574
3575 case Primitive::kPrimDouble: {
3576 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003577 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003578 if (index.IsConstant()) {
3579 __ movsd(out, Address(obj,
3580 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
3581 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003582 __ movsd(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003583 }
3584 break;
3585 }
3586
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003587 case Primitive::kPrimVoid:
3588 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07003589 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003590 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003591 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003592}
3593
3594void LocationsBuilderX86_64::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003595 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003596
3597 bool needs_write_barrier =
3598 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
3599 bool needs_runtime_call = instruction->NeedsTypeCheck();
3600
Nicolas Geoffray39468442014-09-02 15:17:15 +01003601 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003602 instruction, needs_runtime_call ? LocationSummary::kCall : LocationSummary::kNoCall);
3603 if (needs_runtime_call) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003604 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003605 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3606 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
3607 locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003608 } else {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003609 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01003610 locations->SetInAt(
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003611 1, Location::RegisterOrConstant(instruction->InputAt(1)));
3612 locations->SetInAt(2, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003613 if (value_type == Primitive::kPrimLong) {
Mark Mendell40741f32015-04-20 22:10:34 -04003614 locations->SetInAt(2, Location::RegisterOrInt32LongConstant(instruction->InputAt(2)));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003615 } else if (value_type == Primitive::kPrimFloat || value_type == Primitive::kPrimDouble) {
3616 locations->SetInAt(2, Location::RequiresFpuRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003617 } else {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003618 locations->SetInAt(2, Location::RegisterOrConstant(instruction->InputAt(2)));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003619 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003620
3621 if (needs_write_barrier) {
3622 // Temporary registers for the write barrier.
3623 locations->AddTemp(Location::RequiresRegister());
3624 locations->AddTemp(Location::RequiresRegister());
3625 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003626 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003627}
3628
3629void InstructionCodeGeneratorX86_64::VisitArraySet(HArraySet* instruction) {
3630 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003631 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003632 Location index = locations->InAt(1);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003633 Location value = locations->InAt(2);
Nicolas Geoffray39468442014-09-02 15:17:15 +01003634 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003635 bool needs_runtime_call = locations->WillCall();
3636 bool needs_write_barrier =
3637 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003638
3639 switch (value_type) {
3640 case Primitive::kPrimBoolean:
3641 case Primitive::kPrimByte: {
3642 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003643 if (index.IsConstant()) {
3644 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003645 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003646 __ movb(Address(obj, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003647 } else {
Roland Levillain199f3362014-11-27 17:15:16 +00003648 __ movb(Address(obj, offset),
3649 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003650 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003651 } else {
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003652 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003653 __ movb(Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset),
3654 value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003655 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003656 __ movb(Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003657 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3658 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003659 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003660 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003661 break;
3662 }
3663
3664 case Primitive::kPrimShort:
3665 case Primitive::kPrimChar: {
3666 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003667 if (index.IsConstant()) {
3668 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003669 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003670 __ movw(Address(obj, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003671 } else {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003672 DCHECK(value.IsConstant()) << value;
Roland Levillain199f3362014-11-27 17:15:16 +00003673 __ movw(Address(obj, offset),
3674 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003675 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003676 } else {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003677 DCHECK(index.IsRegister()) << index;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003678 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003679 __ movw(Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset),
3680 value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003681 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003682 DCHECK(value.IsConstant()) << value;
Roland Levillain271ab9c2014-11-27 15:23:57 +00003683 __ movw(Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003684 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3685 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003686 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003687 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003688 break;
3689 }
3690
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003691 case Primitive::kPrimInt:
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003692 case Primitive::kPrimNot: {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003693 if (!needs_runtime_call) {
3694 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
3695 if (index.IsConstant()) {
3696 size_t offset =
3697 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
3698 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003699 __ movl(Address(obj, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003700 } else {
3701 DCHECK(value.IsConstant()) << value;
Mark Mendell40741f32015-04-20 22:10:34 -04003702 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
3703 __ movl(Address(obj, offset), Immediate(v));
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003704 }
3705 } else {
3706 DCHECK(index.IsRegister()) << index;
3707 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003708 __ movl(Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset),
3709 value.AsRegister<CpuRegister>());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003710 } else {
3711 DCHECK(value.IsConstant()) << value;
Mark Mendell40741f32015-04-20 22:10:34 -04003712 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003713 __ movl(Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset),
Mark Mendell40741f32015-04-20 22:10:34 -04003714 Immediate(v));
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003715 }
3716 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003717 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003718 if (needs_write_barrier) {
3719 DCHECK_EQ(value_type, Primitive::kPrimNot);
Roland Levillain271ab9c2014-11-27 15:23:57 +00003720 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
3721 CpuRegister card = locations->GetTemp(1).AsRegister<CpuRegister>();
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003722 codegen_->MarkGCCard(
3723 temp, card, obj, value.AsRegister<CpuRegister>(), instruction->GetValueCanBeNull());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003724 }
3725 } else {
3726 DCHECK_EQ(value_type, Primitive::kPrimNot);
Roland Levillain199f3362014-11-27 17:15:16 +00003727 __ gs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pAputObject),
3728 true));
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003729 DCHECK(!codegen_->IsLeafMethod());
3730 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3731 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003732 break;
3733 }
3734
3735 case Primitive::kPrimLong: {
3736 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003737 if (index.IsConstant()) {
3738 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Mark Mendell40741f32015-04-20 22:10:34 -04003739 if (value.IsRegister()) {
3740 __ movq(Address(obj, offset), value.AsRegister<CpuRegister>());
3741 } else {
3742 int64_t v = value.GetConstant()->AsLongConstant()->GetValue();
3743 DCHECK(IsInt<32>(v));
3744 int32_t v_32 = v;
3745 __ movq(Address(obj, offset), Immediate(v_32));
3746 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003747 } else {
Mark Mendell40741f32015-04-20 22:10:34 -04003748 if (value.IsRegister()) {
3749 __ movq(Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset),
3750 value.AsRegister<CpuRegister>());
3751 } else {
3752 int64_t v = value.GetConstant()->AsLongConstant()->GetValue();
3753 DCHECK(IsInt<32>(v));
3754 int32_t v_32 = v;
3755 __ movq(Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset),
3756 Immediate(v_32));
3757 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003758 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003759 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003760 break;
3761 }
3762
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003763 case Primitive::kPrimFloat: {
3764 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
3765 if (index.IsConstant()) {
3766 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
3767 DCHECK(value.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003768 __ movss(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 __ movss(Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, 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
3778 case Primitive::kPrimDouble: {
3779 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
3780 if (index.IsConstant()) {
3781 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
3782 DCHECK(value.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003783 __ movsd(Address(obj, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003784 } else {
3785 DCHECK(value.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003786 __ movsd(Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset),
3787 value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003788 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003789 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003790 break;
3791 }
3792
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003793 case Primitive::kPrimVoid:
3794 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07003795 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003796 }
3797}
3798
3799void LocationsBuilderX86_64::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003800 LocationSummary* locations =
3801 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003802 locations->SetInAt(0, Location::RequiresRegister());
3803 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003804}
3805
3806void InstructionCodeGeneratorX86_64::VisitArrayLength(HArrayLength* instruction) {
3807 LocationSummary* locations = instruction->GetLocations();
3808 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003809 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
3810 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003811 __ movl(out, Address(obj, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00003812 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003813}
3814
3815void LocationsBuilderX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003816 LocationSummary* locations =
3817 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Mark Mendellf60c90b2015-03-04 15:12:59 -05003818 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
Mark Mendell99dbd682015-04-22 16:18:52 -04003819 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003820 if (instruction->HasUses()) {
3821 locations->SetOut(Location::SameAsFirstInput());
3822 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003823}
3824
3825void InstructionCodeGeneratorX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
3826 LocationSummary* locations = instruction->GetLocations();
Mark Mendellf60c90b2015-03-04 15:12:59 -05003827 Location index_loc = locations->InAt(0);
3828 Location length_loc = locations->InAt(1);
3829 SlowPathCodeX86_64* slow_path =
3830 new (GetGraph()->GetArena()) BoundsCheckSlowPathX86_64(instruction, index_loc, length_loc);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003831
Mark Mendell99dbd682015-04-22 16:18:52 -04003832 if (length_loc.IsConstant()) {
3833 int32_t length = CodeGenerator::GetInt32ValueOf(length_loc.GetConstant());
3834 if (index_loc.IsConstant()) {
3835 // BCE will remove the bounds check if we are guarenteed to pass.
3836 int32_t index = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
3837 if (index < 0 || index >= length) {
3838 codegen_->AddSlowPath(slow_path);
3839 __ jmp(slow_path->GetEntryLabel());
3840 } else {
3841 // Some optimization after BCE may have generated this, and we should not
3842 // generate a bounds check if it is a valid range.
3843 }
3844 return;
3845 }
3846
3847 // We have to reverse the jump condition because the length is the constant.
3848 CpuRegister index_reg = index_loc.AsRegister<CpuRegister>();
3849 __ cmpl(index_reg, Immediate(length));
3850 codegen_->AddSlowPath(slow_path);
3851 __ j(kAboveEqual, slow_path->GetEntryLabel());
Mark Mendellf60c90b2015-03-04 15:12:59 -05003852 } else {
Mark Mendell99dbd682015-04-22 16:18:52 -04003853 CpuRegister length = length_loc.AsRegister<CpuRegister>();
3854 if (index_loc.IsConstant()) {
3855 int32_t value = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
3856 __ cmpl(length, Immediate(value));
3857 } else {
3858 __ cmpl(length, index_loc.AsRegister<CpuRegister>());
3859 }
3860 codegen_->AddSlowPath(slow_path);
3861 __ j(kBelowEqual, slow_path->GetEntryLabel());
Mark Mendellf60c90b2015-03-04 15:12:59 -05003862 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003863}
3864
3865void CodeGeneratorX86_64::MarkGCCard(CpuRegister temp,
3866 CpuRegister card,
3867 CpuRegister object,
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003868 CpuRegister value,
3869 bool value_can_be_null) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003870 Label is_null;
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003871 if (value_can_be_null) {
3872 __ testl(value, value);
3873 __ j(kEqual, &is_null);
3874 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003875 __ gs()->movq(card, Address::Absolute(
3876 Thread::CardTableOffset<kX86_64WordSize>().Int32Value(), true));
3877 __ movq(temp, object);
3878 __ shrq(temp, Immediate(gc::accounting::CardTable::kCardShift));
3879 __ movb(Address(temp, card, TIMES_1, 0), card);
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003880 if (value_can_be_null) {
3881 __ Bind(&is_null);
3882 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003883}
3884
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003885void LocationsBuilderX86_64::VisitTemporary(HTemporary* temp) {
3886 temp->SetLocations(nullptr);
3887}
3888
3889void InstructionCodeGeneratorX86_64::VisitTemporary(HTemporary* temp) {
3890 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003891 UNUSED(temp);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003892}
3893
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003894void LocationsBuilderX86_64::VisitParallelMove(HParallelMove* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003895 UNUSED(instruction);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003896 LOG(FATAL) << "Unimplemented";
3897}
3898
3899void InstructionCodeGeneratorX86_64::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003900 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
3901}
3902
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003903void LocationsBuilderX86_64::VisitSuspendCheck(HSuspendCheck* instruction) {
3904 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
3905}
3906
3907void InstructionCodeGeneratorX86_64::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003908 HBasicBlock* block = instruction->GetBlock();
3909 if (block->GetLoopInformation() != nullptr) {
3910 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
3911 // The back edge will generate the suspend check.
3912 return;
3913 }
3914 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
3915 // The goto will generate the suspend check.
3916 return;
3917 }
3918 GenerateSuspendCheck(instruction, nullptr);
3919}
3920
3921void InstructionCodeGeneratorX86_64::GenerateSuspendCheck(HSuspendCheck* instruction,
3922 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003923 SuspendCheckSlowPathX86_64* slow_path =
Nicolas Geoffraydb216f42015-05-05 17:02:20 +01003924 down_cast<SuspendCheckSlowPathX86_64*>(instruction->GetSlowPath());
3925 if (slow_path == nullptr) {
3926 slow_path = new (GetGraph()->GetArena()) SuspendCheckSlowPathX86_64(instruction, successor);
3927 instruction->SetSlowPath(slow_path);
3928 codegen_->AddSlowPath(slow_path);
3929 if (successor != nullptr) {
3930 DCHECK(successor->IsLoopHeader());
3931 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(instruction);
3932 }
3933 } else {
3934 DCHECK_EQ(slow_path->GetSuccessor(), successor);
3935 }
3936
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003937 __ gs()->cmpw(Address::Absolute(
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003938 Thread::ThreadFlagsOffset<kX86_64WordSize>().Int32Value(), true), Immediate(0));
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003939 if (successor == nullptr) {
3940 __ j(kNotEqual, slow_path->GetEntryLabel());
3941 __ Bind(slow_path->GetReturnLabel());
3942 } else {
3943 __ j(kEqual, codegen_->GetLabelOf(successor));
3944 __ jmp(slow_path->GetEntryLabel());
3945 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003946}
3947
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003948X86_64Assembler* ParallelMoveResolverX86_64::GetAssembler() const {
3949 return codegen_->GetAssembler();
3950}
3951
3952void ParallelMoveResolverX86_64::EmitMove(size_t index) {
3953 MoveOperands* move = moves_.Get(index);
3954 Location source = move->GetSource();
3955 Location destination = move->GetDestination();
3956
3957 if (source.IsRegister()) {
3958 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003959 __ movq(destination.AsRegister<CpuRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003960 } else if (destination.IsStackSlot()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003961 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00003962 source.AsRegister<CpuRegister>());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003963 } else {
3964 DCHECK(destination.IsDoubleStackSlot());
3965 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00003966 source.AsRegister<CpuRegister>());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003967 }
3968 } else if (source.IsStackSlot()) {
3969 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003970 __ movl(destination.AsRegister<CpuRegister>(),
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003971 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003972 } else if (destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003973 __ movss(destination.AsFpuRegister<XmmRegister>(),
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003974 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003975 } else {
3976 DCHECK(destination.IsStackSlot());
3977 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
3978 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
3979 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003980 } else if (source.IsDoubleStackSlot()) {
3981 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003982 __ movq(destination.AsRegister<CpuRegister>(),
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003983 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003984 } else if (destination.IsFpuRegister()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003985 __ movsd(destination.AsFpuRegister<XmmRegister>(),
3986 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003987 } else {
Nicolas Geoffrayc8147a72014-10-21 16:06:20 +01003988 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003989 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
3990 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
3991 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003992 } else if (source.IsConstant()) {
3993 HConstant* constant = source.GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00003994 if (constant->IsIntConstant() || constant->IsNullConstant()) {
3995 int32_t value = CodeGenerator::GetInt32ValueOf(constant);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003996 if (destination.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00003997 if (value == 0) {
3998 __ xorl(destination.AsRegister<CpuRegister>(), destination.AsRegister<CpuRegister>());
3999 } else {
4000 __ movl(destination.AsRegister<CpuRegister>(), Immediate(value));
4001 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004002 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004003 DCHECK(destination.IsStackSlot()) << destination;
Nicolas Geoffray748f1402015-01-27 08:17:54 +00004004 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), Immediate(value));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004005 }
4006 } else if (constant->IsLongConstant()) {
4007 int64_t value = constant->AsLongConstant()->GetValue();
4008 if (destination.IsRegister()) {
Mark Mendell92e83bf2015-05-07 11:25:03 -04004009 codegen_->Load64BitValue(destination.AsRegister<CpuRegister>(), value);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004010 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004011 DCHECK(destination.IsDoubleStackSlot()) << destination;
Mark Mendell92e83bf2015-05-07 11:25:03 -04004012 codegen_->Load64BitValue(CpuRegister(TMP), value);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004013 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
4014 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004015 } else if (constant->IsFloatConstant()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004016 float fp_value = constant->AsFloatConstant()->GetValue();
Roland Levillainda4d79b2015-03-24 14:36:11 +00004017 int32_t value = bit_cast<int32_t, float>(fp_value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004018 if (destination.IsFpuRegister()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004019 XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
4020 if (value == 0) {
4021 // easy FP 0.0.
4022 __ xorps(dest, dest);
4023 } else {
Mark Mendell92e83bf2015-05-07 11:25:03 -04004024 __ movss(dest, codegen_->LiteralFloatAddress(fp_value));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004025 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004026 } else {
4027 DCHECK(destination.IsStackSlot()) << destination;
Mark Mendell92e83bf2015-05-07 11:25:03 -04004028 Immediate imm(value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004029 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), imm);
4030 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004031 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004032 DCHECK(constant->IsDoubleConstant()) << constant->DebugName();
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004033 double fp_value = constant->AsDoubleConstant()->GetValue();
Roland Levillainda4d79b2015-03-24 14:36:11 +00004034 int64_t value = bit_cast<int64_t, double>(fp_value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004035 if (destination.IsFpuRegister()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004036 XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
4037 if (value == 0) {
4038 __ xorpd(dest, dest);
4039 } else {
Mark Mendell92e83bf2015-05-07 11:25:03 -04004040 __ movsd(dest, codegen_->LiteralDoubleAddress(fp_value));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004041 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004042 } else {
4043 DCHECK(destination.IsDoubleStackSlot()) << destination;
Mark Mendell92e83bf2015-05-07 11:25:03 -04004044 codegen_->Load64BitValue(CpuRegister(TMP), value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004045 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
4046 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004047 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004048 } else if (source.IsFpuRegister()) {
4049 if (destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004050 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004051 } else if (destination.IsStackSlot()) {
4052 __ movss(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00004053 source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004054 } else {
Nicolas Geoffray31596742014-11-24 15:28:45 +00004055 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004056 __ movsd(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00004057 source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004058 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004059 }
4060}
4061
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004062void ParallelMoveResolverX86_64::Exchange32(CpuRegister reg, int mem) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004063 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004064 __ movl(Address(CpuRegister(RSP), mem), reg);
4065 __ movl(reg, CpuRegister(TMP));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004066}
4067
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004068void ParallelMoveResolverX86_64::Exchange32(int mem1, int mem2) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004069 ScratchRegisterScope ensure_scratch(
4070 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
4071
4072 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
4073 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
4074 __ movl(CpuRegister(ensure_scratch.GetRegister()),
4075 Address(CpuRegister(RSP), mem2 + stack_offset));
4076 __ movl(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
4077 __ movl(Address(CpuRegister(RSP), mem1 + stack_offset),
4078 CpuRegister(ensure_scratch.GetRegister()));
4079}
4080
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004081void ParallelMoveResolverX86_64::Exchange64(CpuRegister reg, int mem) {
4082 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
4083 __ movq(Address(CpuRegister(RSP), mem), reg);
4084 __ movq(reg, CpuRegister(TMP));
4085}
4086
4087void ParallelMoveResolverX86_64::Exchange64(int mem1, int mem2) {
4088 ScratchRegisterScope ensure_scratch(
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004089 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004090
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004091 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
4092 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
4093 __ movq(CpuRegister(ensure_scratch.GetRegister()),
4094 Address(CpuRegister(RSP), mem2 + stack_offset));
4095 __ movq(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
4096 __ movq(Address(CpuRegister(RSP), mem1 + stack_offset),
4097 CpuRegister(ensure_scratch.GetRegister()));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004098}
4099
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004100void ParallelMoveResolverX86_64::Exchange32(XmmRegister reg, int mem) {
4101 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
4102 __ movss(Address(CpuRegister(RSP), mem), reg);
4103 __ movd(reg, CpuRegister(TMP));
4104}
4105
4106void ParallelMoveResolverX86_64::Exchange64(XmmRegister reg, int mem) {
4107 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
4108 __ movsd(Address(CpuRegister(RSP), mem), reg);
4109 __ movd(reg, CpuRegister(TMP));
4110}
4111
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004112void ParallelMoveResolverX86_64::EmitSwap(size_t index) {
4113 MoveOperands* move = moves_.Get(index);
4114 Location source = move->GetSource();
4115 Location destination = move->GetDestination();
4116
4117 if (source.IsRegister() && destination.IsRegister()) {
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004118 __ xchgq(destination.AsRegister<CpuRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004119 } else if (source.IsRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004120 Exchange32(source.AsRegister<CpuRegister>(), destination.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004121 } else if (source.IsStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004122 Exchange32(destination.AsRegister<CpuRegister>(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004123 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004124 Exchange32(destination.GetStackIndex(), source.GetStackIndex());
4125 } else if (source.IsRegister() && destination.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004126 Exchange64(source.AsRegister<CpuRegister>(), destination.GetStackIndex());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004127 } else if (source.IsDoubleStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004128 Exchange64(destination.AsRegister<CpuRegister>(), source.GetStackIndex());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004129 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
4130 Exchange64(destination.GetStackIndex(), source.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004131 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004132 __ movd(CpuRegister(TMP), source.AsFpuRegister<XmmRegister>());
4133 __ movaps(source.AsFpuRegister<XmmRegister>(), destination.AsFpuRegister<XmmRegister>());
4134 __ movd(destination.AsFpuRegister<XmmRegister>(), CpuRegister(TMP));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004135 } else if (source.IsFpuRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004136 Exchange32(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004137 } else if (source.IsStackSlot() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004138 Exchange32(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004139 } else if (source.IsFpuRegister() && destination.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004140 Exchange64(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004141 } else if (source.IsDoubleStackSlot() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004142 Exchange64(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004143 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004144 LOG(FATAL) << "Unimplemented swap between " << source << " and " << destination;
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004145 }
4146}
4147
4148
4149void ParallelMoveResolverX86_64::SpillScratch(int reg) {
4150 __ pushq(CpuRegister(reg));
4151}
4152
4153
4154void ParallelMoveResolverX86_64::RestoreScratch(int reg) {
4155 __ popq(CpuRegister(reg));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004156}
4157
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004158void InstructionCodeGeneratorX86_64::GenerateClassInitializationCheck(
4159 SlowPathCodeX86_64* slow_path, CpuRegister class_reg) {
4160 __ cmpl(Address(class_reg, mirror::Class::StatusOffset().Int32Value()),
4161 Immediate(mirror::Class::kStatusInitialized));
4162 __ j(kLess, slow_path->GetEntryLabel());
4163 __ Bind(slow_path->GetExitLabel());
4164 // No need for memory fence, thanks to the X86_64 memory model.
4165}
4166
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004167void LocationsBuilderX86_64::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004168 LocationSummary::CallKind call_kind = cls->CanCallRuntime()
4169 ? LocationSummary::kCallOnSlowPath
4170 : LocationSummary::kNoCall;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004171 LocationSummary* locations =
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004172 new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004173 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004174 locations->SetOut(Location::RequiresRegister());
4175}
4176
4177void InstructionCodeGeneratorX86_64::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004178 LocationSummary* locations = cls->GetLocations();
4179 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
4180 CpuRegister current_method = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004181 if (cls->IsReferrersClass()) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004182 DCHECK(!cls->CanCallRuntime());
4183 DCHECK(!cls->MustGenerateClinitCheck());
Mathieu Chartiere401d142015-04-22 13:56:20 -07004184 __ movl(out, Address(current_method, ArtMethod::DeclaringClassOffset().Int32Value()));
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004185 } else {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004186 DCHECK(cls->CanCallRuntime());
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004187 __ movl(out, Address(
Mathieu Chartiere401d142015-04-22 13:56:20 -07004188 current_method, ArtMethod::DexCacheResolvedTypesOffset().Int32Value()));
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004189 __ movl(out, Address(out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex())));
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004190 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86_64(
4191 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
4192 codegen_->AddSlowPath(slow_path);
4193 __ testl(out, out);
4194 __ j(kEqual, slow_path->GetEntryLabel());
4195 if (cls->MustGenerateClinitCheck()) {
4196 GenerateClassInitializationCheck(slow_path, out);
4197 } else {
4198 __ Bind(slow_path->GetExitLabel());
4199 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004200 }
4201}
4202
4203void LocationsBuilderX86_64::VisitClinitCheck(HClinitCheck* check) {
4204 LocationSummary* locations =
4205 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
4206 locations->SetInAt(0, Location::RequiresRegister());
4207 if (check->HasUses()) {
4208 locations->SetOut(Location::SameAsFirstInput());
4209 }
4210}
4211
4212void InstructionCodeGeneratorX86_64::VisitClinitCheck(HClinitCheck* check) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004213 // We assume the class to not be null.
4214 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86_64(
4215 check->GetLoadClass(), check, check->GetDexPc(), true);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004216 codegen_->AddSlowPath(slow_path);
Roland Levillain199f3362014-11-27 17:15:16 +00004217 GenerateClassInitializationCheck(slow_path,
4218 check->GetLocations()->InAt(0).AsRegister<CpuRegister>());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004219}
4220
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004221void LocationsBuilderX86_64::VisitLoadString(HLoadString* load) {
4222 LocationSummary* locations =
4223 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01004224 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004225 locations->SetOut(Location::RequiresRegister());
4226}
4227
4228void InstructionCodeGeneratorX86_64::VisitLoadString(HLoadString* load) {
4229 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathX86_64(load);
4230 codegen_->AddSlowPath(slow_path);
4231
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01004232 LocationSummary* locations = load->GetLocations();
4233 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
4234 CpuRegister current_method = locations->InAt(0).AsRegister<CpuRegister>();
Mathieu Chartiere401d142015-04-22 13:56:20 -07004235 __ movl(out, Address(current_method, ArtMethod::DeclaringClassOffset().Int32Value()));
Mathieu Chartiereace4582014-11-24 18:29:54 -08004236 __ movl(out, Address(out, mirror::Class::DexCacheStringsOffset().Int32Value()));
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004237 __ movl(out, Address(out, CodeGenerator::GetCacheOffset(load->GetStringIndex())));
4238 __ testl(out, out);
4239 __ j(kEqual, slow_path->GetEntryLabel());
4240 __ Bind(slow_path->GetExitLabel());
4241}
4242
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004243void LocationsBuilderX86_64::VisitLoadException(HLoadException* load) {
4244 LocationSummary* locations =
4245 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
4246 locations->SetOut(Location::RequiresRegister());
4247}
4248
4249void InstructionCodeGeneratorX86_64::VisitLoadException(HLoadException* load) {
4250 Address address = Address::Absolute(
4251 Thread::ExceptionOffset<kX86_64WordSize>().Int32Value(), true);
Roland Levillain271ab9c2014-11-27 15:23:57 +00004252 __ gs()->movl(load->GetLocations()->Out().AsRegister<CpuRegister>(), address);
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004253 __ gs()->movl(address, Immediate(0));
4254}
4255
4256void LocationsBuilderX86_64::VisitThrow(HThrow* instruction) {
4257 LocationSummary* locations =
4258 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
4259 InvokeRuntimeCallingConvention calling_convention;
4260 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4261}
4262
4263void InstructionCodeGeneratorX86_64::VisitThrow(HThrow* instruction) {
4264 __ gs()->call(
4265 Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pDeliverException), true));
4266 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
4267}
4268
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004269void LocationsBuilderX86_64::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004270 LocationSummary::CallKind call_kind = instruction->IsClassFinal()
4271 ? LocationSummary::kNoCall
4272 : LocationSummary::kCallOnSlowPath;
4273 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
4274 locations->SetInAt(0, Location::RequiresRegister());
4275 locations->SetInAt(1, Location::Any());
4276 locations->SetOut(Location::RequiresRegister());
4277}
4278
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004279void InstructionCodeGeneratorX86_64::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004280 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004281 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004282 Location cls = locations->InAt(1);
Roland Levillain271ab9c2014-11-27 15:23:57 +00004283 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004284 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
4285 Label done, zero;
4286 SlowPathCodeX86_64* slow_path = nullptr;
4287
4288 // Return 0 if `obj` is null.
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004289 // Avoid null check if we know obj is not null.
4290 if (instruction->MustDoNullCheck()) {
4291 __ testl(obj, obj);
4292 __ j(kEqual, &zero);
4293 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004294 // Compare the class of `obj` with `cls`.
4295 __ movl(out, Address(obj, class_offset));
4296 if (cls.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004297 __ cmpl(out, cls.AsRegister<CpuRegister>());
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004298 } else {
4299 DCHECK(cls.IsStackSlot()) << cls;
4300 __ cmpl(out, Address(CpuRegister(RSP), cls.GetStackIndex()));
4301 }
4302 if (instruction->IsClassFinal()) {
4303 // Classes must be equal for the instanceof to succeed.
4304 __ j(kNotEqual, &zero);
4305 __ movl(out, Immediate(1));
4306 __ jmp(&done);
4307 } else {
4308 // If the classes are not equal, we go into a slow path.
4309 DCHECK(locations->OnlyCallsOnSlowPath());
4310 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86_64(
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004311 instruction, locations->InAt(1), locations->Out(), instruction->GetDexPc());
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004312 codegen_->AddSlowPath(slow_path);
4313 __ j(kNotEqual, slow_path->GetEntryLabel());
4314 __ movl(out, Immediate(1));
4315 __ jmp(&done);
4316 }
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004317
4318 if (instruction->MustDoNullCheck() || instruction->IsClassFinal()) {
4319 __ Bind(&zero);
4320 __ movl(out, Immediate(0));
4321 }
4322
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004323 if (slow_path != nullptr) {
4324 __ Bind(slow_path->GetExitLabel());
4325 }
4326 __ Bind(&done);
4327}
4328
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004329void LocationsBuilderX86_64::VisitCheckCast(HCheckCast* instruction) {
4330 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
4331 instruction, LocationSummary::kCallOnSlowPath);
4332 locations->SetInAt(0, Location::RequiresRegister());
4333 locations->SetInAt(1, Location::Any());
4334 locations->AddTemp(Location::RequiresRegister());
4335}
4336
4337void InstructionCodeGeneratorX86_64::VisitCheckCast(HCheckCast* instruction) {
4338 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004339 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004340 Location cls = locations->InAt(1);
Roland Levillain271ab9c2014-11-27 15:23:57 +00004341 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004342 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
4343 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86_64(
4344 instruction, locations->InAt(1), locations->GetTemp(0), instruction->GetDexPc());
4345 codegen_->AddSlowPath(slow_path);
4346
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004347 // Avoid null check if we know obj is not null.
4348 if (instruction->MustDoNullCheck()) {
4349 __ testl(obj, obj);
4350 __ j(kEqual, slow_path->GetExitLabel());
4351 }
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004352 // Compare the class of `obj` with `cls`.
4353 __ movl(temp, Address(obj, class_offset));
4354 if (cls.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004355 __ cmpl(temp, cls.AsRegister<CpuRegister>());
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004356 } else {
4357 DCHECK(cls.IsStackSlot()) << cls;
4358 __ cmpl(temp, Address(CpuRegister(RSP), cls.GetStackIndex()));
4359 }
4360 // Classes must be equal for the checkcast to succeed.
4361 __ j(kNotEqual, slow_path->GetEntryLabel());
4362 __ Bind(slow_path->GetExitLabel());
4363}
4364
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00004365void LocationsBuilderX86_64::VisitMonitorOperation(HMonitorOperation* instruction) {
4366 LocationSummary* locations =
4367 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
4368 InvokeRuntimeCallingConvention calling_convention;
4369 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4370}
4371
4372void InstructionCodeGeneratorX86_64::VisitMonitorOperation(HMonitorOperation* instruction) {
4373 __ gs()->call(Address::Absolute(instruction->IsEnter()
4374 ? QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pLockObject)
4375 : QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pUnlockObject),
4376 true));
4377 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
4378}
4379
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004380void LocationsBuilderX86_64::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); }
4381void LocationsBuilderX86_64::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); }
4382void LocationsBuilderX86_64::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); }
4383
4384void LocationsBuilderX86_64::HandleBitwiseOperation(HBinaryOperation* instruction) {
4385 LocationSummary* locations =
4386 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
4387 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
4388 || instruction->GetResultType() == Primitive::kPrimLong);
4389 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell40741f32015-04-20 22:10:34 -04004390 locations->SetInAt(1, Location::Any());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004391 locations->SetOut(Location::SameAsFirstInput());
4392}
4393
4394void InstructionCodeGeneratorX86_64::VisitAnd(HAnd* instruction) {
4395 HandleBitwiseOperation(instruction);
4396}
4397
4398void InstructionCodeGeneratorX86_64::VisitOr(HOr* instruction) {
4399 HandleBitwiseOperation(instruction);
4400}
4401
4402void InstructionCodeGeneratorX86_64::VisitXor(HXor* instruction) {
4403 HandleBitwiseOperation(instruction);
4404}
4405
4406void InstructionCodeGeneratorX86_64::HandleBitwiseOperation(HBinaryOperation* instruction) {
4407 LocationSummary* locations = instruction->GetLocations();
4408 Location first = locations->InAt(0);
4409 Location second = locations->InAt(1);
4410 DCHECK(first.Equals(locations->Out()));
4411
4412 if (instruction->GetResultType() == Primitive::kPrimInt) {
4413 if (second.IsRegister()) {
4414 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004415 __ andl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004416 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004417 __ orl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004418 } else {
4419 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004420 __ xorl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004421 }
4422 } else if (second.IsConstant()) {
4423 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
4424 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004425 __ andl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004426 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004427 __ orl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004428 } else {
4429 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004430 __ xorl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004431 }
4432 } else {
4433 Address address(CpuRegister(RSP), second.GetStackIndex());
4434 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004435 __ andl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004436 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004437 __ orl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004438 } else {
4439 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004440 __ xorl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004441 }
4442 }
4443 } else {
4444 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004445 CpuRegister first_reg = first.AsRegister<CpuRegister>();
4446 bool second_is_constant = false;
4447 int64_t value = 0;
4448 if (second.IsConstant()) {
4449 second_is_constant = true;
4450 value = second.GetConstant()->AsLongConstant()->GetValue();
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004451 }
Mark Mendell40741f32015-04-20 22:10:34 -04004452 bool is_int32_value = IsInt<32>(value);
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004453
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004454 if (instruction->IsAnd()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004455 if (second_is_constant) {
Mark Mendell40741f32015-04-20 22:10:34 -04004456 if (is_int32_value) {
4457 __ andq(first_reg, Immediate(static_cast<int32_t>(value)));
4458 } else {
4459 __ andq(first_reg, codegen_->LiteralInt64Address(value));
4460 }
4461 } else if (second.IsDoubleStackSlot()) {
4462 __ andq(first_reg, Address(CpuRegister(RSP), second.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004463 } else {
4464 __ andq(first_reg, second.AsRegister<CpuRegister>());
4465 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004466 } else if (instruction->IsOr()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004467 if (second_is_constant) {
Mark Mendell40741f32015-04-20 22:10:34 -04004468 if (is_int32_value) {
4469 __ orq(first_reg, Immediate(static_cast<int32_t>(value)));
4470 } else {
4471 __ orq(first_reg, codegen_->LiteralInt64Address(value));
4472 }
4473 } else if (second.IsDoubleStackSlot()) {
4474 __ orq(first_reg, Address(CpuRegister(RSP), second.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004475 } else {
4476 __ orq(first_reg, second.AsRegister<CpuRegister>());
4477 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004478 } else {
4479 DCHECK(instruction->IsXor());
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004480 if (second_is_constant) {
Mark Mendell40741f32015-04-20 22:10:34 -04004481 if (is_int32_value) {
4482 __ xorq(first_reg, Immediate(static_cast<int32_t>(value)));
4483 } else {
4484 __ xorq(first_reg, codegen_->LiteralInt64Address(value));
4485 }
4486 } else if (second.IsDoubleStackSlot()) {
4487 __ xorq(first_reg, Address(CpuRegister(RSP), second.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004488 } else {
4489 __ xorq(first_reg, second.AsRegister<CpuRegister>());
4490 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004491 }
4492 }
4493}
4494
Calin Juravleb1498f62015-02-16 13:13:29 +00004495void LocationsBuilderX86_64::VisitBoundType(HBoundType* instruction) {
4496 // Nothing to do, this should be removed during prepare for register allocator.
4497 UNUSED(instruction);
4498 LOG(FATAL) << "Unreachable";
4499}
4500
4501void InstructionCodeGeneratorX86_64::VisitBoundType(HBoundType* instruction) {
4502 // Nothing to do, this should be removed during prepare for register allocator.
4503 UNUSED(instruction);
4504 LOG(FATAL) << "Unreachable";
4505}
4506
Mark Mendell92e83bf2015-05-07 11:25:03 -04004507void CodeGeneratorX86_64::Load64BitValue(CpuRegister dest, int64_t value) {
4508 if (value == 0) {
4509 __ xorl(dest, dest);
4510 } else if (value > 0 && IsInt<32>(value)) {
4511 // We can use a 32 bit move, as it will zero-extend and is one byte shorter.
4512 __ movl(dest, Immediate(static_cast<int32_t>(value)));
4513 } else {
4514 __ movq(dest, Immediate(value));
4515 }
4516}
4517
Mark Mendellf55c3e02015-03-26 21:07:46 -04004518void CodeGeneratorX86_64::Finalize(CodeAllocator* allocator) {
4519 // Generate the constant area if needed.
Mark Mendell39dcf552015-04-09 20:42:42 -04004520 X86_64Assembler* assembler = GetAssembler();
4521 if (!assembler->IsConstantAreaEmpty()) {
Mark Mendellf55c3e02015-03-26 21:07:46 -04004522 // Align to 4 byte boundary to reduce cache misses, as the data is 4 and 8
4523 // byte values. If used for vectors at a later time, this will need to be
4524 // updated to 16 bytes with the appropriate offset.
Mark Mendell39dcf552015-04-09 20:42:42 -04004525 assembler->Align(4, 0);
4526 constant_area_start_ = assembler->CodeSize();
4527 assembler->AddConstantArea();
Mark Mendellf55c3e02015-03-26 21:07:46 -04004528 }
4529
4530 // And finish up.
4531 CodeGenerator::Finalize(allocator);
4532}
4533
4534/**
4535 * Class to handle late fixup of offsets into constant area.
4536 */
4537class RIPFixup : public AssemblerFixup, public ArenaObject<kArenaAllocMisc> {
4538 public:
Mark Mendell39dcf552015-04-09 20:42:42 -04004539 RIPFixup(const CodeGeneratorX86_64& codegen, int offset)
Mark Mendellf55c3e02015-03-26 21:07:46 -04004540 : codegen_(codegen), offset_into_constant_area_(offset) {}
4541
4542 private:
4543 void Process(const MemoryRegion& region, int pos) OVERRIDE {
4544 // Patch the correct offset for the instruction. We use the address of the
4545 // 'next' instruction, which is 'pos' (patch the 4 bytes before).
4546 int constant_offset = codegen_.ConstantAreaStart() + offset_into_constant_area_;
4547 int relative_position = constant_offset - pos;
4548
4549 // Patch in the right value.
4550 region.StoreUnaligned<int32_t>(pos - 4, relative_position);
4551 }
4552
Mark Mendell39dcf552015-04-09 20:42:42 -04004553 const CodeGeneratorX86_64& codegen_;
Mark Mendellf55c3e02015-03-26 21:07:46 -04004554
4555 // Location in constant area that the fixup refers to.
4556 int offset_into_constant_area_;
4557};
4558
4559Address CodeGeneratorX86_64::LiteralDoubleAddress(double v) {
4560 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddDouble(v));
4561 return Address::RIP(fixup);
4562}
4563
4564Address CodeGeneratorX86_64::LiteralFloatAddress(float v) {
4565 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddFloat(v));
4566 return Address::RIP(fixup);
4567}
4568
4569Address CodeGeneratorX86_64::LiteralInt32Address(int32_t v) {
4570 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddInt32(v));
4571 return Address::RIP(fixup);
4572}
4573
4574Address CodeGeneratorX86_64::LiteralInt64Address(int64_t v) {
4575 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddInt64(v));
4576 return Address::RIP(fixup);
4577}
4578
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004579} // namespace x86_64
4580} // namespace art