Skip to content

Commit c2d1900

Browse files
committed
[FuncSpec] Estimate dead blocks more accurately.
Currently we only consider basic blocks with a unique predecessor when estimating the size of dead code. However, we could expand to this to consider blocks with a back-edge, or blocks preceded by dead blocks. Differential Revision: https://reviews.llvm.org/D156903
1 parent 7b14c05 commit c2d1900

File tree

3 files changed

+48
-23
lines changed

3 files changed

+48
-23
lines changed

llvm/include/llvm/Transforms/IPO/FunctionSpecialization.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,10 @@ class InstCostVisitor : public InstVisitor<InstCostVisitor, Constant *> {
184184
private:
185185
friend class InstVisitor<InstCostVisitor, Constant *>;
186186

187+
static bool canEliminateSuccessor(BasicBlock *BB, BasicBlock *Succ,
188+
DenseSet<BasicBlock *> &DeadBlocks);
189+
190+
Cost estimateBasicBlocks(SmallVectorImpl<BasicBlock *> &WorkList);
187191
Cost estimateSwitchInst(SwitchInst &I);
188192
Cost estimateBranchInst(BranchInst &I);
189193

llvm/lib/Transforms/IPO/FunctionSpecialization.cpp

Lines changed: 33 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,11 @@ static cl::opt<unsigned> MaxIncomingPhiValues(
8383
"The maximum number of incoming values a PHI node can have to be "
8484
"considered during the specialization bonus estimation"));
8585

86+
static cl::opt<unsigned> MaxBlockPredecessors(
87+
"funcspec-max-block-predecessors", cl::init(2), cl::Hidden, cl::desc(
88+
"The maximum number of predecessors a basic block can have to be "
89+
"considered during the estimation of dead code"));
90+
8691
static cl::opt<unsigned> MinFunctionSize(
8792
"funcspec-min-function-size", cl::init(100), cl::Hidden, cl::desc(
8893
"Don't specialize functions that have less than this number of "
@@ -101,16 +106,24 @@ static cl::opt<bool> SpecializeLiteralConstant(
101106
"Enable specialization of functions that take a literal constant as an "
102107
"argument"));
103108

109+
bool InstCostVisitor::canEliminateSuccessor(BasicBlock *BB, BasicBlock *Succ,
110+
DenseSet<BasicBlock *> &DeadBlocks) {
111+
unsigned I = 0;
112+
return all_of(predecessors(Succ),
113+
[&I, BB, Succ, &DeadBlocks] (BasicBlock *Pred) {
114+
return I++ < MaxBlockPredecessors &&
115+
(Pred == BB || Pred == Succ || DeadBlocks.contains(Pred));
116+
});
117+
}
118+
104119
// Estimates the codesize savings due to dead code after constant propagation.
105120
// \p WorkList represents the basic blocks of a specialization which will
106121
// eventually become dead once we replace instructions that are known to be
107122
// constants. The successors of such blocks are added to the list as long as
108123
// the \p Solver found they were executable prior to specialization, and only
109-
// if they have a unique predecessor.
110-
static Cost estimateBasicBlocks(SmallVectorImpl<BasicBlock *> &WorkList,
111-
DenseSet<BasicBlock *> &DeadBlocks,
112-
ConstMap &KnownConstants, SCCPSolver &Solver,
113-
TargetTransformInfo &TTI) {
124+
// if all their predecessors are dead.
125+
Cost InstCostVisitor::estimateBasicBlocks(
126+
SmallVectorImpl<BasicBlock *> &WorkList) {
114127
Cost CodeSize = 0;
115128
// Accumulate the instruction cost of each basic block weighted by frequency.
116129
while (!WorkList.empty()) {
@@ -139,10 +152,10 @@ static Cost estimateBasicBlocks(SmallVectorImpl<BasicBlock *> &WorkList,
139152
}
140153

141154
// Keep adding dead successors to the list as long as they are
142-
// executable and they have a unique predecessor.
155+
// executable and only reachable from dead blocks.
143156
for (BasicBlock *SuccBB : successors(BB))
144-
if (Solver.isBlockExecutable(SuccBB) &&
145-
SuccBB->getUniquePredecessor() == BB)
157+
if (isBlockExecutable(SuccBB) &&
158+
canEliminateSuccessor(BB, SuccBB, DeadBlocks))
146159
WorkList.push_back(SuccBB);
147160
}
148161
return CodeSize;
@@ -185,9 +198,13 @@ Bonus InstCostVisitor::getUserBonus(Instruction *User, Value *Use, Constant *C)
185198
C = visit(*User);
186199
if (!C)
187200
return {0, 0};
188-
KnownConstants.insert({User, C});
189201
}
190202

203+
// Even though it doesn't make sense to bind switch and branch instructions
204+
// with a constant, unlike any other instruction type, it prevents estimating
205+
// their bonus multiple times.
206+
KnownConstants.insert({User, C});
207+
191208
CodeSize += TTI.getInstructionCost(User, TargetTransformInfo::TCK_CodeSize);
192209

193210
uint64_t Weight = BFI.getBlockFreq(User->getParent()).getFrequency() /
@@ -226,13 +243,12 @@ Cost InstCostVisitor::estimateSwitchInst(SwitchInst &I) {
226243
SmallVector<BasicBlock *> WorkList;
227244
for (const auto &Case : I.cases()) {
228245
BasicBlock *BB = Case.getCaseSuccessor();
229-
if (BB == Succ || !Solver.isBlockExecutable(BB) ||
230-
BB->getUniquePredecessor() != I.getParent())
231-
continue;
232-
WorkList.push_back(BB);
246+
if (BB != Succ && isBlockExecutable(BB) &&
247+
canEliminateSuccessor(I.getParent(), BB, DeadBlocks))
248+
WorkList.push_back(BB);
233249
}
234250

235-
return estimateBasicBlocks(WorkList, DeadBlocks, KnownConstants, Solver, TTI);
251+
return estimateBasicBlocks(WorkList);
236252
}
237253

238254
Cost InstCostVisitor::estimateBranchInst(BranchInst &I) {
@@ -245,11 +261,11 @@ Cost InstCostVisitor::estimateBranchInst(BranchInst &I) {
245261
// Initialize the worklist with the dead successor as long as
246262
// it is executable and has a unique predecessor.
247263
SmallVector<BasicBlock *> WorkList;
248-
if (Solver.isBlockExecutable(Succ) &&
249-
Succ->getUniquePredecessor() == I.getParent())
264+
if (isBlockExecutable(Succ) &&
265+
canEliminateSuccessor(I.getParent(), Succ, DeadBlocks))
250266
WorkList.push_back(Succ);
251267

252-
return estimateBasicBlocks(WorkList, DeadBlocks, KnownConstants, Solver, TTI);
268+
return estimateBasicBlocks(WorkList);
253269
}
254270

255271
Constant *InstCostVisitor::visitPHINode(PHINode &I) {

llvm/unittests/Transforms/IPO/FunctionSpecializationTest.cpp

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -194,16 +194,18 @@ TEST_F(FunctionSpecializationTest, BranchInst) {
194194
entry:
195195
br label %loop
196196
loop:
197-
br i1 %cond, label %bb0, label %bb2
197+
br i1 %cond, label %bb0, label %bb3
198198
bb0:
199199
%0 = mul i32 %a, 2
200200
%1 = sub i32 6, 5
201-
br label %bb1
201+
br i1 %cond, label %bb1, label %bb2
202202
bb1:
203203
%2 = add i32 %0, %b
204204
%3 = sdiv i32 8, 2
205-
br label %loop
205+
br label %bb2
206206
bb2:
207+
br label %loop
208+
bb3:
207209
ret void
208210
}
209211
)";
@@ -220,14 +222,16 @@ TEST_F(FunctionSpecializationTest, BranchInst) {
220222
BasicBlock &Loop = *++FuncIter;
221223
BasicBlock &BB0 = *++FuncIter;
222224
BasicBlock &BB1 = *++FuncIter;
225+
BasicBlock &BB2 = *++FuncIter;
223226

224227
Instruction &Branch = Loop.front();
225228
Instruction &Mul = BB0.front();
226229
Instruction &Sub = *++BB0.begin();
227-
Instruction &BrBB1 = BB0.back();
230+
Instruction &BrBB1BB2 = BB0.back();
228231
Instruction &Add = BB1.front();
229232
Instruction &Sdiv = *++BB1.begin();
230-
Instruction &BrLoop = BB1.back();
233+
Instruction &BrBB2 = BB1.back();
234+
Instruction &BrLoop = BB2.front();
231235

232236
// mul
233237
Bonus Ref = getInstCost(Mul);
@@ -244,8 +248,9 @@ TEST_F(FunctionSpecializationTest, BranchInst) {
244248
// branch + sub + br + sdiv + br
245249
Ref = getInstCost(Branch) +
246250
getInstCost(Sub, /*SizeOnly =*/ true) +
247-
getInstCost(BrBB1, /*SizeOnly =*/ true) +
251+
getInstCost(BrBB1BB2) +
248252
getInstCost(Sdiv, /*SizeOnly =*/ true) +
253+
getInstCost(BrBB2, /*SizeOnly =*/ true) +
249254
getInstCost(BrLoop, /*SizeOnly =*/ true);
250255
Test = Specializer.getSpecializationBonus(F->getArg(2), False, Visitor);
251256
EXPECT_EQ(Test, Ref);

0 commit comments

Comments
 (0)