[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:
Kito Cheng
2021-06-23 16:18:54 +08:00
parent 10726992fa
commit ff13189c5d
17 changed files with 991 additions and 793 deletions

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;
}
};

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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'

View 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

View File

@@ -184,6 +184,7 @@ add_llvm_component_library(LLVMSupport
Regex.cpp
RISCVAttributes.cpp
RISCVAttributeParser.cpp
RISCVISAInfo.cpp
ScaledNumber.cpp
ScopedPrinter.cpp
SHA1.cpp

View 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();
}

View File

@@ -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());
}
}

View File

@@ -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

View File

@@ -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 {

View File

@@ -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

View File

@@ -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"

View File

@@ -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)

View File

@@ -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