Subversion Repositories QNX 8.QNX8 LLVM/Clang compiler suite

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. //===--- RISCVVIntrinsicUtils.h - RISC-V Vector Intrinsic Utils -*- C++ -*-===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8.  
  9. #ifndef CLANG_SUPPORT_RISCVVINTRINSICUTILS_H
  10. #define CLANG_SUPPORT_RISCVVINTRINSICUTILS_H
  11.  
  12. #include "llvm/ADT/ArrayRef.h"
  13. #include "llvm/ADT/BitmaskEnum.h"
  14. #include "llvm/ADT/SmallVector.h"
  15. #include "llvm/ADT/StringRef.h"
  16. #include <cstdint>
  17. #include <optional>
  18. #include <set>
  19. #include <string>
  20. #include <unordered_map>
  21. #include <vector>
  22.  
  23. namespace llvm {
  24. class raw_ostream;
  25. } // end namespace llvm
  26.  
  27. namespace clang {
  28. namespace RISCV {
  29.  
  30. using VScaleVal = std::optional<unsigned>;
  31.  
  32. // Modifier for vector type.
  33. enum class VectorTypeModifier : uint8_t {
  34.   NoModifier,
  35.   Widening2XVector,
  36.   Widening4XVector,
  37.   Widening8XVector,
  38.   MaskVector,
  39.   Log2EEW3,
  40.   Log2EEW4,
  41.   Log2EEW5,
  42.   Log2EEW6,
  43.   FixedSEW8,
  44.   FixedSEW16,
  45.   FixedSEW32,
  46.   FixedSEW64,
  47.   LFixedLog2LMULN3,
  48.   LFixedLog2LMULN2,
  49.   LFixedLog2LMULN1,
  50.   LFixedLog2LMUL0,
  51.   LFixedLog2LMUL1,
  52.   LFixedLog2LMUL2,
  53.   LFixedLog2LMUL3,
  54.   SFixedLog2LMULN3,
  55.   SFixedLog2LMULN2,
  56.   SFixedLog2LMULN1,
  57.   SFixedLog2LMUL0,
  58.   SFixedLog2LMUL1,
  59.   SFixedLog2LMUL2,
  60.   SFixedLog2LMUL3,
  61. };
  62.  
  63. // Similar to basic type but used to describe what's kind of type related to
  64. // basic vector type, used to compute type info of arguments.
  65. enum class BaseTypeModifier : uint8_t {
  66.   Invalid,
  67.   Scalar,
  68.   Vector,
  69.   Void,
  70.   SizeT,
  71.   Ptrdiff,
  72.   UnsignedLong,
  73.   SignedLong,
  74. };
  75.  
  76. // Modifier for type, used for both scalar and vector types.
  77. enum class TypeModifier : uint8_t {
  78.   NoModifier = 0,
  79.   Pointer = 1 << 0,
  80.   Const = 1 << 1,
  81.   Immediate = 1 << 2,
  82.   UnsignedInteger = 1 << 3,
  83.   SignedInteger = 1 << 4,
  84.   Float = 1 << 5,
  85.   // LMUL1 should be kind of VectorTypeModifier, but that might come with
  86.   // Widening2XVector for widening reduction.
  87.   // However that might require VectorTypeModifier become bitmask rather than
  88.   // simple enum, so we decide keek LMUL1 in TypeModifier for code size
  89.   // optimization of clang binary size.
  90.   LMUL1 = 1 << 6,
  91.   MaxOffset = 6,
  92.   LLVM_MARK_AS_BITMASK_ENUM(LMUL1),
  93. };
  94.  
  95. class Policy {
  96. public:
  97.   enum PolicyType {
  98.     Undisturbed,
  99.     Agnostic,
  100.   };
  101.  
  102. private:
  103.   // The default assumption for an RVV instruction is TAMA, as an undisturbed
  104.   // policy generally will affect the performance of an out-of-order core.
  105.   const PolicyType TailPolicy = Agnostic;
  106.   const PolicyType MaskPolicy = Agnostic;
  107.  
  108. public:
  109.   Policy() = default;
  110.   Policy(PolicyType TailPolicy) : TailPolicy(TailPolicy) {}
  111.   Policy(PolicyType TailPolicy, PolicyType MaskPolicy)
  112.       : TailPolicy(TailPolicy), MaskPolicy(MaskPolicy) {}
  113.  
  114.   bool isTAMAPolicy() const {
  115.     return TailPolicy == Agnostic && MaskPolicy == Agnostic;
  116.   }
  117.  
  118.   bool isTAMUPolicy() const {
  119.     return TailPolicy == Agnostic && MaskPolicy == Undisturbed;
  120.   }
  121.  
  122.   bool isTUMAPolicy() const {
  123.     return TailPolicy == Undisturbed && MaskPolicy == Agnostic;
  124.   }
  125.  
  126.   bool isTUMUPolicy() const {
  127.     return TailPolicy == Undisturbed && MaskPolicy == Undisturbed;
  128.   }
  129.  
  130.   bool isTAPolicy() const { return TailPolicy == Agnostic; }
  131.  
  132.   bool isTUPolicy() const { return TailPolicy == Undisturbed; }
  133.  
  134.   bool isMAPolicy() const { return MaskPolicy == Agnostic; }
  135.  
  136.   bool isMUPolicy() const { return MaskPolicy == Undisturbed; }
  137.  
  138.   bool operator==(const Policy &Other) const {
  139.     return TailPolicy == Other.TailPolicy && MaskPolicy == Other.MaskPolicy;
  140.   }
  141.  
  142.   bool operator!=(const Policy &Other) const { return !(*this == Other); }
  143.  
  144.   bool operator<(const Policy &Other) const {
  145.     // Just for maintain the old order for quick test.
  146.     if (MaskPolicy != Other.MaskPolicy)
  147.       return Other.MaskPolicy < MaskPolicy;
  148.     return TailPolicy < Other.TailPolicy;
  149.   }
  150. };
  151.  
  152. // PrototypeDescriptor is used to compute type info of arguments or return
  153. // value.
  154. struct PrototypeDescriptor {
  155.   constexpr PrototypeDescriptor() = default;
  156.   constexpr PrototypeDescriptor(
  157.       BaseTypeModifier PT,
  158.       VectorTypeModifier VTM = VectorTypeModifier::NoModifier,
  159.       TypeModifier TM = TypeModifier::NoModifier)
  160.       : PT(static_cast<uint8_t>(PT)), VTM(static_cast<uint8_t>(VTM)),
  161.         TM(static_cast<uint8_t>(TM)) {}
  162.   constexpr PrototypeDescriptor(uint8_t PT, uint8_t VTM, uint8_t TM)
  163.       : PT(PT), VTM(VTM), TM(TM) {}
  164.  
  165.   uint8_t PT = static_cast<uint8_t>(BaseTypeModifier::Invalid);
  166.   uint8_t VTM = static_cast<uint8_t>(VectorTypeModifier::NoModifier);
  167.   uint8_t TM = static_cast<uint8_t>(TypeModifier::NoModifier);
  168.  
  169.   bool operator!=(const PrototypeDescriptor &PD) const {
  170.     return !(*this == PD);
  171.   }
  172.   bool operator==(const PrototypeDescriptor &PD) const {
  173.     return PD.PT == PT && PD.VTM == VTM && PD.TM == TM;
  174.   }
  175.   bool operator<(const PrototypeDescriptor &PD) const {
  176.     return std::tie(PT, VTM, TM) < std::tie(PD.PT, PD.VTM, PD.TM);
  177.   }
  178.   static const PrototypeDescriptor Mask;
  179.   static const PrototypeDescriptor Vector;
  180.   static const PrototypeDescriptor VL;
  181.   static std::optional<PrototypeDescriptor>
  182.   parsePrototypeDescriptor(llvm::StringRef PrototypeStr);
  183. };
  184.  
  185. llvm::SmallVector<PrototypeDescriptor>
  186. parsePrototypes(llvm::StringRef Prototypes);
  187.  
  188. // Basic type of vector type.
  189. enum class BasicType : uint8_t {
  190.   Unknown = 0,
  191.   Int8 = 1 << 0,
  192.   Int16 = 1 << 1,
  193.   Int32 = 1 << 2,
  194.   Int64 = 1 << 3,
  195.   Float16 = 1 << 4,
  196.   Float32 = 1 << 5,
  197.   Float64 = 1 << 6,
  198.   MaxOffset = 6,
  199.   LLVM_MARK_AS_BITMASK_ENUM(Float64),
  200. };
  201.  
  202. // Type of vector type.
  203. enum ScalarTypeKind : uint8_t {
  204.   Void,
  205.   Size_t,
  206.   Ptrdiff_t,
  207.   UnsignedLong,
  208.   SignedLong,
  209.   Boolean,
  210.   SignedInteger,
  211.   UnsignedInteger,
  212.   Float,
  213.   Invalid,
  214. };
  215.  
  216. // Exponential LMUL
  217. struct LMULType {
  218.   int Log2LMUL;
  219.   LMULType(int Log2LMUL);
  220.   // Return the C/C++ string representation of LMUL
  221.   std::string str() const;
  222.   std::optional<unsigned> getScale(unsigned ElementBitwidth) const;
  223.   void MulLog2LMUL(int Log2LMUL);
  224. };
  225.  
  226. class RVVType;
  227. using RVVTypePtr = RVVType *;
  228. using RVVTypes = std::vector<RVVTypePtr>;
  229. class RVVTypeCache;
  230.  
  231. // This class is compact representation of a valid and invalid RVVType.
  232. class RVVType {
  233.   friend class RVVTypeCache;
  234.  
  235.   BasicType BT;
  236.   ScalarTypeKind ScalarType = Invalid;
  237.   LMULType LMUL;
  238.   bool IsPointer = false;
  239.   // IsConstant indices are "int", but have the constant expression.
  240.   bool IsImmediate = false;
  241.   // Const qualifier for pointer to const object or object of const type.
  242.   bool IsConstant = false;
  243.   unsigned ElementBitwidth = 0;
  244.   VScaleVal Scale = 0;
  245.   bool Valid;
  246.  
  247.   std::string BuiltinStr;
  248.   std::string ClangBuiltinStr;
  249.   std::string Str;
  250.   std::string ShortStr;
  251.  
  252.   enum class FixedLMULType { LargerThan, SmallerThan };
  253.  
  254.   RVVType(BasicType BT, int Log2LMUL, const PrototypeDescriptor &Profile);
  255.  
  256. public:
  257.   // Return the string representation of a type, which is an encoded string for
  258.   // passing to the BUILTIN() macro in Builtins.def.
  259.   const std::string &getBuiltinStr() const { return BuiltinStr; }
  260.  
  261.   // Return the clang builtin type for RVV vector type which are used in the
  262.   // riscv_vector.h header file.
  263.   const std::string &getClangBuiltinStr() const { return ClangBuiltinStr; }
  264.  
  265.   // Return the C/C++ string representation of a type for use in the
  266.   // riscv_vector.h header file.
  267.   const std::string &getTypeStr() const { return Str; }
  268.  
  269.   // Return the short name of a type for C/C++ name suffix.
  270.   const std::string &getShortStr() {
  271.     // Not all types are used in short name, so compute the short name by
  272.     // demanded.
  273.     if (ShortStr.empty())
  274.       initShortStr();
  275.     return ShortStr;
  276.   }
  277.  
  278.   bool isValid() const { return Valid; }
  279.   bool isScalar() const { return Scale && *Scale == 0; }
  280.   bool isVector() const { return Scale && *Scale != 0; }
  281.   bool isVector(unsigned Width) const {
  282.     return isVector() && ElementBitwidth == Width;
  283.   }
  284.   bool isFloat() const { return ScalarType == ScalarTypeKind::Float; }
  285.   bool isSignedInteger() const {
  286.     return ScalarType == ScalarTypeKind::SignedInteger;
  287.   }
  288.   bool isFloatVector(unsigned Width) const {
  289.     return isVector() && isFloat() && ElementBitwidth == Width;
  290.   }
  291.   bool isFloat(unsigned Width) const {
  292.     return isFloat() && ElementBitwidth == Width;
  293.   }
  294.   bool isConstant() const { return IsConstant; }
  295.   bool isPointer() const { return IsPointer; }
  296.   unsigned getElementBitwidth() const { return ElementBitwidth; }
  297.  
  298.   ScalarTypeKind getScalarType() const { return ScalarType; }
  299.   VScaleVal getScale() const { return Scale; }
  300.  
  301. private:
  302.   // Verify RVV vector type and set Valid.
  303.   bool verifyType() const;
  304.  
  305.   // Creates a type based on basic types of TypeRange
  306.   void applyBasicType();
  307.  
  308.   // Applies a prototype modifier to the current type. The result maybe an
  309.   // invalid type.
  310.   void applyModifier(const PrototypeDescriptor &prototype);
  311.  
  312.   void applyLog2EEW(unsigned Log2EEW);
  313.   void applyFixedSEW(unsigned NewSEW);
  314.   void applyFixedLog2LMUL(int Log2LMUL, enum FixedLMULType Type);
  315.  
  316.   // Compute and record a string for legal type.
  317.   void initBuiltinStr();
  318.   // Compute and record a builtin RVV vector type string.
  319.   void initClangBuiltinStr();
  320.   // Compute and record a type string for used in the header.
  321.   void initTypeStr();
  322.   // Compute and record a short name of a type for C/C++ name suffix.
  323.   void initShortStr();
  324. };
  325.  
  326. // This class is used to manage RVVType, RVVType should only created by this
  327. // class, also provided thread-safe cache capability.
  328. class RVVTypeCache {
  329. private:
  330.   std::unordered_map<uint64_t, RVVType> LegalTypes;
  331.   std::set<uint64_t> IllegalTypes;
  332.  
  333. public:
  334.   /// Compute output and input types by applying different config (basic type
  335.   /// and LMUL with type transformers). It also record result of type in legal
  336.   /// or illegal set to avoid compute the same config again. The result maybe
  337.   /// have illegal RVVType.
  338.   std::optional<RVVTypes>
  339.   computeTypes(BasicType BT, int Log2LMUL, unsigned NF,
  340.                llvm::ArrayRef<PrototypeDescriptor> Prototype);
  341.   std::optional<RVVTypePtr> computeType(BasicType BT, int Log2LMUL,
  342.                                         PrototypeDescriptor Proto);
  343. };
  344.  
  345. enum PolicyScheme : uint8_t {
  346.   SchemeNone,
  347.   // Passthru operand is at first parameter in C builtin.
  348.   HasPassthruOperand,
  349.   HasPolicyOperand,
  350. };
  351.  
  352. // TODO refactor RVVIntrinsic class design after support all intrinsic
  353. // combination. This represents an instantiation of an intrinsic with a
  354. // particular type and prototype
  355. class RVVIntrinsic {
  356.  
  357. private:
  358.   std::string BuiltinName; // Builtin name
  359.   std::string Name;        // C intrinsic name.
  360.   std::string OverloadedName;
  361.   std::string IRName;
  362.   bool IsMasked;
  363.   bool HasMaskedOffOperand;
  364.   bool HasVL;
  365.   PolicyScheme Scheme;
  366.   bool SupportOverloading;
  367.   bool HasBuiltinAlias;
  368.   std::string ManualCodegen;
  369.   RVVTypePtr OutputType; // Builtin output type
  370.   RVVTypes InputTypes;   // Builtin input types
  371.   // The types we use to obtain the specific LLVM intrinsic. They are index of
  372.   // InputTypes. -1 means the return type.
  373.   std::vector<int64_t> IntrinsicTypes;
  374.   unsigned NF = 1;
  375.   Policy PolicyAttrs;
  376.  
  377. public:
  378.   RVVIntrinsic(llvm::StringRef Name, llvm::StringRef Suffix,
  379.                llvm::StringRef OverloadedName, llvm::StringRef OverloadedSuffix,
  380.                llvm::StringRef IRName, bool IsMasked, bool HasMaskedOffOperand,
  381.                bool HasVL, PolicyScheme Scheme, bool SupportOverloading,
  382.                bool HasBuiltinAlias, llvm::StringRef ManualCodegen,
  383.                const RVVTypes &Types,
  384.                const std::vector<int64_t> &IntrinsicTypes,
  385.                const std::vector<llvm::StringRef> &RequiredFeatures,
  386.                unsigned NF, Policy PolicyAttrs);
  387.   ~RVVIntrinsic() = default;
  388.  
  389.   RVVTypePtr getOutputType() const { return OutputType; }
  390.   const RVVTypes &getInputTypes() const { return InputTypes; }
  391.   llvm::StringRef getBuiltinName() const { return BuiltinName; }
  392.   llvm::StringRef getName() const { return Name; }
  393.   llvm::StringRef getOverloadedName() const { return OverloadedName; }
  394.   bool hasMaskedOffOperand() const { return HasMaskedOffOperand; }
  395.   bool hasVL() const { return HasVL; }
  396.   bool hasPolicy() const { return Scheme != PolicyScheme::SchemeNone; }
  397.   bool hasPassthruOperand() const {
  398.     return Scheme == PolicyScheme::HasPassthruOperand;
  399.   }
  400.   bool hasPolicyOperand() const {
  401.     return Scheme == PolicyScheme::HasPolicyOperand;
  402.   }
  403.   bool supportOverloading() const { return SupportOverloading; }
  404.   bool hasBuiltinAlias() const { return HasBuiltinAlias; }
  405.   bool hasManualCodegen() const { return !ManualCodegen.empty(); }
  406.   bool isMasked() const { return IsMasked; }
  407.   llvm::StringRef getIRName() const { return IRName; }
  408.   llvm::StringRef getManualCodegen() const { return ManualCodegen; }
  409.   PolicyScheme getPolicyScheme() const { return Scheme; }
  410.   unsigned getNF() const { return NF; }
  411.   const std::vector<int64_t> &getIntrinsicTypes() const {
  412.     return IntrinsicTypes;
  413.   }
  414.   Policy getPolicyAttrs() const {
  415.     return PolicyAttrs;
  416.   }
  417.   unsigned getPolicyAttrsBits() const {
  418.     // CGBuiltin.cpp
  419.     // The 0th bit simulates the `vta` of RVV
  420.     // The 1st bit simulates the `vma` of RVV
  421.     // int PolicyAttrs = 0;
  422.  
  423.     if (PolicyAttrs.isTUMAPolicy())
  424.       return 2;
  425.     if (PolicyAttrs.isTAMAPolicy())
  426.       return 3;
  427.     if (PolicyAttrs.isTUMUPolicy())
  428.       return 0;
  429.     if (PolicyAttrs.isTAMUPolicy())
  430.       return 1;
  431.  
  432.     llvm_unreachable("unsupport policy");
  433.     return 0;
  434.   }
  435.  
  436.   // Return the type string for a BUILTIN() macro in Builtins.def.
  437.   std::string getBuiltinTypeStr() const;
  438.  
  439.   static std::string
  440.   getSuffixStr(RVVTypeCache &TypeCache, BasicType Type, int Log2LMUL,
  441.                llvm::ArrayRef<PrototypeDescriptor> PrototypeDescriptors);
  442.  
  443.   static llvm::SmallVector<PrototypeDescriptor>
  444.   computeBuiltinTypes(llvm::ArrayRef<PrototypeDescriptor> Prototype,
  445.                       bool IsMasked, bool HasMaskedOffOperand, bool HasVL,
  446.                       unsigned NF, PolicyScheme DefaultScheme,
  447.                       Policy PolicyAttrs);
  448.  
  449.   static llvm::SmallVector<Policy> getSupportedUnMaskedPolicies();
  450.   static llvm::SmallVector<Policy>
  451.       getSupportedMaskedPolicies(bool HasTailPolicy, bool HasMaskPolicy);
  452.  
  453.   static void updateNamesAndPolicy(bool IsMasked, bool HasPolicy,
  454.                                    std::string &Name, std::string &BuiltinName,
  455.                                    std::string &OverloadedName,
  456.                                    Policy &PolicyAttrs);
  457. };
  458.  
  459. // RVVRequire should be sync'ed with target features, but only
  460. // required features used in riscv_vector.td.
  461. enum RVVRequire : uint8_t {
  462.   RVV_REQ_None = 0,
  463.   RVV_REQ_RV64 = 1 << 0,
  464.   RVV_REQ_FullMultiply = 1 << 1,
  465.  
  466.   LLVM_MARK_AS_BITMASK_ENUM(RVV_REQ_FullMultiply)
  467. };
  468.  
  469. // Raw RVV intrinsic info, used to expand later.
  470. // This struct is highly compact for minimized code size.
  471. struct RVVIntrinsicRecord {
  472.   // Intrinsic name, e.g. vadd_vv
  473.   const char *Name;
  474.  
  475.   // Overloaded intrinsic name, could be empty if it can be computed from Name.
  476.   // e.g. vadd
  477.   const char *OverloadedName;
  478.  
  479.   // Prototype for this intrinsic, index of RVVSignatureTable.
  480.   uint16_t PrototypeIndex;
  481.  
  482.   // Suffix of intrinsic name, index of RVVSignatureTable.
  483.   uint16_t SuffixIndex;
  484.  
  485.   // Suffix of overloaded intrinsic name, index of RVVSignatureTable.
  486.   uint16_t OverloadedSuffixIndex;
  487.  
  488.   // Length of the prototype.
  489.   uint8_t PrototypeLength;
  490.  
  491.   // Length of intrinsic name suffix.
  492.   uint8_t SuffixLength;
  493.  
  494.   // Length of overloaded intrinsic suffix.
  495.   uint8_t OverloadedSuffixSize;
  496.  
  497.   // Required target features for this intrinsic.
  498.   uint8_t RequiredExtensions;
  499.  
  500.   // Supported type, mask of BasicType.
  501.   uint8_t TypeRangeMask;
  502.  
  503.   // Supported LMUL.
  504.   uint8_t Log2LMULMask;
  505.  
  506.   // Number of fields, greater than 1 if it's segment load/store.
  507.   uint8_t NF;
  508.  
  509.   bool HasMasked : 1;
  510.   bool HasVL : 1;
  511.   bool HasMaskedOffOperand : 1;
  512.   bool HasTailPolicy : 1;
  513.   bool HasMaskPolicy : 1;
  514.   uint8_t UnMaskedPolicyScheme : 2;
  515.   uint8_t MaskedPolicyScheme : 2;
  516. };
  517.  
  518. llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
  519.                               const RVVIntrinsicRecord &RVVInstrRecord);
  520.  
  521. LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();
  522. } // end namespace RISCV
  523.  
  524. } // end namespace clang
  525.  
  526. #endif // CLANG_SUPPORT_RISCVVINTRINSICUTILS_H
  527.