blob: ae7bcc8f0e67786fd7cca82b45a52de2b558d666 [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());
2538 locations->SetOut(Location::SameAsFirstInput());
2539 break;
2540 }
2541 case Primitive::kPrimLong: {
2542 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002543 locations->SetInAt(1, Location::RegisterOrInt32LongConstant(mul->InputAt(1)));
2544 if (locations->InAt(1).IsConstant()) {
2545 // Can use 3 operand multiply.
2546 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2547 } else {
2548 locations->SetOut(Location::SameAsFirstInput());
2549 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002550 break;
2551 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01002552 case Primitive::kPrimFloat:
2553 case Primitive::kPrimDouble: {
2554 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendellf55c3e02015-03-26 21:07:46 -04002555 locations->SetInAt(1, Location::Any());
Calin Juravleb5bfa962014-10-21 18:02:24 +01002556 locations->SetOut(Location::SameAsFirstInput());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002557 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002558 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002559
2560 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002561 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002562 }
2563}
2564
2565void InstructionCodeGeneratorX86_64::VisitMul(HMul* mul) {
2566 LocationSummary* locations = mul->GetLocations();
2567 Location first = locations->InAt(0);
2568 Location second = locations->InAt(1);
Calin Juravle34bacdf2014-10-07 20:23:36 +01002569 switch (mul->GetResultType()) {
2570 case Primitive::kPrimInt: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002571 DCHECK(first.Equals(locations->Out()));
Calin Juravle34bacdf2014-10-07 20:23:36 +01002572 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002573 __ imull(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002574 } else if (second.IsConstant()) {
2575 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002576 __ imull(first.AsRegister<CpuRegister>(), imm);
Calin Juravle34bacdf2014-10-07 20:23:36 +01002577 } else {
2578 DCHECK(second.IsStackSlot());
Roland Levillain199f3362014-11-27 17:15:16 +00002579 __ imull(first.AsRegister<CpuRegister>(),
2580 Address(CpuRegister(RSP), second.GetStackIndex()));
Calin Juravle34bacdf2014-10-07 20:23:36 +01002581 }
2582 break;
2583 }
2584 case Primitive::kPrimLong: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002585 if (second.IsConstant()) {
2586 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
2587 DCHECK(IsInt<32>(value));
2588 __ imulq(locations->Out().AsRegister<CpuRegister>(),
2589 first.AsRegister<CpuRegister>(),
2590 Immediate(static_cast<int32_t>(value)));
2591 } else {
2592 DCHECK(first.Equals(locations->Out()));
2593 __ imulq(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
2594 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002595 break;
2596 }
2597
Calin Juravleb5bfa962014-10-21 18:02:24 +01002598 case Primitive::kPrimFloat: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002599 DCHECK(first.Equals(locations->Out()));
Mark Mendellf55c3e02015-03-26 21:07:46 -04002600 if (second.IsFpuRegister()) {
2601 __ mulss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2602 } else if (second.IsConstant()) {
2603 __ mulss(first.AsFpuRegister<XmmRegister>(),
2604 codegen_->LiteralFloatAddress(second.GetConstant()->AsFloatConstant()->GetValue()));
2605 } else {
2606 DCHECK(second.IsStackSlot());
2607 __ mulss(first.AsFpuRegister<XmmRegister>(),
2608 Address(CpuRegister(RSP), second.GetStackIndex()));
2609 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002610 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002611 }
2612
2613 case Primitive::kPrimDouble: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002614 DCHECK(first.Equals(locations->Out()));
Mark Mendellf55c3e02015-03-26 21:07:46 -04002615 if (second.IsFpuRegister()) {
2616 __ mulsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2617 } else if (second.IsConstant()) {
2618 __ mulsd(first.AsFpuRegister<XmmRegister>(),
2619 codegen_->LiteralDoubleAddress(second.GetConstant()->AsDoubleConstant()->GetValue()));
2620 } else {
2621 DCHECK(second.IsDoubleStackSlot());
2622 __ mulsd(first.AsFpuRegister<XmmRegister>(),
2623 Address(CpuRegister(RSP), second.GetStackIndex()));
2624 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01002625 break;
2626 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002627
2628 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002629 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002630 }
2631}
2632
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002633void InstructionCodeGeneratorX86_64::PushOntoFPStack(Location source, uint32_t temp_offset,
2634 uint32_t stack_adjustment, bool is_float) {
2635 if (source.IsStackSlot()) {
2636 DCHECK(is_float);
2637 __ flds(Address(CpuRegister(RSP), source.GetStackIndex() + stack_adjustment));
2638 } else if (source.IsDoubleStackSlot()) {
2639 DCHECK(!is_float);
2640 __ fldl(Address(CpuRegister(RSP), source.GetStackIndex() + stack_adjustment));
2641 } else {
2642 // Write the value to the temporary location on the stack and load to FP stack.
2643 if (is_float) {
2644 Location stack_temp = Location::StackSlot(temp_offset);
2645 codegen_->Move(stack_temp, source);
2646 __ flds(Address(CpuRegister(RSP), temp_offset));
2647 } else {
2648 Location stack_temp = Location::DoubleStackSlot(temp_offset);
2649 codegen_->Move(stack_temp, source);
2650 __ fldl(Address(CpuRegister(RSP), temp_offset));
2651 }
2652 }
2653}
2654
2655void InstructionCodeGeneratorX86_64::GenerateRemFP(HRem *rem) {
2656 Primitive::Type type = rem->GetResultType();
2657 bool is_float = type == Primitive::kPrimFloat;
2658 size_t elem_size = Primitive::ComponentSize(type);
2659 LocationSummary* locations = rem->GetLocations();
2660 Location first = locations->InAt(0);
2661 Location second = locations->InAt(1);
2662 Location out = locations->Out();
2663
2664 // Create stack space for 2 elements.
2665 // TODO: enhance register allocator to ask for stack temporaries.
2666 __ subq(CpuRegister(RSP), Immediate(2 * elem_size));
2667
2668 // Load the values to the FP stack in reverse order, using temporaries if needed.
2669 PushOntoFPStack(second, elem_size, 2 * elem_size, is_float);
2670 PushOntoFPStack(first, 0, 2 * elem_size, is_float);
2671
2672 // Loop doing FPREM until we stabilize.
2673 Label retry;
2674 __ Bind(&retry);
2675 __ fprem();
2676
2677 // Move FP status to AX.
2678 __ fstsw();
2679
2680 // And see if the argument reduction is complete. This is signaled by the
2681 // C2 FPU flag bit set to 0.
2682 __ andl(CpuRegister(RAX), Immediate(kC2ConditionMask));
2683 __ j(kNotEqual, &retry);
2684
2685 // We have settled on the final value. Retrieve it into an XMM register.
2686 // Store FP top of stack to real stack.
2687 if (is_float) {
2688 __ fsts(Address(CpuRegister(RSP), 0));
2689 } else {
2690 __ fstl(Address(CpuRegister(RSP), 0));
2691 }
2692
2693 // Pop the 2 items from the FP stack.
2694 __ fucompp();
2695
2696 // Load the value from the stack into an XMM register.
2697 DCHECK(out.IsFpuRegister()) << out;
2698 if (is_float) {
2699 __ movss(out.AsFpuRegister<XmmRegister>(), Address(CpuRegister(RSP), 0));
2700 } else {
2701 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(CpuRegister(RSP), 0));
2702 }
2703
2704 // And remove the temporary stack space we allocated.
2705 __ addq(CpuRegister(RSP), Immediate(2 * elem_size));
2706}
2707
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002708void InstructionCodeGeneratorX86_64::DivRemOneOrMinusOne(HBinaryOperation* instruction) {
2709 DCHECK(instruction->IsDiv() || instruction->IsRem());
2710
2711 LocationSummary* locations = instruction->GetLocations();
2712 Location second = locations->InAt(1);
2713 DCHECK(second.IsConstant());
2714
2715 CpuRegister output_register = locations->Out().AsRegister<CpuRegister>();
2716 CpuRegister input_register = locations->InAt(0).AsRegister<CpuRegister>();
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002717 int64_t imm = Int64FromConstant(second.GetConstant());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002718
2719 DCHECK(imm == 1 || imm == -1);
2720
2721 switch (instruction->GetResultType()) {
2722 case Primitive::kPrimInt: {
2723 if (instruction->IsRem()) {
2724 __ xorl(output_register, output_register);
2725 } else {
2726 __ movl(output_register, input_register);
2727 if (imm == -1) {
2728 __ negl(output_register);
2729 }
2730 }
2731 break;
2732 }
2733
2734 case Primitive::kPrimLong: {
2735 if (instruction->IsRem()) {
Mark Mendell92e83bf2015-05-07 11:25:03 -04002736 __ xorl(output_register, output_register);
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002737 } else {
2738 __ movq(output_register, input_register);
2739 if (imm == -1) {
2740 __ negq(output_register);
2741 }
2742 }
2743 break;
2744 }
2745
2746 default:
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002747 LOG(FATAL) << "Unexpected type for div by (-)1 " << instruction->GetResultType();
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002748 }
2749}
2750
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002751void InstructionCodeGeneratorX86_64::DivByPowerOfTwo(HDiv* instruction) {
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002752 LocationSummary* locations = instruction->GetLocations();
2753 Location second = locations->InAt(1);
2754
2755 CpuRegister output_register = locations->Out().AsRegister<CpuRegister>();
2756 CpuRegister numerator = locations->InAt(0).AsRegister<CpuRegister>();
2757
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002758 int64_t imm = Int64FromConstant(second.GetConstant());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002759
2760 DCHECK(IsPowerOfTwo(std::abs(imm)));
2761
2762 CpuRegister tmp = locations->GetTemp(0).AsRegister<CpuRegister>();
2763
2764 if (instruction->GetResultType() == Primitive::kPrimInt) {
2765 __ leal(tmp, Address(numerator, std::abs(imm) - 1));
2766 __ testl(numerator, numerator);
2767 __ cmov(kGreaterEqual, tmp, numerator);
2768 int shift = CTZ(imm);
2769 __ sarl(tmp, Immediate(shift));
2770
2771 if (imm < 0) {
2772 __ negl(tmp);
2773 }
2774
2775 __ movl(output_register, tmp);
2776 } else {
2777 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
2778 CpuRegister rdx = locations->GetTemp(0).AsRegister<CpuRegister>();
2779
Mark Mendell92e83bf2015-05-07 11:25:03 -04002780 codegen_->Load64BitValue(rdx, std::abs(imm) - 1);
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002781 __ addq(rdx, numerator);
2782 __ testq(numerator, numerator);
2783 __ cmov(kGreaterEqual, rdx, numerator);
2784 int shift = CTZ(imm);
2785 __ sarq(rdx, Immediate(shift));
2786
2787 if (imm < 0) {
2788 __ negq(rdx);
2789 }
2790
2791 __ movq(output_register, rdx);
2792 }
2793}
2794
2795void InstructionCodeGeneratorX86_64::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) {
2796 DCHECK(instruction->IsDiv() || instruction->IsRem());
2797
2798 LocationSummary* locations = instruction->GetLocations();
2799 Location second = locations->InAt(1);
2800
2801 CpuRegister numerator = instruction->IsDiv() ? locations->GetTemp(1).AsRegister<CpuRegister>()
2802 : locations->GetTemp(0).AsRegister<CpuRegister>();
2803 CpuRegister eax = locations->InAt(0).AsRegister<CpuRegister>();
2804 CpuRegister edx = instruction->IsDiv() ? locations->GetTemp(0).AsRegister<CpuRegister>()
2805 : locations->Out().AsRegister<CpuRegister>();
2806 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
2807
2808 DCHECK_EQ(RAX, eax.AsRegister());
2809 DCHECK_EQ(RDX, edx.AsRegister());
2810 if (instruction->IsDiv()) {
2811 DCHECK_EQ(RAX, out.AsRegister());
2812 } else {
2813 DCHECK_EQ(RDX, out.AsRegister());
2814 }
2815
2816 int64_t magic;
2817 int shift;
2818
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002819 // TODO: can these branches be written as one?
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002820 if (instruction->GetResultType() == Primitive::kPrimInt) {
2821 int imm = second.GetConstant()->AsIntConstant()->GetValue();
2822
2823 CalculateMagicAndShiftForDivRem(imm, false /* is_long */, &magic, &shift);
2824
2825 __ movl(numerator, eax);
2826
2827 Label no_div;
2828 Label end;
2829 __ testl(eax, eax);
2830 __ j(kNotEqual, &no_div);
2831
2832 __ xorl(out, out);
2833 __ jmp(&end);
2834
2835 __ Bind(&no_div);
2836
2837 __ movl(eax, Immediate(magic));
2838 __ imull(numerator);
2839
2840 if (imm > 0 && magic < 0) {
2841 __ addl(edx, numerator);
2842 } else if (imm < 0 && magic > 0) {
2843 __ subl(edx, numerator);
2844 }
2845
2846 if (shift != 0) {
2847 __ sarl(edx, Immediate(shift));
2848 }
2849
2850 __ movl(eax, edx);
2851 __ shrl(edx, Immediate(31));
2852 __ addl(edx, eax);
2853
2854 if (instruction->IsRem()) {
2855 __ movl(eax, numerator);
2856 __ imull(edx, Immediate(imm));
2857 __ subl(eax, edx);
2858 __ movl(edx, eax);
2859 } else {
2860 __ movl(eax, edx);
2861 }
2862 __ Bind(&end);
2863 } else {
2864 int64_t imm = second.GetConstant()->AsLongConstant()->GetValue();
2865
2866 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
2867
2868 CpuRegister rax = eax;
2869 CpuRegister rdx = edx;
2870
2871 CalculateMagicAndShiftForDivRem(imm, true /* is_long */, &magic, &shift);
2872
2873 // Save the numerator.
2874 __ movq(numerator, rax);
2875
2876 // RAX = magic
Mark Mendell92e83bf2015-05-07 11:25:03 -04002877 codegen_->Load64BitValue(rax, magic);
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002878
2879 // RDX:RAX = magic * numerator
2880 __ imulq(numerator);
2881
2882 if (imm > 0 && magic < 0) {
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002883 // RDX += numerator
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002884 __ addq(rdx, numerator);
2885 } else if (imm < 0 && magic > 0) {
2886 // RDX -= numerator
2887 __ subq(rdx, numerator);
2888 }
2889
2890 // Shift if needed.
2891 if (shift != 0) {
2892 __ sarq(rdx, Immediate(shift));
2893 }
2894
2895 // RDX += 1 if RDX < 0
2896 __ movq(rax, rdx);
2897 __ shrq(rdx, Immediate(63));
2898 __ addq(rdx, rax);
2899
2900 if (instruction->IsRem()) {
2901 __ movq(rax, numerator);
2902
2903 if (IsInt<32>(imm)) {
2904 __ imulq(rdx, Immediate(static_cast<int32_t>(imm)));
2905 } else {
Mark Mendell92e83bf2015-05-07 11:25:03 -04002906 __ imulq(rdx, codegen_->LiteralInt64Address(imm));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002907 }
2908
2909 __ subq(rax, rdx);
2910 __ movq(rdx, rax);
2911 } else {
2912 __ movq(rax, rdx);
2913 }
2914 }
2915}
2916
Calin Juravlebacfec32014-11-14 15:54:36 +00002917void InstructionCodeGeneratorX86_64::GenerateDivRemIntegral(HBinaryOperation* instruction) {
2918 DCHECK(instruction->IsDiv() || instruction->IsRem());
2919 Primitive::Type type = instruction->GetResultType();
2920 DCHECK(type == Primitive::kPrimInt || Primitive::kPrimLong);
2921
2922 bool is_div = instruction->IsDiv();
2923 LocationSummary* locations = instruction->GetLocations();
2924
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002925 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
2926 Location second = locations->InAt(1);
Calin Juravlebacfec32014-11-14 15:54:36 +00002927
Roland Levillain271ab9c2014-11-27 15:23:57 +00002928 DCHECK_EQ(RAX, locations->InAt(0).AsRegister<CpuRegister>().AsRegister());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002929 DCHECK_EQ(is_div ? RAX : RDX, out.AsRegister());
Calin Juravlebacfec32014-11-14 15:54:36 +00002930
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002931 if (second.IsConstant()) {
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002932 int64_t imm = Int64FromConstant(second.GetConstant());
Calin Juravlebacfec32014-11-14 15:54:36 +00002933
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002934 if (imm == 0) {
2935 // Do not generate anything. DivZeroCheck would prevent any code to be executed.
2936 } else if (imm == 1 || imm == -1) {
2937 DivRemOneOrMinusOne(instruction);
2938 } else if (instruction->IsDiv() && IsPowerOfTwo(std::abs(imm))) {
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002939 DivByPowerOfTwo(instruction->AsDiv());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002940 } else {
2941 DCHECK(imm <= -2 || imm >= 2);
2942 GenerateDivRemWithAnyConstant(instruction);
2943 }
Calin Juravlebacfec32014-11-14 15:54:36 +00002944 } else {
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002945 SlowPathCodeX86_64* slow_path =
2946 new (GetGraph()->GetArena()) DivRemMinusOneSlowPathX86_64(
2947 out.AsRegister(), type, is_div);
2948 codegen_->AddSlowPath(slow_path);
Calin Juravlebacfec32014-11-14 15:54:36 +00002949
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002950 CpuRegister second_reg = second.AsRegister<CpuRegister>();
2951 // 0x80000000(00000000)/-1 triggers an arithmetic exception!
2952 // Dividing by -1 is actually negation and -0x800000000(00000000) = 0x80000000(00000000)
2953 // so it's safe to just use negl instead of more complex comparisons.
2954 if (type == Primitive::kPrimInt) {
2955 __ cmpl(second_reg, Immediate(-1));
2956 __ j(kEqual, slow_path->GetEntryLabel());
2957 // edx:eax <- sign-extended of eax
2958 __ cdq();
2959 // eax = quotient, edx = remainder
2960 __ idivl(second_reg);
2961 } else {
2962 __ cmpq(second_reg, Immediate(-1));
2963 __ j(kEqual, slow_path->GetEntryLabel());
2964 // rdx:rax <- sign-extended of rax
2965 __ cqo();
2966 // rax = quotient, rdx = remainder
2967 __ idivq(second_reg);
2968 }
2969 __ Bind(slow_path->GetExitLabel());
2970 }
Calin Juravlebacfec32014-11-14 15:54:36 +00002971}
2972
Calin Juravle7c4954d2014-10-28 16:57:40 +00002973void LocationsBuilderX86_64::VisitDiv(HDiv* div) {
2974 LocationSummary* locations =
2975 new (GetGraph()->GetArena()) LocationSummary(div, LocationSummary::kNoCall);
2976 switch (div->GetResultType()) {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002977 case Primitive::kPrimInt:
2978 case Primitive::kPrimLong: {
Calin Juravled0d48522014-11-04 16:40:20 +00002979 locations->SetInAt(0, Location::RegisterLocation(RAX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002980 locations->SetInAt(1, Location::RegisterOrConstant(div->InputAt(1)));
Calin Juravled0d48522014-11-04 16:40:20 +00002981 locations->SetOut(Location::SameAsFirstInput());
2982 // Intel uses edx:eax as the dividend.
2983 locations->AddTemp(Location::RegisterLocation(RDX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002984 // We need to save the numerator while we tweak rax and rdx. As we are using imul in a way
2985 // which enforces results to be in RAX and RDX, things are simpler if we use RDX also as
2986 // output and request another temp.
2987 if (div->InputAt(1)->IsConstant()) {
2988 locations->AddTemp(Location::RequiresRegister());
2989 }
Calin Juravled0d48522014-11-04 16:40:20 +00002990 break;
2991 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002992
Calin Juravle7c4954d2014-10-28 16:57:40 +00002993 case Primitive::kPrimFloat:
2994 case Primitive::kPrimDouble: {
2995 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendellf55c3e02015-03-26 21:07:46 -04002996 locations->SetInAt(1, Location::Any());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002997 locations->SetOut(Location::SameAsFirstInput());
2998 break;
2999 }
3000
3001 default:
3002 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
3003 }
3004}
3005
3006void InstructionCodeGeneratorX86_64::VisitDiv(HDiv* div) {
3007 LocationSummary* locations = div->GetLocations();
3008 Location first = locations->InAt(0);
3009 Location second = locations->InAt(1);
3010 DCHECK(first.Equals(locations->Out()));
3011
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003012 Primitive::Type type = div->GetResultType();
3013 switch (type) {
3014 case Primitive::kPrimInt:
3015 case Primitive::kPrimLong: {
Calin Juravlebacfec32014-11-14 15:54:36 +00003016 GenerateDivRemIntegral(div);
Calin Juravled0d48522014-11-04 16:40:20 +00003017 break;
3018 }
3019
Calin Juravle7c4954d2014-10-28 16:57:40 +00003020 case Primitive::kPrimFloat: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04003021 if (second.IsFpuRegister()) {
3022 __ divss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
3023 } else if (second.IsConstant()) {
3024 __ divss(first.AsFpuRegister<XmmRegister>(),
3025 codegen_->LiteralFloatAddress(second.GetConstant()->AsFloatConstant()->GetValue()));
3026 } else {
3027 DCHECK(second.IsStackSlot());
3028 __ divss(first.AsFpuRegister<XmmRegister>(),
3029 Address(CpuRegister(RSP), second.GetStackIndex()));
3030 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00003031 break;
3032 }
3033
3034 case Primitive::kPrimDouble: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04003035 if (second.IsFpuRegister()) {
3036 __ divsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
3037 } else if (second.IsConstant()) {
3038 __ divsd(first.AsFpuRegister<XmmRegister>(),
3039 codegen_->LiteralDoubleAddress(second.GetConstant()->AsDoubleConstant()->GetValue()));
3040 } else {
3041 DCHECK(second.IsDoubleStackSlot());
3042 __ divsd(first.AsFpuRegister<XmmRegister>(),
3043 Address(CpuRegister(RSP), second.GetStackIndex()));
3044 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00003045 break;
3046 }
3047
3048 default:
3049 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
3050 }
3051}
3052
Calin Juravlebacfec32014-11-14 15:54:36 +00003053void LocationsBuilderX86_64::VisitRem(HRem* rem) {
Calin Juravled2ec87d2014-12-08 14:24:46 +00003054 Primitive::Type type = rem->GetResultType();
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003055 LocationSummary* locations =
3056 new (GetGraph()->GetArena()) LocationSummary(rem, LocationSummary::kNoCall);
Calin Juravled2ec87d2014-12-08 14:24:46 +00003057
3058 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00003059 case Primitive::kPrimInt:
3060 case Primitive::kPrimLong: {
3061 locations->SetInAt(0, Location::RegisterLocation(RAX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003062 locations->SetInAt(1, Location::RegisterOrConstant(rem->InputAt(1)));
Calin Juravlebacfec32014-11-14 15:54:36 +00003063 // Intel uses rdx:rax as the dividend and puts the remainder in rdx
3064 locations->SetOut(Location::RegisterLocation(RDX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003065 // We need to save the numerator while we tweak eax and edx. As we are using imul in a way
3066 // which enforces results to be in RAX and RDX, things are simpler if we use EAX also as
3067 // output and request another temp.
3068 if (rem->InputAt(1)->IsConstant()) {
3069 locations->AddTemp(Location::RequiresRegister());
3070 }
Calin Juravlebacfec32014-11-14 15:54:36 +00003071 break;
3072 }
3073
3074 case Primitive::kPrimFloat:
3075 case Primitive::kPrimDouble: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003076 locations->SetInAt(0, Location::Any());
3077 locations->SetInAt(1, Location::Any());
3078 locations->SetOut(Location::RequiresFpuRegister());
3079 locations->AddTemp(Location::RegisterLocation(RAX));
Calin Juravlebacfec32014-11-14 15:54:36 +00003080 break;
3081 }
3082
3083 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00003084 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00003085 }
3086}
3087
3088void InstructionCodeGeneratorX86_64::VisitRem(HRem* rem) {
3089 Primitive::Type type = rem->GetResultType();
3090 switch (type) {
3091 case Primitive::kPrimInt:
3092 case Primitive::kPrimLong: {
3093 GenerateDivRemIntegral(rem);
3094 break;
3095 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003096 case Primitive::kPrimFloat:
Calin Juravled2ec87d2014-12-08 14:24:46 +00003097 case Primitive::kPrimDouble: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003098 GenerateRemFP(rem);
Calin Juravled2ec87d2014-12-08 14:24:46 +00003099 break;
3100 }
Calin Juravlebacfec32014-11-14 15:54:36 +00003101 default:
3102 LOG(FATAL) << "Unexpected rem type " << rem->GetResultType();
3103 }
3104}
3105
Calin Juravled0d48522014-11-04 16:40:20 +00003106void LocationsBuilderX86_64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
3107 LocationSummary* locations =
3108 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3109 locations->SetInAt(0, Location::Any());
3110 if (instruction->HasUses()) {
3111 locations->SetOut(Location::SameAsFirstInput());
3112 }
3113}
3114
3115void InstructionCodeGeneratorX86_64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
3116 SlowPathCodeX86_64* slow_path =
3117 new (GetGraph()->GetArena()) DivZeroCheckSlowPathX86_64(instruction);
3118 codegen_->AddSlowPath(slow_path);
3119
3120 LocationSummary* locations = instruction->GetLocations();
3121 Location value = locations->InAt(0);
3122
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003123 switch (instruction->GetType()) {
3124 case Primitive::kPrimInt: {
3125 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003126 __ testl(value.AsRegister<CpuRegister>(), value.AsRegister<CpuRegister>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003127 __ j(kEqual, slow_path->GetEntryLabel());
3128 } else if (value.IsStackSlot()) {
3129 __ cmpl(Address(CpuRegister(RSP), value.GetStackIndex()), Immediate(0));
3130 __ j(kEqual, slow_path->GetEntryLabel());
3131 } else {
3132 DCHECK(value.IsConstant()) << value;
3133 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
3134 __ jmp(slow_path->GetEntryLabel());
3135 }
3136 }
3137 break;
Calin Juravled0d48522014-11-04 16:40:20 +00003138 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003139 case Primitive::kPrimLong: {
3140 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003141 __ testq(value.AsRegister<CpuRegister>(), value.AsRegister<CpuRegister>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003142 __ j(kEqual, slow_path->GetEntryLabel());
3143 } else if (value.IsDoubleStackSlot()) {
3144 __ cmpq(Address(CpuRegister(RSP), value.GetStackIndex()), Immediate(0));
3145 __ j(kEqual, slow_path->GetEntryLabel());
3146 } else {
3147 DCHECK(value.IsConstant()) << value;
3148 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
3149 __ jmp(slow_path->GetEntryLabel());
3150 }
3151 }
3152 break;
3153 }
3154 default:
3155 LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
Calin Juravled0d48522014-11-04 16:40:20 +00003156 }
Calin Juravled0d48522014-11-04 16:40:20 +00003157}
3158
Calin Juravle9aec02f2014-11-18 23:06:35 +00003159void LocationsBuilderX86_64::HandleShift(HBinaryOperation* op) {
3160 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
3161
3162 LocationSummary* locations =
3163 new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
3164
3165 switch (op->GetResultType()) {
3166 case Primitive::kPrimInt:
3167 case Primitive::kPrimLong: {
3168 locations->SetInAt(0, Location::RequiresRegister());
3169 // The shift count needs to be in CL.
3170 locations->SetInAt(1, Location::ByteRegisterOrConstant(RCX, op->InputAt(1)));
3171 locations->SetOut(Location::SameAsFirstInput());
3172 break;
3173 }
3174 default:
3175 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
3176 }
3177}
3178
3179void InstructionCodeGeneratorX86_64::HandleShift(HBinaryOperation* op) {
3180 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
3181
3182 LocationSummary* locations = op->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003183 CpuRegister first_reg = locations->InAt(0).AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003184 Location second = locations->InAt(1);
3185
3186 switch (op->GetResultType()) {
3187 case Primitive::kPrimInt: {
3188 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003189 CpuRegister second_reg = second.AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003190 if (op->IsShl()) {
3191 __ shll(first_reg, second_reg);
3192 } else if (op->IsShr()) {
3193 __ sarl(first_reg, second_reg);
3194 } else {
3195 __ shrl(first_reg, second_reg);
3196 }
3197 } else {
Nicolas Geoffray486cc192014-12-08 18:00:55 +00003198 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxIntShiftValue);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003199 if (op->IsShl()) {
3200 __ shll(first_reg, imm);
3201 } else if (op->IsShr()) {
3202 __ sarl(first_reg, imm);
3203 } else {
3204 __ shrl(first_reg, imm);
3205 }
3206 }
3207 break;
3208 }
3209 case Primitive::kPrimLong: {
3210 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003211 CpuRegister second_reg = second.AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003212 if (op->IsShl()) {
3213 __ shlq(first_reg, second_reg);
3214 } else if (op->IsShr()) {
3215 __ sarq(first_reg, second_reg);
3216 } else {
3217 __ shrq(first_reg, second_reg);
3218 }
3219 } else {
Nicolas Geoffray486cc192014-12-08 18:00:55 +00003220 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxLongShiftValue);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003221 if (op->IsShl()) {
3222 __ shlq(first_reg, imm);
3223 } else if (op->IsShr()) {
3224 __ sarq(first_reg, imm);
3225 } else {
3226 __ shrq(first_reg, imm);
3227 }
3228 }
3229 break;
3230 }
3231 default:
3232 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
3233 }
3234}
3235
3236void LocationsBuilderX86_64::VisitShl(HShl* shl) {
3237 HandleShift(shl);
3238}
3239
3240void InstructionCodeGeneratorX86_64::VisitShl(HShl* shl) {
3241 HandleShift(shl);
3242}
3243
3244void LocationsBuilderX86_64::VisitShr(HShr* shr) {
3245 HandleShift(shr);
3246}
3247
3248void InstructionCodeGeneratorX86_64::VisitShr(HShr* shr) {
3249 HandleShift(shr);
3250}
3251
3252void LocationsBuilderX86_64::VisitUShr(HUShr* ushr) {
3253 HandleShift(ushr);
3254}
3255
3256void InstructionCodeGeneratorX86_64::VisitUShr(HUShr* ushr) {
3257 HandleShift(ushr);
3258}
3259
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003260void LocationsBuilderX86_64::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003261 LocationSummary* locations =
3262 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01003263 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003264 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Nicolas Geoffray69aa6012015-06-09 10:34:25 +01003265 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003266 locations->SetOut(Location::RegisterLocation(RAX));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003267}
3268
3269void InstructionCodeGeneratorX86_64::VisitNewInstance(HNewInstance* instruction) {
3270 InvokeRuntimeCallingConvention calling_convention;
Mark Mendell92e83bf2015-05-07 11:25:03 -04003271 codegen_->Load64BitValue(CpuRegister(calling_convention.GetRegisterAt(0)),
3272 instruction->GetTypeIndex());
Roland Levillain4d027112015-07-01 15:41:14 +01003273 // Note: if heap poisoning is enabled, the entry point takes cares
3274 // of poisoning the reference.
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +00003275 __ gs()->call(
3276 Address::Absolute(GetThreadOffset<kX86_64WordSize>(instruction->GetEntrypoint()), true));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003277
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01003278 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray39468442014-09-02 15:17:15 +01003279 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003280}
3281
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003282void LocationsBuilderX86_64::VisitNewArray(HNewArray* instruction) {
3283 LocationSummary* locations =
3284 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
3285 InvokeRuntimeCallingConvention calling_convention;
3286 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003287 locations->SetOut(Location::RegisterLocation(RAX));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08003288 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray69aa6012015-06-09 10:34:25 +01003289 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003290}
3291
3292void InstructionCodeGeneratorX86_64::VisitNewArray(HNewArray* instruction) {
3293 InvokeRuntimeCallingConvention calling_convention;
Mark Mendell92e83bf2015-05-07 11:25:03 -04003294 codegen_->Load64BitValue(CpuRegister(calling_convention.GetRegisterAt(0)),
3295 instruction->GetTypeIndex());
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003296
Roland Levillain4d027112015-07-01 15:41:14 +01003297 // Note: if heap poisoning is enabled, the entry point takes cares
3298 // of poisoning the reference.
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +00003299 __ gs()->call(
3300 Address::Absolute(GetThreadOffset<kX86_64WordSize>(instruction->GetEntrypoint()), true));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003301
3302 DCHECK(!codegen_->IsLeafMethod());
3303 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3304}
3305
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003306void LocationsBuilderX86_64::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003307 LocationSummary* locations =
3308 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003309 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
3310 if (location.IsStackSlot()) {
3311 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
3312 } else if (location.IsDoubleStackSlot()) {
3313 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
3314 }
3315 locations->SetOut(location);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003316}
3317
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01003318void InstructionCodeGeneratorX86_64::VisitParameterValue(
3319 HParameterValue* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003320 // Nothing to do, the parameter is already at its location.
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01003321}
3322
3323void LocationsBuilderX86_64::VisitCurrentMethod(HCurrentMethod* instruction) {
3324 LocationSummary* locations =
3325 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3326 locations->SetOut(Location::RegisterLocation(kMethodRegisterArgument));
3327}
3328
3329void InstructionCodeGeneratorX86_64::VisitCurrentMethod(
3330 HCurrentMethod* instruction ATTRIBUTE_UNUSED) {
3331 // Nothing to do, the method is already at its location.
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003332}
3333
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003334void LocationsBuilderX86_64::VisitNot(HNot* not_) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003335 LocationSummary* locations =
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003336 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003337 locations->SetInAt(0, Location::RequiresRegister());
3338 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003339}
3340
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003341void InstructionCodeGeneratorX86_64::VisitNot(HNot* not_) {
3342 LocationSummary* locations = not_->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003343 DCHECK_EQ(locations->InAt(0).AsRegister<CpuRegister>().AsRegister(),
3344 locations->Out().AsRegister<CpuRegister>().AsRegister());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003345 Location out = locations->Out();
Nicolas Geoffrayd8ef2e92015-02-24 16:02:06 +00003346 switch (not_->GetResultType()) {
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003347 case Primitive::kPrimInt:
Roland Levillain271ab9c2014-11-27 15:23:57 +00003348 __ notl(out.AsRegister<CpuRegister>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003349 break;
3350
3351 case Primitive::kPrimLong:
Roland Levillain271ab9c2014-11-27 15:23:57 +00003352 __ notq(out.AsRegister<CpuRegister>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003353 break;
3354
3355 default:
3356 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
3357 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003358}
3359
David Brazdil66d126e2015-04-03 16:02:44 +01003360void LocationsBuilderX86_64::VisitBooleanNot(HBooleanNot* bool_not) {
3361 LocationSummary* locations =
3362 new (GetGraph()->GetArena()) LocationSummary(bool_not, LocationSummary::kNoCall);
3363 locations->SetInAt(0, Location::RequiresRegister());
3364 locations->SetOut(Location::SameAsFirstInput());
3365}
3366
3367void InstructionCodeGeneratorX86_64::VisitBooleanNot(HBooleanNot* bool_not) {
David Brazdil66d126e2015-04-03 16:02:44 +01003368 LocationSummary* locations = bool_not->GetLocations();
3369 DCHECK_EQ(locations->InAt(0).AsRegister<CpuRegister>().AsRegister(),
3370 locations->Out().AsRegister<CpuRegister>().AsRegister());
3371 Location out = locations->Out();
3372 __ xorl(out.AsRegister<CpuRegister>(), Immediate(1));
3373}
3374
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003375void LocationsBuilderX86_64::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003376 LocationSummary* locations =
3377 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003378 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
3379 locations->SetInAt(i, Location::Any());
3380 }
3381 locations->SetOut(Location::Any());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003382}
3383
3384void InstructionCodeGeneratorX86_64::VisitPhi(HPhi* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003385 UNUSED(instruction);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003386 LOG(FATAL) << "Unimplemented";
3387}
3388
Calin Juravle52c48962014-12-16 17:02:57 +00003389void InstructionCodeGeneratorX86_64::GenerateMemoryBarrier(MemBarrierKind kind) {
3390 /*
3391 * According to the JSR-133 Cookbook, for x86 only StoreLoad/AnyAny barriers need memory fence.
3392 * All other barriers (LoadAny, AnyStore, StoreStore) are nops due to the x86 memory model.
3393 * For those cases, all we need to ensure is that there is a scheduling barrier in place.
3394 */
3395 switch (kind) {
3396 case MemBarrierKind::kAnyAny: {
3397 __ mfence();
3398 break;
3399 }
3400 case MemBarrierKind::kAnyStore:
3401 case MemBarrierKind::kLoadAny:
3402 case MemBarrierKind::kStoreStore: {
3403 // nop
3404 break;
3405 }
3406 default:
3407 LOG(FATAL) << "Unexpected memory barier " << kind;
3408 }
3409}
3410
3411void LocationsBuilderX86_64::HandleFieldGet(HInstruction* instruction) {
3412 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
3413
Nicolas Geoffray39468442014-09-02 15:17:15 +01003414 LocationSummary* locations =
3415 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Calin Juravle52c48962014-12-16 17:02:57 +00003416 locations->SetInAt(0, Location::RequiresRegister());
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003417 if (Primitive::IsFloatingPointType(instruction->GetType())) {
3418 locations->SetOut(Location::RequiresFpuRegister());
3419 } else {
3420 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3421 }
Calin Juravle52c48962014-12-16 17:02:57 +00003422}
3423
3424void InstructionCodeGeneratorX86_64::HandleFieldGet(HInstruction* instruction,
3425 const FieldInfo& field_info) {
3426 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
3427
3428 LocationSummary* locations = instruction->GetLocations();
3429 CpuRegister base = locations->InAt(0).AsRegister<CpuRegister>();
3430 Location out = locations->Out();
3431 bool is_volatile = field_info.IsVolatile();
3432 Primitive::Type field_type = field_info.GetFieldType();
3433 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
3434
3435 switch (field_type) {
3436 case Primitive::kPrimBoolean: {
3437 __ movzxb(out.AsRegister<CpuRegister>(), Address(base, offset));
3438 break;
3439 }
3440
3441 case Primitive::kPrimByte: {
3442 __ movsxb(out.AsRegister<CpuRegister>(), Address(base, offset));
3443 break;
3444 }
3445
3446 case Primitive::kPrimShort: {
3447 __ movsxw(out.AsRegister<CpuRegister>(), Address(base, offset));
3448 break;
3449 }
3450
3451 case Primitive::kPrimChar: {
3452 __ movzxw(out.AsRegister<CpuRegister>(), Address(base, offset));
3453 break;
3454 }
3455
3456 case Primitive::kPrimInt:
3457 case Primitive::kPrimNot: {
3458 __ movl(out.AsRegister<CpuRegister>(), Address(base, offset));
3459 break;
3460 }
3461
3462 case Primitive::kPrimLong: {
3463 __ movq(out.AsRegister<CpuRegister>(), Address(base, offset));
3464 break;
3465 }
3466
3467 case Primitive::kPrimFloat: {
3468 __ movss(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
3469 break;
3470 }
3471
3472 case Primitive::kPrimDouble: {
3473 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
3474 break;
3475 }
3476
3477 case Primitive::kPrimVoid:
3478 LOG(FATAL) << "Unreachable type " << field_type;
3479 UNREACHABLE();
3480 }
3481
Calin Juravle77520bc2015-01-12 18:45:46 +00003482 codegen_->MaybeRecordImplicitNullCheck(instruction);
3483
Calin Juravle52c48962014-12-16 17:02:57 +00003484 if (is_volatile) {
3485 GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
3486 }
Roland Levillain4d027112015-07-01 15:41:14 +01003487
3488 if (field_type == Primitive::kPrimNot) {
3489 __ MaybeUnpoisonHeapReference(out.AsRegister<CpuRegister>());
3490 }
Calin Juravle52c48962014-12-16 17:02:57 +00003491}
3492
3493void LocationsBuilderX86_64::HandleFieldSet(HInstruction* instruction,
3494 const FieldInfo& field_info) {
3495 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3496
3497 LocationSummary* locations =
3498 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Roland Levillain4d027112015-07-01 15:41:14 +01003499 Primitive::Type field_type = field_info.GetFieldType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003500 bool needs_write_barrier =
Roland Levillain4d027112015-07-01 15:41:14 +01003501 CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
Calin Juravle52c48962014-12-16 17:02:57 +00003502
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003503 locations->SetInAt(0, Location::RequiresRegister());
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003504 if (Primitive::IsFloatingPointType(instruction->InputAt(1)->GetType())) {
3505 locations->SetInAt(1, Location::RequiresFpuRegister());
3506 } else {
Mark Mendell40741f32015-04-20 22:10:34 -04003507 locations->SetInAt(1, Location::RegisterOrInt32LongConstant(instruction->InputAt(1)));
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003508 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003509 if (needs_write_barrier) {
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01003510 // Temporary registers for the write barrier.
Roland Levillain4d027112015-07-01 15:41:14 +01003511 locations->AddTemp(Location::RequiresRegister()); // Possibly used for reference poisoning too.
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003512 locations->AddTemp(Location::RequiresRegister());
Roland Levillain4d027112015-07-01 15:41:14 +01003513 } else if (kPoisonHeapReferences && field_type == Primitive::kPrimNot) {
3514 // Temporary register for the reference poisoning.
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003515 locations->AddTemp(Location::RequiresRegister());
3516 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003517}
3518
Calin Juravle52c48962014-12-16 17:02:57 +00003519void InstructionCodeGeneratorX86_64::HandleFieldSet(HInstruction* instruction,
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003520 const FieldInfo& field_info,
3521 bool value_can_be_null) {
Calin Juravle52c48962014-12-16 17:02:57 +00003522 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3523
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003524 LocationSummary* locations = instruction->GetLocations();
Calin Juravle52c48962014-12-16 17:02:57 +00003525 CpuRegister base = locations->InAt(0).AsRegister<CpuRegister>();
3526 Location value = locations->InAt(1);
3527 bool is_volatile = field_info.IsVolatile();
3528 Primitive::Type field_type = field_info.GetFieldType();
3529 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
3530
3531 if (is_volatile) {
3532 GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
3533 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003534
3535 switch (field_type) {
3536 case Primitive::kPrimBoolean:
3537 case Primitive::kPrimByte: {
Mark Mendell40741f32015-04-20 22:10:34 -04003538 if (value.IsConstant()) {
3539 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
3540 __ movb(Address(base, offset), Immediate(v));
3541 } else {
3542 __ movb(Address(base, offset), value.AsRegister<CpuRegister>());
3543 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003544 break;
3545 }
3546
3547 case Primitive::kPrimShort:
3548 case Primitive::kPrimChar: {
Mark Mendell40741f32015-04-20 22:10:34 -04003549 if (value.IsConstant()) {
3550 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
3551 __ movw(Address(base, offset), Immediate(v));
3552 } else {
3553 __ movw(Address(base, offset), value.AsRegister<CpuRegister>());
3554 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003555 break;
3556 }
3557
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003558 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003559 case Primitive::kPrimNot: {
Mark Mendell40741f32015-04-20 22:10:34 -04003560 if (value.IsConstant()) {
3561 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
Roland Levillain4d027112015-07-01 15:41:14 +01003562 // `field_type == Primitive::kPrimNot` implies `v == 0`.
3563 DCHECK((field_type != Primitive::kPrimNot) || (v == 0));
3564 // Note: if heap poisoning is enabled, no need to poison
3565 // (negate) `v` if it is a reference, as it would be null.
Roland Levillain06b66d02015-07-01 12:47:25 +01003566 __ movl(Address(base, offset), Immediate(v));
Mark Mendell40741f32015-04-20 22:10:34 -04003567 } else {
Roland Levillain4d027112015-07-01 15:41:14 +01003568 if (kPoisonHeapReferences && field_type == Primitive::kPrimNot) {
3569 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
3570 __ movl(temp, value.AsRegister<CpuRegister>());
3571 __ PoisonHeapReference(temp);
3572 __ movl(Address(base, offset), temp);
3573 } else {
3574 __ movl(Address(base, offset), value.AsRegister<CpuRegister>());
3575 }
Mark Mendell40741f32015-04-20 22:10:34 -04003576 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003577 break;
3578 }
3579
3580 case Primitive::kPrimLong: {
Mark Mendell40741f32015-04-20 22:10:34 -04003581 if (value.IsConstant()) {
3582 int64_t v = value.GetConstant()->AsLongConstant()->GetValue();
3583 DCHECK(IsInt<32>(v));
3584 int32_t v_32 = v;
3585 __ movq(Address(base, offset), Immediate(v_32));
3586 } else {
3587 __ movq(Address(base, offset), value.AsRegister<CpuRegister>());
3588 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003589 break;
3590 }
3591
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003592 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00003593 __ movss(Address(base, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003594 break;
3595 }
3596
3597 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00003598 __ movsd(Address(base, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003599 break;
3600 }
3601
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003602 case Primitive::kPrimVoid:
3603 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003604 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003605 }
Calin Juravle52c48962014-12-16 17:02:57 +00003606
Calin Juravle77520bc2015-01-12 18:45:46 +00003607 codegen_->MaybeRecordImplicitNullCheck(instruction);
3608
3609 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
3610 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
3611 CpuRegister card = locations->GetTemp(1).AsRegister<CpuRegister>();
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003612 codegen_->MarkGCCard(temp, card, base, value.AsRegister<CpuRegister>(), value_can_be_null);
Calin Juravle77520bc2015-01-12 18:45:46 +00003613 }
3614
Calin Juravle52c48962014-12-16 17:02:57 +00003615 if (is_volatile) {
3616 GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
3617 }
3618}
3619
3620void LocationsBuilderX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
3621 HandleFieldSet(instruction, instruction->GetFieldInfo());
3622}
3623
3624void InstructionCodeGeneratorX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003625 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003626}
3627
3628void LocationsBuilderX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Calin Juravle52c48962014-12-16 17:02:57 +00003629 HandleFieldGet(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003630}
3631
3632void InstructionCodeGeneratorX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Calin Juravle52c48962014-12-16 17:02:57 +00003633 HandleFieldGet(instruction, instruction->GetFieldInfo());
3634}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003635
Calin Juravle52c48962014-12-16 17:02:57 +00003636void LocationsBuilderX86_64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
3637 HandleFieldGet(instruction);
3638}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003639
Calin Juravle52c48962014-12-16 17:02:57 +00003640void InstructionCodeGeneratorX86_64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
3641 HandleFieldGet(instruction, instruction->GetFieldInfo());
3642}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003643
Calin Juravle52c48962014-12-16 17:02:57 +00003644void LocationsBuilderX86_64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
3645 HandleFieldSet(instruction, instruction->GetFieldInfo());
3646}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003647
Calin Juravle52c48962014-12-16 17:02:57 +00003648void InstructionCodeGeneratorX86_64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003649 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003650}
3651
3652void LocationsBuilderX86_64::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003653 LocationSummary* locations =
3654 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003655 Location loc = codegen_->GetCompilerOptions().GetImplicitNullChecks()
3656 ? Location::RequiresRegister()
3657 : Location::Any();
3658 locations->SetInAt(0, loc);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003659 if (instruction->HasUses()) {
3660 locations->SetOut(Location::SameAsFirstInput());
3661 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003662}
3663
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003664void InstructionCodeGeneratorX86_64::GenerateImplicitNullCheck(HNullCheck* instruction) {
Calin Juravle77520bc2015-01-12 18:45:46 +00003665 if (codegen_->CanMoveNullCheckToUser(instruction)) {
3666 return;
3667 }
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003668 LocationSummary* locations = instruction->GetLocations();
3669 Location obj = locations->InAt(0);
3670
3671 __ testl(CpuRegister(RAX), Address(obj.AsRegister<CpuRegister>(), 0));
3672 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3673}
3674
3675void InstructionCodeGeneratorX86_64::GenerateExplicitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +01003676 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathX86_64(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003677 codegen_->AddSlowPath(slow_path);
3678
3679 LocationSummary* locations = instruction->GetLocations();
3680 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003681
3682 if (obj.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00003683 __ testl(obj.AsRegister<CpuRegister>(), obj.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003684 } else if (obj.IsStackSlot()) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003685 __ cmpl(Address(CpuRegister(RSP), obj.GetStackIndex()), Immediate(0));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003686 } else {
3687 DCHECK(obj.IsConstant()) << obj;
3688 DCHECK_EQ(obj.GetConstant()->AsIntConstant()->GetValue(), 0);
3689 __ jmp(slow_path->GetEntryLabel());
3690 return;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003691 }
3692 __ j(kEqual, slow_path->GetEntryLabel());
3693}
3694
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003695void InstructionCodeGeneratorX86_64::VisitNullCheck(HNullCheck* instruction) {
3696 if (codegen_->GetCompilerOptions().GetImplicitNullChecks()) {
3697 GenerateImplicitNullCheck(instruction);
3698 } else {
3699 GenerateExplicitNullCheck(instruction);
3700 }
3701}
3702
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003703void LocationsBuilderX86_64::VisitArrayGet(HArrayGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003704 LocationSummary* locations =
3705 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003706 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell40741f32015-04-20 22:10:34 -04003707 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003708 if (Primitive::IsFloatingPointType(instruction->GetType())) {
3709 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
3710 } else {
3711 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3712 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003713}
3714
3715void InstructionCodeGeneratorX86_64::VisitArrayGet(HArrayGet* instruction) {
3716 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003717 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003718 Location index = locations->InAt(1);
Roland Levillain4d027112015-07-01 15:41:14 +01003719 Primitive::Type type = instruction->GetType();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003720
Roland Levillain4d027112015-07-01 15:41:14 +01003721 switch (type) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003722 case Primitive::kPrimBoolean: {
3723 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003724 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003725 if (index.IsConstant()) {
3726 __ movzxb(out, Address(obj,
3727 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
3728 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003729 __ movzxb(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003730 }
3731 break;
3732 }
3733
3734 case Primitive::kPrimByte: {
3735 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003736 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003737 if (index.IsConstant()) {
3738 __ movsxb(out, Address(obj,
3739 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
3740 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003741 __ movsxb(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003742 }
3743 break;
3744 }
3745
3746 case Primitive::kPrimShort: {
3747 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003748 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003749 if (index.IsConstant()) {
3750 __ movsxw(out, Address(obj,
3751 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
3752 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003753 __ movsxw(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003754 }
3755 break;
3756 }
3757
3758 case Primitive::kPrimChar: {
3759 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003760 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003761 if (index.IsConstant()) {
3762 __ movzxw(out, Address(obj,
3763 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
3764 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003765 __ movzxw(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003766 }
3767 break;
3768 }
3769
3770 case Primitive::kPrimInt:
3771 case Primitive::kPrimNot: {
Roland Levillain33d69032015-06-18 18:20:59 +01003772 static_assert(sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
3773 "art::mirror::HeapReference<mirror::Object> and int32_t have different sizes.");
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003774 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003775 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003776 if (index.IsConstant()) {
3777 __ movl(out, Address(obj,
3778 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
3779 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003780 __ movl(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003781 }
3782 break;
3783 }
3784
3785 case Primitive::kPrimLong: {
3786 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003787 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003788 if (index.IsConstant()) {
3789 __ movq(out, Address(obj,
3790 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
3791 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003792 __ movq(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003793 }
3794 break;
3795 }
3796
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003797 case Primitive::kPrimFloat: {
3798 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003799 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003800 if (index.IsConstant()) {
3801 __ movss(out, Address(obj,
3802 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
3803 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003804 __ movss(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003805 }
3806 break;
3807 }
3808
3809 case Primitive::kPrimDouble: {
3810 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003811 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003812 if (index.IsConstant()) {
3813 __ movsd(out, Address(obj,
3814 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
3815 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003816 __ movsd(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003817 }
3818 break;
3819 }
3820
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003821 case Primitive::kPrimVoid:
Roland Levillain4d027112015-07-01 15:41:14 +01003822 LOG(FATAL) << "Unreachable type " << type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003823 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003824 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003825 codegen_->MaybeRecordImplicitNullCheck(instruction);
Roland Levillain4d027112015-07-01 15:41:14 +01003826
3827 if (type == Primitive::kPrimNot) {
3828 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
3829 __ MaybeUnpoisonHeapReference(out);
3830 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003831}
3832
3833void LocationsBuilderX86_64::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003834 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003835
3836 bool needs_write_barrier =
3837 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
3838 bool needs_runtime_call = instruction->NeedsTypeCheck();
3839
Nicolas Geoffray39468442014-09-02 15:17:15 +01003840 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003841 instruction, needs_runtime_call ? LocationSummary::kCall : LocationSummary::kNoCall);
3842 if (needs_runtime_call) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003843 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003844 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3845 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
3846 locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003847 } else {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003848 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01003849 locations->SetInAt(
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003850 1, Location::RegisterOrConstant(instruction->InputAt(1)));
3851 locations->SetInAt(2, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003852 if (value_type == Primitive::kPrimLong) {
Mark Mendell40741f32015-04-20 22:10:34 -04003853 locations->SetInAt(2, Location::RegisterOrInt32LongConstant(instruction->InputAt(2)));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003854 } else if (value_type == Primitive::kPrimFloat || value_type == Primitive::kPrimDouble) {
3855 locations->SetInAt(2, Location::RequiresFpuRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003856 } else {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003857 locations->SetInAt(2, Location::RegisterOrConstant(instruction->InputAt(2)));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003858 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003859
3860 if (needs_write_barrier) {
3861 // Temporary registers for the write barrier.
Roland Levillain4d027112015-07-01 15:41:14 +01003862 locations->AddTemp(Location::RequiresRegister()); // Possibly used for ref. poisoning too.
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003863 locations->AddTemp(Location::RequiresRegister());
3864 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003865 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003866}
3867
3868void InstructionCodeGeneratorX86_64::VisitArraySet(HArraySet* instruction) {
3869 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003870 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003871 Location index = locations->InAt(1);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003872 Location value = locations->InAt(2);
Nicolas Geoffray39468442014-09-02 15:17:15 +01003873 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003874 bool needs_runtime_call = locations->WillCall();
3875 bool needs_write_barrier =
3876 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003877
3878 switch (value_type) {
3879 case Primitive::kPrimBoolean:
3880 case Primitive::kPrimByte: {
3881 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003882 if (index.IsConstant()) {
3883 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003884 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003885 __ movb(Address(obj, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003886 } else {
Roland Levillain199f3362014-11-27 17:15:16 +00003887 __ movb(Address(obj, offset),
3888 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003889 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003890 } else {
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003891 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003892 __ movb(Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset),
3893 value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003894 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003895 __ movb(Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003896 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3897 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003898 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003899 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003900 break;
3901 }
3902
3903 case Primitive::kPrimShort:
3904 case Primitive::kPrimChar: {
3905 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003906 if (index.IsConstant()) {
3907 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003908 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003909 __ movw(Address(obj, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003910 } else {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003911 DCHECK(value.IsConstant()) << value;
Roland Levillain199f3362014-11-27 17:15:16 +00003912 __ movw(Address(obj, offset),
3913 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003914 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003915 } else {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003916 DCHECK(index.IsRegister()) << index;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003917 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003918 __ movw(Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset),
3919 value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003920 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003921 DCHECK(value.IsConstant()) << value;
Roland Levillain271ab9c2014-11-27 15:23:57 +00003922 __ movw(Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003923 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3924 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003925 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003926 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003927 break;
3928 }
3929
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003930 case Primitive::kPrimInt:
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003931 case Primitive::kPrimNot: {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003932 if (!needs_runtime_call) {
3933 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
3934 if (index.IsConstant()) {
3935 size_t offset =
3936 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
3937 if (value.IsRegister()) {
Roland Levillain4d027112015-07-01 15:41:14 +01003938 if (kPoisonHeapReferences && value_type == Primitive::kPrimNot) {
3939 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
3940 __ movl(temp, value.AsRegister<CpuRegister>());
3941 __ PoisonHeapReference(temp);
3942 __ movl(Address(obj, offset), temp);
3943 } else {
3944 __ movl(Address(obj, offset), value.AsRegister<CpuRegister>());
3945 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003946 } else {
3947 DCHECK(value.IsConstant()) << value;
Mark Mendell40741f32015-04-20 22:10:34 -04003948 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
Roland Levillain4d027112015-07-01 15:41:14 +01003949 // `value_type == Primitive::kPrimNot` implies `v == 0`.
3950 DCHECK((value_type != Primitive::kPrimNot) || (v == 0));
3951 // Note: if heap poisoning is enabled, no need to poison
3952 // (negate) `v` if it is a reference, as it would be null.
Mark Mendell40741f32015-04-20 22:10:34 -04003953 __ movl(Address(obj, offset), Immediate(v));
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003954 }
3955 } else {
3956 DCHECK(index.IsRegister()) << index;
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, index.AsRegister<CpuRegister>(), TIMES_4, data_offset), temp);
3963 } else {
3964 __ movl(Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset),
3965 value.AsRegister<CpuRegister>());
3966 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003967 } else {
3968 DCHECK(value.IsConstant()) << value;
Mark Mendell40741f32015-04-20 22:10:34 -04003969 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
Roland Levillain4d027112015-07-01 15:41:14 +01003970 // `value_type == Primitive::kPrimNot` implies `v == 0`.
3971 DCHECK((value_type != Primitive::kPrimNot) || (v == 0));
3972 // Note: if heap poisoning is enabled, no need to poison
3973 // (negate) `v` if it is a reference, as it would be null.
Roland Levillain271ab9c2014-11-27 15:23:57 +00003974 __ movl(Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset),
Mark Mendell40741f32015-04-20 22:10:34 -04003975 Immediate(v));
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003976 }
3977 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003978 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003979 if (needs_write_barrier) {
3980 DCHECK_EQ(value_type, Primitive::kPrimNot);
Roland Levillain271ab9c2014-11-27 15:23:57 +00003981 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
3982 CpuRegister card = locations->GetTemp(1).AsRegister<CpuRegister>();
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003983 codegen_->MarkGCCard(
3984 temp, card, obj, value.AsRegister<CpuRegister>(), instruction->GetValueCanBeNull());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003985 }
3986 } else {
3987 DCHECK_EQ(value_type, Primitive::kPrimNot);
Roland Levillain4d027112015-07-01 15:41:14 +01003988 // Note: if heap poisoning is enabled, pAputObject takes cares
3989 // of poisoning the reference.
Roland Levillain199f3362014-11-27 17:15:16 +00003990 __ gs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pAputObject),
3991 true));
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003992 DCHECK(!codegen_->IsLeafMethod());
3993 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3994 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003995 break;
3996 }
3997
3998 case Primitive::kPrimLong: {
3999 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004000 if (index.IsConstant()) {
4001 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Mark Mendell40741f32015-04-20 22:10:34 -04004002 if (value.IsRegister()) {
4003 __ movq(Address(obj, offset), value.AsRegister<CpuRegister>());
4004 } else {
4005 int64_t v = value.GetConstant()->AsLongConstant()->GetValue();
4006 DCHECK(IsInt<32>(v));
4007 int32_t v_32 = v;
4008 __ movq(Address(obj, offset), Immediate(v_32));
4009 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004010 } else {
Mark Mendell40741f32015-04-20 22:10:34 -04004011 if (value.IsRegister()) {
4012 __ movq(Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset),
4013 value.AsRegister<CpuRegister>());
4014 } else {
4015 int64_t v = value.GetConstant()->AsLongConstant()->GetValue();
4016 DCHECK(IsInt<32>(v));
4017 int32_t v_32 = v;
4018 __ movq(Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset),
4019 Immediate(v_32));
4020 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004021 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004022 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004023 break;
4024 }
4025
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004026 case Primitive::kPrimFloat: {
4027 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
4028 if (index.IsConstant()) {
4029 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4030 DCHECK(value.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004031 __ movss(Address(obj, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004032 } else {
4033 DCHECK(value.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004034 __ movss(Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset),
4035 value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004036 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004037 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004038 break;
4039 }
4040
4041 case Primitive::kPrimDouble: {
4042 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
4043 if (index.IsConstant()) {
4044 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
4045 DCHECK(value.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004046 __ movsd(Address(obj, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004047 } else {
4048 DCHECK(value.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004049 __ movsd(Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset),
4050 value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004051 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004052 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004053 break;
4054 }
4055
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004056 case Primitive::kPrimVoid:
4057 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07004058 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004059 }
4060}
4061
4062void LocationsBuilderX86_64::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004063 LocationSummary* locations =
4064 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01004065 locations->SetInAt(0, Location::RequiresRegister());
4066 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004067}
4068
4069void InstructionCodeGeneratorX86_64::VisitArrayLength(HArrayLength* instruction) {
4070 LocationSummary* locations = instruction->GetLocations();
4071 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004072 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
4073 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004074 __ movl(out, Address(obj, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00004075 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004076}
4077
4078void LocationsBuilderX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004079 LocationSummary* locations =
4080 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Mark Mendellf60c90b2015-03-04 15:12:59 -05004081 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
Mark Mendell99dbd682015-04-22 16:18:52 -04004082 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004083 if (instruction->HasUses()) {
4084 locations->SetOut(Location::SameAsFirstInput());
4085 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004086}
4087
4088void InstructionCodeGeneratorX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
4089 LocationSummary* locations = instruction->GetLocations();
Mark Mendellf60c90b2015-03-04 15:12:59 -05004090 Location index_loc = locations->InAt(0);
4091 Location length_loc = locations->InAt(1);
4092 SlowPathCodeX86_64* slow_path =
4093 new (GetGraph()->GetArena()) BoundsCheckSlowPathX86_64(instruction, index_loc, length_loc);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004094
Mark Mendell99dbd682015-04-22 16:18:52 -04004095 if (length_loc.IsConstant()) {
4096 int32_t length = CodeGenerator::GetInt32ValueOf(length_loc.GetConstant());
4097 if (index_loc.IsConstant()) {
4098 // BCE will remove the bounds check if we are guarenteed to pass.
4099 int32_t index = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
4100 if (index < 0 || index >= length) {
4101 codegen_->AddSlowPath(slow_path);
4102 __ jmp(slow_path->GetEntryLabel());
4103 } else {
4104 // Some optimization after BCE may have generated this, and we should not
4105 // generate a bounds check if it is a valid range.
4106 }
4107 return;
4108 }
4109
4110 // We have to reverse the jump condition because the length is the constant.
4111 CpuRegister index_reg = index_loc.AsRegister<CpuRegister>();
4112 __ cmpl(index_reg, Immediate(length));
4113 codegen_->AddSlowPath(slow_path);
4114 __ j(kAboveEqual, slow_path->GetEntryLabel());
Mark Mendellf60c90b2015-03-04 15:12:59 -05004115 } else {
Mark Mendell99dbd682015-04-22 16:18:52 -04004116 CpuRegister length = length_loc.AsRegister<CpuRegister>();
4117 if (index_loc.IsConstant()) {
4118 int32_t value = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
4119 __ cmpl(length, Immediate(value));
4120 } else {
4121 __ cmpl(length, index_loc.AsRegister<CpuRegister>());
4122 }
4123 codegen_->AddSlowPath(slow_path);
4124 __ j(kBelowEqual, slow_path->GetEntryLabel());
Mark Mendellf60c90b2015-03-04 15:12:59 -05004125 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004126}
4127
4128void CodeGeneratorX86_64::MarkGCCard(CpuRegister temp,
4129 CpuRegister card,
4130 CpuRegister object,
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004131 CpuRegister value,
4132 bool value_can_be_null) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004133 Label is_null;
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004134 if (value_can_be_null) {
4135 __ testl(value, value);
4136 __ j(kEqual, &is_null);
4137 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004138 __ gs()->movq(card, Address::Absolute(
4139 Thread::CardTableOffset<kX86_64WordSize>().Int32Value(), true));
4140 __ movq(temp, object);
4141 __ shrq(temp, Immediate(gc::accounting::CardTable::kCardShift));
Roland Levillain4d027112015-07-01 15:41:14 +01004142 __ movb(Address(temp, card, TIMES_1, 0), card);
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004143 if (value_can_be_null) {
4144 __ Bind(&is_null);
4145 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004146}
4147
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004148void LocationsBuilderX86_64::VisitTemporary(HTemporary* temp) {
4149 temp->SetLocations(nullptr);
4150}
4151
4152void InstructionCodeGeneratorX86_64::VisitTemporary(HTemporary* temp) {
4153 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07004154 UNUSED(temp);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004155}
4156
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004157void LocationsBuilderX86_64::VisitParallelMove(HParallelMove* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07004158 UNUSED(instruction);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004159 LOG(FATAL) << "Unimplemented";
4160}
4161
4162void InstructionCodeGeneratorX86_64::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004163 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
4164}
4165
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004166void LocationsBuilderX86_64::VisitSuspendCheck(HSuspendCheck* instruction) {
4167 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
4168}
4169
4170void InstructionCodeGeneratorX86_64::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004171 HBasicBlock* block = instruction->GetBlock();
4172 if (block->GetLoopInformation() != nullptr) {
4173 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
4174 // The back edge will generate the suspend check.
4175 return;
4176 }
4177 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
4178 // The goto will generate the suspend check.
4179 return;
4180 }
4181 GenerateSuspendCheck(instruction, nullptr);
4182}
4183
4184void InstructionCodeGeneratorX86_64::GenerateSuspendCheck(HSuspendCheck* instruction,
4185 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004186 SuspendCheckSlowPathX86_64* slow_path =
Nicolas Geoffraydb216f42015-05-05 17:02:20 +01004187 down_cast<SuspendCheckSlowPathX86_64*>(instruction->GetSlowPath());
4188 if (slow_path == nullptr) {
4189 slow_path = new (GetGraph()->GetArena()) SuspendCheckSlowPathX86_64(instruction, successor);
4190 instruction->SetSlowPath(slow_path);
4191 codegen_->AddSlowPath(slow_path);
4192 if (successor != nullptr) {
4193 DCHECK(successor->IsLoopHeader());
4194 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(instruction);
4195 }
4196 } else {
4197 DCHECK_EQ(slow_path->GetSuccessor(), successor);
4198 }
4199
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004200 __ gs()->cmpw(Address::Absolute(
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004201 Thread::ThreadFlagsOffset<kX86_64WordSize>().Int32Value(), true), Immediate(0));
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004202 if (successor == nullptr) {
4203 __ j(kNotEqual, slow_path->GetEntryLabel());
4204 __ Bind(slow_path->GetReturnLabel());
4205 } else {
4206 __ j(kEqual, codegen_->GetLabelOf(successor));
4207 __ jmp(slow_path->GetEntryLabel());
4208 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004209}
4210
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004211X86_64Assembler* ParallelMoveResolverX86_64::GetAssembler() const {
4212 return codegen_->GetAssembler();
4213}
4214
4215void ParallelMoveResolverX86_64::EmitMove(size_t index) {
4216 MoveOperands* move = moves_.Get(index);
4217 Location source = move->GetSource();
4218 Location destination = move->GetDestination();
4219
4220 if (source.IsRegister()) {
4221 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004222 __ movq(destination.AsRegister<CpuRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004223 } else if (destination.IsStackSlot()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004224 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00004225 source.AsRegister<CpuRegister>());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004226 } else {
4227 DCHECK(destination.IsDoubleStackSlot());
4228 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00004229 source.AsRegister<CpuRegister>());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004230 }
4231 } else if (source.IsStackSlot()) {
4232 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004233 __ movl(destination.AsRegister<CpuRegister>(),
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004234 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004235 } else if (destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004236 __ movss(destination.AsFpuRegister<XmmRegister>(),
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004237 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004238 } else {
4239 DCHECK(destination.IsStackSlot());
4240 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
4241 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
4242 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004243 } else if (source.IsDoubleStackSlot()) {
4244 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004245 __ movq(destination.AsRegister<CpuRegister>(),
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004246 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004247 } else if (destination.IsFpuRegister()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004248 __ movsd(destination.AsFpuRegister<XmmRegister>(),
4249 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004250 } else {
Nicolas Geoffrayc8147a72014-10-21 16:06:20 +01004251 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004252 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
4253 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
4254 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004255 } else if (source.IsConstant()) {
4256 HConstant* constant = source.GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00004257 if (constant->IsIntConstant() || constant->IsNullConstant()) {
4258 int32_t value = CodeGenerator::GetInt32ValueOf(constant);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004259 if (destination.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00004260 if (value == 0) {
4261 __ xorl(destination.AsRegister<CpuRegister>(), destination.AsRegister<CpuRegister>());
4262 } else {
4263 __ movl(destination.AsRegister<CpuRegister>(), Immediate(value));
4264 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004265 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004266 DCHECK(destination.IsStackSlot()) << destination;
Nicolas Geoffray748f1402015-01-27 08:17:54 +00004267 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), Immediate(value));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004268 }
4269 } else if (constant->IsLongConstant()) {
4270 int64_t value = constant->AsLongConstant()->GetValue();
4271 if (destination.IsRegister()) {
Mark Mendell92e83bf2015-05-07 11:25:03 -04004272 codegen_->Load64BitValue(destination.AsRegister<CpuRegister>(), value);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004273 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004274 DCHECK(destination.IsDoubleStackSlot()) << destination;
Mark Mendell92e83bf2015-05-07 11:25:03 -04004275 codegen_->Load64BitValue(CpuRegister(TMP), value);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004276 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
4277 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004278 } else if (constant->IsFloatConstant()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004279 float fp_value = constant->AsFloatConstant()->GetValue();
Roland Levillainda4d79b2015-03-24 14:36:11 +00004280 int32_t value = bit_cast<int32_t, float>(fp_value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004281 if (destination.IsFpuRegister()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004282 XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
4283 if (value == 0) {
4284 // easy FP 0.0.
4285 __ xorps(dest, dest);
4286 } else {
Mark Mendell92e83bf2015-05-07 11:25:03 -04004287 __ movss(dest, codegen_->LiteralFloatAddress(fp_value));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004288 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004289 } else {
4290 DCHECK(destination.IsStackSlot()) << destination;
Mark Mendell92e83bf2015-05-07 11:25:03 -04004291 Immediate imm(value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004292 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), imm);
4293 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004294 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004295 DCHECK(constant->IsDoubleConstant()) << constant->DebugName();
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004296 double fp_value = constant->AsDoubleConstant()->GetValue();
Roland Levillainda4d79b2015-03-24 14:36:11 +00004297 int64_t value = bit_cast<int64_t, double>(fp_value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004298 if (destination.IsFpuRegister()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004299 XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
4300 if (value == 0) {
4301 __ xorpd(dest, dest);
4302 } else {
Mark Mendell92e83bf2015-05-07 11:25:03 -04004303 __ movsd(dest, codegen_->LiteralDoubleAddress(fp_value));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004304 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004305 } else {
4306 DCHECK(destination.IsDoubleStackSlot()) << destination;
Mark Mendell92e83bf2015-05-07 11:25:03 -04004307 codegen_->Load64BitValue(CpuRegister(TMP), value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004308 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
4309 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004310 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004311 } else if (source.IsFpuRegister()) {
4312 if (destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004313 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004314 } else if (destination.IsStackSlot()) {
4315 __ movss(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00004316 source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004317 } else {
Nicolas Geoffray31596742014-11-24 15:28:45 +00004318 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004319 __ movsd(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00004320 source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004321 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004322 }
4323}
4324
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004325void ParallelMoveResolverX86_64::Exchange32(CpuRegister reg, int mem) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004326 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004327 __ movl(Address(CpuRegister(RSP), mem), reg);
4328 __ movl(reg, CpuRegister(TMP));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004329}
4330
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004331void ParallelMoveResolverX86_64::Exchange32(int mem1, int mem2) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004332 ScratchRegisterScope ensure_scratch(
4333 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
4334
4335 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
4336 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
4337 __ movl(CpuRegister(ensure_scratch.GetRegister()),
4338 Address(CpuRegister(RSP), mem2 + stack_offset));
4339 __ movl(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
4340 __ movl(Address(CpuRegister(RSP), mem1 + stack_offset),
4341 CpuRegister(ensure_scratch.GetRegister()));
4342}
4343
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004344void ParallelMoveResolverX86_64::Exchange64(CpuRegister reg, int mem) {
4345 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
4346 __ movq(Address(CpuRegister(RSP), mem), reg);
4347 __ movq(reg, CpuRegister(TMP));
4348}
4349
4350void ParallelMoveResolverX86_64::Exchange64(int mem1, int mem2) {
4351 ScratchRegisterScope ensure_scratch(
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004352 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004353
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004354 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
4355 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
4356 __ movq(CpuRegister(ensure_scratch.GetRegister()),
4357 Address(CpuRegister(RSP), mem2 + stack_offset));
4358 __ movq(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
4359 __ movq(Address(CpuRegister(RSP), mem1 + stack_offset),
4360 CpuRegister(ensure_scratch.GetRegister()));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004361}
4362
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004363void ParallelMoveResolverX86_64::Exchange32(XmmRegister reg, int mem) {
4364 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
4365 __ movss(Address(CpuRegister(RSP), mem), reg);
4366 __ movd(reg, CpuRegister(TMP));
4367}
4368
4369void ParallelMoveResolverX86_64::Exchange64(XmmRegister reg, int mem) {
4370 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
4371 __ movsd(Address(CpuRegister(RSP), mem), reg);
4372 __ movd(reg, CpuRegister(TMP));
4373}
4374
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004375void ParallelMoveResolverX86_64::EmitSwap(size_t index) {
4376 MoveOperands* move = moves_.Get(index);
4377 Location source = move->GetSource();
4378 Location destination = move->GetDestination();
4379
4380 if (source.IsRegister() && destination.IsRegister()) {
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004381 __ xchgq(destination.AsRegister<CpuRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004382 } else if (source.IsRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004383 Exchange32(source.AsRegister<CpuRegister>(), destination.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004384 } else if (source.IsStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004385 Exchange32(destination.AsRegister<CpuRegister>(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004386 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004387 Exchange32(destination.GetStackIndex(), source.GetStackIndex());
4388 } else if (source.IsRegister() && destination.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004389 Exchange64(source.AsRegister<CpuRegister>(), destination.GetStackIndex());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004390 } else if (source.IsDoubleStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004391 Exchange64(destination.AsRegister<CpuRegister>(), source.GetStackIndex());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004392 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
4393 Exchange64(destination.GetStackIndex(), source.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004394 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004395 __ movd(CpuRegister(TMP), source.AsFpuRegister<XmmRegister>());
4396 __ movaps(source.AsFpuRegister<XmmRegister>(), destination.AsFpuRegister<XmmRegister>());
4397 __ movd(destination.AsFpuRegister<XmmRegister>(), CpuRegister(TMP));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004398 } else if (source.IsFpuRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004399 Exchange32(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004400 } else if (source.IsStackSlot() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004401 Exchange32(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004402 } else if (source.IsFpuRegister() && destination.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004403 Exchange64(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004404 } else if (source.IsDoubleStackSlot() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004405 Exchange64(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004406 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004407 LOG(FATAL) << "Unimplemented swap between " << source << " and " << destination;
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004408 }
4409}
4410
4411
4412void ParallelMoveResolverX86_64::SpillScratch(int reg) {
4413 __ pushq(CpuRegister(reg));
4414}
4415
4416
4417void ParallelMoveResolverX86_64::RestoreScratch(int reg) {
4418 __ popq(CpuRegister(reg));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004419}
4420
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004421void InstructionCodeGeneratorX86_64::GenerateClassInitializationCheck(
4422 SlowPathCodeX86_64* slow_path, CpuRegister class_reg) {
4423 __ cmpl(Address(class_reg, mirror::Class::StatusOffset().Int32Value()),
4424 Immediate(mirror::Class::kStatusInitialized));
4425 __ j(kLess, slow_path->GetEntryLabel());
4426 __ Bind(slow_path->GetExitLabel());
4427 // No need for memory fence, thanks to the X86_64 memory model.
4428}
4429
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004430void LocationsBuilderX86_64::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004431 LocationSummary::CallKind call_kind = cls->CanCallRuntime()
4432 ? LocationSummary::kCallOnSlowPath
4433 : LocationSummary::kNoCall;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004434 LocationSummary* locations =
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004435 new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004436 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004437 locations->SetOut(Location::RequiresRegister());
4438}
4439
4440void InstructionCodeGeneratorX86_64::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004441 LocationSummary* locations = cls->GetLocations();
4442 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
4443 CpuRegister current_method = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004444 if (cls->IsReferrersClass()) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004445 DCHECK(!cls->CanCallRuntime());
4446 DCHECK(!cls->MustGenerateClinitCheck());
Mathieu Chartiere401d142015-04-22 13:56:20 -07004447 __ movl(out, Address(current_method, ArtMethod::DeclaringClassOffset().Int32Value()));
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004448 } else {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004449 DCHECK(cls->CanCallRuntime());
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004450 __ movl(out, Address(
Mathieu Chartiere401d142015-04-22 13:56:20 -07004451 current_method, ArtMethod::DexCacheResolvedTypesOffset().Int32Value()));
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004452 __ movl(out, Address(out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex())));
Roland Levillain4d027112015-07-01 15:41:14 +01004453 __ MaybeUnpoisonHeapReference(out);
4454
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004455 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86_64(
4456 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
4457 codegen_->AddSlowPath(slow_path);
4458 __ testl(out, out);
4459 __ j(kEqual, slow_path->GetEntryLabel());
4460 if (cls->MustGenerateClinitCheck()) {
4461 GenerateClassInitializationCheck(slow_path, out);
4462 } else {
4463 __ Bind(slow_path->GetExitLabel());
4464 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004465 }
4466}
4467
4468void LocationsBuilderX86_64::VisitClinitCheck(HClinitCheck* check) {
4469 LocationSummary* locations =
4470 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
4471 locations->SetInAt(0, Location::RequiresRegister());
4472 if (check->HasUses()) {
4473 locations->SetOut(Location::SameAsFirstInput());
4474 }
4475}
4476
4477void InstructionCodeGeneratorX86_64::VisitClinitCheck(HClinitCheck* check) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004478 // We assume the class to not be null.
4479 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86_64(
4480 check->GetLoadClass(), check, check->GetDexPc(), true);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004481 codegen_->AddSlowPath(slow_path);
Roland Levillain199f3362014-11-27 17:15:16 +00004482 GenerateClassInitializationCheck(slow_path,
4483 check->GetLocations()->InAt(0).AsRegister<CpuRegister>());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004484}
4485
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004486void LocationsBuilderX86_64::VisitLoadString(HLoadString* load) {
4487 LocationSummary* locations =
4488 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01004489 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004490 locations->SetOut(Location::RequiresRegister());
4491}
4492
4493void InstructionCodeGeneratorX86_64::VisitLoadString(HLoadString* load) {
4494 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathX86_64(load);
4495 codegen_->AddSlowPath(slow_path);
4496
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01004497 LocationSummary* locations = load->GetLocations();
4498 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
4499 CpuRegister current_method = locations->InAt(0).AsRegister<CpuRegister>();
Mathieu Chartiere401d142015-04-22 13:56:20 -07004500 __ movl(out, Address(current_method, ArtMethod::DeclaringClassOffset().Int32Value()));
Mathieu Chartiereace4582014-11-24 18:29:54 -08004501 __ movl(out, Address(out, mirror::Class::DexCacheStringsOffset().Int32Value()));
Roland Levillain4d027112015-07-01 15:41:14 +01004502 __ MaybeUnpoisonHeapReference(out);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004503 __ movl(out, Address(out, CodeGenerator::GetCacheOffset(load->GetStringIndex())));
Roland Levillain4d027112015-07-01 15:41:14 +01004504 __ MaybeUnpoisonHeapReference(out);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004505 __ testl(out, out);
4506 __ j(kEqual, slow_path->GetEntryLabel());
4507 __ Bind(slow_path->GetExitLabel());
4508}
4509
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004510void LocationsBuilderX86_64::VisitLoadException(HLoadException* load) {
4511 LocationSummary* locations =
4512 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
4513 locations->SetOut(Location::RequiresRegister());
4514}
4515
4516void InstructionCodeGeneratorX86_64::VisitLoadException(HLoadException* load) {
4517 Address address = Address::Absolute(
4518 Thread::ExceptionOffset<kX86_64WordSize>().Int32Value(), true);
Roland Levillain271ab9c2014-11-27 15:23:57 +00004519 __ gs()->movl(load->GetLocations()->Out().AsRegister<CpuRegister>(), address);
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004520 __ gs()->movl(address, Immediate(0));
4521}
4522
4523void LocationsBuilderX86_64::VisitThrow(HThrow* instruction) {
4524 LocationSummary* locations =
4525 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
4526 InvokeRuntimeCallingConvention calling_convention;
4527 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4528}
4529
4530void InstructionCodeGeneratorX86_64::VisitThrow(HThrow* instruction) {
4531 __ gs()->call(
4532 Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pDeliverException), true));
4533 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
4534}
4535
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004536void LocationsBuilderX86_64::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004537 LocationSummary::CallKind call_kind = instruction->IsClassFinal()
4538 ? LocationSummary::kNoCall
4539 : LocationSummary::kCallOnSlowPath;
4540 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
4541 locations->SetInAt(0, Location::RequiresRegister());
4542 locations->SetInAt(1, Location::Any());
4543 locations->SetOut(Location::RequiresRegister());
4544}
4545
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004546void InstructionCodeGeneratorX86_64::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004547 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004548 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004549 Location cls = locations->InAt(1);
Roland Levillain271ab9c2014-11-27 15:23:57 +00004550 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004551 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
4552 Label done, zero;
4553 SlowPathCodeX86_64* slow_path = nullptr;
4554
4555 // Return 0 if `obj` is null.
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004556 // Avoid null check if we know obj is not null.
4557 if (instruction->MustDoNullCheck()) {
4558 __ testl(obj, obj);
4559 __ j(kEqual, &zero);
4560 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004561 // Compare the class of `obj` with `cls`.
4562 __ movl(out, Address(obj, class_offset));
Roland Levillain4d027112015-07-01 15:41:14 +01004563 __ MaybeUnpoisonHeapReference(out);
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004564 if (cls.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004565 __ cmpl(out, cls.AsRegister<CpuRegister>());
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004566 } else {
4567 DCHECK(cls.IsStackSlot()) << cls;
4568 __ cmpl(out, Address(CpuRegister(RSP), cls.GetStackIndex()));
4569 }
4570 if (instruction->IsClassFinal()) {
4571 // Classes must be equal for the instanceof to succeed.
4572 __ j(kNotEqual, &zero);
4573 __ movl(out, Immediate(1));
4574 __ jmp(&done);
4575 } else {
4576 // If the classes are not equal, we go into a slow path.
4577 DCHECK(locations->OnlyCallsOnSlowPath());
4578 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86_64(
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004579 instruction, locations->InAt(1), locations->Out(), instruction->GetDexPc());
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004580 codegen_->AddSlowPath(slow_path);
4581 __ j(kNotEqual, slow_path->GetEntryLabel());
4582 __ movl(out, Immediate(1));
4583 __ jmp(&done);
4584 }
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004585
4586 if (instruction->MustDoNullCheck() || instruction->IsClassFinal()) {
4587 __ Bind(&zero);
4588 __ movl(out, Immediate(0));
4589 }
4590
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004591 if (slow_path != nullptr) {
4592 __ Bind(slow_path->GetExitLabel());
4593 }
4594 __ Bind(&done);
4595}
4596
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004597void LocationsBuilderX86_64::VisitCheckCast(HCheckCast* instruction) {
4598 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
4599 instruction, LocationSummary::kCallOnSlowPath);
4600 locations->SetInAt(0, Location::RequiresRegister());
4601 locations->SetInAt(1, Location::Any());
4602 locations->AddTemp(Location::RequiresRegister());
4603}
4604
4605void InstructionCodeGeneratorX86_64::VisitCheckCast(HCheckCast* instruction) {
4606 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004607 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004608 Location cls = locations->InAt(1);
Roland Levillain271ab9c2014-11-27 15:23:57 +00004609 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004610 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
4611 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86_64(
4612 instruction, locations->InAt(1), locations->GetTemp(0), instruction->GetDexPc());
4613 codegen_->AddSlowPath(slow_path);
4614
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004615 // Avoid null check if we know obj is not null.
4616 if (instruction->MustDoNullCheck()) {
4617 __ testl(obj, obj);
4618 __ j(kEqual, slow_path->GetExitLabel());
4619 }
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004620 // Compare the class of `obj` with `cls`.
4621 __ movl(temp, Address(obj, class_offset));
Roland Levillain4d027112015-07-01 15:41:14 +01004622 __ MaybeUnpoisonHeapReference(temp);
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004623 if (cls.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004624 __ cmpl(temp, cls.AsRegister<CpuRegister>());
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004625 } else {
4626 DCHECK(cls.IsStackSlot()) << cls;
4627 __ cmpl(temp, Address(CpuRegister(RSP), cls.GetStackIndex()));
4628 }
Roland Levillain4d027112015-07-01 15:41:14 +01004629 // The checkcast succeeds if the classes are equal (fast path).
4630 // Otherwise, we need to go into the slow path to check the types.
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004631 __ j(kNotEqual, slow_path->GetEntryLabel());
4632 __ Bind(slow_path->GetExitLabel());
4633}
4634
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00004635void LocationsBuilderX86_64::VisitMonitorOperation(HMonitorOperation* instruction) {
4636 LocationSummary* locations =
4637 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
4638 InvokeRuntimeCallingConvention calling_convention;
4639 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4640}
4641
4642void InstructionCodeGeneratorX86_64::VisitMonitorOperation(HMonitorOperation* instruction) {
4643 __ gs()->call(Address::Absolute(instruction->IsEnter()
4644 ? QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pLockObject)
4645 : QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pUnlockObject),
4646 true));
4647 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
4648}
4649
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004650void LocationsBuilderX86_64::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); }
4651void LocationsBuilderX86_64::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); }
4652void LocationsBuilderX86_64::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); }
4653
4654void LocationsBuilderX86_64::HandleBitwiseOperation(HBinaryOperation* instruction) {
4655 LocationSummary* locations =
4656 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
4657 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
4658 || instruction->GetResultType() == Primitive::kPrimLong);
4659 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell40741f32015-04-20 22:10:34 -04004660 locations->SetInAt(1, Location::Any());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004661 locations->SetOut(Location::SameAsFirstInput());
4662}
4663
4664void InstructionCodeGeneratorX86_64::VisitAnd(HAnd* instruction) {
4665 HandleBitwiseOperation(instruction);
4666}
4667
4668void InstructionCodeGeneratorX86_64::VisitOr(HOr* instruction) {
4669 HandleBitwiseOperation(instruction);
4670}
4671
4672void InstructionCodeGeneratorX86_64::VisitXor(HXor* instruction) {
4673 HandleBitwiseOperation(instruction);
4674}
4675
4676void InstructionCodeGeneratorX86_64::HandleBitwiseOperation(HBinaryOperation* instruction) {
4677 LocationSummary* locations = instruction->GetLocations();
4678 Location first = locations->InAt(0);
4679 Location second = locations->InAt(1);
4680 DCHECK(first.Equals(locations->Out()));
4681
4682 if (instruction->GetResultType() == Primitive::kPrimInt) {
4683 if (second.IsRegister()) {
4684 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004685 __ andl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004686 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004687 __ orl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004688 } else {
4689 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004690 __ xorl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004691 }
4692 } else if (second.IsConstant()) {
4693 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
4694 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004695 __ andl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004696 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004697 __ orl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004698 } else {
4699 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004700 __ xorl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004701 }
4702 } else {
4703 Address address(CpuRegister(RSP), second.GetStackIndex());
4704 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004705 __ andl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004706 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004707 __ orl(first.AsRegister<CpuRegister>(), address);
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>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004711 }
4712 }
4713 } else {
4714 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004715 CpuRegister first_reg = first.AsRegister<CpuRegister>();
4716 bool second_is_constant = false;
4717 int64_t value = 0;
4718 if (second.IsConstant()) {
4719 second_is_constant = true;
4720 value = second.GetConstant()->AsLongConstant()->GetValue();
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004721 }
Mark Mendell40741f32015-04-20 22:10:34 -04004722 bool is_int32_value = IsInt<32>(value);
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004723
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004724 if (instruction->IsAnd()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004725 if (second_is_constant) {
Mark Mendell40741f32015-04-20 22:10:34 -04004726 if (is_int32_value) {
4727 __ andq(first_reg, Immediate(static_cast<int32_t>(value)));
4728 } else {
4729 __ andq(first_reg, codegen_->LiteralInt64Address(value));
4730 }
4731 } else if (second.IsDoubleStackSlot()) {
4732 __ andq(first_reg, Address(CpuRegister(RSP), second.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004733 } else {
4734 __ andq(first_reg, second.AsRegister<CpuRegister>());
4735 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004736 } else if (instruction->IsOr()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004737 if (second_is_constant) {
Mark Mendell40741f32015-04-20 22:10:34 -04004738 if (is_int32_value) {
4739 __ orq(first_reg, Immediate(static_cast<int32_t>(value)));
4740 } else {
4741 __ orq(first_reg, codegen_->LiteralInt64Address(value));
4742 }
4743 } else if (second.IsDoubleStackSlot()) {
4744 __ orq(first_reg, Address(CpuRegister(RSP), second.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004745 } else {
4746 __ orq(first_reg, second.AsRegister<CpuRegister>());
4747 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004748 } else {
4749 DCHECK(instruction->IsXor());
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004750 if (second_is_constant) {
Mark Mendell40741f32015-04-20 22:10:34 -04004751 if (is_int32_value) {
4752 __ xorq(first_reg, Immediate(static_cast<int32_t>(value)));
4753 } else {
4754 __ xorq(first_reg, codegen_->LiteralInt64Address(value));
4755 }
4756 } else if (second.IsDoubleStackSlot()) {
4757 __ xorq(first_reg, Address(CpuRegister(RSP), second.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004758 } else {
4759 __ xorq(first_reg, second.AsRegister<CpuRegister>());
4760 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004761 }
4762 }
4763}
4764
Calin Juravleb1498f62015-02-16 13:13:29 +00004765void LocationsBuilderX86_64::VisitBoundType(HBoundType* instruction) {
4766 // Nothing to do, this should be removed during prepare for register allocator.
4767 UNUSED(instruction);
4768 LOG(FATAL) << "Unreachable";
4769}
4770
4771void InstructionCodeGeneratorX86_64::VisitBoundType(HBoundType* instruction) {
4772 // Nothing to do, this should be removed during prepare for register allocator.
4773 UNUSED(instruction);
4774 LOG(FATAL) << "Unreachable";
4775}
4776
Mark Mendell92e83bf2015-05-07 11:25:03 -04004777void CodeGeneratorX86_64::Load64BitValue(CpuRegister dest, int64_t value) {
4778 if (value == 0) {
4779 __ xorl(dest, dest);
4780 } else if (value > 0 && IsInt<32>(value)) {
4781 // We can use a 32 bit move, as it will zero-extend and is one byte shorter.
4782 __ movl(dest, Immediate(static_cast<int32_t>(value)));
4783 } else {
4784 __ movq(dest, Immediate(value));
4785 }
4786}
4787
Mark Mendellf55c3e02015-03-26 21:07:46 -04004788void CodeGeneratorX86_64::Finalize(CodeAllocator* allocator) {
4789 // Generate the constant area if needed.
Mark Mendell39dcf552015-04-09 20:42:42 -04004790 X86_64Assembler* assembler = GetAssembler();
4791 if (!assembler->IsConstantAreaEmpty()) {
Mark Mendellf55c3e02015-03-26 21:07:46 -04004792 // Align to 4 byte boundary to reduce cache misses, as the data is 4 and 8
4793 // byte values. If used for vectors at a later time, this will need to be
4794 // updated to 16 bytes with the appropriate offset.
Mark Mendell39dcf552015-04-09 20:42:42 -04004795 assembler->Align(4, 0);
4796 constant_area_start_ = assembler->CodeSize();
4797 assembler->AddConstantArea();
Mark Mendellf55c3e02015-03-26 21:07:46 -04004798 }
4799
4800 // And finish up.
4801 CodeGenerator::Finalize(allocator);
4802}
4803
4804/**
4805 * Class to handle late fixup of offsets into constant area.
4806 */
4807class RIPFixup : public AssemblerFixup, public ArenaObject<kArenaAllocMisc> {
4808 public:
Mark Mendell39dcf552015-04-09 20:42:42 -04004809 RIPFixup(const CodeGeneratorX86_64& codegen, int offset)
Mark Mendellf55c3e02015-03-26 21:07:46 -04004810 : codegen_(codegen), offset_into_constant_area_(offset) {}
4811
4812 private:
4813 void Process(const MemoryRegion& region, int pos) OVERRIDE {
4814 // Patch the correct offset for the instruction. We use the address of the
4815 // 'next' instruction, which is 'pos' (patch the 4 bytes before).
4816 int constant_offset = codegen_.ConstantAreaStart() + offset_into_constant_area_;
4817 int relative_position = constant_offset - pos;
4818
4819 // Patch in the right value.
4820 region.StoreUnaligned<int32_t>(pos - 4, relative_position);
4821 }
4822
Mark Mendell39dcf552015-04-09 20:42:42 -04004823 const CodeGeneratorX86_64& codegen_;
Mark Mendellf55c3e02015-03-26 21:07:46 -04004824
4825 // Location in constant area that the fixup refers to.
4826 int offset_into_constant_area_;
4827};
4828
4829Address CodeGeneratorX86_64::LiteralDoubleAddress(double v) {
4830 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddDouble(v));
4831 return Address::RIP(fixup);
4832}
4833
4834Address CodeGeneratorX86_64::LiteralFloatAddress(float v) {
4835 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddFloat(v));
4836 return Address::RIP(fixup);
4837}
4838
4839Address CodeGeneratorX86_64::LiteralInt32Address(int32_t v) {
4840 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddInt32(v));
4841 return Address::RIP(fixup);
4842}
4843
4844Address CodeGeneratorX86_64::LiteralInt64Address(int64_t v) {
4845 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddInt64(v));
4846 return Address::RIP(fixup);
4847}
4848
Roland Levillain4d027112015-07-01 15:41:14 +01004849#undef __
4850
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004851} // namespace x86_64
4852} // namespace art