Skip to content

Commit

Permalink
[ThinLTO] Internalize readonly globals
Browse files Browse the repository at this point in the history
This patch allows internalising globals if all accesses to them
(from live functions) are from non-volatile load instructions

Differential revision: https://reviews.llvm.org/D49362

llvm-svn: 346584
  • Loading branch information
eleviant committed Nov 10, 2018
1 parent 825f9d3 commit be8d199
Show file tree
Hide file tree
Showing 42 changed files with 774 additions and 89 deletions.
50 changes: 38 additions & 12 deletions llvm/include/llvm/IR/ModuleSummaryIndex.h
Expand Up @@ -163,13 +163,13 @@ using GlobalValueSummaryMapTy =
/// Struct that holds a reference to a particular GUID in a global value
/// summary.
struct ValueInfo {
PointerIntPair<const GlobalValueSummaryMapTy::value_type *, 1, bool>
RefAndFlag;
PointerIntPair<const GlobalValueSummaryMapTy::value_type *, 2, int>
RefAndFlags;

ValueInfo() = default;
ValueInfo(bool HaveGVs, const GlobalValueSummaryMapTy::value_type *R) {
RefAndFlag.setPointer(R);
RefAndFlag.setInt(HaveGVs);
RefAndFlags.setPointer(R);
RefAndFlags.setInt(HaveGVs);
}

operator bool() const { return getRef(); }
Expand All @@ -189,10 +189,12 @@ struct ValueInfo {
: getRef()->second.U.Name;
}

bool haveGVs() const { return RefAndFlag.getInt(); }
bool haveGVs() const { return RefAndFlags.getInt() & 0x1; }
bool isReadOnly() const { return RefAndFlags.getInt() & 0x2; }
void setReadOnly() { RefAndFlags.setInt(RefAndFlags.getInt() | 0x2); }

const GlobalValueSummaryMapTy::value_type *getRef() const {
return RefAndFlag.getPointer();
return RefAndFlags.getPointer();
}

bool isDSOLocal() const;
Expand Down Expand Up @@ -543,6 +545,8 @@ class FunctionSummary : public GlobalValueSummary {
std::move(TypeTestAssumeConstVCalls),
std::move(TypeCheckedLoadConstVCalls)});
}
// Gets the number of immutable refs in RefEdgeList
unsigned immutableRefCount() const;

/// Check if this is a function summary.
static bool classof(const GlobalValueSummary *GVS) {
Expand Down Expand Up @@ -652,19 +656,30 @@ template <> struct DenseMapInfo<FunctionSummary::ConstVCall> {
/// Global variable summary information to aid decisions and
/// implementation of importing.
///
/// Currently this doesn't add anything to the base \p GlobalValueSummary,
/// but is a placeholder as additional info may be added to the summary
/// for variables.
/// Global variable summary has extra flag, telling if it is
/// modified during the program run or not. This affects ThinLTO
/// internalization
class GlobalVarSummary : public GlobalValueSummary {

public:
GlobalVarSummary(GVFlags Flags, std::vector<ValueInfo> Refs)
: GlobalValueSummary(GlobalVarKind, Flags, std::move(Refs)) {}
struct GVarFlags {
GVarFlags(bool ReadOnly = false) : ReadOnly(ReadOnly) {}

unsigned ReadOnly : 1;
} VarFlags;

GlobalVarSummary(GVFlags Flags, GVarFlags VarFlags,
std::vector<ValueInfo> Refs)
: GlobalValueSummary(GlobalVarKind, Flags, std::move(Refs)),
VarFlags(VarFlags) {}

/// Check if this is a global variable summary.
static bool classof(const GlobalValueSummary *GVS) {
return GVS->getSummaryKind() == GlobalVarKind;
}

GVarFlags varflags() const { return VarFlags; }
void setReadOnly(bool RO) { VarFlags.ReadOnly = RO; }
bool isReadOnly() const { return VarFlags.ReadOnly; }
};

struct TypeTestResolution {
Expand Down Expand Up @@ -1135,6 +1150,9 @@ class ModuleSummaryIndex {

/// Print out strongly connected components for debugging.
void dumpSCCs(raw_ostream &OS);

/// Analyze index and detect unmodified globals
void propagateConstants(const DenseSet<GlobalValue::GUID> &PreservedSymbols);
};

/// GraphTraits definition to build SCC for the index
Expand Down Expand Up @@ -1184,6 +1202,14 @@ struct GraphTraits<ModuleSummaryIndex *> : public GraphTraits<ValueInfo> {
}
};

static inline bool canImportGlobalVar(GlobalValueSummary *S) {
assert(isa<GlobalVarSummary>(S->getBaseObject()));

// We don't import GV with references, because it can result
// in promotion of local variables in the source module.
return !GlobalValue::isInterposableLinkage(S->linkage()) &&
!S->notEligibleToImport() && S->refs().empty();
}
} // end namespace llvm

#endif // LLVM_IR_MODULESUMMARYINDEX_H
8 changes: 8 additions & 0 deletions llvm/include/llvm/Transforms/IPO/FunctionImport.h
Expand Up @@ -176,6 +176,14 @@ void computeDeadSymbols(
const DenseSet<GlobalValue::GUID> &GUIDPreservedSymbols,
function_ref<PrevailingType(GlobalValue::GUID)> isPrevailing);

/// Compute dead symbols and run constant propagation in combined index
/// after that.
void computeDeadSymbolsWithConstProp(
ModuleSummaryIndex &Index,
const DenseSet<GlobalValue::GUID> &GUIDPreservedSymbols,
function_ref<PrevailingType(GlobalValue::GUID)> isPrevailing,
bool ImportEnabled);

/// Converts value \p GV to declaration, or replaces with a declaration if
/// it is an alias. Returns true if converted, false if replaced.
bool convertToDeclaration(GlobalValue &GV);
Expand Down
1 change: 0 additions & 1 deletion llvm/include/llvm/Transforms/Utils/FunctionImportUtils.h
Expand Up @@ -113,7 +113,6 @@ class FunctionImportGlobalProcessing {
bool renameModuleForThinLTO(
Module &M, const ModuleSummaryIndex &Index,
SetVector<GlobalValue *> *GlobalsToImport = nullptr);

} // End llvm namespace

#endif
75 changes: 58 additions & 17 deletions llvm/lib/Analysis/ModuleSummaryAnalysis.cpp
Expand Up @@ -220,10 +220,19 @@ static void addIntrinsicToSummary(
}
}

static void computeFunctionSummary(
ModuleSummaryIndex &Index, const Module &M, const Function &F,
BlockFrequencyInfo *BFI, ProfileSummaryInfo *PSI, DominatorTree &DT,
bool HasLocalsInUsedOrAsm, DenseSet<GlobalValue::GUID> &CantBePromoted) {
static bool isNonVolatileLoad(const Instruction *I) {
if (const auto *LI = dyn_cast<LoadInst>(I))
return !LI->isVolatile();

return false;
}

static void computeFunctionSummary(ModuleSummaryIndex &Index, const Module &M,
const Function &F, BlockFrequencyInfo *BFI,
ProfileSummaryInfo *PSI, DominatorTree &DT,
bool HasLocalsInUsedOrAsm,
DenseSet<GlobalValue::GUID> &CantBePromoted,
bool IsThinLTO) {
// Summary not currently supported for anonymous functions, they should
// have been named.
assert(F.hasName());
Expand All @@ -244,13 +253,21 @@ static void computeFunctionSummary(
// Add personality function, prefix data and prologue data to function's ref
// list.
findRefEdges(Index, &F, RefEdges, Visited);
std::vector<const Instruction *> NonVolatileLoads;

bool HasInlineAsmMaybeReferencingInternal = false;
for (const BasicBlock &BB : F)
for (const Instruction &I : BB) {
if (isa<DbgInfoIntrinsic>(I))
continue;
++NumInsts;
if (isNonVolatileLoad(&I)) {
// Postpone processing of non-volatile load instructions
// See comments below
Visited.insert(&I);
NonVolatileLoads.push_back(&I);
continue;
}
findRefEdges(Index, &I, RefEdges, Visited);
auto CS = ImmutableCallSite(&I);
if (!CS)
Expand Down Expand Up @@ -340,6 +357,24 @@ static void computeFunctionSummary(
}
}

// By now we processed all instructions in a function, except
// non-volatile loads. All new refs we add in a loop below
// are obviously constant. All constant refs are grouped in the
// end of RefEdges vector, so we can use a single integer value
// to identify them.
unsigned RefCnt = RefEdges.size();
for (const Instruction *I : NonVolatileLoads) {
Visited.erase(I);
findRefEdges(Index, I, RefEdges, Visited);
}
std::vector<ValueInfo> Refs = RefEdges.takeVector();
// Regular LTO module doesn't participate in ThinLTO import,
// so no reference from it can be readonly, since this would
// require importing variable as local copy
if (IsThinLTO)
for (; RefCnt < Refs.size(); ++RefCnt)
Refs[RefCnt].setReadOnly();

// Explicit add hot edges to enforce importing for designated GUIDs for
// sample PGO, to enable the same inlines as the profiled optimized binary.
for (auto &I : F.getImportGUIDs())
Expand All @@ -363,9 +398,9 @@ static void computeFunctionSummary(
// Don't try to import functions with noinline attribute.
F.getAttributes().hasFnAttribute(Attribute::NoInline)};
auto FuncSummary = llvm::make_unique<FunctionSummary>(
Flags, NumInsts, FunFlags, RefEdges.takeVector(),
CallGraphEdges.takeVector(), TypeTests.takeVector(),
TypeTestAssumeVCalls.takeVector(), TypeCheckedLoadVCalls.takeVector(),
Flags, NumInsts, FunFlags, std::move(Refs), CallGraphEdges.takeVector(),
TypeTests.takeVector(), TypeTestAssumeVCalls.takeVector(),
TypeCheckedLoadVCalls.takeVector(),
TypeTestAssumeConstVCalls.takeVector(),
TypeCheckedLoadConstVCalls.takeVector());
if (NonRenamableLocal)
Expand All @@ -382,8 +417,13 @@ computeVariableSummary(ModuleSummaryIndex &Index, const GlobalVariable &V,
bool NonRenamableLocal = isNonRenamableLocal(V);
GlobalValueSummary::GVFlags Flags(V.getLinkage(), NonRenamableLocal,
/* Live = */ false, V.isDSOLocal());
auto GVarSummary =
llvm::make_unique<GlobalVarSummary>(Flags, RefEdges.takeVector());

// Don't mark variables we won't be able to internalize as read-only.
GlobalVarSummary::GVarFlags VarFlags(
!V.hasComdat() && !V.hasAppendingLinkage() && !V.isInterposable() &&
!V.hasAvailableExternallyLinkage() && !V.hasDLLExportStorageClass());
auto GVarSummary = llvm::make_unique<GlobalVarSummary>(Flags, VarFlags,
RefEdges.takeVector());
if (NonRenamableLocal)
CantBePromoted.insert(V.getGUID());
if (HasBlockAddress)
Expand Down Expand Up @@ -487,13 +527,19 @@ ModuleSummaryIndex llvm::buildModuleSummaryIndex(
Index.addGlobalValueSummary(*GV, std::move(Summary));
} else {
std::unique_ptr<GlobalVarSummary> Summary =
llvm::make_unique<GlobalVarSummary>(GVFlags,
ArrayRef<ValueInfo>{});
llvm::make_unique<GlobalVarSummary>(
GVFlags, GlobalVarSummary::GVarFlags(),
ArrayRef<ValueInfo>{});
Index.addGlobalValueSummary(*GV, std::move(Summary));
}
});
}

bool IsThinLTO = true;
if (auto *MD =
mdconst::extract_or_null<ConstantInt>(M.getModuleFlag("ThinLTO")))
IsThinLTO = MD->getZExtValue();

// Compute summaries for all functions defined in module, and save in the
// index.
for (auto &F : M) {
Expand All @@ -514,7 +560,7 @@ ModuleSummaryIndex llvm::buildModuleSummaryIndex(

computeFunctionSummary(Index, M, F, BFI, PSI, DT,
!LocalsUsed.empty() || HasLocalInlineAsmSymbol,
CantBePromoted);
CantBePromoted, IsThinLTO);
}

// Compute summaries for all variables defined in module, and save in the
Expand Down Expand Up @@ -545,11 +591,6 @@ ModuleSummaryIndex llvm::buildModuleSummaryIndex(
setLiveRoot(Index, "llvm.global_dtors");
setLiveRoot(Index, "llvm.global.annotations");

bool IsThinLTO = true;
if (auto *MD =
mdconst::extract_or_null<ConstantInt>(M.getModuleFlag("ThinLTO")))
IsThinLTO = MD->getZExtValue();

for (auto &GlobalList : Index) {
// Ignore entries for references that are undefined in the current module.
if (GlobalList.second.SummaryList.empty())
Expand Down
3 changes: 2 additions & 1 deletion llvm/lib/AsmParser/LLParser.cpp
Expand Up @@ -7642,7 +7642,8 @@ bool LLParser::ParseVariableSummary(std::string Name, GlobalValue::GUID GUID,
if (ParseToken(lltok::rparen, "expected ')' here"))
return true;

auto GS = llvm::make_unique<GlobalVarSummary>(GVFlags, std::move(Refs));
auto GS = llvm::make_unique<GlobalVarSummary>(
GVFlags, GlobalVarSummary::GVarFlags(), std::move(Refs));

GS->setModulePath(ModulePath);

Expand Down

0 comments on commit be8d199

Please sign in to comment.