235 lines
7.5 KiB
C++
235 lines
7.5 KiB
C++
//===-- RISCVTargetParser - Parser for target features ----------*- 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 implements a target parser to recognise hardware features
|
|
// for RISC-V CPUs.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef LLVM_TARGETPARSER_RISCVTARGETPARSER_H
|
|
#define LLVM_TARGETPARSER_RISCVTARGETPARSER_H
|
|
|
|
#include "llvm/ADT/StringRef.h"
|
|
#include "llvm/Support/Compiler.h"
|
|
#include "llvm/Support/Error.h"
|
|
#include "llvm/Support/MathExtras.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
|
|
namespace llvm {
|
|
|
|
class Triple;
|
|
|
|
namespace RISCV {
|
|
|
|
struct CPUModel {
|
|
uint32_t MVendorID;
|
|
uint64_t MArchID;
|
|
uint64_t MImpID;
|
|
|
|
bool isValid() const { return MVendorID != 0 && MArchID != 0 && MImpID != 0; }
|
|
|
|
bool operator==(const CPUModel &Other) const {
|
|
return MVendorID == Other.MVendorID && MArchID == Other.MArchID &&
|
|
MImpID == Other.MImpID;
|
|
}
|
|
};
|
|
|
|
struct CPUInfo {
|
|
StringLiteral Name;
|
|
StringLiteral DefaultMarch;
|
|
bool FastScalarUnalignedAccess;
|
|
bool FastVectorUnalignedAccess;
|
|
CPUModel Model;
|
|
bool is64Bit() const { return DefaultMarch.starts_with("rv64"); }
|
|
};
|
|
|
|
/// Fatal errors encountered during parsing.
|
|
struct ParserError : public ErrorInfo<ParserError, StringError> {
|
|
using ErrorInfo<ParserError, StringError>::ErrorInfo;
|
|
explicit ParserError(const Twine &S)
|
|
: ErrorInfo(S, inconvertibleErrorCode()) {}
|
|
LLVM_ABI static char ID;
|
|
};
|
|
|
|
/// Warnings encountered during parsing.
|
|
struct ParserWarning : public ErrorInfo<ParserWarning, StringError> {
|
|
using ErrorInfo<ParserWarning, StringError>::ErrorInfo;
|
|
explicit ParserWarning(const Twine &S)
|
|
: ErrorInfo(S, inconvertibleErrorCode()) {}
|
|
LLVM_ABI static char ID;
|
|
};
|
|
|
|
// We use 64 bits as the known part in the scalable vector types.
|
|
static constexpr unsigned RVVBitsPerBlock = 64;
|
|
static constexpr unsigned RVVBytesPerBlock = RVVBitsPerBlock / 8;
|
|
|
|
LLVM_ABI void getFeaturesForCPU(StringRef CPU,
|
|
SmallVectorImpl<std::string> &EnabledFeatures,
|
|
bool NeedPlus = false);
|
|
LLVM_ABI void getAllTuneFeatures(SmallVectorImpl<StringRef> &TuneFeatures);
|
|
LLVM_ABI void
|
|
getCPUConfigurableTuneFeatures(StringRef CPU,
|
|
SmallVectorImpl<StringRef> &Directives);
|
|
/// Parse the tune feature string with the respective processor. If \p ProcName
|
|
/// is empty, directives are not filtered by processor.
|
|
LLVM_ABI Error
|
|
parseTuneFeatureString(StringRef ProcName, StringRef TFString,
|
|
SmallVectorImpl<std::string> &TuneFeatures);
|
|
LLVM_ABI bool parseCPU(StringRef CPU, bool IsRV64);
|
|
LLVM_ABI bool parseTuneCPU(StringRef CPU, bool IsRV64);
|
|
LLVM_ABI StringRef getMArchFromMcpu(StringRef CPU);
|
|
LLVM_ABI void fillValidCPUArchList(SmallVectorImpl<StringRef> &Values,
|
|
bool IsRV64);
|
|
LLVM_ABI void fillValidTuneCPUArchList(SmallVectorImpl<StringRef> &Values,
|
|
bool IsRV64);
|
|
LLVM_ABI bool hasFastScalarUnalignedAccess(StringRef CPU);
|
|
LLVM_ABI bool hasFastVectorUnalignedAccess(StringRef CPU);
|
|
LLVM_ABI bool hasValidCPUModel(StringRef CPU);
|
|
LLVM_ABI CPUModel getCPUModel(StringRef CPU);
|
|
LLVM_ABI StringRef getCPUNameFromCPUModel(const CPUModel &Model);
|
|
|
|
} // namespace RISCV
|
|
|
|
namespace RISCVVType {
|
|
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,
|
|
};
|
|
|
|
// 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 <= 64;
|
|
}
|
|
|
|
// 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);
|
|
}
|
|
|
|
LLVM_ABI unsigned encodeVTYPE(VLMUL VLMUL, unsigned SEW, bool TailAgnostic,
|
|
bool MaskAgnostic, bool AltFmt = false);
|
|
|
|
LLVM_ABI unsigned encodeXSfmmVType(unsigned SEW, unsigned Widen, bool AltFmt);
|
|
|
|
namespace IME {
|
|
inline static bool isValidLambda(unsigned Lambda) {
|
|
return Lambda == 0 || (isPowerOf2_32(Lambda) && Lambda <= 64);
|
|
}
|
|
|
|
LLVM_ABI unsigned encodeLambda(unsigned Lambda);
|
|
|
|
LLVM_ABI std::optional<unsigned> decodeLambda(unsigned Encoding);
|
|
|
|
LLVM_ABI uint64_t getVTypeFieldsMask(unsigned XLen);
|
|
|
|
LLVM_ABI uint64_t encodeVTypeFields(unsigned XLen, unsigned Lambda,
|
|
bool AltFmtA, bool AltFmtB,
|
|
bool BlockSize16);
|
|
|
|
LLVM_ABI uint64_t addVTypeFields(uint64_t VType, unsigned XLen, unsigned Lambda,
|
|
bool AltFmtA, bool AltFmtB, bool BlockSize16);
|
|
|
|
LLVM_ABI unsigned getLambdaEncoding(uint64_t VType, unsigned XLen);
|
|
|
|
LLVM_ABI std::optional<unsigned> getLambda(uint64_t VType, unsigned XLen);
|
|
|
|
LLVM_ABI bool isAltFmtA(uint64_t VType, unsigned XLen);
|
|
|
|
LLVM_ABI bool isAltFmtB(uint64_t VType, unsigned XLen);
|
|
|
|
LLVM_ABI bool isBlockSize16(uint64_t VType, unsigned XLen);
|
|
} // namespace IME
|
|
|
|
inline static VLMUL getVLMUL(unsigned VType) {
|
|
unsigned VLMul = VType & 0x7;
|
|
return static_cast<VLMUL>(VLMul);
|
|
}
|
|
|
|
// Decode VLMUL into 1,2,4,8 and fractional indicator.
|
|
LLVM_ABI std::pair<unsigned, bool> decodeVLMUL(VLMUL VLMul);
|
|
|
|
inline static VLMUL encodeLMUL(unsigned LMUL, bool Fractional) {
|
|
assert(isValidLMUL(LMUL, Fractional) && "Unsupported LMUL");
|
|
unsigned LmulLog2 = Log2_32(LMUL);
|
|
return static_cast<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 unsigned decodeTWiden(unsigned TWiden) {
|
|
assert((TWiden == 1 || TWiden == 2 || TWiden == 3) &&
|
|
"Unexpected TWiden value");
|
|
return 1 << (TWiden - 1);
|
|
}
|
|
|
|
inline static bool hasXSfmmWiden(unsigned VType) {
|
|
unsigned TWiden = (VType >> 9) & 0x3;
|
|
return TWiden != 0;
|
|
}
|
|
|
|
inline static unsigned getXSfmmWiden(unsigned VType) {
|
|
unsigned TWiden = (VType >> 9) & 0x3;
|
|
assert(TWiden != 0 && "Invalid widen value");
|
|
return 1 << (TWiden - 1);
|
|
}
|
|
|
|
inline static bool isTailAgnostic(unsigned VType) { return VType & 0x40; }
|
|
|
|
inline static bool isMaskAgnostic(unsigned VType) { return VType & 0x80; }
|
|
|
|
inline static bool isAltFmt(unsigned VType) { return VType & 0x100; }
|
|
|
|
inline static bool isValidVType(unsigned VType) {
|
|
return getSEW(VType) <= 64 && getVLMUL(VType) != LMUL_RESERVED &&
|
|
(!isAltFmt(VType) || getSEW(VType) < 32);
|
|
}
|
|
|
|
static inline bool isValidXSfmmVType(unsigned VTypeI) {
|
|
return (VTypeI & ~0x738) == 0 && RISCVVType::hasXSfmmWiden(VTypeI) &&
|
|
RISCVVType::getSEW(VTypeI) * RISCVVType::getXSfmmWiden(VTypeI) <= 64 &&
|
|
isValidVType(VTypeI);
|
|
}
|
|
|
|
LLVM_ABI void printVType(unsigned VType, raw_ostream &OS);
|
|
|
|
LLVM_ABI void printXSfmmVType(unsigned VType, raw_ostream &OS);
|
|
|
|
LLVM_ABI unsigned getSEWLMULRatio(unsigned SEW, VLMUL VLMul);
|
|
|
|
LLVM_ABI std::optional<VLMUL> getSameRatioLMUL(unsigned Ratio, unsigned EEW);
|
|
} // namespace RISCVVType
|
|
|
|
} // namespace llvm
|
|
|
|
#endif
|