blob: 84af4b14b9f7dc6ed5d077af8af319354fabeb6a [file] [log] [blame]
Krzysztof Parzyszek7b59ae22016-04-19 18:30:18 +00001//===--- HexagonBranchRelaxation.cpp - Identify and relax long jumps ------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#define DEBUG_TYPE "hexagon-brelax"
11
12#include "Hexagon.h"
13#include "HexagonInstrInfo.h"
14#include "HexagonSubtarget.h"
Krzysztof Parzyszek7b59ae22016-04-19 18:30:18 +000015#include "llvm/ADT/DenseMap.h"
Eugene Zelenko82085922016-12-13 22:13:50 +000016#include "llvm/ADT/SmallVector.h"
17#include "llvm/ADT/StringRef.h"
18#include "llvm/CodeGen/MachineBasicBlock.h"
Krzysztof Parzyszek7b59ae22016-04-19 18:30:18 +000019#include "llvm/CodeGen/MachineFunction.h"
20#include "llvm/CodeGen/MachineFunctionPass.h"
Eugene Zelenko82085922016-12-13 22:13:50 +000021#include "llvm/CodeGen/MachineInstr.h"
22#include "llvm/CodeGen/MachineOperand.h"
Krzysztof Parzyszek7b59ae22016-04-19 18:30:18 +000023#include "llvm/CodeGen/Passes.h"
Eugene Zelenko82085922016-12-13 22:13:50 +000024#include "llvm/Pass.h"
Krzysztof Parzyszek7b59ae22016-04-19 18:30:18 +000025#include "llvm/Support/CommandLine.h"
26#include "llvm/Support/Debug.h"
27#include "llvm/Support/raw_ostream.h"
Eugene Zelenko82085922016-12-13 22:13:50 +000028#include <cassert>
29#include <cstdint>
30#include <cstdlib>
31#include <iterator>
Krzysztof Parzyszek7b59ae22016-04-19 18:30:18 +000032
33using namespace llvm;
34
35// Since we have no exact knowledge of code layout, allow some safety buffer
36// for jump target. This is measured in bytes.
37static cl::opt<uint32_t> BranchRelaxSafetyBuffer("branch-relax-safety-buffer",
38 cl::init(200), cl::Hidden, cl::ZeroOrMore, cl::desc("safety buffer size"));
39
40namespace llvm {
Eugene Zelenko82085922016-12-13 22:13:50 +000041
Krzysztof Parzyszek7b59ae22016-04-19 18:30:18 +000042 FunctionPass *createHexagonBranchRelaxation();
43 void initializeHexagonBranchRelaxationPass(PassRegistry&);
Eugene Zelenko82085922016-12-13 22:13:50 +000044
45} // end namespace llvm
Krzysztof Parzyszek7b59ae22016-04-19 18:30:18 +000046
47namespace {
Eugene Zelenko82085922016-12-13 22:13:50 +000048
Krzysztof Parzyszek7b59ae22016-04-19 18:30:18 +000049 struct HexagonBranchRelaxation : public MachineFunctionPass {
50 public:
51 static char ID;
Eugene Zelenko82085922016-12-13 22:13:50 +000052
Krzysztof Parzyszek7b59ae22016-04-19 18:30:18 +000053 HexagonBranchRelaxation() : MachineFunctionPass(ID) {
54 initializeHexagonBranchRelaxationPass(*PassRegistry::getPassRegistry());
55 }
56
57 bool runOnMachineFunction(MachineFunction &MF) override;
58
Mehdi Amini117296c2016-10-01 02:56:57 +000059 StringRef getPassName() const override {
Krzysztof Parzyszek7b59ae22016-04-19 18:30:18 +000060 return "Hexagon Branch Relaxation";
61 }
62
63 void getAnalysisUsage(AnalysisUsage &AU) const override {
64 AU.setPreservesCFG();
65 MachineFunctionPass::getAnalysisUsage(AU);
66 }
67
68 private:
69 const HexagonInstrInfo *HII;
70 const HexagonRegisterInfo *HRI;
71
72 bool relaxBranches(MachineFunction &MF);
73 void computeOffset(MachineFunction &MF,
74 DenseMap<MachineBasicBlock*, unsigned> &BlockToInstOffset);
75 bool reGenerateBranch(MachineFunction &MF,
76 DenseMap<MachineBasicBlock*, unsigned> &BlockToInstOffset);
77 bool isJumpOutOfRange(MachineInstr &MI,
78 DenseMap<MachineBasicBlock*, unsigned> &BlockToInstOffset);
79 };
80
81 char HexagonBranchRelaxation::ID = 0;
Eugene Zelenko82085922016-12-13 22:13:50 +000082
Krzysztof Parzyszek7b59ae22016-04-19 18:30:18 +000083} // end anonymous namespace
84
85INITIALIZE_PASS(HexagonBranchRelaxation, "hexagon-brelax",
86 "Hexagon Branch Relaxation", false, false)
87
88FunctionPass *llvm::createHexagonBranchRelaxation() {
89 return new HexagonBranchRelaxation();
90}
91
Krzysztof Parzyszek7b59ae22016-04-19 18:30:18 +000092bool HexagonBranchRelaxation::runOnMachineFunction(MachineFunction &MF) {
93 DEBUG(dbgs() << "****** Hexagon Branch Relaxation ******\n");
94
95 auto &HST = MF.getSubtarget<HexagonSubtarget>();
96 HII = HST.getInstrInfo();
97 HRI = HST.getRegisterInfo();
98
99 bool Changed = false;
100 Changed = relaxBranches(MF);
101 return Changed;
102}
103
Krzysztof Parzyszek7b59ae22016-04-19 18:30:18 +0000104void HexagonBranchRelaxation::computeOffset(MachineFunction &MF,
105 DenseMap<MachineBasicBlock*, unsigned> &OffsetMap) {
106 // offset of the current instruction from the start.
107 unsigned InstOffset = 0;
108 for (auto &B : MF) {
109 if (B.getAlignment()) {
110 // Although we don't know the exact layout of the final code, we need
111 // to account for alignment padding somehow. This heuristic pads each
112 // aligned basic block according to the alignment value.
113 int ByteAlign = (1u << B.getAlignment()) - 1;
114 InstOffset = (InstOffset + ByteAlign) & ~(ByteAlign);
115 }
116 OffsetMap[&B] = InstOffset;
117 for (auto &MI : B.instrs())
Krzysztof Parzyszekf0b34a52016-07-29 21:49:42 +0000118 InstOffset += HII->getSize(MI);
Krzysztof Parzyszek7b59ae22016-04-19 18:30:18 +0000119 }
120}
121
Krzysztof Parzyszek7b59ae22016-04-19 18:30:18 +0000122/// relaxBranches - For Hexagon, if the jump target/loop label is too far from
123/// the jump/loop instruction then, we need to make sure that we have constant
124/// extenders set for jumps and loops.
125
126/// There are six iterations in this phase. It's self explanatory below.
127bool HexagonBranchRelaxation::relaxBranches(MachineFunction &MF) {
128 // Compute the offset of each basic block
129 // offset of the current instruction from the start.
130 // map for each instruction to the beginning of the function
131 DenseMap<MachineBasicBlock*, unsigned> BlockToInstOffset;
132 computeOffset(MF, BlockToInstOffset);
133
134 return reGenerateBranch(MF, BlockToInstOffset);
135}
136
Krzysztof Parzyszek7b59ae22016-04-19 18:30:18 +0000137/// Check if a given instruction is:
138/// - a jump to a distant target
139/// - that exceeds its immediate range
140/// If both conditions are true, it requires constant extension.
141bool HexagonBranchRelaxation::isJumpOutOfRange(MachineInstr &MI,
142 DenseMap<MachineBasicBlock*, unsigned> &BlockToInstOffset) {
143 MachineBasicBlock &B = *MI.getParent();
144 auto FirstTerm = B.getFirstInstrTerminator();
145 if (FirstTerm == B.instr_end())
146 return false;
147
148 unsigned InstOffset = BlockToInstOffset[&B];
149 unsigned Distance = 0;
150
151 // To save time, estimate exact position of a branch instruction
152 // as one at the end of the MBB.
153 // Number of instructions times typical instruction size.
154 InstOffset += HII->nonDbgBBSize(&B) * HEXAGON_INSTR_SIZE;
155
Eugene Zelenko82085922016-12-13 22:13:50 +0000156 MachineBasicBlock *TBB = nullptr, *FBB = nullptr;
Krzysztof Parzyszek7b59ae22016-04-19 18:30:18 +0000157 SmallVector<MachineOperand, 4> Cond;
158
159 // Try to analyze this branch.
Jacques Pienaar71c30a12016-07-15 14:41:04 +0000160 if (HII->analyzeBranch(B, TBB, FBB, Cond, false)) {
Krzysztof Parzyszek7b59ae22016-04-19 18:30:18 +0000161 // Could not analyze it. See if this is something we can recognize.
162 // If it is a NVJ, it should always have its target in
163 // a fixed location.
Krzysztof Parzyszekf0b34a52016-07-29 21:49:42 +0000164 if (HII->isNewValueJump(*FirstTerm))
165 TBB = FirstTerm->getOperand(HII->getCExtOpNum(*FirstTerm)).getMBB();
Krzysztof Parzyszek7b59ae22016-04-19 18:30:18 +0000166 }
167 if (TBB && &MI == &*FirstTerm) {
168 Distance = std::abs((long long)InstOffset - BlockToInstOffset[TBB])
169 + BranchRelaxSafetyBuffer;
Krzysztof Parzyszekf0b34a52016-07-29 21:49:42 +0000170 return !HII->isJumpWithinBranchRange(*FirstTerm, Distance);
Krzysztof Parzyszek7b59ae22016-04-19 18:30:18 +0000171 }
172 if (FBB) {
173 // Look for second terminator.
174 auto SecondTerm = std::next(FirstTerm);
175 assert(SecondTerm != B.instr_end() &&
176 (SecondTerm->isBranch() || SecondTerm->isCall()) &&
177 "Bad second terminator");
178 if (&MI != &*SecondTerm)
179 return false;
180 // Analyze the second branch in the BB.
181 Distance = std::abs((long long)InstOffset - BlockToInstOffset[FBB])
182 + BranchRelaxSafetyBuffer;
Krzysztof Parzyszekf0b34a52016-07-29 21:49:42 +0000183 return !HII->isJumpWithinBranchRange(*SecondTerm, Distance);
Krzysztof Parzyszek7b59ae22016-04-19 18:30:18 +0000184 }
185 return false;
186}
187
Krzysztof Parzyszek7b59ae22016-04-19 18:30:18 +0000188bool HexagonBranchRelaxation::reGenerateBranch(MachineFunction &MF,
189 DenseMap<MachineBasicBlock*, unsigned> &BlockToInstOffset) {
190 bool Changed = false;
191
192 for (auto &B : MF) {
193 for (auto &MI : B) {
194 if (!MI.isBranch() || !isJumpOutOfRange(MI, BlockToInstOffset))
195 continue;
196 DEBUG(dbgs() << "Long distance jump. isExtendable("
Krzysztof Parzyszekf0b34a52016-07-29 21:49:42 +0000197 << HII->isExtendable(MI) << ") isConstExtended("
198 << HII->isConstExtended(MI) << ") " << MI);
Krzysztof Parzyszek7b59ae22016-04-19 18:30:18 +0000199
200 // Since we have not merged HW loops relaxation into
201 // this code (yet), soften our approach for the moment.
Krzysztof Parzyszekf0b34a52016-07-29 21:49:42 +0000202 if (!HII->isExtendable(MI) && !HII->isExtended(MI)) {
Krzysztof Parzyszek7b59ae22016-04-19 18:30:18 +0000203 DEBUG(dbgs() << "\tUnderimplemented relax branch instruction.\n");
204 } else {
205 // Find which operand is expandable.
Krzysztof Parzyszekf0b34a52016-07-29 21:49:42 +0000206 int ExtOpNum = HII->getCExtOpNum(MI);
Krzysztof Parzyszek7b59ae22016-04-19 18:30:18 +0000207 MachineOperand &MO = MI.getOperand(ExtOpNum);
208 // This need to be something we understand. So far we assume all
209 // branches have only MBB address as expandable field.
210 // If it changes, this will need to be expanded.
211 assert(MO.isMBB() && "Branch with unknown expandable field type");
212 // Mark given operand as extended.
213 MO.addTargetFlag(HexagonII::HMOTF_ConstExtended);
214 Changed = true;
215 }
216 }
217 }
218 return Changed;
219}