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