xref: /openbsd-src/gnu/llvm/clang/utils/TableGen/SveEmitter.cpp (revision 12c855180aad702bbcca06e0398d774beeafb155)
1ec727ea7Spatrick //===- SveEmitter.cpp - Generate arm_sve.h for use with clang -*- C++ -*-===//
2ec727ea7Spatrick //
3ec727ea7Spatrick //  Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4ec727ea7Spatrick //  See https://llvm.org/LICENSE.txt for license information.
5ec727ea7Spatrick //  SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6ec727ea7Spatrick //
7ec727ea7Spatrick //===----------------------------------------------------------------------===//
8ec727ea7Spatrick //
9ec727ea7Spatrick // This tablegen backend is responsible for emitting arm_sve.h, which includes
10ec727ea7Spatrick // a declaration and definition of each function specified by the ARM C/C++
11ec727ea7Spatrick // Language Extensions (ACLE).
12ec727ea7Spatrick //
13ec727ea7Spatrick // For details, visit:
14ec727ea7Spatrick //  https://developer.arm.com/architectures/system-architectures/software-standards/acle
15ec727ea7Spatrick //
16ec727ea7Spatrick // Each SVE instruction is implemented in terms of 1 or more functions which
17ec727ea7Spatrick // are suffixed with the element type of the input vectors.  Functions may be
18ec727ea7Spatrick // implemented in terms of generic vector operations such as +, *, -, etc. or
19ec727ea7Spatrick // by calling a __builtin_-prefixed function which will be handled by clang's
20ec727ea7Spatrick // CodeGen library.
21ec727ea7Spatrick //
22ec727ea7Spatrick // See also the documentation in include/clang/Basic/arm_sve.td.
23ec727ea7Spatrick //
24ec727ea7Spatrick //===----------------------------------------------------------------------===//
25ec727ea7Spatrick 
26ec727ea7Spatrick #include "llvm/ADT/STLExtras.h"
27ec727ea7Spatrick #include "llvm/ADT/StringMap.h"
28ec727ea7Spatrick #include "llvm/ADT/ArrayRef.h"
29ec727ea7Spatrick #include "llvm/ADT/StringExtras.h"
30ec727ea7Spatrick #include "llvm/TableGen/Record.h"
31ec727ea7Spatrick #include "llvm/TableGen/Error.h"
32ec727ea7Spatrick #include <string>
33ec727ea7Spatrick #include <sstream>
34ec727ea7Spatrick #include <set>
35ec727ea7Spatrick #include <cctype>
36ec727ea7Spatrick #include <tuple>
37ec727ea7Spatrick 
38ec727ea7Spatrick using namespace llvm;
39ec727ea7Spatrick 
40ec727ea7Spatrick enum ClassKind {
41ec727ea7Spatrick   ClassNone,
42ec727ea7Spatrick   ClassS,     // signed/unsigned, e.g., "_s8", "_u8" suffix
43ec727ea7Spatrick   ClassG,     // Overloaded name without type suffix
44ec727ea7Spatrick };
45ec727ea7Spatrick 
46ec727ea7Spatrick using TypeSpec = std::string;
47ec727ea7Spatrick 
48ec727ea7Spatrick namespace {
49ec727ea7Spatrick 
50ec727ea7Spatrick class ImmCheck {
51ec727ea7Spatrick   unsigned Arg;
52ec727ea7Spatrick   unsigned Kind;
53ec727ea7Spatrick   unsigned ElementSizeInBits;
54ec727ea7Spatrick 
55ec727ea7Spatrick public:
ImmCheck(unsigned Arg,unsigned Kind,unsigned ElementSizeInBits=0)56ec727ea7Spatrick   ImmCheck(unsigned Arg, unsigned Kind, unsigned ElementSizeInBits = 0)
57ec727ea7Spatrick       : Arg(Arg), Kind(Kind), ElementSizeInBits(ElementSizeInBits) {}
58ec727ea7Spatrick   ImmCheck(const ImmCheck &Other) = default;
59ec727ea7Spatrick   ~ImmCheck() = default;
60ec727ea7Spatrick 
getArg() const61ec727ea7Spatrick   unsigned getArg() const { return Arg; }
getKind() const62ec727ea7Spatrick   unsigned getKind() const { return Kind; }
getElementSizeInBits() const63ec727ea7Spatrick   unsigned getElementSizeInBits() const { return ElementSizeInBits; }
64ec727ea7Spatrick };
65ec727ea7Spatrick 
66ec727ea7Spatrick class SVEType {
67ec727ea7Spatrick   TypeSpec TS;
68ec727ea7Spatrick   bool Float, Signed, Immediate, Void, Constant, Pointer, BFloat;
69ec727ea7Spatrick   bool DefaultType, IsScalable, Predicate, PredicatePattern, PrefetchOp;
70ec727ea7Spatrick   unsigned Bitwidth, ElementBitwidth, NumVectors;
71ec727ea7Spatrick 
72ec727ea7Spatrick public:
SVEType()73ec727ea7Spatrick   SVEType() : SVEType(TypeSpec(), 'v') {}
74ec727ea7Spatrick 
SVEType(TypeSpec TS,char CharMod)75ec727ea7Spatrick   SVEType(TypeSpec TS, char CharMod)
76ec727ea7Spatrick       : TS(TS), Float(false), Signed(true), Immediate(false), Void(false),
77ec727ea7Spatrick         Constant(false), Pointer(false), BFloat(false), DefaultType(false),
78ec727ea7Spatrick         IsScalable(true), Predicate(false), PredicatePattern(false),
79ec727ea7Spatrick         PrefetchOp(false), Bitwidth(128), ElementBitwidth(~0U), NumVectors(1) {
80ec727ea7Spatrick     if (!TS.empty())
81ec727ea7Spatrick       applyTypespec();
82ec727ea7Spatrick     applyModifier(CharMod);
83ec727ea7Spatrick   }
84ec727ea7Spatrick 
isPointer() const85ec727ea7Spatrick   bool isPointer() const { return Pointer; }
isVoidPointer() const86ec727ea7Spatrick   bool isVoidPointer() const { return Pointer && Void; }
isSigned() const87ec727ea7Spatrick   bool isSigned() const { return Signed; }
isImmediate() const88ec727ea7Spatrick   bool isImmediate() const { return Immediate; }
isScalar() const89ec727ea7Spatrick   bool isScalar() const { return NumVectors == 0; }
isVector() const90ec727ea7Spatrick   bool isVector() const { return NumVectors > 0; }
isScalableVector() const91ec727ea7Spatrick   bool isScalableVector() const { return isVector() && IsScalable; }
isChar() const92ec727ea7Spatrick   bool isChar() const { return ElementBitwidth == 8; }
isVoid() const93ec727ea7Spatrick   bool isVoid() const { return Void & !Pointer; }
isDefault() const94ec727ea7Spatrick   bool isDefault() const { return DefaultType; }
isFloat() const95ec727ea7Spatrick   bool isFloat() const { return Float && !BFloat; }
isBFloat() const96ec727ea7Spatrick   bool isBFloat() const { return BFloat && !Float; }
isFloatingPoint() const97ec727ea7Spatrick   bool isFloatingPoint() const { return Float || BFloat; }
isInteger() const98ec727ea7Spatrick   bool isInteger() const { return !isFloatingPoint() && !Predicate; }
isScalarPredicate() const99ec727ea7Spatrick   bool isScalarPredicate() const {
100ec727ea7Spatrick     return !isFloatingPoint() && Predicate && NumVectors == 0;
101ec727ea7Spatrick   }
isPredicateVector() const102ec727ea7Spatrick   bool isPredicateVector() const { return Predicate; }
isPredicatePattern() const103ec727ea7Spatrick   bool isPredicatePattern() const { return PredicatePattern; }
isPrefetchOp() const104ec727ea7Spatrick   bool isPrefetchOp() const { return PrefetchOp; }
isConstant() const105ec727ea7Spatrick   bool isConstant() const { return Constant; }
getElementSizeInBits() const106ec727ea7Spatrick   unsigned getElementSizeInBits() const { return ElementBitwidth; }
getNumVectors() const107ec727ea7Spatrick   unsigned getNumVectors() const { return NumVectors; }
108ec727ea7Spatrick 
getNumElements() const109ec727ea7Spatrick   unsigned getNumElements() const {
110ec727ea7Spatrick     assert(ElementBitwidth != ~0U);
111ec727ea7Spatrick     return Bitwidth / ElementBitwidth;
112ec727ea7Spatrick   }
getSizeInBits() const113ec727ea7Spatrick   unsigned getSizeInBits() const {
114ec727ea7Spatrick     return Bitwidth;
115ec727ea7Spatrick   }
116ec727ea7Spatrick 
117ec727ea7Spatrick   /// Return the string representation of a type, which is an encoded
118ec727ea7Spatrick   /// string for passing to the BUILTIN() macro in Builtins.def.
119ec727ea7Spatrick   std::string builtin_str() const;
120ec727ea7Spatrick 
121ec727ea7Spatrick   /// Return the C/C++ string representation of a type for use in the
122ec727ea7Spatrick   /// arm_sve.h header file.
123ec727ea7Spatrick   std::string str() const;
124ec727ea7Spatrick 
125ec727ea7Spatrick private:
126ec727ea7Spatrick   /// Creates the type based on the typespec string in TS.
127ec727ea7Spatrick   void applyTypespec();
128ec727ea7Spatrick 
129ec727ea7Spatrick   /// Applies a prototype modifier to the type.
130ec727ea7Spatrick   void applyModifier(char Mod);
131ec727ea7Spatrick };
132ec727ea7Spatrick 
133ec727ea7Spatrick 
134ec727ea7Spatrick class SVEEmitter;
135ec727ea7Spatrick 
136ec727ea7Spatrick /// The main grunt class. This represents an instantiation of an intrinsic with
137ec727ea7Spatrick /// a particular typespec and prototype.
138ec727ea7Spatrick class Intrinsic {
139ec727ea7Spatrick   /// The unmangled name.
140ec727ea7Spatrick   std::string Name;
141ec727ea7Spatrick 
142ec727ea7Spatrick   /// The name of the corresponding LLVM IR intrinsic.
143ec727ea7Spatrick   std::string LLVMName;
144ec727ea7Spatrick 
145ec727ea7Spatrick   /// Intrinsic prototype.
146ec727ea7Spatrick   std::string Proto;
147ec727ea7Spatrick 
148ec727ea7Spatrick   /// The base type spec for this intrinsic.
149ec727ea7Spatrick   TypeSpec BaseTypeSpec;
150ec727ea7Spatrick 
151ec727ea7Spatrick   /// The base class kind. Most intrinsics use ClassS, which has full type
152ec727ea7Spatrick   /// info for integers (_s32/_u32), or ClassG which is used for overloaded
153ec727ea7Spatrick   /// intrinsics.
154ec727ea7Spatrick   ClassKind Class;
155ec727ea7Spatrick 
156ec727ea7Spatrick   /// The architectural #ifdef guard.
157ec727ea7Spatrick   std::string Guard;
158ec727ea7Spatrick 
159ec727ea7Spatrick   // The merge suffix such as _m, _x or _z.
160ec727ea7Spatrick   std::string MergeSuffix;
161ec727ea7Spatrick 
162ec727ea7Spatrick   /// The types of return value [0] and parameters [1..].
163ec727ea7Spatrick   std::vector<SVEType> Types;
164ec727ea7Spatrick 
165ec727ea7Spatrick   /// The "base type", which is VarType('d', BaseTypeSpec).
166ec727ea7Spatrick   SVEType BaseType;
167ec727ea7Spatrick 
168ec727ea7Spatrick   uint64_t Flags;
169ec727ea7Spatrick 
170ec727ea7Spatrick   SmallVector<ImmCheck, 2> ImmChecks;
171ec727ea7Spatrick 
172ec727ea7Spatrick public:
173ec727ea7Spatrick   Intrinsic(StringRef Name, StringRef Proto, uint64_t MergeTy,
174ec727ea7Spatrick             StringRef MergeSuffix, uint64_t MemoryElementTy, StringRef LLVMName,
175ec727ea7Spatrick             uint64_t Flags, ArrayRef<ImmCheck> ImmChecks, TypeSpec BT,
176ec727ea7Spatrick             ClassKind Class, SVEEmitter &Emitter, StringRef Guard);
177ec727ea7Spatrick 
178ec727ea7Spatrick   ~Intrinsic()=default;
179ec727ea7Spatrick 
getName() const180ec727ea7Spatrick   std::string getName() const { return Name; }
getLLVMName() const181ec727ea7Spatrick   std::string getLLVMName() const { return LLVMName; }
getProto() const182ec727ea7Spatrick   std::string getProto() const { return Proto; }
getBaseTypeSpec() const183ec727ea7Spatrick   TypeSpec getBaseTypeSpec() const { return BaseTypeSpec; }
getBaseType() const184ec727ea7Spatrick   SVEType getBaseType() const { return BaseType; }
185ec727ea7Spatrick 
getGuard() const186ec727ea7Spatrick   StringRef getGuard() const { return Guard; }
getClassKind() const187ec727ea7Spatrick   ClassKind getClassKind() const { return Class; }
188ec727ea7Spatrick 
getReturnType() const189ec727ea7Spatrick   SVEType getReturnType() const { return Types[0]; }
getTypes() const190ec727ea7Spatrick   ArrayRef<SVEType> getTypes() const { return Types; }
getParamType(unsigned I) const191ec727ea7Spatrick   SVEType getParamType(unsigned I) const { return Types[I + 1]; }
getNumParams() const192ec727ea7Spatrick   unsigned getNumParams() const { return Proto.size() - 1; }
193ec727ea7Spatrick 
getFlags() const194ec727ea7Spatrick   uint64_t getFlags() const { return Flags; }
isFlagSet(uint64_t Flag) const195ec727ea7Spatrick   bool isFlagSet(uint64_t Flag) const { return Flags & Flag;}
196ec727ea7Spatrick 
getImmChecks() const197ec727ea7Spatrick   ArrayRef<ImmCheck> getImmChecks() const { return ImmChecks; }
198ec727ea7Spatrick 
199ec727ea7Spatrick   /// Return the type string for a BUILTIN() macro in Builtins.def.
200ec727ea7Spatrick   std::string getBuiltinTypeStr();
201ec727ea7Spatrick 
202ec727ea7Spatrick   /// Return the name, mangled with type information. The name is mangled for
203ec727ea7Spatrick   /// ClassS, so will add type suffixes such as _u32/_s32.
getMangledName() const204ec727ea7Spatrick   std::string getMangledName() const { return mangleName(ClassS); }
205ec727ea7Spatrick 
206ec727ea7Spatrick   /// Returns true if the intrinsic is overloaded, in that it should also generate
207ec727ea7Spatrick   /// a short form without the type-specifiers, e.g. 'svld1(..)' instead of
208ec727ea7Spatrick   /// 'svld1_u32(..)'.
isOverloadedIntrinsic(StringRef Name)209ec727ea7Spatrick   static bool isOverloadedIntrinsic(StringRef Name) {
210a9ac8606Spatrick     auto BrOpen = Name.find('[');
211ec727ea7Spatrick     auto BrClose = Name.find(']');
212ec727ea7Spatrick     return BrOpen != std::string::npos && BrClose != std::string::npos;
213ec727ea7Spatrick   }
214ec727ea7Spatrick 
215ec727ea7Spatrick   /// Return true if the intrinsic takes a splat operand.
hasSplat() const216ec727ea7Spatrick   bool hasSplat() const {
217ec727ea7Spatrick     // These prototype modifiers are described in arm_sve.td.
218ec727ea7Spatrick     return Proto.find_first_of("ajfrKLR@") != std::string::npos;
219ec727ea7Spatrick   }
220ec727ea7Spatrick 
221ec727ea7Spatrick   /// Return the parameter index of the splat operand.
getSplatIdx() const222ec727ea7Spatrick   unsigned getSplatIdx() const {
223ec727ea7Spatrick     // These prototype modifiers are described in arm_sve.td.
224ec727ea7Spatrick     auto Idx = Proto.find_first_of("ajfrKLR@");
225ec727ea7Spatrick     assert(Idx != std::string::npos && Idx > 0 &&
226ec727ea7Spatrick            "Prototype has no splat operand");
227ec727ea7Spatrick     return Idx - 1;
228ec727ea7Spatrick   }
229ec727ea7Spatrick 
230ec727ea7Spatrick   /// Emits the intrinsic declaration to the ostream.
231ec727ea7Spatrick   void emitIntrinsic(raw_ostream &OS) const;
232ec727ea7Spatrick 
233ec727ea7Spatrick private:
getMergeSuffix() const234ec727ea7Spatrick   std::string getMergeSuffix() const { return MergeSuffix; }
235ec727ea7Spatrick   std::string mangleName(ClassKind LocalCK) const;
236ec727ea7Spatrick   std::string replaceTemplatedArgs(std::string Name, TypeSpec TS,
237ec727ea7Spatrick                                    std::string Proto) const;
238ec727ea7Spatrick };
239ec727ea7Spatrick 
240ec727ea7Spatrick class SVEEmitter {
241ec727ea7Spatrick private:
242ec727ea7Spatrick   // The reinterpret builtins are generated separately because they
243ec727ea7Spatrick   // need the cross product of all types (121 functions in total),
244ec727ea7Spatrick   // which is inconvenient to specify in the arm_sve.td file or
245ec727ea7Spatrick   // generate in CGBuiltin.cpp.
246ec727ea7Spatrick   struct ReinterpretTypeInfo {
247ec727ea7Spatrick     const char *Suffix;
248ec727ea7Spatrick     const char *Type;
249ec727ea7Spatrick     const char *BuiltinType;
250ec727ea7Spatrick   };
251ec727ea7Spatrick   SmallVector<ReinterpretTypeInfo, 12> Reinterprets = {
252ec727ea7Spatrick       {"s8", "svint8_t", "q16Sc"},   {"s16", "svint16_t", "q8Ss"},
253ec727ea7Spatrick       {"s32", "svint32_t", "q4Si"},  {"s64", "svint64_t", "q2SWi"},
254ec727ea7Spatrick       {"u8", "svuint8_t", "q16Uc"},  {"u16", "svuint16_t", "q8Us"},
255ec727ea7Spatrick       {"u32", "svuint32_t", "q4Ui"}, {"u64", "svuint64_t", "q2UWi"},
256ec727ea7Spatrick       {"f16", "svfloat16_t", "q8h"}, {"bf16", "svbfloat16_t", "q8y"},
257ec727ea7Spatrick       {"f32", "svfloat32_t", "q4f"}, {"f64", "svfloat64_t", "q2d"}};
258ec727ea7Spatrick 
259ec727ea7Spatrick   RecordKeeper &Records;
260ec727ea7Spatrick   llvm::StringMap<uint64_t> EltTypes;
261ec727ea7Spatrick   llvm::StringMap<uint64_t> MemEltTypes;
262ec727ea7Spatrick   llvm::StringMap<uint64_t> FlagTypes;
263ec727ea7Spatrick   llvm::StringMap<uint64_t> MergeTypes;
264ec727ea7Spatrick   llvm::StringMap<uint64_t> ImmCheckTypes;
265ec727ea7Spatrick 
266ec727ea7Spatrick public:
SVEEmitter(RecordKeeper & R)267ec727ea7Spatrick   SVEEmitter(RecordKeeper &R) : Records(R) {
268ec727ea7Spatrick     for (auto *RV : Records.getAllDerivedDefinitions("EltType"))
269ec727ea7Spatrick       EltTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");
270ec727ea7Spatrick     for (auto *RV : Records.getAllDerivedDefinitions("MemEltType"))
271ec727ea7Spatrick       MemEltTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");
272ec727ea7Spatrick     for (auto *RV : Records.getAllDerivedDefinitions("FlagType"))
273ec727ea7Spatrick       FlagTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");
274ec727ea7Spatrick     for (auto *RV : Records.getAllDerivedDefinitions("MergeType"))
275ec727ea7Spatrick       MergeTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");
276ec727ea7Spatrick     for (auto *RV : Records.getAllDerivedDefinitions("ImmCheckType"))
277ec727ea7Spatrick       ImmCheckTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");
278ec727ea7Spatrick   }
279ec727ea7Spatrick 
280ec727ea7Spatrick   /// Returns the enum value for the immcheck type
getEnumValueForImmCheck(StringRef C) const281ec727ea7Spatrick   unsigned getEnumValueForImmCheck(StringRef C) const {
282ec727ea7Spatrick     auto It = ImmCheckTypes.find(C);
283ec727ea7Spatrick     if (It != ImmCheckTypes.end())
284ec727ea7Spatrick       return It->getValue();
285ec727ea7Spatrick     llvm_unreachable("Unsupported imm check");
286ec727ea7Spatrick   }
287ec727ea7Spatrick 
288ec727ea7Spatrick   /// Returns the enum value for the flag type
getEnumValueForFlag(StringRef C) const289ec727ea7Spatrick   uint64_t getEnumValueForFlag(StringRef C) const {
290ec727ea7Spatrick     auto Res = FlagTypes.find(C);
291ec727ea7Spatrick     if (Res != FlagTypes.end())
292ec727ea7Spatrick       return Res->getValue();
293ec727ea7Spatrick     llvm_unreachable("Unsupported flag");
294ec727ea7Spatrick   }
295ec727ea7Spatrick 
296ec727ea7Spatrick   // Returns the SVETypeFlags for a given value and mask.
encodeFlag(uint64_t V,StringRef MaskName) const297ec727ea7Spatrick   uint64_t encodeFlag(uint64_t V, StringRef MaskName) const {
298ec727ea7Spatrick     auto It = FlagTypes.find(MaskName);
299ec727ea7Spatrick     if (It != FlagTypes.end()) {
300ec727ea7Spatrick       uint64_t Mask = It->getValue();
301ec727ea7Spatrick       unsigned Shift = llvm::countTrailingZeros(Mask);
302ec727ea7Spatrick       return (V << Shift) & Mask;
303ec727ea7Spatrick     }
304ec727ea7Spatrick     llvm_unreachable("Unsupported flag");
305ec727ea7Spatrick   }
306ec727ea7Spatrick 
307ec727ea7Spatrick   // Returns the SVETypeFlags for the given element type.
encodeEltType(StringRef EltName)308ec727ea7Spatrick   uint64_t encodeEltType(StringRef EltName) {
309ec727ea7Spatrick     auto It = EltTypes.find(EltName);
310ec727ea7Spatrick     if (It != EltTypes.end())
311ec727ea7Spatrick       return encodeFlag(It->getValue(), "EltTypeMask");
312ec727ea7Spatrick     llvm_unreachable("Unsupported EltType");
313ec727ea7Spatrick   }
314ec727ea7Spatrick 
315ec727ea7Spatrick   // Returns the SVETypeFlags for the given memory element type.
encodeMemoryElementType(uint64_t MT)316ec727ea7Spatrick   uint64_t encodeMemoryElementType(uint64_t MT) {
317ec727ea7Spatrick     return encodeFlag(MT, "MemEltTypeMask");
318ec727ea7Spatrick   }
319ec727ea7Spatrick 
320ec727ea7Spatrick   // Returns the SVETypeFlags for the given merge type.
encodeMergeType(uint64_t MT)321ec727ea7Spatrick   uint64_t encodeMergeType(uint64_t MT) {
322ec727ea7Spatrick     return encodeFlag(MT, "MergeTypeMask");
323ec727ea7Spatrick   }
324ec727ea7Spatrick 
325ec727ea7Spatrick   // Returns the SVETypeFlags for the given splat operand.
encodeSplatOperand(unsigned SplatIdx)326ec727ea7Spatrick   unsigned encodeSplatOperand(unsigned SplatIdx) {
327ec727ea7Spatrick     assert(SplatIdx < 7 && "SplatIdx out of encodable range");
328ec727ea7Spatrick     return encodeFlag(SplatIdx + 1, "SplatOperandMask");
329ec727ea7Spatrick   }
330ec727ea7Spatrick 
331ec727ea7Spatrick   // Returns the SVETypeFlags value for the given SVEType.
332ec727ea7Spatrick   uint64_t encodeTypeFlags(const SVEType &T);
333ec727ea7Spatrick 
334ec727ea7Spatrick   /// Emit arm_sve.h.
335ec727ea7Spatrick   void createHeader(raw_ostream &o);
336ec727ea7Spatrick 
337ec727ea7Spatrick   /// Emit all the __builtin prototypes and code needed by Sema.
338ec727ea7Spatrick   void createBuiltins(raw_ostream &o);
339ec727ea7Spatrick 
340ec727ea7Spatrick   /// Emit all the information needed to map builtin -> LLVM IR intrinsic.
341ec727ea7Spatrick   void createCodeGenMap(raw_ostream &o);
342ec727ea7Spatrick 
343ec727ea7Spatrick   /// Emit all the range checks for the immediates.
344ec727ea7Spatrick   void createRangeChecks(raw_ostream &o);
345ec727ea7Spatrick 
346ec727ea7Spatrick   /// Create the SVETypeFlags used in CGBuiltins
347ec727ea7Spatrick   void createTypeFlags(raw_ostream &o);
348ec727ea7Spatrick 
349ec727ea7Spatrick   /// Create intrinsic and add it to \p Out
350ec727ea7Spatrick   void createIntrinsic(Record *R, SmallVectorImpl<std::unique_ptr<Intrinsic>> &Out);
351ec727ea7Spatrick };
352ec727ea7Spatrick 
353ec727ea7Spatrick } // end anonymous namespace
354ec727ea7Spatrick 
355ec727ea7Spatrick 
356ec727ea7Spatrick //===----------------------------------------------------------------------===//
357ec727ea7Spatrick // Type implementation
358ec727ea7Spatrick //===----------------------------------------------------------------------===//
359ec727ea7Spatrick 
builtin_str() const360ec727ea7Spatrick std::string SVEType::builtin_str() const {
361ec727ea7Spatrick   std::string S;
362ec727ea7Spatrick   if (isVoid())
363ec727ea7Spatrick     return "v";
364ec727ea7Spatrick 
365a9ac8606Spatrick   if (isScalarPredicate())
366a9ac8606Spatrick     return "b";
367a9ac8606Spatrick 
368ec727ea7Spatrick   if (isVoidPointer())
369ec727ea7Spatrick     S += "v";
370ec727ea7Spatrick   else if (!isFloatingPoint())
371ec727ea7Spatrick     switch (ElementBitwidth) {
372ec727ea7Spatrick     case 1: S += "b"; break;
373ec727ea7Spatrick     case 8: S += "c"; break;
374ec727ea7Spatrick     case 16: S += "s"; break;
375ec727ea7Spatrick     case 32: S += "i"; break;
376ec727ea7Spatrick     case 64: S += "Wi"; break;
377ec727ea7Spatrick     case 128: S += "LLLi"; break;
378ec727ea7Spatrick     default: llvm_unreachable("Unhandled case!");
379ec727ea7Spatrick     }
380ec727ea7Spatrick   else if (isFloat())
381ec727ea7Spatrick     switch (ElementBitwidth) {
382ec727ea7Spatrick     case 16: S += "h"; break;
383ec727ea7Spatrick     case 32: S += "f"; break;
384ec727ea7Spatrick     case 64: S += "d"; break;
385ec727ea7Spatrick     default: llvm_unreachable("Unhandled case!");
386ec727ea7Spatrick     }
387ec727ea7Spatrick   else if (isBFloat()) {
388ec727ea7Spatrick     assert(ElementBitwidth == 16 && "Not a valid BFloat.");
389ec727ea7Spatrick     S += "y";
390ec727ea7Spatrick   }
391ec727ea7Spatrick 
392ec727ea7Spatrick   if (!isFloatingPoint()) {
393ec727ea7Spatrick     if ((isChar() || isPointer()) && !isVoidPointer()) {
394ec727ea7Spatrick       // Make chars and typed pointers explicitly signed.
395ec727ea7Spatrick       if (Signed)
396ec727ea7Spatrick         S = "S" + S;
397ec727ea7Spatrick       else if (!Signed)
398ec727ea7Spatrick         S = "U" + S;
399ec727ea7Spatrick     } else if (!isVoidPointer() && !Signed) {
400ec727ea7Spatrick       S = "U" + S;
401ec727ea7Spatrick     }
402ec727ea7Spatrick   }
403ec727ea7Spatrick 
404ec727ea7Spatrick   // Constant indices are "int", but have the "constant expression" modifier.
405ec727ea7Spatrick   if (isImmediate()) {
406ec727ea7Spatrick     assert(!isFloat() && "fp immediates are not supported");
407ec727ea7Spatrick     S = "I" + S;
408ec727ea7Spatrick   }
409ec727ea7Spatrick 
410ec727ea7Spatrick   if (isScalar()) {
411ec727ea7Spatrick     if (Constant) S += "C";
412ec727ea7Spatrick     if (Pointer) S += "*";
413ec727ea7Spatrick     return S;
414ec727ea7Spatrick   }
415ec727ea7Spatrick 
416ec727ea7Spatrick   assert(isScalableVector() && "Unsupported type");
417ec727ea7Spatrick   return "q" + utostr(getNumElements() * NumVectors) + S;
418ec727ea7Spatrick }
419ec727ea7Spatrick 
str() const420ec727ea7Spatrick std::string SVEType::str() const {
421ec727ea7Spatrick   if (isPredicatePattern())
422a9ac8606Spatrick     return "enum svpattern";
423ec727ea7Spatrick 
424ec727ea7Spatrick   if (isPrefetchOp())
425a9ac8606Spatrick     return "enum svprfop";
426ec727ea7Spatrick 
427ec727ea7Spatrick   std::string S;
428ec727ea7Spatrick   if (Void)
429ec727ea7Spatrick     S += "void";
430ec727ea7Spatrick   else {
431ec727ea7Spatrick     if (isScalableVector())
432ec727ea7Spatrick       S += "sv";
433ec727ea7Spatrick     if (!Signed && !isFloatingPoint())
434ec727ea7Spatrick       S += "u";
435ec727ea7Spatrick 
436ec727ea7Spatrick     if (Float)
437ec727ea7Spatrick       S += "float";
438ec727ea7Spatrick     else if (isScalarPredicate() || isPredicateVector())
439ec727ea7Spatrick       S += "bool";
440ec727ea7Spatrick     else if (isBFloat())
441ec727ea7Spatrick       S += "bfloat";
442ec727ea7Spatrick     else
443ec727ea7Spatrick       S += "int";
444ec727ea7Spatrick 
445ec727ea7Spatrick     if (!isScalarPredicate() && !isPredicateVector())
446ec727ea7Spatrick       S += utostr(ElementBitwidth);
447ec727ea7Spatrick     if (!isScalableVector() && isVector())
448ec727ea7Spatrick       S += "x" + utostr(getNumElements());
449ec727ea7Spatrick     if (NumVectors > 1)
450ec727ea7Spatrick       S += "x" + utostr(NumVectors);
451ec727ea7Spatrick     if (!isScalarPredicate())
452ec727ea7Spatrick       S += "_t";
453ec727ea7Spatrick   }
454ec727ea7Spatrick 
455ec727ea7Spatrick   if (Constant)
456ec727ea7Spatrick     S += " const";
457ec727ea7Spatrick   if (Pointer)
458ec727ea7Spatrick     S += " *";
459ec727ea7Spatrick 
460ec727ea7Spatrick   return S;
461ec727ea7Spatrick }
applyTypespec()462ec727ea7Spatrick void SVEType::applyTypespec() {
463ec727ea7Spatrick   for (char I : TS) {
464ec727ea7Spatrick     switch (I) {
465ec727ea7Spatrick     case 'P':
466ec727ea7Spatrick       Predicate = true;
467ec727ea7Spatrick       break;
468ec727ea7Spatrick     case 'U':
469ec727ea7Spatrick       Signed = false;
470ec727ea7Spatrick       break;
471ec727ea7Spatrick     case 'c':
472ec727ea7Spatrick       ElementBitwidth = 8;
473ec727ea7Spatrick       break;
474ec727ea7Spatrick     case 's':
475ec727ea7Spatrick       ElementBitwidth = 16;
476ec727ea7Spatrick       break;
477ec727ea7Spatrick     case 'i':
478ec727ea7Spatrick       ElementBitwidth = 32;
479ec727ea7Spatrick       break;
480ec727ea7Spatrick     case 'l':
481ec727ea7Spatrick       ElementBitwidth = 64;
482ec727ea7Spatrick       break;
483ec727ea7Spatrick     case 'h':
484ec727ea7Spatrick       Float = true;
485ec727ea7Spatrick       ElementBitwidth = 16;
486ec727ea7Spatrick       break;
487ec727ea7Spatrick     case 'f':
488ec727ea7Spatrick       Float = true;
489ec727ea7Spatrick       ElementBitwidth = 32;
490ec727ea7Spatrick       break;
491ec727ea7Spatrick     case 'd':
492ec727ea7Spatrick       Float = true;
493ec727ea7Spatrick       ElementBitwidth = 64;
494ec727ea7Spatrick       break;
495ec727ea7Spatrick     case 'b':
496ec727ea7Spatrick       BFloat = true;
497ec727ea7Spatrick       Float = false;
498ec727ea7Spatrick       ElementBitwidth = 16;
499ec727ea7Spatrick       break;
500ec727ea7Spatrick     default:
501ec727ea7Spatrick       llvm_unreachable("Unhandled type code!");
502ec727ea7Spatrick     }
503ec727ea7Spatrick   }
504ec727ea7Spatrick   assert(ElementBitwidth != ~0U && "Bad element bitwidth!");
505ec727ea7Spatrick }
506ec727ea7Spatrick 
applyModifier(char Mod)507ec727ea7Spatrick void SVEType::applyModifier(char Mod) {
508ec727ea7Spatrick   switch (Mod) {
509ec727ea7Spatrick   case '2':
510ec727ea7Spatrick     NumVectors = 2;
511ec727ea7Spatrick     break;
512ec727ea7Spatrick   case '3':
513ec727ea7Spatrick     NumVectors = 3;
514ec727ea7Spatrick     break;
515ec727ea7Spatrick   case '4':
516ec727ea7Spatrick     NumVectors = 4;
517ec727ea7Spatrick     break;
518ec727ea7Spatrick   case 'v':
519ec727ea7Spatrick     Void = true;
520ec727ea7Spatrick     break;
521ec727ea7Spatrick   case 'd':
522ec727ea7Spatrick     DefaultType = true;
523ec727ea7Spatrick     break;
524ec727ea7Spatrick   case 'c':
525ec727ea7Spatrick     Constant = true;
526*12c85518Srobert     [[fallthrough]];
527ec727ea7Spatrick   case 'p':
528ec727ea7Spatrick     Pointer = true;
529ec727ea7Spatrick     Bitwidth = ElementBitwidth;
530ec727ea7Spatrick     NumVectors = 0;
531ec727ea7Spatrick     break;
532ec727ea7Spatrick   case 'e':
533ec727ea7Spatrick     Signed = false;
534ec727ea7Spatrick     ElementBitwidth /= 2;
535ec727ea7Spatrick     break;
536ec727ea7Spatrick   case 'h':
537ec727ea7Spatrick     ElementBitwidth /= 2;
538ec727ea7Spatrick     break;
539ec727ea7Spatrick   case 'q':
540ec727ea7Spatrick     ElementBitwidth /= 4;
541ec727ea7Spatrick     break;
542ec727ea7Spatrick   case 'b':
543ec727ea7Spatrick     Signed = false;
544ec727ea7Spatrick     Float = false;
545ec727ea7Spatrick     BFloat = false;
546ec727ea7Spatrick     ElementBitwidth /= 4;
547ec727ea7Spatrick     break;
548ec727ea7Spatrick   case 'o':
549ec727ea7Spatrick     ElementBitwidth *= 4;
550ec727ea7Spatrick     break;
551ec727ea7Spatrick   case 'P':
552ec727ea7Spatrick     Signed = true;
553ec727ea7Spatrick     Float = false;
554ec727ea7Spatrick     BFloat = false;
555ec727ea7Spatrick     Predicate = true;
556ec727ea7Spatrick     Bitwidth = 16;
557ec727ea7Spatrick     ElementBitwidth = 1;
558ec727ea7Spatrick     break;
559ec727ea7Spatrick   case 's':
560ec727ea7Spatrick   case 'a':
561ec727ea7Spatrick     Bitwidth = ElementBitwidth;
562ec727ea7Spatrick     NumVectors = 0;
563ec727ea7Spatrick     break;
564ec727ea7Spatrick   case 'R':
565ec727ea7Spatrick     ElementBitwidth /= 2;
566ec727ea7Spatrick     NumVectors = 0;
567ec727ea7Spatrick     break;
568ec727ea7Spatrick   case 'r':
569ec727ea7Spatrick     ElementBitwidth /= 4;
570ec727ea7Spatrick     NumVectors = 0;
571ec727ea7Spatrick     break;
572ec727ea7Spatrick   case '@':
573ec727ea7Spatrick     Signed = false;
574ec727ea7Spatrick     Float = false;
575ec727ea7Spatrick     BFloat = false;
576ec727ea7Spatrick     ElementBitwidth /= 4;
577ec727ea7Spatrick     NumVectors = 0;
578ec727ea7Spatrick     break;
579ec727ea7Spatrick   case 'K':
580ec727ea7Spatrick     Signed = true;
581ec727ea7Spatrick     Float = false;
582ec727ea7Spatrick     BFloat = false;
583ec727ea7Spatrick     Bitwidth = ElementBitwidth;
584ec727ea7Spatrick     NumVectors = 0;
585ec727ea7Spatrick     break;
586ec727ea7Spatrick   case 'L':
587ec727ea7Spatrick     Signed = false;
588ec727ea7Spatrick     Float = false;
589ec727ea7Spatrick     BFloat = false;
590ec727ea7Spatrick     Bitwidth = ElementBitwidth;
591ec727ea7Spatrick     NumVectors = 0;
592ec727ea7Spatrick     break;
593ec727ea7Spatrick   case 'u':
594ec727ea7Spatrick     Predicate = false;
595ec727ea7Spatrick     Signed = false;
596ec727ea7Spatrick     Float = false;
597ec727ea7Spatrick     BFloat = false;
598ec727ea7Spatrick     break;
599ec727ea7Spatrick   case 'x':
600ec727ea7Spatrick     Predicate = false;
601ec727ea7Spatrick     Signed = true;
602ec727ea7Spatrick     Float = false;
603ec727ea7Spatrick     BFloat = false;
604ec727ea7Spatrick     break;
605ec727ea7Spatrick   case 'i':
606ec727ea7Spatrick     Predicate = false;
607ec727ea7Spatrick     Float = false;
608ec727ea7Spatrick     BFloat = false;
609ec727ea7Spatrick     ElementBitwidth = Bitwidth = 64;
610ec727ea7Spatrick     NumVectors = 0;
611ec727ea7Spatrick     Signed = false;
612ec727ea7Spatrick     Immediate = true;
613ec727ea7Spatrick     break;
614ec727ea7Spatrick   case 'I':
615ec727ea7Spatrick     Predicate = false;
616ec727ea7Spatrick     Float = false;
617ec727ea7Spatrick     BFloat = false;
618ec727ea7Spatrick     ElementBitwidth = Bitwidth = 32;
619ec727ea7Spatrick     NumVectors = 0;
620ec727ea7Spatrick     Signed = true;
621ec727ea7Spatrick     Immediate = true;
622ec727ea7Spatrick     PredicatePattern = true;
623ec727ea7Spatrick     break;
624ec727ea7Spatrick   case 'J':
625ec727ea7Spatrick     Predicate = false;
626ec727ea7Spatrick     Float = false;
627ec727ea7Spatrick     BFloat = false;
628ec727ea7Spatrick     ElementBitwidth = Bitwidth = 32;
629ec727ea7Spatrick     NumVectors = 0;
630ec727ea7Spatrick     Signed = true;
631ec727ea7Spatrick     Immediate = true;
632ec727ea7Spatrick     PrefetchOp = true;
633ec727ea7Spatrick     break;
634ec727ea7Spatrick   case 'k':
635ec727ea7Spatrick     Predicate = false;
636ec727ea7Spatrick     Signed = true;
637ec727ea7Spatrick     Float = false;
638ec727ea7Spatrick     BFloat = false;
639ec727ea7Spatrick     ElementBitwidth = Bitwidth = 32;
640ec727ea7Spatrick     NumVectors = 0;
641ec727ea7Spatrick     break;
642ec727ea7Spatrick   case 'l':
643ec727ea7Spatrick     Predicate = false;
644ec727ea7Spatrick     Signed = true;
645ec727ea7Spatrick     Float = false;
646ec727ea7Spatrick     BFloat = false;
647ec727ea7Spatrick     ElementBitwidth = Bitwidth = 64;
648ec727ea7Spatrick     NumVectors = 0;
649ec727ea7Spatrick     break;
650ec727ea7Spatrick   case 'm':
651ec727ea7Spatrick     Predicate = false;
652ec727ea7Spatrick     Signed = false;
653ec727ea7Spatrick     Float = false;
654ec727ea7Spatrick     BFloat = false;
655ec727ea7Spatrick     ElementBitwidth = Bitwidth = 32;
656ec727ea7Spatrick     NumVectors = 0;
657ec727ea7Spatrick     break;
658ec727ea7Spatrick   case 'n':
659ec727ea7Spatrick     Predicate = false;
660ec727ea7Spatrick     Signed = false;
661ec727ea7Spatrick     Float = false;
662ec727ea7Spatrick     BFloat = false;
663ec727ea7Spatrick     ElementBitwidth = Bitwidth = 64;
664ec727ea7Spatrick     NumVectors = 0;
665ec727ea7Spatrick     break;
666ec727ea7Spatrick   case 'w':
667ec727ea7Spatrick     ElementBitwidth = 64;
668ec727ea7Spatrick     break;
669ec727ea7Spatrick   case 'j':
670ec727ea7Spatrick     ElementBitwidth = Bitwidth = 64;
671ec727ea7Spatrick     NumVectors = 0;
672ec727ea7Spatrick     break;
673ec727ea7Spatrick   case 'f':
674ec727ea7Spatrick     Signed = false;
675ec727ea7Spatrick     ElementBitwidth = Bitwidth = 64;
676ec727ea7Spatrick     NumVectors = 0;
677ec727ea7Spatrick     break;
678ec727ea7Spatrick   case 'g':
679ec727ea7Spatrick     Signed = false;
680ec727ea7Spatrick     Float = false;
681ec727ea7Spatrick     BFloat = false;
682ec727ea7Spatrick     ElementBitwidth = 64;
683ec727ea7Spatrick     break;
684ec727ea7Spatrick   case 't':
685ec727ea7Spatrick     Signed = true;
686ec727ea7Spatrick     Float = false;
687ec727ea7Spatrick     BFloat = false;
688ec727ea7Spatrick     ElementBitwidth = 32;
689ec727ea7Spatrick     break;
690ec727ea7Spatrick   case 'z':
691ec727ea7Spatrick     Signed = false;
692ec727ea7Spatrick     Float = false;
693ec727ea7Spatrick     BFloat = false;
694ec727ea7Spatrick     ElementBitwidth = 32;
695ec727ea7Spatrick     break;
696ec727ea7Spatrick   case 'O':
697ec727ea7Spatrick     Predicate = false;
698ec727ea7Spatrick     Float = true;
699ec727ea7Spatrick     ElementBitwidth = 16;
700ec727ea7Spatrick     break;
701ec727ea7Spatrick   case 'M':
702ec727ea7Spatrick     Predicate = false;
703ec727ea7Spatrick     Float = true;
704ec727ea7Spatrick     BFloat = false;
705ec727ea7Spatrick     ElementBitwidth = 32;
706ec727ea7Spatrick     break;
707ec727ea7Spatrick   case 'N':
708ec727ea7Spatrick     Predicate = false;
709ec727ea7Spatrick     Float = true;
710ec727ea7Spatrick     ElementBitwidth = 64;
711ec727ea7Spatrick     break;
712ec727ea7Spatrick   case 'Q':
713ec727ea7Spatrick     Constant = true;
714ec727ea7Spatrick     Pointer = true;
715ec727ea7Spatrick     Void = true;
716ec727ea7Spatrick     NumVectors = 0;
717ec727ea7Spatrick     break;
718ec727ea7Spatrick   case 'S':
719ec727ea7Spatrick     Constant = true;
720ec727ea7Spatrick     Pointer = true;
721ec727ea7Spatrick     ElementBitwidth = Bitwidth = 8;
722ec727ea7Spatrick     NumVectors = 0;
723ec727ea7Spatrick     Signed = true;
724ec727ea7Spatrick     break;
725ec727ea7Spatrick   case 'W':
726ec727ea7Spatrick     Constant = true;
727ec727ea7Spatrick     Pointer = true;
728ec727ea7Spatrick     ElementBitwidth = Bitwidth = 8;
729ec727ea7Spatrick     NumVectors = 0;
730ec727ea7Spatrick     Signed = false;
731ec727ea7Spatrick     break;
732ec727ea7Spatrick   case 'T':
733ec727ea7Spatrick     Constant = true;
734ec727ea7Spatrick     Pointer = true;
735ec727ea7Spatrick     ElementBitwidth = Bitwidth = 16;
736ec727ea7Spatrick     NumVectors = 0;
737ec727ea7Spatrick     Signed = true;
738ec727ea7Spatrick     break;
739ec727ea7Spatrick   case 'X':
740ec727ea7Spatrick     Constant = true;
741ec727ea7Spatrick     Pointer = true;
742ec727ea7Spatrick     ElementBitwidth = Bitwidth = 16;
743ec727ea7Spatrick     NumVectors = 0;
744ec727ea7Spatrick     Signed = false;
745ec727ea7Spatrick     break;
746ec727ea7Spatrick   case 'Y':
747ec727ea7Spatrick     Constant = true;
748ec727ea7Spatrick     Pointer = true;
749ec727ea7Spatrick     ElementBitwidth = Bitwidth = 32;
750ec727ea7Spatrick     NumVectors = 0;
751ec727ea7Spatrick     Signed = false;
752ec727ea7Spatrick     break;
753ec727ea7Spatrick   case 'U':
754ec727ea7Spatrick     Constant = true;
755ec727ea7Spatrick     Pointer = true;
756ec727ea7Spatrick     ElementBitwidth = Bitwidth = 32;
757ec727ea7Spatrick     NumVectors = 0;
758ec727ea7Spatrick     Signed = true;
759ec727ea7Spatrick     break;
760ec727ea7Spatrick   case 'A':
761ec727ea7Spatrick     Pointer = true;
762ec727ea7Spatrick     ElementBitwidth = Bitwidth = 8;
763ec727ea7Spatrick     NumVectors = 0;
764ec727ea7Spatrick     Signed = true;
765ec727ea7Spatrick     break;
766ec727ea7Spatrick   case 'B':
767ec727ea7Spatrick     Pointer = true;
768ec727ea7Spatrick     ElementBitwidth = Bitwidth = 16;
769ec727ea7Spatrick     NumVectors = 0;
770ec727ea7Spatrick     Signed = true;
771ec727ea7Spatrick     break;
772ec727ea7Spatrick   case 'C':
773ec727ea7Spatrick     Pointer = true;
774ec727ea7Spatrick     ElementBitwidth = Bitwidth = 32;
775ec727ea7Spatrick     NumVectors = 0;
776ec727ea7Spatrick     Signed = true;
777ec727ea7Spatrick     break;
778ec727ea7Spatrick   case 'D':
779ec727ea7Spatrick     Pointer = true;
780ec727ea7Spatrick     ElementBitwidth = Bitwidth = 64;
781ec727ea7Spatrick     NumVectors = 0;
782ec727ea7Spatrick     Signed = true;
783ec727ea7Spatrick     break;
784ec727ea7Spatrick   case 'E':
785ec727ea7Spatrick     Pointer = true;
786ec727ea7Spatrick     ElementBitwidth = Bitwidth = 8;
787ec727ea7Spatrick     NumVectors = 0;
788ec727ea7Spatrick     Signed = false;
789ec727ea7Spatrick     break;
790ec727ea7Spatrick   case 'F':
791ec727ea7Spatrick     Pointer = true;
792ec727ea7Spatrick     ElementBitwidth = Bitwidth = 16;
793ec727ea7Spatrick     NumVectors = 0;
794ec727ea7Spatrick     Signed = false;
795ec727ea7Spatrick     break;
796ec727ea7Spatrick   case 'G':
797ec727ea7Spatrick     Pointer = true;
798ec727ea7Spatrick     ElementBitwidth = Bitwidth = 32;
799ec727ea7Spatrick     NumVectors = 0;
800ec727ea7Spatrick     Signed = false;
801ec727ea7Spatrick     break;
802ec727ea7Spatrick   default:
803ec727ea7Spatrick     llvm_unreachable("Unhandled character!");
804ec727ea7Spatrick   }
805ec727ea7Spatrick }
806ec727ea7Spatrick 
807ec727ea7Spatrick 
808ec727ea7Spatrick //===----------------------------------------------------------------------===//
809ec727ea7Spatrick // Intrinsic implementation
810ec727ea7Spatrick //===----------------------------------------------------------------------===//
811ec727ea7Spatrick 
Intrinsic(StringRef Name,StringRef Proto,uint64_t MergeTy,StringRef MergeSuffix,uint64_t MemoryElementTy,StringRef LLVMName,uint64_t Flags,ArrayRef<ImmCheck> Checks,TypeSpec BT,ClassKind Class,SVEEmitter & Emitter,StringRef Guard)812ec727ea7Spatrick Intrinsic::Intrinsic(StringRef Name, StringRef Proto, uint64_t MergeTy,
813ec727ea7Spatrick                      StringRef MergeSuffix, uint64_t MemoryElementTy,
814ec727ea7Spatrick                      StringRef LLVMName, uint64_t Flags,
815ec727ea7Spatrick                      ArrayRef<ImmCheck> Checks, TypeSpec BT, ClassKind Class,
816ec727ea7Spatrick                      SVEEmitter &Emitter, StringRef Guard)
817ec727ea7Spatrick     : Name(Name.str()), LLVMName(LLVMName), Proto(Proto.str()),
818ec727ea7Spatrick       BaseTypeSpec(BT), Class(Class), Guard(Guard.str()),
819ec727ea7Spatrick       MergeSuffix(MergeSuffix.str()), BaseType(BT, 'd'), Flags(Flags),
820ec727ea7Spatrick       ImmChecks(Checks.begin(), Checks.end()) {
821ec727ea7Spatrick   // Types[0] is the return value.
822ec727ea7Spatrick   for (unsigned I = 0; I < Proto.size(); ++I) {
823ec727ea7Spatrick     SVEType T(BaseTypeSpec, Proto[I]);
824ec727ea7Spatrick     Types.push_back(T);
825ec727ea7Spatrick 
826ec727ea7Spatrick     // Add range checks for immediates
827ec727ea7Spatrick     if (I > 0) {
828ec727ea7Spatrick       if (T.isPredicatePattern())
829ec727ea7Spatrick         ImmChecks.emplace_back(
830ec727ea7Spatrick             I - 1, Emitter.getEnumValueForImmCheck("ImmCheck0_31"));
831ec727ea7Spatrick       else if (T.isPrefetchOp())
832ec727ea7Spatrick         ImmChecks.emplace_back(
833ec727ea7Spatrick             I - 1, Emitter.getEnumValueForImmCheck("ImmCheck0_13"));
834ec727ea7Spatrick     }
835ec727ea7Spatrick   }
836ec727ea7Spatrick 
837ec727ea7Spatrick   // Set flags based on properties
838ec727ea7Spatrick   this->Flags |= Emitter.encodeTypeFlags(BaseType);
839ec727ea7Spatrick   this->Flags |= Emitter.encodeMemoryElementType(MemoryElementTy);
840ec727ea7Spatrick   this->Flags |= Emitter.encodeMergeType(MergeTy);
841ec727ea7Spatrick   if (hasSplat())
842ec727ea7Spatrick     this->Flags |= Emitter.encodeSplatOperand(getSplatIdx());
843ec727ea7Spatrick }
844ec727ea7Spatrick 
getBuiltinTypeStr()845ec727ea7Spatrick std::string Intrinsic::getBuiltinTypeStr() {
846ec727ea7Spatrick   std::string S = getReturnType().builtin_str();
847ec727ea7Spatrick   for (unsigned I = 0; I < getNumParams(); ++I)
848ec727ea7Spatrick     S += getParamType(I).builtin_str();
849ec727ea7Spatrick 
850ec727ea7Spatrick   return S;
851ec727ea7Spatrick }
852ec727ea7Spatrick 
replaceTemplatedArgs(std::string Name,TypeSpec TS,std::string Proto) const853ec727ea7Spatrick std::string Intrinsic::replaceTemplatedArgs(std::string Name, TypeSpec TS,
854ec727ea7Spatrick                                             std::string Proto) const {
855ec727ea7Spatrick   std::string Ret = Name;
856ec727ea7Spatrick   while (Ret.find('{') != std::string::npos) {
857ec727ea7Spatrick     size_t Pos = Ret.find('{');
858ec727ea7Spatrick     size_t End = Ret.find('}');
859ec727ea7Spatrick     unsigned NumChars = End - Pos + 1;
860ec727ea7Spatrick     assert(NumChars == 3 && "Unexpected template argument");
861ec727ea7Spatrick 
862ec727ea7Spatrick     SVEType T;
863ec727ea7Spatrick     char C = Ret[Pos+1];
864ec727ea7Spatrick     switch(C) {
865ec727ea7Spatrick     default:
866ec727ea7Spatrick       llvm_unreachable("Unknown predication specifier");
867ec727ea7Spatrick     case 'd':
868ec727ea7Spatrick       T = SVEType(TS, 'd');
869ec727ea7Spatrick       break;
870ec727ea7Spatrick     case '0':
871ec727ea7Spatrick     case '1':
872ec727ea7Spatrick     case '2':
873ec727ea7Spatrick     case '3':
874ec727ea7Spatrick       T = SVEType(TS, Proto[C - '0']);
875ec727ea7Spatrick       break;
876ec727ea7Spatrick     }
877ec727ea7Spatrick 
878ec727ea7Spatrick     // Replace templated arg with the right suffix (e.g. u32)
879ec727ea7Spatrick     std::string TypeCode;
880ec727ea7Spatrick     if (T.isInteger())
881ec727ea7Spatrick       TypeCode = T.isSigned() ? 's' : 'u';
882ec727ea7Spatrick     else if (T.isPredicateVector())
883ec727ea7Spatrick       TypeCode = 'b';
884ec727ea7Spatrick     else if (T.isBFloat())
885ec727ea7Spatrick       TypeCode = "bf";
886ec727ea7Spatrick     else
887ec727ea7Spatrick       TypeCode = 'f';
888ec727ea7Spatrick     Ret.replace(Pos, NumChars, TypeCode + utostr(T.getElementSizeInBits()));
889ec727ea7Spatrick   }
890ec727ea7Spatrick 
891ec727ea7Spatrick   return Ret;
892ec727ea7Spatrick }
893ec727ea7Spatrick 
mangleName(ClassKind LocalCK) const894ec727ea7Spatrick std::string Intrinsic::mangleName(ClassKind LocalCK) const {
895ec727ea7Spatrick   std::string S = getName();
896ec727ea7Spatrick 
897ec727ea7Spatrick   if (LocalCK == ClassG) {
898ec727ea7Spatrick     // Remove the square brackets and everything in between.
899a9ac8606Spatrick     while (S.find('[') != std::string::npos) {
900a9ac8606Spatrick       auto Start = S.find('[');
901ec727ea7Spatrick       auto End = S.find(']');
902ec727ea7Spatrick       S.erase(Start, (End-Start)+1);
903ec727ea7Spatrick     }
904ec727ea7Spatrick   } else {
905ec727ea7Spatrick     // Remove the square brackets.
906a9ac8606Spatrick     while (S.find('[') != std::string::npos) {
907ec727ea7Spatrick       auto BrPos = S.find('[');
908ec727ea7Spatrick       if (BrPos != std::string::npos)
909ec727ea7Spatrick         S.erase(BrPos, 1);
910ec727ea7Spatrick       BrPos = S.find(']');
911ec727ea7Spatrick       if (BrPos != std::string::npos)
912ec727ea7Spatrick         S.erase(BrPos, 1);
913ec727ea7Spatrick     }
914ec727ea7Spatrick   }
915ec727ea7Spatrick 
916ec727ea7Spatrick   // Replace all {d} like expressions with e.g. 'u32'
917ec727ea7Spatrick   return replaceTemplatedArgs(S, getBaseTypeSpec(), getProto()) +
918ec727ea7Spatrick          getMergeSuffix();
919ec727ea7Spatrick }
920ec727ea7Spatrick 
emitIntrinsic(raw_ostream & OS) const921ec727ea7Spatrick void Intrinsic::emitIntrinsic(raw_ostream &OS) const {
922a9ac8606Spatrick   bool IsOverloaded = getClassKind() == ClassG && getProto().size() > 1;
923ec727ea7Spatrick 
924a9ac8606Spatrick   std::string FullName = mangleName(ClassS);
925a9ac8606Spatrick   std::string ProtoName = mangleName(getClassKind());
926a9ac8606Spatrick 
927a9ac8606Spatrick   OS << (IsOverloaded ? "__aio " : "__ai ")
928a9ac8606Spatrick      << "__attribute__((__clang_arm_builtin_alias("
929ec727ea7Spatrick      << "__builtin_sve_" << FullName << ")))\n";
930ec727ea7Spatrick 
931ec727ea7Spatrick   OS << getTypes()[0].str() << " " << ProtoName << "(";
932ec727ea7Spatrick   for (unsigned I = 0; I < getTypes().size() - 1; ++I) {
933ec727ea7Spatrick     if (I != 0)
934ec727ea7Spatrick       OS << ", ";
935ec727ea7Spatrick     OS << getTypes()[I + 1].str();
936ec727ea7Spatrick   }
937ec727ea7Spatrick   OS << ");\n";
938ec727ea7Spatrick }
939ec727ea7Spatrick 
940ec727ea7Spatrick //===----------------------------------------------------------------------===//
941ec727ea7Spatrick // SVEEmitter implementation
942ec727ea7Spatrick //===----------------------------------------------------------------------===//
encodeTypeFlags(const SVEType & T)943ec727ea7Spatrick uint64_t SVEEmitter::encodeTypeFlags(const SVEType &T) {
944ec727ea7Spatrick   if (T.isFloat()) {
945ec727ea7Spatrick     switch (T.getElementSizeInBits()) {
946ec727ea7Spatrick     case 16:
947ec727ea7Spatrick       return encodeEltType("EltTyFloat16");
948ec727ea7Spatrick     case 32:
949ec727ea7Spatrick       return encodeEltType("EltTyFloat32");
950ec727ea7Spatrick     case 64:
951ec727ea7Spatrick       return encodeEltType("EltTyFloat64");
952ec727ea7Spatrick     default:
953ec727ea7Spatrick       llvm_unreachable("Unhandled float element bitwidth!");
954ec727ea7Spatrick     }
955ec727ea7Spatrick   }
956ec727ea7Spatrick 
957ec727ea7Spatrick   if (T.isBFloat()) {
958ec727ea7Spatrick     assert(T.getElementSizeInBits() == 16 && "Not a valid BFloat.");
959ec727ea7Spatrick     return encodeEltType("EltTyBFloat16");
960ec727ea7Spatrick   }
961ec727ea7Spatrick 
962ec727ea7Spatrick   if (T.isPredicateVector()) {
963ec727ea7Spatrick     switch (T.getElementSizeInBits()) {
964ec727ea7Spatrick     case 8:
965ec727ea7Spatrick       return encodeEltType("EltTyBool8");
966ec727ea7Spatrick     case 16:
967ec727ea7Spatrick       return encodeEltType("EltTyBool16");
968ec727ea7Spatrick     case 32:
969ec727ea7Spatrick       return encodeEltType("EltTyBool32");
970ec727ea7Spatrick     case 64:
971ec727ea7Spatrick       return encodeEltType("EltTyBool64");
972ec727ea7Spatrick     default:
973ec727ea7Spatrick       llvm_unreachable("Unhandled predicate element bitwidth!");
974ec727ea7Spatrick     }
975ec727ea7Spatrick   }
976ec727ea7Spatrick 
977ec727ea7Spatrick   switch (T.getElementSizeInBits()) {
978ec727ea7Spatrick   case 8:
979ec727ea7Spatrick     return encodeEltType("EltTyInt8");
980ec727ea7Spatrick   case 16:
981ec727ea7Spatrick     return encodeEltType("EltTyInt16");
982ec727ea7Spatrick   case 32:
983ec727ea7Spatrick     return encodeEltType("EltTyInt32");
984ec727ea7Spatrick   case 64:
985ec727ea7Spatrick     return encodeEltType("EltTyInt64");
986ec727ea7Spatrick   default:
987ec727ea7Spatrick     llvm_unreachable("Unhandled integer element bitwidth!");
988ec727ea7Spatrick   }
989ec727ea7Spatrick }
990ec727ea7Spatrick 
createIntrinsic(Record * R,SmallVectorImpl<std::unique_ptr<Intrinsic>> & Out)991ec727ea7Spatrick void SVEEmitter::createIntrinsic(
992ec727ea7Spatrick     Record *R, SmallVectorImpl<std::unique_ptr<Intrinsic>> &Out) {
993ec727ea7Spatrick   StringRef Name = R->getValueAsString("Name");
994ec727ea7Spatrick   StringRef Proto = R->getValueAsString("Prototype");
995ec727ea7Spatrick   StringRef Types = R->getValueAsString("Types");
996*12c85518Srobert   StringRef Guard = R->getValueAsString("TargetGuard");
997ec727ea7Spatrick   StringRef LLVMName = R->getValueAsString("LLVMIntrinsic");
998ec727ea7Spatrick   uint64_t Merge = R->getValueAsInt("Merge");
999ec727ea7Spatrick   StringRef MergeSuffix = R->getValueAsString("MergeSuffix");
1000ec727ea7Spatrick   uint64_t MemEltType = R->getValueAsInt("MemEltType");
1001ec727ea7Spatrick   std::vector<Record*> FlagsList = R->getValueAsListOfDefs("Flags");
1002ec727ea7Spatrick   std::vector<Record*> ImmCheckList = R->getValueAsListOfDefs("ImmChecks");
1003ec727ea7Spatrick 
1004ec727ea7Spatrick   int64_t Flags = 0;
1005ec727ea7Spatrick   for (auto FlagRec : FlagsList)
1006ec727ea7Spatrick     Flags |= FlagRec->getValueAsInt("Value");
1007ec727ea7Spatrick 
1008ec727ea7Spatrick   // Create a dummy TypeSpec for non-overloaded builtins.
1009ec727ea7Spatrick   if (Types.empty()) {
1010ec727ea7Spatrick     assert((Flags & getEnumValueForFlag("IsOverloadNone")) &&
1011ec727ea7Spatrick            "Expect TypeSpec for overloaded builtin!");
1012ec727ea7Spatrick     Types = "i";
1013ec727ea7Spatrick   }
1014ec727ea7Spatrick 
1015ec727ea7Spatrick   // Extract type specs from string
1016ec727ea7Spatrick   SmallVector<TypeSpec, 8> TypeSpecs;
1017ec727ea7Spatrick   TypeSpec Acc;
1018ec727ea7Spatrick   for (char I : Types) {
1019ec727ea7Spatrick     Acc.push_back(I);
1020ec727ea7Spatrick     if (islower(I)) {
1021ec727ea7Spatrick       TypeSpecs.push_back(TypeSpec(Acc));
1022ec727ea7Spatrick       Acc.clear();
1023ec727ea7Spatrick     }
1024ec727ea7Spatrick   }
1025ec727ea7Spatrick 
1026ec727ea7Spatrick   // Remove duplicate type specs.
1027ec727ea7Spatrick   llvm::sort(TypeSpecs);
1028ec727ea7Spatrick   TypeSpecs.erase(std::unique(TypeSpecs.begin(), TypeSpecs.end()),
1029ec727ea7Spatrick                   TypeSpecs.end());
1030ec727ea7Spatrick 
1031ec727ea7Spatrick   // Create an Intrinsic for each type spec.
1032ec727ea7Spatrick   for (auto TS : TypeSpecs) {
1033ec727ea7Spatrick     // Collate a list of range/option checks for the immediates.
1034ec727ea7Spatrick     SmallVector<ImmCheck, 2> ImmChecks;
1035ec727ea7Spatrick     for (auto *R : ImmCheckList) {
1036ec727ea7Spatrick       int64_t Arg = R->getValueAsInt("Arg");
1037ec727ea7Spatrick       int64_t EltSizeArg = R->getValueAsInt("EltSizeArg");
1038ec727ea7Spatrick       int64_t Kind = R->getValueAsDef("Kind")->getValueAsInt("Value");
1039ec727ea7Spatrick       assert(Arg >= 0 && Kind >= 0 && "Arg and Kind must be nonnegative");
1040ec727ea7Spatrick 
1041ec727ea7Spatrick       unsigned ElementSizeInBits = 0;
1042ec727ea7Spatrick       if (EltSizeArg >= 0)
1043ec727ea7Spatrick         ElementSizeInBits =
1044ec727ea7Spatrick             SVEType(TS, Proto[EltSizeArg + /* offset by return arg */ 1])
1045ec727ea7Spatrick                 .getElementSizeInBits();
1046ec727ea7Spatrick       ImmChecks.push_back(ImmCheck(Arg, Kind, ElementSizeInBits));
1047ec727ea7Spatrick     }
1048ec727ea7Spatrick 
1049ec727ea7Spatrick     Out.push_back(std::make_unique<Intrinsic>(
1050ec727ea7Spatrick         Name, Proto, Merge, MergeSuffix, MemEltType, LLVMName, Flags, ImmChecks,
1051ec727ea7Spatrick         TS, ClassS, *this, Guard));
1052ec727ea7Spatrick 
1053ec727ea7Spatrick     // Also generate the short-form (e.g. svadd_m) for the given type-spec.
1054ec727ea7Spatrick     if (Intrinsic::isOverloadedIntrinsic(Name))
1055ec727ea7Spatrick       Out.push_back(std::make_unique<Intrinsic>(
1056ec727ea7Spatrick           Name, Proto, Merge, MergeSuffix, MemEltType, LLVMName, Flags,
1057ec727ea7Spatrick           ImmChecks, TS, ClassG, *this, Guard));
1058ec727ea7Spatrick   }
1059ec727ea7Spatrick }
1060ec727ea7Spatrick 
createHeader(raw_ostream & OS)1061ec727ea7Spatrick void SVEEmitter::createHeader(raw_ostream &OS) {
1062ec727ea7Spatrick   OS << "/*===---- arm_sve.h - ARM SVE intrinsics "
1063ec727ea7Spatrick         "-----------------------------------===\n"
1064ec727ea7Spatrick         " *\n"
1065ec727ea7Spatrick         " *\n"
1066ec727ea7Spatrick         " * Part of the LLVM Project, under the Apache License v2.0 with LLVM "
1067ec727ea7Spatrick         "Exceptions.\n"
1068ec727ea7Spatrick         " * See https://llvm.org/LICENSE.txt for license information.\n"
1069ec727ea7Spatrick         " * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n"
1070ec727ea7Spatrick         " *\n"
1071ec727ea7Spatrick         " *===-----------------------------------------------------------------"
1072ec727ea7Spatrick         "------===\n"
1073ec727ea7Spatrick         " */\n\n";
1074ec727ea7Spatrick 
1075ec727ea7Spatrick   OS << "#ifndef __ARM_SVE_H\n";
1076ec727ea7Spatrick   OS << "#define __ARM_SVE_H\n\n";
1077ec727ea7Spatrick 
1078ec727ea7Spatrick   OS << "#if !defined(__LITTLE_ENDIAN__)\n";
1079ec727ea7Spatrick   OS << "#error \"Big endian is currently not supported for arm_sve.h\"\n";
1080ec727ea7Spatrick   OS << "#endif\n";
1081ec727ea7Spatrick 
1082ec727ea7Spatrick   OS << "#include <stdint.h>\n\n";
1083ec727ea7Spatrick   OS << "#ifdef  __cplusplus\n";
1084ec727ea7Spatrick   OS << "extern \"C\" {\n";
1085ec727ea7Spatrick   OS << "#else\n";
1086ec727ea7Spatrick   OS << "#include <stdbool.h>\n";
1087ec727ea7Spatrick   OS << "#endif\n\n";
1088ec727ea7Spatrick 
1089ec727ea7Spatrick   OS << "typedef __fp16 float16_t;\n";
1090ec727ea7Spatrick   OS << "typedef float float32_t;\n";
1091ec727ea7Spatrick   OS << "typedef double float64_t;\n";
1092ec727ea7Spatrick 
1093ec727ea7Spatrick   OS << "typedef __SVInt8_t svint8_t;\n";
1094ec727ea7Spatrick   OS << "typedef __SVInt16_t svint16_t;\n";
1095ec727ea7Spatrick   OS << "typedef __SVInt32_t svint32_t;\n";
1096ec727ea7Spatrick   OS << "typedef __SVInt64_t svint64_t;\n";
1097ec727ea7Spatrick   OS << "typedef __SVUint8_t svuint8_t;\n";
1098ec727ea7Spatrick   OS << "typedef __SVUint16_t svuint16_t;\n";
1099ec727ea7Spatrick   OS << "typedef __SVUint32_t svuint32_t;\n";
1100ec727ea7Spatrick   OS << "typedef __SVUint64_t svuint64_t;\n";
1101ec727ea7Spatrick   OS << "typedef __SVFloat16_t svfloat16_t;\n\n";
1102ec727ea7Spatrick 
1103ec727ea7Spatrick   OS << "typedef __SVBFloat16_t svbfloat16_t;\n";
1104ec727ea7Spatrick 
1105ec727ea7Spatrick   OS << "#include <arm_bf16.h>\n";
1106ec727ea7Spatrick   OS << "typedef __bf16 bfloat16_t;\n";
1107ec727ea7Spatrick 
1108ec727ea7Spatrick   OS << "typedef __SVFloat32_t svfloat32_t;\n";
1109ec727ea7Spatrick   OS << "typedef __SVFloat64_t svfloat64_t;\n";
1110ec727ea7Spatrick   OS << "typedef __clang_svint8x2_t svint8x2_t;\n";
1111ec727ea7Spatrick   OS << "typedef __clang_svint16x2_t svint16x2_t;\n";
1112ec727ea7Spatrick   OS << "typedef __clang_svint32x2_t svint32x2_t;\n";
1113ec727ea7Spatrick   OS << "typedef __clang_svint64x2_t svint64x2_t;\n";
1114ec727ea7Spatrick   OS << "typedef __clang_svuint8x2_t svuint8x2_t;\n";
1115ec727ea7Spatrick   OS << "typedef __clang_svuint16x2_t svuint16x2_t;\n";
1116ec727ea7Spatrick   OS << "typedef __clang_svuint32x2_t svuint32x2_t;\n";
1117ec727ea7Spatrick   OS << "typedef __clang_svuint64x2_t svuint64x2_t;\n";
1118ec727ea7Spatrick   OS << "typedef __clang_svfloat16x2_t svfloat16x2_t;\n";
1119ec727ea7Spatrick   OS << "typedef __clang_svfloat32x2_t svfloat32x2_t;\n";
1120ec727ea7Spatrick   OS << "typedef __clang_svfloat64x2_t svfloat64x2_t;\n";
1121ec727ea7Spatrick   OS << "typedef __clang_svint8x3_t svint8x3_t;\n";
1122ec727ea7Spatrick   OS << "typedef __clang_svint16x3_t svint16x3_t;\n";
1123ec727ea7Spatrick   OS << "typedef __clang_svint32x3_t svint32x3_t;\n";
1124ec727ea7Spatrick   OS << "typedef __clang_svint64x3_t svint64x3_t;\n";
1125ec727ea7Spatrick   OS << "typedef __clang_svuint8x3_t svuint8x3_t;\n";
1126ec727ea7Spatrick   OS << "typedef __clang_svuint16x3_t svuint16x3_t;\n";
1127ec727ea7Spatrick   OS << "typedef __clang_svuint32x3_t svuint32x3_t;\n";
1128ec727ea7Spatrick   OS << "typedef __clang_svuint64x3_t svuint64x3_t;\n";
1129ec727ea7Spatrick   OS << "typedef __clang_svfloat16x3_t svfloat16x3_t;\n";
1130ec727ea7Spatrick   OS << "typedef __clang_svfloat32x3_t svfloat32x3_t;\n";
1131ec727ea7Spatrick   OS << "typedef __clang_svfloat64x3_t svfloat64x3_t;\n";
1132ec727ea7Spatrick   OS << "typedef __clang_svint8x4_t svint8x4_t;\n";
1133ec727ea7Spatrick   OS << "typedef __clang_svint16x4_t svint16x4_t;\n";
1134ec727ea7Spatrick   OS << "typedef __clang_svint32x4_t svint32x4_t;\n";
1135ec727ea7Spatrick   OS << "typedef __clang_svint64x4_t svint64x4_t;\n";
1136ec727ea7Spatrick   OS << "typedef __clang_svuint8x4_t svuint8x4_t;\n";
1137ec727ea7Spatrick   OS << "typedef __clang_svuint16x4_t svuint16x4_t;\n";
1138ec727ea7Spatrick   OS << "typedef __clang_svuint32x4_t svuint32x4_t;\n";
1139ec727ea7Spatrick   OS << "typedef __clang_svuint64x4_t svuint64x4_t;\n";
1140ec727ea7Spatrick   OS << "typedef __clang_svfloat16x4_t svfloat16x4_t;\n";
1141ec727ea7Spatrick   OS << "typedef __clang_svfloat32x4_t svfloat32x4_t;\n";
1142ec727ea7Spatrick   OS << "typedef __clang_svfloat64x4_t svfloat64x4_t;\n";
1143ec727ea7Spatrick   OS << "typedef __SVBool_t  svbool_t;\n\n";
1144ec727ea7Spatrick 
1145ec727ea7Spatrick   OS << "typedef __clang_svbfloat16x2_t svbfloat16x2_t;\n";
1146ec727ea7Spatrick   OS << "typedef __clang_svbfloat16x3_t svbfloat16x3_t;\n";
1147ec727ea7Spatrick   OS << "typedef __clang_svbfloat16x4_t svbfloat16x4_t;\n";
1148ec727ea7Spatrick 
1149a9ac8606Spatrick   OS << "enum svpattern\n";
1150ec727ea7Spatrick   OS << "{\n";
1151ec727ea7Spatrick   OS << "  SV_POW2 = 0,\n";
1152ec727ea7Spatrick   OS << "  SV_VL1 = 1,\n";
1153ec727ea7Spatrick   OS << "  SV_VL2 = 2,\n";
1154ec727ea7Spatrick   OS << "  SV_VL3 = 3,\n";
1155ec727ea7Spatrick   OS << "  SV_VL4 = 4,\n";
1156ec727ea7Spatrick   OS << "  SV_VL5 = 5,\n";
1157ec727ea7Spatrick   OS << "  SV_VL6 = 6,\n";
1158ec727ea7Spatrick   OS << "  SV_VL7 = 7,\n";
1159ec727ea7Spatrick   OS << "  SV_VL8 = 8,\n";
1160ec727ea7Spatrick   OS << "  SV_VL16 = 9,\n";
1161ec727ea7Spatrick   OS << "  SV_VL32 = 10,\n";
1162ec727ea7Spatrick   OS << "  SV_VL64 = 11,\n";
1163ec727ea7Spatrick   OS << "  SV_VL128 = 12,\n";
1164ec727ea7Spatrick   OS << "  SV_VL256 = 13,\n";
1165ec727ea7Spatrick   OS << "  SV_MUL4 = 29,\n";
1166ec727ea7Spatrick   OS << "  SV_MUL3 = 30,\n";
1167ec727ea7Spatrick   OS << "  SV_ALL = 31\n";
1168a9ac8606Spatrick   OS << "};\n\n";
1169ec727ea7Spatrick 
1170a9ac8606Spatrick   OS << "enum svprfop\n";
1171ec727ea7Spatrick   OS << "{\n";
1172ec727ea7Spatrick   OS << "  SV_PLDL1KEEP = 0,\n";
1173ec727ea7Spatrick   OS << "  SV_PLDL1STRM = 1,\n";
1174ec727ea7Spatrick   OS << "  SV_PLDL2KEEP = 2,\n";
1175ec727ea7Spatrick   OS << "  SV_PLDL2STRM = 3,\n";
1176ec727ea7Spatrick   OS << "  SV_PLDL3KEEP = 4,\n";
1177ec727ea7Spatrick   OS << "  SV_PLDL3STRM = 5,\n";
1178ec727ea7Spatrick   OS << "  SV_PSTL1KEEP = 8,\n";
1179ec727ea7Spatrick   OS << "  SV_PSTL1STRM = 9,\n";
1180ec727ea7Spatrick   OS << "  SV_PSTL2KEEP = 10,\n";
1181ec727ea7Spatrick   OS << "  SV_PSTL2STRM = 11,\n";
1182ec727ea7Spatrick   OS << "  SV_PSTL3KEEP = 12,\n";
1183ec727ea7Spatrick   OS << "  SV_PSTL3STRM = 13\n";
1184a9ac8606Spatrick   OS << "};\n\n";
1185ec727ea7Spatrick 
1186ec727ea7Spatrick   OS << "/* Function attributes */\n";
1187a9ac8606Spatrick   OS << "#define __ai static __inline__ __attribute__((__always_inline__, "
1188a9ac8606Spatrick         "__nodebug__))\n\n";
1189a9ac8606Spatrick   OS << "#define __aio static __inline__ __attribute__((__always_inline__, "
1190ec727ea7Spatrick         "__nodebug__, __overloadable__))\n\n";
1191ec727ea7Spatrick 
1192ec727ea7Spatrick   // Add reinterpret functions.
1193ec727ea7Spatrick   for (auto ShortForm : { false, true } )
1194ec727ea7Spatrick     for (const ReinterpretTypeInfo &From : Reinterprets)
1195ec727ea7Spatrick       for (const ReinterpretTypeInfo &To : Reinterprets) {
1196ec727ea7Spatrick         if (ShortForm) {
1197*12c85518Srobert           OS << "__aio __attribute__((target(\"sve\"))) " << From.Type
1198*12c85518Srobert              << " svreinterpret_" << From.Suffix;
1199ec727ea7Spatrick           OS << "(" << To.Type << " op) {\n";
1200ec727ea7Spatrick           OS << "  return __builtin_sve_reinterpret_" << From.Suffix << "_"
1201ec727ea7Spatrick              << To.Suffix << "(op);\n";
1202ec727ea7Spatrick           OS << "}\n\n";
1203ec727ea7Spatrick         } else
1204ec727ea7Spatrick           OS << "#define svreinterpret_" << From.Suffix << "_" << To.Suffix
1205ec727ea7Spatrick              << "(...) __builtin_sve_reinterpret_" << From.Suffix << "_"
1206ec727ea7Spatrick              << To.Suffix << "(__VA_ARGS__)\n";
1207ec727ea7Spatrick       }
1208ec727ea7Spatrick 
1209ec727ea7Spatrick   SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
1210ec727ea7Spatrick   std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
1211ec727ea7Spatrick   for (auto *R : RV)
1212ec727ea7Spatrick     createIntrinsic(R, Defs);
1213ec727ea7Spatrick 
1214ec727ea7Spatrick   // Sort intrinsics in header file by following order/priority:
1215ec727ea7Spatrick   // - Architectural guard (i.e. does it require SVE2 or SVE2_AES)
1216ec727ea7Spatrick   // - Class (is intrinsic overloaded or not)
1217ec727ea7Spatrick   // - Intrinsic name
1218ec727ea7Spatrick   std::stable_sort(
1219ec727ea7Spatrick       Defs.begin(), Defs.end(), [](const std::unique_ptr<Intrinsic> &A,
1220ec727ea7Spatrick                                    const std::unique_ptr<Intrinsic> &B) {
1221ec727ea7Spatrick         auto ToTuple = [](const std::unique_ptr<Intrinsic> &I) {
1222ec727ea7Spatrick           return std::make_tuple(I->getGuard(), (unsigned)I->getClassKind(), I->getName());
1223ec727ea7Spatrick         };
1224ec727ea7Spatrick         return ToTuple(A) < ToTuple(B);
1225ec727ea7Spatrick       });
1226ec727ea7Spatrick 
1227*12c85518Srobert   // Actually emit the intrinsic declarations.
1228*12c85518Srobert   for (auto &I : Defs)
1229ec727ea7Spatrick     I->emitIntrinsic(OS);
1230ec727ea7Spatrick 
1231ec727ea7Spatrick   OS << "#define svcvtnt_bf16_x      svcvtnt_bf16_m\n";
1232ec727ea7Spatrick   OS << "#define svcvtnt_bf16_f32_x  svcvtnt_bf16_f32_m\n";
1233ec727ea7Spatrick 
1234ec727ea7Spatrick   OS << "#define svcvtnt_f16_x      svcvtnt_f16_m\n";
1235ec727ea7Spatrick   OS << "#define svcvtnt_f16_f32_x  svcvtnt_f16_f32_m\n";
1236ec727ea7Spatrick   OS << "#define svcvtnt_f32_x      svcvtnt_f32_m\n";
1237ec727ea7Spatrick   OS << "#define svcvtnt_f32_f64_x  svcvtnt_f32_f64_m\n\n";
1238ec727ea7Spatrick 
1239ec727ea7Spatrick   OS << "#define svcvtxnt_f32_x     svcvtxnt_f32_m\n";
1240ec727ea7Spatrick   OS << "#define svcvtxnt_f32_f64_x svcvtxnt_f32_f64_m\n\n";
1241ec727ea7Spatrick 
1242ec727ea7Spatrick   OS << "#ifdef __cplusplus\n";
1243ec727ea7Spatrick   OS << "} // extern \"C\"\n";
1244ec727ea7Spatrick   OS << "#endif\n\n";
1245*12c85518Srobert   OS << "#undef __ai\n\n";
1246*12c85518Srobert   OS << "#undef __aio\n\n";
1247ec727ea7Spatrick   OS << "#endif /* __ARM_SVE_H */\n";
1248ec727ea7Spatrick }
1249ec727ea7Spatrick 
createBuiltins(raw_ostream & OS)1250ec727ea7Spatrick void SVEEmitter::createBuiltins(raw_ostream &OS) {
1251ec727ea7Spatrick   std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
1252ec727ea7Spatrick   SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
1253ec727ea7Spatrick   for (auto *R : RV)
1254ec727ea7Spatrick     createIntrinsic(R, Defs);
1255ec727ea7Spatrick 
1256ec727ea7Spatrick   // The mappings must be sorted based on BuiltinID.
1257ec727ea7Spatrick   llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A,
1258ec727ea7Spatrick                       const std::unique_ptr<Intrinsic> &B) {
1259ec727ea7Spatrick     return A->getMangledName() < B->getMangledName();
1260ec727ea7Spatrick   });
1261ec727ea7Spatrick 
1262ec727ea7Spatrick   OS << "#ifdef GET_SVE_BUILTINS\n";
1263ec727ea7Spatrick   for (auto &Def : Defs) {
1264ec727ea7Spatrick     // Only create BUILTINs for non-overloaded intrinsics, as overloaded
1265ec727ea7Spatrick     // declarations only live in the header file.
1266ec727ea7Spatrick     if (Def->getClassKind() != ClassG)
1267*12c85518Srobert       OS << "TARGET_BUILTIN(__builtin_sve_" << Def->getMangledName() << ", \""
1268*12c85518Srobert          << Def->getBuiltinTypeStr() << "\", \"n\", \"" << Def->getGuard()
1269*12c85518Srobert          << "\")\n";
1270ec727ea7Spatrick   }
1271ec727ea7Spatrick 
1272ec727ea7Spatrick   // Add reinterpret builtins
1273ec727ea7Spatrick   for (const ReinterpretTypeInfo &From : Reinterprets)
1274ec727ea7Spatrick     for (const ReinterpretTypeInfo &To : Reinterprets)
1275*12c85518Srobert       OS << "TARGET_BUILTIN(__builtin_sve_reinterpret_" << From.Suffix << "_"
1276ec727ea7Spatrick          << To.Suffix << +", \"" << From.BuiltinType << To.BuiltinType
1277*12c85518Srobert          << "\", \"n\", \"sve\")\n";
1278ec727ea7Spatrick 
1279ec727ea7Spatrick   OS << "#endif\n\n";
1280ec727ea7Spatrick }
1281ec727ea7Spatrick 
createCodeGenMap(raw_ostream & OS)1282ec727ea7Spatrick void SVEEmitter::createCodeGenMap(raw_ostream &OS) {
1283ec727ea7Spatrick   std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
1284ec727ea7Spatrick   SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
1285ec727ea7Spatrick   for (auto *R : RV)
1286ec727ea7Spatrick     createIntrinsic(R, Defs);
1287ec727ea7Spatrick 
1288ec727ea7Spatrick   // The mappings must be sorted based on BuiltinID.
1289ec727ea7Spatrick   llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A,
1290ec727ea7Spatrick                       const std::unique_ptr<Intrinsic> &B) {
1291ec727ea7Spatrick     return A->getMangledName() < B->getMangledName();
1292ec727ea7Spatrick   });
1293ec727ea7Spatrick 
1294ec727ea7Spatrick   OS << "#ifdef GET_SVE_LLVM_INTRINSIC_MAP\n";
1295ec727ea7Spatrick   for (auto &Def : Defs) {
1296ec727ea7Spatrick     // Builtins only exist for non-overloaded intrinsics, overloaded
1297ec727ea7Spatrick     // declarations only live in the header file.
1298ec727ea7Spatrick     if (Def->getClassKind() == ClassG)
1299ec727ea7Spatrick       continue;
1300ec727ea7Spatrick 
1301ec727ea7Spatrick     uint64_t Flags = Def->getFlags();
1302ec727ea7Spatrick     auto FlagString = std::to_string(Flags);
1303ec727ea7Spatrick 
1304ec727ea7Spatrick     std::string LLVMName = Def->getLLVMName();
1305ec727ea7Spatrick     std::string Builtin = Def->getMangledName();
1306ec727ea7Spatrick     if (!LLVMName.empty())
1307ec727ea7Spatrick       OS << "SVEMAP1(" << Builtin << ", " << LLVMName << ", " << FlagString
1308ec727ea7Spatrick          << "),\n";
1309ec727ea7Spatrick     else
1310ec727ea7Spatrick       OS << "SVEMAP2(" << Builtin << ", " << FlagString << "),\n";
1311ec727ea7Spatrick   }
1312ec727ea7Spatrick   OS << "#endif\n\n";
1313ec727ea7Spatrick }
1314ec727ea7Spatrick 
createRangeChecks(raw_ostream & OS)1315ec727ea7Spatrick void SVEEmitter::createRangeChecks(raw_ostream &OS) {
1316ec727ea7Spatrick   std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
1317ec727ea7Spatrick   SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
1318ec727ea7Spatrick   for (auto *R : RV)
1319ec727ea7Spatrick     createIntrinsic(R, Defs);
1320ec727ea7Spatrick 
1321ec727ea7Spatrick   // The mappings must be sorted based on BuiltinID.
1322ec727ea7Spatrick   llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A,
1323ec727ea7Spatrick                       const std::unique_ptr<Intrinsic> &B) {
1324ec727ea7Spatrick     return A->getMangledName() < B->getMangledName();
1325ec727ea7Spatrick   });
1326ec727ea7Spatrick 
1327ec727ea7Spatrick 
1328ec727ea7Spatrick   OS << "#ifdef GET_SVE_IMMEDIATE_CHECK\n";
1329ec727ea7Spatrick 
1330ec727ea7Spatrick   // Ensure these are only emitted once.
1331ec727ea7Spatrick   std::set<std::string> Emitted;
1332ec727ea7Spatrick 
1333ec727ea7Spatrick   for (auto &Def : Defs) {
1334ec727ea7Spatrick     if (Emitted.find(Def->getMangledName()) != Emitted.end() ||
1335ec727ea7Spatrick         Def->getImmChecks().empty())
1336ec727ea7Spatrick       continue;
1337ec727ea7Spatrick 
1338ec727ea7Spatrick     OS << "case SVE::BI__builtin_sve_" << Def->getMangledName() << ":\n";
1339ec727ea7Spatrick     for (auto &Check : Def->getImmChecks())
1340ec727ea7Spatrick       OS << "ImmChecks.push_back(std::make_tuple(" << Check.getArg() << ", "
1341ec727ea7Spatrick          << Check.getKind() << ", " << Check.getElementSizeInBits() << "));\n";
1342ec727ea7Spatrick     OS << "  break;\n";
1343ec727ea7Spatrick 
1344ec727ea7Spatrick     Emitted.insert(Def->getMangledName());
1345ec727ea7Spatrick   }
1346ec727ea7Spatrick 
1347ec727ea7Spatrick   OS << "#endif\n\n";
1348ec727ea7Spatrick }
1349ec727ea7Spatrick 
1350ec727ea7Spatrick /// Create the SVETypeFlags used in CGBuiltins
createTypeFlags(raw_ostream & OS)1351ec727ea7Spatrick void SVEEmitter::createTypeFlags(raw_ostream &OS) {
1352ec727ea7Spatrick   OS << "#ifdef LLVM_GET_SVE_TYPEFLAGS\n";
1353ec727ea7Spatrick   for (auto &KV : FlagTypes)
1354ec727ea7Spatrick     OS << "const uint64_t " << KV.getKey() << " = " << KV.getValue() << ";\n";
1355ec727ea7Spatrick   OS << "#endif\n\n";
1356ec727ea7Spatrick 
1357ec727ea7Spatrick   OS << "#ifdef LLVM_GET_SVE_ELTTYPES\n";
1358ec727ea7Spatrick   for (auto &KV : EltTypes)
1359ec727ea7Spatrick     OS << "  " << KV.getKey() << " = " << KV.getValue() << ",\n";
1360ec727ea7Spatrick   OS << "#endif\n\n";
1361ec727ea7Spatrick 
1362ec727ea7Spatrick   OS << "#ifdef LLVM_GET_SVE_MEMELTTYPES\n";
1363ec727ea7Spatrick   for (auto &KV : MemEltTypes)
1364ec727ea7Spatrick     OS << "  " << KV.getKey() << " = " << KV.getValue() << ",\n";
1365ec727ea7Spatrick   OS << "#endif\n\n";
1366ec727ea7Spatrick 
1367ec727ea7Spatrick   OS << "#ifdef LLVM_GET_SVE_MERGETYPES\n";
1368ec727ea7Spatrick   for (auto &KV : MergeTypes)
1369ec727ea7Spatrick     OS << "  " << KV.getKey() << " = " << KV.getValue() << ",\n";
1370ec727ea7Spatrick   OS << "#endif\n\n";
1371ec727ea7Spatrick 
1372ec727ea7Spatrick   OS << "#ifdef LLVM_GET_SVE_IMMCHECKTYPES\n";
1373ec727ea7Spatrick   for (auto &KV : ImmCheckTypes)
1374ec727ea7Spatrick     OS << "  " << KV.getKey() << " = " << KV.getValue() << ",\n";
1375ec727ea7Spatrick   OS << "#endif\n\n";
1376ec727ea7Spatrick }
1377ec727ea7Spatrick 
1378ec727ea7Spatrick namespace clang {
EmitSveHeader(RecordKeeper & Records,raw_ostream & OS)1379ec727ea7Spatrick void EmitSveHeader(RecordKeeper &Records, raw_ostream &OS) {
1380ec727ea7Spatrick   SVEEmitter(Records).createHeader(OS);
1381ec727ea7Spatrick }
1382ec727ea7Spatrick 
EmitSveBuiltins(RecordKeeper & Records,raw_ostream & OS)1383ec727ea7Spatrick void EmitSveBuiltins(RecordKeeper &Records, raw_ostream &OS) {
1384ec727ea7Spatrick   SVEEmitter(Records).createBuiltins(OS);
1385ec727ea7Spatrick }
1386ec727ea7Spatrick 
EmitSveBuiltinCG(RecordKeeper & Records,raw_ostream & OS)1387ec727ea7Spatrick void EmitSveBuiltinCG(RecordKeeper &Records, raw_ostream &OS) {
1388ec727ea7Spatrick   SVEEmitter(Records).createCodeGenMap(OS);
1389ec727ea7Spatrick }
1390ec727ea7Spatrick 
EmitSveRangeChecks(RecordKeeper & Records,raw_ostream & OS)1391ec727ea7Spatrick void EmitSveRangeChecks(RecordKeeper &Records, raw_ostream &OS) {
1392ec727ea7Spatrick   SVEEmitter(Records).createRangeChecks(OS);
1393ec727ea7Spatrick }
1394ec727ea7Spatrick 
EmitSveTypeFlags(RecordKeeper & Records,raw_ostream & OS)1395ec727ea7Spatrick void EmitSveTypeFlags(RecordKeeper &Records, raw_ostream &OS) {
1396ec727ea7Spatrick   SVEEmitter(Records).createTypeFlags(OS);
1397ec727ea7Spatrick }
1398ec727ea7Spatrick 
1399ec727ea7Spatrick } // End namespace clang
1400