AMDGPU: Mark test as XFAIL in expensive_checks builds
[llvm-project.git] / llvm / lib / Target / PowerPC / PPCEarlyReturn.cpp
blobcc4bed7b3dde2ae47f7d6b3a459c21195cbe749a
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.
12 //===----------------------------------------------------------------------===//
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"
24 using namespace llvm;
26 #define DEBUG_TYPE "ppc-early-ret"
27 STATISTIC(NumBCLR, "Number of early conditional returns");
28 STATISTIC(NumBLR, "Number of early returns");
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());
40 const TargetInstrInfo *TII;
42 protected:
43 bool processBlock(MachineBasicBlock &ReturnMBB) {
44 bool Changed = false;
46 MachineBasicBlock::iterator I = ReturnMBB.begin();
47 I = ReturnMBB.SkipPHIsLabelsAndDebug(I);
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;
55 SmallVector<MachineBasicBlock*, 8> PredToRemove;
56 for (MachineBasicBlock *Pred : ReturnMBB.predecessors()) {
57 bool OtherReference = false, BlockChanged = false;
59 if (Pred->empty())
60 continue;
62 for (MachineBasicBlock::iterator J = Pred->getLastNonDebugInstr();;) {
63 if (J == Pred->end())
64 break;
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);
73 MachineBasicBlock::iterator K = J--;
74 K->eraseFromParent();
75 BlockChanged = true;
76 ++NumBLR;
77 continue;
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);
90 MachineBasicBlock::iterator K = J--;
91 K->eraseFromParent();
92 BlockChanged = true;
93 ++NumBCLR;
94 continue;
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);
107 MachineBasicBlock::iterator K = J--;
108 K->eraseFromParent();
109 BlockChanged = true;
110 ++NumBCLR;
111 continue;
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;
125 if (J == Pred->begin())
126 break;
128 --J;
131 if (Pred->canFallThrough() && Pred->isLayoutSuccessor(&ReturnMBB))
132 OtherReference = true;
134 // Predecessors are stored in a vector and can't be removed here.
135 if (!OtherReference && BlockChanged) {
136 PredToRemove.push_back(Pred);
139 if (BlockChanged)
140 Changed = true;
143 for (MachineBasicBlock *MBB : PredToRemove)
144 MBB->removeSuccessor(&ReturnMBB, true);
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);
158 if (ReturnMBB.pred_empty())
159 ReturnMBB.eraseFromParent();
162 return Changed;
165 public:
166 bool runOnMachineFunction(MachineFunction &MF) override {
167 if (skipFunction(MF.getFunction()))
168 return false;
170 TII = MF.getSubtarget().getInstrInfo();
172 bool Changed = false;
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;
179 for (MachineBasicBlock &B : llvm::make_early_inc_range(MF))
180 Changed |= processBlock(B);
182 return Changed;
185 MachineFunctionProperties getRequiredProperties() const override {
186 return MachineFunctionProperties().set(
187 MachineFunctionProperties::Property::NoVRegs);
190 void getAnalysisUsage(AnalysisUsage &AU) const override {
191 MachineFunctionPass::getAnalysisUsage(AU);
196 INITIALIZE_PASS(PPCEarlyReturn, DEBUG_TYPE,
197 "PowerPC Early-Return Creation", false, false)
199 char PPCEarlyReturn::ID = 0;
200 FunctionPass*
201 llvm::createPPCEarlyReturnPass() { return new PPCEarlyReturn(); }