[Flang] remove whole-archive option for AIX linker (#76039)
[llvm-project.git] / clang / utils / TableGen / SveEmitter.cpp
blob311c6b09dc790135cc774aaf15ac0be784cc5c63
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).
13 // For details, visit:
14 // https://developer.arm.com/architectures/system-architectures/software-standards/acle
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.
22 // See also the documentation in include/clang/Basic/arm_sve.td.
24 //===----------------------------------------------------------------------===//
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>
39 using namespace llvm;
41 enum ClassKind {
42 ClassNone,
43 ClassS, // signed/unsigned, e.g., "_s8", "_u8" suffix
44 ClassG, // Overloaded name without type suffix
47 enum class ACLEKind { SVE, SME };
49 using TypeSpec = std::string;
51 namespace {
53 class ImmCheck {
54 unsigned Arg;
55 unsigned Kind;
56 unsigned ElementSizeInBits;
58 public:
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;
64 unsigned getArg() const { return Arg; }
65 unsigned getKind() const { return Kind; }
66 unsigned getElementSizeInBits() const { return ElementSizeInBits; }
69 class SVEType {
70 bool Float, Signed, Immediate, Void, Constant, Pointer, BFloat;
71 bool DefaultType, IsScalable, Predicate, PredicatePattern, PrefetchOp,
72 Svcount;
73 unsigned Bitwidth, ElementBitwidth, NumVectors;
75 public:
76 SVEType() : SVEType("", 'v') {}
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(CharMod);
89 SVEType(const SVEType &Base, unsigned NumV) : SVEType(Base) {
90 NumVectors = NumV;
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;
110 bool isScalarPredicate() const {
111 return !isFloatingPoint() && Predicate && NumVectors == 0;
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; }
121 unsigned getNumElements() const {
122 assert(ElementBitwidth != ~0U);
123 return Bitwidth / ElementBitwidth;
125 unsigned getSizeInBits() const {
126 return Bitwidth;
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;
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;
137 private:
138 /// Creates the type based on the typespec string in TS.
139 void applyTypespec(StringRef TS);
141 /// Applies a prototype modifier to the type.
142 void applyModifier(char Mod);
145 class SVEEmitter;
147 /// The main grunt class. This represents an instantiation of an intrinsic with
148 /// a particular typespec and prototype.
149 class Intrinsic {
150 /// The unmangled name.
151 std::string Name;
153 /// The name of the corresponding LLVM IR intrinsic.
154 std::string LLVMName;
156 /// Intrinsic prototype.
157 std::string Proto;
159 /// The base type spec for this intrinsic.
160 TypeSpec BaseTypeSpec;
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;
167 /// The architectural #ifdef guard.
168 std::string Guard;
170 // The merge suffix such as _m, _x or _z.
171 std::string MergeSuffix;
173 /// The types of return value [0] and parameters [1..].
174 std::vector<SVEType> Types;
176 /// The "base type", which is VarType('d', BaseTypeSpec).
177 SVEType BaseType;
179 uint64_t Flags;
181 SmallVector<ImmCheck, 2> ImmChecks;
183 public:
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);
189 ~Intrinsic()=default;
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; }
197 StringRef getGuard() const { return Guard; }
198 ClassKind getClassKind() const { return Class; }
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(Proto, '.')) - 1;
207 uint64_t getFlags() const { return Flags; }
208 bool isFlagSet(uint64_t Flag) const { return Flags & Flag;}
210 ArrayRef<ImmCheck> getImmChecks() const { return ImmChecks; }
212 /// Return the type string for a BUILTIN() macro in Builtins.def.
213 std::string getBuiltinTypeStr();
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(ClassS); }
219 /// As above, but mangles the LLVM name instead.
220 std::string getMangledLLVMName() const { return mangleLLVMName(); }
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('[');
227 auto BrClose = Name.find(']');
228 return BrOpen != std::string::npos && BrClose != std::string::npos;
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("ajfrKLR@") != std::string::npos;
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;
246 // Multivector modifier can be skipped
247 if (Proto[I] == '.')
248 I += 2;
250 assert(I != Proto.size() && "Prototype has no splat operand");
251 return Param;
254 /// Emits the intrinsic declaration to the ostream.
255 void emitIntrinsic(raw_ostream &OS, SVEEmitter &Emitter, ACLEKind Kind) const;
257 private:
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;
265 class SVEEmitter {
266 private:
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;
276 static const std::array<ReinterpretTypeInfo, 12> Reinterprets;
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;
285 public:
286 SVEEmitter(RecordKeeper &R) : Records(R) {
287 for (auto *RV : Records.getAllDerivedDefinitions("EltType"))
288 EltTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");
289 for (auto *RV : Records.getAllDerivedDefinitions("MemEltType"))
290 MemEltTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");
291 for (auto *RV : Records.getAllDerivedDefinitions("FlagType"))
292 FlagTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");
293 for (auto *RV : Records.getAllDerivedDefinitions("MergeType"))
294 MergeTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");
295 for (auto *RV : Records.getAllDerivedDefinitions("ImmCheckType"))
296 ImmCheckTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");
299 /// Returns the enum value for the immcheck type
300 unsigned getEnumValueForImmCheck(StringRef C) const {
301 auto It = ImmCheckTypes.find(C);
302 if (It != ImmCheckTypes.end())
303 return It->getValue();
304 llvm_unreachable("Unsupported imm check");
307 /// Returns the enum value for the flag type
308 uint64_t getEnumValueForFlag(StringRef C) const {
309 auto Res = FlagTypes.find(C);
310 if (Res != FlagTypes.end())
311 return Res->getValue();
312 llvm_unreachable("Unsupported flag");
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(MaskName);
318 if (It != FlagTypes.end()) {
319 uint64_t Mask = It->getValue();
320 unsigned Shift = llvm::countr_zero(Mask);
321 assert(Shift < 64 && "Mask value produced an invalid shift value");
322 return (V << Shift) & Mask;
324 llvm_unreachable("Unsupported flag");
327 // Returns the SVETypeFlags for the given element type.
328 uint64_t encodeEltType(StringRef EltName) {
329 auto It = EltTypes.find(EltName);
330 if (It != EltTypes.end())
331 return encodeFlag(It->getValue(), "EltTypeMask");
332 llvm_unreachable("Unsupported EltType");
335 // Returns the SVETypeFlags for the given memory element type.
336 uint64_t encodeMemoryElementType(uint64_t MT) {
337 return encodeFlag(MT, "MemEltTypeMask");
340 // Returns the SVETypeFlags for the given merge type.
341 uint64_t encodeMergeType(uint64_t MT) {
342 return encodeFlag(MT, "MergeTypeMask");
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(SplatIdx + 1, "SplatOperandMask");
351 // Returns the SVETypeFlags value for the given SVEType.
352 uint64_t encodeTypeFlags(const SVEType &T);
354 /// Emit arm_sve.h.
355 void createHeader(raw_ostream &o);
357 // Emits core intrinsics in both arm_sme.h and arm_sve.h
358 void createCoreHeaderIntrinsics(raw_ostream &o, SVEEmitter &Emitter,
359 ACLEKind Kind);
361 /// Emit all the __builtin prototypes and code needed by Sema.
362 void createBuiltins(raw_ostream &o);
364 /// Emit all the information needed to map builtin -> LLVM IR intrinsic.
365 void createCodeGenMap(raw_ostream &o);
367 /// Emit all the range checks for the immediates.
368 void createRangeChecks(raw_ostream &o);
370 /// Create the SVETypeFlags used in CGBuiltins
371 void createTypeFlags(raw_ostream &o);
373 /// Emit arm_sme.h.
374 void createSMEHeader(raw_ostream &o);
376 /// Emit all the SME __builtin prototypes and code needed by Sema.
377 void createSMEBuiltins(raw_ostream &o);
379 /// Emit all the information needed to map builtin -> LLVM IR intrinsic.
380 void createSMECodeGenMap(raw_ostream &o);
382 /// Create a table for a builtin's requirement for PSTATE.SM.
383 void createStreamingAttrs(raw_ostream &o, ACLEKind Kind);
385 /// Emit all the range checks for the immediates.
386 void createSMERangeChecks(raw_ostream &o);
388 /// Create a table for a builtin's requirement for PSTATE.ZA.
389 void createBuiltinZAState(raw_ostream &OS);
391 /// Create intrinsic and add it to \p Out
392 void createIntrinsic(Record *R,
393 SmallVectorImpl<std::unique_ptr<Intrinsic>> &Out);
396 const std::array<SVEEmitter::ReinterpretTypeInfo, 12> SVEEmitter::Reinterprets =
397 {{{SVEType("c", 'd'), "s8"},
398 {SVEType("Uc", 'd'), "u8"},
399 {SVEType("s", 'd'), "s16"},
400 {SVEType("Us", 'd'), "u16"},
401 {SVEType("i", 'd'), "s32"},
402 {SVEType("Ui", 'd'), "u32"},
403 {SVEType("l", 'd'), "s64"},
404 {SVEType("Ul", 'd'), "u64"},
405 {SVEType("h", 'd'), "f16"},
406 {SVEType("b", 'd'), "bf16"},
407 {SVEType("f", 'd'), "f32"},
408 {SVEType("d", 'd'), "f64"}}};
410 } // end anonymous namespace
413 //===----------------------------------------------------------------------===//
414 // Type implementation
415 //===----------------------------------------------------------------------===//
417 std::string SVEType::builtin_str() const {
418 std::string S;
419 if (isVoid())
420 return "v";
422 if (isScalarPredicate())
423 return "b";
425 if (isSvcount())
426 return "Qa";
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!");
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!");
447 else if (isBFloat()) {
448 assert(ElementBitwidth == 16 && "Not a valid BFloat.");
449 S += "y";
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;
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;
470 if (isScalar()) {
471 if (Constant) S += "C";
472 if (Pointer) S += "*";
473 return S;
476 if (isFixedLengthVector())
477 return "V" + utostr(getNumElements() * NumVectors) + S;
478 return "q" + utostr(getNumElements() * NumVectors) + S;
481 std::string SVEType::str() const {
482 if (isPredicatePattern())
483 return "enum svpattern";
485 if (isPrefetchOp())
486 return "enum svprfop";
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";
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";
508 if (!isScalarPredicate() && !isPredicateVector() && !isSvcount())
509 S += utostr(ElementBitwidth);
510 if (isFixedLengthVector())
511 S += "x" + utostr(getNumElements());
512 if (NumVectors > 1)
513 S += "x" + utostr(NumVectors);
514 if (!isScalarPredicate())
515 S += "_t";
518 if (Constant)
519 S += " const";
520 if (Pointer)
521 S += " *";
523 return S;
526 void 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!");
574 assert(ElementBitwidth != ~0U && "Bad element bitwidth!");
577 void 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!");
915 /// Returns the modifier and number of vectors for the given operand \p Op.
916 std::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;
930 if (P == Op)
931 return {Mod, NumVectors};
933 Proto = Proto.drop_front(CharsToSkip);
935 llvm_unreachable("Unexpected Op");
938 //===----------------------------------------------------------------------===//
939 // Intrinsic implementation
940 //===----------------------------------------------------------------------===//
942 Intrinsic::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(Mod, NumVectors) = getProtoModifier(Proto, I);
956 SVEType T(BaseTypeSpec, Mod, NumVectors);
957 Types.push_back(T);
959 // Add range checks for immediates
960 if (I > 0) {
961 if (T.isPredicatePattern())
962 ImmChecks.emplace_back(
963 I - 1, Emitter.getEnumValueForImmCheck("ImmCheck0_31"));
964 else if (T.isPrefetchOp())
965 ImmChecks.emplace_back(
966 I - 1, Emitter.getEnumValueForImmCheck("ImmCheck0_13"));
970 // Set flags based on properties
971 this->Flags |= Emitter.encodeTypeFlags(BaseType);
972 this->Flags |= Emitter.encodeMemoryElementType(MemoryElementTy);
973 this->Flags |= Emitter.encodeMergeType(MergeTy);
974 if (hasSplat())
975 this->Flags |= Emitter.encodeSplatOperand(getSplatIdx());
978 std::string Intrinsic::getBuiltinTypeStr() {
979 std::string S = getReturnType().builtin_str();
980 for (unsigned I = 0; I < getNumParams(); ++I)
981 S += getParamType(I).builtin_str();
983 return S;
986 std::string Intrinsic::replaceTemplatedArgs(std::string Name, TypeSpec TS,
987 std::string Proto) const {
988 std::string Ret = Name;
989 while (Ret.find('{') != std::string::npos) {
990 size_t Pos = Ret.find('{');
991 size_t End = Ret.find('}');
992 unsigned NumChars = End - Pos + 1;
993 assert(NumChars == 3 && "Unexpected template argument");
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;
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, NumChars, TypeCode + utostr(T.getElementSizeInBits()));
1026 return Ret;
1029 std::string Intrinsic::mangleLLVMName() const {
1030 std::string S = getLLVMName();
1032 // Replace all {d} like expressions with e.g. 'u32'
1033 return replaceTemplatedArgs(S, getBaseTypeSpec(), getProto());
1036 std::string Intrinsic::mangleName(ClassKind LocalCK) const {
1037 std::string S = getName();
1039 if (LocalCK == ClassG) {
1040 // Remove the square brackets and everything in between.
1041 while (S.find('[') != std::string::npos) {
1042 auto Start = S.find('[');
1043 auto End = S.find(']');
1044 S.erase(Start, (End-Start)+1);
1046 } else {
1047 // Remove the square brackets.
1048 while (S.find('[') != std::string::npos) {
1049 auto BrPos = S.find('[');
1050 if (BrPos != std::string::npos)
1051 S.erase(BrPos, 1);
1052 BrPos = S.find(']');
1053 if (BrPos != std::string::npos)
1054 S.erase(BrPos, 1);
1058 // Replace all {d} like expressions with e.g. 'u32'
1059 return replaceTemplatedArgs(S, getBaseTypeSpec(), getProto()) +
1060 getMergeSuffix();
1063 void Intrinsic::emitIntrinsic(raw_ostream &OS, SVEEmitter &Emitter,
1064 ACLEKind Kind) const {
1065 bool IsOverloaded = getClassKind() == ClassG && getProto().size() > 1;
1067 std::string FullName = mangleName(ClassS);
1068 std::string ProtoName = mangleName(getClassKind());
1069 std::string SMEAttrs = "";
1071 if (Flags & Emitter.getEnumValueForFlag("IsStreaming"))
1072 SMEAttrs += ", arm_streaming";
1073 if (Flags & Emitter.getEnumValueForFlag("IsStreamingCompatible"))
1074 SMEAttrs += ", arm_streaming_compatible";
1075 if (Flags & Emitter.getEnumValueForFlag("IsSharedZA"))
1076 SMEAttrs += ", arm_shared_za";
1077 if (Flags & Emitter.getEnumValueForFlag("IsPreservesZA"))
1078 SMEAttrs += ", arm_preserves_za";
1080 OS << (IsOverloaded ? "__aio " : "__ai ")
1081 << "__attribute__((__clang_arm_builtin_alias(";
1083 switch (Kind) {
1084 case ACLEKind::SME:
1085 OS << "__builtin_sme_" << FullName << ")";
1086 break;
1087 case ACLEKind::SVE:
1088 OS << "__builtin_sve_" << FullName << ")";
1089 break;
1092 if (!SMEAttrs.empty())
1093 OS << SMEAttrs;
1094 OS << "))\n";
1096 OS << getTypes()[0].str() << " " << ProtoName << "(";
1097 for (unsigned I = 0; I < getTypes().size() - 1; ++I) {
1098 if (I != 0)
1099 OS << ", ";
1100 OS << getTypes()[I + 1].str();
1102 OS << ");\n";
1105 //===----------------------------------------------------------------------===//
1106 // SVEEmitter implementation
1107 //===----------------------------------------------------------------------===//
1108 uint64_t SVEEmitter::encodeTypeFlags(const SVEType &T) {
1109 if (T.isFloat()) {
1110 switch (T.getElementSizeInBits()) {
1111 case 16:
1112 return encodeEltType("EltTyFloat16");
1113 case 32:
1114 return encodeEltType("EltTyFloat32");
1115 case 64:
1116 return encodeEltType("EltTyFloat64");
1117 default:
1118 llvm_unreachable("Unhandled float element bitwidth!");
1122 if (T.isBFloat()) {
1123 assert(T.getElementSizeInBits() == 16 && "Not a valid BFloat.");
1124 return encodeEltType("EltTyBFloat16");
1127 if (T.isPredicateVector() || T.isSvcount()) {
1128 switch (T.getElementSizeInBits()) {
1129 case 8:
1130 return encodeEltType("EltTyBool8");
1131 case 16:
1132 return encodeEltType("EltTyBool16");
1133 case 32:
1134 return encodeEltType("EltTyBool32");
1135 case 64:
1136 return encodeEltType("EltTyBool64");
1137 default:
1138 llvm_unreachable("Unhandled predicate element bitwidth!");
1142 switch (T.getElementSizeInBits()) {
1143 case 8:
1144 return encodeEltType("EltTyInt8");
1145 case 16:
1146 return encodeEltType("EltTyInt16");
1147 case 32:
1148 return encodeEltType("EltTyInt32");
1149 case 64:
1150 return encodeEltType("EltTyInt64");
1151 case 128:
1152 return encodeEltType("EltTyInt128");
1153 default:
1154 llvm_unreachable("Unhandled integer element bitwidth!");
1158 void SVEEmitter::createIntrinsic(
1159 Record *R, SmallVectorImpl<std::unique_ptr<Intrinsic>> &Out) {
1160 StringRef Name = R->getValueAsString("Name");
1161 StringRef Proto = R->getValueAsString("Prototype");
1162 StringRef Types = R->getValueAsString("Types");
1163 StringRef Guard = R->getValueAsString("TargetGuard");
1164 StringRef LLVMName = R->getValueAsString("LLVMIntrinsic");
1165 uint64_t Merge = R->getValueAsInt("Merge");
1166 StringRef MergeSuffix = R->getValueAsString("MergeSuffix");
1167 uint64_t MemEltType = R->getValueAsInt("MemEltType");
1168 std::vector<Record*> FlagsList = R->getValueAsListOfDefs("Flags");
1169 std::vector<Record*> ImmCheckList = R->getValueAsListOfDefs("ImmChecks");
1171 int64_t Flags = 0;
1172 for (auto FlagRec : FlagsList)
1173 Flags |= FlagRec->getValueAsInt("Value");
1175 // Create a dummy TypeSpec for non-overloaded builtins.
1176 if (Types.empty()) {
1177 assert((Flags & getEnumValueForFlag("IsOverloadNone")) &&
1178 "Expect TypeSpec for overloaded builtin!");
1179 Types = "i";
1182 // Extract type specs from string
1183 SmallVector<TypeSpec, 8> TypeSpecs;
1184 TypeSpec Acc;
1185 for (char I : Types) {
1186 Acc.push_back(I);
1187 if (islower(I)) {
1188 TypeSpecs.push_back(TypeSpec(Acc));
1189 Acc.clear();
1193 // Remove duplicate type specs.
1194 llvm::sort(TypeSpecs);
1195 TypeSpecs.erase(std::unique(TypeSpecs.begin(), TypeSpecs.end()),
1196 TypeSpecs.end());
1198 // Create an Intrinsic for each type spec.
1199 for (auto TS : TypeSpecs) {
1200 // Collate a list of range/option checks for the immediates.
1201 SmallVector<ImmCheck, 2> ImmChecks;
1202 for (auto *R : ImmCheckList) {
1203 int64_t Arg = R->getValueAsInt("Arg");
1204 int64_t EltSizeArg = R->getValueAsInt("EltSizeArg");
1205 int64_t Kind = R->getValueAsDef("Kind")->getValueAsInt("Value");
1206 assert(Arg >= 0 && Kind >= 0 && "Arg and Kind must be nonnegative");
1208 unsigned ElementSizeInBits = 0;
1209 char Mod;
1210 unsigned NumVectors;
1211 std::tie(Mod, NumVectors) = getProtoModifier(Proto, EltSizeArg + 1);
1212 if (EltSizeArg >= 0)
1213 ElementSizeInBits = SVEType(TS, Mod, NumVectors).getElementSizeInBits();
1214 ImmChecks.push_back(ImmCheck(Arg, Kind, ElementSizeInBits));
1217 Out.push_back(std::make_unique<Intrinsic>(
1218 Name, Proto, Merge, MergeSuffix, MemEltType, LLVMName, Flags, ImmChecks,
1219 TS, ClassS, *this, Guard));
1221 // Also generate the short-form (e.g. svadd_m) for the given type-spec.
1222 if (Intrinsic::isOverloadedIntrinsic(Name))
1223 Out.push_back(std::make_unique<Intrinsic>(
1224 Name, Proto, Merge, MergeSuffix, MemEltType, LLVMName, Flags,
1225 ImmChecks, TS, ClassG, *this, Guard));
1229 void SVEEmitter::createCoreHeaderIntrinsics(raw_ostream &OS,
1230 SVEEmitter &Emitter,
1231 ACLEKind Kind) {
1232 SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
1233 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
1234 for (auto *R : RV)
1235 createIntrinsic(R, Defs);
1237 // Sort intrinsics in header file by following order/priority:
1238 // - Architectural guard (i.e. does it require SVE2 or SVE2_AES)
1239 // - Class (is intrinsic overloaded or not)
1240 // - Intrinsic name
1241 std::stable_sort(Defs.begin(), Defs.end(),
1242 [](const std::unique_ptr<Intrinsic> &A,
1243 const std::unique_ptr<Intrinsic> &B) {
1244 auto ToTuple = [](const std::unique_ptr<Intrinsic> &I) {
1245 return std::make_tuple(I->getGuard(),
1246 (unsigned)I->getClassKind(),
1247 I->getName());
1249 return ToTuple(A) < ToTuple(B);
1252 // Actually emit the intrinsic declarations.
1253 for (auto &I : Defs)
1254 I->emitIntrinsic(OS, Emitter, Kind);
1257 void SVEEmitter::createHeader(raw_ostream &OS) {
1258 OS << "/*===---- arm_sve.h - ARM SVE intrinsics "
1259 "-----------------------------------===\n"
1260 " *\n"
1261 " *\n"
1262 " * Part of the LLVM Project, under the Apache License v2.0 with LLVM "
1263 "Exceptions.\n"
1264 " * See https://llvm.org/LICENSE.txt for license information.\n"
1265 " * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n"
1266 " *\n"
1267 " *===-----------------------------------------------------------------"
1268 "------===\n"
1269 " */\n\n";
1271 OS << "#ifndef __ARM_SVE_H\n";
1272 OS << "#define __ARM_SVE_H\n\n";
1274 OS << "#if !defined(__LITTLE_ENDIAN__)\n";
1275 OS << "#error \"Big endian is currently not supported for arm_sve.h\"\n";
1276 OS << "#endif\n";
1278 OS << "#include <stdint.h>\n\n";
1279 OS << "#ifdef __cplusplus\n";
1280 OS << "extern \"C\" {\n";
1281 OS << "#else\n";
1282 OS << "#include <stdbool.h>\n";
1283 OS << "#endif\n\n";
1285 OS << "typedef __fp16 float16_t;\n";
1286 OS << "typedef float float32_t;\n";
1287 OS << "typedef double float64_t;\n";
1289 OS << "typedef __SVInt8_t svint8_t;\n";
1290 OS << "typedef __SVInt16_t svint16_t;\n";
1291 OS << "typedef __SVInt32_t svint32_t;\n";
1292 OS << "typedef __SVInt64_t svint64_t;\n";
1293 OS << "typedef __SVUint8_t svuint8_t;\n";
1294 OS << "typedef __SVUint16_t svuint16_t;\n";
1295 OS << "typedef __SVUint32_t svuint32_t;\n";
1296 OS << "typedef __SVUint64_t svuint64_t;\n";
1297 OS << "typedef __SVFloat16_t svfloat16_t;\n\n";
1299 OS << "typedef __SVBfloat16_t svbfloat16_t;\n";
1301 OS << "#include <arm_bf16.h>\n";
1302 OS << "#include <arm_vector_types.h>\n";
1304 OS << "typedef __SVFloat32_t svfloat32_t;\n";
1305 OS << "typedef __SVFloat64_t svfloat64_t;\n";
1306 OS << "typedef __clang_svint8x2_t svint8x2_t;\n";
1307 OS << "typedef __clang_svint16x2_t svint16x2_t;\n";
1308 OS << "typedef __clang_svint32x2_t svint32x2_t;\n";
1309 OS << "typedef __clang_svint64x2_t svint64x2_t;\n";
1310 OS << "typedef __clang_svuint8x2_t svuint8x2_t;\n";
1311 OS << "typedef __clang_svuint16x2_t svuint16x2_t;\n";
1312 OS << "typedef __clang_svuint32x2_t svuint32x2_t;\n";
1313 OS << "typedef __clang_svuint64x2_t svuint64x2_t;\n";
1314 OS << "typedef __clang_svfloat16x2_t svfloat16x2_t;\n";
1315 OS << "typedef __clang_svfloat32x2_t svfloat32x2_t;\n";
1316 OS << "typedef __clang_svfloat64x2_t svfloat64x2_t;\n";
1317 OS << "typedef __clang_svint8x3_t svint8x3_t;\n";
1318 OS << "typedef __clang_svint16x3_t svint16x3_t;\n";
1319 OS << "typedef __clang_svint32x3_t svint32x3_t;\n";
1320 OS << "typedef __clang_svint64x3_t svint64x3_t;\n";
1321 OS << "typedef __clang_svuint8x3_t svuint8x3_t;\n";
1322 OS << "typedef __clang_svuint16x3_t svuint16x3_t;\n";
1323 OS << "typedef __clang_svuint32x3_t svuint32x3_t;\n";
1324 OS << "typedef __clang_svuint64x3_t svuint64x3_t;\n";
1325 OS << "typedef __clang_svfloat16x3_t svfloat16x3_t;\n";
1326 OS << "typedef __clang_svfloat32x3_t svfloat32x3_t;\n";
1327 OS << "typedef __clang_svfloat64x3_t svfloat64x3_t;\n";
1328 OS << "typedef __clang_svint8x4_t svint8x4_t;\n";
1329 OS << "typedef __clang_svint16x4_t svint16x4_t;\n";
1330 OS << "typedef __clang_svint32x4_t svint32x4_t;\n";
1331 OS << "typedef __clang_svint64x4_t svint64x4_t;\n";
1332 OS << "typedef __clang_svuint8x4_t svuint8x4_t;\n";
1333 OS << "typedef __clang_svuint16x4_t svuint16x4_t;\n";
1334 OS << "typedef __clang_svuint32x4_t svuint32x4_t;\n";
1335 OS << "typedef __clang_svuint64x4_t svuint64x4_t;\n";
1336 OS << "typedef __clang_svfloat16x4_t svfloat16x4_t;\n";
1337 OS << "typedef __clang_svfloat32x4_t svfloat32x4_t;\n";
1338 OS << "typedef __clang_svfloat64x4_t svfloat64x4_t;\n";
1339 OS << "typedef __SVBool_t svbool_t;\n";
1340 OS << "typedef __clang_svboolx2_t svboolx2_t;\n";
1341 OS << "typedef __clang_svboolx4_t svboolx4_t;\n\n";
1343 OS << "typedef __clang_svbfloat16x2_t svbfloat16x2_t;\n";
1344 OS << "typedef __clang_svbfloat16x3_t svbfloat16x3_t;\n";
1345 OS << "typedef __clang_svbfloat16x4_t svbfloat16x4_t;\n";
1347 OS << "typedef __SVCount_t svcount_t;\n\n";
1349 OS << "enum svpattern\n";
1350 OS << "{\n";
1351 OS << " SV_POW2 = 0,\n";
1352 OS << " SV_VL1 = 1,\n";
1353 OS << " SV_VL2 = 2,\n";
1354 OS << " SV_VL3 = 3,\n";
1355 OS << " SV_VL4 = 4,\n";
1356 OS << " SV_VL5 = 5,\n";
1357 OS << " SV_VL6 = 6,\n";
1358 OS << " SV_VL7 = 7,\n";
1359 OS << " SV_VL8 = 8,\n";
1360 OS << " SV_VL16 = 9,\n";
1361 OS << " SV_VL32 = 10,\n";
1362 OS << " SV_VL64 = 11,\n";
1363 OS << " SV_VL128 = 12,\n";
1364 OS << " SV_VL256 = 13,\n";
1365 OS << " SV_MUL4 = 29,\n";
1366 OS << " SV_MUL3 = 30,\n";
1367 OS << " SV_ALL = 31\n";
1368 OS << "};\n\n";
1370 OS << "enum svprfop\n";
1371 OS << "{\n";
1372 OS << " SV_PLDL1KEEP = 0,\n";
1373 OS << " SV_PLDL1STRM = 1,\n";
1374 OS << " SV_PLDL2KEEP = 2,\n";
1375 OS << " SV_PLDL2STRM = 3,\n";
1376 OS << " SV_PLDL3KEEP = 4,\n";
1377 OS << " SV_PLDL3STRM = 5,\n";
1378 OS << " SV_PSTL1KEEP = 8,\n";
1379 OS << " SV_PSTL1STRM = 9,\n";
1380 OS << " SV_PSTL2KEEP = 10,\n";
1381 OS << " SV_PSTL2STRM = 11,\n";
1382 OS << " SV_PSTL3KEEP = 12,\n";
1383 OS << " SV_PSTL3STRM = 13\n";
1384 OS << "};\n\n";
1386 OS << "/* Function attributes */\n";
1387 OS << "#define __ai static __inline__ __attribute__((__always_inline__, "
1388 "__nodebug__))\n\n";
1389 OS << "#define __aio static __inline__ __attribute__((__always_inline__, "
1390 "__nodebug__, __overloadable__))\n\n";
1392 // Add reinterpret functions.
1393 for (auto [N, Suffix] :
1394 std::initializer_list<std::pair<unsigned, const char *>>{
1395 {1, ""}, {2, "_x2"}, {3, "_x3"}, {4, "_x4"}}) {
1396 for (auto ShortForm : {false, true})
1397 for (const ReinterpretTypeInfo &To : Reinterprets) {
1398 SVEType ToV(To.BaseType, N);
1399 for (const ReinterpretTypeInfo &From : Reinterprets) {
1400 SVEType FromV(From.BaseType, N);
1401 if (ShortForm) {
1402 OS << "__aio __attribute__((target(\"sve\"))) " << ToV.str()
1403 << " svreinterpret_" << To.Suffix;
1404 OS << "(" << FromV.str() << " op) __arm_streaming_compatible {\n";
1405 OS << " return __builtin_sve_reinterpret_" << To.Suffix << "_"
1406 << From.Suffix << Suffix << "(op);\n";
1407 OS << "}\n\n";
1408 } else
1409 OS << "#define svreinterpret_" << To.Suffix << "_" << From.Suffix
1410 << Suffix << "(...) __builtin_sve_reinterpret_" << To.Suffix
1411 << "_" << From.Suffix << Suffix << "(__VA_ARGS__)\n";
1416 createCoreHeaderIntrinsics(OS, *this, ACLEKind::SVE);
1418 OS << "#define svcvtnt_bf16_x svcvtnt_bf16_m\n";
1419 OS << "#define svcvtnt_bf16_f32_x svcvtnt_bf16_f32_m\n";
1421 OS << "#define svcvtnt_f16_x svcvtnt_f16_m\n";
1422 OS << "#define svcvtnt_f16_f32_x svcvtnt_f16_f32_m\n";
1423 OS << "#define svcvtnt_f32_x svcvtnt_f32_m\n";
1424 OS << "#define svcvtnt_f32_f64_x svcvtnt_f32_f64_m\n\n";
1426 OS << "#define svcvtxnt_f32_x svcvtxnt_f32_m\n";
1427 OS << "#define svcvtxnt_f32_f64_x svcvtxnt_f32_f64_m\n\n";
1429 OS << "#ifdef __cplusplus\n";
1430 OS << "} // extern \"C\"\n";
1431 OS << "#endif\n\n";
1432 OS << "#undef __ai\n\n";
1433 OS << "#undef __aio\n\n";
1434 OS << "#endif /* __ARM_SVE_H */\n";
1437 void SVEEmitter::createBuiltins(raw_ostream &OS) {
1438 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
1439 SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
1440 for (auto *R : RV)
1441 createIntrinsic(R, Defs);
1443 // The mappings must be sorted based on BuiltinID.
1444 llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A,
1445 const std::unique_ptr<Intrinsic> &B) {
1446 return A->getMangledName() < B->getMangledName();
1449 OS << "#ifdef GET_SVE_BUILTINS\n";
1450 for (auto &Def : Defs) {
1451 // Only create BUILTINs for non-overloaded intrinsics, as overloaded
1452 // declarations only live in the header file.
1453 if (Def->getClassKind() != ClassG)
1454 OS << "TARGET_BUILTIN(__builtin_sve_" << Def->getMangledName() << ", \""
1455 << Def->getBuiltinTypeStr() << "\", \"n\", \"" << Def->getGuard()
1456 << "\")\n";
1459 // Add reinterpret functions.
1460 for (auto [N, Suffix] :
1461 std::initializer_list<std::pair<unsigned, const char *>>{
1462 {1, ""}, {2, "_x2"}, {3, "_x3"}, {4, "_x4"}}) {
1463 for (const ReinterpretTypeInfo &To : Reinterprets) {
1464 SVEType ToV(To.BaseType, N);
1465 for (const ReinterpretTypeInfo &From : Reinterprets) {
1466 SVEType FromV(From.BaseType, N);
1467 OS << "TARGET_BUILTIN(__builtin_sve_reinterpret_" << To.Suffix << "_"
1468 << From.Suffix << Suffix << +", \"" << ToV.builtin_str()
1469 << FromV.builtin_str() << "\", \"n\", \"sve\")\n";
1474 OS << "#endif\n\n";
1477 void SVEEmitter::createCodeGenMap(raw_ostream &OS) {
1478 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
1479 SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
1480 for (auto *R : RV)
1481 createIntrinsic(R, Defs);
1483 // The mappings must be sorted based on BuiltinID.
1484 llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A,
1485 const std::unique_ptr<Intrinsic> &B) {
1486 return A->getMangledName() < B->getMangledName();
1489 OS << "#ifdef GET_SVE_LLVM_INTRINSIC_MAP\n";
1490 for (auto &Def : Defs) {
1491 // Builtins only exist for non-overloaded intrinsics, overloaded
1492 // declarations only live in the header file.
1493 if (Def->getClassKind() == ClassG)
1494 continue;
1496 uint64_t Flags = Def->getFlags();
1497 auto FlagString = std::to_string(Flags);
1499 std::string LLVMName = Def->getMangledLLVMName();
1500 std::string Builtin = Def->getMangledName();
1501 if (!LLVMName.empty())
1502 OS << "SVEMAP1(" << Builtin << ", " << LLVMName << ", " << FlagString
1503 << "),\n";
1504 else
1505 OS << "SVEMAP2(" << Builtin << ", " << FlagString << "),\n";
1507 OS << "#endif\n\n";
1510 void SVEEmitter::createRangeChecks(raw_ostream &OS) {
1511 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
1512 SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
1513 for (auto *R : RV)
1514 createIntrinsic(R, Defs);
1516 // The mappings must be sorted based on BuiltinID.
1517 llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A,
1518 const std::unique_ptr<Intrinsic> &B) {
1519 return A->getMangledName() < B->getMangledName();
1523 OS << "#ifdef GET_SVE_IMMEDIATE_CHECK\n";
1525 // Ensure these are only emitted once.
1526 std::set<std::string> Emitted;
1528 for (auto &Def : Defs) {
1529 if (Emitted.find(Def->getMangledName()) != Emitted.end() ||
1530 Def->getImmChecks().empty())
1531 continue;
1533 OS << "case SVE::BI__builtin_sve_" << Def->getMangledName() << ":\n";
1534 for (auto &Check : Def->getImmChecks())
1535 OS << "ImmChecks.push_back(std::make_tuple(" << Check.getArg() << ", "
1536 << Check.getKind() << ", " << Check.getElementSizeInBits() << "));\n";
1537 OS << " break;\n";
1539 Emitted.insert(Def->getMangledName());
1542 OS << "#endif\n\n";
1545 /// Create the SVETypeFlags used in CGBuiltins
1546 void SVEEmitter::createTypeFlags(raw_ostream &OS) {
1547 OS << "#ifdef LLVM_GET_SVE_TYPEFLAGS\n";
1548 for (auto &KV : FlagTypes)
1549 OS << "const uint64_t " << KV.getKey() << " = " << KV.getValue() << ";\n";
1550 OS << "#endif\n\n";
1552 OS << "#ifdef LLVM_GET_SVE_ELTTYPES\n";
1553 for (auto &KV : EltTypes)
1554 OS << " " << KV.getKey() << " = " << KV.getValue() << ",\n";
1555 OS << "#endif\n\n";
1557 OS << "#ifdef LLVM_GET_SVE_MEMELTTYPES\n";
1558 for (auto &KV : MemEltTypes)
1559 OS << " " << KV.getKey() << " = " << KV.getValue() << ",\n";
1560 OS << "#endif\n\n";
1562 OS << "#ifdef LLVM_GET_SVE_MERGETYPES\n";
1563 for (auto &KV : MergeTypes)
1564 OS << " " << KV.getKey() << " = " << KV.getValue() << ",\n";
1565 OS << "#endif\n\n";
1567 OS << "#ifdef LLVM_GET_SVE_IMMCHECKTYPES\n";
1568 for (auto &KV : ImmCheckTypes)
1569 OS << " " << KV.getKey() << " = " << KV.getValue() << ",\n";
1570 OS << "#endif\n\n";
1573 void SVEEmitter::createSMEHeader(raw_ostream &OS) {
1574 OS << "/*===---- arm_sme_draft_spec_subject_to_change.h - ARM SME intrinsics "
1575 "------===\n"
1576 " *\n"
1577 " *\n"
1578 " * Part of the LLVM Project, under the Apache License v2.0 with LLVM "
1579 "Exceptions.\n"
1580 " * See https://llvm.org/LICENSE.txt for license information.\n"
1581 " * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n"
1582 " *\n"
1583 " *===-----------------------------------------------------------------"
1584 "------===\n"
1585 " */\n\n";
1587 OS << "#ifndef __ARM_SME_H\n";
1588 OS << "#define __ARM_SME_H\n\n";
1590 OS << "#if !defined(__LITTLE_ENDIAN__)\n";
1591 OS << "#error \"Big endian is currently not supported for arm_sme_draft_spec_subject_to_change.h\"\n";
1592 OS << "#endif\n";
1594 OS << "#include <arm_sve.h>\n\n";
1596 OS << "/* Function attributes */\n";
1597 OS << "#define __ai static __inline__ __attribute__((__always_inline__, "
1598 "__nodebug__))\n\n";
1599 OS << "#define __aio static __inline__ __attribute__((__always_inline__, "
1600 "__nodebug__, __overloadable__))\n\n";
1602 OS << "#ifdef __cplusplus\n";
1603 OS << "extern \"C\" {\n";
1604 OS << "#endif\n\n";
1606 createCoreHeaderIntrinsics(OS, *this, ACLEKind::SME);
1608 OS << "#ifdef __cplusplus\n";
1609 OS << "} // extern \"C\"\n";
1610 OS << "#endif\n\n";
1611 OS << "#undef __ai\n\n";
1612 OS << "#endif /* __ARM_SME_H */\n";
1615 void SVEEmitter::createSMEBuiltins(raw_ostream &OS) {
1616 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
1617 SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
1618 for (auto *R : RV) {
1619 createIntrinsic(R, Defs);
1622 // The mappings must be sorted based on BuiltinID.
1623 llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A,
1624 const std::unique_ptr<Intrinsic> &B) {
1625 return A->getMangledName() < B->getMangledName();
1628 OS << "#ifdef GET_SME_BUILTINS\n";
1629 for (auto &Def : Defs) {
1630 // Only create BUILTINs for non-overloaded intrinsics, as overloaded
1631 // declarations only live in the header file.
1632 if (Def->getClassKind() != ClassG)
1633 OS << "TARGET_BUILTIN(__builtin_sme_" << Def->getMangledName() << ", \""
1634 << Def->getBuiltinTypeStr() << "\", \"n\", \"" << Def->getGuard()
1635 << "\")\n";
1638 OS << "#endif\n\n";
1641 void SVEEmitter::createSMECodeGenMap(raw_ostream &OS) {
1642 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
1643 SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
1644 for (auto *R : RV) {
1645 createIntrinsic(R, Defs);
1648 // The mappings must be sorted based on BuiltinID.
1649 llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A,
1650 const std::unique_ptr<Intrinsic> &B) {
1651 return A->getMangledName() < B->getMangledName();
1654 OS << "#ifdef GET_SME_LLVM_INTRINSIC_MAP\n";
1655 for (auto &Def : Defs) {
1656 // Builtins only exist for non-overloaded intrinsics, overloaded
1657 // declarations only live in the header file.
1658 if (Def->getClassKind() == ClassG)
1659 continue;
1661 uint64_t Flags = Def->getFlags();
1662 auto FlagString = std::to_string(Flags);
1664 std::string LLVMName = Def->getLLVMName();
1665 std::string Builtin = Def->getMangledName();
1666 if (!LLVMName.empty())
1667 OS << "SMEMAP1(" << Builtin << ", " << LLVMName << ", " << FlagString
1668 << "),\n";
1669 else
1670 OS << "SMEMAP2(" << Builtin << ", " << FlagString << "),\n";
1672 OS << "#endif\n\n";
1675 void SVEEmitter::createSMERangeChecks(raw_ostream &OS) {
1676 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
1677 SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
1678 for (auto *R : RV) {
1679 createIntrinsic(R, Defs);
1682 // The mappings must be sorted based on BuiltinID.
1683 llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A,
1684 const std::unique_ptr<Intrinsic> &B) {
1685 return A->getMangledName() < B->getMangledName();
1689 OS << "#ifdef GET_SME_IMMEDIATE_CHECK\n";
1691 // Ensure these are only emitted once.
1692 std::set<std::string> Emitted;
1694 for (auto &Def : Defs) {
1695 if (Emitted.find(Def->getMangledName()) != Emitted.end() ||
1696 Def->getImmChecks().empty())
1697 continue;
1699 OS << "case SME::BI__builtin_sme_" << Def->getMangledName() << ":\n";
1700 for (auto &Check : Def->getImmChecks())
1701 OS << "ImmChecks.push_back(std::make_tuple(" << Check.getArg() << ", "
1702 << Check.getKind() << ", " << Check.getElementSizeInBits() << "));\n";
1703 OS << " break;\n";
1705 Emitted.insert(Def->getMangledName());
1708 OS << "#endif\n\n";
1711 void SVEEmitter::createBuiltinZAState(raw_ostream &OS) {
1712 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
1713 SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
1714 for (auto *R : RV)
1715 createIntrinsic(R, Defs);
1717 std::map<bool, std::set<std::string>> DefsZAState;
1719 uint64_t IsSharedZAFlag = getEnumValueForFlag("IsSharedZA");
1720 for (auto &Def : Defs) {
1721 bool HasZAState = Def->isFlagSet(IsSharedZAFlag);
1722 DefsZAState[HasZAState].insert(Def->getMangledName());
1725 OS << "#ifdef GET_SME_BUILTIN_HAS_ZA_STATE\n";
1727 for (auto HasZA : {true, false}) {
1728 auto Names = DefsZAState[HasZA];
1729 for (auto Name : Names)
1730 OS << "case SME::BI__builtin_sme_" << Name << ":\n";
1731 OS << " return " << (HasZA ? "true" : "false") << ";\n";
1733 OS << "#endif\n\n";
1736 void SVEEmitter::createStreamingAttrs(raw_ostream &OS, ACLEKind Kind) {
1737 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
1738 SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
1739 for (auto *R : RV)
1740 createIntrinsic(R, Defs);
1742 StringRef ExtensionKind;
1743 switch (Kind) {
1744 case ACLEKind::SME:
1745 ExtensionKind = "SME";
1746 break;
1747 case ACLEKind::SVE:
1748 ExtensionKind = "SVE";
1749 break;
1752 OS << "#ifdef GET_" << ExtensionKind << "_STREAMING_ATTRS\n";
1754 llvm::StringMap<std::set<std::string>> StreamingMap;
1756 uint64_t IsStreamingFlag = getEnumValueForFlag("IsStreaming");
1757 uint64_t IsStreamingCompatibleFlag =
1758 getEnumValueForFlag("IsStreamingCompatible");
1759 for (auto &Def : Defs) {
1760 if (Def->isFlagSet(IsStreamingFlag))
1761 StreamingMap["ArmStreaming"].insert(Def->getMangledName());
1762 else if (Def->isFlagSet(IsStreamingCompatibleFlag))
1763 StreamingMap["ArmStreamingCompatible"].insert(Def->getMangledName());
1764 else
1765 StreamingMap["ArmNonStreaming"].insert(Def->getMangledName());
1768 for (auto BuiltinType : StreamingMap.keys()) {
1769 for (auto Name : StreamingMap[BuiltinType]) {
1770 OS << "case " << ExtensionKind << "::BI__builtin_"
1771 << ExtensionKind.lower() << "_";
1772 OS << Name << ":\n";
1774 OS << " BuiltinType = " << BuiltinType << ";\n";
1775 OS << " break;\n";
1778 OS << "#endif\n\n";
1781 namespace clang {
1782 void EmitSveHeader(RecordKeeper &Records, raw_ostream &OS) {
1783 SVEEmitter(Records).createHeader(OS);
1786 void EmitSveBuiltins(RecordKeeper &Records, raw_ostream &OS) {
1787 SVEEmitter(Records).createBuiltins(OS);
1790 void EmitSveBuiltinCG(RecordKeeper &Records, raw_ostream &OS) {
1791 SVEEmitter(Records).createCodeGenMap(OS);
1794 void EmitSveRangeChecks(RecordKeeper &Records, raw_ostream &OS) {
1795 SVEEmitter(Records).createRangeChecks(OS);
1798 void EmitSveTypeFlags(RecordKeeper &Records, raw_ostream &OS) {
1799 SVEEmitter(Records).createTypeFlags(OS);
1802 void EmitSveStreamingAttrs(RecordKeeper &Records, raw_ostream &OS) {
1803 SVEEmitter(Records).createStreamingAttrs(OS, ACLEKind::SVE);
1806 void EmitSmeHeader(RecordKeeper &Records, raw_ostream &OS) {
1807 SVEEmitter(Records).createSMEHeader(OS);
1810 void EmitSmeBuiltins(RecordKeeper &Records, raw_ostream &OS) {
1811 SVEEmitter(Records).createSMEBuiltins(OS);
1814 void EmitSmeBuiltinCG(RecordKeeper &Records, raw_ostream &OS) {
1815 SVEEmitter(Records).createSMECodeGenMap(OS);
1818 void EmitSmeRangeChecks(RecordKeeper &Records, raw_ostream &OS) {
1819 SVEEmitter(Records).createSMERangeChecks(OS);
1822 void EmitSmeStreamingAttrs(RecordKeeper &Records, raw_ostream &OS) {
1823 SVEEmitter(Records).createStreamingAttrs(OS, ACLEKind::SME);
1826 void EmitSmeBuiltinZAState(RecordKeeper &Records, raw_ostream &OS) {
1827 SVEEmitter(Records).createBuiltinZAState(OS);
1829 } // End namespace clang