[RISCV] Unify the arch string parsing logic to to RISCVISAInfo.
How many place you need to modify when implementing a new extension for RISC-V? At least 7 places as I know: - Add new SubtargetFeature at RISCV.td - -march parser in RISCV.cpp - RISCVTargetInfo::initFeatureMap@RISCV.cpp for handling feature vector. - RISCVTargetInfo::getTargetDefines@RISCV.cpp for pre-define marco. - Arch string parser for ELF attribute in RISCVAsmParser.cpp - ELF attribute emittion in RISCVAsmParser.cpp, and make sure it's in canonical order... - ELF attribute emittion in RISCVTargetStreamer.cpp, and again, must in canonical order... And now, this patch provide an unified infrastructure for handling (almost) everything of RISC-V arch string. After this patch, you only need to update 2 places for implement an extension for RISC-V: - Add new SubtargetFeature at RISCV.td, hmmm, it's hard to avoid. - Add new entry to RISCVSupportedExtension@RISCVISAInfo.cpp or SupportedExperimentalExtensions@RISCVISAInfo.cpp . Most codes are come from existing -march parser, but with few new feature/bug fixes: - Accept version for -march, e.g. -march=rv32i2p0. - Reject version info with `p` but without minor version number like `rv32i2p`. Differential Revision: https://reviews.llvm.org/D105168
This commit is contained in:
@@ -306,6 +306,8 @@ def err_opt_not_valid_without_opt : Error<
|
||||
"option '%0' cannot be specified without '%1'">;
|
||||
def err_opt_not_valid_on_target : Error<
|
||||
"option '%0' cannot be specified on this target">;
|
||||
def err_invalid_feature_combination : Error<
|
||||
"invalid feature combination: %0">;
|
||||
|
||||
// Source manager
|
||||
def err_cannot_open_file : Error<"cannot open file '%0': %1">, DefaultFatal;
|
||||
|
||||
@@ -11,10 +11,12 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "RISCV.h"
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
#include "clang/Basic/MacroBuilder.h"
|
||||
#include "clang/Basic/TargetBuiltins.h"
|
||||
#include "llvm/ADT/StringSwitch.h"
|
||||
#include "llvm/Support/TargetParser.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
using namespace clang;
|
||||
using namespace clang::targets;
|
||||
@@ -122,6 +124,7 @@ void RISCVTargetInfo::getTargetDefines(const LangOptions &Opts,
|
||||
bool Is64Bit = getTriple().getArch() == llvm::Triple::riscv64;
|
||||
Builder.defineMacro("__riscv_xlen", Is64Bit ? "64" : "32");
|
||||
StringRef CodeModel = getTargetOpts().CodeModel;
|
||||
unsigned FLen = ISAInfo->getFLen();
|
||||
if (CodeModel == "default")
|
||||
CodeModel = "small";
|
||||
|
||||
@@ -142,17 +145,23 @@ void RISCVTargetInfo::getTargetDefines(const LangOptions &Opts,
|
||||
Builder.defineMacro("__riscv_abi_rve");
|
||||
|
||||
Builder.defineMacro("__riscv_arch_test");
|
||||
Builder.defineMacro("__riscv_i", "2000000");
|
||||
|
||||
if (HasM) {
|
||||
Builder.defineMacro("__riscv_m", "2000000");
|
||||
for (auto &Extension : ISAInfo->getExtensions()) {
|
||||
auto ExtName = Extension.first;
|
||||
auto ExtInfo = Extension.second;
|
||||
unsigned Version =
|
||||
(ExtInfo.MajorVersion * 1000000) + (ExtInfo.MinorVersion * 1000);
|
||||
|
||||
Builder.defineMacro(Twine("__riscv_", ExtName), Twine(Version));
|
||||
}
|
||||
|
||||
if (ISAInfo->hasExtension("m")) {
|
||||
Builder.defineMacro("__riscv_mul");
|
||||
Builder.defineMacro("__riscv_div");
|
||||
Builder.defineMacro("__riscv_muldiv");
|
||||
}
|
||||
|
||||
if (HasA) {
|
||||
Builder.defineMacro("__riscv_a", "2000000");
|
||||
if (ISAInfo->hasExtension("a")) {
|
||||
Builder.defineMacro("__riscv_atomic");
|
||||
Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1");
|
||||
Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2");
|
||||
@@ -161,64 +170,17 @@ void RISCVTargetInfo::getTargetDefines(const LangOptions &Opts,
|
||||
Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8");
|
||||
}
|
||||
|
||||
if (HasF || HasD) {
|
||||
Builder.defineMacro("__riscv_f", "2000000");
|
||||
Builder.defineMacro("__riscv_flen", HasD ? "64" : "32");
|
||||
if (FLen) {
|
||||
Builder.defineMacro("__riscv_flen", Twine(FLen));
|
||||
Builder.defineMacro("__riscv_fdiv");
|
||||
Builder.defineMacro("__riscv_fsqrt");
|
||||
}
|
||||
|
||||
if (HasD)
|
||||
Builder.defineMacro("__riscv_d", "2000000");
|
||||
|
||||
if (HasC) {
|
||||
Builder.defineMacro("__riscv_c", "2000000");
|
||||
if (ISAInfo->hasExtension("c"))
|
||||
Builder.defineMacro("__riscv_compressed");
|
||||
}
|
||||
|
||||
if (HasV) {
|
||||
Builder.defineMacro("__riscv_v", "10000");
|
||||
if (ISAInfo->hasExtension("v"))
|
||||
Builder.defineMacro("__riscv_vector");
|
||||
}
|
||||
|
||||
if (HasZba)
|
||||
Builder.defineMacro("__riscv_zba", "1000000");
|
||||
|
||||
if (HasZbb)
|
||||
Builder.defineMacro("__riscv_zbb", "1000000");
|
||||
|
||||
if (HasZbc)
|
||||
Builder.defineMacro("__riscv_zbc", "1000000");
|
||||
|
||||
if (HasZbe)
|
||||
Builder.defineMacro("__riscv_zbe", "93000");
|
||||
|
||||
if (HasZbf)
|
||||
Builder.defineMacro("__riscv_zbf", "93000");
|
||||
|
||||
if (HasZbm)
|
||||
Builder.defineMacro("__riscv_zbm", "93000");
|
||||
|
||||
if (HasZbp)
|
||||
Builder.defineMacro("__riscv_zbp", "93000");
|
||||
|
||||
if (HasZbr)
|
||||
Builder.defineMacro("__riscv_zbr", "93000");
|
||||
|
||||
if (HasZbs)
|
||||
Builder.defineMacro("__riscv_zbs", "1000000");
|
||||
|
||||
if (HasZbt)
|
||||
Builder.defineMacro("__riscv_zbt", "93000");
|
||||
|
||||
if (HasZfh)
|
||||
Builder.defineMacro("__riscv_zfh", "1000");
|
||||
|
||||
if (HasZvamo)
|
||||
Builder.defineMacro("__riscv_zvamo", "10000");
|
||||
|
||||
if (HasZvlsseg)
|
||||
Builder.defineMacro("__riscv_zvlsseg", "10000");
|
||||
}
|
||||
|
||||
const Builtin::Info RISCVTargetInfo::BuiltinInfo[] = {
|
||||
@@ -247,75 +209,36 @@ bool RISCVTargetInfo::initFeatureMap(
|
||||
/// Return true if has this feature, need to sync with handleTargetFeatures.
|
||||
bool RISCVTargetInfo::hasFeature(StringRef Feature) const {
|
||||
bool Is64Bit = getTriple().getArch() == llvm::Triple::riscv64;
|
||||
return llvm::StringSwitch<bool>(Feature)
|
||||
.Case("riscv", true)
|
||||
.Case("riscv32", !Is64Bit)
|
||||
.Case("riscv64", Is64Bit)
|
||||
.Case("64bit", Is64Bit)
|
||||
.Case("m", HasM)
|
||||
.Case("a", HasA)
|
||||
.Case("f", HasF)
|
||||
.Case("d", HasD)
|
||||
.Case("c", HasC)
|
||||
.Case("experimental-v", HasV)
|
||||
.Case("experimental-zba", HasZba)
|
||||
.Case("experimental-zbb", HasZbb)
|
||||
.Case("experimental-zbc", HasZbc)
|
||||
.Case("experimental-zbe", HasZbe)
|
||||
.Case("experimental-zbf", HasZbf)
|
||||
.Case("experimental-zbm", HasZbm)
|
||||
.Case("experimental-zbp", HasZbp)
|
||||
.Case("experimental-zbr", HasZbr)
|
||||
.Case("experimental-zbs", HasZbs)
|
||||
.Case("experimental-zbt", HasZbt)
|
||||
.Case("experimental-zfh", HasZfh)
|
||||
.Case("experimental-zvamo", HasZvamo)
|
||||
.Case("experimental-zvlsseg", HasZvlsseg)
|
||||
.Default(false);
|
||||
auto Result = llvm::StringSwitch<Optional<bool>>(Feature)
|
||||
.Case("riscv", true)
|
||||
.Case("riscv32", !Is64Bit)
|
||||
.Case("riscv64", Is64Bit)
|
||||
.Case("64bit", Is64Bit)
|
||||
.Default(None);
|
||||
if (Result.hasValue())
|
||||
return Result.getValue();
|
||||
|
||||
if (ISAInfo->isSupportedExtensionFeature(Feature))
|
||||
return ISAInfo->hasExtension(Feature);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Perform initialization based on the user configured set of features.
|
||||
bool RISCVTargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
|
||||
DiagnosticsEngine &Diags) {
|
||||
for (const auto &Feature : Features) {
|
||||
if (Feature == "+m")
|
||||
HasM = true;
|
||||
else if (Feature == "+a")
|
||||
HasA = true;
|
||||
else if (Feature == "+f")
|
||||
HasF = true;
|
||||
else if (Feature == "+d")
|
||||
HasD = true;
|
||||
else if (Feature == "+c")
|
||||
HasC = true;
|
||||
else if (Feature == "+experimental-v")
|
||||
HasV = true;
|
||||
else if (Feature == "+experimental-zba")
|
||||
HasZba = true;
|
||||
else if (Feature == "+experimental-zbb")
|
||||
HasZbb = true;
|
||||
else if (Feature == "+experimental-zbc")
|
||||
HasZbc = true;
|
||||
else if (Feature == "+experimental-zbe")
|
||||
HasZbe = true;
|
||||
else if (Feature == "+experimental-zbf")
|
||||
HasZbf = true;
|
||||
else if (Feature == "+experimental-zbm")
|
||||
HasZbm = true;
|
||||
else if (Feature == "+experimental-zbp")
|
||||
HasZbp = true;
|
||||
else if (Feature == "+experimental-zbr")
|
||||
HasZbr = true;
|
||||
else if (Feature == "+experimental-zbs")
|
||||
HasZbs = true;
|
||||
else if (Feature == "+experimental-zbt")
|
||||
HasZbt = true;
|
||||
else if (Feature == "+experimental-zfh")
|
||||
HasZfh = true;
|
||||
else if (Feature == "+experimental-zvamo")
|
||||
HasZvamo = true;
|
||||
else if (Feature == "+experimental-zvlsseg")
|
||||
HasZvlsseg = true;
|
||||
unsigned XLen = getTriple().isArch64Bit() ? 64 : 32;
|
||||
auto ParseResult = llvm::RISCVISAInfo::parseFeatures(XLen, Features);
|
||||
if (!ParseResult) {
|
||||
std::string Buffer;
|
||||
llvm::raw_string_ostream OutputErrMsg(Buffer);
|
||||
handleAllErrors(ParseResult.takeError(), [&](llvm::StringError &ErrMsg) {
|
||||
OutputErrMsg << ErrMsg.getMessage();
|
||||
});
|
||||
Diags.Report(diag::err_invalid_feature_combination) << OutputErrMsg.str();
|
||||
return false;
|
||||
} else {
|
||||
ISAInfo = std::move(*ParseResult);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "clang/Basic/TargetOptions.h"
|
||||
#include "llvm/ADT/Triple.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/RISCVISAInfo.h"
|
||||
|
||||
namespace clang {
|
||||
namespace targets {
|
||||
@@ -25,26 +26,7 @@ namespace targets {
|
||||
class RISCVTargetInfo : public TargetInfo {
|
||||
protected:
|
||||
std::string ABI, CPU;
|
||||
bool HasM = false;
|
||||
bool HasA = false;
|
||||
bool HasF = false;
|
||||
bool HasD = false;
|
||||
bool HasC = false;
|
||||
bool HasV = false;
|
||||
bool HasZba = false;
|
||||
bool HasZbb = false;
|
||||
bool HasZbc = false;
|
||||
bool HasZbe = false;
|
||||
bool HasZbf = false;
|
||||
bool HasZbm = false;
|
||||
bool HasZbp = false;
|
||||
bool HasZbr = false;
|
||||
bool HasZbs = false;
|
||||
bool HasZbt = false;
|
||||
bool HasZfh = false;
|
||||
bool HasZvamo = false;
|
||||
bool HasZvlsseg = false;
|
||||
|
||||
std::unique_ptr<llvm::RISCVISAInfo> ISAInfo;
|
||||
static const Builtin::Info BuiltinInfo[];
|
||||
|
||||
public:
|
||||
@@ -141,7 +123,7 @@ public:
|
||||
void setMaxAtomicWidth() override {
|
||||
MaxAtomicPromoteWidth = 128;
|
||||
|
||||
if (HasA)
|
||||
if (ISAInfo->hasExtension("a"))
|
||||
MaxAtomicInlineWidth = 32;
|
||||
}
|
||||
};
|
||||
@@ -170,7 +152,7 @@ public:
|
||||
void setMaxAtomicWidth() override {
|
||||
MaxAtomicPromoteWidth = 128;
|
||||
|
||||
if (HasA)
|
||||
if (ISAInfo->hasExtension("a"))
|
||||
MaxAtomicInlineWidth = 64;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -7,450 +7,41 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "RISCV.h"
|
||||
#include "ToolChains/CommonArgs.h"
|
||||
#include "clang/Basic/CharInfo.h"
|
||||
#include "clang/Driver/Driver.h"
|
||||
#include "clang/Driver/DriverDiagnostic.h"
|
||||
#include "clang/Driver/Options.h"
|
||||
#include "llvm/Option/ArgList.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/Option/ArgList.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include "llvm/Support/RISCVISAInfo.h"
|
||||
#include "llvm/Support/TargetParser.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "ToolChains/CommonArgs.h"
|
||||
|
||||
using namespace clang::driver;
|
||||
using namespace clang::driver::tools;
|
||||
using namespace clang;
|
||||
using namespace llvm::opt;
|
||||
|
||||
namespace {
|
||||
// Represents the major and version number components of a RISC-V extension
|
||||
struct RISCVExtensionVersion {
|
||||
StringRef Major;
|
||||
StringRef Minor;
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
static StringRef getExtensionTypeDesc(StringRef Ext) {
|
||||
if (Ext.startswith("sx"))
|
||||
return "non-standard supervisor-level extension";
|
||||
if (Ext.startswith("s"))
|
||||
return "standard supervisor-level extension";
|
||||
if (Ext.startswith("x"))
|
||||
return "non-standard user-level extension";
|
||||
if (Ext.startswith("z"))
|
||||
return "standard user-level extension";
|
||||
return StringRef();
|
||||
}
|
||||
|
||||
static StringRef getExtensionType(StringRef Ext) {
|
||||
if (Ext.startswith("sx"))
|
||||
return "sx";
|
||||
if (Ext.startswith("s"))
|
||||
return "s";
|
||||
if (Ext.startswith("x"))
|
||||
return "x";
|
||||
if (Ext.startswith("z"))
|
||||
return "z";
|
||||
return StringRef();
|
||||
}
|
||||
|
||||
// If the extension is supported as experimental, return the version of that
|
||||
// extension that the compiler currently supports.
|
||||
static Optional<RISCVExtensionVersion>
|
||||
isExperimentalExtension(StringRef Ext) {
|
||||
if (Ext == "zba" || Ext == "zbb" || Ext == "zbc" || Ext == "zbs")
|
||||
return RISCVExtensionVersion{"1", "0"};
|
||||
if (Ext == "zbe" || Ext == "zbf" || Ext == "zbm" || Ext == "zbp" ||
|
||||
Ext == "zbr" || Ext == "zbt")
|
||||
return RISCVExtensionVersion{"0", "93"};
|
||||
if (Ext == "v" || Ext == "zvamo" || Ext == "zvlsseg")
|
||||
return RISCVExtensionVersion{"0", "10"};
|
||||
if (Ext == "zfh")
|
||||
return RISCVExtensionVersion{"0", "1"};
|
||||
return None;
|
||||
}
|
||||
|
||||
static bool isSupportedExtension(StringRef Ext) {
|
||||
// LLVM supports "z" extensions which are marked as experimental.
|
||||
if (isExperimentalExtension(Ext))
|
||||
return true;
|
||||
|
||||
// LLVM does not support "sx", "s" nor "x" extensions.
|
||||
return false;
|
||||
}
|
||||
|
||||
// Extensions may have a version number, and may be separated by
|
||||
// an underscore '_' e.g.: rv32i2_m2.
|
||||
// Version number is divided into major and minor version numbers,
|
||||
// separated by a 'p'. If the minor version is 0 then 'p0' can be
|
||||
// omitted from the version string. E.g., rv32i2p0, rv32i2, rv32i2p1.
|
||||
static bool getExtensionVersion(const Driver &D, const ArgList &Args,
|
||||
StringRef MArch, StringRef Ext, StringRef In,
|
||||
std::string &Major, std::string &Minor) {
|
||||
Major = std::string(In.take_while(isDigit));
|
||||
In = In.substr(Major.size());
|
||||
|
||||
if (Major.size() && In.consume_front("p")) {
|
||||
Minor = std::string(In.take_while(isDigit));
|
||||
In = In.substr(Major.size() + 1);
|
||||
|
||||
// Expected 'p' to be followed by minor version number.
|
||||
if (Minor.empty()) {
|
||||
std::string Error =
|
||||
"minor version number missing after 'p' for extension";
|
||||
D.Diag(diag::err_drv_invalid_riscv_ext_arch_name)
|
||||
<< MArch << Error << Ext;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Expected multi-character extension with version number to have no
|
||||
// subsequent characters (i.e. must either end string or be followed by
|
||||
// an underscore).
|
||||
if (Ext.size() > 1 && In.size()) {
|
||||
std::string Error =
|
||||
"multi-character extensions must be separated by underscores";
|
||||
D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) << MArch << Error << In;
|
||||
return false;
|
||||
}
|
||||
|
||||
// If experimental extension, require use of current version number number
|
||||
if (auto ExperimentalExtension = isExperimentalExtension(Ext)) {
|
||||
if (!Args.hasArg(options::OPT_menable_experimental_extensions)) {
|
||||
std::string Error =
|
||||
"requires '-menable-experimental-extensions' for experimental extension";
|
||||
D.Diag(diag::err_drv_invalid_riscv_ext_arch_name)
|
||||
<< MArch << Error << Ext;
|
||||
return false;
|
||||
} else if (Major.empty() && Minor.empty()) {
|
||||
std::string Error =
|
||||
"experimental extension requires explicit version number";
|
||||
D.Diag(diag::err_drv_invalid_riscv_ext_arch_name)
|
||||
<< MArch << Error << Ext;
|
||||
return false;
|
||||
}
|
||||
auto SupportedVers = *ExperimentalExtension;
|
||||
if (Major != SupportedVers.Major || Minor != SupportedVers.Minor) {
|
||||
std::string Error =
|
||||
"unsupported version number " + Major;
|
||||
if (!Minor.empty())
|
||||
Error += "." + Minor;
|
||||
Error += " for experimental extension (this compiler supports "
|
||||
+ SupportedVers.Major.str() + "."
|
||||
+ SupportedVers.Minor.str() + ")";
|
||||
|
||||
D.Diag(diag::err_drv_invalid_riscv_ext_arch_name)
|
||||
<< MArch << Error << Ext;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Allow extensions to declare no version number
|
||||
if (Major.empty() && Minor.empty())
|
||||
return true;
|
||||
|
||||
// TODO: Handle supported extensions with version number.
|
||||
std::string Error = "unsupported version number " + Major;
|
||||
if (!Minor.empty())
|
||||
Error += "." + Minor;
|
||||
Error += " for extension";
|
||||
D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) << MArch << Error << Ext;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Handle other types of extensions other than the standard
|
||||
// general purpose and standard user-level extensions.
|
||||
// Parse the ISA string containing non-standard user-level
|
||||
// extensions, standard supervisor-level extensions and
|
||||
// non-standard supervisor-level extensions.
|
||||
// These extensions start with 'z', 'x', 's', 'sx' prefixes, follow a
|
||||
// canonical order, might have a version number (major, minor)
|
||||
// and are separated by a single underscore '_'.
|
||||
// Set the hardware features for the extensions that are supported.
|
||||
static void getExtensionFeatures(const Driver &D,
|
||||
const ArgList &Args,
|
||||
std::vector<StringRef> &Features,
|
||||
StringRef &MArch, StringRef &Exts) {
|
||||
if (Exts.empty())
|
||||
return;
|
||||
|
||||
// Multi-letter extensions are seperated by a single underscore
|
||||
// as described in RISC-V User-Level ISA V2.2.
|
||||
SmallVector<StringRef, 8> Split;
|
||||
Exts.split(Split, StringRef("_"));
|
||||
|
||||
SmallVector<StringRef, 4> Prefix{"z", "x", "s", "sx"};
|
||||
auto I = Prefix.begin();
|
||||
auto E = Prefix.end();
|
||||
|
||||
SmallVector<StringRef, 8> AllExts;
|
||||
|
||||
for (StringRef Ext : Split) {
|
||||
if (Ext.empty()) {
|
||||
D.Diag(diag::err_drv_invalid_riscv_arch_name) << MArch
|
||||
<< "extension name missing after separator '_'";
|
||||
return;
|
||||
}
|
||||
|
||||
StringRef Type = getExtensionType(Ext);
|
||||
StringRef Desc = getExtensionTypeDesc(Ext);
|
||||
auto Pos = Ext.find_if(isDigit);
|
||||
StringRef Name(Ext.substr(0, Pos));
|
||||
StringRef Vers(Ext.substr(Pos));
|
||||
|
||||
if (Type.empty()) {
|
||||
D.Diag(diag::err_drv_invalid_riscv_ext_arch_name)
|
||||
<< MArch << "invalid extension prefix" << Ext;
|
||||
return;
|
||||
}
|
||||
|
||||
// Check ISA extensions are specified in the canonical order.
|
||||
while (I != E && *I != Type)
|
||||
++I;
|
||||
|
||||
if (I == E) {
|
||||
std::string Error = std::string(Desc);
|
||||
Error += " not given in canonical order";
|
||||
D.Diag(diag::err_drv_invalid_riscv_ext_arch_name)
|
||||
<< MArch << Error << Ext;
|
||||
return;
|
||||
}
|
||||
|
||||
// The order is OK, do not advance I to the next prefix
|
||||
// to allow repeated extension type, e.g.: rv32ixabc_xdef.
|
||||
|
||||
if (Name.size() == Type.size()) {
|
||||
std::string Error = std::string(Desc);
|
||||
Error += " name missing after";
|
||||
D.Diag(diag::err_drv_invalid_riscv_ext_arch_name)
|
||||
<< MArch << Error << Type;
|
||||
return;
|
||||
}
|
||||
|
||||
std::string Major, Minor;
|
||||
if (!getExtensionVersion(D, Args, MArch, Name, Vers, Major, Minor))
|
||||
return;
|
||||
|
||||
// Check if duplicated extension.
|
||||
if (llvm::is_contained(AllExts, Name)) {
|
||||
std::string Error = "duplicated ";
|
||||
Error += Desc;
|
||||
D.Diag(diag::err_drv_invalid_riscv_ext_arch_name)
|
||||
<< MArch << Error << Name;
|
||||
return;
|
||||
}
|
||||
|
||||
// Extension format is correct, keep parsing the extensions.
|
||||
// TODO: Save Type, Name, Major, Minor to avoid parsing them later.
|
||||
AllExts.push_back(Name);
|
||||
}
|
||||
|
||||
// Set target features.
|
||||
// TODO: Hardware features to be handled in Support/TargetParser.cpp.
|
||||
// TODO: Use version number when setting target features.
|
||||
for (auto Ext : AllExts) {
|
||||
if (!isSupportedExtension(Ext)) {
|
||||
StringRef Desc = getExtensionTypeDesc(getExtensionType(Ext));
|
||||
std::string Error = "unsupported ";
|
||||
Error += Desc;
|
||||
D.Diag(diag::err_drv_invalid_riscv_ext_arch_name)
|
||||
<< MArch << Error << Ext;
|
||||
return;
|
||||
}
|
||||
if (Ext == "zvlsseg") {
|
||||
Features.push_back("+experimental-v");
|
||||
Features.push_back("+experimental-zvlsseg");
|
||||
} else if (Ext == "zvamo") {
|
||||
Features.push_back("+experimental-v");
|
||||
Features.push_back("+experimental-zvlsseg");
|
||||
Features.push_back("+experimental-zvamo");
|
||||
} else if (isExperimentalExtension(Ext))
|
||||
Features.push_back(Args.MakeArgString("+experimental-" + Ext));
|
||||
else
|
||||
Features.push_back(Args.MakeArgString("+" + Ext));
|
||||
}
|
||||
}
|
||||
|
||||
// Returns false if an error is diagnosed.
|
||||
static bool getArchFeatures(const Driver &D, StringRef MArch,
|
||||
static bool getArchFeatures(const Driver &D, StringRef Arch,
|
||||
std::vector<StringRef> &Features,
|
||||
const ArgList &Args) {
|
||||
// RISC-V ISA strings must be lowercase.
|
||||
if (llvm::any_of(MArch, [](char c) { return isupper(c); })) {
|
||||
D.Diag(diag::err_drv_invalid_riscv_arch_name)
|
||||
<< MArch << "string must be lowercase";
|
||||
bool EnableExperimentalExtensions =
|
||||
Args.hasArg(options::OPT_menable_experimental_extensions);
|
||||
auto ISAInfo =
|
||||
llvm::RISCVISAInfo::parseArchString(Arch, EnableExperimentalExtensions);
|
||||
if (!ISAInfo) {
|
||||
handleAllErrors(ISAInfo.takeError(), [&](llvm::StringError &ErrMsg) {
|
||||
D.Diag(diag::err_drv_invalid_riscv_arch_name)
|
||||
<< Arch << ErrMsg.getMessage();
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// ISA string must begin with rv32 or rv64.
|
||||
if (!(MArch.startswith("rv32") || MArch.startswith("rv64")) ||
|
||||
(MArch.size() < 5)) {
|
||||
D.Diag(diag::err_drv_invalid_riscv_arch_name)
|
||||
<< MArch << "string must begin with rv32{i,e,g} or rv64{i,g}";
|
||||
return false;
|
||||
}
|
||||
|
||||
bool HasRV64 = MArch.startswith("rv64");
|
||||
|
||||
// The canonical order specified in ISA manual.
|
||||
// Ref: Table 22.1 in RISC-V User-Level ISA V2.2
|
||||
StringRef StdExts = "mafdqlcbjtpvn";
|
||||
bool HasF = false, HasD = false;
|
||||
char Baseline = MArch[4];
|
||||
|
||||
// First letter should be 'e', 'i' or 'g'.
|
||||
switch (Baseline) {
|
||||
default:
|
||||
D.Diag(diag::err_drv_invalid_riscv_arch_name)
|
||||
<< MArch << "first letter should be 'e', 'i' or 'g'";
|
||||
return false;
|
||||
case 'e': {
|
||||
StringRef Error;
|
||||
// Currently LLVM does not support 'e'.
|
||||
// Extension 'e' is not allowed in rv64.
|
||||
if (HasRV64)
|
||||
Error = "standard user-level extension 'e' requires 'rv32'";
|
||||
else
|
||||
Error = "unsupported standard user-level extension 'e'";
|
||||
D.Diag(diag::err_drv_invalid_riscv_arch_name) << MArch << Error;
|
||||
return false;
|
||||
}
|
||||
case 'i':
|
||||
break;
|
||||
case 'g':
|
||||
// g = imafd
|
||||
StdExts = StdExts.drop_front(4);
|
||||
Features.push_back("+m");
|
||||
Features.push_back("+a");
|
||||
Features.push_back("+f");
|
||||
Features.push_back("+d");
|
||||
HasF = true;
|
||||
HasD = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// Skip rvxxx
|
||||
StringRef Exts = MArch.substr(5);
|
||||
|
||||
// Remove multi-letter standard extensions, non-standard extensions and
|
||||
// supervisor-level extensions. They have 'z', 'x', 's', 'sx' prefixes.
|
||||
// Parse them at the end.
|
||||
// Find the very first occurrence of 's', 'x' or 'z'.
|
||||
StringRef OtherExts;
|
||||
size_t Pos = Exts.find_first_of("zsx");
|
||||
if (Pos != StringRef::npos) {
|
||||
OtherExts = Exts.substr(Pos);
|
||||
Exts = Exts.substr(0, Pos);
|
||||
}
|
||||
|
||||
std::string Major, Minor;
|
||||
if (!getExtensionVersion(D, Args, MArch, std::string(1, Baseline), Exts,
|
||||
Major, Minor))
|
||||
return false;
|
||||
|
||||
// Consume the base ISA version number and any '_' between rvxxx and the
|
||||
// first extension
|
||||
Exts = Exts.drop_front(Major.size());
|
||||
if (!Minor.empty())
|
||||
Exts = Exts.drop_front(Minor.size() + 1 /*'p'*/);
|
||||
Exts.consume_front("_");
|
||||
|
||||
// TODO: Use version number when setting target features
|
||||
|
||||
auto StdExtsItr = StdExts.begin();
|
||||
auto StdExtsEnd = StdExts.end();
|
||||
|
||||
for (auto I = Exts.begin(), E = Exts.end(); I != E; ) {
|
||||
char c = *I;
|
||||
|
||||
// Check ISA extensions are specified in the canonical order.
|
||||
while (StdExtsItr != StdExtsEnd && *StdExtsItr != c)
|
||||
++StdExtsItr;
|
||||
|
||||
if (StdExtsItr == StdExtsEnd) {
|
||||
// Either c contains a valid extension but it was not given in
|
||||
// canonical order or it is an invalid extension.
|
||||
StringRef Error;
|
||||
if (StdExts.contains(c))
|
||||
Error = "standard user-level extension not given in canonical order";
|
||||
else
|
||||
Error = "invalid standard user-level extension";
|
||||
D.Diag(diag::err_drv_invalid_riscv_ext_arch_name)
|
||||
<< MArch << Error << std::string(1, c);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Move to next char to prevent repeated letter.
|
||||
++StdExtsItr;
|
||||
|
||||
std::string Next, Major, Minor;
|
||||
if (std::next(I) != E)
|
||||
Next = std::string(std::next(I), E);
|
||||
if (!getExtensionVersion(D, Args, MArch, std::string(1, c), Next, Major,
|
||||
Minor))
|
||||
return false;
|
||||
|
||||
// The order is OK, then push it into features.
|
||||
// TODO: Use version number when setting target features
|
||||
switch (c) {
|
||||
default:
|
||||
// Currently LLVM supports only "mafdc".
|
||||
D.Diag(diag::err_drv_invalid_riscv_ext_arch_name)
|
||||
<< MArch << "unsupported standard user-level extension"
|
||||
<< std::string(1, c);
|
||||
return false;
|
||||
case 'm':
|
||||
Features.push_back("+m");
|
||||
break;
|
||||
case 'a':
|
||||
Features.push_back("+a");
|
||||
break;
|
||||
case 'f':
|
||||
Features.push_back("+f");
|
||||
HasF = true;
|
||||
break;
|
||||
case 'd':
|
||||
Features.push_back("+d");
|
||||
HasD = true;
|
||||
break;
|
||||
case 'c':
|
||||
Features.push_back("+c");
|
||||
break;
|
||||
case 'v':
|
||||
Features.push_back("+experimental-v");
|
||||
Features.push_back("+experimental-zvlsseg");
|
||||
break;
|
||||
}
|
||||
|
||||
// Consume full extension name and version, including any optional '_'
|
||||
// between this extension and the next
|
||||
++I;
|
||||
I += Major.size();
|
||||
if (Minor.size())
|
||||
I += Minor.size() + 1 /*'p'*/;
|
||||
if (*I == '_')
|
||||
++I;
|
||||
}
|
||||
|
||||
// Dependency check.
|
||||
// It's illegal to specify the 'd' (double-precision floating point)
|
||||
// extension without also specifying the 'f' (single precision
|
||||
// floating-point) extension.
|
||||
if (HasD && !HasF) {
|
||||
D.Diag(diag::err_drv_invalid_riscv_arch_name)
|
||||
<< MArch << "d requires f extension to also be specified";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Additional dependency checks.
|
||||
// TODO: The 'q' extension requires rv64.
|
||||
// TODO: It is illegal to specify 'e' extensions with 'f' and 'd'.
|
||||
|
||||
// Handle all other types of extensions.
|
||||
getExtensionFeatures(D, Args, Features, MArch, OtherExts);
|
||||
|
||||
(*ISAInfo)->toFeatures(Args, Features);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -598,24 +189,30 @@ StringRef riscv::getRISCVABI(const ArgList &Args, const llvm::Triple &Triple) {
|
||||
// rv32* -> ilp32
|
||||
// rv64g | rv64*d -> lp64d
|
||||
// rv64* -> lp64
|
||||
StringRef MArch = getRISCVArch(Args, Triple);
|
||||
StringRef Arch = getRISCVArch(Args, Triple);
|
||||
|
||||
if (MArch.startswith_insensitive("rv32")) {
|
||||
// FIXME: parse `March` to find `D` extension properly
|
||||
if (MArch.substr(4).contains_insensitive("d") ||
|
||||
MArch.startswith_insensitive("rv32g"))
|
||||
return "ilp32d";
|
||||
else if (MArch.startswith_insensitive("rv32e"))
|
||||
return "ilp32e";
|
||||
else
|
||||
auto ParseResult = llvm::RISCVISAInfo::parseArchString(
|
||||
Arch, /* EnableExperimentalExtension */ true);
|
||||
if (!ParseResult) {
|
||||
// Ignore parsing error, just go 3rd step.
|
||||
consumeError(ParseResult.takeError());
|
||||
} else {
|
||||
auto &ISAInfo = *ParseResult;
|
||||
bool HasD = ISAInfo->hasExtension("d");
|
||||
unsigned XLen = ISAInfo->getXLen();
|
||||
if (XLen == 32) {
|
||||
bool HasE = ISAInfo->hasExtension("e");
|
||||
if (HasD)
|
||||
return "ilp32d";
|
||||
if (HasE)
|
||||
return "ilp32e";
|
||||
return "ilp32";
|
||||
} else if (MArch.startswith_insensitive("rv64")) {
|
||||
// FIXME: parse `March` to find `D` extension properly
|
||||
if (MArch.substr(4).contains_insensitive("d") ||
|
||||
MArch.startswith_insensitive("rv64g"))
|
||||
return "lp64d";
|
||||
else
|
||||
} else if (XLen == 64) {
|
||||
if (HasD)
|
||||
return "lp64d";
|
||||
return "lp64";
|
||||
}
|
||||
llvm_unreachable();
|
||||
}
|
||||
|
||||
// 3. Choose a default based on the triple
|
||||
|
||||
@@ -65,9 +65,9 @@
|
||||
|
||||
// CHECK-LP64F: "-target-abi" "lp64f"
|
||||
|
||||
// RUN: %clang -target riscv64-unknown-elf %s -### -o %t.o -march=rv64d -mabi=lp64d 2>&1 \
|
||||
// RUN: %clang -target riscv64-unknown-elf %s -### -o %t.o -march=rv64ifd -mabi=lp64d 2>&1 \
|
||||
// RUN: | FileCheck -check-prefix=CHECK-LP64D %s
|
||||
// RUN: %clang -target riscv64-unknown-elf %s -### -o %t.o -march=rv64d 2>&1 \
|
||||
// RUN: %clang -target riscv64-unknown-elf %s -### -o %t.o -march=rv64ifd 2>&1 \
|
||||
// RUN: | FileCheck -check-prefix=CHECK-LP64D %s
|
||||
// RUN: %clang -target riscv64-unknown-elf %s -### -o %t.o -march=rv64g 2>&1 \
|
||||
// RUN: | FileCheck -check-prefix=CHECK-LP64D %s
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
// RUN: %clang -target riscv32-unknown-elf -march=rv32i -### %s \
|
||||
// RUN: -fsyntax-only 2>&1 | FileCheck %s
|
||||
// RUN: %clang -target riscv32-unknown-elf -march=rv32i2p0 -### %s \
|
||||
// RUN: -fsyntax-only 2>&1 | FileCheck %s
|
||||
// RUN: %clang -target riscv32-unknown-elf -march=rv32im -### %s \
|
||||
// RUN: -fsyntax-only 2>&1 | FileCheck %s
|
||||
// RUN: %clang -target riscv32-unknown-elf -march=rv32ima -### %s \
|
||||
@@ -68,6 +70,8 @@
|
||||
|
||||
// RUN: %clang -target riscv64-unknown-elf -march=rv64i -### %s \
|
||||
// RUN: -fsyntax-only 2>&1 | FileCheck %s
|
||||
// RUN: %clang -target riscv64-unknown-elf -march=rv64i2p0 -### %s \
|
||||
// RUN: -fsyntax-only 2>&1 | FileCheck %s
|
||||
// RUN: %clang -target riscv64-unknown-elf -march=rv64im -### %s \
|
||||
// RUN: -fsyntax-only 2>&1 | FileCheck %s
|
||||
// RUN: %clang -target riscv64-unknown-elf -march=rv64ima -### %s \
|
||||
@@ -195,11 +199,6 @@
|
||||
|
||||
// Testing specific messages and unsupported extensions.
|
||||
|
||||
// RUN: %clang -target riscv32-unknown-elf -march=rv32e -### %s \
|
||||
// RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32E %s
|
||||
// RV32E: error: invalid arch name 'rv32e',
|
||||
// RV32E: standard user-level extension 'e'
|
||||
|
||||
// RUN: %clang -target riscv64-unknown-elf -march=rv64e -### %s \
|
||||
// RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV64E %s
|
||||
// RV64E: error: invalid arch name 'rv64e',
|
||||
@@ -308,11 +307,6 @@
|
||||
// RV32-IMINOR-MISS: error: invalid arch name 'rv32i2p',
|
||||
// RV32-IMINOR-MISS: minor version number missing after 'p' for extension 'i'
|
||||
|
||||
// RUN: %clang -target riscv32-unknown-elf -march=rv32i2p0 -### %s \
|
||||
// RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32-IMINOR0 %s
|
||||
// RV32-IMINOR0: error: invalid arch name 'rv32i2p0',
|
||||
// RV32-IMINOR0: unsupported version number 2.0 for extension 'i'
|
||||
|
||||
// RUN: %clang -target riscv32-unknown-elf -march=rv32i2p1 -### %s \
|
||||
// RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32-IMINOR1 %s
|
||||
// RV32-IMINOR1: error: invalid arch name 'rv32i2p1', unsupported
|
||||
@@ -417,7 +411,7 @@
|
||||
// RUN: %clang -target riscv32-unknown-elf -march=rv32iv0p1 -menable-experimental-extensions -### %s -c 2>&1 | \
|
||||
// RUN: FileCheck -check-prefix=RV32-EXPERIMENTAL-V-BADVERS %s
|
||||
// RV32-EXPERIMENTAL-V-BADVERS: error: invalid arch name 'rv32iv0p1'
|
||||
// RV32-EXPERIMENTAL-V-BADVERS: unsupported version number 0.1 for experimental extension
|
||||
// RV32-EXPERIMENTAL-V-BADVERS: unsupported version number 0.1 for experimental extension 'v'
|
||||
|
||||
// RUN: %clang -target riscv32-unknown-elf -march=rv32iv0p10 -menable-experimental-extensions -### %s -c 2>&1 | \
|
||||
// RUN: FileCheck -check-prefix=RV32-EXPERIMENTAL-V-GOODVERS %s
|
||||
@@ -445,7 +439,7 @@
|
||||
// RUN: %clang -target riscv32-unknown-elf -march=rv32izvamo0p1 -menable-experimental-extensions -### %s -c 2>&1 | \
|
||||
// RUN: FileCheck -check-prefix=RV32-EXPERIMENTAL-ZVAMO-BADVERS %s
|
||||
// RV32-EXPERIMENTAL-ZVAMO-BADVERS: error: invalid arch name 'rv32izvamo0p1'
|
||||
// RV32-EXPERIMENTAL-ZVAMO-BADVERS: unsupported version number 0.1 for experimental extension
|
||||
// RV32-EXPERIMENTAL-ZVAMO-BADVERS: unsupported version number 0.1 for experimental extension 'zvamo'
|
||||
|
||||
// RUN: %clang -target riscv32-unknown-elf -march=rv32izvamo0p10 -menable-experimental-extensions -### %s -c 2>&1 | \
|
||||
// RUN: FileCheck -check-prefix=RV32-EXPERIMENTAL-ZVAMO-GOODVERS %s
|
||||
@@ -464,7 +458,7 @@
|
||||
// RUN: %clang -target riscv32-unknown-elf -march=rv32izvlsseg0p1 -menable-experimental-extensions -### %s -c 2>&1 | \
|
||||
// RUN: FileCheck -check-prefix=RV32-EXPERIMENTAL-ZVLSSEG-BADVERS %s
|
||||
// RV32-EXPERIMENTAL-ZVLSSEG-BADVERS: error: invalid arch name 'rv32izvlsseg0p1'
|
||||
// RV32-EXPERIMENTAL-ZVLSSEG-BADVERS: unsupported version number 0.1 for experimental extension
|
||||
// RV32-EXPERIMENTAL-ZVLSSEG-BADVERS: unsupported version number 0.1 for experimental extension 'zvlsseg'
|
||||
|
||||
// RUN: %clang -target riscv32-unknown-elf -march=rv32izvlsseg0p10 -menable-experimental-extensions -### %s -c 2>&1 | \
|
||||
// RUN: FileCheck -check-prefix=RV32-EXPERIMENTAL-ZVLSSEG-GOODVERS %s
|
||||
|
||||
@@ -31,3 +31,7 @@
|
||||
// DEFAULT-LINUX-SAME: "-target-feature" "+f"
|
||||
// DEFAULT-LINUX-SAME: "-target-feature" "+d"
|
||||
// DEFAULT-LINUX-SAME: "-target-feature" "+c"
|
||||
|
||||
// RUN: not %clang -cc1 -triple riscv64-unknown-elf -target-feature +e 2>&1 | FileCheck %s -check-prefix=RV64-WITH-E
|
||||
|
||||
// RV64-WITH-E: error: invalid feature combination: standard user-level extension 'e' requires 'rv32'
|
||||
|
||||
90
llvm/include/llvm/Support/RISCVISAInfo.h
Normal file
90
llvm/include/llvm/Support/RISCVISAInfo.h
Normal file
@@ -0,0 +1,90 @@
|
||||
//===-- RISCVISAInfo.h - RISCV ISA Information ------*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_SUPPORT_RISCVISAINFO_H
|
||||
#define LLVM_SUPPORT_RISCVISAINFO_H
|
||||
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Option/ArgList.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
struct RISCVExtensionInfo {
|
||||
std::string ExtName;
|
||||
unsigned MajorVersion;
|
||||
unsigned MinorVersion;
|
||||
};
|
||||
|
||||
class RISCVISAInfo {
|
||||
public:
|
||||
RISCVISAInfo(const RISCVISAInfo &) = delete;
|
||||
RISCVISAInfo &operator=(const RISCVISAInfo &) = delete;
|
||||
|
||||
static bool compareExtension(const std::string &LHS, const std::string &RHS);
|
||||
|
||||
/// Helper class for OrderedExtensionMap.
|
||||
struct ExtensionComparator {
|
||||
bool operator()(const std::string &LHS, const std::string &RHS) const {
|
||||
return compareExtension(LHS, RHS);
|
||||
}
|
||||
};
|
||||
|
||||
/// OrderedExtensionMap is std::map, it's specialized to keep entries
|
||||
/// in canonical order of extension.
|
||||
typedef std::map<std::string, RISCVExtensionInfo, ExtensionComparator>
|
||||
OrderedExtensionMap;
|
||||
|
||||
/// Parse RISCV ISA info from arch string.
|
||||
static llvm::Expected<std::unique_ptr<RISCVISAInfo>>
|
||||
parseArchString(StringRef Arch, bool EnableExperimentalExtension,
|
||||
bool ExperimentalExtensionVersionCheck = true);
|
||||
|
||||
/// Parse RISCV ISA info from feature vector.
|
||||
static llvm::Expected<std::unique_ptr<RISCVISAInfo>>
|
||||
parseFeatures(unsigned XLen, const std::vector<std::string> &Features);
|
||||
|
||||
/// Convert RISCV ISA info to a feature vector.
|
||||
void toFeatures(const llvm::opt::ArgList &Args,
|
||||
std::vector<StringRef> &Features) const;
|
||||
|
||||
const OrderedExtensionMap &getExtensions() const { return Exts; };
|
||||
|
||||
unsigned getXLen() const { return XLen; };
|
||||
unsigned getFLen() const { return FLen; };
|
||||
|
||||
bool hasExtension(StringRef Ext) const;
|
||||
std::string toString() const;
|
||||
|
||||
static bool isSupportedExtensionFeature(StringRef Ext);
|
||||
static bool isSupportedExtension(StringRef Ext);
|
||||
static bool isSupportedExtension(StringRef Ext, unsigned MajorVersion,
|
||||
unsigned MinorVersion);
|
||||
|
||||
private:
|
||||
RISCVISAInfo(unsigned XLen) : XLen(XLen), FLen(0) {}
|
||||
|
||||
unsigned XLen;
|
||||
unsigned FLen;
|
||||
|
||||
OrderedExtensionMap Exts;
|
||||
|
||||
void addExtension(StringRef ExtName, unsigned MajorVersion,
|
||||
unsigned MinorVersion);
|
||||
|
||||
void updateFLen();
|
||||
};
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
#endif
|
||||
@@ -184,6 +184,7 @@ add_llvm_component_library(LLVMSupport
|
||||
Regex.cpp
|
||||
RISCVAttributes.cpp
|
||||
RISCVAttributeParser.cpp
|
||||
RISCVISAInfo.cpp
|
||||
ScaledNumber.cpp
|
||||
ScopedPrinter.cpp
|
||||
SHA1.cpp
|
||||
|
||||
716
llvm/lib/Support/RISCVISAInfo.cpp
Normal file
716
llvm/lib/Support/RISCVISAInfo.cpp
Normal file
@@ -0,0 +1,716 @@
|
||||
//===-- RISCVISAInfo.cpp - RISCV Arch String Parser --------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Support/RISCVISAInfo.h"
|
||||
#include "llvm/ADT/None.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Support/Errc.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
namespace {
|
||||
/// Represents the major and version number components of a RISC-V extension
|
||||
struct RISCVExtensionVersion {
|
||||
unsigned Major;
|
||||
unsigned Minor;
|
||||
};
|
||||
|
||||
struct RISCVSupportedExtension {
|
||||
const char *Name;
|
||||
/// Supported version.
|
||||
RISCVExtensionVersion Version;
|
||||
};
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
static constexpr StringLiteral AllStdExts = "mafdqlcbjtpvn";
|
||||
|
||||
static const RISCVSupportedExtension SupportedExtensions[] = {
|
||||
{"i", RISCVExtensionVersion{2, 0}},
|
||||
{"e", RISCVExtensionVersion{1, 9}},
|
||||
{"m", RISCVExtensionVersion{2, 0}},
|
||||
{"a", RISCVExtensionVersion{2, 0}},
|
||||
{"f", RISCVExtensionVersion{2, 0}},
|
||||
{"d", RISCVExtensionVersion{2, 0}},
|
||||
{"c", RISCVExtensionVersion{2, 0}},
|
||||
};
|
||||
|
||||
static const RISCVSupportedExtension SupportedExperimentalExtensions[] = {
|
||||
{"v", RISCVExtensionVersion{0, 10}},
|
||||
{"zba", RISCVExtensionVersion{1, 0}},
|
||||
{"zbb", RISCVExtensionVersion{1, 0}},
|
||||
{"zbc", RISCVExtensionVersion{1, 0}},
|
||||
{"zbe", RISCVExtensionVersion{0, 93}},
|
||||
{"zbf", RISCVExtensionVersion{0, 93}},
|
||||
{"zbm", RISCVExtensionVersion{0, 93}},
|
||||
{"zbp", RISCVExtensionVersion{0, 93}},
|
||||
{"zbr", RISCVExtensionVersion{0, 93}},
|
||||
{"zbs", RISCVExtensionVersion{1, 0}},
|
||||
{"zbt", RISCVExtensionVersion{0, 93}},
|
||||
|
||||
{"zvamo", RISCVExtensionVersion{0, 10}},
|
||||
{"zvlsseg", RISCVExtensionVersion{0, 10}},
|
||||
|
||||
{"zfh", RISCVExtensionVersion{0, 1}},
|
||||
};
|
||||
|
||||
static bool stripExperimentalPrefix(StringRef &Ext) {
|
||||
return Ext.consume_front("experimental-");
|
||||
}
|
||||
|
||||
struct FindByName {
|
||||
FindByName(StringRef Ext) : Ext(Ext){};
|
||||
StringRef Ext;
|
||||
bool operator()(const RISCVSupportedExtension &ExtInfo) {
|
||||
return ExtInfo.Name == Ext;
|
||||
}
|
||||
};
|
||||
|
||||
static Optional<RISCVExtensionVersion> findDefaultVersion(StringRef ExtName) {
|
||||
// Find default version of an extension.
|
||||
// TODO: We might set default version based on profile or ISA spec.
|
||||
for (auto &ExtInfo : {makeArrayRef(SupportedExtensions),
|
||||
makeArrayRef(SupportedExperimentalExtensions)}) {
|
||||
auto ExtensionInfoIterator = llvm::find_if(ExtInfo, FindByName(ExtName));
|
||||
|
||||
if (ExtensionInfoIterator == ExtInfo.end()) {
|
||||
continue;
|
||||
}
|
||||
return ExtensionInfoIterator->Version;
|
||||
}
|
||||
return None;
|
||||
}
|
||||
|
||||
void RISCVISAInfo::addExtension(StringRef ExtName, unsigned MajorVersion,
|
||||
unsigned MinorVersion) {
|
||||
RISCVExtensionInfo Ext;
|
||||
Ext.ExtName = ExtName.str();
|
||||
Ext.MajorVersion = MajorVersion;
|
||||
Ext.MinorVersion = MinorVersion;
|
||||
Exts[ExtName.str()] = Ext;
|
||||
}
|
||||
|
||||
static StringRef getExtensionTypeDesc(StringRef Ext) {
|
||||
if (Ext.startswith("sx"))
|
||||
return "non-standard supervisor-level extension";
|
||||
if (Ext.startswith("s"))
|
||||
return "standard supervisor-level extension";
|
||||
if (Ext.startswith("x"))
|
||||
return "non-standard user-level extension";
|
||||
if (Ext.startswith("z"))
|
||||
return "standard user-level extension";
|
||||
return StringRef();
|
||||
}
|
||||
|
||||
static StringRef getExtensionType(StringRef Ext) {
|
||||
if (Ext.startswith("sx"))
|
||||
return "sx";
|
||||
if (Ext.startswith("s"))
|
||||
return "s";
|
||||
if (Ext.startswith("x"))
|
||||
return "x";
|
||||
if (Ext.startswith("z"))
|
||||
return "z";
|
||||
return StringRef();
|
||||
}
|
||||
|
||||
static Optional<RISCVExtensionVersion> isExperimentalExtension(StringRef Ext) {
|
||||
auto ExtIterator =
|
||||
llvm::find_if(SupportedExperimentalExtensions, FindByName(Ext));
|
||||
if (ExtIterator == std::end(SupportedExperimentalExtensions))
|
||||
return None;
|
||||
|
||||
return ExtIterator->Version;
|
||||
}
|
||||
|
||||
bool RISCVISAInfo::isSupportedExtensionFeature(StringRef Ext) {
|
||||
bool IsExperimental = stripExperimentalPrefix(Ext);
|
||||
|
||||
if (IsExperimental)
|
||||
return llvm::any_of(SupportedExperimentalExtensions, FindByName(Ext));
|
||||
else
|
||||
return llvm::any_of(SupportedExtensions, FindByName(Ext));
|
||||
}
|
||||
|
||||
bool RISCVISAInfo::isSupportedExtension(StringRef Ext) {
|
||||
return llvm::any_of(SupportedExtensions, FindByName(Ext)) ||
|
||||
llvm::any_of(SupportedExperimentalExtensions, FindByName(Ext));
|
||||
}
|
||||
|
||||
bool RISCVISAInfo::isSupportedExtension(StringRef Ext, unsigned MajorVersion,
|
||||
unsigned MinorVersion) {
|
||||
auto FindByNameAndVersion = [=](const RISCVSupportedExtension &ExtInfo) {
|
||||
return ExtInfo.Name == Ext && (MajorVersion == ExtInfo.Version.Major) &&
|
||||
(MinorVersion == ExtInfo.Version.Minor);
|
||||
};
|
||||
return llvm::any_of(SupportedExtensions, FindByNameAndVersion) ||
|
||||
llvm::any_of(SupportedExperimentalExtensions, FindByNameAndVersion);
|
||||
}
|
||||
|
||||
bool RISCVISAInfo::hasExtension(StringRef Ext) const {
|
||||
stripExperimentalPrefix(Ext);
|
||||
|
||||
if (!isSupportedExtension(Ext))
|
||||
return false;
|
||||
|
||||
return Exts.count(Ext.str()) != 0;
|
||||
}
|
||||
|
||||
// Get the rank for single-letter extension, lower value meaning higher
|
||||
// priority.
|
||||
static int singleLetterExtensionRank(char Ext) {
|
||||
switch (Ext) {
|
||||
case 'i':
|
||||
return -2;
|
||||
case 'e':
|
||||
return -1;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
size_t Pos = AllStdExts.find(Ext);
|
||||
int Rank;
|
||||
if (Pos == StringRef::npos)
|
||||
// If we got an unknown extension letter, then give it an alphabetical
|
||||
// order, but after all known standard extensions.
|
||||
Rank = AllStdExts.size() + (Ext - 'a');
|
||||
else
|
||||
Rank = Pos;
|
||||
|
||||
return Rank;
|
||||
}
|
||||
|
||||
// Get the rank for multi-letter extension, lower value meaning higher
|
||||
// priority/order in canonical order.
|
||||
static int multiLetterExtensionRank(const std::string &ExtName) {
|
||||
assert(ExtName.length() >= 2);
|
||||
int HighOrder;
|
||||
int LowOrder = 0;
|
||||
// The order between multi-char extensions: s -> h -> z -> x.
|
||||
char ExtClass = ExtName[0];
|
||||
switch (ExtClass) {
|
||||
case 's':
|
||||
HighOrder = 0;
|
||||
break;
|
||||
case 'h':
|
||||
HighOrder = 1;
|
||||
break;
|
||||
case 'z':
|
||||
HighOrder = 2;
|
||||
// `z` extension must be sorted by canonical order of second letter.
|
||||
// e.g. zmx has higher rank than zax.
|
||||
LowOrder = singleLetterExtensionRank(ExtName[1]);
|
||||
break;
|
||||
case 'x':
|
||||
HighOrder = 3;
|
||||
break;
|
||||
default:
|
||||
llvm_unreachable("Unknown prefix for multi-char extension");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return (HighOrder << 8) + LowOrder;
|
||||
}
|
||||
|
||||
// Compare function for extension.
|
||||
// Only compare the extension name, ignore version comparison.
|
||||
bool RISCVISAInfo::compareExtension(const std::string &LHS,
|
||||
const std::string &RHS) {
|
||||
size_t LHSLen = LHS.length();
|
||||
size_t RHSLen = RHS.length();
|
||||
if (LHSLen == 1 && RHSLen != 1)
|
||||
return true;
|
||||
|
||||
if (LHSLen != 1 && RHSLen == 1)
|
||||
return false;
|
||||
|
||||
if (LHSLen == 1 && RHSLen == 1)
|
||||
return singleLetterExtensionRank(LHS[0]) <
|
||||
singleLetterExtensionRank(RHS[0]);
|
||||
|
||||
// Both are multi-char ext here.
|
||||
int LHSRank = multiLetterExtensionRank(LHS);
|
||||
int RHSRank = multiLetterExtensionRank(RHS);
|
||||
if (LHSRank != RHSRank)
|
||||
return LHSRank < RHSRank;
|
||||
|
||||
// If the rank is same, it must be sorted by lexicographic order.
|
||||
return LHS < RHS;
|
||||
}
|
||||
|
||||
void RISCVISAInfo::toFeatures(const llvm::opt::ArgList &Args,
|
||||
std::vector<StringRef> &Features) const {
|
||||
for (auto &Ext : Exts) {
|
||||
StringRef ExtName = Ext.first;
|
||||
|
||||
if (ExtName == "i")
|
||||
continue;
|
||||
|
||||
if (ExtName == "zvlsseg") {
|
||||
Features.push_back("+experimental-v");
|
||||
Features.push_back("+experimental-zvlsseg");
|
||||
} else if (ExtName == "zvamo") {
|
||||
Features.push_back("+experimental-v");
|
||||
Features.push_back("+experimental-zvlsseg");
|
||||
Features.push_back("+experimental-zvamo");
|
||||
} else if (isExperimentalExtension(ExtName)) {
|
||||
Features.push_back(Args.MakeArgString("+experimental-" + ExtName));
|
||||
} else {
|
||||
Features.push_back(Args.MakeArgString("+" + ExtName));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Extensions may have a version number, and may be separated by
|
||||
// an underscore '_' e.g.: rv32i2_m2.
|
||||
// Version number is divided into major and minor version numbers,
|
||||
// separated by a 'p'. If the minor version is 0 then 'p0' can be
|
||||
// omitted from the version string. E.g., rv32i2p0, rv32i2, rv32i2p1.
|
||||
static Error getExtensionVersion(StringRef Ext, StringRef In, unsigned &Major,
|
||||
unsigned &Minor, unsigned &ConsumeLength,
|
||||
bool EnableExperimentalExtension,
|
||||
bool ExperimentalExtensionVersionCheck) {
|
||||
StringRef MajorStr, MinorStr;
|
||||
Major = 0;
|
||||
Minor = 0;
|
||||
ConsumeLength = 0;
|
||||
MajorStr = In.take_while(isDigit);
|
||||
In = In.substr(MajorStr.size());
|
||||
|
||||
if (!MajorStr.empty() && In.consume_front("p")) {
|
||||
MinorStr = In.take_while(isDigit);
|
||||
In = In.substr(MajorStr.size() + 1);
|
||||
|
||||
// Expected 'p' to be followed by minor version number.
|
||||
if (MinorStr.empty()) {
|
||||
return createStringError(
|
||||
errc::invalid_argument,
|
||||
"minor version number missing after 'p' for extension '" + Ext + "'");
|
||||
}
|
||||
}
|
||||
|
||||
if (!MajorStr.empty() && MajorStr.getAsInteger(10, Major))
|
||||
return createStringError(
|
||||
errc::invalid_argument,
|
||||
"Failed to parse major version number for extension '" + Ext + "'");
|
||||
|
||||
if (!MinorStr.empty() && MinorStr.getAsInteger(10, Minor))
|
||||
return createStringError(
|
||||
errc::invalid_argument,
|
||||
"Failed to parse minor version number for extension '" + Ext + "'");
|
||||
|
||||
ConsumeLength = MajorStr.size();
|
||||
|
||||
if (!MinorStr.empty())
|
||||
ConsumeLength += MinorStr.size() + 1 /*'p'*/;
|
||||
|
||||
// Expected multi-character extension with version number to have no
|
||||
// subsequent characters (i.e. must either end string or be followed by
|
||||
// an underscore).
|
||||
if (Ext.size() > 1 && In.size()) {
|
||||
std::string Error =
|
||||
"multi-character extensions must be separated by underscores";
|
||||
return createStringError(errc::invalid_argument, Error);
|
||||
}
|
||||
|
||||
// If experimental extension, require use of current version number number
|
||||
if (auto ExperimentalExtension = isExperimentalExtension(Ext)) {
|
||||
if (!EnableExperimentalExtension) {
|
||||
std::string Error = "requires '-menable-experimental-extensions' for "
|
||||
"experimental extension '" +
|
||||
Ext.str() + "'";
|
||||
return createStringError(errc::invalid_argument, Error);
|
||||
}
|
||||
|
||||
if (ExperimentalExtensionVersionCheck &&
|
||||
(MajorStr.empty() && MinorStr.empty())) {
|
||||
std::string Error =
|
||||
"experimental extension requires explicit version number `" +
|
||||
Ext.str() + "`";
|
||||
return createStringError(errc::invalid_argument, Error);
|
||||
}
|
||||
|
||||
auto SupportedVers = *ExperimentalExtension;
|
||||
if (ExperimentalExtensionVersionCheck &&
|
||||
(Major != SupportedVers.Major || Minor != SupportedVers.Minor)) {
|
||||
std::string Error = "unsupported version number " + MajorStr.str();
|
||||
if (!MinorStr.empty())
|
||||
Error += "." + MinorStr.str();
|
||||
Error += " for experimental extension '" + Ext.str() +
|
||||
"'(this compiler supports " + utostr(SupportedVers.Major) + "." +
|
||||
utostr(SupportedVers.Minor) + ")";
|
||||
return createStringError(errc::invalid_argument, Error);
|
||||
}
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
// Exception rule for `g`, we don't have clear version scheme for that on
|
||||
// ISA spec.
|
||||
if (Ext == "g")
|
||||
return Error::success();
|
||||
|
||||
if (MajorStr.empty() && MinorStr.empty()) {
|
||||
if (auto DefaultVersion = findDefaultVersion(Ext)) {
|
||||
Major = DefaultVersion->Major;
|
||||
Minor = DefaultVersion->Minor;
|
||||
}
|
||||
// No matter found or not, return success, assume other place will
|
||||
// verify.
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
if (RISCVISAInfo::isSupportedExtension(Ext, Major, Minor))
|
||||
return Error::success();
|
||||
|
||||
std::string Error = "unsupported version number " + std::string(MajorStr);
|
||||
if (!MinorStr.empty())
|
||||
Error += "." + MinorStr.str();
|
||||
Error += " for extension '" + Ext.str() + "'";
|
||||
return createStringError(errc::invalid_argument, Error);
|
||||
}
|
||||
|
||||
llvm::Expected<std::unique_ptr<RISCVISAInfo>>
|
||||
RISCVISAInfo::parseFeatures(unsigned XLen,
|
||||
const std::vector<std::string> &Features) {
|
||||
assert(XLen == 32 || XLen == 64);
|
||||
std::unique_ptr<RISCVISAInfo> ISAInfo(new RISCVISAInfo(XLen));
|
||||
|
||||
bool HasE = false;
|
||||
for (auto &Feature : Features) {
|
||||
StringRef ExtName = Feature;
|
||||
bool Experimental = false;
|
||||
assert(ExtName.size() > 1 && (ExtName[0] == '+' || ExtName[0] == '-'));
|
||||
bool Add = ExtName[0] == '+';
|
||||
ExtName = ExtName.drop_front(1); // Drop '+' or '-'
|
||||
Experimental = stripExperimentalPrefix(ExtName);
|
||||
auto ExtensionInfos = Experimental
|
||||
? makeArrayRef(SupportedExperimentalExtensions)
|
||||
: makeArrayRef(SupportedExtensions);
|
||||
auto ExtensionInfoIterator =
|
||||
llvm::find_if(ExtensionInfos, FindByName(ExtName));
|
||||
|
||||
// Not all features is related to ISA extension, like `relax` or
|
||||
// `save-restore`, skip those feature.
|
||||
if (ExtensionInfoIterator == ExtensionInfos.end())
|
||||
continue;
|
||||
|
||||
if (Add) {
|
||||
if (ExtName == "e") {
|
||||
if (XLen != 32)
|
||||
return createStringError(
|
||||
errc::invalid_argument,
|
||||
"standard user-level extension 'e' requires 'rv32'");
|
||||
HasE = true;
|
||||
}
|
||||
|
||||
ISAInfo->addExtension(ExtName, ExtensionInfoIterator->Version.Major,
|
||||
ExtensionInfoIterator->Version.Minor);
|
||||
} else
|
||||
ISAInfo->Exts.erase(ExtName.str());
|
||||
}
|
||||
if (!HasE) {
|
||||
if (auto Version = findDefaultVersion("i"))
|
||||
ISAInfo->addExtension("i", Version->Major, Version->Minor);
|
||||
else
|
||||
llvm_unreachable("Default extension version for 'i' not found?");
|
||||
}
|
||||
|
||||
ISAInfo->updateFLen();
|
||||
|
||||
return std::move(ISAInfo);
|
||||
}
|
||||
|
||||
llvm::Expected<std::unique_ptr<RISCVISAInfo>>
|
||||
RISCVISAInfo::parseArchString(StringRef Arch, bool EnableExperimentalExtension,
|
||||
bool ExperimentalExtensionVersionCheck) {
|
||||
// RISC-V ISA strings must be lowercase.
|
||||
if (llvm::any_of(Arch, isupper)) {
|
||||
return createStringError(errc::invalid_argument,
|
||||
"string must be lowercase");
|
||||
}
|
||||
|
||||
bool HasRV64 = Arch.startswith("rv64");
|
||||
// ISA string must begin with rv32 or rv64.
|
||||
if (!(Arch.startswith("rv32") || HasRV64) || (Arch.size() < 5)) {
|
||||
return createStringError(errc::invalid_argument,
|
||||
"string must begin with rv32{i,e,g} or rv64{i,g}");
|
||||
}
|
||||
|
||||
unsigned XLen = HasRV64 ? 64 : 32;
|
||||
std::unique_ptr<RISCVISAInfo> ISAInfo(new RISCVISAInfo(XLen));
|
||||
|
||||
// The canonical order specified in ISA manual.
|
||||
// Ref: Table 22.1 in RISC-V User-Level ISA V2.2
|
||||
StringRef StdExts = AllStdExts;
|
||||
bool HasF = false, HasD = false;
|
||||
char Baseline = Arch[4];
|
||||
|
||||
// First letter should be 'e', 'i' or 'g'.
|
||||
switch (Baseline) {
|
||||
default:
|
||||
return createStringError(errc::invalid_argument,
|
||||
"first letter should be 'e', 'i' or 'g'");
|
||||
case 'e': {
|
||||
// Extension 'e' is not allowed in rv64.
|
||||
if (HasRV64)
|
||||
return createStringError(
|
||||
errc::invalid_argument,
|
||||
"standard user-level extension 'e' requires 'rv32'");
|
||||
break;
|
||||
}
|
||||
case 'i':
|
||||
break;
|
||||
case 'g':
|
||||
// g = imafd
|
||||
StdExts = StdExts.drop_front(4);
|
||||
HasF = true;
|
||||
HasD = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// Skip rvxxx
|
||||
StringRef Exts = Arch.substr(5);
|
||||
|
||||
// Remove multi-letter standard extensions, non-standard extensions and
|
||||
// supervisor-level extensions. They have 'z', 'x', 's', 'sx' prefixes.
|
||||
// Parse them at the end.
|
||||
// Find the very first occurrence of 's', 'x' or 'z'.
|
||||
StringRef OtherExts;
|
||||
size_t Pos = Exts.find_first_of("zsx");
|
||||
if (Pos != StringRef::npos) {
|
||||
OtherExts = Exts.substr(Pos);
|
||||
Exts = Exts.substr(0, Pos);
|
||||
}
|
||||
|
||||
unsigned Major, Minor, ConsumeLength;
|
||||
if (auto E = getExtensionVersion(std::string(1, Baseline), Exts, Major, Minor,
|
||||
ConsumeLength, EnableExperimentalExtension,
|
||||
ExperimentalExtensionVersionCheck))
|
||||
return std::move(E);
|
||||
|
||||
if (Baseline == 'g') {
|
||||
// No matter which version is given to `g`, we always set imafd to default
|
||||
// version since the we don't have clear version scheme for that on
|
||||
// ISA spec.
|
||||
for (auto Ext : {"i", "m", "a", "f", "d"})
|
||||
if (auto Version = findDefaultVersion(Ext))
|
||||
ISAInfo->addExtension(Ext, Version->Major, Version->Minor);
|
||||
else
|
||||
llvm_unreachable("Default extension version not found?");
|
||||
} else
|
||||
// Baseline is `i` or `e`
|
||||
ISAInfo->addExtension(std::string(1, Baseline), Major, Minor);
|
||||
|
||||
// Consume the base ISA version number and any '_' between rvxxx and the
|
||||
// first extension
|
||||
Exts = Exts.drop_front(ConsumeLength);
|
||||
Exts.consume_front("_");
|
||||
|
||||
// TODO: Use version number when setting target features
|
||||
|
||||
auto StdExtsItr = StdExts.begin();
|
||||
auto StdExtsEnd = StdExts.end();
|
||||
for (auto I = Exts.begin(), E = Exts.end(); I != E;) {
|
||||
char C = *I;
|
||||
|
||||
// Check ISA extensions are specified in the canonical order.
|
||||
while (StdExtsItr != StdExtsEnd && *StdExtsItr != C)
|
||||
++StdExtsItr;
|
||||
|
||||
if (StdExtsItr == StdExtsEnd) {
|
||||
// Either c contains a valid extension but it was not given in
|
||||
// canonical order or it is an invalid extension.
|
||||
if (StdExts.contains(C)) {
|
||||
return createStringError(
|
||||
errc::invalid_argument,
|
||||
"standard user-level extension not given in canonical order '%c'",
|
||||
C);
|
||||
}
|
||||
|
||||
return createStringError(errc::invalid_argument,
|
||||
"invalid standard user-level extension '%c'", C);
|
||||
}
|
||||
|
||||
// Move to next char to prevent repeated letter.
|
||||
++StdExtsItr;
|
||||
|
||||
std::string Next;
|
||||
unsigned Major, Minor, ConsumeLength;
|
||||
if (std::next(I) != E)
|
||||
Next = std::string(std::next(I), E);
|
||||
if (auto E = getExtensionVersion(std::string(1, C), Next, Major, Minor,
|
||||
ConsumeLength, EnableExperimentalExtension,
|
||||
ExperimentalExtensionVersionCheck))
|
||||
return std::move(E);
|
||||
|
||||
// The order is OK, then push it into features.
|
||||
// TODO: Use version number when setting target features
|
||||
switch (C) {
|
||||
default:
|
||||
// Currently LLVM supports only "mafdcbv".
|
||||
return createStringError(errc::invalid_argument,
|
||||
"unsupported standard user-level extension '%c'",
|
||||
C);
|
||||
case 'm':
|
||||
ISAInfo->addExtension("m", Major, Minor);
|
||||
break;
|
||||
case 'a':
|
||||
ISAInfo->addExtension("a", Major, Minor);
|
||||
break;
|
||||
case 'f':
|
||||
ISAInfo->addExtension("f", Major, Minor);
|
||||
HasF = true;
|
||||
break;
|
||||
case 'd':
|
||||
ISAInfo->addExtension("d", Major, Minor);
|
||||
HasD = true;
|
||||
break;
|
||||
case 'c':
|
||||
ISAInfo->addExtension("c", Major, Minor);
|
||||
break;
|
||||
case 'v':
|
||||
ISAInfo->addExtension("v", Major, Minor);
|
||||
ISAInfo->addExtension("zvlsseg", Major, Minor);
|
||||
break;
|
||||
}
|
||||
// Consume full extension name and version, including any optional '_'
|
||||
// between this extension and the next
|
||||
++I;
|
||||
I += ConsumeLength;
|
||||
if (*I == '_')
|
||||
++I;
|
||||
}
|
||||
// Dependency check.
|
||||
// It's illegal to specify the 'd' (double-precision floating point)
|
||||
// extension without also specifying the 'f' (single precision
|
||||
// floating-point) extension.
|
||||
// TODO: This has been removed in later specs, which specify that D implies F
|
||||
if (HasD && !HasF)
|
||||
return createStringError(errc::invalid_argument,
|
||||
"d requires f extension to also be specified");
|
||||
|
||||
// Additional dependency checks.
|
||||
// TODO: The 'q' extension requires rv64.
|
||||
// TODO: It is illegal to specify 'e' extensions with 'f' and 'd'.
|
||||
|
||||
if (OtherExts.empty())
|
||||
return std::move(ISAInfo);
|
||||
|
||||
// Handle other types of extensions other than the standard
|
||||
// general purpose and standard user-level extensions.
|
||||
// Parse the ISA string containing non-standard user-level
|
||||
// extensions, standard supervisor-level extensions and
|
||||
// non-standard supervisor-level extensions.
|
||||
// These extensions start with 'z', 'x', 's', 'sx' prefixes, follow a
|
||||
// canonical order, might have a version number (major, minor)
|
||||
// and are separated by a single underscore '_'.
|
||||
// Set the hardware features for the extensions that are supported.
|
||||
|
||||
// Multi-letter extensions are seperated by a single underscore
|
||||
// as described in RISC-V User-Level ISA V2.2.
|
||||
SmallVector<StringRef, 8> Split;
|
||||
OtherExts.split(Split, '_');
|
||||
|
||||
SmallVector<StringRef, 8> AllExts;
|
||||
std::array<StringRef, 4> Prefix{"z", "x", "s", "sx"};
|
||||
auto I = Prefix.begin();
|
||||
auto E = Prefix.end();
|
||||
|
||||
for (StringRef Ext : Split) {
|
||||
if (Ext.empty())
|
||||
return createStringError(errc::invalid_argument,
|
||||
"extension name missing after separator '_'");
|
||||
|
||||
StringRef Type = getExtensionType(Ext);
|
||||
StringRef Desc = getExtensionTypeDesc(Ext);
|
||||
auto Pos = Ext.find_if(isDigit);
|
||||
StringRef Name(Ext.substr(0, Pos));
|
||||
StringRef Vers(Ext.substr(Pos));
|
||||
|
||||
if (Type.empty())
|
||||
return createStringError(errc::invalid_argument,
|
||||
"invalid extension prefix '" + Ext + "'");
|
||||
|
||||
// Check ISA extensions are specified in the canonical order.
|
||||
while (I != E && *I != Type)
|
||||
++I;
|
||||
|
||||
if (I == E)
|
||||
return createStringError(errc::invalid_argument,
|
||||
"%s not given in canonical order '%s'",
|
||||
Desc.str().c_str(), Ext.str().c_str());
|
||||
|
||||
if (Name.size() == Type.size()) {
|
||||
return createStringError(errc::invalid_argument,
|
||||
"%s name missing after '%s'", Desc.str().c_str(),
|
||||
Type.str().c_str());
|
||||
}
|
||||
|
||||
unsigned Major, Minor, ConsumeLength;
|
||||
if (auto E = getExtensionVersion(Name, Vers, Major, Minor, ConsumeLength,
|
||||
EnableExperimentalExtension,
|
||||
ExperimentalExtensionVersionCheck))
|
||||
return std::move(E);
|
||||
|
||||
// Check if duplicated extension.
|
||||
if (llvm::is_contained(AllExts, Name))
|
||||
return createStringError(errc::invalid_argument, "duplicated %s '%s'",
|
||||
Desc.str().c_str(), Name.str().c_str());
|
||||
|
||||
ISAInfo->addExtension(Name, Major, Minor);
|
||||
// Extension format is correct, keep parsing the extensions.
|
||||
// TODO: Save Type, Name, Major, Minor to avoid parsing them later.
|
||||
AllExts.push_back(Name);
|
||||
}
|
||||
|
||||
for (auto Ext : AllExts) {
|
||||
if (!isSupportedExtension(Ext)) {
|
||||
StringRef Desc = getExtensionTypeDesc(getExtensionType(Ext));
|
||||
return createStringError(errc::invalid_argument, "unsupported %s '%s'",
|
||||
Desc.str().c_str(), Ext.str().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
ISAInfo->updateFLen();
|
||||
|
||||
return std::move(ISAInfo);
|
||||
}
|
||||
|
||||
void RISCVISAInfo::updateFLen() {
|
||||
FLen = 0;
|
||||
// TODO: Handle q extension.
|
||||
if (Exts.count("d"))
|
||||
FLen = 64;
|
||||
else if (Exts.count("f"))
|
||||
FLen = 32;
|
||||
}
|
||||
|
||||
std::string RISCVISAInfo::toString() const {
|
||||
std::string Buffer;
|
||||
raw_string_ostream Arch(Buffer);
|
||||
|
||||
Arch << "rv" << XLen;
|
||||
|
||||
ListSeparator LS("_");
|
||||
for (auto &Ext : Exts) {
|
||||
StringRef ExtName = Ext.first;
|
||||
auto ExtInfo = Ext.second;
|
||||
Arch << LS << ExtName;
|
||||
Arch << ExtInfo.MajorVersion << "p" << ExtInfo.MinorVersion;
|
||||
}
|
||||
|
||||
return Arch.str();
|
||||
}
|
||||
@@ -36,6 +36,7 @@
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
#include "llvm/Support/RISCVAttributes.h"
|
||||
#include "llvm/Support/RISCVISAInfo.h"
|
||||
|
||||
#include <limits>
|
||||
|
||||
@@ -50,6 +51,10 @@ using namespace llvm;
|
||||
STATISTIC(RISCVNumInstrsCompressed,
|
||||
"Number of RISC-V Compressed instructions emitted");
|
||||
|
||||
namespace llvm {
|
||||
extern const SubtargetFeatureKV RISCVFeatureKV[RISCV::NumSubtargetFeatures];
|
||||
} // namespace llvm
|
||||
|
||||
namespace {
|
||||
struct RISCVOperand;
|
||||
|
||||
@@ -2059,106 +2064,35 @@ bool RISCVAsmParser::parseDirectiveAttribute() {
|
||||
|
||||
if (Tag == RISCVAttrs::ARCH) {
|
||||
StringRef Arch = StringValue;
|
||||
if (Arch.consume_front("rv32"))
|
||||
for (auto Feature : RISCVFeatureKV)
|
||||
if (llvm::RISCVISAInfo::isSupportedExtensionFeature(Feature.Key))
|
||||
clearFeatureBits(Feature.Value, Feature.Key);
|
||||
|
||||
auto ParseResult = llvm::RISCVISAInfo::parseArchString(
|
||||
StringValue, /*EnableExperimentalExtension=*/true,
|
||||
/*ExperimentalExtensionVersionCheck=*/false);
|
||||
if (!ParseResult) {
|
||||
std::string Buffer;
|
||||
raw_string_ostream OutputErrMsg(Buffer);
|
||||
handleAllErrors(ParseResult.takeError(), [&](llvm::StringError &ErrMsg) {
|
||||
OutputErrMsg << "invalid arch name '" << Arch << "', "
|
||||
<< ErrMsg.getMessage();
|
||||
});
|
||||
|
||||
return Error(ValueExprLoc, OutputErrMsg.str());
|
||||
}
|
||||
auto &ISAInfo = *ParseResult;
|
||||
|
||||
for (auto Feature : RISCVFeatureKV)
|
||||
if (ISAInfo->hasExtension(Feature.Key))
|
||||
setFeatureBits(Feature.Value, Feature.Key);
|
||||
|
||||
if (ISAInfo->getXLen() == 32)
|
||||
clearFeatureBits(RISCV::Feature64Bit, "64bit");
|
||||
else if (Arch.consume_front("rv64"))
|
||||
else if (ISAInfo->getXLen() == 64)
|
||||
setFeatureBits(RISCV::Feature64Bit, "64bit");
|
||||
else
|
||||
return Error(ValueExprLoc, "bad arch string " + Arch);
|
||||
|
||||
// .attribute arch overrides the current architecture, so unset all
|
||||
// currently enabled extensions
|
||||
clearFeatureBits(RISCV::FeatureRV32E, "e");
|
||||
clearFeatureBits(RISCV::FeatureStdExtM, "m");
|
||||
clearFeatureBits(RISCV::FeatureStdExtA, "a");
|
||||
clearFeatureBits(RISCV::FeatureStdExtF, "f");
|
||||
clearFeatureBits(RISCV::FeatureStdExtD, "d");
|
||||
clearFeatureBits(RISCV::FeatureStdExtC, "c");
|
||||
clearFeatureBits(RISCV::FeatureStdExtV, "experimental-v");
|
||||
clearFeatureBits(RISCV::FeatureStdExtZfh, "experimental-zfh");
|
||||
clearFeatureBits(RISCV::FeatureStdExtZba, "experimental-zba");
|
||||
clearFeatureBits(RISCV::FeatureStdExtZbb, "experimental-zbb");
|
||||
clearFeatureBits(RISCV::FeatureStdExtZbc, "experimental-zbc");
|
||||
clearFeatureBits(RISCV::FeatureStdExtZbe, "experimental-zbe");
|
||||
clearFeatureBits(RISCV::FeatureStdExtZbf, "experimental-zbf");
|
||||
clearFeatureBits(RISCV::FeatureStdExtZbm, "experimental-zbm");
|
||||
clearFeatureBits(RISCV::FeatureStdExtZbp, "experimental-zbp");
|
||||
clearFeatureBits(RISCV::FeatureStdExtZbr, "experimental-zbr");
|
||||
clearFeatureBits(RISCV::FeatureStdExtZbs, "experimental-zbs");
|
||||
clearFeatureBits(RISCV::FeatureStdExtZbt, "experimental-zbt");
|
||||
clearFeatureBits(RISCV::FeatureStdExtZvamo, "experimental-zvamo");
|
||||
clearFeatureBits(RISCV::FeatureStdExtZvlsseg, "experimental-zvlsseg");
|
||||
|
||||
while (!Arch.empty()) {
|
||||
bool DropFirst = true;
|
||||
if (Arch[0] == 'i')
|
||||
clearFeatureBits(RISCV::FeatureRV32E, "e");
|
||||
else if (Arch[0] == 'e')
|
||||
setFeatureBits(RISCV::FeatureRV32E, "e");
|
||||
else if (Arch[0] == 'g') {
|
||||
clearFeatureBits(RISCV::FeatureRV32E, "e");
|
||||
setFeatureBits(RISCV::FeatureStdExtM, "m");
|
||||
setFeatureBits(RISCV::FeatureStdExtA, "a");
|
||||
setFeatureBits(RISCV::FeatureStdExtF, "f");
|
||||
setFeatureBits(RISCV::FeatureStdExtD, "d");
|
||||
} else if (Arch[0] == 'm')
|
||||
setFeatureBits(RISCV::FeatureStdExtM, "m");
|
||||
else if (Arch[0] == 'a')
|
||||
setFeatureBits(RISCV::FeatureStdExtA, "a");
|
||||
else if (Arch[0] == 'f')
|
||||
setFeatureBits(RISCV::FeatureStdExtF, "f");
|
||||
else if (Arch[0] == 'd') {
|
||||
setFeatureBits(RISCV::FeatureStdExtF, "f");
|
||||
setFeatureBits(RISCV::FeatureStdExtD, "d");
|
||||
} else if (Arch[0] == 'c') {
|
||||
setFeatureBits(RISCV::FeatureStdExtC, "c");
|
||||
} else if (Arch[0] == 'v') {
|
||||
setFeatureBits(RISCV::FeatureStdExtV, "experimental-v");
|
||||
} else if (Arch[0] == 's' || Arch[0] == 'x' || Arch[0] == 'z') {
|
||||
StringRef Ext =
|
||||
Arch.take_until([](char c) { return ::isdigit(c) || c == '_'; });
|
||||
if (Ext == "zba")
|
||||
setFeatureBits(RISCV::FeatureStdExtZba, "experimental-zba");
|
||||
else if (Ext == "zbb")
|
||||
setFeatureBits(RISCV::FeatureStdExtZbb, "experimental-zbb");
|
||||
else if (Ext == "zbc")
|
||||
setFeatureBits(RISCV::FeatureStdExtZbc, "experimental-zbc");
|
||||
else if (Ext == "zbe")
|
||||
setFeatureBits(RISCV::FeatureStdExtZbe, "experimental-zbe");
|
||||
else if (Ext == "zbf")
|
||||
setFeatureBits(RISCV::FeatureStdExtZbf, "experimental-zbf");
|
||||
else if (Ext == "zbm")
|
||||
setFeatureBits(RISCV::FeatureStdExtZbm, "experimental-zbm");
|
||||
else if (Ext == "zbp")
|
||||
setFeatureBits(RISCV::FeatureStdExtZbp, "experimental-zbp");
|
||||
else if (Ext == "zbr")
|
||||
setFeatureBits(RISCV::FeatureStdExtZbr, "experimental-zbr");
|
||||
else if (Ext == "zbs")
|
||||
setFeatureBits(RISCV::FeatureStdExtZbs, "experimental-zbs");
|
||||
else if (Ext == "zbt")
|
||||
setFeatureBits(RISCV::FeatureStdExtZbt, "experimental-zbt");
|
||||
else if (Ext == "zfh")
|
||||
setFeatureBits(RISCV::FeatureStdExtZfh, "experimental-zfh");
|
||||
else if (Ext == "zvamo")
|
||||
setFeatureBits(RISCV::FeatureStdExtZvamo, "experimental-zvamo");
|
||||
else if (Ext == "zvlsseg")
|
||||
setFeatureBits(RISCV::FeatureStdExtZvlsseg, "experimental-zvlsseg");
|
||||
else
|
||||
return Error(ValueExprLoc, "bad arch string " + Ext);
|
||||
Arch = Arch.drop_until([](char c) { return ::isdigit(c) || c == '_'; });
|
||||
DropFirst = false;
|
||||
} else
|
||||
return Error(ValueExprLoc, "bad arch string " + Arch);
|
||||
|
||||
if (DropFirst)
|
||||
Arch = Arch.drop_front(1);
|
||||
int major = 0;
|
||||
int minor = 0;
|
||||
Arch.consumeInteger(10, major);
|
||||
Arch.consume_front("p");
|
||||
Arch.consumeInteger(10, minor);
|
||||
Arch = Arch.drop_while([](char c) { return c == '_'; });
|
||||
}
|
||||
}
|
||||
|
||||
if (IsIntegerValue)
|
||||
@@ -2167,54 +2101,26 @@ bool RISCVAsmParser::parseDirectiveAttribute() {
|
||||
if (Tag != RISCVAttrs::ARCH) {
|
||||
getTargetStreamer().emitTextAttribute(Tag, StringValue);
|
||||
} else {
|
||||
std::string formalArchStr = "rv32";
|
||||
if (getFeatureBits(RISCV::Feature64Bit))
|
||||
formalArchStr = "rv64";
|
||||
if (getFeatureBits(RISCV::FeatureRV32E))
|
||||
formalArchStr = (Twine(formalArchStr) + "e1p9").str();
|
||||
else
|
||||
formalArchStr = (Twine(formalArchStr) + "i2p0").str();
|
||||
std::vector<std::string> FeatureVector;
|
||||
RISCVFeatures::toFeatureVector(FeatureVector, getSTI().getFeatureBits());
|
||||
|
||||
if (getFeatureBits(RISCV::FeatureStdExtM))
|
||||
formalArchStr = (Twine(formalArchStr) + "_m2p0").str();
|
||||
if (getFeatureBits(RISCV::FeatureStdExtA))
|
||||
formalArchStr = (Twine(formalArchStr) + "_a2p0").str();
|
||||
if (getFeatureBits(RISCV::FeatureStdExtF))
|
||||
formalArchStr = (Twine(formalArchStr) + "_f2p0").str();
|
||||
if (getFeatureBits(RISCV::FeatureStdExtD))
|
||||
formalArchStr = (Twine(formalArchStr) + "_d2p0").str();
|
||||
if (getFeatureBits(RISCV::FeatureStdExtC))
|
||||
formalArchStr = (Twine(formalArchStr) + "_c2p0").str();
|
||||
if (getFeatureBits(RISCV::FeatureStdExtV))
|
||||
formalArchStr = (Twine(formalArchStr) + "_v0p10").str();
|
||||
if (getFeatureBits(RISCV::FeatureStdExtZfh))
|
||||
formalArchStr = (Twine(formalArchStr) + "_zfh0p1").str();
|
||||
if (getFeatureBits(RISCV::FeatureStdExtZba))
|
||||
formalArchStr = (Twine(formalArchStr) + "_zba1p0").str();
|
||||
if (getFeatureBits(RISCV::FeatureStdExtZbb))
|
||||
formalArchStr = (Twine(formalArchStr) + "_zbb1p0").str();
|
||||
if (getFeatureBits(RISCV::FeatureStdExtZbc))
|
||||
formalArchStr = (Twine(formalArchStr) + "_zbc1p0").str();
|
||||
if (getFeatureBits(RISCV::FeatureStdExtZbe))
|
||||
formalArchStr = (Twine(formalArchStr) + "_zbe0p93").str();
|
||||
if (getFeatureBits(RISCV::FeatureStdExtZbf))
|
||||
formalArchStr = (Twine(formalArchStr) + "_zbf0p93").str();
|
||||
if (getFeatureBits(RISCV::FeatureStdExtZbm))
|
||||
formalArchStr = (Twine(formalArchStr) + "_zbm0p93").str();
|
||||
if (getFeatureBits(RISCV::FeatureStdExtZbp))
|
||||
formalArchStr = (Twine(formalArchStr) + "_zbp0p93").str();
|
||||
if (getFeatureBits(RISCV::FeatureStdExtZbr))
|
||||
formalArchStr = (Twine(formalArchStr) + "_zbr0p93").str();
|
||||
if (getFeatureBits(RISCV::FeatureStdExtZbs))
|
||||
formalArchStr = (Twine(formalArchStr) + "_zbs1p0").str();
|
||||
if (getFeatureBits(RISCV::FeatureStdExtZbt))
|
||||
formalArchStr = (Twine(formalArchStr) + "_zbt0p93").str();
|
||||
if (getFeatureBits(RISCV::FeatureStdExtZvamo))
|
||||
formalArchStr = (Twine(formalArchStr) + "_zvamo0p10").str();
|
||||
if (getFeatureBits(RISCV::FeatureStdExtZvlsseg))
|
||||
formalArchStr = (Twine(formalArchStr) + "_zvlsseg0p10").str();
|
||||
// Parse that by RISCVISAInfo->
|
||||
unsigned XLen = getFeatureBits(RISCV::Feature64Bit) ? 64 : 32;
|
||||
auto ParseResult = llvm::RISCVISAInfo::parseFeatures(XLen, FeatureVector);
|
||||
if (!ParseResult) {
|
||||
std::string Buffer;
|
||||
raw_string_ostream OutputErrMsg(Buffer);
|
||||
handleAllErrors(ParseResult.takeError(),
|
||||
[&](llvm::StringError &ErrMsg) {
|
||||
OutputErrMsg << ErrMsg.getMessage();
|
||||
});
|
||||
|
||||
getTargetStreamer().emitTextAttribute(Tag, formalArchStr);
|
||||
return Error(ValueExprLoc, OutputErrMsg.str());
|
||||
}
|
||||
auto &ISAInfo = *ParseResult;
|
||||
|
||||
// Then emit the arch string.
|
||||
getTargetStreamer().emitTextAttribute(Tag, ISAInfo->toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,9 +14,14 @@
|
||||
#include "RISCVBaseInfo.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/Triple.h"
|
||||
#include "llvm/MC/MCSubtargetInfo.h"
|
||||
#include "llvm/Support/RISCVISAInfo.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
extern const SubtargetFeatureKV RISCVFeatureKV[RISCV::NumSubtargetFeatures];
|
||||
|
||||
namespace RISCVSysReg {
|
||||
#define GET_SysRegsList_IMPL
|
||||
#include "RISCVGenSearchableTables.inc"
|
||||
@@ -96,6 +101,15 @@ void validate(const Triple &TT, const FeatureBitset &FeatureBits) {
|
||||
report_fatal_error("RV32E can't be enabled for an RV64 target");
|
||||
}
|
||||
|
||||
void toFeatureVector(std::vector<std::string> &FeatureVector,
|
||||
const FeatureBitset &FeatureBits) {
|
||||
for (auto Feature : RISCVFeatureKV) {
|
||||
if (FeatureBits[Feature.Value] &&
|
||||
llvm::RISCVISAInfo::isSupportedExtensionFeature(Feature.Key))
|
||||
FeatureVector.push_back(std::string("+") + Feature.Key);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace RISCVFeatures
|
||||
|
||||
// Encode VTYPE into the binary format used by the the VSETVLI instruction which
|
||||
|
||||
@@ -324,6 +324,10 @@ namespace RISCVFeatures {
|
||||
// triple. Exits with report_fatal_error if not.
|
||||
void validate(const Triple &TT, const FeatureBitset &FeatureBits);
|
||||
|
||||
// Convert FeatureBitset to FeatureVector.
|
||||
void toFeatureVector(std::vector<std::string> &FeatureVector,
|
||||
const FeatureBitset &FeatureBits);
|
||||
|
||||
} // namespace RISCVFeatures
|
||||
|
||||
namespace RISCVVType {
|
||||
|
||||
@@ -11,9 +11,11 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "RISCVTargetStreamer.h"
|
||||
#include "RISCVBaseInfo.h"
|
||||
#include "RISCVMCTargetDesc.h"
|
||||
#include "llvm/Support/FormattedStream.h"
|
||||
#include "llvm/Support/RISCVAttributes.h"
|
||||
#include "llvm/Support/RISCVISAInfo.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
@@ -43,53 +45,19 @@ void RISCVTargetStreamer::emitTargetAttributes(const MCSubtargetInfo &STI) {
|
||||
else
|
||||
emitAttribute(RISCVAttrs::STACK_ALIGN, RISCVAttrs::ALIGN_16);
|
||||
|
||||
std::string Arch = "rv32";
|
||||
if (STI.hasFeature(RISCV::Feature64Bit))
|
||||
Arch = "rv64";
|
||||
if (STI.hasFeature(RISCV::FeatureRV32E))
|
||||
Arch += "e1p9";
|
||||
else
|
||||
Arch += "i2p0";
|
||||
if (STI.hasFeature(RISCV::FeatureStdExtM))
|
||||
Arch += "_m2p0";
|
||||
if (STI.hasFeature(RISCV::FeatureStdExtA))
|
||||
Arch += "_a2p0";
|
||||
if (STI.hasFeature(RISCV::FeatureStdExtF))
|
||||
Arch += "_f2p0";
|
||||
if (STI.hasFeature(RISCV::FeatureStdExtD))
|
||||
Arch += "_d2p0";
|
||||
if (STI.hasFeature(RISCV::FeatureStdExtC))
|
||||
Arch += "_c2p0";
|
||||
if (STI.hasFeature(RISCV::FeatureStdExtV))
|
||||
Arch += "_v0p10";
|
||||
if (STI.hasFeature(RISCV::FeatureStdExtZfh))
|
||||
Arch += "_zfh0p1";
|
||||
if (STI.hasFeature(RISCV::FeatureStdExtZba))
|
||||
Arch += "_zba1p0";
|
||||
if (STI.hasFeature(RISCV::FeatureStdExtZbb))
|
||||
Arch += "_zbb1p0";
|
||||
if (STI.hasFeature(RISCV::FeatureStdExtZbc))
|
||||
Arch += "_zbc1p0";
|
||||
if (STI.hasFeature(RISCV::FeatureStdExtZbe))
|
||||
Arch += "_zbe0p93";
|
||||
if (STI.hasFeature(RISCV::FeatureStdExtZbf))
|
||||
Arch += "_zbf0p93";
|
||||
if (STI.hasFeature(RISCV::FeatureStdExtZbm))
|
||||
Arch += "_zbm0p93";
|
||||
if (STI.hasFeature(RISCV::FeatureStdExtZbp))
|
||||
Arch += "_zbp0p93";
|
||||
if (STI.hasFeature(RISCV::FeatureStdExtZbr))
|
||||
Arch += "_zbr0p93";
|
||||
if (STI.hasFeature(RISCV::FeatureStdExtZbs))
|
||||
Arch += "_zbs1p0";
|
||||
if (STI.hasFeature(RISCV::FeatureStdExtZbt))
|
||||
Arch += "_zbt0p93";
|
||||
if (STI.hasFeature(RISCV::FeatureStdExtZvamo))
|
||||
Arch += "_zvamo0p10";
|
||||
if (STI.hasFeature(RISCV::FeatureStdExtZvlsseg))
|
||||
Arch += "_zvlsseg0p10";
|
||||
unsigned XLen = STI.hasFeature(RISCV::Feature64Bit) ? 64 : 32;
|
||||
std::vector<std::string> FeatureVector;
|
||||
RISCVFeatures::toFeatureVector(FeatureVector, STI.getFeatureBits());
|
||||
|
||||
emitTextAttribute(RISCVAttrs::ARCH, Arch);
|
||||
auto ParseResult = llvm::RISCVISAInfo::parseFeatures(XLen, FeatureVector);
|
||||
if (!ParseResult) {
|
||||
/* Assume any error about features should handled earlier. */
|
||||
consumeError(ParseResult.takeError());
|
||||
llvm_unreachable("Parsing feature error when emitTargetAttributes?");
|
||||
} else {
|
||||
auto &ISAInfo = *ParseResult;
|
||||
emitTextAttribute(RISCVAttrs::ARCH, ISAInfo->toString());
|
||||
}
|
||||
}
|
||||
|
||||
// This part is for ascii assembly output
|
||||
|
||||
@@ -9,9 +9,6 @@
|
||||
.attribute arch, "rv32i2"
|
||||
# CHECK: attribute 5, "rv32i2p0"
|
||||
|
||||
.attribute arch, "rv32i2p"
|
||||
# CHECK: attribute 5, "rv32i2p0"
|
||||
|
||||
.attribute arch, "rv32i2p0"
|
||||
# CHECK: attribute 5, "rv32i2p0"
|
||||
|
||||
@@ -33,11 +30,11 @@
|
||||
.attribute arch, "rv32ima2p0_fdc"
|
||||
# CHECK: attribute 5, "rv32i2p0_m2p0_a2p0_f2p0_d2p0_c2p0"
|
||||
|
||||
.attribute arch, "rv32ima2p_fdc"
|
||||
.attribute arch, "rv32ima2p0_fdc"
|
||||
# CHECK: attribute 5, "rv32i2p0_m2p0_a2p0_f2p0_d2p0_c2p0"
|
||||
|
||||
.attribute arch, "rv32iv"
|
||||
# CHECK: attribute 5, "rv32i2p0_v0p10"
|
||||
# CHECK: attribute 5, "rv32i2p0_v0p10_zvlsseg0p10"
|
||||
|
||||
.attribute arch, "rv32izba"
|
||||
# CHECK: attribute 5, "rv32i2p0_zba1p0"
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
# RUN: | llvm-objdump --triple=riscv64 -d -M no-aliases - \
|
||||
# RUN: | FileCheck -check-prefix=CHECK-INST %s
|
||||
|
||||
.attribute arch, "rv64i2p0_m2p0_a2p0_d2p0_c2p0"
|
||||
.attribute arch, "rv64i2p0_m2p0_a2p0_f2p0_d2p0_c2p0"
|
||||
|
||||
# CHECK-INST: lr.w t0, (t1)
|
||||
lr.w t0, (t1)
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
# RUN: not llvm-mc %s -triple=riscv64 -filetype=asm 2>&1 | FileCheck %s
|
||||
|
||||
.attribute arch, "foo"
|
||||
# CHECK: [[@LINE-1]]:18: error: bad arch string foo
|
||||
# CHECK: [[@LINE-1]]:18: error: invalid arch name 'foo', string must begin with rv32{i,e,g} or rv64{i,g}
|
||||
|
||||
.attribute arch, "rv32i2p0_y2p0"
|
||||
# CHECK: [[@LINE-1]]:18: error: bad arch string y2p0
|
||||
# CHECK: [[@LINE-1]]:18: error: invalid arch name 'rv32i2p0_y2p0', invalid standard user-level extension 'y'
|
||||
|
||||
.attribute stack_align, "16"
|
||||
# CHECK: [[@LINE-1]]:25: error: expected numeric constant
|
||||
|
||||
Reference in New Issue
Block a user