blob: 2c1392be962a5b0344fbc389a7a19ffa2ee8a9fa [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)
Roland Levillain4d027112015-07-01 15:41:14 +0100216 : 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
Roland Levillain4fa13f62015-07-06 18:11:54 +0100366inline Condition X86_64IntegerCondition(IfCondition cond) {
Dave Allison20dfc792014-06-16 20:44:29 -0700367 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;
Dave Allison20dfc792014-06-16 20:44:29 -0700374 }
Roland Levillain4fa13f62015-07-06 18:11:54 +0100375 LOG(FATAL) << "Unreachable";
376 UNREACHABLE();
377}
378
379inline Condition X86_64FPCondition(IfCondition cond) {
380 switch (cond) {
381 case kCondEQ: return kEqual;
382 case kCondNE: return kNotEqual;
383 case kCondLT: return kBelow;
384 case kCondLE: return kBelowEqual;
385 case kCondGT: return kAbove;
386 case kCondGE: return kAboveEqual;
387 };
388 LOG(FATAL) << "Unreachable";
389 UNREACHABLE();
Dave Allison20dfc792014-06-16 20:44:29 -0700390}
391
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800392void CodeGeneratorX86_64::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke,
Nicolas Geoffray38207af2015-06-01 15:46:22 +0100393 Location temp) {
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800394 // All registers are assumed to be correctly set up.
395
396 // TODO: Implement all kinds of calls:
397 // 1) boot -> boot
398 // 2) app -> boot
399 // 3) app -> app
400 //
401 // Currently we implement the app -> app logic, which looks up in the resolve cache.
402
Jeff Hao848f70a2014-01-15 13:49:50 -0800403 if (invoke->IsStringInit()) {
Nicolas Geoffray38207af2015-06-01 15:46:22 +0100404 CpuRegister reg = temp.AsRegister<CpuRegister>();
Jeff Hao848f70a2014-01-15 13:49:50 -0800405 // temp = thread->string_init_entrypoint
Jeff Haocad65422015-06-18 21:16:08 -0700406 __ gs()->movq(reg, Address::Absolute(invoke->GetStringInitOffset(), true));
Nicolas Geoffray1cf95282014-12-12 19:22:03 +0000407 // (temp + offset_of_quick_compiled_code)()
Nicolas Geoffray38207af2015-06-01 15:46:22 +0100408 __ call(Address(reg, ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Nicolas Geoffray1cf95282014-12-12 19:22:03 +0000409 kX86_64WordSize).SizeValue()));
Nicolas Geoffray38207af2015-06-01 15:46:22 +0100410 } else if (invoke->IsRecursive()) {
411 __ call(&frame_entry_label_);
Nicolas Geoffray1cf95282014-12-12 19:22:03 +0000412 } else {
Nicolas Geoffray38207af2015-06-01 15:46:22 +0100413 CpuRegister reg = temp.AsRegister<CpuRegister>();
Nicolas Geoffrayae71a052015-06-09 14:12:28 +0100414 Location current_method = invoke->GetLocations()->InAt(invoke->GetCurrentMethodInputIndex());
415 Register method_reg;
416 if (current_method.IsRegister()) {
417 method_reg = current_method.AsRegister<Register>();
418 } else {
419 DCHECK(invoke->GetLocations()->Intrinsified());
420 DCHECK(!current_method.IsValid());
421 method_reg = reg.AsRegister();
422 __ movq(reg, Address(CpuRegister(RSP), kCurrentMethodStackOffset));
423 }
Nicolas Geoffray38207af2015-06-01 15:46:22 +0100424 // temp = temp->dex_cache_resolved_methods_;
Nicolas Geoffrayae71a052015-06-09 14:12:28 +0100425 __ movl(reg, Address(CpuRegister(method_reg),
426 ArtMethod::DexCacheResolvedMethodsOffset().SizeValue()));
Nicolas Geoffray38207af2015-06-01 15:46:22 +0100427 // temp = temp[index_in_cache]
428 __ movq(reg, Address(
429 reg, CodeGenerator::GetCachePointerOffset(invoke->GetDexMethodIndex())));
430 // (temp + offset_of_quick_compiled_code)()
431 __ call(Address(reg, ArtMethod::EntryPointFromQuickCompiledCodeOffset(
432 kX86_64WordSize).SizeValue()));
Nicolas Geoffray1cf95282014-12-12 19:22:03 +0000433 }
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800434
435 DCHECK(!IsLeafMethod());
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800436}
437
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100438void CodeGeneratorX86_64::DumpCoreRegister(std::ostream& stream, int reg) const {
David Brazdilc74652862015-05-13 17:50:09 +0100439 stream << Register(reg);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100440}
441
442void CodeGeneratorX86_64::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
David Brazdilc74652862015-05-13 17:50:09 +0100443 stream << FloatRegister(reg);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100444}
445
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100446size_t CodeGeneratorX86_64::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
447 __ movq(Address(CpuRegister(RSP), stack_index), CpuRegister(reg_id));
448 return kX86_64WordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100449}
450
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100451size_t CodeGeneratorX86_64::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
452 __ movq(CpuRegister(reg_id), Address(CpuRegister(RSP), stack_index));
453 return kX86_64WordSize;
454}
455
456size_t CodeGeneratorX86_64::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
457 __ movsd(Address(CpuRegister(RSP), stack_index), XmmRegister(reg_id));
458 return kX86_64WordSize;
459}
460
461size_t CodeGeneratorX86_64::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
462 __ movsd(XmmRegister(reg_id), Address(CpuRegister(RSP), stack_index));
463 return kX86_64WordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100464}
465
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000466static constexpr int kNumberOfCpuRegisterPairs = 0;
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +0000467// Use a fake return address register to mimic Quick.
468static constexpr Register kFakeReturnRegister = Register(kLastCpuRegister + 1);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400469CodeGeneratorX86_64::CodeGeneratorX86_64(HGraph* graph,
470 const X86_64InstructionSetFeatures& isa_features,
471 const CompilerOptions& compiler_options)
Nicolas Geoffray98893962015-01-21 12:32:32 +0000472 : CodeGenerator(graph,
473 kNumberOfCpuRegisters,
474 kNumberOfFloatRegisters,
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000475 kNumberOfCpuRegisterPairs,
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000476 ComputeRegisterMask(reinterpret_cast<const int*>(kCoreCalleeSaves),
477 arraysize(kCoreCalleeSaves))
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +0000478 | (1 << kFakeReturnRegister),
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000479 ComputeRegisterMask(reinterpret_cast<const int*>(kFpuCalleeSaves),
480 arraysize(kFpuCalleeSaves)),
Nicolas Geoffray98893962015-01-21 12:32:32 +0000481 compiler_options),
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100482 block_labels_(graph->GetArena(), 0),
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100483 location_builder_(graph, this),
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000484 instruction_visitor_(graph, this),
Mark Mendellfb8d2792015-03-31 22:16:59 -0400485 move_resolver_(graph->GetArena(), this),
Mark Mendellf55c3e02015-03-26 21:07:46 -0400486 isa_features_(isa_features),
487 constant_area_start_(0) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000488 AddAllocatedRegister(Location::RegisterLocation(kFakeReturnRegister));
489}
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100490
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100491InstructionCodeGeneratorX86_64::InstructionCodeGeneratorX86_64(HGraph* graph,
492 CodeGeneratorX86_64* codegen)
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100493 : HGraphVisitor(graph),
494 assembler_(codegen->GetAssembler()),
495 codegen_(codegen) {}
496
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100497Location CodeGeneratorX86_64::AllocateFreeRegister(Primitive::Type type) const {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100498 switch (type) {
499 case Primitive::kPrimLong:
500 case Primitive::kPrimByte:
501 case Primitive::kPrimBoolean:
502 case Primitive::kPrimChar:
503 case Primitive::kPrimShort:
504 case Primitive::kPrimInt:
505 case Primitive::kPrimNot: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100506 size_t reg = FindFreeEntry(blocked_core_registers_, kNumberOfCpuRegisters);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100507 return Location::RegisterLocation(reg);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100508 }
509
510 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100511 case Primitive::kPrimDouble: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100512 size_t reg = FindFreeEntry(blocked_fpu_registers_, kNumberOfFloatRegisters);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100513 return Location::FpuRegisterLocation(reg);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100514 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100515
516 case Primitive::kPrimVoid:
517 LOG(FATAL) << "Unreachable type " << type;
518 }
519
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100520 return Location();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100521}
522
Nicolas Geoffray98893962015-01-21 12:32:32 +0000523void CodeGeneratorX86_64::SetupBlockedRegisters(bool is_baseline) const {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100524 // Stack register is always reserved.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100525 blocked_core_registers_[RSP] = true;
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100526
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000527 // Block the register used as TMP.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100528 blocked_core_registers_[TMP] = true;
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000529
Nicolas Geoffray98893962015-01-21 12:32:32 +0000530 if (is_baseline) {
531 for (size_t i = 0; i < arraysize(kCoreCalleeSaves); ++i) {
532 blocked_core_registers_[kCoreCalleeSaves[i]] = true;
533 }
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000534 for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
535 blocked_fpu_registers_[kFpuCalleeSaves[i]] = true;
536 }
Nicolas Geoffray98893962015-01-21 12:32:32 +0000537 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100538}
539
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100540static dwarf::Reg DWARFReg(Register reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +0100541 return dwarf::Reg::X86_64Core(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100542}
David Srbecky9d8606d2015-04-12 09:35:32 +0100543
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100544static dwarf::Reg DWARFReg(FloatRegister reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +0100545 return dwarf::Reg::X86_64Fp(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100546}
547
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100548void CodeGeneratorX86_64::GenerateFrameEntry() {
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100549 __ cfi().SetCurrentCFAOffset(kX86_64WordSize); // return address
Nicolas Geoffray1cf95282014-12-12 19:22:03 +0000550 __ Bind(&frame_entry_label_);
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100551 bool skip_overflow_check = IsLeafMethod()
Dave Allison648d7112014-07-25 16:15:27 -0700552 && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kX86_64);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000553 DCHECK(GetCompilerOptions().GetImplicitStackOverflowChecks());
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100554
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000555 if (!skip_overflow_check) {
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100556 __ testq(CpuRegister(RAX), Address(
557 CpuRegister(RSP), -static_cast<int32_t>(GetStackOverflowReservedBytes(kX86_64))));
Nicolas Geoffray39468442014-09-02 15:17:15 +0100558 RecordPcInfo(nullptr, 0);
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100559 }
Nicolas Geoffraya26369a2015-01-22 08:46:05 +0000560
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000561 if (HasEmptyFrame()) {
562 return;
563 }
564
Nicolas Geoffray98893962015-01-21 12:32:32 +0000565 for (int i = arraysize(kCoreCalleeSaves) - 1; i >= 0; --i) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000566 Register reg = kCoreCalleeSaves[i];
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +0000567 if (allocated_registers_.ContainsCoreRegister(reg)) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000568 __ pushq(CpuRegister(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100569 __ cfi().AdjustCFAOffset(kX86_64WordSize);
570 __ cfi().RelOffset(DWARFReg(reg), 0);
Nicolas Geoffray98893962015-01-21 12:32:32 +0000571 }
572 }
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100573
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100574 int adjust = GetFrameSize() - GetCoreSpillSize();
575 __ subq(CpuRegister(RSP), Immediate(adjust));
576 __ cfi().AdjustCFAOffset(adjust);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000577 uint32_t xmm_spill_location = GetFpuSpillStart();
578 size_t xmm_spill_slot_size = GetFloatingPointSpillSlotSize();
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100579
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000580 for (int i = arraysize(kFpuCalleeSaves) - 1; i >= 0; --i) {
581 if (allocated_registers_.ContainsFloatingPointRegister(kFpuCalleeSaves[i])) {
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100582 int offset = xmm_spill_location + (xmm_spill_slot_size * i);
583 __ movsd(Address(CpuRegister(RSP), offset), XmmRegister(kFpuCalleeSaves[i]));
584 __ cfi().RelOffset(DWARFReg(kFpuCalleeSaves[i]), offset);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000585 }
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100586 }
587
Mathieu Chartiere401d142015-04-22 13:56:20 -0700588 __ movq(Address(CpuRegister(RSP), kCurrentMethodStackOffset),
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100589 CpuRegister(kMethodRegisterArgument));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100590}
591
592void CodeGeneratorX86_64::GenerateFrameExit() {
David Srbeckyc34dc932015-04-12 09:27:43 +0100593 __ cfi().RememberState();
594 if (!HasEmptyFrame()) {
595 uint32_t xmm_spill_location = GetFpuSpillStart();
596 size_t xmm_spill_slot_size = GetFloatingPointSpillSlotSize();
597 for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
598 if (allocated_registers_.ContainsFloatingPointRegister(kFpuCalleeSaves[i])) {
599 int offset = xmm_spill_location + (xmm_spill_slot_size * i);
600 __ movsd(XmmRegister(kFpuCalleeSaves[i]), Address(CpuRegister(RSP), offset));
601 __ cfi().Restore(DWARFReg(kFpuCalleeSaves[i]));
602 }
603 }
604
605 int adjust = GetFrameSize() - GetCoreSpillSize();
606 __ addq(CpuRegister(RSP), Immediate(adjust));
607 __ cfi().AdjustCFAOffset(-adjust);
608
609 for (size_t i = 0; i < arraysize(kCoreCalleeSaves); ++i) {
610 Register reg = kCoreCalleeSaves[i];
611 if (allocated_registers_.ContainsCoreRegister(reg)) {
612 __ popq(CpuRegister(reg));
613 __ cfi().AdjustCFAOffset(-static_cast<int>(kX86_64WordSize));
614 __ cfi().Restore(DWARFReg(reg));
615 }
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000616 }
617 }
David Srbeckyc34dc932015-04-12 09:27:43 +0100618 __ ret();
619 __ cfi().RestoreState();
620 __ cfi().DefCFAOffset(GetFrameSize());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100621}
622
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100623void CodeGeneratorX86_64::Bind(HBasicBlock* block) {
624 __ Bind(GetLabelOf(block));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100625}
626
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100627Location CodeGeneratorX86_64::GetStackLocation(HLoadLocal* load) const {
628 switch (load->GetType()) {
629 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100630 case Primitive::kPrimDouble:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100631 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100632
633 case Primitive::kPrimInt:
634 case Primitive::kPrimNot:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100635 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100636 return Location::StackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100637
638 case Primitive::kPrimBoolean:
639 case Primitive::kPrimByte:
640 case Primitive::kPrimChar:
641 case Primitive::kPrimShort:
642 case Primitive::kPrimVoid:
643 LOG(FATAL) << "Unexpected type " << load->GetType();
Andreas Gampe65b798e2015-04-06 09:35:22 -0700644 UNREACHABLE();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100645 }
646
647 LOG(FATAL) << "Unreachable";
Andreas Gampe65b798e2015-04-06 09:35:22 -0700648 UNREACHABLE();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100649}
650
651void CodeGeneratorX86_64::Move(Location destination, Location source) {
652 if (source.Equals(destination)) {
653 return;
654 }
655 if (destination.IsRegister()) {
656 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000657 __ movq(destination.AsRegister<CpuRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100658 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000659 __ movd(destination.AsRegister<CpuRegister>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100660 } else if (source.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000661 __ movl(destination.AsRegister<CpuRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100662 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100663 } else {
664 DCHECK(source.IsDoubleStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +0000665 __ movq(destination.AsRegister<CpuRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100666 Address(CpuRegister(RSP), source.GetStackIndex()));
667 }
668 } else if (destination.IsFpuRegister()) {
669 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000670 __ movd(destination.AsFpuRegister<XmmRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100671 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000672 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100673 } else if (source.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000674 __ movss(destination.AsFpuRegister<XmmRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100675 Address(CpuRegister(RSP), source.GetStackIndex()));
676 } else {
677 DCHECK(source.IsDoubleStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +0000678 __ movsd(destination.AsFpuRegister<XmmRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100679 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100680 }
681 } else if (destination.IsStackSlot()) {
682 if (source.IsRegister()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100683 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +0000684 source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100685 } else if (source.IsFpuRegister()) {
686 __ movss(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +0000687 source.AsFpuRegister<XmmRegister>());
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500688 } else if (source.IsConstant()) {
689 HConstant* constant = source.GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000690 int32_t value = GetInt32ValueOf(constant);
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500691 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), Immediate(value));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100692 } else {
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500693 DCHECK(source.IsStackSlot()) << source;
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000694 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
695 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100696 }
697 } else {
698 DCHECK(destination.IsDoubleStackSlot());
699 if (source.IsRegister()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100700 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +0000701 source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100702 } else if (source.IsFpuRegister()) {
703 __ movsd(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +0000704 source.AsFpuRegister<XmmRegister>());
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500705 } else if (source.IsConstant()) {
706 HConstant* constant = source.GetConstant();
Zheng Xu12bca972015-03-30 19:35:50 +0800707 int64_t value;
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500708 if (constant->IsDoubleConstant()) {
Roland Levillainda4d79b2015-03-24 14:36:11 +0000709 value = bit_cast<int64_t, double>(constant->AsDoubleConstant()->GetValue());
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500710 } else {
711 DCHECK(constant->IsLongConstant());
712 value = constant->AsLongConstant()->GetValue();
713 }
Mark Mendell92e83bf2015-05-07 11:25:03 -0400714 Load64BitValue(CpuRegister(TMP), value);
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500715 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100716 } else {
717 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000718 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
719 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100720 }
721 }
722}
723
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100724void CodeGeneratorX86_64::Move(HInstruction* instruction,
725 Location location,
726 HInstruction* move_for) {
Calin Juravlea21f5982014-11-13 15:53:04 +0000727 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100728 if (instruction->IsCurrentMethod()) {
Mathieu Chartiere3b034a2015-05-31 14:29:23 -0700729 Move(location, Location::DoubleStackSlot(kCurrentMethodStackOffset));
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100730 } else if (locations != nullptr && locations->Out().Equals(location)) {
Calin Juravlea21f5982014-11-13 15:53:04 +0000731 return;
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100732 } else if (locations != nullptr && locations->Out().IsConstant()) {
Calin Juravlea21f5982014-11-13 15:53:04 +0000733 HConstant* const_to_move = locations->Out().GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000734 if (const_to_move->IsIntConstant() || const_to_move->IsNullConstant()) {
735 Immediate imm(GetInt32ValueOf(const_to_move));
Calin Juravlea21f5982014-11-13 15:53:04 +0000736 if (location.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000737 __ movl(location.AsRegister<CpuRegister>(), imm);
Calin Juravlea21f5982014-11-13 15:53:04 +0000738 } else if (location.IsStackSlot()) {
739 __ movl(Address(CpuRegister(RSP), location.GetStackIndex()), imm);
740 } else {
741 DCHECK(location.IsConstant());
742 DCHECK_EQ(location.GetConstant(), const_to_move);
743 }
744 } else if (const_to_move->IsLongConstant()) {
745 int64_t value = const_to_move->AsLongConstant()->GetValue();
746 if (location.IsRegister()) {
Mark Mendell92e83bf2015-05-07 11:25:03 -0400747 Load64BitValue(location.AsRegister<CpuRegister>(), value);
Calin Juravlea21f5982014-11-13 15:53:04 +0000748 } else if (location.IsDoubleStackSlot()) {
Mark Mendell92e83bf2015-05-07 11:25:03 -0400749 Load64BitValue(CpuRegister(TMP), value);
Calin Juravlea21f5982014-11-13 15:53:04 +0000750 __ movq(Address(CpuRegister(RSP), location.GetStackIndex()), CpuRegister(TMP));
751 } else {
752 DCHECK(location.IsConstant());
753 DCHECK_EQ(location.GetConstant(), const_to_move);
754 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100755 }
Roland Levillain476df552014-10-09 17:51:36 +0100756 } else if (instruction->IsLoadLocal()) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100757 switch (instruction->GetType()) {
758 case Primitive::kPrimBoolean:
759 case Primitive::kPrimByte:
760 case Primitive::kPrimChar:
761 case Primitive::kPrimShort:
762 case Primitive::kPrimInt:
763 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100764 case Primitive::kPrimFloat:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100765 Move(location, Location::StackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
766 break;
767
768 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100769 case Primitive::kPrimDouble:
Roland Levillain199f3362014-11-27 17:15:16 +0000770 Move(location,
771 Location::DoubleStackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100772 break;
773
774 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100775 LOG(FATAL) << "Unexpected local type " << instruction->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100776 }
Nicolas Geoffrayf43083d2014-11-07 10:48:10 +0000777 } else if (instruction->IsTemporary()) {
778 Location temp_location = GetTemporaryLocation(instruction->AsTemporary());
779 Move(location, temp_location);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100780 } else {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100781 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100782 switch (instruction->GetType()) {
783 case Primitive::kPrimBoolean:
784 case Primitive::kPrimByte:
785 case Primitive::kPrimChar:
786 case Primitive::kPrimShort:
787 case Primitive::kPrimInt:
788 case Primitive::kPrimNot:
789 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100790 case Primitive::kPrimFloat:
791 case Primitive::kPrimDouble:
Calin Juravlea21f5982014-11-13 15:53:04 +0000792 Move(location, locations->Out());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100793 break;
794
795 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100796 LOG(FATAL) << "Unexpected type " << instruction->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100797 }
798 }
799}
800
David Brazdilfc6a86a2015-06-26 10:33:45 +0000801void InstructionCodeGeneratorX86_64::HandleGoto(HInstruction* got, HBasicBlock* successor) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100802 DCHECK(!successor->IsExitBlock());
803
804 HBasicBlock* block = got->GetBlock();
805 HInstruction* previous = got->GetPrevious();
806
807 HLoopInformation* info = block->GetLoopInformation();
David Brazdil46e2a392015-03-16 17:31:52 +0000808 if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100809 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
810 return;
811 }
812
813 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
814 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
815 }
816 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100817 __ jmp(codegen_->GetLabelOf(successor));
818 }
819}
820
David Brazdilfc6a86a2015-06-26 10:33:45 +0000821void LocationsBuilderX86_64::VisitGoto(HGoto* got) {
822 got->SetLocations(nullptr);
823}
824
825void InstructionCodeGeneratorX86_64::VisitGoto(HGoto* got) {
826 HandleGoto(got, got->GetSuccessor());
827}
828
829void LocationsBuilderX86_64::VisitTryBoundary(HTryBoundary* try_boundary) {
830 try_boundary->SetLocations(nullptr);
831}
832
833void InstructionCodeGeneratorX86_64::VisitTryBoundary(HTryBoundary* try_boundary) {
834 HBasicBlock* successor = try_boundary->GetNormalFlowSuccessor();
835 if (!successor->IsExitBlock()) {
836 HandleGoto(try_boundary, successor);
837 }
838}
839
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100840void LocationsBuilderX86_64::VisitExit(HExit* exit) {
841 exit->SetLocations(nullptr);
842}
843
844void InstructionCodeGeneratorX86_64::VisitExit(HExit* exit) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700845 UNUSED(exit);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100846}
847
Mark Mendellc4701932015-04-10 13:18:51 -0400848void InstructionCodeGeneratorX86_64::GenerateFPJumps(HCondition* cond,
849 Label* true_label,
850 Label* false_label) {
Roland Levillain4fa13f62015-07-06 18:11:54 +0100851 if (cond->IsFPConditionTrueIfNaN()) {
852 __ j(kUnordered, true_label);
853 } else if (cond->IsFPConditionFalseIfNaN()) {
854 __ j(kUnordered, false_label);
Mark Mendellc4701932015-04-10 13:18:51 -0400855 }
Roland Levillain4fa13f62015-07-06 18:11:54 +0100856 __ j(X86_64FPCondition(cond->GetCondition()), true_label);
Mark Mendellc4701932015-04-10 13:18:51 -0400857}
858
859void InstructionCodeGeneratorX86_64::GenerateCompareTestAndBranch(HIf* if_instr,
860 HCondition* condition,
861 Label* true_target,
862 Label* false_target,
863 Label* always_true_target) {
864 LocationSummary* locations = condition->GetLocations();
865 Location left = locations->InAt(0);
866 Location right = locations->InAt(1);
867
868 // We don't want true_target as a nullptr.
869 if (true_target == nullptr) {
870 true_target = always_true_target;
871 }
872 bool falls_through = (false_target == nullptr);
873
874 // FP compares don't like null false_targets.
875 if (false_target == nullptr) {
876 false_target = codegen_->GetLabelOf(if_instr->IfFalseSuccessor());
877 }
878
879 Primitive::Type type = condition->InputAt(0)->GetType();
880 switch (type) {
881 case Primitive::kPrimLong: {
882 CpuRegister left_reg = left.AsRegister<CpuRegister>();
883 if (right.IsConstant()) {
884 int64_t value = right.GetConstant()->AsLongConstant()->GetValue();
885 if (IsInt<32>(value)) {
886 if (value == 0) {
887 __ testq(left_reg, left_reg);
888 } else {
889 __ cmpq(left_reg, Immediate(static_cast<int32_t>(value)));
890 }
891 } else {
Roland Levillain4fa13f62015-07-06 18:11:54 +0100892 // Value won't fit in a 32-bit integer.
Mark Mendellc4701932015-04-10 13:18:51 -0400893 __ cmpq(left_reg, codegen_->LiteralInt64Address(value));
894 }
895 } else if (right.IsDoubleStackSlot()) {
896 __ cmpq(left_reg, Address(CpuRegister(RSP), right.GetStackIndex()));
897 } else {
898 __ cmpq(left_reg, right.AsRegister<CpuRegister>());
899 }
Roland Levillain4fa13f62015-07-06 18:11:54 +0100900 __ j(X86_64IntegerCondition(condition->GetCondition()), true_target);
Mark Mendellc4701932015-04-10 13:18:51 -0400901 break;
902 }
903 case Primitive::kPrimFloat: {
904 if (right.IsFpuRegister()) {
905 __ ucomiss(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
906 } else if (right.IsConstant()) {
907 __ ucomiss(left.AsFpuRegister<XmmRegister>(),
908 codegen_->LiteralFloatAddress(
909 right.GetConstant()->AsFloatConstant()->GetValue()));
910 } else {
911 DCHECK(right.IsStackSlot());
912 __ ucomiss(left.AsFpuRegister<XmmRegister>(),
913 Address(CpuRegister(RSP), right.GetStackIndex()));
914 }
915 GenerateFPJumps(condition, true_target, false_target);
916 break;
917 }
918 case Primitive::kPrimDouble: {
919 if (right.IsFpuRegister()) {
920 __ ucomisd(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
921 } else if (right.IsConstant()) {
922 __ ucomisd(left.AsFpuRegister<XmmRegister>(),
923 codegen_->LiteralDoubleAddress(
924 right.GetConstant()->AsDoubleConstant()->GetValue()));
925 } else {
926 DCHECK(right.IsDoubleStackSlot());
927 __ ucomisd(left.AsFpuRegister<XmmRegister>(),
928 Address(CpuRegister(RSP), right.GetStackIndex()));
929 }
930 GenerateFPJumps(condition, true_target, false_target);
931 break;
932 }
933 default:
934 LOG(FATAL) << "Unexpected condition type " << type;
935 }
936
937 if (!falls_through) {
938 __ jmp(false_target);
939 }
940}
941
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700942void InstructionCodeGeneratorX86_64::GenerateTestAndBranch(HInstruction* instruction,
943 Label* true_target,
944 Label* false_target,
945 Label* always_true_target) {
946 HInstruction* cond = instruction->InputAt(0);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100947 if (cond->IsIntConstant()) {
948 // Constant condition, statically compared against 1.
949 int32_t cond_value = cond->AsIntConstant()->GetValue();
950 if (cond_value == 1) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700951 if (always_true_target != nullptr) {
952 __ jmp(always_true_target);
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100953 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100954 return;
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100955 } else {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100956 DCHECK_EQ(cond_value, 0);
957 }
958 } else {
Roland Levillain4fa13f62015-07-06 18:11:54 +0100959 bool is_materialized =
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100960 !cond->IsCondition() || cond->AsCondition()->NeedsMaterialization();
961 // Moves do not affect the eflags register, so if the condition is
962 // evaluated just before the if, we don't need to evaluate it
Mark Mendellc4701932015-04-10 13:18:51 -0400963 // again. We can't use the eflags on FP conditions if they are
964 // materialized due to the complex branching.
965 Primitive::Type type = cond->IsCondition() ? cond->InputAt(0)->GetType() : Primitive::kPrimInt;
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100966 bool eflags_set = cond->IsCondition()
Mark Mendellc4701932015-04-10 13:18:51 -0400967 && cond->AsCondition()->IsBeforeWhenDisregardMoves(instruction)
968 && !Primitive::IsFloatingPointType(type);
969
Roland Levillain4fa13f62015-07-06 18:11:54 +0100970 if (is_materialized) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100971 if (!eflags_set) {
972 // Materialized condition, compare against 0.
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700973 Location lhs = instruction->GetLocations()->InAt(0);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100974 if (lhs.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +0000975 __ testl(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>());
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100976 } else {
977 __ cmpl(Address(CpuRegister(RSP), lhs.GetStackIndex()),
978 Immediate(0));
979 }
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700980 __ j(kNotEqual, true_target);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100981 } else {
Roland Levillain4fa13f62015-07-06 18:11:54 +0100982 __ j(X86_64IntegerCondition(cond->AsCondition()->GetCondition()), true_target);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100983 }
984 } else {
Roland Levillain4fa13f62015-07-06 18:11:54 +0100985 // Condition has not been materialized, use its inputs as the
986 // comparison and its condition as the branch condition.
987
Mark Mendellc4701932015-04-10 13:18:51 -0400988 // Is this a long or FP comparison that has been folded into the HCondition?
989 if (type == Primitive::kPrimLong || Primitive::IsFloatingPointType(type)) {
Roland Levillain4fa13f62015-07-06 18:11:54 +0100990 // Generate the comparison directly.
Mark Mendellc4701932015-04-10 13:18:51 -0400991 GenerateCompareTestAndBranch(instruction->AsIf(), cond->AsCondition(),
992 true_target, false_target, always_true_target);
993 return;
994 }
Roland Levillain4fa13f62015-07-06 18:11:54 +0100995
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100996 Location lhs = cond->GetLocations()->InAt(0);
997 Location rhs = cond->GetLocations()->InAt(1);
998 if (rhs.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000999 __ cmpl(lhs.AsRegister<CpuRegister>(), rhs.AsRegister<CpuRegister>());
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001000 } else if (rhs.IsConstant()) {
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001001 int32_t constant = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
Nicolas Geoffray748f1402015-01-27 08:17:54 +00001002 if (constant == 0) {
1003 __ testl(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>());
1004 } else {
1005 __ cmpl(lhs.AsRegister<CpuRegister>(), Immediate(constant));
1006 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001007 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001008 __ cmpl(lhs.AsRegister<CpuRegister>(),
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001009 Address(CpuRegister(RSP), rhs.GetStackIndex()));
1010 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001011 __ j(X86_64IntegerCondition(cond->AsCondition()->GetCondition()), true_target);
Dave Allison20dfc792014-06-16 20:44:29 -07001012 }
Dave Allison20dfc792014-06-16 20:44:29 -07001013 }
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001014 if (false_target != nullptr) {
1015 __ jmp(false_target);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001016 }
1017}
1018
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001019void LocationsBuilderX86_64::VisitIf(HIf* if_instr) {
1020 LocationSummary* locations =
1021 new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall);
1022 HInstruction* cond = if_instr->InputAt(0);
1023 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
1024 locations->SetInAt(0, Location::Any());
1025 }
1026}
1027
1028void InstructionCodeGeneratorX86_64::VisitIf(HIf* if_instr) {
1029 Label* true_target = codegen_->GetLabelOf(if_instr->IfTrueSuccessor());
1030 Label* false_target = codegen_->GetLabelOf(if_instr->IfFalseSuccessor());
1031 Label* always_true_target = true_target;
1032 if (codegen_->GoesToNextBlock(if_instr->GetBlock(),
1033 if_instr->IfTrueSuccessor())) {
1034 always_true_target = nullptr;
1035 }
1036 if (codegen_->GoesToNextBlock(if_instr->GetBlock(),
1037 if_instr->IfFalseSuccessor())) {
1038 false_target = nullptr;
1039 }
1040 GenerateTestAndBranch(if_instr, true_target, false_target, always_true_target);
1041}
1042
1043void LocationsBuilderX86_64::VisitDeoptimize(HDeoptimize* deoptimize) {
1044 LocationSummary* locations = new (GetGraph()->GetArena())
1045 LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
1046 HInstruction* cond = deoptimize->InputAt(0);
1047 DCHECK(cond->IsCondition());
1048 if (cond->AsCondition()->NeedsMaterialization()) {
1049 locations->SetInAt(0, Location::Any());
1050 }
1051}
1052
1053void InstructionCodeGeneratorX86_64::VisitDeoptimize(HDeoptimize* deoptimize) {
1054 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena())
1055 DeoptimizationSlowPathX86_64(deoptimize);
1056 codegen_->AddSlowPath(slow_path);
1057 Label* slow_path_entry = slow_path->GetEntryLabel();
1058 GenerateTestAndBranch(deoptimize, slow_path_entry, nullptr, slow_path_entry);
1059}
1060
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001061void LocationsBuilderX86_64::VisitLocal(HLocal* local) {
1062 local->SetLocations(nullptr);
1063}
1064
1065void InstructionCodeGeneratorX86_64::VisitLocal(HLocal* local) {
1066 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
1067}
1068
1069void LocationsBuilderX86_64::VisitLoadLocal(HLoadLocal* local) {
1070 local->SetLocations(nullptr);
1071}
1072
1073void InstructionCodeGeneratorX86_64::VisitLoadLocal(HLoadLocal* load) {
1074 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001075 UNUSED(load);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001076}
1077
1078void LocationsBuilderX86_64::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001079 LocationSummary* locations =
1080 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001081 switch (store->InputAt(1)->GetType()) {
1082 case Primitive::kPrimBoolean:
1083 case Primitive::kPrimByte:
1084 case Primitive::kPrimChar:
1085 case Primitive::kPrimShort:
1086 case Primitive::kPrimInt:
1087 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001088 case Primitive::kPrimFloat:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001089 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
1090 break;
1091
1092 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001093 case Primitive::kPrimDouble:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001094 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
1095 break;
1096
1097 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001098 LOG(FATAL) << "Unexpected local type " << store->InputAt(1)->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001099 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001100}
1101
1102void InstructionCodeGeneratorX86_64::VisitStoreLocal(HStoreLocal* store) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001103 UNUSED(store);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001104}
1105
Roland Levillain0d37cd02015-05-27 16:39:19 +01001106void LocationsBuilderX86_64::VisitCondition(HCondition* cond) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001107 LocationSummary* locations =
Roland Levillain0d37cd02015-05-27 16:39:19 +01001108 new (GetGraph()->GetArena()) LocationSummary(cond, LocationSummary::kNoCall);
Mark Mendellc4701932015-04-10 13:18:51 -04001109 // Handle the long/FP comparisons made in instruction simplification.
1110 switch (cond->InputAt(0)->GetType()) {
1111 case Primitive::kPrimLong:
1112 locations->SetInAt(0, Location::RequiresRegister());
1113 locations->SetInAt(1, Location::Any());
1114 break;
1115 case Primitive::kPrimFloat:
1116 case Primitive::kPrimDouble:
1117 locations->SetInAt(0, Location::RequiresFpuRegister());
1118 locations->SetInAt(1, Location::Any());
1119 break;
1120 default:
1121 locations->SetInAt(0, Location::RequiresRegister());
1122 locations->SetInAt(1, Location::Any());
1123 break;
1124 }
Roland Levillain0d37cd02015-05-27 16:39:19 +01001125 if (cond->NeedsMaterialization()) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001126 locations->SetOut(Location::RequiresRegister());
1127 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001128}
1129
Roland Levillain0d37cd02015-05-27 16:39:19 +01001130void InstructionCodeGeneratorX86_64::VisitCondition(HCondition* cond) {
Mark Mendellc4701932015-04-10 13:18:51 -04001131 if (!cond->NeedsMaterialization()) {
1132 return;
Dave Allison20dfc792014-06-16 20:44:29 -07001133 }
Mark Mendellc4701932015-04-10 13:18:51 -04001134
1135 LocationSummary* locations = cond->GetLocations();
1136 Location lhs = locations->InAt(0);
1137 Location rhs = locations->InAt(1);
1138 CpuRegister reg = locations->Out().AsRegister<CpuRegister>();
1139 Label true_label, false_label;
1140
1141 switch (cond->InputAt(0)->GetType()) {
1142 default:
1143 // Integer case.
1144
1145 // Clear output register: setcc only sets the low byte.
1146 __ xorl(reg, reg);
1147
1148 if (rhs.IsRegister()) {
1149 __ cmpl(lhs.AsRegister<CpuRegister>(), rhs.AsRegister<CpuRegister>());
1150 } else if (rhs.IsConstant()) {
1151 int32_t constant = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
1152 if (constant == 0) {
1153 __ testl(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>());
1154 } else {
1155 __ cmpl(lhs.AsRegister<CpuRegister>(), Immediate(constant));
1156 }
1157 } else {
1158 __ cmpl(lhs.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), rhs.GetStackIndex()));
1159 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001160 __ setcc(X86_64IntegerCondition(cond->GetCondition()), reg);
Mark Mendellc4701932015-04-10 13:18:51 -04001161 return;
1162 case Primitive::kPrimLong:
1163 // Clear output register: setcc only sets the low byte.
1164 __ xorl(reg, reg);
1165
1166 if (rhs.IsRegister()) {
1167 __ cmpq(lhs.AsRegister<CpuRegister>(), rhs.AsRegister<CpuRegister>());
1168 } else if (rhs.IsConstant()) {
1169 int64_t value = rhs.GetConstant()->AsLongConstant()->GetValue();
1170 if (IsInt<32>(value)) {
1171 if (value == 0) {
1172 __ testq(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>());
1173 } else {
1174 __ cmpq(lhs.AsRegister<CpuRegister>(), Immediate(static_cast<int32_t>(value)));
1175 }
1176 } else {
1177 // Value won't fit in an int.
1178 __ cmpq(lhs.AsRegister<CpuRegister>(), codegen_->LiteralInt64Address(value));
1179 }
1180 } else {
1181 __ cmpq(lhs.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), rhs.GetStackIndex()));
1182 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001183 __ setcc(X86_64IntegerCondition(cond->GetCondition()), reg);
Mark Mendellc4701932015-04-10 13:18:51 -04001184 return;
1185 case Primitive::kPrimFloat: {
1186 XmmRegister lhs_reg = lhs.AsFpuRegister<XmmRegister>();
1187 if (rhs.IsConstant()) {
1188 float value = rhs.GetConstant()->AsFloatConstant()->GetValue();
1189 __ ucomiss(lhs_reg, codegen_->LiteralFloatAddress(value));
1190 } else if (rhs.IsStackSlot()) {
1191 __ ucomiss(lhs_reg, Address(CpuRegister(RSP), rhs.GetStackIndex()));
1192 } else {
1193 __ ucomiss(lhs_reg, rhs.AsFpuRegister<XmmRegister>());
1194 }
1195 GenerateFPJumps(cond, &true_label, &false_label);
1196 break;
1197 }
1198 case Primitive::kPrimDouble: {
1199 XmmRegister lhs_reg = lhs.AsFpuRegister<XmmRegister>();
1200 if (rhs.IsConstant()) {
1201 double value = rhs.GetConstant()->AsDoubleConstant()->GetValue();
1202 __ ucomisd(lhs_reg, codegen_->LiteralDoubleAddress(value));
1203 } else if (rhs.IsDoubleStackSlot()) {
1204 __ ucomisd(lhs_reg, Address(CpuRegister(RSP), rhs.GetStackIndex()));
1205 } else {
1206 __ ucomisd(lhs_reg, rhs.AsFpuRegister<XmmRegister>());
1207 }
1208 GenerateFPJumps(cond, &true_label, &false_label);
1209 break;
1210 }
1211 }
1212
1213 // Convert the jumps into the result.
1214 Label done_label;
1215
Roland Levillain4fa13f62015-07-06 18:11:54 +01001216 // False case: result = 0.
Mark Mendellc4701932015-04-10 13:18:51 -04001217 __ Bind(&false_label);
1218 __ xorl(reg, reg);
1219 __ jmp(&done_label);
1220
Roland Levillain4fa13f62015-07-06 18:11:54 +01001221 // True case: result = 1.
Mark Mendellc4701932015-04-10 13:18:51 -04001222 __ Bind(&true_label);
1223 __ movl(reg, Immediate(1));
1224 __ Bind(&done_label);
Dave Allison20dfc792014-06-16 20:44:29 -07001225}
1226
1227void LocationsBuilderX86_64::VisitEqual(HEqual* comp) {
1228 VisitCondition(comp);
1229}
1230
1231void InstructionCodeGeneratorX86_64::VisitEqual(HEqual* comp) {
1232 VisitCondition(comp);
1233}
1234
1235void LocationsBuilderX86_64::VisitNotEqual(HNotEqual* comp) {
1236 VisitCondition(comp);
1237}
1238
1239void InstructionCodeGeneratorX86_64::VisitNotEqual(HNotEqual* comp) {
1240 VisitCondition(comp);
1241}
1242
1243void LocationsBuilderX86_64::VisitLessThan(HLessThan* comp) {
1244 VisitCondition(comp);
1245}
1246
1247void InstructionCodeGeneratorX86_64::VisitLessThan(HLessThan* comp) {
1248 VisitCondition(comp);
1249}
1250
1251void LocationsBuilderX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1252 VisitCondition(comp);
1253}
1254
1255void InstructionCodeGeneratorX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1256 VisitCondition(comp);
1257}
1258
1259void LocationsBuilderX86_64::VisitGreaterThan(HGreaterThan* comp) {
1260 VisitCondition(comp);
1261}
1262
1263void InstructionCodeGeneratorX86_64::VisitGreaterThan(HGreaterThan* comp) {
1264 VisitCondition(comp);
1265}
1266
1267void LocationsBuilderX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1268 VisitCondition(comp);
1269}
1270
1271void InstructionCodeGeneratorX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1272 VisitCondition(comp);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001273}
1274
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001275void LocationsBuilderX86_64::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001276 LocationSummary* locations =
1277 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Calin Juravleddb7df22014-11-25 20:56:51 +00001278 switch (compare->InputAt(0)->GetType()) {
1279 case Primitive::kPrimLong: {
1280 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell40741f32015-04-20 22:10:34 -04001281 locations->SetInAt(1, Location::Any());
Calin Juravleddb7df22014-11-25 20:56:51 +00001282 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1283 break;
1284 }
1285 case Primitive::kPrimFloat:
1286 case Primitive::kPrimDouble: {
1287 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendell40741f32015-04-20 22:10:34 -04001288 locations->SetInAt(1, Location::Any());
Calin Juravleddb7df22014-11-25 20:56:51 +00001289 locations->SetOut(Location::RequiresRegister());
1290 break;
1291 }
1292 default:
1293 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
1294 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001295}
1296
1297void InstructionCodeGeneratorX86_64::VisitCompare(HCompare* compare) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001298 LocationSummary* locations = compare->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00001299 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Calin Juravleddb7df22014-11-25 20:56:51 +00001300 Location left = locations->InAt(0);
1301 Location right = locations->InAt(1);
1302
1303 Label less, greater, done;
1304 Primitive::Type type = compare->InputAt(0)->GetType();
1305 switch (type) {
1306 case Primitive::kPrimLong: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04001307 CpuRegister left_reg = left.AsRegister<CpuRegister>();
1308 if (right.IsConstant()) {
1309 int64_t value = right.GetConstant()->AsLongConstant()->GetValue();
Mark Mendell40741f32015-04-20 22:10:34 -04001310 if (IsInt<32>(value)) {
1311 if (value == 0) {
1312 __ testq(left_reg, left_reg);
1313 } else {
1314 __ cmpq(left_reg, Immediate(static_cast<int32_t>(value)));
1315 }
Mark Mendell3f6c7f62015-03-13 13:47:53 -04001316 } else {
Mark Mendell40741f32015-04-20 22:10:34 -04001317 // Value won't fit in an int.
1318 __ cmpq(left_reg, codegen_->LiteralInt64Address(value));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04001319 }
Mark Mendell40741f32015-04-20 22:10:34 -04001320 } else if (right.IsDoubleStackSlot()) {
1321 __ cmpq(left_reg, Address(CpuRegister(RSP), right.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04001322 } else {
1323 __ cmpq(left_reg, right.AsRegister<CpuRegister>());
1324 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001325 break;
Calin Juravleddb7df22014-11-25 20:56:51 +00001326 }
1327 case Primitive::kPrimFloat: {
Mark Mendell40741f32015-04-20 22:10:34 -04001328 XmmRegister left_reg = left.AsFpuRegister<XmmRegister>();
1329 if (right.IsConstant()) {
1330 float value = right.GetConstant()->AsFloatConstant()->GetValue();
1331 __ ucomiss(left_reg, codegen_->LiteralFloatAddress(value));
1332 } else if (right.IsStackSlot()) {
1333 __ ucomiss(left_reg, Address(CpuRegister(RSP), right.GetStackIndex()));
1334 } else {
1335 __ ucomiss(left_reg, right.AsFpuRegister<XmmRegister>());
1336 }
Calin Juravleddb7df22014-11-25 20:56:51 +00001337 __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
1338 break;
1339 }
1340 case Primitive::kPrimDouble: {
Mark Mendell40741f32015-04-20 22:10:34 -04001341 XmmRegister left_reg = left.AsFpuRegister<XmmRegister>();
1342 if (right.IsConstant()) {
1343 double value = right.GetConstant()->AsDoubleConstant()->GetValue();
1344 __ ucomisd(left_reg, codegen_->LiteralDoubleAddress(value));
1345 } else if (right.IsDoubleStackSlot()) {
1346 __ ucomisd(left_reg, Address(CpuRegister(RSP), right.GetStackIndex()));
1347 } else {
1348 __ ucomisd(left_reg, right.AsFpuRegister<XmmRegister>());
1349 }
Calin Juravleddb7df22014-11-25 20:56:51 +00001350 __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
1351 break;
1352 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001353 default:
Calin Juravleddb7df22014-11-25 20:56:51 +00001354 LOG(FATAL) << "Unexpected compare type " << type;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001355 }
Calin Juravleddb7df22014-11-25 20:56:51 +00001356 __ movl(out, Immediate(0));
Calin Juravle91debbc2014-11-26 19:01:09 +00001357 __ j(kEqual, &done);
Calin Juravleddb7df22014-11-25 20:56:51 +00001358 __ j(type == Primitive::kPrimLong ? kLess : kBelow, &less); // ucomis{s,d} sets CF (kBelow)
Calin Juravlefd861242014-11-25 20:56:51 +00001359
Calin Juravle91debbc2014-11-26 19:01:09 +00001360 __ Bind(&greater);
Calin Juravleddb7df22014-11-25 20:56:51 +00001361 __ movl(out, Immediate(1));
1362 __ jmp(&done);
1363
1364 __ Bind(&less);
1365 __ movl(out, Immediate(-1));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001366
1367 __ Bind(&done);
1368}
1369
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001370void LocationsBuilderX86_64::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001371 LocationSummary* locations =
1372 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001373 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001374}
1375
1376void InstructionCodeGeneratorX86_64::VisitIntConstant(HIntConstant* constant) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001377 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001378 UNUSED(constant);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001379}
1380
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001381void LocationsBuilderX86_64::VisitNullConstant(HNullConstant* constant) {
1382 LocationSummary* locations =
1383 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1384 locations->SetOut(Location::ConstantLocation(constant));
1385}
1386
1387void InstructionCodeGeneratorX86_64::VisitNullConstant(HNullConstant* constant) {
1388 // Will be generated at use site.
1389 UNUSED(constant);
1390}
1391
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001392void LocationsBuilderX86_64::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001393 LocationSummary* locations =
1394 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001395 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001396}
1397
1398void InstructionCodeGeneratorX86_64::VisitLongConstant(HLongConstant* constant) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001399 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001400 UNUSED(constant);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001401}
1402
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001403void LocationsBuilderX86_64::VisitFloatConstant(HFloatConstant* constant) {
1404 LocationSummary* locations =
1405 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1406 locations->SetOut(Location::ConstantLocation(constant));
1407}
1408
1409void InstructionCodeGeneratorX86_64::VisitFloatConstant(HFloatConstant* constant) {
1410 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001411 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001412}
1413
1414void LocationsBuilderX86_64::VisitDoubleConstant(HDoubleConstant* constant) {
1415 LocationSummary* locations =
1416 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1417 locations->SetOut(Location::ConstantLocation(constant));
1418}
1419
1420void InstructionCodeGeneratorX86_64::VisitDoubleConstant(HDoubleConstant* constant) {
1421 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001422 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001423}
1424
Calin Juravle27df7582015-04-17 19:12:31 +01001425void LocationsBuilderX86_64::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
1426 memory_barrier->SetLocations(nullptr);
1427}
1428
1429void InstructionCodeGeneratorX86_64::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
1430 GenerateMemoryBarrier(memory_barrier->GetBarrierKind());
1431}
1432
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001433void LocationsBuilderX86_64::VisitReturnVoid(HReturnVoid* ret) {
1434 ret->SetLocations(nullptr);
1435}
1436
1437void InstructionCodeGeneratorX86_64::VisitReturnVoid(HReturnVoid* ret) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001438 UNUSED(ret);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001439 codegen_->GenerateFrameExit();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001440}
1441
1442void LocationsBuilderX86_64::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001443 LocationSummary* locations =
1444 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001445 switch (ret->InputAt(0)->GetType()) {
1446 case Primitive::kPrimBoolean:
1447 case Primitive::kPrimByte:
1448 case Primitive::kPrimChar:
1449 case Primitive::kPrimShort:
1450 case Primitive::kPrimInt:
1451 case Primitive::kPrimNot:
1452 case Primitive::kPrimLong:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001453 locations->SetInAt(0, Location::RegisterLocation(RAX));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001454 break;
1455
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001456 case Primitive::kPrimFloat:
1457 case Primitive::kPrimDouble:
Mark Mendell40741f32015-04-20 22:10:34 -04001458 locations->SetInAt(0, Location::FpuRegisterLocation(XMM0));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001459 break;
1460
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001461 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001462 LOG(FATAL) << "Unexpected return type " << ret->InputAt(0)->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001463 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001464}
1465
1466void InstructionCodeGeneratorX86_64::VisitReturn(HReturn* ret) {
1467 if (kIsDebugBuild) {
1468 switch (ret->InputAt(0)->GetType()) {
1469 case Primitive::kPrimBoolean:
1470 case Primitive::kPrimByte:
1471 case Primitive::kPrimChar:
1472 case Primitive::kPrimShort:
1473 case Primitive::kPrimInt:
1474 case Primitive::kPrimNot:
1475 case Primitive::kPrimLong:
Roland Levillain271ab9c2014-11-27 15:23:57 +00001476 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegister<CpuRegister>().AsRegister(), RAX);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001477 break;
1478
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001479 case Primitive::kPrimFloat:
1480 case Primitive::kPrimDouble:
Roland Levillain271ab9c2014-11-27 15:23:57 +00001481 DCHECK_EQ(ret->GetLocations()->InAt(0).AsFpuRegister<XmmRegister>().AsFloatRegister(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001482 XMM0);
1483 break;
1484
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001485 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001486 LOG(FATAL) << "Unexpected return type " << ret->InputAt(0)->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001487 }
1488 }
1489 codegen_->GenerateFrameExit();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001490}
1491
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01001492Location InvokeDexCallingConventionVisitorX86_64::GetReturnLocation(Primitive::Type type) const {
1493 switch (type) {
1494 case Primitive::kPrimBoolean:
1495 case Primitive::kPrimByte:
1496 case Primitive::kPrimChar:
1497 case Primitive::kPrimShort:
1498 case Primitive::kPrimInt:
1499 case Primitive::kPrimNot:
1500 case Primitive::kPrimLong:
1501 return Location::RegisterLocation(RAX);
1502
1503 case Primitive::kPrimVoid:
1504 return Location::NoLocation();
1505
1506 case Primitive::kPrimDouble:
1507 case Primitive::kPrimFloat:
1508 return Location::FpuRegisterLocation(XMM0);
1509 }
Nicolas Geoffray0d1652e2015-06-03 12:12:19 +01001510
1511 UNREACHABLE();
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01001512}
1513
1514Location InvokeDexCallingConventionVisitorX86_64::GetMethodLocation() const {
1515 return Location::RegisterLocation(kMethodRegisterArgument);
1516}
1517
Roland Levillain2d27c8e2015-04-28 15:48:45 +01001518Location InvokeDexCallingConventionVisitorX86_64::GetNextLocation(Primitive::Type type) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001519 switch (type) {
1520 case Primitive::kPrimBoolean:
1521 case Primitive::kPrimByte:
1522 case Primitive::kPrimChar:
1523 case Primitive::kPrimShort:
1524 case Primitive::kPrimInt:
1525 case Primitive::kPrimNot: {
1526 uint32_t index = gp_index_++;
1527 stack_index_++;
1528 if (index < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001529 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001530 } else {
1531 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
1532 }
1533 }
1534
1535 case Primitive::kPrimLong: {
1536 uint32_t index = gp_index_;
1537 stack_index_ += 2;
1538 if (index < calling_convention.GetNumberOfRegisters()) {
1539 gp_index_ += 1;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001540 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001541 } else {
1542 gp_index_ += 2;
1543 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
1544 }
1545 }
1546
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001547 case Primitive::kPrimFloat: {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01001548 uint32_t index = float_index_++;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001549 stack_index_++;
1550 if (index < calling_convention.GetNumberOfFpuRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001551 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001552 } else {
1553 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
1554 }
1555 }
1556
1557 case Primitive::kPrimDouble: {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01001558 uint32_t index = float_index_++;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001559 stack_index_ += 2;
1560 if (index < calling_convention.GetNumberOfFpuRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001561 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001562 } else {
1563 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
1564 }
1565 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001566
1567 case Primitive::kPrimVoid:
1568 LOG(FATAL) << "Unexpected parameter type " << type;
1569 break;
1570 }
1571 return Location();
1572}
1573
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001574void LocationsBuilderX86_64::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Roland Levillain3e3d7332015-04-28 11:00:54 +01001575 // When we do not run baseline, explicit clinit checks triggered by static
1576 // invokes must have been pruned by art::PrepareForRegisterAllocation.
1577 DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01001578
Mark Mendellfb8d2792015-03-31 22:16:59 -04001579 IntrinsicLocationsBuilderX86_64 intrinsic(codegen_);
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001580 if (intrinsic.TryDispatch(invoke)) {
1581 return;
1582 }
1583
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001584 HandleInvoke(invoke);
1585}
1586
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001587static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorX86_64* codegen) {
1588 if (invoke->GetLocations()->Intrinsified()) {
1589 IntrinsicCodeGeneratorX86_64 intrinsic(codegen);
1590 intrinsic.Dispatch(invoke);
1591 return true;
1592 }
1593 return false;
1594}
1595
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001596void InstructionCodeGeneratorX86_64::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Roland Levillain3e3d7332015-04-28 11:00:54 +01001597 // When we do not run baseline, explicit clinit checks triggered by static
1598 // invokes must have been pruned by art::PrepareForRegisterAllocation.
1599 DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01001600
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001601 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1602 return;
1603 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001604
Nicolas Geoffray38207af2015-06-01 15:46:22 +01001605 LocationSummary* locations = invoke->GetLocations();
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001606 codegen_->GenerateStaticOrDirectCall(
Nicolas Geoffray38207af2015-06-01 15:46:22 +01001607 invoke, locations->HasTemps() ? locations->GetTemp(0) : Location::NoLocation());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +00001608 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001609}
1610
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001611void LocationsBuilderX86_64::HandleInvoke(HInvoke* invoke) {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01001612 InvokeDexCallingConventionVisitorX86_64 calling_convention_visitor;
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01001613 CodeGenerator::CreateCommonInvokeLocationSummary(invoke, &calling_convention_visitor);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001614}
1615
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001616void LocationsBuilderX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Mark Mendellfb8d2792015-03-31 22:16:59 -04001617 IntrinsicLocationsBuilderX86_64 intrinsic(codegen_);
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001618 if (intrinsic.TryDispatch(invoke)) {
1619 return;
1620 }
1621
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001622 HandleInvoke(invoke);
1623}
1624
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001625void InstructionCodeGeneratorX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001626 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1627 return;
1628 }
1629
Roland Levillain271ab9c2014-11-27 15:23:57 +00001630 CpuRegister temp = invoke->GetLocations()->GetTemp(0).AsRegister<CpuRegister>();
Mathieu Chartiere401d142015-04-22 13:56:20 -07001631 size_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
1632 invoke->GetVTableIndex(), kX86_64PointerSize).SizeValue();
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001633 LocationSummary* locations = invoke->GetLocations();
1634 Location receiver = locations->InAt(0);
1635 size_t class_offset = mirror::Object::ClassOffset().SizeValue();
1636 // temp = object->GetClass();
Nicolas Geoffray38207af2015-06-01 15:46:22 +01001637 DCHECK(receiver.IsRegister());
1638 __ movl(temp, Address(receiver.AsRegister<CpuRegister>(), class_offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00001639 codegen_->MaybeRecordImplicitNullCheck(invoke);
Roland Levillain4d027112015-07-01 15:41:14 +01001640 __ MaybeUnpoisonHeapReference(temp);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001641 // temp = temp->GetMethodAt(method_offset);
Mathieu Chartiere401d142015-04-22 13:56:20 -07001642 __ movq(temp, Address(temp, method_offset));
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001643 // call temp->GetEntryPoint();
Mathieu Chartiere401d142015-04-22 13:56:20 -07001644 __ call(Address(temp, ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001645 kX86_64WordSize).SizeValue()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001646
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001647 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray39468442014-09-02 15:17:15 +01001648 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001649}
1650
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001651void LocationsBuilderX86_64::VisitInvokeInterface(HInvokeInterface* invoke) {
1652 HandleInvoke(invoke);
1653 // Add the hidden argument.
1654 invoke->GetLocations()->AddTemp(Location::RegisterLocation(RAX));
1655}
1656
1657void InstructionCodeGeneratorX86_64::VisitInvokeInterface(HInvokeInterface* invoke) {
1658 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001659 CpuRegister temp = invoke->GetLocations()->GetTemp(0).AsRegister<CpuRegister>();
Mathieu Chartiere401d142015-04-22 13:56:20 -07001660 uint32_t method_offset = mirror::Class::EmbeddedImTableEntryOffset(
1661 invoke->GetImtIndex() % mirror::Class::kImtSize, kX86_64PointerSize).Uint32Value();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001662 LocationSummary* locations = invoke->GetLocations();
1663 Location receiver = locations->InAt(0);
1664 size_t class_offset = mirror::Object::ClassOffset().SizeValue();
1665
1666 // Set the hidden argument.
Mark Mendell92e83bf2015-05-07 11:25:03 -04001667 CpuRegister hidden_reg = invoke->GetLocations()->GetTemp(1).AsRegister<CpuRegister>();
1668 codegen_->Load64BitValue(hidden_reg, invoke->GetDexMethodIndex());
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001669
1670 // temp = object->GetClass();
1671 if (receiver.IsStackSlot()) {
1672 __ movl(temp, Address(CpuRegister(RSP), receiver.GetStackIndex()));
1673 __ movl(temp, Address(temp, class_offset));
1674 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001675 __ movl(temp, Address(receiver.AsRegister<CpuRegister>(), class_offset));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001676 }
Calin Juravle77520bc2015-01-12 18:45:46 +00001677 codegen_->MaybeRecordImplicitNullCheck(invoke);
Roland Levillain4d027112015-07-01 15:41:14 +01001678 __ MaybeUnpoisonHeapReference(temp);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001679 // temp = temp->GetImtEntryAt(method_offset);
Mathieu Chartiere401d142015-04-22 13:56:20 -07001680 __ movq(temp, Address(temp, method_offset));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001681 // call temp->GetEntryPoint();
Mathieu Chartiere401d142015-04-22 13:56:20 -07001682 __ call(Address(temp, ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001683 kX86_64WordSize).SizeValue()));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001684
1685 DCHECK(!codegen_->IsLeafMethod());
1686 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1687}
1688
Roland Levillain88cb1752014-10-20 16:36:47 +01001689void LocationsBuilderX86_64::VisitNeg(HNeg* neg) {
1690 LocationSummary* locations =
1691 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
1692 switch (neg->GetResultType()) {
1693 case Primitive::kPrimInt:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001694 case Primitive::kPrimLong:
Roland Levillain88cb1752014-10-20 16:36:47 +01001695 locations->SetInAt(0, Location::RequiresRegister());
1696 locations->SetOut(Location::SameAsFirstInput());
1697 break;
1698
Roland Levillain88cb1752014-10-20 16:36:47 +01001699 case Primitive::kPrimFloat:
1700 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001701 locations->SetInAt(0, Location::RequiresFpuRegister());
Roland Levillain5368c212014-11-27 15:03:41 +00001702 locations->SetOut(Location::SameAsFirstInput());
Roland Levillain5368c212014-11-27 15:03:41 +00001703 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain88cb1752014-10-20 16:36:47 +01001704 break;
1705
1706 default:
1707 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1708 }
1709}
1710
1711void InstructionCodeGeneratorX86_64::VisitNeg(HNeg* neg) {
1712 LocationSummary* locations = neg->GetLocations();
1713 Location out = locations->Out();
1714 Location in = locations->InAt(0);
1715 switch (neg->GetResultType()) {
1716 case Primitive::kPrimInt:
1717 DCHECK(in.IsRegister());
Roland Levillain3dbcb382014-10-28 17:30:07 +00001718 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001719 __ negl(out.AsRegister<CpuRegister>());
Roland Levillain88cb1752014-10-20 16:36:47 +01001720 break;
1721
1722 case Primitive::kPrimLong:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001723 DCHECK(in.IsRegister());
Roland Levillain3dbcb382014-10-28 17:30:07 +00001724 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001725 __ negq(out.AsRegister<CpuRegister>());
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001726 break;
1727
Roland Levillain5368c212014-11-27 15:03:41 +00001728 case Primitive::kPrimFloat: {
1729 DCHECK(in.Equals(out));
Mark Mendell40741f32015-04-20 22:10:34 -04001730 XmmRegister mask = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
Roland Levillain5368c212014-11-27 15:03:41 +00001731 // Implement float negation with an exclusive or with value
1732 // 0x80000000 (mask for bit 31, representing the sign of a
1733 // single-precision floating-point number).
Mark Mendell40741f32015-04-20 22:10:34 -04001734 __ movss(mask, codegen_->LiteralInt32Address(0x80000000));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001735 __ xorps(out.AsFpuRegister<XmmRegister>(), mask);
Roland Levillain3dbcb382014-10-28 17:30:07 +00001736 break;
Roland Levillain5368c212014-11-27 15:03:41 +00001737 }
Roland Levillain3dbcb382014-10-28 17:30:07 +00001738
Roland Levillain5368c212014-11-27 15:03:41 +00001739 case Primitive::kPrimDouble: {
1740 DCHECK(in.Equals(out));
Mark Mendell40741f32015-04-20 22:10:34 -04001741 XmmRegister mask = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
Roland Levillain5368c212014-11-27 15:03:41 +00001742 // Implement double negation with an exclusive or with value
Roland Levillain3dbcb382014-10-28 17:30:07 +00001743 // 0x8000000000000000 (mask for bit 63, representing the sign of
Roland Levillain5368c212014-11-27 15:03:41 +00001744 // a double-precision floating-point number).
Mark Mendell40741f32015-04-20 22:10:34 -04001745 __ movsd(mask, codegen_->LiteralInt64Address(INT64_C(0x8000000000000000)));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001746 __ xorpd(out.AsFpuRegister<XmmRegister>(), mask);
Roland Levillain88cb1752014-10-20 16:36:47 +01001747 break;
Roland Levillain5368c212014-11-27 15:03:41 +00001748 }
Roland Levillain88cb1752014-10-20 16:36:47 +01001749
1750 default:
1751 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1752 }
1753}
1754
Roland Levillaindff1f282014-11-05 14:15:05 +00001755void LocationsBuilderX86_64::VisitTypeConversion(HTypeConversion* conversion) {
1756 LocationSummary* locations =
1757 new (GetGraph()->GetArena()) LocationSummary(conversion, LocationSummary::kNoCall);
1758 Primitive::Type result_type = conversion->GetResultType();
1759 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00001760 DCHECK_NE(result_type, input_type);
David Brazdil46e2a392015-03-16 17:31:52 +00001761
David Brazdilb2bd1c52015-03-25 11:17:37 +00001762 // The Java language does not allow treating boolean as an integral type but
1763 // our bit representation makes it safe.
David Brazdil46e2a392015-03-16 17:31:52 +00001764
Roland Levillaindff1f282014-11-05 14:15:05 +00001765 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00001766 case Primitive::kPrimByte:
1767 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001768 case Primitive::kPrimBoolean:
1769 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001770 case Primitive::kPrimShort:
1771 case Primitive::kPrimInt:
1772 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001773 // Processing a Dex `int-to-byte' instruction.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001774 locations->SetInAt(0, Location::Any());
1775 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1776 break;
1777
1778 default:
1779 LOG(FATAL) << "Unexpected type conversion from " << input_type
1780 << " to " << result_type;
1781 }
1782 break;
1783
Roland Levillain01a8d712014-11-14 16:27:39 +00001784 case Primitive::kPrimShort:
1785 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001786 case Primitive::kPrimBoolean:
1787 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00001788 case Primitive::kPrimByte:
1789 case Primitive::kPrimInt:
1790 case Primitive::kPrimChar:
1791 // Processing a Dex `int-to-short' instruction.
1792 locations->SetInAt(0, Location::Any());
1793 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1794 break;
1795
1796 default:
1797 LOG(FATAL) << "Unexpected type conversion from " << input_type
1798 << " to " << result_type;
1799 }
1800 break;
1801
Roland Levillain946e1432014-11-11 17:35:19 +00001802 case Primitive::kPrimInt:
1803 switch (input_type) {
1804 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00001805 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00001806 locations->SetInAt(0, Location::Any());
1807 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1808 break;
1809
1810 case Primitive::kPrimFloat:
Roland Levillain3f8f9362014-12-02 17:45:01 +00001811 // Processing a Dex `float-to-int' instruction.
1812 locations->SetInAt(0, Location::RequiresFpuRegister());
1813 locations->SetOut(Location::RequiresRegister());
1814 locations->AddTemp(Location::RequiresFpuRegister());
1815 break;
1816
Roland Levillain946e1432014-11-11 17:35:19 +00001817 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001818 // Processing a Dex `double-to-int' instruction.
1819 locations->SetInAt(0, Location::RequiresFpuRegister());
1820 locations->SetOut(Location::RequiresRegister());
1821 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain946e1432014-11-11 17:35:19 +00001822 break;
1823
1824 default:
1825 LOG(FATAL) << "Unexpected type conversion from " << input_type
1826 << " to " << result_type;
1827 }
1828 break;
1829
Roland Levillaindff1f282014-11-05 14:15:05 +00001830 case Primitive::kPrimLong:
1831 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001832 case Primitive::kPrimBoolean:
1833 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00001834 case Primitive::kPrimByte:
1835 case Primitive::kPrimShort:
1836 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00001837 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001838 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00001839 // TODO: We would benefit from a (to-be-implemented)
1840 // Location::RegisterOrStackSlot requirement for this input.
1841 locations->SetInAt(0, Location::RequiresRegister());
1842 locations->SetOut(Location::RequiresRegister());
1843 break;
1844
1845 case Primitive::kPrimFloat:
Roland Levillain624279f2014-12-04 11:54:28 +00001846 // Processing a Dex `float-to-long' instruction.
1847 locations->SetInAt(0, Location::RequiresFpuRegister());
1848 locations->SetOut(Location::RequiresRegister());
1849 locations->AddTemp(Location::RequiresFpuRegister());
1850 break;
1851
Roland Levillaindff1f282014-11-05 14:15:05 +00001852 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001853 // Processing a Dex `double-to-long' instruction.
1854 locations->SetInAt(0, Location::RequiresFpuRegister());
1855 locations->SetOut(Location::RequiresRegister());
1856 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillaindff1f282014-11-05 14:15:05 +00001857 break;
1858
1859 default:
1860 LOG(FATAL) << "Unexpected type conversion from " << input_type
1861 << " to " << result_type;
1862 }
1863 break;
1864
Roland Levillain981e4542014-11-14 11:47:14 +00001865 case Primitive::kPrimChar:
1866 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001867 case Primitive::kPrimBoolean:
1868 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00001869 case Primitive::kPrimByte:
1870 case Primitive::kPrimShort:
1871 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00001872 // Processing a Dex `int-to-char' instruction.
1873 locations->SetInAt(0, Location::Any());
1874 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1875 break;
1876
1877 default:
1878 LOG(FATAL) << "Unexpected type conversion from " << input_type
1879 << " to " << result_type;
1880 }
1881 break;
1882
Roland Levillaindff1f282014-11-05 14:15:05 +00001883 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00001884 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001885 case Primitive::kPrimBoolean:
1886 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001887 case Primitive::kPrimByte:
1888 case Primitive::kPrimShort:
1889 case Primitive::kPrimInt:
1890 case Primitive::kPrimChar:
1891 // Processing a Dex `int-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04001892 locations->SetInAt(0, Location::Any());
Roland Levillaincff13742014-11-17 14:32:17 +00001893 locations->SetOut(Location::RequiresFpuRegister());
1894 break;
1895
1896 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00001897 // Processing a Dex `long-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04001898 locations->SetInAt(0, Location::Any());
Roland Levillain6d0e4832014-11-27 18:31:21 +00001899 locations->SetOut(Location::RequiresFpuRegister());
1900 break;
1901
Roland Levillaincff13742014-11-17 14:32:17 +00001902 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001903 // Processing a Dex `double-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04001904 locations->SetInAt(0, Location::Any());
Roland Levillain8964e2b2014-12-04 12:10:50 +00001905 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00001906 break;
1907
1908 default:
1909 LOG(FATAL) << "Unexpected type conversion from " << input_type
1910 << " to " << result_type;
1911 };
1912 break;
1913
Roland Levillaindff1f282014-11-05 14:15:05 +00001914 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00001915 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001916 case Primitive::kPrimBoolean:
1917 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001918 case Primitive::kPrimByte:
1919 case Primitive::kPrimShort:
1920 case Primitive::kPrimInt:
1921 case Primitive::kPrimChar:
1922 // Processing a Dex `int-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04001923 locations->SetInAt(0, Location::Any());
Roland Levillaincff13742014-11-17 14:32:17 +00001924 locations->SetOut(Location::RequiresFpuRegister());
1925 break;
1926
1927 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00001928 // Processing a Dex `long-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04001929 locations->SetInAt(0, Location::Any());
Roland Levillain647b9ed2014-11-27 12:06:00 +00001930 locations->SetOut(Location::RequiresFpuRegister());
1931 break;
1932
Roland Levillaincff13742014-11-17 14:32:17 +00001933 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001934 // Processing a Dex `float-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04001935 locations->SetInAt(0, Location::Any());
Roland Levillain8964e2b2014-12-04 12:10:50 +00001936 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00001937 break;
1938
1939 default:
1940 LOG(FATAL) << "Unexpected type conversion from " << input_type
1941 << " to " << result_type;
1942 }
Roland Levillaindff1f282014-11-05 14:15:05 +00001943 break;
1944
1945 default:
1946 LOG(FATAL) << "Unexpected type conversion from " << input_type
1947 << " to " << result_type;
1948 }
1949}
1950
1951void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conversion) {
1952 LocationSummary* locations = conversion->GetLocations();
1953 Location out = locations->Out();
1954 Location in = locations->InAt(0);
1955 Primitive::Type result_type = conversion->GetResultType();
1956 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00001957 DCHECK_NE(result_type, input_type);
Roland Levillaindff1f282014-11-05 14:15:05 +00001958 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00001959 case Primitive::kPrimByte:
1960 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001961 case Primitive::kPrimBoolean:
1962 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001963 case Primitive::kPrimShort:
1964 case Primitive::kPrimInt:
1965 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001966 // Processing a Dex `int-to-byte' instruction.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001967 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001968 __ movsxb(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain51d3fc42014-11-13 14:11:42 +00001969 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001970 __ movsxb(out.AsRegister<CpuRegister>(),
Roland Levillain51d3fc42014-11-13 14:11:42 +00001971 Address(CpuRegister(RSP), in.GetStackIndex()));
1972 } else {
1973 DCHECK(in.GetConstant()->IsIntConstant());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001974 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain51d3fc42014-11-13 14:11:42 +00001975 Immediate(static_cast<int8_t>(in.GetConstant()->AsIntConstant()->GetValue())));
1976 }
1977 break;
1978
1979 default:
1980 LOG(FATAL) << "Unexpected type conversion from " << input_type
1981 << " to " << result_type;
1982 }
1983 break;
1984
Roland Levillain01a8d712014-11-14 16:27:39 +00001985 case Primitive::kPrimShort:
1986 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001987 case Primitive::kPrimBoolean:
1988 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00001989 case Primitive::kPrimByte:
1990 case Primitive::kPrimInt:
1991 case Primitive::kPrimChar:
1992 // Processing a Dex `int-to-short' instruction.
1993 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001994 __ movsxw(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain01a8d712014-11-14 16:27:39 +00001995 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001996 __ movsxw(out.AsRegister<CpuRegister>(),
Roland Levillain01a8d712014-11-14 16:27:39 +00001997 Address(CpuRegister(RSP), in.GetStackIndex()));
1998 } else {
1999 DCHECK(in.GetConstant()->IsIntConstant());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002000 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain01a8d712014-11-14 16:27:39 +00002001 Immediate(static_cast<int16_t>(in.GetConstant()->AsIntConstant()->GetValue())));
2002 }
2003 break;
2004
2005 default:
2006 LOG(FATAL) << "Unexpected type conversion from " << input_type
2007 << " to " << result_type;
2008 }
2009 break;
2010
Roland Levillain946e1432014-11-11 17:35:19 +00002011 case Primitive::kPrimInt:
2012 switch (input_type) {
2013 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00002014 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00002015 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002016 __ movl(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain946e1432014-11-11 17:35:19 +00002017 } else if (in.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002018 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain946e1432014-11-11 17:35:19 +00002019 Address(CpuRegister(RSP), in.GetStackIndex()));
2020 } else {
2021 DCHECK(in.IsConstant());
2022 DCHECK(in.GetConstant()->IsLongConstant());
2023 int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002024 __ movl(out.AsRegister<CpuRegister>(), Immediate(static_cast<int32_t>(value)));
Roland Levillain946e1432014-11-11 17:35:19 +00002025 }
2026 break;
2027
Roland Levillain3f8f9362014-12-02 17:45:01 +00002028 case Primitive::kPrimFloat: {
2029 // Processing a Dex `float-to-int' instruction.
2030 XmmRegister input = in.AsFpuRegister<XmmRegister>();
2031 CpuRegister output = out.AsRegister<CpuRegister>();
2032 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
2033 Label done, nan;
2034
2035 __ movl(output, Immediate(kPrimIntMax));
2036 // temp = int-to-float(output)
Roland Levillain624279f2014-12-04 11:54:28 +00002037 __ cvtsi2ss(temp, output, false);
Roland Levillain3f8f9362014-12-02 17:45:01 +00002038 // if input >= temp goto done
2039 __ comiss(input, temp);
2040 __ j(kAboveEqual, &done);
2041 // if input == NaN goto nan
2042 __ j(kUnordered, &nan);
2043 // output = float-to-int-truncate(input)
Roland Levillain624279f2014-12-04 11:54:28 +00002044 __ cvttss2si(output, input, false);
Roland Levillain3f8f9362014-12-02 17:45:01 +00002045 __ jmp(&done);
2046 __ Bind(&nan);
2047 // output = 0
2048 __ xorl(output, output);
2049 __ Bind(&done);
2050 break;
2051 }
2052
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002053 case Primitive::kPrimDouble: {
2054 // Processing a Dex `double-to-int' instruction.
2055 XmmRegister input = in.AsFpuRegister<XmmRegister>();
2056 CpuRegister output = out.AsRegister<CpuRegister>();
2057 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
2058 Label done, nan;
2059
2060 __ movl(output, Immediate(kPrimIntMax));
2061 // temp = int-to-double(output)
2062 __ cvtsi2sd(temp, output);
2063 // if input >= temp goto done
2064 __ comisd(input, temp);
2065 __ j(kAboveEqual, &done);
2066 // if input == NaN goto nan
2067 __ j(kUnordered, &nan);
2068 // output = double-to-int-truncate(input)
2069 __ cvttsd2si(output, input);
2070 __ jmp(&done);
2071 __ Bind(&nan);
2072 // output = 0
2073 __ xorl(output, output);
2074 __ Bind(&done);
Roland Levillain946e1432014-11-11 17:35:19 +00002075 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002076 }
Roland Levillain946e1432014-11-11 17:35:19 +00002077
2078 default:
2079 LOG(FATAL) << "Unexpected type conversion from " << input_type
2080 << " to " << result_type;
2081 }
2082 break;
2083
Roland Levillaindff1f282014-11-05 14:15:05 +00002084 case Primitive::kPrimLong:
2085 switch (input_type) {
2086 DCHECK(out.IsRegister());
David Brazdil46e2a392015-03-16 17:31:52 +00002087 case Primitive::kPrimBoolean:
2088 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00002089 case Primitive::kPrimByte:
2090 case Primitive::kPrimShort:
2091 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00002092 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002093 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00002094 DCHECK(in.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002095 __ movsxd(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillaindff1f282014-11-05 14:15:05 +00002096 break;
2097
Roland Levillain624279f2014-12-04 11:54:28 +00002098 case Primitive::kPrimFloat: {
2099 // Processing a Dex `float-to-long' instruction.
2100 XmmRegister input = in.AsFpuRegister<XmmRegister>();
2101 CpuRegister output = out.AsRegister<CpuRegister>();
2102 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
2103 Label done, nan;
2104
Mark Mendell92e83bf2015-05-07 11:25:03 -04002105 codegen_->Load64BitValue(output, kPrimLongMax);
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002106 // temp = long-to-float(output)
Roland Levillain624279f2014-12-04 11:54:28 +00002107 __ cvtsi2ss(temp, output, true);
2108 // if input >= temp goto done
2109 __ comiss(input, temp);
2110 __ j(kAboveEqual, &done);
2111 // if input == NaN goto nan
2112 __ j(kUnordered, &nan);
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002113 // output = float-to-long-truncate(input)
Roland Levillain624279f2014-12-04 11:54:28 +00002114 __ cvttss2si(output, input, true);
2115 __ jmp(&done);
2116 __ Bind(&nan);
2117 // output = 0
Mark Mendell92e83bf2015-05-07 11:25:03 -04002118 __ xorl(output, output);
Roland Levillain624279f2014-12-04 11:54:28 +00002119 __ Bind(&done);
2120 break;
2121 }
2122
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002123 case Primitive::kPrimDouble: {
2124 // Processing a Dex `double-to-long' instruction.
2125 XmmRegister input = in.AsFpuRegister<XmmRegister>();
2126 CpuRegister output = out.AsRegister<CpuRegister>();
2127 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
2128 Label done, nan;
2129
Mark Mendell92e83bf2015-05-07 11:25:03 -04002130 codegen_->Load64BitValue(output, kPrimLongMax);
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002131 // temp = long-to-double(output)
2132 __ cvtsi2sd(temp, output, true);
2133 // if input >= temp goto done
2134 __ comisd(input, temp);
2135 __ j(kAboveEqual, &done);
2136 // if input == NaN goto nan
2137 __ j(kUnordered, &nan);
2138 // output = double-to-long-truncate(input)
2139 __ cvttsd2si(output, input, true);
2140 __ jmp(&done);
2141 __ Bind(&nan);
2142 // output = 0
Mark Mendell92e83bf2015-05-07 11:25:03 -04002143 __ xorl(output, output);
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002144 __ Bind(&done);
Roland Levillaindff1f282014-11-05 14:15:05 +00002145 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002146 }
Roland Levillaindff1f282014-11-05 14:15:05 +00002147
2148 default:
2149 LOG(FATAL) << "Unexpected type conversion from " << input_type
2150 << " to " << result_type;
2151 }
2152 break;
2153
Roland Levillain981e4542014-11-14 11:47:14 +00002154 case Primitive::kPrimChar:
2155 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002156 case Primitive::kPrimBoolean:
2157 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00002158 case Primitive::kPrimByte:
2159 case Primitive::kPrimShort:
2160 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00002161 // Processing a Dex `int-to-char' instruction.
2162 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002163 __ movzxw(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain981e4542014-11-14 11:47:14 +00002164 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002165 __ movzxw(out.AsRegister<CpuRegister>(),
Roland Levillain981e4542014-11-14 11:47:14 +00002166 Address(CpuRegister(RSP), in.GetStackIndex()));
2167 } else {
2168 DCHECK(in.GetConstant()->IsIntConstant());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002169 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain981e4542014-11-14 11:47:14 +00002170 Immediate(static_cast<uint16_t>(in.GetConstant()->AsIntConstant()->GetValue())));
2171 }
2172 break;
2173
2174 default:
2175 LOG(FATAL) << "Unexpected type conversion from " << input_type
2176 << " to " << result_type;
2177 }
2178 break;
2179
Roland Levillaindff1f282014-11-05 14:15:05 +00002180 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00002181 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002182 case Primitive::kPrimBoolean:
2183 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002184 case Primitive::kPrimByte:
2185 case Primitive::kPrimShort:
2186 case Primitive::kPrimInt:
2187 case Primitive::kPrimChar:
Roland Levillain6d0e4832014-11-27 18:31:21 +00002188 // Processing a Dex `int-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002189 if (in.IsRegister()) {
2190 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), false);
2191 } else if (in.IsConstant()) {
2192 int32_t v = in.GetConstant()->AsIntConstant()->GetValue();
2193 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
2194 if (v == 0) {
2195 __ xorps(dest, dest);
2196 } else {
2197 __ movss(dest, codegen_->LiteralFloatAddress(static_cast<float>(v)));
2198 }
2199 } else {
2200 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(),
2201 Address(CpuRegister(RSP), in.GetStackIndex()), false);
2202 }
Roland Levillaincff13742014-11-17 14:32:17 +00002203 break;
2204
2205 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00002206 // Processing a Dex `long-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002207 if (in.IsRegister()) {
2208 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), true);
2209 } else if (in.IsConstant()) {
2210 int64_t v = in.GetConstant()->AsLongConstant()->GetValue();
2211 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
2212 if (v == 0) {
2213 __ xorps(dest, dest);
2214 } else {
2215 __ movss(dest, codegen_->LiteralFloatAddress(static_cast<float>(v)));
2216 }
2217 } else {
2218 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(),
2219 Address(CpuRegister(RSP), in.GetStackIndex()), true);
2220 }
Roland Levillain6d0e4832014-11-27 18:31:21 +00002221 break;
2222
Roland Levillaincff13742014-11-17 14:32:17 +00002223 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002224 // Processing a Dex `double-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002225 if (in.IsFpuRegister()) {
2226 __ cvtsd2ss(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
2227 } else if (in.IsConstant()) {
2228 double v = in.GetConstant()->AsDoubleConstant()->GetValue();
2229 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
2230 if (bit_cast<int64_t, double>(v) == 0) {
2231 __ xorps(dest, dest);
2232 } else {
2233 __ movss(dest, codegen_->LiteralFloatAddress(static_cast<float>(v)));
2234 }
2235 } else {
2236 __ cvtsd2ss(out.AsFpuRegister<XmmRegister>(),
2237 Address(CpuRegister(RSP), in.GetStackIndex()));
2238 }
Roland Levillaincff13742014-11-17 14:32:17 +00002239 break;
2240
2241 default:
2242 LOG(FATAL) << "Unexpected type conversion from " << input_type
2243 << " to " << result_type;
2244 };
2245 break;
2246
Roland Levillaindff1f282014-11-05 14:15:05 +00002247 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00002248 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002249 case Primitive::kPrimBoolean:
2250 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002251 case Primitive::kPrimByte:
2252 case Primitive::kPrimShort:
2253 case Primitive::kPrimInt:
2254 case Primitive::kPrimChar:
Roland Levillain6d0e4832014-11-27 18:31:21 +00002255 // Processing a Dex `int-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002256 if (in.IsRegister()) {
2257 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), false);
2258 } else if (in.IsConstant()) {
2259 int32_t v = in.GetConstant()->AsIntConstant()->GetValue();
2260 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
2261 if (v == 0) {
2262 __ xorpd(dest, dest);
2263 } else {
2264 __ movsd(dest, codegen_->LiteralDoubleAddress(static_cast<double>(v)));
2265 }
2266 } else {
2267 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(),
2268 Address(CpuRegister(RSP), in.GetStackIndex()), false);
2269 }
Roland Levillaincff13742014-11-17 14:32:17 +00002270 break;
2271
2272 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00002273 // Processing a Dex `long-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002274 if (in.IsRegister()) {
2275 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), true);
2276 } else if (in.IsConstant()) {
2277 int64_t v = in.GetConstant()->AsLongConstant()->GetValue();
2278 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
2279 if (v == 0) {
2280 __ xorpd(dest, dest);
2281 } else {
2282 __ movsd(dest, codegen_->LiteralDoubleAddress(static_cast<double>(v)));
2283 }
2284 } else {
2285 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(),
2286 Address(CpuRegister(RSP), in.GetStackIndex()), true);
2287 }
Roland Levillain647b9ed2014-11-27 12:06:00 +00002288 break;
2289
Roland Levillaincff13742014-11-17 14:32:17 +00002290 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002291 // Processing a Dex `float-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002292 if (in.IsFpuRegister()) {
2293 __ cvtss2sd(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
2294 } else if (in.IsConstant()) {
2295 float v = in.GetConstant()->AsFloatConstant()->GetValue();
2296 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
2297 if (bit_cast<int32_t, float>(v) == 0) {
2298 __ xorpd(dest, dest);
2299 } else {
2300 __ movsd(dest, codegen_->LiteralDoubleAddress(static_cast<double>(v)));
2301 }
2302 } else {
2303 __ cvtss2sd(out.AsFpuRegister<XmmRegister>(),
2304 Address(CpuRegister(RSP), in.GetStackIndex()));
2305 }
Roland Levillaincff13742014-11-17 14:32:17 +00002306 break;
2307
2308 default:
2309 LOG(FATAL) << "Unexpected type conversion from " << input_type
2310 << " to " << result_type;
2311 };
Roland Levillaindff1f282014-11-05 14:15:05 +00002312 break;
2313
2314 default:
2315 LOG(FATAL) << "Unexpected type conversion from " << input_type
2316 << " to " << result_type;
2317 }
2318}
2319
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002320void LocationsBuilderX86_64::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002321 LocationSummary* locations =
2322 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002323 switch (add->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002324 case Primitive::kPrimInt: {
2325 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002326 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
2327 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002328 break;
2329 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002330
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002331 case Primitive::kPrimLong: {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002332 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell09b84632015-02-13 17:48:38 -05002333 // We can use a leaq or addq if the constant can fit in an immediate.
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002334 locations->SetInAt(1, Location::RegisterOrInt32LongConstant(add->InputAt(1)));
Mark Mendell09b84632015-02-13 17:48:38 -05002335 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002336 break;
2337 }
2338
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002339 case Primitive::kPrimDouble:
2340 case Primitive::kPrimFloat: {
2341 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendellf55c3e02015-03-26 21:07:46 -04002342 locations->SetInAt(1, Location::Any());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002343 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002344 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002345 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002346
2347 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002348 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002349 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002350}
2351
2352void InstructionCodeGeneratorX86_64::VisitAdd(HAdd* add) {
2353 LocationSummary* locations = add->GetLocations();
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002354 Location first = locations->InAt(0);
2355 Location second = locations->InAt(1);
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002356 Location out = locations->Out();
Calin Juravle11351682014-10-23 15:38:15 +01002357
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002358 switch (add->GetResultType()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002359 case Primitive::kPrimInt: {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002360 if (second.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002361 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
2362 __ addl(out.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Mark Mendell33bf2452015-05-27 10:08:24 -04002363 } else if (out.AsRegister<Register>() == second.AsRegister<Register>()) {
2364 __ addl(out.AsRegister<CpuRegister>(), first.AsRegister<CpuRegister>());
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002365 } else {
2366 __ leal(out.AsRegister<CpuRegister>(), Address(
2367 first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>(), TIMES_1, 0));
2368 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002369 } else if (second.IsConstant()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002370 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
2371 __ addl(out.AsRegister<CpuRegister>(),
2372 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
2373 } else {
2374 __ leal(out.AsRegister<CpuRegister>(), Address(
2375 first.AsRegister<CpuRegister>(), second.GetConstant()->AsIntConstant()->GetValue()));
2376 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002377 } else {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002378 DCHECK(first.Equals(locations->Out()));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002379 __ addl(first.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), second.GetStackIndex()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002380 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002381 break;
2382 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002383
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002384 case Primitive::kPrimLong: {
Mark Mendell09b84632015-02-13 17:48:38 -05002385 if (second.IsRegister()) {
2386 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
2387 __ addq(out.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Mark Mendell33bf2452015-05-27 10:08:24 -04002388 } else if (out.AsRegister<Register>() == second.AsRegister<Register>()) {
2389 __ addq(out.AsRegister<CpuRegister>(), first.AsRegister<CpuRegister>());
Mark Mendell09b84632015-02-13 17:48:38 -05002390 } else {
2391 __ leaq(out.AsRegister<CpuRegister>(), Address(
2392 first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>(), TIMES_1, 0));
2393 }
2394 } else {
2395 DCHECK(second.IsConstant());
2396 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
2397 int32_t int32_value = Low32Bits(value);
2398 DCHECK_EQ(int32_value, value);
2399 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
2400 __ addq(out.AsRegister<CpuRegister>(), Immediate(int32_value));
2401 } else {
2402 __ leaq(out.AsRegister<CpuRegister>(), Address(
2403 first.AsRegister<CpuRegister>(), int32_value));
2404 }
2405 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002406 break;
2407 }
2408
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002409 case Primitive::kPrimFloat: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04002410 if (second.IsFpuRegister()) {
2411 __ addss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2412 } else if (second.IsConstant()) {
2413 __ addss(first.AsFpuRegister<XmmRegister>(),
2414 codegen_->LiteralFloatAddress(second.GetConstant()->AsFloatConstant()->GetValue()));
2415 } else {
2416 DCHECK(second.IsStackSlot());
2417 __ addss(first.AsFpuRegister<XmmRegister>(),
2418 Address(CpuRegister(RSP), second.GetStackIndex()));
2419 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002420 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002421 }
2422
2423 case Primitive::kPrimDouble: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04002424 if (second.IsFpuRegister()) {
2425 __ addsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2426 } else if (second.IsConstant()) {
2427 __ addsd(first.AsFpuRegister<XmmRegister>(),
2428 codegen_->LiteralDoubleAddress(second.GetConstant()->AsDoubleConstant()->GetValue()));
2429 } else {
2430 DCHECK(second.IsDoubleStackSlot());
2431 __ addsd(first.AsFpuRegister<XmmRegister>(),
2432 Address(CpuRegister(RSP), second.GetStackIndex()));
2433 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002434 break;
2435 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002436
2437 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002438 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002439 }
2440}
2441
2442void LocationsBuilderX86_64::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002443 LocationSummary* locations =
2444 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002445 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002446 case Primitive::kPrimInt: {
2447 locations->SetInAt(0, Location::RequiresRegister());
2448 locations->SetInAt(1, Location::Any());
2449 locations->SetOut(Location::SameAsFirstInput());
2450 break;
2451 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002452 case Primitive::kPrimLong: {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002453 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002454 locations->SetInAt(1, Location::RegisterOrInt32LongConstant(sub->InputAt(1)));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002455 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002456 break;
2457 }
Calin Juravle11351682014-10-23 15:38:15 +01002458 case Primitive::kPrimFloat:
2459 case Primitive::kPrimDouble: {
2460 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendellf55c3e02015-03-26 21:07:46 -04002461 locations->SetInAt(1, Location::Any());
Calin Juravle11351682014-10-23 15:38:15 +01002462 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002463 break;
Calin Juravle11351682014-10-23 15:38:15 +01002464 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002465 default:
Calin Juravle11351682014-10-23 15:38:15 +01002466 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002467 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002468}
2469
2470void InstructionCodeGeneratorX86_64::VisitSub(HSub* sub) {
2471 LocationSummary* locations = sub->GetLocations();
Calin Juravle11351682014-10-23 15:38:15 +01002472 Location first = locations->InAt(0);
2473 Location second = locations->InAt(1);
2474 DCHECK(first.Equals(locations->Out()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002475 switch (sub->GetResultType()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002476 case Primitive::kPrimInt: {
Calin Juravle11351682014-10-23 15:38:15 +01002477 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002478 __ subl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Calin Juravle11351682014-10-23 15:38:15 +01002479 } else if (second.IsConstant()) {
2480 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002481 __ subl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002482 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002483 __ subl(first.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), second.GetStackIndex()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002484 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002485 break;
2486 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002487 case Primitive::kPrimLong: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002488 if (second.IsConstant()) {
2489 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
2490 DCHECK(IsInt<32>(value));
2491 __ subq(first.AsRegister<CpuRegister>(), Immediate(static_cast<int32_t>(value)));
2492 } else {
2493 __ subq(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
2494 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002495 break;
2496 }
2497
Calin Juravle11351682014-10-23 15:38:15 +01002498 case Primitive::kPrimFloat: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04002499 if (second.IsFpuRegister()) {
2500 __ subss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2501 } else if (second.IsConstant()) {
2502 __ subss(first.AsFpuRegister<XmmRegister>(),
2503 codegen_->LiteralFloatAddress(second.GetConstant()->AsFloatConstant()->GetValue()));
2504 } else {
2505 DCHECK(second.IsStackSlot());
2506 __ subss(first.AsFpuRegister<XmmRegister>(),
2507 Address(CpuRegister(RSP), second.GetStackIndex()));
2508 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002509 break;
Calin Juravle11351682014-10-23 15:38:15 +01002510 }
2511
2512 case Primitive::kPrimDouble: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04002513 if (second.IsFpuRegister()) {
2514 __ subsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2515 } else if (second.IsConstant()) {
2516 __ subsd(first.AsFpuRegister<XmmRegister>(),
2517 codegen_->LiteralDoubleAddress(second.GetConstant()->AsDoubleConstant()->GetValue()));
2518 } else {
2519 DCHECK(second.IsDoubleStackSlot());
2520 __ subsd(first.AsFpuRegister<XmmRegister>(),
2521 Address(CpuRegister(RSP), second.GetStackIndex()));
2522 }
Calin Juravle11351682014-10-23 15:38:15 +01002523 break;
2524 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002525
2526 default:
Calin Juravle11351682014-10-23 15:38:15 +01002527 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002528 }
2529}
2530
Calin Juravle34bacdf2014-10-07 20:23:36 +01002531void LocationsBuilderX86_64::VisitMul(HMul* mul) {
2532 LocationSummary* locations =
2533 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
2534 switch (mul->GetResultType()) {
2535 case Primitive::kPrimInt: {
2536 locations->SetInAt(0, Location::RequiresRegister());
2537 locations->SetInAt(1, Location::Any());
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002538 if (mul->InputAt(1)->IsIntConstant()) {
2539 // Can use 3 operand multiply.
2540 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2541 } else {
2542 locations->SetOut(Location::SameAsFirstInput());
2543 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002544 break;
2545 }
2546 case Primitive::kPrimLong: {
2547 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002548 locations->SetInAt(1, Location::Any());
2549 if (mul->InputAt(1)->IsLongConstant() &&
2550 IsInt<32>(mul->InputAt(1)->AsLongConstant()->GetValue())) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002551 // Can use 3 operand multiply.
2552 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2553 } else {
2554 locations->SetOut(Location::SameAsFirstInput());
2555 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002556 break;
2557 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01002558 case Primitive::kPrimFloat:
2559 case Primitive::kPrimDouble: {
2560 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendellf55c3e02015-03-26 21:07:46 -04002561 locations->SetInAt(1, Location::Any());
Calin Juravleb5bfa962014-10-21 18:02:24 +01002562 locations->SetOut(Location::SameAsFirstInput());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002563 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002564 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002565
2566 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002567 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002568 }
2569}
2570
2571void InstructionCodeGeneratorX86_64::VisitMul(HMul* mul) {
2572 LocationSummary* locations = mul->GetLocations();
2573 Location first = locations->InAt(0);
2574 Location second = locations->InAt(1);
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002575 Location out = locations->Out();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002576 switch (mul->GetResultType()) {
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002577 case Primitive::kPrimInt:
2578 // The constant may have ended up in a register, so test explicitly to avoid
2579 // problems where the output may not be the same as the first operand.
2580 if (mul->InputAt(1)->IsIntConstant()) {
2581 Immediate imm(mul->InputAt(1)->AsIntConstant()->GetValue());
2582 __ imull(out.AsRegister<CpuRegister>(), first.AsRegister<CpuRegister>(), imm);
2583 } else if (second.IsRegister()) {
2584 DCHECK(first.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002585 __ imull(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002586 } else {
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002587 DCHECK(first.Equals(out));
Calin Juravle34bacdf2014-10-07 20:23:36 +01002588 DCHECK(second.IsStackSlot());
Roland Levillain199f3362014-11-27 17:15:16 +00002589 __ imull(first.AsRegister<CpuRegister>(),
2590 Address(CpuRegister(RSP), second.GetStackIndex()));
Calin Juravle34bacdf2014-10-07 20:23:36 +01002591 }
2592 break;
Calin Juravle34bacdf2014-10-07 20:23:36 +01002593 case Primitive::kPrimLong: {
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002594 // The constant may have ended up in a register, so test explicitly to avoid
2595 // problems where the output may not be the same as the first operand.
2596 if (mul->InputAt(1)->IsLongConstant()) {
2597 int64_t value = mul->InputAt(1)->AsLongConstant()->GetValue();
2598 if (IsInt<32>(value)) {
2599 __ imulq(out.AsRegister<CpuRegister>(), first.AsRegister<CpuRegister>(),
2600 Immediate(static_cast<int32_t>(value)));
2601 } else {
2602 // Have to use the constant area.
2603 DCHECK(first.Equals(out));
2604 __ imulq(first.AsRegister<CpuRegister>(), codegen_->LiteralInt64Address(value));
2605 }
2606 } else if (second.IsRegister()) {
2607 DCHECK(first.Equals(out));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002608 __ imulq(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002609 } else {
2610 DCHECK(second.IsDoubleStackSlot());
2611 DCHECK(first.Equals(out));
2612 __ imulq(first.AsRegister<CpuRegister>(),
2613 Address(CpuRegister(RSP), second.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002614 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002615 break;
2616 }
2617
Calin Juravleb5bfa962014-10-21 18:02:24 +01002618 case Primitive::kPrimFloat: {
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002619 DCHECK(first.Equals(out));
Mark Mendellf55c3e02015-03-26 21:07:46 -04002620 if (second.IsFpuRegister()) {
2621 __ mulss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2622 } else if (second.IsConstant()) {
2623 __ mulss(first.AsFpuRegister<XmmRegister>(),
2624 codegen_->LiteralFloatAddress(second.GetConstant()->AsFloatConstant()->GetValue()));
2625 } else {
2626 DCHECK(second.IsStackSlot());
2627 __ mulss(first.AsFpuRegister<XmmRegister>(),
2628 Address(CpuRegister(RSP), second.GetStackIndex()));
2629 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002630 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002631 }
2632
2633 case Primitive::kPrimDouble: {
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002634 DCHECK(first.Equals(out));
Mark Mendellf55c3e02015-03-26 21:07:46 -04002635 if (second.IsFpuRegister()) {
2636 __ mulsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2637 } else if (second.IsConstant()) {
2638 __ mulsd(first.AsFpuRegister<XmmRegister>(),
2639 codegen_->LiteralDoubleAddress(second.GetConstant()->AsDoubleConstant()->GetValue()));
2640 } else {
2641 DCHECK(second.IsDoubleStackSlot());
2642 __ mulsd(first.AsFpuRegister<XmmRegister>(),
2643 Address(CpuRegister(RSP), second.GetStackIndex()));
2644 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01002645 break;
2646 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002647
2648 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002649 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002650 }
2651}
2652
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002653void InstructionCodeGeneratorX86_64::PushOntoFPStack(Location source, uint32_t temp_offset,
2654 uint32_t stack_adjustment, bool is_float) {
2655 if (source.IsStackSlot()) {
2656 DCHECK(is_float);
2657 __ flds(Address(CpuRegister(RSP), source.GetStackIndex() + stack_adjustment));
2658 } else if (source.IsDoubleStackSlot()) {
2659 DCHECK(!is_float);
2660 __ fldl(Address(CpuRegister(RSP), source.GetStackIndex() + stack_adjustment));
2661 } else {
2662 // Write the value to the temporary location on the stack and load to FP stack.
2663 if (is_float) {
2664 Location stack_temp = Location::StackSlot(temp_offset);
2665 codegen_->Move(stack_temp, source);
2666 __ flds(Address(CpuRegister(RSP), temp_offset));
2667 } else {
2668 Location stack_temp = Location::DoubleStackSlot(temp_offset);
2669 codegen_->Move(stack_temp, source);
2670 __ fldl(Address(CpuRegister(RSP), temp_offset));
2671 }
2672 }
2673}
2674
2675void InstructionCodeGeneratorX86_64::GenerateRemFP(HRem *rem) {
2676 Primitive::Type type = rem->GetResultType();
2677 bool is_float = type == Primitive::kPrimFloat;
2678 size_t elem_size = Primitive::ComponentSize(type);
2679 LocationSummary* locations = rem->GetLocations();
2680 Location first = locations->InAt(0);
2681 Location second = locations->InAt(1);
2682 Location out = locations->Out();
2683
2684 // Create stack space for 2 elements.
2685 // TODO: enhance register allocator to ask for stack temporaries.
2686 __ subq(CpuRegister(RSP), Immediate(2 * elem_size));
2687
2688 // Load the values to the FP stack in reverse order, using temporaries if needed.
2689 PushOntoFPStack(second, elem_size, 2 * elem_size, is_float);
2690 PushOntoFPStack(first, 0, 2 * elem_size, is_float);
2691
2692 // Loop doing FPREM until we stabilize.
2693 Label retry;
2694 __ Bind(&retry);
2695 __ fprem();
2696
2697 // Move FP status to AX.
2698 __ fstsw();
2699
2700 // And see if the argument reduction is complete. This is signaled by the
2701 // C2 FPU flag bit set to 0.
2702 __ andl(CpuRegister(RAX), Immediate(kC2ConditionMask));
2703 __ j(kNotEqual, &retry);
2704
2705 // We have settled on the final value. Retrieve it into an XMM register.
2706 // Store FP top of stack to real stack.
2707 if (is_float) {
2708 __ fsts(Address(CpuRegister(RSP), 0));
2709 } else {
2710 __ fstl(Address(CpuRegister(RSP), 0));
2711 }
2712
2713 // Pop the 2 items from the FP stack.
2714 __ fucompp();
2715
2716 // Load the value from the stack into an XMM register.
2717 DCHECK(out.IsFpuRegister()) << out;
2718 if (is_float) {
2719 __ movss(out.AsFpuRegister<XmmRegister>(), Address(CpuRegister(RSP), 0));
2720 } else {
2721 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(CpuRegister(RSP), 0));
2722 }
2723
2724 // And remove the temporary stack space we allocated.
2725 __ addq(CpuRegister(RSP), Immediate(2 * elem_size));
2726}
2727
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002728void InstructionCodeGeneratorX86_64::DivRemOneOrMinusOne(HBinaryOperation* instruction) {
2729 DCHECK(instruction->IsDiv() || instruction->IsRem());
2730
2731 LocationSummary* locations = instruction->GetLocations();
2732 Location second = locations->InAt(1);
2733 DCHECK(second.IsConstant());
2734
2735 CpuRegister output_register = locations->Out().AsRegister<CpuRegister>();
2736 CpuRegister input_register = locations->InAt(0).AsRegister<CpuRegister>();
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002737 int64_t imm = Int64FromConstant(second.GetConstant());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002738
2739 DCHECK(imm == 1 || imm == -1);
2740
2741 switch (instruction->GetResultType()) {
2742 case Primitive::kPrimInt: {
2743 if (instruction->IsRem()) {
2744 __ xorl(output_register, output_register);
2745 } else {
2746 __ movl(output_register, input_register);
2747 if (imm == -1) {
2748 __ negl(output_register);
2749 }
2750 }
2751 break;
2752 }
2753
2754 case Primitive::kPrimLong: {
2755 if (instruction->IsRem()) {
Mark Mendell92e83bf2015-05-07 11:25:03 -04002756 __ xorl(output_register, output_register);
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002757 } else {
2758 __ movq(output_register, input_register);
2759 if (imm == -1) {
2760 __ negq(output_register);
2761 }
2762 }
2763 break;
2764 }
2765
2766 default:
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002767 LOG(FATAL) << "Unexpected type for div by (-)1 " << instruction->GetResultType();
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002768 }
2769}
2770
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002771void InstructionCodeGeneratorX86_64::DivByPowerOfTwo(HDiv* instruction) {
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002772 LocationSummary* locations = instruction->GetLocations();
2773 Location second = locations->InAt(1);
2774
2775 CpuRegister output_register = locations->Out().AsRegister<CpuRegister>();
2776 CpuRegister numerator = locations->InAt(0).AsRegister<CpuRegister>();
2777
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002778 int64_t imm = Int64FromConstant(second.GetConstant());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002779
2780 DCHECK(IsPowerOfTwo(std::abs(imm)));
2781
2782 CpuRegister tmp = locations->GetTemp(0).AsRegister<CpuRegister>();
2783
2784 if (instruction->GetResultType() == Primitive::kPrimInt) {
2785 __ leal(tmp, Address(numerator, std::abs(imm) - 1));
2786 __ testl(numerator, numerator);
2787 __ cmov(kGreaterEqual, tmp, numerator);
2788 int shift = CTZ(imm);
2789 __ sarl(tmp, Immediate(shift));
2790
2791 if (imm < 0) {
2792 __ negl(tmp);
2793 }
2794
2795 __ movl(output_register, tmp);
2796 } else {
2797 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
2798 CpuRegister rdx = locations->GetTemp(0).AsRegister<CpuRegister>();
2799
Mark Mendell92e83bf2015-05-07 11:25:03 -04002800 codegen_->Load64BitValue(rdx, std::abs(imm) - 1);
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002801 __ addq(rdx, numerator);
2802 __ testq(numerator, numerator);
2803 __ cmov(kGreaterEqual, rdx, numerator);
2804 int shift = CTZ(imm);
2805 __ sarq(rdx, Immediate(shift));
2806
2807 if (imm < 0) {
2808 __ negq(rdx);
2809 }
2810
2811 __ movq(output_register, rdx);
2812 }
2813}
2814
2815void InstructionCodeGeneratorX86_64::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) {
2816 DCHECK(instruction->IsDiv() || instruction->IsRem());
2817
2818 LocationSummary* locations = instruction->GetLocations();
2819 Location second = locations->InAt(1);
2820
2821 CpuRegister numerator = instruction->IsDiv() ? locations->GetTemp(1).AsRegister<CpuRegister>()
2822 : locations->GetTemp(0).AsRegister<CpuRegister>();
2823 CpuRegister eax = locations->InAt(0).AsRegister<CpuRegister>();
2824 CpuRegister edx = instruction->IsDiv() ? locations->GetTemp(0).AsRegister<CpuRegister>()
2825 : locations->Out().AsRegister<CpuRegister>();
2826 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
2827
2828 DCHECK_EQ(RAX, eax.AsRegister());
2829 DCHECK_EQ(RDX, edx.AsRegister());
2830 if (instruction->IsDiv()) {
2831 DCHECK_EQ(RAX, out.AsRegister());
2832 } else {
2833 DCHECK_EQ(RDX, out.AsRegister());
2834 }
2835
2836 int64_t magic;
2837 int shift;
2838
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002839 // TODO: can these branches be written as one?
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002840 if (instruction->GetResultType() == Primitive::kPrimInt) {
2841 int imm = second.GetConstant()->AsIntConstant()->GetValue();
2842
2843 CalculateMagicAndShiftForDivRem(imm, false /* is_long */, &magic, &shift);
2844
2845 __ movl(numerator, eax);
2846
2847 Label no_div;
2848 Label end;
2849 __ testl(eax, eax);
2850 __ j(kNotEqual, &no_div);
2851
2852 __ xorl(out, out);
2853 __ jmp(&end);
2854
2855 __ Bind(&no_div);
2856
2857 __ movl(eax, Immediate(magic));
2858 __ imull(numerator);
2859
2860 if (imm > 0 && magic < 0) {
2861 __ addl(edx, numerator);
2862 } else if (imm < 0 && magic > 0) {
2863 __ subl(edx, numerator);
2864 }
2865
2866 if (shift != 0) {
2867 __ sarl(edx, Immediate(shift));
2868 }
2869
2870 __ movl(eax, edx);
2871 __ shrl(edx, Immediate(31));
2872 __ addl(edx, eax);
2873
2874 if (instruction->IsRem()) {
2875 __ movl(eax, numerator);
2876 __ imull(edx, Immediate(imm));
2877 __ subl(eax, edx);
2878 __ movl(edx, eax);
2879 } else {
2880 __ movl(eax, edx);
2881 }
2882 __ Bind(&end);
2883 } else {
2884 int64_t imm = second.GetConstant()->AsLongConstant()->GetValue();
2885
2886 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
2887
2888 CpuRegister rax = eax;
2889 CpuRegister rdx = edx;
2890
2891 CalculateMagicAndShiftForDivRem(imm, true /* is_long */, &magic, &shift);
2892
2893 // Save the numerator.
2894 __ movq(numerator, rax);
2895
2896 // RAX = magic
Mark Mendell92e83bf2015-05-07 11:25:03 -04002897 codegen_->Load64BitValue(rax, magic);
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002898
2899 // RDX:RAX = magic * numerator
2900 __ imulq(numerator);
2901
2902 if (imm > 0 && magic < 0) {
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002903 // RDX += numerator
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002904 __ addq(rdx, numerator);
2905 } else if (imm < 0 && magic > 0) {
2906 // RDX -= numerator
2907 __ subq(rdx, numerator);
2908 }
2909
2910 // Shift if needed.
2911 if (shift != 0) {
2912 __ sarq(rdx, Immediate(shift));
2913 }
2914
2915 // RDX += 1 if RDX < 0
2916 __ movq(rax, rdx);
2917 __ shrq(rdx, Immediate(63));
2918 __ addq(rdx, rax);
2919
2920 if (instruction->IsRem()) {
2921 __ movq(rax, numerator);
2922
2923 if (IsInt<32>(imm)) {
2924 __ imulq(rdx, Immediate(static_cast<int32_t>(imm)));
2925 } else {
Mark Mendell92e83bf2015-05-07 11:25:03 -04002926 __ imulq(rdx, codegen_->LiteralInt64Address(imm));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002927 }
2928
2929 __ subq(rax, rdx);
2930 __ movq(rdx, rax);
2931 } else {
2932 __ movq(rax, rdx);
2933 }
2934 }
2935}
2936
Calin Juravlebacfec32014-11-14 15:54:36 +00002937void InstructionCodeGeneratorX86_64::GenerateDivRemIntegral(HBinaryOperation* instruction) {
2938 DCHECK(instruction->IsDiv() || instruction->IsRem());
2939 Primitive::Type type = instruction->GetResultType();
2940 DCHECK(type == Primitive::kPrimInt || Primitive::kPrimLong);
2941
2942 bool is_div = instruction->IsDiv();
2943 LocationSummary* locations = instruction->GetLocations();
2944
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002945 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
2946 Location second = locations->InAt(1);
Calin Juravlebacfec32014-11-14 15:54:36 +00002947
Roland Levillain271ab9c2014-11-27 15:23:57 +00002948 DCHECK_EQ(RAX, locations->InAt(0).AsRegister<CpuRegister>().AsRegister());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002949 DCHECK_EQ(is_div ? RAX : RDX, out.AsRegister());
Calin Juravlebacfec32014-11-14 15:54:36 +00002950
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002951 if (second.IsConstant()) {
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002952 int64_t imm = Int64FromConstant(second.GetConstant());
Calin Juravlebacfec32014-11-14 15:54:36 +00002953
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002954 if (imm == 0) {
2955 // Do not generate anything. DivZeroCheck would prevent any code to be executed.
2956 } else if (imm == 1 || imm == -1) {
2957 DivRemOneOrMinusOne(instruction);
2958 } else if (instruction->IsDiv() && IsPowerOfTwo(std::abs(imm))) {
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002959 DivByPowerOfTwo(instruction->AsDiv());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002960 } else {
2961 DCHECK(imm <= -2 || imm >= 2);
2962 GenerateDivRemWithAnyConstant(instruction);
2963 }
Calin Juravlebacfec32014-11-14 15:54:36 +00002964 } else {
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002965 SlowPathCodeX86_64* slow_path =
2966 new (GetGraph()->GetArena()) DivRemMinusOneSlowPathX86_64(
2967 out.AsRegister(), type, is_div);
2968 codegen_->AddSlowPath(slow_path);
Calin Juravlebacfec32014-11-14 15:54:36 +00002969
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002970 CpuRegister second_reg = second.AsRegister<CpuRegister>();
2971 // 0x80000000(00000000)/-1 triggers an arithmetic exception!
2972 // Dividing by -1 is actually negation and -0x800000000(00000000) = 0x80000000(00000000)
2973 // so it's safe to just use negl instead of more complex comparisons.
2974 if (type == Primitive::kPrimInt) {
2975 __ cmpl(second_reg, Immediate(-1));
2976 __ j(kEqual, slow_path->GetEntryLabel());
2977 // edx:eax <- sign-extended of eax
2978 __ cdq();
2979 // eax = quotient, edx = remainder
2980 __ idivl(second_reg);
2981 } else {
2982 __ cmpq(second_reg, Immediate(-1));
2983 __ j(kEqual, slow_path->GetEntryLabel());
2984 // rdx:rax <- sign-extended of rax
2985 __ cqo();
2986 // rax = quotient, rdx = remainder
2987 __ idivq(second_reg);
2988 }
2989 __ Bind(slow_path->GetExitLabel());
2990 }
Calin Juravlebacfec32014-11-14 15:54:36 +00002991}
2992
Calin Juravle7c4954d2014-10-28 16:57:40 +00002993void LocationsBuilderX86_64::VisitDiv(HDiv* div) {
2994 LocationSummary* locations =
2995 new (GetGraph()->GetArena()) LocationSummary(div, LocationSummary::kNoCall);
2996 switch (div->GetResultType()) {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002997 case Primitive::kPrimInt:
2998 case Primitive::kPrimLong: {
Calin Juravled0d48522014-11-04 16:40:20 +00002999 locations->SetInAt(0, Location::RegisterLocation(RAX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003000 locations->SetInAt(1, Location::RegisterOrConstant(div->InputAt(1)));
Calin Juravled0d48522014-11-04 16:40:20 +00003001 locations->SetOut(Location::SameAsFirstInput());
3002 // Intel uses edx:eax as the dividend.
3003 locations->AddTemp(Location::RegisterLocation(RDX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003004 // We need to save the numerator while we tweak rax and rdx. As we are using imul in a way
3005 // which enforces results to be in RAX and RDX, things are simpler if we use RDX also as
3006 // output and request another temp.
3007 if (div->InputAt(1)->IsConstant()) {
3008 locations->AddTemp(Location::RequiresRegister());
3009 }
Calin Juravled0d48522014-11-04 16:40:20 +00003010 break;
3011 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003012
Calin Juravle7c4954d2014-10-28 16:57:40 +00003013 case Primitive::kPrimFloat:
3014 case Primitive::kPrimDouble: {
3015 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendellf55c3e02015-03-26 21:07:46 -04003016 locations->SetInAt(1, Location::Any());
Calin Juravle7c4954d2014-10-28 16:57:40 +00003017 locations->SetOut(Location::SameAsFirstInput());
3018 break;
3019 }
3020
3021 default:
3022 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
3023 }
3024}
3025
3026void InstructionCodeGeneratorX86_64::VisitDiv(HDiv* div) {
3027 LocationSummary* locations = div->GetLocations();
3028 Location first = locations->InAt(0);
3029 Location second = locations->InAt(1);
3030 DCHECK(first.Equals(locations->Out()));
3031
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003032 Primitive::Type type = div->GetResultType();
3033 switch (type) {
3034 case Primitive::kPrimInt:
3035 case Primitive::kPrimLong: {
Calin Juravlebacfec32014-11-14 15:54:36 +00003036 GenerateDivRemIntegral(div);
Calin Juravled0d48522014-11-04 16:40:20 +00003037 break;
3038 }
3039
Calin Juravle7c4954d2014-10-28 16:57:40 +00003040 case Primitive::kPrimFloat: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04003041 if (second.IsFpuRegister()) {
3042 __ divss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
3043 } else if (second.IsConstant()) {
3044 __ divss(first.AsFpuRegister<XmmRegister>(),
3045 codegen_->LiteralFloatAddress(second.GetConstant()->AsFloatConstant()->GetValue()));
3046 } else {
3047 DCHECK(second.IsStackSlot());
3048 __ divss(first.AsFpuRegister<XmmRegister>(),
3049 Address(CpuRegister(RSP), second.GetStackIndex()));
3050 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00003051 break;
3052 }
3053
3054 case Primitive::kPrimDouble: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04003055 if (second.IsFpuRegister()) {
3056 __ divsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
3057 } else if (second.IsConstant()) {
3058 __ divsd(first.AsFpuRegister<XmmRegister>(),
3059 codegen_->LiteralDoubleAddress(second.GetConstant()->AsDoubleConstant()->GetValue()));
3060 } else {
3061 DCHECK(second.IsDoubleStackSlot());
3062 __ divsd(first.AsFpuRegister<XmmRegister>(),
3063 Address(CpuRegister(RSP), second.GetStackIndex()));
3064 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00003065 break;
3066 }
3067
3068 default:
3069 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
3070 }
3071}
3072
Calin Juravlebacfec32014-11-14 15:54:36 +00003073void LocationsBuilderX86_64::VisitRem(HRem* rem) {
Calin Juravled2ec87d2014-12-08 14:24:46 +00003074 Primitive::Type type = rem->GetResultType();
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003075 LocationSummary* locations =
3076 new (GetGraph()->GetArena()) LocationSummary(rem, LocationSummary::kNoCall);
Calin Juravled2ec87d2014-12-08 14:24:46 +00003077
3078 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00003079 case Primitive::kPrimInt:
3080 case Primitive::kPrimLong: {
3081 locations->SetInAt(0, Location::RegisterLocation(RAX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003082 locations->SetInAt(1, Location::RegisterOrConstant(rem->InputAt(1)));
Calin Juravlebacfec32014-11-14 15:54:36 +00003083 // Intel uses rdx:rax as the dividend and puts the remainder in rdx
3084 locations->SetOut(Location::RegisterLocation(RDX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003085 // We need to save the numerator while we tweak eax and edx. As we are using imul in a way
3086 // which enforces results to be in RAX and RDX, things are simpler if we use EAX also as
3087 // output and request another temp.
3088 if (rem->InputAt(1)->IsConstant()) {
3089 locations->AddTemp(Location::RequiresRegister());
3090 }
Calin Juravlebacfec32014-11-14 15:54:36 +00003091 break;
3092 }
3093
3094 case Primitive::kPrimFloat:
3095 case Primitive::kPrimDouble: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003096 locations->SetInAt(0, Location::Any());
3097 locations->SetInAt(1, Location::Any());
3098 locations->SetOut(Location::RequiresFpuRegister());
3099 locations->AddTemp(Location::RegisterLocation(RAX));
Calin Juravlebacfec32014-11-14 15:54:36 +00003100 break;
3101 }
3102
3103 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00003104 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00003105 }
3106}
3107
3108void InstructionCodeGeneratorX86_64::VisitRem(HRem* rem) {
3109 Primitive::Type type = rem->GetResultType();
3110 switch (type) {
3111 case Primitive::kPrimInt:
3112 case Primitive::kPrimLong: {
3113 GenerateDivRemIntegral(rem);
3114 break;
3115 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003116 case Primitive::kPrimFloat:
Calin Juravled2ec87d2014-12-08 14:24:46 +00003117 case Primitive::kPrimDouble: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003118 GenerateRemFP(rem);
Calin Juravled2ec87d2014-12-08 14:24:46 +00003119 break;
3120 }
Calin Juravlebacfec32014-11-14 15:54:36 +00003121 default:
3122 LOG(FATAL) << "Unexpected rem type " << rem->GetResultType();
3123 }
3124}
3125
Calin Juravled0d48522014-11-04 16:40:20 +00003126void LocationsBuilderX86_64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
3127 LocationSummary* locations =
3128 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3129 locations->SetInAt(0, Location::Any());
3130 if (instruction->HasUses()) {
3131 locations->SetOut(Location::SameAsFirstInput());
3132 }
3133}
3134
3135void InstructionCodeGeneratorX86_64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
3136 SlowPathCodeX86_64* slow_path =
3137 new (GetGraph()->GetArena()) DivZeroCheckSlowPathX86_64(instruction);
3138 codegen_->AddSlowPath(slow_path);
3139
3140 LocationSummary* locations = instruction->GetLocations();
3141 Location value = locations->InAt(0);
3142
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003143 switch (instruction->GetType()) {
Serguei Katkov8c0676c2015-08-03 13:55:33 +06003144 case Primitive::kPrimByte:
3145 case Primitive::kPrimChar:
3146 case Primitive::kPrimShort:
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003147 case Primitive::kPrimInt: {
3148 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003149 __ testl(value.AsRegister<CpuRegister>(), value.AsRegister<CpuRegister>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003150 __ j(kEqual, slow_path->GetEntryLabel());
3151 } else if (value.IsStackSlot()) {
3152 __ cmpl(Address(CpuRegister(RSP), value.GetStackIndex()), Immediate(0));
3153 __ j(kEqual, slow_path->GetEntryLabel());
3154 } else {
3155 DCHECK(value.IsConstant()) << value;
3156 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
3157 __ jmp(slow_path->GetEntryLabel());
3158 }
3159 }
3160 break;
Calin Juravled0d48522014-11-04 16:40:20 +00003161 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003162 case Primitive::kPrimLong: {
3163 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003164 __ testq(value.AsRegister<CpuRegister>(), value.AsRegister<CpuRegister>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003165 __ j(kEqual, slow_path->GetEntryLabel());
3166 } else if (value.IsDoubleStackSlot()) {
3167 __ cmpq(Address(CpuRegister(RSP), value.GetStackIndex()), Immediate(0));
3168 __ j(kEqual, slow_path->GetEntryLabel());
3169 } else {
3170 DCHECK(value.IsConstant()) << value;
3171 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
3172 __ jmp(slow_path->GetEntryLabel());
3173 }
3174 }
3175 break;
3176 }
3177 default:
3178 LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
Calin Juravled0d48522014-11-04 16:40:20 +00003179 }
Calin Juravled0d48522014-11-04 16:40:20 +00003180}
3181
Calin Juravle9aec02f2014-11-18 23:06:35 +00003182void LocationsBuilderX86_64::HandleShift(HBinaryOperation* op) {
3183 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
3184
3185 LocationSummary* locations =
3186 new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
3187
3188 switch (op->GetResultType()) {
3189 case Primitive::kPrimInt:
3190 case Primitive::kPrimLong: {
3191 locations->SetInAt(0, Location::RequiresRegister());
3192 // The shift count needs to be in CL.
3193 locations->SetInAt(1, Location::ByteRegisterOrConstant(RCX, op->InputAt(1)));
3194 locations->SetOut(Location::SameAsFirstInput());
3195 break;
3196 }
3197 default:
3198 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
3199 }
3200}
3201
3202void InstructionCodeGeneratorX86_64::HandleShift(HBinaryOperation* op) {
3203 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
3204
3205 LocationSummary* locations = op->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003206 CpuRegister first_reg = locations->InAt(0).AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003207 Location second = locations->InAt(1);
3208
3209 switch (op->GetResultType()) {
3210 case Primitive::kPrimInt: {
3211 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003212 CpuRegister second_reg = second.AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003213 if (op->IsShl()) {
3214 __ shll(first_reg, second_reg);
3215 } else if (op->IsShr()) {
3216 __ sarl(first_reg, second_reg);
3217 } else {
3218 __ shrl(first_reg, second_reg);
3219 }
3220 } else {
Nicolas Geoffray486cc192014-12-08 18:00:55 +00003221 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxIntShiftValue);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003222 if (op->IsShl()) {
3223 __ shll(first_reg, imm);
3224 } else if (op->IsShr()) {
3225 __ sarl(first_reg, imm);
3226 } else {
3227 __ shrl(first_reg, imm);
3228 }
3229 }
3230 break;
3231 }
3232 case Primitive::kPrimLong: {
3233 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003234 CpuRegister second_reg = second.AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003235 if (op->IsShl()) {
3236 __ shlq(first_reg, second_reg);
3237 } else if (op->IsShr()) {
3238 __ sarq(first_reg, second_reg);
3239 } else {
3240 __ shrq(first_reg, second_reg);
3241 }
3242 } else {
Nicolas Geoffray486cc192014-12-08 18:00:55 +00003243 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxLongShiftValue);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003244 if (op->IsShl()) {
3245 __ shlq(first_reg, imm);
3246 } else if (op->IsShr()) {
3247 __ sarq(first_reg, imm);
3248 } else {
3249 __ shrq(first_reg, imm);
3250 }
3251 }
3252 break;
3253 }
3254 default:
3255 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
3256 }
3257}
3258
3259void LocationsBuilderX86_64::VisitShl(HShl* shl) {
3260 HandleShift(shl);
3261}
3262
3263void InstructionCodeGeneratorX86_64::VisitShl(HShl* shl) {
3264 HandleShift(shl);
3265}
3266
3267void LocationsBuilderX86_64::VisitShr(HShr* shr) {
3268 HandleShift(shr);
3269}
3270
3271void InstructionCodeGeneratorX86_64::VisitShr(HShr* shr) {
3272 HandleShift(shr);
3273}
3274
3275void LocationsBuilderX86_64::VisitUShr(HUShr* ushr) {
3276 HandleShift(ushr);
3277}
3278
3279void InstructionCodeGeneratorX86_64::VisitUShr(HUShr* ushr) {
3280 HandleShift(ushr);
3281}
3282
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003283void LocationsBuilderX86_64::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003284 LocationSummary* locations =
3285 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01003286 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003287 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Nicolas Geoffray69aa6012015-06-09 10:34:25 +01003288 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003289 locations->SetOut(Location::RegisterLocation(RAX));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003290}
3291
3292void InstructionCodeGeneratorX86_64::VisitNewInstance(HNewInstance* instruction) {
3293 InvokeRuntimeCallingConvention calling_convention;
Mark Mendell92e83bf2015-05-07 11:25:03 -04003294 codegen_->Load64BitValue(CpuRegister(calling_convention.GetRegisterAt(0)),
3295 instruction->GetTypeIndex());
Roland Levillain4d027112015-07-01 15:41:14 +01003296 // Note: if heap poisoning is enabled, the entry point takes cares
3297 // of poisoning the reference.
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +00003298 __ gs()->call(
3299 Address::Absolute(GetThreadOffset<kX86_64WordSize>(instruction->GetEntrypoint()), true));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003300
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01003301 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray39468442014-09-02 15:17:15 +01003302 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003303}
3304
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003305void LocationsBuilderX86_64::VisitNewArray(HNewArray* instruction) {
3306 LocationSummary* locations =
3307 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
3308 InvokeRuntimeCallingConvention calling_convention;
3309 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003310 locations->SetOut(Location::RegisterLocation(RAX));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08003311 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray69aa6012015-06-09 10:34:25 +01003312 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003313}
3314
3315void InstructionCodeGeneratorX86_64::VisitNewArray(HNewArray* instruction) {
3316 InvokeRuntimeCallingConvention calling_convention;
Mark Mendell92e83bf2015-05-07 11:25:03 -04003317 codegen_->Load64BitValue(CpuRegister(calling_convention.GetRegisterAt(0)),
3318 instruction->GetTypeIndex());
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003319
Roland Levillain4d027112015-07-01 15:41:14 +01003320 // Note: if heap poisoning is enabled, the entry point takes cares
3321 // of poisoning the reference.
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +00003322 __ gs()->call(
3323 Address::Absolute(GetThreadOffset<kX86_64WordSize>(instruction->GetEntrypoint()), true));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003324
3325 DCHECK(!codegen_->IsLeafMethod());
3326 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3327}
3328
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003329void LocationsBuilderX86_64::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003330 LocationSummary* locations =
3331 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003332 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
3333 if (location.IsStackSlot()) {
3334 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
3335 } else if (location.IsDoubleStackSlot()) {
3336 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
3337 }
3338 locations->SetOut(location);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003339}
3340
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01003341void InstructionCodeGeneratorX86_64::VisitParameterValue(
3342 HParameterValue* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003343 // Nothing to do, the parameter is already at its location.
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01003344}
3345
3346void LocationsBuilderX86_64::VisitCurrentMethod(HCurrentMethod* instruction) {
3347 LocationSummary* locations =
3348 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3349 locations->SetOut(Location::RegisterLocation(kMethodRegisterArgument));
3350}
3351
3352void InstructionCodeGeneratorX86_64::VisitCurrentMethod(
3353 HCurrentMethod* instruction ATTRIBUTE_UNUSED) {
3354 // Nothing to do, the method is already at its location.
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003355}
3356
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003357void LocationsBuilderX86_64::VisitNot(HNot* not_) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003358 LocationSummary* locations =
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003359 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003360 locations->SetInAt(0, Location::RequiresRegister());
3361 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003362}
3363
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003364void InstructionCodeGeneratorX86_64::VisitNot(HNot* not_) {
3365 LocationSummary* locations = not_->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003366 DCHECK_EQ(locations->InAt(0).AsRegister<CpuRegister>().AsRegister(),
3367 locations->Out().AsRegister<CpuRegister>().AsRegister());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003368 Location out = locations->Out();
Nicolas Geoffrayd8ef2e92015-02-24 16:02:06 +00003369 switch (not_->GetResultType()) {
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003370 case Primitive::kPrimInt:
Roland Levillain271ab9c2014-11-27 15:23:57 +00003371 __ notl(out.AsRegister<CpuRegister>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003372 break;
3373
3374 case Primitive::kPrimLong:
Roland Levillain271ab9c2014-11-27 15:23:57 +00003375 __ notq(out.AsRegister<CpuRegister>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003376 break;
3377
3378 default:
3379 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
3380 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003381}
3382
David Brazdil66d126e2015-04-03 16:02:44 +01003383void LocationsBuilderX86_64::VisitBooleanNot(HBooleanNot* bool_not) {
3384 LocationSummary* locations =
3385 new (GetGraph()->GetArena()) LocationSummary(bool_not, LocationSummary::kNoCall);
3386 locations->SetInAt(0, Location::RequiresRegister());
3387 locations->SetOut(Location::SameAsFirstInput());
3388}
3389
3390void InstructionCodeGeneratorX86_64::VisitBooleanNot(HBooleanNot* bool_not) {
David Brazdil66d126e2015-04-03 16:02:44 +01003391 LocationSummary* locations = bool_not->GetLocations();
3392 DCHECK_EQ(locations->InAt(0).AsRegister<CpuRegister>().AsRegister(),
3393 locations->Out().AsRegister<CpuRegister>().AsRegister());
3394 Location out = locations->Out();
3395 __ xorl(out.AsRegister<CpuRegister>(), Immediate(1));
3396}
3397
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003398void LocationsBuilderX86_64::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003399 LocationSummary* locations =
3400 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003401 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
3402 locations->SetInAt(i, Location::Any());
3403 }
3404 locations->SetOut(Location::Any());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003405}
3406
3407void InstructionCodeGeneratorX86_64::VisitPhi(HPhi* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003408 UNUSED(instruction);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003409 LOG(FATAL) << "Unimplemented";
3410}
3411
Calin Juravle52c48962014-12-16 17:02:57 +00003412void InstructionCodeGeneratorX86_64::GenerateMemoryBarrier(MemBarrierKind kind) {
3413 /*
3414 * According to the JSR-133 Cookbook, for x86 only StoreLoad/AnyAny barriers need memory fence.
3415 * All other barriers (LoadAny, AnyStore, StoreStore) are nops due to the x86 memory model.
3416 * For those cases, all we need to ensure is that there is a scheduling barrier in place.
3417 */
3418 switch (kind) {
3419 case MemBarrierKind::kAnyAny: {
3420 __ mfence();
3421 break;
3422 }
3423 case MemBarrierKind::kAnyStore:
3424 case MemBarrierKind::kLoadAny:
3425 case MemBarrierKind::kStoreStore: {
3426 // nop
3427 break;
3428 }
3429 default:
3430 LOG(FATAL) << "Unexpected memory barier " << kind;
3431 }
3432}
3433
3434void LocationsBuilderX86_64::HandleFieldGet(HInstruction* instruction) {
3435 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
3436
Nicolas Geoffray39468442014-09-02 15:17:15 +01003437 LocationSummary* locations =
3438 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Calin Juravle52c48962014-12-16 17:02:57 +00003439 locations->SetInAt(0, Location::RequiresRegister());
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003440 if (Primitive::IsFloatingPointType(instruction->GetType())) {
3441 locations->SetOut(Location::RequiresFpuRegister());
3442 } else {
3443 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3444 }
Calin Juravle52c48962014-12-16 17:02:57 +00003445}
3446
3447void InstructionCodeGeneratorX86_64::HandleFieldGet(HInstruction* instruction,
3448 const FieldInfo& field_info) {
3449 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
3450
3451 LocationSummary* locations = instruction->GetLocations();
3452 CpuRegister base = locations->InAt(0).AsRegister<CpuRegister>();
3453 Location out = locations->Out();
3454 bool is_volatile = field_info.IsVolatile();
3455 Primitive::Type field_type = field_info.GetFieldType();
3456 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
3457
3458 switch (field_type) {
3459 case Primitive::kPrimBoolean: {
3460 __ movzxb(out.AsRegister<CpuRegister>(), Address(base, offset));
3461 break;
3462 }
3463
3464 case Primitive::kPrimByte: {
3465 __ movsxb(out.AsRegister<CpuRegister>(), Address(base, offset));
3466 break;
3467 }
3468
3469 case Primitive::kPrimShort: {
3470 __ movsxw(out.AsRegister<CpuRegister>(), Address(base, offset));
3471 break;
3472 }
3473
3474 case Primitive::kPrimChar: {
3475 __ movzxw(out.AsRegister<CpuRegister>(), Address(base, offset));
3476 break;
3477 }
3478
3479 case Primitive::kPrimInt:
3480 case Primitive::kPrimNot: {
3481 __ movl(out.AsRegister<CpuRegister>(), Address(base, offset));
3482 break;
3483 }
3484
3485 case Primitive::kPrimLong: {
3486 __ movq(out.AsRegister<CpuRegister>(), Address(base, offset));
3487 break;
3488 }
3489
3490 case Primitive::kPrimFloat: {
3491 __ movss(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
3492 break;
3493 }
3494
3495 case Primitive::kPrimDouble: {
3496 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
3497 break;
3498 }
3499
3500 case Primitive::kPrimVoid:
3501 LOG(FATAL) << "Unreachable type " << field_type;
3502 UNREACHABLE();
3503 }
3504
Calin Juravle77520bc2015-01-12 18:45:46 +00003505 codegen_->MaybeRecordImplicitNullCheck(instruction);
3506
Calin Juravle52c48962014-12-16 17:02:57 +00003507 if (is_volatile) {
3508 GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
3509 }
Roland Levillain4d027112015-07-01 15:41:14 +01003510
3511 if (field_type == Primitive::kPrimNot) {
3512 __ MaybeUnpoisonHeapReference(out.AsRegister<CpuRegister>());
3513 }
Calin Juravle52c48962014-12-16 17:02:57 +00003514}
3515
3516void LocationsBuilderX86_64::HandleFieldSet(HInstruction* instruction,
3517 const FieldInfo& field_info) {
3518 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3519
3520 LocationSummary* locations =
3521 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Roland Levillain4d027112015-07-01 15:41:14 +01003522 Primitive::Type field_type = field_info.GetFieldType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003523 bool needs_write_barrier =
Roland Levillain4d027112015-07-01 15:41:14 +01003524 CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
Calin Juravle52c48962014-12-16 17:02:57 +00003525
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003526 locations->SetInAt(0, Location::RequiresRegister());
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003527 if (Primitive::IsFloatingPointType(instruction->InputAt(1)->GetType())) {
3528 locations->SetInAt(1, Location::RequiresFpuRegister());
3529 } else {
Mark Mendell40741f32015-04-20 22:10:34 -04003530 locations->SetInAt(1, Location::RegisterOrInt32LongConstant(instruction->InputAt(1)));
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003531 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003532 if (needs_write_barrier) {
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01003533 // Temporary registers for the write barrier.
Roland Levillain4d027112015-07-01 15:41:14 +01003534 locations->AddTemp(Location::RequiresRegister()); // Possibly used for reference poisoning too.
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003535 locations->AddTemp(Location::RequiresRegister());
Roland Levillain4d027112015-07-01 15:41:14 +01003536 } else if (kPoisonHeapReferences && field_type == Primitive::kPrimNot) {
3537 // Temporary register for the reference poisoning.
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003538 locations->AddTemp(Location::RequiresRegister());
3539 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003540}
3541
Calin Juravle52c48962014-12-16 17:02:57 +00003542void InstructionCodeGeneratorX86_64::HandleFieldSet(HInstruction* instruction,
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003543 const FieldInfo& field_info,
3544 bool value_can_be_null) {
Calin Juravle52c48962014-12-16 17:02:57 +00003545 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3546
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003547 LocationSummary* locations = instruction->GetLocations();
Calin Juravle52c48962014-12-16 17:02:57 +00003548 CpuRegister base = locations->InAt(0).AsRegister<CpuRegister>();
3549 Location value = locations->InAt(1);
3550 bool is_volatile = field_info.IsVolatile();
3551 Primitive::Type field_type = field_info.GetFieldType();
3552 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
3553
3554 if (is_volatile) {
3555 GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
3556 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003557
3558 switch (field_type) {
3559 case Primitive::kPrimBoolean:
3560 case Primitive::kPrimByte: {
Mark Mendell40741f32015-04-20 22:10:34 -04003561 if (value.IsConstant()) {
3562 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
3563 __ movb(Address(base, offset), Immediate(v));
3564 } else {
3565 __ movb(Address(base, offset), value.AsRegister<CpuRegister>());
3566 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003567 break;
3568 }
3569
3570 case Primitive::kPrimShort:
3571 case Primitive::kPrimChar: {
Mark Mendell40741f32015-04-20 22:10:34 -04003572 if (value.IsConstant()) {
3573 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
3574 __ movw(Address(base, offset), Immediate(v));
3575 } else {
3576 __ movw(Address(base, offset), value.AsRegister<CpuRegister>());
3577 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003578 break;
3579 }
3580
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003581 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003582 case Primitive::kPrimNot: {
Mark Mendell40741f32015-04-20 22:10:34 -04003583 if (value.IsConstant()) {
3584 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
Roland Levillain4d027112015-07-01 15:41:14 +01003585 // `field_type == Primitive::kPrimNot` implies `v == 0`.
3586 DCHECK((field_type != Primitive::kPrimNot) || (v == 0));
3587 // Note: if heap poisoning is enabled, no need to poison
3588 // (negate) `v` if it is a reference, as it would be null.
Roland Levillain06b66d02015-07-01 12:47:25 +01003589 __ movl(Address(base, offset), Immediate(v));
Mark Mendell40741f32015-04-20 22:10:34 -04003590 } else {
Roland Levillain4d027112015-07-01 15:41:14 +01003591 if (kPoisonHeapReferences && field_type == Primitive::kPrimNot) {
3592 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
3593 __ movl(temp, value.AsRegister<CpuRegister>());
3594 __ PoisonHeapReference(temp);
3595 __ movl(Address(base, offset), temp);
3596 } else {
3597 __ movl(Address(base, offset), value.AsRegister<CpuRegister>());
3598 }
Mark Mendell40741f32015-04-20 22:10:34 -04003599 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003600 break;
3601 }
3602
3603 case Primitive::kPrimLong: {
Mark Mendell40741f32015-04-20 22:10:34 -04003604 if (value.IsConstant()) {
3605 int64_t v = value.GetConstant()->AsLongConstant()->GetValue();
3606 DCHECK(IsInt<32>(v));
3607 int32_t v_32 = v;
3608 __ movq(Address(base, offset), Immediate(v_32));
3609 } else {
3610 __ movq(Address(base, offset), value.AsRegister<CpuRegister>());
3611 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003612 break;
3613 }
3614
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003615 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00003616 __ movss(Address(base, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003617 break;
3618 }
3619
3620 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00003621 __ movsd(Address(base, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003622 break;
3623 }
3624
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003625 case Primitive::kPrimVoid:
3626 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003627 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003628 }
Calin Juravle52c48962014-12-16 17:02:57 +00003629
Calin Juravle77520bc2015-01-12 18:45:46 +00003630 codegen_->MaybeRecordImplicitNullCheck(instruction);
3631
3632 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
3633 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
3634 CpuRegister card = locations->GetTemp(1).AsRegister<CpuRegister>();
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003635 codegen_->MarkGCCard(temp, card, base, value.AsRegister<CpuRegister>(), value_can_be_null);
Calin Juravle77520bc2015-01-12 18:45:46 +00003636 }
3637
Calin Juravle52c48962014-12-16 17:02:57 +00003638 if (is_volatile) {
3639 GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
3640 }
3641}
3642
3643void LocationsBuilderX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
3644 HandleFieldSet(instruction, instruction->GetFieldInfo());
3645}
3646
3647void InstructionCodeGeneratorX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003648 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003649}
3650
3651void LocationsBuilderX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Calin Juravle52c48962014-12-16 17:02:57 +00003652 HandleFieldGet(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003653}
3654
3655void InstructionCodeGeneratorX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Calin Juravle52c48962014-12-16 17:02:57 +00003656 HandleFieldGet(instruction, instruction->GetFieldInfo());
3657}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003658
Calin Juravle52c48962014-12-16 17:02:57 +00003659void LocationsBuilderX86_64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
3660 HandleFieldGet(instruction);
3661}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003662
Calin Juravle52c48962014-12-16 17:02:57 +00003663void InstructionCodeGeneratorX86_64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
3664 HandleFieldGet(instruction, instruction->GetFieldInfo());
3665}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003666
Calin Juravle52c48962014-12-16 17:02:57 +00003667void LocationsBuilderX86_64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
3668 HandleFieldSet(instruction, instruction->GetFieldInfo());
3669}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003670
Calin Juravle52c48962014-12-16 17:02:57 +00003671void InstructionCodeGeneratorX86_64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003672 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003673}
3674
3675void LocationsBuilderX86_64::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003676 LocationSummary* locations =
3677 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003678 Location loc = codegen_->GetCompilerOptions().GetImplicitNullChecks()
3679 ? Location::RequiresRegister()
3680 : Location::Any();
3681 locations->SetInAt(0, loc);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003682 if (instruction->HasUses()) {
3683 locations->SetOut(Location::SameAsFirstInput());
3684 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003685}
3686
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003687void InstructionCodeGeneratorX86_64::GenerateImplicitNullCheck(HNullCheck* instruction) {
Calin Juravle77520bc2015-01-12 18:45:46 +00003688 if (codegen_->CanMoveNullCheckToUser(instruction)) {
3689 return;
3690 }
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003691 LocationSummary* locations = instruction->GetLocations();
3692 Location obj = locations->InAt(0);
3693
3694 __ testl(CpuRegister(RAX), Address(obj.AsRegister<CpuRegister>(), 0));
3695 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3696}
3697
3698void InstructionCodeGeneratorX86_64::GenerateExplicitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +01003699 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathX86_64(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003700 codegen_->AddSlowPath(slow_path);
3701
3702 LocationSummary* locations = instruction->GetLocations();
3703 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003704
3705 if (obj.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00003706 __ testl(obj.AsRegister<CpuRegister>(), obj.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003707 } else if (obj.IsStackSlot()) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003708 __ cmpl(Address(CpuRegister(RSP), obj.GetStackIndex()), Immediate(0));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003709 } else {
3710 DCHECK(obj.IsConstant()) << obj;
3711 DCHECK_EQ(obj.GetConstant()->AsIntConstant()->GetValue(), 0);
3712 __ jmp(slow_path->GetEntryLabel());
3713 return;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003714 }
3715 __ j(kEqual, slow_path->GetEntryLabel());
3716}
3717
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003718void InstructionCodeGeneratorX86_64::VisitNullCheck(HNullCheck* instruction) {
3719 if (codegen_->GetCompilerOptions().GetImplicitNullChecks()) {
3720 GenerateImplicitNullCheck(instruction);
3721 } else {
3722 GenerateExplicitNullCheck(instruction);
3723 }
3724}
3725
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003726void LocationsBuilderX86_64::VisitArrayGet(HArrayGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003727 LocationSummary* locations =
3728 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003729 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell40741f32015-04-20 22:10:34 -04003730 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003731 if (Primitive::IsFloatingPointType(instruction->GetType())) {
3732 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
3733 } else {
3734 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3735 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003736}
3737
3738void InstructionCodeGeneratorX86_64::VisitArrayGet(HArrayGet* instruction) {
3739 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003740 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003741 Location index = locations->InAt(1);
Roland Levillain4d027112015-07-01 15:41:14 +01003742 Primitive::Type type = instruction->GetType();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003743
Roland Levillain4d027112015-07-01 15:41:14 +01003744 switch (type) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003745 case Primitive::kPrimBoolean: {
3746 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003747 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003748 if (index.IsConstant()) {
3749 __ movzxb(out, Address(obj,
3750 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
3751 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003752 __ movzxb(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003753 }
3754 break;
3755 }
3756
3757 case Primitive::kPrimByte: {
3758 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003759 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003760 if (index.IsConstant()) {
3761 __ movsxb(out, Address(obj,
3762 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
3763 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003764 __ movsxb(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003765 }
3766 break;
3767 }
3768
3769 case Primitive::kPrimShort: {
3770 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003771 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003772 if (index.IsConstant()) {
3773 __ movsxw(out, Address(obj,
3774 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
3775 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003776 __ movsxw(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003777 }
3778 break;
3779 }
3780
3781 case Primitive::kPrimChar: {
3782 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003783 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003784 if (index.IsConstant()) {
3785 __ movzxw(out, Address(obj,
3786 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
3787 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003788 __ movzxw(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003789 }
3790 break;
3791 }
3792
3793 case Primitive::kPrimInt:
3794 case Primitive::kPrimNot: {
Roland Levillain33d69032015-06-18 18:20:59 +01003795 static_assert(sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
3796 "art::mirror::HeapReference<mirror::Object> and int32_t have different sizes.");
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003797 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003798 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003799 if (index.IsConstant()) {
3800 __ movl(out, Address(obj,
3801 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
3802 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003803 __ movl(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003804 }
3805 break;
3806 }
3807
3808 case Primitive::kPrimLong: {
3809 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003810 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003811 if (index.IsConstant()) {
3812 __ movq(out, Address(obj,
3813 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
3814 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003815 __ movq(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003816 }
3817 break;
3818 }
3819
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003820 case Primitive::kPrimFloat: {
3821 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003822 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003823 if (index.IsConstant()) {
3824 __ movss(out, Address(obj,
3825 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
3826 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003827 __ movss(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003828 }
3829 break;
3830 }
3831
3832 case Primitive::kPrimDouble: {
3833 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003834 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003835 if (index.IsConstant()) {
3836 __ movsd(out, Address(obj,
3837 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
3838 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003839 __ movsd(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003840 }
3841 break;
3842 }
3843
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003844 case Primitive::kPrimVoid:
Roland Levillain4d027112015-07-01 15:41:14 +01003845 LOG(FATAL) << "Unreachable type " << type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003846 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003847 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003848 codegen_->MaybeRecordImplicitNullCheck(instruction);
Roland Levillain4d027112015-07-01 15:41:14 +01003849
3850 if (type == Primitive::kPrimNot) {
3851 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
3852 __ MaybeUnpoisonHeapReference(out);
3853 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003854}
3855
3856void LocationsBuilderX86_64::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003857 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003858
3859 bool needs_write_barrier =
3860 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
3861 bool needs_runtime_call = instruction->NeedsTypeCheck();
3862
Nicolas Geoffray39468442014-09-02 15:17:15 +01003863 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003864 instruction, needs_runtime_call ? LocationSummary::kCall : LocationSummary::kNoCall);
3865 if (needs_runtime_call) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003866 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003867 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3868 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
3869 locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003870 } else {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003871 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01003872 locations->SetInAt(
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003873 1, Location::RegisterOrConstant(instruction->InputAt(1)));
3874 locations->SetInAt(2, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003875 if (value_type == Primitive::kPrimLong) {
Mark Mendell40741f32015-04-20 22:10:34 -04003876 locations->SetInAt(2, Location::RegisterOrInt32LongConstant(instruction->InputAt(2)));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003877 } else if (value_type == Primitive::kPrimFloat || value_type == Primitive::kPrimDouble) {
3878 locations->SetInAt(2, Location::RequiresFpuRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003879 } else {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003880 locations->SetInAt(2, Location::RegisterOrConstant(instruction->InputAt(2)));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003881 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003882
3883 if (needs_write_barrier) {
3884 // Temporary registers for the write barrier.
Roland Levillain4d027112015-07-01 15:41:14 +01003885 locations->AddTemp(Location::RequiresRegister()); // Possibly used for ref. poisoning too.
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003886 locations->AddTemp(Location::RequiresRegister());
3887 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003888 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003889}
3890
3891void InstructionCodeGeneratorX86_64::VisitArraySet(HArraySet* instruction) {
3892 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003893 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003894 Location index = locations->InAt(1);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003895 Location value = locations->InAt(2);
Nicolas Geoffray39468442014-09-02 15:17:15 +01003896 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003897 bool needs_runtime_call = locations->WillCall();
3898 bool needs_write_barrier =
3899 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003900
3901 switch (value_type) {
3902 case Primitive::kPrimBoolean:
3903 case Primitive::kPrimByte: {
3904 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003905 if (index.IsConstant()) {
3906 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003907 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003908 __ movb(Address(obj, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003909 } else {
Roland Levillain199f3362014-11-27 17:15:16 +00003910 __ movb(Address(obj, offset),
3911 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003912 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003913 } else {
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003914 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003915 __ movb(Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset),
3916 value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003917 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003918 __ movb(Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003919 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3920 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003921 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003922 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003923 break;
3924 }
3925
3926 case Primitive::kPrimShort:
3927 case Primitive::kPrimChar: {
3928 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003929 if (index.IsConstant()) {
3930 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003931 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003932 __ movw(Address(obj, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003933 } else {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003934 DCHECK(value.IsConstant()) << value;
Roland Levillain199f3362014-11-27 17:15:16 +00003935 __ movw(Address(obj, offset),
3936 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003937 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003938 } else {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003939 DCHECK(index.IsRegister()) << index;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003940 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003941 __ movw(Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset),
3942 value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003943 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003944 DCHECK(value.IsConstant()) << value;
Roland Levillain271ab9c2014-11-27 15:23:57 +00003945 __ movw(Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003946 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3947 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003948 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003949 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003950 break;
3951 }
3952
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003953 case Primitive::kPrimInt:
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003954 case Primitive::kPrimNot: {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003955 if (!needs_runtime_call) {
3956 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
3957 if (index.IsConstant()) {
3958 size_t offset =
3959 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
3960 if (value.IsRegister()) {
Roland Levillain4d027112015-07-01 15:41:14 +01003961 if (kPoisonHeapReferences && value_type == Primitive::kPrimNot) {
3962 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
3963 __ movl(temp, value.AsRegister<CpuRegister>());
3964 __ PoisonHeapReference(temp);
3965 __ movl(Address(obj, offset), temp);
3966 } else {
3967 __ movl(Address(obj, offset), value.AsRegister<CpuRegister>());
3968 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003969 } else {
3970 DCHECK(value.IsConstant()) << value;
Mark Mendell40741f32015-04-20 22:10:34 -04003971 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
Roland Levillain4d027112015-07-01 15:41:14 +01003972 // `value_type == Primitive::kPrimNot` implies `v == 0`.
3973 DCHECK((value_type != Primitive::kPrimNot) || (v == 0));
3974 // Note: if heap poisoning is enabled, no need to poison
3975 // (negate) `v` if it is a reference, as it would be null.
Mark Mendell40741f32015-04-20 22:10:34 -04003976 __ movl(Address(obj, offset), Immediate(v));
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003977 }
3978 } else {
3979 DCHECK(index.IsRegister()) << index;
3980 if (value.IsRegister()) {
Roland Levillain4d027112015-07-01 15:41:14 +01003981 if (kPoisonHeapReferences && value_type == Primitive::kPrimNot) {
3982 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
3983 __ movl(temp, value.AsRegister<CpuRegister>());
3984 __ PoisonHeapReference(temp);
3985 __ movl(Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset), temp);
3986 } else {
3987 __ movl(Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset),
3988 value.AsRegister<CpuRegister>());
3989 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003990 } else {
3991 DCHECK(value.IsConstant()) << value;
Mark Mendell40741f32015-04-20 22:10:34 -04003992 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
Roland Levillain4d027112015-07-01 15:41:14 +01003993 // `value_type == Primitive::kPrimNot` implies `v == 0`.
3994 DCHECK((value_type != Primitive::kPrimNot) || (v == 0));
3995 // Note: if heap poisoning is enabled, no need to poison
3996 // (negate) `v` if it is a reference, as it would be null.
Roland Levillain271ab9c2014-11-27 15:23:57 +00003997 __ movl(Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset),
Mark Mendell40741f32015-04-20 22:10:34 -04003998 Immediate(v));
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003999 }
4000 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004001 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004002 if (needs_write_barrier) {
4003 DCHECK_EQ(value_type, Primitive::kPrimNot);
Roland Levillain271ab9c2014-11-27 15:23:57 +00004004 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
4005 CpuRegister card = locations->GetTemp(1).AsRegister<CpuRegister>();
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004006 codegen_->MarkGCCard(
4007 temp, card, obj, value.AsRegister<CpuRegister>(), instruction->GetValueCanBeNull());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004008 }
4009 } else {
4010 DCHECK_EQ(value_type, Primitive::kPrimNot);
Roland Levillain4d027112015-07-01 15:41:14 +01004011 // Note: if heap poisoning is enabled, pAputObject takes cares
4012 // of poisoning the reference.
Roland Levillain199f3362014-11-27 17:15:16 +00004013 __ gs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pAputObject),
4014 true));
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004015 DCHECK(!codegen_->IsLeafMethod());
4016 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
4017 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004018 break;
4019 }
4020
4021 case Primitive::kPrimLong: {
4022 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004023 if (index.IsConstant()) {
4024 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Mark Mendell40741f32015-04-20 22:10:34 -04004025 if (value.IsRegister()) {
4026 __ movq(Address(obj, offset), value.AsRegister<CpuRegister>());
4027 } else {
4028 int64_t v = value.GetConstant()->AsLongConstant()->GetValue();
4029 DCHECK(IsInt<32>(v));
4030 int32_t v_32 = v;
4031 __ movq(Address(obj, offset), Immediate(v_32));
4032 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004033 } else {
Mark Mendell40741f32015-04-20 22:10:34 -04004034 if (value.IsRegister()) {
4035 __ movq(Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset),
4036 value.AsRegister<CpuRegister>());
4037 } else {
4038 int64_t v = value.GetConstant()->AsLongConstant()->GetValue();
4039 DCHECK(IsInt<32>(v));
4040 int32_t v_32 = v;
4041 __ movq(Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset),
4042 Immediate(v_32));
4043 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004044 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004045 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004046 break;
4047 }
4048
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004049 case Primitive::kPrimFloat: {
4050 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
4051 if (index.IsConstant()) {
4052 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4053 DCHECK(value.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004054 __ movss(Address(obj, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004055 } else {
4056 DCHECK(value.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004057 __ movss(Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset),
4058 value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004059 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004060 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004061 break;
4062 }
4063
4064 case Primitive::kPrimDouble: {
4065 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
4066 if (index.IsConstant()) {
4067 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
4068 DCHECK(value.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004069 __ movsd(Address(obj, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004070 } else {
4071 DCHECK(value.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004072 __ movsd(Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset),
4073 value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004074 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004075 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004076 break;
4077 }
4078
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004079 case Primitive::kPrimVoid:
4080 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07004081 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004082 }
4083}
4084
4085void LocationsBuilderX86_64::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004086 LocationSummary* locations =
4087 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01004088 locations->SetInAt(0, Location::RequiresRegister());
4089 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004090}
4091
4092void InstructionCodeGeneratorX86_64::VisitArrayLength(HArrayLength* instruction) {
4093 LocationSummary* locations = instruction->GetLocations();
4094 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004095 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
4096 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004097 __ movl(out, Address(obj, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00004098 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004099}
4100
4101void LocationsBuilderX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004102 LocationSummary* locations =
4103 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Mark Mendellf60c90b2015-03-04 15:12:59 -05004104 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
Mark Mendell99dbd682015-04-22 16:18:52 -04004105 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004106 if (instruction->HasUses()) {
4107 locations->SetOut(Location::SameAsFirstInput());
4108 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004109}
4110
4111void InstructionCodeGeneratorX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
4112 LocationSummary* locations = instruction->GetLocations();
Mark Mendellf60c90b2015-03-04 15:12:59 -05004113 Location index_loc = locations->InAt(0);
4114 Location length_loc = locations->InAt(1);
4115 SlowPathCodeX86_64* slow_path =
4116 new (GetGraph()->GetArena()) BoundsCheckSlowPathX86_64(instruction, index_loc, length_loc);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004117
Mark Mendell99dbd682015-04-22 16:18:52 -04004118 if (length_loc.IsConstant()) {
4119 int32_t length = CodeGenerator::GetInt32ValueOf(length_loc.GetConstant());
4120 if (index_loc.IsConstant()) {
4121 // BCE will remove the bounds check if we are guarenteed to pass.
4122 int32_t index = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
4123 if (index < 0 || index >= length) {
4124 codegen_->AddSlowPath(slow_path);
4125 __ jmp(slow_path->GetEntryLabel());
4126 } else {
4127 // Some optimization after BCE may have generated this, and we should not
4128 // generate a bounds check if it is a valid range.
4129 }
4130 return;
4131 }
4132
4133 // We have to reverse the jump condition because the length is the constant.
4134 CpuRegister index_reg = index_loc.AsRegister<CpuRegister>();
4135 __ cmpl(index_reg, Immediate(length));
4136 codegen_->AddSlowPath(slow_path);
4137 __ j(kAboveEqual, slow_path->GetEntryLabel());
Mark Mendellf60c90b2015-03-04 15:12:59 -05004138 } else {
Mark Mendell99dbd682015-04-22 16:18:52 -04004139 CpuRegister length = length_loc.AsRegister<CpuRegister>();
4140 if (index_loc.IsConstant()) {
4141 int32_t value = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
4142 __ cmpl(length, Immediate(value));
4143 } else {
4144 __ cmpl(length, index_loc.AsRegister<CpuRegister>());
4145 }
4146 codegen_->AddSlowPath(slow_path);
4147 __ j(kBelowEqual, slow_path->GetEntryLabel());
Mark Mendellf60c90b2015-03-04 15:12:59 -05004148 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004149}
4150
4151void CodeGeneratorX86_64::MarkGCCard(CpuRegister temp,
4152 CpuRegister card,
4153 CpuRegister object,
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004154 CpuRegister value,
4155 bool value_can_be_null) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004156 Label is_null;
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004157 if (value_can_be_null) {
4158 __ testl(value, value);
4159 __ j(kEqual, &is_null);
4160 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004161 __ gs()->movq(card, Address::Absolute(
4162 Thread::CardTableOffset<kX86_64WordSize>().Int32Value(), true));
4163 __ movq(temp, object);
4164 __ shrq(temp, Immediate(gc::accounting::CardTable::kCardShift));
Roland Levillain4d027112015-07-01 15:41:14 +01004165 __ movb(Address(temp, card, TIMES_1, 0), card);
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004166 if (value_can_be_null) {
4167 __ Bind(&is_null);
4168 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004169}
4170
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004171void LocationsBuilderX86_64::VisitTemporary(HTemporary* temp) {
4172 temp->SetLocations(nullptr);
4173}
4174
4175void InstructionCodeGeneratorX86_64::VisitTemporary(HTemporary* temp) {
4176 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07004177 UNUSED(temp);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004178}
4179
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004180void LocationsBuilderX86_64::VisitParallelMove(HParallelMove* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07004181 UNUSED(instruction);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004182 LOG(FATAL) << "Unimplemented";
4183}
4184
4185void InstructionCodeGeneratorX86_64::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004186 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
4187}
4188
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004189void LocationsBuilderX86_64::VisitSuspendCheck(HSuspendCheck* instruction) {
4190 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
4191}
4192
4193void InstructionCodeGeneratorX86_64::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004194 HBasicBlock* block = instruction->GetBlock();
4195 if (block->GetLoopInformation() != nullptr) {
4196 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
4197 // The back edge will generate the suspend check.
4198 return;
4199 }
4200 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
4201 // The goto will generate the suspend check.
4202 return;
4203 }
4204 GenerateSuspendCheck(instruction, nullptr);
4205}
4206
4207void InstructionCodeGeneratorX86_64::GenerateSuspendCheck(HSuspendCheck* instruction,
4208 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004209 SuspendCheckSlowPathX86_64* slow_path =
Nicolas Geoffraydb216f42015-05-05 17:02:20 +01004210 down_cast<SuspendCheckSlowPathX86_64*>(instruction->GetSlowPath());
4211 if (slow_path == nullptr) {
4212 slow_path = new (GetGraph()->GetArena()) SuspendCheckSlowPathX86_64(instruction, successor);
4213 instruction->SetSlowPath(slow_path);
4214 codegen_->AddSlowPath(slow_path);
4215 if (successor != nullptr) {
4216 DCHECK(successor->IsLoopHeader());
4217 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(instruction);
4218 }
4219 } else {
4220 DCHECK_EQ(slow_path->GetSuccessor(), successor);
4221 }
4222
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004223 __ gs()->cmpw(Address::Absolute(
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004224 Thread::ThreadFlagsOffset<kX86_64WordSize>().Int32Value(), true), Immediate(0));
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004225 if (successor == nullptr) {
4226 __ j(kNotEqual, slow_path->GetEntryLabel());
4227 __ Bind(slow_path->GetReturnLabel());
4228 } else {
4229 __ j(kEqual, codegen_->GetLabelOf(successor));
4230 __ jmp(slow_path->GetEntryLabel());
4231 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004232}
4233
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004234X86_64Assembler* ParallelMoveResolverX86_64::GetAssembler() const {
4235 return codegen_->GetAssembler();
4236}
4237
4238void ParallelMoveResolverX86_64::EmitMove(size_t index) {
4239 MoveOperands* move = moves_.Get(index);
4240 Location source = move->GetSource();
4241 Location destination = move->GetDestination();
4242
4243 if (source.IsRegister()) {
4244 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004245 __ movq(destination.AsRegister<CpuRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004246 } else if (destination.IsStackSlot()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004247 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00004248 source.AsRegister<CpuRegister>());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004249 } else {
4250 DCHECK(destination.IsDoubleStackSlot());
4251 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00004252 source.AsRegister<CpuRegister>());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004253 }
4254 } else if (source.IsStackSlot()) {
4255 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004256 __ movl(destination.AsRegister<CpuRegister>(),
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004257 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004258 } else if (destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004259 __ movss(destination.AsFpuRegister<XmmRegister>(),
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004260 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004261 } else {
4262 DCHECK(destination.IsStackSlot());
4263 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
4264 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
4265 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004266 } else if (source.IsDoubleStackSlot()) {
4267 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004268 __ movq(destination.AsRegister<CpuRegister>(),
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004269 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004270 } else if (destination.IsFpuRegister()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004271 __ movsd(destination.AsFpuRegister<XmmRegister>(),
4272 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004273 } else {
Nicolas Geoffrayc8147a72014-10-21 16:06:20 +01004274 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004275 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
4276 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
4277 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004278 } else if (source.IsConstant()) {
4279 HConstant* constant = source.GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00004280 if (constant->IsIntConstant() || constant->IsNullConstant()) {
4281 int32_t value = CodeGenerator::GetInt32ValueOf(constant);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004282 if (destination.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00004283 if (value == 0) {
4284 __ xorl(destination.AsRegister<CpuRegister>(), destination.AsRegister<CpuRegister>());
4285 } else {
4286 __ movl(destination.AsRegister<CpuRegister>(), Immediate(value));
4287 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004288 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004289 DCHECK(destination.IsStackSlot()) << destination;
Nicolas Geoffray748f1402015-01-27 08:17:54 +00004290 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), Immediate(value));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004291 }
4292 } else if (constant->IsLongConstant()) {
4293 int64_t value = constant->AsLongConstant()->GetValue();
4294 if (destination.IsRegister()) {
Mark Mendell92e83bf2015-05-07 11:25:03 -04004295 codegen_->Load64BitValue(destination.AsRegister<CpuRegister>(), value);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004296 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004297 DCHECK(destination.IsDoubleStackSlot()) << destination;
Mark Mendell92e83bf2015-05-07 11:25:03 -04004298 codegen_->Load64BitValue(CpuRegister(TMP), value);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004299 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
4300 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004301 } else if (constant->IsFloatConstant()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004302 float fp_value = constant->AsFloatConstant()->GetValue();
Roland Levillainda4d79b2015-03-24 14:36:11 +00004303 int32_t value = bit_cast<int32_t, float>(fp_value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004304 if (destination.IsFpuRegister()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004305 XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
4306 if (value == 0) {
4307 // easy FP 0.0.
4308 __ xorps(dest, dest);
4309 } else {
Mark Mendell92e83bf2015-05-07 11:25:03 -04004310 __ movss(dest, codegen_->LiteralFloatAddress(fp_value));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004311 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004312 } else {
4313 DCHECK(destination.IsStackSlot()) << destination;
Mark Mendell92e83bf2015-05-07 11:25:03 -04004314 Immediate imm(value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004315 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), imm);
4316 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004317 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004318 DCHECK(constant->IsDoubleConstant()) << constant->DebugName();
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004319 double fp_value = constant->AsDoubleConstant()->GetValue();
Roland Levillainda4d79b2015-03-24 14:36:11 +00004320 int64_t value = bit_cast<int64_t, double>(fp_value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004321 if (destination.IsFpuRegister()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004322 XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
4323 if (value == 0) {
4324 __ xorpd(dest, dest);
4325 } else {
Mark Mendell92e83bf2015-05-07 11:25:03 -04004326 __ movsd(dest, codegen_->LiteralDoubleAddress(fp_value));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004327 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004328 } else {
4329 DCHECK(destination.IsDoubleStackSlot()) << destination;
Mark Mendell92e83bf2015-05-07 11:25:03 -04004330 codegen_->Load64BitValue(CpuRegister(TMP), value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004331 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
4332 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004333 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004334 } else if (source.IsFpuRegister()) {
4335 if (destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004336 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004337 } else if (destination.IsStackSlot()) {
4338 __ movss(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00004339 source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004340 } else {
Nicolas Geoffray31596742014-11-24 15:28:45 +00004341 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004342 __ movsd(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00004343 source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004344 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004345 }
4346}
4347
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004348void ParallelMoveResolverX86_64::Exchange32(CpuRegister reg, int mem) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004349 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004350 __ movl(Address(CpuRegister(RSP), mem), reg);
4351 __ movl(reg, CpuRegister(TMP));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004352}
4353
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004354void ParallelMoveResolverX86_64::Exchange32(int mem1, int mem2) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004355 ScratchRegisterScope ensure_scratch(
4356 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
4357
4358 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
4359 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
4360 __ movl(CpuRegister(ensure_scratch.GetRegister()),
4361 Address(CpuRegister(RSP), mem2 + stack_offset));
4362 __ movl(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
4363 __ movl(Address(CpuRegister(RSP), mem1 + stack_offset),
4364 CpuRegister(ensure_scratch.GetRegister()));
4365}
4366
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004367void ParallelMoveResolverX86_64::Exchange64(CpuRegister reg, int mem) {
4368 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
4369 __ movq(Address(CpuRegister(RSP), mem), reg);
4370 __ movq(reg, CpuRegister(TMP));
4371}
4372
4373void ParallelMoveResolverX86_64::Exchange64(int mem1, int mem2) {
4374 ScratchRegisterScope ensure_scratch(
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004375 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004376
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004377 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
4378 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
4379 __ movq(CpuRegister(ensure_scratch.GetRegister()),
4380 Address(CpuRegister(RSP), mem2 + stack_offset));
4381 __ movq(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
4382 __ movq(Address(CpuRegister(RSP), mem1 + stack_offset),
4383 CpuRegister(ensure_scratch.GetRegister()));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004384}
4385
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004386void ParallelMoveResolverX86_64::Exchange32(XmmRegister reg, int mem) {
4387 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
4388 __ movss(Address(CpuRegister(RSP), mem), reg);
4389 __ movd(reg, CpuRegister(TMP));
4390}
4391
4392void ParallelMoveResolverX86_64::Exchange64(XmmRegister reg, int mem) {
4393 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
4394 __ movsd(Address(CpuRegister(RSP), mem), reg);
4395 __ movd(reg, CpuRegister(TMP));
4396}
4397
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004398void ParallelMoveResolverX86_64::EmitSwap(size_t index) {
4399 MoveOperands* move = moves_.Get(index);
4400 Location source = move->GetSource();
4401 Location destination = move->GetDestination();
4402
4403 if (source.IsRegister() && destination.IsRegister()) {
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004404 __ xchgq(destination.AsRegister<CpuRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004405 } else if (source.IsRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004406 Exchange32(source.AsRegister<CpuRegister>(), destination.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004407 } else if (source.IsStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004408 Exchange32(destination.AsRegister<CpuRegister>(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004409 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004410 Exchange32(destination.GetStackIndex(), source.GetStackIndex());
4411 } else if (source.IsRegister() && destination.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004412 Exchange64(source.AsRegister<CpuRegister>(), destination.GetStackIndex());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004413 } else if (source.IsDoubleStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004414 Exchange64(destination.AsRegister<CpuRegister>(), source.GetStackIndex());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004415 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
4416 Exchange64(destination.GetStackIndex(), source.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004417 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004418 __ movd(CpuRegister(TMP), source.AsFpuRegister<XmmRegister>());
4419 __ movaps(source.AsFpuRegister<XmmRegister>(), destination.AsFpuRegister<XmmRegister>());
4420 __ movd(destination.AsFpuRegister<XmmRegister>(), CpuRegister(TMP));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004421 } else if (source.IsFpuRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004422 Exchange32(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004423 } else if (source.IsStackSlot() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004424 Exchange32(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004425 } else if (source.IsFpuRegister() && destination.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004426 Exchange64(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004427 } else if (source.IsDoubleStackSlot() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004428 Exchange64(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004429 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004430 LOG(FATAL) << "Unimplemented swap between " << source << " and " << destination;
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004431 }
4432}
4433
4434
4435void ParallelMoveResolverX86_64::SpillScratch(int reg) {
4436 __ pushq(CpuRegister(reg));
4437}
4438
4439
4440void ParallelMoveResolverX86_64::RestoreScratch(int reg) {
4441 __ popq(CpuRegister(reg));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004442}
4443
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004444void InstructionCodeGeneratorX86_64::GenerateClassInitializationCheck(
4445 SlowPathCodeX86_64* slow_path, CpuRegister class_reg) {
4446 __ cmpl(Address(class_reg, mirror::Class::StatusOffset().Int32Value()),
4447 Immediate(mirror::Class::kStatusInitialized));
4448 __ j(kLess, slow_path->GetEntryLabel());
4449 __ Bind(slow_path->GetExitLabel());
4450 // No need for memory fence, thanks to the X86_64 memory model.
4451}
4452
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004453void LocationsBuilderX86_64::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004454 LocationSummary::CallKind call_kind = cls->CanCallRuntime()
4455 ? LocationSummary::kCallOnSlowPath
4456 : LocationSummary::kNoCall;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004457 LocationSummary* locations =
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004458 new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004459 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004460 locations->SetOut(Location::RequiresRegister());
4461}
4462
4463void InstructionCodeGeneratorX86_64::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004464 LocationSummary* locations = cls->GetLocations();
4465 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
4466 CpuRegister current_method = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004467 if (cls->IsReferrersClass()) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004468 DCHECK(!cls->CanCallRuntime());
4469 DCHECK(!cls->MustGenerateClinitCheck());
Mathieu Chartiere401d142015-04-22 13:56:20 -07004470 __ movl(out, Address(current_method, ArtMethod::DeclaringClassOffset().Int32Value()));
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004471 } else {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004472 DCHECK(cls->CanCallRuntime());
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004473 __ movl(out, Address(
Mathieu Chartiere401d142015-04-22 13:56:20 -07004474 current_method, ArtMethod::DexCacheResolvedTypesOffset().Int32Value()));
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004475 __ movl(out, Address(out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex())));
Roland Levillain4d027112015-07-01 15:41:14 +01004476 __ MaybeUnpoisonHeapReference(out);
4477
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004478 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86_64(
4479 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
4480 codegen_->AddSlowPath(slow_path);
4481 __ testl(out, out);
4482 __ j(kEqual, slow_path->GetEntryLabel());
4483 if (cls->MustGenerateClinitCheck()) {
4484 GenerateClassInitializationCheck(slow_path, out);
4485 } else {
4486 __ Bind(slow_path->GetExitLabel());
4487 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004488 }
4489}
4490
4491void LocationsBuilderX86_64::VisitClinitCheck(HClinitCheck* check) {
4492 LocationSummary* locations =
4493 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
4494 locations->SetInAt(0, Location::RequiresRegister());
4495 if (check->HasUses()) {
4496 locations->SetOut(Location::SameAsFirstInput());
4497 }
4498}
4499
4500void InstructionCodeGeneratorX86_64::VisitClinitCheck(HClinitCheck* check) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004501 // We assume the class to not be null.
4502 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86_64(
4503 check->GetLoadClass(), check, check->GetDexPc(), true);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004504 codegen_->AddSlowPath(slow_path);
Roland Levillain199f3362014-11-27 17:15:16 +00004505 GenerateClassInitializationCheck(slow_path,
4506 check->GetLocations()->InAt(0).AsRegister<CpuRegister>());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004507}
4508
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004509void LocationsBuilderX86_64::VisitLoadString(HLoadString* load) {
4510 LocationSummary* locations =
4511 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01004512 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004513 locations->SetOut(Location::RequiresRegister());
4514}
4515
4516void InstructionCodeGeneratorX86_64::VisitLoadString(HLoadString* load) {
4517 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathX86_64(load);
4518 codegen_->AddSlowPath(slow_path);
4519
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01004520 LocationSummary* locations = load->GetLocations();
4521 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
4522 CpuRegister current_method = locations->InAt(0).AsRegister<CpuRegister>();
Mathieu Chartiere401d142015-04-22 13:56:20 -07004523 __ movl(out, Address(current_method, ArtMethod::DeclaringClassOffset().Int32Value()));
Mathieu Chartiereace4582014-11-24 18:29:54 -08004524 __ movl(out, Address(out, mirror::Class::DexCacheStringsOffset().Int32Value()));
Roland Levillain4d027112015-07-01 15:41:14 +01004525 __ MaybeUnpoisonHeapReference(out);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004526 __ movl(out, Address(out, CodeGenerator::GetCacheOffset(load->GetStringIndex())));
Roland Levillain4d027112015-07-01 15:41:14 +01004527 __ MaybeUnpoisonHeapReference(out);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004528 __ testl(out, out);
4529 __ j(kEqual, slow_path->GetEntryLabel());
4530 __ Bind(slow_path->GetExitLabel());
4531}
4532
David Brazdilcb1c0552015-08-04 16:22:25 +01004533static Address GetExceptionTlsAddress() {
4534 return Address::Absolute(Thread::ExceptionOffset<kX86_64WordSize>().Int32Value(), true);
4535}
4536
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004537void LocationsBuilderX86_64::VisitLoadException(HLoadException* load) {
4538 LocationSummary* locations =
4539 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
4540 locations->SetOut(Location::RequiresRegister());
4541}
4542
4543void InstructionCodeGeneratorX86_64::VisitLoadException(HLoadException* load) {
David Brazdilcb1c0552015-08-04 16:22:25 +01004544 __ gs()->movl(load->GetLocations()->Out().AsRegister<CpuRegister>(), GetExceptionTlsAddress());
4545}
4546
4547void LocationsBuilderX86_64::VisitClearException(HClearException* clear) {
4548 new (GetGraph()->GetArena()) LocationSummary(clear, LocationSummary::kNoCall);
4549}
4550
4551void InstructionCodeGeneratorX86_64::VisitClearException(HClearException* clear ATTRIBUTE_UNUSED) {
4552 __ gs()->movl(GetExceptionTlsAddress(), Immediate(0));
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004553}
4554
4555void LocationsBuilderX86_64::VisitThrow(HThrow* instruction) {
4556 LocationSummary* locations =
4557 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
4558 InvokeRuntimeCallingConvention calling_convention;
4559 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4560}
4561
4562void InstructionCodeGeneratorX86_64::VisitThrow(HThrow* instruction) {
4563 __ gs()->call(
4564 Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pDeliverException), true));
4565 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
4566}
4567
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004568void LocationsBuilderX86_64::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004569 LocationSummary::CallKind call_kind = instruction->IsClassFinal()
4570 ? LocationSummary::kNoCall
4571 : LocationSummary::kCallOnSlowPath;
4572 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
4573 locations->SetInAt(0, Location::RequiresRegister());
4574 locations->SetInAt(1, Location::Any());
4575 locations->SetOut(Location::RequiresRegister());
4576}
4577
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004578void InstructionCodeGeneratorX86_64::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004579 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004580 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004581 Location cls = locations->InAt(1);
Roland Levillain271ab9c2014-11-27 15:23:57 +00004582 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004583 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
4584 Label done, zero;
4585 SlowPathCodeX86_64* slow_path = nullptr;
4586
4587 // Return 0 if `obj` is null.
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004588 // Avoid null check if we know obj is not null.
4589 if (instruction->MustDoNullCheck()) {
4590 __ testl(obj, obj);
4591 __ j(kEqual, &zero);
4592 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004593 // Compare the class of `obj` with `cls`.
4594 __ movl(out, Address(obj, class_offset));
Roland Levillain4d027112015-07-01 15:41:14 +01004595 __ MaybeUnpoisonHeapReference(out);
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004596 if (cls.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004597 __ cmpl(out, cls.AsRegister<CpuRegister>());
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004598 } else {
4599 DCHECK(cls.IsStackSlot()) << cls;
4600 __ cmpl(out, Address(CpuRegister(RSP), cls.GetStackIndex()));
4601 }
4602 if (instruction->IsClassFinal()) {
4603 // Classes must be equal for the instanceof to succeed.
4604 __ j(kNotEqual, &zero);
4605 __ movl(out, Immediate(1));
4606 __ jmp(&done);
4607 } else {
4608 // If the classes are not equal, we go into a slow path.
4609 DCHECK(locations->OnlyCallsOnSlowPath());
4610 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86_64(
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004611 instruction, locations->InAt(1), locations->Out(), instruction->GetDexPc());
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004612 codegen_->AddSlowPath(slow_path);
4613 __ j(kNotEqual, slow_path->GetEntryLabel());
4614 __ movl(out, Immediate(1));
4615 __ jmp(&done);
4616 }
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004617
4618 if (instruction->MustDoNullCheck() || instruction->IsClassFinal()) {
4619 __ Bind(&zero);
4620 __ movl(out, Immediate(0));
4621 }
4622
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004623 if (slow_path != nullptr) {
4624 __ Bind(slow_path->GetExitLabel());
4625 }
4626 __ Bind(&done);
4627}
4628
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004629void LocationsBuilderX86_64::VisitCheckCast(HCheckCast* instruction) {
4630 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
4631 instruction, LocationSummary::kCallOnSlowPath);
4632 locations->SetInAt(0, Location::RequiresRegister());
4633 locations->SetInAt(1, Location::Any());
4634 locations->AddTemp(Location::RequiresRegister());
4635}
4636
4637void InstructionCodeGeneratorX86_64::VisitCheckCast(HCheckCast* instruction) {
4638 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004639 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004640 Location cls = locations->InAt(1);
Roland Levillain271ab9c2014-11-27 15:23:57 +00004641 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004642 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
4643 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86_64(
4644 instruction, locations->InAt(1), locations->GetTemp(0), instruction->GetDexPc());
4645 codegen_->AddSlowPath(slow_path);
4646
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004647 // Avoid null check if we know obj is not null.
4648 if (instruction->MustDoNullCheck()) {
4649 __ testl(obj, obj);
4650 __ j(kEqual, slow_path->GetExitLabel());
4651 }
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004652 // Compare the class of `obj` with `cls`.
4653 __ movl(temp, Address(obj, class_offset));
Roland Levillain4d027112015-07-01 15:41:14 +01004654 __ MaybeUnpoisonHeapReference(temp);
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004655 if (cls.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004656 __ cmpl(temp, cls.AsRegister<CpuRegister>());
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004657 } else {
4658 DCHECK(cls.IsStackSlot()) << cls;
4659 __ cmpl(temp, Address(CpuRegister(RSP), cls.GetStackIndex()));
4660 }
Roland Levillain4d027112015-07-01 15:41:14 +01004661 // The checkcast succeeds if the classes are equal (fast path).
4662 // Otherwise, we need to go into the slow path to check the types.
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004663 __ j(kNotEqual, slow_path->GetEntryLabel());
4664 __ Bind(slow_path->GetExitLabel());
4665}
4666
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00004667void LocationsBuilderX86_64::VisitMonitorOperation(HMonitorOperation* instruction) {
4668 LocationSummary* locations =
4669 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
4670 InvokeRuntimeCallingConvention calling_convention;
4671 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4672}
4673
4674void InstructionCodeGeneratorX86_64::VisitMonitorOperation(HMonitorOperation* instruction) {
4675 __ gs()->call(Address::Absolute(instruction->IsEnter()
4676 ? QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pLockObject)
4677 : QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pUnlockObject),
4678 true));
4679 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
4680}
4681
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004682void LocationsBuilderX86_64::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); }
4683void LocationsBuilderX86_64::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); }
4684void LocationsBuilderX86_64::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); }
4685
4686void LocationsBuilderX86_64::HandleBitwiseOperation(HBinaryOperation* instruction) {
4687 LocationSummary* locations =
4688 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
4689 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
4690 || instruction->GetResultType() == Primitive::kPrimLong);
4691 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell40741f32015-04-20 22:10:34 -04004692 locations->SetInAt(1, Location::Any());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004693 locations->SetOut(Location::SameAsFirstInput());
4694}
4695
4696void InstructionCodeGeneratorX86_64::VisitAnd(HAnd* instruction) {
4697 HandleBitwiseOperation(instruction);
4698}
4699
4700void InstructionCodeGeneratorX86_64::VisitOr(HOr* instruction) {
4701 HandleBitwiseOperation(instruction);
4702}
4703
4704void InstructionCodeGeneratorX86_64::VisitXor(HXor* instruction) {
4705 HandleBitwiseOperation(instruction);
4706}
4707
4708void InstructionCodeGeneratorX86_64::HandleBitwiseOperation(HBinaryOperation* instruction) {
4709 LocationSummary* locations = instruction->GetLocations();
4710 Location first = locations->InAt(0);
4711 Location second = locations->InAt(1);
4712 DCHECK(first.Equals(locations->Out()));
4713
4714 if (instruction->GetResultType() == Primitive::kPrimInt) {
4715 if (second.IsRegister()) {
4716 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004717 __ andl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004718 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004719 __ orl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004720 } else {
4721 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004722 __ xorl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004723 }
4724 } else if (second.IsConstant()) {
4725 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
4726 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004727 __ andl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004728 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004729 __ orl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004730 } else {
4731 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004732 __ xorl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004733 }
4734 } else {
4735 Address address(CpuRegister(RSP), second.GetStackIndex());
4736 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004737 __ andl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004738 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004739 __ orl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004740 } else {
4741 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004742 __ xorl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004743 }
4744 }
4745 } else {
4746 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004747 CpuRegister first_reg = first.AsRegister<CpuRegister>();
4748 bool second_is_constant = false;
4749 int64_t value = 0;
4750 if (second.IsConstant()) {
4751 second_is_constant = true;
4752 value = second.GetConstant()->AsLongConstant()->GetValue();
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004753 }
Mark Mendell40741f32015-04-20 22:10:34 -04004754 bool is_int32_value = IsInt<32>(value);
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004755
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004756 if (instruction->IsAnd()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004757 if (second_is_constant) {
Mark Mendell40741f32015-04-20 22:10:34 -04004758 if (is_int32_value) {
4759 __ andq(first_reg, Immediate(static_cast<int32_t>(value)));
4760 } else {
4761 __ andq(first_reg, codegen_->LiteralInt64Address(value));
4762 }
4763 } else if (second.IsDoubleStackSlot()) {
4764 __ andq(first_reg, Address(CpuRegister(RSP), second.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004765 } else {
4766 __ andq(first_reg, second.AsRegister<CpuRegister>());
4767 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004768 } else if (instruction->IsOr()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004769 if (second_is_constant) {
Mark Mendell40741f32015-04-20 22:10:34 -04004770 if (is_int32_value) {
4771 __ orq(first_reg, Immediate(static_cast<int32_t>(value)));
4772 } else {
4773 __ orq(first_reg, codegen_->LiteralInt64Address(value));
4774 }
4775 } else if (second.IsDoubleStackSlot()) {
4776 __ orq(first_reg, Address(CpuRegister(RSP), second.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004777 } else {
4778 __ orq(first_reg, second.AsRegister<CpuRegister>());
4779 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004780 } else {
4781 DCHECK(instruction->IsXor());
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004782 if (second_is_constant) {
Mark Mendell40741f32015-04-20 22:10:34 -04004783 if (is_int32_value) {
4784 __ xorq(first_reg, Immediate(static_cast<int32_t>(value)));
4785 } else {
4786 __ xorq(first_reg, codegen_->LiteralInt64Address(value));
4787 }
4788 } else if (second.IsDoubleStackSlot()) {
4789 __ xorq(first_reg, Address(CpuRegister(RSP), second.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004790 } else {
4791 __ xorq(first_reg, second.AsRegister<CpuRegister>());
4792 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004793 }
4794 }
4795}
4796
Calin Juravleb1498f62015-02-16 13:13:29 +00004797void LocationsBuilderX86_64::VisitBoundType(HBoundType* instruction) {
4798 // Nothing to do, this should be removed during prepare for register allocator.
4799 UNUSED(instruction);
4800 LOG(FATAL) << "Unreachable";
4801}
4802
4803void InstructionCodeGeneratorX86_64::VisitBoundType(HBoundType* instruction) {
4804 // Nothing to do, this should be removed during prepare for register allocator.
4805 UNUSED(instruction);
4806 LOG(FATAL) << "Unreachable";
4807}
4808
Nicolas Geoffray2e7cd752015-07-10 11:38:52 +01004809void LocationsBuilderX86_64::VisitFakeString(HFakeString* instruction) {
4810 DCHECK(codegen_->IsBaseline());
4811 LocationSummary* locations =
4812 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
4813 locations->SetOut(Location::ConstantLocation(GetGraph()->GetNullConstant()));
4814}
4815
4816void InstructionCodeGeneratorX86_64::VisitFakeString(HFakeString* instruction ATTRIBUTE_UNUSED) {
4817 DCHECK(codegen_->IsBaseline());
4818 // Will be generated at use site.
4819}
4820
Mark Mendell92e83bf2015-05-07 11:25:03 -04004821void CodeGeneratorX86_64::Load64BitValue(CpuRegister dest, int64_t value) {
4822 if (value == 0) {
4823 __ xorl(dest, dest);
4824 } else if (value > 0 && IsInt<32>(value)) {
4825 // We can use a 32 bit move, as it will zero-extend and is one byte shorter.
4826 __ movl(dest, Immediate(static_cast<int32_t>(value)));
4827 } else {
4828 __ movq(dest, Immediate(value));
4829 }
4830}
4831
Mark Mendellf55c3e02015-03-26 21:07:46 -04004832void CodeGeneratorX86_64::Finalize(CodeAllocator* allocator) {
4833 // Generate the constant area if needed.
Mark Mendell39dcf552015-04-09 20:42:42 -04004834 X86_64Assembler* assembler = GetAssembler();
4835 if (!assembler->IsConstantAreaEmpty()) {
Mark Mendellf55c3e02015-03-26 21:07:46 -04004836 // Align to 4 byte boundary to reduce cache misses, as the data is 4 and 8
4837 // byte values. If used for vectors at a later time, this will need to be
4838 // updated to 16 bytes with the appropriate offset.
Mark Mendell39dcf552015-04-09 20:42:42 -04004839 assembler->Align(4, 0);
4840 constant_area_start_ = assembler->CodeSize();
4841 assembler->AddConstantArea();
Mark Mendellf55c3e02015-03-26 21:07:46 -04004842 }
4843
4844 // And finish up.
4845 CodeGenerator::Finalize(allocator);
4846}
4847
4848/**
4849 * Class to handle late fixup of offsets into constant area.
4850 */
4851class RIPFixup : public AssemblerFixup, public ArenaObject<kArenaAllocMisc> {
4852 public:
Mark Mendell39dcf552015-04-09 20:42:42 -04004853 RIPFixup(const CodeGeneratorX86_64& codegen, int offset)
Mark Mendellf55c3e02015-03-26 21:07:46 -04004854 : codegen_(codegen), offset_into_constant_area_(offset) {}
4855
4856 private:
4857 void Process(const MemoryRegion& region, int pos) OVERRIDE {
4858 // Patch the correct offset for the instruction. We use the address of the
4859 // 'next' instruction, which is 'pos' (patch the 4 bytes before).
4860 int constant_offset = codegen_.ConstantAreaStart() + offset_into_constant_area_;
4861 int relative_position = constant_offset - pos;
4862
4863 // Patch in the right value.
4864 region.StoreUnaligned<int32_t>(pos - 4, relative_position);
4865 }
4866
Mark Mendell39dcf552015-04-09 20:42:42 -04004867 const CodeGeneratorX86_64& codegen_;
Mark Mendellf55c3e02015-03-26 21:07:46 -04004868
4869 // Location in constant area that the fixup refers to.
4870 int offset_into_constant_area_;
4871};
4872
4873Address CodeGeneratorX86_64::LiteralDoubleAddress(double v) {
4874 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddDouble(v));
4875 return Address::RIP(fixup);
4876}
4877
4878Address CodeGeneratorX86_64::LiteralFloatAddress(float v) {
4879 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddFloat(v));
4880 return Address::RIP(fixup);
4881}
4882
4883Address CodeGeneratorX86_64::LiteralInt32Address(int32_t v) {
4884 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddInt32(v));
4885 return Address::RIP(fixup);
4886}
4887
4888Address CodeGeneratorX86_64::LiteralInt64Address(int64_t v) {
4889 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddInt64(v));
4890 return Address::RIP(fixup);
4891}
4892
Roland Levillain4d027112015-07-01 15:41:14 +01004893#undef __
4894
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004895} // namespace x86_64
4896} // namespace art