xref: /freebsd/contrib/llvm-project/llvm/lib/Target/Hexagon/HexagonCFGOptimizer.cpp (revision e8d8bef961a50d4dc22501cde4fb9fb0be1b2532)
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