diff options
Diffstat (limited to 'include/llvm/IR/ModuleSummaryIndex.h')
-rw-r--r-- | include/llvm/IR/ModuleSummaryIndex.h | 253 |
1 files changed, 207 insertions, 46 deletions
diff --git a/include/llvm/IR/ModuleSummaryIndex.h b/include/llvm/IR/ModuleSummaryIndex.h index a1acee494475..aacf8cfc089f 100644 --- a/include/llvm/IR/ModuleSummaryIndex.h +++ b/include/llvm/IR/ModuleSummaryIndex.h @@ -1,9 +1,8 @@ //===- llvm/ModuleSummaryIndex.h - Module Summary Index ---------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -120,7 +119,7 @@ class GlobalValueSummary; using GlobalValueSummaryList = std::vector<std::unique_ptr<GlobalValueSummary>>; -struct GlobalValueSummaryInfo { +struct LLVM_ALIGNAS(8) GlobalValueSummaryInfo { union NameOrGV { NameOrGV(bool HaveGVs) { if (HaveGVs) @@ -163,7 +162,8 @@ using GlobalValueSummaryMapTy = /// Struct that holds a reference to a particular GUID in a global value /// summary. struct ValueInfo { - PointerIntPair<const GlobalValueSummaryMapTy::value_type *, 2, int> + enum Flags { HaveGV = 1, ReadOnly = 2, WriteOnly = 4 }; + PointerIntPair<const GlobalValueSummaryMapTy::value_type *, 3, int> RefAndFlags; ValueInfo() = default; @@ -189,15 +189,42 @@ struct ValueInfo { : getRef()->second.U.Name; } - bool haveGVs() const { return RefAndFlags.getInt() & 0x1; } - bool isReadOnly() const { return RefAndFlags.getInt() & 0x2; } - void setReadOnly() { RefAndFlags.setInt(RefAndFlags.getInt() | 0x2); } + bool haveGVs() const { return RefAndFlags.getInt() & HaveGV; } + bool isReadOnly() const { + assert(isValidAccessSpecifier()); + return RefAndFlags.getInt() & ReadOnly; + } + bool isWriteOnly() const { + assert(isValidAccessSpecifier()); + return RefAndFlags.getInt() & WriteOnly; + } + unsigned getAccessSpecifier() const { + assert(isValidAccessSpecifier()); + return RefAndFlags.getInt() & (ReadOnly | WriteOnly); + } + bool isValidAccessSpecifier() const { + unsigned BadAccessMask = ReadOnly | WriteOnly; + return (RefAndFlags.getInt() & BadAccessMask) != BadAccessMask; + } + void setReadOnly() { + // We expect ro/wo attribute to set only once during + // ValueInfo lifetime. + assert(getAccessSpecifier() == 0); + RefAndFlags.setInt(RefAndFlags.getInt() | ReadOnly); + } + void setWriteOnly() { + assert(getAccessSpecifier() == 0); + RefAndFlags.setInt(RefAndFlags.getInt() | WriteOnly); + } const GlobalValueSummaryMapTy::value_type *getRef() const { return RefAndFlags.getPointer(); } bool isDSOLocal() const; + + /// Checks if all copies are eligible for auto-hiding (have flag set). + bool canAutoHide() const; }; inline raw_ostream &operator<<(raw_ostream &OS, const ValueInfo &VI) { @@ -280,11 +307,23 @@ public: /// within the same linkage unit. unsigned DSOLocal : 1; + /// In the per-module summary, indicates that the global value is + /// linkonce_odr and global unnamed addr (so eligible for auto-hiding + /// via hidden visibility). In the combined summary, indicates that the + /// prevailing linkonce_odr copy can be auto-hidden via hidden visibility + /// when it is upgraded to weak_odr in the backend. This is legal when + /// all copies are eligible for auto-hiding (i.e. all copies were + /// linkonce_odr global unnamed addr. If any copy is not (e.g. it was + /// originally weak_odr, we cannot auto-hide the prevailing copy as it + /// means the symbol was externally visible. + unsigned CanAutoHide : 1; + /// Convenience Constructors explicit GVFlags(GlobalValue::LinkageTypes Linkage, - bool NotEligibleToImport, bool Live, bool IsLocal) + bool NotEligibleToImport, bool Live, bool IsLocal, + bool CanAutoHide) : Linkage(Linkage), NotEligibleToImport(NotEligibleToImport), - Live(Live), DSOLocal(IsLocal) {} + Live(Live), DSOLocal(IsLocal), CanAutoHide(CanAutoHide) {} }; private: @@ -365,6 +404,10 @@ public: bool isDSOLocal() const { return Flags.DSOLocal; } + void setCanAutoHide(bool CanAutoHide) { Flags.CanAutoHide = CanAutoHide; } + + bool canAutoHide() const { return Flags.CanAutoHide; } + /// Flag that this global value cannot be imported. void setNotEligibleToImport() { Flags.NotEligibleToImport = true; } @@ -381,25 +424,35 @@ public: /// Alias summary information. class AliasSummary : public GlobalValueSummary { + ValueInfo AliaseeValueInfo; + + /// This is the Aliasee in the same module as alias (could get from VI, trades + /// memory for time). Note that this pointer may be null (and the value info + /// empty) when we have a distributed index where the alias is being imported + /// (as a copy of the aliasee), but the aliasee is not. GlobalValueSummary *AliaseeSummary; - // AliaseeGUID is only set and accessed when we are building a combined index - // via the BitcodeReader. - GlobalValue::GUID AliaseeGUID; public: AliasSummary(GVFlags Flags) : GlobalValueSummary(AliasKind, Flags, ArrayRef<ValueInfo>{}), - AliaseeSummary(nullptr), AliaseeGUID(0) {} + AliaseeSummary(nullptr) {} /// Check if this is an alias summary. static bool classof(const GlobalValueSummary *GVS) { return GVS->getSummaryKind() == AliasKind; } - void setAliasee(GlobalValueSummary *Aliasee) { AliaseeSummary = Aliasee; } - void setAliaseeGUID(GlobalValue::GUID GUID) { AliaseeGUID = GUID; } + void setAliasee(ValueInfo &AliaseeVI, GlobalValueSummary *Aliasee) { + AliaseeValueInfo = AliaseeVI; + AliaseeSummary = Aliasee; + } - bool hasAliasee() const { return !!AliaseeSummary; } + bool hasAliasee() const { + assert(!!AliaseeSummary == (AliaseeValueInfo && + !AliaseeValueInfo.getSummaryList().empty()) && + "Expect to have both aliasee summary and summary list or neither"); + return !!AliaseeSummary; + } const GlobalValueSummary &getAliasee() const { assert(AliaseeSummary && "Unexpected missing aliasee summary"); @@ -410,10 +463,13 @@ public: return const_cast<GlobalValueSummary &>( static_cast<const AliasSummary *>(this)->getAliasee()); } - bool hasAliaseeGUID() const { return AliaseeGUID != 0; } - const GlobalValue::GUID &getAliaseeGUID() const { - assert(AliaseeGUID && "Unexpected missing aliasee GUID"); - return AliaseeGUID; + ValueInfo getAliaseeVI() const { + assert(AliaseeValueInfo && "Unexpected missing aliasee"); + return AliaseeValueInfo; + } + GlobalValue::GUID getAliaseeGUID() const { + assert(AliaseeValueInfo && "Unexpected missing aliasee"); + return AliaseeValueInfo.getGUID(); } }; @@ -500,7 +556,8 @@ public: return FunctionSummary( FunctionSummary::GVFlags( GlobalValue::LinkageTypes::AvailableExternallyLinkage, - /*NotEligibleToImport=*/true, /*Live=*/true, /*IsLocal=*/false), + /*NotEligibleToImport=*/true, /*Live=*/true, /*IsLocal=*/false, + /*CanAutoHide=*/false), /*InsCount=*/0, FunctionSummary::FFlags{}, /*EntryCount=*/0, std::vector<ValueInfo>(), std::move(Edges), std::vector<GlobalValue::GUID>(), @@ -552,8 +609,8 @@ public: std::move(TypeTestAssumeConstVCalls), std::move(TypeCheckedLoadConstVCalls)}); } - // Gets the number of immutable refs in RefEdgeList - unsigned immutableRefCount() const; + // Gets the number of readonly and writeonly refs in RefEdgeList + std::pair<unsigned, unsigned> specialRefCounts() const; /// Check if this is a function summary. static bool classof(const GlobalValueSummary *GVS) { @@ -666,18 +723,43 @@ template <> struct DenseMapInfo<FunctionSummary::ConstVCall> { } }; +/// The ValueInfo and offset for a function within a vtable definition +/// initializer array. +struct VirtFuncOffset { + VirtFuncOffset(ValueInfo VI, uint64_t Offset) + : FuncVI(VI), VTableOffset(Offset) {} + + ValueInfo FuncVI; + uint64_t VTableOffset; +}; +/// List of functions referenced by a particular vtable definition. +using VTableFuncList = std::vector<VirtFuncOffset>; + /// Global variable summary information to aid decisions and /// implementation of importing. /// -/// Global variable summary has extra flag, telling if it is -/// modified during the program run or not. This affects ThinLTO -/// internalization +/// Global variable summary has two extra flag, telling if it is +/// readonly or writeonly. Both readonly and writeonly variables +/// can be optimized in the backed: readonly variables can be +/// const-folded, while writeonly vars can be completely eliminated +/// together with corresponding stores. We let both things happen +/// by means of internalizing such variables after ThinLTO import. class GlobalVarSummary : public GlobalValueSummary { +private: + /// For vtable definitions this holds the list of functions and + /// their corresponding offsets within the initializer array. + std::unique_ptr<VTableFuncList> VTableFuncs; + public: struct GVarFlags { - GVarFlags(bool ReadOnly = false) : ReadOnly(ReadOnly) {} - - unsigned ReadOnly : 1; + GVarFlags(bool ReadOnly, bool WriteOnly) + : MaybeReadOnly(ReadOnly), MaybeWriteOnly(WriteOnly) {} + + // In permodule summaries both MaybeReadOnly and MaybeWriteOnly + // bits are set, because attribute propagation occurs later on + // thin link phase. + unsigned MaybeReadOnly : 1; + unsigned MaybeWriteOnly : 1; } VarFlags; GlobalVarSummary(GVFlags Flags, GVarFlags VarFlags, @@ -691,8 +773,21 @@ public: } GVarFlags varflags() const { return VarFlags; } - void setReadOnly(bool RO) { VarFlags.ReadOnly = RO; } - bool isReadOnly() const { return VarFlags.ReadOnly; } + void setReadOnly(bool RO) { VarFlags.MaybeReadOnly = RO; } + void setWriteOnly(bool WO) { VarFlags.MaybeWriteOnly = WO; } + bool maybeReadOnly() const { return VarFlags.MaybeReadOnly; } + bool maybeWriteOnly() const { return VarFlags.MaybeWriteOnly; } + + void setVTableFuncs(VTableFuncList Funcs) { + assert(!VTableFuncs); + VTableFuncs = llvm::make_unique<VTableFuncList>(std::move(Funcs)); + } + + ArrayRef<VirtFuncOffset> vTableFuncs() const { + if (VTableFuncs) + return *VTableFuncs; + return {}; + } }; struct TypeTestResolution { @@ -791,6 +886,29 @@ using GVSummaryMapTy = DenseMap<GlobalValue::GUID, GlobalValueSummary *>; using TypeIdSummaryMapTy = std::multimap<GlobalValue::GUID, std::pair<std::string, TypeIdSummary>>; +/// The following data structures summarize type metadata information. +/// For type metadata overview see https://llvm.org/docs/TypeMetadata.html. +/// Each type metadata includes both the type identifier and the offset of +/// the address point of the type (the address held by objects of that type +/// which may not be the beginning of the virtual table). Vtable definitions +/// are decorated with type metadata for the types they are compatible with. +/// +/// Holds information about vtable definitions decorated with type metadata: +/// the vtable definition value and its address point offset in a type +/// identifier metadata it is decorated (compatible) with. +struct TypeIdOffsetVtableInfo { + TypeIdOffsetVtableInfo(uint64_t Offset, ValueInfo VI) + : AddressPointOffset(Offset), VTableVI(VI) {} + + uint64_t AddressPointOffset; + ValueInfo VTableVI; +}; +/// List of vtable definitions decorated by a particular type identifier, +/// and their corresponding offsets in that type identifier's metadata. +/// Note that each type identifier may be compatible with multiple vtables, due +/// to inheritance, which is why this is a vector. +using TypeIdCompatibleVtableInfo = std::vector<TypeIdOffsetVtableInfo>; + /// Class to hold module path string table and global value map, /// and encapsulate methods for operating on them. class ModuleSummaryIndex { @@ -803,9 +921,15 @@ private: ModulePathStringTableTy ModulePathStringTable; /// Mapping from type identifier GUIDs to type identifier and its summary - /// information. + /// information. Produced by thin link. TypeIdSummaryMapTy TypeIdMap; + /// Mapping from type identifier to information about vtables decorated + /// with that type identifier's metadata. Produced by per module summary + /// analysis and consumed by thin link. For more information, see description + /// above where TypeIdCompatibleVtableInfo is defined. + std::map<std::string, TypeIdCompatibleVtableInfo> TypeIdCompatibleVtableMap; + /// Mapping from original ID to GUID. If original ID can map to multiple /// GUIDs, it will be mapped to 0. std::map<GlobalValue::GUID, GlobalValue::GUID> OidGuidMap; @@ -1044,24 +1168,30 @@ public: OidGuidMap[OrigGUID] = ValueGUID; } - /// Find the summary for global \p GUID in module \p ModuleId, or nullptr if + /// Find the summary for ValueInfo \p VI in module \p ModuleId, or nullptr if /// not found. - GlobalValueSummary *findSummaryInModule(GlobalValue::GUID ValueGUID, - StringRef ModuleId) const { - auto CalleeInfo = getValueInfo(ValueGUID); - if (!CalleeInfo) { - return nullptr; // This function does not have a summary - } + GlobalValueSummary *findSummaryInModule(ValueInfo VI, StringRef ModuleId) const { + auto SummaryList = VI.getSummaryList(); auto Summary = - llvm::find_if(CalleeInfo.getSummaryList(), + llvm::find_if(SummaryList, [&](const std::unique_ptr<GlobalValueSummary> &Summary) { return Summary->modulePath() == ModuleId; }); - if (Summary == CalleeInfo.getSummaryList().end()) + if (Summary == SummaryList.end()) return nullptr; return Summary->get(); } + /// Find the summary for global \p GUID in module \p ModuleId, or nullptr if + /// not found. + GlobalValueSummary *findSummaryInModule(GlobalValue::GUID ValueGUID, + StringRef ModuleId) const { + auto CalleeInfo = getValueInfo(ValueGUID); + if (!CalleeInfo) + return nullptr; // This function does not have a summary + return findSummaryInModule(CalleeInfo, ModuleId); + } + /// Returns the first GlobalValueSummary for \p GV, asserting that there /// is only one if \p PerModuleIndex. GlobalValueSummary *getGlobalValueSummary(const GlobalValue &GV, @@ -1163,6 +1293,29 @@ public: return nullptr; } + const std::map<std::string, TypeIdCompatibleVtableInfo> & + typeIdCompatibleVtableMap() const { + return TypeIdCompatibleVtableMap; + } + + /// Return an existing or new TypeIdCompatibleVtableMap entry for \p TypeId. + /// This accessor can mutate the map and therefore should not be used in + /// the ThinLTO backends. + TypeIdCompatibleVtableInfo & + getOrInsertTypeIdCompatibleVtableSummary(StringRef TypeId) { + return TypeIdCompatibleVtableMap[TypeId]; + } + + /// For the given \p TypeId, this returns the TypeIdCompatibleVtableMap + /// entry if present in the summary map. This may be used when importing. + Optional<TypeIdCompatibleVtableInfo> + getTypeIdCompatibleVtableSummary(StringRef TypeId) const { + auto I = TypeIdCompatibleVtableMap.find(TypeId); + if (I == TypeIdCompatibleVtableMap.end()) + return None; + return I->second; + } + /// Collect for the given module the list of functions it defines /// (GUID -> Summary). void collectDefinedFunctionsForModule(StringRef ModulePath, @@ -1170,8 +1323,16 @@ public: /// Collect for each module the list of Summaries it defines (GUID -> /// Summary). - void collectDefinedGVSummariesPerModule( - StringMap<GVSummaryMapTy> &ModuleToDefinedGVSummaries) const; + template <class Map> + void + collectDefinedGVSummariesPerModule(Map &ModuleToDefinedGVSummaries) const { + for (auto &GlobalList : *this) { + auto GUID = GlobalList.first; + for (auto &Summary : GlobalList.second.SummaryList) { + ModuleToDefinedGVSummaries[Summary->modulePath()][GUID] = Summary.get(); + } + } + } /// Print to an output stream. void print(raw_ostream &OS, bool IsForDebug = false) const; @@ -1186,7 +1347,7 @@ public: void dumpSCCs(raw_ostream &OS); /// Analyze index and detect unmodified globals - void propagateConstants(const DenseSet<GlobalValue::GUID> &PreservedSymbols); + void propagateAttributes(const DenseSet<GlobalValue::GUID> &PreservedSymbols); }; /// GraphTraits definition to build SCC for the index |