blob: 6891455631a80b18143f1d8d4ae1482342b93210 [file] [log] [blame]
Krzysztof Parzyszek7b59ae22016-04-19 18:30:18 +00001//===--- HexagonBranchRelaxation.cpp - Identify and relax long jumps ------===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
Krzysztof Parzyszek7b59ae22016-04-19 18:30:18 +00006//
7//===----------------------------------------------------------------------===//
8
9#define DEBUG_TYPE "hexagon-brelax"
10
11#include "Hexagon.h"
12#include "HexagonInstrInfo.h"
13#include "HexagonSubtarget.h"
Krzysztof Parzyszek7b59ae22016-04-19 18:30:18 +000014#include "llvm/ADT/DenseMap.h"
Eugene Zelenko82085922016-12-13 22:13:50 +000015#include "llvm/ADT/SmallVector.h"
16#include "llvm/ADT/StringRef.h"
17#include "llvm/CodeGen/MachineBasicBlock.h"
Krzysztof Parzyszek7b59ae22016-04-19 18:30:18 +000018#include "llvm/CodeGen/MachineFunction.h"
19#include "llvm/CodeGen/MachineFunctionPass.h"
Eugene Zelenko82085922016-12-13 22:13:50 +000020#include "llvm/CodeGen/MachineInstr.h"
21#include "llvm/CodeGen/MachineOperand.h"
Krzysztof Parzyszek7b59ae22016-04-19 18:30:18 +000022#include "llvm/CodeGen/Passes.h"
Eugene Zelenko82085922016-12-13 22:13:50 +000023#include "llvm/Pass.h"
Krzysztof Parzyszek7b59ae22016-04-19 18:30:18 +000024#include "llvm/Support/CommandLine.h"
25#include "llvm/Support/Debug.h"
26#include "llvm/Support/raw_ostream.h"
Eugene Zelenko82085922016-12-13 22:13:50 +000027#include <cassert>
28#include <cstdint>
29#include <cstdlib>
30#include <iterator>
Krzysztof Parzyszek7b59ae22016-04-19 18:30:18 +000031
32using namespace llvm;
33
34// Since we have no exact knowledge of code layout, allow some safety buffer
35// for jump target. This is measured in bytes.
36static cl::opt<uint32_t> BranchRelaxSafetyBuffer("branch-relax-safety-buffer",
37 cl::init(200), cl::Hidden, cl::ZeroOrMore, cl::desc("safety buffer size"));
38
39namespace llvm {
Eugene Zelenko82085922016-12-13 22:13:50 +000040
Krzysztof Parzyszek7b59ae22016-04-19 18:30:18 +000041 FunctionPass *createHexagonBranchRelaxation();
42 void initializeHexagonBranchRelaxationPass(PassRegistry&);
Eugene Zelenko82085922016-12-13 22:13:50 +000043
44} // end namespace llvm
Krzysztof Parzyszek7b59ae22016-04-19 18:30:18 +000045
46namespace {
Eugene Zelenko82085922016-12-13 22:13:50 +000047
Krzysztof Parzyszek7b59ae22016-04-19 18:30:18 +000048 struct HexagonBranchRelaxation : public MachineFunctionPass {
49 public:
50 static char ID;
Eugene Zelenko82085922016-12-13 22:13:50 +000051
Krzysztof Parzyszek7b59ae22016-04-19 18:30:18 +000052 HexagonBranchRelaxation() : MachineFunctionPass(ID) {
53 initializeHexagonBranchRelaxationPass(*PassRegistry::getPassRegistry());
54 }
55
56 bool runOnMachineFunction(MachineFunction &MF) override;
57
Mehdi Amini117296c2016-10-01 02:56:57 +000058 StringRef getPassName() const override {
Krzysztof Parzyszek7b59ae22016-04-19 18:30:18 +000059 return "Hexagon Branch Relaxation";
60 }
61
62 void getAnalysisUsage(AnalysisUsage &AU) const override {
63 AU.setPreservesCFG();
64 MachineFunctionPass::getAnalysisUsage(AU);
65 }
66
67 private:
68 const HexagonInstrInfo *HII;
69 const HexagonRegisterInfo *HRI;
70
71 bool relaxBranches(MachineFunction &MF);
72 void computeOffset(MachineFunction &MF,
73 DenseMap<MachineBasicBlock*, unsigned> &BlockToInstOffset);
74 bool reGenerateBranch(MachineFunction &MF,
75 DenseMap<MachineBasicBlock*, unsigned> &BlockToInstOffset);
76 bool isJumpOutOfRange(MachineInstr &MI,
77 DenseMap<MachineBasicBlock*, unsigned> &BlockToInstOffset);
78 };
79
80 char HexagonBranchRelaxation::ID = 0;
Eugene Zelenko82085922016-12-13 22:13:50 +000081
Krzysztof Parzyszek7b59ae22016-04-19 18:30:18 +000082} // end anonymous namespace
83
84INITIALIZE_PASS(HexagonBranchRelaxation, "hexagon-brelax",
85 "Hexagon Branch Relaxation", false, false)
86
87FunctionPass *llvm::createHexagonBranchRelaxation() {
88 return new HexagonBranchRelaxation();
89}
90
Krzysztof Parzyszek7b59ae22016-04-19 18:30:18 +000091bool HexagonBranchRelaxation::runOnMachineFunction(MachineFunction &MF) {
Nicola Zaghend34e60c2018-05-14 12:53:11 +000092 LLVM_DEBUG(dbgs() << "****** Hexagon Branch Relaxation ******\n");
Krzysztof Parzyszek7b59ae22016-04-19 18:30:18 +000093
94 auto &HST = MF.getSubtarget<HexagonSubtarget>();
95 HII = HST.getInstrInfo();
96 HRI = HST.getRegisterInfo();
97
98 bool Changed = false;
99 Changed = relaxBranches(MF);
100 return Changed;
101}
102
Krzysztof Parzyszek7b59ae22016-04-19 18:30:18 +0000103void HexagonBranchRelaxation::computeOffset(MachineFunction &MF,
104 DenseMap<MachineBasicBlock*, unsigned> &OffsetMap) {
105 // offset of the current instruction from the start.
106 unsigned InstOffset = 0;
107 for (auto &B : MF) {
Guillaume Chatelet805c1572020-01-21 15:00:04 +0100108 if (B.getAlignment() != Align(1)) {
Krzysztof Parzyszek7b59ae22016-04-19 18:30:18 +0000109 // Although we don't know the exact layout of the final code, we need
110 // to account for alignment padding somehow. This heuristic pads each
111 // aligned basic block according to the alignment value.
Guillaume Chateletd4c46712019-09-18 15:49:49 +0000112 InstOffset = alignTo(InstOffset, B.getAlignment());
Krzysztof Parzyszek7b59ae22016-04-19 18:30:18 +0000113 }
114 OffsetMap[&B] = InstOffset;
Krzysztof Parzyszekca93f5e2018-03-23 19:47:13 +0000115 for (auto &MI : B.instrs()) {
Krzysztof Parzyszekf0b34a52016-07-29 21:49:42 +0000116 InstOffset += HII->getSize(MI);
Krzysztof Parzyszekca93f5e2018-03-23 19:47:13 +0000117 // Assume that all extendable branches will be extended.
118 if (MI.isBranch() && HII->isExtendable(MI))
119 InstOffset += HEXAGON_INSTR_SIZE;
120 }
Krzysztof Parzyszek7b59ae22016-04-19 18:30:18 +0000121 }
122}
123
Krzysztof Parzyszek7b59ae22016-04-19 18:30:18 +0000124/// relaxBranches - For Hexagon, if the jump target/loop label is too far from
125/// the jump/loop instruction then, we need to make sure that we have constant
126/// extenders set for jumps and loops.
127
128/// There are six iterations in this phase. It's self explanatory below.
129bool HexagonBranchRelaxation::relaxBranches(MachineFunction &MF) {
130 // Compute the offset of each basic block
131 // offset of the current instruction from the start.
132 // map for each instruction to the beginning of the function
133 DenseMap<MachineBasicBlock*, unsigned> BlockToInstOffset;
134 computeOffset(MF, BlockToInstOffset);
135
136 return reGenerateBranch(MF, BlockToInstOffset);
137}
138
Krzysztof Parzyszek7b59ae22016-04-19 18:30:18 +0000139/// Check if a given instruction is:
140/// - a jump to a distant target
141/// - that exceeds its immediate range
142/// If both conditions are true, it requires constant extension.
143bool HexagonBranchRelaxation::isJumpOutOfRange(MachineInstr &MI,
144 DenseMap<MachineBasicBlock*, unsigned> &BlockToInstOffset) {
145 MachineBasicBlock &B = *MI.getParent();
146 auto FirstTerm = B.getFirstInstrTerminator();
147 if (FirstTerm == B.instr_end())
148 return false;
149
Krzysztof Parzyszekca93f5e2018-03-23 19:47:13 +0000150 if (HII->isExtended(MI))
151 return false;
152
Krzysztof Parzyszek7b59ae22016-04-19 18:30:18 +0000153 unsigned InstOffset = BlockToInstOffset[&B];
154 unsigned Distance = 0;
155
156 // To save time, estimate exact position of a branch instruction
157 // as one at the end of the MBB.
158 // Number of instructions times typical instruction size.
159 InstOffset += HII->nonDbgBBSize(&B) * HEXAGON_INSTR_SIZE;
160
Eugene Zelenko82085922016-12-13 22:13:50 +0000161 MachineBasicBlock *TBB = nullptr, *FBB = nullptr;
Krzysztof Parzyszek7b59ae22016-04-19 18:30:18 +0000162 SmallVector<MachineOperand, 4> Cond;
163
164 // Try to analyze this branch.
Jacques Pienaar71c30a12016-07-15 14:41:04 +0000165 if (HII->analyzeBranch(B, TBB, FBB, Cond, false)) {
Krzysztof Parzyszek7b59ae22016-04-19 18:30:18 +0000166 // Could not analyze it. See if this is something we can recognize.
167 // If it is a NVJ, it should always have its target in
168 // a fixed location.
Krzysztof Parzyszekf0b34a52016-07-29 21:49:42 +0000169 if (HII->isNewValueJump(*FirstTerm))
170 TBB = FirstTerm->getOperand(HII->getCExtOpNum(*FirstTerm)).getMBB();
Krzysztof Parzyszek7b59ae22016-04-19 18:30:18 +0000171 }
172 if (TBB && &MI == &*FirstTerm) {
173 Distance = std::abs((long long)InstOffset - BlockToInstOffset[TBB])
174 + BranchRelaxSafetyBuffer;
Krzysztof Parzyszekf0b34a52016-07-29 21:49:42 +0000175 return !HII->isJumpWithinBranchRange(*FirstTerm, Distance);
Krzysztof Parzyszek7b59ae22016-04-19 18:30:18 +0000176 }
177 if (FBB) {
178 // Look for second terminator.
179 auto SecondTerm = std::next(FirstTerm);
180 assert(SecondTerm != B.instr_end() &&
181 (SecondTerm->isBranch() || SecondTerm->isCall()) &&
182 "Bad second terminator");
183 if (&MI != &*SecondTerm)
184 return false;
185 // Analyze the second branch in the BB.
186 Distance = std::abs((long long)InstOffset - BlockToInstOffset[FBB])
187 + BranchRelaxSafetyBuffer;
Krzysztof Parzyszekf0b34a52016-07-29 21:49:42 +0000188 return !HII->isJumpWithinBranchRange(*SecondTerm, Distance);
Krzysztof Parzyszek7b59ae22016-04-19 18:30:18 +0000189 }
190 return false;
191}
192
Krzysztof Parzyszek7b59ae22016-04-19 18:30:18 +0000193bool HexagonBranchRelaxation::reGenerateBranch(MachineFunction &MF,
194 DenseMap<MachineBasicBlock*, unsigned> &BlockToInstOffset) {
195 bool Changed = false;
196
197 for (auto &B : MF) {
198 for (auto &MI : B) {
199 if (!MI.isBranch() || !isJumpOutOfRange(MI, BlockToInstOffset))
200 continue;
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000201 LLVM_DEBUG(dbgs() << "Long distance jump. isExtendable("
202 << HII->isExtendable(MI) << ") isConstExtended("
203 << HII->isConstExtended(MI) << ") " << MI);
Krzysztof Parzyszek7b59ae22016-04-19 18:30:18 +0000204
205 // Since we have not merged HW loops relaxation into
206 // this code (yet), soften our approach for the moment.
Krzysztof Parzyszekf0b34a52016-07-29 21:49:42 +0000207 if (!HII->isExtendable(MI) && !HII->isExtended(MI)) {
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000208 LLVM_DEBUG(dbgs() << "\tUnderimplemented relax branch instruction.\n");
Krzysztof Parzyszek7b59ae22016-04-19 18:30:18 +0000209 } else {
210 // Find which operand is expandable.
Krzysztof Parzyszekf0b34a52016-07-29 21:49:42 +0000211 int ExtOpNum = HII->getCExtOpNum(MI);
Krzysztof Parzyszek7b59ae22016-04-19 18:30:18 +0000212 MachineOperand &MO = MI.getOperand(ExtOpNum);
213 // This need to be something we understand. So far we assume all
214 // branches have only MBB address as expandable field.
215 // If it changes, this will need to be expanded.
216 assert(MO.isMBB() && "Branch with unknown expandable field type");
217 // Mark given operand as extended.
218 MO.addTargetFlag(HexagonII::HMOTF_ConstExtended);
219 Changed = true;
220 }
221 }
222 }
223 return Changed;
224}