1//===- RISCVVIntrinsicUtils.cpp - RISC-V Vector Intrinsic Utils -*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "clang/Support/RISCVVIntrinsicUtils.h"
10#include "llvm/ADT/ArrayRef.h"
11#include "llvm/ADT/StringExtras.h"
12#include "llvm/ADT/Twine.h"
13#include "llvm/Support/ErrorHandling.h"
14#include "llvm/Support/raw_ostream.h"
15#include <optional>
16
17using namespace llvm;
18
19namespace clang {
20namespace RISCV {
21
22const PrototypeDescriptor PrototypeDescriptor::Mask = PrototypeDescriptor(
23 BaseTypeModifier::Vector, VectorTypeModifier::MaskVector);
24const PrototypeDescriptor PrototypeDescriptor::VL =
25 PrototypeDescriptor(BaseTypeModifier::SizeT);
26const PrototypeDescriptor PrototypeDescriptor::Vector =
27 PrototypeDescriptor(BaseTypeModifier::Vector);
28
29//===----------------------------------------------------------------------===//
30// Type implementation
31//===----------------------------------------------------------------------===//
32
33LMULType::LMULType(int NewLog2LMUL) {
34 // Check Log2LMUL is -3, -2, -1, 0, 1, 2, 3
35 assert(NewLog2LMUL <= 3 && NewLog2LMUL >= -3 && "Bad LMUL number!");
36 Log2LMUL = NewLog2LMUL;
37}
38
39std::string LMULType::str() const {
40 if (Log2LMUL < 0)
41 return "mf" + utostr(X: 1ULL << (-Log2LMUL));
42 return "m" + utostr(X: 1ULL << Log2LMUL);
43}
44
45VScaleVal LMULType::getScale(unsigned ElementBitwidth) const {
46 int Log2ScaleResult = 0;
47 switch (ElementBitwidth) {
48 default:
49 break;
50 case 8:
51 Log2ScaleResult = Log2LMUL + 3;
52 break;
53 case 16:
54 Log2ScaleResult = Log2LMUL + 2;
55 break;
56 case 32:
57 Log2ScaleResult = Log2LMUL + 1;
58 break;
59 case 64:
60 Log2ScaleResult = Log2LMUL;
61 break;
62 }
63 // Illegal vscale result would be less than 1
64 if (Log2ScaleResult < 0)
65 return std::nullopt;
66 return 1 << Log2ScaleResult;
67}
68
69void LMULType::MulLog2LMUL(int log2LMUL) { Log2LMUL += log2LMUL; }
70
71RVVType::RVVType(BasicType BT, int Log2LMUL,
72 const PrototypeDescriptor &prototype)
73 : BT(BT), LMUL(LMULType(Log2LMUL)) {
74 applyBasicType();
75 applyModifier(prototype);
76 Valid = verifyType();
77 if (Valid) {
78 initBuiltinStr();
79 initTypeStr();
80 if (isVector()) {
81 initClangBuiltinStr();
82 }
83 }
84}
85
86// clang-format off
87// boolean type are encoded the ratio of n (SEW/LMUL)
88// SEW/LMUL | 1 | 2 | 4 | 8 | 16 | 32 | 64
89// c type | vbool64_t | vbool32_t | vbool16_t | vbool8_t | vbool4_t | vbool2_t | vbool1_t
90// IR type | nxv1i1 | nxv2i1 | nxv4i1 | nxv8i1 | nxv16i1 | nxv32i1 | nxv64i1
91
92// type\lmul | 1/8 | 1/4 | 1/2 | 1 | 2 | 4 | 8
93// -------- |------ | -------- | ------- | ------- | -------- | -------- | --------
94// i64 | N/A | N/A | N/A | nxv1i64 | nxv2i64 | nxv4i64 | nxv8i64
95// i32 | N/A | N/A | nxv1i32 | nxv2i32 | nxv4i32 | nxv8i32 | nxv16i32
96// i16 | N/A | nxv1i16 | nxv2i16 | nxv4i16 | nxv8i16 | nxv16i16 | nxv32i16
97// i8 | nxv1i8 | nxv2i8 | nxv4i8 | nxv8i8 | nxv16i8 | nxv32i8 | nxv64i8
98// double | N/A | N/A | N/A | nxv1f64 | nxv2f64 | nxv4f64 | nxv8f64
99// float | N/A | N/A | nxv1f32 | nxv2f32 | nxv4f32 | nxv8f32 | nxv16f32
100// half | N/A | nxv1f16 | nxv2f16 | nxv4f16 | nxv8f16 | nxv16f16 | nxv32f16
101// bfloat16 | N/A | nxv1bf16 | nxv2bf16| nxv4bf16| nxv8bf16 | nxv16bf16| nxv32bf16
102// clang-format on
103
104bool RVVType::verifyType() const {
105 if (ScalarType == Invalid)
106 return false;
107 if (isScalar())
108 return true;
109 if (!Scale)
110 return false;
111 if (isFloat() && ElementBitwidth == 8)
112 return false;
113 if (isBFloat() && ElementBitwidth != 16)
114 return false;
115 if (IsTuple && (NF == 1 || NF > 8))
116 return false;
117 if (IsTuple && (1 << std::max(a: 0, b: LMUL.Log2LMUL)) * NF > 8)
118 return false;
119 unsigned V = *Scale;
120 switch (ElementBitwidth) {
121 case 1:
122 case 8:
123 // Check Scale is 1,2,4,8,16,32,64
124 return (V <= 64 && isPowerOf2_32(Value: V));
125 case 16:
126 // Check Scale is 1,2,4,8,16,32
127 return (V <= 32 && isPowerOf2_32(Value: V));
128 case 32:
129 // Check Scale is 1,2,4,8,16
130 return (V <= 16 && isPowerOf2_32(Value: V));
131 case 64:
132 // Check Scale is 1,2,4,8
133 return (V <= 8 && isPowerOf2_32(Value: V));
134 }
135 return false;
136}
137
138void RVVType::initBuiltinStr() {
139 assert(isValid() && "RVVType is invalid");
140 switch (ScalarType) {
141 case ScalarTypeKind::Void:
142 BuiltinStr = "v";
143 return;
144 case ScalarTypeKind::Size_t:
145 BuiltinStr = "z";
146 if (IsImmediate)
147 BuiltinStr = "I" + BuiltinStr;
148 if (IsPointer)
149 BuiltinStr += "*";
150 return;
151 case ScalarTypeKind::Ptrdiff_t:
152 BuiltinStr = "Y";
153 return;
154 case ScalarTypeKind::UnsignedLong:
155 BuiltinStr = "ULi";
156 return;
157 case ScalarTypeKind::SignedLong:
158 BuiltinStr = "Li";
159 return;
160 case ScalarTypeKind::Boolean:
161 assert(ElementBitwidth == 1);
162 BuiltinStr += "b";
163 break;
164 case ScalarTypeKind::SignedInteger:
165 case ScalarTypeKind::UnsignedInteger:
166 switch (ElementBitwidth) {
167 case 8:
168 BuiltinStr += "c";
169 break;
170 case 16:
171 BuiltinStr += "s";
172 break;
173 case 32:
174 BuiltinStr += "i";
175 break;
176 case 64:
177 BuiltinStr += "Wi";
178 break;
179 default:
180 llvm_unreachable("Unhandled ElementBitwidth!");
181 }
182 if (isSignedInteger())
183 BuiltinStr = "S" + BuiltinStr;
184 else
185 BuiltinStr = "U" + BuiltinStr;
186 break;
187 case ScalarTypeKind::Float:
188 switch (ElementBitwidth) {
189 case 16:
190 BuiltinStr += "x";
191 break;
192 case 32:
193 BuiltinStr += "f";
194 break;
195 case 64:
196 BuiltinStr += "d";
197 break;
198 default:
199 llvm_unreachable("Unhandled ElementBitwidth!");
200 }
201 break;
202 case ScalarTypeKind::BFloat:
203 BuiltinStr += "y";
204 break;
205 case ScalarTypeKind::FloatE4M3:
206 BuiltinStr += "a";
207 break;
208 case ScalarTypeKind::FloatE5M2:
209 BuiltinStr += "b";
210 break;
211 default:
212 llvm_unreachable("ScalarType is invalid!");
213 }
214 if (IsImmediate)
215 BuiltinStr = "I" + BuiltinStr;
216 if (isScalar()) {
217 if (IsConstant)
218 BuiltinStr += "C";
219 if (IsPointer)
220 BuiltinStr += "*";
221 return;
222 }
223 BuiltinStr = "q" + utostr(X: *Scale) + BuiltinStr;
224 // Pointer to vector types. Defined for segment load intrinsics.
225 // segment load intrinsics have pointer type arguments to store the loaded
226 // vector values.
227 if (IsPointer)
228 BuiltinStr += "*";
229
230 if (IsTuple)
231 BuiltinStr = "T" + utostr(X: NF) + BuiltinStr;
232}
233
234void RVVType::initClangBuiltinStr() {
235 assert(isValid() && "RVVType is invalid");
236 assert(isVector() && "Handle Vector type only");
237
238 ClangBuiltinStr = "__rvv_";
239 switch (ScalarType) {
240 case ScalarTypeKind::Boolean:
241 ClangBuiltinStr += "bool" + utostr(X: 64 / *Scale) + "_t";
242 return;
243 case ScalarTypeKind::Float:
244 ClangBuiltinStr += "float";
245 break;
246 case ScalarTypeKind::BFloat:
247 ClangBuiltinStr += "bfloat";
248 break;
249 case ScalarTypeKind::SignedInteger:
250 ClangBuiltinStr += "int";
251 break;
252 case ScalarTypeKind::UnsignedInteger:
253 ClangBuiltinStr += "uint";
254 break;
255 case ScalarTypeKind::FloatE4M3:
256 ClangBuiltinStr += "float8e4m3" + LMUL.str() + "_t";
257 return;
258 case ScalarTypeKind::FloatE5M2:
259 ClangBuiltinStr += "float8e5m2" + LMUL.str() + "_t";
260 return;
261 default:
262 llvm_unreachable("ScalarTypeKind is invalid");
263 }
264 ClangBuiltinStr += utostr(X: ElementBitwidth) + LMUL.str() +
265 (IsTuple ? "x" + utostr(X: NF) : "") + "_t";
266}
267
268void RVVType::initTypeStr() {
269 assert(isValid() && "RVVType is invalid");
270
271 if (IsConstant)
272 Str += "const ";
273
274 auto getTypeString = [&](StringRef TypeStr) {
275 if (isScalar())
276 return Twine(TypeStr + Twine(ElementBitwidth) + "_t").str();
277 return Twine("v" + TypeStr + Twine(ElementBitwidth) + LMUL.str() +
278 (IsTuple ? "x" + utostr(X: NF) : "") + "_t")
279 .str();
280 };
281
282 switch (ScalarType) {
283 case ScalarTypeKind::Void:
284 Str = "void";
285 return;
286 case ScalarTypeKind::Size_t:
287 Str = "size_t";
288 if (IsPointer)
289 Str += " *";
290 return;
291 case ScalarTypeKind::Ptrdiff_t:
292 Str = "ptrdiff_t";
293 return;
294 case ScalarTypeKind::UnsignedLong:
295 Str = "unsigned long";
296 return;
297 case ScalarTypeKind::SignedLong:
298 Str = "long";
299 return;
300 case ScalarTypeKind::Boolean:
301 if (isScalar())
302 Str += "bool";
303 else
304 // Vector bool is special case, the formulate is
305 // `vbool<N>_t = MVT::nxv<64/N>i1` ex. vbool16_t = MVT::4i1
306 Str += "vbool" + utostr(X: 64 / *Scale) + "_t";
307 break;
308 case ScalarTypeKind::Float:
309 if (isScalar()) {
310 if (ElementBitwidth == 64)
311 Str += "double";
312 else if (ElementBitwidth == 32)
313 Str += "float";
314 else if (ElementBitwidth == 16)
315 Str += "_Float16";
316 else
317 llvm_unreachable("Unhandled floating type.");
318 } else
319 Str += getTypeString("float");
320 break;
321 case ScalarTypeKind::BFloat:
322 if (isScalar()) {
323 if (ElementBitwidth == 16)
324 Str += "__bf16";
325 else
326 llvm_unreachable("Unhandled floating type.");
327 } else
328 Str += getTypeString("bfloat");
329 break;
330 case ScalarTypeKind::SignedInteger:
331 Str += getTypeString("int");
332 break;
333 case ScalarTypeKind::UnsignedInteger:
334 Str += getTypeString("uint");
335 break;
336 case ScalarTypeKind::FloatE4M3:
337 Str += "vfloat8e4m3" + LMUL.str() + "_t";
338 break;
339 case ScalarTypeKind::FloatE5M2:
340 Str += "vfloat8e5m2" + LMUL.str() + "_t";
341 break;
342 default:
343 llvm_unreachable("ScalarType is invalid!");
344 }
345 if (IsPointer)
346 Str += " *";
347}
348
349void RVVType::initShortStr() {
350 switch (ScalarType) {
351 case ScalarTypeKind::Boolean:
352 assert(isVector());
353 ShortStr = "b" + utostr(X: 64 / *Scale);
354 return;
355 case ScalarTypeKind::Float:
356 ShortStr = "f" + utostr(X: ElementBitwidth);
357 break;
358 case ScalarTypeKind::BFloat:
359 ShortStr = "bf" + utostr(X: ElementBitwidth);
360 break;
361 case ScalarTypeKind::SignedInteger:
362 ShortStr = "i" + utostr(X: ElementBitwidth);
363 break;
364 case ScalarTypeKind::UnsignedInteger:
365 ShortStr = "u" + utostr(X: ElementBitwidth);
366 break;
367 case ScalarTypeKind::FloatE4M3:
368 ShortStr = "f8e4m3";
369 break;
370 case ScalarTypeKind::FloatE5M2:
371 ShortStr = "f8e5m2";
372 break;
373 default:
374 llvm_unreachable("Unhandled case!");
375 }
376 if (isVector())
377 ShortStr += LMUL.str();
378 if (isTuple())
379 ShortStr += "x" + utostr(X: NF);
380}
381
382static VectorTypeModifier getTupleVTM(unsigned NF) {
383 assert(2 <= NF && NF <= 8 && "2 <= NF <= 8");
384 return static_cast<VectorTypeModifier>(
385 static_cast<uint8_t>(VectorTypeModifier::Tuple2) + (NF - 2));
386}
387
388void RVVType::applyBasicType() {
389 switch (BT) {
390 case BasicType::Int8:
391 ElementBitwidth = 8;
392 ScalarType = ScalarTypeKind::SignedInteger;
393 break;
394 case BasicType::Int16:
395 ElementBitwidth = 16;
396 ScalarType = ScalarTypeKind::SignedInteger;
397 break;
398 case BasicType::Int32:
399 ElementBitwidth = 32;
400 ScalarType = ScalarTypeKind::SignedInteger;
401 break;
402 case BasicType::Int64:
403 ElementBitwidth = 64;
404 ScalarType = ScalarTypeKind::SignedInteger;
405 break;
406 case BasicType::Float16:
407 ElementBitwidth = 16;
408 ScalarType = ScalarTypeKind::Float;
409 break;
410 case BasicType::Float32:
411 ElementBitwidth = 32;
412 ScalarType = ScalarTypeKind::Float;
413 break;
414 case BasicType::Float64:
415 ElementBitwidth = 64;
416 ScalarType = ScalarTypeKind::Float;
417 break;
418 case BasicType::BFloat16:
419 ElementBitwidth = 16;
420 ScalarType = ScalarTypeKind::BFloat;
421 break;
422 case BasicType::F8E4M3:
423 ElementBitwidth = 8;
424 ScalarType = ScalarTypeKind::FloatE4M3;
425 break;
426 case BasicType::F8E5M2:
427 ElementBitwidth = 8;
428 ScalarType = ScalarTypeKind::FloatE5M2;
429 break;
430 default:
431 llvm_unreachable("Unhandled type code!");
432 }
433 assert(ElementBitwidth != 0 && "Bad element bitwidth!");
434}
435
436std::optional<PrototypeDescriptor>
437PrototypeDescriptor::parsePrototypeDescriptor(
438 llvm::StringRef PrototypeDescriptorStr) {
439 PrototypeDescriptor PD;
440 BaseTypeModifier PT = BaseTypeModifier::Invalid;
441 VectorTypeModifier VTM = VectorTypeModifier::NoModifier;
442
443 if (PrototypeDescriptorStr.empty())
444 return PD;
445
446 // Handle base type modifier
447 auto PType = PrototypeDescriptorStr.back();
448 switch (PType) {
449 case 'e':
450 PT = BaseTypeModifier::Scalar;
451 break;
452 case 'v':
453 PT = BaseTypeModifier::Vector;
454 break;
455 case 'w':
456 PT = BaseTypeModifier::Vector;
457 VTM = VectorTypeModifier::Widening2XVector;
458 break;
459 case 'd':
460 PT = BaseTypeModifier::Vector;
461 VTM = VectorTypeModifier::DoubleLMULVector;
462 break;
463 case 'q':
464 PT = BaseTypeModifier::Vector;
465 VTM = VectorTypeModifier::Widening4XVector;
466 break;
467 case 'o':
468 PT = BaseTypeModifier::Vector;
469 VTM = VectorTypeModifier::Widening8XVector;
470 break;
471 case 'm':
472 PT = BaseTypeModifier::Vector;
473 VTM = VectorTypeModifier::MaskVector;
474 break;
475 case '0':
476 PT = BaseTypeModifier::Void;
477 break;
478 case 'z':
479 PT = BaseTypeModifier::SizeT;
480 break;
481 case 't':
482 PT = BaseTypeModifier::Ptrdiff;
483 break;
484 case 'u':
485 PT = BaseTypeModifier::UnsignedLong;
486 break;
487 case 'l':
488 PT = BaseTypeModifier::SignedLong;
489 break;
490 case 'f':
491 PT = BaseTypeModifier::Float32;
492 break;
493 default:
494 llvm_unreachable("Illegal primitive type transformers!");
495 }
496 PD.PT = PT;
497 PrototypeDescriptorStr = PrototypeDescriptorStr.drop_back();
498
499 // Compute the vector type transformers, it can only appear one time.
500 if (PrototypeDescriptorStr.starts_with(Prefix: "(")) {
501 assert(VTM == VectorTypeModifier::NoModifier &&
502 "VectorTypeModifier should only have one modifier");
503 size_t Idx = PrototypeDescriptorStr.find(C: ')');
504 assert(Idx != StringRef::npos);
505 StringRef ComplexType = PrototypeDescriptorStr.slice(Start: 1, End: Idx);
506 PrototypeDescriptorStr = PrototypeDescriptorStr.drop_front(N: Idx + 1);
507 assert(!PrototypeDescriptorStr.contains('(') &&
508 "Only allow one vector type modifier");
509
510 auto ComplexTT = ComplexType.split(Separator: ":");
511 if (ComplexTT.first == "Log2EEW") {
512 uint32_t Log2EEW;
513 if (ComplexTT.second.getAsInteger(Radix: 10, Result&: Log2EEW)) {
514 llvm_unreachable("Invalid Log2EEW value!");
515 return std::nullopt;
516 }
517 switch (Log2EEW) {
518 case 3:
519 VTM = VectorTypeModifier::Log2EEW3;
520 break;
521 case 4:
522 VTM = VectorTypeModifier::Log2EEW4;
523 break;
524 case 5:
525 VTM = VectorTypeModifier::Log2EEW5;
526 break;
527 case 6:
528 VTM = VectorTypeModifier::Log2EEW6;
529 break;
530 default:
531 llvm_unreachable("Invalid Log2EEW value, should be [3-6]");
532 return std::nullopt;
533 }
534 } else if (ComplexTT.first == "FixedSEW") {
535 uint32_t NewSEW;
536 if (ComplexTT.second.getAsInteger(Radix: 10, Result&: NewSEW)) {
537 llvm_unreachable("Invalid FixedSEW value!");
538 return std::nullopt;
539 }
540 switch (NewSEW) {
541 case 8:
542 VTM = VectorTypeModifier::FixedSEW8;
543 break;
544 case 16:
545 VTM = VectorTypeModifier::FixedSEW16;
546 break;
547 case 32:
548 VTM = VectorTypeModifier::FixedSEW32;
549 break;
550 case 64:
551 VTM = VectorTypeModifier::FixedSEW64;
552 break;
553 default:
554 llvm_unreachable("Invalid FixedSEW value, should be 8, 16, 32 or 64");
555 return std::nullopt;
556 }
557 } else if (ComplexTT.first == "LFixedLog2LMUL") {
558 int32_t Log2LMUL;
559 if (ComplexTT.second.getAsInteger(Radix: 10, Result&: Log2LMUL)) {
560 llvm_unreachable("Invalid LFixedLog2LMUL value!");
561 return std::nullopt;
562 }
563 switch (Log2LMUL) {
564 case -3:
565 VTM = VectorTypeModifier::LFixedLog2LMULN3;
566 break;
567 case -2:
568 VTM = VectorTypeModifier::LFixedLog2LMULN2;
569 break;
570 case -1:
571 VTM = VectorTypeModifier::LFixedLog2LMULN1;
572 break;
573 case 0:
574 VTM = VectorTypeModifier::LFixedLog2LMUL0;
575 break;
576 case 1:
577 VTM = VectorTypeModifier::LFixedLog2LMUL1;
578 break;
579 case 2:
580 VTM = VectorTypeModifier::LFixedLog2LMUL2;
581 break;
582 case 3:
583 VTM = VectorTypeModifier::LFixedLog2LMUL3;
584 break;
585 default:
586 llvm_unreachable("Invalid LFixedLog2LMUL value, should be [-3, 3]");
587 return std::nullopt;
588 }
589 } else if (ComplexTT.first == "SFixedLog2LMUL") {
590 int32_t Log2LMUL;
591 if (ComplexTT.second.getAsInteger(Radix: 10, Result&: Log2LMUL)) {
592 llvm_unreachable("Invalid SFixedLog2LMUL value!");
593 return std::nullopt;
594 }
595 switch (Log2LMUL) {
596 case -3:
597 VTM = VectorTypeModifier::SFixedLog2LMULN3;
598 break;
599 case -2:
600 VTM = VectorTypeModifier::SFixedLog2LMULN2;
601 break;
602 case -1:
603 VTM = VectorTypeModifier::SFixedLog2LMULN1;
604 break;
605 case 0:
606 VTM = VectorTypeModifier::SFixedLog2LMUL0;
607 break;
608 case 1:
609 VTM = VectorTypeModifier::SFixedLog2LMUL1;
610 break;
611 case 2:
612 VTM = VectorTypeModifier::SFixedLog2LMUL2;
613 break;
614 case 3:
615 VTM = VectorTypeModifier::SFixedLog2LMUL3;
616 break;
617 default:
618 llvm_unreachable("Invalid LFixedLog2LMUL value, should be [-3, 3]");
619 return std::nullopt;
620 }
621
622 } else if (ComplexTT.first == "SEFixedLog2LMUL") {
623 int32_t Log2LMUL;
624 if (ComplexTT.second.getAsInteger(Radix: 10, Result&: Log2LMUL)) {
625 llvm_unreachable("Invalid SEFixedLog2LMUL value!");
626 return std::nullopt;
627 }
628 switch (Log2LMUL) {
629 case -3:
630 VTM = VectorTypeModifier::SEFixedLog2LMULN3;
631 break;
632 case -2:
633 VTM = VectorTypeModifier::SEFixedLog2LMULN2;
634 break;
635 case -1:
636 VTM = VectorTypeModifier::SEFixedLog2LMULN1;
637 break;
638 case 0:
639 VTM = VectorTypeModifier::SEFixedLog2LMUL0;
640 break;
641 case 1:
642 VTM = VectorTypeModifier::SEFixedLog2LMUL1;
643 break;
644 case 2:
645 VTM = VectorTypeModifier::SEFixedLog2LMUL2;
646 break;
647 case 3:
648 VTM = VectorTypeModifier::SEFixedLog2LMUL3;
649 break;
650 default:
651 llvm_unreachable("Invalid LFixedLog2LMUL value, should be [-3, 3]");
652 return std::nullopt;
653 }
654 } else if (ComplexTT.first == "Tuple") {
655 unsigned NF = 0;
656 if (ComplexTT.second.getAsInteger(Radix: 10, Result&: NF)) {
657 llvm_unreachable("Invalid NF value!");
658 return std::nullopt;
659 }
660 VTM = getTupleVTM(NF);
661 } else {
662 llvm_unreachable("Illegal complex type transformers!");
663 }
664 }
665 PD.VTM = VTM;
666
667 // Compute the remain type transformers
668 TypeModifier TM = TypeModifier::NoModifier;
669 for (char I : PrototypeDescriptorStr) {
670 switch (I) {
671 case 'P':
672 if ((TM & TypeModifier::Const) == TypeModifier::Const)
673 llvm_unreachable("'P' transformer cannot be used after 'C'");
674 if ((TM & TypeModifier::Pointer) == TypeModifier::Pointer)
675 llvm_unreachable("'P' transformer cannot be used twice");
676 TM |= TypeModifier::Pointer;
677 break;
678 case 'C':
679 TM |= TypeModifier::Const;
680 break;
681 case 'K':
682 TM |= TypeModifier::Immediate;
683 break;
684 case 'U':
685 TM |= TypeModifier::UnsignedInteger;
686 break;
687 case 'I':
688 TM |= TypeModifier::SignedInteger;
689 break;
690 case 'F':
691 TM |= TypeModifier::Float;
692 break;
693 case 'Y':
694 TM |= TypeModifier::BFloat;
695 break;
696 case 'S':
697 TM |= TypeModifier::LMUL1;
698 break;
699 case 'A':
700 TM |= TypeModifier::AltFP8;
701 break;
702 default:
703 llvm_unreachable("Illegal non-primitive type transformer!");
704 }
705 }
706 PD.TM = TM;
707
708 return PD;
709}
710
711void RVVType::applyModifier(const PrototypeDescriptor &Transformer) {
712 // Handle primitive type transformer
713 switch (static_cast<BaseTypeModifier>(Transformer.PT)) {
714 case BaseTypeModifier::Scalar:
715 Scale = 0;
716 break;
717 case BaseTypeModifier::Vector:
718 Scale = LMUL.getScale(ElementBitwidth);
719 break;
720 case BaseTypeModifier::Void:
721 ScalarType = ScalarTypeKind::Void;
722 break;
723 case BaseTypeModifier::SizeT:
724 ScalarType = ScalarTypeKind::Size_t;
725 break;
726 case BaseTypeModifier::Ptrdiff:
727 ScalarType = ScalarTypeKind::Ptrdiff_t;
728 break;
729 case BaseTypeModifier::UnsignedLong:
730 ScalarType = ScalarTypeKind::UnsignedLong;
731 break;
732 case BaseTypeModifier::SignedLong:
733 ScalarType = ScalarTypeKind::SignedLong;
734 break;
735 case BaseTypeModifier::Float32:
736 ElementBitwidth = 32;
737 ScalarType = ScalarTypeKind::Float;
738 break;
739 case BaseTypeModifier::Invalid:
740 ScalarType = ScalarTypeKind::Invalid;
741 return;
742 }
743
744 switch (static_cast<VectorTypeModifier>(Transformer.VTM)) {
745 case VectorTypeModifier::Widening2XVector:
746 ElementBitwidth *= 2;
747 LMUL.MulLog2LMUL(log2LMUL: 1);
748 Scale = LMUL.getScale(ElementBitwidth);
749 if (ScalarType == ScalarTypeKind::BFloat)
750 ScalarType = ScalarTypeKind::Float;
751 if (ScalarType == ScalarTypeKind::FloatE4M3 ||
752 ScalarType == ScalarTypeKind::FloatE5M2)
753 ScalarType = ScalarTypeKind::BFloat;
754 break;
755 case VectorTypeModifier::DoubleLMULVector:
756 LMUL.MulLog2LMUL(log2LMUL: 1);
757 Scale = LMUL.getScale(ElementBitwidth);
758 break;
759 case VectorTypeModifier::Widening4XVector:
760 ElementBitwidth *= 4;
761 LMUL.MulLog2LMUL(log2LMUL: 2);
762 Scale = LMUL.getScale(ElementBitwidth);
763 if (ScalarType == ScalarTypeKind::FloatE4M3 ||
764 ScalarType == ScalarTypeKind::FloatE5M2)
765 ScalarType = ScalarTypeKind::Float;
766 break;
767 case VectorTypeModifier::Widening8XVector:
768 ElementBitwidth *= 8;
769 LMUL.MulLog2LMUL(log2LMUL: 3);
770 Scale = LMUL.getScale(ElementBitwidth);
771 break;
772 case VectorTypeModifier::MaskVector:
773 ScalarType = ScalarTypeKind::Boolean;
774 Scale = LMUL.getScale(ElementBitwidth);
775 ElementBitwidth = 1;
776 break;
777 case VectorTypeModifier::DoubleLMULMaskVector:
778 ScalarType = ScalarTypeKind::Boolean;
779 LMUL.MulLog2LMUL(log2LMUL: 1);
780 Scale = LMUL.getScale(ElementBitwidth);
781 ElementBitwidth = 1;
782 break;
783 case VectorTypeModifier::Log2EEW3:
784 applyLog2EEW(Log2EEW: 3);
785 break;
786 case VectorTypeModifier::Log2EEW4:
787 applyLog2EEW(Log2EEW: 4);
788 break;
789 case VectorTypeModifier::Log2EEW5:
790 applyLog2EEW(Log2EEW: 5);
791 break;
792 case VectorTypeModifier::Log2EEW6:
793 applyLog2EEW(Log2EEW: 6);
794 break;
795 case VectorTypeModifier::FixedSEW8:
796 applyFixedSEW(NewSEW: 8);
797 break;
798 case VectorTypeModifier::FixedSEW16:
799 applyFixedSEW(NewSEW: 16);
800 break;
801 case VectorTypeModifier::FixedSEW32:
802 applyFixedSEW(NewSEW: 32);
803 break;
804 case VectorTypeModifier::FixedSEW64:
805 applyFixedSEW(NewSEW: 64);
806 break;
807 case VectorTypeModifier::LFixedLog2LMULN3:
808 applyFixedLog2LMUL(Log2LMUL: -3, Type: FixedLMULType::LargerThan);
809 break;
810 case VectorTypeModifier::LFixedLog2LMULN2:
811 applyFixedLog2LMUL(Log2LMUL: -2, Type: FixedLMULType::LargerThan);
812 break;
813 case VectorTypeModifier::LFixedLog2LMULN1:
814 applyFixedLog2LMUL(Log2LMUL: -1, Type: FixedLMULType::LargerThan);
815 break;
816 case VectorTypeModifier::LFixedLog2LMUL0:
817 applyFixedLog2LMUL(Log2LMUL: 0, Type: FixedLMULType::LargerThan);
818 break;
819 case VectorTypeModifier::LFixedLog2LMUL1:
820 applyFixedLog2LMUL(Log2LMUL: 1, Type: FixedLMULType::LargerThan);
821 break;
822 case VectorTypeModifier::LFixedLog2LMUL2:
823 applyFixedLog2LMUL(Log2LMUL: 2, Type: FixedLMULType::LargerThan);
824 break;
825 case VectorTypeModifier::LFixedLog2LMUL3:
826 applyFixedLog2LMUL(Log2LMUL: 3, Type: FixedLMULType::LargerThan);
827 break;
828 case VectorTypeModifier::SFixedLog2LMULN3:
829 applyFixedLog2LMUL(Log2LMUL: -3, Type: FixedLMULType::SmallerThan);
830 break;
831 case VectorTypeModifier::SFixedLog2LMULN2:
832 applyFixedLog2LMUL(Log2LMUL: -2, Type: FixedLMULType::SmallerThan);
833 break;
834 case VectorTypeModifier::SFixedLog2LMULN1:
835 applyFixedLog2LMUL(Log2LMUL: -1, Type: FixedLMULType::SmallerThan);
836 break;
837 case VectorTypeModifier::SFixedLog2LMUL0:
838 applyFixedLog2LMUL(Log2LMUL: 0, Type: FixedLMULType::SmallerThan);
839 break;
840 case VectorTypeModifier::SFixedLog2LMUL1:
841 applyFixedLog2LMUL(Log2LMUL: 1, Type: FixedLMULType::SmallerThan);
842 break;
843 case VectorTypeModifier::SFixedLog2LMUL2:
844 applyFixedLog2LMUL(Log2LMUL: 2, Type: FixedLMULType::SmallerThan);
845 break;
846 case VectorTypeModifier::SFixedLog2LMUL3:
847 applyFixedLog2LMUL(Log2LMUL: 3, Type: FixedLMULType::SmallerThan);
848 break;
849 case VectorTypeModifier::SEFixedLog2LMULN3:
850 applyFixedLog2LMUL(Log2LMUL: -3, Type: FixedLMULType::SmallerOrEqual);
851 break;
852 case VectorTypeModifier::SEFixedLog2LMULN2:
853 applyFixedLog2LMUL(Log2LMUL: -2, Type: FixedLMULType::SmallerOrEqual);
854 break;
855 case VectorTypeModifier::SEFixedLog2LMULN1:
856 applyFixedLog2LMUL(Log2LMUL: -1, Type: FixedLMULType::SmallerOrEqual);
857 break;
858 case VectorTypeModifier::SEFixedLog2LMUL0:
859 applyFixedLog2LMUL(Log2LMUL: 0, Type: FixedLMULType::SmallerOrEqual);
860 break;
861 case VectorTypeModifier::SEFixedLog2LMUL1:
862 applyFixedLog2LMUL(Log2LMUL: 1, Type: FixedLMULType::SmallerOrEqual);
863 break;
864 case VectorTypeModifier::SEFixedLog2LMUL2:
865 applyFixedLog2LMUL(Log2LMUL: 2, Type: FixedLMULType::SmallerOrEqual);
866 break;
867 case VectorTypeModifier::SEFixedLog2LMUL3:
868 applyFixedLog2LMUL(Log2LMUL: 3, Type: FixedLMULType::SmallerOrEqual);
869 break;
870 case VectorTypeModifier::Tuple2:
871 case VectorTypeModifier::Tuple3:
872 case VectorTypeModifier::Tuple4:
873 case VectorTypeModifier::Tuple5:
874 case VectorTypeModifier::Tuple6:
875 case VectorTypeModifier::Tuple7:
876 case VectorTypeModifier::Tuple8: {
877 IsTuple = true;
878 NF = 2 + static_cast<uint8_t>(Transformer.VTM) -
879 static_cast<uint8_t>(VectorTypeModifier::Tuple2);
880 break;
881 }
882 case VectorTypeModifier::NoModifier:
883 break;
884 }
885
886 // Early return if the current type modifier is already invalid.
887 if (ScalarType == Invalid)
888 return;
889
890 for (unsigned TypeModifierMaskShift = 0;
891 TypeModifierMaskShift <= static_cast<unsigned>(TypeModifier::MaxOffset);
892 ++TypeModifierMaskShift) {
893 unsigned TypeModifierMask = 1 << TypeModifierMaskShift;
894 if ((static_cast<unsigned>(Transformer.TM) & TypeModifierMask) !=
895 TypeModifierMask)
896 continue;
897 switch (static_cast<TypeModifier>(TypeModifierMask)) {
898 case TypeModifier::Pointer:
899 IsPointer = true;
900 break;
901 case TypeModifier::Const:
902 IsConstant = true;
903 break;
904 case TypeModifier::Immediate:
905 IsImmediate = true;
906 IsConstant = true;
907 break;
908 case TypeModifier::UnsignedInteger:
909 ScalarType = ScalarTypeKind::UnsignedInteger;
910 break;
911 case TypeModifier::SignedInteger:
912 ScalarType = ScalarTypeKind::SignedInteger;
913 break;
914 case TypeModifier::Float:
915 ScalarType = ScalarTypeKind::Float;
916 break;
917 case TypeModifier::BFloat:
918 ScalarType = ScalarTypeKind::BFloat;
919 break;
920 case TypeModifier::LMUL1:
921 LMUL = LMULType(0);
922 // Update ElementBitwidth need to update Scale too.
923 Scale = LMUL.getScale(ElementBitwidth);
924 break;
925 case TypeModifier::AltFP8:
926 if (ScalarType == ScalarTypeKind::FloatE4M3)
927 ScalarType = ScalarTypeKind::FloatE5M2;
928 else if (ScalarType == ScalarTypeKind::FloatE5M2)
929 ScalarType = ScalarTypeKind::FloatE4M3;
930 else
931 llvm_unreachable("AltFP8 modifier requires an OFP8 base type");
932 break;
933 default:
934 llvm_unreachable("Unknown type modifier mask!");
935 }
936 }
937}
938
939void RVVType::applyLog2EEW(unsigned Log2EEW) {
940 // update new elmul = (eew/sew) * lmul
941 LMUL.MulLog2LMUL(log2LMUL: Log2EEW - Log2_32(Value: ElementBitwidth));
942 // update new eew
943 ElementBitwidth = 1 << Log2EEW;
944 ScalarType = ScalarTypeKind::SignedInteger;
945 Scale = LMUL.getScale(ElementBitwidth);
946}
947
948void RVVType::applyFixedSEW(unsigned NewSEW) {
949 // Set invalid type if src and dst SEW are same.
950 if (ElementBitwidth == NewSEW) {
951 ScalarType = ScalarTypeKind::Invalid;
952 return;
953 }
954 // Update new SEW
955 ElementBitwidth = NewSEW;
956 Scale = LMUL.getScale(ElementBitwidth);
957}
958
959void RVVType::applyFixedLog2LMUL(int Log2LMUL, enum FixedLMULType Type) {
960 switch (Type) {
961 case FixedLMULType::LargerThan:
962 if (Log2LMUL <= LMUL.Log2LMUL) {
963 ScalarType = ScalarTypeKind::Invalid;
964 return;
965 }
966 break;
967 case FixedLMULType::SmallerThan:
968 if (Log2LMUL >= LMUL.Log2LMUL) {
969 ScalarType = ScalarTypeKind::Invalid;
970 return;
971 }
972 break;
973 case FixedLMULType::SmallerOrEqual:
974 if (Log2LMUL > LMUL.Log2LMUL) {
975 ScalarType = ScalarTypeKind::Invalid;
976 return;
977 }
978 break;
979 }
980
981 // Update new LMUL
982 LMUL = LMULType(Log2LMUL);
983 Scale = LMUL.getScale(ElementBitwidth);
984}
985
986std::optional<RVVTypes>
987RVVTypeCache::computeTypes(BasicType BT, int Log2LMUL, unsigned NF,
988 ArrayRef<PrototypeDescriptor> Prototype) {
989 RVVTypes Types;
990 for (const PrototypeDescriptor &Proto : Prototype) {
991 auto T = computeType(BT, Log2LMUL, Proto);
992 if (!T)
993 return std::nullopt;
994 // Record legal type index
995 Types.push_back(x: *T);
996 }
997 return Types;
998}
999
1000// Compute the hash value of RVVType, used for cache the result of computeType.
1001static uint64_t computeRVVTypeHashValue(BasicType BT, int Log2LMUL,
1002 PrototypeDescriptor Proto) {
1003 // Layout of hash value:
1004 // 0 8 24 32 40 48
1005 // | Log2LMUL + 3 | BT | Proto.PT | Proto.TM | Proto.VTM |
1006 assert(Log2LMUL >= -3 && Log2LMUL <= 3);
1007 return (Log2LMUL + 3) | (static_cast<uint64_t>(BT) & 0xffff) << 8 |
1008 (static_cast<uint64_t>(Proto.PT) << 24) |
1009 (static_cast<uint64_t>(Proto.TM) << 32) |
1010 (static_cast<uint64_t>(Proto.VTM) << 40);
1011}
1012
1013std::optional<RVVTypePtr> RVVTypeCache::computeType(BasicType BT, int Log2LMUL,
1014 PrototypeDescriptor Proto) {
1015 uint64_t Idx = computeRVVTypeHashValue(BT, Log2LMUL, Proto);
1016 // Search first
1017 auto It = LegalTypes.find(x: Idx);
1018 if (It != LegalTypes.end())
1019 return &(It->second);
1020
1021 if (IllegalTypes.count(x: Idx))
1022 return std::nullopt;
1023
1024 // Compute type and record the result.
1025 RVVType T(BT, Log2LMUL, Proto);
1026 if (T.isValid()) {
1027 // Record legal type index and value.
1028 std::pair<std::unordered_map<uint64_t, RVVType>::iterator, bool>
1029 InsertResult = LegalTypes.insert(x: {Idx, T});
1030 return &(InsertResult.first->second);
1031 }
1032 // Record illegal type index.
1033 IllegalTypes.insert(x: Idx);
1034 return std::nullopt;
1035}
1036
1037//===----------------------------------------------------------------------===//
1038// RVVIntrinsic implementation
1039//===----------------------------------------------------------------------===//
1040RVVIntrinsic::RVVIntrinsic(
1041 StringRef NewName, StringRef Suffix, StringRef NewOverloadedName,
1042 StringRef OverloadedSuffix, StringRef IRName, bool IsMasked,
1043 bool HasMaskedOffOperand, bool HasVL, PolicyScheme Scheme,
1044 bool SupportOverloading, bool HasBuiltinAlias, StringRef ManualCodegen,
1045 const RVVTypes &OutInTypes, const std::vector<int64_t> &NewIntrinsicTypes,
1046 unsigned NF, bool HasSegInstSEW, Policy NewPolicyAttrs,
1047 bool HasFRMRoundModeOp, unsigned TWiden, bool AltFmt)
1048 : IRName(IRName), IsMasked(IsMasked),
1049 HasMaskedOffOperand(HasMaskedOffOperand), HasVL(HasVL), Scheme(Scheme),
1050 SupportOverloading(SupportOverloading), HasBuiltinAlias(HasBuiltinAlias),
1051 ManualCodegen(ManualCodegen.str()), NF(NF), HasSegInstSEW(HasSegInstSEW),
1052 PolicyAttrs(NewPolicyAttrs), TWiden(TWiden) {
1053
1054 // Init BuiltinName, Name and OverloadedName
1055 BuiltinName = NewName.str();
1056 Name = BuiltinName;
1057 if (NewOverloadedName.empty())
1058 OverloadedName = NewName.split(Separator: "_").first.str();
1059 else
1060 OverloadedName = NewOverloadedName.str();
1061 if (!Suffix.empty())
1062 Name += "_" + Suffix.str();
1063 if (!OverloadedSuffix.empty())
1064 OverloadedName += "_" + OverloadedSuffix.str();
1065
1066 updateNamesAndPolicy(IsMasked, HasPolicy: hasPolicy(), Name, BuiltinName, OverloadedName,
1067 PolicyAttrs, HasFRMRoundModeOp, AltFmt);
1068
1069 // Init OutputType and InputTypes
1070 OutputType = OutInTypes[0];
1071 InputTypes.assign(first: OutInTypes.begin() + 1, last: OutInTypes.end());
1072
1073 // IntrinsicTypes is unmasked TA version index. Need to update it
1074 // if there is merge operand (It is always in first operand).
1075 IntrinsicTypes = NewIntrinsicTypes;
1076 if ((IsMasked && hasMaskedOffOperand()) ||
1077 (!IsMasked && hasPassthruOperand())) {
1078 for (auto &I : IntrinsicTypes) {
1079 if (I >= 0)
1080 I += 1;
1081 }
1082 }
1083}
1084
1085std::string RVVIntrinsic::getBuiltinTypeStr() const {
1086 std::string S;
1087 S += OutputType->getBuiltinStr();
1088 for (const auto &T : InputTypes) {
1089 S += T->getBuiltinStr();
1090 }
1091 return S;
1092}
1093
1094std::string RVVIntrinsic::getSuffixStr(
1095 RVVTypeCache &TypeCache, BasicType Type, int Log2LMUL,
1096 llvm::ArrayRef<PrototypeDescriptor> PrototypeDescriptors) {
1097 SmallVector<std::string> SuffixStrs;
1098 for (auto PD : PrototypeDescriptors) {
1099 auto T = TypeCache.computeType(BT: Type, Log2LMUL, Proto: PD);
1100 SuffixStrs.push_back(Elt: (*T)->getShortStr());
1101 }
1102 return join(R&: SuffixStrs, Separator: "_");
1103}
1104
1105llvm::SmallVector<PrototypeDescriptor> RVVIntrinsic::computeBuiltinTypes(
1106 llvm::ArrayRef<PrototypeDescriptor> Prototype, bool IsMasked,
1107 bool HasMaskedOffOperand, bool MaskedPrototypeHasResultMask, bool HasVL,
1108 unsigned NF, PolicyScheme DefaultScheme, Policy PolicyAttrs, bool IsTuple) {
1109 SmallVector<PrototypeDescriptor> NewPrototype(Prototype);
1110 bool HasPassthruOp = DefaultScheme == PolicyScheme::HasPassthruOperand;
1111 if (IsMasked) {
1112 // If HasMaskedOffOperand, insert result type as first input operand if
1113 // need.
1114 if (HasMaskedOffOperand && !PolicyAttrs.isTAMAPolicy()) {
1115 if (NF == 1) {
1116 NewPrototype.insert(I: NewPrototype.begin() + 1, Elt: NewPrototype[0]);
1117 } else if (NF > 1) {
1118 if (IsTuple) {
1119 PrototypeDescriptor BasePtrOperand = Prototype[1];
1120 PrototypeDescriptor MaskoffType =
1121 PrototypeDescriptor(BaseTypeModifier::Vector, getTupleVTM(NF),
1122 BasePtrOperand.TM & ~TypeModifier::Pointer);
1123 NewPrototype.insert(I: NewPrototype.begin() + 1, Elt: MaskoffType);
1124 } else {
1125 // Convert
1126 // (void, op0 address, op1 address, ...)
1127 // to
1128 // (void, op0 address, op1 address, ..., maskedoff0, maskedoff1, ...)
1129 PrototypeDescriptor MaskoffType = NewPrototype[1];
1130 MaskoffType.TM &= ~TypeModifier::Pointer;
1131 NewPrototype.insert(I: NewPrototype.begin() + NF + 1, NumToInsert: NF, Elt: MaskoffType);
1132 }
1133 }
1134 }
1135 if (HasMaskedOffOperand && NF > 1) {
1136 // Convert
1137 // (void, op0 address, op1 address, ..., maskedoff0, maskedoff1, ...)
1138 // to
1139 // (void, op0 address, op1 address, ..., mask, maskedoff0, maskedoff1,
1140 // ...)
1141 if (IsTuple)
1142 NewPrototype.insert(I: NewPrototype.begin() + 1,
1143 Elt: PrototypeDescriptor::Mask);
1144 else
1145 NewPrototype.insert(I: NewPrototype.begin() + NF + 1,
1146 Elt: PrototypeDescriptor::Mask);
1147 } else {
1148 if (MaskedPrototypeHasResultMask)
1149 NewPrototype.insert(
1150 I: NewPrototype.begin() + 1,
1151 Elt: PrototypeDescriptor(BaseTypeModifier::Vector,
1152 VectorTypeModifier::DoubleLMULMaskVector));
1153 else
1154 NewPrototype.insert(I: NewPrototype.begin() + 1,
1155 Elt: PrototypeDescriptor::Mask);
1156 }
1157 } else {
1158 if (NF == 1) {
1159 if (PolicyAttrs.isTUPolicy() && HasPassthruOp)
1160 NewPrototype.insert(I: NewPrototype.begin(), Elt: NewPrototype[0]);
1161 } else if (PolicyAttrs.isTUPolicy() && HasPassthruOp) {
1162 if (IsTuple) {
1163 PrototypeDescriptor BasePtrOperand = Prototype[0];
1164 PrototypeDescriptor MaskoffType =
1165 PrototypeDescriptor(BaseTypeModifier::Vector, getTupleVTM(NF),
1166 BasePtrOperand.TM & ~TypeModifier::Pointer);
1167 NewPrototype.insert(I: NewPrototype.begin(), Elt: MaskoffType);
1168 } else {
1169 // NF > 1 cases for segment load operations.
1170 // Convert
1171 // (void, op0 address, op1 address, ...)
1172 // to
1173 // (void, op0 address, op1 address, maskedoff0, maskedoff1, ...)
1174 PrototypeDescriptor MaskoffType = Prototype[1];
1175 MaskoffType.TM &= ~TypeModifier::Pointer;
1176 NewPrototype.insert(I: NewPrototype.begin() + NF + 1, NumToInsert: NF, Elt: MaskoffType);
1177 }
1178 }
1179 }
1180
1181 // If HasVL, append PrototypeDescriptor:VL to last operand
1182 if (HasVL)
1183 NewPrototype.push_back(Elt: PrototypeDescriptor::VL);
1184
1185 return NewPrototype;
1186}
1187
1188llvm::SmallVector<Policy> RVVIntrinsic::getSupportedUnMaskedPolicies() {
1189 return {Policy(Policy::PolicyType::Undisturbed)}; // TU
1190}
1191
1192llvm::SmallVector<Policy>
1193RVVIntrinsic::getSupportedMaskedPolicies(bool HasTailPolicy,
1194 bool HasMaskPolicy) {
1195 if (HasTailPolicy && HasMaskPolicy)
1196 return {Policy(Policy::PolicyType::Undisturbed,
1197 Policy::PolicyType::Agnostic), // TUM
1198 Policy(Policy::PolicyType::Undisturbed,
1199 Policy::PolicyType::Undisturbed), // TUMU
1200 Policy(Policy::PolicyType::Agnostic,
1201 Policy::PolicyType::Undisturbed)}; // MU
1202 if (HasTailPolicy && !HasMaskPolicy)
1203 return {Policy(Policy::PolicyType::Undisturbed,
1204 Policy::PolicyType::Agnostic)}; // TU
1205 if (!HasTailPolicy && HasMaskPolicy)
1206 return {Policy(Policy::PolicyType::Agnostic,
1207 Policy::PolicyType::Undisturbed)}; // MU
1208 llvm_unreachable("An RVV instruction should not be without both tail policy "
1209 "and mask policy");
1210}
1211
1212void RVVIntrinsic::updateNamesAndPolicy(bool IsMasked, bool HasPolicy,
1213 std::string &Name,
1214 std::string &BuiltinName,
1215 std::string &OverloadedName,
1216 Policy &PolicyAttrs,
1217 bool HasFRMRoundModeOp, bool AltFmt) {
1218
1219 auto appendPolicySuffix = [&](const std::string &suffix) {
1220 Name += suffix;
1221 BuiltinName += suffix;
1222 OverloadedName += suffix;
1223 };
1224
1225 if (HasFRMRoundModeOp) {
1226 Name += "_rm";
1227 BuiltinName += "_rm";
1228 }
1229
1230 if (AltFmt)
1231 BuiltinName += "_alt";
1232
1233 if (IsMasked) {
1234 if (PolicyAttrs.isTUMUPolicy())
1235 appendPolicySuffix("_tumu");
1236 else if (PolicyAttrs.isTUMAPolicy())
1237 appendPolicySuffix("_tum");
1238 else if (PolicyAttrs.isTAMUPolicy())
1239 appendPolicySuffix("_mu");
1240 else if (PolicyAttrs.isTAMAPolicy()) {
1241 Name += "_m";
1242 BuiltinName += "_m";
1243 } else
1244 llvm_unreachable("Unhandled policy condition");
1245 } else {
1246 if (PolicyAttrs.isTUPolicy())
1247 appendPolicySuffix("_tu");
1248 else if (PolicyAttrs.isTAPolicy()) // no suffix needed
1249 return;
1250 else
1251 llvm_unreachable("Unhandled policy condition");
1252 }
1253}
1254
1255SmallVector<PrototypeDescriptor> parsePrototypes(StringRef Prototypes) {
1256 SmallVector<PrototypeDescriptor> PrototypeDescriptors;
1257 const StringRef Primaries("evwdqom0ztulf");
1258 while (!Prototypes.empty()) {
1259 size_t Idx = 0;
1260 // Skip over complex prototype because it could contain primitive type
1261 // character.
1262 if (Prototypes[0] == '(')
1263 Idx = Prototypes.find_first_of(C: ')');
1264 Idx = Prototypes.find_first_of(Chars: Primaries, From: Idx);
1265 assert(Idx != StringRef::npos);
1266 auto PD = PrototypeDescriptor::parsePrototypeDescriptor(
1267 PrototypeDescriptorStr: Prototypes.slice(Start: 0, End: Idx + 1));
1268 if (!PD)
1269 llvm_unreachable("Error during parsing prototype.");
1270 PrototypeDescriptors.push_back(Elt: *PD);
1271 Prototypes = Prototypes.drop_front(N: Idx + 1);
1272 }
1273 return PrototypeDescriptors;
1274}
1275
1276#define STRINGIFY(NAME) \
1277 case NAME: \
1278 OS << #NAME; \
1279 break;
1280
1281llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, enum PolicyScheme PS) {
1282 switch (PS) {
1283 STRINGIFY(SchemeNone)
1284 STRINGIFY(HasPassthruOperand)
1285 STRINGIFY(HasPolicyOperand)
1286 }
1287 return OS;
1288}
1289
1290#undef STRINGIFY
1291
1292raw_ostream &operator<<(raw_ostream &OS, const RVVIntrinsicRecord &Record) {
1293 OS << "{";
1294 OS << "/*Name=*/\"" << Record.Name << "\", ";
1295 if (Record.OverloadedName == nullptr ||
1296 StringRef(Record.OverloadedName).empty())
1297 OS << "/*OverloadedName=*/nullptr, ";
1298 else
1299 OS << "/*OverloadedName=*/\"" << Record.OverloadedName << "\", ";
1300 OS << "/*RequiredExtensions=*/\"" << Record.RequiredExtensions << "\", ";
1301 OS << "/*PrototypeIndex=*/" << Record.PrototypeIndex << ", ";
1302 OS << "/*SuffixIndex=*/" << Record.SuffixIndex << ", ";
1303 OS << "/*OverloadedSuffixIndex=*/" << Record.OverloadedSuffixIndex << ", ";
1304 OS << "/*PrototypeLength=*/" << (int)Record.PrototypeLength << ", ";
1305 OS << "/*SuffixLength=*/" << (int)Record.SuffixLength << ", ";
1306 OS << "/*OverloadedSuffixSize=*/" << (int)Record.OverloadedSuffixSize << ", ";
1307 OS << "/*TypeRangeMask=*/" << (int)Record.TypeRangeMask << ", ";
1308 OS << "/*Log2LMULMask=*/" << (int)Record.Log2LMULMask << ", ";
1309 OS << "/*NF=*/" << (int)Record.NF << ", ";
1310 OS << "/*HasMasked=*/" << (int)Record.HasMasked << ", ";
1311 OS << "/*HasVL=*/" << (int)Record.HasVL << ", ";
1312 OS << "/*HasMaskedOffOperand=*/" << (int)Record.HasMaskedOffOperand << ", ";
1313 OS << "/*HasTailPolicy=*/" << (int)Record.HasTailPolicy << ", ";
1314 OS << "/*HasMaskPolicy=*/" << (int)Record.HasMaskPolicy << ", ";
1315 OS << "/*HasFRMRoundModeOp=*/" << (int)Record.HasFRMRoundModeOp << ", ";
1316 OS << "/*MaskedPrototypeHasResultMask=*/"
1317 << (int)Record.MaskedPrototypeHasResultMask << ", ";
1318 OS << "/*AltFmt=*/" << (int)Record.AltFmt << ",";
1319 OS << "/*IsTuple=*/" << (int)Record.IsTuple << ", ";
1320 OS << "/*UnMaskedPolicyScheme=*/" << (PolicyScheme)Record.UnMaskedPolicyScheme
1321 << ", ";
1322 OS << "/*MaskedPolicyScheme=*/" << (PolicyScheme)Record.MaskedPolicyScheme
1323 << ", ";
1324 OS << "},\n";
1325 return OS;
1326}
1327
1328} // end namespace RISCV
1329} // end namespace clang
1330