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