193 lines
7.3 KiB
C++
193 lines
7.3 KiB
C++
//===- llvm/CodeGen/BasicBlockMatchingAndInference.cpp ----------*- C++ -*-===//
|
|
//
|
|
// 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// In Propeller's profile, we have already read the hash values of basic blocks,
|
|
// as well as the weights of basic blocks and edges in the CFG. In this file,
|
|
// we first match the basic blocks in the profile with those in the current
|
|
// MachineFunction using the basic block hash, thereby obtaining the weights of
|
|
// some basic blocks and edges. Subsequently, we infer the weights of all basic
|
|
// blocks using an inference algorithm.
|
|
//
|
|
// TODO: Integrate part of the code in this file with BOLT's implementation into
|
|
// the LLVM infrastructure, enabling both BOLT and Propeller to reuse it.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "llvm/CodeGen/BasicBlockMatchingAndInference.h"
|
|
#include "llvm/ADT/DenseMap.h"
|
|
#include "llvm/CodeGen/BasicBlockSectionsProfileReader.h"
|
|
#include "llvm/CodeGen/MachineBlockHashInfo.h"
|
|
#include "llvm/CodeGen/Passes.h"
|
|
#include "llvm/InitializePasses.h"
|
|
#include <llvm/Support/CommandLine.h>
|
|
|
|
using namespace llvm;
|
|
|
|
static cl::opt<float>
|
|
PropellerInferThreshold("propeller-infer-threshold",
|
|
cl::desc("Threshold for infer stale profile"),
|
|
cl::init(0.6), cl::Optional);
|
|
|
|
/// The object is used to identify and match basic blocks given their hashes.
|
|
class StaleMatcher {
|
|
public:
|
|
/// Initialize stale matcher.
|
|
void init(const std::vector<MachineBasicBlock *> &Blocks,
|
|
const std::vector<BlendedBlockHash> &Hashes) {
|
|
assert(Blocks.size() == Hashes.size() &&
|
|
"incorrect matcher initialization");
|
|
for (size_t I = 0; I < Blocks.size(); I++) {
|
|
MachineBasicBlock *Block = Blocks[I];
|
|
uint16_t OpHash = Hashes[I].getOpcodeHash();
|
|
OpHashToBlocks[OpHash].push_back(std::make_pair(Hashes[I], Block));
|
|
}
|
|
}
|
|
|
|
/// Find the most similar block for a given hash.
|
|
MachineBasicBlock *matchBlock(BlendedBlockHash BlendedHash) const {
|
|
auto BlockIt = OpHashToBlocks.find(BlendedHash.getOpcodeHash());
|
|
if (BlockIt == OpHashToBlocks.end()) {
|
|
return nullptr;
|
|
}
|
|
MachineBasicBlock *BestBlock = nullptr;
|
|
uint64_t BestDist = std::numeric_limits<uint64_t>::max();
|
|
for (auto It : BlockIt->second) {
|
|
MachineBasicBlock *Block = It.second;
|
|
BlendedBlockHash Hash = It.first;
|
|
uint64_t Dist = Hash.distance(BlendedHash);
|
|
if (BestBlock == nullptr || Dist < BestDist) {
|
|
BestDist = Dist;
|
|
BestBlock = Block;
|
|
}
|
|
}
|
|
return BestBlock;
|
|
}
|
|
|
|
private:
|
|
using HashBlockPairType = std::pair<BlendedBlockHash, MachineBasicBlock *>;
|
|
DenseMap<uint16_t, std::vector<HashBlockPairType>> OpHashToBlocks;
|
|
};
|
|
|
|
INITIALIZE_PASS_BEGIN(BasicBlockMatchingAndInference,
|
|
"machine-block-match-infer",
|
|
"Machine Block Matching and Inference Analysis", true,
|
|
true)
|
|
INITIALIZE_PASS_DEPENDENCY(MachineBlockHashInfo)
|
|
INITIALIZE_PASS_DEPENDENCY(BasicBlockSectionsProfileReaderWrapperPass)
|
|
INITIALIZE_PASS_END(BasicBlockMatchingAndInference, "machine-block-match-infer",
|
|
"Machine Block Matching and Inference Analysis", true, true)
|
|
|
|
char BasicBlockMatchingAndInference::ID = 0;
|
|
|
|
BasicBlockMatchingAndInference::BasicBlockMatchingAndInference()
|
|
: MachineFunctionPass(ID) {}
|
|
|
|
void BasicBlockMatchingAndInference::getAnalysisUsage(AnalysisUsage &AU) const {
|
|
AU.addRequired<MachineBlockHashInfo>();
|
|
AU.addRequired<BasicBlockSectionsProfileReaderWrapperPass>();
|
|
AU.setPreservesAll();
|
|
MachineFunctionPass::getAnalysisUsage(AU);
|
|
}
|
|
|
|
std::optional<BasicBlockMatchingAndInference::WeightInfo>
|
|
BasicBlockMatchingAndInference::getWeightInfo(StringRef FuncName) const {
|
|
auto It = ProgramWeightInfo.find(FuncName);
|
|
if (It == ProgramWeightInfo.end()) {
|
|
return std::nullopt;
|
|
}
|
|
return It->second;
|
|
}
|
|
|
|
BasicBlockMatchingAndInference::WeightInfo
|
|
BasicBlockMatchingAndInference::initWeightInfoByMatching(MachineFunction &MF) {
|
|
std::vector<MachineBasicBlock *> Blocks;
|
|
std::vector<BlendedBlockHash> Hashes;
|
|
auto BSPR = &getAnalysis<BasicBlockSectionsProfileReaderWrapperPass>();
|
|
auto MBHI = &getAnalysis<MachineBlockHashInfo>();
|
|
for (auto &Block : MF) {
|
|
Blocks.push_back(&Block);
|
|
Hashes.push_back(BlendedBlockHash(MBHI->getMBBHash(Block)));
|
|
}
|
|
StaleMatcher Matcher;
|
|
Matcher.init(Blocks, Hashes);
|
|
BasicBlockMatchingAndInference::WeightInfo MatchWeight;
|
|
const CFGProfile *CFG = BSPR->getFunctionCFGProfile(MF.getName());
|
|
if (CFG == nullptr)
|
|
return MatchWeight;
|
|
for (auto &BlockCount : CFG->NodeCounts) {
|
|
if (CFG->BBHashes.count(BlockCount.first.BaseID)) {
|
|
auto Hash = CFG->BBHashes.lookup(BlockCount.first.BaseID);
|
|
MachineBasicBlock *Block = Matcher.matchBlock(BlendedBlockHash(Hash));
|
|
// When a basic block has clone copies, sum their counts.
|
|
if (Block != nullptr)
|
|
MatchWeight.BlockWeights[Block] += BlockCount.second;
|
|
}
|
|
}
|
|
for (auto &PredItem : CFG->EdgeCounts) {
|
|
auto PredID = PredItem.first.BaseID;
|
|
if (!CFG->BBHashes.count(PredID))
|
|
continue;
|
|
auto PredHash = CFG->BBHashes.lookup(PredID);
|
|
MachineBasicBlock *PredBlock =
|
|
Matcher.matchBlock(BlendedBlockHash(PredHash));
|
|
if (PredBlock == nullptr)
|
|
continue;
|
|
for (auto &SuccItem : PredItem.second) {
|
|
auto SuccID = SuccItem.first.BaseID;
|
|
auto EdgeWeight = SuccItem.second;
|
|
if (CFG->BBHashes.count(SuccID)) {
|
|
auto SuccHash = CFG->BBHashes.lookup(SuccID);
|
|
MachineBasicBlock *SuccBlock =
|
|
Matcher.matchBlock(BlendedBlockHash(SuccHash));
|
|
// When an edge has clone copies, sum their counts.
|
|
if (SuccBlock != nullptr)
|
|
MatchWeight.EdgeWeights[std::make_pair(PredBlock, SuccBlock)] +=
|
|
EdgeWeight;
|
|
}
|
|
}
|
|
}
|
|
return MatchWeight;
|
|
}
|
|
|
|
void BasicBlockMatchingAndInference::generateWeightInfoByInference(
|
|
MachineFunction &MF,
|
|
BasicBlockMatchingAndInference::WeightInfo &MatchWeight) {
|
|
BlockEdgeMap Successors;
|
|
for (auto &Block : MF) {
|
|
for (auto *Succ : Block.successors())
|
|
Successors[&Block].push_back(Succ);
|
|
}
|
|
SampleProfileInference<MachineFunction> SPI(
|
|
MF, Successors, MatchWeight.BlockWeights, MatchWeight.EdgeWeights);
|
|
BlockWeightMap BlockWeights;
|
|
EdgeWeightMap EdgeWeights;
|
|
SPI.apply(BlockWeights, EdgeWeights);
|
|
ProgramWeightInfo.try_emplace(
|
|
MF.getName(), BasicBlockMatchingAndInference::WeightInfo{
|
|
std::move(BlockWeights), std::move(EdgeWeights)});
|
|
}
|
|
|
|
bool BasicBlockMatchingAndInference::runOnMachineFunction(MachineFunction &MF) {
|
|
if (MF.empty())
|
|
return false;
|
|
auto MatchWeight = initWeightInfoByMatching(MF);
|
|
// If the ratio of the number of MBBs in matching to the total number of MBBs
|
|
// in the function is less than the threshold value, the processing should be
|
|
// abandoned.
|
|
if (static_cast<float>(MatchWeight.BlockWeights.size()) / MF.size() <
|
|
PropellerInferThreshold) {
|
|
return false;
|
|
}
|
|
generateWeightInfoByInference(MF, MatchWeight);
|
|
return false;
|
|
}
|
|
|
|
MachineFunctionPass *llvm::createBasicBlockMatchingAndInferencePass() {
|
|
return new BasicBlockMatchingAndInference();
|
|
}
|