xref: /llvm-project/llvm/lib/Target/PowerPC/PPCEarlyReturn.cpp (revision f71cb9dbb739bb58ce7e52e49fe384ff2ff11687)
1 //===------------- PPCEarlyReturn.cpp - Form Early Returns ----------------===//
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 // A pass that form early (predicated) returns. If-conversion handles some of
10 // this, but this pass picks up some remaining cases.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "PPC.h"
15 #include "PPCInstrInfo.h"
16 #include "llvm/ADT/STLExtras.h"
17 #include "llvm/ADT/Statistic.h"
18 #include "llvm/CodeGen/MachineFrameInfo.h"
19 #include "llvm/CodeGen/MachineFunctionPass.h"
20 #include "llvm/CodeGen/MachineInstrBuilder.h"
21 #include "llvm/CodeGen/MachineMemOperand.h"
22 #include "llvm/Support/ErrorHandling.h"
23 
24 using namespace llvm;
25 
26 #define DEBUG_TYPE "ppc-early-ret"
27 STATISTIC(NumBCLR, "Number of early conditional returns");
28 STATISTIC(NumBLR,  "Number of early returns");
29 
30 namespace {
31   // PPCEarlyReturn pass - For simple functions without epilogue code, move
32   // returns up, and create conditional returns, to avoid unnecessary
33   // branch-to-blr sequences.
34   struct PPCEarlyReturn : public MachineFunctionPass {
35     static char ID;
36     PPCEarlyReturn() : MachineFunctionPass(ID) {
37       initializePPCEarlyReturnPass(*PassRegistry::getPassRegistry());
38     }
39 
40     const TargetInstrInfo *TII;
41 
42 protected:
43     bool processBlock(MachineBasicBlock &ReturnMBB) {
44       bool Changed = false;
45 
46       MachineBasicBlock::iterator I = ReturnMBB.begin();
47       I = ReturnMBB.SkipPHIsLabelsAndDebug(I);
48 
49       // The block must be essentially empty except for the blr.
50       if (I == ReturnMBB.end() ||
51           (I->getOpcode() != PPC::BLR && I->getOpcode() != PPC::BLR8) ||
52           I != ReturnMBB.getLastNonDebugInstr())
53         return Changed;
54 
55       SmallVector<MachineBasicBlock*, 8> PredToRemove;
56       for (MachineBasicBlock *Pred : ReturnMBB.predecessors()) {
57         bool OtherReference = false, BlockChanged = false;
58 
59         if (Pred->empty())
60           continue;
61 
62         for (MachineBasicBlock::iterator J = Pred->getLastNonDebugInstr();;) {
63           if (J == Pred->end())
64             break;
65 
66           if (J->getOpcode() == PPC::B) {
67             if (J->getOperand(0).getMBB() == &ReturnMBB) {
68               // This is an unconditional branch to the return. Replace the
69               // branch with a blr.
70               MachineInstr *MI = ReturnMBB.getParent()->CloneMachineInstr(&*I);
71               Pred->insert(J, MI);
72 
73               MachineBasicBlock::iterator K = J--;
74               K->eraseFromParent();
75               BlockChanged = true;
76               ++NumBLR;
77               continue;
78             }
79           } else if (J->getOpcode() == PPC::BCC) {
80             if (J->getOperand(2).getMBB() == &ReturnMBB) {
81               // This is a conditional branch to the return. Replace the branch
82               // with a bclr.
83               MachineInstr *MI = ReturnMBB.getParent()->CloneMachineInstr(&*I);
84               MI->setDesc(TII->get(PPC::BCCLR));
85               MachineInstrBuilder(*ReturnMBB.getParent(), MI)
86                   .add(J->getOperand(0))
87                   .add(J->getOperand(1));
88               Pred->insert(J, MI);
89 
90               MachineBasicBlock::iterator K = J--;
91               K->eraseFromParent();
92               BlockChanged = true;
93               ++NumBCLR;
94               continue;
95             }
96           } else if (J->getOpcode() == PPC::BC || J->getOpcode() == PPC::BCn) {
97             if (J->getOperand(1).getMBB() == &ReturnMBB) {
98               // This is a conditional branch to the return. Replace the branch
99               // with a bclr.
100               MachineInstr *MI = ReturnMBB.getParent()->CloneMachineInstr(&*I);
101               MI->setDesc(
102                   TII->get(J->getOpcode() == PPC::BC ? PPC::BCLR : PPC::BCLRn));
103               MachineInstrBuilder(*ReturnMBB.getParent(), MI)
104                   .add(J->getOperand(0));
105               Pred->insert(J, MI);
106 
107               MachineBasicBlock::iterator K = J--;
108               K->eraseFromParent();
109               BlockChanged = true;
110               ++NumBCLR;
111               continue;
112             }
113           } else if (J->isBranch()) {
114             if (J->isIndirectBranch()) {
115               if (ReturnMBB.hasAddressTaken())
116                 OtherReference = true;
117             } else
118               for (unsigned i = 0; i < J->getNumOperands(); ++i)
119                 if (J->getOperand(i).isMBB() &&
120                     J->getOperand(i).getMBB() == &ReturnMBB)
121                   OtherReference = true;
122           } else if (!J->isTerminator() && !J->isDebugInstr())
123             break;
124 
125           if (J == Pred->begin())
126             break;
127 
128           --J;
129         }
130 
131         if (Pred->canFallThrough() && Pred->isLayoutSuccessor(&ReturnMBB))
132           OtherReference = true;
133 
134         // Predecessors are stored in a vector and can't be removed here.
135         if (!OtherReference && BlockChanged) {
136           PredToRemove.push_back(Pred);
137         }
138 
139         if (BlockChanged)
140           Changed = true;
141       }
142 
143       for (MachineBasicBlock *MBB : PredToRemove)
144         MBB->removeSuccessor(&ReturnMBB, true);
145 
146       if (Changed && !ReturnMBB.hasAddressTaken()) {
147         // We now might be able to merge this blr-only block into its
148         // by-layout predecessor.
149         if (ReturnMBB.pred_size() == 1) {
150           MachineBasicBlock &PrevMBB = **ReturnMBB.pred_begin();
151           if (PrevMBB.isLayoutSuccessor(&ReturnMBB) && PrevMBB.canFallThrough()) {
152             // Move the blr into the preceding block.
153             PrevMBB.splice(PrevMBB.end(), &ReturnMBB, I);
154             PrevMBB.removeSuccessor(&ReturnMBB, true);
155           }
156         }
157 
158         if (ReturnMBB.pred_empty())
159           ReturnMBB.eraseFromParent();
160       }
161 
162       return Changed;
163     }
164 
165 public:
166     bool runOnMachineFunction(MachineFunction &MF) override {
167       if (skipFunction(MF.getFunction()))
168         return false;
169 
170       TII = MF.getSubtarget().getInstrInfo();
171 
172       bool Changed = false;
173 
174       // If the function does not have at least two blocks, then there is
175       // nothing to do.
176       if (MF.size() < 2)
177         return Changed;
178 
179       for (MachineBasicBlock &B : llvm::make_early_inc_range(MF))
180         Changed |= processBlock(B);
181 
182       return Changed;
183     }
184 
185     MachineFunctionProperties getRequiredProperties() const override {
186       return MachineFunctionProperties().set(
187           MachineFunctionProperties::Property::NoVRegs);
188     }
189 
190     void getAnalysisUsage(AnalysisUsage &AU) const override {
191       MachineFunctionPass::getAnalysisUsage(AU);
192     }
193   };
194 }
195 
196 INITIALIZE_PASS(PPCEarlyReturn, DEBUG_TYPE,
197                 "PowerPC Early-Return Creation", false, false)
198 
199 char PPCEarlyReturn::ID = 0;
200 FunctionPass*
201 llvm::createPPCEarlyReturnPass() { return new PPCEarlyReturn(); }
202