aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/CodeGen/BasicBlockPathCloning.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/CodeGen/BasicBlockPathCloning.cpp')
-rw-r--r--llvm/lib/CodeGen/BasicBlockPathCloning.cpp245
1 files changed, 245 insertions, 0 deletions
diff --git a/llvm/lib/CodeGen/BasicBlockPathCloning.cpp b/llvm/lib/CodeGen/BasicBlockPathCloning.cpp
new file mode 100644
index 000000000000..5d5f3c3da481
--- /dev/null
+++ b/llvm/lib/CodeGen/BasicBlockPathCloning.cpp
@@ -0,0 +1,245 @@
+//===-- 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;
+
+ BasicBlockSectionsProfileReader *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(BasicBlockSectionsProfileReader)
+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<BasicBlockSectionsProfileReader>()
+ .getClonePathsForFunction(MF.getName()));
+}
+
+void BasicBlockPathCloning::getAnalysisUsage(AnalysisUsage &AU) const {
+ AU.setPreservesAll();
+ AU.addRequired<BasicBlockSectionsProfileReader>();
+ MachineFunctionPass::getAnalysisUsage(AU);
+}
+
+MachineFunctionPass *llvm::createBasicBlockPathCloningPass() {
+ return new BasicBlockPathCloning();
+}