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/STLExtras.h"
27 #include "llvm/ADT/StringMap.h"
28 #include "llvm/ADT/ArrayRef.h"
29 #include "llvm/ADT/StringExtras.h"
30 #include "llvm/TableGen/Record.h"
31 #include "llvm/TableGen/Error.h"
32 #include <string>
33 #include <sstream>
34 #include <set>
35 #include <cctype>
36 #include <tuple>
37 
38 using namespace llvm;
39 
40 enum ClassKind {
41   ClassNone,
42   ClassS,     // signed/unsigned, e.g., "_s8", "_u8" suffix
43   ClassG,     // Overloaded name without type suffix
44 };
45 
46 using TypeSpec = std::string;
47 
48 namespace {
49 
50 class ImmCheck {
51   unsigned Arg;
52   unsigned Kind;
53   unsigned ElementSizeInBits;
54 
55 public:
56   ImmCheck(unsigned Arg, unsigned Kind, unsigned ElementSizeInBits = 0)
57       : Arg(Arg), Kind(Kind), ElementSizeInBits(ElementSizeInBits) {}
58   ImmCheck(const ImmCheck &Other) = default;
59   ~ImmCheck() = default;
60 
61   unsigned getArg() const { return Arg; }
62   unsigned getKind() const { return Kind; }
63   unsigned getElementSizeInBits() const { return ElementSizeInBits; }
64 };
65 
66 class SVEType {
67   TypeSpec TS;
68   bool Float, Signed, Immediate, Void, Constant, Pointer;
69   bool DefaultType, IsScalable, Predicate, PredicatePattern, PrefetchOp;
70   unsigned Bitwidth, ElementBitwidth, NumVectors;
71 
72 public:
73   SVEType() : SVEType(TypeSpec(), 'v') {}
74 
75   SVEType(TypeSpec TS, char CharMod)
76       : TS(TS), Float(false), Signed(true), Immediate(false), Void(false),
77         Constant(false), Pointer(false), DefaultType(false), IsScalable(true),
78         Predicate(false), PredicatePattern(false), PrefetchOp(false),
79         Bitwidth(128), ElementBitwidth(~0U), NumVectors(1) {
80     if (!TS.empty())
81       applyTypespec();
82     applyModifier(CharMod);
83   }
84 
85   bool isPointer() const { return Pointer; }
86   bool isVoidPointer() const { return Pointer && Void; }
87   bool isSigned() const { return Signed; }
88   bool isImmediate() const { return Immediate; }
89   bool isScalar() const { return NumVectors == 0; }
90   bool isVector() const { return NumVectors > 0; }
91   bool isScalableVector() const { return isVector() && IsScalable; }
92   bool isChar() const { return ElementBitwidth == 8; }
93   bool isVoid() const { return Void & !Pointer; }
94   bool isDefault() const { return DefaultType; }
95   bool isFloat() const { return Float; }
96   bool isInteger() const { return !Float && !Predicate; }
97   bool isScalarPredicate() const { return !Float && ElementBitwidth == 1; }
98   bool isPredicateVector() const { return Predicate; }
99   bool isPredicatePattern() const { return PredicatePattern; }
100   bool isPrefetchOp() const { return PrefetchOp; }
101   bool isConstant() const { return Constant; }
102   unsigned getElementSizeInBits() const { return ElementBitwidth; }
103   unsigned getNumVectors() const { return NumVectors; }
104 
105   unsigned getNumElements() const {
106     assert(ElementBitwidth != ~0U);
107     return Bitwidth / ElementBitwidth;
108   }
109   unsigned getSizeInBits() const {
110     return Bitwidth;
111   }
112 
113   /// Return the string representation of a type, which is an encoded
114   /// string for passing to the BUILTIN() macro in Builtins.def.
115   std::string builtin_str() const;
116 
117   /// Return the C/C++ string representation of a type for use in the
118   /// arm_sve.h header file.
119   std::string str() const;
120 
121 private:
122   /// Creates the type based on the typespec string in TS.
123   void applyTypespec();
124 
125   /// Applies a prototype modifier to the type.
126   void applyModifier(char Mod);
127 };
128 
129 
130 class SVEEmitter;
131 
132 /// The main grunt class. This represents an instantiation of an intrinsic with
133 /// a particular typespec and prototype.
134 class Intrinsic {
135   /// The unmangled name.
136   std::string Name;
137 
138   /// The name of the corresponding LLVM IR intrinsic.
139   std::string LLVMName;
140 
141   /// Intrinsic prototype.
142   std::string Proto;
143 
144   /// The base type spec for this intrinsic.
145   TypeSpec BaseTypeSpec;
146 
147   /// The base class kind. Most intrinsics use ClassS, which has full type
148   /// info for integers (_s32/_u32), or ClassG which is used for overloaded
149   /// intrinsics.
150   ClassKind Class;
151 
152   /// The architectural #ifdef guard.
153   std::string Guard;
154 
155   // The merge suffix such as _m, _x or _z.
156   std::string MergeSuffix;
157 
158   /// The types of return value [0] and parameters [1..].
159   std::vector<SVEType> Types;
160 
161   /// The "base type", which is VarType('d', BaseTypeSpec).
162   SVEType BaseType;
163 
164   uint64_t Flags;
165 
166   SmallVector<ImmCheck, 2> ImmChecks;
167 
168 public:
169   Intrinsic(StringRef Name, StringRef Proto, uint64_t MergeTy,
170             StringRef MergeSuffix, uint64_t MemoryElementTy, StringRef LLVMName,
171             uint64_t Flags, ArrayRef<ImmCheck> ImmChecks, TypeSpec BT,
172             ClassKind Class, SVEEmitter &Emitter, StringRef Guard);
173 
174   ~Intrinsic()=default;
175 
176   std::string getName() const { return Name; }
177   std::string getLLVMName() const { return LLVMName; }
178   std::string getProto() const { return Proto; }
179   TypeSpec getBaseTypeSpec() const { return BaseTypeSpec; }
180   SVEType getBaseType() const { return BaseType; }
181 
182   StringRef getGuard() const { return Guard; }
183   ClassKind getClassKind() const { return Class; }
184 
185   SVEType getReturnType() const { return Types[0]; }
186   ArrayRef<SVEType> getTypes() const { return Types; }
187   SVEType getParamType(unsigned I) const { return Types[I + 1]; }
188   unsigned getNumParams() const { return Proto.size() - 1; }
189 
190   uint64_t getFlags() const { return Flags; }
191   bool isFlagSet(uint64_t Flag) const { return Flags & Flag;}
192 
193   ArrayRef<ImmCheck> getImmChecks() const { return ImmChecks; }
194 
195   /// Return the type string for a BUILTIN() macro in Builtins.def.
196   std::string getBuiltinTypeStr();
197 
198   /// Return the name, mangled with type information. The name is mangled for
199   /// ClassS, so will add type suffixes such as _u32/_s32.
200   std::string getMangledName() const { return mangleName(ClassS); }
201 
202   /// Returns true if the intrinsic is overloaded, in that it should also generate
203   /// a short form without the type-specifiers, e.g. 'svld1(..)' instead of
204   /// 'svld1_u32(..)'.
205   static bool isOverloadedIntrinsic(StringRef Name) {
206     auto BrOpen = Name.find("[");
207     auto BrClose = Name.find(']');
208     return BrOpen != std::string::npos && BrClose != std::string::npos;
209   }
210 
211   /// Return true if the intrinsic takes a splat operand.
212   bool hasSplat() const {
213     // These prototype modifiers are described in arm_sve.td.
214     return Proto.find_first_of("ajfrKLR") != std::string::npos;
215   }
216 
217   /// Return the parameter index of the splat operand.
218   unsigned getSplatIdx() const {
219     // These prototype modifiers are described in arm_sve.td.
220     auto Idx = Proto.find_first_of("ajfrKLR");
221     assert(Idx != std::string::npos && Idx > 0 &&
222            "Prototype has no splat operand");
223     return Idx - 1;
224   }
225 
226   /// Emits the intrinsic declaration to the ostream.
227   void emitIntrinsic(raw_ostream &OS) const;
228 
229 private:
230   std::string getMergeSuffix() const { return MergeSuffix; }
231   std::string mangleName(ClassKind LocalCK) const;
232   std::string replaceTemplatedArgs(std::string Name, TypeSpec TS,
233                                    std::string Proto) const;
234 };
235 
236 class SVEEmitter {
237 private:
238   RecordKeeper &Records;
239   llvm::StringMap<uint64_t> EltTypes;
240   llvm::StringMap<uint64_t> MemEltTypes;
241   llvm::StringMap<uint64_t> FlagTypes;
242   llvm::StringMap<uint64_t> MergeTypes;
243   llvm::StringMap<uint64_t> ImmCheckTypes;
244 
245 public:
246   SVEEmitter(RecordKeeper &R) : Records(R) {
247     for (auto *RV : Records.getAllDerivedDefinitions("EltType"))
248       EltTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");
249     for (auto *RV : Records.getAllDerivedDefinitions("MemEltType"))
250       MemEltTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");
251     for (auto *RV : Records.getAllDerivedDefinitions("FlagType"))
252       FlagTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");
253     for (auto *RV : Records.getAllDerivedDefinitions("MergeType"))
254       MergeTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");
255     for (auto *RV : Records.getAllDerivedDefinitions("ImmCheckType"))
256       ImmCheckTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");
257   }
258 
259   /// Returns the enum value for the immcheck type
260   unsigned getEnumValueForImmCheck(StringRef C) const {
261     auto It = ImmCheckTypes.find(C);
262     if (It != ImmCheckTypes.end())
263       return It->getValue();
264     llvm_unreachable("Unsupported imm check");
265   }
266 
267   /// Returns the enum value for the flag type
268   uint64_t getEnumValueForFlag(StringRef C) const {
269     auto Res = FlagTypes.find(C);
270     if (Res != FlagTypes.end())
271       return Res->getValue();
272     llvm_unreachable("Unsupported flag");
273   }
274 
275   // Returns the SVETypeFlags for a given value and mask.
276   uint64_t encodeFlag(uint64_t V, StringRef MaskName) const {
277     auto It = FlagTypes.find(MaskName);
278     if (It != FlagTypes.end()) {
279       uint64_t Mask = It->getValue();
280       unsigned Shift = llvm::countTrailingZeros(Mask);
281       return (V << Shift) & Mask;
282     }
283     llvm_unreachable("Unsupported flag");
284   }
285 
286   // Returns the SVETypeFlags for the given element type.
287   uint64_t encodeEltType(StringRef EltName) {
288     auto It = EltTypes.find(EltName);
289     if (It != EltTypes.end())
290       return encodeFlag(It->getValue(), "EltTypeMask");
291     llvm_unreachable("Unsupported EltType");
292   }
293 
294   // Returns the SVETypeFlags for the given memory element type.
295   uint64_t encodeMemoryElementType(uint64_t MT) {
296     return encodeFlag(MT, "MemEltTypeMask");
297   }
298 
299   // Returns the SVETypeFlags for the given merge type.
300   uint64_t encodeMergeType(uint64_t MT) {
301     return encodeFlag(MT, "MergeTypeMask");
302   }
303 
304   // Returns the SVETypeFlags for the given splat operand.
305   unsigned encodeSplatOperand(unsigned SplatIdx) {
306     assert(SplatIdx < 7 && "SplatIdx out of encodable range");
307     return encodeFlag(SplatIdx + 1, "SplatOperandMask");
308   }
309 
310   // Returns the SVETypeFlags value for the given SVEType.
311   uint64_t encodeTypeFlags(const SVEType &T);
312 
313   /// Emit arm_sve.h.
314   void createHeader(raw_ostream &o);
315 
316   /// Emit all the __builtin prototypes and code needed by Sema.
317   void createBuiltins(raw_ostream &o);
318 
319   /// Emit all the information needed to map builtin -> LLVM IR intrinsic.
320   void createCodeGenMap(raw_ostream &o);
321 
322   /// Emit all the range checks for the immediates.
323   void createRangeChecks(raw_ostream &o);
324 
325   /// Create the SVETypeFlags used in CGBuiltins
326   void createTypeFlags(raw_ostream &o);
327 
328   /// Create intrinsic and add it to \p Out
329   void createIntrinsic(Record *R, SmallVectorImpl<std::unique_ptr<Intrinsic>> &Out);
330 };
331 
332 } // end anonymous namespace
333 
334 
335 //===----------------------------------------------------------------------===//
336 // Type implementation
337 //===----------------------------------------------------------------------===//
338 
339 std::string SVEType::builtin_str() const {
340   std::string S;
341   if (isVoid())
342     return "v";
343 
344   if (isVoidPointer())
345     S += "v";
346   else if (!Float)
347     switch (ElementBitwidth) {
348     case 1: S += "b"; break;
349     case 8: S += "c"; break;
350     case 16: S += "s"; break;
351     case 32: S += "i"; break;
352     case 64: S += "Wi"; break;
353     case 128: S += "LLLi"; break;
354     default: llvm_unreachable("Unhandled case!");
355     }
356   else
357     switch (ElementBitwidth) {
358     case 16: S += "h"; break;
359     case 32: S += "f"; break;
360     case 64: S += "d"; break;
361     default: llvm_unreachable("Unhandled case!");
362     }
363 
364   if (!isFloat()) {
365     if ((isChar() || isPointer()) && !isVoidPointer()) {
366       // Make chars and typed pointers explicitly signed.
367       if (Signed)
368         S = "S" + S;
369       else if (!Signed)
370         S = "U" + S;
371     } else if (!isVoidPointer() && !Signed) {
372       S = "U" + S;
373     }
374   }
375 
376   // Constant indices are "int", but have the "constant expression" modifier.
377   if (isImmediate()) {
378     assert(!isFloat() && "fp immediates are not supported");
379     S = "I" + S;
380   }
381 
382   if (isScalar()) {
383     if (Constant) S += "C";
384     if (Pointer) S += "*";
385     return S;
386   }
387 
388   assert(isScalableVector() && "Unsupported type");
389   return "q" + utostr(getNumElements() * NumVectors) + S;
390 }
391 
392 std::string SVEType::str() const {
393   if (isPredicatePattern())
394     return "sv_pattern";
395 
396   if (isPrefetchOp())
397     return "sv_prfop";
398 
399   std::string S;
400   if (Void)
401     S += "void";
402   else {
403     if (isScalableVector())
404       S += "sv";
405     if (!Signed && !Float)
406       S += "u";
407 
408     if (Float)
409       S += "float";
410     else if (isScalarPredicate())
411       S += "bool";
412     else
413       S += "int";
414 
415     if (!isScalarPredicate())
416       S += utostr(ElementBitwidth);
417     if (!isScalableVector() && isVector())
418       S += "x" + utostr(getNumElements());
419     if (NumVectors > 1)
420       S += "x" + utostr(NumVectors);
421     S += "_t";
422   }
423 
424   if (Constant)
425     S += " const";
426   if (Pointer)
427     S += " *";
428 
429   return S;
430 }
431 void SVEType::applyTypespec() {
432   for (char I : TS) {
433     switch (I) {
434     case 'P':
435       Predicate = true;
436       ElementBitwidth = 1;
437       break;
438     case 'U':
439       Signed = false;
440       break;
441     case 'c':
442       ElementBitwidth = 8;
443       break;
444     case 's':
445       ElementBitwidth = 16;
446       break;
447     case 'i':
448       ElementBitwidth = 32;
449       break;
450     case 'l':
451       ElementBitwidth = 64;
452       break;
453     case 'h':
454       Float = true;
455       ElementBitwidth = 16;
456       break;
457     case 'f':
458       Float = true;
459       ElementBitwidth = 32;
460       break;
461     case 'd':
462       Float = true;
463       ElementBitwidth = 64;
464       break;
465     default:
466       llvm_unreachable("Unhandled type code!");
467     }
468   }
469   assert(ElementBitwidth != ~0U && "Bad element bitwidth!");
470 }
471 
472 void SVEType::applyModifier(char Mod) {
473   switch (Mod) {
474   case 'v':
475     Void = true;
476     break;
477   case 'd':
478     DefaultType = true;
479     break;
480   case 'c':
481     Constant = true;
482     LLVM_FALLTHROUGH;
483   case 'p':
484     Pointer = true;
485     Bitwidth = ElementBitwidth;
486     NumVectors = 0;
487     break;
488   case 'e':
489     Signed = false;
490     ElementBitwidth /= 2;
491     break;
492   case 'h':
493     ElementBitwidth /= 2;
494     break;
495   case 'q':
496     ElementBitwidth /= 4;
497     break;
498   case 'o':
499     ElementBitwidth *= 4;
500     break;
501   case 'P':
502     Signed = true;
503     Float = false;
504     Predicate = true;
505     Bitwidth = 16;
506     ElementBitwidth = 1;
507     break;
508   case 'a':
509     Bitwidth = ElementBitwidth;
510     NumVectors = 0;
511     break;
512   case 'u':
513     Predicate = false;
514     Signed = false;
515     Float = false;
516     break;
517   case 'x':
518     Predicate = false;
519     Signed = true;
520     Float = false;
521     break;
522   case 'i':
523     Predicate = false;
524     Float = false;
525     ElementBitwidth = Bitwidth = 64;
526     NumVectors = 0;
527     Signed = false;
528     Immediate = true;
529     break;
530   case 'I':
531     Predicate = false;
532     Float = false;
533     ElementBitwidth = Bitwidth = 32;
534     NumVectors = 0;
535     Signed = true;
536     Immediate = true;
537     PredicatePattern = true;
538     break;
539   case 'k':
540     Predicate = false;
541     Signed = true;
542     Float = false;
543     ElementBitwidth = Bitwidth = 32;
544     NumVectors = 0;
545     break;
546   case 'l':
547     Predicate = false;
548     Signed = true;
549     Float = false;
550     ElementBitwidth = Bitwidth = 64;
551     NumVectors = 0;
552     break;
553   case 'm':
554     Predicate = false;
555     Signed = false;
556     Float = false;
557     ElementBitwidth = Bitwidth = 32;
558     NumVectors = 0;
559     break;
560   case 'n':
561     Predicate = false;
562     Signed = false;
563     Float = false;
564     ElementBitwidth = Bitwidth = 64;
565     NumVectors = 0;
566     break;
567   case 't':
568     Signed = true;
569     Float = false;
570     ElementBitwidth = 32;
571     break;
572   case 'z':
573     Signed = false;
574     Float = false;
575     ElementBitwidth = 32;
576     break;
577   case 'O':
578     Predicate = false;
579     Float = true;
580     ElementBitwidth = 16;
581     break;
582   case 'M':
583     Predicate = false;
584     Float = true;
585     ElementBitwidth = 32;
586     break;
587   case 'N':
588     Predicate = false;
589     Float = true;
590     ElementBitwidth = 64;
591     break;
592   case 'S':
593     Constant = true;
594     Pointer = true;
595     ElementBitwidth = Bitwidth = 8;
596     NumVectors = 0;
597     Signed = true;
598     break;
599   case 'W':
600     Constant = true;
601     Pointer = true;
602     ElementBitwidth = Bitwidth = 8;
603     NumVectors = 0;
604     Signed = false;
605     break;
606   case 'T':
607     Constant = true;
608     Pointer = true;
609     ElementBitwidth = Bitwidth = 16;
610     NumVectors = 0;
611     Signed = true;
612     break;
613   case 'X':
614     Constant = true;
615     Pointer = true;
616     ElementBitwidth = Bitwidth = 16;
617     NumVectors = 0;
618     Signed = false;
619     break;
620   case 'Y':
621     Constant = true;
622     Pointer = true;
623     ElementBitwidth = Bitwidth = 32;
624     NumVectors = 0;
625     Signed = false;
626     break;
627   case 'U':
628     Constant = true;
629     Pointer = true;
630     ElementBitwidth = Bitwidth = 32;
631     NumVectors = 0;
632     Signed = true;
633     break;
634   case 'A':
635     Pointer = true;
636     ElementBitwidth = Bitwidth = 8;
637     NumVectors = 0;
638     Signed = true;
639     break;
640   case 'B':
641     Pointer = true;
642     ElementBitwidth = Bitwidth = 16;
643     NumVectors = 0;
644     Signed = true;
645     break;
646   case 'C':
647     Pointer = true;
648     ElementBitwidth = Bitwidth = 32;
649     NumVectors = 0;
650     Signed = true;
651     break;
652   case 'D':
653     Pointer = true;
654     ElementBitwidth = Bitwidth = 64;
655     NumVectors = 0;
656     Signed = true;
657     break;
658   case 'E':
659     Pointer = true;
660     ElementBitwidth = Bitwidth = 8;
661     NumVectors = 0;
662     Signed = false;
663     break;
664   case 'F':
665     Pointer = true;
666     ElementBitwidth = Bitwidth = 16;
667     NumVectors = 0;
668     Signed = false;
669     break;
670   case 'G':
671     Pointer = true;
672     ElementBitwidth = Bitwidth = 32;
673     NumVectors = 0;
674     Signed = false;
675     break;
676   default:
677     llvm_unreachable("Unhandled character!");
678   }
679 }
680 
681 
682 //===----------------------------------------------------------------------===//
683 // Intrinsic implementation
684 //===----------------------------------------------------------------------===//
685 
686 Intrinsic::Intrinsic(StringRef Name, StringRef Proto, uint64_t MergeTy,
687                      StringRef MergeSuffix, uint64_t MemoryElementTy,
688                      StringRef LLVMName, uint64_t Flags,
689                      ArrayRef<ImmCheck> Checks, TypeSpec BT, ClassKind Class,
690                      SVEEmitter &Emitter, StringRef Guard)
691     : Name(Name.str()), LLVMName(LLVMName), Proto(Proto.str()),
692       BaseTypeSpec(BT), Class(Class), Guard(Guard.str()),
693       MergeSuffix(MergeSuffix.str()), BaseType(BT, 'd'), Flags(Flags),
694       ImmChecks(Checks.begin(), Checks.end()) {
695 
696   // Types[0] is the return value.
697   for (unsigned I = 0; I < Proto.size(); ++I) {
698     SVEType T(BaseTypeSpec, Proto[I]);
699     Types.push_back(T);
700 
701     // Add range checks for immediates
702     if (I > 0) {
703       if (T.isPredicatePattern())
704         ImmChecks.emplace_back(
705             I - 1, Emitter.getEnumValueForImmCheck("ImmCheck0_31"));
706     }
707   }
708 
709   // Set flags based on properties
710   this->Flags |= Emitter.encodeTypeFlags(BaseType);
711   this->Flags |= Emitter.encodeMemoryElementType(MemoryElementTy);
712   this->Flags |= Emitter.encodeMergeType(MergeTy);
713   if (hasSplat())
714     this->Flags |= Emitter.encodeSplatOperand(getSplatIdx());
715 }
716 
717 std::string Intrinsic::getBuiltinTypeStr() {
718   std::string S;
719 
720   SVEType RetT = getReturnType();
721   // Since the return value must be one type, return a vector type of the
722   // appropriate width which we will bitcast.  An exception is made for
723   // returning structs of 2, 3, or 4 vectors which are returned in a sret-like
724   // fashion, storing them to a pointer arg.
725   if (RetT.getNumVectors() > 1) {
726     S += "vv*"; // void result with void* first argument
727   } else
728     S += RetT.builtin_str();
729 
730   for (unsigned I = 0; I < getNumParams(); ++I)
731     S += getParamType(I).builtin_str();
732 
733   return S;
734 }
735 
736 std::string Intrinsic::replaceTemplatedArgs(std::string Name, TypeSpec TS,
737                                             std::string Proto) const {
738   std::string Ret = Name;
739   while (Ret.find('{') != std::string::npos) {
740     size_t Pos = Ret.find('{');
741     size_t End = Ret.find('}');
742     unsigned NumChars = End - Pos + 1;
743     assert(NumChars == 3 && "Unexpected template argument");
744 
745     SVEType T;
746     char C = Ret[Pos+1];
747     switch(C) {
748     default:
749       llvm_unreachable("Unknown predication specifier");
750     case 'd':
751       T = SVEType(TS, 'd');
752       break;
753     case '0':
754     case '1':
755     case '2':
756     case '3':
757       T = SVEType(TS, Proto[C - '0']);
758       break;
759     }
760 
761     // Replace templated arg with the right suffix (e.g. u32)
762     std::string TypeCode;
763     if (T.isInteger())
764       TypeCode = T.isSigned() ? 's' : 'u';
765     else if (T.isPredicateVector())
766       TypeCode = 'b';
767     else
768       TypeCode = 'f';
769     Ret.replace(Pos, NumChars, TypeCode + utostr(T.getElementSizeInBits()));
770   }
771 
772   return Ret;
773 }
774 
775 std::string Intrinsic::mangleName(ClassKind LocalCK) const {
776   std::string S = getName();
777 
778   if (LocalCK == ClassG) {
779     // Remove the square brackets and everything in between.
780     while (S.find("[") != std::string::npos) {
781       auto Start = S.find("[");
782       auto End = S.find(']');
783       S.erase(Start, (End-Start)+1);
784     }
785   } else {
786     // Remove the square brackets.
787     while (S.find("[") != std::string::npos) {
788       auto BrPos = S.find('[');
789       if (BrPos != std::string::npos)
790         S.erase(BrPos, 1);
791       BrPos = S.find(']');
792       if (BrPos != std::string::npos)
793         S.erase(BrPos, 1);
794     }
795   }
796 
797   // Replace all {d} like expressions with e.g. 'u32'
798   return replaceTemplatedArgs(S, getBaseTypeSpec(), getProto()) +
799          getMergeSuffix();
800 }
801 
802 void Intrinsic::emitIntrinsic(raw_ostream &OS) const {
803   // Use the preprocessor to
804   if (getClassKind() != ClassG || getProto().size() <= 1) {
805     OS << "#define " << mangleName(getClassKind())
806        << "(...) __builtin_sve_" << mangleName(ClassS)
807        << "(__VA_ARGS__)\n";
808   } else {
809     std::string FullName = mangleName(ClassS);
810     std::string ProtoName = mangleName(ClassG);
811 
812     OS << "__aio __attribute__((__clang_arm_builtin_alias("
813        << "__builtin_sve_" << FullName << ")))\n";
814 
815     OS << getTypes()[0].str() << " " << ProtoName << "(";
816     for (unsigned I = 0; I < getTypes().size() - 1; ++I) {
817       if (I != 0)
818         OS << ", ";
819       OS << getTypes()[I + 1].str();
820     }
821     OS << ");\n";
822   }
823 }
824 
825 //===----------------------------------------------------------------------===//
826 // SVEEmitter implementation
827 //===----------------------------------------------------------------------===//
828 uint64_t SVEEmitter::encodeTypeFlags(const SVEType &T) {
829   if (T.isFloat()) {
830     switch (T.getElementSizeInBits()) {
831     case 16:
832       return encodeEltType("EltTyFloat16");
833     case 32:
834       return encodeEltType("EltTyFloat32");
835     case 64:
836       return encodeEltType("EltTyFloat64");
837     default:
838       llvm_unreachable("Unhandled float element bitwidth!");
839     }
840   }
841 
842   if (T.isPredicateVector()) {
843     switch (T.getElementSizeInBits()) {
844     case 8:
845       return encodeEltType("EltTyBool8");
846     case 16:
847       return encodeEltType("EltTyBool16");
848     case 32:
849       return encodeEltType("EltTyBool32");
850     case 64:
851       return encodeEltType("EltTyBool64");
852     default:
853       llvm_unreachable("Unhandled predicate element bitwidth!");
854     }
855   }
856 
857   switch (T.getElementSizeInBits()) {
858   case 8:
859     return encodeEltType("EltTyInt8");
860   case 16:
861     return encodeEltType("EltTyInt16");
862   case 32:
863     return encodeEltType("EltTyInt32");
864   case 64:
865     return encodeEltType("EltTyInt64");
866   default:
867     llvm_unreachable("Unhandled integer element bitwidth!");
868   }
869 }
870 
871 void SVEEmitter::createIntrinsic(
872     Record *R, SmallVectorImpl<std::unique_ptr<Intrinsic>> &Out) {
873   StringRef Name = R->getValueAsString("Name");
874   StringRef Proto = R->getValueAsString("Prototype");
875   StringRef Types = R->getValueAsString("Types");
876   StringRef Guard = R->getValueAsString("ArchGuard");
877   StringRef LLVMName = R->getValueAsString("LLVMIntrinsic");
878   uint64_t Merge = R->getValueAsInt("Merge");
879   StringRef MergeSuffix = R->getValueAsString("MergeSuffix");
880   uint64_t MemEltType = R->getValueAsInt("MemEltType");
881   std::vector<Record*> FlagsList = R->getValueAsListOfDefs("Flags");
882   std::vector<Record*> ImmCheckList = R->getValueAsListOfDefs("ImmChecks");
883 
884   int64_t Flags = 0;
885   for (auto FlagRec : FlagsList)
886     Flags |= FlagRec->getValueAsInt("Value");
887 
888   // Create a dummy TypeSpec for non-overloaded builtins.
889   if (Types.empty()) {
890     assert((Flags & getEnumValueForFlag("IsOverloadNone")) &&
891            "Expect TypeSpec for overloaded builtin!");
892     Types = "i";
893   }
894 
895   // Extract type specs from string
896   SmallVector<TypeSpec, 8> TypeSpecs;
897   TypeSpec Acc;
898   for (char I : Types) {
899     Acc.push_back(I);
900     if (islower(I)) {
901       TypeSpecs.push_back(TypeSpec(Acc));
902       Acc.clear();
903     }
904   }
905 
906   // Remove duplicate type specs.
907   llvm::sort(TypeSpecs);
908   TypeSpecs.erase(std::unique(TypeSpecs.begin(), TypeSpecs.end()),
909                   TypeSpecs.end());
910 
911   // Create an Intrinsic for each type spec.
912   for (auto TS : TypeSpecs) {
913     // Collate a list of range/option checks for the immediates.
914     SmallVector<ImmCheck, 2> ImmChecks;
915     for (auto *R : ImmCheckList) {
916       int64_t Arg = R->getValueAsInt("Arg");
917       int64_t EltSizeArg = R->getValueAsInt("EltSizeArg");
918       int64_t Kind = R->getValueAsDef("Kind")->getValueAsInt("Value");
919       assert(Arg >= 0 && Kind >= 0 && "Arg and Kind must be nonnegative");
920 
921       unsigned ElementSizeInBits = 0;
922       if (EltSizeArg >= 0)
923         ElementSizeInBits =
924             SVEType(TS, Proto[EltSizeArg + /* offset by return arg */ 1])
925                 .getElementSizeInBits();
926       ImmChecks.push_back(ImmCheck(Arg, Kind, ElementSizeInBits));
927     }
928 
929     Out.push_back(std::make_unique<Intrinsic>(
930         Name, Proto, Merge, MergeSuffix, MemEltType, LLVMName, Flags, ImmChecks,
931         TS, ClassS, *this, Guard));
932 
933     // Also generate the short-form (e.g. svadd_m) for the given type-spec.
934     if (Intrinsic::isOverloadedIntrinsic(Name))
935       Out.push_back(std::make_unique<Intrinsic>(
936           Name, Proto, Merge, MergeSuffix, MemEltType, LLVMName, Flags,
937           ImmChecks, TS, ClassG, *this, Guard));
938   }
939 }
940 
941 void SVEEmitter::createHeader(raw_ostream &OS) {
942   OS << "/*===---- arm_sve.h - ARM SVE intrinsics "
943         "-----------------------------------===\n"
944         " *\n"
945         " *\n"
946         " * Part of the LLVM Project, under the Apache License v2.0 with LLVM "
947         "Exceptions.\n"
948         " * See https://llvm.org/LICENSE.txt for license information.\n"
949         " * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n"
950         " *\n"
951         " *===-----------------------------------------------------------------"
952         "------===\n"
953         " */\n\n";
954 
955   OS << "#ifndef __ARM_SVE_H\n";
956   OS << "#define __ARM_SVE_H\n\n";
957 
958   OS << "#if !defined(__ARM_FEATURE_SVE)\n";
959   OS << "#error \"SVE support not enabled\"\n";
960   OS << "#else\n\n";
961 
962   OS << "#include <stdint.h>\n\n";
963   OS << "#ifdef  __cplusplus\n";
964   OS << "extern \"C\" {\n";
965   OS << "#else\n";
966   OS << "#include <stdbool.h>\n";
967   OS << "#endif\n\n";
968 
969   OS << "typedef __fp16 float16_t;\n";
970   OS << "typedef float float32_t;\n";
971   OS << "typedef double float64_t;\n";
972   OS << "typedef bool bool_t;\n\n";
973 
974   OS << "typedef __SVInt8_t svint8_t;\n";
975   OS << "typedef __SVInt16_t svint16_t;\n";
976   OS << "typedef __SVInt32_t svint32_t;\n";
977   OS << "typedef __SVInt64_t svint64_t;\n";
978   OS << "typedef __SVUint8_t svuint8_t;\n";
979   OS << "typedef __SVUint16_t svuint16_t;\n";
980   OS << "typedef __SVUint32_t svuint32_t;\n";
981   OS << "typedef __SVUint64_t svuint64_t;\n";
982   OS << "typedef __SVFloat16_t svfloat16_t;\n";
983   OS << "typedef __SVFloat32_t svfloat32_t;\n";
984   OS << "typedef __SVFloat64_t svfloat64_t;\n";
985   OS << "typedef __SVBool_t  svbool_t;\n\n";
986 
987   OS << "typedef enum\n";
988   OS << "{\n";
989   OS << "  SV_POW2 = 0,\n";
990   OS << "  SV_VL1 = 1,\n";
991   OS << "  SV_VL2 = 2,\n";
992   OS << "  SV_VL3 = 3,\n";
993   OS << "  SV_VL4 = 4,\n";
994   OS << "  SV_VL5 = 5,\n";
995   OS << "  SV_VL6 = 6,\n";
996   OS << "  SV_VL7 = 7,\n";
997   OS << "  SV_VL8 = 8,\n";
998   OS << "  SV_VL16 = 9,\n";
999   OS << "  SV_VL32 = 10,\n";
1000   OS << "  SV_VL64 = 11,\n";
1001   OS << "  SV_VL128 = 12,\n";
1002   OS << "  SV_VL256 = 13,\n";
1003   OS << "  SV_MUL4 = 29,\n";
1004   OS << "  SV_MUL3 = 30,\n";
1005   OS << "  SV_ALL = 31\n";
1006   OS << "} sv_pattern;\n\n";
1007 
1008   OS << "/* Function attributes */\n";
1009   OS << "#define __aio static inline __attribute__((__always_inline__, "
1010         "__nodebug__, __overloadable__))\n\n";
1011 
1012   SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
1013   std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
1014   for (auto *R : RV)
1015     createIntrinsic(R, Defs);
1016 
1017   // Sort intrinsics in header file by following order/priority:
1018   // - Architectural guard (i.e. does it require SVE2 or SVE2_AES)
1019   // - Class (is intrinsic overloaded or not)
1020   // - Intrinsic name
1021   std::stable_sort(
1022       Defs.begin(), Defs.end(), [](const std::unique_ptr<Intrinsic> &A,
1023                                    const std::unique_ptr<Intrinsic> &B) {
1024         auto ToTuple = [](const std::unique_ptr<Intrinsic> &I) {
1025           return std::make_tuple(I->getGuard(), (unsigned)I->getClassKind(), I->getName());
1026         };
1027         return ToTuple(A) < ToTuple(B);
1028       });
1029 
1030   StringRef InGuard = "";
1031   for (auto &I : Defs) {
1032     // Emit #endif/#if pair if needed.
1033     if (I->getGuard() != InGuard) {
1034       if (!InGuard.empty())
1035         OS << "#endif  //" << InGuard << "\n";
1036       InGuard = I->getGuard();
1037       if (!InGuard.empty())
1038         OS << "\n#if " << InGuard << "\n";
1039     }
1040 
1041     // Actually emit the intrinsic declaration.
1042     I->emitIntrinsic(OS);
1043   }
1044 
1045   if (!InGuard.empty())
1046     OS << "#endif  //" << InGuard << "\n";
1047 
1048   OS << "#if defined(__ARM_FEATURE_SVE2)\n";
1049   OS << "#define svcvtnt_f16_x      svcvtnt_f16_m\n";
1050   OS << "#define svcvtnt_f16_f32_x  svcvtnt_f16_f32_m\n";
1051   OS << "#define svcvtnt_f32_x      svcvtnt_f32_m\n";
1052   OS << "#define svcvtnt_f32_f64_x  svcvtnt_f32_f64_m\n\n";
1053 
1054   OS << "#define svcvtxnt_f32_x     svcvtxnt_f32_m\n";
1055   OS << "#define svcvtxnt_f32_f64_x svcvtxnt_f32_f64_m\n\n";
1056 
1057   OS << "#endif /*__ARM_FEATURE_SVE2 */\n\n";
1058 
1059   OS << "#ifdef __cplusplus\n";
1060   OS << "} // extern \"C\"\n";
1061   OS << "#endif\n\n";
1062   OS << "#endif /*__ARM_FEATURE_SVE */\n\n";
1063   OS << "#endif /* __ARM_SVE_H */\n";
1064 }
1065 
1066 void SVEEmitter::createBuiltins(raw_ostream &OS) {
1067   std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
1068   SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
1069   for (auto *R : RV)
1070     createIntrinsic(R, Defs);
1071 
1072   // The mappings must be sorted based on BuiltinID.
1073   llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A,
1074                       const std::unique_ptr<Intrinsic> &B) {
1075     return A->getMangledName() < B->getMangledName();
1076   });
1077 
1078   OS << "#ifdef GET_SVE_BUILTINS\n";
1079   for (auto &Def : Defs) {
1080     // Only create BUILTINs for non-overloaded intrinsics, as overloaded
1081     // declarations only live in the header file.
1082     if (Def->getClassKind() != ClassG)
1083       OS << "BUILTIN(__builtin_sve_" << Def->getMangledName() << ", \""
1084          << Def->getBuiltinTypeStr() << "\", \"n\")\n";
1085   }
1086   OS << "#endif\n\n";
1087 }
1088 
1089 void SVEEmitter::createCodeGenMap(raw_ostream &OS) {
1090   std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
1091   SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
1092   for (auto *R : RV)
1093     createIntrinsic(R, Defs);
1094 
1095   // The mappings must be sorted based on BuiltinID.
1096   llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A,
1097                       const std::unique_ptr<Intrinsic> &B) {
1098     return A->getMangledName() < B->getMangledName();
1099   });
1100 
1101   OS << "#ifdef GET_SVE_LLVM_INTRINSIC_MAP\n";
1102   for (auto &Def : Defs) {
1103     // Builtins only exist for non-overloaded intrinsics, overloaded
1104     // declarations only live in the header file.
1105     if (Def->getClassKind() == ClassG)
1106       continue;
1107 
1108     uint64_t Flags = Def->getFlags();
1109     auto FlagString = std::to_string(Flags);
1110 
1111     std::string LLVMName = Def->getLLVMName();
1112     std::string Builtin = Def->getMangledName();
1113     if (!LLVMName.empty())
1114       OS << "SVEMAP1(" << Builtin << ", " << LLVMName << ", " << FlagString
1115          << "),\n";
1116     else
1117       OS << "SVEMAP2(" << Builtin << ", " << FlagString << "),\n";
1118   }
1119   OS << "#endif\n\n";
1120 }
1121 
1122 void SVEEmitter::createRangeChecks(raw_ostream &OS) {
1123   std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
1124   SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
1125   for (auto *R : RV)
1126     createIntrinsic(R, Defs);
1127 
1128   // The mappings must be sorted based on BuiltinID.
1129   llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A,
1130                       const std::unique_ptr<Intrinsic> &B) {
1131     return A->getMangledName() < B->getMangledName();
1132   });
1133 
1134 
1135   OS << "#ifdef GET_SVE_IMMEDIATE_CHECK\n";
1136 
1137   // Ensure these are only emitted once.
1138   std::set<std::string> Emitted;
1139 
1140   for (auto &Def : Defs) {
1141     if (Emitted.find(Def->getMangledName()) != Emitted.end() ||
1142         Def->getImmChecks().empty())
1143       continue;
1144 
1145     OS << "case SVE::BI__builtin_sve_" << Def->getMangledName() << ":\n";
1146     for (auto &Check : Def->getImmChecks())
1147       OS << "ImmChecks.push_back(std::make_tuple(" << Check.getArg() << ", "
1148          << Check.getKind() << ", " << Check.getElementSizeInBits() << "));\n";
1149     OS << "  break;\n";
1150 
1151     Emitted.insert(Def->getMangledName());
1152   }
1153 
1154   OS << "#endif\n\n";
1155 }
1156 
1157 /// Create the SVETypeFlags used in CGBuiltins
1158 void SVEEmitter::createTypeFlags(raw_ostream &OS) {
1159   OS << "#ifdef LLVM_GET_SVE_TYPEFLAGS\n";
1160   for (auto &KV : FlagTypes)
1161     OS << "const uint64_t " << KV.getKey() << " = " << KV.getValue() << ";\n";
1162   OS << "#endif\n\n";
1163 
1164   OS << "#ifdef LLVM_GET_SVE_ELTTYPES\n";
1165   for (auto &KV : EltTypes)
1166     OS << "  " << KV.getKey() << " = " << KV.getValue() << ",\n";
1167   OS << "#endif\n\n";
1168 
1169   OS << "#ifdef LLVM_GET_SVE_MEMELTTYPES\n";
1170   for (auto &KV : MemEltTypes)
1171     OS << "  " << KV.getKey() << " = " << KV.getValue() << ",\n";
1172   OS << "#endif\n\n";
1173 
1174   OS << "#ifdef LLVM_GET_SVE_MERGETYPES\n";
1175   for (auto &KV : MergeTypes)
1176     OS << "  " << KV.getKey() << " = " << KV.getValue() << ",\n";
1177   OS << "#endif\n\n";
1178 
1179   OS << "#ifdef LLVM_GET_SVE_IMMCHECKTYPES\n";
1180   for (auto &KV : ImmCheckTypes)
1181     OS << "  " << KV.getKey() << " = " << KV.getValue() << ",\n";
1182   OS << "#endif\n\n";
1183 }
1184 
1185 namespace clang {
1186 void EmitSveHeader(RecordKeeper &Records, raw_ostream &OS) {
1187   SVEEmitter(Records).createHeader(OS);
1188 }
1189 
1190 void EmitSveBuiltins(RecordKeeper &Records, raw_ostream &OS) {
1191   SVEEmitter(Records).createBuiltins(OS);
1192 }
1193 
1194 void EmitSveBuiltinCG(RecordKeeper &Records, raw_ostream &OS) {
1195   SVEEmitter(Records).createCodeGenMap(OS);
1196 }
1197 
1198 void EmitSveRangeChecks(RecordKeeper &Records, raw_ostream &OS) {
1199   SVEEmitter(Records).createRangeChecks(OS);
1200 }
1201 
1202 void EmitSveTypeFlags(RecordKeeper &Records, raw_ostream &OS) {
1203   SVEEmitter(Records).createTypeFlags(OS);
1204 }
1205 
1206 } // End namespace clang
1207