12f09f445SMaksim Panchenko //===- bolt/Passes/LoopInversionPass.cpp ----------------------------------===//
2a34c753fSRafael Auler //
3a34c753fSRafael Auler // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4a34c753fSRafael Auler // See https://llvm.org/LICENSE.txt for license information.
5a34c753fSRafael Auler // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6a34c753fSRafael Auler //
7a34c753fSRafael Auler //===----------------------------------------------------------------------===//
8a34c753fSRafael Auler //
92f09f445SMaksim Panchenko // This file implements the LoopInversionPass class.
102f09f445SMaksim Panchenko //
11a34c753fSRafael Auler //===----------------------------------------------------------------------===//
12a34c753fSRafael Auler
13a34c753fSRafael Auler #include "bolt/Passes/LoopInversionPass.h"
14a34c753fSRafael Auler #include "bolt/Core/ParallelUtilities.h"
15a34c753fSRafael Auler
16a34c753fSRafael Auler using namespace llvm;
17a34c753fSRafael Auler
18a34c753fSRafael Auler namespace opts {
19a34c753fSRafael Auler extern cl::OptionCategory BoltCategory;
20a34c753fSRafael Auler
21a34c753fSRafael Auler extern cl::opt<bolt::ReorderBasicBlocks::LayoutType> ReorderBlocks;
22a34c753fSRafael Auler
23a34c753fSRafael Auler static cl::opt<bool> LoopReorder(
24a34c753fSRafael Auler "loop-inversion-opt",
25a34c753fSRafael Auler cl::desc("reorder unconditional jump instructions in loops optimization"),
26a34c753fSRafael Auler cl::init(true), cl::cat(BoltCategory), cl::ReallyHidden);
27a34c753fSRafael Auler } // namespace opts
28a34c753fSRafael Auler
29a34c753fSRafael Auler namespace llvm {
30a34c753fSRafael Auler namespace bolt {
31a34c753fSRafael Auler
runOnFunction(BinaryFunction & BF)32a34c753fSRafael Auler bool LoopInversionPass::runOnFunction(BinaryFunction &BF) {
33a34c753fSRafael Auler bool IsChanged = false;
348477bc67SFabian Parzefall if (BF.getLayout().block_size() < 3 || !BF.hasValidProfile())
35a34c753fSRafael Auler return false;
36a34c753fSRafael Auler
378477bc67SFabian Parzefall BF.getLayout().updateLayoutIndices();
388477bc67SFabian Parzefall for (BinaryBasicBlock *BB : BF.getLayout().blocks()) {
39a34c753fSRafael Auler if (BB->succ_size() != 1 || BB->pred_size() != 1)
40a34c753fSRafael Auler continue;
41a34c753fSRafael Auler
42a34c753fSRafael Auler BinaryBasicBlock *SuccBB = *BB->succ_begin();
43a34c753fSRafael Auler BinaryBasicBlock *PredBB = *BB->pred_begin();
44a34c753fSRafael Auler const unsigned BBIndex = BB->getLayoutIndex();
45a34c753fSRafael Auler const unsigned SuccBBIndex = SuccBB->getLayoutIndex();
46a34c753fSRafael Auler if (SuccBB == PredBB && BB != SuccBB && BBIndex != 0 && SuccBBIndex != 0 &&
4748ff38ceSFabian Parzefall SuccBB->succ_size() == 2 &&
4848ff38ceSFabian Parzefall BB->getFragmentNum() == SuccBB->getFragmentNum()) {
49a34c753fSRafael Auler // Get the second successor (after loop BB)
50a34c753fSRafael Auler BinaryBasicBlock *SecondSucc = nullptr;
51a34c753fSRafael Auler for (BinaryBasicBlock *Succ : SuccBB->successors()) {
52a34c753fSRafael Auler if (Succ != &*BB) {
53a34c753fSRafael Auler SecondSucc = Succ;
54a34c753fSRafael Auler break;
55a34c753fSRafael Auler }
56a34c753fSRafael Auler }
57a34c753fSRafael Auler
584609f60eSspupyrev assert(SecondSucc != nullptr && "Unable to find a second BB successor");
594609f60eSspupyrev const uint64_t LoopCount = SuccBB->getBranchInfo(*BB).Count;
604609f60eSspupyrev const uint64_t ExitCount = SuccBB->getBranchInfo(*SecondSucc).Count;
614609f60eSspupyrev
624609f60eSspupyrev if (LoopCount < ExitCount) {
634609f60eSspupyrev if (BBIndex > SuccBBIndex)
64a34c753fSRafael Auler continue;
654609f60eSspupyrev } else if (BBIndex < SuccBBIndex) {
664609f60eSspupyrev continue;
674609f60eSspupyrev }
68a34c753fSRafael Auler
69a34c753fSRafael Auler IsChanged = true;
70a34c753fSRafael Auler BB->setLayoutIndex(SuccBBIndex);
71a34c753fSRafael Auler SuccBB->setLayoutIndex(BBIndex);
72a34c753fSRafael Auler }
73a34c753fSRafael Auler }
74a34c753fSRafael Auler
75a34c753fSRafael Auler if (IsChanged) {
768477bc67SFabian Parzefall BinaryFunction::BasicBlockOrderType NewOrder(BF.getLayout().block_begin(),
778477bc67SFabian Parzefall BF.getLayout().block_end());
78d2c87699SAmir Ayupov llvm::sort(NewOrder, [&](BinaryBasicBlock *BB1, BinaryBasicBlock *BB2) {
79a34c753fSRafael Auler return BB1->getLayoutIndex() < BB2->getLayoutIndex();
80a34c753fSRafael Auler });
818477bc67SFabian Parzefall BF.getLayout().update(NewOrder);
82a34c753fSRafael Auler }
83a34c753fSRafael Auler
84a34c753fSRafael Auler return IsChanged;
85a34c753fSRafael Auler }
86a34c753fSRafael Auler
runOnFunctions(BinaryContext & BC)87a5f3d1a8SAmir Ayupov Error LoopInversionPass::runOnFunctions(BinaryContext &BC) {
88a34c753fSRafael Auler std::atomic<uint64_t> ModifiedFuncCount{0};
89a34c753fSRafael Auler if (opts::ReorderBlocks == ReorderBasicBlocks::LT_NONE ||
90a34c753fSRafael Auler opts::LoopReorder == false)
91a5f3d1a8SAmir Ayupov return Error::success();
92a34c753fSRafael Auler
93a34c753fSRafael Auler ParallelUtilities::WorkFuncTy WorkFun = [&](BinaryFunction &BF) {
94a34c753fSRafael Auler if (runOnFunction(BF))
95a34c753fSRafael Auler ++ModifiedFuncCount;
96a34c753fSRafael Auler };
97a34c753fSRafael Auler
98a34c753fSRafael Auler ParallelUtilities::PredicateTy SkipFunc = [&](const BinaryFunction &BF) {
99a34c753fSRafael Auler return !shouldOptimize(BF);
100a34c753fSRafael Auler };
101a34c753fSRafael Auler
102a34c753fSRafael Auler ParallelUtilities::runOnEachFunction(
103a34c753fSRafael Auler BC, ParallelUtilities::SchedulingPolicy::SP_TRIVIAL, WorkFun, SkipFunc,
104a34c753fSRafael Auler "LoopInversionPass");
105a34c753fSRafael Auler
106*52cf0711SAmir Ayupov BC.outs() << "BOLT-INFO: " << ModifiedFuncCount
107a34c753fSRafael Auler << " Functions were reordered by LoopInversionPass\n";
108a5f3d1a8SAmir Ayupov return Error::success();
109a34c753fSRafael Auler }
110a34c753fSRafael Auler
111a34c753fSRafael Auler } // end namespace bolt
112a34c753fSRafael Auler } // end namespace llvm
113