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