//===------------- PPCEarlyReturn.cpp - Form Early Returns ----------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // A pass that form early (predicated) returns. If-conversion handles some of // this, but this pass picks up some remaining cases. // //===----------------------------------------------------------------------===// #include "MCTargetDesc/PPCPredicates.h" #include "PPC.h" #include "PPCInstrBuilder.h" #include "PPCInstrInfo.h" #include "PPCMachineFunctionInfo.h" #include "PPCTargetMachine.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Statistic.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineMemOperand.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; #define DEBUG_TYPE "ppc-early-ret" STATISTIC(NumBCLR, "Number of early conditional returns"); STATISTIC(NumBLR, "Number of early returns"); namespace { // PPCEarlyReturn pass - For simple functions without epilogue code, move // returns up, and create conditional returns, to avoid unnecessary // branch-to-blr sequences. struct PPCEarlyReturn : public MachineFunctionPass { static char ID; PPCEarlyReturn() : MachineFunctionPass(ID) { initializePPCEarlyReturnPass(*PassRegistry::getPassRegistry()); } const TargetInstrInfo *TII; protected: bool processBlock(MachineBasicBlock &ReturnMBB) { bool Changed = false; MachineBasicBlock::iterator I = ReturnMBB.begin(); I = ReturnMBB.SkipPHIsLabelsAndDebug(I); // The block must be essentially empty except for the blr. if (I == ReturnMBB.end() || (I->getOpcode() != PPC::BLR && I->getOpcode() != PPC::BLR8) || I != ReturnMBB.getLastNonDebugInstr()) return Changed; SmallVector PredToRemove; for (MachineBasicBlock::pred_iterator PI = ReturnMBB.pred_begin(), PIE = ReturnMBB.pred_end(); PI != PIE; ++PI) { bool OtherReference = false, BlockChanged = false; if ((*PI)->empty()) continue; for (MachineBasicBlock::iterator J = (*PI)->getLastNonDebugInstr();;) { if (J == (*PI)->end()) break; if (J->getOpcode() == PPC::B) { if (J->getOperand(0).getMBB() == &ReturnMBB) { // This is an unconditional branch to the return. Replace the // branch with a blr. MachineInstr *MI = ReturnMBB.getParent()->CloneMachineInstr(&*I); (*PI)->insert(J, MI); MachineBasicBlock::iterator K = J--; K->eraseFromParent(); BlockChanged = true; ++NumBLR; continue; } } else if (J->getOpcode() == PPC::BCC) { if (J->getOperand(2).getMBB() == &ReturnMBB) { // This is a conditional branch to the return. Replace the branch // with a bclr. MachineInstr *MI = ReturnMBB.getParent()->CloneMachineInstr(&*I); MI->setDesc(TII->get(PPC::BCCLR)); MachineInstrBuilder(*ReturnMBB.getParent(), MI) .add(J->getOperand(0)) .add(J->getOperand(1)); (*PI)->insert(J, MI); MachineBasicBlock::iterator K = J--; K->eraseFromParent(); BlockChanged = true; ++NumBCLR; continue; } } else if (J->getOpcode() == PPC::BC || J->getOpcode() == PPC::BCn) { if (J->getOperand(1).getMBB() == &ReturnMBB) { // This is a conditional branch to the return. Replace the branch // with a bclr. MachineInstr *MI = ReturnMBB.getParent()->CloneMachineInstr(&*I); MI->setDesc( TII->get(J->getOpcode() == PPC::BC ? PPC::BCLR : PPC::BCLRn)); MachineInstrBuilder(*ReturnMBB.getParent(), MI) .add(J->getOperand(0)); (*PI)->insert(J, MI); MachineBasicBlock::iterator K = J--; K->eraseFromParent(); BlockChanged = true; ++NumBCLR; continue; } } else if (J->isBranch()) { if (J->isIndirectBranch()) { if (ReturnMBB.hasAddressTaken()) OtherReference = true; } else for (unsigned i = 0; i < J->getNumOperands(); ++i) if (J->getOperand(i).isMBB() && J->getOperand(i).getMBB() == &ReturnMBB) OtherReference = true; } else if (!J->isTerminator() && !J->isDebugInstr()) break; if (J == (*PI)->begin()) break; --J; } if ((*PI)->canFallThrough() && (*PI)->isLayoutSuccessor(&ReturnMBB)) OtherReference = true; // Predecessors are stored in a vector and can't be removed here. if (!OtherReference && BlockChanged) { PredToRemove.push_back(*PI); } if (BlockChanged) Changed = true; } for (unsigned i = 0, ie = PredToRemove.size(); i != ie; ++i) PredToRemove[i]->removeSuccessor(&ReturnMBB, true); if (Changed && !ReturnMBB.hasAddressTaken()) { // We now might be able to merge this blr-only block into its // by-layout predecessor. if (ReturnMBB.pred_size() == 1) { MachineBasicBlock &PrevMBB = **ReturnMBB.pred_begin(); if (PrevMBB.isLayoutSuccessor(&ReturnMBB) && PrevMBB.canFallThrough()) { // Move the blr into the preceding block. PrevMBB.splice(PrevMBB.end(), &ReturnMBB, I); PrevMBB.removeSuccessor(&ReturnMBB, true); } } if (ReturnMBB.pred_empty()) ReturnMBB.eraseFromParent(); } return Changed; } public: bool runOnMachineFunction(MachineFunction &MF) override { if (skipFunction(MF.getFunction())) return false; TII = MF.getSubtarget().getInstrInfo(); bool Changed = false; // If the function does not have at least two blocks, then there is // nothing to do. if (MF.size() < 2) return Changed; // We can't use a range-based for loop due to clobbering the iterator. for (MachineFunction::iterator I = MF.begin(), E = MF.end(); I != E;) { MachineBasicBlock &B = *I++; Changed |= processBlock(B); } return Changed; } MachineFunctionProperties getRequiredProperties() const override { return MachineFunctionProperties().set( MachineFunctionProperties::Property::NoVRegs); } void getAnalysisUsage(AnalysisUsage &AU) const override { MachineFunctionPass::getAnalysisUsage(AU); } }; } INITIALIZE_PASS(PPCEarlyReturn, DEBUG_TYPE, "PowerPC Early-Return Creation", false, false) char PPCEarlyReturn::ID = 0; FunctionPass* llvm::createPPCEarlyReturnPass() { return new PPCEarlyReturn(); }