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 _______________________________________________ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits