xref: /llvm-project/bolt/lib/Passes/LoopInversionPass.cpp (revision 52cf07116bf0a8cab87b0f55176d198bcaa02575)
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