blob: a86d060821e54ad20aa7feab638945b2118d2ad3 [file] [log] [blame]
Aart Bikf8f5a162017-02-06 15:35:29 -08001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "code_generator_x86.h"
18#include "mirror/array-inl.h"
19
20namespace art {
21namespace x86 {
22
23// NOLINT on __ macro to suppress wrong warning/fix (misc-macro-parentheses) from clang-tidy.
24#define __ down_cast<X86Assembler*>(GetAssembler())-> // NOLINT
25
26void LocationsBuilderX86::VisitVecReplicateScalar(HVecReplicateScalar* instruction) {
27 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
28 switch (instruction->GetPackedType()) {
29 case Primitive::kPrimLong:
30 // Long needs extra temporary to load the register pair.
31 locations->AddTemp(Location::RequiresFpuRegister());
32 FALLTHROUGH_INTENDED;
33 case Primitive::kPrimBoolean:
34 case Primitive::kPrimByte:
35 case Primitive::kPrimChar:
36 case Primitive::kPrimShort:
37 case Primitive::kPrimInt:
38 locations->SetInAt(0, Location::RequiresRegister());
39 locations->SetOut(Location::RequiresFpuRegister());
40 break;
41 case Primitive::kPrimFloat:
42 case Primitive::kPrimDouble:
43 locations->SetInAt(0, Location::RequiresFpuRegister());
44 locations->SetOut(Location::SameAsFirstInput());
45 break;
46 default:
47 LOG(FATAL) << "Unsupported SIMD type";
48 UNREACHABLE();
49 }
50}
51
52void InstructionCodeGeneratorX86::VisitVecReplicateScalar(HVecReplicateScalar* instruction) {
53 LocationSummary* locations = instruction->GetLocations();
54 XmmRegister reg = locations->Out().AsFpuRegister<XmmRegister>();
55 switch (instruction->GetPackedType()) {
56 case Primitive::kPrimBoolean:
57 case Primitive::kPrimByte:
58 DCHECK_EQ(16u, instruction->GetVectorLength());
59 __ movd(reg, locations->InAt(0).AsRegister<Register>());
60 __ punpcklbw(reg, reg);
61 __ punpcklwd(reg, reg);
62 __ pshufd(reg, reg, Immediate(0));
63 break;
64 case Primitive::kPrimChar:
65 case Primitive::kPrimShort:
66 DCHECK_EQ(8u, instruction->GetVectorLength());
67 __ movd(reg, locations->InAt(0).AsRegister<Register>());
68 __ punpcklwd(reg, reg);
69 __ pshufd(reg, reg, Immediate(0));
70 break;
71 case Primitive::kPrimInt:
72 DCHECK_EQ(4u, instruction->GetVectorLength());
73 __ movd(reg, locations->InAt(0).AsRegister<Register>());
74 __ pshufd(reg, reg, Immediate(0));
75 break;
76 case Primitive::kPrimLong: {
77 XmmRegister tmp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
78 DCHECK_EQ(2u, instruction->GetVectorLength());
79 __ movd(reg, locations->InAt(0).AsRegisterPairLow<Register>());
80 __ movd(tmp, locations->InAt(0).AsRegisterPairHigh<Register>());
81 __ punpckldq(reg, tmp);
82 __ punpcklqdq(reg, reg);
83 break;
84 }
85 case Primitive::kPrimFloat:
86 DCHECK(locations->InAt(0).Equals(locations->Out()));
87 DCHECK_EQ(4u, instruction->GetVectorLength());
88 __ shufps(reg, reg, Immediate(0));
89 break;
90 case Primitive::kPrimDouble:
91 DCHECK(locations->InAt(0).Equals(locations->Out()));
92 DCHECK_EQ(2u, instruction->GetVectorLength());
93 __ shufpd(reg, reg, Immediate(0));
94 break;
95 default:
96 LOG(FATAL) << "Unsupported SIMD type";
97 UNREACHABLE();
98 }
99}
100
101void LocationsBuilderX86::VisitVecSetScalars(HVecSetScalars* instruction) {
102 LOG(FATAL) << "No SIMD for " << instruction->GetId();
103}
104
105void InstructionCodeGeneratorX86::VisitVecSetScalars(HVecSetScalars* instruction) {
106 LOG(FATAL) << "No SIMD for " << instruction->GetId();
107}
108
109void LocationsBuilderX86::VisitVecSumReduce(HVecSumReduce* instruction) {
110 LOG(FATAL) << "No SIMD for " << instruction->GetId();
111}
112
113void InstructionCodeGeneratorX86::VisitVecSumReduce(HVecSumReduce* instruction) {
114 LOG(FATAL) << "No SIMD for " << instruction->GetId();
115}
116
117// Helper to set up locations for vector unary operations.
118static void CreateVecUnOpLocations(ArenaAllocator* arena, HVecUnaryOperation* instruction) {
119 LocationSummary* locations = new (arena) LocationSummary(instruction);
120 switch (instruction->GetPackedType()) {
121 case Primitive::kPrimBoolean:
122 case Primitive::kPrimByte:
123 case Primitive::kPrimChar:
124 case Primitive::kPrimShort:
125 case Primitive::kPrimInt:
126 case Primitive::kPrimLong:
127 case Primitive::kPrimFloat:
128 case Primitive::kPrimDouble:
129 locations->SetInAt(0, Location::RequiresFpuRegister());
130 locations->SetOut(Location::RequiresFpuRegister());
131 break;
132 default:
133 LOG(FATAL) << "Unsupported SIMD type";
134 UNREACHABLE();
135 }
136}
137
138void LocationsBuilderX86::VisitVecCnv(HVecCnv* instruction) {
139 CreateVecUnOpLocations(GetGraph()->GetArena(), instruction);
140}
141
142void InstructionCodeGeneratorX86::VisitVecCnv(HVecCnv* instruction) {
143 LocationSummary* locations = instruction->GetLocations();
144 XmmRegister src = locations->InAt(0).AsFpuRegister<XmmRegister>();
145 XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
146 Primitive::Type from = instruction->GetInputType();
147 Primitive::Type to = instruction->GetResultType();
148 if (from == Primitive::kPrimInt && to == Primitive::kPrimFloat) {
149 DCHECK_EQ(4u, instruction->GetVectorLength());
150 __ cvtdq2ps(dst, src);
151 } else {
152 LOG(FATAL) << "Unsupported SIMD type";
153 }
154}
155
156void LocationsBuilderX86::VisitVecNeg(HVecNeg* instruction) {
157 CreateVecUnOpLocations(GetGraph()->GetArena(), instruction);
158}
159
160void InstructionCodeGeneratorX86::VisitVecNeg(HVecNeg* instruction) {
161 LocationSummary* locations = instruction->GetLocations();
162 XmmRegister src = locations->InAt(0).AsFpuRegister<XmmRegister>();
163 XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
164 switch (instruction->GetPackedType()) {
165 case Primitive::kPrimByte:
166 DCHECK_EQ(16u, instruction->GetVectorLength());
167 __ pxor(dst, dst);
168 __ psubb(dst, src);
169 break;
170 case Primitive::kPrimChar:
171 case Primitive::kPrimShort:
172 DCHECK_EQ(8u, instruction->GetVectorLength());
173 __ pxor(dst, dst);
174 __ psubw(dst, src);
175 break;
176 case Primitive::kPrimInt:
177 DCHECK_EQ(4u, instruction->GetVectorLength());
178 __ pxor(dst, dst);
179 __ psubd(dst, src);
180 break;
181 case Primitive::kPrimLong:
182 DCHECK_EQ(2u, instruction->GetVectorLength());
183 __ pxor(dst, dst);
184 __ psubq(dst, src);
185 break;
186 case Primitive::kPrimFloat:
187 DCHECK_EQ(4u, instruction->GetVectorLength());
188 __ xorps(dst, dst);
189 __ subps(dst, src);
190 break;
191 case Primitive::kPrimDouble:
192 DCHECK_EQ(2u, instruction->GetVectorLength());
193 __ xorpd(dst, dst);
194 __ subpd(dst, src);
195 break;
196 default:
197 LOG(FATAL) << "Unsupported SIMD type";
198 UNREACHABLE();
199 }
200}
201
Aart Bik6daebeb2017-04-03 14:35:41 -0700202void LocationsBuilderX86::VisitVecAbs(HVecAbs* instruction) {
203 CreateVecUnOpLocations(GetGraph()->GetArena(), instruction);
204 if (instruction->GetPackedType() == Primitive::kPrimInt) {
205 instruction->GetLocations()->AddTemp(Location::RequiresFpuRegister());
206 }
207}
208
209void InstructionCodeGeneratorX86::VisitVecAbs(HVecAbs* instruction) {
210 LocationSummary* locations = instruction->GetLocations();
211 XmmRegister src = locations->InAt(0).AsFpuRegister<XmmRegister>();
212 XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
213 switch (instruction->GetPackedType()) {
214 case Primitive::kPrimInt: {
215 DCHECK_EQ(4u, instruction->GetVectorLength());
216 XmmRegister tmp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
217 __ movaps(dst, src);
218 __ pxor(tmp, tmp);
219 __ pcmpgtd(tmp, dst);
220 __ pxor(dst, tmp);
221 __ psubd(dst, tmp);
222 break;
223 }
224 case Primitive::kPrimFloat:
225 DCHECK_EQ(4u, instruction->GetVectorLength());
226 __ pcmpeqb(dst, dst); // all ones
227 __ psrld(dst, Immediate(1));
228 __ andps(dst, src);
229 break;
230 case Primitive::kPrimDouble:
231 DCHECK_EQ(2u, instruction->GetVectorLength());
232 __ pcmpeqb(dst, dst); // all ones
233 __ psrlq(dst, Immediate(1));
234 __ andpd(dst, src);
235 break;
236 default:
237 LOG(FATAL) << "Unsupported SIMD type";
238 UNREACHABLE();
239 }
240}
241
Aart Bikf8f5a162017-02-06 15:35:29 -0800242void LocationsBuilderX86::VisitVecNot(HVecNot* instruction) {
243 CreateVecUnOpLocations(GetGraph()->GetArena(), instruction);
244 // Boolean-not requires a temporary to construct the 16 x one.
245 if (instruction->GetPackedType() == Primitive::kPrimBoolean) {
246 instruction->GetLocations()->AddTemp(Location::RequiresFpuRegister());
247 }
248}
249
250void InstructionCodeGeneratorX86::VisitVecNot(HVecNot* instruction) {
251 LocationSummary* locations = instruction->GetLocations();
252 XmmRegister src = locations->InAt(0).AsFpuRegister<XmmRegister>();
253 XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
254 switch (instruction->GetPackedType()) {
255 case Primitive::kPrimBoolean: { // special case boolean-not
256 DCHECK_EQ(16u, instruction->GetVectorLength());
257 XmmRegister tmp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
258 __ pxor(dst, dst);
259 __ pcmpeqb(tmp, tmp); // all ones
260 __ psubb(dst, tmp); // 16 x one
261 __ pxor(dst, src);
262 break;
263 }
264 case Primitive::kPrimByte:
265 case Primitive::kPrimChar:
266 case Primitive::kPrimShort:
267 case Primitive::kPrimInt:
268 case Primitive::kPrimLong:
269 DCHECK_LE(2u, instruction->GetVectorLength());
270 DCHECK_LE(instruction->GetVectorLength(), 16u);
271 __ pcmpeqb(dst, dst); // all ones
272 __ pxor(dst, src);
273 break;
274 case Primitive::kPrimFloat:
275 DCHECK_EQ(4u, instruction->GetVectorLength());
276 __ pcmpeqb(dst, dst); // all ones
277 __ xorps(dst, src);
278 break;
279 case Primitive::kPrimDouble:
280 DCHECK_EQ(2u, instruction->GetVectorLength());
281 __ pcmpeqb(dst, dst); // all ones
282 __ xorpd(dst, src);
283 break;
284 default:
285 LOG(FATAL) << "Unsupported SIMD type";
286 UNREACHABLE();
287 }
288}
289
290// Helper to set up locations for vector binary operations.
291static void CreateVecBinOpLocations(ArenaAllocator* arena, HVecBinaryOperation* instruction) {
292 LocationSummary* locations = new (arena) LocationSummary(instruction);
293 switch (instruction->GetPackedType()) {
294 case Primitive::kPrimBoolean:
295 case Primitive::kPrimByte:
296 case Primitive::kPrimChar:
297 case Primitive::kPrimShort:
298 case Primitive::kPrimInt:
299 case Primitive::kPrimLong:
300 case Primitive::kPrimFloat:
301 case Primitive::kPrimDouble:
302 locations->SetInAt(0, Location::RequiresFpuRegister());
303 locations->SetInAt(1, Location::RequiresFpuRegister());
304 locations->SetOut(Location::SameAsFirstInput());
305 break;
306 default:
307 LOG(FATAL) << "Unsupported SIMD type";
308 UNREACHABLE();
309 }
310}
311
312void LocationsBuilderX86::VisitVecAdd(HVecAdd* instruction) {
313 CreateVecBinOpLocations(GetGraph()->GetArena(), instruction);
314}
315
316void InstructionCodeGeneratorX86::VisitVecAdd(HVecAdd* instruction) {
317 LocationSummary* locations = instruction->GetLocations();
318 DCHECK(locations->InAt(0).Equals(locations->Out()));
319 XmmRegister src = locations->InAt(1).AsFpuRegister<XmmRegister>();
320 XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
321 switch (instruction->GetPackedType()) {
322 case Primitive::kPrimByte:
323 DCHECK_EQ(16u, instruction->GetVectorLength());
324 __ paddb(dst, src);
325 break;
326 case Primitive::kPrimChar:
327 case Primitive::kPrimShort:
328 DCHECK_EQ(8u, instruction->GetVectorLength());
329 __ paddw(dst, src);
330 break;
331 case Primitive::kPrimInt:
332 DCHECK_EQ(4u, instruction->GetVectorLength());
333 __ paddd(dst, src);
334 break;
335 case Primitive::kPrimLong:
336 DCHECK_EQ(2u, instruction->GetVectorLength());
337 __ paddq(dst, src);
338 break;
339 case Primitive::kPrimFloat:
340 DCHECK_EQ(4u, instruction->GetVectorLength());
341 __ addps(dst, src);
342 break;
343 case Primitive::kPrimDouble:
344 DCHECK_EQ(2u, instruction->GetVectorLength());
345 __ addpd(dst, src);
346 break;
347 default:
348 LOG(FATAL) << "Unsupported SIMD type";
349 UNREACHABLE();
350 }
351}
352
Aart Bikf3e61ee2017-04-12 17:09:20 -0700353void LocationsBuilderX86::VisitVecHalvingAdd(HVecHalvingAdd* instruction) {
354 CreateVecBinOpLocations(GetGraph()->GetArena(), instruction);
355}
356
357void InstructionCodeGeneratorX86::VisitVecHalvingAdd(HVecHalvingAdd* instruction) {
358 LocationSummary* locations = instruction->GetLocations();
359 DCHECK(locations->InAt(0).Equals(locations->Out()));
360 XmmRegister src = locations->InAt(1).AsFpuRegister<XmmRegister>();
361 XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
362
363 DCHECK(instruction->IsRounded());
364 DCHECK(instruction->IsUnsigned());
365
366 switch (instruction->GetPackedType()) {
367 case Primitive::kPrimByte:
368 DCHECK_EQ(16u, instruction->GetVectorLength());
369 __ pavgb(dst, src);
370 return;
371 case Primitive::kPrimChar:
372 case Primitive::kPrimShort:
373 DCHECK_EQ(8u, instruction->GetVectorLength());
374 __ pavgw(dst, src);
375 return;
376 default:
377 LOG(FATAL) << "Unsupported SIMD type";
378 UNREACHABLE();
379 }
380}
381
Aart Bikf8f5a162017-02-06 15:35:29 -0800382void LocationsBuilderX86::VisitVecSub(HVecSub* instruction) {
383 CreateVecBinOpLocations(GetGraph()->GetArena(), instruction);
384}
385
386void InstructionCodeGeneratorX86::VisitVecSub(HVecSub* instruction) {
387 LocationSummary* locations = instruction->GetLocations();
388 DCHECK(locations->InAt(0).Equals(locations->Out()));
389 XmmRegister src = locations->InAt(1).AsFpuRegister<XmmRegister>();
390 XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
391 switch (instruction->GetPackedType()) {
392 case Primitive::kPrimByte:
393 DCHECK_EQ(16u, instruction->GetVectorLength());
394 __ psubb(dst, src);
395 break;
396 case Primitive::kPrimChar:
397 case Primitive::kPrimShort:
398 DCHECK_EQ(8u, instruction->GetVectorLength());
399 __ psubw(dst, src);
400 break;
401 case Primitive::kPrimInt:
402 DCHECK_EQ(4u, instruction->GetVectorLength());
403 __ psubd(dst, src);
404 break;
405 case Primitive::kPrimLong:
406 DCHECK_EQ(2u, instruction->GetVectorLength());
407 __ psubq(dst, src);
408 break;
409 case Primitive::kPrimFloat:
410 DCHECK_EQ(4u, instruction->GetVectorLength());
411 __ subps(dst, src);
412 break;
413 case Primitive::kPrimDouble:
414 DCHECK_EQ(2u, instruction->GetVectorLength());
415 __ subpd(dst, src);
416 break;
417 default:
418 LOG(FATAL) << "Unsupported SIMD type";
419 UNREACHABLE();
420 }
421}
422
423void LocationsBuilderX86::VisitVecMul(HVecMul* instruction) {
424 CreateVecBinOpLocations(GetGraph()->GetArena(), instruction);
425}
426
427void InstructionCodeGeneratorX86::VisitVecMul(HVecMul* instruction) {
428 LocationSummary* locations = instruction->GetLocations();
429 DCHECK(locations->InAt(0).Equals(locations->Out()));
430 XmmRegister src = locations->InAt(1).AsFpuRegister<XmmRegister>();
431 XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
432 switch (instruction->GetPackedType()) {
433 case Primitive::kPrimChar:
434 case Primitive::kPrimShort:
435 DCHECK_EQ(8u, instruction->GetVectorLength());
436 __ pmullw(dst, src);
437 break;
438 case Primitive::kPrimInt:
439 DCHECK_EQ(4u, instruction->GetVectorLength());
440 __ pmulld(dst, src);
441 break;
442 case Primitive::kPrimFloat:
443 DCHECK_EQ(4u, instruction->GetVectorLength());
444 __ mulps(dst, src);
445 break;
446 case Primitive::kPrimDouble:
447 DCHECK_EQ(2u, instruction->GetVectorLength());
448 __ mulpd(dst, src);
449 break;
450 default:
451 LOG(FATAL) << "Unsupported SIMD type";
452 UNREACHABLE();
453 }
454}
455
456void LocationsBuilderX86::VisitVecDiv(HVecDiv* instruction) {
457 CreateVecBinOpLocations(GetGraph()->GetArena(), instruction);
458}
459
460void InstructionCodeGeneratorX86::VisitVecDiv(HVecDiv* instruction) {
461 LocationSummary* locations = instruction->GetLocations();
462 DCHECK(locations->InAt(0).Equals(locations->Out()));
463 XmmRegister src = locations->InAt(1).AsFpuRegister<XmmRegister>();
464 XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
465 switch (instruction->GetPackedType()) {
466 case Primitive::kPrimFloat:
467 DCHECK_EQ(4u, instruction->GetVectorLength());
468 __ divps(dst, src);
469 break;
470 case Primitive::kPrimDouble:
471 DCHECK_EQ(2u, instruction->GetVectorLength());
472 __ divpd(dst, src);
473 break;
474 default:
475 LOG(FATAL) << "Unsupported SIMD type";
476 UNREACHABLE();
477 }
478}
479
Aart Bikf3e61ee2017-04-12 17:09:20 -0700480void LocationsBuilderX86::VisitVecMin(HVecMin* instruction) {
481 CreateVecBinOpLocations(GetGraph()->GetArena(), instruction);
482}
483
484void InstructionCodeGeneratorX86::VisitVecMin(HVecMin* instruction) {
485 LOG(FATAL) << "No SIMD for " << instruction->GetId();
486}
487
488void LocationsBuilderX86::VisitVecMax(HVecMax* instruction) {
489 CreateVecBinOpLocations(GetGraph()->GetArena(), instruction);
490}
491
492void InstructionCodeGeneratorX86::VisitVecMax(HVecMax* instruction) {
493 LOG(FATAL) << "No SIMD for " << instruction->GetId();
494}
495
Aart Bikf8f5a162017-02-06 15:35:29 -0800496void LocationsBuilderX86::VisitVecAnd(HVecAnd* instruction) {
497 CreateVecBinOpLocations(GetGraph()->GetArena(), instruction);
498}
499
500void InstructionCodeGeneratorX86::VisitVecAnd(HVecAnd* instruction) {
501 LocationSummary* locations = instruction->GetLocations();
502 DCHECK(locations->InAt(0).Equals(locations->Out()));
503 XmmRegister src = locations->InAt(1).AsFpuRegister<XmmRegister>();
504 XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
505 switch (instruction->GetPackedType()) {
506 case Primitive::kPrimBoolean:
507 case Primitive::kPrimByte:
508 case Primitive::kPrimChar:
509 case Primitive::kPrimShort:
510 case Primitive::kPrimInt:
511 case Primitive::kPrimLong:
512 DCHECK_LE(2u, instruction->GetVectorLength());
513 DCHECK_LE(instruction->GetVectorLength(), 16u);
514 __ pand(dst, src);
515 break;
516 case Primitive::kPrimFloat:
517 DCHECK_EQ(4u, instruction->GetVectorLength());
518 __ andps(dst, src);
519 break;
520 case Primitive::kPrimDouble:
521 DCHECK_EQ(2u, instruction->GetVectorLength());
522 __ andpd(dst, src);
523 break;
524 default:
525 LOG(FATAL) << "Unsupported SIMD type";
526 UNREACHABLE();
527 }
528}
529
530void LocationsBuilderX86::VisitVecAndNot(HVecAndNot* instruction) {
531 CreateVecBinOpLocations(GetGraph()->GetArena(), instruction);
532}
533
534void InstructionCodeGeneratorX86::VisitVecAndNot(HVecAndNot* instruction) {
535 LocationSummary* locations = instruction->GetLocations();
536 DCHECK(locations->InAt(0).Equals(locations->Out()));
537 XmmRegister src = locations->InAt(1).AsFpuRegister<XmmRegister>();
538 XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
539 switch (instruction->GetPackedType()) {
540 case Primitive::kPrimBoolean:
541 case Primitive::kPrimByte:
542 case Primitive::kPrimChar:
543 case Primitive::kPrimShort:
544 case Primitive::kPrimInt:
545 case Primitive::kPrimLong:
546 DCHECK_LE(2u, instruction->GetVectorLength());
547 DCHECK_LE(instruction->GetVectorLength(), 16u);
548 __ pandn(dst, src);
549 break;
550 case Primitive::kPrimFloat:
551 DCHECK_EQ(4u, instruction->GetVectorLength());
552 __ andnps(dst, src);
553 break;
554 case Primitive::kPrimDouble:
555 DCHECK_EQ(2u, instruction->GetVectorLength());
556 __ andnpd(dst, src);
557 break;
558 default:
559 LOG(FATAL) << "Unsupported SIMD type";
560 UNREACHABLE();
561 }
562}
563
564void LocationsBuilderX86::VisitVecOr(HVecOr* instruction) {
565 CreateVecBinOpLocations(GetGraph()->GetArena(), instruction);
566}
567
568void InstructionCodeGeneratorX86::VisitVecOr(HVecOr* instruction) {
569 LocationSummary* locations = instruction->GetLocations();
570 DCHECK(locations->InAt(0).Equals(locations->Out()));
571 XmmRegister src = locations->InAt(1).AsFpuRegister<XmmRegister>();
572 XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
573 switch (instruction->GetPackedType()) {
574 case Primitive::kPrimBoolean:
575 case Primitive::kPrimByte:
576 case Primitive::kPrimChar:
577 case Primitive::kPrimShort:
578 case Primitive::kPrimInt:
579 case Primitive::kPrimLong:
580 DCHECK_LE(2u, instruction->GetVectorLength());
581 DCHECK_LE(instruction->GetVectorLength(), 16u);
582 __ por(dst, src);
583 break;
584 case Primitive::kPrimFloat:
585 DCHECK_EQ(4u, instruction->GetVectorLength());
586 __ orps(dst, src);
587 break;
588 case Primitive::kPrimDouble:
589 DCHECK_EQ(2u, instruction->GetVectorLength());
590 __ orpd(dst, src);
591 break;
592 default:
593 LOG(FATAL) << "Unsupported SIMD type";
594 UNREACHABLE();
595 }
596}
597
598void LocationsBuilderX86::VisitVecXor(HVecXor* instruction) {
599 CreateVecBinOpLocations(GetGraph()->GetArena(), instruction);
600}
601
602void InstructionCodeGeneratorX86::VisitVecXor(HVecXor* instruction) {
603 LocationSummary* locations = instruction->GetLocations();
604 DCHECK(locations->InAt(0).Equals(locations->Out()));
605 XmmRegister src = locations->InAt(1).AsFpuRegister<XmmRegister>();
606 XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
607 switch (instruction->GetPackedType()) {
608 case Primitive::kPrimBoolean:
609 case Primitive::kPrimByte:
610 case Primitive::kPrimChar:
611 case Primitive::kPrimShort:
612 case Primitive::kPrimInt:
613 case Primitive::kPrimLong:
614 DCHECK_LE(2u, instruction->GetVectorLength());
615 DCHECK_LE(instruction->GetVectorLength(), 16u);
616 __ pxor(dst, src);
617 break;
618 case Primitive::kPrimFloat:
619 DCHECK_EQ(4u, instruction->GetVectorLength());
620 __ xorps(dst, src);
621 break;
622 case Primitive::kPrimDouble:
623 DCHECK_EQ(2u, instruction->GetVectorLength());
624 __ xorpd(dst, src);
625 break;
626 default:
627 LOG(FATAL) << "Unsupported SIMD type";
628 UNREACHABLE();
629 }
630}
631
632// Helper to set up locations for vector shift operations.
633static void CreateVecShiftLocations(ArenaAllocator* arena, HVecBinaryOperation* instruction) {
634 LocationSummary* locations = new (arena) LocationSummary(instruction);
635 switch (instruction->GetPackedType()) {
636 case Primitive::kPrimChar:
637 case Primitive::kPrimShort:
638 case Primitive::kPrimInt:
639 case Primitive::kPrimLong:
640 locations->SetInAt(0, Location::RequiresFpuRegister());
641 locations->SetInAt(1, Location::ConstantLocation(instruction->InputAt(1)->AsConstant()));
642 locations->SetOut(Location::SameAsFirstInput());
643 break;
644 default:
645 LOG(FATAL) << "Unsupported SIMD type";
646 UNREACHABLE();
647 }
648}
649
650void LocationsBuilderX86::VisitVecShl(HVecShl* instruction) {
651 CreateVecShiftLocations(GetGraph()->GetArena(), instruction);
652}
653
654void InstructionCodeGeneratorX86::VisitVecShl(HVecShl* instruction) {
655 LocationSummary* locations = instruction->GetLocations();
656 DCHECK(locations->InAt(0).Equals(locations->Out()));
657 int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
658 XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
659 switch (instruction->GetPackedType()) {
660 case Primitive::kPrimChar:
661 case Primitive::kPrimShort:
662 DCHECK_EQ(8u, instruction->GetVectorLength());
663 __ psllw(dst, Immediate(static_cast<uint8_t>(value)));
664 break;
665 case Primitive::kPrimInt:
666 DCHECK_EQ(4u, instruction->GetVectorLength());
667 __ pslld(dst, Immediate(static_cast<uint8_t>(value)));
668 break;
669 case Primitive::kPrimLong:
670 DCHECK_EQ(2u, instruction->GetVectorLength());
671 __ psllq(dst, Immediate(static_cast<uint8_t>(value)));
672 break;
673 default:
674 LOG(FATAL) << "Unsupported SIMD type";
675 UNREACHABLE();
676 }
677}
678
679void LocationsBuilderX86::VisitVecShr(HVecShr* instruction) {
680 CreateVecShiftLocations(GetGraph()->GetArena(), instruction);
681}
682
683void InstructionCodeGeneratorX86::VisitVecShr(HVecShr* instruction) {
684 LocationSummary* locations = instruction->GetLocations();
685 DCHECK(locations->InAt(0).Equals(locations->Out()));
686 int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
687 XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
688 switch (instruction->GetPackedType()) {
689 case Primitive::kPrimChar:
690 case Primitive::kPrimShort:
691 DCHECK_EQ(8u, instruction->GetVectorLength());
692 __ psraw(dst, Immediate(static_cast<uint8_t>(value)));
693 break;
694 case Primitive::kPrimInt:
695 DCHECK_EQ(4u, instruction->GetVectorLength());
696 __ psrad(dst, Immediate(static_cast<uint8_t>(value)));
697 break;
698 default:
699 LOG(FATAL) << "Unsupported SIMD type";
700 UNREACHABLE();
701 }
702}
703
704void LocationsBuilderX86::VisitVecUShr(HVecUShr* instruction) {
705 CreateVecShiftLocations(GetGraph()->GetArena(), instruction);
706}
707
708void InstructionCodeGeneratorX86::VisitVecUShr(HVecUShr* instruction) {
709 LocationSummary* locations = instruction->GetLocations();
710 DCHECK(locations->InAt(0).Equals(locations->Out()));
711 int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
712 XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
713 switch (instruction->GetPackedType()) {
714 case Primitive::kPrimChar:
715 case Primitive::kPrimShort:
716 DCHECK_EQ(8u, instruction->GetVectorLength());
717 __ psrlw(dst, Immediate(static_cast<uint8_t>(value)));
718 break;
719 case Primitive::kPrimInt:
720 DCHECK_EQ(4u, instruction->GetVectorLength());
721 __ psrld(dst, Immediate(static_cast<uint8_t>(value)));
722 break;
723 case Primitive::kPrimLong:
724 DCHECK_EQ(2u, instruction->GetVectorLength());
725 __ psrlq(dst, Immediate(static_cast<uint8_t>(value)));
726 break;
727 default:
728 LOG(FATAL) << "Unsupported SIMD type";
729 UNREACHABLE();
730 }
731}
732
733// Helper to set up locations for vector memory operations.
734static void CreateVecMemLocations(ArenaAllocator* arena,
735 HVecMemoryOperation* instruction,
736 bool is_load) {
737 LocationSummary* locations = new (arena) LocationSummary(instruction);
738 switch (instruction->GetPackedType()) {
739 case Primitive::kPrimBoolean:
740 case Primitive::kPrimByte:
741 case Primitive::kPrimChar:
742 case Primitive::kPrimShort:
743 case Primitive::kPrimInt:
744 case Primitive::kPrimLong:
745 case Primitive::kPrimFloat:
746 case Primitive::kPrimDouble:
747 locations->SetInAt(0, Location::RequiresRegister());
748 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
749 if (is_load) {
750 locations->SetOut(Location::RequiresFpuRegister());
751 } else {
752 locations->SetInAt(2, Location::RequiresFpuRegister());
753 }
754 break;
755 default:
756 LOG(FATAL) << "Unsupported SIMD type";
757 UNREACHABLE();
758 }
759}
760
761// Helper to set up registers and address for vector memory operations.
762static Address CreateVecMemRegisters(HVecMemoryOperation* instruction,
763 Location* reg_loc,
764 bool is_load) {
765 LocationSummary* locations = instruction->GetLocations();
766 Location base = locations->InAt(0);
767 Location index = locations->InAt(1);
768 *reg_loc = is_load ? locations->Out() : locations->InAt(2);
769 size_t size = Primitive::ComponentSize(instruction->GetPackedType());
770 uint32_t offset = mirror::Array::DataOffset(size).Uint32Value();
771 ScaleFactor scale = TIMES_1;
772 switch (size) {
773 case 2: scale = TIMES_2; break;
774 case 4: scale = TIMES_4; break;
775 case 8: scale = TIMES_8; break;
776 default: break;
777 }
778 return CodeGeneratorX86::ArrayAddress(base.AsRegister<Register>(), index, scale, offset);
779}
780
781void LocationsBuilderX86::VisitVecLoad(HVecLoad* instruction) {
782 CreateVecMemLocations(GetGraph()->GetArena(), instruction, /*is_load*/ true);
783}
784
785void InstructionCodeGeneratorX86::VisitVecLoad(HVecLoad* instruction) {
786 Location reg_loc = Location::NoLocation();
787 Address address = CreateVecMemRegisters(instruction, &reg_loc, /*is_load*/ true);
788 XmmRegister reg = reg_loc.AsFpuRegister<XmmRegister>();
789 bool is_aligned16 = instruction->GetAlignment().IsAlignedAt(16);
790 switch (instruction->GetPackedType()) {
791 case Primitive::kPrimBoolean:
792 case Primitive::kPrimByte:
793 case Primitive::kPrimChar:
794 case Primitive::kPrimShort:
795 case Primitive::kPrimInt:
796 case Primitive::kPrimLong:
797 DCHECK_LE(2u, instruction->GetVectorLength());
798 DCHECK_LE(instruction->GetVectorLength(), 16u);
799 is_aligned16 ? __ movdqa(reg, address) : __ movdqu(reg, address);
800 break;
801 case Primitive::kPrimFloat:
802 DCHECK_EQ(4u, instruction->GetVectorLength());
803 is_aligned16 ? __ movaps(reg, address) : __ movups(reg, address);
804 break;
805 case Primitive::kPrimDouble:
806 DCHECK_EQ(2u, instruction->GetVectorLength());
807 is_aligned16 ? __ movapd(reg, address) : __ movupd(reg, address);
808 break;
809 default:
810 LOG(FATAL) << "Unsupported SIMD type";
811 UNREACHABLE();
812 }
813}
814
815void LocationsBuilderX86::VisitVecStore(HVecStore* instruction) {
816 CreateVecMemLocations(GetGraph()->GetArena(), instruction, /*is_load*/ false);
817}
818
819void InstructionCodeGeneratorX86::VisitVecStore(HVecStore* instruction) {
820 Location reg_loc = Location::NoLocation();
821 Address address = CreateVecMemRegisters(instruction, &reg_loc, /*is_load*/ false);
822 XmmRegister reg = reg_loc.AsFpuRegister<XmmRegister>();
823 bool is_aligned16 = instruction->GetAlignment().IsAlignedAt(16);
824 switch (instruction->GetPackedType()) {
825 case Primitive::kPrimBoolean:
826 case Primitive::kPrimByte:
827 case Primitive::kPrimChar:
828 case Primitive::kPrimShort:
829 case Primitive::kPrimInt:
830 case Primitive::kPrimLong:
831 DCHECK_LE(2u, instruction->GetVectorLength());
832 DCHECK_LE(instruction->GetVectorLength(), 16u);
833 is_aligned16 ? __ movdqa(address, reg) : __ movdqu(address, reg);
834 break;
835 case Primitive::kPrimFloat:
836 DCHECK_EQ(4u, instruction->GetVectorLength());
837 is_aligned16 ? __ movaps(address, reg) : __ movups(address, reg);
838 break;
839 case Primitive::kPrimDouble:
840 DCHECK_EQ(2u, instruction->GetVectorLength());
841 is_aligned16 ? __ movapd(address, reg) : __ movupd(address, reg);
842 break;
843 default:
844 LOG(FATAL) << "Unsupported SIMD type";
845 UNREACHABLE();
846 }
847}
848
849#undef __
850
851} // namespace x86
852} // namespace art