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"
10e8d8bef9SDimitry 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
HexagonCFGOptimizer()450b57cec5SDimitry Andric HexagonCFGOptimizer() : MachineFunctionPass(ID) {
460b57cec5SDimitry Andric initializeHexagonCFGOptimizerPass(*PassRegistry::getPassRegistry());
470b57cec5SDimitry Andric }
480b57cec5SDimitry Andric
getPassName() const490b57cec5SDimitry Andric StringRef getPassName() const override { return "Hexagon CFG Optimizer"; }
500b57cec5SDimitry Andric bool runOnMachineFunction(MachineFunction &Fn) override;
510b57cec5SDimitry Andric
getRequiredProperties() const520b57cec5SDimitry 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
IsConditionalBranch(int Opc)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
IsUnconditionalJump(int Opc)770b57cec5SDimitry Andric static bool IsUnconditionalJump(int Opc) {
780b57cec5SDimitry Andric return (Opc == Hexagon::J2_jump);
790b57cec5SDimitry Andric }
800b57cec5SDimitry Andric
InvertAndChangeJumpTarget(MachineInstr & MI,MachineBasicBlock * NewTarget)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
isOnFallThroughPath(MachineBasicBlock * MBB)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
runOnMachineFunction(MachineFunction & Fn)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.
121*04eeddc0SDimitry Andric for (MachineBasicBlock &MBB : Fn) {
1220b57cec5SDimitry Andric // Traverse the basic block.
123*04eeddc0SDimitry Andric MachineBasicBlock::iterator MII = MBB.getFirstTerminator();
124*04eeddc0SDimitry Andric if (MII != MBB.end()) {
1250b57cec5SDimitry Andric MachineInstr &MI = *MII;
1260b57cec5SDimitry Andric int Opc = MI.getOpcode();
1270b57cec5SDimitry Andric if (IsConditionalBranch(Opc)) {
1280b57cec5SDimitry Andric // (Case 1) Transform the code if the following condition occurs:
1290b57cec5SDimitry Andric // BB1: if (p0) jump BB3
1300b57cec5SDimitry Andric // ...falls-through to BB2 ...
1310b57cec5SDimitry Andric // BB2: jump BB4
1320b57cec5SDimitry Andric // ...next block in layout is BB3...
1330b57cec5SDimitry Andric // BB3: ...
1340b57cec5SDimitry Andric //
1350b57cec5SDimitry Andric // Transform this to:
1360b57cec5SDimitry Andric // BB1: if (!p0) jump BB4
1370b57cec5SDimitry Andric // Remove BB2
1380b57cec5SDimitry Andric // BB3: ...
1390b57cec5SDimitry Andric //
1400b57cec5SDimitry Andric // (Case 2) A variation occurs when BB3 contains a JMP to BB4:
1410b57cec5SDimitry Andric // BB1: if (p0) jump BB3
1420b57cec5SDimitry Andric // ...falls-through to BB2 ...
1430b57cec5SDimitry Andric // BB2: jump BB4
1440b57cec5SDimitry Andric // ...other basic blocks ...
1450b57cec5SDimitry Andric // BB4:
1460b57cec5SDimitry Andric // ...not a fall-thru
1470b57cec5SDimitry Andric // BB3: ...
1480b57cec5SDimitry Andric // jump BB4
1490b57cec5SDimitry Andric //
1500b57cec5SDimitry Andric // Transform this to:
1510b57cec5SDimitry Andric // BB1: if (!p0) jump BB4
1520b57cec5SDimitry Andric // Remove BB2
1530b57cec5SDimitry Andric // BB3: ...
1540b57cec5SDimitry Andric // BB4: ...
155*04eeddc0SDimitry Andric unsigned NumSuccs = MBB.succ_size();
156*04eeddc0SDimitry Andric MachineBasicBlock::succ_iterator SI = MBB.succ_begin();
1570b57cec5SDimitry Andric MachineBasicBlock* FirstSucc = *SI;
1580b57cec5SDimitry Andric MachineBasicBlock* SecondSucc = *(++SI);
1590b57cec5SDimitry Andric MachineBasicBlock* LayoutSucc = nullptr;
1600b57cec5SDimitry Andric MachineBasicBlock* JumpAroundTarget = nullptr;
1610b57cec5SDimitry Andric
162*04eeddc0SDimitry Andric if (MBB.isLayoutSuccessor(FirstSucc)) {
1630b57cec5SDimitry Andric LayoutSucc = FirstSucc;
1640b57cec5SDimitry Andric JumpAroundTarget = SecondSucc;
165*04eeddc0SDimitry Andric } else if (MBB.isLayoutSuccessor(SecondSucc)) {
1660b57cec5SDimitry Andric LayoutSucc = SecondSucc;
1670b57cec5SDimitry Andric JumpAroundTarget = FirstSucc;
1680b57cec5SDimitry Andric } else {
1690b57cec5SDimitry Andric // Odd case...cannot handle.
1700b57cec5SDimitry Andric }
1710b57cec5SDimitry Andric
1720b57cec5SDimitry Andric // The target of the unconditional branch must be JumpAroundTarget.
1730b57cec5SDimitry Andric // TODO: If not, we should not invert the unconditional branch.
1740b57cec5SDimitry Andric MachineBasicBlock* CondBranchTarget = nullptr;
1750b57cec5SDimitry Andric if (MI.getOpcode() == Hexagon::J2_jumpt ||
1760b57cec5SDimitry Andric MI.getOpcode() == Hexagon::J2_jumpf) {
1770b57cec5SDimitry Andric CondBranchTarget = MI.getOperand(1).getMBB();
1780b57cec5SDimitry Andric }
1790b57cec5SDimitry Andric
1800b57cec5SDimitry Andric if (!LayoutSucc || (CondBranchTarget != JumpAroundTarget)) {
1810b57cec5SDimitry Andric continue;
1820b57cec5SDimitry Andric }
1830b57cec5SDimitry Andric
1840b57cec5SDimitry Andric if ((NumSuccs == 2) && LayoutSucc && (LayoutSucc->pred_size() == 1)) {
1850b57cec5SDimitry Andric // Ensure that BB2 has one instruction -- an unconditional jump.
1860b57cec5SDimitry Andric if ((LayoutSucc->size() == 1) &&
1870b57cec5SDimitry Andric IsUnconditionalJump(LayoutSucc->front().getOpcode())) {
1880b57cec5SDimitry Andric assert(JumpAroundTarget && "jump target is needed to process second basic block");
1890b57cec5SDimitry Andric MachineBasicBlock* UncondTarget =
1900b57cec5SDimitry Andric LayoutSucc->front().getOperand(0).getMBB();
1910b57cec5SDimitry Andric // Check if the layout successor of BB2 is BB3.
1920b57cec5SDimitry Andric bool case1 = LayoutSucc->isLayoutSuccessor(JumpAroundTarget);
1930b57cec5SDimitry Andric bool case2 = JumpAroundTarget->isSuccessor(UncondTarget) &&
1940b57cec5SDimitry Andric !JumpAroundTarget->empty() &&
1950b57cec5SDimitry Andric IsUnconditionalJump(JumpAroundTarget->back().getOpcode()) &&
1960b57cec5SDimitry Andric JumpAroundTarget->pred_size() == 1 &&
1970b57cec5SDimitry Andric JumpAroundTarget->succ_size() == 1;
1980b57cec5SDimitry Andric
1990b57cec5SDimitry Andric if (case1 || case2) {
2000b57cec5SDimitry Andric InvertAndChangeJumpTarget(MI, UncondTarget);
201*04eeddc0SDimitry Andric MBB.replaceSuccessor(JumpAroundTarget, UncondTarget);
2020b57cec5SDimitry Andric
2030b57cec5SDimitry Andric // Remove the unconditional branch in LayoutSucc.
2040b57cec5SDimitry Andric LayoutSucc->erase(LayoutSucc->begin());
2050b57cec5SDimitry Andric LayoutSucc->replaceSuccessor(UncondTarget, JumpAroundTarget);
2060b57cec5SDimitry Andric
2070b57cec5SDimitry Andric // This code performs the conversion for case 2, which moves
2080b57cec5SDimitry Andric // the block to the fall-thru case (BB3 in the code above).
2090b57cec5SDimitry Andric if (case2 && !case1) {
2100b57cec5SDimitry Andric JumpAroundTarget->moveAfter(LayoutSucc);
2110b57cec5SDimitry Andric // only move a block if it doesn't have a fall-thru. otherwise
2120b57cec5SDimitry Andric // the CFG will be incorrect.
2130b57cec5SDimitry Andric if (!isOnFallThroughPath(UncondTarget))
2140b57cec5SDimitry Andric UncondTarget->moveAfter(JumpAroundTarget);
2150b57cec5SDimitry Andric }
2160b57cec5SDimitry Andric
2170b57cec5SDimitry Andric // Correct live-in information. Is used by post-RA scheduler
2180b57cec5SDimitry Andric // The live-in to LayoutSucc is now all values live-in to
2190b57cec5SDimitry Andric // JumpAroundTarget.
2200b57cec5SDimitry Andric std::vector<MachineBasicBlock::RegisterMaskPair> OrigLiveIn(
2210b57cec5SDimitry Andric LayoutSucc->livein_begin(), LayoutSucc->livein_end());
2220b57cec5SDimitry Andric std::vector<MachineBasicBlock::RegisterMaskPair> NewLiveIn(
2230b57cec5SDimitry Andric JumpAroundTarget->livein_begin(),
2240b57cec5SDimitry Andric JumpAroundTarget->livein_end());
2250b57cec5SDimitry Andric for (const auto &OrigLI : OrigLiveIn)
2260b57cec5SDimitry Andric LayoutSucc->removeLiveIn(OrigLI.PhysReg);
2270b57cec5SDimitry Andric for (const auto &NewLI : NewLiveIn)
2280b57cec5SDimitry Andric LayoutSucc->addLiveIn(NewLI);
2290b57cec5SDimitry Andric }
2300b57cec5SDimitry Andric }
2310b57cec5SDimitry Andric }
2320b57cec5SDimitry Andric }
2330b57cec5SDimitry Andric }
2340b57cec5SDimitry Andric }
2350b57cec5SDimitry Andric return true;
2360b57cec5SDimitry Andric }
2370b57cec5SDimitry Andric
2380b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
2390b57cec5SDimitry Andric // Public Constructor Functions
2400b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
2410b57cec5SDimitry Andric
2420b57cec5SDimitry Andric INITIALIZE_PASS(HexagonCFGOptimizer, "hexagon-cfg", "Hexagon CFG Optimizer",
2430b57cec5SDimitry Andric false, false)
2440b57cec5SDimitry Andric
createHexagonCFGOptimizer()2450b57cec5SDimitry Andric FunctionPass *llvm::createHexagonCFGOptimizer() {
2460b57cec5SDimitry Andric return new HexagonCFGOptimizer();
2470b57cec5SDimitry Andric }
248