aboutsummaryrefslogtreecommitdiff
path: root/clang/lib
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/Driver/ToolChains/Gnu.cpp127
1 files changed, 126 insertions, 1 deletions
diff --git a/clang/lib/Driver/ToolChains/Gnu.cpp b/clang/lib/Driver/ToolChains/Gnu.cpp
index 835215a..02228e1 100644
--- a/clang/lib/Driver/ToolChains/Gnu.cpp
+++ b/clang/lib/Driver/ToolChains/Gnu.cpp
@@ -30,6 +30,7 @@
#include "llvm/Option/ArgList.h"
#include "llvm/Support/CodeGen.h"
#include "llvm/Support/Path.h"
+#include "llvm/Support/RISCVISAInfo.h"
#include "llvm/Support/VirtualFileSystem.h"
#include "llvm/TargetParser/TargetParser.h"
#include <system_error>
@@ -1715,6 +1716,129 @@ static void findCSKYMultilibs(const Driver &D, const llvm::Triple &TargetTriple,
Result.Multilibs = CSKYMultilibs;
}
+/// Extend the multi-lib re-use selection mechanism for RISC-V.
+/// This function will try to re-use multi-lib if they are compatible.
+/// Definition of compatible:
+/// - ABI must be the same.
+/// - multi-lib is a subset of current arch, e.g. multi-lib=march=rv32im
+/// is a subset of march=rv32imc.
+/// - march that contains atomic extension can't reuse multi-lib that
+/// doesn't have atomic, vice versa. e.g. multi-lib=march=rv32im and
+/// march=rv32ima are not compatible, because software and hardware
+/// atomic operation can't work together correctly.
+static bool
+selectRISCVMultilib(const MultilibSet &RISCVMultilibSet, StringRef Arch,
+ const Multilib::flags_list &Flags,
+ llvm::SmallVectorImpl<Multilib> &SelectedMultilibs) {
+ // Try to find the perfect matching multi-lib first.
+ if (RISCVMultilibSet.select(Flags, SelectedMultilibs))
+ return true;
+
+ Multilib::flags_list NewFlags;
+ std::vector<MultilibBuilder> NewMultilibs;
+
+ llvm::Expected<std::unique_ptr<llvm::RISCVISAInfo>> ParseResult =
+ llvm::RISCVISAInfo::parseArchString(
+ Arch, /*EnableExperimentalExtension=*/true,
+ /*ExperimentalExtensionVersionCheck=*/false);
+ if (!ParseResult) {
+ // Ignore any error here, we assume it will be handled in another place.
+ consumeError(ParseResult.takeError());
+ return false;
+ }
+
+ auto &ISAInfo = *ParseResult;
+
+ addMultilibFlag(ISAInfo->getXLen() == 32, "-m32", NewFlags);
+ addMultilibFlag(ISAInfo->getXLen() == 64, "-m64", NewFlags);
+
+ // Collect all flags except march=*
+ for (StringRef Flag : Flags) {
+ if (Flag.startswith("!march=") || Flag.startswith("-march="))
+ continue;
+
+ NewFlags.push_back(Flag.str());
+ }
+
+ llvm::StringSet<> AllArchExts;
+ // Reconstruct multi-lib list, and break march option into separated
+ // extension. e.g. march=rv32im -> +i +m
+ for (const auto &M : RISCVMultilibSet) {
+ bool Skip = false;
+
+ MultilibBuilder NewMultilib =
+ MultilibBuilder(M.gccSuffix(), M.osSuffix(), M.includeSuffix());
+ for (StringRef Flag : M.flags()) {
+ // Add back all flags except -march.
+ if (!Flag.consume_front("-march=")) {
+ NewMultilib.flag(Flag);
+ continue;
+ }
+
+ // Break down -march into individual extension.
+ llvm::Expected<std::unique_ptr<llvm::RISCVISAInfo>> MLConfigParseResult =
+ llvm::RISCVISAInfo::parseArchString(
+ Flag, /*EnableExperimentalExtension=*/true,
+ /*ExperimentalExtensionVersionCheck=*/false);
+ if (!MLConfigParseResult) {
+ // Ignore any error here, we assume it will handled in another place.
+ llvm::consumeError(MLConfigParseResult.takeError());
+
+ // We might get a parsing error if rv32e in the list, we could just skip
+ // that and process the rest of multi-lib configs.
+ Skip = true;
+ continue;
+ }
+ auto &MLConfigISAInfo = *MLConfigParseResult;
+
+ const llvm::RISCVISAInfo::OrderedExtensionMap &MLConfigArchExts =
+ MLConfigISAInfo->getExtensions();
+ for (auto MLConfigArchExt : MLConfigArchExts) {
+ auto ExtName = MLConfigArchExt.first;
+ NewMultilib.flag(Twine("-", ExtName).str());
+
+ if (AllArchExts.insert(ExtName).second) {
+ addMultilibFlag(ISAInfo->hasExtension(ExtName),
+ Twine("-", ExtName).str(), NewFlags);
+ }
+ }
+
+ // Check the XLEN explicitly.
+ if (MLConfigISAInfo->getXLen() == 32) {
+ NewMultilib.flag("-m32");
+ NewMultilib.flag("!m64");
+ } else {
+ NewMultilib.flag("!m32");
+ NewMultilib.flag("-m64");
+ }
+
+ // Atomic extension must be explicitly checked, soft and hard atomic
+ // operation never co-work correctly.
+ if (!MLConfigISAInfo->hasExtension("a"))
+ NewMultilib.flag("!a");
+ }
+
+ if (Skip)
+ continue;
+
+ NewMultilibs.emplace_back(NewMultilib);
+ }
+
+ // Build an internal used only multi-lib list, used for checking any
+ // compatible multi-lib.
+ MultilibSet NewRISCVMultilibs =
+ MultilibSetBuilder().Either(NewMultilibs).makeMultilibSet();
+
+ if (NewRISCVMultilibs.select(NewFlags, SelectedMultilibs))
+ for (const Multilib &NewSelectedM : SelectedMultilibs)
+ for (const auto &M : RISCVMultilibSet)
+ // Look up the corresponding multi-lib entry in original multi-lib set.
+ if (M.gccSuffix() == NewSelectedM.gccSuffix())
+ return true;
+
+ return false;
+}
+
static void findRISCVBareMetalMultilibs(const Driver &D,
const llvm::Triple &TargetTriple,
StringRef Path, const ArgList &Args,
@@ -1766,7 +1890,8 @@ static void findRISCVBareMetalMultilibs(const Driver &D,
}
}
- if (RISCVMultilibs.select(Flags, Result.SelectedMultilibs))
+ if (selectRISCVMultilib(RISCVMultilibs, MArch, Flags,
+ Result.SelectedMultilibs))
Result.Multilibs = RISCVMultilibs;
}