#include "llvm/Transforms/Utils/SampleProfileInference.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include <queue>
#include <set>
#include <stack>
#include <unordered_set>
usingnamespacellvm;
#define DEBUG_TYPE …
namespace {
static cl::opt<bool> SampleProfileEvenFlowDistribution(
"sample-profile-even-flow-distribution", cl::init(true), cl::Hidden,
cl::desc("Try to evenly distribute flow when there are multiple equally "
"likely options."));
static cl::opt<bool> SampleProfileRebalanceUnknown(
"sample-profile-rebalance-unknown", cl::init(true), cl::Hidden,
cl::desc("Evenly re-distribute flow among unknown subgraphs."));
static cl::opt<bool> SampleProfileJoinIslands(
"sample-profile-join-islands", cl::init(true), cl::Hidden,
cl::desc("Join isolated components having positive flow."));
static cl::opt<unsigned> SampleProfileProfiCostBlockInc(
"sample-profile-profi-cost-block-inc", cl::init(10), cl::Hidden,
cl::desc("The cost of increasing a block's count by one."));
static cl::opt<unsigned> SampleProfileProfiCostBlockDec(
"sample-profile-profi-cost-block-dec", cl::init(20), cl::Hidden,
cl::desc("The cost of decreasing a block's count by one."));
static cl::opt<unsigned> SampleProfileProfiCostBlockEntryInc(
"sample-profile-profi-cost-block-entry-inc", cl::init(40), cl::Hidden,
cl::desc("The cost of increasing the entry block's count by one."));
static cl::opt<unsigned> SampleProfileProfiCostBlockEntryDec(
"sample-profile-profi-cost-block-entry-dec", cl::init(10), cl::Hidden,
cl::desc("The cost of decreasing the entry block's count by one."));
static cl::opt<unsigned> SampleProfileProfiCostBlockZeroInc(
"sample-profile-profi-cost-block-zero-inc", cl::init(11), cl::Hidden,
cl::desc("The cost of increasing a count of zero-weight block by one."));
static cl::opt<unsigned> SampleProfileProfiCostBlockUnknownInc(
"sample-profile-profi-cost-block-unknown-inc", cl::init(0), cl::Hidden,
cl::desc("The cost of increasing an unknown block's count by one."));
static constexpr int64_t INF = …;
class MinCostMaxFlow { … };
class FlowAdjuster { … };
std::pair<int64_t, int64_t> assignBlockCosts(const ProfiParams &Params,
const FlowBlock &Block);
std::pair<int64_t, int64_t> assignJumpCosts(const ProfiParams &Params,
const FlowJump &Jump);
void initializeNetwork(const ProfiParams &Params, MinCostMaxFlow &Network,
FlowFunction &Func) { … }
std::pair<int64_t, int64_t> assignBlockCosts(const ProfiParams &Params,
const FlowBlock &Block) { … }
std::pair<int64_t, int64_t> assignJumpCosts(const ProfiParams &Params,
const FlowJump &Jump) { … }
void extractWeights(const ProfiParams &Params, MinCostMaxFlow &Network,
FlowFunction &Func) { … }
#ifndef NDEBUG
void verifyInput(const FlowFunction &Func) {
assert(Func.Entry == 0 && Func.Blocks[0].isEntry());
size_t NumExitBlocks = 0;
for (size_t I = 1; I < Func.Blocks.size(); I++) {
assert(!Func.Blocks[I].isEntry() && "multiple entry blocks");
if (Func.Blocks[I].isExit())
NumExitBlocks++;
}
assert(NumExitBlocks > 0 && "cannot find exit blocks");
for (auto &Block : Func.Blocks) {
std::unordered_set<uint64_t> UniqueSuccs;
for (auto &Jump : Block.SuccJumps) {
auto It = UniqueSuccs.insert(Jump->Target);
assert(It.second && "input CFG contains parallel edges");
}
}
for (auto &Block : Func.Blocks) {
assert((!Block.isEntry() || !Block.isExit()) &&
"a block cannot be an entry and an exit");
}
for (auto &Block : Func.Blocks) {
assert((!Block.HasUnknownWeight || Block.Weight == 0 || Block.isEntry()) &&
"non-zero weight of a block w/o weight except for an entry");
}
for (auto &Jump : Func.Jumps) {
assert((!Jump.HasUnknownWeight || Jump.Weight == 0) &&
"non-zero weight of a jump w/o weight");
}
}
void verifyOutput(const FlowFunction &Func) {
const uint64_t NumBlocks = Func.Blocks.size();
auto InFlow = std::vector<uint64_t>(NumBlocks, 0);
auto OutFlow = std::vector<uint64_t>(NumBlocks, 0);
for (const auto &Jump : Func.Jumps) {
InFlow[Jump.Target] += Jump.Flow;
OutFlow[Jump.Source] += Jump.Flow;
}
uint64_t TotalInFlow = 0;
uint64_t TotalOutFlow = 0;
for (uint64_t I = 0; I < NumBlocks; I++) {
auto &Block = Func.Blocks[I];
if (Block.isEntry()) {
TotalInFlow += Block.Flow;
assert(Block.Flow == OutFlow[I] && "incorrectly computed control flow");
} else if (Block.isExit()) {
TotalOutFlow += Block.Flow;
assert(Block.Flow == InFlow[I] && "incorrectly computed control flow");
} else {
assert(Block.Flow == OutFlow[I] && "incorrectly computed control flow");
assert(Block.Flow == InFlow[I] && "incorrectly computed control flow");
}
}
assert(TotalInFlow == TotalOutFlow && "incorrectly computed control flow");
auto PositiveFlowEdges = std::vector<std::vector<uint64_t>>(NumBlocks);
for (const auto &Jump : Func.Jumps) {
if (Jump.Flow > 0) {
PositiveFlowEdges[Jump.Source].push_back(Jump.Target);
}
}
std::queue<uint64_t> Queue;
auto Visited = BitVector(NumBlocks, false);
Queue.push(Func.Entry);
Visited[Func.Entry] = true;
while (!Queue.empty()) {
uint64_t Src = Queue.front();
Queue.pop();
for (uint64_t Dst : PositiveFlowEdges[Src]) {
if (!Visited[Dst]) {
Queue.push(Dst);
Visited[Dst] = true;
}
}
}
for (uint64_t I = 0; I < NumBlocks; I++) {
auto &Block = Func.Blocks[I];
assert((Visited[I] || Block.Flow == 0) && "an isolated flow component");
}
}
#endif
}
void llvm::applyFlowInference(const ProfiParams &Params, FlowFunction &Func) { … }
void llvm::applyFlowInference(FlowFunction &Func) { … }