xref: /freebsd/contrib/llvm-project/llvm/lib/Target/Hexagon/HexagonCFGOptimizer.cpp (revision 0b57cec536236d46e3dba9bd041533462f33dbb7)
1*0b57cec5SDimitry Andric //===- HexagonCFGOptimizer.cpp - CFG optimizations ------------------------===//
2*0b57cec5SDimitry Andric //
3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric //
7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric 
9*0b57cec5SDimitry Andric #include "Hexagon.h"
10*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineBasicBlock.h"
11*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineBranchProbabilityInfo.h"
12*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunction.h"
13*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h"
14*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstr.h"
15*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineOperand.h"
16*0b57cec5SDimitry Andric #include "llvm/CodeGen/TargetInstrInfo.h"
17*0b57cec5SDimitry Andric #include "llvm/CodeGen/TargetSubtargetInfo.h"
18*0b57cec5SDimitry Andric #include "llvm/Pass.h"
19*0b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h"
20*0b57cec5SDimitry Andric #include <cassert>
21*0b57cec5SDimitry Andric #include <vector>
22*0b57cec5SDimitry Andric 
23*0b57cec5SDimitry Andric using namespace llvm;
24*0b57cec5SDimitry Andric 
25*0b57cec5SDimitry Andric #define DEBUG_TYPE "hexagon_cfg"
26*0b57cec5SDimitry Andric 
27*0b57cec5SDimitry Andric namespace llvm {
28*0b57cec5SDimitry Andric 
29*0b57cec5SDimitry Andric FunctionPass *createHexagonCFGOptimizer();
30*0b57cec5SDimitry Andric void initializeHexagonCFGOptimizerPass(PassRegistry&);
31*0b57cec5SDimitry Andric 
32*0b57cec5SDimitry Andric } // end namespace llvm
33*0b57cec5SDimitry Andric 
34*0b57cec5SDimitry Andric namespace {
35*0b57cec5SDimitry Andric 
36*0b57cec5SDimitry Andric class HexagonCFGOptimizer : public MachineFunctionPass {
37*0b57cec5SDimitry Andric private:
38*0b57cec5SDimitry Andric   void InvertAndChangeJumpTarget(MachineInstr &, MachineBasicBlock *);
39*0b57cec5SDimitry Andric   bool isOnFallThroughPath(MachineBasicBlock *MBB);
40*0b57cec5SDimitry Andric 
41*0b57cec5SDimitry Andric public:
42*0b57cec5SDimitry Andric   static char ID;
43*0b57cec5SDimitry Andric 
44*0b57cec5SDimitry Andric   HexagonCFGOptimizer() : MachineFunctionPass(ID) {
45*0b57cec5SDimitry Andric     initializeHexagonCFGOptimizerPass(*PassRegistry::getPassRegistry());
46*0b57cec5SDimitry Andric   }
47*0b57cec5SDimitry Andric 
48*0b57cec5SDimitry Andric   StringRef getPassName() const override { return "Hexagon CFG Optimizer"; }
49*0b57cec5SDimitry Andric   bool runOnMachineFunction(MachineFunction &Fn) override;
50*0b57cec5SDimitry Andric 
51*0b57cec5SDimitry Andric   MachineFunctionProperties getRequiredProperties() const override {
52*0b57cec5SDimitry Andric     return MachineFunctionProperties().set(
53*0b57cec5SDimitry Andric         MachineFunctionProperties::Property::NoVRegs);
54*0b57cec5SDimitry Andric   }
55*0b57cec5SDimitry Andric };
56*0b57cec5SDimitry Andric 
57*0b57cec5SDimitry Andric } // end anonymous namespace
58*0b57cec5SDimitry Andric 
59*0b57cec5SDimitry Andric char HexagonCFGOptimizer::ID = 0;
60*0b57cec5SDimitry Andric 
61*0b57cec5SDimitry Andric static bool IsConditionalBranch(int Opc) {
62*0b57cec5SDimitry Andric   switch (Opc) {
63*0b57cec5SDimitry Andric     case Hexagon::J2_jumpt:
64*0b57cec5SDimitry Andric     case Hexagon::J2_jumptpt:
65*0b57cec5SDimitry Andric     case Hexagon::J2_jumpf:
66*0b57cec5SDimitry Andric     case Hexagon::J2_jumpfpt:
67*0b57cec5SDimitry Andric     case Hexagon::J2_jumptnew:
68*0b57cec5SDimitry Andric     case Hexagon::J2_jumpfnew:
69*0b57cec5SDimitry Andric     case Hexagon::J2_jumptnewpt:
70*0b57cec5SDimitry Andric     case Hexagon::J2_jumpfnewpt:
71*0b57cec5SDimitry Andric       return true;
72*0b57cec5SDimitry Andric   }
73*0b57cec5SDimitry Andric   return false;
74*0b57cec5SDimitry Andric }
75*0b57cec5SDimitry Andric 
76*0b57cec5SDimitry Andric static bool IsUnconditionalJump(int Opc) {
77*0b57cec5SDimitry Andric   return (Opc == Hexagon::J2_jump);
78*0b57cec5SDimitry Andric }
79*0b57cec5SDimitry Andric 
80*0b57cec5SDimitry Andric void HexagonCFGOptimizer::InvertAndChangeJumpTarget(
81*0b57cec5SDimitry Andric     MachineInstr &MI, MachineBasicBlock *NewTarget) {
82*0b57cec5SDimitry Andric   const TargetInstrInfo *TII =
83*0b57cec5SDimitry Andric       MI.getParent()->getParent()->getSubtarget().getInstrInfo();
84*0b57cec5SDimitry Andric   int NewOpcode = 0;
85*0b57cec5SDimitry Andric   switch (MI.getOpcode()) {
86*0b57cec5SDimitry Andric   case Hexagon::J2_jumpt:
87*0b57cec5SDimitry Andric     NewOpcode = Hexagon::J2_jumpf;
88*0b57cec5SDimitry Andric     break;
89*0b57cec5SDimitry Andric   case Hexagon::J2_jumpf:
90*0b57cec5SDimitry Andric     NewOpcode = Hexagon::J2_jumpt;
91*0b57cec5SDimitry Andric     break;
92*0b57cec5SDimitry Andric   case Hexagon::J2_jumptnewpt:
93*0b57cec5SDimitry Andric     NewOpcode = Hexagon::J2_jumpfnewpt;
94*0b57cec5SDimitry Andric     break;
95*0b57cec5SDimitry Andric   case Hexagon::J2_jumpfnewpt:
96*0b57cec5SDimitry Andric     NewOpcode = Hexagon::J2_jumptnewpt;
97*0b57cec5SDimitry Andric     break;
98*0b57cec5SDimitry Andric   default:
99*0b57cec5SDimitry Andric     llvm_unreachable("Cannot handle this case");
100*0b57cec5SDimitry Andric   }
101*0b57cec5SDimitry Andric 
102*0b57cec5SDimitry Andric   MI.setDesc(TII->get(NewOpcode));
103*0b57cec5SDimitry Andric   MI.getOperand(1).setMBB(NewTarget);
104*0b57cec5SDimitry Andric }
105*0b57cec5SDimitry Andric 
106*0b57cec5SDimitry Andric bool HexagonCFGOptimizer::isOnFallThroughPath(MachineBasicBlock *MBB) {
107*0b57cec5SDimitry Andric   if (MBB->canFallThrough())
108*0b57cec5SDimitry Andric     return true;
109*0b57cec5SDimitry Andric   for (MachineBasicBlock *PB : MBB->predecessors())
110*0b57cec5SDimitry Andric     if (PB->isLayoutSuccessor(MBB) && PB->canFallThrough())
111*0b57cec5SDimitry Andric       return true;
112*0b57cec5SDimitry Andric   return false;
113*0b57cec5SDimitry Andric }
114*0b57cec5SDimitry Andric 
115*0b57cec5SDimitry Andric bool HexagonCFGOptimizer::runOnMachineFunction(MachineFunction &Fn) {
116*0b57cec5SDimitry Andric   if (skipFunction(Fn.getFunction()))
117*0b57cec5SDimitry Andric     return false;
118*0b57cec5SDimitry Andric 
119*0b57cec5SDimitry Andric   // Loop over all of the basic blocks.
120*0b57cec5SDimitry Andric   for (MachineFunction::iterator MBBb = Fn.begin(), MBBe = Fn.end();
121*0b57cec5SDimitry Andric        MBBb != MBBe; ++MBBb) {
122*0b57cec5SDimitry Andric     MachineBasicBlock *MBB = &*MBBb;
123*0b57cec5SDimitry Andric 
124*0b57cec5SDimitry Andric     // Traverse the basic block.
125*0b57cec5SDimitry Andric     MachineBasicBlock::iterator MII = MBB->getFirstTerminator();
126*0b57cec5SDimitry Andric     if (MII != MBB->end()) {
127*0b57cec5SDimitry Andric       MachineInstr &MI = *MII;
128*0b57cec5SDimitry Andric       int Opc = MI.getOpcode();
129*0b57cec5SDimitry Andric       if (IsConditionalBranch(Opc)) {
130*0b57cec5SDimitry Andric         // (Case 1) Transform the code if the following condition occurs:
131*0b57cec5SDimitry Andric         //   BB1: if (p0) jump BB3
132*0b57cec5SDimitry Andric         //   ...falls-through to BB2 ...
133*0b57cec5SDimitry Andric         //   BB2: jump BB4
134*0b57cec5SDimitry Andric         //   ...next block in layout is BB3...
135*0b57cec5SDimitry Andric         //   BB3: ...
136*0b57cec5SDimitry Andric         //
137*0b57cec5SDimitry Andric         //  Transform this to:
138*0b57cec5SDimitry Andric         //  BB1: if (!p0) jump BB4
139*0b57cec5SDimitry Andric         //  Remove BB2
140*0b57cec5SDimitry Andric         //  BB3: ...
141*0b57cec5SDimitry Andric         //
142*0b57cec5SDimitry Andric         // (Case 2) A variation occurs when BB3 contains a JMP to BB4:
143*0b57cec5SDimitry Andric         //   BB1: if (p0) jump BB3
144*0b57cec5SDimitry Andric         //   ...falls-through to BB2 ...
145*0b57cec5SDimitry Andric         //   BB2: jump BB4
146*0b57cec5SDimitry Andric         //   ...other basic blocks ...
147*0b57cec5SDimitry Andric         //   BB4:
148*0b57cec5SDimitry Andric         //   ...not a fall-thru
149*0b57cec5SDimitry Andric         //   BB3: ...
150*0b57cec5SDimitry Andric         //     jump BB4
151*0b57cec5SDimitry Andric         //
152*0b57cec5SDimitry Andric         // Transform this to:
153*0b57cec5SDimitry Andric         //   BB1: if (!p0) jump BB4
154*0b57cec5SDimitry Andric         //   Remove BB2
155*0b57cec5SDimitry Andric         //   BB3: ...
156*0b57cec5SDimitry Andric         //   BB4: ...
157*0b57cec5SDimitry Andric         unsigned NumSuccs = MBB->succ_size();
158*0b57cec5SDimitry Andric         MachineBasicBlock::succ_iterator SI = MBB->succ_begin();
159*0b57cec5SDimitry Andric         MachineBasicBlock* FirstSucc = *SI;
160*0b57cec5SDimitry Andric         MachineBasicBlock* SecondSucc = *(++SI);
161*0b57cec5SDimitry Andric         MachineBasicBlock* LayoutSucc = nullptr;
162*0b57cec5SDimitry Andric         MachineBasicBlock* JumpAroundTarget = nullptr;
163*0b57cec5SDimitry Andric 
164*0b57cec5SDimitry Andric         if (MBB->isLayoutSuccessor(FirstSucc)) {
165*0b57cec5SDimitry Andric           LayoutSucc = FirstSucc;
166*0b57cec5SDimitry Andric           JumpAroundTarget = SecondSucc;
167*0b57cec5SDimitry Andric         } else if (MBB->isLayoutSuccessor(SecondSucc)) {
168*0b57cec5SDimitry Andric           LayoutSucc = SecondSucc;
169*0b57cec5SDimitry Andric           JumpAroundTarget = FirstSucc;
170*0b57cec5SDimitry Andric         } else {
171*0b57cec5SDimitry Andric           // Odd case...cannot handle.
172*0b57cec5SDimitry Andric         }
173*0b57cec5SDimitry Andric 
174*0b57cec5SDimitry Andric         // The target of the unconditional branch must be JumpAroundTarget.
175*0b57cec5SDimitry Andric         // TODO: If not, we should not invert the unconditional branch.
176*0b57cec5SDimitry Andric         MachineBasicBlock* CondBranchTarget = nullptr;
177*0b57cec5SDimitry Andric         if (MI.getOpcode() == Hexagon::J2_jumpt ||
178*0b57cec5SDimitry Andric             MI.getOpcode() == Hexagon::J2_jumpf) {
179*0b57cec5SDimitry Andric           CondBranchTarget = MI.getOperand(1).getMBB();
180*0b57cec5SDimitry Andric         }
181*0b57cec5SDimitry Andric 
182*0b57cec5SDimitry Andric         if (!LayoutSucc || (CondBranchTarget != JumpAroundTarget)) {
183*0b57cec5SDimitry Andric           continue;
184*0b57cec5SDimitry Andric         }
185*0b57cec5SDimitry Andric 
186*0b57cec5SDimitry Andric         if ((NumSuccs == 2) && LayoutSucc && (LayoutSucc->pred_size() == 1)) {
187*0b57cec5SDimitry Andric           // Ensure that BB2 has one instruction -- an unconditional jump.
188*0b57cec5SDimitry Andric           if ((LayoutSucc->size() == 1) &&
189*0b57cec5SDimitry Andric               IsUnconditionalJump(LayoutSucc->front().getOpcode())) {
190*0b57cec5SDimitry Andric             assert(JumpAroundTarget && "jump target is needed to process second basic block");
191*0b57cec5SDimitry Andric             MachineBasicBlock* UncondTarget =
192*0b57cec5SDimitry Andric               LayoutSucc->front().getOperand(0).getMBB();
193*0b57cec5SDimitry Andric             // Check if the layout successor of BB2 is BB3.
194*0b57cec5SDimitry Andric             bool case1 = LayoutSucc->isLayoutSuccessor(JumpAroundTarget);
195*0b57cec5SDimitry Andric             bool case2 = JumpAroundTarget->isSuccessor(UncondTarget) &&
196*0b57cec5SDimitry Andric               !JumpAroundTarget->empty() &&
197*0b57cec5SDimitry Andric               IsUnconditionalJump(JumpAroundTarget->back().getOpcode()) &&
198*0b57cec5SDimitry Andric               JumpAroundTarget->pred_size() == 1 &&
199*0b57cec5SDimitry Andric               JumpAroundTarget->succ_size() == 1;
200*0b57cec5SDimitry Andric 
201*0b57cec5SDimitry Andric             if (case1 || case2) {
202*0b57cec5SDimitry Andric               InvertAndChangeJumpTarget(MI, UncondTarget);
203*0b57cec5SDimitry Andric               MBB->replaceSuccessor(JumpAroundTarget, UncondTarget);
204*0b57cec5SDimitry Andric 
205*0b57cec5SDimitry Andric               // Remove the unconditional branch in LayoutSucc.
206*0b57cec5SDimitry Andric               LayoutSucc->erase(LayoutSucc->begin());
207*0b57cec5SDimitry Andric               LayoutSucc->replaceSuccessor(UncondTarget, JumpAroundTarget);
208*0b57cec5SDimitry Andric 
209*0b57cec5SDimitry Andric               // This code performs the conversion for case 2, which moves
210*0b57cec5SDimitry Andric               // the block to the fall-thru case (BB3 in the code above).
211*0b57cec5SDimitry Andric               if (case2 && !case1) {
212*0b57cec5SDimitry Andric                 JumpAroundTarget->moveAfter(LayoutSucc);
213*0b57cec5SDimitry Andric                 // only move a block if it doesn't have a fall-thru. otherwise
214*0b57cec5SDimitry Andric                 // the CFG will be incorrect.
215*0b57cec5SDimitry Andric                 if (!isOnFallThroughPath(UncondTarget))
216*0b57cec5SDimitry Andric                   UncondTarget->moveAfter(JumpAroundTarget);
217*0b57cec5SDimitry Andric               }
218*0b57cec5SDimitry Andric 
219*0b57cec5SDimitry Andric               // Correct live-in information. Is used by post-RA scheduler
220*0b57cec5SDimitry Andric               // The live-in to LayoutSucc is now all values live-in to
221*0b57cec5SDimitry Andric               // JumpAroundTarget.
222*0b57cec5SDimitry Andric               std::vector<MachineBasicBlock::RegisterMaskPair> OrigLiveIn(
223*0b57cec5SDimitry Andric                   LayoutSucc->livein_begin(), LayoutSucc->livein_end());
224*0b57cec5SDimitry Andric               std::vector<MachineBasicBlock::RegisterMaskPair> NewLiveIn(
225*0b57cec5SDimitry Andric                   JumpAroundTarget->livein_begin(),
226*0b57cec5SDimitry Andric                   JumpAroundTarget->livein_end());
227*0b57cec5SDimitry Andric               for (const auto &OrigLI : OrigLiveIn)
228*0b57cec5SDimitry Andric                 LayoutSucc->removeLiveIn(OrigLI.PhysReg);
229*0b57cec5SDimitry Andric               for (const auto &NewLI : NewLiveIn)
230*0b57cec5SDimitry Andric                 LayoutSucc->addLiveIn(NewLI);
231*0b57cec5SDimitry Andric             }
232*0b57cec5SDimitry Andric           }
233*0b57cec5SDimitry Andric         }
234*0b57cec5SDimitry Andric       }
235*0b57cec5SDimitry Andric     }
236*0b57cec5SDimitry Andric   }
237*0b57cec5SDimitry Andric   return true;
238*0b57cec5SDimitry Andric }
239*0b57cec5SDimitry Andric 
240*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
241*0b57cec5SDimitry Andric //                         Public Constructor Functions
242*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
243*0b57cec5SDimitry Andric 
244*0b57cec5SDimitry Andric INITIALIZE_PASS(HexagonCFGOptimizer, "hexagon-cfg", "Hexagon CFG Optimizer",
245*0b57cec5SDimitry Andric                 false, false)
246*0b57cec5SDimitry Andric 
247*0b57cec5SDimitry Andric FunctionPass *llvm::createHexagonCFGOptimizer() {
248*0b57cec5SDimitry Andric   return new HexagonCFGOptimizer();
249*0b57cec5SDimitry Andric }
250