1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-26 04:32:44 +01:00

[PGO] Refactor Value Profiling into a plugin based oracle and create a well defined API for the plugins.

Summary: This PR creates a utility class called ValueProfileCollector that tells PGOInstrumentationGen and PGOInstrumentationUse what to value-profile and where to attach the profile metadata. It then refactors logic scattered in PGOInstrumentation.cpp into two plugins that plug into the ValueProfileCollector.

Authored By: Wael Yehia <wyehia@ca.ibm.com>

Reviewer: davidxl, tejohnson, xur

Reviewed By: davidxl, tejohnson, xur

Subscribers: llvm-commits

Tag: #llvm

Differential Revision: https://reviews.llvm.org/D67920

Patch By Wael Yehia <wyehia@ca.ibm.com>

llvm-svn: 373601
This commit is contained in:
Bardia Mahjour 2019-10-03 14:20:50 +00:00
parent e03c5f1b6b
commit 729f819c81
5 changed files with 280 additions and 120 deletions

View File

@ -14,6 +14,7 @@ add_llvm_library(LLVMInstrumentation
PGOMemOPSizeOpt.cpp
PoisonChecking.cpp
SanitizerCoverage.cpp
ValueProfileCollector.cpp
ThreadSanitizer.cpp
HWAddressSanitizer.cpp

View File

@ -48,6 +48,7 @@
//===----------------------------------------------------------------------===//
#include "CFGMST.h"
#include "ValueProfileCollector.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/STLExtras.h"
@ -61,7 +62,6 @@
#include "llvm/Analysis/BlockFrequencyInfo.h"
#include "llvm/Analysis/BranchProbabilityInfo.h"
#include "llvm/Analysis/CFG.h"
#include "llvm/Analysis/IndirectCallVisitor.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/OptimizationRemarkEmitter.h"
#include "llvm/Analysis/ProfileSummaryInfo.h"
@ -121,6 +121,7 @@
using namespace llvm;
using ProfileCount = Function::ProfileCount;
using VPCandidateInfo = ValueProfileCollector::CandidateInfo;
#define DEBUG_TYPE "pgo-instrumentation"
@ -287,6 +288,11 @@ static std::string getBranchCondString(Instruction *TI) {
return result;
}
static const char *ValueProfKindDescr[] = {
#define VALUE_PROF_KIND(Enumerator, Value, Descr) Descr,
#include "llvm/ProfileData/InstrProfData.inc"
};
namespace {
/// The select instruction visitor plays three roles specified
@ -349,50 +355,6 @@ struct SelectInstVisitor : public InstVisitor<SelectInstVisitor> {
unsigned getNumOfSelectInsts() const { return NSIs; }
};
/// Instruction Visitor class to visit memory intrinsic calls.
struct MemIntrinsicVisitor : public InstVisitor<MemIntrinsicVisitor> {
Function &F;
unsigned NMemIs = 0; // Number of memIntrinsics instrumented.
VisitMode Mode = VM_counting; // Visiting mode.
unsigned CurCtrId = 0; // Current counter index.
unsigned TotalNumCtrs = 0; // Total number of counters
GlobalVariable *FuncNameVar = nullptr;
uint64_t FuncHash = 0;
PGOUseFunc *UseFunc = nullptr;
std::vector<Instruction *> Candidates;
MemIntrinsicVisitor(Function &Func) : F(Func) {}
void countMemIntrinsics(Function &Func) {
NMemIs = 0;
Mode = VM_counting;
visit(Func);
}
void instrumentMemIntrinsics(Function &Func, unsigned TotalNC,
GlobalVariable *FNV, uint64_t FHash) {
Mode = VM_instrument;
TotalNumCtrs = TotalNC;
FuncHash = FHash;
FuncNameVar = FNV;
visit(Func);
}
std::vector<Instruction *> findMemIntrinsics(Function &Func) {
Candidates.clear();
Mode = VM_annotate;
visit(Func);
return Candidates;
}
// Visit the IR stream and annotate all mem intrinsic call instructions.
void instrumentOneMemIntrinsic(MemIntrinsic &MI);
// Visit \p MI instruction and perform tasks according to visit mode.
void visitMemIntrinsic(MemIntrinsic &SI);
unsigned getNumOfMemIntrinsics() const { return NMemIs; }
};
class PGOInstrumentationGenLegacyPass : public ModulePass {
public:
@ -564,13 +526,14 @@ private:
// A map that stores the Comdat group in function F.
std::unordered_multimap<Comdat *, GlobalValue *> &ComdatMembers;
ValueProfileCollector VPC;
void computeCFGHash();
void renameComdatFunction();
public:
std::vector<std::vector<Instruction *>> ValueSites;
std::vector<std::vector<VPCandidateInfo>> ValueSites;
SelectInstVisitor SIVisitor;
MemIntrinsicVisitor MIVisitor;
std::string FuncName;
GlobalVariable *FuncNameVar;
@ -605,23 +568,21 @@ public:
std::unordered_multimap<Comdat *, GlobalValue *> &ComdatMembers,
bool CreateGlobalVar = false, BranchProbabilityInfo *BPI = nullptr,
BlockFrequencyInfo *BFI = nullptr, bool IsCS = false)
: F(Func), IsCS(IsCS), ComdatMembers(ComdatMembers),
ValueSites(IPVK_Last + 1), SIVisitor(Func), MIVisitor(Func),
MST(F, BPI, BFI) {
: F(Func), IsCS(IsCS), ComdatMembers(ComdatMembers), VPC(Func),
ValueSites(IPVK_Last + 1), SIVisitor(Func), MST(F, BPI, BFI) {
// This should be done before CFG hash computation.
SIVisitor.countSelects(Func);
MIVisitor.countMemIntrinsics(Func);
ValueSites[IPVK_MemOPSize] = VPC.get(IPVK_MemOPSize);
if (!IsCS) {
NumOfPGOSelectInsts += SIVisitor.getNumOfSelectInsts();
NumOfPGOMemIntrinsics += MIVisitor.getNumOfMemIntrinsics();
NumOfPGOMemIntrinsics += ValueSites[IPVK_MemOPSize].size();
NumOfPGOBB += MST.BBInfos.size();
ValueSites[IPVK_IndirectCallTarget] = findIndirectCalls(Func);
ValueSites[IPVK_IndirectCallTarget] = VPC.get(IPVK_IndirectCallTarget);
} else {
NumOfCSPGOSelectInsts += SIVisitor.getNumOfSelectInsts();
NumOfCSPGOMemIntrinsics += MIVisitor.getNumOfMemIntrinsics();
NumOfCSPGOMemIntrinsics += ValueSites[IPVK_MemOPSize].size();
NumOfCSPGOBB += MST.BBInfos.size();
}
ValueSites[IPVK_MemOPSize] = MIVisitor.findMemIntrinsics(Func);
FuncName = getPGOFuncName(F);
computeCFGHash();
@ -875,28 +836,36 @@ static void instrumentOneFunc(
if (DisableValueProfiling)
return;
unsigned NumIndirectCalls = 0;
for (auto &I : FuncInfo.ValueSites[IPVK_IndirectCallTarget]) {
CallSite CS(I);
Value *Callee = CS.getCalledValue();
LLVM_DEBUG(dbgs() << "Instrument one indirect call: CallSite Index = "
<< NumIndirectCalls << "\n");
IRBuilder<> Builder(I);
assert(Builder.GetInsertPoint() != I->getParent()->end() &&
"Cannot get the Instrumentation point");
Builder.CreateCall(
Intrinsic::getDeclaration(M, Intrinsic::instrprof_value_profile),
{ConstantExpr::getBitCast(FuncInfo.FuncNameVar, I8PtrTy),
Builder.getInt64(FuncInfo.FunctionHash),
Builder.CreatePtrToInt(Callee, Builder.getInt64Ty()),
Builder.getInt32(IPVK_IndirectCallTarget),
Builder.getInt32(NumIndirectCalls++)});
}
NumOfPGOICall += NumIndirectCalls;
NumOfPGOICall += FuncInfo.ValueSites[IPVK_IndirectCallTarget].size();
// Now instrument memop intrinsic calls.
FuncInfo.MIVisitor.instrumentMemIntrinsics(
F, NumCounters, FuncInfo.FuncNameVar, FuncInfo.FunctionHash);
// For each VP Kind, walk the VP candidates and instrument each one.
for (uint32_t Kind = IPVK_First; Kind <= IPVK_Last; ++Kind) {
unsigned SiteIndex = 0;
if (Kind == IPVK_MemOPSize && !PGOInstrMemOP)
continue;
for (VPCandidateInfo Cand : FuncInfo.ValueSites[Kind]) {
LLVM_DEBUG(dbgs() << "Instrument one VP " << ValueProfKindDescr[Kind]
<< " site: CallSite Index = " << SiteIndex << "\n");
IRBuilder<> Builder(Cand.InsertPt);
assert(Builder.GetInsertPoint() != Cand.InsertPt->getParent()->end() &&
"Cannot get the Instrumentation point");
Value *ToProfile = nullptr;
if (Cand.V->getType()->isIntegerTy())
ToProfile = Builder.CreateZExtOrTrunc(Cand.V, Builder.getInt64Ty());
else if (Cand.V->getType()->isPointerTy())
ToProfile = Builder.CreatePtrToInt(Cand.V, Builder.getInt64Ty());
assert(ToProfile && "value profiling Value is of unexpected type");
Builder.CreateCall(
Intrinsic::getDeclaration(M, Intrinsic::instrprof_value_profile),
{ConstantExpr::getBitCast(FuncInfo.FuncNameVar, I8PtrTy),
Builder.getInt64(FuncInfo.FunctionHash), ToProfile,
Builder.getInt32(Kind), Builder.getInt32(SiteIndex++)});
}
} // IPVK_First <= Kind <= IPVK_Last
}
namespace {
@ -1429,43 +1398,6 @@ void SelectInstVisitor::visitSelectInst(SelectInst &SI) {
llvm_unreachable("Unknown visiting mode");
}
void MemIntrinsicVisitor::instrumentOneMemIntrinsic(MemIntrinsic &MI) {
Module *M = F.getParent();
IRBuilder<> Builder(&MI);
Type *Int64Ty = Builder.getInt64Ty();
Type *I8PtrTy = Builder.getInt8PtrTy();
Value *Length = MI.getLength();
assert(!isa<ConstantInt>(Length));
Builder.CreateCall(
Intrinsic::getDeclaration(M, Intrinsic::instrprof_value_profile),
{ConstantExpr::getBitCast(FuncNameVar, I8PtrTy),
Builder.getInt64(FuncHash), Builder.CreateZExtOrTrunc(Length, Int64Ty),
Builder.getInt32(IPVK_MemOPSize), Builder.getInt32(CurCtrId)});
++CurCtrId;
}
void MemIntrinsicVisitor::visitMemIntrinsic(MemIntrinsic &MI) {
if (!PGOInstrMemOP)
return;
Value *Length = MI.getLength();
// Not instrument constant length calls.
if (dyn_cast<ConstantInt>(Length))
return;
switch (Mode) {
case VM_counting:
NMemIs++;
return;
case VM_instrument:
instrumentOneMemIntrinsic(MI);
return;
case VM_annotate:
Candidates.push_back(&MI);
return;
}
llvm_unreachable("Unknown visiting mode");
}
// Traverse all valuesites and annotate the instructions for all value kind.
void PGOUseFunc::annotateValueSites() {
if (DisableValueProfiling)
@ -1478,11 +1410,6 @@ void PGOUseFunc::annotateValueSites() {
annotateValueSites(Kind);
}
static const char *ValueProfKindDescr[] = {
#define VALUE_PROF_KIND(Enumerator, Value, Descr) Descr,
#include "llvm/ProfileData/InstrProfData.inc"
};
// Annotate the instructions for a specific value kind.
void PGOUseFunc::annotateValueSites(uint32_t Kind) {
assert(Kind <= IPVK_Last);
@ -1501,11 +1428,11 @@ void PGOUseFunc::annotateValueSites(uint32_t Kind) {
return;
}
for (auto &I : ValueSites) {
for (VPCandidateInfo &I : ValueSites) {
LLVM_DEBUG(dbgs() << "Read one value site profile (kind = " << Kind
<< "): Index = " << ValueSiteIndex << " out of "
<< NumValueSites << "\n");
annotateValueSite(*M, *I, ProfileRecord,
annotateValueSite(*M, *I.AnnotatedInst, ProfileRecord,
static_cast<InstrProfValueKind>(Kind), ValueSiteIndex,
Kind == IPVK_MemOPSize ? MaxNumMemOPAnnotations
: MaxNumAnnotations);

View File

@ -0,0 +1,78 @@
//===- ValueProfileCollector.cpp - determine what to value profile --------===//
//
// 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
//
//===----------------------------------------------------------------------===//
//
// The implementation of the ValueProfileCollector via ValueProfileCollectorImpl
//
//===----------------------------------------------------------------------===//
#include "ValueProfilePlugins.inc"
#include "llvm/IR/InstIterator.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/InitializePasses.h"
#include <cassert>
using namespace llvm;
namespace {
/// A plugin-based class that takes an arbitrary number of Plugin types.
/// Each plugin type must satisfy the following API:
/// 1) the constructor must take a `Function &f`. Typically, the plugin would
/// scan the function looking for candidates.
/// 2) contain a member function with the following signature and name:
/// void run(std::vector<CandidateInfo> &Candidates);
/// such that the plugin would append its result into the vector parameter.
///
/// Plugins are defined in ValueProfilePlugins.inc
template <class... Ts> class PluginChain;
/// The type PluginChainFinal is the final chain of plugins that will be used by
/// ValueProfileCollectorImpl.
using PluginChainFinal = PluginChain<VP_PLUGIN_LIST>;
template <> class PluginChain<> {
public:
PluginChain(Function &F) {}
void get(InstrProfValueKind K, std::vector<CandidateInfo> &Candidates) {}
};
template <class PluginT, class... Ts>
class PluginChain<PluginT, Ts...> : public PluginChain<Ts...> {
PluginT Plugin;
using Base = PluginChain<Ts...>;
public:
PluginChain(Function &F) : PluginChain<Ts...>(F), Plugin(F) {}
void get(InstrProfValueKind K, std::vector<CandidateInfo> &Candidates) {
if (K == PluginT::Kind)
Plugin.run(Candidates);
Base::get(K, Candidates);
}
};
} // end anonymous namespace
/// ValueProfileCollectorImpl inherits the API of PluginChainFinal.
class ValueProfileCollector::ValueProfileCollectorImpl : public PluginChainFinal {
public:
using PluginChainFinal::PluginChainFinal;
};
ValueProfileCollector::ValueProfileCollector(Function &F)
: PImpl(new ValueProfileCollectorImpl(F)) {}
ValueProfileCollector::~ValueProfileCollector() = default;
std::vector<CandidateInfo>
ValueProfileCollector::get(InstrProfValueKind Kind) const {
std::vector<CandidateInfo> Result;
PImpl->get(Kind, Result);
return Result;
}

View File

@ -0,0 +1,79 @@
//===- ValueProfileCollector.h - determine what to value profile ----------===//
//
// 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
//
//===----------------------------------------------------------------------===//
//
// This file contains a utility class, ValueProfileCollector, that is used to
// determine what kind of llvm::Value's are worth value-profiling, at which
// point in the program, and which instruction holds the Value Profile metadata.
// Currently, the only users of this utility is the PGOInstrumentation[Gen|Use]
// passes.
//===----------------------------------------------------------------------===//
#ifndef LLVM_ANALYSIS_PROFILE_GEN_ANALYSIS_H
#define LLVM_ANALYSIS_PROFILE_GEN_ANALYSIS_H
#include "llvm/IR/Function.h"
#include "llvm/IR/PassManager.h"
#include "llvm/Pass.h"
#include "llvm/ProfileData/InstrProf.h"
namespace llvm {
/// Utility analysis that determines what values are worth profiling.
/// The actual logic is inside the ValueProfileCollectorImpl, whose job is to
/// populate the Candidates vector.
///
/// Value profiling an expression means to track the values that this expression
/// takes at runtime and the frequency of each value.
/// It is important to distinguish between two sets of value profiles for a
/// particular expression:
/// 1) The set of values at the point of evaluation.
/// 2) The set of values at the point of use.
/// In some cases, the two sets are identical, but it's not unusual for the two
/// to differ.
///
/// To elaborate more, consider this C code, and focus on the expression `nn`:
/// void foo(int nn, bool b) {
/// if (b) memcpy(x, y, nn);
/// }
/// The point of evaluation can be as early as the start of the function, and
/// let's say the value profile for `nn` is:
/// total=100; (value,freq) set = {(8,10), (32,50)}
/// The point of use is right before we call memcpy, and since we execute the
/// memcpy conditionally, the value profile of `nn` can be:
/// total=15; (value,freq) set = {(8,10), (4,5)}
///
/// For this reason, a plugin is responsible for computing the insertion point
/// for each value to be profiled. The `CandidateInfo` structure encapsulates
/// all the information needed for each value profile site.
class ValueProfileCollector {
public:
struct CandidateInfo {
Value *V; // The value to profile.
Instruction *InsertPt; // Insert the VP lib call before this instr.
Instruction *AnnotatedInst; // Where metadata is attached.
};
ValueProfileCollector(Function &Fn);
ValueProfileCollector(ValueProfileCollector &&) = delete;
ValueProfileCollector &operator=(ValueProfileCollector &&) = delete;
ValueProfileCollector(const ValueProfileCollector &) = delete;
ValueProfileCollector &operator=(const ValueProfileCollector &) = delete;
~ValueProfileCollector();
/// returns a list of value profiling candidates of the given kind
std::vector<CandidateInfo> get(InstrProfValueKind Kind) const;
private:
class ValueProfileCollectorImpl;
std::unique_ptr<ValueProfileCollectorImpl> PImpl;
};
} // namespace llvm
#endif

View File

@ -0,0 +1,75 @@
//=== ValueProfilePlugins.inc - set of plugins used by ValueProfileCollector =//
//
// 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
//
//===----------------------------------------------------------------------===//
//
// This file contains a set of plugin classes used in ValueProfileCollectorImpl.
// Each plugin is responsible for collecting Value Profiling candidates for a
// particular optimization.
// Each plugin must satisfy the interface described in ValueProfileCollector.cpp
//
//===----------------------------------------------------------------------===//
#include "ValueProfileCollector.h"
#include "llvm/Analysis/IndirectCallVisitor.h"
#include "llvm/IR/InstVisitor.h"
using namespace llvm;
using CandidateInfo = ValueProfileCollector::CandidateInfo;
///--------------------------- MemIntrinsicPlugin ------------------------------
class MemIntrinsicPlugin : public InstVisitor<MemIntrinsicPlugin> {
Function &F;
std::vector<CandidateInfo> *Candidates;
public:
static constexpr InstrProfValueKind Kind = IPVK_MemOPSize;
MemIntrinsicPlugin(Function &Fn) : F(Fn), Candidates(nullptr) {}
void run(std::vector<CandidateInfo> &Cs) {
Candidates = &Cs;
visit(F);
Candidates = nullptr;
}
void visitMemIntrinsic(MemIntrinsic &MI) {
Value *Length = MI.getLength();
// Not instrument constant length calls.
if (dyn_cast<ConstantInt>(Length))
return;
Instruction *InsertPt = &MI;
Instruction *AnnotatedInst = &MI;
Candidates->emplace_back(CandidateInfo{Length, InsertPt, AnnotatedInst});
}
};
///------------------------ IndirectCallPromotionPlugin ------------------------
class IndirectCallPromotionPlugin {
Function &F;
public:
static constexpr InstrProfValueKind Kind = IPVK_IndirectCallTarget;
IndirectCallPromotionPlugin(Function &Fn) : F(Fn) {}
void run(std::vector<CandidateInfo> &Candidates) {
std::vector<Instruction *> Result = findIndirectCalls(F);
for (Instruction *I : Result) {
Value *Callee = CallSite(I).getCalledValue();
Instruction *InsertPt = I;
Instruction *AnnotatedInst = I;
Candidates.emplace_back(CandidateInfo{Callee, InsertPt, AnnotatedInst});
}
}
};
///----------------------- Registration of the plugins -------------------------
/// For now, registering a plugin with the ValueProfileCollector is done by
/// adding the plugin type to the VP_PLUGIN_LIST macro.
#define VP_PLUGIN_LIST \
MemIntrinsicPlugin, \
IndirectCallPromotionPlugin