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;
34*8477bc67SFabian Parzefall if (BF.getLayout().block_size() < 3 || !BF.hasValidProfile())
35a34c753fSRafael Auler return false;
36a34c753fSRafael Auler
37*8477bc67SFabian Parzefall BF.getLayout().updateLayoutIndices();
38*8477bc67SFabian 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 &&
47a34c753fSRafael Auler SuccBB->succ_size() == 2 && BB->isCold() == SuccBB->isCold()) {
48a34c753fSRafael Auler // Get the second successor (after loop BB)
49a34c753fSRafael Auler BinaryBasicBlock *SecondSucc = nullptr;
50a34c753fSRafael Auler for (BinaryBasicBlock *Succ : SuccBB->successors()) {
51a34c753fSRafael Auler if (Succ != &*BB) {
52a34c753fSRafael Auler SecondSucc = Succ;
53a34c753fSRafael Auler break;
54a34c753fSRafael Auler }
55a34c753fSRafael Auler }
56a34c753fSRafael Auler
574609f60eSspupyrev assert(SecondSucc != nullptr && "Unable to find a second BB successor");
584609f60eSspupyrev const uint64_t LoopCount = SuccBB->getBranchInfo(*BB).Count;
594609f60eSspupyrev const uint64_t ExitCount = SuccBB->getBranchInfo(*SecondSucc).Count;
604609f60eSspupyrev
614609f60eSspupyrev if (LoopCount < ExitCount) {
624609f60eSspupyrev if (BBIndex > SuccBBIndex)
63a34c753fSRafael Auler continue;
644609f60eSspupyrev } else if (BBIndex < SuccBBIndex) {
654609f60eSspupyrev continue;
664609f60eSspupyrev }
67a34c753fSRafael Auler
68a34c753fSRafael Auler IsChanged = true;
69a34c753fSRafael Auler BB->setLayoutIndex(SuccBBIndex);
70a34c753fSRafael Auler SuccBB->setLayoutIndex(BBIndex);
71a34c753fSRafael Auler }
72a34c753fSRafael Auler }
73a34c753fSRafael Auler
74a34c753fSRafael Auler if (IsChanged) {
75*8477bc67SFabian Parzefall BinaryFunction::BasicBlockOrderType NewOrder(BF.getLayout().block_begin(),
76*8477bc67SFabian Parzefall BF.getLayout().block_end());
77d2c87699SAmir Ayupov llvm::sort(NewOrder, [&](BinaryBasicBlock *BB1, BinaryBasicBlock *BB2) {
78a34c753fSRafael Auler return BB1->getLayoutIndex() < BB2->getLayoutIndex();
79a34c753fSRafael Auler });
80*8477bc67SFabian Parzefall BF.getLayout().update(NewOrder);
81a34c753fSRafael Auler }
82a34c753fSRafael Auler
83a34c753fSRafael Auler return IsChanged;
84a34c753fSRafael Auler }
85a34c753fSRafael Auler
runOnFunctions(BinaryContext & BC)86a34c753fSRafael Auler void LoopInversionPass::runOnFunctions(BinaryContext &BC) {
87a34c753fSRafael Auler std::atomic<uint64_t> ModifiedFuncCount{0};
88a34c753fSRafael Auler if (opts::ReorderBlocks == ReorderBasicBlocks::LT_NONE ||
89a34c753fSRafael Auler opts::LoopReorder == false)
90a34c753fSRafael Auler return;
91a34c753fSRafael Auler
92a34c753fSRafael Auler ParallelUtilities::WorkFuncTy WorkFun = [&](BinaryFunction &BF) {
93a34c753fSRafael Auler if (runOnFunction(BF))
94a34c753fSRafael Auler ++ModifiedFuncCount;
95a34c753fSRafael Auler };
96a34c753fSRafael Auler
97a34c753fSRafael Auler ParallelUtilities::PredicateTy SkipFunc = [&](const BinaryFunction &BF) {
98a34c753fSRafael Auler return !shouldOptimize(BF);
99a34c753fSRafael Auler };
100a34c753fSRafael Auler
101a34c753fSRafael Auler ParallelUtilities::runOnEachFunction(
102a34c753fSRafael Auler BC, ParallelUtilities::SchedulingPolicy::SP_TRIVIAL, WorkFun, SkipFunc,
103a34c753fSRafael Auler "LoopInversionPass");
104a34c753fSRafael Auler
105a34c753fSRafael Auler outs() << "BOLT-INFO: " << ModifiedFuncCount
106a34c753fSRafael Auler << " Functions were reordered by LoopInversionPass\n";
107a34c753fSRafael Auler }
108a34c753fSRafael Auler
109a34c753fSRafael Auler } // end namespace bolt
110a34c753fSRafael Auler } // end namespace llvm
111