https://github.com/SpencerAbson updated https://github.com/llvm/llvm-project/pull/117717
>From 850b7c0173f47a382093ff345d9bf35ee9e1643e Mon Sep 17 00:00:00 2001 From: Spencer Abson <spencer.ab...@arm.com> Date: Tue, 26 Nov 2024 13:49:12 +0000 Subject: [PATCH 1/8] Refactor parts of SveEmitter.cpp --- clang/include/clang/Basic/arm_sve.td | 28 +- ...#12752a66d88e6d5bc8de5376bca6898e3e71f901# | 1874 +++++++++++++++++ clang/utils/TableGen/SveEmitter.cpp | 369 ++-- 3 files changed, 2048 insertions(+), 223 deletions(-) create mode 100644 clang/utils/TableGen/#12752a66d88e6d5bc8de5376bca6898e3e71f901# diff --git a/clang/include/clang/Basic/arm_sve.td b/clang/include/clang/Basic/arm_sve.td index b36e592042da0b..e551d6e46b8f33 100644 --- a/clang/include/clang/Basic/arm_sve.td +++ b/clang/include/clang/Basic/arm_sve.td @@ -762,14 +762,14 @@ def SVCMPLS_WIDE_N : SInst<"svcmple_wide[_n_{d}]", "PPdj", "UcUsUi", MergeNone, //////////////////////////////////////////////////////////////////////////////// // While comparisons -def SVWHILELE_S32 : SInst<"svwhilele_{d}[_{1}]", "Pkk", "PcPsPiPl", MergeNone, "aarch64_sve_whilele", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>; -def SVWHILELE_S64 : SInst<"svwhilele_{d}[_{1}]", "Pll", "PcPsPiPl", MergeNone, "aarch64_sve_whilele", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>; -def SVWHILELO_U32 : SInst<"svwhilelt_{d}[_{1}]", "Pmm", "PUcPUsPUiPUl", MergeNone, "aarch64_sve_whilelo", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>; -def SVWHILELO_U64 : SInst<"svwhilelt_{d}[_{1}]", "Pnn", "PUcPUsPUiPUl", MergeNone, "aarch64_sve_whilelo", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>; -def SVWHILELS_U32 : SInst<"svwhilele_{d}[_{1}]", "Pmm", "PUcPUsPUiPUl", MergeNone, "aarch64_sve_whilels", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>; -def SVWHILELS_U64 : SInst<"svwhilele_{d}[_{1}]", "Pnn", "PUcPUsPUiPUl", MergeNone, "aarch64_sve_whilels", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>; -def SVWHILELT_S32 : SInst<"svwhilelt_{d}[_{1}]", "Pkk", "PcPsPiPl", MergeNone, "aarch64_sve_whilelt", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>; -def SVWHILELT_S64 : SInst<"svwhilelt_{d}[_{1}]", "Pll", "PcPsPiPl", MergeNone, "aarch64_sve_whilelt", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>; +def SVWHILELE_S32 : SInst<"svwhilele_{d}[_{1}]", "Pkk", "PcPsPiPl", MergeNone, "aarch64_sve_whilele", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>; +def SVWHILELE_S64 : SInst<"svwhilele_{d}[_{1}]", "Pll", "PcPsPiPl", MergeNone, "aarch64_sve_whilele", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>; +def SVWHILELO_U32 : SInst<"svwhilelt_{d}[_{1}]", "Pmm", "PcPsPiPl", MergeNone, "aarch64_sve_whilelo", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>; +def SVWHILELO_U64 : SInst<"svwhilelt_{d}[_{1}]", "Pnn", "PcPsPiPl", MergeNone, "aarch64_sve_whilelo", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>; +def SVWHILELS_U32 : SInst<"svwhilele_{d}[_{1}]", "Pmm", "PcPsPiPl", MergeNone, "aarch64_sve_whilels", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>; +def SVWHILELS_U64 : SInst<"svwhilele_{d}[_{1}]", "Pnn", "PcPsPiPl", MergeNone, "aarch64_sve_whilels", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>; +def SVWHILELT_S32 : SInst<"svwhilelt_{d}[_{1}]", "Pkk", "PcPsPiPl", MergeNone, "aarch64_sve_whilelt", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>; +def SVWHILELT_S64 : SInst<"svwhilelt_{d}[_{1}]", "Pll", "PcPsPiPl", MergeNone, "aarch64_sve_whilelt", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>; //////////////////////////////////////////////////////////////////////////////// // Counting bit @@ -1365,10 +1365,10 @@ def SVWHILEGE_S32 : SInst<"svwhilege_{d}[_{1}]", "Pkk", "PcPsPiPl", MergeNon def SVWHILEGE_S64 : SInst<"svwhilege_{d}[_{1}]", "Pll", "PcPsPiPl", MergeNone, "aarch64_sve_whilege", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>; def SVWHILEGT_S32 : SInst<"svwhilegt_{d}[_{1}]", "Pkk", "PcPsPiPl", MergeNone, "aarch64_sve_whilegt", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>; def SVWHILEGT_S64 : SInst<"svwhilegt_{d}[_{1}]", "Pll", "PcPsPiPl", MergeNone, "aarch64_sve_whilegt", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>; -def SVWHILEHI_U32 : SInst<"svwhilegt_{d}[_{1}]", "Pmm", "PUcPUsPUiPUl", MergeNone, "aarch64_sve_whilehi", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>; -def SVWHILEHI_U64 : SInst<"svwhilegt_{d}[_{1}]", "Pnn", "PUcPUsPUiPUl", MergeNone, "aarch64_sve_whilehi", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>; -def SVWHILEHS_U32 : SInst<"svwhilege_{d}[_{1}]", "Pmm", "PUcPUsPUiPUl", MergeNone, "aarch64_sve_whilehs", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>; -def SVWHILEHS_U64 : SInst<"svwhilege_{d}[_{1}]", "Pnn", "PUcPUsPUiPUl", MergeNone, "aarch64_sve_whilehs", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>; +def SVWHILEHI_U32 : SInst<"svwhilegt_{d}[_{1}]", "Pmm", "PcPsPiPl", MergeNone, "aarch64_sve_whilehi", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>; +def SVWHILEHI_U64 : SInst<"svwhilegt_{d}[_{1}]", "Pnn", "PcPsPiPl", MergeNone, "aarch64_sve_whilehi", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>; +def SVWHILEHS_U32 : SInst<"svwhilege_{d}[_{1}]", "Pmm", "PcPsPiPl", MergeNone, "aarch64_sve_whilehs", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>; +def SVWHILEHS_U64 : SInst<"svwhilege_{d}[_{1}]", "Pnn", "PcPsPiPl", MergeNone, "aarch64_sve_whilehs", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>; } let SVETargetGuard = "sve2p1", SMETargetGuard = "sme2" in { @@ -2326,7 +2326,7 @@ let SVETargetGuard = "sve2p1,bf16", SMETargetGuard = "sme2p1,bf16" in { // Multi-vector convert to/from floating-point. // let SVETargetGuard = InvalidMode, SMETargetGuard = "sme2" in { - def SVCVT_F16_X2 : SInst<"svcvt_f16[_f32_x2]", "e2", "f", MergeNone, "aarch64_sve_fcvt_x2", [IsStreaming],[]>; + def SVCVT_F16_X2 : SInst<"svcvt_f16[_f32_x2]", "h2", "f", MergeNone, "aarch64_sve_fcvt_x2", [IsStreaming],[]>; def SVCVT_BF16_X2 : SInst<"svcvt_bf16[_f32_x2]", "$2", "f", MergeNone, "aarch64_sve_bfcvt_x2", [IsOverloadNone, IsStreaming],[]>; def SVCVT_F32_U32_X2 : SInst<"svcvt_{d}[_u32_x2]", "2.d2.u", "f", MergeNone, "aarch64_sve_ucvtf_x2", [IsStreaming, IsOverloadWhileOrMultiVecCvt], []>; @@ -2348,7 +2348,7 @@ let SVETargetGuard = InvalidMode, SMETargetGuard = "sme-f16f16" in { // Multi-vector floating-point convert from single-precision to interleaved half-precision/BFloat16 // let SVETargetGuard = InvalidMode, SMETargetGuard = "sme2" in { - def SVCVTN_F16_X2 : SInst<"svcvtn_f16[_f32_x2]", "e2", "f", MergeNone, "aarch64_sve_fcvtn_x2", [IsStreaming],[]>; + def SVCVTN_F16_X2 : SInst<"svcvtn_f16[_f32_x2]", "h2", "f", MergeNone, "aarch64_sve_fcvtn_x2", [IsStreaming],[]>; def SVCVTN_BF16_X2 : SInst<"svcvtn_bf16[_f32_x2]", "$2", "f", MergeNone, "aarch64_sve_bfcvtn_x2", [IsOverloadNone, IsStreaming],[]>; } diff --git a/clang/utils/TableGen/#12752a66d88e6d5bc8de5376bca6898e3e71f901# b/clang/utils/TableGen/#12752a66d88e6d5bc8de5376bca6898e3e71f901# new file mode 100644 index 00000000000000..40a798928f4d69 --- /dev/null +++ b/clang/utils/TableGen/#12752a66d88e6d5bc8de5376bca6898e3e71f901# @@ -0,0 +1,1874 @@ +//===- 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/ArrayRef.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/TableGen/Error.h" +#include "llvm/TableGen/Record.h" +#include "ImmCheck.h" +#include <array> +#include <cctype> +#include <set> +#include <sstream> +#include <string> +#include <tuple> + +using namespace llvm; + +enum ClassKind { + ClassNone, + ClassS, // signed/unsigned, e.g., "_s8", "_u8" suffix + ClassG, // Overloaded name without type suffix +}; + +enum class ACLEKind { SVE, SME }; + +using TypeSpec = std::string; + +namespace { +class SVEType { + bool Float, Signed, Immediate, Void, Constant, Pointer, BFloat; + bool DefaultType, IsScalable, Predicate, PredicatePattern, PrefetchOp, + Svcount; + unsigned Bitwidth, ElementBitwidth, NumVectors; + +public: + SVEType() : SVEType("", 'v') {} + + SVEType(StringRef TS, char CharMod, unsigned NumVectors = 1) + : Float(false), Signed(true), Immediate(false), Void(false), + Constant(false), Pointer(false), BFloat(false), DefaultType(false), + IsScalable(true), Predicate(false), PredicatePattern(false), + PrefetchOp(false), Svcount(false), Bitwidth(128), ElementBitwidth(~0U), + NumVectors(NumVectors) { + if (!TS.empty()) + applyTypespec(TS); + applyModifier(CharMod); + } + + SVEType(const SVEType &Base, unsigned NumV) : SVEType(Base) { + NumVectors = NumV; + } + + 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 isFixedLengthVector() 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 && !Svcount; + } + bool isScalarPredicate() const { + return !isFloatingPoint() && Predicate && NumVectors == 0; + } + bool isPredicateVector() const { return Predicate; } + bool isPredicatePattern() const { return PredicatePattern; } + bool isPrefetchOp() const { return PrefetchOp; } + bool isSvcount() const { return Svcount; } + 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(StringRef TS); + + /// 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 SVEGuard, SMEGuard; + + // 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 SVEGuard, + StringRef SMEGuard); + + ~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 getSVEGuard() const { return SVEGuard; } + StringRef getSMEGuard() const { return SMEGuard; } + void printGuard(raw_ostream &OS) const { + if (!SVEGuard.empty() && SMEGuard.empty()) + OS << SVEGuard; + else if (SVEGuard.empty() && !SMEGuard.empty()) + OS << SMEGuard; + else { + if (SVEGuard.find(",") != std::string::npos || + SVEGuard.find("|") != std::string::npos) + OS << "(" << SVEGuard << ")"; + else + OS << SVEGuard; + OS << "|"; + if (SMEGuard.find(",") != std::string::npos || + SMEGuard.find("|") != std::string::npos) + OS << "(" << SMEGuard << ")"; + else + OS << SMEGuard; + } + } + 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() - (2 * llvm::count(Proto, '.')) - 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); } + + /// As above, but mangles the LLVM name instead. + std::string getMangledLLVMName() const { return mangleLLVMName(); } + + /// 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 { + unsigned I = 1, Param = 0; + for (; I < Proto.size(); ++I, ++Param) { + if (Proto[I] == 'a' || Proto[I] == 'j' || Proto[I] == 'f' || + Proto[I] == 'r' || Proto[I] == 'K' || Proto[I] == 'L' || + Proto[I] == 'R' || Proto[I] == '@') + break; + + // Multivector modifier can be skipped + if (Proto[I] == '.') + I += 2; + } + assert(I != Proto.size() && "Prototype has no splat operand"); + return Param; + } + + /// Emits the intrinsic declaration to the ostream. + void emitIntrinsic(raw_ostream &OS, SVEEmitter &Emitter, ACLEKind Kind) const; + +private: + std::string getMergeSuffix() const { return MergeSuffix; } + std::string mangleName(ClassKind LocalCK) const; + std::string mangleLLVMName() 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 { + SVEType BaseType; + const char *Suffix; + }; + + static const std::array<ReinterpretTypeInfo, 12> Reinterprets; + + 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::countr_zero(Mask); + assert(Shift < 64 && "Mask value produced an invalid shift value"); + 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); + + // Emits core intrinsics in both arm_sme.h and arm_sve.h + void createCoreHeaderIntrinsics(raw_ostream &o, SVEEmitter &Emitter, + ACLEKind Kind); + + /// 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); + + /// Emit arm_sme.h. + void createSMEHeader(raw_ostream &o); + + /// Emit all the SME __builtin prototypes and code needed by Sema. + void createSMEBuiltins(raw_ostream &o); + + /// Emit all the information needed to map builtin -> LLVM IR intrinsic. + void createSMECodeGenMap(raw_ostream &o); + + /// Create a table for a builtin's requirement for PSTATE.SM. + void createStreamingAttrs(raw_ostream &o, ACLEKind Kind); + + /// Emit all the range checks for the immediates. + void createSMERangeChecks(raw_ostream &o); + + /// Create a table for a builtin's requirement for PSTATE.ZA. + void createBuiltinZAState(raw_ostream &OS); + + /// Create intrinsic and add it to \p Out + void createIntrinsic(Record *R, + SmallVectorImpl<std::unique_ptr<Intrinsic>> &Out); +}; + +const std::array<SVEEmitter::ReinterpretTypeInfo, 12> SVEEmitter::Reinterprets = + {{{SVEType("c", 'd'), "s8"}, + {SVEType("Uc", 'd'), "u8"}, + {SVEType("s", 'd'), "s16"}, + {SVEType("Us", 'd'), "u16"}, + {SVEType("i", 'd'), "s32"}, + {SVEType("Ui", 'd'), "u32"}, + {SVEType("l", 'd'), "s64"}, + {SVEType("Ul", 'd'), "u64"}, + {SVEType("h", 'd'), "f16"}, + {SVEType("b", 'd'), "bf16"}, + {SVEType("f", 'd'), "f32"}, + {SVEType("d", 'd'), "f64"}}}; + +} // end anonymous namespace + + +//===----------------------------------------------------------------------===// +// Type implementation +//===----------------------------------------------------------------------===// + +std::string SVEType::builtin_str() const { + std::string S; + if (isVoid()) + return "v"; + + if (isScalarPredicate()) + return "b"; + + if (isSvcount()) + return "Qa"; + + 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; + } + + if (isFixedLengthVector()) + return "V" + utostr(getNumElements() * NumVectors) + S; + 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() || isSvcount()) + S += "sv"; + if (!Signed && !isFloatingPoint()) + S += "u"; + + if (Float) + S += "float"; + else if (isSvcount()) + S += "count"; + else if (isScalarPredicate() || isPredicateVector()) + S += "bool"; + else if (isBFloat()) + S += "bfloat"; + else + S += "int"; + + if (!isScalarPredicate() && !isPredicateVector() && !isSvcount()) + S += utostr(ElementBitwidth); + if (isFixedLengthVector()) + 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(StringRef TS) { + for (char I : TS) { + switch (I) { + case 'Q': + Svcount = true; + break; + 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 'q': + ElementBitwidth = 128; + 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 'v': + Void = true; + break; + case 'd': + DefaultType = true; + break; + case 'c': + Constant = true; + [[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; + Svcount = false; + Bitwidth = 16; + ElementBitwidth = 1; + break; + case '{': + IsScalable = false; + Bitwidth = 128; + NumVectors = 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; + Svcount = false; + Signed = false; + Float = false; + BFloat = false; + break; + case 'x': + Predicate = false; + Svcount = false; + Signed = true; + Float = false; + BFloat = false; + break; + case 'i': + Predicate = false; + Svcount = false; + Float = false; + BFloat = false; + ElementBitwidth = Bitwidth = 64; + NumVectors = 0; + Signed = false; + Immediate = true; + break; + case 'I': + Predicate = false; + Svcount = false; + Float = false; + BFloat = false; + ElementBitwidth = Bitwidth = 32; + NumVectors = 0; + Signed = true; + Immediate = true; + PredicatePattern = true; + break; + case 'J': + Predicate = false; + Svcount = false; + Float = false; + BFloat = false; + ElementBitwidth = Bitwidth = 32; + NumVectors = 0; + Signed = true; + Immediate = true; + PrefetchOp = true; + break; + case 'k': + Predicate = false; + Svcount = false; + Signed = true; + Float = false; + BFloat = false; + ElementBitwidth = Bitwidth = 32; + NumVectors = 0; + break; + case 'l': + Predicate = false; + Svcount = false; + Signed = true; + Float = false; + BFloat = false; + ElementBitwidth = Bitwidth = 64; + NumVectors = 0; + break; + case 'm': + Predicate = false; + Svcount = false; + Signed = false; + Float = false; + BFloat = false; + ElementBitwidth = Bitwidth = 32; + NumVectors = 0; + break; + case 'n': + Predicate = false; + Svcount = 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 '[': + Signed = false; + Float = false; + BFloat = false; + ElementBitwidth = 8; + 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; + Svcount = false; + Float = true; + ElementBitwidth = 16; + break; + case 'M': + Predicate = false; + Svcount = false; + Float = true; + BFloat = false; + ElementBitwidth = 32; + break; + case 'N': + Predicate = false; + Svcount = 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 '%': + Pointer = true; + Void = true; + NumVectors = 0; + 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; + case '$': + Predicate = false; + Svcount = false; + Float = false; + BFloat = true; + ElementBitwidth = 16; + break; + case '}': + Predicate = false; + Signed = true; + Svcount = true; + NumVectors = 0; + Float = false; + BFloat = false; + break; + case '.': + llvm_unreachable(". is never a type in itself"); + break; + default: + llvm_unreachable("Unhandled character!"); + } +} + +/// Returns the modifier and number of vectors for the given operand \p Op. +std::pair<char, unsigned> getProtoModifier(StringRef Proto, unsigned Op) { + for (unsigned P = 0; !Proto.empty(); ++P) { + unsigned NumVectors = 1; + unsigned CharsToSkip = 1; + char Mod = Proto[0]; + if (Mod == '2' || Mod == '3' || Mod == '4') { + NumVectors = Mod - '0'; + Mod = 'd'; + if (Proto.size() > 1 && Proto[1] == '.') { + Mod = Proto[2]; + CharsToSkip = 3; + } + } + + if (P == Op) + return {Mod, NumVectors}; + + Proto = Proto.drop_front(CharsToSkip); + } + llvm_unreachable("Unexpected Op"); +} + +//===----------------------------------------------------------------------===// +// 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 SVEGuard, + StringRef SMEGuard) + : Name(Name.str()), LLVMName(LLVMName), Proto(Proto.str()), + BaseTypeSpec(BT), Class(Class), SVEGuard(SVEGuard.str()), + SMEGuard(SMEGuard.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 < (getNumParams() + 1); ++I) { + char Mod; + unsigned NumVectors; + std::tie(Mod, NumVectors) = getProtoModifier(Proto, I); + SVEType T(BaseTypeSpec, Mod, NumVectors); + 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.isSvcount()) + TypeCode = 'c'; + 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::mangleLLVMName() const { + std::string S = getLLVMName(); + + // Replace all {d} like expressions with e.g. 'u32' + return replaceTemplatedArgs(S, getBaseTypeSpec(), getProto()); +} + +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, SVEEmitter &Emitter, + ACLEKind Kind) 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("; + + switch (Kind) { + case ACLEKind::SME: + OS << "__builtin_sme_" << FullName << ")"; + break; + case ACLEKind::SVE: + OS << "__builtin_sve_" << FullName << ")"; + break; + } + + OS << "))\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() || T.isSvcount()) { + 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"); + case 128: + return encodeEltType("EltTyInt128"); + 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 SVEGuard = R->getValueAsString("SVETargetGuard"); + StringRef SMEGuard = R->getValueAsString("SMETargetGuard"); + 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; + char Mod; + unsigned NumVectors; + std::tie(Mod, NumVectors) = getProtoModifier(Proto, EltSizeArg + 1); + if (EltSizeArg >= 0) + ElementSizeInBits = SVEType(TS, Mod, NumVectors).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, SVEGuard, SMEGuard)); + + // 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, SVEGuard, SMEGuard)); + } +} + +void SVEEmitter::createCoreHeaderIntrinsics(raw_ostream &OS, + SVEEmitter &Emitter, + ACLEKind Kind) { + 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->getSVEGuard().str() + I->getSMEGuard().str(), + (unsigned)I->getClassKind(), I->getName()); + }; + return ToTuple(A) < ToTuple(B); + }); + + // Actually emit the intrinsic declarations. + for (auto &I : Defs) + I->emitIntrinsic(OS, Emitter, Kind); +} + +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(__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 << "typedef __SVBfloat16_t svbfloat16_t;\n"; + + OS << "#include <arm_bf16.h>\n"; + OS << "#include <arm_vector_types.h>\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"; + OS << "typedef __clang_svboolx2_t svboolx2_t;\n"; + OS << "typedef __clang_svboolx4_t svboolx4_t;\n\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 << "typedef __SVCount_t svcount_t;\n\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 [N, Suffix] : + std::initializer_list<std::pair<unsigned, const char *>>{ + {1, ""}, {2, "_x2"}, {3, "_x3"}, {4, "_x4"}}) { + for (auto ShortForm : {false, true}) + for (const ReinterpretTypeInfo &To : Reinterprets) { + SVEType ToV(To.BaseType, N); + for (const ReinterpretTypeInfo &From : Reinterprets) { + SVEType FromV(From.BaseType, N); + OS << "__aio " + "__attribute__((__clang_arm_builtin_alias(__builtin_sve_" + "reinterpret_" + << To.Suffix << "_" << From.Suffix << Suffix << ")))\n" + << ToV.str() << " svreinterpret_" << To.Suffix; + if (!ShortForm) + OS << "_" << From.Suffix << Suffix; + OS << "(" << FromV.str() << " op);\n"; + } + } + } + + createCoreHeaderIntrinsics(OS, *this, ACLEKind::SVE); + + OS << "#define svcvtnt_bf16_x svcvtnt_bf16_m\n"; + OS << "#define svcvtnt_bf16_f32_x svcvtnt_bf16_f32_m\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 << "#ifdef __cplusplus\n"; + OS << "} // extern \"C\"\n"; + OS << "#endif\n\n"; + OS << "#undef __ai\n\n"; + OS << "#undef __aio\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 << "TARGET_BUILTIN(__builtin_sve_" << Def->getMangledName() << ", \"" + << Def->getBuiltinTypeStr() << "\", \"n\", \""; + Def->printGuard(OS); + OS << "\")\n"; + } + } + + // Add reinterpret functions. + for (auto [N, Suffix] : + std::initializer_list<std::pair<unsigned, const char *>>{ + {1, ""}, {2, "_x2"}, {3, "_x3"}, {4, "_x4"}}) { + for (const ReinterpretTypeInfo &To : Reinterprets) { + SVEType ToV(To.BaseType, N); + for (const ReinterpretTypeInfo &From : Reinterprets) { + SVEType FromV(From.BaseType, N); + OS << "TARGET_BUILTIN(__builtin_sve_reinterpret_" << To.Suffix << "_" + << From.Suffix << Suffix << +", \"" << ToV.builtin_str() + << FromV.builtin_str() << "\", \"n\", \"sme|sve\")\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->getMangledLLVMName(); + 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() << ", " + << Check.getBitWidth() << "));\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_ARM_INTRIN_IMMCHECKTYPES\n"; + for (auto &KV : ImmCheckTypes) + OS << " " << KV.getKey() << " = " << KV.getValue() << ",\n"; + OS << "#endif\n\n"; +} + +void SVEEmitter::createSMEHeader(raw_ostream &OS) { + OS << "/*===---- arm_sme.h - ARM SME 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_SME_H\n"; + OS << "#define __ARM_SME_H\n\n"; + + OS << "#if !defined(__LITTLE_ENDIAN__)\n"; + OS << "#error \"Big endian is currently not supported for arm_sme.h\"\n"; + OS << "#endif\n"; + + OS << "#include <arm_sve.h>\n\n"; + OS << "#include <stddef.h>\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"; + + OS << "#ifdef __cplusplus\n"; + OS << "extern \"C\" {\n"; + OS << "#endif\n\n"; + + OS << "void __arm_za_disable(void) __arm_streaming_compatible;\n\n"; + + OS << "__ai bool __arm_has_sme(void) __arm_streaming_compatible {\n"; + OS << " uint64_t x0, x1;\n"; + OS << " __builtin_arm_get_sme_state(&x0, &x1);\n"; + OS << " return x0 & (1ULL << 63);\n"; + OS << "}\n\n"; + + OS << "__ai bool __arm_in_streaming_mode(void) __arm_streaming_compatible " + "{\n"; + OS << " uint64_t x0, x1;\n"; + OS << " __builtin_arm_get_sme_state(&x0, &x1);\n"; + OS << " return x0 & 1;\n"; + OS << "}\n\n"; + + OS << "void *__arm_sc_memcpy(void *dest, const void *src, size_t n) __arm_streaming_compatible;\n"; + OS << "void *__arm_sc_memmove(void *dest, const void *src, size_t n) __arm_streaming_compatible;\n"; + OS << "void *__arm_sc_memset(void *s, int c, size_t n) __arm_streaming_compatible;\n"; + OS << "void *__arm_sc_memchr(void *s, int c, size_t n) __arm_streaming_compatible;\n\n"; + + OS << "__ai __attribute__((target(\"sme\"))) void svundef_za(void) " + "__arm_streaming_compatible __arm_out(\"za\") " + "{ }\n\n"; + + createCoreHeaderIntrinsics(OS, *this, ACLEKind::SME); + + OS << "#ifdef __cplusplus\n"; + OS << "} // extern \"C\"\n"; + OS << "#endif\n\n"; + OS << "#undef __ai\n\n"; + OS << "#endif /* __ARM_SME_H */\n"; +} + +void SVEEmitter::createSMEBuiltins(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_SME_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 << "TARGET_BUILTIN(__builtin_sme_" << Def->getMangledName() << ", \"" + << Def->getBuiltinTypeStr() << "\", \"n\", \""; + Def->printGuard(OS); + OS << "\")\n"; + } + } + + OS << "#endif\n\n"; +} + +void SVEEmitter::createSMECodeGenMap(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_SME_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 << "SMEMAP1(" << Builtin << ", " << LLVMName << ", " << FlagString + << "),\n"; + else + OS << "SMEMAP2(" << Builtin << ", " << FlagString << "),\n"; + } + OS << "#endif\n\n"; +} + +void SVEEmitter::createSMERangeChecks(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_SME_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 SME::BI__builtin_sme_" << Def->getMangledName() << ":\n"; + for (auto &Check : Def->getImmChecks()) + OS << "ImmChecks.push_back(std::make_tuple(" << Check.getArg() << ", " + << Check.getKind() << ", " << Check.getElementSizeInBits() << ", " + << Check.getBitWidth() << "));\n"; + OS << " break;\n"; + + Emitted.insert(Def->getMangledName()); + } + + OS << "#endif\n\n"; +} + +void SVEEmitter::createBuiltinZAState(raw_ostream &OS) { + std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst"); + SmallVector<std::unique_ptr<Intrinsic>, 128> Defs; + for (auto *R : RV) + createIntrinsic(R, Defs); + + std::map<std::string, std::set<std::string>> IntrinsicsPerState; + for (auto &Def : Defs) { + std::string Key; + auto AddToKey = [&Key](const std::string &S) -> void { + Key = Key.empty() ? S : (Key + " | " + S); + }; + + if (Def->isFlagSet(getEnumValueForFlag("IsInZA"))) + AddToKey("ArmInZA"); + else if (Def->isFlagSet(getEnumValueForFlag("IsOutZA"))) + AddToKey("ArmOutZA"); + else if (Def->isFlagSet(getEnumValueForFlag("IsInOutZA"))) + AddToKey("ArmInOutZA"); + + if (Def->isFlagSet(getEnumValueForFlag("IsInZT0"))) + AddToKey("ArmInZT0"); + else if (Def->isFlagSet(getEnumValueForFlag("IsOutZT0"))) + AddToKey("ArmOutZT0"); + else if (Def->isFlagSet(getEnumValueForFlag("IsInOutZT0"))) + AddToKey("ArmInOutZT0"); + + if (!Key.empty()) + IntrinsicsPerState[Key].insert(Def->getMangledName()); + } + + OS << "#ifdef GET_SME_BUILTIN_GET_STATE\n"; + for (auto &KV : IntrinsicsPerState) { + for (StringRef Name : KV.second) + OS << "case SME::BI__builtin_sme_" << Name << ":\n"; + OS << " return " << KV.first << ";\n"; + } + OS << "#endif\n\n"; +} + +void SVEEmitter::createStreamingAttrs(raw_ostream &OS, ACLEKind Kind) { + std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst"); + SmallVector<std::unique_ptr<Intrinsic>, 128> Defs; + for (auto *R : RV) + createIntrinsic(R, Defs); + + StringRef ExtensionKind; + switch (Kind) { + case ACLEKind::SME: + ExtensionKind = "SME"; + break; + case ACLEKind::SVE: + ExtensionKind = "SVE"; + break; + } + + OS << "#ifdef GET_" << ExtensionKind << "_STREAMING_ATTRS\n"; + + llvm::StringMap<std::set<std::string>> StreamingMap; + + uint64_t IsStreamingFlag = getEnumValueForFlag("IsStreaming"); + uint64_t VerifyRuntimeMode = getEnumValueForFlag("VerifyRuntimeMode"); + uint64_t IsStreamingCompatibleFlag = + getEnumValueForFlag("IsStreamingCompatible"); + + for (auto &Def : Defs) { + if (!Def->isFlagSet(VerifyRuntimeMode) && !Def->getSVEGuard().empty() && + !Def->getSMEGuard().empty()) + report_fatal_error("Missing VerifyRuntimeMode flag"); + + if (Def->isFlagSet(IsStreamingFlag)) + StreamingMap["ArmStreaming"].insert(Def->getMangledName()); + else if (Def->isFlagSet(VerifyRuntimeMode)) + StreamingMap["VerifyRuntimeMode"].insert(Def->getMangledName()); + else if (Def->isFlagSet(IsStreamingCompatibleFlag)) + StreamingMap["ArmStreamingCompatible"].insert(Def->getMangledName()); + else + StreamingMap["ArmNonStreaming"].insert(Def->getMangledName()); + } + + for (auto BuiltinType : StreamingMap.keys()) { + for (auto Name : StreamingMap[BuiltinType]) { + OS << "case " << ExtensionKind << "::BI__builtin_" + << ExtensionKind.lower() << "_"; + OS << Name << ":\n"; + } + OS << " BuiltinType = " << BuiltinType << ";\n"; + OS << " break;\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); +} + +void EmitSveStreamingAttrs(RecordKeeper &Records, raw_ostream &OS) { + SVEEmitter(Records).createStreamingAttrs(OS, ACLEKind::SVE); +} + +void EmitSmeHeader(RecordKeeper &Records, raw_ostream &OS) { + SVEEmitter(Records).createSMEHeader(OS); +} + +void EmitSmeBuiltins(RecordKeeper &Records, raw_ostream &OS) { + SVEEmitter(Records).createSMEBuiltins(OS); +} + +void EmitSmeBuiltinCG(RecordKeeper &Records, raw_ostream &OS) { + SVEEmitter(Records).createSMECodeGenMap(OS); +} + +void EmitSmeRangeChecks(RecordKeeper &Records, raw_ostream &OS) { + SVEEmitter(Records).createSMERangeChecks(OS); +} + +void EmitSmeStreamingAttrs(RecordKeeper &Records, raw_ostream &OS) { + SVEEmitter(Records).createStreamingAttrs(OS, ACLEKind::SME); +} + +void EmitSmeBuiltinZAState(RecordKeeper &Records, raw_ostream &OS) { + SVEEmitter(Records).createBuiltinZAState(OS); +} +} // End namespace clang diff --git a/clang/utils/TableGen/SveEmitter.cpp b/clang/utils/TableGen/SveEmitter.cpp index e9fa01ea98dced..60754327014c47 100644 --- a/clang/utils/TableGen/SveEmitter.cpp +++ b/clang/utils/TableGen/SveEmitter.cpp @@ -50,20 +50,31 @@ using TypeSpec = std::string; namespace { class SVEType { - bool Float, Signed, Immediate, Void, Constant, Pointer, BFloat, MFloat; - bool DefaultType, IsScalable, Predicate, PredicatePattern, PrefetchOp, - Svcount, Fpm; + + enum TypeKind { + Void, + Float, + SInt, + UInt, + BFloat16, + MFloat8, + Svcount, + PrefetchOp, + PredicatePattern, + Predicate, + Fpm + }; + TypeKind Kind; + bool Immediate, Constant, Pointer, DefaultType, IsScalable; unsigned Bitwidth, ElementBitwidth, NumVectors; public: SVEType() : SVEType("", 'v') {} SVEType(StringRef TS, char CharMod, unsigned NumVectors = 1) - : Float(false), Signed(true), Immediate(false), Void(false), - Constant(false), Pointer(false), BFloat(false), MFloat(false), - DefaultType(false), IsScalable(true), Predicate(false), - PredicatePattern(false), PrefetchOp(false), Svcount(false), Fpm(false), - Bitwidth(128), ElementBitwidth(~0U), NumVectors(NumVectors) { + : Kind(SInt), Immediate(false), Constant(false), Pointer(false), + DefaultType(false), IsScalable(true), Bitwidth(128), + ElementBitwidth(~0U), NumVectors(NumVectors) { if (!TS.empty()) applyTypespec(TS); applyModifier(CharMod); @@ -74,34 +85,32 @@ class SVEType { } bool isPointer() const { return Pointer; } - bool isVoidPointer() const { return Pointer && Void; } - bool isSigned() const { return Signed; } + bool isConstant() const { return Constant; } bool isImmediate() const { return Immediate; } + bool isSigned() const { return Kind != UInt; } bool isScalar() const { return NumVectors == 0; } bool isVector() const { return NumVectors > 0; } bool isScalableVector() const { return isVector() && IsScalable; } bool isFixedLengthVector() const { return isVector() && !IsScalable; } - bool isChar() const { return ElementBitwidth == 8 && !MFloat; } - bool isVoid() const { return Void && !Pointer; } + bool isChar() const { return ElementBitwidth == 8 && isInteger(); } + bool isVoid() const { return Kind == Void; } bool isDefault() const { return DefaultType; } - bool isFloat() const { return Float && !BFloat && !MFloat; } - bool isBFloat() const { return BFloat && !Float && !MFloat; } - bool isMFloat() const { - return MFloat && !BFloat && !Float; - } - bool isFloatingPoint() const { return Float || BFloat; } - bool isInteger() const { - return !isFloatingPoint() && !Predicate && !Svcount; + bool isFloat() const { return Kind == Float; } + bool isBFloat() const { return Kind == BFloat16; } + bool isMFloat() const { return Kind == MFloat8; } + bool isTypedPointer() const { return Pointer && Kind != Void; } + bool isFloatingPoint() const { + return Kind == Float || Kind == BFloat16 || Kind == MFloat8; } + bool isInteger() const { return Kind == SInt || Kind == UInt; } bool isScalarPredicate() const { - return !isFloatingPoint() && Predicate && NumVectors == 0; + return Kind == Predicate && NumVectors == 0; } - bool isPredicateVector() const { return Predicate; } - bool isPredicatePattern() const { return PredicatePattern; } - bool isPrefetchOp() const { return PrefetchOp; } - bool isSvcount() const { return Svcount; } - bool isConstant() const { return Constant; } - bool isFpm() const { return Fpm; } + bool isPredicate() const { return Kind == Predicate; } + bool isPredicatePattern() const { return Kind == PredicatePattern; } + bool isPrefetchOp() const { return Kind == PrefetchOp; } + bool isSvcount() const { return Kind == Svcount; } + bool isFpm() const { return Kind == Fpm; } unsigned getElementSizeInBits() const { return ElementBitwidth; } unsigned getNumVectors() const { return NumVectors; } @@ -425,9 +434,7 @@ const std::array<SVEEmitter::ReinterpretTypeInfo, 12> SVEEmitter::Reinterprets = //===----------------------------------------------------------------------===// std::string SVEType::builtin_str() const { - std::string S; - if (isVoid()) - return "v"; + std::string OutStr; if (isScalarPredicate()) return "b"; @@ -435,62 +442,81 @@ std::string SVEType::builtin_str() const { if (isSvcount()) return "Qa"; - 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()) + if (isVoid()) { + OutStr += "v"; + if (!isPointer()) + return OutStr; + } 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!"); + case 16: + OutStr += "h"; + break; + case 32: + OutStr += "f"; + break; + case 64: + OutStr += "d"; + break; + default: + llvm_unreachable("Unhandled float type!"); } - else if (isBFloat()) { + } else if (isBFloat()) { assert(ElementBitwidth == 16 && "Not a valid BFloat."); - S += "y"; + OutStr += "y"; } else if (isMFloat()) { assert(ElementBitwidth == 8 && "Not a valid MFloat."); - S += "m"; + OutStr += "m"; + } else { + switch (ElementBitwidth) { + case 1: + OutStr += "b"; + break; + case 8: + OutStr += "c"; + break; + case 16: + OutStr += "s"; + break; + case 32: + OutStr += "i"; + break; + case 64: + OutStr += "Wi"; + break; + case 128: + OutStr += "LLLi"; + break; + default: + llvm_unreachable("Unhandled bitwidth!"); + } } - 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; - } + // Make chars and typed pointers explicitly signed. + if (!isFloatingPoint() && !isVoid()) { + if ((ElementBitwidth == 8 || isPointer()) && isSigned()) + OutStr = "S" + OutStr; + if (!isSigned()) + OutStr = "U" + OutStr; } // Constant indices are "int", but have the "constant expression" modifier. if (isImmediate()) { - assert(!isFloat() && "fp immediates are not supported"); - S = "I" + S; + assert(!isFloatingPoint() && "fp immediates are not supported"); + OutStr = "I" + OutStr; } if (isScalar()) { - if (Constant) S += "C"; - if (Pointer) S += "*"; - return S; + if (Constant) + OutStr += "C"; + if (Pointer) + OutStr += "*"; + return OutStr; } if (isFixedLengthVector()) - return "V" + utostr(getNumElements() * NumVectors) + S; - return "q" + utostr(getNumElements() * NumVectors) + S; + return "V" + utostr(getNumElements() * NumVectors) + OutStr; + return "q" + utostr(getNumElements() * NumVectors) + OutStr; } - std::string SVEType::str() const { if (isPredicatePattern()) return "enum svpattern"; @@ -502,28 +528,30 @@ std::string SVEType::str() const { return "fpm_t"; std::string S; - if (Void) + if (isVoid()) S += "void"; else { if (isScalableVector() || isSvcount()) S += "sv"; - if (!Signed && !isFloatingPoint()) - S += "u"; - if (Float) + if (isFloat()) S += "float"; else if (isSvcount()) S += "count"; - else if (isScalarPredicate() || isPredicateVector()) + else if (isPredicate()) S += "bool"; else if (isBFloat()) S += "bfloat"; else if (isMFloat()) S += "mfloat"; - else - S += "int"; + else { + if (isSigned()) + S += "int"; + else + S += "uint"; + }; - if (!isScalarPredicate() && !isPredicateVector() && !isSvcount()) + if (!isPredicate() && !isSvcount()) S += utostr(ElementBitwidth); if (isFixedLengthVector()) S += "x" + utostr(getNumElements()); @@ -545,13 +573,13 @@ void SVEType::applyTypespec(StringRef TS) { for (char I : TS) { switch (I) { case 'Q': - Svcount = true; + Kind = Svcount; break; case 'P': - Predicate = true; + Kind = Predicate; break; case 'U': - Signed = false; + Kind = UInt; break; case 'c': ElementBitwidth = 8; @@ -569,28 +597,23 @@ void SVEType::applyTypespec(StringRef TS) { ElementBitwidth = 128; break; case 'h': - Float = true; + Kind = Float; ElementBitwidth = 16; break; case 'f': - Float = true; + Kind = Float; ElementBitwidth = 32; break; case 'd': - Float = true; + Kind = Float; ElementBitwidth = 64; break; case 'b': - BFloat = true; - Float = false; - MFloat = false; + Kind = BFloat16; ElementBitwidth = 16; break; case 'm': - Signed = false; - MFloat = true; - Float = false; - BFloat = false; + Kind = MFloat8; ElementBitwidth = 8; break; default: @@ -603,7 +626,7 @@ void SVEType::applyTypespec(StringRef TS) { void SVEType::applyModifier(char Mod) { switch (Mod) { case 'v': - Void = true; + Kind = Void; break; case 'd': DefaultType = true; @@ -617,7 +640,7 @@ void SVEType::applyModifier(char Mod) { NumVectors = 0; break; case 'e': - Signed = false; + Kind = UInt; ElementBitwidth /= 2; break; case 'h': @@ -627,20 +650,14 @@ void SVEType::applyModifier(char Mod) { ElementBitwidth /= 4; break; case 'b': - Signed = false; - Float = false; - BFloat = false; + Kind = UInt; ElementBitwidth /= 4; break; case 'o': ElementBitwidth *= 4; break; case 'P': - Signed = true; - Float = false; - BFloat = false; - Predicate = true; - Svcount = false; + Kind = Predicate; Bitwidth = 16; ElementBitwidth = 1; break; @@ -663,108 +680,66 @@ void SVEType::applyModifier(char Mod) { NumVectors = 0; break; case '@': - Signed = false; - Float = false; - BFloat = false; + Kind = UInt; ElementBitwidth /= 4; NumVectors = 0; break; case 'K': - Signed = true; - Float = false; - BFloat = false; + Kind = SInt; Bitwidth = ElementBitwidth; NumVectors = 0; break; case 'L': - Signed = false; - Float = false; - BFloat = false; + Kind = UInt; Bitwidth = ElementBitwidth; NumVectors = 0; break; case 'u': - Predicate = false; - Svcount = false; - Signed = false; - Float = false; - BFloat = false; + Kind = UInt; break; case 'x': - Predicate = false; - Svcount = false; - Signed = true; - Float = false; - BFloat = false; + Kind = SInt; break; case 'i': - Predicate = false; - Svcount = false; - Float = false; - BFloat = false; + Kind = UInt; ElementBitwidth = Bitwidth = 64; NumVectors = 0; - Signed = false; Immediate = true; break; case 'I': - Predicate = false; - Svcount = false; - Float = false; - BFloat = false; + Kind = PredicatePattern; ElementBitwidth = Bitwidth = 32; NumVectors = 0; - Signed = true; Immediate = true; - PredicatePattern = true; break; case 'J': - Predicate = false; - Svcount = false; - Float = false; - BFloat = false; + Kind = PrefetchOp; ElementBitwidth = Bitwidth = 32; NumVectors = 0; - Signed = true; Immediate = true; - PrefetchOp = true; break; case 'k': - Predicate = false; - Svcount = false; - Signed = true; - Float = false; - BFloat = false; + Kind = SInt; ElementBitwidth = Bitwidth = 32; NumVectors = 0; break; case 'l': - Predicate = false; - Svcount = false; - Signed = true; - Float = false; - BFloat = false; + Kind = SInt; ElementBitwidth = Bitwidth = 64; NumVectors = 0; break; case 'm': - Predicate = false; - Svcount = false; - Signed = false; - Float = false; - BFloat = false; + Kind = UInt; ElementBitwidth = Bitwidth = 32; NumVectors = 0; break; case '>': - Fpm = true; - [[fallthrough]]; + Kind = Fpm; + ElementBitwidth = Bitwidth = 64; + NumVectors = 0; + break; case 'n': - Predicate = false; - Svcount = false; - Signed = false; - Float = false; - BFloat = false; + Kind = UInt; ElementBitwidth = Bitwidth = 64; NumVectors = 0; break; @@ -776,167 +751,143 @@ void SVEType::applyModifier(char Mod) { NumVectors = 0; break; case 'f': - Signed = false; + Kind = UInt; ElementBitwidth = Bitwidth = 64; NumVectors = 0; break; case 'g': - Signed = false; - Float = false; - BFloat = false; + Kind = UInt; ElementBitwidth = 64; break; case '[': - Signed = false; - Float = false; - BFloat = false; + Kind = UInt; ElementBitwidth = 8; break; case 't': - Signed = true; - Float = false; - BFloat = false; + Kind = SInt; ElementBitwidth = 32; break; case 'z': - Signed = false; - Float = false; - BFloat = false; + Kind = UInt; ElementBitwidth = 32; break; case 'O': - Predicate = false; - Svcount = false; - Float = true; + Kind = Float; ElementBitwidth = 16; break; case 'M': - Predicate = false; - Svcount = false; - Float = true; - BFloat = false; + Kind = Float; ElementBitwidth = 32; break; case 'N': - Predicate = false; - Svcount = false; - Float = true; + Kind = Float; ElementBitwidth = 64; break; case 'Q': + Kind = Void; Constant = true; Pointer = true; - Void = true; NumVectors = 0; break; case 'S': + Kind = SInt; Constant = true; Pointer = true; ElementBitwidth = Bitwidth = 8; NumVectors = 0; - Signed = true; break; case 'W': + Kind = UInt; Constant = true; Pointer = true; ElementBitwidth = Bitwidth = 8; NumVectors = 0; - Signed = false; break; case 'T': + Kind = SInt; Constant = true; Pointer = true; ElementBitwidth = Bitwidth = 16; NumVectors = 0; - Signed = true; break; case 'X': + Kind = UInt; Constant = true; Pointer = true; ElementBitwidth = Bitwidth = 16; NumVectors = 0; - Signed = false; break; case 'Y': + Kind = UInt; Constant = true; Pointer = true; ElementBitwidth = Bitwidth = 32; NumVectors = 0; - Signed = false; break; case 'U': + Kind = SInt; Constant = true; Pointer = true; ElementBitwidth = Bitwidth = 32; NumVectors = 0; - Signed = true; break; case '%': + Kind = Void; Pointer = true; - Void = true; NumVectors = 0; break; case 'A': + Kind = SInt; Pointer = true; ElementBitwidth = Bitwidth = 8; NumVectors = 0; - Signed = true; break; case 'B': + Kind = SInt; Pointer = true; ElementBitwidth = Bitwidth = 16; NumVectors = 0; - Signed = true; break; case 'C': + Kind = SInt; Pointer = true; ElementBitwidth = Bitwidth = 32; NumVectors = 0; - Signed = true; break; case 'D': + Kind = SInt; Pointer = true; ElementBitwidth = Bitwidth = 64; NumVectors = 0; - Signed = true; break; case 'E': + Kind = UInt; Pointer = true; ElementBitwidth = Bitwidth = 8; NumVectors = 0; - Signed = false; break; case 'F': + Kind = UInt; Pointer = true; ElementBitwidth = Bitwidth = 16; NumVectors = 0; - Signed = false; break; case 'G': + Kind = UInt; Pointer = true; ElementBitwidth = Bitwidth = 32; NumVectors = 0; - Signed = false; break; case '$': - Predicate = false; - Svcount = false; - Float = false; - BFloat = true; + Kind = BFloat16; ElementBitwidth = 16; break; case '}': - Predicate = false; - Signed = true; - Svcount = true; + Kind = Svcount; NumVectors = 0; - Float = false; - BFloat = false; break; case '~': - Float = false; - BFloat = false; - MFloat = true; + Kind = MFloat8; ElementBitwidth = 8; break; case '.': @@ -1061,7 +1012,7 @@ std::string Intrinsic::replaceTemplatedArgs(std::string Name, TypeSpec TS, TypeCode = T.isSigned() ? 's' : 'u'; else if (T.isSvcount()) TypeCode = 'c'; - else if (T.isPredicateVector()) + else if (T.isPredicate()) TypeCode = 'b'; else if (T.isBFloat()) TypeCode = "bf"; @@ -1165,7 +1116,7 @@ uint64_t SVEEmitter::encodeTypeFlags(const SVEType &T) { return encodeEltType("EltTyMFloat8"); } - if (T.isPredicateVector() || T.isSvcount()) { + if (T.isPredicate() || T.isSvcount()) { switch (T.getElementSizeInBits()) { case 8: return encodeEltType("EltTyBool8"); >From 20e5fc18074d3955716e014d87b32488c70a37ae Mon Sep 17 00:00:00 2001 From: Spencer Abson <spencer.ab...@arm.com> Date: Tue, 26 Nov 2024 16:35:51 +0000 Subject: [PATCH 2/8] Replace isSigned() --- clang/utils/TableGen/SveEmitter.cpp | 33 ++++++++++++++--------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/clang/utils/TableGen/SveEmitter.cpp b/clang/utils/TableGen/SveEmitter.cpp index 60754327014c47..01238654f8ce65 100644 --- a/clang/utils/TableGen/SveEmitter.cpp +++ b/clang/utils/TableGen/SveEmitter.cpp @@ -87,7 +87,6 @@ class SVEType { bool isPointer() const { return Pointer; } bool isConstant() const { return Constant; } bool isImmediate() const { return Immediate; } - bool isSigned() const { return Kind != UInt; } bool isScalar() const { return NumVectors == 0; } bool isVector() const { return NumVectors > 0; } bool isScalableVector() const { return isVector() && IsScalable; } @@ -98,11 +97,12 @@ class SVEType { bool isFloat() const { return Kind == Float; } bool isBFloat() const { return Kind == BFloat16; } bool isMFloat() const { return Kind == MFloat8; } - bool isTypedPointer() const { return Pointer && Kind != Void; } bool isFloatingPoint() const { return Kind == Float || Kind == BFloat16 || Kind == MFloat8; } bool isInteger() const { return Kind == SInt || Kind == UInt; } + bool isSignedInteger() const { return Kind == SInt; } + bool isUnsignedInteger() const { return Kind == UInt; } bool isScalarPredicate() const { return Kind == Predicate && NumVectors == 0; } @@ -491,13 +491,11 @@ std::string SVEType::builtin_str() const { } } - // Make chars and typed pointers explicitly signed. - if (!isFloatingPoint() && !isVoid()) { - if ((ElementBitwidth == 8 || isPointer()) && isSigned()) - OutStr = "S" + OutStr; - if (!isSigned()) - OutStr = "U" + OutStr; - } + // Make chars and integer pointers explicitly signed. + if((ElementBitwidth == 8 || isPointer()) && isSignedInteger()) + OutStr = "S" + OutStr; + else if(isUnsignedInteger()) + OutStr = "U" + OutStr; // Constant indices are "int", but have the "constant expression" modifier. if (isImmediate()) { @@ -544,12 +542,10 @@ std::string SVEType::str() const { S += "bfloat"; else if (isMFloat()) S += "mfloat"; - else { - if (isSigned()) - S += "int"; - else - S += "uint"; - }; + else if (isSignedInteger()) + S += "int"; + else if (isUnsignedInteger()) + S += "uint"; if (!isPredicate() && !isSvcount()) S += utostr(ElementBitwidth); @@ -1008,8 +1004,11 @@ std::string Intrinsic::replaceTemplatedArgs(std::string Name, TypeSpec TS, // Replace templated arg with the right suffix (e.g. u32) std::string TypeCode; - if (T.isInteger()) - TypeCode = T.isSigned() ? 's' : 'u'; + + if(T.isSignedInteger()) + TypeCode = 's'; + else if (T.isUnsignedInteger()) + TypeCode = 'u'; else if (T.isSvcount()) TypeCode = 'c'; else if (T.isPredicate()) >From ad46796c38ddaab3291d1640a04426007a8f826a Mon Sep 17 00:00:00 2001 From: Spencer Abson <spencer.ab...@arm.com> Date: Tue, 26 Nov 2024 16:43:41 +0000 Subject: [PATCH 3/8] [NFC] Fix format --- clang/utils/TableGen/SveEmitter.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clang/utils/TableGen/SveEmitter.cpp b/clang/utils/TableGen/SveEmitter.cpp index 01238654f8ce65..2f91f30b4f69eb 100644 --- a/clang/utils/TableGen/SveEmitter.cpp +++ b/clang/utils/TableGen/SveEmitter.cpp @@ -492,9 +492,9 @@ std::string SVEType::builtin_str() const { } // Make chars and integer pointers explicitly signed. - if((ElementBitwidth == 8 || isPointer()) && isSignedInteger()) + if ((ElementBitwidth == 8 || isPointer()) && isSignedInteger()) OutStr = "S" + OutStr; - else if(isUnsignedInteger()) + else if (isUnsignedInteger()) OutStr = "U" + OutStr; // Constant indices are "int", but have the "constant expression" modifier. @@ -1005,7 +1005,7 @@ std::string Intrinsic::replaceTemplatedArgs(std::string Name, TypeSpec TS, // Replace templated arg with the right suffix (e.g. u32) std::string TypeCode; - if(T.isSignedInteger()) + if (T.isSignedInteger()) TypeCode = 's'; else if (T.isUnsignedInteger()) TypeCode = 'u'; >From 3146eaaf7e942cc867dcef35165ee4ebcf6ef84d Mon Sep 17 00:00:00 2001 From: Spencer Abson <spencer.ab...@arm.com> Date: Wed, 27 Nov 2024 13:32:38 +0000 Subject: [PATCH 4/8] Refactor builtin_str() --- clang/utils/TableGen/SveEmitter.cpp | 112 ++++++++++++++-------------- 1 file changed, 55 insertions(+), 57 deletions(-) diff --git a/clang/utils/TableGen/SveEmitter.cpp b/clang/utils/TableGen/SveEmitter.cpp index 2f91f30b4f69eb..7f167c717d1e4b 100644 --- a/clang/utils/TableGen/SveEmitter.cpp +++ b/clang/utils/TableGen/SveEmitter.cpp @@ -136,6 +136,9 @@ class SVEType { /// Applies a prototype modifier to the type. void applyModifier(char Mod); + + /// Get the builtin base for this SVEType, e.g, 'Wi' for svint64_t. + std::string builtinBaseType() const; }; class SVEEmitter; @@ -433,88 +436,82 @@ const std::array<SVEEmitter::ReinterpretTypeInfo, 12> SVEEmitter::Reinterprets = // Type implementation //===----------------------------------------------------------------------===// -std::string SVEType::builtin_str() const { - std::string OutStr; - - if (isScalarPredicate()) - return "b"; - - if (isSvcount()) +std::string SVEType::builtinBaseType() const { + switch (Kind) { + case TypeKind::Void: + return "v"; + case TypeKind::Svcount: return "Qa"; - - if (isVoid()) { - OutStr += "v"; - if (!isPointer()) - return OutStr; - } else if (isFloat()) { + case TypeKind::BFloat16: + assert(ElementBitwidth == 16 && "Invalid BFloat16!"); + return "y"; + case TypeKind::MFloat8: + assert(ElementBitwidth == 8 && "Invalid MFloat8!"); + return "c"; + case TypeKind::Float: switch (ElementBitwidth) { case 16: - OutStr += "h"; - break; + return "h"; case 32: - OutStr += "f"; - break; + return "f"; case 64: - OutStr += "d"; - break; + return "d"; default: - llvm_unreachable("Unhandled float type!"); + llvm_unreachable("Unhandled float width!"); } - } else if (isBFloat()) { - assert(ElementBitwidth == 16 && "Not a valid BFloat."); - OutStr += "y"; - } else if (isMFloat()) { - assert(ElementBitwidth == 8 && "Not a valid MFloat."); - OutStr += "m"; - } else { + case TypeKind::Predicate: + if (isScalar()) + return "b"; + [[fallthrough]]; + // SInt/UInt, PredicatePattern, PrefetchOp. + default: switch (ElementBitwidth) { case 1: - OutStr += "b"; - break; + return "b"; case 8: - OutStr += "c"; - break; + return "c"; case 16: - OutStr += "s"; - break; + return "s"; case 32: - OutStr += "i"; - break; + return "i"; case 64: - OutStr += "Wi"; - break; + return "Wi"; case 128: - OutStr += "LLLi"; - break; + return "LLLi"; default: llvm_unreachable("Unhandled bitwidth!"); } } +} - // Make chars and integer pointers explicitly signed. - if ((ElementBitwidth == 8 || isPointer()) && isSignedInteger()) - OutStr = "S" + OutStr; - else if (isUnsignedInteger()) - OutStr = "U" + OutStr; +std::string SVEType::builtin_str() const { + + std::string Prefix; - // Constant indices are "int", but have the "constant expression" modifier. - if (isImmediate()) { + if (isScalableVector()) + Prefix = "q" + llvm::utostr(getNumElements() * NumVectors); + else if (isFixedLengthVector()) + Prefix = "V" + llvm::utostr(getNumElements() * NumVectors); + else if (isImmediate()) { assert(!isFloatingPoint() && "fp immediates are not supported"); - OutStr = "I" + OutStr; + Prefix = "I"; } - if (isScalar()) { - if (Constant) - OutStr += "C"; - if (Pointer) - OutStr += "*"; - return OutStr; - } + // Make chars and integer pointers explicitly signed. + if ((ElementBitwidth == 8 || isPointer()) && isSignedInteger()) + Prefix += "S"; + else if (isUnsignedInteger()) + Prefix += "U"; - if (isFixedLengthVector()) - return "V" + utostr(getNumElements() * NumVectors) + OutStr; - return "q" + utostr(getNumElements() * NumVectors) + OutStr; + std::string BuiltinStr = Prefix + builtinBaseType(); + if (isConstant()) + BuiltinStr += "C"; + if (isPointer()) + BuiltinStr += "*"; + + return BuiltinStr; } + std::string SVEType::str() const { if (isPredicatePattern()) return "enum svpattern"; @@ -623,6 +620,7 @@ void SVEType::applyModifier(char Mod) { switch (Mod) { case 'v': Kind = Void; + NumVectors = 0; break; case 'd': DefaultType = true; >From a9f0e6fb4a225b7ee92057ac7bfc1923cc118b9c Mon Sep 17 00:00:00 2001 From: Spencer Abson <spencer.ab...@arm.com> Date: Wed, 27 Nov 2024 14:00:10 +0000 Subject: [PATCH 5/8] Refactor SVEType::str() --- clang/utils/TableGen/SveEmitter.cpp | 87 +++++++++++++++-------------- 1 file changed, 45 insertions(+), 42 deletions(-) diff --git a/clang/utils/TableGen/SveEmitter.cpp b/clang/utils/TableGen/SveEmitter.cpp index 7f167c717d1e4b..2309830b367a79 100644 --- a/clang/utils/TableGen/SveEmitter.cpp +++ b/clang/utils/TableGen/SveEmitter.cpp @@ -513,53 +513,56 @@ std::string SVEType::builtin_str() const { } std::string SVEType::str() const { - if (isPredicatePattern()) - return "enum svpattern"; + std::string TypeStr; - if (isPrefetchOp()) + switch (Kind) { + case TypeKind::PrefetchOp: return "enum svprfop"; - - if (isFpm()) - return "fpm_t"; - - std::string S; - if (isVoid()) - S += "void"; - else { - if (isScalableVector() || isSvcount()) - S += "sv"; - - if (isFloat()) - S += "float"; - else if (isSvcount()) - S += "count"; - else if (isPredicate()) - S += "bool"; - else if (isBFloat()) - S += "bfloat"; - else if (isMFloat()) - S += "mfloat"; - else if (isSignedInteger()) - S += "int"; - else if (isUnsignedInteger()) - S += "uint"; - - if (!isPredicate() && !isSvcount()) - S += utostr(ElementBitwidth); - if (isFixedLengthVector()) - S += "x" + utostr(getNumElements()); - if (NumVectors > 1) - S += "x" + utostr(NumVectors); - if (!isScalarPredicate()) - S += "_t"; + case TypeKind::PredicatePattern: + return "enum svpattern"; + case TypeKind::Fpm: + TypeStr += "fpm"; + break; + case TypeKind::Void: + TypeStr += "void"; + break; + case TypeKind::Float: + TypeStr += "float" + llvm::utostr(ElementBitwidth); + break; + case TypeKind::Svcount: + TypeStr += "svcount"; + break; + case TypeKind::Predicate: + TypeStr += "bool"; + break; + case TypeKind::BFloat16: + TypeStr += "bfloat16"; + break; + case TypeKind::MFloat8: + TypeStr += "mfloat8"; + break; + case TypeKind::SInt: + TypeStr += "int" + llvm::utostr(ElementBitwidth); + break; + case TypeKind::UInt: + TypeStr += "uint" + llvm::utostr(ElementBitwidth); } - if (Constant) - S += " const"; - if (Pointer) - S += " *"; + if (isFixedLengthVector()) + TypeStr += "x" + llvm::utostr(getNumElements()); + else if (isScalableVector()) + TypeStr = "sv" + TypeStr; - return S; + if (NumVectors > 1) + TypeStr += "x" + llvm::utostr(NumVectors); + if (!isScalarPredicate() && !isVoid()) + TypeStr += "_t"; + if (isConstant()) + TypeStr += " const"; + if (isPointer()) + TypeStr += " *"; + + return TypeStr; } void SVEType::applyTypespec(StringRef TS) { >From 6288a81491bdeb8a33fe039b206b7ec38bdbca30 Mon Sep 17 00:00:00 2001 From: Spencer Abson <spencer.ab...@arm.com> Date: Thu, 28 Nov 2024 14:41:48 +0000 Subject: [PATCH 6/8] Fix improper predicate builtin strings --- clang/utils/TableGen/SveEmitter.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/clang/utils/TableGen/SveEmitter.cpp b/clang/utils/TableGen/SveEmitter.cpp index 2309830b367a79..c8d94f69708d4b 100644 --- a/clang/utils/TableGen/SveEmitter.cpp +++ b/clang/utils/TableGen/SveEmitter.cpp @@ -116,7 +116,7 @@ class SVEType { unsigned getNumElements() const { assert(ElementBitwidth != ~0U); - return Bitwidth / ElementBitwidth; + return isPredicate() ? 16 : (Bitwidth / ElementBitwidth); } unsigned getSizeInBits() const { return Bitwidth; @@ -137,7 +137,7 @@ class SVEType { /// Applies a prototype modifier to the type. void applyModifier(char Mod); - /// Get the builtin base for this SVEType, e.g, 'Wi' for svint64_t. + /// Get the builtin base for this SVEType, e.g. 'Wi' for svint64_t. std::string builtinBaseType() const; }; @@ -442,6 +442,11 @@ std::string SVEType::builtinBaseType() const { return "v"; case TypeKind::Svcount: return "Qa"; + case TypeKind::PrefetchOp: + case TypeKind::PredicatePattern: + return "i"; + case TypeKind::Predicate: + return "b"; case TypeKind::BFloat16: assert(ElementBitwidth == 16 && "Invalid BFloat16!"); return "y"; @@ -459,11 +464,8 @@ std::string SVEType::builtinBaseType() const { default: llvm_unreachable("Unhandled float width!"); } - case TypeKind::Predicate: - if (isScalar()) - return "b"; - [[fallthrough]]; - // SInt/UInt, PredicatePattern, PrefetchOp. + case TypeKind::SInt: + case TypeKind::UInt: default: switch (ElementBitwidth) { case 1: @@ -482,10 +484,10 @@ std::string SVEType::builtinBaseType() const { llvm_unreachable("Unhandled bitwidth!"); } } + llvm_unreachable("Unhandled TypeKind!"); } std::string SVEType::builtin_str() const { - std::string Prefix; if (isScalableVector()) >From e9f10f9e144103349e4adb1ee8d7ced2f208e486 Mon Sep 17 00:00:00 2001 From: Spencer Abson <spencer.ab...@arm.com> Date: Thu, 28 Nov 2024 14:57:26 +0000 Subject: [PATCH 7/8] Remove default from typekind switch --- clang/utils/TableGen/SveEmitter.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/clang/utils/TableGen/SveEmitter.cpp b/clang/utils/TableGen/SveEmitter.cpp index c8d94f69708d4b..333cfe29434e4e 100644 --- a/clang/utils/TableGen/SveEmitter.cpp +++ b/clang/utils/TableGen/SveEmitter.cpp @@ -466,7 +466,6 @@ std::string SVEType::builtinBaseType() const { } case TypeKind::SInt: case TypeKind::UInt: - default: switch (ElementBitwidth) { case 1: return "b"; >From 643a12ab5f862f0deeb9484de1f4c98371c9c81d Mon Sep 17 00:00:00 2001 From: Spencer Abson <spencer.ab...@arm.com> Date: Fri, 29 Nov 2024 11:49:18 +0000 Subject: [PATCH 8/8] Rebase and add 'Invalid' TypeKind --- clang/utils/TableGen/SveEmitter.cpp | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/clang/utils/TableGen/SveEmitter.cpp b/clang/utils/TableGen/SveEmitter.cpp index 333cfe29434e4e..8e0af6bc732895 100644 --- a/clang/utils/TableGen/SveEmitter.cpp +++ b/clang/utils/TableGen/SveEmitter.cpp @@ -52,6 +52,7 @@ namespace { class SVEType { enum TypeKind { + Invalid, Void, Float, SInt, @@ -72,7 +73,7 @@ class SVEType { SVEType() : SVEType("", 'v') {} SVEType(StringRef TS, char CharMod, unsigned NumVectors = 1) - : Kind(SInt), Immediate(false), Constant(false), Pointer(false), + : Kind(Invalid), Immediate(false), Constant(false), Pointer(false), DefaultType(false), IsScalable(true), Bitwidth(128), ElementBitwidth(~0U), NumVectors(NumVectors) { if (!TS.empty()) @@ -111,6 +112,7 @@ class SVEType { bool isPrefetchOp() const { return Kind == PrefetchOp; } bool isSvcount() const { return Kind == Svcount; } bool isFpm() const { return Kind == Fpm; } + bool isInvalid() const { return Kind == Invalid; } unsigned getElementSizeInBits() const { return ElementBitwidth; } unsigned getNumVectors() const { return NumVectors; } @@ -445,6 +447,8 @@ std::string SVEType::builtinBaseType() const { case TypeKind::PrefetchOp: case TypeKind::PredicatePattern: return "i"; + case TypeKind::Fpm: + return "Wi"; case TypeKind::Predicate: return "b"; case TypeKind::BFloat16: @@ -482,6 +486,8 @@ std::string SVEType::builtinBaseType() const { default: llvm_unreachable("Unhandled bitwidth!"); } + case TypeKind::Invalid: + llvm_unreachable("Attempting to resolve builtin string from Invalid type!"); } llvm_unreachable("Unhandled TypeKind!"); } @@ -547,6 +553,9 @@ std::string SVEType::str() const { break; case TypeKind::UInt: TypeStr += "uint" + llvm::utostr(ElementBitwidth); + break; + case TypeKind::Invalid: + llvm_unreachable("Attempting to resolve type name from Invalid type!"); } if (isFixedLengthVector()) @@ -570,27 +579,35 @@ void SVEType::applyTypespec(StringRef TS) { for (char I : TS) { switch (I) { case 'Q': + assert(Kind == Invalid && "Invalid use of modifer!"); Kind = Svcount; break; case 'P': + assert(Kind == Invalid && "Invalid use of modifer!"); Kind = Predicate; break; case 'U': + assert(Kind == Invalid && "Invalid use of modifer!"); Kind = UInt; break; case 'c': + Kind = isInvalid() ? SInt : Kind; ElementBitwidth = 8; break; case 's': + Kind = isInvalid() ? SInt : Kind; ElementBitwidth = 16; break; case 'i': + Kind = isInvalid() ? SInt : Kind; ElementBitwidth = 32; break; case 'l': + Kind = isInvalid() ? SInt : Kind; ElementBitwidth = 64; break; case 'q': + Kind = SInt; ElementBitwidth = 128; break; case 'h': _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits