llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Aviral Goel (aviralg) <details> <summary>Changes</summary> This change introduces support for linking static libraries and multi-arch static libraries. To implement this, we have added two `link` overloads to the `EntityLinker`: a static library folds in as a bundle of TU summaries, and a multi-arch static library contributes only the static library with the matching target triple. The target triple is supplied through a new optional flag, `--target-triple`. If unspecified, it is inferred from the first input, if possible. rdar://184656074 --- Patch is 70.51 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/215349.diff 21 Files Affected: - (modified) clang/include/clang/ScalableStaticAnalysis/Core/EntityLinker/EntityLinker.h (+51-5) - (modified) clang/include/clang/ScalableStaticAnalysis/Core/EntityLinker/MultiArchStaticLibrary.h (+3) - (modified) clang/include/clang/ScalableStaticAnalysis/Core/EntityLinker/StaticLibrary.h (+9-3) - (modified) clang/include/clang/ScalableStaticAnalysis/Core/Support/FormatProviders.h (+8) - (modified) clang/include/clang/ScalableStaticAnalysis/Tool/Utils.h (+14) - (modified) clang/lib/ScalableStaticAnalysis/Core/EntityLinker/EntityLinker.cpp (+78) - (modified) clang/lib/ScalableStaticAnalysis/Tool/Utils.cpp (+21) - (added) clang/test/Analysis/Scalable/ssaf-linker/Inputs/libord-reversed.json (+62) - (added) clang/test/Analysis/Scalable/ssaf-linker/Inputs/libtwo-2arch.json (+39) - (added) clang/test/Analysis/Scalable/ssaf-linker/Inputs/tu-linux.json (+11) - (added) clang/test/Analysis/Scalable/ssaf-linker/Inputs/tu-x86_64.json (+11) - (modified) clang/test/Analysis/Scalable/ssaf-linker/help.test (+12-11) - (modified) clang/test/Analysis/Scalable/ssaf-linker/io.test (+10-2) - (modified) clang/test/Analysis/Scalable/ssaf-linker/linking-errors.test (+119-6) - (modified) clang/test/Analysis/Scalable/ssaf-linker/linking.test (+137) - (modified) clang/test/Analysis/Scalable/ssaf-linker/time.test (+3-3) - (modified) clang/test/Analysis/Scalable/ssaf-linker/verbose.test (+47-6) - (modified) clang/tools/clang-ssaf-linker/CMakeLists.txt (+1) - (added) clang/tools/clang-ssaf-linker/LinkCLI.cpp (+295) - (added) clang/tools/clang-ssaf-linker/LinkCLI.h (+111) - (modified) clang/tools/clang-ssaf-linker/SSAFLinker.cpp (+16-118) ``````````diff diff --git a/clang/include/clang/ScalableStaticAnalysis/Core/EntityLinker/EntityLinker.h b/clang/include/clang/ScalableStaticAnalysis/Core/EntityLinker/EntityLinker.h index f07def1a9b344..2df3ad1c9cf3c 100644 --- a/clang/include/clang/ScalableStaticAnalysis/Core/EntityLinker/EntityLinker.h +++ b/clang/include/clang/ScalableStaticAnalysis/Core/EntityLinker/EntityLinker.h @@ -8,6 +8,8 @@ // // This file defines the EntityLinker class that combines multiple TU summaries // into a unified LU summary by deduplicating entities and patching summaries. +// TU summaries may be supplied individually, bundled in a static library, or +// bundled in one architecture member of a multi-architecture static library. // //===----------------------------------------------------------------------===// @@ -17,6 +19,7 @@ #include "clang/ScalableStaticAnalysis/Core/EntityLinker/LUSummaryEncoding.h" #include "llvm/Support/Error.h" #include "llvm/TargetParser/Triple.h" +#include <cstddef> #include <map> #include <memory> #include <set> @@ -24,17 +27,22 @@ namespace clang::ssaf { +class MultiArchStaticLibrary; +class StaticLibrary; class TUSummaryEncoding; class EntityLinker { LUSummaryEncoding Output; + + // Namespaces of the TU summaries folded in, supplied directly or as members + // of a library. std::set<BuildNamespace> ProcessedTUNamespaces; public: /// Constructs an EntityLinker to link TU summaries into a LU summary. /// - /// \param TargetTriple The target triple of the link unit. Every linked TU - /// must report the same triple. + /// \param TargetTriple The target triple of the link unit. Every linked + /// input must report the same triple. /// \param LUNamespace The namespace identifying this link unit. EntityLinker(llvm::Triple TargetTriple, NestedBuildNamespace LUNamespace) : Output(std::move(TargetTriple), std::move(LUNamespace)) {} @@ -45,11 +53,40 @@ class EntityLinker { /// and merges them into a single data store. /// /// \param Summary The TU summary to link. Ownership is transferred. - /// \returns Error if the TU namespace has already been linked or if patching - /// fails, success otherwise. Corrupted summary data (missing linkage - /// information, duplicate entity IDs, etc.) triggers a fatal error. + /// \returns Error if \p Summary reports a different target triple than this + /// link unit, if its TU namespace has already been linked, or if + /// patching fails; success otherwise. Corrupted summary data + /// (missing linkage information, duplicate entity IDs, etc.) + /// triggers a fatal error. llvm::Error link(std::unique_ptr<TUSummaryEncoding> Summary); + /// Links every member of a static library into the LU summary. + /// + /// Members are folded in unconditionally, in an unspecified order, exactly as + /// if each had been passed as an individual TU summary. + /// + /// \param Library The static library to link. Ownership is transferred. + /// \returns Error if \p Library reports a different target triple than this + /// link unit or if any member fails to link, success otherwise. + llvm::Error link(std::unique_ptr<StaticLibrary> Library); + + /// Links the architecture member matching this link unit into the LU summary. + /// + /// Members for other architectures are discarded. + /// + /// \param Library The multi-arch static library to link. Ownership is + /// transferred. + /// \returns Error if \p Library has no member whose target triple equals this + /// link unit's, or if the selected member fails to link; success + /// otherwise. + llvm::Error link(std::unique_ptr<MultiArchStaticLibrary> Library); + + /// Returns the number of TU summaries folded in so far. + /// + /// Counts members expanded from libraries as well as TU summaries linked + /// directly, so it is not the number of link() calls. + size_t getLinkedTUCount() const { return ProcessedTUNamespaces.size(); } + /// Returns the accumulated LU summary. /// /// \returns LU summary containing all the deduplicated and patched entity @@ -57,6 +94,15 @@ class EntityLinker { LUSummaryEncoding takeOutput() && { return std::move(Output); } private: + /// Checks that an input belongs to this link unit's target. + /// + /// \param TargetTriple The triple of the input being linked. + /// \param InputNamespace The namespace naming that input in the diagnostic. + /// \returns Error if \p TargetTriple differs from this link unit's, success + /// otherwise. + llvm::Error checkTargetTriple(const llvm::Triple &TargetTriple, + const BuildNamespace &InputNamespace) const; + /// Resolves a TU entity name to an LU entity name and ID. /// /// \param OldName The entity name in the TU namespace. diff --git a/clang/include/clang/ScalableStaticAnalysis/Core/EntityLinker/MultiArchStaticLibrary.h b/clang/include/clang/ScalableStaticAnalysis/Core/EntityLinker/MultiArchStaticLibrary.h index f5ddafbb9d577..b900d5458e9b5 100644 --- a/clang/include/clang/ScalableStaticAnalysis/Core/EntityLinker/MultiArchStaticLibrary.h +++ b/clang/include/clang/ScalableStaticAnalysis/Core/EntityLinker/MultiArchStaticLibrary.h @@ -23,6 +23,7 @@ namespace clang::ssaf { +class LinkCLI; class MultiArchCreateCLI; /// Represents a multi-architecture static library. @@ -32,6 +33,8 @@ class MultiArchCreateCLI; /// architectures; the wrapper's \c Namespace identifies that shared library and /// every member's namespace must agree on its name. class MultiArchStaticLibrary { + friend class EntityLinker; + friend class LinkCLI; friend class MultiArchCreateCLI; friend class SerializationFormat; friend class TestFixture; diff --git a/clang/include/clang/ScalableStaticAnalysis/Core/EntityLinker/StaticLibrary.h b/clang/include/clang/ScalableStaticAnalysis/Core/EntityLinker/StaticLibrary.h index c74fc4b16e0b2..db1477a42e9b5 100644 --- a/clang/include/clang/ScalableStaticAnalysis/Core/EntityLinker/StaticLibrary.h +++ b/clang/include/clang/ScalableStaticAnalysis/Core/EntityLinker/StaticLibrary.h @@ -23,6 +23,7 @@ namespace clang::ssaf { +class LinkCLI; class MultiArchCreateCLI; class StaticLibraryCreateCLI; @@ -30,8 +31,8 @@ class StaticLibraryCreateCLI; /// /// A StaticLibrary bundles member translation units without performing /// entity resolution, mirroring the role of ar / libtool -static / lib.exe -/// in native build pipelines. It is consumed by the EntityLinker for -/// selective inclusion when passed as a command line argument. +/// in native build pipelines. It is consumed by the EntityLinker when passed +/// as a command line argument. /// /// Static libraries are single-architecture: every member's target triple /// must equal the library's. Multi-architecture static libraries are @@ -40,8 +41,13 @@ class StaticLibraryCreateCLI; /// /// Members are stored as encoded TUSummaryEncoding objects: the /// static-library tool never decodes per-entity payloads, and the linker -/// consumes them as-is during its selective inclusion pass. +/// consumes them as-is while folding them into its link unit. +/// +/// TODO: The linker currently folds in every member. Restrict inclusion to +/// the members a link unit actually references, as native linkers do. class StaticLibrary { + friend class EntityLinker; + friend class LinkCLI; friend class MultiArchCreateCLI; friend class MultiArchStaticLibrary; friend class SerializationFormat; diff --git a/clang/include/clang/ScalableStaticAnalysis/Core/Support/FormatProviders.h b/clang/include/clang/ScalableStaticAnalysis/Core/Support/FormatProviders.h index e4a7b54033924..e671a7c2d088a 100644 --- a/clang/include/clang/ScalableStaticAnalysis/Core/Support/FormatProviders.h +++ b/clang/include/clang/ScalableStaticAnalysis/Core/Support/FormatProviders.h @@ -22,6 +22,7 @@ #include "clang/ScalableStaticAnalysis/Core/WholeProgramAnalysis/AnalysisName.h" #include "llvm/Support/FormatProviders.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/TargetParser/Triple.h" namespace llvm { @@ -88,6 +89,13 @@ template <> struct format_provider<clang::ssaf::AnalysisName> { } }; +template <> struct format_provider<llvm::Triple> { + static void format(const llvm::Triple &Val, raw_ostream &OS, + StringRef Style) { + OS << llvm::Triple::normalize(Val.str()); + } +}; + } // namespace llvm #endif // LLVM_CLANG_SCALABLESTATICANALYSIS_CORE_SUPPORT_FORMATPROVIDERS_H diff --git a/clang/include/clang/ScalableStaticAnalysis/Tool/Utils.h b/clang/include/clang/ScalableStaticAnalysis/Tool/Utils.h index 8ceb539a055de..9c82a2de0608c 100644 --- a/clang/include/clang/ScalableStaticAnalysis/Tool/Utils.h +++ b/clang/include/clang/ScalableStaticAnalysis/Tool/Utils.h @@ -23,6 +23,7 @@ #include "llvm/Support/Error.h" #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/WithColor.h" +#include "llvm/TargetParser/Triple.h" #include <string> namespace clang::ssaf { @@ -76,6 +77,19 @@ void loadPlugins(llvm::ArrayRef<std::string> Paths); void initTool(int argc, const char **argv, llvm::StringRef Version, llvm::cl::OptionCategory &Category, llvm::StringRef ToolHeading); +//===----------------------------------------------------------------------===// +// Target Triples +//===----------------------------------------------------------------------===// + +/// Parses and validates a target triple supplied on the command line. +/// +/// \param FlagName The option supplying \p Value, named in the diagnostic. +/// \param Value The triple as spelled by the user. Must not be empty. +/// \returns The parsed triple. Calls fail() and exits if the architecture is +/// unrecognized. +llvm::Triple parseTargetTripleOrFail(llvm::StringRef FlagName, + llvm::StringRef Value); + //===----------------------------------------------------------------------===// // Data Structures //===----------------------------------------------------------------------===// diff --git a/clang/lib/ScalableStaticAnalysis/Core/EntityLinker/EntityLinker.cpp b/clang/lib/ScalableStaticAnalysis/Core/EntityLinker/EntityLinker.cpp index 462978932a53d..b703efd8324fb 100644 --- a/clang/lib/ScalableStaticAnalysis/Core/EntityLinker/EntityLinker.cpp +++ b/clang/lib/ScalableStaticAnalysis/Core/EntityLinker/EntityLinker.cpp @@ -8,11 +8,15 @@ #include "clang/ScalableStaticAnalysis/Core/EntityLinker/EntityLinker.h" #include "clang/ScalableStaticAnalysis/Core/EntityLinker/EntitySummaryEncoding.h" +#include "clang/ScalableStaticAnalysis/Core/EntityLinker/MultiArchStaticLibrary.h" +#include "clang/ScalableStaticAnalysis/Core/EntityLinker/StaticLibrary.h" #include "clang/ScalableStaticAnalysis/Core/EntityLinker/TUSummaryEncoding.h" #include "clang/ScalableStaticAnalysis/Core/Model/EntityLinkage.h" #include "clang/ScalableStaticAnalysis/Core/Model/EntityName.h" #include "clang/ScalableStaticAnalysis/Core/Support/ErrorBuilder.h" #include "clang/ScalableStaticAnalysis/Core/Support/FormatProviders.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringExtras.h" #include <cassert> using namespace clang::ssaf; @@ -44,6 +48,16 @@ static constexpr const char *FailedToInsertEntityIntoOutputSummary = static constexpr const char *DuplicateTUNamespace = "failed to link TU summary: duplicate {0}"; +static constexpr const char *LinkingStaticLibraryMember = + "failed to link member {0} of static library {1}"; + +static constexpr const char *MismatchedTargetTriple = + "target triple '{0}' of {1} does not match link unit target triple '{2}'"; + +static constexpr const char *NoMemberForTargetTriple = + "multi-arch static library {0} has no member for target triple '{1}' " + "(available: {2})"; + } // namespace ErrorMessages static NestedBuildNamespace @@ -180,7 +194,25 @@ EntityLinker::patch(const std::vector<EntitySummaryEncoding *> &PatchTargets, return llvm::Error::success(); } +llvm::Error +EntityLinker::checkTargetTriple(const llvm::Triple &TargetTriple, + const BuildNamespace &InputNamespace) const { + if (TargetTriple != Output.TargetTriple) { + return ErrorBuilder::create(std::errc::invalid_argument, + ErrorMessages::MismatchedTargetTriple, + TargetTriple, InputNamespace, + Output.TargetTriple) + .build(); + } + return llvm::Error::success(); +} + llvm::Error EntityLinker::link(std::unique_ptr<TUSummaryEncoding> Summary) { + if (auto Err = + checkTargetTriple(Summary->TargetTriple, Summary->TUNamespace)) { + return Err; + } + auto [_, Inserted] = ProcessedTUNamespaces.insert(Summary->TUNamespace); if (!Inserted) { return ErrorBuilder::create(std::errc::invalid_argument, @@ -195,3 +227,49 @@ llvm::Error EntityLinker::link(std::unique_ptr<TUSummaryEncoding> Summary) { auto PatchTargets = merge(SummaryRef, EntityResolutionTable); return patch(PatchTargets, EntityResolutionTable); } + +llvm::Error EntityLinker::link(std::unique_ptr<StaticLibrary> Library) { + if (auto Err = checkTargetTriple(Library->TargetTriple, Library->Namespace)) { + return Err; + } + + while (!Library->Members.empty()) { + auto Node = Library->Members.extract(Library->Members.begin()); + const BuildNamespace MemberNamespace = Node.value()->TUNamespace; + + if (auto Err = link(std::move(Node.value()))) { + return ErrorBuilder::wrap(std::move(Err)) + .context(ErrorMessages::LinkingStaticLibraryMember, MemberNamespace, + Library->Namespace) + .build(); + } + } + + return llvm::Error::success(); +} + +llvm::Error +EntityLinker::link(std::unique_ptr<MultiArchStaticLibrary> Library) { + auto MatchingMember = llvm::find_if( + Library->Members, [this](const std::unique_ptr<StaticLibrary> &Member) { + return Member->TargetTriple == Output.TargetTriple; + }); + + if (MatchingMember == Library->Members.end()) { + auto TargetTriples = llvm::map_range( + Library->Members, [](const std::unique_ptr<StaticLibrary> &Member) { + return llvm::Triple::normalize(Member->TargetTriple.str()); + }); + std::string Available = Library->Members.empty() + ? std::string("none") + : llvm::join(TargetTriples, ", "); + + return ErrorBuilder::create(std::errc::invalid_argument, + ErrorMessages::NoMemberForTargetTriple, + Library->Namespace, Output.TargetTriple, + Available) + .build(); + } + + return link(std::move(Library->Members.extract(MatchingMember).value())); +} diff --git a/clang/lib/ScalableStaticAnalysis/Tool/Utils.cpp b/clang/lib/ScalableStaticAnalysis/Tool/Utils.cpp index 6a740f57741d7..03139f378186f 100644 --- a/clang/lib/ScalableStaticAnalysis/Tool/Utils.cpp +++ b/clang/lib/ScalableStaticAnalysis/Tool/Utils.cpp @@ -56,6 +56,9 @@ constexpr const char *FileAlreadyExists = "File already exists"; constexpr const char *FailedToLoadPlugin = "failed to load plugin '{0}': {1}"; +constexpr const char *InvalidTargetTriple = + "invalid {0} '{1}': unrecognized architecture"; + } // namespace ErrorMessages llvm::StringRef ToolName; @@ -148,6 +151,24 @@ void clang::ssaf::loadPlugins(llvm::ArrayRef<std::string> Paths) { } } +llvm::Triple clang::ssaf::parseTargetTripleOrFail(llvm::StringRef FlagName, + llvm::StringRef Value) { + assert(!Value.empty() && + "parseTargetTripleOrFail: triple value cannot be empty"); + + // Normalize so the components are moved to their proper places. + llvm::Triple T(llvm::Triple::normalize(Value)); + + // Only the architecture is validated. Validating vendor or OS rejects real + // targets like x86_64-unknown-linux-gnu. A misspelled vendor or OS is instead + // caught as a triple mismatch during linking or library creation. + if (T.getArch() == llvm::Triple::UnknownArch) { + fail(ErrorMessages::InvalidTargetTriple, FlagName, Value); + } + + return T; +} + void clang::ssaf::initTool(int argc, const char **argv, llvm::StringRef Version, llvm::cl::OptionCategory &Category, llvm::StringRef ToolHeading) { diff --git a/clang/test/Analysis/Scalable/ssaf-linker/Inputs/libord-reversed.json b/clang/test/Analysis/Scalable/ssaf-linker/Inputs/libord-reversed.json new file mode 100644 index 0000000000000..0356200cb9aa5 --- /dev/null +++ b/clang/test/Analysis/Scalable/ssaf-linker/Inputs/libord-reversed.json @@ -0,0 +1,62 @@ +{ + "members": [ + { + "data": [], + "id_table": [ + { + "id": 0, + "name": { + "suffix": "", + "usr": "c:@F@only_in_b#" + } + } + ], + "linkage_table": [ + { + "id": 0, + "linkage": { + "type": "Internal" + } + } + ], + "target_triple": "arm64-apple-macosx", + "tu_namespace": { + "kind": "CompilationUnit", + "name": "tu-b.cpp" + }, + "type": "TUSummary" + }, + { + "data": [], + "id_table": [ + { + "id": 0, + "name": { + "suffix": "", + "usr": "c:@F@only_in_a#" + } + } + ], + "linkage_table": [ + { + "id": 0, + "linkage": { + "type": "Internal" + } + } + ], + "target_triple": "arm64-apple-macosx", + "tu_namespace": { + "kind": "CompilationUnit", + "name": "tu-a.cpp" + }, + "type": "TUSummary" + } + ], + "namespace": { + "kind": "StaticLibrary", + "name": "libord" + }, + "target_triple": "arm64-apple-macosx", + "type": "StaticLibrary" +} diff --git a/clang/test/Analysis/Scalable/ssaf-linker/Inputs/libtwo-2arch.json b/clang/test/Analysis/Scalable/ssaf-linker/Inputs/libtwo-2arch.json new file mode 100644 index 0000000000000..c52597151dae3 --- /dev/null +++ b/clang/test/Analysis/Scalable/ssaf-linker/Inputs/libtwo-2arch.json @@ -0,0 +1,39 @@ +{ + "members": [ + { + "members": [], + "namespace": { + "kind": "StaticLibrary", + "name": "libtwo" + }, + "target_triple": "arm64-apple-macosx", + "type": "StaticLibrary" + }, + { + "members": [ + { + "data": [], + "id_table": [], + "linkage_table": [], + "target_triple": "x86_64-apple-macosx", + "tu_namespace": { + "kind": "CompilationUnit", + "name": "x86.cpp" + }, + "type": "TUSummary" + } + ], + "namespace": { + "kind": "StaticLibrary", + "name": "libtwo" + }, + "target_triple": "x86_64-apple-macosx", + "type": "StaticLibrary" + } + ], + "namespace": { + "kind": "MultiArchStaticLibrary", + "name": "libtwo" + }, + "type": "MultiArchStaticLibrary" +} diff --git a/clang/test/Analysis/Scalable/ssaf-linker/Inputs/tu-linux.json b/clang/test/Analysis/Scalable/ssaf-linker/Inputs/tu-linux.json new file mode 100644 index 0000000000000..9bf5495c9e2f1 --- /dev/null +++ b/clang/test/Analysis/Scalable/ssaf-linker/Inputs/tu-linux.json @@ -0,0 +1,11 @@ +{ + "tu_namespace": { + "kind": "CompilationUnit", + "name": "linux.cpp" + }, + "id_table": [], + "linkage_table": [], + "data": [], + "target_triple": "x86_64-unknown-linux-gnu", + "type": "TUSummary" +} diff --git a/clang/test/Analysis/Scalable/ssaf-linker/Inputs/tu-x86_64.json b/clang/test/Analysis/Scalable/ssaf-linker/Inputs/tu-x86_64.json new file mode 100644 index 0000000000000..a482c204f77c7 --- /dev/null +++ b/clang/test/Analysis/Scalable/ssaf-linker/Inputs/tu-x86_64.json @@ -0,0 +1,11 @@ +{ + "tu_namespace": { + "kind": "CompilationUnit", + "name": "x86.cpp" + }, + "id_table": [], + "linkage_table": [], + "data": [], + "target_triple": "x86_64-apple-macosx", + "type": "TUSummary" +} diff --git a/clang/test/Analysis/Scalable/ssaf-linker/help.test b/clang/test/Analysis/Scalable/ssaf-linker/help.test index 7b0c21f066016..45d8e11a15e... [truncated] `````````` </details> https://github.com/llvm/llvm-project/pull/215349 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
