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;
206 BuiltinStr += "a";
207 break;
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(*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(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) {
241 ClangBuiltinStr += "bool" + utostr(64 / *Scale) + "_t";
242 return;
244 ClangBuiltinStr += "float";
245 break;
247 ClangBuiltinStr += "bfloat";
248 break;
250 ClangBuiltinStr += "int";
251 break;
255 ClangBuiltinStr += "uint";
256 break;
257 default:
258 llvm_unreachable("ScalarTypeKind is invalid");
259 }
260 ClangBuiltinStr += utostr(ElementBitwidth) + LMUL.str() +
261 (IsTuple ? "x" + utostr(NF) : "") + "_t";
262}
263
264void RVVType::initTypeStr() {
265 assert(isValid() && "RVVType is invalid");
266
267 if (IsConstant)
268 Str += "const ";
269
270 auto getTypeString = [&](StringRef TypeStr) {
271 if (isScalar())
272 return Twine(TypeStr + Twine(ElementBitwidth) + "_t").str();
273 return Twine("v" + TypeStr + Twine(ElementBitwidth) + LMUL.str() +
274 (IsTuple ? "x" + utostr(NF) : "") + "_t")
275 .str();
276 };
277
278 switch (ScalarType) {
280 Str = "void";
281 return;
283 Str = "size_t";
284 if (IsPointer)
285 Str += " *";
286 return;
288 Str = "ptrdiff_t";
289 return;
291 Str = "unsigned long";
292 return;
294 Str = "long";
295 return;
297 if (isScalar())
298 Str += "bool";
299 else
300 // Vector bool is special case, the formulate is
301 // `vbool<N>_t = MVT::nxv<64/N>i1` ex. vbool16_t = MVT::4i1
302 Str += "vbool" + utostr(64 / *Scale) + "_t";
303 break;
305 if (isScalar()) {
306 if (ElementBitwidth == 64)
307 Str += "double";
308 else if (ElementBitwidth == 32)
309 Str += "float";
310 else if (ElementBitwidth == 16)
311 Str += "_Float16";
312 else
313 llvm_unreachable("Unhandled floating type.");
314 } else
315 Str += getTypeString("float");
316 break;
318 if (isScalar()) {
319 if (ElementBitwidth == 16)
320 Str += "__bf16";
321 else
322 llvm_unreachable("Unhandled floating type.");
323 } else
324 Str += getTypeString("bfloat");
325 break;
327 Str += getTypeString("int");
328 break;
332 Str += getTypeString("uint");
333 break;
334 default:
335 llvm_unreachable("ScalarType is invalid!");
336 }
337 if (IsPointer)
338 Str += " *";
339}
340
341void RVVType::initShortStr() {
342 switch (ScalarType) {
344 assert(isVector());
345 ShortStr = "b" + utostr(64 / *Scale);
346 return;
348 ShortStr = "f" + utostr(ElementBitwidth);
349 break;
351 ShortStr = "bf" + utostr(ElementBitwidth);
352 break;
354 ShortStr = "i" + utostr(ElementBitwidth);
355 break;
357 ShortStr = "u" + utostr(ElementBitwidth);
358 break;
360 ShortStr = "f8e4m3";
361 break;
363 ShortStr = "f8e5m2";
364 break;
365 default:
366 llvm_unreachable("Unhandled case!");
367 }
368 if (isVector())
369 ShortStr += LMUL.str();
370 if (isTuple())
371 ShortStr += "x" + utostr(NF);
372}
373
374static VectorTypeModifier getTupleVTM(unsigned NF) {
375 assert(2 <= NF && NF <= 8 && "2 <= NF <= 8");
376 return static_cast<VectorTypeModifier>(
377 static_cast<uint8_t>(VectorTypeModifier::Tuple2) + (NF - 2));
378}
379
380void RVVType::applyBasicType() {
381 switch (BT) {
382 case BasicType::Int8:
383 ElementBitwidth = 8;
385 break;
386 case BasicType::Int16:
387 ElementBitwidth = 16;
389 break;
390 case BasicType::Int32:
391 ElementBitwidth = 32;
393 break;
394 case BasicType::Int64:
395 ElementBitwidth = 64;
397 break;
399 ElementBitwidth = 16;
400 ScalarType = ScalarTypeKind::Float;
401 break;
403 ElementBitwidth = 32;
404 ScalarType = ScalarTypeKind::Float;
405 break;
407 ElementBitwidth = 64;
408 ScalarType = ScalarTypeKind::Float;
409 break;
411 ElementBitwidth = 16;
412 ScalarType = ScalarTypeKind::BFloat;
413 break;
415 ElementBitwidth = 8;
416 ScalarType = ScalarTypeKind::FloatE4M3;
417 break;
419 ElementBitwidth = 8;
420 ScalarType = ScalarTypeKind::FloatE5M2;
421 break;
422 default:
423 llvm_unreachable("Unhandled type code!");
424 }
425 assert(ElementBitwidth != 0 && "Bad element bitwidth!");
426}
427
428std::optional<PrototypeDescriptor>
430 llvm::StringRef PrototypeDescriptorStr) {
434
435 if (PrototypeDescriptorStr.empty())
436 return PD;
437
438 // Handle base type modifier
439 auto PType = PrototypeDescriptorStr.back();
440 switch (PType) {
441 case 'e':
443 break;
444 case 'v':
446 break;
447 case 'w':
450 break;
451 case 'q':
454 break;
455 case 'o':
458 break;
459 case 'm':
462 break;
463 case '0':
465 break;
466 case 'z':
468 break;
469 case 't':
471 break;
472 case 'u':
474 break;
475 case 'l':
477 break;
478 case 'f':
480 break;
481 default:
482 llvm_unreachable("Illegal primitive type transformers!");
483 }
484 PD.PT = static_cast<uint8_t>(PT);
485 PrototypeDescriptorStr = PrototypeDescriptorStr.drop_back();
486
487 // Compute the vector type transformers, it can only appear one time.
488 if (PrototypeDescriptorStr.starts_with("(")) {
490 "VectorTypeModifier should only have one modifier");
491 size_t Idx = PrototypeDescriptorStr.find(')');
492 assert(Idx != StringRef::npos);
493 StringRef ComplexType = PrototypeDescriptorStr.slice(1, Idx);
494 PrototypeDescriptorStr = PrototypeDescriptorStr.drop_front(Idx + 1);
495 assert(!PrototypeDescriptorStr.contains('(') &&
496 "Only allow one vector type modifier");
497
498 auto ComplexTT = ComplexType.split(":");
499 if (ComplexTT.first == "Log2EEW") {
500 uint32_t Log2EEW;
501 if (ComplexTT.second.getAsInteger(10, Log2EEW)) {
502 llvm_unreachable("Invalid Log2EEW value!");
503 return std::nullopt;
504 }
505 switch (Log2EEW) {
506 case 3:
508 break;
509 case 4:
511 break;
512 case 5:
514 break;
515 case 6:
517 break;
518 default:
519 llvm_unreachable("Invalid Log2EEW value, should be [3-6]");
520 return std::nullopt;
521 }
522 } else if (ComplexTT.first == "FixedSEW") {
523 uint32_t NewSEW;
524 if (ComplexTT.second.getAsInteger(10, NewSEW)) {
525 llvm_unreachable("Invalid FixedSEW value!");
526 return std::nullopt;
527 }
528 switch (NewSEW) {
529 case 8:
531 break;
532 case 16:
534 break;
535 case 32:
537 break;
538 case 64:
540 break;
541 default:
542 llvm_unreachable("Invalid FixedSEW value, should be 8, 16, 32 or 64");
543 return std::nullopt;
544 }
545 } else if (ComplexTT.first == "LFixedLog2LMUL") {
546 int32_t Log2LMUL;
547 if (ComplexTT.second.getAsInteger(10, Log2LMUL)) {
548 llvm_unreachable("Invalid LFixedLog2LMUL value!");
549 return std::nullopt;
550 }
551 switch (Log2LMUL) {
552 case -3:
554 break;
555 case -2:
557 break;
558 case -1:
560 break;
561 case 0:
563 break;
564 case 1:
566 break;
567 case 2:
569 break;
570 case 3:
572 break;
573 default:
574 llvm_unreachable("Invalid LFixedLog2LMUL value, should be [-3, 3]");
575 return std::nullopt;
576 }
577 } else if (ComplexTT.first == "SFixedLog2LMUL") {
578 int32_t Log2LMUL;
579 if (ComplexTT.second.getAsInteger(10, Log2LMUL)) {
580 llvm_unreachable("Invalid SFixedLog2LMUL value!");
581 return std::nullopt;
582 }
583 switch (Log2LMUL) {
584 case -3:
586 break;
587 case -2:
589 break;
590 case -1:
592 break;
593 case 0:
595 break;
596 case 1:
598 break;
599 case 2:
601 break;
602 case 3:
604 break;
605 default:
606 llvm_unreachable("Invalid LFixedLog2LMUL value, should be [-3, 3]");
607 return std::nullopt;
608 }
609
610 } else if (ComplexTT.first == "SEFixedLog2LMUL") {
611 int32_t Log2LMUL;
612 if (ComplexTT.second.getAsInteger(10, Log2LMUL)) {
613 llvm_unreachable("Invalid SEFixedLog2LMUL value!");
614 return std::nullopt;
615 }
616 switch (Log2LMUL) {
617 case -3:
619 break;
620 case -2:
622 break;
623 case -1:
625 break;
626 case 0:
628 break;
629 case 1:
631 break;
632 case 2:
634 break;
635 case 3:
637 break;
638 default:
639 llvm_unreachable("Invalid LFixedLog2LMUL value, should be [-3, 3]");
640 return std::nullopt;
641 }
642 } else if (ComplexTT.first == "Tuple") {
643 unsigned NF = 0;
644 if (ComplexTT.second.getAsInteger(10, NF)) {
645 llvm_unreachable("Invalid NF value!");
646 return std::nullopt;
647 }
648 VTM = getTupleVTM(NF);
649 } else {
650 llvm_unreachable("Illegal complex type transformers!");
651 }
652 }
653 PD.VTM = static_cast<uint8_t>(VTM);
654
655 // Compute the remain type transformers
657 for (char I : PrototypeDescriptorStr) {
658 switch (I) {
659 case 'P':
661 llvm_unreachable("'P' transformer cannot be used after 'C'");
663 llvm_unreachable("'P' transformer cannot be used twice");
665 break;
666 case 'C':
668 break;
669 case 'K':
671 break;
672 case 'U':
674 break;
675 case 'I':
677 break;
678 case 'F':
680 break;
681 case 'Y':
683 break;
684 case 'S':
686 break;
687 default:
688 llvm_unreachable("Illegal non-primitive type transformer!");
689 }
690 }
691 PD.TM = static_cast<uint8_t>(TM);
692
693 return PD;
694}
695
696void RVVType::applyModifier(const PrototypeDescriptor &Transformer) {
697 // Handle primitive type transformer
698 switch (static_cast<BaseTypeModifier>(Transformer.PT)) {
700 Scale = 0;
701 break;
703 Scale = LMUL.getScale(ElementBitwidth);
704 break;
706 ScalarType = ScalarTypeKind::Void;
707 break;
709 ScalarType = ScalarTypeKind::Size_t;
710 break;
712 ScalarType = ScalarTypeKind::Ptrdiff_t;
713 break;
715 ScalarType = ScalarTypeKind::UnsignedLong;
716 break;
718 ScalarType = ScalarTypeKind::SignedLong;
719 break;
721 ElementBitwidth = 32;
722 ScalarType = ScalarTypeKind::Float;
723 break;
725 ScalarType = ScalarTypeKind::Invalid;
726 return;
727 }
728
729 switch (static_cast<VectorTypeModifier>(Transformer.VTM)) {
731 ElementBitwidth *= 2;
732 LMUL.MulLog2LMUL(1);
733 Scale = LMUL.getScale(ElementBitwidth);
734 if (ScalarType == ScalarTypeKind::BFloat)
735 ScalarType = ScalarTypeKind::Float;
736 if (ScalarType == ScalarTypeKind::FloatE4M3 ||
737 ScalarType == ScalarTypeKind::FloatE5M2)
738 ScalarType = ScalarTypeKind::BFloat;
739 break;
741 ElementBitwidth *= 4;
742 LMUL.MulLog2LMUL(2);
743 Scale = LMUL.getScale(ElementBitwidth);
744 if (ScalarType == ScalarTypeKind::FloatE4M3 ||
745 ScalarType == ScalarTypeKind::FloatE5M2)
746 ScalarType = ScalarTypeKind::Float;
747 break;
749 ElementBitwidth *= 8;
750 LMUL.MulLog2LMUL(3);
751 Scale = LMUL.getScale(ElementBitwidth);
752 break;
754 ScalarType = ScalarTypeKind::Boolean;
755 Scale = LMUL.getScale(ElementBitwidth);
756 ElementBitwidth = 1;
757 break;
759 applyLog2EEW(3);
760 break;
762 applyLog2EEW(4);
763 break;
765 applyLog2EEW(5);
766 break;
768 applyLog2EEW(6);
769 break;
771 applyFixedSEW(8);
772 break;
774 applyFixedSEW(16);
775 break;
777 applyFixedSEW(32);
778 break;
780 applyFixedSEW(64);
781 break;
783 applyFixedLog2LMUL(-3, FixedLMULType::LargerThan);
784 break;
786 applyFixedLog2LMUL(-2, FixedLMULType::LargerThan);
787 break;
789 applyFixedLog2LMUL(-1, FixedLMULType::LargerThan);
790 break;
792 applyFixedLog2LMUL(0, FixedLMULType::LargerThan);
793 break;
795 applyFixedLog2LMUL(1, FixedLMULType::LargerThan);
796 break;
798 applyFixedLog2LMUL(2, FixedLMULType::LargerThan);
799 break;
801 applyFixedLog2LMUL(3, FixedLMULType::LargerThan);
802 break;
804 applyFixedLog2LMUL(-3, FixedLMULType::SmallerThan);
805 break;
807 applyFixedLog2LMUL(-2, FixedLMULType::SmallerThan);
808 break;
810 applyFixedLog2LMUL(-1, FixedLMULType::SmallerThan);
811 break;
813 applyFixedLog2LMUL(0, FixedLMULType::SmallerThan);
814 break;
816 applyFixedLog2LMUL(1, FixedLMULType::SmallerThan);
817 break;
819 applyFixedLog2LMUL(2, FixedLMULType::SmallerThan);
820 break;
822 applyFixedLog2LMUL(3, FixedLMULType::SmallerThan);
823 break;
825 applyFixedLog2LMUL(-3, FixedLMULType::SmallerOrEqual);
826 break;
828 applyFixedLog2LMUL(-2, FixedLMULType::SmallerOrEqual);
829 break;
831 applyFixedLog2LMUL(-1, FixedLMULType::SmallerOrEqual);
832 break;
834 applyFixedLog2LMUL(0, FixedLMULType::SmallerOrEqual);
835 break;
837 applyFixedLog2LMUL(1, FixedLMULType::SmallerOrEqual);
838 break;
840 applyFixedLog2LMUL(2, FixedLMULType::SmallerOrEqual);
841 break;
843 applyFixedLog2LMUL(3, FixedLMULType::SmallerOrEqual);
844 break;
852 IsTuple = true;
853 NF = 2 + static_cast<uint8_t>(Transformer.VTM) -
854 static_cast<uint8_t>(VectorTypeModifier::Tuple2);
855 break;
856 }
858 break;
859 }
860
861 // Early return if the current type modifier is already invalid.
862 if (ScalarType == Invalid)
863 return;
864
865 for (unsigned TypeModifierMaskShift = 0;
866 TypeModifierMaskShift <= static_cast<unsigned>(TypeModifier::MaxOffset);
867 ++TypeModifierMaskShift) {
868 unsigned TypeModifierMask = 1 << TypeModifierMaskShift;
869 if ((static_cast<unsigned>(Transformer.TM) & TypeModifierMask) !=
870 TypeModifierMask)
871 continue;
872 switch (static_cast<TypeModifier>(TypeModifierMask)) {
874 IsPointer = true;
875 break;
877 IsConstant = true;
878 break;
880 IsImmediate = true;
881 IsConstant = true;
882 break;
885 break;
888 break;
890 ScalarType = ScalarTypeKind::Float;
891 break;
893 ScalarType = ScalarTypeKind::BFloat;
894 break;
896 LMUL = LMULType(0);
897 // Update ElementBitwidth need to update Scale too.
898 Scale = LMUL.getScale(ElementBitwidth);
899 break;
900 default:
901 llvm_unreachable("Unknown type modifier mask!");
902 }
903 }
904}
905
906void RVVType::applyLog2EEW(unsigned Log2EEW) {
907 // update new elmul = (eew/sew) * lmul
908 LMUL.MulLog2LMUL(Log2EEW - Log2_32(ElementBitwidth));
909 // update new eew
910 ElementBitwidth = 1 << Log2EEW;
912 Scale = LMUL.getScale(ElementBitwidth);
913}
914
915void RVVType::applyFixedSEW(unsigned NewSEW) {
916 // Set invalid type if src and dst SEW are same.
917 if (ElementBitwidth == NewSEW) {
918 ScalarType = ScalarTypeKind::Invalid;
919 return;
920 }
921 // Update new SEW
922 ElementBitwidth = NewSEW;
923 Scale = LMUL.getScale(ElementBitwidth);
924}
925
926void RVVType::applyFixedLog2LMUL(int Log2LMUL, enum FixedLMULType Type) {
927 switch (Type) {
928 case FixedLMULType::LargerThan:
929 if (Log2LMUL <= LMUL.Log2LMUL) {
930 ScalarType = ScalarTypeKind::Invalid;
931 return;
932 }
933 break;
934 case FixedLMULType::SmallerThan:
935 if (Log2LMUL >= LMUL.Log2LMUL) {
936 ScalarType = ScalarTypeKind::Invalid;
937 return;
938 }
939 break;
940 case FixedLMULType::SmallerOrEqual:
941 if (Log2LMUL > LMUL.Log2LMUL) {
942 ScalarType = ScalarTypeKind::Invalid;
943 return;
944 }
945 break;
946 }
947
948 // Update new LMUL
949 LMUL = LMULType(Log2LMUL);
950 Scale = LMUL.getScale(ElementBitwidth);
951}
952
953std::optional<RVVTypes>
954RVVTypeCache::computeTypes(BasicType BT, int Log2LMUL, unsigned NF,
956 RVVTypes Types;
957 for (const PrototypeDescriptor &Proto : Prototype) {
958 auto T = computeType(BT, Log2LMUL, Proto);
959 if (!T)
960 return std::nullopt;
961 // Record legal type index
962 Types.push_back(*T);
963 }
964 return Types;
965}
966
967// Compute the hash value of RVVType, used for cache the result of computeType.
968static uint64_t computeRVVTypeHashValue(BasicType BT, int Log2LMUL,
969 PrototypeDescriptor Proto) {
970 // Layout of hash value:
971 // 0 8 24 32 40 48
972 // | Log2LMUL + 3 | BT | Proto.PT | Proto.TM | Proto.VTM |
973 assert(Log2LMUL >= -3 && Log2LMUL <= 3);
974 return (Log2LMUL + 3) | (static_cast<uint64_t>(BT) & 0xffff) << 8 |
975 ((uint64_t)(Proto.PT & 0xff) << 24) |
976 ((uint64_t)(Proto.TM & 0xff) << 32) |
977 ((uint64_t)(Proto.VTM & 0xff) << 40);
978}
979
980std::optional<RVVTypePtr> RVVTypeCache::computeType(BasicType BT, int Log2LMUL,
981 PrototypeDescriptor Proto) {
982 uint64_t Idx = computeRVVTypeHashValue(BT, Log2LMUL, Proto);
983 // Search first
984 auto It = LegalTypes.find(Idx);
985 if (It != LegalTypes.end())
986 return &(It->second);
987
988 if (IllegalTypes.count(Idx))
989 return std::nullopt;
990
991 // Compute type and record the result.
992 RVVType T(BT, Log2LMUL, Proto);
993 if (T.isValid()) {
994 // Record legal type index and value.
995 std::pair<std::unordered_map<uint64_t, RVVType>::iterator, bool>
996 InsertResult = LegalTypes.insert({Idx, T});
997 return &(InsertResult.first->second);
998 }
999 // Record illegal type index.
1000 IllegalTypes.insert(Idx);
1001 return std::nullopt;
1002}
1003
1004//===----------------------------------------------------------------------===//
1005// RVVIntrinsic implementation
1006//===----------------------------------------------------------------------===//
1007RVVIntrinsic::RVVIntrinsic(StringRef NewName, StringRef Suffix,
1008 StringRef NewOverloadedName,
1009 StringRef OverloadedSuffix, StringRef IRName,
1010 bool IsMasked, bool HasMaskedOffOperand, bool HasVL,
1011 PolicyScheme Scheme, bool SupportOverloading,
1012 bool HasBuiltinAlias, StringRef ManualCodegen,
1013 const RVVTypes &OutInTypes,
1014 const std::vector<int64_t> &NewIntrinsicTypes,
1015 unsigned NF, Policy NewPolicyAttrs,
1016 bool HasFRMRoundModeOp, unsigned TWiden, bool AltFmt)
1017 : IRName(IRName), IsMasked(IsMasked),
1018 HasMaskedOffOperand(HasMaskedOffOperand), HasVL(HasVL), Scheme(Scheme),
1019 SupportOverloading(SupportOverloading), HasBuiltinAlias(HasBuiltinAlias),
1020 ManualCodegen(ManualCodegen.str()), NF(NF), PolicyAttrs(NewPolicyAttrs),
1021 TWiden(TWiden) {
1022
1023 // Init BuiltinName, Name and OverloadedName
1024 BuiltinName = NewName.str();
1025 Name = BuiltinName;
1026 if (NewOverloadedName.empty())
1027 OverloadedName = NewName.split("_").first.str();
1028 else
1029 OverloadedName = NewOverloadedName.str();
1030 if (!Suffix.empty())
1031 Name += "_" + Suffix.str();
1032 if (!OverloadedSuffix.empty())
1033 OverloadedName += "_" + OverloadedSuffix.str();
1034
1035 updateNamesAndPolicy(IsMasked, hasPolicy(), Name, BuiltinName, OverloadedName,
1036 PolicyAttrs, HasFRMRoundModeOp, AltFmt);
1037
1038 // Init OutputType and InputTypes
1039 OutputType = OutInTypes[0];
1040 InputTypes.assign(OutInTypes.begin() + 1, OutInTypes.end());
1041
1042 // IntrinsicTypes is unmasked TA version index. Need to update it
1043 // if there is merge operand (It is always in first operand).
1044 IntrinsicTypes = NewIntrinsicTypes;
1045 if ((IsMasked && hasMaskedOffOperand()) ||
1046 (!IsMasked && hasPassthruOperand())) {
1047 for (auto &I : IntrinsicTypes) {
1048 if (I >= 0)
1049 I += 1;
1050 }
1051 }
1052}
1053
1055 std::string S;
1056 S += OutputType->getBuiltinStr();
1057 for (const auto &T : InputTypes) {
1058 S += T->getBuiltinStr();
1059 }
1060 return S;
1061}
1062
1064 RVVTypeCache &TypeCache, BasicType Type, int Log2LMUL,
1065 llvm::ArrayRef<PrototypeDescriptor> PrototypeDescriptors) {
1066 SmallVector<std::string> SuffixStrs;
1067 for (auto PD : PrototypeDescriptors) {
1068 auto T = TypeCache.computeType(Type, Log2LMUL, PD);
1069 SuffixStrs.push_back((*T)->getShortStr());
1070 }
1071 return join(SuffixStrs, "_");
1072}
1073
1076 bool HasMaskedOffOperand, bool HasVL, unsigned NF,
1077 PolicyScheme DefaultScheme, Policy PolicyAttrs, bool IsTuple) {
1079 bool HasPassthruOp = DefaultScheme == PolicyScheme::HasPassthruOperand;
1080 if (IsMasked) {
1081 // If HasMaskedOffOperand, insert result type as first input operand if
1082 // need.
1083 if (HasMaskedOffOperand && !PolicyAttrs.isTAMAPolicy()) {
1084 if (NF == 1) {
1085 NewPrototype.insert(NewPrototype.begin() + 1, NewPrototype[0]);
1086 } else if (NF > 1) {
1087 if (IsTuple) {
1088 PrototypeDescriptor BasePtrOperand = Prototype[1];
1090 static_cast<uint8_t>(BaseTypeModifier::Vector),
1091 static_cast<uint8_t>(getTupleVTM(NF)),
1092 BasePtrOperand.TM & ~static_cast<uint8_t>(TypeModifier::Pointer));
1093 NewPrototype.insert(NewPrototype.begin() + 1, MaskoffType);
1094 } else {
1095 // Convert
1096 // (void, op0 address, op1 address, ...)
1097 // to
1098 // (void, op0 address, op1 address, ..., maskedoff0, maskedoff1, ...)
1099 PrototypeDescriptor MaskoffType = NewPrototype[1];
1100 MaskoffType.TM &= ~static_cast<uint8_t>(TypeModifier::Pointer);
1101 NewPrototype.insert(NewPrototype.begin() + NF + 1, NF, MaskoffType);
1102 }
1103 }
1104 }
1105 if (HasMaskedOffOperand && NF > 1) {
1106 // Convert
1107 // (void, op0 address, op1 address, ..., maskedoff0, maskedoff1, ...)
1108 // to
1109 // (void, op0 address, op1 address, ..., mask, maskedoff0, maskedoff1,
1110 // ...)
1111 if (IsTuple)
1112 NewPrototype.insert(NewPrototype.begin() + 1,
1114 else
1115 NewPrototype.insert(NewPrototype.begin() + NF + 1,
1117 } else {
1118 // If IsMasked, insert PrototypeDescriptor:Mask as first input operand.
1119 NewPrototype.insert(NewPrototype.begin() + 1, PrototypeDescriptor::Mask);
1120 }
1121 } else {
1122 if (NF == 1) {
1123 if (PolicyAttrs.isTUPolicy() && HasPassthruOp)
1124 NewPrototype.insert(NewPrototype.begin(), NewPrototype[0]);
1125 } else if (PolicyAttrs.isTUPolicy() && HasPassthruOp) {
1126 if (IsTuple) {
1127 PrototypeDescriptor BasePtrOperand = Prototype[0];
1129 static_cast<uint8_t>(BaseTypeModifier::Vector),
1130 static_cast<uint8_t>(getTupleVTM(NF)),
1131 BasePtrOperand.TM & ~static_cast<uint8_t>(TypeModifier::Pointer));
1132 NewPrototype.insert(NewPrototype.begin(), MaskoffType);
1133 } else {
1134 // NF > 1 cases for segment load operations.
1135 // Convert
1136 // (void, op0 address, op1 address, ...)
1137 // to
1138 // (void, op0 address, op1 address, maskedoff0, maskedoff1, ...)
1139 PrototypeDescriptor MaskoffType = Prototype[1];
1140 MaskoffType.TM &= ~static_cast<uint8_t>(TypeModifier::Pointer);
1141 NewPrototype.insert(NewPrototype.begin() + NF + 1, NF, MaskoffType);
1142 }
1143 }
1144 }
1145
1146 // If HasVL, append PrototypeDescriptor:VL to last operand
1147 if (HasVL)
1148 NewPrototype.push_back(PrototypeDescriptor::VL);
1149
1150 return NewPrototype;
1151}
1152
1156
1159 bool HasMaskPolicy) {
1160 if (HasTailPolicy && HasMaskPolicy)
1167 if (HasTailPolicy && !HasMaskPolicy)
1170 if (!HasTailPolicy && HasMaskPolicy)
1173 llvm_unreachable("An RVV instruction should not be without both tail policy "
1174 "and mask policy");
1175}
1176
1177void RVVIntrinsic::updateNamesAndPolicy(bool IsMasked, bool HasPolicy,
1178 std::string &Name,
1179 std::string &BuiltinName,
1180 std::string &OverloadedName,
1181 Policy &PolicyAttrs,
1182 bool HasFRMRoundModeOp, bool AltFmt) {
1183
1184 auto appendPolicySuffix = [&](const std::string &suffix) {
1185 Name += suffix;
1186 BuiltinName += suffix;
1187 OverloadedName += suffix;
1188 };
1189
1190 if (HasFRMRoundModeOp) {
1191 Name += "_rm";
1192 BuiltinName += "_rm";
1193 }
1194
1195 if (AltFmt)
1196 BuiltinName += "_alt";
1197
1198 if (IsMasked) {
1199 if (PolicyAttrs.isTUMUPolicy())
1200 appendPolicySuffix("_tumu");
1201 else if (PolicyAttrs.isTUMAPolicy())
1202 appendPolicySuffix("_tum");
1203 else if (PolicyAttrs.isTAMUPolicy())
1204 appendPolicySuffix("_mu");
1205 else if (PolicyAttrs.isTAMAPolicy()) {
1206 Name += "_m";
1207 BuiltinName += "_m";
1208 } else
1209 llvm_unreachable("Unhandled policy condition");
1210 } else {
1211 if (PolicyAttrs.isTUPolicy())
1212 appendPolicySuffix("_tu");
1213 else if (PolicyAttrs.isTAPolicy()) // no suffix needed
1214 return;
1215 else
1216 llvm_unreachable("Unhandled policy condition");
1217 }
1218}
1219
1221 SmallVector<PrototypeDescriptor> PrototypeDescriptors;
1222 const StringRef Primaries("evwqom0ztulf");
1223 while (!Prototypes.empty()) {
1224 size_t Idx = 0;
1225 // Skip over complex prototype because it could contain primitive type
1226 // character.
1227 if (Prototypes[0] == '(')
1228 Idx = Prototypes.find_first_of(')');
1229 Idx = Prototypes.find_first_of(Primaries, Idx);
1230 assert(Idx != StringRef::npos);
1232 Prototypes.slice(0, Idx + 1));
1233 if (!PD)
1234 llvm_unreachable("Error during parsing prototype.");
1235 PrototypeDescriptors.push_back(*PD);
1236 Prototypes = Prototypes.drop_front(Idx + 1);
1237 }
1238 return PrototypeDescriptors;
1239}
1240
1241#define STRINGIFY(NAME) \
1242 case NAME: \
1243 OS << #NAME; \
1244 break;
1245
1246llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, enum PolicyScheme PS) {
1247 switch (PS) {
1251 }
1252 return OS;
1253}
1254
1255#undef STRINGIFY
1256
1257raw_ostream &operator<<(raw_ostream &OS, const RVVIntrinsicRecord &Record) {
1258 OS << "{";
1259 OS << "/*Name=*/\"" << Record.Name << "\", ";
1260 if (Record.OverloadedName == nullptr ||
1261 StringRef(Record.OverloadedName).empty())
1262 OS << "/*OverloadedName=*/nullptr, ";
1263 else
1264 OS << "/*OverloadedName=*/\"" << Record.OverloadedName << "\", ";
1265 OS << "/*RequiredExtensions=*/\"" << Record.RequiredExtensions << "\", ";
1266 OS << "/*PrototypeIndex=*/" << Record.PrototypeIndex << ", ";
1267 OS << "/*SuffixIndex=*/" << Record.SuffixIndex << ", ";
1268 OS << "/*OverloadedSuffixIndex=*/" << Record.OverloadedSuffixIndex << ", ";
1269 OS << "/*PrototypeLength=*/" << (int)Record.PrototypeLength << ", ";
1270 OS << "/*SuffixLength=*/" << (int)Record.SuffixLength << ", ";
1271 OS << "/*OverloadedSuffixSize=*/" << (int)Record.OverloadedSuffixSize << ", ";
1272 OS << "/*TypeRangeMask=*/" << (int)Record.TypeRangeMask << ", ";
1273 OS << "/*Log2LMULMask=*/" << (int)Record.Log2LMULMask << ", ";
1274 OS << "/*NF=*/" << (int)Record.NF << ", ";
1275 OS << "/*HasMasked=*/" << (int)Record.HasMasked << ", ";
1276 OS << "/*HasVL=*/" << (int)Record.HasVL << ", ";
1277 OS << "/*HasMaskedOffOperand=*/" << (int)Record.HasMaskedOffOperand << ", ";
1278 OS << "/*HasTailPolicy=*/" << (int)Record.HasTailPolicy << ", ";
1279 OS << "/*HasMaskPolicy=*/" << (int)Record.HasMaskPolicy << ", ";
1280 OS << "/*HasFRMRoundModeOp=*/" << (int)Record.HasFRMRoundModeOp << ", ";
1281 OS << "/*AltFmt=*/" << (int)Record.AltFmt << ",";
1282 OS << "/*IsTuple=*/" << (int)Record.IsTuple << ", ";
1283 OS << "/*UnMaskedPolicyScheme=*/" << (PolicyScheme)Record.UnMaskedPolicyScheme
1284 << ", ";
1285 OS << "/*MaskedPolicyScheme=*/" << (PolicyScheme)Record.MaskedPolicyScheme
1286 << ", ";
1287 OS << "},\n";
1288 return OS;
1289}
1290
1291} // end namespace RISCV
1292} // 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:3276
static llvm::SmallVector< Policy > getSupportedMaskedPolicies(bool HasTailPolicy, bool HasMaskPolicy)
static llvm::SmallVector< PrototypeDescriptor > computeBuiltinTypes(llvm::ArrayRef< PrototypeDescriptor > Prototype, bool IsMasked, bool HasMaskedOffOperand, bool HasVL, unsigned NF, PolicyScheme DefaultScheme, Policy PolicyAttrs, bool IsTuple)
static std::string getSuffixStr(RVVTypeCache &TypeCache, BasicType Type, int Log2LMUL, llvm::ArrayRef< PrototypeDescriptor > PrototypeDescriptors)
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, bool AltFmt)
static void updateNamesAndPolicy(bool IsMasked, bool HasPolicy, std::string &Name, std::string &BuiltinName, std::string &OverloadedName, Policy &PolicyAttrs, bool HasFRMRoundModeOp, bool AltFmt)
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:563
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