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
24using namespace llvm;
25
26#define DEBUG_TYPE "ppc-early-ret"
27STATISTIC(NumBCLR, "Number of early conditional returns");
28STATISTIC(NumBLR, "Number of early returns");
29
30namespace {
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
38 const TargetInstrInfo *TII;
39
40protected:
41 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(i: 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(Orig: &*I);
69 Pred->insert(I: 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(i: 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(Orig: &*I);
82 MI->setDesc(TII->get(Opcode: PPC::BCCLR));
83 MachineInstrBuilder(*ReturnMBB.getParent(), MI)
84 .add(MO: J->getOperand(i: 0))
85 .add(MO: J->getOperand(i: 1));
86 Pred->insert(I: 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(i: 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(Orig: &*I);
99 MI->setDesc(
100 TII->get(Opcode: J->getOpcode() == PPC::BC ? PPC::BCLR : PPC::BCLRn));
101 MachineInstrBuilder(*ReturnMBB.getParent(), MI)
102 .add(MO: J->getOperand(i: 0));
103 Pred->insert(I: 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(MBB: &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(Elt: Pred);
135 }
136
137 if (BlockChanged)
138 Changed = true;
139 }
140
141 for (MachineBasicBlock *MBB : PredToRemove)
142 MBB->removeSuccessor(Succ: &ReturnMBB, NormalizeSuccProbs: 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(MBB: &ReturnMBB) && PrevMBB.canFallThrough()) {
150 // Move the blr into the preceding block.
151 PrevMBB.splice(Where: PrevMBB.end(), Other: &ReturnMBB, From: I);
152 PrevMBB.removeSuccessor(Succ: &ReturnMBB, NormalizeSuccProbs: true);
153 }
154 }
155
156 if (ReturnMBB.pred_empty())
157 ReturnMBB.eraseFromParent();
158 }
159
160 return Changed;
161 }
162
163public:
164 bool runOnMachineFunction(MachineFunction &MF) override {
165 if (skipFunction(F: 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(Range&: MF))
178 Changed |= processBlock(ReturnMBB&: B);
179
180 return Changed;
181 }
182
183 MachineFunctionProperties getRequiredProperties() const override {
184 return MachineFunctionProperties().setNoVRegs();
185 }
186
187 void getAnalysisUsage(AnalysisUsage &AU) const override {
188 MachineFunctionPass::getAnalysisUsage(AU);
189 }
190 };
191}
192
193INITIALIZE_PASS(PPCEarlyReturn, DEBUG_TYPE,
194 "PowerPC Early-Return Creation", false, false)
195
196char PPCEarlyReturn::ID = 0;
197FunctionPass*
198llvm::createPPCEarlyReturnPass() { return new PPCEarlyReturn(); }
199