#ifndef CLANG_SUPPORT_RISCVVINTRINSICUTILS_H
#define CLANG_SUPPORT_RISCVVINTRINSICUTILS_H
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/BitmaskEnum.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include <cstdint>
#include <string>
#include <vector>
namespace llvm {
class raw_ostream;
}
namespace clang {
namespace RISCV {
using VScaleVal = llvm::Optional<unsigned>;
enum class VectorTypeModifier : uint8_t {
NoModifier,
Widening2XVector,
Widening4XVector,
Widening8XVector,
MaskVector,
Log2EEW3,
Log2EEW4,
Log2EEW5,
Log2EEW6,
FixedSEW8,
FixedSEW16,
FixedSEW32,
FixedSEW64,
LFixedLog2LMULN3,
LFixedLog2LMULN2,
LFixedLog2LMULN1,
LFixedLog2LMUL0,
LFixedLog2LMUL1,
LFixedLog2LMUL2,
LFixedLog2LMUL3,
SFixedLog2LMULN3,
SFixedLog2LMULN2,
SFixedLog2LMULN1,
SFixedLog2LMUL0,
SFixedLog2LMUL1,
SFixedLog2LMUL2,
SFixedLog2LMUL3,
};
enum class BaseTypeModifier : uint8_t {
Invalid,
Scalar,
Vector,
Void,
SizeT,
Ptrdiff,
UnsignedLong,
SignedLong,
};
enum class TypeModifier : uint8_t {
NoModifier = 0,
Pointer = 1 << 0,
Const = 1 << 1,
Immediate = 1 << 2,
UnsignedInteger = 1 << 3,
SignedInteger = 1 << 4,
Float = 1 << 5,
LMUL1 = 1 << 6,
MaxOffset = 6,
LLVM_MARK_AS_BITMASK_ENUM(LMUL1),
};
struct PrototypeDescriptor {
constexpr PrototypeDescriptor() = default;
constexpr PrototypeDescriptor(
BaseTypeModifier PT,
VectorTypeModifier VTM = VectorTypeModifier::NoModifier,
TypeModifier TM = TypeModifier::NoModifier)
: PT(static_cast<uint8_t>(PT)), VTM(static_cast<uint8_t>(VTM)),
TM(static_cast<uint8_t>(TM)) {}
constexpr PrototypeDescriptor(uint8_t PT, uint8_t VTM, uint8_t TM)
: PT(PT), VTM(VTM), TM(TM) {}
uint8_t PT = static_cast<uint8_t>(BaseTypeModifier::Invalid);
uint8_t VTM = static_cast<uint8_t>(VectorTypeModifier::NoModifier);
uint8_t TM = static_cast<uint8_t>(TypeModifier::NoModifier);
bool operator!=(const PrototypeDescriptor &PD) const {
return !(*this == PD);
}
bool operator==(const PrototypeDescriptor &PD) const {
return PD.PT == PT && PD.VTM == VTM && PD.TM == TM;
}
bool operator<(const PrototypeDescriptor &PD) const {
return std::tie(PT, VTM, TM) < std::tie(PD.PT, PD.VTM, PD.TM);
}
static const PrototypeDescriptor Mask;
static const PrototypeDescriptor Vector;
static const PrototypeDescriptor VL;
static llvm::Optional<PrototypeDescriptor>
parsePrototypeDescriptor(llvm::StringRef PrototypeStr);
};
llvm::SmallVector<PrototypeDescriptor>
parsePrototypes(llvm::StringRef Prototypes);
enum class BasicType : uint8_t {
Unknown = 0,
Int8 = 1 << 0,
Int16 = 1 << 1,
Int32 = 1 << 2,
Int64 = 1 << 3,
Float16 = 1 << 4,
Float32 = 1 << 5,
Float64 = 1 << 6,
MaxOffset = 6,
LLVM_MARK_AS_BITMASK_ENUM(Float64),
};
enum ScalarTypeKind : uint8_t {
Void,
Size_t,
Ptrdiff_t,
UnsignedLong,
SignedLong,
Boolean,
SignedInteger,
UnsignedInteger,
Float,
Invalid,
};
struct LMULType {
int Log2LMUL;
LMULType(int Log2LMUL);
std::string str() const;
llvm::Optional<unsigned> getScale(unsigned ElementBitwidth) const;
void MulLog2LMUL(int Log2LMUL);
};
class RVVType;
using RVVTypePtr = RVVType *;
using RVVTypes = std::vector<RVVTypePtr>;
class RVVType {
BasicType BT;
ScalarTypeKind ScalarType = Invalid;
LMULType LMUL;
bool IsPointer = false;
bool IsImmediate = false;
bool IsConstant = false;
unsigned ElementBitwidth = 0;
VScaleVal Scale = 0;
bool Valid;
std::string BuiltinStr;
std::string ClangBuiltinStr;
std::string Str;
std::string ShortStr;
enum class FixedLMULType { LargerThan, SmallerThan };
public:
RVVType() : BT(BasicType::Unknown), LMUL(0), Valid(false) {}
RVVType(BasicType BT, int Log2LMUL, const PrototypeDescriptor &Profile);
const std::string &getBuiltinStr() const { return BuiltinStr; }
const std::string &getClangBuiltinStr() const { return ClangBuiltinStr; }
const std::string &getTypeStr() const { return Str; }
const std::string &getShortStr() {
if (ShortStr.empty())
initShortStr();
return ShortStr;
}
bool isValid() const { return Valid; }
bool isScalar() const { return Scale && Scale.value() == 0; }
bool isVector() const { return Scale && Scale.value() != 0; }
bool isVector(unsigned Width) const {
return isVector() && ElementBitwidth == Width;
}
bool isFloat() const { return ScalarType == ScalarTypeKind::Float; }
bool isSignedInteger() const {
return ScalarType == ScalarTypeKind::SignedInteger;
}
bool isFloatVector(unsigned Width) const {
return isVector() && isFloat() && ElementBitwidth == Width;
}
bool isFloat(unsigned Width) const {
return isFloat() && ElementBitwidth == Width;
}
bool isConstant() const { return IsConstant; }
bool isPointer() const { return IsPointer; }
unsigned getElementBitwidth() const { return ElementBitwidth; }
ScalarTypeKind getScalarType() const { return ScalarType; }
VScaleVal getScale() const { return Scale; }
private:
bool verifyType() const;
void applyBasicType();
void applyModifier(const PrototypeDescriptor &prototype);
void applyLog2EEW(unsigned Log2EEW);
void applyFixedSEW(unsigned NewSEW);
void applyFixedLog2LMUL(int Log2LMUL, enum FixedLMULType Type);
void initBuiltinStr();
void initClangBuiltinStr();
void initTypeStr();
void initShortStr();
public:
static llvm::Optional<RVVTypes>
computeTypes(BasicType BT, int Log2LMUL, unsigned NF,
llvm::ArrayRef<PrototypeDescriptor> Prototype);
static llvm::Optional<RVVTypePtr> computeType(BasicType BT, int Log2LMUL,
PrototypeDescriptor Proto);
};
enum PolicyScheme : uint8_t {
SchemeNone,
HasPassthruOperand,
HasPolicyOperand,
};
class RVVIntrinsic {
private:
std::string BuiltinName; std::string Name; std::string OverloadedName;
std::string IRName;
bool IsMasked;
bool HasVL;
PolicyScheme Scheme;
bool HasUnMaskedOverloaded;
bool HasBuiltinAlias;
std::string ManualCodegen;
RVVTypePtr OutputType; RVVTypes InputTypes; std::vector<int64_t> IntrinsicTypes;
unsigned NF = 1;
public:
RVVIntrinsic(llvm::StringRef Name, llvm::StringRef Suffix,
llvm::StringRef OverloadedName, llvm::StringRef OverloadedSuffix,
llvm::StringRef IRName, bool IsMasked, bool HasMaskedOffOperand,
bool HasVL, PolicyScheme Scheme, bool HasUnMaskedOverloaded,
bool HasBuiltinAlias, llvm::StringRef ManualCodegen,
const RVVTypes &Types,
const std::vector<int64_t> &IntrinsicTypes,
const std::vector<llvm::StringRef> &RequiredFeatures,
unsigned NF);
~RVVIntrinsic() = default;
RVVTypePtr getOutputType() const { return OutputType; }
const RVVTypes &getInputTypes() const { return InputTypes; }
llvm::StringRef getBuiltinName() const { return BuiltinName; }
llvm::StringRef getName() const { return Name; }
llvm::StringRef getOverloadedName() const { return OverloadedName; }
bool hasVL() const { return HasVL; }
bool hasPolicy() const { return Scheme != SchemeNone; }
bool hasPassthruOperand() const { return Scheme == HasPassthruOperand; }
bool hasPolicyOperand() const { return Scheme == HasPolicyOperand; }
bool hasUnMaskedOverloaded() const { return HasUnMaskedOverloaded; }
bool hasBuiltinAlias() const { return HasBuiltinAlias; }
bool hasManualCodegen() const { return !ManualCodegen.empty(); }
bool isMasked() const { return IsMasked; }
llvm::StringRef getIRName() const { return IRName; }
llvm::StringRef getManualCodegen() const { return ManualCodegen; }
PolicyScheme getPolicyScheme() const { return Scheme; }
unsigned getNF() const { return NF; }
const std::vector<int64_t> &getIntrinsicTypes() const {
return IntrinsicTypes;
}
std::string getBuiltinTypeStr() const;
static std::string
getSuffixStr(BasicType Type, int Log2LMUL,
llvm::ArrayRef<PrototypeDescriptor> PrototypeDescriptors);
static llvm::SmallVector<PrototypeDescriptor>
computeBuiltinTypes(llvm::ArrayRef<PrototypeDescriptor> Prototype,
bool IsMasked, bool HasMaskedOffOperand, bool HasVL,
unsigned NF);
};
enum RVVRequire : uint8_t {
RVV_REQ_None = 0,
RVV_REQ_RV64 = 1 << 0,
RVV_REQ_FullMultiply = 1 << 1,
LLVM_MARK_AS_BITMASK_ENUM(RVV_REQ_FullMultiply)
};
struct RVVIntrinsicRecord {
const char *Name;
const char *OverloadedName;
uint16_t PrototypeIndex;
uint16_t SuffixIndex;
uint16_t OverloadedSuffixIndex;
uint8_t PrototypeLength;
uint8_t SuffixLength;
uint8_t OverloadedSuffixSize;
uint8_t RequiredExtensions;
uint8_t TypeRangeMask;
uint8_t Log2LMULMask;
uint8_t NF;
bool HasMasked : 1;
bool HasVL : 1;
bool HasMaskedOffOperand : 1;
};
llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
const RVVIntrinsicRecord &RVVInstrRecord);
LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();
}
}
#endif