blob: a657194ce3fe4f00f1cec239cb1fdaee2455720d [file] [log] [blame]
Mark Mendell09ed1a32015-03-25 08:30:06 -04001/*
2 * Copyright (C) 2015 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 "intrinsics_x86.h"
18
Andreas Gampe21030dd2015-05-07 14:46:15 -070019#include <limits>
20
Mark Mendellfb8d2792015-03-31 22:16:59 -040021#include "arch/x86/instruction_set_features_x86.h"
Mathieu Chartiere401d142015-04-22 13:56:20 -070022#include "art_method.h"
Mark Mendelld5897672015-08-12 21:16:41 -040023#include "base/bit_utils.h"
Mark Mendell09ed1a32015-03-25 08:30:06 -040024#include "code_generator_x86.h"
25#include "entrypoints/quick/quick_entrypoints.h"
26#include "intrinsics.h"
Andreas Gampe85b62f22015-09-09 13:15:38 -070027#include "intrinsics_utils.h"
Mark Mendell09ed1a32015-03-25 08:30:06 -040028#include "mirror/array-inl.h"
Mark Mendell09ed1a32015-03-25 08:30:06 -040029#include "mirror/string.h"
30#include "thread.h"
31#include "utils/x86/assembler_x86.h"
32#include "utils/x86/constants_x86.h"
33
34namespace art {
35
36namespace x86 {
37
38static constexpr int kDoubleNaNHigh = 0x7FF80000;
39static constexpr int kDoubleNaNLow = 0x00000000;
Mark P Mendell2f10a5f2016-01-25 14:47:50 +000040static constexpr int64_t kDoubleNaN = INT64_C(0x7FF8000000000000);
41static constexpr int32_t kFloatNaN = INT32_C(0x7FC00000);
Mark Mendell09ed1a32015-03-25 08:30:06 -040042
Mark Mendellfb8d2792015-03-31 22:16:59 -040043IntrinsicLocationsBuilderX86::IntrinsicLocationsBuilderX86(CodeGeneratorX86* codegen)
Mark P Mendell2f10a5f2016-01-25 14:47:50 +000044 : arena_(codegen->GetGraph()->GetArena()),
45 codegen_(codegen) {
Mark Mendellfb8d2792015-03-31 22:16:59 -040046}
47
48
Mark Mendell09ed1a32015-03-25 08:30:06 -040049X86Assembler* IntrinsicCodeGeneratorX86::GetAssembler() {
Roland Levillainb488b782015-10-22 11:38:49 +010050 return down_cast<X86Assembler*>(codegen_->GetAssembler());
Mark Mendell09ed1a32015-03-25 08:30:06 -040051}
52
53ArenaAllocator* IntrinsicCodeGeneratorX86::GetAllocator() {
54 return codegen_->GetGraph()->GetArena();
55}
56
57bool IntrinsicLocationsBuilderX86::TryDispatch(HInvoke* invoke) {
58 Dispatch(invoke);
59 LocationSummary* res = invoke->GetLocations();
Roland Levillain0d5a2812015-11-13 10:07:31 +000060 if (res == nullptr) {
61 return false;
62 }
Roland Levillain0d5a2812015-11-13 10:07:31 +000063 return res->Intrinsified();
Mark Mendell09ed1a32015-03-25 08:30:06 -040064}
65
Roland Levillainec525fc2015-04-28 15:50:20 +010066static void MoveArguments(HInvoke* invoke, CodeGeneratorX86* codegen) {
Roland Levillain2d27c8e2015-04-28 15:48:45 +010067 InvokeDexCallingConventionVisitorX86 calling_convention_visitor;
Roland Levillainec525fc2015-04-28 15:50:20 +010068 IntrinsicVisitor::MoveArguments(invoke, codegen, &calling_convention_visitor);
Mark Mendell09ed1a32015-03-25 08:30:06 -040069}
70
Andreas Gampe85b62f22015-09-09 13:15:38 -070071using IntrinsicSlowPathX86 = IntrinsicSlowPath<InvokeDexCallingConventionVisitorX86>;
Mark Mendell09ed1a32015-03-25 08:30:06 -040072
Mark Mendell09ed1a32015-03-25 08:30:06 -040073#define __ assembler->
74
75static void CreateFPToIntLocations(ArenaAllocator* arena, HInvoke* invoke, bool is64bit) {
76 LocationSummary* locations = new (arena) LocationSummary(invoke,
77 LocationSummary::kNoCall,
78 kIntrinsified);
79 locations->SetInAt(0, Location::RequiresFpuRegister());
80 locations->SetOut(Location::RequiresRegister());
81 if (is64bit) {
82 locations->AddTemp(Location::RequiresFpuRegister());
83 }
84}
85
86static void CreateIntToFPLocations(ArenaAllocator* arena, HInvoke* invoke, bool is64bit) {
87 LocationSummary* locations = new (arena) LocationSummary(invoke,
88 LocationSummary::kNoCall,
89 kIntrinsified);
90 locations->SetInAt(0, Location::RequiresRegister());
91 locations->SetOut(Location::RequiresFpuRegister());
92 if (is64bit) {
93 locations->AddTemp(Location::RequiresFpuRegister());
94 locations->AddTemp(Location::RequiresFpuRegister());
95 }
96}
97
98static void MoveFPToInt(LocationSummary* locations, bool is64bit, X86Assembler* assembler) {
99 Location input = locations->InAt(0);
100 Location output = locations->Out();
101 if (is64bit) {
102 // Need to use the temporary.
103 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
104 __ movsd(temp, input.AsFpuRegister<XmmRegister>());
105 __ movd(output.AsRegisterPairLow<Register>(), temp);
106 __ psrlq(temp, Immediate(32));
107 __ movd(output.AsRegisterPairHigh<Register>(), temp);
108 } else {
109 __ movd(output.AsRegister<Register>(), input.AsFpuRegister<XmmRegister>());
110 }
111}
112
113static void MoveIntToFP(LocationSummary* locations, bool is64bit, X86Assembler* assembler) {
114 Location input = locations->InAt(0);
115 Location output = locations->Out();
116 if (is64bit) {
117 // Need to use the temporary.
118 XmmRegister temp1 = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
119 XmmRegister temp2 = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
120 __ movd(temp1, input.AsRegisterPairLow<Register>());
121 __ movd(temp2, input.AsRegisterPairHigh<Register>());
122 __ punpckldq(temp1, temp2);
123 __ movsd(output.AsFpuRegister<XmmRegister>(), temp1);
124 } else {
125 __ movd(output.AsFpuRegister<XmmRegister>(), input.AsRegister<Register>());
126 }
127}
128
129void IntrinsicLocationsBuilderX86::VisitDoubleDoubleToRawLongBits(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +0000130 CreateFPToIntLocations(arena_, invoke, /* is64bit */ true);
Mark Mendell09ed1a32015-03-25 08:30:06 -0400131}
132void IntrinsicLocationsBuilderX86::VisitDoubleLongBitsToDouble(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +0000133 CreateIntToFPLocations(arena_, invoke, /* is64bit */ true);
Mark Mendell09ed1a32015-03-25 08:30:06 -0400134}
135
136void IntrinsicCodeGeneratorX86::VisitDoubleDoubleToRawLongBits(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +0000137 MoveFPToInt(invoke->GetLocations(), /* is64bit */ true, GetAssembler());
Mark Mendell09ed1a32015-03-25 08:30:06 -0400138}
139void IntrinsicCodeGeneratorX86::VisitDoubleLongBitsToDouble(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +0000140 MoveIntToFP(invoke->GetLocations(), /* is64bit */ true, GetAssembler());
Mark Mendell09ed1a32015-03-25 08:30:06 -0400141}
142
143void IntrinsicLocationsBuilderX86::VisitFloatFloatToRawIntBits(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +0000144 CreateFPToIntLocations(arena_, invoke, /* is64bit */ false);
Mark Mendell09ed1a32015-03-25 08:30:06 -0400145}
146void IntrinsicLocationsBuilderX86::VisitFloatIntBitsToFloat(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +0000147 CreateIntToFPLocations(arena_, invoke, /* is64bit */ false);
Mark Mendell09ed1a32015-03-25 08:30:06 -0400148}
149
150void IntrinsicCodeGeneratorX86::VisitFloatFloatToRawIntBits(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +0000151 MoveFPToInt(invoke->GetLocations(), /* is64bit */ false, GetAssembler());
Mark Mendell09ed1a32015-03-25 08:30:06 -0400152}
153void IntrinsicCodeGeneratorX86::VisitFloatIntBitsToFloat(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +0000154 MoveIntToFP(invoke->GetLocations(), /* is64bit */ false, GetAssembler());
Mark Mendell09ed1a32015-03-25 08:30:06 -0400155}
156
157static void CreateIntToIntLocations(ArenaAllocator* arena, HInvoke* invoke) {
158 LocationSummary* locations = new (arena) LocationSummary(invoke,
159 LocationSummary::kNoCall,
160 kIntrinsified);
161 locations->SetInAt(0, Location::RequiresRegister());
162 locations->SetOut(Location::SameAsFirstInput());
163}
164
165static void CreateLongToIntLocations(ArenaAllocator* arena, HInvoke* invoke) {
166 LocationSummary* locations = new (arena) LocationSummary(invoke,
167 LocationSummary::kNoCall,
168 kIntrinsified);
169 locations->SetInAt(0, Location::RequiresRegister());
170 locations->SetOut(Location::RequiresRegister());
171}
172
173static void CreateLongToLongLocations(ArenaAllocator* arena, HInvoke* invoke) {
174 LocationSummary* locations = new (arena) LocationSummary(invoke,
175 LocationSummary::kNoCall,
176 kIntrinsified);
177 locations->SetInAt(0, Location::RequiresRegister());
178 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
179}
180
181static void GenReverseBytes(LocationSummary* locations,
182 Primitive::Type size,
183 X86Assembler* assembler) {
184 Register out = locations->Out().AsRegister<Register>();
185
186 switch (size) {
187 case Primitive::kPrimShort:
188 // TODO: Can be done with an xchg of 8b registers. This is straight from Quick.
189 __ bswapl(out);
190 __ sarl(out, Immediate(16));
191 break;
192 case Primitive::kPrimInt:
193 __ bswapl(out);
194 break;
195 default:
196 LOG(FATAL) << "Unexpected size for reverse-bytes: " << size;
197 UNREACHABLE();
198 }
199}
200
201void IntrinsicLocationsBuilderX86::VisitIntegerReverseBytes(HInvoke* invoke) {
202 CreateIntToIntLocations(arena_, invoke);
203}
204
205void IntrinsicCodeGeneratorX86::VisitIntegerReverseBytes(HInvoke* invoke) {
206 GenReverseBytes(invoke->GetLocations(), Primitive::kPrimInt, GetAssembler());
207}
208
Mark Mendell58d25fd2015-04-03 14:52:31 -0400209void IntrinsicLocationsBuilderX86::VisitLongReverseBytes(HInvoke* invoke) {
210 CreateLongToLongLocations(arena_, invoke);
211}
212
213void IntrinsicCodeGeneratorX86::VisitLongReverseBytes(HInvoke* invoke) {
214 LocationSummary* locations = invoke->GetLocations();
215 Location input = locations->InAt(0);
216 Register input_lo = input.AsRegisterPairLow<Register>();
217 Register input_hi = input.AsRegisterPairHigh<Register>();
218 Location output = locations->Out();
219 Register output_lo = output.AsRegisterPairLow<Register>();
220 Register output_hi = output.AsRegisterPairHigh<Register>();
221
222 X86Assembler* assembler = GetAssembler();
223 // Assign the inputs to the outputs, mixing low/high.
224 __ movl(output_lo, input_hi);
225 __ movl(output_hi, input_lo);
226 __ bswapl(output_lo);
227 __ bswapl(output_hi);
228}
229
Mark Mendell09ed1a32015-03-25 08:30:06 -0400230void IntrinsicLocationsBuilderX86::VisitShortReverseBytes(HInvoke* invoke) {
231 CreateIntToIntLocations(arena_, invoke);
232}
233
234void IntrinsicCodeGeneratorX86::VisitShortReverseBytes(HInvoke* invoke) {
235 GenReverseBytes(invoke->GetLocations(), Primitive::kPrimShort, GetAssembler());
236}
237
238
239// TODO: Consider Quick's way of doing Double abs through integer operations, as the immediate we
240// need is 64b.
241
242static void CreateFloatToFloat(ArenaAllocator* arena, HInvoke* invoke) {
243 // TODO: Enable memory operations when the assembler supports them.
244 LocationSummary* locations = new (arena) LocationSummary(invoke,
245 LocationSummary::kNoCall,
246 kIntrinsified);
247 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendell09ed1a32015-03-25 08:30:06 -0400248 locations->SetOut(Location::SameAsFirstInput());
Mark P Mendell2f10a5f2016-01-25 14:47:50 +0000249 HInvokeStaticOrDirect* static_or_direct = invoke->AsInvokeStaticOrDirect();
250 DCHECK(static_or_direct != nullptr);
Nicolas Geoffray97793072016-02-16 15:33:54 +0000251 if (static_or_direct->HasSpecialInput() &&
252 invoke->InputAt(static_or_direct->GetSpecialInputIndex())->IsX86ComputeBaseMethodAddress()) {
Mark P Mendell2f10a5f2016-01-25 14:47:50 +0000253 // We need addressibility for the constant area.
254 locations->SetInAt(1, Location::RequiresRegister());
255 // We need a temporary to hold the constant.
256 locations->AddTemp(Location::RequiresFpuRegister());
257 }
Mark Mendell09ed1a32015-03-25 08:30:06 -0400258}
259
Mark P Mendell2f10a5f2016-01-25 14:47:50 +0000260static void MathAbsFP(LocationSummary* locations,
261 bool is64bit,
262 X86Assembler* assembler,
263 CodeGeneratorX86* codegen) {
Mark Mendell09ed1a32015-03-25 08:30:06 -0400264 Location output = locations->Out();
265
Mark P Mendell2f10a5f2016-01-25 14:47:50 +0000266 DCHECK(output.IsFpuRegister());
Nicolas Geoffray97793072016-02-16 15:33:54 +0000267 if (locations->GetInputCount() == 2 && locations->InAt(1).IsValid()) {
Mark P Mendell2f10a5f2016-01-25 14:47:50 +0000268 DCHECK(locations->InAt(1).IsRegister());
269 // We also have a constant area pointer.
270 Register constant_area = locations->InAt(1).AsRegister<Register>();
271 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
272 if (is64bit) {
273 __ movsd(temp, codegen->LiteralInt64Address(INT64_C(0x7FFFFFFFFFFFFFFF), constant_area));
274 __ andpd(output.AsFpuRegister<XmmRegister>(), temp);
275 } else {
276 __ movss(temp, codegen->LiteralInt32Address(INT32_C(0x7FFFFFFF), constant_area));
277 __ andps(output.AsFpuRegister<XmmRegister>(), temp);
278 }
279 } else {
Mark Mendell09ed1a32015-03-25 08:30:06 -0400280 // Create the right constant on an aligned stack.
281 if (is64bit) {
282 __ subl(ESP, Immediate(8));
283 __ pushl(Immediate(0x7FFFFFFF));
284 __ pushl(Immediate(0xFFFFFFFF));
285 __ andpd(output.AsFpuRegister<XmmRegister>(), Address(ESP, 0));
286 } else {
287 __ subl(ESP, Immediate(12));
288 __ pushl(Immediate(0x7FFFFFFF));
289 __ andps(output.AsFpuRegister<XmmRegister>(), Address(ESP, 0));
290 }
291 __ addl(ESP, Immediate(16));
Mark Mendell09ed1a32015-03-25 08:30:06 -0400292 }
293}
294
295void IntrinsicLocationsBuilderX86::VisitMathAbsDouble(HInvoke* invoke) {
296 CreateFloatToFloat(arena_, invoke);
297}
298
299void IntrinsicCodeGeneratorX86::VisitMathAbsDouble(HInvoke* invoke) {
Mark P Mendell2f10a5f2016-01-25 14:47:50 +0000300 MathAbsFP(invoke->GetLocations(), /* is64bit */ true, GetAssembler(), codegen_);
Mark Mendell09ed1a32015-03-25 08:30:06 -0400301}
302
303void IntrinsicLocationsBuilderX86::VisitMathAbsFloat(HInvoke* invoke) {
304 CreateFloatToFloat(arena_, invoke);
305}
306
307void IntrinsicCodeGeneratorX86::VisitMathAbsFloat(HInvoke* invoke) {
Mark P Mendell2f10a5f2016-01-25 14:47:50 +0000308 MathAbsFP(invoke->GetLocations(), /* is64bit */ false, GetAssembler(), codegen_);
Mark Mendell09ed1a32015-03-25 08:30:06 -0400309}
310
311static void CreateAbsIntLocation(ArenaAllocator* arena, HInvoke* invoke) {
312 LocationSummary* locations = new (arena) LocationSummary(invoke,
313 LocationSummary::kNoCall,
314 kIntrinsified);
315 locations->SetInAt(0, Location::RegisterLocation(EAX));
316 locations->SetOut(Location::SameAsFirstInput());
317 locations->AddTemp(Location::RegisterLocation(EDX));
318}
319
320static void GenAbsInteger(LocationSummary* locations, X86Assembler* assembler) {
321 Location output = locations->Out();
322 Register out = output.AsRegister<Register>();
323 DCHECK_EQ(out, EAX);
324 Register temp = locations->GetTemp(0).AsRegister<Register>();
325 DCHECK_EQ(temp, EDX);
326
327 // Sign extend EAX into EDX.
328 __ cdq();
329
330 // XOR EAX with sign.
331 __ xorl(EAX, EDX);
332
333 // Subtract out sign to correct.
334 __ subl(EAX, EDX);
335
336 // The result is in EAX.
337}
338
339static void CreateAbsLongLocation(ArenaAllocator* arena, HInvoke* invoke) {
340 LocationSummary* locations = new (arena) LocationSummary(invoke,
341 LocationSummary::kNoCall,
342 kIntrinsified);
343 locations->SetInAt(0, Location::RequiresRegister());
344 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
345 locations->AddTemp(Location::RequiresRegister());
346}
347
348static void GenAbsLong(LocationSummary* locations, X86Assembler* assembler) {
349 Location input = locations->InAt(0);
350 Register input_lo = input.AsRegisterPairLow<Register>();
351 Register input_hi = input.AsRegisterPairHigh<Register>();
352 Location output = locations->Out();
353 Register output_lo = output.AsRegisterPairLow<Register>();
354 Register output_hi = output.AsRegisterPairHigh<Register>();
355 Register temp = locations->GetTemp(0).AsRegister<Register>();
356
357 // Compute the sign into the temporary.
358 __ movl(temp, input_hi);
359 __ sarl(temp, Immediate(31));
360
361 // Store the sign into the output.
362 __ movl(output_lo, temp);
363 __ movl(output_hi, temp);
364
365 // XOR the input to the output.
366 __ xorl(output_lo, input_lo);
367 __ xorl(output_hi, input_hi);
368
369 // Subtract the sign.
370 __ subl(output_lo, temp);
371 __ sbbl(output_hi, temp);
372}
373
374void IntrinsicLocationsBuilderX86::VisitMathAbsInt(HInvoke* invoke) {
375 CreateAbsIntLocation(arena_, invoke);
376}
377
378void IntrinsicCodeGeneratorX86::VisitMathAbsInt(HInvoke* invoke) {
379 GenAbsInteger(invoke->GetLocations(), GetAssembler());
380}
381
382void IntrinsicLocationsBuilderX86::VisitMathAbsLong(HInvoke* invoke) {
383 CreateAbsLongLocation(arena_, invoke);
384}
385
386void IntrinsicCodeGeneratorX86::VisitMathAbsLong(HInvoke* invoke) {
387 GenAbsLong(invoke->GetLocations(), GetAssembler());
388}
389
Mark P Mendell2f10a5f2016-01-25 14:47:50 +0000390static void GenMinMaxFP(LocationSummary* locations,
391 bool is_min,
392 bool is_double,
393 X86Assembler* assembler,
394 CodeGeneratorX86* codegen) {
Mark Mendell09ed1a32015-03-25 08:30:06 -0400395 Location op1_loc = locations->InAt(0);
396 Location op2_loc = locations->InAt(1);
397 Location out_loc = locations->Out();
398 XmmRegister out = out_loc.AsFpuRegister<XmmRegister>();
399
400 // Shortcut for same input locations.
401 if (op1_loc.Equals(op2_loc)) {
402 DCHECK(out_loc.Equals(op1_loc));
403 return;
404 }
405
406 // (out := op1)
407 // out <=? op2
408 // if Nan jmp Nan_label
409 // if out is min jmp done
410 // if op2 is min jmp op2_label
411 // handle -0/+0
412 // jmp done
413 // Nan_label:
414 // out := NaN
415 // op2_label:
416 // out := op2
417 // done:
418 //
419 // This removes one jmp, but needs to copy one input (op1) to out.
420 //
421 // TODO: This is straight from Quick (except literal pool). Make NaN an out-of-line slowpath?
422
423 XmmRegister op2 = op2_loc.AsFpuRegister<XmmRegister>();
424
Mark Mendell0c9497d2015-08-21 09:30:05 -0400425 NearLabel nan, done, op2_label;
Mark Mendell09ed1a32015-03-25 08:30:06 -0400426 if (is_double) {
427 __ ucomisd(out, op2);
428 } else {
429 __ ucomiss(out, op2);
430 }
431
432 __ j(Condition::kParityEven, &nan);
433
434 __ j(is_min ? Condition::kAbove : Condition::kBelow, &op2_label);
435 __ j(is_min ? Condition::kBelow : Condition::kAbove, &done);
436
437 // Handle 0.0/-0.0.
438 if (is_min) {
439 if (is_double) {
440 __ orpd(out, op2);
441 } else {
442 __ orps(out, op2);
443 }
444 } else {
445 if (is_double) {
446 __ andpd(out, op2);
447 } else {
448 __ andps(out, op2);
449 }
450 }
451 __ jmp(&done);
452
453 // NaN handling.
454 __ Bind(&nan);
Mark P Mendell2f10a5f2016-01-25 14:47:50 +0000455 // Do we have a constant area pointer?
Nicolas Geoffray97793072016-02-16 15:33:54 +0000456 if (locations->GetInputCount() == 3 && locations->InAt(2).IsValid()) {
Mark P Mendell2f10a5f2016-01-25 14:47:50 +0000457 DCHECK(locations->InAt(2).IsRegister());
458 Register constant_area = locations->InAt(2).AsRegister<Register>();
459 if (is_double) {
460 __ movsd(out, codegen->LiteralInt64Address(kDoubleNaN, constant_area));
461 } else {
462 __ movss(out, codegen->LiteralInt32Address(kFloatNaN, constant_area));
463 }
Mark Mendell09ed1a32015-03-25 08:30:06 -0400464 } else {
Mark P Mendell2f10a5f2016-01-25 14:47:50 +0000465 if (is_double) {
466 __ pushl(Immediate(kDoubleNaNHigh));
467 __ pushl(Immediate(kDoubleNaNLow));
468 __ movsd(out, Address(ESP, 0));
469 __ addl(ESP, Immediate(8));
470 } else {
471 __ pushl(Immediate(kFloatNaN));
472 __ movss(out, Address(ESP, 0));
473 __ addl(ESP, Immediate(4));
474 }
Mark Mendell09ed1a32015-03-25 08:30:06 -0400475 }
476 __ jmp(&done);
477
478 // out := op2;
479 __ Bind(&op2_label);
480 if (is_double) {
481 __ movsd(out, op2);
482 } else {
483 __ movss(out, op2);
484 }
485
486 // Done.
487 __ Bind(&done);
488}
489
490static void CreateFPFPToFPLocations(ArenaAllocator* arena, HInvoke* invoke) {
491 LocationSummary* locations = new (arena) LocationSummary(invoke,
492 LocationSummary::kNoCall,
493 kIntrinsified);
494 locations->SetInAt(0, Location::RequiresFpuRegister());
495 locations->SetInAt(1, Location::RequiresFpuRegister());
496 // The following is sub-optimal, but all we can do for now. It would be fine to also accept
497 // the second input to be the output (we can simply swap inputs).
498 locations->SetOut(Location::SameAsFirstInput());
Mark P Mendell2f10a5f2016-01-25 14:47:50 +0000499 HInvokeStaticOrDirect* static_or_direct = invoke->AsInvokeStaticOrDirect();
500 DCHECK(static_or_direct != nullptr);
Nicolas Geoffray97793072016-02-16 15:33:54 +0000501 if (static_or_direct->HasSpecialInput() &&
502 invoke->InputAt(static_or_direct->GetSpecialInputIndex())->IsX86ComputeBaseMethodAddress()) {
Mark P Mendell2f10a5f2016-01-25 14:47:50 +0000503 locations->SetInAt(2, Location::RequiresRegister());
504 }
Mark Mendell09ed1a32015-03-25 08:30:06 -0400505}
506
507void IntrinsicLocationsBuilderX86::VisitMathMinDoubleDouble(HInvoke* invoke) {
508 CreateFPFPToFPLocations(arena_, invoke);
509}
510
511void IntrinsicCodeGeneratorX86::VisitMathMinDoubleDouble(HInvoke* invoke) {
Mark P Mendell2f10a5f2016-01-25 14:47:50 +0000512 GenMinMaxFP(invoke->GetLocations(),
513 /* is_min */ true,
514 /* is_double */ true,
515 GetAssembler(),
516 codegen_);
Mark Mendell09ed1a32015-03-25 08:30:06 -0400517}
518
519void IntrinsicLocationsBuilderX86::VisitMathMinFloatFloat(HInvoke* invoke) {
520 CreateFPFPToFPLocations(arena_, invoke);
521}
522
523void IntrinsicCodeGeneratorX86::VisitMathMinFloatFloat(HInvoke* invoke) {
Mark P Mendell2f10a5f2016-01-25 14:47:50 +0000524 GenMinMaxFP(invoke->GetLocations(),
525 /* is_min */ true,
526 /* is_double */ false,
527 GetAssembler(),
528 codegen_);
Mark Mendell09ed1a32015-03-25 08:30:06 -0400529}
530
531void IntrinsicLocationsBuilderX86::VisitMathMaxDoubleDouble(HInvoke* invoke) {
532 CreateFPFPToFPLocations(arena_, invoke);
533}
534
535void IntrinsicCodeGeneratorX86::VisitMathMaxDoubleDouble(HInvoke* invoke) {
Mark P Mendell2f10a5f2016-01-25 14:47:50 +0000536 GenMinMaxFP(invoke->GetLocations(),
537 /* is_min */ false,
538 /* is_double */ true,
539 GetAssembler(),
540 codegen_);
Mark Mendell09ed1a32015-03-25 08:30:06 -0400541}
542
543void IntrinsicLocationsBuilderX86::VisitMathMaxFloatFloat(HInvoke* invoke) {
544 CreateFPFPToFPLocations(arena_, invoke);
545}
546
547void IntrinsicCodeGeneratorX86::VisitMathMaxFloatFloat(HInvoke* invoke) {
Mark P Mendell2f10a5f2016-01-25 14:47:50 +0000548 GenMinMaxFP(invoke->GetLocations(),
549 /* is_min */ false,
550 /* is_double */ false,
551 GetAssembler(),
552 codegen_);
Mark Mendell09ed1a32015-03-25 08:30:06 -0400553}
554
555static void GenMinMax(LocationSummary* locations, bool is_min, bool is_long,
556 X86Assembler* assembler) {
557 Location op1_loc = locations->InAt(0);
558 Location op2_loc = locations->InAt(1);
559
560 // Shortcut for same input locations.
561 if (op1_loc.Equals(op2_loc)) {
562 // Can return immediately, as op1_loc == out_loc.
563 // Note: if we ever support separate registers, e.g., output into memory, we need to check for
564 // a copy here.
565 DCHECK(locations->Out().Equals(op1_loc));
566 return;
567 }
568
569 if (is_long) {
570 // Need to perform a subtract to get the sign right.
571 // op1 is already in the same location as the output.
572 Location output = locations->Out();
573 Register output_lo = output.AsRegisterPairLow<Register>();
574 Register output_hi = output.AsRegisterPairHigh<Register>();
575
576 Register op2_lo = op2_loc.AsRegisterPairLow<Register>();
577 Register op2_hi = op2_loc.AsRegisterPairHigh<Register>();
578
579 // Spare register to compute the subtraction to set condition code.
580 Register temp = locations->GetTemp(0).AsRegister<Register>();
581
582 // Subtract off op2_low.
583 __ movl(temp, output_lo);
584 __ subl(temp, op2_lo);
585
586 // Now use the same tempo and the borrow to finish the subtraction of op2_hi.
587 __ movl(temp, output_hi);
588 __ sbbl(temp, op2_hi);
589
590 // Now the condition code is correct.
591 Condition cond = is_min ? Condition::kGreaterEqual : Condition::kLess;
592 __ cmovl(cond, output_lo, op2_lo);
593 __ cmovl(cond, output_hi, op2_hi);
594 } else {
595 Register out = locations->Out().AsRegister<Register>();
596 Register op2 = op2_loc.AsRegister<Register>();
597
598 // (out := op1)
599 // out <=? op2
600 // if out is min jmp done
601 // out := op2
602 // done:
603
604 __ cmpl(out, op2);
605 Condition cond = is_min ? Condition::kGreater : Condition::kLess;
606 __ cmovl(cond, out, op2);
607 }
608}
609
610static void CreateIntIntToIntLocations(ArenaAllocator* arena, HInvoke* invoke) {
611 LocationSummary* locations = new (arena) LocationSummary(invoke,
612 LocationSummary::kNoCall,
613 kIntrinsified);
614 locations->SetInAt(0, Location::RequiresRegister());
615 locations->SetInAt(1, Location::RequiresRegister());
616 locations->SetOut(Location::SameAsFirstInput());
617}
618
619static void CreateLongLongToLongLocations(ArenaAllocator* arena, HInvoke* invoke) {
620 LocationSummary* locations = new (arena) LocationSummary(invoke,
621 LocationSummary::kNoCall,
622 kIntrinsified);
623 locations->SetInAt(0, Location::RequiresRegister());
624 locations->SetInAt(1, Location::RequiresRegister());
625 locations->SetOut(Location::SameAsFirstInput());
626 // Register to use to perform a long subtract to set cc.
627 locations->AddTemp(Location::RequiresRegister());
628}
629
630void IntrinsicLocationsBuilderX86::VisitMathMinIntInt(HInvoke* invoke) {
631 CreateIntIntToIntLocations(arena_, invoke);
632}
633
634void IntrinsicCodeGeneratorX86::VisitMathMinIntInt(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +0000635 GenMinMax(invoke->GetLocations(), /* is_min */ true, /* is_long */ false, GetAssembler());
Mark Mendell09ed1a32015-03-25 08:30:06 -0400636}
637
638void IntrinsicLocationsBuilderX86::VisitMathMinLongLong(HInvoke* invoke) {
639 CreateLongLongToLongLocations(arena_, invoke);
640}
641
642void IntrinsicCodeGeneratorX86::VisitMathMinLongLong(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +0000643 GenMinMax(invoke->GetLocations(), /* is_min */ true, /* is_long */ true, GetAssembler());
Mark Mendell09ed1a32015-03-25 08:30:06 -0400644}
645
646void IntrinsicLocationsBuilderX86::VisitMathMaxIntInt(HInvoke* invoke) {
647 CreateIntIntToIntLocations(arena_, invoke);
648}
649
650void IntrinsicCodeGeneratorX86::VisitMathMaxIntInt(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +0000651 GenMinMax(invoke->GetLocations(), /* is_min */ false, /* is_long */ false, GetAssembler());
Mark Mendell09ed1a32015-03-25 08:30:06 -0400652}
653
654void IntrinsicLocationsBuilderX86::VisitMathMaxLongLong(HInvoke* invoke) {
655 CreateLongLongToLongLocations(arena_, invoke);
656}
657
658void IntrinsicCodeGeneratorX86::VisitMathMaxLongLong(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +0000659 GenMinMax(invoke->GetLocations(), /* is_min */ false, /* is_long */ true, GetAssembler());
Mark Mendell09ed1a32015-03-25 08:30:06 -0400660}
661
662static void CreateFPToFPLocations(ArenaAllocator* arena, HInvoke* invoke) {
663 LocationSummary* locations = new (arena) LocationSummary(invoke,
664 LocationSummary::kNoCall,
665 kIntrinsified);
666 locations->SetInAt(0, Location::RequiresFpuRegister());
667 locations->SetOut(Location::RequiresFpuRegister());
668}
669
670void IntrinsicLocationsBuilderX86::VisitMathSqrt(HInvoke* invoke) {
671 CreateFPToFPLocations(arena_, invoke);
672}
673
674void IntrinsicCodeGeneratorX86::VisitMathSqrt(HInvoke* invoke) {
675 LocationSummary* locations = invoke->GetLocations();
676 XmmRegister in = locations->InAt(0).AsFpuRegister<XmmRegister>();
677 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
678
679 GetAssembler()->sqrtsd(out, in);
680}
681
Mark Mendellfb8d2792015-03-31 22:16:59 -0400682static void InvokeOutOfLineIntrinsic(CodeGeneratorX86* codegen, HInvoke* invoke) {
Roland Levillainec525fc2015-04-28 15:50:20 +0100683 MoveArguments(invoke, codegen);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400684
685 DCHECK(invoke->IsInvokeStaticOrDirect());
Nicolas Geoffray94015b92015-06-04 18:21:04 +0100686 codegen->GenerateStaticOrDirectCall(invoke->AsInvokeStaticOrDirect(),
687 Location::RegisterLocation(EAX));
Mingyao Yange90db122015-04-03 17:56:54 -0700688 codegen->RecordPcInfo(invoke, invoke->GetDexPc());
Mark Mendellfb8d2792015-03-31 22:16:59 -0400689
690 // Copy the result back to the expected output.
691 Location out = invoke->GetLocations()->Out();
692 if (out.IsValid()) {
693 DCHECK(out.IsRegister());
Andreas Gampe85b62f22015-09-09 13:15:38 -0700694 codegen->MoveFromReturnRegister(out, invoke->GetType());
Mark Mendellfb8d2792015-03-31 22:16:59 -0400695 }
696}
697
698static void CreateSSE41FPToFPLocations(ArenaAllocator* arena,
699 HInvoke* invoke,
700 CodeGeneratorX86* codegen) {
701 // Do we have instruction support?
702 if (codegen->GetInstructionSetFeatures().HasSSE4_1()) {
703 CreateFPToFPLocations(arena, invoke);
704 return;
705 }
706
707 // We have to fall back to a call to the intrinsic.
708 LocationSummary* locations = new (arena) LocationSummary(invoke,
709 LocationSummary::kCall);
710 InvokeRuntimeCallingConvention calling_convention;
711 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetFpuRegisterAt(0)));
712 locations->SetOut(Location::FpuRegisterLocation(XMM0));
713 // Needs to be EAX for the invoke.
714 locations->AddTemp(Location::RegisterLocation(EAX));
715}
716
717static void GenSSE41FPToFPIntrinsic(CodeGeneratorX86* codegen,
718 HInvoke* invoke,
719 X86Assembler* assembler,
720 int round_mode) {
721 LocationSummary* locations = invoke->GetLocations();
722 if (locations->WillCall()) {
723 InvokeOutOfLineIntrinsic(codegen, invoke);
724 } else {
725 XmmRegister in = locations->InAt(0).AsFpuRegister<XmmRegister>();
726 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
727 __ roundsd(out, in, Immediate(round_mode));
728 }
729}
730
731void IntrinsicLocationsBuilderX86::VisitMathCeil(HInvoke* invoke) {
732 CreateSSE41FPToFPLocations(arena_, invoke, codegen_);
733}
734
735void IntrinsicCodeGeneratorX86::VisitMathCeil(HInvoke* invoke) {
736 GenSSE41FPToFPIntrinsic(codegen_, invoke, GetAssembler(), 2);
737}
738
739void IntrinsicLocationsBuilderX86::VisitMathFloor(HInvoke* invoke) {
740 CreateSSE41FPToFPLocations(arena_, invoke, codegen_);
741}
742
743void IntrinsicCodeGeneratorX86::VisitMathFloor(HInvoke* invoke) {
744 GenSSE41FPToFPIntrinsic(codegen_, invoke, GetAssembler(), 1);
745}
746
747void IntrinsicLocationsBuilderX86::VisitMathRint(HInvoke* invoke) {
748 CreateSSE41FPToFPLocations(arena_, invoke, codegen_);
749}
750
751void IntrinsicCodeGeneratorX86::VisitMathRint(HInvoke* invoke) {
752 GenSSE41FPToFPIntrinsic(codegen_, invoke, GetAssembler(), 0);
753}
754
755// Note that 32 bit x86 doesn't have the capability to inline MathRoundDouble,
756// as it needs 64 bit instructions.
757void IntrinsicLocationsBuilderX86::VisitMathRoundFloat(HInvoke* invoke) {
Andreas Gampee6d0d8d2015-12-28 09:54:29 -0800758 // See intrinsics.h.
759 if (!kRoundIsPlusPointFive) {
760 return;
761 }
762
Mark Mendellfb8d2792015-03-31 22:16:59 -0400763 // Do we have instruction support?
764 if (codegen_->GetInstructionSetFeatures().HasSSE4_1()) {
765 LocationSummary* locations = new (arena_) LocationSummary(invoke,
766 LocationSummary::kNoCall,
767 kIntrinsified);
768 locations->SetInAt(0, Location::RequiresFpuRegister());
Nicolas Geoffrayd9b92402015-04-21 10:02:22 +0100769 locations->SetOut(Location::RequiresRegister());
Mark Mendellfb8d2792015-03-31 22:16:59 -0400770 locations->AddTemp(Location::RequiresFpuRegister());
771 locations->AddTemp(Location::RequiresFpuRegister());
772 return;
773 }
774
775 // We have to fall back to a call to the intrinsic.
776 LocationSummary* locations = new (arena_) LocationSummary(invoke,
777 LocationSummary::kCall);
778 InvokeRuntimeCallingConvention calling_convention;
779 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetFpuRegisterAt(0)));
780 locations->SetOut(Location::RegisterLocation(EAX));
781 // Needs to be EAX for the invoke.
782 locations->AddTemp(Location::RegisterLocation(EAX));
783}
784
785void IntrinsicCodeGeneratorX86::VisitMathRoundFloat(HInvoke* invoke) {
786 LocationSummary* locations = invoke->GetLocations();
787 if (locations->WillCall()) {
788 InvokeOutOfLineIntrinsic(codegen_, invoke);
789 return;
790 }
791
792 // Implement RoundFloat as t1 = floor(input + 0.5f); convert to int.
793 XmmRegister in = locations->InAt(0).AsFpuRegister<XmmRegister>();
794 Register out = locations->Out().AsRegister<Register>();
795 XmmRegister maxInt = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
796 XmmRegister inPlusPointFive = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
Mark Mendell0c9497d2015-08-21 09:30:05 -0400797 NearLabel done, nan;
Mark Mendellfb8d2792015-03-31 22:16:59 -0400798 X86Assembler* assembler = GetAssembler();
799
800 // Generate 0.5 into inPlusPointFive.
801 __ movl(out, Immediate(bit_cast<int32_t, float>(0.5f)));
802 __ movd(inPlusPointFive, out);
803
804 // Add in the input.
805 __ addss(inPlusPointFive, in);
806
807 // And truncate to an integer.
808 __ roundss(inPlusPointFive, inPlusPointFive, Immediate(1));
809
810 __ movl(out, Immediate(kPrimIntMax));
811 // maxInt = int-to-float(out)
812 __ cvtsi2ss(maxInt, out);
813
814 // if inPlusPointFive >= maxInt goto done
815 __ comiss(inPlusPointFive, maxInt);
816 __ j(kAboveEqual, &done);
817
818 // if input == NaN goto nan
819 __ j(kUnordered, &nan);
820
821 // output = float-to-int-truncate(input)
822 __ cvttss2si(out, inPlusPointFive);
823 __ jmp(&done);
824 __ Bind(&nan);
825
826 // output = 0
827 __ xorl(out, out);
828 __ Bind(&done);
829}
830
Mark Mendella4f12202015-08-06 15:23:34 -0400831static void CreateFPToFPCallLocations(ArenaAllocator* arena,
832 HInvoke* invoke) {
833 LocationSummary* locations = new (arena) LocationSummary(invoke,
834 LocationSummary::kCall,
835 kIntrinsified);
836 InvokeRuntimeCallingConvention calling_convention;
837 locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
838 locations->SetOut(Location::FpuRegisterLocation(XMM0));
839}
840
841static void GenFPToFPCall(HInvoke* invoke, CodeGeneratorX86* codegen, QuickEntrypointEnum entry) {
842 LocationSummary* locations = invoke->GetLocations();
843 DCHECK(locations->WillCall());
844 DCHECK(invoke->IsInvokeStaticOrDirect());
845 X86Assembler* assembler = codegen->GetAssembler();
846
847 // We need some place to pass the parameters.
848 __ subl(ESP, Immediate(16));
849 __ cfi().AdjustCFAOffset(16);
850
851 // Pass the parameters at the bottom of the stack.
852 __ movsd(Address(ESP, 0), XMM0);
853
854 // If we have a second parameter, pass it next.
855 if (invoke->GetNumberOfArguments() == 2) {
856 __ movsd(Address(ESP, 8), XMM1);
857 }
858
859 // Now do the actual call.
860 __ fs()->call(Address::Absolute(GetThreadOffset<kX86WordSize>(entry)));
861
862 // Extract the return value from the FP stack.
863 __ fstpl(Address(ESP, 0));
864 __ movsd(XMM0, Address(ESP, 0));
865
866 // And clean up the stack.
867 __ addl(ESP, Immediate(16));
868 __ cfi().AdjustCFAOffset(-16);
869
870 codegen->RecordPcInfo(invoke, invoke->GetDexPc());
871}
872
873void IntrinsicLocationsBuilderX86::VisitMathCos(HInvoke* invoke) {
874 CreateFPToFPCallLocations(arena_, invoke);
875}
876
877void IntrinsicCodeGeneratorX86::VisitMathCos(HInvoke* invoke) {
878 GenFPToFPCall(invoke, codegen_, kQuickCos);
879}
880
881void IntrinsicLocationsBuilderX86::VisitMathSin(HInvoke* invoke) {
882 CreateFPToFPCallLocations(arena_, invoke);
883}
884
885void IntrinsicCodeGeneratorX86::VisitMathSin(HInvoke* invoke) {
886 GenFPToFPCall(invoke, codegen_, kQuickSin);
887}
888
889void IntrinsicLocationsBuilderX86::VisitMathAcos(HInvoke* invoke) {
890 CreateFPToFPCallLocations(arena_, invoke);
891}
892
893void IntrinsicCodeGeneratorX86::VisitMathAcos(HInvoke* invoke) {
894 GenFPToFPCall(invoke, codegen_, kQuickAcos);
895}
896
897void IntrinsicLocationsBuilderX86::VisitMathAsin(HInvoke* invoke) {
898 CreateFPToFPCallLocations(arena_, invoke);
899}
900
901void IntrinsicCodeGeneratorX86::VisitMathAsin(HInvoke* invoke) {
902 GenFPToFPCall(invoke, codegen_, kQuickAsin);
903}
904
905void IntrinsicLocationsBuilderX86::VisitMathAtan(HInvoke* invoke) {
906 CreateFPToFPCallLocations(arena_, invoke);
907}
908
909void IntrinsicCodeGeneratorX86::VisitMathAtan(HInvoke* invoke) {
910 GenFPToFPCall(invoke, codegen_, kQuickAtan);
911}
912
913void IntrinsicLocationsBuilderX86::VisitMathCbrt(HInvoke* invoke) {
914 CreateFPToFPCallLocations(arena_, invoke);
915}
916
917void IntrinsicCodeGeneratorX86::VisitMathCbrt(HInvoke* invoke) {
918 GenFPToFPCall(invoke, codegen_, kQuickCbrt);
919}
920
921void IntrinsicLocationsBuilderX86::VisitMathCosh(HInvoke* invoke) {
922 CreateFPToFPCallLocations(arena_, invoke);
923}
924
925void IntrinsicCodeGeneratorX86::VisitMathCosh(HInvoke* invoke) {
926 GenFPToFPCall(invoke, codegen_, kQuickCosh);
927}
928
929void IntrinsicLocationsBuilderX86::VisitMathExp(HInvoke* invoke) {
930 CreateFPToFPCallLocations(arena_, invoke);
931}
932
933void IntrinsicCodeGeneratorX86::VisitMathExp(HInvoke* invoke) {
934 GenFPToFPCall(invoke, codegen_, kQuickExp);
935}
936
937void IntrinsicLocationsBuilderX86::VisitMathExpm1(HInvoke* invoke) {
938 CreateFPToFPCallLocations(arena_, invoke);
939}
940
941void IntrinsicCodeGeneratorX86::VisitMathExpm1(HInvoke* invoke) {
942 GenFPToFPCall(invoke, codegen_, kQuickExpm1);
943}
944
945void IntrinsicLocationsBuilderX86::VisitMathLog(HInvoke* invoke) {
946 CreateFPToFPCallLocations(arena_, invoke);
947}
948
949void IntrinsicCodeGeneratorX86::VisitMathLog(HInvoke* invoke) {
950 GenFPToFPCall(invoke, codegen_, kQuickLog);
951}
952
953void IntrinsicLocationsBuilderX86::VisitMathLog10(HInvoke* invoke) {
954 CreateFPToFPCallLocations(arena_, invoke);
955}
956
957void IntrinsicCodeGeneratorX86::VisitMathLog10(HInvoke* invoke) {
958 GenFPToFPCall(invoke, codegen_, kQuickLog10);
959}
960
961void IntrinsicLocationsBuilderX86::VisitMathSinh(HInvoke* invoke) {
962 CreateFPToFPCallLocations(arena_, invoke);
963}
964
965void IntrinsicCodeGeneratorX86::VisitMathSinh(HInvoke* invoke) {
966 GenFPToFPCall(invoke, codegen_, kQuickSinh);
967}
968
969void IntrinsicLocationsBuilderX86::VisitMathTan(HInvoke* invoke) {
970 CreateFPToFPCallLocations(arena_, invoke);
971}
972
973void IntrinsicCodeGeneratorX86::VisitMathTan(HInvoke* invoke) {
974 GenFPToFPCall(invoke, codegen_, kQuickTan);
975}
976
977void IntrinsicLocationsBuilderX86::VisitMathTanh(HInvoke* invoke) {
978 CreateFPToFPCallLocations(arena_, invoke);
979}
980
981void IntrinsicCodeGeneratorX86::VisitMathTanh(HInvoke* invoke) {
982 GenFPToFPCall(invoke, codegen_, kQuickTanh);
983}
984
985static void CreateFPFPToFPCallLocations(ArenaAllocator* arena,
986 HInvoke* invoke) {
987 LocationSummary* locations = new (arena) LocationSummary(invoke,
988 LocationSummary::kCall,
989 kIntrinsified);
990 InvokeRuntimeCallingConvention calling_convention;
991 locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
992 locations->SetInAt(1, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(1)));
993 locations->SetOut(Location::FpuRegisterLocation(XMM0));
994}
995
996void IntrinsicLocationsBuilderX86::VisitMathAtan2(HInvoke* invoke) {
997 CreateFPFPToFPCallLocations(arena_, invoke);
998}
999
1000void IntrinsicCodeGeneratorX86::VisitMathAtan2(HInvoke* invoke) {
1001 GenFPToFPCall(invoke, codegen_, kQuickAtan2);
1002}
1003
1004void IntrinsicLocationsBuilderX86::VisitMathHypot(HInvoke* invoke) {
1005 CreateFPFPToFPCallLocations(arena_, invoke);
1006}
1007
1008void IntrinsicCodeGeneratorX86::VisitMathHypot(HInvoke* invoke) {
1009 GenFPToFPCall(invoke, codegen_, kQuickHypot);
1010}
1011
1012void IntrinsicLocationsBuilderX86::VisitMathNextAfter(HInvoke* invoke) {
1013 CreateFPFPToFPCallLocations(arena_, invoke);
1014}
1015
1016void IntrinsicCodeGeneratorX86::VisitMathNextAfter(HInvoke* invoke) {
1017 GenFPToFPCall(invoke, codegen_, kQuickNextAfter);
1018}
1019
Mark Mendell09ed1a32015-03-25 08:30:06 -04001020void IntrinsicLocationsBuilderX86::VisitStringCharAt(HInvoke* invoke) {
1021 // The inputs plus one temp.
1022 LocationSummary* locations = new (arena_) LocationSummary(invoke,
1023 LocationSummary::kCallOnSlowPath,
1024 kIntrinsified);
1025 locations->SetInAt(0, Location::RequiresRegister());
1026 locations->SetInAt(1, Location::RequiresRegister());
1027 locations->SetOut(Location::SameAsFirstInput());
Mark Mendell09ed1a32015-03-25 08:30:06 -04001028}
1029
1030void IntrinsicCodeGeneratorX86::VisitStringCharAt(HInvoke* invoke) {
1031 LocationSummary* locations = invoke->GetLocations();
1032
Mark Mendell6bc53a92015-07-01 14:26:52 -04001033 // Location of reference to data array.
Mark Mendell09ed1a32015-03-25 08:30:06 -04001034 const int32_t value_offset = mirror::String::ValueOffset().Int32Value();
Mark Mendell6bc53a92015-07-01 14:26:52 -04001035 // Location of count.
Mark Mendell09ed1a32015-03-25 08:30:06 -04001036 const int32_t count_offset = mirror::String::CountOffset().Int32Value();
Mark Mendell09ed1a32015-03-25 08:30:06 -04001037
1038 Register obj = locations->InAt(0).AsRegister<Register>();
1039 Register idx = locations->InAt(1).AsRegister<Register>();
1040 Register out = locations->Out().AsRegister<Register>();
Mark Mendell09ed1a32015-03-25 08:30:06 -04001041
1042 // TODO: Maybe we can support range check elimination. Overall, though, I think it's not worth
1043 // the cost.
1044 // TODO: For simplicity, the index parameter is requested in a register, so different from Quick
1045 // we will not optimize the code for constants (which would save a register).
1046
Andreas Gampe85b62f22015-09-09 13:15:38 -07001047 SlowPathCode* slow_path = new (GetAllocator()) IntrinsicSlowPathX86(invoke);
Mark Mendell09ed1a32015-03-25 08:30:06 -04001048 codegen_->AddSlowPath(slow_path);
1049
1050 X86Assembler* assembler = GetAssembler();
1051
1052 __ cmpl(idx, Address(obj, count_offset));
1053 codegen_->MaybeRecordImplicitNullCheck(invoke);
1054 __ j(kAboveEqual, slow_path->GetEntryLabel());
1055
Jeff Hao848f70a2014-01-15 13:49:50 -08001056 // out = out[2*idx].
1057 __ movzxw(out, Address(out, idx, ScaleFactor::TIMES_2, value_offset));
Mark Mendell09ed1a32015-03-25 08:30:06 -04001058
1059 __ Bind(slow_path->GetExitLabel());
1060}
1061
Mark Mendell6bc53a92015-07-01 14:26:52 -04001062void IntrinsicLocationsBuilderX86::VisitSystemArrayCopyChar(HInvoke* invoke) {
1063 // We need at least two of the positions or length to be an integer constant,
1064 // or else we won't have enough free registers.
1065 HIntConstant* src_pos = invoke->InputAt(1)->AsIntConstant();
1066 HIntConstant* dest_pos = invoke->InputAt(3)->AsIntConstant();
1067 HIntConstant* length = invoke->InputAt(4)->AsIntConstant();
1068
1069 int num_constants =
1070 ((src_pos != nullptr) ? 1 : 0)
1071 + ((dest_pos != nullptr) ? 1 : 0)
1072 + ((length != nullptr) ? 1 : 0);
1073
1074 if (num_constants < 2) {
1075 // Not enough free registers.
1076 return;
1077 }
1078
1079 // As long as we are checking, we might as well check to see if the src and dest
1080 // positions are >= 0.
1081 if ((src_pos != nullptr && src_pos->GetValue() < 0) ||
1082 (dest_pos != nullptr && dest_pos->GetValue() < 0)) {
1083 // We will have to fail anyways.
1084 return;
1085 }
1086
1087 // And since we are already checking, check the length too.
1088 if (length != nullptr) {
1089 int32_t len = length->GetValue();
1090 if (len < 0) {
1091 // Just call as normal.
1092 return;
1093 }
1094 }
1095
1096 // Okay, it is safe to generate inline code.
1097 LocationSummary* locations =
1098 new (arena_) LocationSummary(invoke, LocationSummary::kCallOnSlowPath, kIntrinsified);
1099 // arraycopy(Object src, int srcPos, Object dest, int destPos, int length).
1100 locations->SetInAt(0, Location::RequiresRegister());
1101 locations->SetInAt(1, Location::RegisterOrConstant(invoke->InputAt(1)));
1102 locations->SetInAt(2, Location::RequiresRegister());
1103 locations->SetInAt(3, Location::RegisterOrConstant(invoke->InputAt(3)));
1104 locations->SetInAt(4, Location::RegisterOrConstant(invoke->InputAt(4)));
1105
1106 // And we need some temporaries. We will use REP MOVSW, so we need fixed registers.
1107 locations->AddTemp(Location::RegisterLocation(ESI));
1108 locations->AddTemp(Location::RegisterLocation(EDI));
1109 locations->AddTemp(Location::RegisterLocation(ECX));
1110}
1111
1112static void CheckPosition(X86Assembler* assembler,
1113 Location pos,
1114 Register input,
1115 Register length,
Andreas Gampe85b62f22015-09-09 13:15:38 -07001116 SlowPathCode* slow_path,
Mark Mendell6bc53a92015-07-01 14:26:52 -04001117 Register input_len,
1118 Register temp) {
1119 // Where is the length in the String?
1120 const uint32_t length_offset = mirror::Array::LengthOffset().Uint32Value();
1121
1122 if (pos.IsConstant()) {
1123 int32_t pos_const = pos.GetConstant()->AsIntConstant()->GetValue();
1124 if (pos_const == 0) {
1125 // Check that length(input) >= length.
1126 __ cmpl(Address(input, length_offset), length);
1127 __ j(kLess, slow_path->GetEntryLabel());
1128 } else {
1129 // Check that length(input) >= pos.
1130 __ movl(input_len, Address(input, length_offset));
1131 __ cmpl(input_len, Immediate(pos_const));
1132 __ j(kLess, slow_path->GetEntryLabel());
1133
1134 // Check that (length(input) - pos) >= length.
1135 __ leal(temp, Address(input_len, -pos_const));
1136 __ cmpl(temp, length);
1137 __ j(kLess, slow_path->GetEntryLabel());
1138 }
1139 } else {
1140 // Check that pos >= 0.
1141 Register pos_reg = pos.AsRegister<Register>();
1142 __ testl(pos_reg, pos_reg);
1143 __ j(kLess, slow_path->GetEntryLabel());
1144
1145 // Check that pos <= length(input).
1146 __ cmpl(Address(input, length_offset), pos_reg);
1147 __ j(kLess, slow_path->GetEntryLabel());
1148
1149 // Check that (length(input) - pos) >= length.
1150 __ movl(temp, Address(input, length_offset));
1151 __ subl(temp, pos_reg);
1152 __ cmpl(temp, length);
1153 __ j(kLess, slow_path->GetEntryLabel());
1154 }
1155}
1156
1157void IntrinsicCodeGeneratorX86::VisitSystemArrayCopyChar(HInvoke* invoke) {
1158 X86Assembler* assembler = GetAssembler();
1159 LocationSummary* locations = invoke->GetLocations();
1160
1161 Register src = locations->InAt(0).AsRegister<Register>();
1162 Location srcPos = locations->InAt(1);
1163 Register dest = locations->InAt(2).AsRegister<Register>();
1164 Location destPos = locations->InAt(3);
1165 Location length = locations->InAt(4);
1166
1167 // Temporaries that we need for MOVSW.
1168 Register src_base = locations->GetTemp(0).AsRegister<Register>();
1169 DCHECK_EQ(src_base, ESI);
1170 Register dest_base = locations->GetTemp(1).AsRegister<Register>();
1171 DCHECK_EQ(dest_base, EDI);
1172 Register count = locations->GetTemp(2).AsRegister<Register>();
1173 DCHECK_EQ(count, ECX);
1174
Andreas Gampe85b62f22015-09-09 13:15:38 -07001175 SlowPathCode* slow_path = new (GetAllocator()) IntrinsicSlowPathX86(invoke);
Mark Mendell6bc53a92015-07-01 14:26:52 -04001176 codegen_->AddSlowPath(slow_path);
1177
1178 // Bail out if the source and destination are the same (to handle overlap).
1179 __ cmpl(src, dest);
1180 __ j(kEqual, slow_path->GetEntryLabel());
1181
1182 // Bail out if the source is null.
1183 __ testl(src, src);
1184 __ j(kEqual, slow_path->GetEntryLabel());
1185
1186 // Bail out if the destination is null.
1187 __ testl(dest, dest);
1188 __ j(kEqual, slow_path->GetEntryLabel());
1189
1190 // If the length is negative, bail out.
1191 // We have already checked in the LocationsBuilder for the constant case.
1192 if (!length.IsConstant()) {
1193 __ cmpl(length.AsRegister<Register>(), length.AsRegister<Register>());
1194 __ j(kLess, slow_path->GetEntryLabel());
1195 }
1196
1197 // We need the count in ECX.
1198 if (length.IsConstant()) {
1199 __ movl(count, Immediate(length.GetConstant()->AsIntConstant()->GetValue()));
1200 } else {
1201 __ movl(count, length.AsRegister<Register>());
1202 }
1203
1204 // Validity checks: source.
1205 CheckPosition(assembler, srcPos, src, count, slow_path, src_base, dest_base);
1206
1207 // Validity checks: dest.
1208 CheckPosition(assembler, destPos, dest, count, slow_path, src_base, dest_base);
1209
1210 // Okay, everything checks out. Finally time to do the copy.
1211 // Check assumption that sizeof(Char) is 2 (used in scaling below).
1212 const size_t char_size = Primitive::ComponentSize(Primitive::kPrimChar);
1213 DCHECK_EQ(char_size, 2u);
1214
1215 const uint32_t data_offset = mirror::Array::DataOffset(char_size).Uint32Value();
1216
1217 if (srcPos.IsConstant()) {
1218 int32_t srcPos_const = srcPos.GetConstant()->AsIntConstant()->GetValue();
1219 __ leal(src_base, Address(src, char_size * srcPos_const + data_offset));
1220 } else {
1221 __ leal(src_base, Address(src, srcPos.AsRegister<Register>(),
1222 ScaleFactor::TIMES_2, data_offset));
1223 }
1224 if (destPos.IsConstant()) {
1225 int32_t destPos_const = destPos.GetConstant()->AsIntConstant()->GetValue();
1226
1227 __ leal(dest_base, Address(dest, char_size * destPos_const + data_offset));
1228 } else {
1229 __ leal(dest_base, Address(dest, destPos.AsRegister<Register>(),
1230 ScaleFactor::TIMES_2, data_offset));
1231 }
1232
1233 // Do the move.
1234 __ rep_movsw();
1235
1236 __ Bind(slow_path->GetExitLabel());
1237}
1238
Nicolas Geoffrayd75948a2015-03-27 09:53:16 +00001239void IntrinsicLocationsBuilderX86::VisitStringCompareTo(HInvoke* invoke) {
1240 // The inputs plus one temp.
1241 LocationSummary* locations = new (arena_) LocationSummary(invoke,
1242 LocationSummary::kCall,
1243 kIntrinsified);
1244 InvokeRuntimeCallingConvention calling_convention;
1245 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
1246 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
1247 locations->SetOut(Location::RegisterLocation(EAX));
Nicolas Geoffrayd75948a2015-03-27 09:53:16 +00001248}
1249
1250void IntrinsicCodeGeneratorX86::VisitStringCompareTo(HInvoke* invoke) {
1251 X86Assembler* assembler = GetAssembler();
1252 LocationSummary* locations = invoke->GetLocations();
1253
Nicolas Geoffray512e04d2015-03-27 17:21:24 +00001254 // Note that the null check must have been done earlier.
Calin Juravle641547a2015-04-21 22:08:51 +01001255 DCHECK(!invoke->CanDoImplicitNullCheckOn(invoke->InputAt(0)));
Nicolas Geoffrayd75948a2015-03-27 09:53:16 +00001256
1257 Register argument = locations->InAt(1).AsRegister<Register>();
1258 __ testl(argument, argument);
Andreas Gampe85b62f22015-09-09 13:15:38 -07001259 SlowPathCode* slow_path = new (GetAllocator()) IntrinsicSlowPathX86(invoke);
Nicolas Geoffrayd75948a2015-03-27 09:53:16 +00001260 codegen_->AddSlowPath(slow_path);
1261 __ j(kEqual, slow_path->GetEntryLabel());
1262
1263 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pStringCompareTo)));
1264 __ Bind(slow_path->GetExitLabel());
1265}
1266
Agi Csakid7138c82015-08-13 17:46:44 -07001267void IntrinsicLocationsBuilderX86::VisitStringEquals(HInvoke* invoke) {
1268 LocationSummary* locations = new (arena_) LocationSummary(invoke,
1269 LocationSummary::kNoCall,
1270 kIntrinsified);
1271 locations->SetInAt(0, Location::RequiresRegister());
1272 locations->SetInAt(1, Location::RequiresRegister());
1273
1274 // Request temporary registers, ECX and EDI needed for repe_cmpsl instruction.
1275 locations->AddTemp(Location::RegisterLocation(ECX));
1276 locations->AddTemp(Location::RegisterLocation(EDI));
1277
1278 // Set output, ESI needed for repe_cmpsl instruction anyways.
1279 locations->SetOut(Location::RegisterLocation(ESI), Location::kOutputOverlap);
1280}
1281
1282void IntrinsicCodeGeneratorX86::VisitStringEquals(HInvoke* invoke) {
1283 X86Assembler* assembler = GetAssembler();
1284 LocationSummary* locations = invoke->GetLocations();
1285
1286 Register str = locations->InAt(0).AsRegister<Register>();
1287 Register arg = locations->InAt(1).AsRegister<Register>();
1288 Register ecx = locations->GetTemp(0).AsRegister<Register>();
1289 Register edi = locations->GetTemp(1).AsRegister<Register>();
1290 Register esi = locations->Out().AsRegister<Register>();
1291
Mark Mendell0c9497d2015-08-21 09:30:05 -04001292 NearLabel end, return_true, return_false;
Agi Csakid7138c82015-08-13 17:46:44 -07001293
1294 // Get offsets of count, value, and class fields within a string object.
1295 const uint32_t count_offset = mirror::String::CountOffset().Uint32Value();
1296 const uint32_t value_offset = mirror::String::ValueOffset().Uint32Value();
1297 const uint32_t class_offset = mirror::Object::ClassOffset().Uint32Value();
1298
1299 // Note that the null check must have been done earlier.
1300 DCHECK(!invoke->CanDoImplicitNullCheckOn(invoke->InputAt(0)));
1301
Nicolas Geoffraya83a54d2015-10-02 17:30:26 +01001302 StringEqualsOptimizations optimizations(invoke);
1303 if (!optimizations.GetArgumentNotNull()) {
1304 // Check if input is null, return false if it is.
1305 __ testl(arg, arg);
1306 __ j(kEqual, &return_false);
1307 }
Agi Csakid7138c82015-08-13 17:46:44 -07001308
Nicolas Geoffraya83a54d2015-10-02 17:30:26 +01001309 if (!optimizations.GetArgumentIsString()) {
Vladimir Marko53b52002016-05-24 19:30:45 +01001310 // Instanceof check for the argument by comparing class fields.
1311 // All string objects must have the same type since String cannot be subclassed.
1312 // Receiver must be a string object, so its class field is equal to all strings' class fields.
1313 // If the argument is a string object, its class field must be equal to receiver's class field.
Nicolas Geoffraya83a54d2015-10-02 17:30:26 +01001314 __ movl(ecx, Address(str, class_offset));
1315 __ cmpl(ecx, Address(arg, class_offset));
1316 __ j(kNotEqual, &return_false);
1317 }
Agi Csakid7138c82015-08-13 17:46:44 -07001318
1319 // Reference equality check, return true if same reference.
1320 __ cmpl(str, arg);
1321 __ j(kEqual, &return_true);
1322
1323 // Load length of receiver string.
1324 __ movl(ecx, Address(str, count_offset));
1325 // Check if lengths are equal, return false if they're not.
1326 __ cmpl(ecx, Address(arg, count_offset));
1327 __ j(kNotEqual, &return_false);
1328 // Return true if both strings are empty.
Mark Mendell0c9497d2015-08-21 09:30:05 -04001329 __ jecxz(&return_true);
Agi Csakid7138c82015-08-13 17:46:44 -07001330
1331 // Load starting addresses of string values into ESI/EDI as required for repe_cmpsl instruction.
1332 __ leal(esi, Address(str, value_offset));
1333 __ leal(edi, Address(arg, value_offset));
1334
1335 // Divide string length by 2 to compare characters 2 at a time and adjust for odd lengths.
1336 __ addl(ecx, Immediate(1));
1337 __ shrl(ecx, Immediate(1));
1338
1339 // Assertions that must hold in order to compare strings 2 characters at a time.
1340 DCHECK_ALIGNED(value_offset, 4);
1341 static_assert(IsAligned<4>(kObjectAlignment), "String of odd length is not zero padded");
1342
1343 // Loop to compare strings two characters at a time starting at the beginning of the string.
1344 __ repe_cmpsl();
1345 // If strings are not equal, zero flag will be cleared.
1346 __ j(kNotEqual, &return_false);
1347
1348 // Return true and exit the function.
1349 // If loop does not result in returning false, we return true.
1350 __ Bind(&return_true);
1351 __ movl(esi, Immediate(1));
1352 __ jmp(&end);
1353
1354 // Return false and exit the function.
1355 __ Bind(&return_false);
1356 __ xorl(esi, esi);
1357 __ Bind(&end);
1358}
1359
Andreas Gampe21030dd2015-05-07 14:46:15 -07001360static void CreateStringIndexOfLocations(HInvoke* invoke,
1361 ArenaAllocator* allocator,
1362 bool start_at_zero) {
1363 LocationSummary* locations = new (allocator) LocationSummary(invoke,
1364 LocationSummary::kCallOnSlowPath,
1365 kIntrinsified);
1366 // The data needs to be in EDI for scasw. So request that the string is there, anyways.
1367 locations->SetInAt(0, Location::RegisterLocation(EDI));
1368 // If we look for a constant char, we'll still have to copy it into EAX. So just request the
1369 // allocator to do that, anyways. We can still do the constant check by checking the parameter
1370 // of the instruction explicitly.
1371 // Note: This works as we don't clobber EAX anywhere.
1372 locations->SetInAt(1, Location::RegisterLocation(EAX));
1373 if (!start_at_zero) {
1374 locations->SetInAt(2, Location::RequiresRegister()); // The starting index.
1375 }
1376 // As we clobber EDI during execution anyways, also use it as the output.
1377 locations->SetOut(Location::SameAsFirstInput());
1378
1379 // repne scasw uses ECX as the counter.
1380 locations->AddTemp(Location::RegisterLocation(ECX));
1381 // Need another temporary to be able to compute the result.
1382 locations->AddTemp(Location::RequiresRegister());
1383}
1384
1385static void GenerateStringIndexOf(HInvoke* invoke,
1386 X86Assembler* assembler,
1387 CodeGeneratorX86* codegen,
1388 ArenaAllocator* allocator,
1389 bool start_at_zero) {
1390 LocationSummary* locations = invoke->GetLocations();
1391
1392 // Note that the null check must have been done earlier.
1393 DCHECK(!invoke->CanDoImplicitNullCheckOn(invoke->InputAt(0)));
1394
1395 Register string_obj = locations->InAt(0).AsRegister<Register>();
1396 Register search_value = locations->InAt(1).AsRegister<Register>();
1397 Register counter = locations->GetTemp(0).AsRegister<Register>();
1398 Register string_length = locations->GetTemp(1).AsRegister<Register>();
1399 Register out = locations->Out().AsRegister<Register>();
1400
1401 // Check our assumptions for registers.
1402 DCHECK_EQ(string_obj, EDI);
1403 DCHECK_EQ(search_value, EAX);
1404 DCHECK_EQ(counter, ECX);
1405 DCHECK_EQ(out, EDI);
1406
1407 // Check for code points > 0xFFFF. Either a slow-path check when we don't know statically,
Vladimir Markofb6c90a2016-05-06 15:52:12 +01001408 // or directly dispatch for a large constant, or omit slow-path for a small constant or a char.
Andreas Gampe85b62f22015-09-09 13:15:38 -07001409 SlowPathCode* slow_path = nullptr;
Vladimir Markofb6c90a2016-05-06 15:52:12 +01001410 HInstruction* code_point = invoke->InputAt(1);
1411 if (code_point->IsIntConstant()) {
Vladimir Markoda051082016-05-17 16:10:20 +01001412 if (static_cast<uint32_t>(code_point->AsIntConstant()->GetValue()) >
Andreas Gampe21030dd2015-05-07 14:46:15 -07001413 std::numeric_limits<uint16_t>::max()) {
1414 // Always needs the slow-path. We could directly dispatch to it, but this case should be
1415 // rare, so for simplicity just put the full slow-path down and branch unconditionally.
1416 slow_path = new (allocator) IntrinsicSlowPathX86(invoke);
1417 codegen->AddSlowPath(slow_path);
1418 __ jmp(slow_path->GetEntryLabel());
1419 __ Bind(slow_path->GetExitLabel());
1420 return;
1421 }
Vladimir Markofb6c90a2016-05-06 15:52:12 +01001422 } else if (code_point->GetType() != Primitive::kPrimChar) {
Andreas Gampe21030dd2015-05-07 14:46:15 -07001423 __ cmpl(search_value, Immediate(std::numeric_limits<uint16_t>::max()));
1424 slow_path = new (allocator) IntrinsicSlowPathX86(invoke);
1425 codegen->AddSlowPath(slow_path);
1426 __ j(kAbove, slow_path->GetEntryLabel());
1427 }
1428
1429 // From here down, we know that we are looking for a char that fits in 16 bits.
1430 // Location of reference to data array within the String object.
1431 int32_t value_offset = mirror::String::ValueOffset().Int32Value();
1432 // Location of count within the String object.
1433 int32_t count_offset = mirror::String::CountOffset().Int32Value();
1434
1435 // Load string length, i.e., the count field of the string.
1436 __ movl(string_length, Address(string_obj, count_offset));
1437
1438 // Do a zero-length check.
1439 // TODO: Support jecxz.
Mark Mendell0c9497d2015-08-21 09:30:05 -04001440 NearLabel not_found_label;
Andreas Gampe21030dd2015-05-07 14:46:15 -07001441 __ testl(string_length, string_length);
1442 __ j(kEqual, &not_found_label);
1443
1444 if (start_at_zero) {
1445 // Number of chars to scan is the same as the string length.
1446 __ movl(counter, string_length);
1447
1448 // Move to the start of the string.
1449 __ addl(string_obj, Immediate(value_offset));
1450 } else {
1451 Register start_index = locations->InAt(2).AsRegister<Register>();
1452
1453 // Do a start_index check.
1454 __ cmpl(start_index, string_length);
1455 __ j(kGreaterEqual, &not_found_label);
1456
1457 // Ensure we have a start index >= 0;
1458 __ xorl(counter, counter);
1459 __ cmpl(start_index, Immediate(0));
1460 __ cmovl(kGreater, counter, start_index);
1461
1462 // Move to the start of the string: string_obj + value_offset + 2 * start_index.
1463 __ leal(string_obj, Address(string_obj, counter, ScaleFactor::TIMES_2, value_offset));
1464
1465 // Now update ecx (the repne scasw work counter). We have string.length - start_index left to
1466 // compare.
1467 __ negl(counter);
1468 __ leal(counter, Address(string_length, counter, ScaleFactor::TIMES_1, 0));
1469 }
1470
1471 // Everything is set up for repne scasw:
1472 // * Comparison address in EDI.
1473 // * Counter in ECX.
1474 __ repne_scasw();
1475
1476 // Did we find a match?
1477 __ j(kNotEqual, &not_found_label);
1478
1479 // Yes, we matched. Compute the index of the result.
1480 __ subl(string_length, counter);
1481 __ leal(out, Address(string_length, -1));
1482
Mark Mendell0c9497d2015-08-21 09:30:05 -04001483 NearLabel done;
Andreas Gampe21030dd2015-05-07 14:46:15 -07001484 __ jmp(&done);
1485
1486 // Failed to match; return -1.
1487 __ Bind(&not_found_label);
1488 __ movl(out, Immediate(-1));
1489
1490 // And join up at the end.
1491 __ Bind(&done);
1492 if (slow_path != nullptr) {
1493 __ Bind(slow_path->GetExitLabel());
1494 }
1495}
1496
1497void IntrinsicLocationsBuilderX86::VisitStringIndexOf(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +00001498 CreateStringIndexOfLocations(invoke, arena_, /* start_at_zero */ true);
Andreas Gampe21030dd2015-05-07 14:46:15 -07001499}
1500
1501void IntrinsicCodeGeneratorX86::VisitStringIndexOf(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +00001502 GenerateStringIndexOf(invoke, GetAssembler(), codegen_, GetAllocator(), /* start_at_zero */ true);
Andreas Gampe21030dd2015-05-07 14:46:15 -07001503}
1504
1505void IntrinsicLocationsBuilderX86::VisitStringIndexOfAfter(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +00001506 CreateStringIndexOfLocations(invoke, arena_, /* start_at_zero */ false);
Andreas Gampe21030dd2015-05-07 14:46:15 -07001507}
1508
1509void IntrinsicCodeGeneratorX86::VisitStringIndexOfAfter(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +00001510 GenerateStringIndexOf(
1511 invoke, GetAssembler(), codegen_, GetAllocator(), /* start_at_zero */ false);
Andreas Gampe21030dd2015-05-07 14:46:15 -07001512}
1513
Jeff Hao848f70a2014-01-15 13:49:50 -08001514void IntrinsicLocationsBuilderX86::VisitStringNewStringFromBytes(HInvoke* invoke) {
1515 LocationSummary* locations = new (arena_) LocationSummary(invoke,
1516 LocationSummary::kCall,
1517 kIntrinsified);
1518 InvokeRuntimeCallingConvention calling_convention;
1519 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
1520 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
1521 locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
1522 locations->SetInAt(3, Location::RegisterLocation(calling_convention.GetRegisterAt(3)));
1523 locations->SetOut(Location::RegisterLocation(EAX));
Jeff Hao848f70a2014-01-15 13:49:50 -08001524}
1525
1526void IntrinsicCodeGeneratorX86::VisitStringNewStringFromBytes(HInvoke* invoke) {
1527 X86Assembler* assembler = GetAssembler();
1528 LocationSummary* locations = invoke->GetLocations();
1529
1530 Register byte_array = locations->InAt(0).AsRegister<Register>();
1531 __ testl(byte_array, byte_array);
Andreas Gampe85b62f22015-09-09 13:15:38 -07001532 SlowPathCode* slow_path = new (GetAllocator()) IntrinsicSlowPathX86(invoke);
Jeff Hao848f70a2014-01-15 13:49:50 -08001533 codegen_->AddSlowPath(slow_path);
1534 __ j(kEqual, slow_path->GetEntryLabel());
1535
1536 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pAllocStringFromBytes)));
Roland Levillainf969a202016-03-09 16:14:00 +00001537 CheckEntrypointTypes<kQuickAllocStringFromBytes, void*, void*, int32_t, int32_t, int32_t>();
Jeff Hao848f70a2014-01-15 13:49:50 -08001538 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1539 __ Bind(slow_path->GetExitLabel());
1540}
1541
1542void IntrinsicLocationsBuilderX86::VisitStringNewStringFromChars(HInvoke* invoke) {
1543 LocationSummary* locations = new (arena_) LocationSummary(invoke,
1544 LocationSummary::kCall,
1545 kIntrinsified);
1546 InvokeRuntimeCallingConvention calling_convention;
1547 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
1548 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
1549 locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
1550 locations->SetOut(Location::RegisterLocation(EAX));
1551}
1552
1553void IntrinsicCodeGeneratorX86::VisitStringNewStringFromChars(HInvoke* invoke) {
1554 X86Assembler* assembler = GetAssembler();
1555
Roland Levillaincc3839c2016-02-29 16:23:48 +00001556 // No need to emit code checking whether `locations->InAt(2)` is a null
1557 // pointer, as callers of the native method
1558 //
1559 // java.lang.StringFactory.newStringFromChars(int offset, int charCount, char[] data)
1560 //
1561 // all include a null check on `data` before calling that method.
Jeff Hao848f70a2014-01-15 13:49:50 -08001562 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pAllocStringFromChars)));
Roland Levillainf969a202016-03-09 16:14:00 +00001563 CheckEntrypointTypes<kQuickAllocStringFromChars, void*, int32_t, int32_t, void*>();
Jeff Hao848f70a2014-01-15 13:49:50 -08001564 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1565}
1566
1567void IntrinsicLocationsBuilderX86::VisitStringNewStringFromString(HInvoke* invoke) {
1568 LocationSummary* locations = new (arena_) LocationSummary(invoke,
1569 LocationSummary::kCall,
1570 kIntrinsified);
1571 InvokeRuntimeCallingConvention calling_convention;
1572 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
1573 locations->SetOut(Location::RegisterLocation(EAX));
Jeff Hao848f70a2014-01-15 13:49:50 -08001574}
1575
1576void IntrinsicCodeGeneratorX86::VisitStringNewStringFromString(HInvoke* invoke) {
1577 X86Assembler* assembler = GetAssembler();
1578 LocationSummary* locations = invoke->GetLocations();
1579
1580 Register string_to_copy = locations->InAt(0).AsRegister<Register>();
1581 __ testl(string_to_copy, string_to_copy);
Andreas Gampe85b62f22015-09-09 13:15:38 -07001582 SlowPathCode* slow_path = new (GetAllocator()) IntrinsicSlowPathX86(invoke);
Jeff Hao848f70a2014-01-15 13:49:50 -08001583 codegen_->AddSlowPath(slow_path);
1584 __ j(kEqual, slow_path->GetEntryLabel());
1585
1586 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pAllocStringFromString)));
Roland Levillainf969a202016-03-09 16:14:00 +00001587 CheckEntrypointTypes<kQuickAllocStringFromString, void*, void*>();
Jeff Hao848f70a2014-01-15 13:49:50 -08001588 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1589 __ Bind(slow_path->GetExitLabel());
1590}
1591
Mark Mendell8f8926a2015-08-17 11:39:06 -04001592void IntrinsicLocationsBuilderX86::VisitStringGetCharsNoCheck(HInvoke* invoke) {
1593 // public void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin);
1594 LocationSummary* locations = new (arena_) LocationSummary(invoke,
1595 LocationSummary::kNoCall,
1596 kIntrinsified);
1597 locations->SetInAt(0, Location::RequiresRegister());
1598 locations->SetInAt(1, Location::RegisterOrConstant(invoke->InputAt(1)));
1599 // Place srcEnd in ECX to save a move below.
1600 locations->SetInAt(2, Location::RegisterLocation(ECX));
1601 locations->SetInAt(3, Location::RequiresRegister());
1602 locations->SetInAt(4, Location::RequiresRegister());
1603
1604 // And we need some temporaries. We will use REP MOVSW, so we need fixed registers.
1605 // We don't have enough registers to also grab ECX, so handle below.
1606 locations->AddTemp(Location::RegisterLocation(ESI));
1607 locations->AddTemp(Location::RegisterLocation(EDI));
1608}
1609
1610void IntrinsicCodeGeneratorX86::VisitStringGetCharsNoCheck(HInvoke* invoke) {
1611 X86Assembler* assembler = GetAssembler();
1612 LocationSummary* locations = invoke->GetLocations();
1613
1614 size_t char_component_size = Primitive::ComponentSize(Primitive::kPrimChar);
1615 // Location of data in char array buffer.
1616 const uint32_t data_offset = mirror::Array::DataOffset(char_component_size).Uint32Value();
1617 // Location of char array data in string.
1618 const uint32_t value_offset = mirror::String::ValueOffset().Uint32Value();
1619
1620 // public void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin);
1621 Register obj = locations->InAt(0).AsRegister<Register>();
1622 Location srcBegin = locations->InAt(1);
1623 int srcBegin_value =
1624 srcBegin.IsConstant() ? srcBegin.GetConstant()->AsIntConstant()->GetValue() : 0;
1625 Register srcEnd = locations->InAt(2).AsRegister<Register>();
1626 Register dst = locations->InAt(3).AsRegister<Register>();
1627 Register dstBegin = locations->InAt(4).AsRegister<Register>();
1628
1629 // Check assumption that sizeof(Char) is 2 (used in scaling below).
1630 const size_t char_size = Primitive::ComponentSize(Primitive::kPrimChar);
1631 DCHECK_EQ(char_size, 2u);
1632
1633 // Compute the address of the destination buffer.
1634 __ leal(EDI, Address(dst, dstBegin, ScaleFactor::TIMES_2, data_offset));
1635
1636 // Compute the address of the source string.
1637 if (srcBegin.IsConstant()) {
1638 // Compute the address of the source string by adding the number of chars from
1639 // the source beginning to the value offset of a string.
1640 __ leal(ESI, Address(obj, srcBegin_value * char_size + value_offset));
1641 } else {
1642 __ leal(ESI, Address(obj, srcBegin.AsRegister<Register>(),
1643 ScaleFactor::TIMES_2, value_offset));
1644 }
1645
1646 // Compute the number of chars (words) to move.
1647 // Now is the time to save ECX, since we don't know if it will be used later.
1648 __ pushl(ECX);
1649 int stack_adjust = kX86WordSize;
1650 __ cfi().AdjustCFAOffset(stack_adjust);
1651 DCHECK_EQ(srcEnd, ECX);
1652 if (srcBegin.IsConstant()) {
1653 if (srcBegin_value != 0) {
1654 __ subl(ECX, Immediate(srcBegin_value));
1655 }
1656 } else {
1657 DCHECK(srcBegin.IsRegister());
1658 __ subl(ECX, srcBegin.AsRegister<Register>());
1659 }
1660
1661 // Do the move.
1662 __ rep_movsw();
1663
1664 // And restore ECX.
1665 __ popl(ECX);
1666 __ cfi().AdjustCFAOffset(-stack_adjust);
1667}
1668
Mark Mendell09ed1a32015-03-25 08:30:06 -04001669static void GenPeek(LocationSummary* locations, Primitive::Type size, X86Assembler* assembler) {
1670 Register address = locations->InAt(0).AsRegisterPairLow<Register>();
1671 Location out_loc = locations->Out();
1672 // x86 allows unaligned access. We do not have to check the input or use specific instructions
1673 // to avoid a SIGBUS.
1674 switch (size) {
1675 case Primitive::kPrimByte:
1676 __ movsxb(out_loc.AsRegister<Register>(), Address(address, 0));
1677 break;
1678 case Primitive::kPrimShort:
1679 __ movsxw(out_loc.AsRegister<Register>(), Address(address, 0));
1680 break;
1681 case Primitive::kPrimInt:
1682 __ movl(out_loc.AsRegister<Register>(), Address(address, 0));
1683 break;
1684 case Primitive::kPrimLong:
1685 __ movl(out_loc.AsRegisterPairLow<Register>(), Address(address, 0));
1686 __ movl(out_loc.AsRegisterPairHigh<Register>(), Address(address, 4));
1687 break;
1688 default:
1689 LOG(FATAL) << "Type not recognized for peek: " << size;
1690 UNREACHABLE();
1691 }
1692}
1693
1694void IntrinsicLocationsBuilderX86::VisitMemoryPeekByte(HInvoke* invoke) {
1695 CreateLongToIntLocations(arena_, invoke);
1696}
1697
1698void IntrinsicCodeGeneratorX86::VisitMemoryPeekByte(HInvoke* invoke) {
1699 GenPeek(invoke->GetLocations(), Primitive::kPrimByte, GetAssembler());
1700}
1701
1702void IntrinsicLocationsBuilderX86::VisitMemoryPeekIntNative(HInvoke* invoke) {
1703 CreateLongToIntLocations(arena_, invoke);
1704}
1705
1706void IntrinsicCodeGeneratorX86::VisitMemoryPeekIntNative(HInvoke* invoke) {
1707 GenPeek(invoke->GetLocations(), Primitive::kPrimInt, GetAssembler());
1708}
1709
1710void IntrinsicLocationsBuilderX86::VisitMemoryPeekLongNative(HInvoke* invoke) {
1711 CreateLongToLongLocations(arena_, invoke);
1712}
1713
1714void IntrinsicCodeGeneratorX86::VisitMemoryPeekLongNative(HInvoke* invoke) {
1715 GenPeek(invoke->GetLocations(), Primitive::kPrimLong, GetAssembler());
1716}
1717
1718void IntrinsicLocationsBuilderX86::VisitMemoryPeekShortNative(HInvoke* invoke) {
1719 CreateLongToIntLocations(arena_, invoke);
1720}
1721
1722void IntrinsicCodeGeneratorX86::VisitMemoryPeekShortNative(HInvoke* invoke) {
1723 GenPeek(invoke->GetLocations(), Primitive::kPrimShort, GetAssembler());
1724}
1725
1726static void CreateLongIntToVoidLocations(ArenaAllocator* arena, Primitive::Type size,
1727 HInvoke* invoke) {
1728 LocationSummary* locations = new (arena) LocationSummary(invoke,
1729 LocationSummary::kNoCall,
1730 kIntrinsified);
1731 locations->SetInAt(0, Location::RequiresRegister());
Roland Levillain4c0eb422015-04-24 16:43:49 +01001732 HInstruction* value = invoke->InputAt(1);
Mark Mendell09ed1a32015-03-25 08:30:06 -04001733 if (size == Primitive::kPrimByte) {
1734 locations->SetInAt(1, Location::ByteRegisterOrConstant(EDX, value));
1735 } else {
1736 locations->SetInAt(1, Location::RegisterOrConstant(value));
1737 }
1738}
1739
1740static void GenPoke(LocationSummary* locations, Primitive::Type size, X86Assembler* assembler) {
1741 Register address = locations->InAt(0).AsRegisterPairLow<Register>();
1742 Location value_loc = locations->InAt(1);
1743 // x86 allows unaligned access. We do not have to check the input or use specific instructions
1744 // to avoid a SIGBUS.
1745 switch (size) {
1746 case Primitive::kPrimByte:
1747 if (value_loc.IsConstant()) {
1748 __ movb(Address(address, 0),
1749 Immediate(value_loc.GetConstant()->AsIntConstant()->GetValue()));
1750 } else {
1751 __ movb(Address(address, 0), value_loc.AsRegister<ByteRegister>());
1752 }
1753 break;
1754 case Primitive::kPrimShort:
1755 if (value_loc.IsConstant()) {
1756 __ movw(Address(address, 0),
1757 Immediate(value_loc.GetConstant()->AsIntConstant()->GetValue()));
1758 } else {
1759 __ movw(Address(address, 0), value_loc.AsRegister<Register>());
1760 }
1761 break;
1762 case Primitive::kPrimInt:
1763 if (value_loc.IsConstant()) {
1764 __ movl(Address(address, 0),
1765 Immediate(value_loc.GetConstant()->AsIntConstant()->GetValue()));
1766 } else {
1767 __ movl(Address(address, 0), value_loc.AsRegister<Register>());
1768 }
1769 break;
1770 case Primitive::kPrimLong:
1771 if (value_loc.IsConstant()) {
1772 int64_t value = value_loc.GetConstant()->AsLongConstant()->GetValue();
1773 __ movl(Address(address, 0), Immediate(Low32Bits(value)));
1774 __ movl(Address(address, 4), Immediate(High32Bits(value)));
1775 } else {
1776 __ movl(Address(address, 0), value_loc.AsRegisterPairLow<Register>());
1777 __ movl(Address(address, 4), value_loc.AsRegisterPairHigh<Register>());
1778 }
1779 break;
1780 default:
1781 LOG(FATAL) << "Type not recognized for poke: " << size;
1782 UNREACHABLE();
1783 }
1784}
1785
1786void IntrinsicLocationsBuilderX86::VisitMemoryPokeByte(HInvoke* invoke) {
1787 CreateLongIntToVoidLocations(arena_, Primitive::kPrimByte, invoke);
1788}
1789
1790void IntrinsicCodeGeneratorX86::VisitMemoryPokeByte(HInvoke* invoke) {
1791 GenPoke(invoke->GetLocations(), Primitive::kPrimByte, GetAssembler());
1792}
1793
1794void IntrinsicLocationsBuilderX86::VisitMemoryPokeIntNative(HInvoke* invoke) {
1795 CreateLongIntToVoidLocations(arena_, Primitive::kPrimInt, invoke);
1796}
1797
1798void IntrinsicCodeGeneratorX86::VisitMemoryPokeIntNative(HInvoke* invoke) {
1799 GenPoke(invoke->GetLocations(), Primitive::kPrimInt, GetAssembler());
1800}
1801
1802void IntrinsicLocationsBuilderX86::VisitMemoryPokeLongNative(HInvoke* invoke) {
1803 CreateLongIntToVoidLocations(arena_, Primitive::kPrimLong, invoke);
1804}
1805
1806void IntrinsicCodeGeneratorX86::VisitMemoryPokeLongNative(HInvoke* invoke) {
1807 GenPoke(invoke->GetLocations(), Primitive::kPrimLong, GetAssembler());
1808}
1809
1810void IntrinsicLocationsBuilderX86::VisitMemoryPokeShortNative(HInvoke* invoke) {
1811 CreateLongIntToVoidLocations(arena_, Primitive::kPrimShort, invoke);
1812}
1813
1814void IntrinsicCodeGeneratorX86::VisitMemoryPokeShortNative(HInvoke* invoke) {
1815 GenPoke(invoke->GetLocations(), Primitive::kPrimShort, GetAssembler());
1816}
1817
1818void IntrinsicLocationsBuilderX86::VisitThreadCurrentThread(HInvoke* invoke) {
1819 LocationSummary* locations = new (arena_) LocationSummary(invoke,
1820 LocationSummary::kNoCall,
1821 kIntrinsified);
1822 locations->SetOut(Location::RequiresRegister());
1823}
1824
1825void IntrinsicCodeGeneratorX86::VisitThreadCurrentThread(HInvoke* invoke) {
1826 Register out = invoke->GetLocations()->Out().AsRegister<Register>();
1827 GetAssembler()->fs()->movl(out, Address::Absolute(Thread::PeerOffset<kX86WordSize>()));
1828}
1829
Roland Levillain0d5a2812015-11-13 10:07:31 +00001830static void GenUnsafeGet(HInvoke* invoke,
1831 Primitive::Type type,
1832 bool is_volatile,
1833 CodeGeneratorX86* codegen) {
1834 X86Assembler* assembler = down_cast<X86Assembler*>(codegen->GetAssembler());
1835 LocationSummary* locations = invoke->GetLocations();
1836 Location base_loc = locations->InAt(1);
1837 Register base = base_loc.AsRegister<Register>();
1838 Location offset_loc = locations->InAt(2);
1839 Register offset = offset_loc.AsRegisterPairLow<Register>();
1840 Location output_loc = locations->Out();
Mark Mendell09ed1a32015-03-25 08:30:06 -04001841
1842 switch (type) {
Roland Levillain7c1559a2015-12-15 10:55:36 +00001843 case Primitive::kPrimInt: {
Roland Levillain0d5a2812015-11-13 10:07:31 +00001844 Register output = output_loc.AsRegister<Register>();
1845 __ movl(output, Address(base, offset, ScaleFactor::TIMES_1, 0));
Roland Levillain7c1559a2015-12-15 10:55:36 +00001846 break;
1847 }
1848
1849 case Primitive::kPrimNot: {
1850 Register output = output_loc.AsRegister<Register>();
1851 if (kEmitCompilerReadBarrier) {
1852 if (kUseBakerReadBarrier) {
1853 Location temp = locations->GetTemp(0);
Sang, Chunlei0fcd2b82016-04-05 17:12:59 +08001854 Address src(base, offset, ScaleFactor::TIMES_1, 0);
1855 codegen->GenerateReferenceLoadWithBakerReadBarrier(
1856 invoke, output_loc, base, src, temp, /* needs_null_check */ false);
Roland Levillain7c1559a2015-12-15 10:55:36 +00001857 } else {
1858 __ movl(output, Address(base, offset, ScaleFactor::TIMES_1, 0));
1859 codegen->GenerateReadBarrierSlow(
1860 invoke, output_loc, output_loc, base_loc, 0U, offset_loc);
1861 }
1862 } else {
1863 __ movl(output, Address(base, offset, ScaleFactor::TIMES_1, 0));
1864 __ MaybeUnpoisonHeapReference(output);
Roland Levillain4d027112015-07-01 15:41:14 +01001865 }
Mark Mendell09ed1a32015-03-25 08:30:06 -04001866 break;
Roland Levillain4d027112015-07-01 15:41:14 +01001867 }
Mark Mendell09ed1a32015-03-25 08:30:06 -04001868
1869 case Primitive::kPrimLong: {
Roland Levillain0d5a2812015-11-13 10:07:31 +00001870 Register output_lo = output_loc.AsRegisterPairLow<Register>();
1871 Register output_hi = output_loc.AsRegisterPairHigh<Register>();
Mark Mendell09ed1a32015-03-25 08:30:06 -04001872 if (is_volatile) {
1873 // Need to use a XMM to read atomically.
1874 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
1875 __ movsd(temp, Address(base, offset, ScaleFactor::TIMES_1, 0));
1876 __ movd(output_lo, temp);
1877 __ psrlq(temp, Immediate(32));
1878 __ movd(output_hi, temp);
1879 } else {
1880 __ movl(output_lo, Address(base, offset, ScaleFactor::TIMES_1, 0));
1881 __ movl(output_hi, Address(base, offset, ScaleFactor::TIMES_1, 4));
1882 }
1883 }
1884 break;
1885
1886 default:
1887 LOG(FATAL) << "Unsupported op size " << type;
1888 UNREACHABLE();
1889 }
1890}
1891
Roland Levillain7c1559a2015-12-15 10:55:36 +00001892static void CreateIntIntIntToIntLocations(ArenaAllocator* arena,
1893 HInvoke* invoke,
1894 Primitive::Type type,
1895 bool is_volatile) {
Roland Levillain0d5a2812015-11-13 10:07:31 +00001896 bool can_call = kEmitCompilerReadBarrier &&
1897 (invoke->GetIntrinsic() == Intrinsics::kUnsafeGetObject ||
1898 invoke->GetIntrinsic() == Intrinsics::kUnsafeGetObjectVolatile);
Mark Mendell09ed1a32015-03-25 08:30:06 -04001899 LocationSummary* locations = new (arena) LocationSummary(invoke,
Roland Levillain0d5a2812015-11-13 10:07:31 +00001900 can_call ?
1901 LocationSummary::kCallOnSlowPath :
1902 LocationSummary::kNoCall,
Mark Mendell09ed1a32015-03-25 08:30:06 -04001903 kIntrinsified);
1904 locations->SetInAt(0, Location::NoLocation()); // Unused receiver.
1905 locations->SetInAt(1, Location::RequiresRegister());
1906 locations->SetInAt(2, Location::RequiresRegister());
Roland Levillain7c1559a2015-12-15 10:55:36 +00001907 if (type == Primitive::kPrimLong) {
Mark Mendell09ed1a32015-03-25 08:30:06 -04001908 if (is_volatile) {
1909 // Need to use XMM to read volatile.
1910 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain3d312422016-06-23 13:53:42 +01001911 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Mark Mendell09ed1a32015-03-25 08:30:06 -04001912 } else {
1913 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
1914 }
1915 } else {
Roland Levillain3d312422016-06-23 13:53:42 +01001916 locations->SetOut(Location::RequiresRegister(),
1917 can_call ? Location::kOutputOverlap : Location::kNoOutputOverlap);
Mark Mendell09ed1a32015-03-25 08:30:06 -04001918 }
Roland Levillain7c1559a2015-12-15 10:55:36 +00001919 if (type == Primitive::kPrimNot && kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
1920 // We need a temporary register for the read barrier marking slow
Sang, Chunlei0fcd2b82016-04-05 17:12:59 +08001921 // path in InstructionCodeGeneratorX86::GenerateReferenceLoadWithBakerReadBarrier.
Roland Levillain7c1559a2015-12-15 10:55:36 +00001922 locations->AddTemp(Location::RequiresRegister());
1923 }
Mark Mendell09ed1a32015-03-25 08:30:06 -04001924}
1925
1926void IntrinsicLocationsBuilderX86::VisitUnsafeGet(HInvoke* invoke) {
Roland Levillain7c1559a2015-12-15 10:55:36 +00001927 CreateIntIntIntToIntLocations(arena_, invoke, Primitive::kPrimInt, /* is_volatile */ false);
Mark Mendell09ed1a32015-03-25 08:30:06 -04001928}
1929void IntrinsicLocationsBuilderX86::VisitUnsafeGetVolatile(HInvoke* invoke) {
Roland Levillain7c1559a2015-12-15 10:55:36 +00001930 CreateIntIntIntToIntLocations(arena_, invoke, Primitive::kPrimInt, /* is_volatile */ true);
Mark Mendell09ed1a32015-03-25 08:30:06 -04001931}
1932void IntrinsicLocationsBuilderX86::VisitUnsafeGetLong(HInvoke* invoke) {
Roland Levillain7c1559a2015-12-15 10:55:36 +00001933 CreateIntIntIntToIntLocations(arena_, invoke, Primitive::kPrimLong, /* is_volatile */ false);
Mark Mendell09ed1a32015-03-25 08:30:06 -04001934}
1935void IntrinsicLocationsBuilderX86::VisitUnsafeGetLongVolatile(HInvoke* invoke) {
Roland Levillain7c1559a2015-12-15 10:55:36 +00001936 CreateIntIntIntToIntLocations(arena_, invoke, Primitive::kPrimLong, /* is_volatile */ true);
Mark Mendell09ed1a32015-03-25 08:30:06 -04001937}
1938void IntrinsicLocationsBuilderX86::VisitUnsafeGetObject(HInvoke* invoke) {
Roland Levillain7c1559a2015-12-15 10:55:36 +00001939 CreateIntIntIntToIntLocations(arena_, invoke, Primitive::kPrimNot, /* is_volatile */ false);
Mark Mendell09ed1a32015-03-25 08:30:06 -04001940}
1941void IntrinsicLocationsBuilderX86::VisitUnsafeGetObjectVolatile(HInvoke* invoke) {
Roland Levillain7c1559a2015-12-15 10:55:36 +00001942 CreateIntIntIntToIntLocations(arena_, invoke, Primitive::kPrimNot, /* is_volatile */ true);
Mark Mendell09ed1a32015-03-25 08:30:06 -04001943}
1944
1945
1946void IntrinsicCodeGeneratorX86::VisitUnsafeGet(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +00001947 GenUnsafeGet(invoke, Primitive::kPrimInt, /* is_volatile */ false, codegen_);
Mark Mendell09ed1a32015-03-25 08:30:06 -04001948}
1949void IntrinsicCodeGeneratorX86::VisitUnsafeGetVolatile(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +00001950 GenUnsafeGet(invoke, Primitive::kPrimInt, /* is_volatile */ true, codegen_);
Mark Mendell09ed1a32015-03-25 08:30:06 -04001951}
1952void IntrinsicCodeGeneratorX86::VisitUnsafeGetLong(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +00001953 GenUnsafeGet(invoke, Primitive::kPrimLong, /* is_volatile */ false, codegen_);
Mark Mendell09ed1a32015-03-25 08:30:06 -04001954}
1955void IntrinsicCodeGeneratorX86::VisitUnsafeGetLongVolatile(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +00001956 GenUnsafeGet(invoke, Primitive::kPrimLong, /* is_volatile */ true, codegen_);
Mark Mendell09ed1a32015-03-25 08:30:06 -04001957}
1958void IntrinsicCodeGeneratorX86::VisitUnsafeGetObject(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +00001959 GenUnsafeGet(invoke, Primitive::kPrimNot, /* is_volatile */ false, codegen_);
Mark Mendell09ed1a32015-03-25 08:30:06 -04001960}
1961void IntrinsicCodeGeneratorX86::VisitUnsafeGetObjectVolatile(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +00001962 GenUnsafeGet(invoke, Primitive::kPrimNot, /* is_volatile */ true, codegen_);
Mark Mendell09ed1a32015-03-25 08:30:06 -04001963}
1964
1965
1966static void CreateIntIntIntIntToVoidPlusTempsLocations(ArenaAllocator* arena,
1967 Primitive::Type type,
1968 HInvoke* invoke,
1969 bool is_volatile) {
1970 LocationSummary* locations = new (arena) LocationSummary(invoke,
1971 LocationSummary::kNoCall,
1972 kIntrinsified);
1973 locations->SetInAt(0, Location::NoLocation()); // Unused receiver.
1974 locations->SetInAt(1, Location::RequiresRegister());
1975 locations->SetInAt(2, Location::RequiresRegister());
1976 locations->SetInAt(3, Location::RequiresRegister());
1977 if (type == Primitive::kPrimNot) {
1978 // Need temp registers for card-marking.
Roland Levillain4d027112015-07-01 15:41:14 +01001979 locations->AddTemp(Location::RequiresRegister()); // Possibly used for reference poisoning too.
Mark Mendell09ed1a32015-03-25 08:30:06 -04001980 // Ensure the value is in a byte register.
1981 locations->AddTemp(Location::RegisterLocation(ECX));
1982 } else if (type == Primitive::kPrimLong && is_volatile) {
1983 locations->AddTemp(Location::RequiresFpuRegister());
1984 locations->AddTemp(Location::RequiresFpuRegister());
1985 }
1986}
1987
1988void IntrinsicLocationsBuilderX86::VisitUnsafePut(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +00001989 CreateIntIntIntIntToVoidPlusTempsLocations(
1990 arena_, Primitive::kPrimInt, invoke, /* is_volatile */ false);
Mark Mendell09ed1a32015-03-25 08:30:06 -04001991}
1992void IntrinsicLocationsBuilderX86::VisitUnsafePutOrdered(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +00001993 CreateIntIntIntIntToVoidPlusTempsLocations(
1994 arena_, Primitive::kPrimInt, invoke, /* is_volatile */ false);
Mark Mendell09ed1a32015-03-25 08:30:06 -04001995}
1996void IntrinsicLocationsBuilderX86::VisitUnsafePutVolatile(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +00001997 CreateIntIntIntIntToVoidPlusTempsLocations(
1998 arena_, Primitive::kPrimInt, invoke, /* is_volatile */ true);
Mark Mendell09ed1a32015-03-25 08:30:06 -04001999}
2000void IntrinsicLocationsBuilderX86::VisitUnsafePutObject(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +00002001 CreateIntIntIntIntToVoidPlusTempsLocations(
2002 arena_, Primitive::kPrimNot, invoke, /* is_volatile */ false);
Mark Mendell09ed1a32015-03-25 08:30:06 -04002003}
2004void IntrinsicLocationsBuilderX86::VisitUnsafePutObjectOrdered(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +00002005 CreateIntIntIntIntToVoidPlusTempsLocations(
2006 arena_, Primitive::kPrimNot, invoke, /* is_volatile */ false);
Mark Mendell09ed1a32015-03-25 08:30:06 -04002007}
2008void IntrinsicLocationsBuilderX86::VisitUnsafePutObjectVolatile(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +00002009 CreateIntIntIntIntToVoidPlusTempsLocations(
2010 arena_, Primitive::kPrimNot, invoke, /* is_volatile */ true);
Mark Mendell09ed1a32015-03-25 08:30:06 -04002011}
2012void IntrinsicLocationsBuilderX86::VisitUnsafePutLong(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +00002013 CreateIntIntIntIntToVoidPlusTempsLocations(
2014 arena_, Primitive::kPrimLong, invoke, /* is_volatile */ false);
Mark Mendell09ed1a32015-03-25 08:30:06 -04002015}
2016void IntrinsicLocationsBuilderX86::VisitUnsafePutLongOrdered(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +00002017 CreateIntIntIntIntToVoidPlusTempsLocations(
2018 arena_, Primitive::kPrimLong, invoke, /* is_volatile */ false);
Mark Mendell09ed1a32015-03-25 08:30:06 -04002019}
2020void IntrinsicLocationsBuilderX86::VisitUnsafePutLongVolatile(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +00002021 CreateIntIntIntIntToVoidPlusTempsLocations(
2022 arena_, Primitive::kPrimLong, invoke, /* is_volatile */ true);
Mark Mendell09ed1a32015-03-25 08:30:06 -04002023}
2024
2025// We don't care for ordered: it requires an AnyStore barrier, which is already given by the x86
2026// memory model.
2027static void GenUnsafePut(LocationSummary* locations,
2028 Primitive::Type type,
2029 bool is_volatile,
2030 CodeGeneratorX86* codegen) {
Roland Levillainb488b782015-10-22 11:38:49 +01002031 X86Assembler* assembler = down_cast<X86Assembler*>(codegen->GetAssembler());
Mark Mendell09ed1a32015-03-25 08:30:06 -04002032 Register base = locations->InAt(1).AsRegister<Register>();
2033 Register offset = locations->InAt(2).AsRegisterPairLow<Register>();
2034 Location value_loc = locations->InAt(3);
2035
2036 if (type == Primitive::kPrimLong) {
2037 Register value_lo = value_loc.AsRegisterPairLow<Register>();
2038 Register value_hi = value_loc.AsRegisterPairHigh<Register>();
2039 if (is_volatile) {
2040 XmmRegister temp1 = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
2041 XmmRegister temp2 = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
2042 __ movd(temp1, value_lo);
2043 __ movd(temp2, value_hi);
2044 __ punpckldq(temp1, temp2);
2045 __ movsd(Address(base, offset, ScaleFactor::TIMES_1, 0), temp1);
2046 } else {
2047 __ movl(Address(base, offset, ScaleFactor::TIMES_1, 0), value_lo);
2048 __ movl(Address(base, offset, ScaleFactor::TIMES_1, 4), value_hi);
2049 }
Roland Levillain4d027112015-07-01 15:41:14 +01002050 } else if (kPoisonHeapReferences && type == Primitive::kPrimNot) {
2051 Register temp = locations->GetTemp(0).AsRegister<Register>();
2052 __ movl(temp, value_loc.AsRegister<Register>());
2053 __ PoisonHeapReference(temp);
2054 __ movl(Address(base, offset, ScaleFactor::TIMES_1, 0), temp);
Mark Mendell09ed1a32015-03-25 08:30:06 -04002055 } else {
2056 __ movl(Address(base, offset, ScaleFactor::TIMES_1, 0), value_loc.AsRegister<Register>());
2057 }
2058
2059 if (is_volatile) {
Mark P Mendell17077d82015-12-16 19:15:59 +00002060 codegen->MemoryFence();
Mark Mendell09ed1a32015-03-25 08:30:06 -04002061 }
2062
2063 if (type == Primitive::kPrimNot) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01002064 bool value_can_be_null = true; // TODO: Worth finding out this information?
Mark Mendell09ed1a32015-03-25 08:30:06 -04002065 codegen->MarkGCCard(locations->GetTemp(0).AsRegister<Register>(),
2066 locations->GetTemp(1).AsRegister<Register>(),
2067 base,
Nicolas Geoffray07276db2015-05-18 14:22:09 +01002068 value_loc.AsRegister<Register>(),
2069 value_can_be_null);
Mark Mendell09ed1a32015-03-25 08:30:06 -04002070 }
2071}
2072
2073void IntrinsicCodeGeneratorX86::VisitUnsafePut(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +00002074 GenUnsafePut(invoke->GetLocations(), Primitive::kPrimInt, /* is_volatile */ false, codegen_);
Mark Mendell09ed1a32015-03-25 08:30:06 -04002075}
2076void IntrinsicCodeGeneratorX86::VisitUnsafePutOrdered(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +00002077 GenUnsafePut(invoke->GetLocations(), Primitive::kPrimInt, /* is_volatile */ false, codegen_);
Mark Mendell09ed1a32015-03-25 08:30:06 -04002078}
2079void IntrinsicCodeGeneratorX86::VisitUnsafePutVolatile(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +00002080 GenUnsafePut(invoke->GetLocations(), Primitive::kPrimInt, /* is_volatile */ true, codegen_);
Mark Mendell09ed1a32015-03-25 08:30:06 -04002081}
2082void IntrinsicCodeGeneratorX86::VisitUnsafePutObject(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +00002083 GenUnsafePut(invoke->GetLocations(), Primitive::kPrimNot, /* is_volatile */ false, codegen_);
Mark Mendell09ed1a32015-03-25 08:30:06 -04002084}
2085void IntrinsicCodeGeneratorX86::VisitUnsafePutObjectOrdered(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +00002086 GenUnsafePut(invoke->GetLocations(), Primitive::kPrimNot, /* is_volatile */ false, codegen_);
Mark Mendell09ed1a32015-03-25 08:30:06 -04002087}
2088void IntrinsicCodeGeneratorX86::VisitUnsafePutObjectVolatile(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +00002089 GenUnsafePut(invoke->GetLocations(), Primitive::kPrimNot, /* is_volatile */ true, codegen_);
Mark Mendell09ed1a32015-03-25 08:30:06 -04002090}
2091void IntrinsicCodeGeneratorX86::VisitUnsafePutLong(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +00002092 GenUnsafePut(invoke->GetLocations(), Primitive::kPrimLong, /* is_volatile */ false, codegen_);
Mark Mendell09ed1a32015-03-25 08:30:06 -04002093}
2094void IntrinsicCodeGeneratorX86::VisitUnsafePutLongOrdered(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +00002095 GenUnsafePut(invoke->GetLocations(), Primitive::kPrimLong, /* is_volatile */ false, codegen_);
Mark Mendell09ed1a32015-03-25 08:30:06 -04002096}
2097void IntrinsicCodeGeneratorX86::VisitUnsafePutLongVolatile(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +00002098 GenUnsafePut(invoke->GetLocations(), Primitive::kPrimLong, /* is_volatile */ true, codegen_);
Mark Mendell09ed1a32015-03-25 08:30:06 -04002099}
2100
Mark Mendell58d25fd2015-04-03 14:52:31 -04002101static void CreateIntIntIntIntIntToInt(ArenaAllocator* arena, Primitive::Type type,
2102 HInvoke* invoke) {
2103 LocationSummary* locations = new (arena) LocationSummary(invoke,
2104 LocationSummary::kNoCall,
2105 kIntrinsified);
2106 locations->SetInAt(0, Location::NoLocation()); // Unused receiver.
2107 locations->SetInAt(1, Location::RequiresRegister());
2108 // Offset is a long, but in 32 bit mode, we only need the low word.
2109 // Can we update the invoke here to remove a TypeConvert to Long?
2110 locations->SetInAt(2, Location::RequiresRegister());
2111 // Expected value must be in EAX or EDX:EAX.
2112 // For long, new value must be in ECX:EBX.
2113 if (type == Primitive::kPrimLong) {
2114 locations->SetInAt(3, Location::RegisterPairLocation(EAX, EDX));
2115 locations->SetInAt(4, Location::RegisterPairLocation(EBX, ECX));
2116 } else {
2117 locations->SetInAt(3, Location::RegisterLocation(EAX));
2118 locations->SetInAt(4, Location::RequiresRegister());
2119 }
2120
2121 // Force a byte register for the output.
2122 locations->SetOut(Location::RegisterLocation(EAX));
2123 if (type == Primitive::kPrimNot) {
2124 // Need temp registers for card-marking.
Roland Levillainb488b782015-10-22 11:38:49 +01002125 locations->AddTemp(Location::RequiresRegister()); // Possibly used for reference poisoning too.
Mark Mendell58d25fd2015-04-03 14:52:31 -04002126 // Need a byte register for marking.
2127 locations->AddTemp(Location::RegisterLocation(ECX));
2128 }
2129}
2130
2131void IntrinsicLocationsBuilderX86::VisitUnsafeCASInt(HInvoke* invoke) {
2132 CreateIntIntIntIntIntToInt(arena_, Primitive::kPrimInt, invoke);
2133}
2134
2135void IntrinsicLocationsBuilderX86::VisitUnsafeCASLong(HInvoke* invoke) {
2136 CreateIntIntIntIntIntToInt(arena_, Primitive::kPrimLong, invoke);
2137}
2138
2139void IntrinsicLocationsBuilderX86::VisitUnsafeCASObject(HInvoke* invoke) {
Roland Levillain391b8662015-12-18 11:43:38 +00002140 // The UnsafeCASObject intrinsic is missing a read barrier, and
2141 // therefore sometimes does not work as expected (b/25883050).
2142 // Turn it off temporarily as a quick fix, until the read barrier is
Roland Levillain3d312422016-06-23 13:53:42 +01002143 // implemented (see TODO in GenCAS).
Roland Levillain391b8662015-12-18 11:43:38 +00002144 //
Roland Levillain3d312422016-06-23 13:53:42 +01002145 // TODO(rpl): Implement read barrier support in GenCAS and re-enable
Roland Levillain391b8662015-12-18 11:43:38 +00002146 // this intrinsic.
2147 if (kEmitCompilerReadBarrier) {
2148 return;
2149 }
2150
Mark Mendell58d25fd2015-04-03 14:52:31 -04002151 CreateIntIntIntIntIntToInt(arena_, Primitive::kPrimNot, invoke);
2152}
2153
2154static void GenCAS(Primitive::Type type, HInvoke* invoke, CodeGeneratorX86* codegen) {
Roland Levillainb488b782015-10-22 11:38:49 +01002155 X86Assembler* assembler = down_cast<X86Assembler*>(codegen->GetAssembler());
Mark Mendell58d25fd2015-04-03 14:52:31 -04002156 LocationSummary* locations = invoke->GetLocations();
2157
2158 Register base = locations->InAt(1).AsRegister<Register>();
2159 Register offset = locations->InAt(2).AsRegisterPairLow<Register>();
2160 Location out = locations->Out();
2161 DCHECK_EQ(out.AsRegister<Register>(), EAX);
2162
Roland Levillainb488b782015-10-22 11:38:49 +01002163 if (type == Primitive::kPrimNot) {
Roland Levillain4d027112015-07-01 15:41:14 +01002164 Register expected = locations->InAt(3).AsRegister<Register>();
Roland Levillainb488b782015-10-22 11:38:49 +01002165 // Ensure `expected` is in EAX (required by the CMPXCHG instruction).
Roland Levillain4d027112015-07-01 15:41:14 +01002166 DCHECK_EQ(expected, EAX);
Mark Mendell58d25fd2015-04-03 14:52:31 -04002167 Register value = locations->InAt(4).AsRegister<Register>();
Roland Levillain4d027112015-07-01 15:41:14 +01002168
Roland Levillainb488b782015-10-22 11:38:49 +01002169 // Mark card for object assuming new value is stored.
2170 bool value_can_be_null = true; // TODO: Worth finding out this information?
2171 codegen->MarkGCCard(locations->GetTemp(0).AsRegister<Register>(),
2172 locations->GetTemp(1).AsRegister<Register>(),
2173 base,
2174 value,
2175 value_can_be_null);
2176
2177 bool base_equals_value = (base == value);
2178 if (kPoisonHeapReferences) {
2179 if (base_equals_value) {
2180 // If `base` and `value` are the same register location, move
2181 // `value` to a temporary register. This way, poisoning
2182 // `value` won't invalidate `base`.
2183 value = locations->GetTemp(0).AsRegister<Register>();
2184 __ movl(value, base);
Roland Levillain4d027112015-07-01 15:41:14 +01002185 }
Roland Levillainb488b782015-10-22 11:38:49 +01002186
2187 // Check that the register allocator did not assign the location
2188 // of `expected` (EAX) to `value` nor to `base`, so that heap
2189 // poisoning (when enabled) works as intended below.
2190 // - If `value` were equal to `expected`, both references would
2191 // be poisoned twice, meaning they would not be poisoned at
2192 // all, as heap poisoning uses address negation.
2193 // - If `base` were equal to `expected`, poisoning `expected`
2194 // would invalidate `base`.
2195 DCHECK_NE(value, expected);
2196 DCHECK_NE(base, expected);
2197
2198 __ PoisonHeapReference(expected);
2199 __ PoisonHeapReference(value);
Mark Mendell58d25fd2015-04-03 14:52:31 -04002200 }
2201
Roland Levillain391b8662015-12-18 11:43:38 +00002202 // TODO: Add a read barrier for the reference stored in the object
2203 // before attempting the CAS, similar to the one in the
2204 // art::Unsafe_compareAndSwapObject JNI implementation.
2205 //
2206 // Note that this code is not (yet) used when read barriers are
2207 // enabled (see IntrinsicLocationsBuilderX86::VisitUnsafeCASObject).
2208 DCHECK(!kEmitCompilerReadBarrier);
Mark Mendell58d25fd2015-04-03 14:52:31 -04002209 __ LockCmpxchgl(Address(base, offset, TIMES_1, 0), value);
Mark Mendell58d25fd2015-04-03 14:52:31 -04002210
Roland Levillain0d5a2812015-11-13 10:07:31 +00002211 // LOCK CMPXCHG has full barrier semantics, and we don't need
Roland Levillainb488b782015-10-22 11:38:49 +01002212 // scheduling barriers at this time.
Mark Mendell58d25fd2015-04-03 14:52:31 -04002213
Roland Levillainb488b782015-10-22 11:38:49 +01002214 // Convert ZF into the boolean result.
2215 __ setb(kZero, out.AsRegister<Register>());
2216 __ movzxb(out.AsRegister<Register>(), out.AsRegister<ByteRegister>());
Roland Levillain4d027112015-07-01 15:41:14 +01002217
Roland Levillain391b8662015-12-18 11:43:38 +00002218 // If heap poisoning is enabled, we need to unpoison the values
2219 // that were poisoned earlier.
Roland Levillainb488b782015-10-22 11:38:49 +01002220 if (kPoisonHeapReferences) {
2221 if (base_equals_value) {
2222 // `value` has been moved to a temporary register, no need to
2223 // unpoison it.
2224 } else {
2225 // Ensure `value` is different from `out`, so that unpoisoning
2226 // the former does not invalidate the latter.
2227 DCHECK_NE(value, out.AsRegister<Register>());
2228 __ UnpoisonHeapReference(value);
2229 }
2230 // Do not unpoison the reference contained in register
2231 // `expected`, as it is the same as register `out` (EAX).
2232 }
2233 } else {
2234 if (type == Primitive::kPrimInt) {
2235 // Ensure the expected value is in EAX (required by the CMPXCHG
2236 // instruction).
2237 DCHECK_EQ(locations->InAt(3).AsRegister<Register>(), EAX);
2238 __ LockCmpxchgl(Address(base, offset, TIMES_1, 0),
2239 locations->InAt(4).AsRegister<Register>());
2240 } else if (type == Primitive::kPrimLong) {
2241 // Ensure the expected value is in EAX:EDX and that the new
2242 // value is in EBX:ECX (required by the CMPXCHG8B instruction).
2243 DCHECK_EQ(locations->InAt(3).AsRegisterPairLow<Register>(), EAX);
2244 DCHECK_EQ(locations->InAt(3).AsRegisterPairHigh<Register>(), EDX);
2245 DCHECK_EQ(locations->InAt(4).AsRegisterPairLow<Register>(), EBX);
2246 DCHECK_EQ(locations->InAt(4).AsRegisterPairHigh<Register>(), ECX);
2247 __ LockCmpxchg8b(Address(base, offset, TIMES_1, 0));
2248 } else {
2249 LOG(FATAL) << "Unexpected CAS type " << type;
2250 }
2251
Roland Levillain0d5a2812015-11-13 10:07:31 +00002252 // LOCK CMPXCHG/LOCK CMPXCHG8B have full barrier semantics, and we
2253 // don't need scheduling barriers at this time.
Roland Levillainb488b782015-10-22 11:38:49 +01002254
2255 // Convert ZF into the boolean result.
2256 __ setb(kZero, out.AsRegister<Register>());
2257 __ movzxb(out.AsRegister<Register>(), out.AsRegister<ByteRegister>());
Roland Levillain4d027112015-07-01 15:41:14 +01002258 }
Mark Mendell58d25fd2015-04-03 14:52:31 -04002259}
2260
2261void IntrinsicCodeGeneratorX86::VisitUnsafeCASInt(HInvoke* invoke) {
2262 GenCAS(Primitive::kPrimInt, invoke, codegen_);
2263}
2264
2265void IntrinsicCodeGeneratorX86::VisitUnsafeCASLong(HInvoke* invoke) {
2266 GenCAS(Primitive::kPrimLong, invoke, codegen_);
2267}
2268
2269void IntrinsicCodeGeneratorX86::VisitUnsafeCASObject(HInvoke* invoke) {
Roland Levillain3d312422016-06-23 13:53:42 +01002270 // The UnsafeCASObject intrinsic is missing a read barrier, and
2271 // therefore sometimes does not work as expected (b/25883050).
2272 // Turn it off temporarily as a quick fix, until the read barrier is
2273 // implemented (see TODO in GenCAS).
2274 //
2275 // TODO(rpl): Implement read barrier support in GenCAS and re-enable
2276 // this intrinsic.
2277 DCHECK(!kEmitCompilerReadBarrier);
2278
Mark Mendell58d25fd2015-04-03 14:52:31 -04002279 GenCAS(Primitive::kPrimNot, invoke, codegen_);
2280}
2281
2282void IntrinsicLocationsBuilderX86::VisitIntegerReverse(HInvoke* invoke) {
2283 LocationSummary* locations = new (arena_) LocationSummary(invoke,
2284 LocationSummary::kNoCall,
2285 kIntrinsified);
2286 locations->SetInAt(0, Location::RequiresRegister());
2287 locations->SetOut(Location::SameAsFirstInput());
2288 locations->AddTemp(Location::RequiresRegister());
2289}
2290
2291static void SwapBits(Register reg, Register temp, int32_t shift, int32_t mask,
2292 X86Assembler* assembler) {
2293 Immediate imm_shift(shift);
2294 Immediate imm_mask(mask);
2295 __ movl(temp, reg);
2296 __ shrl(reg, imm_shift);
2297 __ andl(temp, imm_mask);
2298 __ andl(reg, imm_mask);
2299 __ shll(temp, imm_shift);
2300 __ orl(reg, temp);
2301}
2302
2303void IntrinsicCodeGeneratorX86::VisitIntegerReverse(HInvoke* invoke) {
Aart Bika19616e2016-02-01 18:57:58 -08002304 X86Assembler* assembler = GetAssembler();
Mark Mendell58d25fd2015-04-03 14:52:31 -04002305 LocationSummary* locations = invoke->GetLocations();
2306
2307 Register reg = locations->InAt(0).AsRegister<Register>();
2308 Register temp = locations->GetTemp(0).AsRegister<Register>();
2309
2310 /*
2311 * Use one bswap instruction to reverse byte order first and then use 3 rounds of
2312 * swapping bits to reverse bits in a number x. Using bswap to save instructions
2313 * compared to generic luni implementation which has 5 rounds of swapping bits.
2314 * x = bswap x
2315 * x = (x & 0x55555555) << 1 | (x >> 1) & 0x55555555;
2316 * x = (x & 0x33333333) << 2 | (x >> 2) & 0x33333333;
2317 * x = (x & 0x0F0F0F0F) << 4 | (x >> 4) & 0x0F0F0F0F;
2318 */
2319 __ bswapl(reg);
2320 SwapBits(reg, temp, 1, 0x55555555, assembler);
2321 SwapBits(reg, temp, 2, 0x33333333, assembler);
2322 SwapBits(reg, temp, 4, 0x0f0f0f0f, assembler);
2323}
2324
2325void IntrinsicLocationsBuilderX86::VisitLongReverse(HInvoke* invoke) {
2326 LocationSummary* locations = new (arena_) LocationSummary(invoke,
2327 LocationSummary::kNoCall,
2328 kIntrinsified);
2329 locations->SetInAt(0, Location::RequiresRegister());
2330 locations->SetOut(Location::SameAsFirstInput());
2331 locations->AddTemp(Location::RequiresRegister());
2332}
2333
2334void IntrinsicCodeGeneratorX86::VisitLongReverse(HInvoke* invoke) {
Aart Bika19616e2016-02-01 18:57:58 -08002335 X86Assembler* assembler = GetAssembler();
Mark Mendell58d25fd2015-04-03 14:52:31 -04002336 LocationSummary* locations = invoke->GetLocations();
2337
2338 Register reg_low = locations->InAt(0).AsRegisterPairLow<Register>();
2339 Register reg_high = locations->InAt(0).AsRegisterPairHigh<Register>();
2340 Register temp = locations->GetTemp(0).AsRegister<Register>();
2341
2342 // We want to swap high/low, then bswap each one, and then do the same
2343 // as a 32 bit reverse.
2344 // Exchange high and low.
2345 __ movl(temp, reg_low);
2346 __ movl(reg_low, reg_high);
2347 __ movl(reg_high, temp);
2348
2349 // bit-reverse low
2350 __ bswapl(reg_low);
2351 SwapBits(reg_low, temp, 1, 0x55555555, assembler);
2352 SwapBits(reg_low, temp, 2, 0x33333333, assembler);
2353 SwapBits(reg_low, temp, 4, 0x0f0f0f0f, assembler);
2354
2355 // bit-reverse high
2356 __ bswapl(reg_high);
2357 SwapBits(reg_high, temp, 1, 0x55555555, assembler);
2358 SwapBits(reg_high, temp, 2, 0x33333333, assembler);
2359 SwapBits(reg_high, temp, 4, 0x0f0f0f0f, assembler);
2360}
2361
Aart Bikc39dac12016-01-21 08:59:48 -08002362static void CreateBitCountLocations(
2363 ArenaAllocator* arena, CodeGeneratorX86* codegen, HInvoke* invoke, bool is_long) {
2364 if (!codegen->GetInstructionSetFeatures().HasPopCnt()) {
2365 // Do nothing if there is no popcnt support. This results in generating
2366 // a call for the intrinsic rather than direct code.
2367 return;
2368 }
2369 LocationSummary* locations = new (arena) LocationSummary(invoke,
2370 LocationSummary::kNoCall,
2371 kIntrinsified);
2372 if (is_long) {
Aart Bikc39dac12016-01-21 08:59:48 -08002373 locations->AddTemp(Location::RequiresRegister());
Aart Bikc39dac12016-01-21 08:59:48 -08002374 }
Aart Bik2a946072016-01-21 12:49:00 -08002375 locations->SetInAt(0, Location::Any());
Aart Bikc39dac12016-01-21 08:59:48 -08002376 locations->SetOut(Location::RequiresRegister());
2377}
2378
Aart Bika19616e2016-02-01 18:57:58 -08002379static void GenBitCount(X86Assembler* assembler,
2380 CodeGeneratorX86* codegen,
2381 HInvoke* invoke, bool is_long) {
Aart Bikc39dac12016-01-21 08:59:48 -08002382 LocationSummary* locations = invoke->GetLocations();
2383 Location src = locations->InAt(0);
2384 Register out = locations->Out().AsRegister<Register>();
2385
2386 if (invoke->InputAt(0)->IsConstant()) {
2387 // Evaluate this at compile time.
2388 int64_t value = Int64FromConstant(invoke->InputAt(0)->AsConstant());
Roland Levillainfa3912e2016-04-01 18:21:55 +01002389 int32_t result = is_long
Aart Bikc39dac12016-01-21 08:59:48 -08002390 ? POPCOUNT(static_cast<uint64_t>(value))
2391 : POPCOUNT(static_cast<uint32_t>(value));
Roland Levillainfa3912e2016-04-01 18:21:55 +01002392 codegen->Load32BitValue(out, result);
Aart Bikc39dac12016-01-21 08:59:48 -08002393 return;
2394 }
2395
2396 // Handle the non-constant cases.
2397 if (!is_long) {
2398 if (src.IsRegister()) {
2399 __ popcntl(out, src.AsRegister<Register>());
2400 } else {
2401 DCHECK(src.IsStackSlot());
2402 __ popcntl(out, Address(ESP, src.GetStackIndex()));
2403 }
Aart Bik2a946072016-01-21 12:49:00 -08002404 } else {
2405 // The 64-bit case needs to worry about two parts.
2406 Register temp = locations->GetTemp(0).AsRegister<Register>();
2407 if (src.IsRegisterPair()) {
2408 __ popcntl(temp, src.AsRegisterPairLow<Register>());
2409 __ popcntl(out, src.AsRegisterPairHigh<Register>());
2410 } else {
2411 DCHECK(src.IsDoubleStackSlot());
2412 __ popcntl(temp, Address(ESP, src.GetStackIndex()));
2413 __ popcntl(out, Address(ESP, src.GetHighStackIndex(kX86WordSize)));
2414 }
2415 __ addl(out, temp);
Aart Bikc39dac12016-01-21 08:59:48 -08002416 }
Aart Bikc39dac12016-01-21 08:59:48 -08002417}
2418
2419void IntrinsicLocationsBuilderX86::VisitIntegerBitCount(HInvoke* invoke) {
2420 CreateBitCountLocations(arena_, codegen_, invoke, /* is_long */ false);
2421}
2422
2423void IntrinsicCodeGeneratorX86::VisitIntegerBitCount(HInvoke* invoke) {
Aart Bika19616e2016-02-01 18:57:58 -08002424 GenBitCount(GetAssembler(), codegen_, invoke, /* is_long */ false);
Aart Bikc39dac12016-01-21 08:59:48 -08002425}
2426
2427void IntrinsicLocationsBuilderX86::VisitLongBitCount(HInvoke* invoke) {
2428 CreateBitCountLocations(arena_, codegen_, invoke, /* is_long */ true);
2429}
2430
2431void IntrinsicCodeGeneratorX86::VisitLongBitCount(HInvoke* invoke) {
Aart Bika19616e2016-02-01 18:57:58 -08002432 GenBitCount(GetAssembler(), codegen_, invoke, /* is_long */ true);
Aart Bikc39dac12016-01-21 08:59:48 -08002433}
2434
Mark Mendelld5897672015-08-12 21:16:41 -04002435static void CreateLeadingZeroLocations(ArenaAllocator* arena, HInvoke* invoke, bool is_long) {
2436 LocationSummary* locations = new (arena) LocationSummary(invoke,
2437 LocationSummary::kNoCall,
2438 kIntrinsified);
2439 if (is_long) {
2440 locations->SetInAt(0, Location::RequiresRegister());
2441 } else {
2442 locations->SetInAt(0, Location::Any());
2443 }
2444 locations->SetOut(Location::RequiresRegister());
2445}
2446
Aart Bika19616e2016-02-01 18:57:58 -08002447static void GenLeadingZeros(X86Assembler* assembler,
2448 CodeGeneratorX86* codegen,
2449 HInvoke* invoke, bool is_long) {
Mark Mendelld5897672015-08-12 21:16:41 -04002450 LocationSummary* locations = invoke->GetLocations();
2451 Location src = locations->InAt(0);
2452 Register out = locations->Out().AsRegister<Register>();
2453
2454 if (invoke->InputAt(0)->IsConstant()) {
2455 // Evaluate this at compile time.
2456 int64_t value = Int64FromConstant(invoke->InputAt(0)->AsConstant());
2457 if (value == 0) {
2458 value = is_long ? 64 : 32;
2459 } else {
2460 value = is_long ? CLZ(static_cast<uint64_t>(value)) : CLZ(static_cast<uint32_t>(value));
2461 }
Aart Bika19616e2016-02-01 18:57:58 -08002462 codegen->Load32BitValue(out, value);
Mark Mendelld5897672015-08-12 21:16:41 -04002463 return;
2464 }
2465
2466 // Handle the non-constant cases.
2467 if (!is_long) {
2468 if (src.IsRegister()) {
2469 __ bsrl(out, src.AsRegister<Register>());
2470 } else {
2471 DCHECK(src.IsStackSlot());
2472 __ bsrl(out, Address(ESP, src.GetStackIndex()));
2473 }
2474
2475 // BSR sets ZF if the input was zero, and the output is undefined.
Mark Mendell0c9497d2015-08-21 09:30:05 -04002476 NearLabel all_zeroes, done;
Mark Mendelld5897672015-08-12 21:16:41 -04002477 __ j(kEqual, &all_zeroes);
2478
2479 // Correct the result from BSR to get the final CLZ result.
2480 __ xorl(out, Immediate(31));
2481 __ jmp(&done);
2482
2483 // Fix the zero case with the expected result.
2484 __ Bind(&all_zeroes);
2485 __ movl(out, Immediate(32));
2486
2487 __ Bind(&done);
2488 return;
2489 }
2490
2491 // 64 bit case needs to worry about both parts of the register.
2492 DCHECK(src.IsRegisterPair());
2493 Register src_lo = src.AsRegisterPairLow<Register>();
2494 Register src_hi = src.AsRegisterPairHigh<Register>();
Mark Mendell0c9497d2015-08-21 09:30:05 -04002495 NearLabel handle_low, done, all_zeroes;
Mark Mendelld5897672015-08-12 21:16:41 -04002496
2497 // Is the high word zero?
2498 __ testl(src_hi, src_hi);
2499 __ j(kEqual, &handle_low);
2500
2501 // High word is not zero. We know that the BSR result is defined in this case.
2502 __ bsrl(out, src_hi);
2503
2504 // Correct the result from BSR to get the final CLZ result.
2505 __ xorl(out, Immediate(31));
2506 __ jmp(&done);
2507
2508 // High word was zero. We have to compute the low word count and add 32.
2509 __ Bind(&handle_low);
2510 __ bsrl(out, src_lo);
2511 __ j(kEqual, &all_zeroes);
2512
2513 // We had a valid result. Use an XOR to both correct the result and add 32.
2514 __ xorl(out, Immediate(63));
2515 __ jmp(&done);
2516
2517 // All zero case.
2518 __ Bind(&all_zeroes);
2519 __ movl(out, Immediate(64));
2520
2521 __ Bind(&done);
2522}
2523
2524void IntrinsicLocationsBuilderX86::VisitIntegerNumberOfLeadingZeros(HInvoke* invoke) {
2525 CreateLeadingZeroLocations(arena_, invoke, /* is_long */ false);
2526}
2527
2528void IntrinsicCodeGeneratorX86::VisitIntegerNumberOfLeadingZeros(HInvoke* invoke) {
Aart Bika19616e2016-02-01 18:57:58 -08002529 GenLeadingZeros(GetAssembler(), codegen_, invoke, /* is_long */ false);
Mark Mendelld5897672015-08-12 21:16:41 -04002530}
2531
2532void IntrinsicLocationsBuilderX86::VisitLongNumberOfLeadingZeros(HInvoke* invoke) {
2533 CreateLeadingZeroLocations(arena_, invoke, /* is_long */ true);
2534}
2535
2536void IntrinsicCodeGeneratorX86::VisitLongNumberOfLeadingZeros(HInvoke* invoke) {
Aart Bika19616e2016-02-01 18:57:58 -08002537 GenLeadingZeros(GetAssembler(), codegen_, invoke, /* is_long */ true);
Mark Mendelld5897672015-08-12 21:16:41 -04002538}
2539
Mark Mendell2d554792015-09-15 21:45:18 -04002540static void CreateTrailingZeroLocations(ArenaAllocator* arena, HInvoke* invoke, bool is_long) {
2541 LocationSummary* locations = new (arena) LocationSummary(invoke,
2542 LocationSummary::kNoCall,
2543 kIntrinsified);
2544 if (is_long) {
2545 locations->SetInAt(0, Location::RequiresRegister());
2546 } else {
2547 locations->SetInAt(0, Location::Any());
2548 }
2549 locations->SetOut(Location::RequiresRegister());
2550}
2551
Aart Bika19616e2016-02-01 18:57:58 -08002552static void GenTrailingZeros(X86Assembler* assembler,
2553 CodeGeneratorX86* codegen,
2554 HInvoke* invoke, bool is_long) {
Mark Mendell2d554792015-09-15 21:45:18 -04002555 LocationSummary* locations = invoke->GetLocations();
2556 Location src = locations->InAt(0);
2557 Register out = locations->Out().AsRegister<Register>();
2558
2559 if (invoke->InputAt(0)->IsConstant()) {
2560 // Evaluate this at compile time.
2561 int64_t value = Int64FromConstant(invoke->InputAt(0)->AsConstant());
2562 if (value == 0) {
2563 value = is_long ? 64 : 32;
2564 } else {
2565 value = is_long ? CTZ(static_cast<uint64_t>(value)) : CTZ(static_cast<uint32_t>(value));
2566 }
Aart Bika19616e2016-02-01 18:57:58 -08002567 codegen->Load32BitValue(out, value);
Mark Mendell2d554792015-09-15 21:45:18 -04002568 return;
2569 }
2570
2571 // Handle the non-constant cases.
2572 if (!is_long) {
2573 if (src.IsRegister()) {
2574 __ bsfl(out, src.AsRegister<Register>());
2575 } else {
2576 DCHECK(src.IsStackSlot());
2577 __ bsfl(out, Address(ESP, src.GetStackIndex()));
2578 }
2579
2580 // BSF sets ZF if the input was zero, and the output is undefined.
2581 NearLabel done;
2582 __ j(kNotEqual, &done);
2583
2584 // Fix the zero case with the expected result.
2585 __ movl(out, Immediate(32));
2586
2587 __ Bind(&done);
2588 return;
2589 }
2590
2591 // 64 bit case needs to worry about both parts of the register.
2592 DCHECK(src.IsRegisterPair());
2593 Register src_lo = src.AsRegisterPairLow<Register>();
2594 Register src_hi = src.AsRegisterPairHigh<Register>();
2595 NearLabel done, all_zeroes;
2596
2597 // If the low word is zero, then ZF will be set. If not, we have the answer.
2598 __ bsfl(out, src_lo);
2599 __ j(kNotEqual, &done);
2600
2601 // Low word was zero. We have to compute the high word count and add 32.
2602 __ bsfl(out, src_hi);
2603 __ j(kEqual, &all_zeroes);
2604
2605 // We had a valid result. Add 32 to account for the low word being zero.
2606 __ addl(out, Immediate(32));
2607 __ jmp(&done);
2608
2609 // All zero case.
2610 __ Bind(&all_zeroes);
2611 __ movl(out, Immediate(64));
2612
2613 __ Bind(&done);
2614}
2615
2616void IntrinsicLocationsBuilderX86::VisitIntegerNumberOfTrailingZeros(HInvoke* invoke) {
2617 CreateTrailingZeroLocations(arena_, invoke, /* is_long */ false);
2618}
2619
2620void IntrinsicCodeGeneratorX86::VisitIntegerNumberOfTrailingZeros(HInvoke* invoke) {
Aart Bika19616e2016-02-01 18:57:58 -08002621 GenTrailingZeros(GetAssembler(), codegen_, invoke, /* is_long */ false);
Mark Mendell2d554792015-09-15 21:45:18 -04002622}
2623
2624void IntrinsicLocationsBuilderX86::VisitLongNumberOfTrailingZeros(HInvoke* invoke) {
2625 CreateTrailingZeroLocations(arena_, invoke, /* is_long */ true);
2626}
2627
2628void IntrinsicCodeGeneratorX86::VisitLongNumberOfTrailingZeros(HInvoke* invoke) {
Aart Bika19616e2016-02-01 18:57:58 -08002629 GenTrailingZeros(GetAssembler(), codegen_, invoke, /* is_long */ true);
Mark Mendell2d554792015-09-15 21:45:18 -04002630}
2631
Serguei Katkov288c7a82016-05-16 11:53:15 +06002632void IntrinsicLocationsBuilderX86::VisitReferenceGetReferent(HInvoke* invoke) {
2633 if (kEmitCompilerReadBarrier) {
2634 // Do not intrinsify this call with the read barrier configuration.
2635 return;
2636 }
2637 LocationSummary* locations = new (arena_) LocationSummary(invoke,
2638 LocationSummary::kCallOnSlowPath,
2639 kIntrinsified);
2640 locations->SetInAt(0, Location::RequiresRegister());
2641 locations->SetOut(Location::SameAsFirstInput());
2642 locations->AddTemp(Location::RequiresRegister());
2643}
2644
2645void IntrinsicCodeGeneratorX86::VisitReferenceGetReferent(HInvoke* invoke) {
2646 DCHECK(!kEmitCompilerReadBarrier);
2647 LocationSummary* locations = invoke->GetLocations();
2648 X86Assembler* assembler = GetAssembler();
2649
2650 Register obj = locations->InAt(0).AsRegister<Register>();
2651 Register out = locations->Out().AsRegister<Register>();
2652
2653 SlowPathCode* slow_path = new (GetAllocator()) IntrinsicSlowPathX86(invoke);
2654 codegen_->AddSlowPath(slow_path);
2655
2656 // Load ArtMethod first.
2657 HInvokeStaticOrDirect* invoke_direct = invoke->AsInvokeStaticOrDirect();
2658 DCHECK(invoke_direct != nullptr);
2659 Location temp_loc = codegen_->GenerateCalleeMethodStaticOrDirectCall(
2660 invoke_direct, locations->GetTemp(0));
2661 DCHECK(temp_loc.Equals(locations->GetTemp(0)));
2662 Register temp = temp_loc.AsRegister<Register>();
2663
2664 // Now get declaring class.
2665 __ movl(temp, Address(temp, ArtMethod::DeclaringClassOffset().Int32Value()));
2666
2667 uint32_t slow_path_flag_offset = codegen_->GetReferenceSlowFlagOffset();
2668 uint32_t disable_flag_offset = codegen_->GetReferenceDisableFlagOffset();
2669 DCHECK_NE(slow_path_flag_offset, 0u);
2670 DCHECK_NE(disable_flag_offset, 0u);
2671 DCHECK_NE(slow_path_flag_offset, disable_flag_offset);
2672
2673 // Check static flags preventing us for using intrinsic.
2674 if (slow_path_flag_offset == disable_flag_offset + 1) {
2675 __ cmpw(Address(temp, disable_flag_offset), Immediate(0));
2676 __ j(kNotEqual, slow_path->GetEntryLabel());
2677 } else {
2678 __ cmpb(Address(temp, disable_flag_offset), Immediate(0));
2679 __ j(kNotEqual, slow_path->GetEntryLabel());
2680 __ cmpb(Address(temp, slow_path_flag_offset), Immediate(0));
2681 __ j(kNotEqual, slow_path->GetEntryLabel());
2682 }
2683
2684 // Fast path.
2685 __ movl(out, Address(obj, mirror::Reference::ReferentOffset().Int32Value()));
2686 codegen_->MaybeRecordImplicitNullCheck(invoke);
2687 __ MaybeUnpoisonHeapReference(out);
2688 __ Bind(slow_path->GetExitLabel());
2689}
2690
Aart Bik2f9fcc92016-03-01 15:16:54 -08002691UNIMPLEMENTED_INTRINSIC(X86, MathRoundDouble)
Aart Bik2f9fcc92016-03-01 15:16:54 -08002692UNIMPLEMENTED_INTRINSIC(X86, SystemArrayCopy)
2693UNIMPLEMENTED_INTRINSIC(X86, FloatIsInfinite)
2694UNIMPLEMENTED_INTRINSIC(X86, DoubleIsInfinite)
2695UNIMPLEMENTED_INTRINSIC(X86, IntegerHighestOneBit)
2696UNIMPLEMENTED_INTRINSIC(X86, LongHighestOneBit)
2697UNIMPLEMENTED_INTRINSIC(X86, IntegerLowestOneBit)
2698UNIMPLEMENTED_INTRINSIC(X86, LongLowestOneBit)
Mark Mendell09ed1a32015-03-25 08:30:06 -04002699
Aart Bik0e54c012016-03-04 12:08:31 -08002700// 1.8.
2701UNIMPLEMENTED_INTRINSIC(X86, UnsafeGetAndAddInt)
2702UNIMPLEMENTED_INTRINSIC(X86, UnsafeGetAndAddLong)
2703UNIMPLEMENTED_INTRINSIC(X86, UnsafeGetAndSetInt)
2704UNIMPLEMENTED_INTRINSIC(X86, UnsafeGetAndSetLong)
2705UNIMPLEMENTED_INTRINSIC(X86, UnsafeGetAndSetObject)
Aart Bik0e54c012016-03-04 12:08:31 -08002706
Aart Bik2f9fcc92016-03-01 15:16:54 -08002707UNREACHABLE_INTRINSICS(X86)
Roland Levillain4d027112015-07-01 15:41:14 +01002708
2709#undef __
2710
Mark Mendell09ed1a32015-03-25 08:30:06 -04002711} // namespace x86
2712} // namespace art