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 default:
206 llvm_unreachable("ScalarType is invalid!");
207 }
208 if (IsImmediate)
209 BuiltinStr = "I" + BuiltinStr;
210 if (isScalar()) {
211 if (IsConstant)
212 BuiltinStr += "C";
213 if (IsPointer)
214 BuiltinStr += "*";
215 return;
216 }
217 BuiltinStr = "q" + utostr(X: *Scale) + BuiltinStr;
218 // Pointer to vector types. Defined for segment load intrinsics.
219 // segment load intrinsics have pointer type arguments to store the loaded
220 // vector values.
221 if (IsPointer)
222 BuiltinStr += "*";
223
224 if (IsTuple)
225 BuiltinStr = "T" + utostr(X: NF) + BuiltinStr;
226}
227
228void RVVType::initClangBuiltinStr() {
229 assert(isValid() && "RVVType is invalid");
230 assert(isVector() && "Handle Vector type only");
231
232 ClangBuiltinStr = "__rvv_";
233 switch (ScalarType) {
234 case ScalarTypeKind::Boolean:
235 ClangBuiltinStr += "bool" + utostr(X: 64 / *Scale) + "_t";
236 return;
237 case ScalarTypeKind::Float:
238 ClangBuiltinStr += "float";
239 break;
240 case ScalarTypeKind::BFloat:
241 ClangBuiltinStr += "bfloat";
242 break;
243 case ScalarTypeKind::SignedInteger:
244 ClangBuiltinStr += "int";
245 break;
246 case ScalarTypeKind::UnsignedInteger:
247 ClangBuiltinStr += "uint";
248 break;
249 default:
250 llvm_unreachable("ScalarTypeKind is invalid");
251 }
252 ClangBuiltinStr += utostr(X: ElementBitwidth) + LMUL.str() +
253 (IsTuple ? "x" + utostr(X: NF) : "") + "_t";
254}
255
256void RVVType::initTypeStr() {
257 assert(isValid() && "RVVType is invalid");
258
259 if (IsConstant)
260 Str += "const ";
261
262 auto getTypeString = [&](StringRef TypeStr) {
263 if (isScalar())
264 return Twine(TypeStr + Twine(ElementBitwidth) + "_t").str();
265 return Twine("v" + TypeStr + Twine(ElementBitwidth) + LMUL.str() +
266 (IsTuple ? "x" + utostr(X: NF) : "") + "_t")
267 .str();
268 };
269
270 switch (ScalarType) {
271 case ScalarTypeKind::Void:
272 Str = "void";
273 return;
274 case ScalarTypeKind::Size_t:
275 Str = "size_t";
276 if (IsPointer)
277 Str += " *";
278 return;
279 case ScalarTypeKind::Ptrdiff_t:
280 Str = "ptrdiff_t";
281 return;
282 case ScalarTypeKind::UnsignedLong:
283 Str = "unsigned long";
284 return;
285 case ScalarTypeKind::SignedLong:
286 Str = "long";
287 return;
288 case ScalarTypeKind::Boolean:
289 if (isScalar())
290 Str += "bool";
291 else
292 // Vector bool is special case, the formulate is
293 // `vbool<N>_t = MVT::nxv<64/N>i1` ex. vbool16_t = MVT::4i1
294 Str += "vbool" + utostr(X: 64 / *Scale) + "_t";
295 break;
296 case ScalarTypeKind::Float:
297 if (isScalar()) {
298 if (ElementBitwidth == 64)
299 Str += "double";
300 else if (ElementBitwidth == 32)
301 Str += "float";
302 else if (ElementBitwidth == 16)
303 Str += "_Float16";
304 else
305 llvm_unreachable("Unhandled floating type.");
306 } else
307 Str += getTypeString("float");
308 break;
309 case ScalarTypeKind::BFloat:
310 if (isScalar()) {
311 if (ElementBitwidth == 16)
312 Str += "__bf16";
313 else
314 llvm_unreachable("Unhandled floating type.");
315 } else
316 Str += getTypeString("bfloat");
317 break;
318 case ScalarTypeKind::SignedInteger:
319 Str += getTypeString("int");
320 break;
321 case ScalarTypeKind::UnsignedInteger:
322 Str += getTypeString("uint");
323 break;
324 default:
325 llvm_unreachable("ScalarType is invalid!");
326 }
327 if (IsPointer)
328 Str += " *";
329}
330
331void RVVType::initShortStr() {
332 switch (ScalarType) {
333 case ScalarTypeKind::Boolean:
334 assert(isVector());
335 ShortStr = "b" + utostr(X: 64 / *Scale);
336 return;
337 case ScalarTypeKind::Float:
338 ShortStr = "f" + utostr(X: ElementBitwidth);
339 break;
340 case ScalarTypeKind::BFloat:
341 ShortStr = "bf" + utostr(X: ElementBitwidth);
342 break;
343 case ScalarTypeKind::SignedInteger:
344 ShortStr = "i" + utostr(X: ElementBitwidth);
345 break;
346 case ScalarTypeKind::UnsignedInteger:
347 ShortStr = "u" + utostr(X: ElementBitwidth);
348 break;
349 default:
350 llvm_unreachable("Unhandled case!");
351 }
352 if (isVector())
353 ShortStr += LMUL.str();
354 if (isTuple())
355 ShortStr += "x" + utostr(X: NF);
356}
357
358static VectorTypeModifier getTupleVTM(unsigned NF) {
359 assert(2 <= NF && NF <= 8 && "2 <= NF <= 8");
360 return static_cast<VectorTypeModifier>(
361 static_cast<uint8_t>(VectorTypeModifier::Tuple2) + (NF - 2));
362}
363
364void RVVType::applyBasicType() {
365 switch (BT) {
366 case BasicType::Int8:
367 ElementBitwidth = 8;
368 ScalarType = ScalarTypeKind::SignedInteger;
369 break;
370 case BasicType::Int16:
371 ElementBitwidth = 16;
372 ScalarType = ScalarTypeKind::SignedInteger;
373 break;
374 case BasicType::Int32:
375 ElementBitwidth = 32;
376 ScalarType = ScalarTypeKind::SignedInteger;
377 break;
378 case BasicType::Int64:
379 ElementBitwidth = 64;
380 ScalarType = ScalarTypeKind::SignedInteger;
381 break;
382 case BasicType::Float16:
383 ElementBitwidth = 16;
384 ScalarType = ScalarTypeKind::Float;
385 break;
386 case BasicType::Float32:
387 ElementBitwidth = 32;
388 ScalarType = ScalarTypeKind::Float;
389 break;
390 case BasicType::Float64:
391 ElementBitwidth = 64;
392 ScalarType = ScalarTypeKind::Float;
393 break;
394 case BasicType::BFloat16:
395 ElementBitwidth = 16;
396 ScalarType = ScalarTypeKind::BFloat;
397 break;
398 default:
399 llvm_unreachable("Unhandled type code!");
400 }
401 assert(ElementBitwidth != 0 && "Bad element bitwidth!");
402}
403
404std::optional<PrototypeDescriptor>
405PrototypeDescriptor::parsePrototypeDescriptor(
406 llvm::StringRef PrototypeDescriptorStr) {
407 PrototypeDescriptor PD;
408 BaseTypeModifier PT = BaseTypeModifier::Invalid;
409 VectorTypeModifier VTM = VectorTypeModifier::NoModifier;
410
411 if (PrototypeDescriptorStr.empty())
412 return PD;
413
414 // Handle base type modifier
415 auto PType = PrototypeDescriptorStr.back();
416 switch (PType) {
417 case 'e':
418 PT = BaseTypeModifier::Scalar;
419 break;
420 case 'v':
421 PT = BaseTypeModifier::Vector;
422 break;
423 case 'w':
424 PT = BaseTypeModifier::Vector;
425 VTM = VectorTypeModifier::Widening2XVector;
426 break;
427 case 'q':
428 PT = BaseTypeModifier::Vector;
429 VTM = VectorTypeModifier::Widening4XVector;
430 break;
431 case 'o':
432 PT = BaseTypeModifier::Vector;
433 VTM = VectorTypeModifier::Widening8XVector;
434 break;
435 case 'm':
436 PT = BaseTypeModifier::Vector;
437 VTM = VectorTypeModifier::MaskVector;
438 break;
439 case '0':
440 PT = BaseTypeModifier::Void;
441 break;
442 case 'z':
443 PT = BaseTypeModifier::SizeT;
444 break;
445 case 't':
446 PT = BaseTypeModifier::Ptrdiff;
447 break;
448 case 'u':
449 PT = BaseTypeModifier::UnsignedLong;
450 break;
451 case 'l':
452 PT = BaseTypeModifier::SignedLong;
453 break;
454 case 'f':
455 PT = BaseTypeModifier::Float32;
456 break;
457 default:
458 llvm_unreachable("Illegal primitive type transformers!");
459 }
460 PD.PT = static_cast<uint8_t>(PT);
461 PrototypeDescriptorStr = PrototypeDescriptorStr.drop_back();
462
463 // Compute the vector type transformers, it can only appear one time.
464 if (PrototypeDescriptorStr.starts_with(Prefix: "(")) {
465 assert(VTM == VectorTypeModifier::NoModifier &&
466 "VectorTypeModifier should only have one modifier");
467 size_t Idx = PrototypeDescriptorStr.find(C: ')');
468 assert(Idx != StringRef::npos);
469 StringRef ComplexType = PrototypeDescriptorStr.slice(Start: 1, End: Idx);
470 PrototypeDescriptorStr = PrototypeDescriptorStr.drop_front(N: Idx + 1);
471 assert(!PrototypeDescriptorStr.contains('(') &&
472 "Only allow one vector type modifier");
473
474 auto ComplexTT = ComplexType.split(Separator: ":");
475 if (ComplexTT.first == "Log2EEW") {
476 uint32_t Log2EEW;
477 if (ComplexTT.second.getAsInteger(Radix: 10, Result&: Log2EEW)) {
478 llvm_unreachable("Invalid Log2EEW value!");
479 return std::nullopt;
480 }
481 switch (Log2EEW) {
482 case 3:
483 VTM = VectorTypeModifier::Log2EEW3;
484 break;
485 case 4:
486 VTM = VectorTypeModifier::Log2EEW4;
487 break;
488 case 5:
489 VTM = VectorTypeModifier::Log2EEW5;
490 break;
491 case 6:
492 VTM = VectorTypeModifier::Log2EEW6;
493 break;
494 default:
495 llvm_unreachable("Invalid Log2EEW value, should be [3-6]");
496 return std::nullopt;
497 }
498 } else if (ComplexTT.first == "FixedSEW") {
499 uint32_t NewSEW;
500 if (ComplexTT.second.getAsInteger(Radix: 10, Result&: NewSEW)) {
501 llvm_unreachable("Invalid FixedSEW value!");
502 return std::nullopt;
503 }
504 switch (NewSEW) {
505 case 8:
506 VTM = VectorTypeModifier::FixedSEW8;
507 break;
508 case 16:
509 VTM = VectorTypeModifier::FixedSEW16;
510 break;
511 case 32:
512 VTM = VectorTypeModifier::FixedSEW32;
513 break;
514 case 64:
515 VTM = VectorTypeModifier::FixedSEW64;
516 break;
517 default:
518 llvm_unreachable("Invalid FixedSEW value, should be 8, 16, 32 or 64");
519 return std::nullopt;
520 }
521 } else if (ComplexTT.first == "LFixedLog2LMUL") {
522 int32_t Log2LMUL;
523 if (ComplexTT.second.getAsInteger(Radix: 10, Result&: Log2LMUL)) {
524 llvm_unreachable("Invalid LFixedLog2LMUL value!");
525 return std::nullopt;
526 }
527 switch (Log2LMUL) {
528 case -3:
529 VTM = VectorTypeModifier::LFixedLog2LMULN3;
530 break;
531 case -2:
532 VTM = VectorTypeModifier::LFixedLog2LMULN2;
533 break;
534 case -1:
535 VTM = VectorTypeModifier::LFixedLog2LMULN1;
536 break;
537 case 0:
538 VTM = VectorTypeModifier::LFixedLog2LMUL0;
539 break;
540 case 1:
541 VTM = VectorTypeModifier::LFixedLog2LMUL1;
542 break;
543 case 2:
544 VTM = VectorTypeModifier::LFixedLog2LMUL2;
545 break;
546 case 3:
547 VTM = VectorTypeModifier::LFixedLog2LMUL3;
548 break;
549 default:
550 llvm_unreachable("Invalid LFixedLog2LMUL value, should be [-3, 3]");
551 return std::nullopt;
552 }
553 } else if (ComplexTT.first == "SFixedLog2LMUL") {
554 int32_t Log2LMUL;
555 if (ComplexTT.second.getAsInteger(Radix: 10, Result&: Log2LMUL)) {
556 llvm_unreachable("Invalid SFixedLog2LMUL value!");
557 return std::nullopt;
558 }
559 switch (Log2LMUL) {
560 case -3:
561 VTM = VectorTypeModifier::SFixedLog2LMULN3;
562 break;
563 case -2:
564 VTM = VectorTypeModifier::SFixedLog2LMULN2;
565 break;
566 case -1:
567 VTM = VectorTypeModifier::SFixedLog2LMULN1;
568 break;
569 case 0:
570 VTM = VectorTypeModifier::SFixedLog2LMUL0;
571 break;
572 case 1:
573 VTM = VectorTypeModifier::SFixedLog2LMUL1;
574 break;
575 case 2:
576 VTM = VectorTypeModifier::SFixedLog2LMUL2;
577 break;
578 case 3:
579 VTM = VectorTypeModifier::SFixedLog2LMUL3;
580 break;
581 default:
582 llvm_unreachable("Invalid LFixedLog2LMUL value, should be [-3, 3]");
583 return std::nullopt;
584 }
585
586 } else if (ComplexTT.first == "SEFixedLog2LMUL") {
587 int32_t Log2LMUL;
588 if (ComplexTT.second.getAsInteger(Radix: 10, Result&: Log2LMUL)) {
589 llvm_unreachable("Invalid SEFixedLog2LMUL value!");
590 return std::nullopt;
591 }
592 switch (Log2LMUL) {
593 case -3:
594 VTM = VectorTypeModifier::SEFixedLog2LMULN3;
595 break;
596 case -2:
597 VTM = VectorTypeModifier::SEFixedLog2LMULN2;
598 break;
599 case -1:
600 VTM = VectorTypeModifier::SEFixedLog2LMULN1;
601 break;
602 case 0:
603 VTM = VectorTypeModifier::SEFixedLog2LMUL0;
604 break;
605 case 1:
606 VTM = VectorTypeModifier::SEFixedLog2LMUL1;
607 break;
608 case 2:
609 VTM = VectorTypeModifier::SEFixedLog2LMUL2;
610 break;
611 case 3:
612 VTM = VectorTypeModifier::SEFixedLog2LMUL3;
613 break;
614 default:
615 llvm_unreachable("Invalid LFixedLog2LMUL value, should be [-3, 3]");
616 return std::nullopt;
617 }
618 } else if (ComplexTT.first == "Tuple") {
619 unsigned NF = 0;
620 if (ComplexTT.second.getAsInteger(Radix: 10, Result&: NF)) {
621 llvm_unreachable("Invalid NF value!");
622 return std::nullopt;
623 }
624 VTM = getTupleVTM(NF);
625 } else {
626 llvm_unreachable("Illegal complex type transformers!");
627 }
628 }
629 PD.VTM = static_cast<uint8_t>(VTM);
630
631 // Compute the remain type transformers
632 TypeModifier TM = TypeModifier::NoModifier;
633 for (char I : PrototypeDescriptorStr) {
634 switch (I) {
635 case 'P':
636 if ((TM & TypeModifier::Const) == TypeModifier::Const)
637 llvm_unreachable("'P' transformer cannot be used after 'C'");
638 if ((TM & TypeModifier::Pointer) == TypeModifier::Pointer)
639 llvm_unreachable("'P' transformer cannot be used twice");
640 TM |= TypeModifier::Pointer;
641 break;
642 case 'C':
643 TM |= TypeModifier::Const;
644 break;
645 case 'K':
646 TM |= TypeModifier::Immediate;
647 break;
648 case 'U':
649 TM |= TypeModifier::UnsignedInteger;
650 break;
651 case 'I':
652 TM |= TypeModifier::SignedInteger;
653 break;
654 case 'F':
655 TM |= TypeModifier::Float;
656 break;
657 case 'S':
658 TM |= TypeModifier::LMUL1;
659 break;
660 default:
661 llvm_unreachable("Illegal non-primitive type transformer!");
662 }
663 }
664 PD.TM = static_cast<uint8_t>(TM);
665
666 return PD;
667}
668
669void RVVType::applyModifier(const PrototypeDescriptor &Transformer) {
670 // Handle primitive type transformer
671 switch (static_cast<BaseTypeModifier>(Transformer.PT)) {
672 case BaseTypeModifier::Scalar:
673 Scale = 0;
674 break;
675 case BaseTypeModifier::Vector:
676 Scale = LMUL.getScale(ElementBitwidth);
677 break;
678 case BaseTypeModifier::Void:
679 ScalarType = ScalarTypeKind::Void;
680 break;
681 case BaseTypeModifier::SizeT:
682 ScalarType = ScalarTypeKind::Size_t;
683 break;
684 case BaseTypeModifier::Ptrdiff:
685 ScalarType = ScalarTypeKind::Ptrdiff_t;
686 break;
687 case BaseTypeModifier::UnsignedLong:
688 ScalarType = ScalarTypeKind::UnsignedLong;
689 break;
690 case BaseTypeModifier::SignedLong:
691 ScalarType = ScalarTypeKind::SignedLong;
692 break;
693 case BaseTypeModifier::Float32:
694 ElementBitwidth = 32;
695 ScalarType = ScalarTypeKind::Float;
696 break;
697 case BaseTypeModifier::Invalid:
698 ScalarType = ScalarTypeKind::Invalid;
699 return;
700 }
701
702 switch (static_cast<VectorTypeModifier>(Transformer.VTM)) {
703 case VectorTypeModifier::Widening2XVector:
704 ElementBitwidth *= 2;
705 LMUL.MulLog2LMUL(log2LMUL: 1);
706 Scale = LMUL.getScale(ElementBitwidth);
707 break;
708 case VectorTypeModifier::Widening4XVector:
709 ElementBitwidth *= 4;
710 LMUL.MulLog2LMUL(log2LMUL: 2);
711 Scale = LMUL.getScale(ElementBitwidth);
712 break;
713 case VectorTypeModifier::Widening8XVector:
714 ElementBitwidth *= 8;
715 LMUL.MulLog2LMUL(log2LMUL: 3);
716 Scale = LMUL.getScale(ElementBitwidth);
717 break;
718 case VectorTypeModifier::MaskVector:
719 ScalarType = ScalarTypeKind::Boolean;
720 Scale = LMUL.getScale(ElementBitwidth);
721 ElementBitwidth = 1;
722 break;
723 case VectorTypeModifier::Log2EEW3:
724 applyLog2EEW(Log2EEW: 3);
725 break;
726 case VectorTypeModifier::Log2EEW4:
727 applyLog2EEW(Log2EEW: 4);
728 break;
729 case VectorTypeModifier::Log2EEW5:
730 applyLog2EEW(Log2EEW: 5);
731 break;
732 case VectorTypeModifier::Log2EEW6:
733 applyLog2EEW(Log2EEW: 6);
734 break;
735 case VectorTypeModifier::FixedSEW8:
736 applyFixedSEW(NewSEW: 8);
737 break;
738 case VectorTypeModifier::FixedSEW16:
739 applyFixedSEW(NewSEW: 16);
740 break;
741 case VectorTypeModifier::FixedSEW32:
742 applyFixedSEW(NewSEW: 32);
743 break;
744 case VectorTypeModifier::FixedSEW64:
745 applyFixedSEW(NewSEW: 64);
746 break;
747 case VectorTypeModifier::LFixedLog2LMULN3:
748 applyFixedLog2LMUL(Log2LMUL: -3, Type: FixedLMULType::LargerThan);
749 break;
750 case VectorTypeModifier::LFixedLog2LMULN2:
751 applyFixedLog2LMUL(Log2LMUL: -2, Type: FixedLMULType::LargerThan);
752 break;
753 case VectorTypeModifier::LFixedLog2LMULN1:
754 applyFixedLog2LMUL(Log2LMUL: -1, Type: FixedLMULType::LargerThan);
755 break;
756 case VectorTypeModifier::LFixedLog2LMUL0:
757 applyFixedLog2LMUL(Log2LMUL: 0, Type: FixedLMULType::LargerThan);
758 break;
759 case VectorTypeModifier::LFixedLog2LMUL1:
760 applyFixedLog2LMUL(Log2LMUL: 1, Type: FixedLMULType::LargerThan);
761 break;
762 case VectorTypeModifier::LFixedLog2LMUL2:
763 applyFixedLog2LMUL(Log2LMUL: 2, Type: FixedLMULType::LargerThan);
764 break;
765 case VectorTypeModifier::LFixedLog2LMUL3:
766 applyFixedLog2LMUL(Log2LMUL: 3, Type: FixedLMULType::LargerThan);
767 break;
768 case VectorTypeModifier::SFixedLog2LMULN3:
769 applyFixedLog2LMUL(Log2LMUL: -3, Type: FixedLMULType::SmallerThan);
770 break;
771 case VectorTypeModifier::SFixedLog2LMULN2:
772 applyFixedLog2LMUL(Log2LMUL: -2, Type: FixedLMULType::SmallerThan);
773 break;
774 case VectorTypeModifier::SFixedLog2LMULN1:
775 applyFixedLog2LMUL(Log2LMUL: -1, Type: FixedLMULType::SmallerThan);
776 break;
777 case VectorTypeModifier::SFixedLog2LMUL0:
778 applyFixedLog2LMUL(Log2LMUL: 0, Type: FixedLMULType::SmallerThan);
779 break;
780 case VectorTypeModifier::SFixedLog2LMUL1:
781 applyFixedLog2LMUL(Log2LMUL: 1, Type: FixedLMULType::SmallerThan);
782 break;
783 case VectorTypeModifier::SFixedLog2LMUL2:
784 applyFixedLog2LMUL(Log2LMUL: 2, Type: FixedLMULType::SmallerThan);
785 break;
786 case VectorTypeModifier::SFixedLog2LMUL3:
787 applyFixedLog2LMUL(Log2LMUL: 3, Type: FixedLMULType::SmallerThan);
788 break;
789 case VectorTypeModifier::SEFixedLog2LMULN3:
790 applyFixedLog2LMUL(Log2LMUL: -3, Type: FixedLMULType::SmallerOrEqual);
791 break;
792 case VectorTypeModifier::SEFixedLog2LMULN2:
793 applyFixedLog2LMUL(Log2LMUL: -2, Type: FixedLMULType::SmallerOrEqual);
794 break;
795 case VectorTypeModifier::SEFixedLog2LMULN1:
796 applyFixedLog2LMUL(Log2LMUL: -1, Type: FixedLMULType::SmallerOrEqual);
797 break;
798 case VectorTypeModifier::SEFixedLog2LMUL0:
799 applyFixedLog2LMUL(Log2LMUL: 0, Type: FixedLMULType::SmallerOrEqual);
800 break;
801 case VectorTypeModifier::SEFixedLog2LMUL1:
802 applyFixedLog2LMUL(Log2LMUL: 1, Type: FixedLMULType::SmallerOrEqual);
803 break;
804 case VectorTypeModifier::SEFixedLog2LMUL2:
805 applyFixedLog2LMUL(Log2LMUL: 2, Type: FixedLMULType::SmallerOrEqual);
806 break;
807 case VectorTypeModifier::SEFixedLog2LMUL3:
808 applyFixedLog2LMUL(Log2LMUL: 3, Type: FixedLMULType::SmallerOrEqual);
809 break;
810 case VectorTypeModifier::Tuple2:
811 case VectorTypeModifier::Tuple3:
812 case VectorTypeModifier::Tuple4:
813 case VectorTypeModifier::Tuple5:
814 case VectorTypeModifier::Tuple6:
815 case VectorTypeModifier::Tuple7:
816 case VectorTypeModifier::Tuple8: {
817 IsTuple = true;
818 NF = 2 + static_cast<uint8_t>(Transformer.VTM) -
819 static_cast<uint8_t>(VectorTypeModifier::Tuple2);
820 break;
821 }
822 case VectorTypeModifier::NoModifier:
823 break;
824 }
825
826 // Early return if the current type modifier is already invalid.
827 if (ScalarType == Invalid)
828 return;
829
830 for (unsigned TypeModifierMaskShift = 0;
831 TypeModifierMaskShift <= static_cast<unsigned>(TypeModifier::MaxOffset);
832 ++TypeModifierMaskShift) {
833 unsigned TypeModifierMask = 1 << TypeModifierMaskShift;
834 if ((static_cast<unsigned>(Transformer.TM) & TypeModifierMask) !=
835 TypeModifierMask)
836 continue;
837 switch (static_cast<TypeModifier>(TypeModifierMask)) {
838 case TypeModifier::Pointer:
839 IsPointer = true;
840 break;
841 case TypeModifier::Const:
842 IsConstant = true;
843 break;
844 case TypeModifier::Immediate:
845 IsImmediate = true;
846 IsConstant = true;
847 break;
848 case TypeModifier::UnsignedInteger:
849 ScalarType = ScalarTypeKind::UnsignedInteger;
850 break;
851 case TypeModifier::SignedInteger:
852 ScalarType = ScalarTypeKind::SignedInteger;
853 break;
854 case TypeModifier::Float:
855 ScalarType = ScalarTypeKind::Float;
856 break;
857 case TypeModifier::BFloat:
858 ScalarType = ScalarTypeKind::BFloat;
859 break;
860 case TypeModifier::LMUL1:
861 LMUL = LMULType(0);
862 // Update ElementBitwidth need to update Scale too.
863 Scale = LMUL.getScale(ElementBitwidth);
864 break;
865 default:
866 llvm_unreachable("Unknown type modifier mask!");
867 }
868 }
869}
870
871void RVVType::applyLog2EEW(unsigned Log2EEW) {
872 // update new elmul = (eew/sew) * lmul
873 LMUL.MulLog2LMUL(log2LMUL: Log2EEW - Log2_32(Value: ElementBitwidth));
874 // update new eew
875 ElementBitwidth = 1 << Log2EEW;
876 ScalarType = ScalarTypeKind::SignedInteger;
877 Scale = LMUL.getScale(ElementBitwidth);
878}
879
880void RVVType::applyFixedSEW(unsigned NewSEW) {
881 // Set invalid type if src and dst SEW are same.
882 if (ElementBitwidth == NewSEW) {
883 ScalarType = ScalarTypeKind::Invalid;
884 return;
885 }
886 // Update new SEW
887 ElementBitwidth = NewSEW;
888 Scale = LMUL.getScale(ElementBitwidth);
889}
890
891void RVVType::applyFixedLog2LMUL(int Log2LMUL, enum FixedLMULType Type) {
892 switch (Type) {
893 case FixedLMULType::LargerThan:
894 if (Log2LMUL <= LMUL.Log2LMUL) {
895 ScalarType = ScalarTypeKind::Invalid;
896 return;
897 }
898 break;
899 case FixedLMULType::SmallerThan:
900 if (Log2LMUL >= LMUL.Log2LMUL) {
901 ScalarType = ScalarTypeKind::Invalid;
902 return;
903 }
904 break;
905 case FixedLMULType::SmallerOrEqual:
906 if (Log2LMUL > LMUL.Log2LMUL) {
907 ScalarType = ScalarTypeKind::Invalid;
908 return;
909 }
910 break;
911 }
912
913 // Update new LMUL
914 LMUL = LMULType(Log2LMUL);
915 Scale = LMUL.getScale(ElementBitwidth);
916}
917
918std::optional<RVVTypes>
919RVVTypeCache::computeTypes(BasicType BT, int Log2LMUL, unsigned NF,
920 ArrayRef<PrototypeDescriptor> Prototype) {
921 RVVTypes Types;
922 for (const PrototypeDescriptor &Proto : Prototype) {
923 auto T = computeType(BT, Log2LMUL, Proto);
924 if (!T)
925 return std::nullopt;
926 // Record legal type index
927 Types.push_back(x: *T);
928 }
929 return Types;
930}
931
932// Compute the hash value of RVVType, used for cache the result of computeType.
933static uint64_t computeRVVTypeHashValue(BasicType BT, int Log2LMUL,
934 PrototypeDescriptor Proto) {
935 // Layout of hash value:
936 // 0 8 16 24 32 40
937 // | Log2LMUL + 3 | BT | Proto.PT | Proto.TM | Proto.VTM |
938 assert(Log2LMUL >= -3 && Log2LMUL <= 3);
939 return (Log2LMUL + 3) | (static_cast<uint64_t>(BT) & 0xff) << 8 |
940 ((uint64_t)(Proto.PT & 0xff) << 16) |
941 ((uint64_t)(Proto.TM & 0xff) << 24) |
942 ((uint64_t)(Proto.VTM & 0xff) << 32);
943}
944
945std::optional<RVVTypePtr> RVVTypeCache::computeType(BasicType BT, int Log2LMUL,
946 PrototypeDescriptor Proto) {
947 uint64_t Idx = computeRVVTypeHashValue(BT, Log2LMUL, Proto);
948 // Search first
949 auto It = LegalTypes.find(x: Idx);
950 if (It != LegalTypes.end())
951 return &(It->second);
952
953 if (IllegalTypes.count(x: Idx))
954 return std::nullopt;
955
956 // Compute type and record the result.
957 RVVType T(BT, Log2LMUL, Proto);
958 if (T.isValid()) {
959 // Record legal type index and value.
960 std::pair<std::unordered_map<uint64_t, RVVType>::iterator, bool>
961 InsertResult = LegalTypes.insert(x: {Idx, T});
962 return &(InsertResult.first->second);
963 }
964 // Record illegal type index.
965 IllegalTypes.insert(x: Idx);
966 return std::nullopt;
967}
968
969//===----------------------------------------------------------------------===//
970// RVVIntrinsic implementation
971//===----------------------------------------------------------------------===//
972RVVIntrinsic::RVVIntrinsic(
973 StringRef NewName, StringRef Suffix, StringRef NewOverloadedName,
974 StringRef OverloadedSuffix, StringRef IRName, bool IsMasked,
975 bool HasMaskedOffOperand, bool HasVL, PolicyScheme Scheme,
976 bool SupportOverloading, bool HasBuiltinAlias, StringRef ManualCodegen,
977 const RVVTypes &OutInTypes, const std::vector<int64_t> &NewIntrinsicTypes,
978 unsigned NF, Policy NewPolicyAttrs, bool HasFRMRoundModeOp)
979 : IRName(IRName), IsMasked(IsMasked),
980 HasMaskedOffOperand(HasMaskedOffOperand), HasVL(HasVL), Scheme(Scheme),
981 SupportOverloading(SupportOverloading), HasBuiltinAlias(HasBuiltinAlias),
982 ManualCodegen(ManualCodegen.str()), NF(NF), PolicyAttrs(NewPolicyAttrs) {
983
984 // Init BuiltinName, Name and OverloadedName
985 BuiltinName = NewName.str();
986 Name = BuiltinName;
987 if (NewOverloadedName.empty())
988 OverloadedName = NewName.split(Separator: "_").first.str();
989 else
990 OverloadedName = NewOverloadedName.str();
991 if (!Suffix.empty())
992 Name += "_" + Suffix.str();
993 if (!OverloadedSuffix.empty())
994 OverloadedName += "_" + OverloadedSuffix.str();
995
996 updateNamesAndPolicy(IsMasked, HasPolicy: hasPolicy(), Name, BuiltinName, OverloadedName,
997 PolicyAttrs, HasFRMRoundModeOp);
998
999 // Init OutputType and InputTypes
1000 OutputType = OutInTypes[0];
1001 InputTypes.assign(first: OutInTypes.begin() + 1, last: OutInTypes.end());
1002
1003 // IntrinsicTypes is unmasked TA version index. Need to update it
1004 // if there is merge operand (It is always in first operand).
1005 IntrinsicTypes = NewIntrinsicTypes;
1006 if ((IsMasked && hasMaskedOffOperand()) ||
1007 (!IsMasked && hasPassthruOperand())) {
1008 for (auto &I : IntrinsicTypes) {
1009 if (I >= 0)
1010 I += 1;
1011 }
1012 }
1013}
1014
1015std::string RVVIntrinsic::getBuiltinTypeStr() const {
1016 std::string S;
1017 S += OutputType->getBuiltinStr();
1018 for (const auto &T : InputTypes) {
1019 S += T->getBuiltinStr();
1020 }
1021 return S;
1022}
1023
1024std::string RVVIntrinsic::getSuffixStr(
1025 RVVTypeCache &TypeCache, BasicType Type, int Log2LMUL,
1026 llvm::ArrayRef<PrototypeDescriptor> PrototypeDescriptors) {
1027 SmallVector<std::string> SuffixStrs;
1028 for (auto PD : PrototypeDescriptors) {
1029 auto T = TypeCache.computeType(BT: Type, Log2LMUL, Proto: PD);
1030 SuffixStrs.push_back(Elt: (*T)->getShortStr());
1031 }
1032 return join(R&: SuffixStrs, Separator: "_");
1033}
1034
1035llvm::SmallVector<PrototypeDescriptor> RVVIntrinsic::computeBuiltinTypes(
1036 llvm::ArrayRef<PrototypeDescriptor> Prototype, bool IsMasked,
1037 bool HasMaskedOffOperand, bool HasVL, unsigned NF,
1038 PolicyScheme DefaultScheme, Policy PolicyAttrs, bool IsTuple) {
1039 SmallVector<PrototypeDescriptor> NewPrototype(Prototype);
1040 bool HasPassthruOp = DefaultScheme == PolicyScheme::HasPassthruOperand;
1041 if (IsMasked) {
1042 // If HasMaskedOffOperand, insert result type as first input operand if
1043 // need.
1044 if (HasMaskedOffOperand && !PolicyAttrs.isTAMAPolicy()) {
1045 if (NF == 1) {
1046 NewPrototype.insert(I: NewPrototype.begin() + 1, Elt: NewPrototype[0]);
1047 } else if (NF > 1) {
1048 if (IsTuple) {
1049 PrototypeDescriptor BasePtrOperand = Prototype[1];
1050 PrototypeDescriptor MaskoffType = PrototypeDescriptor(
1051 static_cast<uint8_t>(BaseTypeModifier::Vector),
1052 static_cast<uint8_t>(getTupleVTM(NF)),
1053 BasePtrOperand.TM & ~static_cast<uint8_t>(TypeModifier::Pointer));
1054 NewPrototype.insert(I: NewPrototype.begin() + 1, Elt: MaskoffType);
1055 } else {
1056 // Convert
1057 // (void, op0 address, op1 address, ...)
1058 // to
1059 // (void, op0 address, op1 address, ..., maskedoff0, maskedoff1, ...)
1060 PrototypeDescriptor MaskoffType = NewPrototype[1];
1061 MaskoffType.TM &= ~static_cast<uint8_t>(TypeModifier::Pointer);
1062 NewPrototype.insert(I: NewPrototype.begin() + NF + 1, NumToInsert: NF, Elt: MaskoffType);
1063 }
1064 }
1065 }
1066 if (HasMaskedOffOperand && NF > 1) {
1067 // Convert
1068 // (void, op0 address, op1 address, ..., maskedoff0, maskedoff1, ...)
1069 // to
1070 // (void, op0 address, op1 address, ..., mask, maskedoff0, maskedoff1,
1071 // ...)
1072 if (IsTuple)
1073 NewPrototype.insert(I: NewPrototype.begin() + 1,
1074 Elt: PrototypeDescriptor::Mask);
1075 else
1076 NewPrototype.insert(I: NewPrototype.begin() + NF + 1,
1077 Elt: PrototypeDescriptor::Mask);
1078 } else {
1079 // If IsMasked, insert PrototypeDescriptor:Mask as first input operand.
1080 NewPrototype.insert(I: NewPrototype.begin() + 1, Elt: PrototypeDescriptor::Mask);
1081 }
1082 } else {
1083 if (NF == 1) {
1084 if (PolicyAttrs.isTUPolicy() && HasPassthruOp)
1085 NewPrototype.insert(I: NewPrototype.begin(), Elt: NewPrototype[0]);
1086 } else if (PolicyAttrs.isTUPolicy() && HasPassthruOp) {
1087 if (IsTuple) {
1088 PrototypeDescriptor BasePtrOperand = Prototype[0];
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(), Elt: MaskoffType);
1094 } else {
1095 // NF > 1 cases for segment load operations.
1096 // Convert
1097 // (void, op0 address, op1 address, ...)
1098 // to
1099 // (void, op0 address, op1 address, maskedoff0, maskedoff1, ...)
1100 PrototypeDescriptor MaskoffType = Prototype[1];
1101 MaskoffType.TM &= ~static_cast<uint8_t>(TypeModifier::Pointer);
1102 NewPrototype.insert(I: NewPrototype.begin() + NF + 1, NumToInsert: NF, Elt: MaskoffType);
1103 }
1104 }
1105 }
1106
1107 // If HasVL, append PrototypeDescriptor:VL to last operand
1108 if (HasVL)
1109 NewPrototype.push_back(Elt: PrototypeDescriptor::VL);
1110
1111 return NewPrototype;
1112}
1113
1114llvm::SmallVector<Policy> RVVIntrinsic::getSupportedUnMaskedPolicies() {
1115 return {Policy(Policy::PolicyType::Undisturbed)}; // TU
1116}
1117
1118llvm::SmallVector<Policy>
1119RVVIntrinsic::getSupportedMaskedPolicies(bool HasTailPolicy,
1120 bool HasMaskPolicy) {
1121 if (HasTailPolicy && HasMaskPolicy)
1122 return {Policy(Policy::PolicyType::Undisturbed,
1123 Policy::PolicyType::Agnostic), // TUM
1124 Policy(Policy::PolicyType::Undisturbed,
1125 Policy::PolicyType::Undisturbed), // TUMU
1126 Policy(Policy::PolicyType::Agnostic,
1127 Policy::PolicyType::Undisturbed)}; // MU
1128 if (HasTailPolicy && !HasMaskPolicy)
1129 return {Policy(Policy::PolicyType::Undisturbed,
1130 Policy::PolicyType::Agnostic)}; // TU
1131 if (!HasTailPolicy && HasMaskPolicy)
1132 return {Policy(Policy::PolicyType::Agnostic,
1133 Policy::PolicyType::Undisturbed)}; // MU
1134 llvm_unreachable("An RVV instruction should not be without both tail policy "
1135 "and mask policy");
1136}
1137
1138void RVVIntrinsic::updateNamesAndPolicy(
1139 bool IsMasked, bool HasPolicy, std::string &Name, std::string &BuiltinName,
1140 std::string &OverloadedName, Policy &PolicyAttrs, bool HasFRMRoundModeOp) {
1141
1142 auto appendPolicySuffix = [&](const std::string &suffix) {
1143 Name += suffix;
1144 BuiltinName += suffix;
1145 OverloadedName += suffix;
1146 };
1147
1148 if (HasFRMRoundModeOp) {
1149 Name += "_rm";
1150 BuiltinName += "_rm";
1151 }
1152
1153 if (IsMasked) {
1154 if (PolicyAttrs.isTUMUPolicy())
1155 appendPolicySuffix("_tumu");
1156 else if (PolicyAttrs.isTUMAPolicy())
1157 appendPolicySuffix("_tum");
1158 else if (PolicyAttrs.isTAMUPolicy())
1159 appendPolicySuffix("_mu");
1160 else if (PolicyAttrs.isTAMAPolicy()) {
1161 Name += "_m";
1162 BuiltinName += "_m";
1163 } else
1164 llvm_unreachable("Unhandled policy condition");
1165 } else {
1166 if (PolicyAttrs.isTUPolicy())
1167 appendPolicySuffix("_tu");
1168 else if (PolicyAttrs.isTAPolicy()) // no suffix needed
1169 return;
1170 else
1171 llvm_unreachable("Unhandled policy condition");
1172 }
1173}
1174
1175SmallVector<PrototypeDescriptor> parsePrototypes(StringRef Prototypes) {
1176 SmallVector<PrototypeDescriptor> PrototypeDescriptors;
1177 const StringRef Primaries("evwqom0ztulf");
1178 while (!Prototypes.empty()) {
1179 size_t Idx = 0;
1180 // Skip over complex prototype because it could contain primitive type
1181 // character.
1182 if (Prototypes[0] == '(')
1183 Idx = Prototypes.find_first_of(C: ')');
1184 Idx = Prototypes.find_first_of(Chars: Primaries, From: Idx);
1185 assert(Idx != StringRef::npos);
1186 auto PD = PrototypeDescriptor::parsePrototypeDescriptor(
1187 PrototypeDescriptorStr: Prototypes.slice(Start: 0, End: Idx + 1));
1188 if (!PD)
1189 llvm_unreachable("Error during parsing prototype.");
1190 PrototypeDescriptors.push_back(Elt: *PD);
1191 Prototypes = Prototypes.drop_front(N: Idx + 1);
1192 }
1193 return PrototypeDescriptors;
1194}
1195
1196#define STRINGIFY(NAME) \
1197 case NAME: \
1198 OS << #NAME; \
1199 break;
1200
1201llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, enum PolicyScheme PS) {
1202 switch (PS) {
1203 STRINGIFY(SchemeNone)
1204 STRINGIFY(HasPassthruOperand)
1205 STRINGIFY(HasPolicyOperand)
1206 }
1207 return OS;
1208}
1209
1210#undef STRINGIFY
1211
1212raw_ostream &operator<<(raw_ostream &OS, const RVVIntrinsicRecord &Record) {
1213 OS << "{";
1214 OS << "/*Name=*/\"" << Record.Name << "\", ";
1215 if (Record.OverloadedName == nullptr ||
1216 StringRef(Record.OverloadedName).empty())
1217 OS << "/*OverloadedName=*/nullptr, ";
1218 else
1219 OS << "/*OverloadedName=*/\"" << Record.OverloadedName << "\", ";
1220 OS << "/*RequiredExtensions=*/\"" << Record.RequiredExtensions << "\", ";
1221 OS << "/*PrototypeIndex=*/" << Record.PrototypeIndex << ", ";
1222 OS << "/*SuffixIndex=*/" << Record.SuffixIndex << ", ";
1223 OS << "/*OverloadedSuffixIndex=*/" << Record.OverloadedSuffixIndex << ", ";
1224 OS << "/*PrototypeLength=*/" << (int)Record.PrototypeLength << ", ";
1225 OS << "/*SuffixLength=*/" << (int)Record.SuffixLength << ", ";
1226 OS << "/*OverloadedSuffixSize=*/" << (int)Record.OverloadedSuffixSize << ", ";
1227 OS << "/*TypeRangeMask=*/" << (int)Record.TypeRangeMask << ", ";
1228 OS << "/*Log2LMULMask=*/" << (int)Record.Log2LMULMask << ", ";
1229 OS << "/*NF=*/" << (int)Record.NF << ", ";
1230 OS << "/*HasMasked=*/" << (int)Record.HasMasked << ", ";
1231 OS << "/*HasVL=*/" << (int)Record.HasVL << ", ";
1232 OS << "/*HasMaskedOffOperand=*/" << (int)Record.HasMaskedOffOperand << ", ";
1233 OS << "/*HasTailPolicy=*/" << (int)Record.HasTailPolicy << ", ";
1234 OS << "/*HasMaskPolicy=*/" << (int)Record.HasMaskPolicy << ", ";
1235 OS << "/*HasFRMRoundModeOp=*/" << (int)Record.HasFRMRoundModeOp << ", ";
1236 OS << "/*IsTuple=*/" << (int)Record.IsTuple << ", ";
1237 OS << "/*UnMaskedPolicyScheme=*/" << (PolicyScheme)Record.UnMaskedPolicyScheme
1238 << ", ";
1239 OS << "/*MaskedPolicyScheme=*/" << (PolicyScheme)Record.MaskedPolicyScheme
1240 << ", ";
1241 OS << "},\n";
1242 return OS;
1243}
1244
1245} // end namespace RISCV
1246} // end namespace clang
1247