From 3885d8da3a7ab56649c39afdd3c5f59fe6bd8b1a Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Fri, 3 Jul 2020 10:17:22 +0900 Subject: [PATCH 01/77] Implement Serialization --- include/swift/SIL/ModuleSummary.h | 75 ++++++++++++++ .../swift/Serialization/ModuleSummaryFile.h | 43 ++++++++ lib/SIL/Utils/CMakeLists.txt | 1 + lib/SIL/Utils/ModuleSummaryIndex.cpp | 66 +++++++++++++ lib/Serialization/CMakeLists.txt | 1 + lib/Serialization/ModuleSummaryFile.cpp | 97 +++++++++++++++++++ 6 files changed, 283 insertions(+) create mode 100644 include/swift/SIL/ModuleSummary.h create mode 100644 include/swift/Serialization/ModuleSummaryFile.h create mode 100644 lib/SIL/Utils/ModuleSummaryIndex.cpp create mode 100644 lib/Serialization/ModuleSummaryFile.cpp diff --git a/include/swift/SIL/ModuleSummary.h b/include/swift/SIL/ModuleSummary.h new file mode 100644 index 0000000000000..d57b5231da007 --- /dev/null +++ b/include/swift/SIL/ModuleSummary.h @@ -0,0 +1,75 @@ +#include "swift/AST/Decl.h" +#include "swift/SIL/SILDeclRef.h" + +namespace swift { + +using GUID = uint64_t; +GUID getGUID(llvm::StringRef Str) { return llvm::MD5Hash(Str); } + +class FunctionSummary { +public: + class EdgeTy { + public: + GUID CalleeFnOrTable; + enum class Kind { + Static, + Witness, + VTable, + kindCount, + }; + + Kind kind; + + EdgeTy(SILDeclRef CalleeFn, Kind kind) : kind(kind) { + // FIXME + auto name = CalleeFn.getDecl()->getBaseName().getIdentifier().str(); + this->CalleeFnOrTable = getGUID(name); + } + + public: + Kind getKind() const { return kind; } + + EdgeTy(GUID callee, Kind kind) : CalleeFnOrTable(callee), kind(kind) {} + + static EdgeTy staticCall(GUID Callee) { + return EdgeTy(Callee, Kind::Static); + } + static EdgeTy witnessCall(GUID Callee) { + return EdgeTy(Callee, Kind::Witness); + } + static EdgeTy vtableCall(GUID Callee) { + return EdgeTy(Callee, Kind::VTable); + } + static EdgeTy witnessCall(SILDeclRef Callee) { + return EdgeTy(Callee, Kind::Witness); + } + static EdgeTy vtableCall(SILDeclRef Callee) { + return EdgeTy(Callee, Kind::VTable); + } + }; + +private: + std::vector CallGraphEdgeList; + +public: + FunctionSummary(std::vector CGEdges) + : CallGraphEdgeList(std::move(CGEdges)) {} + FunctionSummary() = default; + + void addCall(GUID targetGUID, EdgeTy::Kind kind) { + CallGraphEdgeList.emplace_back(targetGUID, kind); + } +}; + +class ModuleSummaryIndex { + std::map> FunctionSummaryMap; + +public: + ModuleSummaryIndex() = default; + + void addFunctionSummary(GUID guid, std::unique_ptr summary) { + FunctionSummaryMap.insert(std::make_pair(guid, std::move(summary))); + } +}; + +}; // namespace swift diff --git a/include/swift/Serialization/ModuleSummaryFile.h b/include/swift/Serialization/ModuleSummaryFile.h new file mode 100644 index 0000000000000..b39778909135e --- /dev/null +++ b/include/swift/Serialization/ModuleSummaryFile.h @@ -0,0 +1,43 @@ +#ifndef SWIFT_SERIALIZATION_MODULE_SUMMARY_FILE_H +#define SWIFT_SERIALIZATION_MODULE_SUMMARY_FILE_H + +#include "swift/SIL/ModuleSummary.h" +#include "llvm/Bitcode/RecordLayout.h" +#include "llvm/Support/MemoryBuffer.h" +#include + +namespace swift { + +namespace modulesummary { + +enum BlockID { + MODULE_BLOCK_ID = llvm::bitc::FIRST_APPLICATION_BLOCKID, + + CONTROL_BLOCK_ID, + + FUNCTION_SUMMARY_ID, +}; + +namespace function_summary { +using namespace llvm; +enum { + METADATA, + CALL_GRAPH_EDGE, +}; + +using MetadataLayout = BCRecordLayout // Function GUID + >; +using CallGraphEdgeLayout = + BCRecordLayout, // FunctionSummary::Edge::Kind + BCFixed<64> // Target GUID + >; +} // namespace function_summary + +std::unique_ptr +loadModuleSummaryIndex(std::unique_ptr inputBuffer); +} // namespace modulesummary +} // namespace swift + +#endif diff --git a/lib/SIL/Utils/CMakeLists.txt b/lib/SIL/Utils/CMakeLists.txt index 503af715ecab2..97cfa008ee42b 100644 --- a/lib/SIL/Utils/CMakeLists.txt +++ b/lib/SIL/Utils/CMakeLists.txt @@ -6,6 +6,7 @@ target_sources(swiftSIL PRIVATE InstructionUtils.cpp LoopInfo.cpp MemAccessUtils.cpp + ModuleSummaryIndex.cpp OptimizationRemark.cpp OwnershipUtils.cpp PrettyStackTrace.cpp diff --git a/lib/SIL/Utils/ModuleSummaryIndex.cpp b/lib/SIL/Utils/ModuleSummaryIndex.cpp new file mode 100644 index 0000000000000..191a933ce7b78 --- /dev/null +++ b/lib/SIL/Utils/ModuleSummaryIndex.cpp @@ -0,0 +1,66 @@ +#include "swift/Demangling/Demangle.h" +#include "swift/SIL/ModuleSummary.h" +#include "swift/SIL/SILFunction.h" +#include "swift/SIL/SILModule.h" +#include "swift/SILOptimizer/Analysis/BasicCalleeAnalysis.h" +#include "swift/SILOptimizer/Analysis/FunctionOrder.h" +#include "swift/SILOptimizer/PassManager/Transforms.h" +#include "llvm/Support/MD5.h" +#include "llvm/Support/raw_ostream.h" + +#define DEBUG_TYPE "function-order-printer" + +using namespace swift; + +std::unique_ptr +buildFunctionSummaryIndex(SILFunction &F, BasicCalleeAnalysis &BCA) { + std::vector CallGraphEdgeList; + + for (auto &BB : F) { + for (auto &I : BB) { + auto FAS = FullApplySite::isa(&I); + if (!FAS) + continue; + CalleeList Callees = BCA.getCalleeList(FAS); + if (Callees.isIncomplete()) { + auto Callee = FAS.getCalleeOrigin(); + switch (Callee->getKind()) { + case ValueKind::WitnessMethodInst: { + auto WMI = cast(Callee); + auto edge = FunctionSummary::EdgeTy::witnessCall(WMI->getMember()); + CallGraphEdgeList.push_back(edge); + break; + } + case ValueKind::ClassMethodInst: { + auto CMI = cast(Callee); + auto edge = FunctionSummary::EdgeTy::vtableCall(CMI->getMember()); + CallGraphEdgeList.push_back(edge); + break; + } + default: + llvm_unreachable("invalid kind"); + } + continue; + } + + // For static calls + std::vector CalleeGUIDs; + for (auto Callee : Callees) { + auto edge = + FunctionSummary::EdgeTy::staticCall(getGUID(Callee->getName())); + CallGraphEdgeList.push_back(edge); + } + } + } + return std::make_unique(CallGraphEdgeList); +} + +ModuleSummaryIndex buildModuleSummaryIndex(SILModule &M, + BasicCalleeAnalysis &BCA) { + ModuleSummaryIndex index; + for (auto &F : M) { + auto FS = buildFunctionSummaryIndex(F, BCA); + index.addFunctionSummary(getGUID(F.getName()), std::move(FS)); + } + return index; +} diff --git a/lib/Serialization/CMakeLists.txt b/lib/Serialization/CMakeLists.txt index 9a795e3a9b64d..f06342fd8b657 100644 --- a/lib/Serialization/CMakeLists.txt +++ b/lib/Serialization/CMakeLists.txt @@ -4,6 +4,7 @@ add_swift_host_library(swiftSerialization STATIC ModuleDependencyScanner.cpp ModuleFile.cpp ModuleFileSharedCore.cpp + ModuleSummaryFile.cpp Serialization.cpp SerializedModuleLoader.cpp SerializedSILLoader.cpp diff --git a/lib/Serialization/ModuleSummaryFile.cpp b/lib/Serialization/ModuleSummaryFile.cpp new file mode 100644 index 0000000000000..3dfa39ded7cca --- /dev/null +++ b/lib/Serialization/ModuleSummaryFile.cpp @@ -0,0 +1,97 @@ +#include "swift/Serialization/ModuleSummaryFile.h" +#include "BCReadingExtras.h" +#include "memory" +#include "llvm/Bitstream/BitstreamReader.h" + +namespace swift { + +namespace modulesummary { + +static llvm::Optional +getEdgeKind(unsigned edgeKind) { + if (edgeKind < unsigned(FunctionSummary::EdgeTy::Kind::kindCount)) + return FunctionSummary::EdgeTy::Kind(edgeKind); + return None; +} + +std::unique_ptr +loadModuleSummaryIndex(std::unique_ptr inputBuffer) { + llvm::BitstreamCursor cursor{inputBuffer->getMemBufferRef()}; + + auto moduleSummary = std::make_unique(); + + while (!cursor.AtEndOfStream()) { + llvm::Expected maybeEntry = + cursor.advance(llvm::BitstreamCursor::AF_DontPopBlockAtEnd); + if (!maybeEntry) { + llvm::report_fatal_error("Should have entry"); + } + + auto entry = maybeEntry.get(); + if (entry.Kind != llvm::BitstreamEntry::SubBlock) + break; + + switch (entry.ID) { + case CONTROL_BLOCK_ID: { + if (cursor.SkipBlock()) + llvm::report_fatal_error("Can't skip block"); + break; + } + case FUNCTION_SUMMARY_ID: { + if (llvm::Error Err = cursor.EnterSubBlock(FUNCTION_SUMMARY_ID)) { + llvm::report_fatal_error("Can't enter subblock"); + } + + llvm::Expected maybeNext = cursor.advance(); + if (!maybeNext) + llvm::report_fatal_error("Should have next entry"); + + llvm::BitstreamEntry next = maybeNext.get(); + + GUID guid; + std::unique_ptr FS; + std::vector CGEdges; + + llvm::SmallVector scratch; + while (next.Kind == llvm::BitstreamEntry::Record) { + scratch.clear(); + llvm::StringRef blobData; + llvm::Expected maybeKind = + cursor.readRecord(next.ID, scratch, &blobData); + + if (!maybeKind) + llvm::report_fatal_error("Should have kind"); + + unsigned kind = maybeKind.get(); + switch (kind) { + case function_summary::METADATA: { + function_summary::MetadataLayout::readRecord(scratch, guid); + FS = std::make_unique(); + break; + } + case function_summary::CALL_GRAPH_EDGE: { + unsigned edgeKindID, targetGUID; + function_summary::CallGraphEdgeLayout::readRecord(scratch, edgeKindID, + targetGUID); + auto edgeKind = getEdgeKind(edgeKindID); + if (!edgeKind) + llvm::report_fatal_error("Bad edge kind"); + if (!FS) + llvm::report_fatal_error("Invalid state"); + + FS->addCall(targetGUID, edgeKind.getValue()); + break; + } + } + } + + moduleSummary->addFunctionSummary(guid, std::move(FS)); + } + } + } + + return moduleSummary; +} + +} // namespace modulesummary +} // namespace swift From 0fe440b6d1aba23c5d0f2bc4a1998b6744110025 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Fri, 3 Jul 2020 11:37:34 +0900 Subject: [PATCH 02/77] Implement encode --- include/swift/SIL/ModuleSummary.h | 29 +++++- .../swift/Serialization/ModuleSummaryFile.h | 8 +- lib/SIL/Utils/ModuleSummaryIndex.cpp | 2 +- lib/Serialization/ModuleSummaryFile.cpp | 93 +++++++++++++++++-- 4 files changed, 118 insertions(+), 14 deletions(-) diff --git a/include/swift/SIL/ModuleSummary.h b/include/swift/SIL/ModuleSummary.h index d57b5231da007..5d6eb6311ed52 100644 --- a/include/swift/SIL/ModuleSummary.h +++ b/include/swift/SIL/ModuleSummary.h @@ -28,6 +28,7 @@ class FunctionSummary { public: Kind getKind() const { return kind; } + GUID getCallee() const { return CalleeFnOrTable; } EdgeTy(GUID callee, Kind kind) : CalleeFnOrTable(callee), kind(kind) {} @@ -48,8 +49,10 @@ class FunctionSummary { } }; + using CallGraphEdgeListTy = std::vector; + private: - std::vector CallGraphEdgeList; + CallGraphEdgeListTy CallGraphEdgeList; public: FunctionSummary(std::vector CGEdges) @@ -59,16 +62,34 @@ class FunctionSummary { void addCall(GUID targetGUID, EdgeTy::Kind kind) { CallGraphEdgeList.emplace_back(targetGUID, kind); } + + ArrayRef calls() const { return CallGraphEdgeList; } +}; + +struct FunctionSummaryInfo { + StringRef Name; + std::unique_ptr TheSummary; }; class ModuleSummaryIndex { - std::map> FunctionSummaryMap; + using FunctionSummaryMapTy = std::map; + FunctionSummaryMapTy FunctionSummaryMap; public: ModuleSummaryIndex() = default; - void addFunctionSummary(GUID guid, std::unique_ptr summary) { - FunctionSummaryMap.insert(std::make_pair(guid, std::move(summary))); + void addFunctionSummary(StringRef name, + std::unique_ptr summary) { + auto guid = getGUID(name); + FunctionSummaryMap.insert( + std::make_pair(guid, FunctionSummaryInfo{name, std::move(summary)})); + } + + FunctionSummaryMapTy::const_iterator begin() const { + return FunctionSummaryMap.begin(); + } + FunctionSummaryMapTy::const_iterator end() const { + return FunctionSummaryMap.end(); } }; diff --git a/include/swift/Serialization/ModuleSummaryFile.h b/include/swift/Serialization/ModuleSummaryFile.h index b39778909135e..a8f1c842419aa 100644 --- a/include/swift/Serialization/ModuleSummaryFile.h +++ b/include/swift/Serialization/ModuleSummaryFile.h @@ -13,8 +13,6 @@ namespace modulesummary { enum BlockID { MODULE_BLOCK_ID = llvm::bitc::FIRST_APPLICATION_BLOCKID, - CONTROL_BLOCK_ID, - FUNCTION_SUMMARY_ID, }; @@ -26,7 +24,8 @@ enum { }; using MetadataLayout = BCRecordLayout // Function GUID + BCFixed<64>, // Function GUID + BCBlob // Name string >; using CallGraphEdgeLayout = BCRecordLayout; } // namespace function_summary +bool emitModuleSummaryIndex(const ModuleSummaryIndex &index, + DiagnosticEngine &diags, StringRef path); + std::unique_ptr loadModuleSummaryIndex(std::unique_ptr inputBuffer); } // namespace modulesummary diff --git a/lib/SIL/Utils/ModuleSummaryIndex.cpp b/lib/SIL/Utils/ModuleSummaryIndex.cpp index 191a933ce7b78..a3d55bd79c9cb 100644 --- a/lib/SIL/Utils/ModuleSummaryIndex.cpp +++ b/lib/SIL/Utils/ModuleSummaryIndex.cpp @@ -60,7 +60,7 @@ ModuleSummaryIndex buildModuleSummaryIndex(SILModule &M, ModuleSummaryIndex index; for (auto &F : M) { auto FS = buildFunctionSummaryIndex(F, BCA); - index.addFunctionSummary(getGUID(F.getName()), std::move(FS)); + index.addFunctionSummary(F.getName(), std::move(FS)); } return index; } diff --git a/lib/Serialization/ModuleSummaryFile.cpp b/lib/Serialization/ModuleSummaryFile.cpp index 3dfa39ded7cca..e62f7f4943637 100644 --- a/lib/Serialization/ModuleSummaryFile.cpp +++ b/lib/Serialization/ModuleSummaryFile.cpp @@ -1,7 +1,9 @@ #include "swift/Serialization/ModuleSummaryFile.h" #include "BCReadingExtras.h" #include "memory" +#include "swift/AST/FileSystem.h" #include "llvm/Bitstream/BitstreamReader.h" +#include "llvm/Bitstream/BitstreamWriter.h" namespace swift { @@ -14,6 +16,88 @@ getEdgeKind(unsigned edgeKind) { return None; } +class Serializer { + SmallVector Buffer; + llvm::BitstreamWriter Out{Buffer}; + + /// A reusable buffer for emitting records. + SmallVector ScratchRecord; + + void emitBlockID(unsigned ID, StringRef name, + SmallVectorImpl &nameBuffer); + + void emitRecordID(unsigned ID, StringRef name, + SmallVectorImpl &nameBuffer); + +public: + void emit(const ModuleSummaryIndex &index); + void write(llvm::raw_ostream &os); +}; + +void Serializer::emitBlockID(unsigned ID, StringRef name, + llvm::SmallVectorImpl &nameBuffer) { + SmallVector idBuffer; + idBuffer.push_back(ID); + Out.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID, idBuffer); + + // Emit the block name if present. + if (name.empty()) + return; + nameBuffer.resize(name.size()); + memcpy(nameBuffer.data(), name.data(), name.size()); + Out.EmitRecord(llvm::bitc::BLOCKINFO_CODE_BLOCKNAME, nameBuffer); +} + +void Serializer::emitRecordID(unsigned ID, StringRef name, + SmallVectorImpl &nameBuffer) { + assert(ID < 256 && "can't fit record ID in next to name"); + nameBuffer.resize(name.size() + 1); + nameBuffer[0] = ID; + memcpy(nameBuffer.data() + 1, name.data(), name.size()); + Out.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, nameBuffer); +} + +void Serializer::emit(const ModuleSummaryIndex &index) { + SmallVector nameBuffer; +#define BLOCK(X) emitBlockID(X##_ID, #X, nameBuffer) +#define BLOCK_RECORD(K, X) emitRecordID(K::X, #X, nameBuffer) + + BLOCK(FUNCTION_SUMMARY); + BLOCK_RECORD(function_summary, METADATA); + BLOCK_RECORD(function_summary, CALL_GRAPH_EDGE); + + llvm::BCBlockRAII restoreBlock(Out, FUNCTION_SUMMARY_ID, 8); + using namespace function_summary; + + for (const auto &pair : index) { + auto &info = pair.second; + using namespace function_summary; + MetadataLayout MDlayout(Out); + MDlayout.emit(ScratchRecord, pair.first, info.Name); + + for (auto call : info.TheSummary->calls()) { + CallGraphEdgeLayout edgeLayout(Out); + edgeLayout.emit(ScratchRecord, unsigned(call.getKind()), + call.getCallee()); + } + } +} + +void Serializer::write(llvm::raw_ostream &os) { + os.write(Buffer.data(), Buffer.size()); + os.flush(); +} + +bool emitModuleSummaryIndex(const ModuleSummaryIndex &index, + DiagnosticEngine &diags, StringRef path) { + return withOutputFile(diags, path, [&](llvm::raw_ostream &out) { + Serializer serializer; + serializer.emit(index); + serializer.write(out); + return false; + }); +} + std::unique_ptr loadModuleSummaryIndex(std::unique_ptr inputBuffer) { llvm::BitstreamCursor cursor{inputBuffer->getMemBufferRef()}; @@ -32,11 +116,6 @@ loadModuleSummaryIndex(std::unique_ptr inputBuffer) { break; switch (entry.ID) { - case CONTROL_BLOCK_ID: { - if (cursor.SkipBlock()) - llvm::report_fatal_error("Can't skip block"); - break; - } case FUNCTION_SUMMARY_ID: { if (llvm::Error Err = cursor.EnterSubBlock(FUNCTION_SUMMARY_ID)) { llvm::report_fatal_error("Can't enter subblock"); @@ -49,6 +128,7 @@ loadModuleSummaryIndex(std::unique_ptr inputBuffer) { llvm::BitstreamEntry next = maybeNext.get(); GUID guid; + std::string Name; std::unique_ptr FS; std::vector CGEdges; @@ -66,6 +146,7 @@ loadModuleSummaryIndex(std::unique_ptr inputBuffer) { switch (kind) { case function_summary::METADATA: { function_summary::MetadataLayout::readRecord(scratch, guid); + Name = blobData.str(); FS = std::make_unique(); break; } @@ -85,7 +166,7 @@ loadModuleSummaryIndex(std::unique_ptr inputBuffer) { } } - moduleSummary->addFunctionSummary(guid, std::move(FS)); + moduleSummary->addFunctionSummary(Name, std::move(FS)); } } } From 082aefde2f5aa16ea04156b1edc59228eacf83dd Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Fri, 3 Jul 2020 14:20:23 +0900 Subject: [PATCH 03/77] Implement frontend --- include/swift/Basic/FileTypes.def | 1 + include/swift/Frontend/FrontendOptions.h | 2 ++ include/swift/Option/Options.td | 3 +++ include/swift/SIL/ModuleSummary.h | 13 ++++++++++++- include/swift/Serialization/ModuleSummaryFile.h | 4 ++-- lib/Basic/FileTypes.cpp | 3 +++ lib/Driver/Driver.cpp | 1 + lib/Driver/ToolChains.cpp | 2 ++ lib/Frontend/ArgsToFrontendOptionsConverter.cpp | 2 ++ lib/Frontend/FrontendOptions.cpp | 14 ++++++++++++++ lib/FrontendTool/FrontendTool.cpp | 14 ++++++++++++++ lib/SIL/Utils/CMakeLists.txt | 1 - lib/SILOptimizer/Utils/CMakeLists.txt | 1 + .../Utils/ModuleSummaryIndex.cpp | 2 +- test/Serialization/module-summary.swift | 10 ++++++++++ 15 files changed, 68 insertions(+), 5 deletions(-) rename lib/{SIL => SILOptimizer}/Utils/ModuleSummaryIndex.cpp (97%) create mode 100644 test/Serialization/module-summary.swift diff --git a/include/swift/Basic/FileTypes.def b/include/swift/Basic/FileTypes.def index 1435813ae6e6c..bb343b110fee1 100644 --- a/include/swift/Basic/FileTypes.def +++ b/include/swift/Basic/FileTypes.def @@ -48,6 +48,7 @@ TYPE("dSYM", dSYM, "dSYM", "") TYPE("dependencies", Dependencies, "d", "") TYPE("autolink", AutolinkFile, "autolink", "") TYPE("swiftmodule", SwiftModuleFile, "swiftmodule", "") +TYPE("swiftmodule-summary", SwiftModuleSummaryFile, "swiftmodule.summary", "") TYPE("swiftdoc", SwiftModuleDocFile, "swiftdoc", "") TYPE("swiftinterface", SwiftModuleInterfaceFile, "swiftinterface", "") TYPE("private-swiftinterface", PrivateSwiftModuleInterfaceFile, "private.swiftinterface", "") diff --git a/include/swift/Frontend/FrontendOptions.h b/include/swift/Frontend/FrontendOptions.h index 4c9afa649e6b5..a165759611715 100644 --- a/include/swift/Frontend/FrontendOptions.h +++ b/include/swift/Frontend/FrontendOptions.h @@ -111,6 +111,8 @@ class FrontendOptions { EmitSILGen, ///< Emit raw SIL EmitSIL, ///< Emit canonical SIL + EmitModuleSummary, /// < Emit module summary + EmitModuleOnly, ///< Emit module only MergeModules, ///< Merge modules only diff --git a/include/swift/Option/Options.td b/include/swift/Option/Options.td index d76685bf7d540..f2ed910f4f2d8 100644 --- a/include/swift/Option/Options.td +++ b/include/swift/Option/Options.td @@ -918,6 +918,9 @@ def emit_imported_modules : Flag<["-"], "emit-imported-modules">, def emit_pcm : Flag<["-"], "emit-pcm">, HelpText<"Emit a precompiled Clang module from a module map">, ModeOpt, Flags<[FrontendOption, NoInteractiveOption, DoesNotAffectIncrementalBuild]>; +def emit_module_summary : Flag<["-"], "emit-module-summary">, + HelpText<"Emit module summary">, ModeOpt, + Flags<[FrontendOption, NoInteractiveOption, DoesNotAffectIncrementalBuild]>; def c : Flag<["-"], "c">, Alias, Flags<[FrontendOption, NoInteractiveOption]>, ModeOpt; diff --git a/include/swift/SIL/ModuleSummary.h b/include/swift/SIL/ModuleSummary.h index 5d6eb6311ed52..2949e21a8f1bc 100644 --- a/include/swift/SIL/ModuleSummary.h +++ b/include/swift/SIL/ModuleSummary.h @@ -1,10 +1,16 @@ +#ifndef SWIFT_SIL_MODULE_SUMMARY_H +#define SWIFT_SIL_MODULE_SUMMARY_H + #include "swift/AST/Decl.h" #include "swift/SIL/SILDeclRef.h" +// FIXME: Move this into another module to avoid circular dependencies. +#include "swift/SILOptimizer/Analysis/BasicCalleeAnalysis.h" + namespace swift { using GUID = uint64_t; -GUID getGUID(llvm::StringRef Str) { return llvm::MD5Hash(Str); } +static GUID getGUID(llvm::StringRef Str) { return llvm::MD5Hash(Str); } class FunctionSummary { public: @@ -93,4 +99,9 @@ class ModuleSummaryIndex { } }; +ModuleSummaryIndex buildModuleSummaryIndex(SILModule &M, + BasicCalleeAnalysis &BCA); + }; // namespace swift + +#endif diff --git a/include/swift/Serialization/ModuleSummaryFile.h b/include/swift/Serialization/ModuleSummaryFile.h index a8f1c842419aa..63676344a5188 100644 --- a/include/swift/Serialization/ModuleSummaryFile.h +++ b/include/swift/Serialization/ModuleSummaryFile.h @@ -24,13 +24,13 @@ enum { }; using MetadataLayout = BCRecordLayout, // Function GUID + BCVBR<16>, // Function GUID BCBlob // Name string >; using CallGraphEdgeLayout = BCRecordLayout, // FunctionSummary::Edge::Kind - BCFixed<64> // Target GUID + BCVBR<16> // Target GUID >; } // namespace function_summary diff --git a/lib/Basic/FileTypes.cpp b/lib/Basic/FileTypes.cpp index d2c1570495dd8..949f6b5873c04 100644 --- a/lib/Basic/FileTypes.cpp +++ b/lib/Basic/FileTypes.cpp @@ -90,6 +90,7 @@ bool file_types::isTextual(ID Id) { case file_types::TY_PCH: case file_types::TY_SIB: case file_types::TY_RawSIB: + case file_types::TY_SwiftModuleSummaryFile: case file_types::TY_SwiftModuleFile: case file_types::TY_SwiftModuleDocFile: case file_types::TY_SwiftSourceInfoFile: @@ -139,6 +140,7 @@ bool file_types::isAfterLLVM(ID Id) { case file_types::TY_SwiftSourceInfoFile: case file_types::TY_SwiftCrossImportDir: case file_types::TY_SwiftOverlayFile: + case file_types::TY_SwiftModuleSummaryFile: case file_types::TY_SerializedDiagnostics: case file_types::TY_ClangModuleFile: case file_types::TY_SwiftDeps: @@ -188,6 +190,7 @@ bool file_types::isPartOfSwiftCompilation(ID Id) { case file_types::TY_PrivateSwiftModuleInterfaceFile: case file_types::TY_SwiftSourceInfoFile: case file_types::TY_SwiftCrossImportDir: + case file_types::TY_SwiftModuleSummaryFile: case file_types::TY_SwiftOverlayFile: case file_types::TY_SerializedDiagnostics: case file_types::TY_ClangModuleFile: diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp index e24362c4c6c22..c7707e227ab0f 100644 --- a/lib/Driver/Driver.cpp +++ b/lib/Driver/Driver.cpp @@ -2005,6 +2005,7 @@ void Driver::buildActions(SmallVectorImpl &TopLevelActions, case file_types::TY_SwiftModuleInterfaceFile: case file_types::TY_PrivateSwiftModuleInterfaceFile: case file_types::TY_SwiftCrossImportDir: + case file_types::TY_SwiftModuleSummaryFile: // FIXME(katei) case file_types::TY_SwiftOverlayFile: case file_types::TY_JSONDependencies: // We could in theory handle assembly or LLVM input, but let's not. diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp index 0429ead73e0e3..945f5a557eee5 100644 --- a/lib/Driver/ToolChains.cpp +++ b/lib/Driver/ToolChains.cpp @@ -615,6 +615,7 @@ const char *ToolChain::JobContext::computeFrontendModeForCompile() const { case file_types::TY_PrivateSwiftModuleInterfaceFile: case file_types::TY_SwiftSourceInfoFile: case file_types::TY_SwiftCrossImportDir: + case file_types::TY_SwiftModuleSummaryFile: // FIXME(katei) case file_types::TY_SwiftOverlayFile: llvm_unreachable("Output type can never be primary output."); case file_types::TY_INVALID: @@ -872,6 +873,7 @@ ToolChain::constructInvocation(const BackendJobAction &job, case file_types::TY_PrivateSwiftModuleInterfaceFile: case file_types::TY_SwiftSourceInfoFile: case file_types::TY_SwiftCrossImportDir: + case file_types::TY_SwiftModuleSummaryFile: case file_types::TY_SwiftOverlayFile: llvm_unreachable("Output type can never be primary output."); case file_types::TY_INVALID: diff --git a/lib/Frontend/ArgsToFrontendOptionsConverter.cpp b/lib/Frontend/ArgsToFrontendOptionsConverter.cpp index ed0cea436f515..04cc506a2d68c 100644 --- a/lib/Frontend/ArgsToFrontendOptionsConverter.cpp +++ b/lib/Frontend/ArgsToFrontendOptionsConverter.cpp @@ -388,6 +388,8 @@ ArgsToFrontendOptionsConverter::determineRequestedAction(const ArgList &args) { return FrontendOptions::ActionType::Immediate; if (Opt.matches(OPT_compile_module_from_interface)) return FrontendOptions::ActionType::CompileModuleFromInterface; + if (Opt.matches(OPT_emit_module_summary)) + return FrontendOptions::ActionType::EmitModuleSummary; llvm_unreachable("Unhandled mode option"); } diff --git a/lib/Frontend/FrontendOptions.cpp b/lib/Frontend/FrontendOptions.cpp index 1e1253ddcb6c5..c258b2895554d 100644 --- a/lib/Frontend/FrontendOptions.cpp +++ b/lib/Frontend/FrontendOptions.cpp @@ -48,6 +48,7 @@ bool FrontendOptions::needsProperModuleName(ActionType action) { case ActionType::EmitSIL: case ActionType::EmitSIBGen: case ActionType::EmitSIB: + case ActionType::EmitModuleSummary: case ActionType::EmitModuleOnly: case ActionType::MergeModules: case ActionType::CompileModuleFromInterface: @@ -145,6 +146,9 @@ FrontendOptions::formatForPrincipalOutputFileForAction(ActionType action) { case ActionType::EmitSIB: return TY_SIB; + case ActionType::EmitModuleSummary: + return TY_SwiftModuleSummaryFile; + case ActionType::MergeModules: case ActionType::EmitModuleOnly: case ActionType::CompileModuleFromInterface: @@ -201,6 +205,7 @@ bool FrontendOptions::canActionEmitDependencies(ActionType action) { case ActionType::Typecheck: case ActionType::MergeModules: case ActionType::EmitModuleOnly: + case ActionType::EmitModuleSummary: case ActionType::EmitPCH: case ActionType::EmitSILGen: case ActionType::EmitSIL: @@ -247,6 +252,7 @@ bool FrontendOptions::canActionEmitReferenceDependencies(ActionType action) { case ActionType::EmitSIL: case ActionType::EmitSIBGen: case ActionType::EmitSIB: + case ActionType::EmitModuleSummary: case ActionType::EmitIR: case ActionType::EmitBC: case ActionType::EmitAssembly: @@ -294,6 +300,7 @@ bool FrontendOptions::canActionEmitObjCHeader(ActionType action) { case ActionType::EmitSIL: case ActionType::EmitSIBGen: case ActionType::EmitSIB: + case ActionType::EmitModuleSummary: case ActionType::EmitIR: case ActionType::EmitBC: case ActionType::EmitAssembly: @@ -333,6 +340,7 @@ bool FrontendOptions::canActionEmitLoadedModuleTrace(ActionType action) { case ActionType::EmitSIL: case ActionType::EmitSIBGen: case ActionType::EmitSIB: + case ActionType::EmitModuleSummary: case ActionType::EmitIR: case ActionType::EmitBC: case ActionType::EmitAssembly: @@ -372,6 +380,7 @@ bool FrontendOptions::canActionEmitModule(ActionType action) { case ActionType::EmitSIL: case ActionType::EmitSIBGen: case ActionType::EmitSIB: + case ActionType::EmitModuleSummary: case ActionType::EmitIR: case ActionType::EmitBC: case ActionType::EmitAssembly: @@ -415,6 +424,7 @@ bool FrontendOptions::canActionEmitInterface(ActionType action) { case ActionType::EmitModuleOnly: case ActionType::EmitSIL: case ActionType::EmitSIB: + case ActionType::EmitModuleSummary: case ActionType::EmitIR: case ActionType::EmitBC: case ActionType::EmitAssembly: @@ -442,6 +452,7 @@ bool FrontendOptions::doesActionProduceOutput(ActionType action) { case ActionType::EmitSIL: case ActionType::EmitSIBGen: case ActionType::EmitSIB: + case ActionType::EmitModuleSummary: case ActionType::EmitModuleOnly: case ActionType::EmitAssembly: case ActionType::EmitIR: @@ -471,6 +482,7 @@ bool FrontendOptions::doesActionProduceTextualOutput(ActionType action) { case ActionType::EmitPCH: case ActionType::EmitSIBGen: case ActionType::EmitSIB: + case ActionType::EmitModuleSummary: case ActionType::MergeModules: case ActionType::EmitModuleOnly: case ActionType::CompileModuleFromInterface: @@ -530,6 +542,7 @@ bool FrontendOptions::doesActionGenerateSIL(ActionType action) { case ActionType::EmitSIBGen: case ActionType::EmitSIL: case ActionType::EmitSIB: + case ActionType::EmitModuleSummary: case ActionType::EmitModuleOnly: case ActionType::MergeModules: case ActionType::Immediate: @@ -566,6 +579,7 @@ bool FrontendOptions::doesActionGenerateIR(ActionType action) { case ActionType::EmitSIL: case ActionType::EmitSIBGen: case ActionType::EmitSIB: + case ActionType::EmitModuleSummary: case ActionType::EmitImportedModules: case ActionType::EmitPCM: case ActionType::DumpPCM: diff --git a/lib/FrontendTool/FrontendTool.cpp b/lib/FrontendTool/FrontendTool.cpp index 7d581d7b3366d..b8d17a7e5c5d5 100644 --- a/lib/FrontendTool/FrontendTool.cpp +++ b/lib/FrontendTool/FrontendTool.cpp @@ -65,6 +65,8 @@ #include "swift/Syntax/Serialization/SyntaxSerialization.h" #include "swift/Syntax/SyntaxNodes.h" #include "swift/TBDGen/TBDGen.h" +#include "swift/SIL/ModuleSummary.h" +#include "swift/Serialization/ModuleSummaryFile.h" #include "clang/AST/ASTContext.h" @@ -1824,6 +1826,13 @@ static bool serializeSIB(SILModule *SM, const PrimarySpecificPaths &PSPs, return Context.hadError(); } +static bool emitModuleSummary(SILModule *SM, const PrimarySpecificPaths &PSPs, + const ASTContext &Context) { + BasicCalleeAnalysis BCA(SM); + auto Summary = buildModuleSummaryIndex(*SM, BCA); + return modulesummary::emitModuleSummaryIndex(Summary, Context.Diags, PSPs.OutputFilename); +} + static GeneratedModule generateIR(const IRGenOptions &IRGenOpts, const TBDGenOptions &TBDOpts, std::unique_ptr SM, @@ -2050,6 +2059,11 @@ static bool performCompileStepsPostSILGen(CompilerInstance &Instance, if (Action == FrontendOptions::ActionType::EmitSIB) return serializeSIB(SM.get(), PSPs, Context, MSF); + + + if (Action == FrontendOptions::ActionType::EmitModuleSummary) { + return emitModuleSummary(SM.get(), PSPs, Context); + } if (PSPs.haveModuleOrModuleDocOutputPaths()) { if (Action == FrontendOptions::ActionType::MergeModules || diff --git a/lib/SIL/Utils/CMakeLists.txt b/lib/SIL/Utils/CMakeLists.txt index 97cfa008ee42b..503af715ecab2 100644 --- a/lib/SIL/Utils/CMakeLists.txt +++ b/lib/SIL/Utils/CMakeLists.txt @@ -6,7 +6,6 @@ target_sources(swiftSIL PRIVATE InstructionUtils.cpp LoopInfo.cpp MemAccessUtils.cpp - ModuleSummaryIndex.cpp OptimizationRemark.cpp OwnershipUtils.cpp PrettyStackTrace.cpp diff --git a/lib/SILOptimizer/Utils/CMakeLists.txt b/lib/SILOptimizer/Utils/CMakeLists.txt index 40359206beeb2..3c96c5593e107 100644 --- a/lib/SILOptimizer/Utils/CMakeLists.txt +++ b/lib/SILOptimizer/Utils/CMakeLists.txt @@ -14,6 +14,7 @@ target_sources(swiftSILOptimizer PRIVATE KeyPathProjector.cpp LoadStoreOptUtils.cpp LoopUtils.cpp + ModuleSummaryIndex.cpp OptimizerStatsUtils.cpp PartialApplyCombiner.cpp PerformanceInlinerUtils.cpp diff --git a/lib/SIL/Utils/ModuleSummaryIndex.cpp b/lib/SILOptimizer/Utils/ModuleSummaryIndex.cpp similarity index 97% rename from lib/SIL/Utils/ModuleSummaryIndex.cpp rename to lib/SILOptimizer/Utils/ModuleSummaryIndex.cpp index a3d55bd79c9cb..b6da30b944f52 100644 --- a/lib/SIL/Utils/ModuleSummaryIndex.cpp +++ b/lib/SILOptimizer/Utils/ModuleSummaryIndex.cpp @@ -55,7 +55,7 @@ buildFunctionSummaryIndex(SILFunction &F, BasicCalleeAnalysis &BCA) { return std::make_unique(CallGraphEdgeList); } -ModuleSummaryIndex buildModuleSummaryIndex(SILModule &M, +ModuleSummaryIndex swift::buildModuleSummaryIndex(SILModule &M, BasicCalleeAnalysis &BCA) { ModuleSummaryIndex index; for (auto &F : M) { diff --git a/test/Serialization/module-summary.swift b/test/Serialization/module-summary.swift new file mode 100644 index 0000000000000..1817e6b2585ca --- /dev/null +++ b/test/Serialization/module-summary.swift @@ -0,0 +1,10 @@ +// RUN: %swift-frontend -emit-module-summary %s + +func foo() {} +func bar(_: Int) {} + +public func publicFunc() {} + +public struct X { + func method1() {} +} From 2611f8fc1decfa79ccddb853959f449c80d3ce91 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Fri, 3 Jul 2020 15:12:08 +0900 Subject: [PATCH 04/77] Add test case --- .../swift/Serialization/ModuleSummaryFile.h | 2 ++ lib/AST/FineGrainedDependencyFormat.cpp | 2 +- lib/Serialization/ModuleSummaryFile.cpp | 34 ++++++++++++++++++- test/Serialization/module-summary.swift | 21 +++++++++--- 4 files changed, 52 insertions(+), 7 deletions(-) diff --git a/include/swift/Serialization/ModuleSummaryFile.h b/include/swift/Serialization/ModuleSummaryFile.h index 63676344a5188..7c1954446bdc7 100644 --- a/include/swift/Serialization/ModuleSummaryFile.h +++ b/include/swift/Serialization/ModuleSummaryFile.h @@ -10,6 +10,8 @@ namespace swift { namespace modulesummary { +const unsigned char MODULE_SUMMARY_SIGNATURE[] = {'M', 'O', 'D', 'S'}; + enum BlockID { MODULE_BLOCK_ID = llvm::bitc::FIRST_APPLICATION_BLOCKID, diff --git a/lib/AST/FineGrainedDependencyFormat.cpp b/lib/AST/FineGrainedDependencyFormat.cpp index b52cc2af98baf..8d3c9b9c9240e 100644 --- a/lib/AST/FineGrainedDependencyFormat.cpp +++ b/lib/AST/FineGrainedDependencyFormat.cpp @@ -483,4 +483,4 @@ bool swift::fine_grained_dependencies::writeFineGrainedDependencyGraph( serializer.writeFineGrainedDependencyGraph(out, g); return false; }); -} \ No newline at end of file +} diff --git a/lib/Serialization/ModuleSummaryFile.cpp b/lib/Serialization/ModuleSummaryFile.cpp index e62f7f4943637..2a9636ba0c113 100644 --- a/lib/Serialization/ModuleSummaryFile.cpp +++ b/lib/Serialization/ModuleSummaryFile.cpp @@ -23,6 +23,8 @@ class Serializer { /// A reusable buffer for emitting records. SmallVector ScratchRecord; + void writeSignature(); + void writeBlockInfoBlock(); void emitBlockID(unsigned ID, StringRef name, SmallVectorImpl &nameBuffer); @@ -57,7 +59,14 @@ void Serializer::emitRecordID(unsigned ID, StringRef name, Out.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, nameBuffer); } -void Serializer::emit(const ModuleSummaryIndex &index) { +void Serializer::writeSignature() { + for (auto c : MODULE_SUMMARY_SIGNATURE) + Out.Emit((unsigned) c, 8); +} + +void Serializer::writeBlockInfoBlock() { + llvm::BCBlockRAII restoreBlock(Out, llvm::bitc::BLOCKINFO_BLOCK_ID, 2); + SmallVector nameBuffer; #define BLOCK(X) emitBlockID(X##_ID, #X, nameBuffer) #define BLOCK_RECORD(K, X) emitRecordID(K::X, #X, nameBuffer) @@ -65,6 +74,12 @@ void Serializer::emit(const ModuleSummaryIndex &index) { BLOCK(FUNCTION_SUMMARY); BLOCK_RECORD(function_summary, METADATA); BLOCK_RECORD(function_summary, CALL_GRAPH_EDGE); +} + +void Serializer::emit(const ModuleSummaryIndex &index) { + + writeSignature(); + writeBlockInfoBlock(); llvm::BCBlockRAII restoreBlock(Out, FUNCTION_SUMMARY_ID, 8); using namespace function_summary; @@ -98,10 +113,27 @@ bool emitModuleSummaryIndex(const ModuleSummaryIndex &index, }); } +static bool readSignature(llvm::BitstreamCursor Cursor) { + for (unsigned char byte : MODULE_SUMMARY_SIGNATURE) { + if (Cursor.AtEndOfStream()) + return true; + if (auto maybeRead = Cursor.Read(8)) { + if (maybeRead.get() != byte) + return true; + } else { + return true; + } + } + return false; +} + std::unique_ptr loadModuleSummaryIndex(std::unique_ptr inputBuffer) { llvm::BitstreamCursor cursor{inputBuffer->getMemBufferRef()}; + if (readSignature(cursor)) + return nullptr; + auto moduleSummary = std::make_unique(); while (!cursor.AtEndOfStream()) { diff --git a/test/Serialization/module-summary.swift b/test/Serialization/module-summary.swift index 1817e6b2585ca..ba5e1036c831f 100644 --- a/test/Serialization/module-summary.swift +++ b/test/Serialization/module-summary.swift @@ -1,10 +1,21 @@ -// RUN: %swift-frontend -emit-module-summary %s +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend -emit-module-summary %s -o %t +// RUN: llvm-bcanalyzer -dump %t/*.swiftmodule.summary | %FileCheck %s +// CHECK: blob data = '$s4main10publicFuncyyF' -func foo() {} -func bar(_: Int) {} +func foo() { bar(0) } +func bar(_ i: Int) { + if (i == 0) { return } + foo() +} -public func publicFunc() {} +public func publicFunc() { + foo() +} public struct X { - func method1() {} + func method1() { + publicFunc() + } } From c70265207e00bcf5eb853bef0b2e211a5cc8937b Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Fri, 3 Jul 2020 17:41:15 +0900 Subject: [PATCH 05/77] Add module block --- include/swift/SIL/ModuleSummary.h | 7 ++ .../swift/Serialization/ModuleSummaryFile.h | 21 +++++- lib/SILOptimizer/Utils/ModuleSummaryIndex.cpp | 3 + lib/Serialization/ModuleSummaryFile.cpp | 74 +++++++++++++++---- 4 files changed, 89 insertions(+), 16 deletions(-) diff --git a/include/swift/SIL/ModuleSummary.h b/include/swift/SIL/ModuleSummary.h index 2949e21a8f1bc..daa84fe91aa4f 100644 --- a/include/swift/SIL/ModuleSummary.h +++ b/include/swift/SIL/ModuleSummary.h @@ -80,10 +80,17 @@ struct FunctionSummaryInfo { class ModuleSummaryIndex { using FunctionSummaryMapTy = std::map; FunctionSummaryMapTy FunctionSummaryMap; + + std::string ModuleName; public: ModuleSummaryIndex() = default; + std::string getModuleName() const { return this->ModuleName; } + void setModuleName(std::string name) { + this->ModuleName = name; + } + void addFunctionSummary(StringRef name, std::unique_ptr summary) { auto guid = getGUID(name); diff --git a/include/swift/Serialization/ModuleSummaryFile.h b/include/swift/Serialization/ModuleSummaryFile.h index 7c1954446bdc7..b257d09a170c3 100644 --- a/include/swift/Serialization/ModuleSummaryFile.h +++ b/include/swift/Serialization/ModuleSummaryFile.h @@ -10,16 +10,33 @@ namespace swift { namespace modulesummary { +using llvm::BCArray; +using llvm::BCBlob; +using llvm::BCFixed; +using llvm::BCGenericRecordLayout; +using llvm::BCRecordLayout; +using llvm::BCVBR; + const unsigned char MODULE_SUMMARY_SIGNATURE[] = {'M', 'O', 'D', 'S'}; enum BlockID { - MODULE_BLOCK_ID = llvm::bitc::FIRST_APPLICATION_BLOCKID, + MODULE_SUMMARY_ID = llvm::bitc::FIRST_APPLICATION_BLOCKID, FUNCTION_SUMMARY_ID, }; +namespace module_summary { +enum { + MODULE_METADATA, +}; + +using MetadataLayout = BCRecordLayout< + MODULE_METADATA, + BCBlob // Module name +>; +}; + namespace function_summary { -using namespace llvm; enum { METADATA, CALL_GRAPH_EDGE, diff --git a/lib/SILOptimizer/Utils/ModuleSummaryIndex.cpp b/lib/SILOptimizer/Utils/ModuleSummaryIndex.cpp index b6da30b944f52..3306e5beb239d 100644 --- a/lib/SILOptimizer/Utils/ModuleSummaryIndex.cpp +++ b/lib/SILOptimizer/Utils/ModuleSummaryIndex.cpp @@ -58,6 +58,9 @@ buildFunctionSummaryIndex(SILFunction &F, BasicCalleeAnalysis &BCA) { ModuleSummaryIndex swift::buildModuleSummaryIndex(SILModule &M, BasicCalleeAnalysis &BCA) { ModuleSummaryIndex index; + + index.setModuleName(M.getSwiftModule()->getName().str()); + for (auto &F : M) { auto FS = buildFunctionSummaryIndex(F, BCA); index.addFunctionSummary(F.getName(), std::move(FS)); diff --git a/lib/Serialization/ModuleSummaryFile.cpp b/lib/Serialization/ModuleSummaryFile.cpp index 2a9636ba0c113..2f08090872fe0 100644 --- a/lib/Serialization/ModuleSummaryFile.cpp +++ b/lib/Serialization/ModuleSummaryFile.cpp @@ -32,7 +32,9 @@ class Serializer { SmallVectorImpl &nameBuffer); public: - void emit(const ModuleSummaryIndex &index); + + void emitHeader(); + void emitModuleSummary(const ModuleSummaryIndex &index); void write(llvm::raw_ostream &os); }; @@ -71,29 +73,40 @@ void Serializer::writeBlockInfoBlock() { #define BLOCK(X) emitBlockID(X##_ID, #X, nameBuffer) #define BLOCK_RECORD(K, X) emitRecordID(K::X, #X, nameBuffer) + BLOCK(MODULE_SUMMARY); + BLOCK_RECORD(module_summary, MODULE_METADATA); + BLOCK(FUNCTION_SUMMARY); BLOCK_RECORD(function_summary, METADATA); BLOCK_RECORD(function_summary, CALL_GRAPH_EDGE); } -void Serializer::emit(const ModuleSummaryIndex &index) { - +void Serializer::emitHeader() { writeSignature(); writeBlockInfoBlock(); +} - llvm::BCBlockRAII restoreBlock(Out, FUNCTION_SUMMARY_ID, 8); - using namespace function_summary; +void Serializer::emitModuleSummary(const ModuleSummaryIndex &index) { + using namespace module_summary; - for (const auto &pair : index) { - auto &info = pair.second; + llvm::BCBlockRAII restoreBlock(Out, MODULE_SUMMARY_ID, 3); + module_summary::MetadataLayout MDLayout(Out); + MDLayout.emit(ScratchRecord, index.getModuleName()); + { + llvm::BCBlockRAII restoreBlock(Out, FUNCTION_SUMMARY_ID, 4); using namespace function_summary; - MetadataLayout MDlayout(Out); - MDlayout.emit(ScratchRecord, pair.first, info.Name); - for (auto call : info.TheSummary->calls()) { - CallGraphEdgeLayout edgeLayout(Out); - edgeLayout.emit(ScratchRecord, unsigned(call.getKind()), - call.getCallee()); + for (const auto &pair : index) { + auto &info = pair.second; + using namespace function_summary; + function_summary::MetadataLayout MDlayout(Out); + MDlayout.emit(ScratchRecord, pair.first, info.Name); + + for (auto call : info.TheSummary->calls()) { + CallGraphEdgeLayout edgeLayout(Out); + edgeLayout.emit(ScratchRecord, unsigned(call.getKind()), + call.getCallee()); + } } } } @@ -107,7 +120,8 @@ bool emitModuleSummaryIndex(const ModuleSummaryIndex &index, DiagnosticEngine &diags, StringRef path) { return withOutputFile(diags, path, [&](llvm::raw_ostream &out) { Serializer serializer; - serializer.emit(index); + serializer.emitHeader(); + serializer.emitModuleSummary(index); serializer.write(out); return false; }); @@ -148,6 +162,37 @@ loadModuleSummaryIndex(std::unique_ptr inputBuffer) { break; switch (entry.ID) { + case MODULE_SUMMARY_ID: { + if (llvm::Error Err = cursor.EnterSubBlock(MODULE_SUMMARY_ID)) { + llvm::report_fatal_error("Can't enter subblock"); + } + + llvm::Expected maybeNext = cursor.advance(); + if (!maybeNext) + llvm::report_fatal_error("Should have next entry"); + + llvm::BitstreamEntry next = maybeNext.get(); + llvm::SmallVector scratch; + while (next.Kind == llvm::BitstreamEntry::Record) { + scratch.clear(); + llvm::StringRef blobData; + llvm::Expected maybeKind = + cursor.readRecord(next.ID, scratch, &blobData); + + if (!maybeKind) + llvm::report_fatal_error("Should have kind"); + + unsigned kind = maybeKind.get(); + + switch (kind) { + case module_summary::MODULE_METADATA: { + moduleSummary->setModuleName(blobData.str()); + break; + } + } + } + break; + } case FUNCTION_SUMMARY_ID: { if (llvm::Error Err = cursor.EnterSubBlock(FUNCTION_SUMMARY_ID)) { llvm::report_fatal_error("Can't enter subblock"); @@ -199,6 +244,7 @@ loadModuleSummaryIndex(std::unique_ptr inputBuffer) { } moduleSummary->addFunctionSummary(Name, std::move(FS)); + break; } } } From 5cb1e6d5ce508a75f349dbe9d7486da56480bde1 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Sat, 4 Jul 2020 00:21:14 +0900 Subject: [PATCH 06/77] Add frontend mode --- include/swift/SIL/ModuleSummary.h | 24 ++-- .../swift/Serialization/ModuleSummaryFile.h | 4 +- lib/Serialization/ModuleSummaryFile.cpp | 22 ++-- test/Serialization/Inputs/module1.swift | 1 + test/Serialization/Inputs/module2.swift | 5 + test/Serialization/module-summary.swift | 19 ++- tools/driver/CMakeLists.txt | 1 + tools/driver/cross_module_opt_main.cpp | 118 ++++++++++++++++++ tools/driver/driver.cpp | 9 ++ 9 files changed, 177 insertions(+), 26 deletions(-) create mode 100644 test/Serialization/Inputs/module1.swift create mode 100644 test/Serialization/Inputs/module2.swift create mode 100644 tools/driver/cross_module_opt_main.cpp diff --git a/include/swift/SIL/ModuleSummary.h b/include/swift/SIL/ModuleSummary.h index daa84fe91aa4f..a1114375454cd 100644 --- a/include/swift/SIL/ModuleSummary.h +++ b/include/swift/SIL/ModuleSummary.h @@ -78,10 +78,10 @@ struct FunctionSummaryInfo { }; class ModuleSummaryIndex { - using FunctionSummaryMapTy = std::map; - FunctionSummaryMapTy FunctionSummaryMap; - - std::string ModuleName; + using FunctionSummaryInfoMapTy = std::map; + FunctionSummaryInfoMapTy FunctionSummaryInfoMap; + + std::string ModuleName; // Only for debug purpose public: ModuleSummaryIndex() = default; @@ -94,15 +94,21 @@ class ModuleSummaryIndex { void addFunctionSummary(StringRef name, std::unique_ptr summary) { auto guid = getGUID(name); - FunctionSummaryMap.insert( + FunctionSummaryInfoMap.insert( std::make_pair(guid, FunctionSummaryInfo{name, std::move(summary)})); } - FunctionSummaryMapTy::const_iterator begin() const { - return FunctionSummaryMap.begin(); + const std::pair + getFunctionInfo(GUID guid) const { + auto &entry = FunctionSummaryInfoMap.at(guid); + return std::make_pair(entry.TheSummary.get(), entry.Name); + } + + FunctionSummaryInfoMapTy::const_iterator begin() const { + return FunctionSummaryInfoMap.begin(); } - FunctionSummaryMapTy::const_iterator end() const { - return FunctionSummaryMap.end(); + FunctionSummaryInfoMapTy::const_iterator end() const { + return FunctionSummaryInfoMap.end(); } }; diff --git a/include/swift/Serialization/ModuleSummaryFile.h b/include/swift/Serialization/ModuleSummaryFile.h index b257d09a170c3..026a20cf35c0a 100644 --- a/include/swift/Serialization/ModuleSummaryFile.h +++ b/include/swift/Serialization/ModuleSummaryFile.h @@ -56,8 +56,8 @@ using CallGraphEdgeLayout = bool emitModuleSummaryIndex(const ModuleSummaryIndex &index, DiagnosticEngine &diags, StringRef path); -std::unique_ptr -loadModuleSummaryIndex(std::unique_ptr inputBuffer); +bool loadModuleSummaryIndex(std::unique_ptr inputBuffer, + ModuleSummaryIndex &moduleSummary); } // namespace modulesummary } // namespace swift diff --git a/lib/Serialization/ModuleSummaryFile.cpp b/lib/Serialization/ModuleSummaryFile.cpp index 2f08090872fe0..06024a8a77b70 100644 --- a/lib/Serialization/ModuleSummaryFile.cpp +++ b/lib/Serialization/ModuleSummaryFile.cpp @@ -93,10 +93,8 @@ void Serializer::emitModuleSummary(const ModuleSummaryIndex &index) { module_summary::MetadataLayout MDLayout(Out); MDLayout.emit(ScratchRecord, index.getModuleName()); { - llvm::BCBlockRAII restoreBlock(Out, FUNCTION_SUMMARY_ID, 4); - using namespace function_summary; - for (const auto &pair : index) { + llvm::BCBlockRAII restoreBlock(Out, FUNCTION_SUMMARY_ID, 4); auto &info = pair.second; using namespace function_summary; function_summary::MetadataLayout MDlayout(Out); @@ -141,14 +139,13 @@ static bool readSignature(llvm::BitstreamCursor Cursor) { return false; } -std::unique_ptr -loadModuleSummaryIndex(std::unique_ptr inputBuffer) { +bool loadModuleSummaryIndex(std::unique_ptr inputBuffer, + ModuleSummaryIndex &moduleSummary) { llvm::BitstreamCursor cursor{inputBuffer->getMemBufferRef()}; - if (readSignature(cursor)) - return nullptr; - - auto moduleSummary = std::make_unique(); + if (readSignature(cursor)) { + llvm::report_fatal_error("Invalid signature"); + } while (!cursor.AtEndOfStream()) { llvm::Expected maybeEntry = @@ -186,7 +183,7 @@ loadModuleSummaryIndex(std::unique_ptr inputBuffer) { switch (kind) { case module_summary::MODULE_METADATA: { - moduleSummary->setModuleName(blobData.str()); + moduleSummary.setModuleName(blobData.str()); break; } } @@ -243,13 +240,12 @@ loadModuleSummaryIndex(std::unique_ptr inputBuffer) { } } - moduleSummary->addFunctionSummary(Name, std::move(FS)); + moduleSummary.addFunctionSummary(Name, std::move(FS)); break; } } } - - return moduleSummary; + return false; } } // namespace modulesummary diff --git a/test/Serialization/Inputs/module1.swift b/test/Serialization/Inputs/module1.swift new file mode 100644 index 0000000000000..ac8bc0d030901 --- /dev/null +++ b/test/Serialization/Inputs/module1.swift @@ -0,0 +1 @@ +public func module1Func() -> Int { return 1 } diff --git a/test/Serialization/Inputs/module2.swift b/test/Serialization/Inputs/module2.swift new file mode 100644 index 0000000000000..b2e88ee83e44a --- /dev/null +++ b/test/Serialization/Inputs/module2.swift @@ -0,0 +1,5 @@ +import module1 + +public func module2Func() -> Int { + return module1Func() +} diff --git a/test/Serialization/module-summary.swift b/test/Serialization/module-summary.swift index ba5e1036c831f..a0b481b19f8ee 100644 --- a/test/Serialization/module-summary.swift +++ b/test/Serialization/module-summary.swift @@ -1,15 +1,30 @@ // RUN: %empty-directory(%t) -// RUN: %target-swift-frontend -emit-module-summary %s -o %t -// RUN: llvm-bcanalyzer -dump %t/*.swiftmodule.summary | %FileCheck %s +// RUN: %target-swift-frontend -emit-module %S/Inputs/module1.swift -parse-as-library -o %t +// RUN: %target-swift-frontend -emit-module-summary %S/Inputs/module1.swift -parse-as-library -o %t +// RUN: %target-swift-frontend -emit-module %S/Inputs/module2.swift -parse-as-library -I %t -o %t +// RUN: %target-swift-frontend -emit-module-summary %S/Inputs/module2.swift -parse-as-library -I %t -o %t +// RUN: %target-swift-frontend -emit-module-summary %s -I %t -o %t +// RUN: llvm-bcanalyzer -dump %t/module-summary.swiftmodule.summary | %FileCheck %s // CHECK: blob data = '$s4main10publicFuncyyF' +import module2 + func foo() { bar(0) } func bar(_ i: Int) { if (i == 0) { return } foo() } +func callTwice() { + foo() + bar(0) +} + +func callExternalFunc() { + _ = module2Func() +} + public func publicFunc() { foo() } diff --git a/tools/driver/CMakeLists.txt b/tools/driver/CMakeLists.txt index aabba372ae647..0c33df44404c0 100644 --- a/tools/driver/CMakeLists.txt +++ b/tools/driver/CMakeLists.txt @@ -2,6 +2,7 @@ add_swift_host_tool(swift-frontend driver.cpp autolink_extract_main.cpp modulewrap_main.cpp + cross_module_opt_main.cpp swift_indent_main.cpp swift_symbolgraph_extract_main.cpp SWIFT_COMPONENT compiler diff --git a/tools/driver/cross_module_opt_main.cpp b/tools/driver/cross_module_opt_main.cpp new file mode 100644 index 0000000000000..4c2fbea81aabc --- /dev/null +++ b/tools/driver/cross_module_opt_main.cpp @@ -0,0 +1,118 @@ +#include "swift/AST/DiagnosticsFrontend.h" +#include "swift/Basic/LLVMInitialize.h" +#include "swift/Frontend/Frontend.h" +#include "swift/Frontend/PrintingDiagnosticConsumer.h" +#include "swift/Option/Options.h" +#include "swift/SIL/SILModule.h" +#include "swift/SIL/TypeLowering.h" +#include "swift/Serialization/ModuleSummaryFile.h" +#include "swift/Serialization/Validation.h" +#include "swift/Subsystems.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/Bitstream/BitstreamReader.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Option/Option.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/TargetSelect.h" + +using namespace llvm::opt; +using namespace swift; + +class MergeModuleSummaryInvocation { +private: + std::string MainExecutablePath; + std::string OutputFilename = "-"; + std::vector InputFilenames; + +public: + void setMainExecutablePath(const std::string &Path) { + MainExecutablePath = Path; + } + + const std::string &getOutputFilename() { return OutputFilename; } + + const std::vector &getInputFilenames() { return InputFilenames; } + + int parseArgs(llvm::ArrayRef Args, DiagnosticEngine &Diags) { + using namespace options; + + // Parse frontend command line options using Swift's option table. + std::unique_ptr Table = createSwiftOptTable(); + unsigned MissingIndex; + unsigned MissingCount; + llvm::opt::InputArgList ParsedArgs = + Table->ParseArgs(Args, MissingIndex, MissingCount, ModuleWrapOption); + if (MissingCount) { + Diags.diagnose(SourceLoc(), diag::error_missing_arg_value, + ParsedArgs.getArgString(MissingIndex), MissingCount); + return 1; + } + + if (ParsedArgs.hasArg(OPT_UNKNOWN)) { + for (const Arg *A : ParsedArgs.filtered(OPT_UNKNOWN)) { + Diags.diagnose(SourceLoc(), diag::error_unknown_arg, + A->getAsString(ParsedArgs)); + } + return true; + } + + for (const Arg *A : ParsedArgs.filtered(OPT_INPUT)) { + InputFilenames.push_back(A->getValue()); + } + + if (InputFilenames.empty()) { + Diags.diagnose(SourceLoc(), diag::error_mode_requires_an_input_file); + return 1; + } + + if (const Arg *A = ParsedArgs.getLastArg(OPT_o)) { + OutputFilename = A->getValue(); + } + + return 0; + } +}; + +int cross_module_opt_main(ArrayRef Args, const char *Argv0, + void *MainAddr) { + INITIALIZE_LLVM(); + + CompilerInstance Instance; + PrintingDiagnosticConsumer PDC; + Instance.addDiagnosticConsumer(&PDC); + + MergeModuleSummaryInvocation Invocation; + std::string MainExecutablePath = + llvm::sys::fs::getMainExecutable(Argv0, MainAddr); + Invocation.setMainExecutablePath(MainExecutablePath); + + // Parse arguments. + if (Invocation.parseArgs(Args, Instance.getDiags()) != 0) { + return 1; + } + + auto TheSummary = std::make_unique(); + + for (auto Filename : Invocation.getInputFilenames()) { + auto ErrOrBuf = llvm::MemoryBuffer::getFile(Filename); + if (!ErrOrBuf) { + Instance.getDiags().diagnose( + SourceLoc(), diag::error_no_such_file_or_directory, Filename); + return 1; + } + + auto HasErr = swift::modulesummary::loadModuleSummaryIndex( + std::move(ErrOrBuf.get()), *TheSummary.get()); + + if (HasErr) + llvm::report_fatal_error("Invalid module summary"); + } + + TheSummary->setModuleName("combined"); + + modulesummary::emitModuleSummaryIndex(*TheSummary, Instance.getDiags(), + Invocation.getOutputFilename()); + return 0; +} diff --git a/tools/driver/driver.cpp b/tools/driver/driver.cpp index ff189f773ab28..d5ad7457f7001 100644 --- a/tools/driver/driver.cpp +++ b/tools/driver/driver.cpp @@ -66,6 +66,9 @@ extern int autolink_extract_main(ArrayRef Args, const char *Argv0, extern int modulewrap_main(ArrayRef Args, const char *Argv0, void *MainAddr); +extern int cross_module_opt_main(ArrayRef Args, const char *Argv0, + void *MainAddr); + /// Run 'swift-indent' extern int swift_indent_main(ArrayRef Args, const char *Argv0, void *MainAddr); @@ -140,6 +143,12 @@ static int run_driver(StringRef ExecName, argv.data()+argv.size()), argv[0], (void *)(intptr_t)getExecutablePath); } + + if (FirstArg == "-merge-summary") { + return cross_module_opt_main( + llvm::makeArrayRef(argv.data() + 2, argv.data() + argv.size()), + argv[0], (void *)(intptr_t)getExecutablePath); + } } // Run the integrated Swift frontend when called as "swift-frontend" but From 08b2fd36dfc7eb6f96c74398d24240d50685665e Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Sat, 4 Jul 2020 14:04:31 +0900 Subject: [PATCH 07/77] Merge module summary --- include/swift/SIL/ModuleSummary.h | 4 +- .../swift/Serialization/ModuleSummaryFile.h | 2 +- lib/Serialization/ModuleSummaryFile.cpp | 244 ++++++++++++------ test/Serialization/module-summary.swift | 2 + tools/driver/cross_module_opt_main.cpp | 2 +- tools/driver/driver.cpp | 2 +- 6 files changed, 167 insertions(+), 89 deletions(-) diff --git a/include/swift/SIL/ModuleSummary.h b/include/swift/SIL/ModuleSummary.h index a1114375454cd..58941692fa819 100644 --- a/include/swift/SIL/ModuleSummary.h +++ b/include/swift/SIL/ModuleSummary.h @@ -73,7 +73,7 @@ class FunctionSummary { }; struct FunctionSummaryInfo { - StringRef Name; + std::string Name; std::unique_ptr TheSummary; }; @@ -91,7 +91,7 @@ class ModuleSummaryIndex { this->ModuleName = name; } - void addFunctionSummary(StringRef name, + void addFunctionSummary(std::string name, std::unique_ptr summary) { auto guid = getGUID(name); FunctionSummaryInfoMap.insert( diff --git a/include/swift/Serialization/ModuleSummaryFile.h b/include/swift/Serialization/ModuleSummaryFile.h index 026a20cf35c0a..3ce08c8c6ce58 100644 --- a/include/swift/Serialization/ModuleSummaryFile.h +++ b/include/swift/Serialization/ModuleSummaryFile.h @@ -56,7 +56,7 @@ using CallGraphEdgeLayout = bool emitModuleSummaryIndex(const ModuleSummaryIndex &index, DiagnosticEngine &diags, StringRef path); -bool loadModuleSummaryIndex(std::unique_ptr inputBuffer, +bool loadModuleSummaryIndex(llvm::MemoryBufferRef inputBuffer, ModuleSummaryIndex &moduleSummary); } // namespace modulesummary } // namespace swift diff --git a/lib/Serialization/ModuleSummaryFile.cpp b/lib/Serialization/ModuleSummaryFile.cpp index 06024a8a77b70..c7cd2e7ac911a 100644 --- a/lib/Serialization/ModuleSummaryFile.cpp +++ b/lib/Serialization/ModuleSummaryFile.cpp @@ -98,6 +98,9 @@ void Serializer::emitModuleSummary(const ModuleSummaryIndex &index) { auto &info = pair.second; using namespace function_summary; function_summary::MetadataLayout MDlayout(Out); + + llvm::dbgs() << "Emitting " << info.Name << "\n"; + MDlayout.emit(ScratchRecord, pair.first, info.Name); for (auto call : info.TheSummary->calls()) { @@ -125,7 +128,26 @@ bool emitModuleSummaryIndex(const ModuleSummaryIndex &index, }); } -static bool readSignature(llvm::BitstreamCursor Cursor) { +class Deserializer { + llvm::BitstreamCursor Cursor; + SmallVector Scratch; + StringRef BlobData; + + ModuleSummaryIndex &moduleSummary; + + bool readSignature(); + bool readModuleSummaryMetadata(); + bool readFunctionSummary(); + bool readSingleModuleSummary(); + +public: + Deserializer(llvm::MemoryBufferRef inputBuffer, + ModuleSummaryIndex &moduleSummary) + : Cursor{inputBuffer}, moduleSummary(moduleSummary) {} + bool readModuleSummary(); +}; + +bool Deserializer::readSignature() { for (unsigned char byte : MODULE_SUMMARY_SIGNATURE) { if (Cursor.AtEndOfStream()) return true; @@ -139,17 +161,132 @@ static bool readSignature(llvm::BitstreamCursor Cursor) { return false; } -bool loadModuleSummaryIndex(std::unique_ptr inputBuffer, - ModuleSummaryIndex &moduleSummary) { - llvm::BitstreamCursor cursor{inputBuffer->getMemBufferRef()}; +bool Deserializer::readModuleSummaryMetadata() { + llvm::Expected maybeEntry = Cursor.advance(); + if (!maybeEntry) + llvm::report_fatal_error("Should have next entry"); + + llvm::BitstreamEntry entry = maybeEntry.get(); + + if (entry.Kind != llvm::BitstreamEntry::Record) { + return true; + } + Scratch.clear(); + auto maybeKind = Cursor.readRecord(entry.ID, Scratch, &BlobData); + + if (!maybeKind) { + consumeError(maybeKind.takeError()); + return true; + } + + if (maybeKind.get() != module_summary::MODULE_METADATA) { + return true; + } + + moduleSummary.setModuleName(BlobData.str()); + + llvm::dbgs() << "Start loading module " << moduleSummary.getModuleName() + << "\n"; + return false; +} + +bool Deserializer::readFunctionSummary() { + if (llvm::Error Err = Cursor.EnterSubBlock(FUNCTION_SUMMARY_ID)) { + llvm::report_fatal_error("Can't enter subblock"); + } + + llvm::Expected maybeNext = Cursor.advance(); + if (!maybeNext) + llvm::report_fatal_error("Should have next entry"); + + llvm::BitstreamEntry next = maybeNext.get(); + + GUID guid; + std::string Name; + std::unique_ptr FS; + + while (next.Kind == llvm::BitstreamEntry::Record) { + Scratch.clear(); + + auto maybeKind = Cursor.readRecord(next.ID, Scratch, &BlobData); + + if (!maybeKind) + llvm::report_fatal_error("Should have kind"); + + switch (maybeKind.get()) { + case function_summary::METADATA: { + function_summary::MetadataLayout::readRecord(Scratch, guid); + Name = BlobData.str(); + FS = std::make_unique(); + break; + } + case function_summary::CALL_GRAPH_EDGE: { + unsigned edgeKindID, targetGUID; + function_summary::CallGraphEdgeLayout::readRecord(Scratch, edgeKindID, + targetGUID); + auto edgeKind = getEdgeKind(edgeKindID); + if (!edgeKind) + llvm::report_fatal_error("Bad edge kind"); + if (!FS) + llvm::report_fatal_error("Invalid state"); + + FS->addCall(targetGUID, edgeKind.getValue()); + break; + } + } + + maybeNext = Cursor.advance(); + if (!maybeNext) + llvm::report_fatal_error("Should have next entry"); - if (readSignature(cursor)) { + next = maybeNext.get(); + } + + llvm::dbgs() << "Added " << Name << " in FS list\n"; + moduleSummary.addFunctionSummary(Name, std::move(FS)); + return false; +} + +bool Deserializer::readSingleModuleSummary() { + if (llvm::Error Err = Cursor.EnterSubBlock(MODULE_SUMMARY_ID)) { + llvm::report_fatal_error("Can't enter subblock"); + } + + if (readModuleSummaryMetadata()) { + return true; + } + + llvm::Expected maybeNext = Cursor.advance(); + if (!maybeNext) + llvm::report_fatal_error("Should have next entry"); + + llvm::BitstreamEntry next = maybeNext.get(); + while (next.Kind == llvm::BitstreamEntry::SubBlock) { + switch (next.ID) { + case FUNCTION_SUMMARY_ID: { + readFunctionSummary(); + break; + } + } + + maybeNext = Cursor.advance(); + if (!maybeNext) { + consumeError(maybeNext.takeError()); + return true; + } + next = maybeNext.get(); + } + return false; +} + +bool Deserializer::readModuleSummary() { + if (readSignature()) { llvm::report_fatal_error("Invalid signature"); } - while (!cursor.AtEndOfStream()) { + while (!Cursor.AtEndOfStream()) { llvm::Expected maybeEntry = - cursor.advance(llvm::BitstreamCursor::AF_DontPopBlockAtEnd); + Cursor.advance(llvm::BitstreamCursor::AF_DontPopBlockAtEnd); if (!maybeEntry) { llvm::report_fatal_error("Should have entry"); } @@ -159,88 +296,21 @@ bool loadModuleSummaryIndex(std::unique_ptr inputBuffer, break; switch (entry.ID) { - case MODULE_SUMMARY_ID: { - if (llvm::Error Err = cursor.EnterSubBlock(MODULE_SUMMARY_ID)) { - llvm::report_fatal_error("Can't enter subblock"); + case llvm::bitc::BLOCKINFO_BLOCK_ID: { + if (Cursor.SkipBlock()) { + return true; } - - llvm::Expected maybeNext = cursor.advance(); - if (!maybeNext) - llvm::report_fatal_error("Should have next entry"); - - llvm::BitstreamEntry next = maybeNext.get(); - llvm::SmallVector scratch; - while (next.Kind == llvm::BitstreamEntry::Record) { - scratch.clear(); - llvm::StringRef blobData; - llvm::Expected maybeKind = - cursor.readRecord(next.ID, scratch, &blobData); - - if (!maybeKind) - llvm::report_fatal_error("Should have kind"); - - unsigned kind = maybeKind.get(); - - switch (kind) { - case module_summary::MODULE_METADATA: { - moduleSummary.setModuleName(blobData.str()); - break; - } - } + break; + } + case MODULE_SUMMARY_ID: { + if (readSingleModuleSummary()) { + return true; } break; } case FUNCTION_SUMMARY_ID: { - if (llvm::Error Err = cursor.EnterSubBlock(FUNCTION_SUMMARY_ID)) { - llvm::report_fatal_error("Can't enter subblock"); - } - - llvm::Expected maybeNext = cursor.advance(); - if (!maybeNext) - llvm::report_fatal_error("Should have next entry"); - - llvm::BitstreamEntry next = maybeNext.get(); - - GUID guid; - std::string Name; - std::unique_ptr FS; - std::vector CGEdges; - - llvm::SmallVector scratch; - while (next.Kind == llvm::BitstreamEntry::Record) { - scratch.clear(); - llvm::StringRef blobData; - llvm::Expected maybeKind = - cursor.readRecord(next.ID, scratch, &blobData); - - if (!maybeKind) - llvm::report_fatal_error("Should have kind"); - - unsigned kind = maybeKind.get(); - switch (kind) { - case function_summary::METADATA: { - function_summary::MetadataLayout::readRecord(scratch, guid); - Name = blobData.str(); - FS = std::make_unique(); - break; - } - case function_summary::CALL_GRAPH_EDGE: { - unsigned edgeKindID, targetGUID; - function_summary::CallGraphEdgeLayout::readRecord(scratch, edgeKindID, - targetGUID); - auto edgeKind = getEdgeKind(edgeKindID); - if (!edgeKind) - llvm::report_fatal_error("Bad edge kind"); - if (!FS) - llvm::report_fatal_error("Invalid state"); - - FS->addCall(targetGUID, edgeKind.getValue()); - break; - } - } - } - - moduleSummary.addFunctionSummary(Name, std::move(FS)); + llvm_unreachable("FUNCTION_SUMMARY block should be handled in " + "'readSingleModuleSummary'"); break; } } @@ -248,5 +318,11 @@ bool loadModuleSummaryIndex(std::unique_ptr inputBuffer, return false; } +bool loadModuleSummaryIndex(llvm::MemoryBufferRef inputBuffer, + ModuleSummaryIndex &moduleSummary) { + Deserializer deserializer(inputBuffer, moduleSummary); + return deserializer.readModuleSummary(); +} + } // namespace modulesummary } // namespace swift diff --git a/test/Serialization/module-summary.swift b/test/Serialization/module-summary.swift index a0b481b19f8ee..fcff8ff576a91 100644 --- a/test/Serialization/module-summary.swift +++ b/test/Serialization/module-summary.swift @@ -8,6 +8,8 @@ // CHECK: blob data = '$s4main10publicFuncyyF' +// RUN: %swift_frontend_plain -cross-module-opt %t/module-summary.swiftmodule.summary %t/module1.swiftmodule.summary %t/module2.swiftmodule.summary -o %t/merged-module.summary + import module2 func foo() { bar(0) } diff --git a/tools/driver/cross_module_opt_main.cpp b/tools/driver/cross_module_opt_main.cpp index 4c2fbea81aabc..e4afa21da024a 100644 --- a/tools/driver/cross_module_opt_main.cpp +++ b/tools/driver/cross_module_opt_main.cpp @@ -104,7 +104,7 @@ int cross_module_opt_main(ArrayRef Args, const char *Argv0, } auto HasErr = swift::modulesummary::loadModuleSummaryIndex( - std::move(ErrOrBuf.get()), *TheSummary.get()); + ErrOrBuf.get()->getMemBufferRef(), *TheSummary.get()); if (HasErr) llvm::report_fatal_error("Invalid module summary"); diff --git a/tools/driver/driver.cpp b/tools/driver/driver.cpp index d5ad7457f7001..594ad1da3cf1a 100644 --- a/tools/driver/driver.cpp +++ b/tools/driver/driver.cpp @@ -144,7 +144,7 @@ static int run_driver(StringRef ExecName, argv[0], (void *)(intptr_t)getExecutablePath); } - if (FirstArg == "-merge-summary") { + if (FirstArg == "-cross-module-opt") { return cross_module_opt_main( llvm::makeArrayRef(argv.data() + 2, argv.data() + argv.size()), argv[0], (void *)(intptr_t)getExecutablePath); From c23c02a436e9b64cb43afdf2e4cb4af4a620513b Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Sat, 4 Jul 2020 14:46:05 +0900 Subject: [PATCH 08/77] Add test case --- include/swift/SIL/ModuleSummary.h | 10 +++++++--- lib/Serialization/ModuleSummaryFile.cpp | 14 +++++++++++--- test/Serialization/module-summary.swift | 24 +++++++++++++++++++++--- tools/driver/cross_module_opt_main.cpp | 2 ++ 4 files changed, 41 insertions(+), 9 deletions(-) diff --git a/include/swift/SIL/ModuleSummary.h b/include/swift/SIL/ModuleSummary.h index 58941692fa819..039508b8a77e9 100644 --- a/include/swift/SIL/ModuleSummary.h +++ b/include/swift/SIL/ModuleSummary.h @@ -98,10 +98,14 @@ class ModuleSummaryIndex { std::make_pair(guid, FunctionSummaryInfo{name, std::move(summary)})); } - const std::pair + const llvm::Optional> getFunctionInfo(GUID guid) const { - auto &entry = FunctionSummaryInfoMap.at(guid); - return std::make_pair(entry.TheSummary.get(), entry.Name); + auto found = FunctionSummaryInfoMap.find(guid); + if (found == FunctionSummaryInfoMap.end()) { + return None; + } + auto &entry = found->second; + return std::make_pair(entry.TheSummary.get(), StringRef(entry.Name)); } FunctionSummaryInfoMapTy::const_iterator begin() const { diff --git a/lib/Serialization/ModuleSummaryFile.cpp b/lib/Serialization/ModuleSummaryFile.cpp index c7cd2e7ac911a..5d1569bb7a9b1 100644 --- a/lib/Serialization/ModuleSummaryFile.cpp +++ b/lib/Serialization/ModuleSummaryFile.cpp @@ -203,7 +203,8 @@ bool Deserializer::readFunctionSummary() { GUID guid; std::string Name; - std::unique_ptr FS; + FunctionSummary *FS; + std::unique_ptr NewFSOwner; while (next.Kind == llvm::BitstreamEntry::Record) { Scratch.clear(); @@ -217,7 +218,12 @@ bool Deserializer::readFunctionSummary() { case function_summary::METADATA: { function_summary::MetadataLayout::readRecord(Scratch, guid); Name = BlobData.str(); - FS = std::make_unique(); + if (auto info = moduleSummary.getFunctionInfo(guid)) { + FS = info.getValue().first; + } else { + NewFSOwner = std::make_unique(); + FS = NewFSOwner.get(); + } break; } case function_summary::CALL_GRAPH_EDGE: { @@ -243,7 +249,9 @@ bool Deserializer::readFunctionSummary() { } llvm::dbgs() << "Added " << Name << " in FS list\n"; - moduleSummary.addFunctionSummary(Name, std::move(FS)); + if (auto &FS = NewFSOwner) { + moduleSummary.addFunctionSummary(Name, std::move(FS)); + } return false; } diff --git a/test/Serialization/module-summary.swift b/test/Serialization/module-summary.swift index fcff8ff576a91..88bb1d292a6ea 100644 --- a/test/Serialization/module-summary.swift +++ b/test/Serialization/module-summary.swift @@ -4,11 +4,29 @@ // RUN: %target-swift-frontend -emit-module %S/Inputs/module2.swift -parse-as-library -I %t -o %t // RUN: %target-swift-frontend -emit-module-summary %S/Inputs/module2.swift -parse-as-library -I %t -o %t // RUN: %target-swift-frontend -emit-module-summary %s -I %t -o %t -// RUN: llvm-bcanalyzer -dump %t/module-summary.swiftmodule.summary | %FileCheck %s -// CHECK: blob data = '$s4main10publicFuncyyF' +// RUN: llvm-bcanalyzer -dump %t/module-summary.swiftmodule.summary | %FileCheck %s --check-prefix MAIN-CHECK + +// MAIN-CHECK: blob data = '$s4main10publicFuncyyF' + +// MAIN-CHECK: blob data = '$s7module20A4FuncSiyF' +// MAIN-CHECK-NEXT: + + +// MAIN-CHECK: blob data = '$s4main9callTwiceyyF' +// MAIN-CHECK-NEXT: +// MAIN-CHECK-NEXT: +// MAIN-CHECK-NEXT: + // RUN: %swift_frontend_plain -cross-module-opt %t/module-summary.swiftmodule.summary %t/module1.swiftmodule.summary %t/module2.swiftmodule.summary -o %t/merged-module.summary +// RUN: llvm-bcanalyzer -dump %t/merged-module.summary | %FileCheck %s --check-prefix MERGED-CHECK + +// MERGED-CHECK: blob data = '$s7module10A4FuncSiyF' +// MERGED-CHECK-NEXT: + +// MERGED-CHECK: blob data = '$s7module20A4FuncSiyF' +// MERGED-CHECK-NEXT: +// MERGED-CHECK-NEXT: import module2 diff --git a/tools/driver/cross_module_opt_main.cpp b/tools/driver/cross_module_opt_main.cpp index e4afa21da024a..935124175bb01 100644 --- a/tools/driver/cross_module_opt_main.cpp +++ b/tools/driver/cross_module_opt_main.cpp @@ -75,6 +75,8 @@ class MergeModuleSummaryInvocation { } }; +class ModuleSummaryLinker {}; + int cross_module_opt_main(ArrayRef Args, const char *Argv0, void *MainAddr) { INITIALIZE_LLVM(); From aec688e7f8c7e7bd6a42f453a4d732d44c5c8b8a Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Sat, 4 Jul 2020 15:51:33 +0900 Subject: [PATCH 09/77] Mark dead symbols --- include/swift/SIL/ModuleSummary.h | 9 +++++ lib/Serialization/ModuleSummaryFile.cpp | 3 +- test/Serialization/module-summary.swift | 21 ++++++---- tools/driver/cross_module_opt_main.cpp | 51 ++++++++++++++++++++++++- 4 files changed, 74 insertions(+), 10 deletions(-) diff --git a/include/swift/SIL/ModuleSummary.h b/include/swift/SIL/ModuleSummary.h index 039508b8a77e9..4f665126f3dd4 100644 --- a/include/swift/SIL/ModuleSummary.h +++ b/include/swift/SIL/ModuleSummary.h @@ -55,9 +55,15 @@ class FunctionSummary { } }; + + struct FlagsTy { + unsigned Live : 1; + }; + using CallGraphEdgeListTy = std::vector; private: + FlagsTy Flags; CallGraphEdgeListTy CallGraphEdgeList; public: @@ -70,6 +76,9 @@ class FunctionSummary { } ArrayRef calls() const { return CallGraphEdgeList; } + + bool isLive() const { return Flags.Live; } + void setLive(bool Live) { Flags.Live = Live; } }; struct FunctionSummaryInfo { diff --git a/lib/Serialization/ModuleSummaryFile.cpp b/lib/Serialization/ModuleSummaryFile.cpp index 5d1569bb7a9b1..9427c2dd9d074 100644 --- a/lib/Serialization/ModuleSummaryFile.cpp +++ b/lib/Serialization/ModuleSummaryFile.cpp @@ -227,7 +227,8 @@ bool Deserializer::readFunctionSummary() { break; } case function_summary::CALL_GRAPH_EDGE: { - unsigned edgeKindID, targetGUID; + unsigned edgeKindID; + GUID targetGUID; function_summary::CallGraphEdgeLayout::readRecord(Scratch, edgeKindID, targetGUID); auto edgeKind = getEdgeKind(edgeKindID); diff --git a/test/Serialization/module-summary.swift b/test/Serialization/module-summary.swift index 88bb1d292a6ea..d7f8aefc4ff9d 100644 --- a/test/Serialization/module-summary.swift +++ b/test/Serialization/module-summary.swift @@ -8,7 +8,11 @@ // MAIN-CHECK: blob data = '$s4main10publicFuncyyF' + +// Ensure that call graph edge has correct function guid // MAIN-CHECK: blob data = '$s7module20A4FuncSiyF' +// MAIN-CHECK: blob data = 'main' +// MAIN-CHECK-NEXT: // MAIN-CHECK-NEXT: @@ -17,7 +21,6 @@ // MAIN-CHECK-NEXT: // MAIN-CHECK-NEXT: - // RUN: %swift_frontend_plain -cross-module-opt %t/module-summary.swiftmodule.summary %t/module1.swiftmodule.summary %t/module2.swiftmodule.summary -o %t/merged-module.summary // RUN: llvm-bcanalyzer -dump %t/merged-module.summary | %FileCheck %s --check-prefix MERGED-CHECK @@ -25,14 +28,14 @@ // MERGED-CHECK-NEXT: // MERGED-CHECK: blob data = '$s7module20A4FuncSiyF' -// MERGED-CHECK-NEXT: +// MERGED-CHECK-NEXT: // MERGED-CHECK-NEXT: import module2 func foo() { bar(0) } func bar(_ i: Int) { - if (i == 0) { return } + if (i == 0) { return } foo() } @@ -49,8 +52,10 @@ public func publicFunc() { foo() } -public struct X { - func method1() { - publicFunc() - } -} +// public struct X { +// func method1() { +// publicFunc() +// } +// } + +publicFunc() diff --git a/tools/driver/cross_module_opt_main.cpp b/tools/driver/cross_module_opt_main.cpp index 935124175bb01..48e588c6cf15b 100644 --- a/tools/driver/cross_module_opt_main.cpp +++ b/tools/driver/cross_module_opt_main.cpp @@ -9,6 +9,7 @@ #include "swift/Serialization/Validation.h" #include "swift/Subsystems.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/Bitstream/BitstreamReader.h" #include "llvm/Option/ArgList.h" #include "llvm/Option/Option.h" @@ -75,7 +76,52 @@ class MergeModuleSummaryInvocation { } }; -class ModuleSummaryLinker {}; +static llvm::DenseSet computePreservedGUIDs() { + llvm::DenseSet Set(1); + Set.insert(getGUID("main")); + return Set; +} + +void markDeadSymbols(ModuleSummaryIndex &summary, llvm::DenseSet &PreservedGUIDs) { + + SmallVector Worklist; + unsigned LiveSymbols = 0; + + for (auto GUID : PreservedGUIDs) { + Worklist.push_back(GUID); + } + + while (!Worklist.empty()) { + auto GUID = Worklist.pop_back_val(); + + auto maybePair = summary.getFunctionInfo(GUID); + if (!maybePair) { + llvm_unreachable("Bad GUID"); + } + auto pair = maybePair.getValue(); + auto FS = pair.first; + if (FS->isLive()) continue; + + llvm::dbgs() << "Mark " << pair.second << " as live\n"; + FS->setLive(true); + LiveSymbols++; + + for (auto Call : FS->calls()) { + switch (Call.getKind()) { + case FunctionSummary::EdgeTy::Kind::Static: { + Worklist.push_back(Call.getCallee()); + continue; + } + case FunctionSummary::EdgeTy::Kind::Witness: + case FunctionSummary::EdgeTy::Kind::VTable: { + llvm_unreachable("Witness and VTable calls are not supported yet."); + } + case FunctionSummary::EdgeTy::Kind::kindCount: + llvm_unreachable("impossible"); + } + } + } +} int cross_module_opt_main(ArrayRef Args, const char *Argv0, void *MainAddr) { @@ -113,6 +159,9 @@ int cross_module_opt_main(ArrayRef Args, const char *Argv0, } TheSummary->setModuleName("combined"); + + auto PreservedGUIDs = computePreservedGUIDs(); + markDeadSymbols(*TheSummary.get(), PreservedGUIDs); modulesummary::emitModuleSummaryIndex(*TheSummary, Instance.getDiags(), Invocation.getOutputFilename()); From ef0ed0ad1bcfcbd3b445f5b209899184920db640 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Sat, 4 Jul 2020 16:02:20 +0900 Subject: [PATCH 10/77] Serialize live mark --- .../swift/Serialization/ModuleSummaryFile.h | 1 + lib/Serialization/ModuleSummaryFile.cpp | 9 ++++++--- test/Serialization/module-summary.swift | 19 +++++++++++++------ 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/include/swift/Serialization/ModuleSummaryFile.h b/include/swift/Serialization/ModuleSummaryFile.h index 3ce08c8c6ce58..c02cba1208c00 100644 --- a/include/swift/Serialization/ModuleSummaryFile.h +++ b/include/swift/Serialization/ModuleSummaryFile.h @@ -44,6 +44,7 @@ enum { using MetadataLayout = BCRecordLayout, // Function GUID + BCFixed<1>, // live BCBlob // Name string >; using CallGraphEdgeLayout = diff --git a/lib/Serialization/ModuleSummaryFile.cpp b/lib/Serialization/ModuleSummaryFile.cpp index 9427c2dd9d074..8cb8da1fb70d6 100644 --- a/lib/Serialization/ModuleSummaryFile.cpp +++ b/lib/Serialization/ModuleSummaryFile.cpp @@ -96,14 +96,15 @@ void Serializer::emitModuleSummary(const ModuleSummaryIndex &index) { for (const auto &pair : index) { llvm::BCBlockRAII restoreBlock(Out, FUNCTION_SUMMARY_ID, 4); auto &info = pair.second; + auto &summary = info.TheSummary; using namespace function_summary; function_summary::MetadataLayout MDlayout(Out); llvm::dbgs() << "Emitting " << info.Name << "\n"; - MDlayout.emit(ScratchRecord, pair.first, info.Name); + MDlayout.emit(ScratchRecord, pair.first, summary->isLive(), info.Name); - for (auto call : info.TheSummary->calls()) { + for (auto call : summary->calls()) { CallGraphEdgeLayout edgeLayout(Out); edgeLayout.emit(ScratchRecord, unsigned(call.getKind()), call.getCallee()); @@ -216,7 +217,8 @@ bool Deserializer::readFunctionSummary() { switch (maybeKind.get()) { case function_summary::METADATA: { - function_summary::MetadataLayout::readRecord(Scratch, guid); + unsigned isLive; + function_summary::MetadataLayout::readRecord(Scratch, guid, isLive); Name = BlobData.str(); if (auto info = moduleSummary.getFunctionInfo(guid)) { FS = info.getValue().first; @@ -224,6 +226,7 @@ bool Deserializer::readFunctionSummary() { NewFSOwner = std::make_unique(); FS = NewFSOwner.get(); } + FS->setLive(isLive); break; } case function_summary::CALL_GRAPH_EDGE: { diff --git a/test/Serialization/module-summary.swift b/test/Serialization/module-summary.swift index d7f8aefc4ff9d..eed235453a5d2 100644 --- a/test/Serialization/module-summary.swift +++ b/test/Serialization/module-summary.swift @@ -6,17 +6,17 @@ // RUN: %target-swift-frontend -emit-module-summary %s -I %t -o %t // RUN: llvm-bcanalyzer -dump %t/module-summary.swiftmodule.summary | %FileCheck %s --check-prefix MAIN-CHECK -// MAIN-CHECK: blob data = '$s4main10publicFuncyyF' +// MAIN-CHECK: blob data = '$s4main10publicFuncyyF' // Ensure that call graph edge has correct function guid -// MAIN-CHECK: blob data = '$s7module20A4FuncSiyF' -// MAIN-CHECK: blob data = 'main' +// MAIN-CHECK: blob data = '$s7module20A4FuncSiyF' +// MAIN-CHECK: blob data = 'main' // MAIN-CHECK-NEXT: // MAIN-CHECK-NEXT: -// MAIN-CHECK: blob data = '$s4main9callTwiceyyF' +// MAIN-CHECK: blob data = '$s4main9callTwiceyyF' // MAIN-CHECK-NEXT: // MAIN-CHECK-NEXT: // MAIN-CHECK-NEXT: @@ -24,13 +24,20 @@ // RUN: %swift_frontend_plain -cross-module-opt %t/module-summary.swiftmodule.summary %t/module1.swiftmodule.summary %t/module2.swiftmodule.summary -o %t/merged-module.summary // RUN: llvm-bcanalyzer -dump %t/merged-module.summary | %FileCheck %s --check-prefix MERGED-CHECK -// MERGED-CHECK: blob data = '$s7module10A4FuncSiyF' +// MERGED-CHECK: blob data = '$s7module10A4FuncSiyF' // MERGED-CHECK-NEXT: -// MERGED-CHECK: blob data = '$s7module20A4FuncSiyF' +// MERGED-CHECK: blob data = '$s7module20A4FuncSiyF' // MERGED-CHECK-NEXT: // MERGED-CHECK-NEXT: +// RUN: llvm-bcanalyzer -dump %t/merged-module.summary | %FileCheck %s --check-prefix LIVE-CHECK + +// LIVE-CHECK-DAG: blob data = '$s4main10publicFuncyyF' +// LIVE-CHECK-DAG: blob data = '$s4main3fooyyF' +// LIVE-CHECK-DAG: blob data = 'main' +// LIVE-CHECK-DAG: blob data = '$s4main3baryySiF' + import module2 func foo() { bar(0) } From 26e0a003363ecc122098c4f5526979f50d3cd65d Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Sat, 4 Jul 2020 17:20:58 +0900 Subject: [PATCH 11/77] Move option as frontend only --- include/swift/Option/FrontendOptions.td | 3 +++ include/swift/Option/Options.td | 3 --- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/swift/Option/FrontendOptions.td b/include/swift/Option/FrontendOptions.td index 92d1cbe1f4117..af1bb131879f2 100644 --- a/include/swift/Option/FrontendOptions.td +++ b/include/swift/Option/FrontendOptions.td @@ -40,6 +40,9 @@ def emit_module_doc_path def emit_module_source_info : Flag<["-"], "emit-module-source-info">, HelpText<"Output module source info file">; + +def emit_module_summary : Flag<["-"], "emit-module-summary">, + HelpText<"Emit module summary">; def ignore_module_source_info : Flag<["-"], "ignore-module-source-info">, HelpText<"Avoid getting source location from .swiftsourceinfo files">; diff --git a/include/swift/Option/Options.td b/include/swift/Option/Options.td index f2ed910f4f2d8..d76685bf7d540 100644 --- a/include/swift/Option/Options.td +++ b/include/swift/Option/Options.td @@ -918,9 +918,6 @@ def emit_imported_modules : Flag<["-"], "emit-imported-modules">, def emit_pcm : Flag<["-"], "emit-pcm">, HelpText<"Emit a precompiled Clang module from a module map">, ModeOpt, Flags<[FrontendOption, NoInteractiveOption, DoesNotAffectIncrementalBuild]>; -def emit_module_summary : Flag<["-"], "emit-module-summary">, - HelpText<"Emit module summary">, ModeOpt, - Flags<[FrontendOption, NoInteractiveOption, DoesNotAffectIncrementalBuild]>; def c : Flag<["-"], "c">, Alias, Flags<[FrontendOption, NoInteractiveOption]>, ModeOpt; From 4b919cc304f0a6302643e7e1fcee759e9ba5af95 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Sat, 4 Jul 2020 17:37:59 +0900 Subject: [PATCH 12/77] Add -module-summary-path option --- include/swift/Frontend/FrontendOptions.h | 2 ++ include/swift/Option/FrontendOptions.td | 4 ++++ lib/Frontend/ArgsToFrontendOptionsConverter.cpp | 3 +++ 3 files changed, 9 insertions(+) diff --git a/include/swift/Frontend/FrontendOptions.h b/include/swift/Frontend/FrontendOptions.h index a165759611715..987d8859b7edb 100644 --- a/include/swift/Frontend/FrontendOptions.h +++ b/include/swift/Frontend/FrontendOptions.h @@ -72,6 +72,8 @@ class FrontendOptions { /// The path to which we should store indexing data, if any. std::string IndexStorePath; + /// The path to combined module summary file + std::string ModuleSummaryPath; /// The path to look in when loading a module interface file, to see if a /// binary module has already been built for use by the compiler. std::string PrebuiltModuleCachePath; diff --git a/include/swift/Option/FrontendOptions.td b/include/swift/Option/FrontendOptions.td index af1bb131879f2..100558f362980 100644 --- a/include/swift/Option/FrontendOptions.td +++ b/include/swift/Option/FrontendOptions.td @@ -44,6 +44,10 @@ def emit_module_source_info : Flag<["-"], "emit-module-source-info">, def emit_module_summary : Flag<["-"], "emit-module-summary">, HelpText<"Emit module summary">; +def module_summary_path + : Separate<["-"], "module-summary-path">, MetaVarName<"">, + HelpText<"Combined module summary file ">; + def ignore_module_source_info : Flag<["-"], "ignore-module-source-info">, HelpText<"Avoid getting source location from .swiftsourceinfo files">; diff --git a/lib/Frontend/ArgsToFrontendOptionsConverter.cpp b/lib/Frontend/ArgsToFrontendOptionsConverter.cpp index 04cc506a2d68c..5806c404fdf13 100644 --- a/lib/Frontend/ArgsToFrontendOptionsConverter.cpp +++ b/lib/Frontend/ArgsToFrontendOptionsConverter.cpp @@ -57,6 +57,9 @@ bool ArgsToFrontendOptionsConverter::convert( if (const Arg *A = Args.getLastArg(OPT_group_info_path)) { Opts.GroupInfoPath = A->getValue(); } + if (const Arg *A = Args.getLastArg(OPT_module_summary_path)) { + Opts.ModuleSummaryPath = A->getValue(); + } if (const Arg *A = Args.getLastArg(OPT_index_store_path)) { Opts.IndexStorePath = A->getValue(); } From 6f97373ddb312e240869e57f7c38811ac20e8835 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Sat, 4 Jul 2020 19:42:27 +0900 Subject: [PATCH 13/77] Add optimize passes --- include/swift/AST/SILOptions.h | 3 + include/swift/Frontend/FrontendOptions.h | 6 +- include/swift/Option/Options.td | 6 ++ .../swift/SILOptimizer/PassManager/Passes.def | 2 + .../ArgsToFrontendOptionsConverter.cpp | 6 +- lib/Frontend/CompilerInvocation.cpp | 4 + lib/Frontend/FrontendOptions.cpp | 14 ---- lib/FrontendTool/FrontendTool.cpp | 19 +++-- lib/SILOptimizer/IPO/CMakeLists.txt | 1 + .../IPO/CrossDeadFunctionElimination.cpp | 78 +++++++++++++++++++ lib/SILOptimizer/PassManager/PassPipeline.cpp | 10 ++- test/Serialization/module-summary.swift | 18 ++++- 12 files changed, 133 insertions(+), 34 deletions(-) create mode 100644 lib/SILOptimizer/IPO/CrossDeadFunctionElimination.cpp diff --git a/include/swift/AST/SILOptions.h b/include/swift/AST/SILOptions.h index af8d8c29f2c69..5570802f7bdfe 100644 --- a/include/swift/AST/SILOptions.h +++ b/include/swift/AST/SILOptions.h @@ -153,6 +153,9 @@ class SILOptions { /// Enable large loadable types IRGen pass. bool EnableLargeLoadableTypes = true; + /// The path to combined module summary file + std::string ModuleSummaryPath; + /// The name of the file to which the backend should save optimization /// records. std::string OptRecordFile; diff --git a/include/swift/Frontend/FrontendOptions.h b/include/swift/Frontend/FrontendOptions.h index 987d8859b7edb..1271b437391a6 100644 --- a/include/swift/Frontend/FrontendOptions.h +++ b/include/swift/Frontend/FrontendOptions.h @@ -72,8 +72,8 @@ class FrontendOptions { /// The path to which we should store indexing data, if any. std::string IndexStorePath; - /// The path to combined module summary file - std::string ModuleSummaryPath; + /// The path to which we should emit combined module summary file + std::string ModuleSummaryOutputPath; /// The path to look in when loading a module interface file, to see if a /// binary module has already been built for use by the compiler. std::string PrebuiltModuleCachePath; @@ -113,8 +113,6 @@ class FrontendOptions { EmitSILGen, ///< Emit raw SIL EmitSIL, ///< Emit canonical SIL - EmitModuleSummary, /// < Emit module summary - EmitModuleOnly, ///< Emit module only MergeModules, ///< Merge modules only diff --git a/include/swift/Option/Options.td b/include/swift/Option/Options.td index d76685bf7d540..9584e008723c1 100644 --- a/include/swift/Option/Options.td +++ b/include/swift/Option/Options.td @@ -443,6 +443,12 @@ def emit_module_path_EQ : Joined<["-"], "emit-module-path=">, ArgumentIsPath, SupplementaryOutput]>, Alias; +def emit_module_summary_path : Separate<["-"], "emit-module-summary-path">, + Flags<[FrontendOption, NoInteractiveOption, DoesNotAffectIncrementalBuild, + ArgumentIsPath, SupplementaryOutput]>, + HelpText<"Emit a module summary to ">, + MetaVarName<"">; + def emit_module_interface : Flag<["-"], "emit-module-interface">, Flags<[NoInteractiveOption, DoesNotAffectIncrementalBuild, diff --git a/include/swift/SILOptimizer/PassManager/Passes.def b/include/swift/SILOptimizer/PassManager/Passes.def index 46e11b243424c..ed6eb62953dd9 100644 --- a/include/swift/SILOptimizer/PassManager/Passes.def +++ b/include/swift/SILOptimizer/PassManager/Passes.def @@ -66,6 +66,8 @@ PASS(AccessEnforcementWMO, "access-enforcement-wmo", "Access Enforcement Whole Module Optimization") PASS(CrossModuleSerializationSetup, "cross-module-serialization-setup", "Setup serialization flags for cross-module optimization") +PASS(CrossDeadFunctionElimination, "sil-cross-deadfuncelim", + "Cross Dead Function Elimination") PASS(AccessSummaryDumper, "access-summary-dump", "Dump Address Parameter Access Summary") PASS(AccessedStorageAnalysisDumper, "accessed-storage-analysis-dump", diff --git a/lib/Frontend/ArgsToFrontendOptionsConverter.cpp b/lib/Frontend/ArgsToFrontendOptionsConverter.cpp index 5806c404fdf13..267a2c05c36ea 100644 --- a/lib/Frontend/ArgsToFrontendOptionsConverter.cpp +++ b/lib/Frontend/ArgsToFrontendOptionsConverter.cpp @@ -57,8 +57,8 @@ bool ArgsToFrontendOptionsConverter::convert( if (const Arg *A = Args.getLastArg(OPT_group_info_path)) { Opts.GroupInfoPath = A->getValue(); } - if (const Arg *A = Args.getLastArg(OPT_module_summary_path)) { - Opts.ModuleSummaryPath = A->getValue(); + if (const Arg *A = Args.getLastArg(OPT_emit_module_summary_path)) { + Opts.ModuleSummaryOutputPath = A->getValue(); } if (const Arg *A = Args.getLastArg(OPT_index_store_path)) { Opts.IndexStorePath = A->getValue(); @@ -391,8 +391,6 @@ ArgsToFrontendOptionsConverter::determineRequestedAction(const ArgList &args) { return FrontendOptions::ActionType::Immediate; if (Opt.matches(OPT_compile_module_from_interface)) return FrontendOptions::ActionType::CompileModuleFromInterface; - if (Opt.matches(OPT_emit_module_summary)) - return FrontendOptions::ActionType::EmitModuleSummary; llvm_unreachable("Unhandled mode option"); } diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 2b623be2cf615..9d3784ff91359 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -1189,6 +1189,10 @@ static bool ParseSILArgs(SILOptions &Opts, ArgList &Args, if (const Arg *A = Args.getLastArg(OPT_save_optimization_record_path)) Opts.OptRecordFile = A->getValue(); + if (const Arg *A = Args.getLastArg(OPT_module_summary_path)) { + Opts.ModuleSummaryPath = A->getValue(); + } + if (Args.hasArg(OPT_debug_on_sil)) { // Derive the name of the SIL file for debugging from // the regular outputfile. diff --git a/lib/Frontend/FrontendOptions.cpp b/lib/Frontend/FrontendOptions.cpp index c258b2895554d..1e1253ddcb6c5 100644 --- a/lib/Frontend/FrontendOptions.cpp +++ b/lib/Frontend/FrontendOptions.cpp @@ -48,7 +48,6 @@ bool FrontendOptions::needsProperModuleName(ActionType action) { case ActionType::EmitSIL: case ActionType::EmitSIBGen: case ActionType::EmitSIB: - case ActionType::EmitModuleSummary: case ActionType::EmitModuleOnly: case ActionType::MergeModules: case ActionType::CompileModuleFromInterface: @@ -146,9 +145,6 @@ FrontendOptions::formatForPrincipalOutputFileForAction(ActionType action) { case ActionType::EmitSIB: return TY_SIB; - case ActionType::EmitModuleSummary: - return TY_SwiftModuleSummaryFile; - case ActionType::MergeModules: case ActionType::EmitModuleOnly: case ActionType::CompileModuleFromInterface: @@ -205,7 +201,6 @@ bool FrontendOptions::canActionEmitDependencies(ActionType action) { case ActionType::Typecheck: case ActionType::MergeModules: case ActionType::EmitModuleOnly: - case ActionType::EmitModuleSummary: case ActionType::EmitPCH: case ActionType::EmitSILGen: case ActionType::EmitSIL: @@ -252,7 +247,6 @@ bool FrontendOptions::canActionEmitReferenceDependencies(ActionType action) { case ActionType::EmitSIL: case ActionType::EmitSIBGen: case ActionType::EmitSIB: - case ActionType::EmitModuleSummary: case ActionType::EmitIR: case ActionType::EmitBC: case ActionType::EmitAssembly: @@ -300,7 +294,6 @@ bool FrontendOptions::canActionEmitObjCHeader(ActionType action) { case ActionType::EmitSIL: case ActionType::EmitSIBGen: case ActionType::EmitSIB: - case ActionType::EmitModuleSummary: case ActionType::EmitIR: case ActionType::EmitBC: case ActionType::EmitAssembly: @@ -340,7 +333,6 @@ bool FrontendOptions::canActionEmitLoadedModuleTrace(ActionType action) { case ActionType::EmitSIL: case ActionType::EmitSIBGen: case ActionType::EmitSIB: - case ActionType::EmitModuleSummary: case ActionType::EmitIR: case ActionType::EmitBC: case ActionType::EmitAssembly: @@ -380,7 +372,6 @@ bool FrontendOptions::canActionEmitModule(ActionType action) { case ActionType::EmitSIL: case ActionType::EmitSIBGen: case ActionType::EmitSIB: - case ActionType::EmitModuleSummary: case ActionType::EmitIR: case ActionType::EmitBC: case ActionType::EmitAssembly: @@ -424,7 +415,6 @@ bool FrontendOptions::canActionEmitInterface(ActionType action) { case ActionType::EmitModuleOnly: case ActionType::EmitSIL: case ActionType::EmitSIB: - case ActionType::EmitModuleSummary: case ActionType::EmitIR: case ActionType::EmitBC: case ActionType::EmitAssembly: @@ -452,7 +442,6 @@ bool FrontendOptions::doesActionProduceOutput(ActionType action) { case ActionType::EmitSIL: case ActionType::EmitSIBGen: case ActionType::EmitSIB: - case ActionType::EmitModuleSummary: case ActionType::EmitModuleOnly: case ActionType::EmitAssembly: case ActionType::EmitIR: @@ -482,7 +471,6 @@ bool FrontendOptions::doesActionProduceTextualOutput(ActionType action) { case ActionType::EmitPCH: case ActionType::EmitSIBGen: case ActionType::EmitSIB: - case ActionType::EmitModuleSummary: case ActionType::MergeModules: case ActionType::EmitModuleOnly: case ActionType::CompileModuleFromInterface: @@ -542,7 +530,6 @@ bool FrontendOptions::doesActionGenerateSIL(ActionType action) { case ActionType::EmitSIBGen: case ActionType::EmitSIL: case ActionType::EmitSIB: - case ActionType::EmitModuleSummary: case ActionType::EmitModuleOnly: case ActionType::MergeModules: case ActionType::Immediate: @@ -579,7 +566,6 @@ bool FrontendOptions::doesActionGenerateIR(ActionType action) { case ActionType::EmitSIL: case ActionType::EmitSIBGen: case ActionType::EmitSIB: - case ActionType::EmitModuleSummary: case ActionType::EmitImportedModules: case ActionType::EmitPCM: case ActionType::DumpPCM: diff --git a/lib/FrontendTool/FrontendTool.cpp b/lib/FrontendTool/FrontendTool.cpp index b8d17a7e5c5d5..85a5d0c6d889d 100644 --- a/lib/FrontendTool/FrontendTool.cpp +++ b/lib/FrontendTool/FrontendTool.cpp @@ -1826,11 +1826,13 @@ static bool serializeSIB(SILModule *SM, const PrimarySpecificPaths &PSPs, return Context.hadError(); } -static bool emitModuleSummary(SILModule *SM, const PrimarySpecificPaths &PSPs, +static bool emitModuleSummary(SILModule *SM, + const std::string &ModuleSummaryOutputPath, const ASTContext &Context) { - BasicCalleeAnalysis BCA(SM); - auto Summary = buildModuleSummaryIndex(*SM, BCA); - return modulesummary::emitModuleSummaryIndex(Summary, Context.Diags, PSPs.OutputFilename); + BasicCalleeAnalysis BCA(SM); + auto Summary = buildModuleSummaryIndex(*SM, BCA); + return modulesummary::emitModuleSummaryIndex(Summary, Context.Diags, + ModuleSummaryOutputPath); } static GeneratedModule @@ -2059,10 +2061,11 @@ static bool performCompileStepsPostSILGen(CompilerInstance &Instance, if (Action == FrontendOptions::ActionType::EmitSIB) return serializeSIB(SM.get(), PSPs, Context, MSF); - - - if (Action == FrontendOptions::ActionType::EmitModuleSummary) { - return emitModuleSummary(SM.get(), PSPs, Context); + + if (!opts.ModuleSummaryOutputPath.empty()) { + if (emitModuleSummary(SM.get(), opts.ModuleSummaryOutputPath, Context)) { + return true; + } } if (PSPs.haveModuleOrModuleDocOutputPaths()) { diff --git a/lib/SILOptimizer/IPO/CMakeLists.txt b/lib/SILOptimizer/IPO/CMakeLists.txt index f9324eaafa21a..053a1c63bde75 100644 --- a/lib/SILOptimizer/IPO/CMakeLists.txt +++ b/lib/SILOptimizer/IPO/CMakeLists.txt @@ -2,6 +2,7 @@ target_sources(swiftSILOptimizer PRIVATE CapturePromotion.cpp CapturePropagation.cpp ClosureSpecializer.cpp + CrossDeadFunctionElimination.cpp CrossModuleSerializationSetup.cpp DeadFunctionElimination.cpp GlobalOpt.cpp diff --git a/lib/SILOptimizer/IPO/CrossDeadFunctionElimination.cpp b/lib/SILOptimizer/IPO/CrossDeadFunctionElimination.cpp new file mode 100644 index 0000000000000..216cfeec2c5b8 --- /dev/null +++ b/lib/SILOptimizer/IPO/CrossDeadFunctionElimination.cpp @@ -0,0 +1,78 @@ +#define DEBUG_TYPE "sil-cross-dead-function-elimination" +#include "swift/AST/DiagnosticsFrontend.h" +#include "swift/AST/ProtocolConformance.h" +#include "swift/SIL/InstructionUtils.h" +#include "swift/SIL/PatternMatch.h" +#include "swift/SIL/SILBuilder.h" +#include "swift/SIL/SILVisitor.h" +#include "swift/SILOptimizer/PassManager/Passes.h" +#include "swift/SILOptimizer/PassManager/Transforms.h" +#include "swift/Serialization/ModuleSummaryFile.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +using namespace swift; + +STATISTIC(NumDeadFunc, "Number of dead functions eliminated"); + +//===----------------------------------------------------------------------===// +// Pass Definition and Entry Points +//===----------------------------------------------------------------------===// + +namespace { + +class SILCrossDeadFuncElimination : public SILModuleTransform { +private: + ModuleSummaryIndex TheSummary; + +public: + SILCrossDeadFuncElimination() {} + + void run() override { + LLVM_DEBUG(llvm::dbgs() << "Running CrossDeadFuncElimination\n"); + auto &Context = getModule()->getASTContext(); + auto ModuleSummaryPath = getOptions().ModuleSummaryPath; + auto ErrOrBuf = llvm::MemoryBuffer::getFile(ModuleSummaryPath); + if (!ErrOrBuf) { + Context.Diags.diagnose(SourceLoc(), diag::error_no_such_file_or_directory, + ModuleSummaryPath); + return; + } + + auto HasErr = modulesummary::loadModuleSummaryIndex( + ErrOrBuf.get()->getMemBufferRef(), TheSummary); + if (HasErr) { + llvm::report_fatal_error("Invalid module summary"); + } + + auto M = getModule(); + + for (auto &pair : TheSummary) { + auto &info = pair.second; + if (info.TheSummary->isLive()) { + continue; + } + + auto F = M->lookUpFunction(info.Name); + if (!F) { + llvm::dbgs() << "Couldn't eliminate " << info.Name + << " because it's not found\n"; + continue; + } + F->dropAllReferences(); + notifyWillDeleteFunction(F); + M->eraseFunction(F); + + llvm::dbgs() << "Eliminate " << info.Name << "\n"; + } + this->invalidateFunctionTables(); + } +}; + +} // end anonymous namespace + +SILTransform *swift::createCrossDeadFunctionElimination() { + return new SILCrossDeadFuncElimination(); +} diff --git a/lib/SILOptimizer/PassManager/PassPipeline.cpp b/lib/SILOptimizer/PassManager/PassPipeline.cpp index ee6de4e92a26d..c1b2e9606cd36 100644 --- a/lib/SILOptimizer/PassManager/PassPipeline.cpp +++ b/lib/SILOptimizer/PassManager/PassPipeline.cpp @@ -410,6 +410,13 @@ static void addPerfDebugSerializationPipeline(SILPassPipelinePlan &P) { P.addPerformanceSILLinker(); } +static void addCrossModuleOptimizationsPipeline(SILPassPipelinePlan &P, + const SILOptions &Options) { + P.startPipeline("Cross Module Optimization Passes"); + if (!Options.ModuleSummaryPath.empty()) { + P.addCrossDeadFunctionElimination(); + } +} static void addPrepareOptimizationsPipeline(SILPassPipelinePlan &P) { P.startPipeline("PrepareOptimizationPasses"); @@ -710,7 +717,8 @@ SILPassPipelinePlan::getPerformancePassPipeline(const SILOptions &Options) { addPerfDebugSerializationPipeline(P); return P; } - + + addCrossModuleOptimizationsPipeline(P, Options); // Passes which run once before all other optimizations run. Those passes are // _not_ intended to run later again. addPrepareOptimizationsPipeline(P); diff --git a/test/Serialization/module-summary.swift b/test/Serialization/module-summary.swift index eed235453a5d2..d631b30d1c246 100644 --- a/test/Serialization/module-summary.swift +++ b/test/Serialization/module-summary.swift @@ -1,9 +1,9 @@ // RUN: %empty-directory(%t) // RUN: %target-swift-frontend -emit-module %S/Inputs/module1.swift -parse-as-library -o %t -// RUN: %target-swift-frontend -emit-module-summary %S/Inputs/module1.swift -parse-as-library -o %t +// RUN: %target-swift-frontend -emit-sil %S/Inputs/module1.swift -emit-module-summary-path %t/module1.swiftmodule.summary -parse-as-library > /dev/null // RUN: %target-swift-frontend -emit-module %S/Inputs/module2.swift -parse-as-library -I %t -o %t -// RUN: %target-swift-frontend -emit-module-summary %S/Inputs/module2.swift -parse-as-library -I %t -o %t -// RUN: %target-swift-frontend -emit-module-summary %s -I %t -o %t +// RUN: %target-swift-frontend -emit-sil %S/Inputs/module2.swift -emit-module-summary-path %t/module2.swiftmodule.summary -I %t -parse-as-library > /dev/null +// RUN: %target-swift-frontend -emit-sil %s -emit-module-summary-path %t/module-summary.swiftmodule.summary -I %t > /dev/null // RUN: llvm-bcanalyzer -dump %t/module-summary.swiftmodule.summary | %FileCheck %s --check-prefix MAIN-CHECK // MAIN-CHECK: blob data = '$s4main10publicFuncyyF' @@ -38,6 +38,18 @@ // LIVE-CHECK-DAG: blob data = 'main' // LIVE-CHECK-DAG: blob data = '$s4main3baryySiF' +// RUN: %target-swift-frontend -emit-sil %s -module-summary-path %t/merged-module.summary -O -I %t | %FileCheck %s --check-prefix DEADFUNC-CHECK +// DEADFUNC-CHECK: @main +// DEADFUNC-CHECK: @$s4main3baryySiF +// DEADFUNC-CHECK: @$s4main10publicFuncyyF + +// DEADFUNC-CHECK-NOT: @$s4main16callExternalFuncyyF +// DEADFUNC-CHECK-NOT: @$sSi2eeoiySbSi_SitFZ +// DEADFUNC-CHECK-NOT: @$s7module20A4FuncSiyF +// DEADFUNC-CHECK-NOT: @$sSi22_builtinIntegerLiteralSiBI_tcfC +// DEADFUNC-CHECK-NOT: @$s4main9callTwiceyyF + + import module2 func foo() { bar(0) } From 2fd0b68b2f36fd8b3442ac8db994c2b9aa24d8fd Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Sat, 4 Jul 2020 20:06:44 +0900 Subject: [PATCH 14/77] Add option to sil-opt --- test/Serialization/module-summary.swift | 16 ++++++---------- tools/sil-opt/SILOpt.cpp | 7 +++++++ 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/test/Serialization/module-summary.swift b/test/Serialization/module-summary.swift index d631b30d1c246..dfb00f0b3e5b3 100644 --- a/test/Serialization/module-summary.swift +++ b/test/Serialization/module-summary.swift @@ -38,10 +38,12 @@ // LIVE-CHECK-DAG: blob data = 'main' // LIVE-CHECK-DAG: blob data = '$s4main3baryySiF' -// RUN: %target-swift-frontend -emit-sil %s -module-summary-path %t/merged-module.summary -O -I %t | %FileCheck %s --check-prefix DEADFUNC-CHECK -// DEADFUNC-CHECK: @main -// DEADFUNC-CHECK: @$s4main3baryySiF -// DEADFUNC-CHECK: @$s4main10publicFuncyyF +// RUN: %target-swift-frontend -emit-sil %s -I %t -o %t/main.sil +// RUN: %target-sil-opt -emit-sorted-sil %t/main.sil -module-summary-path %t/merged-module.summary --sil-cross-deadfuncelim -I %t | %FileCheck %s --check-prefix DEADFUNC-CHECK +// RUN: %target-swift-frontend -emit-sil %s -module-summary-path %t/merged-module.summary -I %t -O | %FileCheck %s --check-prefix DEADFUNC-CHECK +// DEADFUNC-CHECK-DAG: @$s4main10publicFuncyyF +// DEADFUNC-CHECK-DAG: @$s4main3baryySiF +// DEADFUNC-CHECK-DAG: @main // DEADFUNC-CHECK-NOT: @$s4main16callExternalFuncyyF // DEADFUNC-CHECK-NOT: @$sSi2eeoiySbSi_SitFZ @@ -71,10 +73,4 @@ public func publicFunc() { foo() } -// public struct X { -// func method1() { -// publicFunc() -// } -// } - publicFunc() diff --git a/tools/sil-opt/SILOpt.cpp b/tools/sil-opt/SILOpt.cpp index 490bf85550abb..8a78ff7e7ca14 100644 --- a/tools/sil-opt/SILOpt.cpp +++ b/tools/sil-opt/SILOpt.cpp @@ -76,6 +76,9 @@ ModuleName("module-name", llvm::cl::desc("The name of the module if processing" " a module. Necessary for processing " "stdin.")); +static llvm::cl::opt +ModuleSummaryPath("module-summary-path", llvm::cl::desc("module summary filename")); + static llvm::cl::opt EnableLibraryEvolution("enable-library-evolution", llvm::cl::desc("Compile the module to export resilient " @@ -370,6 +373,10 @@ int main(int argc, char **argv) { SILOpts.OptRecordFile = RemarksFilename; SILOpts.OptRecordPasses = RemarksPasses; + if (!ModuleSummaryPath.empty()) { + SILOpts.ModuleSummaryPath = ModuleSummaryPath; + } + SILOpts.VerifyExclusivity = VerifyExclusivity; if (EnforceExclusivity.getNumOccurrences() != 0) { switch (EnforceExclusivity) { From 16ee0bcb6bfb9773dbc779c047ae932155ac2f29 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Sun, 5 Jul 2020 00:07:24 +0900 Subject: [PATCH 15/77] Refactor test case --- test/Serialization/module-summary.swift | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/test/Serialization/module-summary.swift b/test/Serialization/module-summary.swift index dfb00f0b3e5b3..aaadd8ec73651 100644 --- a/test/Serialization/module-summary.swift +++ b/test/Serialization/module-summary.swift @@ -1,8 +1,6 @@ // RUN: %empty-directory(%t) -// RUN: %target-swift-frontend -emit-module %S/Inputs/module1.swift -parse-as-library -o %t -// RUN: %target-swift-frontend -emit-sil %S/Inputs/module1.swift -emit-module-summary-path %t/module1.swiftmodule.summary -parse-as-library > /dev/null -// RUN: %target-swift-frontend -emit-module %S/Inputs/module2.swift -parse-as-library -I %t -o %t -// RUN: %target-swift-frontend -emit-sil %S/Inputs/module2.swift -emit-module-summary-path %t/module2.swiftmodule.summary -I %t -parse-as-library > /dev/null +// RUN: %target-swift-frontend -emit-module %S/Inputs/module1.swift -emit-module-summary-path %t/module1.swiftmodule.summary -parse-as-library -o %t +// RUN: %target-swift-frontend -emit-module %S/Inputs/module2.swift -emit-module-summary-path %t/module2.swiftmodule.summary -parse-as-library -I %t -o %t // RUN: %target-swift-frontend -emit-sil %s -emit-module-summary-path %t/module-summary.swiftmodule.summary -I %t > /dev/null // RUN: llvm-bcanalyzer -dump %t/module-summary.swiftmodule.summary | %FileCheck %s --check-prefix MAIN-CHECK From cfce5ccbcb9e73f9adbc565b1b5a2c8c00d18144 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Sun, 5 Jul 2020 10:04:42 +0900 Subject: [PATCH 16/77] Serialize table dispatch info --- include/swift/SIL/ModuleSummary.h | 39 +++++++++++++------ .../swift/Serialization/ModuleSummaryFile.h | 7 ++-- lib/SILOptimizer/Utils/ModuleSummaryIndex.cpp | 8 ++++ lib/Serialization/ModuleSummaryFile.cpp | 8 ++-- test/Serialization/Inputs/module1.swift | 4 ++ test/Serialization/Inputs/module2.swift | 4 ++ test/Serialization/module-summary.swift | 14 +++++-- 7 files changed, 62 insertions(+), 22 deletions(-) diff --git a/include/swift/SIL/ModuleSummary.h b/include/swift/SIL/ModuleSummary.h index 4f665126f3dd4..4368903c66b8a 100644 --- a/include/swift/SIL/ModuleSummary.h +++ b/include/swift/SIL/ModuleSummary.h @@ -15,8 +15,10 @@ static GUID getGUID(llvm::StringRef Str) { return llvm::MD5Hash(Str); } class FunctionSummary { public: class EdgeTy { + GUID CalleeFn; + GUID Table; public: - GUID CalleeFnOrTable; + enum class Kind { Static, Witness, @@ -26,17 +28,26 @@ class FunctionSummary { Kind kind; - EdgeTy(SILDeclRef CalleeFn, Kind kind) : kind(kind) { - // FIXME - auto name = CalleeFn.getDecl()->getBaseName().getIdentifier().str(); - this->CalleeFnOrTable = getGUID(name); + EdgeTy(FuncDecl &CalleeFn, TypeDecl &Context, Kind kind) : kind(kind) { + // FIXME: This is really fragile + this->CalleeFn = getGUID(CalleeFn.getBaseIdentifier().str()); + this->Table = getGUID(Context.getNameStr()); } public: Kind getKind() const { return kind; } - GUID getCallee() const { return CalleeFnOrTable; } + GUID getCallee() const { return CalleeFn; } + GUID getTable() const { + // If kind is static, Table guid should be 0 + assert(kind != Kind::Static || Table == 0); + return Table; + } + + EdgeTy(GUID callee, GUID table, Kind kind) + : CalleeFn(callee), Table(table), kind(kind) {} - EdgeTy(GUID callee, Kind kind) : CalleeFnOrTable(callee), kind(kind) {} + EdgeTy(GUID callee, Kind kind) + : CalleeFn(callee), Table(0), kind(kind) {} static EdgeTy staticCall(GUID Callee) { return EdgeTy(Callee, Kind::Static); @@ -48,10 +59,14 @@ class FunctionSummary { return EdgeTy(Callee, Kind::VTable); } static EdgeTy witnessCall(SILDeclRef Callee) { - return EdgeTy(Callee, Kind::Witness); + auto &Fn = *Callee.getFuncDecl(); + auto Context = dyn_cast(Fn.getDeclContext()); + return EdgeTy(Fn, *Context, Kind::Witness); } static EdgeTy vtableCall(SILDeclRef Callee) { - return EdgeTy(Callee, Kind::VTable); + auto &Fn = *Callee.getFuncDecl(); + auto Context = dyn_cast(Fn.getDeclContext()); + return EdgeTy(Fn, *Context, Kind::VTable); } }; @@ -71,8 +86,10 @@ class FunctionSummary { : CallGraphEdgeList(std::move(CGEdges)) {} FunctionSummary() = default; - void addCall(GUID targetGUID, EdgeTy::Kind kind) { - CallGraphEdgeList.emplace_back(targetGUID, kind); + void addCall(GUID targetGUID, GUID tableGUID, EdgeTy::Kind kind) { + // If kind is static, Table guid should be 0 + assert(kind != EdgeTy::Kind::Static || tableGUID == 0); + CallGraphEdgeList.emplace_back(targetGUID, tableGUID, kind); } ArrayRef calls() const { return CallGraphEdgeList; } diff --git a/include/swift/Serialization/ModuleSummaryFile.h b/include/swift/Serialization/ModuleSummaryFile.h index c02cba1208c00..a87b6454f3369 100644 --- a/include/swift/Serialization/ModuleSummaryFile.h +++ b/include/swift/Serialization/ModuleSummaryFile.h @@ -43,14 +43,15 @@ enum { }; using MetadataLayout = BCRecordLayout, // Function GUID + BCVBR<16>, // Function GUID BCFixed<1>, // live - BCBlob // Name string + BCBlob // Name string >; using CallGraphEdgeLayout = BCRecordLayout, // FunctionSummary::Edge::Kind - BCVBR<16> // Target GUID + BCVBR<16>, // Target Function GUID + BCVBR<16> // Table GUID >; } // namespace function_summary diff --git a/lib/SILOptimizer/Utils/ModuleSummaryIndex.cpp b/lib/SILOptimizer/Utils/ModuleSummaryIndex.cpp index 3306e5beb239d..7ce640c68db86 100644 --- a/lib/SILOptimizer/Utils/ModuleSummaryIndex.cpp +++ b/lib/SILOptimizer/Utils/ModuleSummaryIndex.cpp @@ -27,12 +27,20 @@ buildFunctionSummaryIndex(SILFunction &F, BasicCalleeAnalysis &BCA) { switch (Callee->getKind()) { case ValueKind::WitnessMethodInst: { auto WMI = cast(Callee); + auto member = WMI->getMember(); + auto CalleeFn = member.getFuncDecl(); + auto Protocol = dyn_cast(CalleeFn->getDeclContext()); + Protocol->getModuleContext()->getNameStr(); + llvm::dbgs() << "Record " << WMI->getMember().getFuncDecl()->getNameStr() + << " of " << Protocol->getNameStr() << " as reference to PWT\n"; + auto edge = FunctionSummary::EdgeTy::witnessCall(WMI->getMember()); CallGraphEdgeList.push_back(edge); break; } case ValueKind::ClassMethodInst: { auto CMI = cast(Callee); + llvm::dbgs() << "Record " << CMI->getMember().getDecl()->getBaseName().getIdentifier().str() << " as reference to VTable\n"; auto edge = FunctionSummary::EdgeTy::vtableCall(CMI->getMember()); CallGraphEdgeList.push_back(edge); break; diff --git a/lib/Serialization/ModuleSummaryFile.cpp b/lib/Serialization/ModuleSummaryFile.cpp index 8cb8da1fb70d6..6b532c679e3c1 100644 --- a/lib/Serialization/ModuleSummaryFile.cpp +++ b/lib/Serialization/ModuleSummaryFile.cpp @@ -107,7 +107,7 @@ void Serializer::emitModuleSummary(const ModuleSummaryIndex &index) { for (auto call : summary->calls()) { CallGraphEdgeLayout edgeLayout(Out); edgeLayout.emit(ScratchRecord, unsigned(call.getKind()), - call.getCallee()); + call.getCallee(), call.getTable()); } } } @@ -231,16 +231,16 @@ bool Deserializer::readFunctionSummary() { } case function_summary::CALL_GRAPH_EDGE: { unsigned edgeKindID; - GUID targetGUID; + GUID targetGUID, targetTable; function_summary::CallGraphEdgeLayout::readRecord(Scratch, edgeKindID, - targetGUID); + targetGUID, targetTable); auto edgeKind = getEdgeKind(edgeKindID); if (!edgeKind) llvm::report_fatal_error("Bad edge kind"); if (!FS) llvm::report_fatal_error("Invalid state"); - FS->addCall(targetGUID, edgeKind.getValue()); + FS->addCall(targetGUID, targetTable, edgeKind.getValue()); break; } } diff --git a/test/Serialization/Inputs/module1.swift b/test/Serialization/Inputs/module1.swift index ac8bc0d030901..63afd92d17961 100644 --- a/test/Serialization/Inputs/module1.swift +++ b/test/Serialization/Inputs/module1.swift @@ -1 +1,5 @@ public func module1Func() -> Int { return 1 } + +public protocol P { + func memberMethod() +} diff --git a/test/Serialization/Inputs/module2.swift b/test/Serialization/Inputs/module2.swift index b2e88ee83e44a..b5676496a3815 100644 --- a/test/Serialization/Inputs/module2.swift +++ b/test/Serialization/Inputs/module2.swift @@ -3,3 +3,7 @@ import module1 public func module2Func() -> Int { return module1Func() } + +public func useP(_ t: T) { + t.memberMethod() +} diff --git a/test/Serialization/module-summary.swift b/test/Serialization/module-summary.swift index aaadd8ec73651..cc196cdc9e0b3 100644 --- a/test/Serialization/module-summary.swift +++ b/test/Serialization/module-summary.swift @@ -10,15 +10,21 @@ // Ensure that call graph edge has correct function guid // MAIN-CHECK: blob data = '$s7module20A4FuncSiyF' // MAIN-CHECK: blob data = 'main' -// MAIN-CHECK-NEXT: +// MAIN-CHECK-NEXT: // MAIN-CHECK-NEXT: // MAIN-CHECK: blob data = '$s4main9callTwiceyyF' -// MAIN-CHECK-NEXT: -// MAIN-CHECK-NEXT: +// MAIN-CHECK-NEXT: +// MAIN-CHECK-NEXT: // MAIN-CHECK-NEXT: +// RUN: llvm-bcanalyzer -dump %t/module2.swiftmodule.summary | %FileCheck %s --check-prefix TABLE-CHECK +// TABLE-CHECK: blob data = '$s7module24usePyyx7module11PRzlF' +// TABLE-CHECK-NEXT: +// TABLE-CHECK-NEXT: + + // RUN: %swift_frontend_plain -cross-module-opt %t/module-summary.swiftmodule.summary %t/module1.swiftmodule.summary %t/module2.swiftmodule.summary -o %t/merged-module.summary // RUN: llvm-bcanalyzer -dump %t/merged-module.summary | %FileCheck %s --check-prefix MERGED-CHECK @@ -26,7 +32,7 @@ // MERGED-CHECK-NEXT: // MERGED-CHECK: blob data = '$s7module20A4FuncSiyF' -// MERGED-CHECK-NEXT: +// MERGED-CHECK-NEXT: // MERGED-CHECK-NEXT: // RUN: llvm-bcanalyzer -dump %t/merged-module.summary | %FileCheck %s --check-prefix LIVE-CHECK From e659a35a80504b9dd2b6b95ee084b2364a55f110 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Sun, 5 Jul 2020 12:28:05 +0900 Subject: [PATCH 17/77] Index function tables --- include/swift/SIL/ModuleSummary.h | 57 +++++++++++++++++++ lib/SILOptimizer/Utils/ModuleSummaryIndex.cpp | 35 +++++++++++- 2 files changed, 90 insertions(+), 2 deletions(-) diff --git a/include/swift/SIL/ModuleSummary.h b/include/swift/SIL/ModuleSummary.h index 4368903c66b8a..34e0ccadacd56 100644 --- a/include/swift/SIL/ModuleSummary.h +++ b/include/swift/SIL/ModuleSummary.h @@ -12,6 +12,41 @@ namespace swift { using GUID = uint64_t; static GUID getGUID(llvm::StringRef Str) { return llvm::MD5Hash(Str); } +struct TableFuncSlot { + enum class KindTy { + Witness, VTable, + }; + + KindTy Kind; + GUID VirtualFuncID; + GUID TableID; + + TableFuncSlot(FuncDecl &VirtualFunc, TypeDecl &Context, KindTy kind) : Kind(kind) { + switch (Kind) { + case KindTy::Witness: { + assert(isa(Context)); + break; + } + case KindTy::VTable: { + assert(isa(Context)); + break; + } + } + VirtualFuncID = getGUID(VirtualFunc.getBaseIdentifier().str()); + TableID = getGUID(Context.getNameStr()); + } + + TableFuncSlot(FuncDecl &VirtualFunc, ProtocolDecl &Context) + : TableFuncSlot(VirtualFunc, Context, KindTy::Witness) { } + + TableFuncSlot(FuncDecl &VirtualFunc, ClassDecl &Context) + : TableFuncSlot(VirtualFunc, Context, KindTy::VTable) { } + + bool operator<(const TableFuncSlot &rhs) const { + return Kind < rhs.Kind && TableID < rhs.TableID && VirtualFuncID < rhs.VirtualFuncID; + } +}; + class FunctionSummary { public: class EdgeTy { @@ -105,7 +140,10 @@ struct FunctionSummaryInfo { class ModuleSummaryIndex { using FunctionSummaryInfoMapTy = std::map; + using FuncTableMapTy = std::map>; + FunctionSummaryInfoMapTy FunctionSummaryInfoMap; + FuncTableMapTy FuncTableMap; std::string ModuleName; // Only for debug purpose @@ -133,6 +171,25 @@ class ModuleSummaryIndex { auto &entry = found->second; return std::make_pair(entry.TheSummary.get(), StringRef(entry.Name)); } + + void addImplementation(TableFuncSlot slot, GUID funcGUID) { + auto found = FuncTableMap.find(slot); + if (found == FuncTableMap.end()) { + FuncTableMap.insert(std::make_pair(slot, std::vector{ funcGUID })); + return; + } + found->second.push_back(funcGUID); + } + + llvm::Optional> + getImplementations(TableFuncSlot slot) const { + auto found = FuncTableMap.find(slot); + if (found == FuncTableMap.end()) { + return None; + } + return ArrayRef(found->second); + } + FunctionSummaryInfoMapTy::const_iterator begin() const { return FunctionSummaryInfoMap.begin(); diff --git a/lib/SILOptimizer/Utils/ModuleSummaryIndex.cpp b/lib/SILOptimizer/Utils/ModuleSummaryIndex.cpp index 7ce640c68db86..087fb35af666e 100644 --- a/lib/SILOptimizer/Utils/ModuleSummaryIndex.cpp +++ b/lib/SILOptimizer/Utils/ModuleSummaryIndex.cpp @@ -30,8 +30,7 @@ buildFunctionSummaryIndex(SILFunction &F, BasicCalleeAnalysis &BCA) { auto member = WMI->getMember(); auto CalleeFn = member.getFuncDecl(); auto Protocol = dyn_cast(CalleeFn->getDeclContext()); - Protocol->getModuleContext()->getNameStr(); - llvm::dbgs() << "Record " << WMI->getMember().getFuncDecl()->getNameStr() + llvm::dbgs() << "Record " << CalleeFn->getNameStr() << " of " << Protocol->getNameStr() << " as reference to PWT\n"; auto edge = FunctionSummary::EdgeTy::witnessCall(WMI->getMember()); @@ -63,6 +62,30 @@ buildFunctionSummaryIndex(SILFunction &F, BasicCalleeAnalysis &BCA) { return std::make_unique(CallGraphEdgeList); } +void indexWitnessTable(ModuleSummaryIndex &index, SILWitnessTable &WT) { + auto &Protocol = *WT.getProtocol(); + for (auto entry : WT.getEntries()) { + if (entry.getKind() != SILWitnessTable::Method) break; + + auto methodWitness = entry.getMethodWitness(); + auto VirtualFunc = methodWitness.Requirement.getFuncDecl(); + auto Witness = methodWitness.Witness; + TableFuncSlot slot(*VirtualFunc, Protocol); + index.addImplementation(slot, getGUID(Witness->getName())); + } +} + + +void indexVTable(ModuleSummaryIndex &index, SILVTable &VT) { + auto &Class = *VT.getClass(); + for (auto entry : VT.getEntries()) { + auto VirtualFunc = entry.getMethod().getFuncDecl(); + auto Impl = entry.getImplementation(); + TableFuncSlot slot(*VirtualFunc, Class); + index.addImplementation(slot, getGUID(Impl->getName())); + } +} + ModuleSummaryIndex swift::buildModuleSummaryIndex(SILModule &M, BasicCalleeAnalysis &BCA) { ModuleSummaryIndex index; @@ -73,5 +96,13 @@ ModuleSummaryIndex swift::buildModuleSummaryIndex(SILModule &M, auto FS = buildFunctionSummaryIndex(F, BCA); index.addFunctionSummary(F.getName(), std::move(FS)); } + + for (auto &WT : M.getWitnessTableList()) { + indexWitnessTable(index, WT); + } + + for (auto &VT : M.getVTables()) { + indexVTable(index, *VT); + } return index; } From 0613f98ad9a4bc5354525dcc7bbefdf0f636caae Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Sun, 5 Jul 2020 14:24:04 +0900 Subject: [PATCH 18/77] Serialize virtual method info --- include/swift/SIL/ModuleSummary.h | 46 ++++++++++++------- .../swift/Serialization/ModuleSummaryFile.h | 21 +++++++++ lib/SILOptimizer/Utils/ModuleSummaryIndex.cpp | 5 +- lib/Serialization/ModuleSummaryFile.cpp | 26 +++++++++++ test/Serialization/Inputs/module1.swift | 5 ++ test/Serialization/Inputs/module2.swift | 9 ++++ test/Serialization/module-summary.swift | 10 ++++ 7 files changed, 103 insertions(+), 19 deletions(-) diff --git a/include/swift/SIL/ModuleSummary.h b/include/swift/SIL/ModuleSummary.h index 34e0ccadacd56..1487b71586710 100644 --- a/include/swift/SIL/ModuleSummary.h +++ b/include/swift/SIL/ModuleSummary.h @@ -12,7 +12,7 @@ namespace swift { using GUID = uint64_t; static GUID getGUID(llvm::StringRef Str) { return llvm::MD5Hash(Str); } -struct TableFuncSlot { +struct VirtualMethodSlot { enum class KindTy { Witness, VTable, }; @@ -21,7 +21,7 @@ struct TableFuncSlot { GUID VirtualFuncID; GUID TableID; - TableFuncSlot(FuncDecl &VirtualFunc, TypeDecl &Context, KindTy kind) : Kind(kind) { + VirtualMethodSlot(FuncDecl &VirtualFunc, TypeDecl &Context, KindTy kind) : Kind(kind) { switch (Kind) { case KindTy::Witness: { assert(isa(Context)); @@ -36,14 +36,23 @@ struct TableFuncSlot { TableID = getGUID(Context.getNameStr()); } - TableFuncSlot(FuncDecl &VirtualFunc, ProtocolDecl &Context) - : TableFuncSlot(VirtualFunc, Context, KindTy::Witness) { } + VirtualMethodSlot(FuncDecl &VirtualFunc, ProtocolDecl &Context) + : VirtualMethodSlot(VirtualFunc, Context, KindTy::Witness) { } - TableFuncSlot(FuncDecl &VirtualFunc, ClassDecl &Context) - : TableFuncSlot(VirtualFunc, Context, KindTy::VTable) { } + VirtualMethodSlot(FuncDecl &VirtualFunc, ClassDecl &Context) + : VirtualMethodSlot(VirtualFunc, Context, KindTy::VTable) { } - bool operator<(const TableFuncSlot &rhs) const { - return Kind < rhs.Kind && TableID < rhs.TableID && VirtualFuncID < rhs.VirtualFuncID; + bool operator<(const VirtualMethodSlot &rhs) const { + if (Kind > rhs.Kind) + return false; + if (Kind < rhs.Kind) + return true; + if (TableID > rhs.TableID) + return false; + if (TableID < rhs.TableID) + return true; + + return VirtualFuncID < rhs.VirtualFuncID; } }; @@ -140,10 +149,10 @@ struct FunctionSummaryInfo { class ModuleSummaryIndex { using FunctionSummaryInfoMapTy = std::map; - using FuncTableMapTy = std::map>; + using VirtualMethodInfoMapTy = std::map>; FunctionSummaryInfoMapTy FunctionSummaryInfoMap; - FuncTableMapTy FuncTableMap; + VirtualMethodInfoMapTy VirtualMethodInfoMap; std::string ModuleName; // Only for debug purpose @@ -172,24 +181,27 @@ class ModuleSummaryIndex { return std::make_pair(entry.TheSummary.get(), StringRef(entry.Name)); } - void addImplementation(TableFuncSlot slot, GUID funcGUID) { - auto found = FuncTableMap.find(slot); - if (found == FuncTableMap.end()) { - FuncTableMap.insert(std::make_pair(slot, std::vector{ funcGUID })); + void addImplementation(VirtualMethodSlot slot, GUID funcGUID) { + auto found = VirtualMethodInfoMap.find(slot); + if (found == VirtualMethodInfoMap.end()) { + VirtualMethodInfoMap.insert(std::make_pair(slot, std::vector{ funcGUID })); return; } found->second.push_back(funcGUID); } llvm::Optional> - getImplementations(TableFuncSlot slot) const { - auto found = FuncTableMap.find(slot); - if (found == FuncTableMap.end()) { + getImplementations(VirtualMethodSlot slot) const { + auto found = VirtualMethodInfoMap.find(slot); + if (found == VirtualMethodInfoMap.end()) { return None; } return ArrayRef(found->second); } + const VirtualMethodInfoMapTy &virtualMethods() const { + return VirtualMethodInfoMap; + } FunctionSummaryInfoMapTy::const_iterator begin() const { return FunctionSummaryInfoMap.begin(); diff --git a/include/swift/Serialization/ModuleSummaryFile.h b/include/swift/Serialization/ModuleSummaryFile.h index a87b6454f3369..2801dbadb8ed7 100644 --- a/include/swift/Serialization/ModuleSummaryFile.h +++ b/include/swift/Serialization/ModuleSummaryFile.h @@ -23,6 +23,8 @@ enum BlockID { MODULE_SUMMARY_ID = llvm::bitc::FIRST_APPLICATION_BLOCKID, FUNCTION_SUMMARY_ID, + + VIRTUAL_METHOD_INFO_ID, }; namespace module_summary { @@ -36,6 +38,25 @@ using MetadataLayout = BCRecordLayout< >; }; +namespace virtual_method_info { +enum { + METHOD_METADATA, + METHOD_IMPL, +}; + +using MethodMetadataLayout = BCRecordLayout< + METHOD_METADATA, + BCFixed<1>, // KindTy (WitnessTable or VTable) + BCVBR<16>, // VirtualFunc GUID + BCVBR<16> // Table GUID +>; + +using MethodImplLayout = BCRecordLayout< + METHOD_IMPL, + BCVBR<16> // Impl func GUID +>; +}; + namespace function_summary { enum { METADATA, diff --git a/lib/SILOptimizer/Utils/ModuleSummaryIndex.cpp b/lib/SILOptimizer/Utils/ModuleSummaryIndex.cpp index 087fb35af666e..b3ce8f94b24b9 100644 --- a/lib/SILOptimizer/Utils/ModuleSummaryIndex.cpp +++ b/lib/SILOptimizer/Utils/ModuleSummaryIndex.cpp @@ -70,7 +70,8 @@ void indexWitnessTable(ModuleSummaryIndex &index, SILWitnessTable &WT) { auto methodWitness = entry.getMethodWitness(); auto VirtualFunc = methodWitness.Requirement.getFuncDecl(); auto Witness = methodWitness.Witness; - TableFuncSlot slot(*VirtualFunc, Protocol); + llvm::dbgs() << "Emit table entry for " << Witness->getName() << "\n"; + VirtualMethodSlot slot(*VirtualFunc, Protocol); index.addImplementation(slot, getGUID(Witness->getName())); } } @@ -81,7 +82,7 @@ void indexVTable(ModuleSummaryIndex &index, SILVTable &VT) { for (auto entry : VT.getEntries()) { auto VirtualFunc = entry.getMethod().getFuncDecl(); auto Impl = entry.getImplementation(); - TableFuncSlot slot(*VirtualFunc, Class); + VirtualMethodSlot slot(*VirtualFunc, Class); index.addImplementation(slot, getGUID(Impl->getName())); } } diff --git a/lib/Serialization/ModuleSummaryFile.cpp b/lib/Serialization/ModuleSummaryFile.cpp index 6b532c679e3c1..3a6b796d7eed6 100644 --- a/lib/Serialization/ModuleSummaryFile.cpp +++ b/lib/Serialization/ModuleSummaryFile.cpp @@ -79,6 +79,11 @@ void Serializer::writeBlockInfoBlock() { BLOCK(FUNCTION_SUMMARY); BLOCK_RECORD(function_summary, METADATA); BLOCK_RECORD(function_summary, CALL_GRAPH_EDGE); + + BLOCK(VIRTUAL_METHOD_INFO); + BLOCK_RECORD(virtual_method_info, METHOD_METADATA); + BLOCK_RECORD(virtual_method_info, METHOD_IMPL); + } void Serializer::emitHeader() { @@ -111,6 +116,27 @@ void Serializer::emitModuleSummary(const ModuleSummaryIndex &index) { } } } + + { + for (auto &method : index.virtualMethods()) { + llvm::BCBlockRAII restoreBlock(Out, VIRTUAL_METHOD_INFO_ID, 5); + auto &slot = method.first; + auto impls = method.second; + using namespace virtual_method_info; + + MethodMetadataLayout MDLayout(Out); + + MDLayout.emit(ScratchRecord, + unsigned(slot.Kind), + slot.VirtualFuncID, + slot.TableID); + + for (auto impl : impls) { + MethodImplLayout ImplLayout(Out); + ImplLayout.emit(ScratchRecord, impl); + } + } + } } void Serializer::write(llvm::raw_ostream &os) { diff --git a/test/Serialization/Inputs/module1.swift b/test/Serialization/Inputs/module1.swift index 63afd92d17961..85b849b8d05ce 100644 --- a/test/Serialization/Inputs/module1.swift +++ b/test/Serialization/Inputs/module1.swift @@ -2,4 +2,9 @@ public func module1Func() -> Int { return 1 } public protocol P { func memberMethod() + func defaultProvided() +} + +extension P { + public func defaultProvided() {} } diff --git a/test/Serialization/Inputs/module2.swift b/test/Serialization/Inputs/module2.swift index b5676496a3815..53d1949285910 100644 --- a/test/Serialization/Inputs/module2.swift +++ b/test/Serialization/Inputs/module2.swift @@ -4,6 +4,15 @@ public func module2Func() -> Int { return module1Func() } +public struct Concrete1 : P { + public func memberMethod() {} + public func defaultProvided() {} +} + +public struct Concrete2 : P { + public func memberMethod() {} +} + public func useP(_ t: T) { t.memberMethod() } diff --git a/test/Serialization/module-summary.swift b/test/Serialization/module-summary.swift index cc196cdc9e0b3..5d000f7133bf7 100644 --- a/test/Serialization/module-summary.swift +++ b/test/Serialization/module-summary.swift @@ -24,6 +24,16 @@ // TABLE-CHECK-NEXT: // TABLE-CHECK-NEXT: +// TABLE-CHECK: +// TABLE-CHECK-NEXT: +// TABLE-CHECK-NEXT: +// TABLE-CHECK-NEXT: + +// TABLE-CHECK: +// TABLE-CHECK-NEXT: +// TABLE-CHECK-NEXT: +// TABLE-CHECK-NEXT: + // RUN: %swift_frontend_plain -cross-module-opt %t/module-summary.swiftmodule.summary %t/module1.swiftmodule.summary %t/module2.swiftmodule.summary -o %t/merged-module.summary // RUN: llvm-bcanalyzer -dump %t/merged-module.summary | %FileCheck %s --check-prefix MERGED-CHECK From 0454a467736feb1dfc301a66669c84869dee02df Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Sun, 5 Jul 2020 14:47:51 +0900 Subject: [PATCH 19/77] Deserialize virtual method info --- include/swift/SIL/ModuleSummary.h | 35 +++++++++-- lib/Serialization/ModuleSummaryFile.cpp | 78 ++++++++++++++++++++++++- 2 files changed, 106 insertions(+), 7 deletions(-) diff --git a/include/swift/SIL/ModuleSummary.h b/include/swift/SIL/ModuleSummary.h index 1487b71586710..47d04928cf028 100644 --- a/include/swift/SIL/ModuleSummary.h +++ b/include/swift/SIL/ModuleSummary.h @@ -15,12 +15,14 @@ static GUID getGUID(llvm::StringRef Str) { return llvm::MD5Hash(Str); } struct VirtualMethodSlot { enum class KindTy { Witness, VTable, + kindCount, }; KindTy Kind; GUID VirtualFuncID; GUID TableID; - + VirtualMethodSlot(KindTy kind, GUID virtualFuncID, GUID tableID) + : Kind(kind), VirtualFuncID(virtualFuncID), TableID(tableID) { } VirtualMethodSlot(FuncDecl &VirtualFunc, TypeDecl &Context, KindTy kind) : Kind(kind) { switch (Kind) { case KindTy::Witness: { @@ -30,6 +32,10 @@ struct VirtualMethodSlot { case KindTy::VTable: { assert(isa(Context)); break; + + } + case KindTy::kindCount: { + llvm_unreachable("impossible"); } } VirtualFuncID = getGUID(VirtualFunc.getBaseIdentifier().str()); @@ -78,14 +84,35 @@ class FunctionSummary { this->Table = getGUID(Context.getNameStr()); } - public: - Kind getKind() const { return kind; } - GUID getCallee() const { return CalleeFn; } GUID getTable() const { // If kind is static, Table guid should be 0 assert(kind != Kind::Static || Table == 0); return Table; } + public: + Kind getKind() const { return kind; } + GUID getCallee() const { return CalleeFn; } + + VirtualMethodSlot slot() const { + VirtualMethodSlot::KindTy slotKind; + switch (kind) { + case Kind::Witness: { + slotKind = VirtualMethodSlot::KindTy::Witness; + break; + } + case Kind::VTable: { + slotKind = VirtualMethodSlot::KindTy::VTable; + break; + } + case Kind::Static: { + llvm_unreachable("Can't get slot for static call"); + } + case Kind::kindCount: { + llvm_unreachable("impossible"); + } + } + return VirtualMethodSlot(slotKind, CalleeFn, Table); + } EdgeTy(GUID callee, GUID table, Kind kind) : CalleeFn(callee), Table(table), kind(kind) {} diff --git a/lib/Serialization/ModuleSummaryFile.cpp b/lib/Serialization/ModuleSummaryFile.cpp index 3a6b796d7eed6..3f29ab15cf0f8 100644 --- a/lib/Serialization/ModuleSummaryFile.cpp +++ b/lib/Serialization/ModuleSummaryFile.cpp @@ -16,6 +16,14 @@ getEdgeKind(unsigned edgeKind) { return None; } + +static llvm::Optional +getSlotKind(unsigned kind) { + if (kind < unsigned(FunctionSummary::EdgeTy::Kind::kindCount)) + return VirtualMethodSlot::KindTy(kind); + return None; +} + class Serializer { SmallVector Buffer; llvm::BitstreamWriter Out{Buffer}; @@ -164,6 +172,7 @@ class Deserializer { bool readSignature(); bool readModuleSummaryMetadata(); + bool readVirtualMethodInfo(); bool readFunctionSummary(); bool readSingleModuleSummary(); @@ -285,6 +294,60 @@ bool Deserializer::readFunctionSummary() { return false; } +bool Deserializer::readVirtualMethodInfo() { + if (llvm::Error Err = Cursor.EnterSubBlock(VIRTUAL_METHOD_INFO_ID)) { + llvm::report_fatal_error("Can't enter subblock"); + } + + llvm::Expected maybeNext = Cursor.advance(); + if (!maybeNext) + llvm::report_fatal_error("Should have next entry"); + + llvm::BitstreamEntry next = maybeNext.get(); + + llvm::Optional slot; + + while (next.Kind == llvm::BitstreamEntry::Record) { + Scratch.clear(); + + auto maybeKind = Cursor.readRecord(next.ID, Scratch, &BlobData); + + if (!maybeKind) + llvm::report_fatal_error("Should have kind"); + + switch (maybeKind.get()) { + case virtual_method_info::METHOD_METADATA: { + unsigned methodKindID; + GUID virtualFuncGUID, tableGUID; + virtual_method_info::MethodMetadataLayout::readRecord(Scratch, methodKindID, virtualFuncGUID, tableGUID); + + auto Kind = getSlotKind(methodKindID); + if (!Kind) + llvm::report_fatal_error("Bad method kind"); + + slot = VirtualMethodSlot(Kind.getValue(), virtualFuncGUID, tableGUID); + break; + } + case virtual_method_info::METHOD_IMPL: { + GUID implGUID; + virtual_method_info::MethodImplLayout::readRecord(Scratch, implGUID); + if (!slot) + llvm::report_fatal_error("Slot should be set before impl"); + moduleSummary.addImplementation(slot.getValue(), implGUID); + break; + } + } + + maybeNext = Cursor.advance(); + if (!maybeNext) + llvm::report_fatal_error("Should have next entry"); + + next = maybeNext.get(); + } + + return false; +} + bool Deserializer::readSingleModuleSummary() { if (llvm::Error Err = Cursor.EnterSubBlock(MODULE_SUMMARY_ID)) { llvm::report_fatal_error("Can't enter subblock"); @@ -302,9 +365,17 @@ bool Deserializer::readSingleModuleSummary() { while (next.Kind == llvm::BitstreamEntry::SubBlock) { switch (next.ID) { case FUNCTION_SUMMARY_ID: { - readFunctionSummary(); + if (readFunctionSummary()) { + llvm::report_fatal_error("Failed to read FS"); + } break; } + case VIRTUAL_METHOD_INFO_ID: { + if (readVirtualMethodInfo()) { + llvm::report_fatal_error("Failed to read virtual method info"); + } + break; + } } maybeNext = Cursor.advance(); @@ -346,8 +417,9 @@ bool Deserializer::readModuleSummary() { } break; } - case FUNCTION_SUMMARY_ID: { - llvm_unreachable("FUNCTION_SUMMARY block should be handled in " + case FUNCTION_SUMMARY_ID: + case VIRTUAL_METHOD_INFO_ID: { + llvm_unreachable("FUNCTION_SUMMARY and VIRTUAL_METHOD_INFO_ID blocks should be handled in " "'readSingleModuleSummary'"); break; } From bb22ed16dcf5280f715f3a778c31f519e1b9e082 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Sun, 5 Jul 2020 16:14:49 +0900 Subject: [PATCH 20/77] Implement table entry elimination --- .../IPO/CrossDeadFunctionElimination.cpp | 70 +++++++++++++------ .../IPO/DeadFunctionElimination.cpp | 2 + test/Serialization/Inputs/module2.swift | 1 + test/Serialization/module-summary.swift | 37 +++++++--- tools/driver/cross_module_opt_main.cpp | 8 ++- 5 files changed, 87 insertions(+), 31 deletions(-) diff --git a/lib/SILOptimizer/IPO/CrossDeadFunctionElimination.cpp b/lib/SILOptimizer/IPO/CrossDeadFunctionElimination.cpp index 216cfeec2c5b8..e097afddd78c8 100644 --- a/lib/SILOptimizer/IPO/CrossDeadFunctionElimination.cpp +++ b/lib/SILOptimizer/IPO/CrossDeadFunctionElimination.cpp @@ -29,33 +29,41 @@ class SILCrossDeadFuncElimination : public SILModuleTransform { public: SILCrossDeadFuncElimination() {} - - void run() override { - LLVM_DEBUG(llvm::dbgs() << "Running CrossDeadFuncElimination\n"); - auto &Context = getModule()->getASTContext(); - auto ModuleSummaryPath = getOptions().ModuleSummaryPath; - auto ErrOrBuf = llvm::MemoryBuffer::getFile(ModuleSummaryPath); - if (!ErrOrBuf) { - Context.Diags.diagnose(SourceLoc(), diag::error_no_such_file_or_directory, - ModuleSummaryPath); - return; + + void eliminateDeadEntriesFromTables(SILModule &M) { + + for (auto VT : M.getVTables()) { + VT->removeEntries_if([&] (SILVTable::Entry &entry) -> bool { + auto Impl = entry.getImplementation(); + auto &maybePair = TheSummary.getFunctionInfo(getGUID(Impl->getName())); + if (!maybePair) + return false; + auto info = maybePair.getValue().first; + return !info->isLive(); + }); } - - auto HasErr = modulesummary::loadModuleSummaryIndex( - ErrOrBuf.get()->getMemBufferRef(), TheSummary); - if (HasErr) { - llvm::report_fatal_error("Invalid module summary"); + + + for (auto &WT : M.getWitnessTableList()) { + WT.clearMethods_if([&] (const SILWitnessTable::MethodWitness &MW) -> bool { + auto Impl = MW.Witness; + auto &maybePair = TheSummary.getFunctionInfo(getGUID(Impl->getName())); + if (!maybePair) + return false; + auto info = maybePair.getValue().first; + return !info->isLive(); + }); } - - auto M = getModule(); - + } + + void eliminateDeadFunctions(SILModule &M) { for (auto &pair : TheSummary) { auto &info = pair.second; if (info.TheSummary->isLive()) { continue; } - auto F = M->lookUpFunction(info.Name); + auto F = M.lookUpFunction(info.Name); if (!F) { llvm::dbgs() << "Couldn't eliminate " << info.Name << " because it's not found\n"; @@ -63,10 +71,32 @@ class SILCrossDeadFuncElimination : public SILModuleTransform { } F->dropAllReferences(); notifyWillDeleteFunction(F); - M->eraseFunction(F); + M.eraseFunction(F); llvm::dbgs() << "Eliminate " << info.Name << "\n"; } + } + + void run() override { + LLVM_DEBUG(llvm::dbgs() << "Running CrossDeadFuncElimination\n"); + auto &Context = getModule()->getASTContext(); + auto ModuleSummaryPath = getOptions().ModuleSummaryPath; + auto ErrOrBuf = llvm::MemoryBuffer::getFile(ModuleSummaryPath); + if (!ErrOrBuf) { + Context.Diags.diagnose(SourceLoc(), diag::error_no_such_file_or_directory, + ModuleSummaryPath); + return; + } + + auto HasErr = modulesummary::loadModuleSummaryIndex( + ErrOrBuf.get()->getMemBufferRef(), TheSummary); + if (HasErr) { + llvm::report_fatal_error("Invalid module summary"); + } + + auto &M = *getModule(); + this->eliminateDeadEntriesFromTables(M); + this->eliminateDeadFunctions(M); this->invalidateFunctionTables(); } }; diff --git a/lib/SILOptimizer/IPO/DeadFunctionElimination.cpp b/lib/SILOptimizer/IPO/DeadFunctionElimination.cpp index c72e35aee7817..053f899909d90 100644 --- a/lib/SILOptimizer/IPO/DeadFunctionElimination.cpp +++ b/lib/SILOptimizer/IPO/DeadFunctionElimination.cpp @@ -484,6 +484,8 @@ class DeadFunctionElimination : FunctionLivenessComputation { continue; SILFunction *F = entry. getMethodWitness().Witness; + if (!F) + continue; auto *fd = cast( entry.getMethodWitness().Requirement.getDecl()); MethodInfo *mi = getMethodInfo(fd, /*isWitnessTable*/ true); diff --git a/test/Serialization/Inputs/module2.swift b/test/Serialization/Inputs/module2.swift index 53d1949285910..55786a8e54bc6 100644 --- a/test/Serialization/Inputs/module2.swift +++ b/test/Serialization/Inputs/module2.swift @@ -11,6 +11,7 @@ public struct Concrete1 : P { public struct Concrete2 : P { public func memberMethod() {} + public init() {} } public func useP(_ t: T) { diff --git a/test/Serialization/module-summary.swift b/test/Serialization/module-summary.swift index 5d000f7133bf7..6e0d6f1632465 100644 --- a/test/Serialization/module-summary.swift +++ b/test/Serialization/module-summary.swift @@ -11,6 +11,8 @@ // MAIN-CHECK: blob data = '$s7module20A4FuncSiyF' // MAIN-CHECK: blob data = 'main' // MAIN-CHECK-NEXT: +// MAIN-CHECK-NEXT: +// MAIN-CHECK-NEXT: // MAIN-CHECK-NEXT: @@ -53,19 +55,33 @@ // LIVE-CHECK-DAG: blob data = '$s4main3baryySiF' // RUN: %target-swift-frontend -emit-sil %s -I %t -o %t/main.sil -// RUN: %target-sil-opt -emit-sorted-sil %t/main.sil -module-summary-path %t/merged-module.summary --sil-cross-deadfuncelim -I %t | %FileCheck %s --check-prefix DEADFUNC-CHECK -// RUN: %target-swift-frontend -emit-sil %s -module-summary-path %t/merged-module.summary -I %t -O | %FileCheck %s --check-prefix DEADFUNC-CHECK -// DEADFUNC-CHECK-DAG: @$s4main10publicFuncyyF -// DEADFUNC-CHECK-DAG: @$s4main3baryySiF -// DEADFUNC-CHECK-DAG: @main +// RUN: %target-sil-opt -emit-sorted-sil %t/main.sil -module-summary-path %t/merged-module.summary --sil-cross-deadfuncelim -I %t | %FileCheck %s --check-prefix DEADFUNC-MAIN-CHECK +// RUN: %target-swift-frontend -emit-sil %s -module-summary-path %t/merged-module.summary -I %t -O | %FileCheck %s --check-prefix DEADFUNC-MAIN-CHECK +// DEADFUNC-MAIN-CHECK-DAG: @$s4main10publicFuncyyF +// DEADFUNC-MAIN-CHECK-DAG: @$s4main3baryySiF +// DEADFUNC-MAIN-CHECK-DAG: @main -// DEADFUNC-CHECK-NOT: @$s4main16callExternalFuncyyF -// DEADFUNC-CHECK-NOT: @$sSi2eeoiySbSi_SitFZ -// DEADFUNC-CHECK-NOT: @$s7module20A4FuncSiyF -// DEADFUNC-CHECK-NOT: @$sSi22_builtinIntegerLiteralSiBI_tcfC -// DEADFUNC-CHECK-NOT: @$s4main9callTwiceyyF +// DEADFUNC-MAIN-CHECK-NOT: @$s4main16callExternalFuncyyF +// DEADFUNC-MAIN-CHECK-NOT: @$sSi2eeoiySbSi_SitFZ +// DEADFUNC-MAIN-CHECK-NOT: @$s7module20A4FuncSiyF +// DEADFUNC-MAIN-CHECK-NOT: @$sSi22_builtinIntegerLiteralSiBI_tcfC +// DEADFUNC-MAIN-CHECK-NOT: @$s4main9callTwiceyyF +// RUN: %target-swift-frontend -emit-sil %S/Inputs/module2.swift -parse-as-library -module-summary-path %t/merged-module.summary -I %t -O | %FileCheck %s --check-prefix DEADFUNC-MODULE2-CHECK + +// DEADFUNC-MODULE2-CHECK-DAG: @$s7module29Concrete1V12memberMethodyyF +// DEADFUNC-MODULE2-CHECK-DAG: @$s7module29Concrete1V7module11PAadEP12memberMethodyyFTW +// DEADFUNC-MODULE2-CHECK-DAG: @$s7module29Concrete2V12memberMethodyyF +// DEADFUNC-MODULE2-CHECK-DAG: @$s7module29Concrete2V7module11PAadEP12memberMethodyyFTW +// DEADFUNC-MODULE2-CHECK-DAG: @$s7module24usePyyx7module11PRzlF + +// DEADFUNC-MODULE2-CHECK-NOT: @$s7module29Concrete2V7module11PAadEP15defaultProvidedyyFTW +// DEADFUNC-MODULE2-CHECK-NOT: @$s7module20A4FuncSiyF +// DEADFUNC-MODULE2-CHECK-NOT: @$s7module29Concrete1V7module11PAadEP15defaultProvidedyyFTW +// DEADFUNC-MODULE2-CHECK-NOT: @$s7module11PPAAE15defaultProvidedyyF + +import module1 import module2 func foo() { bar(0) } @@ -88,3 +104,4 @@ public func publicFunc() { } publicFunc() +useP(Concrete2()) diff --git a/tools/driver/cross_module_opt_main.cpp b/tools/driver/cross_module_opt_main.cpp index 48e588c6cf15b..d2da3e6a0a33a 100644 --- a/tools/driver/cross_module_opt_main.cpp +++ b/tools/driver/cross_module_opt_main.cpp @@ -114,7 +114,13 @@ void markDeadSymbols(ModuleSummaryIndex &summary, llvm::DenseSet &Preserve } case FunctionSummary::EdgeTy::Kind::Witness: case FunctionSummary::EdgeTy::Kind::VTable: { - llvm_unreachable("Witness and VTable calls are not supported yet."); + auto Impls = summary.getImplementations(Call.slot()); + if (!Impls) + llvm_unreachable("Impls not found for the slot"); + for (auto Impl : Impls.getValue()) { + Worklist.push_back(Impl); + } + break; } case FunctionSummary::EdgeTy::Kind::kindCount: llvm_unreachable("impossible"); From 64579b4b839b3329e8171ead828e943043965822 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Sat, 18 Jul 2020 15:24:00 +0900 Subject: [PATCH 21/77] Refactoring not to use BasicCalleeAnalysis --- lib/SILOptimizer/Utils/ModuleSummaryIndex.cpp | 88 ++++++++++--------- 1 file changed, 45 insertions(+), 43 deletions(-) diff --git a/lib/SILOptimizer/Utils/ModuleSummaryIndex.cpp b/lib/SILOptimizer/Utils/ModuleSummaryIndex.cpp index b3ce8f94b24b9..f689b25488058 100644 --- a/lib/SILOptimizer/Utils/ModuleSummaryIndex.cpp +++ b/lib/SILOptimizer/Utils/ModuleSummaryIndex.cpp @@ -12,54 +12,56 @@ using namespace swift; -std::unique_ptr -buildFunctionSummaryIndex(SILFunction &F, BasicCalleeAnalysis &BCA) { +namespace { +class FunctionSummaryIndexer { std::vector CallGraphEdgeList; +public: + void indexInstruction(SILFunction &F, SILInstruction *I); + void indexFunction(SILFunction &F); + + std::unique_ptr takeSummary() { + return std::make_unique(std::move(CallGraphEdgeList)); + } +}; - for (auto &BB : F) { - for (auto &I : BB) { - auto FAS = FullApplySite::isa(&I); - if (!FAS) - continue; - CalleeList Callees = BCA.getCalleeList(FAS); - if (Callees.isIncomplete()) { - auto Callee = FAS.getCalleeOrigin(); - switch (Callee->getKind()) { - case ValueKind::WitnessMethodInst: { - auto WMI = cast(Callee); - auto member = WMI->getMember(); - auto CalleeFn = member.getFuncDecl(); - auto Protocol = dyn_cast(CalleeFn->getDeclContext()); - llvm::dbgs() << "Record " << CalleeFn->getNameStr() - << " of " << Protocol->getNameStr() << " as reference to PWT\n"; +void FunctionSummaryIndexer::indexInstruction(SILFunction &F, SILInstruction *I) { + // TODO: Handle dynamically replacable function ref inst + if (auto *FRI = dyn_cast(I)) { + SILFunction *callee = FRI->getReferencedFunctionOrNull(); + assert(callee); + auto edge = + FunctionSummary::EdgeTy::staticCall(getGUID(callee->getName())); + CallGraphEdgeList.push_back(edge); + return; + } - auto edge = FunctionSummary::EdgeTy::witnessCall(WMI->getMember()); - CallGraphEdgeList.push_back(edge); - break; - } - case ValueKind::ClassMethodInst: { - auto CMI = cast(Callee); - llvm::dbgs() << "Record " << CMI->getMember().getDecl()->getBaseName().getIdentifier().str() << " as reference to VTable\n"; - auto edge = FunctionSummary::EdgeTy::vtableCall(CMI->getMember()); - CallGraphEdgeList.push_back(edge); - break; - } - default: - llvm_unreachable("invalid kind"); - } - continue; - } + if (auto *WMI = dyn_cast(I)) { + auto edge = FunctionSummary::EdgeTy::witnessCall(WMI->getMember()); + CallGraphEdgeList.push_back(edge); + return; + } - // For static calls - std::vector CalleeGUIDs; - for (auto Callee : Callees) { - auto edge = - FunctionSummary::EdgeTy::staticCall(getGUID(Callee->getName())); - CallGraphEdgeList.push_back(edge); - } - } + if (auto *MI = dyn_cast(I)) { + auto edge = FunctionSummary::EdgeTy::vtableCall(MI->getMember()); + CallGraphEdgeList.push_back(edge); + return; } - return std::make_unique(CallGraphEdgeList); +} + +void FunctionSummaryIndexer::indexFunction(SILFunction &F) { + for (auto &BB : F) { + for (auto &I : BB) { + indexInstruction(F, &I); + } + } +} +}; + +std::unique_ptr +buildFunctionSummaryIndex(SILFunction &F, BasicCalleeAnalysis &BCA) { + FunctionSummaryIndexer indexer; + indexer.indexFunction(F); + return indexer.takeSummary(); } void indexWitnessTable(ModuleSummaryIndex &index, SILWitnessTable &WT) { From 643263ba185b594c7f25b61a3eb1737941e7dba6 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Sat, 18 Jul 2020 23:11:46 +0900 Subject: [PATCH 22/77] Use mangled identifier for GUID --- include/swift/SIL/ModuleSummary.h | 78 ++++--------------- .../swift/Serialization/ModuleSummaryFile.h | 6 +- lib/SILOptimizer/Utils/ModuleSummaryIndex.cpp | 10 +-- lib/Serialization/ModuleSummaryFile.cpp | 17 ++-- test/Serialization/module-summary.swift | 38 +++++---- 5 files changed, 52 insertions(+), 97 deletions(-) diff --git a/include/swift/SIL/ModuleSummary.h b/include/swift/SIL/ModuleSummary.h index 47d04928cf028..626d8f1d17fc6 100644 --- a/include/swift/SIL/ModuleSummary.h +++ b/include/swift/SIL/ModuleSummary.h @@ -3,6 +3,7 @@ #include "swift/AST/Decl.h" #include "swift/SIL/SILDeclRef.h" +#include "swift/AST/ASTMangler.h" // FIXME: Move this into another module to avoid circular dependencies. #include "swift/SILOptimizer/Analysis/BasicCalleeAnalysis.h" @@ -20,44 +21,17 @@ struct VirtualMethodSlot { KindTy Kind; GUID VirtualFuncID; - GUID TableID; - VirtualMethodSlot(KindTy kind, GUID virtualFuncID, GUID tableID) - : Kind(kind), VirtualFuncID(virtualFuncID), TableID(tableID) { } - VirtualMethodSlot(FuncDecl &VirtualFunc, TypeDecl &Context, KindTy kind) : Kind(kind) { - switch (Kind) { - case KindTy::Witness: { - assert(isa(Context)); - break; - } - case KindTy::VTable: { - assert(isa(Context)); - break; - - } - case KindTy::kindCount: { - llvm_unreachable("impossible"); - } - } - VirtualFuncID = getGUID(VirtualFunc.getBaseIdentifier().str()); - TableID = getGUID(Context.getNameStr()); + VirtualMethodSlot(KindTy kind, GUID virtualFuncID) + : Kind(kind), VirtualFuncID(virtualFuncID) { } + VirtualMethodSlot(SILDeclRef VirtualFuncRef, KindTy kind) : Kind(kind) { + VirtualFuncID = getGUID(VirtualFuncRef.mangle()); } - - VirtualMethodSlot(FuncDecl &VirtualFunc, ProtocolDecl &Context) - : VirtualMethodSlot(VirtualFunc, Context, KindTy::Witness) { } - - VirtualMethodSlot(FuncDecl &VirtualFunc, ClassDecl &Context) - : VirtualMethodSlot(VirtualFunc, Context, KindTy::VTable) { } - + bool operator<(const VirtualMethodSlot &rhs) const { if (Kind > rhs.Kind) return false; if (Kind < rhs.Kind) return true; - if (TableID > rhs.TableID) - return false; - if (TableID < rhs.TableID) - return true; - return VirtualFuncID < rhs.VirtualFuncID; } }; @@ -66,7 +40,6 @@ class FunctionSummary { public: class EdgeTy { GUID CalleeFn; - GUID Table; public: enum class Kind { @@ -78,17 +51,10 @@ class FunctionSummary { Kind kind; - EdgeTy(FuncDecl &CalleeFn, TypeDecl &Context, Kind kind) : kind(kind) { - // FIXME: This is really fragile - this->CalleeFn = getGUID(CalleeFn.getBaseIdentifier().str()); - this->Table = getGUID(Context.getNameStr()); + EdgeTy(SILDeclRef &CalleeFn, Kind kind) : kind(kind) { + this->CalleeFn = getGUID(CalleeFn.mangle()); } - GUID getTable() const { - // If kind is static, Table guid should be 0 - assert(kind != Kind::Static || Table == 0); - return Table; - } public: Kind getKind() const { return kind; } GUID getCallee() const { return CalleeFn; } @@ -111,33 +77,21 @@ class FunctionSummary { llvm_unreachable("impossible"); } } - return VirtualMethodSlot(slotKind, CalleeFn, Table); + return VirtualMethodSlot(slotKind, CalleeFn); } - EdgeTy(GUID callee, GUID table, Kind kind) - : CalleeFn(callee), Table(table), kind(kind) {} - EdgeTy(GUID callee, Kind kind) - : CalleeFn(callee), Table(0), kind(kind) {} + : CalleeFn(callee), kind(kind) {} static EdgeTy staticCall(GUID Callee) { return EdgeTy(Callee, Kind::Static); } - static EdgeTy witnessCall(GUID Callee) { - return EdgeTy(Callee, Kind::Witness); - } - static EdgeTy vtableCall(GUID Callee) { - return EdgeTy(Callee, Kind::VTable); - } + static EdgeTy witnessCall(SILDeclRef Callee) { - auto &Fn = *Callee.getFuncDecl(); - auto Context = dyn_cast(Fn.getDeclContext()); - return EdgeTy(Fn, *Context, Kind::Witness); + return EdgeTy(Callee, Kind::Witness); } static EdgeTy vtableCall(SILDeclRef Callee) { - auto &Fn = *Callee.getFuncDecl(); - auto Context = dyn_cast(Fn.getDeclContext()); - return EdgeTy(Fn, *Context, Kind::VTable); + return EdgeTy(Callee, Kind::VTable); } }; @@ -157,10 +111,8 @@ class FunctionSummary { : CallGraphEdgeList(std::move(CGEdges)) {} FunctionSummary() = default; - void addCall(GUID targetGUID, GUID tableGUID, EdgeTy::Kind kind) { - // If kind is static, Table guid should be 0 - assert(kind != EdgeTy::Kind::Static || tableGUID == 0); - CallGraphEdgeList.emplace_back(targetGUID, tableGUID, kind); + void addCall(GUID targetGUID, EdgeTy::Kind kind) { + CallGraphEdgeList.emplace_back(targetGUID, kind); } ArrayRef calls() const { return CallGraphEdgeList; } diff --git a/include/swift/Serialization/ModuleSummaryFile.h b/include/swift/Serialization/ModuleSummaryFile.h index 2801dbadb8ed7..dee809284730f 100644 --- a/include/swift/Serialization/ModuleSummaryFile.h +++ b/include/swift/Serialization/ModuleSummaryFile.h @@ -47,8 +47,7 @@ enum { using MethodMetadataLayout = BCRecordLayout< METHOD_METADATA, BCFixed<1>, // KindTy (WitnessTable or VTable) - BCVBR<16>, // VirtualFunc GUID - BCVBR<16> // Table GUID + BCVBR<16> // VirtualFunc GUID >; using MethodImplLayout = BCRecordLayout< @@ -71,8 +70,7 @@ using MetadataLayout = BCRecordLayout, // FunctionSummary::Edge::Kind - BCVBR<16>, // Target Function GUID - BCVBR<16> // Table GUID + BCVBR<16> // Target Function GUID >; } // namespace function_summary diff --git a/lib/SILOptimizer/Utils/ModuleSummaryIndex.cpp b/lib/SILOptimizer/Utils/ModuleSummaryIndex.cpp index f689b25488058..90e8724f7c0ba 100644 --- a/lib/SILOptimizer/Utils/ModuleSummaryIndex.cpp +++ b/lib/SILOptimizer/Utils/ModuleSummaryIndex.cpp @@ -65,26 +65,21 @@ buildFunctionSummaryIndex(SILFunction &F, BasicCalleeAnalysis &BCA) { } void indexWitnessTable(ModuleSummaryIndex &index, SILWitnessTable &WT) { - auto &Protocol = *WT.getProtocol(); for (auto entry : WT.getEntries()) { if (entry.getKind() != SILWitnessTable::Method) break; auto methodWitness = entry.getMethodWitness(); - auto VirtualFunc = methodWitness.Requirement.getFuncDecl(); auto Witness = methodWitness.Witness; - llvm::dbgs() << "Emit table entry for " << Witness->getName() << "\n"; - VirtualMethodSlot slot(*VirtualFunc, Protocol); + VirtualMethodSlot slot(methodWitness.Requirement, VirtualMethodSlot::KindTy::Witness); index.addImplementation(slot, getGUID(Witness->getName())); } } void indexVTable(ModuleSummaryIndex &index, SILVTable &VT) { - auto &Class = *VT.getClass(); for (auto entry : VT.getEntries()) { - auto VirtualFunc = entry.getMethod().getFuncDecl(); auto Impl = entry.getImplementation(); - VirtualMethodSlot slot(*VirtualFunc, Class); + VirtualMethodSlot slot(entry.getMethod(), VirtualMethodSlot::KindTy::VTable); index.addImplementation(slot, getGUID(Impl->getName())); } } @@ -97,6 +92,7 @@ ModuleSummaryIndex swift::buildModuleSummaryIndex(SILModule &M, for (auto &F : M) { auto FS = buildFunctionSummaryIndex(F, BCA); + FS->setLive(false); index.addFunctionSummary(F.getName(), std::move(FS)); } diff --git a/lib/Serialization/ModuleSummaryFile.cpp b/lib/Serialization/ModuleSummaryFile.cpp index 3f29ab15cf0f8..090cdeb027ac1 100644 --- a/lib/Serialization/ModuleSummaryFile.cpp +++ b/lib/Serialization/ModuleSummaryFile.cpp @@ -120,7 +120,7 @@ void Serializer::emitModuleSummary(const ModuleSummaryIndex &index) { for (auto call : summary->calls()) { CallGraphEdgeLayout edgeLayout(Out); edgeLayout.emit(ScratchRecord, unsigned(call.getKind()), - call.getCallee(), call.getTable()); + call.getCallee()); } } } @@ -136,8 +136,7 @@ void Serializer::emitModuleSummary(const ModuleSummaryIndex &index) { MDLayout.emit(ScratchRecord, unsigned(slot.Kind), - slot.VirtualFuncID, - slot.TableID); + slot.VirtualFuncID); for (auto impl : impls) { MethodImplLayout ImplLayout(Out); @@ -266,16 +265,16 @@ bool Deserializer::readFunctionSummary() { } case function_summary::CALL_GRAPH_EDGE: { unsigned edgeKindID; - GUID targetGUID, targetTable; + GUID targetGUID; function_summary::CallGraphEdgeLayout::readRecord(Scratch, edgeKindID, - targetGUID, targetTable); + targetGUID); auto edgeKind = getEdgeKind(edgeKindID); if (!edgeKind) llvm::report_fatal_error("Bad edge kind"); if (!FS) llvm::report_fatal_error("Invalid state"); - FS->addCall(targetGUID, targetTable, edgeKind.getValue()); + FS->addCall(targetGUID, edgeKind.getValue()); break; } } @@ -318,14 +317,14 @@ bool Deserializer::readVirtualMethodInfo() { switch (maybeKind.get()) { case virtual_method_info::METHOD_METADATA: { unsigned methodKindID; - GUID virtualFuncGUID, tableGUID; - virtual_method_info::MethodMetadataLayout::readRecord(Scratch, methodKindID, virtualFuncGUID, tableGUID); + GUID virtualFuncGUID; + virtual_method_info::MethodMetadataLayout::readRecord(Scratch, methodKindID, virtualFuncGUID); auto Kind = getSlotKind(methodKindID); if (!Kind) llvm::report_fatal_error("Bad method kind"); - slot = VirtualMethodSlot(Kind.getValue(), virtualFuncGUID, tableGUID); + slot = VirtualMethodSlot(Kind.getValue(), virtualFuncGUID); break; } case virtual_method_info::METHOD_IMPL: { diff --git a/test/Serialization/module-summary.swift b/test/Serialization/module-summary.swift index 6e0d6f1632465..8d85e73e99e76 100644 --- a/test/Serialization/module-summary.swift +++ b/test/Serialization/module-summary.swift @@ -10,30 +10,37 @@ // Ensure that call graph edge has correct function guid // MAIN-CHECK: blob data = '$s7module20A4FuncSiyF' // MAIN-CHECK: blob data = 'main' -// MAIN-CHECK-NEXT: -// MAIN-CHECK-NEXT: -// MAIN-CHECK-NEXT: +// MAIN-CHECK-NEXT: +// MAIN-CHECK-NEXT: +// MAIN-CHECK-NEXT: // MAIN-CHECK-NEXT: // MAIN-CHECK: blob data = '$s4main9callTwiceyyF' -// MAIN-CHECK-NEXT: -// MAIN-CHECK-NEXT: +// MAIN-CHECK-NEXT: +// MAIN-CHECK-NEXT: // MAIN-CHECK-NEXT: // RUN: llvm-bcanalyzer -dump %t/module2.swiftmodule.summary | %FileCheck %s --check-prefix TABLE-CHECK -// TABLE-CHECK: blob data = '$s7module24usePyyx7module11PRzlF' -// TABLE-CHECK-NEXT: + +// TABLE-CHECK-DAG: blob data = '$s7module29Concrete2V7module11PAadEP15defaultProvidedyyFTW' +// TABLE-CHECK-DAG: blob data = '$s7module29Concrete2V7module11PAadEP12memberMethodyyFTW' + +// TABLE-CHECK: blob data = '$s7module24usePyyx7module11PRzlF' +// TABLE-CHECK-NEXT: // TABLE-CHECK-NEXT: -// TABLE-CHECK: -// TABLE-CHECK-NEXT: -// TABLE-CHECK-NEXT: +// TABLE-CHECK-DAG: blob data = '$s7module29Concrete1V7module11PAadEP15defaultProvidedyyFTW' +// TABLE-CHECK-DAG: blob data = '$s7module29Concrete1V7module11PAadEP12memberMethodyyFTW' + +// TABLE-CHECK: +// TABLE-CHECK-NEXT: +// TABLE-CHECK-NEXT: // TABLE-CHECK-NEXT: -// TABLE-CHECK: -// TABLE-CHECK-NEXT: -// TABLE-CHECK-NEXT: +// TABLE-CHECK: +// TABLE-CHECK-NEXT: +// TABLE-CHECK-NEXT: // TABLE-CHECK-NEXT: @@ -44,7 +51,7 @@ // MERGED-CHECK-NEXT: // MERGED-CHECK: blob data = '$s7module20A4FuncSiyF' -// MERGED-CHECK-NEXT: +// MERGED-CHECK-NEXT: // MERGED-CHECK-NEXT: // RUN: llvm-bcanalyzer -dump %t/merged-module.summary | %FileCheck %s --check-prefix LIVE-CHECK @@ -84,6 +91,8 @@ import module1 import module2 +class S {} + func foo() { bar(0) } func bar(_ i: Int) { if (i == 0) { return } @@ -100,6 +109,7 @@ func callExternalFunc() { } public func publicFunc() { + S() foo() } From 3a3577558d4c6ccb1e0a9d13d36d7688a3ce24ca Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Tue, 21 Jul 2020 11:40:31 +0900 Subject: [PATCH 23/77] WIP --- include/swift/SIL/ModuleSummary.h | 43 ++++++-- .../swift/Serialization/ModuleSummaryFile.h | 4 +- lib/FrontendTool/FrontendTool.cpp | 6 +- lib/IRGen/GenClass.cpp | 1 + lib/IRGen/GenMeta.cpp | 2 + lib/IRGen/GenObjC.cpp | 1 + lib/SIL/IR/SILDefaultWitnessTable.cpp | 2 +- lib/SIL/IR/SILModule.cpp | 8 +- lib/SIL/IR/SILVTable.cpp | 4 +- lib/SIL/Verifier/SILVerifier.cpp | 4 +- .../IPO/CrossDeadFunctionElimination.cpp | 64 ++++++++++++ .../IPO/DeadFunctionElimination.cpp | 44 +++++---- lib/SILOptimizer/Utils/ModuleSummaryIndex.cpp | 97 ++++++++++++++++--- lib/Serialization/ModuleSummaryFile.cpp | 20 ++-- tools/driver/cross_module_opt_main.cpp | 15 ++- 15 files changed, 255 insertions(+), 60 deletions(-) diff --git a/include/swift/SIL/ModuleSummary.h b/include/swift/SIL/ModuleSummary.h index 626d8f1d17fc6..3f342be92227b 100644 --- a/include/swift/SIL/ModuleSummary.h +++ b/include/swift/SIL/ModuleSummary.h @@ -40,6 +40,7 @@ class FunctionSummary { public: class EdgeTy { GUID CalleeFn; + std::string Name; public: enum class Kind { @@ -52,12 +53,37 @@ class FunctionSummary { Kind kind; EdgeTy(SILDeclRef &CalleeFn, Kind kind) : kind(kind) { + this->Name = CalleeFn.mangle(); this->CalleeFn = getGUID(CalleeFn.mangle()); } public: Kind getKind() const { return kind; } GUID getCallee() const { return CalleeFn; } + std::string getName() const { return Name; }; + + void dump() const { + llvm::dbgs() << "FunctionSummary(kind: "; + switch (kind) { + case Kind::Witness: { + llvm::dbgs() << "Witness"; + break; + } + case Kind::VTable: { + llvm::dbgs() << "VTable"; + break; + } + case Kind::Static: { + llvm::dbgs() << "Static"; + break; + } + case Kind::kindCount: { + llvm_unreachable("impossible"); + } + } + llvm::dbgs() << ", name: " << getName() << " , callee: "; + llvm::dbgs() << getCallee() << ")\n"; + } VirtualMethodSlot slot() const { VirtualMethodSlot::KindTy slotKind; @@ -80,11 +106,12 @@ class FunctionSummary { return VirtualMethodSlot(slotKind, CalleeFn); } - EdgeTy(GUID callee, Kind kind) - : CalleeFn(callee), kind(kind) {} + EdgeTy(GUID callee, std::string name, Kind kind) + : CalleeFn(callee), Name(name), kind(kind) {} - static EdgeTy staticCall(GUID Callee) { - return EdgeTy(Callee, Kind::Static); + static EdgeTy staticCall(SILFunction *CalleeFn) { + GUID guid = getGUID(CalleeFn->getName()); + return EdgeTy(guid, CalleeFn->getName(), Kind::Static); } static EdgeTy witnessCall(SILDeclRef Callee) { @@ -98,6 +125,7 @@ class FunctionSummary { struct FlagsTy { unsigned Live : 1; + unsigned Preserved: 1; }; using CallGraphEdgeListTy = std::vector; @@ -111,14 +139,17 @@ class FunctionSummary { : CallGraphEdgeList(std::move(CGEdges)) {} FunctionSummary() = default; - void addCall(GUID targetGUID, EdgeTy::Kind kind) { - CallGraphEdgeList.emplace_back(targetGUID, kind); + void addCall(GUID targetGUID, std::string name, EdgeTy::Kind kind) { + CallGraphEdgeList.emplace_back(targetGUID, name, kind); } ArrayRef calls() const { return CallGraphEdgeList; } bool isLive() const { return Flags.Live; } void setLive(bool Live) { Flags.Live = Live; } + + bool isPreserved() const { return Flags.Preserved; } + void setPreserved(bool Preserved) { Flags.Preserved = Preserved; } }; struct FunctionSummaryInfo { diff --git a/include/swift/Serialization/ModuleSummaryFile.h b/include/swift/Serialization/ModuleSummaryFile.h index dee809284730f..18d138b398ec6 100644 --- a/include/swift/Serialization/ModuleSummaryFile.h +++ b/include/swift/Serialization/ModuleSummaryFile.h @@ -65,12 +65,14 @@ enum { using MetadataLayout = BCRecordLayout, // Function GUID BCFixed<1>, // live + BCFixed<1>, // preserved BCBlob // Name string >; using CallGraphEdgeLayout = BCRecordLayout, // FunctionSummary::Edge::Kind - BCVBR<16> // Target Function GUID + BCVBR<16>, // Target Function GUID + BCBlob // Name string >; } // namespace function_summary diff --git a/lib/FrontendTool/FrontendTool.cpp b/lib/FrontendTool/FrontendTool.cpp index 85a5d0c6d889d..bb7c05d3932c1 100644 --- a/lib/FrontendTool/FrontendTool.cpp +++ b/lib/FrontendTool/FrontendTool.cpp @@ -2059,15 +2059,15 @@ static bool performCompileStepsPostSILGen(CompilerInstance &Instance, if (observer) observer->performedSILProcessing(*SM); - if (Action == FrontendOptions::ActionType::EmitSIB) - return serializeSIB(SM.get(), PSPs, Context, MSF); - if (!opts.ModuleSummaryOutputPath.empty()) { if (emitModuleSummary(SM.get(), opts.ModuleSummaryOutputPath, Context)) { return true; } } + if (Action == FrontendOptions::ActionType::EmitSIB) + return serializeSIB(SM.get(), PSPs, Context, MSF); + if (PSPs.haveModuleOrModuleDocOutputPaths()) { if (Action == FrontendOptions::ActionType::MergeModules || Action == FrontendOptions::ActionType::EmitModuleOnly) { diff --git a/lib/IRGen/GenClass.cpp b/lib/IRGen/GenClass.cpp index 912f0e3ad6131..d3bdcfb962549 100644 --- a/lib/IRGen/GenClass.cpp +++ b/lib/IRGen/GenClass.cpp @@ -2246,6 +2246,7 @@ irgen::emitClassPrivateDataFields(IRGenModule &IGM, // This should only be used with generic classes. assert(cls->isGenericContext()); + llvm::dbgs() << "Emitting Class private data field for " << cls->getName() << "\n"; SILType selfType = getSelfType(cls); auto &classTI = IGM.getTypeInfo(selfType).as(); diff --git a/lib/IRGen/GenMeta.cpp b/lib/IRGen/GenMeta.cpp index 514f3798183c4..21e57af98bc0c 100644 --- a/lib/IRGen/GenMeta.cpp +++ b/lib/IRGen/GenMeta.cpp @@ -894,6 +894,8 @@ namespace { if (!entry.isValid() || entry.getKind() != SILWitnessTable::Method || entry.getMethodWitness().Requirement != func) continue; + if (!entry.getMethodWitness().Witness) + continue; return IGM.getAddrOfSILFunction(entry.getMethodWitness().Witness, NotForDefinition); } diff --git a/lib/IRGen/GenObjC.cpp b/lib/IRGen/GenObjC.cpp index c46cadcaa5745..5c118577a03b2 100644 --- a/lib/IRGen/GenObjC.cpp +++ b/lib/IRGen/GenObjC.cpp @@ -925,6 +925,7 @@ void irgen::emitObjCPartialApplication(IRGenFunction &IGF, static llvm::Constant *findSwiftAsObjCThunk(IRGenModule &IGM, SILDeclRef ref, SILFunction *&SILFn) { SILFn = IGM.getSILModule().lookUpFunction(ref); + llvm::dbgs() << "Looking for '" << ref.mangle() << "'\n"; assert(SILFn && "no IR function for swift-as-objc thunk"); auto fn = IGM.getAddrOfSILFunction(SILFn, NotForDefinition); ApplyIRLinkage(IRLinkage::Internal).to(fn); diff --git a/lib/SIL/IR/SILDefaultWitnessTable.cpp b/lib/SIL/IR/SILDefaultWitnessTable.cpp index 7c427f5ba6f89..69953d8e641c2 100644 --- a/lib/SIL/IR/SILDefaultWitnessTable.cpp +++ b/lib/SIL/IR/SILDefaultWitnessTable.cpp @@ -104,7 +104,7 @@ std::string SILDefaultWitnessTable::getUniqueName() const { SILDefaultWitnessTable::~SILDefaultWitnessTable() { // Drop the reference count of witness functions referenced by this table. for (auto entry : getEntries()) { - if (entry.isValid() && entry.getKind() == SILWitnessTable::Method) { + if (entry.isValid() && entry.getKind() == SILWitnessTable::Method && entry.getMethodWitness().Witness) { entry.getMethodWitness().Witness->decrementRefCount(); } } diff --git a/lib/SIL/IR/SILModule.cpp b/lib/SIL/IR/SILModule.cpp index e5c0dd5a3f842..ed9f344e63dac 100644 --- a/lib/SIL/IR/SILModule.cpp +++ b/lib/SIL/IR/SILModule.cpp @@ -112,22 +112,28 @@ SILModule::SILModule(llvm::PointerUnion context, SILModule::~SILModule() { // Decrement ref count for each SILGlobalVariable with static initializers. + llvm::dbgs() << "In SILModule::~SILModule()\n"; + llvm::dbgs() << "Before dropping global variable reference\n"; for (SILGlobalVariable &v : silGlobals) v.dropAllReferences(); + llvm::dbgs() << "After dropping reference\n"; + llvm::dbgs() << "Before destructing VTables\n"; for (auto vt : vtables) vt->~SILVTable(); - + llvm::dbgs() << "After destructing VTables\n"; // Drop everything functions in this module reference. // // This is necessary since the functions may reference each other. We don't // need to worry about sil_witness_tables since witness tables reference each // other via protocol conformances and sil_vtables don't reference each other // at all. + llvm::dbgs() << "Before dropping function reference\n"; for (SILFunction &F : *this) { F.dropAllReferences(); F.dropDynamicallyReplacedFunction(); } + llvm::dbgs() << "After dropping function reference\n"; } std::unique_ptr SILModule::createEmptyModule( diff --git a/lib/SIL/IR/SILVTable.cpp b/lib/SIL/IR/SILVTable.cpp index 1bb556736c348..3c4c46465a41d 100644 --- a/lib/SIL/IR/SILVTable.cpp +++ b/lib/SIL/IR/SILVTable.cpp @@ -75,6 +75,8 @@ SILVTable::SILVTable(ClassDecl *c, IsSerialized_t serialized, SILVTable::~SILVTable() { // Drop the reference count of functions referenced by this table. for (const Entry &entry : getEntries()) { - entry.getImplementation()->decrementRefCount(); + if (entry.getImplementation()) { + entry.getImplementation()->decrementRefCount(); + } } } diff --git a/lib/SIL/Verifier/SILVerifier.cpp b/lib/SIL/Verifier/SILVerifier.cpp index 8bf94cf5d4913..68be1d0140411 100644 --- a/lib/SIL/Verifier/SILVerifier.cpp +++ b/lib/SIL/Verifier/SILVerifier.cpp @@ -5521,7 +5521,8 @@ void SILDefaultWitnessTable::verify(const SILModule &M) const { continue; SILFunction *F = E.getMethodWitness().Witness; - + // Default witness can be null + if (!F) continue; #if 0 // FIXME: For now, all default witnesses are private. assert(F->hasValidLinkageForFragileRef() && @@ -5534,6 +5535,7 @@ void SILDefaultWitnessTable::verify(const SILModule &M) const { "Default witnesses must have witness_method representation."); } #endif + llvm::dbgs() << "End of SILDefaultWitnessTable::verify '" << getUniqueName() << "'\n"; } /// Verify that a global variable follows invariants. diff --git a/lib/SILOptimizer/IPO/CrossDeadFunctionElimination.cpp b/lib/SILOptimizer/IPO/CrossDeadFunctionElimination.cpp index e097afddd78c8..6f73bb849138c 100644 --- a/lib/SILOptimizer/IPO/CrossDeadFunctionElimination.cpp +++ b/lib/SILOptimizer/IPO/CrossDeadFunctionElimination.cpp @@ -54,6 +54,18 @@ class SILCrossDeadFuncElimination : public SILModuleTransform { return !info->isLive(); }); } + + for (auto &WT : M.getDefaultWitnessTables()) { + WT.clearMethods_if([&](SILFunction *MW) -> bool { + if (!MW) + return false; + auto &maybePair = TheSummary.getFunctionInfo(getGUID(MW->getName())); + if (!maybePair) + return false; + auto info = maybePair.getValue().first; + return !info->isLive(); + }); + } } void eliminateDeadFunctions(SILModule &M) { @@ -76,6 +88,56 @@ class SILCrossDeadFuncElimination : public SILModuleTransform { llvm::dbgs() << "Eliminate " << info.Name << "\n"; } } + + void ensureLive(SILFunction *F) { + ensureLive(getGUID(F->getName())); + } + + void ensureLive(GUID guid) { + auto maybePair = this->TheSummary.getFunctionInfo(guid); + if (maybePair) { + auto pair = maybePair.getValue(); + pair.first->setLive(true); + } + } + + void ensureLive(VirtualMethodSlot slot) { + auto Impls = this->TheSummary.getImplementations(slot); + if (!Impls) return; + for (auto Impl : Impls.getValue()) { + ensureLive(Impl); + } + } + + void + ensureKeyPathComponentIsAlive(const KeyPathPatternComponent &component) { + component.visitReferencedFunctionsAndMethods( + [this](SILFunction *F) { + this->ensureLive(F); + }, + [this](SILDeclRef method) { + auto decl = cast(method.getDecl()); + if (auto clas = dyn_cast(decl->getDeclContext())) { + VirtualMethodSlot slot(method, VirtualMethodSlot::KindTy::VTable); + this->ensureLive(slot); + } else if (isa(decl->getDeclContext())) { + VirtualMethodSlot slot(method, VirtualMethodSlot::KindTy::Witness); + this->ensureLive(slot); + } else { + llvm_unreachable("key path keyed by a non-class, non-protocol method"); + } + } + ); + } + + void ensurePreserved(SILModule &M) { + // Check property descriptor implementations. + for (SILProperty &P : M.getPropertyList()) { + if (auto component = P.getComponent()) { + ensureKeyPathComponentIsAlive(*component); + } + } + } void run() override { LLVM_DEBUG(llvm::dbgs() << "Running CrossDeadFuncElimination\n"); @@ -95,9 +157,11 @@ class SILCrossDeadFuncElimination : public SILModuleTransform { } auto &M = *getModule(); + this->ensurePreserved(M); this->eliminateDeadEntriesFromTables(M); this->eliminateDeadFunctions(M); this->invalidateFunctionTables(); + M.print(llvm::dbgs()); } }; diff --git a/lib/SILOptimizer/IPO/DeadFunctionElimination.cpp b/lib/SILOptimizer/IPO/DeadFunctionElimination.cpp index 053f899909d90..eb4e17030fc48 100644 --- a/lib/SILOptimizer/IPO/DeadFunctionElimination.cpp +++ b/lib/SILOptimizer/IPO/DeadFunctionElimination.cpp @@ -141,10 +141,14 @@ class FunctionLivenessComputation { } /// Marks a function as alive. - void makeAlive(SILFunction *F) { - AliveFunctionsAndTables.insert(F); - assert(F && "function does not exist"); - Worklist.insert(F); + void makeAlive(SILFunction *F, StringRef Context) { + if (F) { + AliveFunctionsAndTables.insert(F); + assert(F && "function does not exist"); + Worklist.insert(F); + } else { + llvm::dbgs() << "Found garbage in " << Context << "\n"; + } } /// Marks all contained functions and witness tables of a witness table as @@ -172,7 +176,7 @@ class FunctionLivenessComputation { if (F) { MethodInfo *MI = getMethodInfo(fd, /*isWitnessMethod*/ true); if (MI->methodIsCalled || !F->isDefinition()) - ensureAlive(F); + ensureAlive(F, "void makeAlive(SILWitnessTable *WT)"); } } break; @@ -205,7 +209,7 @@ class FunctionLivenessComputation { ensureKeyPathComponentIsAlive(const KeyPathPatternComponent &component) { component.visitReferencedFunctionsAndMethods( [this](SILFunction *F) { - ensureAlive(F); + ensureAlive(F, "ensureKeyPathComponentIsAlive"); }, [this](SILDeclRef method) { if (method.isForeign) { @@ -229,9 +233,9 @@ class FunctionLivenessComputation { } /// Marks a function as alive if it is not alive yet. - void ensureAlive(SILFunction *F) { + void ensureAlive(SILFunction *F, StringRef Context) { if (!isAlive(F)) - makeAlive(F); + makeAlive(F, Context); } /// Marks a witness table as alive if it is not alive yet. @@ -278,7 +282,7 @@ class FunctionLivenessComputation { if (!isAlive(FImpl.F) && canHaveSameImplementation(FD, MethodCl, FImpl.Impl.get())) { - makeAlive(FImpl.F); + makeAlive(FImpl.F, "ensureAliveClassMethod"); } else { allImplsAreCalled = false; } @@ -299,9 +303,9 @@ class FunctionLivenessComputation { Module->lookUpWitnessTable(Conf, /*deserializeLazily*/ false); if (!WT || isAlive(WT)) - makeAlive(FImpl.F); + makeAlive(FImpl.F, "ensureAliveProtocolMethod"); } else { - makeAlive(FImpl.F); + makeAlive(FImpl.F, "ensureAliveProtocolMethod"); } } } @@ -329,11 +333,11 @@ class FunctionLivenessComputation { MethodInfo *mi = getMethodInfo(funcDecl, /*isWitnessTable*/ false); ensureAliveClassMethod(mi, dyn_cast(funcDecl), MethodCl); } else if (auto *FRI = dyn_cast(&I)) { - ensureAlive(FRI->getInitiallyReferencedFunction()); + ensureAlive(FRI->getInitiallyReferencedFunction(), F->getName()); } else if (auto *FRI = dyn_cast(&I)) { - ensureAlive(FRI->getInitiallyReferencedFunction()); + ensureAlive(FRI->getInitiallyReferencedFunction(), F->getName()); } else if (auto *FRI = dyn_cast(&I)) { - ensureAlive(FRI->getInitiallyReferencedFunction()); + ensureAlive(FRI->getInitiallyReferencedFunction(), F->getName()); } else if (auto *KPI = dyn_cast(&I)) { for (auto &component : KPI->getPattern()->getComponents()) ensureKeyPathComponentIsAlive(component); @@ -388,13 +392,13 @@ class FunctionLivenessComputation { for (SILFunction &F : *Module) { if (isAnchorFunction(&F)) { LLVM_DEBUG(llvm::dbgs() << " anchor function: " << F.getName() <<"\n"); - ensureAlive(&F); + ensureAlive(&F, "findAnchors"); } if (!F.shouldOptimize()) { LLVM_DEBUG(llvm::dbgs() << " anchor a no optimization function: " << F.getName() << "\n"); - ensureAlive(&F); + ensureAlive(&F, "findAnchors.shouldOptimize"); } } } @@ -507,7 +511,7 @@ class DeadFunctionElimination : FunctionLivenessComputation { if (entry.getMethod().kind == SILDeclRef::Kind::Deallocator || entry.getMethod().kind == SILDeclRef::Kind::IVarDestroyer) { // Destructors are alive because they are called from swift_release - ensureAlive(entry.getImplementation()); + ensureAlive(entry.getImplementation(), "findAnchorsInTables.vtable"); continue; } @@ -591,11 +595,11 @@ class DeadFunctionElimination : FunctionLivenessComputation { } // Check differentiability witness entries. for (auto &dw : Module->getDifferentiabilityWitnessList()) { - ensureAlive(dw.getOriginalFunction()); + ensureAlive(dw.getOriginalFunction(), "findAnchorsInTables.differentiability"); if (dw.getJVP()) - ensureAlive(dw.getJVP()); + ensureAlive(dw.getJVP(), "findAnchorsInTables.differentiability"); if (dw.getVJP()) - ensureAlive(dw.getVJP()); + ensureAlive(dw.getVJP(), "findAnchorsInTables.differentiability"); } } diff --git a/lib/SILOptimizer/Utils/ModuleSummaryIndex.cpp b/lib/SILOptimizer/Utils/ModuleSummaryIndex.cpp index 90e8724f7c0ba..795d40495fa32 100644 --- a/lib/SILOptimizer/Utils/ModuleSummaryIndex.cpp +++ b/lib/SILOptimizer/Utils/ModuleSummaryIndex.cpp @@ -30,7 +30,7 @@ void FunctionSummaryIndexer::indexInstruction(SILFunction &F, SILInstruction *I) SILFunction *callee = FRI->getReferencedFunctionOrNull(); assert(callee); auto edge = - FunctionSummary::EdgeTy::staticCall(getGUID(callee->getName())); + FunctionSummary::EdgeTy::staticCall(callee); CallGraphEdgeList.push_back(edge); return; } @@ -46,6 +46,30 @@ void FunctionSummaryIndexer::indexInstruction(SILFunction &F, SILInstruction *I) CallGraphEdgeList.push_back(edge); return; } + + if (auto *KPI = dyn_cast(I)) { + for (auto &component : KPI->getPattern()->getComponents()) { + component.visitReferencedFunctionsAndMethods( + [this](SILFunction *F) { + auto edge = + FunctionSummary::EdgeTy::staticCall(F); + CallGraphEdgeList.push_back(edge); + }, + [this](SILDeclRef method) { + auto decl = cast(method.getDecl()); + if (auto clas = dyn_cast(decl->getDeclContext())) { + auto edge = FunctionSummary::EdgeTy::vtableCall(method); + CallGraphEdgeList.push_back(edge); + } else if (isa(decl->getDeclContext())) { + auto edge = FunctionSummary::EdgeTy::witnessCall(method); + CallGraphEdgeList.push_back(edge); + } else { + llvm_unreachable("key path keyed by a non-class, non-protocol method"); + } + } + ); + } + } } void FunctionSummaryIndexer::indexFunction(SILFunction &F) { @@ -58,7 +82,7 @@ void FunctionSummaryIndexer::indexFunction(SILFunction &F) { }; std::unique_ptr -buildFunctionSummaryIndex(SILFunction &F, BasicCalleeAnalysis &BCA) { +buildFunctionSummaryIndex(SILFunction &F) { FunctionSummaryIndexer indexer; indexer.indexFunction(F); return indexer.takeSummary(); @@ -76,12 +100,58 @@ void indexWitnessTable(ModuleSummaryIndex &index, SILWitnessTable &WT) { } -void indexVTable(ModuleSummaryIndex &index, SILVTable &VT) { - for (auto entry : VT.getEntries()) { - auto Impl = entry.getImplementation(); - VirtualMethodSlot slot(entry.getMethod(), VirtualMethodSlot::KindTy::VTable); - index.addImplementation(slot, getGUID(Impl->getName())); +void indexVTable(ModuleSummaryIndex &index, SILModule &M) { + std::vector Preserved; + for (auto &VT : M.getVTables()) { + for (auto entry : VT->getEntries()) { + auto Impl = entry.getImplementation(); + if (entry.getMethod().kind == SILDeclRef::Kind::Deallocator || + entry.getMethod().kind == SILDeclRef::Kind::IVarDestroyer) { + // Destructors are alive because they are called from swift_release + auto edge = FunctionSummary::EdgeTy::staticCall(Impl); + llvm::dbgs() << "Preserve deallocator '" << Impl->getName() << "'\n"; + Preserved.push_back(edge); + } + VirtualMethodSlot slot(entry.getMethod(), VirtualMethodSlot::KindTy::VTable); + index.addImplementation(slot, getGUID(Impl->getName())); + } } + + auto FS = std::make_unique(Preserved); + FS->setPreserved(true); + llvm::dbgs() << "Summary: Preserved " << Preserved.size() << " deallocators\n"; + index.addFunctionSummary("__destructors_preserved_fs", std::move(FS)); +} + +void indexKeyPathComponent(ModuleSummaryIndex &index, SILModule &M) { + std::vector CallGraphEdgeList; + for (SILProperty &P : M.getPropertyList()) { + if (auto component = P.getComponent()) { + component->visitReferencedFunctionsAndMethods( + [&](SILFunction *F) { + auto FS = buildFunctionSummaryIndex(*F); + llvm::dbgs() << "Preserve keypath funcs " << F->getName() << "\n"; + FS->setPreserved(true); + index.addFunctionSummary(F->getName(), std::move(FS)); + }, + [&](SILDeclRef method) { + auto decl = cast(method.getDecl()); + if (auto clas = dyn_cast(decl->getDeclContext())) { + auto edge = FunctionSummary::EdgeTy::vtableCall(method); + CallGraphEdgeList.push_back(edge); + } else if (isa(decl->getDeclContext())) { + auto edge = FunctionSummary::EdgeTy::witnessCall(method); + CallGraphEdgeList.push_back(edge); + } else { + llvm_unreachable("key path keyed by a non-class, non-protocol method"); + } + } + ); + } + } + auto FS = std::make_unique(std::move(CallGraphEdgeList)); + FS->setPreserved(true); + index.addFunctionSummary("__keypath_preserved_fs", std::move(FS)); } ModuleSummaryIndex swift::buildModuleSummaryIndex(SILModule &M, @@ -89,9 +159,16 @@ ModuleSummaryIndex swift::buildModuleSummaryIndex(SILModule &M, ModuleSummaryIndex index; index.setModuleName(M.getSwiftModule()->getName().str()); + + // Preserve keypath things temporarily + indexKeyPathComponent(index, M); for (auto &F : M) { - auto FS = buildFunctionSummaryIndex(F, BCA); + auto FS = buildFunctionSummaryIndex(F); + if (F.getRepresentation() == SILFunctionTypeRepresentation::ObjCMethod) { + llvm::dbgs() << "Preserve " << F.getName() << " due to ObjCMethod\n"; + FS->setPreserved(true); + } FS->setLive(false); index.addFunctionSummary(F.getName(), std::move(FS)); } @@ -100,8 +177,6 @@ ModuleSummaryIndex swift::buildModuleSummaryIndex(SILModule &M, indexWitnessTable(index, WT); } - for (auto &VT : M.getVTables()) { - indexVTable(index, *VT); - } + indexVTable(index, M); return index; } diff --git a/lib/Serialization/ModuleSummaryFile.cpp b/lib/Serialization/ModuleSummaryFile.cpp index 090cdeb027ac1..1bce424a9fb1b 100644 --- a/lib/Serialization/ModuleSummaryFile.cpp +++ b/lib/Serialization/ModuleSummaryFile.cpp @@ -102,32 +102,30 @@ void Serializer::emitHeader() { void Serializer::emitModuleSummary(const ModuleSummaryIndex &index) { using namespace module_summary; - llvm::BCBlockRAII restoreBlock(Out, MODULE_SUMMARY_ID, 3); + llvm::BCBlockRAII restoreBlock(Out, MODULE_SUMMARY_ID, 4); module_summary::MetadataLayout MDLayout(Out); MDLayout.emit(ScratchRecord, index.getModuleName()); { for (const auto &pair : index) { - llvm::BCBlockRAII restoreBlock(Out, FUNCTION_SUMMARY_ID, 4); + llvm::BCBlockRAII restoreBlock(Out, FUNCTION_SUMMARY_ID, 32); auto &info = pair.second; auto &summary = info.TheSummary; using namespace function_summary; function_summary::MetadataLayout MDlayout(Out); - llvm::dbgs() << "Emitting " << info.Name << "\n"; - - MDlayout.emit(ScratchRecord, pair.first, summary->isLive(), info.Name); + MDlayout.emit(ScratchRecord, pair.first, summary->isLive(), summary->isPreserved(), info.Name); for (auto call : summary->calls()) { CallGraphEdgeLayout edgeLayout(Out); edgeLayout.emit(ScratchRecord, unsigned(call.getKind()), - call.getCallee()); + call.getCallee(), call.getName()); } } } { for (auto &method : index.virtualMethods()) { - llvm::BCBlockRAII restoreBlock(Out, VIRTUAL_METHOD_INFO_ID, 5); + llvm::BCBlockRAII restoreBlock(Out, VIRTUAL_METHOD_INFO_ID, 8); auto &slot = method.first; auto impls = method.second; using namespace virtual_method_info; @@ -251,8 +249,8 @@ bool Deserializer::readFunctionSummary() { switch (maybeKind.get()) { case function_summary::METADATA: { - unsigned isLive; - function_summary::MetadataLayout::readRecord(Scratch, guid, isLive); + unsigned isLive, isPreserved; + function_summary::MetadataLayout::readRecord(Scratch, guid, isLive, isPreserved); Name = BlobData.str(); if (auto info = moduleSummary.getFunctionInfo(guid)) { FS = info.getValue().first; @@ -261,6 +259,7 @@ bool Deserializer::readFunctionSummary() { FS = NewFSOwner.get(); } FS->setLive(isLive); + FS->setPreserved(isPreserved); break; } case function_summary::CALL_GRAPH_EDGE: { @@ -274,7 +273,7 @@ bool Deserializer::readFunctionSummary() { if (!FS) llvm::report_fatal_error("Invalid state"); - FS->addCall(targetGUID, edgeKind.getValue()); + FS->addCall(targetGUID, BlobData.str(), edgeKind.getValue()); break; } } @@ -286,7 +285,6 @@ bool Deserializer::readFunctionSummary() { next = maybeNext.get(); } - llvm::dbgs() << "Added " << Name << " in FS list\n"; if (auto &FS = NewFSOwner) { moduleSummary.addFunctionSummary(Name, std::move(FS)); } diff --git a/tools/driver/cross_module_opt_main.cpp b/tools/driver/cross_module_opt_main.cpp index d2da3e6a0a33a..201cdeb9b01c6 100644 --- a/tools/driver/cross_module_opt_main.cpp +++ b/tools/driver/cross_module_opt_main.cpp @@ -76,9 +76,15 @@ class MergeModuleSummaryInvocation { } }; -static llvm::DenseSet computePreservedGUIDs() { +static llvm::DenseSet computePreservedGUIDs(ModuleSummaryIndex *summary) { llvm::DenseSet Set(1); Set.insert(getGUID("main")); + for (auto &pair : *summary) { + auto &info = pair.second; + if (info.TheSummary->isPreserved()) { + Set.insert(pair.first); + } + } return Set; } @@ -115,8 +121,9 @@ void markDeadSymbols(ModuleSummaryIndex &summary, llvm::DenseSet &Preserve case FunctionSummary::EdgeTy::Kind::Witness: case FunctionSummary::EdgeTy::Kind::VTable: { auto Impls = summary.getImplementations(Call.slot()); - if (!Impls) - llvm_unreachable("Impls not found for the slot"); + if (!Impls) { + continue; + } for (auto Impl : Impls.getValue()) { Worklist.push_back(Impl); } @@ -166,7 +173,7 @@ int cross_module_opt_main(ArrayRef Args, const char *Argv0, TheSummary->setModuleName("combined"); - auto PreservedGUIDs = computePreservedGUIDs(); + auto PreservedGUIDs = computePreservedGUIDs(TheSummary.get()); markDeadSymbols(*TheSummary.get(), PreservedGUIDs); modulesummary::emitModuleSummaryIndex(*TheSummary, Instance.getDiags(), From 9462d57d3d9ca2aa699b12e8019048cbccf65ee3 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Tue, 21 Jul 2020 11:53:39 +0900 Subject: [PATCH 24/77] Fix tests --- test/Serialization/module-summary.swift | 32 ++++++++++++------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/test/Serialization/module-summary.swift b/test/Serialization/module-summary.swift index 8d85e73e99e76..68a1abd7a5c8b 100644 --- a/test/Serialization/module-summary.swift +++ b/test/Serialization/module-summary.swift @@ -4,34 +4,34 @@ // RUN: %target-swift-frontend -emit-sil %s -emit-module-summary-path %t/module-summary.swiftmodule.summary -I %t > /dev/null // RUN: llvm-bcanalyzer -dump %t/module-summary.swiftmodule.summary | %FileCheck %s --check-prefix MAIN-CHECK -// MAIN-CHECK: blob data = '$s4main10publicFuncyyF' +// MAIN-CHECK: blob data = '$s4main10publicFuncyyF' // Ensure that call graph edge has correct function guid -// MAIN-CHECK: blob data = '$s7module20A4FuncSiyF' -// MAIN-CHECK: blob data = 'main' +// MAIN-CHECK: blob data = '$s7module20A4FuncSiyF' +// MAIN-CHECK: blob data = 'main' // MAIN-CHECK-NEXT: // MAIN-CHECK-NEXT: // MAIN-CHECK-NEXT: // MAIN-CHECK-NEXT: -// MAIN-CHECK: blob data = '$s4main9callTwiceyyF' +// MAIN-CHECK: blob data = '$s4main9callTwiceyyF' // MAIN-CHECK-NEXT: // MAIN-CHECK-NEXT: // MAIN-CHECK-NEXT: // RUN: llvm-bcanalyzer -dump %t/module2.swiftmodule.summary | %FileCheck %s --check-prefix TABLE-CHECK -// TABLE-CHECK-DAG: blob data = '$s7module29Concrete2V7module11PAadEP15defaultProvidedyyFTW' -// TABLE-CHECK-DAG: blob data = '$s7module29Concrete2V7module11PAadEP12memberMethodyyFTW' +// TABLE-CHECK-DAG: blob data = '$s7module29Concrete2V7module11PAadEP15defaultProvidedyyFTW' +// TABLE-CHECK-DAG: blob data = '$s7module29Concrete2V7module11PAadEP12memberMethodyyFTW' -// TABLE-CHECK: blob data = '$s7module24usePyyx7module11PRzlF' -// TABLE-CHECK-NEXT: +// TABLE-CHECK: blob data = '$s7module24usePyyx7module11PRzlF' +// TABLE-CHECK-NEXT: // TABLE-CHECK-NEXT: -// TABLE-CHECK-DAG: blob data = '$s7module29Concrete1V7module11PAadEP15defaultProvidedyyFTW' -// TABLE-CHECK-DAG: blob data = '$s7module29Concrete1V7module11PAadEP12memberMethodyyFTW' +// TABLE-CHECK-DAG: blob data = '$s7module29Concrete1V7module11PAadEP15defaultProvidedyyFTW' +// TABLE-CHECK-DAG: blob data = '$s7module29Concrete1V7module11PAadEP12memberMethodyyFTW' // TABLE-CHECK: // TABLE-CHECK-NEXT: @@ -47,19 +47,19 @@ // RUN: %swift_frontend_plain -cross-module-opt %t/module-summary.swiftmodule.summary %t/module1.swiftmodule.summary %t/module2.swiftmodule.summary -o %t/merged-module.summary // RUN: llvm-bcanalyzer -dump %t/merged-module.summary | %FileCheck %s --check-prefix MERGED-CHECK -// MERGED-CHECK: blob data = '$s7module10A4FuncSiyF' +// MERGED-CHECK: blob data = '$s7module10A4FuncSiyF' // MERGED-CHECK-NEXT: -// MERGED-CHECK: blob data = '$s7module20A4FuncSiyF' +// MERGED-CHECK: blob data = '$s7module20A4FuncSiyF' // MERGED-CHECK-NEXT: // MERGED-CHECK-NEXT: // RUN: llvm-bcanalyzer -dump %t/merged-module.summary | %FileCheck %s --check-prefix LIVE-CHECK -// LIVE-CHECK-DAG: blob data = '$s4main10publicFuncyyF' -// LIVE-CHECK-DAG: blob data = '$s4main3fooyyF' -// LIVE-CHECK-DAG: blob data = 'main' -// LIVE-CHECK-DAG: blob data = '$s4main3baryySiF' +// LIVE-CHECK-DAG: blob data = '$s4main10publicFuncyyF' +// LIVE-CHECK-DAG: blob data = '$s4main3fooyyF' +// LIVE-CHECK-DAG: blob data = 'main' +// LIVE-CHECK-DAG: blob data = '$s4main3baryySiF' // RUN: %target-swift-frontend -emit-sil %s -I %t -o %t/main.sil // RUN: %target-sil-opt -emit-sorted-sil %t/main.sil -module-summary-path %t/merged-module.summary --sil-cross-deadfuncelim -I %t | %FileCheck %s --check-prefix DEADFUNC-MAIN-CHECK From 17120349723c4a6edd506655d3599a1857f58a7d Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Wed, 22 Jul 2020 02:48:56 +0900 Subject: [PATCH 25/77] WIP --- .../SILOptimizer/PassManager/PassPipeline.def | 1 + .../swift/SILOptimizer/PassManager/Passes.h | 2 ++ lib/Frontend/Frontend.cpp | 3 ++ lib/IRGen/GenDecl.cpp | 2 ++ lib/IRGen/GenObjC.cpp | 1 - lib/SIL/Verifier/SILVerifier.cpp | 1 - .../IPO/CrossDeadFunctionElimination.cpp | 36 ++++++++++++------- lib/SILOptimizer/PassManager/PassPipeline.cpp | 8 ++++- lib/SILOptimizer/PassManager/Passes.cpp | 10 ++++++ lib/SILOptimizer/Utils/ModuleSummaryIndex.cpp | 1 + test/Serialization/module-summary.swift | 23 ++++++------ 11 files changed, 63 insertions(+), 25 deletions(-) diff --git a/include/swift/SILOptimizer/PassManager/PassPipeline.def b/include/swift/SILOptimizer/PassManager/PassPipeline.def index ebc3eed48cc80..88dc64381d95c 100644 --- a/include/swift/SILOptimizer/PassManager/PassPipeline.def +++ b/include/swift/SILOptimizer/PassManager/PassPipeline.def @@ -24,6 +24,7 @@ PASSPIPELINE(Diagnostic, "Guaranteed Passes") PASSPIPELINE(OwnershipEliminator, "Utility pass to just run the ownership eliminator pass") +PASSPIPELINE(CrossModuleEliminator, "Passes run at -module-summary-path") PASSPIPELINE(Performance, "Passes run at -O") PASSPIPELINE(Onone, "Passes run at -Onone") PASSPIPELINE(InstCount, "Utility pipeline to just run the inst count pass") diff --git a/include/swift/SILOptimizer/PassManager/Passes.h b/include/swift/SILOptimizer/PassManager/Passes.h index ec587e24e086b..602944412e447 100644 --- a/include/swift/SILOptimizer/PassManager/Passes.h +++ b/include/swift/SILOptimizer/PassManager/Passes.h @@ -42,6 +42,8 @@ namespace swift { /// Run the SIL ownership eliminator pass on \p M. bool runSILOwnershipEliminatorPass(SILModule &M); + bool runSILCrossModuleEliminatorPass(SILModule &M); + void runSILOptimizationPassesWithFileSpecification(SILModule &Module, StringRef FileName); diff --git a/lib/Frontend/Frontend.cpp b/lib/Frontend/Frontend.cpp index 7e000a0b6a563..edb5e3d9cef2c 100644 --- a/lib/Frontend/Frontend.cpp +++ b/lib/Frontend/Frontend.cpp @@ -1066,6 +1066,9 @@ bool CompilerInstance::performSILProcessing(SILModule *silModule) { } performSILInstCountIfNeeded(silModule); + if (runSILCrossModuleEliminatorPass(*silModule)) { + return true; + } return false; } diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp index 93e9c6c2e7d57..e7d7751f37a53 100644 --- a/lib/IRGen/GenDecl.cpp +++ b/lib/IRGen/GenDecl.cpp @@ -1036,6 +1036,7 @@ void IRGenerator::emitGlobalTopLevel( // correspond to definitions in the LLVM module. unsigned nextOrderNumber = 0; for (auto &silFn : PrimaryIGM->getSILModule().getFunctions()) { + llvm::dbgs() << "[katei debug] SILFunction " << silFn.getName() << "\n"; // Don't bother adding external declarations to the function order. if (!silFn.isDefinition()) continue; FunctionOrder.insert(std::make_pair(&silFn, nextOrderNumber++)); @@ -1223,6 +1224,7 @@ void IRGenerator::emitLazyDefinitions() { // Emit any lazy function definitions we require. while (!LazyFunctionDefinitions.empty()) { SILFunction *f = LazyFunctionDefinitions.pop_back_val(); + llvm::dbgs() << "[katei debug] Emit lazy fn " << f->getName() << "\n"; CurrentIGMPtr IGM = getGenModule(f); assert(!f->isPossiblyUsedExternally() && "function with externally-visible linkage emitted lazily?"); diff --git a/lib/IRGen/GenObjC.cpp b/lib/IRGen/GenObjC.cpp index 5c118577a03b2..c46cadcaa5745 100644 --- a/lib/IRGen/GenObjC.cpp +++ b/lib/IRGen/GenObjC.cpp @@ -925,7 +925,6 @@ void irgen::emitObjCPartialApplication(IRGenFunction &IGF, static llvm::Constant *findSwiftAsObjCThunk(IRGenModule &IGM, SILDeclRef ref, SILFunction *&SILFn) { SILFn = IGM.getSILModule().lookUpFunction(ref); - llvm::dbgs() << "Looking for '" << ref.mangle() << "'\n"; assert(SILFn && "no IR function for swift-as-objc thunk"); auto fn = IGM.getAddrOfSILFunction(SILFn, NotForDefinition); ApplyIRLinkage(IRLinkage::Internal).to(fn); diff --git a/lib/SIL/Verifier/SILVerifier.cpp b/lib/SIL/Verifier/SILVerifier.cpp index 68be1d0140411..ec8c14c7801af 100644 --- a/lib/SIL/Verifier/SILVerifier.cpp +++ b/lib/SIL/Verifier/SILVerifier.cpp @@ -5535,7 +5535,6 @@ void SILDefaultWitnessTable::verify(const SILModule &M) const { "Default witnesses must have witness_method representation."); } #endif - llvm::dbgs() << "End of SILDefaultWitnessTable::verify '" << getUniqueName() << "'\n"; } /// Verify that a global variable follows invariants. diff --git a/lib/SILOptimizer/IPO/CrossDeadFunctionElimination.cpp b/lib/SILOptimizer/IPO/CrossDeadFunctionElimination.cpp index 6f73bb849138c..4100e3afb1e1d 100644 --- a/lib/SILOptimizer/IPO/CrossDeadFunctionElimination.cpp +++ b/lib/SILOptimizer/IPO/CrossDeadFunctionElimination.cpp @@ -42,10 +42,12 @@ class SILCrossDeadFuncElimination : public SILModuleTransform { return !info->isLive(); }); } - - - for (auto &WT : M.getWitnessTableList()) { - WT.clearMethods_if([&] (const SILWitnessTable::MethodWitness &MW) -> bool { + + auto &WitnessTables = M.getWitnessTableList(); + for (auto WI = WitnessTables.begin(), EI = WitnessTables.end(); WI != EI;) { + SILWitnessTable *WT = &*WI; + ++WI; + WT->clearMethods_if([&] (const SILWitnessTable::MethodWitness &MW) -> bool { auto Impl = MW.Witness; auto &maybePair = TheSummary.getFunctionInfo(getGUID(Impl->getName())); if (!maybePair) @@ -55,8 +57,13 @@ class SILCrossDeadFuncElimination : public SILModuleTransform { }); } - for (auto &WT : M.getDefaultWitnessTables()) { - WT.clearMethods_if([&](SILFunction *MW) -> bool { + auto DefaultWitnessTables = M.getDefaultWitnessTables(); + for (auto WI = DefaultWitnessTables.begin(), + EI = DefaultWitnessTables.end(); + WI != EI;) { + SILDefaultWitnessTable *WT = &*WI; + ++WI; + WT->clearMethods_if([&](SILFunction *MW) -> bool { if (!MW) return false; auto &maybePair = TheSummary.getFunctionInfo(getGUID(MW->getName())); @@ -68,7 +75,7 @@ class SILCrossDeadFuncElimination : public SILModuleTransform { } } - void eliminateDeadFunctions(SILModule &M) { + void eliminateDeadFunctions(SILModule &M, std::vector &DeadFunctions) { for (auto &pair : TheSummary) { auto &info = pair.second; if (info.TheSummary->isLive()) { @@ -82,9 +89,7 @@ class SILCrossDeadFuncElimination : public SILModuleTransform { continue; } F->dropAllReferences(); - notifyWillDeleteFunction(F); - M.eraseFunction(F); - + DeadFunctions.push_back(F); llvm::dbgs() << "Eliminate " << info.Name << "\n"; } } @@ -159,9 +164,16 @@ class SILCrossDeadFuncElimination : public SILModuleTransform { auto &M = *getModule(); this->ensurePreserved(M); this->eliminateDeadEntriesFromTables(M); - this->eliminateDeadFunctions(M); + std::vector DeadFunctions; + this->eliminateDeadFunctions(M, DeadFunctions); + + while (!DeadFunctions.empty()) { + SILFunction *F = DeadFunctions.back(); + DeadFunctions.pop_back(); + notifyWillDeleteFunction(F); + M.eraseFunction(F); + } this->invalidateFunctionTables(); - M.print(llvm::dbgs()); } }; diff --git a/lib/SILOptimizer/PassManager/PassPipeline.cpp b/lib/SILOptimizer/PassManager/PassPipeline.cpp index c1b2e9606cd36..c687d1a25fecc 100644 --- a/lib/SILOptimizer/PassManager/PassPipeline.cpp +++ b/lib/SILOptimizer/PassManager/PassPipeline.cpp @@ -709,6 +709,13 @@ SILPassPipelinePlan::getIRGenPreparePassPipeline(const SILOptions &Options) { return P; } +SILPassPipelinePlan +SILPassPipelinePlan::getCrossModuleEliminatorPassPipeline(const SILOptions &Options) { + SILPassPipelinePlan P(Options); + addCrossModuleOptimizationsPipeline(P, Options); + return P; +} + SILPassPipelinePlan SILPassPipelinePlan::getPerformancePassPipeline(const SILOptions &Options) { SILPassPipelinePlan P(Options); @@ -718,7 +725,6 @@ SILPassPipelinePlan::getPerformancePassPipeline(const SILOptions &Options) { return P; } - addCrossModuleOptimizationsPipeline(P, Options); // Passes which run once before all other optimizations run. Those passes are // _not_ intended to run later again. addPrepareOptimizationsPipeline(P); diff --git a/lib/SILOptimizer/PassManager/Passes.cpp b/lib/SILOptimizer/PassManager/Passes.cpp index 1d57b543bda66..be76b9a8ca50f 100644 --- a/lib/SILOptimizer/PassManager/Passes.cpp +++ b/lib/SILOptimizer/PassManager/Passes.cpp @@ -84,6 +84,16 @@ bool swift::runSILOwnershipEliminatorPass(SILModule &Module) { return Ctx.hadError(); } +bool swift::runSILCrossModuleEliminatorPass(SILModule &Module) { + auto &Ctx = Module.getASTContext(); + + auto &opts = Module.getOptions(); + executePassPipelinePlan( + &Module, SILPassPipelinePlan::getCrossModuleEliminatorPassPipeline(opts)); + + return Ctx.hadError(); +} + void swift::runSILOptimizationPasses(SILModule &Module) { auto &opts = Module.getOptions(); diff --git a/lib/SILOptimizer/Utils/ModuleSummaryIndex.cpp b/lib/SILOptimizer/Utils/ModuleSummaryIndex.cpp index 795d40495fa32..e5d1413e775e4 100644 --- a/lib/SILOptimizer/Utils/ModuleSummaryIndex.cpp +++ b/lib/SILOptimizer/Utils/ModuleSummaryIndex.cpp @@ -94,6 +94,7 @@ void indexWitnessTable(ModuleSummaryIndex &index, SILWitnessTable &WT) { auto methodWitness = entry.getMethodWitness(); auto Witness = methodWitness.Witness; + if (!Witness) continue; VirtualMethodSlot slot(methodWitness.Requirement, VirtualMethodSlot::KindTy::Witness); index.addImplementation(slot, getGUID(Witness->getName())); } diff --git a/test/Serialization/module-summary.swift b/test/Serialization/module-summary.swift index 68a1abd7a5c8b..8a3db3eb60d3a 100644 --- a/test/Serialization/module-summary.swift +++ b/test/Serialization/module-summary.swift @@ -77,16 +77,19 @@ // RUN: %target-swift-frontend -emit-sil %S/Inputs/module2.swift -parse-as-library -module-summary-path %t/merged-module.summary -I %t -O | %FileCheck %s --check-prefix DEADFUNC-MODULE2-CHECK -// DEADFUNC-MODULE2-CHECK-DAG: @$s7module29Concrete1V12memberMethodyyF -// DEADFUNC-MODULE2-CHECK-DAG: @$s7module29Concrete1V7module11PAadEP12memberMethodyyFTW -// DEADFUNC-MODULE2-CHECK-DAG: @$s7module29Concrete2V12memberMethodyyF -// DEADFUNC-MODULE2-CHECK-DAG: @$s7module29Concrete2V7module11PAadEP12memberMethodyyFTW -// DEADFUNC-MODULE2-CHECK-DAG: @$s7module24usePyyx7module11PRzlF - -// DEADFUNC-MODULE2-CHECK-NOT: @$s7module29Concrete2V7module11PAadEP15defaultProvidedyyFTW -// DEADFUNC-MODULE2-CHECK-NOT: @$s7module20A4FuncSiyF -// DEADFUNC-MODULE2-CHECK-NOT: @$s7module29Concrete1V7module11PAadEP15defaultProvidedyyFTW -// DEADFUNC-MODULE2-CHECK-NOT: @$s7module11PPAAE15defaultProvidedyyF +// DEADFUNC-MODULE2-CHECK-DAG: $s7module29Concrete1V12memberMethodyyF +// DEADFUNC-MODULE2-CHECK-DAG: $s7module29Concrete1V7module11PAadEP12memberMethodyyFTW +// DEADFUNC-MODULE2-CHECK-DAG: $s7module29Concrete2V12memberMethodyyF +// DEADFUNC-MODULE2-CHECK-DAG: $s7module29Concrete2V7module11PAadEP12memberMethodyyFTW +// DEADFUNC-MODULE2-CHECK-DAG: $s7module24usePyyx7module11PRzlF + +// DEADFUNC-MODULE2-CHECK-NOT: $s7module29Concrete2V7module11PAadEP15defaultProvidedyyFTW +// DEADFUNC-MODULE2-CHECK-NOT: $s7module20A4FuncSiyF +// DEADFUNC-MODULE2-CHECK-NOT: $s7module29Concrete1V7module11PAadEP15defaultProvidedyyFTW +// DEADFUNC-MODULE2-CHECK-NOT: $s7module11PPAAE15defaultProvidedyyF + + +// RUN: %target-swift-frontend -emit-ir %S/Inputs/module2.swift -parse-as-library -module-summary-path %t/merged-module.summary -I %t -O | %FileCheck %s --check-prefix DEADFUNC-MODULE2-CHECK import module1 import module2 From ef4e2b543d3fd28052f5a4c277f52295a8dca4fc Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Fri, 31 Jul 2020 21:55:59 +0900 Subject: [PATCH 26/77] Pass link --- lib/IRGen/GenDecl.cpp | 72 ++++++++++++++++++++++++++++++++++++++++- lib/IRGen/GenProto.cpp | 2 +- lib/IRGen/IRGen.cpp | 6 ++++ lib/IRGen/IRGenModule.h | 2 ++ 4 files changed, 80 insertions(+), 2 deletions(-) diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp index e7d7751f37a53..c807e78dd3873 100644 --- a/lib/IRGen/GenDecl.cpp +++ b/lib/IRGen/GenDecl.cpp @@ -31,6 +31,7 @@ #include "swift/Demangling/ManglingMacros.h" #include "swift/IRGen/Linking.h" #include "swift/Runtime/HeapObject.h" +#include "swift/Serialization/SerializedModuleLoader.h" #include "swift/SIL/FormalLinkage.h" #include "swift/SIL/SILDebugScope.h" #include "swift/SIL/SILModule.h" @@ -439,6 +440,18 @@ class PrettySynthesizedFileUnitEmission : public llvm::PrettyStackTraceEntry { } }; +class PrettySerializedASTFileUnitEmission : public llvm::PrettyStackTraceEntry { + const SerializedASTFile &SAF; + +public: + explicit PrettySerializedASTFileUnitEmission(const SerializedASTFile &SAF) + : SAF(SAF) {} + + void print(raw_ostream &os) const override { + os << "While emitting IR for serialized ast file" << &SAF << "\n"; + } +}; + } // end anonymous namespace /// Emit all the top-level code in the source file. @@ -499,6 +512,64 @@ void IRGenModule::emitSourceFile(SourceFile &SF) { } } +void IRGenModule::emitSerializedASTFile(SerializedASTFile &SAF) { + PrettySerializedASTFileUnitEmission StackEntry(SAF); + SmallVector TopLevelDecls; + SmallVector LocalTypeDecls; + SmallVector OpaqueReturnTypeDecls; + SAF.getTopLevelDecls(TopLevelDecls); + SAF.getLocalTypeDecls(LocalTypeDecls); + SAF.getOpaqueReturnTypeDecls(OpaqueReturnTypeDecls); + // Emit types and other global decls. + for (auto *decl : TopLevelDecls) + emitGlobalDecl(decl); + for (auto *localDecl : LocalTypeDecls) + emitGlobalDecl(localDecl); + for (auto *opaqueDecl : OpaqueReturnTypeDecls) + maybeEmitOpaqueTypeDecl(opaqueDecl); + + SAF.collectLinkLibraries([this](LinkLibrary linkLib) { + this->addLinkLibrary(linkLib); + }); + + if (ObjCInterop) + this->addLinkLibrary(LinkLibrary("objc", LibraryKind::Library)); + + // FIXME: It'd be better to have the driver invocation or build system that + // executes the linker introduce these compatibility libraries, since at + // that point we know whether we're building an executable, which is the only + // place where the compatibility libraries take effect. For the benefit of + // build systems that build Swift code, but don't use Swift to drive + // the linker, we can also use autolinking to pull in the compatibility + // libraries. This may however cause the library to get pulled in in + // situations where it isn't useful, such as for dylibs, though this is + // harmless aside from code size. + if (!IRGen.Opts.UseJIT) { + if (auto compatibilityVersion + = IRGen.Opts.AutolinkRuntimeCompatibilityLibraryVersion) { + if (*compatibilityVersion <= llvm::VersionTuple(5, 0)) { + this->addLinkLibrary(LinkLibrary("swiftCompatibility50", + LibraryKind::Library, + /*forceLoad*/ true)); + } + if (*compatibilityVersion <= llvm::VersionTuple(5, 1)) { + this->addLinkLibrary(LinkLibrary("swiftCompatibility51", + LibraryKind::Library, + /*forceLoad*/ true)); + } + } + + if (auto compatibilityVersion = + IRGen.Opts.AutolinkRuntimeCompatibilityDynamicReplacementLibraryVersion) { + if (*compatibilityVersion <= llvm::VersionTuple(5, 0)) { + this->addLinkLibrary(LinkLibrary("swiftCompatibilityDynamicReplacements", + LibraryKind::Library, + /*forceLoad*/ true)); + } + } + } +} + /// Emit all the top-level code in the synthesized file unit. void IRGenModule::emitSynthesizedFileUnit(SynthesizedFileUnit &SFU) { PrettySynthesizedFileUnitEmission StackEntry(SFU); @@ -1036,7 +1107,6 @@ void IRGenerator::emitGlobalTopLevel( // correspond to definitions in the LLVM module. unsigned nextOrderNumber = 0; for (auto &silFn : PrimaryIGM->getSILModule().getFunctions()) { - llvm::dbgs() << "[katei debug] SILFunction " << silFn.getName() << "\n"; // Don't bother adding external declarations to the function order. if (!silFn.isDefinition()) continue; FunctionOrder.insert(std::make_pair(&silFn, nextOrderNumber++)); diff --git a/lib/IRGen/GenProto.cpp b/lib/IRGen/GenProto.cpp index 2795553485a5a..138c01645841c 100644 --- a/lib/IRGen/GenProto.cpp +++ b/lib/IRGen/GenProto.cpp @@ -1900,7 +1900,7 @@ namespace { } // Add the witness. - B.addRelativeAddress(witnesses.front()); + B.addRelativeAddressOrNull(witnesses.front()); witnesses = witnesses.drop_front(); } assert(witnesses.empty() && "Wrong # of resilient witnesses"); diff --git a/lib/IRGen/IRGen.cpp b/lib/IRGen/IRGen.cpp index 3cd5923dcb862..e970ea2dbfebe 100644 --- a/lib/IRGen/IRGen.cpp +++ b/lib/IRGen/IRGen.cpp @@ -34,6 +34,7 @@ #include "swift/IRGen/IRGenSILPasses.h" #include "swift/LLVMPasses/Passes.h" #include "swift/LLVMPasses/PassesFwd.h" +#include "swift/Serialization/SerializedModuleLoader.h" #include "swift/SIL/SILModule.h" #include "swift/SIL/SILRemarkStreamer.h" #include "swift/SILOptimizer/PassManager/PassManager.h" @@ -958,6 +959,8 @@ GeneratedModule IRGenRequest::evaluate(Evaluator &evaluator, for (auto *file : filesToEmit) { if (auto *nextSF = dyn_cast(file)) { IGM.emitSourceFile(*nextSF); + } else if (auto nextSAF = dyn_cast(file)) { + IGM.emitSerializedASTFile(*nextSAF); } else if (auto *nextSFU = dyn_cast(file)) { IGM.emitSynthesizedFileUnit(*nextSFU); } else { @@ -1196,6 +1199,9 @@ static void performParallelIRGeneration(IRGenDescriptor desc) { if (auto *SF = dyn_cast(File)) { CurrentIGMPtr IGM = irgen.getGenModule(SF); IGM->emitSourceFile(*SF); + } if (auto *SAF = dyn_cast(File)) { + CurrentIGMPtr IGM = irgen.getGenModule(SAF); + IGM->emitSerializedASTFile(*SAF); } else if (auto *nextSFU = dyn_cast(File)) { CurrentIGMPtr IGM = irgen.getGenModule(nextSFU); IGM->emitSynthesizedFileUnit(*nextSFU); diff --git a/lib/IRGen/IRGenModule.h b/lib/IRGen/IRGenModule.h index 1b1a0958a7db6..ebb5ae26a93a1 100644 --- a/lib/IRGen/IRGenModule.h +++ b/lib/IRGen/IRGenModule.h @@ -110,6 +110,7 @@ namespace swift { class SILWitnessTable; class SourceLoc; class SourceFile; + class SerializedASTFile; class Type; enum class TypeReferenceKind : unsigned; @@ -1308,6 +1309,7 @@ private: \ llvm::LLVMContext &getLLVMContext() const { return *LLVMContext; } void emitSourceFile(SourceFile &SF); + void emitSerializedASTFile(SerializedASTFile &SF); void emitSynthesizedFileUnit(SynthesizedFileUnit &SFU); void addLinkLibrary(const LinkLibrary &linkLib); From cf1cda3c3ea64ef83630d6dcc5bfe4596052ae16 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Sat, 1 Aug 2020 12:21:32 +0900 Subject: [PATCH 27/77] it works --- lib/Frontend/Frontend.cpp | 6 +-- lib/IRGen/GenDecl.cpp | 1 - lib/SILOptimizer/PassManager/PassPipeline.cpp | 1 + lib/SILOptimizer/Utils/ModuleSummaryIndex.cpp | 47 +++++++++++++------ 4 files changed, 36 insertions(+), 19 deletions(-) diff --git a/lib/Frontend/Frontend.cpp b/lib/Frontend/Frontend.cpp index edb5e3d9cef2c..7d51ffb6f54a2 100644 --- a/lib/Frontend/Frontend.cpp +++ b/lib/Frontend/Frontend.cpp @@ -1045,6 +1045,9 @@ static void countStatsPostSILOpt(UnifiedStatsReporter &Stats, } bool CompilerInstance::performSILProcessing(SILModule *silModule) { + if (runSILCrossModuleEliminatorPass(*silModule)) { + return true; + } if (performMandatorySILPasses(Invocation, silModule)) return true; @@ -1066,9 +1069,6 @@ bool CompilerInstance::performSILProcessing(SILModule *silModule) { } performSILInstCountIfNeeded(silModule); - if (runSILCrossModuleEliminatorPass(*silModule)) { - return true; - } return false; } diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp index c807e78dd3873..8a456c688420e 100644 --- a/lib/IRGen/GenDecl.cpp +++ b/lib/IRGen/GenDecl.cpp @@ -1294,7 +1294,6 @@ void IRGenerator::emitLazyDefinitions() { // Emit any lazy function definitions we require. while (!LazyFunctionDefinitions.empty()) { SILFunction *f = LazyFunctionDefinitions.pop_back_val(); - llvm::dbgs() << "[katei debug] Emit lazy fn " << f->getName() << "\n"; CurrentIGMPtr IGM = getGenModule(f); assert(!f->isPossiblyUsedExternally() && "function with externally-visible linkage emitted lazily?"); diff --git a/lib/SILOptimizer/PassManager/PassPipeline.cpp b/lib/SILOptimizer/PassManager/PassPipeline.cpp index c687d1a25fecc..65c7ca93b8ff3 100644 --- a/lib/SILOptimizer/PassManager/PassPipeline.cpp +++ b/lib/SILOptimizer/PassManager/PassPipeline.cpp @@ -416,6 +416,7 @@ static void addCrossModuleOptimizationsPipeline(SILPassPipelinePlan &P, if (!Options.ModuleSummaryPath.empty()) { P.addCrossDeadFunctionElimination(); } + P.addMandatorySILLinker(); } static void addPrepareOptimizationsPipeline(SILPassPipelinePlan &P) { diff --git a/lib/SILOptimizer/Utils/ModuleSummaryIndex.cpp b/lib/SILOptimizer/Utils/ModuleSummaryIndex.cpp index e5d1413e775e4..dc72cfa86d906 100644 --- a/lib/SILOptimizer/Utils/ModuleSummaryIndex.cpp +++ b/lib/SILOptimizer/Utils/ModuleSummaryIndex.cpp @@ -88,16 +88,30 @@ buildFunctionSummaryIndex(SILFunction &F) { return indexer.takeSummary(); } -void indexWitnessTable(ModuleSummaryIndex &index, SILWitnessTable &WT) { - for (auto entry : WT.getEntries()) { - if (entry.getKind() != SILWitnessTable::Method) break; - - auto methodWitness = entry.getMethodWitness(); - auto Witness = methodWitness.Witness; - if (!Witness) continue; - VirtualMethodSlot slot(methodWitness.Requirement, VirtualMethodSlot::KindTy::Witness); - index.addImplementation(slot, getGUID(Witness->getName())); +void indexWitnessTable(ModuleSummaryIndex &index, SILModule &M) { + std::vector Preserved; + for (auto &WT : M.getWitnessTableList()) { + auto isExternalProto = WT.getDeclContext()->getParentModule() != M.getSwiftModule() || + WT.getProtocol()->getParentModule() != M.getSwiftModule(); + for (auto entry : WT.getEntries()) { + if (entry.getKind() != SILWitnessTable::Method) continue; + + auto methodWitness = entry.getMethodWitness(); + auto Witness = methodWitness.Witness; + if (!Witness) continue; + VirtualMethodSlot slot(methodWitness.Requirement, VirtualMethodSlot::KindTy::Witness); + index.addImplementation(slot, getGUID(Witness->getName())); + if (isExternalProto) { + auto edge = FunctionSummary::EdgeTy::staticCall(Witness); + Preserved.push_back(edge); + } + } } + + auto FS = std::make_unique(Preserved); + FS->setPreserved(true); + llvm::dbgs() << "Summary: Preserved " << Preserved.size() << " external witnesses\n"; + index.addFunctionSummary("__external_witnesses_preserved_fs", std::move(FS)); } @@ -113,6 +127,12 @@ void indexVTable(ModuleSummaryIndex &index, SILModule &M) { llvm::dbgs() << "Preserve deallocator '" << Impl->getName() << "'\n"; Preserved.push_back(edge); } + auto methodMod = entry.getMethod().getDecl()->getModuleContext(); + auto isExternalMethod = methodMod != M.getSwiftModule(); + if (entry.getKind() == SILVTableEntry::Override && isExternalMethod) { + auto edge = FunctionSummary::EdgeTy::staticCall(Impl); + Preserved.push_back(edge); + } VirtualMethodSlot slot(entry.getMethod(), VirtualMethodSlot::KindTy::VTable); index.addImplementation(slot, getGUID(Impl->getName())); } @@ -121,7 +141,7 @@ void indexVTable(ModuleSummaryIndex &index, SILModule &M) { auto FS = std::make_unique(Preserved); FS->setPreserved(true); llvm::dbgs() << "Summary: Preserved " << Preserved.size() << " deallocators\n"; - index.addFunctionSummary("__destructors_preserved_fs", std::move(FS)); + index.addFunctionSummary("__vtable_destructors_and_externals_preserved_fs", std::move(FS)); } void indexKeyPathComponent(ModuleSummaryIndex &index, SILModule &M) { @@ -173,11 +193,8 @@ ModuleSummaryIndex swift::buildModuleSummaryIndex(SILModule &M, FS->setLive(false); index.addFunctionSummary(F.getName(), std::move(FS)); } - - for (auto &WT : M.getWitnessTableList()) { - indexWitnessTable(index, WT); - } - + + indexWitnessTable(index, M); indexVTable(index, M); return index; } From f645fd218b5a4387b3b121257a56c829c4a19d31 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Sat, 1 Aug 2020 14:03:09 +0900 Subject: [PATCH 28/77] Collect dependency libraries recursively when the primary is sib --- lib/Serialization/SerializedModuleLoader.cpp | 28 ++++++++++++++++---- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/lib/Serialization/SerializedModuleLoader.cpp b/lib/Serialization/SerializedModuleLoader.cpp index 77d0a0a2154a0..9db073c3e777d 100644 --- a/lib/Serialization/SerializedModuleLoader.cpp +++ b/lib/Serialization/SerializedModuleLoader.cpp @@ -1114,12 +1114,30 @@ void SerializedASTFile::getImportedModules( void SerializedASTFile::collectLinkLibrariesFromImports( ModuleDecl::LinkLibraryCallback callback) const { - llvm::SmallVector Imports; - File.getImportedModules(Imports, {ModuleDecl::ImportFilterKind::Public, - ModuleDecl::ImportFilterKind::Private}); + llvm::SmallDenseSet visited; + SmallVector stack; - for (auto Import : Imports) - Import.importedModule->collectLinkLibraries(callback); + ModuleDecl::ImportFilter filter = {ModuleDecl::ImportFilterKind::Public, + ModuleDecl::ImportFilterKind::Private}; + File.getImportedModules(stack, filter); + + // Make sure the top-level module is first; we want pre-order-ish traversal. + auto topLevelModule = + ModuleDecl::ImportedModule{ModuleDecl::AccessPathTy(), getParentModule()}; + stack.emplace_back(topLevelModule); + + while (!stack.empty()) { + auto next = stack.pop_back_val().importedModule; + + if (!visited.insert(next).second) + continue; + + if (next->getName() != getParentModule()->getName()) { + next->collectLinkLibraries(callback); + } + + next->getImportedModules(stack, filter); + } } void SerializedASTFile::collectLinkLibraries( From e7930d7ec20f0cc7d30e88380db63cd996084c87 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Sat, 1 Aug 2020 18:33:08 +0900 Subject: [PATCH 29/77] Remove debug prints --- lib/SIL/IR/SILModule.cpp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/lib/SIL/IR/SILModule.cpp b/lib/SIL/IR/SILModule.cpp index ed9f344e63dac..e5c0dd5a3f842 100644 --- a/lib/SIL/IR/SILModule.cpp +++ b/lib/SIL/IR/SILModule.cpp @@ -112,28 +112,22 @@ SILModule::SILModule(llvm::PointerUnion context, SILModule::~SILModule() { // Decrement ref count for each SILGlobalVariable with static initializers. - llvm::dbgs() << "In SILModule::~SILModule()\n"; - llvm::dbgs() << "Before dropping global variable reference\n"; for (SILGlobalVariable &v : silGlobals) v.dropAllReferences(); - llvm::dbgs() << "After dropping reference\n"; - llvm::dbgs() << "Before destructing VTables\n"; for (auto vt : vtables) vt->~SILVTable(); - llvm::dbgs() << "After destructing VTables\n"; + // Drop everything functions in this module reference. // // This is necessary since the functions may reference each other. We don't // need to worry about sil_witness_tables since witness tables reference each // other via protocol conformances and sil_vtables don't reference each other // at all. - llvm::dbgs() << "Before dropping function reference\n"; for (SILFunction &F : *this) { F.dropAllReferences(); F.dropDynamicallyReplacedFunction(); } - llvm::dbgs() << "After dropping function reference\n"; } std::unique_ptr SILModule::createEmptyModule( From 03110f86694ddf5b297ef792c6c7e02ae00284bf Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Sat, 1 Aug 2020 22:25:27 +0900 Subject: [PATCH 30/77] Manage optimization passes --- lib/Frontend/Frontend.cpp | 6 ++++-- lib/Serialization/DeserializeSIL.cpp | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/Frontend/Frontend.cpp b/lib/Frontend/Frontend.cpp index 7d51ffb6f54a2..fe42055ffb4de 100644 --- a/lib/Frontend/Frontend.cpp +++ b/lib/Frontend/Frontend.cpp @@ -1045,9 +1045,11 @@ static void countStatsPostSILOpt(UnifiedStatsReporter &Stats, } bool CompilerInstance::performSILProcessing(SILModule *silModule) { - if (runSILCrossModuleEliminatorPass(*silModule)) { - return true; + + if (!silModule->getOptions().ModuleSummaryPath.empty()) { + return runSILCrossModuleEliminatorPass(*silModule); } + if (performMandatorySILPasses(Invocation, silModule)) return true; diff --git a/lib/Serialization/DeserializeSIL.cpp b/lib/Serialization/DeserializeSIL.cpp index 86565d2ee9314..4017571db434c 100644 --- a/lib/Serialization/DeserializeSIL.cpp +++ b/lib/Serialization/DeserializeSIL.cpp @@ -672,7 +672,7 @@ SILDeserializer::readSILFunctionChecked(DeclID FID, SILFunction *existingFn, // Mark this function as deserialized. This avoids rerunning diagnostic // passes. Certain passes in the madatory pipeline may not work as expected // after arbitrary optimization and lowering. - if (!MF->isSIB()) +// if (!MF->isSIB()) fn->setWasDeserializedCanonical(); fn->setBare(IsBare); From 717f59f8196772aa07ae7040b84f8dbc37cf1829 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Mon, 3 Aug 2020 08:56:03 +0900 Subject: [PATCH 31/77] Fix sib format for ClassSubclassScope --- lib/IRGen/GenClass.cpp | 1 - lib/SILOptimizer/IPO/CrossDeadFunctionElimination.cpp | 2 -- lib/Serialization/DeserializeSIL.cpp | 9 +++++---- lib/Serialization/ModuleFormat.h | 2 +- lib/Serialization/ModuleSummaryFile.cpp | 2 +- lib/Serialization/SILFormat.h | 1 + lib/Serialization/Serialization.cpp | 4 +++- lib/Serialization/SerializeSIL.cpp | 3 ++- 8 files changed, 13 insertions(+), 11 deletions(-) diff --git a/lib/IRGen/GenClass.cpp b/lib/IRGen/GenClass.cpp index d3bdcfb962549..912f0e3ad6131 100644 --- a/lib/IRGen/GenClass.cpp +++ b/lib/IRGen/GenClass.cpp @@ -2246,7 +2246,6 @@ irgen::emitClassPrivateDataFields(IRGenModule &IGM, // This should only be used with generic classes. assert(cls->isGenericContext()); - llvm::dbgs() << "Emitting Class private data field for " << cls->getName() << "\n"; SILType selfType = getSelfType(cls); auto &classTI = IGM.getTypeInfo(selfType).as(); diff --git a/lib/SILOptimizer/IPO/CrossDeadFunctionElimination.cpp b/lib/SILOptimizer/IPO/CrossDeadFunctionElimination.cpp index 4100e3afb1e1d..b90ec53edad9e 100644 --- a/lib/SILOptimizer/IPO/CrossDeadFunctionElimination.cpp +++ b/lib/SILOptimizer/IPO/CrossDeadFunctionElimination.cpp @@ -84,8 +84,6 @@ class SILCrossDeadFuncElimination : public SILModuleTransform { auto F = M.lookUpFunction(info.Name); if (!F) { - llvm::dbgs() << "Couldn't eliminate " << info.Name - << " because it's not found\n"; continue; } F->dropAllReferences(); diff --git a/lib/Serialization/DeserializeSIL.cpp b/lib/Serialization/DeserializeSIL.cpp index 4017571db434c..6d6b44bbd91c5 100644 --- a/lib/Serialization/DeserializeSIL.cpp +++ b/lib/Serialization/DeserializeSIL.cpp @@ -512,14 +512,14 @@ SILDeserializer::readSILFunctionChecked(DeclID FID, SILFunction *existingFn, GenericSignatureID genericSigID; unsigned rawLinkage, isTransparent, isSerialized, isThunk, isWithoutactuallyEscapingThunk, specialPurpose, inlineStrategy, - optimizationMode, effect, numSpecAttrs, hasQualifiedOwnership, + optimizationMode, subclassScope, effect, numSpecAttrs, hasQualifiedOwnership, isWeakImported, LIST_VER_TUPLE_PIECES(available), isDynamic, isExactSelfClass; ArrayRef SemanticsIDs; SILFunctionLayout::readRecord( scratch, rawLinkage, isTransparent, isSerialized, isThunk, isWithoutactuallyEscapingThunk, specialPurpose, inlineStrategy, - optimizationMode, effect, numSpecAttrs, hasQualifiedOwnership, + optimizationMode, subclassScope, effect, numSpecAttrs, hasQualifiedOwnership, isWeakImported, LIST_VER_TUPLE_PIECES(available), isDynamic, isExactSelfClass, funcTyID, replacedFunctionID, genericSigID, @@ -640,6 +640,7 @@ SILDeserializer::readSILFunctionChecked(DeclID FID, SILFunction *existingFn, fn->setEffectsKind(EffectsKind(effect)); fn->setOptimizationMode(OptimizationMode(optimizationMode)); fn->setAlwaysWeakImported(isWeakImported); + fn->setClassSubclassScope(SubclassScope(subclassScope)); llvm::VersionTuple available; DECODE_VER_TUPLE(available); @@ -2825,14 +2826,14 @@ bool SILDeserializer::hasSILFunction(StringRef Name, GenericSignatureID genericSigID; unsigned rawLinkage, isTransparent, isSerialized, isThunk, isWithoutactuallyEscapingThunk, isGlobal, inlineStrategy, - optimizationMode, effect, numSpecAttrs, hasQualifiedOwnership, + optimizationMode, subclassScope, effect, numSpecAttrs, hasQualifiedOwnership, isWeakImported, LIST_VER_TUPLE_PIECES(available), isDynamic, isExactSelfClass; ArrayRef SemanticsIDs; SILFunctionLayout::readRecord( scratch, rawLinkage, isTransparent, isSerialized, isThunk, isWithoutactuallyEscapingThunk, isGlobal, inlineStrategy, - optimizationMode, effect, numSpecAttrs, hasQualifiedOwnership, + optimizationMode, subclassScope, effect, numSpecAttrs, hasQualifiedOwnership, isWeakImported, LIST_VER_TUPLE_PIECES(available), isDynamic, isExactSelfClass, funcTyID, replacedFunctionID, genericSigID, diff --git a/lib/Serialization/ModuleFormat.h b/lib/Serialization/ModuleFormat.h index 351721a916022..48380a55b4054 100644 --- a/lib/Serialization/ModuleFormat.h +++ b/lib/Serialization/ModuleFormat.h @@ -55,7 +55,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0; /// describe what change you made. The content of this comment isn't important; /// it just ensures a conflict if two people change the module format. /// Don't worry about adhering to the 80-column limit for this line. -const uint16_t SWIFTMODULE_VERSION_MINOR = 566; // async +const uint16_t SWIFTMODULE_VERSION_MINOR = 567; // subclass scope /// A standard hash seed used for all string hashes in a serialized module. /// diff --git a/lib/Serialization/ModuleSummaryFile.cpp b/lib/Serialization/ModuleSummaryFile.cpp index 1bce424a9fb1b..3db702f54de4b 100644 --- a/lib/Serialization/ModuleSummaryFile.cpp +++ b/lib/Serialization/ModuleSummaryFile.cpp @@ -125,7 +125,7 @@ void Serializer::emitModuleSummary(const ModuleSummaryIndex &index) { { for (auto &method : index.virtualMethods()) { - llvm::BCBlockRAII restoreBlock(Out, VIRTUAL_METHOD_INFO_ID, 8); + llvm::BCBlockRAII restoreBlock(Out, VIRTUAL_METHOD_INFO_ID, 32); auto &slot = method.first; auto impls = method.second; using namespace virtual_method_info; diff --git a/lib/Serialization/SILFormat.h b/lib/Serialization/SILFormat.h index ec16f5e92b975..9712590728ac2 100644 --- a/lib/Serialization/SILFormat.h +++ b/lib/Serialization/SILFormat.h @@ -281,6 +281,7 @@ namespace sil_block { BCFixed<3>, // specialPurpose BCFixed<2>, // inlineStrategy BCFixed<2>, // optimizationMode + BCFixed<2>, // classSubclassScope BCFixed<3>, // side effect info. BCVBR<8>, // number of specialize attributes BCFixed<1>, // has qualified ownership diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index 3b64d9322e085..d3c0f06cc2b46 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -580,7 +580,9 @@ DeclID Serializer::addDeclRef(const Decl *D, bool allowTypeAliasXRef) { assert((!D || allowTypeAliasXRef || !isa(D) || D->getModuleContext() == M) && "cannot cross-reference typealiases directly (use the TypeAliasType)"); - + if (D && isDeclXRef(D) && isa(D)) { + llvm::dbgs() << "[katei debug] addDeclRef destructor\n"; + } return DeclsToSerialize.addRef(D); } diff --git a/lib/Serialization/SerializeSIL.cpp b/lib/Serialization/SerializeSIL.cpp index 285db801310ff..53b5d04d71523 100644 --- a/lib/Serialization/SerializeSIL.cpp +++ b/lib/Serialization/SerializeSIL.cpp @@ -435,7 +435,8 @@ void SILSerializer::writeSILFunction(const SILFunction &F, bool DeclOnly) { (unsigned)F.isTransparent(), (unsigned)F.isSerialized(), (unsigned)F.isThunk(), (unsigned)F.isWithoutActuallyEscapingThunk(), (unsigned)F.getSpecialPurpose(), (unsigned)F.getInlineStrategy(), - (unsigned)F.getOptimizationMode(), (unsigned)F.getEffectsKind(), + (unsigned)F.getOptimizationMode(), (unsigned)F.getClassSubclassScope(), + (unsigned)F.getEffectsKind(), (unsigned)numSpecAttrs, (unsigned)F.hasOwnership(), F.isAlwaysWeakImported(), LIST_VER_TUPLE_PIECES(available), (unsigned)F.isDynamicallyReplaceable(), From 1ae41b8ec0145e22565d5e8d217a01a14d6eb767 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Mon, 3 Aug 2020 13:37:15 +0900 Subject: [PATCH 32/77] Fix deserializing implicit decl deinit --- lib/Serialization/Deserialization.cpp | 5 ++++- lib/Serialization/Serialization.cpp | 3 --- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp index 8197ba44e96e4..6139880cb139f 100644 --- a/lib/Serialization/Deserialization.cpp +++ b/lib/Serialization/Deserialization.cpp @@ -1611,7 +1611,10 @@ ModuleFile::resolveCrossReference(ModuleID MID, uint32_t pathLen) { getXRefDeclNameForError()); } - if (!privateDiscriminator.empty()) { + if (memberName.getKind() == DeclBaseName::Kind::Destructor) { + auto CD = dyn_cast(nominal); + values.push_back(CD->getDestructor()); + } else if (!privateDiscriminator.empty()) { ModuleDecl *searchModule = M; if (!searchModule) searchModule = nominal->getModuleContext(); diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index d3c0f06cc2b46..f6cbb6ac617a6 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -580,9 +580,6 @@ DeclID Serializer::addDeclRef(const Decl *D, bool allowTypeAliasXRef) { assert((!D || allowTypeAliasXRef || !isa(D) || D->getModuleContext() == M) && "cannot cross-reference typealiases directly (use the TypeAliasType)"); - if (D && isDeclXRef(D) && isa(D)) { - llvm::dbgs() << "[katei debug] addDeclRef destructor\n"; - } return DeclsToSerialize.addRef(D); } From 7abda1d8ec6f1ddb3666e57adfb3e3546db0cd02 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Mon, 3 Aug 2020 23:04:03 +0900 Subject: [PATCH 33/77] Add debug options for tracing liveness --- tools/driver/cross_module_opt_main.cpp | 151 +++++++++++++------------ tools/driver/driver.cpp | 2 +- 2 files changed, 80 insertions(+), 73 deletions(-) diff --git a/tools/driver/cross_module_opt_main.cpp b/tools/driver/cross_module_opt_main.cpp index 201cdeb9b01c6..aa38eeff7c576 100644 --- a/tools/driver/cross_module_opt_main.cpp +++ b/tools/driver/cross_module_opt_main.cpp @@ -1,3 +1,5 @@ +#define DEBUG_TYPE "lto-cross-module-opt" + #include "swift/AST/DiagnosticsFrontend.h" #include "swift/Basic/LLVMInitialize.h" #include "swift/Frontend/Frontend.h" @@ -13,6 +15,8 @@ #include "llvm/Bitstream/BitstreamReader.h" #include "llvm/Option/ArgList.h" #include "llvm/Option/Option.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" @@ -21,60 +25,15 @@ using namespace llvm::opt; using namespace swift; -class MergeModuleSummaryInvocation { -private: - std::string MainExecutablePath; - std::string OutputFilename = "-"; - std::vector InputFilenames; - -public: - void setMainExecutablePath(const std::string &Path) { - MainExecutablePath = Path; - } - - const std::string &getOutputFilename() { return OutputFilename; } - - const std::vector &getInputFilenames() { return InputFilenames; } - - int parseArgs(llvm::ArrayRef Args, DiagnosticEngine &Diags) { - using namespace options; - - // Parse frontend command line options using Swift's option table. - std::unique_ptr Table = createSwiftOptTable(); - unsigned MissingIndex; - unsigned MissingCount; - llvm::opt::InputArgList ParsedArgs = - Table->ParseArgs(Args, MissingIndex, MissingCount, ModuleWrapOption); - if (MissingCount) { - Diags.diagnose(SourceLoc(), diag::error_missing_arg_value, - ParsedArgs.getArgString(MissingIndex), MissingCount); - return 1; - } - - if (ParsedArgs.hasArg(OPT_UNKNOWN)) { - for (const Arg *A : ParsedArgs.filtered(OPT_UNKNOWN)) { - Diags.diagnose(SourceLoc(), diag::error_unknown_arg, - A->getAsString(ParsedArgs)); - } - return true; - } - - for (const Arg *A : ParsedArgs.filtered(OPT_INPUT)) { - InputFilenames.push_back(A->getValue()); - } - - if (InputFilenames.empty()) { - Diags.diagnose(SourceLoc(), diag::error_mode_requires_an_input_file); - return 1; - } - - if (const Arg *A = ParsedArgs.getLastArg(OPT_o)) { - OutputFilename = A->getValue(); - } +static llvm::cl::opt + LTOPrintLiveTrace("lto-print-live-trace", llvm::cl::init(""), + llvm::cl::desc("Print liveness trace for the symbol")); - return 0; - } -}; +static llvm::cl::list + InputFilenames(llvm::cl::Positional, llvm::cl::desc("[input files...]"), + llvm::cl::OneOrMore); +static llvm::cl::opt + OutputFilename("o", llvm::cl::desc("output filename")); static llvm::DenseSet computePreservedGUIDs(ModuleSummaryIndex *summary) { llvm::DenseSet Set(1); @@ -88,34 +47,79 @@ static llvm::DenseSet computePreservedGUIDs(ModuleSummaryIndex *summary) { return Set; } +class LivenessTrace { +public: + enum ReasonTy { Preserved, StaticReferenced, IndirectReferenced }; + std::shared_ptr markedBy; + std::string symbol; + GUID guid; + ReasonTy reason; + + LivenessTrace(std::shared_ptr markedBy, GUID guid, + ReasonTy reason) + : markedBy(markedBy), guid(guid), reason(reason) {} + + void setName(std::string name) { this->symbol = name; } + + void dump() { dump(llvm::errs()); } + void dump(llvm::raw_ostream &os) { + if (!symbol.empty()) { + os << symbol; + } else { + os << "**missing name**" + << " (" << guid << ")"; + } + os << "is referenced by:\n"; + + auto target = markedBy; + while (target) { + os << " - "; + if (!target->symbol.empty()) { + os << target->symbol; + } else { + os << "**missing name**"; + } + os << " (" << target->guid << ")"; + os << "\n"; + target = target->markedBy; + } + } +}; + void markDeadSymbols(ModuleSummaryIndex &summary, llvm::DenseSet &PreservedGUIDs) { - - SmallVector Worklist; + + SmallVector, 8> Worklist; unsigned LiveSymbols = 0; for (auto GUID : PreservedGUIDs) { - Worklist.push_back(GUID); + Worklist.push_back(std::make_shared( + nullptr, GUID, LivenessTrace::Preserved)); } - + std::shared_ptr dumpTarget; while (!Worklist.empty()) { - auto GUID = Worklist.pop_back_val(); - - auto maybePair = summary.getFunctionInfo(GUID); + auto trace = Worklist.pop_back_val(); + + auto maybePair = summary.getFunctionInfo(trace->guid); if (!maybePair) { llvm_unreachable("Bad GUID"); } auto pair = maybePair.getValue(); auto FS = pair.first; + trace->setName(pair.second); + if (LTOPrintLiveTrace == pair.second) { + dumpTarget = trace; + } if (FS->isLive()) continue; - llvm::dbgs() << "Mark " << pair.second << " as live\n"; + LLVM_DEBUG(llvm::dbgs() << "Mark " << pair.second << " as live\n"); FS->setLive(true); LiveSymbols++; for (auto Call : FS->calls()) { switch (Call.getKind()) { case FunctionSummary::EdgeTy::Kind::Static: { - Worklist.push_back(Call.getCallee()); + Worklist.push_back(std::make_shared( + trace, Call.getCallee(), LivenessTrace::StaticReferenced)); continue; } case FunctionSummary::EdgeTy::Kind::Witness: @@ -125,7 +129,8 @@ void markDeadSymbols(ModuleSummaryIndex &summary, llvm::DenseSet &Preserve continue; } for (auto Impl : Impls.getValue()) { - Worklist.push_back(Impl); + Worklist.push_back(std::make_shared( + trace, Impl, LivenessTrace::IndirectReferenced)); } break; } @@ -134,29 +139,31 @@ void markDeadSymbols(ModuleSummaryIndex &summary, llvm::DenseSet &Preserve } } } + if (dumpTarget) { + dumpTarget->dump(); + } } int cross_module_opt_main(ArrayRef Args, const char *Argv0, void *MainAddr) { INITIALIZE_LLVM(); + llvm::cl::ParseCommandLineOptions(Args.size(), Args.data(), "Swift LTO\n"); + CompilerInstance Instance; PrintingDiagnosticConsumer PDC; Instance.addDiagnosticConsumer(&PDC); - MergeModuleSummaryInvocation Invocation; - std::string MainExecutablePath = - llvm::sys::fs::getMainExecutable(Argv0, MainAddr); - Invocation.setMainExecutablePath(MainExecutablePath); - - // Parse arguments. - if (Invocation.parseArgs(Args, Instance.getDiags()) != 0) { + if (InputFilenames.empty()) { + Instance.getDiags().diagnose(SourceLoc(), + diag::error_mode_requires_an_input_file); return 1; } auto TheSummary = std::make_unique(); - for (auto Filename : Invocation.getInputFilenames()) { + for (auto Filename : InputFilenames) { + LLVM_DEBUG(llvm::dbgs() << "Loading module summary " << Filename << "\n"); auto ErrOrBuf = llvm::MemoryBuffer::getFile(Filename); if (!ErrOrBuf) { Instance.getDiags().diagnose( @@ -177,6 +184,6 @@ int cross_module_opt_main(ArrayRef Args, const char *Argv0, markDeadSymbols(*TheSummary.get(), PreservedGUIDs); modulesummary::emitModuleSummaryIndex(*TheSummary, Instance.getDiags(), - Invocation.getOutputFilename()); + OutputFilename); return 0; } diff --git a/tools/driver/driver.cpp b/tools/driver/driver.cpp index 594ad1da3cf1a..f54dc9fda1041 100644 --- a/tools/driver/driver.cpp +++ b/tools/driver/driver.cpp @@ -146,7 +146,7 @@ static int run_driver(StringRef ExecName, if (FirstArg == "-cross-module-opt") { return cross_module_opt_main( - llvm::makeArrayRef(argv.data() + 2, argv.data() + argv.size()), + llvm::makeArrayRef(argv.data() + 1, argv.data() + argv.size()), argv[0], (void *)(intptr_t)getExecutablePath); } } From 6a48ed1f2e839fa444a7dedadd9c4e43cc9b9159 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Tue, 4 Aug 2020 00:26:23 +0900 Subject: [PATCH 34/77] Remove debug print --- .../IPO/CrossDeadFunctionElimination.cpp | 2 +- lib/SILOptimizer/Utils/ModuleSummaryIndex.cpp | 12 ++++++------ lib/Serialization/ModuleSummaryFile.cpp | 2 -- tools/driver/cross_module_opt_main.cpp | 3 +-- 4 files changed, 8 insertions(+), 11 deletions(-) diff --git a/lib/SILOptimizer/IPO/CrossDeadFunctionElimination.cpp b/lib/SILOptimizer/IPO/CrossDeadFunctionElimination.cpp index b90ec53edad9e..efae798337042 100644 --- a/lib/SILOptimizer/IPO/CrossDeadFunctionElimination.cpp +++ b/lib/SILOptimizer/IPO/CrossDeadFunctionElimination.cpp @@ -88,7 +88,7 @@ class SILCrossDeadFuncElimination : public SILModuleTransform { } F->dropAllReferences(); DeadFunctions.push_back(F); - llvm::dbgs() << "Eliminate " << info.Name << "\n"; + LLVM_DEBUG(llvm::dbgs() << "Eliminate " << info.Name << "\n"); } } diff --git a/lib/SILOptimizer/Utils/ModuleSummaryIndex.cpp b/lib/SILOptimizer/Utils/ModuleSummaryIndex.cpp index dc72cfa86d906..158b22392c9d5 100644 --- a/lib/SILOptimizer/Utils/ModuleSummaryIndex.cpp +++ b/lib/SILOptimizer/Utils/ModuleSummaryIndex.cpp @@ -8,7 +8,7 @@ #include "llvm/Support/MD5.h" #include "llvm/Support/raw_ostream.h" -#define DEBUG_TYPE "function-order-printer" +#define DEBUG_TYPE "module-summary-index" using namespace swift; @@ -110,7 +110,7 @@ void indexWitnessTable(ModuleSummaryIndex &index, SILModule &M) { auto FS = std::make_unique(Preserved); FS->setPreserved(true); - llvm::dbgs() << "Summary: Preserved " << Preserved.size() << " external witnesses\n"; + LLVM_DEBUG(llvm::dbgs() << "Summary: Preserved " << Preserved.size() << " external witnesses\n"); index.addFunctionSummary("__external_witnesses_preserved_fs", std::move(FS)); } @@ -124,7 +124,7 @@ void indexVTable(ModuleSummaryIndex &index, SILModule &M) { entry.getMethod().kind == SILDeclRef::Kind::IVarDestroyer) { // Destructors are alive because they are called from swift_release auto edge = FunctionSummary::EdgeTy::staticCall(Impl); - llvm::dbgs() << "Preserve deallocator '" << Impl->getName() << "'\n"; + LLVM_DEBUG(llvm::dbgs() << "Preserve deallocator '" << Impl->getName() << "'\n"); Preserved.push_back(edge); } auto methodMod = entry.getMethod().getDecl()->getModuleContext(); @@ -140,7 +140,7 @@ void indexVTable(ModuleSummaryIndex &index, SILModule &M) { auto FS = std::make_unique(Preserved); FS->setPreserved(true); - llvm::dbgs() << "Summary: Preserved " << Preserved.size() << " deallocators\n"; + LLVM_DEBUG(llvm::dbgs() << "Summary: Preserved " << Preserved.size() << " deallocators\n"); index.addFunctionSummary("__vtable_destructors_and_externals_preserved_fs", std::move(FS)); } @@ -151,7 +151,7 @@ void indexKeyPathComponent(ModuleSummaryIndex &index, SILModule &M) { component->visitReferencedFunctionsAndMethods( [&](SILFunction *F) { auto FS = buildFunctionSummaryIndex(*F); - llvm::dbgs() << "Preserve keypath funcs " << F->getName() << "\n"; + LLVM_DEBUG(llvm::dbgs() << "Preserve keypath funcs " << F->getName() << "\n"); FS->setPreserved(true); index.addFunctionSummary(F->getName(), std::move(FS)); }, @@ -187,7 +187,7 @@ ModuleSummaryIndex swift::buildModuleSummaryIndex(SILModule &M, for (auto &F : M) { auto FS = buildFunctionSummaryIndex(F); if (F.getRepresentation() == SILFunctionTypeRepresentation::ObjCMethod) { - llvm::dbgs() << "Preserve " << F.getName() << " due to ObjCMethod\n"; + LLVM_DEBUG(llvm::dbgs() << "Preserve " << F.getName() << " due to ObjCMethod\n"); FS->setPreserved(true); } FS->setLive(false); diff --git a/lib/Serialization/ModuleSummaryFile.cpp b/lib/Serialization/ModuleSummaryFile.cpp index 3db702f54de4b..bbaa9b55b3a96 100644 --- a/lib/Serialization/ModuleSummaryFile.cpp +++ b/lib/Serialization/ModuleSummaryFile.cpp @@ -218,8 +218,6 @@ bool Deserializer::readModuleSummaryMetadata() { moduleSummary.setModuleName(BlobData.str()); - llvm::dbgs() << "Start loading module " << moduleSummary.getModuleName() - << "\n"; return false; } diff --git a/tools/driver/cross_module_opt_main.cpp b/tools/driver/cross_module_opt_main.cpp index aa38eeff7c576..9a6b837f1a4dc 100644 --- a/tools/driver/cross_module_opt_main.cpp +++ b/tools/driver/cross_module_opt_main.cpp @@ -30,8 +30,7 @@ static llvm::cl::opt llvm::cl::desc("Print liveness trace for the symbol")); static llvm::cl::list - InputFilenames(llvm::cl::Positional, llvm::cl::desc("[input files...]"), - llvm::cl::OneOrMore); + InputFilenames(llvm::cl::Positional, llvm::cl::desc("[input files...]")); static llvm::cl::opt OutputFilename("o", llvm::cl::desc("output filename")); From 06313919ff7274b88bc7169fe5a1a8280a46e62d Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Wed, 5 Aug 2020 20:08:41 +0900 Subject: [PATCH 35/77] [Serialization] Serialize hasCReferences info hasCReferences is true when the decl has @_cdecl or @_silgen_name and it affects to linkage at LLVM IR level --- lib/Serialization/DeserializeSIL.cpp | 9 +++++---- lib/Serialization/ModuleFormat.h | 2 +- lib/Serialization/SILFormat.h | 1 + lib/Serialization/SerializeSIL.cpp | 2 +- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/Serialization/DeserializeSIL.cpp b/lib/Serialization/DeserializeSIL.cpp index 6d6b44bbd91c5..d2202409efa6f 100644 --- a/lib/Serialization/DeserializeSIL.cpp +++ b/lib/Serialization/DeserializeSIL.cpp @@ -512,14 +512,14 @@ SILDeserializer::readSILFunctionChecked(DeclID FID, SILFunction *existingFn, GenericSignatureID genericSigID; unsigned rawLinkage, isTransparent, isSerialized, isThunk, isWithoutactuallyEscapingThunk, specialPurpose, inlineStrategy, - optimizationMode, subclassScope, effect, numSpecAttrs, hasQualifiedOwnership, + optimizationMode, subclassScope, hasCReferences, effect, numSpecAttrs, hasQualifiedOwnership, isWeakImported, LIST_VER_TUPLE_PIECES(available), isDynamic, isExactSelfClass; ArrayRef SemanticsIDs; SILFunctionLayout::readRecord( scratch, rawLinkage, isTransparent, isSerialized, isThunk, isWithoutactuallyEscapingThunk, specialPurpose, inlineStrategy, - optimizationMode, subclassScope, effect, numSpecAttrs, hasQualifiedOwnership, + optimizationMode, subclassScope, hasCReferences, effect, numSpecAttrs, hasQualifiedOwnership, isWeakImported, LIST_VER_TUPLE_PIECES(available), isDynamic, isExactSelfClass, funcTyID, replacedFunctionID, genericSigID, @@ -641,6 +641,7 @@ SILDeserializer::readSILFunctionChecked(DeclID FID, SILFunction *existingFn, fn->setOptimizationMode(OptimizationMode(optimizationMode)); fn->setAlwaysWeakImported(isWeakImported); fn->setClassSubclassScope(SubclassScope(subclassScope)); + fn->setHasCReferences(bool(hasCReferences)); llvm::VersionTuple available; DECODE_VER_TUPLE(available); @@ -2826,14 +2827,14 @@ bool SILDeserializer::hasSILFunction(StringRef Name, GenericSignatureID genericSigID; unsigned rawLinkage, isTransparent, isSerialized, isThunk, isWithoutactuallyEscapingThunk, isGlobal, inlineStrategy, - optimizationMode, subclassScope, effect, numSpecAttrs, hasQualifiedOwnership, + optimizationMode, subclassScope, hasCReferences, effect, numSpecAttrs, hasQualifiedOwnership, isWeakImported, LIST_VER_TUPLE_PIECES(available), isDynamic, isExactSelfClass; ArrayRef SemanticsIDs; SILFunctionLayout::readRecord( scratch, rawLinkage, isTransparent, isSerialized, isThunk, isWithoutactuallyEscapingThunk, isGlobal, inlineStrategy, - optimizationMode, subclassScope, effect, numSpecAttrs, hasQualifiedOwnership, + optimizationMode, subclassScope, hasCReferences, effect, numSpecAttrs, hasQualifiedOwnership, isWeakImported, LIST_VER_TUPLE_PIECES(available), isDynamic, isExactSelfClass, funcTyID, replacedFunctionID, genericSigID, diff --git a/lib/Serialization/ModuleFormat.h b/lib/Serialization/ModuleFormat.h index 48380a55b4054..3b6477a7ebbd6 100644 --- a/lib/Serialization/ModuleFormat.h +++ b/lib/Serialization/ModuleFormat.h @@ -55,7 +55,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0; /// describe what change you made. The content of this comment isn't important; /// it just ensures a conflict if two people change the module format. /// Don't worry about adhering to the 80-column limit for this line. -const uint16_t SWIFTMODULE_VERSION_MINOR = 567; // subclass scope +const uint16_t SWIFTMODULE_VERSION_MINOR = 568; // hasCReferences /// A standard hash seed used for all string hashes in a serialized module. /// diff --git a/lib/Serialization/SILFormat.h b/lib/Serialization/SILFormat.h index 9712590728ac2..352ee1db39719 100644 --- a/lib/Serialization/SILFormat.h +++ b/lib/Serialization/SILFormat.h @@ -282,6 +282,7 @@ namespace sil_block { BCFixed<2>, // inlineStrategy BCFixed<2>, // optimizationMode BCFixed<2>, // classSubclassScope + BCFixed<1>, // hasCReferences BCFixed<3>, // side effect info. BCVBR<8>, // number of specialize attributes BCFixed<1>, // has qualified ownership diff --git a/lib/Serialization/SerializeSIL.cpp b/lib/Serialization/SerializeSIL.cpp index 53b5d04d71523..35cea9d531011 100644 --- a/lib/Serialization/SerializeSIL.cpp +++ b/lib/Serialization/SerializeSIL.cpp @@ -436,7 +436,7 @@ void SILSerializer::writeSILFunction(const SILFunction &F, bool DeclOnly) { (unsigned)F.isThunk(), (unsigned)F.isWithoutActuallyEscapingThunk(), (unsigned)F.getSpecialPurpose(), (unsigned)F.getInlineStrategy(), (unsigned)F.getOptimizationMode(), (unsigned)F.getClassSubclassScope(), - (unsigned)F.getEffectsKind(), + (unsigned)F.hasCReferences(), (unsigned)F.getEffectsKind(), (unsigned)numSpecAttrs, (unsigned)F.hasOwnership(), F.isAlwaysWeakImported(), LIST_VER_TUPLE_PIECES(available), (unsigned)F.isDynamicallyReplaceable(), From 07f95d48d271e3ba74aa7cf43a9f1dec31f75d09 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Wed, 5 Aug 2020 20:12:52 +0900 Subject: [PATCH 36/77] Preserve funcs which have @_cdecl or @_silgen_name because they can be used externally --- lib/SILOptimizer/Utils/ModuleSummaryIndex.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/SILOptimizer/Utils/ModuleSummaryIndex.cpp b/lib/SILOptimizer/Utils/ModuleSummaryIndex.cpp index 158b22392c9d5..4509d055bef63 100644 --- a/lib/SILOptimizer/Utils/ModuleSummaryIndex.cpp +++ b/lib/SILOptimizer/Utils/ModuleSummaryIndex.cpp @@ -190,6 +190,11 @@ ModuleSummaryIndex swift::buildModuleSummaryIndex(SILModule &M, LLVM_DEBUG(llvm::dbgs() << "Preserve " << F.getName() << " due to ObjCMethod\n"); FS->setPreserved(true); } + if (F.hasCReferences()) { + LLVM_DEBUG(llvm::dbgs() << "Preserve " << F.getName() << " due to @_silgen_name or @_cdecl\n"); + FS->setPreserved(true); + } + FS->setLive(false); index.addFunctionSummary(F.getName(), std::move(FS)); } From 23071db369f1ad68467d65aa8cc682c835d43820 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Thu, 6 Aug 2020 00:47:43 +0900 Subject: [PATCH 37/77] [Serialization] Serialize Differentiability WT index sorted --- lib/Serialization/Serialization.cpp | 2 ++ lib/Serialization/SerializeSIL.cpp | 10 +++++----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index f6cbb6ac617a6..14cd3f095cf69 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -855,6 +855,8 @@ void Serializer::writeBlockInfoBlock() { BLOCK_RECORD(sil_index_block, SIL_DEFAULT_WITNESS_TABLE_NAMES); BLOCK_RECORD(sil_index_block, SIL_DEFAULT_WITNESS_TABLE_OFFSETS); BLOCK_RECORD(sil_index_block, SIL_PROPERTY_OFFSETS); + BLOCK_RECORD(sil_index_block, SIL_DIFFERENTIABILITY_WITNESS_NAMES); + BLOCK_RECORD(sil_index_block, SIL_DIFFERENTIABILITY_WITNESS_OFFSETS); #undef BLOCK #undef BLOCK_RECORD diff --git a/lib/Serialization/SerializeSIL.cpp b/lib/Serialization/SerializeSIL.cpp index 35cea9d531011..3136720f13529 100644 --- a/lib/Serialization/SerializeSIL.cpp +++ b/lib/Serialization/SerializeSIL.cpp @@ -2347,6 +2347,11 @@ void SILSerializer::writeIndexTables() { DefaultWitnessTableOffset); } + if (!PropertyOffset.empty()) { + Offset.emit(ScratchRecord, sil_index_block::SIL_PROPERTY_OFFSETS, + PropertyOffset); + } + if (!DifferentiabilityWitnessList.empty()) { writeIndexTable(S, List, sil_index_block::SIL_DIFFERENTIABILITY_WITNESS_NAMES, @@ -2356,11 +2361,6 @@ void SILSerializer::writeIndexTables() { DifferentiabilityWitnessOffset); } - if (!PropertyOffset.empty()) { - Offset.emit(ScratchRecord, sil_index_block::SIL_PROPERTY_OFFSETS, - PropertyOffset); - } - } void SILSerializer::writeSILGlobalVar(const SILGlobalVariable &g) { From 80fd8d102eabe7f90dc6aa5484578f466728c8d1 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Sat, 8 Aug 2020 00:10:38 +0900 Subject: [PATCH 38/77] Refactoring --- include/swift/SIL/ModuleSummary.h | 22 +++++++++------------- lib/Serialization/ModuleSummaryFile.cpp | 10 +++++----- 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/include/swift/SIL/ModuleSummary.h b/include/swift/SIL/ModuleSummary.h index 3f342be92227b..74b743de0c5c0 100644 --- a/include/swift/SIL/ModuleSummary.h +++ b/include/swift/SIL/ModuleSummary.h @@ -133,6 +133,7 @@ class FunctionSummary { private: FlagsTy Flags; CallGraphEdgeListTy CallGraphEdgeList; + std::string Name; public: FunctionSummary(std::vector CGEdges) @@ -150,15 +151,12 @@ class FunctionSummary { bool isPreserved() const { return Flags.Preserved; } void setPreserved(bool Preserved) { Flags.Preserved = Preserved; } -}; - -struct FunctionSummaryInfo { - std::string Name; - std::unique_ptr TheSummary; + std::string getName() const { return Name; } + void setName(std::string name) { this->Name = name; } }; class ModuleSummaryIndex { - using FunctionSummaryInfoMapTy = std::map; + using FunctionSummaryInfoMapTy = std::map>; using VirtualMethodInfoMapTy = std::map>; FunctionSummaryInfoMapTy FunctionSummaryInfoMap; @@ -174,21 +172,19 @@ class ModuleSummaryIndex { this->ModuleName = name; } - void addFunctionSummary(std::string name, - std::unique_ptr summary) { - auto guid = getGUID(name); + void addFunctionSummary(std::unique_ptr summary) { + auto guid = getGUID(summary->getName()); FunctionSummaryInfoMap.insert( - std::make_pair(guid, FunctionSummaryInfo{name, std::move(summary)})); + std::make_pair(guid, std::move(summary))); } - const llvm::Optional> + const llvm::Optional getFunctionInfo(GUID guid) const { auto found = FunctionSummaryInfoMap.find(guid); if (found == FunctionSummaryInfoMap.end()) { return None; } - auto &entry = found->second; - return std::make_pair(entry.TheSummary.get(), StringRef(entry.Name)); + return found->second.get(); } void addImplementation(VirtualMethodSlot slot, GUID funcGUID) { diff --git a/lib/Serialization/ModuleSummaryFile.cpp b/lib/Serialization/ModuleSummaryFile.cpp index bbaa9b55b3a96..10f5a41875a67 100644 --- a/lib/Serialization/ModuleSummaryFile.cpp +++ b/lib/Serialization/ModuleSummaryFile.cpp @@ -108,12 +108,11 @@ void Serializer::emitModuleSummary(const ModuleSummaryIndex &index) { { for (const auto &pair : index) { llvm::BCBlockRAII restoreBlock(Out, FUNCTION_SUMMARY_ID, 32); - auto &info = pair.second; - auto &summary = info.TheSummary; + auto &summary = pair.second; using namespace function_summary; function_summary::MetadataLayout MDlayout(Out); - MDlayout.emit(ScratchRecord, pair.first, summary->isLive(), summary->isPreserved(), info.Name); + MDlayout.emit(ScratchRecord, pair.first, summary->isLive(), summary->isPreserved(), summary->getName()); for (auto call : summary->calls()) { CallGraphEdgeLayout edgeLayout(Out); @@ -251,13 +250,14 @@ bool Deserializer::readFunctionSummary() { function_summary::MetadataLayout::readRecord(Scratch, guid, isLive, isPreserved); Name = BlobData.str(); if (auto info = moduleSummary.getFunctionInfo(guid)) { - FS = info.getValue().first; + FS = info.getValue(); } else { NewFSOwner = std::make_unique(); FS = NewFSOwner.get(); } FS->setLive(isLive); FS->setPreserved(isPreserved); + FS->setName(Name); break; } case function_summary::CALL_GRAPH_EDGE: { @@ -284,7 +284,7 @@ bool Deserializer::readFunctionSummary() { } if (auto &FS = NewFSOwner) { - moduleSummary.addFunctionSummary(Name, std::move(FS)); + moduleSummary.addFunctionSummary(std::move(FS)); } return false; } From d54db343ffa0a9b92ddef6accc8eae8103161981 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Tue, 11 Aug 2020 23:56:01 +0900 Subject: [PATCH 39/77] [Prototype] Port refactored versions --- include/swift/SIL/ModuleSummary.h | 333 +++++++------- include/swift/Serialization/ModuleSummary.h | 250 ++++++++++ .../swift/Serialization/ModuleSummaryFile.h | 87 ---- lib/FrontendTool/FrontendTool.cpp | 9 +- .../IPO/CrossDeadFunctionElimination.cpp | 97 +--- lib/SILOptimizer/Utils/CMakeLists.txt | 1 - lib/SILOptimizer/Utils/ModuleSummaryIndex.cpp | 205 --------- lib/Serialization/CMakeLists.txt | 3 +- lib/Serialization/ModuleSummaryFile.cpp | 433 ------------------ lib/Serialization/ModuleSummaryFormat.cpp | 426 +++++++++++++++++ lib/Serialization/ModuleSummaryFormat.h | 71 +++ lib/Serialization/ModuleSummaryIndexer.cpp | 270 +++++++++++ tools/driver/cross_module_opt_main.cpp | 78 ++-- 13 files changed, 1276 insertions(+), 987 deletions(-) create mode 100644 include/swift/Serialization/ModuleSummary.h delete mode 100644 include/swift/Serialization/ModuleSummaryFile.h delete mode 100644 lib/SILOptimizer/Utils/ModuleSummaryIndex.cpp delete mode 100644 lib/Serialization/ModuleSummaryFile.cpp create mode 100644 lib/Serialization/ModuleSummaryFormat.cpp create mode 100644 lib/Serialization/ModuleSummaryFormat.h create mode 100644 lib/Serialization/ModuleSummaryIndexer.cpp diff --git a/include/swift/SIL/ModuleSummary.h b/include/swift/SIL/ModuleSummary.h index 74b743de0c5c0..36350c84c3581 100644 --- a/include/swift/SIL/ModuleSummary.h +++ b/include/swift/SIL/ModuleSummary.h @@ -1,225 +1,250 @@ +//===----- ModuleSummary.h --------------------------------------*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + #ifndef SWIFT_SIL_MODULE_SUMMARY_H #define SWIFT_SIL_MODULE_SUMMARY_H #include "swift/AST/Decl.h" -#include "swift/SIL/SILDeclRef.h" -#include "swift/AST/ASTMangler.h" - -// FIXME: Move this into another module to avoid circular dependencies. -#include "swift/SILOptimizer/Analysis/BasicCalleeAnalysis.h" +#include "swift/SIL/SILFunction.h" +#include "llvm/Support/YAMLTraits.h" namespace swift { -using GUID = uint64_t; -static GUID getGUID(llvm::StringRef Str) { return llvm::MD5Hash(Str); } +namespace modulesummary { -struct VirtualMethodSlot { - enum class KindTy { - Witness, VTable, - kindCount, - }; - - KindTy Kind; - GUID VirtualFuncID; - VirtualMethodSlot(KindTy kind, GUID virtualFuncID) - : Kind(kind), VirtualFuncID(virtualFuncID) { } - VirtualMethodSlot(SILDeclRef VirtualFuncRef, KindTy kind) : Kind(kind) { - VirtualFuncID = getGUID(VirtualFuncRef.mangle()); - } +using GUID = uint64_t; - bool operator<(const VirtualMethodSlot &rhs) const { - if (Kind > rhs.Kind) - return false; - if (Kind < rhs.Kind) - return true; - return VirtualFuncID < rhs.VirtualFuncID; - } -}; +/// Compute globally unique identifier from the symbol. +GUID getGUIDFromUniqueName(llvm::StringRef Name); +/// Function summary information to help callee analysis class FunctionSummary { public: - class EdgeTy { - GUID CalleeFn; - std::string Name; + /// Function call information + class Call { public: - - enum class Kind { - Static, + /// Kinds of callee reference. + enum KindTy { + /// The call references a function statically + Direct, + /// The call references a function via a witness table. Witness, + /// The call references a function via a vtable. VTable, kindCount, }; - Kind kind; - - EdgeTy(SILDeclRef &CalleeFn, Kind kind) : kind(kind) { - this->Name = CalleeFn.mangle(); - this->CalleeFn = getGUID(CalleeFn.mangle()); - } + private: + // For import/export + friend llvm::yaml::MappingTraits; + /// The callee function GUID. This can be a static function or a virtual + /// function GUID. + GUID Callee; + /// The symbol name of the callee function only for debug and test purposes. + std::string Name; + /// Kind of the callee reference. + KindTy Kind; public: - Kind getKind() const { return kind; } - GUID getCallee() const { return CalleeFn; } - std::string getName() const { return Name; }; - - void dump() const { - llvm::dbgs() << "FunctionSummary(kind: "; - switch (kind) { - case Kind::Witness: { - llvm::dbgs() << "Witness"; - break; - } - case Kind::VTable: { - llvm::dbgs() << "VTable"; - break; - } - case Kind::Static: { - llvm::dbgs() << "Static"; - break; - } - case Kind::kindCount: { - llvm_unreachable("impossible"); - } - } - llvm::dbgs() << ", name: " << getName() << " , callee: "; - llvm::dbgs() << getCallee() << ")\n"; - } - - VirtualMethodSlot slot() const { - VirtualMethodSlot::KindTy slotKind; - switch (kind) { - case Kind::Witness: { - slotKind = VirtualMethodSlot::KindTy::Witness; - break; - } - case Kind::VTable: { - slotKind = VirtualMethodSlot::KindTy::VTable; - break; - } - case Kind::Static: { - llvm_unreachable("Can't get slot for static call"); - } - case Kind::kindCount: { - llvm_unreachable("impossible"); - } - } - return VirtualMethodSlot(slotKind, CalleeFn); - } - - EdgeTy(GUID callee, std::string name, Kind kind) - : CalleeFn(callee), Name(name), kind(kind) {} + friend ::llvm::yaml::MappingTraits; + Call() = default; + Call(GUID callee, std::string name, KindTy kind) + : Callee(callee), Name(name), Kind(kind) {} - static EdgeTy staticCall(SILFunction *CalleeFn) { - GUID guid = getGUID(CalleeFn->getName()); - return EdgeTy(guid, CalleeFn->getName(), Kind::Static); - } - - static EdgeTy witnessCall(SILDeclRef Callee) { - return EdgeTy(Callee, Kind::Witness); - } - static EdgeTy vtableCall(SILDeclRef Callee) { - return EdgeTy(Callee, Kind::VTable); - } + KindTy getKind() const { return Kind; } + GUID getCallee() const { return Callee; } + std::string getName() const { return Name; }; }; - + /// Function state flags struct FlagsTy { - unsigned Live : 1; - unsigned Preserved: 1; + /// In per-module summary, always false. + /// In combined summary, indicates that the function is live. + bool Live; + /// Indicates that the function must be considered a live root for liveness + /// analysis. + bool Preserved; }; - - using CallGraphEdgeListTy = std::vector; + + using CallGraphEdgeListTy = std::vector; private: + // For import/export + friend llvm::yaml::MappingTraits; + + /// The function identity. + GUID Guid; + /// The function state flags. FlagsTy Flags; + /// List of Call from this function. CallGraphEdgeListTy CallGraphEdgeList; + /// The symbol name of the function only for debug and test purposes. std::string Name; public: - FunctionSummary(std::vector CGEdges) - : CallGraphEdgeList(std::move(CGEdges)) {} FunctionSummary() = default; + FunctionSummary(GUID guid) + : Guid(guid), Flags({false, false}), CallGraphEdgeList(), Name("") {} - void addCall(GUID targetGUID, std::string name, EdgeTy::Kind kind) { - CallGraphEdgeList.emplace_back(targetGUID, name, kind); - } + /// Add a call to the list. + void addCall(Call call) { CallGraphEdgeList.push_back(call); } + + /// Return the list of Call from this function + ArrayRef calls() const { return CallGraphEdgeList; } - ArrayRef calls() const { return CallGraphEdgeList; } - bool isLive() const { return Flags.Live; } void setLive(bool Live) { Flags.Live = Live; } bool isPreserved() const { return Flags.Preserved; } void setPreserved(bool Preserved) { Flags.Preserved = Preserved; } + std::string getName() const { return Name; } void setName(std::string name) { this->Name = name; } + + GUID getGUID() const { return Guid; } }; -class ModuleSummaryIndex { - using FunctionSummaryInfoMapTy = std::map>; - using VirtualMethodInfoMapTy = std::map>; +/// A slot in a set of virtual tables. +struct VFuncSlot { + /// Kinds of table. + enum KindTy { + Witness, + VTable, + kindCount, + }; + + /// Kind of table. + KindTy Kind; + /// The virtual function GUID. + GUID VFuncID; - FunctionSummaryInfoMapTy FunctionSummaryInfoMap; - VirtualMethodInfoMapTy VirtualMethodInfoMap; + VFuncSlot(KindTy Kind, GUID VFuncID) : Kind(Kind), VFuncID(VFuncID) {} +}; + +using FunctionSummaryMapTy = std::map>; +using VFuncToImplsMapTy = std::map>; - std::string ModuleName; // Only for debug purpose +/// Module summary that consists of function summaries and virtual function +/// tables. +class ModuleSummaryIndex { + // For import/export + friend llvm::yaml::MappingTraits; + + /// Map from function GUID to function summary. + FunctionSummaryMapTy FunctionSummaryMap; + /// Map from virtual function GUID to list of implementations for witness + /// tables. + VFuncToImplsMapTy WitnessTableMethodMap; + /// Map from virtual function GUID to list of implementations for vtables. + VFuncToImplsMapTy VTableMethodMap; + /// The symbol name of the module. + std::string Name; + VFuncToImplsMapTy &getVFuncMap(VFuncSlot::KindTy kind) { + switch (kind) { + case VFuncSlot::Witness: + return WitnessTableMethodMap; + case VFuncSlot::VTable: + return VTableMethodMap; + case VFuncSlot::kindCount: { + llvm_unreachable("impossible"); + } + } + } + const VFuncToImplsMapTy &getVFuncMap(VFuncSlot::KindTy kind) const { + switch (kind) { + case VFuncSlot::Witness: + return WitnessTableMethodMap; + case VFuncSlot::VTable: + return VTableMethodMap; + case VFuncSlot::kindCount: { + llvm_unreachable("impossible"); + } + } + } public: + friend ::llvm::yaml::MappingTraits; ModuleSummaryIndex() = default; - std::string getModuleName() const { return this->ModuleName; } - void setModuleName(std::string name) { - this->ModuleName = name; - } + std::string getName() const { return this->Name; } + void setName(std::string name) { this->Name = name; } + /// Add a global value summary. void addFunctionSummary(std::unique_ptr summary) { - auto guid = getGUID(summary->getName()); - FunctionSummaryInfoMap.insert( - std::make_pair(guid, std::move(summary))); + FunctionSummaryMap.insert( + std::make_pair(summary->getGUID(), std::move(summary))); } - const llvm::Optional - getFunctionInfo(GUID guid) const { - auto found = FunctionSummaryInfoMap.find(guid); - if (found == FunctionSummaryInfoMap.end()) { - return None; + /// Return a FunctionSummary for GUID if it exists, otherwise return nullptr. + FunctionSummary *getFunctionSummary(GUID guid) const { + auto found = FunctionSummaryMap.find(guid); + if (found == FunctionSummaryMap.end()) { + return nullptr; } - return found->second.get(); + auto &entry = found->second; + return entry.get(); } - - void addImplementation(VirtualMethodSlot slot, GUID funcGUID) { - auto found = VirtualMethodInfoMap.find(slot); - if (found == VirtualMethodInfoMap.end()) { - VirtualMethodInfoMap.insert(std::make_pair(slot, std::vector{ funcGUID })); + + /// Record a implementation for the virtual function slot. + void addImplementation(VFuncSlot slot, GUID implGUID) { + VFuncToImplsMapTy &table = getVFuncMap(slot.Kind); + auto found = table.find(slot.VFuncID); + if (found == table.end()) { + table.insert(std::make_pair(slot.VFuncID, std::vector{implGUID})); return; } - found->second.push_back(funcGUID); + found->second.push_back(implGUID); } - - llvm::Optional> - getImplementations(VirtualMethodSlot slot) const { - auto found = VirtualMethodInfoMap.find(slot); - if (found == VirtualMethodInfoMap.end()) { - return None; + + /// Return a list of implementations for the virtual function slot. + ArrayRef getImplementations(VFuncSlot slot) const { + const VFuncToImplsMapTy &table = getVFuncMap(slot.Kind); + auto found = table.find(slot.VFuncID); + if (found == table.end()) { + return ArrayRef(); } return ArrayRef(found->second); } - const VirtualMethodInfoMapTy &virtualMethods() const { - return VirtualMethodInfoMap; + const VFuncToImplsMapTy &getWitnessTableMethodMap() const { + return WitnessTableMethodMap; + } + const VFuncToImplsMapTy &getVTableMethodMap() const { + return VTableMethodMap; } - FunctionSummaryInfoMapTy::const_iterator begin() const { - return FunctionSummaryInfoMap.begin(); + FunctionSummaryMapTy::const_iterator functions_begin() const { + return FunctionSummaryMap.begin(); } - FunctionSummaryInfoMapTy::const_iterator end() const { - return FunctionSummaryInfoMap.end(); + FunctionSummaryMapTy::const_iterator functions_end() const { + return FunctionSummaryMap.end(); } }; -ModuleSummaryIndex buildModuleSummaryIndex(SILModule &M, - BasicCalleeAnalysis &BCA); - -}; // namespace swift +/// Compute a \c ModuleSummaryIndex from the given SILModule. +std::unique_ptr buildModuleSummaryIndex(SILModule &M); + +/// Serializes a module summary to the given output file. +/// +/// \returns false on success, true on error. +bool writeModuleSummaryIndex(const ModuleSummaryIndex &index, + DiagnosticEngine &diags, StringRef path); + +/// Attempt to deserialize the module summary. +/// +/// \returns false on success, true on error. +bool loadModuleSummaryIndex(llvm::MemoryBufferRef inputBuffer, + ModuleSummaryIndex &moduleSummary); +} // namespace modulesummary +} // namespace swift #endif diff --git a/include/swift/Serialization/ModuleSummary.h b/include/swift/Serialization/ModuleSummary.h new file mode 100644 index 0000000000000..36350c84c3581 --- /dev/null +++ b/include/swift/Serialization/ModuleSummary.h @@ -0,0 +1,250 @@ +//===----- ModuleSummary.h --------------------------------------*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_SIL_MODULE_SUMMARY_H +#define SWIFT_SIL_MODULE_SUMMARY_H + +#include "swift/AST/Decl.h" +#include "swift/SIL/SILFunction.h" +#include "llvm/Support/YAMLTraits.h" + +namespace swift { + +namespace modulesummary { + +using GUID = uint64_t; + +/// Compute globally unique identifier from the symbol. +GUID getGUIDFromUniqueName(llvm::StringRef Name); + +/// Function summary information to help callee analysis +class FunctionSummary { +public: + /// Function call information + class Call { + public: + /// Kinds of callee reference. + enum KindTy { + /// The call references a function statically + Direct, + /// The call references a function via a witness table. + Witness, + /// The call references a function via a vtable. + VTable, + kindCount, + }; + + private: + // For import/export + friend llvm::yaml::MappingTraits; + + /// The callee function GUID. This can be a static function or a virtual + /// function GUID. + GUID Callee; + /// The symbol name of the callee function only for debug and test purposes. + std::string Name; + /// Kind of the callee reference. + KindTy Kind; + public: + friend ::llvm::yaml::MappingTraits; + Call() = default; + Call(GUID callee, std::string name, KindTy kind) + : Callee(callee), Name(name), Kind(kind) {} + + KindTy getKind() const { return Kind; } + GUID getCallee() const { return Callee; } + std::string getName() const { return Name; }; + }; + + /// Function state flags + struct FlagsTy { + /// In per-module summary, always false. + /// In combined summary, indicates that the function is live. + bool Live; + /// Indicates that the function must be considered a live root for liveness + /// analysis. + bool Preserved; + }; + + using CallGraphEdgeListTy = std::vector; + +private: + // For import/export + friend llvm::yaml::MappingTraits; + + /// The function identity. + GUID Guid; + /// The function state flags. + FlagsTy Flags; + /// List of Call from this function. + CallGraphEdgeListTy CallGraphEdgeList; + /// The symbol name of the function only for debug and test purposes. + std::string Name; + +public: + FunctionSummary() = default; + FunctionSummary(GUID guid) + : Guid(guid), Flags({false, false}), CallGraphEdgeList(), Name("") {} + + /// Add a call to the list. + void addCall(Call call) { CallGraphEdgeList.push_back(call); } + + /// Return the list of Call from this function + ArrayRef calls() const { return CallGraphEdgeList; } + + bool isLive() const { return Flags.Live; } + void setLive(bool Live) { Flags.Live = Live; } + + bool isPreserved() const { return Flags.Preserved; } + void setPreserved(bool Preserved) { Flags.Preserved = Preserved; } + + std::string getName() const { return Name; } + void setName(std::string name) { this->Name = name; } + + GUID getGUID() const { return Guid; } +}; + +/// A slot in a set of virtual tables. +struct VFuncSlot { + /// Kinds of table. + enum KindTy { + Witness, + VTable, + kindCount, + }; + + /// Kind of table. + KindTy Kind; + /// The virtual function GUID. + GUID VFuncID; + + VFuncSlot(KindTy Kind, GUID VFuncID) : Kind(Kind), VFuncID(VFuncID) {} +}; + +using FunctionSummaryMapTy = std::map>; +using VFuncToImplsMapTy = std::map>; + +/// Module summary that consists of function summaries and virtual function +/// tables. +class ModuleSummaryIndex { + // For import/export + friend llvm::yaml::MappingTraits; + + /// Map from function GUID to function summary. + FunctionSummaryMapTy FunctionSummaryMap; + /// Map from virtual function GUID to list of implementations for witness + /// tables. + VFuncToImplsMapTy WitnessTableMethodMap; + /// Map from virtual function GUID to list of implementations for vtables. + VFuncToImplsMapTy VTableMethodMap; + /// The symbol name of the module. + std::string Name; + + VFuncToImplsMapTy &getVFuncMap(VFuncSlot::KindTy kind) { + switch (kind) { + case VFuncSlot::Witness: + return WitnessTableMethodMap; + case VFuncSlot::VTable: + return VTableMethodMap; + case VFuncSlot::kindCount: { + llvm_unreachable("impossible"); + } + } + } + const VFuncToImplsMapTy &getVFuncMap(VFuncSlot::KindTy kind) const { + switch (kind) { + case VFuncSlot::Witness: + return WitnessTableMethodMap; + case VFuncSlot::VTable: + return VTableMethodMap; + case VFuncSlot::kindCount: { + llvm_unreachable("impossible"); + } + } + } +public: + friend ::llvm::yaml::MappingTraits; + ModuleSummaryIndex() = default; + + std::string getName() const { return this->Name; } + void setName(std::string name) { this->Name = name; } + + /// Add a global value summary. + void addFunctionSummary(std::unique_ptr summary) { + FunctionSummaryMap.insert( + std::make_pair(summary->getGUID(), std::move(summary))); + } + + /// Return a FunctionSummary for GUID if it exists, otherwise return nullptr. + FunctionSummary *getFunctionSummary(GUID guid) const { + auto found = FunctionSummaryMap.find(guid); + if (found == FunctionSummaryMap.end()) { + return nullptr; + } + auto &entry = found->second; + return entry.get(); + } + + /// Record a implementation for the virtual function slot. + void addImplementation(VFuncSlot slot, GUID implGUID) { + VFuncToImplsMapTy &table = getVFuncMap(slot.Kind); + auto found = table.find(slot.VFuncID); + if (found == table.end()) { + table.insert(std::make_pair(slot.VFuncID, std::vector{implGUID})); + return; + } + found->second.push_back(implGUID); + } + + /// Return a list of implementations for the virtual function slot. + ArrayRef getImplementations(VFuncSlot slot) const { + const VFuncToImplsMapTy &table = getVFuncMap(slot.Kind); + auto found = table.find(slot.VFuncID); + if (found == table.end()) { + return ArrayRef(); + } + return ArrayRef(found->second); + } + + const VFuncToImplsMapTy &getWitnessTableMethodMap() const { + return WitnessTableMethodMap; + } + const VFuncToImplsMapTy &getVTableMethodMap() const { + return VTableMethodMap; + } + + FunctionSummaryMapTy::const_iterator functions_begin() const { + return FunctionSummaryMap.begin(); + } + FunctionSummaryMapTy::const_iterator functions_end() const { + return FunctionSummaryMap.end(); + } +}; + +/// Compute a \c ModuleSummaryIndex from the given SILModule. +std::unique_ptr buildModuleSummaryIndex(SILModule &M); + +/// Serializes a module summary to the given output file. +/// +/// \returns false on success, true on error. +bool writeModuleSummaryIndex(const ModuleSummaryIndex &index, + DiagnosticEngine &diags, StringRef path); + +/// Attempt to deserialize the module summary. +/// +/// \returns false on success, true on error. +bool loadModuleSummaryIndex(llvm::MemoryBufferRef inputBuffer, + ModuleSummaryIndex &moduleSummary); +} // namespace modulesummary +} // namespace swift + +#endif diff --git a/include/swift/Serialization/ModuleSummaryFile.h b/include/swift/Serialization/ModuleSummaryFile.h deleted file mode 100644 index 18d138b398ec6..0000000000000 --- a/include/swift/Serialization/ModuleSummaryFile.h +++ /dev/null @@ -1,87 +0,0 @@ -#ifndef SWIFT_SERIALIZATION_MODULE_SUMMARY_FILE_H -#define SWIFT_SERIALIZATION_MODULE_SUMMARY_FILE_H - -#include "swift/SIL/ModuleSummary.h" -#include "llvm/Bitcode/RecordLayout.h" -#include "llvm/Support/MemoryBuffer.h" -#include - -namespace swift { - -namespace modulesummary { - -using llvm::BCArray; -using llvm::BCBlob; -using llvm::BCFixed; -using llvm::BCGenericRecordLayout; -using llvm::BCRecordLayout; -using llvm::BCVBR; - -const unsigned char MODULE_SUMMARY_SIGNATURE[] = {'M', 'O', 'D', 'S'}; - -enum BlockID { - MODULE_SUMMARY_ID = llvm::bitc::FIRST_APPLICATION_BLOCKID, - - FUNCTION_SUMMARY_ID, - - VIRTUAL_METHOD_INFO_ID, -}; - -namespace module_summary { -enum { - MODULE_METADATA, -}; - -using MetadataLayout = BCRecordLayout< - MODULE_METADATA, - BCBlob // Module name ->; -}; - -namespace virtual_method_info { -enum { - METHOD_METADATA, - METHOD_IMPL, -}; - -using MethodMetadataLayout = BCRecordLayout< - METHOD_METADATA, - BCFixed<1>, // KindTy (WitnessTable or VTable) - BCVBR<16> // VirtualFunc GUID ->; - -using MethodImplLayout = BCRecordLayout< - METHOD_IMPL, - BCVBR<16> // Impl func GUID ->; -}; - -namespace function_summary { -enum { - METADATA, - CALL_GRAPH_EDGE, -}; - -using MetadataLayout = BCRecordLayout, // Function GUID - BCFixed<1>, // live - BCFixed<1>, // preserved - BCBlob // Name string - >; -using CallGraphEdgeLayout = - BCRecordLayout, // FunctionSummary::Edge::Kind - BCVBR<16>, // Target Function GUID - BCBlob // Name string - >; -} // namespace function_summary - -bool emitModuleSummaryIndex(const ModuleSummaryIndex &index, - DiagnosticEngine &diags, StringRef path); - -bool loadModuleSummaryIndex(llvm::MemoryBufferRef inputBuffer, - ModuleSummaryIndex &moduleSummary); -} // namespace modulesummary -} // namespace swift - -#endif diff --git a/lib/FrontendTool/FrontendTool.cpp b/lib/FrontendTool/FrontendTool.cpp index bb7c05d3932c1..51857c97f8c2e 100644 --- a/lib/FrontendTool/FrontendTool.cpp +++ b/lib/FrontendTool/FrontendTool.cpp @@ -66,7 +66,7 @@ #include "swift/Syntax/SyntaxNodes.h" #include "swift/TBDGen/TBDGen.h" #include "swift/SIL/ModuleSummary.h" -#include "swift/Serialization/ModuleSummaryFile.h" +#include "swift/Serialization/ModuleSummary.h" #include "clang/AST/ASTContext.h" @@ -1829,10 +1829,9 @@ static bool serializeSIB(SILModule *SM, const PrimarySpecificPaths &PSPs, static bool emitModuleSummary(SILModule *SM, const std::string &ModuleSummaryOutputPath, const ASTContext &Context) { - BasicCalleeAnalysis BCA(SM); - auto Summary = buildModuleSummaryIndex(*SM, BCA); - return modulesummary::emitModuleSummaryIndex(Summary, Context.Diags, - ModuleSummaryOutputPath); + auto Summary = modulesummary::buildModuleSummaryIndex(*SM); + return modulesummary::writeModuleSummaryIndex(*Summary.get(), Context.Diags, + ModuleSummaryOutputPath); } static GeneratedModule diff --git a/lib/SILOptimizer/IPO/CrossDeadFunctionElimination.cpp b/lib/SILOptimizer/IPO/CrossDeadFunctionElimination.cpp index efae798337042..86e17384f562f 100644 --- a/lib/SILOptimizer/IPO/CrossDeadFunctionElimination.cpp +++ b/lib/SILOptimizer/IPO/CrossDeadFunctionElimination.cpp @@ -7,7 +7,7 @@ #include "swift/SIL/SILVisitor.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/Serialization/ModuleSummaryFile.h" +#include "swift/Serialization/ModuleSummary.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Statistic.h" @@ -23,6 +23,8 @@ STATISTIC(NumDeadFunc, "Number of dead functions eliminated"); namespace { +using namespace modulesummary; + class SILCrossDeadFuncElimination : public SILModuleTransform { private: ModuleSummaryIndex TheSummary; @@ -35,11 +37,11 @@ class SILCrossDeadFuncElimination : public SILModuleTransform { for (auto VT : M.getVTables()) { VT->removeEntries_if([&] (SILVTable::Entry &entry) -> bool { auto Impl = entry.getImplementation(); - auto &maybePair = TheSummary.getFunctionInfo(getGUID(Impl->getName())); - if (!maybePair) + GUID guid = getGUIDFromUniqueName(Impl->getName()); + auto maybeSummary = TheSummary.getFunctionSummary(guid); + if (!maybeSummary) return false; - auto info = maybePair.getValue().first; - return !info->isLive(); + return !maybeSummary->isLive(); }); } @@ -49,11 +51,11 @@ class SILCrossDeadFuncElimination : public SILModuleTransform { ++WI; WT->clearMethods_if([&] (const SILWitnessTable::MethodWitness &MW) -> bool { auto Impl = MW.Witness; - auto &maybePair = TheSummary.getFunctionInfo(getGUID(Impl->getName())); - if (!maybePair) + GUID guid = getGUIDFromUniqueName(Impl->getName()); + auto maybeSummary = TheSummary.getFunctionSummary(guid); + if (!maybeSummary) return false; - auto info = maybePair.getValue().first; - return !info->isLive(); + return !maybeSummary->isLive(); }); } @@ -66,79 +68,25 @@ class SILCrossDeadFuncElimination : public SILModuleTransform { WT->clearMethods_if([&](SILFunction *MW) -> bool { if (!MW) return false; - auto &maybePair = TheSummary.getFunctionInfo(getGUID(MW->getName())); - if (!maybePair) + GUID guid = getGUIDFromUniqueName(MW->getName()); + auto maybeSummary = TheSummary.getFunctionSummary(guid); + if (!maybeSummary) return false; - auto info = maybePair.getValue().first; - return !info->isLive(); + return !maybeSummary->isLive(); }); } } void eliminateDeadFunctions(SILModule &M, std::vector &DeadFunctions) { - for (auto &pair : TheSummary) { - auto &info = pair.second; - if (info.TheSummary->isLive()) { + for (SILFunction &F : M) { + auto guid = getGUIDFromUniqueName(F.getName()); + auto summary = TheSummary.getFunctionSummary(guid); + if (summary->isLive()) { continue; } - - auto F = M.lookUpFunction(info.Name); - if (!F) { - continue; - } - F->dropAllReferences(); - DeadFunctions.push_back(F); - LLVM_DEBUG(llvm::dbgs() << "Eliminate " << info.Name << "\n"); - } - } - - void ensureLive(SILFunction *F) { - ensureLive(getGUID(F->getName())); - } - - void ensureLive(GUID guid) { - auto maybePair = this->TheSummary.getFunctionInfo(guid); - if (maybePair) { - auto pair = maybePair.getValue(); - pair.first->setLive(true); - } - } - - void ensureLive(VirtualMethodSlot slot) { - auto Impls = this->TheSummary.getImplementations(slot); - if (!Impls) return; - for (auto Impl : Impls.getValue()) { - ensureLive(Impl); - } - } - - void - ensureKeyPathComponentIsAlive(const KeyPathPatternComponent &component) { - component.visitReferencedFunctionsAndMethods( - [this](SILFunction *F) { - this->ensureLive(F); - }, - [this](SILDeclRef method) { - auto decl = cast(method.getDecl()); - if (auto clas = dyn_cast(decl->getDeclContext())) { - VirtualMethodSlot slot(method, VirtualMethodSlot::KindTy::VTable); - this->ensureLive(slot); - } else if (isa(decl->getDeclContext())) { - VirtualMethodSlot slot(method, VirtualMethodSlot::KindTy::Witness); - this->ensureLive(slot); - } else { - llvm_unreachable("key path keyed by a non-class, non-protocol method"); - } - } - ); - } - - void ensurePreserved(SILModule &M) { - // Check property descriptor implementations. - for (SILProperty &P : M.getPropertyList()) { - if (auto component = P.getComponent()) { - ensureKeyPathComponentIsAlive(*component); - } + F.dropAllReferences(); + DeadFunctions.push_back(&F); + LLVM_DEBUG(llvm::dbgs() << "Eliminate " << F.getName() << "\n"); } } @@ -160,7 +108,6 @@ class SILCrossDeadFuncElimination : public SILModuleTransform { } auto &M = *getModule(); - this->ensurePreserved(M); this->eliminateDeadEntriesFromTables(M); std::vector DeadFunctions; this->eliminateDeadFunctions(M, DeadFunctions); diff --git a/lib/SILOptimizer/Utils/CMakeLists.txt b/lib/SILOptimizer/Utils/CMakeLists.txt index 3c96c5593e107..40359206beeb2 100644 --- a/lib/SILOptimizer/Utils/CMakeLists.txt +++ b/lib/SILOptimizer/Utils/CMakeLists.txt @@ -14,7 +14,6 @@ target_sources(swiftSILOptimizer PRIVATE KeyPathProjector.cpp LoadStoreOptUtils.cpp LoopUtils.cpp - ModuleSummaryIndex.cpp OptimizerStatsUtils.cpp PartialApplyCombiner.cpp PerformanceInlinerUtils.cpp diff --git a/lib/SILOptimizer/Utils/ModuleSummaryIndex.cpp b/lib/SILOptimizer/Utils/ModuleSummaryIndex.cpp deleted file mode 100644 index 4509d055bef63..0000000000000 --- a/lib/SILOptimizer/Utils/ModuleSummaryIndex.cpp +++ /dev/null @@ -1,205 +0,0 @@ -#include "swift/Demangling/Demangle.h" -#include "swift/SIL/ModuleSummary.h" -#include "swift/SIL/SILFunction.h" -#include "swift/SIL/SILModule.h" -#include "swift/SILOptimizer/Analysis/BasicCalleeAnalysis.h" -#include "swift/SILOptimizer/Analysis/FunctionOrder.h" -#include "swift/SILOptimizer/PassManager/Transforms.h" -#include "llvm/Support/MD5.h" -#include "llvm/Support/raw_ostream.h" - -#define DEBUG_TYPE "module-summary-index" - -using namespace swift; - -namespace { -class FunctionSummaryIndexer { - std::vector CallGraphEdgeList; -public: - void indexInstruction(SILFunction &F, SILInstruction *I); - void indexFunction(SILFunction &F); - - std::unique_ptr takeSummary() { - return std::make_unique(std::move(CallGraphEdgeList)); - } -}; - -void FunctionSummaryIndexer::indexInstruction(SILFunction &F, SILInstruction *I) { - // TODO: Handle dynamically replacable function ref inst - if (auto *FRI = dyn_cast(I)) { - SILFunction *callee = FRI->getReferencedFunctionOrNull(); - assert(callee); - auto edge = - FunctionSummary::EdgeTy::staticCall(callee); - CallGraphEdgeList.push_back(edge); - return; - } - - if (auto *WMI = dyn_cast(I)) { - auto edge = FunctionSummary::EdgeTy::witnessCall(WMI->getMember()); - CallGraphEdgeList.push_back(edge); - return; - } - - if (auto *MI = dyn_cast(I)) { - auto edge = FunctionSummary::EdgeTy::vtableCall(MI->getMember()); - CallGraphEdgeList.push_back(edge); - return; - } - - if (auto *KPI = dyn_cast(I)) { - for (auto &component : KPI->getPattern()->getComponents()) { - component.visitReferencedFunctionsAndMethods( - [this](SILFunction *F) { - auto edge = - FunctionSummary::EdgeTy::staticCall(F); - CallGraphEdgeList.push_back(edge); - }, - [this](SILDeclRef method) { - auto decl = cast(method.getDecl()); - if (auto clas = dyn_cast(decl->getDeclContext())) { - auto edge = FunctionSummary::EdgeTy::vtableCall(method); - CallGraphEdgeList.push_back(edge); - } else if (isa(decl->getDeclContext())) { - auto edge = FunctionSummary::EdgeTy::witnessCall(method); - CallGraphEdgeList.push_back(edge); - } else { - llvm_unreachable("key path keyed by a non-class, non-protocol method"); - } - } - ); - } - } -} - -void FunctionSummaryIndexer::indexFunction(SILFunction &F) { - for (auto &BB : F) { - for (auto &I : BB) { - indexInstruction(F, &I); - } - } -} -}; - -std::unique_ptr -buildFunctionSummaryIndex(SILFunction &F) { - FunctionSummaryIndexer indexer; - indexer.indexFunction(F); - return indexer.takeSummary(); -} - -void indexWitnessTable(ModuleSummaryIndex &index, SILModule &M) { - std::vector Preserved; - for (auto &WT : M.getWitnessTableList()) { - auto isExternalProto = WT.getDeclContext()->getParentModule() != M.getSwiftModule() || - WT.getProtocol()->getParentModule() != M.getSwiftModule(); - for (auto entry : WT.getEntries()) { - if (entry.getKind() != SILWitnessTable::Method) continue; - - auto methodWitness = entry.getMethodWitness(); - auto Witness = methodWitness.Witness; - if (!Witness) continue; - VirtualMethodSlot slot(methodWitness.Requirement, VirtualMethodSlot::KindTy::Witness); - index.addImplementation(slot, getGUID(Witness->getName())); - if (isExternalProto) { - auto edge = FunctionSummary::EdgeTy::staticCall(Witness); - Preserved.push_back(edge); - } - } - } - - auto FS = std::make_unique(Preserved); - FS->setPreserved(true); - LLVM_DEBUG(llvm::dbgs() << "Summary: Preserved " << Preserved.size() << " external witnesses\n"); - index.addFunctionSummary("__external_witnesses_preserved_fs", std::move(FS)); -} - - -void indexVTable(ModuleSummaryIndex &index, SILModule &M) { - std::vector Preserved; - for (auto &VT : M.getVTables()) { - for (auto entry : VT->getEntries()) { - auto Impl = entry.getImplementation(); - if (entry.getMethod().kind == SILDeclRef::Kind::Deallocator || - entry.getMethod().kind == SILDeclRef::Kind::IVarDestroyer) { - // Destructors are alive because they are called from swift_release - auto edge = FunctionSummary::EdgeTy::staticCall(Impl); - LLVM_DEBUG(llvm::dbgs() << "Preserve deallocator '" << Impl->getName() << "'\n"); - Preserved.push_back(edge); - } - auto methodMod = entry.getMethod().getDecl()->getModuleContext(); - auto isExternalMethod = methodMod != M.getSwiftModule(); - if (entry.getKind() == SILVTableEntry::Override && isExternalMethod) { - auto edge = FunctionSummary::EdgeTy::staticCall(Impl); - Preserved.push_back(edge); - } - VirtualMethodSlot slot(entry.getMethod(), VirtualMethodSlot::KindTy::VTable); - index.addImplementation(slot, getGUID(Impl->getName())); - } - } - - auto FS = std::make_unique(Preserved); - FS->setPreserved(true); - LLVM_DEBUG(llvm::dbgs() << "Summary: Preserved " << Preserved.size() << " deallocators\n"); - index.addFunctionSummary("__vtable_destructors_and_externals_preserved_fs", std::move(FS)); -} - -void indexKeyPathComponent(ModuleSummaryIndex &index, SILModule &M) { - std::vector CallGraphEdgeList; - for (SILProperty &P : M.getPropertyList()) { - if (auto component = P.getComponent()) { - component->visitReferencedFunctionsAndMethods( - [&](SILFunction *F) { - auto FS = buildFunctionSummaryIndex(*F); - LLVM_DEBUG(llvm::dbgs() << "Preserve keypath funcs " << F->getName() << "\n"); - FS->setPreserved(true); - index.addFunctionSummary(F->getName(), std::move(FS)); - }, - [&](SILDeclRef method) { - auto decl = cast(method.getDecl()); - if (auto clas = dyn_cast(decl->getDeclContext())) { - auto edge = FunctionSummary::EdgeTy::vtableCall(method); - CallGraphEdgeList.push_back(edge); - } else if (isa(decl->getDeclContext())) { - auto edge = FunctionSummary::EdgeTy::witnessCall(method); - CallGraphEdgeList.push_back(edge); - } else { - llvm_unreachable("key path keyed by a non-class, non-protocol method"); - } - } - ); - } - } - auto FS = std::make_unique(std::move(CallGraphEdgeList)); - FS->setPreserved(true); - index.addFunctionSummary("__keypath_preserved_fs", std::move(FS)); -} - -ModuleSummaryIndex swift::buildModuleSummaryIndex(SILModule &M, - BasicCalleeAnalysis &BCA) { - ModuleSummaryIndex index; - - index.setModuleName(M.getSwiftModule()->getName().str()); - - // Preserve keypath things temporarily - indexKeyPathComponent(index, M); - - for (auto &F : M) { - auto FS = buildFunctionSummaryIndex(F); - if (F.getRepresentation() == SILFunctionTypeRepresentation::ObjCMethod) { - LLVM_DEBUG(llvm::dbgs() << "Preserve " << F.getName() << " due to ObjCMethod\n"); - FS->setPreserved(true); - } - if (F.hasCReferences()) { - LLVM_DEBUG(llvm::dbgs() << "Preserve " << F.getName() << " due to @_silgen_name or @_cdecl\n"); - FS->setPreserved(true); - } - - FS->setLive(false); - index.addFunctionSummary(F.getName(), std::move(FS)); - } - - indexWitnessTable(index, M); - indexVTable(index, M); - return index; -} diff --git a/lib/Serialization/CMakeLists.txt b/lib/Serialization/CMakeLists.txt index f06342fd8b657..13e6664ca93c9 100644 --- a/lib/Serialization/CMakeLists.txt +++ b/lib/Serialization/CMakeLists.txt @@ -4,7 +4,8 @@ add_swift_host_library(swiftSerialization STATIC ModuleDependencyScanner.cpp ModuleFile.cpp ModuleFileSharedCore.cpp - ModuleSummaryFile.cpp + ModuleSummaryFormat.cpp + ModuleSummaryIndexer.cpp Serialization.cpp SerializedModuleLoader.cpp SerializedSILLoader.cpp diff --git a/lib/Serialization/ModuleSummaryFile.cpp b/lib/Serialization/ModuleSummaryFile.cpp deleted file mode 100644 index 10f5a41875a67..0000000000000 --- a/lib/Serialization/ModuleSummaryFile.cpp +++ /dev/null @@ -1,433 +0,0 @@ -#include "swift/Serialization/ModuleSummaryFile.h" -#include "BCReadingExtras.h" -#include "memory" -#include "swift/AST/FileSystem.h" -#include "llvm/Bitstream/BitstreamReader.h" -#include "llvm/Bitstream/BitstreamWriter.h" - -namespace swift { - -namespace modulesummary { - -static llvm::Optional -getEdgeKind(unsigned edgeKind) { - if (edgeKind < unsigned(FunctionSummary::EdgeTy::Kind::kindCount)) - return FunctionSummary::EdgeTy::Kind(edgeKind); - return None; -} - - -static llvm::Optional -getSlotKind(unsigned kind) { - if (kind < unsigned(FunctionSummary::EdgeTy::Kind::kindCount)) - return VirtualMethodSlot::KindTy(kind); - return None; -} - -class Serializer { - SmallVector Buffer; - llvm::BitstreamWriter Out{Buffer}; - - /// A reusable buffer for emitting records. - SmallVector ScratchRecord; - - void writeSignature(); - void writeBlockInfoBlock(); - void emitBlockID(unsigned ID, StringRef name, - SmallVectorImpl &nameBuffer); - - void emitRecordID(unsigned ID, StringRef name, - SmallVectorImpl &nameBuffer); - -public: - - void emitHeader(); - void emitModuleSummary(const ModuleSummaryIndex &index); - void write(llvm::raw_ostream &os); -}; - -void Serializer::emitBlockID(unsigned ID, StringRef name, - llvm::SmallVectorImpl &nameBuffer) { - SmallVector idBuffer; - idBuffer.push_back(ID); - Out.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID, idBuffer); - - // Emit the block name if present. - if (name.empty()) - return; - nameBuffer.resize(name.size()); - memcpy(nameBuffer.data(), name.data(), name.size()); - Out.EmitRecord(llvm::bitc::BLOCKINFO_CODE_BLOCKNAME, nameBuffer); -} - -void Serializer::emitRecordID(unsigned ID, StringRef name, - SmallVectorImpl &nameBuffer) { - assert(ID < 256 && "can't fit record ID in next to name"); - nameBuffer.resize(name.size() + 1); - nameBuffer[0] = ID; - memcpy(nameBuffer.data() + 1, name.data(), name.size()); - Out.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, nameBuffer); -} - -void Serializer::writeSignature() { - for (auto c : MODULE_SUMMARY_SIGNATURE) - Out.Emit((unsigned) c, 8); -} - -void Serializer::writeBlockInfoBlock() { - llvm::BCBlockRAII restoreBlock(Out, llvm::bitc::BLOCKINFO_BLOCK_ID, 2); - - SmallVector nameBuffer; -#define BLOCK(X) emitBlockID(X##_ID, #X, nameBuffer) -#define BLOCK_RECORD(K, X) emitRecordID(K::X, #X, nameBuffer) - - BLOCK(MODULE_SUMMARY); - BLOCK_RECORD(module_summary, MODULE_METADATA); - - BLOCK(FUNCTION_SUMMARY); - BLOCK_RECORD(function_summary, METADATA); - BLOCK_RECORD(function_summary, CALL_GRAPH_EDGE); - - BLOCK(VIRTUAL_METHOD_INFO); - BLOCK_RECORD(virtual_method_info, METHOD_METADATA); - BLOCK_RECORD(virtual_method_info, METHOD_IMPL); - -} - -void Serializer::emitHeader() { - writeSignature(); - writeBlockInfoBlock(); -} - -void Serializer::emitModuleSummary(const ModuleSummaryIndex &index) { - using namespace module_summary; - - llvm::BCBlockRAII restoreBlock(Out, MODULE_SUMMARY_ID, 4); - module_summary::MetadataLayout MDLayout(Out); - MDLayout.emit(ScratchRecord, index.getModuleName()); - { - for (const auto &pair : index) { - llvm::BCBlockRAII restoreBlock(Out, FUNCTION_SUMMARY_ID, 32); - auto &summary = pair.second; - using namespace function_summary; - function_summary::MetadataLayout MDlayout(Out); - - MDlayout.emit(ScratchRecord, pair.first, summary->isLive(), summary->isPreserved(), summary->getName()); - - for (auto call : summary->calls()) { - CallGraphEdgeLayout edgeLayout(Out); - edgeLayout.emit(ScratchRecord, unsigned(call.getKind()), - call.getCallee(), call.getName()); - } - } - } - - { - for (auto &method : index.virtualMethods()) { - llvm::BCBlockRAII restoreBlock(Out, VIRTUAL_METHOD_INFO_ID, 32); - auto &slot = method.first; - auto impls = method.second; - using namespace virtual_method_info; - - MethodMetadataLayout MDLayout(Out); - - MDLayout.emit(ScratchRecord, - unsigned(slot.Kind), - slot.VirtualFuncID); - - for (auto impl : impls) { - MethodImplLayout ImplLayout(Out); - ImplLayout.emit(ScratchRecord, impl); - } - } - } -} - -void Serializer::write(llvm::raw_ostream &os) { - os.write(Buffer.data(), Buffer.size()); - os.flush(); -} - -bool emitModuleSummaryIndex(const ModuleSummaryIndex &index, - DiagnosticEngine &diags, StringRef path) { - return withOutputFile(diags, path, [&](llvm::raw_ostream &out) { - Serializer serializer; - serializer.emitHeader(); - serializer.emitModuleSummary(index); - serializer.write(out); - return false; - }); -} - -class Deserializer { - llvm::BitstreamCursor Cursor; - SmallVector Scratch; - StringRef BlobData; - - ModuleSummaryIndex &moduleSummary; - - bool readSignature(); - bool readModuleSummaryMetadata(); - bool readVirtualMethodInfo(); - bool readFunctionSummary(); - bool readSingleModuleSummary(); - -public: - Deserializer(llvm::MemoryBufferRef inputBuffer, - ModuleSummaryIndex &moduleSummary) - : Cursor{inputBuffer}, moduleSummary(moduleSummary) {} - bool readModuleSummary(); -}; - -bool Deserializer::readSignature() { - for (unsigned char byte : MODULE_SUMMARY_SIGNATURE) { - if (Cursor.AtEndOfStream()) - return true; - if (auto maybeRead = Cursor.Read(8)) { - if (maybeRead.get() != byte) - return true; - } else { - return true; - } - } - return false; -} - -bool Deserializer::readModuleSummaryMetadata() { - llvm::Expected maybeEntry = Cursor.advance(); - if (!maybeEntry) - llvm::report_fatal_error("Should have next entry"); - - llvm::BitstreamEntry entry = maybeEntry.get(); - - if (entry.Kind != llvm::BitstreamEntry::Record) { - return true; - } - Scratch.clear(); - auto maybeKind = Cursor.readRecord(entry.ID, Scratch, &BlobData); - - if (!maybeKind) { - consumeError(maybeKind.takeError()); - return true; - } - - if (maybeKind.get() != module_summary::MODULE_METADATA) { - return true; - } - - moduleSummary.setModuleName(BlobData.str()); - - return false; -} - -bool Deserializer::readFunctionSummary() { - if (llvm::Error Err = Cursor.EnterSubBlock(FUNCTION_SUMMARY_ID)) { - llvm::report_fatal_error("Can't enter subblock"); - } - - llvm::Expected maybeNext = Cursor.advance(); - if (!maybeNext) - llvm::report_fatal_error("Should have next entry"); - - llvm::BitstreamEntry next = maybeNext.get(); - - GUID guid; - std::string Name; - FunctionSummary *FS; - std::unique_ptr NewFSOwner; - - while (next.Kind == llvm::BitstreamEntry::Record) { - Scratch.clear(); - - auto maybeKind = Cursor.readRecord(next.ID, Scratch, &BlobData); - - if (!maybeKind) - llvm::report_fatal_error("Should have kind"); - - switch (maybeKind.get()) { - case function_summary::METADATA: { - unsigned isLive, isPreserved; - function_summary::MetadataLayout::readRecord(Scratch, guid, isLive, isPreserved); - Name = BlobData.str(); - if (auto info = moduleSummary.getFunctionInfo(guid)) { - FS = info.getValue(); - } else { - NewFSOwner = std::make_unique(); - FS = NewFSOwner.get(); - } - FS->setLive(isLive); - FS->setPreserved(isPreserved); - FS->setName(Name); - break; - } - case function_summary::CALL_GRAPH_EDGE: { - unsigned edgeKindID; - GUID targetGUID; - function_summary::CallGraphEdgeLayout::readRecord(Scratch, edgeKindID, - targetGUID); - auto edgeKind = getEdgeKind(edgeKindID); - if (!edgeKind) - llvm::report_fatal_error("Bad edge kind"); - if (!FS) - llvm::report_fatal_error("Invalid state"); - - FS->addCall(targetGUID, BlobData.str(), edgeKind.getValue()); - break; - } - } - - maybeNext = Cursor.advance(); - if (!maybeNext) - llvm::report_fatal_error("Should have next entry"); - - next = maybeNext.get(); - } - - if (auto &FS = NewFSOwner) { - moduleSummary.addFunctionSummary(std::move(FS)); - } - return false; -} - -bool Deserializer::readVirtualMethodInfo() { - if (llvm::Error Err = Cursor.EnterSubBlock(VIRTUAL_METHOD_INFO_ID)) { - llvm::report_fatal_error("Can't enter subblock"); - } - - llvm::Expected maybeNext = Cursor.advance(); - if (!maybeNext) - llvm::report_fatal_error("Should have next entry"); - - llvm::BitstreamEntry next = maybeNext.get(); - - llvm::Optional slot; - - while (next.Kind == llvm::BitstreamEntry::Record) { - Scratch.clear(); - - auto maybeKind = Cursor.readRecord(next.ID, Scratch, &BlobData); - - if (!maybeKind) - llvm::report_fatal_error("Should have kind"); - - switch (maybeKind.get()) { - case virtual_method_info::METHOD_METADATA: { - unsigned methodKindID; - GUID virtualFuncGUID; - virtual_method_info::MethodMetadataLayout::readRecord(Scratch, methodKindID, virtualFuncGUID); - - auto Kind = getSlotKind(methodKindID); - if (!Kind) - llvm::report_fatal_error("Bad method kind"); - - slot = VirtualMethodSlot(Kind.getValue(), virtualFuncGUID); - break; - } - case virtual_method_info::METHOD_IMPL: { - GUID implGUID; - virtual_method_info::MethodImplLayout::readRecord(Scratch, implGUID); - if (!slot) - llvm::report_fatal_error("Slot should be set before impl"); - moduleSummary.addImplementation(slot.getValue(), implGUID); - break; - } - } - - maybeNext = Cursor.advance(); - if (!maybeNext) - llvm::report_fatal_error("Should have next entry"); - - next = maybeNext.get(); - } - - return false; -} - -bool Deserializer::readSingleModuleSummary() { - if (llvm::Error Err = Cursor.EnterSubBlock(MODULE_SUMMARY_ID)) { - llvm::report_fatal_error("Can't enter subblock"); - } - - if (readModuleSummaryMetadata()) { - return true; - } - - llvm::Expected maybeNext = Cursor.advance(); - if (!maybeNext) - llvm::report_fatal_error("Should have next entry"); - - llvm::BitstreamEntry next = maybeNext.get(); - while (next.Kind == llvm::BitstreamEntry::SubBlock) { - switch (next.ID) { - case FUNCTION_SUMMARY_ID: { - if (readFunctionSummary()) { - llvm::report_fatal_error("Failed to read FS"); - } - break; - } - case VIRTUAL_METHOD_INFO_ID: { - if (readVirtualMethodInfo()) { - llvm::report_fatal_error("Failed to read virtual method info"); - } - break; - } - } - - maybeNext = Cursor.advance(); - if (!maybeNext) { - consumeError(maybeNext.takeError()); - return true; - } - next = maybeNext.get(); - } - return false; -} - -bool Deserializer::readModuleSummary() { - if (readSignature()) { - llvm::report_fatal_error("Invalid signature"); - } - - while (!Cursor.AtEndOfStream()) { - llvm::Expected maybeEntry = - Cursor.advance(llvm::BitstreamCursor::AF_DontPopBlockAtEnd); - if (!maybeEntry) { - llvm::report_fatal_error("Should have entry"); - } - - auto entry = maybeEntry.get(); - if (entry.Kind != llvm::BitstreamEntry::SubBlock) - break; - - switch (entry.ID) { - case llvm::bitc::BLOCKINFO_BLOCK_ID: { - if (Cursor.SkipBlock()) { - return true; - } - break; - } - case MODULE_SUMMARY_ID: { - if (readSingleModuleSummary()) { - return true; - } - break; - } - case FUNCTION_SUMMARY_ID: - case VIRTUAL_METHOD_INFO_ID: { - llvm_unreachable("FUNCTION_SUMMARY and VIRTUAL_METHOD_INFO_ID blocks should be handled in " - "'readSingleModuleSummary'"); - break; - } - } - } - return false; -} - -bool loadModuleSummaryIndex(llvm::MemoryBufferRef inputBuffer, - ModuleSummaryIndex &moduleSummary) { - Deserializer deserializer(inputBuffer, moduleSummary); - return deserializer.readModuleSummary(); -} - -} // namespace modulesummary -} // namespace swift diff --git a/lib/Serialization/ModuleSummaryFormat.cpp b/lib/Serialization/ModuleSummaryFormat.cpp new file mode 100644 index 0000000000000..99d06faca72be --- /dev/null +++ b/lib/Serialization/ModuleSummaryFormat.cpp @@ -0,0 +1,426 @@ +//===--- ModuleSummaryFormat.cpp - Read and write module summary files ----===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#include "ModuleSummaryFormat.h" +#include "BCReadingExtras.h" +#include "memory" +#include "swift/AST/FileSystem.h" +#include "swift/Serialization/ModuleSummary.h" +#include "llvm/Bitstream/BitstreamReader.h" +#include "llvm/Bitstream/BitstreamWriter.h" +#include "llvm/Support/CommandLine.h" + +using namespace swift; +using namespace modulesummary; +using namespace llvm; + +static cl::opt ModuleSummaryEmbedDebugName( + "module-summary-embed-debug-name", cl::init(false), + cl::desc("Embed function names for debugging purpose")); + +namespace { + +class Serializer { + SmallVector Buffer; + BitstreamWriter Out{Buffer}; + + /// A reusable buffer for emitting records. + SmallVector ScratchRecord; + + std::array AbbrCodes; + + template void registerRecordAbbr() { + using AbbrArrayTy = decltype(AbbrCodes); + static_assert(Layout::Code <= std::tuple_size::value, + "layout has invalid record code"); + AbbrCodes[Layout::Code] = Layout::emitAbbrev(Out); + } + + void writeSignature(); + void writeBlockInfoBlock(); + void emitBlockID(unsigned ID, StringRef name, + SmallVectorImpl &nameBuffer); + + void emitRecordID(unsigned ID, StringRef name, + SmallVectorImpl &nameBuffer); + void emitVFuncTable(const VFuncToImplsMapTy T, VFuncSlot::KindTy kind); + +public: + void emitHeader(); + void emitModuleSummary(const ModuleSummaryIndex &index); + void emitFunctionSummary(const FunctionSummary *summary); + void write(raw_ostream &os); +}; + +void Serializer::emitBlockID(unsigned ID, StringRef name, + SmallVectorImpl &nameBuffer) { + SmallVector idBuffer; + idBuffer.push_back(ID); + Out.EmitRecord(bitc::BLOCKINFO_CODE_SETBID, idBuffer); + + // Emit the block name if present. + if (name.empty()) + return; + nameBuffer.resize(name.size()); + memcpy(nameBuffer.data(), name.data(), name.size()); + Out.EmitRecord(bitc::BLOCKINFO_CODE_BLOCKNAME, nameBuffer); +} + +void Serializer::emitRecordID(unsigned ID, StringRef name, + SmallVectorImpl &nameBuffer) { + assert(ID < 256 && "can't fit record ID in next to name"); + nameBuffer.resize(name.size() + 1); + nameBuffer[0] = ID; + memcpy(nameBuffer.data() + 1, name.data(), name.size()); + Out.EmitRecord(bitc::BLOCKINFO_CODE_SETRECORDNAME, nameBuffer); +} + +void Serializer::writeSignature() { + for (auto c : MODULE_SUMMARY_SIGNATURE) + Out.Emit((unsigned)c, 8); +} + +void Serializer::writeBlockInfoBlock() { + BCBlockRAII restoreBlock(Out, bitc::BLOCKINFO_BLOCK_ID, 2); + + SmallVector nameBuffer; +#define BLOCK(X) emitBlockID(X##_ID, #X, nameBuffer) +#define BLOCK_RECORD(K, X) emitRecordID(K::X, #X, nameBuffer) + + BLOCK(RECORD_BLOCK); + BLOCK_RECORD(record_block, MODULE_METADATA); + + BLOCK_RECORD(record_block, FUNC_METADATA); + BLOCK_RECORD(record_block, CALL_GRAPH_EDGE); + + BLOCK_RECORD(record_block, VFUNC_METADATA); + BLOCK_RECORD(record_block, VFUNC_IMPL); +} + +void Serializer::emitHeader() { + writeSignature(); + writeBlockInfoBlock(); +} + +void Serializer::emitFunctionSummary(const FunctionSummary *summary) { + using namespace record_block; + std::string debugFuncName = + ModuleSummaryEmbedDebugName ? summary->getName() : ""; + FunctionMetadataLayout::emitRecord( + Out, ScratchRecord, AbbrCodes[FunctionMetadataLayout::Code], + summary->getGUID(), unsigned(summary->isLive()), + unsigned(summary->isPreserved()), debugFuncName); + + for (auto call : summary->calls()) { + std::string debugName = ModuleSummaryEmbedDebugName ? call.getName() : ""; + CallGraphEdgeLayout::emitRecord( + Out, ScratchRecord, AbbrCodes[CallGraphEdgeLayout::Code], + unsigned(call.getKind()), call.getCallee(), debugName); + } +} + +void Serializer::emitVFuncTable(const VFuncToImplsMapTy T, + VFuncSlot::KindTy kind) { + for (auto &pair : T) { + GUID guid = pair.first; + std::vector impls = pair.second; + using namespace record_block; + + VFuncMetadataLayout::emitRecord(Out, ScratchRecord, + AbbrCodes[VFuncMetadataLayout::Code], + unsigned(kind), guid); + + for (auto impl : impls) { + VFuncImplLayout::emitRecord(Out, ScratchRecord, + AbbrCodes[VFuncImplLayout::Code], impl); + } + } +} + +void Serializer::emitModuleSummary(const ModuleSummaryIndex &index) { + using namespace record_block; + + BCBlockRAII restoreBlock(Out, RECORD_BLOCK_ID, 8); + + registerRecordAbbr(); + registerRecordAbbr(); + registerRecordAbbr(); + registerRecordAbbr(); + registerRecordAbbr(); + + ModuleMetadataLayout::emitRecord(Out, ScratchRecord, + AbbrCodes[ModuleMetadataLayout::Code], + index.getName()); + for (auto FI = index.functions_begin(), FE = index.functions_end(); FI != FE; + ++FI) { + emitFunctionSummary(FI->second.get()); + } + + emitVFuncTable(index.getWitnessTableMethodMap(), VFuncSlot::Witness); + emitVFuncTable(index.getVTableMethodMap(), VFuncSlot::VTable); +} + +void Serializer::write(raw_ostream &os) { + os.write(Buffer.data(), Buffer.size()); + os.flush(); +} + +class Deserializer { + BitstreamCursor Cursor; + SmallVector Scratch; + StringRef BlobData; + + ModuleSummaryIndex &moduleSummary; + + // These all return true if there was an error. + bool readSignature(); + bool enterTopLevelBlock(); + bool readModuleMetadata(); + +public: + Deserializer(MemoryBufferRef inputBuffer, ModuleSummaryIndex &moduleSummary) + : Cursor{inputBuffer}, moduleSummary(moduleSummary) {} + bool readModuleSummary(); +}; + +bool Deserializer::readSignature() { + for (unsigned char byte : MODULE_SUMMARY_SIGNATURE) { + if (Cursor.AtEndOfStream()) + return true; + if (auto maybeRead = Cursor.Read(8)) { + if (maybeRead.get() != byte) + return true; + } else { + return true; + } + } + return false; +} + +bool Deserializer::enterTopLevelBlock() { + // Read the BLOCKINFO_BLOCK, which contains metadata used when dumping + // the binary data with llvm-bcanalyzer. + { + auto next = Cursor.advance(); + if (!next) { + consumeError(next.takeError()); + return true; + } + + if (next->Kind != llvm::BitstreamEntry::SubBlock) + return true; + + if (next->ID != llvm::bitc::BLOCKINFO_BLOCK_ID) + return true; + + if (!Cursor.ReadBlockInfoBlock()) + return true; + } + + // Enters our subblock, which contains the actual summary information. + { + auto next = Cursor.advance(); + if (!next) { + consumeError(next.takeError()); + return true; + } + + if (next->Kind != llvm::BitstreamEntry::SubBlock) + return true; + + if (next->ID != RECORD_BLOCK_ID) + return true; + + if (auto err = Cursor.EnterSubBlock(RECORD_BLOCK_ID)) { + consumeError(std::move(err)); + return true; + } + } + return false; +} + +bool Deserializer::readModuleMetadata() { + Expected maybeEntry = Cursor.advance(); + if (!maybeEntry) + report_fatal_error("Should have next entry"); + + BitstreamEntry entry = maybeEntry.get(); + + if (entry.Kind != BitstreamEntry::Record) { + return true; + } + Scratch.clear(); + auto maybeKind = Cursor.readRecord(entry.ID, Scratch, &BlobData); + + if (!maybeKind) { + consumeError(maybeKind.takeError()); + return true; + } + + if (maybeKind.get() != record_block::MODULE_METADATA) { + return true; + } + + moduleSummary.setName(BlobData.str()); + + return false; +} + +static Optional getCallKind(unsigned kind) { + if (kind < unsigned(FunctionSummary::Call::KindTy::kindCount)) + return FunctionSummary::Call::KindTy(kind); + return None; +} + +static Optional getSlotKind(unsigned kind) { + if (kind < unsigned(FunctionSummary::Call::KindTy::kindCount)) + return VFuncSlot::KindTy(kind); + return None; +} + +bool Deserializer::readModuleSummary() { + using namespace record_block; + if (readSignature()) { + return true; + } + if (enterTopLevelBlock()) { + return true; + } + + if (readModuleMetadata()) { + return true; + } + + FunctionSummary *CurrentFunc; + Optional CurrentSlot; + + while (!Cursor.AtEndOfStream()) { + Scratch.clear(); + Expected entry = Cursor.advance(); + + if (!entry) { + // Success if there is no content + consumeError(entry.takeError()); + return false; + } + + if (entry->Kind == llvm::BitstreamEntry::EndBlock) { + Cursor.ReadBlockEnd(); + break; + } + + if (entry->Kind != llvm::BitstreamEntry::Record) { + llvm::report_fatal_error("Bad bitstream entry kind"); + } + + auto recordID = Cursor.readRecord(entry->ID, Scratch, &BlobData); + if (!recordID) { + consumeError(recordID.takeError()); + return true; + } + + switch (recordID.get()) { + case MODULE_METADATA: + // METADATA must appear at the beginning and is handled by + // readModuleSummaryMetadata(). + llvm::report_fatal_error("Unexpected MODULE_METADATA record"); + case FUNC_METADATA: { + GUID guid; + std::string name; + unsigned isLive, isPreserved; + bool shouldMerge = false; + + FunctionMetadataLayout::readRecord(Scratch, guid, isLive, isPreserved); + name = BlobData.str(); + if (auto summary = moduleSummary.getFunctionSummary(guid)) { + CurrentFunc = summary; + shouldMerge = true; + } else { + auto NewFS = std::make_unique(guid); + CurrentFunc = NewFS.get(); + moduleSummary.addFunctionSummary(std::move(NewFS)); + } + // Overwrite iff flags are true for merging function summaries of same functions. + if (!shouldMerge || isLive) { + CurrentFunc->setLive(isLive); + } + if (!shouldMerge || isPreserved) { + CurrentFunc->setPreserved(isPreserved); + } + if (!shouldMerge || !name.empty()) { + CurrentFunc->setName(name); + } + break; + } + case CALL_GRAPH_EDGE: { + // CALL_GRAPH_EDGE must follow a FUNC_METADATA. + if (!CurrentFunc) { + report_fatal_error("Unexpected CALL_GRAPH_EDGE record"); + } + unsigned callKindID; + GUID calleeGUID; + CallGraphEdgeLayout::readRecord(Scratch, callKindID, calleeGUID); + + auto callKind = getCallKind(callKindID); + if (!callKind) { + report_fatal_error("Bad call kind"); + } + FunctionSummary::Call call(calleeGUID, BlobData.str(), callKind.getValue()); + CurrentFunc->addCall(call); + break; + } + case VFUNC_METADATA: { + unsigned rawVFuncKind; + GUID vFuncGUID; + VFuncMetadataLayout::readRecord(Scratch, rawVFuncKind, vFuncGUID); + + auto Kind = getSlotKind(rawVFuncKind); + if (!Kind) { + report_fatal_error("Bad vfunc slot kind"); + } + CurrentSlot = VFuncSlot(Kind.getValue(), vFuncGUID); + break; + } + case VFUNC_IMPL: { + // VFUNC_IMPL must follow a VFUNC_METADATA. + if (!CurrentSlot) { + report_fatal_error("Unexpected METHOD_IMPL record"); + } + GUID implGUID; + VFuncImplLayout::readRecord(Scratch, implGUID); + moduleSummary.addImplementation(CurrentSlot.getValue(), implGUID); + break; + } + } + } + + return false; +} + +}; // namespace + +bool modulesummary::writeModuleSummaryIndex(const ModuleSummaryIndex &index, + DiagnosticEngine &diags, + StringRef path) { + return withOutputFile(diags, path, [&](raw_ostream &out) { + Serializer serializer; + serializer.emitHeader(); + serializer.emitModuleSummary(index); + serializer.write(out); + return false; + }); +} +bool modulesummary::loadModuleSummaryIndex(MemoryBufferRef inputBuffer, + ModuleSummaryIndex &moduleSummary) { + Deserializer deserializer(inputBuffer, moduleSummary); + return deserializer.readModuleSummary(); +} diff --git a/lib/Serialization/ModuleSummaryFormat.h b/lib/Serialization/ModuleSummaryFormat.h new file mode 100644 index 0000000000000..c689bd1917da4 --- /dev/null +++ b/lib/Serialization/ModuleSummaryFormat.h @@ -0,0 +1,71 @@ +//===--- ModuleSummaryFormat.h - Read and write module summary files ------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_SERIALIZATION_MODULE_SUMMARY_FILE_H +#define SWIFT_SERIALIZATION_MODULE_SUMMARY_FILE_H + +#include "llvm/Bitcode/RecordLayout.h" +#include + +namespace swift { + +namespace modulesummary { + +using llvm::BCBlob; +using llvm::BCFixed; +using llvm::BCRecordLayout; + +const unsigned char MODULE_SUMMARY_SIGNATURE[] = {'M', 'O', 'D', 'S'}; +const unsigned RECORD_BLOCK_ID = llvm::bitc::FIRST_APPLICATION_BLOCKID; + +namespace record_block { +enum { + MODULE_METADATA, + FUNC_METADATA, + CALL_GRAPH_EDGE, + VFUNC_METADATA, + VFUNC_IMPL, +}; + +using BCGUID = llvm::BCVBR<16>; + +using ModuleMetadataLayout = BCRecordLayout; + +using FunctionMetadataLayout = BCRecordLayout, // live + BCFixed<1>, // preserved + BCBlob // name (debug purpose) + >; +using CallGraphEdgeLayout = + BCRecordLayout, // call kind (direct, vtable or witness) + BCGUID, // callee func guid + BCBlob // name (debug purpose) + >; + +using VFuncMetadataLayout = + BCRecordLayout, // vfunc kind (vtable or witness) + BCGUID // vfunc guid + >; + +using VFuncImplLayout = BCRecordLayout; +} // namespace record_block +} // namespace modulesummary +} // namespace swift + +#endif diff --git a/lib/Serialization/ModuleSummaryIndexer.cpp b/lib/Serialization/ModuleSummaryIndexer.cpp new file mode 100644 index 0000000000000..7d3edf330b919 --- /dev/null +++ b/lib/Serialization/ModuleSummaryIndexer.cpp @@ -0,0 +1,270 @@ +#include "swift/SIL/SILDeclRef.h" +#include "swift/SIL/SILFunction.h" +#include "swift/SIL/SILModule.h" +#include "swift/Serialization/ModuleSummary.h" +#include "llvm/Support/MD5.h" +#include "llvm/Support/raw_ostream.h" + +#define DEBUG_TYPE "module-summary-index" + +using namespace swift; +using namespace modulesummary; + +GUID modulesummary::getGUIDFromUniqueName(llvm::StringRef Name) { + return llvm::MD5Hash(Name); +} + +namespace { +class FunctionSummaryIndexer { + const SILFunction &F; + std::unique_ptr TheSummary; + + void indexDirectFunctionCall(const SILFunction &Callee); + void indexIndirectFunctionCall(const SILDeclRef &Callee, + FunctionSummary::Call::KindTy Kind); + void indexInstruction(const SILInstruction *I); + +public: + FunctionSummaryIndexer(const SILFunction &F) : F(F) {} + void indexFunction(); + + std::unique_ptr takeSummary() { + return std::move(TheSummary); + } +}; + +void FunctionSummaryIndexer::indexDirectFunctionCall( + const SILFunction &Callee) { + GUID guid = getGUIDFromUniqueName(Callee.getName()); + FunctionSummary::Call call(guid, Callee.getName(), + FunctionSummary::Call::Direct); + TheSummary->addCall(call); +} + +void FunctionSummaryIndexer::indexIndirectFunctionCall( + const SILDeclRef &Callee, FunctionSummary::Call::KindTy Kind) { + StringRef mangledName = Callee.mangle(); + GUID guid = getGUIDFromUniqueName(mangledName); + FunctionSummary::Call call(guid, mangledName, Kind); + TheSummary->addCall(call); +} + +void FunctionSummaryIndexer::indexInstruction(const SILInstruction *I) { + if (auto *FRI = dyn_cast(I)) { + SILFunction *callee = FRI->getReferencedFunctionOrNull(); + assert(callee); + indexDirectFunctionCall(*callee); + return; + } + + if (auto *WMI = dyn_cast(I)) { + indexIndirectFunctionCall(WMI->getMember(), FunctionSummary::Call::Witness); + return; + } + + if (auto *MI = dyn_cast(I)) { + indexIndirectFunctionCall(MI->getMember(), FunctionSummary::Call::VTable); + return; + } + + if (auto *FRI = dyn_cast(I)) { + SILFunction *callee = FRI->getInitiallyReferencedFunction(); + assert(callee); + indexDirectFunctionCall(*callee); + return; + } + + if (auto *FRI = dyn_cast(I)) { + SILFunction *callee = FRI->getInitiallyReferencedFunction(); + assert(callee); + indexDirectFunctionCall(*callee); + return; + } + + if (auto *KPI = dyn_cast(I)) { + for (auto &component : KPI->getPattern()->getComponents()) { + component.visitReferencedFunctionsAndMethods( + [this](SILFunction *F) { + assert(F); + indexDirectFunctionCall(*F); + }, + [this](SILDeclRef method) { + auto decl = cast(method.getDecl()); + if (auto clas = dyn_cast(decl->getDeclContext())) { + indexIndirectFunctionCall(method, FunctionSummary::Call::VTable); + } else if (isa(decl->getDeclContext())) { + indexIndirectFunctionCall(method, FunctionSummary::Call::Witness); + } else { + llvm_unreachable( + "key path keyed by a non-class, non-protocol method"); + } + }); + } + } +} + +bool shouldPreserveFunction(const SILFunction &F) { + if (F.getRepresentation() == SILFunctionTypeRepresentation::ObjCMethod) { + return true; + } + if (F.hasCReferences()) { + return true; + } + if (F.isDynamicallyReplaceable()) { + return true; + } + return false; +} + +void FunctionSummaryIndexer::indexFunction() { + GUID guid = getGUIDFromUniqueName(F.getName()); + TheSummary = std::make_unique(guid); + TheSummary->setName(F.getName()); + for (auto &BB : F) { + for (auto &I : BB) { + indexInstruction(&I); + } + } + TheSummary->setPreserved(shouldPreserveFunction(F)); +} + +class ModuleSummaryIndexer { + std::unique_ptr TheSummary; + const SILModule &Mod; + void ensurePreserved(const SILFunction &F); + void ensurePreserved(const SILDeclRef &Ref, VFuncSlot::KindTy Kind); + void preserveKeyPathFunctions(const SILProperty &P); + void indexWitnessTable(const SILWitnessTable &WT); + void indexVTable(const SILVTable &VT); + +public: + ModuleSummaryIndexer(const SILModule &M) : Mod(M) {} + void indexModule(); + std::unique_ptr takeSummary() { + return std::move(TheSummary); + } +}; + +void ModuleSummaryIndexer::ensurePreserved(const SILFunction &F) { + GUID guid = getGUIDFromUniqueName(F.getName()); + auto FS = TheSummary->getFunctionSummary(guid); + assert(FS); + FS->setPreserved(true); +} + +static VFuncSlot createVFuncSlot(SILDeclRef VFuncRef, VFuncSlot::KindTy Kind) { + return VFuncSlot(Kind, getGUIDFromUniqueName(VFuncRef.mangle())); +} + +void ModuleSummaryIndexer::ensurePreserved(const SILDeclRef &Ref, + VFuncSlot::KindTy Kind) { + auto slot = createVFuncSlot(Ref, Kind); + auto Impls = TheSummary->getImplementations(slot); + if (Impls.empty()) + return; + + for (GUID Impl : Impls) { + auto FS = TheSummary->getFunctionSummary(Impl); + assert(FS); + FS->setPreserved(true); + } +} + +void ModuleSummaryIndexer::preserveKeyPathFunctions(const SILProperty &P) { + auto maybeComponent = P.getComponent(); + if (!maybeComponent) + return; + + KeyPathPatternComponent component = maybeComponent.getValue(); + component.visitReferencedFunctionsAndMethods( + [&](SILFunction *F) { ensurePreserved(*F); }, + [&](SILDeclRef method) { + auto decl = cast(method.getDecl()); + if (isa(decl->getDeclContext())) { + ensurePreserved(method, VFuncSlot::VTable); + } else if (isa(decl->getDeclContext())) { + ensurePreserved(method, VFuncSlot::Witness); + } else { + llvm_unreachable( + "key path keyed by a non-class, non-protocol method"); + } + }); +} + +void ModuleSummaryIndexer::indexWitnessTable(const SILWitnessTable &WT) { + auto isPossibllyUsedExternally = + WT.getDeclContext()->getParentModule() != Mod.getSwiftModule() || + WT.getProtocol()->getParentModule() != Mod.getSwiftModule(); + for (auto entry : WT.getEntries()) { + if (entry.getKind() != SILWitnessTable::Method) + continue; + + auto methodWitness = entry.getMethodWitness(); + auto Witness = methodWitness.Witness; + if (!Witness) + continue; + auto slot = createVFuncSlot(methodWitness.Requirement, VFuncSlot::Witness); + TheSummary->addImplementation(slot, + getGUIDFromUniqueName(Witness->getName())); + + if (isPossibllyUsedExternally) { + ensurePreserved(*Witness); + } + } +} + +void ModuleSummaryIndexer::indexVTable(const SILVTable &VT) { + + for (auto entry : VT.getEntries()) { + auto Impl = entry.getImplementation(); + if (entry.getMethod().kind == SILDeclRef::Kind::Deallocator || + entry.getMethod().kind == SILDeclRef::Kind::IVarDestroyer) { + // Destructors are preserved because they can be called from swift_release + // dynamically + ensurePreserved(*Impl); + } + auto methodModule = entry.getMethod().getDecl()->getModuleContext(); + auto isExternalMethod = methodModule != Mod.getSwiftModule(); + + if (entry.getKind() == SILVTableEntry::Override && isExternalMethod) { + ensurePreserved(*Impl); + } + auto slot = createVFuncSlot(entry.getMethod(), VFuncSlot::VTable); + TheSummary->addImplementation(slot, getGUIDFromUniqueName(Impl->getName())); + } +} + +void ModuleSummaryIndexer::indexModule() { + TheSummary = std::make_unique(); + auto moduleName = Mod.getSwiftModule()->getName().str(); + TheSummary->setName(moduleName); + + for (auto &F : Mod) { + FunctionSummaryIndexer indexer(F); + indexer.indexFunction(); + std::unique_ptr FS = indexer.takeSummary(); + FS->setPreserved(shouldPreserveFunction(F)); + TheSummary->addFunctionSummary(std::move(FS)); + } + + // FIXME: KeyPaths can be eliminated but now preserved conservatively. + for (auto &P : Mod.getPropertyList()) { + preserveKeyPathFunctions(P); + } + + for (auto &WT : Mod.getWitnessTableList()) { + indexWitnessTable(WT); + } + + for (auto VT : Mod.getVTables()) { + indexVTable(*VT); + } +} +}; // namespace + +std::unique_ptr +modulesummary::buildModuleSummaryIndex(SILModule &M) { + ModuleSummaryIndexer indexer(M); + indexer.indexModule(); + return indexer.takeSummary(); +} diff --git a/tools/driver/cross_module_opt_main.cpp b/tools/driver/cross_module_opt_main.cpp index 9a6b837f1a4dc..f54934eddb438 100644 --- a/tools/driver/cross_module_opt_main.cpp +++ b/tools/driver/cross_module_opt_main.cpp @@ -7,7 +7,7 @@ #include "swift/Option/Options.h" #include "swift/SIL/SILModule.h" #include "swift/SIL/TypeLowering.h" -#include "swift/Serialization/ModuleSummaryFile.h" +#include "swift/Serialization/ModuleSummary.h" #include "swift/Serialization/Validation.h" #include "swift/Subsystems.h" #include "llvm/ADT/ArrayRef.h" @@ -24,6 +24,7 @@ using namespace llvm::opt; using namespace swift; +using namespace modulesummary; static llvm::cl::opt LTOPrintLiveTrace("lto-print-live-trace", llvm::cl::init(""), @@ -36,11 +37,12 @@ static llvm::cl::opt static llvm::DenseSet computePreservedGUIDs(ModuleSummaryIndex *summary) { llvm::DenseSet Set(1); - Set.insert(getGUID("main")); - for (auto &pair : *summary) { - auto &info = pair.second; - if (info.TheSummary->isPreserved()) { - Set.insert(pair.first); + Set.insert(getGUIDFromUniqueName("main")); + for (auto FI = summary->functions_begin(), FE = summary->functions_end(); + FI != FE; ++FI) { + auto summary = FI->second.get(); + if (summary->isPreserved()) { + Set.insert(FI->first); } } return Set; @@ -85,6 +87,27 @@ class LivenessTrace { } }; +VFuncSlot createVFuncSlot(FunctionSummary::Call call) { + VFuncSlot::KindTy slotKind; + switch (call.getKind()) { + case FunctionSummary::Call::Witness: { + slotKind = VFuncSlot::Witness; + break; + } + case FunctionSummary::Call::VTable: { + slotKind = VFuncSlot::VTable; + break; + } + case FunctionSummary::Call::Direct: { + llvm_unreachable("Can't get slot for static call"); + } + case FunctionSummary::Call::kindCount: { + llvm_unreachable("impossible"); + } + } + return VFuncSlot(slotKind, call.getCallee()); +} + void markDeadSymbols(ModuleSummaryIndex &summary, llvm::DenseSet &PreservedGUIDs) { SmallVector, 8> Worklist; @@ -98,42 +121,45 @@ void markDeadSymbols(ModuleSummaryIndex &summary, llvm::DenseSet &Preserve while (!Worklist.empty()) { auto trace = Worklist.pop_back_val(); - auto maybePair = summary.getFunctionInfo(trace->guid); - if (!maybePair) { + auto maybeSummary = summary.getFunctionSummary(trace->guid); + if (!maybeSummary) { llvm_unreachable("Bad GUID"); } - auto pair = maybePair.getValue(); - auto FS = pair.first; - trace->setName(pair.second); - if (LTOPrintLiveTrace == pair.second) { - dumpTarget = trace; + auto FS = maybeSummary; + if (!FS->getName().empty()) { + trace->setName(FS->getName()); + if (LTOPrintLiveTrace == FS->getName()) { + dumpTarget = trace; + } } if (FS->isLive()) continue; - LLVM_DEBUG(llvm::dbgs() << "Mark " << pair.second << " as live\n"); + if (!FS->getName().empty()) { + LLVM_DEBUG(llvm::dbgs() << "Mark " << FS->getName() << " as live\n"); + } else { + LLVM_DEBUG(llvm::dbgs() << "Mark (" << FS->getGUID() << ") as live\n"); + } FS->setLive(true); LiveSymbols++; for (auto Call : FS->calls()) { switch (Call.getKind()) { - case FunctionSummary::EdgeTy::Kind::Static: { + case FunctionSummary::Call::Direct: { Worklist.push_back(std::make_shared( trace, Call.getCallee(), LivenessTrace::StaticReferenced)); continue; } - case FunctionSummary::EdgeTy::Kind::Witness: - case FunctionSummary::EdgeTy::Kind::VTable: { - auto Impls = summary.getImplementations(Call.slot()); - if (!Impls) { - continue; - } - for (auto Impl : Impls.getValue()) { + case FunctionSummary::Call::Witness: + case FunctionSummary::Call::VTable: { + VFuncSlot slot = createVFuncSlot(Call); + auto Impls = summary.getImplementations(slot); + for (auto Impl : Impls) { Worklist.push_back(std::make_shared( trace, Impl, LivenessTrace::IndirectReferenced)); } break; } - case FunctionSummary::EdgeTy::Kind::kindCount: + case FunctionSummary::Call::kindCount: llvm_unreachable("impossible"); } } @@ -177,12 +203,12 @@ int cross_module_opt_main(ArrayRef Args, const char *Argv0, llvm::report_fatal_error("Invalid module summary"); } - TheSummary->setModuleName("combined"); + TheSummary->setName("combined"); auto PreservedGUIDs = computePreservedGUIDs(TheSummary.get()); markDeadSymbols(*TheSummary.get(), PreservedGUIDs); - modulesummary::emitModuleSummaryIndex(*TheSummary, Instance.getDiags(), - OutputFilename); + modulesummary::writeModuleSummaryIndex(*TheSummary, Instance.getDiags(), + OutputFilename); return 0; } From 60e8b9398e910ac7c79eba1e5480e73fae48f558 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Wed, 12 Aug 2020 13:29:26 +0900 Subject: [PATCH 40/77] [Protoype] Port testing tool --- tools/CMakeLists.txt | 1 + .../swift-module-summary-test/CMakeLists.txt | 10 + .../swift-module-summary-test.cpp | 197 ++++++++++++++++++ 3 files changed, 208 insertions(+) create mode 100644 tools/swift-module-summary-test/CMakeLists.txt create mode 100644 tools/swift-module-summary-test/swift-module-summary-test.cpp diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 8eafc0873899b..b0f0a18cfb709 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -32,6 +32,7 @@ add_swift_tool_subdirectory(swift-api-digester) add_swift_tool_subdirectory(swift-ast-script) add_swift_tool_subdirectory(swift-syntax-test) add_swift_tool_subdirectory(swift-refactor) +add_swift_tool_subdirectory(swift-module-summary-test) if(SWIFT_BUILD_SYNTAXPARSERLIB) add_swift_tool_subdirectory(libSwiftSyntaxParser) add_swift_tool_subdirectory(swift-syntax-parser-test) diff --git a/tools/swift-module-summary-test/CMakeLists.txt b/tools/swift-module-summary-test/CMakeLists.txt new file mode 100644 index 0000000000000..26959c266cf58 --- /dev/null +++ b/tools/swift-module-summary-test/CMakeLists.txt @@ -0,0 +1,10 @@ +add_swift_host_tool(swift-module-summary-test + swift-module-summary-test.cpp + LLVM_LINK_COMPONENTS + Support + SWIFT_COMPONENT tools +) + +target_link_libraries(swift-module-summary-test + PRIVATE + swiftSerialization) diff --git a/tools/swift-module-summary-test/swift-module-summary-test.cpp b/tools/swift-module-summary-test/swift-module-summary-test.cpp new file mode 100644 index 0000000000000..f30ff8e276bf9 --- /dev/null +++ b/tools/swift-module-summary-test/swift-module-summary-test.cpp @@ -0,0 +1,197 @@ +//===--- swift-module-summary-test.cpp - Test util for C parser library ---===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// Testing utility for the C API of the parser library. +// +//===----------------------------------------------------------------------===// + +#include "swift/AST/FileSystem.h" +#include "swift/Basic/LLVM.h" +#include "swift/Basic/LLVMInitialize.h" +#include "swift/Serialization/ModuleSummary.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/YAMLParser.h" +#include "llvm/Support/YAMLTraits.h" + +using namespace swift; +using namespace modulesummary; + +enum class ActionType : unsigned { + None, + BinaryToYAML, + YAMLToBinary, +}; + +namespace options { + +static llvm::cl::OptionCategory Category("swift-module-summary-test Options"); + +static llvm::cl::opt + InputFilename(llvm::cl::Positional, llvm::cl::desc(""), + llvm::cl::init("-"), llvm::cl::value_desc("filename")); + +static llvm::cl::opt + OutputFilename("o", llvm::cl::desc("Override output filename"), + llvm::cl::value_desc("filename")); + +static llvm::cl::opt + Action(llvm::cl::desc("Mode:"), llvm::cl::init(ActionType::None), + llvm::cl::cat(Category), + llvm::cl::values( + clEnumValN(ActionType::BinaryToYAML, "to-yaml", + "Convert new binary .swiftdeps format to YAML"), + clEnumValN(ActionType::YAMLToBinary, "from-yaml", + "Convert YAML to new binary .swiftdeps format"))); + +} // namespace options + +LLVM_YAML_DECLARE_MAPPING_TRAITS(modulesummary::ModuleSummaryIndex) +LLVM_YAML_DECLARE_MAPPING_TRAITS(modulesummary::FunctionSummary) +LLVM_YAML_DECLARE_MAPPING_TRAITS(modulesummary::FunctionSummary::Call) +LLVM_YAML_IS_SEQUENCE_VECTOR(modulesummary::FunctionSummary::Call) +LLVM_YAML_DECLARE_ENUM_TRAITS(modulesummary::FunctionSummary::Call::KindTy) + +namespace llvm { +namespace yaml { + +template <> struct MappingTraits> { + static void mapping(IO &io, std::unique_ptr &Ptr) { + if (!Ptr) { + Ptr.reset(new FunctionSummary()); + } + MappingTraits::mapping(io, *Ptr.get()); + } +}; + +void ScalarEnumerationTraits::enumeration( + IO &io, FunctionSummary::Call::KindTy &V) { + using Kind = FunctionSummary::Call::KindTy; + io.enumCase(V, "direct", Kind::Direct); + io.enumCase(V, "vtable", Kind::VTable); + io.enumCase(V, "witness", Kind::Witness); +} + +void MappingTraits::mapping(IO &io, + FunctionSummary::Call &V) { + io.mapRequired("callee_name", V.Name); + io.mapRequired("callee_guid", V.Callee); + io.mapRequired("kind", V.Kind); +} + +void MappingTraits::mapping(IO &io, FunctionSummary &V) { + io.mapRequired("name", V.Name); + io.mapRequired("guid", V.Guid); + io.mapRequired("live", V.Flags.Live); + io.mapRequired("preserved", V.Flags.Preserved); + io.mapRequired("calls", V.CallGraphEdgeList); +} + +template <> +struct CustomMappingTraits { + static void inputOne(IO &io, StringRef Key, + FunctionSummaryMapTy &V) { + GUID KeyInt; + if (Key.getAsInteger(0, KeyInt)) { + io.setError("key not an integer"); + return; + } + io.mapRequired(Key.str().c_str(), V[KeyInt]); + } + static void output(IO &io, FunctionSummaryMapTy &V) { + for (auto &P : V) + io.mapRequired(llvm::utostr(P.first).c_str(), P.second); + } +}; + +template <> +struct CustomMappingTraits { + static void inputOne(IO &io, StringRef Key, VFuncToImplsMapTy &V) { + GUID KeyInt; + if (Key.getAsInteger(0, KeyInt)) { + io.setError("key not an integer"); + return; + } + io.mapRequired(Key.str().c_str(), V[KeyInt]); + } + static void output(IO &io, VFuncToImplsMapTy &V) { + for (auto &P : V) + io.mapRequired(llvm::utostr(P.first).c_str(), P.second); + } +}; + +void MappingTraits::mapping(IO &io, ModuleSummaryIndex &V) { + io.mapRequired("module_name", V.Name); + io.mapRequired("functions", V.FunctionSummaryMap); + io.mapRequired("witness_tables", V.WitnessTableMethodMap); + io.mapRequired("vtables", V.VTableMethodMap); +} +} // namespace yaml +} // namespace llvm + +int main(int argc, char *argv[]) { + PROGRAM_START(argc, argv); + llvm::cl::ParseCommandLineOptions(argc, argv, "Swift Module Summary Test\n"); + + StringRef fname = options::InputFilename; + SourceManager sourceMgr; + DiagnosticEngine diags(sourceMgr); + + auto fileBufOrErr = llvm::MemoryBuffer::getFile(fname); + if (!fileBufOrErr) { + llvm::errs() << "error opening file '" << fname + << "': " << fileBufOrErr.getError().message(); + return 1; + } + + switch (options::Action) { + case ActionType::None: { + llvm::errs() << "action required\n"; + llvm::cl::PrintHelpMessage(); + return 1; + } + case ActionType::BinaryToYAML: { + modulesummary::ModuleSummaryIndex summary; + modulesummary::loadModuleSummaryIndex(fileBufOrErr.get()->getMemBufferRef(), + summary); + + bool hadError = withOutputFile(diags, options::OutputFilename, + [&](llvm::raw_pwrite_stream &out) { + out << "# Module-summary v0\n"; + llvm::yaml::Output yamlWriter(out); + yamlWriter << summary; + return false; + }); + + if (hadError) { + llvm::errs() << "Failed to write YAML swiftdeps\n"; + } + break; + } + case ActionType::YAMLToBinary: + ModuleSummaryIndex summary; + llvm::yaml::Input yamlReader(fileBufOrErr.get()->getMemBufferRef(), + nullptr); + yamlReader >> summary; + if (yamlReader.error()) { + llvm::errs() << "Failed to parse YAML swiftdeps\n"; + return 1; + } + + if (writeModuleSummaryIndex(summary, diags, options::OutputFilename)) { + llvm::errs() << "Failed to write binary module summary\n"; + return 1; + } + break; + } + return 0; +} From 48bf5bfefe357f48b4315abeae826a210481c248 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Thu, 13 Aug 2020 18:38:50 +0900 Subject: [PATCH 41/77] [Cherry-pick me] Use SILInstructionVisitor pattern --- lib/Serialization/ModuleSummaryIndexer.cpp | 108 +++++++++++---------- 1 file changed, 55 insertions(+), 53 deletions(-) diff --git a/lib/Serialization/ModuleSummaryIndexer.cpp b/lib/Serialization/ModuleSummaryIndexer.cpp index 7d3edf330b919..b3a7f42dc1ea2 100644 --- a/lib/Serialization/ModuleSummaryIndexer.cpp +++ b/lib/Serialization/ModuleSummaryIndexer.cpp @@ -1,6 +1,7 @@ #include "swift/SIL/SILDeclRef.h" #include "swift/SIL/SILFunction.h" #include "swift/SIL/SILModule.h" +#include "swift/SIL/SILVisitor.h" #include "swift/Serialization/ModuleSummary.h" #include "llvm/Support/MD5.h" #include "llvm/Support/raw_ostream.h" @@ -15,17 +16,25 @@ GUID modulesummary::getGUIDFromUniqueName(llvm::StringRef Name) { } namespace { -class FunctionSummaryIndexer { - const SILFunction &F; +class FunctionSummaryIndexer : public SILInstructionVisitor { + friend SILInstructionVisitor; + + SILFunction &F; std::unique_ptr TheSummary; void indexDirectFunctionCall(const SILFunction &Callee); void indexIndirectFunctionCall(const SILDeclRef &Callee, FunctionSummary::Call::KindTy Kind); - void indexInstruction(const SILInstruction *I); + void visitFunctionRefInst(FunctionRefInst *FRI); + void visitWitnessMethodInst(WitnessMethodInst *WMI); + void visitMethodInst(MethodInst *MI); + void visitDynamicFunctionRefInst(DynamicFunctionRefInst *FRI); + void visitPreviousDynamicFunctionRefInst(PreviousDynamicFunctionRefInst *FRI); + void visitKeyPathInst(KeyPathInst *KPI); + void visitSILInstruction(SILInstruction *I) {} public: - FunctionSummaryIndexer(const SILFunction &F) : F(F) {} + FunctionSummaryIndexer(SILFunction &F) : F(F) {} void indexFunction(); std::unique_ptr takeSummary() { @@ -49,57 +58,50 @@ void FunctionSummaryIndexer::indexIndirectFunctionCall( TheSummary->addCall(call); } -void FunctionSummaryIndexer::indexInstruction(const SILInstruction *I) { - if (auto *FRI = dyn_cast(I)) { - SILFunction *callee = FRI->getReferencedFunctionOrNull(); - assert(callee); - indexDirectFunctionCall(*callee); - return; - } +void FunctionSummaryIndexer::visitFunctionRefInst(FunctionRefInst *FRI) { + SILFunction *callee = FRI->getReferencedFunctionOrNull(); + assert(callee); + indexDirectFunctionCall(*callee); +} - if (auto *WMI = dyn_cast(I)) { - indexIndirectFunctionCall(WMI->getMember(), FunctionSummary::Call::Witness); - return; - } +void FunctionSummaryIndexer::visitWitnessMethodInst(WitnessMethodInst *WMI) { + indexIndirectFunctionCall(WMI->getMember(), FunctionSummary::Call::Witness); +} - if (auto *MI = dyn_cast(I)) { - indexIndirectFunctionCall(MI->getMember(), FunctionSummary::Call::VTable); - return; - } +void FunctionSummaryIndexer::visitMethodInst(MethodInst *MI) { + indexIndirectFunctionCall(MI->getMember(), FunctionSummary::Call::VTable); +} - if (auto *FRI = dyn_cast(I)) { - SILFunction *callee = FRI->getInitiallyReferencedFunction(); - assert(callee); - indexDirectFunctionCall(*callee); - return; - } +void FunctionSummaryIndexer::visitDynamicFunctionRefInst(DynamicFunctionRefInst *FRI) { + SILFunction *callee = FRI->getInitiallyReferencedFunction(); + assert(callee); + indexDirectFunctionCall(*callee); +} - if (auto *FRI = dyn_cast(I)) { - SILFunction *callee = FRI->getInitiallyReferencedFunction(); - assert(callee); - indexDirectFunctionCall(*callee); - return; - } +void FunctionSummaryIndexer::visitPreviousDynamicFunctionRefInst(PreviousDynamicFunctionRefInst *FRI) { + SILFunction *callee = FRI->getInitiallyReferencedFunction(); + assert(callee); + indexDirectFunctionCall(*callee); +} - if (auto *KPI = dyn_cast(I)) { - for (auto &component : KPI->getPattern()->getComponents()) { - component.visitReferencedFunctionsAndMethods( - [this](SILFunction *F) { - assert(F); - indexDirectFunctionCall(*F); - }, - [this](SILDeclRef method) { - auto decl = cast(method.getDecl()); - if (auto clas = dyn_cast(decl->getDeclContext())) { - indexIndirectFunctionCall(method, FunctionSummary::Call::VTable); - } else if (isa(decl->getDeclContext())) { - indexIndirectFunctionCall(method, FunctionSummary::Call::Witness); - } else { - llvm_unreachable( - "key path keyed by a non-class, non-protocol method"); - } - }); - } +void FunctionSummaryIndexer::visitKeyPathInst(KeyPathInst *KPI) { + for (auto &component : KPI->getPattern()->getComponents()) { + component.visitReferencedFunctionsAndMethods( + [this](SILFunction *F) { + assert(F); + indexDirectFunctionCall(*F); + }, + [this](SILDeclRef method) { + auto decl = cast(method.getDecl()); + if (auto clas = dyn_cast(decl->getDeclContext())) { + indexIndirectFunctionCall(method, FunctionSummary::Call::VTable); + } else if (isa(decl->getDeclContext())) { + indexIndirectFunctionCall(method, FunctionSummary::Call::Witness); + } else { + llvm_unreachable( + "key path keyed by a non-class, non-protocol method"); + } + }); } } @@ -122,7 +124,7 @@ void FunctionSummaryIndexer::indexFunction() { TheSummary->setName(F.getName()); for (auto &BB : F) { for (auto &I : BB) { - indexInstruction(&I); + visit(&I); } } TheSummary->setPreserved(shouldPreserveFunction(F)); @@ -130,7 +132,7 @@ void FunctionSummaryIndexer::indexFunction() { class ModuleSummaryIndexer { std::unique_ptr TheSummary; - const SILModule &Mod; + SILModule &Mod; void ensurePreserved(const SILFunction &F); void ensurePreserved(const SILDeclRef &Ref, VFuncSlot::KindTy Kind); void preserveKeyPathFunctions(const SILProperty &P); @@ -138,7 +140,7 @@ class ModuleSummaryIndexer { void indexVTable(const SILVTable &VT); public: - ModuleSummaryIndexer(const SILModule &M) : Mod(M) {} + ModuleSummaryIndexer(SILModule &M) : Mod(M) {} void indexModule(); std::unique_ptr takeSummary() { return std::move(TheSummary); From 00e266634defcd63d36d42a34f5889d0d727b8c8 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Fri, 14 Aug 2020 01:06:24 +0900 Subject: [PATCH 42/77] [Module Indexer] Index type reference information --- include/swift/Serialization/ModuleSummary.h | 21 +++ lib/Serialization/ModuleSummaryIndexer.cpp | 171 ++++++++++++++++++++ 2 files changed, 192 insertions(+) diff --git a/include/swift/Serialization/ModuleSummary.h b/include/swift/Serialization/ModuleSummary.h index 36350c84c3581..dacf5a2eaa0a6 100644 --- a/include/swift/Serialization/ModuleSummary.h +++ b/include/swift/Serialization/ModuleSummary.h @@ -65,6 +65,13 @@ class FunctionSummary { std::string getName() const { return Name; }; }; + struct TypeRef { + /// The type identity. + GUID Guid; + /// The symbol name of the type only for debug and test purposes. + std::string Name; + }; + /// Function state flags struct FlagsTy { /// In per-module summary, always false. @@ -76,6 +83,7 @@ class FunctionSummary { }; using CallGraphEdgeListTy = std::vector; + using TypeRefListTy = std::vector; private: // For import/export @@ -87,6 +95,8 @@ class FunctionSummary { FlagsTy Flags; /// List of Call from this function. CallGraphEdgeListTy CallGraphEdgeList; + /// List of TypeRef from this function. + TypeRefListTy TypeRefList; /// The symbol name of the function only for debug and test purposes. std::string Name; @@ -101,6 +111,11 @@ class FunctionSummary { /// Return the list of Call from this function ArrayRef calls() const { return CallGraphEdgeList; } + /// TBD + void addTypeRef(TypeRef ref) { TypeRefList.push_back(ref); } + /// TBD + ArrayRef typeRefs() const { return TypeRefList; } + bool isLive() const { return Flags.Live; } void setLive(bool Live) { Flags.Live = Live; } @@ -132,6 +147,7 @@ struct VFuncSlot { using FunctionSummaryMapTy = std::map>; using VFuncToImplsMapTy = std::map>; +using UsedTypeListTy = std::vector; /// Module summary that consists of function summaries and virtual function /// tables. @@ -146,6 +162,9 @@ class ModuleSummaryIndex { VFuncToImplsMapTy WitnessTableMethodMap; /// Map from virtual function GUID to list of implementations for vtables. VFuncToImplsMapTy VTableMethodMap; + /// In per-module summary, always empty map. + /// In combined summary, map from type GUID to liveness of the type. + UsedTypeListTy UsedTypeList; /// The symbol name of the module. std::string Name; @@ -215,6 +234,8 @@ class ModuleSummaryIndex { return ArrayRef(found->second); } + void markUsedType(GUID typeGUID) { UsedTypeList.push_back(typeGUID); } + const VFuncToImplsMapTy &getWitnessTableMethodMap() const { return WitnessTableMethodMap; } diff --git a/lib/Serialization/ModuleSummaryIndexer.cpp b/lib/Serialization/ModuleSummaryIndexer.cpp index b3a7f42dc1ea2..0cc4026e4356f 100644 --- a/lib/Serialization/ModuleSummaryIndexer.cpp +++ b/lib/Serialization/ModuleSummaryIndexer.cpp @@ -1,3 +1,4 @@ +#include "swift/AST/ASTMangler.h" #include "swift/SIL/SILDeclRef.h" #include "swift/SIL/SILFunction.h" #include "swift/SIL/SILModule.h" @@ -26,12 +27,53 @@ class FunctionSummaryIndexer : public SILInstructionVisitoraddCall(call); } +void FunctionSummaryIndexer::indexUseOfType(CanType type) { + Mangle::ASTMangler mangler; + type.visit([&](Type t) { + std::string mangled = mangler.mangleTypeWithoutPrefix(t); + GUID guid = getGUIDFromUniqueName(mangled); + TheSummary->addTypeRef({guid, mangled}); + }); +} + +void FunctionSummaryIndexer::visitAllocExistentialBoxInst( + AllocExistentialBoxInst *AEBI) { + indexUseOfType(AEBI->getFormalConcreteType()); +} + +void FunctionSummaryIndexer::visitAllocGlobalInst(AllocGlobalInst *AGI) { + indexUseOfType(AGI->getReferencedGlobal()->getLoweredType().getASTType()); +} + +void FunctionSummaryIndexer::visitAllocRefInst(AllocRefInst *ARI) { + indexUseOfType(ARI->getType().getASTType()); +} +void FunctionSummaryIndexer::visitAllocStackInst(AllocStackInst *ASI) { + indexUseOfType(ASI->getType().getASTType()); +} +void FunctionSummaryIndexer::visitAllocValueBufferInst( + AllocValueBufferInst *AVBI) { + indexUseOfType(AVBI->getType().getASTType()); +} +void FunctionSummaryIndexer::visitApplyInst(ApplyInst *AI) { + indexUseOfType(AI->getSubstCalleeType()); +} +void FunctionSummaryIndexer::visitBeginApplyInst(BeginApplyInst *BAI) { + indexUseOfType(BAI->getSubstCalleeType()); +} +void FunctionSummaryIndexer::visitBuiltinInst(BuiltinInst *BI) { + // FIXME: Need to index substitution map? +} +void FunctionSummaryIndexer::visitCheckedCastBranchInst( + CheckedCastBranchInst *CCBI) { + indexUseOfType(CCBI->getSourceFormalType()); + indexUseOfType(CCBI->getTargetFormalType()); +} +void FunctionSummaryIndexer::visitCheckedCastAddrBranchInst( + CheckedCastAddrBranchInst *CCABI) { + indexUseOfType(CCABI->getSourceFormalType()); + indexUseOfType(CCABI->getTargetFormalType()); +} +void FunctionSummaryIndexer::visitCheckedCastValueBranchInst( + CheckedCastValueBranchInst *CCVBI) { + indexUseOfType(CCVBI->getSourceFormalType()); + indexUseOfType(CCVBI->getTargetFormalType()); +} +void FunctionSummaryIndexer::visitCopyAddrInst(CopyAddrInst *CAI) { + indexUseOfType(CAI->getSrc()->getType().getASTType()); + indexUseOfType(CAI->getDest()->getType().getASTType()); +} +void FunctionSummaryIndexer::visitCopyValueInst(CopyValueInst *CVI) { + indexUseOfType(CVI->getOperand()->getType().getASTType()); +} +void FunctionSummaryIndexer::visitDestroyAddrInst(DestroyAddrInst *DAI) { + indexUseOfType(DAI->getOperand()->getType().getASTType()); +} +void FunctionSummaryIndexer::visitDestroyValueInst(DestroyValueInst *DVI) { + indexUseOfType(DVI->getOperand()->getType().getASTType()); +} +void FunctionSummaryIndexer::visitGlobalAddrInst(GlobalAddrInst *GAI) { + indexUseOfType(GAI->getReferencedGlobal()->getLoweredType().getASTType()); +} +void FunctionSummaryIndexer::visitGlobalValueInst(GlobalValueInst *GVI) { + indexUseOfType(GVI->getReferencedGlobal()->getLoweredType().getASTType()); +} +void FunctionSummaryIndexer::visitInitEnumDataAddrInst( + InitEnumDataAddrInst *IEDAI) { + indexUseOfType(IEDAI->getOperand()->getType().getASTType()); +} +void FunctionSummaryIndexer::visitInjectEnumAddrInst(InjectEnumAddrInst *IEAI) { + indexUseOfType(IEAI->getOperand()->getType().getASTType()); +} +void FunctionSummaryIndexer::visitInitExistentialAddrInst( + InitExistentialAddrInst *IEAI) { + indexUseOfType(IEAI->getFormalConcreteType()); +} +void FunctionSummaryIndexer::visitInitExistentialMetatypeInst( + InitExistentialMetatypeInst *IEMI) { + indexUseOfType(IEMI->getOperand()->getType().getASTType()); +} +void FunctionSummaryIndexer::visitInitExistentialRefInst( + InitExistentialRefInst *IERI) { + indexUseOfType(IERI->getFormalConcreteType()); +} +void FunctionSummaryIndexer::visitInitExistentialValueInst( + InitExistentialValueInst *IEVI) { + indexUseOfType(IEVI->getFormalConcreteType()); +} +void FunctionSummaryIndexer::visitMetatypeInst(MetatypeInst *MI) { + indexUseOfType(MI->getType().getASTType()); +} +void FunctionSummaryIndexer::visitPartialApplyInst(PartialApplyInst *PAI) { + indexUseOfType(PAI->getSubstCalleeType()); +} +void FunctionSummaryIndexer::visitSelectEnumAddrInst(SelectEnumAddrInst *SEAI) { + indexUseOfType(SEAI->getEnumOperand()->getType().getASTType()); +} +void FunctionSummaryIndexer::visitStructElementAddrInst( + StructElementAddrInst *SEAI) { + indexUseOfType(SEAI->getOperand()->getType().getASTType()); +} +void FunctionSummaryIndexer::visitTryApplyInst(TryApplyInst *TAI) { + indexUseOfType(TAI->getSubstCalleeType()); +} +void FunctionSummaryIndexer::visitTupleElementAddrInst( + TupleElementAddrInst *TEAI) { + indexUseOfType(TEAI->getOperand()->getType().getASTType()); +} +void FunctionSummaryIndexer::visitUnconditionalCheckedCastInst( + UnconditionalCheckedCastInst *UCCI) { + indexUseOfType(UCCI->getSourceFormalType()); + indexUseOfType(UCCI->getTargetFormalType()); +} +void FunctionSummaryIndexer::visitUnconditionalCheckedCastAddrInst( + UnconditionalCheckedCastAddrInst *UCCAI) { + indexUseOfType(UCCAI->getSourceFormalType()); + indexUseOfType(UCCAI->getTargetFormalType()); +} +void FunctionSummaryIndexer::visitUncheckedTakeEnumDataAddrInst( + UncheckedTakeEnumDataAddrInst *UTEDAI) { + indexUseOfType(UTEDAI->getOperand()->getType().getASTType()); +} + void FunctionSummaryIndexer::visitFunctionRefInst(FunctionRefInst *FRI) { SILFunction *callee = FRI->getReferencedFunctionOrNull(); assert(callee); From c58fb6d693e0f54186fd817e59f1fd8df61633c1 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Fri, 14 Aug 2020 01:20:20 +0900 Subject: [PATCH 43/77] [Cleanup] Remove flagile test case --- test/Serialization/module-summary.swift | 120 ------------------------ 1 file changed, 120 deletions(-) delete mode 100644 test/Serialization/module-summary.swift diff --git a/test/Serialization/module-summary.swift b/test/Serialization/module-summary.swift deleted file mode 100644 index 8a3db3eb60d3a..0000000000000 --- a/test/Serialization/module-summary.swift +++ /dev/null @@ -1,120 +0,0 @@ -// RUN: %empty-directory(%t) -// RUN: %target-swift-frontend -emit-module %S/Inputs/module1.swift -emit-module-summary-path %t/module1.swiftmodule.summary -parse-as-library -o %t -// RUN: %target-swift-frontend -emit-module %S/Inputs/module2.swift -emit-module-summary-path %t/module2.swiftmodule.summary -parse-as-library -I %t -o %t -// RUN: %target-swift-frontend -emit-sil %s -emit-module-summary-path %t/module-summary.swiftmodule.summary -I %t > /dev/null -// RUN: llvm-bcanalyzer -dump %t/module-summary.swiftmodule.summary | %FileCheck %s --check-prefix MAIN-CHECK - -// MAIN-CHECK: blob data = '$s4main10publicFuncyyF' - - -// Ensure that call graph edge has correct function guid -// MAIN-CHECK: blob data = '$s7module20A4FuncSiyF' -// MAIN-CHECK: blob data = 'main' -// MAIN-CHECK-NEXT: -// MAIN-CHECK-NEXT: -// MAIN-CHECK-NEXT: -// MAIN-CHECK-NEXT: - - -// MAIN-CHECK: blob data = '$s4main9callTwiceyyF' -// MAIN-CHECK-NEXT: -// MAIN-CHECK-NEXT: -// MAIN-CHECK-NEXT: - -// RUN: llvm-bcanalyzer -dump %t/module2.swiftmodule.summary | %FileCheck %s --check-prefix TABLE-CHECK - -// TABLE-CHECK-DAG: blob data = '$s7module29Concrete2V7module11PAadEP15defaultProvidedyyFTW' -// TABLE-CHECK-DAG: blob data = '$s7module29Concrete2V7module11PAadEP12memberMethodyyFTW' - -// TABLE-CHECK: blob data = '$s7module24usePyyx7module11PRzlF' -// TABLE-CHECK-NEXT: -// TABLE-CHECK-NEXT: - -// TABLE-CHECK-DAG: blob data = '$s7module29Concrete1V7module11PAadEP15defaultProvidedyyFTW' -// TABLE-CHECK-DAG: blob data = '$s7module29Concrete1V7module11PAadEP12memberMethodyyFTW' - -// TABLE-CHECK: -// TABLE-CHECK-NEXT: -// TABLE-CHECK-NEXT: -// TABLE-CHECK-NEXT: - -// TABLE-CHECK: -// TABLE-CHECK-NEXT: -// TABLE-CHECK-NEXT: -// TABLE-CHECK-NEXT: - - -// RUN: %swift_frontend_plain -cross-module-opt %t/module-summary.swiftmodule.summary %t/module1.swiftmodule.summary %t/module2.swiftmodule.summary -o %t/merged-module.summary -// RUN: llvm-bcanalyzer -dump %t/merged-module.summary | %FileCheck %s --check-prefix MERGED-CHECK - -// MERGED-CHECK: blob data = '$s7module10A4FuncSiyF' -// MERGED-CHECK-NEXT: - -// MERGED-CHECK: blob data = '$s7module20A4FuncSiyF' -// MERGED-CHECK-NEXT: -// MERGED-CHECK-NEXT: - -// RUN: llvm-bcanalyzer -dump %t/merged-module.summary | %FileCheck %s --check-prefix LIVE-CHECK - -// LIVE-CHECK-DAG: blob data = '$s4main10publicFuncyyF' -// LIVE-CHECK-DAG: blob data = '$s4main3fooyyF' -// LIVE-CHECK-DAG: blob data = 'main' -// LIVE-CHECK-DAG: blob data = '$s4main3baryySiF' - -// RUN: %target-swift-frontend -emit-sil %s -I %t -o %t/main.sil -// RUN: %target-sil-opt -emit-sorted-sil %t/main.sil -module-summary-path %t/merged-module.summary --sil-cross-deadfuncelim -I %t | %FileCheck %s --check-prefix DEADFUNC-MAIN-CHECK -// RUN: %target-swift-frontend -emit-sil %s -module-summary-path %t/merged-module.summary -I %t -O | %FileCheck %s --check-prefix DEADFUNC-MAIN-CHECK -// DEADFUNC-MAIN-CHECK-DAG: @$s4main10publicFuncyyF -// DEADFUNC-MAIN-CHECK-DAG: @$s4main3baryySiF -// DEADFUNC-MAIN-CHECK-DAG: @main - -// DEADFUNC-MAIN-CHECK-NOT: @$s4main16callExternalFuncyyF -// DEADFUNC-MAIN-CHECK-NOT: @$sSi2eeoiySbSi_SitFZ -// DEADFUNC-MAIN-CHECK-NOT: @$s7module20A4FuncSiyF -// DEADFUNC-MAIN-CHECK-NOT: @$sSi22_builtinIntegerLiteralSiBI_tcfC -// DEADFUNC-MAIN-CHECK-NOT: @$s4main9callTwiceyyF - - -// RUN: %target-swift-frontend -emit-sil %S/Inputs/module2.swift -parse-as-library -module-summary-path %t/merged-module.summary -I %t -O | %FileCheck %s --check-prefix DEADFUNC-MODULE2-CHECK - -// DEADFUNC-MODULE2-CHECK-DAG: $s7module29Concrete1V12memberMethodyyF -// DEADFUNC-MODULE2-CHECK-DAG: $s7module29Concrete1V7module11PAadEP12memberMethodyyFTW -// DEADFUNC-MODULE2-CHECK-DAG: $s7module29Concrete2V12memberMethodyyF -// DEADFUNC-MODULE2-CHECK-DAG: $s7module29Concrete2V7module11PAadEP12memberMethodyyFTW -// DEADFUNC-MODULE2-CHECK-DAG: $s7module24usePyyx7module11PRzlF - -// DEADFUNC-MODULE2-CHECK-NOT: $s7module29Concrete2V7module11PAadEP15defaultProvidedyyFTW -// DEADFUNC-MODULE2-CHECK-NOT: $s7module20A4FuncSiyF -// DEADFUNC-MODULE2-CHECK-NOT: $s7module29Concrete1V7module11PAadEP15defaultProvidedyyFTW -// DEADFUNC-MODULE2-CHECK-NOT: $s7module11PPAAE15defaultProvidedyyF - - -// RUN: %target-swift-frontend -emit-ir %S/Inputs/module2.swift -parse-as-library -module-summary-path %t/merged-module.summary -I %t -O | %FileCheck %s --check-prefix DEADFUNC-MODULE2-CHECK - -import module1 -import module2 - -class S {} - -func foo() { bar(0) } -func bar(_ i: Int) { - if (i == 0) { return } - foo() -} - -func callTwice() { - foo() - bar(0) -} - -func callExternalFunc() { - _ = module2Func() -} - -public func publicFunc() { - S() - foo() -} - -publicFunc() -useP(Concrete2()) From 687ef6fbf89277418de5217d5d60d98ca7b05364 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Fri, 14 Aug 2020 01:14:48 +0900 Subject: [PATCH 44/77] [Serialization] Serialize type ref information --- lib/Serialization/ModuleSummaryFormat.cpp | 21 +++++++++++++++++++ lib/Serialization/ModuleSummaryFormat.h | 6 ++++++ .../swift-module-summary-test.cpp | 8 +++++++ 3 files changed, 35 insertions(+) diff --git a/lib/Serialization/ModuleSummaryFormat.cpp b/lib/Serialization/ModuleSummaryFormat.cpp index 99d06faca72be..0158ada111aed 100644 --- a/lib/Serialization/ModuleSummaryFormat.cpp +++ b/lib/Serialization/ModuleSummaryFormat.cpp @@ -101,6 +101,7 @@ void Serializer::writeBlockInfoBlock() { BLOCK_RECORD(record_block, FUNC_METADATA); BLOCK_RECORD(record_block, CALL_GRAPH_EDGE); + BLOCK_RECORD(record_block, TYPE_REF); BLOCK_RECORD(record_block, VFUNC_METADATA); BLOCK_RECORD(record_block, VFUNC_IMPL); @@ -126,6 +127,13 @@ void Serializer::emitFunctionSummary(const FunctionSummary *summary) { Out, ScratchRecord, AbbrCodes[CallGraphEdgeLayout::Code], unsigned(call.getKind()), call.getCallee(), debugName); } + + for (auto typeRef : summary->typeRefs()) { + std::string debugName = ModuleSummaryEmbedDebugName ? typeRef.Name : ""; + TypeRefLayout::emitRecord(Out, ScratchRecord, + AbbrCodes[TypeRefLayout::Code], typeRef.Guid, + debugName); + } } void Serializer::emitVFuncTable(const VFuncToImplsMapTy T, @@ -154,6 +162,7 @@ void Serializer::emitModuleSummary(const ModuleSummaryIndex &index) { registerRecordAbbr(); registerRecordAbbr(); registerRecordAbbr(); + registerRecordAbbr(); registerRecordAbbr(); registerRecordAbbr(); @@ -378,6 +387,18 @@ bool Deserializer::readModuleSummary() { CurrentFunc->addCall(call); break; } + case TYPE_REF: { + // TYPE_REF must follow a FUNC_METADATA. + if (!CurrentFunc) { + report_fatal_error("Unexpected TYPE_REF record"); + } + GUID typeGUID; + std::string name; + TypeRefLayout::readRecord(Scratch, typeGUID); + name = BlobData.str(); + CurrentFunc->addTypeRef({typeGUID, name}); + break; + } case VFUNC_METADATA: { unsigned rawVFuncKind; GUID vFuncGUID; diff --git a/lib/Serialization/ModuleSummaryFormat.h b/lib/Serialization/ModuleSummaryFormat.h index c689bd1917da4..fad86e9cfad68 100644 --- a/lib/Serialization/ModuleSummaryFormat.h +++ b/lib/Serialization/ModuleSummaryFormat.h @@ -32,6 +32,7 @@ enum { MODULE_METADATA, FUNC_METADATA, CALL_GRAPH_EDGE, + TYPE_REF, VFUNC_METADATA, VFUNC_IMPL, }; @@ -55,6 +56,11 @@ using CallGraphEdgeLayout = BCBlob // name (debug purpose) >; +using TypeRefLayout = BCRecordLayout; + using VFuncMetadataLayout = BCRecordLayout, // vfunc kind (vtable or witness) diff --git a/tools/swift-module-summary-test/swift-module-summary-test.cpp b/tools/swift-module-summary-test/swift-module-summary-test.cpp index f30ff8e276bf9..8270324b21650 100644 --- a/tools/swift-module-summary-test/swift-module-summary-test.cpp +++ b/tools/swift-module-summary-test/swift-module-summary-test.cpp @@ -58,7 +58,9 @@ static llvm::cl::opt LLVM_YAML_DECLARE_MAPPING_TRAITS(modulesummary::ModuleSummaryIndex) LLVM_YAML_DECLARE_MAPPING_TRAITS(modulesummary::FunctionSummary) LLVM_YAML_DECLARE_MAPPING_TRAITS(modulesummary::FunctionSummary::Call) +LLVM_YAML_DECLARE_MAPPING_TRAITS(modulesummary::FunctionSummary::TypeRef) LLVM_YAML_IS_SEQUENCE_VECTOR(modulesummary::FunctionSummary::Call) +LLVM_YAML_IS_SEQUENCE_VECTOR(modulesummary::FunctionSummary::TypeRef) LLVM_YAML_DECLARE_ENUM_TRAITS(modulesummary::FunctionSummary::Call::KindTy) namespace llvm { @@ -88,12 +90,18 @@ void MappingTraits::mapping(IO &io, io.mapRequired("kind", V.Kind); } +void MappingTraits::mapping(IO &io, + FunctionSummary::TypeRef &V) { + io.mapRequired("name", V.Name); + io.mapRequired("guid", V.Guid); +} void MappingTraits::mapping(IO &io, FunctionSummary &V) { io.mapRequired("name", V.Name); io.mapRequired("guid", V.Guid); io.mapRequired("live", V.Flags.Live); io.mapRequired("preserved", V.Flags.Preserved); io.mapRequired("calls", V.CallGraphEdgeList); + io.mapRequired("type_refs", V.TypeRefList); } template <> From 96d1501aba20cd1debd004abd2316dd4186cafa7 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Fri, 14 Aug 2020 01:44:29 +0900 Subject: [PATCH 45/77] [Prototype] Port upstream test cases --- test/Serialization/empty_module_summary.swift | 9 +++ test/Serialization/function_summary.swift | 71 +++++++++++++++++++ .../module_summary_preserved.swift | 59 +++++++++++++++ .../Serialization/module_summary_tables.swift | 39 ++++++++++ test/lit.cfg | 2 + 5 files changed, 180 insertions(+) create mode 100644 test/Serialization/empty_module_summary.swift create mode 100644 test/Serialization/function_summary.swift create mode 100644 test/Serialization/module_summary_preserved.swift create mode 100644 test/Serialization/module_summary_tables.swift diff --git a/test/Serialization/empty_module_summary.swift b/test/Serialization/empty_module_summary.swift new file mode 100644 index 0000000000000..27e9e62d75d0a --- /dev/null +++ b/test/Serialization/empty_module_summary.swift @@ -0,0 +1,9 @@ +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend -emit-sib -emit-module-summary-path %t/empty.swiftmodule.summary -module-name empty %s +// RUN: llvm-bcanalyzer -dump %t/empty.swiftmodule.summary | %FileCheck %s -check-prefix BCANALYZER + +// BCANALYZER-NOT: UnknownCode + +// RUN: %swift-module-summary-test --to-yaml %t/empty.swiftmodule.summary -o - | %FileCheck %s + +// CHECK: module_name: empty diff --git a/test/Serialization/function_summary.swift b/test/Serialization/function_summary.swift new file mode 100644 index 0000000000000..d0c893e85c925 --- /dev/null +++ b/test/Serialization/function_summary.swift @@ -0,0 +1,71 @@ +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend -emit-sib -emit-module-summary-path %t/function_summary.swiftmodule.summary -module-name function_summary -Xllvm -module-summary-embed-debug-name %s +// RUN: llvm-bcanalyzer -dump %t/function_summary.swiftmodule.summary | %FileCheck %s -check-prefix BCANALYZER + +// BCANALYZER-NOT: UnknownCode + +// RUN: %swift-module-summary-test --to-yaml %t/function_summary.swiftmodule.summary -o %t/function_summary.summary.yaml + +// `bar` references `foo` directly +// RUN: cat %t/function_summary.summary.yaml | %FileCheck %s -check-prefix DIRECT-CALL + +// DIRECT-CALL: 15904760426814321987: +// DIRECT-CALL-NEXT: name: '$s16function_summary3baryyF' +// DIRECT-CALL-NEXT: guid: 15904760426814321987 +// DIRECT-CALL-NEXT: live: false +// DIRECT-CALL-NEXT: preserved: false +// DIRECT-CALL-NEXT: calls: +// DIRECT-CALL-NEXT: - callee_name: '$s16function_summary3fooyyF' +// DIRECT-CALL-NEXT: callee_guid: 3365867516365370991 +// DIRECT-CALL-NEXT: kind: direct +func foo() {} + +func bar() { + foo() +} + +// `useGenericP` and `useExistentialP` reference `#P.protoMember` through witness table +// RUN: cat %t/function_summary.summary.yaml | %FileCheck %s -check-prefix WITNESS-CALL + +// WITNESS-CALL: 2534322708691595658: +// WITNESS-CALL-NEXT: name: '$s16function_summary15useExistentialPyyAA1P_pF' +// WITNESS-CALL-NEXT: guid: 2534322708691595658 +// WITNESS-CALL-NEXT: live: false +// WITNESS-CALL-NEXT: preserved: false +// WITNESS-CALL-NEXT: calls: +// WITNESS-CALL-NEXT: - callee_name: '$s16function_summary1PP11protoMemberyyF' +// WITNESS-CALL-NEXT: callee_guid: 12061107285276415735 +// WITNESS-CALL-NEXT: kind: witness + +protocol P { + func protoMember() +} + +func useExistentialP(_ v: P) { + v.protoMember() +} + +// `useClassC` reference `#P.classMember` through vtable +// RUN: cat %t/function_summary.summary.yaml | %FileCheck %s -check-prefix VTABLE-CALL + +// VTABLE-CALL: 6451800047657108456: +// VTABLE-CALL-NEXT: name: '$s16function_summary9useClassCyyAA1CCF' +// VTABLE-CALL-NEXT: guid: 6451800047657108456 +// VTABLE-CALL-NEXT: live: false +// VTABLE-CALL-NEXT: preserved: false +// VTABLE-CALL-NEXT: calls: +// VTABLE-CALL-NEXT: - callee_name: '$s16function_summary1CC11classMemberyyF' +// VTABLE-CALL-NEXT: callee_guid: 7506985369146111998 +// VTABLE-CALL-NEXT: kind: vtable + +class C { + func classMember() {} +} + +class D : C { + override func classMember() {} +} + +func useClassC(_ v: C) { + v.classMember() +} diff --git a/test/Serialization/module_summary_preserved.swift b/test/Serialization/module_summary_preserved.swift new file mode 100644 index 0000000000000..91d14495eadbd --- /dev/null +++ b/test/Serialization/module_summary_preserved.swift @@ -0,0 +1,59 @@ +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend -emit-sib -emit-module-summary-path %t/preserved.swiftmodule.summary -module-name preserved -Xllvm -module-summary-embed-debug-name %s +// RUN: %swift-module-summary-test --to-yaml %t/preserved.swiftmodule.summary -o %t/preserved.summary.yaml +// RUN: cat %t/preserved.summary.yaml | %FileCheck %s -check-prefix REPLACABLE +// REPLACABLE: 909315153062346157: +// REPLACABLE-NEXT: name: '$s9preserved12replaceable1SiyF' +// REPLACABLE-NEXT: guid: 909315153062346157 +// REPLACABLE-NEXT: live: false +// REPLACABLE-NEXT: preserved: true + +// REPLACABLE: 3380283816534000009: +// REPLACABLE-NEXT: name: '$s9preserved14replaceable1_rSiyF' +// REPLACABLE-NEXT: guid: 3380283816534000009 +// REPLACABLE-NEXT: live: false +// REPLACABLE-NEXT: preserved: false + +dynamic func replaceable1() -> Int { + return 0 +} + +@_dynamicReplacement(for: replaceable1()) +func replaceable1_r() -> Int { + return 3 +} + + +// RUN: cat %t/preserved.summary.yaml | %FileCheck %s -check-prefix CDECL +// CDECL: 401177591854398425: +// CDECL-NEXT: name: callableFromC2 +// CDECL-NEXT: guid: 401177591854398425 +// CDECL-NEXT: live: false +// CDECL-NEXT: preserved: true +// CDECL-NEXT: calls: [] +// CDECL: 2609850307322683057: +// CDECL-NEXT: name: callableFromC1 +// CDECL-NEXT: guid: 2609850307322683057 +// CDECL-NEXT: live: false +// CDECL-NEXT: preserved: true +@_cdecl("callableFromC1") +func callableFromC1(x: Int) -> Int { + return 1 +} + +@_silgen_name("callableFromC2") +func callableFromC2(x: Int) -> Int { + return 2 +} + +// RUN: cat %t/preserved.summary.yaml | %FileCheck %s -check-prefix OBJC +// OBJC: 3149498140227613915: +// OBJC-NEXT: name: '$s9preserved1AC11objcMethod1yyFTo' +// OBJC-NEXT: guid: 3149498140227613915 +// OBJC-NEXT: live: false +// OBJC-NEXT: preserved: true +import Foundation + +class A: NSObject { + @objc func objcMethod1() {} +} diff --git a/test/Serialization/module_summary_tables.swift b/test/Serialization/module_summary_tables.swift new file mode 100644 index 0000000000000..423d03bac5885 --- /dev/null +++ b/test/Serialization/module_summary_tables.swift @@ -0,0 +1,39 @@ +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend -emit-sib -emit-module-summary-path %t/tables.swiftmodule.summary -module-name tables -Xllvm -module-summary-embed-debug-name %s +// RUN: llvm-bcanalyzer -dump %t/tables.swiftmodule.summary | %FileCheck %s -check-prefix BCANALYZER + +// BCANALYZER-NOT: UnknownCode + +// RUN: %swift-module-summary-test --to-yaml %t/tables.swiftmodule.summary -o - | %FileCheck %s + + +// CHECK: 767048646313834908: +// CHECK-NEXT: name: '$s6tables1SVAA1PA2aDP11protoMemberyyFTW' +// CHECK: 11756327503593502600: +// CHECK-NEXT: name: '$s6tables1DC11classMemberyyF' +// CHECK: 17602567966448237004: +// CHECK-NEXT: name: '$s6tables1CC11classMemberyyF' + +// `protoMember` witness is recorded on the table +// CHECK: witness_tables: +// CHECK: 2682576275888919121: [ 767048646313834908 ] +// `classMember` impls are recorded on the table +// CHECK: vtables: +// CHECK: 17602567966448237004: [ 17602567966448237004, 11756327503593502600 ] + +protocol P { + func protoMember() +} + +struct S : P { + func protoMember() {} +} + + +class C { + func classMember() {} +} + +class D : C { + override func classMember() {} +} diff --git a/test/lit.cfg b/test/lit.cfg index 629388790da42..58b58e1e136f2 100644 --- a/test/lit.cfg +++ b/test/lit.cfg @@ -262,6 +262,7 @@ config.sil_passpipeline_dumper = inferSwiftBinary('sil-passpipeline-dumper') config.lldb_moduleimport_test = inferSwiftBinary('lldb-moduleimport-test') config.swift_ide_test = inferSwiftBinary('swift-ide-test') config.swift_dependency_tool = inferSwiftBinary('swift-dependency-tool') +config.swift_module_summary_test = inferSwiftBinary('swift-module-summary-test') config.swift_syntax_test = inferSwiftBinary('swift-syntax-test') if 'syntax_parser_lib' in config.available_features: config.swift_syntax_parser_test = inferSwiftBinary('swift-syntax-parser-test') @@ -422,6 +423,7 @@ config.substitutions.append( ('%swift-dump-pcm', "%r -dump-pcm" % config.swiftc) config.substitutions.append( ('%swift-ide-test_plain', config.swift_ide_test) ) config.substitutions.append( ('%swift-ide-test', "%r %s %s -swift-version %s" % (config.swift_ide_test, mcp_opt, ccp_opt, swift_version)) ) config.substitutions.append( ('%swift-dependency-tool', config.swift_dependency_tool) ) +config.substitutions.append( ('%swift-module-summary-test', config.swift_module_summary_test) ) config.substitutions.append( ('%swift-syntax-test', config.swift_syntax_test) ) if 'syntax_parser_lib' in config.available_features: config.substitutions.append( ('%swift-syntax-parser-test', config.swift_syntax_parser_test) ) From 25daa62aac5ea1859813c01282c892055f20cfa7 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Fri, 14 Aug 2020 01:44:43 +0900 Subject: [PATCH 46/77] [Prototype] Add test case for type addr --- test/Serialization/type_refs_summary.swift | 29 ++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 test/Serialization/type_refs_summary.swift diff --git a/test/Serialization/type_refs_summary.swift b/test/Serialization/type_refs_summary.swift new file mode 100644 index 0000000000000..5307cbdc2e802 --- /dev/null +++ b/test/Serialization/type_refs_summary.swift @@ -0,0 +1,29 @@ +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend -emit-sib -emit-module-summary-path %t/type_refs.swiftmodule.summary -module-name type_refs -Xllvm -module-summary-embed-debug-name %s +// RUN: llvm-bcanalyzer -dump %t/type_refs.swiftmodule.summary | %FileCheck %s -check-prefix BCANALYZER + +// BCANALYZER-NOT: UnknownCode + +// RUN: %swift-module-summary-test --to-yaml %t/type_refs.swiftmodule.summary -o %t/type_refs.summary.yaml + +// Ensure that type reference to S is recorded +// RUN: cat %t/type_refs.summary.yaml | %FileCheck %s -check-prefix SIMPLE-COERCE + +// SIMPLE-COERCE: name: '$s9type_refs9coerceToPyAA1P_pAA1SVF' +// SIMPLE-COERCE-NEXT: guid: 15452386893050095333 +// SIMPLE-COERCE-NEXT: live: false +// SIMPLE-COERCE-NEXT: preserved: false +// SIMPLE-COERCE-NEXT: calls: [] +// SIMPLE-COERCE-NEXT: type_refs: +// SIMPLE-COERCE-NEXT: - name: 9type_refs1SV +// SIMPLE-COERCE-NEXT: guid: 12736589225588998764 + +protocol P { + func foo() +} + +struct S : P { + func foo() {} +} + +func coerceToP(_ x: S) -> P { return x } From 83930883823e29b7d6b12b31162186832d8240c4 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Fri, 14 Aug 2020 09:39:02 +0900 Subject: [PATCH 47/77] [Prototype] Fix crashing when mangling Archettype and OpaqueArchettype depend on its context and they don't have witness table directly, so we don't need to index them. And they can't be mangled. --- lib/Serialization/ModuleSummaryIndexer.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/Serialization/ModuleSummaryIndexer.cpp b/lib/Serialization/ModuleSummaryIndexer.cpp index 0cc4026e4356f..3f3f6ca8e5f17 100644 --- a/lib/Serialization/ModuleSummaryIndexer.cpp +++ b/lib/Serialization/ModuleSummaryIndexer.cpp @@ -103,6 +103,10 @@ void FunctionSummaryIndexer::indexIndirectFunctionCall( void FunctionSummaryIndexer::indexUseOfType(CanType type) { Mangle::ASTMangler mangler; type.visit([&](Type t) { + if (t.getPointer()->hasArchetype() || + t.getPointer()->hasOpaqueArchetype()) { + return; + } std::string mangled = mangler.mangleTypeWithoutPrefix(t); GUID guid = getGUIDFromUniqueName(mangled); TheSummary->addTypeRef({guid, mangled}); From 34849df058652a935cbc4cb70528bd2837a22c33 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Fri, 14 Aug 2020 09:56:53 +0900 Subject: [PATCH 48/77] [Prototype] Mark used types and serialize them --- include/swift/Serialization/ModuleSummary.h | 4 ++++ lib/Serialization/ModuleSummaryFormat.cpp | 19 +++++++++++++++++++ lib/Serialization/ModuleSummaryFormat.h | 4 ++++ lib/Serialization/ModuleSummaryIndexer.cpp | 6 +++++- tools/driver/cross_module_opt_main.cpp | 8 +++++++- .../swift-module-summary-test.cpp | 1 + 6 files changed, 40 insertions(+), 2 deletions(-) diff --git a/include/swift/Serialization/ModuleSummary.h b/include/swift/Serialization/ModuleSummary.h index dacf5a2eaa0a6..4c2cb72aa1df4 100644 --- a/include/swift/Serialization/ModuleSummary.h +++ b/include/swift/Serialization/ModuleSummary.h @@ -243,6 +243,10 @@ class ModuleSummaryIndex { return VTableMethodMap; } + ArrayRef getUsedTypeList() const { + return ArrayRef(UsedTypeList); + } + FunctionSummaryMapTy::const_iterator functions_begin() const { return FunctionSummaryMap.begin(); } diff --git a/lib/Serialization/ModuleSummaryFormat.cpp b/lib/Serialization/ModuleSummaryFormat.cpp index 0158ada111aed..e67f701d7cf95 100644 --- a/lib/Serialization/ModuleSummaryFormat.cpp +++ b/lib/Serialization/ModuleSummaryFormat.cpp @@ -53,6 +53,7 @@ class Serializer { void emitRecordID(unsigned ID, StringRef name, SmallVectorImpl &nameBuffer); void emitVFuncTable(const VFuncToImplsMapTy T, VFuncSlot::KindTy kind); + void emitUsedTypeList(const ArrayRef L); public: void emitHeader(); @@ -105,6 +106,8 @@ void Serializer::writeBlockInfoBlock() { BLOCK_RECORD(record_block, VFUNC_METADATA); BLOCK_RECORD(record_block, VFUNC_IMPL); + + BLOCK_RECORD(record_block, USED_TYPE); } void Serializer::emitHeader() { @@ -154,6 +157,14 @@ void Serializer::emitVFuncTable(const VFuncToImplsMapTy T, } } +void Serializer::emitUsedTypeList(const ArrayRef L) { + using namespace record_block; + for (GUID usedType : L) { + UsedTypeLayout::emitRecord(Out, ScratchRecord, + AbbrCodes[UsedTypeLayout::Code], usedType); + } +} + void Serializer::emitModuleSummary(const ModuleSummaryIndex &index) { using namespace record_block; @@ -165,6 +176,7 @@ void Serializer::emitModuleSummary(const ModuleSummaryIndex &index) { registerRecordAbbr(); registerRecordAbbr(); registerRecordAbbr(); + registerRecordAbbr(); ModuleMetadataLayout::emitRecord(Out, ScratchRecord, AbbrCodes[ModuleMetadataLayout::Code], @@ -176,6 +188,8 @@ void Serializer::emitModuleSummary(const ModuleSummaryIndex &index) { emitVFuncTable(index.getWitnessTableMethodMap(), VFuncSlot::Witness); emitVFuncTable(index.getVTableMethodMap(), VFuncSlot::VTable); + + emitUsedTypeList(index.getUsedTypeList()); } void Serializer::write(raw_ostream &os) { @@ -421,6 +435,11 @@ bool Deserializer::readModuleSummary() { moduleSummary.addImplementation(CurrentSlot.getValue(), implGUID); break; } + case USED_TYPE: { + GUID typeGUID; + UsedTypeLayout::readRecord(Scratch, typeGUID); + moduleSummary.markUsedType(typeGUID); + } } } diff --git a/lib/Serialization/ModuleSummaryFormat.h b/lib/Serialization/ModuleSummaryFormat.h index fad86e9cfad68..660a27fc88420 100644 --- a/lib/Serialization/ModuleSummaryFormat.h +++ b/lib/Serialization/ModuleSummaryFormat.h @@ -35,6 +35,7 @@ enum { TYPE_REF, VFUNC_METADATA, VFUNC_IMPL, + USED_TYPE, }; using BCGUID = llvm::BCVBR<16>; @@ -70,6 +71,9 @@ using VFuncMetadataLayout = using VFuncImplLayout = BCRecordLayout; +using UsedTypeLayout = BCRecordLayout; } // namespace record_block } // namespace modulesummary } // namespace swift diff --git a/lib/Serialization/ModuleSummaryIndexer.cpp b/lib/Serialization/ModuleSummaryIndexer.cpp index 3f3f6ca8e5f17..b6615b09069af 100644 --- a/lib/Serialization/ModuleSummaryIndexer.cpp +++ b/lib/Serialization/ModuleSummaryIndexer.cpp @@ -23,6 +23,8 @@ class FunctionSummaryIndexer : public SILInstructionVisitor TheSummary; + std::set RecordedTypes; + void indexDirectFunctionCall(const SILFunction &Callee); void indexIndirectFunctionCall(const SILDeclRef &Callee, FunctionSummary::Call::KindTy Kind); @@ -109,7 +111,9 @@ void FunctionSummaryIndexer::indexUseOfType(CanType type) { } std::string mangled = mangler.mangleTypeWithoutPrefix(t); GUID guid = getGUIDFromUniqueName(mangled); - TheSummary->addTypeRef({guid, mangled}); + if (RecordedTypes.insert(guid).second) { + TheSummary->addTypeRef({guid, mangled}); + } }); } diff --git a/tools/driver/cross_module_opt_main.cpp b/tools/driver/cross_module_opt_main.cpp index f54934eddb438..2720017329231 100644 --- a/tools/driver/cross_module_opt_main.cpp +++ b/tools/driver/cross_module_opt_main.cpp @@ -111,6 +111,7 @@ VFuncSlot createVFuncSlot(FunctionSummary::Call call) { void markDeadSymbols(ModuleSummaryIndex &summary, llvm::DenseSet &PreservedGUIDs) { SmallVector, 8> Worklist; + std::set UseMarkedTypes; unsigned LiveSymbols = 0; for (auto GUID : PreservedGUIDs) { @@ -141,7 +142,12 @@ void markDeadSymbols(ModuleSummaryIndex &summary, llvm::DenseSet &Preserve } FS->setLive(true); LiveSymbols++; - + + for (auto typeRef : FS->typeRefs()) { + if (UseMarkedTypes.insert(typeRef.Guid).second) { + summary.markUsedType(typeRef.Guid); + } + } for (auto Call : FS->calls()) { switch (Call.getKind()) { case FunctionSummary::Call::Direct: { diff --git a/tools/swift-module-summary-test/swift-module-summary-test.cpp b/tools/swift-module-summary-test/swift-module-summary-test.cpp index 8270324b21650..dda1885f286cc 100644 --- a/tools/swift-module-summary-test/swift-module-summary-test.cpp +++ b/tools/swift-module-summary-test/swift-module-summary-test.cpp @@ -142,6 +142,7 @@ void MappingTraits::mapping(IO &io, ModuleSummaryIndex &V) { io.mapRequired("functions", V.FunctionSummaryMap); io.mapRequired("witness_tables", V.WitnessTableMethodMap); io.mapRequired("vtables", V.VTableMethodMap); + io.mapRequired("used_types", V.UsedTypeList); } } // namespace yaml } // namespace llvm From 639d040d2b9bf02bbb08e6632d9e9de3d874f0ef Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Fri, 14 Aug 2020 10:36:11 +0900 Subject: [PATCH 49/77] [Prototype] Add test case for type ref marking --- test/Serialization/type_refs_summary.swift | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/test/Serialization/type_refs_summary.swift b/test/Serialization/type_refs_summary.swift index 5307cbdc2e802..b55ddf473803a 100644 --- a/test/Serialization/type_refs_summary.swift +++ b/test/Serialization/type_refs_summary.swift @@ -18,6 +18,14 @@ // SIMPLE-COERCE-NEXT: - name: 9type_refs1SV // SIMPLE-COERCE-NEXT: guid: 12736589225588998764 + +// RUN: %swift_frontend_plain -cross-module-opt %t/type_refs.swiftmodule.summary -module-summary-embed-debug-name -o %t/type_refs.swiftmodule.merged-summary +// RUN: %swift-module-summary-test --to-yaml %t/type_refs.swiftmodule.merged-summary -o %t/type_refs.merged-summary.yaml +// Ensure that WT of V is not used. +// RUN: cat %t/type_refs.merged-summary.yaml | %FileCheck %s -check-prefix USED-TYPE + +// USED-TYPE-NOT: s9type_refs1VVXMt + protocol P { func foo() } @@ -26,4 +34,10 @@ struct S : P { func foo() {} } +struct V : P { + func foo() {} +} + func coerceToP(_ x: S) -> P { return x } + +_ = coerceToP(S()) From 8ed15bd29964913b684c2063749428cffe1ed075 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Sat, 15 Aug 2020 11:12:14 +0900 Subject: [PATCH 50/77] [Prototype] Implement type ref based elimination --- include/swift/SIL/ModuleSummary.h | 20 ++++--- include/swift/Serialization/ModuleSummary.h | 20 ++++--- .../IPO/CrossDeadFunctionElimination.cpp | 25 +++++++- lib/Serialization/ModuleSummaryFormat.cpp | 10 ++-- lib/Serialization/ModuleSummaryFormat.h | 3 +- lib/Serialization/ModuleSummaryIndexer.cpp | 18 ++++-- tools/driver/cross_module_opt_main.cpp | 59 ++++++++++++++++--- .../swift-module-summary-test.cpp | 7 +++ 8 files changed, 129 insertions(+), 33 deletions(-) diff --git a/include/swift/SIL/ModuleSummary.h b/include/swift/SIL/ModuleSummary.h index 36350c84c3581..65aff60d1b99d 100644 --- a/include/swift/SIL/ModuleSummary.h +++ b/include/swift/SIL/ModuleSummary.h @@ -130,8 +130,13 @@ struct VFuncSlot { VFuncSlot(KindTy Kind, GUID VFuncID) : Kind(Kind), VFuncID(VFuncID) {} }; +struct VFuncImpl { + GUID Guid; + GUID TypeGuid; +}; + using FunctionSummaryMapTy = std::map>; -using VFuncToImplsMapTy = std::map>; +using VFuncToImplsMapTy = std::map>; /// Module summary that consists of function summaries and virtual function /// tables. @@ -195,24 +200,25 @@ class ModuleSummaryIndex { } /// Record a implementation for the virtual function slot. - void addImplementation(VFuncSlot slot, GUID implGUID) { + void addImplementation(VFuncSlot slot, GUID implGUID, GUID typeGUID) { VFuncToImplsMapTy &table = getVFuncMap(slot.Kind); auto found = table.find(slot.VFuncID); + VFuncImpl impl = {implGUID, typeGUID}; if (found == table.end()) { - table.insert(std::make_pair(slot.VFuncID, std::vector{implGUID})); + table.insert(std::make_pair(slot.VFuncID, std::vector{impl})); return; } - found->second.push_back(implGUID); + found->second.push_back(impl); } /// Return a list of implementations for the virtual function slot. - ArrayRef getImplementations(VFuncSlot slot) const { + ArrayRef getImplementations(VFuncSlot slot) const { const VFuncToImplsMapTy &table = getVFuncMap(slot.Kind); auto found = table.find(slot.VFuncID); if (found == table.end()) { - return ArrayRef(); + return ArrayRef(); } - return ArrayRef(found->second); + return ArrayRef(found->second); } const VFuncToImplsMapTy &getWitnessTableMethodMap() const { diff --git a/include/swift/Serialization/ModuleSummary.h b/include/swift/Serialization/ModuleSummary.h index 4c2cb72aa1df4..72f2546a0fd00 100644 --- a/include/swift/Serialization/ModuleSummary.h +++ b/include/swift/Serialization/ModuleSummary.h @@ -145,8 +145,13 @@ struct VFuncSlot { VFuncSlot(KindTy Kind, GUID VFuncID) : Kind(Kind), VFuncID(VFuncID) {} }; +struct VFuncImpl { + GUID Guid; + GUID TypeGuid; +}; + using FunctionSummaryMapTy = std::map>; -using VFuncToImplsMapTy = std::map>; +using VFuncToImplsMapTy = std::map>; using UsedTypeListTy = std::vector; /// Module summary that consists of function summaries and virtual function @@ -214,24 +219,25 @@ class ModuleSummaryIndex { } /// Record a implementation for the virtual function slot. - void addImplementation(VFuncSlot slot, GUID implGUID) { + void addImplementation(VFuncSlot slot, GUID implGUID, GUID typeGUID) { VFuncToImplsMapTy &table = getVFuncMap(slot.Kind); auto found = table.find(slot.VFuncID); + VFuncImpl impl = {implGUID, typeGUID}; if (found == table.end()) { - table.insert(std::make_pair(slot.VFuncID, std::vector{implGUID})); + table.insert(std::make_pair(slot.VFuncID, std::vector{impl})); return; } - found->second.push_back(implGUID); + found->second.push_back(impl); } /// Return a list of implementations for the virtual function slot. - ArrayRef getImplementations(VFuncSlot slot) const { + ArrayRef getImplementations(VFuncSlot slot) const { const VFuncToImplsMapTy &table = getVFuncMap(slot.Kind); auto found = table.find(slot.VFuncID); if (found == table.end()) { - return ArrayRef(); + return ArrayRef(); } - return ArrayRef(found->second); + return ArrayRef(found->second); } void markUsedType(GUID typeGUID) { UsedTypeList.push_back(typeGUID); } diff --git a/lib/SILOptimizer/IPO/CrossDeadFunctionElimination.cpp b/lib/SILOptimizer/IPO/CrossDeadFunctionElimination.cpp index 86e17384f562f..d412de9064d08 100644 --- a/lib/SILOptimizer/IPO/CrossDeadFunctionElimination.cpp +++ b/lib/SILOptimizer/IPO/CrossDeadFunctionElimination.cpp @@ -1,4 +1,5 @@ #define DEBUG_TYPE "sil-cross-dead-function-elimination" +#include "swift/AST/ASTMangler.h" #include "swift/AST/DiagnosticsFrontend.h" #include "swift/AST/ProtocolConformance.h" #include "swift/SIL/InstructionUtils.h" @@ -31,7 +32,29 @@ class SILCrossDeadFuncElimination : public SILModuleTransform { public: SILCrossDeadFuncElimination() {} - + + void eliminateDeadTables(SILModule &M) { + auto &WitnessTables = M.getWitnessTableList(); + std::set UsedTypes; + for (auto type : TheSummary.getUsedTypeList()) { + UsedTypes.insert(type); + } + Mangle::ASTMangler mangler; + for (auto WI = WitnessTables.begin(), EI = WitnessTables.end(); WI != EI;) { + SILWitnessTable *WT = &*WI; + ++WI; + CanType type = WI->getConformingType(); + std::string mangled = mangler.mangleTypeWithoutPrefix(type); + GUID guid = getGUIDFromUniqueName(mangled); + if (UsedTypes.find(guid) != UsedTypes.end()) { + continue; + } + WT->clearMethods_if([&] (const SILWitnessTable::MethodWitness &MW) -> bool { + return true; + }); + } + } + void eliminateDeadEntriesFromTables(SILModule &M) { for (auto VT : M.getVTables()) { diff --git a/lib/Serialization/ModuleSummaryFormat.cpp b/lib/Serialization/ModuleSummaryFormat.cpp index e67f701d7cf95..078e5d06249d6 100644 --- a/lib/Serialization/ModuleSummaryFormat.cpp +++ b/lib/Serialization/ModuleSummaryFormat.cpp @@ -143,7 +143,7 @@ void Serializer::emitVFuncTable(const VFuncToImplsMapTy T, VFuncSlot::KindTy kind) { for (auto &pair : T) { GUID guid = pair.first; - std::vector impls = pair.second; + std::vector impls = pair.second; using namespace record_block; VFuncMetadataLayout::emitRecord(Out, ScratchRecord, @@ -152,7 +152,7 @@ void Serializer::emitVFuncTable(const VFuncToImplsMapTy T, for (auto impl : impls) { VFuncImplLayout::emitRecord(Out, ScratchRecord, - AbbrCodes[VFuncImplLayout::Code], impl); + AbbrCodes[VFuncImplLayout::Code], impl.Guid, impl.TypeGuid); } } } @@ -430,9 +430,9 @@ bool Deserializer::readModuleSummary() { if (!CurrentSlot) { report_fatal_error("Unexpected METHOD_IMPL record"); } - GUID implGUID; - VFuncImplLayout::readRecord(Scratch, implGUID); - moduleSummary.addImplementation(CurrentSlot.getValue(), implGUID); + GUID implGUID, typeGUID; + VFuncImplLayout::readRecord(Scratch, implGUID, typeGUID); + moduleSummary.addImplementation(CurrentSlot.getValue(), implGUID, typeGUID); break; } case USED_TYPE: { diff --git a/lib/Serialization/ModuleSummaryFormat.h b/lib/Serialization/ModuleSummaryFormat.h index 660a27fc88420..4ccf0b43e9c86 100644 --- a/lib/Serialization/ModuleSummaryFormat.h +++ b/lib/Serialization/ModuleSummaryFormat.h @@ -69,7 +69,8 @@ using VFuncMetadataLayout = >; using VFuncImplLayout = BCRecordLayout; using UsedTypeLayout = BCRecordLayout { friend SILInstructionVisitor; @@ -344,8 +350,8 @@ void ModuleSummaryIndexer::ensurePreserved(const SILDeclRef &Ref, if (Impls.empty()) return; - for (GUID Impl : Impls) { - auto FS = TheSummary->getFunctionSummary(Impl); + for (VFuncImpl Impl : Impls) { + auto FS = TheSummary->getFunctionSummary(Impl.Guid); assert(FS); FS->setPreserved(true); } @@ -376,6 +382,7 @@ void ModuleSummaryIndexer::indexWitnessTable(const SILWitnessTable &WT) { auto isPossibllyUsedExternally = WT.getDeclContext()->getParentModule() != Mod.getSwiftModule() || WT.getProtocol()->getParentModule() != Mod.getSwiftModule(); + auto typeGUID = getTypeGUID(WT.getConformingType()); for (auto entry : WT.getEntries()) { if (entry.getKind() != SILWitnessTable::Method) continue; @@ -386,7 +393,8 @@ void ModuleSummaryIndexer::indexWitnessTable(const SILWitnessTable &WT) { continue; auto slot = createVFuncSlot(methodWitness.Requirement, VFuncSlot::Witness); TheSummary->addImplementation(slot, - getGUIDFromUniqueName(Witness->getName())); + getGUIDFromUniqueName(Witness->getName()), + typeGUID); if (isPossibllyUsedExternally) { ensurePreserved(*Witness); @@ -395,7 +403,7 @@ void ModuleSummaryIndexer::indexWitnessTable(const SILWitnessTable &WT) { } void ModuleSummaryIndexer::indexVTable(const SILVTable &VT) { - + auto typeGUID = getTypeGUID(VT.getClass()->getInterfaceType()); for (auto entry : VT.getEntries()) { auto Impl = entry.getImplementation(); if (entry.getMethod().kind == SILDeclRef::Kind::Deallocator || @@ -411,7 +419,7 @@ void ModuleSummaryIndexer::indexVTable(const SILVTable &VT) { ensurePreserved(*Impl); } auto slot = createVFuncSlot(entry.getMethod(), VFuncSlot::VTable); - TheSummary->addImplementation(slot, getGUIDFromUniqueName(Impl->getName())); + TheSummary->addImplementation(slot, getGUIDFromUniqueName(Impl->getName()), typeGUID); } } diff --git a/tools/driver/cross_module_opt_main.cpp b/tools/driver/cross_module_opt_main.cpp index 2720017329231..922ac9ee72cca 100644 --- a/tools/driver/cross_module_opt_main.cpp +++ b/tools/driver/cross_module_opt_main.cpp @@ -108,10 +108,56 @@ VFuncSlot createVFuncSlot(FunctionSummary::Call call) { return VFuncSlot(slotKind, call.getCallee()); } +void markDeadTypeRef(ModuleSummaryIndex &summary, const llvm::DenseSet &PreservedGUIDs) { + SmallVector Worklist; + SmallSetVector beenInWorklist; + SmallSetVector UseMarkedTypes; + + Worklist.append(PreservedGUIDs.begin(), PreservedGUIDs.end()); + + while (!Worklist.empty()) { + auto target = Worklist.pop_back_val(); + if (!beenInWorklist.insert(target)) { + continue; + } + auto maybeSummary = summary.getFunctionSummary(target); + if (!maybeSummary) { + llvm_unreachable("Bad GUID"); + } + auto FS = maybeSummary; + + for (auto typeRef : FS->typeRefs()) { + if (UseMarkedTypes.insert(typeRef.Guid)) { + summary.markUsedType(typeRef.Guid); + } + } + for (auto Call : FS->calls()) { + switch (Call.getKind()) { + case FunctionSummary::Call::Direct: { + Worklist.push_back(Call.getCallee()); + continue; + } + case FunctionSummary::Call::Witness: + case FunctionSummary::Call::VTable: { + VFuncSlot slot = createVFuncSlot(Call); + auto Impls = summary.getImplementations(slot); + for (auto Impl : Impls) { + Worklist.push_back(Impl.Guid); + } + break; + } + case FunctionSummary::Call::kindCount: + llvm_unreachable("impossible"); + } + } + } +} + void markDeadSymbols(ModuleSummaryIndex &summary, llvm::DenseSet &PreservedGUIDs) { SmallVector, 8> Worklist; - std::set UseMarkedTypes; + auto UsedTypesList = summary.getUsedTypeList(); + std::set UsedTypesSet(UsedTypesList.begin(), UsedTypesList.end()); unsigned LiveSymbols = 0; for (auto GUID : PreservedGUIDs) { @@ -143,11 +189,6 @@ void markDeadSymbols(ModuleSummaryIndex &summary, llvm::DenseSet &Preserve FS->setLive(true); LiveSymbols++; - for (auto typeRef : FS->typeRefs()) { - if (UseMarkedTypes.insert(typeRef.Guid).second) { - summary.markUsedType(typeRef.Guid); - } - } for (auto Call : FS->calls()) { switch (Call.getKind()) { case FunctionSummary::Call::Direct: { @@ -160,8 +201,11 @@ void markDeadSymbols(ModuleSummaryIndex &summary, llvm::DenseSet &Preserve VFuncSlot slot = createVFuncSlot(Call); auto Impls = summary.getImplementations(slot); for (auto Impl : Impls) { + if (UsedTypesSet.find(Impl.TypeGuid) == UsedTypesSet.end()) { + continue; + } Worklist.push_back(std::make_shared( - trace, Impl, LivenessTrace::IndirectReferenced)); + trace, Impl.Guid, LivenessTrace::IndirectReferenced)); } break; } @@ -212,6 +256,7 @@ int cross_module_opt_main(ArrayRef Args, const char *Argv0, TheSummary->setName("combined"); auto PreservedGUIDs = computePreservedGUIDs(TheSummary.get()); + markDeadTypeRef(*TheSummary.get(), PreservedGUIDs); markDeadSymbols(*TheSummary.get(), PreservedGUIDs); modulesummary::writeModuleSummaryIndex(*TheSummary, Instance.getDiags(), diff --git a/tools/swift-module-summary-test/swift-module-summary-test.cpp b/tools/swift-module-summary-test/swift-module-summary-test.cpp index dda1885f286cc..664a747d050a9 100644 --- a/tools/swift-module-summary-test/swift-module-summary-test.cpp +++ b/tools/swift-module-summary-test/swift-module-summary-test.cpp @@ -59,8 +59,10 @@ LLVM_YAML_DECLARE_MAPPING_TRAITS(modulesummary::ModuleSummaryIndex) LLVM_YAML_DECLARE_MAPPING_TRAITS(modulesummary::FunctionSummary) LLVM_YAML_DECLARE_MAPPING_TRAITS(modulesummary::FunctionSummary::Call) LLVM_YAML_DECLARE_MAPPING_TRAITS(modulesummary::FunctionSummary::TypeRef) +LLVM_YAML_DECLARE_MAPPING_TRAITS(modulesummary::VFuncImpl) LLVM_YAML_IS_SEQUENCE_VECTOR(modulesummary::FunctionSummary::Call) LLVM_YAML_IS_SEQUENCE_VECTOR(modulesummary::FunctionSummary::TypeRef) +LLVM_YAML_IS_SEQUENCE_VECTOR(modulesummary::VFuncImpl) LLVM_YAML_DECLARE_ENUM_TRAITS(modulesummary::FunctionSummary::Call::KindTy) namespace llvm { @@ -121,6 +123,11 @@ struct CustomMappingTraits { } }; +void MappingTraits::mapping(IO &io, VFuncImpl &V) { + io.mapRequired("guid", V.Guid); + io.mapRequired("type_guid", V.TypeGuid); +} + template <> struct CustomMappingTraits { static void inputOne(IO &io, StringRef Key, VFuncToImplsMapTy &V) { From f569f7d96df3660528ee2fde0aaac4ffb4d031d2 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Sat, 15 Aug 2020 11:22:20 +0900 Subject: [PATCH 51/77] [Prototype] Add test for type reference from witness impl --- .../Serialization/module_summary_tables.swift | 14 +++- test/Serialization/type_refs_summary.swift | 74 +++++++++++++++++-- 2 files changed, 76 insertions(+), 12 deletions(-) diff --git a/test/Serialization/module_summary_tables.swift b/test/Serialization/module_summary_tables.swift index 423d03bac5885..d99bb365764df 100644 --- a/test/Serialization/module_summary_tables.swift +++ b/test/Serialization/module_summary_tables.swift @@ -15,11 +15,17 @@ // CHECK-NEXT: name: '$s6tables1CC11classMemberyyF' // `protoMember` witness is recorded on the table -// CHECK: witness_tables: -// CHECK: 2682576275888919121: [ 767048646313834908 ] +// CHECK: witness_tables: +// CHECK-NEXT: 2682576275888919121: +// CHECK-NEXT: - guid: 767048646313834908 +// CHECK-NEXT: type_guid: 16119760784751072103 // `classMember` impls are recorded on the table -// CHECK: vtables: -// CHECK: 17602567966448237004: [ 17602567966448237004, 11756327503593502600 ] +// CHECK: vtables: +// CHECK: 17602567966448237004: +// CHECK-NEXT: - guid: 17602567966448237004 +// CHECK-NEXT: type_guid: 3703703597861618193 +// CHECK-NEXT: - guid: 11756327503593502600 +// CHECK-NEXT: type_guid: 9043091933214513226 protocol P { func protoMember() diff --git a/test/Serialization/type_refs_summary.swift b/test/Serialization/type_refs_summary.swift index b55ddf473803a..0baa9445792d8 100644 --- a/test/Serialization/type_refs_summary.swift +++ b/test/Serialization/type_refs_summary.swift @@ -6,17 +6,64 @@ // RUN: %swift-module-summary-test --to-yaml %t/type_refs.swiftmodule.summary -o %t/type_refs.summary.yaml -// Ensure that type reference to S is recorded +// Ensure that type reference to S, C and D are recorded // RUN: cat %t/type_refs.summary.yaml | %FileCheck %s -check-prefix SIMPLE-COERCE +// SIMPLE-COERCE: name: '$s9type_refs11coerceToAnyyypAA1DCF' +// SIMPLE-COERCE-NEXT: guid: 14079990488171131 +// SIMPLE-COERCE-NEXT: live: false +// SIMPLE-COERCE-NEXT: preserved: false +// SIMPLE-COERCE-NEXT: calls: [] +// SIMPLE-COERCE-NEXT: type_refs: +// SIMPLE-COERCE-NEXT: - name: 9type_refs1DC +// SIMPLE-COERCE-NEXT: guid: 1332210649212571009 + +// SIMPLE-COERCE: name: '$s9type_refs11coerceToAnyyypAA1CCF' +// SIMPLE-COERCE-NEXT: guid: 1940219073901329473 +// SIMPLE-COERCE-NEXT: live: false +// SIMPLE-COERCE-NEXT: preserved: false +// SIMPLE-COERCE-NEXT: calls: [] +// SIMPLE-COERCE-NEXT: type_refs: +// SIMPLE-COERCE-NEXT: - name: 9type_refs1CC +// SIMPLE-COERCE-NEXT: guid: 14053292587484144632 + // SIMPLE-COERCE: name: '$s9type_refs9coerceToPyAA1P_pAA1SVF' -// SIMPLE-COERCE-NEXT: guid: 15452386893050095333 -// SIMPLE-COERCE-NEXT: live: false -// SIMPLE-COERCE-NEXT: preserved: false -// SIMPLE-COERCE-NEXT: calls: [] -// SIMPLE-COERCE-NEXT: type_refs: -// SIMPLE-COERCE-NEXT: - name: 9type_refs1SV -// SIMPLE-COERCE-NEXT: guid: 12736589225588998764 +// SIMPLE-COERCE-NEXT: guid: 15452386893050095333 +// SIMPLE-COERCE-NEXT: live: false +// SIMPLE-COERCE-NEXT: preserved: false +// SIMPLE-COERCE-NEXT: calls: [] +// SIMPLE-COERCE-NEXT: type_refs: +// SIMPLE-COERCE-NEXT: - name: 9type_refs1SV +// SIMPLE-COERCE-NEXT: guid: 12736589225588998764 + + + +// Ensure that witness impl of S.foo for P has type ref to S +// RUN: cat %t/type_refs.summary.yaml | %FileCheck %s -check-prefix WITNESS-IMPL + +// WITNESS-IMPL: 12925277474523063582: +// WITNESS-IMPL-NEXT: name: '$s9type_refs1SVAA1PA2aDP3fooyyFTW' + +// WITNESS-IMPL: witness_tables: +// WITNESS-IMPL-NEXT: 17891631795932606560: +// WITNESS-IMPL-NEXT: - guid: 12925277474523063582 +// WITNESS-IMPL-NEXT: type_guid: 12736589225588998764 + + +// Ensure that vtable impl of C.bar and D.bar have type ref to C +// RUN: cat %t/type_refs.summary.yaml | %FileCheck %s -check-prefix WITNESS-IMPL + + +// VTABLE-IMPL: 14897920476774525675: +// VTABLE-IMPL-NEXT: name: '$s9type_refs1CC3baryyF' +// VTABLE-IMPL: 16977749031506698911: +// VTABLE-IMPL-NEXT: name: '$s9type_refs1DC3baryyF' + +// VTABLE-IMPL: 14897920476774525675: +// VTABLE-IMPL-NEXT: - guid: 14897920476774525675 +// VTABLE-IMPL-NEXT: type_guid: 14053292587484144632 +// VTABLE-IMPL-NEXT: - guid: 16977749031506698911 +// VTABLE-IMPL-NEXT: type_guid: 1332210649212571009 // RUN: %swift_frontend_plain -cross-module-opt %t/type_refs.swiftmodule.summary -module-summary-embed-debug-name -o %t/type_refs.swiftmodule.merged-summary @@ -38,6 +85,17 @@ struct V : P { func foo() {} } +class C { + func bar() {} +} + +class D : C { + override func bar() {} +} + func coerceToP(_ x: S) -> P { return x } _ = coerceToP(S()) + +func coerceToAny(_ x: C) -> Any { return x } +func coerceToAny(_ x: D) -> Any { return x } From 86ac64183828fb4a474bef27879421fc6adb2444 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Sat, 15 Aug 2020 12:02:07 +0900 Subject: [PATCH 52/77] [Prototype] Fix vtable type reference --- lib/Serialization/ModuleSummaryIndexer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Serialization/ModuleSummaryIndexer.cpp b/lib/Serialization/ModuleSummaryIndexer.cpp index 63cf915565025..83214a809b23a 100644 --- a/lib/Serialization/ModuleSummaryIndexer.cpp +++ b/lib/Serialization/ModuleSummaryIndexer.cpp @@ -403,7 +403,7 @@ void ModuleSummaryIndexer::indexWitnessTable(const SILWitnessTable &WT) { } void ModuleSummaryIndexer::indexVTable(const SILVTable &VT) { - auto typeGUID = getTypeGUID(VT.getClass()->getInterfaceType()); + auto typeGUID = getTypeGUID(VT.getClass()->getDeclaredType()->getCanonicalType()); for (auto entry : VT.getEntries()) { auto Impl = entry.getImplementation(); if (entry.getMethod().kind == SILDeclRef::Kind::Deallocator || From 20e3699f3b315bb482427e8bfa2a7325a22a735d Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Sat, 15 Aug 2020 14:48:57 +0900 Subject: [PATCH 53/77] [Prototype] Avoid to crash with unclear reason --- lib/Serialization/ModuleSummaryIndexer.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/Serialization/ModuleSummaryIndexer.cpp b/lib/Serialization/ModuleSummaryIndexer.cpp index 83214a809b23a..a68a56212553c 100644 --- a/lib/Serialization/ModuleSummaryIndexer.cpp +++ b/lib/Serialization/ModuleSummaryIndexer.cpp @@ -112,7 +112,9 @@ void FunctionSummaryIndexer::indexUseOfType(CanType type) { Mangle::ASTMangler mangler; type.visit([&](Type t) { if (t.getPointer()->hasArchetype() || - t.getPointer()->hasOpaqueArchetype()) { + t.getPointer()->hasOpaqueArchetype() || + t.getPointer()->getKind() == TypeKind::SILBlockStorage || + t.getPointer()->getKind() == TypeKind::SILFunction) { return; } std::string mangled = mangler.mangleTypeWithoutPrefix(t); From efa577363dbdb641f32fbbb8268b4d8872b11600 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Sat, 15 Aug 2020 16:34:12 +0900 Subject: [PATCH 54/77] [Prototype] Use nominal type decl instead of canonical type to compute GUID This is necessary to support generic type reference --- lib/Serialization/ModuleSummaryIndexer.cpp | 16 ++++---- .../module_summary_generic_type_ref.swift | 37 +++++++++++++++++++ .../Serialization/module_summary_tables.swift | 6 +-- test/Serialization/type_refs_summary.swift | 32 ++++++++-------- 4 files changed, 63 insertions(+), 28 deletions(-) create mode 100644 test/Serialization/module_summary_generic_type_ref.swift diff --git a/lib/Serialization/ModuleSummaryIndexer.cpp b/lib/Serialization/ModuleSummaryIndexer.cpp index a68a56212553c..5b37633962e8d 100644 --- a/lib/Serialization/ModuleSummaryIndexer.cpp +++ b/lib/Serialization/ModuleSummaryIndexer.cpp @@ -16,9 +16,9 @@ GUID modulesummary::getGUIDFromUniqueName(llvm::StringRef Name) { return llvm::MD5Hash(Name); } -static GUID getTypeGUID(Type type) { +static GUID getTypeGUID(NominalTypeDecl *type) { Mangle::ASTMangler mangler; - std::string mangled = mangler.mangleTypeWithoutPrefix(type); + std::string mangled = mangler.mangleNominalType(type); return getGUIDFromUniqueName(mangled); } @@ -111,13 +111,11 @@ void FunctionSummaryIndexer::indexIndirectFunctionCall( void FunctionSummaryIndexer::indexUseOfType(CanType type) { Mangle::ASTMangler mangler; type.visit([&](Type t) { - if (t.getPointer()->hasArchetype() || - t.getPointer()->hasOpaqueArchetype() || - t.getPointer()->getKind() == TypeKind::SILBlockStorage || - t.getPointer()->getKind() == TypeKind::SILFunction) { + auto *decl = t->getAnyNominal(); + if (!decl) { return; } - std::string mangled = mangler.mangleTypeWithoutPrefix(t); + std::string mangled = mangler.mangleNominalType(decl); GUID guid = getGUIDFromUniqueName(mangled); if (RecordedTypes.insert(guid).second) { TheSummary->addTypeRef({guid, mangled}); @@ -384,7 +382,7 @@ void ModuleSummaryIndexer::indexWitnessTable(const SILWitnessTable &WT) { auto isPossibllyUsedExternally = WT.getDeclContext()->getParentModule() != Mod.getSwiftModule() || WT.getProtocol()->getParentModule() != Mod.getSwiftModule(); - auto typeGUID = getTypeGUID(WT.getConformingType()); + auto typeGUID = getTypeGUID(WT.getConformingType()->getAnyNominal()); for (auto entry : WT.getEntries()) { if (entry.getKind() != SILWitnessTable::Method) continue; @@ -405,7 +403,7 @@ void ModuleSummaryIndexer::indexWitnessTable(const SILWitnessTable &WT) { } void ModuleSummaryIndexer::indexVTable(const SILVTable &VT) { - auto typeGUID = getTypeGUID(VT.getClass()->getDeclaredType()->getCanonicalType()); + auto typeGUID = getTypeGUID(VT.getClass()); for (auto entry : VT.getEntries()) { auto Impl = entry.getImplementation(); if (entry.getMethod().kind == SILDeclRef::Kind::Deallocator || diff --git a/test/Serialization/module_summary_generic_type_ref.swift b/test/Serialization/module_summary_generic_type_ref.swift new file mode 100644 index 0000000000000..b7e001aa53711 --- /dev/null +++ b/test/Serialization/module_summary_generic_type_ref.swift @@ -0,0 +1,37 @@ +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend -emit-sib -emit-module-summary-path %t/default_wt.swiftmodule.summary -module-name default_wt -Xllvm -module-summary-embed-debug-name %s +// RUN: %swift_frontend_plain -cross-module-opt %t/default_wt.swiftmodule.summary -module-summary-embed-debug-name -o %t/default_wt.swiftmodule.merged-summary +// RUN: %swift-module-summary-test --to-yaml %t/default_wt.swiftmodule.merged-summary -o %t/default_wt.merged-summary.yaml + +// Ensure that optimizer won't eliminate PrimitiveSequenceType.getPrimitiveSequence +// RUN: %target-swift-frontend -c -module-summary-path %t/default_wt.swiftmodule.merged-summary default_wt.sib -o %t/default_wt.o +// RUN: %target-swiftc_driver %t/default_wt.o -o %t/default_wt +// RUN: %t/default_wt + +// RUN: cat %t/default_wt.merged-summary.yaml | %FileCheck %s +// CHECK: 8732890044670327403: +// CHECK-NEXT: name: '$s10default_wt11HappyStructV13requiredValueSiyF' +// CHECK-NEXT: guid: 8732890044670327403 +// CHECK-NEXT: live: true + +protocol HappyProtocol { + func requiredValue() -> Int +} + +extension HappyProtocol { + // Need to access requiredValue indirectly through wt + @_optimize(none) + func getRequiredValue() -> Int { + return requiredValue() + } +} + +struct HappyStruct : HappyProtocol { + func requiredValue() -> Int { 1 } +} + +func consume(_ v: HappyStruct) { + _ = v.getRequiredValue() +} + +consume(HappyStruct()) diff --git a/test/Serialization/module_summary_tables.swift b/test/Serialization/module_summary_tables.swift index d99bb365764df..c6d7b7dfed45f 100644 --- a/test/Serialization/module_summary_tables.swift +++ b/test/Serialization/module_summary_tables.swift @@ -18,14 +18,14 @@ // CHECK: witness_tables: // CHECK-NEXT: 2682576275888919121: // CHECK-NEXT: - guid: 767048646313834908 -// CHECK-NEXT: type_guid: 16119760784751072103 +// CHECK-NEXT: type_guid: 16808374101942615301 // `classMember` impls are recorded on the table // CHECK: vtables: // CHECK: 17602567966448237004: // CHECK-NEXT: - guid: 17602567966448237004 -// CHECK-NEXT: type_guid: 3703703597861618193 +// CHECK-NEXT: type_guid: 6261216615345887281 // CHECK-NEXT: - guid: 11756327503593502600 -// CHECK-NEXT: type_guid: 9043091933214513226 +// CHECK-NEXT: type_guid: 1726984972356197982 protocol P { func protoMember() diff --git a/test/Serialization/type_refs_summary.swift b/test/Serialization/type_refs_summary.swift index 0baa9445792d8..bf1e955cefe49 100644 --- a/test/Serialization/type_refs_summary.swift +++ b/test/Serialization/type_refs_summary.swift @@ -15,17 +15,17 @@ // SIMPLE-COERCE-NEXT: preserved: false // SIMPLE-COERCE-NEXT: calls: [] // SIMPLE-COERCE-NEXT: type_refs: -// SIMPLE-COERCE-NEXT: - name: 9type_refs1DC -// SIMPLE-COERCE-NEXT: guid: 1332210649212571009 - -// SIMPLE-COERCE: name: '$s9type_refs11coerceToAnyyypAA1CCF' -// SIMPLE-COERCE-NEXT: guid: 1940219073901329473 -// SIMPLE-COERCE-NEXT: live: false -// SIMPLE-COERCE-NEXT: preserved: false -// SIMPLE-COERCE-NEXT: calls: [] -// SIMPLE-COERCE-NEXT: type_refs: -// SIMPLE-COERCE-NEXT: - name: 9type_refs1CC -// SIMPLE-COERCE-NEXT: guid: 14053292587484144632 +// SIMPLE-COERCE-NEXT: - name: '$s9type_refs1DC' +// SIMPLE-COERCE-NEXT: guid: 9126595621082655001 + +// SIMPLE-COERCE: name: '$s9type_refs11coerceToAnyyypAA1CCF' +// SIMPLE-COERCE-NEXT: guid: 1940219073901329473 +// SIMPLE-COERCE-NEXT: live: false +// SIMPLE-COERCE-NEXT: preserved: false +// SIMPLE-COERCE-NEXT: calls: [] +// SIMPLE-COERCE-NEXT: type_refs: +// SIMPLE-COERCE-NEXT: - name: '$s9type_refs1CC' +// SIMPLE-COERCE-NEXT: guid: 3331627721515121492 // SIMPLE-COERCE: name: '$s9type_refs9coerceToPyAA1P_pAA1SVF' // SIMPLE-COERCE-NEXT: guid: 15452386893050095333 @@ -33,8 +33,8 @@ // SIMPLE-COERCE-NEXT: preserved: false // SIMPLE-COERCE-NEXT: calls: [] // SIMPLE-COERCE-NEXT: type_refs: -// SIMPLE-COERCE-NEXT: - name: 9type_refs1SV -// SIMPLE-COERCE-NEXT: guid: 12736589225588998764 +// SIMPLE-COERCE-NEXT: - name: '$s9type_refs1SV' +// SIMPLE-COERCE-NEXT: guid: 5397591673202260225 @@ -47,7 +47,7 @@ // WITNESS-IMPL: witness_tables: // WITNESS-IMPL-NEXT: 17891631795932606560: // WITNESS-IMPL-NEXT: - guid: 12925277474523063582 -// WITNESS-IMPL-NEXT: type_guid: 12736589225588998764 +// WITNESS-IMPL-NEXT: type_guid: 5397591673202260225 // Ensure that vtable impl of C.bar and D.bar have type ref to C @@ -61,9 +61,9 @@ // VTABLE-IMPL: 14897920476774525675: // VTABLE-IMPL-NEXT: - guid: 14897920476774525675 -// VTABLE-IMPL-NEXT: type_guid: 14053292587484144632 +// VTABLE-IMPL-NEXT: type_guid: 3331627721515121492 // VTABLE-IMPL-NEXT: - guid: 16977749031506698911 -// VTABLE-IMPL-NEXT: type_guid: 1332210649212571009 +// VTABLE-IMPL-NEXT: type_guid: 9126595621082655001 // RUN: %swift_frontend_plain -cross-module-opt %t/type_refs.swiftmodule.summary -module-summary-embed-debug-name -o %t/type_refs.swiftmodule.merged-summary From bcb98b91648f5ab371fe5f670dda03ba54130d23 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Sun, 16 Aug 2020 00:15:13 +0900 Subject: [PATCH 55/77] [Prototype] Fix invalid StringRef use --- lib/Serialization/ModuleSummaryIndexer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Serialization/ModuleSummaryIndexer.cpp b/lib/Serialization/ModuleSummaryIndexer.cpp index 5b37633962e8d..bcd1f95c7a5e2 100644 --- a/lib/Serialization/ModuleSummaryIndexer.cpp +++ b/lib/Serialization/ModuleSummaryIndexer.cpp @@ -102,7 +102,7 @@ void FunctionSummaryIndexer::indexDirectFunctionCall( void FunctionSummaryIndexer::indexIndirectFunctionCall( const SILDeclRef &Callee, FunctionSummary::Call::KindTy Kind) { - StringRef mangledName = Callee.mangle(); + std::string mangledName = Callee.mangle(); GUID guid = getGUIDFromUniqueName(mangledName); FunctionSummary::Call call(guid, mangledName, Kind); TheSummary->addCall(call); From 09d81ceaeab1ff55344eea4152a160a160659de1 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Sun, 16 Aug 2020 03:25:11 +0900 Subject: [PATCH 56/77] [Prototype] Implement dot export feature --- include/swift/Serialization/ModuleSummary.h | 1 + .../swift-module-summary-test.cpp | 201 +++++++++++++++++- 2 files changed, 199 insertions(+), 3 deletions(-) diff --git a/include/swift/Serialization/ModuleSummary.h b/include/swift/Serialization/ModuleSummary.h index 72f2546a0fd00..394f8ff33e349 100644 --- a/include/swift/Serialization/ModuleSummary.h +++ b/include/swift/Serialization/ModuleSummary.h @@ -259,6 +259,7 @@ class ModuleSummaryIndex { FunctionSummaryMapTy::const_iterator functions_end() const { return FunctionSummaryMap.end(); } + size_t functions_size() const { return FunctionSummaryMap.size(); } }; /// Compute a \c ModuleSummaryIndex from the given SILModule. diff --git a/tools/swift-module-summary-test/swift-module-summary-test.cpp b/tools/swift-module-summary-test/swift-module-summary-test.cpp index 664a747d050a9..e6a0b2b50cffe 100644 --- a/tools/swift-module-summary-test/swift-module-summary-test.cpp +++ b/tools/swift-module-summary-test/swift-module-summary-test.cpp @@ -17,8 +17,10 @@ #include "swift/AST/FileSystem.h" #include "swift/Basic/LLVM.h" #include "swift/Basic/LLVMInitialize.h" +#include "swift/Demangling/Demangle.h" #include "swift/Serialization/ModuleSummary.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/GraphWriter.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/YAMLParser.h" #include "llvm/Support/YAMLTraits.h" @@ -30,6 +32,7 @@ enum class ActionType : unsigned { None, BinaryToYAML, YAMLToBinary, + BinaryToDot, }; namespace options { @@ -49,9 +52,11 @@ static llvm::cl::opt llvm::cl::cat(Category), llvm::cl::values( clEnumValN(ActionType::BinaryToYAML, "to-yaml", - "Convert new binary .swiftdeps format to YAML"), + "Convert new binary .swiftmodule.summary format to YAML"), clEnumValN(ActionType::YAMLToBinary, "from-yaml", - "Convert YAML to new binary .swiftdeps format"))); + "Convert YAML to new binary .swiftmodule.summary format"), + clEnumValN(ActionType::BinaryToDot, "binary-to-dot", + "Convert new binary .swiftmodule.summary format to Dot"))); } // namespace options @@ -154,6 +159,184 @@ void MappingTraits::mapping(IO &io, ModuleSummaryIndex &V) { } // namespace yaml } // namespace llvm +VFuncSlot createVFuncSlot(FunctionSummary::Call call) { + VFuncSlot::KindTy slotKind; + switch (call.getKind()) { + case FunctionSummary::Call::Witness: { + slotKind = VFuncSlot::Witness; + break; + } + case FunctionSummary::Call::VTable: { + slotKind = VFuncSlot::VTable; + break; + } + case FunctionSummary::Call::Direct: { + llvm_unreachable("Can't get slot for static call"); + } + case FunctionSummary::Call::kindCount: { + llvm_unreachable("impossible"); + } + } + return VFuncSlot(slotKind, call.getCallee()); +} + +struct CallGraph { + struct Node; + + struct Edge { + FunctionSummary::Call Call; + GUID Target; + Node *Child; + }; + + struct Node { + FunctionSummary *FS; + SmallVector Children; + }; + + struct child_iterator + : public std::iterator { + SmallVectorImpl::iterator baseIter; + + child_iterator(SmallVectorImpl::iterator baseIter) : + baseIter(baseIter) + { } + + child_iterator &operator++() { baseIter++; return *this; } + child_iterator operator++(int) { + auto tmp = *this; + ++baseIter; + return tmp; + } + Node *operator*() const { return baseIter->Child; } + bool operator==(const child_iterator &RHS) const { + return baseIter == RHS.baseIter; + } + bool operator!=(const child_iterator &RHS) const { + return baseIter != RHS.baseIter; + } + difference_type operator-(const child_iterator &RHS) const { + return baseIter - RHS.baseIter; + } + }; + + std::vector Nodes; + using iterator = std::vector::iterator; + CallGraph(ModuleSummaryIndex *); +}; + +CallGraph::CallGraph(ModuleSummaryIndex *Summary) { + Nodes.resize(Summary->functions_size()); + llvm::DenseMap NodeMap; + int idx = 0; + for (auto FI = Summary->functions_begin(), FE = Summary->functions_end(); + FI != FE; ++FI) { + Node &node = Nodes[idx++]; + node.FS = FI->second.get(); + NodeMap[FI->first] = &node; + } + + for (Node &node : Nodes) { + for (FunctionSummary::Call call : node.FS->calls()) { + switch (call.getKind()) { + case FunctionSummary::Call::Witness: + case FunctionSummary::Call::VTable: { + VFuncSlot slot = createVFuncSlot(call); + for (auto Impl : Summary->getImplementations(slot)) { + Node *CalleeNode = NodeMap[Impl.Guid]; + node.Children.push_back({ call, Impl.Guid, CalleeNode }); + } + break; + } + case FunctionSummary::Call::Direct: { + Node *CalleeNode = NodeMap[call.getCallee()]; + node.Children.push_back({ call, call.getCallee(), CalleeNode }); + break; + } + case FunctionSummary::Call::kindCount: + llvm_unreachable("impossible"); + } + } + } +} + + +namespace llvm { + + template <> struct GraphTraits { + typedef CallGraph::child_iterator ChildIteratorType; + typedef CallGraph::Node *NodeRef; + + static NodeRef getEntryNode(NodeRef N) { return N; } + static inline ChildIteratorType child_begin(NodeRef N) { + return N->Children.begin(); + } + static inline ChildIteratorType child_end(NodeRef N) { + return N->Children.end(); + } + }; + + template <> struct GraphTraits + : public GraphTraits { + typedef CallGraph *GraphType; + typedef CallGraph::Node *NodeRef; + + static NodeRef getEntryNode(GraphType F) { return nullptr; } + + typedef pointer_iterator nodes_iterator; + static nodes_iterator nodes_begin(GraphType CG) { + return nodes_iterator(CG->Nodes.begin()); + } + static nodes_iterator nodes_end(GraphType CG) { + return nodes_iterator(CG->Nodes.end()); + } + static unsigned size(GraphType CG) { return CG->Nodes.size(); } + }; + + /// This is everything the llvm::GraphWriter needs to write the call graph in + /// a dot file. + template <> + struct DOTGraphTraits : public DefaultDOTGraphTraits { + + DOTGraphTraits(bool isSimple = false) : DefaultDOTGraphTraits(isSimple) {} + + std::string getNodeLabel(const CallGraph::Node *Node, + const CallGraph *Graph) { + Demangle::Context DCtx; + return DCtx.demangleSymbolAsString(Node->FS->getName()); + } + + static std::string getEdgeSourceLabel(const CallGraph::Node *Node, + CallGraph::child_iterator I) { + std::string Label; + raw_string_ostream O(Label); + FunctionSummary::Call call = I.baseIter->Call; + Demangle::Context DCtx; + O << DCtx.demangleSymbolAsString(call.getName()); + O << " ("; + switch (call.getKind()) { + case FunctionSummary::Call::Witness: { + O << "W"; + break; + } + case FunctionSummary::Call::VTable: { + O << "V"; + break; + } + case FunctionSummary::Call::Direct: { + O << "D"; + break; + } + case FunctionSummary::Call::kindCount: + llvm_unreachable("impossible"); + } + O << ")"; + return Label; + } + }; +} // namespace llvm + int main(int argc, char *argv[]) { PROGRAM_START(argc, argv); llvm::cl::ParseCommandLineOptions(argc, argv, "Swift Module Summary Test\n"); @@ -193,7 +376,7 @@ int main(int argc, char *argv[]) { } break; } - case ActionType::YAMLToBinary: + case ActionType::YAMLToBinary: { ModuleSummaryIndex summary; llvm::yaml::Input yamlReader(fileBufOrErr.get()->getMemBufferRef(), nullptr); @@ -209,5 +392,17 @@ int main(int argc, char *argv[]) { } break; } + case ActionType::BinaryToDot: { + modulesummary::ModuleSummaryIndex summary; + modulesummary::loadModuleSummaryIndex(fileBufOrErr.get()->getMemBufferRef(), + summary); + CallGraph CG(&summary); + withOutputFile(diags, options::OutputFilename, [&](raw_ostream &out) { + llvm::WriteGraph(out, &CG); + return false; + }); + break; + } + } return 0; } From 3a7b5f59acd0b51cdf5e5e32c73e9763a6d527b7 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Sun, 16 Aug 2020 03:33:05 +0900 Subject: [PATCH 57/77] [Prototype] Keep call unique --- lib/Serialization/ModuleSummaryIndexer.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/lib/Serialization/ModuleSummaryIndexer.cpp b/lib/Serialization/ModuleSummaryIndexer.cpp index bcd1f95c7a5e2..13641695c2077 100644 --- a/lib/Serialization/ModuleSummaryIndexer.cpp +++ b/lib/Serialization/ModuleSummaryIndexer.cpp @@ -30,6 +30,9 @@ class FunctionSummaryIndexer : public SILInstructionVisitor TheSummary; std::set RecordedTypes; + std::set RecordedDirectTargets; + std::set RecordedVTableTargets; + std::set RecordedWitnessTargets; void indexDirectFunctionCall(const SILFunction &Callee); void indexIndirectFunctionCall(const SILDeclRef &Callee, @@ -95,6 +98,9 @@ class FunctionSummaryIndexer : public SILInstructionVisitoraddCall(call); @@ -104,6 +110,11 @@ void FunctionSummaryIndexer::indexIndirectFunctionCall( const SILDeclRef &Callee, FunctionSummary::Call::KindTy Kind) { std::string mangledName = Callee.mangle(); GUID guid = getGUIDFromUniqueName(mangledName); + std::set &RecordedTargets = Kind == FunctionSummary::Call::VTable ? + RecordedVTableTargets : RecordedWitnessTargets; + if (!RecordedTargets.insert(guid).second) { + return; + } FunctionSummary::Call call(guid, mangledName, Kind); TheSummary->addCall(call); } From 4e9ba8cfbad50ceda9d3dab79a56c949018f2bf4 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Sun, 16 Aug 2020 09:51:41 +0900 Subject: [PATCH 58/77] [Prototype] Improve dot export stlyle --- .../swift-module-summary-test.cpp | 38 ++++++++++++------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/tools/swift-module-summary-test/swift-module-summary-test.cpp b/tools/swift-module-summary-test/swift-module-summary-test.cpp index e6a0b2b50cffe..e12a7aeb56310 100644 --- a/tools/swift-module-summary-test/swift-module-summary-test.cpp +++ b/tools/swift-module-summary-test/swift-module-summary-test.cpp @@ -47,6 +47,10 @@ static llvm::cl::opt OutputFilename("o", llvm::cl::desc("Override output filename"), llvm::cl::value_desc("filename")); +static llvm::cl::opt + OmitDeadSymbol("omit-dead-symbol", llvm::cl::init(false), + llvm::cl::desc("Omit dead symbols")); + static llvm::cl::opt Action(llvm::cl::desc("Mode:"), llvm::cl::init(ActionType::None), llvm::cl::cat(Category), @@ -192,6 +196,7 @@ struct CallGraph { struct Node { FunctionSummary *FS; SmallVector Children; + Node(FunctionSummary *FS) : FS(FS), Children() {} }; struct child_iterator @@ -227,13 +232,12 @@ struct CallGraph { }; CallGraph::CallGraph(ModuleSummaryIndex *Summary) { - Nodes.resize(Summary->functions_size()); llvm::DenseMap NodeMap; - int idx = 0; for (auto FI = Summary->functions_begin(), FE = Summary->functions_end(); FI != FE; ++FI) { - Node &node = Nodes[idx++]; - node.FS = FI->second.get(); + if (options::OmitDeadSymbol && !FI->second->isLive()) continue; + Nodes.emplace_back(FI->second.get()); + Node &node = Nodes.back(); NodeMap[FI->first] = &node; } @@ -307,31 +311,39 @@ namespace llvm { return DCtx.demangleSymbolAsString(Node->FS->getName()); } - static std::string getEdgeSourceLabel(const CallGraph::Node *Node, - CallGraph::child_iterator I) { + static std::string getNodeAttributes(const CallGraph::Node *Node, + const CallGraph *Graph) { + std::string color = Node->FS->isLive() ? "green" : "red"; + std::string attrs = "color=\"" + color + "\""; + return attrs; + } + + static std::string getEdgeAttributes(const CallGraph::Node *Node, + CallGraph::child_iterator I, + const CallGraph *Graph) { std::string Label; raw_string_ostream O(Label); - FunctionSummary::Call call = I.baseIter->Call; Demangle::Context DCtx; - O << DCtx.demangleSymbolAsString(call.getName()); - O << " ("; + FunctionSummary::Call call = I.baseIter->Call; + std::string demangled = DCtx.demangleSymbolAsString(call.getName()); + O << "label=\""; switch (call.getKind()) { case FunctionSummary::Call::Witness: { - O << "W"; + O << "(W) " << demangled; break; } case FunctionSummary::Call::VTable: { - O << "V"; + O << "(V) " << demangled; break; } case FunctionSummary::Call::Direct: { - O << "D"; + O << "(D)"; break; } case FunctionSummary::Call::kindCount: llvm_unreachable("impossible"); } - O << ")"; + O << "\""; return Label; } }; From 29c5ef3561d481b64d24fd36bd523df1081038fe Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Sun, 16 Aug 2020 21:01:42 +0900 Subject: [PATCH 59/77] [Prototype] Mark main entry function as preserved --- lib/Serialization/ModuleSummaryIndexer.cpp | 4 ++++ tools/driver/cross_module_opt_main.cpp | 1 - 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/Serialization/ModuleSummaryIndexer.cpp b/lib/Serialization/ModuleSummaryIndexer.cpp index 13641695c2077..ec66f12dd9630 100644 --- a/lib/Serialization/ModuleSummaryIndexer.cpp +++ b/lib/Serialization/ModuleSummaryIndexer.cpp @@ -302,6 +302,10 @@ void FunctionSummaryIndexer::visitKeyPathInst(KeyPathInst *KPI) { } bool shouldPreserveFunction(const SILFunction &F) { + if (F.getName().equals(SWIFT_ENTRY_POINT_FUNCTION)) { + return true; + } + if (F.getRepresentation() == SILFunctionTypeRepresentation::ObjCMethod) { return true; } diff --git a/tools/driver/cross_module_opt_main.cpp b/tools/driver/cross_module_opt_main.cpp index 922ac9ee72cca..922d06cd4a3dc 100644 --- a/tools/driver/cross_module_opt_main.cpp +++ b/tools/driver/cross_module_opt_main.cpp @@ -37,7 +37,6 @@ static llvm::cl::opt static llvm::DenseSet computePreservedGUIDs(ModuleSummaryIndex *summary) { llvm::DenseSet Set(1); - Set.insert(getGUIDFromUniqueName("main")); for (auto FI = summary->functions_begin(), FE = summary->functions_end(); FI != FE; ++FI) { auto summary = FI->second.get(); From e2a20f264ffaba1bf30994879670e5bc9001dd28 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Sun, 16 Aug 2020 23:08:48 +0900 Subject: [PATCH 60/77] [Prototype] Create Dominator Tree --- .../swift-module-summary-test.cpp | 194 ++++++++++++------ 1 file changed, 134 insertions(+), 60 deletions(-) diff --git a/tools/swift-module-summary-test/swift-module-summary-test.cpp b/tools/swift-module-summary-test/swift-module-summary-test.cpp index e12a7aeb56310..191dbbe100512 100644 --- a/tools/swift-module-summary-test/swift-module-summary-test.cpp +++ b/tools/swift-module-summary-test/swift-module-summary-test.cpp @@ -20,6 +20,8 @@ #include "swift/Demangling/Demangle.h" #include "swift/Serialization/ModuleSummary.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/GenericDomTree.h" +#include "llvm/Support/GenericDomTreeConstruction.h" #include "llvm/Support/GraphWriter.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/YAMLParser.h" @@ -32,6 +34,7 @@ enum class ActionType : unsigned { None, BinaryToYAML, YAMLToBinary, + BinaryToDominators, BinaryToDot, }; @@ -51,16 +54,19 @@ static llvm::cl::opt OmitDeadSymbol("omit-dead-symbol", llvm::cl::init(false), llvm::cl::desc("Omit dead symbols")); -static llvm::cl::opt - Action(llvm::cl::desc("Mode:"), llvm::cl::init(ActionType::None), - llvm::cl::cat(Category), - llvm::cl::values( - clEnumValN(ActionType::BinaryToYAML, "to-yaml", - "Convert new binary .swiftmodule.summary format to YAML"), - clEnumValN(ActionType::YAMLToBinary, "from-yaml", - "Convert YAML to new binary .swiftmodule.summary format"), - clEnumValN(ActionType::BinaryToDot, "binary-to-dot", - "Convert new binary .swiftmodule.summary format to Dot"))); +static llvm::cl::opt Action( + llvm::cl::desc("Mode:"), llvm::cl::init(ActionType::None), + llvm::cl::cat(Category), + llvm::cl::values( + clEnumValN(ActionType::BinaryToYAML, "to-yaml", + "Convert new binary .swiftmodule.summary format to YAML"), + clEnumValN(ActionType::YAMLToBinary, "from-yaml", + "Convert YAML to new binary .swiftmodule.summary format"), + clEnumValN( + ActionType::BinaryToDominators, "binary-to-dom", + "Convert new binary .swiftmodule.summary format to dominator tree"), + clEnumValN(ActionType::BinaryToDot, "binary-to-dot", + "Convert new binary .swiftmodule.summary format to Dot"))); } // namespace options @@ -190,72 +196,73 @@ struct CallGraph { struct Edge { FunctionSummary::Call Call; GUID Target; - Node *Child; }; struct Node { - FunctionSummary *FS; - SmallVector Children; - Node(FunctionSummary *FS) : FS(FS), Children() {} - }; - - struct child_iterator - : public std::iterator { - SmallVectorImpl::iterator baseIter; - - child_iterator(SmallVectorImpl::iterator baseIter) : - baseIter(baseIter) - { } - - child_iterator &operator++() { baseIter++; return *this; } - child_iterator operator++(int) { - auto tmp = *this; - ++baseIter; - return tmp; - } - Node *operator*() const { return baseIter->Child; } - bool operator==(const child_iterator &RHS) const { - return baseIter == RHS.baseIter; - } - bool operator!=(const child_iterator &RHS) const { - return baseIter != RHS.baseIter; - } - difference_type operator-(const child_iterator &RHS) const { - return baseIter - RHS.baseIter; + GUID Guid; + CallGraph *Parent; + std::vector Children; + std::vector PredChildren; + std::vector Edges; + + CallGraph *getParent() const { return Parent; } + + void printAsOperand(raw_ostream &OS, bool /*PrintType*/) { + FunctionSummary *FS = Parent->Summary.getFunctionSummary(Guid); + if (!FS) { + OS << "Entry node"; + return; + } + OS << "Fn#" << FS->getName(); } }; + using child_iterator = std::vector::iterator; + std::vector Nodes; + Node EntryNode; + ModuleSummaryIndex Summary; using iterator = std::vector::iterator; - CallGraph(ModuleSummaryIndex *); + CallGraph(ModuleSummaryIndex); }; -CallGraph::CallGraph(ModuleSummaryIndex *Summary) { - llvm::DenseMap NodeMap; - for (auto FI = Summary->functions_begin(), FE = Summary->functions_end(); +CallGraph::CallGraph(ModuleSummaryIndex Summary) : Nodes(), EntryNode() { + std::map NodeMap; + Nodes.resize(Summary.functions_size()); + int idx = 0; + for (auto FI = Summary.functions_begin(), FE = Summary.functions_end(); FI != FE; ++FI) { - if (options::OmitDeadSymbol && !FI->second->isLive()) continue; - Nodes.emplace_back(FI->second.get()); - Node &node = Nodes.back(); - NodeMap[FI->first] = &node; + Node *node = &Nodes[idx++]; + node->Guid = FI->first; + node->Parent = this; + NodeMap[FI->first] = node; + if (FI->second->isPreserved()) { + EntryNode.Children.push_back(node); + EntryNode.PredChildren.push_back(node); + } } + EntryNode.Parent = this; for (Node &node : Nodes) { - for (FunctionSummary::Call call : node.FS->calls()) { + FunctionSummary *FS = Summary.getFunctionSummary(node.Guid); + for (FunctionSummary::Call call : FS->calls()) { switch (call.getKind()) { case FunctionSummary::Call::Witness: case FunctionSummary::Call::VTable: { VFuncSlot slot = createVFuncSlot(call); - for (auto Impl : Summary->getImplementations(slot)) { + for (auto Impl : Summary.getImplementations(slot)) { Node *CalleeNode = NodeMap[Impl.Guid]; - node.Children.push_back({ call, Impl.Guid, CalleeNode }); + node.Children.push_back(CalleeNode); + node.PredChildren.push_back(CalleeNode); + node.Edges.push_back({call, Impl.Guid}); } break; } case FunctionSummary::Call::Direct: { Node *CalleeNode = NodeMap[call.getCallee()]; - node.Children.push_back({ call, call.getCallee(), CalleeNode }); + node.Children.push_back(CalleeNode); + node.PredChildren.push_back(CalleeNode); + node.Edges.push_back({call, call.getCallee()}); break; } case FunctionSummary::Call::kindCount: @@ -263,9 +270,9 @@ CallGraph::CallGraph(ModuleSummaryIndex *Summary) { } } } + this->Summary = std::move(Summary); } - namespace llvm { template <> struct GraphTraits { @@ -281,13 +288,28 @@ namespace llvm { } }; + template <> struct GraphTraits> { + using ChildIteratorType = CallGraph::child_iterator; + using Node = CallGraph::Node; + using NodeRef = Node *; + static NodeRef getEntryNode(Inverse G) { + return G.Graph; + } + static inline ChildIteratorType child_begin(NodeRef N) { + return N->PredChildren.begin(); + } + static inline ChildIteratorType child_end(NodeRef N) { + return N->PredChildren.end(); + } + }; + template <> struct GraphTraits : public GraphTraits { typedef CallGraph *GraphType; typedef CallGraph::Node *NodeRef; - - static NodeRef getEntryNode(GraphType F) { return nullptr; } - + + static NodeRef getEntryNode(GraphType G) { return &G->EntryNode; } + typedef pointer_iterator nodes_iterator; static nodes_iterator nodes_begin(GraphType CG) { return nodes_iterator(CG->Nodes.begin()); @@ -307,13 +329,15 @@ namespace llvm { std::string getNodeLabel(const CallGraph::Node *Node, const CallGraph *Graph) { + FunctionSummary *FS = Graph->Summary.getFunctionSummary(Node->Guid); Demangle::Context DCtx; - return DCtx.demangleSymbolAsString(Node->FS->getName()); + return DCtx.demangleSymbolAsString(FS->getName()); } static std::string getNodeAttributes(const CallGraph::Node *Node, const CallGraph *Graph) { - std::string color = Node->FS->isLive() ? "green" : "red"; + FunctionSummary *FS = Graph->Summary.getFunctionSummary(Node->Guid); + std::string color = FS->isLive() ? "green" : "red"; std::string attrs = "color=\"" + color + "\""; return attrs; } @@ -321,10 +345,12 @@ namespace llvm { static std::string getEdgeAttributes(const CallGraph::Node *Node, CallGraph::child_iterator I, const CallGraph *Graph) { + unsigned ChildIdx = I - Node->Children.begin(); std::string Label; raw_string_ostream O(Label); Demangle::Context DCtx; - FunctionSummary::Call call = I.baseIter->Call; + CallGraph::Edge edge = Node->Edges[ChildIdx]; + FunctionSummary::Call call = edge.Call; std::string demangled = DCtx.demangleSymbolAsString(call.getName()); O << "label=\""; switch (call.getKind()) { @@ -348,6 +374,47 @@ namespace llvm { } }; } // namespace llvm +using DomCallTreeBase = llvm::DominatorTreeBase; +using DomCallInfoNode = llvm::DomTreeNodeBase; + +namespace llvm { + +template <> struct GraphTraits { + using ChildIteratorType = DomCallInfoNode::iterator; + using NodeRef = DomCallInfoNode *; + + static NodeRef getEntryNode(NodeRef N) { return N; } + static inline ChildIteratorType child_begin(NodeRef N) { return N->begin(); } + static inline ChildIteratorType child_end(NodeRef N) { return N->end(); } +}; + +template <> struct GraphTraits { + using ChildIteratorType = DomCallInfoNode::const_iterator; + using NodeRef = const DomCallInfoNode *; + + static NodeRef getEntryNode(NodeRef N) { return N; } + static inline ChildIteratorType child_begin(NodeRef N) { return N->begin(); } + static inline ChildIteratorType child_end(NodeRef N) { return N->end(); } +}; + +namespace DomTreeBuilder { +extern template void Calculate(DomCallTreeBase &DT); +template void Calculate(DomCallTreeBase &DT); +} // namespace DomTreeBuilder +} // namespace llvm + +class DomCallTree : public DomCallTreeBase { + using super = DominatorTreeBase; + +public: + DomCallTree(CallGraph &CG) : DominatorTreeBase() { recalculate(CG); } +}; + +int dominance_analysis(CallGraph &CG) { + DomCallTree DT(CG); + DT.print(llvm::dbgs()); + return 0; +}; int main(int argc, char *argv[]) { PROGRAM_START(argc, argv); @@ -408,13 +475,20 @@ int main(int argc, char *argv[]) { modulesummary::ModuleSummaryIndex summary; modulesummary::loadModuleSummaryIndex(fileBufOrErr.get()->getMemBufferRef(), summary); - CallGraph CG(&summary); + CallGraph CG(std::move(summary)); withOutputFile(diags, options::OutputFilename, [&](raw_ostream &out) { llvm::WriteGraph(out, &CG); return false; }); break; } + case ActionType::BinaryToDominators: { + modulesummary::ModuleSummaryIndex summary; + modulesummary::loadModuleSummaryIndex(fileBufOrErr.get()->getMemBufferRef(), + summary); + CallGraph CG(std::move(summary)); + return dominance_analysis(CG); + } } return 0; } From 9400c5094a293dc960fc330a29d086e990389e3a Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Mon, 17 Aug 2020 00:24:14 +0900 Subject: [PATCH 61/77] [Prototype] Print dominant instruction size --- include/swift/Serialization/ModuleSummary.h | 5 ++ lib/Serialization/ModuleSummaryFormat.cpp | 7 ++- lib/Serialization/ModuleSummaryFormat.h | 2 + lib/Serialization/ModuleSummaryIndexer.cpp | 4 +- .../swift-module-summary-test.cpp | 62 ++++++++++++++++++- 5 files changed, 75 insertions(+), 5 deletions(-) diff --git a/include/swift/Serialization/ModuleSummary.h b/include/swift/Serialization/ModuleSummary.h index 394f8ff33e349..97520c195f7f7 100644 --- a/include/swift/Serialization/ModuleSummary.h +++ b/include/swift/Serialization/ModuleSummary.h @@ -99,6 +99,8 @@ class FunctionSummary { TypeRefListTy TypeRefList; /// The symbol name of the function only for debug and test purposes. std::string Name; + /// Size of instructions only for debug purpose + size_t InstSize; public: FunctionSummary() = default; @@ -126,6 +128,9 @@ class FunctionSummary { void setName(std::string name) { this->Name = name; } GUID getGUID() const { return Guid; } + + size_t getInstSize() const { return InstSize; } + void setInstSize(size_t size) { this->InstSize = size; } }; /// A slot in a set of virtual tables. diff --git a/lib/Serialization/ModuleSummaryFormat.cpp b/lib/Serialization/ModuleSummaryFormat.cpp index 078e5d06249d6..d4369d7808854 100644 --- a/lib/Serialization/ModuleSummaryFormat.cpp +++ b/lib/Serialization/ModuleSummaryFormat.cpp @@ -122,7 +122,7 @@ void Serializer::emitFunctionSummary(const FunctionSummary *summary) { FunctionMetadataLayout::emitRecord( Out, ScratchRecord, AbbrCodes[FunctionMetadataLayout::Code], summary->getGUID(), unsigned(summary->isLive()), - unsigned(summary->isPreserved()), debugFuncName); + unsigned(summary->isPreserved()), summary->getInstSize(), debugFuncName); for (auto call : summary->calls()) { std::string debugName = ModuleSummaryEmbedDebugName ? call.getName() : ""; @@ -361,8 +361,10 @@ bool Deserializer::readModuleSummary() { std::string name; unsigned isLive, isPreserved; bool shouldMerge = false; + uint32_t instSize; - FunctionMetadataLayout::readRecord(Scratch, guid, isLive, isPreserved); + FunctionMetadataLayout::readRecord(Scratch, guid, isLive, isPreserved, + instSize); name = BlobData.str(); if (auto summary = moduleSummary.getFunctionSummary(guid)) { CurrentFunc = summary; @@ -382,6 +384,7 @@ bool Deserializer::readModuleSummary() { if (!shouldMerge || !name.empty()) { CurrentFunc->setName(name); } + CurrentFunc->setInstSize(instSize); break; } case CALL_GRAPH_EDGE: { diff --git a/lib/Serialization/ModuleSummaryFormat.h b/lib/Serialization/ModuleSummaryFormat.h index 4ccf0b43e9c86..f3e8f6472a9ac 100644 --- a/lib/Serialization/ModuleSummaryFormat.h +++ b/lib/Serialization/ModuleSummaryFormat.h @@ -23,6 +23,7 @@ namespace modulesummary { using llvm::BCBlob; using llvm::BCFixed; using llvm::BCRecordLayout; +using llvm::BCVBR; const unsigned char MODULE_SUMMARY_SIGNATURE[] = {'M', 'O', 'D', 'S'}; const unsigned RECORD_BLOCK_ID = llvm::bitc::FIRST_APPLICATION_BLOCKID; @@ -48,6 +49,7 @@ using FunctionMetadataLayout = BCRecordLayout, // live BCFixed<1>, // preserved + BCVBR<16>, // instruction size BCBlob // name (debug purpose) >; using CallGraphEdgeLayout = diff --git a/lib/Serialization/ModuleSummaryIndexer.cpp b/lib/Serialization/ModuleSummaryIndexer.cpp index ec66f12dd9630..fbda6a0701c49 100644 --- a/lib/Serialization/ModuleSummaryIndexer.cpp +++ b/lib/Serialization/ModuleSummaryIndexer.cpp @@ -320,14 +320,17 @@ bool shouldPreserveFunction(const SILFunction &F) { void FunctionSummaryIndexer::indexFunction() { GUID guid = getGUIDFromUniqueName(F.getName()); + size_t instSize = 0; TheSummary = std::make_unique(guid); TheSummary->setName(F.getName()); for (auto &BB : F) { for (auto &I : BB) { visit(&I); + instSize++; } } TheSummary->setPreserved(shouldPreserveFunction(F)); + TheSummary->setInstSize(instSize); } class ModuleSummaryIndexer { @@ -447,7 +450,6 @@ void ModuleSummaryIndexer::indexModule() { FunctionSummaryIndexer indexer(F); indexer.indexFunction(); std::unique_ptr FS = indexer.takeSummary(); - FS->setPreserved(shouldPreserveFunction(F)); TheSummary->addFunctionSummary(std::move(FS)); } diff --git a/tools/swift-module-summary-test/swift-module-summary-test.cpp b/tools/swift-module-summary-test/swift-module-summary-test.cpp index 191dbbe100512..fdbc5c73aebfc 100644 --- a/tools/swift-module-summary-test/swift-module-summary-test.cpp +++ b/tools/swift-module-summary-test/swift-module-summary-test.cpp @@ -207,6 +207,10 @@ struct CallGraph { CallGraph *getParent() const { return Parent; } + FunctionSummary *getFS() const { + return Parent->Summary.getFunctionSummary(Guid); + } + void printAsOperand(raw_ostream &OS, bool /*PrintType*/) { FunctionSummary *FS = Parent->Summary.getFunctionSummary(Guid); if (!FS) { @@ -410,9 +414,55 @@ class DomCallTree : public DomCallTreeBase { DomCallTree(CallGraph &CG) : DominatorTreeBase() { recalculate(CG); } }; +class RetainedSizeCalculator { + struct Entry { + DomCallInfoNode *DomNode; + size_t InstSize; + }; + std::map SizeCache; + std::vector Entries; + + size_t getInstSize(DomCallInfoNode *domNode) { + auto FS = domNode->getBlock()->getFS(); + size_t size = FS->getInstSize(); + for (auto I = domNode->begin(), E = domNode->end(); I != E; ++I) { + auto Child = *I; + size += getInstSize(Child); + } + SizeCache[domNode] = size; + return size; + } + + void calculateRecursively(DomCallInfoNode *domNode) { + Entries.push_back({domNode, getInstSize(domNode)}); + for (auto child : domNode->getChildren()) { + calculateRecursively(child); + } + } + +public: + void calculate(DomCallInfoNode *root) { + for (auto child : root->getChildren()) { + calculateRecursively(child); + } + std::sort(Entries.begin(), Entries.end(), + [](Entry lhs, Entry rhs) { return lhs.InstSize > rhs.InstSize; }); + } + + void display(llvm::raw_ostream &O) { + for (auto entry : Entries) { + auto FS = entry.DomNode->getBlock()->getFS(); + O << entry.InstSize << "\t| " << FS->getName() << "\n"; + } + } +}; + int dominance_analysis(CallGraph &CG) { DomCallTree DT(CG); - DT.print(llvm::dbgs()); + DomCallInfoNode *Root = DT.getRootNode(); + RetainedSizeCalculator calculator; + calculator.calculate(Root); + calculator.display(llvm::dbgs()); return 0; }; @@ -487,7 +537,15 @@ int main(int argc, char *argv[]) { modulesummary::loadModuleSummaryIndex(fileBufOrErr.get()->getMemBufferRef(), summary); CallGraph CG(std::move(summary)); - return dominance_analysis(CG); + DomCallTree DT(CG); + DomCallInfoNode *Root = DT.getRootNode(); + RetainedSizeCalculator calculator; + calculator.calculate(Root); + withOutputFile(diags, options::OutputFilename, [&](raw_ostream &out) { + calculator.display(out); + return false; + }); + break; } } return 0; From 361daa1e7fdef1ceb040102ca46928735214c347 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Mon, 17 Aug 2020 01:29:38 +0900 Subject: [PATCH 62/77] [Prototype] Add table header for dominator list --- tools/swift-module-summary-test/swift-module-summary-test.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/swift-module-summary-test/swift-module-summary-test.cpp b/tools/swift-module-summary-test/swift-module-summary-test.cpp index fdbc5c73aebfc..354a89197709a 100644 --- a/tools/swift-module-summary-test/swift-module-summary-test.cpp +++ b/tools/swift-module-summary-test/swift-module-summary-test.cpp @@ -450,6 +450,7 @@ class RetainedSizeCalculator { } void display(llvm::raw_ostream &O) { + O << "size\t| symbol\n"; for (auto entry : Entries) { auto FS = entry.DomNode->getBlock()->getFS(); O << entry.InstSize << "\t| " << FS->getName() << "\n"; From 03f4a05112ca8a0d78a1e787eed33f93b72d805f Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Mon, 17 Aug 2020 01:33:47 +0900 Subject: [PATCH 63/77] [Prototype] Implement eager elimination which disable debug print --- lib/Serialization/ModuleSummaryIndexer.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/lib/Serialization/ModuleSummaryIndexer.cpp b/lib/Serialization/ModuleSummaryIndexer.cpp index fbda6a0701c49..e172e66b69cf3 100644 --- a/lib/Serialization/ModuleSummaryIndexer.cpp +++ b/lib/Serialization/ModuleSummaryIndexer.cpp @@ -4,11 +4,17 @@ #include "swift/SIL/SILModule.h" #include "swift/SIL/SILVisitor.h" #include "swift/Serialization/ModuleSummary.h" +#include "llvm/Support/CommandLine.h" #include "llvm/Support/MD5.h" #include "llvm/Support/raw_ostream.h" #define DEBUG_TYPE "module-summary-index" +static llvm::cl::opt EagerElimination( + "module-summary-eager-elim", llvm::cl::init(false), + llvm::cl::desc( + "Enable eager elimination which doesn't support debug print")); + using namespace swift; using namespace modulesummary; @@ -302,6 +308,12 @@ void FunctionSummaryIndexer::visitKeyPathInst(KeyPathInst *KPI) { } bool shouldPreserveFunction(const SILFunction &F) { + if (EagerElimination && + (F.getName().equals("swift_unexpectedError") || + F.getName().equals("swift_errorInMain") || + F.getName().equals("$ss23_getErrorDomainNSStringyyXlSPyxGs0B0RzlF"))) { + return false; + } if (F.getName().equals(SWIFT_ENTRY_POINT_FUNCTION)) { return true; } From 5d22d4fe66f990c6182bb46e94caf3c10b82fc3a Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Mon, 17 Aug 2020 12:17:45 +0000 Subject: [PATCH 64/77] [Prototype] Fix swift-module-summary-test link libraries --- tools/swift-module-summary-test/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/swift-module-summary-test/CMakeLists.txt b/tools/swift-module-summary-test/CMakeLists.txt index 26959c266cf58..6abe01902a77b 100644 --- a/tools/swift-module-summary-test/CMakeLists.txt +++ b/tools/swift-module-summary-test/CMakeLists.txt @@ -7,4 +7,6 @@ add_swift_host_tool(swift-module-summary-test target_link_libraries(swift-module-summary-test PRIVATE + swiftAST + swiftDemangling swiftSerialization) From 1dea85593e9fe4cb0d7dda4de5fe1ee916bea16d Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Tue, 18 Aug 2020 02:59:59 +0900 Subject: [PATCH 65/77] [Prototype] Implement public KeyPath elimination --- include/swift/SIL/SILInstruction.h | 5 +- include/swift/SIL/SILProperty.h | 9 +++- lib/IRGen/GenKeyPath.cpp | 42 ++++++++++----- lib/SIL/IR/SILInstructions.cpp | 51 +++++++++++++++++++ .../IPO/CrossDeadFunctionElimination.cpp | 12 +++++ 5 files changed, 103 insertions(+), 16 deletions(-) diff --git a/include/swift/SIL/SILInstruction.h b/include/swift/SIL/SILInstruction.h index dd9e3731b9ac9..3a5c44cccec44 100644 --- a/include/swift/SIL/SILInstruction.h +++ b/include/swift/SIL/SILInstruction.h @@ -2953,7 +2953,10 @@ class KeyPathPatternComponent { void visitReferencedFunctionsAndMethods( std::function functionCallBack, std::function methodCallBack) const; - + + void clearReferencedFunctions_if( + llvm::function_ref predicate); + void incrementRefCounts() const; void decrementRefCounts() const; diff --git a/include/swift/SIL/SILProperty.h b/include/swift/SIL/SILProperty.h index d1bddb6010da1..b4cb16f762840 100644 --- a/include/swift/SIL/SILProperty.h +++ b/include/swift/SIL/SILProperty.h @@ -67,7 +67,14 @@ class SILProperty : public llvm::ilist_node, const Optional &getComponent() const { return Component; } - + + void clearReferencedFunctions_if( + llvm::function_ref predicate) { + if (Component) { + Component->clearReferencedFunctions_if(predicate); + } + } + void print(SILPrintContext &Ctx) const; void dump() const; diff --git a/lib/IRGen/GenKeyPath.cpp b/lib/IRGen/GenKeyPath.cpp index 41128f62b8620..65b3cb77c5870 100644 --- a/lib/IRGen/GenKeyPath.cpp +++ b/lib/IRGen/GenKeyPath.cpp @@ -119,7 +119,11 @@ getAccessorForComputedComponent(IRGenModule &IGM, accessor = component.getSubscriptIndexHash(); break; } - + + if (!accessor) { + return nullptr; + } + // If the accessor is not generic, and locally available, we can use it as is. // If it's only externally available, we need a local thunk to relative- // reference. @@ -510,10 +514,18 @@ getWitnessTableForComputedComponent(IRGenModule &IGM, fields.addNullPointer(IGM.FunctionPtrTy); fields.addSignedPointer(copy, schemaKeyPath, PointerAuthEntity::Special::KeyPathCopy); - fields.addSignedPointer(equals, schemaKeyPath, - PointerAuthEntity::Special::KeyPathEquals); - fields.addSignedPointer(hash, schemaKeyPath, - PointerAuthEntity::Special::KeyPathHash); + if (equals) + fields.addSignedPointer(equals, schemaKeyPath, + PointerAuthEntity::Special::KeyPathEquals); + else + fields.addNullPointer(IGM.FunctionPtrTy); + + if (hash) + fields.addSignedPointer(hash, schemaKeyPath, + PointerAuthEntity::Special::KeyPathHash); + else + fields.addNullPointer(IGM.FunctionPtrTy); + return fields.finishAndCreateGlobal( "keypath_witnesses", IGM.getPointerAlignment(), /*constant*/ true, llvm::GlobalVariable::PrivateLinkage); @@ -914,6 +926,11 @@ emitKeyPathComponent(IRGenModule &IGM, switch (id.getKind()) { case KeyPathPatternComponent::ComputedPropertyId::Function: { idKind = KeyPathComponentHeader::Pointer; + if (!id.getFunction()) { + idValue = nullptr; + idResolution = KeyPathComponentHeader::Resolved; + break; + } // FIXME: Does this need to be signed? auto idRef = IGM.getAddrOfLLVMVariableOrGOTEquivalent( LinkEntity::forSILFunction(id.getFunction(), false)); @@ -1066,7 +1083,7 @@ emitKeyPathComponent(IRGenModule &IGM, switch (idKind) { case KeyPathComponentHeader::Pointer: // Use a relative offset to the referent. - fields.addRelativeAddress(idValue); + fields.addRelativeAddressOrNull(idValue); break; case KeyPathComponentHeader::VTableOffset: @@ -1077,15 +1094,12 @@ emitKeyPathComponent(IRGenModule &IGM, } // Push the accessors, possibly thunked to marshal generic environment. - fields.addRelativeAddress( - getAccessorForComputedComponent(IGM, component, Getter, - genericEnv, requirements, - hasSubscriptIndices)); + fields.addRelativeAddressOrNull(getAccessorForComputedComponent( + IGM, component, Getter, genericEnv, requirements, hasSubscriptIndices)); if (settable) - fields.addRelativeAddress( - getAccessorForComputedComponent(IGM, component, Setter, - genericEnv, requirements, - hasSubscriptIndices)); + fields.addRelativeAddressOrNull( + getAccessorForComputedComponent(IGM, component, Setter, genericEnv, + requirements, hasSubscriptIndices)); if (!isInstantiableOnce) { // If there's generic context or subscript indexes, embed as diff --git a/lib/SIL/IR/SILInstructions.cpp b/lib/SIL/IR/SILInstructions.cpp index 85e21ea609f21..f33faa288dc0c 100644 --- a/lib/SIL/IR/SILInstructions.cpp +++ b/lib/SIL/IR/SILInstructions.cpp @@ -2530,6 +2530,57 @@ forEachRefcountableReference(const KeyPathPatternComponent &component, } } +void KeyPathPatternComponent::clearReferencedFunctions_if( + llvm::function_ref predicate) { + switch (getKind()) { + case KeyPathPatternComponent::Kind::StoredProperty: + case KeyPathPatternComponent::Kind::OptionalChain: + case KeyPathPatternComponent::Kind::OptionalWrap: + case KeyPathPatternComponent::Kind::OptionalForce: + case KeyPathPatternComponent::Kind::TupleElement: + return; + case KeyPathPatternComponent::Kind::SettableProperty: { + auto setter = getComputedPropertySetter(); + if (predicate(setter)) { + SetterAndIdKind.setPointer(nullptr); + } + LLVM_FALLTHROUGH; + } + case KeyPathPatternComponent::Kind::GettableProperty: + auto getter = getComputedPropertyGetter(); + if (predicate(getter)) { + ValueAndKind.setPointer(nullptr); + } + switch (getComputedPropertyId().getKind()) { + case KeyPathPatternComponent::ComputedPropertyId::DeclRef: + // Mark the vtable entry as used somehow? + break; + case KeyPathPatternComponent::ComputedPropertyId::Function: { + auto idFn = getComputedPropertyId().getFunction(); + if (predicate(idFn)) { + IdValue = ComputedPropertyId::ValueType(); + } + break; + } + case KeyPathPatternComponent::ComputedPropertyId::Property: + break; + } + + if (auto equals = getSubscriptIndexEquals()) { + if (predicate(equals)) { + IndexEquality.Equal = nullptr; + } + } + + if (auto hash = getSubscriptIndexHash()) { + if (predicate(hash)) { + IndexEquality.Hash = nullptr; + } + } + return; + } +} + void KeyPathPatternComponent::incrementRefCounts() const { forEachRefcountableReference(*this, [&](SILFunction *f) { f->incrementRefCount(); }); diff --git a/lib/SILOptimizer/IPO/CrossDeadFunctionElimination.cpp b/lib/SILOptimizer/IPO/CrossDeadFunctionElimination.cpp index d412de9064d08..24b1805f12610 100644 --- a/lib/SILOptimizer/IPO/CrossDeadFunctionElimination.cpp +++ b/lib/SILOptimizer/IPO/CrossDeadFunctionElimination.cpp @@ -113,6 +113,17 @@ class SILCrossDeadFuncElimination : public SILModuleTransform { } } + void cleanupSILProperty(SILModule &M, + const std::vector &DeadFunctions) { + std::set DeadFunctionsSet(DeadFunctions.begin(), + DeadFunctions.end()); + for (SILProperty &P : M.getPropertyList()) { + P.clearReferencedFunctions_if([&](SILFunction *f) { + return DeadFunctionsSet.find(f) != DeadFunctionsSet.end(); + }); + } + } + void run() override { LLVM_DEBUG(llvm::dbgs() << "Running CrossDeadFuncElimination\n"); auto &Context = getModule()->getASTContext(); @@ -134,6 +145,7 @@ class SILCrossDeadFuncElimination : public SILModuleTransform { this->eliminateDeadEntriesFromTables(M); std::vector DeadFunctions; this->eliminateDeadFunctions(M, DeadFunctions); + this->cleanupSILProperty(M, DeadFunctions); while (!DeadFunctions.empty()) { SILFunction *F = DeadFunctions.back(); From 0810558866061b3ec996bf7f86b14981e8323a05 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Tue, 18 Aug 2020 03:07:01 +0900 Subject: [PATCH 66/77] [Prototype] Move test suites into LTO directory --- test/{Serialization => LTO}/empty_module_summary.swift | 0 test/{Serialization => LTO}/function_summary.swift | 0 test/{Serialization => LTO}/module_summary_generic_type_ref.swift | 0 test/{Serialization => LTO}/module_summary_preserved.swift | 0 test/{Serialization => LTO}/module_summary_tables.swift | 0 test/{Serialization => LTO}/type_refs_summary.swift | 0 6 files changed, 0 insertions(+), 0 deletions(-) rename test/{Serialization => LTO}/empty_module_summary.swift (100%) rename test/{Serialization => LTO}/function_summary.swift (100%) rename test/{Serialization => LTO}/module_summary_generic_type_ref.swift (100%) rename test/{Serialization => LTO}/module_summary_preserved.swift (100%) rename test/{Serialization => LTO}/module_summary_tables.swift (100%) rename test/{Serialization => LTO}/type_refs_summary.swift (100%) diff --git a/test/Serialization/empty_module_summary.swift b/test/LTO/empty_module_summary.swift similarity index 100% rename from test/Serialization/empty_module_summary.swift rename to test/LTO/empty_module_summary.swift diff --git a/test/Serialization/function_summary.swift b/test/LTO/function_summary.swift similarity index 100% rename from test/Serialization/function_summary.swift rename to test/LTO/function_summary.swift diff --git a/test/Serialization/module_summary_generic_type_ref.swift b/test/LTO/module_summary_generic_type_ref.swift similarity index 100% rename from test/Serialization/module_summary_generic_type_ref.swift rename to test/LTO/module_summary_generic_type_ref.swift diff --git a/test/Serialization/module_summary_preserved.swift b/test/LTO/module_summary_preserved.swift similarity index 100% rename from test/Serialization/module_summary_preserved.swift rename to test/LTO/module_summary_preserved.swift diff --git a/test/Serialization/module_summary_tables.swift b/test/LTO/module_summary_tables.swift similarity index 100% rename from test/Serialization/module_summary_tables.swift rename to test/LTO/module_summary_tables.swift diff --git a/test/Serialization/type_refs_summary.swift b/test/LTO/type_refs_summary.swift similarity index 100% rename from test/Serialization/type_refs_summary.swift rename to test/LTO/type_refs_summary.swift From 20c3f4252caf8bd3feaf885777a92555b28cde0e Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Tue, 18 Aug 2020 08:34:55 +0900 Subject: [PATCH 67/77] [Prototype] Don't preserve public KeyPaths --- lib/Serialization/ModuleSummaryIndexer.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/lib/Serialization/ModuleSummaryIndexer.cpp b/lib/Serialization/ModuleSummaryIndexer.cpp index e172e66b69cf3..821040fc952fb 100644 --- a/lib/Serialization/ModuleSummaryIndexer.cpp +++ b/lib/Serialization/ModuleSummaryIndexer.cpp @@ -465,11 +465,6 @@ void ModuleSummaryIndexer::indexModule() { TheSummary->addFunctionSummary(std::move(FS)); } - // FIXME: KeyPaths can be eliminated but now preserved conservatively. - for (auto &P : Mod.getPropertyList()) { - preserveKeyPathFunctions(P); - } - for (auto &WT : Mod.getWitnessTableList()) { indexWitnessTable(WT); } From 159ac2b093fd6e88fccd13049d509318e7c49a2e Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Tue, 18 Aug 2020 14:28:12 +0900 Subject: [PATCH 68/77] [Prototype] Serialize instruction size to YAML --- include/swift/Serialization/ModuleSummary.h | 6 +++--- lib/Serialization/ModuleSummaryIndexer.cpp | 2 +- .../swift-module-summary-test/swift-module-summary-test.cpp | 1 + 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/include/swift/Serialization/ModuleSummary.h b/include/swift/Serialization/ModuleSummary.h index 97520c195f7f7..ecffdb42aeb6e 100644 --- a/include/swift/Serialization/ModuleSummary.h +++ b/include/swift/Serialization/ModuleSummary.h @@ -100,7 +100,7 @@ class FunctionSummary { /// The symbol name of the function only for debug and test purposes. std::string Name; /// Size of instructions only for debug purpose - size_t InstSize; + uint32_t InstSize; public: FunctionSummary() = default; @@ -129,8 +129,8 @@ class FunctionSummary { GUID getGUID() const { return Guid; } - size_t getInstSize() const { return InstSize; } - void setInstSize(size_t size) { this->InstSize = size; } + uint32_t getInstSize() const { return InstSize; } + void setInstSize(uint32_t size) { this->InstSize = size; } }; /// A slot in a set of virtual tables. diff --git a/lib/Serialization/ModuleSummaryIndexer.cpp b/lib/Serialization/ModuleSummaryIndexer.cpp index 821040fc952fb..59a2c574d3926 100644 --- a/lib/Serialization/ModuleSummaryIndexer.cpp +++ b/lib/Serialization/ModuleSummaryIndexer.cpp @@ -332,7 +332,7 @@ bool shouldPreserveFunction(const SILFunction &F) { void FunctionSummaryIndexer::indexFunction() { GUID guid = getGUIDFromUniqueName(F.getName()); - size_t instSize = 0; + uint32_t instSize = 0; TheSummary = std::make_unique(guid); TheSummary->setName(F.getName()); for (auto &BB : F) { diff --git a/tools/swift-module-summary-test/swift-module-summary-test.cpp b/tools/swift-module-summary-test/swift-module-summary-test.cpp index 354a89197709a..db5b710f46092 100644 --- a/tools/swift-module-summary-test/swift-module-summary-test.cpp +++ b/tools/swift-module-summary-test/swift-module-summary-test.cpp @@ -119,6 +119,7 @@ void MappingTraits::mapping(IO &io, FunctionSummary &V) { io.mapRequired("preserved", V.Flags.Preserved); io.mapRequired("calls", V.CallGraphEdgeList); io.mapRequired("type_refs", V.TypeRefList); + io.mapRequired("inst_size", V.InstSize); } template <> From 89d9b4d3c47b09d9c0e90bca5c35460bac3e840d Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Tue, 18 Aug 2020 15:19:38 +0900 Subject: [PATCH 69/77] [Prototype] Add dominator tree mode for tools --- .../swift-module-summary-test.cpp | 60 ++++++++++++++++--- 1 file changed, 53 insertions(+), 7 deletions(-) diff --git a/tools/swift-module-summary-test/swift-module-summary-test.cpp b/tools/swift-module-summary-test/swift-module-summary-test.cpp index db5b710f46092..f251f12a00699 100644 --- a/tools/swift-module-summary-test/swift-module-summary-test.cpp +++ b/tools/swift-module-summary-test/swift-module-summary-test.cpp @@ -26,6 +26,7 @@ #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/YAMLParser.h" #include "llvm/Support/YAMLTraits.h" +#include using namespace swift; using namespace modulesummary; @@ -35,6 +36,7 @@ enum class ActionType : unsigned { BinaryToYAML, YAMLToBinary, BinaryToDominators, + BinaryToDominatorTree, BinaryToDot, }; @@ -62,8 +64,11 @@ static llvm::cl::opt Action( "Convert new binary .swiftmodule.summary format to YAML"), clEnumValN(ActionType::YAMLToBinary, "from-yaml", "Convert YAML to new binary .swiftmodule.summary format"), + clEnumValN(ActionType::BinaryToDominators, "binary-to-dom", + "Convert new binary .swiftmodule.summary format to " + "dominators list"), clEnumValN( - ActionType::BinaryToDominators, "binary-to-dom", + ActionType::BinaryToDominatorTree, "binary-to-dom-tree", "Convert new binary .swiftmodule.summary format to dominator tree"), clEnumValN(ActionType::BinaryToDot, "binary-to-dot", "Convert new binary .swiftmodule.summary format to Dot"))); @@ -418,14 +423,14 @@ class DomCallTree : public DomCallTreeBase { class RetainedSizeCalculator { struct Entry { DomCallInfoNode *DomNode; - size_t InstSize; + uint32_t InstSize; }; - std::map SizeCache; + std::map SizeCache; std::vector Entries; - size_t getInstSize(DomCallInfoNode *domNode) { + uint32_t getInstSize(DomCallInfoNode *domNode) { auto FS = domNode->getBlock()->getFS(); - size_t size = FS->getInstSize(); + uint32_t size = FS->getInstSize(); for (auto I = domNode->begin(), E = domNode->end(); I != E; ++I) { auto Child = *I; size += getInstSize(Child); @@ -457,10 +462,46 @@ class RetainedSizeCalculator { O << entry.InstSize << "\t| " << FS->getName() << "\n"; } } + + void displayTreeRec(llvm::raw_ostream &O, uint32_t TotalSize, + DomCallInfoNode *Root, unsigned Lev) { + auto Size = getInstSize(Root); + auto Percent = (double(Size) / TotalSize * 100); + auto FS = Root->getBlock()->getFS(); + O << Size << "\t| "; + llvm::format_provider::format(Percent, O, "f2"); + O << "\t| "; + O.indent(2 * Lev) << FS->getName() << "\n"; + + auto Children = Root->getChildren(); + std::sort(Children.begin(), Children.end(), + [&](DomCallInfoNode *lhs, DomCallInfoNode *rhs) { + return getInstSize(lhs) > getInstSize(rhs); + }); + for (auto Child : Children) { + displayTreeRec(O, TotalSize, Child, Lev + 1); + } + } + void displayTree(llvm::raw_ostream &O, DomCallInfoNode *Root) { + O << "size\t| %\t| symbol\n"; + uint32_t TotalSize = 0; + for (auto Child : Root->getChildren()) { + TotalSize += getInstSize(Child); + } + auto Children = Root->getChildren(); + std::sort(Children.begin(), Children.end(), + [&](DomCallInfoNode *lhs, DomCallInfoNode *rhs) { + return getInstSize(lhs) > getInstSize(rhs); + }); + for (auto Child : Children) { + displayTreeRec(O, TotalSize, Child, 0); + } + } }; int dominance_analysis(CallGraph &CG) { DomCallTree DT(CG); + DT.print(llvm::dbgs()); DomCallInfoNode *Root = DT.getRootNode(); RetainedSizeCalculator calculator; calculator.calculate(Root); @@ -534,7 +575,8 @@ int main(int argc, char *argv[]) { }); break; } - case ActionType::BinaryToDominators: { + case ActionType::BinaryToDominators: + case ActionType::BinaryToDominatorTree: { modulesummary::ModuleSummaryIndex summary; modulesummary::loadModuleSummaryIndex(fileBufOrErr.get()->getMemBufferRef(), summary); @@ -544,7 +586,11 @@ int main(int argc, char *argv[]) { RetainedSizeCalculator calculator; calculator.calculate(Root); withOutputFile(diags, options::OutputFilename, [&](raw_ostream &out) { - calculator.display(out); + if (options::Action == ActionType::BinaryToDominators) { + calculator.display(out); + } else { + calculator.displayTree(out, Root); + } return false; }); break; From af4ffc118154c6c52a952e0ea79a7b2de63d1775 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Tue, 18 Aug 2020 17:15:58 +0900 Subject: [PATCH 70/77] [Prototype] Trace whole reachable call path --- tools/driver/cross_module_opt_main.cpp | 41 ++++++++++++++++++-------- 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/tools/driver/cross_module_opt_main.cpp b/tools/driver/cross_module_opt_main.cpp index 922d06cd4a3dc..2c55353441da5 100644 --- a/tools/driver/cross_module_opt_main.cpp +++ b/tools/driver/cross_module_opt_main.cpp @@ -160,10 +160,18 @@ void markDeadSymbols(ModuleSummaryIndex &summary, llvm::DenseSet &Preserve unsigned LiveSymbols = 0; for (auto GUID : PreservedGUIDs) { - Worklist.push_back(std::make_shared( - nullptr, GUID, LivenessTrace::Preserved)); + auto trace = std::make_shared( + nullptr, GUID, LivenessTrace::Preserved); + auto maybeFS = summary.getFunctionSummary(GUID); + if (!maybeFS) { + llvm_unreachable("Bad GUID"); + } + if (!maybeFS->getName().empty()) { + trace->setName(maybeFS->getName()); + } + Worklist.push_back(trace); } - std::shared_ptr dumpTarget; + std::set> dumpTargets; while (!Worklist.empty()) { auto trace = Worklist.pop_back_val(); @@ -172,12 +180,6 @@ void markDeadSymbols(ModuleSummaryIndex &summary, llvm::DenseSet &Preserve llvm_unreachable("Bad GUID"); } auto FS = maybeSummary; - if (!FS->getName().empty()) { - trace->setName(FS->getName()); - if (LTOPrintLiveTrace == FS->getName()) { - dumpTarget = trace; - } - } if (FS->isLive()) continue; if (!FS->getName().empty()) { @@ -188,10 +190,25 @@ void markDeadSymbols(ModuleSummaryIndex &summary, llvm::DenseSet &Preserve FS->setLive(true); LiveSymbols++; + auto queueWorklist = [&](std::shared_ptr trace) { + auto maybeCallee = summary.getFunctionSummary(trace->guid); + if (!maybeCallee) { + llvm_unreachable("Bad GUID"); + } + auto Callee = maybeCallee; + if (!Callee->getName().empty()) { + trace->setName(Callee->getName()); + if (LTOPrintLiveTrace == Callee->getName()) { + dumpTargets.insert(trace); + } + } + Worklist.push_back(trace); + }; + for (auto Call : FS->calls()) { switch (Call.getKind()) { case FunctionSummary::Call::Direct: { - Worklist.push_back(std::make_shared( + queueWorklist(std::make_shared( trace, Call.getCallee(), LivenessTrace::StaticReferenced)); continue; } @@ -203,7 +220,7 @@ void markDeadSymbols(ModuleSummaryIndex &summary, llvm::DenseSet &Preserve if (UsedTypesSet.find(Impl.TypeGuid) == UsedTypesSet.end()) { continue; } - Worklist.push_back(std::make_shared( + queueWorklist(std::make_shared( trace, Impl.Guid, LivenessTrace::IndirectReferenced)); } break; @@ -213,7 +230,7 @@ void markDeadSymbols(ModuleSummaryIndex &summary, llvm::DenseSet &Preserve } } } - if (dumpTarget) { + for (auto dumpTarget : dumpTargets) { dumpTarget->dump(); } } From 179aeb3f9ee9f23b32a373d6aa31b35c9afb9a6d Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Fri, 28 Aug 2020 14:39:20 +0900 Subject: [PATCH 71/77] Trigger CI From 16e90d7ea6151ffa5727ead78e822a13f1fcc0e6 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Mon, 9 Nov 2020 10:33:41 +0900 Subject: [PATCH 72/77] Fix bad merge issues --- include/swift/Basic/FileTypes.def | 1 - include/swift/Option/FrontendOptions.td | 3 -- lib/Basic/FileTypes.cpp | 3 -- lib/Driver/Driver.cpp | 3 +- lib/Driver/ToolChains.cpp | 4 +-- .../IPO/DeadFunctionElimination.cpp | 2 +- lib/Serialization/DeserializeSIL.cpp | 30 +++++++++---------- lib/Serialization/ModuleSummaryIndexer.cpp | 6 ++-- lib/Serialization/SerializedModuleLoader.cpp | 20 ++++++++----- .../swift-module-summary-test.cpp | 10 +++---- 10 files changed, 38 insertions(+), 44 deletions(-) diff --git a/include/swift/Basic/FileTypes.def b/include/swift/Basic/FileTypes.def index 15bf4dc7fcf4f..2a051381ec0fe 100644 --- a/include/swift/Basic/FileTypes.def +++ b/include/swift/Basic/FileTypes.def @@ -48,7 +48,6 @@ TYPE("dSYM", dSYM, "dSYM", "") TYPE("dependencies", Dependencies, "d", "") TYPE("autolink", AutolinkFile, "autolink", "") TYPE("swiftmodule", SwiftModuleFile, "swiftmodule", "") -TYPE("swiftmodule-summary", SwiftModuleSummaryFile, "swiftmodule.summary", "") TYPE("swiftdoc", SwiftModuleDocFile, "swiftdoc", "") TYPE("swiftinterface", SwiftModuleInterfaceFile, "swiftinterface", "") TYPE("private-swiftinterface", PrivateSwiftModuleInterfaceFile, "private.swiftinterface", "") diff --git a/include/swift/Option/FrontendOptions.td b/include/swift/Option/FrontendOptions.td index c610028cdff0a..293b3938f621f 100644 --- a/include/swift/Option/FrontendOptions.td +++ b/include/swift/Option/FrontendOptions.td @@ -41,9 +41,6 @@ def emit_module_doc_path def emit_module_source_info : Flag<["-"], "emit-module-source-info">, HelpText<"Output module source info file">; -def emit_module_summary : Flag<["-"], "emit-module-summary">, - HelpText<"Emit module summary">; - def module_summary_path : Separate<["-"], "module-summary-path">, MetaVarName<"">, HelpText<"Combined module summary file ">; diff --git a/lib/Basic/FileTypes.cpp b/lib/Basic/FileTypes.cpp index d07b7193f7b5c..8d5563af486c2 100644 --- a/lib/Basic/FileTypes.cpp +++ b/lib/Basic/FileTypes.cpp @@ -90,7 +90,6 @@ bool file_types::isTextual(ID Id) { case file_types::TY_PCH: case file_types::TY_SIB: case file_types::TY_RawSIB: - case file_types::TY_SwiftModuleSummaryFile: case file_types::TY_SwiftModuleFile: case file_types::TY_SwiftModuleDocFile: case file_types::TY_SwiftSourceInfoFile: @@ -140,7 +139,6 @@ bool file_types::isAfterLLVM(ID Id) { case file_types::TY_SwiftModuleDocFile: case file_types::TY_SwiftSourceInfoFile: case file_types::TY_SwiftCrossImportDir: - case file_types::TY_SwiftModuleSummaryFile: case file_types::TY_SwiftOverlayFile: case file_types::TY_SwiftModuleSummaryFile: case file_types::TY_SerializedDiagnostics: @@ -192,7 +190,6 @@ bool file_types::isPartOfSwiftCompilation(ID Id) { case file_types::TY_PrivateSwiftModuleInterfaceFile: case file_types::TY_SwiftSourceInfoFile: case file_types::TY_SwiftCrossImportDir: - case file_types::TY_SwiftModuleSummaryFile: case file_types::TY_SwiftOverlayFile: case file_types::TY_SwiftModuleSummaryFile: case file_types::TY_SerializedDiagnostics: diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp index 21b011f599a1d..906c37c3d4bef 100644 --- a/lib/Driver/Driver.cpp +++ b/lib/Driver/Driver.cpp @@ -2057,9 +2057,8 @@ void Driver::buildActions(SmallVectorImpl &TopLevelActions, case file_types::TY_BitstreamOptRecord: case file_types::TY_SwiftModuleInterfaceFile: case file_types::TY_PrivateSwiftModuleInterfaceFile: - case file_types::TY_SwiftModuleSummaryFile: case file_types::TY_SwiftCrossImportDir: - case file_types::TY_SwiftModuleSummaryFile: // FIXME(katei) + case file_types::TY_SwiftModuleSummaryFile: case file_types::TY_SwiftOverlayFile: case file_types::TY_JSONDependencies: // We could in theory handle assembly or LLVM input, but let's not. diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp index d54285a00118f..46eec136c9426 100644 --- a/lib/Driver/ToolChains.cpp +++ b/lib/Driver/ToolChains.cpp @@ -628,10 +628,9 @@ const char *ToolChain::JobContext::computeFrontendModeForCompile() const { case file_types::TY_BitstreamOptRecord: case file_types::TY_SwiftModuleInterfaceFile: case file_types::TY_PrivateSwiftModuleInterfaceFile: - case file_types::TY_SwiftModuleSummaryFile: case file_types::TY_SwiftSourceInfoFile: case file_types::TY_SwiftCrossImportDir: - case file_types::TY_SwiftModuleSummaryFile: // FIXME(katei) + case file_types::TY_SwiftModuleSummaryFile: case file_types::TY_SwiftOverlayFile: llvm_unreachable("Output type can never be primary output."); case file_types::TY_INVALID: @@ -890,7 +889,6 @@ ToolChain::constructInvocation(const BackendJobAction &job, case file_types::TY_BitstreamOptRecord: case file_types::TY_SwiftModuleInterfaceFile: case file_types::TY_PrivateSwiftModuleInterfaceFile: - case file_types::TY_SwiftModuleSummaryFile: case file_types::TY_SwiftSourceInfoFile: case file_types::TY_SwiftCrossImportDir: case file_types::TY_SwiftModuleSummaryFile: diff --git a/lib/SILOptimizer/IPO/DeadFunctionElimination.cpp b/lib/SILOptimizer/IPO/DeadFunctionElimination.cpp index 99f3c9a82f600..60e19bce1684c 100644 --- a/lib/SILOptimizer/IPO/DeadFunctionElimination.cpp +++ b/lib/SILOptimizer/IPO/DeadFunctionElimination.cpp @@ -403,7 +403,7 @@ class FunctionLivenessComputation { // Make sure that functions referenced by _specialize(target: targetFun()) // are kept alive. F.forEachSpecializeAttrTargetFunction( - [this](SILFunction *targetFun) { ensureAlive(targetFun); }); + [this](SILFunction *targetFun) { ensureAlive(targetFun, "forEachSpecializeAttrTargetFunction"); }); if (!F.shouldOptimize()) { LLVM_DEBUG(llvm::dbgs() << " anchor a no optimization function: " diff --git a/lib/Serialization/DeserializeSIL.cpp b/lib/Serialization/DeserializeSIL.cpp index 912e33220cb42..fed6d05a53130 100644 --- a/lib/Serialization/DeserializeSIL.cpp +++ b/lib/Serialization/DeserializeSIL.cpp @@ -510,18 +510,17 @@ SILDeserializer::readSILFunctionChecked(DeclID FID, SILFunction *existingFn, IdentifierID replacedFunctionID; GenericSignatureID genericSigID; unsigned rawLinkage, isTransparent, isSerialized, isThunk, - isWithoutactuallyEscapingThunk, isAsync, specialPurpose, inlineStrategy, - optimizationMode, subclassScope, hasCReferences, effect, numSpecAttrs, hasQualifiedOwnership, - isWeakImported, LIST_VER_TUPLE_PIECES(available), + isWithoutactuallyEscapingThunk, specialPurpose, inlineStrategy, + optimizationMode, subclassScope, hasCReferences, effect, numSpecAttrs, + hasQualifiedOwnership, isWeakImported, LIST_VER_TUPLE_PIECES(available), isDynamic, isExactSelfClass; ArrayRef SemanticsIDs; SILFunctionLayout::readRecord( scratch, rawLinkage, isTransparent, isSerialized, isThunk, - isWithoutactuallyEscapingThunk, isAsync, specialPurpose, inlineStrategy, - optimizationMode, subclassScope, hasCReferences, effect, numSpecAttrs, hasQualifiedOwnership, - isWeakImported, LIST_VER_TUPLE_PIECES(available), - isDynamic, isExactSelfClass, - funcTyID, replacedFunctionID, genericSigID, + isWithoutactuallyEscapingThunk, specialPurpose, inlineStrategy, + optimizationMode, subclassScope, hasCReferences, effect, numSpecAttrs, + hasQualifiedOwnership, isWeakImported, LIST_VER_TUPLE_PIECES(available), + isDynamic, isExactSelfClass, funcTyID, replacedFunctionID, genericSigID, clangNodeOwnerID, SemanticsIDs); if (funcTyID == 0) { @@ -2861,18 +2860,17 @@ bool SILDeserializer::hasSILFunction(StringRef Name, IdentifierID replacedFunctionID; GenericSignatureID genericSigID; unsigned rawLinkage, isTransparent, isSerialized, isThunk, - isWithoutactuallyEscapingThunk, isAsync, isGlobal, inlineStrategy, - optimizationMode, subclassScope, hasCReferences, effect, numSpecAttrs, hasQualifiedOwnership, - isWeakImported, LIST_VER_TUPLE_PIECES(available), + isWithoutactuallyEscapingThunk, isGlobal, inlineStrategy, + optimizationMode, subclassScope, hasCReferences, effect, numSpecAttrs, + hasQualifiedOwnership, isWeakImported, LIST_VER_TUPLE_PIECES(available), isDynamic, isExactSelfClass; ArrayRef SemanticsIDs; SILFunctionLayout::readRecord( scratch, rawLinkage, isTransparent, isSerialized, isThunk, - isWithoutactuallyEscapingThunk, isAsync, isGlobal, inlineStrategy, - optimizationMode, subclassScope, hasCReferences, effect, numSpecAttrs, hasQualifiedOwnership, - isWeakImported, LIST_VER_TUPLE_PIECES(available), - isDynamic, isExactSelfClass, - funcTyID, replacedFunctionID, genericSigID, + isWithoutactuallyEscapingThunk, isGlobal, inlineStrategy, + optimizationMode, subclassScope, hasCReferences, effect, numSpecAttrs, + hasQualifiedOwnership, isWeakImported, LIST_VER_TUPLE_PIECES(available), + isDynamic, isExactSelfClass, funcTyID, replacedFunctionID, genericSigID, clangOwnerID, SemanticsIDs); auto linkage = fromStableSILLinkage(rawLinkage); if (!linkage) { diff --git a/lib/Serialization/ModuleSummaryIndexer.cpp b/lib/Serialization/ModuleSummaryIndexer.cpp index 59a2c574d3926..6c8e353a84659 100644 --- a/lib/Serialization/ModuleSummaryIndexer.cpp +++ b/lib/Serialization/ModuleSummaryIndexer.cpp @@ -107,7 +107,7 @@ void FunctionSummaryIndexer::indexDirectFunctionCall( if (!RecordedDirectTargets.insert(guid).second) { return; } - FunctionSummary::Call call(guid, Callee.getName(), + FunctionSummary::Call call(guid, Callee.getName().str(), FunctionSummary::Call::Direct); TheSummary->addCall(call); } @@ -334,7 +334,7 @@ void FunctionSummaryIndexer::indexFunction() { GUID guid = getGUIDFromUniqueName(F.getName()); uint32_t instSize = 0; TheSummary = std::make_unique(guid); - TheSummary->setName(F.getName()); + TheSummary->setName(F.getName().str()); for (auto &BB : F) { for (auto &I : BB) { visit(&I); @@ -456,7 +456,7 @@ void ModuleSummaryIndexer::indexVTable(const SILVTable &VT) { void ModuleSummaryIndexer::indexModule() { TheSummary = std::make_unique(); auto moduleName = Mod.getSwiftModule()->getName().str(); - TheSummary->setName(moduleName); + TheSummary->setName(moduleName.str()); for (auto &F : Mod) { FunctionSummaryIndexer indexer(F); diff --git a/lib/Serialization/SerializedModuleLoader.cpp b/lib/Serialization/SerializedModuleLoader.cpp index 67cfb83f7a0e4..ec6ec76045f69 100644 --- a/lib/Serialization/SerializedModuleLoader.cpp +++ b/lib/Serialization/SerializedModuleLoader.cpp @@ -1123,15 +1123,21 @@ void SerializedASTFile::collectLinkLibrariesFromImports( ModuleDecl::LinkLibraryCallback callback) const { llvm::SmallDenseSet visited; - SmallVector stack; - ModuleDecl::ImportFilter filter = {ModuleDecl::ImportFilterKind::Exported, - ModuleDecl::ImportFilterKind::Default}; - File.getImportedModules(stack, filter); + SmallVector stack; + + ModuleDecl::ImportFilter filter = { + ModuleDecl::ImportFilterKind::Exported, + ModuleDecl::ImportFilterKind::Default, + ModuleDecl::ImportFilterKind::SPIAccessControl}; + + auto *topLevel = getParentModule(); + + ModuleDecl::ImportFilter topLevelFilter = filter; + topLevelFilter |= ModuleDecl::ImportFilterKind::ImplementationOnly; + topLevel->getImportedModules(stack, topLevelFilter); // Make sure the top-level module is first; we want pre-order-ish traversal. - auto topLevelModule = - ModuleDecl::ImportedModule{ModuleDecl::AccessPathTy(), getParentModule()}; - stack.emplace_back(topLevelModule); + stack.emplace_back(ImportPath::Access(), topLevel); while (!stack.empty()) { auto next = stack.pop_back_val().importedModule; diff --git a/tools/swift-module-summary-test/swift-module-summary-test.cpp b/tools/swift-module-summary-test/swift-module-summary-test.cpp index f251f12a00699..751f28bc94a7e 100644 --- a/tools/swift-module-summary-test/swift-module-summary-test.cpp +++ b/tools/swift-module-summary-test/swift-module-summary-test.cpp @@ -441,14 +441,14 @@ class RetainedSizeCalculator { void calculateRecursively(DomCallInfoNode *domNode) { Entries.push_back({domNode, getInstSize(domNode)}); - for (auto child : domNode->getChildren()) { + for (auto child : domNode->children()) { calculateRecursively(child); } } public: void calculate(DomCallInfoNode *root) { - for (auto child : root->getChildren()) { + for (auto child : root->children()) { calculateRecursively(child); } std::sort(Entries.begin(), Entries.end(), @@ -473,7 +473,7 @@ class RetainedSizeCalculator { O << "\t| "; O.indent(2 * Lev) << FS->getName() << "\n"; - auto Children = Root->getChildren(); + auto Children = Root->children(); std::sort(Children.begin(), Children.end(), [&](DomCallInfoNode *lhs, DomCallInfoNode *rhs) { return getInstSize(lhs) > getInstSize(rhs); @@ -485,10 +485,10 @@ class RetainedSizeCalculator { void displayTree(llvm::raw_ostream &O, DomCallInfoNode *Root) { O << "size\t| %\t| symbol\n"; uint32_t TotalSize = 0; - for (auto Child : Root->getChildren()) { + for (auto Child : Root->children()) { TotalSize += getInstSize(Child); } - auto Children = Root->getChildren(); + auto Children = Root->children(); std::sort(Children.begin(), Children.end(), [&](DomCallInfoNode *lhs, DomCallInfoNode *rhs) { return getInstSize(lhs) > getInstSize(rhs); From 20dd2891a212b392e2d40dae0caaa5e78d444e54 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Mon, 9 Nov 2020 11:02:22 +0900 Subject: [PATCH 73/77] Fix test cases for LTO --- test/LTO/module_summary_generic_type_ref.swift | 6 +++--- test/LTO/module_summary_preserved.swift | 5 ++++- test/LTO/type_refs_summary.swift | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/test/LTO/module_summary_generic_type_ref.swift b/test/LTO/module_summary_generic_type_ref.swift index b7e001aa53711..d8c2fef8950f2 100644 --- a/test/LTO/module_summary_generic_type_ref.swift +++ b/test/LTO/module_summary_generic_type_ref.swift @@ -1,12 +1,12 @@ // RUN: %empty-directory(%t) // RUN: %target-swift-frontend -emit-sib -emit-module-summary-path %t/default_wt.swiftmodule.summary -module-name default_wt -Xllvm -module-summary-embed-debug-name %s -// RUN: %swift_frontend_plain -cross-module-opt %t/default_wt.swiftmodule.summary -module-summary-embed-debug-name -o %t/default_wt.swiftmodule.merged-summary +// RUN: %swift_frontend_plain -merge-module-summary %t/default_wt.swiftmodule.summary -module-summary-embed-debug-name -o %t/default_wt.swiftmodule.merged-summary // RUN: %swift-module-summary-test --to-yaml %t/default_wt.swiftmodule.merged-summary -o %t/default_wt.merged-summary.yaml // Ensure that optimizer won't eliminate PrimitiveSequenceType.getPrimitiveSequence // RUN: %target-swift-frontend -c -module-summary-path %t/default_wt.swiftmodule.merged-summary default_wt.sib -o %t/default_wt.o -// RUN: %target-swiftc_driver %t/default_wt.o -o %t/default_wt -// RUN: %t/default_wt +// RUN: %target-build-swift %t/default_wt.o -o %t/default_wt +// RUN: %target-run %t/default_wt // RUN: cat %t/default_wt.merged-summary.yaml | %FileCheck %s // CHECK: 8732890044670327403: diff --git a/test/LTO/module_summary_preserved.swift b/test/LTO/module_summary_preserved.swift index 91d14495eadbd..9767b88e36a00 100644 --- a/test/LTO/module_summary_preserved.swift +++ b/test/LTO/module_summary_preserved.swift @@ -46,14 +46,17 @@ func callableFromC2(x: Int) -> Int { return 2 } -// RUN: cat %t/preserved.summary.yaml | %FileCheck %s -check-prefix OBJC +// RUN: if [ %target-runtime == "objc" ]; then cat %t/preserved.summary.yaml | %FileCheck %s -check-prefix OBJC; fi // OBJC: 3149498140227613915: // OBJC-NEXT: name: '$s9preserved1AC11objcMethod1yyFTo' // OBJC-NEXT: guid: 3149498140227613915 // OBJC-NEXT: live: false // OBJC-NEXT: preserved: true + +#if canImport(ObjectiveC) import Foundation class A: NSObject { @objc func objcMethod1() {} } +#endif diff --git a/test/LTO/type_refs_summary.swift b/test/LTO/type_refs_summary.swift index bf1e955cefe49..36145e18e1720 100644 --- a/test/LTO/type_refs_summary.swift +++ b/test/LTO/type_refs_summary.swift @@ -66,7 +66,7 @@ // VTABLE-IMPL-NEXT: type_guid: 9126595621082655001 -// RUN: %swift_frontend_plain -cross-module-opt %t/type_refs.swiftmodule.summary -module-summary-embed-debug-name -o %t/type_refs.swiftmodule.merged-summary +// RUN: %swift_frontend_plain -merge-module-summary %t/type_refs.swiftmodule.summary -module-summary-embed-debug-name -o %t/type_refs.swiftmodule.merged-summary // RUN: %swift-module-summary-test --to-yaml %t/type_refs.swiftmodule.merged-summary -o %t/type_refs.merged-summary.yaml // Ensure that WT of V is not used. // RUN: cat %t/type_refs.merged-summary.yaml | %FileCheck %s -check-prefix USED-TYPE From 08c6fd0ea84396bc19c8a5d1ae917075fd84fa6c Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Mon, 9 Nov 2020 11:03:48 +0900 Subject: [PATCH 74/77] [WASM] Run LTO tests on CI --- utils/webassembly/ci.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/utils/webassembly/ci.sh b/utils/webassembly/ci.sh index 80bf7f32450ed..d14aa2861bcc3 100755 --- a/utils/webassembly/ci.sh +++ b/utils/webassembly/ci.sh @@ -47,10 +47,14 @@ fi if [[ "$(uname)" == "Linux" ]]; then $RUN_TEST_BIN --build-dir $TARGET_BUILD_DIR --target wasi-wasm32 \ $TARGET_BUILD_DIR/swift-${HOST_PLATFORM}-x86_64/test-wasi-wasm32/stdlib + $RUN_TEST_BIN --build-dir $TARGET_BUILD_DIR --target wasi-wasm32 \ + $TARGET_BUILD_DIR/swift-${HOST_PLATFORM}-x86_64/test-wasi-wasm32/LTO echo "Skip running test suites for Linux" else $RUN_TEST_BIN --build-dir $TARGET_BUILD_DIR --target wasi-wasm32 \ $TARGET_BUILD_DIR/swift-${HOST_PLATFORM}-x86_64/test-wasi-wasm32/stdlib + $RUN_TEST_BIN --build-dir $TARGET_BUILD_DIR --target wasi-wasm32 \ + $TARGET_BUILD_DIR/swift-${HOST_PLATFORM}-x86_64/test-wasi-wasm32/LTO # Run test but ignore failure temporarily ninja check-swift-wasi-wasm32 -C $TARGET_BUILD_DIR/swift-$HOST_SUFFIX || true From 7dd2fa6913c75f2cd0f8cdf80647d3b74ce531e0 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Mon, 9 Nov 2020 15:47:19 +0900 Subject: [PATCH 75/77] Fix -module-summary-path handling between driver and frontend --- include/swift/Option/FrontendOptions.td | 4 ---- include/swift/Option/Options.td | 3 +++ lib/Driver/ToolChains.cpp | 1 + 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/swift/Option/FrontendOptions.td b/include/swift/Option/FrontendOptions.td index 293b3938f621f..5e766ef4518b2 100644 --- a/include/swift/Option/FrontendOptions.td +++ b/include/swift/Option/FrontendOptions.td @@ -41,10 +41,6 @@ def emit_module_doc_path def emit_module_source_info : Flag<["-"], "emit-module-source-info">, HelpText<"Output module source info file">; -def module_summary_path - : Separate<["-"], "module-summary-path">, MetaVarName<"">, - HelpText<"Combined module summary file ">; - def ignore_module_source_info : Flag<["-"], "ignore-module-source-info">, HelpText<"Avoid getting source location from .swiftsourceinfo files">; diff --git a/include/swift/Option/Options.td b/include/swift/Option/Options.td index d0bb1e0cb990f..80d52d685c664 100644 --- a/include/swift/Option/Options.td +++ b/include/swift/Option/Options.td @@ -445,6 +445,9 @@ def emit_module_summary_path : Flags<[FrontendOption, NoInteractiveOption, DoesNotAffectIncrementalBuild, ArgumentIsPath, SupplementaryOutput]>, MetaVarName<"">, HelpText<"Output module summary file to ">; +def module_summary_path : Separate<["-"], "module-summary-path">, + Flags<[FrontendOption, ArgumentIsPath]>, MetaVarName<"">, + HelpText<"Combined module summary file ">; def emit_module_interface : Flag<["-"], "emit-module-interface">, diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp index 46eec136c9426..6696cd256f0ab 100644 --- a/lib/Driver/ToolChains.cpp +++ b/lib/Driver/ToolChains.cpp @@ -230,6 +230,7 @@ void ToolChain::addCommonFrontendArgs(const OutputInfo &OI, inputArgs.AddLastArg(arguments, options::OPT_import_underlying_module); inputArgs.AddLastArg(arguments, options::OPT_module_cache_path); inputArgs.AddLastArg(arguments, options::OPT_module_link_name); + inputArgs.AddLastArg(arguments, options::OPT_module_summary_path); inputArgs.AddLastArg(arguments, options::OPT_nostdimport); inputArgs.AddLastArg(arguments, options::OPT_parse_stdlib); inputArgs.AddLastArg(arguments, options::OPT_resource_dir); From 656ccc7be6f7baeb67379f6f6b9cc7ba4b068971 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Mon, 9 Nov 2020 16:29:54 +0900 Subject: [PATCH 76/77] Accept LLVM BC for LLVM LTO --- lib/Driver/Driver.cpp | 2 +- lib/Driver/WebAssemblyToolChains.cpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp index 906c37c3d4bef..815fe587ad9c5 100644 --- a/lib/Driver/Driver.cpp +++ b/lib/Driver/Driver.cpp @@ -2028,6 +2028,7 @@ void Driver::buildActions(SmallVectorImpl &TopLevelActions, } case file_types::TY_AutolinkFile: case file_types::TY_Object: + case file_types::TY_LLVM_BC: case file_types::TY_TBD: // Object inputs are only okay if linking. if (OI.shouldLink()) { @@ -2041,7 +2042,6 @@ void Driver::buildActions(SmallVectorImpl &TopLevelActions, case file_types::TY_Dependencies: case file_types::TY_Assembly: case file_types::TY_LLVM_IR: - case file_types::TY_LLVM_BC: case file_types::TY_SerializedDiagnostics: case file_types::TY_ObjCHeader: case file_types::TY_ClangModuleFile: diff --git a/lib/Driver/WebAssemblyToolChains.cpp b/lib/Driver/WebAssemblyToolChains.cpp index 55f1c329a5f39..7aa8d8b1e2524 100644 --- a/lib/Driver/WebAssemblyToolChains.cpp +++ b/lib/Driver/WebAssemblyToolChains.cpp @@ -124,6 +124,7 @@ toolchains::WebAssembly::constructInvocation(const DynamicLinkJobAction &job, addPrimaryInputsOfType(Arguments, context.Inputs, context.Args, file_types::TY_Object); addInputsOfType(Arguments, context.InputActions, file_types::TY_Object); + addInputsOfType(Arguments, context.InputActions, file_types::TY_LLVM_BC); if (!context.OI.SDKPath.empty()) { Arguments.push_back("--sysroot"); From b3d242f539245dfd9559e5ec264fdc469cd039ca Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Mon, 9 Nov 2020 16:37:21 +0900 Subject: [PATCH 77/77] Minimize diff from upstream --- include/swift/Option/FrontendOptions.td | 2 +- lib/Basic/FileTypes.cpp | 2 +- lib/Driver/Driver.cpp | 2 +- lib/Driver/ToolChains.cpp | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/swift/Option/FrontendOptions.td b/include/swift/Option/FrontendOptions.td index 5e766ef4518b2..5bd469453947b 100644 --- a/include/swift/Option/FrontendOptions.td +++ b/include/swift/Option/FrontendOptions.td @@ -40,7 +40,7 @@ def emit_module_doc_path def emit_module_source_info : Flag<["-"], "emit-module-source-info">, HelpText<"Output module source info file">; - + def ignore_module_source_info : Flag<["-"], "ignore-module-source-info">, HelpText<"Avoid getting source location from .swiftsourceinfo files">; diff --git a/lib/Basic/FileTypes.cpp b/lib/Basic/FileTypes.cpp index 8d5563af486c2..f4af753c5e56a 100644 --- a/lib/Basic/FileTypes.cpp +++ b/lib/Basic/FileTypes.cpp @@ -139,8 +139,8 @@ bool file_types::isAfterLLVM(ID Id) { case file_types::TY_SwiftModuleDocFile: case file_types::TY_SwiftSourceInfoFile: case file_types::TY_SwiftCrossImportDir: - case file_types::TY_SwiftOverlayFile: case file_types::TY_SwiftModuleSummaryFile: + case file_types::TY_SwiftOverlayFile: case file_types::TY_SerializedDiagnostics: case file_types::TY_ClangModuleFile: case file_types::TY_SwiftDeps: diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp index 815fe587ad9c5..92f629c7c287e 100644 --- a/lib/Driver/Driver.cpp +++ b/lib/Driver/Driver.cpp @@ -2057,8 +2057,8 @@ void Driver::buildActions(SmallVectorImpl &TopLevelActions, case file_types::TY_BitstreamOptRecord: case file_types::TY_SwiftModuleInterfaceFile: case file_types::TY_PrivateSwiftModuleInterfaceFile: - case file_types::TY_SwiftCrossImportDir: case file_types::TY_SwiftModuleSummaryFile: + case file_types::TY_SwiftCrossImportDir: case file_types::TY_SwiftOverlayFile: case file_types::TY_JSONDependencies: // We could in theory handle assembly or LLVM input, but let's not. diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp index 6696cd256f0ab..893b8517b1230 100644 --- a/lib/Driver/ToolChains.cpp +++ b/lib/Driver/ToolChains.cpp @@ -629,9 +629,9 @@ const char *ToolChain::JobContext::computeFrontendModeForCompile() const { case file_types::TY_BitstreamOptRecord: case file_types::TY_SwiftModuleInterfaceFile: case file_types::TY_PrivateSwiftModuleInterfaceFile: + case file_types::TY_SwiftModuleSummaryFile: case file_types::TY_SwiftSourceInfoFile: case file_types::TY_SwiftCrossImportDir: - case file_types::TY_SwiftModuleSummaryFile: case file_types::TY_SwiftOverlayFile: llvm_unreachable("Output type can never be primary output."); case file_types::TY_INVALID: @@ -890,9 +890,9 @@ ToolChain::constructInvocation(const BackendJobAction &job, case file_types::TY_BitstreamOptRecord: case file_types::TY_SwiftModuleInterfaceFile: case file_types::TY_PrivateSwiftModuleInterfaceFile: + case file_types::TY_SwiftModuleSummaryFile: case file_types::TY_SwiftSourceInfoFile: case file_types::TY_SwiftCrossImportDir: - case file_types::TY_SwiftModuleSummaryFile: case file_types::TY_SwiftOverlayFile: llvm_unreachable("Output type can never be primary output."); case file_types::TY_INVALID: