10b57cec5SDimitry Andric //===- HexagonCFGOptimizer.cpp - CFG optimizations ------------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 90b57cec5SDimitry Andric #include "Hexagon.h" 10*e8d8bef9SDimitry Andric #include "MCTargetDesc/HexagonMCTargetDesc.h" 110b57cec5SDimitry Andric #include "llvm/CodeGen/MachineBasicBlock.h" 120b57cec5SDimitry Andric #include "llvm/CodeGen/MachineBranchProbabilityInfo.h" 130b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunction.h" 140b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h" 150b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstr.h" 160b57cec5SDimitry Andric #include "llvm/CodeGen/MachineOperand.h" 170b57cec5SDimitry Andric #include "llvm/CodeGen/TargetInstrInfo.h" 180b57cec5SDimitry Andric #include "llvm/CodeGen/TargetSubtargetInfo.h" 190b57cec5SDimitry Andric #include "llvm/Pass.h" 200b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h" 210b57cec5SDimitry Andric #include <cassert> 220b57cec5SDimitry Andric #include <vector> 230b57cec5SDimitry Andric 240b57cec5SDimitry Andric using namespace llvm; 250b57cec5SDimitry Andric 260b57cec5SDimitry Andric #define DEBUG_TYPE "hexagon_cfg" 270b57cec5SDimitry Andric 280b57cec5SDimitry Andric namespace llvm { 290b57cec5SDimitry Andric 300b57cec5SDimitry Andric FunctionPass *createHexagonCFGOptimizer(); 310b57cec5SDimitry Andric void initializeHexagonCFGOptimizerPass(PassRegistry&); 320b57cec5SDimitry Andric 330b57cec5SDimitry Andric } // end namespace llvm 340b57cec5SDimitry Andric 350b57cec5SDimitry Andric namespace { 360b57cec5SDimitry Andric 370b57cec5SDimitry Andric class HexagonCFGOptimizer : public MachineFunctionPass { 380b57cec5SDimitry Andric private: 390b57cec5SDimitry Andric void InvertAndChangeJumpTarget(MachineInstr &, MachineBasicBlock *); 400b57cec5SDimitry Andric bool isOnFallThroughPath(MachineBasicBlock *MBB); 410b57cec5SDimitry Andric 420b57cec5SDimitry Andric public: 430b57cec5SDimitry Andric static char ID; 440b57cec5SDimitry Andric 450b57cec5SDimitry Andric HexagonCFGOptimizer() : MachineFunctionPass(ID) { 460b57cec5SDimitry Andric initializeHexagonCFGOptimizerPass(*PassRegistry::getPassRegistry()); 470b57cec5SDimitry Andric } 480b57cec5SDimitry Andric 490b57cec5SDimitry Andric StringRef getPassName() const override { return "Hexagon CFG Optimizer"; } 500b57cec5SDimitry Andric bool runOnMachineFunction(MachineFunction &Fn) override; 510b57cec5SDimitry Andric 520b57cec5SDimitry Andric MachineFunctionProperties getRequiredProperties() const override { 530b57cec5SDimitry Andric return MachineFunctionProperties().set( 540b57cec5SDimitry Andric MachineFunctionProperties::Property::NoVRegs); 550b57cec5SDimitry Andric } 560b57cec5SDimitry Andric }; 570b57cec5SDimitry Andric 580b57cec5SDimitry Andric } // end anonymous namespace 590b57cec5SDimitry Andric 600b57cec5SDimitry Andric char HexagonCFGOptimizer::ID = 0; 610b57cec5SDimitry Andric 620b57cec5SDimitry Andric static bool IsConditionalBranch(int Opc) { 630b57cec5SDimitry Andric switch (Opc) { 640b57cec5SDimitry Andric case Hexagon::J2_jumpt: 650b57cec5SDimitry Andric case Hexagon::J2_jumptpt: 660b57cec5SDimitry Andric case Hexagon::J2_jumpf: 670b57cec5SDimitry Andric case Hexagon::J2_jumpfpt: 680b57cec5SDimitry Andric case Hexagon::J2_jumptnew: 690b57cec5SDimitry Andric case Hexagon::J2_jumpfnew: 700b57cec5SDimitry Andric case Hexagon::J2_jumptnewpt: 710b57cec5SDimitry Andric case Hexagon::J2_jumpfnewpt: 720b57cec5SDimitry Andric return true; 730b57cec5SDimitry Andric } 740b57cec5SDimitry Andric return false; 750b57cec5SDimitry Andric } 760b57cec5SDimitry Andric 770b57cec5SDimitry Andric static bool IsUnconditionalJump(int Opc) { 780b57cec5SDimitry Andric return (Opc == Hexagon::J2_jump); 790b57cec5SDimitry Andric } 800b57cec5SDimitry Andric 810b57cec5SDimitry Andric void HexagonCFGOptimizer::InvertAndChangeJumpTarget( 820b57cec5SDimitry Andric MachineInstr &MI, MachineBasicBlock *NewTarget) { 830b57cec5SDimitry Andric const TargetInstrInfo *TII = 840b57cec5SDimitry Andric MI.getParent()->getParent()->getSubtarget().getInstrInfo(); 850b57cec5SDimitry Andric int NewOpcode = 0; 860b57cec5SDimitry Andric switch (MI.getOpcode()) { 870b57cec5SDimitry Andric case Hexagon::J2_jumpt: 880b57cec5SDimitry Andric NewOpcode = Hexagon::J2_jumpf; 890b57cec5SDimitry Andric break; 900b57cec5SDimitry Andric case Hexagon::J2_jumpf: 910b57cec5SDimitry Andric NewOpcode = Hexagon::J2_jumpt; 920b57cec5SDimitry Andric break; 930b57cec5SDimitry Andric case Hexagon::J2_jumptnewpt: 940b57cec5SDimitry Andric NewOpcode = Hexagon::J2_jumpfnewpt; 950b57cec5SDimitry Andric break; 960b57cec5SDimitry Andric case Hexagon::J2_jumpfnewpt: 970b57cec5SDimitry Andric NewOpcode = Hexagon::J2_jumptnewpt; 980b57cec5SDimitry Andric break; 990b57cec5SDimitry Andric default: 1000b57cec5SDimitry Andric llvm_unreachable("Cannot handle this case"); 1010b57cec5SDimitry Andric } 1020b57cec5SDimitry Andric 1030b57cec5SDimitry Andric MI.setDesc(TII->get(NewOpcode)); 1040b57cec5SDimitry Andric MI.getOperand(1).setMBB(NewTarget); 1050b57cec5SDimitry Andric } 1060b57cec5SDimitry Andric 1070b57cec5SDimitry Andric bool HexagonCFGOptimizer::isOnFallThroughPath(MachineBasicBlock *MBB) { 1080b57cec5SDimitry Andric if (MBB->canFallThrough()) 1090b57cec5SDimitry Andric return true; 1100b57cec5SDimitry Andric for (MachineBasicBlock *PB : MBB->predecessors()) 1110b57cec5SDimitry Andric if (PB->isLayoutSuccessor(MBB) && PB->canFallThrough()) 1120b57cec5SDimitry Andric return true; 1130b57cec5SDimitry Andric return false; 1140b57cec5SDimitry Andric } 1150b57cec5SDimitry Andric 1160b57cec5SDimitry Andric bool HexagonCFGOptimizer::runOnMachineFunction(MachineFunction &Fn) { 1170b57cec5SDimitry Andric if (skipFunction(Fn.getFunction())) 1180b57cec5SDimitry Andric return false; 1190b57cec5SDimitry Andric 1200b57cec5SDimitry Andric // Loop over all of the basic blocks. 1210b57cec5SDimitry Andric for (MachineFunction::iterator MBBb = Fn.begin(), MBBe = Fn.end(); 1220b57cec5SDimitry Andric MBBb != MBBe; ++MBBb) { 1230b57cec5SDimitry Andric MachineBasicBlock *MBB = &*MBBb; 1240b57cec5SDimitry Andric 1250b57cec5SDimitry Andric // Traverse the basic block. 1260b57cec5SDimitry Andric MachineBasicBlock::iterator MII = MBB->getFirstTerminator(); 1270b57cec5SDimitry Andric if (MII != MBB->end()) { 1280b57cec5SDimitry Andric MachineInstr &MI = *MII; 1290b57cec5SDimitry Andric int Opc = MI.getOpcode(); 1300b57cec5SDimitry Andric if (IsConditionalBranch(Opc)) { 1310b57cec5SDimitry Andric // (Case 1) Transform the code if the following condition occurs: 1320b57cec5SDimitry Andric // BB1: if (p0) jump BB3 1330b57cec5SDimitry Andric // ...falls-through to BB2 ... 1340b57cec5SDimitry Andric // BB2: jump BB4 1350b57cec5SDimitry Andric // ...next block in layout is BB3... 1360b57cec5SDimitry Andric // BB3: ... 1370b57cec5SDimitry Andric // 1380b57cec5SDimitry Andric // Transform this to: 1390b57cec5SDimitry Andric // BB1: if (!p0) jump BB4 1400b57cec5SDimitry Andric // Remove BB2 1410b57cec5SDimitry Andric // BB3: ... 1420b57cec5SDimitry Andric // 1430b57cec5SDimitry Andric // (Case 2) A variation occurs when BB3 contains a JMP to BB4: 1440b57cec5SDimitry Andric // BB1: if (p0) jump BB3 1450b57cec5SDimitry Andric // ...falls-through to BB2 ... 1460b57cec5SDimitry Andric // BB2: jump BB4 1470b57cec5SDimitry Andric // ...other basic blocks ... 1480b57cec5SDimitry Andric // BB4: 1490b57cec5SDimitry Andric // ...not a fall-thru 1500b57cec5SDimitry Andric // BB3: ... 1510b57cec5SDimitry Andric // jump BB4 1520b57cec5SDimitry Andric // 1530b57cec5SDimitry Andric // Transform this to: 1540b57cec5SDimitry Andric // BB1: if (!p0) jump BB4 1550b57cec5SDimitry Andric // Remove BB2 1560b57cec5SDimitry Andric // BB3: ... 1570b57cec5SDimitry Andric // BB4: ... 1580b57cec5SDimitry Andric unsigned NumSuccs = MBB->succ_size(); 1590b57cec5SDimitry Andric MachineBasicBlock::succ_iterator SI = MBB->succ_begin(); 1600b57cec5SDimitry Andric MachineBasicBlock* FirstSucc = *SI; 1610b57cec5SDimitry Andric MachineBasicBlock* SecondSucc = *(++SI); 1620b57cec5SDimitry Andric MachineBasicBlock* LayoutSucc = nullptr; 1630b57cec5SDimitry Andric MachineBasicBlock* JumpAroundTarget = nullptr; 1640b57cec5SDimitry Andric 1650b57cec5SDimitry Andric if (MBB->isLayoutSuccessor(FirstSucc)) { 1660b57cec5SDimitry Andric LayoutSucc = FirstSucc; 1670b57cec5SDimitry Andric JumpAroundTarget = SecondSucc; 1680b57cec5SDimitry Andric } else if (MBB->isLayoutSuccessor(SecondSucc)) { 1690b57cec5SDimitry Andric LayoutSucc = SecondSucc; 1700b57cec5SDimitry Andric JumpAroundTarget = FirstSucc; 1710b57cec5SDimitry Andric } else { 1720b57cec5SDimitry Andric // Odd case...cannot handle. 1730b57cec5SDimitry Andric } 1740b57cec5SDimitry Andric 1750b57cec5SDimitry Andric // The target of the unconditional branch must be JumpAroundTarget. 1760b57cec5SDimitry Andric // TODO: If not, we should not invert the unconditional branch. 1770b57cec5SDimitry Andric MachineBasicBlock* CondBranchTarget = nullptr; 1780b57cec5SDimitry Andric if (MI.getOpcode() == Hexagon::J2_jumpt || 1790b57cec5SDimitry Andric MI.getOpcode() == Hexagon::J2_jumpf) { 1800b57cec5SDimitry Andric CondBranchTarget = MI.getOperand(1).getMBB(); 1810b57cec5SDimitry Andric } 1820b57cec5SDimitry Andric 1830b57cec5SDimitry Andric if (!LayoutSucc || (CondBranchTarget != JumpAroundTarget)) { 1840b57cec5SDimitry Andric continue; 1850b57cec5SDimitry Andric } 1860b57cec5SDimitry Andric 1870b57cec5SDimitry Andric if ((NumSuccs == 2) && LayoutSucc && (LayoutSucc->pred_size() == 1)) { 1880b57cec5SDimitry Andric // Ensure that BB2 has one instruction -- an unconditional jump. 1890b57cec5SDimitry Andric if ((LayoutSucc->size() == 1) && 1900b57cec5SDimitry Andric IsUnconditionalJump(LayoutSucc->front().getOpcode())) { 1910b57cec5SDimitry Andric assert(JumpAroundTarget && "jump target is needed to process second basic block"); 1920b57cec5SDimitry Andric MachineBasicBlock* UncondTarget = 1930b57cec5SDimitry Andric LayoutSucc->front().getOperand(0).getMBB(); 1940b57cec5SDimitry Andric // Check if the layout successor of BB2 is BB3. 1950b57cec5SDimitry Andric bool case1 = LayoutSucc->isLayoutSuccessor(JumpAroundTarget); 1960b57cec5SDimitry Andric bool case2 = JumpAroundTarget->isSuccessor(UncondTarget) && 1970b57cec5SDimitry Andric !JumpAroundTarget->empty() && 1980b57cec5SDimitry Andric IsUnconditionalJump(JumpAroundTarget->back().getOpcode()) && 1990b57cec5SDimitry Andric JumpAroundTarget->pred_size() == 1 && 2000b57cec5SDimitry Andric JumpAroundTarget->succ_size() == 1; 2010b57cec5SDimitry Andric 2020b57cec5SDimitry Andric if (case1 || case2) { 2030b57cec5SDimitry Andric InvertAndChangeJumpTarget(MI, UncondTarget); 2040b57cec5SDimitry Andric MBB->replaceSuccessor(JumpAroundTarget, UncondTarget); 2050b57cec5SDimitry Andric 2060b57cec5SDimitry Andric // Remove the unconditional branch in LayoutSucc. 2070b57cec5SDimitry Andric LayoutSucc->erase(LayoutSucc->begin()); 2080b57cec5SDimitry Andric LayoutSucc->replaceSuccessor(UncondTarget, JumpAroundTarget); 2090b57cec5SDimitry Andric 2100b57cec5SDimitry Andric // This code performs the conversion for case 2, which moves 2110b57cec5SDimitry Andric // the block to the fall-thru case (BB3 in the code above). 2120b57cec5SDimitry Andric if (case2 && !case1) { 2130b57cec5SDimitry Andric JumpAroundTarget->moveAfter(LayoutSucc); 2140b57cec5SDimitry Andric // only move a block if it doesn't have a fall-thru. otherwise 2150b57cec5SDimitry Andric // the CFG will be incorrect. 2160b57cec5SDimitry Andric if (!isOnFallThroughPath(UncondTarget)) 2170b57cec5SDimitry Andric UncondTarget->moveAfter(JumpAroundTarget); 2180b57cec5SDimitry Andric } 2190b57cec5SDimitry Andric 2200b57cec5SDimitry Andric // Correct live-in information. Is used by post-RA scheduler 2210b57cec5SDimitry Andric // The live-in to LayoutSucc is now all values live-in to 2220b57cec5SDimitry Andric // JumpAroundTarget. 2230b57cec5SDimitry Andric std::vector<MachineBasicBlock::RegisterMaskPair> OrigLiveIn( 2240b57cec5SDimitry Andric LayoutSucc->livein_begin(), LayoutSucc->livein_end()); 2250b57cec5SDimitry Andric std::vector<MachineBasicBlock::RegisterMaskPair> NewLiveIn( 2260b57cec5SDimitry Andric JumpAroundTarget->livein_begin(), 2270b57cec5SDimitry Andric JumpAroundTarget->livein_end()); 2280b57cec5SDimitry Andric for (const auto &OrigLI : OrigLiveIn) 2290b57cec5SDimitry Andric LayoutSucc->removeLiveIn(OrigLI.PhysReg); 2300b57cec5SDimitry Andric for (const auto &NewLI : NewLiveIn) 2310b57cec5SDimitry Andric LayoutSucc->addLiveIn(NewLI); 2320b57cec5SDimitry Andric } 2330b57cec5SDimitry Andric } 2340b57cec5SDimitry Andric } 2350b57cec5SDimitry Andric } 2360b57cec5SDimitry Andric } 2370b57cec5SDimitry Andric } 2380b57cec5SDimitry Andric return true; 2390b57cec5SDimitry Andric } 2400b57cec5SDimitry Andric 2410b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 2420b57cec5SDimitry Andric // Public Constructor Functions 2430b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 2440b57cec5SDimitry Andric 2450b57cec5SDimitry Andric INITIALIZE_PASS(HexagonCFGOptimizer, "hexagon-cfg", "Hexagon CFG Optimizer", 2460b57cec5SDimitry Andric false, false) 2470b57cec5SDimitry Andric 2480b57cec5SDimitry Andric FunctionPass *llvm::createHexagonCFGOptimizer() { 2490b57cec5SDimitry Andric return new HexagonCFGOptimizer(); 2500b57cec5SDimitry Andric } 251