Skip to content

Commit c57b104

Browse files
koachantstellar
authored andcommitted
[SPARC] Implement hooks for conditional branch relaxation
Integrate the BranchRelaxation pass to help with relaxing out-of-range conditional branches. This is mostly of concern for SPARCv9, which uses conditional branches with much smaller range than its v8 counterparts. (Some large autogenerated code, such as the ones generated by TableGen, already hits this limitation when building in Release) Reviewed By: arsenm Differential Revision: https://reviews.llvm.org/D142458 (cherry picked from commit 24e3001)
1 parent c3591d7 commit c57b104

File tree

10 files changed

+250
-45
lines changed

10 files changed

+250
-45
lines changed

llvm/lib/Target/Sparc/MCTargetDesc/SparcInstPrinter.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,8 @@ void SparcInstPrinter::printCCOperand(const MCInst *MI, int opNum,
178178
default: break;
179179
case SP::FBCOND:
180180
case SP::FBCONDA:
181+
case SP::FBCOND_V9:
182+
case SP::FBCONDA_V9:
181183
case SP::BPFCC:
182184
case SP::BPFCCA:
183185
case SP::BPFCCNT:

llvm/lib/Target/Sparc/SparcInstrInfo.cpp

Lines changed: 101 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ using namespace llvm;
2828
#define GET_INSTRINFO_CTOR_DTOR
2929
#include "SparcGenInstrInfo.inc"
3030

31+
static cl::opt<unsigned> BPccDisplacementBits(
32+
"sparc-bpcc-offset-bits", cl::Hidden, cl::init(19),
33+
cl::desc("Restrict range of BPcc/FBPfcc instructions (DEBUG)"));
34+
3135
// Pin the vtable to this file.
3236
void SparcInstrInfo::anchor() {}
3337

@@ -73,11 +77,6 @@ unsigned SparcInstrInfo::isStoreToStackSlot(const MachineInstr &MI,
7377
return 0;
7478
}
7579

76-
static bool IsIntegerCC(unsigned CC)
77-
{
78-
return (CC <= SPCC::ICC_VC);
79-
}
80-
8180
static SPCC::CondCodes GetOppositeBranchCondition(SPCC::CondCodes CC)
8281
{
8382
switch(CC) {
@@ -155,9 +154,7 @@ static SPCC::CondCodes GetOppositeBranchCondition(SPCC::CondCodes CC)
155154
llvm_unreachable("Invalid cond code");
156155
}
157156

158-
static bool isUncondBranchOpcode(int Opc) {
159-
return Opc == SP::BA || Opc == SP::BPA;
160-
}
157+
static bool isUncondBranchOpcode(int Opc) { return Opc == SP::BA; }
161158

162159
static bool isI32CondBranchOpcode(int Opc) {
163160
return Opc == SP::BCOND || Opc == SP::BPICC || Opc == SP::BPICCA ||
@@ -169,7 +166,10 @@ static bool isI64CondBranchOpcode(int Opc) {
169166
Opc == SP::BPXCCANT;
170167
}
171168

172-
static bool isFCondBranchOpcode(int Opc) { return Opc == SP::FBCOND; }
169+
static bool isFCondBranchOpcode(int Opc) {
170+
return Opc == SP::FBCOND || Opc == SP::FBCONDA || Opc == SP::FBCOND_V9 ||
171+
Opc == SP::FBCONDA_V9;
172+
}
173173

174174
static bool isCondBranchOpcode(int Opc) {
175175
return isI32CondBranchOpcode(Opc) || isI64CondBranchOpcode(Opc) ||
@@ -193,6 +193,34 @@ static void parseCondBranch(MachineInstr *LastInst, MachineBasicBlock *&Target,
193193
Target = LastInst->getOperand(0).getMBB();
194194
}
195195

196+
MachineBasicBlock *
197+
SparcInstrInfo::getBranchDestBlock(const MachineInstr &MI) const {
198+
switch (MI.getOpcode()) {
199+
default:
200+
llvm_unreachable("unexpected opcode!");
201+
case SP::BA:
202+
case SP::BCOND:
203+
case SP::BCONDA:
204+
case SP::FBCOND:
205+
case SP::FBCONDA:
206+
case SP::BPICC:
207+
case SP::BPICCA:
208+
case SP::BPICCNT:
209+
case SP::BPICCANT:
210+
case SP::BPXCC:
211+
case SP::BPXCCA:
212+
case SP::BPXCCNT:
213+
case SP::BPXCCANT:
214+
case SP::BPFCC:
215+
case SP::BPFCCA:
216+
case SP::BPFCCNT:
217+
case SP::BPFCCANT:
218+
case SP::FBCOND_V9:
219+
case SP::FBCONDA_V9:
220+
return MI.getOperand(0).getMBB();
221+
}
222+
}
223+
196224
bool SparcInstrInfo::analyzeBranch(MachineBasicBlock &MBB,
197225
MachineBasicBlock *&TBB,
198226
MachineBasicBlock *&FBB,
@@ -285,36 +313,37 @@ unsigned SparcInstrInfo::insertBranch(MachineBasicBlock &MBB,
285313
assert(TBB && "insertBranch must not be told to insert a fallthrough");
286314
assert((Cond.size() <= 2) &&
287315
"Sparc branch conditions should have at most two components!");
288-
assert(!BytesAdded && "code size not handled");
289316

290317
if (Cond.empty()) {
291318
assert(!FBB && "Unconditional branch with multiple successors!");
292-
BuildMI(&MBB, DL, get(Subtarget.isV9() ? SP::BPA : SP::BA)).addMBB(TBB);
319+
BuildMI(&MBB, DL, get(SP::BA)).addMBB(TBB);
320+
if (BytesAdded)
321+
*BytesAdded = 8;
293322
return 1;
294323
}
295324

296325
// Conditional branch
297326
unsigned Opc = Cond[0].getImm();
298327
unsigned CC = Cond[1].getImm();
328+
BuildMI(&MBB, DL, get(Opc)).addMBB(TBB).addImm(CC);
299329

300-
if (IsIntegerCC(CC)) {
301-
BuildMI(&MBB, DL, get(Opc)).addMBB(TBB).addImm(CC);
302-
} else {
303-
BuildMI(&MBB, DL, get(SP::FBCOND)).addMBB(TBB).addImm(CC);
304-
}
305-
if (!FBB)
330+
if (!FBB) {
331+
if (BytesAdded)
332+
*BytesAdded = 8;
306333
return 1;
334+
}
307335

308-
BuildMI(&MBB, DL, get(Subtarget.isV9() ? SP::BPA : SP::BA)).addMBB(FBB);
336+
BuildMI(&MBB, DL, get(SP::BA)).addMBB(FBB);
337+
if (BytesAdded)
338+
*BytesAdded = 16;
309339
return 2;
310340
}
311341

312342
unsigned SparcInstrInfo::removeBranch(MachineBasicBlock &MBB,
313343
int *BytesRemoved) const {
314-
assert(!BytesRemoved && "code size not handled");
315-
316344
MachineBasicBlock::iterator I = MBB.end();
317345
unsigned Count = 0;
346+
int Removed = 0;
318347
while (I != MBB.begin()) {
319348
--I;
320349

@@ -326,9 +355,13 @@ unsigned SparcInstrInfo::removeBranch(MachineBasicBlock &MBB,
326355
break; // Not a branch
327356

328357
I->eraseFromParent();
358+
Removed += getInstSizeInBytes(*I);
329359
I = MBB.end();
330360
++Count;
331361
}
362+
363+
if (BytesRemoved)
364+
*BytesRemoved = Removed;
332365
return Count;
333366
}
334367

@@ -340,6 +373,37 @@ bool SparcInstrInfo::reverseBranchCondition(
340373
return false;
341374
}
342375

376+
bool SparcInstrInfo::isBranchOffsetInRange(unsigned BranchOpc,
377+
int64_t Offset) const {
378+
assert((Offset & 0b11) == 0 && "Malformed branch offset");
379+
switch (BranchOpc) {
380+
case SP::BA:
381+
case SP::BCOND:
382+
case SP::BCONDA:
383+
case SP::FBCOND:
384+
case SP::FBCONDA:
385+
return isIntN(22, Offset >> 2);
386+
387+
case SP::BPICC:
388+
case SP::BPICCA:
389+
case SP::BPICCNT:
390+
case SP::BPICCANT:
391+
case SP::BPXCC:
392+
case SP::BPXCCA:
393+
case SP::BPXCCNT:
394+
case SP::BPXCCANT:
395+
case SP::BPFCC:
396+
case SP::BPFCCA:
397+
case SP::BPFCCNT:
398+
case SP::BPFCCANT:
399+
case SP::FBCOND_V9:
400+
case SP::FBCONDA_V9:
401+
return isIntN(BPccDisplacementBits, Offset >> 2);
402+
}
403+
404+
llvm_unreachable("Unknown branch instruction!");
405+
}
406+
343407
void SparcInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
344408
MachineBasicBlock::iterator I,
345409
const DebugLoc &DL, MCRegister DestReg,
@@ -530,6 +594,23 @@ Register SparcInstrInfo::getGlobalBaseReg(MachineFunction *MF) const {
530594
return GlobalBaseReg;
531595
}
532596

597+
unsigned SparcInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const {
598+
unsigned Opcode = MI.getOpcode();
599+
600+
if (MI.isInlineAsm()) {
601+
const MachineFunction *MF = MI.getParent()->getParent();
602+
const char *AsmStr = MI.getOperand(0).getSymbolName();
603+
return getInlineAsmLength(AsmStr, *MF->getTarget().getMCAsmInfo());
604+
}
605+
606+
// If the instruction has a delay slot, be conservative and also include
607+
// it for sizing purposes. This is done so that the BranchRelaxation pass
608+
// will not mistakenly mark out-of-range branches as in-range.
609+
if (MI.hasDelaySlot())
610+
return get(Opcode).getSize() * 2;
611+
return get(Opcode).getSize();
612+
}
613+
533614
bool SparcInstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
534615
switch (MI.getOpcode()) {
535616
case TargetOpcode::LOAD_STACK_GUARD: {

llvm/lib/Target/Sparc/SparcInstrInfo.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ class SparcInstrInfo : public SparcGenInstrInfo {
6464
unsigned isStoreToStackSlot(const MachineInstr &MI,
6565
int &FrameIndex) const override;
6666

67+
MachineBasicBlock *getBranchDestBlock(const MachineInstr &MI) const override;
68+
6769
bool analyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB,
6870
MachineBasicBlock *&FBB,
6971
SmallVectorImpl<MachineOperand> &Cond,
@@ -80,6 +82,9 @@ class SparcInstrInfo : public SparcGenInstrInfo {
8082
bool
8183
reverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const override;
8284

85+
/// Determine if the branch target is in range.
86+
bool isBranchOffsetInRange(unsigned BranchOpc, int64_t Offset) const override;
87+
8388
void copyPhysReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
8489
const DebugLoc &DL, MCRegister DestReg, MCRegister SrcReg,
8590
bool KillSrc) const override;
@@ -99,6 +104,10 @@ class SparcInstrInfo : public SparcGenInstrInfo {
99104

100105
Register getGlobalBaseReg(MachineFunction *MF) const;
101106

107+
/// GetInstSize - Return the number of bytes of code the specified
108+
/// instruction may be. This returns the maximum number of bytes.
109+
unsigned getInstSizeInBytes(const MachineInstr &MI) const override;
110+
102111
// Lower pseudo instructions after register allocation.
103112
bool expandPostRAPseudo(MachineInstr &MI) const override;
104113
};

llvm/lib/Target/Sparc/SparcInstrInfo.td

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -850,15 +850,8 @@ class BranchPredictAlways<dag ins, string asmstr, list<dag> pattern>
850850
: F2_3<0b001, 0, 1, (outs), ins, asmstr, pattern>;
851851
}
852852

853-
let cond = 8 in {
854-
// If we're compiling for v9, prefer BPA rather than BA
855-
// TODO: Disallow BA emission when FeatureV8Deprecated isn't enabled
856-
let Predicates = [HasV9], cc = 0b00 in
857-
def BPA : BranchPredictAlways<(ins bprtarget:$imm19),
858-
"ba %icc, $imm19", [(br bb:$imm19)]>;
859-
853+
let cond = 8 in
860854
def BA : BranchAlways<(ins brtarget:$imm22), "ba $imm22", [(br bb:$imm22)]>;
861-
}
862855

863856
let isBranch = 1, isTerminator = 1, hasDelaySlot = 1 in {
864857

llvm/lib/Target/Sparc/SparcTargetMachine.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeSparcTarget() {
3232
initializeSparcDAGToDAGISelPass(PR);
3333
}
3434

35+
static cl::opt<bool>
36+
BranchRelaxation("sparc-enable-branch-relax", cl::Hidden, cl::init(true),
37+
cl::desc("Relax out of range conditional branches"));
38+
3539
static std::string computeDataLayout(const Triple &T, bool is64Bit) {
3640
// Sparc is typically big endian, but some are little.
3741
std::string Ret = T.getArch() == Triple::sparcel ? "e" : "E";
@@ -182,6 +186,9 @@ bool SparcPassConfig::addInstSelector() {
182186
}
183187

184188
void SparcPassConfig::addPreEmitPass(){
189+
if (BranchRelaxation)
190+
addPass(&BranchRelaxationPassID);
191+
185192
addPass(createSparcDelaySlotFillerPass());
186193

187194
if (this->getSparcTargetMachine().getSubtargetImpl()->insertNOPLoad())
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
2+
; RUN: llc < %s -mtriple=sparc64 -sparc-bpcc-offset-bits=4 | FileCheck --check-prefix=SPARC64 %s
3+
4+
define i32 @branch_relax_int(i32 %in) {
5+
; SPARC64-LABEL: branch_relax_int:
6+
; SPARC64: .cfi_startproc
7+
; SPARC64-NEXT: ! %bb.0:
8+
; SPARC64-NEXT: save %sp, -128, %sp
9+
; SPARC64-NEXT: .cfi_def_cfa_register %fp
10+
; SPARC64-NEXT: .cfi_window_save
11+
; SPARC64-NEXT: .cfi_register %o7, %i7
12+
; SPARC64-NEXT: cmp %i0, 0
13+
; SPARC64-NEXT: bne %icc, .LBB0_1
14+
; SPARC64-NEXT: nop
15+
; SPARC64-NEXT: ba .LBB0_2
16+
; SPARC64-NEXT: nop
17+
; SPARC64-NEXT: .LBB0_1: ! %false
18+
; SPARC64-NEXT: !APP
19+
; SPARC64-NEXT: nop
20+
; SPARC64-NEXT: nop
21+
; SPARC64-NEXT: nop
22+
; SPARC64-NEXT: nop
23+
; SPARC64-NEXT: nop
24+
; SPARC64-NEXT: nop
25+
; SPARC64-NEXT: nop
26+
; SPARC64-NEXT: nop
27+
; SPARC64-NEXT: !NO_APP
28+
; SPARC64-NEXT: ret
29+
; SPARC64-NEXT: restore %g0, %g0, %o0
30+
; SPARC64-NEXT: .LBB0_2: ! %true
31+
; SPARC64-NEXT: mov 4, %i0
32+
; SPARC64-NEXT: !APP
33+
; SPARC64-NEXT: nop
34+
; SPARC64-NEXT: nop
35+
; SPARC64-NEXT: nop
36+
; SPARC64-NEXT: nop
37+
; SPARC64-NEXT: nop
38+
; SPARC64-NEXT: nop
39+
; SPARC64-NEXT: nop
40+
; SPARC64-NEXT: nop
41+
; SPARC64-NEXT: !NO_APP
42+
; SPARC64-NEXT: ret
43+
; SPARC64-NEXT: restore
44+
%tst = icmp eq i32 %in, 0
45+
br i1 %tst, label %true, label %false
46+
47+
true:
48+
call void asm sideeffect "nop\0A\09nop\0A\09nop\0A\09nop\0A\09nop\0A\09nop\0A\09nop\0A\09nop", ""()
49+
ret i32 4
50+
51+
false:
52+
call void asm sideeffect "nop\0A\09nop\0A\09nop\0A\09nop\0A\09nop\0A\09nop\0A\09nop\0A\09nop", ""()
53+
ret i32 0
54+
}
55+
56+
define float @branch_relax_float(float %in) {
57+
; SPARC64-LABEL: branch_relax_float:
58+
; SPARC64: .cfi_startproc
59+
; SPARC64-NEXT: ! %bb.0:
60+
; SPARC64-NEXT: save %sp, -128, %sp
61+
; SPARC64-NEXT: .cfi_def_cfa_register %fp
62+
; SPARC64-NEXT: .cfi_window_save
63+
; SPARC64-NEXT: .cfi_register %o7, %i7
64+
; SPARC64-NEXT: sethi %h44(.LCPI1_0), %i0
65+
; SPARC64-NEXT: add %i0, %m44(.LCPI1_0), %i0
66+
; SPARC64-NEXT: sllx %i0, 12, %i0
67+
; SPARC64-NEXT: ld [%i0+%l44(.LCPI1_0)], %f0
68+
; SPARC64-NEXT: fcmps %fcc0, %f1, %f0
69+
; SPARC64-NEXT: fbe %fcc0, .LBB1_1
70+
; SPARC64-NEXT: nop
71+
; SPARC64-NEXT: ba .LBB1_2
72+
; SPARC64-NEXT: nop
73+
; SPARC64-NEXT: .LBB1_1: ! %true
74+
; SPARC64-NEXT: sethi %h44(.LCPI1_1), %i0
75+
; SPARC64-NEXT: add %i0, %m44(.LCPI1_1), %i0
76+
; SPARC64-NEXT: sllx %i0, 12, %i0
77+
; SPARC64-NEXT: ld [%i0+%l44(.LCPI1_1)], %f0
78+
; SPARC64-NEXT: !APP
79+
; SPARC64-NEXT: nop
80+
; SPARC64-NEXT: nop
81+
; SPARC64-NEXT: nop
82+
; SPARC64-NEXT: nop
83+
; SPARC64-NEXT: nop
84+
; SPARC64-NEXT: nop
85+
; SPARC64-NEXT: nop
86+
; SPARC64-NEXT: nop
87+
; SPARC64-NEXT: !NO_APP
88+
; SPARC64-NEXT: ret
89+
; SPARC64-NEXT: restore
90+
; SPARC64-NEXT: .LBB1_2: ! %false
91+
; SPARC64-NEXT: !APP
92+
; SPARC64-NEXT: nop
93+
; SPARC64-NEXT: nop
94+
; SPARC64-NEXT: nop
95+
; SPARC64-NEXT: nop
96+
; SPARC64-NEXT: nop
97+
; SPARC64-NEXT: nop
98+
; SPARC64-NEXT: nop
99+
; SPARC64-NEXT: nop
100+
; SPARC64-NEXT: !NO_APP
101+
; SPARC64-NEXT: ret
102+
; SPARC64-NEXT: restore
103+
%tst = fcmp oeq float %in, 0.0
104+
br i1 %tst, label %true, label %false
105+
106+
true:
107+
call void asm sideeffect "nop\0A\09nop\0A\09nop\0A\09nop\0A\09nop\0A\09nop\0A\09nop\0A\09nop", ""()
108+
ret float 4.0
109+
110+
false:
111+
call void asm sideeffect "nop\0A\09nop\0A\09nop\0A\09nop\0A\09nop\0A\09nop\0A\09nop\0A\09nop", ""()
112+
ret float 0.0
113+
}

0 commit comments

Comments
 (0)