clang 23.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 'd':
454 break;
455 case 'q':
458 break;
459 case 'o':
462 break;
463 case 'm':
466 break;
467 case '0':
469 break;
470 case 'z':
472 break;
473 case 't':
475 break;
476 case 'u':
478 break;
479 case 'l':
481 break;
482 case 'f':
484 break;
485 default:
486 llvm_unreachable("Illegal primitive type transformers!");
487 }
488 PD.PT = PT;
489 PrototypeDescriptorStr = PrototypeDescriptorStr.drop_back();
490
491 // Compute the vector type transformers, it can only appear one time.
492 if (PrototypeDescriptorStr.starts_with("(")) {
494 "VectorTypeModifier should only have one modifier");
495 size_t Idx = PrototypeDescriptorStr.find(')');
496 assert(Idx != StringRef::npos);
497 StringRef ComplexType = PrototypeDescriptorStr.slice(1, Idx);
498 PrototypeDescriptorStr = PrototypeDescriptorStr.drop_front(Idx + 1);
499 assert(!PrototypeDescriptorStr.contains('(') &&
500 "Only allow one vector type modifier");
501
502 auto ComplexTT = ComplexType.split(":");
503 if (ComplexTT.first == "Log2EEW") {
504 uint32_t Log2EEW;
505 if (ComplexTT.second.getAsInteger(10, Log2EEW)) {
506 llvm_unreachable("Invalid Log2EEW value!");
507 return std::nullopt;
508 }
509 switch (Log2EEW) {
510 case 3:
512 break;
513 case 4:
515 break;
516 case 5:
518 break;
519 case 6:
521 break;
522 default:
523 llvm_unreachable("Invalid Log2EEW value, should be [3-6]");
524 return std::nullopt;
525 }
526 } else if (ComplexTT.first == "FixedSEW") {
527 uint32_t NewSEW;
528 if (ComplexTT.second.getAsInteger(10, NewSEW)) {
529 llvm_unreachable("Invalid FixedSEW value!");
530 return std::nullopt;
531 }
532 switch (NewSEW) {
533 case 8:
535 break;
536 case 16:
538 break;
539 case 32:
541 break;
542 case 64:
544 break;
545 default:
546 llvm_unreachable("Invalid FixedSEW value, should be 8, 16, 32 or 64");
547 return std::nullopt;
548 }
549 } else if (ComplexTT.first == "LFixedLog2LMUL") {
550 int32_t Log2LMUL;
551 if (ComplexTT.second.getAsInteger(10, Log2LMUL)) {
552 llvm_unreachable("Invalid LFixedLog2LMUL value!");
553 return std::nullopt;
554 }
555 switch (Log2LMUL) {
556 case -3:
558 break;
559 case -2:
561 break;
562 case -1:
564 break;
565 case 0:
567 break;
568 case 1:
570 break;
571 case 2:
573 break;
574 case 3:
576 break;
577 default:
578 llvm_unreachable("Invalid LFixedLog2LMUL value, should be [-3, 3]");
579 return std::nullopt;
580 }
581 } else if (ComplexTT.first == "SFixedLog2LMUL") {
582 int32_t Log2LMUL;
583 if (ComplexTT.second.getAsInteger(10, Log2LMUL)) {
584 llvm_unreachable("Invalid SFixedLog2LMUL value!");
585 return std::nullopt;
586 }
587 switch (Log2LMUL) {
588 case -3:
590 break;
591 case -2:
593 break;
594 case -1:
596 break;
597 case 0:
599 break;
600 case 1:
602 break;
603 case 2:
605 break;
606 case 3:
608 break;
609 default:
610 llvm_unreachable("Invalid LFixedLog2LMUL value, should be [-3, 3]");
611 return std::nullopt;
612 }
613
614 } else if (ComplexTT.first == "SEFixedLog2LMUL") {
615 int32_t Log2LMUL;
616 if (ComplexTT.second.getAsInteger(10, Log2LMUL)) {
617 llvm_unreachable("Invalid SEFixedLog2LMUL value!");
618 return std::nullopt;
619 }
620 switch (Log2LMUL) {
621 case -3:
623 break;
624 case -2:
626 break;
627 case -1:
629 break;
630 case 0:
632 break;
633 case 1:
635 break;
636 case 2:
638 break;
639 case 3:
641 break;
642 default:
643 llvm_unreachable("Invalid LFixedLog2LMUL value, should be [-3, 3]");
644 return std::nullopt;
645 }
646 } else if (ComplexTT.first == "Tuple") {
647 unsigned NF = 0;
648 if (ComplexTT.second.getAsInteger(10, NF)) {
649 llvm_unreachable("Invalid NF value!");
650 return std::nullopt;
651 }
652 VTM = getTupleVTM(NF);
653 } else {
654 llvm_unreachable("Illegal complex type transformers!");
655 }
656 }
657 PD.VTM = VTM;
658
659 // Compute the remain type transformers
661 for (char I : PrototypeDescriptorStr) {
662 switch (I) {
663 case 'P':
665 llvm_unreachable("'P' transformer cannot be used after 'C'");
667 llvm_unreachable("'P' transformer cannot be used twice");
669 break;
670 case 'C':
672 break;
673 case 'K':
675 break;
676 case 'U':
678 break;
679 case 'I':
681 break;
682 case 'F':
684 break;
685 case 'Y':
687 break;
688 case 'S':
690 break;
691 default:
692 llvm_unreachable("Illegal non-primitive type transformer!");
693 }
694 }
695 PD.TM = TM;
696
697 return PD;
698}
699
700void RVVType::applyModifier(const PrototypeDescriptor &Transformer) {
701 // Handle primitive type transformer
702 switch (static_cast<BaseTypeModifier>(Transformer.PT)) {
704 Scale = 0;
705 break;
707 Scale = LMUL.getScale(ElementBitwidth);
708 break;
710 ScalarType = ScalarTypeKind::Void;
711 break;
713 ScalarType = ScalarTypeKind::Size_t;
714 break;
716 ScalarType = ScalarTypeKind::Ptrdiff_t;
717 break;
719 ScalarType = ScalarTypeKind::UnsignedLong;
720 break;
722 ScalarType = ScalarTypeKind::SignedLong;
723 break;
725 ElementBitwidth = 32;
726 ScalarType = ScalarTypeKind::Float;
727 break;
729 ScalarType = ScalarTypeKind::Invalid;
730 return;
731 }
732
733 switch (static_cast<VectorTypeModifier>(Transformer.VTM)) {
735 ElementBitwidth *= 2;
736 LMUL.MulLog2LMUL(1);
737 Scale = LMUL.getScale(ElementBitwidth);
738 if (ScalarType == ScalarTypeKind::BFloat)
739 ScalarType = ScalarTypeKind::Float;
740 if (ScalarType == ScalarTypeKind::FloatE4M3 ||
741 ScalarType == ScalarTypeKind::FloatE5M2)
742 ScalarType = ScalarTypeKind::BFloat;
743 break;
745 LMUL.MulLog2LMUL(1);
746 Scale = LMUL.getScale(ElementBitwidth);
747 break;
749 ElementBitwidth *= 4;
750 LMUL.MulLog2LMUL(2);
751 Scale = LMUL.getScale(ElementBitwidth);
752 if (ScalarType == ScalarTypeKind::FloatE4M3 ||
753 ScalarType == ScalarTypeKind::FloatE5M2)
754 ScalarType = ScalarTypeKind::Float;
755 break;
757 ElementBitwidth *= 8;
758 LMUL.MulLog2LMUL(3);
759 Scale = LMUL.getScale(ElementBitwidth);
760 break;
762 ScalarType = ScalarTypeKind::Boolean;
763 Scale = LMUL.getScale(ElementBitwidth);
764 ElementBitwidth = 1;
765 break;
767 applyLog2EEW(3);
768 break;
770 applyLog2EEW(4);
771 break;
773 applyLog2EEW(5);
774 break;
776 applyLog2EEW(6);
777 break;
779 applyFixedSEW(8);
780 break;
782 applyFixedSEW(16);
783 break;
785 applyFixedSEW(32);
786 break;
788 applyFixedSEW(64);
789 break;
791 applyFixedLog2LMUL(-3, FixedLMULType::LargerThan);
792 break;
794 applyFixedLog2LMUL(-2, FixedLMULType::LargerThan);
795 break;
797 applyFixedLog2LMUL(-1, FixedLMULType::LargerThan);
798 break;
800 applyFixedLog2LMUL(0, FixedLMULType::LargerThan);
801 break;
803 applyFixedLog2LMUL(1, FixedLMULType::LargerThan);
804 break;
806 applyFixedLog2LMUL(2, FixedLMULType::LargerThan);
807 break;
809 applyFixedLog2LMUL(3, FixedLMULType::LargerThan);
810 break;
812 applyFixedLog2LMUL(-3, FixedLMULType::SmallerThan);
813 break;
815 applyFixedLog2LMUL(-2, FixedLMULType::SmallerThan);
816 break;
818 applyFixedLog2LMUL(-1, FixedLMULType::SmallerThan);
819 break;
821 applyFixedLog2LMUL(0, FixedLMULType::SmallerThan);
822 break;
824 applyFixedLog2LMUL(1, FixedLMULType::SmallerThan);
825 break;
827 applyFixedLog2LMUL(2, FixedLMULType::SmallerThan);
828 break;
830 applyFixedLog2LMUL(3, FixedLMULType::SmallerThan);
831 break;
833 applyFixedLog2LMUL(-3, FixedLMULType::SmallerOrEqual);
834 break;
836 applyFixedLog2LMUL(-2, FixedLMULType::SmallerOrEqual);
837 break;
839 applyFixedLog2LMUL(-1, FixedLMULType::SmallerOrEqual);
840 break;
842 applyFixedLog2LMUL(0, FixedLMULType::SmallerOrEqual);
843 break;
845 applyFixedLog2LMUL(1, FixedLMULType::SmallerOrEqual);
846 break;
848 applyFixedLog2LMUL(2, FixedLMULType::SmallerOrEqual);
849 break;
851 applyFixedLog2LMUL(3, FixedLMULType::SmallerOrEqual);
852 break;
860 IsTuple = true;
861 NF = 2 + static_cast<uint8_t>(Transformer.VTM) -
862 static_cast<uint8_t>(VectorTypeModifier::Tuple2);
863 break;
864 }
866 break;
867 }
868
869 // Early return if the current type modifier is already invalid.
870 if (ScalarType == Invalid)
871 return;
872
873 for (unsigned TypeModifierMaskShift = 0;
874 TypeModifierMaskShift <= static_cast<unsigned>(TypeModifier::MaxOffset);
875 ++TypeModifierMaskShift) {
876 unsigned TypeModifierMask = 1 << TypeModifierMaskShift;
877 if ((static_cast<unsigned>(Transformer.TM) & TypeModifierMask) !=
878 TypeModifierMask)
879 continue;
880 switch (static_cast<TypeModifier>(TypeModifierMask)) {
882 IsPointer = true;
883 break;
885 IsConstant = true;
886 break;
888 IsImmediate = true;
889 IsConstant = true;
890 break;
893 break;
896 break;
898 ScalarType = ScalarTypeKind::Float;
899 break;
901 ScalarType = ScalarTypeKind::BFloat;
902 break;
904 LMUL = LMULType(0);
905 // Update ElementBitwidth need to update Scale too.
906 Scale = LMUL.getScale(ElementBitwidth);
907 break;
908 default:
909 llvm_unreachable("Unknown type modifier mask!");
910 }
911 }
912}
913
914void RVVType::applyLog2EEW(unsigned Log2EEW) {
915 // update new elmul = (eew/sew) * lmul
916 LMUL.MulLog2LMUL(Log2EEW - Log2_32(ElementBitwidth));
917 // update new eew
918 ElementBitwidth = 1 << Log2EEW;
920 Scale = LMUL.getScale(ElementBitwidth);
921}
922
923void RVVType::applyFixedSEW(unsigned NewSEW) {
924 // Set invalid type if src and dst SEW are same.
925 if (ElementBitwidth == NewSEW) {
926 ScalarType = ScalarTypeKind::Invalid;
927 return;
928 }
929 // Update new SEW
930 ElementBitwidth = NewSEW;
931 Scale = LMUL.getScale(ElementBitwidth);
932}
933
934void RVVType::applyFixedLog2LMUL(int Log2LMUL, enum FixedLMULType Type) {
935 switch (Type) {
936 case FixedLMULType::LargerThan:
937 if (Log2LMUL <= LMUL.Log2LMUL) {
938 ScalarType = ScalarTypeKind::Invalid;
939 return;
940 }
941 break;
942 case FixedLMULType::SmallerThan:
943 if (Log2LMUL >= LMUL.Log2LMUL) {
944 ScalarType = ScalarTypeKind::Invalid;
945 return;
946 }
947 break;
948 case FixedLMULType::SmallerOrEqual:
949 if (Log2LMUL > LMUL.Log2LMUL) {
950 ScalarType = ScalarTypeKind::Invalid;
951 return;
952 }
953 break;
954 }
955
956 // Update new LMUL
957 LMUL = LMULType(Log2LMUL);
958 Scale = LMUL.getScale(ElementBitwidth);
959}
960
961std::optional<RVVTypes>
962RVVTypeCache::computeTypes(BasicType BT, int Log2LMUL, unsigned NF,
964 RVVTypes Types;
965 for (const PrototypeDescriptor &Proto : Prototype) {
966 auto T = computeType(BT, Log2LMUL, Proto);
967 if (!T)
968 return std::nullopt;
969 // Record legal type index
970 Types.push_back(*T);
971 }
972 return Types;
973}
974
975// Compute the hash value of RVVType, used for cache the result of computeType.
976static uint64_t computeRVVTypeHashValue(BasicType BT, int Log2LMUL,
977 PrototypeDescriptor Proto) {
978 // Layout of hash value:
979 // 0 8 24 32 40 48
980 // | Log2LMUL + 3 | BT | Proto.PT | Proto.TM | Proto.VTM |
981 assert(Log2LMUL >= -3 && Log2LMUL <= 3);
982 return (Log2LMUL + 3) | (static_cast<uint64_t>(BT) & 0xffff) << 8 |
983 (static_cast<uint64_t>(Proto.PT) << 24) |
984 (static_cast<uint64_t>(Proto.TM) << 32) |
985 (static_cast<uint64_t>(Proto.VTM) << 40);
986}
987
988std::optional<RVVTypePtr> RVVTypeCache::computeType(BasicType BT, int Log2LMUL,
989 PrototypeDescriptor Proto) {
990 uint64_t Idx = computeRVVTypeHashValue(BT, Log2LMUL, Proto);
991 // Search first
992 auto It = LegalTypes.find(Idx);
993 if (It != LegalTypes.end())
994 return &(It->second);
995
996 if (IllegalTypes.count(Idx))
997 return std::nullopt;
998
999 // Compute type and record the result.
1000 RVVType T(BT, Log2LMUL, Proto);
1001 if (T.isValid()) {
1002 // Record legal type index and value.
1003 std::pair<std::unordered_map<uint64_t, RVVType>::iterator, bool>
1004 InsertResult = LegalTypes.insert({Idx, T});
1005 return &(InsertResult.first->second);
1006 }
1007 // Record illegal type index.
1008 IllegalTypes.insert(Idx);
1009 return std::nullopt;
1010}
1011
1012//===----------------------------------------------------------------------===//
1013// RVVIntrinsic implementation
1014//===----------------------------------------------------------------------===//
1015RVVIntrinsic::RVVIntrinsic(StringRef NewName, StringRef Suffix,
1016 StringRef NewOverloadedName,
1017 StringRef OverloadedSuffix, StringRef IRName,
1018 bool IsMasked, bool HasMaskedOffOperand, bool HasVL,
1019 PolicyScheme Scheme, bool SupportOverloading,
1020 bool HasBuiltinAlias, StringRef ManualCodegen,
1021 const RVVTypes &OutInTypes,
1022 const std::vector<int64_t> &NewIntrinsicTypes,
1023 unsigned NF, Policy NewPolicyAttrs,
1024 bool HasFRMRoundModeOp, unsigned TWiden, bool AltFmt)
1025 : IRName(IRName), IsMasked(IsMasked),
1026 HasMaskedOffOperand(HasMaskedOffOperand), HasVL(HasVL), Scheme(Scheme),
1027 SupportOverloading(SupportOverloading), HasBuiltinAlias(HasBuiltinAlias),
1028 ManualCodegen(ManualCodegen.str()), NF(NF), PolicyAttrs(NewPolicyAttrs),
1029 TWiden(TWiden) {
1030
1031 // Init BuiltinName, Name and OverloadedName
1032 BuiltinName = NewName.str();
1033 Name = BuiltinName;
1034 if (NewOverloadedName.empty())
1035 OverloadedName = NewName.split("_").first.str();
1036 else
1037 OverloadedName = NewOverloadedName.str();
1038 if (!Suffix.empty())
1039 Name += "_" + Suffix.str();
1040 if (!OverloadedSuffix.empty())
1041 OverloadedName += "_" + OverloadedSuffix.str();
1042
1043 updateNamesAndPolicy(IsMasked, hasPolicy(), Name, BuiltinName, OverloadedName,
1044 PolicyAttrs, HasFRMRoundModeOp, AltFmt);
1045
1046 // Init OutputType and InputTypes
1047 OutputType = OutInTypes[0];
1048 InputTypes.assign(OutInTypes.begin() + 1, OutInTypes.end());
1049
1050 // IntrinsicTypes is unmasked TA version index. Need to update it
1051 // if there is merge operand (It is always in first operand).
1052 IntrinsicTypes = NewIntrinsicTypes;
1053 if ((IsMasked && hasMaskedOffOperand()) ||
1054 (!IsMasked && hasPassthruOperand())) {
1055 for (auto &I : IntrinsicTypes) {
1056 if (I >= 0)
1057 I += 1;
1058 }
1059 }
1060}
1061
1063 std::string S;
1064 S += OutputType->getBuiltinStr();
1065 for (const auto &T : InputTypes) {
1066 S += T->getBuiltinStr();
1067 }
1068 return S;
1069}
1070
1072 RVVTypeCache &TypeCache, BasicType Type, int Log2LMUL,
1073 llvm::ArrayRef<PrototypeDescriptor> PrototypeDescriptors) {
1074 SmallVector<std::string> SuffixStrs;
1075 for (auto PD : PrototypeDescriptors) {
1076 auto T = TypeCache.computeType(Type, Log2LMUL, PD);
1077 SuffixStrs.push_back((*T)->getShortStr());
1078 }
1079 return join(SuffixStrs, "_");
1080}
1081
1084 bool HasMaskedOffOperand, bool HasVL, unsigned NF,
1085 PolicyScheme DefaultScheme, Policy PolicyAttrs, bool IsTuple) {
1087 bool HasPassthruOp = DefaultScheme == PolicyScheme::HasPassthruOperand;
1088 if (IsMasked) {
1089 // If HasMaskedOffOperand, insert result type as first input operand if
1090 // need.
1091 if (HasMaskedOffOperand && !PolicyAttrs.isTAMAPolicy()) {
1092 if (NF == 1) {
1093 NewPrototype.insert(NewPrototype.begin() + 1, NewPrototype[0]);
1094 } else if (NF > 1) {
1095 if (IsTuple) {
1096 PrototypeDescriptor BasePtrOperand = Prototype[1];
1097 PrototypeDescriptor MaskoffType =
1099 BasePtrOperand.TM & ~TypeModifier::Pointer);
1100 NewPrototype.insert(NewPrototype.begin() + 1, MaskoffType);
1101 } else {
1102 // Convert
1103 // (void, op0 address, op1 address, ...)
1104 // to
1105 // (void, op0 address, op1 address, ..., maskedoff0, maskedoff1, ...)
1106 PrototypeDescriptor MaskoffType = NewPrototype[1];
1107 MaskoffType.TM &= ~TypeModifier::Pointer;
1108 NewPrototype.insert(NewPrototype.begin() + NF + 1, NF, MaskoffType);
1109 }
1110 }
1111 }
1112 if (HasMaskedOffOperand && NF > 1) {
1113 // Convert
1114 // (void, op0 address, op1 address, ..., maskedoff0, maskedoff1, ...)
1115 // to
1116 // (void, op0 address, op1 address, ..., mask, maskedoff0, maskedoff1,
1117 // ...)
1118 if (IsTuple)
1119 NewPrototype.insert(NewPrototype.begin() + 1,
1121 else
1122 NewPrototype.insert(NewPrototype.begin() + NF + 1,
1124 } else {
1125 // If IsMasked, insert PrototypeDescriptor:Mask as first input operand.
1126 NewPrototype.insert(NewPrototype.begin() + 1, PrototypeDescriptor::Mask);
1127 }
1128 } else {
1129 if (NF == 1) {
1130 if (PolicyAttrs.isTUPolicy() && HasPassthruOp)
1131 NewPrototype.insert(NewPrototype.begin(), NewPrototype[0]);
1132 } else if (PolicyAttrs.isTUPolicy() && HasPassthruOp) {
1133 if (IsTuple) {
1134 PrototypeDescriptor BasePtrOperand = Prototype[0];
1135 PrototypeDescriptor MaskoffType =
1137 BasePtrOperand.TM & ~TypeModifier::Pointer);
1138 NewPrototype.insert(NewPrototype.begin(), MaskoffType);
1139 } else {
1140 // NF > 1 cases for segment load operations.
1141 // Convert
1142 // (void, op0 address, op1 address, ...)
1143 // to
1144 // (void, op0 address, op1 address, maskedoff0, maskedoff1, ...)
1145 PrototypeDescriptor MaskoffType = Prototype[1];
1146 MaskoffType.TM &= ~TypeModifier::Pointer;
1147 NewPrototype.insert(NewPrototype.begin() + NF + 1, NF, MaskoffType);
1148 }
1149 }
1150 }
1151
1152 // If HasVL, append PrototypeDescriptor:VL to last operand
1153 if (HasVL)
1154 NewPrototype.push_back(PrototypeDescriptor::VL);
1155
1156 return NewPrototype;
1157}
1158
1162
1165 bool HasMaskPolicy) {
1166 if (HasTailPolicy && HasMaskPolicy)
1173 if (HasTailPolicy && !HasMaskPolicy)
1176 if (!HasTailPolicy && HasMaskPolicy)
1179 llvm_unreachable("An RVV instruction should not be without both tail policy "
1180 "and mask policy");
1181}
1182
1183void RVVIntrinsic::updateNamesAndPolicy(bool IsMasked, bool HasPolicy,
1184 std::string &Name,
1185 std::string &BuiltinName,
1186 std::string &OverloadedName,
1187 Policy &PolicyAttrs,
1188 bool HasFRMRoundModeOp, bool AltFmt) {
1189
1190 auto appendPolicySuffix = [&](const std::string &suffix) {
1191 Name += suffix;
1192 BuiltinName += suffix;
1193 OverloadedName += suffix;
1194 };
1195
1196 if (HasFRMRoundModeOp) {
1197 Name += "_rm";
1198 BuiltinName += "_rm";
1199 }
1200
1201 if (AltFmt)
1202 BuiltinName += "_alt";
1203
1204 if (IsMasked) {
1205 if (PolicyAttrs.isTUMUPolicy())
1206 appendPolicySuffix("_tumu");
1207 else if (PolicyAttrs.isTUMAPolicy())
1208 appendPolicySuffix("_tum");
1209 else if (PolicyAttrs.isTAMUPolicy())
1210 appendPolicySuffix("_mu");
1211 else if (PolicyAttrs.isTAMAPolicy()) {
1212 Name += "_m";
1213 BuiltinName += "_m";
1214 } else
1215 llvm_unreachable("Unhandled policy condition");
1216 } else {
1217 if (PolicyAttrs.isTUPolicy())
1218 appendPolicySuffix("_tu");
1219 else if (PolicyAttrs.isTAPolicy()) // no suffix needed
1220 return;
1221 else
1222 llvm_unreachable("Unhandled policy condition");
1223 }
1224}
1225
1227 SmallVector<PrototypeDescriptor> PrototypeDescriptors;
1228 const StringRef Primaries("evwdqom0ztulf");
1229 while (!Prototypes.empty()) {
1230 size_t Idx = 0;
1231 // Skip over complex prototype because it could contain primitive type
1232 // character.
1233 if (Prototypes[0] == '(')
1234 Idx = Prototypes.find_first_of(')');
1235 Idx = Prototypes.find_first_of(Primaries, Idx);
1236 assert(Idx != StringRef::npos);
1238 Prototypes.slice(0, Idx + 1));
1239 if (!PD)
1240 llvm_unreachable("Error during parsing prototype.");
1241 PrototypeDescriptors.push_back(*PD);
1242 Prototypes = Prototypes.drop_front(Idx + 1);
1243 }
1244 return PrototypeDescriptors;
1245}
1246
1247#define STRINGIFY(NAME) \
1248 case NAME: \
1249 OS << #NAME; \
1250 break;
1251
1252llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, enum PolicyScheme PS) {
1253 switch (PS) {
1257 }
1258 return OS;
1259}
1260
1261#undef STRINGIFY
1262
1263raw_ostream &operator<<(raw_ostream &OS, const RVVIntrinsicRecord &Record) {
1264 OS << "{";
1265 OS << "/*Name=*/\"" << Record.Name << "\", ";
1266 if (Record.OverloadedName == nullptr ||
1267 StringRef(Record.OverloadedName).empty())
1268 OS << "/*OverloadedName=*/nullptr, ";
1269 else
1270 OS << "/*OverloadedName=*/\"" << Record.OverloadedName << "\", ";
1271 OS << "/*RequiredExtensions=*/\"" << Record.RequiredExtensions << "\", ";
1272 OS << "/*PrototypeIndex=*/" << Record.PrototypeIndex << ", ";
1273 OS << "/*SuffixIndex=*/" << Record.SuffixIndex << ", ";
1274 OS << "/*OverloadedSuffixIndex=*/" << Record.OverloadedSuffixIndex << ", ";
1275 OS << "/*PrototypeLength=*/" << (int)Record.PrototypeLength << ", ";
1276 OS << "/*SuffixLength=*/" << (int)Record.SuffixLength << ", ";
1277 OS << "/*OverloadedSuffixSize=*/" << (int)Record.OverloadedSuffixSize << ", ";
1278 OS << "/*TypeRangeMask=*/" << (int)Record.TypeRangeMask << ", ";
1279 OS << "/*Log2LMULMask=*/" << (int)Record.Log2LMULMask << ", ";
1280 OS << "/*NF=*/" << (int)Record.NF << ", ";
1281 OS << "/*HasMasked=*/" << (int)Record.HasMasked << ", ";
1282 OS << "/*HasVL=*/" << (int)Record.HasVL << ", ";
1283 OS << "/*HasMaskedOffOperand=*/" << (int)Record.HasMaskedOffOperand << ", ";
1284 OS << "/*HasTailPolicy=*/" << (int)Record.HasTailPolicy << ", ";
1285 OS << "/*HasMaskPolicy=*/" << (int)Record.HasMaskPolicy << ", ";
1286 OS << "/*HasFRMRoundModeOp=*/" << (int)Record.HasFRMRoundModeOp << ", ";
1287 OS << "/*AltFmt=*/" << (int)Record.AltFmt << ",";
1288 OS << "/*IsTuple=*/" << (int)Record.IsTuple << ", ";
1289 OS << "/*UnMaskedPolicyScheme=*/" << (PolicyScheme)Record.UnMaskedPolicyScheme
1290 << ", ";
1291 OS << "/*MaskedPolicyScheme=*/" << (PolicyScheme)Record.MaskedPolicyScheme
1292 << ", ";
1293 OS << "},\n";
1294 return OS;
1295}
1296
1297} // end namespace RISCV
1298} // 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:3330
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:1871
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())))
@ Type
The name was classified as a type.
Definition Sema.h:564
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