blob: f4874fe2bc75162bcf5f10a64145a1c2194031d0 [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_arm64.h"
18#include "mirror/array-inl.h"
19
20using namespace vixl::aarch64; // NOLINT(build/namespaces)
21
22namespace art {
23namespace arm64 {
24
25using helpers::DRegisterFrom;
26using helpers::HeapOperand;
27using helpers::InputRegisterAt;
28using helpers::Int64ConstantFrom;
29using helpers::XRegisterFrom;
30
31#define __ GetVIXLAssembler()->
32
33void LocationsBuilderARM64::VisitVecReplicateScalar(HVecReplicateScalar* instruction) {
34 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
35 switch (instruction->GetPackedType()) {
36 case Primitive::kPrimBoolean:
37 case Primitive::kPrimByte:
38 case Primitive::kPrimChar:
39 case Primitive::kPrimShort:
40 case Primitive::kPrimInt:
41 locations->SetInAt(0, Location::RequiresRegister());
42 locations->SetOut(Location::RequiresFpuRegister());
43 break;
44 case Primitive::kPrimFloat:
45 locations->SetInAt(0, Location::RequiresFpuRegister());
46 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
47 break;
48 default:
49 LOG(FATAL) << "Unsupported SIMD type";
50 UNREACHABLE();
51 }
52}
53
54void InstructionCodeGeneratorARM64::VisitVecReplicateScalar(HVecReplicateScalar* instruction) {
55 LocationSummary* locations = instruction->GetLocations();
56 FPRegister dst = DRegisterFrom(locations->Out());
57 switch (instruction->GetPackedType()) {
58 case Primitive::kPrimBoolean:
59 case Primitive::kPrimByte:
60 DCHECK_EQ(8u, instruction->GetVectorLength());
61 __ Dup(dst.V8B(), InputRegisterAt(instruction, 0));
62 break;
63 case Primitive::kPrimChar:
64 case Primitive::kPrimShort:
65 DCHECK_EQ(4u, instruction->GetVectorLength());
66 __ Dup(dst.V4H(), InputRegisterAt(instruction, 0));
67 break;
68 case Primitive::kPrimInt:
69 DCHECK_EQ(2u, instruction->GetVectorLength());
70 __ Dup(dst.V2S(), InputRegisterAt(instruction, 0));
71 break;
72 case Primitive::kPrimFloat:
73 DCHECK_EQ(2u, instruction->GetVectorLength());
74 __ Dup(dst.V2S(), DRegisterFrom(locations->InAt(0)).V2S(), 0);
75 break;
76 default:
77 LOG(FATAL) << "Unsupported SIMD type";
78 UNREACHABLE();
79 }
80}
81
82void LocationsBuilderARM64::VisitVecSetScalars(HVecSetScalars* instruction) {
83 LOG(FATAL) << "No SIMD for " << instruction->GetId();
84}
85
86void InstructionCodeGeneratorARM64::VisitVecSetScalars(HVecSetScalars* instruction) {
87 LOG(FATAL) << "No SIMD for " << instruction->GetId();
88}
89
90void LocationsBuilderARM64::VisitVecSumReduce(HVecSumReduce* instruction) {
91 LOG(FATAL) << "No SIMD for " << instruction->GetId();
92}
93
94void InstructionCodeGeneratorARM64::VisitVecSumReduce(HVecSumReduce* instruction) {
95 LOG(FATAL) << "No SIMD for " << instruction->GetId();
96}
97
98// Helper to set up locations for vector unary operations.
99static void CreateVecUnOpLocations(ArenaAllocator* arena, HVecUnaryOperation* instruction) {
100 LocationSummary* locations = new (arena) LocationSummary(instruction);
101 switch (instruction->GetPackedType()) {
102 case Primitive::kPrimBoolean:
103 locations->SetInAt(0, Location::RequiresFpuRegister());
104 locations->SetOut(Location::RequiresFpuRegister(),
105 instruction->IsVecNot() ? Location::kOutputOverlap
106 : Location::kNoOutputOverlap);
107 break;
108 case Primitive::kPrimByte:
109 case Primitive::kPrimChar:
110 case Primitive::kPrimShort:
111 case Primitive::kPrimInt:
112 case Primitive::kPrimFloat:
113 locations->SetInAt(0, Location::RequiresFpuRegister());
114 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
115 break;
116 default:
117 LOG(FATAL) << "Unsupported SIMD type";
118 UNREACHABLE();
119 }
120}
121
122void LocationsBuilderARM64::VisitVecCnv(HVecCnv* instruction) {
123 CreateVecUnOpLocations(GetGraph()->GetArena(), instruction);
124}
125
126void InstructionCodeGeneratorARM64::VisitVecCnv(HVecCnv* instruction) {
127 LocationSummary* locations = instruction->GetLocations();
128 FPRegister src = DRegisterFrom(locations->InAt(0));
129 FPRegister dst = DRegisterFrom(locations->Out());
130 Primitive::Type from = instruction->GetInputType();
131 Primitive::Type to = instruction->GetResultType();
132 if (from == Primitive::kPrimInt && to == Primitive::kPrimFloat) {
133 DCHECK_EQ(2u, instruction->GetVectorLength());
134 __ Scvtf(dst.V2S(), src.V2S());
135 } else {
136 LOG(FATAL) << "Unsupported SIMD type";
137 }
138}
139
140void LocationsBuilderARM64::VisitVecNeg(HVecNeg* instruction) {
141 CreateVecUnOpLocations(GetGraph()->GetArena(), instruction);
142}
143
144void InstructionCodeGeneratorARM64::VisitVecNeg(HVecNeg* instruction) {
145 LocationSummary* locations = instruction->GetLocations();
146 FPRegister src = DRegisterFrom(locations->InAt(0));
147 FPRegister dst = DRegisterFrom(locations->Out());
148 switch (instruction->GetPackedType()) {
149 case Primitive::kPrimByte:
150 DCHECK_EQ(8u, instruction->GetVectorLength());
151 __ Neg(dst.V8B(), src.V8B());
152 break;
153 case Primitive::kPrimChar:
154 case Primitive::kPrimShort:
155 DCHECK_EQ(4u, instruction->GetVectorLength());
156 __ Neg(dst.V4H(), src.V4H());
157 break;
158 case Primitive::kPrimInt:
159 DCHECK_EQ(2u, instruction->GetVectorLength());
160 __ Neg(dst.V2S(), src.V2S());
161 break;
162 case Primitive::kPrimFloat:
163 DCHECK_EQ(2u, instruction->GetVectorLength());
164 __ Fneg(dst.V2S(), src.V2S());
165 break;
166 default:
167 LOG(FATAL) << "Unsupported SIMD type";
168 UNREACHABLE();
169 }
170}
171
Aart Bik6daebeb2017-04-03 14:35:41 -0700172void LocationsBuilderARM64::VisitVecAbs(HVecAbs* instruction) {
173 CreateVecUnOpLocations(GetGraph()->GetArena(), instruction);
174}
175
176void InstructionCodeGeneratorARM64::VisitVecAbs(HVecAbs* instruction) {
177 LocationSummary* locations = instruction->GetLocations();
178 FPRegister src = DRegisterFrom(locations->InAt(0));
179 FPRegister dst = DRegisterFrom(locations->Out());
180 switch (instruction->GetPackedType()) {
181 case Primitive::kPrimByte:
182 DCHECK_EQ(8u, instruction->GetVectorLength());
183 __ Abs(dst.V8B(), src.V8B());
184 break;
185 case Primitive::kPrimChar:
186 case Primitive::kPrimShort:
187 DCHECK_EQ(4u, instruction->GetVectorLength());
188 __ Abs(dst.V4H(), src.V4H());
189 break;
190 case Primitive::kPrimInt:
191 DCHECK_EQ(2u, instruction->GetVectorLength());
192 __ Abs(dst.V2S(), src.V2S());
193 break;
194 case Primitive::kPrimFloat:
195 DCHECK_EQ(2u, instruction->GetVectorLength());
196 __ Fabs(dst.V2S(), src.V2S());
197 break;
198 default:
199 LOG(FATAL) << "Unsupported SIMD type";
200 }
201}
202
Aart Bikf8f5a162017-02-06 15:35:29 -0800203void LocationsBuilderARM64::VisitVecNot(HVecNot* instruction) {
204 CreateVecUnOpLocations(GetGraph()->GetArena(), instruction);
205}
206
207void InstructionCodeGeneratorARM64::VisitVecNot(HVecNot* instruction) {
208 LocationSummary* locations = instruction->GetLocations();
209 FPRegister src = DRegisterFrom(locations->InAt(0));
210 FPRegister dst = DRegisterFrom(locations->Out());
211 switch (instruction->GetPackedType()) {
212 case Primitive::kPrimBoolean: // special case boolean-not
213 DCHECK_EQ(8u, instruction->GetVectorLength());
214 __ Movi(dst.V8B(), 1);
215 __ Eor(dst.V8B(), dst.V8B(), src.V8B());
216 break;
217 case Primitive::kPrimByte:
218 case Primitive::kPrimChar:
219 case Primitive::kPrimShort:
220 case Primitive::kPrimInt:
221 __ Not(dst.V8B(), src.V8B()); // lanes do not matter
222 break;
223 default:
224 LOG(FATAL) << "Unsupported SIMD type";
225 UNREACHABLE();
226 }
227}
228
229// Helper to set up locations for vector binary operations.
230static void CreateVecBinOpLocations(ArenaAllocator* arena, HVecBinaryOperation* instruction) {
231 LocationSummary* locations = new (arena) LocationSummary(instruction);
232 switch (instruction->GetPackedType()) {
233 case Primitive::kPrimBoolean:
234 case Primitive::kPrimByte:
235 case Primitive::kPrimChar:
236 case Primitive::kPrimShort:
237 case Primitive::kPrimInt:
238 case Primitive::kPrimFloat:
239 locations->SetInAt(0, Location::RequiresFpuRegister());
240 locations->SetInAt(1, Location::RequiresFpuRegister());
241 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
242 break;
243 default:
244 LOG(FATAL) << "Unsupported SIMD type";
245 UNREACHABLE();
246 }
247}
248
249void LocationsBuilderARM64::VisitVecAdd(HVecAdd* instruction) {
250 CreateVecBinOpLocations(GetGraph()->GetArena(), instruction);
251}
252
253void InstructionCodeGeneratorARM64::VisitVecAdd(HVecAdd* instruction) {
254 LocationSummary* locations = instruction->GetLocations();
255 FPRegister lhs = DRegisterFrom(locations->InAt(0));
256 FPRegister rhs = DRegisterFrom(locations->InAt(1));
257 FPRegister dst = DRegisterFrom(locations->Out());
258 switch (instruction->GetPackedType()) {
259 case Primitive::kPrimByte:
260 DCHECK_EQ(8u, instruction->GetVectorLength());
261 __ Add(dst.V8B(), lhs.V8B(), rhs.V8B());
262 break;
263 case Primitive::kPrimChar:
264 case Primitive::kPrimShort:
265 DCHECK_EQ(4u, instruction->GetVectorLength());
266 __ Add(dst.V4H(), lhs.V4H(), rhs.V4H());
267 break;
268 case Primitive::kPrimInt:
269 DCHECK_EQ(2u, instruction->GetVectorLength());
270 __ Add(dst.V2S(), lhs.V2S(), rhs.V2S());
271 break;
272 case Primitive::kPrimFloat:
273 DCHECK_EQ(2u, instruction->GetVectorLength());
274 __ Fadd(dst.V2S(), lhs.V2S(), rhs.V2S());
275 break;
276 default:
277 LOG(FATAL) << "Unsupported SIMD type";
278 UNREACHABLE();
279 }
280}
281
282void LocationsBuilderARM64::VisitVecSub(HVecSub* instruction) {
283 CreateVecBinOpLocations(GetGraph()->GetArena(), instruction);
284}
285
286void InstructionCodeGeneratorARM64::VisitVecSub(HVecSub* instruction) {
287 LocationSummary* locations = instruction->GetLocations();
288 FPRegister lhs = DRegisterFrom(locations->InAt(0));
289 FPRegister rhs = DRegisterFrom(locations->InAt(1));
290 FPRegister dst = DRegisterFrom(locations->Out());
291 switch (instruction->GetPackedType()) {
292 case Primitive::kPrimByte:
293 DCHECK_EQ(8u, instruction->GetVectorLength());
294 __ Sub(dst.V8B(), lhs.V8B(), rhs.V8B());
295 break;
296 case Primitive::kPrimChar:
297 case Primitive::kPrimShort:
298 DCHECK_EQ(4u, instruction->GetVectorLength());
299 __ Sub(dst.V4H(), lhs.V4H(), rhs.V4H());
300 break;
301 case Primitive::kPrimInt:
302 DCHECK_EQ(2u, instruction->GetVectorLength());
303 __ Sub(dst.V2S(), lhs.V2S(), rhs.V2S());
304 break;
305 case Primitive::kPrimFloat:
306 DCHECK_EQ(2u, instruction->GetVectorLength());
307 __ Fsub(dst.V2S(), lhs.V2S(), rhs.V2S());
308 break;
309 default:
310 LOG(FATAL) << "Unsupported SIMD type";
311 UNREACHABLE();
312 }
313}
314
315void LocationsBuilderARM64::VisitVecMul(HVecMul* instruction) {
316 CreateVecBinOpLocations(GetGraph()->GetArena(), instruction);
317}
318
319void InstructionCodeGeneratorARM64::VisitVecMul(HVecMul* instruction) {
320 LocationSummary* locations = instruction->GetLocations();
321 FPRegister lhs = DRegisterFrom(locations->InAt(0));
322 FPRegister rhs = DRegisterFrom(locations->InAt(1));
323 FPRegister dst = DRegisterFrom(locations->Out());
324 switch (instruction->GetPackedType()) {
325 case Primitive::kPrimByte:
326 DCHECK_EQ(8u, instruction->GetVectorLength());
327 __ Mul(dst.V8B(), lhs.V8B(), rhs.V8B());
328 break;
329 case Primitive::kPrimChar:
330 case Primitive::kPrimShort:
331 DCHECK_EQ(4u, instruction->GetVectorLength());
332 __ Mul(dst.V4H(), lhs.V4H(), rhs.V4H());
333 break;
334 case Primitive::kPrimInt:
335 DCHECK_EQ(2u, instruction->GetVectorLength());
336 __ Mul(dst.V2S(), lhs.V2S(), rhs.V2S());
337 break;
338 case Primitive::kPrimFloat:
339 DCHECK_EQ(2u, instruction->GetVectorLength());
340 __ Fmul(dst.V2S(), lhs.V2S(), rhs.V2S());
341 break;
342 default:
343 LOG(FATAL) << "Unsupported SIMD type";
344 UNREACHABLE();
345 }
346}
347
348void LocationsBuilderARM64::VisitVecDiv(HVecDiv* instruction) {
349 CreateVecBinOpLocations(GetGraph()->GetArena(), instruction);
350}
351
352void InstructionCodeGeneratorARM64::VisitVecDiv(HVecDiv* instruction) {
353 LocationSummary* locations = instruction->GetLocations();
354 FPRegister lhs = DRegisterFrom(locations->InAt(0));
355 FPRegister rhs = DRegisterFrom(locations->InAt(1));
356 FPRegister dst = DRegisterFrom(locations->Out());
357 switch (instruction->GetPackedType()) {
358 case Primitive::kPrimFloat:
359 DCHECK_EQ(2u, instruction->GetVectorLength());
360 __ Fdiv(dst.V2S(), lhs.V2S(), rhs.V2S());
361 break;
362 default:
363 LOG(FATAL) << "Unsupported SIMD type";
364 UNREACHABLE();
365 }
366}
367
368void LocationsBuilderARM64::VisitVecAnd(HVecAnd* instruction) {
369 CreateVecBinOpLocations(GetGraph()->GetArena(), instruction);
370}
371
372void InstructionCodeGeneratorARM64::VisitVecAnd(HVecAnd* instruction) {
373 LocationSummary* locations = instruction->GetLocations();
374 FPRegister lhs = DRegisterFrom(locations->InAt(0));
375 FPRegister rhs = DRegisterFrom(locations->InAt(1));
376 FPRegister dst = DRegisterFrom(locations->Out());
377 switch (instruction->GetPackedType()) {
378 case Primitive::kPrimBoolean:
379 case Primitive::kPrimByte:
380 case Primitive::kPrimChar:
381 case Primitive::kPrimShort:
382 case Primitive::kPrimInt:
383 case Primitive::kPrimFloat:
384 __ And(dst.V8B(), lhs.V8B(), rhs.V8B()); // lanes do not matter
385 break;
386 default:
387 LOG(FATAL) << "Unsupported SIMD type";
388 UNREACHABLE();
389 }
390}
391
392void LocationsBuilderARM64::VisitVecAndNot(HVecAndNot* instruction) {
393 LOG(FATAL) << "Unsupported SIMD instruction " << instruction->GetId();
394}
395
396void InstructionCodeGeneratorARM64::VisitVecAndNot(HVecAndNot* instruction) {
397 LOG(FATAL) << "Unsupported SIMD instruction " << instruction->GetId();
398}
399
400void LocationsBuilderARM64::VisitVecOr(HVecOr* instruction) {
401 CreateVecBinOpLocations(GetGraph()->GetArena(), instruction);
402}
403
404void InstructionCodeGeneratorARM64::VisitVecOr(HVecOr* instruction) {
405 LocationSummary* locations = instruction->GetLocations();
406 FPRegister lhs = DRegisterFrom(locations->InAt(0));
407 FPRegister rhs = DRegisterFrom(locations->InAt(1));
408 FPRegister dst = DRegisterFrom(locations->Out());
409 switch (instruction->GetPackedType()) {
410 case Primitive::kPrimBoolean:
411 case Primitive::kPrimByte:
412 case Primitive::kPrimChar:
413 case Primitive::kPrimShort:
414 case Primitive::kPrimInt:
415 case Primitive::kPrimFloat:
416 __ Orr(dst.V8B(), lhs.V8B(), rhs.V8B()); // lanes do not matter
417 break;
418 default:
419 LOG(FATAL) << "Unsupported SIMD type";
420 UNREACHABLE();
421 }
422}
423
424void LocationsBuilderARM64::VisitVecXor(HVecXor* instruction) {
425 CreateVecBinOpLocations(GetGraph()->GetArena(), instruction);
426}
427
428void InstructionCodeGeneratorARM64::VisitVecXor(HVecXor* instruction) {
429 LocationSummary* locations = instruction->GetLocations();
430 FPRegister lhs = DRegisterFrom(locations->InAt(0));
431 FPRegister rhs = DRegisterFrom(locations->InAt(1));
432 FPRegister dst = DRegisterFrom(locations->Out());
433 switch (instruction->GetPackedType()) {
434 case Primitive::kPrimBoolean:
435 case Primitive::kPrimByte:
436 case Primitive::kPrimChar:
437 case Primitive::kPrimShort:
438 case Primitive::kPrimInt:
439 case Primitive::kPrimFloat:
440 __ Eor(dst.V8B(), lhs.V8B(), rhs.V8B()); // lanes do not matter
441 break;
442 default:
443 LOG(FATAL) << "Unsupported SIMD type";
444 UNREACHABLE();
445 }
446}
447
448// Helper to set up locations for vector shift operations.
449static void CreateVecShiftLocations(ArenaAllocator* arena, HVecBinaryOperation* instruction) {
450 LocationSummary* locations = new (arena) LocationSummary(instruction);
451 switch (instruction->GetPackedType()) {
452 case Primitive::kPrimByte:
453 case Primitive::kPrimChar:
454 case Primitive::kPrimShort:
455 case Primitive::kPrimInt:
456 locations->SetInAt(0, Location::RequiresFpuRegister());
457 locations->SetInAt(1, Location::ConstantLocation(instruction->InputAt(1)->AsConstant()));
458 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
459 break;
460 default:
461 LOG(FATAL) << "Unsupported SIMD type";
462 UNREACHABLE();
463 }
464}
465
466void LocationsBuilderARM64::VisitVecShl(HVecShl* instruction) {
467 CreateVecShiftLocations(GetGraph()->GetArena(), instruction);
468}
469
470void InstructionCodeGeneratorARM64::VisitVecShl(HVecShl* instruction) {
471 LocationSummary* locations = instruction->GetLocations();
472 FPRegister lhs = DRegisterFrom(locations->InAt(0));
473 FPRegister dst = DRegisterFrom(locations->Out());
474 int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
475 switch (instruction->GetPackedType()) {
476 case Primitive::kPrimByte:
477 DCHECK_EQ(8u, instruction->GetVectorLength());
478 __ Shl(dst.V8B(), lhs.V8B(), value);
479 break;
480 case Primitive::kPrimChar:
481 case Primitive::kPrimShort:
482 DCHECK_EQ(4u, instruction->GetVectorLength());
483 __ Shl(dst.V4H(), lhs.V4H(), value);
484 break;
485 case Primitive::kPrimInt:
486 DCHECK_EQ(2u, instruction->GetVectorLength());
487 __ Shl(dst.V2S(), lhs.V2S(), value);
488 break;
489 default:
490 LOG(FATAL) << "Unsupported SIMD type";
491 UNREACHABLE();
492 }
493}
494
495void LocationsBuilderARM64::VisitVecShr(HVecShr* instruction) {
496 CreateVecShiftLocations(GetGraph()->GetArena(), instruction);
497}
498
499void InstructionCodeGeneratorARM64::VisitVecShr(HVecShr* instruction) {
500 LocationSummary* locations = instruction->GetLocations();
501 FPRegister lhs = DRegisterFrom(locations->InAt(0));
502 FPRegister dst = DRegisterFrom(locations->Out());
503 int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
504 switch (instruction->GetPackedType()) {
505 case Primitive::kPrimByte:
506 DCHECK_EQ(8u, instruction->GetVectorLength());
507 __ Sshr(dst.V8B(), lhs.V8B(), value);
508 break;
509 case Primitive::kPrimChar:
510 case Primitive::kPrimShort:
511 DCHECK_EQ(4u, instruction->GetVectorLength());
512 __ Sshr(dst.V4H(), lhs.V4H(), value);
513 break;
514 case Primitive::kPrimInt:
515 DCHECK_EQ(2u, instruction->GetVectorLength());
516 __ Sshr(dst.V2S(), lhs.V2S(), value);
517 break;
518 default:
519 LOG(FATAL) << "Unsupported SIMD type";
520 UNREACHABLE();
521 }
522}
523
524void LocationsBuilderARM64::VisitVecUShr(HVecUShr* instruction) {
525 CreateVecShiftLocations(GetGraph()->GetArena(), instruction);
526}
527
528void InstructionCodeGeneratorARM64::VisitVecUShr(HVecUShr* instruction) {
529 LocationSummary* locations = instruction->GetLocations();
530 FPRegister lhs = DRegisterFrom(locations->InAt(0));
531 FPRegister dst = DRegisterFrom(locations->Out());
532 int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
533 switch (instruction->GetPackedType()) {
534 case Primitive::kPrimByte:
535 DCHECK_EQ(8u, instruction->GetVectorLength());
536 __ Ushr(dst.V8B(), lhs.V8B(), value);
537 break;
538 case Primitive::kPrimChar:
539 case Primitive::kPrimShort:
540 DCHECK_EQ(4u, instruction->GetVectorLength());
541 __ Ushr(dst.V4H(), lhs.V4H(), value);
542 break;
543 case Primitive::kPrimInt:
544 DCHECK_EQ(2u, instruction->GetVectorLength());
545 __ Ushr(dst.V2S(), lhs.V2S(), value);
546 break;
547 default:
548 LOG(FATAL) << "Unsupported SIMD type";
549 UNREACHABLE();
550 }
551}
552
553// Helper to set up locations for vector memory operations.
554static void CreateVecMemLocations(ArenaAllocator* arena,
555 HVecMemoryOperation* instruction,
556 bool is_load) {
557 LocationSummary* locations = new (arena) LocationSummary(instruction);
558 switch (instruction->GetPackedType()) {
559 case Primitive::kPrimBoolean:
560 case Primitive::kPrimByte:
561 case Primitive::kPrimChar:
562 case Primitive::kPrimShort:
563 case Primitive::kPrimInt:
564 case Primitive::kPrimFloat:
565 locations->SetInAt(0, Location::RequiresRegister());
566 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
567 if (is_load) {
568 locations->SetOut(Location::RequiresFpuRegister());
569 } else {
570 locations->SetInAt(2, Location::RequiresFpuRegister());
571 }
572 break;
573 default:
574 LOG(FATAL) << "Unsupported SIMD type";
575 UNREACHABLE();
576 }
577}
578
579// Helper to set up registers and address for vector memory operations.
580MemOperand InstructionCodeGeneratorARM64::CreateVecMemRegisters(
581 HVecMemoryOperation* instruction,
582 Location* reg_loc,
583 bool is_load) {
584 LocationSummary* locations = instruction->GetLocations();
585 Register base = InputRegisterAt(instruction, 0);
586 Location index = locations->InAt(1);
587 *reg_loc = is_load ? locations->Out() : locations->InAt(2);
588
589 Primitive::Type packed_type = instruction->GetPackedType();
590 uint32_t offset = mirror::Array::DataOffset(Primitive::ComponentSize(packed_type)).Uint32Value();
591 size_t shift = Primitive::ComponentSizeShift(packed_type);
592
593 UseScratchRegisterScope temps(GetVIXLAssembler());
594 Register temp = temps.AcquireSameSizeAs(base);
595 if (index.IsConstant()) {
596 offset += Int64ConstantFrom(index) << shift;
597 __ Add(temp, base, offset);
598 } else {
599 if (instruction->InputAt(0)->IsIntermediateAddress()) {
600 temp = base;
601 } else {
602 __ Add(temp, base, offset);
603 }
604 __ Add(temp.X(), temp.X(), Operand(XRegisterFrom(index), LSL, shift));
605 }
606 return HeapOperand(temp);
607}
608
609void LocationsBuilderARM64::VisitVecLoad(HVecLoad* instruction) {
610 CreateVecMemLocations(GetGraph()->GetArena(), instruction, /*is_load*/ true);
611}
612
613void InstructionCodeGeneratorARM64::VisitVecLoad(HVecLoad* instruction) {
614 Location reg_loc = Location::NoLocation();
615 MemOperand mem = CreateVecMemRegisters(instruction, &reg_loc, /*is_load*/ true);
616 FPRegister reg = DRegisterFrom(reg_loc);
617 switch (instruction->GetPackedType()) {
618 case Primitive::kPrimBoolean:
619 case Primitive::kPrimByte:
620 DCHECK_EQ(8u, instruction->GetVectorLength());
621 __ Ld1(reg.V8B(), mem);
622 break;
623 case Primitive::kPrimChar:
624 case Primitive::kPrimShort:
625 DCHECK_EQ(4u, instruction->GetVectorLength());
626 __ Ld1(reg.V4H(), mem);
627 break;
628 case Primitive::kPrimInt:
629 case Primitive::kPrimFloat:
630 DCHECK_EQ(2u, instruction->GetVectorLength());
631 __ Ld1(reg.V2S(), mem);
632 break;
633 default:
634 LOG(FATAL) << "Unsupported SIMD type";
635 UNREACHABLE();
636 }
637}
638
639void LocationsBuilderARM64::VisitVecStore(HVecStore* instruction) {
640 CreateVecMemLocations(GetGraph()->GetArena(), instruction, /*is_load*/ false);
641}
642
643void InstructionCodeGeneratorARM64::VisitVecStore(HVecStore* instruction) {
644 Location reg_loc = Location::NoLocation();
645 MemOperand mem = CreateVecMemRegisters(instruction, &reg_loc, /*is_load*/ false);
646 FPRegister reg = DRegisterFrom(reg_loc);
647 switch (instruction->GetPackedType()) {
648 case Primitive::kPrimBoolean:
649 case Primitive::kPrimByte:
650 DCHECK_EQ(8u, instruction->GetVectorLength());
651 __ St1(reg.V8B(), mem);
652 break;
653 case Primitive::kPrimChar:
654 case Primitive::kPrimShort:
655 DCHECK_EQ(4u, instruction->GetVectorLength());
656 __ St1(reg.V4H(), mem);
657 break;
658 case Primitive::kPrimInt:
659 case Primitive::kPrimFloat:
660 DCHECK_EQ(2u, instruction->GetVectorLength());
661 __ St1(reg.V2S(), mem);
662 break;
663 default:
664 LOG(FATAL) << "Unsupported SIMD type";
665 UNREACHABLE();
666 }
667}
668
669#undef __
670
671} // namespace arm64
672} // namespace art