[llvm-branch-commits] [clang] [Multilib] Custom flags processing for library selection (PR #110659)
via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Thu Oct 24 02:18:12 PDT 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang-driver
Author: Victor Campos (vhscampos)
<details>
<summary>Changes</summary>
Select library variants in the multilib system using the flags passed in the '-fmultilib-flag=' format.
Multilib flags that were not passed in the command-line have their default value fed into the library selection mechanism.
A warning is shown if the flag's value is invalid. The closest valid value is suggested (string edit distance).
Details about this change can be found in this thread: https://discourse.llvm.org/t/rfc-multilib-custom-flags/81058
---
Full diff: https://github.com/llvm/llvm-project/pull/110659.diff
5 Files Affected:
- (modified) clang/include/clang/Basic/DiagnosticDriverKinds.td (+6)
- (modified) clang/include/clang/Driver/Multilib.h (+3)
- (modified) clang/lib/Driver/Driver.cpp (+1-3)
- (modified) clang/lib/Driver/Multilib.cpp (+134-3)
- (added) clang/test/Driver/baremetal-multilib-custom-flags.yaml (+57)
``````````diff
diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td
index 65551bd7761a9d..6874614557f837 100644
--- a/clang/include/clang/Basic/DiagnosticDriverKinds.td
+++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td
@@ -14,6 +14,12 @@ def err_drv_no_such_file_with_suggestion : Error<
def err_drv_unsupported_opt : Error<"unsupported option '%0'">;
def err_drv_unsupported_opt_with_suggestion : Error<
"unsupported option '%0'; did you mean '%1'?">;
+def warn_drv_unsupported_opt : Warning<
+ "unsupported option '%0'">,
+ InGroup<UnusedCommandLineArgument>;
+def warn_drv_unsupported_opt_with_suggestion : Warning<
+ "unsupported option '%0'; did you mean '%1'?">,
+ InGroup<UnusedCommandLineArgument>;
def err_drv_unsupported_opt_for_target : Error<
"unsupported option '%0' for target '%1'">;
def err_drv_unsupported_opt_for_language_mode : Error<
diff --git a/clang/include/clang/Driver/Multilib.h b/clang/include/clang/Driver/Multilib.h
index 333b1d2b555bd9..f99d4e6313ff26 100644
--- a/clang/include/clang/Driver/Multilib.h
+++ b/clang/include/clang/Driver/Multilib.h
@@ -163,6 +163,9 @@ class MultilibSet {
const_iterator begin() const { return Multilibs.begin(); }
const_iterator end() const { return Multilibs.end(); }
+ Multilib::flags_list
+ processCustomFlags(const Driver &D, const Multilib::flags_list &Flags) const;
+
/// Select compatible variants, \returns false if none are compatible
bool select(const Driver &D, const Multilib::flags_list &Flags,
llvm::SmallVectorImpl<Multilib> &) const;
diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp
index 9878a9dad78d40..cee10d36070616 100644
--- a/clang/lib/Driver/Driver.cpp
+++ b/clang/lib/Driver/Driver.cpp
@@ -2324,9 +2324,7 @@ bool Driver::HandleImmediateArgs(Compilation &C) {
}
if (C.getArgs().hasArg(options::OPT_print_multi_lib)) {
- for (const Multilib &Multilib : TC.getMultilibs())
- if (!Multilib.isError())
- llvm::outs() << Multilib << "\n";
+ llvm::outs() << TC.getMultilibs();
return false;
}
diff --git a/clang/lib/Driver/Multilib.cpp b/clang/lib/Driver/Multilib.cpp
index 81fe97517b0f91..a4a4a74a9c7ad4 100644
--- a/clang/lib/Driver/Multilib.cpp
+++ b/clang/lib/Driver/Multilib.cpp
@@ -12,6 +12,7 @@
#include "clang/Driver/Driver.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Error.h"
@@ -95,9 +96,113 @@ MultilibSet &MultilibSet::FilterOut(FilterCallback F) {
void MultilibSet::push_back(const Multilib &M) { Multilibs.push_back(M); }
+static void WarnUnclaimedMultilibCustomFlags(
+ const Driver &D, const SmallVector<StringRef> &UnclaimedCustomFlagValues,
+ const SmallVector<custom_flag::CustomFlagDeclarationPtr> &CustomFlagDecls) {
+ struct EditDistanceInfo {
+ StringRef FlagValue;
+ unsigned EditDistance;
+ };
+ const unsigned MaxEditDistance = 5;
+
+ for (StringRef Unclaimed : UnclaimedCustomFlagValues) {
+ std::optional<EditDistanceInfo> BestCandidate;
+ for (const auto &Decl : CustomFlagDecls) {
+ for (const auto &Value : Decl->ValueList) {
+ const std::string &FlagValueName = Value.Name;
+ unsigned EditDistance =
+ Unclaimed.edit_distance(FlagValueName, /*AllowReplacements=*/true,
+ /*MaxEditDistance=*/MaxEditDistance);
+ if (!BestCandidate || (EditDistance <= MaxEditDistance &&
+ EditDistance < BestCandidate->EditDistance)) {
+ BestCandidate = {FlagValueName, EditDistance};
+ }
+ }
+ }
+ if (!BestCandidate)
+ D.Diag(clang::diag::warn_drv_unsupported_opt)
+ << (custom_flag::Prefix + Unclaimed).str();
+ else
+ D.Diag(clang::diag::warn_drv_unsupported_opt_with_suggestion)
+ << (custom_flag::Prefix + Unclaimed).str()
+ << (custom_flag::Prefix + BestCandidate->FlagValue).str();
+ }
+}
+
+namespace clang::driver::custom_flag {
+class ValueNameToDetailMap {
+ SmallVector<std::pair<StringRef, const CustomFlagValueDetail *>> Mapping;
+
+public:
+ template <typename It>
+ ValueNameToDetailMap(It FlagDeclsBegin, It FlagDeclsEnd) {
+ for (auto DeclIt = FlagDeclsBegin; DeclIt != FlagDeclsEnd; ++DeclIt) {
+ const CustomFlagDeclarationPtr &Decl = *DeclIt;
+ for (const auto &Value : Decl->ValueList)
+ Mapping.emplace_back(Value.Name, &Value);
+ }
+ }
+
+ const CustomFlagValueDetail *get(StringRef Key) const {
+ auto Iter = llvm::find_if(
+ Mapping, [&](const auto &Pair) { return Pair.first == Key; });
+ return Iter != Mapping.end() ? Iter->second : nullptr;
+ }
+};
+} // namespace clang::driver::custom_flag
+
+Multilib::flags_list
+MultilibSet::processCustomFlags(const Driver &D,
+ const Multilib::flags_list &Flags) const {
+ Multilib::flags_list Result;
+ SmallVector<const custom_flag::CustomFlagValueDetail *>
+ ClaimedCustomFlagValues;
+ SmallVector<StringRef> UnclaimedCustomFlagValueStrs;
+
+ const auto ValueNameToValueDetail = custom_flag::ValueNameToDetailMap(
+ CustomFlagDecls.begin(), CustomFlagDecls.end());
+
+ for (StringRef Flag : Flags) {
+ if (!Flag.starts_with(custom_flag::Prefix)) {
+ Result.push_back(Flag.str());
+ continue;
+ }
+
+ StringRef CustomFlagValueStr = Flag.substr(custom_flag::Prefix.size());
+ const custom_flag::CustomFlagValueDetail *Detail =
+ ValueNameToValueDetail.get(CustomFlagValueStr);
+ if (Detail)
+ ClaimedCustomFlagValues.push_back(Detail);
+ else
+ UnclaimedCustomFlagValueStrs.push_back(CustomFlagValueStr);
+ }
+
+ llvm::SmallSet<custom_flag::CustomFlagDeclarationPtr, 32>
+ TriggeredCustomFlagDecls;
+
+ for (auto *CustomFlagValue : llvm::reverse(ClaimedCustomFlagValues)) {
+ if (!TriggeredCustomFlagDecls.insert(CustomFlagValue->Decl).second)
+ continue;
+ Result.push_back(std::string(custom_flag::Prefix) + CustomFlagValue->Name);
+ }
+
+ for (const auto &Decl : CustomFlagDecls) {
+ if (TriggeredCustomFlagDecls.contains(Decl))
+ continue;
+ Result.push_back(std::string(custom_flag::Prefix) +
+ Decl->ValueList[Decl->DefaultValueIdx].Name);
+ }
+
+ WarnUnclaimedMultilibCustomFlags(D, UnclaimedCustomFlagValueStrs,
+ CustomFlagDecls);
+
+ return Result;
+}
+
bool MultilibSet::select(const Driver &D, const Multilib::flags_list &Flags,
llvm::SmallVectorImpl<Multilib> &Selected) const {
- llvm::StringSet<> FlagSet(expandFlags(Flags));
+ Multilib::flags_list FlagsWithCustom = processCustomFlags(D, Flags);
+ llvm::StringSet<> FlagSet(expandFlags(FlagsWithCustom));
Selected.clear();
bool AnyErrors = false;
@@ -393,8 +498,34 @@ LLVM_DUMP_METHOD void MultilibSet::dump() const {
}
void MultilibSet::print(raw_ostream &OS) const {
- for (const auto &M : *this)
- OS << M << "\n";
+ const auto ValueNameToValueDetail = custom_flag::ValueNameToDetailMap(
+ CustomFlagDecls.begin(), CustomFlagDecls.end());
+
+ for (const auto &M : *this) {
+ if (M.isError())
+ continue;
+ llvm::SmallString<128> Buf;
+ llvm::raw_svector_ostream StrOS(Buf);
+
+ M.print(StrOS);
+
+ for (StringRef Flag : M.flags()) {
+ if (!Flag.starts_with(custom_flag::Prefix))
+ continue;
+
+ StringRef CustomFlagValueStr = Flag.substr(custom_flag::Prefix.size());
+ const custom_flag::CustomFlagValueDetail *Detail =
+ ValueNameToValueDetail.get(CustomFlagValueStr);
+
+ if (!Detail || !Detail->ExtraBuildArgs)
+ continue;
+
+ for (StringRef Arg : *Detail->ExtraBuildArgs)
+ StrOS << '@' << (Arg[0] == '-' ? Arg.substr(1) : Arg);
+ }
+
+ OS << StrOS.str() << '\n';
+ }
}
raw_ostream &clang::driver::operator<<(raw_ostream &OS, const MultilibSet &MS) {
diff --git a/clang/test/Driver/baremetal-multilib-custom-flags.yaml b/clang/test/Driver/baremetal-multilib-custom-flags.yaml
new file mode 100644
index 00000000000000..3a19951c741247
--- /dev/null
+++ b/clang/test/Driver/baremetal-multilib-custom-flags.yaml
@@ -0,0 +1,57 @@
+# RUN: %clang --multi-lib-config=%s -no-canonical-prefixes -x c %s -### -o /dev/null 2>&1 \
+# RUN: --target=thumbv8m.main-none-eabi -mfpu=none --sysroot= \
+# RUN: | FileCheck --check-prefix=CHECK-DEFAULT %s
+
+# CHECK-DEFAULT: "-cc1" "-triple" "thumbv8m.main-unknown-none-eabi"
+# CHECK-DEFAULT-SAME: "-internal-isystem" "[[SYSROOT:[^"]*]]/bin/../lib/clang-runtimes/arm-none-eabi/thumb/v8-m.main/nofp/include"
+# CHECK-DEFAULT-NEXT: "-L[[SYSROOT]]/bin/../lib/clang-runtimes/arm-none-eabi/thumb/v8-m.main/nofp/lib"
+
+# RUN: %clang --multi-lib-config=%s -no-canonical-prefixes -x c %s -### -o /dev/null 2>&1 \
+# RUN: --target=thumbv8m.main-none-eabi -mfpu=none -fmultilib-flag=no-multithreaded --sysroot= \
+# RUN: | FileCheck --check-prefix=CHECK-NOMULTI %s
+
+# CHECK-NOMULTI: "-cc1" "-triple" "thumbv8m.main-unknown-none-eabi"
+# CHECK-NOMULTI-SAME: "-internal-isystem" "[[SYSROOT:[^"]*]]/bin/../lib/clang-runtimes/arm-none-eabi/thumb/v8-m.main/nofp/include"
+# CHECK-NOMULTI-NEXT: "-L[[SYSROOT]]/bin/../lib/clang-runtimes/arm-none-eabi/thumb/v8-m.main/nofp/lib"
+
+# RUN: %clang --multi-lib-config=%s -no-canonical-prefixes -x c %s -### -o /dev/null 2>&1 \
+# RUN: --target=thumbv8m.main-none-eabi -mfpu=none -fmultilib-flag=multithreaded --sysroot= \
+# RUN: | FileCheck --check-prefix=CHECK-MULTI %s
+
+# CHECK-MULTI: "-cc1" "-triple" "thumbv8m.main-unknown-none-eabi"
+# CHECK-MULTI-SAME: "-internal-isystem" "[[SYSROOT:[^"]*]]/bin/../lib/clang-runtimes/arm-none-eabi/multithreaded/thumb/v8-m.main/nofp/include"
+# CHECK-MULTI-NEXT: "-L[[SYSROOT]]/bin/../lib/clang-runtimes/arm-none-eabi/multithreaded/thumb/v8-m.main/nofp/lib"
+
+# RUN: %clang --multi-lib-config=%s -no-canonical-prefixes -x c %s -### -o /dev/null 2>&1 \
+# RUN: --target=thumbv8m.main-none-eabi -mfpu=none -fmultilib-flag=singlethreaded -fmultilib-flag=no-io --sysroot= \
+# RUN: | FileCheck --check-prefix=CHECK-WARNING %s
+# CHECK-WARNING-DAG: warning: unsupported option '-fmultilib-flag=singlethreaded'
+# CHECK-WARNING-DAG: warning: unsupported option '-fmultilib-flag=no-io'; did you mean '-fmultilib-flag=io-none'?
+
+---
+MultilibVersion: 1.0
+
+Groups:
+- Name: stdlib
+ Type: Exclusive
+
+Variants:
+- Dir: arm-none-eabi/thumb/v8-m.main/nofp
+ Flags: [--target=thumbv8m.main-unknown-none-eabi, -mfpu=none, -fmultilib-flag=no-multithreaded]
+ Group: stdlib
+- Dir: arm-none-eabi/multithreaded/thumb/v8-m.main/nofp
+ Flags: [--target=thumbv8m.main-unknown-none-eabi, -mfpu=none, -fmultilib-flag=multithreaded]
+ Group: stdlib
+
+Flags:
+ - Name: multithreading
+ Values:
+ - Name: no-multithreaded
+ - Name: multithreaded
+ Default: no-multithreaded
+ - Name: io
+ Values:
+ - Name: io-none
+ - Name: io-semihosting
+ - Name: io-linux-syscalls
+ Default: io-none
\ No newline at end of file
``````````
</details>
https://github.com/llvm/llvm-project/pull/110659
More information about the llvm-branch-commits
mailing list