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