blob: 384737f55ab8bbdcf2e81342ea61e750d91368d3 [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
19#include "code_generator_x86.h"
20#include "entrypoints/quick/quick_entrypoints.h"
21#include "intrinsics.h"
22#include "mirror/array-inl.h"
23#include "mirror/art_method.h"
24#include "mirror/string.h"
25#include "thread.h"
26#include "utils/x86/assembler_x86.h"
27#include "utils/x86/constants_x86.h"
28
29namespace art {
30
31namespace x86 {
32
33static constexpr int kDoubleNaNHigh = 0x7FF80000;
34static constexpr int kDoubleNaNLow = 0x00000000;
35static constexpr int kFloatNaN = 0x7FC00000;
36
37X86Assembler* IntrinsicCodeGeneratorX86::GetAssembler() {
38 return reinterpret_cast<X86Assembler*>(codegen_->GetAssembler());
39}
40
41ArenaAllocator* IntrinsicCodeGeneratorX86::GetAllocator() {
42 return codegen_->GetGraph()->GetArena();
43}
44
45bool IntrinsicLocationsBuilderX86::TryDispatch(HInvoke* invoke) {
46 Dispatch(invoke);
47 LocationSummary* res = invoke->GetLocations();
48 return res != nullptr && res->Intrinsified();
49}
50
51#define __ reinterpret_cast<X86Assembler*>(codegen->GetAssembler())->
52
53// TODO: target as memory.
54static void MoveFromReturnRegister(Location target,
55 Primitive::Type type,
56 CodeGeneratorX86* codegen) {
57 if (!target.IsValid()) {
58 DCHECK(type == Primitive::kPrimVoid);
59 return;
60 }
61
62 switch (type) {
63 case Primitive::kPrimBoolean:
64 case Primitive::kPrimByte:
65 case Primitive::kPrimChar:
66 case Primitive::kPrimShort:
67 case Primitive::kPrimInt:
68 case Primitive::kPrimNot: {
69 Register target_reg = target.AsRegister<Register>();
70 if (target_reg != EAX) {
71 __ movl(target_reg, EAX);
72 }
73 break;
74 }
75 case Primitive::kPrimLong: {
76 Register target_reg_lo = target.AsRegisterPairLow<Register>();
77 Register target_reg_hi = target.AsRegisterPairHigh<Register>();
78 if (target_reg_lo != EAX) {
79 __ movl(target_reg_lo, EAX);
80 }
81 if (target_reg_hi != EDX) {
82 __ movl(target_reg_hi, EDX);
83 }
84 break;
85 }
86
87 case Primitive::kPrimVoid:
88 LOG(FATAL) << "Unexpected void type for valid location " << target;
89 UNREACHABLE();
90
91 case Primitive::kPrimDouble: {
92 XmmRegister target_reg = target.AsFpuRegister<XmmRegister>();
93 if (target_reg != XMM0) {
94 __ movsd(target_reg, XMM0);
95 }
96 break;
97 }
98 case Primitive::kPrimFloat: {
99 XmmRegister target_reg = target.AsFpuRegister<XmmRegister>();
100 if (target_reg != XMM0) {
101 __ movss(target_reg, XMM0);
102 }
103 break;
104 }
105 }
106}
107
108static void MoveArguments(HInvoke* invoke, ArenaAllocator* arena, CodeGeneratorX86* codegen) {
109 if (invoke->InputCount() == 0) {
110 return;
111 }
112
113 LocationSummary* locations = invoke->GetLocations();
114 InvokeDexCallingConventionVisitor calling_convention_visitor;
115
116 // We're moving potentially two or more locations to locations that could overlap, so we need
117 // a parallel move resolver.
118 HParallelMove parallel_move(arena);
119
120 for (size_t i = 0; i < invoke->InputCount(); i++) {
121 HInstruction* input = invoke->InputAt(i);
122 Location cc_loc = calling_convention_visitor.GetNextLocation(input->GetType());
123 Location actual_loc = locations->InAt(i);
124
125 parallel_move.AddMove(actual_loc, cc_loc, nullptr);
126 }
127
128 codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
129}
130
131// Slow-path for fallback (calling the managed code to handle the intrinsic) in an intrinsified
132// call. This will copy the arguments into the positions for a regular call.
133//
134// Note: The actual parameters are required to be in the locations given by the invoke's location
135// summary. If an intrinsic modifies those locations before a slowpath call, they must be
136// restored!
137class IntrinsicSlowPathX86 : public SlowPathCodeX86 {
138 public:
139 explicit IntrinsicSlowPathX86(HInvoke* invoke, Register temp)
140 : invoke_(invoke) {
141 // The temporary register has to be EAX for x86 invokes.
142 DCHECK_EQ(temp, EAX);
143 }
144
145 void EmitNativeCode(CodeGenerator* codegen_in) OVERRIDE {
146 CodeGeneratorX86* codegen = down_cast<CodeGeneratorX86*>(codegen_in);
147 __ Bind(GetEntryLabel());
148
149 SaveLiveRegisters(codegen, invoke_->GetLocations());
150
151 MoveArguments(invoke_, codegen->GetGraph()->GetArena(), codegen);
152
153 if (invoke_->IsInvokeStaticOrDirect()) {
154 codegen->GenerateStaticOrDirectCall(invoke_->AsInvokeStaticOrDirect(), EAX);
155 } else {
156 UNIMPLEMENTED(FATAL) << "Non-direct intrinsic slow-path not yet implemented";
157 UNREACHABLE();
158 }
159
160 // Copy the result back to the expected output.
161 Location out = invoke_->GetLocations()->Out();
162 if (out.IsValid()) {
163 DCHECK(out.IsRegister()); // TODO: Replace this when we support output in memory.
164 DCHECK(!invoke_->GetLocations()->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
165 MoveFromReturnRegister(out, invoke_->GetType(), codegen);
166 }
167
168 RestoreLiveRegisters(codegen, invoke_->GetLocations());
169 __ jmp(GetExitLabel());
170 }
171
172 private:
173 // The instruction where this slow path is happening.
174 HInvoke* const invoke_;
175
176 DISALLOW_COPY_AND_ASSIGN(IntrinsicSlowPathX86);
177};
178
179#undef __
180#define __ assembler->
181
182static void CreateFPToIntLocations(ArenaAllocator* arena, HInvoke* invoke, bool is64bit) {
183 LocationSummary* locations = new (arena) LocationSummary(invoke,
184 LocationSummary::kNoCall,
185 kIntrinsified);
186 locations->SetInAt(0, Location::RequiresFpuRegister());
187 locations->SetOut(Location::RequiresRegister());
188 if (is64bit) {
189 locations->AddTemp(Location::RequiresFpuRegister());
190 }
191}
192
193static void CreateIntToFPLocations(ArenaAllocator* arena, HInvoke* invoke, bool is64bit) {
194 LocationSummary* locations = new (arena) LocationSummary(invoke,
195 LocationSummary::kNoCall,
196 kIntrinsified);
197 locations->SetInAt(0, Location::RequiresRegister());
198 locations->SetOut(Location::RequiresFpuRegister());
199 if (is64bit) {
200 locations->AddTemp(Location::RequiresFpuRegister());
201 locations->AddTemp(Location::RequiresFpuRegister());
202 }
203}
204
205static void MoveFPToInt(LocationSummary* locations, bool is64bit, X86Assembler* assembler) {
206 Location input = locations->InAt(0);
207 Location output = locations->Out();
208 if (is64bit) {
209 // Need to use the temporary.
210 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
211 __ movsd(temp, input.AsFpuRegister<XmmRegister>());
212 __ movd(output.AsRegisterPairLow<Register>(), temp);
213 __ psrlq(temp, Immediate(32));
214 __ movd(output.AsRegisterPairHigh<Register>(), temp);
215 } else {
216 __ movd(output.AsRegister<Register>(), input.AsFpuRegister<XmmRegister>());
217 }
218}
219
220static void MoveIntToFP(LocationSummary* locations, bool is64bit, X86Assembler* assembler) {
221 Location input = locations->InAt(0);
222 Location output = locations->Out();
223 if (is64bit) {
224 // Need to use the temporary.
225 XmmRegister temp1 = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
226 XmmRegister temp2 = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
227 __ movd(temp1, input.AsRegisterPairLow<Register>());
228 __ movd(temp2, input.AsRegisterPairHigh<Register>());
229 __ punpckldq(temp1, temp2);
230 __ movsd(output.AsFpuRegister<XmmRegister>(), temp1);
231 } else {
232 __ movd(output.AsFpuRegister<XmmRegister>(), input.AsRegister<Register>());
233 }
234}
235
236void IntrinsicLocationsBuilderX86::VisitDoubleDoubleToRawLongBits(HInvoke* invoke) {
237 CreateFPToIntLocations(arena_, invoke, true);
238}
239void IntrinsicLocationsBuilderX86::VisitDoubleLongBitsToDouble(HInvoke* invoke) {
240 CreateIntToFPLocations(arena_, invoke, true);
241}
242
243void IntrinsicCodeGeneratorX86::VisitDoubleDoubleToRawLongBits(HInvoke* invoke) {
244 MoveFPToInt(invoke->GetLocations(), true, GetAssembler());
245}
246void IntrinsicCodeGeneratorX86::VisitDoubleLongBitsToDouble(HInvoke* invoke) {
247 MoveIntToFP(invoke->GetLocations(), true, GetAssembler());
248}
249
250void IntrinsicLocationsBuilderX86::VisitFloatFloatToRawIntBits(HInvoke* invoke) {
251 CreateFPToIntLocations(arena_, invoke, false);
252}
253void IntrinsicLocationsBuilderX86::VisitFloatIntBitsToFloat(HInvoke* invoke) {
254 CreateIntToFPLocations(arena_, invoke, false);
255}
256
257void IntrinsicCodeGeneratorX86::VisitFloatFloatToRawIntBits(HInvoke* invoke) {
258 MoveFPToInt(invoke->GetLocations(), false, GetAssembler());
259}
260void IntrinsicCodeGeneratorX86::VisitFloatIntBitsToFloat(HInvoke* invoke) {
261 MoveIntToFP(invoke->GetLocations(), false, GetAssembler());
262}
263
264static void CreateIntToIntLocations(ArenaAllocator* arena, HInvoke* invoke) {
265 LocationSummary* locations = new (arena) LocationSummary(invoke,
266 LocationSummary::kNoCall,
267 kIntrinsified);
268 locations->SetInAt(0, Location::RequiresRegister());
269 locations->SetOut(Location::SameAsFirstInput());
270}
271
272static void CreateLongToIntLocations(ArenaAllocator* arena, HInvoke* invoke) {
273 LocationSummary* locations = new (arena) LocationSummary(invoke,
274 LocationSummary::kNoCall,
275 kIntrinsified);
276 locations->SetInAt(0, Location::RequiresRegister());
277 locations->SetOut(Location::RequiresRegister());
278}
279
280static void CreateLongToLongLocations(ArenaAllocator* arena, HInvoke* invoke) {
281 LocationSummary* locations = new (arena) LocationSummary(invoke,
282 LocationSummary::kNoCall,
283 kIntrinsified);
284 locations->SetInAt(0, Location::RequiresRegister());
285 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
286}
287
288static void GenReverseBytes(LocationSummary* locations,
289 Primitive::Type size,
290 X86Assembler* assembler) {
291 Register out = locations->Out().AsRegister<Register>();
292
293 switch (size) {
294 case Primitive::kPrimShort:
295 // TODO: Can be done with an xchg of 8b registers. This is straight from Quick.
296 __ bswapl(out);
297 __ sarl(out, Immediate(16));
298 break;
299 case Primitive::kPrimInt:
300 __ bswapl(out);
301 break;
302 default:
303 LOG(FATAL) << "Unexpected size for reverse-bytes: " << size;
304 UNREACHABLE();
305 }
306}
307
308void IntrinsicLocationsBuilderX86::VisitIntegerReverseBytes(HInvoke* invoke) {
309 CreateIntToIntLocations(arena_, invoke);
310}
311
312void IntrinsicCodeGeneratorX86::VisitIntegerReverseBytes(HInvoke* invoke) {
313 GenReverseBytes(invoke->GetLocations(), Primitive::kPrimInt, GetAssembler());
314}
315
316void IntrinsicLocationsBuilderX86::VisitShortReverseBytes(HInvoke* invoke) {
317 CreateIntToIntLocations(arena_, invoke);
318}
319
320void IntrinsicCodeGeneratorX86::VisitShortReverseBytes(HInvoke* invoke) {
321 GenReverseBytes(invoke->GetLocations(), Primitive::kPrimShort, GetAssembler());
322}
323
324
325// TODO: Consider Quick's way of doing Double abs through integer operations, as the immediate we
326// need is 64b.
327
328static void CreateFloatToFloat(ArenaAllocator* arena, HInvoke* invoke) {
329 // TODO: Enable memory operations when the assembler supports them.
330 LocationSummary* locations = new (arena) LocationSummary(invoke,
331 LocationSummary::kNoCall,
332 kIntrinsified);
333 locations->SetInAt(0, Location::RequiresFpuRegister());
334 // TODO: Allow x86 to work with memory. This requires assembler support, see below.
335 // locations->SetInAt(0, Location::Any()); // X86 can work on memory directly.
336 locations->SetOut(Location::SameAsFirstInput());
337}
338
339static void MathAbsFP(LocationSummary* locations, bool is64bit, X86Assembler* assembler) {
340 Location output = locations->Out();
341
342 if (output.IsFpuRegister()) {
343 // Create the right constant on an aligned stack.
344 if (is64bit) {
345 __ subl(ESP, Immediate(8));
346 __ pushl(Immediate(0x7FFFFFFF));
347 __ pushl(Immediate(0xFFFFFFFF));
348 __ andpd(output.AsFpuRegister<XmmRegister>(), Address(ESP, 0));
349 } else {
350 __ subl(ESP, Immediate(12));
351 __ pushl(Immediate(0x7FFFFFFF));
352 __ andps(output.AsFpuRegister<XmmRegister>(), Address(ESP, 0));
353 }
354 __ addl(ESP, Immediate(16));
355 } else {
356 // TODO: update when assember support is available.
357 UNIMPLEMENTED(FATAL) << "Needs assembler support.";
358// Once assembler support is available, in-memory operations look like this:
359// if (is64bit) {
360// DCHECK(output.IsDoubleStackSlot());
361// __ andl(Address(Register(RSP), output.GetHighStackIndex(kX86WordSize)),
362// Immediate(0x7FFFFFFF));
363// } else {
364// DCHECK(output.IsStackSlot());
365// // Can use and with a literal directly.
366// __ andl(Address(Register(RSP), output.GetStackIndex()), Immediate(0x7FFFFFFF));
367// }
368 }
369}
370
371void IntrinsicLocationsBuilderX86::VisitMathAbsDouble(HInvoke* invoke) {
372 CreateFloatToFloat(arena_, invoke);
373}
374
375void IntrinsicCodeGeneratorX86::VisitMathAbsDouble(HInvoke* invoke) {
376 MathAbsFP(invoke->GetLocations(), true, GetAssembler());
377}
378
379void IntrinsicLocationsBuilderX86::VisitMathAbsFloat(HInvoke* invoke) {
380 CreateFloatToFloat(arena_, invoke);
381}
382
383void IntrinsicCodeGeneratorX86::VisitMathAbsFloat(HInvoke* invoke) {
384 MathAbsFP(invoke->GetLocations(), false, GetAssembler());
385}
386
387static void CreateAbsIntLocation(ArenaAllocator* arena, HInvoke* invoke) {
388 LocationSummary* locations = new (arena) LocationSummary(invoke,
389 LocationSummary::kNoCall,
390 kIntrinsified);
391 locations->SetInAt(0, Location::RegisterLocation(EAX));
392 locations->SetOut(Location::SameAsFirstInput());
393 locations->AddTemp(Location::RegisterLocation(EDX));
394}
395
396static void GenAbsInteger(LocationSummary* locations, X86Assembler* assembler) {
397 Location output = locations->Out();
398 Register out = output.AsRegister<Register>();
399 DCHECK_EQ(out, EAX);
400 Register temp = locations->GetTemp(0).AsRegister<Register>();
401 DCHECK_EQ(temp, EDX);
402
403 // Sign extend EAX into EDX.
404 __ cdq();
405
406 // XOR EAX with sign.
407 __ xorl(EAX, EDX);
408
409 // Subtract out sign to correct.
410 __ subl(EAX, EDX);
411
412 // The result is in EAX.
413}
414
415static void CreateAbsLongLocation(ArenaAllocator* arena, HInvoke* invoke) {
416 LocationSummary* locations = new (arena) LocationSummary(invoke,
417 LocationSummary::kNoCall,
418 kIntrinsified);
419 locations->SetInAt(0, Location::RequiresRegister());
420 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
421 locations->AddTemp(Location::RequiresRegister());
422}
423
424static void GenAbsLong(LocationSummary* locations, X86Assembler* assembler) {
425 Location input = locations->InAt(0);
426 Register input_lo = input.AsRegisterPairLow<Register>();
427 Register input_hi = input.AsRegisterPairHigh<Register>();
428 Location output = locations->Out();
429 Register output_lo = output.AsRegisterPairLow<Register>();
430 Register output_hi = output.AsRegisterPairHigh<Register>();
431 Register temp = locations->GetTemp(0).AsRegister<Register>();
432
433 // Compute the sign into the temporary.
434 __ movl(temp, input_hi);
435 __ sarl(temp, Immediate(31));
436
437 // Store the sign into the output.
438 __ movl(output_lo, temp);
439 __ movl(output_hi, temp);
440
441 // XOR the input to the output.
442 __ xorl(output_lo, input_lo);
443 __ xorl(output_hi, input_hi);
444
445 // Subtract the sign.
446 __ subl(output_lo, temp);
447 __ sbbl(output_hi, temp);
448}
449
450void IntrinsicLocationsBuilderX86::VisitMathAbsInt(HInvoke* invoke) {
451 CreateAbsIntLocation(arena_, invoke);
452}
453
454void IntrinsicCodeGeneratorX86::VisitMathAbsInt(HInvoke* invoke) {
455 GenAbsInteger(invoke->GetLocations(), GetAssembler());
456}
457
458void IntrinsicLocationsBuilderX86::VisitMathAbsLong(HInvoke* invoke) {
459 CreateAbsLongLocation(arena_, invoke);
460}
461
462void IntrinsicCodeGeneratorX86::VisitMathAbsLong(HInvoke* invoke) {
463 GenAbsLong(invoke->GetLocations(), GetAssembler());
464}
465
466static void GenMinMaxFP(LocationSummary* locations, bool is_min, bool is_double,
467 X86Assembler* assembler) {
468 Location op1_loc = locations->InAt(0);
469 Location op2_loc = locations->InAt(1);
470 Location out_loc = locations->Out();
471 XmmRegister out = out_loc.AsFpuRegister<XmmRegister>();
472
473 // Shortcut for same input locations.
474 if (op1_loc.Equals(op2_loc)) {
475 DCHECK(out_loc.Equals(op1_loc));
476 return;
477 }
478
479 // (out := op1)
480 // out <=? op2
481 // if Nan jmp Nan_label
482 // if out is min jmp done
483 // if op2 is min jmp op2_label
484 // handle -0/+0
485 // jmp done
486 // Nan_label:
487 // out := NaN
488 // op2_label:
489 // out := op2
490 // done:
491 //
492 // This removes one jmp, but needs to copy one input (op1) to out.
493 //
494 // TODO: This is straight from Quick (except literal pool). Make NaN an out-of-line slowpath?
495
496 XmmRegister op2 = op2_loc.AsFpuRegister<XmmRegister>();
497
498 Label nan, done, op2_label;
499 if (is_double) {
500 __ ucomisd(out, op2);
501 } else {
502 __ ucomiss(out, op2);
503 }
504
505 __ j(Condition::kParityEven, &nan);
506
507 __ j(is_min ? Condition::kAbove : Condition::kBelow, &op2_label);
508 __ j(is_min ? Condition::kBelow : Condition::kAbove, &done);
509
510 // Handle 0.0/-0.0.
511 if (is_min) {
512 if (is_double) {
513 __ orpd(out, op2);
514 } else {
515 __ orps(out, op2);
516 }
517 } else {
518 if (is_double) {
519 __ andpd(out, op2);
520 } else {
521 __ andps(out, op2);
522 }
523 }
524 __ jmp(&done);
525
526 // NaN handling.
527 __ Bind(&nan);
528 if (is_double) {
529 __ pushl(Immediate(kDoubleNaNHigh));
530 __ pushl(Immediate(kDoubleNaNLow));
531 __ movsd(out, Address(ESP, 0));
532 __ addl(ESP, Immediate(8));
533 } else {
534 __ pushl(Immediate(kFloatNaN));
535 __ movss(out, Address(ESP, 0));
536 __ addl(ESP, Immediate(4));
537 }
538 __ jmp(&done);
539
540 // out := op2;
541 __ Bind(&op2_label);
542 if (is_double) {
543 __ movsd(out, op2);
544 } else {
545 __ movss(out, op2);
546 }
547
548 // Done.
549 __ Bind(&done);
550}
551
552static void CreateFPFPToFPLocations(ArenaAllocator* arena, HInvoke* invoke) {
553 LocationSummary* locations = new (arena) LocationSummary(invoke,
554 LocationSummary::kNoCall,
555 kIntrinsified);
556 locations->SetInAt(0, Location::RequiresFpuRegister());
557 locations->SetInAt(1, Location::RequiresFpuRegister());
558 // The following is sub-optimal, but all we can do for now. It would be fine to also accept
559 // the second input to be the output (we can simply swap inputs).
560 locations->SetOut(Location::SameAsFirstInput());
561}
562
563void IntrinsicLocationsBuilderX86::VisitMathMinDoubleDouble(HInvoke* invoke) {
564 CreateFPFPToFPLocations(arena_, invoke);
565}
566
567void IntrinsicCodeGeneratorX86::VisitMathMinDoubleDouble(HInvoke* invoke) {
568 GenMinMaxFP(invoke->GetLocations(), true, true, GetAssembler());
569}
570
571void IntrinsicLocationsBuilderX86::VisitMathMinFloatFloat(HInvoke* invoke) {
572 CreateFPFPToFPLocations(arena_, invoke);
573}
574
575void IntrinsicCodeGeneratorX86::VisitMathMinFloatFloat(HInvoke* invoke) {
576 GenMinMaxFP(invoke->GetLocations(), true, false, GetAssembler());
577}
578
579void IntrinsicLocationsBuilderX86::VisitMathMaxDoubleDouble(HInvoke* invoke) {
580 CreateFPFPToFPLocations(arena_, invoke);
581}
582
583void IntrinsicCodeGeneratorX86::VisitMathMaxDoubleDouble(HInvoke* invoke) {
584 GenMinMaxFP(invoke->GetLocations(), false, true, GetAssembler());
585}
586
587void IntrinsicLocationsBuilderX86::VisitMathMaxFloatFloat(HInvoke* invoke) {
588 CreateFPFPToFPLocations(arena_, invoke);
589}
590
591void IntrinsicCodeGeneratorX86::VisitMathMaxFloatFloat(HInvoke* invoke) {
592 GenMinMaxFP(invoke->GetLocations(), false, false, GetAssembler());
593}
594
595static void GenMinMax(LocationSummary* locations, bool is_min, bool is_long,
596 X86Assembler* assembler) {
597 Location op1_loc = locations->InAt(0);
598 Location op2_loc = locations->InAt(1);
599
600 // Shortcut for same input locations.
601 if (op1_loc.Equals(op2_loc)) {
602 // Can return immediately, as op1_loc == out_loc.
603 // Note: if we ever support separate registers, e.g., output into memory, we need to check for
604 // a copy here.
605 DCHECK(locations->Out().Equals(op1_loc));
606 return;
607 }
608
609 if (is_long) {
610 // Need to perform a subtract to get the sign right.
611 // op1 is already in the same location as the output.
612 Location output = locations->Out();
613 Register output_lo = output.AsRegisterPairLow<Register>();
614 Register output_hi = output.AsRegisterPairHigh<Register>();
615
616 Register op2_lo = op2_loc.AsRegisterPairLow<Register>();
617 Register op2_hi = op2_loc.AsRegisterPairHigh<Register>();
618
619 // Spare register to compute the subtraction to set condition code.
620 Register temp = locations->GetTemp(0).AsRegister<Register>();
621
622 // Subtract off op2_low.
623 __ movl(temp, output_lo);
624 __ subl(temp, op2_lo);
625
626 // Now use the same tempo and the borrow to finish the subtraction of op2_hi.
627 __ movl(temp, output_hi);
628 __ sbbl(temp, op2_hi);
629
630 // Now the condition code is correct.
631 Condition cond = is_min ? Condition::kGreaterEqual : Condition::kLess;
632 __ cmovl(cond, output_lo, op2_lo);
633 __ cmovl(cond, output_hi, op2_hi);
634 } else {
635 Register out = locations->Out().AsRegister<Register>();
636 Register op2 = op2_loc.AsRegister<Register>();
637
638 // (out := op1)
639 // out <=? op2
640 // if out is min jmp done
641 // out := op2
642 // done:
643
644 __ cmpl(out, op2);
645 Condition cond = is_min ? Condition::kGreater : Condition::kLess;
646 __ cmovl(cond, out, op2);
647 }
648}
649
650static void CreateIntIntToIntLocations(ArenaAllocator* arena, HInvoke* invoke) {
651 LocationSummary* locations = new (arena) LocationSummary(invoke,
652 LocationSummary::kNoCall,
653 kIntrinsified);
654 locations->SetInAt(0, Location::RequiresRegister());
655 locations->SetInAt(1, Location::RequiresRegister());
656 locations->SetOut(Location::SameAsFirstInput());
657}
658
659static void CreateLongLongToLongLocations(ArenaAllocator* arena, HInvoke* invoke) {
660 LocationSummary* locations = new (arena) LocationSummary(invoke,
661 LocationSummary::kNoCall,
662 kIntrinsified);
663 locations->SetInAt(0, Location::RequiresRegister());
664 locations->SetInAt(1, Location::RequiresRegister());
665 locations->SetOut(Location::SameAsFirstInput());
666 // Register to use to perform a long subtract to set cc.
667 locations->AddTemp(Location::RequiresRegister());
668}
669
670void IntrinsicLocationsBuilderX86::VisitMathMinIntInt(HInvoke* invoke) {
671 CreateIntIntToIntLocations(arena_, invoke);
672}
673
674void IntrinsicCodeGeneratorX86::VisitMathMinIntInt(HInvoke* invoke) {
675 GenMinMax(invoke->GetLocations(), true, false, GetAssembler());
676}
677
678void IntrinsicLocationsBuilderX86::VisitMathMinLongLong(HInvoke* invoke) {
679 CreateLongLongToLongLocations(arena_, invoke);
680}
681
682void IntrinsicCodeGeneratorX86::VisitMathMinLongLong(HInvoke* invoke) {
683 GenMinMax(invoke->GetLocations(), true, true, GetAssembler());
684}
685
686void IntrinsicLocationsBuilderX86::VisitMathMaxIntInt(HInvoke* invoke) {
687 CreateIntIntToIntLocations(arena_, invoke);
688}
689
690void IntrinsicCodeGeneratorX86::VisitMathMaxIntInt(HInvoke* invoke) {
691 GenMinMax(invoke->GetLocations(), false, false, GetAssembler());
692}
693
694void IntrinsicLocationsBuilderX86::VisitMathMaxLongLong(HInvoke* invoke) {
695 CreateLongLongToLongLocations(arena_, invoke);
696}
697
698void IntrinsicCodeGeneratorX86::VisitMathMaxLongLong(HInvoke* invoke) {
699 GenMinMax(invoke->GetLocations(), false, true, GetAssembler());
700}
701
702static void CreateFPToFPLocations(ArenaAllocator* arena, HInvoke* invoke) {
703 LocationSummary* locations = new (arena) LocationSummary(invoke,
704 LocationSummary::kNoCall,
705 kIntrinsified);
706 locations->SetInAt(0, Location::RequiresFpuRegister());
707 locations->SetOut(Location::RequiresFpuRegister());
708}
709
710void IntrinsicLocationsBuilderX86::VisitMathSqrt(HInvoke* invoke) {
711 CreateFPToFPLocations(arena_, invoke);
712}
713
714void IntrinsicCodeGeneratorX86::VisitMathSqrt(HInvoke* invoke) {
715 LocationSummary* locations = invoke->GetLocations();
716 XmmRegister in = locations->InAt(0).AsFpuRegister<XmmRegister>();
717 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
718
719 GetAssembler()->sqrtsd(out, in);
720}
721
722void IntrinsicLocationsBuilderX86::VisitStringCharAt(HInvoke* invoke) {
723 // The inputs plus one temp.
724 LocationSummary* locations = new (arena_) LocationSummary(invoke,
725 LocationSummary::kCallOnSlowPath,
726 kIntrinsified);
727 locations->SetInAt(0, Location::RequiresRegister());
728 locations->SetInAt(1, Location::RequiresRegister());
729 locations->SetOut(Location::SameAsFirstInput());
730 // Needs to be EAX for the invoke.
731 locations->AddTemp(Location::RegisterLocation(EAX));
732}
733
734void IntrinsicCodeGeneratorX86::VisitStringCharAt(HInvoke* invoke) {
735 LocationSummary* locations = invoke->GetLocations();
736
737 // Location of reference to data array
738 const int32_t value_offset = mirror::String::ValueOffset().Int32Value();
739 // Location of count
740 const int32_t count_offset = mirror::String::CountOffset().Int32Value();
741 // Starting offset within data array
742 const int32_t offset_offset = mirror::String::OffsetOffset().Int32Value();
743 // Start of char data with array_
744 const int32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Int32Value();
745
746 Register obj = locations->InAt(0).AsRegister<Register>();
747 Register idx = locations->InAt(1).AsRegister<Register>();
748 Register out = locations->Out().AsRegister<Register>();
749 Location temp_loc = locations->GetTemp(0);
750 Register temp = temp_loc.AsRegister<Register>();
751
752 // TODO: Maybe we can support range check elimination. Overall, though, I think it's not worth
753 // the cost.
754 // TODO: For simplicity, the index parameter is requested in a register, so different from Quick
755 // we will not optimize the code for constants (which would save a register).
756
757 SlowPathCodeX86* slow_path = new (GetAllocator()) IntrinsicSlowPathX86(invoke, temp);
758 codegen_->AddSlowPath(slow_path);
759
760 X86Assembler* assembler = GetAssembler();
761
762 __ cmpl(idx, Address(obj, count_offset));
763 codegen_->MaybeRecordImplicitNullCheck(invoke);
764 __ j(kAboveEqual, slow_path->GetEntryLabel());
765
766 // Get the actual element.
767 __ movl(temp, idx); // temp := idx.
768 __ addl(temp, Address(obj, offset_offset)); // temp := offset + idx.
769 __ movl(out, Address(obj, value_offset)); // obj := obj.array.
770 // out = out[2*temp].
771 __ movzxw(out, Address(out, temp, ScaleFactor::TIMES_2, data_offset));
772
773 __ Bind(slow_path->GetExitLabel());
774}
775
Nicolas Geoffrayd75948a2015-03-27 09:53:16 +0000776void IntrinsicLocationsBuilderX86::VisitStringCompareTo(HInvoke* invoke) {
777 // The inputs plus one temp.
778 LocationSummary* locations = new (arena_) LocationSummary(invoke,
779 LocationSummary::kCall,
780 kIntrinsified);
781 InvokeRuntimeCallingConvention calling_convention;
782 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
783 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
784 locations->SetOut(Location::RegisterLocation(EAX));
785 // Needs to be EAX for the invoke.
786 locations->AddTemp(Location::RegisterLocation(EAX));
787}
788
789void IntrinsicCodeGeneratorX86::VisitStringCompareTo(HInvoke* invoke) {
790 X86Assembler* assembler = GetAssembler();
791 LocationSummary* locations = invoke->GetLocations();
792
Nicolas Geoffray512e04d2015-03-27 17:21:24 +0000793 // Note that the null check must have been done earlier.
Nicolas Geoffrayd75948a2015-03-27 09:53:16 +0000794 DCHECK(!invoke->CanDoImplicitNullCheck());
795
796 Register argument = locations->InAt(1).AsRegister<Register>();
797 __ testl(argument, argument);
798 SlowPathCodeX86* slow_path = new (GetAllocator()) IntrinsicSlowPathX86(
799 invoke, locations->GetTemp(0).AsRegister<Register>());
800 codegen_->AddSlowPath(slow_path);
801 __ j(kEqual, slow_path->GetEntryLabel());
802
803 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pStringCompareTo)));
804 __ Bind(slow_path->GetExitLabel());
805}
806
Mark Mendell09ed1a32015-03-25 08:30:06 -0400807static void GenPeek(LocationSummary* locations, Primitive::Type size, X86Assembler* assembler) {
808 Register address = locations->InAt(0).AsRegisterPairLow<Register>();
809 Location out_loc = locations->Out();
810 // x86 allows unaligned access. We do not have to check the input or use specific instructions
811 // to avoid a SIGBUS.
812 switch (size) {
813 case Primitive::kPrimByte:
814 __ movsxb(out_loc.AsRegister<Register>(), Address(address, 0));
815 break;
816 case Primitive::kPrimShort:
817 __ movsxw(out_loc.AsRegister<Register>(), Address(address, 0));
818 break;
819 case Primitive::kPrimInt:
820 __ movl(out_loc.AsRegister<Register>(), Address(address, 0));
821 break;
822 case Primitive::kPrimLong:
823 __ movl(out_loc.AsRegisterPairLow<Register>(), Address(address, 0));
824 __ movl(out_loc.AsRegisterPairHigh<Register>(), Address(address, 4));
825 break;
826 default:
827 LOG(FATAL) << "Type not recognized for peek: " << size;
828 UNREACHABLE();
829 }
830}
831
832void IntrinsicLocationsBuilderX86::VisitMemoryPeekByte(HInvoke* invoke) {
833 CreateLongToIntLocations(arena_, invoke);
834}
835
836void IntrinsicCodeGeneratorX86::VisitMemoryPeekByte(HInvoke* invoke) {
837 GenPeek(invoke->GetLocations(), Primitive::kPrimByte, GetAssembler());
838}
839
840void IntrinsicLocationsBuilderX86::VisitMemoryPeekIntNative(HInvoke* invoke) {
841 CreateLongToIntLocations(arena_, invoke);
842}
843
844void IntrinsicCodeGeneratorX86::VisitMemoryPeekIntNative(HInvoke* invoke) {
845 GenPeek(invoke->GetLocations(), Primitive::kPrimInt, GetAssembler());
846}
847
848void IntrinsicLocationsBuilderX86::VisitMemoryPeekLongNative(HInvoke* invoke) {
849 CreateLongToLongLocations(arena_, invoke);
850}
851
852void IntrinsicCodeGeneratorX86::VisitMemoryPeekLongNative(HInvoke* invoke) {
853 GenPeek(invoke->GetLocations(), Primitive::kPrimLong, GetAssembler());
854}
855
856void IntrinsicLocationsBuilderX86::VisitMemoryPeekShortNative(HInvoke* invoke) {
857 CreateLongToIntLocations(arena_, invoke);
858}
859
860void IntrinsicCodeGeneratorX86::VisitMemoryPeekShortNative(HInvoke* invoke) {
861 GenPeek(invoke->GetLocations(), Primitive::kPrimShort, GetAssembler());
862}
863
864static void CreateLongIntToVoidLocations(ArenaAllocator* arena, Primitive::Type size,
865 HInvoke* invoke) {
866 LocationSummary* locations = new (arena) LocationSummary(invoke,
867 LocationSummary::kNoCall,
868 kIntrinsified);
869 locations->SetInAt(0, Location::RequiresRegister());
870 HInstruction *value = invoke->InputAt(1);
871 if (size == Primitive::kPrimByte) {
872 locations->SetInAt(1, Location::ByteRegisterOrConstant(EDX, value));
873 } else {
874 locations->SetInAt(1, Location::RegisterOrConstant(value));
875 }
876}
877
878static void GenPoke(LocationSummary* locations, Primitive::Type size, X86Assembler* assembler) {
879 Register address = locations->InAt(0).AsRegisterPairLow<Register>();
880 Location value_loc = locations->InAt(1);
881 // x86 allows unaligned access. We do not have to check the input or use specific instructions
882 // to avoid a SIGBUS.
883 switch (size) {
884 case Primitive::kPrimByte:
885 if (value_loc.IsConstant()) {
886 __ movb(Address(address, 0),
887 Immediate(value_loc.GetConstant()->AsIntConstant()->GetValue()));
888 } else {
889 __ movb(Address(address, 0), value_loc.AsRegister<ByteRegister>());
890 }
891 break;
892 case Primitive::kPrimShort:
893 if (value_loc.IsConstant()) {
894 __ movw(Address(address, 0),
895 Immediate(value_loc.GetConstant()->AsIntConstant()->GetValue()));
896 } else {
897 __ movw(Address(address, 0), value_loc.AsRegister<Register>());
898 }
899 break;
900 case Primitive::kPrimInt:
901 if (value_loc.IsConstant()) {
902 __ movl(Address(address, 0),
903 Immediate(value_loc.GetConstant()->AsIntConstant()->GetValue()));
904 } else {
905 __ movl(Address(address, 0), value_loc.AsRegister<Register>());
906 }
907 break;
908 case Primitive::kPrimLong:
909 if (value_loc.IsConstant()) {
910 int64_t value = value_loc.GetConstant()->AsLongConstant()->GetValue();
911 __ movl(Address(address, 0), Immediate(Low32Bits(value)));
912 __ movl(Address(address, 4), Immediate(High32Bits(value)));
913 } else {
914 __ movl(Address(address, 0), value_loc.AsRegisterPairLow<Register>());
915 __ movl(Address(address, 4), value_loc.AsRegisterPairHigh<Register>());
916 }
917 break;
918 default:
919 LOG(FATAL) << "Type not recognized for poke: " << size;
920 UNREACHABLE();
921 }
922}
923
924void IntrinsicLocationsBuilderX86::VisitMemoryPokeByte(HInvoke* invoke) {
925 CreateLongIntToVoidLocations(arena_, Primitive::kPrimByte, invoke);
926}
927
928void IntrinsicCodeGeneratorX86::VisitMemoryPokeByte(HInvoke* invoke) {
929 GenPoke(invoke->GetLocations(), Primitive::kPrimByte, GetAssembler());
930}
931
932void IntrinsicLocationsBuilderX86::VisitMemoryPokeIntNative(HInvoke* invoke) {
933 CreateLongIntToVoidLocations(arena_, Primitive::kPrimInt, invoke);
934}
935
936void IntrinsicCodeGeneratorX86::VisitMemoryPokeIntNative(HInvoke* invoke) {
937 GenPoke(invoke->GetLocations(), Primitive::kPrimInt, GetAssembler());
938}
939
940void IntrinsicLocationsBuilderX86::VisitMemoryPokeLongNative(HInvoke* invoke) {
941 CreateLongIntToVoidLocations(arena_, Primitive::kPrimLong, invoke);
942}
943
944void IntrinsicCodeGeneratorX86::VisitMemoryPokeLongNative(HInvoke* invoke) {
945 GenPoke(invoke->GetLocations(), Primitive::kPrimLong, GetAssembler());
946}
947
948void IntrinsicLocationsBuilderX86::VisitMemoryPokeShortNative(HInvoke* invoke) {
949 CreateLongIntToVoidLocations(arena_, Primitive::kPrimShort, invoke);
950}
951
952void IntrinsicCodeGeneratorX86::VisitMemoryPokeShortNative(HInvoke* invoke) {
953 GenPoke(invoke->GetLocations(), Primitive::kPrimShort, GetAssembler());
954}
955
956void IntrinsicLocationsBuilderX86::VisitThreadCurrentThread(HInvoke* invoke) {
957 LocationSummary* locations = new (arena_) LocationSummary(invoke,
958 LocationSummary::kNoCall,
959 kIntrinsified);
960 locations->SetOut(Location::RequiresRegister());
961}
962
963void IntrinsicCodeGeneratorX86::VisitThreadCurrentThread(HInvoke* invoke) {
964 Register out = invoke->GetLocations()->Out().AsRegister<Register>();
965 GetAssembler()->fs()->movl(out, Address::Absolute(Thread::PeerOffset<kX86WordSize>()));
966}
967
968static void GenUnsafeGet(LocationSummary* locations, Primitive::Type type,
969 bool is_volatile, X86Assembler* assembler) {
970 Register base = locations->InAt(1).AsRegister<Register>();
971 Register offset = locations->InAt(2).AsRegisterPairLow<Register>();
972 Location output = locations->Out();
973
974 switch (type) {
975 case Primitive::kPrimInt:
976 case Primitive::kPrimNot:
977 __ movl(output.AsRegister<Register>(), Address(base, offset, ScaleFactor::TIMES_1, 0));
978 break;
979
980 case Primitive::kPrimLong: {
981 Register output_lo = output.AsRegisterPairLow<Register>();
982 Register output_hi = output.AsRegisterPairHigh<Register>();
983 if (is_volatile) {
984 // Need to use a XMM to read atomically.
985 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
986 __ movsd(temp, Address(base, offset, ScaleFactor::TIMES_1, 0));
987 __ movd(output_lo, temp);
988 __ psrlq(temp, Immediate(32));
989 __ movd(output_hi, temp);
990 } else {
991 __ movl(output_lo, Address(base, offset, ScaleFactor::TIMES_1, 0));
992 __ movl(output_hi, Address(base, offset, ScaleFactor::TIMES_1, 4));
993 }
994 }
995 break;
996
997 default:
998 LOG(FATAL) << "Unsupported op size " << type;
999 UNREACHABLE();
1000 }
1001}
1002
1003static void CreateIntIntIntToIntLocations(ArenaAllocator* arena, HInvoke* invoke,
1004 bool is_long, bool is_volatile) {
1005 LocationSummary* locations = new (arena) LocationSummary(invoke,
1006 LocationSummary::kNoCall,
1007 kIntrinsified);
1008 locations->SetInAt(0, Location::NoLocation()); // Unused receiver.
1009 locations->SetInAt(1, Location::RequiresRegister());
1010 locations->SetInAt(2, Location::RequiresRegister());
1011 if (is_long) {
1012 if (is_volatile) {
1013 // Need to use XMM to read volatile.
1014 locations->AddTemp(Location::RequiresFpuRegister());
1015 locations->SetOut(Location::RequiresRegister());
1016 } else {
1017 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
1018 }
1019 } else {
1020 locations->SetOut(Location::RequiresRegister());
1021 }
1022}
1023
1024void IntrinsicLocationsBuilderX86::VisitUnsafeGet(HInvoke* invoke) {
1025 CreateIntIntIntToIntLocations(arena_, invoke, false, false);
1026}
1027void IntrinsicLocationsBuilderX86::VisitUnsafeGetVolatile(HInvoke* invoke) {
1028 CreateIntIntIntToIntLocations(arena_, invoke, false, true);
1029}
1030void IntrinsicLocationsBuilderX86::VisitUnsafeGetLong(HInvoke* invoke) {
1031 CreateIntIntIntToIntLocations(arena_, invoke, false, false);
1032}
1033void IntrinsicLocationsBuilderX86::VisitUnsafeGetLongVolatile(HInvoke* invoke) {
1034 CreateIntIntIntToIntLocations(arena_, invoke, true, true);
1035}
1036void IntrinsicLocationsBuilderX86::VisitUnsafeGetObject(HInvoke* invoke) {
1037 CreateIntIntIntToIntLocations(arena_, invoke, false, false);
1038}
1039void IntrinsicLocationsBuilderX86::VisitUnsafeGetObjectVolatile(HInvoke* invoke) {
1040 CreateIntIntIntToIntLocations(arena_, invoke, false, true);
1041}
1042
1043
1044void IntrinsicCodeGeneratorX86::VisitUnsafeGet(HInvoke* invoke) {
1045 GenUnsafeGet(invoke->GetLocations(), Primitive::kPrimInt, false, GetAssembler());
1046}
1047void IntrinsicCodeGeneratorX86::VisitUnsafeGetVolatile(HInvoke* invoke) {
1048 GenUnsafeGet(invoke->GetLocations(), Primitive::kPrimInt, true, GetAssembler());
1049}
1050void IntrinsicCodeGeneratorX86::VisitUnsafeGetLong(HInvoke* invoke) {
1051 GenUnsafeGet(invoke->GetLocations(), Primitive::kPrimLong, false, GetAssembler());
1052}
1053void IntrinsicCodeGeneratorX86::VisitUnsafeGetLongVolatile(HInvoke* invoke) {
1054 GenUnsafeGet(invoke->GetLocations(), Primitive::kPrimLong, true, GetAssembler());
1055}
1056void IntrinsicCodeGeneratorX86::VisitUnsafeGetObject(HInvoke* invoke) {
1057 GenUnsafeGet(invoke->GetLocations(), Primitive::kPrimNot, false, GetAssembler());
1058}
1059void IntrinsicCodeGeneratorX86::VisitUnsafeGetObjectVolatile(HInvoke* invoke) {
1060 GenUnsafeGet(invoke->GetLocations(), Primitive::kPrimNot, true, GetAssembler());
1061}
1062
1063
1064static void CreateIntIntIntIntToVoidPlusTempsLocations(ArenaAllocator* arena,
1065 Primitive::Type type,
1066 HInvoke* invoke,
1067 bool is_volatile) {
1068 LocationSummary* locations = new (arena) LocationSummary(invoke,
1069 LocationSummary::kNoCall,
1070 kIntrinsified);
1071 locations->SetInAt(0, Location::NoLocation()); // Unused receiver.
1072 locations->SetInAt(1, Location::RequiresRegister());
1073 locations->SetInAt(2, Location::RequiresRegister());
1074 locations->SetInAt(3, Location::RequiresRegister());
1075 if (type == Primitive::kPrimNot) {
1076 // Need temp registers for card-marking.
1077 locations->AddTemp(Location::RequiresRegister());
1078 // Ensure the value is in a byte register.
1079 locations->AddTemp(Location::RegisterLocation(ECX));
1080 } else if (type == Primitive::kPrimLong && is_volatile) {
1081 locations->AddTemp(Location::RequiresFpuRegister());
1082 locations->AddTemp(Location::RequiresFpuRegister());
1083 }
1084}
1085
1086void IntrinsicLocationsBuilderX86::VisitUnsafePut(HInvoke* invoke) {
1087 CreateIntIntIntIntToVoidPlusTempsLocations(arena_, Primitive::kPrimInt, invoke, false);
1088}
1089void IntrinsicLocationsBuilderX86::VisitUnsafePutOrdered(HInvoke* invoke) {
1090 CreateIntIntIntIntToVoidPlusTempsLocations(arena_, Primitive::kPrimInt, invoke, false);
1091}
1092void IntrinsicLocationsBuilderX86::VisitUnsafePutVolatile(HInvoke* invoke) {
1093 CreateIntIntIntIntToVoidPlusTempsLocations(arena_, Primitive::kPrimInt, invoke, true);
1094}
1095void IntrinsicLocationsBuilderX86::VisitUnsafePutObject(HInvoke* invoke) {
1096 CreateIntIntIntIntToVoidPlusTempsLocations(arena_, Primitive::kPrimNot, invoke, false);
1097}
1098void IntrinsicLocationsBuilderX86::VisitUnsafePutObjectOrdered(HInvoke* invoke) {
1099 CreateIntIntIntIntToVoidPlusTempsLocations(arena_, Primitive::kPrimNot, invoke, false);
1100}
1101void IntrinsicLocationsBuilderX86::VisitUnsafePutObjectVolatile(HInvoke* invoke) {
1102 CreateIntIntIntIntToVoidPlusTempsLocations(arena_, Primitive::kPrimNot, invoke, true);
1103}
1104void IntrinsicLocationsBuilderX86::VisitUnsafePutLong(HInvoke* invoke) {
1105 CreateIntIntIntIntToVoidPlusTempsLocations(arena_, Primitive::kPrimLong, invoke, false);
1106}
1107void IntrinsicLocationsBuilderX86::VisitUnsafePutLongOrdered(HInvoke* invoke) {
1108 CreateIntIntIntIntToVoidPlusTempsLocations(arena_, Primitive::kPrimLong, invoke, false);
1109}
1110void IntrinsicLocationsBuilderX86::VisitUnsafePutLongVolatile(HInvoke* invoke) {
1111 CreateIntIntIntIntToVoidPlusTempsLocations(arena_, Primitive::kPrimLong, invoke, true);
1112}
1113
1114// We don't care for ordered: it requires an AnyStore barrier, which is already given by the x86
1115// memory model.
1116static void GenUnsafePut(LocationSummary* locations,
1117 Primitive::Type type,
1118 bool is_volatile,
1119 CodeGeneratorX86* codegen) {
1120 X86Assembler* assembler = reinterpret_cast<X86Assembler*>(codegen->GetAssembler());
1121 Register base = locations->InAt(1).AsRegister<Register>();
1122 Register offset = locations->InAt(2).AsRegisterPairLow<Register>();
1123 Location value_loc = locations->InAt(3);
1124
1125 if (type == Primitive::kPrimLong) {
1126 Register value_lo = value_loc.AsRegisterPairLow<Register>();
1127 Register value_hi = value_loc.AsRegisterPairHigh<Register>();
1128 if (is_volatile) {
1129 XmmRegister temp1 = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
1130 XmmRegister temp2 = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
1131 __ movd(temp1, value_lo);
1132 __ movd(temp2, value_hi);
1133 __ punpckldq(temp1, temp2);
1134 __ movsd(Address(base, offset, ScaleFactor::TIMES_1, 0), temp1);
1135 } else {
1136 __ movl(Address(base, offset, ScaleFactor::TIMES_1, 0), value_lo);
1137 __ movl(Address(base, offset, ScaleFactor::TIMES_1, 4), value_hi);
1138 }
1139 } else {
1140 __ movl(Address(base, offset, ScaleFactor::TIMES_1, 0), value_loc.AsRegister<Register>());
1141 }
1142
1143 if (is_volatile) {
1144 __ mfence();
1145 }
1146
1147 if (type == Primitive::kPrimNot) {
1148 codegen->MarkGCCard(locations->GetTemp(0).AsRegister<Register>(),
1149 locations->GetTemp(1).AsRegister<Register>(),
1150 base,
1151 value_loc.AsRegister<Register>());
1152 }
1153}
1154
1155void IntrinsicCodeGeneratorX86::VisitUnsafePut(HInvoke* invoke) {
1156 GenUnsafePut(invoke->GetLocations(), Primitive::kPrimInt, false, codegen_);
1157}
1158void IntrinsicCodeGeneratorX86::VisitUnsafePutOrdered(HInvoke* invoke) {
1159 GenUnsafePut(invoke->GetLocations(), Primitive::kPrimInt, false, codegen_);
1160}
1161void IntrinsicCodeGeneratorX86::VisitUnsafePutVolatile(HInvoke* invoke) {
1162 GenUnsafePut(invoke->GetLocations(), Primitive::kPrimInt, true, codegen_);
1163}
1164void IntrinsicCodeGeneratorX86::VisitUnsafePutObject(HInvoke* invoke) {
1165 GenUnsafePut(invoke->GetLocations(), Primitive::kPrimNot, false, codegen_);
1166}
1167void IntrinsicCodeGeneratorX86::VisitUnsafePutObjectOrdered(HInvoke* invoke) {
1168 GenUnsafePut(invoke->GetLocations(), Primitive::kPrimNot, false, codegen_);
1169}
1170void IntrinsicCodeGeneratorX86::VisitUnsafePutObjectVolatile(HInvoke* invoke) {
1171 GenUnsafePut(invoke->GetLocations(), Primitive::kPrimNot, true, codegen_);
1172}
1173void IntrinsicCodeGeneratorX86::VisitUnsafePutLong(HInvoke* invoke) {
1174 GenUnsafePut(invoke->GetLocations(), Primitive::kPrimLong, false, codegen_);
1175}
1176void IntrinsicCodeGeneratorX86::VisitUnsafePutLongOrdered(HInvoke* invoke) {
1177 GenUnsafePut(invoke->GetLocations(), Primitive::kPrimLong, false, codegen_);
1178}
1179void IntrinsicCodeGeneratorX86::VisitUnsafePutLongVolatile(HInvoke* invoke) {
1180 GenUnsafePut(invoke->GetLocations(), Primitive::kPrimLong, true, codegen_);
1181}
1182
1183// Unimplemented intrinsics.
1184
1185#define UNIMPLEMENTED_INTRINSIC(Name) \
1186void IntrinsicLocationsBuilderX86::Visit ## Name(HInvoke* invoke ATTRIBUTE_UNUSED) { \
1187} \
1188void IntrinsicCodeGeneratorX86::Visit ## Name(HInvoke* invoke ATTRIBUTE_UNUSED) { \
1189}
1190
1191UNIMPLEMENTED_INTRINSIC(IntegerReverse)
1192UNIMPLEMENTED_INTRINSIC(LongReverse)
1193UNIMPLEMENTED_INTRINSIC(LongReverseBytes)
1194UNIMPLEMENTED_INTRINSIC(MathFloor)
1195UNIMPLEMENTED_INTRINSIC(MathCeil)
1196UNIMPLEMENTED_INTRINSIC(MathRint)
1197UNIMPLEMENTED_INTRINSIC(MathRoundDouble)
1198UNIMPLEMENTED_INTRINSIC(MathRoundFloat)
Mark Mendell09ed1a32015-03-25 08:30:06 -04001199UNIMPLEMENTED_INTRINSIC(StringIndexOf)
1200UNIMPLEMENTED_INTRINSIC(StringIndexOfAfter)
1201UNIMPLEMENTED_INTRINSIC(SystemArrayCopyChar)
1202UNIMPLEMENTED_INTRINSIC(UnsafeCASInt)
1203UNIMPLEMENTED_INTRINSIC(UnsafeCASLong)
1204UNIMPLEMENTED_INTRINSIC(UnsafeCASObject)
1205UNIMPLEMENTED_INTRINSIC(ReferenceGetReferent)
1206
1207} // namespace x86
1208} // namespace art