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