• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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