MSP430BranchSelector.cpp
8.62 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
//===-- MSP430BranchSelector.cpp - Emit long conditional branches ---------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file contains a pass that scans a machine function to determine which
// conditional branches need more than 10 bits of displacement to reach their
// target basic block. It does this in two passes; a calculation of basic block
// positions pass, and a branch pseudo op to machine branch opcode pass. This
// pass should be run last, just before the assembly printer.
//
//===----------------------------------------------------------------------===//
#include "MSP430.h"
#include "MSP430InstrInfo.h"
#include "MSP430Subtarget.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Target/TargetMachine.h"
using namespace llvm;
#define DEBUG_TYPE "msp430-branch-select"
static cl::opt<bool>
BranchSelectEnabled("msp430-branch-select", cl::Hidden, cl::init(true),
cl::desc("Expand out of range branches"));
STATISTIC(NumSplit, "Number of machine basic blocks split");
STATISTIC(NumExpanded, "Number of branches expanded to long format");
namespace {
class MSP430BSel : public MachineFunctionPass {
typedef SmallVector<int, 16> OffsetVector;
MachineFunction *MF;
const MSP430InstrInfo *TII;
unsigned measureFunction(OffsetVector &BlockOffsets,
MachineBasicBlock *FromBB = nullptr);
bool expandBranches(OffsetVector &BlockOffsets);
public:
static char ID;
MSP430BSel() : MachineFunctionPass(ID) {}
bool runOnMachineFunction(MachineFunction &MF) override;
MachineFunctionProperties getRequiredProperties() const override {
return MachineFunctionProperties().set(
MachineFunctionProperties::Property::NoVRegs);
}
StringRef getPassName() const override { return "MSP430 Branch Selector"; }
};
char MSP430BSel::ID = 0;
}
static bool isInRage(int DistanceInBytes) {
// According to CC430 Family User's Guide, Section 4.5.1.3, branch
// instructions have the signed 10-bit word offset field, so first we need to
// convert the distance from bytes to words, then check if it fits in 10-bit
// signed integer.
const int WordSize = 2;
assert((DistanceInBytes % WordSize == 0) &&
"Branch offset should be word aligned!");
int Words = DistanceInBytes / WordSize;
return isInt<10>(Words);
}
/// Measure each basic block, fill the BlockOffsets, and return the size of
/// the function, starting with BB
unsigned MSP430BSel::measureFunction(OffsetVector &BlockOffsets,
MachineBasicBlock *FromBB) {
// Give the blocks of the function a dense, in-order, numbering.
MF->RenumberBlocks(FromBB);
MachineFunction::iterator Begin;
if (FromBB == nullptr) {
Begin = MF->begin();
} else {
Begin = FromBB->getIterator();
}
BlockOffsets.resize(MF->getNumBlockIDs());
unsigned TotalSize = BlockOffsets[Begin->getNumber()];
for (auto &MBB : make_range(Begin, MF->end())) {
BlockOffsets[MBB.getNumber()] = TotalSize;
for (MachineInstr &MI : MBB) {
TotalSize += TII->getInstSizeInBytes(MI);
}
}
return TotalSize;
}
/// Do expand branches and split the basic blocks if necessary.
/// Returns true if made any change.
bool MSP430BSel::expandBranches(OffsetVector &BlockOffsets) {
// For each conditional branch, if the offset to its destination is larger
// than the offset field allows, transform it into a long branch sequence
// like this:
// short branch:
// bCC MBB
// long branch:
// b!CC $PC+6
// b MBB
//
bool MadeChange = false;
for (auto MBB = MF->begin(), E = MF->end(); MBB != E; ++MBB) {
unsigned MBBStartOffset = 0;
for (auto MI = MBB->begin(), EE = MBB->end(); MI != EE; ++MI) {
MBBStartOffset += TII->getInstSizeInBytes(*MI);
// If this instruction is not a short branch then skip it.
if (MI->getOpcode() != MSP430::JCC && MI->getOpcode() != MSP430::JMP) {
continue;
}
MachineBasicBlock *DestBB = MI->getOperand(0).getMBB();
// Determine the distance from the current branch to the destination
// block. MBBStartOffset already includes the size of the current branch
// instruction.
int BlockDistance =
BlockOffsets[DestBB->getNumber()] - BlockOffsets[MBB->getNumber()];
int BranchDistance = BlockDistance - MBBStartOffset;
// If this branch is in range, ignore it.
if (isInRage(BranchDistance)) {
continue;
}
LLVM_DEBUG(dbgs() << " Found a branch that needs expanding, "
<< printMBBReference(*DestBB) << ", Distance "
<< BranchDistance << "\n");
// If JCC is not the last instruction we need to split the MBB.
if (MI->getOpcode() == MSP430::JCC && std::next(MI) != EE) {
LLVM_DEBUG(dbgs() << " Found a basic block that needs to be split, "
<< printMBBReference(*MBB) << "\n");
// Create a new basic block.
MachineBasicBlock *NewBB =
MF->CreateMachineBasicBlock(MBB->getBasicBlock());
MF->insert(std::next(MBB), NewBB);
// Splice the instructions following MI over to the NewBB.
NewBB->splice(NewBB->end(), &*MBB, std::next(MI), MBB->end());
// Update the successor lists.
for (MachineBasicBlock *Succ : MBB->successors()) {
if (Succ == DestBB) {
continue;
}
MBB->replaceSuccessor(Succ, NewBB);
NewBB->addSuccessor(Succ);
}
// We introduced a new MBB so all following blocks should be numbered
// and measured again.
measureFunction(BlockOffsets, &*MBB);
++NumSplit;
// It may be not necessary to start all over at this point, but it's
// safer do this anyway.
return true;
}
MachineInstr &OldBranch = *MI;
DebugLoc dl = OldBranch.getDebugLoc();
int InstrSizeDiff = -TII->getInstSizeInBytes(OldBranch);
if (MI->getOpcode() == MSP430::JCC) {
MachineBasicBlock *NextMBB = &*std::next(MBB);
assert(MBB->isSuccessor(NextMBB) &&
"This block must have a layout successor!");
// The BCC operands are:
// 0. Target MBB
// 1. MSP430 branch predicate
SmallVector<MachineOperand, 1> Cond;
Cond.push_back(MI->getOperand(1));
// Jump over the long branch on the opposite condition
TII->reverseBranchCondition(Cond);
MI = BuildMI(*MBB, MI, dl, TII->get(MSP430::JCC))
.addMBB(NextMBB)
.add(Cond[0]);
InstrSizeDiff += TII->getInstSizeInBytes(*MI);
++MI;
}
// Unconditional branch to the real destination.
MI = BuildMI(*MBB, MI, dl, TII->get(MSP430::Bi)).addMBB(DestBB);
InstrSizeDiff += TII->getInstSizeInBytes(*MI);
// Remove the old branch from the function.
OldBranch.eraseFromParent();
// The size of a new instruction is different from the old one, so we need
// to correct all block offsets.
for (int i = MBB->getNumber() + 1, e = BlockOffsets.size(); i < e; ++i) {
BlockOffsets[i] += InstrSizeDiff;
}
MBBStartOffset += InstrSizeDiff;
++NumExpanded;
MadeChange = true;
}
}
return MadeChange;
}
bool MSP430BSel::runOnMachineFunction(MachineFunction &mf) {
MF = &mf;
TII = static_cast<const MSP430InstrInfo *>(MF->getSubtarget().getInstrInfo());
// If the pass is disabled, just bail early.
if (!BranchSelectEnabled)
return false;
LLVM_DEBUG(dbgs() << "\n********** " << getPassName() << " **********\n");
// BlockOffsets - Contains the distance from the beginning of the function to
// the beginning of each basic block.
OffsetVector BlockOffsets;
unsigned FunctionSize = measureFunction(BlockOffsets);
// If the entire function is smaller than the displacement of a branch field,
// we know we don't need to expand any branches in this
// function. This is a common case.
if (isInRage(FunctionSize)) {
return false;
}
// Iteratively expand branches until we reach a fixed point.
bool MadeChange = false;
while (expandBranches(BlockOffsets))
MadeChange = true;
return MadeChange;
}
/// Returns an instance of the Branch Selection Pass
FunctionPass *llvm::createMSP430BranchSelectionPass() {
return new MSP430BSel();
}