1//===- SveEmitter.cpp - Generate arm_sve.h for use with clang -*- 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// This tablegen backend is responsible for emitting arm_sve.h, which includes
10// a declaration and definition of each function specified by the ARM C/C++
11// Language Extensions (ACLE).
12//
13// For details, visit:
14// https://developer.arm.com/architectures/system-architectures/software-standards/acle
15//
16// Each SVE instruction is implemented in terms of 1 or more functions which
17// are suffixed with the element type of the input vectors. Functions may be
18// implemented in terms of generic vector operations such as +, *, -, etc. or
19// by calling a __builtin_-prefixed function which will be handled by clang's
20// CodeGen library.
21//
22// See also the documentation in include/clang/Basic/arm_sve.td.
23//
24//===----------------------------------------------------------------------===//
25
26#include "llvm/ADT/ArrayRef.h"
27#include "llvm/ADT/STLExtras.h"
28#include "llvm/ADT/StringExtras.h"
29#include "llvm/ADT/StringMap.h"
30#include "llvm/TableGen/Error.h"
31#include "llvm/TableGen/Record.h"
32#include <array>
33#include <cctype>
34#include <set>
35#include <sstream>
36#include <string>
37#include <tuple>
38
39using namespace llvm;
40
41enum ClassKind {
42 ClassNone,
43 ClassS, // signed/unsigned, e.g., "_s8", "_u8" suffix
44 ClassG, // Overloaded name without type suffix
45};
46
47enum class ACLEKind { SVE, SME };
48
49using TypeSpec = std::string;
50
51namespace {
52
53class ImmCheck {
54 unsigned Arg;
55 unsigned Kind;
56 unsigned ElementSizeInBits;
57
58public:
59 ImmCheck(unsigned Arg, unsigned Kind, unsigned ElementSizeInBits = 0)
60 : Arg(Arg), Kind(Kind), ElementSizeInBits(ElementSizeInBits) {}
61 ImmCheck(const ImmCheck &Other) = default;
62 ~ImmCheck() = default;
63
64 unsigned getArg() const { return Arg; }
65 unsigned getKind() const { return Kind; }
66 unsigned getElementSizeInBits() const { return ElementSizeInBits; }
67};
68
69class SVEType {
70 bool Float, Signed, Immediate, Void, Constant, Pointer, BFloat;
71 bool DefaultType, IsScalable, Predicate, PredicatePattern, PrefetchOp,
72 Svcount;
73 unsigned Bitwidth, ElementBitwidth, NumVectors;
74
75public:
76 SVEType() : SVEType("", 'v') {}
77
78 SVEType(StringRef TS, char CharMod, unsigned NumVectors = 1)
79 : Float(false), Signed(true), Immediate(false), Void(false),
80 Constant(false), Pointer(false), BFloat(false), DefaultType(false),
81 IsScalable(true), Predicate(false), PredicatePattern(false),
82 PrefetchOp(false), Svcount(false), Bitwidth(128), ElementBitwidth(~0U),
83 NumVectors(NumVectors) {
84 if (!TS.empty())
85 applyTypespec(TS);
86 applyModifier(Mod: CharMod);
87 }
88
89 SVEType(const SVEType &Base, unsigned NumV) : SVEType(Base) {
90 NumVectors = NumV;
91 }
92
93 bool isPointer() const { return Pointer; }
94 bool isVoidPointer() const { return Pointer && Void; }
95 bool isSigned() const { return Signed; }
96 bool isImmediate() const { return Immediate; }
97 bool isScalar() const { return NumVectors == 0; }
98 bool isVector() const { return NumVectors > 0; }
99 bool isScalableVector() const { return isVector() && IsScalable; }
100 bool isFixedLengthVector() const { return isVector() && !IsScalable; }
101 bool isChar() const { return ElementBitwidth == 8; }
102 bool isVoid() const { return Void && !Pointer; }
103 bool isDefault() const { return DefaultType; }
104 bool isFloat() const { return Float && !BFloat; }
105 bool isBFloat() const { return BFloat && !Float; }
106 bool isFloatingPoint() const { return Float || BFloat; }
107 bool isInteger() const {
108 return !isFloatingPoint() && !Predicate && !Svcount;
109 }
110 bool isScalarPredicate() const {
111 return !isFloatingPoint() && Predicate && NumVectors == 0;
112 }
113 bool isPredicateVector() const { return Predicate; }
114 bool isPredicatePattern() const { return PredicatePattern; }
115 bool isPrefetchOp() const { return PrefetchOp; }
116 bool isSvcount() const { return Svcount; }
117 bool isConstant() const { return Constant; }
118 unsigned getElementSizeInBits() const { return ElementBitwidth; }
119 unsigned getNumVectors() const { return NumVectors; }
120
121 unsigned getNumElements() const {
122 assert(ElementBitwidth != ~0U);
123 return Bitwidth / ElementBitwidth;
124 }
125 unsigned getSizeInBits() const {
126 return Bitwidth;
127 }
128
129 /// Return the string representation of a type, which is an encoded
130 /// string for passing to the BUILTIN() macro in Builtins.def.
131 std::string builtin_str() const;
132
133 /// Return the C/C++ string representation of a type for use in the
134 /// arm_sve.h header file.
135 std::string str() const;
136
137private:
138 /// Creates the type based on the typespec string in TS.
139 void applyTypespec(StringRef TS);
140
141 /// Applies a prototype modifier to the type.
142 void applyModifier(char Mod);
143};
144
145class SVEEmitter;
146
147/// The main grunt class. This represents an instantiation of an intrinsic with
148/// a particular typespec and prototype.
149class Intrinsic {
150 /// The unmangled name.
151 std::string Name;
152
153 /// The name of the corresponding LLVM IR intrinsic.
154 std::string LLVMName;
155
156 /// Intrinsic prototype.
157 std::string Proto;
158
159 /// The base type spec for this intrinsic.
160 TypeSpec BaseTypeSpec;
161
162 /// The base class kind. Most intrinsics use ClassS, which has full type
163 /// info for integers (_s32/_u32), or ClassG which is used for overloaded
164 /// intrinsics.
165 ClassKind Class;
166
167 /// The architectural #ifdef guard.
168 std::string Guard;
169
170 // The merge suffix such as _m, _x or _z.
171 std::string MergeSuffix;
172
173 /// The types of return value [0] and parameters [1..].
174 std::vector<SVEType> Types;
175
176 /// The "base type", which is VarType('d', BaseTypeSpec).
177 SVEType BaseType;
178
179 uint64_t Flags;
180
181 SmallVector<ImmCheck, 2> ImmChecks;
182
183public:
184 Intrinsic(StringRef Name, StringRef Proto, uint64_t MergeTy,
185 StringRef MergeSuffix, uint64_t MemoryElementTy, StringRef LLVMName,
186 uint64_t Flags, ArrayRef<ImmCheck> ImmChecks, TypeSpec BT,
187 ClassKind Class, SVEEmitter &Emitter, StringRef Guard);
188
189 ~Intrinsic()=default;
190
191 std::string getName() const { return Name; }
192 std::string getLLVMName() const { return LLVMName; }
193 std::string getProto() const { return Proto; }
194 TypeSpec getBaseTypeSpec() const { return BaseTypeSpec; }
195 SVEType getBaseType() const { return BaseType; }
196
197 StringRef getGuard() const { return Guard; }
198 ClassKind getClassKind() const { return Class; }
199
200 SVEType getReturnType() const { return Types[0]; }
201 ArrayRef<SVEType> getTypes() const { return Types; }
202 SVEType getParamType(unsigned I) const { return Types[I + 1]; }
203 unsigned getNumParams() const {
204 return Proto.size() - (2 * llvm::count(Range: Proto, Element: '.')) - 1;
205 }
206
207 uint64_t getFlags() const { return Flags; }
208 bool isFlagSet(uint64_t Flag) const { return Flags & Flag;}
209
210 ArrayRef<ImmCheck> getImmChecks() const { return ImmChecks; }
211
212 /// Return the type string for a BUILTIN() macro in Builtins.def.
213 std::string getBuiltinTypeStr();
214
215 /// Return the name, mangled with type information. The name is mangled for
216 /// ClassS, so will add type suffixes such as _u32/_s32.
217 std::string getMangledName() const { return mangleName(LocalCK: ClassS); }
218
219 /// As above, but mangles the LLVM name instead.
220 std::string getMangledLLVMName() const { return mangleLLVMName(); }
221
222 /// Returns true if the intrinsic is overloaded, in that it should also generate
223 /// a short form without the type-specifiers, e.g. 'svld1(..)' instead of
224 /// 'svld1_u32(..)'.
225 static bool isOverloadedIntrinsic(StringRef Name) {
226 auto BrOpen = Name.find(C: '[');
227 auto BrClose = Name.find(C: ']');
228 return BrOpen != std::string::npos && BrClose != std::string::npos;
229 }
230
231 /// Return true if the intrinsic takes a splat operand.
232 bool hasSplat() const {
233 // These prototype modifiers are described in arm_sve.td.
234 return Proto.find_first_of(s: "ajfrKLR@") != std::string::npos;
235 }
236
237 /// Return the parameter index of the splat operand.
238 unsigned getSplatIdx() const {
239 unsigned I = 1, Param = 0;
240 for (; I < Proto.size(); ++I, ++Param) {
241 if (Proto[I] == 'a' || Proto[I] == 'j' || Proto[I] == 'f' ||
242 Proto[I] == 'r' || Proto[I] == 'K' || Proto[I] == 'L' ||
243 Proto[I] == 'R' || Proto[I] == '@')
244 break;
245
246 // Multivector modifier can be skipped
247 if (Proto[I] == '.')
248 I += 2;
249 }
250 assert(I != Proto.size() && "Prototype has no splat operand");
251 return Param;
252 }
253
254 /// Emits the intrinsic declaration to the ostream.
255 void emitIntrinsic(raw_ostream &OS, SVEEmitter &Emitter, ACLEKind Kind) const;
256
257private:
258 std::string getMergeSuffix() const { return MergeSuffix; }
259 std::string mangleName(ClassKind LocalCK) const;
260 std::string mangleLLVMName() const;
261 std::string replaceTemplatedArgs(std::string Name, TypeSpec TS,
262 std::string Proto) const;
263};
264
265class SVEEmitter {
266private:
267 // The reinterpret builtins are generated separately because they
268 // need the cross product of all types (121 functions in total),
269 // which is inconvenient to specify in the arm_sve.td file or
270 // generate in CGBuiltin.cpp.
271 struct ReinterpretTypeInfo {
272 SVEType BaseType;
273 const char *Suffix;
274 };
275
276 static const std::array<ReinterpretTypeInfo, 12> Reinterprets;
277
278 RecordKeeper &Records;
279 llvm::StringMap<uint64_t> EltTypes;
280 llvm::StringMap<uint64_t> MemEltTypes;
281 llvm::StringMap<uint64_t> FlagTypes;
282 llvm::StringMap<uint64_t> MergeTypes;
283 llvm::StringMap<uint64_t> ImmCheckTypes;
284
285public:
286 SVEEmitter(RecordKeeper &R) : Records(R) {
287 for (auto *RV : Records.getAllDerivedDefinitions(ClassName: "EltType"))
288 EltTypes[RV->getNameInitAsString()] = RV->getValueAsInt(FieldName: "Value");
289 for (auto *RV : Records.getAllDerivedDefinitions(ClassName: "MemEltType"))
290 MemEltTypes[RV->getNameInitAsString()] = RV->getValueAsInt(FieldName: "Value");
291 for (auto *RV : Records.getAllDerivedDefinitions(ClassName: "FlagType"))
292 FlagTypes[RV->getNameInitAsString()] = RV->getValueAsInt(FieldName: "Value");
293 for (auto *RV : Records.getAllDerivedDefinitions(ClassName: "MergeType"))
294 MergeTypes[RV->getNameInitAsString()] = RV->getValueAsInt(FieldName: "Value");
295 for (auto *RV : Records.getAllDerivedDefinitions(ClassName: "ImmCheckType"))
296 ImmCheckTypes[RV->getNameInitAsString()] = RV->getValueAsInt(FieldName: "Value");
297 }
298
299 /// Returns the enum value for the immcheck type
300 unsigned getEnumValueForImmCheck(StringRef C) const {
301 auto It = ImmCheckTypes.find(Key: C);
302 if (It != ImmCheckTypes.end())
303 return It->getValue();
304 llvm_unreachable("Unsupported imm check");
305 }
306
307 /// Returns the enum value for the flag type
308 uint64_t getEnumValueForFlag(StringRef C) const {
309 auto Res = FlagTypes.find(Key: C);
310 if (Res != FlagTypes.end())
311 return Res->getValue();
312 llvm_unreachable("Unsupported flag");
313 }
314
315 // Returns the SVETypeFlags for a given value and mask.
316 uint64_t encodeFlag(uint64_t V, StringRef MaskName) const {
317 auto It = FlagTypes.find(Key: MaskName);
318 if (It != FlagTypes.end()) {
319 uint64_t Mask = It->getValue();
320 unsigned Shift = llvm::countr_zero(Val: Mask);
321 assert(Shift < 64 && "Mask value produced an invalid shift value");
322 return (V << Shift) & Mask;
323 }
324 llvm_unreachable("Unsupported flag");
325 }
326
327 // Returns the SVETypeFlags for the given element type.
328 uint64_t encodeEltType(StringRef EltName) {
329 auto It = EltTypes.find(Key: EltName);
330 if (It != EltTypes.end())
331 return encodeFlag(V: It->getValue(), MaskName: "EltTypeMask");
332 llvm_unreachable("Unsupported EltType");
333 }
334
335 // Returns the SVETypeFlags for the given memory element type.
336 uint64_t encodeMemoryElementType(uint64_t MT) {
337 return encodeFlag(V: MT, MaskName: "MemEltTypeMask");
338 }
339
340 // Returns the SVETypeFlags for the given merge type.
341 uint64_t encodeMergeType(uint64_t MT) {
342 return encodeFlag(V: MT, MaskName: "MergeTypeMask");
343 }
344
345 // Returns the SVETypeFlags for the given splat operand.
346 unsigned encodeSplatOperand(unsigned SplatIdx) {
347 assert(SplatIdx < 7 && "SplatIdx out of encodable range");
348 return encodeFlag(V: SplatIdx + 1, MaskName: "SplatOperandMask");
349 }
350
351 // Returns the SVETypeFlags value for the given SVEType.
352 uint64_t encodeTypeFlags(const SVEType &T);
353
354 /// Emit arm_sve.h.
355 void createHeader(raw_ostream &o);
356
357 // Emits core intrinsics in both arm_sme.h and arm_sve.h
358 void createCoreHeaderIntrinsics(raw_ostream &o, SVEEmitter &Emitter,
359 ACLEKind Kind);
360
361 /// Emit all the __builtin prototypes and code needed by Sema.
362 void createBuiltins(raw_ostream &o);
363
364 /// Emit all the information needed to map builtin -> LLVM IR intrinsic.
365 void createCodeGenMap(raw_ostream &o);
366
367 /// Emit all the range checks for the immediates.
368 void createRangeChecks(raw_ostream &o);
369
370 /// Create the SVETypeFlags used in CGBuiltins
371 void createTypeFlags(raw_ostream &o);
372
373 /// Emit arm_sme.h.
374 void createSMEHeader(raw_ostream &o);
375
376 /// Emit all the SME __builtin prototypes and code needed by Sema.
377 void createSMEBuiltins(raw_ostream &o);
378
379 /// Emit all the information needed to map builtin -> LLVM IR intrinsic.
380 void createSMECodeGenMap(raw_ostream &o);
381
382 /// Create a table for a builtin's requirement for PSTATE.SM.
383 void createStreamingAttrs(raw_ostream &o, ACLEKind Kind);
384
385 /// Emit all the range checks for the immediates.
386 void createSMERangeChecks(raw_ostream &o);
387
388 /// Create a table for a builtin's requirement for PSTATE.ZA.
389 void createBuiltinZAState(raw_ostream &OS);
390
391 /// Create intrinsic and add it to \p Out
392 void createIntrinsic(Record *R,
393 SmallVectorImpl<std::unique_ptr<Intrinsic>> &Out);
394};
395
396const std::array<SVEEmitter::ReinterpretTypeInfo, 12> SVEEmitter::Reinterprets =
397 {._M_elems: {{.BaseType: SVEType("c", 'd'), .Suffix: "s8"},
398 {.BaseType: SVEType("Uc", 'd'), .Suffix: "u8"},
399 {.BaseType: SVEType("s", 'd'), .Suffix: "s16"},
400 {.BaseType: SVEType("Us", 'd'), .Suffix: "u16"},
401 {.BaseType: SVEType("i", 'd'), .Suffix: "s32"},
402 {.BaseType: SVEType("Ui", 'd'), .Suffix: "u32"},
403 {.BaseType: SVEType("l", 'd'), .Suffix: "s64"},
404 {.BaseType: SVEType("Ul", 'd'), .Suffix: "u64"},
405 {.BaseType: SVEType("h", 'd'), .Suffix: "f16"},
406 {.BaseType: SVEType("b", 'd'), .Suffix: "bf16"},
407 {.BaseType: SVEType("f", 'd'), .Suffix: "f32"},
408 {.BaseType: SVEType("d", 'd'), .Suffix: "f64"}}};
409
410} // end anonymous namespace
411
412
413//===----------------------------------------------------------------------===//
414// Type implementation
415//===----------------------------------------------------------------------===//
416
417std::string SVEType::builtin_str() const {
418 std::string S;
419 if (isVoid())
420 return "v";
421
422 if (isScalarPredicate())
423 return "b";
424
425 if (isSvcount())
426 return "Qa";
427
428 if (isVoidPointer())
429 S += "v";
430 else if (!isFloatingPoint())
431 switch (ElementBitwidth) {
432 case 1: S += "b"; break;
433 case 8: S += "c"; break;
434 case 16: S += "s"; break;
435 case 32: S += "i"; break;
436 case 64: S += "Wi"; break;
437 case 128: S += "LLLi"; break;
438 default: llvm_unreachable("Unhandled case!");
439 }
440 else if (isFloat())
441 switch (ElementBitwidth) {
442 case 16: S += "h"; break;
443 case 32: S += "f"; break;
444 case 64: S += "d"; break;
445 default: llvm_unreachable("Unhandled case!");
446 }
447 else if (isBFloat()) {
448 assert(ElementBitwidth == 16 && "Not a valid BFloat.");
449 S += "y";
450 }
451
452 if (!isFloatingPoint()) {
453 if ((isChar() || isPointer()) && !isVoidPointer()) {
454 // Make chars and typed pointers explicitly signed.
455 if (Signed)
456 S = "S" + S;
457 else if (!Signed)
458 S = "U" + S;
459 } else if (!isVoidPointer() && !Signed) {
460 S = "U" + S;
461 }
462 }
463
464 // Constant indices are "int", but have the "constant expression" modifier.
465 if (isImmediate()) {
466 assert(!isFloat() && "fp immediates are not supported");
467 S = "I" + S;
468 }
469
470 if (isScalar()) {
471 if (Constant) S += "C";
472 if (Pointer) S += "*";
473 return S;
474 }
475
476 if (isFixedLengthVector())
477 return "V" + utostr(X: getNumElements() * NumVectors) + S;
478 return "q" + utostr(X: getNumElements() * NumVectors) + S;
479}
480
481std::string SVEType::str() const {
482 if (isPredicatePattern())
483 return "enum svpattern";
484
485 if (isPrefetchOp())
486 return "enum svprfop";
487
488 std::string S;
489 if (Void)
490 S += "void";
491 else {
492 if (isScalableVector() || isSvcount())
493 S += "sv";
494 if (!Signed && !isFloatingPoint())
495 S += "u";
496
497 if (Float)
498 S += "float";
499 else if (isSvcount())
500 S += "count";
501 else if (isScalarPredicate() || isPredicateVector())
502 S += "bool";
503 else if (isBFloat())
504 S += "bfloat";
505 else
506 S += "int";
507
508 if (!isScalarPredicate() && !isPredicateVector() && !isSvcount())
509 S += utostr(X: ElementBitwidth);
510 if (isFixedLengthVector())
511 S += "x" + utostr(X: getNumElements());
512 if (NumVectors > 1)
513 S += "x" + utostr(X: NumVectors);
514 if (!isScalarPredicate())
515 S += "_t";
516 }
517
518 if (Constant)
519 S += " const";
520 if (Pointer)
521 S += " *";
522
523 return S;
524}
525
526void SVEType::applyTypespec(StringRef TS) {
527 for (char I : TS) {
528 switch (I) {
529 case 'Q':
530 Svcount = true;
531 break;
532 case 'P':
533 Predicate = true;
534 break;
535 case 'U':
536 Signed = false;
537 break;
538 case 'c':
539 ElementBitwidth = 8;
540 break;
541 case 's':
542 ElementBitwidth = 16;
543 break;
544 case 'i':
545 ElementBitwidth = 32;
546 break;
547 case 'l':
548 ElementBitwidth = 64;
549 break;
550 case 'q':
551 ElementBitwidth = 128;
552 break;
553 case 'h':
554 Float = true;
555 ElementBitwidth = 16;
556 break;
557 case 'f':
558 Float = true;
559 ElementBitwidth = 32;
560 break;
561 case 'd':
562 Float = true;
563 ElementBitwidth = 64;
564 break;
565 case 'b':
566 BFloat = true;
567 Float = false;
568 ElementBitwidth = 16;
569 break;
570 default:
571 llvm_unreachable("Unhandled type code!");
572 }
573 }
574 assert(ElementBitwidth != ~0U && "Bad element bitwidth!");
575}
576
577void SVEType::applyModifier(char Mod) {
578 switch (Mod) {
579 case 'v':
580 Void = true;
581 break;
582 case 'd':
583 DefaultType = true;
584 break;
585 case 'c':
586 Constant = true;
587 [[fallthrough]];
588 case 'p':
589 Pointer = true;
590 Bitwidth = ElementBitwidth;
591 NumVectors = 0;
592 break;
593 case 'e':
594 Signed = false;
595 ElementBitwidth /= 2;
596 break;
597 case 'h':
598 ElementBitwidth /= 2;
599 break;
600 case 'q':
601 ElementBitwidth /= 4;
602 break;
603 case 'b':
604 Signed = false;
605 Float = false;
606 BFloat = false;
607 ElementBitwidth /= 4;
608 break;
609 case 'o':
610 ElementBitwidth *= 4;
611 break;
612 case 'P':
613 Signed = true;
614 Float = false;
615 BFloat = false;
616 Predicate = true;
617 Svcount = false;
618 Bitwidth = 16;
619 ElementBitwidth = 1;
620 break;
621 case '{':
622 IsScalable = false;
623 Bitwidth = 128;
624 NumVectors = 1;
625 break;
626 case 's':
627 case 'a':
628 Bitwidth = ElementBitwidth;
629 NumVectors = 0;
630 break;
631 case 'R':
632 ElementBitwidth /= 2;
633 NumVectors = 0;
634 break;
635 case 'r':
636 ElementBitwidth /= 4;
637 NumVectors = 0;
638 break;
639 case '@':
640 Signed = false;
641 Float = false;
642 BFloat = false;
643 ElementBitwidth /= 4;
644 NumVectors = 0;
645 break;
646 case 'K':
647 Signed = true;
648 Float = false;
649 BFloat = false;
650 Bitwidth = ElementBitwidth;
651 NumVectors = 0;
652 break;
653 case 'L':
654 Signed = false;
655 Float = false;
656 BFloat = false;
657 Bitwidth = ElementBitwidth;
658 NumVectors = 0;
659 break;
660 case 'u':
661 Predicate = false;
662 Svcount = false;
663 Signed = false;
664 Float = false;
665 BFloat = false;
666 break;
667 case 'x':
668 Predicate = false;
669 Svcount = false;
670 Signed = true;
671 Float = false;
672 BFloat = false;
673 break;
674 case 'i':
675 Predicate = false;
676 Svcount = false;
677 Float = false;
678 BFloat = false;
679 ElementBitwidth = Bitwidth = 64;
680 NumVectors = 0;
681 Signed = false;
682 Immediate = true;
683 break;
684 case 'I':
685 Predicate = false;
686 Svcount = false;
687 Float = false;
688 BFloat = false;
689 ElementBitwidth = Bitwidth = 32;
690 NumVectors = 0;
691 Signed = true;
692 Immediate = true;
693 PredicatePattern = true;
694 break;
695 case 'J':
696 Predicate = false;
697 Svcount = false;
698 Float = false;
699 BFloat = false;
700 ElementBitwidth = Bitwidth = 32;
701 NumVectors = 0;
702 Signed = true;
703 Immediate = true;
704 PrefetchOp = true;
705 break;
706 case 'k':
707 Predicate = false;
708 Svcount = false;
709 Signed = true;
710 Float = false;
711 BFloat = false;
712 ElementBitwidth = Bitwidth = 32;
713 NumVectors = 0;
714 break;
715 case 'l':
716 Predicate = false;
717 Svcount = false;
718 Signed = true;
719 Float = false;
720 BFloat = false;
721 ElementBitwidth = Bitwidth = 64;
722 NumVectors = 0;
723 break;
724 case 'm':
725 Predicate = false;
726 Svcount = false;
727 Signed = false;
728 Float = false;
729 BFloat = false;
730 ElementBitwidth = Bitwidth = 32;
731 NumVectors = 0;
732 break;
733 case 'n':
734 Predicate = false;
735 Svcount = false;
736 Signed = false;
737 Float = false;
738 BFloat = false;
739 ElementBitwidth = Bitwidth = 64;
740 NumVectors = 0;
741 break;
742 case 'w':
743 ElementBitwidth = 64;
744 break;
745 case 'j':
746 ElementBitwidth = Bitwidth = 64;
747 NumVectors = 0;
748 break;
749 case 'f':
750 Signed = false;
751 ElementBitwidth = Bitwidth = 64;
752 NumVectors = 0;
753 break;
754 case 'g':
755 Signed = false;
756 Float = false;
757 BFloat = false;
758 ElementBitwidth = 64;
759 break;
760 case '[':
761 Signed = false;
762 Float = false;
763 BFloat = false;
764 ElementBitwidth = 8;
765 break;
766 case 't':
767 Signed = true;
768 Float = false;
769 BFloat = false;
770 ElementBitwidth = 32;
771 break;
772 case 'z':
773 Signed = false;
774 Float = false;
775 BFloat = false;
776 ElementBitwidth = 32;
777 break;
778 case 'O':
779 Predicate = false;
780 Svcount = false;
781 Float = true;
782 ElementBitwidth = 16;
783 break;
784 case 'M':
785 Predicate = false;
786 Svcount = false;
787 Float = true;
788 BFloat = false;
789 ElementBitwidth = 32;
790 break;
791 case 'N':
792 Predicate = false;
793 Svcount = false;
794 Float = true;
795 ElementBitwidth = 64;
796 break;
797 case 'Q':
798 Constant = true;
799 Pointer = true;
800 Void = true;
801 NumVectors = 0;
802 break;
803 case 'S':
804 Constant = true;
805 Pointer = true;
806 ElementBitwidth = Bitwidth = 8;
807 NumVectors = 0;
808 Signed = true;
809 break;
810 case 'W':
811 Constant = true;
812 Pointer = true;
813 ElementBitwidth = Bitwidth = 8;
814 NumVectors = 0;
815 Signed = false;
816 break;
817 case 'T':
818 Constant = true;
819 Pointer = true;
820 ElementBitwidth = Bitwidth = 16;
821 NumVectors = 0;
822 Signed = true;
823 break;
824 case 'X':
825 Constant = true;
826 Pointer = true;
827 ElementBitwidth = Bitwidth = 16;
828 NumVectors = 0;
829 Signed = false;
830 break;
831 case 'Y':
832 Constant = true;
833 Pointer = true;
834 ElementBitwidth = Bitwidth = 32;
835 NumVectors = 0;
836 Signed = false;
837 break;
838 case 'U':
839 Constant = true;
840 Pointer = true;
841 ElementBitwidth = Bitwidth = 32;
842 NumVectors = 0;
843 Signed = true;
844 break;
845 case '%':
846 Pointer = true;
847 Void = true;
848 NumVectors = 0;
849 break;
850 case 'A':
851 Pointer = true;
852 ElementBitwidth = Bitwidth = 8;
853 NumVectors = 0;
854 Signed = true;
855 break;
856 case 'B':
857 Pointer = true;
858 ElementBitwidth = Bitwidth = 16;
859 NumVectors = 0;
860 Signed = true;
861 break;
862 case 'C':
863 Pointer = true;
864 ElementBitwidth = Bitwidth = 32;
865 NumVectors = 0;
866 Signed = true;
867 break;
868 case 'D':
869 Pointer = true;
870 ElementBitwidth = Bitwidth = 64;
871 NumVectors = 0;
872 Signed = true;
873 break;
874 case 'E':
875 Pointer = true;
876 ElementBitwidth = Bitwidth = 8;
877 NumVectors = 0;
878 Signed = false;
879 break;
880 case 'F':
881 Pointer = true;
882 ElementBitwidth = Bitwidth = 16;
883 NumVectors = 0;
884 Signed = false;
885 break;
886 case 'G':
887 Pointer = true;
888 ElementBitwidth = Bitwidth = 32;
889 NumVectors = 0;
890 Signed = false;
891 break;
892 case '$':
893 Predicate = false;
894 Svcount = false;
895 Float = false;
896 BFloat = true;
897 ElementBitwidth = 16;
898 break;
899 case '}':
900 Predicate = false;
901 Signed = true;
902 Svcount = true;
903 NumVectors = 0;
904 Float = false;
905 BFloat = false;
906 break;
907 case '.':
908 llvm_unreachable(". is never a type in itself");
909 break;
910 default:
911 llvm_unreachable("Unhandled character!");
912 }
913}
914
915/// Returns the modifier and number of vectors for the given operand \p Op.
916std::pair<char, unsigned> getProtoModifier(StringRef Proto, unsigned Op) {
917 for (unsigned P = 0; !Proto.empty(); ++P) {
918 unsigned NumVectors = 1;
919 unsigned CharsToSkip = 1;
920 char Mod = Proto[0];
921 if (Mod == '2' || Mod == '3' || Mod == '4') {
922 NumVectors = Mod - '0';
923 Mod = 'd';
924 if (Proto.size() > 1 && Proto[1] == '.') {
925 Mod = Proto[2];
926 CharsToSkip = 3;
927 }
928 }
929
930 if (P == Op)
931 return {Mod, NumVectors};
932
933 Proto = Proto.drop_front(N: CharsToSkip);
934 }
935 llvm_unreachable("Unexpected Op");
936}
937
938//===----------------------------------------------------------------------===//
939// Intrinsic implementation
940//===----------------------------------------------------------------------===//
941
942Intrinsic::Intrinsic(StringRef Name, StringRef Proto, uint64_t MergeTy,
943 StringRef MergeSuffix, uint64_t MemoryElementTy,
944 StringRef LLVMName, uint64_t Flags,
945 ArrayRef<ImmCheck> Checks, TypeSpec BT, ClassKind Class,
946 SVEEmitter &Emitter, StringRef Guard)
947 : Name(Name.str()), LLVMName(LLVMName), Proto(Proto.str()),
948 BaseTypeSpec(BT), Class(Class), Guard(Guard.str()),
949 MergeSuffix(MergeSuffix.str()), BaseType(BT, 'd'), Flags(Flags),
950 ImmChecks(Checks.begin(), Checks.end()) {
951 // Types[0] is the return value.
952 for (unsigned I = 0; I < (getNumParams() + 1); ++I) {
953 char Mod;
954 unsigned NumVectors;
955 std::tie(args&: Mod, args&: NumVectors) = getProtoModifier(Proto, Op: I);
956 SVEType T(BaseTypeSpec, Mod, NumVectors);
957 Types.push_back(x: T);
958
959 // Add range checks for immediates
960 if (I > 0) {
961 if (T.isPredicatePattern())
962 ImmChecks.emplace_back(
963 Args: I - 1, Args: Emitter.getEnumValueForImmCheck(C: "ImmCheck0_31"));
964 else if (T.isPrefetchOp())
965 ImmChecks.emplace_back(
966 Args: I - 1, Args: Emitter.getEnumValueForImmCheck(C: "ImmCheck0_13"));
967 }
968 }
969
970 // Set flags based on properties
971 this->Flags |= Emitter.encodeTypeFlags(T: BaseType);
972 this->Flags |= Emitter.encodeMemoryElementType(MT: MemoryElementTy);
973 this->Flags |= Emitter.encodeMergeType(MT: MergeTy);
974 if (hasSplat())
975 this->Flags |= Emitter.encodeSplatOperand(SplatIdx: getSplatIdx());
976}
977
978std::string Intrinsic::getBuiltinTypeStr() {
979 std::string S = getReturnType().builtin_str();
980 for (unsigned I = 0; I < getNumParams(); ++I)
981 S += getParamType(I).builtin_str();
982
983 return S;
984}
985
986std::string Intrinsic::replaceTemplatedArgs(std::string Name, TypeSpec TS,
987 std::string Proto) const {
988 std::string Ret = Name;
989 while (Ret.find(c: '{') != std::string::npos) {
990 size_t Pos = Ret.find(c: '{');
991 size_t End = Ret.find(c: '}');
992 unsigned NumChars = End - Pos + 1;
993 assert(NumChars == 3 && "Unexpected template argument");
994
995 SVEType T;
996 char C = Ret[Pos+1];
997 switch(C) {
998 default:
999 llvm_unreachable("Unknown predication specifier");
1000 case 'd':
1001 T = SVEType(TS, 'd');
1002 break;
1003 case '0':
1004 case '1':
1005 case '2':
1006 case '3':
1007 T = SVEType(TS, Proto[C - '0']);
1008 break;
1009 }
1010
1011 // Replace templated arg with the right suffix (e.g. u32)
1012 std::string TypeCode;
1013 if (T.isInteger())
1014 TypeCode = T.isSigned() ? 's' : 'u';
1015 else if (T.isSvcount())
1016 TypeCode = 'c';
1017 else if (T.isPredicateVector())
1018 TypeCode = 'b';
1019 else if (T.isBFloat())
1020 TypeCode = "bf";
1021 else
1022 TypeCode = 'f';
1023 Ret.replace(pos: Pos, n: NumChars, str: TypeCode + utostr(X: T.getElementSizeInBits()));
1024 }
1025
1026 return Ret;
1027}
1028
1029std::string Intrinsic::mangleLLVMName() const {
1030 std::string S = getLLVMName();
1031
1032 // Replace all {d} like expressions with e.g. 'u32'
1033 return replaceTemplatedArgs(Name: S, TS: getBaseTypeSpec(), Proto: getProto());
1034}
1035
1036std::string Intrinsic::mangleName(ClassKind LocalCK) const {
1037 std::string S = getName();
1038
1039 if (LocalCK == ClassG) {
1040 // Remove the square brackets and everything in between.
1041 while (S.find(c: '[') != std::string::npos) {
1042 auto Start = S.find(c: '[');
1043 auto End = S.find(c: ']');
1044 S.erase(pos: Start, n: (End-Start)+1);
1045 }
1046 } else {
1047 // Remove the square brackets.
1048 while (S.find(c: '[') != std::string::npos) {
1049 auto BrPos = S.find(c: '[');
1050 if (BrPos != std::string::npos)
1051 S.erase(pos: BrPos, n: 1);
1052 BrPos = S.find(c: ']');
1053 if (BrPos != std::string::npos)
1054 S.erase(pos: BrPos, n: 1);
1055 }
1056 }
1057
1058 // Replace all {d} like expressions with e.g. 'u32'
1059 return replaceTemplatedArgs(Name: S, TS: getBaseTypeSpec(), Proto: getProto()) +
1060 getMergeSuffix();
1061}
1062
1063void Intrinsic::emitIntrinsic(raw_ostream &OS, SVEEmitter &Emitter,
1064 ACLEKind Kind) const {
1065 bool IsOverloaded = getClassKind() == ClassG && getProto().size() > 1;
1066
1067 std::string FullName = mangleName(LocalCK: ClassS);
1068 std::string ProtoName = mangleName(LocalCK: getClassKind());
1069 OS << (IsOverloaded ? "__aio " : "__ai ")
1070 << "__attribute__((__clang_arm_builtin_alias(";
1071
1072 switch (Kind) {
1073 case ACLEKind::SME:
1074 OS << "__builtin_sme_" << FullName << ")";
1075 break;
1076 case ACLEKind::SVE:
1077 OS << "__builtin_sve_" << FullName << ")";
1078 break;
1079 }
1080
1081 OS << "))\n";
1082
1083 OS << getTypes()[0].str() << " " << ProtoName << "(";
1084 for (unsigned I = 0; I < getTypes().size() - 1; ++I) {
1085 if (I != 0)
1086 OS << ", ";
1087 OS << getTypes()[I + 1].str();
1088 }
1089 OS << ");\n";
1090}
1091
1092//===----------------------------------------------------------------------===//
1093// SVEEmitter implementation
1094//===----------------------------------------------------------------------===//
1095uint64_t SVEEmitter::encodeTypeFlags(const SVEType &T) {
1096 if (T.isFloat()) {
1097 switch (T.getElementSizeInBits()) {
1098 case 16:
1099 return encodeEltType(EltName: "EltTyFloat16");
1100 case 32:
1101 return encodeEltType(EltName: "EltTyFloat32");
1102 case 64:
1103 return encodeEltType(EltName: "EltTyFloat64");
1104 default:
1105 llvm_unreachable("Unhandled float element bitwidth!");
1106 }
1107 }
1108
1109 if (T.isBFloat()) {
1110 assert(T.getElementSizeInBits() == 16 && "Not a valid BFloat.");
1111 return encodeEltType(EltName: "EltTyBFloat16");
1112 }
1113
1114 if (T.isPredicateVector() || T.isSvcount()) {
1115 switch (T.getElementSizeInBits()) {
1116 case 8:
1117 return encodeEltType(EltName: "EltTyBool8");
1118 case 16:
1119 return encodeEltType(EltName: "EltTyBool16");
1120 case 32:
1121 return encodeEltType(EltName: "EltTyBool32");
1122 case 64:
1123 return encodeEltType(EltName: "EltTyBool64");
1124 default:
1125 llvm_unreachable("Unhandled predicate element bitwidth!");
1126 }
1127 }
1128
1129 switch (T.getElementSizeInBits()) {
1130 case 8:
1131 return encodeEltType(EltName: "EltTyInt8");
1132 case 16:
1133 return encodeEltType(EltName: "EltTyInt16");
1134 case 32:
1135 return encodeEltType(EltName: "EltTyInt32");
1136 case 64:
1137 return encodeEltType(EltName: "EltTyInt64");
1138 case 128:
1139 return encodeEltType(EltName: "EltTyInt128");
1140 default:
1141 llvm_unreachable("Unhandled integer element bitwidth!");
1142 }
1143}
1144
1145void SVEEmitter::createIntrinsic(
1146 Record *R, SmallVectorImpl<std::unique_ptr<Intrinsic>> &Out) {
1147 StringRef Name = R->getValueAsString(FieldName: "Name");
1148 StringRef Proto = R->getValueAsString(FieldName: "Prototype");
1149 StringRef Types = R->getValueAsString(FieldName: "Types");
1150 StringRef Guard = R->getValueAsString(FieldName: "TargetGuard");
1151 StringRef LLVMName = R->getValueAsString(FieldName: "LLVMIntrinsic");
1152 uint64_t Merge = R->getValueAsInt(FieldName: "Merge");
1153 StringRef MergeSuffix = R->getValueAsString(FieldName: "MergeSuffix");
1154 uint64_t MemEltType = R->getValueAsInt(FieldName: "MemEltType");
1155 std::vector<Record*> FlagsList = R->getValueAsListOfDefs(FieldName: "Flags");
1156 std::vector<Record*> ImmCheckList = R->getValueAsListOfDefs(FieldName: "ImmChecks");
1157
1158 int64_t Flags = 0;
1159 for (auto FlagRec : FlagsList)
1160 Flags |= FlagRec->getValueAsInt(FieldName: "Value");
1161
1162 // Create a dummy TypeSpec for non-overloaded builtins.
1163 if (Types.empty()) {
1164 assert((Flags & getEnumValueForFlag("IsOverloadNone")) &&
1165 "Expect TypeSpec for overloaded builtin!");
1166 Types = "i";
1167 }
1168
1169 // Extract type specs from string
1170 SmallVector<TypeSpec, 8> TypeSpecs;
1171 TypeSpec Acc;
1172 for (char I : Types) {
1173 Acc.push_back(c: I);
1174 if (islower(I)) {
1175 TypeSpecs.push_back(Elt: TypeSpec(Acc));
1176 Acc.clear();
1177 }
1178 }
1179
1180 // Remove duplicate type specs.
1181 llvm::sort(C&: TypeSpecs);
1182 TypeSpecs.erase(CS: std::unique(first: TypeSpecs.begin(), last: TypeSpecs.end()),
1183 CE: TypeSpecs.end());
1184
1185 // Create an Intrinsic for each type spec.
1186 for (auto TS : TypeSpecs) {
1187 // Collate a list of range/option checks for the immediates.
1188 SmallVector<ImmCheck, 2> ImmChecks;
1189 for (auto *R : ImmCheckList) {
1190 int64_t Arg = R->getValueAsInt(FieldName: "Arg");
1191 int64_t EltSizeArg = R->getValueAsInt(FieldName: "EltSizeArg");
1192 int64_t Kind = R->getValueAsDef(FieldName: "Kind")->getValueAsInt(FieldName: "Value");
1193 assert(Arg >= 0 && Kind >= 0 && "Arg and Kind must be nonnegative");
1194
1195 unsigned ElementSizeInBits = 0;
1196 char Mod;
1197 unsigned NumVectors;
1198 std::tie(args&: Mod, args&: NumVectors) = getProtoModifier(Proto, Op: EltSizeArg + 1);
1199 if (EltSizeArg >= 0)
1200 ElementSizeInBits = SVEType(TS, Mod, NumVectors).getElementSizeInBits();
1201 ImmChecks.push_back(Elt: ImmCheck(Arg, Kind, ElementSizeInBits));
1202 }
1203
1204 Out.push_back(Elt: std::make_unique<Intrinsic>(
1205 args&: Name, args&: Proto, args&: Merge, args&: MergeSuffix, args&: MemEltType, args&: LLVMName, args&: Flags, args&: ImmChecks,
1206 args&: TS, args: ClassS, args&: *this, args&: Guard));
1207
1208 // Also generate the short-form (e.g. svadd_m) for the given type-spec.
1209 if (Intrinsic::isOverloadedIntrinsic(Name))
1210 Out.push_back(Elt: std::make_unique<Intrinsic>(
1211 args&: Name, args&: Proto, args&: Merge, args&: MergeSuffix, args&: MemEltType, args&: LLVMName, args&: Flags,
1212 args&: ImmChecks, args&: TS, args: ClassG, args&: *this, args&: Guard));
1213 }
1214}
1215
1216void SVEEmitter::createCoreHeaderIntrinsics(raw_ostream &OS,
1217 SVEEmitter &Emitter,
1218 ACLEKind Kind) {
1219 SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
1220 std::vector<Record *> RV = Records.getAllDerivedDefinitions(ClassName: "Inst");
1221 for (auto *R : RV)
1222 createIntrinsic(R, Out&: Defs);
1223
1224 // Sort intrinsics in header file by following order/priority:
1225 // - Architectural guard (i.e. does it require SVE2 or SVE2_AES)
1226 // - Class (is intrinsic overloaded or not)
1227 // - Intrinsic name
1228 std::stable_sort(first: Defs.begin(), last: Defs.end(),
1229 comp: [](const std::unique_ptr<Intrinsic> &A,
1230 const std::unique_ptr<Intrinsic> &B) {
1231 auto ToTuple = [](const std::unique_ptr<Intrinsic> &I) {
1232 return std::make_tuple(args: I->getGuard(),
1233 args: (unsigned)I->getClassKind(),
1234 args: I->getName());
1235 };
1236 return ToTuple(A) < ToTuple(B);
1237 });
1238
1239 // Actually emit the intrinsic declarations.
1240 for (auto &I : Defs)
1241 I->emitIntrinsic(OS, Emitter, Kind);
1242}
1243
1244void SVEEmitter::createHeader(raw_ostream &OS) {
1245 OS << "/*===---- arm_sve.h - ARM SVE intrinsics "
1246 "-----------------------------------===\n"
1247 " *\n"
1248 " *\n"
1249 " * Part of the LLVM Project, under the Apache License v2.0 with LLVM "
1250 "Exceptions.\n"
1251 " * See https://llvm.org/LICENSE.txt for license information.\n"
1252 " * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n"
1253 " *\n"
1254 " *===-----------------------------------------------------------------"
1255 "------===\n"
1256 " */\n\n";
1257
1258 OS << "#ifndef __ARM_SVE_H\n";
1259 OS << "#define __ARM_SVE_H\n\n";
1260
1261 OS << "#if !defined(__LITTLE_ENDIAN__)\n";
1262 OS << "#error \"Big endian is currently not supported for arm_sve.h\"\n";
1263 OS << "#endif\n";
1264
1265 OS << "#include <stdint.h>\n\n";
1266 OS << "#ifdef __cplusplus\n";
1267 OS << "extern \"C\" {\n";
1268 OS << "#else\n";
1269 OS << "#include <stdbool.h>\n";
1270 OS << "#endif\n\n";
1271
1272 OS << "typedef __fp16 float16_t;\n";
1273 OS << "typedef float float32_t;\n";
1274 OS << "typedef double float64_t;\n";
1275
1276 OS << "typedef __SVInt8_t svint8_t;\n";
1277 OS << "typedef __SVInt16_t svint16_t;\n";
1278 OS << "typedef __SVInt32_t svint32_t;\n";
1279 OS << "typedef __SVInt64_t svint64_t;\n";
1280 OS << "typedef __SVUint8_t svuint8_t;\n";
1281 OS << "typedef __SVUint16_t svuint16_t;\n";
1282 OS << "typedef __SVUint32_t svuint32_t;\n";
1283 OS << "typedef __SVUint64_t svuint64_t;\n";
1284 OS << "typedef __SVFloat16_t svfloat16_t;\n\n";
1285
1286 OS << "typedef __SVBfloat16_t svbfloat16_t;\n";
1287
1288 OS << "#include <arm_bf16.h>\n";
1289 OS << "#include <arm_vector_types.h>\n";
1290
1291 OS << "typedef __SVFloat32_t svfloat32_t;\n";
1292 OS << "typedef __SVFloat64_t svfloat64_t;\n";
1293 OS << "typedef __clang_svint8x2_t svint8x2_t;\n";
1294 OS << "typedef __clang_svint16x2_t svint16x2_t;\n";
1295 OS << "typedef __clang_svint32x2_t svint32x2_t;\n";
1296 OS << "typedef __clang_svint64x2_t svint64x2_t;\n";
1297 OS << "typedef __clang_svuint8x2_t svuint8x2_t;\n";
1298 OS << "typedef __clang_svuint16x2_t svuint16x2_t;\n";
1299 OS << "typedef __clang_svuint32x2_t svuint32x2_t;\n";
1300 OS << "typedef __clang_svuint64x2_t svuint64x2_t;\n";
1301 OS << "typedef __clang_svfloat16x2_t svfloat16x2_t;\n";
1302 OS << "typedef __clang_svfloat32x2_t svfloat32x2_t;\n";
1303 OS << "typedef __clang_svfloat64x2_t svfloat64x2_t;\n";
1304 OS << "typedef __clang_svint8x3_t svint8x3_t;\n";
1305 OS << "typedef __clang_svint16x3_t svint16x3_t;\n";
1306 OS << "typedef __clang_svint32x3_t svint32x3_t;\n";
1307 OS << "typedef __clang_svint64x3_t svint64x3_t;\n";
1308 OS << "typedef __clang_svuint8x3_t svuint8x3_t;\n";
1309 OS << "typedef __clang_svuint16x3_t svuint16x3_t;\n";
1310 OS << "typedef __clang_svuint32x3_t svuint32x3_t;\n";
1311 OS << "typedef __clang_svuint64x3_t svuint64x3_t;\n";
1312 OS << "typedef __clang_svfloat16x3_t svfloat16x3_t;\n";
1313 OS << "typedef __clang_svfloat32x3_t svfloat32x3_t;\n";
1314 OS << "typedef __clang_svfloat64x3_t svfloat64x3_t;\n";
1315 OS << "typedef __clang_svint8x4_t svint8x4_t;\n";
1316 OS << "typedef __clang_svint16x4_t svint16x4_t;\n";
1317 OS << "typedef __clang_svint32x4_t svint32x4_t;\n";
1318 OS << "typedef __clang_svint64x4_t svint64x4_t;\n";
1319 OS << "typedef __clang_svuint8x4_t svuint8x4_t;\n";
1320 OS << "typedef __clang_svuint16x4_t svuint16x4_t;\n";
1321 OS << "typedef __clang_svuint32x4_t svuint32x4_t;\n";
1322 OS << "typedef __clang_svuint64x4_t svuint64x4_t;\n";
1323 OS << "typedef __clang_svfloat16x4_t svfloat16x4_t;\n";
1324 OS << "typedef __clang_svfloat32x4_t svfloat32x4_t;\n";
1325 OS << "typedef __clang_svfloat64x4_t svfloat64x4_t;\n";
1326 OS << "typedef __SVBool_t svbool_t;\n";
1327 OS << "typedef __clang_svboolx2_t svboolx2_t;\n";
1328 OS << "typedef __clang_svboolx4_t svboolx4_t;\n\n";
1329
1330 OS << "typedef __clang_svbfloat16x2_t svbfloat16x2_t;\n";
1331 OS << "typedef __clang_svbfloat16x3_t svbfloat16x3_t;\n";
1332 OS << "typedef __clang_svbfloat16x4_t svbfloat16x4_t;\n";
1333
1334 OS << "typedef __SVCount_t svcount_t;\n\n";
1335
1336 OS << "enum svpattern\n";
1337 OS << "{\n";
1338 OS << " SV_POW2 = 0,\n";
1339 OS << " SV_VL1 = 1,\n";
1340 OS << " SV_VL2 = 2,\n";
1341 OS << " SV_VL3 = 3,\n";
1342 OS << " SV_VL4 = 4,\n";
1343 OS << " SV_VL5 = 5,\n";
1344 OS << " SV_VL6 = 6,\n";
1345 OS << " SV_VL7 = 7,\n";
1346 OS << " SV_VL8 = 8,\n";
1347 OS << " SV_VL16 = 9,\n";
1348 OS << " SV_VL32 = 10,\n";
1349 OS << " SV_VL64 = 11,\n";
1350 OS << " SV_VL128 = 12,\n";
1351 OS << " SV_VL256 = 13,\n";
1352 OS << " SV_MUL4 = 29,\n";
1353 OS << " SV_MUL3 = 30,\n";
1354 OS << " SV_ALL = 31\n";
1355 OS << "};\n\n";
1356
1357 OS << "enum svprfop\n";
1358 OS << "{\n";
1359 OS << " SV_PLDL1KEEP = 0,\n";
1360 OS << " SV_PLDL1STRM = 1,\n";
1361 OS << " SV_PLDL2KEEP = 2,\n";
1362 OS << " SV_PLDL2STRM = 3,\n";
1363 OS << " SV_PLDL3KEEP = 4,\n";
1364 OS << " SV_PLDL3STRM = 5,\n";
1365 OS << " SV_PSTL1KEEP = 8,\n";
1366 OS << " SV_PSTL1STRM = 9,\n";
1367 OS << " SV_PSTL2KEEP = 10,\n";
1368 OS << " SV_PSTL2STRM = 11,\n";
1369 OS << " SV_PSTL3KEEP = 12,\n";
1370 OS << " SV_PSTL3STRM = 13\n";
1371 OS << "};\n\n";
1372
1373 OS << "/* Function attributes */\n";
1374 OS << "#define __ai static __inline__ __attribute__((__always_inline__, "
1375 "__nodebug__))\n\n";
1376 OS << "#define __aio static __inline__ __attribute__((__always_inline__, "
1377 "__nodebug__, __overloadable__))\n\n";
1378
1379 // Add reinterpret functions.
1380 for (auto [N, Suffix] :
1381 std::initializer_list<std::pair<unsigned, const char *>>{
1382 {1, ""}, {2, "_x2"}, {3, "_x3"}, {4, "_x4"}}) {
1383 for (auto ShortForm : {false, true})
1384 for (const ReinterpretTypeInfo &To : Reinterprets) {
1385 SVEType ToV(To.BaseType, N);
1386 for (const ReinterpretTypeInfo &From : Reinterprets) {
1387 SVEType FromV(From.BaseType, N);
1388 if (ShortForm) {
1389 OS << "__aio __attribute__((target(\"sve\"))) " << ToV.str()
1390 << " svreinterpret_" << To.Suffix;
1391 OS << "(" << FromV.str() << " op) __arm_streaming_compatible {\n";
1392 OS << " return __builtin_sve_reinterpret_" << To.Suffix << "_"
1393 << From.Suffix << Suffix << "(op);\n";
1394 OS << "}\n\n";
1395 } else
1396 OS << "#define svreinterpret_" << To.Suffix << "_" << From.Suffix
1397 << Suffix << "(...) __builtin_sve_reinterpret_" << To.Suffix
1398 << "_" << From.Suffix << Suffix << "(__VA_ARGS__)\n";
1399 }
1400 }
1401 }
1402
1403 createCoreHeaderIntrinsics(OS, Emitter&: *this, Kind: ACLEKind::SVE);
1404
1405 OS << "#define svcvtnt_bf16_x svcvtnt_bf16_m\n";
1406 OS << "#define svcvtnt_bf16_f32_x svcvtnt_bf16_f32_m\n";
1407
1408 OS << "#define svcvtnt_f16_x svcvtnt_f16_m\n";
1409 OS << "#define svcvtnt_f16_f32_x svcvtnt_f16_f32_m\n";
1410 OS << "#define svcvtnt_f32_x svcvtnt_f32_m\n";
1411 OS << "#define svcvtnt_f32_f64_x svcvtnt_f32_f64_m\n\n";
1412
1413 OS << "#define svcvtxnt_f32_x svcvtxnt_f32_m\n";
1414 OS << "#define svcvtxnt_f32_f64_x svcvtxnt_f32_f64_m\n\n";
1415
1416 OS << "#ifdef __cplusplus\n";
1417 OS << "} // extern \"C\"\n";
1418 OS << "#endif\n\n";
1419 OS << "#undef __ai\n\n";
1420 OS << "#undef __aio\n\n";
1421 OS << "#endif /* __ARM_SVE_H */\n";
1422}
1423
1424void SVEEmitter::createBuiltins(raw_ostream &OS) {
1425 std::vector<Record *> RV = Records.getAllDerivedDefinitions(ClassName: "Inst");
1426 SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
1427 for (auto *R : RV)
1428 createIntrinsic(R, Out&: Defs);
1429
1430 // The mappings must be sorted based on BuiltinID.
1431 llvm::sort(C&: Defs, Comp: [](const std::unique_ptr<Intrinsic> &A,
1432 const std::unique_ptr<Intrinsic> &B) {
1433 return A->getMangledName() < B->getMangledName();
1434 });
1435
1436 OS << "#ifdef GET_SVE_BUILTINS\n";
1437 for (auto &Def : Defs) {
1438 // Only create BUILTINs for non-overloaded intrinsics, as overloaded
1439 // declarations only live in the header file.
1440 if (Def->getClassKind() != ClassG)
1441 OS << "TARGET_BUILTIN(__builtin_sve_" << Def->getMangledName() << ", \""
1442 << Def->getBuiltinTypeStr() << "\", \"n\", \"" << Def->getGuard()
1443 << "\")\n";
1444 }
1445
1446 // Add reinterpret functions.
1447 for (auto [N, Suffix] :
1448 std::initializer_list<std::pair<unsigned, const char *>>{
1449 {1, ""}, {2, "_x2"}, {3, "_x3"}, {4, "_x4"}}) {
1450 for (const ReinterpretTypeInfo &To : Reinterprets) {
1451 SVEType ToV(To.BaseType, N);
1452 for (const ReinterpretTypeInfo &From : Reinterprets) {
1453 SVEType FromV(From.BaseType, N);
1454 OS << "TARGET_BUILTIN(__builtin_sve_reinterpret_" << To.Suffix << "_"
1455 << From.Suffix << Suffix << +", \"" << ToV.builtin_str()
1456 << FromV.builtin_str() << "\", \"n\", \"sve\")\n";
1457 }
1458 }
1459 }
1460
1461 OS << "#endif\n\n";
1462}
1463
1464void SVEEmitter::createCodeGenMap(raw_ostream &OS) {
1465 std::vector<Record *> RV = Records.getAllDerivedDefinitions(ClassName: "Inst");
1466 SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
1467 for (auto *R : RV)
1468 createIntrinsic(R, Out&: Defs);
1469
1470 // The mappings must be sorted based on BuiltinID.
1471 llvm::sort(C&: Defs, Comp: [](const std::unique_ptr<Intrinsic> &A,
1472 const std::unique_ptr<Intrinsic> &B) {
1473 return A->getMangledName() < B->getMangledName();
1474 });
1475
1476 OS << "#ifdef GET_SVE_LLVM_INTRINSIC_MAP\n";
1477 for (auto &Def : Defs) {
1478 // Builtins only exist for non-overloaded intrinsics, overloaded
1479 // declarations only live in the header file.
1480 if (Def->getClassKind() == ClassG)
1481 continue;
1482
1483 uint64_t Flags = Def->getFlags();
1484 auto FlagString = std::to_string(val: Flags);
1485
1486 std::string LLVMName = Def->getMangledLLVMName();
1487 std::string Builtin = Def->getMangledName();
1488 if (!LLVMName.empty())
1489 OS << "SVEMAP1(" << Builtin << ", " << LLVMName << ", " << FlagString
1490 << "),\n";
1491 else
1492 OS << "SVEMAP2(" << Builtin << ", " << FlagString << "),\n";
1493 }
1494 OS << "#endif\n\n";
1495}
1496
1497void SVEEmitter::createRangeChecks(raw_ostream &OS) {
1498 std::vector<Record *> RV = Records.getAllDerivedDefinitions(ClassName: "Inst");
1499 SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
1500 for (auto *R : RV)
1501 createIntrinsic(R, Out&: Defs);
1502
1503 // The mappings must be sorted based on BuiltinID.
1504 llvm::sort(C&: Defs, Comp: [](const std::unique_ptr<Intrinsic> &A,
1505 const std::unique_ptr<Intrinsic> &B) {
1506 return A->getMangledName() < B->getMangledName();
1507 });
1508
1509
1510 OS << "#ifdef GET_SVE_IMMEDIATE_CHECK\n";
1511
1512 // Ensure these are only emitted once.
1513 std::set<std::string> Emitted;
1514
1515 for (auto &Def : Defs) {
1516 if (Emitted.find(x: Def->getMangledName()) != Emitted.end() ||
1517 Def->getImmChecks().empty())
1518 continue;
1519
1520 OS << "case SVE::BI__builtin_sve_" << Def->getMangledName() << ":\n";
1521 for (auto &Check : Def->getImmChecks())
1522 OS << "ImmChecks.push_back(std::make_tuple(" << Check.getArg() << ", "
1523 << Check.getKind() << ", " << Check.getElementSizeInBits() << "));\n";
1524 OS << " break;\n";
1525
1526 Emitted.insert(x: Def->getMangledName());
1527 }
1528
1529 OS << "#endif\n\n";
1530}
1531
1532/// Create the SVETypeFlags used in CGBuiltins
1533void SVEEmitter::createTypeFlags(raw_ostream &OS) {
1534 OS << "#ifdef LLVM_GET_SVE_TYPEFLAGS\n";
1535 for (auto &KV : FlagTypes)
1536 OS << "const uint64_t " << KV.getKey() << " = " << KV.getValue() << ";\n";
1537 OS << "#endif\n\n";
1538
1539 OS << "#ifdef LLVM_GET_SVE_ELTTYPES\n";
1540 for (auto &KV : EltTypes)
1541 OS << " " << KV.getKey() << " = " << KV.getValue() << ",\n";
1542 OS << "#endif\n\n";
1543
1544 OS << "#ifdef LLVM_GET_SVE_MEMELTTYPES\n";
1545 for (auto &KV : MemEltTypes)
1546 OS << " " << KV.getKey() << " = " << KV.getValue() << ",\n";
1547 OS << "#endif\n\n";
1548
1549 OS << "#ifdef LLVM_GET_SVE_MERGETYPES\n";
1550 for (auto &KV : MergeTypes)
1551 OS << " " << KV.getKey() << " = " << KV.getValue() << ",\n";
1552 OS << "#endif\n\n";
1553
1554 OS << "#ifdef LLVM_GET_SVE_IMMCHECKTYPES\n";
1555 for (auto &KV : ImmCheckTypes)
1556 OS << " " << KV.getKey() << " = " << KV.getValue() << ",\n";
1557 OS << "#endif\n\n";
1558}
1559
1560void SVEEmitter::createSMEHeader(raw_ostream &OS) {
1561 OS << "/*===---- arm_sme.h - ARM SME intrinsics "
1562 "------===\n"
1563 " *\n"
1564 " *\n"
1565 " * Part of the LLVM Project, under the Apache License v2.0 with LLVM "
1566 "Exceptions.\n"
1567 " * See https://llvm.org/LICENSE.txt for license information.\n"
1568 " * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n"
1569 " *\n"
1570 " *===-----------------------------------------------------------------"
1571 "------===\n"
1572 " */\n\n";
1573
1574 OS << "#ifndef __ARM_SME_H\n";
1575 OS << "#define __ARM_SME_H\n\n";
1576
1577 OS << "#if !defined(__LITTLE_ENDIAN__)\n";
1578 OS << "#error \"Big endian is currently not supported for arm_sme.h\"\n";
1579 OS << "#endif\n";
1580
1581 OS << "#include <arm_sve.h>\n\n";
1582 OS << "#include <stddef.h>\n\n";
1583
1584 OS << "/* Function attributes */\n";
1585 OS << "#define __ai static __inline__ __attribute__((__always_inline__, "
1586 "__nodebug__))\n\n";
1587 OS << "#define __aio static __inline__ __attribute__((__always_inline__, "
1588 "__nodebug__, __overloadable__))\n\n";
1589
1590 OS << "#ifdef __cplusplus\n";
1591 OS << "extern \"C\" {\n";
1592 OS << "#endif\n\n";
1593
1594 OS << "void __arm_za_disable(void) __arm_streaming_compatible;\n\n";
1595
1596 OS << "__ai bool __arm_has_sme(void) __arm_streaming_compatible {\n";
1597 OS << " uint64_t x0, x1;\n";
1598 OS << " __builtin_arm_get_sme_state(&x0, &x1);\n";
1599 OS << " return x0 & (1ULL << 63);\n";
1600 OS << "}\n\n";
1601
1602 OS << "__ai bool __arm_in_streaming_mode(void) __arm_streaming_compatible "
1603 "{\n";
1604 OS << " uint64_t x0, x1;\n";
1605 OS << " __builtin_arm_get_sme_state(&x0, &x1);\n";
1606 OS << " return x0 & 1;\n";
1607 OS << "}\n\n";
1608
1609 OS << "void *__arm_sc_memcpy(void *dest, const void *src, size_t n) __arm_streaming_compatible;\n";
1610 OS << "void *__arm_sc_memmove(void *dest, const void *src, size_t n) __arm_streaming_compatible;\n";
1611 OS << "void *__arm_sc_memset(void *s, int c, size_t n) __arm_streaming_compatible;\n";
1612 OS << "void *__arm_sc_memchr(void *s, int c, size_t n) __arm_streaming_compatible;\n\n";
1613
1614 OS << "__ai __attribute__((target(\"sme\"))) void svundef_za(void) "
1615 "__arm_streaming_compatible __arm_out(\"za\") "
1616 "{ }\n\n";
1617
1618 createCoreHeaderIntrinsics(OS, Emitter&: *this, Kind: ACLEKind::SME);
1619
1620 OS << "#ifdef __cplusplus\n";
1621 OS << "} // extern \"C\"\n";
1622 OS << "#endif\n\n";
1623 OS << "#undef __ai\n\n";
1624 OS << "#endif /* __ARM_SME_H */\n";
1625}
1626
1627void SVEEmitter::createSMEBuiltins(raw_ostream &OS) {
1628 std::vector<Record *> RV = Records.getAllDerivedDefinitions(ClassName: "Inst");
1629 SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
1630 for (auto *R : RV) {
1631 createIntrinsic(R, Out&: Defs);
1632 }
1633
1634 // The mappings must be sorted based on BuiltinID.
1635 llvm::sort(C&: Defs, Comp: [](const std::unique_ptr<Intrinsic> &A,
1636 const std::unique_ptr<Intrinsic> &B) {
1637 return A->getMangledName() < B->getMangledName();
1638 });
1639
1640 OS << "#ifdef GET_SME_BUILTINS\n";
1641 for (auto &Def : Defs) {
1642 // Only create BUILTINs for non-overloaded intrinsics, as overloaded
1643 // declarations only live in the header file.
1644 if (Def->getClassKind() != ClassG)
1645 OS << "TARGET_BUILTIN(__builtin_sme_" << Def->getMangledName() << ", \""
1646 << Def->getBuiltinTypeStr() << "\", \"n\", \"" << Def->getGuard()
1647 << "\")\n";
1648 }
1649
1650 OS << "#endif\n\n";
1651}
1652
1653void SVEEmitter::createSMECodeGenMap(raw_ostream &OS) {
1654 std::vector<Record *> RV = Records.getAllDerivedDefinitions(ClassName: "Inst");
1655 SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
1656 for (auto *R : RV) {
1657 createIntrinsic(R, Out&: Defs);
1658 }
1659
1660 // The mappings must be sorted based on BuiltinID.
1661 llvm::sort(C&: Defs, Comp: [](const std::unique_ptr<Intrinsic> &A,
1662 const std::unique_ptr<Intrinsic> &B) {
1663 return A->getMangledName() < B->getMangledName();
1664 });
1665
1666 OS << "#ifdef GET_SME_LLVM_INTRINSIC_MAP\n";
1667 for (auto &Def : Defs) {
1668 // Builtins only exist for non-overloaded intrinsics, overloaded
1669 // declarations only live in the header file.
1670 if (Def->getClassKind() == ClassG)
1671 continue;
1672
1673 uint64_t Flags = Def->getFlags();
1674 auto FlagString = std::to_string(val: Flags);
1675
1676 std::string LLVMName = Def->getLLVMName();
1677 std::string Builtin = Def->getMangledName();
1678 if (!LLVMName.empty())
1679 OS << "SMEMAP1(" << Builtin << ", " << LLVMName << ", " << FlagString
1680 << "),\n";
1681 else
1682 OS << "SMEMAP2(" << Builtin << ", " << FlagString << "),\n";
1683 }
1684 OS << "#endif\n\n";
1685}
1686
1687void SVEEmitter::createSMERangeChecks(raw_ostream &OS) {
1688 std::vector<Record *> RV = Records.getAllDerivedDefinitions(ClassName: "Inst");
1689 SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
1690 for (auto *R : RV) {
1691 createIntrinsic(R, Out&: Defs);
1692 }
1693
1694 // The mappings must be sorted based on BuiltinID.
1695 llvm::sort(C&: Defs, Comp: [](const std::unique_ptr<Intrinsic> &A,
1696 const std::unique_ptr<Intrinsic> &B) {
1697 return A->getMangledName() < B->getMangledName();
1698 });
1699
1700
1701 OS << "#ifdef GET_SME_IMMEDIATE_CHECK\n";
1702
1703 // Ensure these are only emitted once.
1704 std::set<std::string> Emitted;
1705
1706 for (auto &Def : Defs) {
1707 if (Emitted.find(x: Def->getMangledName()) != Emitted.end() ||
1708 Def->getImmChecks().empty())
1709 continue;
1710
1711 OS << "case SME::BI__builtin_sme_" << Def->getMangledName() << ":\n";
1712 for (auto &Check : Def->getImmChecks())
1713 OS << "ImmChecks.push_back(std::make_tuple(" << Check.getArg() << ", "
1714 << Check.getKind() << ", " << Check.getElementSizeInBits() << "));\n";
1715 OS << " break;\n";
1716
1717 Emitted.insert(x: Def->getMangledName());
1718 }
1719
1720 OS << "#endif\n\n";
1721}
1722
1723void SVEEmitter::createBuiltinZAState(raw_ostream &OS) {
1724 std::vector<Record *> RV = Records.getAllDerivedDefinitions(ClassName: "Inst");
1725 SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
1726 for (auto *R : RV)
1727 createIntrinsic(R, Out&: Defs);
1728
1729 std::map<std::string, std::set<std::string>> IntrinsicsPerState;
1730 for (auto &Def : Defs) {
1731 std::string Key;
1732 auto AddToKey = [&Key](const std::string &S) -> void {
1733 Key = Key.empty() ? S : (Key + " | " + S);
1734 };
1735
1736 if (Def->isFlagSet(Flag: getEnumValueForFlag(C: "IsInZA")))
1737 AddToKey("ArmInZA");
1738 else if (Def->isFlagSet(Flag: getEnumValueForFlag(C: "IsOutZA")))
1739 AddToKey("ArmOutZA");
1740 else if (Def->isFlagSet(Flag: getEnumValueForFlag(C: "IsInOutZA")))
1741 AddToKey("ArmInOutZA");
1742
1743 if (Def->isFlagSet(Flag: getEnumValueForFlag(C: "IsInZT0")))
1744 AddToKey("ArmInZT0");
1745 else if (Def->isFlagSet(Flag: getEnumValueForFlag(C: "IsOutZT0")))
1746 AddToKey("ArmOutZT0");
1747 else if (Def->isFlagSet(Flag: getEnumValueForFlag(C: "IsInOutZT0")))
1748 AddToKey("ArmInOutZT0");
1749
1750 if (!Key.empty())
1751 IntrinsicsPerState[Key].insert(x: Def->getMangledName());
1752 }
1753
1754 OS << "#ifdef GET_SME_BUILTIN_GET_STATE\n";
1755 for (auto &KV : IntrinsicsPerState) {
1756 for (StringRef Name : KV.second)
1757 OS << "case SME::BI__builtin_sme_" << Name << ":\n";
1758 OS << " return " << KV.first << ";\n";
1759 }
1760 OS << "#endif\n\n";
1761}
1762
1763void SVEEmitter::createStreamingAttrs(raw_ostream &OS, ACLEKind Kind) {
1764 std::vector<Record *> RV = Records.getAllDerivedDefinitions(ClassName: "Inst");
1765 SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
1766 for (auto *R : RV)
1767 createIntrinsic(R, Out&: Defs);
1768
1769 StringRef ExtensionKind;
1770 switch (Kind) {
1771 case ACLEKind::SME:
1772 ExtensionKind = "SME";
1773 break;
1774 case ACLEKind::SVE:
1775 ExtensionKind = "SVE";
1776 break;
1777 }
1778
1779 OS << "#ifdef GET_" << ExtensionKind << "_STREAMING_ATTRS\n";
1780
1781 llvm::StringMap<std::set<std::string>> StreamingMap;
1782
1783 uint64_t IsStreamingFlag = getEnumValueForFlag(C: "IsStreaming");
1784 uint64_t IsStreamingOrSVE2p1Flag = getEnumValueForFlag(C: "IsStreamingOrSVE2p1");
1785 uint64_t IsStreamingCompatibleFlag =
1786 getEnumValueForFlag(C: "IsStreamingCompatible");
1787 for (auto &Def : Defs) {
1788 if (Def->isFlagSet(Flag: IsStreamingFlag))
1789 StreamingMap["ArmStreaming"].insert(x: Def->getMangledName());
1790 else if (Def->isFlagSet(Flag: IsStreamingOrSVE2p1Flag))
1791 StreamingMap["ArmStreamingOrSVE2p1"].insert(x: Def->getMangledName());
1792 else if (Def->isFlagSet(Flag: IsStreamingCompatibleFlag))
1793 StreamingMap["ArmStreamingCompatible"].insert(x: Def->getMangledName());
1794 else
1795 StreamingMap["ArmNonStreaming"].insert(x: Def->getMangledName());
1796 }
1797
1798 for (auto BuiltinType : StreamingMap.keys()) {
1799 for (auto Name : StreamingMap[BuiltinType]) {
1800 OS << "case " << ExtensionKind << "::BI__builtin_"
1801 << ExtensionKind.lower() << "_";
1802 OS << Name << ":\n";
1803 }
1804 OS << " BuiltinType = " << BuiltinType << ";\n";
1805 OS << " break;\n";
1806 }
1807
1808 OS << "#endif\n\n";
1809}
1810
1811namespace clang {
1812void EmitSveHeader(RecordKeeper &Records, raw_ostream &OS) {
1813 SVEEmitter(Records).createHeader(OS);
1814}
1815
1816void EmitSveBuiltins(RecordKeeper &Records, raw_ostream &OS) {
1817 SVEEmitter(Records).createBuiltins(OS);
1818}
1819
1820void EmitSveBuiltinCG(RecordKeeper &Records, raw_ostream &OS) {
1821 SVEEmitter(Records).createCodeGenMap(OS);
1822}
1823
1824void EmitSveRangeChecks(RecordKeeper &Records, raw_ostream &OS) {
1825 SVEEmitter(Records).createRangeChecks(OS);
1826}
1827
1828void EmitSveTypeFlags(RecordKeeper &Records, raw_ostream &OS) {
1829 SVEEmitter(Records).createTypeFlags(OS);
1830}
1831
1832void EmitSveStreamingAttrs(RecordKeeper &Records, raw_ostream &OS) {
1833 SVEEmitter(Records).createStreamingAttrs(OS, Kind: ACLEKind::SVE);
1834}
1835
1836void EmitSmeHeader(RecordKeeper &Records, raw_ostream &OS) {
1837 SVEEmitter(Records).createSMEHeader(OS);
1838}
1839
1840void EmitSmeBuiltins(RecordKeeper &Records, raw_ostream &OS) {
1841 SVEEmitter(Records).createSMEBuiltins(OS);
1842}
1843
1844void EmitSmeBuiltinCG(RecordKeeper &Records, raw_ostream &OS) {
1845 SVEEmitter(Records).createSMECodeGenMap(OS);
1846}
1847
1848void EmitSmeRangeChecks(RecordKeeper &Records, raw_ostream &OS) {
1849 SVEEmitter(Records).createSMERangeChecks(OS);
1850}
1851
1852void EmitSmeStreamingAttrs(RecordKeeper &Records, raw_ostream &OS) {
1853 SVEEmitter(Records).createStreamingAttrs(OS, Kind: ACLEKind::SME);
1854}
1855
1856void EmitSmeBuiltinZAState(RecordKeeper &Records, raw_ostream &OS) {
1857 SVEEmitter(Records).createBuiltinZAState(OS);
1858}
1859} // End namespace clang
1860

source code of clang/utils/TableGen/SveEmitter.cpp