blob: 287737b4c80119882bc105f8e416ea9cec344a26 [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()) {
3144 case Primitive::kPrimInt: {
3145 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003146 __ testl(value.AsRegister<CpuRegister>(), value.AsRegister<CpuRegister>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003147 __ j(kEqual, slow_path->GetEntryLabel());
3148 } else if (value.IsStackSlot()) {
3149 __ cmpl(Address(CpuRegister(RSP), value.GetStackIndex()), Immediate(0));
3150 __ j(kEqual, slow_path->GetEntryLabel());
3151 } else {
3152 DCHECK(value.IsConstant()) << value;
3153 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
3154 __ jmp(slow_path->GetEntryLabel());
3155 }
3156 }
3157 break;
Calin Juravled0d48522014-11-04 16:40:20 +00003158 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003159 case Primitive::kPrimLong: {
3160 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003161 __ testq(value.AsRegister<CpuRegister>(), value.AsRegister<CpuRegister>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003162 __ j(kEqual, slow_path->GetEntryLabel());
3163 } else if (value.IsDoubleStackSlot()) {
3164 __ cmpq(Address(CpuRegister(RSP), value.GetStackIndex()), Immediate(0));
3165 __ j(kEqual, slow_path->GetEntryLabel());
3166 } else {
3167 DCHECK(value.IsConstant()) << value;
3168 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
3169 __ jmp(slow_path->GetEntryLabel());
3170 }
3171 }
3172 break;
3173 }
3174 default:
3175 LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
Calin Juravled0d48522014-11-04 16:40:20 +00003176 }
Calin Juravled0d48522014-11-04 16:40:20 +00003177}
3178
Calin Juravle9aec02f2014-11-18 23:06:35 +00003179void LocationsBuilderX86_64::HandleShift(HBinaryOperation* op) {
3180 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
3181
3182 LocationSummary* locations =
3183 new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
3184
3185 switch (op->GetResultType()) {
3186 case Primitive::kPrimInt:
3187 case Primitive::kPrimLong: {
3188 locations->SetInAt(0, Location::RequiresRegister());
3189 // The shift count needs to be in CL.
3190 locations->SetInAt(1, Location::ByteRegisterOrConstant(RCX, op->InputAt(1)));
3191 locations->SetOut(Location::SameAsFirstInput());
3192 break;
3193 }
3194 default:
3195 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
3196 }
3197}
3198
3199void InstructionCodeGeneratorX86_64::HandleShift(HBinaryOperation* op) {
3200 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
3201
3202 LocationSummary* locations = op->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003203 CpuRegister first_reg = locations->InAt(0).AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003204 Location second = locations->InAt(1);
3205
3206 switch (op->GetResultType()) {
3207 case Primitive::kPrimInt: {
3208 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003209 CpuRegister second_reg = second.AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003210 if (op->IsShl()) {
3211 __ shll(first_reg, second_reg);
3212 } else if (op->IsShr()) {
3213 __ sarl(first_reg, second_reg);
3214 } else {
3215 __ shrl(first_reg, second_reg);
3216 }
3217 } else {
Nicolas Geoffray486cc192014-12-08 18:00:55 +00003218 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxIntShiftValue);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003219 if (op->IsShl()) {
3220 __ shll(first_reg, imm);
3221 } else if (op->IsShr()) {
3222 __ sarl(first_reg, imm);
3223 } else {
3224 __ shrl(first_reg, imm);
3225 }
3226 }
3227 break;
3228 }
3229 case Primitive::kPrimLong: {
3230 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003231 CpuRegister second_reg = second.AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003232 if (op->IsShl()) {
3233 __ shlq(first_reg, second_reg);
3234 } else if (op->IsShr()) {
3235 __ sarq(first_reg, second_reg);
3236 } else {
3237 __ shrq(first_reg, second_reg);
3238 }
3239 } else {
Nicolas Geoffray486cc192014-12-08 18:00:55 +00003240 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxLongShiftValue);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003241 if (op->IsShl()) {
3242 __ shlq(first_reg, imm);
3243 } else if (op->IsShr()) {
3244 __ sarq(first_reg, imm);
3245 } else {
3246 __ shrq(first_reg, imm);
3247 }
3248 }
3249 break;
3250 }
3251 default:
3252 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
3253 }
3254}
3255
3256void LocationsBuilderX86_64::VisitShl(HShl* shl) {
3257 HandleShift(shl);
3258}
3259
3260void InstructionCodeGeneratorX86_64::VisitShl(HShl* shl) {
3261 HandleShift(shl);
3262}
3263
3264void LocationsBuilderX86_64::VisitShr(HShr* shr) {
3265 HandleShift(shr);
3266}
3267
3268void InstructionCodeGeneratorX86_64::VisitShr(HShr* shr) {
3269 HandleShift(shr);
3270}
3271
3272void LocationsBuilderX86_64::VisitUShr(HUShr* ushr) {
3273 HandleShift(ushr);
3274}
3275
3276void InstructionCodeGeneratorX86_64::VisitUShr(HUShr* ushr) {
3277 HandleShift(ushr);
3278}
3279
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003280void LocationsBuilderX86_64::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003281 LocationSummary* locations =
3282 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01003283 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003284 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Nicolas Geoffray69aa6012015-06-09 10:34:25 +01003285 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003286 locations->SetOut(Location::RegisterLocation(RAX));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003287}
3288
3289void InstructionCodeGeneratorX86_64::VisitNewInstance(HNewInstance* instruction) {
3290 InvokeRuntimeCallingConvention calling_convention;
Mark Mendell92e83bf2015-05-07 11:25:03 -04003291 codegen_->Load64BitValue(CpuRegister(calling_convention.GetRegisterAt(0)),
3292 instruction->GetTypeIndex());
Roland Levillain4d027112015-07-01 15:41:14 +01003293 // Note: if heap poisoning is enabled, the entry point takes cares
3294 // of poisoning the reference.
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +00003295 __ gs()->call(
3296 Address::Absolute(GetThreadOffset<kX86_64WordSize>(instruction->GetEntrypoint()), true));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003297
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01003298 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray39468442014-09-02 15:17:15 +01003299 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003300}
3301
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003302void LocationsBuilderX86_64::VisitNewArray(HNewArray* instruction) {
3303 LocationSummary* locations =
3304 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
3305 InvokeRuntimeCallingConvention calling_convention;
3306 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003307 locations->SetOut(Location::RegisterLocation(RAX));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08003308 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray69aa6012015-06-09 10:34:25 +01003309 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003310}
3311
3312void InstructionCodeGeneratorX86_64::VisitNewArray(HNewArray* instruction) {
3313 InvokeRuntimeCallingConvention calling_convention;
Mark Mendell92e83bf2015-05-07 11:25:03 -04003314 codegen_->Load64BitValue(CpuRegister(calling_convention.GetRegisterAt(0)),
3315 instruction->GetTypeIndex());
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003316
Roland Levillain4d027112015-07-01 15:41:14 +01003317 // Note: if heap poisoning is enabled, the entry point takes cares
3318 // of poisoning the reference.
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +00003319 __ gs()->call(
3320 Address::Absolute(GetThreadOffset<kX86_64WordSize>(instruction->GetEntrypoint()), true));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003321
3322 DCHECK(!codegen_->IsLeafMethod());
3323 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3324}
3325
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003326void LocationsBuilderX86_64::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003327 LocationSummary* locations =
3328 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003329 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
3330 if (location.IsStackSlot()) {
3331 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
3332 } else if (location.IsDoubleStackSlot()) {
3333 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
3334 }
3335 locations->SetOut(location);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003336}
3337
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01003338void InstructionCodeGeneratorX86_64::VisitParameterValue(
3339 HParameterValue* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003340 // Nothing to do, the parameter is already at its location.
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01003341}
3342
3343void LocationsBuilderX86_64::VisitCurrentMethod(HCurrentMethod* instruction) {
3344 LocationSummary* locations =
3345 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3346 locations->SetOut(Location::RegisterLocation(kMethodRegisterArgument));
3347}
3348
3349void InstructionCodeGeneratorX86_64::VisitCurrentMethod(
3350 HCurrentMethod* instruction ATTRIBUTE_UNUSED) {
3351 // Nothing to do, the method is already at its location.
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003352}
3353
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003354void LocationsBuilderX86_64::VisitNot(HNot* not_) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003355 LocationSummary* locations =
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003356 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003357 locations->SetInAt(0, Location::RequiresRegister());
3358 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003359}
3360
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003361void InstructionCodeGeneratorX86_64::VisitNot(HNot* not_) {
3362 LocationSummary* locations = not_->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003363 DCHECK_EQ(locations->InAt(0).AsRegister<CpuRegister>().AsRegister(),
3364 locations->Out().AsRegister<CpuRegister>().AsRegister());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003365 Location out = locations->Out();
Nicolas Geoffrayd8ef2e92015-02-24 16:02:06 +00003366 switch (not_->GetResultType()) {
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003367 case Primitive::kPrimInt:
Roland Levillain271ab9c2014-11-27 15:23:57 +00003368 __ notl(out.AsRegister<CpuRegister>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003369 break;
3370
3371 case Primitive::kPrimLong:
Roland Levillain271ab9c2014-11-27 15:23:57 +00003372 __ notq(out.AsRegister<CpuRegister>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003373 break;
3374
3375 default:
3376 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
3377 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003378}
3379
David Brazdil66d126e2015-04-03 16:02:44 +01003380void LocationsBuilderX86_64::VisitBooleanNot(HBooleanNot* bool_not) {
3381 LocationSummary* locations =
3382 new (GetGraph()->GetArena()) LocationSummary(bool_not, LocationSummary::kNoCall);
3383 locations->SetInAt(0, Location::RequiresRegister());
3384 locations->SetOut(Location::SameAsFirstInput());
3385}
3386
3387void InstructionCodeGeneratorX86_64::VisitBooleanNot(HBooleanNot* bool_not) {
David Brazdil66d126e2015-04-03 16:02:44 +01003388 LocationSummary* locations = bool_not->GetLocations();
3389 DCHECK_EQ(locations->InAt(0).AsRegister<CpuRegister>().AsRegister(),
3390 locations->Out().AsRegister<CpuRegister>().AsRegister());
3391 Location out = locations->Out();
3392 __ xorl(out.AsRegister<CpuRegister>(), Immediate(1));
3393}
3394
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003395void LocationsBuilderX86_64::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003396 LocationSummary* locations =
3397 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003398 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
3399 locations->SetInAt(i, Location::Any());
3400 }
3401 locations->SetOut(Location::Any());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003402}
3403
3404void InstructionCodeGeneratorX86_64::VisitPhi(HPhi* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003405 UNUSED(instruction);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003406 LOG(FATAL) << "Unimplemented";
3407}
3408
Calin Juravle52c48962014-12-16 17:02:57 +00003409void InstructionCodeGeneratorX86_64::GenerateMemoryBarrier(MemBarrierKind kind) {
3410 /*
3411 * According to the JSR-133 Cookbook, for x86 only StoreLoad/AnyAny barriers need memory fence.
3412 * All other barriers (LoadAny, AnyStore, StoreStore) are nops due to the x86 memory model.
3413 * For those cases, all we need to ensure is that there is a scheduling barrier in place.
3414 */
3415 switch (kind) {
3416 case MemBarrierKind::kAnyAny: {
3417 __ mfence();
3418 break;
3419 }
3420 case MemBarrierKind::kAnyStore:
3421 case MemBarrierKind::kLoadAny:
3422 case MemBarrierKind::kStoreStore: {
3423 // nop
3424 break;
3425 }
3426 default:
3427 LOG(FATAL) << "Unexpected memory barier " << kind;
3428 }
3429}
3430
3431void LocationsBuilderX86_64::HandleFieldGet(HInstruction* instruction) {
3432 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
3433
Nicolas Geoffray39468442014-09-02 15:17:15 +01003434 LocationSummary* locations =
3435 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Calin Juravle52c48962014-12-16 17:02:57 +00003436 locations->SetInAt(0, Location::RequiresRegister());
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003437 if (Primitive::IsFloatingPointType(instruction->GetType())) {
3438 locations->SetOut(Location::RequiresFpuRegister());
3439 } else {
3440 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3441 }
Calin Juravle52c48962014-12-16 17:02:57 +00003442}
3443
3444void InstructionCodeGeneratorX86_64::HandleFieldGet(HInstruction* instruction,
3445 const FieldInfo& field_info) {
3446 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
3447
3448 LocationSummary* locations = instruction->GetLocations();
3449 CpuRegister base = locations->InAt(0).AsRegister<CpuRegister>();
3450 Location out = locations->Out();
3451 bool is_volatile = field_info.IsVolatile();
3452 Primitive::Type field_type = field_info.GetFieldType();
3453 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
3454
3455 switch (field_type) {
3456 case Primitive::kPrimBoolean: {
3457 __ movzxb(out.AsRegister<CpuRegister>(), Address(base, offset));
3458 break;
3459 }
3460
3461 case Primitive::kPrimByte: {
3462 __ movsxb(out.AsRegister<CpuRegister>(), Address(base, offset));
3463 break;
3464 }
3465
3466 case Primitive::kPrimShort: {
3467 __ movsxw(out.AsRegister<CpuRegister>(), Address(base, offset));
3468 break;
3469 }
3470
3471 case Primitive::kPrimChar: {
3472 __ movzxw(out.AsRegister<CpuRegister>(), Address(base, offset));
3473 break;
3474 }
3475
3476 case Primitive::kPrimInt:
3477 case Primitive::kPrimNot: {
3478 __ movl(out.AsRegister<CpuRegister>(), Address(base, offset));
3479 break;
3480 }
3481
3482 case Primitive::kPrimLong: {
3483 __ movq(out.AsRegister<CpuRegister>(), Address(base, offset));
3484 break;
3485 }
3486
3487 case Primitive::kPrimFloat: {
3488 __ movss(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
3489 break;
3490 }
3491
3492 case Primitive::kPrimDouble: {
3493 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
3494 break;
3495 }
3496
3497 case Primitive::kPrimVoid:
3498 LOG(FATAL) << "Unreachable type " << field_type;
3499 UNREACHABLE();
3500 }
3501
Calin Juravle77520bc2015-01-12 18:45:46 +00003502 codegen_->MaybeRecordImplicitNullCheck(instruction);
3503
Calin Juravle52c48962014-12-16 17:02:57 +00003504 if (is_volatile) {
3505 GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
3506 }
Roland Levillain4d027112015-07-01 15:41:14 +01003507
3508 if (field_type == Primitive::kPrimNot) {
3509 __ MaybeUnpoisonHeapReference(out.AsRegister<CpuRegister>());
3510 }
Calin Juravle52c48962014-12-16 17:02:57 +00003511}
3512
3513void LocationsBuilderX86_64::HandleFieldSet(HInstruction* instruction,
3514 const FieldInfo& field_info) {
3515 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3516
3517 LocationSummary* locations =
3518 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Roland Levillain4d027112015-07-01 15:41:14 +01003519 Primitive::Type field_type = field_info.GetFieldType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003520 bool needs_write_barrier =
Roland Levillain4d027112015-07-01 15:41:14 +01003521 CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
Calin Juravle52c48962014-12-16 17:02:57 +00003522
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003523 locations->SetInAt(0, Location::RequiresRegister());
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003524 if (Primitive::IsFloatingPointType(instruction->InputAt(1)->GetType())) {
3525 locations->SetInAt(1, Location::RequiresFpuRegister());
3526 } else {
Mark Mendell40741f32015-04-20 22:10:34 -04003527 locations->SetInAt(1, Location::RegisterOrInt32LongConstant(instruction->InputAt(1)));
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003528 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003529 if (needs_write_barrier) {
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01003530 // Temporary registers for the write barrier.
Roland Levillain4d027112015-07-01 15:41:14 +01003531 locations->AddTemp(Location::RequiresRegister()); // Possibly used for reference poisoning too.
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003532 locations->AddTemp(Location::RequiresRegister());
Roland Levillain4d027112015-07-01 15:41:14 +01003533 } else if (kPoisonHeapReferences && field_type == Primitive::kPrimNot) {
3534 // Temporary register for the reference poisoning.
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003535 locations->AddTemp(Location::RequiresRegister());
3536 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003537}
3538
Calin Juravle52c48962014-12-16 17:02:57 +00003539void InstructionCodeGeneratorX86_64::HandleFieldSet(HInstruction* instruction,
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003540 const FieldInfo& field_info,
3541 bool value_can_be_null) {
Calin Juravle52c48962014-12-16 17:02:57 +00003542 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3543
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003544 LocationSummary* locations = instruction->GetLocations();
Calin Juravle52c48962014-12-16 17:02:57 +00003545 CpuRegister base = locations->InAt(0).AsRegister<CpuRegister>();
3546 Location value = locations->InAt(1);
3547 bool is_volatile = field_info.IsVolatile();
3548 Primitive::Type field_type = field_info.GetFieldType();
3549 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
3550
3551 if (is_volatile) {
3552 GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
3553 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003554
3555 switch (field_type) {
3556 case Primitive::kPrimBoolean:
3557 case Primitive::kPrimByte: {
Mark Mendell40741f32015-04-20 22:10:34 -04003558 if (value.IsConstant()) {
3559 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
3560 __ movb(Address(base, offset), Immediate(v));
3561 } else {
3562 __ movb(Address(base, offset), value.AsRegister<CpuRegister>());
3563 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003564 break;
3565 }
3566
3567 case Primitive::kPrimShort:
3568 case Primitive::kPrimChar: {
Mark Mendell40741f32015-04-20 22:10:34 -04003569 if (value.IsConstant()) {
3570 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
3571 __ movw(Address(base, offset), Immediate(v));
3572 } else {
3573 __ movw(Address(base, offset), value.AsRegister<CpuRegister>());
3574 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003575 break;
3576 }
3577
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003578 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003579 case Primitive::kPrimNot: {
Mark Mendell40741f32015-04-20 22:10:34 -04003580 if (value.IsConstant()) {
3581 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
Roland Levillain4d027112015-07-01 15:41:14 +01003582 // `field_type == Primitive::kPrimNot` implies `v == 0`.
3583 DCHECK((field_type != Primitive::kPrimNot) || (v == 0));
3584 // Note: if heap poisoning is enabled, no need to poison
3585 // (negate) `v` if it is a reference, as it would be null.
Roland Levillain06b66d02015-07-01 12:47:25 +01003586 __ movl(Address(base, offset), Immediate(v));
Mark Mendell40741f32015-04-20 22:10:34 -04003587 } else {
Roland Levillain4d027112015-07-01 15:41:14 +01003588 if (kPoisonHeapReferences && field_type == Primitive::kPrimNot) {
3589 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
3590 __ movl(temp, value.AsRegister<CpuRegister>());
3591 __ PoisonHeapReference(temp);
3592 __ movl(Address(base, offset), temp);
3593 } else {
3594 __ movl(Address(base, offset), value.AsRegister<CpuRegister>());
3595 }
Mark Mendell40741f32015-04-20 22:10:34 -04003596 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003597 break;
3598 }
3599
3600 case Primitive::kPrimLong: {
Mark Mendell40741f32015-04-20 22:10:34 -04003601 if (value.IsConstant()) {
3602 int64_t v = value.GetConstant()->AsLongConstant()->GetValue();
3603 DCHECK(IsInt<32>(v));
3604 int32_t v_32 = v;
3605 __ movq(Address(base, offset), Immediate(v_32));
3606 } else {
3607 __ movq(Address(base, offset), value.AsRegister<CpuRegister>());
3608 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003609 break;
3610 }
3611
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003612 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00003613 __ movss(Address(base, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003614 break;
3615 }
3616
3617 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00003618 __ movsd(Address(base, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003619 break;
3620 }
3621
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003622 case Primitive::kPrimVoid:
3623 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003624 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003625 }
Calin Juravle52c48962014-12-16 17:02:57 +00003626
Calin Juravle77520bc2015-01-12 18:45:46 +00003627 codegen_->MaybeRecordImplicitNullCheck(instruction);
3628
3629 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
3630 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
3631 CpuRegister card = locations->GetTemp(1).AsRegister<CpuRegister>();
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003632 codegen_->MarkGCCard(temp, card, base, value.AsRegister<CpuRegister>(), value_can_be_null);
Calin Juravle77520bc2015-01-12 18:45:46 +00003633 }
3634
Calin Juravle52c48962014-12-16 17:02:57 +00003635 if (is_volatile) {
3636 GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
3637 }
3638}
3639
3640void LocationsBuilderX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
3641 HandleFieldSet(instruction, instruction->GetFieldInfo());
3642}
3643
3644void InstructionCodeGeneratorX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003645 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003646}
3647
3648void LocationsBuilderX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Calin Juravle52c48962014-12-16 17:02:57 +00003649 HandleFieldGet(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003650}
3651
3652void InstructionCodeGeneratorX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Calin Juravle52c48962014-12-16 17:02:57 +00003653 HandleFieldGet(instruction, instruction->GetFieldInfo());
3654}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003655
Calin Juravle52c48962014-12-16 17:02:57 +00003656void LocationsBuilderX86_64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
3657 HandleFieldGet(instruction);
3658}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003659
Calin Juravle52c48962014-12-16 17:02:57 +00003660void InstructionCodeGeneratorX86_64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
3661 HandleFieldGet(instruction, instruction->GetFieldInfo());
3662}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003663
Calin Juravle52c48962014-12-16 17:02:57 +00003664void LocationsBuilderX86_64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
3665 HandleFieldSet(instruction, instruction->GetFieldInfo());
3666}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003667
Calin Juravle52c48962014-12-16 17:02:57 +00003668void InstructionCodeGeneratorX86_64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003669 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003670}
3671
3672void LocationsBuilderX86_64::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003673 LocationSummary* locations =
3674 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003675 Location loc = codegen_->GetCompilerOptions().GetImplicitNullChecks()
3676 ? Location::RequiresRegister()
3677 : Location::Any();
3678 locations->SetInAt(0, loc);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003679 if (instruction->HasUses()) {
3680 locations->SetOut(Location::SameAsFirstInput());
3681 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003682}
3683
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003684void InstructionCodeGeneratorX86_64::GenerateImplicitNullCheck(HNullCheck* instruction) {
Calin Juravle77520bc2015-01-12 18:45:46 +00003685 if (codegen_->CanMoveNullCheckToUser(instruction)) {
3686 return;
3687 }
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003688 LocationSummary* locations = instruction->GetLocations();
3689 Location obj = locations->InAt(0);
3690
3691 __ testl(CpuRegister(RAX), Address(obj.AsRegister<CpuRegister>(), 0));
3692 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3693}
3694
3695void InstructionCodeGeneratorX86_64::GenerateExplicitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +01003696 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathX86_64(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003697 codegen_->AddSlowPath(slow_path);
3698
3699 LocationSummary* locations = instruction->GetLocations();
3700 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003701
3702 if (obj.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00003703 __ testl(obj.AsRegister<CpuRegister>(), obj.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003704 } else if (obj.IsStackSlot()) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003705 __ cmpl(Address(CpuRegister(RSP), obj.GetStackIndex()), Immediate(0));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003706 } else {
3707 DCHECK(obj.IsConstant()) << obj;
3708 DCHECK_EQ(obj.GetConstant()->AsIntConstant()->GetValue(), 0);
3709 __ jmp(slow_path->GetEntryLabel());
3710 return;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003711 }
3712 __ j(kEqual, slow_path->GetEntryLabel());
3713}
3714
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003715void InstructionCodeGeneratorX86_64::VisitNullCheck(HNullCheck* instruction) {
3716 if (codegen_->GetCompilerOptions().GetImplicitNullChecks()) {
3717 GenerateImplicitNullCheck(instruction);
3718 } else {
3719 GenerateExplicitNullCheck(instruction);
3720 }
3721}
3722
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003723void LocationsBuilderX86_64::VisitArrayGet(HArrayGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003724 LocationSummary* locations =
3725 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003726 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell40741f32015-04-20 22:10:34 -04003727 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003728 if (Primitive::IsFloatingPointType(instruction->GetType())) {
3729 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
3730 } else {
3731 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3732 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003733}
3734
3735void InstructionCodeGeneratorX86_64::VisitArrayGet(HArrayGet* instruction) {
3736 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003737 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003738 Location index = locations->InAt(1);
Roland Levillain4d027112015-07-01 15:41:14 +01003739 Primitive::Type type = instruction->GetType();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003740
Roland Levillain4d027112015-07-01 15:41:14 +01003741 switch (type) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003742 case Primitive::kPrimBoolean: {
3743 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003744 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003745 if (index.IsConstant()) {
3746 __ movzxb(out, Address(obj,
3747 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
3748 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003749 __ movzxb(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003750 }
3751 break;
3752 }
3753
3754 case Primitive::kPrimByte: {
3755 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003756 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003757 if (index.IsConstant()) {
3758 __ movsxb(out, Address(obj,
3759 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
3760 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003761 __ movsxb(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003762 }
3763 break;
3764 }
3765
3766 case Primitive::kPrimShort: {
3767 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003768 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003769 if (index.IsConstant()) {
3770 __ movsxw(out, Address(obj,
3771 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
3772 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003773 __ movsxw(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003774 }
3775 break;
3776 }
3777
3778 case Primitive::kPrimChar: {
3779 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003780 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003781 if (index.IsConstant()) {
3782 __ movzxw(out, Address(obj,
3783 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
3784 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003785 __ movzxw(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003786 }
3787 break;
3788 }
3789
3790 case Primitive::kPrimInt:
3791 case Primitive::kPrimNot: {
Roland Levillain33d69032015-06-18 18:20:59 +01003792 static_assert(sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
3793 "art::mirror::HeapReference<mirror::Object> and int32_t have different sizes.");
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003794 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003795 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003796 if (index.IsConstant()) {
3797 __ movl(out, Address(obj,
3798 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
3799 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003800 __ movl(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003801 }
3802 break;
3803 }
3804
3805 case Primitive::kPrimLong: {
3806 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003807 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003808 if (index.IsConstant()) {
3809 __ movq(out, Address(obj,
3810 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
3811 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003812 __ movq(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003813 }
3814 break;
3815 }
3816
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003817 case Primitive::kPrimFloat: {
3818 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003819 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003820 if (index.IsConstant()) {
3821 __ movss(out, Address(obj,
3822 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
3823 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003824 __ movss(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003825 }
3826 break;
3827 }
3828
3829 case Primitive::kPrimDouble: {
3830 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003831 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003832 if (index.IsConstant()) {
3833 __ movsd(out, Address(obj,
3834 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
3835 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003836 __ movsd(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003837 }
3838 break;
3839 }
3840
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003841 case Primitive::kPrimVoid:
Roland Levillain4d027112015-07-01 15:41:14 +01003842 LOG(FATAL) << "Unreachable type " << type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003843 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003844 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003845 codegen_->MaybeRecordImplicitNullCheck(instruction);
Roland Levillain4d027112015-07-01 15:41:14 +01003846
3847 if (type == Primitive::kPrimNot) {
3848 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
3849 __ MaybeUnpoisonHeapReference(out);
3850 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003851}
3852
3853void LocationsBuilderX86_64::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003854 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003855
3856 bool needs_write_barrier =
3857 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
3858 bool needs_runtime_call = instruction->NeedsTypeCheck();
3859
Nicolas Geoffray39468442014-09-02 15:17:15 +01003860 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003861 instruction, needs_runtime_call ? LocationSummary::kCall : LocationSummary::kNoCall);
3862 if (needs_runtime_call) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003863 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003864 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3865 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
3866 locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003867 } else {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003868 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01003869 locations->SetInAt(
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003870 1, Location::RegisterOrConstant(instruction->InputAt(1)));
3871 locations->SetInAt(2, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003872 if (value_type == Primitive::kPrimLong) {
Mark Mendell40741f32015-04-20 22:10:34 -04003873 locations->SetInAt(2, Location::RegisterOrInt32LongConstant(instruction->InputAt(2)));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003874 } else if (value_type == Primitive::kPrimFloat || value_type == Primitive::kPrimDouble) {
3875 locations->SetInAt(2, Location::RequiresFpuRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003876 } else {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003877 locations->SetInAt(2, Location::RegisterOrConstant(instruction->InputAt(2)));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003878 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003879
3880 if (needs_write_barrier) {
3881 // Temporary registers for the write barrier.
Roland Levillain4d027112015-07-01 15:41:14 +01003882 locations->AddTemp(Location::RequiresRegister()); // Possibly used for ref. poisoning too.
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003883 locations->AddTemp(Location::RequiresRegister());
3884 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003885 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003886}
3887
3888void InstructionCodeGeneratorX86_64::VisitArraySet(HArraySet* instruction) {
3889 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003890 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003891 Location index = locations->InAt(1);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003892 Location value = locations->InAt(2);
Nicolas Geoffray39468442014-09-02 15:17:15 +01003893 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003894 bool needs_runtime_call = locations->WillCall();
3895 bool needs_write_barrier =
3896 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003897
3898 switch (value_type) {
3899 case Primitive::kPrimBoolean:
3900 case Primitive::kPrimByte: {
3901 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003902 if (index.IsConstant()) {
3903 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003904 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003905 __ movb(Address(obj, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003906 } else {
Roland Levillain199f3362014-11-27 17:15:16 +00003907 __ movb(Address(obj, offset),
3908 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003909 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003910 } else {
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003911 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003912 __ movb(Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset),
3913 value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003914 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003915 __ movb(Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003916 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3917 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003918 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003919 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003920 break;
3921 }
3922
3923 case Primitive::kPrimShort:
3924 case Primitive::kPrimChar: {
3925 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003926 if (index.IsConstant()) {
3927 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003928 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003929 __ movw(Address(obj, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003930 } else {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003931 DCHECK(value.IsConstant()) << value;
Roland Levillain199f3362014-11-27 17:15:16 +00003932 __ movw(Address(obj, offset),
3933 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003934 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003935 } else {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003936 DCHECK(index.IsRegister()) << index;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003937 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003938 __ movw(Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset),
3939 value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003940 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003941 DCHECK(value.IsConstant()) << value;
Roland Levillain271ab9c2014-11-27 15:23:57 +00003942 __ movw(Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003943 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3944 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003945 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003946 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003947 break;
3948 }
3949
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003950 case Primitive::kPrimInt:
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003951 case Primitive::kPrimNot: {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003952 if (!needs_runtime_call) {
3953 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
3954 if (index.IsConstant()) {
3955 size_t offset =
3956 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
3957 if (value.IsRegister()) {
Roland Levillain4d027112015-07-01 15:41:14 +01003958 if (kPoisonHeapReferences && value_type == Primitive::kPrimNot) {
3959 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
3960 __ movl(temp, value.AsRegister<CpuRegister>());
3961 __ PoisonHeapReference(temp);
3962 __ movl(Address(obj, offset), temp);
3963 } else {
3964 __ movl(Address(obj, offset), value.AsRegister<CpuRegister>());
3965 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003966 } else {
3967 DCHECK(value.IsConstant()) << value;
Mark Mendell40741f32015-04-20 22:10:34 -04003968 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
Roland Levillain4d027112015-07-01 15:41:14 +01003969 // `value_type == Primitive::kPrimNot` implies `v == 0`.
3970 DCHECK((value_type != Primitive::kPrimNot) || (v == 0));
3971 // Note: if heap poisoning is enabled, no need to poison
3972 // (negate) `v` if it is a reference, as it would be null.
Mark Mendell40741f32015-04-20 22:10:34 -04003973 __ movl(Address(obj, offset), Immediate(v));
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003974 }
3975 } else {
3976 DCHECK(index.IsRegister()) << index;
3977 if (value.IsRegister()) {
Roland Levillain4d027112015-07-01 15:41:14 +01003978 if (kPoisonHeapReferences && value_type == Primitive::kPrimNot) {
3979 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
3980 __ movl(temp, value.AsRegister<CpuRegister>());
3981 __ PoisonHeapReference(temp);
3982 __ movl(Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset), temp);
3983 } else {
3984 __ movl(Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset),
3985 value.AsRegister<CpuRegister>());
3986 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003987 } else {
3988 DCHECK(value.IsConstant()) << value;
Mark Mendell40741f32015-04-20 22:10:34 -04003989 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
Roland Levillain4d027112015-07-01 15:41:14 +01003990 // `value_type == Primitive::kPrimNot` implies `v == 0`.
3991 DCHECK((value_type != Primitive::kPrimNot) || (v == 0));
3992 // Note: if heap poisoning is enabled, no need to poison
3993 // (negate) `v` if it is a reference, as it would be null.
Roland Levillain271ab9c2014-11-27 15:23:57 +00003994 __ movl(Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset),
Mark Mendell40741f32015-04-20 22:10:34 -04003995 Immediate(v));
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003996 }
3997 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003998 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003999 if (needs_write_barrier) {
4000 DCHECK_EQ(value_type, Primitive::kPrimNot);
Roland Levillain271ab9c2014-11-27 15:23:57 +00004001 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
4002 CpuRegister card = locations->GetTemp(1).AsRegister<CpuRegister>();
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004003 codegen_->MarkGCCard(
4004 temp, card, obj, value.AsRegister<CpuRegister>(), instruction->GetValueCanBeNull());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004005 }
4006 } else {
4007 DCHECK_EQ(value_type, Primitive::kPrimNot);
Roland Levillain4d027112015-07-01 15:41:14 +01004008 // Note: if heap poisoning is enabled, pAputObject takes cares
4009 // of poisoning the reference.
Roland Levillain199f3362014-11-27 17:15:16 +00004010 __ gs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pAputObject),
4011 true));
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004012 DCHECK(!codegen_->IsLeafMethod());
4013 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
4014 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004015 break;
4016 }
4017
4018 case Primitive::kPrimLong: {
4019 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004020 if (index.IsConstant()) {
4021 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Mark Mendell40741f32015-04-20 22:10:34 -04004022 if (value.IsRegister()) {
4023 __ movq(Address(obj, offset), value.AsRegister<CpuRegister>());
4024 } else {
4025 int64_t v = value.GetConstant()->AsLongConstant()->GetValue();
4026 DCHECK(IsInt<32>(v));
4027 int32_t v_32 = v;
4028 __ movq(Address(obj, offset), Immediate(v_32));
4029 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004030 } else {
Mark Mendell40741f32015-04-20 22:10:34 -04004031 if (value.IsRegister()) {
4032 __ movq(Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset),
4033 value.AsRegister<CpuRegister>());
4034 } else {
4035 int64_t v = value.GetConstant()->AsLongConstant()->GetValue();
4036 DCHECK(IsInt<32>(v));
4037 int32_t v_32 = v;
4038 __ movq(Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset),
4039 Immediate(v_32));
4040 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004041 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004042 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004043 break;
4044 }
4045
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004046 case Primitive::kPrimFloat: {
4047 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
4048 if (index.IsConstant()) {
4049 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4050 DCHECK(value.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004051 __ movss(Address(obj, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004052 } else {
4053 DCHECK(value.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004054 __ movss(Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset),
4055 value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004056 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004057 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004058 break;
4059 }
4060
4061 case Primitive::kPrimDouble: {
4062 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
4063 if (index.IsConstant()) {
4064 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
4065 DCHECK(value.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004066 __ movsd(Address(obj, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004067 } else {
4068 DCHECK(value.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004069 __ movsd(Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset),
4070 value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004071 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004072 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004073 break;
4074 }
4075
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004076 case Primitive::kPrimVoid:
4077 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07004078 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004079 }
4080}
4081
4082void LocationsBuilderX86_64::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004083 LocationSummary* locations =
4084 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01004085 locations->SetInAt(0, Location::RequiresRegister());
4086 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004087}
4088
4089void InstructionCodeGeneratorX86_64::VisitArrayLength(HArrayLength* instruction) {
4090 LocationSummary* locations = instruction->GetLocations();
4091 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004092 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
4093 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004094 __ movl(out, Address(obj, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00004095 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004096}
4097
4098void LocationsBuilderX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004099 LocationSummary* locations =
4100 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Mark Mendellf60c90b2015-03-04 15:12:59 -05004101 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
Mark Mendell99dbd682015-04-22 16:18:52 -04004102 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004103 if (instruction->HasUses()) {
4104 locations->SetOut(Location::SameAsFirstInput());
4105 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004106}
4107
4108void InstructionCodeGeneratorX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
4109 LocationSummary* locations = instruction->GetLocations();
Mark Mendellf60c90b2015-03-04 15:12:59 -05004110 Location index_loc = locations->InAt(0);
4111 Location length_loc = locations->InAt(1);
4112 SlowPathCodeX86_64* slow_path =
4113 new (GetGraph()->GetArena()) BoundsCheckSlowPathX86_64(instruction, index_loc, length_loc);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004114
Mark Mendell99dbd682015-04-22 16:18:52 -04004115 if (length_loc.IsConstant()) {
4116 int32_t length = CodeGenerator::GetInt32ValueOf(length_loc.GetConstant());
4117 if (index_loc.IsConstant()) {
4118 // BCE will remove the bounds check if we are guarenteed to pass.
4119 int32_t index = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
4120 if (index < 0 || index >= length) {
4121 codegen_->AddSlowPath(slow_path);
4122 __ jmp(slow_path->GetEntryLabel());
4123 } else {
4124 // Some optimization after BCE may have generated this, and we should not
4125 // generate a bounds check if it is a valid range.
4126 }
4127 return;
4128 }
4129
4130 // We have to reverse the jump condition because the length is the constant.
4131 CpuRegister index_reg = index_loc.AsRegister<CpuRegister>();
4132 __ cmpl(index_reg, Immediate(length));
4133 codegen_->AddSlowPath(slow_path);
4134 __ j(kAboveEqual, slow_path->GetEntryLabel());
Mark Mendellf60c90b2015-03-04 15:12:59 -05004135 } else {
Mark Mendell99dbd682015-04-22 16:18:52 -04004136 CpuRegister length = length_loc.AsRegister<CpuRegister>();
4137 if (index_loc.IsConstant()) {
4138 int32_t value = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
4139 __ cmpl(length, Immediate(value));
4140 } else {
4141 __ cmpl(length, index_loc.AsRegister<CpuRegister>());
4142 }
4143 codegen_->AddSlowPath(slow_path);
4144 __ j(kBelowEqual, slow_path->GetEntryLabel());
Mark Mendellf60c90b2015-03-04 15:12:59 -05004145 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004146}
4147
4148void CodeGeneratorX86_64::MarkGCCard(CpuRegister temp,
4149 CpuRegister card,
4150 CpuRegister object,
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004151 CpuRegister value,
4152 bool value_can_be_null) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004153 Label is_null;
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004154 if (value_can_be_null) {
4155 __ testl(value, value);
4156 __ j(kEqual, &is_null);
4157 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004158 __ gs()->movq(card, Address::Absolute(
4159 Thread::CardTableOffset<kX86_64WordSize>().Int32Value(), true));
4160 __ movq(temp, object);
4161 __ shrq(temp, Immediate(gc::accounting::CardTable::kCardShift));
Roland Levillain4d027112015-07-01 15:41:14 +01004162 __ movb(Address(temp, card, TIMES_1, 0), card);
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004163 if (value_can_be_null) {
4164 __ Bind(&is_null);
4165 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004166}
4167
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004168void LocationsBuilderX86_64::VisitTemporary(HTemporary* temp) {
4169 temp->SetLocations(nullptr);
4170}
4171
4172void InstructionCodeGeneratorX86_64::VisitTemporary(HTemporary* temp) {
4173 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07004174 UNUSED(temp);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004175}
4176
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004177void LocationsBuilderX86_64::VisitParallelMove(HParallelMove* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07004178 UNUSED(instruction);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004179 LOG(FATAL) << "Unimplemented";
4180}
4181
4182void InstructionCodeGeneratorX86_64::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004183 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
4184}
4185
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004186void LocationsBuilderX86_64::VisitSuspendCheck(HSuspendCheck* instruction) {
4187 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
4188}
4189
4190void InstructionCodeGeneratorX86_64::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004191 HBasicBlock* block = instruction->GetBlock();
4192 if (block->GetLoopInformation() != nullptr) {
4193 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
4194 // The back edge will generate the suspend check.
4195 return;
4196 }
4197 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
4198 // The goto will generate the suspend check.
4199 return;
4200 }
4201 GenerateSuspendCheck(instruction, nullptr);
4202}
4203
4204void InstructionCodeGeneratorX86_64::GenerateSuspendCheck(HSuspendCheck* instruction,
4205 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004206 SuspendCheckSlowPathX86_64* slow_path =
Nicolas Geoffraydb216f42015-05-05 17:02:20 +01004207 down_cast<SuspendCheckSlowPathX86_64*>(instruction->GetSlowPath());
4208 if (slow_path == nullptr) {
4209 slow_path = new (GetGraph()->GetArena()) SuspendCheckSlowPathX86_64(instruction, successor);
4210 instruction->SetSlowPath(slow_path);
4211 codegen_->AddSlowPath(slow_path);
4212 if (successor != nullptr) {
4213 DCHECK(successor->IsLoopHeader());
4214 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(instruction);
4215 }
4216 } else {
4217 DCHECK_EQ(slow_path->GetSuccessor(), successor);
4218 }
4219
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004220 __ gs()->cmpw(Address::Absolute(
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004221 Thread::ThreadFlagsOffset<kX86_64WordSize>().Int32Value(), true), Immediate(0));
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004222 if (successor == nullptr) {
4223 __ j(kNotEqual, slow_path->GetEntryLabel());
4224 __ Bind(slow_path->GetReturnLabel());
4225 } else {
4226 __ j(kEqual, codegen_->GetLabelOf(successor));
4227 __ jmp(slow_path->GetEntryLabel());
4228 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004229}
4230
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004231X86_64Assembler* ParallelMoveResolverX86_64::GetAssembler() const {
4232 return codegen_->GetAssembler();
4233}
4234
4235void ParallelMoveResolverX86_64::EmitMove(size_t index) {
4236 MoveOperands* move = moves_.Get(index);
4237 Location source = move->GetSource();
4238 Location destination = move->GetDestination();
4239
4240 if (source.IsRegister()) {
4241 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004242 __ movq(destination.AsRegister<CpuRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004243 } else if (destination.IsStackSlot()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004244 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00004245 source.AsRegister<CpuRegister>());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004246 } else {
4247 DCHECK(destination.IsDoubleStackSlot());
4248 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00004249 source.AsRegister<CpuRegister>());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004250 }
4251 } else if (source.IsStackSlot()) {
4252 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004253 __ movl(destination.AsRegister<CpuRegister>(),
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004254 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004255 } else if (destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004256 __ movss(destination.AsFpuRegister<XmmRegister>(),
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004257 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004258 } else {
4259 DCHECK(destination.IsStackSlot());
4260 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
4261 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
4262 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004263 } else if (source.IsDoubleStackSlot()) {
4264 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004265 __ movq(destination.AsRegister<CpuRegister>(),
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004266 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004267 } else if (destination.IsFpuRegister()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004268 __ movsd(destination.AsFpuRegister<XmmRegister>(),
4269 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004270 } else {
Nicolas Geoffrayc8147a72014-10-21 16:06:20 +01004271 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004272 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
4273 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
4274 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004275 } else if (source.IsConstant()) {
4276 HConstant* constant = source.GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00004277 if (constant->IsIntConstant() || constant->IsNullConstant()) {
4278 int32_t value = CodeGenerator::GetInt32ValueOf(constant);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004279 if (destination.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00004280 if (value == 0) {
4281 __ xorl(destination.AsRegister<CpuRegister>(), destination.AsRegister<CpuRegister>());
4282 } else {
4283 __ movl(destination.AsRegister<CpuRegister>(), Immediate(value));
4284 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004285 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004286 DCHECK(destination.IsStackSlot()) << destination;
Nicolas Geoffray748f1402015-01-27 08:17:54 +00004287 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), Immediate(value));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004288 }
4289 } else if (constant->IsLongConstant()) {
4290 int64_t value = constant->AsLongConstant()->GetValue();
4291 if (destination.IsRegister()) {
Mark Mendell92e83bf2015-05-07 11:25:03 -04004292 codegen_->Load64BitValue(destination.AsRegister<CpuRegister>(), value);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004293 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004294 DCHECK(destination.IsDoubleStackSlot()) << destination;
Mark Mendell92e83bf2015-05-07 11:25:03 -04004295 codegen_->Load64BitValue(CpuRegister(TMP), value);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004296 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
4297 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004298 } else if (constant->IsFloatConstant()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004299 float fp_value = constant->AsFloatConstant()->GetValue();
Roland Levillainda4d79b2015-03-24 14:36:11 +00004300 int32_t value = bit_cast<int32_t, float>(fp_value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004301 if (destination.IsFpuRegister()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004302 XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
4303 if (value == 0) {
4304 // easy FP 0.0.
4305 __ xorps(dest, dest);
4306 } else {
Mark Mendell92e83bf2015-05-07 11:25:03 -04004307 __ movss(dest, codegen_->LiteralFloatAddress(fp_value));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004308 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004309 } else {
4310 DCHECK(destination.IsStackSlot()) << destination;
Mark Mendell92e83bf2015-05-07 11:25:03 -04004311 Immediate imm(value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004312 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), imm);
4313 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004314 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004315 DCHECK(constant->IsDoubleConstant()) << constant->DebugName();
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004316 double fp_value = constant->AsDoubleConstant()->GetValue();
Roland Levillainda4d79b2015-03-24 14:36:11 +00004317 int64_t value = bit_cast<int64_t, double>(fp_value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004318 if (destination.IsFpuRegister()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004319 XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
4320 if (value == 0) {
4321 __ xorpd(dest, dest);
4322 } else {
Mark Mendell92e83bf2015-05-07 11:25:03 -04004323 __ movsd(dest, codegen_->LiteralDoubleAddress(fp_value));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004324 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004325 } else {
4326 DCHECK(destination.IsDoubleStackSlot()) << destination;
Mark Mendell92e83bf2015-05-07 11:25:03 -04004327 codegen_->Load64BitValue(CpuRegister(TMP), value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004328 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
4329 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004330 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004331 } else if (source.IsFpuRegister()) {
4332 if (destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004333 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004334 } else if (destination.IsStackSlot()) {
4335 __ movss(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00004336 source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004337 } else {
Nicolas Geoffray31596742014-11-24 15:28:45 +00004338 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004339 __ movsd(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00004340 source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004341 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004342 }
4343}
4344
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004345void ParallelMoveResolverX86_64::Exchange32(CpuRegister reg, int mem) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004346 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004347 __ movl(Address(CpuRegister(RSP), mem), reg);
4348 __ movl(reg, CpuRegister(TMP));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004349}
4350
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004351void ParallelMoveResolverX86_64::Exchange32(int mem1, int mem2) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004352 ScratchRegisterScope ensure_scratch(
4353 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
4354
4355 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
4356 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
4357 __ movl(CpuRegister(ensure_scratch.GetRegister()),
4358 Address(CpuRegister(RSP), mem2 + stack_offset));
4359 __ movl(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
4360 __ movl(Address(CpuRegister(RSP), mem1 + stack_offset),
4361 CpuRegister(ensure_scratch.GetRegister()));
4362}
4363
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004364void ParallelMoveResolverX86_64::Exchange64(CpuRegister reg, int mem) {
4365 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
4366 __ movq(Address(CpuRegister(RSP), mem), reg);
4367 __ movq(reg, CpuRegister(TMP));
4368}
4369
4370void ParallelMoveResolverX86_64::Exchange64(int mem1, int mem2) {
4371 ScratchRegisterScope ensure_scratch(
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004372 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004373
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004374 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
4375 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
4376 __ movq(CpuRegister(ensure_scratch.GetRegister()),
4377 Address(CpuRegister(RSP), mem2 + stack_offset));
4378 __ movq(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
4379 __ movq(Address(CpuRegister(RSP), mem1 + stack_offset),
4380 CpuRegister(ensure_scratch.GetRegister()));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004381}
4382
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004383void ParallelMoveResolverX86_64::Exchange32(XmmRegister reg, int mem) {
4384 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
4385 __ movss(Address(CpuRegister(RSP), mem), reg);
4386 __ movd(reg, CpuRegister(TMP));
4387}
4388
4389void ParallelMoveResolverX86_64::Exchange64(XmmRegister reg, int mem) {
4390 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
4391 __ movsd(Address(CpuRegister(RSP), mem), reg);
4392 __ movd(reg, CpuRegister(TMP));
4393}
4394
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004395void ParallelMoveResolverX86_64::EmitSwap(size_t index) {
4396 MoveOperands* move = moves_.Get(index);
4397 Location source = move->GetSource();
4398 Location destination = move->GetDestination();
4399
4400 if (source.IsRegister() && destination.IsRegister()) {
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004401 __ xchgq(destination.AsRegister<CpuRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004402 } else if (source.IsRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004403 Exchange32(source.AsRegister<CpuRegister>(), destination.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004404 } else if (source.IsStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004405 Exchange32(destination.AsRegister<CpuRegister>(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004406 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004407 Exchange32(destination.GetStackIndex(), source.GetStackIndex());
4408 } else if (source.IsRegister() && destination.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004409 Exchange64(source.AsRegister<CpuRegister>(), destination.GetStackIndex());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004410 } else if (source.IsDoubleStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004411 Exchange64(destination.AsRegister<CpuRegister>(), source.GetStackIndex());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004412 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
4413 Exchange64(destination.GetStackIndex(), source.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004414 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004415 __ movd(CpuRegister(TMP), source.AsFpuRegister<XmmRegister>());
4416 __ movaps(source.AsFpuRegister<XmmRegister>(), destination.AsFpuRegister<XmmRegister>());
4417 __ movd(destination.AsFpuRegister<XmmRegister>(), CpuRegister(TMP));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004418 } else if (source.IsFpuRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004419 Exchange32(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004420 } else if (source.IsStackSlot() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004421 Exchange32(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004422 } else if (source.IsFpuRegister() && destination.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004423 Exchange64(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004424 } else if (source.IsDoubleStackSlot() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004425 Exchange64(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004426 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004427 LOG(FATAL) << "Unimplemented swap between " << source << " and " << destination;
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004428 }
4429}
4430
4431
4432void ParallelMoveResolverX86_64::SpillScratch(int reg) {
4433 __ pushq(CpuRegister(reg));
4434}
4435
4436
4437void ParallelMoveResolverX86_64::RestoreScratch(int reg) {
4438 __ popq(CpuRegister(reg));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004439}
4440
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004441void InstructionCodeGeneratorX86_64::GenerateClassInitializationCheck(
4442 SlowPathCodeX86_64* slow_path, CpuRegister class_reg) {
4443 __ cmpl(Address(class_reg, mirror::Class::StatusOffset().Int32Value()),
4444 Immediate(mirror::Class::kStatusInitialized));
4445 __ j(kLess, slow_path->GetEntryLabel());
4446 __ Bind(slow_path->GetExitLabel());
4447 // No need for memory fence, thanks to the X86_64 memory model.
4448}
4449
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004450void LocationsBuilderX86_64::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004451 LocationSummary::CallKind call_kind = cls->CanCallRuntime()
4452 ? LocationSummary::kCallOnSlowPath
4453 : LocationSummary::kNoCall;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004454 LocationSummary* locations =
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004455 new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004456 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004457 locations->SetOut(Location::RequiresRegister());
4458}
4459
4460void InstructionCodeGeneratorX86_64::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004461 LocationSummary* locations = cls->GetLocations();
4462 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
4463 CpuRegister current_method = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004464 if (cls->IsReferrersClass()) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004465 DCHECK(!cls->CanCallRuntime());
4466 DCHECK(!cls->MustGenerateClinitCheck());
Mathieu Chartiere401d142015-04-22 13:56:20 -07004467 __ movl(out, Address(current_method, ArtMethod::DeclaringClassOffset().Int32Value()));
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004468 } else {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004469 DCHECK(cls->CanCallRuntime());
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004470 __ movl(out, Address(
Mathieu Chartiere401d142015-04-22 13:56:20 -07004471 current_method, ArtMethod::DexCacheResolvedTypesOffset().Int32Value()));
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004472 __ movl(out, Address(out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex())));
Roland Levillain4d027112015-07-01 15:41:14 +01004473 __ MaybeUnpoisonHeapReference(out);
4474
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004475 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86_64(
4476 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
4477 codegen_->AddSlowPath(slow_path);
4478 __ testl(out, out);
4479 __ j(kEqual, slow_path->GetEntryLabel());
4480 if (cls->MustGenerateClinitCheck()) {
4481 GenerateClassInitializationCheck(slow_path, out);
4482 } else {
4483 __ Bind(slow_path->GetExitLabel());
4484 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004485 }
4486}
4487
4488void LocationsBuilderX86_64::VisitClinitCheck(HClinitCheck* check) {
4489 LocationSummary* locations =
4490 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
4491 locations->SetInAt(0, Location::RequiresRegister());
4492 if (check->HasUses()) {
4493 locations->SetOut(Location::SameAsFirstInput());
4494 }
4495}
4496
4497void InstructionCodeGeneratorX86_64::VisitClinitCheck(HClinitCheck* check) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004498 // We assume the class to not be null.
4499 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86_64(
4500 check->GetLoadClass(), check, check->GetDexPc(), true);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004501 codegen_->AddSlowPath(slow_path);
Roland Levillain199f3362014-11-27 17:15:16 +00004502 GenerateClassInitializationCheck(slow_path,
4503 check->GetLocations()->InAt(0).AsRegister<CpuRegister>());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004504}
4505
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004506void LocationsBuilderX86_64::VisitLoadString(HLoadString* load) {
4507 LocationSummary* locations =
4508 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01004509 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004510 locations->SetOut(Location::RequiresRegister());
4511}
4512
4513void InstructionCodeGeneratorX86_64::VisitLoadString(HLoadString* load) {
4514 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathX86_64(load);
4515 codegen_->AddSlowPath(slow_path);
4516
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01004517 LocationSummary* locations = load->GetLocations();
4518 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
4519 CpuRegister current_method = locations->InAt(0).AsRegister<CpuRegister>();
Mathieu Chartiere401d142015-04-22 13:56:20 -07004520 __ movl(out, Address(current_method, ArtMethod::DeclaringClassOffset().Int32Value()));
Mathieu Chartiereace4582014-11-24 18:29:54 -08004521 __ movl(out, Address(out, mirror::Class::DexCacheStringsOffset().Int32Value()));
Roland Levillain4d027112015-07-01 15:41:14 +01004522 __ MaybeUnpoisonHeapReference(out);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004523 __ movl(out, Address(out, CodeGenerator::GetCacheOffset(load->GetStringIndex())));
Roland Levillain4d027112015-07-01 15:41:14 +01004524 __ MaybeUnpoisonHeapReference(out);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004525 __ testl(out, out);
4526 __ j(kEqual, slow_path->GetEntryLabel());
4527 __ Bind(slow_path->GetExitLabel());
4528}
4529
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004530void LocationsBuilderX86_64::VisitLoadException(HLoadException* load) {
4531 LocationSummary* locations =
4532 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
4533 locations->SetOut(Location::RequiresRegister());
4534}
4535
4536void InstructionCodeGeneratorX86_64::VisitLoadException(HLoadException* load) {
4537 Address address = Address::Absolute(
4538 Thread::ExceptionOffset<kX86_64WordSize>().Int32Value(), true);
Roland Levillain271ab9c2014-11-27 15:23:57 +00004539 __ gs()->movl(load->GetLocations()->Out().AsRegister<CpuRegister>(), address);
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004540 __ gs()->movl(address, Immediate(0));
4541}
4542
4543void LocationsBuilderX86_64::VisitThrow(HThrow* instruction) {
4544 LocationSummary* locations =
4545 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
4546 InvokeRuntimeCallingConvention calling_convention;
4547 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4548}
4549
4550void InstructionCodeGeneratorX86_64::VisitThrow(HThrow* instruction) {
4551 __ gs()->call(
4552 Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pDeliverException), true));
4553 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
4554}
4555
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004556void LocationsBuilderX86_64::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004557 LocationSummary::CallKind call_kind = instruction->IsClassFinal()
4558 ? LocationSummary::kNoCall
4559 : LocationSummary::kCallOnSlowPath;
4560 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
4561 locations->SetInAt(0, Location::RequiresRegister());
4562 locations->SetInAt(1, Location::Any());
4563 locations->SetOut(Location::RequiresRegister());
4564}
4565
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004566void InstructionCodeGeneratorX86_64::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004567 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004568 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004569 Location cls = locations->InAt(1);
Roland Levillain271ab9c2014-11-27 15:23:57 +00004570 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004571 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
4572 Label done, zero;
4573 SlowPathCodeX86_64* slow_path = nullptr;
4574
4575 // Return 0 if `obj` is null.
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004576 // Avoid null check if we know obj is not null.
4577 if (instruction->MustDoNullCheck()) {
4578 __ testl(obj, obj);
4579 __ j(kEqual, &zero);
4580 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004581 // Compare the class of `obj` with `cls`.
4582 __ movl(out, Address(obj, class_offset));
Roland Levillain4d027112015-07-01 15:41:14 +01004583 __ MaybeUnpoisonHeapReference(out);
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004584 if (cls.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004585 __ cmpl(out, cls.AsRegister<CpuRegister>());
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004586 } else {
4587 DCHECK(cls.IsStackSlot()) << cls;
4588 __ cmpl(out, Address(CpuRegister(RSP), cls.GetStackIndex()));
4589 }
4590 if (instruction->IsClassFinal()) {
4591 // Classes must be equal for the instanceof to succeed.
4592 __ j(kNotEqual, &zero);
4593 __ movl(out, Immediate(1));
4594 __ jmp(&done);
4595 } else {
4596 // If the classes are not equal, we go into a slow path.
4597 DCHECK(locations->OnlyCallsOnSlowPath());
4598 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86_64(
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004599 instruction, locations->InAt(1), locations->Out(), instruction->GetDexPc());
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004600 codegen_->AddSlowPath(slow_path);
4601 __ j(kNotEqual, slow_path->GetEntryLabel());
4602 __ movl(out, Immediate(1));
4603 __ jmp(&done);
4604 }
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004605
4606 if (instruction->MustDoNullCheck() || instruction->IsClassFinal()) {
4607 __ Bind(&zero);
4608 __ movl(out, Immediate(0));
4609 }
4610
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004611 if (slow_path != nullptr) {
4612 __ Bind(slow_path->GetExitLabel());
4613 }
4614 __ Bind(&done);
4615}
4616
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004617void LocationsBuilderX86_64::VisitCheckCast(HCheckCast* instruction) {
4618 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
4619 instruction, LocationSummary::kCallOnSlowPath);
4620 locations->SetInAt(0, Location::RequiresRegister());
4621 locations->SetInAt(1, Location::Any());
4622 locations->AddTemp(Location::RequiresRegister());
4623}
4624
4625void InstructionCodeGeneratorX86_64::VisitCheckCast(HCheckCast* instruction) {
4626 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004627 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004628 Location cls = locations->InAt(1);
Roland Levillain271ab9c2014-11-27 15:23:57 +00004629 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004630 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
4631 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86_64(
4632 instruction, locations->InAt(1), locations->GetTemp(0), instruction->GetDexPc());
4633 codegen_->AddSlowPath(slow_path);
4634
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004635 // Avoid null check if we know obj is not null.
4636 if (instruction->MustDoNullCheck()) {
4637 __ testl(obj, obj);
4638 __ j(kEqual, slow_path->GetExitLabel());
4639 }
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004640 // Compare the class of `obj` with `cls`.
4641 __ movl(temp, Address(obj, class_offset));
Roland Levillain4d027112015-07-01 15:41:14 +01004642 __ MaybeUnpoisonHeapReference(temp);
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004643 if (cls.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004644 __ cmpl(temp, cls.AsRegister<CpuRegister>());
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004645 } else {
4646 DCHECK(cls.IsStackSlot()) << cls;
4647 __ cmpl(temp, Address(CpuRegister(RSP), cls.GetStackIndex()));
4648 }
Roland Levillain4d027112015-07-01 15:41:14 +01004649 // The checkcast succeeds if the classes are equal (fast path).
4650 // Otherwise, we need to go into the slow path to check the types.
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004651 __ j(kNotEqual, slow_path->GetEntryLabel());
4652 __ Bind(slow_path->GetExitLabel());
4653}
4654
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00004655void LocationsBuilderX86_64::VisitMonitorOperation(HMonitorOperation* instruction) {
4656 LocationSummary* locations =
4657 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
4658 InvokeRuntimeCallingConvention calling_convention;
4659 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4660}
4661
4662void InstructionCodeGeneratorX86_64::VisitMonitorOperation(HMonitorOperation* instruction) {
4663 __ gs()->call(Address::Absolute(instruction->IsEnter()
4664 ? QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pLockObject)
4665 : QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pUnlockObject),
4666 true));
4667 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
4668}
4669
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004670void LocationsBuilderX86_64::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); }
4671void LocationsBuilderX86_64::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); }
4672void LocationsBuilderX86_64::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); }
4673
4674void LocationsBuilderX86_64::HandleBitwiseOperation(HBinaryOperation* instruction) {
4675 LocationSummary* locations =
4676 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
4677 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
4678 || instruction->GetResultType() == Primitive::kPrimLong);
4679 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell40741f32015-04-20 22:10:34 -04004680 locations->SetInAt(1, Location::Any());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004681 locations->SetOut(Location::SameAsFirstInput());
4682}
4683
4684void InstructionCodeGeneratorX86_64::VisitAnd(HAnd* instruction) {
4685 HandleBitwiseOperation(instruction);
4686}
4687
4688void InstructionCodeGeneratorX86_64::VisitOr(HOr* instruction) {
4689 HandleBitwiseOperation(instruction);
4690}
4691
4692void InstructionCodeGeneratorX86_64::VisitXor(HXor* instruction) {
4693 HandleBitwiseOperation(instruction);
4694}
4695
4696void InstructionCodeGeneratorX86_64::HandleBitwiseOperation(HBinaryOperation* instruction) {
4697 LocationSummary* locations = instruction->GetLocations();
4698 Location first = locations->InAt(0);
4699 Location second = locations->InAt(1);
4700 DCHECK(first.Equals(locations->Out()));
4701
4702 if (instruction->GetResultType() == Primitive::kPrimInt) {
4703 if (second.IsRegister()) {
4704 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004705 __ andl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004706 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004707 __ orl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004708 } else {
4709 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004710 __ xorl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004711 }
4712 } else if (second.IsConstant()) {
4713 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
4714 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004715 __ andl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004716 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004717 __ orl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004718 } else {
4719 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004720 __ xorl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004721 }
4722 } else {
4723 Address address(CpuRegister(RSP), second.GetStackIndex());
4724 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004725 __ andl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004726 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004727 __ orl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004728 } else {
4729 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004730 __ xorl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004731 }
4732 }
4733 } else {
4734 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004735 CpuRegister first_reg = first.AsRegister<CpuRegister>();
4736 bool second_is_constant = false;
4737 int64_t value = 0;
4738 if (second.IsConstant()) {
4739 second_is_constant = true;
4740 value = second.GetConstant()->AsLongConstant()->GetValue();
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004741 }
Mark Mendell40741f32015-04-20 22:10:34 -04004742 bool is_int32_value = IsInt<32>(value);
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004743
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004744 if (instruction->IsAnd()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004745 if (second_is_constant) {
Mark Mendell40741f32015-04-20 22:10:34 -04004746 if (is_int32_value) {
4747 __ andq(first_reg, Immediate(static_cast<int32_t>(value)));
4748 } else {
4749 __ andq(first_reg, codegen_->LiteralInt64Address(value));
4750 }
4751 } else if (second.IsDoubleStackSlot()) {
4752 __ andq(first_reg, Address(CpuRegister(RSP), second.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004753 } else {
4754 __ andq(first_reg, second.AsRegister<CpuRegister>());
4755 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004756 } else if (instruction->IsOr()) {
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 __ orq(first_reg, Immediate(static_cast<int32_t>(value)));
4760 } else {
4761 __ orq(first_reg, codegen_->LiteralInt64Address(value));
4762 }
4763 } else if (second.IsDoubleStackSlot()) {
4764 __ orq(first_reg, Address(CpuRegister(RSP), second.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004765 } else {
4766 __ orq(first_reg, second.AsRegister<CpuRegister>());
4767 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004768 } else {
4769 DCHECK(instruction->IsXor());
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004770 if (second_is_constant) {
Mark Mendell40741f32015-04-20 22:10:34 -04004771 if (is_int32_value) {
4772 __ xorq(first_reg, Immediate(static_cast<int32_t>(value)));
4773 } else {
4774 __ xorq(first_reg, codegen_->LiteralInt64Address(value));
4775 }
4776 } else if (second.IsDoubleStackSlot()) {
4777 __ xorq(first_reg, Address(CpuRegister(RSP), second.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004778 } else {
4779 __ xorq(first_reg, second.AsRegister<CpuRegister>());
4780 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004781 }
4782 }
4783}
4784
Calin Juravleb1498f62015-02-16 13:13:29 +00004785void LocationsBuilderX86_64::VisitBoundType(HBoundType* instruction) {
4786 // Nothing to do, this should be removed during prepare for register allocator.
4787 UNUSED(instruction);
4788 LOG(FATAL) << "Unreachable";
4789}
4790
4791void InstructionCodeGeneratorX86_64::VisitBoundType(HBoundType* instruction) {
4792 // Nothing to do, this should be removed during prepare for register allocator.
4793 UNUSED(instruction);
4794 LOG(FATAL) << "Unreachable";
4795}
4796
Nicolas Geoffray2e7cd752015-07-10 11:38:52 +01004797void LocationsBuilderX86_64::VisitFakeString(HFakeString* instruction) {
4798 DCHECK(codegen_->IsBaseline());
4799 LocationSummary* locations =
4800 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
4801 locations->SetOut(Location::ConstantLocation(GetGraph()->GetNullConstant()));
4802}
4803
4804void InstructionCodeGeneratorX86_64::VisitFakeString(HFakeString* instruction ATTRIBUTE_UNUSED) {
4805 DCHECK(codegen_->IsBaseline());
4806 // Will be generated at use site.
4807}
4808
Mark Mendell92e83bf2015-05-07 11:25:03 -04004809void CodeGeneratorX86_64::Load64BitValue(CpuRegister dest, int64_t value) {
4810 if (value == 0) {
4811 __ xorl(dest, dest);
4812 } else if (value > 0 && IsInt<32>(value)) {
4813 // We can use a 32 bit move, as it will zero-extend and is one byte shorter.
4814 __ movl(dest, Immediate(static_cast<int32_t>(value)));
4815 } else {
4816 __ movq(dest, Immediate(value));
4817 }
4818}
4819
Mark Mendellf55c3e02015-03-26 21:07:46 -04004820void CodeGeneratorX86_64::Finalize(CodeAllocator* allocator) {
4821 // Generate the constant area if needed.
Mark Mendell39dcf552015-04-09 20:42:42 -04004822 X86_64Assembler* assembler = GetAssembler();
4823 if (!assembler->IsConstantAreaEmpty()) {
Mark Mendellf55c3e02015-03-26 21:07:46 -04004824 // Align to 4 byte boundary to reduce cache misses, as the data is 4 and 8
4825 // byte values. If used for vectors at a later time, this will need to be
4826 // updated to 16 bytes with the appropriate offset.
Mark Mendell39dcf552015-04-09 20:42:42 -04004827 assembler->Align(4, 0);
4828 constant_area_start_ = assembler->CodeSize();
4829 assembler->AddConstantArea();
Mark Mendellf55c3e02015-03-26 21:07:46 -04004830 }
4831
4832 // And finish up.
4833 CodeGenerator::Finalize(allocator);
4834}
4835
4836/**
4837 * Class to handle late fixup of offsets into constant area.
4838 */
4839class RIPFixup : public AssemblerFixup, public ArenaObject<kArenaAllocMisc> {
4840 public:
Mark Mendell39dcf552015-04-09 20:42:42 -04004841 RIPFixup(const CodeGeneratorX86_64& codegen, int offset)
Mark Mendellf55c3e02015-03-26 21:07:46 -04004842 : codegen_(codegen), offset_into_constant_area_(offset) {}
4843
4844 private:
4845 void Process(const MemoryRegion& region, int pos) OVERRIDE {
4846 // Patch the correct offset for the instruction. We use the address of the
4847 // 'next' instruction, which is 'pos' (patch the 4 bytes before).
4848 int constant_offset = codegen_.ConstantAreaStart() + offset_into_constant_area_;
4849 int relative_position = constant_offset - pos;
4850
4851 // Patch in the right value.
4852 region.StoreUnaligned<int32_t>(pos - 4, relative_position);
4853 }
4854
Mark Mendell39dcf552015-04-09 20:42:42 -04004855 const CodeGeneratorX86_64& codegen_;
Mark Mendellf55c3e02015-03-26 21:07:46 -04004856
4857 // Location in constant area that the fixup refers to.
4858 int offset_into_constant_area_;
4859};
4860
4861Address CodeGeneratorX86_64::LiteralDoubleAddress(double v) {
4862 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddDouble(v));
4863 return Address::RIP(fixup);
4864}
4865
4866Address CodeGeneratorX86_64::LiteralFloatAddress(float v) {
4867 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddFloat(v));
4868 return Address::RIP(fixup);
4869}
4870
4871Address CodeGeneratorX86_64::LiteralInt32Address(int32_t v) {
4872 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddInt32(v));
4873 return Address::RIP(fixup);
4874}
4875
4876Address CodeGeneratorX86_64::LiteralInt64Address(int64_t v) {
4877 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddInt64(v));
4878 return Address::RIP(fixup);
4879}
4880
Roland Levillain4d027112015-07-01 15:41:14 +01004881#undef __
4882
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004883} // namespace x86_64
4884} // namespace art