diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2020-07-26 19:36:28 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2020-07-26 19:36:28 +0000 |
commit | cfca06d7963fa0909f90483b42a6d7d194d01e08 (patch) | |
tree | 209fb2a2d68f8f277793fc8df46c753d31bc853b /clang/lib/Driver/ToolChains/Arch/RISCV.cpp | |
parent | 706b4fc47bbc608932d3b491ae19a3b9cde9497b (diff) |
Notes
Diffstat (limited to 'clang/lib/Driver/ToolChains/Arch/RISCV.cpp')
-rw-r--r-- | clang/lib/Driver/ToolChains/Arch/RISCV.cpp | 193 |
1 files changed, 142 insertions, 51 deletions
diff --git a/clang/lib/Driver/ToolChains/Arch/RISCV.cpp b/clang/lib/Driver/ToolChains/Arch/RISCV.cpp index 8c343b8693f3..80d12e5aa8da 100644 --- a/clang/lib/Driver/ToolChains/Arch/RISCV.cpp +++ b/clang/lib/Driver/ToolChains/Arch/RISCV.cpp @@ -22,6 +22,14 @@ 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"; @@ -29,6 +37,8 @@ static StringRef getExtensionTypeDesc(StringRef Ext) { 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(); } @@ -39,10 +49,29 @@ static StringRef getExtensionType(StringRef Ext) { 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 == "b" || Ext == "zbb" || Ext == "zbc" || Ext == "zbe" || + Ext == "zbf" || Ext == "zbm" || Ext == "zbp" || Ext == "zbr" || + Ext == "zbs" || Ext == "zbt" || Ext == "zbproposedc") + return RISCVExtensionVersion{"0", "92"}; + if (Ext == "v") + return RISCVExtensionVersion{"0", "8"}; + 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; } @@ -52,17 +81,15 @@ static bool isSupportedExtension(StringRef Ext) { // 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, StringRef MArch, - StringRef Ext, StringRef In, +static bool getExtensionVersion(const Driver &D, const ArgList &Args, + StringRef MArch, StringRef Ext, StringRef In, std::string &Major, std::string &Minor) { - Major = In.take_while(isDigit); + Major = std::string(In.take_while(isDigit)); In = In.substr(Major.size()); - if (Major.empty()) - return true; - if (In.consume_front("p")) { - Minor = 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()) { @@ -74,7 +101,53 @@ static bool getExtensionVersion(const Driver &D, StringRef MArch, } } - // TODO: Handle extensions with version number. + // 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; @@ -89,7 +162,7 @@ static bool getExtensionVersion(const Driver &D, StringRef MArch, // Parse the ISA string containing non-standard user-level // extensions, standard supervisor-level extensions and // non-standard supervisor-level extensions. -// These extensions start with 'x', 's', 'sx' prefixes, follow a +// 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. @@ -105,7 +178,7 @@ static void getExtensionFeatures(const Driver &D, SmallVector<StringRef, 8> Split; Exts.split(Split, StringRef("_")); - SmallVector<StringRef, 3> Prefix{"x", "s", "sx"}; + SmallVector<StringRef, 4> Prefix{"z", "x", "s", "sx"}; auto I = Prefix.begin(); auto E = Prefix.end(); @@ -119,8 +192,10 @@ static void getExtensionFeatures(const Driver &D, } StringRef Type = getExtensionType(Ext); - StringRef Name(Ext.substr(Type.size())); 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) @@ -133,7 +208,7 @@ static void getExtensionFeatures(const Driver &D, ++I; if (I == E) { - std::string Error = Desc; + 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; @@ -143,35 +218,30 @@ static void getExtensionFeatures(const Driver &D, // The order is OK, do not advance I to the next prefix // to allow repeated extension type, e.g.: rv32ixabc_xdef. - if (Name.empty()) { - std::string Error = Desc; + 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 << Ext; + << MArch << Error << Type; return; } std::string Major, Minor; - auto Pos = Name.find_if(isDigit); - if (Pos != StringRef::npos) { - auto Next = Name.substr(Pos); - Name = Name.substr(0, Pos); - if (!getExtensionVersion(D, MArch, Ext, Next, Major, Minor)) - return; - } + if (!getExtensionVersion(D, Args, MArch, Name, Vers, Major, Minor)) + return; // Check if duplicated extension. - if (llvm::is_contained(AllExts, Ext)) { + if (llvm::is_contained(AllExts, Name)) { std::string Error = "duplicated "; Error += Desc; D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) - << MArch << Error << Ext; + << 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(Ext); + AllExts.push_back(Name); } // Set target features. @@ -186,7 +256,10 @@ static void getExtensionFeatures(const Driver &D, << MArch << Error << Ext; return; } - Features.push_back(Args.MakeArgString("+" + Ext)); + if (isExperimentalExtension(Ext)) + Features.push_back(Args.MakeArgString("+experimental-" + Ext)); + else + Features.push_back(Args.MakeArgString("+" + Ext)); } } @@ -251,28 +324,35 @@ static bool getArchFeatures(const Driver &D, StringRef MArch, // Skip rvxxx StringRef Exts = MArch.substr(5); - // Remove non-standard extensions and supervisor-level extensions. - // They have 'x', 's', 'sx' prefixes. Parse them at the end. - // Find the very first occurrence of 's' or 'x'. + // 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("sx"); + 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, MArch, std::string(1, Baseline), Exts, 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 - // and consume the underscore '_' that might follow. auto StdExtsItr = StdExts.begin(); auto StdExtsEnd = StdExts.end(); - for (auto I = Exts.begin(), E = Exts.end(); I != E; ++I) { + for (auto I = Exts.begin(), E = Exts.end(); I != E; ) { char c = *I; // Check ISA extensions are specified in the canonical order. @@ -295,18 +375,15 @@ static bool getArchFeatures(const Driver &D, StringRef MArch, // Move to next char to prevent repeated letter. ++StdExtsItr; - if (std::next(I) != E) { - // Skip c. - std::string Next = std::string(std::next(I), E); - std::string Major, Minor; - if (!getExtensionVersion(D, MArch, std::string(1, c), Next, Major, Minor)) - return false; - - // TODO: Use version number when setting target features - // and consume the underscore '_' that might follow. - } + 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". @@ -331,7 +408,22 @@ static bool getArchFeatures(const Driver &D, StringRef MArch, case 'c': Features.push_back("+c"); break; + case 'b': + Features.push_back("+experimental-b"); + break; + case 'v': + Features.push_back("+experimental-v"); + 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. @@ -433,12 +525,11 @@ void riscv::getRISCVTargetFeatures(const Driver &D, const llvm::Triple &Triple, Features.push_back("-relax"); // GCC Compatibility: -mno-save-restore is default, unless -msave-restore is - // specified... - if (Args.hasFlag(options::OPT_msave_restore, options::OPT_mno_save_restore, false)) { - // ... but we don't support -msave-restore, so issue a warning. - D.Diag(diag::warn_drv_clang_unsupported) - << Args.getLastArg(options::OPT_msave_restore)->getAsString(Args); - } + // specified. + if (Args.hasFlag(options::OPT_msave_restore, options::OPT_mno_save_restore, false)) + Features.push_back("+save-restore"); + else + Features.push_back("-save-restore"); // Now add any that the user explicitly requested on the command line, // which may override the defaults. |