Index: clang/include/clang/Basic/TargetBuiltins.h =================================================================== --- clang/include/clang/Basic/TargetBuiltins.h +++ clang/include/clang/Basic/TargetBuiltins.h @@ -17,6 +17,7 @@ #include #include "clang/Basic/Builtins.h" +#include "llvm/Support/MathExtras.h" #undef PPC namespace clang { @@ -163,6 +164,9 @@ /// Flags to identify the types for overloaded SVE builtins. class SVETypeFlags { uint64_t Flags; + unsigned EltTypeShift; + unsigned MemEltTypeShift; + unsigned MergeTypeShift; public: #define LLVM_GET_SVE_TYPEFLAGS @@ -181,15 +185,27 @@ #undef LLVM_GET_SVE_MEMELTTYPES }; - SVETypeFlags(uint64_t F) : Flags(F) {} - SVETypeFlags(EltType ET, bool IsUnsigned) : Flags(ET) {} + enum MergeType { +#define LLVM_GET_SVE_MERGETYPES +#include "clang/Basic/arm_sve_typeflags.inc" +#undef LLVM_GET_SVE_MERGETYPES + }; + SVETypeFlags(uint64_t F) : Flags(F) { + EltTypeShift = llvm::countTrailingZeros(EltTypeMask); + MemEltTypeShift = llvm::countTrailingZeros(MemEltTypeMask); + MergeTypeShift = llvm::countTrailingZeros(MergeTypeMask); + } EltType getEltType() const { - return (EltType)((Flags & EltTypeMask) - FirstEltType); + return (EltType)((Flags & EltTypeMask) >> EltTypeShift); } MemEltType getMemEltType() const { - return (MemEltType)((Flags & MemEltTypeMask) - FirstMemEltType); + return (MemEltType)((Flags & MemEltTypeMask) >> MemEltTypeShift); + } + + MergeType getMergeType() const { + return (MergeType)((Flags & MergeTypeMask) >> MergeTypeShift); } bool isLoad() const { return Flags & IsLoad; } Index: clang/include/clang/Basic/arm_sve.td =================================================================== --- clang/include/clang/Basic/arm_sve.td +++ clang/include/clang/Basic/arm_sve.td @@ -84,15 +84,16 @@ // Y: const pointer to uint32_t // Z: const pointer to uint64_t -class MergeType { +class MergeType { int Value = val; + string Suffix = suffix; } def MergeNone : MergeType<0>; -def MergeAny : MergeType<1>; -def MergeOp1 : MergeType<2>; -def MergeZero : MergeType<3>; -def MergeAnyExp : MergeType<4>; // Use merged builtin with explicit -def MergeZeroExp : MergeType<5>; // generation of its inactive argument. +def MergeAny : MergeType<1, "_x">; +def MergeOp1 : MergeType<2, "_m">; +def MergeZero : MergeType<3, "_z">; +def MergeAnyExp : MergeType<4, "_x">; // Use merged builtin with explicit +def MergeZeroExp : MergeType<5, "_z">; // generation of its inactive argument. class EltType { int Value = val; @@ -134,13 +135,17 @@ // : : // : : def MemEltTypeMask : FlagType<0x00000070>; -def IsLoad : FlagType<0x00000080>; -def IsStore : FlagType<0x00000100>; -def IsGatherLoad : FlagType<0x00000200>; -def IsScatterStore : FlagType<0x00000400>; -def IsStructLoad : FlagType<0x00000800>; -def IsStructStore : FlagType<0x00001000>; -def IsZExtReturn : FlagType<0x00002000>; // Return value is sign-extend by default +def FirstMergeTypeMask : FlagType<0x00000080>; +// : : +// : : +def MergeTypeMask : FlagType<0x00000380>; +def IsLoad : FlagType<0x00002000>; +def IsStore : FlagType<0x00004000>; +def IsGatherLoad : FlagType<0x00008000>; +def IsScatterStore : FlagType<0x00010000>; +def IsStructLoad : FlagType<0x00020000>; +def IsStructStore : FlagType<0x00040000>; +def IsZExtReturn : FlagType<0x00080000>; // Return value is sign-extend by default // Every intrinsic subclasses Inst. class Inst Flags = ft; int MemEltType = met.Value; Index: clang/utils/TableGen/SveEmitter.cpp =================================================================== --- clang/utils/TableGen/SveEmitter.cpp +++ clang/utils/TableGen/SveEmitter.cpp @@ -65,9 +65,6 @@ applyModifier(CharMod); } - /// Return the value in SVETypeFlags for this type. - unsigned getTypeFlags() const; - bool isPointer() const { return Pointer; } bool isVoidPointer() const { return Pointer && Void; } bool isSigned() const { return Signed; } @@ -138,36 +135,22 @@ /// 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 Types; /// The "base type", which is VarType('d', BaseTypeSpec). SVEType BaseType; - unsigned Flags; + uint64_t Flags; public: - /// The type of predication. - enum MergeType { - MergeNone, - MergeAny, - MergeOp1, - MergeZero, - MergeAnyExp, - MergeZeroExp, - MergeInvalid - } Merge; - - Intrinsic(StringRef Name, StringRef Proto, int64_t MT, StringRef LLVMName, - unsigned Flags, TypeSpec BT, ClassKind Class, SVEEmitter &Emitter, - StringRef Guard) - : Name(Name.str()), LLVMName(LLVMName), Proto(Proto.str()), - BaseTypeSpec(BT), Class(Class), Guard(Guard.str()), BaseType(BT, 'd'), - Flags(Flags), Merge(MergeType(MT)) { - // Types[0] is the return value. - for (unsigned I = 0; I < Proto.size(); ++I) - Types.emplace_back(BaseTypeSpec, Proto[I]); - } + Intrinsic(StringRef Name, StringRef Proto, uint64_t MergeTy, + StringRef MergeSuffix, uint64_t MemoryElementTy, StringRef LLVMName, + uint64_t Flags, TypeSpec BT, ClassKind Class, SVEEmitter &Emitter, + StringRef Guard); ~Intrinsic()=default; @@ -179,14 +162,13 @@ StringRef getGuard() const { return Guard; } ClassKind getClassKind() const { return Class; } - MergeType getMergeType() const { return Merge; } SVEType getReturnType() const { return Types[0]; } ArrayRef getTypes() const { return Types; } SVEType getParamType(unsigned I) const { return Types[I + 1]; } unsigned getNumParams() const { return Proto.size() - 1; } - unsigned getFlags() const { return Flags; } + uint64_t getFlags() const { return Flags; } bool isFlagSet(uint64_t Flag) const { return Flags & Flag;} /// Return the type string for a BUILTIN() macro in Builtins.def. @@ -209,7 +191,7 @@ void emitIntrinsic(raw_ostream &OS) const; private: - std::string getMergeSuffix() const; + std::string getMergeSuffix() const { return MergeSuffix; } std::string mangleName(ClassKind LocalCK) const; std::string replaceTemplatedArgs(std::string Name, TypeSpec TS, std::string Proto) const; @@ -221,8 +203,8 @@ llvm::StringMap EltTypes; llvm::StringMap MemEltTypes; llvm::StringMap FlagTypes; + llvm::StringMap MergeTypes; - unsigned getTypeFlags(const SVEType &T); public: SVEEmitter(RecordKeeper &R) : Records(R) { for (auto *RV : Records.getAllDerivedDefinitions("EltType")) @@ -231,8 +213,56 @@ 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"); + } + + /// Returns the enum value for the flag type + unsigned 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. + unsigned encodeFlag(unsigned 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. + unsigned 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. + unsigned encodeMemoryElementType(unsigned MT) { + return encodeFlag(MT, "MemEltTypeMask"); + } + + // Returns the SVETypeFlags for the given merge type. + unsigned encodeMergeType(unsigned 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. + unsigned encodeTypeFlags(const SVEType &T); + /// Emit arm_sve.h. void createHeader(raw_ostream &o); @@ -256,36 +286,6 @@ // Type implementation //===----------------------------------------------------------------------===// -unsigned SVEEmitter::getTypeFlags(const SVEType &T) { - unsigned FirstEltType = EltTypes["FirstEltType"]; - if (T.isFloat()) { - switch (T.getElementSizeInBits()) { - case 16: return FirstEltType + EltTypes["EltTyFloat16"]; - case 32: return FirstEltType + EltTypes["EltTyFloat32"]; - case 64: return FirstEltType + EltTypes["EltTyFloat64"]; - default: llvm_unreachable("Unhandled float element bitwidth!"); - } - } - - if (T.isPredicateVector()) { - switch (T.getElementSizeInBits()) { - case 8: return FirstEltType + EltTypes["EltTyBool8"]; - case 16: return FirstEltType + EltTypes["EltTyBool16"]; - case 32: return FirstEltType + EltTypes["EltTyBool32"]; - case 64: return FirstEltType + EltTypes["EltTyBool64"]; - default: llvm_unreachable("Unhandled predicate element bitwidth!"); - } - } - - switch (T.getElementSizeInBits()) { - case 8: return FirstEltType + EltTypes["EltTyInt8"]; - case 16: return FirstEltType + EltTypes["EltTyInt16"]; - case 32: return FirstEltType + EltTypes["EltTyInt32"]; - case 64: return FirstEltType + EltTypes["EltTyInt64"]; - default: llvm_unreachable("Unhandled integer element bitwidth!"); - } -} - std::string SVEType::builtin_str() const { std::string S; if (isVoid()) @@ -543,6 +543,26 @@ // Intrinsic implementation //===----------------------------------------------------------------------===// +Intrinsic::Intrinsic(StringRef Name, StringRef Proto, uint64_t MergeTy, + StringRef MergeSuffix, uint64_t MemoryElementTy, + StringRef LLVMName, uint64_t Flags, 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) { + + // Types[0] is the return value. + for (unsigned I = 0; I < Proto.size(); ++I) { + SVEType T(BaseTypeSpec, Proto[I]); + Types.push_back(T); + } + + // Set flags based on properties + this->Flags |= Emitter.encodeTypeFlags(BaseType); + this->Flags |= Emitter.encodeMemoryElementType(MemoryElementTy); + this->Flags |= Emitter.encodeMergeType(MergeTy); +} + std::string Intrinsic::getBuiltinTypeStr() { std::string S; @@ -601,20 +621,6 @@ return Ret; } -// ACLE function names have a merge style postfix. -std::string Intrinsic::getMergeSuffix() const { - switch (getMergeType()) { - default: - llvm_unreachable("Unknown predication specifier"); - case MergeNone: return ""; - case MergeAny: - case MergeAnyExp: return "_x"; - case MergeOp1: return "_m"; - case MergeZero: - case MergeZeroExp: return "_z"; - } -} - std::string Intrinsic::mangleName(ClassKind LocalCK) const { std::string S = getName(); @@ -668,6 +674,49 @@ //===----------------------------------------------------------------------===// // SVEEmitter implementation //===----------------------------------------------------------------------===// +unsigned 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.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> &Out) { StringRef Name = R->getValueAsString("Name"); @@ -675,13 +724,14 @@ StringRef Types = R->getValueAsString("Types"); StringRef Guard = R->getValueAsString("ArchGuard"); StringRef LLVMName = R->getValueAsString("LLVMIntrinsic"); - int64_t Merge = R->getValueAsInt("Merge"); + uint64_t Merge = R->getValueAsInt("Merge"); + StringRef MergeSuffix = R->getValueAsString("MergeSuffix"); + uint64_t MemEltType = R->getValueAsInt("MemEltType"); std::vector FlagsList = R->getValueAsListOfDefs("Flags"); int64_t Flags = 0; for (auto FlagRec : FlagsList) Flags |= FlagRec->getValueAsInt("Value"); - Flags |= R->getValueAsInt("MemEltType") + MemEltTypes["FirstMemEltType"]; // Extract type specs from string SmallVector TypeSpecs; @@ -701,14 +751,15 @@ // Create an Intrinsic for each type spec. for (auto TS : TypeSpecs) { - Out.push_back(std::make_unique(Name, Proto, Merge, - LLVMName, Flags, TS, ClassS, - *this, Guard)); + Out.push_back(std::make_unique(Name, Proto, Merge, MergeSuffix, + MemEltType, LLVMName, Flags, 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( - Name, Proto, Merge, LLVMName, Flags, TS, ClassG, *this, Guard)); + Out.push_back(std::make_unique(Name, Proto, Merge, MergeSuffix, + MemEltType, LLVMName, Flags, TS, + ClassG, *this, Guard)); } } @@ -846,7 +897,7 @@ if (Def->getClassKind() == ClassG) continue; - uint64_t Flags = Def->getFlags() | getTypeFlags(Def->getBaseType()); + uint64_t Flags = Def->getFlags(); auto FlagString = std::to_string(Flags); std::string LLVMName = Def->getLLVMName(); @@ -876,6 +927,11 @@ 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"; } namespace clang {