xref: /freebsd/contrib/llvm-project/llvm/lib/Target/PowerPC/PPCEarlyReturn.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
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;
PPCEarlyReturn__anoncdf4a6150111::PPCEarlyReturn36     PPCEarlyReturn() : MachineFunctionPass(ID) {}
37 
38     const TargetInstrInfo *TII;
39 
40 protected:
processBlock__anoncdf4a6150111::PPCEarlyReturn41     bool processBlock(MachineBasicBlock &ReturnMBB) {
42       bool Changed = false;
43 
44       MachineBasicBlock::iterator I = ReturnMBB.begin();
45       I = ReturnMBB.SkipPHIsLabelsAndDebug(I);
46 
47       // The block must be essentially empty except for the blr.
48       if (I == ReturnMBB.end() ||
49           (I->getOpcode() != PPC::BLR && I->getOpcode() != PPC::BLR8) ||
50           I != ReturnMBB.getLastNonDebugInstr())
51         return Changed;
52 
53       SmallVector<MachineBasicBlock*, 8> PredToRemove;
54       for (MachineBasicBlock *Pred : ReturnMBB.predecessors()) {
55         bool OtherReference = false, BlockChanged = false;
56 
57         if (Pred->empty())
58           continue;
59 
60         for (MachineBasicBlock::iterator J = Pred->getLastNonDebugInstr();;) {
61           if (J == Pred->end())
62             break;
63 
64           if (J->getOpcode() == PPC::B) {
65             if (J->getOperand(0).getMBB() == &ReturnMBB) {
66               // This is an unconditional branch to the return. Replace the
67               // branch with a blr.
68               MachineInstr *MI = ReturnMBB.getParent()->CloneMachineInstr(&*I);
69               Pred->insert(J, MI);
70 
71               MachineBasicBlock::iterator K = J--;
72               K->eraseFromParent();
73               BlockChanged = true;
74               ++NumBLR;
75               continue;
76             }
77           } else if (J->getOpcode() == PPC::BCC) {
78             if (J->getOperand(2).getMBB() == &ReturnMBB) {
79               // This is a conditional branch to the return. Replace the branch
80               // with a bclr.
81               MachineInstr *MI = ReturnMBB.getParent()->CloneMachineInstr(&*I);
82               MI->setDesc(TII->get(PPC::BCCLR));
83               MachineInstrBuilder(*ReturnMBB.getParent(), MI)
84                   .add(J->getOperand(0))
85                   .add(J->getOperand(1));
86               Pred->insert(J, MI);
87 
88               MachineBasicBlock::iterator K = J--;
89               K->eraseFromParent();
90               BlockChanged = true;
91               ++NumBCLR;
92               continue;
93             }
94           } else if (J->getOpcode() == PPC::BC || J->getOpcode() == PPC::BCn) {
95             if (J->getOperand(1).getMBB() == &ReturnMBB) {
96               // This is a conditional branch to the return. Replace the branch
97               // with a bclr.
98               MachineInstr *MI = ReturnMBB.getParent()->CloneMachineInstr(&*I);
99               MI->setDesc(
100                   TII->get(J->getOpcode() == PPC::BC ? PPC::BCLR : PPC::BCLRn));
101               MachineInstrBuilder(*ReturnMBB.getParent(), MI)
102                   .add(J->getOperand(0));
103               Pred->insert(J, MI);
104 
105               MachineBasicBlock::iterator K = J--;
106               K->eraseFromParent();
107               BlockChanged = true;
108               ++NumBCLR;
109               continue;
110             }
111           } else if (J->isBranch()) {
112             if (J->isIndirectBranch()) {
113               if (ReturnMBB.hasAddressTaken())
114                 OtherReference = true;
115             } else
116               for (unsigned i = 0; i < J->getNumOperands(); ++i)
117                 if (J->getOperand(i).isMBB() &&
118                     J->getOperand(i).getMBB() == &ReturnMBB)
119                   OtherReference = true;
120           } else if (!J->isTerminator() && !J->isDebugInstr())
121             break;
122 
123           if (J == Pred->begin())
124             break;
125 
126           --J;
127         }
128 
129         if (Pred->canFallThrough() && Pred->isLayoutSuccessor(&ReturnMBB))
130           OtherReference = true;
131 
132         // Predecessors are stored in a vector and can't be removed here.
133         if (!OtherReference && BlockChanged) {
134           PredToRemove.push_back(Pred);
135         }
136 
137         if (BlockChanged)
138           Changed = true;
139       }
140 
141       for (MachineBasicBlock *MBB : PredToRemove)
142         MBB->removeSuccessor(&ReturnMBB, true);
143 
144       if (Changed && !ReturnMBB.hasAddressTaken()) {
145         // We now might be able to merge this blr-only block into its
146         // by-layout predecessor.
147         if (ReturnMBB.pred_size() == 1) {
148           MachineBasicBlock &PrevMBB = **ReturnMBB.pred_begin();
149           if (PrevMBB.isLayoutSuccessor(&ReturnMBB) && PrevMBB.canFallThrough()) {
150             // Move the blr into the preceding block.
151             PrevMBB.splice(PrevMBB.end(), &ReturnMBB, I);
152             PrevMBB.removeSuccessor(&ReturnMBB, true);
153           }
154         }
155 
156         if (ReturnMBB.pred_empty())
157           ReturnMBB.eraseFromParent();
158       }
159 
160       return Changed;
161     }
162 
163 public:
runOnMachineFunction__anoncdf4a6150111::PPCEarlyReturn164     bool runOnMachineFunction(MachineFunction &MF) override {
165       if (skipFunction(MF.getFunction()))
166         return false;
167 
168       TII = MF.getSubtarget().getInstrInfo();
169 
170       bool Changed = false;
171 
172       // If the function does not have at least two blocks, then there is
173       // nothing to do.
174       if (MF.size() < 2)
175         return Changed;
176 
177       for (MachineBasicBlock &B : llvm::make_early_inc_range(MF))
178         Changed |= processBlock(B);
179 
180       return Changed;
181     }
182 
getRequiredProperties__anoncdf4a6150111::PPCEarlyReturn183     MachineFunctionProperties getRequiredProperties() const override {
184       return MachineFunctionProperties().setNoVRegs();
185     }
186 
getAnalysisUsage__anoncdf4a6150111::PPCEarlyReturn187     void getAnalysisUsage(AnalysisUsage &AU) const override {
188       MachineFunctionPass::getAnalysisUsage(AU);
189     }
190   };
191 }
192 
193 INITIALIZE_PASS(PPCEarlyReturn, DEBUG_TYPE,
194                 "PowerPC Early-Return Creation", false, false)
195 
196 char PPCEarlyReturn::ID = 0;
197 FunctionPass*
createPPCEarlyReturnPass()198 llvm::createPPCEarlyReturnPass() { return new PPCEarlyReturn(); }
199