1 //===- RISCVVEmitter.cpp - Generate riscv_vector.h for use with clang -----===//
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 // This tablegen backend is responsible for emitting riscv_vector.h which
10 // includes a declaration and definition of each intrinsic functions specified
11 // in https://github.com/riscv/rvv-intrinsic-doc.
12 //
13 // See also the documentation in include/clang/Basic/riscv_vector.td.
14 //
15 //===----------------------------------------------------------------------===//
16
17 #include "llvm/ADT/ArrayRef.h"
18 #include "llvm/ADT/SmallSet.h"
19 #include "llvm/ADT/StringExtras.h"
20 #include "llvm/ADT/StringMap.h"
21 #include "llvm/ADT/StringSet.h"
22 #include "llvm/ADT/Twine.h"
23 #include "llvm/TableGen/Error.h"
24 #include "llvm/TableGen/Record.h"
25 #include <numeric>
26
27 using namespace llvm;
28 using BasicType = char;
29 using VScaleVal = Optional<unsigned>;
30
31 namespace {
32
33 // Exponential LMUL
34 struct LMULType {
35 int Log2LMUL;
36 LMULType(int Log2LMUL);
37 // Return the C/C++ string representation of LMUL
38 std::string str() const;
39 Optional<unsigned> getScale(unsigned ElementBitwidth) const;
40 void MulLog2LMUL(int Log2LMUL);
41 LMULType &operator*=(uint32_t RHS);
42 };
43
44 // This class is compact representation of a valid and invalid RVVType.
45 class RVVType {
46 enum ScalarTypeKind : uint32_t {
47 Void,
48 Size_t,
49 Ptrdiff_t,
50 UnsignedLong,
51 SignedLong,
52 Boolean,
53 SignedInteger,
54 UnsignedInteger,
55 Float,
56 Invalid,
57 };
58 BasicType BT;
59 ScalarTypeKind ScalarType = Invalid;
60 LMULType LMUL;
61 bool IsPointer = false;
62 // IsConstant indices are "int", but have the constant expression.
63 bool IsImmediate = false;
64 // Const qualifier for pointer to const object or object of const type.
65 bool IsConstant = false;
66 unsigned ElementBitwidth = 0;
67 VScaleVal Scale = 0;
68 bool Valid;
69
70 std::string BuiltinStr;
71 std::string ClangBuiltinStr;
72 std::string Str;
73 std::string ShortStr;
74
75 public:
RVVType()76 RVVType() : RVVType(BasicType(), 0, StringRef()) {}
77 RVVType(BasicType BT, int Log2LMUL, StringRef prototype);
78
79 // Return the string representation of a type, which is an encoded string for
80 // passing to the BUILTIN() macro in Builtins.def.
getBuiltinStr() const81 const std::string &getBuiltinStr() const { return BuiltinStr; }
82
83 // Return the clang buitlin type for RVV vector type which are used in the
84 // riscv_vector.h header file.
getClangBuiltinStr() const85 const std::string &getClangBuiltinStr() const { return ClangBuiltinStr; }
86
87 // Return the C/C++ string representation of a type for use in the
88 // riscv_vector.h header file.
getTypeStr() const89 const std::string &getTypeStr() const { return Str; }
90
91 // Return the short name of a type for C/C++ name suffix.
getShortStr()92 const std::string &getShortStr() {
93 // Not all types are used in short name, so compute the short name by
94 // demanded.
95 if (ShortStr.empty())
96 initShortStr();
97 return ShortStr;
98 }
99
isValid() const100 bool isValid() const { return Valid; }
isScalar() const101 bool isScalar() const { return Scale.hasValue() && Scale.getValue() == 0; }
isVector() const102 bool isVector() const { return Scale.hasValue() && Scale.getValue() != 0; }
isFloat() const103 bool isFloat() const { return ScalarType == ScalarTypeKind::Float; }
isSignedInteger() const104 bool isSignedInteger() const {
105 return ScalarType == ScalarTypeKind::SignedInteger;
106 }
isFloatVector(unsigned Width) const107 bool isFloatVector(unsigned Width) const {
108 return isVector() && isFloat() && ElementBitwidth == Width;
109 }
isFloat(unsigned Width) const110 bool isFloat(unsigned Width) const {
111 return isFloat() && ElementBitwidth == Width;
112 }
113
114 private:
115 // Verify RVV vector type and set Valid.
116 bool verifyType() const;
117
118 // Creates a type based on basic types of TypeRange
119 void applyBasicType();
120
121 // Applies a prototype modifier to the current type. The result maybe an
122 // invalid type.
123 void applyModifier(StringRef prototype);
124
125 // Compute and record a string for legal type.
126 void initBuiltinStr();
127 // Compute and record a builtin RVV vector type string.
128 void initClangBuiltinStr();
129 // Compute and record a type string for used in the header.
130 void initTypeStr();
131 // Compute and record a short name of a type for C/C++ name suffix.
132 void initShortStr();
133 };
134
135 using RVVTypePtr = RVVType *;
136 using RVVTypes = std::vector<RVVTypePtr>;
137
138 enum RISCVExtension : uint8_t {
139 Basic = 0,
140 F = 1 << 1,
141 D = 1 << 2,
142 Zfh = 1 << 3,
143 Zvamo = 1 << 4,
144 };
145
146 // TODO refactor RVVIntrinsic class design after support all intrinsic
147 // combination. This represents an instantiation of an intrinsic with a
148 // particular type and prototype
149 class RVVIntrinsic {
150
151 private:
152 std::string Name; // Builtin name
153 std::string MangledName;
154 std::string IRName;
155 bool HasSideEffects;
156 bool IsMask;
157 bool HasMaskedOffOperand;
158 bool HasVL;
159 bool HasNoMaskedOverloaded;
160 bool HasAutoDef; // There is automiatic definition in header
161 std::string ManualCodegen;
162 RVVTypePtr OutputType; // Builtin output type
163 RVVTypes InputTypes; // Builtin input types
164 // The types we use to obtain the specific LLVM intrinsic. They are index of
165 // InputTypes. -1 means the return type.
166 std::vector<int64_t> IntrinsicTypes;
167 uint8_t RISCVExtensions = 0;
168
169 public:
170 RVVIntrinsic(StringRef Name, StringRef Suffix, StringRef MangledName,
171 StringRef IRName, bool HasSideEffects, bool IsMask,
172 bool HasMaskedOffOperand, bool HasVL, bool HasNoMaskedOverloaded,
173 bool HasAutoDef, StringRef ManualCodegen, const RVVTypes &Types,
174 const std::vector<int64_t> &IntrinsicTypes,
175 StringRef RequiredExtension);
176 ~RVVIntrinsic() = default;
177
getName() const178 StringRef getName() const { return Name; }
getMangledName() const179 StringRef getMangledName() const { return MangledName; }
hasSideEffects() const180 bool hasSideEffects() const { return HasSideEffects; }
hasMaskedOffOperand() const181 bool hasMaskedOffOperand() const { return HasMaskedOffOperand; }
hasVL() const182 bool hasVL() const { return HasVL; }
hasNoMaskedOverloaded() const183 bool hasNoMaskedOverloaded() const { return HasNoMaskedOverloaded; }
hasManualCodegen() const184 bool hasManualCodegen() const { return !ManualCodegen.empty(); }
hasAutoDef() const185 bool hasAutoDef() const { return HasAutoDef; }
isMask() const186 bool isMask() const { return IsMask; }
getIRName() const187 StringRef getIRName() const { return IRName; }
getManualCodegen() const188 StringRef getManualCodegen() const { return ManualCodegen; }
getRISCVExtensions() const189 uint8_t getRISCVExtensions() const { return RISCVExtensions; }
190
191 // Return the type string for a BUILTIN() macro in Builtins.def.
192 std::string getBuiltinTypeStr() const;
193
194 // Emit the code block for switch body in EmitRISCVBuiltinExpr, it should
195 // init the RVVIntrinsic ID and IntrinsicTypes.
196 void emitCodeGenSwitchBody(raw_ostream &o) const;
197
198 // Emit the macros for mapping C/C++ intrinsic function to builtin functions.
199 void emitIntrinsicMacro(raw_ostream &o) const;
200
201 // Emit the mangled function definition.
202 void emitMangledFuncDef(raw_ostream &o) const;
203 };
204
205 class RVVEmitter {
206 private:
207 RecordKeeper &Records;
208 std::string HeaderCode;
209 // Concat BasicType, LMUL and Proto as key
210 StringMap<RVVType> LegalTypes;
211 StringSet<> IllegalTypes;
212
213 public:
RVVEmitter(RecordKeeper & R)214 RVVEmitter(RecordKeeper &R) : Records(R) {}
215
216 /// Emit riscv_vector.h
217 void createHeader(raw_ostream &o);
218
219 /// Emit all the __builtin prototypes and code needed by Sema.
220 void createBuiltins(raw_ostream &o);
221
222 /// Emit all the information needed to map builtin -> LLVM IR intrinsic.
223 void createCodeGen(raw_ostream &o);
224
225 std::string getSuffixStr(char Type, int Log2LMUL, StringRef Prototypes);
226
227 private:
228 /// Create all intrinsics and add them to \p Out
229 void createRVVIntrinsics(std::vector<std::unique_ptr<RVVIntrinsic>> &Out);
230 /// Compute output and input types by applying different config (basic type
231 /// and LMUL with type transformers). It also record result of type in legal
232 /// or illegal set to avoid compute the same config again. The result maybe
233 /// have illegal RVVType.
234 Optional<RVVTypes> computeTypes(BasicType BT, int Log2LMUL,
235 ArrayRef<std::string> PrototypeSeq);
236 Optional<RVVTypePtr> computeType(BasicType BT, int Log2LMUL, StringRef Proto);
237
238 /// Emit Acrh predecessor definitions and body, assume the element of Defs are
239 /// sorted by extension.
240 void emitArchMacroAndBody(
241 std::vector<std::unique_ptr<RVVIntrinsic>> &Defs, raw_ostream &o,
242 std::function<void(raw_ostream &, const RVVIntrinsic &)>);
243
244 // Emit the architecture preprocessor definitions. Return true when emits
245 // non-empty string.
246 bool emitExtDefStr(uint8_t Extensions, raw_ostream &o);
247 // Slice Prototypes string into sub prototype string and process each sub
248 // prototype string individually in the Handler.
249 void parsePrototypes(StringRef Prototypes,
250 std::function<void(StringRef)> Handler);
251 };
252
253 } // namespace
254
255 //===----------------------------------------------------------------------===//
256 // Type implementation
257 //===----------------------------------------------------------------------===//
258
LMULType(int NewLog2LMUL)259 LMULType::LMULType(int NewLog2LMUL) {
260 // Check Log2LMUL is -3, -2, -1, 0, 1, 2, 3
261 assert(NewLog2LMUL <= 3 && NewLog2LMUL >= -3 && "Bad LMUL number!");
262 Log2LMUL = NewLog2LMUL;
263 }
264
str() const265 std::string LMULType::str() const {
266 if (Log2LMUL < 0)
267 return "mf" + utostr(1ULL << (-Log2LMUL));
268 return "m" + utostr(1ULL << Log2LMUL);
269 }
270
getScale(unsigned ElementBitwidth) const271 VScaleVal LMULType::getScale(unsigned ElementBitwidth) const {
272 int Log2ScaleResult = 0;
273 switch (ElementBitwidth) {
274 default:
275 break;
276 case 8:
277 Log2ScaleResult = Log2LMUL + 3;
278 break;
279 case 16:
280 Log2ScaleResult = Log2LMUL + 2;
281 break;
282 case 32:
283 Log2ScaleResult = Log2LMUL + 1;
284 break;
285 case 64:
286 Log2ScaleResult = Log2LMUL;
287 break;
288 }
289 // Illegal vscale result would be less than 1
290 if (Log2ScaleResult < 0)
291 return None;
292 return 1 << Log2ScaleResult;
293 }
294
MulLog2LMUL(int log2LMUL)295 void LMULType::MulLog2LMUL(int log2LMUL) { Log2LMUL += log2LMUL; }
296
operator *=(uint32_t RHS)297 LMULType &LMULType::operator*=(uint32_t RHS) {
298 assert(isPowerOf2_32(RHS));
299 this->Log2LMUL = this->Log2LMUL + Log2_32(RHS);
300 return *this;
301 }
302
RVVType(BasicType BT,int Log2LMUL,StringRef prototype)303 RVVType::RVVType(BasicType BT, int Log2LMUL, StringRef prototype)
304 : BT(BT), LMUL(LMULType(Log2LMUL)) {
305 applyBasicType();
306 applyModifier(prototype);
307 Valid = verifyType();
308 if (Valid) {
309 initBuiltinStr();
310 initTypeStr();
311 if (isVector()) {
312 initClangBuiltinStr();
313 }
314 }
315 }
316
317 // clang-format off
318 // boolean type are encoded the ratio of n (SEW/LMUL)
319 // SEW/LMUL | 1 | 2 | 4 | 8 | 16 | 32 | 64
320 // c type | vbool64_t | vbool32_t | vbool16_t | vbool8_t | vbool4_t | vbool2_t | vbool1_t
321 // IR type | nxv1i1 | nxv2i1 | nxv4i1 | nxv8i1 | nxv16i1 | nxv32i1 | nxv64i1
322
323 // type\lmul | 1/8 | 1/4 | 1/2 | 1 | 2 | 4 | 8
324 // -------- |------ | -------- | ------- | ------- | -------- | -------- | --------
325 // i64 | N/A | N/A | N/A | nxv1i64 | nxv2i64 | nxv4i64 | nxv8i64
326 // i32 | N/A | N/A | nxv1i32 | nxv2i32 | nxv4i32 | nxv8i32 | nxv16i32
327 // i16 | N/A | nxv1i16 | nxv2i16 | nxv4i16 | nxv8i16 | nxv16i16 | nxv32i16
328 // i8 | nxv1i8 | nxv2i8 | nxv4i8 | nxv8i8 | nxv16i8 | nxv32i8 | nxv64i8
329 // double | N/A | N/A | N/A | nxv1f64 | nxv2f64 | nxv4f64 | nxv8f64
330 // float | N/A | N/A | nxv1f32 | nxv2f32 | nxv4f32 | nxv8f32 | nxv16f32
331 // half | N/A | nxv1f16 | nxv2f16 | nxv4f16 | nxv8f16 | nxv16f16 | nxv32f16
332 // clang-format on
333
verifyType() const334 bool RVVType::verifyType() const {
335 if (ScalarType == Invalid)
336 return false;
337 if (isScalar())
338 return true;
339 if (!Scale.hasValue())
340 return false;
341 if (isFloat() && ElementBitwidth == 8)
342 return false;
343 unsigned V = Scale.getValue();
344 switch (ElementBitwidth) {
345 case 1:
346 case 8:
347 // Check Scale is 1,2,4,8,16,32,64
348 return (V <= 64 && isPowerOf2_32(V));
349 case 16:
350 // Check Scale is 1,2,4,8,16,32
351 return (V <= 32 && isPowerOf2_32(V));
352 case 32:
353 // Check Scale is 1,2,4,8,16
354 return (V <= 16 && isPowerOf2_32(V));
355 case 64:
356 // Check Scale is 1,2,4,8
357 return (V <= 8 && isPowerOf2_32(V));
358 }
359 return false;
360 }
361
initBuiltinStr()362 void RVVType::initBuiltinStr() {
363 assert(isValid() && "RVVType is invalid");
364 switch (ScalarType) {
365 case ScalarTypeKind::Void:
366 BuiltinStr = "v";
367 return;
368 case ScalarTypeKind::Size_t:
369 BuiltinStr = "z";
370 if (IsImmediate)
371 BuiltinStr = "I" + BuiltinStr;
372 if (IsPointer)
373 BuiltinStr += "*";
374 return;
375 case ScalarTypeKind::Ptrdiff_t:
376 BuiltinStr = "Y";
377 return;
378 case ScalarTypeKind::UnsignedLong:
379 BuiltinStr = "ULi";
380 return;
381 case ScalarTypeKind::SignedLong:
382 BuiltinStr = "Li";
383 return;
384 case ScalarTypeKind::Boolean:
385 assert(ElementBitwidth == 1);
386 BuiltinStr += "b";
387 break;
388 case ScalarTypeKind::SignedInteger:
389 case ScalarTypeKind::UnsignedInteger:
390 switch (ElementBitwidth) {
391 case 8:
392 BuiltinStr += "c";
393 break;
394 case 16:
395 BuiltinStr += "s";
396 break;
397 case 32:
398 BuiltinStr += "i";
399 break;
400 case 64:
401 BuiltinStr += "Wi";
402 break;
403 default:
404 llvm_unreachable("Unhandled ElementBitwidth!");
405 }
406 if (isSignedInteger())
407 BuiltinStr = "S" + BuiltinStr;
408 else
409 BuiltinStr = "U" + BuiltinStr;
410 break;
411 case ScalarTypeKind::Float:
412 switch (ElementBitwidth) {
413 case 16:
414 BuiltinStr += "h";
415 break;
416 case 32:
417 BuiltinStr += "f";
418 break;
419 case 64:
420 BuiltinStr += "d";
421 break;
422 default:
423 llvm_unreachable("Unhandled ElementBitwidth!");
424 }
425 break;
426 default:
427 llvm_unreachable("ScalarType is invalid!");
428 }
429 if (IsImmediate)
430 BuiltinStr = "I" + BuiltinStr;
431 if (isScalar()) {
432 if (IsConstant)
433 BuiltinStr += "C";
434 if (IsPointer)
435 BuiltinStr += "*";
436 return;
437 }
438 BuiltinStr = "q" + utostr(Scale.getValue()) + BuiltinStr;
439 }
440
initClangBuiltinStr()441 void RVVType::initClangBuiltinStr() {
442 assert(isValid() && "RVVType is invalid");
443 assert(isVector() && "Handle Vector type only");
444
445 ClangBuiltinStr = "__rvv_";
446 switch (ScalarType) {
447 case ScalarTypeKind::Boolean:
448 ClangBuiltinStr += "bool" + utostr(64 / Scale.getValue()) + "_t";
449 return;
450 case ScalarTypeKind::Float:
451 ClangBuiltinStr += "float";
452 break;
453 case ScalarTypeKind::SignedInteger:
454 ClangBuiltinStr += "int";
455 break;
456 case ScalarTypeKind::UnsignedInteger:
457 ClangBuiltinStr += "uint";
458 break;
459 default:
460 llvm_unreachable("ScalarTypeKind is invalid");
461 }
462 ClangBuiltinStr += utostr(ElementBitwidth) + LMUL.str() + "_t";
463 }
464
initTypeStr()465 void RVVType::initTypeStr() {
466 assert(isValid() && "RVVType is invalid");
467
468 if (IsConstant)
469 Str += "const ";
470
471 auto getTypeString = [&](StringRef TypeStr) {
472 if (isScalar())
473 return Twine(TypeStr + Twine(ElementBitwidth) + "_t").str();
474 return Twine("v" + TypeStr + Twine(ElementBitwidth) + LMUL.str() + "_t")
475 .str();
476 };
477
478 switch (ScalarType) {
479 case ScalarTypeKind::Void:
480 Str = "void";
481 return;
482 case ScalarTypeKind::Size_t:
483 Str = "size_t";
484 if (IsPointer)
485 Str += " *";
486 return;
487 case ScalarTypeKind::Ptrdiff_t:
488 Str = "ptrdiff_t";
489 return;
490 case ScalarTypeKind::UnsignedLong:
491 Str = "unsigned long";
492 return;
493 case ScalarTypeKind::SignedLong:
494 Str = "long";
495 return;
496 case ScalarTypeKind::Boolean:
497 if (isScalar())
498 Str += "bool";
499 else
500 // Vector bool is special case, the formulate is
501 // `vbool<N>_t = MVT::nxv<64/N>i1` ex. vbool16_t = MVT::4i1
502 Str += "vbool" + utostr(64 / Scale.getValue()) + "_t";
503 break;
504 case ScalarTypeKind::Float:
505 if (isScalar()) {
506 if (ElementBitwidth == 64)
507 Str += "double";
508 else if (ElementBitwidth == 32)
509 Str += "float";
510 assert((ElementBitwidth == 32 || ElementBitwidth == 64) &&
511 "Unhandled floating type");
512 } else
513 Str += getTypeString("float");
514 break;
515 case ScalarTypeKind::SignedInteger:
516 Str += getTypeString("int");
517 break;
518 case ScalarTypeKind::UnsignedInteger:
519 Str += getTypeString("uint");
520 break;
521 default:
522 llvm_unreachable("ScalarType is invalid!");
523 }
524 if (IsPointer)
525 Str += " *";
526 }
527
initShortStr()528 void RVVType::initShortStr() {
529 switch (ScalarType) {
530 case ScalarTypeKind::Boolean:
531 assert(isVector());
532 ShortStr = "b" + utostr(64 / Scale.getValue());
533 return;
534 case ScalarTypeKind::Float:
535 ShortStr = "f" + utostr(ElementBitwidth);
536 break;
537 case ScalarTypeKind::SignedInteger:
538 ShortStr = "i" + utostr(ElementBitwidth);
539 break;
540 case ScalarTypeKind::UnsignedInteger:
541 ShortStr = "u" + utostr(ElementBitwidth);
542 break;
543 default:
544 PrintFatalError("Unhandled case!");
545 }
546 if (isVector())
547 ShortStr += LMUL.str();
548 }
549
applyBasicType()550 void RVVType::applyBasicType() {
551 switch (BT) {
552 case 'c':
553 ElementBitwidth = 8;
554 ScalarType = ScalarTypeKind::SignedInteger;
555 break;
556 case 's':
557 ElementBitwidth = 16;
558 ScalarType = ScalarTypeKind::SignedInteger;
559 break;
560 case 'i':
561 ElementBitwidth = 32;
562 ScalarType = ScalarTypeKind::SignedInteger;
563 break;
564 case 'l':
565 ElementBitwidth = 64;
566 ScalarType = ScalarTypeKind::SignedInteger;
567 break;
568 case 'h':
569 ElementBitwidth = 16;
570 ScalarType = ScalarTypeKind::Float;
571 break;
572 case 'f':
573 ElementBitwidth = 32;
574 ScalarType = ScalarTypeKind::Float;
575 break;
576 case 'd':
577 ElementBitwidth = 64;
578 ScalarType = ScalarTypeKind::Float;
579 break;
580 default:
581 PrintFatalError("Unhandled type code!");
582 }
583 assert(ElementBitwidth != 0 && "Bad element bitwidth!");
584 }
585
applyModifier(StringRef Transformer)586 void RVVType::applyModifier(StringRef Transformer) {
587 if (Transformer.empty())
588 return;
589 // Handle primitive type transformer
590 auto PType = Transformer.back();
591 switch (PType) {
592 case 'e':
593 Scale = 0;
594 break;
595 case 'v':
596 Scale = LMUL.getScale(ElementBitwidth);
597 break;
598 case 'w':
599 ElementBitwidth *= 2;
600 LMUL *= 2;
601 Scale = LMUL.getScale(ElementBitwidth);
602 break;
603 case 'q':
604 ElementBitwidth *= 4;
605 LMUL *= 4;
606 Scale = LMUL.getScale(ElementBitwidth);
607 break;
608 case 'o':
609 ElementBitwidth *= 8;
610 LMUL *= 8;
611 Scale = LMUL.getScale(ElementBitwidth);
612 break;
613 case 'm':
614 ScalarType = ScalarTypeKind::Boolean;
615 Scale = LMUL.getScale(ElementBitwidth);
616 ElementBitwidth = 1;
617 break;
618 case '0':
619 ScalarType = ScalarTypeKind::Void;
620 break;
621 case 'z':
622 ScalarType = ScalarTypeKind::Size_t;
623 break;
624 case 't':
625 ScalarType = ScalarTypeKind::Ptrdiff_t;
626 break;
627 case 'u':
628 ScalarType = ScalarTypeKind::UnsignedLong;
629 break;
630 case 'l':
631 ScalarType = ScalarTypeKind::SignedLong;
632 break;
633 default:
634 PrintFatalError("Illegal primitive type transformers!");
635 }
636 Transformer = Transformer.drop_back();
637
638 // Extract and compute complex type transformer. It can only appear one time.
639 if (Transformer.startswith("(")) {
640 size_t Idx = Transformer.find(')');
641 assert(Idx != StringRef::npos);
642 StringRef ComplexType = Transformer.slice(1, Idx);
643 Transformer = Transformer.drop_front(Idx + 1);
644 assert(Transformer.find('(') == StringRef::npos &&
645 "Only allow one complex type transformer");
646
647 auto UpdateAndCheckComplexProto = [&]() {
648 Scale = LMUL.getScale(ElementBitwidth);
649 const StringRef VectorPrototypes("vwqom");
650 if (!VectorPrototypes.contains(PType))
651 PrintFatalError("Complex type transformer only supports vector type!");
652 if (Transformer.find_first_of("PCKWS") != StringRef::npos)
653 PrintFatalError(
654 "Illegal type transformer for Complex type transformer");
655 };
656 auto ComputeFixedLog2LMUL =
657 [&](StringRef Value,
658 std::function<bool(const int32_t &, const int32_t &)> Compare) {
659 int32_t Log2LMUL;
660 Value.getAsInteger(10, Log2LMUL);
661 if (!Compare(Log2LMUL, LMUL.Log2LMUL)) {
662 ScalarType = Invalid;
663 return false;
664 }
665 // Update new LMUL
666 LMUL = LMULType(Log2LMUL);
667 UpdateAndCheckComplexProto();
668 return true;
669 };
670 auto ComplexTT = ComplexType.split(":");
671 if (ComplexTT.first == "Log2EEW") {
672 uint32_t Log2EEW;
673 ComplexTT.second.getAsInteger(10, Log2EEW);
674 // update new elmul = (eew/sew) * lmul
675 LMUL.MulLog2LMUL(Log2EEW - Log2_32(ElementBitwidth));
676 // update new eew
677 ElementBitwidth = 1 << Log2EEW;
678 ScalarType = ScalarTypeKind::SignedInteger;
679 UpdateAndCheckComplexProto();
680 } else if (ComplexTT.first == "FixedSEW") {
681 uint32_t NewSEW;
682 ComplexTT.second.getAsInteger(10, NewSEW);
683 // Set invalid type if src and dst SEW are same.
684 if (ElementBitwidth == NewSEW) {
685 ScalarType = Invalid;
686 return;
687 }
688 // Update new SEW
689 ElementBitwidth = NewSEW;
690 UpdateAndCheckComplexProto();
691 } else if (ComplexTT.first == "LFixedLog2LMUL") {
692 // New LMUL should be larger than old
693 if (!ComputeFixedLog2LMUL(ComplexTT.second, std::greater<int32_t>()))
694 return;
695 } else if (ComplexTT.first == "SFixedLog2LMUL") {
696 // New LMUL should be smaller than old
697 if (!ComputeFixedLog2LMUL(ComplexTT.second, std::less<int32_t>()))
698 return;
699 } else {
700 PrintFatalError("Illegal complex type transformers!");
701 }
702 }
703
704 // Compute the remain type transformers
705 for (char I : Transformer) {
706 switch (I) {
707 case 'P':
708 if (IsConstant)
709 PrintFatalError("'P' transformer cannot be used after 'C'");
710 if (IsPointer)
711 PrintFatalError("'P' transformer cannot be used twice");
712 IsPointer = true;
713 break;
714 case 'C':
715 if (IsConstant)
716 PrintFatalError("'C' transformer cannot be used twice");
717 IsConstant = true;
718 break;
719 case 'K':
720 IsImmediate = true;
721 break;
722 case 'U':
723 ScalarType = ScalarTypeKind::UnsignedInteger;
724 break;
725 case 'I':
726 ScalarType = ScalarTypeKind::SignedInteger;
727 break;
728 case 'F':
729 ScalarType = ScalarTypeKind::Float;
730 break;
731 case 'S':
732 LMUL = LMULType(0);
733 // Update ElementBitwidth need to update Scale too.
734 Scale = LMUL.getScale(ElementBitwidth);
735 break;
736 default:
737 PrintFatalError("Illegal non-primitive type transformer!");
738 }
739 }
740 }
741
742 //===----------------------------------------------------------------------===//
743 // RVVIntrinsic implementation
744 //===----------------------------------------------------------------------===//
RVVIntrinsic(StringRef NewName,StringRef Suffix,StringRef NewMangledName,StringRef IRName,bool HasSideEffects,bool IsMask,bool HasMaskedOffOperand,bool HasVL,bool HasNoMaskedOverloaded,bool HasAutoDef,StringRef ManualCodegen,const RVVTypes & OutInTypes,const std::vector<int64_t> & NewIntrinsicTypes,StringRef RequiredExtension)745 RVVIntrinsic::RVVIntrinsic(StringRef NewName, StringRef Suffix,
746 StringRef NewMangledName, StringRef IRName,
747 bool HasSideEffects, bool IsMask,
748 bool HasMaskedOffOperand, bool HasVL,
749 bool HasNoMaskedOverloaded, bool HasAutoDef,
750 StringRef ManualCodegen, const RVVTypes &OutInTypes,
751 const std::vector<int64_t> &NewIntrinsicTypes,
752 StringRef RequiredExtension)
753 : IRName(IRName), HasSideEffects(HasSideEffects), IsMask(IsMask),
754 HasMaskedOffOperand(HasMaskedOffOperand), HasVL(HasVL),
755 HasNoMaskedOverloaded(HasNoMaskedOverloaded), HasAutoDef(HasAutoDef),
756 ManualCodegen(ManualCodegen.str()) {
757
758 // Init Name and MangledName
759 Name = NewName.str();
760 if (NewMangledName.empty())
761 MangledName = NewName.split("_").first.str();
762 else
763 MangledName = NewMangledName.str();
764 if (!Suffix.empty())
765 Name += "_" + Suffix.str();
766 if (IsMask) {
767 Name += "_m";
768 }
769 // Init RISC-V extensions
770 for (const auto &T : OutInTypes) {
771 if (T->isFloatVector(16) || T->isFloat(16))
772 RISCVExtensions |= RISCVExtension::Zfh;
773 else if (T->isFloatVector(32) || T->isFloat(32))
774 RISCVExtensions |= RISCVExtension::F;
775 else if (T->isFloatVector(64) || T->isFloat(64))
776 RISCVExtensions |= RISCVExtension::D;
777 }
778 if (RequiredExtension == "Zvamo")
779 RISCVExtensions |= RISCVExtension::Zvamo;
780
781 // Init OutputType and InputTypes
782 OutputType = OutInTypes[0];
783 InputTypes.assign(OutInTypes.begin() + 1, OutInTypes.end());
784
785 // IntrinsicTypes is nonmasked version index. Need to update it
786 // if there is maskedoff operand (It is always in first operand).
787 IntrinsicTypes = NewIntrinsicTypes;
788 if (IsMask && HasMaskedOffOperand) {
789 for (auto &I : IntrinsicTypes) {
790 if (I >= 0)
791 I += 1;
792 }
793 }
794 }
795
getBuiltinTypeStr() const796 std::string RVVIntrinsic::getBuiltinTypeStr() const {
797 std::string S;
798 S += OutputType->getBuiltinStr();
799 for (const auto &T : InputTypes) {
800 S += T->getBuiltinStr();
801 }
802 return S;
803 }
804
emitCodeGenSwitchBody(raw_ostream & OS) const805 void RVVIntrinsic::emitCodeGenSwitchBody(raw_ostream &OS) const {
806 if (!getIRName().empty())
807 OS << " ID = Intrinsic::riscv_" + getIRName() + ";\n";
808 if (hasManualCodegen()) {
809 OS << ManualCodegen;
810 OS << "break;\n";
811 return;
812 }
813
814 if (isMask()) {
815 if (hasVL()) {
816 OS << " std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1);\n";
817 } else {
818 OS << " std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end());\n";
819 }
820 }
821
822 OS << " IntrinsicTypes = {";
823 ListSeparator LS;
824 for (const auto &Idx : IntrinsicTypes) {
825 if (Idx == -1)
826 OS << LS << "ResultType";
827 else
828 OS << LS << "Ops[" << Idx << "]->getType()";
829 }
830
831 // VL could be i64 or i32, need to encode it in IntrinsicTypes. VL is
832 // always last operand.
833 if (hasVL())
834 OS << ", Ops.back()->getType()";
835 OS << "};\n";
836 OS << " break;\n";
837 }
838
emitIntrinsicMacro(raw_ostream & OS) const839 void RVVIntrinsic::emitIntrinsicMacro(raw_ostream &OS) const {
840 OS << "#define " << getName() << "(";
841 if (!InputTypes.empty()) {
842 ListSeparator LS;
843 for (unsigned i = 0, e = InputTypes.size(); i != e; ++i)
844 OS << LS << "op" << i;
845 }
846 OS << ") \\\n";
847 OS << "__builtin_rvv_" << getName() << "(";
848 if (!InputTypes.empty()) {
849 ListSeparator LS;
850 for (unsigned i = 0, e = InputTypes.size(); i != e; ++i)
851 OS << LS << "(" << InputTypes[i]->getTypeStr() << ")(op" << i << ")";
852 }
853 OS << ")\n";
854 }
855
emitMangledFuncDef(raw_ostream & OS) const856 void RVVIntrinsic::emitMangledFuncDef(raw_ostream &OS) const {
857 OS << "__attribute__((clang_builtin_alias(";
858 OS << "__builtin_rvv_" << getName() << ")))\n";
859 OS << OutputType->getTypeStr() << " " << getMangledName() << "(";
860 // Emit function arguments
861 if (!InputTypes.empty()) {
862 ListSeparator LS;
863 for (unsigned i = 0; i < InputTypes.size(); ++i)
864 OS << LS << InputTypes[i]->getTypeStr() << " op" << i;
865 }
866 OS << ");\n\n";
867 }
868
869 //===----------------------------------------------------------------------===//
870 // RVVEmitter implementation
871 //===----------------------------------------------------------------------===//
createHeader(raw_ostream & OS)872 void RVVEmitter::createHeader(raw_ostream &OS) {
873
874 OS << "/*===---- riscv_vector.h - RISC-V V-extension RVVIntrinsics "
875 "-------------------===\n"
876 " *\n"
877 " *\n"
878 " * Part of the LLVM Project, under the Apache License v2.0 with LLVM "
879 "Exceptions.\n"
880 " * See https://llvm.org/LICENSE.txt for license information.\n"
881 " * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n"
882 " *\n"
883 " *===-----------------------------------------------------------------"
884 "------===\n"
885 " */\n\n";
886
887 OS << "#ifndef __RISCV_VECTOR_H\n";
888 OS << "#define __RISCV_VECTOR_H\n\n";
889
890 OS << "#include <stdint.h>\n";
891 OS << "#include <stddef.h>\n\n";
892
893 OS << "#ifndef __riscv_vector\n";
894 OS << "#error \"Vector intrinsics require the vector extension.\"\n";
895 OS << "#endif\n\n";
896
897 OS << "#ifdef __cplusplus\n";
898 OS << "extern \"C\" {\n";
899 OS << "#endif\n\n";
900
901 std::vector<std::unique_ptr<RVVIntrinsic>> Defs;
902 createRVVIntrinsics(Defs);
903
904 // Print header code
905 if (!HeaderCode.empty()) {
906 OS << HeaderCode;
907 }
908
909 auto printType = [&](auto T) {
910 OS << "typedef " << T->getClangBuiltinStr() << " " << T->getTypeStr()
911 << ";\n";
912 };
913
914 constexpr int Log2LMULs[] = {-3, -2, -1, 0, 1, 2, 3};
915 // Print RVV boolean types.
916 for (int Log2LMUL : Log2LMULs) {
917 auto T = computeType('c', Log2LMUL, "m");
918 if (T.hasValue())
919 printType(T.getValue());
920 }
921 // Print RVV int/float types.
922 for (char I : StringRef("csil")) {
923 for (int Log2LMUL : Log2LMULs) {
924 auto T = computeType(I, Log2LMUL, "v");
925 if (T.hasValue()) {
926 printType(T.getValue());
927 auto UT = computeType(I, Log2LMUL, "Uv");
928 printType(UT.getValue());
929 }
930 }
931 }
932 OS << "#if defined(__riscv_zfh)\n";
933 for (int Log2LMUL : Log2LMULs) {
934 auto T = computeType('h', Log2LMUL, "v");
935 if (T.hasValue())
936 printType(T.getValue());
937 }
938 OS << "#endif\n";
939
940 OS << "#if defined(__riscv_f)\n";
941 for (int Log2LMUL : Log2LMULs) {
942 auto T = computeType('f', Log2LMUL, "v");
943 if (T.hasValue())
944 printType(T.getValue());
945 }
946 OS << "#endif\n";
947
948 OS << "#if defined(__riscv_d)\n";
949 for (int Log2LMUL : Log2LMULs) {
950 auto T = computeType('d', Log2LMUL, "v");
951 if (T.hasValue())
952 printType(T.getValue());
953 }
954 OS << "#endif\n\n";
955
956 // The same extension include in the same arch guard marco.
957 std::stable_sort(Defs.begin(), Defs.end(),
958 [](const std::unique_ptr<RVVIntrinsic> &A,
959 const std::unique_ptr<RVVIntrinsic> &B) {
960 return A->getRISCVExtensions() < B->getRISCVExtensions();
961 });
962
963 // Print intrinsic functions with macro
964 emitArchMacroAndBody(Defs, OS, [](raw_ostream &OS, const RVVIntrinsic &Inst) {
965 Inst.emitIntrinsicMacro(OS);
966 });
967
968 OS << "#define __riscv_v_intrinsic_overloading 1\n";
969
970 // Print Overloaded APIs
971 OS << "#define __rvv_overloaded static inline "
972 "__attribute__((__always_inline__, __nodebug__, __overloadable__))\n";
973
974 emitArchMacroAndBody(Defs, OS, [](raw_ostream &OS, const RVVIntrinsic &Inst) {
975 if (!Inst.isMask() && !Inst.hasNoMaskedOverloaded())
976 return;
977 OS << "__rvv_overloaded ";
978 Inst.emitMangledFuncDef(OS);
979 });
980
981 OS << "\n#ifdef __cplusplus\n";
982 OS << "}\n";
983 OS << "#endif // __riscv_vector\n";
984 OS << "#endif // __RISCV_VECTOR_H\n";
985 }
986
createBuiltins(raw_ostream & OS)987 void RVVEmitter::createBuiltins(raw_ostream &OS) {
988 std::vector<std::unique_ptr<RVVIntrinsic>> Defs;
989 createRVVIntrinsics(Defs);
990
991 OS << "#if defined(TARGET_BUILTIN) && !defined(RISCVV_BUILTIN)\n";
992 OS << "#define RISCVV_BUILTIN(ID, TYPE, ATTRS) TARGET_BUILTIN(ID, TYPE, "
993 "ATTRS, \"experimental-v\")\n";
994 OS << "#endif\n";
995 for (auto &Def : Defs) {
996 OS << "RISCVV_BUILTIN(__builtin_rvv_" << Def->getName() << ",\""
997 << Def->getBuiltinTypeStr() << "\", ";
998 if (!Def->hasSideEffects())
999 OS << "\"n\")\n";
1000 else
1001 OS << "\"\")\n";
1002 }
1003 OS << "#undef RISCVV_BUILTIN\n";
1004 }
1005
createCodeGen(raw_ostream & OS)1006 void RVVEmitter::createCodeGen(raw_ostream &OS) {
1007 std::vector<std::unique_ptr<RVVIntrinsic>> Defs;
1008 createRVVIntrinsics(Defs);
1009 // IR name could be empty, use the stable sort preserves the relative order.
1010 std::stable_sort(Defs.begin(), Defs.end(),
1011 [](const std::unique_ptr<RVVIntrinsic> &A,
1012 const std::unique_ptr<RVVIntrinsic> &B) {
1013 return A->getIRName() < B->getIRName();
1014 });
1015 // Print switch body when the ir name or ManualCodegen changes from previous
1016 // iteration.
1017 RVVIntrinsic *PrevDef = Defs.begin()->get();
1018 for (auto &Def : Defs) {
1019 StringRef CurIRName = Def->getIRName();
1020 if (CurIRName != PrevDef->getIRName() ||
1021 (Def->getManualCodegen() != PrevDef->getManualCodegen())) {
1022 PrevDef->emitCodeGenSwitchBody(OS);
1023 }
1024 PrevDef = Def.get();
1025 OS << "case RISCV::BI__builtin_rvv_" << Def->getName() << ":\n";
1026 }
1027 Defs.back()->emitCodeGenSwitchBody(OS);
1028 OS << "\n";
1029 }
1030
parsePrototypes(StringRef Prototypes,std::function<void (StringRef)> Handler)1031 void RVVEmitter::parsePrototypes(StringRef Prototypes,
1032 std::function<void(StringRef)> Handler) {
1033 const StringRef Primaries("evwqom0ztul");
1034 while (!Prototypes.empty()) {
1035 size_t Idx = 0;
1036 // Skip over complex prototype because it could contain primitive type
1037 // character.
1038 if (Prototypes[0] == '(')
1039 Idx = Prototypes.find_first_of(')');
1040 Idx = Prototypes.find_first_of(Primaries, Idx);
1041 assert(Idx != StringRef::npos);
1042 Handler(Prototypes.slice(0, Idx + 1));
1043 Prototypes = Prototypes.drop_front(Idx + 1);
1044 }
1045 }
1046
getSuffixStr(char Type,int Log2LMUL,StringRef Prototypes)1047 std::string RVVEmitter::getSuffixStr(char Type, int Log2LMUL,
1048 StringRef Prototypes) {
1049 SmallVector<std::string> SuffixStrs;
1050 parsePrototypes(Prototypes, [&](StringRef Proto) {
1051 auto T = computeType(Type, Log2LMUL, Proto);
1052 SuffixStrs.push_back(T.getValue()->getShortStr());
1053 });
1054 return join(SuffixStrs, "_");
1055 }
1056
createRVVIntrinsics(std::vector<std::unique_ptr<RVVIntrinsic>> & Out)1057 void RVVEmitter::createRVVIntrinsics(
1058 std::vector<std::unique_ptr<RVVIntrinsic>> &Out) {
1059 std::vector<Record *> RV = Records.getAllDerivedDefinitions("RVVBuiltin");
1060 for (auto *R : RV) {
1061 StringRef Name = R->getValueAsString("Name");
1062 StringRef SuffixProto = R->getValueAsString("Suffix");
1063 StringRef MangledName = R->getValueAsString("MangledName");
1064 StringRef Prototypes = R->getValueAsString("Prototype");
1065 StringRef TypeRange = R->getValueAsString("TypeRange");
1066 bool HasMask = R->getValueAsBit("HasMask");
1067 bool HasMaskedOffOperand = R->getValueAsBit("HasMaskedOffOperand");
1068 bool HasVL = R->getValueAsBit("HasVL");
1069 bool HasNoMaskedOverloaded = R->getValueAsBit("HasNoMaskedOverloaded");
1070 bool HasSideEffects = R->getValueAsBit("HasSideEffects");
1071 std::vector<int64_t> Log2LMULList = R->getValueAsListOfInts("Log2LMUL");
1072 StringRef ManualCodegen = R->getValueAsString("ManualCodegen");
1073 StringRef ManualCodegenMask = R->getValueAsString("ManualCodegenMask");
1074 std::vector<int64_t> IntrinsicTypes =
1075 R->getValueAsListOfInts("IntrinsicTypes");
1076 StringRef RequiredExtension = R->getValueAsString("RequiredExtension");
1077 StringRef IRName = R->getValueAsString("IRName");
1078 StringRef IRNameMask = R->getValueAsString("IRNameMask");
1079
1080 StringRef HeaderCodeStr = R->getValueAsString("HeaderCode");
1081 bool HasAutoDef = HeaderCodeStr.empty();
1082 if (!HeaderCodeStr.empty()) {
1083 HeaderCode += HeaderCodeStr.str();
1084 }
1085 // Parse prototype and create a list of primitive type with transformers
1086 // (operand) in ProtoSeq. ProtoSeq[0] is output operand.
1087 SmallVector<std::string> ProtoSeq;
1088 parsePrototypes(Prototypes, [&ProtoSeq](StringRef Proto) {
1089 ProtoSeq.push_back(Proto.str());
1090 });
1091
1092 // Compute Builtin types
1093 SmallVector<std::string> ProtoMaskSeq = ProtoSeq;
1094 if (HasMask) {
1095 // If HasMaskedOffOperand, insert result type as first input operand.
1096 if (HasMaskedOffOperand)
1097 ProtoMaskSeq.insert(ProtoMaskSeq.begin() + 1, ProtoSeq[0]);
1098 // If HasMask, insert 'm' as first input operand.
1099 ProtoMaskSeq.insert(ProtoMaskSeq.begin() + 1, "m");
1100 }
1101 // If HasVL, append 'z' to last operand
1102 if (HasVL) {
1103 ProtoSeq.push_back("z");
1104 ProtoMaskSeq.push_back("z");
1105 }
1106
1107 // Create Intrinsics for each type and LMUL.
1108 for (char I : TypeRange) {
1109 for (int Log2LMUL : Log2LMULList) {
1110 Optional<RVVTypes> Types = computeTypes(I, Log2LMUL, ProtoSeq);
1111 // Ignored to create new intrinsic if there are any illegal types.
1112 if (!Types.hasValue())
1113 continue;
1114
1115 auto SuffixStr = getSuffixStr(I, Log2LMUL, SuffixProto);
1116 // Create a non-mask intrinsic
1117 Out.push_back(std::make_unique<RVVIntrinsic>(
1118 Name, SuffixStr, MangledName, IRName, HasSideEffects,
1119 /*IsMask=*/false, /*HasMaskedOffOperand=*/false, HasVL,
1120 HasNoMaskedOverloaded, HasAutoDef, ManualCodegen, Types.getValue(),
1121 IntrinsicTypes, RequiredExtension));
1122 if (HasMask) {
1123 // Create a mask intrinsic
1124 Optional<RVVTypes> MaskTypes =
1125 computeTypes(I, Log2LMUL, ProtoMaskSeq);
1126 Out.push_back(std::make_unique<RVVIntrinsic>(
1127 Name, SuffixStr, MangledName, IRNameMask, HasSideEffects,
1128 /*IsMask=*/true, HasMaskedOffOperand, HasVL,
1129 HasNoMaskedOverloaded, HasAutoDef, ManualCodegenMask,
1130 MaskTypes.getValue(), IntrinsicTypes, RequiredExtension));
1131 }
1132 } // end for Log2LMULList
1133 } // end for TypeRange
1134 }
1135 }
1136
1137 Optional<RVVTypes>
computeTypes(BasicType BT,int Log2LMUL,ArrayRef<std::string> PrototypeSeq)1138 RVVEmitter::computeTypes(BasicType BT, int Log2LMUL,
1139 ArrayRef<std::string> PrototypeSeq) {
1140 RVVTypes Types;
1141 for (const std::string &Proto : PrototypeSeq) {
1142 auto T = computeType(BT, Log2LMUL, Proto);
1143 if (!T.hasValue())
1144 return llvm::None;
1145 // Record legal type index
1146 Types.push_back(T.getValue());
1147 }
1148 return Types;
1149 }
1150
computeType(BasicType BT,int Log2LMUL,StringRef Proto)1151 Optional<RVVTypePtr> RVVEmitter::computeType(BasicType BT, int Log2LMUL,
1152 StringRef Proto) {
1153 std::string Idx = Twine(Twine(BT) + Twine(Log2LMUL) + Proto).str();
1154 // Search first
1155 auto It = LegalTypes.find(Idx);
1156 if (It != LegalTypes.end())
1157 return &(It->second);
1158 if (IllegalTypes.count(Idx))
1159 return llvm::None;
1160 // Compute type and record the result.
1161 RVVType T(BT, Log2LMUL, Proto);
1162 if (T.isValid()) {
1163 // Record legal type index and value.
1164 LegalTypes.insert({Idx, T});
1165 return &(LegalTypes[Idx]);
1166 }
1167 // Record illegal type index.
1168 IllegalTypes.insert(Idx);
1169 return llvm::None;
1170 }
1171
emitArchMacroAndBody(std::vector<std::unique_ptr<RVVIntrinsic>> & Defs,raw_ostream & OS,std::function<void (raw_ostream &,const RVVIntrinsic &)> PrintBody)1172 void RVVEmitter::emitArchMacroAndBody(
1173 std::vector<std::unique_ptr<RVVIntrinsic>> &Defs, raw_ostream &OS,
1174 std::function<void(raw_ostream &, const RVVIntrinsic &)> PrintBody) {
1175 uint8_t PrevExt = (*Defs.begin())->getRISCVExtensions();
1176 bool NeedEndif = emitExtDefStr(PrevExt, OS);
1177 for (auto &Def : Defs) {
1178 uint8_t CurExt = Def->getRISCVExtensions();
1179 if (CurExt != PrevExt) {
1180 if (NeedEndif)
1181 OS << "#endif\n\n";
1182 NeedEndif = emitExtDefStr(CurExt, OS);
1183 PrevExt = CurExt;
1184 }
1185 if (Def->hasAutoDef())
1186 PrintBody(OS, *Def);
1187 }
1188 if (NeedEndif)
1189 OS << "#endif\n\n";
1190 }
1191
emitExtDefStr(uint8_t Extents,raw_ostream & OS)1192 bool RVVEmitter::emitExtDefStr(uint8_t Extents, raw_ostream &OS) {
1193 if (Extents == RISCVExtension::Basic)
1194 return false;
1195 OS << "#if ";
1196 ListSeparator LS(" && ");
1197 if (Extents & RISCVExtension::F)
1198 OS << LS << "defined(__riscv_f)";
1199 if (Extents & RISCVExtension::D)
1200 OS << LS << "defined(__riscv_d)";
1201 if (Extents & RISCVExtension::Zfh)
1202 OS << LS << "defined(__riscv_zfh)";
1203 if (Extents & RISCVExtension::Zvamo)
1204 OS << LS << "defined(__riscv_zvamo)";
1205 OS << "\n";
1206 return true;
1207 }
1208
1209 namespace clang {
EmitRVVHeader(RecordKeeper & Records,raw_ostream & OS)1210 void EmitRVVHeader(RecordKeeper &Records, raw_ostream &OS) {
1211 RVVEmitter(Records).createHeader(OS);
1212 }
1213
EmitRVVBuiltins(RecordKeeper & Records,raw_ostream & OS)1214 void EmitRVVBuiltins(RecordKeeper &Records, raw_ostream &OS) {
1215 RVVEmitter(Records).createBuiltins(OS);
1216 }
1217
EmitRVVBuiltinCG(RecordKeeper & Records,raw_ostream & OS)1218 void EmitRVVBuiltinCG(RecordKeeper &Records, raw_ostream &OS) {
1219 RVVEmitter(Records).createCodeGen(OS);
1220 }
1221
1222 } // End namespace clang
1223