123a3eab6SHal Finkel //===------------- PPCEarlyReturn.cpp - Form Early Returns ----------------===//
223a3eab6SHal Finkel //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
623a3eab6SHal Finkel //
723a3eab6SHal Finkel //===----------------------------------------------------------------------===//
823a3eab6SHal Finkel //
923a3eab6SHal Finkel // A pass that form early (predicated) returns. If-conversion handles some of
1023a3eab6SHal Finkel // this, but this pass picks up some remaining cases.
1123a3eab6SHal Finkel //
1223a3eab6SHal Finkel //===----------------------------------------------------------------------===//
1323a3eab6SHal Finkel
14b550cb17SMehdi Amini #include "MCTargetDesc/PPCPredicates.h"
156bda14b3SChandler Carruth #include "PPC.h"
1623a3eab6SHal Finkel #include "PPCInstrBuilder.h"
17b550cb17SMehdi Amini #include "PPCInstrInfo.h"
1823a3eab6SHal Finkel #include "PPCMachineFunctionInfo.h"
1923a3eab6SHal Finkel #include "PPCTargetMachine.h"
2023a3eab6SHal Finkel #include "llvm/ADT/STLExtras.h"
2123a3eab6SHal Finkel #include "llvm/ADT/Statistic.h"
2223a3eab6SHal Finkel #include "llvm/CodeGen/MachineFrameInfo.h"
2323a3eab6SHal Finkel #include "llvm/CodeGen/MachineFunctionPass.h"
2423a3eab6SHal Finkel #include "llvm/CodeGen/MachineInstrBuilder.h"
2523a3eab6SHal Finkel #include "llvm/CodeGen/MachineMemOperand.h"
2623a3eab6SHal Finkel #include "llvm/CodeGen/MachineRegisterInfo.h"
2723a3eab6SHal Finkel #include "llvm/MC/MCAsmInfo.h"
2889b57061SReid Kleckner #include "llvm/MC/TargetRegistry.h"
2923a3eab6SHal Finkel #include "llvm/Support/Debug.h"
3023a3eab6SHal Finkel #include "llvm/Support/ErrorHandling.h"
3123a3eab6SHal Finkel #include "llvm/Support/raw_ostream.h"
3223a3eab6SHal Finkel
3323a3eab6SHal Finkel using namespace llvm;
3423a3eab6SHal Finkel
3523a3eab6SHal Finkel #define DEBUG_TYPE "ppc-early-ret"
3623a3eab6SHal Finkel STATISTIC(NumBCLR, "Number of early conditional returns");
3723a3eab6SHal Finkel STATISTIC(NumBLR, "Number of early returns");
3823a3eab6SHal Finkel
3923a3eab6SHal Finkel namespace {
4023a3eab6SHal Finkel // PPCEarlyReturn pass - For simple functions without epilogue code, move
4123a3eab6SHal Finkel // returns up, and create conditional returns, to avoid unnecessary
4223a3eab6SHal Finkel // branch-to-blr sequences.
4323a3eab6SHal Finkel struct PPCEarlyReturn : public MachineFunctionPass {
4423a3eab6SHal Finkel static char ID;
PPCEarlyReturn__anon21024b450111::PPCEarlyReturn4523a3eab6SHal Finkel PPCEarlyReturn() : MachineFunctionPass(ID) {
4623a3eab6SHal Finkel initializePPCEarlyReturnPass(*PassRegistry::getPassRegistry());
4723a3eab6SHal Finkel }
4823a3eab6SHal Finkel
4923a3eab6SHal Finkel const TargetInstrInfo *TII;
5023a3eab6SHal Finkel
5123a3eab6SHal Finkel protected:
processBlock__anon21024b450111::PPCEarlyReturn5223a3eab6SHal Finkel bool processBlock(MachineBasicBlock &ReturnMBB) {
5323a3eab6SHal Finkel bool Changed = false;
5423a3eab6SHal Finkel
5523a3eab6SHal Finkel MachineBasicBlock::iterator I = ReturnMBB.begin();
56830a8c1fSKeith Walker I = ReturnMBB.SkipPHIsLabelsAndDebug(I);
5723a3eab6SHal Finkel
5823a3eab6SHal Finkel // The block must be essentially empty except for the blr.
5923a3eab6SHal Finkel if (I == ReturnMBB.end() ||
6023a3eab6SHal Finkel (I->getOpcode() != PPC::BLR && I->getOpcode() != PPC::BLR8) ||
6123a3eab6SHal Finkel I != ReturnMBB.getLastNonDebugInstr())
6223a3eab6SHal Finkel return Changed;
6323a3eab6SHal Finkel
6423a3eab6SHal Finkel SmallVector<MachineBasicBlock*, 8> PredToRemove;
65*ef2d0e0fSKazu Hirata for (MachineBasicBlock *Pred : ReturnMBB.predecessors()) {
6623a3eab6SHal Finkel bool OtherReference = false, BlockChanged = false;
67d3b904d4SKit Barton
68*ef2d0e0fSKazu Hirata if (Pred->empty())
69d3b904d4SKit Barton continue;
70d3b904d4SKit Barton
71*ef2d0e0fSKazu Hirata for (MachineBasicBlock::iterator J = Pred->getLastNonDebugInstr();;) {
72*ef2d0e0fSKazu Hirata if (J == Pred->end())
73d3b904d4SKit Barton break;
74d3b904d4SKit Barton
7523a3eab6SHal Finkel if (J->getOpcode() == PPC::B) {
7623a3eab6SHal Finkel if (J->getOperand(0).getMBB() == &ReturnMBB) {
7723a3eab6SHal Finkel // This is an unconditional branch to the return. Replace the
7823a3eab6SHal Finkel // branch with a blr.
79d37befdfSKang Zhang MachineInstr *MI = ReturnMBB.getParent()->CloneMachineInstr(&*I);
80*ef2d0e0fSKazu Hirata Pred->insert(J, MI);
81d37befdfSKang Zhang
8223a3eab6SHal Finkel MachineBasicBlock::iterator K = J--;
8323a3eab6SHal Finkel K->eraseFromParent();
8423a3eab6SHal Finkel BlockChanged = true;
8523a3eab6SHal Finkel ++NumBLR;
8623a3eab6SHal Finkel continue;
8723a3eab6SHal Finkel }
8823a3eab6SHal Finkel } else if (J->getOpcode() == PPC::BCC) {
8923a3eab6SHal Finkel if (J->getOperand(2).getMBB() == &ReturnMBB) {
9023a3eab6SHal Finkel // This is a conditional branch to the return. Replace the branch
9123a3eab6SHal Finkel // with a bclr.
92d37befdfSKang Zhang MachineInstr *MI = ReturnMBB.getParent()->CloneMachineInstr(&*I);
93d37befdfSKang Zhang MI->setDesc(TII->get(PPC::BCCLR));
94d37befdfSKang Zhang MachineInstrBuilder(*ReturnMBB.getParent(), MI)
95782a4dd1SKang Zhang .add(J->getOperand(0))
96d37befdfSKang Zhang .add(J->getOperand(1));
97*ef2d0e0fSKazu Hirata Pred->insert(J, MI);
98d37befdfSKang Zhang
9923a3eab6SHal Finkel MachineBasicBlock::iterator K = J--;
10023a3eab6SHal Finkel K->eraseFromParent();
10123a3eab6SHal Finkel BlockChanged = true;
10223a3eab6SHal Finkel ++NumBCLR;
10323a3eab6SHal Finkel continue;
10423a3eab6SHal Finkel }
10523a3eab6SHal Finkel } else if (J->getOpcode() == PPC::BC || J->getOpcode() == PPC::BCn) {
10623a3eab6SHal Finkel if (J->getOperand(1).getMBB() == &ReturnMBB) {
10723a3eab6SHal Finkel // This is a conditional branch to the return. Replace the branch
10823a3eab6SHal Finkel // with a bclr.
109d37befdfSKang Zhang MachineInstr *MI = ReturnMBB.getParent()->CloneMachineInstr(&*I);
110d37befdfSKang Zhang MI->setDesc(
111d37befdfSKang Zhang TII->get(J->getOpcode() == PPC::BC ? PPC::BCLR : PPC::BCLRn));
112d37befdfSKang Zhang MachineInstrBuilder(*ReturnMBB.getParent(), MI)
113d37befdfSKang Zhang .add(J->getOperand(0));
114*ef2d0e0fSKazu Hirata Pred->insert(J, MI);
115d37befdfSKang Zhang
11623a3eab6SHal Finkel MachineBasicBlock::iterator K = J--;
11723a3eab6SHal Finkel K->eraseFromParent();
11823a3eab6SHal Finkel BlockChanged = true;
11923a3eab6SHal Finkel ++NumBCLR;
12023a3eab6SHal Finkel continue;
12123a3eab6SHal Finkel }
12223a3eab6SHal Finkel } else if (J->isBranch()) {
12323a3eab6SHal Finkel if (J->isIndirectBranch()) {
12423a3eab6SHal Finkel if (ReturnMBB.hasAddressTaken())
12523a3eab6SHal Finkel OtherReference = true;
12623a3eab6SHal Finkel } else
12723a3eab6SHal Finkel for (unsigned i = 0; i < J->getNumOperands(); ++i)
12823a3eab6SHal Finkel if (J->getOperand(i).isMBB() &&
12923a3eab6SHal Finkel J->getOperand(i).getMBB() == &ReturnMBB)
13023a3eab6SHal Finkel OtherReference = true;
131801bf7ebSShiva Chen } else if (!J->isTerminator() && !J->isDebugInstr())
13223a3eab6SHal Finkel break;
13323a3eab6SHal Finkel
134*ef2d0e0fSKazu Hirata if (J == Pred->begin())
13523a3eab6SHal Finkel break;
13623a3eab6SHal Finkel
13723a3eab6SHal Finkel --J;
13823a3eab6SHal Finkel }
13923a3eab6SHal Finkel
140*ef2d0e0fSKazu Hirata if (Pred->canFallThrough() && Pred->isLayoutSuccessor(&ReturnMBB))
14123a3eab6SHal Finkel OtherReference = true;
14223a3eab6SHal Finkel
14323a3eab6SHal Finkel // Predecessors are stored in a vector and can't be removed here.
14423a3eab6SHal Finkel if (!OtherReference && BlockChanged) {
145*ef2d0e0fSKazu Hirata PredToRemove.push_back(Pred);
14623a3eab6SHal Finkel }
14723a3eab6SHal Finkel
14823a3eab6SHal Finkel if (BlockChanged)
14923a3eab6SHal Finkel Changed = true;
15023a3eab6SHal Finkel }
15123a3eab6SHal Finkel
15223a3eab6SHal Finkel for (unsigned i = 0, ie = PredToRemove.size(); i != ie; ++i)
153c106989fSCong Hou PredToRemove[i]->removeSuccessor(&ReturnMBB, true);
15423a3eab6SHal Finkel
15523a3eab6SHal Finkel if (Changed && !ReturnMBB.hasAddressTaken()) {
15623a3eab6SHal Finkel // We now might be able to merge this blr-only block into its
15723a3eab6SHal Finkel // by-layout predecessor.
1580867b151SHans Wennborg if (ReturnMBB.pred_size() == 1) {
1590be238ceSAaron Ballman MachineBasicBlock &PrevMBB = **ReturnMBB.pred_begin();
1600867b151SHans Wennborg if (PrevMBB.isLayoutSuccessor(&ReturnMBB) && PrevMBB.canFallThrough()) {
1610867b151SHans Wennborg // Move the blr into the preceding block.
16223a3eab6SHal Finkel PrevMBB.splice(PrevMBB.end(), &ReturnMBB, I);
163c106989fSCong Hou PrevMBB.removeSuccessor(&ReturnMBB, true);
16423a3eab6SHal Finkel }
1650867b151SHans Wennborg }
16623a3eab6SHal Finkel
16723a3eab6SHal Finkel if (ReturnMBB.pred_empty())
16823a3eab6SHal Finkel ReturnMBB.eraseFromParent();
16923a3eab6SHal Finkel }
17023a3eab6SHal Finkel
17123a3eab6SHal Finkel return Changed;
17223a3eab6SHal Finkel }
17323a3eab6SHal Finkel
17423a3eab6SHal Finkel public:
runOnMachineFunction__anon21024b450111::PPCEarlyReturn17523a3eab6SHal Finkel bool runOnMachineFunction(MachineFunction &MF) override {
176f1caa283SMatthias Braun if (skipFunction(MF.getFunction()))
177289bd5f6SAndrew Kaylor return false;
178289bd5f6SAndrew Kaylor
17923a3eab6SHal Finkel TII = MF.getSubtarget().getInstrInfo();
18023a3eab6SHal Finkel
18123a3eab6SHal Finkel bool Changed = false;
18223a3eab6SHal Finkel
18323a3eab6SHal Finkel // If the function does not have at least two blocks, then there is
18423a3eab6SHal Finkel // nothing to do.
18523a3eab6SHal Finkel if (MF.size() < 2)
18623a3eab6SHal Finkel return Changed;
18723a3eab6SHal Finkel
1882c4ba3e9SKazu Hirata for (MachineBasicBlock &B : llvm::make_early_inc_range(MF))
189490bc465SKang Zhang Changed |= processBlock(B);
19023a3eab6SHal Finkel
19123a3eab6SHal Finkel return Changed;
19223a3eab6SHal Finkel }
19323a3eab6SHal Finkel
getRequiredProperties__anon21024b450111::PPCEarlyReturn1941dbf7a57SDerek Schuff MachineFunctionProperties getRequiredProperties() const override {
1951dbf7a57SDerek Schuff return MachineFunctionProperties().set(
1961eb47368SMatthias Braun MachineFunctionProperties::Property::NoVRegs);
1971dbf7a57SDerek Schuff }
1981dbf7a57SDerek Schuff
getAnalysisUsage__anon21024b450111::PPCEarlyReturn19923a3eab6SHal Finkel void getAnalysisUsage(AnalysisUsage &AU) const override {
20023a3eab6SHal Finkel MachineFunctionPass::getAnalysisUsage(AU);
20123a3eab6SHal Finkel }
20223a3eab6SHal Finkel };
203f00654e3SAlexander Kornienko }
20423a3eab6SHal Finkel
20523a3eab6SHal Finkel INITIALIZE_PASS(PPCEarlyReturn, DEBUG_TYPE,
20623a3eab6SHal Finkel "PowerPC Early-Return Creation", false, false)
20723a3eab6SHal Finkel
20823a3eab6SHal Finkel char PPCEarlyReturn::ID = 0;
20923a3eab6SHal Finkel FunctionPass*
createPPCEarlyReturnPass()21023a3eab6SHal Finkel llvm::createPPCEarlyReturnPass() { return new PPCEarlyReturn(); }
211