xref: /freebsd/contrib/llvm-project/llvm/lib/Target/Hexagon/HexagonBranchRelaxation.cpp (revision 0b57cec536236d46e3dba9bd041533462f33dbb7)
1*0b57cec5SDimitry Andric //===--- HexagonBranchRelaxation.cpp - Identify and relax long jumps ------===//
2*0b57cec5SDimitry Andric //
3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric //
7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric 
9*0b57cec5SDimitry Andric #define DEBUG_TYPE "hexagon-brelax"
10*0b57cec5SDimitry Andric 
11*0b57cec5SDimitry Andric #include "Hexagon.h"
12*0b57cec5SDimitry Andric #include "HexagonInstrInfo.h"
13*0b57cec5SDimitry Andric #include "HexagonSubtarget.h"
14*0b57cec5SDimitry Andric #include "llvm/ADT/DenseMap.h"
15*0b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h"
16*0b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h"
17*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineBasicBlock.h"
18*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunction.h"
19*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h"
20*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstr.h"
21*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineOperand.h"
22*0b57cec5SDimitry Andric #include "llvm/CodeGen/Passes.h"
23*0b57cec5SDimitry Andric #include "llvm/Pass.h"
24*0b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h"
25*0b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
26*0b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
27*0b57cec5SDimitry Andric #include <cassert>
28*0b57cec5SDimitry Andric #include <cstdint>
29*0b57cec5SDimitry Andric #include <cstdlib>
30*0b57cec5SDimitry Andric #include <iterator>
31*0b57cec5SDimitry Andric 
32*0b57cec5SDimitry Andric using namespace llvm;
33*0b57cec5SDimitry Andric 
34*0b57cec5SDimitry Andric // Since we have no exact knowledge of code layout, allow some safety buffer
35*0b57cec5SDimitry Andric // for jump target. This is measured in bytes.
36*0b57cec5SDimitry Andric static cl::opt<uint32_t> BranchRelaxSafetyBuffer("branch-relax-safety-buffer",
37*0b57cec5SDimitry Andric   cl::init(200), cl::Hidden, cl::ZeroOrMore, cl::desc("safety buffer size"));
38*0b57cec5SDimitry Andric 
39*0b57cec5SDimitry Andric namespace llvm {
40*0b57cec5SDimitry Andric 
41*0b57cec5SDimitry Andric   FunctionPass *createHexagonBranchRelaxation();
42*0b57cec5SDimitry Andric   void initializeHexagonBranchRelaxationPass(PassRegistry&);
43*0b57cec5SDimitry Andric 
44*0b57cec5SDimitry Andric } // end namespace llvm
45*0b57cec5SDimitry Andric 
46*0b57cec5SDimitry Andric namespace {
47*0b57cec5SDimitry Andric 
48*0b57cec5SDimitry Andric   struct HexagonBranchRelaxation : public MachineFunctionPass {
49*0b57cec5SDimitry Andric   public:
50*0b57cec5SDimitry Andric     static char ID;
51*0b57cec5SDimitry Andric 
52*0b57cec5SDimitry Andric     HexagonBranchRelaxation() : MachineFunctionPass(ID) {
53*0b57cec5SDimitry Andric       initializeHexagonBranchRelaxationPass(*PassRegistry::getPassRegistry());
54*0b57cec5SDimitry Andric     }
55*0b57cec5SDimitry Andric 
56*0b57cec5SDimitry Andric     bool runOnMachineFunction(MachineFunction &MF) override;
57*0b57cec5SDimitry Andric 
58*0b57cec5SDimitry Andric     StringRef getPassName() const override {
59*0b57cec5SDimitry Andric       return "Hexagon Branch Relaxation";
60*0b57cec5SDimitry Andric     }
61*0b57cec5SDimitry Andric 
62*0b57cec5SDimitry Andric     void getAnalysisUsage(AnalysisUsage &AU) const override {
63*0b57cec5SDimitry Andric       AU.setPreservesCFG();
64*0b57cec5SDimitry Andric       MachineFunctionPass::getAnalysisUsage(AU);
65*0b57cec5SDimitry Andric     }
66*0b57cec5SDimitry Andric 
67*0b57cec5SDimitry Andric   private:
68*0b57cec5SDimitry Andric     const HexagonInstrInfo *HII;
69*0b57cec5SDimitry Andric     const HexagonRegisterInfo *HRI;
70*0b57cec5SDimitry Andric 
71*0b57cec5SDimitry Andric     bool relaxBranches(MachineFunction &MF);
72*0b57cec5SDimitry Andric     void computeOffset(MachineFunction &MF,
73*0b57cec5SDimitry Andric           DenseMap<MachineBasicBlock*, unsigned> &BlockToInstOffset);
74*0b57cec5SDimitry Andric     bool reGenerateBranch(MachineFunction &MF,
75*0b57cec5SDimitry Andric           DenseMap<MachineBasicBlock*, unsigned> &BlockToInstOffset);
76*0b57cec5SDimitry Andric     bool isJumpOutOfRange(MachineInstr &MI,
77*0b57cec5SDimitry Andric           DenseMap<MachineBasicBlock*, unsigned> &BlockToInstOffset);
78*0b57cec5SDimitry Andric   };
79*0b57cec5SDimitry Andric 
80*0b57cec5SDimitry Andric   char HexagonBranchRelaxation::ID = 0;
81*0b57cec5SDimitry Andric 
82*0b57cec5SDimitry Andric } // end anonymous namespace
83*0b57cec5SDimitry Andric 
84*0b57cec5SDimitry Andric INITIALIZE_PASS(HexagonBranchRelaxation, "hexagon-brelax",
85*0b57cec5SDimitry Andric                 "Hexagon Branch Relaxation", false, false)
86*0b57cec5SDimitry Andric 
87*0b57cec5SDimitry Andric FunctionPass *llvm::createHexagonBranchRelaxation() {
88*0b57cec5SDimitry Andric   return new HexagonBranchRelaxation();
89*0b57cec5SDimitry Andric }
90*0b57cec5SDimitry Andric 
91*0b57cec5SDimitry Andric bool HexagonBranchRelaxation::runOnMachineFunction(MachineFunction &MF) {
92*0b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "****** Hexagon Branch Relaxation ******\n");
93*0b57cec5SDimitry Andric 
94*0b57cec5SDimitry Andric   auto &HST = MF.getSubtarget<HexagonSubtarget>();
95*0b57cec5SDimitry Andric   HII = HST.getInstrInfo();
96*0b57cec5SDimitry Andric   HRI = HST.getRegisterInfo();
97*0b57cec5SDimitry Andric 
98*0b57cec5SDimitry Andric   bool Changed = false;
99*0b57cec5SDimitry Andric   Changed = relaxBranches(MF);
100*0b57cec5SDimitry Andric   return Changed;
101*0b57cec5SDimitry Andric }
102*0b57cec5SDimitry Andric 
103*0b57cec5SDimitry Andric void HexagonBranchRelaxation::computeOffset(MachineFunction &MF,
104*0b57cec5SDimitry Andric       DenseMap<MachineBasicBlock*, unsigned> &OffsetMap) {
105*0b57cec5SDimitry Andric   // offset of the current instruction from the start.
106*0b57cec5SDimitry Andric   unsigned InstOffset = 0;
107*0b57cec5SDimitry Andric   for (auto &B : MF) {
108*0b57cec5SDimitry Andric     if (B.getAlignment()) {
109*0b57cec5SDimitry Andric       // Although we don't know the exact layout of the final code, we need
110*0b57cec5SDimitry Andric       // to account for alignment padding somehow. This heuristic pads each
111*0b57cec5SDimitry Andric       // aligned basic block according to the alignment value.
112*0b57cec5SDimitry Andric       int ByteAlign = (1u << B.getAlignment()) - 1;
113*0b57cec5SDimitry Andric       InstOffset = (InstOffset + ByteAlign) & ~(ByteAlign);
114*0b57cec5SDimitry Andric     }
115*0b57cec5SDimitry Andric     OffsetMap[&B] = InstOffset;
116*0b57cec5SDimitry Andric     for (auto &MI : B.instrs()) {
117*0b57cec5SDimitry Andric       InstOffset += HII->getSize(MI);
118*0b57cec5SDimitry Andric       // Assume that all extendable branches will be extended.
119*0b57cec5SDimitry Andric       if (MI.isBranch() && HII->isExtendable(MI))
120*0b57cec5SDimitry Andric         InstOffset += HEXAGON_INSTR_SIZE;
121*0b57cec5SDimitry Andric     }
122*0b57cec5SDimitry Andric   }
123*0b57cec5SDimitry Andric }
124*0b57cec5SDimitry Andric 
125*0b57cec5SDimitry Andric /// relaxBranches - For Hexagon, if the jump target/loop label is too far from
126*0b57cec5SDimitry Andric /// the jump/loop instruction then, we need to make sure that we have constant
127*0b57cec5SDimitry Andric /// extenders set for jumps and loops.
128*0b57cec5SDimitry Andric 
129*0b57cec5SDimitry Andric /// There are six iterations in this phase. It's self explanatory below.
130*0b57cec5SDimitry Andric bool HexagonBranchRelaxation::relaxBranches(MachineFunction &MF) {
131*0b57cec5SDimitry Andric   // Compute the offset of each basic block
132*0b57cec5SDimitry Andric   // offset of the current instruction from the start.
133*0b57cec5SDimitry Andric   // map for each instruction to the beginning of the function
134*0b57cec5SDimitry Andric   DenseMap<MachineBasicBlock*, unsigned> BlockToInstOffset;
135*0b57cec5SDimitry Andric   computeOffset(MF, BlockToInstOffset);
136*0b57cec5SDimitry Andric 
137*0b57cec5SDimitry Andric   return reGenerateBranch(MF, BlockToInstOffset);
138*0b57cec5SDimitry Andric }
139*0b57cec5SDimitry Andric 
140*0b57cec5SDimitry Andric /// Check if a given instruction is:
141*0b57cec5SDimitry Andric /// - a jump to a distant target
142*0b57cec5SDimitry Andric /// - that exceeds its immediate range
143*0b57cec5SDimitry Andric /// If both conditions are true, it requires constant extension.
144*0b57cec5SDimitry Andric bool HexagonBranchRelaxation::isJumpOutOfRange(MachineInstr &MI,
145*0b57cec5SDimitry Andric       DenseMap<MachineBasicBlock*, unsigned> &BlockToInstOffset) {
146*0b57cec5SDimitry Andric   MachineBasicBlock &B = *MI.getParent();
147*0b57cec5SDimitry Andric   auto FirstTerm = B.getFirstInstrTerminator();
148*0b57cec5SDimitry Andric   if (FirstTerm == B.instr_end())
149*0b57cec5SDimitry Andric     return false;
150*0b57cec5SDimitry Andric 
151*0b57cec5SDimitry Andric   if (HII->isExtended(MI))
152*0b57cec5SDimitry Andric     return false;
153*0b57cec5SDimitry Andric 
154*0b57cec5SDimitry Andric   unsigned InstOffset = BlockToInstOffset[&B];
155*0b57cec5SDimitry Andric   unsigned Distance = 0;
156*0b57cec5SDimitry Andric 
157*0b57cec5SDimitry Andric   // To save time, estimate exact position of a branch instruction
158*0b57cec5SDimitry Andric   // as one at the end of the MBB.
159*0b57cec5SDimitry Andric   // Number of instructions times typical instruction size.
160*0b57cec5SDimitry Andric   InstOffset += HII->nonDbgBBSize(&B) * HEXAGON_INSTR_SIZE;
161*0b57cec5SDimitry Andric 
162*0b57cec5SDimitry Andric   MachineBasicBlock *TBB = nullptr, *FBB = nullptr;
163*0b57cec5SDimitry Andric   SmallVector<MachineOperand, 4> Cond;
164*0b57cec5SDimitry Andric 
165*0b57cec5SDimitry Andric   // Try to analyze this branch.
166*0b57cec5SDimitry Andric   if (HII->analyzeBranch(B, TBB, FBB, Cond, false)) {
167*0b57cec5SDimitry Andric     // Could not analyze it. See if this is something we can recognize.
168*0b57cec5SDimitry Andric     // If it is a NVJ, it should always have its target in
169*0b57cec5SDimitry Andric     // a fixed location.
170*0b57cec5SDimitry Andric     if (HII->isNewValueJump(*FirstTerm))
171*0b57cec5SDimitry Andric       TBB = FirstTerm->getOperand(HII->getCExtOpNum(*FirstTerm)).getMBB();
172*0b57cec5SDimitry Andric   }
173*0b57cec5SDimitry Andric   if (TBB && &MI == &*FirstTerm) {
174*0b57cec5SDimitry Andric     Distance = std::abs((long long)InstOffset - BlockToInstOffset[TBB])
175*0b57cec5SDimitry Andric                 + BranchRelaxSafetyBuffer;
176*0b57cec5SDimitry Andric     return !HII->isJumpWithinBranchRange(*FirstTerm, Distance);
177*0b57cec5SDimitry Andric   }
178*0b57cec5SDimitry Andric   if (FBB) {
179*0b57cec5SDimitry Andric     // Look for second terminator.
180*0b57cec5SDimitry Andric     auto SecondTerm = std::next(FirstTerm);
181*0b57cec5SDimitry Andric     assert(SecondTerm != B.instr_end() &&
182*0b57cec5SDimitry Andric           (SecondTerm->isBranch() || SecondTerm->isCall()) &&
183*0b57cec5SDimitry Andric           "Bad second terminator");
184*0b57cec5SDimitry Andric     if (&MI != &*SecondTerm)
185*0b57cec5SDimitry Andric       return false;
186*0b57cec5SDimitry Andric     // Analyze the second branch in the BB.
187*0b57cec5SDimitry Andric     Distance = std::abs((long long)InstOffset - BlockToInstOffset[FBB])
188*0b57cec5SDimitry Andric                 + BranchRelaxSafetyBuffer;
189*0b57cec5SDimitry Andric     return !HII->isJumpWithinBranchRange(*SecondTerm, Distance);
190*0b57cec5SDimitry Andric   }
191*0b57cec5SDimitry Andric   return false;
192*0b57cec5SDimitry Andric }
193*0b57cec5SDimitry Andric 
194*0b57cec5SDimitry Andric bool HexagonBranchRelaxation::reGenerateBranch(MachineFunction &MF,
195*0b57cec5SDimitry Andric       DenseMap<MachineBasicBlock*, unsigned> &BlockToInstOffset) {
196*0b57cec5SDimitry Andric   bool Changed = false;
197*0b57cec5SDimitry Andric 
198*0b57cec5SDimitry Andric   for (auto &B : MF) {
199*0b57cec5SDimitry Andric     for (auto &MI : B) {
200*0b57cec5SDimitry Andric       if (!MI.isBranch() || !isJumpOutOfRange(MI, BlockToInstOffset))
201*0b57cec5SDimitry Andric         continue;
202*0b57cec5SDimitry Andric       LLVM_DEBUG(dbgs() << "Long distance jump. isExtendable("
203*0b57cec5SDimitry Andric                         << HII->isExtendable(MI) << ") isConstExtended("
204*0b57cec5SDimitry Andric                         << HII->isConstExtended(MI) << ") " << MI);
205*0b57cec5SDimitry Andric 
206*0b57cec5SDimitry Andric       // Since we have not merged HW loops relaxation into
207*0b57cec5SDimitry Andric       // this code (yet), soften our approach for the moment.
208*0b57cec5SDimitry Andric       if (!HII->isExtendable(MI) && !HII->isExtended(MI)) {
209*0b57cec5SDimitry Andric         LLVM_DEBUG(dbgs() << "\tUnderimplemented relax branch instruction.\n");
210*0b57cec5SDimitry Andric       } else {
211*0b57cec5SDimitry Andric         // Find which operand is expandable.
212*0b57cec5SDimitry Andric         int ExtOpNum = HII->getCExtOpNum(MI);
213*0b57cec5SDimitry Andric         MachineOperand &MO = MI.getOperand(ExtOpNum);
214*0b57cec5SDimitry Andric         // This need to be something we understand. So far we assume all
215*0b57cec5SDimitry Andric         // branches have only MBB address as expandable field.
216*0b57cec5SDimitry Andric         // If it changes, this will need to be expanded.
217*0b57cec5SDimitry Andric         assert(MO.isMBB() && "Branch with unknown expandable field type");
218*0b57cec5SDimitry Andric         // Mark given operand as extended.
219*0b57cec5SDimitry Andric         MO.addTargetFlag(HexagonII::HMOTF_ConstExtended);
220*0b57cec5SDimitry Andric         Changed = true;
221*0b57cec5SDimitry Andric       }
222*0b57cec5SDimitry Andric     }
223*0b57cec5SDimitry Andric   }
224*0b57cec5SDimitry Andric   return Changed;
225*0b57cec5SDimitry Andric }
226