Skip to content

Commit 83cbab2

Browse files
committed
[SOL] Allow branch folding to run in SBF (#154)
* Implement analysis functions * Add test and fix others
1 parent d85073e commit 83cbab2

File tree

7 files changed

+381
-79
lines changed

7 files changed

+381
-79
lines changed

llvm/lib/Target/SBF/SBFInstrInfo.cpp

Lines changed: 263 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,50 @@
1818
#include "llvm/IR/DebugLoc.h"
1919
#include "llvm/Support/ErrorHandling.h"
2020
#include <cassert>
21-
#include <iterator>
2221

2322
#define GET_INSTRINFO_CTOR_DTOR
2423
#include "SBFGenInstrInfo.inc"
2524

2625
using namespace llvm;
2726

27+
static inline bool isUncondBranchOpcode(int Opc) { return Opc == SBF::JMP; }
28+
29+
static inline bool isCondBranchOpcode(int Opc) {
30+
switch (Opc) {
31+
case SBF::JEQ_ri:
32+
case SBF::JEQ_rr:
33+
case SBF::JUGT_ri:
34+
case SBF::JUGT_rr:
35+
case SBF::JUGE_ri:
36+
case SBF::JUGE_rr:
37+
case SBF::JNE_ri:
38+
case SBF::JNE_rr:
39+
case SBF::JSGT_ri:
40+
case SBF::JSGT_rr:
41+
case SBF::JSGE_ri:
42+
case SBF::JSGE_rr:
43+
case SBF::JULT_ri:
44+
case SBF::JULT_rr:
45+
case SBF::JULE_ri:
46+
case SBF::JULE_rr:
47+
case SBF::JSLT_ri:
48+
case SBF::JSLT_rr:
49+
case SBF::JSLE_ri:
50+
case SBF::JSLE_rr:
51+
return true;
52+
default:
53+
return false;
54+
}
55+
}
56+
57+
static void parseCondBranch(MachineInstr *LastInst, MachineBasicBlock *&Target,
58+
SmallVectorImpl<MachineOperand> &Cond) {
59+
Cond.push_back(MachineOperand::CreateImm(LastInst->getOpcode()));
60+
Cond.push_back(LastInst->getOperand(0));
61+
Cond.push_back(LastInst->getOperand(1));
62+
Target = LastInst->getOperand(2).getMBB();
63+
}
64+
2865
SBFInstrInfo::SBFInstrInfo()
2966
: SBFGenInstrInfo(SBF::ADJCALLSTACKDOWN, SBF::ADJCALLSTACKUP) {}
3067

@@ -104,94 +141,262 @@ bool SBFInstrInfo::analyzeBranch(MachineBasicBlock &MBB,
104141
MachineBasicBlock *&FBB,
105142
SmallVectorImpl<MachineOperand> &Cond,
106143
bool AllowModify) const {
107-
// Start from the bottom of the block and work up, examining the
108-
// terminator instructions.
109-
MachineBasicBlock::iterator I = MBB.end();
110-
while (I != MBB.begin()) {
111-
--I;
112-
if (I->isDebugInstr())
113-
continue;
114-
115-
// Working from the bottom, when we see a non-terminator
116-
// instruction, we're done.
117-
if (!isUnpredicatedTerminator(*I))
118-
break;
119-
120-
// A terminator that isn't a branch can't easily be handled
121-
// by this analysis.
122-
if (!I->isBranch())
123-
return true;
124-
125-
// Handle unconditional branches.
126-
if (I->getOpcode() == SBF::JMP) {
127-
if (!AllowModify) {
128-
TBB = I->getOperand(0).getMBB();
129-
continue;
130-
}
144+
// If the block has no terminators, it just falls into the block after it.
145+
MachineBasicBlock::iterator I = MBB.getLastNonDebugInstr();
146+
if (I == MBB.end())
147+
return false;
148+
149+
if (!isUnpredicatedTerminator(*I))
150+
return false;
151+
152+
// Get the last instruction in the block.
153+
MachineInstr *LastInst = &*I;
154+
155+
// If there is only one terminator instruction, process it.
156+
unsigned LastOpc = LastInst->getOpcode();
157+
if (I == MBB.begin() || !isUnpredicatedTerminator(*--I)) {
158+
if (isUncondBranchOpcode(LastOpc)) {
159+
TBB = LastInst->getOperand(0).getMBB();
160+
return false;
161+
}
162+
if (isCondBranchOpcode(LastOpc)) {
163+
// Block ends with fall-through condbranch.
164+
parseCondBranch(LastInst, TBB, Cond);
165+
return false;
166+
}
167+
return true; // Unknown case
168+
}
169+
170+
// Get the instruction before it if it is a terminator.
171+
MachineInstr *SecondLastInst = &*I;
172+
unsigned SecondLastOpc = SecondLastInst->getOpcode();
131173

132-
// If the block has any instructions after a J, delete them.
133-
MBB.erase(std::next(I), MBB.end());
134-
Cond.clear();
135-
FBB = nullptr;
136-
137-
// Delete the J if it's equivalent to a fall-through.
138-
if (MBB.isLayoutSuccessor(I->getOperand(0).getMBB())) {
139-
TBB = nullptr;
140-
I->eraseFromParent();
141-
I = MBB.end();
142-
continue;
174+
// If AllowModify is true and the block ends with two or more unconditional
175+
// branches, delete all but the first unconditional branch.
176+
if (AllowModify && isUncondBranchOpcode(LastOpc)) {
177+
while (isUncondBranchOpcode(SecondLastOpc)) {
178+
LastInst->eraseFromParent();
179+
LastInst = SecondLastInst;
180+
LastOpc = LastInst->getOpcode();
181+
if (I == MBB.begin() || !isUnpredicatedTerminator(*--I)) {
182+
// Return now the only terminator is an unconditional branch.
183+
TBB = LastInst->getOperand(0).getMBB();
184+
return false;
143185
}
186+
SecondLastInst = &*I;
187+
SecondLastOpc = SecondLastInst->getOpcode();
188+
}
189+
}
144190

145-
// TBB is used to indicate the unconditinal destination.
146-
TBB = I->getOperand(0).getMBB();
147-
continue;
191+
// If we're allowed to modify and the block ends in a unconditional branch
192+
// which could simply fallthrough, remove the branch. (Note: This case only
193+
// matters when we can't understand the whole sequence, otherwise it's also
194+
// handled by BranchFolding.cpp.)
195+
if (AllowModify && isUncondBranchOpcode(LastOpc) &&
196+
MBB.isLayoutSuccessor(getBranchDestBlock(*LastInst))) {
197+
LastInst->eraseFromParent();
198+
LastInst = SecondLastInst;
199+
LastOpc = LastInst->getOpcode();
200+
if (I == MBB.begin() || !isUnpredicatedTerminator(*--I)) {
201+
assert(!isUncondBranchOpcode(LastOpc) &&
202+
"unreachable unconditional branches removed above");
203+
204+
if (isCondBranchOpcode(LastOpc)) {
205+
// Block ends with fall-through condbranch.
206+
parseCondBranch(LastInst, TBB, Cond);
207+
return false;
208+
}
209+
return true; // Can't handle indirect branch.
148210
}
149-
// Cannot handle conditional branches
211+
SecondLastInst = &*I;
212+
SecondLastOpc = SecondLastInst->getOpcode();
213+
}
214+
215+
// If there are three terminators, we don't know what sort of block this is.
216+
if (SecondLastInst && I != MBB.begin() && isUnpredicatedTerminator(*--I))
150217
return true;
218+
219+
// If the block ends with a conditional jump and a JA, handle it.
220+
if (isCondBranchOpcode(SecondLastOpc) && isUncondBranchOpcode(LastOpc)) {
221+
parseCondBranch(SecondLastInst, TBB, Cond);
222+
FBB = LastInst->getOperand(0).getMBB();
223+
return false;
151224
}
152225

153-
return false;
226+
// If the block ends with two unconditional branches, handle it. The second
227+
// one is not executed, so remove it.
228+
if (isUncondBranchOpcode(SecondLastOpc) && isUncondBranchOpcode(LastOpc)) {
229+
TBB = SecondLastInst->getOperand(0).getMBB();
230+
I = LastInst;
231+
if (AllowModify)
232+
I->eraseFromParent();
233+
return false;
234+
}
235+
236+
// Otherwise, can't handle this.
237+
return true;
154238
}
155239

156240
unsigned SBFInstrInfo::insertBranch(MachineBasicBlock &MBB,
157241
MachineBasicBlock *TBB,
158242
MachineBasicBlock *FBB,
159243
ArrayRef<MachineOperand> Cond,
160-
const DebugLoc &DL,
161-
int *BytesAdded) const {
244+
const DebugLoc &DL, int *BytesAdded) const {
162245
assert(!BytesAdded && "code size not handled");
163246

164247
// Shouldn't be a fall through.
165248
assert(TBB && "insertBranch must not be told to insert a fallthrough");
166249

250+
if (BytesAdded)
251+
*BytesAdded = 8;
252+
167253
if (Cond.empty()) {
168254
// Unconditional branch
169255
assert(!FBB && "Unconditional branch with multiple successors!");
170256
BuildMI(&MBB, DL, get(SBF::JMP)).addMBB(TBB);
171257
return 1;
172258
}
173259

174-
llvm_unreachable("Unexpected conditional branch");
260+
// See the order we parse the jump information in `parseCondBranch`
261+
BuildMI(&MBB, DL, get(Cond[0].getImm()))
262+
.add(Cond[1])
263+
.add(Cond[2])
264+
.addMBB(TBB);
265+
266+
if (FBB) {
267+
BuildMI(&MBB, DL, get(SBF::JMP)).addMBB(FBB);
268+
if (BytesAdded)
269+
*BytesAdded += 8;
270+
}
271+
272+
return 1;
175273
}
176274

177275
unsigned SBFInstrInfo::removeBranch(MachineBasicBlock &MBB,
178276
int *BytesRemoved) const {
179277
assert(!BytesRemoved && "code size not handled");
180278

181-
MachineBasicBlock::iterator I = MBB.end();
182-
unsigned Count = 0;
183-
184-
while (I != MBB.begin()) {
185-
--I;
186-
if (I->isDebugInstr())
187-
continue;
188-
if (I->getOpcode() != SBF::JMP)
189-
break;
190-
// Remove the branch.
191-
I->eraseFromParent();
192-
I = MBB.end();
193-
++Count;
279+
MachineBasicBlock::iterator I = MBB.getLastNonDebugInstr();
280+
if (I == MBB.end())
281+
return 0;
282+
283+
if (!isUncondBranchOpcode(I->getOpcode()) &&
284+
!isCondBranchOpcode(I->getOpcode()))
285+
return 0;
286+
287+
// Remove the branch.
288+
I->eraseFromParent();
289+
290+
I = MBB.end();
291+
292+
if (I == MBB.begin()) {
293+
if (BytesRemoved)
294+
*BytesRemoved = 8;
295+
return 1;
296+
}
297+
298+
--I;
299+
if (!isCondBranchOpcode(I->getOpcode())) {
300+
if (BytesRemoved)
301+
*BytesRemoved = 8;
302+
return 1;
303+
}
304+
305+
// Remove the branch.
306+
I->eraseFromParent();
307+
if (BytesRemoved)
308+
*BytesRemoved = 16;
309+
310+
return 2;
311+
}
312+
313+
bool SBFInstrInfo::reverseBranchCondition(
314+
SmallVectorImpl<MachineOperand> &Cond) const {
315+
switch (Cond[0].getImm()) {
316+
default:
317+
llvm_unreachable("Unknown conditional branch!");
318+
case SBF::JEQ_ri:
319+
Cond[0].setImm(SBF::JNE_ri);
320+
break;
321+
case SBF::JEQ_rr:
322+
Cond[0].setImm(SBF::JNE_rr);
323+
break;
324+
case SBF::JUGT_ri:
325+
Cond[0].setImm(SBF::JULE_ri);
326+
break;
327+
case SBF::JUGT_rr:
328+
Cond[0].setImm(SBF::JULE_rr);
329+
break;
330+
case SBF::JUGE_ri:
331+
Cond[0].setImm(SBF::JULT_ri);
332+
break;
333+
case SBF::JUGE_rr:
334+
Cond[0].setImm(SBF::JULT_rr);
335+
break;
336+
case SBF::JNE_ri:
337+
Cond[0].setImm(SBF::JEQ_ri);
338+
break;
339+
case SBF::JNE_rr:
340+
Cond[0].setImm(SBF::JEQ_rr);
341+
break;
342+
case SBF::JSGT_ri:
343+
Cond[0].setImm(SBF::JSLE_ri);
344+
break;
345+
case SBF::JSGT_rr:
346+
Cond[0].setImm(SBF::JSLE_rr);
347+
break;
348+
case SBF::JSGE_ri:
349+
Cond[0].setImm(SBF::JSLT_ri);
350+
break;
351+
case SBF::JSGE_rr:
352+
Cond[0].setImm(SBF::JSLT_rr);
353+
break;
354+
case SBF::JULT_ri:
355+
Cond[0].setImm(SBF::JUGE_ri);
356+
break;
357+
case SBF::JULT_rr:
358+
Cond[0].setImm(SBF::JUGE_rr);
359+
break;
360+
case SBF::JULE_ri:
361+
Cond[0].setImm(SBF::JUGT_ri);
362+
break;
363+
case SBF::JULE_rr:
364+
Cond[0].setImm(SBF::JUGT_rr);
365+
break;
366+
case SBF::JSLT_ri:
367+
Cond[0].setImm(SBF::JSGE_ri);
368+
break;
369+
case SBF::JSLT_rr:
370+
Cond[0].setImm(SBF::JSGE_rr);
371+
break;
372+
case SBF::JSLE_ri:
373+
Cond[0].setImm(SBF::JSGT_ri);
374+
break;
375+
case SBF::JSLE_rr:
376+
Cond[0].setImm(SBF::JSGT_rr);
377+
break;
194378
}
195379

196-
return Count;
380+
return false;
381+
}
382+
383+
MachineBasicBlock *
384+
SBFInstrInfo::getBranchDestBlock(const MachineInstr &MI) const {
385+
unsigned Opcode = MI.getOpcode();
386+
if (Opcode == SBF::JMP) {
387+
return MI.getOperand(0).getMBB();
388+
}
389+
390+
if (isCondBranchOpcode(Opcode)) {
391+
return MI.getOperand(2).getMBB();
392+
}
393+
394+
llvm_unreachable("unexpected opcode!");
395+
}
396+
397+
unsigned SBFInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const {
398+
if (MI.getOpcode() == SBF::LD_imm64)
399+
return 16;
400+
401+
return 8;
197402
}

llvm/lib/Target/SBF/SBFInstrInfo.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,13 @@ class SBFInstrInfo : public SBFGenInstrInfo {
5858
int *BytesAdded = nullptr) const override;
5959
void initializeTargetFeatures(bool HasExplicitSext, bool NewMemEncoding);
6060

61+
bool
62+
reverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const override;
63+
64+
MachineBasicBlock *getBranchDestBlock(const MachineInstr &MI) const override;
65+
66+
unsigned getInstSizeInBytes(const MachineInstr &MI) const override;
67+
6168
private:
6269
bool HasExplicitSignExt;
6370
bool NewMemEncoding;

0 commit comments

Comments
 (0)