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