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: " << instruction->GetPackedType();
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: " << instruction->GetPackedType();
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: " << instruction->GetPackedType();
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: " << instruction->GetPackedType();
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: " << instruction->GetPackedType();
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->GetReductionKind()) {
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->GetReductionKind()) {
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: " << instruction->GetPackedType();
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: " << instruction->GetPackedType();
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: " << instruction->GetPackedType();
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: " << instruction->GetPackedType();
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: " << instruction->GetPackedType();
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: " << instruction->GetPackedType();
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: " << instruction->GetPackedType();
438       UNREACHABLE();
439   }
440 }
441 
VisitVecSaturationAdd(HVecSaturationAdd * instruction)442 void LocationsBuilderMIPS::VisitVecSaturationAdd(HVecSaturationAdd* instruction) {
443   CreateVecBinOpLocations(GetGraph()->GetAllocator(), instruction);
444 }
445 
VisitVecSaturationAdd(HVecSaturationAdd * instruction)446 void InstructionCodeGeneratorMIPS::VisitVecSaturationAdd(HVecSaturationAdd* instruction) {
447   LOG(FATAL) << "Unsupported SIMD " << instruction->GetId();
448 }
449 
VisitVecHalvingAdd(HVecHalvingAdd * instruction)450 void LocationsBuilderMIPS::VisitVecHalvingAdd(HVecHalvingAdd* instruction) {
451   CreateVecBinOpLocations(GetGraph()->GetAllocator(), instruction);
452 }
453 
VisitVecHalvingAdd(HVecHalvingAdd * instruction)454 void InstructionCodeGeneratorMIPS::VisitVecHalvingAdd(HVecHalvingAdd* instruction) {
455   LocationSummary* locations = instruction->GetLocations();
456   VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
457   VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
458   VectorRegister dst = VectorRegisterFrom(locations->Out());
459   switch (instruction->GetPackedType()) {
460     case DataType::Type::kUint8:
461       DCHECK_EQ(16u, instruction->GetVectorLength());
462       instruction->IsRounded()
463           ? __ Aver_uB(dst, lhs, rhs)
464           : __ Ave_uB(dst, lhs, rhs);
465       break;
466     case DataType::Type::kInt8:
467       DCHECK_EQ(16u, instruction->GetVectorLength());
468       instruction->IsRounded()
469           ? __ Aver_sB(dst, lhs, rhs)
470           : __ Ave_sB(dst, lhs, rhs);
471       break;
472     case DataType::Type::kUint16:
473       DCHECK_EQ(8u, instruction->GetVectorLength());
474       instruction->IsRounded()
475           ? __ Aver_uH(dst, lhs, rhs)
476           : __ Ave_uH(dst, lhs, rhs);
477       break;
478     case DataType::Type::kInt16:
479       DCHECK_EQ(8u, instruction->GetVectorLength());
480       instruction->IsRounded()
481           ? __ Aver_sH(dst, lhs, rhs)
482           : __ Ave_sH(dst, lhs, rhs);
483       break;
484     default:
485       LOG(FATAL) << "Unsupported SIMD type: " << instruction->GetPackedType();
486       UNREACHABLE();
487   }
488 }
489 
VisitVecSub(HVecSub * instruction)490 void LocationsBuilderMIPS::VisitVecSub(HVecSub* instruction) {
491   CreateVecBinOpLocations(GetGraph()->GetAllocator(), instruction);
492 }
493 
VisitVecSub(HVecSub * instruction)494 void InstructionCodeGeneratorMIPS::VisitVecSub(HVecSub* instruction) {
495   LocationSummary* locations = instruction->GetLocations();
496   VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
497   VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
498   VectorRegister dst = VectorRegisterFrom(locations->Out());
499   switch (instruction->GetPackedType()) {
500     case DataType::Type::kUint8:
501     case DataType::Type::kInt8:
502       DCHECK_EQ(16u, instruction->GetVectorLength());
503       __ SubvB(dst, lhs, rhs);
504       break;
505     case DataType::Type::kUint16:
506     case DataType::Type::kInt16:
507       DCHECK_EQ(8u, instruction->GetVectorLength());
508       __ SubvH(dst, lhs, rhs);
509       break;
510     case DataType::Type::kInt32:
511       DCHECK_EQ(4u, instruction->GetVectorLength());
512       __ SubvW(dst, lhs, rhs);
513       break;
514     case DataType::Type::kInt64:
515       DCHECK_EQ(2u, instruction->GetVectorLength());
516       __ SubvD(dst, lhs, rhs);
517       break;
518     case DataType::Type::kFloat32:
519       DCHECK_EQ(4u, instruction->GetVectorLength());
520       __ FsubW(dst, lhs, rhs);
521       break;
522     case DataType::Type::kFloat64:
523       DCHECK_EQ(2u, instruction->GetVectorLength());
524       __ FsubD(dst, lhs, rhs);
525       break;
526     default:
527       LOG(FATAL) << "Unsupported SIMD type: " << instruction->GetPackedType();
528       UNREACHABLE();
529   }
530 }
531 
VisitVecSaturationSub(HVecSaturationSub * instruction)532 void LocationsBuilderMIPS::VisitVecSaturationSub(HVecSaturationSub* instruction) {
533   CreateVecBinOpLocations(GetGraph()->GetAllocator(), instruction);
534 }
535 
VisitVecSaturationSub(HVecSaturationSub * instruction)536 void InstructionCodeGeneratorMIPS::VisitVecSaturationSub(HVecSaturationSub* instruction) {
537   LOG(FATAL) << "Unsupported SIMD " << instruction->GetId();
538 }
539 
VisitVecMul(HVecMul * instruction)540 void LocationsBuilderMIPS::VisitVecMul(HVecMul* instruction) {
541   CreateVecBinOpLocations(GetGraph()->GetAllocator(), instruction);
542 }
543 
VisitVecMul(HVecMul * instruction)544 void InstructionCodeGeneratorMIPS::VisitVecMul(HVecMul* instruction) {
545   LocationSummary* locations = instruction->GetLocations();
546   VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
547   VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
548   VectorRegister dst = VectorRegisterFrom(locations->Out());
549   switch (instruction->GetPackedType()) {
550     case DataType::Type::kUint8:
551     case DataType::Type::kInt8:
552       DCHECK_EQ(16u, instruction->GetVectorLength());
553       __ MulvB(dst, lhs, rhs);
554       break;
555     case DataType::Type::kUint16:
556     case DataType::Type::kInt16:
557       DCHECK_EQ(8u, instruction->GetVectorLength());
558       __ MulvH(dst, lhs, rhs);
559       break;
560     case DataType::Type::kInt32:
561       DCHECK_EQ(4u, instruction->GetVectorLength());
562       __ MulvW(dst, lhs, rhs);
563       break;
564     case DataType::Type::kInt64:
565       DCHECK_EQ(2u, instruction->GetVectorLength());
566       __ MulvD(dst, lhs, rhs);
567       break;
568     case DataType::Type::kFloat32:
569       DCHECK_EQ(4u, instruction->GetVectorLength());
570       __ FmulW(dst, lhs, rhs);
571       break;
572     case DataType::Type::kFloat64:
573       DCHECK_EQ(2u, instruction->GetVectorLength());
574       __ FmulD(dst, lhs, rhs);
575       break;
576     default:
577       LOG(FATAL) << "Unsupported SIMD type: " << instruction->GetPackedType();
578       UNREACHABLE();
579   }
580 }
581 
VisitVecDiv(HVecDiv * instruction)582 void LocationsBuilderMIPS::VisitVecDiv(HVecDiv* instruction) {
583   CreateVecBinOpLocations(GetGraph()->GetAllocator(), instruction);
584 }
585 
VisitVecDiv(HVecDiv * instruction)586 void InstructionCodeGeneratorMIPS::VisitVecDiv(HVecDiv* instruction) {
587   LocationSummary* locations = instruction->GetLocations();
588   VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
589   VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
590   VectorRegister dst = VectorRegisterFrom(locations->Out());
591   switch (instruction->GetPackedType()) {
592     case DataType::Type::kFloat32:
593       DCHECK_EQ(4u, instruction->GetVectorLength());
594       __ FdivW(dst, lhs, rhs);
595       break;
596     case DataType::Type::kFloat64:
597       DCHECK_EQ(2u, instruction->GetVectorLength());
598       __ FdivD(dst, lhs, rhs);
599       break;
600     default:
601       LOG(FATAL) << "Unsupported SIMD type: " << instruction->GetPackedType();
602       UNREACHABLE();
603   }
604 }
605 
VisitVecMin(HVecMin * instruction)606 void LocationsBuilderMIPS::VisitVecMin(HVecMin* instruction) {
607   CreateVecBinOpLocations(GetGraph()->GetAllocator(), instruction);
608 }
609 
VisitVecMin(HVecMin * instruction)610 void InstructionCodeGeneratorMIPS::VisitVecMin(HVecMin* instruction) {
611   LocationSummary* locations = instruction->GetLocations();
612   VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
613   VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
614   VectorRegister dst = VectorRegisterFrom(locations->Out());
615   switch (instruction->GetPackedType()) {
616     case DataType::Type::kUint8:
617       DCHECK_EQ(16u, instruction->GetVectorLength());
618       __ Min_uB(dst, lhs, rhs);
619       break;
620     case DataType::Type::kInt8:
621       DCHECK_EQ(16u, instruction->GetVectorLength());
622       __ Min_sB(dst, lhs, rhs);
623       break;
624     case DataType::Type::kUint16:
625       DCHECK_EQ(8u, instruction->GetVectorLength());
626       __ Min_uH(dst, lhs, rhs);
627       break;
628     case DataType::Type::kInt16:
629       DCHECK_EQ(8u, instruction->GetVectorLength());
630       __ Min_sH(dst, lhs, rhs);
631       break;
632     case DataType::Type::kUint32:
633       DCHECK_EQ(4u, instruction->GetVectorLength());
634       __ Min_uW(dst, lhs, rhs);
635       break;
636     case DataType::Type::kInt32:
637       DCHECK_EQ(4u, instruction->GetVectorLength());
638       __ Min_sW(dst, lhs, rhs);
639       break;
640     case DataType::Type::kUint64:
641       DCHECK_EQ(2u, instruction->GetVectorLength());
642       __ Min_uD(dst, lhs, rhs);
643       break;
644     case DataType::Type::kInt64:
645       DCHECK_EQ(2u, instruction->GetVectorLength());
646       __ Min_sD(dst, lhs, rhs);
647       break;
648     // When one of arguments is NaN, fmin.df returns other argument, but Java expects a NaN value.
649     // TODO: Fix min(x, NaN) cases for float and double.
650     case DataType::Type::kFloat32:
651       DCHECK_EQ(4u, instruction->GetVectorLength());
652       __ FminW(dst, lhs, rhs);
653       break;
654     case DataType::Type::kFloat64:
655       DCHECK_EQ(2u, instruction->GetVectorLength());
656       __ FminD(dst, lhs, rhs);
657       break;
658     default:
659       LOG(FATAL) << "Unsupported SIMD type: " << instruction->GetPackedType();
660       UNREACHABLE();
661   }
662 }
663 
VisitVecMax(HVecMax * instruction)664 void LocationsBuilderMIPS::VisitVecMax(HVecMax* instruction) {
665   CreateVecBinOpLocations(GetGraph()->GetAllocator(), instruction);
666 }
667 
VisitVecMax(HVecMax * instruction)668 void InstructionCodeGeneratorMIPS::VisitVecMax(HVecMax* instruction) {
669   LocationSummary* locations = instruction->GetLocations();
670   VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
671   VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
672   VectorRegister dst = VectorRegisterFrom(locations->Out());
673   switch (instruction->GetPackedType()) {
674     case DataType::Type::kUint8:
675       DCHECK_EQ(16u, instruction->GetVectorLength());
676       __ Max_uB(dst, lhs, rhs);
677       break;
678     case DataType::Type::kInt8:
679       DCHECK_EQ(16u, instruction->GetVectorLength());
680       __ Max_sB(dst, lhs, rhs);
681       break;
682     case DataType::Type::kUint16:
683       DCHECK_EQ(8u, instruction->GetVectorLength());
684       __ Max_uH(dst, lhs, rhs);
685       break;
686     case DataType::Type::kInt16:
687       DCHECK_EQ(8u, instruction->GetVectorLength());
688       __ Max_sH(dst, lhs, rhs);
689       break;
690     case DataType::Type::kUint32:
691       DCHECK_EQ(4u, instruction->GetVectorLength());
692       __ Max_uW(dst, lhs, rhs);
693       break;
694     case DataType::Type::kInt32:
695       DCHECK_EQ(4u, instruction->GetVectorLength());
696       __ Max_sW(dst, lhs, rhs);
697       break;
698     case DataType::Type::kUint64:
699       DCHECK_EQ(2u, instruction->GetVectorLength());
700       __ Max_uD(dst, lhs, rhs);
701       break;
702     case DataType::Type::kInt64:
703       DCHECK_EQ(2u, instruction->GetVectorLength());
704       __ Max_sD(dst, lhs, rhs);
705       break;
706     // When one of arguments is NaN, fmax.df returns other argument, but Java expects a NaN value.
707     // TODO: Fix max(x, NaN) cases for float and double.
708     case DataType::Type::kFloat32:
709       DCHECK_EQ(4u, instruction->GetVectorLength());
710       __ FmaxW(dst, lhs, rhs);
711       break;
712     case DataType::Type::kFloat64:
713       DCHECK_EQ(2u, instruction->GetVectorLength());
714       __ FmaxD(dst, lhs, rhs);
715       break;
716     default:
717       LOG(FATAL) << "Unsupported SIMD type: " << instruction->GetPackedType();
718       UNREACHABLE();
719   }
720 }
721 
VisitVecAnd(HVecAnd * instruction)722 void LocationsBuilderMIPS::VisitVecAnd(HVecAnd* instruction) {
723   CreateVecBinOpLocations(GetGraph()->GetAllocator(), instruction);
724 }
725 
VisitVecAnd(HVecAnd * instruction)726 void InstructionCodeGeneratorMIPS::VisitVecAnd(HVecAnd* instruction) {
727   LocationSummary* locations = instruction->GetLocations();
728   VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
729   VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
730   VectorRegister dst = VectorRegisterFrom(locations->Out());
731   switch (instruction->GetPackedType()) {
732     case DataType::Type::kBool:
733     case DataType::Type::kUint8:
734     case DataType::Type::kInt8:
735     case DataType::Type::kUint16:
736     case DataType::Type::kInt16:
737     case DataType::Type::kInt32:
738     case DataType::Type::kInt64:
739     case DataType::Type::kFloat32:
740     case DataType::Type::kFloat64:
741       DCHECK_LE(2u, instruction->GetVectorLength());
742       DCHECK_LE(instruction->GetVectorLength(), 16u);
743       __ AndV(dst, lhs, rhs);  // lanes do not matter
744       break;
745     default:
746       LOG(FATAL) << "Unsupported SIMD type: " << instruction->GetPackedType();
747       UNREACHABLE();
748   }
749 }
750 
VisitVecAndNot(HVecAndNot * instruction)751 void LocationsBuilderMIPS::VisitVecAndNot(HVecAndNot* instruction) {
752   CreateVecBinOpLocations(GetGraph()->GetAllocator(), instruction);
753 }
754 
VisitVecAndNot(HVecAndNot * instruction)755 void InstructionCodeGeneratorMIPS::VisitVecAndNot(HVecAndNot* instruction) {
756   LOG(FATAL) << "No SIMD for " << instruction->GetId();
757 }
758 
VisitVecOr(HVecOr * instruction)759 void LocationsBuilderMIPS::VisitVecOr(HVecOr* instruction) {
760   CreateVecBinOpLocations(GetGraph()->GetAllocator(), instruction);
761 }
762 
VisitVecOr(HVecOr * instruction)763 void InstructionCodeGeneratorMIPS::VisitVecOr(HVecOr* instruction) {
764   LocationSummary* locations = instruction->GetLocations();
765   VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
766   VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
767   VectorRegister dst = VectorRegisterFrom(locations->Out());
768   switch (instruction->GetPackedType()) {
769     case DataType::Type::kBool:
770     case DataType::Type::kUint8:
771     case DataType::Type::kInt8:
772     case DataType::Type::kUint16:
773     case DataType::Type::kInt16:
774     case DataType::Type::kInt32:
775     case DataType::Type::kInt64:
776     case DataType::Type::kFloat32:
777     case DataType::Type::kFloat64:
778       DCHECK_LE(2u, instruction->GetVectorLength());
779       DCHECK_LE(instruction->GetVectorLength(), 16u);
780       __ OrV(dst, lhs, rhs);  // lanes do not matter
781       break;
782     default:
783       LOG(FATAL) << "Unsupported SIMD type: " << instruction->GetPackedType();
784       UNREACHABLE();
785   }
786 }
787 
VisitVecXor(HVecXor * instruction)788 void LocationsBuilderMIPS::VisitVecXor(HVecXor* instruction) {
789   CreateVecBinOpLocations(GetGraph()->GetAllocator(), instruction);
790 }
791 
VisitVecXor(HVecXor * instruction)792 void InstructionCodeGeneratorMIPS::VisitVecXor(HVecXor* instruction) {
793   LocationSummary* locations = instruction->GetLocations();
794   VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
795   VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
796   VectorRegister dst = VectorRegisterFrom(locations->Out());
797   switch (instruction->GetPackedType()) {
798     case DataType::Type::kBool:
799     case DataType::Type::kUint8:
800     case DataType::Type::kInt8:
801     case DataType::Type::kUint16:
802     case DataType::Type::kInt16:
803     case DataType::Type::kInt32:
804     case DataType::Type::kInt64:
805     case DataType::Type::kFloat32:
806     case DataType::Type::kFloat64:
807       DCHECK_LE(2u, instruction->GetVectorLength());
808       DCHECK_LE(instruction->GetVectorLength(), 16u);
809       __ XorV(dst, lhs, rhs);  // lanes do not matter
810       break;
811     default:
812       LOG(FATAL) << "Unsupported SIMD type: " << instruction->GetPackedType();
813       UNREACHABLE();
814   }
815 }
816 
817 // Helper to set up locations for vector shift operations.
CreateVecShiftLocations(ArenaAllocator * allocator,HVecBinaryOperation * instruction)818 static void CreateVecShiftLocations(ArenaAllocator* allocator, HVecBinaryOperation* instruction) {
819   LocationSummary* locations = new (allocator) LocationSummary(instruction);
820   switch (instruction->GetPackedType()) {
821     case DataType::Type::kUint8:
822     case DataType::Type::kInt8:
823     case DataType::Type::kUint16:
824     case DataType::Type::kInt16:
825     case DataType::Type::kInt32:
826     case DataType::Type::kInt64:
827       locations->SetInAt(0, Location::RequiresFpuRegister());
828       locations->SetInAt(1, Location::ConstantLocation(instruction->InputAt(1)->AsConstant()));
829       locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
830       break;
831     default:
832       LOG(FATAL) << "Unsupported SIMD type: " << instruction->GetPackedType();
833       UNREACHABLE();
834   }
835 }
836 
VisitVecShl(HVecShl * instruction)837 void LocationsBuilderMIPS::VisitVecShl(HVecShl* instruction) {
838   CreateVecShiftLocations(GetGraph()->GetAllocator(), instruction);
839 }
840 
VisitVecShl(HVecShl * instruction)841 void InstructionCodeGeneratorMIPS::VisitVecShl(HVecShl* instruction) {
842   LocationSummary* locations = instruction->GetLocations();
843   VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
844   VectorRegister dst = VectorRegisterFrom(locations->Out());
845   int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
846   switch (instruction->GetPackedType()) {
847     case DataType::Type::kUint8:
848     case DataType::Type::kInt8:
849       DCHECK_EQ(16u, instruction->GetVectorLength());
850       __ SlliB(dst, lhs, value);
851       break;
852     case DataType::Type::kUint16:
853     case DataType::Type::kInt16:
854       DCHECK_EQ(8u, instruction->GetVectorLength());
855       __ SlliH(dst, lhs, value);
856       break;
857     case DataType::Type::kInt32:
858       DCHECK_EQ(4u, instruction->GetVectorLength());
859       __ SlliW(dst, lhs, value);
860       break;
861     case DataType::Type::kInt64:
862       DCHECK_EQ(2u, instruction->GetVectorLength());
863       __ SlliD(dst, lhs, value);
864       break;
865     default:
866       LOG(FATAL) << "Unsupported SIMD type: " << instruction->GetPackedType();
867       UNREACHABLE();
868   }
869 }
870 
VisitVecShr(HVecShr * instruction)871 void LocationsBuilderMIPS::VisitVecShr(HVecShr* instruction) {
872   CreateVecShiftLocations(GetGraph()->GetAllocator(), instruction);
873 }
874 
VisitVecShr(HVecShr * instruction)875 void InstructionCodeGeneratorMIPS::VisitVecShr(HVecShr* instruction) {
876   LocationSummary* locations = instruction->GetLocations();
877   VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
878   VectorRegister dst = VectorRegisterFrom(locations->Out());
879   int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
880   switch (instruction->GetPackedType()) {
881     case DataType::Type::kUint8:
882     case DataType::Type::kInt8:
883       DCHECK_EQ(16u, instruction->GetVectorLength());
884       __ SraiB(dst, lhs, value);
885       break;
886     case DataType::Type::kUint16:
887     case DataType::Type::kInt16:
888       DCHECK_EQ(8u, instruction->GetVectorLength());
889       __ SraiH(dst, lhs, value);
890       break;
891     case DataType::Type::kInt32:
892       DCHECK_EQ(4u, instruction->GetVectorLength());
893       __ SraiW(dst, lhs, value);
894       break;
895     case DataType::Type::kInt64:
896       DCHECK_EQ(2u, instruction->GetVectorLength());
897       __ SraiD(dst, lhs, value);
898       break;
899     default:
900       LOG(FATAL) << "Unsupported SIMD type: " << instruction->GetPackedType();
901       UNREACHABLE();
902   }
903 }
904 
VisitVecUShr(HVecUShr * instruction)905 void LocationsBuilderMIPS::VisitVecUShr(HVecUShr* instruction) {
906   CreateVecShiftLocations(GetGraph()->GetAllocator(), instruction);
907 }
908 
VisitVecUShr(HVecUShr * instruction)909 void InstructionCodeGeneratorMIPS::VisitVecUShr(HVecUShr* instruction) {
910   LocationSummary* locations = instruction->GetLocations();
911   VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
912   VectorRegister dst = VectorRegisterFrom(locations->Out());
913   int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
914   switch (instruction->GetPackedType()) {
915     case DataType::Type::kUint8:
916     case DataType::Type::kInt8:
917       DCHECK_EQ(16u, instruction->GetVectorLength());
918       __ SrliB(dst, lhs, value);
919       break;
920     case DataType::Type::kUint16:
921     case DataType::Type::kInt16:
922       DCHECK_EQ(8u, instruction->GetVectorLength());
923       __ SrliH(dst, lhs, value);
924       break;
925     case DataType::Type::kInt32:
926       DCHECK_EQ(4u, instruction->GetVectorLength());
927       __ SrliW(dst, lhs, value);
928       break;
929     case DataType::Type::kInt64:
930       DCHECK_EQ(2u, instruction->GetVectorLength());
931       __ SrliD(dst, lhs, value);
932       break;
933     default:
934       LOG(FATAL) << "Unsupported SIMD type: " << instruction->GetPackedType();
935       UNREACHABLE();
936   }
937 }
938 
VisitVecSetScalars(HVecSetScalars * instruction)939 void LocationsBuilderMIPS::VisitVecSetScalars(HVecSetScalars* instruction) {
940   LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(instruction);
941 
942   DCHECK_EQ(1u, instruction->InputCount());  // only one input currently implemented
943 
944   HInstruction* input = instruction->InputAt(0);
945   bool is_zero = IsZeroBitPattern(input);
946 
947   switch (instruction->GetPackedType()) {
948     case DataType::Type::kBool:
949     case DataType::Type::kUint8:
950     case DataType::Type::kInt8:
951     case DataType::Type::kUint16:
952     case DataType::Type::kInt16:
953     case DataType::Type::kInt32:
954     case DataType::Type::kInt64:
955       locations->SetInAt(0, is_zero ? Location::ConstantLocation(input->AsConstant())
956                                     : Location::RequiresRegister());
957       locations->SetOut(Location::RequiresFpuRegister());
958       break;
959     case DataType::Type::kFloat32:
960     case DataType::Type::kFloat64:
961       locations->SetInAt(0, is_zero ? Location::ConstantLocation(input->AsConstant())
962                                     : Location::RequiresFpuRegister());
963       locations->SetOut(Location::RequiresFpuRegister());
964       break;
965     default:
966       LOG(FATAL) << "Unsupported SIMD type: " << instruction->GetPackedType();
967       UNREACHABLE();
968   }
969 }
970 
VisitVecSetScalars(HVecSetScalars * instruction)971 void InstructionCodeGeneratorMIPS::VisitVecSetScalars(HVecSetScalars* instruction) {
972   LocationSummary* locations = instruction->GetLocations();
973   VectorRegister dst = VectorRegisterFrom(locations->Out());
974 
975   DCHECK_EQ(1u, instruction->InputCount());  // only one input currently implemented
976 
977   // Zero out all other elements first.
978   __ FillW(dst, ZERO);
979 
980   // Shorthand for any type of zero.
981   if (IsZeroBitPattern(instruction->InputAt(0))) {
982     return;
983   }
984 
985   // Set required elements.
986   switch (instruction->GetPackedType()) {
987     case DataType::Type::kBool:
988     case DataType::Type::kUint8:
989     case DataType::Type::kInt8:
990       DCHECK_EQ(16u, instruction->GetVectorLength());
991       __ InsertB(dst, locations->InAt(0).AsRegister<Register>(), 0);
992       break;
993     case DataType::Type::kUint16:
994     case DataType::Type::kInt16:
995       DCHECK_EQ(8u, instruction->GetVectorLength());
996       __ InsertH(dst, locations->InAt(0).AsRegister<Register>(), 0);
997       break;
998     case DataType::Type::kInt32:
999       DCHECK_EQ(4u, instruction->GetVectorLength());
1000       __ InsertW(dst, locations->InAt(0).AsRegister<Register>(), 0);
1001       break;
1002     case DataType::Type::kInt64:
1003       DCHECK_EQ(2u, instruction->GetVectorLength());
1004       __ InsertW(dst, locations->InAt(0).AsRegisterPairLow<Register>(), 0);
1005       __ InsertW(dst, locations->InAt(0).AsRegisterPairHigh<Register>(), 1);
1006       break;
1007     default:
1008       LOG(FATAL) << "Unsupported SIMD type: " << instruction->GetPackedType();
1009       UNREACHABLE();
1010   }
1011 }
1012 
1013 // Helper to set up locations for vector accumulations.
CreateVecAccumLocations(ArenaAllocator * allocator,HVecOperation * instruction)1014 static void CreateVecAccumLocations(ArenaAllocator* allocator, HVecOperation* instruction) {
1015   LocationSummary* locations = new (allocator) LocationSummary(instruction);
1016   switch (instruction->GetPackedType()) {
1017     case DataType::Type::kUint8:
1018     case DataType::Type::kInt8:
1019     case DataType::Type::kUint16:
1020     case DataType::Type::kInt16:
1021     case DataType::Type::kInt32:
1022     case DataType::Type::kInt64:
1023       locations->SetInAt(0, Location::RequiresFpuRegister());
1024       locations->SetInAt(1, Location::RequiresFpuRegister());
1025       locations->SetInAt(2, Location::RequiresFpuRegister());
1026       locations->SetOut(Location::SameAsFirstInput());
1027       break;
1028     default:
1029       LOG(FATAL) << "Unsupported SIMD type: " << instruction->GetPackedType();
1030       UNREACHABLE();
1031   }
1032 }
1033 
VisitVecMultiplyAccumulate(HVecMultiplyAccumulate * instruction)1034 void LocationsBuilderMIPS::VisitVecMultiplyAccumulate(HVecMultiplyAccumulate* instruction) {
1035   CreateVecAccumLocations(GetGraph()->GetAllocator(), instruction);
1036 }
1037 
VisitVecMultiplyAccumulate(HVecMultiplyAccumulate * instruction)1038 void InstructionCodeGeneratorMIPS::VisitVecMultiplyAccumulate(HVecMultiplyAccumulate* instruction) {
1039   LocationSummary* locations = instruction->GetLocations();
1040   VectorRegister acc = VectorRegisterFrom(locations->InAt(0));
1041   VectorRegister left = VectorRegisterFrom(locations->InAt(1));
1042   VectorRegister right = VectorRegisterFrom(locations->InAt(2));
1043   switch (instruction->GetPackedType()) {
1044     case DataType::Type::kUint8:
1045     case DataType::Type::kInt8:
1046       DCHECK_EQ(16u, instruction->GetVectorLength());
1047       if (instruction->GetOpKind() == HInstruction::kAdd) {
1048         __ MaddvB(acc, left, right);
1049       } else {
1050         __ MsubvB(acc, left, right);
1051       }
1052       break;
1053     case DataType::Type::kUint16:
1054     case DataType::Type::kInt16:
1055       DCHECK_EQ(8u, instruction->GetVectorLength());
1056       if (instruction->GetOpKind() == HInstruction::kAdd) {
1057         __ MaddvH(acc, left, right);
1058       } else {
1059         __ MsubvH(acc, left, right);
1060       }
1061       break;
1062     case DataType::Type::kInt32:
1063       DCHECK_EQ(4u, instruction->GetVectorLength());
1064       if (instruction->GetOpKind() == HInstruction::kAdd) {
1065         __ MaddvW(acc, left, right);
1066       } else {
1067         __ MsubvW(acc, left, right);
1068       }
1069       break;
1070     case DataType::Type::kInt64:
1071       DCHECK_EQ(2u, instruction->GetVectorLength());
1072       if (instruction->GetOpKind() == HInstruction::kAdd) {
1073         __ MaddvD(acc, left, right);
1074       } else {
1075         __ MsubvD(acc, left, right);
1076       }
1077       break;
1078     default:
1079       LOG(FATAL) << "Unsupported SIMD type: " << instruction->GetPackedType();
1080       UNREACHABLE();
1081   }
1082 }
1083 
VisitVecSADAccumulate(HVecSADAccumulate * instruction)1084 void LocationsBuilderMIPS::VisitVecSADAccumulate(HVecSADAccumulate* instruction) {
1085   CreateVecAccumLocations(GetGraph()->GetAllocator(), instruction);
1086   LocationSummary* locations = instruction->GetLocations();
1087   // All conversions require at least one temporary register.
1088   locations->AddTemp(Location::RequiresFpuRegister());
1089   // Some conversions require a second temporary register.
1090   HVecOperation* a = instruction->InputAt(1)->AsVecOperation();
1091   HVecOperation* b = instruction->InputAt(2)->AsVecOperation();
1092   DCHECK_EQ(HVecOperation::ToSignedType(a->GetPackedType()),
1093             HVecOperation::ToSignedType(b->GetPackedType()));
1094   switch (a->GetPackedType()) {
1095     case DataType::Type::kInt32:
1096       if (instruction->GetPackedType() == DataType::Type::kInt32) {
1097         break;
1098       }
1099       FALLTHROUGH_INTENDED;
1100     case DataType::Type::kUint8:
1101     case DataType::Type::kInt8:
1102     case DataType::Type::kUint16:
1103     case DataType::Type::kInt16:
1104       locations->AddTemp(Location::RequiresFpuRegister());
1105       break;
1106     default:
1107       break;
1108   }
1109 }
1110 
VisitVecSADAccumulate(HVecSADAccumulate * instruction)1111 void InstructionCodeGeneratorMIPS::VisitVecSADAccumulate(HVecSADAccumulate* instruction) {
1112   LocationSummary* locations = instruction->GetLocations();
1113   VectorRegister acc = VectorRegisterFrom(locations->InAt(0));
1114   VectorRegister left = VectorRegisterFrom(locations->InAt(1));
1115   VectorRegister right = VectorRegisterFrom(locations->InAt(2));
1116   VectorRegister tmp = static_cast<VectorRegister>(FTMP);
1117   VectorRegister tmp1 = VectorRegisterFrom(locations->GetTemp(0));
1118 
1119   DCHECK(locations->InAt(0).Equals(locations->Out()));
1120 
1121   // Handle all feasible acc_T += sad(a_S, b_S) type combinations (T x S).
1122   HVecOperation* a = instruction->InputAt(1)->AsVecOperation();
1123   HVecOperation* b = instruction->InputAt(2)->AsVecOperation();
1124   DCHECK_EQ(HVecOperation::ToSignedType(a->GetPackedType()),
1125             HVecOperation::ToSignedType(b->GetPackedType()));
1126   switch (a->GetPackedType()) {
1127     case DataType::Type::kUint8:
1128     case DataType::Type::kInt8:
1129       DCHECK_EQ(16u, a->GetVectorLength());
1130       switch (instruction->GetPackedType()) {
1131         case DataType::Type::kUint16:
1132         case DataType::Type::kInt16: {
1133           DCHECK_EQ(8u, instruction->GetVectorLength());
1134           VectorRegister tmp2 = VectorRegisterFrom(locations->GetTemp(1));
1135           __ FillB(tmp, ZERO);
1136           __ Hadd_sH(tmp1, left, tmp);
1137           __ Hadd_sH(tmp2, right, tmp);
1138           __ Asub_sH(tmp1, tmp1, tmp2);
1139           __ AddvH(acc, acc, tmp1);
1140           __ Hadd_sH(tmp1, tmp, left);
1141           __ Hadd_sH(tmp2, tmp, right);
1142           __ Asub_sH(tmp1, tmp1, tmp2);
1143           __ AddvH(acc, acc, tmp1);
1144           break;
1145         }
1146         case DataType::Type::kInt32: {
1147           DCHECK_EQ(4u, 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           __ AddvW(acc, acc, tmp1);
1155           __ Hadd_sH(tmp1, tmp, left);
1156           __ Hadd_sH(tmp2, tmp, right);
1157           __ Asub_sH(tmp1, tmp1, tmp2);
1158           __ Hadd_sW(tmp1, tmp1, tmp1);
1159           __ AddvW(acc, acc, tmp1);
1160           break;
1161         }
1162         case DataType::Type::kInt64: {
1163           DCHECK_EQ(2u, instruction->GetVectorLength());
1164           VectorRegister tmp2 = VectorRegisterFrom(locations->GetTemp(1));
1165           __ FillB(tmp, ZERO);
1166           __ Hadd_sH(tmp1, left, tmp);
1167           __ Hadd_sH(tmp2, right, tmp);
1168           __ Asub_sH(tmp1, tmp1, tmp2);
1169           __ Hadd_sW(tmp1, tmp1, tmp1);
1170           __ Hadd_sD(tmp1, tmp1, tmp1);
1171           __ AddvD(acc, acc, tmp1);
1172           __ Hadd_sH(tmp1, tmp, left);
1173           __ Hadd_sH(tmp2, tmp, right);
1174           __ Asub_sH(tmp1, tmp1, tmp2);
1175           __ Hadd_sW(tmp1, tmp1, tmp1);
1176           __ Hadd_sD(tmp1, tmp1, tmp1);
1177           __ AddvD(acc, acc, tmp1);
1178           break;
1179         }
1180         default:
1181           LOG(FATAL) << "Unsupported SIMD type: " << instruction->GetPackedType();
1182           UNREACHABLE();
1183       }
1184       break;
1185     case DataType::Type::kUint16:
1186     case DataType::Type::kInt16:
1187       DCHECK_EQ(8u, a->GetVectorLength());
1188       switch (instruction->GetPackedType()) {
1189         case DataType::Type::kInt32: {
1190           DCHECK_EQ(4u, instruction->GetVectorLength());
1191           VectorRegister tmp2 = VectorRegisterFrom(locations->GetTemp(1));
1192           __ FillH(tmp, ZERO);
1193           __ Hadd_sW(tmp1, left, tmp);
1194           __ Hadd_sW(tmp2, right, tmp);
1195           __ Asub_sW(tmp1, tmp1, tmp2);
1196           __ AddvW(acc, acc, tmp1);
1197           __ Hadd_sW(tmp1, tmp, left);
1198           __ Hadd_sW(tmp2, tmp, right);
1199           __ Asub_sW(tmp1, tmp1, tmp2);
1200           __ AddvW(acc, acc, tmp1);
1201           break;
1202         }
1203         case DataType::Type::kInt64: {
1204           DCHECK_EQ(2u, instruction->GetVectorLength());
1205           VectorRegister tmp2 = VectorRegisterFrom(locations->GetTemp(1));
1206           __ FillH(tmp, ZERO);
1207           __ Hadd_sW(tmp1, left, tmp);
1208           __ Hadd_sW(tmp2, right, tmp);
1209           __ Asub_sW(tmp1, tmp1, tmp2);
1210           __ Hadd_sD(tmp1, tmp1, tmp1);
1211           __ AddvD(acc, acc, tmp1);
1212           __ Hadd_sW(tmp1, tmp, left);
1213           __ Hadd_sW(tmp2, tmp, right);
1214           __ Asub_sW(tmp1, tmp1, tmp2);
1215           __ Hadd_sD(tmp1, tmp1, tmp1);
1216           __ AddvD(acc, acc, tmp1);
1217           break;
1218         }
1219         default:
1220           LOG(FATAL) << "Unsupported SIMD type: " << instruction->GetPackedType();
1221           UNREACHABLE();
1222       }
1223       break;
1224     case DataType::Type::kInt32:
1225       DCHECK_EQ(4u, a->GetVectorLength());
1226       switch (instruction->GetPackedType()) {
1227         case DataType::Type::kInt32: {
1228           DCHECK_EQ(4u, instruction->GetVectorLength());
1229           __ FillW(tmp, ZERO);
1230           __ SubvW(tmp1, left, right);
1231           __ Add_aW(tmp1, tmp1, tmp);
1232           __ AddvW(acc, acc, tmp1);
1233           break;
1234         }
1235         case DataType::Type::kInt64: {
1236           DCHECK_EQ(2u, instruction->GetVectorLength());
1237           VectorRegister tmp2 = VectorRegisterFrom(locations->GetTemp(1));
1238           __ FillW(tmp, ZERO);
1239           __ Hadd_sD(tmp1, left, tmp);
1240           __ Hadd_sD(tmp2, right, tmp);
1241           __ Asub_sD(tmp1, tmp1, tmp2);
1242           __ AddvD(acc, acc, tmp1);
1243           __ Hadd_sD(tmp1, tmp, left);
1244           __ Hadd_sD(tmp2, tmp, right);
1245           __ Asub_sD(tmp1, tmp1, tmp2);
1246           __ AddvD(acc, acc, tmp1);
1247           break;
1248         }
1249         default:
1250           LOG(FATAL) << "Unsupported SIMD type: " << instruction->GetPackedType();
1251           UNREACHABLE();
1252       }
1253       break;
1254     case DataType::Type::kInt64: {
1255       DCHECK_EQ(2u, a->GetVectorLength());
1256       switch (instruction->GetPackedType()) {
1257         case DataType::Type::kInt64: {
1258           DCHECK_EQ(2u, instruction->GetVectorLength());
1259           __ FillW(tmp, ZERO);
1260           __ SubvD(tmp1, left, right);
1261           __ Add_aD(tmp1, tmp1, tmp);
1262           __ AddvD(acc, acc, tmp1);
1263           break;
1264         }
1265         default:
1266           LOG(FATAL) << "Unsupported SIMD type: " << instruction->GetPackedType();
1267           UNREACHABLE();
1268       }
1269       break;
1270     }
1271     default:
1272       LOG(FATAL) << "Unsupported SIMD type: " << instruction->GetPackedType();
1273       UNREACHABLE();
1274   }
1275 }
1276 
VisitVecDotProd(HVecDotProd * instruction)1277 void LocationsBuilderMIPS::VisitVecDotProd(HVecDotProd* instruction) {
1278   LOG(FATAL) << "No SIMD for " << instruction->GetId();
1279 }
1280 
VisitVecDotProd(HVecDotProd * instruction)1281 void InstructionCodeGeneratorMIPS::VisitVecDotProd(HVecDotProd* instruction) {
1282   LOG(FATAL) << "No SIMD for " << instruction->GetId();
1283 }
1284 
1285 // Helper to set up locations for vector memory operations.
CreateVecMemLocations(ArenaAllocator * allocator,HVecMemoryOperation * instruction,bool is_load)1286 static void CreateVecMemLocations(ArenaAllocator* allocator,
1287                                   HVecMemoryOperation* instruction,
1288                                   bool is_load) {
1289   LocationSummary* locations = new (allocator) LocationSummary(instruction);
1290   switch (instruction->GetPackedType()) {
1291     case DataType::Type::kBool:
1292     case DataType::Type::kUint8:
1293     case DataType::Type::kInt8:
1294     case DataType::Type::kUint16:
1295     case DataType::Type::kInt16:
1296     case DataType::Type::kInt32:
1297     case DataType::Type::kInt64:
1298     case DataType::Type::kFloat32:
1299     case DataType::Type::kFloat64:
1300       locations->SetInAt(0, Location::RequiresRegister());
1301       locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
1302       if (is_load) {
1303         locations->SetOut(Location::RequiresFpuRegister());
1304       } else {
1305         locations->SetInAt(2, Location::RequiresFpuRegister());
1306       }
1307       break;
1308     default:
1309       LOG(FATAL) << "Unsupported SIMD type: " << instruction->GetPackedType();
1310       UNREACHABLE();
1311   }
1312 }
1313 
1314 // Helper to prepare register and offset for vector memory operations. Returns the offset and sets
1315 // 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)1316 int32_t InstructionCodeGeneratorMIPS::VecAddress(LocationSummary* locations,
1317                                                  size_t size,
1318                                                  /* out */ Register* adjusted_base) {
1319   Register base = locations->InAt(0).AsRegister<Register>();
1320   Location index = locations->InAt(1);
1321   int scale = TIMES_1;
1322   switch (size) {
1323     case 2: scale = TIMES_2; break;
1324     case 4: scale = TIMES_4; break;
1325     case 8: scale = TIMES_8; break;
1326     default: break;
1327   }
1328   int32_t offset = mirror::Array::DataOffset(size).Int32Value();
1329 
1330   if (index.IsConstant()) {
1331     offset += index.GetConstant()->AsIntConstant()->GetValue() << scale;
1332     __ AdjustBaseOffsetAndElementSizeShift(base, offset, scale);
1333     *adjusted_base = base;
1334   } else {
1335     Register index_reg = index.AsRegister<Register>();
1336     if (scale != TIMES_1) {
1337       __ Lsa(AT, index_reg, base, scale);
1338     } else {
1339       __ Addu(AT, base, index_reg);
1340     }
1341     *adjusted_base = AT;
1342   }
1343   return offset;
1344 }
1345 
VisitVecLoad(HVecLoad * instruction)1346 void LocationsBuilderMIPS::VisitVecLoad(HVecLoad* instruction) {
1347   CreateVecMemLocations(GetGraph()->GetAllocator(), instruction, /* is_load= */ true);
1348 }
1349 
VisitVecLoad(HVecLoad * instruction)1350 void InstructionCodeGeneratorMIPS::VisitVecLoad(HVecLoad* instruction) {
1351   LocationSummary* locations = instruction->GetLocations();
1352   size_t size = DataType::Size(instruction->GetPackedType());
1353   VectorRegister reg = VectorRegisterFrom(locations->Out());
1354   Register base;
1355   int32_t offset = VecAddress(locations, size, &base);
1356   switch (instruction->GetPackedType()) {
1357     case DataType::Type::kBool:
1358     case DataType::Type::kUint8:
1359     case DataType::Type::kInt8:
1360       DCHECK_EQ(16u, instruction->GetVectorLength());
1361       __ LdB(reg, base, offset);
1362       break;
1363     case DataType::Type::kUint16:
1364     case DataType::Type::kInt16:
1365       // Loading 8-bytes (needed if dealing with compressed strings in StringCharAt) from unaligned
1366       // memory address may cause a trap to the kernel if the CPU doesn't directly support unaligned
1367       // loads and stores.
1368       // TODO: Implement support for StringCharAt.
1369       DCHECK(!instruction->IsStringCharAt());
1370       DCHECK_EQ(8u, instruction->GetVectorLength());
1371       __ LdH(reg, base, offset);
1372       break;
1373     case DataType::Type::kInt32:
1374     case DataType::Type::kFloat32:
1375       DCHECK_EQ(4u, instruction->GetVectorLength());
1376       __ LdW(reg, base, offset);
1377       break;
1378     case DataType::Type::kInt64:
1379     case DataType::Type::kFloat64:
1380       DCHECK_EQ(2u, instruction->GetVectorLength());
1381       __ LdD(reg, base, offset);
1382       break;
1383     default:
1384       LOG(FATAL) << "Unsupported SIMD type: " << instruction->GetPackedType();
1385       UNREACHABLE();
1386   }
1387 }
1388 
VisitVecStore(HVecStore * instruction)1389 void LocationsBuilderMIPS::VisitVecStore(HVecStore* instruction) {
1390   CreateVecMemLocations(GetGraph()->GetAllocator(), instruction, /* is_load= */ false);
1391 }
1392 
VisitVecStore(HVecStore * instruction)1393 void InstructionCodeGeneratorMIPS::VisitVecStore(HVecStore* instruction) {
1394   LocationSummary* locations = instruction->GetLocations();
1395   size_t size = DataType::Size(instruction->GetPackedType());
1396   VectorRegister reg = VectorRegisterFrom(locations->InAt(2));
1397   Register base;
1398   int32_t offset = VecAddress(locations, size, &base);
1399   switch (instruction->GetPackedType()) {
1400     case DataType::Type::kBool:
1401     case DataType::Type::kUint8:
1402     case DataType::Type::kInt8:
1403       DCHECK_EQ(16u, instruction->GetVectorLength());
1404       __ StB(reg, base, offset);
1405       break;
1406     case DataType::Type::kUint16:
1407     case DataType::Type::kInt16:
1408       DCHECK_EQ(8u, instruction->GetVectorLength());
1409       __ StH(reg, base, offset);
1410       break;
1411     case DataType::Type::kInt32:
1412     case DataType::Type::kFloat32:
1413       DCHECK_EQ(4u, instruction->GetVectorLength());
1414       __ StW(reg, base, offset);
1415       break;
1416     case DataType::Type::kInt64:
1417     case DataType::Type::kFloat64:
1418       DCHECK_EQ(2u, instruction->GetVectorLength());
1419       __ StD(reg, base, offset);
1420       break;
1421     default:
1422       LOG(FATAL) << "Unsupported SIMD type: " << instruction->GetPackedType();
1423       UNREACHABLE();
1424   }
1425 }
1426 
1427 #undef __
1428 
1429 }  // namespace mips
1430 }  // namespace art
1431