1//===- RISCVVIntrinsicUtils.cpp - RISC-V Vector Intrinsic Utils -*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "clang/Support/RISCVVIntrinsicUtils.h"
10#include "llvm/ADT/ArrayRef.h"
11#include "llvm/ADT/StringExtras.h"
12#include "llvm/ADT/Twine.h"
13#include "llvm/Support/ErrorHandling.h"
14#include "llvm/Support/raw_ostream.h"
15#include <optional>
16
17using namespace llvm;
18
19namespace clang {
20namespace RISCV {
21
22const PrototypeDescriptor PrototypeDescriptor::Mask = PrototypeDescriptor(
23 BaseTypeModifier::Vector, VectorTypeModifier::MaskVector);
24const PrototypeDescriptor PrototypeDescriptor::VL =
25 PrototypeDescriptor(BaseTypeModifier::SizeT);
26const PrototypeDescriptor PrototypeDescriptor::Vector =
27 PrototypeDescriptor(BaseTypeModifier::Vector);
28
29//===----------------------------------------------------------------------===//
30// Type implementation
31//===----------------------------------------------------------------------===//
32
33LMULType::LMULType(int NewLog2LMUL) {
34 // Check Log2LMUL is -3, -2, -1, 0, 1, 2, 3
35 assert(NewLog2LMUL <= 3 && NewLog2LMUL >= -3 && "Bad LMUL number!");
36 Log2LMUL = NewLog2LMUL;
37}
38
39std::string LMULType::str() const {
40 if (Log2LMUL < 0)
41 return "mf" + utostr(X: 1ULL << (-Log2LMUL));
42 return "m" + utostr(X: 1ULL << Log2LMUL);
43}
44
45VScaleVal LMULType::getScale(unsigned ElementBitwidth) const {
46 int Log2ScaleResult = 0;
47 switch (ElementBitwidth) {
48 default:
49 break;
50 case 8:
51 Log2ScaleResult = Log2LMUL + 3;
52 break;
53 case 16:
54 Log2ScaleResult = Log2LMUL + 2;
55 break;
56 case 32:
57 Log2ScaleResult = Log2LMUL + 1;
58 break;
59 case 64:
60 Log2ScaleResult = Log2LMUL;
61 break;
62 }
63 // Illegal vscale result would be less than 1
64 if (Log2ScaleResult < 0)
65 return std::nullopt;
66 return 1 << Log2ScaleResult;
67}
68
69void LMULType::MulLog2LMUL(int log2LMUL) { Log2LMUL += log2LMUL; }
70
71RVVType::RVVType(BasicType BT, int Log2LMUL,
72 const PrototypeDescriptor &prototype)
73 : BT(BT), LMUL(LMULType(Log2LMUL)) {
74 applyBasicType();
75 applyModifier(prototype);
76 Valid = verifyType();
77 if (Valid) {
78 initBuiltinStr();
79 initTypeStr();
80 if (isVector()) {
81 initClangBuiltinStr();
82 }
83 }
84}
85
86// clang-format off
87// boolean type are encoded the ratio of n (SEW/LMUL)
88// SEW/LMUL | 1 | 2 | 4 | 8 | 16 | 32 | 64
89// c type | vbool64_t | vbool32_t | vbool16_t | vbool8_t | vbool4_t | vbool2_t | vbool1_t
90// IR type | nxv1i1 | nxv2i1 | nxv4i1 | nxv8i1 | nxv16i1 | nxv32i1 | nxv64i1
91
92// type\lmul | 1/8 | 1/4 | 1/2 | 1 | 2 | 4 | 8
93// -------- |------ | -------- | ------- | ------- | -------- | -------- | --------
94// i64 | N/A | N/A | N/A | nxv1i64 | nxv2i64 | nxv4i64 | nxv8i64
95// i32 | N/A | N/A | nxv1i32 | nxv2i32 | nxv4i32 | nxv8i32 | nxv16i32
96// i16 | N/A | nxv1i16 | nxv2i16 | nxv4i16 | nxv8i16 | nxv16i16 | nxv32i16
97// i8 | nxv1i8 | nxv2i8 | nxv4i8 | nxv8i8 | nxv16i8 | nxv32i8 | nxv64i8
98// double | N/A | N/A | N/A | nxv1f64 | nxv2f64 | nxv4f64 | nxv8f64
99// float | N/A | N/A | nxv1f32 | nxv2f32 | nxv4f32 | nxv8f32 | nxv16f32
100// half | N/A | nxv1f16 | nxv2f16 | nxv4f16 | nxv8f16 | nxv16f16 | nxv32f16
101// bfloat16 | N/A | nxv1bf16 | nxv2bf16| nxv4bf16| nxv8bf16 | nxv16bf16| nxv32bf16
102// clang-format on
103
104bool RVVType::verifyType() const {
105 if (ScalarType == Invalid)
106 return false;
107 if (isScalar())
108 return true;
109 if (!Scale)
110 return false;
111 if (isFloat() && ElementBitwidth == 8)
112 return false;
113 if (isBFloat() && ElementBitwidth != 16)
114 return false;
115 if (IsTuple && (NF == 1 || NF > 8))
116 return false;
117 if (IsTuple && (1 << std::max(a: 0, b: LMUL.Log2LMUL)) * NF > 8)
118 return false;
119 unsigned V = *Scale;
120 switch (ElementBitwidth) {
121 case 1:
122 case 8:
123 // Check Scale is 1,2,4,8,16,32,64
124 return (V <= 64 && isPowerOf2_32(Value: V));
125 case 16:
126 // Check Scale is 1,2,4,8,16,32
127 return (V <= 32 && isPowerOf2_32(Value: V));
128 case 32:
129 // Check Scale is 1,2,4,8,16
130 return (V <= 16 && isPowerOf2_32(Value: V));
131 case 64:
132 // Check Scale is 1,2,4,8
133 return (V <= 8 && isPowerOf2_32(Value: V));
134 }
135 return false;
136}
137
138void RVVType::initBuiltinStr() {
139 assert(isValid() && "RVVType is invalid");
140 switch (ScalarType) {
141 case ScalarTypeKind::Void:
142 BuiltinStr = "v";
143 return;
144 case ScalarTypeKind::Size_t:
145 BuiltinStr = "z";
146 if (IsImmediate)
147 BuiltinStr = "I" + BuiltinStr;
148 if (IsPointer)
149 BuiltinStr += "*";
150 return;
151 case ScalarTypeKind::Ptrdiff_t:
152 BuiltinStr = "Y";
153 return;
154 case ScalarTypeKind::UnsignedLong:
155 BuiltinStr = "ULi";
156 return;
157 case ScalarTypeKind::SignedLong:
158 BuiltinStr = "Li";
159 return;
160 case ScalarTypeKind::Boolean:
161 assert(ElementBitwidth == 1);
162 BuiltinStr += "b";
163 break;
164 case ScalarTypeKind::SignedInteger:
165 case ScalarTypeKind::UnsignedInteger:
166 switch (ElementBitwidth) {
167 case 8:
168 BuiltinStr += "c";
169 break;
170 case 16:
171 BuiltinStr += "s";
172 break;
173 case 32:
174 BuiltinStr += "i";
175 break;
176 case 64:
177 BuiltinStr += "Wi";
178 break;
179 default:
180 llvm_unreachable("Unhandled ElementBitwidth!");
181 }
182 if (isSignedInteger())
183 BuiltinStr = "S" + BuiltinStr;
184 else
185 BuiltinStr = "U" + BuiltinStr;
186 break;
187 case ScalarTypeKind::Float:
188 switch (ElementBitwidth) {
189 case 16:
190 BuiltinStr += "x";
191 break;
192 case 32:
193 BuiltinStr += "f";
194 break;
195 case 64:
196 BuiltinStr += "d";
197 break;
198 default:
199 llvm_unreachable("Unhandled ElementBitwidth!");
200 }
201 break;
202 case ScalarTypeKind::BFloat:
203 BuiltinStr += "y";
204 break;
205 case ScalarTypeKind::FloatE4M3:
206 BuiltinStr += "a";
207 break;
208 case ScalarTypeKind::FloatE5M2:
209 BuiltinStr += "b";
210 break;
211 default:
212 llvm_unreachable("ScalarType is invalid!");
213 }
214 if (IsImmediate)
215 BuiltinStr = "I" + BuiltinStr;
216 if (isScalar()) {
217 if (IsConstant)
218 BuiltinStr += "C";
219 if (IsPointer)
220 BuiltinStr += "*";
221 return;
222 }
223 BuiltinStr = "q" + utostr(X: *Scale) + BuiltinStr;
224 // Pointer to vector types. Defined for segment load intrinsics.
225 // segment load intrinsics have pointer type arguments to store the loaded
226 // vector values.
227 if (IsPointer)
228 BuiltinStr += "*";
229
230 if (IsTuple)
231 BuiltinStr = "T" + utostr(X: NF) + BuiltinStr;
232}
233
234void RVVType::initClangBuiltinStr() {
235 assert(isValid() && "RVVType is invalid");
236 assert(isVector() && "Handle Vector type only");
237
238 ClangBuiltinStr = "__rvv_";
239 switch (ScalarType) {
240 case ScalarTypeKind::Boolean:
241 ClangBuiltinStr += "bool" + utostr(X: 64 / *Scale) + "_t";
242 return;
243 case ScalarTypeKind::Float:
244 ClangBuiltinStr += "float";
245 break;
246 case ScalarTypeKind::BFloat:
247 ClangBuiltinStr += "bfloat";
248 break;
249 case ScalarTypeKind::SignedInteger:
250 ClangBuiltinStr += "int";
251 break;
252 case ScalarTypeKind::UnsignedInteger:
253 case ScalarTypeKind::FloatE4M3:
254 case ScalarTypeKind::FloatE5M2:
255 ClangBuiltinStr += "uint";
256 break;
257 default:
258 llvm_unreachable("ScalarTypeKind is invalid");
259 }
260 ClangBuiltinStr += utostr(X: ElementBitwidth) + LMUL.str() +
261 (IsTuple ? "x" + utostr(X: 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(X: NF) : "") + "_t")
275 .str();
276 };
277
278 switch (ScalarType) {
279 case ScalarTypeKind::Void:
280 Str = "void";
281 return;
282 case ScalarTypeKind::Size_t:
283 Str = "size_t";
284 if (IsPointer)
285 Str += " *";
286 return;
287 case ScalarTypeKind::Ptrdiff_t:
288 Str = "ptrdiff_t";
289 return;
290 case ScalarTypeKind::UnsignedLong:
291 Str = "unsigned long";
292 return;
293 case ScalarTypeKind::SignedLong:
294 Str = "long";
295 return;
296 case ScalarTypeKind::Boolean:
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(X: 64 / *Scale) + "_t";
303 break;
304 case ScalarTypeKind::Float:
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;
317 case ScalarTypeKind::BFloat:
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;
326 case ScalarTypeKind::SignedInteger:
327 Str += getTypeString("int");
328 break;
329 case ScalarTypeKind::UnsignedInteger:
330 case ScalarTypeKind::FloatE4M3:
331 case ScalarTypeKind::FloatE5M2:
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) {
343 case ScalarTypeKind::Boolean:
344 assert(isVector());
345 ShortStr = "b" + utostr(X: 64 / *Scale);
346 return;
347 case ScalarTypeKind::Float:
348 ShortStr = "f" + utostr(X: ElementBitwidth);
349 break;
350 case ScalarTypeKind::BFloat:
351 ShortStr = "bf" + utostr(X: ElementBitwidth);
352 break;
353 case ScalarTypeKind::SignedInteger:
354 ShortStr = "i" + utostr(X: ElementBitwidth);
355 break;
356 case ScalarTypeKind::UnsignedInteger:
357 ShortStr = "u" + utostr(X: ElementBitwidth);
358 break;
359 case ScalarTypeKind::FloatE4M3:
360 ShortStr = "f8e4m3";
361 break;
362 case ScalarTypeKind::FloatE5M2:
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(X: 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;
384 ScalarType = ScalarTypeKind::SignedInteger;
385 break;
386 case BasicType::Int16:
387 ElementBitwidth = 16;
388 ScalarType = ScalarTypeKind::SignedInteger;
389 break;
390 case BasicType::Int32:
391 ElementBitwidth = 32;
392 ScalarType = ScalarTypeKind::SignedInteger;
393 break;
394 case BasicType::Int64:
395 ElementBitwidth = 64;
396 ScalarType = ScalarTypeKind::SignedInteger;
397 break;
398 case BasicType::Float16:
399 ElementBitwidth = 16;
400 ScalarType = ScalarTypeKind::Float;
401 break;
402 case BasicType::Float32:
403 ElementBitwidth = 32;
404 ScalarType = ScalarTypeKind::Float;
405 break;
406 case BasicType::Float64:
407 ElementBitwidth = 64;
408 ScalarType = ScalarTypeKind::Float;
409 break;
410 case BasicType::BFloat16:
411 ElementBitwidth = 16;
412 ScalarType = ScalarTypeKind::BFloat;
413 break;
414 case BasicType::F8E4M3:
415 ElementBitwidth = 8;
416 ScalarType = ScalarTypeKind::FloatE4M3;
417 break;
418 case BasicType::F8E5M2:
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>
429PrototypeDescriptor::parsePrototypeDescriptor(
430 llvm::StringRef PrototypeDescriptorStr) {
431 PrototypeDescriptor PD;
432 BaseTypeModifier PT = BaseTypeModifier::Invalid;
433 VectorTypeModifier VTM = VectorTypeModifier::NoModifier;
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':
442 PT = BaseTypeModifier::Scalar;
443 break;
444 case 'v':
445 PT = BaseTypeModifier::Vector;
446 break;
447 case 'w':
448 PT = BaseTypeModifier::Vector;
449 VTM = VectorTypeModifier::Widening2XVector;
450 break;
451 case 'q':
452 PT = BaseTypeModifier::Vector;
453 VTM = VectorTypeModifier::Widening4XVector;
454 break;
455 case 'o':
456 PT = BaseTypeModifier::Vector;
457 VTM = VectorTypeModifier::Widening8XVector;
458 break;
459 case 'm':
460 PT = BaseTypeModifier::Vector;
461 VTM = VectorTypeModifier::MaskVector;
462 break;
463 case '0':
464 PT = BaseTypeModifier::Void;
465 break;
466 case 'z':
467 PT = BaseTypeModifier::SizeT;
468 break;
469 case 't':
470 PT = BaseTypeModifier::Ptrdiff;
471 break;
472 case 'u':
473 PT = BaseTypeModifier::UnsignedLong;
474 break;
475 case 'l':
476 PT = BaseTypeModifier::SignedLong;
477 break;
478 case 'f':
479 PT = BaseTypeModifier::Float32;
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(Prefix: "(")) {
489 assert(VTM == VectorTypeModifier::NoModifier &&
490 "VectorTypeModifier should only have one modifier");
491 size_t Idx = PrototypeDescriptorStr.find(C: ')');
492 assert(Idx != StringRef::npos);
493 StringRef ComplexType = PrototypeDescriptorStr.slice(Start: 1, End: Idx);
494 PrototypeDescriptorStr = PrototypeDescriptorStr.drop_front(N: Idx + 1);
495 assert(!PrototypeDescriptorStr.contains('(') &&
496 "Only allow one vector type modifier");
497
498 auto ComplexTT = ComplexType.split(Separator: ":");
499 if (ComplexTT.first == "Log2EEW") {
500 uint32_t Log2EEW;
501 if (ComplexTT.second.getAsInteger(Radix: 10, Result&: Log2EEW)) {
502 llvm_unreachable("Invalid Log2EEW value!");
503 return std::nullopt;
504 }
505 switch (Log2EEW) {
506 case 3:
507 VTM = VectorTypeModifier::Log2EEW3;
508 break;
509 case 4:
510 VTM = VectorTypeModifier::Log2EEW4;
511 break;
512 case 5:
513 VTM = VectorTypeModifier::Log2EEW5;
514 break;
515 case 6:
516 VTM = VectorTypeModifier::Log2EEW6;
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(Radix: 10, Result&: NewSEW)) {
525 llvm_unreachable("Invalid FixedSEW value!");
526 return std::nullopt;
527 }
528 switch (NewSEW) {
529 case 8:
530 VTM = VectorTypeModifier::FixedSEW8;
531 break;
532 case 16:
533 VTM = VectorTypeModifier::FixedSEW16;
534 break;
535 case 32:
536 VTM = VectorTypeModifier::FixedSEW32;
537 break;
538 case 64:
539 VTM = VectorTypeModifier::FixedSEW64;
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(Radix: 10, Result&: Log2LMUL)) {
548 llvm_unreachable("Invalid LFixedLog2LMUL value!");
549 return std::nullopt;
550 }
551 switch (Log2LMUL) {
552 case -3:
553 VTM = VectorTypeModifier::LFixedLog2LMULN3;
554 break;
555 case -2:
556 VTM = VectorTypeModifier::LFixedLog2LMULN2;
557 break;
558 case -1:
559 VTM = VectorTypeModifier::LFixedLog2LMULN1;
560 break;
561 case 0:
562 VTM = VectorTypeModifier::LFixedLog2LMUL0;
563 break;
564 case 1:
565 VTM = VectorTypeModifier::LFixedLog2LMUL1;
566 break;
567 case 2:
568 VTM = VectorTypeModifier::LFixedLog2LMUL2;
569 break;
570 case 3:
571 VTM = VectorTypeModifier::LFixedLog2LMUL3;
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(Radix: 10, Result&: Log2LMUL)) {
580 llvm_unreachable("Invalid SFixedLog2LMUL value!");
581 return std::nullopt;
582 }
583 switch (Log2LMUL) {
584 case -3:
585 VTM = VectorTypeModifier::SFixedLog2LMULN3;
586 break;
587 case -2:
588 VTM = VectorTypeModifier::SFixedLog2LMULN2;
589 break;
590 case -1:
591 VTM = VectorTypeModifier::SFixedLog2LMULN1;
592 break;
593 case 0:
594 VTM = VectorTypeModifier::SFixedLog2LMUL0;
595 break;
596 case 1:
597 VTM = VectorTypeModifier::SFixedLog2LMUL1;
598 break;
599 case 2:
600 VTM = VectorTypeModifier::SFixedLog2LMUL2;
601 break;
602 case 3:
603 VTM = VectorTypeModifier::SFixedLog2LMUL3;
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(Radix: 10, Result&: Log2LMUL)) {
613 llvm_unreachable("Invalid SEFixedLog2LMUL value!");
614 return std::nullopt;
615 }
616 switch (Log2LMUL) {
617 case -3:
618 VTM = VectorTypeModifier::SEFixedLog2LMULN3;
619 break;
620 case -2:
621 VTM = VectorTypeModifier::SEFixedLog2LMULN2;
622 break;
623 case -1:
624 VTM = VectorTypeModifier::SEFixedLog2LMULN1;
625 break;
626 case 0:
627 VTM = VectorTypeModifier::SEFixedLog2LMUL0;
628 break;
629 case 1:
630 VTM = VectorTypeModifier::SEFixedLog2LMUL1;
631 break;
632 case 2:
633 VTM = VectorTypeModifier::SEFixedLog2LMUL2;
634 break;
635 case 3:
636 VTM = VectorTypeModifier::SEFixedLog2LMUL3;
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(Radix: 10, Result&: 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
656 TypeModifier TM = TypeModifier::NoModifier;
657 for (char I : PrototypeDescriptorStr) {
658 switch (I) {
659 case 'P':
660 if ((TM & TypeModifier::Const) == TypeModifier::Const)
661 llvm_unreachable("'P' transformer cannot be used after 'C'");
662 if ((TM & TypeModifier::Pointer) == TypeModifier::Pointer)
663 llvm_unreachable("'P' transformer cannot be used twice");
664 TM |= TypeModifier::Pointer;
665 break;
666 case 'C':
667 TM |= TypeModifier::Const;
668 break;
669 case 'K':
670 TM |= TypeModifier::Immediate;
671 break;
672 case 'U':
673 TM |= TypeModifier::UnsignedInteger;
674 break;
675 case 'I':
676 TM |= TypeModifier::SignedInteger;
677 break;
678 case 'F':
679 TM |= TypeModifier::Float;
680 break;
681 case 'Y':
682 TM |= TypeModifier::BFloat;
683 break;
684 case 'S':
685 TM |= TypeModifier::LMUL1;
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)) {
699 case BaseTypeModifier::Scalar:
700 Scale = 0;
701 break;
702 case BaseTypeModifier::Vector:
703 Scale = LMUL.getScale(ElementBitwidth);
704 break;
705 case BaseTypeModifier::Void:
706 ScalarType = ScalarTypeKind::Void;
707 break;
708 case BaseTypeModifier::SizeT:
709 ScalarType = ScalarTypeKind::Size_t;
710 break;
711 case BaseTypeModifier::Ptrdiff:
712 ScalarType = ScalarTypeKind::Ptrdiff_t;
713 break;
714 case BaseTypeModifier::UnsignedLong:
715 ScalarType = ScalarTypeKind::UnsignedLong;
716 break;
717 case BaseTypeModifier::SignedLong:
718 ScalarType = ScalarTypeKind::SignedLong;
719 break;
720 case BaseTypeModifier::Float32:
721 ElementBitwidth = 32;
722 ScalarType = ScalarTypeKind::Float;
723 break;
724 case BaseTypeModifier::Invalid:
725 ScalarType = ScalarTypeKind::Invalid;
726 return;
727 }
728
729 switch (static_cast<VectorTypeModifier>(Transformer.VTM)) {
730 case VectorTypeModifier::Widening2XVector:
731 ElementBitwidth *= 2;
732 LMUL.MulLog2LMUL(log2LMUL: 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;
740 case VectorTypeModifier::Widening4XVector:
741 ElementBitwidth *= 4;
742 LMUL.MulLog2LMUL(log2LMUL: 2);
743 Scale = LMUL.getScale(ElementBitwidth);
744 if (ScalarType == ScalarTypeKind::FloatE4M3 ||
745 ScalarType == ScalarTypeKind::FloatE5M2)
746 ScalarType = ScalarTypeKind::Float;
747 break;
748 case VectorTypeModifier::Widening8XVector:
749 ElementBitwidth *= 8;
750 LMUL.MulLog2LMUL(log2LMUL: 3);
751 Scale = LMUL.getScale(ElementBitwidth);
752 break;
753 case VectorTypeModifier::MaskVector:
754 ScalarType = ScalarTypeKind::Boolean;
755 Scale = LMUL.getScale(ElementBitwidth);
756 ElementBitwidth = 1;
757 break;
758 case VectorTypeModifier::Log2EEW3:
759 applyLog2EEW(Log2EEW: 3);
760 break;
761 case VectorTypeModifier::Log2EEW4:
762 applyLog2EEW(Log2EEW: 4);
763 break;
764 case VectorTypeModifier::Log2EEW5:
765 applyLog2EEW(Log2EEW: 5);
766 break;
767 case VectorTypeModifier::Log2EEW6:
768 applyLog2EEW(Log2EEW: 6);
769 break;
770 case VectorTypeModifier::FixedSEW8:
771 applyFixedSEW(NewSEW: 8);
772 break;
773 case VectorTypeModifier::FixedSEW16:
774 applyFixedSEW(NewSEW: 16);
775 break;
776 case VectorTypeModifier::FixedSEW32:
777 applyFixedSEW(NewSEW: 32);
778 break;
779 case VectorTypeModifier::FixedSEW64:
780 applyFixedSEW(NewSEW: 64);
781 break;
782 case VectorTypeModifier::LFixedLog2LMULN3:
783 applyFixedLog2LMUL(Log2LMUL: -3, Type: FixedLMULType::LargerThan);
784 break;
785 case VectorTypeModifier::LFixedLog2LMULN2:
786 applyFixedLog2LMUL(Log2LMUL: -2, Type: FixedLMULType::LargerThan);
787 break;
788 case VectorTypeModifier::LFixedLog2LMULN1:
789 applyFixedLog2LMUL(Log2LMUL: -1, Type: FixedLMULType::LargerThan);
790 break;
791 case VectorTypeModifier::LFixedLog2LMUL0:
792 applyFixedLog2LMUL(Log2LMUL: 0, Type: FixedLMULType::LargerThan);
793 break;
794 case VectorTypeModifier::LFixedLog2LMUL1:
795 applyFixedLog2LMUL(Log2LMUL: 1, Type: FixedLMULType::LargerThan);
796 break;
797 case VectorTypeModifier::LFixedLog2LMUL2:
798 applyFixedLog2LMUL(Log2LMUL: 2, Type: FixedLMULType::LargerThan);
799 break;
800 case VectorTypeModifier::LFixedLog2LMUL3:
801 applyFixedLog2LMUL(Log2LMUL: 3, Type: FixedLMULType::LargerThan);
802 break;
803 case VectorTypeModifier::SFixedLog2LMULN3:
804 applyFixedLog2LMUL(Log2LMUL: -3, Type: FixedLMULType::SmallerThan);
805 break;
806 case VectorTypeModifier::SFixedLog2LMULN2:
807 applyFixedLog2LMUL(Log2LMUL: -2, Type: FixedLMULType::SmallerThan);
808 break;
809 case VectorTypeModifier::SFixedLog2LMULN1:
810 applyFixedLog2LMUL(Log2LMUL: -1, Type: FixedLMULType::SmallerThan);
811 break;
812 case VectorTypeModifier::SFixedLog2LMUL0:
813 applyFixedLog2LMUL(Log2LMUL: 0, Type: FixedLMULType::SmallerThan);
814 break;
815 case VectorTypeModifier::SFixedLog2LMUL1:
816 applyFixedLog2LMUL(Log2LMUL: 1, Type: FixedLMULType::SmallerThan);
817 break;
818 case VectorTypeModifier::SFixedLog2LMUL2:
819 applyFixedLog2LMUL(Log2LMUL: 2, Type: FixedLMULType::SmallerThan);
820 break;
821 case VectorTypeModifier::SFixedLog2LMUL3:
822 applyFixedLog2LMUL(Log2LMUL: 3, Type: FixedLMULType::SmallerThan);
823 break;
824 case VectorTypeModifier::SEFixedLog2LMULN3:
825 applyFixedLog2LMUL(Log2LMUL: -3, Type: FixedLMULType::SmallerOrEqual);
826 break;
827 case VectorTypeModifier::SEFixedLog2LMULN2:
828 applyFixedLog2LMUL(Log2LMUL: -2, Type: FixedLMULType::SmallerOrEqual);
829 break;
830 case VectorTypeModifier::SEFixedLog2LMULN1:
831 applyFixedLog2LMUL(Log2LMUL: -1, Type: FixedLMULType::SmallerOrEqual);
832 break;
833 case VectorTypeModifier::SEFixedLog2LMUL0:
834 applyFixedLog2LMUL(Log2LMUL: 0, Type: FixedLMULType::SmallerOrEqual);
835 break;
836 case VectorTypeModifier::SEFixedLog2LMUL1:
837 applyFixedLog2LMUL(Log2LMUL: 1, Type: FixedLMULType::SmallerOrEqual);
838 break;
839 case VectorTypeModifier::SEFixedLog2LMUL2:
840 applyFixedLog2LMUL(Log2LMUL: 2, Type: FixedLMULType::SmallerOrEqual);
841 break;
842 case VectorTypeModifier::SEFixedLog2LMUL3:
843 applyFixedLog2LMUL(Log2LMUL: 3, Type: FixedLMULType::SmallerOrEqual);
844 break;
845 case VectorTypeModifier::Tuple2:
846 case VectorTypeModifier::Tuple3:
847 case VectorTypeModifier::Tuple4:
848 case VectorTypeModifier::Tuple5:
849 case VectorTypeModifier::Tuple6:
850 case VectorTypeModifier::Tuple7:
851 case VectorTypeModifier::Tuple8: {
852 IsTuple = true;
853 NF = 2 + static_cast<uint8_t>(Transformer.VTM) -
854 static_cast<uint8_t>(VectorTypeModifier::Tuple2);
855 break;
856 }
857 case VectorTypeModifier::NoModifier:
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)) {
873 case TypeModifier::Pointer:
874 IsPointer = true;
875 break;
876 case TypeModifier::Const:
877 IsConstant = true;
878 break;
879 case TypeModifier::Immediate:
880 IsImmediate = true;
881 IsConstant = true;
882 break;
883 case TypeModifier::UnsignedInteger:
884 ScalarType = ScalarTypeKind::UnsignedInteger;
885 break;
886 case TypeModifier::SignedInteger:
887 ScalarType = ScalarTypeKind::SignedInteger;
888 break;
889 case TypeModifier::Float:
890 ScalarType = ScalarTypeKind::Float;
891 break;
892 case TypeModifier::BFloat:
893 ScalarType = ScalarTypeKind::BFloat;
894 break;
895 case TypeModifier::LMUL1:
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(log2LMUL: Log2EEW - Log2_32(Value: ElementBitwidth));
909 // update new eew
910 ElementBitwidth = 1 << Log2EEW;
911 ScalarType = ScalarTypeKind::SignedInteger;
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,
955 ArrayRef<PrototypeDescriptor> Prototype) {
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(x: *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(x: Idx);
985 if (It != LegalTypes.end())
986 return &(It->second);
987
988 if (IllegalTypes.count(x: 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(x: {Idx, T});
997 return &(InsertResult.first->second);
998 }
999 // Record illegal type index.
1000 IllegalTypes.insert(x: 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(Separator: "_").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: hasPolicy(), Name, BuiltinName, OverloadedName,
1036 PolicyAttrs, HasFRMRoundModeOp, AltFmt);
1037
1038 // Init OutputType and InputTypes
1039 OutputType = OutInTypes[0];
1040 InputTypes.assign(first: OutInTypes.begin() + 1, last: 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
1054std::string RVVIntrinsic::getBuiltinTypeStr() const {
1055 std::string S;
1056 S += OutputType->getBuiltinStr();
1057 for (const auto &T : InputTypes) {
1058 S += T->getBuiltinStr();
1059 }
1060 return S;
1061}
1062
1063std::string RVVIntrinsic::getSuffixStr(
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(BT: Type, Log2LMUL, Proto: PD);
1069 SuffixStrs.push_back(Elt: (*T)->getShortStr());
1070 }
1071 return join(R&: SuffixStrs, Separator: "_");
1072}
1073
1074llvm::SmallVector<PrototypeDescriptor> RVVIntrinsic::computeBuiltinTypes(
1075 llvm::ArrayRef<PrototypeDescriptor> Prototype, bool IsMasked,
1076 bool HasMaskedOffOperand, bool HasVL, unsigned NF,
1077 PolicyScheme DefaultScheme, Policy PolicyAttrs, bool IsTuple) {
1078 SmallVector<PrototypeDescriptor> NewPrototype(Prototype);
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(I: NewPrototype.begin() + 1, Elt: NewPrototype[0]);
1086 } else if (NF > 1) {
1087 if (IsTuple) {
1088 PrototypeDescriptor BasePtrOperand = Prototype[1];
1089 PrototypeDescriptor MaskoffType = PrototypeDescriptor(
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(I: NewPrototype.begin() + 1, Elt: 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(I: NewPrototype.begin() + NF + 1, NumToInsert: NF, Elt: 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(I: NewPrototype.begin() + 1,
1113 Elt: PrototypeDescriptor::Mask);
1114 else
1115 NewPrototype.insert(I: NewPrototype.begin() + NF + 1,
1116 Elt: PrototypeDescriptor::Mask);
1117 } else {
1118 // If IsMasked, insert PrototypeDescriptor:Mask as first input operand.
1119 NewPrototype.insert(I: NewPrototype.begin() + 1, Elt: PrototypeDescriptor::Mask);
1120 }
1121 } else {
1122 if (NF == 1) {
1123 if (PolicyAttrs.isTUPolicy() && HasPassthruOp)
1124 NewPrototype.insert(I: NewPrototype.begin(), Elt: NewPrototype[0]);
1125 } else if (PolicyAttrs.isTUPolicy() && HasPassthruOp) {
1126 if (IsTuple) {
1127 PrototypeDescriptor BasePtrOperand = Prototype[0];
1128 PrototypeDescriptor MaskoffType = PrototypeDescriptor(
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(I: NewPrototype.begin(), Elt: 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(I: NewPrototype.begin() + NF + 1, NumToInsert: NF, Elt: MaskoffType);
1142 }
1143 }
1144 }
1145
1146 // If HasVL, append PrototypeDescriptor:VL to last operand
1147 if (HasVL)
1148 NewPrototype.push_back(Elt: PrototypeDescriptor::VL);
1149
1150 return NewPrototype;
1151}
1152
1153llvm::SmallVector<Policy> RVVIntrinsic::getSupportedUnMaskedPolicies() {
1154 return {Policy(Policy::PolicyType::Undisturbed)}; // TU
1155}
1156
1157llvm::SmallVector<Policy>
1158RVVIntrinsic::getSupportedMaskedPolicies(bool HasTailPolicy,
1159 bool HasMaskPolicy) {
1160 if (HasTailPolicy && HasMaskPolicy)
1161 return {Policy(Policy::PolicyType::Undisturbed,
1162 Policy::PolicyType::Agnostic), // TUM
1163 Policy(Policy::PolicyType::Undisturbed,
1164 Policy::PolicyType::Undisturbed), // TUMU
1165 Policy(Policy::PolicyType::Agnostic,
1166 Policy::PolicyType::Undisturbed)}; // MU
1167 if (HasTailPolicy && !HasMaskPolicy)
1168 return {Policy(Policy::PolicyType::Undisturbed,
1169 Policy::PolicyType::Agnostic)}; // TU
1170 if (!HasTailPolicy && HasMaskPolicy)
1171 return {Policy(Policy::PolicyType::Agnostic,
1172 Policy::PolicyType::Undisturbed)}; // MU
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
1220SmallVector<PrototypeDescriptor> parsePrototypes(StringRef Prototypes) {
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(C: ')');
1229 Idx = Prototypes.find_first_of(Chars: Primaries, From: Idx);
1230 assert(Idx != StringRef::npos);
1231 auto PD = PrototypeDescriptor::parsePrototypeDescriptor(
1232 PrototypeDescriptorStr: Prototypes.slice(Start: 0, End: Idx + 1));
1233 if (!PD)
1234 llvm_unreachable("Error during parsing prototype.");
1235 PrototypeDescriptors.push_back(Elt: *PD);
1236 Prototypes = Prototypes.drop_front(N: 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) {
1248 STRINGIFY(SchemeNone)
1249 STRINGIFY(HasPassthruOperand)
1250 STRINGIFY(HasPolicyOperand)
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
1293