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   /// Emits the intrinsic declaration to the ostream.
212   void emitIntrinsic(raw_ostream &OS) const;
213 
214 private:
215   std::string getMergeSuffix() const { return MergeSuffix; }
216   std::string mangleName(ClassKind LocalCK) const;
217   std::string replaceTemplatedArgs(std::string Name, TypeSpec TS,
218                                    std::string Proto) const;
219 };
220 
221 class SVEEmitter {
222 private:
223   RecordKeeper &Records;
224   llvm::StringMap<uint64_t> EltTypes;
225   llvm::StringMap<uint64_t> MemEltTypes;
226   llvm::StringMap<uint64_t> FlagTypes;
227   llvm::StringMap<uint64_t> MergeTypes;
228   llvm::StringMap<uint64_t> ImmCheckTypes;
229 
230 public:
231   SVEEmitter(RecordKeeper &R) : Records(R) {
232     for (auto *RV : Records.getAllDerivedDefinitions("EltType"))
233       EltTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");
234     for (auto *RV : Records.getAllDerivedDefinitions("MemEltType"))
235       MemEltTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");
236     for (auto *RV : Records.getAllDerivedDefinitions("FlagType"))
237       FlagTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");
238     for (auto *RV : Records.getAllDerivedDefinitions("MergeType"))
239       MergeTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");
240     for (auto *RV : Records.getAllDerivedDefinitions("ImmCheckType"))
241       ImmCheckTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");
242   }
243 
244   /// Returns the enum value for the immcheck type
245   unsigned getEnumValueForImmCheck(StringRef C) const {
246     auto It = ImmCheckTypes.find(C);
247     if (It != ImmCheckTypes.end())
248       return It->getValue();
249     llvm_unreachable("Unsupported imm check");
250   }
251 
252   // Returns the SVETypeFlags for a given value and mask.
253   uint64_t encodeFlag(uint64_t V, StringRef MaskName) const {
254     auto It = FlagTypes.find(MaskName);
255     if (It != FlagTypes.end()) {
256       uint64_t Mask = It->getValue();
257       unsigned Shift = llvm::countTrailingZeros(Mask);
258       return (V << Shift) & Mask;
259     }
260     llvm_unreachable("Unsupported flag");
261   }
262 
263   // Returns the SVETypeFlags for the given element type.
264   uint64_t encodeEltType(StringRef EltName) {
265     auto It = EltTypes.find(EltName);
266     if (It != EltTypes.end())
267       return encodeFlag(It->getValue(), "EltTypeMask");
268     llvm_unreachable("Unsupported EltType");
269   }
270 
271   // Returns the SVETypeFlags for the given memory element type.
272   uint64_t encodeMemoryElementType(uint64_t MT) {
273     return encodeFlag(MT, "MemEltTypeMask");
274   }
275 
276   // Returns the SVETypeFlags for the given merge type.
277   uint64_t encodeMergeType(uint64_t MT) {
278     return encodeFlag(MT, "MergeTypeMask");
279   }
280 
281   // Returns the SVETypeFlags value for the given SVEType.
282   uint64_t encodeTypeFlags(const SVEType &T);
283 
284   /// Emit arm_sve.h.
285   void createHeader(raw_ostream &o);
286 
287   /// Emit all the __builtin prototypes and code needed by Sema.
288   void createBuiltins(raw_ostream &o);
289 
290   /// Emit all the information needed to map builtin -> LLVM IR intrinsic.
291   void createCodeGenMap(raw_ostream &o);
292 
293   /// Emit all the range checks for the immediates.
294   void createRangeChecks(raw_ostream &o);
295 
296   /// Create the SVETypeFlags used in CGBuiltins
297   void createTypeFlags(raw_ostream &o);
298 
299   /// Create intrinsic and add it to \p Out
300   void createIntrinsic(Record *R, SmallVectorImpl<std::unique_ptr<Intrinsic>> &Out);
301 };
302 
303 } // end anonymous namespace
304 
305 
306 //===----------------------------------------------------------------------===//
307 // Type implementation
308 //===----------------------------------------------------------------------===//
309 
310 std::string SVEType::builtin_str() const {
311   std::string S;
312   if (isVoid())
313     return "v";
314 
315   if (isVoidPointer())
316     S += "v";
317   else if (!Float)
318     switch (ElementBitwidth) {
319     case 1: S += "b"; break;
320     case 8: S += "c"; break;
321     case 16: S += "s"; break;
322     case 32: S += "i"; break;
323     case 64: S += "Wi"; break;
324     case 128: S += "LLLi"; break;
325     default: llvm_unreachable("Unhandled case!");
326     }
327   else
328     switch (ElementBitwidth) {
329     case 16: S += "h"; break;
330     case 32: S += "f"; break;
331     case 64: S += "d"; break;
332     default: llvm_unreachable("Unhandled case!");
333     }
334 
335   if (!isFloat()) {
336     if ((isChar() || isPointer()) && !isVoidPointer()) {
337       // Make chars and typed pointers explicitly signed.
338       if (Signed)
339         S = "S" + S;
340       else if (!Signed)
341         S = "U" + S;
342     } else if (!isVoidPointer() && !Signed) {
343       S = "U" + S;
344     }
345   }
346 
347   // Constant indices are "int", but have the "constant expression" modifier.
348   if (isImmediate()) {
349     assert(!isFloat() && "fp immediates are not supported");
350     S = "I" + S;
351   }
352 
353   if (isScalar()) {
354     if (Constant) S += "C";
355     if (Pointer) S += "*";
356     return S;
357   }
358 
359   assert(isScalableVector() && "Unsupported type");
360   return "q" + utostr(getNumElements() * NumVectors) + S;
361 }
362 
363 std::string SVEType::str() const {
364   if (isPredicatePattern())
365     return "sv_pattern";
366 
367   if (isPrefetchOp())
368     return "sv_prfop";
369 
370   std::string S;
371   if (Void)
372     S += "void";
373   else {
374     if (isScalableVector())
375       S += "sv";
376     if (!Signed && !Float)
377       S += "u";
378 
379     if (Float)
380       S += "float";
381     else if (isScalarPredicate())
382       S += "bool";
383     else
384       S += "int";
385 
386     if (!isScalarPredicate())
387       S += utostr(ElementBitwidth);
388     if (!isScalableVector() && isVector())
389       S += "x" + utostr(getNumElements());
390     if (NumVectors > 1)
391       S += "x" + utostr(NumVectors);
392     S += "_t";
393   }
394 
395   if (Constant)
396     S += " const";
397   if (Pointer)
398     S += " *";
399 
400   return S;
401 }
402 void SVEType::applyTypespec() {
403   for (char I : TS) {
404     switch (I) {
405     case 'P':
406       Predicate = true;
407       ElementBitwidth = 1;
408       break;
409     case 'U':
410       Signed = false;
411       break;
412     case 'c':
413       ElementBitwidth = 8;
414       break;
415     case 's':
416       ElementBitwidth = 16;
417       break;
418     case 'i':
419       ElementBitwidth = 32;
420       break;
421     case 'l':
422       ElementBitwidth = 64;
423       break;
424     case 'h':
425       Float = true;
426       ElementBitwidth = 16;
427       break;
428     case 'f':
429       Float = true;
430       ElementBitwidth = 32;
431       break;
432     case 'd':
433       Float = true;
434       ElementBitwidth = 64;
435       break;
436     default:
437       llvm_unreachable("Unhandled type code!");
438     }
439   }
440   assert(ElementBitwidth != ~0U && "Bad element bitwidth!");
441 }
442 
443 void SVEType::applyModifier(char Mod) {
444   switch (Mod) {
445   case 'v':
446     Void = true;
447     break;
448   case 'd':
449     DefaultType = true;
450     break;
451   case 'c':
452     Constant = true;
453     LLVM_FALLTHROUGH;
454   case 'p':
455     Pointer = true;
456     Bitwidth = ElementBitwidth;
457     NumVectors = 0;
458     break;
459   case 'P':
460     Signed = true;
461     Float = false;
462     Predicate = true;
463     Bitwidth = 16;
464     ElementBitwidth = 1;
465     break;
466   case 'i':
467     Predicate = false;
468     Float = false;
469     ElementBitwidth = Bitwidth = 64;
470     NumVectors = 0;
471     Signed = false;
472     Immediate = true;
473     break;
474   case 'I':
475     Predicate = false;
476     Float = false;
477     ElementBitwidth = Bitwidth = 32;
478     NumVectors = 0;
479     Signed = true;
480     Immediate = true;
481     PredicatePattern = true;
482     break;
483   case 'l':
484     Predicate = false;
485     Signed = true;
486     Float = false;
487     ElementBitwidth = Bitwidth = 64;
488     NumVectors = 0;
489     break;
490   case 'S':
491     Constant = true;
492     Pointer = true;
493     ElementBitwidth = Bitwidth = 8;
494     NumVectors = 0;
495     Signed = true;
496     break;
497   case 'W':
498     Constant = true;
499     Pointer = true;
500     ElementBitwidth = Bitwidth = 8;
501     NumVectors = 0;
502     Signed = false;
503     break;
504   case 'T':
505     Constant = true;
506     Pointer = true;
507     ElementBitwidth = Bitwidth = 16;
508     NumVectors = 0;
509     Signed = true;
510     break;
511   case 'X':
512     Constant = true;
513     Pointer = true;
514     ElementBitwidth = Bitwidth = 16;
515     NumVectors = 0;
516     Signed = false;
517     break;
518   case 'Y':
519     Constant = true;
520     Pointer = true;
521     ElementBitwidth = Bitwidth = 32;
522     NumVectors = 0;
523     Signed = false;
524     break;
525   case 'U':
526     Constant = true;
527     Pointer = true;
528     ElementBitwidth = Bitwidth = 32;
529     NumVectors = 0;
530     Signed = true;
531     break;
532   case 'A':
533     Pointer = true;
534     ElementBitwidth = Bitwidth = 8;
535     NumVectors = 0;
536     Signed = true;
537     break;
538   case 'B':
539     Pointer = true;
540     ElementBitwidth = Bitwidth = 16;
541     NumVectors = 0;
542     Signed = true;
543     break;
544   case 'C':
545     Pointer = true;
546     ElementBitwidth = Bitwidth = 32;
547     NumVectors = 0;
548     Signed = true;
549     break;
550   case 'D':
551     Pointer = true;
552     ElementBitwidth = Bitwidth = 64;
553     NumVectors = 0;
554     Signed = true;
555     break;
556   case 'E':
557     Pointer = true;
558     ElementBitwidth = Bitwidth = 8;
559     NumVectors = 0;
560     Signed = false;
561     break;
562   case 'F':
563     Pointer = true;
564     ElementBitwidth = Bitwidth = 16;
565     NumVectors = 0;
566     Signed = false;
567     break;
568   case 'G':
569     Pointer = true;
570     ElementBitwidth = Bitwidth = 32;
571     NumVectors = 0;
572     Signed = false;
573     break;
574   default:
575     llvm_unreachable("Unhandled character!");
576   }
577 }
578 
579 
580 //===----------------------------------------------------------------------===//
581 // Intrinsic implementation
582 //===----------------------------------------------------------------------===//
583 
584 Intrinsic::Intrinsic(StringRef Name, StringRef Proto, uint64_t MergeTy,
585                      StringRef MergeSuffix, uint64_t MemoryElementTy,
586                      StringRef LLVMName, uint64_t Flags,
587                      ArrayRef<ImmCheck> Checks, TypeSpec BT, ClassKind Class,
588                      SVEEmitter &Emitter, StringRef Guard)
589     : Name(Name.str()), LLVMName(LLVMName), Proto(Proto.str()),
590       BaseTypeSpec(BT), Class(Class), Guard(Guard.str()),
591       MergeSuffix(MergeSuffix.str()), BaseType(BT, 'd'), Flags(Flags),
592       ImmChecks(Checks.begin(), Checks.end()) {
593 
594   // Types[0] is the return value.
595   for (unsigned I = 0; I < Proto.size(); ++I) {
596     SVEType T(BaseTypeSpec, Proto[I]);
597     Types.push_back(T);
598 
599     // Add range checks for immediates
600     if (I > 0) {
601       if (T.isPredicatePattern())
602         ImmChecks.emplace_back(
603             I - 1, Emitter.getEnumValueForImmCheck("ImmCheck0_31"));
604     }
605   }
606 
607   // Set flags based on properties
608   this->Flags |= Emitter.encodeTypeFlags(BaseType);
609   this->Flags |= Emitter.encodeMemoryElementType(MemoryElementTy);
610   this->Flags |= Emitter.encodeMergeType(MergeTy);
611 }
612 
613 std::string Intrinsic::getBuiltinTypeStr() {
614   std::string S;
615 
616   SVEType RetT = getReturnType();
617   // Since the return value must be one type, return a vector type of the
618   // appropriate width which we will bitcast.  An exception is made for
619   // returning structs of 2, 3, or 4 vectors which are returned in a sret-like
620   // fashion, storing them to a pointer arg.
621   if (RetT.getNumVectors() > 1) {
622     S += "vv*"; // void result with void* first argument
623   } else
624     S += RetT.builtin_str();
625 
626   for (unsigned I = 0; I < getNumParams(); ++I)
627     S += getParamType(I).builtin_str();
628 
629   return S;
630 }
631 
632 std::string Intrinsic::replaceTemplatedArgs(std::string Name, TypeSpec TS,
633                                             std::string Proto) const {
634   std::string Ret = Name;
635   while (Ret.find('{') != std::string::npos) {
636     size_t Pos = Ret.find('{');
637     size_t End = Ret.find('}');
638     unsigned NumChars = End - Pos + 1;
639     assert(NumChars == 3 && "Unexpected template argument");
640 
641     SVEType T;
642     char C = Ret[Pos+1];
643     switch(C) {
644     default:
645       llvm_unreachable("Unknown predication specifier");
646     case 'd':
647       T = SVEType(TS, 'd');
648       break;
649     case '0':
650     case '1':
651     case '2':
652     case '3':
653       T = SVEType(TS, Proto[C - '0']);
654       break;
655     }
656 
657     // Replace templated arg with the right suffix (e.g. u32)
658     std::string TypeCode;
659     if (T.isInteger())
660       TypeCode = T.isSigned() ? 's' : 'u';
661     else if (T.isPredicateVector())
662       TypeCode = 'b';
663     else
664       TypeCode = 'f';
665     Ret.replace(Pos, NumChars, TypeCode + utostr(T.getElementSizeInBits()));
666   }
667 
668   return Ret;
669 }
670 
671 std::string Intrinsic::mangleName(ClassKind LocalCK) const {
672   std::string S = getName();
673 
674   if (LocalCK == ClassG) {
675     // Remove the square brackets and everything in between.
676     while (S.find("[") != std::string::npos) {
677       auto Start = S.find("[");
678       auto End = S.find(']');
679       S.erase(Start, (End-Start)+1);
680     }
681   } else {
682     // Remove the square brackets.
683     while (S.find("[") != std::string::npos) {
684       auto BrPos = S.find('[');
685       if (BrPos != std::string::npos)
686         S.erase(BrPos, 1);
687       BrPos = S.find(']');
688       if (BrPos != std::string::npos)
689         S.erase(BrPos, 1);
690     }
691   }
692 
693   // Replace all {d} like expressions with e.g. 'u32'
694   return replaceTemplatedArgs(S, getBaseTypeSpec(), getProto()) +
695          getMergeSuffix();
696 }
697 
698 void Intrinsic::emitIntrinsic(raw_ostream &OS) const {
699   // Use the preprocessor to
700   if (getClassKind() != ClassG || getProto().size() <= 1) {
701     OS << "#define " << mangleName(getClassKind())
702        << "(...) __builtin_sve_" << mangleName(ClassS)
703        << "(__VA_ARGS__)\n";
704   } else {
705     std::string FullName = mangleName(ClassS);
706     std::string ProtoName = mangleName(ClassG);
707 
708     OS << "__aio __attribute__((__clang_arm_builtin_alias("
709        << "__builtin_sve_" << FullName << ")))\n";
710 
711     OS << getTypes()[0].str() << " " << ProtoName << "(";
712     for (unsigned I = 0; I < getTypes().size() - 1; ++I) {
713       if (I != 0)
714         OS << ", ";
715       OS << getTypes()[I + 1].str();
716     }
717     OS << ");\n";
718   }
719 }
720 
721 //===----------------------------------------------------------------------===//
722 // SVEEmitter implementation
723 //===----------------------------------------------------------------------===//
724 uint64_t SVEEmitter::encodeTypeFlags(const SVEType &T) {
725   if (T.isFloat()) {
726     switch (T.getElementSizeInBits()) {
727     case 16:
728       return encodeEltType("EltTyFloat16");
729     case 32:
730       return encodeEltType("EltTyFloat32");
731     case 64:
732       return encodeEltType("EltTyFloat64");
733     default:
734       llvm_unreachable("Unhandled float element bitwidth!");
735     }
736   }
737 
738   if (T.isPredicateVector()) {
739     switch (T.getElementSizeInBits()) {
740     case 8:
741       return encodeEltType("EltTyBool8");
742     case 16:
743       return encodeEltType("EltTyBool16");
744     case 32:
745       return encodeEltType("EltTyBool32");
746     case 64:
747       return encodeEltType("EltTyBool64");
748     default:
749       llvm_unreachable("Unhandled predicate element bitwidth!");
750     }
751   }
752 
753   switch (T.getElementSizeInBits()) {
754   case 8:
755     return encodeEltType("EltTyInt8");
756   case 16:
757     return encodeEltType("EltTyInt16");
758   case 32:
759     return encodeEltType("EltTyInt32");
760   case 64:
761     return encodeEltType("EltTyInt64");
762   default:
763     llvm_unreachable("Unhandled integer element bitwidth!");
764   }
765 }
766 
767 void SVEEmitter::createIntrinsic(
768     Record *R, SmallVectorImpl<std::unique_ptr<Intrinsic>> &Out) {
769   StringRef Name = R->getValueAsString("Name");
770   StringRef Proto = R->getValueAsString("Prototype");
771   StringRef Types = R->getValueAsString("Types");
772   StringRef Guard = R->getValueAsString("ArchGuard");
773   StringRef LLVMName = R->getValueAsString("LLVMIntrinsic");
774   uint64_t Merge = R->getValueAsInt("Merge");
775   StringRef MergeSuffix = R->getValueAsString("MergeSuffix");
776   uint64_t MemEltType = R->getValueAsInt("MemEltType");
777   std::vector<Record*> FlagsList = R->getValueAsListOfDefs("Flags");
778   std::vector<Record*> ImmCheckList = R->getValueAsListOfDefs("ImmChecks");
779 
780   int64_t Flags = 0;
781   for (auto FlagRec : FlagsList)
782     Flags |= FlagRec->getValueAsInt("Value");
783 
784   // Extract type specs from string
785   SmallVector<TypeSpec, 8> TypeSpecs;
786   TypeSpec Acc;
787   for (char I : Types) {
788     Acc.push_back(I);
789     if (islower(I)) {
790       TypeSpecs.push_back(TypeSpec(Acc));
791       Acc.clear();
792     }
793   }
794 
795   // Remove duplicate type specs.
796   llvm::sort(TypeSpecs);
797   TypeSpecs.erase(std::unique(TypeSpecs.begin(), TypeSpecs.end()),
798                   TypeSpecs.end());
799 
800   // Create an Intrinsic for each type spec.
801   for (auto TS : TypeSpecs) {
802     // Collate a list of range/option checks for the immediates.
803     SmallVector<ImmCheck, 2> ImmChecks;
804     for (auto *R : ImmCheckList) {
805       int64_t Arg = R->getValueAsInt("Arg");
806       int64_t EltSizeArg = R->getValueAsInt("EltSizeArg");
807       int64_t Kind = R->getValueAsDef("Kind")->getValueAsInt("Value");
808       assert(Arg >= 0 && Kind >= 0 && "Arg and Kind must be nonnegative");
809 
810       unsigned ElementSizeInBits = 0;
811       if (EltSizeArg >= 0)
812         ElementSizeInBits =
813             SVEType(TS, Proto[EltSizeArg + /* offset by return arg */ 1])
814                 .getElementSizeInBits();
815       ImmChecks.push_back(ImmCheck(Arg, Kind, ElementSizeInBits));
816     }
817 
818     Out.push_back(std::make_unique<Intrinsic>(
819         Name, Proto, Merge, MergeSuffix, MemEltType, LLVMName, Flags, ImmChecks,
820         TS, ClassS, *this, Guard));
821 
822     // Also generate the short-form (e.g. svadd_m) for the given type-spec.
823     if (Intrinsic::isOverloadedIntrinsic(Name))
824       Out.push_back(std::make_unique<Intrinsic>(
825           Name, Proto, Merge, MergeSuffix, MemEltType, LLVMName, Flags,
826           ImmChecks, TS, ClassG, *this, Guard));
827   }
828 }
829 
830 void SVEEmitter::createHeader(raw_ostream &OS) {
831   OS << "/*===---- arm_sve.h - ARM SVE intrinsics "
832         "-----------------------------------===\n"
833         " *\n"
834         " *\n"
835         " * Part of the LLVM Project, under the Apache License v2.0 with LLVM "
836         "Exceptions.\n"
837         " * See https://llvm.org/LICENSE.txt for license information.\n"
838         " * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n"
839         " *\n"
840         " *===-----------------------------------------------------------------"
841         "------===\n"
842         " */\n\n";
843 
844   OS << "#ifndef __ARM_SVE_H\n";
845   OS << "#define __ARM_SVE_H\n\n";
846 
847   OS << "#if !defined(__ARM_FEATURE_SVE)\n";
848   OS << "#error \"SVE support not enabled\"\n";
849   OS << "#else\n\n";
850 
851   OS << "#include <stdint.h>\n\n";
852   OS << "#ifdef  __cplusplus\n";
853   OS << "extern \"C\" {\n";
854   OS << "#else\n";
855   OS << "#include <stdbool.h>\n";
856   OS << "#endif\n\n";
857 
858   OS << "typedef __fp16 float16_t;\n";
859   OS << "typedef float float32_t;\n";
860   OS << "typedef double float64_t;\n";
861   OS << "typedef bool bool_t;\n\n";
862 
863   OS << "typedef __SVInt8_t svint8_t;\n";
864   OS << "typedef __SVInt16_t svint16_t;\n";
865   OS << "typedef __SVInt32_t svint32_t;\n";
866   OS << "typedef __SVInt64_t svint64_t;\n";
867   OS << "typedef __SVUint8_t svuint8_t;\n";
868   OS << "typedef __SVUint16_t svuint16_t;\n";
869   OS << "typedef __SVUint32_t svuint32_t;\n";
870   OS << "typedef __SVUint64_t svuint64_t;\n";
871   OS << "typedef __SVFloat16_t svfloat16_t;\n";
872   OS << "typedef __SVFloat32_t svfloat32_t;\n";
873   OS << "typedef __SVFloat64_t svfloat64_t;\n";
874   OS << "typedef __SVBool_t  svbool_t;\n\n";
875 
876   OS << "typedef enum\n";
877   OS << "{\n";
878   OS << "  SV_POW2 = 0,\n";
879   OS << "  SV_VL1 = 1,\n";
880   OS << "  SV_VL2 = 2,\n";
881   OS << "  SV_VL3 = 3,\n";
882   OS << "  SV_VL4 = 4,\n";
883   OS << "  SV_VL5 = 5,\n";
884   OS << "  SV_VL6 = 6,\n";
885   OS << "  SV_VL7 = 7,\n";
886   OS << "  SV_VL8 = 8,\n";
887   OS << "  SV_VL16 = 9,\n";
888   OS << "  SV_VL32 = 10,\n";
889   OS << "  SV_VL64 = 11,\n";
890   OS << "  SV_VL128 = 12,\n";
891   OS << "  SV_VL256 = 13,\n";
892   OS << "  SV_MUL4 = 29,\n";
893   OS << "  SV_MUL3 = 30,\n";
894   OS << "  SV_ALL = 31\n";
895   OS << "} sv_pattern;\n\n";
896 
897   OS << "/* Function attributes */\n";
898   OS << "#define __aio static inline __attribute__((__always_inline__, "
899         "__nodebug__, __overloadable__))\n\n";
900 
901   SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
902   std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
903   for (auto *R : RV)
904     createIntrinsic(R, Defs);
905 
906   // Sort intrinsics in header file by following order/priority:
907   // - Architectural guard (i.e. does it require SVE2 or SVE2_AES)
908   // - Class (is intrinsic overloaded or not)
909   // - Intrinsic name
910   std::stable_sort(
911       Defs.begin(), Defs.end(), [](const std::unique_ptr<Intrinsic> &A,
912                                    const std::unique_ptr<Intrinsic> &B) {
913         auto ToTuple = [](const std::unique_ptr<Intrinsic> &I) {
914           return std::make_tuple(I->getGuard(), (unsigned)I->getClassKind(), I->getName());
915         };
916         return ToTuple(A) < ToTuple(B);
917       });
918 
919   StringRef InGuard = "";
920   for (auto &I : Defs) {
921     // Emit #endif/#if pair if needed.
922     if (I->getGuard() != InGuard) {
923       if (!InGuard.empty())
924         OS << "#endif  //" << InGuard << "\n";
925       InGuard = I->getGuard();
926       if (!InGuard.empty())
927         OS << "\n#if " << InGuard << "\n";
928     }
929 
930     // Actually emit the intrinsic declaration.
931     I->emitIntrinsic(OS);
932   }
933 
934   if (!InGuard.empty())
935     OS << "#endif  //" << InGuard << "\n";
936 
937   OS << "#ifdef __cplusplus\n";
938   OS << "} // extern \"C\"\n";
939   OS << "#endif\n\n";
940   OS << "#endif /*__ARM_FEATURE_SVE */\n\n";
941   OS << "#endif /* __ARM_SVE_H */\n";
942 }
943 
944 void SVEEmitter::createBuiltins(raw_ostream &OS) {
945   std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
946   SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
947   for (auto *R : RV)
948     createIntrinsic(R, Defs);
949 
950   // The mappings must be sorted based on BuiltinID.
951   llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A,
952                       const std::unique_ptr<Intrinsic> &B) {
953     return A->getMangledName() < B->getMangledName();
954   });
955 
956   OS << "#ifdef GET_SVE_BUILTINS\n";
957   for (auto &Def : Defs) {
958     // Only create BUILTINs for non-overloaded intrinsics, as overloaded
959     // declarations only live in the header file.
960     if (Def->getClassKind() != ClassG)
961       OS << "BUILTIN(__builtin_sve_" << Def->getMangledName() << ", \""
962          << Def->getBuiltinTypeStr() << "\", \"n\")\n";
963   }
964   OS << "#endif\n\n";
965 }
966 
967 void SVEEmitter::createCodeGenMap(raw_ostream &OS) {
968   std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
969   SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
970   for (auto *R : RV)
971     createIntrinsic(R, Defs);
972 
973   // The mappings must be sorted based on BuiltinID.
974   llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A,
975                       const std::unique_ptr<Intrinsic> &B) {
976     return A->getMangledName() < B->getMangledName();
977   });
978 
979   OS << "#ifdef GET_SVE_LLVM_INTRINSIC_MAP\n";
980   for (auto &Def : Defs) {
981     // Builtins only exist for non-overloaded intrinsics, overloaded
982     // declarations only live in the header file.
983     if (Def->getClassKind() == ClassG)
984       continue;
985 
986     uint64_t Flags = Def->getFlags();
987     auto FlagString = std::to_string(Flags);
988 
989     std::string LLVMName = Def->getLLVMName();
990     std::string Builtin = Def->getMangledName();
991     if (!LLVMName.empty())
992       OS << "SVEMAP1(" << Builtin << ", " << LLVMName << ", " << FlagString
993          << "),\n";
994     else
995       OS << "SVEMAP2(" << Builtin << ", " << FlagString << "),\n";
996   }
997   OS << "#endif\n\n";
998 }
999 
1000 void SVEEmitter::createRangeChecks(raw_ostream &OS) {
1001   std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
1002   SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
1003   for (auto *R : RV)
1004     createIntrinsic(R, Defs);
1005 
1006   // The mappings must be sorted based on BuiltinID.
1007   llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A,
1008                       const std::unique_ptr<Intrinsic> &B) {
1009     return A->getMangledName() < B->getMangledName();
1010   });
1011 
1012 
1013   OS << "#ifdef GET_SVE_IMMEDIATE_CHECK\n";
1014 
1015   // Ensure these are only emitted once.
1016   std::set<std::string> Emitted;
1017 
1018   for (auto &Def : Defs) {
1019     if (Emitted.find(Def->getMangledName()) != Emitted.end() ||
1020         Def->getImmChecks().empty())
1021       continue;
1022 
1023     OS << "case SVE::BI__builtin_sve_" << Def->getMangledName() << ":\n";
1024     for (auto &Check : Def->getImmChecks())
1025       OS << "ImmChecks.push_back(std::make_tuple(" << Check.getArg() << ", "
1026          << Check.getKind() << ", " << Check.getElementSizeInBits() << "));\n";
1027     OS << "  break;\n";
1028 
1029     Emitted.insert(Def->getMangledName());
1030   }
1031 
1032   OS << "#endif\n\n";
1033 }
1034 
1035 /// Create the SVETypeFlags used in CGBuiltins
1036 void SVEEmitter::createTypeFlags(raw_ostream &OS) {
1037   OS << "#ifdef LLVM_GET_SVE_TYPEFLAGS\n";
1038   for (auto &KV : FlagTypes)
1039     OS << "const uint64_t " << KV.getKey() << " = " << KV.getValue() << ";\n";
1040   OS << "#endif\n\n";
1041 
1042   OS << "#ifdef LLVM_GET_SVE_ELTTYPES\n";
1043   for (auto &KV : EltTypes)
1044     OS << "  " << KV.getKey() << " = " << KV.getValue() << ",\n";
1045   OS << "#endif\n\n";
1046 
1047   OS << "#ifdef LLVM_GET_SVE_MEMELTTYPES\n";
1048   for (auto &KV : MemEltTypes)
1049     OS << "  " << KV.getKey() << " = " << KV.getValue() << ",\n";
1050   OS << "#endif\n\n";
1051 
1052   OS << "#ifdef LLVM_GET_SVE_MERGETYPES\n";
1053   for (auto &KV : MergeTypes)
1054     OS << "  " << KV.getKey() << " = " << KV.getValue() << ",\n";
1055   OS << "#endif\n\n";
1056 
1057   OS << "#ifdef LLVM_GET_SVE_IMMCHECKTYPES\n";
1058   for (auto &KV : ImmCheckTypes)
1059     OS << "  " << KV.getKey() << " = " << KV.getValue() << ",\n";
1060   OS << "#endif\n\n";
1061 }
1062 
1063 namespace clang {
1064 void EmitSveHeader(RecordKeeper &Records, raw_ostream &OS) {
1065   SVEEmitter(Records).createHeader(OS);
1066 }
1067 
1068 void EmitSveBuiltins(RecordKeeper &Records, raw_ostream &OS) {
1069   SVEEmitter(Records).createBuiltins(OS);
1070 }
1071 
1072 void EmitSveBuiltinCG(RecordKeeper &Records, raw_ostream &OS) {
1073   SVEEmitter(Records).createCodeGenMap(OS);
1074 }
1075 
1076 void EmitSveRangeChecks(RecordKeeper &Records, raw_ostream &OS) {
1077   SVEEmitter(Records).createRangeChecks(OS);
1078 }
1079 
1080 void EmitSveTypeFlags(RecordKeeper &Records, raw_ostream &OS) {
1081   SVEEmitter(Records).createTypeFlags(OS);
1082 }
1083 
1084 } // End namespace clang
1085