clang 22.0.0git
RISCVVIntrinsicUtils.cpp
Go to the documentation of this file.
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
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
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(1ULL << (-Log2LMUL));
42 return "m" + utostr(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(0, 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(V));
125 case 16:
126 // Check Scale is 1,2,4,8,16,32
127 return (V <= 32 && isPowerOf2_32(V));
128 case 32:
129 // Check Scale is 1,2,4,8,16
130 return (V <= 16 && isPowerOf2_32(V));
131 case 64:
132 // Check Scale is 1,2,4,8
133 return (V <= 8 && isPowerOf2_32(V));
134 }
135 return false;
136}
137
138void RVVType::initBuiltinStr() {
139 assert(isValid() && "RVVType is invalid");
140 switch (ScalarType) {
142 BuiltinStr = "v";
143 return;
145 BuiltinStr = "z";
146 if (IsImmediate)
147 BuiltinStr = "I" + BuiltinStr;
148 if (IsPointer)
149 BuiltinStr += "*";
150 return;
152 BuiltinStr = "Y";
153 return;
155 BuiltinStr = "ULi";
156 return;
158 BuiltinStr = "Li";
159 return;
161 assert(ElementBitwidth == 1);
162 BuiltinStr += "b";
163 break;
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;
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;
203 BuiltinStr += "y";
204 break;
205 default:
206 llvm_unreachable("ScalarType is invalid!");
207 }
208 if (IsImmediate)
209 BuiltinStr = "I" + BuiltinStr;
210 if (isScalar()) {
211 if (IsConstant)
212 BuiltinStr += "C";
213 if (IsPointer)
214 BuiltinStr += "*";
215 return;
216 }
217 BuiltinStr = "q" + utostr(*Scale) + BuiltinStr;
218 // Pointer to vector types. Defined for segment load intrinsics.
219 // segment load intrinsics have pointer type arguments to store the loaded
220 // vector values.
221 if (IsPointer)
222 BuiltinStr += "*";
223
224 if (IsTuple)
225 BuiltinStr = "T" + utostr(NF) + BuiltinStr;
226}
227
228void RVVType::initClangBuiltinStr() {
229 assert(isValid() && "RVVType is invalid");
230 assert(isVector() && "Handle Vector type only");
231
232 ClangBuiltinStr = "__rvv_";
233 switch (ScalarType) {
235 ClangBuiltinStr += "bool" + utostr(64 / *Scale) + "_t";
236 return;
238 ClangBuiltinStr += "float";
239 break;
241 ClangBuiltinStr += "bfloat";
242 break;
244 ClangBuiltinStr += "int";
245 break;
247 ClangBuiltinStr += "uint";
248 break;
249 default:
250 llvm_unreachable("ScalarTypeKind is invalid");
251 }
252 ClangBuiltinStr += utostr(ElementBitwidth) + LMUL.str() +
253 (IsTuple ? "x" + utostr(NF) : "") + "_t";
254}
255
256void RVVType::initTypeStr() {
257 assert(isValid() && "RVVType is invalid");
258
259 if (IsConstant)
260 Str += "const ";
261
262 auto getTypeString = [&](StringRef TypeStr) {
263 if (isScalar())
264 return Twine(TypeStr + Twine(ElementBitwidth) + "_t").str();
265 return Twine("v" + TypeStr + Twine(ElementBitwidth) + LMUL.str() +
266 (IsTuple ? "x" + utostr(NF) : "") + "_t")
267 .str();
268 };
269
270 switch (ScalarType) {
272 Str = "void";
273 return;
275 Str = "size_t";
276 if (IsPointer)
277 Str += " *";
278 return;
280 Str = "ptrdiff_t";
281 return;
283 Str = "unsigned long";
284 return;
286 Str = "long";
287 return;
289 if (isScalar())
290 Str += "bool";
291 else
292 // Vector bool is special case, the formulate is
293 // `vbool<N>_t = MVT::nxv<64/N>i1` ex. vbool16_t = MVT::4i1
294 Str += "vbool" + utostr(64 / *Scale) + "_t";
295 break;
297 if (isScalar()) {
298 if (ElementBitwidth == 64)
299 Str += "double";
300 else if (ElementBitwidth == 32)
301 Str += "float";
302 else if (ElementBitwidth == 16)
303 Str += "_Float16";
304 else
305 llvm_unreachable("Unhandled floating type.");
306 } else
307 Str += getTypeString("float");
308 break;
310 if (isScalar()) {
311 if (ElementBitwidth == 16)
312 Str += "__bf16";
313 else
314 llvm_unreachable("Unhandled floating type.");
315 } else
316 Str += getTypeString("bfloat");
317 break;
319 Str += getTypeString("int");
320 break;
322 Str += getTypeString("uint");
323 break;
324 default:
325 llvm_unreachable("ScalarType is invalid!");
326 }
327 if (IsPointer)
328 Str += " *";
329}
330
331void RVVType::initShortStr() {
332 switch (ScalarType) {
334 assert(isVector());
335 ShortStr = "b" + utostr(64 / *Scale);
336 return;
338 ShortStr = "f" + utostr(ElementBitwidth);
339 break;
341 ShortStr = "bf" + utostr(ElementBitwidth);
342 break;
344 ShortStr = "i" + utostr(ElementBitwidth);
345 break;
347 ShortStr = "u" + utostr(ElementBitwidth);
348 break;
349 default:
350 llvm_unreachable("Unhandled case!");
351 }
352 if (isVector())
353 ShortStr += LMUL.str();
354 if (isTuple())
355 ShortStr += "x" + utostr(NF);
356}
357
358static VectorTypeModifier getTupleVTM(unsigned NF) {
359 assert(2 <= NF && NF <= 8 && "2 <= NF <= 8");
360 return static_cast<VectorTypeModifier>(
361 static_cast<uint8_t>(VectorTypeModifier::Tuple2) + (NF - 2));
362}
363
364void RVVType::applyBasicType() {
365 switch (BT) {
366 case BasicType::Int8:
367 ElementBitwidth = 8;
369 break;
370 case BasicType::Int16:
371 ElementBitwidth = 16;
373 break;
374 case BasicType::Int32:
375 ElementBitwidth = 32;
377 break;
378 case BasicType::Int64:
379 ElementBitwidth = 64;
381 break;
383 ElementBitwidth = 16;
384 ScalarType = ScalarTypeKind::Float;
385 break;
387 ElementBitwidth = 32;
388 ScalarType = ScalarTypeKind::Float;
389 break;
391 ElementBitwidth = 64;
392 ScalarType = ScalarTypeKind::Float;
393 break;
395 ElementBitwidth = 16;
396 ScalarType = ScalarTypeKind::BFloat;
397 break;
398 default:
399 llvm_unreachable("Unhandled type code!");
400 }
401 assert(ElementBitwidth != 0 && "Bad element bitwidth!");
402}
403
404std::optional<PrototypeDescriptor>
406 llvm::StringRef PrototypeDescriptorStr) {
410
411 if (PrototypeDescriptorStr.empty())
412 return PD;
413
414 // Handle base type modifier
415 auto PType = PrototypeDescriptorStr.back();
416 switch (PType) {
417 case 'e':
419 break;
420 case 'v':
422 break;
423 case 'w':
426 break;
427 case 'q':
430 break;
431 case 'o':
434 break;
435 case 'm':
438 break;
439 case '0':
441 break;
442 case 'z':
444 break;
445 case 't':
447 break;
448 case 'u':
450 break;
451 case 'l':
453 break;
454 case 'f':
456 break;
457 default:
458 llvm_unreachable("Illegal primitive type transformers!");
459 }
460 PD.PT = static_cast<uint8_t>(PT);
461 PrototypeDescriptorStr = PrototypeDescriptorStr.drop_back();
462
463 // Compute the vector type transformers, it can only appear one time.
464 if (PrototypeDescriptorStr.starts_with("(")) {
466 "VectorTypeModifier should only have one modifier");
467 size_t Idx = PrototypeDescriptorStr.find(')');
468 assert(Idx != StringRef::npos);
469 StringRef ComplexType = PrototypeDescriptorStr.slice(1, Idx);
470 PrototypeDescriptorStr = PrototypeDescriptorStr.drop_front(Idx + 1);
471 assert(!PrototypeDescriptorStr.contains('(') &&
472 "Only allow one vector type modifier");
473
474 auto ComplexTT = ComplexType.split(":");
475 if (ComplexTT.first == "Log2EEW") {
476 uint32_t Log2EEW;
477 if (ComplexTT.second.getAsInteger(10, Log2EEW)) {
478 llvm_unreachable("Invalid Log2EEW value!");
479 return std::nullopt;
480 }
481 switch (Log2EEW) {
482 case 3:
484 break;
485 case 4:
487 break;
488 case 5:
490 break;
491 case 6:
493 break;
494 default:
495 llvm_unreachable("Invalid Log2EEW value, should be [3-6]");
496 return std::nullopt;
497 }
498 } else if (ComplexTT.first == "FixedSEW") {
499 uint32_t NewSEW;
500 if (ComplexTT.second.getAsInteger(10, NewSEW)) {
501 llvm_unreachable("Invalid FixedSEW value!");
502 return std::nullopt;
503 }
504 switch (NewSEW) {
505 case 8:
507 break;
508 case 16:
510 break;
511 case 32:
513 break;
514 case 64:
516 break;
517 default:
518 llvm_unreachable("Invalid FixedSEW value, should be 8, 16, 32 or 64");
519 return std::nullopt;
520 }
521 } else if (ComplexTT.first == "LFixedLog2LMUL") {
522 int32_t Log2LMUL;
523 if (ComplexTT.second.getAsInteger(10, Log2LMUL)) {
524 llvm_unreachable("Invalid LFixedLog2LMUL value!");
525 return std::nullopt;
526 }
527 switch (Log2LMUL) {
528 case -3:
530 break;
531 case -2:
533 break;
534 case -1:
536 break;
537 case 0:
539 break;
540 case 1:
542 break;
543 case 2:
545 break;
546 case 3:
548 break;
549 default:
550 llvm_unreachable("Invalid LFixedLog2LMUL value, should be [-3, 3]");
551 return std::nullopt;
552 }
553 } else if (ComplexTT.first == "SFixedLog2LMUL") {
554 int32_t Log2LMUL;
555 if (ComplexTT.second.getAsInteger(10, Log2LMUL)) {
556 llvm_unreachable("Invalid SFixedLog2LMUL value!");
557 return std::nullopt;
558 }
559 switch (Log2LMUL) {
560 case -3:
562 break;
563 case -2:
565 break;
566 case -1:
568 break;
569 case 0:
571 break;
572 case 1:
574 break;
575 case 2:
577 break;
578 case 3:
580 break;
581 default:
582 llvm_unreachable("Invalid LFixedLog2LMUL value, should be [-3, 3]");
583 return std::nullopt;
584 }
585
586 } else if (ComplexTT.first == "SEFixedLog2LMUL") {
587 int32_t Log2LMUL;
588 if (ComplexTT.second.getAsInteger(10, Log2LMUL)) {
589 llvm_unreachable("Invalid SEFixedLog2LMUL value!");
590 return std::nullopt;
591 }
592 switch (Log2LMUL) {
593 case -3:
595 break;
596 case -2:
598 break;
599 case -1:
601 break;
602 case 0:
604 break;
605 case 1:
607 break;
608 case 2:
610 break;
611 case 3:
613 break;
614 default:
615 llvm_unreachable("Invalid LFixedLog2LMUL value, should be [-3, 3]");
616 return std::nullopt;
617 }
618 } else if (ComplexTT.first == "Tuple") {
619 unsigned NF = 0;
620 if (ComplexTT.second.getAsInteger(10, NF)) {
621 llvm_unreachable("Invalid NF value!");
622 return std::nullopt;
623 }
624 VTM = getTupleVTM(NF);
625 } else {
626 llvm_unreachable("Illegal complex type transformers!");
627 }
628 }
629 PD.VTM = static_cast<uint8_t>(VTM);
630
631 // Compute the remain type transformers
633 for (char I : PrototypeDescriptorStr) {
634 switch (I) {
635 case 'P':
637 llvm_unreachable("'P' transformer cannot be used after 'C'");
639 llvm_unreachable("'P' transformer cannot be used twice");
641 break;
642 case 'C':
644 break;
645 case 'K':
647 break;
648 case 'U':
650 break;
651 case 'I':
653 break;
654 case 'F':
656 break;
657 case 'Y':
659 break;
660 case 'S':
662 break;
663 default:
664 llvm_unreachable("Illegal non-primitive type transformer!");
665 }
666 }
667 PD.TM = static_cast<uint8_t>(TM);
668
669 return PD;
670}
671
672void RVVType::applyModifier(const PrototypeDescriptor &Transformer) {
673 // Handle primitive type transformer
674 switch (static_cast<BaseTypeModifier>(Transformer.PT)) {
676 Scale = 0;
677 break;
679 Scale = LMUL.getScale(ElementBitwidth);
680 break;
682 ScalarType = ScalarTypeKind::Void;
683 break;
685 ScalarType = ScalarTypeKind::Size_t;
686 break;
688 ScalarType = ScalarTypeKind::Ptrdiff_t;
689 break;
691 ScalarType = ScalarTypeKind::UnsignedLong;
692 break;
694 ScalarType = ScalarTypeKind::SignedLong;
695 break;
697 ElementBitwidth = 32;
698 ScalarType = ScalarTypeKind::Float;
699 break;
701 ScalarType = ScalarTypeKind::Invalid;
702 return;
703 }
704
705 switch (static_cast<VectorTypeModifier>(Transformer.VTM)) {
707 ElementBitwidth *= 2;
708 LMUL.MulLog2LMUL(1);
709 Scale = LMUL.getScale(ElementBitwidth);
710 if (ScalarType == ScalarTypeKind::BFloat)
711 ScalarType = ScalarTypeKind::Float;
712 break;
714 ElementBitwidth *= 4;
715 LMUL.MulLog2LMUL(2);
716 Scale = LMUL.getScale(ElementBitwidth);
717 break;
719 ElementBitwidth *= 8;
720 LMUL.MulLog2LMUL(3);
721 Scale = LMUL.getScale(ElementBitwidth);
722 break;
724 ScalarType = ScalarTypeKind::Boolean;
725 Scale = LMUL.getScale(ElementBitwidth);
726 ElementBitwidth = 1;
727 break;
729 applyLog2EEW(3);
730 break;
732 applyLog2EEW(4);
733 break;
735 applyLog2EEW(5);
736 break;
738 applyLog2EEW(6);
739 break;
741 applyFixedSEW(8);
742 break;
744 applyFixedSEW(16);
745 break;
747 applyFixedSEW(32);
748 break;
750 applyFixedSEW(64);
751 break;
753 applyFixedLog2LMUL(-3, FixedLMULType::LargerThan);
754 break;
756 applyFixedLog2LMUL(-2, FixedLMULType::LargerThan);
757 break;
759 applyFixedLog2LMUL(-1, FixedLMULType::LargerThan);
760 break;
762 applyFixedLog2LMUL(0, FixedLMULType::LargerThan);
763 break;
765 applyFixedLog2LMUL(1, FixedLMULType::LargerThan);
766 break;
768 applyFixedLog2LMUL(2, FixedLMULType::LargerThan);
769 break;
771 applyFixedLog2LMUL(3, FixedLMULType::LargerThan);
772 break;
774 applyFixedLog2LMUL(-3, FixedLMULType::SmallerThan);
775 break;
777 applyFixedLog2LMUL(-2, FixedLMULType::SmallerThan);
778 break;
780 applyFixedLog2LMUL(-1, FixedLMULType::SmallerThan);
781 break;
783 applyFixedLog2LMUL(0, FixedLMULType::SmallerThan);
784 break;
786 applyFixedLog2LMUL(1, FixedLMULType::SmallerThan);
787 break;
789 applyFixedLog2LMUL(2, FixedLMULType::SmallerThan);
790 break;
792 applyFixedLog2LMUL(3, FixedLMULType::SmallerThan);
793 break;
795 applyFixedLog2LMUL(-3, FixedLMULType::SmallerOrEqual);
796 break;
798 applyFixedLog2LMUL(-2, FixedLMULType::SmallerOrEqual);
799 break;
801 applyFixedLog2LMUL(-1, FixedLMULType::SmallerOrEqual);
802 break;
804 applyFixedLog2LMUL(0, FixedLMULType::SmallerOrEqual);
805 break;
807 applyFixedLog2LMUL(1, FixedLMULType::SmallerOrEqual);
808 break;
810 applyFixedLog2LMUL(2, FixedLMULType::SmallerOrEqual);
811 break;
813 applyFixedLog2LMUL(3, FixedLMULType::SmallerOrEqual);
814 break;
822 IsTuple = true;
823 NF = 2 + static_cast<uint8_t>(Transformer.VTM) -
824 static_cast<uint8_t>(VectorTypeModifier::Tuple2);
825 break;
826 }
828 break;
829 }
830
831 // Early return if the current type modifier is already invalid.
832 if (ScalarType == Invalid)
833 return;
834
835 for (unsigned TypeModifierMaskShift = 0;
836 TypeModifierMaskShift <= static_cast<unsigned>(TypeModifier::MaxOffset);
837 ++TypeModifierMaskShift) {
838 unsigned TypeModifierMask = 1 << TypeModifierMaskShift;
839 if ((static_cast<unsigned>(Transformer.TM) & TypeModifierMask) !=
840 TypeModifierMask)
841 continue;
842 switch (static_cast<TypeModifier>(TypeModifierMask)) {
844 IsPointer = true;
845 break;
847 IsConstant = true;
848 break;
850 IsImmediate = true;
851 IsConstant = true;
852 break;
855 break;
858 break;
860 ScalarType = ScalarTypeKind::Float;
861 break;
863 ScalarType = ScalarTypeKind::BFloat;
864 break;
866 LMUL = LMULType(0);
867 // Update ElementBitwidth need to update Scale too.
868 Scale = LMUL.getScale(ElementBitwidth);
869 break;
870 default:
871 llvm_unreachable("Unknown type modifier mask!");
872 }
873 }
874}
875
876void RVVType::applyLog2EEW(unsigned Log2EEW) {
877 // update new elmul = (eew/sew) * lmul
878 LMUL.MulLog2LMUL(Log2EEW - Log2_32(ElementBitwidth));
879 // update new eew
880 ElementBitwidth = 1 << Log2EEW;
882 Scale = LMUL.getScale(ElementBitwidth);
883}
884
885void RVVType::applyFixedSEW(unsigned NewSEW) {
886 // Set invalid type if src and dst SEW are same.
887 if (ElementBitwidth == NewSEW) {
888 ScalarType = ScalarTypeKind::Invalid;
889 return;
890 }
891 // Update new SEW
892 ElementBitwidth = NewSEW;
893 Scale = LMUL.getScale(ElementBitwidth);
894}
895
896void RVVType::applyFixedLog2LMUL(int Log2LMUL, enum FixedLMULType Type) {
897 switch (Type) {
898 case FixedLMULType::LargerThan:
899 if (Log2LMUL <= LMUL.Log2LMUL) {
900 ScalarType = ScalarTypeKind::Invalid;
901 return;
902 }
903 break;
904 case FixedLMULType::SmallerThan:
905 if (Log2LMUL >= LMUL.Log2LMUL) {
906 ScalarType = ScalarTypeKind::Invalid;
907 return;
908 }
909 break;
910 case FixedLMULType::SmallerOrEqual:
911 if (Log2LMUL > LMUL.Log2LMUL) {
912 ScalarType = ScalarTypeKind::Invalid;
913 return;
914 }
915 break;
916 }
917
918 // Update new LMUL
919 LMUL = LMULType(Log2LMUL);
920 Scale = LMUL.getScale(ElementBitwidth);
921}
922
923std::optional<RVVTypes>
924RVVTypeCache::computeTypes(BasicType BT, int Log2LMUL, unsigned NF,
926 RVVTypes Types;
927 for (const PrototypeDescriptor &Proto : Prototype) {
928 auto T = computeType(BT, Log2LMUL, Proto);
929 if (!T)
930 return std::nullopt;
931 // Record legal type index
932 Types.push_back(*T);
933 }
934 return Types;
935}
936
937// Compute the hash value of RVVType, used for cache the result of computeType.
938static uint64_t computeRVVTypeHashValue(BasicType BT, int Log2LMUL,
939 PrototypeDescriptor Proto) {
940 // Layout of hash value:
941 // 0 8 16 24 32 40
942 // | Log2LMUL + 3 | BT | Proto.PT | Proto.TM | Proto.VTM |
943 assert(Log2LMUL >= -3 && Log2LMUL <= 3);
944 return (Log2LMUL + 3) | (static_cast<uint64_t>(BT) & 0xff) << 8 |
945 ((uint64_t)(Proto.PT & 0xff) << 16) |
946 ((uint64_t)(Proto.TM & 0xff) << 24) |
947 ((uint64_t)(Proto.VTM & 0xff) << 32);
948}
949
950std::optional<RVVTypePtr> RVVTypeCache::computeType(BasicType BT, int Log2LMUL,
951 PrototypeDescriptor Proto) {
952 uint64_t Idx = computeRVVTypeHashValue(BT, Log2LMUL, Proto);
953 // Search first
954 auto It = LegalTypes.find(Idx);
955 if (It != LegalTypes.end())
956 return &(It->second);
957
958 if (IllegalTypes.count(Idx))
959 return std::nullopt;
960
961 // Compute type and record the result.
962 RVVType T(BT, Log2LMUL, Proto);
963 if (T.isValid()) {
964 // Record legal type index and value.
965 std::pair<std::unordered_map<uint64_t, RVVType>::iterator, bool>
966 InsertResult = LegalTypes.insert({Idx, T});
967 return &(InsertResult.first->second);
968 }
969 // Record illegal type index.
970 IllegalTypes.insert(Idx);
971 return std::nullopt;
972}
973
974//===----------------------------------------------------------------------===//
975// RVVIntrinsic implementation
976//===----------------------------------------------------------------------===//
978 StringRef NewName, StringRef Suffix, StringRef NewOverloadedName,
979 StringRef OverloadedSuffix, StringRef IRName, bool IsMasked,
980 bool HasMaskedOffOperand, bool HasVL, PolicyScheme Scheme,
981 bool SupportOverloading, bool HasBuiltinAlias, StringRef ManualCodegen,
982 const RVVTypes &OutInTypes, const std::vector<int64_t> &NewIntrinsicTypes,
983 unsigned NF, Policy NewPolicyAttrs, bool HasFRMRoundModeOp, unsigned TWiden)
984 : IRName(IRName), IsMasked(IsMasked),
985 HasMaskedOffOperand(HasMaskedOffOperand), HasVL(HasVL), Scheme(Scheme),
986 SupportOverloading(SupportOverloading), HasBuiltinAlias(HasBuiltinAlias),
987 ManualCodegen(ManualCodegen.str()), NF(NF), PolicyAttrs(NewPolicyAttrs),
988 TWiden(TWiden) {
989
990 // Init BuiltinName, Name and OverloadedName
991 BuiltinName = NewName.str();
992 Name = BuiltinName;
993 if (NewOverloadedName.empty())
994 OverloadedName = NewName.split("_").first.str();
995 else
996 OverloadedName = NewOverloadedName.str();
997 if (!Suffix.empty())
998 Name += "_" + Suffix.str();
999 if (!OverloadedSuffix.empty())
1000 OverloadedName += "_" + OverloadedSuffix.str();
1001
1002 updateNamesAndPolicy(IsMasked, hasPolicy(), Name, BuiltinName, OverloadedName,
1003 PolicyAttrs, HasFRMRoundModeOp);
1004
1005 // Init OutputType and InputTypes
1006 OutputType = OutInTypes[0];
1007 InputTypes.assign(OutInTypes.begin() + 1, OutInTypes.end());
1008
1009 // IntrinsicTypes is unmasked TA version index. Need to update it
1010 // if there is merge operand (It is always in first operand).
1011 IntrinsicTypes = NewIntrinsicTypes;
1012 if ((IsMasked && hasMaskedOffOperand()) ||
1013 (!IsMasked && hasPassthruOperand())) {
1014 for (auto &I : IntrinsicTypes) {
1015 if (I >= 0)
1016 I += 1;
1017 }
1018 }
1019}
1020
1022 std::string S;
1023 S += OutputType->getBuiltinStr();
1024 for (const auto &T : InputTypes) {
1025 S += T->getBuiltinStr();
1026 }
1027 return S;
1028}
1029
1031 RVVTypeCache &TypeCache, BasicType Type, int Log2LMUL,
1032 llvm::ArrayRef<PrototypeDescriptor> PrototypeDescriptors) {
1033 SmallVector<std::string> SuffixStrs;
1034 for (auto PD : PrototypeDescriptors) {
1035 auto T = TypeCache.computeType(Type, Log2LMUL, PD);
1036 SuffixStrs.push_back((*T)->getShortStr());
1037 }
1038 return join(SuffixStrs, "_");
1039}
1040
1043 bool HasMaskedOffOperand, bool HasVL, unsigned NF,
1044 PolicyScheme DefaultScheme, Policy PolicyAttrs, bool IsTuple) {
1046 bool HasPassthruOp = DefaultScheme == PolicyScheme::HasPassthruOperand;
1047 if (IsMasked) {
1048 // If HasMaskedOffOperand, insert result type as first input operand if
1049 // need.
1050 if (HasMaskedOffOperand && !PolicyAttrs.isTAMAPolicy()) {
1051 if (NF == 1) {
1052 NewPrototype.insert(NewPrototype.begin() + 1, NewPrototype[0]);
1053 } else if (NF > 1) {
1054 if (IsTuple) {
1055 PrototypeDescriptor BasePtrOperand = Prototype[1];
1057 static_cast<uint8_t>(BaseTypeModifier::Vector),
1058 static_cast<uint8_t>(getTupleVTM(NF)),
1059 BasePtrOperand.TM & ~static_cast<uint8_t>(TypeModifier::Pointer));
1060 NewPrototype.insert(NewPrototype.begin() + 1, MaskoffType);
1061 } else {
1062 // Convert
1063 // (void, op0 address, op1 address, ...)
1064 // to
1065 // (void, op0 address, op1 address, ..., maskedoff0, maskedoff1, ...)
1066 PrototypeDescriptor MaskoffType = NewPrototype[1];
1067 MaskoffType.TM &= ~static_cast<uint8_t>(TypeModifier::Pointer);
1068 NewPrototype.insert(NewPrototype.begin() + NF + 1, NF, MaskoffType);
1069 }
1070 }
1071 }
1072 if (HasMaskedOffOperand && NF > 1) {
1073 // Convert
1074 // (void, op0 address, op1 address, ..., maskedoff0, maskedoff1, ...)
1075 // to
1076 // (void, op0 address, op1 address, ..., mask, maskedoff0, maskedoff1,
1077 // ...)
1078 if (IsTuple)
1079 NewPrototype.insert(NewPrototype.begin() + 1,
1081 else
1082 NewPrototype.insert(NewPrototype.begin() + NF + 1,
1084 } else {
1085 // If IsMasked, insert PrototypeDescriptor:Mask as first input operand.
1086 NewPrototype.insert(NewPrototype.begin() + 1, PrototypeDescriptor::Mask);
1087 }
1088 } else {
1089 if (NF == 1) {
1090 if (PolicyAttrs.isTUPolicy() && HasPassthruOp)
1091 NewPrototype.insert(NewPrototype.begin(), NewPrototype[0]);
1092 } else if (PolicyAttrs.isTUPolicy() && HasPassthruOp) {
1093 if (IsTuple) {
1094 PrototypeDescriptor BasePtrOperand = Prototype[0];
1096 static_cast<uint8_t>(BaseTypeModifier::Vector),
1097 static_cast<uint8_t>(getTupleVTM(NF)),
1098 BasePtrOperand.TM & ~static_cast<uint8_t>(TypeModifier::Pointer));
1099 NewPrototype.insert(NewPrototype.begin(), MaskoffType);
1100 } else {
1101 // NF > 1 cases for segment load operations.
1102 // Convert
1103 // (void, op0 address, op1 address, ...)
1104 // to
1105 // (void, op0 address, op1 address, maskedoff0, maskedoff1, ...)
1106 PrototypeDescriptor MaskoffType = Prototype[1];
1107 MaskoffType.TM &= ~static_cast<uint8_t>(TypeModifier::Pointer);
1108 NewPrototype.insert(NewPrototype.begin() + NF + 1, NF, MaskoffType);
1109 }
1110 }
1111 }
1112
1113 // If HasVL, append PrototypeDescriptor:VL to last operand
1114 if (HasVL)
1115 NewPrototype.push_back(PrototypeDescriptor::VL);
1116
1117 return NewPrototype;
1118}
1119
1123
1126 bool HasMaskPolicy) {
1127 if (HasTailPolicy && HasMaskPolicy)
1134 if (HasTailPolicy && !HasMaskPolicy)
1137 if (!HasTailPolicy && HasMaskPolicy)
1140 llvm_unreachable("An RVV instruction should not be without both tail policy "
1141 "and mask policy");
1142}
1143
1145 bool IsMasked, bool HasPolicy, std::string &Name, std::string &BuiltinName,
1146 std::string &OverloadedName, Policy &PolicyAttrs, bool HasFRMRoundModeOp) {
1147
1148 auto appendPolicySuffix = [&](const std::string &suffix) {
1149 Name += suffix;
1150 BuiltinName += suffix;
1151 OverloadedName += suffix;
1152 };
1153
1154 if (HasFRMRoundModeOp) {
1155 Name += "_rm";
1156 BuiltinName += "_rm";
1157 }
1158
1159 if (IsMasked) {
1160 if (PolicyAttrs.isTUMUPolicy())
1161 appendPolicySuffix("_tumu");
1162 else if (PolicyAttrs.isTUMAPolicy())
1163 appendPolicySuffix("_tum");
1164 else if (PolicyAttrs.isTAMUPolicy())
1165 appendPolicySuffix("_mu");
1166 else if (PolicyAttrs.isTAMAPolicy()) {
1167 Name += "_m";
1168 BuiltinName += "_m";
1169 } else
1170 llvm_unreachable("Unhandled policy condition");
1171 } else {
1172 if (PolicyAttrs.isTUPolicy())
1173 appendPolicySuffix("_tu");
1174 else if (PolicyAttrs.isTAPolicy()) // no suffix needed
1175 return;
1176 else
1177 llvm_unreachable("Unhandled policy condition");
1178 }
1179}
1180
1182 SmallVector<PrototypeDescriptor> PrototypeDescriptors;
1183 const StringRef Primaries("evwqom0ztulf");
1184 while (!Prototypes.empty()) {
1185 size_t Idx = 0;
1186 // Skip over complex prototype because it could contain primitive type
1187 // character.
1188 if (Prototypes[0] == '(')
1189 Idx = Prototypes.find_first_of(')');
1190 Idx = Prototypes.find_first_of(Primaries, Idx);
1191 assert(Idx != StringRef::npos);
1193 Prototypes.slice(0, Idx + 1));
1194 if (!PD)
1195 llvm_unreachable("Error during parsing prototype.");
1196 PrototypeDescriptors.push_back(*PD);
1197 Prototypes = Prototypes.drop_front(Idx + 1);
1198 }
1199 return PrototypeDescriptors;
1200}
1201
1202#define STRINGIFY(NAME) \
1203 case NAME: \
1204 OS << #NAME; \
1205 break;
1206
1207llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, enum PolicyScheme PS) {
1208 switch (PS) {
1212 }
1213 return OS;
1214}
1215
1216#undef STRINGIFY
1217
1218raw_ostream &operator<<(raw_ostream &OS, const RVVIntrinsicRecord &Record) {
1219 OS << "{";
1220 OS << "/*Name=*/\"" << Record.Name << "\", ";
1221 if (Record.OverloadedName == nullptr ||
1222 StringRef(Record.OverloadedName).empty())
1223 OS << "/*OverloadedName=*/nullptr, ";
1224 else
1225 OS << "/*OverloadedName=*/\"" << Record.OverloadedName << "\", ";
1226 OS << "/*RequiredExtensions=*/\"" << Record.RequiredExtensions << "\", ";
1227 OS << "/*PrototypeIndex=*/" << Record.PrototypeIndex << ", ";
1228 OS << "/*SuffixIndex=*/" << Record.SuffixIndex << ", ";
1229 OS << "/*OverloadedSuffixIndex=*/" << Record.OverloadedSuffixIndex << ", ";
1230 OS << "/*PrototypeLength=*/" << (int)Record.PrototypeLength << ", ";
1231 OS << "/*SuffixLength=*/" << (int)Record.SuffixLength << ", ";
1232 OS << "/*OverloadedSuffixSize=*/" << (int)Record.OverloadedSuffixSize << ", ";
1233 OS << "/*TypeRangeMask=*/" << (int)Record.TypeRangeMask << ", ";
1234 OS << "/*Log2LMULMask=*/" << (int)Record.Log2LMULMask << ", ";
1235 OS << "/*NF=*/" << (int)Record.NF << ", ";
1236 OS << "/*HasMasked=*/" << (int)Record.HasMasked << ", ";
1237 OS << "/*HasVL=*/" << (int)Record.HasVL << ", ";
1238 OS << "/*HasMaskedOffOperand=*/" << (int)Record.HasMaskedOffOperand << ", ";
1239 OS << "/*HasTailPolicy=*/" << (int)Record.HasTailPolicy << ", ";
1240 OS << "/*HasMaskPolicy=*/" << (int)Record.HasMaskPolicy << ", ";
1241 OS << "/*HasFRMRoundModeOp=*/" << (int)Record.HasFRMRoundModeOp << ", ";
1242 OS << "/*IsTuple=*/" << (int)Record.IsTuple << ", ";
1243 OS << "/*UnMaskedPolicyScheme=*/" << (PolicyScheme)Record.UnMaskedPolicyScheme
1244 << ", ";
1245 OS << "/*MaskedPolicyScheme=*/" << (PolicyScheme)Record.MaskedPolicyScheme
1246 << ", ";
1247 OS << "},\n";
1248 return OS;
1249}
1250
1251} // end namespace RISCV
1252} // end namespace clang
#define V(N, I)
static bool getTypeString(SmallStringEnc &Enc, const Decl *D, const CodeGen::CodeGenModule &CGM, TypeStringCache &TSC)
The XCore ABI includes a type information section that communicates symbol type information to the li...
Definition XCore.cpp:630
llvm::MachO::Record Record
Definition MachO.h:31
#define STRINGIFY(NAME)
static bool isVector(QualType QT, QualType ElementType)
This helper function returns true if QT is a vector type that has element type ElementType.
Complex values, per C99 6.2.5p11.
Definition TypeBase.h:3275
static llvm::SmallVector< Policy > getSupportedMaskedPolicies(bool HasTailPolicy, bool HasMaskPolicy)
RVVIntrinsic(llvm::StringRef Name, llvm::StringRef Suffix, llvm::StringRef OverloadedName, llvm::StringRef OverloadedSuffix, llvm::StringRef IRName, bool IsMasked, bool HasMaskedOffOperand, bool HasVL, PolicyScheme Scheme, bool SupportOverloading, bool HasBuiltinAlias, llvm::StringRef ManualCodegen, const RVVTypes &Types, const std::vector< int64_t > &IntrinsicTypes, unsigned NF, Policy PolicyAttrs, bool HasFRMRoundModeOp, unsigned TWiden)
static llvm::SmallVector< PrototypeDescriptor > computeBuiltinTypes(llvm::ArrayRef< PrototypeDescriptor > Prototype, bool IsMasked, bool HasMaskedOffOperand, bool HasVL, unsigned NF, PolicyScheme DefaultScheme, Policy PolicyAttrs, bool IsTuple)
static void updateNamesAndPolicy(bool IsMasked, bool HasPolicy, std::string &Name, std::string &BuiltinName, std::string &OverloadedName, Policy &PolicyAttrs, bool HasFRMRoundModeOp)
static std::string getSuffixStr(RVVTypeCache &TypeCache, BasicType Type, int Log2LMUL, llvm::ArrayRef< PrototypeDescriptor > PrototypeDescriptors)
static llvm::SmallVector< Policy > getSupportedUnMaskedPolicies()
std::optional< RVVTypePtr > computeType(BasicType BT, int Log2LMUL, PrototypeDescriptor Proto)
std::optional< RVVTypes > computeTypes(BasicType BT, int Log2LMUL, unsigned NF, llvm::ArrayRef< PrototypeDescriptor > Prototype)
Compute output and input types by applying different config (basic type and LMUL with type transforme...
The base class of the type hierarchy.
Definition TypeBase.h:1833
RISCV builtins.
std::optional< unsigned > VScaleVal
llvm::raw_ostream & operator<<(llvm::raw_ostream &OS, enum PolicyScheme PS)
llvm::SmallVector< PrototypeDescriptor > parsePrototypes(llvm::StringRef Prototypes)
std::vector< RVVTypePtr > RVVTypes
static uint64_t computeRVVTypeHashValue(BasicType BT, int Log2LMUL, PrototypeDescriptor Proto)
static VectorTypeModifier getTupleVTM(unsigned NF)
The JSON file list parser is used to communicate input to InstallAPI.
if(T->getSizeExpr()) TRY_TO(TraverseStmt(const_cast< Expr * >(T -> getSizeExpr())))
const FunctionProtoType * T
@ Type
The name was classified as a type.
Definition Sema.h:562
Diagnostic wrappers for TextAPI types for error reporting.
Definition Dominators.h:30
std::optional< unsigned > getScale(unsigned ElementBitwidth) const
static std::optional< PrototypeDescriptor > parsePrototypeDescriptor(llvm::StringRef PrototypeStr)
static const PrototypeDescriptor VL
constexpr PrototypeDescriptor()=default
static const PrototypeDescriptor Mask
static const PrototypeDescriptor Vector