| //===-- RISCVBaseInfo.h - Top level definitions for RISCV MC ----*- 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 file contains small standalone enum definitions for the RISCV target | |
| // useful for the compiler back-end and the MC libraries. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #ifndef LLVM_LIB_TARGET_RISCV_MCTARGETDESC_RISCVBASEINFO_H | |
| #define LLVM_LIB_TARGET_RISCV_MCTARGETDESC_RISCVBASEINFO_H | |
| #include "MCTargetDesc/RISCVMCTargetDesc.h" | |
| #include "llvm/ADT/StringRef.h" | |
| #include "llvm/ADT/StringSwitch.h" | |
| #include "llvm/MC/MCInstrDesc.h" | |
| #include "llvm/MC/SubtargetFeature.h" | |
| #include "llvm/Support/RISCVISAInfo.h" | |
| namespace llvm { | |
| // RISCVII - This namespace holds all of the target specific flags that | |
| // instruction info tracks. All definitions must match RISCVInstrFormats.td. | |
| namespace RISCVII { | |
| enum { | |
| InstFormatPseudo = 0, | |
| InstFormatR = 1, | |
| InstFormatR4 = 2, | |
| InstFormatI = 3, | |
| InstFormatS = 4, | |
| InstFormatB = 5, | |
| InstFormatU = 6, | |
| InstFormatJ = 7, | |
| InstFormatCR = 8, | |
| InstFormatCI = 9, | |
| InstFormatCSS = 10, | |
| InstFormatCIW = 11, | |
| InstFormatCL = 12, | |
| InstFormatCS = 13, | |
| InstFormatCA = 14, | |
| InstFormatCB = 15, | |
| InstFormatCJ = 16, | |
| InstFormatOther = 17, | |
| InstFormatMask = 31, | |
| InstFormatShift = 0, | |
| ConstraintShift = InstFormatShift + 5, | |
| ConstraintMask = 0b111 << ConstraintShift, | |
| VLMulShift = ConstraintShift + 3, | |
| VLMulMask = 0b111 << VLMulShift, | |
| // Do we need to add a dummy mask op when converting RVV Pseudo to MCInst. | |
| HasDummyMaskOpShift = VLMulShift + 3, | |
| HasDummyMaskOpMask = 1 << HasDummyMaskOpShift, | |
| // Force a tail agnostic policy even this instruction has a tied destination. | |
| ForceTailAgnosticShift = HasDummyMaskOpShift + 1, | |
| ForceTailAgnosticMask = 1 << ForceTailAgnosticShift, | |
| // Does this instruction have a merge operand that must be removed when | |
| // converting to MCInst. It will be the first explicit use operand. Used by | |
| // RVV Pseudos. | |
| HasMergeOpShift = ForceTailAgnosticShift + 1, | |
| HasMergeOpMask = 1 << HasMergeOpShift, | |
| // Does this instruction have a SEW operand. It will be the last explicit | |
| // operand unless there is a vector policy operand. Used by RVV Pseudos. | |
| HasSEWOpShift = HasMergeOpShift + 1, | |
| HasSEWOpMask = 1 << HasSEWOpShift, | |
| // Does this instruction have a VL operand. It will be the second to last | |
| // explicit operand unless there is a vector policy operand. Used by RVV | |
| // Pseudos. | |
| HasVLOpShift = HasSEWOpShift + 1, | |
| HasVLOpMask = 1 << HasVLOpShift, | |
| // Does this instruction have a vector policy operand. It will be the last | |
| // explicit operand. Used by RVV Pseudos. | |
| HasVecPolicyOpShift = HasVLOpShift + 1, | |
| HasVecPolicyOpMask = 1 << HasVecPolicyOpShift, | |
| // Is this instruction a vector widening reduction instruction. Used by RVV | |
| // Pseudos. | |
| IsRVVWideningReductionShift = HasVecPolicyOpShift + 1, | |
| IsRVVWideningReductionMask = 1 << IsRVVWideningReductionShift, | |
| // Does this instruction care about mask policy. If it is not, the mask policy | |
| // could be either agnostic or undisturbed. For example, unmasked, store, and | |
| // reduction operations result would not be affected by mask policy, so | |
| // compiler has free to select either one. | |
| UsesMaskPolicyShift = IsRVVWideningReductionShift + 1, | |
| UsesMaskPolicyMask = 1 << UsesMaskPolicyShift, | |
| // Indicates that the result can be considered sign extended from bit 31. Some | |
| // instructions with this flag aren't W instructions, but are either sign | |
| // extended from a smaller size, always outputs a small integer, or put zeros | |
| // in bits 63:31. Used by the SExtWRemoval pass. | |
| IsSignExtendingOpWShift = UsesMaskPolicyShift + 1, | |
| IsSignExtendingOpWMask = 1ULL << IsSignExtendingOpWShift, | |
| }; | |
| // Match with the definitions in RISCVInstrFormats.td | |
| enum VConstraintType { | |
| NoConstraint = 0, | |
| VS2Constraint = 0b001, | |
| VS1Constraint = 0b010, | |
| VMConstraint = 0b100, | |
| }; | |
| enum VLMUL : uint8_t { | |
| LMUL_1 = 0, | |
| LMUL_2, | |
| LMUL_4, | |
| LMUL_8, | |
| LMUL_RESERVED, | |
| LMUL_F8, | |
| LMUL_F4, | |
| LMUL_F2 | |
| }; | |
| enum { | |
| TAIL_UNDISTURBED_MASK_UNDISTURBED = 0, | |
| TAIL_AGNOSTIC = 1, | |
| MASK_AGNOSTIC = 2, | |
| }; | |
| // Helper functions to read TSFlags. | |
| /// \returns the format of the instruction. | |
| static inline unsigned getFormat(uint64_t TSFlags) { | |
| return (TSFlags & InstFormatMask) >> InstFormatShift; | |
| } | |
| /// \returns the constraint for the instruction. | |
| static inline VConstraintType getConstraint(uint64_t TSFlags) { | |
| return static_cast<VConstraintType>((TSFlags & ConstraintMask) >> | |
| ConstraintShift); | |
| } | |
| /// \returns the LMUL for the instruction. | |
| static inline VLMUL getLMul(uint64_t TSFlags) { | |
| return static_cast<VLMUL>((TSFlags & VLMulMask) >> VLMulShift); | |
| } | |
| /// \returns true if there is a dummy mask operand for the instruction. | |
| static inline bool hasDummyMaskOp(uint64_t TSFlags) { | |
| return TSFlags & HasDummyMaskOpMask; | |
| } | |
| /// \returns true if tail agnostic is enforced for the instruction. | |
| static inline bool doesForceTailAgnostic(uint64_t TSFlags) { | |
| return TSFlags & ForceTailAgnosticMask; | |
| } | |
| /// \returns true if there is a merge operand for the instruction. | |
| static inline bool hasMergeOp(uint64_t TSFlags) { | |
| return TSFlags & HasMergeOpMask; | |
| } | |
| /// \returns true if there is a SEW operand for the instruction. | |
| static inline bool hasSEWOp(uint64_t TSFlags) { | |
| return TSFlags & HasSEWOpMask; | |
| } | |
| /// \returns true if there is a VL operand for the instruction. | |
| static inline bool hasVLOp(uint64_t TSFlags) { | |
| return TSFlags & HasVLOpMask; | |
| } | |
| /// \returns true if there is a vector policy operand for this instruction. | |
| static inline bool hasVecPolicyOp(uint64_t TSFlags) { | |
| return TSFlags & HasVecPolicyOpMask; | |
| } | |
| /// \returns true if it is a vector widening reduction instruction. | |
| static inline bool isRVVWideningReduction(uint64_t TSFlags) { | |
| return TSFlags & IsRVVWideningReductionMask; | |
| } | |
| /// \returns true if mask policy is valid for the instruction. | |
| static inline bool usesMaskPolicy(uint64_t TSFlags) { | |
| return TSFlags & UsesMaskPolicyMask; | |
| } | |
| static inline unsigned getMergeOpNum(const MCInstrDesc &Desc) { | |
| assert(hasMergeOp(Desc.TSFlags)); | |
| assert(!Desc.isVariadic()); | |
| return Desc.getNumDefs(); | |
| } | |
| static inline unsigned getVLOpNum(const MCInstrDesc &Desc) { | |
| const uint64_t TSFlags = Desc.TSFlags; | |
| // This method is only called if we expect to have a VL operand, and all | |
| // instructions with VL also have SEW. | |
| assert(hasSEWOp(TSFlags) && hasVLOp(TSFlags)); | |
| unsigned Offset = 2; | |
| if (hasVecPolicyOp(TSFlags)) | |
| Offset = 3; | |
| return Desc.getNumOperands() - Offset; | |
| } | |
| static inline unsigned getSEWOpNum(const MCInstrDesc &Desc) { | |
| const uint64_t TSFlags = Desc.TSFlags; | |
| assert(hasSEWOp(TSFlags)); | |
| unsigned Offset = 1; | |
| if (hasVecPolicyOp(TSFlags)) | |
| Offset = 2; | |
| return Desc.getNumOperands() - Offset; | |
| } | |
| static inline unsigned getVecPolicyOpNum(const MCInstrDesc &Desc) { | |
| assert(hasVecPolicyOp(Desc.TSFlags)); | |
| return Desc.getNumOperands() - 1; | |
| } | |
| // RISC-V Specific Machine Operand Flags | |
| enum { | |
| MO_None = 0, | |
| MO_CALL = 1, | |
| MO_PLT = 2, | |
| MO_LO = 3, | |
| MO_HI = 4, | |
| MO_PCREL_LO = 5, | |
| MO_PCREL_HI = 6, | |
| MO_GOT_HI = 7, | |
| MO_TPREL_LO = 8, | |
| MO_TPREL_HI = 9, | |
| MO_TPREL_ADD = 10, | |
| MO_TLS_GOT_HI = 11, | |
| MO_TLS_GD_HI = 12, | |
| // Used to differentiate between target-specific "direct" flags and "bitmask" | |
| // flags. A machine operand can only have one "direct" flag, but can have | |
| // multiple "bitmask" flags. | |
| MO_DIRECT_FLAG_MASK = 15 | |
| }; | |
| } // namespace RISCVII | |
| namespace RISCVOp { | |
| enum OperandType : unsigned { | |
| OPERAND_FIRST_RISCV_IMM = MCOI::OPERAND_FIRST_TARGET, | |
| OPERAND_UIMM2 = OPERAND_FIRST_RISCV_IMM, | |
| OPERAND_UIMM3, | |
| OPERAND_UIMM4, | |
| OPERAND_UIMM5, | |
| OPERAND_UIMM7, | |
| OPERAND_UIMM7_LSB00, | |
| OPERAND_UIMM8_LSB00, | |
| OPERAND_UIMM8_LSB000, | |
| OPERAND_UIMM12, | |
| OPERAND_ZERO, | |
| OPERAND_SIMM5, | |
| OPERAND_SIMM5_PLUS1, | |
| OPERAND_SIMM6, | |
| OPERAND_SIMM6_NONZERO, | |
| OPERAND_SIMM10_LSB0000_NONZERO, | |
| OPERAND_SIMM12, | |
| OPERAND_SIMM12_LSB00000, | |
| OPERAND_UIMM20, | |
| OPERAND_UIMMLOG2XLEN, | |
| OPERAND_UIMMLOG2XLEN_NONZERO, | |
| OPERAND_UIMM_SHFL, | |
| OPERAND_VTYPEI10, | |
| OPERAND_VTYPEI11, | |
| OPERAND_RVKRNUM, | |
| OPERAND_LAST_RISCV_IMM = OPERAND_RVKRNUM, | |
| // Operand is either a register or uimm5, this is used by V extension pseudo | |
| // instructions to represent a value that be passed as AVL to either vsetvli | |
| // or vsetivli. | |
| OPERAND_AVL, | |
| }; | |
| } // namespace RISCVOp | |
| // Describes the predecessor/successor bits used in the FENCE instruction. | |
| namespace RISCVFenceField { | |
| enum FenceField { | |
| I = 8, | |
| O = 4, | |
| R = 2, | |
| W = 1 | |
| }; | |
| } | |
| // Describes the supported floating point rounding mode encodings. | |
| namespace RISCVFPRndMode { | |
| enum RoundingMode { | |
| RNE = 0, | |
| RTZ = 1, | |
| RDN = 2, | |
| RUP = 3, | |
| RMM = 4, | |
| DYN = 7, | |
| Invalid | |
| }; | |
| inline static StringRef roundingModeToString(RoundingMode RndMode) { | |
| switch (RndMode) { | |
| default: | |
| llvm_unreachable("Unknown floating point rounding mode"); | |
| case RISCVFPRndMode::RNE: | |
| return "rne"; | |
| case RISCVFPRndMode::RTZ: | |
| return "rtz"; | |
| case RISCVFPRndMode::RDN: | |
| return "rdn"; | |
| case RISCVFPRndMode::RUP: | |
| return "rup"; | |
| case RISCVFPRndMode::RMM: | |
| return "rmm"; | |
| case RISCVFPRndMode::DYN: | |
| return "dyn"; | |
| } | |
| } | |
| inline static RoundingMode stringToRoundingMode(StringRef Str) { | |
| return StringSwitch<RoundingMode>(Str) | |
| .Case("rne", RISCVFPRndMode::RNE) | |
| .Case("rtz", RISCVFPRndMode::RTZ) | |
| .Case("rdn", RISCVFPRndMode::RDN) | |
| .Case("rup", RISCVFPRndMode::RUP) | |
| .Case("rmm", RISCVFPRndMode::RMM) | |
| .Case("dyn", RISCVFPRndMode::DYN) | |
| .Default(RISCVFPRndMode::Invalid); | |
| } | |
| inline static bool isValidRoundingMode(unsigned Mode) { | |
| switch (Mode) { | |
| default: | |
| return false; | |
| case RISCVFPRndMode::RNE: | |
| case RISCVFPRndMode::RTZ: | |
| case RISCVFPRndMode::RDN: | |
| case RISCVFPRndMode::RUP: | |
| case RISCVFPRndMode::RMM: | |
| case RISCVFPRndMode::DYN: | |
| return true; | |
| } | |
| } | |
| } // namespace RISCVFPRndMode | |
| namespace RISCVSysReg { | |
| struct SysReg { | |
| const char *Name; | |
| const char *AltName; | |
| const char *DeprecatedName; | |
| unsigned Encoding; | |
| // FIXME: add these additional fields when needed. | |
| // Privilege Access: Read, Write, Read-Only. | |
| // unsigned ReadWrite; | |
| // Privilege Mode: User, System or Machine. | |
| // unsigned Mode; | |
| // Check field name. | |
| // unsigned Extra; | |
| // Register number without the privilege bits. | |
| // unsigned Number; | |
| FeatureBitset FeaturesRequired; | |
| bool isRV32Only; | |
| bool haveRequiredFeatures(const FeatureBitset &ActiveFeatures) const { | |
| // Not in 32-bit mode. | |
| if (isRV32Only && ActiveFeatures[RISCV::Feature64Bit]) | |
| return false; | |
| // No required feature associated with the system register. | |
| if (FeaturesRequired.none()) | |
| return true; | |
| return (FeaturesRequired & ActiveFeatures) == FeaturesRequired; | |
| } | |
| }; | |
| #define GET_SysRegsList_DECL | |
| #include "RISCVGenSearchableTables.inc" | |
| } // end namespace RISCVSysReg | |
| namespace RISCVInsnOpcode { | |
| struct RISCVOpcode { | |
| const char *Name; | |
| unsigned Value; | |
| }; | |
| #define GET_RISCVOpcodesList_DECL | |
| #include "RISCVGenSearchableTables.inc" | |
| } // end namespace RISCVInsnOpcode | |
| namespace RISCVABI { | |
| enum ABI { | |
| ABI_ILP32, | |
| ABI_ILP32F, | |
| ABI_ILP32D, | |
| ABI_ILP32E, | |
| ABI_LP64, | |
| ABI_LP64F, | |
| ABI_LP64D, | |
| ABI_Unknown | |
| }; | |
| // Returns the target ABI, or else a StringError if the requested ABIName is | |
| // not supported for the given TT and FeatureBits combination. | |
| ABI computeTargetABI(const Triple &TT, FeatureBitset FeatureBits, | |
| StringRef ABIName); | |
| ABI getTargetABI(StringRef ABIName); | |
| // Returns the register used to hold the stack pointer after realignment. | |
| MCRegister getBPReg(); | |
| // Returns the register holding shadow call stack pointer. | |
| MCRegister getSCSPReg(); | |
| } // namespace RISCVABI | |
| namespace RISCVFeatures { | |
| // Validates if the given combination of features are valid for the target | |
| // triple. Exits with report_fatal_error if not. | |
| void validate(const Triple &TT, const FeatureBitset &FeatureBits); | |
| llvm::Expected<std::unique_ptr<RISCVISAInfo>> | |
| parseFeatureBits(bool IsRV64, const FeatureBitset &FeatureBits); | |
| } // namespace RISCVFeatures | |
| namespace RISCVVType { | |
| // Is this a SEW value that can be encoded into the VTYPE format. | |
| inline static bool isValidSEW(unsigned SEW) { | |
| return isPowerOf2_32(SEW) && SEW >= 8 && SEW <= 1024; | |
| } | |
| // Is this a LMUL value that can be encoded into the VTYPE format. | |
| inline static bool isValidLMUL(unsigned LMUL, bool Fractional) { | |
| return isPowerOf2_32(LMUL) && LMUL <= 8 && (!Fractional || LMUL != 1); | |
| } | |
| unsigned encodeVTYPE(RISCVII::VLMUL VLMUL, unsigned SEW, bool TailAgnostic, | |
| bool MaskAgnostic); | |
| inline static RISCVII::VLMUL getVLMUL(unsigned VType) { | |
| unsigned VLMUL = VType & 0x7; | |
| return static_cast<RISCVII::VLMUL>(VLMUL); | |
| } | |
| // Decode VLMUL into 1,2,4,8 and fractional indicator. | |
| std::pair<unsigned, bool> decodeVLMUL(RISCVII::VLMUL VLMUL); | |
| inline static RISCVII::VLMUL encodeLMUL(unsigned LMUL, bool Fractional) { | |
| assert(isValidLMUL(LMUL, Fractional) && "Unsupported LMUL"); | |
| unsigned LmulLog2 = Log2_32(LMUL); | |
| return static_cast<RISCVII::VLMUL>(Fractional ? 8 - LmulLog2 : LmulLog2); | |
| } | |
| inline static unsigned decodeVSEW(unsigned VSEW) { | |
| assert(VSEW < 8 && "Unexpected VSEW value"); | |
| return 1 << (VSEW + 3); | |
| } | |
| inline static unsigned encodeSEW(unsigned SEW) { | |
| assert(isValidSEW(SEW) && "Unexpected SEW value"); | |
| return Log2_32(SEW) - 3; | |
| } | |
| inline static unsigned getSEW(unsigned VType) { | |
| unsigned VSEW = (VType >> 3) & 0x7; | |
| return decodeVSEW(VSEW); | |
| } | |
| inline static bool isTailAgnostic(unsigned VType) { return VType & 0x40; } | |
| inline static bool isMaskAgnostic(unsigned VType) { return VType & 0x80; } | |
| void printVType(unsigned VType, raw_ostream &OS); | |
| unsigned getSEWLMULRatio(unsigned SEW, RISCVII::VLMUL VLMul); | |
| } // namespace RISCVVType | |
| namespace RISCVRVC { | |
| bool compress(MCInst &OutInst, const MCInst &MI, const MCSubtargetInfo &STI); | |
| bool uncompress(MCInst &OutInst, const MCInst &MI, const MCSubtargetInfo &STI); | |
| } // namespace RISCVRVC | |
| } // namespace llvm | |
| #endif |