mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-26 19:06:05 +00:00

Port CodeGenPrepare to new pass manager and dependency BasicBlockSectionsProfileReader Fixes: #75380 Co-authored-by: Krishna-13-cyber <84722531+Krishna-13-cyber@users.noreply.github.com>
247 lines
9.4 KiB
C++
247 lines
9.4 KiB
C++
//===-- BasicBlockPathCloning.cpp ---=========-----------------------------===//
|
|
//
|
|
// 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
/// \file
|
|
/// BasicBlockPathCloning implementation.
|
|
///
|
|
/// The purpose of this pass is to clone basic block paths based on information
|
|
/// provided by the -fbasic-block-sections=list option.
|
|
/// Please refer to BasicBlockSectionsProfileReader.cpp to see a path cloning
|
|
/// example.
|
|
//===----------------------------------------------------------------------===//
|
|
// This pass clones the machine basic blocks alongs the given paths and sets up
|
|
// the CFG. It assigns BBIDs to the cloned blocks so that the
|
|
// `BasicBlockSections` pass can correctly map the cluster information to the
|
|
// blocks. The cloned block's BBID will have the same BaseID as the original
|
|
// block, but will get a unique non-zero CloneID (original blocks all have zero
|
|
// CloneIDs). This pass applies a path cloning if it satisfies the following
|
|
// conditions:
|
|
// 1. All BBIDs in the path should be mapped to existing blocks.
|
|
// 2. Each two consecutive BBIDs in the path must have a successor
|
|
// relationship in the CFG.
|
|
// 3. The path should not include a block with indirect branches, except for
|
|
// the last block.
|
|
// If a path does not satisfy all three conditions, it will be rejected, but the
|
|
// CloneIDs for its (supposed to be cloned) blocks will be bypassed to make sure
|
|
// that the `BasicBlockSections` pass can map cluster info correctly to the
|
|
// actually-cloned blocks.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "llvm/ADT/SmallVector.h"
|
|
#include "llvm/ADT/StringRef.h"
|
|
#include "llvm/CodeGen/BasicBlockSectionUtils.h"
|
|
#include "llvm/CodeGen/BasicBlockSectionsProfileReader.h"
|
|
#include "llvm/CodeGen/MachineFunction.h"
|
|
#include "llvm/CodeGen/MachineFunctionPass.h"
|
|
#include "llvm/CodeGen/Passes.h"
|
|
#include "llvm/CodeGen/TargetInstrInfo.h"
|
|
#include "llvm/InitializePasses.h"
|
|
#include "llvm/Support/WithColor.h"
|
|
#include "llvm/Target/TargetMachine.h"
|
|
|
|
using namespace llvm;
|
|
|
|
namespace {
|
|
|
|
// Clones the given block and assigns the given `CloneID` to its BBID. Copies
|
|
// the instructions into the new block and sets up its successors.
|
|
MachineBasicBlock *CloneMachineBasicBlock(MachineBasicBlock &OrigBB,
|
|
unsigned CloneID) {
|
|
auto &MF = *OrigBB.getParent();
|
|
auto TII = MF.getSubtarget().getInstrInfo();
|
|
// Create the clone block and set its BBID based on the original block.
|
|
MachineBasicBlock *CloneBB = MF.CreateMachineBasicBlock(
|
|
OrigBB.getBasicBlock(), UniqueBBID{OrigBB.getBBID()->BaseID, CloneID});
|
|
MF.push_back(CloneBB);
|
|
|
|
// Copy the instructions.
|
|
for (auto &I : OrigBB.instrs()) {
|
|
// Bundled instructions are duplicated together.
|
|
if (I.isBundledWithPred())
|
|
continue;
|
|
TII->duplicate(*CloneBB, CloneBB->end(), I);
|
|
}
|
|
|
|
// Add the successors of the original block as the new block's successors.
|
|
// We set the predecessor after returning from this call.
|
|
for (auto SI = OrigBB.succ_begin(), SE = OrigBB.succ_end(); SI != SE; ++SI)
|
|
CloneBB->copySuccessor(&OrigBB, SI);
|
|
|
|
if (auto FT = OrigBB.getFallThrough(/*JumpToFallThrough=*/false)) {
|
|
// The original block has an implicit fall through.
|
|
// Insert an explicit unconditional jump from the cloned block to the
|
|
// fallthrough block. Technically, this is only needed for the last block
|
|
// of the path, but we do it for all clones for consistency.
|
|
TII->insertUnconditionalBranch(*CloneBB, FT, CloneBB->findBranchDebugLoc());
|
|
}
|
|
return CloneBB;
|
|
}
|
|
|
|
// Returns if we can legally apply the cloning represented by `ClonePath`.
|
|
// `BBIDToBlock` contains the original basic blocks in function `MF` keyed by
|
|
// their `BBID::BaseID`.
|
|
bool IsValidCloning(const MachineFunction &MF,
|
|
const DenseMap<unsigned, MachineBasicBlock *> &BBIDToBlock,
|
|
const SmallVector<unsigned> &ClonePath) {
|
|
const MachineBasicBlock *PrevBB = nullptr;
|
|
for (size_t I = 0; I < ClonePath.size(); ++I) {
|
|
unsigned BBID = ClonePath[I];
|
|
const MachineBasicBlock *PathBB = BBIDToBlock.lookup(BBID);
|
|
if (!PathBB) {
|
|
WithColor::warning() << "no block with id " << BBID << " in function "
|
|
<< MF.getName() << "\n";
|
|
return false;
|
|
}
|
|
|
|
if (PrevBB) {
|
|
if (!PrevBB->isSuccessor(PathBB)) {
|
|
WithColor::warning()
|
|
<< "block #" << BBID << " is not a successor of block #"
|
|
<< PrevBB->getBBID()->BaseID << " in function " << MF.getName()
|
|
<< "\n";
|
|
return false;
|
|
}
|
|
|
|
for (auto &MI : *PathBB) {
|
|
// Avoid cloning when the block contains non-duplicable instructions.
|
|
// CFI instructions are marked as non-duplicable only because of Darwin,
|
|
// so we exclude them from this check.
|
|
if (MI.isNotDuplicable() && !MI.isCFIInstruction()) {
|
|
WithColor::warning()
|
|
<< "block #" << BBID
|
|
<< " has non-duplicable instructions in function " << MF.getName()
|
|
<< "\n";
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (I != ClonePath.size() - 1 && !PathBB->empty() &&
|
|
PathBB->back().isIndirectBranch()) {
|
|
WithColor::warning()
|
|
<< "block #" << BBID
|
|
<< " has indirect branch and appears as the non-tail block of a "
|
|
"path in function "
|
|
<< MF.getName() << "\n";
|
|
return false;
|
|
}
|
|
PrevBB = PathBB;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// Applies all clonings specified in `ClonePaths` to `MF`. Returns true
|
|
// if any clonings have been applied.
|
|
bool ApplyCloning(MachineFunction &MF,
|
|
const SmallVector<SmallVector<unsigned>> &ClonePaths) {
|
|
if (ClonePaths.empty())
|
|
return false;
|
|
bool AnyPathsCloned = false;
|
|
// Map from the final BB IDs to the `MachineBasicBlock`s.
|
|
DenseMap<unsigned, MachineBasicBlock *> BBIDToBlock;
|
|
for (auto &BB : MF)
|
|
BBIDToBlock.try_emplace(BB.getBBID()->BaseID, &BB);
|
|
|
|
DenseMap<unsigned, unsigned> NClonesForBBID;
|
|
auto TII = MF.getSubtarget().getInstrInfo();
|
|
for (const auto &ClonePath : ClonePaths) {
|
|
if (!IsValidCloning(MF, BBIDToBlock, ClonePath)) {
|
|
// We still need to increment the number of clones so we can map
|
|
// to the cluster info correctly.
|
|
for (unsigned BBID : ClonePath)
|
|
++NClonesForBBID[BBID];
|
|
continue;
|
|
}
|
|
MachineBasicBlock *PrevBB = nullptr;
|
|
for (unsigned BBID : ClonePath) {
|
|
MachineBasicBlock *OrigBB = BBIDToBlock.at(BBID);
|
|
if (PrevBB == nullptr) {
|
|
// The first block in the path is not cloned. We only need to make it
|
|
// branch to the next cloned block in the path. Here, we make its
|
|
// fallthrough explicit so we can change it later.
|
|
if (auto FT = OrigBB->getFallThrough(/*JumpToFallThrough=*/false)) {
|
|
TII->insertUnconditionalBranch(*OrigBB, FT,
|
|
OrigBB->findBranchDebugLoc());
|
|
}
|
|
PrevBB = OrigBB;
|
|
continue;
|
|
}
|
|
MachineBasicBlock *CloneBB =
|
|
CloneMachineBasicBlock(*OrigBB, ++NClonesForBBID[BBID]);
|
|
|
|
// Set up the previous block in the path to jump to the clone. This also
|
|
// transfers the successor/predecessor relationship of PrevBB and OrigBB
|
|
// to that of PrevBB and CloneBB.
|
|
PrevBB->ReplaceUsesOfBlockWith(OrigBB, CloneBB);
|
|
|
|
// Copy the livein set.
|
|
for (auto &LiveIn : OrigBB->liveins())
|
|
CloneBB->addLiveIn(LiveIn);
|
|
|
|
PrevBB = CloneBB;
|
|
}
|
|
AnyPathsCloned = true;
|
|
}
|
|
return AnyPathsCloned;
|
|
}
|
|
} // end anonymous namespace
|
|
|
|
namespace llvm {
|
|
class BasicBlockPathCloning : public MachineFunctionPass {
|
|
public:
|
|
static char ID;
|
|
|
|
BasicBlockSectionsProfileReaderWrapperPass *BBSectionsProfileReader = nullptr;
|
|
|
|
BasicBlockPathCloning() : MachineFunctionPass(ID) {
|
|
initializeBasicBlockPathCloningPass(*PassRegistry::getPassRegistry());
|
|
}
|
|
|
|
StringRef getPassName() const override { return "Basic Block Path Cloning"; }
|
|
|
|
void getAnalysisUsage(AnalysisUsage &AU) const override;
|
|
|
|
/// Identify basic blocks that need separate sections and prepare to emit them
|
|
/// accordingly.
|
|
bool runOnMachineFunction(MachineFunction &MF) override;
|
|
};
|
|
|
|
} // namespace llvm
|
|
|
|
char BasicBlockPathCloning::ID = 0;
|
|
INITIALIZE_PASS_BEGIN(
|
|
BasicBlockPathCloning, "bb-path-cloning",
|
|
"Applies path clonings for the -basic-block-sections=list option", false,
|
|
false)
|
|
INITIALIZE_PASS_DEPENDENCY(BasicBlockSectionsProfileReaderWrapperPass)
|
|
INITIALIZE_PASS_END(
|
|
BasicBlockPathCloning, "bb-path-cloning",
|
|
"Applies path clonings for the -basic-block-sections=list option", false,
|
|
false)
|
|
|
|
bool BasicBlockPathCloning::runOnMachineFunction(MachineFunction &MF) {
|
|
assert(MF.getTarget().getBBSectionsType() == BasicBlockSection::List &&
|
|
"BB Sections list not enabled!");
|
|
if (hasInstrProfHashMismatch(MF))
|
|
return false;
|
|
|
|
return ApplyCloning(MF,
|
|
getAnalysis<BasicBlockSectionsProfileReaderWrapperPass>()
|
|
.getClonePathsForFunction(MF.getName()));
|
|
}
|
|
|
|
void BasicBlockPathCloning::getAnalysisUsage(AnalysisUsage &AU) const {
|
|
AU.setPreservesAll();
|
|
AU.addRequired<BasicBlockSectionsProfileReaderWrapperPass>();
|
|
MachineFunctionPass::getAnalysisUsage(AU);
|
|
}
|
|
|
|
MachineFunctionPass *llvm::createBasicBlockPathCloningPass() {
|
|
return new BasicBlockPathCloning();
|
|
}
|