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