blob: 0395db1df91163c54dd0b0070116d7e594869bef [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_mips64.h"
Goran Jakovljevic19680d32017-05-11 10:38:36 +020018#include "mirror/array-inl.h"
Aart Bikf8f5a162017-02-06 15:35:29 -080019
20namespace art {
21namespace mips64 {
22
23// NOLINT on __ macro to suppress wrong warning/fix (misc-macro-parentheses) from clang-tidy.
24#define __ down_cast<Mips64Assembler*>(GetAssembler())-> // NOLINT
25
Goran Jakovljevic19680d32017-05-11 10:38:36 +020026VectorRegister VectorRegisterFrom(Location location) {
27 DCHECK(location.IsFpuRegister());
28 return static_cast<VectorRegister>(location.AsFpuRegister<FpuRegister>());
29}
30
Aart Bikf8f5a162017-02-06 15:35:29 -080031void LocationsBuilderMIPS64::VisitVecReplicateScalar(HVecReplicateScalar* instruction) {
Goran Jakovljevic19680d32017-05-11 10:38:36 +020032 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
33 switch (instruction->GetPackedType()) {
34 case Primitive::kPrimBoolean:
35 case Primitive::kPrimByte:
36 case Primitive::kPrimChar:
37 case Primitive::kPrimShort:
38 case Primitive::kPrimInt:
39 case Primitive::kPrimLong:
40 locations->SetInAt(0, Location::RequiresRegister());
41 locations->SetOut(Location::RequiresFpuRegister());
42 break;
43 case Primitive::kPrimFloat:
44 case Primitive::kPrimDouble:
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 }
Aart Bikf8f5a162017-02-06 15:35:29 -080052}
53
54void InstructionCodeGeneratorMIPS64::VisitVecReplicateScalar(HVecReplicateScalar* instruction) {
Goran Jakovljevic19680d32017-05-11 10:38:36 +020055 LocationSummary* locations = instruction->GetLocations();
56 VectorRegister dst = VectorRegisterFrom(locations->Out());
57 switch (instruction->GetPackedType()) {
58 case Primitive::kPrimBoolean:
59 case Primitive::kPrimByte:
60 DCHECK_EQ(16u, instruction->GetVectorLength());
61 __ FillB(dst, locations->InAt(0).AsRegister<GpuRegister>());
62 break;
63 case Primitive::kPrimChar:
64 case Primitive::kPrimShort:
65 DCHECK_EQ(8u, instruction->GetVectorLength());
66 __ FillH(dst, locations->InAt(0).AsRegister<GpuRegister>());
67 break;
68 case Primitive::kPrimInt:
69 DCHECK_EQ(4u, instruction->GetVectorLength());
70 __ FillW(dst, locations->InAt(0).AsRegister<GpuRegister>());
71 break;
72 case Primitive::kPrimLong:
73 DCHECK_EQ(2u, instruction->GetVectorLength());
74 __ FillD(dst, locations->InAt(0).AsRegister<GpuRegister>());
75 break;
76 case Primitive::kPrimFloat:
77 DCHECK_EQ(4u, instruction->GetVectorLength());
78 __ ReplicateFPToVectorRegister(dst,
79 locations->InAt(0).AsFpuRegister<FpuRegister>(),
80 /* is_double */ false);
81 break;
82 case Primitive::kPrimDouble:
83 DCHECK_EQ(2u, instruction->GetVectorLength());
84 __ ReplicateFPToVectorRegister(dst,
85 locations->InAt(0).AsFpuRegister<FpuRegister>(),
86 /* is_double */ true);
87 break;
88 default:
89 LOG(FATAL) << "Unsupported SIMD type";
90 UNREACHABLE();
91 }
Aart Bikf8f5a162017-02-06 15:35:29 -080092}
93
94void LocationsBuilderMIPS64::VisitVecSetScalars(HVecSetScalars* instruction) {
95 LOG(FATAL) << "No SIMD for " << instruction->GetId();
96}
97
98void InstructionCodeGeneratorMIPS64::VisitVecSetScalars(HVecSetScalars* instruction) {
99 LOG(FATAL) << "No SIMD for " << instruction->GetId();
100}
101
102void LocationsBuilderMIPS64::VisitVecSumReduce(HVecSumReduce* instruction) {
103 LOG(FATAL) << "No SIMD for " << instruction->GetId();
104}
105
106void InstructionCodeGeneratorMIPS64::VisitVecSumReduce(HVecSumReduce* instruction) {
107 LOG(FATAL) << "No SIMD for " << instruction->GetId();
108}
109
110// Helper to set up locations for vector unary operations.
111static void CreateVecUnOpLocations(ArenaAllocator* arena, HVecUnaryOperation* instruction) {
112 LocationSummary* locations = new (arena) LocationSummary(instruction);
113 switch (instruction->GetPackedType()) {
114 case Primitive::kPrimBoolean:
Goran Jakovljevic19680d32017-05-11 10:38:36 +0200115 locations->SetInAt(0, Location::RequiresFpuRegister());
116 locations->SetOut(Location::RequiresFpuRegister(),
117 instruction->IsVecNot() ? Location::kOutputOverlap
118 : Location::kNoOutputOverlap);
119 break;
Aart Bikf8f5a162017-02-06 15:35:29 -0800120 case Primitive::kPrimByte:
121 case Primitive::kPrimChar:
122 case Primitive::kPrimShort:
123 case Primitive::kPrimInt:
Goran Jakovljevic19680d32017-05-11 10:38:36 +0200124 case Primitive::kPrimLong:
Aart Bikf8f5a162017-02-06 15:35:29 -0800125 case Primitive::kPrimFloat:
126 case Primitive::kPrimDouble:
Goran Jakovljevic19680d32017-05-11 10:38:36 +0200127 locations->SetInAt(0, Location::RequiresFpuRegister());
128 locations->SetOut(Location::RequiresFpuRegister(),
129 (instruction->IsVecNeg() || instruction->IsVecAbs())
130 ? Location::kOutputOverlap
131 : Location::kNoOutputOverlap);
Aart Bikf8f5a162017-02-06 15:35:29 -0800132 break;
133 default:
134 LOG(FATAL) << "Unsupported SIMD type";
135 UNREACHABLE();
136 }
137}
138
139void LocationsBuilderMIPS64::VisitVecCnv(HVecCnv* instruction) {
140 CreateVecUnOpLocations(GetGraph()->GetArena(), instruction);
141}
142
143void InstructionCodeGeneratorMIPS64::VisitVecCnv(HVecCnv* instruction) {
Goran Jakovljevic19680d32017-05-11 10:38:36 +0200144 LocationSummary* locations = instruction->GetLocations();
145 VectorRegister src = VectorRegisterFrom(locations->InAt(0));
146 VectorRegister dst = VectorRegisterFrom(locations->Out());
147 Primitive::Type from = instruction->GetInputType();
148 Primitive::Type to = instruction->GetResultType();
149 if (from == Primitive::kPrimInt && to == Primitive::kPrimFloat) {
150 DCHECK_EQ(4u, instruction->GetVectorLength());
151 __ Ffint_sW(dst, src);
152 } else {
153 LOG(FATAL) << "Unsupported SIMD type";
154 UNREACHABLE();
155 }
Aart Bikf8f5a162017-02-06 15:35:29 -0800156}
157
158void LocationsBuilderMIPS64::VisitVecNeg(HVecNeg* instruction) {
159 CreateVecUnOpLocations(GetGraph()->GetArena(), instruction);
160}
161
162void InstructionCodeGeneratorMIPS64::VisitVecNeg(HVecNeg* instruction) {
Goran Jakovljevic19680d32017-05-11 10:38:36 +0200163 LocationSummary* locations = instruction->GetLocations();
164 VectorRegister src = VectorRegisterFrom(locations->InAt(0));
165 VectorRegister dst = VectorRegisterFrom(locations->Out());
166 switch (instruction->GetPackedType()) {
167 case Primitive::kPrimByte:
168 DCHECK_EQ(16u, instruction->GetVectorLength());
169 __ FillB(dst, ZERO);
170 __ SubvB(dst, dst, src);
171 break;
172 case Primitive::kPrimChar:
173 case Primitive::kPrimShort:
174 DCHECK_EQ(8u, instruction->GetVectorLength());
175 __ FillH(dst, ZERO);
176 __ SubvH(dst, dst, src);
177 break;
178 case Primitive::kPrimInt:
179 DCHECK_EQ(4u, instruction->GetVectorLength());
180 __ FillW(dst, ZERO);
181 __ SubvW(dst, dst, src);
182 break;
183 case Primitive::kPrimLong:
184 DCHECK_EQ(2u, instruction->GetVectorLength());
185 __ FillD(dst, ZERO);
186 __ SubvD(dst, dst, src);
187 break;
188 case Primitive::kPrimFloat:
189 DCHECK_EQ(4u, instruction->GetVectorLength());
190 __ FillW(dst, ZERO);
191 __ FsubW(dst, dst, src);
192 break;
193 case Primitive::kPrimDouble:
194 DCHECK_EQ(2u, instruction->GetVectorLength());
195 __ FillD(dst, ZERO);
196 __ FsubD(dst, dst, src);
197 break;
198 default:
199 LOG(FATAL) << "Unsupported SIMD type";
200 UNREACHABLE();
201 }
Aart Bikf8f5a162017-02-06 15:35:29 -0800202}
203
Aart Bik6daebeb2017-04-03 14:35:41 -0700204void LocationsBuilderMIPS64::VisitVecAbs(HVecAbs* instruction) {
205 CreateVecUnOpLocations(GetGraph()->GetArena(), instruction);
206}
207
208void InstructionCodeGeneratorMIPS64::VisitVecAbs(HVecAbs* instruction) {
Goran Jakovljevic19680d32017-05-11 10:38:36 +0200209 LocationSummary* locations = instruction->GetLocations();
210 VectorRegister src = VectorRegisterFrom(locations->InAt(0));
211 VectorRegister dst = VectorRegisterFrom(locations->Out());
212 switch (instruction->GetPackedType()) {
213 case Primitive::kPrimByte:
214 DCHECK_EQ(16u, instruction->GetVectorLength());
215 __ FillB(dst, ZERO); // all zeroes
216 __ Add_aB(dst, dst, src); // dst = abs(0) + abs(src)
217 break;
218 case Primitive::kPrimChar:
219 case Primitive::kPrimShort:
220 DCHECK_EQ(8u, instruction->GetVectorLength());
221 __ FillH(dst, ZERO); // all zeroes
222 __ Add_aH(dst, dst, src); // dst = abs(0) + abs(src)
223 break;
224 case Primitive::kPrimInt:
225 DCHECK_EQ(4u, instruction->GetVectorLength());
226 __ FillW(dst, ZERO); // all zeroes
227 __ Add_aW(dst, dst, src); // dst = abs(0) + abs(src)
228 break;
229 case Primitive::kPrimLong:
230 DCHECK_EQ(2u, instruction->GetVectorLength());
231 __ FillD(dst, ZERO); // all zeroes
232 __ Add_aD(dst, dst, src); // dst = abs(0) + abs(src)
233 break;
234 case Primitive::kPrimFloat:
235 DCHECK_EQ(4u, instruction->GetVectorLength());
236 __ LdiW(dst, -1); // all ones
237 __ SrliW(dst, dst, 1);
238 __ AndV(dst, dst, src);
239 break;
240 case Primitive::kPrimDouble:
241 DCHECK_EQ(2u, instruction->GetVectorLength());
242 __ LdiD(dst, -1); // all ones
243 __ SrliD(dst, dst, 1);
244 __ AndV(dst, dst, src);
245 break;
246 default:
247 LOG(FATAL) << "Unsupported SIMD type";
248 UNREACHABLE();
249 }
Aart Bik6daebeb2017-04-03 14:35:41 -0700250}
251
Aart Bikf8f5a162017-02-06 15:35:29 -0800252void LocationsBuilderMIPS64::VisitVecNot(HVecNot* instruction) {
253 CreateVecUnOpLocations(GetGraph()->GetArena(), instruction);
254}
255
256void InstructionCodeGeneratorMIPS64::VisitVecNot(HVecNot* instruction) {
Goran Jakovljevic19680d32017-05-11 10:38:36 +0200257 LocationSummary* locations = instruction->GetLocations();
258 VectorRegister src = VectorRegisterFrom(locations->InAt(0));
259 VectorRegister dst = VectorRegisterFrom(locations->Out());
260 switch (instruction->GetPackedType()) {
261 case Primitive::kPrimBoolean: // special case boolean-not
262 DCHECK_EQ(16u, instruction->GetVectorLength());
263 __ LdiB(dst, 1);
264 __ XorV(dst, dst, src);
265 break;
266 case Primitive::kPrimByte:
267 case Primitive::kPrimChar:
268 case Primitive::kPrimShort:
269 case Primitive::kPrimInt:
270 case Primitive::kPrimLong:
271 case Primitive::kPrimFloat:
272 case Primitive::kPrimDouble:
273 DCHECK_LE(2u, instruction->GetVectorLength());
274 DCHECK_LE(instruction->GetVectorLength(), 16u);
275 __ NorV(dst, src, src); // lanes do not matter
276 break;
277 default:
278 LOG(FATAL) << "Unsupported SIMD type";
279 UNREACHABLE();
280 }
Aart Bikf8f5a162017-02-06 15:35:29 -0800281}
282
283// Helper to set up locations for vector binary operations.
284static void CreateVecBinOpLocations(ArenaAllocator* arena, HVecBinaryOperation* instruction) {
285 LocationSummary* locations = new (arena) LocationSummary(instruction);
286 switch (instruction->GetPackedType()) {
287 case Primitive::kPrimBoolean:
288 case Primitive::kPrimByte:
289 case Primitive::kPrimChar:
290 case Primitive::kPrimShort:
291 case Primitive::kPrimInt:
Goran Jakovljevic19680d32017-05-11 10:38:36 +0200292 case Primitive::kPrimLong:
Aart Bikf8f5a162017-02-06 15:35:29 -0800293 case Primitive::kPrimFloat:
294 case Primitive::kPrimDouble:
Goran Jakovljevic19680d32017-05-11 10:38:36 +0200295 locations->SetInAt(0, Location::RequiresFpuRegister());
296 locations->SetInAt(1, Location::RequiresFpuRegister());
297 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Aart Bikf8f5a162017-02-06 15:35:29 -0800298 break;
299 default:
300 LOG(FATAL) << "Unsupported SIMD type";
301 UNREACHABLE();
302 }
303}
304
305void LocationsBuilderMIPS64::VisitVecAdd(HVecAdd* instruction) {
306 CreateVecBinOpLocations(GetGraph()->GetArena(), instruction);
307}
308
309void InstructionCodeGeneratorMIPS64::VisitVecAdd(HVecAdd* instruction) {
Goran Jakovljevic19680d32017-05-11 10:38:36 +0200310 LocationSummary* locations = instruction->GetLocations();
311 VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
312 VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
313 VectorRegister dst = VectorRegisterFrom(locations->Out());
314 switch (instruction->GetPackedType()) {
315 case Primitive::kPrimByte:
316 DCHECK_EQ(16u, instruction->GetVectorLength());
317 __ AddvB(dst, lhs, rhs);
318 break;
319 case Primitive::kPrimChar:
320 case Primitive::kPrimShort:
321 DCHECK_EQ(8u, instruction->GetVectorLength());
322 __ AddvH(dst, lhs, rhs);
323 break;
324 case Primitive::kPrimInt:
325 DCHECK_EQ(4u, instruction->GetVectorLength());
326 __ AddvW(dst, lhs, rhs);
327 break;
328 case Primitive::kPrimLong:
329 DCHECK_EQ(2u, instruction->GetVectorLength());
330 __ AddvD(dst, lhs, rhs);
331 break;
332 case Primitive::kPrimFloat:
333 DCHECK_EQ(4u, instruction->GetVectorLength());
334 __ FaddW(dst, lhs, rhs);
335 break;
336 case Primitive::kPrimDouble:
337 DCHECK_EQ(2u, instruction->GetVectorLength());
338 __ FaddD(dst, lhs, rhs);
339 break;
340 default:
341 LOG(FATAL) << "Unsupported SIMD type";
342 UNREACHABLE();
343 }
Aart Bikf8f5a162017-02-06 15:35:29 -0800344}
345
Aart Bikf3e61ee2017-04-12 17:09:20 -0700346void LocationsBuilderMIPS64::VisitVecHalvingAdd(HVecHalvingAdd* instruction) {
347 CreateVecBinOpLocations(GetGraph()->GetArena(), instruction);
348}
349
350void InstructionCodeGeneratorMIPS64::VisitVecHalvingAdd(HVecHalvingAdd* instruction) {
Goran Jakovljevic19680d32017-05-11 10:38:36 +0200351 LocationSummary* locations = instruction->GetLocations();
352 VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
353 VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
354 VectorRegister dst = VectorRegisterFrom(locations->Out());
355 switch (instruction->GetPackedType()) {
356 case Primitive::kPrimByte:
357 DCHECK_EQ(16u, instruction->GetVectorLength());
358 if (instruction->IsUnsigned()) {
359 instruction->IsRounded()
360 ? __ Aver_uB(dst, lhs, rhs)
361 : __ Ave_uB(dst, lhs, rhs);
362 } else {
363 instruction->IsRounded()
364 ? __ Aver_sB(dst, lhs, rhs)
365 : __ Ave_sB(dst, lhs, rhs);
366 }
367 break;
368 case Primitive::kPrimChar:
369 case Primitive::kPrimShort:
370 DCHECK_EQ(8u, instruction->GetVectorLength());
371 if (instruction->IsUnsigned()) {
372 instruction->IsRounded()
373 ? __ Aver_uH(dst, lhs, rhs)
374 : __ Ave_uH(dst, lhs, rhs);
375 } else {
376 instruction->IsRounded()
377 ? __ Aver_sH(dst, lhs, rhs)
378 : __ Ave_sH(dst, lhs, rhs);
379 }
380 break;
381 default:
382 LOG(FATAL) << "Unsupported SIMD type";
383 UNREACHABLE();
384 }
Aart Bikf3e61ee2017-04-12 17:09:20 -0700385}
386
Aart Bikf8f5a162017-02-06 15:35:29 -0800387void LocationsBuilderMIPS64::VisitVecSub(HVecSub* instruction) {
388 CreateVecBinOpLocations(GetGraph()->GetArena(), instruction);
389}
390
391void InstructionCodeGeneratorMIPS64::VisitVecSub(HVecSub* instruction) {
Goran Jakovljevic19680d32017-05-11 10:38:36 +0200392 LocationSummary* locations = instruction->GetLocations();
393 VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
394 VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
395 VectorRegister dst = VectorRegisterFrom(locations->Out());
396 switch (instruction->GetPackedType()) {
397 case Primitive::kPrimByte:
398 DCHECK_EQ(16u, instruction->GetVectorLength());
399 __ SubvB(dst, lhs, rhs);
400 break;
401 case Primitive::kPrimChar:
402 case Primitive::kPrimShort:
403 DCHECK_EQ(8u, instruction->GetVectorLength());
404 __ SubvH(dst, lhs, rhs);
405 break;
406 case Primitive::kPrimInt:
407 DCHECK_EQ(4u, instruction->GetVectorLength());
408 __ SubvW(dst, lhs, rhs);
409 break;
410 case Primitive::kPrimLong:
411 DCHECK_EQ(2u, instruction->GetVectorLength());
412 __ SubvD(dst, lhs, rhs);
413 break;
414 case Primitive::kPrimFloat:
415 DCHECK_EQ(4u, instruction->GetVectorLength());
416 __ FsubW(dst, lhs, rhs);
417 break;
418 case Primitive::kPrimDouble:
419 DCHECK_EQ(2u, instruction->GetVectorLength());
420 __ FsubD(dst, lhs, rhs);
421 break;
422 default:
423 LOG(FATAL) << "Unsupported SIMD type";
424 UNREACHABLE();
425 }
Aart Bikf8f5a162017-02-06 15:35:29 -0800426}
427
428void LocationsBuilderMIPS64::VisitVecMul(HVecMul* instruction) {
429 CreateVecBinOpLocations(GetGraph()->GetArena(), instruction);
430}
431
432void InstructionCodeGeneratorMIPS64::VisitVecMul(HVecMul* instruction) {
Goran Jakovljevic19680d32017-05-11 10:38:36 +0200433 LocationSummary* locations = instruction->GetLocations();
434 VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
435 VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
436 VectorRegister dst = VectorRegisterFrom(locations->Out());
437 switch (instruction->GetPackedType()) {
438 case Primitive::kPrimByte:
439 DCHECK_EQ(16u, instruction->GetVectorLength());
440 __ MulvB(dst, lhs, rhs);
441 break;
442 case Primitive::kPrimChar:
443 case Primitive::kPrimShort:
444 DCHECK_EQ(8u, instruction->GetVectorLength());
445 __ MulvH(dst, lhs, rhs);
446 break;
447 case Primitive::kPrimInt:
448 DCHECK_EQ(4u, instruction->GetVectorLength());
449 __ MulvW(dst, lhs, rhs);
450 break;
451 case Primitive::kPrimLong:
452 DCHECK_EQ(2u, instruction->GetVectorLength());
453 __ MulvD(dst, lhs, rhs);
454 break;
455 case Primitive::kPrimFloat:
456 DCHECK_EQ(4u, instruction->GetVectorLength());
457 __ FmulW(dst, lhs, rhs);
458 break;
459 case Primitive::kPrimDouble:
460 DCHECK_EQ(2u, instruction->GetVectorLength());
461 __ FmulD(dst, lhs, rhs);
462 break;
463 default:
464 LOG(FATAL) << "Unsupported SIMD type";
465 UNREACHABLE();
466 }
Aart Bikf8f5a162017-02-06 15:35:29 -0800467}
468
469void LocationsBuilderMIPS64::VisitVecDiv(HVecDiv* instruction) {
470 CreateVecBinOpLocations(GetGraph()->GetArena(), instruction);
471}
472
473void InstructionCodeGeneratorMIPS64::VisitVecDiv(HVecDiv* instruction) {
Goran Jakovljevic19680d32017-05-11 10:38:36 +0200474 LocationSummary* locations = instruction->GetLocations();
475 VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
476 VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
477 VectorRegister dst = VectorRegisterFrom(locations->Out());
478 switch (instruction->GetPackedType()) {
479 case Primitive::kPrimFloat:
480 DCHECK_EQ(4u, instruction->GetVectorLength());
481 __ FdivW(dst, lhs, rhs);
482 break;
483 case Primitive::kPrimDouble:
484 DCHECK_EQ(2u, instruction->GetVectorLength());
485 __ FdivD(dst, lhs, rhs);
486 break;
487 default:
488 LOG(FATAL) << "Unsupported SIMD type";
489 UNREACHABLE();
490 }
Aart Bikf8f5a162017-02-06 15:35:29 -0800491}
492
Aart Bikf3e61ee2017-04-12 17:09:20 -0700493void LocationsBuilderMIPS64::VisitVecMin(HVecMin* instruction) {
494 CreateVecBinOpLocations(GetGraph()->GetArena(), instruction);
495}
496
497void InstructionCodeGeneratorMIPS64::VisitVecMin(HVecMin* instruction) {
Goran Jakovljevic8fea1e12017-06-06 13:28:42 +0200498 LocationSummary* locations = instruction->GetLocations();
499 VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
500 VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
501 VectorRegister dst = VectorRegisterFrom(locations->Out());
502 switch (instruction->GetPackedType()) {
503 case Primitive::kPrimByte:
504 DCHECK_EQ(16u, instruction->GetVectorLength());
505 if (instruction->IsUnsigned()) {
506 __ Min_uB(dst, lhs, rhs);
507 } else {
508 __ Min_sB(dst, lhs, rhs);
509 }
510 break;
511 case Primitive::kPrimChar:
512 case Primitive::kPrimShort:
513 DCHECK_EQ(8u, instruction->GetVectorLength());
514 if (instruction->IsUnsigned()) {
515 __ Min_uH(dst, lhs, rhs);
516 } else {
517 __ Min_sH(dst, lhs, rhs);
518 }
519 break;
520 case Primitive::kPrimInt:
521 DCHECK_EQ(4u, instruction->GetVectorLength());
522 if (instruction->IsUnsigned()) {
523 __ Min_uW(dst, lhs, rhs);
524 } else {
525 __ Min_sW(dst, lhs, rhs);
526 }
527 break;
528 case Primitive::kPrimLong:
529 DCHECK_EQ(2u, instruction->GetVectorLength());
530 if (instruction->IsUnsigned()) {
531 __ Min_uD(dst, lhs, rhs);
532 } else {
533 __ Min_sD(dst, lhs, rhs);
534 }
535 break;
536 // When one of arguments is NaN, fmin.df returns other argument, but Java expects a NaN value.
537 // TODO: Fix min(x, NaN) cases for float and double.
538 case Primitive::kPrimFloat:
539 DCHECK_EQ(4u, instruction->GetVectorLength());
540 DCHECK(!instruction->IsUnsigned());
541 __ FminW(dst, lhs, rhs);
542 break;
543 case Primitive::kPrimDouble:
544 DCHECK_EQ(2u, instruction->GetVectorLength());
545 DCHECK(!instruction->IsUnsigned());
546 __ FminD(dst, lhs, rhs);
547 break;
548 default:
549 LOG(FATAL) << "Unsupported SIMD type";
550 UNREACHABLE();
551 }
Aart Bikf3e61ee2017-04-12 17:09:20 -0700552}
553
554void LocationsBuilderMIPS64::VisitVecMax(HVecMax* instruction) {
555 CreateVecBinOpLocations(GetGraph()->GetArena(), instruction);
556}
557
558void InstructionCodeGeneratorMIPS64::VisitVecMax(HVecMax* instruction) {
Goran Jakovljevic8fea1e12017-06-06 13:28:42 +0200559 LocationSummary* locations = instruction->GetLocations();
560 VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
561 VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
562 VectorRegister dst = VectorRegisterFrom(locations->Out());
563 switch (instruction->GetPackedType()) {
564 case Primitive::kPrimByte:
565 DCHECK_EQ(16u, instruction->GetVectorLength());
566 if (instruction->IsUnsigned()) {
567 __ Max_uB(dst, lhs, rhs);
568 } else {
569 __ Max_sB(dst, lhs, rhs);
570 }
571 break;
572 case Primitive::kPrimChar:
573 case Primitive::kPrimShort:
574 DCHECK_EQ(8u, instruction->GetVectorLength());
575 if (instruction->IsUnsigned()) {
576 __ Max_uH(dst, lhs, rhs);
577 } else {
578 __ Max_sH(dst, lhs, rhs);
579 }
580 break;
581 case Primitive::kPrimInt:
582 DCHECK_EQ(4u, instruction->GetVectorLength());
583 if (instruction->IsUnsigned()) {
584 __ Max_uW(dst, lhs, rhs);
585 } else {
586 __ Max_sW(dst, lhs, rhs);
587 }
588 break;
589 case Primitive::kPrimLong:
590 DCHECK_EQ(2u, instruction->GetVectorLength());
591 if (instruction->IsUnsigned()) {
592 __ Max_uD(dst, lhs, rhs);
593 } else {
594 __ Max_sD(dst, lhs, rhs);
595 }
596 break;
597 // When one of arguments is NaN, fmax.df returns other argument, but Java expects a NaN value.
598 // TODO: Fix max(x, NaN) cases for float and double.
599 case Primitive::kPrimFloat:
600 DCHECK_EQ(4u, instruction->GetVectorLength());
601 DCHECK(!instruction->IsUnsigned());
602 __ FmaxW(dst, lhs, rhs);
603 break;
604 case Primitive::kPrimDouble:
605 DCHECK_EQ(2u, instruction->GetVectorLength());
606 DCHECK(!instruction->IsUnsigned());
607 __ FmaxD(dst, lhs, rhs);
608 break;
609 default:
610 LOG(FATAL) << "Unsupported SIMD type";
611 UNREACHABLE();
612 }
Aart Bikf3e61ee2017-04-12 17:09:20 -0700613}
614
Aart Bikf8f5a162017-02-06 15:35:29 -0800615void LocationsBuilderMIPS64::VisitVecAnd(HVecAnd* instruction) {
616 CreateVecBinOpLocations(GetGraph()->GetArena(), instruction);
617}
618
619void InstructionCodeGeneratorMIPS64::VisitVecAnd(HVecAnd* instruction) {
Goran Jakovljevic19680d32017-05-11 10:38:36 +0200620 LocationSummary* locations = instruction->GetLocations();
621 VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
622 VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
623 VectorRegister dst = VectorRegisterFrom(locations->Out());
624 switch (instruction->GetPackedType()) {
625 case Primitive::kPrimBoolean:
626 case Primitive::kPrimByte:
627 case Primitive::kPrimChar:
628 case Primitive::kPrimShort:
629 case Primitive::kPrimInt:
630 case Primitive::kPrimLong:
631 case Primitive::kPrimFloat:
632 case Primitive::kPrimDouble:
633 DCHECK_LE(2u, instruction->GetVectorLength());
634 DCHECK_LE(instruction->GetVectorLength(), 16u);
635 __ AndV(dst, lhs, rhs); // lanes do not matter
636 break;
637 default:
638 LOG(FATAL) << "Unsupported SIMD type";
639 UNREACHABLE();
640 }
Aart Bikf8f5a162017-02-06 15:35:29 -0800641}
642
643void LocationsBuilderMIPS64::VisitVecAndNot(HVecAndNot* instruction) {
644 CreateVecBinOpLocations(GetGraph()->GetArena(), instruction);
645}
646
647void InstructionCodeGeneratorMIPS64::VisitVecAndNot(HVecAndNot* instruction) {
648 LOG(FATAL) << "No SIMD for " << instruction->GetId();
649}
650
651void LocationsBuilderMIPS64::VisitVecOr(HVecOr* instruction) {
652 CreateVecBinOpLocations(GetGraph()->GetArena(), instruction);
653}
654
655void InstructionCodeGeneratorMIPS64::VisitVecOr(HVecOr* instruction) {
Goran Jakovljevic19680d32017-05-11 10:38:36 +0200656 LocationSummary* locations = instruction->GetLocations();
657 VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
658 VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
659 VectorRegister dst = VectorRegisterFrom(locations->Out());
660 switch (instruction->GetPackedType()) {
661 case Primitive::kPrimBoolean:
662 case Primitive::kPrimByte:
663 case Primitive::kPrimChar:
664 case Primitive::kPrimShort:
665 case Primitive::kPrimInt:
666 case Primitive::kPrimLong:
667 case Primitive::kPrimFloat:
668 case Primitive::kPrimDouble:
669 DCHECK_LE(2u, instruction->GetVectorLength());
670 DCHECK_LE(instruction->GetVectorLength(), 16u);
671 __ OrV(dst, lhs, rhs); // lanes do not matter
672 break;
673 default:
674 LOG(FATAL) << "Unsupported SIMD type";
675 UNREACHABLE();
676 }
Aart Bikf8f5a162017-02-06 15:35:29 -0800677}
678
679void LocationsBuilderMIPS64::VisitVecXor(HVecXor* instruction) {
680 CreateVecBinOpLocations(GetGraph()->GetArena(), instruction);
681}
682
683void InstructionCodeGeneratorMIPS64::VisitVecXor(HVecXor* instruction) {
Goran Jakovljevic19680d32017-05-11 10:38:36 +0200684 LocationSummary* locations = instruction->GetLocations();
685 VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
686 VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
687 VectorRegister dst = VectorRegisterFrom(locations->Out());
688 switch (instruction->GetPackedType()) {
689 case Primitive::kPrimBoolean:
690 case Primitive::kPrimByte:
691 case Primitive::kPrimChar:
692 case Primitive::kPrimShort:
693 case Primitive::kPrimInt:
694 case Primitive::kPrimLong:
695 case Primitive::kPrimFloat:
696 case Primitive::kPrimDouble:
697 DCHECK_LE(2u, instruction->GetVectorLength());
698 DCHECK_LE(instruction->GetVectorLength(), 16u);
699 __ XorV(dst, lhs, rhs); // lanes do not matter
700 break;
701 default:
702 LOG(FATAL) << "Unsupported SIMD type";
703 UNREACHABLE();
704 }
Aart Bikf8f5a162017-02-06 15:35:29 -0800705}
706
707// Helper to set up locations for vector shift operations.
708static void CreateVecShiftLocations(ArenaAllocator* arena, HVecBinaryOperation* instruction) {
709 LocationSummary* locations = new (arena) LocationSummary(instruction);
710 switch (instruction->GetPackedType()) {
711 case Primitive::kPrimByte:
712 case Primitive::kPrimChar:
713 case Primitive::kPrimShort:
714 case Primitive::kPrimInt:
715 case Primitive::kPrimLong:
Goran Jakovljevic19680d32017-05-11 10:38:36 +0200716 locations->SetInAt(0, Location::RequiresFpuRegister());
717 locations->SetInAt(1, Location::ConstantLocation(instruction->InputAt(1)->AsConstant()));
718 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Aart Bikf8f5a162017-02-06 15:35:29 -0800719 break;
720 default:
721 LOG(FATAL) << "Unsupported SIMD type";
722 UNREACHABLE();
723 }
724}
725
726void LocationsBuilderMIPS64::VisitVecShl(HVecShl* instruction) {
727 CreateVecShiftLocations(GetGraph()->GetArena(), instruction);
728}
729
730void InstructionCodeGeneratorMIPS64::VisitVecShl(HVecShl* instruction) {
Goran Jakovljevic19680d32017-05-11 10:38:36 +0200731 LocationSummary* locations = instruction->GetLocations();
732 VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
733 VectorRegister dst = VectorRegisterFrom(locations->Out());
734 int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
735 switch (instruction->GetPackedType()) {
736 case Primitive::kPrimByte:
737 DCHECK_EQ(16u, instruction->GetVectorLength());
738 __ SlliB(dst, lhs, value);
739 break;
740 case Primitive::kPrimChar:
741 case Primitive::kPrimShort:
742 DCHECK_EQ(8u, instruction->GetVectorLength());
743 __ SlliH(dst, lhs, value);
744 break;
745 case Primitive::kPrimInt:
746 DCHECK_EQ(4u, instruction->GetVectorLength());
747 __ SlliW(dst, lhs, value);
748 break;
749 case Primitive::kPrimLong:
750 DCHECK_EQ(2u, instruction->GetVectorLength());
751 __ SlliD(dst, lhs, value);
752 break;
753 default:
754 LOG(FATAL) << "Unsupported SIMD type";
755 UNREACHABLE();
756 }
Aart Bikf8f5a162017-02-06 15:35:29 -0800757}
758
759void LocationsBuilderMIPS64::VisitVecShr(HVecShr* instruction) {
760 CreateVecShiftLocations(GetGraph()->GetArena(), instruction);
761}
762
763void InstructionCodeGeneratorMIPS64::VisitVecShr(HVecShr* instruction) {
Goran Jakovljevic19680d32017-05-11 10:38:36 +0200764 LocationSummary* locations = instruction->GetLocations();
765 VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
766 VectorRegister dst = VectorRegisterFrom(locations->Out());
767 int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
768 switch (instruction->GetPackedType()) {
769 case Primitive::kPrimByte:
770 DCHECK_EQ(16u, instruction->GetVectorLength());
771 __ SraiB(dst, lhs, value);
772 break;
773 case Primitive::kPrimChar:
774 case Primitive::kPrimShort:
775 DCHECK_EQ(8u, instruction->GetVectorLength());
776 __ SraiH(dst, lhs, value);
777 break;
778 case Primitive::kPrimInt:
779 DCHECK_EQ(4u, instruction->GetVectorLength());
780 __ SraiW(dst, lhs, value);
781 break;
782 case Primitive::kPrimLong:
783 DCHECK_EQ(2u, instruction->GetVectorLength());
784 __ SraiD(dst, lhs, value);
785 break;
786 default:
787 LOG(FATAL) << "Unsupported SIMD type";
788 UNREACHABLE();
789 }
Aart Bikf8f5a162017-02-06 15:35:29 -0800790}
791
792void LocationsBuilderMIPS64::VisitVecUShr(HVecUShr* instruction) {
793 CreateVecShiftLocations(GetGraph()->GetArena(), instruction);
794}
795
796void InstructionCodeGeneratorMIPS64::VisitVecUShr(HVecUShr* instruction) {
Goran Jakovljevic19680d32017-05-11 10:38:36 +0200797 LocationSummary* locations = instruction->GetLocations();
798 VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
799 VectorRegister dst = VectorRegisterFrom(locations->Out());
800 int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
801 switch (instruction->GetPackedType()) {
802 case Primitive::kPrimByte:
803 DCHECK_EQ(16u, instruction->GetVectorLength());
804 __ SrliB(dst, lhs, value);
805 break;
806 case Primitive::kPrimChar:
807 case Primitive::kPrimShort:
808 DCHECK_EQ(8u, instruction->GetVectorLength());
809 __ SrliH(dst, lhs, value);
810 break;
811 case Primitive::kPrimInt:
812 DCHECK_EQ(4u, instruction->GetVectorLength());
813 __ SrliW(dst, lhs, value);
814 break;
815 case Primitive::kPrimLong:
816 DCHECK_EQ(2u, instruction->GetVectorLength());
817 __ SrliD(dst, lhs, value);
818 break;
819 default:
820 LOG(FATAL) << "Unsupported SIMD type";
821 UNREACHABLE();
822 }
Aart Bikf8f5a162017-02-06 15:35:29 -0800823}
824
Artem Serovf34dd202017-04-10 17:41:46 +0100825void LocationsBuilderMIPS64::VisitVecMultiplyAccumulate(HVecMultiplyAccumulate* instr) {
826 LOG(FATAL) << "No SIMD for " << instr->GetId();
827}
828
829void InstructionCodeGeneratorMIPS64::VisitVecMultiplyAccumulate(HVecMultiplyAccumulate* instr) {
830 LOG(FATAL) << "No SIMD for " << instr->GetId();
831}
832
Goran Jakovljevic19680d32017-05-11 10:38:36 +0200833// Helper to set up locations for vector memory operations.
834static void CreateVecMemLocations(ArenaAllocator* arena,
835 HVecMemoryOperation* instruction,
836 bool is_load) {
837 LocationSummary* locations = new (arena) LocationSummary(instruction);
838 switch (instruction->GetPackedType()) {
839 case Primitive::kPrimBoolean:
840 case Primitive::kPrimByte:
841 case Primitive::kPrimChar:
842 case Primitive::kPrimShort:
843 case Primitive::kPrimInt:
844 case Primitive::kPrimLong:
845 case Primitive::kPrimFloat:
846 case Primitive::kPrimDouble:
847 locations->SetInAt(0, Location::RequiresRegister());
848 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
849 if (is_load) {
850 locations->SetOut(Location::RequiresFpuRegister());
851 } else {
852 locations->SetInAt(2, Location::RequiresFpuRegister());
853 }
854 break;
855 default:
856 LOG(FATAL) << "Unsupported SIMD type";
857 UNREACHABLE();
858 }
859}
860
861// Helper to prepare register and offset for vector memory operations. Returns the offset and sets
862// the output parameter adjusted_base to the original base or to a reserved temporary register (AT).
863int32_t InstructionCodeGeneratorMIPS64::VecAddress(LocationSummary* locations,
864 size_t size,
865 /* out */ GpuRegister* adjusted_base) {
866 GpuRegister base = locations->InAt(0).AsRegister<GpuRegister>();
867 Location index = locations->InAt(1);
868 int scale = TIMES_1;
869 switch (size) {
870 case 2: scale = TIMES_2; break;
871 case 4: scale = TIMES_4; break;
872 case 8: scale = TIMES_8; break;
873 default: break;
874 }
875 int32_t offset = mirror::Array::DataOffset(size).Int32Value();
876
877 if (index.IsConstant()) {
878 offset += index.GetConstant()->AsIntConstant()->GetValue() << scale;
879 __ AdjustBaseOffsetAndElementSizeShift(base, offset, scale);
880 *adjusted_base = base;
881 } else {
882 GpuRegister index_reg = index.AsRegister<GpuRegister>();
883 if (scale != TIMES_1) {
884 __ Dlsa(AT, index_reg, base, scale);
885 } else {
886 __ Daddu(AT, base, index_reg);
887 }
888 *adjusted_base = AT;
889 }
890 return offset;
891}
892
Aart Bikf8f5a162017-02-06 15:35:29 -0800893void LocationsBuilderMIPS64::VisitVecLoad(HVecLoad* instruction) {
Goran Jakovljevic19680d32017-05-11 10:38:36 +0200894 CreateVecMemLocations(GetGraph()->GetArena(), instruction, /* is_load */ true);
Aart Bikf8f5a162017-02-06 15:35:29 -0800895}
896
897void InstructionCodeGeneratorMIPS64::VisitVecLoad(HVecLoad* instruction) {
Goran Jakovljevic19680d32017-05-11 10:38:36 +0200898 LocationSummary* locations = instruction->GetLocations();
899 size_t size = Primitive::ComponentSize(instruction->GetPackedType());
900 VectorRegister reg = VectorRegisterFrom(locations->Out());
901 GpuRegister base;
902 int32_t offset = VecAddress(locations, size, &base);
903 switch (instruction->GetPackedType()) {
904 case Primitive::kPrimBoolean:
905 case Primitive::kPrimByte:
906 DCHECK_EQ(16u, instruction->GetVectorLength());
907 __ LdB(reg, base, offset);
908 break;
909 case Primitive::kPrimChar:
910 case Primitive::kPrimShort:
911 // Loading 8-bytes (needed if dealing with compressed strings in StringCharAt) from unaligned
912 // memory address may cause a trap to the kernel if the CPU doesn't directly support unaligned
913 // loads and stores.
914 // TODO: Implement support for StringCharAt.
915 DCHECK(!instruction->IsStringCharAt());
916 DCHECK_EQ(8u, instruction->GetVectorLength());
917 __ LdH(reg, base, offset);
918 break;
919 case Primitive::kPrimInt:
920 case Primitive::kPrimFloat:
921 DCHECK_EQ(4u, instruction->GetVectorLength());
922 __ LdW(reg, base, offset);
923 break;
924 case Primitive::kPrimLong:
925 case Primitive::kPrimDouble:
926 DCHECK_EQ(2u, instruction->GetVectorLength());
927 __ LdD(reg, base, offset);
928 break;
929 default:
930 LOG(FATAL) << "Unsupported SIMD type";
931 UNREACHABLE();
932 }
Aart Bikf8f5a162017-02-06 15:35:29 -0800933}
934
935void LocationsBuilderMIPS64::VisitVecStore(HVecStore* instruction) {
Goran Jakovljevic19680d32017-05-11 10:38:36 +0200936 CreateVecMemLocations(GetGraph()->GetArena(), instruction, /* is_load */ false);
Aart Bikf8f5a162017-02-06 15:35:29 -0800937}
938
939void InstructionCodeGeneratorMIPS64::VisitVecStore(HVecStore* instruction) {
Goran Jakovljevic19680d32017-05-11 10:38:36 +0200940 LocationSummary* locations = instruction->GetLocations();
941 size_t size = Primitive::ComponentSize(instruction->GetPackedType());
942 VectorRegister reg = VectorRegisterFrom(locations->InAt(2));
943 GpuRegister base;
944 int32_t offset = VecAddress(locations, size, &base);
945 switch (instruction->GetPackedType()) {
946 case Primitive::kPrimBoolean:
947 case Primitive::kPrimByte:
948 DCHECK_EQ(16u, instruction->GetVectorLength());
949 __ StB(reg, base, offset);
950 break;
951 case Primitive::kPrimChar:
952 case Primitive::kPrimShort:
953 DCHECK_EQ(8u, instruction->GetVectorLength());
954 __ StH(reg, base, offset);
955 break;
956 case Primitive::kPrimInt:
957 case Primitive::kPrimFloat:
958 DCHECK_EQ(4u, instruction->GetVectorLength());
959 __ StW(reg, base, offset);
960 break;
961 case Primitive::kPrimLong:
962 case Primitive::kPrimDouble:
963 DCHECK_EQ(2u, instruction->GetVectorLength());
964 __ StD(reg, base, offset);
965 break;
966 default:
967 LOG(FATAL) << "Unsupported SIMD type";
968 UNREACHABLE();
969 }
Aart Bikf8f5a162017-02-06 15:35:29 -0800970}
971
972#undef __
973
974} // namespace mips64
975} // namespace art