1 /*
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_mips.h"
18 #include "mirror/array-inl.h"
19
20 namespace art {
21 namespace mips {
22
23 // NOLINT on __ macro to suppress wrong warning/fix (misc-macro-parentheses) from clang-tidy.
24 #define __ down_cast<MipsAssembler*>(GetAssembler())-> // NOLINT
25
VisitVecReplicateScalar(HVecReplicateScalar * instruction)26 void LocationsBuilderMIPS::VisitVecReplicateScalar(HVecReplicateScalar* instruction) {
27 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(instruction);
28 switch (instruction->GetPackedType()) {
29 case DataType::Type::kBool:
30 case DataType::Type::kUint8:
31 case DataType::Type::kInt8:
32 case DataType::Type::kUint16:
33 case DataType::Type::kInt16:
34 case DataType::Type::kInt32:
35 case DataType::Type::kInt64:
36 locations->SetInAt(0, Location::RequiresRegister());
37 locations->SetOut(Location::RequiresFpuRegister());
38 break;
39 case DataType::Type::kFloat32:
40 case DataType::Type::kFloat64:
41 locations->SetInAt(0, Location::RequiresFpuRegister());
42 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
43 break;
44 default:
45 LOG(FATAL) << "Unsupported SIMD type";
46 UNREACHABLE();
47 }
48 }
49
VisitVecReplicateScalar(HVecReplicateScalar * instruction)50 void InstructionCodeGeneratorMIPS::VisitVecReplicateScalar(HVecReplicateScalar* instruction) {
51 LocationSummary* locations = instruction->GetLocations();
52 VectorRegister dst = VectorRegisterFrom(locations->Out());
53 switch (instruction->GetPackedType()) {
54 case DataType::Type::kBool:
55 case DataType::Type::kUint8:
56 case DataType::Type::kInt8:
57 DCHECK_EQ(16u, instruction->GetVectorLength());
58 __ FillB(dst, locations->InAt(0).AsRegister<Register>());
59 break;
60 case DataType::Type::kUint16:
61 case DataType::Type::kInt16:
62 DCHECK_EQ(8u, instruction->GetVectorLength());
63 __ FillH(dst, locations->InAt(0).AsRegister<Register>());
64 break;
65 case DataType::Type::kInt32:
66 DCHECK_EQ(4u, instruction->GetVectorLength());
67 __ FillW(dst, locations->InAt(0).AsRegister<Register>());
68 break;
69 case DataType::Type::kInt64:
70 DCHECK_EQ(2u, instruction->GetVectorLength());
71 __ InsertW(static_cast<VectorRegister>(FTMP),
72 locations->InAt(0).AsRegisterPairLow<Register>(),
73 0);
74 __ InsertW(static_cast<VectorRegister>(FTMP),
75 locations->InAt(0).AsRegisterPairHigh<Register>(),
76 1);
77 __ ReplicateFPToVectorRegister(dst, FTMP, /* is_double */ true);
78 break;
79 case DataType::Type::kFloat32:
80 DCHECK_EQ(4u, instruction->GetVectorLength());
81 __ ReplicateFPToVectorRegister(dst,
82 locations->InAt(0).AsFpuRegister<FRegister>(),
83 /* is_double */ false);
84 break;
85 case DataType::Type::kFloat64:
86 DCHECK_EQ(2u, instruction->GetVectorLength());
87 __ ReplicateFPToVectorRegister(dst,
88 locations->InAt(0).AsFpuRegister<FRegister>(),
89 /* is_double */ true);
90 break;
91 default:
92 LOG(FATAL) << "Unsupported SIMD type";
93 UNREACHABLE();
94 }
95 }
96
VisitVecExtractScalar(HVecExtractScalar * instruction)97 void LocationsBuilderMIPS::VisitVecExtractScalar(HVecExtractScalar* instruction) {
98 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(instruction);
99 switch (instruction->GetPackedType()) {
100 case DataType::Type::kBool:
101 case DataType::Type::kUint8:
102 case DataType::Type::kInt8:
103 case DataType::Type::kUint16:
104 case DataType::Type::kInt16:
105 case DataType::Type::kInt32:
106 case DataType::Type::kInt64:
107 locations->SetInAt(0, Location::RequiresFpuRegister());
108 locations->SetOut(Location::RequiresRegister());
109 break;
110 case DataType::Type::kFloat32:
111 case DataType::Type::kFloat64:
112 locations->SetInAt(0, Location::RequiresFpuRegister());
113 locations->SetOut(Location::SameAsFirstInput());
114 break;
115 default:
116 LOG(FATAL) << "Unsupported SIMD type";
117 UNREACHABLE();
118 }
119 }
120
VisitVecExtractScalar(HVecExtractScalar * instruction)121 void InstructionCodeGeneratorMIPS::VisitVecExtractScalar(HVecExtractScalar* instruction) {
122 LocationSummary* locations = instruction->GetLocations();
123 VectorRegister src = VectorRegisterFrom(locations->InAt(0));
124 switch (instruction->GetPackedType()) {
125 case DataType::Type::kInt32:
126 DCHECK_EQ(4u, instruction->GetVectorLength());
127 __ Copy_sW(locations->Out().AsRegister<Register>(), src, 0);
128 break;
129 case DataType::Type::kInt64:
130 DCHECK_EQ(2u, instruction->GetVectorLength());
131 __ Copy_sW(locations->Out().AsRegisterPairLow<Register>(), src, 0);
132 __ Copy_sW(locations->Out().AsRegisterPairHigh<Register>(), src, 1);
133 break;
134 case DataType::Type::kFloat32:
135 case DataType::Type::kFloat64:
136 DCHECK_LE(2u, instruction->GetVectorLength());
137 DCHECK_LE(instruction->GetVectorLength(), 4u);
138 DCHECK(locations->InAt(0).Equals(locations->Out())); // no code required
139 break;
140 default:
141 LOG(FATAL) << "Unsupported SIMD type";
142 UNREACHABLE();
143 }
144 }
145
146 // Helper to set up locations for vector unary operations.
CreateVecUnOpLocations(ArenaAllocator * allocator,HVecUnaryOperation * instruction)147 static void CreateVecUnOpLocations(ArenaAllocator* allocator, HVecUnaryOperation* instruction) {
148 LocationSummary* locations = new (allocator) LocationSummary(instruction);
149 DataType::Type type = instruction->GetPackedType();
150 switch (type) {
151 case DataType::Type::kBool:
152 locations->SetInAt(0, Location::RequiresFpuRegister());
153 locations->SetOut(Location::RequiresFpuRegister(),
154 instruction->IsVecNot() ? Location::kOutputOverlap
155 : Location::kNoOutputOverlap);
156 break;
157 case DataType::Type::kUint8:
158 case DataType::Type::kInt8:
159 case DataType::Type::kUint16:
160 case DataType::Type::kInt16:
161 case DataType::Type::kInt32:
162 case DataType::Type::kInt64:
163 case DataType::Type::kFloat32:
164 case DataType::Type::kFloat64:
165 locations->SetInAt(0, Location::RequiresFpuRegister());
166 locations->SetOut(Location::RequiresFpuRegister(),
167 (instruction->IsVecNeg() || instruction->IsVecAbs() ||
168 (instruction->IsVecReduce() && type == DataType::Type::kInt64))
169 ? Location::kOutputOverlap
170 : Location::kNoOutputOverlap);
171 break;
172 default:
173 LOG(FATAL) << "Unsupported SIMD type";
174 UNREACHABLE();
175 }
176 }
177
VisitVecReduce(HVecReduce * instruction)178 void LocationsBuilderMIPS::VisitVecReduce(HVecReduce* instruction) {
179 CreateVecUnOpLocations(GetGraph()->GetAllocator(), instruction);
180 }
181
VisitVecReduce(HVecReduce * instruction)182 void InstructionCodeGeneratorMIPS::VisitVecReduce(HVecReduce* instruction) {
183 LocationSummary* locations = instruction->GetLocations();
184 VectorRegister src = VectorRegisterFrom(locations->InAt(0));
185 VectorRegister dst = VectorRegisterFrom(locations->Out());
186 VectorRegister tmp = static_cast<VectorRegister>(FTMP);
187 switch (instruction->GetPackedType()) {
188 case DataType::Type::kInt32:
189 DCHECK_EQ(4u, instruction->GetVectorLength());
190 switch (instruction->GetKind()) {
191 case HVecReduce::kSum:
192 __ Hadd_sD(tmp, src, src);
193 __ IlvlD(dst, tmp, tmp);
194 __ AddvW(dst, dst, tmp);
195 break;
196 case HVecReduce::kMin:
197 __ IlvodW(tmp, src, src);
198 __ Min_sW(tmp, src, tmp);
199 __ IlvlW(dst, tmp, tmp);
200 __ Min_sW(dst, dst, tmp);
201 break;
202 case HVecReduce::kMax:
203 __ IlvodW(tmp, src, src);
204 __ Max_sW(tmp, src, tmp);
205 __ IlvlW(dst, tmp, tmp);
206 __ Max_sW(dst, dst, tmp);
207 break;
208 }
209 break;
210 case DataType::Type::kInt64:
211 DCHECK_EQ(2u, instruction->GetVectorLength());
212 switch (instruction->GetKind()) {
213 case HVecReduce::kSum:
214 __ IlvlD(dst, src, src);
215 __ AddvD(dst, dst, src);
216 break;
217 case HVecReduce::kMin:
218 __ IlvlD(dst, src, src);
219 __ Min_sD(dst, dst, src);
220 break;
221 case HVecReduce::kMax:
222 __ IlvlD(dst, src, src);
223 __ Max_sD(dst, dst, src);
224 break;
225 }
226 break;
227 default:
228 LOG(FATAL) << "Unsupported SIMD type";
229 UNREACHABLE();
230 }
231 }
232
VisitVecCnv(HVecCnv * instruction)233 void LocationsBuilderMIPS::VisitVecCnv(HVecCnv* instruction) {
234 CreateVecUnOpLocations(GetGraph()->GetAllocator(), instruction);
235 }
236
VisitVecCnv(HVecCnv * instruction)237 void InstructionCodeGeneratorMIPS::VisitVecCnv(HVecCnv* instruction) {
238 LocationSummary* locations = instruction->GetLocations();
239 VectorRegister src = VectorRegisterFrom(locations->InAt(0));
240 VectorRegister dst = VectorRegisterFrom(locations->Out());
241 DataType::Type from = instruction->GetInputType();
242 DataType::Type to = instruction->GetResultType();
243 if (from == DataType::Type::kInt32 && to == DataType::Type::kFloat32) {
244 DCHECK_EQ(4u, instruction->GetVectorLength());
245 __ Ffint_sW(dst, src);
246 } else {
247 LOG(FATAL) << "Unsupported SIMD type";
248 }
249 }
250
VisitVecNeg(HVecNeg * instruction)251 void LocationsBuilderMIPS::VisitVecNeg(HVecNeg* instruction) {
252 CreateVecUnOpLocations(GetGraph()->GetAllocator(), instruction);
253 }
254
VisitVecNeg(HVecNeg * instruction)255 void InstructionCodeGeneratorMIPS::VisitVecNeg(HVecNeg* instruction) {
256 LocationSummary* locations = instruction->GetLocations();
257 VectorRegister src = VectorRegisterFrom(locations->InAt(0));
258 VectorRegister dst = VectorRegisterFrom(locations->Out());
259 switch (instruction->GetPackedType()) {
260 case DataType::Type::kUint8:
261 case DataType::Type::kInt8:
262 DCHECK_EQ(16u, instruction->GetVectorLength());
263 __ FillB(dst, ZERO);
264 __ SubvB(dst, dst, src);
265 break;
266 case DataType::Type::kUint16:
267 case DataType::Type::kInt16:
268 DCHECK_EQ(8u, instruction->GetVectorLength());
269 __ FillH(dst, ZERO);
270 __ SubvH(dst, dst, src);
271 break;
272 case DataType::Type::kInt32:
273 DCHECK_EQ(4u, instruction->GetVectorLength());
274 __ FillW(dst, ZERO);
275 __ SubvW(dst, dst, src);
276 break;
277 case DataType::Type::kInt64:
278 DCHECK_EQ(2u, instruction->GetVectorLength());
279 __ FillW(dst, ZERO);
280 __ SubvD(dst, dst, src);
281 break;
282 case DataType::Type::kFloat32:
283 DCHECK_EQ(4u, instruction->GetVectorLength());
284 __ FillW(dst, ZERO);
285 __ FsubW(dst, dst, src);
286 break;
287 case DataType::Type::kFloat64:
288 DCHECK_EQ(2u, instruction->GetVectorLength());
289 __ FillW(dst, ZERO);
290 __ FsubD(dst, dst, src);
291 break;
292 default:
293 LOG(FATAL) << "Unsupported SIMD type";
294 UNREACHABLE();
295 }
296 }
297
VisitVecAbs(HVecAbs * instruction)298 void LocationsBuilderMIPS::VisitVecAbs(HVecAbs* instruction) {
299 CreateVecUnOpLocations(GetGraph()->GetAllocator(), instruction);
300 }
301
VisitVecAbs(HVecAbs * instruction)302 void InstructionCodeGeneratorMIPS::VisitVecAbs(HVecAbs* instruction) {
303 LocationSummary* locations = instruction->GetLocations();
304 VectorRegister src = VectorRegisterFrom(locations->InAt(0));
305 VectorRegister dst = VectorRegisterFrom(locations->Out());
306 switch (instruction->GetPackedType()) {
307 case DataType::Type::kInt8:
308 DCHECK_EQ(16u, instruction->GetVectorLength());
309 __ FillB(dst, ZERO); // all zeroes
310 __ Add_aB(dst, dst, src); // dst = abs(0) + abs(src)
311 break;
312 case DataType::Type::kInt16:
313 DCHECK_EQ(8u, instruction->GetVectorLength());
314 __ FillH(dst, ZERO); // all zeroes
315 __ Add_aH(dst, dst, src); // dst = abs(0) + abs(src)
316 break;
317 case DataType::Type::kInt32:
318 DCHECK_EQ(4u, instruction->GetVectorLength());
319 __ FillW(dst, ZERO); // all zeroes
320 __ Add_aW(dst, dst, src); // dst = abs(0) + abs(src)
321 break;
322 case DataType::Type::kInt64:
323 DCHECK_EQ(2u, instruction->GetVectorLength());
324 __ FillW(dst, ZERO); // all zeroes
325 __ Add_aD(dst, dst, src); // dst = abs(0) + abs(src)
326 break;
327 case DataType::Type::kFloat32:
328 DCHECK_EQ(4u, instruction->GetVectorLength());
329 __ LdiW(dst, -1); // all ones
330 __ SrliW(dst, dst, 1);
331 __ AndV(dst, dst, src);
332 break;
333 case DataType::Type::kFloat64:
334 DCHECK_EQ(2u, instruction->GetVectorLength());
335 __ LdiD(dst, -1); // all ones
336 __ SrliD(dst, dst, 1);
337 __ AndV(dst, dst, src);
338 break;
339 default:
340 LOG(FATAL) << "Unsupported SIMD type";
341 UNREACHABLE();
342 }
343 }
344
VisitVecNot(HVecNot * instruction)345 void LocationsBuilderMIPS::VisitVecNot(HVecNot* instruction) {
346 CreateVecUnOpLocations(GetGraph()->GetAllocator(), instruction);
347 }
348
VisitVecNot(HVecNot * instruction)349 void InstructionCodeGeneratorMIPS::VisitVecNot(HVecNot* instruction) {
350 LocationSummary* locations = instruction->GetLocations();
351 VectorRegister src = VectorRegisterFrom(locations->InAt(0));
352 VectorRegister dst = VectorRegisterFrom(locations->Out());
353 switch (instruction->GetPackedType()) {
354 case DataType::Type::kBool: // special case boolean-not
355 DCHECK_EQ(16u, instruction->GetVectorLength());
356 __ LdiB(dst, 1);
357 __ XorV(dst, dst, src);
358 break;
359 case DataType::Type::kUint8:
360 case DataType::Type::kInt8:
361 case DataType::Type::kUint16:
362 case DataType::Type::kInt16:
363 case DataType::Type::kInt32:
364 case DataType::Type::kInt64:
365 case DataType::Type::kFloat32:
366 case DataType::Type::kFloat64:
367 DCHECK_LE(2u, instruction->GetVectorLength());
368 DCHECK_LE(instruction->GetVectorLength(), 16u);
369 __ NorV(dst, src, src); // lanes do not matter
370 break;
371 default:
372 LOG(FATAL) << "Unsupported SIMD type";
373 UNREACHABLE();
374 }
375 }
376
377 // Helper to set up locations for vector binary operations.
CreateVecBinOpLocations(ArenaAllocator * allocator,HVecBinaryOperation * instruction)378 static void CreateVecBinOpLocations(ArenaAllocator* allocator, HVecBinaryOperation* instruction) {
379 LocationSummary* locations = new (allocator) LocationSummary(instruction);
380 switch (instruction->GetPackedType()) {
381 case DataType::Type::kBool:
382 case DataType::Type::kUint8:
383 case DataType::Type::kInt8:
384 case DataType::Type::kUint16:
385 case DataType::Type::kInt16:
386 case DataType::Type::kInt32:
387 case DataType::Type::kInt64:
388 case DataType::Type::kFloat32:
389 case DataType::Type::kFloat64:
390 locations->SetInAt(0, Location::RequiresFpuRegister());
391 locations->SetInAt(1, Location::RequiresFpuRegister());
392 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
393 break;
394 default:
395 LOG(FATAL) << "Unsupported SIMD type";
396 UNREACHABLE();
397 }
398 }
399
VisitVecAdd(HVecAdd * instruction)400 void LocationsBuilderMIPS::VisitVecAdd(HVecAdd* instruction) {
401 CreateVecBinOpLocations(GetGraph()->GetAllocator(), instruction);
402 }
403
VisitVecAdd(HVecAdd * instruction)404 void InstructionCodeGeneratorMIPS::VisitVecAdd(HVecAdd* instruction) {
405 LocationSummary* locations = instruction->GetLocations();
406 VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
407 VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
408 VectorRegister dst = VectorRegisterFrom(locations->Out());
409 switch (instruction->GetPackedType()) {
410 case DataType::Type::kUint8:
411 case DataType::Type::kInt8:
412 DCHECK_EQ(16u, instruction->GetVectorLength());
413 __ AddvB(dst, lhs, rhs);
414 break;
415 case DataType::Type::kUint16:
416 case DataType::Type::kInt16:
417 DCHECK_EQ(8u, instruction->GetVectorLength());
418 __ AddvH(dst, lhs, rhs);
419 break;
420 case DataType::Type::kInt32:
421 DCHECK_EQ(4u, instruction->GetVectorLength());
422 __ AddvW(dst, lhs, rhs);
423 break;
424 case DataType::Type::kInt64:
425 DCHECK_EQ(2u, instruction->GetVectorLength());
426 __ AddvD(dst, lhs, rhs);
427 break;
428 case DataType::Type::kFloat32:
429 DCHECK_EQ(4u, instruction->GetVectorLength());
430 __ FaddW(dst, lhs, rhs);
431 break;
432 case DataType::Type::kFloat64:
433 DCHECK_EQ(2u, instruction->GetVectorLength());
434 __ FaddD(dst, lhs, rhs);
435 break;
436 default:
437 LOG(FATAL) << "Unsupported SIMD type";
438 UNREACHABLE();
439 }
440 }
441
VisitVecHalvingAdd(HVecHalvingAdd * instruction)442 void LocationsBuilderMIPS::VisitVecHalvingAdd(HVecHalvingAdd* instruction) {
443 CreateVecBinOpLocations(GetGraph()->GetAllocator(), instruction);
444 }
445
VisitVecHalvingAdd(HVecHalvingAdd * instruction)446 void InstructionCodeGeneratorMIPS::VisitVecHalvingAdd(HVecHalvingAdd* instruction) {
447 LocationSummary* locations = instruction->GetLocations();
448 VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
449 VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
450 VectorRegister dst = VectorRegisterFrom(locations->Out());
451 switch (instruction->GetPackedType()) {
452 case DataType::Type::kUint8:
453 DCHECK_EQ(16u, instruction->GetVectorLength());
454 instruction->IsRounded()
455 ? __ Aver_uB(dst, lhs, rhs)
456 : __ Ave_uB(dst, lhs, rhs);
457 break;
458 case DataType::Type::kInt8:
459 DCHECK_EQ(16u, instruction->GetVectorLength());
460 instruction->IsRounded()
461 ? __ Aver_sB(dst, lhs, rhs)
462 : __ Ave_sB(dst, lhs, rhs);
463 break;
464 case DataType::Type::kUint16:
465 DCHECK_EQ(8u, instruction->GetVectorLength());
466 instruction->IsRounded()
467 ? __ Aver_uH(dst, lhs, rhs)
468 : __ Ave_uH(dst, lhs, rhs);
469 break;
470 case DataType::Type::kInt16:
471 DCHECK_EQ(8u, instruction->GetVectorLength());
472 instruction->IsRounded()
473 ? __ Aver_sH(dst, lhs, rhs)
474 : __ Ave_sH(dst, lhs, rhs);
475 break;
476 default:
477 LOG(FATAL) << "Unsupported SIMD type";
478 UNREACHABLE();
479 }
480 }
481
VisitVecSub(HVecSub * instruction)482 void LocationsBuilderMIPS::VisitVecSub(HVecSub* instruction) {
483 CreateVecBinOpLocations(GetGraph()->GetAllocator(), instruction);
484 }
485
VisitVecSub(HVecSub * instruction)486 void InstructionCodeGeneratorMIPS::VisitVecSub(HVecSub* instruction) {
487 LocationSummary* locations = instruction->GetLocations();
488 VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
489 VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
490 VectorRegister dst = VectorRegisterFrom(locations->Out());
491 switch (instruction->GetPackedType()) {
492 case DataType::Type::kUint8:
493 case DataType::Type::kInt8:
494 DCHECK_EQ(16u, instruction->GetVectorLength());
495 __ SubvB(dst, lhs, rhs);
496 break;
497 case DataType::Type::kUint16:
498 case DataType::Type::kInt16:
499 DCHECK_EQ(8u, instruction->GetVectorLength());
500 __ SubvH(dst, lhs, rhs);
501 break;
502 case DataType::Type::kInt32:
503 DCHECK_EQ(4u, instruction->GetVectorLength());
504 __ SubvW(dst, lhs, rhs);
505 break;
506 case DataType::Type::kInt64:
507 DCHECK_EQ(2u, instruction->GetVectorLength());
508 __ SubvD(dst, lhs, rhs);
509 break;
510 case DataType::Type::kFloat32:
511 DCHECK_EQ(4u, instruction->GetVectorLength());
512 __ FsubW(dst, lhs, rhs);
513 break;
514 case DataType::Type::kFloat64:
515 DCHECK_EQ(2u, instruction->GetVectorLength());
516 __ FsubD(dst, lhs, rhs);
517 break;
518 default:
519 LOG(FATAL) << "Unsupported SIMD type";
520 UNREACHABLE();
521 }
522 }
523
VisitVecMul(HVecMul * instruction)524 void LocationsBuilderMIPS::VisitVecMul(HVecMul* instruction) {
525 CreateVecBinOpLocations(GetGraph()->GetAllocator(), instruction);
526 }
527
VisitVecMul(HVecMul * instruction)528 void InstructionCodeGeneratorMIPS::VisitVecMul(HVecMul* instruction) {
529 LocationSummary* locations = instruction->GetLocations();
530 VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
531 VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
532 VectorRegister dst = VectorRegisterFrom(locations->Out());
533 switch (instruction->GetPackedType()) {
534 case DataType::Type::kUint8:
535 case DataType::Type::kInt8:
536 DCHECK_EQ(16u, instruction->GetVectorLength());
537 __ MulvB(dst, lhs, rhs);
538 break;
539 case DataType::Type::kUint16:
540 case DataType::Type::kInt16:
541 DCHECK_EQ(8u, instruction->GetVectorLength());
542 __ MulvH(dst, lhs, rhs);
543 break;
544 case DataType::Type::kInt32:
545 DCHECK_EQ(4u, instruction->GetVectorLength());
546 __ MulvW(dst, lhs, rhs);
547 break;
548 case DataType::Type::kInt64:
549 DCHECK_EQ(2u, instruction->GetVectorLength());
550 __ MulvD(dst, lhs, rhs);
551 break;
552 case DataType::Type::kFloat32:
553 DCHECK_EQ(4u, instruction->GetVectorLength());
554 __ FmulW(dst, lhs, rhs);
555 break;
556 case DataType::Type::kFloat64:
557 DCHECK_EQ(2u, instruction->GetVectorLength());
558 __ FmulD(dst, lhs, rhs);
559 break;
560 default:
561 LOG(FATAL) << "Unsupported SIMD type";
562 UNREACHABLE();
563 }
564 }
565
VisitVecDiv(HVecDiv * instruction)566 void LocationsBuilderMIPS::VisitVecDiv(HVecDiv* instruction) {
567 CreateVecBinOpLocations(GetGraph()->GetAllocator(), instruction);
568 }
569
VisitVecDiv(HVecDiv * instruction)570 void InstructionCodeGeneratorMIPS::VisitVecDiv(HVecDiv* instruction) {
571 LocationSummary* locations = instruction->GetLocations();
572 VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
573 VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
574 VectorRegister dst = VectorRegisterFrom(locations->Out());
575 switch (instruction->GetPackedType()) {
576 case DataType::Type::kFloat32:
577 DCHECK_EQ(4u, instruction->GetVectorLength());
578 __ FdivW(dst, lhs, rhs);
579 break;
580 case DataType::Type::kFloat64:
581 DCHECK_EQ(2u, instruction->GetVectorLength());
582 __ FdivD(dst, lhs, rhs);
583 break;
584 default:
585 LOG(FATAL) << "Unsupported SIMD type";
586 UNREACHABLE();
587 }
588 }
589
VisitVecMin(HVecMin * instruction)590 void LocationsBuilderMIPS::VisitVecMin(HVecMin* instruction) {
591 CreateVecBinOpLocations(GetGraph()->GetAllocator(), instruction);
592 }
593
VisitVecMin(HVecMin * instruction)594 void InstructionCodeGeneratorMIPS::VisitVecMin(HVecMin* instruction) {
595 LocationSummary* locations = instruction->GetLocations();
596 VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
597 VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
598 VectorRegister dst = VectorRegisterFrom(locations->Out());
599 switch (instruction->GetPackedType()) {
600 case DataType::Type::kUint8:
601 DCHECK_EQ(16u, instruction->GetVectorLength());
602 __ Min_uB(dst, lhs, rhs);
603 break;
604 case DataType::Type::kInt8:
605 DCHECK_EQ(16u, instruction->GetVectorLength());
606 __ Min_sB(dst, lhs, rhs);
607 break;
608 case DataType::Type::kUint16:
609 DCHECK_EQ(8u, instruction->GetVectorLength());
610 __ Min_uH(dst, lhs, rhs);
611 break;
612 case DataType::Type::kInt16:
613 DCHECK_EQ(8u, instruction->GetVectorLength());
614 __ Min_sH(dst, lhs, rhs);
615 break;
616 case DataType::Type::kUint32:
617 DCHECK_EQ(4u, instruction->GetVectorLength());
618 __ Min_uW(dst, lhs, rhs);
619 break;
620 case DataType::Type::kInt32:
621 DCHECK_EQ(4u, instruction->GetVectorLength());
622 __ Min_sW(dst, lhs, rhs);
623 break;
624 case DataType::Type::kUint64:
625 DCHECK_EQ(2u, instruction->GetVectorLength());
626 __ Min_uD(dst, lhs, rhs);
627 break;
628 case DataType::Type::kInt64:
629 DCHECK_EQ(2u, instruction->GetVectorLength());
630 __ Min_sD(dst, lhs, rhs);
631 break;
632 // When one of arguments is NaN, fmin.df returns other argument, but Java expects a NaN value.
633 // TODO: Fix min(x, NaN) cases for float and double.
634 case DataType::Type::kFloat32:
635 DCHECK_EQ(4u, instruction->GetVectorLength());
636 __ FminW(dst, lhs, rhs);
637 break;
638 case DataType::Type::kFloat64:
639 DCHECK_EQ(2u, instruction->GetVectorLength());
640 __ FminD(dst, lhs, rhs);
641 break;
642 default:
643 LOG(FATAL) << "Unsupported SIMD type";
644 UNREACHABLE();
645 }
646 }
647
VisitVecMax(HVecMax * instruction)648 void LocationsBuilderMIPS::VisitVecMax(HVecMax* instruction) {
649 CreateVecBinOpLocations(GetGraph()->GetAllocator(), instruction);
650 }
651
VisitVecMax(HVecMax * instruction)652 void InstructionCodeGeneratorMIPS::VisitVecMax(HVecMax* instruction) {
653 LocationSummary* locations = instruction->GetLocations();
654 VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
655 VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
656 VectorRegister dst = VectorRegisterFrom(locations->Out());
657 switch (instruction->GetPackedType()) {
658 case DataType::Type::kUint8:
659 DCHECK_EQ(16u, instruction->GetVectorLength());
660 __ Max_uB(dst, lhs, rhs);
661 break;
662 case DataType::Type::kInt8:
663 DCHECK_EQ(16u, instruction->GetVectorLength());
664 __ Max_sB(dst, lhs, rhs);
665 break;
666 case DataType::Type::kUint16:
667 DCHECK_EQ(8u, instruction->GetVectorLength());
668 __ Max_uH(dst, lhs, rhs);
669 break;
670 case DataType::Type::kInt16:
671 DCHECK_EQ(8u, instruction->GetVectorLength());
672 __ Max_sH(dst, lhs, rhs);
673 break;
674 case DataType::Type::kUint32:
675 DCHECK_EQ(4u, instruction->GetVectorLength());
676 __ Max_uW(dst, lhs, rhs);
677 break;
678 case DataType::Type::kInt32:
679 DCHECK_EQ(4u, instruction->GetVectorLength());
680 __ Max_sW(dst, lhs, rhs);
681 break;
682 case DataType::Type::kUint64:
683 DCHECK_EQ(2u, instruction->GetVectorLength());
684 __ Max_uD(dst, lhs, rhs);
685 break;
686 case DataType::Type::kInt64:
687 DCHECK_EQ(2u, instruction->GetVectorLength());
688 __ Max_sD(dst, lhs, rhs);
689 break;
690 // When one of arguments is NaN, fmax.df returns other argument, but Java expects a NaN value.
691 // TODO: Fix max(x, NaN) cases for float and double.
692 case DataType::Type::kFloat32:
693 DCHECK_EQ(4u, instruction->GetVectorLength());
694 __ FmaxW(dst, lhs, rhs);
695 break;
696 case DataType::Type::kFloat64:
697 DCHECK_EQ(2u, instruction->GetVectorLength());
698 __ FmaxD(dst, lhs, rhs);
699 break;
700 default:
701 LOG(FATAL) << "Unsupported SIMD type";
702 UNREACHABLE();
703 }
704 }
705
VisitVecAnd(HVecAnd * instruction)706 void LocationsBuilderMIPS::VisitVecAnd(HVecAnd* instruction) {
707 CreateVecBinOpLocations(GetGraph()->GetAllocator(), instruction);
708 }
709
VisitVecAnd(HVecAnd * instruction)710 void InstructionCodeGeneratorMIPS::VisitVecAnd(HVecAnd* instruction) {
711 LocationSummary* locations = instruction->GetLocations();
712 VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
713 VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
714 VectorRegister dst = VectorRegisterFrom(locations->Out());
715 switch (instruction->GetPackedType()) {
716 case DataType::Type::kBool:
717 case DataType::Type::kUint8:
718 case DataType::Type::kInt8:
719 case DataType::Type::kUint16:
720 case DataType::Type::kInt16:
721 case DataType::Type::kInt32:
722 case DataType::Type::kInt64:
723 case DataType::Type::kFloat32:
724 case DataType::Type::kFloat64:
725 DCHECK_LE(2u, instruction->GetVectorLength());
726 DCHECK_LE(instruction->GetVectorLength(), 16u);
727 __ AndV(dst, lhs, rhs); // lanes do not matter
728 break;
729 default:
730 LOG(FATAL) << "Unsupported SIMD type";
731 UNREACHABLE();
732 }
733 }
734
VisitVecAndNot(HVecAndNot * instruction)735 void LocationsBuilderMIPS::VisitVecAndNot(HVecAndNot* instruction) {
736 CreateVecBinOpLocations(GetGraph()->GetAllocator(), instruction);
737 }
738
VisitVecAndNot(HVecAndNot * instruction)739 void InstructionCodeGeneratorMIPS::VisitVecAndNot(HVecAndNot* instruction) {
740 LOG(FATAL) << "No SIMD for " << instruction->GetId();
741 }
742
VisitVecOr(HVecOr * instruction)743 void LocationsBuilderMIPS::VisitVecOr(HVecOr* instruction) {
744 CreateVecBinOpLocations(GetGraph()->GetAllocator(), instruction);
745 }
746
VisitVecOr(HVecOr * instruction)747 void InstructionCodeGeneratorMIPS::VisitVecOr(HVecOr* instruction) {
748 LocationSummary* locations = instruction->GetLocations();
749 VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
750 VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
751 VectorRegister dst = VectorRegisterFrom(locations->Out());
752 switch (instruction->GetPackedType()) {
753 case DataType::Type::kBool:
754 case DataType::Type::kUint8:
755 case DataType::Type::kInt8:
756 case DataType::Type::kUint16:
757 case DataType::Type::kInt16:
758 case DataType::Type::kInt32:
759 case DataType::Type::kInt64:
760 case DataType::Type::kFloat32:
761 case DataType::Type::kFloat64:
762 DCHECK_LE(2u, instruction->GetVectorLength());
763 DCHECK_LE(instruction->GetVectorLength(), 16u);
764 __ OrV(dst, lhs, rhs); // lanes do not matter
765 break;
766 default:
767 LOG(FATAL) << "Unsupported SIMD type";
768 UNREACHABLE();
769 }
770 }
771
VisitVecXor(HVecXor * instruction)772 void LocationsBuilderMIPS::VisitVecXor(HVecXor* instruction) {
773 CreateVecBinOpLocations(GetGraph()->GetAllocator(), instruction);
774 }
775
VisitVecXor(HVecXor * instruction)776 void InstructionCodeGeneratorMIPS::VisitVecXor(HVecXor* instruction) {
777 LocationSummary* locations = instruction->GetLocations();
778 VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
779 VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
780 VectorRegister dst = VectorRegisterFrom(locations->Out());
781 switch (instruction->GetPackedType()) {
782 case DataType::Type::kBool:
783 case DataType::Type::kUint8:
784 case DataType::Type::kInt8:
785 case DataType::Type::kUint16:
786 case DataType::Type::kInt16:
787 case DataType::Type::kInt32:
788 case DataType::Type::kInt64:
789 case DataType::Type::kFloat32:
790 case DataType::Type::kFloat64:
791 DCHECK_LE(2u, instruction->GetVectorLength());
792 DCHECK_LE(instruction->GetVectorLength(), 16u);
793 __ XorV(dst, lhs, rhs); // lanes do not matter
794 break;
795 default:
796 LOG(FATAL) << "Unsupported SIMD type";
797 UNREACHABLE();
798 }
799 }
800
801 // Helper to set up locations for vector shift operations.
CreateVecShiftLocations(ArenaAllocator * allocator,HVecBinaryOperation * instruction)802 static void CreateVecShiftLocations(ArenaAllocator* allocator, HVecBinaryOperation* instruction) {
803 LocationSummary* locations = new (allocator) LocationSummary(instruction);
804 switch (instruction->GetPackedType()) {
805 case DataType::Type::kUint8:
806 case DataType::Type::kInt8:
807 case DataType::Type::kUint16:
808 case DataType::Type::kInt16:
809 case DataType::Type::kInt32:
810 case DataType::Type::kInt64:
811 locations->SetInAt(0, Location::RequiresFpuRegister());
812 locations->SetInAt(1, Location::ConstantLocation(instruction->InputAt(1)->AsConstant()));
813 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
814 break;
815 default:
816 LOG(FATAL) << "Unsupported SIMD type";
817 UNREACHABLE();
818 }
819 }
820
VisitVecShl(HVecShl * instruction)821 void LocationsBuilderMIPS::VisitVecShl(HVecShl* instruction) {
822 CreateVecShiftLocations(GetGraph()->GetAllocator(), instruction);
823 }
824
VisitVecShl(HVecShl * instruction)825 void InstructionCodeGeneratorMIPS::VisitVecShl(HVecShl* instruction) {
826 LocationSummary* locations = instruction->GetLocations();
827 VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
828 VectorRegister dst = VectorRegisterFrom(locations->Out());
829 int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
830 switch (instruction->GetPackedType()) {
831 case DataType::Type::kUint8:
832 case DataType::Type::kInt8:
833 DCHECK_EQ(16u, instruction->GetVectorLength());
834 __ SlliB(dst, lhs, value);
835 break;
836 case DataType::Type::kUint16:
837 case DataType::Type::kInt16:
838 DCHECK_EQ(8u, instruction->GetVectorLength());
839 __ SlliH(dst, lhs, value);
840 break;
841 case DataType::Type::kInt32:
842 DCHECK_EQ(4u, instruction->GetVectorLength());
843 __ SlliW(dst, lhs, value);
844 break;
845 case DataType::Type::kInt64:
846 DCHECK_EQ(2u, instruction->GetVectorLength());
847 __ SlliD(dst, lhs, value);
848 break;
849 default:
850 LOG(FATAL) << "Unsupported SIMD type";
851 UNREACHABLE();
852 }
853 }
854
VisitVecShr(HVecShr * instruction)855 void LocationsBuilderMIPS::VisitVecShr(HVecShr* instruction) {
856 CreateVecShiftLocations(GetGraph()->GetAllocator(), instruction);
857 }
858
VisitVecShr(HVecShr * instruction)859 void InstructionCodeGeneratorMIPS::VisitVecShr(HVecShr* instruction) {
860 LocationSummary* locations = instruction->GetLocations();
861 VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
862 VectorRegister dst = VectorRegisterFrom(locations->Out());
863 int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
864 switch (instruction->GetPackedType()) {
865 case DataType::Type::kUint8:
866 case DataType::Type::kInt8:
867 DCHECK_EQ(16u, instruction->GetVectorLength());
868 __ SraiB(dst, lhs, value);
869 break;
870 case DataType::Type::kUint16:
871 case DataType::Type::kInt16:
872 DCHECK_EQ(8u, instruction->GetVectorLength());
873 __ SraiH(dst, lhs, value);
874 break;
875 case DataType::Type::kInt32:
876 DCHECK_EQ(4u, instruction->GetVectorLength());
877 __ SraiW(dst, lhs, value);
878 break;
879 case DataType::Type::kInt64:
880 DCHECK_EQ(2u, instruction->GetVectorLength());
881 __ SraiD(dst, lhs, value);
882 break;
883 default:
884 LOG(FATAL) << "Unsupported SIMD type";
885 UNREACHABLE();
886 }
887 }
888
VisitVecUShr(HVecUShr * instruction)889 void LocationsBuilderMIPS::VisitVecUShr(HVecUShr* instruction) {
890 CreateVecShiftLocations(GetGraph()->GetAllocator(), instruction);
891 }
892
VisitVecUShr(HVecUShr * instruction)893 void InstructionCodeGeneratorMIPS::VisitVecUShr(HVecUShr* instruction) {
894 LocationSummary* locations = instruction->GetLocations();
895 VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
896 VectorRegister dst = VectorRegisterFrom(locations->Out());
897 int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
898 switch (instruction->GetPackedType()) {
899 case DataType::Type::kUint8:
900 case DataType::Type::kInt8:
901 DCHECK_EQ(16u, instruction->GetVectorLength());
902 __ SrliB(dst, lhs, value);
903 break;
904 case DataType::Type::kUint16:
905 case DataType::Type::kInt16:
906 DCHECK_EQ(8u, instruction->GetVectorLength());
907 __ SrliH(dst, lhs, value);
908 break;
909 case DataType::Type::kInt32:
910 DCHECK_EQ(4u, instruction->GetVectorLength());
911 __ SrliW(dst, lhs, value);
912 break;
913 case DataType::Type::kInt64:
914 DCHECK_EQ(2u, instruction->GetVectorLength());
915 __ SrliD(dst, lhs, value);
916 break;
917 default:
918 LOG(FATAL) << "Unsupported SIMD type";
919 UNREACHABLE();
920 }
921 }
922
VisitVecSetScalars(HVecSetScalars * instruction)923 void LocationsBuilderMIPS::VisitVecSetScalars(HVecSetScalars* instruction) {
924 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(instruction);
925
926 DCHECK_EQ(1u, instruction->InputCount()); // only one input currently implemented
927
928 HInstruction* input = instruction->InputAt(0);
929 bool is_zero = IsZeroBitPattern(input);
930
931 switch (instruction->GetPackedType()) {
932 case DataType::Type::kBool:
933 case DataType::Type::kUint8:
934 case DataType::Type::kInt8:
935 case DataType::Type::kUint16:
936 case DataType::Type::kInt16:
937 case DataType::Type::kInt32:
938 case DataType::Type::kInt64:
939 locations->SetInAt(0, is_zero ? Location::ConstantLocation(input->AsConstant())
940 : Location::RequiresRegister());
941 locations->SetOut(Location::RequiresFpuRegister());
942 break;
943 case DataType::Type::kFloat32:
944 case DataType::Type::kFloat64:
945 locations->SetInAt(0, is_zero ? Location::ConstantLocation(input->AsConstant())
946 : Location::RequiresFpuRegister());
947 locations->SetOut(Location::RequiresFpuRegister());
948 break;
949 default:
950 LOG(FATAL) << "Unsupported SIMD type";
951 UNREACHABLE();
952 }
953 }
954
VisitVecSetScalars(HVecSetScalars * instruction)955 void InstructionCodeGeneratorMIPS::VisitVecSetScalars(HVecSetScalars* instruction) {
956 LocationSummary* locations = instruction->GetLocations();
957 VectorRegister dst = VectorRegisterFrom(locations->Out());
958
959 DCHECK_EQ(1u, instruction->InputCount()); // only one input currently implemented
960
961 // Zero out all other elements first.
962 __ FillW(dst, ZERO);
963
964 // Shorthand for any type of zero.
965 if (IsZeroBitPattern(instruction->InputAt(0))) {
966 return;
967 }
968
969 // Set required elements.
970 switch (instruction->GetPackedType()) {
971 case DataType::Type::kBool:
972 case DataType::Type::kUint8:
973 case DataType::Type::kInt8:
974 DCHECK_EQ(16u, instruction->GetVectorLength());
975 __ InsertB(dst, locations->InAt(0).AsRegister<Register>(), 0);
976 break;
977 case DataType::Type::kUint16:
978 case DataType::Type::kInt16:
979 DCHECK_EQ(8u, instruction->GetVectorLength());
980 __ InsertH(dst, locations->InAt(0).AsRegister<Register>(), 0);
981 break;
982 case DataType::Type::kInt32:
983 DCHECK_EQ(4u, instruction->GetVectorLength());
984 __ InsertW(dst, locations->InAt(0).AsRegister<Register>(), 0);
985 break;
986 case DataType::Type::kInt64:
987 DCHECK_EQ(2u, instruction->GetVectorLength());
988 __ InsertW(dst, locations->InAt(0).AsRegisterPairLow<Register>(), 0);
989 __ InsertW(dst, locations->InAt(0).AsRegisterPairHigh<Register>(), 1);
990 break;
991 default:
992 LOG(FATAL) << "Unsupported SIMD type";
993 UNREACHABLE();
994 }
995 }
996
997 // Helper to set up locations for vector accumulations.
CreateVecAccumLocations(ArenaAllocator * allocator,HVecOperation * instruction)998 static void CreateVecAccumLocations(ArenaAllocator* allocator, HVecOperation* instruction) {
999 LocationSummary* locations = new (allocator) LocationSummary(instruction);
1000 switch (instruction->GetPackedType()) {
1001 case DataType::Type::kUint8:
1002 case DataType::Type::kInt8:
1003 case DataType::Type::kUint16:
1004 case DataType::Type::kInt16:
1005 case DataType::Type::kInt32:
1006 case DataType::Type::kInt64:
1007 locations->SetInAt(0, Location::RequiresFpuRegister());
1008 locations->SetInAt(1, Location::RequiresFpuRegister());
1009 locations->SetInAt(2, Location::RequiresFpuRegister());
1010 locations->SetOut(Location::SameAsFirstInput());
1011 break;
1012 default:
1013 LOG(FATAL) << "Unsupported SIMD type";
1014 UNREACHABLE();
1015 }
1016 }
1017
VisitVecMultiplyAccumulate(HVecMultiplyAccumulate * instruction)1018 void LocationsBuilderMIPS::VisitVecMultiplyAccumulate(HVecMultiplyAccumulate* instruction) {
1019 CreateVecAccumLocations(GetGraph()->GetAllocator(), instruction);
1020 }
1021
VisitVecMultiplyAccumulate(HVecMultiplyAccumulate * instruction)1022 void InstructionCodeGeneratorMIPS::VisitVecMultiplyAccumulate(HVecMultiplyAccumulate* instruction) {
1023 LocationSummary* locations = instruction->GetLocations();
1024 VectorRegister acc = VectorRegisterFrom(locations->InAt(0));
1025 VectorRegister left = VectorRegisterFrom(locations->InAt(1));
1026 VectorRegister right = VectorRegisterFrom(locations->InAt(2));
1027 switch (instruction->GetPackedType()) {
1028 case DataType::Type::kUint8:
1029 case DataType::Type::kInt8:
1030 DCHECK_EQ(16u, instruction->GetVectorLength());
1031 if (instruction->GetOpKind() == HInstruction::kAdd) {
1032 __ MaddvB(acc, left, right);
1033 } else {
1034 __ MsubvB(acc, left, right);
1035 }
1036 break;
1037 case DataType::Type::kUint16:
1038 case DataType::Type::kInt16:
1039 DCHECK_EQ(8u, instruction->GetVectorLength());
1040 if (instruction->GetOpKind() == HInstruction::kAdd) {
1041 __ MaddvH(acc, left, right);
1042 } else {
1043 __ MsubvH(acc, left, right);
1044 }
1045 break;
1046 case DataType::Type::kInt32:
1047 DCHECK_EQ(4u, instruction->GetVectorLength());
1048 if (instruction->GetOpKind() == HInstruction::kAdd) {
1049 __ MaddvW(acc, left, right);
1050 } else {
1051 __ MsubvW(acc, left, right);
1052 }
1053 break;
1054 case DataType::Type::kInt64:
1055 DCHECK_EQ(2u, instruction->GetVectorLength());
1056 if (instruction->GetOpKind() == HInstruction::kAdd) {
1057 __ MaddvD(acc, left, right);
1058 } else {
1059 __ MsubvD(acc, left, right);
1060 }
1061 break;
1062 default:
1063 LOG(FATAL) << "Unsupported SIMD type";
1064 UNREACHABLE();
1065 }
1066 }
1067
VisitVecSADAccumulate(HVecSADAccumulate * instruction)1068 void LocationsBuilderMIPS::VisitVecSADAccumulate(HVecSADAccumulate* instruction) {
1069 CreateVecAccumLocations(GetGraph()->GetAllocator(), instruction);
1070 LocationSummary* locations = instruction->GetLocations();
1071 // All conversions require at least one temporary register.
1072 locations->AddTemp(Location::RequiresFpuRegister());
1073 // Some conversions require a second temporary register.
1074 HVecOperation* a = instruction->InputAt(1)->AsVecOperation();
1075 HVecOperation* b = instruction->InputAt(2)->AsVecOperation();
1076 DCHECK_EQ(HVecOperation::ToSignedType(a->GetPackedType()),
1077 HVecOperation::ToSignedType(b->GetPackedType()));
1078 switch (a->GetPackedType()) {
1079 case DataType::Type::kInt32:
1080 if (instruction->GetPackedType() == DataType::Type::kInt32) {
1081 break;
1082 }
1083 FALLTHROUGH_INTENDED;
1084 case DataType::Type::kUint8:
1085 case DataType::Type::kInt8:
1086 case DataType::Type::kUint16:
1087 case DataType::Type::kInt16:
1088 locations->AddTemp(Location::RequiresFpuRegister());
1089 break;
1090 default:
1091 break;
1092 }
1093 }
1094
VisitVecSADAccumulate(HVecSADAccumulate * instruction)1095 void InstructionCodeGeneratorMIPS::VisitVecSADAccumulate(HVecSADAccumulate* instruction) {
1096 LocationSummary* locations = instruction->GetLocations();
1097 VectorRegister acc = VectorRegisterFrom(locations->InAt(0));
1098 VectorRegister left = VectorRegisterFrom(locations->InAt(1));
1099 VectorRegister right = VectorRegisterFrom(locations->InAt(2));
1100 VectorRegister tmp = static_cast<VectorRegister>(FTMP);
1101 VectorRegister tmp1 = VectorRegisterFrom(locations->GetTemp(0));
1102
1103 DCHECK(locations->InAt(0).Equals(locations->Out()));
1104
1105 // Handle all feasible acc_T += sad(a_S, b_S) type combinations (T x S).
1106 HVecOperation* a = instruction->InputAt(1)->AsVecOperation();
1107 HVecOperation* b = instruction->InputAt(2)->AsVecOperation();
1108 DCHECK_EQ(HVecOperation::ToSignedType(a->GetPackedType()),
1109 HVecOperation::ToSignedType(b->GetPackedType()));
1110 switch (a->GetPackedType()) {
1111 case DataType::Type::kUint8:
1112 case DataType::Type::kInt8:
1113 DCHECK_EQ(16u, a->GetVectorLength());
1114 switch (instruction->GetPackedType()) {
1115 case DataType::Type::kUint16:
1116 case DataType::Type::kInt16: {
1117 DCHECK_EQ(8u, instruction->GetVectorLength());
1118 VectorRegister tmp2 = VectorRegisterFrom(locations->GetTemp(1));
1119 __ FillB(tmp, ZERO);
1120 __ Hadd_sH(tmp1, left, tmp);
1121 __ Hadd_sH(tmp2, right, tmp);
1122 __ Asub_sH(tmp1, tmp1, tmp2);
1123 __ AddvH(acc, acc, tmp1);
1124 __ Hadd_sH(tmp1, tmp, left);
1125 __ Hadd_sH(tmp2, tmp, right);
1126 __ Asub_sH(tmp1, tmp1, tmp2);
1127 __ AddvH(acc, acc, tmp1);
1128 break;
1129 }
1130 case DataType::Type::kInt32: {
1131 DCHECK_EQ(4u, instruction->GetVectorLength());
1132 VectorRegister tmp2 = VectorRegisterFrom(locations->GetTemp(1));
1133 __ FillB(tmp, ZERO);
1134 __ Hadd_sH(tmp1, left, tmp);
1135 __ Hadd_sH(tmp2, right, tmp);
1136 __ Asub_sH(tmp1, tmp1, tmp2);
1137 __ Hadd_sW(tmp1, tmp1, tmp1);
1138 __ AddvW(acc, acc, tmp1);
1139 __ Hadd_sH(tmp1, tmp, left);
1140 __ Hadd_sH(tmp2, tmp, right);
1141 __ Asub_sH(tmp1, tmp1, tmp2);
1142 __ Hadd_sW(tmp1, tmp1, tmp1);
1143 __ AddvW(acc, acc, tmp1);
1144 break;
1145 }
1146 case DataType::Type::kInt64: {
1147 DCHECK_EQ(2u, instruction->GetVectorLength());
1148 VectorRegister tmp2 = VectorRegisterFrom(locations->GetTemp(1));
1149 __ FillB(tmp, ZERO);
1150 __ Hadd_sH(tmp1, left, tmp);
1151 __ Hadd_sH(tmp2, right, tmp);
1152 __ Asub_sH(tmp1, tmp1, tmp2);
1153 __ Hadd_sW(tmp1, tmp1, tmp1);
1154 __ Hadd_sD(tmp1, tmp1, tmp1);
1155 __ AddvD(acc, acc, tmp1);
1156 __ Hadd_sH(tmp1, tmp, left);
1157 __ Hadd_sH(tmp2, tmp, right);
1158 __ Asub_sH(tmp1, tmp1, tmp2);
1159 __ Hadd_sW(tmp1, tmp1, tmp1);
1160 __ Hadd_sD(tmp1, tmp1, tmp1);
1161 __ AddvD(acc, acc, tmp1);
1162 break;
1163 }
1164 default:
1165 LOG(FATAL) << "Unsupported SIMD type";
1166 UNREACHABLE();
1167 }
1168 break;
1169 case DataType::Type::kUint16:
1170 case DataType::Type::kInt16:
1171 DCHECK_EQ(8u, a->GetVectorLength());
1172 switch (instruction->GetPackedType()) {
1173 case DataType::Type::kInt32: {
1174 DCHECK_EQ(4u, instruction->GetVectorLength());
1175 VectorRegister tmp2 = VectorRegisterFrom(locations->GetTemp(1));
1176 __ FillH(tmp, ZERO);
1177 __ Hadd_sW(tmp1, left, tmp);
1178 __ Hadd_sW(tmp2, right, tmp);
1179 __ Asub_sW(tmp1, tmp1, tmp2);
1180 __ AddvW(acc, acc, tmp1);
1181 __ Hadd_sW(tmp1, tmp, left);
1182 __ Hadd_sW(tmp2, tmp, right);
1183 __ Asub_sW(tmp1, tmp1, tmp2);
1184 __ AddvW(acc, acc, tmp1);
1185 break;
1186 }
1187 case DataType::Type::kInt64: {
1188 DCHECK_EQ(2u, instruction->GetVectorLength());
1189 VectorRegister tmp2 = VectorRegisterFrom(locations->GetTemp(1));
1190 __ FillH(tmp, ZERO);
1191 __ Hadd_sW(tmp1, left, tmp);
1192 __ Hadd_sW(tmp2, right, tmp);
1193 __ Asub_sW(tmp1, tmp1, tmp2);
1194 __ Hadd_sD(tmp1, tmp1, tmp1);
1195 __ AddvD(acc, acc, tmp1);
1196 __ Hadd_sW(tmp1, tmp, left);
1197 __ Hadd_sW(tmp2, tmp, right);
1198 __ Asub_sW(tmp1, tmp1, tmp2);
1199 __ Hadd_sD(tmp1, tmp1, tmp1);
1200 __ AddvD(acc, acc, tmp1);
1201 break;
1202 }
1203 default:
1204 LOG(FATAL) << "Unsupported SIMD type";
1205 UNREACHABLE();
1206 }
1207 break;
1208 case DataType::Type::kInt32:
1209 DCHECK_EQ(4u, a->GetVectorLength());
1210 switch (instruction->GetPackedType()) {
1211 case DataType::Type::kInt32: {
1212 DCHECK_EQ(4u, instruction->GetVectorLength());
1213 __ FillW(tmp, ZERO);
1214 __ SubvW(tmp1, left, right);
1215 __ Add_aW(tmp1, tmp1, tmp);
1216 __ AddvW(acc, acc, tmp1);
1217 break;
1218 }
1219 case DataType::Type::kInt64: {
1220 DCHECK_EQ(2u, instruction->GetVectorLength());
1221 VectorRegister tmp2 = VectorRegisterFrom(locations->GetTemp(1));
1222 __ FillW(tmp, ZERO);
1223 __ Hadd_sD(tmp1, left, tmp);
1224 __ Hadd_sD(tmp2, right, tmp);
1225 __ Asub_sD(tmp1, tmp1, tmp2);
1226 __ AddvD(acc, acc, tmp1);
1227 __ Hadd_sD(tmp1, tmp, left);
1228 __ Hadd_sD(tmp2, tmp, right);
1229 __ Asub_sD(tmp1, tmp1, tmp2);
1230 __ AddvD(acc, acc, tmp1);
1231 break;
1232 }
1233 default:
1234 LOG(FATAL) << "Unsupported SIMD type";
1235 UNREACHABLE();
1236 }
1237 break;
1238 case DataType::Type::kInt64: {
1239 DCHECK_EQ(2u, a->GetVectorLength());
1240 switch (instruction->GetPackedType()) {
1241 case DataType::Type::kInt64: {
1242 DCHECK_EQ(2u, instruction->GetVectorLength());
1243 __ FillW(tmp, ZERO);
1244 __ SubvD(tmp1, left, right);
1245 __ Add_aD(tmp1, tmp1, tmp);
1246 __ AddvD(acc, acc, tmp1);
1247 break;
1248 }
1249 default:
1250 LOG(FATAL) << "Unsupported SIMD type";
1251 UNREACHABLE();
1252 }
1253 break;
1254 }
1255 default:
1256 LOG(FATAL) << "Unsupported SIMD type";
1257 UNREACHABLE();
1258 }
1259 }
1260
1261 // Helper to set up locations for vector memory operations.
CreateVecMemLocations(ArenaAllocator * allocator,HVecMemoryOperation * instruction,bool is_load)1262 static void CreateVecMemLocations(ArenaAllocator* allocator,
1263 HVecMemoryOperation* instruction,
1264 bool is_load) {
1265 LocationSummary* locations = new (allocator) LocationSummary(instruction);
1266 switch (instruction->GetPackedType()) {
1267 case DataType::Type::kBool:
1268 case DataType::Type::kUint8:
1269 case DataType::Type::kInt8:
1270 case DataType::Type::kUint16:
1271 case DataType::Type::kInt16:
1272 case DataType::Type::kInt32:
1273 case DataType::Type::kInt64:
1274 case DataType::Type::kFloat32:
1275 case DataType::Type::kFloat64:
1276 locations->SetInAt(0, Location::RequiresRegister());
1277 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
1278 if (is_load) {
1279 locations->SetOut(Location::RequiresFpuRegister());
1280 } else {
1281 locations->SetInAt(2, Location::RequiresFpuRegister());
1282 }
1283 break;
1284 default:
1285 LOG(FATAL) << "Unsupported SIMD type";
1286 UNREACHABLE();
1287 }
1288 }
1289
1290 // Helper to prepare register and offset for vector memory operations. Returns the offset and sets
1291 // the output parameter adjusted_base to the original base or to a reserved temporary register (AT).
VecAddress(LocationSummary * locations,size_t size,Register * adjusted_base)1292 int32_t InstructionCodeGeneratorMIPS::VecAddress(LocationSummary* locations,
1293 size_t size,
1294 /* out */ Register* adjusted_base) {
1295 Register base = locations->InAt(0).AsRegister<Register>();
1296 Location index = locations->InAt(1);
1297 int scale = TIMES_1;
1298 switch (size) {
1299 case 2: scale = TIMES_2; break;
1300 case 4: scale = TIMES_4; break;
1301 case 8: scale = TIMES_8; break;
1302 default: break;
1303 }
1304 int32_t offset = mirror::Array::DataOffset(size).Int32Value();
1305
1306 if (index.IsConstant()) {
1307 offset += index.GetConstant()->AsIntConstant()->GetValue() << scale;
1308 __ AdjustBaseOffsetAndElementSizeShift(base, offset, scale);
1309 *adjusted_base = base;
1310 } else {
1311 Register index_reg = index.AsRegister<Register>();
1312 if (scale != TIMES_1) {
1313 __ Lsa(AT, index_reg, base, scale);
1314 } else {
1315 __ Addu(AT, base, index_reg);
1316 }
1317 *adjusted_base = AT;
1318 }
1319 return offset;
1320 }
1321
VisitVecLoad(HVecLoad * instruction)1322 void LocationsBuilderMIPS::VisitVecLoad(HVecLoad* instruction) {
1323 CreateVecMemLocations(GetGraph()->GetAllocator(), instruction, /* is_load */ true);
1324 }
1325
VisitVecLoad(HVecLoad * instruction)1326 void InstructionCodeGeneratorMIPS::VisitVecLoad(HVecLoad* instruction) {
1327 LocationSummary* locations = instruction->GetLocations();
1328 size_t size = DataType::Size(instruction->GetPackedType());
1329 VectorRegister reg = VectorRegisterFrom(locations->Out());
1330 Register base;
1331 int32_t offset = VecAddress(locations, size, &base);
1332 switch (instruction->GetPackedType()) {
1333 case DataType::Type::kBool:
1334 case DataType::Type::kUint8:
1335 case DataType::Type::kInt8:
1336 DCHECK_EQ(16u, instruction->GetVectorLength());
1337 __ LdB(reg, base, offset);
1338 break;
1339 case DataType::Type::kUint16:
1340 case DataType::Type::kInt16:
1341 // Loading 8-bytes (needed if dealing with compressed strings in StringCharAt) from unaligned
1342 // memory address may cause a trap to the kernel if the CPU doesn't directly support unaligned
1343 // loads and stores.
1344 // TODO: Implement support for StringCharAt.
1345 DCHECK(!instruction->IsStringCharAt());
1346 DCHECK_EQ(8u, instruction->GetVectorLength());
1347 __ LdH(reg, base, offset);
1348 break;
1349 case DataType::Type::kInt32:
1350 case DataType::Type::kFloat32:
1351 DCHECK_EQ(4u, instruction->GetVectorLength());
1352 __ LdW(reg, base, offset);
1353 break;
1354 case DataType::Type::kInt64:
1355 case DataType::Type::kFloat64:
1356 DCHECK_EQ(2u, instruction->GetVectorLength());
1357 __ LdD(reg, base, offset);
1358 break;
1359 default:
1360 LOG(FATAL) << "Unsupported SIMD type";
1361 UNREACHABLE();
1362 }
1363 }
1364
VisitVecStore(HVecStore * instruction)1365 void LocationsBuilderMIPS::VisitVecStore(HVecStore* instruction) {
1366 CreateVecMemLocations(GetGraph()->GetAllocator(), instruction, /* is_load */ false);
1367 }
1368
VisitVecStore(HVecStore * instruction)1369 void InstructionCodeGeneratorMIPS::VisitVecStore(HVecStore* instruction) {
1370 LocationSummary* locations = instruction->GetLocations();
1371 size_t size = DataType::Size(instruction->GetPackedType());
1372 VectorRegister reg = VectorRegisterFrom(locations->InAt(2));
1373 Register base;
1374 int32_t offset = VecAddress(locations, size, &base);
1375 switch (instruction->GetPackedType()) {
1376 case DataType::Type::kBool:
1377 case DataType::Type::kUint8:
1378 case DataType::Type::kInt8:
1379 DCHECK_EQ(16u, instruction->GetVectorLength());
1380 __ StB(reg, base, offset);
1381 break;
1382 case DataType::Type::kUint16:
1383 case DataType::Type::kInt16:
1384 DCHECK_EQ(8u, instruction->GetVectorLength());
1385 __ StH(reg, base, offset);
1386 break;
1387 case DataType::Type::kInt32:
1388 case DataType::Type::kFloat32:
1389 DCHECK_EQ(4u, instruction->GetVectorLength());
1390 __ StW(reg, base, offset);
1391 break;
1392 case DataType::Type::kInt64:
1393 case DataType::Type::kFloat64:
1394 DCHECK_EQ(2u, instruction->GetVectorLength());
1395 __ StD(reg, base, offset);
1396 break;
1397 default:
1398 LOG(FATAL) << "Unsupported SIMD type";
1399 UNREACHABLE();
1400 }
1401 }
1402
1403 #undef __
1404
1405 } // namespace mips
1406 } // namespace art
1407