10b57cec5SDimitry Andric //===--- HexagonBranchRelaxation.cpp - Identify and relax long jumps ------===// 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 #define DEBUG_TYPE "hexagon-brelax" 100b57cec5SDimitry Andric 110b57cec5SDimitry Andric #include "Hexagon.h" 120b57cec5SDimitry Andric #include "HexagonInstrInfo.h" 130b57cec5SDimitry Andric #include "HexagonSubtarget.h" 140b57cec5SDimitry Andric #include "llvm/ADT/DenseMap.h" 150b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h" 160b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h" 170b57cec5SDimitry Andric #include "llvm/CodeGen/MachineBasicBlock.h" 180b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunction.h" 190b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h" 200b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstr.h" 210b57cec5SDimitry Andric #include "llvm/CodeGen/MachineOperand.h" 220b57cec5SDimitry Andric #include "llvm/CodeGen/Passes.h" 230b57cec5SDimitry Andric #include "llvm/Pass.h" 240b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h" 250b57cec5SDimitry Andric #include "llvm/Support/Debug.h" 260b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 270b57cec5SDimitry Andric #include <cassert> 280b57cec5SDimitry Andric #include <cstdint> 290b57cec5SDimitry Andric #include <cstdlib> 300b57cec5SDimitry Andric #include <iterator> 310b57cec5SDimitry Andric 320b57cec5SDimitry Andric using namespace llvm; 330b57cec5SDimitry Andric 340b57cec5SDimitry Andric // Since we have no exact knowledge of code layout, allow some safety buffer 350b57cec5SDimitry Andric // for jump target. This is measured in bytes. 360b57cec5SDimitry Andric static cl::opt<uint32_t> BranchRelaxSafetyBuffer("branch-relax-safety-buffer", 370b57cec5SDimitry Andric cl::init(200), cl::Hidden, cl::ZeroOrMore, cl::desc("safety buffer size")); 380b57cec5SDimitry Andric 390b57cec5SDimitry Andric namespace llvm { 400b57cec5SDimitry Andric 410b57cec5SDimitry Andric FunctionPass *createHexagonBranchRelaxation(); 420b57cec5SDimitry Andric void initializeHexagonBranchRelaxationPass(PassRegistry&); 430b57cec5SDimitry Andric 440b57cec5SDimitry Andric } // end namespace llvm 450b57cec5SDimitry Andric 460b57cec5SDimitry Andric namespace { 470b57cec5SDimitry Andric 480b57cec5SDimitry Andric struct HexagonBranchRelaxation : public MachineFunctionPass { 490b57cec5SDimitry Andric public: 500b57cec5SDimitry Andric static char ID; 510b57cec5SDimitry Andric 520b57cec5SDimitry Andric HexagonBranchRelaxation() : MachineFunctionPass(ID) { 530b57cec5SDimitry Andric initializeHexagonBranchRelaxationPass(*PassRegistry::getPassRegistry()); 540b57cec5SDimitry Andric } 550b57cec5SDimitry Andric 560b57cec5SDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override; 570b57cec5SDimitry Andric 580b57cec5SDimitry Andric StringRef getPassName() const override { 590b57cec5SDimitry Andric return "Hexagon Branch Relaxation"; 600b57cec5SDimitry Andric } 610b57cec5SDimitry Andric 620b57cec5SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override { 630b57cec5SDimitry Andric AU.setPreservesCFG(); 640b57cec5SDimitry Andric MachineFunctionPass::getAnalysisUsage(AU); 650b57cec5SDimitry Andric } 660b57cec5SDimitry Andric 670b57cec5SDimitry Andric private: 680b57cec5SDimitry Andric const HexagonInstrInfo *HII; 690b57cec5SDimitry Andric const HexagonRegisterInfo *HRI; 700b57cec5SDimitry Andric 710b57cec5SDimitry Andric bool relaxBranches(MachineFunction &MF); 720b57cec5SDimitry Andric void computeOffset(MachineFunction &MF, 730b57cec5SDimitry Andric DenseMap<MachineBasicBlock*, unsigned> &BlockToInstOffset); 740b57cec5SDimitry Andric bool reGenerateBranch(MachineFunction &MF, 750b57cec5SDimitry Andric DenseMap<MachineBasicBlock*, unsigned> &BlockToInstOffset); 760b57cec5SDimitry Andric bool isJumpOutOfRange(MachineInstr &MI, 770b57cec5SDimitry Andric DenseMap<MachineBasicBlock*, unsigned> &BlockToInstOffset); 780b57cec5SDimitry Andric }; 790b57cec5SDimitry Andric 800b57cec5SDimitry Andric char HexagonBranchRelaxation::ID = 0; 810b57cec5SDimitry Andric 820b57cec5SDimitry Andric } // end anonymous namespace 830b57cec5SDimitry Andric 840b57cec5SDimitry Andric INITIALIZE_PASS(HexagonBranchRelaxation, "hexagon-brelax", 850b57cec5SDimitry Andric "Hexagon Branch Relaxation", false, false) 860b57cec5SDimitry Andric 870b57cec5SDimitry Andric FunctionPass *llvm::createHexagonBranchRelaxation() { 880b57cec5SDimitry Andric return new HexagonBranchRelaxation(); 890b57cec5SDimitry Andric } 900b57cec5SDimitry Andric 910b57cec5SDimitry Andric bool HexagonBranchRelaxation::runOnMachineFunction(MachineFunction &MF) { 920b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "****** Hexagon Branch Relaxation ******\n"); 930b57cec5SDimitry Andric 940b57cec5SDimitry Andric auto &HST = MF.getSubtarget<HexagonSubtarget>(); 950b57cec5SDimitry Andric HII = HST.getInstrInfo(); 960b57cec5SDimitry Andric HRI = HST.getRegisterInfo(); 970b57cec5SDimitry Andric 980b57cec5SDimitry Andric bool Changed = false; 990b57cec5SDimitry Andric Changed = relaxBranches(MF); 1000b57cec5SDimitry Andric return Changed; 1010b57cec5SDimitry Andric } 1020b57cec5SDimitry Andric 1030b57cec5SDimitry Andric void HexagonBranchRelaxation::computeOffset(MachineFunction &MF, 1040b57cec5SDimitry Andric DenseMap<MachineBasicBlock*, unsigned> &OffsetMap) { 1050b57cec5SDimitry Andric // offset of the current instruction from the start. 1060b57cec5SDimitry Andric unsigned InstOffset = 0; 1070b57cec5SDimitry Andric for (auto &B : MF) { 108*8bcb0991SDimitry Andric if (B.getAlignment() != Align::None()) { 1090b57cec5SDimitry Andric // Although we don't know the exact layout of the final code, we need 1100b57cec5SDimitry Andric // to account for alignment padding somehow. This heuristic pads each 1110b57cec5SDimitry Andric // aligned basic block according to the alignment value. 112*8bcb0991SDimitry Andric InstOffset = alignTo(InstOffset, B.getAlignment()); 1130b57cec5SDimitry Andric } 1140b57cec5SDimitry Andric OffsetMap[&B] = InstOffset; 1150b57cec5SDimitry Andric for (auto &MI : B.instrs()) { 1160b57cec5SDimitry Andric InstOffset += HII->getSize(MI); 1170b57cec5SDimitry Andric // Assume that all extendable branches will be extended. 1180b57cec5SDimitry Andric if (MI.isBranch() && HII->isExtendable(MI)) 1190b57cec5SDimitry Andric InstOffset += HEXAGON_INSTR_SIZE; 1200b57cec5SDimitry Andric } 1210b57cec5SDimitry Andric } 1220b57cec5SDimitry Andric } 1230b57cec5SDimitry Andric 1240b57cec5SDimitry Andric /// relaxBranches - For Hexagon, if the jump target/loop label is too far from 1250b57cec5SDimitry Andric /// the jump/loop instruction then, we need to make sure that we have constant 1260b57cec5SDimitry Andric /// extenders set for jumps and loops. 1270b57cec5SDimitry Andric 1280b57cec5SDimitry Andric /// There are six iterations in this phase. It's self explanatory below. 1290b57cec5SDimitry Andric bool HexagonBranchRelaxation::relaxBranches(MachineFunction &MF) { 1300b57cec5SDimitry Andric // Compute the offset of each basic block 1310b57cec5SDimitry Andric // offset of the current instruction from the start. 1320b57cec5SDimitry Andric // map for each instruction to the beginning of the function 1330b57cec5SDimitry Andric DenseMap<MachineBasicBlock*, unsigned> BlockToInstOffset; 1340b57cec5SDimitry Andric computeOffset(MF, BlockToInstOffset); 1350b57cec5SDimitry Andric 1360b57cec5SDimitry Andric return reGenerateBranch(MF, BlockToInstOffset); 1370b57cec5SDimitry Andric } 1380b57cec5SDimitry Andric 1390b57cec5SDimitry Andric /// Check if a given instruction is: 1400b57cec5SDimitry Andric /// - a jump to a distant target 1410b57cec5SDimitry Andric /// - that exceeds its immediate range 1420b57cec5SDimitry Andric /// If both conditions are true, it requires constant extension. 1430b57cec5SDimitry Andric bool HexagonBranchRelaxation::isJumpOutOfRange(MachineInstr &MI, 1440b57cec5SDimitry Andric DenseMap<MachineBasicBlock*, unsigned> &BlockToInstOffset) { 1450b57cec5SDimitry Andric MachineBasicBlock &B = *MI.getParent(); 1460b57cec5SDimitry Andric auto FirstTerm = B.getFirstInstrTerminator(); 1470b57cec5SDimitry Andric if (FirstTerm == B.instr_end()) 1480b57cec5SDimitry Andric return false; 1490b57cec5SDimitry Andric 1500b57cec5SDimitry Andric if (HII->isExtended(MI)) 1510b57cec5SDimitry Andric return false; 1520b57cec5SDimitry Andric 1530b57cec5SDimitry Andric unsigned InstOffset = BlockToInstOffset[&B]; 1540b57cec5SDimitry Andric unsigned Distance = 0; 1550b57cec5SDimitry Andric 1560b57cec5SDimitry Andric // To save time, estimate exact position of a branch instruction 1570b57cec5SDimitry Andric // as one at the end of the MBB. 1580b57cec5SDimitry Andric // Number of instructions times typical instruction size. 1590b57cec5SDimitry Andric InstOffset += HII->nonDbgBBSize(&B) * HEXAGON_INSTR_SIZE; 1600b57cec5SDimitry Andric 1610b57cec5SDimitry Andric MachineBasicBlock *TBB = nullptr, *FBB = nullptr; 1620b57cec5SDimitry Andric SmallVector<MachineOperand, 4> Cond; 1630b57cec5SDimitry Andric 1640b57cec5SDimitry Andric // Try to analyze this branch. 1650b57cec5SDimitry Andric if (HII->analyzeBranch(B, TBB, FBB, Cond, false)) { 1660b57cec5SDimitry Andric // Could not analyze it. See if this is something we can recognize. 1670b57cec5SDimitry Andric // If it is a NVJ, it should always have its target in 1680b57cec5SDimitry Andric // a fixed location. 1690b57cec5SDimitry Andric if (HII->isNewValueJump(*FirstTerm)) 1700b57cec5SDimitry Andric TBB = FirstTerm->getOperand(HII->getCExtOpNum(*FirstTerm)).getMBB(); 1710b57cec5SDimitry Andric } 1720b57cec5SDimitry Andric if (TBB && &MI == &*FirstTerm) { 1730b57cec5SDimitry Andric Distance = std::abs((long long)InstOffset - BlockToInstOffset[TBB]) 1740b57cec5SDimitry Andric + BranchRelaxSafetyBuffer; 1750b57cec5SDimitry Andric return !HII->isJumpWithinBranchRange(*FirstTerm, Distance); 1760b57cec5SDimitry Andric } 1770b57cec5SDimitry Andric if (FBB) { 1780b57cec5SDimitry Andric // Look for second terminator. 1790b57cec5SDimitry Andric auto SecondTerm = std::next(FirstTerm); 1800b57cec5SDimitry Andric assert(SecondTerm != B.instr_end() && 1810b57cec5SDimitry Andric (SecondTerm->isBranch() || SecondTerm->isCall()) && 1820b57cec5SDimitry Andric "Bad second terminator"); 1830b57cec5SDimitry Andric if (&MI != &*SecondTerm) 1840b57cec5SDimitry Andric return false; 1850b57cec5SDimitry Andric // Analyze the second branch in the BB. 1860b57cec5SDimitry Andric Distance = std::abs((long long)InstOffset - BlockToInstOffset[FBB]) 1870b57cec5SDimitry Andric + BranchRelaxSafetyBuffer; 1880b57cec5SDimitry Andric return !HII->isJumpWithinBranchRange(*SecondTerm, Distance); 1890b57cec5SDimitry Andric } 1900b57cec5SDimitry Andric return false; 1910b57cec5SDimitry Andric } 1920b57cec5SDimitry Andric 1930b57cec5SDimitry Andric bool HexagonBranchRelaxation::reGenerateBranch(MachineFunction &MF, 1940b57cec5SDimitry Andric DenseMap<MachineBasicBlock*, unsigned> &BlockToInstOffset) { 1950b57cec5SDimitry Andric bool Changed = false; 1960b57cec5SDimitry Andric 1970b57cec5SDimitry Andric for (auto &B : MF) { 1980b57cec5SDimitry Andric for (auto &MI : B) { 1990b57cec5SDimitry Andric if (!MI.isBranch() || !isJumpOutOfRange(MI, BlockToInstOffset)) 2000b57cec5SDimitry Andric continue; 2010b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Long distance jump. isExtendable(" 2020b57cec5SDimitry Andric << HII->isExtendable(MI) << ") isConstExtended(" 2030b57cec5SDimitry Andric << HII->isConstExtended(MI) << ") " << MI); 2040b57cec5SDimitry Andric 2050b57cec5SDimitry Andric // Since we have not merged HW loops relaxation into 2060b57cec5SDimitry Andric // this code (yet), soften our approach for the moment. 2070b57cec5SDimitry Andric if (!HII->isExtendable(MI) && !HII->isExtended(MI)) { 2080b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "\tUnderimplemented relax branch instruction.\n"); 2090b57cec5SDimitry Andric } else { 2100b57cec5SDimitry Andric // Find which operand is expandable. 2110b57cec5SDimitry Andric int ExtOpNum = HII->getCExtOpNum(MI); 2120b57cec5SDimitry Andric MachineOperand &MO = MI.getOperand(ExtOpNum); 2130b57cec5SDimitry Andric // This need to be something we understand. So far we assume all 2140b57cec5SDimitry Andric // branches have only MBB address as expandable field. 2150b57cec5SDimitry Andric // If it changes, this will need to be expanded. 2160b57cec5SDimitry Andric assert(MO.isMBB() && "Branch with unknown expandable field type"); 2170b57cec5SDimitry Andric // Mark given operand as extended. 2180b57cec5SDimitry Andric MO.addTargetFlag(HexagonII::HMOTF_ConstExtended); 2190b57cec5SDimitry Andric Changed = true; 2200b57cec5SDimitry Andric } 2210b57cec5SDimitry Andric } 2220b57cec5SDimitry Andric } 2230b57cec5SDimitry Andric return Changed; 2240b57cec5SDimitry Andric } 225