blob: bcf947fa52951d952a7d8a81548070ffd7ef6b37 [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
776static void GenPeek(LocationSummary* locations, Primitive::Type size, X86Assembler* assembler) {
777 Register address = locations->InAt(0).AsRegisterPairLow<Register>();
778 Location out_loc = locations->Out();
779 // x86 allows unaligned access. We do not have to check the input or use specific instructions
780 // to avoid a SIGBUS.
781 switch (size) {
782 case Primitive::kPrimByte:
783 __ movsxb(out_loc.AsRegister<Register>(), Address(address, 0));
784 break;
785 case Primitive::kPrimShort:
786 __ movsxw(out_loc.AsRegister<Register>(), Address(address, 0));
787 break;
788 case Primitive::kPrimInt:
789 __ movl(out_loc.AsRegister<Register>(), Address(address, 0));
790 break;
791 case Primitive::kPrimLong:
792 __ movl(out_loc.AsRegisterPairLow<Register>(), Address(address, 0));
793 __ movl(out_loc.AsRegisterPairHigh<Register>(), Address(address, 4));
794 break;
795 default:
796 LOG(FATAL) << "Type not recognized for peek: " << size;
797 UNREACHABLE();
798 }
799}
800
801void IntrinsicLocationsBuilderX86::VisitMemoryPeekByte(HInvoke* invoke) {
802 CreateLongToIntLocations(arena_, invoke);
803}
804
805void IntrinsicCodeGeneratorX86::VisitMemoryPeekByte(HInvoke* invoke) {
806 GenPeek(invoke->GetLocations(), Primitive::kPrimByte, GetAssembler());
807}
808
809void IntrinsicLocationsBuilderX86::VisitMemoryPeekIntNative(HInvoke* invoke) {
810 CreateLongToIntLocations(arena_, invoke);
811}
812
813void IntrinsicCodeGeneratorX86::VisitMemoryPeekIntNative(HInvoke* invoke) {
814 GenPeek(invoke->GetLocations(), Primitive::kPrimInt, GetAssembler());
815}
816
817void IntrinsicLocationsBuilderX86::VisitMemoryPeekLongNative(HInvoke* invoke) {
818 CreateLongToLongLocations(arena_, invoke);
819}
820
821void IntrinsicCodeGeneratorX86::VisitMemoryPeekLongNative(HInvoke* invoke) {
822 GenPeek(invoke->GetLocations(), Primitive::kPrimLong, GetAssembler());
823}
824
825void IntrinsicLocationsBuilderX86::VisitMemoryPeekShortNative(HInvoke* invoke) {
826 CreateLongToIntLocations(arena_, invoke);
827}
828
829void IntrinsicCodeGeneratorX86::VisitMemoryPeekShortNative(HInvoke* invoke) {
830 GenPeek(invoke->GetLocations(), Primitive::kPrimShort, GetAssembler());
831}
832
833static void CreateLongIntToVoidLocations(ArenaAllocator* arena, Primitive::Type size,
834 HInvoke* invoke) {
835 LocationSummary* locations = new (arena) LocationSummary(invoke,
836 LocationSummary::kNoCall,
837 kIntrinsified);
838 locations->SetInAt(0, Location::RequiresRegister());
839 HInstruction *value = invoke->InputAt(1);
840 if (size == Primitive::kPrimByte) {
841 locations->SetInAt(1, Location::ByteRegisterOrConstant(EDX, value));
842 } else {
843 locations->SetInAt(1, Location::RegisterOrConstant(value));
844 }
845}
846
847static void GenPoke(LocationSummary* locations, Primitive::Type size, X86Assembler* assembler) {
848 Register address = locations->InAt(0).AsRegisterPairLow<Register>();
849 Location value_loc = locations->InAt(1);
850 // x86 allows unaligned access. We do not have to check the input or use specific instructions
851 // to avoid a SIGBUS.
852 switch (size) {
853 case Primitive::kPrimByte:
854 if (value_loc.IsConstant()) {
855 __ movb(Address(address, 0),
856 Immediate(value_loc.GetConstant()->AsIntConstant()->GetValue()));
857 } else {
858 __ movb(Address(address, 0), value_loc.AsRegister<ByteRegister>());
859 }
860 break;
861 case Primitive::kPrimShort:
862 if (value_loc.IsConstant()) {
863 __ movw(Address(address, 0),
864 Immediate(value_loc.GetConstant()->AsIntConstant()->GetValue()));
865 } else {
866 __ movw(Address(address, 0), value_loc.AsRegister<Register>());
867 }
868 break;
869 case Primitive::kPrimInt:
870 if (value_loc.IsConstant()) {
871 __ movl(Address(address, 0),
872 Immediate(value_loc.GetConstant()->AsIntConstant()->GetValue()));
873 } else {
874 __ movl(Address(address, 0), value_loc.AsRegister<Register>());
875 }
876 break;
877 case Primitive::kPrimLong:
878 if (value_loc.IsConstant()) {
879 int64_t value = value_loc.GetConstant()->AsLongConstant()->GetValue();
880 __ movl(Address(address, 0), Immediate(Low32Bits(value)));
881 __ movl(Address(address, 4), Immediate(High32Bits(value)));
882 } else {
883 __ movl(Address(address, 0), value_loc.AsRegisterPairLow<Register>());
884 __ movl(Address(address, 4), value_loc.AsRegisterPairHigh<Register>());
885 }
886 break;
887 default:
888 LOG(FATAL) << "Type not recognized for poke: " << size;
889 UNREACHABLE();
890 }
891}
892
893void IntrinsicLocationsBuilderX86::VisitMemoryPokeByte(HInvoke* invoke) {
894 CreateLongIntToVoidLocations(arena_, Primitive::kPrimByte, invoke);
895}
896
897void IntrinsicCodeGeneratorX86::VisitMemoryPokeByte(HInvoke* invoke) {
898 GenPoke(invoke->GetLocations(), Primitive::kPrimByte, GetAssembler());
899}
900
901void IntrinsicLocationsBuilderX86::VisitMemoryPokeIntNative(HInvoke* invoke) {
902 CreateLongIntToVoidLocations(arena_, Primitive::kPrimInt, invoke);
903}
904
905void IntrinsicCodeGeneratorX86::VisitMemoryPokeIntNative(HInvoke* invoke) {
906 GenPoke(invoke->GetLocations(), Primitive::kPrimInt, GetAssembler());
907}
908
909void IntrinsicLocationsBuilderX86::VisitMemoryPokeLongNative(HInvoke* invoke) {
910 CreateLongIntToVoidLocations(arena_, Primitive::kPrimLong, invoke);
911}
912
913void IntrinsicCodeGeneratorX86::VisitMemoryPokeLongNative(HInvoke* invoke) {
914 GenPoke(invoke->GetLocations(), Primitive::kPrimLong, GetAssembler());
915}
916
917void IntrinsicLocationsBuilderX86::VisitMemoryPokeShortNative(HInvoke* invoke) {
918 CreateLongIntToVoidLocations(arena_, Primitive::kPrimShort, invoke);
919}
920
921void IntrinsicCodeGeneratorX86::VisitMemoryPokeShortNative(HInvoke* invoke) {
922 GenPoke(invoke->GetLocations(), Primitive::kPrimShort, GetAssembler());
923}
924
925void IntrinsicLocationsBuilderX86::VisitThreadCurrentThread(HInvoke* invoke) {
926 LocationSummary* locations = new (arena_) LocationSummary(invoke,
927 LocationSummary::kNoCall,
928 kIntrinsified);
929 locations->SetOut(Location::RequiresRegister());
930}
931
932void IntrinsicCodeGeneratorX86::VisitThreadCurrentThread(HInvoke* invoke) {
933 Register out = invoke->GetLocations()->Out().AsRegister<Register>();
934 GetAssembler()->fs()->movl(out, Address::Absolute(Thread::PeerOffset<kX86WordSize>()));
935}
936
937static void GenUnsafeGet(LocationSummary* locations, Primitive::Type type,
938 bool is_volatile, X86Assembler* assembler) {
939 Register base = locations->InAt(1).AsRegister<Register>();
940 Register offset = locations->InAt(2).AsRegisterPairLow<Register>();
941 Location output = locations->Out();
942
943 switch (type) {
944 case Primitive::kPrimInt:
945 case Primitive::kPrimNot:
946 __ movl(output.AsRegister<Register>(), Address(base, offset, ScaleFactor::TIMES_1, 0));
947 break;
948
949 case Primitive::kPrimLong: {
950 Register output_lo = output.AsRegisterPairLow<Register>();
951 Register output_hi = output.AsRegisterPairHigh<Register>();
952 if (is_volatile) {
953 // Need to use a XMM to read atomically.
954 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
955 __ movsd(temp, Address(base, offset, ScaleFactor::TIMES_1, 0));
956 __ movd(output_lo, temp);
957 __ psrlq(temp, Immediate(32));
958 __ movd(output_hi, temp);
959 } else {
960 __ movl(output_lo, Address(base, offset, ScaleFactor::TIMES_1, 0));
961 __ movl(output_hi, Address(base, offset, ScaleFactor::TIMES_1, 4));
962 }
963 }
964 break;
965
966 default:
967 LOG(FATAL) << "Unsupported op size " << type;
968 UNREACHABLE();
969 }
970}
971
972static void CreateIntIntIntToIntLocations(ArenaAllocator* arena, HInvoke* invoke,
973 bool is_long, bool is_volatile) {
974 LocationSummary* locations = new (arena) LocationSummary(invoke,
975 LocationSummary::kNoCall,
976 kIntrinsified);
977 locations->SetInAt(0, Location::NoLocation()); // Unused receiver.
978 locations->SetInAt(1, Location::RequiresRegister());
979 locations->SetInAt(2, Location::RequiresRegister());
980 if (is_long) {
981 if (is_volatile) {
982 // Need to use XMM to read volatile.
983 locations->AddTemp(Location::RequiresFpuRegister());
984 locations->SetOut(Location::RequiresRegister());
985 } else {
986 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
987 }
988 } else {
989 locations->SetOut(Location::RequiresRegister());
990 }
991}
992
993void IntrinsicLocationsBuilderX86::VisitUnsafeGet(HInvoke* invoke) {
994 CreateIntIntIntToIntLocations(arena_, invoke, false, false);
995}
996void IntrinsicLocationsBuilderX86::VisitUnsafeGetVolatile(HInvoke* invoke) {
997 CreateIntIntIntToIntLocations(arena_, invoke, false, true);
998}
999void IntrinsicLocationsBuilderX86::VisitUnsafeGetLong(HInvoke* invoke) {
1000 CreateIntIntIntToIntLocations(arena_, invoke, false, false);
1001}
1002void IntrinsicLocationsBuilderX86::VisitUnsafeGetLongVolatile(HInvoke* invoke) {
1003 CreateIntIntIntToIntLocations(arena_, invoke, true, true);
1004}
1005void IntrinsicLocationsBuilderX86::VisitUnsafeGetObject(HInvoke* invoke) {
1006 CreateIntIntIntToIntLocations(arena_, invoke, false, false);
1007}
1008void IntrinsicLocationsBuilderX86::VisitUnsafeGetObjectVolatile(HInvoke* invoke) {
1009 CreateIntIntIntToIntLocations(arena_, invoke, false, true);
1010}
1011
1012
1013void IntrinsicCodeGeneratorX86::VisitUnsafeGet(HInvoke* invoke) {
1014 GenUnsafeGet(invoke->GetLocations(), Primitive::kPrimInt, false, GetAssembler());
1015}
1016void IntrinsicCodeGeneratorX86::VisitUnsafeGetVolatile(HInvoke* invoke) {
1017 GenUnsafeGet(invoke->GetLocations(), Primitive::kPrimInt, true, GetAssembler());
1018}
1019void IntrinsicCodeGeneratorX86::VisitUnsafeGetLong(HInvoke* invoke) {
1020 GenUnsafeGet(invoke->GetLocations(), Primitive::kPrimLong, false, GetAssembler());
1021}
1022void IntrinsicCodeGeneratorX86::VisitUnsafeGetLongVolatile(HInvoke* invoke) {
1023 GenUnsafeGet(invoke->GetLocations(), Primitive::kPrimLong, true, GetAssembler());
1024}
1025void IntrinsicCodeGeneratorX86::VisitUnsafeGetObject(HInvoke* invoke) {
1026 GenUnsafeGet(invoke->GetLocations(), Primitive::kPrimNot, false, GetAssembler());
1027}
1028void IntrinsicCodeGeneratorX86::VisitUnsafeGetObjectVolatile(HInvoke* invoke) {
1029 GenUnsafeGet(invoke->GetLocations(), Primitive::kPrimNot, true, GetAssembler());
1030}
1031
1032
1033static void CreateIntIntIntIntToVoidPlusTempsLocations(ArenaAllocator* arena,
1034 Primitive::Type type,
1035 HInvoke* invoke,
1036 bool is_volatile) {
1037 LocationSummary* locations = new (arena) LocationSummary(invoke,
1038 LocationSummary::kNoCall,
1039 kIntrinsified);
1040 locations->SetInAt(0, Location::NoLocation()); // Unused receiver.
1041 locations->SetInAt(1, Location::RequiresRegister());
1042 locations->SetInAt(2, Location::RequiresRegister());
1043 locations->SetInAt(3, Location::RequiresRegister());
1044 if (type == Primitive::kPrimNot) {
1045 // Need temp registers for card-marking.
1046 locations->AddTemp(Location::RequiresRegister());
1047 // Ensure the value is in a byte register.
1048 locations->AddTemp(Location::RegisterLocation(ECX));
1049 } else if (type == Primitive::kPrimLong && is_volatile) {
1050 locations->AddTemp(Location::RequiresFpuRegister());
1051 locations->AddTemp(Location::RequiresFpuRegister());
1052 }
1053}
1054
1055void IntrinsicLocationsBuilderX86::VisitUnsafePut(HInvoke* invoke) {
1056 CreateIntIntIntIntToVoidPlusTempsLocations(arena_, Primitive::kPrimInt, invoke, false);
1057}
1058void IntrinsicLocationsBuilderX86::VisitUnsafePutOrdered(HInvoke* invoke) {
1059 CreateIntIntIntIntToVoidPlusTempsLocations(arena_, Primitive::kPrimInt, invoke, false);
1060}
1061void IntrinsicLocationsBuilderX86::VisitUnsafePutVolatile(HInvoke* invoke) {
1062 CreateIntIntIntIntToVoidPlusTempsLocations(arena_, Primitive::kPrimInt, invoke, true);
1063}
1064void IntrinsicLocationsBuilderX86::VisitUnsafePutObject(HInvoke* invoke) {
1065 CreateIntIntIntIntToVoidPlusTempsLocations(arena_, Primitive::kPrimNot, invoke, false);
1066}
1067void IntrinsicLocationsBuilderX86::VisitUnsafePutObjectOrdered(HInvoke* invoke) {
1068 CreateIntIntIntIntToVoidPlusTempsLocations(arena_, Primitive::kPrimNot, invoke, false);
1069}
1070void IntrinsicLocationsBuilderX86::VisitUnsafePutObjectVolatile(HInvoke* invoke) {
1071 CreateIntIntIntIntToVoidPlusTempsLocations(arena_, Primitive::kPrimNot, invoke, true);
1072}
1073void IntrinsicLocationsBuilderX86::VisitUnsafePutLong(HInvoke* invoke) {
1074 CreateIntIntIntIntToVoidPlusTempsLocations(arena_, Primitive::kPrimLong, invoke, false);
1075}
1076void IntrinsicLocationsBuilderX86::VisitUnsafePutLongOrdered(HInvoke* invoke) {
1077 CreateIntIntIntIntToVoidPlusTempsLocations(arena_, Primitive::kPrimLong, invoke, false);
1078}
1079void IntrinsicLocationsBuilderX86::VisitUnsafePutLongVolatile(HInvoke* invoke) {
1080 CreateIntIntIntIntToVoidPlusTempsLocations(arena_, Primitive::kPrimLong, invoke, true);
1081}
1082
1083// We don't care for ordered: it requires an AnyStore barrier, which is already given by the x86
1084// memory model.
1085static void GenUnsafePut(LocationSummary* locations,
1086 Primitive::Type type,
1087 bool is_volatile,
1088 CodeGeneratorX86* codegen) {
1089 X86Assembler* assembler = reinterpret_cast<X86Assembler*>(codegen->GetAssembler());
1090 Register base = locations->InAt(1).AsRegister<Register>();
1091 Register offset = locations->InAt(2).AsRegisterPairLow<Register>();
1092 Location value_loc = locations->InAt(3);
1093
1094 if (type == Primitive::kPrimLong) {
1095 Register value_lo = value_loc.AsRegisterPairLow<Register>();
1096 Register value_hi = value_loc.AsRegisterPairHigh<Register>();
1097 if (is_volatile) {
1098 XmmRegister temp1 = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
1099 XmmRegister temp2 = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
1100 __ movd(temp1, value_lo);
1101 __ movd(temp2, value_hi);
1102 __ punpckldq(temp1, temp2);
1103 __ movsd(Address(base, offset, ScaleFactor::TIMES_1, 0), temp1);
1104 } else {
1105 __ movl(Address(base, offset, ScaleFactor::TIMES_1, 0), value_lo);
1106 __ movl(Address(base, offset, ScaleFactor::TIMES_1, 4), value_hi);
1107 }
1108 } else {
1109 __ movl(Address(base, offset, ScaleFactor::TIMES_1, 0), value_loc.AsRegister<Register>());
1110 }
1111
1112 if (is_volatile) {
1113 __ mfence();
1114 }
1115
1116 if (type == Primitive::kPrimNot) {
1117 codegen->MarkGCCard(locations->GetTemp(0).AsRegister<Register>(),
1118 locations->GetTemp(1).AsRegister<Register>(),
1119 base,
1120 value_loc.AsRegister<Register>());
1121 }
1122}
1123
1124void IntrinsicCodeGeneratorX86::VisitUnsafePut(HInvoke* invoke) {
1125 GenUnsafePut(invoke->GetLocations(), Primitive::kPrimInt, false, codegen_);
1126}
1127void IntrinsicCodeGeneratorX86::VisitUnsafePutOrdered(HInvoke* invoke) {
1128 GenUnsafePut(invoke->GetLocations(), Primitive::kPrimInt, false, codegen_);
1129}
1130void IntrinsicCodeGeneratorX86::VisitUnsafePutVolatile(HInvoke* invoke) {
1131 GenUnsafePut(invoke->GetLocations(), Primitive::kPrimInt, true, codegen_);
1132}
1133void IntrinsicCodeGeneratorX86::VisitUnsafePutObject(HInvoke* invoke) {
1134 GenUnsafePut(invoke->GetLocations(), Primitive::kPrimNot, false, codegen_);
1135}
1136void IntrinsicCodeGeneratorX86::VisitUnsafePutObjectOrdered(HInvoke* invoke) {
1137 GenUnsafePut(invoke->GetLocations(), Primitive::kPrimNot, false, codegen_);
1138}
1139void IntrinsicCodeGeneratorX86::VisitUnsafePutObjectVolatile(HInvoke* invoke) {
1140 GenUnsafePut(invoke->GetLocations(), Primitive::kPrimNot, true, codegen_);
1141}
1142void IntrinsicCodeGeneratorX86::VisitUnsafePutLong(HInvoke* invoke) {
1143 GenUnsafePut(invoke->GetLocations(), Primitive::kPrimLong, false, codegen_);
1144}
1145void IntrinsicCodeGeneratorX86::VisitUnsafePutLongOrdered(HInvoke* invoke) {
1146 GenUnsafePut(invoke->GetLocations(), Primitive::kPrimLong, false, codegen_);
1147}
1148void IntrinsicCodeGeneratorX86::VisitUnsafePutLongVolatile(HInvoke* invoke) {
1149 GenUnsafePut(invoke->GetLocations(), Primitive::kPrimLong, true, codegen_);
1150}
1151
1152// Unimplemented intrinsics.
1153
1154#define UNIMPLEMENTED_INTRINSIC(Name) \
1155void IntrinsicLocationsBuilderX86::Visit ## Name(HInvoke* invoke ATTRIBUTE_UNUSED) { \
1156} \
1157void IntrinsicCodeGeneratorX86::Visit ## Name(HInvoke* invoke ATTRIBUTE_UNUSED) { \
1158}
1159
1160UNIMPLEMENTED_INTRINSIC(IntegerReverse)
1161UNIMPLEMENTED_INTRINSIC(LongReverse)
1162UNIMPLEMENTED_INTRINSIC(LongReverseBytes)
1163UNIMPLEMENTED_INTRINSIC(MathFloor)
1164UNIMPLEMENTED_INTRINSIC(MathCeil)
1165UNIMPLEMENTED_INTRINSIC(MathRint)
1166UNIMPLEMENTED_INTRINSIC(MathRoundDouble)
1167UNIMPLEMENTED_INTRINSIC(MathRoundFloat)
1168UNIMPLEMENTED_INTRINSIC(StringIsEmpty) // Might not want to do these two anyways, inlining should
1169UNIMPLEMENTED_INTRINSIC(StringLength) // be good enough here.
1170UNIMPLEMENTED_INTRINSIC(StringCompareTo)
1171UNIMPLEMENTED_INTRINSIC(StringIndexOf)
1172UNIMPLEMENTED_INTRINSIC(StringIndexOfAfter)
1173UNIMPLEMENTED_INTRINSIC(SystemArrayCopyChar)
1174UNIMPLEMENTED_INTRINSIC(UnsafeCASInt)
1175UNIMPLEMENTED_INTRINSIC(UnsafeCASLong)
1176UNIMPLEMENTED_INTRINSIC(UnsafeCASObject)
1177UNIMPLEMENTED_INTRINSIC(ReferenceGetReferent)
1178
1179} // namespace x86
1180} // namespace art