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