blob: c9d19c8f6608b1dd4a2b5fba5b4917860ea6e99d [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
Dave Allison20dfc792014-06-16 20:44:29 -0700366inline Condition X86_64Condition(IfCondition cond) {
367 switch (cond) {
368 case kCondEQ: return kEqual;
369 case kCondNE: return kNotEqual;
370 case kCondLT: return kLess;
371 case kCondLE: return kLessEqual;
372 case kCondGT: return kGreater;
373 case kCondGE: return kGreaterEqual;
374 default:
375 LOG(FATAL) << "Unknown if condition";
376 }
377 return kEqual;
378}
379
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800380void CodeGeneratorX86_64::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke,
Nicolas Geoffray38207af2015-06-01 15:46:22 +0100381 Location temp) {
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800382 // All registers are assumed to be correctly set up.
383
384 // TODO: Implement all kinds of calls:
385 // 1) boot -> boot
386 // 2) app -> boot
387 // 3) app -> app
388 //
389 // Currently we implement the app -> app logic, which looks up in the resolve cache.
390
Jeff Hao848f70a2014-01-15 13:49:50 -0800391 if (invoke->IsStringInit()) {
Nicolas Geoffray38207af2015-06-01 15:46:22 +0100392 CpuRegister reg = temp.AsRegister<CpuRegister>();
Jeff Hao848f70a2014-01-15 13:49:50 -0800393 // temp = thread->string_init_entrypoint
Jeff Haocad65422015-06-18 21:16:08 -0700394 __ gs()->movq(reg, Address::Absolute(invoke->GetStringInitOffset(), true));
Nicolas Geoffray1cf95282014-12-12 19:22:03 +0000395 // (temp + offset_of_quick_compiled_code)()
Nicolas Geoffray38207af2015-06-01 15:46:22 +0100396 __ call(Address(reg, ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Nicolas Geoffray1cf95282014-12-12 19:22:03 +0000397 kX86_64WordSize).SizeValue()));
Nicolas Geoffray38207af2015-06-01 15:46:22 +0100398 } else if (invoke->IsRecursive()) {
399 __ call(&frame_entry_label_);
Nicolas Geoffray1cf95282014-12-12 19:22:03 +0000400 } else {
Nicolas Geoffray38207af2015-06-01 15:46:22 +0100401 CpuRegister reg = temp.AsRegister<CpuRegister>();
Nicolas Geoffrayae71a052015-06-09 14:12:28 +0100402 Location current_method = invoke->GetLocations()->InAt(invoke->GetCurrentMethodInputIndex());
403 Register method_reg;
404 if (current_method.IsRegister()) {
405 method_reg = current_method.AsRegister<Register>();
406 } else {
407 DCHECK(invoke->GetLocations()->Intrinsified());
408 DCHECK(!current_method.IsValid());
409 method_reg = reg.AsRegister();
410 __ movq(reg, Address(CpuRegister(RSP), kCurrentMethodStackOffset));
411 }
Nicolas Geoffray38207af2015-06-01 15:46:22 +0100412 // temp = temp->dex_cache_resolved_methods_;
Nicolas Geoffrayae71a052015-06-09 14:12:28 +0100413 __ movl(reg, Address(CpuRegister(method_reg),
414 ArtMethod::DexCacheResolvedMethodsOffset().SizeValue()));
Nicolas Geoffray38207af2015-06-01 15:46:22 +0100415 // temp = temp[index_in_cache]
416 __ movq(reg, Address(
417 reg, CodeGenerator::GetCachePointerOffset(invoke->GetDexMethodIndex())));
418 // (temp + offset_of_quick_compiled_code)()
419 __ call(Address(reg, ArtMethod::EntryPointFromQuickCompiledCodeOffset(
420 kX86_64WordSize).SizeValue()));
Nicolas Geoffray1cf95282014-12-12 19:22:03 +0000421 }
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800422
423 DCHECK(!IsLeafMethod());
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800424}
425
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100426void CodeGeneratorX86_64::DumpCoreRegister(std::ostream& stream, int reg) const {
David Brazdilc74652862015-05-13 17:50:09 +0100427 stream << Register(reg);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100428}
429
430void CodeGeneratorX86_64::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
David Brazdilc74652862015-05-13 17:50:09 +0100431 stream << FloatRegister(reg);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100432}
433
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100434size_t CodeGeneratorX86_64::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
435 __ movq(Address(CpuRegister(RSP), stack_index), CpuRegister(reg_id));
436 return kX86_64WordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100437}
438
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100439size_t CodeGeneratorX86_64::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
440 __ movq(CpuRegister(reg_id), Address(CpuRegister(RSP), stack_index));
441 return kX86_64WordSize;
442}
443
444size_t CodeGeneratorX86_64::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
445 __ movsd(Address(CpuRegister(RSP), stack_index), XmmRegister(reg_id));
446 return kX86_64WordSize;
447}
448
449size_t CodeGeneratorX86_64::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
450 __ movsd(XmmRegister(reg_id), Address(CpuRegister(RSP), stack_index));
451 return kX86_64WordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100452}
453
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000454static constexpr int kNumberOfCpuRegisterPairs = 0;
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +0000455// Use a fake return address register to mimic Quick.
456static constexpr Register kFakeReturnRegister = Register(kLastCpuRegister + 1);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400457CodeGeneratorX86_64::CodeGeneratorX86_64(HGraph* graph,
458 const X86_64InstructionSetFeatures& isa_features,
459 const CompilerOptions& compiler_options)
Nicolas Geoffray98893962015-01-21 12:32:32 +0000460 : CodeGenerator(graph,
461 kNumberOfCpuRegisters,
462 kNumberOfFloatRegisters,
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000463 kNumberOfCpuRegisterPairs,
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000464 ComputeRegisterMask(reinterpret_cast<const int*>(kCoreCalleeSaves),
465 arraysize(kCoreCalleeSaves))
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +0000466 | (1 << kFakeReturnRegister),
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000467 ComputeRegisterMask(reinterpret_cast<const int*>(kFpuCalleeSaves),
468 arraysize(kFpuCalleeSaves)),
Nicolas Geoffray98893962015-01-21 12:32:32 +0000469 compiler_options),
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100470 block_labels_(graph->GetArena(), 0),
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100471 location_builder_(graph, this),
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000472 instruction_visitor_(graph, this),
Mark Mendellfb8d2792015-03-31 22:16:59 -0400473 move_resolver_(graph->GetArena(), this),
Mark Mendellf55c3e02015-03-26 21:07:46 -0400474 isa_features_(isa_features),
475 constant_area_start_(0) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000476 AddAllocatedRegister(Location::RegisterLocation(kFakeReturnRegister));
477}
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100478
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100479InstructionCodeGeneratorX86_64::InstructionCodeGeneratorX86_64(HGraph* graph,
480 CodeGeneratorX86_64* codegen)
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100481 : HGraphVisitor(graph),
482 assembler_(codegen->GetAssembler()),
483 codegen_(codegen) {}
484
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100485Location CodeGeneratorX86_64::AllocateFreeRegister(Primitive::Type type) const {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100486 switch (type) {
487 case Primitive::kPrimLong:
488 case Primitive::kPrimByte:
489 case Primitive::kPrimBoolean:
490 case Primitive::kPrimChar:
491 case Primitive::kPrimShort:
492 case Primitive::kPrimInt:
493 case Primitive::kPrimNot: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100494 size_t reg = FindFreeEntry(blocked_core_registers_, kNumberOfCpuRegisters);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100495 return Location::RegisterLocation(reg);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100496 }
497
498 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100499 case Primitive::kPrimDouble: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100500 size_t reg = FindFreeEntry(blocked_fpu_registers_, kNumberOfFloatRegisters);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100501 return Location::FpuRegisterLocation(reg);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100502 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100503
504 case Primitive::kPrimVoid:
505 LOG(FATAL) << "Unreachable type " << type;
506 }
507
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100508 return Location();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100509}
510
Nicolas Geoffray98893962015-01-21 12:32:32 +0000511void CodeGeneratorX86_64::SetupBlockedRegisters(bool is_baseline) const {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100512 // Stack register is always reserved.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100513 blocked_core_registers_[RSP] = true;
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100514
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000515 // Block the register used as TMP.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100516 blocked_core_registers_[TMP] = true;
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000517
Nicolas Geoffray98893962015-01-21 12:32:32 +0000518 if (is_baseline) {
519 for (size_t i = 0; i < arraysize(kCoreCalleeSaves); ++i) {
520 blocked_core_registers_[kCoreCalleeSaves[i]] = true;
521 }
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000522 for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
523 blocked_fpu_registers_[kFpuCalleeSaves[i]] = true;
524 }
Nicolas Geoffray98893962015-01-21 12:32:32 +0000525 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100526}
527
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100528static dwarf::Reg DWARFReg(Register reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +0100529 return dwarf::Reg::X86_64Core(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100530}
David Srbecky9d8606d2015-04-12 09:35:32 +0100531
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100532static dwarf::Reg DWARFReg(FloatRegister reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +0100533 return dwarf::Reg::X86_64Fp(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100534}
535
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100536void CodeGeneratorX86_64::GenerateFrameEntry() {
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100537 __ cfi().SetCurrentCFAOffset(kX86_64WordSize); // return address
Nicolas Geoffray1cf95282014-12-12 19:22:03 +0000538 __ Bind(&frame_entry_label_);
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100539 bool skip_overflow_check = IsLeafMethod()
Dave Allison648d7112014-07-25 16:15:27 -0700540 && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kX86_64);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000541 DCHECK(GetCompilerOptions().GetImplicitStackOverflowChecks());
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100542
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000543 if (!skip_overflow_check) {
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100544 __ testq(CpuRegister(RAX), Address(
545 CpuRegister(RSP), -static_cast<int32_t>(GetStackOverflowReservedBytes(kX86_64))));
Nicolas Geoffray39468442014-09-02 15:17:15 +0100546 RecordPcInfo(nullptr, 0);
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100547 }
Nicolas Geoffraya26369a2015-01-22 08:46:05 +0000548
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000549 if (HasEmptyFrame()) {
550 return;
551 }
552
Nicolas Geoffray98893962015-01-21 12:32:32 +0000553 for (int i = arraysize(kCoreCalleeSaves) - 1; i >= 0; --i) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000554 Register reg = kCoreCalleeSaves[i];
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +0000555 if (allocated_registers_.ContainsCoreRegister(reg)) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000556 __ pushq(CpuRegister(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100557 __ cfi().AdjustCFAOffset(kX86_64WordSize);
558 __ cfi().RelOffset(DWARFReg(reg), 0);
Nicolas Geoffray98893962015-01-21 12:32:32 +0000559 }
560 }
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100561
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100562 int adjust = GetFrameSize() - GetCoreSpillSize();
563 __ subq(CpuRegister(RSP), Immediate(adjust));
564 __ cfi().AdjustCFAOffset(adjust);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000565 uint32_t xmm_spill_location = GetFpuSpillStart();
566 size_t xmm_spill_slot_size = GetFloatingPointSpillSlotSize();
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100567
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000568 for (int i = arraysize(kFpuCalleeSaves) - 1; i >= 0; --i) {
569 if (allocated_registers_.ContainsFloatingPointRegister(kFpuCalleeSaves[i])) {
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100570 int offset = xmm_spill_location + (xmm_spill_slot_size * i);
571 __ movsd(Address(CpuRegister(RSP), offset), XmmRegister(kFpuCalleeSaves[i]));
572 __ cfi().RelOffset(DWARFReg(kFpuCalleeSaves[i]), offset);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000573 }
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100574 }
575
Mathieu Chartiere401d142015-04-22 13:56:20 -0700576 __ movq(Address(CpuRegister(RSP), kCurrentMethodStackOffset),
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100577 CpuRegister(kMethodRegisterArgument));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100578}
579
580void CodeGeneratorX86_64::GenerateFrameExit() {
David Srbeckyc34dc932015-04-12 09:27:43 +0100581 __ cfi().RememberState();
582 if (!HasEmptyFrame()) {
583 uint32_t xmm_spill_location = GetFpuSpillStart();
584 size_t xmm_spill_slot_size = GetFloatingPointSpillSlotSize();
585 for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
586 if (allocated_registers_.ContainsFloatingPointRegister(kFpuCalleeSaves[i])) {
587 int offset = xmm_spill_location + (xmm_spill_slot_size * i);
588 __ movsd(XmmRegister(kFpuCalleeSaves[i]), Address(CpuRegister(RSP), offset));
589 __ cfi().Restore(DWARFReg(kFpuCalleeSaves[i]));
590 }
591 }
592
593 int adjust = GetFrameSize() - GetCoreSpillSize();
594 __ addq(CpuRegister(RSP), Immediate(adjust));
595 __ cfi().AdjustCFAOffset(-adjust);
596
597 for (size_t i = 0; i < arraysize(kCoreCalleeSaves); ++i) {
598 Register reg = kCoreCalleeSaves[i];
599 if (allocated_registers_.ContainsCoreRegister(reg)) {
600 __ popq(CpuRegister(reg));
601 __ cfi().AdjustCFAOffset(-static_cast<int>(kX86_64WordSize));
602 __ cfi().Restore(DWARFReg(reg));
603 }
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000604 }
605 }
David Srbeckyc34dc932015-04-12 09:27:43 +0100606 __ ret();
607 __ cfi().RestoreState();
608 __ cfi().DefCFAOffset(GetFrameSize());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100609}
610
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100611void CodeGeneratorX86_64::Bind(HBasicBlock* block) {
612 __ Bind(GetLabelOf(block));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100613}
614
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100615Location CodeGeneratorX86_64::GetStackLocation(HLoadLocal* load) const {
616 switch (load->GetType()) {
617 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100618 case Primitive::kPrimDouble:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100619 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100620
621 case Primitive::kPrimInt:
622 case Primitive::kPrimNot:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100623 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100624 return Location::StackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100625
626 case Primitive::kPrimBoolean:
627 case Primitive::kPrimByte:
628 case Primitive::kPrimChar:
629 case Primitive::kPrimShort:
630 case Primitive::kPrimVoid:
631 LOG(FATAL) << "Unexpected type " << load->GetType();
Andreas Gampe65b798e2015-04-06 09:35:22 -0700632 UNREACHABLE();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100633 }
634
635 LOG(FATAL) << "Unreachable";
Andreas Gampe65b798e2015-04-06 09:35:22 -0700636 UNREACHABLE();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100637}
638
639void CodeGeneratorX86_64::Move(Location destination, Location source) {
640 if (source.Equals(destination)) {
641 return;
642 }
643 if (destination.IsRegister()) {
644 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000645 __ movq(destination.AsRegister<CpuRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100646 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000647 __ movd(destination.AsRegister<CpuRegister>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100648 } else if (source.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000649 __ movl(destination.AsRegister<CpuRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100650 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100651 } else {
652 DCHECK(source.IsDoubleStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +0000653 __ movq(destination.AsRegister<CpuRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100654 Address(CpuRegister(RSP), source.GetStackIndex()));
655 }
656 } else if (destination.IsFpuRegister()) {
657 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000658 __ movd(destination.AsFpuRegister<XmmRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100659 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000660 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100661 } else if (source.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000662 __ movss(destination.AsFpuRegister<XmmRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100663 Address(CpuRegister(RSP), source.GetStackIndex()));
664 } else {
665 DCHECK(source.IsDoubleStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +0000666 __ movsd(destination.AsFpuRegister<XmmRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100667 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100668 }
669 } else if (destination.IsStackSlot()) {
670 if (source.IsRegister()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100671 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +0000672 source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100673 } else if (source.IsFpuRegister()) {
674 __ movss(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +0000675 source.AsFpuRegister<XmmRegister>());
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500676 } else if (source.IsConstant()) {
677 HConstant* constant = source.GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000678 int32_t value = GetInt32ValueOf(constant);
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500679 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), Immediate(value));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100680 } else {
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500681 DCHECK(source.IsStackSlot()) << source;
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000682 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
683 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100684 }
685 } else {
686 DCHECK(destination.IsDoubleStackSlot());
687 if (source.IsRegister()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100688 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +0000689 source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100690 } else if (source.IsFpuRegister()) {
691 __ movsd(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +0000692 source.AsFpuRegister<XmmRegister>());
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500693 } else if (source.IsConstant()) {
694 HConstant* constant = source.GetConstant();
Zheng Xu12bca972015-03-30 19:35:50 +0800695 int64_t value;
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500696 if (constant->IsDoubleConstant()) {
Roland Levillainda4d79b2015-03-24 14:36:11 +0000697 value = bit_cast<int64_t, double>(constant->AsDoubleConstant()->GetValue());
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500698 } else {
699 DCHECK(constant->IsLongConstant());
700 value = constant->AsLongConstant()->GetValue();
701 }
Mark Mendell92e83bf2015-05-07 11:25:03 -0400702 Load64BitValue(CpuRegister(TMP), value);
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500703 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100704 } else {
705 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000706 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
707 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100708 }
709 }
710}
711
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100712void CodeGeneratorX86_64::Move(HInstruction* instruction,
713 Location location,
714 HInstruction* move_for) {
Calin Juravlea21f5982014-11-13 15:53:04 +0000715 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100716 if (instruction->IsCurrentMethod()) {
Mathieu Chartiere3b034a2015-05-31 14:29:23 -0700717 Move(location, Location::DoubleStackSlot(kCurrentMethodStackOffset));
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100718 } else if (locations != nullptr && locations->Out().Equals(location)) {
Calin Juravlea21f5982014-11-13 15:53:04 +0000719 return;
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100720 } else if (locations != nullptr && locations->Out().IsConstant()) {
Calin Juravlea21f5982014-11-13 15:53:04 +0000721 HConstant* const_to_move = locations->Out().GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000722 if (const_to_move->IsIntConstant() || const_to_move->IsNullConstant()) {
723 Immediate imm(GetInt32ValueOf(const_to_move));
Calin Juravlea21f5982014-11-13 15:53:04 +0000724 if (location.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000725 __ movl(location.AsRegister<CpuRegister>(), imm);
Calin Juravlea21f5982014-11-13 15:53:04 +0000726 } else if (location.IsStackSlot()) {
727 __ movl(Address(CpuRegister(RSP), location.GetStackIndex()), imm);
728 } else {
729 DCHECK(location.IsConstant());
730 DCHECK_EQ(location.GetConstant(), const_to_move);
731 }
732 } else if (const_to_move->IsLongConstant()) {
733 int64_t value = const_to_move->AsLongConstant()->GetValue();
734 if (location.IsRegister()) {
Mark Mendell92e83bf2015-05-07 11:25:03 -0400735 Load64BitValue(location.AsRegister<CpuRegister>(), value);
Calin Juravlea21f5982014-11-13 15:53:04 +0000736 } else if (location.IsDoubleStackSlot()) {
Mark Mendell92e83bf2015-05-07 11:25:03 -0400737 Load64BitValue(CpuRegister(TMP), value);
Calin Juravlea21f5982014-11-13 15:53:04 +0000738 __ movq(Address(CpuRegister(RSP), location.GetStackIndex()), CpuRegister(TMP));
739 } else {
740 DCHECK(location.IsConstant());
741 DCHECK_EQ(location.GetConstant(), const_to_move);
742 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100743 }
Roland Levillain476df552014-10-09 17:51:36 +0100744 } else if (instruction->IsLoadLocal()) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100745 switch (instruction->GetType()) {
746 case Primitive::kPrimBoolean:
747 case Primitive::kPrimByte:
748 case Primitive::kPrimChar:
749 case Primitive::kPrimShort:
750 case Primitive::kPrimInt:
751 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100752 case Primitive::kPrimFloat:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100753 Move(location, Location::StackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
754 break;
755
756 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100757 case Primitive::kPrimDouble:
Roland Levillain199f3362014-11-27 17:15:16 +0000758 Move(location,
759 Location::DoubleStackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100760 break;
761
762 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100763 LOG(FATAL) << "Unexpected local type " << instruction->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100764 }
Nicolas Geoffrayf43083d2014-11-07 10:48:10 +0000765 } else if (instruction->IsTemporary()) {
766 Location temp_location = GetTemporaryLocation(instruction->AsTemporary());
767 Move(location, temp_location);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100768 } else {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100769 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100770 switch (instruction->GetType()) {
771 case Primitive::kPrimBoolean:
772 case Primitive::kPrimByte:
773 case Primitive::kPrimChar:
774 case Primitive::kPrimShort:
775 case Primitive::kPrimInt:
776 case Primitive::kPrimNot:
777 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100778 case Primitive::kPrimFloat:
779 case Primitive::kPrimDouble:
Calin Juravlea21f5982014-11-13 15:53:04 +0000780 Move(location, locations->Out());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100781 break;
782
783 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100784 LOG(FATAL) << "Unexpected type " << instruction->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100785 }
786 }
787}
788
David Brazdilfc6a86a2015-06-26 10:33:45 +0000789void InstructionCodeGeneratorX86_64::HandleGoto(HInstruction* got, HBasicBlock* successor) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100790 DCHECK(!successor->IsExitBlock());
791
792 HBasicBlock* block = got->GetBlock();
793 HInstruction* previous = got->GetPrevious();
794
795 HLoopInformation* info = block->GetLoopInformation();
David Brazdil46e2a392015-03-16 17:31:52 +0000796 if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100797 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
798 return;
799 }
800
801 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
802 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
803 }
804 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100805 __ jmp(codegen_->GetLabelOf(successor));
806 }
807}
808
David Brazdilfc6a86a2015-06-26 10:33:45 +0000809void LocationsBuilderX86_64::VisitGoto(HGoto* got) {
810 got->SetLocations(nullptr);
811}
812
813void InstructionCodeGeneratorX86_64::VisitGoto(HGoto* got) {
814 HandleGoto(got, got->GetSuccessor());
815}
816
817void LocationsBuilderX86_64::VisitTryBoundary(HTryBoundary* try_boundary) {
818 try_boundary->SetLocations(nullptr);
819}
820
821void InstructionCodeGeneratorX86_64::VisitTryBoundary(HTryBoundary* try_boundary) {
822 HBasicBlock* successor = try_boundary->GetNormalFlowSuccessor();
823 if (!successor->IsExitBlock()) {
824 HandleGoto(try_boundary, successor);
825 }
826}
827
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100828void LocationsBuilderX86_64::VisitExit(HExit* exit) {
829 exit->SetLocations(nullptr);
830}
831
832void InstructionCodeGeneratorX86_64::VisitExit(HExit* exit) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700833 UNUSED(exit);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100834}
835
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700836void InstructionCodeGeneratorX86_64::GenerateTestAndBranch(HInstruction* instruction,
837 Label* true_target,
838 Label* false_target,
839 Label* always_true_target) {
840 HInstruction* cond = instruction->InputAt(0);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100841 if (cond->IsIntConstant()) {
842 // Constant condition, statically compared against 1.
843 int32_t cond_value = cond->AsIntConstant()->GetValue();
844 if (cond_value == 1) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700845 if (always_true_target != nullptr) {
846 __ jmp(always_true_target);
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100847 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100848 return;
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100849 } else {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100850 DCHECK_EQ(cond_value, 0);
851 }
852 } else {
853 bool materialized =
854 !cond->IsCondition() || cond->AsCondition()->NeedsMaterialization();
855 // Moves do not affect the eflags register, so if the condition is
856 // evaluated just before the if, we don't need to evaluate it
857 // again.
858 bool eflags_set = cond->IsCondition()
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700859 && cond->AsCondition()->IsBeforeWhenDisregardMoves(instruction);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100860 if (materialized) {
861 if (!eflags_set) {
862 // Materialized condition, compare against 0.
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700863 Location lhs = instruction->GetLocations()->InAt(0);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100864 if (lhs.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +0000865 __ testl(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>());
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100866 } else {
867 __ cmpl(Address(CpuRegister(RSP), lhs.GetStackIndex()),
868 Immediate(0));
869 }
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700870 __ j(kNotEqual, true_target);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100871 } else {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700872 __ j(X86_64Condition(cond->AsCondition()->GetCondition()), true_target);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100873 }
874 } else {
875 Location lhs = cond->GetLocations()->InAt(0);
876 Location rhs = cond->GetLocations()->InAt(1);
877 if (rhs.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000878 __ cmpl(lhs.AsRegister<CpuRegister>(), rhs.AsRegister<CpuRegister>());
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100879 } else if (rhs.IsConstant()) {
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000880 int32_t constant = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
Nicolas Geoffray748f1402015-01-27 08:17:54 +0000881 if (constant == 0) {
882 __ testl(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>());
883 } else {
884 __ cmpl(lhs.AsRegister<CpuRegister>(), Immediate(constant));
885 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100886 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000887 __ cmpl(lhs.AsRegister<CpuRegister>(),
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100888 Address(CpuRegister(RSP), rhs.GetStackIndex()));
889 }
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700890 __ j(X86_64Condition(cond->AsCondition()->GetCondition()), true_target);
Dave Allison20dfc792014-06-16 20:44:29 -0700891 }
Dave Allison20dfc792014-06-16 20:44:29 -0700892 }
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700893 if (false_target != nullptr) {
894 __ jmp(false_target);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100895 }
896}
897
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700898void LocationsBuilderX86_64::VisitIf(HIf* if_instr) {
899 LocationSummary* locations =
900 new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall);
901 HInstruction* cond = if_instr->InputAt(0);
902 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
903 locations->SetInAt(0, Location::Any());
904 }
905}
906
907void InstructionCodeGeneratorX86_64::VisitIf(HIf* if_instr) {
908 Label* true_target = codegen_->GetLabelOf(if_instr->IfTrueSuccessor());
909 Label* false_target = codegen_->GetLabelOf(if_instr->IfFalseSuccessor());
910 Label* always_true_target = true_target;
911 if (codegen_->GoesToNextBlock(if_instr->GetBlock(),
912 if_instr->IfTrueSuccessor())) {
913 always_true_target = nullptr;
914 }
915 if (codegen_->GoesToNextBlock(if_instr->GetBlock(),
916 if_instr->IfFalseSuccessor())) {
917 false_target = nullptr;
918 }
919 GenerateTestAndBranch(if_instr, true_target, false_target, always_true_target);
920}
921
922void LocationsBuilderX86_64::VisitDeoptimize(HDeoptimize* deoptimize) {
923 LocationSummary* locations = new (GetGraph()->GetArena())
924 LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
925 HInstruction* cond = deoptimize->InputAt(0);
926 DCHECK(cond->IsCondition());
927 if (cond->AsCondition()->NeedsMaterialization()) {
928 locations->SetInAt(0, Location::Any());
929 }
930}
931
932void InstructionCodeGeneratorX86_64::VisitDeoptimize(HDeoptimize* deoptimize) {
933 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena())
934 DeoptimizationSlowPathX86_64(deoptimize);
935 codegen_->AddSlowPath(slow_path);
936 Label* slow_path_entry = slow_path->GetEntryLabel();
937 GenerateTestAndBranch(deoptimize, slow_path_entry, nullptr, slow_path_entry);
938}
939
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100940void LocationsBuilderX86_64::VisitLocal(HLocal* local) {
941 local->SetLocations(nullptr);
942}
943
944void InstructionCodeGeneratorX86_64::VisitLocal(HLocal* local) {
945 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
946}
947
948void LocationsBuilderX86_64::VisitLoadLocal(HLoadLocal* local) {
949 local->SetLocations(nullptr);
950}
951
952void InstructionCodeGeneratorX86_64::VisitLoadLocal(HLoadLocal* load) {
953 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700954 UNUSED(load);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100955}
956
957void LocationsBuilderX86_64::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100958 LocationSummary* locations =
959 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100960 switch (store->InputAt(1)->GetType()) {
961 case Primitive::kPrimBoolean:
962 case Primitive::kPrimByte:
963 case Primitive::kPrimChar:
964 case Primitive::kPrimShort:
965 case Primitive::kPrimInt:
966 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100967 case Primitive::kPrimFloat:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100968 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
969 break;
970
971 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100972 case Primitive::kPrimDouble:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100973 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
974 break;
975
976 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100977 LOG(FATAL) << "Unexpected local type " << store->InputAt(1)->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100978 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100979}
980
981void InstructionCodeGeneratorX86_64::VisitStoreLocal(HStoreLocal* store) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700982 UNUSED(store);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100983}
984
Roland Levillain0d37cd02015-05-27 16:39:19 +0100985void LocationsBuilderX86_64::VisitCondition(HCondition* cond) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100986 LocationSummary* locations =
Roland Levillain0d37cd02015-05-27 16:39:19 +0100987 new (GetGraph()->GetArena()) LocationSummary(cond, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +0100988 locations->SetInAt(0, Location::RequiresRegister());
989 locations->SetInAt(1, Location::Any());
Roland Levillain0d37cd02015-05-27 16:39:19 +0100990 if (cond->NeedsMaterialization()) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100991 locations->SetOut(Location::RequiresRegister());
992 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100993}
994
Roland Levillain0d37cd02015-05-27 16:39:19 +0100995void InstructionCodeGeneratorX86_64::VisitCondition(HCondition* cond) {
996 if (cond->NeedsMaterialization()) {
997 LocationSummary* locations = cond->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +0000998 CpuRegister reg = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100999 // Clear register: setcc only sets the low byte.
Mark Mendell92e83bf2015-05-07 11:25:03 -04001000 __ xorl(reg, reg);
Nicolas Geoffray748f1402015-01-27 08:17:54 +00001001 Location lhs = locations->InAt(0);
1002 Location rhs = locations->InAt(1);
1003 if (rhs.IsRegister()) {
1004 __ cmpl(lhs.AsRegister<CpuRegister>(), rhs.AsRegister<CpuRegister>());
1005 } else if (rhs.IsConstant()) {
Mingyao Yangdc5ac732015-02-25 11:28:05 -08001006 int32_t constant = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
Nicolas Geoffray748f1402015-01-27 08:17:54 +00001007 if (constant == 0) {
1008 __ testl(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>());
1009 } else {
1010 __ cmpl(lhs.AsRegister<CpuRegister>(), Immediate(constant));
1011 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001012 } else {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00001013 __ cmpl(lhs.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), rhs.GetStackIndex()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001014 }
Roland Levillain0d37cd02015-05-27 16:39:19 +01001015 __ setcc(X86_64Condition(cond->GetCondition()), reg);
Dave Allison20dfc792014-06-16 20:44:29 -07001016 }
1017}
1018
1019void LocationsBuilderX86_64::VisitEqual(HEqual* comp) {
1020 VisitCondition(comp);
1021}
1022
1023void InstructionCodeGeneratorX86_64::VisitEqual(HEqual* comp) {
1024 VisitCondition(comp);
1025}
1026
1027void LocationsBuilderX86_64::VisitNotEqual(HNotEqual* comp) {
1028 VisitCondition(comp);
1029}
1030
1031void InstructionCodeGeneratorX86_64::VisitNotEqual(HNotEqual* comp) {
1032 VisitCondition(comp);
1033}
1034
1035void LocationsBuilderX86_64::VisitLessThan(HLessThan* comp) {
1036 VisitCondition(comp);
1037}
1038
1039void InstructionCodeGeneratorX86_64::VisitLessThan(HLessThan* comp) {
1040 VisitCondition(comp);
1041}
1042
1043void LocationsBuilderX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1044 VisitCondition(comp);
1045}
1046
1047void InstructionCodeGeneratorX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1048 VisitCondition(comp);
1049}
1050
1051void LocationsBuilderX86_64::VisitGreaterThan(HGreaterThan* comp) {
1052 VisitCondition(comp);
1053}
1054
1055void InstructionCodeGeneratorX86_64::VisitGreaterThan(HGreaterThan* comp) {
1056 VisitCondition(comp);
1057}
1058
1059void LocationsBuilderX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1060 VisitCondition(comp);
1061}
1062
1063void InstructionCodeGeneratorX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1064 VisitCondition(comp);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001065}
1066
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001067void LocationsBuilderX86_64::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001068 LocationSummary* locations =
1069 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Calin Juravleddb7df22014-11-25 20:56:51 +00001070 switch (compare->InputAt(0)->GetType()) {
1071 case Primitive::kPrimLong: {
1072 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell40741f32015-04-20 22:10:34 -04001073 locations->SetInAt(1, Location::Any());
Calin Juravleddb7df22014-11-25 20:56:51 +00001074 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1075 break;
1076 }
1077 case Primitive::kPrimFloat:
1078 case Primitive::kPrimDouble: {
1079 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendell40741f32015-04-20 22:10:34 -04001080 locations->SetInAt(1, Location::Any());
Calin Juravleddb7df22014-11-25 20:56:51 +00001081 locations->SetOut(Location::RequiresRegister());
1082 break;
1083 }
1084 default:
1085 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
1086 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001087}
1088
1089void InstructionCodeGeneratorX86_64::VisitCompare(HCompare* compare) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001090 LocationSummary* locations = compare->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00001091 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Calin Juravleddb7df22014-11-25 20:56:51 +00001092 Location left = locations->InAt(0);
1093 Location right = locations->InAt(1);
1094
1095 Label less, greater, done;
1096 Primitive::Type type = compare->InputAt(0)->GetType();
1097 switch (type) {
1098 case Primitive::kPrimLong: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04001099 CpuRegister left_reg = left.AsRegister<CpuRegister>();
1100 if (right.IsConstant()) {
1101 int64_t value = right.GetConstant()->AsLongConstant()->GetValue();
Mark Mendell40741f32015-04-20 22:10:34 -04001102 if (IsInt<32>(value)) {
1103 if (value == 0) {
1104 __ testq(left_reg, left_reg);
1105 } else {
1106 __ cmpq(left_reg, Immediate(static_cast<int32_t>(value)));
1107 }
Mark Mendell3f6c7f62015-03-13 13:47:53 -04001108 } else {
Mark Mendell40741f32015-04-20 22:10:34 -04001109 // Value won't fit in an int.
1110 __ cmpq(left_reg, codegen_->LiteralInt64Address(value));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04001111 }
Mark Mendell40741f32015-04-20 22:10:34 -04001112 } else if (right.IsDoubleStackSlot()) {
1113 __ cmpq(left_reg, Address(CpuRegister(RSP), right.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04001114 } else {
1115 __ cmpq(left_reg, right.AsRegister<CpuRegister>());
1116 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001117 break;
Calin Juravleddb7df22014-11-25 20:56:51 +00001118 }
1119 case Primitive::kPrimFloat: {
Mark Mendell40741f32015-04-20 22:10:34 -04001120 XmmRegister left_reg = left.AsFpuRegister<XmmRegister>();
1121 if (right.IsConstant()) {
1122 float value = right.GetConstant()->AsFloatConstant()->GetValue();
1123 __ ucomiss(left_reg, codegen_->LiteralFloatAddress(value));
1124 } else if (right.IsStackSlot()) {
1125 __ ucomiss(left_reg, Address(CpuRegister(RSP), right.GetStackIndex()));
1126 } else {
1127 __ ucomiss(left_reg, right.AsFpuRegister<XmmRegister>());
1128 }
Calin Juravleddb7df22014-11-25 20:56:51 +00001129 __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
1130 break;
1131 }
1132 case Primitive::kPrimDouble: {
Mark Mendell40741f32015-04-20 22:10:34 -04001133 XmmRegister left_reg = left.AsFpuRegister<XmmRegister>();
1134 if (right.IsConstant()) {
1135 double value = right.GetConstant()->AsDoubleConstant()->GetValue();
1136 __ ucomisd(left_reg, codegen_->LiteralDoubleAddress(value));
1137 } else if (right.IsDoubleStackSlot()) {
1138 __ ucomisd(left_reg, Address(CpuRegister(RSP), right.GetStackIndex()));
1139 } else {
1140 __ ucomisd(left_reg, right.AsFpuRegister<XmmRegister>());
1141 }
Calin Juravleddb7df22014-11-25 20:56:51 +00001142 __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
1143 break;
1144 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001145 default:
Calin Juravleddb7df22014-11-25 20:56:51 +00001146 LOG(FATAL) << "Unexpected compare type " << type;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001147 }
Calin Juravleddb7df22014-11-25 20:56:51 +00001148 __ movl(out, Immediate(0));
Calin Juravle91debbc2014-11-26 19:01:09 +00001149 __ j(kEqual, &done);
Calin Juravleddb7df22014-11-25 20:56:51 +00001150 __ j(type == Primitive::kPrimLong ? kLess : kBelow, &less); // ucomis{s,d} sets CF (kBelow)
Calin Juravlefd861242014-11-25 20:56:51 +00001151
Calin Juravle91debbc2014-11-26 19:01:09 +00001152 __ Bind(&greater);
Calin Juravleddb7df22014-11-25 20:56:51 +00001153 __ movl(out, Immediate(1));
1154 __ jmp(&done);
1155
1156 __ Bind(&less);
1157 __ movl(out, Immediate(-1));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001158
1159 __ Bind(&done);
1160}
1161
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001162void LocationsBuilderX86_64::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001163 LocationSummary* locations =
1164 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001165 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001166}
1167
1168void InstructionCodeGeneratorX86_64::VisitIntConstant(HIntConstant* constant) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001169 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001170 UNUSED(constant);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001171}
1172
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001173void LocationsBuilderX86_64::VisitNullConstant(HNullConstant* constant) {
1174 LocationSummary* locations =
1175 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1176 locations->SetOut(Location::ConstantLocation(constant));
1177}
1178
1179void InstructionCodeGeneratorX86_64::VisitNullConstant(HNullConstant* constant) {
1180 // Will be generated at use site.
1181 UNUSED(constant);
1182}
1183
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001184void LocationsBuilderX86_64::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001185 LocationSummary* locations =
1186 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001187 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001188}
1189
1190void InstructionCodeGeneratorX86_64::VisitLongConstant(HLongConstant* constant) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001191 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001192 UNUSED(constant);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001193}
1194
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001195void LocationsBuilderX86_64::VisitFloatConstant(HFloatConstant* constant) {
1196 LocationSummary* locations =
1197 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1198 locations->SetOut(Location::ConstantLocation(constant));
1199}
1200
1201void InstructionCodeGeneratorX86_64::VisitFloatConstant(HFloatConstant* constant) {
1202 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001203 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001204}
1205
1206void LocationsBuilderX86_64::VisitDoubleConstant(HDoubleConstant* constant) {
1207 LocationSummary* locations =
1208 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1209 locations->SetOut(Location::ConstantLocation(constant));
1210}
1211
1212void InstructionCodeGeneratorX86_64::VisitDoubleConstant(HDoubleConstant* constant) {
1213 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001214 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001215}
1216
Calin Juravle27df7582015-04-17 19:12:31 +01001217void LocationsBuilderX86_64::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
1218 memory_barrier->SetLocations(nullptr);
1219}
1220
1221void InstructionCodeGeneratorX86_64::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
1222 GenerateMemoryBarrier(memory_barrier->GetBarrierKind());
1223}
1224
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001225void LocationsBuilderX86_64::VisitReturnVoid(HReturnVoid* ret) {
1226 ret->SetLocations(nullptr);
1227}
1228
1229void InstructionCodeGeneratorX86_64::VisitReturnVoid(HReturnVoid* ret) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001230 UNUSED(ret);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001231 codegen_->GenerateFrameExit();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001232}
1233
1234void LocationsBuilderX86_64::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001235 LocationSummary* locations =
1236 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001237 switch (ret->InputAt(0)->GetType()) {
1238 case Primitive::kPrimBoolean:
1239 case Primitive::kPrimByte:
1240 case Primitive::kPrimChar:
1241 case Primitive::kPrimShort:
1242 case Primitive::kPrimInt:
1243 case Primitive::kPrimNot:
1244 case Primitive::kPrimLong:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001245 locations->SetInAt(0, Location::RegisterLocation(RAX));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001246 break;
1247
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001248 case Primitive::kPrimFloat:
1249 case Primitive::kPrimDouble:
Mark Mendell40741f32015-04-20 22:10:34 -04001250 locations->SetInAt(0, Location::FpuRegisterLocation(XMM0));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001251 break;
1252
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001253 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001254 LOG(FATAL) << "Unexpected return type " << ret->InputAt(0)->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001255 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001256}
1257
1258void InstructionCodeGeneratorX86_64::VisitReturn(HReturn* ret) {
1259 if (kIsDebugBuild) {
1260 switch (ret->InputAt(0)->GetType()) {
1261 case Primitive::kPrimBoolean:
1262 case Primitive::kPrimByte:
1263 case Primitive::kPrimChar:
1264 case Primitive::kPrimShort:
1265 case Primitive::kPrimInt:
1266 case Primitive::kPrimNot:
1267 case Primitive::kPrimLong:
Roland Levillain271ab9c2014-11-27 15:23:57 +00001268 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegister<CpuRegister>().AsRegister(), RAX);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001269 break;
1270
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001271 case Primitive::kPrimFloat:
1272 case Primitive::kPrimDouble:
Roland Levillain271ab9c2014-11-27 15:23:57 +00001273 DCHECK_EQ(ret->GetLocations()->InAt(0).AsFpuRegister<XmmRegister>().AsFloatRegister(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001274 XMM0);
1275 break;
1276
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001277 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001278 LOG(FATAL) << "Unexpected return type " << ret->InputAt(0)->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001279 }
1280 }
1281 codegen_->GenerateFrameExit();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001282}
1283
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01001284Location InvokeDexCallingConventionVisitorX86_64::GetReturnLocation(Primitive::Type type) const {
1285 switch (type) {
1286 case Primitive::kPrimBoolean:
1287 case Primitive::kPrimByte:
1288 case Primitive::kPrimChar:
1289 case Primitive::kPrimShort:
1290 case Primitive::kPrimInt:
1291 case Primitive::kPrimNot:
1292 case Primitive::kPrimLong:
1293 return Location::RegisterLocation(RAX);
1294
1295 case Primitive::kPrimVoid:
1296 return Location::NoLocation();
1297
1298 case Primitive::kPrimDouble:
1299 case Primitive::kPrimFloat:
1300 return Location::FpuRegisterLocation(XMM0);
1301 }
Nicolas Geoffray0d1652e2015-06-03 12:12:19 +01001302
1303 UNREACHABLE();
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01001304}
1305
1306Location InvokeDexCallingConventionVisitorX86_64::GetMethodLocation() const {
1307 return Location::RegisterLocation(kMethodRegisterArgument);
1308}
1309
Roland Levillain2d27c8e2015-04-28 15:48:45 +01001310Location InvokeDexCallingConventionVisitorX86_64::GetNextLocation(Primitive::Type type) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001311 switch (type) {
1312 case Primitive::kPrimBoolean:
1313 case Primitive::kPrimByte:
1314 case Primitive::kPrimChar:
1315 case Primitive::kPrimShort:
1316 case Primitive::kPrimInt:
1317 case Primitive::kPrimNot: {
1318 uint32_t index = gp_index_++;
1319 stack_index_++;
1320 if (index < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001321 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001322 } else {
1323 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
1324 }
1325 }
1326
1327 case Primitive::kPrimLong: {
1328 uint32_t index = gp_index_;
1329 stack_index_ += 2;
1330 if (index < calling_convention.GetNumberOfRegisters()) {
1331 gp_index_ += 1;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001332 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001333 } else {
1334 gp_index_ += 2;
1335 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
1336 }
1337 }
1338
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001339 case Primitive::kPrimFloat: {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01001340 uint32_t index = float_index_++;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001341 stack_index_++;
1342 if (index < calling_convention.GetNumberOfFpuRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001343 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001344 } else {
1345 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
1346 }
1347 }
1348
1349 case Primitive::kPrimDouble: {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01001350 uint32_t index = float_index_++;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001351 stack_index_ += 2;
1352 if (index < calling_convention.GetNumberOfFpuRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001353 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001354 } else {
1355 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
1356 }
1357 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001358
1359 case Primitive::kPrimVoid:
1360 LOG(FATAL) << "Unexpected parameter type " << type;
1361 break;
1362 }
1363 return Location();
1364}
1365
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001366void LocationsBuilderX86_64::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Roland Levillain3e3d7332015-04-28 11:00:54 +01001367 // When we do not run baseline, explicit clinit checks triggered by static
1368 // invokes must have been pruned by art::PrepareForRegisterAllocation.
1369 DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01001370
Mark Mendellfb8d2792015-03-31 22:16:59 -04001371 IntrinsicLocationsBuilderX86_64 intrinsic(codegen_);
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001372 if (intrinsic.TryDispatch(invoke)) {
1373 return;
1374 }
1375
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001376 HandleInvoke(invoke);
1377}
1378
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001379static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorX86_64* codegen) {
1380 if (invoke->GetLocations()->Intrinsified()) {
1381 IntrinsicCodeGeneratorX86_64 intrinsic(codegen);
1382 intrinsic.Dispatch(invoke);
1383 return true;
1384 }
1385 return false;
1386}
1387
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001388void InstructionCodeGeneratorX86_64::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Roland Levillain3e3d7332015-04-28 11:00:54 +01001389 // When we do not run baseline, explicit clinit checks triggered by static
1390 // invokes must have been pruned by art::PrepareForRegisterAllocation.
1391 DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01001392
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001393 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1394 return;
1395 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001396
Nicolas Geoffray38207af2015-06-01 15:46:22 +01001397 LocationSummary* locations = invoke->GetLocations();
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001398 codegen_->GenerateStaticOrDirectCall(
Nicolas Geoffray38207af2015-06-01 15:46:22 +01001399 invoke, locations->HasTemps() ? locations->GetTemp(0) : Location::NoLocation());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +00001400 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001401}
1402
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001403void LocationsBuilderX86_64::HandleInvoke(HInvoke* invoke) {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01001404 InvokeDexCallingConventionVisitorX86_64 calling_convention_visitor;
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01001405 CodeGenerator::CreateCommonInvokeLocationSummary(invoke, &calling_convention_visitor);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001406}
1407
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001408void LocationsBuilderX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Mark Mendellfb8d2792015-03-31 22:16:59 -04001409 IntrinsicLocationsBuilderX86_64 intrinsic(codegen_);
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001410 if (intrinsic.TryDispatch(invoke)) {
1411 return;
1412 }
1413
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001414 HandleInvoke(invoke);
1415}
1416
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001417void InstructionCodeGeneratorX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001418 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1419 return;
1420 }
1421
Roland Levillain271ab9c2014-11-27 15:23:57 +00001422 CpuRegister temp = invoke->GetLocations()->GetTemp(0).AsRegister<CpuRegister>();
Mathieu Chartiere401d142015-04-22 13:56:20 -07001423 size_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
1424 invoke->GetVTableIndex(), kX86_64PointerSize).SizeValue();
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001425 LocationSummary* locations = invoke->GetLocations();
1426 Location receiver = locations->InAt(0);
1427 size_t class_offset = mirror::Object::ClassOffset().SizeValue();
1428 // temp = object->GetClass();
Nicolas Geoffray38207af2015-06-01 15:46:22 +01001429 DCHECK(receiver.IsRegister());
1430 __ movl(temp, Address(receiver.AsRegister<CpuRegister>(), class_offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00001431 codegen_->MaybeRecordImplicitNullCheck(invoke);
Roland Levillain4d027112015-07-01 15:41:14 +01001432 __ MaybeUnpoisonHeapReference(temp);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001433 // temp = temp->GetMethodAt(method_offset);
Mathieu Chartiere401d142015-04-22 13:56:20 -07001434 __ movq(temp, Address(temp, method_offset));
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001435 // call temp->GetEntryPoint();
Mathieu Chartiere401d142015-04-22 13:56:20 -07001436 __ call(Address(temp, ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001437 kX86_64WordSize).SizeValue()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001438
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001439 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray39468442014-09-02 15:17:15 +01001440 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001441}
1442
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001443void LocationsBuilderX86_64::VisitInvokeInterface(HInvokeInterface* invoke) {
1444 HandleInvoke(invoke);
1445 // Add the hidden argument.
1446 invoke->GetLocations()->AddTemp(Location::RegisterLocation(RAX));
1447}
1448
1449void InstructionCodeGeneratorX86_64::VisitInvokeInterface(HInvokeInterface* invoke) {
1450 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001451 CpuRegister temp = invoke->GetLocations()->GetTemp(0).AsRegister<CpuRegister>();
Mathieu Chartiere401d142015-04-22 13:56:20 -07001452 uint32_t method_offset = mirror::Class::EmbeddedImTableEntryOffset(
1453 invoke->GetImtIndex() % mirror::Class::kImtSize, kX86_64PointerSize).Uint32Value();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001454 LocationSummary* locations = invoke->GetLocations();
1455 Location receiver = locations->InAt(0);
1456 size_t class_offset = mirror::Object::ClassOffset().SizeValue();
1457
1458 // Set the hidden argument.
Mark Mendell92e83bf2015-05-07 11:25:03 -04001459 CpuRegister hidden_reg = invoke->GetLocations()->GetTemp(1).AsRegister<CpuRegister>();
1460 codegen_->Load64BitValue(hidden_reg, invoke->GetDexMethodIndex());
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001461
1462 // temp = object->GetClass();
1463 if (receiver.IsStackSlot()) {
1464 __ movl(temp, Address(CpuRegister(RSP), receiver.GetStackIndex()));
1465 __ movl(temp, Address(temp, class_offset));
1466 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001467 __ movl(temp, Address(receiver.AsRegister<CpuRegister>(), class_offset));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001468 }
Calin Juravle77520bc2015-01-12 18:45:46 +00001469 codegen_->MaybeRecordImplicitNullCheck(invoke);
Roland Levillain4d027112015-07-01 15:41:14 +01001470 __ MaybeUnpoisonHeapReference(temp);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001471 // temp = temp->GetImtEntryAt(method_offset);
Mathieu Chartiere401d142015-04-22 13:56:20 -07001472 __ movq(temp, Address(temp, method_offset));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001473 // call temp->GetEntryPoint();
Mathieu Chartiere401d142015-04-22 13:56:20 -07001474 __ call(Address(temp, ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001475 kX86_64WordSize).SizeValue()));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001476
1477 DCHECK(!codegen_->IsLeafMethod());
1478 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1479}
1480
Roland Levillain88cb1752014-10-20 16:36:47 +01001481void LocationsBuilderX86_64::VisitNeg(HNeg* neg) {
1482 LocationSummary* locations =
1483 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
1484 switch (neg->GetResultType()) {
1485 case Primitive::kPrimInt:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001486 case Primitive::kPrimLong:
Roland Levillain88cb1752014-10-20 16:36:47 +01001487 locations->SetInAt(0, Location::RequiresRegister());
1488 locations->SetOut(Location::SameAsFirstInput());
1489 break;
1490
Roland Levillain88cb1752014-10-20 16:36:47 +01001491 case Primitive::kPrimFloat:
1492 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001493 locations->SetInAt(0, Location::RequiresFpuRegister());
Roland Levillain5368c212014-11-27 15:03:41 +00001494 locations->SetOut(Location::SameAsFirstInput());
Roland Levillain5368c212014-11-27 15:03:41 +00001495 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain88cb1752014-10-20 16:36:47 +01001496 break;
1497
1498 default:
1499 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1500 }
1501}
1502
1503void InstructionCodeGeneratorX86_64::VisitNeg(HNeg* neg) {
1504 LocationSummary* locations = neg->GetLocations();
1505 Location out = locations->Out();
1506 Location in = locations->InAt(0);
1507 switch (neg->GetResultType()) {
1508 case Primitive::kPrimInt:
1509 DCHECK(in.IsRegister());
Roland Levillain3dbcb382014-10-28 17:30:07 +00001510 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001511 __ negl(out.AsRegister<CpuRegister>());
Roland Levillain88cb1752014-10-20 16:36:47 +01001512 break;
1513
1514 case Primitive::kPrimLong:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001515 DCHECK(in.IsRegister());
Roland Levillain3dbcb382014-10-28 17:30:07 +00001516 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001517 __ negq(out.AsRegister<CpuRegister>());
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001518 break;
1519
Roland Levillain5368c212014-11-27 15:03:41 +00001520 case Primitive::kPrimFloat: {
1521 DCHECK(in.Equals(out));
Mark Mendell40741f32015-04-20 22:10:34 -04001522 XmmRegister mask = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
Roland Levillain5368c212014-11-27 15:03:41 +00001523 // Implement float negation with an exclusive or with value
1524 // 0x80000000 (mask for bit 31, representing the sign of a
1525 // single-precision floating-point number).
Mark Mendell40741f32015-04-20 22:10:34 -04001526 __ movss(mask, codegen_->LiteralInt32Address(0x80000000));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001527 __ xorps(out.AsFpuRegister<XmmRegister>(), mask);
Roland Levillain3dbcb382014-10-28 17:30:07 +00001528 break;
Roland Levillain5368c212014-11-27 15:03:41 +00001529 }
Roland Levillain3dbcb382014-10-28 17:30:07 +00001530
Roland Levillain5368c212014-11-27 15:03:41 +00001531 case Primitive::kPrimDouble: {
1532 DCHECK(in.Equals(out));
Mark Mendell40741f32015-04-20 22:10:34 -04001533 XmmRegister mask = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
Roland Levillain5368c212014-11-27 15:03:41 +00001534 // Implement double negation with an exclusive or with value
Roland Levillain3dbcb382014-10-28 17:30:07 +00001535 // 0x8000000000000000 (mask for bit 63, representing the sign of
Roland Levillain5368c212014-11-27 15:03:41 +00001536 // a double-precision floating-point number).
Mark Mendell40741f32015-04-20 22:10:34 -04001537 __ movsd(mask, codegen_->LiteralInt64Address(INT64_C(0x8000000000000000)));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001538 __ xorpd(out.AsFpuRegister<XmmRegister>(), mask);
Roland Levillain88cb1752014-10-20 16:36:47 +01001539 break;
Roland Levillain5368c212014-11-27 15:03:41 +00001540 }
Roland Levillain88cb1752014-10-20 16:36:47 +01001541
1542 default:
1543 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1544 }
1545}
1546
Roland Levillaindff1f282014-11-05 14:15:05 +00001547void LocationsBuilderX86_64::VisitTypeConversion(HTypeConversion* conversion) {
1548 LocationSummary* locations =
1549 new (GetGraph()->GetArena()) LocationSummary(conversion, LocationSummary::kNoCall);
1550 Primitive::Type result_type = conversion->GetResultType();
1551 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00001552 DCHECK_NE(result_type, input_type);
David Brazdil46e2a392015-03-16 17:31:52 +00001553
David Brazdilb2bd1c52015-03-25 11:17:37 +00001554 // The Java language does not allow treating boolean as an integral type but
1555 // our bit representation makes it safe.
David Brazdil46e2a392015-03-16 17:31:52 +00001556
Roland Levillaindff1f282014-11-05 14:15:05 +00001557 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00001558 case Primitive::kPrimByte:
1559 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001560 case Primitive::kPrimBoolean:
1561 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001562 case Primitive::kPrimShort:
1563 case Primitive::kPrimInt:
1564 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001565 // Processing a Dex `int-to-byte' instruction.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001566 locations->SetInAt(0, Location::Any());
1567 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1568 break;
1569
1570 default:
1571 LOG(FATAL) << "Unexpected type conversion from " << input_type
1572 << " to " << result_type;
1573 }
1574 break;
1575
Roland Levillain01a8d712014-11-14 16:27:39 +00001576 case Primitive::kPrimShort:
1577 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001578 case Primitive::kPrimBoolean:
1579 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00001580 case Primitive::kPrimByte:
1581 case Primitive::kPrimInt:
1582 case Primitive::kPrimChar:
1583 // Processing a Dex `int-to-short' instruction.
1584 locations->SetInAt(0, Location::Any());
1585 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1586 break;
1587
1588 default:
1589 LOG(FATAL) << "Unexpected type conversion from " << input_type
1590 << " to " << result_type;
1591 }
1592 break;
1593
Roland Levillain946e1432014-11-11 17:35:19 +00001594 case Primitive::kPrimInt:
1595 switch (input_type) {
1596 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00001597 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00001598 locations->SetInAt(0, Location::Any());
1599 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1600 break;
1601
1602 case Primitive::kPrimFloat:
Roland Levillain3f8f9362014-12-02 17:45:01 +00001603 // Processing a Dex `float-to-int' instruction.
1604 locations->SetInAt(0, Location::RequiresFpuRegister());
1605 locations->SetOut(Location::RequiresRegister());
1606 locations->AddTemp(Location::RequiresFpuRegister());
1607 break;
1608
Roland Levillain946e1432014-11-11 17:35:19 +00001609 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001610 // Processing a Dex `double-to-int' instruction.
1611 locations->SetInAt(0, Location::RequiresFpuRegister());
1612 locations->SetOut(Location::RequiresRegister());
1613 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain946e1432014-11-11 17:35:19 +00001614 break;
1615
1616 default:
1617 LOG(FATAL) << "Unexpected type conversion from " << input_type
1618 << " to " << result_type;
1619 }
1620 break;
1621
Roland Levillaindff1f282014-11-05 14:15:05 +00001622 case Primitive::kPrimLong:
1623 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001624 case Primitive::kPrimBoolean:
1625 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00001626 case Primitive::kPrimByte:
1627 case Primitive::kPrimShort:
1628 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00001629 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001630 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00001631 // TODO: We would benefit from a (to-be-implemented)
1632 // Location::RegisterOrStackSlot requirement for this input.
1633 locations->SetInAt(0, Location::RequiresRegister());
1634 locations->SetOut(Location::RequiresRegister());
1635 break;
1636
1637 case Primitive::kPrimFloat:
Roland Levillain624279f2014-12-04 11:54:28 +00001638 // Processing a Dex `float-to-long' instruction.
1639 locations->SetInAt(0, Location::RequiresFpuRegister());
1640 locations->SetOut(Location::RequiresRegister());
1641 locations->AddTemp(Location::RequiresFpuRegister());
1642 break;
1643
Roland Levillaindff1f282014-11-05 14:15:05 +00001644 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001645 // Processing a Dex `double-to-long' instruction.
1646 locations->SetInAt(0, Location::RequiresFpuRegister());
1647 locations->SetOut(Location::RequiresRegister());
1648 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillaindff1f282014-11-05 14:15:05 +00001649 break;
1650
1651 default:
1652 LOG(FATAL) << "Unexpected type conversion from " << input_type
1653 << " to " << result_type;
1654 }
1655 break;
1656
Roland Levillain981e4542014-11-14 11:47:14 +00001657 case Primitive::kPrimChar:
1658 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001659 case Primitive::kPrimBoolean:
1660 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00001661 case Primitive::kPrimByte:
1662 case Primitive::kPrimShort:
1663 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00001664 // Processing a Dex `int-to-char' instruction.
1665 locations->SetInAt(0, Location::Any());
1666 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1667 break;
1668
1669 default:
1670 LOG(FATAL) << "Unexpected type conversion from " << input_type
1671 << " to " << result_type;
1672 }
1673 break;
1674
Roland Levillaindff1f282014-11-05 14:15:05 +00001675 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00001676 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001677 case Primitive::kPrimBoolean:
1678 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001679 case Primitive::kPrimByte:
1680 case Primitive::kPrimShort:
1681 case Primitive::kPrimInt:
1682 case Primitive::kPrimChar:
1683 // Processing a Dex `int-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04001684 locations->SetInAt(0, Location::Any());
Roland Levillaincff13742014-11-17 14:32:17 +00001685 locations->SetOut(Location::RequiresFpuRegister());
1686 break;
1687
1688 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00001689 // Processing a Dex `long-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04001690 locations->SetInAt(0, Location::Any());
Roland Levillain6d0e4832014-11-27 18:31:21 +00001691 locations->SetOut(Location::RequiresFpuRegister());
1692 break;
1693
Roland Levillaincff13742014-11-17 14:32:17 +00001694 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001695 // Processing a Dex `double-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04001696 locations->SetInAt(0, Location::Any());
Roland Levillain8964e2b2014-12-04 12:10:50 +00001697 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00001698 break;
1699
1700 default:
1701 LOG(FATAL) << "Unexpected type conversion from " << input_type
1702 << " to " << result_type;
1703 };
1704 break;
1705
Roland Levillaindff1f282014-11-05 14:15:05 +00001706 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00001707 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001708 case Primitive::kPrimBoolean:
1709 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001710 case Primitive::kPrimByte:
1711 case Primitive::kPrimShort:
1712 case Primitive::kPrimInt:
1713 case Primitive::kPrimChar:
1714 // Processing a Dex `int-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04001715 locations->SetInAt(0, Location::Any());
Roland Levillaincff13742014-11-17 14:32:17 +00001716 locations->SetOut(Location::RequiresFpuRegister());
1717 break;
1718
1719 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00001720 // Processing a Dex `long-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04001721 locations->SetInAt(0, Location::Any());
Roland Levillain647b9ed2014-11-27 12:06:00 +00001722 locations->SetOut(Location::RequiresFpuRegister());
1723 break;
1724
Roland Levillaincff13742014-11-17 14:32:17 +00001725 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001726 // Processing a Dex `float-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04001727 locations->SetInAt(0, Location::Any());
Roland Levillain8964e2b2014-12-04 12:10:50 +00001728 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00001729 break;
1730
1731 default:
1732 LOG(FATAL) << "Unexpected type conversion from " << input_type
1733 << " to " << result_type;
1734 }
Roland Levillaindff1f282014-11-05 14:15:05 +00001735 break;
1736
1737 default:
1738 LOG(FATAL) << "Unexpected type conversion from " << input_type
1739 << " to " << result_type;
1740 }
1741}
1742
1743void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conversion) {
1744 LocationSummary* locations = conversion->GetLocations();
1745 Location out = locations->Out();
1746 Location in = locations->InAt(0);
1747 Primitive::Type result_type = conversion->GetResultType();
1748 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00001749 DCHECK_NE(result_type, input_type);
Roland Levillaindff1f282014-11-05 14:15:05 +00001750 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00001751 case Primitive::kPrimByte:
1752 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001753 case Primitive::kPrimBoolean:
1754 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001755 case Primitive::kPrimShort:
1756 case Primitive::kPrimInt:
1757 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001758 // Processing a Dex `int-to-byte' instruction.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001759 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001760 __ movsxb(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain51d3fc42014-11-13 14:11:42 +00001761 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001762 __ movsxb(out.AsRegister<CpuRegister>(),
Roland Levillain51d3fc42014-11-13 14:11:42 +00001763 Address(CpuRegister(RSP), in.GetStackIndex()));
1764 } else {
1765 DCHECK(in.GetConstant()->IsIntConstant());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001766 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain51d3fc42014-11-13 14:11:42 +00001767 Immediate(static_cast<int8_t>(in.GetConstant()->AsIntConstant()->GetValue())));
1768 }
1769 break;
1770
1771 default:
1772 LOG(FATAL) << "Unexpected type conversion from " << input_type
1773 << " to " << result_type;
1774 }
1775 break;
1776
Roland Levillain01a8d712014-11-14 16:27:39 +00001777 case Primitive::kPrimShort:
1778 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001779 case Primitive::kPrimBoolean:
1780 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00001781 case Primitive::kPrimByte:
1782 case Primitive::kPrimInt:
1783 case Primitive::kPrimChar:
1784 // Processing a Dex `int-to-short' instruction.
1785 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001786 __ movsxw(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain01a8d712014-11-14 16:27:39 +00001787 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001788 __ movsxw(out.AsRegister<CpuRegister>(),
Roland Levillain01a8d712014-11-14 16:27:39 +00001789 Address(CpuRegister(RSP), in.GetStackIndex()));
1790 } else {
1791 DCHECK(in.GetConstant()->IsIntConstant());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001792 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain01a8d712014-11-14 16:27:39 +00001793 Immediate(static_cast<int16_t>(in.GetConstant()->AsIntConstant()->GetValue())));
1794 }
1795 break;
1796
1797 default:
1798 LOG(FATAL) << "Unexpected type conversion from " << input_type
1799 << " to " << result_type;
1800 }
1801 break;
1802
Roland Levillain946e1432014-11-11 17:35:19 +00001803 case Primitive::kPrimInt:
1804 switch (input_type) {
1805 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00001806 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00001807 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001808 __ movl(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain946e1432014-11-11 17:35:19 +00001809 } else if (in.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001810 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain946e1432014-11-11 17:35:19 +00001811 Address(CpuRegister(RSP), in.GetStackIndex()));
1812 } else {
1813 DCHECK(in.IsConstant());
1814 DCHECK(in.GetConstant()->IsLongConstant());
1815 int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00001816 __ movl(out.AsRegister<CpuRegister>(), Immediate(static_cast<int32_t>(value)));
Roland Levillain946e1432014-11-11 17:35:19 +00001817 }
1818 break;
1819
Roland Levillain3f8f9362014-12-02 17:45:01 +00001820 case Primitive::kPrimFloat: {
1821 // Processing a Dex `float-to-int' instruction.
1822 XmmRegister input = in.AsFpuRegister<XmmRegister>();
1823 CpuRegister output = out.AsRegister<CpuRegister>();
1824 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
1825 Label done, nan;
1826
1827 __ movl(output, Immediate(kPrimIntMax));
1828 // temp = int-to-float(output)
Roland Levillain624279f2014-12-04 11:54:28 +00001829 __ cvtsi2ss(temp, output, false);
Roland Levillain3f8f9362014-12-02 17:45:01 +00001830 // if input >= temp goto done
1831 __ comiss(input, temp);
1832 __ j(kAboveEqual, &done);
1833 // if input == NaN goto nan
1834 __ j(kUnordered, &nan);
1835 // output = float-to-int-truncate(input)
Roland Levillain624279f2014-12-04 11:54:28 +00001836 __ cvttss2si(output, input, false);
Roland Levillain3f8f9362014-12-02 17:45:01 +00001837 __ jmp(&done);
1838 __ Bind(&nan);
1839 // output = 0
1840 __ xorl(output, output);
1841 __ Bind(&done);
1842 break;
1843 }
1844
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001845 case Primitive::kPrimDouble: {
1846 // Processing a Dex `double-to-int' instruction.
1847 XmmRegister input = in.AsFpuRegister<XmmRegister>();
1848 CpuRegister output = out.AsRegister<CpuRegister>();
1849 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
1850 Label done, nan;
1851
1852 __ movl(output, Immediate(kPrimIntMax));
1853 // temp = int-to-double(output)
1854 __ cvtsi2sd(temp, output);
1855 // if input >= temp goto done
1856 __ comisd(input, temp);
1857 __ j(kAboveEqual, &done);
1858 // if input == NaN goto nan
1859 __ j(kUnordered, &nan);
1860 // output = double-to-int-truncate(input)
1861 __ cvttsd2si(output, input);
1862 __ jmp(&done);
1863 __ Bind(&nan);
1864 // output = 0
1865 __ xorl(output, output);
1866 __ Bind(&done);
Roland Levillain946e1432014-11-11 17:35:19 +00001867 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001868 }
Roland Levillain946e1432014-11-11 17:35:19 +00001869
1870 default:
1871 LOG(FATAL) << "Unexpected type conversion from " << input_type
1872 << " to " << result_type;
1873 }
1874 break;
1875
Roland Levillaindff1f282014-11-05 14:15:05 +00001876 case Primitive::kPrimLong:
1877 switch (input_type) {
1878 DCHECK(out.IsRegister());
David Brazdil46e2a392015-03-16 17:31:52 +00001879 case Primitive::kPrimBoolean:
1880 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00001881 case Primitive::kPrimByte:
1882 case Primitive::kPrimShort:
1883 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00001884 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001885 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00001886 DCHECK(in.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001887 __ movsxd(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillaindff1f282014-11-05 14:15:05 +00001888 break;
1889
Roland Levillain624279f2014-12-04 11:54:28 +00001890 case Primitive::kPrimFloat: {
1891 // Processing a Dex `float-to-long' instruction.
1892 XmmRegister input = in.AsFpuRegister<XmmRegister>();
1893 CpuRegister output = out.AsRegister<CpuRegister>();
1894 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
1895 Label done, nan;
1896
Mark Mendell92e83bf2015-05-07 11:25:03 -04001897 codegen_->Load64BitValue(output, kPrimLongMax);
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001898 // temp = long-to-float(output)
Roland Levillain624279f2014-12-04 11:54:28 +00001899 __ cvtsi2ss(temp, output, true);
1900 // if input >= temp goto done
1901 __ comiss(input, temp);
1902 __ j(kAboveEqual, &done);
1903 // if input == NaN goto nan
1904 __ j(kUnordered, &nan);
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001905 // output = float-to-long-truncate(input)
Roland Levillain624279f2014-12-04 11:54:28 +00001906 __ cvttss2si(output, input, true);
1907 __ jmp(&done);
1908 __ Bind(&nan);
1909 // output = 0
Mark Mendell92e83bf2015-05-07 11:25:03 -04001910 __ xorl(output, output);
Roland Levillain624279f2014-12-04 11:54:28 +00001911 __ Bind(&done);
1912 break;
1913 }
1914
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001915 case Primitive::kPrimDouble: {
1916 // Processing a Dex `double-to-long' instruction.
1917 XmmRegister input = in.AsFpuRegister<XmmRegister>();
1918 CpuRegister output = out.AsRegister<CpuRegister>();
1919 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
1920 Label done, nan;
1921
Mark Mendell92e83bf2015-05-07 11:25:03 -04001922 codegen_->Load64BitValue(output, kPrimLongMax);
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001923 // temp = long-to-double(output)
1924 __ cvtsi2sd(temp, output, true);
1925 // if input >= temp goto done
1926 __ comisd(input, temp);
1927 __ j(kAboveEqual, &done);
1928 // if input == NaN goto nan
1929 __ j(kUnordered, &nan);
1930 // output = double-to-long-truncate(input)
1931 __ cvttsd2si(output, input, true);
1932 __ jmp(&done);
1933 __ Bind(&nan);
1934 // output = 0
Mark Mendell92e83bf2015-05-07 11:25:03 -04001935 __ xorl(output, output);
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001936 __ Bind(&done);
Roland Levillaindff1f282014-11-05 14:15:05 +00001937 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001938 }
Roland Levillaindff1f282014-11-05 14:15:05 +00001939
1940 default:
1941 LOG(FATAL) << "Unexpected type conversion from " << input_type
1942 << " to " << result_type;
1943 }
1944 break;
1945
Roland Levillain981e4542014-11-14 11:47:14 +00001946 case Primitive::kPrimChar:
1947 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001948 case Primitive::kPrimBoolean:
1949 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00001950 case Primitive::kPrimByte:
1951 case Primitive::kPrimShort:
1952 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00001953 // Processing a Dex `int-to-char' instruction.
1954 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001955 __ movzxw(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain981e4542014-11-14 11:47:14 +00001956 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001957 __ movzxw(out.AsRegister<CpuRegister>(),
Roland Levillain981e4542014-11-14 11:47:14 +00001958 Address(CpuRegister(RSP), in.GetStackIndex()));
1959 } else {
1960 DCHECK(in.GetConstant()->IsIntConstant());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001961 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain981e4542014-11-14 11:47:14 +00001962 Immediate(static_cast<uint16_t>(in.GetConstant()->AsIntConstant()->GetValue())));
1963 }
1964 break;
1965
1966 default:
1967 LOG(FATAL) << "Unexpected type conversion from " << input_type
1968 << " to " << result_type;
1969 }
1970 break;
1971
Roland Levillaindff1f282014-11-05 14:15:05 +00001972 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00001973 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001974 case Primitive::kPrimBoolean:
1975 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001976 case Primitive::kPrimByte:
1977 case Primitive::kPrimShort:
1978 case Primitive::kPrimInt:
1979 case Primitive::kPrimChar:
Roland Levillain6d0e4832014-11-27 18:31:21 +00001980 // Processing a Dex `int-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04001981 if (in.IsRegister()) {
1982 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), false);
1983 } else if (in.IsConstant()) {
1984 int32_t v = in.GetConstant()->AsIntConstant()->GetValue();
1985 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
1986 if (v == 0) {
1987 __ xorps(dest, dest);
1988 } else {
1989 __ movss(dest, codegen_->LiteralFloatAddress(static_cast<float>(v)));
1990 }
1991 } else {
1992 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(),
1993 Address(CpuRegister(RSP), in.GetStackIndex()), false);
1994 }
Roland Levillaincff13742014-11-17 14:32:17 +00001995 break;
1996
1997 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00001998 // Processing a Dex `long-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04001999 if (in.IsRegister()) {
2000 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), true);
2001 } else if (in.IsConstant()) {
2002 int64_t v = in.GetConstant()->AsLongConstant()->GetValue();
2003 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
2004 if (v == 0) {
2005 __ xorps(dest, dest);
2006 } else {
2007 __ movss(dest, codegen_->LiteralFloatAddress(static_cast<float>(v)));
2008 }
2009 } else {
2010 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(),
2011 Address(CpuRegister(RSP), in.GetStackIndex()), true);
2012 }
Roland Levillain6d0e4832014-11-27 18:31:21 +00002013 break;
2014
Roland Levillaincff13742014-11-17 14:32:17 +00002015 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002016 // Processing a Dex `double-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002017 if (in.IsFpuRegister()) {
2018 __ cvtsd2ss(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
2019 } else if (in.IsConstant()) {
2020 double v = in.GetConstant()->AsDoubleConstant()->GetValue();
2021 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
2022 if (bit_cast<int64_t, double>(v) == 0) {
2023 __ xorps(dest, dest);
2024 } else {
2025 __ movss(dest, codegen_->LiteralFloatAddress(static_cast<float>(v)));
2026 }
2027 } else {
2028 __ cvtsd2ss(out.AsFpuRegister<XmmRegister>(),
2029 Address(CpuRegister(RSP), in.GetStackIndex()));
2030 }
Roland Levillaincff13742014-11-17 14:32:17 +00002031 break;
2032
2033 default:
2034 LOG(FATAL) << "Unexpected type conversion from " << input_type
2035 << " to " << result_type;
2036 };
2037 break;
2038
Roland Levillaindff1f282014-11-05 14:15:05 +00002039 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00002040 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002041 case Primitive::kPrimBoolean:
2042 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002043 case Primitive::kPrimByte:
2044 case Primitive::kPrimShort:
2045 case Primitive::kPrimInt:
2046 case Primitive::kPrimChar:
Roland Levillain6d0e4832014-11-27 18:31:21 +00002047 // Processing a Dex `int-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002048 if (in.IsRegister()) {
2049 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), false);
2050 } else if (in.IsConstant()) {
2051 int32_t v = in.GetConstant()->AsIntConstant()->GetValue();
2052 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
2053 if (v == 0) {
2054 __ xorpd(dest, dest);
2055 } else {
2056 __ movsd(dest, codegen_->LiteralDoubleAddress(static_cast<double>(v)));
2057 }
2058 } else {
2059 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(),
2060 Address(CpuRegister(RSP), in.GetStackIndex()), false);
2061 }
Roland Levillaincff13742014-11-17 14:32:17 +00002062 break;
2063
2064 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00002065 // Processing a Dex `long-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002066 if (in.IsRegister()) {
2067 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), true);
2068 } else if (in.IsConstant()) {
2069 int64_t v = in.GetConstant()->AsLongConstant()->GetValue();
2070 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
2071 if (v == 0) {
2072 __ xorpd(dest, dest);
2073 } else {
2074 __ movsd(dest, codegen_->LiteralDoubleAddress(static_cast<double>(v)));
2075 }
2076 } else {
2077 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(),
2078 Address(CpuRegister(RSP), in.GetStackIndex()), true);
2079 }
Roland Levillain647b9ed2014-11-27 12:06:00 +00002080 break;
2081
Roland Levillaincff13742014-11-17 14:32:17 +00002082 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002083 // Processing a Dex `float-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002084 if (in.IsFpuRegister()) {
2085 __ cvtss2sd(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
2086 } else if (in.IsConstant()) {
2087 float v = in.GetConstant()->AsFloatConstant()->GetValue();
2088 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
2089 if (bit_cast<int32_t, float>(v) == 0) {
2090 __ xorpd(dest, dest);
2091 } else {
2092 __ movsd(dest, codegen_->LiteralDoubleAddress(static_cast<double>(v)));
2093 }
2094 } else {
2095 __ cvtss2sd(out.AsFpuRegister<XmmRegister>(),
2096 Address(CpuRegister(RSP), in.GetStackIndex()));
2097 }
Roland Levillaincff13742014-11-17 14:32:17 +00002098 break;
2099
2100 default:
2101 LOG(FATAL) << "Unexpected type conversion from " << input_type
2102 << " to " << result_type;
2103 };
Roland Levillaindff1f282014-11-05 14:15:05 +00002104 break;
2105
2106 default:
2107 LOG(FATAL) << "Unexpected type conversion from " << input_type
2108 << " to " << result_type;
2109 }
2110}
2111
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002112void LocationsBuilderX86_64::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002113 LocationSummary* locations =
2114 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002115 switch (add->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002116 case Primitive::kPrimInt: {
2117 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002118 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
2119 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002120 break;
2121 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002122
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002123 case Primitive::kPrimLong: {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002124 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell09b84632015-02-13 17:48:38 -05002125 // We can use a leaq or addq if the constant can fit in an immediate.
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002126 locations->SetInAt(1, Location::RegisterOrInt32LongConstant(add->InputAt(1)));
Mark Mendell09b84632015-02-13 17:48:38 -05002127 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002128 break;
2129 }
2130
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002131 case Primitive::kPrimDouble:
2132 case Primitive::kPrimFloat: {
2133 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendellf55c3e02015-03-26 21:07:46 -04002134 locations->SetInAt(1, Location::Any());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002135 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002136 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002137 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002138
2139 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002140 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002141 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002142}
2143
2144void InstructionCodeGeneratorX86_64::VisitAdd(HAdd* add) {
2145 LocationSummary* locations = add->GetLocations();
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002146 Location first = locations->InAt(0);
2147 Location second = locations->InAt(1);
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002148 Location out = locations->Out();
Calin Juravle11351682014-10-23 15:38:15 +01002149
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002150 switch (add->GetResultType()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002151 case Primitive::kPrimInt: {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002152 if (second.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002153 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
2154 __ addl(out.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Mark Mendell33bf2452015-05-27 10:08:24 -04002155 } else if (out.AsRegister<Register>() == second.AsRegister<Register>()) {
2156 __ addl(out.AsRegister<CpuRegister>(), first.AsRegister<CpuRegister>());
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002157 } else {
2158 __ leal(out.AsRegister<CpuRegister>(), Address(
2159 first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>(), TIMES_1, 0));
2160 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002161 } else if (second.IsConstant()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002162 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
2163 __ addl(out.AsRegister<CpuRegister>(),
2164 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
2165 } else {
2166 __ leal(out.AsRegister<CpuRegister>(), Address(
2167 first.AsRegister<CpuRegister>(), second.GetConstant()->AsIntConstant()->GetValue()));
2168 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002169 } else {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002170 DCHECK(first.Equals(locations->Out()));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002171 __ addl(first.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), second.GetStackIndex()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002172 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002173 break;
2174 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002175
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002176 case Primitive::kPrimLong: {
Mark Mendell09b84632015-02-13 17:48:38 -05002177 if (second.IsRegister()) {
2178 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
2179 __ addq(out.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Mark Mendell33bf2452015-05-27 10:08:24 -04002180 } else if (out.AsRegister<Register>() == second.AsRegister<Register>()) {
2181 __ addq(out.AsRegister<CpuRegister>(), first.AsRegister<CpuRegister>());
Mark Mendell09b84632015-02-13 17:48:38 -05002182 } else {
2183 __ leaq(out.AsRegister<CpuRegister>(), Address(
2184 first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>(), TIMES_1, 0));
2185 }
2186 } else {
2187 DCHECK(second.IsConstant());
2188 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
2189 int32_t int32_value = Low32Bits(value);
2190 DCHECK_EQ(int32_value, value);
2191 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
2192 __ addq(out.AsRegister<CpuRegister>(), Immediate(int32_value));
2193 } else {
2194 __ leaq(out.AsRegister<CpuRegister>(), Address(
2195 first.AsRegister<CpuRegister>(), int32_value));
2196 }
2197 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002198 break;
2199 }
2200
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002201 case Primitive::kPrimFloat: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04002202 if (second.IsFpuRegister()) {
2203 __ addss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2204 } else if (second.IsConstant()) {
2205 __ addss(first.AsFpuRegister<XmmRegister>(),
2206 codegen_->LiteralFloatAddress(second.GetConstant()->AsFloatConstant()->GetValue()));
2207 } else {
2208 DCHECK(second.IsStackSlot());
2209 __ addss(first.AsFpuRegister<XmmRegister>(),
2210 Address(CpuRegister(RSP), second.GetStackIndex()));
2211 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002212 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002213 }
2214
2215 case Primitive::kPrimDouble: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04002216 if (second.IsFpuRegister()) {
2217 __ addsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2218 } else if (second.IsConstant()) {
2219 __ addsd(first.AsFpuRegister<XmmRegister>(),
2220 codegen_->LiteralDoubleAddress(second.GetConstant()->AsDoubleConstant()->GetValue()));
2221 } else {
2222 DCHECK(second.IsDoubleStackSlot());
2223 __ addsd(first.AsFpuRegister<XmmRegister>(),
2224 Address(CpuRegister(RSP), second.GetStackIndex()));
2225 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002226 break;
2227 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002228
2229 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002230 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002231 }
2232}
2233
2234void LocationsBuilderX86_64::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002235 LocationSummary* locations =
2236 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002237 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002238 case Primitive::kPrimInt: {
2239 locations->SetInAt(0, Location::RequiresRegister());
2240 locations->SetInAt(1, Location::Any());
2241 locations->SetOut(Location::SameAsFirstInput());
2242 break;
2243 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002244 case Primitive::kPrimLong: {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002245 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002246 locations->SetInAt(1, Location::RegisterOrInt32LongConstant(sub->InputAt(1)));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002247 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002248 break;
2249 }
Calin Juravle11351682014-10-23 15:38:15 +01002250 case Primitive::kPrimFloat:
2251 case Primitive::kPrimDouble: {
2252 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendellf55c3e02015-03-26 21:07:46 -04002253 locations->SetInAt(1, Location::Any());
Calin Juravle11351682014-10-23 15:38:15 +01002254 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002255 break;
Calin Juravle11351682014-10-23 15:38:15 +01002256 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002257 default:
Calin Juravle11351682014-10-23 15:38:15 +01002258 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002259 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002260}
2261
2262void InstructionCodeGeneratorX86_64::VisitSub(HSub* sub) {
2263 LocationSummary* locations = sub->GetLocations();
Calin Juravle11351682014-10-23 15:38:15 +01002264 Location first = locations->InAt(0);
2265 Location second = locations->InAt(1);
2266 DCHECK(first.Equals(locations->Out()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002267 switch (sub->GetResultType()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002268 case Primitive::kPrimInt: {
Calin Juravle11351682014-10-23 15:38:15 +01002269 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002270 __ subl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Calin Juravle11351682014-10-23 15:38:15 +01002271 } else if (second.IsConstant()) {
2272 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002273 __ subl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002274 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002275 __ subl(first.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), second.GetStackIndex()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002276 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002277 break;
2278 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002279 case Primitive::kPrimLong: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002280 if (second.IsConstant()) {
2281 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
2282 DCHECK(IsInt<32>(value));
2283 __ subq(first.AsRegister<CpuRegister>(), Immediate(static_cast<int32_t>(value)));
2284 } else {
2285 __ subq(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
2286 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002287 break;
2288 }
2289
Calin Juravle11351682014-10-23 15:38:15 +01002290 case Primitive::kPrimFloat: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04002291 if (second.IsFpuRegister()) {
2292 __ subss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2293 } else if (second.IsConstant()) {
2294 __ subss(first.AsFpuRegister<XmmRegister>(),
2295 codegen_->LiteralFloatAddress(second.GetConstant()->AsFloatConstant()->GetValue()));
2296 } else {
2297 DCHECK(second.IsStackSlot());
2298 __ subss(first.AsFpuRegister<XmmRegister>(),
2299 Address(CpuRegister(RSP), second.GetStackIndex()));
2300 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002301 break;
Calin Juravle11351682014-10-23 15:38:15 +01002302 }
2303
2304 case Primitive::kPrimDouble: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04002305 if (second.IsFpuRegister()) {
2306 __ subsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2307 } else if (second.IsConstant()) {
2308 __ subsd(first.AsFpuRegister<XmmRegister>(),
2309 codegen_->LiteralDoubleAddress(second.GetConstant()->AsDoubleConstant()->GetValue()));
2310 } else {
2311 DCHECK(second.IsDoubleStackSlot());
2312 __ subsd(first.AsFpuRegister<XmmRegister>(),
2313 Address(CpuRegister(RSP), second.GetStackIndex()));
2314 }
Calin Juravle11351682014-10-23 15:38:15 +01002315 break;
2316 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002317
2318 default:
Calin Juravle11351682014-10-23 15:38:15 +01002319 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002320 }
2321}
2322
Calin Juravle34bacdf2014-10-07 20:23:36 +01002323void LocationsBuilderX86_64::VisitMul(HMul* mul) {
2324 LocationSummary* locations =
2325 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
2326 switch (mul->GetResultType()) {
2327 case Primitive::kPrimInt: {
2328 locations->SetInAt(0, Location::RequiresRegister());
2329 locations->SetInAt(1, Location::Any());
2330 locations->SetOut(Location::SameAsFirstInput());
2331 break;
2332 }
2333 case Primitive::kPrimLong: {
2334 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002335 locations->SetInAt(1, Location::RegisterOrInt32LongConstant(mul->InputAt(1)));
2336 if (locations->InAt(1).IsConstant()) {
2337 // Can use 3 operand multiply.
2338 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2339 } else {
2340 locations->SetOut(Location::SameAsFirstInput());
2341 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002342 break;
2343 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01002344 case Primitive::kPrimFloat:
2345 case Primitive::kPrimDouble: {
2346 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendellf55c3e02015-03-26 21:07:46 -04002347 locations->SetInAt(1, Location::Any());
Calin Juravleb5bfa962014-10-21 18:02:24 +01002348 locations->SetOut(Location::SameAsFirstInput());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002349 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002350 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002351
2352 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002353 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002354 }
2355}
2356
2357void InstructionCodeGeneratorX86_64::VisitMul(HMul* mul) {
2358 LocationSummary* locations = mul->GetLocations();
2359 Location first = locations->InAt(0);
2360 Location second = locations->InAt(1);
Calin Juravle34bacdf2014-10-07 20:23:36 +01002361 switch (mul->GetResultType()) {
2362 case Primitive::kPrimInt: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002363 DCHECK(first.Equals(locations->Out()));
Calin Juravle34bacdf2014-10-07 20:23:36 +01002364 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002365 __ imull(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002366 } else if (second.IsConstant()) {
2367 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002368 __ imull(first.AsRegister<CpuRegister>(), imm);
Calin Juravle34bacdf2014-10-07 20:23:36 +01002369 } else {
2370 DCHECK(second.IsStackSlot());
Roland Levillain199f3362014-11-27 17:15:16 +00002371 __ imull(first.AsRegister<CpuRegister>(),
2372 Address(CpuRegister(RSP), second.GetStackIndex()));
Calin Juravle34bacdf2014-10-07 20:23:36 +01002373 }
2374 break;
2375 }
2376 case Primitive::kPrimLong: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002377 if (second.IsConstant()) {
2378 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
2379 DCHECK(IsInt<32>(value));
2380 __ imulq(locations->Out().AsRegister<CpuRegister>(),
2381 first.AsRegister<CpuRegister>(),
2382 Immediate(static_cast<int32_t>(value)));
2383 } else {
2384 DCHECK(first.Equals(locations->Out()));
2385 __ imulq(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
2386 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002387 break;
2388 }
2389
Calin Juravleb5bfa962014-10-21 18:02:24 +01002390 case Primitive::kPrimFloat: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002391 DCHECK(first.Equals(locations->Out()));
Mark Mendellf55c3e02015-03-26 21:07:46 -04002392 if (second.IsFpuRegister()) {
2393 __ mulss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2394 } else if (second.IsConstant()) {
2395 __ mulss(first.AsFpuRegister<XmmRegister>(),
2396 codegen_->LiteralFloatAddress(second.GetConstant()->AsFloatConstant()->GetValue()));
2397 } else {
2398 DCHECK(second.IsStackSlot());
2399 __ mulss(first.AsFpuRegister<XmmRegister>(),
2400 Address(CpuRegister(RSP), second.GetStackIndex()));
2401 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002402 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002403 }
2404
2405 case Primitive::kPrimDouble: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002406 DCHECK(first.Equals(locations->Out()));
Mark Mendellf55c3e02015-03-26 21:07:46 -04002407 if (second.IsFpuRegister()) {
2408 __ mulsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2409 } else if (second.IsConstant()) {
2410 __ mulsd(first.AsFpuRegister<XmmRegister>(),
2411 codegen_->LiteralDoubleAddress(second.GetConstant()->AsDoubleConstant()->GetValue()));
2412 } else {
2413 DCHECK(second.IsDoubleStackSlot());
2414 __ mulsd(first.AsFpuRegister<XmmRegister>(),
2415 Address(CpuRegister(RSP), second.GetStackIndex()));
2416 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01002417 break;
2418 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002419
2420 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002421 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002422 }
2423}
2424
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002425void InstructionCodeGeneratorX86_64::PushOntoFPStack(Location source, uint32_t temp_offset,
2426 uint32_t stack_adjustment, bool is_float) {
2427 if (source.IsStackSlot()) {
2428 DCHECK(is_float);
2429 __ flds(Address(CpuRegister(RSP), source.GetStackIndex() + stack_adjustment));
2430 } else if (source.IsDoubleStackSlot()) {
2431 DCHECK(!is_float);
2432 __ fldl(Address(CpuRegister(RSP), source.GetStackIndex() + stack_adjustment));
2433 } else {
2434 // Write the value to the temporary location on the stack and load to FP stack.
2435 if (is_float) {
2436 Location stack_temp = Location::StackSlot(temp_offset);
2437 codegen_->Move(stack_temp, source);
2438 __ flds(Address(CpuRegister(RSP), temp_offset));
2439 } else {
2440 Location stack_temp = Location::DoubleStackSlot(temp_offset);
2441 codegen_->Move(stack_temp, source);
2442 __ fldl(Address(CpuRegister(RSP), temp_offset));
2443 }
2444 }
2445}
2446
2447void InstructionCodeGeneratorX86_64::GenerateRemFP(HRem *rem) {
2448 Primitive::Type type = rem->GetResultType();
2449 bool is_float = type == Primitive::kPrimFloat;
2450 size_t elem_size = Primitive::ComponentSize(type);
2451 LocationSummary* locations = rem->GetLocations();
2452 Location first = locations->InAt(0);
2453 Location second = locations->InAt(1);
2454 Location out = locations->Out();
2455
2456 // Create stack space for 2 elements.
2457 // TODO: enhance register allocator to ask for stack temporaries.
2458 __ subq(CpuRegister(RSP), Immediate(2 * elem_size));
2459
2460 // Load the values to the FP stack in reverse order, using temporaries if needed.
2461 PushOntoFPStack(second, elem_size, 2 * elem_size, is_float);
2462 PushOntoFPStack(first, 0, 2 * elem_size, is_float);
2463
2464 // Loop doing FPREM until we stabilize.
2465 Label retry;
2466 __ Bind(&retry);
2467 __ fprem();
2468
2469 // Move FP status to AX.
2470 __ fstsw();
2471
2472 // And see if the argument reduction is complete. This is signaled by the
2473 // C2 FPU flag bit set to 0.
2474 __ andl(CpuRegister(RAX), Immediate(kC2ConditionMask));
2475 __ j(kNotEqual, &retry);
2476
2477 // We have settled on the final value. Retrieve it into an XMM register.
2478 // Store FP top of stack to real stack.
2479 if (is_float) {
2480 __ fsts(Address(CpuRegister(RSP), 0));
2481 } else {
2482 __ fstl(Address(CpuRegister(RSP), 0));
2483 }
2484
2485 // Pop the 2 items from the FP stack.
2486 __ fucompp();
2487
2488 // Load the value from the stack into an XMM register.
2489 DCHECK(out.IsFpuRegister()) << out;
2490 if (is_float) {
2491 __ movss(out.AsFpuRegister<XmmRegister>(), Address(CpuRegister(RSP), 0));
2492 } else {
2493 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(CpuRegister(RSP), 0));
2494 }
2495
2496 // And remove the temporary stack space we allocated.
2497 __ addq(CpuRegister(RSP), Immediate(2 * elem_size));
2498}
2499
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002500void InstructionCodeGeneratorX86_64::DivRemOneOrMinusOne(HBinaryOperation* instruction) {
2501 DCHECK(instruction->IsDiv() || instruction->IsRem());
2502
2503 LocationSummary* locations = instruction->GetLocations();
2504 Location second = locations->InAt(1);
2505 DCHECK(second.IsConstant());
2506
2507 CpuRegister output_register = locations->Out().AsRegister<CpuRegister>();
2508 CpuRegister input_register = locations->InAt(0).AsRegister<CpuRegister>();
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002509 int64_t imm = Int64FromConstant(second.GetConstant());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002510
2511 DCHECK(imm == 1 || imm == -1);
2512
2513 switch (instruction->GetResultType()) {
2514 case Primitive::kPrimInt: {
2515 if (instruction->IsRem()) {
2516 __ xorl(output_register, output_register);
2517 } else {
2518 __ movl(output_register, input_register);
2519 if (imm == -1) {
2520 __ negl(output_register);
2521 }
2522 }
2523 break;
2524 }
2525
2526 case Primitive::kPrimLong: {
2527 if (instruction->IsRem()) {
Mark Mendell92e83bf2015-05-07 11:25:03 -04002528 __ xorl(output_register, output_register);
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002529 } else {
2530 __ movq(output_register, input_register);
2531 if (imm == -1) {
2532 __ negq(output_register);
2533 }
2534 }
2535 break;
2536 }
2537
2538 default:
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002539 LOG(FATAL) << "Unexpected type for div by (-)1 " << instruction->GetResultType();
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002540 }
2541}
2542
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002543void InstructionCodeGeneratorX86_64::DivByPowerOfTwo(HDiv* instruction) {
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002544 LocationSummary* locations = instruction->GetLocations();
2545 Location second = locations->InAt(1);
2546
2547 CpuRegister output_register = locations->Out().AsRegister<CpuRegister>();
2548 CpuRegister numerator = locations->InAt(0).AsRegister<CpuRegister>();
2549
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002550 int64_t imm = Int64FromConstant(second.GetConstant());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002551
2552 DCHECK(IsPowerOfTwo(std::abs(imm)));
2553
2554 CpuRegister tmp = locations->GetTemp(0).AsRegister<CpuRegister>();
2555
2556 if (instruction->GetResultType() == Primitive::kPrimInt) {
2557 __ leal(tmp, Address(numerator, std::abs(imm) - 1));
2558 __ testl(numerator, numerator);
2559 __ cmov(kGreaterEqual, tmp, numerator);
2560 int shift = CTZ(imm);
2561 __ sarl(tmp, Immediate(shift));
2562
2563 if (imm < 0) {
2564 __ negl(tmp);
2565 }
2566
2567 __ movl(output_register, tmp);
2568 } else {
2569 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
2570 CpuRegister rdx = locations->GetTemp(0).AsRegister<CpuRegister>();
2571
Mark Mendell92e83bf2015-05-07 11:25:03 -04002572 codegen_->Load64BitValue(rdx, std::abs(imm) - 1);
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002573 __ addq(rdx, numerator);
2574 __ testq(numerator, numerator);
2575 __ cmov(kGreaterEqual, rdx, numerator);
2576 int shift = CTZ(imm);
2577 __ sarq(rdx, Immediate(shift));
2578
2579 if (imm < 0) {
2580 __ negq(rdx);
2581 }
2582
2583 __ movq(output_register, rdx);
2584 }
2585}
2586
2587void InstructionCodeGeneratorX86_64::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) {
2588 DCHECK(instruction->IsDiv() || instruction->IsRem());
2589
2590 LocationSummary* locations = instruction->GetLocations();
2591 Location second = locations->InAt(1);
2592
2593 CpuRegister numerator = instruction->IsDiv() ? locations->GetTemp(1).AsRegister<CpuRegister>()
2594 : locations->GetTemp(0).AsRegister<CpuRegister>();
2595 CpuRegister eax = locations->InAt(0).AsRegister<CpuRegister>();
2596 CpuRegister edx = instruction->IsDiv() ? locations->GetTemp(0).AsRegister<CpuRegister>()
2597 : locations->Out().AsRegister<CpuRegister>();
2598 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
2599
2600 DCHECK_EQ(RAX, eax.AsRegister());
2601 DCHECK_EQ(RDX, edx.AsRegister());
2602 if (instruction->IsDiv()) {
2603 DCHECK_EQ(RAX, out.AsRegister());
2604 } else {
2605 DCHECK_EQ(RDX, out.AsRegister());
2606 }
2607
2608 int64_t magic;
2609 int shift;
2610
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002611 // TODO: can these branches be written as one?
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002612 if (instruction->GetResultType() == Primitive::kPrimInt) {
2613 int imm = second.GetConstant()->AsIntConstant()->GetValue();
2614
2615 CalculateMagicAndShiftForDivRem(imm, false /* is_long */, &magic, &shift);
2616
2617 __ movl(numerator, eax);
2618
2619 Label no_div;
2620 Label end;
2621 __ testl(eax, eax);
2622 __ j(kNotEqual, &no_div);
2623
2624 __ xorl(out, out);
2625 __ jmp(&end);
2626
2627 __ Bind(&no_div);
2628
2629 __ movl(eax, Immediate(magic));
2630 __ imull(numerator);
2631
2632 if (imm > 0 && magic < 0) {
2633 __ addl(edx, numerator);
2634 } else if (imm < 0 && magic > 0) {
2635 __ subl(edx, numerator);
2636 }
2637
2638 if (shift != 0) {
2639 __ sarl(edx, Immediate(shift));
2640 }
2641
2642 __ movl(eax, edx);
2643 __ shrl(edx, Immediate(31));
2644 __ addl(edx, eax);
2645
2646 if (instruction->IsRem()) {
2647 __ movl(eax, numerator);
2648 __ imull(edx, Immediate(imm));
2649 __ subl(eax, edx);
2650 __ movl(edx, eax);
2651 } else {
2652 __ movl(eax, edx);
2653 }
2654 __ Bind(&end);
2655 } else {
2656 int64_t imm = second.GetConstant()->AsLongConstant()->GetValue();
2657
2658 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
2659
2660 CpuRegister rax = eax;
2661 CpuRegister rdx = edx;
2662
2663 CalculateMagicAndShiftForDivRem(imm, true /* is_long */, &magic, &shift);
2664
2665 // Save the numerator.
2666 __ movq(numerator, rax);
2667
2668 // RAX = magic
Mark Mendell92e83bf2015-05-07 11:25:03 -04002669 codegen_->Load64BitValue(rax, magic);
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002670
2671 // RDX:RAX = magic * numerator
2672 __ imulq(numerator);
2673
2674 if (imm > 0 && magic < 0) {
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002675 // RDX += numerator
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002676 __ addq(rdx, numerator);
2677 } else if (imm < 0 && magic > 0) {
2678 // RDX -= numerator
2679 __ subq(rdx, numerator);
2680 }
2681
2682 // Shift if needed.
2683 if (shift != 0) {
2684 __ sarq(rdx, Immediate(shift));
2685 }
2686
2687 // RDX += 1 if RDX < 0
2688 __ movq(rax, rdx);
2689 __ shrq(rdx, Immediate(63));
2690 __ addq(rdx, rax);
2691
2692 if (instruction->IsRem()) {
2693 __ movq(rax, numerator);
2694
2695 if (IsInt<32>(imm)) {
2696 __ imulq(rdx, Immediate(static_cast<int32_t>(imm)));
2697 } else {
Mark Mendell92e83bf2015-05-07 11:25:03 -04002698 __ imulq(rdx, codegen_->LiteralInt64Address(imm));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002699 }
2700
2701 __ subq(rax, rdx);
2702 __ movq(rdx, rax);
2703 } else {
2704 __ movq(rax, rdx);
2705 }
2706 }
2707}
2708
Calin Juravlebacfec32014-11-14 15:54:36 +00002709void InstructionCodeGeneratorX86_64::GenerateDivRemIntegral(HBinaryOperation* instruction) {
2710 DCHECK(instruction->IsDiv() || instruction->IsRem());
2711 Primitive::Type type = instruction->GetResultType();
2712 DCHECK(type == Primitive::kPrimInt || Primitive::kPrimLong);
2713
2714 bool is_div = instruction->IsDiv();
2715 LocationSummary* locations = instruction->GetLocations();
2716
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002717 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
2718 Location second = locations->InAt(1);
Calin Juravlebacfec32014-11-14 15:54:36 +00002719
Roland Levillain271ab9c2014-11-27 15:23:57 +00002720 DCHECK_EQ(RAX, locations->InAt(0).AsRegister<CpuRegister>().AsRegister());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002721 DCHECK_EQ(is_div ? RAX : RDX, out.AsRegister());
Calin Juravlebacfec32014-11-14 15:54:36 +00002722
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002723 if (second.IsConstant()) {
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002724 int64_t imm = Int64FromConstant(second.GetConstant());
Calin Juravlebacfec32014-11-14 15:54:36 +00002725
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002726 if (imm == 0) {
2727 // Do not generate anything. DivZeroCheck would prevent any code to be executed.
2728 } else if (imm == 1 || imm == -1) {
2729 DivRemOneOrMinusOne(instruction);
2730 } else if (instruction->IsDiv() && IsPowerOfTwo(std::abs(imm))) {
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002731 DivByPowerOfTwo(instruction->AsDiv());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002732 } else {
2733 DCHECK(imm <= -2 || imm >= 2);
2734 GenerateDivRemWithAnyConstant(instruction);
2735 }
Calin Juravlebacfec32014-11-14 15:54:36 +00002736 } else {
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002737 SlowPathCodeX86_64* slow_path =
2738 new (GetGraph()->GetArena()) DivRemMinusOneSlowPathX86_64(
2739 out.AsRegister(), type, is_div);
2740 codegen_->AddSlowPath(slow_path);
Calin Juravlebacfec32014-11-14 15:54:36 +00002741
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002742 CpuRegister second_reg = second.AsRegister<CpuRegister>();
2743 // 0x80000000(00000000)/-1 triggers an arithmetic exception!
2744 // Dividing by -1 is actually negation and -0x800000000(00000000) = 0x80000000(00000000)
2745 // so it's safe to just use negl instead of more complex comparisons.
2746 if (type == Primitive::kPrimInt) {
2747 __ cmpl(second_reg, Immediate(-1));
2748 __ j(kEqual, slow_path->GetEntryLabel());
2749 // edx:eax <- sign-extended of eax
2750 __ cdq();
2751 // eax = quotient, edx = remainder
2752 __ idivl(second_reg);
2753 } else {
2754 __ cmpq(second_reg, Immediate(-1));
2755 __ j(kEqual, slow_path->GetEntryLabel());
2756 // rdx:rax <- sign-extended of rax
2757 __ cqo();
2758 // rax = quotient, rdx = remainder
2759 __ idivq(second_reg);
2760 }
2761 __ Bind(slow_path->GetExitLabel());
2762 }
Calin Juravlebacfec32014-11-14 15:54:36 +00002763}
2764
Calin Juravle7c4954d2014-10-28 16:57:40 +00002765void LocationsBuilderX86_64::VisitDiv(HDiv* div) {
2766 LocationSummary* locations =
2767 new (GetGraph()->GetArena()) LocationSummary(div, LocationSummary::kNoCall);
2768 switch (div->GetResultType()) {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002769 case Primitive::kPrimInt:
2770 case Primitive::kPrimLong: {
Calin Juravled0d48522014-11-04 16:40:20 +00002771 locations->SetInAt(0, Location::RegisterLocation(RAX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002772 locations->SetInAt(1, Location::RegisterOrConstant(div->InputAt(1)));
Calin Juravled0d48522014-11-04 16:40:20 +00002773 locations->SetOut(Location::SameAsFirstInput());
2774 // Intel uses edx:eax as the dividend.
2775 locations->AddTemp(Location::RegisterLocation(RDX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002776 // We need to save the numerator while we tweak rax and rdx. As we are using imul in a way
2777 // which enforces results to be in RAX and RDX, things are simpler if we use RDX also as
2778 // output and request another temp.
2779 if (div->InputAt(1)->IsConstant()) {
2780 locations->AddTemp(Location::RequiresRegister());
2781 }
Calin Juravled0d48522014-11-04 16:40:20 +00002782 break;
2783 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002784
Calin Juravle7c4954d2014-10-28 16:57:40 +00002785 case Primitive::kPrimFloat:
2786 case Primitive::kPrimDouble: {
2787 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendellf55c3e02015-03-26 21:07:46 -04002788 locations->SetInAt(1, Location::Any());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002789 locations->SetOut(Location::SameAsFirstInput());
2790 break;
2791 }
2792
2793 default:
2794 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2795 }
2796}
2797
2798void InstructionCodeGeneratorX86_64::VisitDiv(HDiv* div) {
2799 LocationSummary* locations = div->GetLocations();
2800 Location first = locations->InAt(0);
2801 Location second = locations->InAt(1);
2802 DCHECK(first.Equals(locations->Out()));
2803
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002804 Primitive::Type type = div->GetResultType();
2805 switch (type) {
2806 case Primitive::kPrimInt:
2807 case Primitive::kPrimLong: {
Calin Juravlebacfec32014-11-14 15:54:36 +00002808 GenerateDivRemIntegral(div);
Calin Juravled0d48522014-11-04 16:40:20 +00002809 break;
2810 }
2811
Calin Juravle7c4954d2014-10-28 16:57:40 +00002812 case Primitive::kPrimFloat: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04002813 if (second.IsFpuRegister()) {
2814 __ divss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2815 } else if (second.IsConstant()) {
2816 __ divss(first.AsFpuRegister<XmmRegister>(),
2817 codegen_->LiteralFloatAddress(second.GetConstant()->AsFloatConstant()->GetValue()));
2818 } else {
2819 DCHECK(second.IsStackSlot());
2820 __ divss(first.AsFpuRegister<XmmRegister>(),
2821 Address(CpuRegister(RSP), second.GetStackIndex()));
2822 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00002823 break;
2824 }
2825
2826 case Primitive::kPrimDouble: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04002827 if (second.IsFpuRegister()) {
2828 __ divsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2829 } else if (second.IsConstant()) {
2830 __ divsd(first.AsFpuRegister<XmmRegister>(),
2831 codegen_->LiteralDoubleAddress(second.GetConstant()->AsDoubleConstant()->GetValue()));
2832 } else {
2833 DCHECK(second.IsDoubleStackSlot());
2834 __ divsd(first.AsFpuRegister<XmmRegister>(),
2835 Address(CpuRegister(RSP), second.GetStackIndex()));
2836 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00002837 break;
2838 }
2839
2840 default:
2841 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2842 }
2843}
2844
Calin Juravlebacfec32014-11-14 15:54:36 +00002845void LocationsBuilderX86_64::VisitRem(HRem* rem) {
Calin Juravled2ec87d2014-12-08 14:24:46 +00002846 Primitive::Type type = rem->GetResultType();
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002847 LocationSummary* locations =
2848 new (GetGraph()->GetArena()) LocationSummary(rem, LocationSummary::kNoCall);
Calin Juravled2ec87d2014-12-08 14:24:46 +00002849
2850 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00002851 case Primitive::kPrimInt:
2852 case Primitive::kPrimLong: {
2853 locations->SetInAt(0, Location::RegisterLocation(RAX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002854 locations->SetInAt(1, Location::RegisterOrConstant(rem->InputAt(1)));
Calin Juravlebacfec32014-11-14 15:54:36 +00002855 // Intel uses rdx:rax as the dividend and puts the remainder in rdx
2856 locations->SetOut(Location::RegisterLocation(RDX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002857 // We need to save the numerator while we tweak eax and edx. As we are using imul in a way
2858 // which enforces results to be in RAX and RDX, things are simpler if we use EAX also as
2859 // output and request another temp.
2860 if (rem->InputAt(1)->IsConstant()) {
2861 locations->AddTemp(Location::RequiresRegister());
2862 }
Calin Juravlebacfec32014-11-14 15:54:36 +00002863 break;
2864 }
2865
2866 case Primitive::kPrimFloat:
2867 case Primitive::kPrimDouble: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002868 locations->SetInAt(0, Location::Any());
2869 locations->SetInAt(1, Location::Any());
2870 locations->SetOut(Location::RequiresFpuRegister());
2871 locations->AddTemp(Location::RegisterLocation(RAX));
Calin Juravlebacfec32014-11-14 15:54:36 +00002872 break;
2873 }
2874
2875 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00002876 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00002877 }
2878}
2879
2880void InstructionCodeGeneratorX86_64::VisitRem(HRem* rem) {
2881 Primitive::Type type = rem->GetResultType();
2882 switch (type) {
2883 case Primitive::kPrimInt:
2884 case Primitive::kPrimLong: {
2885 GenerateDivRemIntegral(rem);
2886 break;
2887 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002888 case Primitive::kPrimFloat:
Calin Juravled2ec87d2014-12-08 14:24:46 +00002889 case Primitive::kPrimDouble: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002890 GenerateRemFP(rem);
Calin Juravled2ec87d2014-12-08 14:24:46 +00002891 break;
2892 }
Calin Juravlebacfec32014-11-14 15:54:36 +00002893 default:
2894 LOG(FATAL) << "Unexpected rem type " << rem->GetResultType();
2895 }
2896}
2897
Calin Juravled0d48522014-11-04 16:40:20 +00002898void LocationsBuilderX86_64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
2899 LocationSummary* locations =
2900 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
2901 locations->SetInAt(0, Location::Any());
2902 if (instruction->HasUses()) {
2903 locations->SetOut(Location::SameAsFirstInput());
2904 }
2905}
2906
2907void InstructionCodeGeneratorX86_64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
2908 SlowPathCodeX86_64* slow_path =
2909 new (GetGraph()->GetArena()) DivZeroCheckSlowPathX86_64(instruction);
2910 codegen_->AddSlowPath(slow_path);
2911
2912 LocationSummary* locations = instruction->GetLocations();
2913 Location value = locations->InAt(0);
2914
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002915 switch (instruction->GetType()) {
2916 case Primitive::kPrimInt: {
2917 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002918 __ testl(value.AsRegister<CpuRegister>(), value.AsRegister<CpuRegister>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002919 __ j(kEqual, slow_path->GetEntryLabel());
2920 } else if (value.IsStackSlot()) {
2921 __ cmpl(Address(CpuRegister(RSP), value.GetStackIndex()), Immediate(0));
2922 __ j(kEqual, slow_path->GetEntryLabel());
2923 } else {
2924 DCHECK(value.IsConstant()) << value;
2925 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
2926 __ jmp(slow_path->GetEntryLabel());
2927 }
2928 }
2929 break;
Calin Juravled0d48522014-11-04 16:40:20 +00002930 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002931 case Primitive::kPrimLong: {
2932 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002933 __ testq(value.AsRegister<CpuRegister>(), value.AsRegister<CpuRegister>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002934 __ j(kEqual, slow_path->GetEntryLabel());
2935 } else if (value.IsDoubleStackSlot()) {
2936 __ cmpq(Address(CpuRegister(RSP), value.GetStackIndex()), Immediate(0));
2937 __ j(kEqual, slow_path->GetEntryLabel());
2938 } else {
2939 DCHECK(value.IsConstant()) << value;
2940 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
2941 __ jmp(slow_path->GetEntryLabel());
2942 }
2943 }
2944 break;
2945 }
2946 default:
2947 LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
Calin Juravled0d48522014-11-04 16:40:20 +00002948 }
Calin Juravled0d48522014-11-04 16:40:20 +00002949}
2950
Calin Juravle9aec02f2014-11-18 23:06:35 +00002951void LocationsBuilderX86_64::HandleShift(HBinaryOperation* op) {
2952 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
2953
2954 LocationSummary* locations =
2955 new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
2956
2957 switch (op->GetResultType()) {
2958 case Primitive::kPrimInt:
2959 case Primitive::kPrimLong: {
2960 locations->SetInAt(0, Location::RequiresRegister());
2961 // The shift count needs to be in CL.
2962 locations->SetInAt(1, Location::ByteRegisterOrConstant(RCX, op->InputAt(1)));
2963 locations->SetOut(Location::SameAsFirstInput());
2964 break;
2965 }
2966 default:
2967 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
2968 }
2969}
2970
2971void InstructionCodeGeneratorX86_64::HandleShift(HBinaryOperation* op) {
2972 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
2973
2974 LocationSummary* locations = op->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002975 CpuRegister first_reg = locations->InAt(0).AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002976 Location second = locations->InAt(1);
2977
2978 switch (op->GetResultType()) {
2979 case Primitive::kPrimInt: {
2980 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002981 CpuRegister second_reg = second.AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002982 if (op->IsShl()) {
2983 __ shll(first_reg, second_reg);
2984 } else if (op->IsShr()) {
2985 __ sarl(first_reg, second_reg);
2986 } else {
2987 __ shrl(first_reg, second_reg);
2988 }
2989 } else {
Nicolas Geoffray486cc192014-12-08 18:00:55 +00002990 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxIntShiftValue);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002991 if (op->IsShl()) {
2992 __ shll(first_reg, imm);
2993 } else if (op->IsShr()) {
2994 __ sarl(first_reg, imm);
2995 } else {
2996 __ shrl(first_reg, imm);
2997 }
2998 }
2999 break;
3000 }
3001 case Primitive::kPrimLong: {
3002 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003003 CpuRegister second_reg = second.AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003004 if (op->IsShl()) {
3005 __ shlq(first_reg, second_reg);
3006 } else if (op->IsShr()) {
3007 __ sarq(first_reg, second_reg);
3008 } else {
3009 __ shrq(first_reg, second_reg);
3010 }
3011 } else {
Nicolas Geoffray486cc192014-12-08 18:00:55 +00003012 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxLongShiftValue);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003013 if (op->IsShl()) {
3014 __ shlq(first_reg, imm);
3015 } else if (op->IsShr()) {
3016 __ sarq(first_reg, imm);
3017 } else {
3018 __ shrq(first_reg, imm);
3019 }
3020 }
3021 break;
3022 }
3023 default:
3024 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
3025 }
3026}
3027
3028void LocationsBuilderX86_64::VisitShl(HShl* shl) {
3029 HandleShift(shl);
3030}
3031
3032void InstructionCodeGeneratorX86_64::VisitShl(HShl* shl) {
3033 HandleShift(shl);
3034}
3035
3036void LocationsBuilderX86_64::VisitShr(HShr* shr) {
3037 HandleShift(shr);
3038}
3039
3040void InstructionCodeGeneratorX86_64::VisitShr(HShr* shr) {
3041 HandleShift(shr);
3042}
3043
3044void LocationsBuilderX86_64::VisitUShr(HUShr* ushr) {
3045 HandleShift(ushr);
3046}
3047
3048void InstructionCodeGeneratorX86_64::VisitUShr(HUShr* ushr) {
3049 HandleShift(ushr);
3050}
3051
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003052void LocationsBuilderX86_64::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003053 LocationSummary* locations =
3054 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01003055 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003056 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Nicolas Geoffray69aa6012015-06-09 10:34:25 +01003057 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003058 locations->SetOut(Location::RegisterLocation(RAX));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003059}
3060
3061void InstructionCodeGeneratorX86_64::VisitNewInstance(HNewInstance* instruction) {
3062 InvokeRuntimeCallingConvention calling_convention;
Mark Mendell92e83bf2015-05-07 11:25:03 -04003063 codegen_->Load64BitValue(CpuRegister(calling_convention.GetRegisterAt(0)),
3064 instruction->GetTypeIndex());
Roland Levillain4d027112015-07-01 15:41:14 +01003065 // Note: if heap poisoning is enabled, the entry point takes cares
3066 // of poisoning the reference.
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +00003067 __ gs()->call(
3068 Address::Absolute(GetThreadOffset<kX86_64WordSize>(instruction->GetEntrypoint()), true));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003069
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01003070 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray39468442014-09-02 15:17:15 +01003071 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003072}
3073
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003074void LocationsBuilderX86_64::VisitNewArray(HNewArray* instruction) {
3075 LocationSummary* locations =
3076 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
3077 InvokeRuntimeCallingConvention calling_convention;
3078 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003079 locations->SetOut(Location::RegisterLocation(RAX));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08003080 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray69aa6012015-06-09 10:34:25 +01003081 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003082}
3083
3084void InstructionCodeGeneratorX86_64::VisitNewArray(HNewArray* instruction) {
3085 InvokeRuntimeCallingConvention calling_convention;
Mark Mendell92e83bf2015-05-07 11:25:03 -04003086 codegen_->Load64BitValue(CpuRegister(calling_convention.GetRegisterAt(0)),
3087 instruction->GetTypeIndex());
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003088
Roland Levillain4d027112015-07-01 15:41:14 +01003089 // Note: if heap poisoning is enabled, the entry point takes cares
3090 // of poisoning the reference.
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +00003091 __ gs()->call(
3092 Address::Absolute(GetThreadOffset<kX86_64WordSize>(instruction->GetEntrypoint()), true));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003093
3094 DCHECK(!codegen_->IsLeafMethod());
3095 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3096}
3097
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003098void LocationsBuilderX86_64::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003099 LocationSummary* locations =
3100 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003101 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
3102 if (location.IsStackSlot()) {
3103 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
3104 } else if (location.IsDoubleStackSlot()) {
3105 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
3106 }
3107 locations->SetOut(location);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003108}
3109
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01003110void InstructionCodeGeneratorX86_64::VisitParameterValue(
3111 HParameterValue* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003112 // Nothing to do, the parameter is already at its location.
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01003113}
3114
3115void LocationsBuilderX86_64::VisitCurrentMethod(HCurrentMethod* instruction) {
3116 LocationSummary* locations =
3117 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3118 locations->SetOut(Location::RegisterLocation(kMethodRegisterArgument));
3119}
3120
3121void InstructionCodeGeneratorX86_64::VisitCurrentMethod(
3122 HCurrentMethod* instruction ATTRIBUTE_UNUSED) {
3123 // Nothing to do, the method is already at its location.
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003124}
3125
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003126void LocationsBuilderX86_64::VisitNot(HNot* not_) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003127 LocationSummary* locations =
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003128 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003129 locations->SetInAt(0, Location::RequiresRegister());
3130 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003131}
3132
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003133void InstructionCodeGeneratorX86_64::VisitNot(HNot* not_) {
3134 LocationSummary* locations = not_->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003135 DCHECK_EQ(locations->InAt(0).AsRegister<CpuRegister>().AsRegister(),
3136 locations->Out().AsRegister<CpuRegister>().AsRegister());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003137 Location out = locations->Out();
Nicolas Geoffrayd8ef2e92015-02-24 16:02:06 +00003138 switch (not_->GetResultType()) {
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003139 case Primitive::kPrimInt:
Roland Levillain271ab9c2014-11-27 15:23:57 +00003140 __ notl(out.AsRegister<CpuRegister>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003141 break;
3142
3143 case Primitive::kPrimLong:
Roland Levillain271ab9c2014-11-27 15:23:57 +00003144 __ notq(out.AsRegister<CpuRegister>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003145 break;
3146
3147 default:
3148 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
3149 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003150}
3151
David Brazdil66d126e2015-04-03 16:02:44 +01003152void LocationsBuilderX86_64::VisitBooleanNot(HBooleanNot* bool_not) {
3153 LocationSummary* locations =
3154 new (GetGraph()->GetArena()) LocationSummary(bool_not, LocationSummary::kNoCall);
3155 locations->SetInAt(0, Location::RequiresRegister());
3156 locations->SetOut(Location::SameAsFirstInput());
3157}
3158
3159void InstructionCodeGeneratorX86_64::VisitBooleanNot(HBooleanNot* bool_not) {
David Brazdil66d126e2015-04-03 16:02:44 +01003160 LocationSummary* locations = bool_not->GetLocations();
3161 DCHECK_EQ(locations->InAt(0).AsRegister<CpuRegister>().AsRegister(),
3162 locations->Out().AsRegister<CpuRegister>().AsRegister());
3163 Location out = locations->Out();
3164 __ xorl(out.AsRegister<CpuRegister>(), Immediate(1));
3165}
3166
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003167void LocationsBuilderX86_64::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003168 LocationSummary* locations =
3169 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003170 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
3171 locations->SetInAt(i, Location::Any());
3172 }
3173 locations->SetOut(Location::Any());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003174}
3175
3176void InstructionCodeGeneratorX86_64::VisitPhi(HPhi* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003177 UNUSED(instruction);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003178 LOG(FATAL) << "Unimplemented";
3179}
3180
Calin Juravle52c48962014-12-16 17:02:57 +00003181void InstructionCodeGeneratorX86_64::GenerateMemoryBarrier(MemBarrierKind kind) {
3182 /*
3183 * According to the JSR-133 Cookbook, for x86 only StoreLoad/AnyAny barriers need memory fence.
3184 * All other barriers (LoadAny, AnyStore, StoreStore) are nops due to the x86 memory model.
3185 * For those cases, all we need to ensure is that there is a scheduling barrier in place.
3186 */
3187 switch (kind) {
3188 case MemBarrierKind::kAnyAny: {
3189 __ mfence();
3190 break;
3191 }
3192 case MemBarrierKind::kAnyStore:
3193 case MemBarrierKind::kLoadAny:
3194 case MemBarrierKind::kStoreStore: {
3195 // nop
3196 break;
3197 }
3198 default:
3199 LOG(FATAL) << "Unexpected memory barier " << kind;
3200 }
3201}
3202
3203void LocationsBuilderX86_64::HandleFieldGet(HInstruction* instruction) {
3204 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
3205
Nicolas Geoffray39468442014-09-02 15:17:15 +01003206 LocationSummary* locations =
3207 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Calin Juravle52c48962014-12-16 17:02:57 +00003208 locations->SetInAt(0, Location::RequiresRegister());
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003209 if (Primitive::IsFloatingPointType(instruction->GetType())) {
3210 locations->SetOut(Location::RequiresFpuRegister());
3211 } else {
3212 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3213 }
Calin Juravle52c48962014-12-16 17:02:57 +00003214}
3215
3216void InstructionCodeGeneratorX86_64::HandleFieldGet(HInstruction* instruction,
3217 const FieldInfo& field_info) {
3218 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
3219
3220 LocationSummary* locations = instruction->GetLocations();
3221 CpuRegister base = locations->InAt(0).AsRegister<CpuRegister>();
3222 Location out = locations->Out();
3223 bool is_volatile = field_info.IsVolatile();
3224 Primitive::Type field_type = field_info.GetFieldType();
3225 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
3226
3227 switch (field_type) {
3228 case Primitive::kPrimBoolean: {
3229 __ movzxb(out.AsRegister<CpuRegister>(), Address(base, offset));
3230 break;
3231 }
3232
3233 case Primitive::kPrimByte: {
3234 __ movsxb(out.AsRegister<CpuRegister>(), Address(base, offset));
3235 break;
3236 }
3237
3238 case Primitive::kPrimShort: {
3239 __ movsxw(out.AsRegister<CpuRegister>(), Address(base, offset));
3240 break;
3241 }
3242
3243 case Primitive::kPrimChar: {
3244 __ movzxw(out.AsRegister<CpuRegister>(), Address(base, offset));
3245 break;
3246 }
3247
3248 case Primitive::kPrimInt:
3249 case Primitive::kPrimNot: {
3250 __ movl(out.AsRegister<CpuRegister>(), Address(base, offset));
3251 break;
3252 }
3253
3254 case Primitive::kPrimLong: {
3255 __ movq(out.AsRegister<CpuRegister>(), Address(base, offset));
3256 break;
3257 }
3258
3259 case Primitive::kPrimFloat: {
3260 __ movss(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
3261 break;
3262 }
3263
3264 case Primitive::kPrimDouble: {
3265 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
3266 break;
3267 }
3268
3269 case Primitive::kPrimVoid:
3270 LOG(FATAL) << "Unreachable type " << field_type;
3271 UNREACHABLE();
3272 }
3273
Calin Juravle77520bc2015-01-12 18:45:46 +00003274 codegen_->MaybeRecordImplicitNullCheck(instruction);
3275
Calin Juravle52c48962014-12-16 17:02:57 +00003276 if (is_volatile) {
3277 GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
3278 }
Roland Levillain4d027112015-07-01 15:41:14 +01003279
3280 if (field_type == Primitive::kPrimNot) {
3281 __ MaybeUnpoisonHeapReference(out.AsRegister<CpuRegister>());
3282 }
Calin Juravle52c48962014-12-16 17:02:57 +00003283}
3284
3285void LocationsBuilderX86_64::HandleFieldSet(HInstruction* instruction,
3286 const FieldInfo& field_info) {
3287 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3288
3289 LocationSummary* locations =
3290 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Roland Levillain4d027112015-07-01 15:41:14 +01003291 Primitive::Type field_type = field_info.GetFieldType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003292 bool needs_write_barrier =
Roland Levillain4d027112015-07-01 15:41:14 +01003293 CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
Calin Juravle52c48962014-12-16 17:02:57 +00003294
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003295 locations->SetInAt(0, Location::RequiresRegister());
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003296 if (Primitive::IsFloatingPointType(instruction->InputAt(1)->GetType())) {
3297 locations->SetInAt(1, Location::RequiresFpuRegister());
3298 } else {
Mark Mendell40741f32015-04-20 22:10:34 -04003299 locations->SetInAt(1, Location::RegisterOrInt32LongConstant(instruction->InputAt(1)));
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003300 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003301 if (needs_write_barrier) {
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01003302 // Temporary registers for the write barrier.
Roland Levillain4d027112015-07-01 15:41:14 +01003303 locations->AddTemp(Location::RequiresRegister()); // Possibly used for reference poisoning too.
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003304 locations->AddTemp(Location::RequiresRegister());
Roland Levillain4d027112015-07-01 15:41:14 +01003305 } else if (kPoisonHeapReferences && field_type == Primitive::kPrimNot) {
3306 // Temporary register for the reference poisoning.
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003307 locations->AddTemp(Location::RequiresRegister());
3308 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003309}
3310
Calin Juravle52c48962014-12-16 17:02:57 +00003311void InstructionCodeGeneratorX86_64::HandleFieldSet(HInstruction* instruction,
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003312 const FieldInfo& field_info,
3313 bool value_can_be_null) {
Calin Juravle52c48962014-12-16 17:02:57 +00003314 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3315
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003316 LocationSummary* locations = instruction->GetLocations();
Calin Juravle52c48962014-12-16 17:02:57 +00003317 CpuRegister base = locations->InAt(0).AsRegister<CpuRegister>();
3318 Location value = locations->InAt(1);
3319 bool is_volatile = field_info.IsVolatile();
3320 Primitive::Type field_type = field_info.GetFieldType();
3321 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
3322
3323 if (is_volatile) {
3324 GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
3325 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003326
3327 switch (field_type) {
3328 case Primitive::kPrimBoolean:
3329 case Primitive::kPrimByte: {
Mark Mendell40741f32015-04-20 22:10:34 -04003330 if (value.IsConstant()) {
3331 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
3332 __ movb(Address(base, offset), Immediate(v));
3333 } else {
3334 __ movb(Address(base, offset), value.AsRegister<CpuRegister>());
3335 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003336 break;
3337 }
3338
3339 case Primitive::kPrimShort:
3340 case Primitive::kPrimChar: {
Mark Mendell40741f32015-04-20 22:10:34 -04003341 if (value.IsConstant()) {
3342 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
3343 __ movw(Address(base, offset), Immediate(v));
3344 } else {
3345 __ movw(Address(base, offset), value.AsRegister<CpuRegister>());
3346 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003347 break;
3348 }
3349
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003350 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003351 case Primitive::kPrimNot: {
Mark Mendell40741f32015-04-20 22:10:34 -04003352 if (value.IsConstant()) {
3353 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
Roland Levillain4d027112015-07-01 15:41:14 +01003354 // `field_type == Primitive::kPrimNot` implies `v == 0`.
3355 DCHECK((field_type != Primitive::kPrimNot) || (v == 0));
3356 // Note: if heap poisoning is enabled, no need to poison
3357 // (negate) `v` if it is a reference, as it would be null.
Roland Levillain06b66d02015-07-01 12:47:25 +01003358 __ movl(Address(base, offset), Immediate(v));
Mark Mendell40741f32015-04-20 22:10:34 -04003359 } else {
Roland Levillain4d027112015-07-01 15:41:14 +01003360 if (kPoisonHeapReferences && field_type == Primitive::kPrimNot) {
3361 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
3362 __ movl(temp, value.AsRegister<CpuRegister>());
3363 __ PoisonHeapReference(temp);
3364 __ movl(Address(base, offset), temp);
3365 } else {
3366 __ movl(Address(base, offset), value.AsRegister<CpuRegister>());
3367 }
Mark Mendell40741f32015-04-20 22:10:34 -04003368 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003369 break;
3370 }
3371
3372 case Primitive::kPrimLong: {
Mark Mendell40741f32015-04-20 22:10:34 -04003373 if (value.IsConstant()) {
3374 int64_t v = value.GetConstant()->AsLongConstant()->GetValue();
3375 DCHECK(IsInt<32>(v));
3376 int32_t v_32 = v;
3377 __ movq(Address(base, offset), Immediate(v_32));
3378 } else {
3379 __ movq(Address(base, offset), value.AsRegister<CpuRegister>());
3380 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003381 break;
3382 }
3383
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003384 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00003385 __ movss(Address(base, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003386 break;
3387 }
3388
3389 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00003390 __ movsd(Address(base, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003391 break;
3392 }
3393
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003394 case Primitive::kPrimVoid:
3395 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003396 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003397 }
Calin Juravle52c48962014-12-16 17:02:57 +00003398
Calin Juravle77520bc2015-01-12 18:45:46 +00003399 codegen_->MaybeRecordImplicitNullCheck(instruction);
3400
3401 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
3402 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
3403 CpuRegister card = locations->GetTemp(1).AsRegister<CpuRegister>();
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003404 codegen_->MarkGCCard(temp, card, base, value.AsRegister<CpuRegister>(), value_can_be_null);
Calin Juravle77520bc2015-01-12 18:45:46 +00003405 }
3406
Calin Juravle52c48962014-12-16 17:02:57 +00003407 if (is_volatile) {
3408 GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
3409 }
3410}
3411
3412void LocationsBuilderX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
3413 HandleFieldSet(instruction, instruction->GetFieldInfo());
3414}
3415
3416void InstructionCodeGeneratorX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003417 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003418}
3419
3420void LocationsBuilderX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Calin Juravle52c48962014-12-16 17:02:57 +00003421 HandleFieldGet(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003422}
3423
3424void InstructionCodeGeneratorX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Calin Juravle52c48962014-12-16 17:02:57 +00003425 HandleFieldGet(instruction, instruction->GetFieldInfo());
3426}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003427
Calin Juravle52c48962014-12-16 17:02:57 +00003428void LocationsBuilderX86_64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
3429 HandleFieldGet(instruction);
3430}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003431
Calin Juravle52c48962014-12-16 17:02:57 +00003432void InstructionCodeGeneratorX86_64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
3433 HandleFieldGet(instruction, instruction->GetFieldInfo());
3434}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003435
Calin Juravle52c48962014-12-16 17:02:57 +00003436void LocationsBuilderX86_64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
3437 HandleFieldSet(instruction, instruction->GetFieldInfo());
3438}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003439
Calin Juravle52c48962014-12-16 17:02:57 +00003440void InstructionCodeGeneratorX86_64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003441 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003442}
3443
3444void LocationsBuilderX86_64::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003445 LocationSummary* locations =
3446 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003447 Location loc = codegen_->GetCompilerOptions().GetImplicitNullChecks()
3448 ? Location::RequiresRegister()
3449 : Location::Any();
3450 locations->SetInAt(0, loc);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003451 if (instruction->HasUses()) {
3452 locations->SetOut(Location::SameAsFirstInput());
3453 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003454}
3455
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003456void InstructionCodeGeneratorX86_64::GenerateImplicitNullCheck(HNullCheck* instruction) {
Calin Juravle77520bc2015-01-12 18:45:46 +00003457 if (codegen_->CanMoveNullCheckToUser(instruction)) {
3458 return;
3459 }
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003460 LocationSummary* locations = instruction->GetLocations();
3461 Location obj = locations->InAt(0);
3462
3463 __ testl(CpuRegister(RAX), Address(obj.AsRegister<CpuRegister>(), 0));
3464 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3465}
3466
3467void InstructionCodeGeneratorX86_64::GenerateExplicitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +01003468 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathX86_64(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003469 codegen_->AddSlowPath(slow_path);
3470
3471 LocationSummary* locations = instruction->GetLocations();
3472 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003473
3474 if (obj.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00003475 __ testl(obj.AsRegister<CpuRegister>(), obj.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003476 } else if (obj.IsStackSlot()) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003477 __ cmpl(Address(CpuRegister(RSP), obj.GetStackIndex()), Immediate(0));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003478 } else {
3479 DCHECK(obj.IsConstant()) << obj;
3480 DCHECK_EQ(obj.GetConstant()->AsIntConstant()->GetValue(), 0);
3481 __ jmp(slow_path->GetEntryLabel());
3482 return;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003483 }
3484 __ j(kEqual, slow_path->GetEntryLabel());
3485}
3486
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003487void InstructionCodeGeneratorX86_64::VisitNullCheck(HNullCheck* instruction) {
3488 if (codegen_->GetCompilerOptions().GetImplicitNullChecks()) {
3489 GenerateImplicitNullCheck(instruction);
3490 } else {
3491 GenerateExplicitNullCheck(instruction);
3492 }
3493}
3494
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003495void LocationsBuilderX86_64::VisitArrayGet(HArrayGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003496 LocationSummary* locations =
3497 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003498 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell40741f32015-04-20 22:10:34 -04003499 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003500 if (Primitive::IsFloatingPointType(instruction->GetType())) {
3501 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
3502 } else {
3503 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3504 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003505}
3506
3507void InstructionCodeGeneratorX86_64::VisitArrayGet(HArrayGet* instruction) {
3508 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003509 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003510 Location index = locations->InAt(1);
Roland Levillain4d027112015-07-01 15:41:14 +01003511 Primitive::Type type = instruction->GetType();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003512
Roland Levillain4d027112015-07-01 15:41:14 +01003513 switch (type) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003514 case Primitive::kPrimBoolean: {
3515 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003516 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003517 if (index.IsConstant()) {
3518 __ movzxb(out, Address(obj,
3519 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
3520 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003521 __ movzxb(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003522 }
3523 break;
3524 }
3525
3526 case Primitive::kPrimByte: {
3527 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003528 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003529 if (index.IsConstant()) {
3530 __ movsxb(out, Address(obj,
3531 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
3532 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003533 __ movsxb(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003534 }
3535 break;
3536 }
3537
3538 case Primitive::kPrimShort: {
3539 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003540 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003541 if (index.IsConstant()) {
3542 __ movsxw(out, Address(obj,
3543 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
3544 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003545 __ movsxw(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003546 }
3547 break;
3548 }
3549
3550 case Primitive::kPrimChar: {
3551 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003552 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003553 if (index.IsConstant()) {
3554 __ movzxw(out, Address(obj,
3555 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
3556 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003557 __ movzxw(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003558 }
3559 break;
3560 }
3561
3562 case Primitive::kPrimInt:
3563 case Primitive::kPrimNot: {
Roland Levillain33d69032015-06-18 18:20:59 +01003564 static_assert(sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
3565 "art::mirror::HeapReference<mirror::Object> and int32_t have different sizes.");
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003566 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003567 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003568 if (index.IsConstant()) {
3569 __ movl(out, Address(obj,
3570 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
3571 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003572 __ movl(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003573 }
3574 break;
3575 }
3576
3577 case Primitive::kPrimLong: {
3578 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003579 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003580 if (index.IsConstant()) {
3581 __ movq(out, Address(obj,
3582 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
3583 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003584 __ movq(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003585 }
3586 break;
3587 }
3588
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003589 case Primitive::kPrimFloat: {
3590 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003591 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003592 if (index.IsConstant()) {
3593 __ movss(out, Address(obj,
3594 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
3595 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003596 __ movss(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003597 }
3598 break;
3599 }
3600
3601 case Primitive::kPrimDouble: {
3602 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003603 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003604 if (index.IsConstant()) {
3605 __ movsd(out, Address(obj,
3606 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
3607 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003608 __ movsd(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003609 }
3610 break;
3611 }
3612
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003613 case Primitive::kPrimVoid:
Roland Levillain4d027112015-07-01 15:41:14 +01003614 LOG(FATAL) << "Unreachable type " << type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003615 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003616 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003617 codegen_->MaybeRecordImplicitNullCheck(instruction);
Roland Levillain4d027112015-07-01 15:41:14 +01003618
3619 if (type == Primitive::kPrimNot) {
3620 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
3621 __ MaybeUnpoisonHeapReference(out);
3622 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003623}
3624
3625void LocationsBuilderX86_64::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003626 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003627
3628 bool needs_write_barrier =
3629 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
3630 bool needs_runtime_call = instruction->NeedsTypeCheck();
3631
Nicolas Geoffray39468442014-09-02 15:17:15 +01003632 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003633 instruction, needs_runtime_call ? LocationSummary::kCall : LocationSummary::kNoCall);
3634 if (needs_runtime_call) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003635 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003636 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3637 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
3638 locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003639 } else {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003640 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01003641 locations->SetInAt(
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003642 1, Location::RegisterOrConstant(instruction->InputAt(1)));
3643 locations->SetInAt(2, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003644 if (value_type == Primitive::kPrimLong) {
Mark Mendell40741f32015-04-20 22:10:34 -04003645 locations->SetInAt(2, Location::RegisterOrInt32LongConstant(instruction->InputAt(2)));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003646 } else if (value_type == Primitive::kPrimFloat || value_type == Primitive::kPrimDouble) {
3647 locations->SetInAt(2, Location::RequiresFpuRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003648 } else {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003649 locations->SetInAt(2, Location::RegisterOrConstant(instruction->InputAt(2)));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003650 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003651
3652 if (needs_write_barrier) {
3653 // Temporary registers for the write barrier.
Roland Levillain4d027112015-07-01 15:41:14 +01003654 locations->AddTemp(Location::RequiresRegister()); // Possibly used for ref. poisoning too.
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003655 locations->AddTemp(Location::RequiresRegister());
3656 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003657 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003658}
3659
3660void InstructionCodeGeneratorX86_64::VisitArraySet(HArraySet* instruction) {
3661 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003662 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003663 Location index = locations->InAt(1);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003664 Location value = locations->InAt(2);
Nicolas Geoffray39468442014-09-02 15:17:15 +01003665 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003666 bool needs_runtime_call = locations->WillCall();
3667 bool needs_write_barrier =
3668 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003669
3670 switch (value_type) {
3671 case Primitive::kPrimBoolean:
3672 case Primitive::kPrimByte: {
3673 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003674 if (index.IsConstant()) {
3675 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003676 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003677 __ movb(Address(obj, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003678 } else {
Roland Levillain199f3362014-11-27 17:15:16 +00003679 __ movb(Address(obj, offset),
3680 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003681 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003682 } else {
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003683 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003684 __ movb(Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset),
3685 value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003686 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003687 __ movb(Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003688 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3689 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003690 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003691 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003692 break;
3693 }
3694
3695 case Primitive::kPrimShort:
3696 case Primitive::kPrimChar: {
3697 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003698 if (index.IsConstant()) {
3699 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003700 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003701 __ movw(Address(obj, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003702 } else {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003703 DCHECK(value.IsConstant()) << value;
Roland Levillain199f3362014-11-27 17:15:16 +00003704 __ movw(Address(obj, offset),
3705 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003706 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003707 } else {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003708 DCHECK(index.IsRegister()) << index;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003709 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003710 __ movw(Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset),
3711 value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003712 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003713 DCHECK(value.IsConstant()) << value;
Roland Levillain271ab9c2014-11-27 15:23:57 +00003714 __ movw(Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003715 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3716 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003717 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003718 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003719 break;
3720 }
3721
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003722 case Primitive::kPrimInt:
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003723 case Primitive::kPrimNot: {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003724 if (!needs_runtime_call) {
3725 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
3726 if (index.IsConstant()) {
3727 size_t offset =
3728 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
3729 if (value.IsRegister()) {
Roland Levillain4d027112015-07-01 15:41:14 +01003730 if (kPoisonHeapReferences && value_type == Primitive::kPrimNot) {
3731 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
3732 __ movl(temp, value.AsRegister<CpuRegister>());
3733 __ PoisonHeapReference(temp);
3734 __ movl(Address(obj, offset), temp);
3735 } else {
3736 __ movl(Address(obj, offset), value.AsRegister<CpuRegister>());
3737 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003738 } else {
3739 DCHECK(value.IsConstant()) << value;
Mark Mendell40741f32015-04-20 22:10:34 -04003740 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
Roland Levillain4d027112015-07-01 15:41:14 +01003741 // `value_type == Primitive::kPrimNot` implies `v == 0`.
3742 DCHECK((value_type != Primitive::kPrimNot) || (v == 0));
3743 // Note: if heap poisoning is enabled, no need to poison
3744 // (negate) `v` if it is a reference, as it would be null.
Mark Mendell40741f32015-04-20 22:10:34 -04003745 __ movl(Address(obj, offset), Immediate(v));
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003746 }
3747 } else {
3748 DCHECK(index.IsRegister()) << index;
3749 if (value.IsRegister()) {
Roland Levillain4d027112015-07-01 15:41:14 +01003750 if (kPoisonHeapReferences && value_type == Primitive::kPrimNot) {
3751 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
3752 __ movl(temp, value.AsRegister<CpuRegister>());
3753 __ PoisonHeapReference(temp);
3754 __ movl(Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset), temp);
3755 } else {
3756 __ movl(Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset),
3757 value.AsRegister<CpuRegister>());
3758 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003759 } else {
3760 DCHECK(value.IsConstant()) << value;
Mark Mendell40741f32015-04-20 22:10:34 -04003761 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
Roland Levillain4d027112015-07-01 15:41:14 +01003762 // `value_type == Primitive::kPrimNot` implies `v == 0`.
3763 DCHECK((value_type != Primitive::kPrimNot) || (v == 0));
3764 // Note: if heap poisoning is enabled, no need to poison
3765 // (negate) `v` if it is a reference, as it would be null.
Roland Levillain271ab9c2014-11-27 15:23:57 +00003766 __ movl(Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset),
Mark Mendell40741f32015-04-20 22:10:34 -04003767 Immediate(v));
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003768 }
3769 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003770 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003771 if (needs_write_barrier) {
3772 DCHECK_EQ(value_type, Primitive::kPrimNot);
Roland Levillain271ab9c2014-11-27 15:23:57 +00003773 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
3774 CpuRegister card = locations->GetTemp(1).AsRegister<CpuRegister>();
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003775 codegen_->MarkGCCard(
3776 temp, card, obj, value.AsRegister<CpuRegister>(), instruction->GetValueCanBeNull());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003777 }
3778 } else {
3779 DCHECK_EQ(value_type, Primitive::kPrimNot);
Roland Levillain4d027112015-07-01 15:41:14 +01003780 // Note: if heap poisoning is enabled, pAputObject takes cares
3781 // of poisoning the reference.
Roland Levillain199f3362014-11-27 17:15:16 +00003782 __ gs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pAputObject),
3783 true));
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003784 DCHECK(!codegen_->IsLeafMethod());
3785 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3786 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003787 break;
3788 }
3789
3790 case Primitive::kPrimLong: {
3791 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003792 if (index.IsConstant()) {
3793 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Mark Mendell40741f32015-04-20 22:10:34 -04003794 if (value.IsRegister()) {
3795 __ movq(Address(obj, offset), value.AsRegister<CpuRegister>());
3796 } else {
3797 int64_t v = value.GetConstant()->AsLongConstant()->GetValue();
3798 DCHECK(IsInt<32>(v));
3799 int32_t v_32 = v;
3800 __ movq(Address(obj, offset), Immediate(v_32));
3801 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003802 } else {
Mark Mendell40741f32015-04-20 22:10:34 -04003803 if (value.IsRegister()) {
3804 __ movq(Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset),
3805 value.AsRegister<CpuRegister>());
3806 } else {
3807 int64_t v = value.GetConstant()->AsLongConstant()->GetValue();
3808 DCHECK(IsInt<32>(v));
3809 int32_t v_32 = v;
3810 __ movq(Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset),
3811 Immediate(v_32));
3812 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003813 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003814 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003815 break;
3816 }
3817
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003818 case Primitive::kPrimFloat: {
3819 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
3820 if (index.IsConstant()) {
3821 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
3822 DCHECK(value.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003823 __ movss(Address(obj, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003824 } else {
3825 DCHECK(value.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003826 __ movss(Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset),
3827 value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003828 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003829 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003830 break;
3831 }
3832
3833 case Primitive::kPrimDouble: {
3834 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
3835 if (index.IsConstant()) {
3836 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
3837 DCHECK(value.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003838 __ movsd(Address(obj, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003839 } else {
3840 DCHECK(value.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003841 __ movsd(Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset),
3842 value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003843 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003844 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003845 break;
3846 }
3847
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003848 case Primitive::kPrimVoid:
3849 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07003850 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003851 }
3852}
3853
3854void LocationsBuilderX86_64::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003855 LocationSummary* locations =
3856 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003857 locations->SetInAt(0, Location::RequiresRegister());
3858 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003859}
3860
3861void InstructionCodeGeneratorX86_64::VisitArrayLength(HArrayLength* instruction) {
3862 LocationSummary* locations = instruction->GetLocations();
3863 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003864 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
3865 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003866 __ movl(out, Address(obj, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00003867 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003868}
3869
3870void LocationsBuilderX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003871 LocationSummary* locations =
3872 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Mark Mendellf60c90b2015-03-04 15:12:59 -05003873 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
Mark Mendell99dbd682015-04-22 16:18:52 -04003874 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003875 if (instruction->HasUses()) {
3876 locations->SetOut(Location::SameAsFirstInput());
3877 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003878}
3879
3880void InstructionCodeGeneratorX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
3881 LocationSummary* locations = instruction->GetLocations();
Mark Mendellf60c90b2015-03-04 15:12:59 -05003882 Location index_loc = locations->InAt(0);
3883 Location length_loc = locations->InAt(1);
3884 SlowPathCodeX86_64* slow_path =
3885 new (GetGraph()->GetArena()) BoundsCheckSlowPathX86_64(instruction, index_loc, length_loc);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003886
Mark Mendell99dbd682015-04-22 16:18:52 -04003887 if (length_loc.IsConstant()) {
3888 int32_t length = CodeGenerator::GetInt32ValueOf(length_loc.GetConstant());
3889 if (index_loc.IsConstant()) {
3890 // BCE will remove the bounds check if we are guarenteed to pass.
3891 int32_t index = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
3892 if (index < 0 || index >= length) {
3893 codegen_->AddSlowPath(slow_path);
3894 __ jmp(slow_path->GetEntryLabel());
3895 } else {
3896 // Some optimization after BCE may have generated this, and we should not
3897 // generate a bounds check if it is a valid range.
3898 }
3899 return;
3900 }
3901
3902 // We have to reverse the jump condition because the length is the constant.
3903 CpuRegister index_reg = index_loc.AsRegister<CpuRegister>();
3904 __ cmpl(index_reg, Immediate(length));
3905 codegen_->AddSlowPath(slow_path);
3906 __ j(kAboveEqual, slow_path->GetEntryLabel());
Mark Mendellf60c90b2015-03-04 15:12:59 -05003907 } else {
Mark Mendell99dbd682015-04-22 16:18:52 -04003908 CpuRegister length = length_loc.AsRegister<CpuRegister>();
3909 if (index_loc.IsConstant()) {
3910 int32_t value = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
3911 __ cmpl(length, Immediate(value));
3912 } else {
3913 __ cmpl(length, index_loc.AsRegister<CpuRegister>());
3914 }
3915 codegen_->AddSlowPath(slow_path);
3916 __ j(kBelowEqual, slow_path->GetEntryLabel());
Mark Mendellf60c90b2015-03-04 15:12:59 -05003917 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003918}
3919
3920void CodeGeneratorX86_64::MarkGCCard(CpuRegister temp,
3921 CpuRegister card,
3922 CpuRegister object,
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003923 CpuRegister value,
3924 bool value_can_be_null) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003925 Label is_null;
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003926 if (value_can_be_null) {
3927 __ testl(value, value);
3928 __ j(kEqual, &is_null);
3929 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003930 __ gs()->movq(card, Address::Absolute(
3931 Thread::CardTableOffset<kX86_64WordSize>().Int32Value(), true));
3932 __ movq(temp, object);
3933 __ shrq(temp, Immediate(gc::accounting::CardTable::kCardShift));
Roland Levillain4d027112015-07-01 15:41:14 +01003934 __ movb(Address(temp, card, TIMES_1, 0), card);
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003935 if (value_can_be_null) {
3936 __ Bind(&is_null);
3937 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003938}
3939
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003940void LocationsBuilderX86_64::VisitTemporary(HTemporary* temp) {
3941 temp->SetLocations(nullptr);
3942}
3943
3944void InstructionCodeGeneratorX86_64::VisitTemporary(HTemporary* temp) {
3945 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003946 UNUSED(temp);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003947}
3948
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003949void LocationsBuilderX86_64::VisitParallelMove(HParallelMove* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003950 UNUSED(instruction);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003951 LOG(FATAL) << "Unimplemented";
3952}
3953
3954void InstructionCodeGeneratorX86_64::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003955 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
3956}
3957
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003958void LocationsBuilderX86_64::VisitSuspendCheck(HSuspendCheck* instruction) {
3959 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
3960}
3961
3962void InstructionCodeGeneratorX86_64::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003963 HBasicBlock* block = instruction->GetBlock();
3964 if (block->GetLoopInformation() != nullptr) {
3965 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
3966 // The back edge will generate the suspend check.
3967 return;
3968 }
3969 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
3970 // The goto will generate the suspend check.
3971 return;
3972 }
3973 GenerateSuspendCheck(instruction, nullptr);
3974}
3975
3976void InstructionCodeGeneratorX86_64::GenerateSuspendCheck(HSuspendCheck* instruction,
3977 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003978 SuspendCheckSlowPathX86_64* slow_path =
Nicolas Geoffraydb216f42015-05-05 17:02:20 +01003979 down_cast<SuspendCheckSlowPathX86_64*>(instruction->GetSlowPath());
3980 if (slow_path == nullptr) {
3981 slow_path = new (GetGraph()->GetArena()) SuspendCheckSlowPathX86_64(instruction, successor);
3982 instruction->SetSlowPath(slow_path);
3983 codegen_->AddSlowPath(slow_path);
3984 if (successor != nullptr) {
3985 DCHECK(successor->IsLoopHeader());
3986 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(instruction);
3987 }
3988 } else {
3989 DCHECK_EQ(slow_path->GetSuccessor(), successor);
3990 }
3991
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003992 __ gs()->cmpw(Address::Absolute(
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003993 Thread::ThreadFlagsOffset<kX86_64WordSize>().Int32Value(), true), Immediate(0));
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003994 if (successor == nullptr) {
3995 __ j(kNotEqual, slow_path->GetEntryLabel());
3996 __ Bind(slow_path->GetReturnLabel());
3997 } else {
3998 __ j(kEqual, codegen_->GetLabelOf(successor));
3999 __ jmp(slow_path->GetEntryLabel());
4000 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004001}
4002
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004003X86_64Assembler* ParallelMoveResolverX86_64::GetAssembler() const {
4004 return codegen_->GetAssembler();
4005}
4006
4007void ParallelMoveResolverX86_64::EmitMove(size_t index) {
4008 MoveOperands* move = moves_.Get(index);
4009 Location source = move->GetSource();
4010 Location destination = move->GetDestination();
4011
4012 if (source.IsRegister()) {
4013 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004014 __ movq(destination.AsRegister<CpuRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004015 } else if (destination.IsStackSlot()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004016 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00004017 source.AsRegister<CpuRegister>());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004018 } else {
4019 DCHECK(destination.IsDoubleStackSlot());
4020 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00004021 source.AsRegister<CpuRegister>());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004022 }
4023 } else if (source.IsStackSlot()) {
4024 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004025 __ movl(destination.AsRegister<CpuRegister>(),
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004026 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004027 } else if (destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004028 __ movss(destination.AsFpuRegister<XmmRegister>(),
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004029 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004030 } else {
4031 DCHECK(destination.IsStackSlot());
4032 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
4033 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
4034 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004035 } else if (source.IsDoubleStackSlot()) {
4036 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004037 __ movq(destination.AsRegister<CpuRegister>(),
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004038 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004039 } else if (destination.IsFpuRegister()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004040 __ movsd(destination.AsFpuRegister<XmmRegister>(),
4041 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004042 } else {
Nicolas Geoffrayc8147a72014-10-21 16:06:20 +01004043 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004044 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
4045 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
4046 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004047 } else if (source.IsConstant()) {
4048 HConstant* constant = source.GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00004049 if (constant->IsIntConstant() || constant->IsNullConstant()) {
4050 int32_t value = CodeGenerator::GetInt32ValueOf(constant);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004051 if (destination.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00004052 if (value == 0) {
4053 __ xorl(destination.AsRegister<CpuRegister>(), destination.AsRegister<CpuRegister>());
4054 } else {
4055 __ movl(destination.AsRegister<CpuRegister>(), Immediate(value));
4056 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004057 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004058 DCHECK(destination.IsStackSlot()) << destination;
Nicolas Geoffray748f1402015-01-27 08:17:54 +00004059 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), Immediate(value));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004060 }
4061 } else if (constant->IsLongConstant()) {
4062 int64_t value = constant->AsLongConstant()->GetValue();
4063 if (destination.IsRegister()) {
Mark Mendell92e83bf2015-05-07 11:25:03 -04004064 codegen_->Load64BitValue(destination.AsRegister<CpuRegister>(), value);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004065 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004066 DCHECK(destination.IsDoubleStackSlot()) << destination;
Mark Mendell92e83bf2015-05-07 11:25:03 -04004067 codegen_->Load64BitValue(CpuRegister(TMP), value);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004068 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
4069 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004070 } else if (constant->IsFloatConstant()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004071 float fp_value = constant->AsFloatConstant()->GetValue();
Roland Levillainda4d79b2015-03-24 14:36:11 +00004072 int32_t value = bit_cast<int32_t, float>(fp_value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004073 if (destination.IsFpuRegister()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004074 XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
4075 if (value == 0) {
4076 // easy FP 0.0.
4077 __ xorps(dest, dest);
4078 } else {
Mark Mendell92e83bf2015-05-07 11:25:03 -04004079 __ movss(dest, codegen_->LiteralFloatAddress(fp_value));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004080 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004081 } else {
4082 DCHECK(destination.IsStackSlot()) << destination;
Mark Mendell92e83bf2015-05-07 11:25:03 -04004083 Immediate imm(value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004084 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), imm);
4085 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004086 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004087 DCHECK(constant->IsDoubleConstant()) << constant->DebugName();
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004088 double fp_value = constant->AsDoubleConstant()->GetValue();
Roland Levillainda4d79b2015-03-24 14:36:11 +00004089 int64_t value = bit_cast<int64_t, double>(fp_value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004090 if (destination.IsFpuRegister()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004091 XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
4092 if (value == 0) {
4093 __ xorpd(dest, dest);
4094 } else {
Mark Mendell92e83bf2015-05-07 11:25:03 -04004095 __ movsd(dest, codegen_->LiteralDoubleAddress(fp_value));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004096 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004097 } else {
4098 DCHECK(destination.IsDoubleStackSlot()) << destination;
Mark Mendell92e83bf2015-05-07 11:25:03 -04004099 codegen_->Load64BitValue(CpuRegister(TMP), value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004100 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
4101 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004102 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004103 } else if (source.IsFpuRegister()) {
4104 if (destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004105 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004106 } else if (destination.IsStackSlot()) {
4107 __ movss(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00004108 source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004109 } else {
Nicolas Geoffray31596742014-11-24 15:28:45 +00004110 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004111 __ movsd(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00004112 source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004113 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004114 }
4115}
4116
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004117void ParallelMoveResolverX86_64::Exchange32(CpuRegister reg, int mem) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004118 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004119 __ movl(Address(CpuRegister(RSP), mem), reg);
4120 __ movl(reg, CpuRegister(TMP));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004121}
4122
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004123void ParallelMoveResolverX86_64::Exchange32(int mem1, int mem2) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004124 ScratchRegisterScope ensure_scratch(
4125 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
4126
4127 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
4128 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
4129 __ movl(CpuRegister(ensure_scratch.GetRegister()),
4130 Address(CpuRegister(RSP), mem2 + stack_offset));
4131 __ movl(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
4132 __ movl(Address(CpuRegister(RSP), mem1 + stack_offset),
4133 CpuRegister(ensure_scratch.GetRegister()));
4134}
4135
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004136void ParallelMoveResolverX86_64::Exchange64(CpuRegister reg, int mem) {
4137 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
4138 __ movq(Address(CpuRegister(RSP), mem), reg);
4139 __ movq(reg, CpuRegister(TMP));
4140}
4141
4142void ParallelMoveResolverX86_64::Exchange64(int mem1, int mem2) {
4143 ScratchRegisterScope ensure_scratch(
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004144 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004145
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004146 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
4147 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
4148 __ movq(CpuRegister(ensure_scratch.GetRegister()),
4149 Address(CpuRegister(RSP), mem2 + stack_offset));
4150 __ movq(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
4151 __ movq(Address(CpuRegister(RSP), mem1 + stack_offset),
4152 CpuRegister(ensure_scratch.GetRegister()));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004153}
4154
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004155void ParallelMoveResolverX86_64::Exchange32(XmmRegister reg, int mem) {
4156 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
4157 __ movss(Address(CpuRegister(RSP), mem), reg);
4158 __ movd(reg, CpuRegister(TMP));
4159}
4160
4161void ParallelMoveResolverX86_64::Exchange64(XmmRegister reg, int mem) {
4162 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
4163 __ movsd(Address(CpuRegister(RSP), mem), reg);
4164 __ movd(reg, CpuRegister(TMP));
4165}
4166
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004167void ParallelMoveResolverX86_64::EmitSwap(size_t index) {
4168 MoveOperands* move = moves_.Get(index);
4169 Location source = move->GetSource();
4170 Location destination = move->GetDestination();
4171
4172 if (source.IsRegister() && destination.IsRegister()) {
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004173 __ xchgq(destination.AsRegister<CpuRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004174 } else if (source.IsRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004175 Exchange32(source.AsRegister<CpuRegister>(), destination.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004176 } else if (source.IsStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004177 Exchange32(destination.AsRegister<CpuRegister>(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004178 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004179 Exchange32(destination.GetStackIndex(), source.GetStackIndex());
4180 } else if (source.IsRegister() && destination.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004181 Exchange64(source.AsRegister<CpuRegister>(), destination.GetStackIndex());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004182 } else if (source.IsDoubleStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004183 Exchange64(destination.AsRegister<CpuRegister>(), source.GetStackIndex());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004184 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
4185 Exchange64(destination.GetStackIndex(), source.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004186 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004187 __ movd(CpuRegister(TMP), source.AsFpuRegister<XmmRegister>());
4188 __ movaps(source.AsFpuRegister<XmmRegister>(), destination.AsFpuRegister<XmmRegister>());
4189 __ movd(destination.AsFpuRegister<XmmRegister>(), CpuRegister(TMP));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004190 } else if (source.IsFpuRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004191 Exchange32(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004192 } else if (source.IsStackSlot() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004193 Exchange32(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004194 } else if (source.IsFpuRegister() && destination.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004195 Exchange64(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004196 } else if (source.IsDoubleStackSlot() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004197 Exchange64(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004198 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004199 LOG(FATAL) << "Unimplemented swap between " << source << " and " << destination;
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004200 }
4201}
4202
4203
4204void ParallelMoveResolverX86_64::SpillScratch(int reg) {
4205 __ pushq(CpuRegister(reg));
4206}
4207
4208
4209void ParallelMoveResolverX86_64::RestoreScratch(int reg) {
4210 __ popq(CpuRegister(reg));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004211}
4212
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004213void InstructionCodeGeneratorX86_64::GenerateClassInitializationCheck(
4214 SlowPathCodeX86_64* slow_path, CpuRegister class_reg) {
4215 __ cmpl(Address(class_reg, mirror::Class::StatusOffset().Int32Value()),
4216 Immediate(mirror::Class::kStatusInitialized));
4217 __ j(kLess, slow_path->GetEntryLabel());
4218 __ Bind(slow_path->GetExitLabel());
4219 // No need for memory fence, thanks to the X86_64 memory model.
4220}
4221
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004222void LocationsBuilderX86_64::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004223 LocationSummary::CallKind call_kind = cls->CanCallRuntime()
4224 ? LocationSummary::kCallOnSlowPath
4225 : LocationSummary::kNoCall;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004226 LocationSummary* locations =
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004227 new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004228 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004229 locations->SetOut(Location::RequiresRegister());
4230}
4231
4232void InstructionCodeGeneratorX86_64::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004233 LocationSummary* locations = cls->GetLocations();
4234 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
4235 CpuRegister current_method = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004236 if (cls->IsReferrersClass()) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004237 DCHECK(!cls->CanCallRuntime());
4238 DCHECK(!cls->MustGenerateClinitCheck());
Mathieu Chartiere401d142015-04-22 13:56:20 -07004239 __ movl(out, Address(current_method, ArtMethod::DeclaringClassOffset().Int32Value()));
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004240 } else {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004241 DCHECK(cls->CanCallRuntime());
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004242 __ movl(out, Address(
Mathieu Chartiere401d142015-04-22 13:56:20 -07004243 current_method, ArtMethod::DexCacheResolvedTypesOffset().Int32Value()));
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004244 __ movl(out, Address(out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex())));
Roland Levillain4d027112015-07-01 15:41:14 +01004245 __ MaybeUnpoisonHeapReference(out);
4246
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004247 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86_64(
4248 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
4249 codegen_->AddSlowPath(slow_path);
4250 __ testl(out, out);
4251 __ j(kEqual, slow_path->GetEntryLabel());
4252 if (cls->MustGenerateClinitCheck()) {
4253 GenerateClassInitializationCheck(slow_path, out);
4254 } else {
4255 __ Bind(slow_path->GetExitLabel());
4256 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004257 }
4258}
4259
4260void LocationsBuilderX86_64::VisitClinitCheck(HClinitCheck* check) {
4261 LocationSummary* locations =
4262 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
4263 locations->SetInAt(0, Location::RequiresRegister());
4264 if (check->HasUses()) {
4265 locations->SetOut(Location::SameAsFirstInput());
4266 }
4267}
4268
4269void InstructionCodeGeneratorX86_64::VisitClinitCheck(HClinitCheck* check) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004270 // We assume the class to not be null.
4271 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86_64(
4272 check->GetLoadClass(), check, check->GetDexPc(), true);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004273 codegen_->AddSlowPath(slow_path);
Roland Levillain199f3362014-11-27 17:15:16 +00004274 GenerateClassInitializationCheck(slow_path,
4275 check->GetLocations()->InAt(0).AsRegister<CpuRegister>());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004276}
4277
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004278void LocationsBuilderX86_64::VisitLoadString(HLoadString* load) {
4279 LocationSummary* locations =
4280 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01004281 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004282 locations->SetOut(Location::RequiresRegister());
4283}
4284
4285void InstructionCodeGeneratorX86_64::VisitLoadString(HLoadString* load) {
4286 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathX86_64(load);
4287 codegen_->AddSlowPath(slow_path);
4288
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01004289 LocationSummary* locations = load->GetLocations();
4290 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
4291 CpuRegister current_method = locations->InAt(0).AsRegister<CpuRegister>();
Mathieu Chartiere401d142015-04-22 13:56:20 -07004292 __ movl(out, Address(current_method, ArtMethod::DeclaringClassOffset().Int32Value()));
Mathieu Chartiereace4582014-11-24 18:29:54 -08004293 __ movl(out, Address(out, mirror::Class::DexCacheStringsOffset().Int32Value()));
Roland Levillain4d027112015-07-01 15:41:14 +01004294 __ MaybeUnpoisonHeapReference(out);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004295 __ movl(out, Address(out, CodeGenerator::GetCacheOffset(load->GetStringIndex())));
Roland Levillain4d027112015-07-01 15:41:14 +01004296 __ MaybeUnpoisonHeapReference(out);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004297 __ testl(out, out);
4298 __ j(kEqual, slow_path->GetEntryLabel());
4299 __ Bind(slow_path->GetExitLabel());
4300}
4301
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004302void LocationsBuilderX86_64::VisitLoadException(HLoadException* load) {
4303 LocationSummary* locations =
4304 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
4305 locations->SetOut(Location::RequiresRegister());
4306}
4307
4308void InstructionCodeGeneratorX86_64::VisitLoadException(HLoadException* load) {
4309 Address address = Address::Absolute(
4310 Thread::ExceptionOffset<kX86_64WordSize>().Int32Value(), true);
Roland Levillain271ab9c2014-11-27 15:23:57 +00004311 __ gs()->movl(load->GetLocations()->Out().AsRegister<CpuRegister>(), address);
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004312 __ gs()->movl(address, Immediate(0));
4313}
4314
4315void LocationsBuilderX86_64::VisitThrow(HThrow* instruction) {
4316 LocationSummary* locations =
4317 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
4318 InvokeRuntimeCallingConvention calling_convention;
4319 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4320}
4321
4322void InstructionCodeGeneratorX86_64::VisitThrow(HThrow* instruction) {
4323 __ gs()->call(
4324 Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pDeliverException), true));
4325 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
4326}
4327
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004328void LocationsBuilderX86_64::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004329 LocationSummary::CallKind call_kind = instruction->IsClassFinal()
4330 ? LocationSummary::kNoCall
4331 : LocationSummary::kCallOnSlowPath;
4332 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
4333 locations->SetInAt(0, Location::RequiresRegister());
4334 locations->SetInAt(1, Location::Any());
4335 locations->SetOut(Location::RequiresRegister());
4336}
4337
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004338void InstructionCodeGeneratorX86_64::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004339 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004340 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004341 Location cls = locations->InAt(1);
Roland Levillain271ab9c2014-11-27 15:23:57 +00004342 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004343 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
4344 Label done, zero;
4345 SlowPathCodeX86_64* slow_path = nullptr;
4346
4347 // Return 0 if `obj` is null.
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004348 // Avoid null check if we know obj is not null.
4349 if (instruction->MustDoNullCheck()) {
4350 __ testl(obj, obj);
4351 __ j(kEqual, &zero);
4352 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004353 // Compare the class of `obj` with `cls`.
4354 __ movl(out, Address(obj, class_offset));
Roland Levillain4d027112015-07-01 15:41:14 +01004355 __ MaybeUnpoisonHeapReference(out);
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004356 if (cls.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004357 __ cmpl(out, cls.AsRegister<CpuRegister>());
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004358 } else {
4359 DCHECK(cls.IsStackSlot()) << cls;
4360 __ cmpl(out, Address(CpuRegister(RSP), cls.GetStackIndex()));
4361 }
4362 if (instruction->IsClassFinal()) {
4363 // Classes must be equal for the instanceof to succeed.
4364 __ j(kNotEqual, &zero);
4365 __ movl(out, Immediate(1));
4366 __ jmp(&done);
4367 } else {
4368 // If the classes are not equal, we go into a slow path.
4369 DCHECK(locations->OnlyCallsOnSlowPath());
4370 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86_64(
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004371 instruction, locations->InAt(1), locations->Out(), instruction->GetDexPc());
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004372 codegen_->AddSlowPath(slow_path);
4373 __ j(kNotEqual, slow_path->GetEntryLabel());
4374 __ movl(out, Immediate(1));
4375 __ jmp(&done);
4376 }
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004377
4378 if (instruction->MustDoNullCheck() || instruction->IsClassFinal()) {
4379 __ Bind(&zero);
4380 __ movl(out, Immediate(0));
4381 }
4382
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004383 if (slow_path != nullptr) {
4384 __ Bind(slow_path->GetExitLabel());
4385 }
4386 __ Bind(&done);
4387}
4388
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004389void LocationsBuilderX86_64::VisitCheckCast(HCheckCast* instruction) {
4390 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
4391 instruction, LocationSummary::kCallOnSlowPath);
4392 locations->SetInAt(0, Location::RequiresRegister());
4393 locations->SetInAt(1, Location::Any());
4394 locations->AddTemp(Location::RequiresRegister());
4395}
4396
4397void InstructionCodeGeneratorX86_64::VisitCheckCast(HCheckCast* instruction) {
4398 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004399 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004400 Location cls = locations->InAt(1);
Roland Levillain271ab9c2014-11-27 15:23:57 +00004401 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004402 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
4403 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86_64(
4404 instruction, locations->InAt(1), locations->GetTemp(0), instruction->GetDexPc());
4405 codegen_->AddSlowPath(slow_path);
4406
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004407 // Avoid null check if we know obj is not null.
4408 if (instruction->MustDoNullCheck()) {
4409 __ testl(obj, obj);
4410 __ j(kEqual, slow_path->GetExitLabel());
4411 }
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004412 // Compare the class of `obj` with `cls`.
4413 __ movl(temp, Address(obj, class_offset));
Roland Levillain4d027112015-07-01 15:41:14 +01004414 __ MaybeUnpoisonHeapReference(temp);
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004415 if (cls.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004416 __ cmpl(temp, cls.AsRegister<CpuRegister>());
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004417 } else {
4418 DCHECK(cls.IsStackSlot()) << cls;
4419 __ cmpl(temp, Address(CpuRegister(RSP), cls.GetStackIndex()));
4420 }
Roland Levillain4d027112015-07-01 15:41:14 +01004421 // The checkcast succeeds if the classes are equal (fast path).
4422 // Otherwise, we need to go into the slow path to check the types.
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004423 __ j(kNotEqual, slow_path->GetEntryLabel());
4424 __ Bind(slow_path->GetExitLabel());
4425}
4426
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00004427void LocationsBuilderX86_64::VisitMonitorOperation(HMonitorOperation* instruction) {
4428 LocationSummary* locations =
4429 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
4430 InvokeRuntimeCallingConvention calling_convention;
4431 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4432}
4433
4434void InstructionCodeGeneratorX86_64::VisitMonitorOperation(HMonitorOperation* instruction) {
4435 __ gs()->call(Address::Absolute(instruction->IsEnter()
4436 ? QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pLockObject)
4437 : QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pUnlockObject),
4438 true));
4439 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
4440}
4441
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004442void LocationsBuilderX86_64::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); }
4443void LocationsBuilderX86_64::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); }
4444void LocationsBuilderX86_64::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); }
4445
4446void LocationsBuilderX86_64::HandleBitwiseOperation(HBinaryOperation* instruction) {
4447 LocationSummary* locations =
4448 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
4449 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
4450 || instruction->GetResultType() == Primitive::kPrimLong);
4451 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell40741f32015-04-20 22:10:34 -04004452 locations->SetInAt(1, Location::Any());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004453 locations->SetOut(Location::SameAsFirstInput());
4454}
4455
4456void InstructionCodeGeneratorX86_64::VisitAnd(HAnd* instruction) {
4457 HandleBitwiseOperation(instruction);
4458}
4459
4460void InstructionCodeGeneratorX86_64::VisitOr(HOr* instruction) {
4461 HandleBitwiseOperation(instruction);
4462}
4463
4464void InstructionCodeGeneratorX86_64::VisitXor(HXor* instruction) {
4465 HandleBitwiseOperation(instruction);
4466}
4467
4468void InstructionCodeGeneratorX86_64::HandleBitwiseOperation(HBinaryOperation* instruction) {
4469 LocationSummary* locations = instruction->GetLocations();
4470 Location first = locations->InAt(0);
4471 Location second = locations->InAt(1);
4472 DCHECK(first.Equals(locations->Out()));
4473
4474 if (instruction->GetResultType() == Primitive::kPrimInt) {
4475 if (second.IsRegister()) {
4476 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004477 __ andl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004478 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004479 __ orl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004480 } else {
4481 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004482 __ xorl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004483 }
4484 } else if (second.IsConstant()) {
4485 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
4486 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004487 __ andl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004488 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004489 __ orl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004490 } else {
4491 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004492 __ xorl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004493 }
4494 } else {
4495 Address address(CpuRegister(RSP), second.GetStackIndex());
4496 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004497 __ andl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004498 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004499 __ orl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004500 } else {
4501 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004502 __ xorl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004503 }
4504 }
4505 } else {
4506 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004507 CpuRegister first_reg = first.AsRegister<CpuRegister>();
4508 bool second_is_constant = false;
4509 int64_t value = 0;
4510 if (second.IsConstant()) {
4511 second_is_constant = true;
4512 value = second.GetConstant()->AsLongConstant()->GetValue();
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004513 }
Mark Mendell40741f32015-04-20 22:10:34 -04004514 bool is_int32_value = IsInt<32>(value);
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004515
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004516 if (instruction->IsAnd()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004517 if (second_is_constant) {
Mark Mendell40741f32015-04-20 22:10:34 -04004518 if (is_int32_value) {
4519 __ andq(first_reg, Immediate(static_cast<int32_t>(value)));
4520 } else {
4521 __ andq(first_reg, codegen_->LiteralInt64Address(value));
4522 }
4523 } else if (second.IsDoubleStackSlot()) {
4524 __ andq(first_reg, Address(CpuRegister(RSP), second.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004525 } else {
4526 __ andq(first_reg, second.AsRegister<CpuRegister>());
4527 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004528 } else if (instruction->IsOr()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004529 if (second_is_constant) {
Mark Mendell40741f32015-04-20 22:10:34 -04004530 if (is_int32_value) {
4531 __ orq(first_reg, Immediate(static_cast<int32_t>(value)));
4532 } else {
4533 __ orq(first_reg, codegen_->LiteralInt64Address(value));
4534 }
4535 } else if (second.IsDoubleStackSlot()) {
4536 __ orq(first_reg, Address(CpuRegister(RSP), second.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004537 } else {
4538 __ orq(first_reg, second.AsRegister<CpuRegister>());
4539 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004540 } else {
4541 DCHECK(instruction->IsXor());
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004542 if (second_is_constant) {
Mark Mendell40741f32015-04-20 22:10:34 -04004543 if (is_int32_value) {
4544 __ xorq(first_reg, Immediate(static_cast<int32_t>(value)));
4545 } else {
4546 __ xorq(first_reg, codegen_->LiteralInt64Address(value));
4547 }
4548 } else if (second.IsDoubleStackSlot()) {
4549 __ xorq(first_reg, Address(CpuRegister(RSP), second.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004550 } else {
4551 __ xorq(first_reg, second.AsRegister<CpuRegister>());
4552 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004553 }
4554 }
4555}
4556
Calin Juravleb1498f62015-02-16 13:13:29 +00004557void LocationsBuilderX86_64::VisitBoundType(HBoundType* instruction) {
4558 // Nothing to do, this should be removed during prepare for register allocator.
4559 UNUSED(instruction);
4560 LOG(FATAL) << "Unreachable";
4561}
4562
4563void InstructionCodeGeneratorX86_64::VisitBoundType(HBoundType* instruction) {
4564 // Nothing to do, this should be removed during prepare for register allocator.
4565 UNUSED(instruction);
4566 LOG(FATAL) << "Unreachable";
4567}
4568
Mark Mendell92e83bf2015-05-07 11:25:03 -04004569void CodeGeneratorX86_64::Load64BitValue(CpuRegister dest, int64_t value) {
4570 if (value == 0) {
4571 __ xorl(dest, dest);
4572 } else if (value > 0 && IsInt<32>(value)) {
4573 // We can use a 32 bit move, as it will zero-extend and is one byte shorter.
4574 __ movl(dest, Immediate(static_cast<int32_t>(value)));
4575 } else {
4576 __ movq(dest, Immediate(value));
4577 }
4578}
4579
Mark Mendellf55c3e02015-03-26 21:07:46 -04004580void CodeGeneratorX86_64::Finalize(CodeAllocator* allocator) {
4581 // Generate the constant area if needed.
Mark Mendell39dcf552015-04-09 20:42:42 -04004582 X86_64Assembler* assembler = GetAssembler();
4583 if (!assembler->IsConstantAreaEmpty()) {
Mark Mendellf55c3e02015-03-26 21:07:46 -04004584 // Align to 4 byte boundary to reduce cache misses, as the data is 4 and 8
4585 // byte values. If used for vectors at a later time, this will need to be
4586 // updated to 16 bytes with the appropriate offset.
Mark Mendell39dcf552015-04-09 20:42:42 -04004587 assembler->Align(4, 0);
4588 constant_area_start_ = assembler->CodeSize();
4589 assembler->AddConstantArea();
Mark Mendellf55c3e02015-03-26 21:07:46 -04004590 }
4591
4592 // And finish up.
4593 CodeGenerator::Finalize(allocator);
4594}
4595
4596/**
4597 * Class to handle late fixup of offsets into constant area.
4598 */
4599class RIPFixup : public AssemblerFixup, public ArenaObject<kArenaAllocMisc> {
4600 public:
Mark Mendell39dcf552015-04-09 20:42:42 -04004601 RIPFixup(const CodeGeneratorX86_64& codegen, int offset)
Mark Mendellf55c3e02015-03-26 21:07:46 -04004602 : codegen_(codegen), offset_into_constant_area_(offset) {}
4603
4604 private:
4605 void Process(const MemoryRegion& region, int pos) OVERRIDE {
4606 // Patch the correct offset for the instruction. We use the address of the
4607 // 'next' instruction, which is 'pos' (patch the 4 bytes before).
4608 int constant_offset = codegen_.ConstantAreaStart() + offset_into_constant_area_;
4609 int relative_position = constant_offset - pos;
4610
4611 // Patch in the right value.
4612 region.StoreUnaligned<int32_t>(pos - 4, relative_position);
4613 }
4614
Mark Mendell39dcf552015-04-09 20:42:42 -04004615 const CodeGeneratorX86_64& codegen_;
Mark Mendellf55c3e02015-03-26 21:07:46 -04004616
4617 // Location in constant area that the fixup refers to.
4618 int offset_into_constant_area_;
4619};
4620
4621Address CodeGeneratorX86_64::LiteralDoubleAddress(double v) {
4622 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddDouble(v));
4623 return Address::RIP(fixup);
4624}
4625
4626Address CodeGeneratorX86_64::LiteralFloatAddress(float v) {
4627 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddFloat(v));
4628 return Address::RIP(fixup);
4629}
4630
4631Address CodeGeneratorX86_64::LiteralInt32Address(int32_t v) {
4632 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddInt32(v));
4633 return Address::RIP(fixup);
4634}
4635
4636Address CodeGeneratorX86_64::LiteralInt64Address(int64_t v) {
4637 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddInt64(v));
4638 return Address::RIP(fixup);
4639}
4640
Roland Levillain4d027112015-07-01 15:41:14 +01004641#undef __
4642
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004643} // namespace x86_64
4644} // namespace art