123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437 |
- //===- SveEmitter.cpp - Generate arm_sve.h for use with clang -*- C++ -*-===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- //
- // This tablegen backend is responsible for emitting arm_sve.h, which includes
- // a declaration and definition of each function specified by the ARM C/C++
- // Language Extensions (ACLE).
- //
- // For details, visit:
- // https://developer.arm.com/architectures/system-architectures/software-standards/acle
- //
- // Each SVE instruction is implemented in terms of 1 or more functions which
- // are suffixed with the element type of the input vectors. Functions may be
- // implemented in terms of generic vector operations such as +, *, -, etc. or
- // by calling a __builtin_-prefixed function which will be handled by clang's
- // CodeGen library.
- //
- // See also the documentation in include/clang/Basic/arm_sve.td.
- //
- //===----------------------------------------------------------------------===//
- #include "llvm/ADT/STLExtras.h"
- #include "llvm/ADT/StringMap.h"
- #include "llvm/ADT/ArrayRef.h"
- #include "llvm/ADT/StringExtras.h"
- #include "llvm/TableGen/Record.h"
- #include "llvm/TableGen/Error.h"
- #include <string>
- #include <sstream>
- #include <set>
- #include <cctype>
- #include <tuple>
- using namespace llvm;
- enum ClassKind {
- ClassNone,
- ClassS, // signed/unsigned, e.g., "_s8", "_u8" suffix
- ClassG, // Overloaded name without type suffix
- };
- using TypeSpec = std::string;
- namespace {
- class ImmCheck {
- unsigned Arg;
- unsigned Kind;
- unsigned ElementSizeInBits;
- public:
- ImmCheck(unsigned Arg, unsigned Kind, unsigned ElementSizeInBits = 0)
- : Arg(Arg), Kind(Kind), ElementSizeInBits(ElementSizeInBits) {}
- ImmCheck(const ImmCheck &Other) = default;
- ~ImmCheck() = default;
- unsigned getArg() const { return Arg; }
- unsigned getKind() const { return Kind; }
- unsigned getElementSizeInBits() const { return ElementSizeInBits; }
- };
- class SVEType {
- TypeSpec TS;
- bool Float, Signed, Immediate, Void, Constant, Pointer, BFloat;
- bool DefaultType, IsScalable, Predicate, PredicatePattern, PrefetchOp;
- unsigned Bitwidth, ElementBitwidth, NumVectors;
- public:
- SVEType() : SVEType(TypeSpec(), 'v') {}
- SVEType(TypeSpec TS, char CharMod)
- : TS(TS), Float(false), Signed(true), Immediate(false), Void(false),
- Constant(false), Pointer(false), BFloat(false), DefaultType(false),
- IsScalable(true), Predicate(false), PredicatePattern(false),
- PrefetchOp(false), Bitwidth(128), ElementBitwidth(~0U), NumVectors(1) {
- if (!TS.empty())
- applyTypespec();
- applyModifier(CharMod);
- }
- bool isPointer() const { return Pointer; }
- bool isVoidPointer() const { return Pointer && Void; }
- bool isSigned() const { return Signed; }
- bool isImmediate() const { return Immediate; }
- bool isScalar() const { return NumVectors == 0; }
- bool isVector() const { return NumVectors > 0; }
- bool isScalableVector() const { return isVector() && IsScalable; }
- bool isChar() const { return ElementBitwidth == 8; }
- bool isVoid() const { return Void & !Pointer; }
- bool isDefault() const { return DefaultType; }
- bool isFloat() const { return Float && !BFloat; }
- bool isBFloat() const { return BFloat && !Float; }
- bool isFloatingPoint() const { return Float || BFloat; }
- bool isInteger() const { return !isFloatingPoint() && !Predicate; }
- bool isScalarPredicate() const {
- return !isFloatingPoint() && Predicate && NumVectors == 0;
- }
- bool isPredicateVector() const { return Predicate; }
- bool isPredicatePattern() const { return PredicatePattern; }
- bool isPrefetchOp() const { return PrefetchOp; }
- bool isConstant() const { return Constant; }
- unsigned getElementSizeInBits() const { return ElementBitwidth; }
- unsigned getNumVectors() const { return NumVectors; }
- unsigned getNumElements() const {
- assert(ElementBitwidth != ~0U);
- return Bitwidth / ElementBitwidth;
- }
- unsigned getSizeInBits() const {
- return Bitwidth;
- }
- /// Return the string representation of a type, which is an encoded
- /// string for passing to the BUILTIN() macro in Builtins.def.
- std::string builtin_str() const;
- /// Return the C/C++ string representation of a type for use in the
- /// arm_sve.h header file.
- std::string str() const;
- private:
- /// Creates the type based on the typespec string in TS.
- void applyTypespec();
- /// Applies a prototype modifier to the type.
- void applyModifier(char Mod);
- };
- class SVEEmitter;
- /// The main grunt class. This represents an instantiation of an intrinsic with
- /// a particular typespec and prototype.
- class Intrinsic {
- /// The unmangled name.
- std::string Name;
- /// The name of the corresponding LLVM IR intrinsic.
- std::string LLVMName;
- /// Intrinsic prototype.
- std::string Proto;
- /// The base type spec for this intrinsic.
- TypeSpec BaseTypeSpec;
- /// The base class kind. Most intrinsics use ClassS, which has full type
- /// info for integers (_s32/_u32), or ClassG which is used for overloaded
- /// intrinsics.
- ClassKind Class;
- /// The architectural #ifdef guard.
- std::string Guard;
- // The merge suffix such as _m, _x or _z.
- std::string MergeSuffix;
- /// The types of return value [0] and parameters [1..].
- std::vector<SVEType> Types;
- /// The "base type", which is VarType('d', BaseTypeSpec).
- SVEType BaseType;
- uint64_t Flags;
- SmallVector<ImmCheck, 2> ImmChecks;
- public:
- Intrinsic(StringRef Name, StringRef Proto, uint64_t MergeTy,
- StringRef MergeSuffix, uint64_t MemoryElementTy, StringRef LLVMName,
- uint64_t Flags, ArrayRef<ImmCheck> ImmChecks, TypeSpec BT,
- ClassKind Class, SVEEmitter &Emitter, StringRef Guard);
- ~Intrinsic()=default;
- std::string getName() const { return Name; }
- std::string getLLVMName() const { return LLVMName; }
- std::string getProto() const { return Proto; }
- TypeSpec getBaseTypeSpec() const { return BaseTypeSpec; }
- SVEType getBaseType() const { return BaseType; }
- StringRef getGuard() const { return Guard; }
- ClassKind getClassKind() const { return Class; }
- SVEType getReturnType() const { return Types[0]; }
- ArrayRef<SVEType> getTypes() const { return Types; }
- SVEType getParamType(unsigned I) const { return Types[I + 1]; }
- unsigned getNumParams() const { return Proto.size() - 1; }
- uint64_t getFlags() const { return Flags; }
- bool isFlagSet(uint64_t Flag) const { return Flags & Flag;}
- ArrayRef<ImmCheck> getImmChecks() const { return ImmChecks; }
- /// Return the type string for a BUILTIN() macro in Builtins.def.
- std::string getBuiltinTypeStr();
- /// Return the name, mangled with type information. The name is mangled for
- /// ClassS, so will add type suffixes such as _u32/_s32.
- std::string getMangledName() const { return mangleName(ClassS); }
- /// Returns true if the intrinsic is overloaded, in that it should also generate
- /// a short form without the type-specifiers, e.g. 'svld1(..)' instead of
- /// 'svld1_u32(..)'.
- static bool isOverloadedIntrinsic(StringRef Name) {
- auto BrOpen = Name.find('[');
- auto BrClose = Name.find(']');
- return BrOpen != std::string::npos && BrClose != std::string::npos;
- }
- /// Return true if the intrinsic takes a splat operand.
- bool hasSplat() const {
- // These prototype modifiers are described in arm_sve.td.
- return Proto.find_first_of("ajfrKLR@") != std::string::npos;
- }
- /// Return the parameter index of the splat operand.
- unsigned getSplatIdx() const {
- // These prototype modifiers are described in arm_sve.td.
- auto Idx = Proto.find_first_of("ajfrKLR@");
- assert(Idx != std::string::npos && Idx > 0 &&
- "Prototype has no splat operand");
- return Idx - 1;
- }
- /// Emits the intrinsic declaration to the ostream.
- void emitIntrinsic(raw_ostream &OS) const;
- private:
- std::string getMergeSuffix() const { return MergeSuffix; }
- std::string mangleName(ClassKind LocalCK) const;
- std::string replaceTemplatedArgs(std::string Name, TypeSpec TS,
- std::string Proto) const;
- };
- class SVEEmitter {
- private:
- // The reinterpret builtins are generated separately because they
- // need the cross product of all types (121 functions in total),
- // which is inconvenient to specify in the arm_sve.td file or
- // generate in CGBuiltin.cpp.
- struct ReinterpretTypeInfo {
- const char *Suffix;
- const char *Type;
- const char *BuiltinType;
- };
- SmallVector<ReinterpretTypeInfo, 12> Reinterprets = {
- {"s8", "svint8_t", "q16Sc"}, {"s16", "svint16_t", "q8Ss"},
- {"s32", "svint32_t", "q4Si"}, {"s64", "svint64_t", "q2SWi"},
- {"u8", "svuint8_t", "q16Uc"}, {"u16", "svuint16_t", "q8Us"},
- {"u32", "svuint32_t", "q4Ui"}, {"u64", "svuint64_t", "q2UWi"},
- {"f16", "svfloat16_t", "q8h"}, {"bf16", "svbfloat16_t", "q8y"},
- {"f32", "svfloat32_t", "q4f"}, {"f64", "svfloat64_t", "q2d"}};
- RecordKeeper &Records;
- llvm::StringMap<uint64_t> EltTypes;
- llvm::StringMap<uint64_t> MemEltTypes;
- llvm::StringMap<uint64_t> FlagTypes;
- llvm::StringMap<uint64_t> MergeTypes;
- llvm::StringMap<uint64_t> ImmCheckTypes;
- public:
- SVEEmitter(RecordKeeper &R) : Records(R) {
- for (auto *RV : Records.getAllDerivedDefinitions("EltType"))
- EltTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");
- for (auto *RV : Records.getAllDerivedDefinitions("MemEltType"))
- MemEltTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");
- for (auto *RV : Records.getAllDerivedDefinitions("FlagType"))
- FlagTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");
- for (auto *RV : Records.getAllDerivedDefinitions("MergeType"))
- MergeTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");
- for (auto *RV : Records.getAllDerivedDefinitions("ImmCheckType"))
- ImmCheckTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");
- }
- /// Returns the enum value for the immcheck type
- unsigned getEnumValueForImmCheck(StringRef C) const {
- auto It = ImmCheckTypes.find(C);
- if (It != ImmCheckTypes.end())
- return It->getValue();
- llvm_unreachable("Unsupported imm check");
- }
- /// Returns the enum value for the flag type
- uint64_t getEnumValueForFlag(StringRef C) const {
- auto Res = FlagTypes.find(C);
- if (Res != FlagTypes.end())
- return Res->getValue();
- llvm_unreachable("Unsupported flag");
- }
- // Returns the SVETypeFlags for a given value and mask.
- uint64_t encodeFlag(uint64_t V, StringRef MaskName) const {
- auto It = FlagTypes.find(MaskName);
- if (It != FlagTypes.end()) {
- uint64_t Mask = It->getValue();
- unsigned Shift = llvm::countTrailingZeros(Mask);
- return (V << Shift) & Mask;
- }
- llvm_unreachable("Unsupported flag");
- }
- // Returns the SVETypeFlags for the given element type.
- uint64_t encodeEltType(StringRef EltName) {
- auto It = EltTypes.find(EltName);
- if (It != EltTypes.end())
- return encodeFlag(It->getValue(), "EltTypeMask");
- llvm_unreachable("Unsupported EltType");
- }
- // Returns the SVETypeFlags for the given memory element type.
- uint64_t encodeMemoryElementType(uint64_t MT) {
- return encodeFlag(MT, "MemEltTypeMask");
- }
- // Returns the SVETypeFlags for the given merge type.
- uint64_t encodeMergeType(uint64_t MT) {
- return encodeFlag(MT, "MergeTypeMask");
- }
- // Returns the SVETypeFlags for the given splat operand.
- unsigned encodeSplatOperand(unsigned SplatIdx) {
- assert(SplatIdx < 7 && "SplatIdx out of encodable range");
- return encodeFlag(SplatIdx + 1, "SplatOperandMask");
- }
- // Returns the SVETypeFlags value for the given SVEType.
- uint64_t encodeTypeFlags(const SVEType &T);
- /// Emit arm_sve.h.
- void createHeader(raw_ostream &o);
- /// Emit all the __builtin prototypes and code needed by Sema.
- void createBuiltins(raw_ostream &o);
- /// Emit all the information needed to map builtin -> LLVM IR intrinsic.
- void createCodeGenMap(raw_ostream &o);
- /// Emit all the range checks for the immediates.
- void createRangeChecks(raw_ostream &o);
- /// Create the SVETypeFlags used in CGBuiltins
- void createTypeFlags(raw_ostream &o);
- /// Create intrinsic and add it to \p Out
- void createIntrinsic(Record *R, SmallVectorImpl<std::unique_ptr<Intrinsic>> &Out);
- };
- } // end anonymous namespace
- //===----------------------------------------------------------------------===//
- // Type implementation
- //===----------------------------------------------------------------------===//
- std::string SVEType::builtin_str() const {
- std::string S;
- if (isVoid())
- return "v";
- if (isScalarPredicate())
- return "b";
- if (isVoidPointer())
- S += "v";
- else if (!isFloatingPoint())
- switch (ElementBitwidth) {
- case 1: S += "b"; break;
- case 8: S += "c"; break;
- case 16: S += "s"; break;
- case 32: S += "i"; break;
- case 64: S += "Wi"; break;
- case 128: S += "LLLi"; break;
- default: llvm_unreachable("Unhandled case!");
- }
- else if (isFloat())
- switch (ElementBitwidth) {
- case 16: S += "h"; break;
- case 32: S += "f"; break;
- case 64: S += "d"; break;
- default: llvm_unreachable("Unhandled case!");
- }
- else if (isBFloat()) {
- assert(ElementBitwidth == 16 && "Not a valid BFloat.");
- S += "y";
- }
- if (!isFloatingPoint()) {
- if ((isChar() || isPointer()) && !isVoidPointer()) {
- // Make chars and typed pointers explicitly signed.
- if (Signed)
- S = "S" + S;
- else if (!Signed)
- S = "U" + S;
- } else if (!isVoidPointer() && !Signed) {
- S = "U" + S;
- }
- }
- // Constant indices are "int", but have the "constant expression" modifier.
- if (isImmediate()) {
- assert(!isFloat() && "fp immediates are not supported");
- S = "I" + S;
- }
- if (isScalar()) {
- if (Constant) S += "C";
- if (Pointer) S += "*";
- return S;
- }
- assert(isScalableVector() && "Unsupported type");
- return "q" + utostr(getNumElements() * NumVectors) + S;
- }
- std::string SVEType::str() const {
- if (isPredicatePattern())
- return "enum svpattern";
- if (isPrefetchOp())
- return "enum svprfop";
- std::string S;
- if (Void)
- S += "void";
- else {
- if (isScalableVector())
- S += "sv";
- if (!Signed && !isFloatingPoint())
- S += "u";
- if (Float)
- S += "float";
- else if (isScalarPredicate() || isPredicateVector())
- S += "bool";
- else if (isBFloat())
- S += "bfloat";
- else
- S += "int";
- if (!isScalarPredicate() && !isPredicateVector())
- S += utostr(ElementBitwidth);
- if (!isScalableVector() && isVector())
- S += "x" + utostr(getNumElements());
- if (NumVectors > 1)
- S += "x" + utostr(NumVectors);
- if (!isScalarPredicate())
- S += "_t";
- }
- if (Constant)
- S += " const";
- if (Pointer)
- S += " *";
- return S;
- }
- void SVEType::applyTypespec() {
- for (char I : TS) {
- switch (I) {
- case 'P':
- Predicate = true;
- break;
- case 'U':
- Signed = false;
- break;
- case 'c':
- ElementBitwidth = 8;
- break;
- case 's':
- ElementBitwidth = 16;
- break;
- case 'i':
- ElementBitwidth = 32;
- break;
- case 'l':
- ElementBitwidth = 64;
- break;
- case 'h':
- Float = true;
- ElementBitwidth = 16;
- break;
- case 'f':
- Float = true;
- ElementBitwidth = 32;
- break;
- case 'd':
- Float = true;
- ElementBitwidth = 64;
- break;
- case 'b':
- BFloat = true;
- Float = false;
- ElementBitwidth = 16;
- break;
- default:
- llvm_unreachable("Unhandled type code!");
- }
- }
- assert(ElementBitwidth != ~0U && "Bad element bitwidth!");
- }
- void SVEType::applyModifier(char Mod) {
- switch (Mod) {
- case '2':
- NumVectors = 2;
- break;
- case '3':
- NumVectors = 3;
- break;
- case '4':
- NumVectors = 4;
- break;
- case 'v':
- Void = true;
- break;
- case 'd':
- DefaultType = true;
- break;
- case 'c':
- Constant = true;
- LLVM_FALLTHROUGH;
- case 'p':
- Pointer = true;
- Bitwidth = ElementBitwidth;
- NumVectors = 0;
- break;
- case 'e':
- Signed = false;
- ElementBitwidth /= 2;
- break;
- case 'h':
- ElementBitwidth /= 2;
- break;
- case 'q':
- ElementBitwidth /= 4;
- break;
- case 'b':
- Signed = false;
- Float = false;
- BFloat = false;
- ElementBitwidth /= 4;
- break;
- case 'o':
- ElementBitwidth *= 4;
- break;
- case 'P':
- Signed = true;
- Float = false;
- BFloat = false;
- Predicate = true;
- Bitwidth = 16;
- ElementBitwidth = 1;
- break;
- case 's':
- case 'a':
- Bitwidth = ElementBitwidth;
- NumVectors = 0;
- break;
- case 'R':
- ElementBitwidth /= 2;
- NumVectors = 0;
- break;
- case 'r':
- ElementBitwidth /= 4;
- NumVectors = 0;
- break;
- case '@':
- Signed = false;
- Float = false;
- BFloat = false;
- ElementBitwidth /= 4;
- NumVectors = 0;
- break;
- case 'K':
- Signed = true;
- Float = false;
- BFloat = false;
- Bitwidth = ElementBitwidth;
- NumVectors = 0;
- break;
- case 'L':
- Signed = false;
- Float = false;
- BFloat = false;
- Bitwidth = ElementBitwidth;
- NumVectors = 0;
- break;
- case 'u':
- Predicate = false;
- Signed = false;
- Float = false;
- BFloat = false;
- break;
- case 'x':
- Predicate = false;
- Signed = true;
- Float = false;
- BFloat = false;
- break;
- case 'i':
- Predicate = false;
- Float = false;
- BFloat = false;
- ElementBitwidth = Bitwidth = 64;
- NumVectors = 0;
- Signed = false;
- Immediate = true;
- break;
- case 'I':
- Predicate = false;
- Float = false;
- BFloat = false;
- ElementBitwidth = Bitwidth = 32;
- NumVectors = 0;
- Signed = true;
- Immediate = true;
- PredicatePattern = true;
- break;
- case 'J':
- Predicate = false;
- Float = false;
- BFloat = false;
- ElementBitwidth = Bitwidth = 32;
- NumVectors = 0;
- Signed = true;
- Immediate = true;
- PrefetchOp = true;
- break;
- case 'k':
- Predicate = false;
- Signed = true;
- Float = false;
- BFloat = false;
- ElementBitwidth = Bitwidth = 32;
- NumVectors = 0;
- break;
- case 'l':
- Predicate = false;
- Signed = true;
- Float = false;
- BFloat = false;
- ElementBitwidth = Bitwidth = 64;
- NumVectors = 0;
- break;
- case 'm':
- Predicate = false;
- Signed = false;
- Float = false;
- BFloat = false;
- ElementBitwidth = Bitwidth = 32;
- NumVectors = 0;
- break;
- case 'n':
- Predicate = false;
- Signed = false;
- Float = false;
- BFloat = false;
- ElementBitwidth = Bitwidth = 64;
- NumVectors = 0;
- break;
- case 'w':
- ElementBitwidth = 64;
- break;
- case 'j':
- ElementBitwidth = Bitwidth = 64;
- NumVectors = 0;
- break;
- case 'f':
- Signed = false;
- ElementBitwidth = Bitwidth = 64;
- NumVectors = 0;
- break;
- case 'g':
- Signed = false;
- Float = false;
- BFloat = false;
- ElementBitwidth = 64;
- break;
- case 't':
- Signed = true;
- Float = false;
- BFloat = false;
- ElementBitwidth = 32;
- break;
- case 'z':
- Signed = false;
- Float = false;
- BFloat = false;
- ElementBitwidth = 32;
- break;
- case 'O':
- Predicate = false;
- Float = true;
- ElementBitwidth = 16;
- break;
- case 'M':
- Predicate = false;
- Float = true;
- BFloat = false;
- ElementBitwidth = 32;
- break;
- case 'N':
- Predicate = false;
- Float = true;
- ElementBitwidth = 64;
- break;
- case 'Q':
- Constant = true;
- Pointer = true;
- Void = true;
- NumVectors = 0;
- break;
- case 'S':
- Constant = true;
- Pointer = true;
- ElementBitwidth = Bitwidth = 8;
- NumVectors = 0;
- Signed = true;
- break;
- case 'W':
- Constant = true;
- Pointer = true;
- ElementBitwidth = Bitwidth = 8;
- NumVectors = 0;
- Signed = false;
- break;
- case 'T':
- Constant = true;
- Pointer = true;
- ElementBitwidth = Bitwidth = 16;
- NumVectors = 0;
- Signed = true;
- break;
- case 'X':
- Constant = true;
- Pointer = true;
- ElementBitwidth = Bitwidth = 16;
- NumVectors = 0;
- Signed = false;
- break;
- case 'Y':
- Constant = true;
- Pointer = true;
- ElementBitwidth = Bitwidth = 32;
- NumVectors = 0;
- Signed = false;
- break;
- case 'U':
- Constant = true;
- Pointer = true;
- ElementBitwidth = Bitwidth = 32;
- NumVectors = 0;
- Signed = true;
- break;
- case 'A':
- Pointer = true;
- ElementBitwidth = Bitwidth = 8;
- NumVectors = 0;
- Signed = true;
- break;
- case 'B':
- Pointer = true;
- ElementBitwidth = Bitwidth = 16;
- NumVectors = 0;
- Signed = true;
- break;
- case 'C':
- Pointer = true;
- ElementBitwidth = Bitwidth = 32;
- NumVectors = 0;
- Signed = true;
- break;
- case 'D':
- Pointer = true;
- ElementBitwidth = Bitwidth = 64;
- NumVectors = 0;
- Signed = true;
- break;
- case 'E':
- Pointer = true;
- ElementBitwidth = Bitwidth = 8;
- NumVectors = 0;
- Signed = false;
- break;
- case 'F':
- Pointer = true;
- ElementBitwidth = Bitwidth = 16;
- NumVectors = 0;
- Signed = false;
- break;
- case 'G':
- Pointer = true;
- ElementBitwidth = Bitwidth = 32;
- NumVectors = 0;
- Signed = false;
- break;
- default:
- llvm_unreachable("Unhandled character!");
- }
- }
- //===----------------------------------------------------------------------===//
- // Intrinsic implementation
- //===----------------------------------------------------------------------===//
- Intrinsic::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)
- : Name(Name.str()), LLVMName(LLVMName), Proto(Proto.str()),
- BaseTypeSpec(BT), Class(Class), Guard(Guard.str()),
- MergeSuffix(MergeSuffix.str()), BaseType(BT, 'd'), Flags(Flags),
- ImmChecks(Checks.begin(), Checks.end()) {
- // Types[0] is the return value.
- for (unsigned I = 0; I < Proto.size(); ++I) {
- SVEType T(BaseTypeSpec, Proto[I]);
- Types.push_back(T);
- // Add range checks for immediates
- if (I > 0) {
- if (T.isPredicatePattern())
- ImmChecks.emplace_back(
- I - 1, Emitter.getEnumValueForImmCheck("ImmCheck0_31"));
- else if (T.isPrefetchOp())
- ImmChecks.emplace_back(
- I - 1, Emitter.getEnumValueForImmCheck("ImmCheck0_13"));
- }
- }
- // Set flags based on properties
- this->Flags |= Emitter.encodeTypeFlags(BaseType);
- this->Flags |= Emitter.encodeMemoryElementType(MemoryElementTy);
- this->Flags |= Emitter.encodeMergeType(MergeTy);
- if (hasSplat())
- this->Flags |= Emitter.encodeSplatOperand(getSplatIdx());
- }
- std::string Intrinsic::getBuiltinTypeStr() {
- std::string S = getReturnType().builtin_str();
- for (unsigned I = 0; I < getNumParams(); ++I)
- S += getParamType(I).builtin_str();
- return S;
- }
- std::string Intrinsic::replaceTemplatedArgs(std::string Name, TypeSpec TS,
- std::string Proto) const {
- std::string Ret = Name;
- while (Ret.find('{') != std::string::npos) {
- size_t Pos = Ret.find('{');
- size_t End = Ret.find('}');
- unsigned NumChars = End - Pos + 1;
- assert(NumChars == 3 && "Unexpected template argument");
- SVEType T;
- char C = Ret[Pos+1];
- switch(C) {
- default:
- llvm_unreachable("Unknown predication specifier");
- case 'd':
- T = SVEType(TS, 'd');
- break;
- case '0':
- case '1':
- case '2':
- case '3':
- T = SVEType(TS, Proto[C - '0']);
- break;
- }
- // Replace templated arg with the right suffix (e.g. u32)
- std::string TypeCode;
- if (T.isInteger())
- TypeCode = T.isSigned() ? 's' : 'u';
- else if (T.isPredicateVector())
- TypeCode = 'b';
- else if (T.isBFloat())
- TypeCode = "bf";
- else
- TypeCode = 'f';
- Ret.replace(Pos, NumChars, TypeCode + utostr(T.getElementSizeInBits()));
- }
- return Ret;
- }
- std::string Intrinsic::mangleName(ClassKind LocalCK) const {
- std::string S = getName();
- if (LocalCK == ClassG) {
- // Remove the square brackets and everything in between.
- while (S.find('[') != std::string::npos) {
- auto Start = S.find('[');
- auto End = S.find(']');
- S.erase(Start, (End-Start)+1);
- }
- } else {
- // Remove the square brackets.
- while (S.find('[') != std::string::npos) {
- auto BrPos = S.find('[');
- if (BrPos != std::string::npos)
- S.erase(BrPos, 1);
- BrPos = S.find(']');
- if (BrPos != std::string::npos)
- S.erase(BrPos, 1);
- }
- }
- // Replace all {d} like expressions with e.g. 'u32'
- return replaceTemplatedArgs(S, getBaseTypeSpec(), getProto()) +
- getMergeSuffix();
- }
- void Intrinsic::emitIntrinsic(raw_ostream &OS) const {
- bool IsOverloaded = getClassKind() == ClassG && getProto().size() > 1;
- std::string FullName = mangleName(ClassS);
- std::string ProtoName = mangleName(getClassKind());
- OS << (IsOverloaded ? "__aio " : "__ai ")
- << "__attribute__((__clang_arm_builtin_alias("
- << "__builtin_sve_" << FullName << ")))\n";
- OS << getTypes()[0].str() << " " << ProtoName << "(";
- for (unsigned I = 0; I < getTypes().size() - 1; ++I) {
- if (I != 0)
- OS << ", ";
- OS << getTypes()[I + 1].str();
- }
- OS << ");\n";
- }
- //===----------------------------------------------------------------------===//
- // SVEEmitter implementation
- //===----------------------------------------------------------------------===//
- uint64_t SVEEmitter::encodeTypeFlags(const SVEType &T) {
- if (T.isFloat()) {
- switch (T.getElementSizeInBits()) {
- case 16:
- return encodeEltType("EltTyFloat16");
- case 32:
- return encodeEltType("EltTyFloat32");
- case 64:
- return encodeEltType("EltTyFloat64");
- default:
- llvm_unreachable("Unhandled float element bitwidth!");
- }
- }
- if (T.isBFloat()) {
- assert(T.getElementSizeInBits() == 16 && "Not a valid BFloat.");
- return encodeEltType("EltTyBFloat16");
- }
- if (T.isPredicateVector()) {
- switch (T.getElementSizeInBits()) {
- case 8:
- return encodeEltType("EltTyBool8");
- case 16:
- return encodeEltType("EltTyBool16");
- case 32:
- return encodeEltType("EltTyBool32");
- case 64:
- return encodeEltType("EltTyBool64");
- default:
- llvm_unreachable("Unhandled predicate element bitwidth!");
- }
- }
- switch (T.getElementSizeInBits()) {
- case 8:
- return encodeEltType("EltTyInt8");
- case 16:
- return encodeEltType("EltTyInt16");
- case 32:
- return encodeEltType("EltTyInt32");
- case 64:
- return encodeEltType("EltTyInt64");
- default:
- llvm_unreachable("Unhandled integer element bitwidth!");
- }
- }
- void SVEEmitter::createIntrinsic(
- Record *R, SmallVectorImpl<std::unique_ptr<Intrinsic>> &Out) {
- StringRef Name = R->getValueAsString("Name");
- StringRef Proto = R->getValueAsString("Prototype");
- StringRef Types = R->getValueAsString("Types");
- StringRef Guard = R->getValueAsString("ArchGuard");
- StringRef LLVMName = R->getValueAsString("LLVMIntrinsic");
- uint64_t Merge = R->getValueAsInt("Merge");
- StringRef MergeSuffix = R->getValueAsString("MergeSuffix");
- uint64_t MemEltType = R->getValueAsInt("MemEltType");
- std::vector<Record*> FlagsList = R->getValueAsListOfDefs("Flags");
- std::vector<Record*> ImmCheckList = R->getValueAsListOfDefs("ImmChecks");
- int64_t Flags = 0;
- for (auto FlagRec : FlagsList)
- Flags |= FlagRec->getValueAsInt("Value");
- // Create a dummy TypeSpec for non-overloaded builtins.
- if (Types.empty()) {
- assert((Flags & getEnumValueForFlag("IsOverloadNone")) &&
- "Expect TypeSpec for overloaded builtin!");
- Types = "i";
- }
- // Extract type specs from string
- SmallVector<TypeSpec, 8> TypeSpecs;
- TypeSpec Acc;
- for (char I : Types) {
- Acc.push_back(I);
- if (islower(I)) {
- TypeSpecs.push_back(TypeSpec(Acc));
- Acc.clear();
- }
- }
- // Remove duplicate type specs.
- llvm::sort(TypeSpecs);
- TypeSpecs.erase(std::unique(TypeSpecs.begin(), TypeSpecs.end()),
- TypeSpecs.end());
- // Create an Intrinsic for each type spec.
- for (auto TS : TypeSpecs) {
- // Collate a list of range/option checks for the immediates.
- SmallVector<ImmCheck, 2> ImmChecks;
- for (auto *R : ImmCheckList) {
- int64_t Arg = R->getValueAsInt("Arg");
- int64_t EltSizeArg = R->getValueAsInt("EltSizeArg");
- int64_t Kind = R->getValueAsDef("Kind")->getValueAsInt("Value");
- assert(Arg >= 0 && Kind >= 0 && "Arg and Kind must be nonnegative");
- unsigned ElementSizeInBits = 0;
- if (EltSizeArg >= 0)
- ElementSizeInBits =
- SVEType(TS, Proto[EltSizeArg + /* offset by return arg */ 1])
- .getElementSizeInBits();
- ImmChecks.push_back(ImmCheck(Arg, Kind, ElementSizeInBits));
- }
- Out.push_back(std::make_unique<Intrinsic>(
- Name, Proto, Merge, MergeSuffix, MemEltType, LLVMName, Flags, ImmChecks,
- TS, ClassS, *this, Guard));
- // Also generate the short-form (e.g. svadd_m) for the given type-spec.
- if (Intrinsic::isOverloadedIntrinsic(Name))
- Out.push_back(std::make_unique<Intrinsic>(
- Name, Proto, Merge, MergeSuffix, MemEltType, LLVMName, Flags,
- ImmChecks, TS, ClassG, *this, Guard));
- }
- }
- void SVEEmitter::createHeader(raw_ostream &OS) {
- OS << "/*===---- arm_sve.h - ARM SVE intrinsics "
- "-----------------------------------===\n"
- " *\n"
- " *\n"
- " * Part of the LLVM Project, under the Apache License v2.0 with LLVM "
- "Exceptions.\n"
- " * See https://llvm.org/LICENSE.txt for license information.\n"
- " * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n"
- " *\n"
- " *===-----------------------------------------------------------------"
- "------===\n"
- " */\n\n";
- OS << "#ifndef __ARM_SVE_H\n";
- OS << "#define __ARM_SVE_H\n\n";
- OS << "#if !defined(__ARM_FEATURE_SVE)\n";
- OS << "#error \"SVE support not enabled\"\n";
- OS << "#else\n\n";
- OS << "#if !defined(__LITTLE_ENDIAN__)\n";
- OS << "#error \"Big endian is currently not supported for arm_sve.h\"\n";
- OS << "#endif\n";
- OS << "#include <stdint.h>\n\n";
- OS << "#ifdef __cplusplus\n";
- OS << "extern \"C\" {\n";
- OS << "#else\n";
- OS << "#include <stdbool.h>\n";
- OS << "#endif\n\n";
- OS << "typedef __fp16 float16_t;\n";
- OS << "typedef float float32_t;\n";
- OS << "typedef double float64_t;\n";
- OS << "typedef __SVInt8_t svint8_t;\n";
- OS << "typedef __SVInt16_t svint16_t;\n";
- OS << "typedef __SVInt32_t svint32_t;\n";
- OS << "typedef __SVInt64_t svint64_t;\n";
- OS << "typedef __SVUint8_t svuint8_t;\n";
- OS << "typedef __SVUint16_t svuint16_t;\n";
- OS << "typedef __SVUint32_t svuint32_t;\n";
- OS << "typedef __SVUint64_t svuint64_t;\n";
- OS << "typedef __SVFloat16_t svfloat16_t;\n\n";
- OS << "#if defined(__ARM_FEATURE_SVE_BF16) && "
- "!defined(__ARM_FEATURE_BF16_SCALAR_ARITHMETIC)\n";
- OS << "#error \"__ARM_FEATURE_BF16_SCALAR_ARITHMETIC must be defined when "
- "__ARM_FEATURE_SVE_BF16 is defined\"\n";
- OS << "#endif\n\n";
- OS << "#if defined(__ARM_FEATURE_SVE_BF16)\n";
- OS << "typedef __SVBFloat16_t svbfloat16_t;\n";
- OS << "#endif\n\n";
- OS << "#if defined(__ARM_FEATURE_BF16_SCALAR_ARITHMETIC)\n";
- OS << "#include <arm_bf16.h>\n";
- OS << "typedef __bf16 bfloat16_t;\n";
- OS << "#endif\n\n";
- OS << "typedef __SVFloat32_t svfloat32_t;\n";
- OS << "typedef __SVFloat64_t svfloat64_t;\n";
- OS << "typedef __clang_svint8x2_t svint8x2_t;\n";
- OS << "typedef __clang_svint16x2_t svint16x2_t;\n";
- OS << "typedef __clang_svint32x2_t svint32x2_t;\n";
- OS << "typedef __clang_svint64x2_t svint64x2_t;\n";
- OS << "typedef __clang_svuint8x2_t svuint8x2_t;\n";
- OS << "typedef __clang_svuint16x2_t svuint16x2_t;\n";
- OS << "typedef __clang_svuint32x2_t svuint32x2_t;\n";
- OS << "typedef __clang_svuint64x2_t svuint64x2_t;\n";
- OS << "typedef __clang_svfloat16x2_t svfloat16x2_t;\n";
- OS << "typedef __clang_svfloat32x2_t svfloat32x2_t;\n";
- OS << "typedef __clang_svfloat64x2_t svfloat64x2_t;\n";
- OS << "typedef __clang_svint8x3_t svint8x3_t;\n";
- OS << "typedef __clang_svint16x3_t svint16x3_t;\n";
- OS << "typedef __clang_svint32x3_t svint32x3_t;\n";
- OS << "typedef __clang_svint64x3_t svint64x3_t;\n";
- OS << "typedef __clang_svuint8x3_t svuint8x3_t;\n";
- OS << "typedef __clang_svuint16x3_t svuint16x3_t;\n";
- OS << "typedef __clang_svuint32x3_t svuint32x3_t;\n";
- OS << "typedef __clang_svuint64x3_t svuint64x3_t;\n";
- OS << "typedef __clang_svfloat16x3_t svfloat16x3_t;\n";
- OS << "typedef __clang_svfloat32x3_t svfloat32x3_t;\n";
- OS << "typedef __clang_svfloat64x3_t svfloat64x3_t;\n";
- OS << "typedef __clang_svint8x4_t svint8x4_t;\n";
- OS << "typedef __clang_svint16x4_t svint16x4_t;\n";
- OS << "typedef __clang_svint32x4_t svint32x4_t;\n";
- OS << "typedef __clang_svint64x4_t svint64x4_t;\n";
- OS << "typedef __clang_svuint8x4_t svuint8x4_t;\n";
- OS << "typedef __clang_svuint16x4_t svuint16x4_t;\n";
- OS << "typedef __clang_svuint32x4_t svuint32x4_t;\n";
- OS << "typedef __clang_svuint64x4_t svuint64x4_t;\n";
- OS << "typedef __clang_svfloat16x4_t svfloat16x4_t;\n";
- OS << "typedef __clang_svfloat32x4_t svfloat32x4_t;\n";
- OS << "typedef __clang_svfloat64x4_t svfloat64x4_t;\n";
- OS << "typedef __SVBool_t svbool_t;\n\n";
- OS << "#ifdef __ARM_FEATURE_SVE_BF16\n";
- OS << "typedef __clang_svbfloat16x2_t svbfloat16x2_t;\n";
- OS << "typedef __clang_svbfloat16x3_t svbfloat16x3_t;\n";
- OS << "typedef __clang_svbfloat16x4_t svbfloat16x4_t;\n";
- OS << "#endif\n";
- OS << "enum svpattern\n";
- OS << "{\n";
- OS << " SV_POW2 = 0,\n";
- OS << " SV_VL1 = 1,\n";
- OS << " SV_VL2 = 2,\n";
- OS << " SV_VL3 = 3,\n";
- OS << " SV_VL4 = 4,\n";
- OS << " SV_VL5 = 5,\n";
- OS << " SV_VL6 = 6,\n";
- OS << " SV_VL7 = 7,\n";
- OS << " SV_VL8 = 8,\n";
- OS << " SV_VL16 = 9,\n";
- OS << " SV_VL32 = 10,\n";
- OS << " SV_VL64 = 11,\n";
- OS << " SV_VL128 = 12,\n";
- OS << " SV_VL256 = 13,\n";
- OS << " SV_MUL4 = 29,\n";
- OS << " SV_MUL3 = 30,\n";
- OS << " SV_ALL = 31\n";
- OS << "};\n\n";
- OS << "enum svprfop\n";
- OS << "{\n";
- OS << " SV_PLDL1KEEP = 0,\n";
- OS << " SV_PLDL1STRM = 1,\n";
- OS << " SV_PLDL2KEEP = 2,\n";
- OS << " SV_PLDL2STRM = 3,\n";
- OS << " SV_PLDL3KEEP = 4,\n";
- OS << " SV_PLDL3STRM = 5,\n";
- OS << " SV_PSTL1KEEP = 8,\n";
- OS << " SV_PSTL1STRM = 9,\n";
- OS << " SV_PSTL2KEEP = 10,\n";
- OS << " SV_PSTL2STRM = 11,\n";
- OS << " SV_PSTL3KEEP = 12,\n";
- OS << " SV_PSTL3STRM = 13\n";
- OS << "};\n\n";
- OS << "/* Function attributes */\n";
- OS << "#define __ai static __inline__ __attribute__((__always_inline__, "
- "__nodebug__))\n\n";
- OS << "#define __aio static __inline__ __attribute__((__always_inline__, "
- "__nodebug__, __overloadable__))\n\n";
- // Add reinterpret functions.
- for (auto ShortForm : { false, true } )
- for (const ReinterpretTypeInfo &From : Reinterprets)
- for (const ReinterpretTypeInfo &To : Reinterprets) {
- const bool IsBFloat = StringRef(From.Suffix).equals("bf16") ||
- StringRef(To.Suffix).equals("bf16");
- if (IsBFloat)
- OS << "#if defined(__ARM_FEATURE_SVE_BF16)\n";
- if (ShortForm) {
- OS << "__aio " << From.Type << " svreinterpret_" << From.Suffix;
- OS << "(" << To.Type << " op) {\n";
- OS << " return __builtin_sve_reinterpret_" << From.Suffix << "_"
- << To.Suffix << "(op);\n";
- OS << "}\n\n";
- } else
- OS << "#define svreinterpret_" << From.Suffix << "_" << To.Suffix
- << "(...) __builtin_sve_reinterpret_" << From.Suffix << "_"
- << To.Suffix << "(__VA_ARGS__)\n";
- if (IsBFloat)
- OS << "#endif /* #if defined(__ARM_FEATURE_SVE_BF16) */\n";
- }
- SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
- std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
- for (auto *R : RV)
- createIntrinsic(R, Defs);
- // Sort intrinsics in header file by following order/priority:
- // - Architectural guard (i.e. does it require SVE2 or SVE2_AES)
- // - Class (is intrinsic overloaded or not)
- // - Intrinsic name
- std::stable_sort(
- Defs.begin(), Defs.end(), [](const std::unique_ptr<Intrinsic> &A,
- const std::unique_ptr<Intrinsic> &B) {
- auto ToTuple = [](const std::unique_ptr<Intrinsic> &I) {
- return std::make_tuple(I->getGuard(), (unsigned)I->getClassKind(), I->getName());
- };
- return ToTuple(A) < ToTuple(B);
- });
- StringRef InGuard = "";
- for (auto &I : Defs) {
- // Emit #endif/#if pair if needed.
- if (I->getGuard() != InGuard) {
- if (!InGuard.empty())
- OS << "#endif //" << InGuard << "\n";
- InGuard = I->getGuard();
- if (!InGuard.empty())
- OS << "\n#if " << InGuard << "\n";
- }
- // Actually emit the intrinsic declaration.
- I->emitIntrinsic(OS);
- }
- if (!InGuard.empty())
- OS << "#endif //" << InGuard << "\n";
- OS << "#if defined(__ARM_FEATURE_SVE_BF16)\n";
- OS << "#define svcvtnt_bf16_x svcvtnt_bf16_m\n";
- OS << "#define svcvtnt_bf16_f32_x svcvtnt_bf16_f32_m\n";
- OS << "#endif /*__ARM_FEATURE_SVE_BF16 */\n\n";
- OS << "#if defined(__ARM_FEATURE_SVE2)\n";
- OS << "#define svcvtnt_f16_x svcvtnt_f16_m\n";
- OS << "#define svcvtnt_f16_f32_x svcvtnt_f16_f32_m\n";
- OS << "#define svcvtnt_f32_x svcvtnt_f32_m\n";
- OS << "#define svcvtnt_f32_f64_x svcvtnt_f32_f64_m\n\n";
- OS << "#define svcvtxnt_f32_x svcvtxnt_f32_m\n";
- OS << "#define svcvtxnt_f32_f64_x svcvtxnt_f32_f64_m\n\n";
- OS << "#endif /*__ARM_FEATURE_SVE2 */\n\n";
- OS << "#ifdef __cplusplus\n";
- OS << "} // extern \"C\"\n";
- OS << "#endif\n\n";
- OS << "#endif /*__ARM_FEATURE_SVE */\n\n";
- OS << "#endif /* __ARM_SVE_H */\n";
- }
- void SVEEmitter::createBuiltins(raw_ostream &OS) {
- std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
- SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
- for (auto *R : RV)
- createIntrinsic(R, Defs);
- // The mappings must be sorted based on BuiltinID.
- llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A,
- const std::unique_ptr<Intrinsic> &B) {
- return A->getMangledName() < B->getMangledName();
- });
- OS << "#ifdef GET_SVE_BUILTINS\n";
- for (auto &Def : Defs) {
- // Only create BUILTINs for non-overloaded intrinsics, as overloaded
- // declarations only live in the header file.
- if (Def->getClassKind() != ClassG)
- OS << "BUILTIN(__builtin_sve_" << Def->getMangledName() << ", \""
- << Def->getBuiltinTypeStr() << "\", \"n\")\n";
- }
- // Add reinterpret builtins
- for (const ReinterpretTypeInfo &From : Reinterprets)
- for (const ReinterpretTypeInfo &To : Reinterprets)
- OS << "BUILTIN(__builtin_sve_reinterpret_" << From.Suffix << "_"
- << To.Suffix << +", \"" << From.BuiltinType << To.BuiltinType
- << "\", \"n\")\n";
- OS << "#endif\n\n";
- }
- void SVEEmitter::createCodeGenMap(raw_ostream &OS) {
- std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
- SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
- for (auto *R : RV)
- createIntrinsic(R, Defs);
- // The mappings must be sorted based on BuiltinID.
- llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A,
- const std::unique_ptr<Intrinsic> &B) {
- return A->getMangledName() < B->getMangledName();
- });
- OS << "#ifdef GET_SVE_LLVM_INTRINSIC_MAP\n";
- for (auto &Def : Defs) {
- // Builtins only exist for non-overloaded intrinsics, overloaded
- // declarations only live in the header file.
- if (Def->getClassKind() == ClassG)
- continue;
- uint64_t Flags = Def->getFlags();
- auto FlagString = std::to_string(Flags);
- std::string LLVMName = Def->getLLVMName();
- std::string Builtin = Def->getMangledName();
- if (!LLVMName.empty())
- OS << "SVEMAP1(" << Builtin << ", " << LLVMName << ", " << FlagString
- << "),\n";
- else
- OS << "SVEMAP2(" << Builtin << ", " << FlagString << "),\n";
- }
- OS << "#endif\n\n";
- }
- void SVEEmitter::createRangeChecks(raw_ostream &OS) {
- std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
- SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
- for (auto *R : RV)
- createIntrinsic(R, Defs);
- // The mappings must be sorted based on BuiltinID.
- llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A,
- const std::unique_ptr<Intrinsic> &B) {
- return A->getMangledName() < B->getMangledName();
- });
- OS << "#ifdef GET_SVE_IMMEDIATE_CHECK\n";
- // Ensure these are only emitted once.
- std::set<std::string> Emitted;
- for (auto &Def : Defs) {
- if (Emitted.find(Def->getMangledName()) != Emitted.end() ||
- Def->getImmChecks().empty())
- continue;
- OS << "case SVE::BI__builtin_sve_" << Def->getMangledName() << ":\n";
- for (auto &Check : Def->getImmChecks())
- OS << "ImmChecks.push_back(std::make_tuple(" << Check.getArg() << ", "
- << Check.getKind() << ", " << Check.getElementSizeInBits() << "));\n";
- OS << " break;\n";
- Emitted.insert(Def->getMangledName());
- }
- OS << "#endif\n\n";
- }
- /// Create the SVETypeFlags used in CGBuiltins
- void SVEEmitter::createTypeFlags(raw_ostream &OS) {
- OS << "#ifdef LLVM_GET_SVE_TYPEFLAGS\n";
- for (auto &KV : FlagTypes)
- OS << "const uint64_t " << KV.getKey() << " = " << KV.getValue() << ";\n";
- OS << "#endif\n\n";
- OS << "#ifdef LLVM_GET_SVE_ELTTYPES\n";
- for (auto &KV : EltTypes)
- OS << " " << KV.getKey() << " = " << KV.getValue() << ",\n";
- OS << "#endif\n\n";
- OS << "#ifdef LLVM_GET_SVE_MEMELTTYPES\n";
- for (auto &KV : MemEltTypes)
- OS << " " << KV.getKey() << " = " << KV.getValue() << ",\n";
- OS << "#endif\n\n";
- OS << "#ifdef LLVM_GET_SVE_MERGETYPES\n";
- for (auto &KV : MergeTypes)
- OS << " " << KV.getKey() << " = " << KV.getValue() << ",\n";
- OS << "#endif\n\n";
- OS << "#ifdef LLVM_GET_SVE_IMMCHECKTYPES\n";
- for (auto &KV : ImmCheckTypes)
- OS << " " << KV.getKey() << " = " << KV.getValue() << ",\n";
- OS << "#endif\n\n";
- }
- namespace clang {
- void EmitSveHeader(RecordKeeper &Records, raw_ostream &OS) {
- SVEEmitter(Records).createHeader(OS);
- }
- void EmitSveBuiltins(RecordKeeper &Records, raw_ostream &OS) {
- SVEEmitter(Records).createBuiltins(OS);
- }
- void EmitSveBuiltinCG(RecordKeeper &Records, raw_ostream &OS) {
- SVEEmitter(Records).createCodeGenMap(OS);
- }
- void EmitSveRangeChecks(RecordKeeper &Records, raw_ostream &OS) {
- SVEEmitter(Records).createRangeChecks(OS);
- }
- void EmitSveTypeFlags(RecordKeeper &Records, raw_ostream &OS) {
- SVEEmitter(Records).createTypeFlags(OS);
- }
- } // End namespace clang
|