2016-04-11 21:58:45 +08:00
|
|
|
//===- ModuleSummaryAnalysis.cpp - Module summary index builder -----------===//
|
|
|
|
//
|
2019-01-19 16:50:56 +08:00
|
|
|
// 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
|
2016-04-11 21:58:45 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This pass builds a ModuleSummaryIndex object for the module, to be written
|
|
|
|
// to bitcode or LLVM assembly.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2020-04-14 08:27:08 +08:00
|
|
|
#include "llvm/Analysis/ModuleSummaryAnalysis.h"
|
2017-08-17 06:07:40 +08:00
|
|
|
#include "llvm/ADT/ArrayRef.h"
|
|
|
|
#include "llvm/ADT/DenseSet.h"
|
2016-12-21 05:12:28 +08:00
|
|
|
#include "llvm/ADT/MapVector.h"
|
2017-08-17 06:07:40 +08:00
|
|
|
#include "llvm/ADT/STLExtras.h"
|
2016-12-21 05:12:28 +08:00
|
|
|
#include "llvm/ADT/SetVector.h"
|
2017-08-17 06:07:40 +08:00
|
|
|
#include "llvm/ADT/SmallPtrSet.h"
|
|
|
|
#include "llvm/ADT/SmallVector.h"
|
|
|
|
#include "llvm/ADT/StringRef.h"
|
2016-04-11 21:58:45 +08:00
|
|
|
#include "llvm/Analysis/BlockFrequencyInfo.h"
|
|
|
|
#include "llvm/Analysis/BranchProbabilityInfo.h"
|
2016-07-17 22:47:01 +08:00
|
|
|
#include "llvm/Analysis/IndirectCallPromotionAnalysis.h"
|
2016-04-11 21:58:45 +08:00
|
|
|
#include "llvm/Analysis/LoopInfo.h"
|
[thinlto] Basic thinlto fdo heuristic
Summary:
This patch improves thinlto importer
by importing 3x larger functions that are called from hot block.
I compared performance with the trunk on spec, and there
were about 2% on povray and 3.33% on milc. These results seems
to be consistant and match the results Teresa got with her simple
heuristic. Some benchmarks got slower but I think they are just
noisy (mcf, xalancbmki, omnetpp)- running the benchmarks again with
more iterations to confirm. Geomean of all benchmarks including the noisy ones
were about +0.02%.
I see much better improvement on google branch with Easwaran patch
for pgo callsite inlining (the inliner actually inline those big functions)
Over all I see +0.5% improvement, and I get +8.65% on povray.
So I guess we will see much bigger change when Easwaran patch will land
(it depends on new pass manager), but it is still worth putting this to trunk
before it.
Implementation details changes:
- Removed CallsiteCount.
- ProfileCount got replaced by Hotness
- hot-import-multiplier is set to 3.0 for now,
didn't have time to tune it up, but I see that we get most of the interesting
functions with 3, so there is no much performance difference with higher, and
binary size doesn't grow as much as with 10.0.
Reviewers: eraman, mehdi_amini, tejohnson
Subscribers: mehdi_amini, llvm-commits
Differential Revision: https://reviews.llvm.org/D24638
llvm-svn: 282437
2016-09-27 04:37:32 +08:00
|
|
|
#include "llvm/Analysis/ProfileSummaryInfo.h"
|
2020-06-01 14:49:57 +08:00
|
|
|
#include "llvm/Analysis/StackSafetyAnalysis.h"
|
2016-12-22 07:03:45 +08:00
|
|
|
#include "llvm/Analysis/TypeMetadataUtils.h"
|
2017-08-17 06:07:40 +08:00
|
|
|
#include "llvm/IR/Attributes.h"
|
|
|
|
#include "llvm/IR/BasicBlock.h"
|
|
|
|
#include "llvm/IR/Constant.h"
|
|
|
|
#include "llvm/IR/Constants.h"
|
2016-04-11 21:58:45 +08:00
|
|
|
#include "llvm/IR/Dominators.h"
|
2017-08-17 06:07:40 +08:00
|
|
|
#include "llvm/IR/Function.h"
|
|
|
|
#include "llvm/IR/GlobalAlias.h"
|
|
|
|
#include "llvm/IR/GlobalValue.h"
|
|
|
|
#include "llvm/IR/GlobalVariable.h"
|
|
|
|
#include "llvm/IR/Instructions.h"
|
2016-04-11 21:58:45 +08:00
|
|
|
#include "llvm/IR/IntrinsicInst.h"
|
2017-08-17 06:07:40 +08:00
|
|
|
#include "llvm/IR/Intrinsics.h"
|
|
|
|
#include "llvm/IR/Metadata.h"
|
|
|
|
#include "llvm/IR/Module.h"
|
|
|
|
#include "llvm/IR/ModuleSummaryIndex.h"
|
|
|
|
#include "llvm/IR/Use.h"
|
|
|
|
#include "llvm/IR/User.h"
|
Sink all InitializePasses.h includes
This file lists every pass in LLVM, and is included by Pass.h, which is
very popular. Every time we add, remove, or rename a pass in LLVM, it
caused lots of recompilation.
I found this fact by looking at this table, which is sorted by the
number of times a file was changed over the last 100,000 git commits
multiplied by the number of object files that depend on it in the
current checkout:
recompiles touches affected_files header
342380 95 3604 llvm/include/llvm/ADT/STLExtras.h
314730 234 1345 llvm/include/llvm/InitializePasses.h
307036 118 2602 llvm/include/llvm/ADT/APInt.h
213049 59 3611 llvm/include/llvm/Support/MathExtras.h
170422 47 3626 llvm/include/llvm/Support/Compiler.h
162225 45 3605 llvm/include/llvm/ADT/Optional.h
158319 63 2513 llvm/include/llvm/ADT/Triple.h
140322 39 3598 llvm/include/llvm/ADT/StringRef.h
137647 59 2333 llvm/include/llvm/Support/Error.h
131619 73 1803 llvm/include/llvm/Support/FileSystem.h
Before this change, touching InitializePasses.h would cause 1345 files
to recompile. After this change, touching it only causes 550 compiles in
an incremental rebuild.
Reviewers: bkramer, asbirlea, bollu, jdoerfert
Differential Revision: https://reviews.llvm.org/D70211
2019-11-14 05:15:01 +08:00
|
|
|
#include "llvm/InitializePasses.h"
|
2017-03-31 08:08:24 +08:00
|
|
|
#include "llvm/Object/ModuleSymbolTable.h"
|
2017-08-17 06:07:40 +08:00
|
|
|
#include "llvm/Object/SymbolicFile.h"
|
2016-04-11 21:58:45 +08:00
|
|
|
#include "llvm/Pass.h"
|
2017-08-17 06:07:40 +08:00
|
|
|
#include "llvm/Support/Casting.h"
|
2018-03-31 08:18:08 +08:00
|
|
|
#include "llvm/Support/CommandLine.h"
|
2021-04-21 22:00:30 +08:00
|
|
|
#include "llvm/Support/FileSystem.h"
|
2017-08-17 06:07:40 +08:00
|
|
|
#include <algorithm>
|
|
|
|
#include <cassert>
|
|
|
|
#include <cstdint>
|
|
|
|
#include <vector>
|
|
|
|
|
2016-04-11 21:58:45 +08:00
|
|
|
using namespace llvm;
|
|
|
|
|
|
|
|
#define DEBUG_TYPE "module-summary-analysis"
|
|
|
|
|
2018-03-31 08:18:08 +08:00
|
|
|
// Option to force edges cold which will block importing when the
|
|
|
|
// -import-cold-multiplier is set to 0. Useful for debugging.
|
|
|
|
FunctionSummary::ForceSummaryHotnessType ForceSummaryEdgesCold =
|
|
|
|
FunctionSummary::FSHT_None;
|
|
|
|
cl::opt<FunctionSummary::ForceSummaryHotnessType, true> FSEC(
|
|
|
|
"force-summary-edges-cold", cl::Hidden, cl::location(ForceSummaryEdgesCold),
|
|
|
|
cl::desc("Force all edges in the function summary to cold"),
|
|
|
|
cl::values(clEnumValN(FunctionSummary::FSHT_None, "none", "None."),
|
|
|
|
clEnumValN(FunctionSummary::FSHT_AllNonCritical,
|
|
|
|
"all-non-critical", "All non-critical edges."),
|
|
|
|
clEnumValN(FunctionSummary::FSHT_All, "all", "All edges.")));
|
|
|
|
|
2019-01-29 07:43:26 +08:00
|
|
|
cl::opt<std::string> ModuleSummaryDotFile(
|
|
|
|
"module-summary-dot-file", cl::init(""), cl::Hidden,
|
|
|
|
cl::value_desc("filename"),
|
|
|
|
cl::desc("File to emit dot graph of new summary into."));
|
|
|
|
|
2016-04-11 21:58:45 +08:00
|
|
|
// Walk through the operands of a given User via worklist iteration and populate
|
|
|
|
// the set of GlobalValue references encountered. Invoked either on an
|
|
|
|
// Instruction or a GlobalVariable (which walks its initializer).
|
2018-10-12 15:24:02 +08:00
|
|
|
// Return true if any of the operands contains blockaddress. This is important
|
|
|
|
// to know when computing summary for global var, because if global variable
|
|
|
|
// references basic block address we can't import it separately from function
|
|
|
|
// containing that basic block. For simplicity we currently don't import such
|
2020-02-18 10:48:38 +08:00
|
|
|
// global vars at all. When importing function we aren't interested if any
|
2018-10-12 15:24:02 +08:00
|
|
|
// instruction in it takes an address of any basic block, because instruction
|
|
|
|
// can only take an address of basic block located in the same function.
|
|
|
|
static bool findRefEdges(ModuleSummaryIndex &Index, const User *CurUser,
|
2017-05-05 02:03:25 +08:00
|
|
|
SetVector<ValueInfo> &RefEdges,
|
2016-04-11 21:58:45 +08:00
|
|
|
SmallPtrSet<const User *, 8> &Visited) {
|
2018-10-12 15:24:02 +08:00
|
|
|
bool HasBlockAddress = false;
|
2016-04-11 21:58:45 +08:00
|
|
|
SmallVector<const User *, 32> Worklist;
|
2021-03-07 06:19:22 +08:00
|
|
|
if (Visited.insert(CurUser).second)
|
|
|
|
Worklist.push_back(CurUser);
|
2016-04-11 21:58:45 +08:00
|
|
|
|
|
|
|
while (!Worklist.empty()) {
|
|
|
|
const User *U = Worklist.pop_back_val();
|
2020-04-23 04:19:15 +08:00
|
|
|
const auto *CB = dyn_cast<CallBase>(U);
|
2016-04-11 21:58:45 +08:00
|
|
|
|
|
|
|
for (const auto &OI : U->operands()) {
|
|
|
|
const User *Operand = dyn_cast<User>(OI);
|
|
|
|
if (!Operand)
|
|
|
|
continue;
|
2018-10-12 15:24:02 +08:00
|
|
|
if (isa<BlockAddress>(Operand)) {
|
|
|
|
HasBlockAddress = true;
|
2016-04-11 21:58:45 +08:00
|
|
|
continue;
|
2018-10-12 15:24:02 +08:00
|
|
|
}
|
2016-12-21 05:12:28 +08:00
|
|
|
if (auto *GV = dyn_cast<GlobalValue>(Operand)) {
|
2016-04-11 21:58:45 +08:00
|
|
|
// We have a reference to a global value. This should be added to
|
|
|
|
// the reference set unless it is a callee. Callees are handled
|
|
|
|
// specially by WriteFunction and are added to a separate list.
|
2020-04-23 04:19:15 +08:00
|
|
|
if (!(CB && CB->isCallee(&OI)))
|
2017-05-05 02:03:25 +08:00
|
|
|
RefEdges.insert(Index.getOrInsertValueInfo(GV));
|
2016-04-11 21:58:45 +08:00
|
|
|
continue;
|
|
|
|
}
|
2021-03-07 06:19:22 +08:00
|
|
|
if (Visited.insert(Operand).second)
|
|
|
|
Worklist.push_back(Operand);
|
2016-04-11 21:58:45 +08:00
|
|
|
}
|
|
|
|
}
|
2018-10-12 15:24:02 +08:00
|
|
|
return HasBlockAddress;
|
2016-04-11 21:58:45 +08:00
|
|
|
}
|
|
|
|
|
[thinlto] Basic thinlto fdo heuristic
Summary:
This patch improves thinlto importer
by importing 3x larger functions that are called from hot block.
I compared performance with the trunk on spec, and there
were about 2% on povray and 3.33% on milc. These results seems
to be consistant and match the results Teresa got with her simple
heuristic. Some benchmarks got slower but I think they are just
noisy (mcf, xalancbmki, omnetpp)- running the benchmarks again with
more iterations to confirm. Geomean of all benchmarks including the noisy ones
were about +0.02%.
I see much better improvement on google branch with Easwaran patch
for pgo callsite inlining (the inliner actually inline those big functions)
Over all I see +0.5% improvement, and I get +8.65% on povray.
So I guess we will see much bigger change when Easwaran patch will land
(it depends on new pass manager), but it is still worth putting this to trunk
before it.
Implementation details changes:
- Removed CallsiteCount.
- ProfileCount got replaced by Hotness
- hot-import-multiplier is set to 3.0 for now,
didn't have time to tune it up, but I see that we get most of the interesting
functions with 3, so there is no much performance difference with higher, and
binary size doesn't grow as much as with 10.0.
Reviewers: eraman, mehdi_amini, tejohnson
Subscribers: mehdi_amini, llvm-commits
Differential Revision: https://reviews.llvm.org/D24638
llvm-svn: 282437
2016-09-27 04:37:32 +08:00
|
|
|
static CalleeInfo::HotnessType getHotness(uint64_t ProfileCount,
|
|
|
|
ProfileSummaryInfo *PSI) {
|
|
|
|
if (!PSI)
|
|
|
|
return CalleeInfo::HotnessType::Unknown;
|
|
|
|
if (PSI->isHotCount(ProfileCount))
|
|
|
|
return CalleeInfo::HotnessType::Hot;
|
|
|
|
if (PSI->isColdCount(ProfileCount))
|
|
|
|
return CalleeInfo::HotnessType::Cold;
|
|
|
|
return CalleeInfo::HotnessType::None;
|
|
|
|
}
|
|
|
|
|
2017-01-05 22:32:16 +08:00
|
|
|
static bool isNonRenamableLocal(const GlobalValue &GV) {
|
|
|
|
return GV.hasSection() && GV.hasLocalLinkage();
|
|
|
|
}
|
|
|
|
|
2017-02-11 06:29:38 +08:00
|
|
|
/// Determine whether this call has all constant integer arguments (excluding
|
|
|
|
/// "this") and summarize it to VCalls or ConstVCalls as appropriate.
|
|
|
|
static void addVCallToSet(DevirtCallSite Call, GlobalValue::GUID Guid,
|
|
|
|
SetVector<FunctionSummary::VFuncId> &VCalls,
|
|
|
|
SetVector<FunctionSummary::ConstVCall> &ConstVCalls) {
|
|
|
|
std::vector<uint64_t> Args;
|
|
|
|
// Start from the second argument to skip the "this" pointer.
|
2021-01-19 02:16:36 +08:00
|
|
|
for (auto &Arg : drop_begin(Call.CB.args())) {
|
2017-02-11 06:29:38 +08:00
|
|
|
auto *CI = dyn_cast<ConstantInt>(Arg);
|
|
|
|
if (!CI || CI->getBitWidth() > 64) {
|
|
|
|
VCalls.insert({Guid, Call.Offset});
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
Args.push_back(CI->getZExtValue());
|
|
|
|
}
|
|
|
|
ConstVCalls.insert({{Guid, Call.Offset}, std::move(Args)});
|
|
|
|
}
|
|
|
|
|
|
|
|
/// If this intrinsic call requires that we add information to the function
|
|
|
|
/// summary, do so via the non-constant reference arguments.
|
|
|
|
static void addIntrinsicToSummary(
|
|
|
|
const CallInst *CI, SetVector<GlobalValue::GUID> &TypeTests,
|
|
|
|
SetVector<FunctionSummary::VFuncId> &TypeTestAssumeVCalls,
|
|
|
|
SetVector<FunctionSummary::VFuncId> &TypeCheckedLoadVCalls,
|
|
|
|
SetVector<FunctionSummary::ConstVCall> &TypeTestAssumeConstVCalls,
|
2018-09-27 22:55:32 +08:00
|
|
|
SetVector<FunctionSummary::ConstVCall> &TypeCheckedLoadConstVCalls,
|
|
|
|
DominatorTree &DT) {
|
2017-02-11 06:29:38 +08:00
|
|
|
switch (CI->getCalledFunction()->getIntrinsicID()) {
|
|
|
|
case Intrinsic::type_test: {
|
|
|
|
auto *TypeMDVal = cast<MetadataAsValue>(CI->getArgOperand(1));
|
|
|
|
auto *TypeId = dyn_cast<MDString>(TypeMDVal->getMetadata());
|
|
|
|
if (!TypeId)
|
|
|
|
break;
|
|
|
|
GlobalValue::GUID Guid = GlobalValue::getGUID(TypeId->getString());
|
|
|
|
|
|
|
|
// Produce a summary from type.test intrinsics. We only summarize type.test
|
|
|
|
// intrinsics that are used other than by an llvm.assume intrinsic.
|
|
|
|
// Intrinsics that are assumed are relevant only to the devirtualization
|
|
|
|
// pass, not the type test lowering pass.
|
|
|
|
bool HasNonAssumeUses = llvm::any_of(CI->uses(), [](const Use &CIU) {
|
2021-04-07 04:17:35 +08:00
|
|
|
return !isa<AssumeInst>(CIU.getUser());
|
2017-02-11 06:29:38 +08:00
|
|
|
});
|
|
|
|
if (HasNonAssumeUses)
|
|
|
|
TypeTests.insert(Guid);
|
|
|
|
|
|
|
|
SmallVector<DevirtCallSite, 4> DevirtCalls;
|
|
|
|
SmallVector<CallInst *, 4> Assumes;
|
2018-09-27 22:55:32 +08:00
|
|
|
findDevirtualizableCallsForTypeTest(DevirtCalls, Assumes, CI, DT);
|
2017-02-11 06:29:38 +08:00
|
|
|
for (auto &Call : DevirtCalls)
|
|
|
|
addVCallToSet(Call, Guid, TypeTestAssumeVCalls,
|
|
|
|
TypeTestAssumeConstVCalls);
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case Intrinsic::type_checked_load: {
|
|
|
|
auto *TypeMDVal = cast<MetadataAsValue>(CI->getArgOperand(2));
|
|
|
|
auto *TypeId = dyn_cast<MDString>(TypeMDVal->getMetadata());
|
|
|
|
if (!TypeId)
|
|
|
|
break;
|
|
|
|
GlobalValue::GUID Guid = GlobalValue::getGUID(TypeId->getString());
|
|
|
|
|
|
|
|
SmallVector<DevirtCallSite, 4> DevirtCalls;
|
|
|
|
SmallVector<Instruction *, 4> LoadedPtrs;
|
|
|
|
SmallVector<Instruction *, 4> Preds;
|
|
|
|
bool HasNonCallUses = false;
|
|
|
|
findDevirtualizableCallsForTypeCheckedLoad(DevirtCalls, LoadedPtrs, Preds,
|
2018-09-27 22:55:32 +08:00
|
|
|
HasNonCallUses, CI, DT);
|
2017-02-11 06:29:38 +08:00
|
|
|
// Any non-call uses of the result of llvm.type.checked.load will
|
|
|
|
// prevent us from optimizing away the llvm.type.test.
|
|
|
|
if (HasNonCallUses)
|
|
|
|
TypeTests.insert(Guid);
|
|
|
|
for (auto &Call : DevirtCalls)
|
|
|
|
addVCallToSet(Call, Guid, TypeCheckedLoadVCalls,
|
|
|
|
TypeCheckedLoadConstVCalls);
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-16 15:08:00 +08:00
|
|
|
static bool isNonVolatileLoad(const Instruction *I) {
|
|
|
|
if (const auto *LI = dyn_cast<LoadInst>(I))
|
|
|
|
return !LI->isVolatile();
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-07-05 23:25:05 +08:00
|
|
|
static bool isNonVolatileStore(const Instruction *I) {
|
|
|
|
if (const auto *SI = dyn_cast<StoreInst>(I))
|
|
|
|
return !SI->isVolatile();
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-06-01 14:49:57 +08:00
|
|
|
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,
|
|
|
|
std::function<const StackSafetyInfo *(const Function &F)> GetSSICallback) {
|
2016-10-28 10:39:38 +08:00
|
|
|
// Summary not currently supported for anonymous functions, they should
|
|
|
|
// have been named.
|
|
|
|
assert(F.hasName());
|
2016-04-11 21:58:45 +08:00
|
|
|
|
|
|
|
unsigned NumInsts = 0;
|
|
|
|
// Map from callee ValueId to profile count. Used to accumulate profile
|
|
|
|
// counts for all static calls to a given callee.
|
2016-12-21 05:12:28 +08:00
|
|
|
MapVector<ValueInfo, CalleeInfo> CallGraphEdges;
|
2019-07-05 23:25:05 +08:00
|
|
|
SetVector<ValueInfo> RefEdges, LoadRefEdges, StoreRefEdges;
|
2016-12-22 07:03:45 +08:00
|
|
|
SetVector<GlobalValue::GUID> TypeTests;
|
2017-02-11 06:29:38 +08:00
|
|
|
SetVector<FunctionSummary::VFuncId> TypeTestAssumeVCalls,
|
|
|
|
TypeCheckedLoadVCalls;
|
|
|
|
SetVector<FunctionSummary::ConstVCall> TypeTestAssumeConstVCalls,
|
|
|
|
TypeCheckedLoadConstVCalls;
|
2016-07-17 22:47:01 +08:00
|
|
|
ICallPromotionAnalysis ICallAnalysis;
|
2017-09-07 13:35:35 +08:00
|
|
|
SmallPtrSet<const User *, 8> Visited;
|
|
|
|
|
|
|
|
// Add personality function, prefix data and prologue data to function's ref
|
|
|
|
// list.
|
|
|
|
findRefEdges(Index, &F, RefEdges, Visited);
|
2018-11-16 15:08:00 +08:00
|
|
|
std::vector<const Instruction *> NonVolatileLoads;
|
2019-07-05 23:25:05 +08:00
|
|
|
std::vector<const Instruction *> NonVolatileStores;
|
2016-04-11 21:58:45 +08:00
|
|
|
|
2016-11-15 00:40:19 +08:00
|
|
|
bool HasInlineAsmMaybeReferencingInternal = false;
|
2021-07-28 09:00:55 +08:00
|
|
|
bool HasIndirBranchToBlockAddress = false;
|
|
|
|
for (const BasicBlock &BB : F) {
|
|
|
|
// We don't allow inlining of function with indirect branch to blockaddress.
|
|
|
|
// If the blockaddress escapes the function, e.g., via a global variable,
|
|
|
|
// inlining may lead to an invalid cross-function reference. So we shouldn't
|
|
|
|
// import such function either.
|
|
|
|
if (BB.hasAddressTaken()) {
|
|
|
|
for (User *U : BlockAddress::get(const_cast<BasicBlock *>(&BB))->users())
|
|
|
|
if (!isa<CallBrInst>(*U)) {
|
|
|
|
HasIndirBranchToBlockAddress = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-27 01:27:42 +08:00
|
|
|
for (const Instruction &I : BB) {
|
2021-09-18 00:21:39 +08:00
|
|
|
if (I.isDebugOrPseudoInst())
|
2016-08-30 08:46:26 +08:00
|
|
|
continue;
|
|
|
|
++NumInsts;
|
2019-07-05 23:25:05 +08:00
|
|
|
// Regular LTO module doesn't participate in ThinLTO import,
|
|
|
|
// so no reference from it can be read/writeonly, since this
|
|
|
|
// would require importing variable as local copy
|
|
|
|
if (IsThinLTO) {
|
|
|
|
if (isNonVolatileLoad(&I)) {
|
|
|
|
// Postpone processing of non-volatile load instructions
|
|
|
|
// See comments below
|
|
|
|
Visited.insert(&I);
|
|
|
|
NonVolatileLoads.push_back(&I);
|
|
|
|
continue;
|
|
|
|
} else if (isNonVolatileStore(&I)) {
|
|
|
|
Visited.insert(&I);
|
|
|
|
NonVolatileStores.push_back(&I);
|
|
|
|
// All references from second operand of store (destination address)
|
|
|
|
// can be considered write-only if they're not referenced by any
|
|
|
|
// non-store instruction. References from first operand of store
|
|
|
|
// (stored value) can't be treated either as read- or as write-only
|
|
|
|
// so we add them to RefEdges as we do with all other instructions
|
|
|
|
// except non-volatile load.
|
|
|
|
Value *Stored = I.getOperand(0);
|
|
|
|
if (auto *GV = dyn_cast<GlobalValue>(Stored))
|
|
|
|
// findRefEdges will try to examine GV operands, so instead
|
|
|
|
// of calling it we should add GV to RefEdges directly.
|
|
|
|
RefEdges.insert(Index.getOrInsertValueInfo(GV));
|
|
|
|
else if (auto *U = dyn_cast<User>(Stored))
|
|
|
|
findRefEdges(Index, U, RefEdges, Visited);
|
|
|
|
continue;
|
|
|
|
}
|
2018-11-16 15:08:00 +08:00
|
|
|
}
|
2017-05-05 02:03:25 +08:00
|
|
|
findRefEdges(Index, &I, RefEdges, Visited);
|
2020-04-23 04:19:15 +08:00
|
|
|
const auto *CB = dyn_cast<CallBase>(&I);
|
|
|
|
if (!CB)
|
2016-08-30 08:46:26 +08:00
|
|
|
continue;
|
2016-10-30 13:40:44 +08:00
|
|
|
|
|
|
|
const auto *CI = dyn_cast<CallInst>(&I);
|
|
|
|
// Since we don't know exactly which local values are referenced in inline
|
2016-11-15 00:40:19 +08:00
|
|
|
// assembly, conservatively mark the function as possibly referencing
|
|
|
|
// a local value from inline assembly to ensure we don't export a
|
|
|
|
// reference (which would require renaming and promotion of the
|
|
|
|
// referenced value).
|
2017-09-02 00:24:02 +08:00
|
|
|
if (HasLocalsInUsedOrAsm && CI && CI->isInlineAsm())
|
2016-11-15 00:40:19 +08:00
|
|
|
HasInlineAsmMaybeReferencingInternal = true;
|
2016-10-30 13:40:44 +08:00
|
|
|
|
2020-04-28 11:15:59 +08:00
|
|
|
auto *CalledValue = CB->getCalledOperand();
|
2020-04-23 04:19:15 +08:00
|
|
|
auto *CalledFunction = CB->getCalledFunction();
|
2017-11-10 08:47:47 +08:00
|
|
|
if (CalledValue && !CalledFunction) {
|
2019-08-23 03:56:14 +08:00
|
|
|
CalledValue = CalledValue->stripPointerCasts();
|
2017-11-10 08:47:47 +08:00
|
|
|
// Stripping pointer casts can reveal a called function.
|
|
|
|
CalledFunction = dyn_cast<Function>(CalledValue);
|
|
|
|
}
|
2016-10-09 00:11:42 +08:00
|
|
|
// Check if this is an alias to a function. If so, get the
|
|
|
|
// called aliasee for the checks below.
|
|
|
|
if (auto *GA = dyn_cast<GlobalAlias>(CalledValue)) {
|
2020-04-14 08:27:08 +08:00
|
|
|
assert(!CalledFunction && "Expected null called function in callsite for alias");
|
2016-10-09 00:11:42 +08:00
|
|
|
CalledFunction = dyn_cast<Function>(GA->getBaseObject());
|
|
|
|
}
|
2016-12-22 07:03:45 +08:00
|
|
|
// Check if this is a direct call to a known function or a known
|
|
|
|
// intrinsic, or an indirect call with profile data.
|
2016-08-30 08:46:26 +08:00
|
|
|
if (CalledFunction) {
|
2017-02-11 06:29:38 +08:00
|
|
|
if (CI && CalledFunction->isIntrinsic()) {
|
|
|
|
addIntrinsicToSummary(
|
|
|
|
CI, TypeTests, TypeTestAssumeVCalls, TypeCheckedLoadVCalls,
|
2018-09-27 22:55:32 +08:00
|
|
|
TypeTestAssumeConstVCalls, TypeCheckedLoadConstVCalls, DT);
|
2017-02-11 06:29:38 +08:00
|
|
|
continue;
|
2016-12-22 07:03:45 +08:00
|
|
|
}
|
2016-10-28 10:39:38 +08:00
|
|
|
// We should have named any anonymous globals
|
|
|
|
assert(CalledFunction->hasName());
|
2020-04-28 00:07:18 +08:00
|
|
|
auto ScaledCount = PSI->getProfileCount(*CB, BFI);
|
2016-12-21 05:12:28 +08:00
|
|
|
auto Hotness = ScaledCount ? getHotness(ScaledCount.getValue(), PSI)
|
|
|
|
: CalleeInfo::HotnessType::Unknown;
|
2018-03-31 08:18:08 +08:00
|
|
|
if (ForceSummaryEdgesCold != FunctionSummary::FSHT_None)
|
|
|
|
Hotness = CalleeInfo::HotnessType::Cold;
|
2016-12-21 05:12:28 +08:00
|
|
|
|
2016-10-09 00:11:42 +08:00
|
|
|
// Use the original CalledValue, in case it was an alias. We want
|
|
|
|
// to record the call edge to the alias in that case. Eventually
|
|
|
|
// an alias summary will be created to associate the alias and
|
|
|
|
// aliasee.
|
2018-01-26 03:27:17 +08:00
|
|
|
auto &ValueInfo = CallGraphEdges[Index.getOrInsertValueInfo(
|
|
|
|
cast<GlobalValue>(CalledValue))];
|
|
|
|
ValueInfo.updateHotness(Hotness);
|
|
|
|
// Add the relative block frequency to CalleeInfo if there is no profile
|
|
|
|
// information.
|
|
|
|
if (BFI != nullptr && Hotness == CalleeInfo::HotnessType::Unknown) {
|
2018-02-23 03:44:08 +08:00
|
|
|
uint64_t BBFreq = BFI->getBlockFreq(&BB).getFrequency();
|
|
|
|
uint64_t EntryFreq = BFI->getEntryFreq();
|
|
|
|
ValueInfo.updateRelBlockFreq(BBFreq, EntryFreq);
|
2018-01-26 03:27:17 +08:00
|
|
|
}
|
2016-08-30 08:46:26 +08:00
|
|
|
} else {
|
|
|
|
// Skip inline assembly calls.
|
|
|
|
if (CI && CI->isInlineAsm())
|
|
|
|
continue;
|
2017-11-18 02:28:05 +08:00
|
|
|
// Skip direct calls.
|
|
|
|
if (!CalledValue || isa<Constant>(CalledValue))
|
|
|
|
continue;
|
2016-04-11 21:58:45 +08:00
|
|
|
|
[ThinLTO] Add funtions in callees metadata to CallGraphEdges
Summary:
If there's a callees metadata attached to the indirect call instruction, add CallGraphEdges to the callees mentioned in the metadata when computing FunctionSummary.
* Why this is necessary:
Consider following code example:
```
(foo.c)
static int f1(int x) {...}
static int f2(int x);
static int (*fptr)(int) = f2;
static int f2(int x) {
if (x) fptr=f1; return f1(x);
}
int foo(int x) {
(*fptr)(x); // !callees metadata of !{i32 (i32)* @f1, i32 (i32)* @f2} would be attached to this call.
}
(bar.c)
int bar(int x) {
return foo(x);
}
```
At LTO time when `foo.o` is imported into `bar.o`, function `foo` might be inlined into `bar` and PGO-guided indirect call promotion will run after that. If the profile data tells that the promotion of `@f1` or `@f2` is beneficial, the optimizer will check if the "promoted" `@f1` or `@f2` (such as `@f1.llvm.0` or `@f2.llvm.0`) is available. Without this patch, importing `!callees` metadata would only add promoted declarations of `@f1` and `@f2` to the `bar.o`, but still the optimizer will assume that the function is available and perform the promotion. The result of that is link failure with `undefined reference to @f1.llvm.0`.
This patch fixes this problem by adding callees in the `!callees` metadata to CallGraphEdges so that their definition would be properly imported into.
One may ask that there already is a logic to add indirect call promotion targets to be added to CallGraphEdges. However, if profile data says "indirect call promotion is only beneficial under a certain inline context", the logic wouldn't work. In the code example above, if profile data is like
```
bar:1000000:100000
1:100000
1: foo:100000
1: 100000 f1:100000
```
, Computing FunctionSummary for `foo.o` wouldn't add `foo->f1` to CallGraphEdges. (Also, it is at least "possible" that one can provide profile data to only link step but not to compilation step).
Reviewers: tejohnson, mehdi_amini, pcc
Reviewed By: tejohnson
Subscribers: inglorion, eraman, llvm-commits
Differential Revision: https://reviews.llvm.org/D44399
llvm-svn: 327358
2018-03-13 12:26:58 +08:00
|
|
|
// Check if the instruction has a callees metadata. If so, add callees
|
|
|
|
// to CallGraphEdges to reflect the references from the metadata, and
|
|
|
|
// to enable importing for subsequent indirect call promotion and
|
|
|
|
// inlining.
|
|
|
|
if (auto *MD = I.getMetadata(LLVMContext::MD_callees)) {
|
|
|
|
for (auto &Op : MD->operands()) {
|
|
|
|
Function *Callee = mdconst::extract_or_null<Function>(Op);
|
|
|
|
if (Callee)
|
|
|
|
CallGraphEdges[Index.getOrInsertValueInfo(Callee)];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-30 08:46:26 +08:00
|
|
|
uint32_t NumVals, NumCandidates;
|
|
|
|
uint64_t TotalCount;
|
|
|
|
auto CandidateProfileData =
|
|
|
|
ICallAnalysis.getPromotionCandidatesForInstruction(
|
|
|
|
&I, NumVals, TotalCount, NumCandidates);
|
|
|
|
for (auto &Candidate : CandidateProfileData)
|
2017-05-05 02:03:25 +08:00
|
|
|
CallGraphEdges[Index.getOrInsertValueInfo(Candidate.Value)]
|
|
|
|
.updateHotness(getHotness(Candidate.Count, PSI));
|
2016-04-11 21:58:45 +08:00
|
|
|
}
|
|
|
|
}
|
2021-07-28 09:00:55 +08:00
|
|
|
}
|
2020-05-22 04:28:24 +08:00
|
|
|
Index.addBlockCount(F.size());
|
2016-04-11 21:58:45 +08:00
|
|
|
|
2019-07-05 23:25:05 +08:00
|
|
|
std::vector<ValueInfo> Refs;
|
|
|
|
if (IsThinLTO) {
|
|
|
|
auto AddRefEdges = [&](const std::vector<const Instruction *> &Instrs,
|
|
|
|
SetVector<ValueInfo> &Edges,
|
|
|
|
SmallPtrSet<const User *, 8> &Cache) {
|
|
|
|
for (const auto *I : Instrs) {
|
|
|
|
Cache.erase(I);
|
|
|
|
findRefEdges(Index, I, Edges, Cache);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// By now we processed all instructions in a function, except
|
|
|
|
// non-volatile loads and non-volatile value stores. Let's find
|
|
|
|
// ref edges for both of instruction sets
|
|
|
|
AddRefEdges(NonVolatileLoads, LoadRefEdges, Visited);
|
|
|
|
// We can add some values to the Visited set when processing load
|
|
|
|
// instructions which are also used by stores in NonVolatileStores.
|
|
|
|
// For example this can happen if we have following code:
|
|
|
|
//
|
|
|
|
// store %Derived* @foo, %Derived** bitcast (%Base** @bar to %Derived**)
|
|
|
|
// %42 = load %Derived*, %Derived** bitcast (%Base** @bar to %Derived**)
|
|
|
|
//
|
|
|
|
// After processing loads we'll add bitcast to the Visited set, and if
|
|
|
|
// we use the same set while processing stores, we'll never see store
|
|
|
|
// to @bar and @bar will be mistakenly treated as readonly.
|
|
|
|
SmallPtrSet<const llvm::User *, 8> StoreCache;
|
|
|
|
AddRefEdges(NonVolatileStores, StoreRefEdges, StoreCache);
|
|
|
|
|
|
|
|
// If both load and store instruction reference the same variable
|
|
|
|
// we won't be able to optimize it. Add all such reference edges
|
|
|
|
// to RefEdges set.
|
|
|
|
for (auto &VI : StoreRefEdges)
|
|
|
|
if (LoadRefEdges.remove(VI))
|
|
|
|
RefEdges.insert(VI);
|
|
|
|
|
|
|
|
unsigned RefCnt = RefEdges.size();
|
|
|
|
// All new reference edges inserted in two loops below are either
|
|
|
|
// read or write only. They will be grouped in the end of RefEdges
|
|
|
|
// vector, so we can use a single integer value to identify them.
|
|
|
|
for (auto &VI : LoadRefEdges)
|
|
|
|
RefEdges.insert(VI);
|
|
|
|
|
|
|
|
unsigned FirstWORef = RefEdges.size();
|
|
|
|
for (auto &VI : StoreRefEdges)
|
|
|
|
RefEdges.insert(VI);
|
|
|
|
|
|
|
|
Refs = RefEdges.takeVector();
|
|
|
|
for (; RefCnt < FirstWORef; ++RefCnt)
|
2018-11-16 15:08:00 +08:00
|
|
|
Refs[RefCnt].setReadOnly();
|
|
|
|
|
2019-07-05 23:25:05 +08:00
|
|
|
for (; RefCnt < Refs.size(); ++RefCnt)
|
|
|
|
Refs[RefCnt].setWriteOnly();
|
|
|
|
} else {
|
|
|
|
Refs = RefEdges.takeVector();
|
|
|
|
}
|
2017-03-01 02:09:44 +08:00
|
|
|
// 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())
|
2017-05-05 02:03:25 +08:00
|
|
|
CallGraphEdges[Index.getOrInsertValueInfo(I)].updateHotness(
|
2018-03-31 08:18:08 +08:00
|
|
|
ForceSummaryEdgesCold == FunctionSummary::FSHT_All
|
|
|
|
? CalleeInfo::HotnessType::Cold
|
|
|
|
: CalleeInfo::HotnessType::Critical);
|
2017-03-01 02:09:44 +08:00
|
|
|
|
2017-01-05 22:32:16 +08:00
|
|
|
bool NonRenamableLocal = isNonRenamableLocal(F);
|
2021-07-28 09:00:55 +08:00
|
|
|
bool NotEligibleForImport = NonRenamableLocal ||
|
|
|
|
HasInlineAsmMaybeReferencingInternal ||
|
|
|
|
HasIndirBranchToBlockAddress;
|
2021-01-28 02:43:51 +08:00
|
|
|
GlobalValueSummary::GVFlags Flags(
|
|
|
|
F.getLinkage(), F.getVisibility(), NotEligibleForImport,
|
|
|
|
/* Live = */ false, F.isDSOLocal(),
|
|
|
|
F.hasLinkOnceODRLinkage() && F.hasGlobalUnnamedAddr());
|
2017-08-05 00:00:58 +08:00
|
|
|
FunctionSummary::FFlags FunFlags{
|
|
|
|
F.hasFnAttribute(Attribute::ReadNone),
|
|
|
|
F.hasFnAttribute(Attribute::ReadOnly),
|
2018-11-07 03:41:35 +08:00
|
|
|
F.hasFnAttribute(Attribute::NoRecurse), F.returnDoesNotAlias(),
|
|
|
|
// FIXME: refactor this to use the same code that inliner is using.
|
2018-12-01 13:11:46 +08:00
|
|
|
// Don't try to import functions with noinline attribute.
|
2021-08-14 02:09:18 +08:00
|
|
|
F.getAttributes().hasFnAttr(Attribute::NoInline),
|
2019-11-09 07:50:55 +08:00
|
|
|
F.hasFnAttribute(Attribute::AlwaysInline)};
|
2020-06-01 14:49:57 +08:00
|
|
|
std::vector<FunctionSummary::ParamAccess> ParamAccesses;
|
|
|
|
if (auto *SSI = GetSSICallback(F))
|
2020-08-15 03:42:21 +08:00
|
|
|
ParamAccesses = SSI->getParamAccesses(Index);
|
2019-08-15 23:54:37 +08:00
|
|
|
auto FuncSummary = std::make_unique<FunctionSummary>(
|
2018-12-14 03:54:27 +08:00
|
|
|
Flags, NumInsts, FunFlags, /*EntryCount=*/0, std::move(Refs),
|
|
|
|
CallGraphEdges.takeVector(), TypeTests.takeVector(),
|
|
|
|
TypeTestAssumeVCalls.takeVector(), TypeCheckedLoadVCalls.takeVector(),
|
2017-02-11 06:29:38 +08:00
|
|
|
TypeTestAssumeConstVCalls.takeVector(),
|
2020-06-01 14:49:57 +08:00
|
|
|
TypeCheckedLoadConstVCalls.takeVector(), std::move(ParamAccesses));
|
2017-01-05 22:32:16 +08:00
|
|
|
if (NonRenamableLocal)
|
|
|
|
CantBePromoted.insert(F.getGUID());
|
2018-06-26 08:20:49 +08:00
|
|
|
Index.addGlobalValueSummary(F, std::move(FuncSummary));
|
2016-04-11 21:58:45 +08:00
|
|
|
}
|
|
|
|
|
[ThinLTO] Add summary entries for index-based WPD
Summary:
If LTOUnit splitting is disabled, the module summary analysis computes
the summary information necessary to perform single implementation
devirtualization during the thin link with the index and no IR. The
information collected from the regular LTO IR in the current hybrid WPD
algorithm is summarized, including:
1) For vtable definitions, record the function pointers and their offset
within the vtable initializer (subsumes the information collected from
IR by tryFindVirtualCallTargets).
2) A record for each type metadata summarizing the vtable definitions
decorated with that metadata (subsumes the TypeIdentiferMap collected
from IR).
Also added are the necessary bitcode records, and the corresponding
assembly support.
The follow-on index-based WPD patch is D55153.
Depends on D53890.
Reviewers: pcc
Subscribers: mehdi_amini, Prazek, inglorion, eraman, steven_wu, dexonsmith, arphaman, llvm-commits
Differential Revision: https://reviews.llvm.org/D54815
llvm-svn: 364960
2019-07-03 03:38:02 +08:00
|
|
|
/// Find function pointers referenced within the given vtable initializer
|
|
|
|
/// (or subset of an initializer) \p I. The starting offset of \p I within
|
|
|
|
/// the vtable initializer is \p StartingOffset. Any discovered function
|
|
|
|
/// pointers are added to \p VTableFuncs along with their cumulative offset
|
|
|
|
/// within the initializer.
|
|
|
|
static void findFuncPointers(const Constant *I, uint64_t StartingOffset,
|
|
|
|
const Module &M, ModuleSummaryIndex &Index,
|
|
|
|
VTableFuncList &VTableFuncs) {
|
|
|
|
// First check if this is a function pointer.
|
|
|
|
if (I->getType()->isPointerTy()) {
|
|
|
|
auto Fn = dyn_cast<Function>(I->stripPointerCasts());
|
|
|
|
// We can disregard __cxa_pure_virtual as a possible call target, as
|
|
|
|
// calls to pure virtuals are UB.
|
|
|
|
if (Fn && Fn->getName() != "__cxa_pure_virtual")
|
|
|
|
VTableFuncs.push_back({Index.getOrInsertValueInfo(Fn), StartingOffset});
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Walk through the elements in the constant struct or array and recursively
|
|
|
|
// look for virtual function pointers.
|
|
|
|
const DataLayout &DL = M.getDataLayout();
|
|
|
|
if (auto *C = dyn_cast<ConstantStruct>(I)) {
|
|
|
|
StructType *STy = dyn_cast<StructType>(C->getType());
|
|
|
|
assert(STy);
|
|
|
|
const StructLayout *SL = DL.getStructLayout(C->getType());
|
|
|
|
|
2021-02-23 12:17:18 +08:00
|
|
|
for (auto EI : llvm::enumerate(STy->elements())) {
|
|
|
|
auto Offset = SL->getElementOffset(EI.index());
|
[ThinLTO] Add summary entries for index-based WPD
Summary:
If LTOUnit splitting is disabled, the module summary analysis computes
the summary information necessary to perform single implementation
devirtualization during the thin link with the index and no IR. The
information collected from the regular LTO IR in the current hybrid WPD
algorithm is summarized, including:
1) For vtable definitions, record the function pointers and their offset
within the vtable initializer (subsumes the information collected from
IR by tryFindVirtualCallTargets).
2) A record for each type metadata summarizing the vtable definitions
decorated with that metadata (subsumes the TypeIdentiferMap collected
from IR).
Also added are the necessary bitcode records, and the corresponding
assembly support.
The follow-on index-based WPD patch is D55153.
Depends on D53890.
Reviewers: pcc
Subscribers: mehdi_amini, Prazek, inglorion, eraman, steven_wu, dexonsmith, arphaman, llvm-commits
Differential Revision: https://reviews.llvm.org/D54815
llvm-svn: 364960
2019-07-03 03:38:02 +08:00
|
|
|
unsigned Op = SL->getElementContainingOffset(Offset);
|
|
|
|
findFuncPointers(cast<Constant>(I->getOperand(Op)),
|
|
|
|
StartingOffset + Offset, M, Index, VTableFuncs);
|
|
|
|
}
|
|
|
|
} else if (auto *C = dyn_cast<ConstantArray>(I)) {
|
|
|
|
ArrayType *ATy = C->getType();
|
|
|
|
Type *EltTy = ATy->getElementType();
|
|
|
|
uint64_t EltSize = DL.getTypeAllocSize(EltTy);
|
|
|
|
for (unsigned i = 0, e = ATy->getNumElements(); i != e; ++i) {
|
|
|
|
findFuncPointers(cast<Constant>(I->getOperand(i)),
|
|
|
|
StartingOffset + i * EltSize, M, Index, VTableFuncs);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Identify the function pointers referenced by vtable definition \p V.
|
|
|
|
static void computeVTableFuncs(ModuleSummaryIndex &Index,
|
|
|
|
const GlobalVariable &V, const Module &M,
|
|
|
|
VTableFuncList &VTableFuncs) {
|
|
|
|
if (!V.isConstant())
|
|
|
|
return;
|
|
|
|
|
|
|
|
findFuncPointers(V.getInitializer(), /*StartingOffset=*/0, M, Index,
|
|
|
|
VTableFuncs);
|
|
|
|
|
|
|
|
#ifndef NDEBUG
|
|
|
|
// Validate that the VTableFuncs list is ordered by offset.
|
|
|
|
uint64_t PrevOffset = 0;
|
|
|
|
for (auto &P : VTableFuncs) {
|
|
|
|
// The findVFuncPointers traversal should have encountered the
|
|
|
|
// functions in offset order. We need to use ">=" since PrevOffset
|
|
|
|
// starts at 0.
|
|
|
|
assert(P.VTableOffset >= PrevOffset);
|
|
|
|
PrevOffset = P.VTableOffset;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Record vtable definition \p V for each type metadata it references.
|
2019-01-18 00:05:04 +08:00
|
|
|
static void
|
[ThinLTO] Add summary entries for index-based WPD
Summary:
If LTOUnit splitting is disabled, the module summary analysis computes
the summary information necessary to perform single implementation
devirtualization during the thin link with the index and no IR. The
information collected from the regular LTO IR in the current hybrid WPD
algorithm is summarized, including:
1) For vtable definitions, record the function pointers and their offset
within the vtable initializer (subsumes the information collected from
IR by tryFindVirtualCallTargets).
2) A record for each type metadata summarizing the vtable definitions
decorated with that metadata (subsumes the TypeIdentiferMap collected
from IR).
Also added are the necessary bitcode records, and the corresponding
assembly support.
The follow-on index-based WPD patch is D55153.
Depends on D53890.
Reviewers: pcc
Subscribers: mehdi_amini, Prazek, inglorion, eraman, steven_wu, dexonsmith, arphaman, llvm-commits
Differential Revision: https://reviews.llvm.org/D54815
llvm-svn: 364960
2019-07-03 03:38:02 +08:00
|
|
|
recordTypeIdCompatibleVtableReferences(ModuleSummaryIndex &Index,
|
|
|
|
const GlobalVariable &V,
|
|
|
|
SmallVectorImpl<MDNode *> &Types) {
|
|
|
|
for (MDNode *Type : Types) {
|
|
|
|
auto TypeID = Type->getOperand(1).get();
|
|
|
|
|
|
|
|
uint64_t Offset =
|
|
|
|
cast<ConstantInt>(
|
|
|
|
cast<ConstantAsMetadata>(Type->getOperand(0))->getValue())
|
|
|
|
->getZExtValue();
|
|
|
|
|
|
|
|
if (auto *TypeId = dyn_cast<MDString>(TypeID))
|
|
|
|
Index.getOrInsertTypeIdCompatibleVtableSummary(TypeId->getString())
|
|
|
|
.push_back({Offset, Index.getOrInsertValueInfo(&V)});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void computeVariableSummary(ModuleSummaryIndex &Index,
|
|
|
|
const GlobalVariable &V,
|
|
|
|
DenseSet<GlobalValue::GUID> &CantBePromoted,
|
|
|
|
const Module &M,
|
|
|
|
SmallVectorImpl<MDNode *> &Types) {
|
2016-12-21 05:12:28 +08:00
|
|
|
SetVector<ValueInfo> RefEdges;
|
2016-04-11 21:58:45 +08:00
|
|
|
SmallPtrSet<const User *, 8> Visited;
|
2018-10-12 15:24:02 +08:00
|
|
|
bool HasBlockAddress = findRefEdges(Index, &V, RefEdges, Visited);
|
2017-01-05 22:32:16 +08:00
|
|
|
bool NonRenamableLocal = isNonRenamableLocal(V);
|
2021-01-28 02:43:51 +08:00
|
|
|
GlobalValueSummary::GVFlags Flags(
|
|
|
|
V.getLinkage(), V.getVisibility(), NonRenamableLocal,
|
|
|
|
/* Live = */ false, V.isDSOLocal(),
|
|
|
|
V.hasLinkOnceODRLinkage() && V.hasGlobalUnnamedAddr());
|
2018-11-16 15:08:00 +08:00
|
|
|
|
[ThinLTO] Add summary entries for index-based WPD
Summary:
If LTOUnit splitting is disabled, the module summary analysis computes
the summary information necessary to perform single implementation
devirtualization during the thin link with the index and no IR. The
information collected from the regular LTO IR in the current hybrid WPD
algorithm is summarized, including:
1) For vtable definitions, record the function pointers and their offset
within the vtable initializer (subsumes the information collected from
IR by tryFindVirtualCallTargets).
2) A record for each type metadata summarizing the vtable definitions
decorated with that metadata (subsumes the TypeIdentiferMap collected
from IR).
Also added are the necessary bitcode records, and the corresponding
assembly support.
The follow-on index-based WPD patch is D55153.
Depends on D53890.
Reviewers: pcc
Subscribers: mehdi_amini, Prazek, inglorion, eraman, steven_wu, dexonsmith, arphaman, llvm-commits
Differential Revision: https://reviews.llvm.org/D54815
llvm-svn: 364960
2019-07-03 03:38:02 +08:00
|
|
|
VTableFuncList VTableFuncs;
|
|
|
|
// If splitting is not enabled, then we compute the summary information
|
|
|
|
// necessary for index-based whole program devirtualization.
|
|
|
|
if (!Index.enableSplitLTOUnit()) {
|
|
|
|
Types.clear();
|
|
|
|
V.getMetadata(LLVMContext::MD_type, Types);
|
|
|
|
if (!Types.empty()) {
|
|
|
|
// Identify the function pointers referenced by this vtable definition.
|
|
|
|
computeVTableFuncs(Index, V, M, VTableFuncs);
|
|
|
|
|
|
|
|
// Record this vtable definition for each type metadata it references.
|
|
|
|
recordTypeIdCompatibleVtableReferences(Index, V, Types);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-05 23:25:05 +08:00
|
|
|
// Don't mark variables we won't be able to internalize as read/write-only.
|
|
|
|
bool CanBeInternalized =
|
2018-11-16 15:08:00 +08:00
|
|
|
!V.hasComdat() && !V.hasAppendingLinkage() && !V.isInterposable() &&
|
2019-07-05 23:25:05 +08:00
|
|
|
!V.hasAvailableExternallyLinkage() && !V.hasDLLExportStorageClass();
|
2020-01-16 00:29:01 +08:00
|
|
|
bool Constant = V.isConstant();
|
[ThinLTO] Summarize vcall_visibility metadata
Summary:
Second patch in series to support Safe Whole Program Devirtualization
Enablement, see RFC here:
http://lists.llvm.org/pipermail/llvm-dev/2019-December/137543.html
Summarize vcall_visibility metadata in ThinLTO global variable summary.
Depends on D71907.
Reviewers: pcc, evgeny777, steven_wu
Subscribers: mehdi_amini, Prazek, inglorion, hiraditya, dexonsmith, arphaman, ostannard, llvm-commits, cfe-commits, davidxl
Tags: #clang, #llvm
Differential Revision: https://reviews.llvm.org/D71911
2019-12-27 01:31:43 +08:00
|
|
|
GlobalVarSummary::GVarFlags VarFlags(CanBeInternalized,
|
|
|
|
Constant ? false : CanBeInternalized,
|
|
|
|
Constant, V.getVCallVisibility());
|
2019-08-15 23:54:37 +08:00
|
|
|
auto GVarSummary = std::make_unique<GlobalVarSummary>(Flags, VarFlags,
|
2020-04-14 08:27:08 +08:00
|
|
|
RefEdges.takeVector());
|
2017-01-05 22:32:16 +08:00
|
|
|
if (NonRenamableLocal)
|
|
|
|
CantBePromoted.insert(V.getGUID());
|
2018-10-12 15:24:02 +08:00
|
|
|
if (HasBlockAddress)
|
|
|
|
GVarSummary->setNotEligibleToImport();
|
[ThinLTO] Add summary entries for index-based WPD
Summary:
If LTOUnit splitting is disabled, the module summary analysis computes
the summary information necessary to perform single implementation
devirtualization during the thin link with the index and no IR. The
information collected from the regular LTO IR in the current hybrid WPD
algorithm is summarized, including:
1) For vtable definitions, record the function pointers and their offset
within the vtable initializer (subsumes the information collected from
IR by tryFindVirtualCallTargets).
2) A record for each type metadata summarizing the vtable definitions
decorated with that metadata (subsumes the TypeIdentiferMap collected
from IR).
Also added are the necessary bitcode records, and the corresponding
assembly support.
The follow-on index-based WPD patch is D55153.
Depends on D53890.
Reviewers: pcc
Subscribers: mehdi_amini, Prazek, inglorion, eraman, steven_wu, dexonsmith, arphaman, llvm-commits
Differential Revision: https://reviews.llvm.org/D54815
llvm-svn: 364960
2019-07-03 03:38:02 +08:00
|
|
|
if (!VTableFuncs.empty())
|
|
|
|
GVarSummary->setVTableFuncs(VTableFuncs);
|
2018-06-26 08:20:49 +08:00
|
|
|
Index.addGlobalValueSummary(V, std::move(GVarSummary));
|
2016-04-11 21:58:45 +08:00
|
|
|
}
|
|
|
|
|
2020-04-14 08:27:08 +08:00
|
|
|
static void
|
|
|
|
computeAliasSummary(ModuleSummaryIndex &Index, const GlobalAlias &A,
|
|
|
|
DenseSet<GlobalValue::GUID> &CantBePromoted) {
|
2017-01-05 22:32:16 +08:00
|
|
|
bool NonRenamableLocal = isNonRenamableLocal(A);
|
2021-01-28 02:43:51 +08:00
|
|
|
GlobalValueSummary::GVFlags Flags(
|
|
|
|
A.getLinkage(), A.getVisibility(), NonRenamableLocal,
|
|
|
|
/* Live = */ false, A.isDSOLocal(),
|
|
|
|
A.hasLinkOnceODRLinkage() && A.hasGlobalUnnamedAddr());
|
2019-08-15 23:54:37 +08:00
|
|
|
auto AS = std::make_unique<AliasSummary>(Flags);
|
2016-10-28 10:39:38 +08:00
|
|
|
auto *Aliasee = A.getBaseObject();
|
[ThinLTO] Restructure AliasSummary to contain ValueInfo of Aliasee
Summary:
The AliasSummary previously contained the AliaseeGUID, which was only
populated when reading the summary from bitcode. This patch changes it
to instead hold the ValueInfo of the aliasee, and always populates it.
This enables more efficient access to the ValueInfo (specifically in the
recent patch r352438 which needed to perform an index hash table lookup
using the aliasee GUID).
As noted in the comments in AliasSummary, we no longer technically need
to keep a pointer to the corresponding aliasee summary, since it could
be obtained by walking the list of summaries on the ValueInfo looking
for the summary in the same module. However, I am concerned that this
would be inefficient when walking through the index during the thin
link for various analyses. That can be reevaluated in the future.
By always populating this new field, we can remove the guard and special
handling for a 0 aliasee GUID when dumping the dot graph of the summary.
An additional improvement in this patch is when reading the summaries
from LLVM assembly we now set the AliaseeSummary field to the aliasee
summary in that same module, which makes it consistent with the behavior
when reading the summary from bitcode.
Reviewers: pcc, mehdi_amini
Subscribers: inglorion, eraman, steven_wu, dexonsmith, arphaman, llvm-commits
Differential Revision: https://reviews.llvm.org/D57470
llvm-svn: 356268
2019-03-15 23:11:38 +08:00
|
|
|
auto AliaseeVI = Index.getValueInfo(Aliasee->getGUID());
|
|
|
|
assert(AliaseeVI && "Alias expects aliasee summary to be available");
|
|
|
|
assert(AliaseeVI.getSummaryList().size() == 1 &&
|
|
|
|
"Expected a single entry per aliasee in per-module index");
|
|
|
|
AS->setAliasee(AliaseeVI, AliaseeVI.getSummaryList()[0].get());
|
2017-01-05 22:32:16 +08:00
|
|
|
if (NonRenamableLocal)
|
|
|
|
CantBePromoted.insert(A.getGUID());
|
2018-06-26 08:20:49 +08:00
|
|
|
Index.addGlobalValueSummary(A, std::move(AS));
|
2016-10-28 10:39:38 +08:00
|
|
|
}
|
|
|
|
|
2017-01-06 05:34:18 +08:00
|
|
|
// Set LiveRoot flag on entries matching the given value name.
|
|
|
|
static void setLiveRoot(ModuleSummaryIndex &Index, StringRef Name) {
|
2017-05-05 02:03:25 +08:00
|
|
|
if (ValueInfo VI = Index.getValueInfo(GlobalValue::getGUID(Name)))
|
|
|
|
for (auto &Summary : VI.getSummaryList())
|
2017-06-02 04:30:06 +08:00
|
|
|
Summary->setLive(true);
|
2017-01-06 05:34:18 +08:00
|
|
|
}
|
|
|
|
|
2016-08-19 15:49:19 +08:00
|
|
|
ModuleSummaryIndex llvm::buildModuleSummaryIndex(
|
|
|
|
const Module &M,
|
[thinlto] Basic thinlto fdo heuristic
Summary:
This patch improves thinlto importer
by importing 3x larger functions that are called from hot block.
I compared performance with the trunk on spec, and there
were about 2% on povray and 3.33% on milc. These results seems
to be consistant and match the results Teresa got with her simple
heuristic. Some benchmarks got slower but I think they are just
noisy (mcf, xalancbmki, omnetpp)- running the benchmarks again with
more iterations to confirm. Geomean of all benchmarks including the noisy ones
were about +0.02%.
I see much better improvement on google branch with Easwaran patch
for pgo callsite inlining (the inliner actually inline those big functions)
Over all I see +0.5% improvement, and I get +8.65% on povray.
So I guess we will see much bigger change when Easwaran patch will land
(it depends on new pass manager), but it is still worth putting this to trunk
before it.
Implementation details changes:
- Removed CallsiteCount.
- ProfileCount got replaced by Hotness
- hot-import-multiplier is set to 3.0 for now,
didn't have time to tune it up, but I see that we get most of the interesting
functions with 3, so there is no much performance difference with higher, and
binary size doesn't grow as much as with 10.0.
Reviewers: eraman, mehdi_amini, tejohnson
Subscribers: mehdi_amini, llvm-commits
Differential Revision: https://reviews.llvm.org/D24638
llvm-svn: 282437
2016-09-27 04:37:32 +08:00
|
|
|
std::function<BlockFrequencyInfo *(const Function &F)> GetBFICallback,
|
2020-06-01 14:49:57 +08:00
|
|
|
ProfileSummaryInfo *PSI,
|
|
|
|
std::function<const StackSafetyInfo *(const Function &F)> GetSSICallback) {
|
2017-05-11 02:52:16 +08:00
|
|
|
assert(PSI);
|
[LTO] Record whether LTOUnit splitting is enabled in index
Summary:
Records in the module summary index whether the bitcode was compiled
with the option necessary to enable splitting the LTO unit
(e.g. -fsanitize=cfi, -fwhole-program-vtables, or -fsplit-lto-unit).
The information is passed down to the ModuleSummaryIndex builder via a
new module flag "EnableSplitLTOUnit", which is propagated onto a flag
on the summary index.
This is then used during the LTO link to check whether all linked
summaries were built with the same value of this flag. If not, an error
is issued when we detect a situation requiring whole program visibility
of the class hierarchy. This is the case when both of the following
conditions are met:
1) We are performing LowerTypeTests or Whole Program Devirtualization.
2) There are type tests or type checked loads in the code.
Note I have also changed the ThinLTOBitcodeWriter to also gate the
module splitting on the value of this flag.
Reviewers: pcc
Subscribers: ormris, mehdi_amini, Prazek, inglorion, eraman, steven_wu, dexonsmith, arphaman, dang, llvm-commits
Differential Revision: https://reviews.llvm.org/D53890
llvm-svn: 350948
2019-01-12 02:31:57 +08:00
|
|
|
bool EnableSplitLTOUnit = false;
|
|
|
|
if (auto *MD = mdconst::extract_or_null<ConstantInt>(
|
|
|
|
M.getModuleFlag("EnableSplitLTOUnit")))
|
|
|
|
EnableSplitLTOUnit = MD->getZExtValue();
|
|
|
|
ModuleSummaryIndex Index(/*HaveGVs=*/true, EnableSplitLTOUnit);
|
2016-10-30 13:40:44 +08:00
|
|
|
|
2016-11-11 00:57:32 +08:00
|
|
|
// Identify the local values in the llvm.used and llvm.compiler.used sets,
|
|
|
|
// which should not be exported as they would then require renaming and
|
|
|
|
// promotion, but we may have opaque uses e.g. in inline asm. We collect them
|
|
|
|
// here because we use this information to mark functions containing inline
|
|
|
|
// assembly calls as not importable.
|
2021-02-24 08:09:05 +08:00
|
|
|
SmallPtrSet<GlobalValue *, 4> LocalsUsed;
|
|
|
|
SmallVector<GlobalValue *, 4> Used;
|
2016-11-11 00:57:32 +08:00
|
|
|
// First collect those in the llvm.used set.
|
2021-02-24 08:09:05 +08:00
|
|
|
collectUsedGlobalVariables(M, Used, /*CompilerUsed=*/false);
|
2016-11-11 00:57:32 +08:00
|
|
|
// Next collect those in the llvm.compiler.used set.
|
2021-02-24 08:09:05 +08:00
|
|
|
collectUsedGlobalVariables(M, Used, /*CompilerUsed=*/true);
|
2017-01-05 22:59:56 +08:00
|
|
|
DenseSet<GlobalValue::GUID> CantBePromoted;
|
2016-10-30 13:40:44 +08:00
|
|
|
for (auto *V : Used) {
|
2017-01-05 22:32:16 +08:00
|
|
|
if (V->hasLocalLinkage()) {
|
2016-10-30 13:40:44 +08:00
|
|
|
LocalsUsed.insert(V);
|
2017-01-05 22:32:16 +08:00
|
|
|
CantBePromoted.insert(V->getGUID());
|
|
|
|
}
|
2016-10-30 13:40:44 +08:00
|
|
|
}
|
2016-04-20 22:39:45 +08:00
|
|
|
|
2017-09-02 00:24:02 +08:00
|
|
|
bool HasLocalInlineAsmSymbol = false;
|
|
|
|
if (!M.getModuleInlineAsm().empty()) {
|
|
|
|
// Collect the local values defined by module level asm, and set up
|
|
|
|
// summaries for these symbols so that they can be marked as NoRename,
|
|
|
|
// to prevent export of any use of them in regular IR that would require
|
|
|
|
// renaming within the module level asm. Note we don't need to create a
|
|
|
|
// summary for weak or global defs, as they don't need to be flagged as
|
|
|
|
// NoRename, and defs in module level asm can't be imported anyway.
|
|
|
|
// Also, any values used but not defined within module level asm should
|
|
|
|
// be listed on the llvm.used or llvm.compiler.used global and marked as
|
|
|
|
// referenced from there.
|
|
|
|
ModuleSymbolTable::CollectAsmSymbols(
|
|
|
|
M, [&](StringRef Name, object::BasicSymbolRef::Flags Flags) {
|
|
|
|
// Symbols not marked as Weak or Global are local definitions.
|
|
|
|
if (Flags & (object::BasicSymbolRef::SF_Weak |
|
|
|
|
object::BasicSymbolRef::SF_Global))
|
|
|
|
return;
|
|
|
|
HasLocalInlineAsmSymbol = true;
|
|
|
|
GlobalValue *GV = M.getNamedValue(Name);
|
|
|
|
if (!GV)
|
|
|
|
return;
|
2020-04-14 08:27:08 +08:00
|
|
|
assert(GV->isDeclaration() && "Def in module asm already has definition");
|
2021-01-28 02:43:51 +08:00
|
|
|
GlobalValueSummary::GVFlags GVFlags(
|
|
|
|
GlobalValue::InternalLinkage, GlobalValue::DefaultVisibility,
|
|
|
|
/* NotEligibleToImport = */ true,
|
|
|
|
/* Live = */ true,
|
|
|
|
/* Local */ GV->isDSOLocal(),
|
|
|
|
GV->hasLinkOnceODRLinkage() && GV->hasGlobalUnnamedAddr());
|
2018-06-26 08:20:49 +08:00
|
|
|
CantBePromoted.insert(GV->getGUID());
|
2017-09-02 00:24:02 +08:00
|
|
|
// Create the appropriate summary type.
|
|
|
|
if (Function *F = dyn_cast<Function>(GV)) {
|
|
|
|
std::unique_ptr<FunctionSummary> Summary =
|
2019-08-15 23:54:37 +08:00
|
|
|
std::make_unique<FunctionSummary>(
|
2018-12-14 03:54:27 +08:00
|
|
|
GVFlags, /*InstCount=*/0,
|
2017-09-02 00:24:02 +08:00
|
|
|
FunctionSummary::FFlags{
|
|
|
|
F->hasFnAttribute(Attribute::ReadNone),
|
|
|
|
F->hasFnAttribute(Attribute::ReadOnly),
|
|
|
|
F->hasFnAttribute(Attribute::NoRecurse),
|
2018-11-07 03:41:35 +08:00
|
|
|
F->returnDoesNotAlias(),
|
2019-11-09 07:50:55 +08:00
|
|
|
/* NoInline = */ false,
|
|
|
|
F->hasFnAttribute(Attribute::AlwaysInline)},
|
2018-12-14 03:54:27 +08:00
|
|
|
/*EntryCount=*/0, ArrayRef<ValueInfo>{},
|
|
|
|
ArrayRef<FunctionSummary::EdgeTy>{},
|
2017-09-02 00:24:02 +08:00
|
|
|
ArrayRef<GlobalValue::GUID>{},
|
|
|
|
ArrayRef<FunctionSummary::VFuncId>{},
|
|
|
|
ArrayRef<FunctionSummary::VFuncId>{},
|
|
|
|
ArrayRef<FunctionSummary::ConstVCall>{},
|
2020-06-01 14:49:57 +08:00
|
|
|
ArrayRef<FunctionSummary::ConstVCall>{},
|
|
|
|
ArrayRef<FunctionSummary::ParamAccess>{});
|
2018-06-26 08:20:49 +08:00
|
|
|
Index.addGlobalValueSummary(*GV, std::move(Summary));
|
2017-09-02 00:24:02 +08:00
|
|
|
} else {
|
|
|
|
std::unique_ptr<GlobalVarSummary> Summary =
|
2019-08-15 23:54:37 +08:00
|
|
|
std::make_unique<GlobalVarSummary>(
|
2020-01-16 00:29:01 +08:00
|
|
|
GVFlags,
|
|
|
|
GlobalVarSummary::GVarFlags(
|
[ThinLTO] Summarize vcall_visibility metadata
Summary:
Second patch in series to support Safe Whole Program Devirtualization
Enablement, see RFC here:
http://lists.llvm.org/pipermail/llvm-dev/2019-December/137543.html
Summarize vcall_visibility metadata in ThinLTO global variable summary.
Depends on D71907.
Reviewers: pcc, evgeny777, steven_wu
Subscribers: mehdi_amini, Prazek, inglorion, hiraditya, dexonsmith, arphaman, ostannard, llvm-commits, cfe-commits, davidxl
Tags: #clang, #llvm
Differential Revision: https://reviews.llvm.org/D71911
2019-12-27 01:31:43 +08:00
|
|
|
false, false, cast<GlobalVariable>(GV)->isConstant(),
|
|
|
|
GlobalObject::VCallVisibilityPublic),
|
2018-11-16 15:08:00 +08:00
|
|
|
ArrayRef<ValueInfo>{});
|
2018-06-26 08:20:49 +08:00
|
|
|
Index.addGlobalValueSummary(*GV, std::move(Summary));
|
2017-09-02 00:24:02 +08:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2018-11-16 15:08:00 +08:00
|
|
|
bool IsThinLTO = true;
|
|
|
|
if (auto *MD =
|
|
|
|
mdconst::extract_or_null<ConstantInt>(M.getModuleFlag("ThinLTO")))
|
|
|
|
IsThinLTO = MD->getZExtValue();
|
|
|
|
|
2016-04-11 21:58:45 +08:00
|
|
|
// Compute summaries for all functions defined in module, and save in the
|
|
|
|
// index.
|
2016-08-19 15:49:19 +08:00
|
|
|
for (auto &F : M) {
|
2016-04-11 21:58:45 +08:00
|
|
|
if (F.isDeclaration())
|
|
|
|
continue;
|
|
|
|
|
2018-09-27 22:55:32 +08:00
|
|
|
DominatorTree DT(const_cast<Function &>(F));
|
2016-04-11 21:58:45 +08:00
|
|
|
BlockFrequencyInfo *BFI = nullptr;
|
|
|
|
std::unique_ptr<BlockFrequencyInfo> BFIPtr;
|
2016-08-19 15:49:19 +08:00
|
|
|
if (GetBFICallback)
|
|
|
|
BFI = GetBFICallback(F);
|
2017-12-22 09:33:52 +08:00
|
|
|
else if (F.hasProfileData()) {
|
2018-09-27 22:55:32 +08:00
|
|
|
LoopInfo LI{DT};
|
2016-04-11 21:58:45 +08:00
|
|
|
BranchProbabilityInfo BPI{F, LI};
|
2019-08-15 23:54:37 +08:00
|
|
|
BFIPtr = std::make_unique<BlockFrequencyInfo>(F, BPI, LI);
|
2016-04-11 21:58:45 +08:00
|
|
|
BFI = BFIPtr.get();
|
|
|
|
}
|
|
|
|
|
2018-09-27 22:55:32 +08:00
|
|
|
computeFunctionSummary(Index, M, F, BFI, PSI, DT,
|
2017-09-02 00:24:02 +08:00
|
|
|
!LocalsUsed.empty() || HasLocalInlineAsmSymbol,
|
2020-06-01 14:49:57 +08:00
|
|
|
CantBePromoted, IsThinLTO, GetSSICallback);
|
2016-04-11 21:58:45 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Compute summaries for all variables defined in module, and save in the
|
|
|
|
// index.
|
[ThinLTO] Add summary entries for index-based WPD
Summary:
If LTOUnit splitting is disabled, the module summary analysis computes
the summary information necessary to perform single implementation
devirtualization during the thin link with the index and no IR. The
information collected from the regular LTO IR in the current hybrid WPD
algorithm is summarized, including:
1) For vtable definitions, record the function pointers and their offset
within the vtable initializer (subsumes the information collected from
IR by tryFindVirtualCallTargets).
2) A record for each type metadata summarizing the vtable definitions
decorated with that metadata (subsumes the TypeIdentiferMap collected
from IR).
Also added are the necessary bitcode records, and the corresponding
assembly support.
The follow-on index-based WPD patch is D55153.
Depends on D53890.
Reviewers: pcc
Subscribers: mehdi_amini, Prazek, inglorion, eraman, steven_wu, dexonsmith, arphaman, llvm-commits
Differential Revision: https://reviews.llvm.org/D54815
llvm-svn: 364960
2019-07-03 03:38:02 +08:00
|
|
|
SmallVector<MDNode *, 2> Types;
|
2016-08-19 15:49:19 +08:00
|
|
|
for (const GlobalVariable &G : M.globals()) {
|
2016-04-11 21:58:45 +08:00
|
|
|
if (G.isDeclaration())
|
|
|
|
continue;
|
[ThinLTO] Add summary entries for index-based WPD
Summary:
If LTOUnit splitting is disabled, the module summary analysis computes
the summary information necessary to perform single implementation
devirtualization during the thin link with the index and no IR. The
information collected from the regular LTO IR in the current hybrid WPD
algorithm is summarized, including:
1) For vtable definitions, record the function pointers and their offset
within the vtable initializer (subsumes the information collected from
IR by tryFindVirtualCallTargets).
2) A record for each type metadata summarizing the vtable definitions
decorated with that metadata (subsumes the TypeIdentiferMap collected
from IR).
Also added are the necessary bitcode records, and the corresponding
assembly support.
The follow-on index-based WPD patch is D55153.
Depends on D53890.
Reviewers: pcc
Subscribers: mehdi_amini, Prazek, inglorion, eraman, steven_wu, dexonsmith, arphaman, llvm-commits
Differential Revision: https://reviews.llvm.org/D54815
llvm-svn: 364960
2019-07-03 03:38:02 +08:00
|
|
|
computeVariableSummary(Index, G, CantBePromoted, M, Types);
|
2016-04-11 21:58:45 +08:00
|
|
|
}
|
2016-10-28 10:39:38 +08:00
|
|
|
|
|
|
|
// Compute summaries for all aliases defined in module, and save in the
|
|
|
|
// index.
|
|
|
|
for (const GlobalAlias &A : M.aliases())
|
2017-01-05 22:32:16 +08:00
|
|
|
computeAliasSummary(Index, A, CantBePromoted);
|
2016-10-28 10:39:38 +08:00
|
|
|
|
2016-10-30 13:40:44 +08:00
|
|
|
for (auto *V : LocalsUsed) {
|
|
|
|
auto *Summary = Index.getGlobalValueSummary(*V);
|
|
|
|
assert(Summary && "Missing summary for global value");
|
2017-01-05 22:32:16 +08:00
|
|
|
Summary->setNotEligibleToImport();
|
2016-10-30 13:40:44 +08:00
|
|
|
}
|
|
|
|
|
2017-01-06 05:34:18 +08:00
|
|
|
// The linker doesn't know about these LLVM produced values, so we need
|
|
|
|
// to flag them as live in the index to ensure index-based dead value
|
|
|
|
// analysis treats them as live roots of the analysis.
|
|
|
|
setLiveRoot(Index, "llvm.used");
|
|
|
|
setLiveRoot(Index, "llvm.compiler.used");
|
|
|
|
setLiveRoot(Index, "llvm.global_ctors");
|
|
|
|
setLiveRoot(Index, "llvm.global_dtors");
|
|
|
|
setLiveRoot(Index, "llvm.global.annotations");
|
|
|
|
|
2017-01-05 22:32:16 +08:00
|
|
|
for (auto &GlobalList : Index) {
|
2017-05-05 02:03:25 +08:00
|
|
|
// Ignore entries for references that are undefined in the current module.
|
|
|
|
if (GlobalList.second.SummaryList.empty())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
assert(GlobalList.second.SummaryList.size() == 1 &&
|
2017-01-05 22:32:16 +08:00
|
|
|
"Expected module's index to have one summary per GUID");
|
2017-05-05 02:03:25 +08:00
|
|
|
auto &Summary = GlobalList.second.SummaryList[0];
|
2017-06-09 07:01:49 +08:00
|
|
|
if (!IsThinLTO) {
|
|
|
|
Summary->setNotEligibleToImport();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2017-01-05 22:32:16 +08:00
|
|
|
bool AllRefsCanBeExternallyReferenced =
|
|
|
|
llvm::all_of(Summary->refs(), [&](const ValueInfo &VI) {
|
2017-05-05 02:03:25 +08:00
|
|
|
return !CantBePromoted.count(VI.getGUID());
|
2017-01-05 22:32:16 +08:00
|
|
|
});
|
|
|
|
if (!AllRefsCanBeExternallyReferenced) {
|
|
|
|
Summary->setNotEligibleToImport();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (auto *FuncSummary = dyn_cast<FunctionSummary>(Summary.get())) {
|
|
|
|
bool AllCallsCanBeExternallyReferenced = llvm::all_of(
|
|
|
|
FuncSummary->calls(), [&](const FunctionSummary::EdgeTy &Edge) {
|
2017-05-05 02:03:25 +08:00
|
|
|
return !CantBePromoted.count(Edge.first.getGUID());
|
2017-01-05 22:32:16 +08:00
|
|
|
});
|
|
|
|
if (!AllCallsCanBeExternallyReferenced)
|
|
|
|
Summary->setNotEligibleToImport();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-29 07:43:26 +08:00
|
|
|
if (!ModuleSummaryDotFile.empty()) {
|
|
|
|
std::error_code EC;
|
2019-08-05 13:43:48 +08:00
|
|
|
raw_fd_ostream OSDot(ModuleSummaryDotFile, EC, sys::fs::OpenFlags::OF_None);
|
2019-01-29 07:43:26 +08:00
|
|
|
if (EC)
|
|
|
|
report_fatal_error(Twine("Failed to open dot file ") +
|
|
|
|
ModuleSummaryDotFile + ": " + EC.message() + "\n");
|
2019-12-18 23:33:15 +08:00
|
|
|
Index.exportToDot(OSDot, {});
|
2019-01-29 07:43:26 +08:00
|
|
|
}
|
|
|
|
|
2016-08-19 15:49:19 +08:00
|
|
|
return Index;
|
2016-04-11 21:58:45 +08:00
|
|
|
}
|
|
|
|
|
2016-11-24 01:53:26 +08:00
|
|
|
AnalysisKey ModuleSummaryIndexAnalysis::Key;
|
2016-08-12 21:53:02 +08:00
|
|
|
|
2020-04-14 08:27:08 +08:00
|
|
|
ModuleSummaryIndex
|
|
|
|
ModuleSummaryIndexAnalysis::run(Module &M, ModuleAnalysisManager &AM) {
|
[thinlto] Basic thinlto fdo heuristic
Summary:
This patch improves thinlto importer
by importing 3x larger functions that are called from hot block.
I compared performance with the trunk on spec, and there
were about 2% on povray and 3.33% on milc. These results seems
to be consistant and match the results Teresa got with her simple
heuristic. Some benchmarks got slower but I think they are just
noisy (mcf, xalancbmki, omnetpp)- running the benchmarks again with
more iterations to confirm. Geomean of all benchmarks including the noisy ones
were about +0.02%.
I see much better improvement on google branch with Easwaran patch
for pgo callsite inlining (the inliner actually inline those big functions)
Over all I see +0.5% improvement, and I get +8.65% on povray.
So I guess we will see much bigger change when Easwaran patch will land
(it depends on new pass manager), but it is still worth putting this to trunk
before it.
Implementation details changes:
- Removed CallsiteCount.
- ProfileCount got replaced by Hotness
- hot-import-multiplier is set to 3.0 for now,
didn't have time to tune it up, but I see that we get most of the interesting
functions with 3, so there is no much performance difference with higher, and
binary size doesn't grow as much as with 10.0.
Reviewers: eraman, mehdi_amini, tejohnson
Subscribers: mehdi_amini, llvm-commits
Differential Revision: https://reviews.llvm.org/D24638
llvm-svn: 282437
2016-09-27 04:37:32 +08:00
|
|
|
ProfileSummaryInfo &PSI = AM.getResult<ProfileSummaryAnalysis>(M);
|
2016-08-12 21:53:02 +08:00
|
|
|
auto &FAM = AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
|
2020-06-01 14:49:57 +08:00
|
|
|
bool NeedSSI = needsParamAccessSummary(M);
|
[thinlto] Basic thinlto fdo heuristic
Summary:
This patch improves thinlto importer
by importing 3x larger functions that are called from hot block.
I compared performance with the trunk on spec, and there
were about 2% on povray and 3.33% on milc. These results seems
to be consistant and match the results Teresa got with her simple
heuristic. Some benchmarks got slower but I think they are just
noisy (mcf, xalancbmki, omnetpp)- running the benchmarks again with
more iterations to confirm. Geomean of all benchmarks including the noisy ones
were about +0.02%.
I see much better improvement on google branch with Easwaran patch
for pgo callsite inlining (the inliner actually inline those big functions)
Over all I see +0.5% improvement, and I get +8.65% on povray.
So I guess we will see much bigger change when Easwaran patch will land
(it depends on new pass manager), but it is still worth putting this to trunk
before it.
Implementation details changes:
- Removed CallsiteCount.
- ProfileCount got replaced by Hotness
- hot-import-multiplier is set to 3.0 for now,
didn't have time to tune it up, but I see that we get most of the interesting
functions with 3, so there is no much performance difference with higher, and
binary size doesn't grow as much as with 10.0.
Reviewers: eraman, mehdi_amini, tejohnson
Subscribers: mehdi_amini, llvm-commits
Differential Revision: https://reviews.llvm.org/D24638
llvm-svn: 282437
2016-09-27 04:37:32 +08:00
|
|
|
return buildModuleSummaryIndex(
|
|
|
|
M,
|
|
|
|
[&FAM](const Function &F) {
|
|
|
|
return &FAM.getResult<BlockFrequencyAnalysis>(
|
|
|
|
*const_cast<Function *>(&F));
|
|
|
|
},
|
2020-06-01 14:49:57 +08:00
|
|
|
&PSI,
|
|
|
|
[&FAM, NeedSSI](const Function &F) -> const StackSafetyInfo * {
|
|
|
|
return NeedSSI ? &FAM.getResult<StackSafetyAnalysis>(
|
|
|
|
const_cast<Function &>(F))
|
|
|
|
: nullptr;
|
|
|
|
});
|
2016-08-12 21:53:02 +08:00
|
|
|
}
|
|
|
|
|
2016-04-11 21:58:45 +08:00
|
|
|
char ModuleSummaryIndexWrapperPass::ID = 0;
|
2017-08-17 06:07:40 +08:00
|
|
|
|
2016-04-11 21:58:45 +08:00
|
|
|
INITIALIZE_PASS_BEGIN(ModuleSummaryIndexWrapperPass, "module-summary-analysis",
|
|
|
|
"Module Summary Analysis", false, true)
|
|
|
|
INITIALIZE_PASS_DEPENDENCY(BlockFrequencyInfoWrapperPass)
|
2017-01-21 14:01:22 +08:00
|
|
|
INITIALIZE_PASS_DEPENDENCY(ProfileSummaryInfoWrapperPass)
|
2020-06-01 14:49:57 +08:00
|
|
|
INITIALIZE_PASS_DEPENDENCY(StackSafetyInfoWrapperPass)
|
2016-04-11 21:58:45 +08:00
|
|
|
INITIALIZE_PASS_END(ModuleSummaryIndexWrapperPass, "module-summary-analysis",
|
|
|
|
"Module Summary Analysis", false, true)
|
|
|
|
|
|
|
|
ModulePass *llvm::createModuleSummaryIndexWrapperPass() {
|
|
|
|
return new ModuleSummaryIndexWrapperPass();
|
|
|
|
}
|
|
|
|
|
|
|
|
ModuleSummaryIndexWrapperPass::ModuleSummaryIndexWrapperPass()
|
|
|
|
: ModulePass(ID) {
|
|
|
|
initializeModuleSummaryIndexWrapperPassPass(*PassRegistry::getPassRegistry());
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ModuleSummaryIndexWrapperPass::runOnModule(Module &M) {
|
2018-11-19 13:23:16 +08:00
|
|
|
auto *PSI = &getAnalysis<ProfileSummaryInfoWrapperPass>().getPSI();
|
2020-06-01 14:49:57 +08:00
|
|
|
bool NeedSSI = needsParamAccessSummary(M);
|
2018-06-26 10:29:08 +08:00
|
|
|
Index.emplace(buildModuleSummaryIndex(
|
[thinlto] Basic thinlto fdo heuristic
Summary:
This patch improves thinlto importer
by importing 3x larger functions that are called from hot block.
I compared performance with the trunk on spec, and there
were about 2% on povray and 3.33% on milc. These results seems
to be consistant and match the results Teresa got with her simple
heuristic. Some benchmarks got slower but I think they are just
noisy (mcf, xalancbmki, omnetpp)- running the benchmarks again with
more iterations to confirm. Geomean of all benchmarks including the noisy ones
were about +0.02%.
I see much better improvement on google branch with Easwaran patch
for pgo callsite inlining (the inliner actually inline those big functions)
Over all I see +0.5% improvement, and I get +8.65% on povray.
So I guess we will see much bigger change when Easwaran patch will land
(it depends on new pass manager), but it is still worth putting this to trunk
before it.
Implementation details changes:
- Removed CallsiteCount.
- ProfileCount got replaced by Hotness
- hot-import-multiplier is set to 3.0 for now,
didn't have time to tune it up, but I see that we get most of the interesting
functions with 3, so there is no much performance difference with higher, and
binary size doesn't grow as much as with 10.0.
Reviewers: eraman, mehdi_amini, tejohnson
Subscribers: mehdi_amini, llvm-commits
Differential Revision: https://reviews.llvm.org/D24638
llvm-svn: 282437
2016-09-27 04:37:32 +08:00
|
|
|
M,
|
|
|
|
[this](const Function &F) {
|
|
|
|
return &(this->getAnalysis<BlockFrequencyInfoWrapperPass>(
|
|
|
|
*const_cast<Function *>(&F))
|
|
|
|
.getBFI());
|
|
|
|
},
|
2020-06-01 14:49:57 +08:00
|
|
|
PSI,
|
|
|
|
[&](const Function &F) -> const StackSafetyInfo * {
|
|
|
|
return NeedSSI ? &getAnalysis<StackSafetyInfoWrapperPass>(
|
|
|
|
const_cast<Function &>(F))
|
|
|
|
.getResult()
|
|
|
|
: nullptr;
|
|
|
|
}));
|
2016-04-11 21:58:45 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ModuleSummaryIndexWrapperPass::doFinalization(Module &M) {
|
2016-08-19 15:49:19 +08:00
|
|
|
Index.reset();
|
2016-04-11 21:58:45 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ModuleSummaryIndexWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const {
|
|
|
|
AU.setPreservesAll();
|
|
|
|
AU.addRequired<BlockFrequencyInfoWrapperPass>();
|
[thinlto] Basic thinlto fdo heuristic
Summary:
This patch improves thinlto importer
by importing 3x larger functions that are called from hot block.
I compared performance with the trunk on spec, and there
were about 2% on povray and 3.33% on milc. These results seems
to be consistant and match the results Teresa got with her simple
heuristic. Some benchmarks got slower but I think they are just
noisy (mcf, xalancbmki, omnetpp)- running the benchmarks again with
more iterations to confirm. Geomean of all benchmarks including the noisy ones
were about +0.02%.
I see much better improvement on google branch with Easwaran patch
for pgo callsite inlining (the inliner actually inline those big functions)
Over all I see +0.5% improvement, and I get +8.65% on povray.
So I guess we will see much bigger change when Easwaran patch will land
(it depends on new pass manager), but it is still worth putting this to trunk
before it.
Implementation details changes:
- Removed CallsiteCount.
- ProfileCount got replaced by Hotness
- hot-import-multiplier is set to 3.0 for now,
didn't have time to tune it up, but I see that we get most of the interesting
functions with 3, so there is no much performance difference with higher, and
binary size doesn't grow as much as with 10.0.
Reviewers: eraman, mehdi_amini, tejohnson
Subscribers: mehdi_amini, llvm-commits
Differential Revision: https://reviews.llvm.org/D24638
llvm-svn: 282437
2016-09-27 04:37:32 +08:00
|
|
|
AU.addRequired<ProfileSummaryInfoWrapperPass>();
|
2020-06-01 14:49:57 +08:00
|
|
|
AU.addRequired<StackSafetyInfoWrapperPass>();
|
2016-04-11 21:58:45 +08:00
|
|
|
}
|
2020-06-02 16:19:57 +08:00
|
|
|
|
|
|
|
char ImmutableModuleSummaryIndexWrapperPass::ID = 0;
|
|
|
|
|
|
|
|
ImmutableModuleSummaryIndexWrapperPass::ImmutableModuleSummaryIndexWrapperPass(
|
|
|
|
const ModuleSummaryIndex *Index)
|
|
|
|
: ImmutablePass(ID), Index(Index) {
|
|
|
|
initializeImmutableModuleSummaryIndexWrapperPassPass(
|
|
|
|
*PassRegistry::getPassRegistry());
|
|
|
|
}
|
|
|
|
|
|
|
|
void ImmutableModuleSummaryIndexWrapperPass::getAnalysisUsage(
|
|
|
|
AnalysisUsage &AU) const {
|
|
|
|
AU.setPreservesAll();
|
|
|
|
}
|
|
|
|
|
|
|
|
ImmutablePass *llvm::createImmutableModuleSummaryIndexWrapperPass(
|
|
|
|
const ModuleSummaryIndex *Index) {
|
|
|
|
return new ImmutableModuleSummaryIndexWrapperPass(Index);
|
|
|
|
}
|
|
|
|
|
|
|
|
INITIALIZE_PASS(ImmutableModuleSummaryIndexWrapperPass, "module-summary-info",
|
|
|
|
"Module summary info", false, true)
|