Skip to content

Commit fed9cf3

Browse files
author
Andres Madrid Ucha
committed
Partial Executer: Track progress of SCCs to avoid redundant visits
The parent tracks whether progress has been made while processing its SCC set. Each visit to a child SCC returns a boolean indicating whether running that child resulted in progress. Children are visited in reverse order. The last child is always the starting SCC. The first child is a copy that contains all basic blocks split into SCCs and used to detect loops. This copy is marked reachable when, during edge registration, we detect a back-edge into the current SCC set. If the copy is reachable, the SCC set forms a loop. After all SCCs have ben analyzed, we use the progress flag to decide whether to visit the copy again. If progress was made, the copy is visited, which recreates the same SCC structure with a new copy at the end. If no progress was made, we stop recursing that set of SCC and mark them as skipped.
1 parent 0a9d382 commit fed9cf3

File tree

1 file changed

+60
-28
lines changed

1 file changed

+60
-28
lines changed

llvm/lib/CheerpWriter/PartialExecuter.cpp

Lines changed: 60 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,7 @@ class PartialInterpreter : public llvm::Interpreter {
301301
}
302302
return nullptr;
303303
}
304-
llvm::BasicBlock* visitBasicBlock(FunctionData& data, llvm::BasicBlock& BB);
304+
llvm::BasicBlock* visitBasicBlock(FunctionData& data, llvm::BasicBlock& BB, bool& BBProgress);
305305
explicit PartialInterpreter(std::unique_ptr<llvm::Module> M)
306306
: llvm::Interpreter(std::move(M), /*preExecute*/false)
307307
{
@@ -634,7 +634,7 @@ class PartialInterpreter : public llvm::Interpreter {
634634
{
635635
return (++functionCounters[F] > 0x1000);
636636
}
637-
void visitOuter(FunctionData& data, llvm::Instruction& I);
637+
void visitOuter(FunctionData& data, llvm::Instruction& I, bool& BBProgress);
638638
bool replaceKnownCEs()
639639
{
640640
if(fullyKnownCEs.empty())
@@ -789,7 +789,7 @@ static void removeEdgeBetweenBlocks(llvm::BasicBlock* from, llvm::BasicBlock* to
789789
}
790790
}
791791

792-
llvm::BasicBlock* PartialInterpreter::visitBasicBlock(FunctionData& data, llvm::BasicBlock& BB)
792+
llvm::BasicBlock* PartialInterpreter::visitBasicBlock(FunctionData& data, llvm::BasicBlock& BB, bool& BBProgress)
793793
{
794794
ExecutionContext& executionContext = getTopCallFrame();
795795
executionContext.CurBB = &BB;
@@ -800,7 +800,7 @@ llvm::BasicBlock* PartialInterpreter::visitBasicBlock(FunctionData& data, llvm::
800800
// Note that here we could also execute a Call, and that implies adding a CallFrame
801801
// executing there (possibly also in depth)
802802
// So getTopCallFrame() has to be called since it will possibly change
803-
visitOuter(data, *getTopCallFrame().CurInst++);
803+
visitOuter(data, *getTopCallFrame().CurInst++, BBProgress);
804804
}
805805

806806
// Find (if there are enough information) the next BB to be visited
@@ -993,9 +993,10 @@ class FunctionData
993993
assert(currentEE);
994994
return *currentEE;
995995
}
996-
void registerEdge(const llvm::BasicBlock* from, const llvm::BasicBlock* to)
996+
bool registerEdge(const llvm::BasicBlock* from, const llvm::BasicBlock* to)
997997
{
998-
visitedEdges.insert({from, to});
998+
auto [it, is_inserted] = visitedEdges.insert({from, to});
999+
return is_inserted;
9991000
}
10001001
bool hasNoInfo(const VectorOfArgs& arguments) const
10011002
{
@@ -1181,29 +1182,36 @@ class FunctionData
11811182
{
11821183
knownValues[&I].everSkipped = true;
11831184
}
1184-
void registerValueForInst(llvm::Instruction& I, const GenericValue& GV, PartialInterpreter::BitMask strongBits)
1185+
bool registerValueForInst(llvm::Instruction& I, const GenericValue& GV, PartialInterpreter::BitMask strongBits)
11851186
{
11861187
// Only support integers for now, to simplify the handling of GVs
11871188
if(!I.getType()->isIntegerTy())
1188-
return;
1189+
return false;
11891190
// Do not attempt tracking of partially known values
11901191
if(strongBits != PartialInterpreter::BitMask::ALL)
1191-
return markInstSkipped(I);
1192+
{
1193+
markInstSkipped(I);
1194+
return false;
1195+
}
11921196
auto it = knownValues.find(&I);
11931197
if(it == knownValues.end())
11941198
{
11951199
// Never registered any value before, save the current one
11961200
knownValues[&I].value = GV;
1201+
return true;
11971202
}
11981203
else if(it->second.everSkipped)
11991204
{
12001205
// Nothing we can do anymore
1206+
return false;
12011207
}
12021208
else if(it->second.value.IntVal != GV.IntVal)
12031209
{
12041210
// Different value observed, bailout
12051211
it->second.everSkipped = true;
1212+
return false;
12061213
}
1214+
return false;
12071215
}
12081216
void replaceKnownValues() const
12091217
{
@@ -1374,6 +1382,7 @@ class BasicBlockGroupNode
13741382
const DeterministicBBSet& blocks;
13751383
bool isMultiHead;
13761384
bool isReachable;
1385+
bool SCCProgress;
13771386
llvm::BasicBlock* start;
13781387
llvm::BasicBlock* from;
13791388
uint32_t currIter;
@@ -1401,7 +1410,7 @@ class BasicBlockGroupNode
14011410
void splitIntoSCCs(std::list<BasicBlockGroupNode>& queueToBePopulated, ReverseMapBBToGroup& blockToGroupMap);
14021411
public:
14031412
BasicBlockGroupNode(FunctionData& data, BasicBlockGroupNode* parentBBGNode, const DeterministicBBSet& OWNEDblocks, llvm::BasicBlock* start = nullptr)
1404-
: parentNode(parentBBGNode), data(data), ownedBlocks(OWNEDblocks), blocks(ownedBlocks), isMultiHead(false), isReachable(parentNode == nullptr), start(start), from(nullptr), visitingAll(false)
1413+
: parentNode(parentBBGNode), data(data), ownedBlocks(OWNEDblocks), blocks(ownedBlocks), isMultiHead(false), isReachable(parentNode == nullptr), SCCProgress(false), start(start), from(nullptr), visitingAll(false)
14051414
{
14061415
if (start)
14071416
assert(start->getParent() == data.getFunction());
@@ -1411,7 +1420,7 @@ class BasicBlockGroupNode
14111420
{
14121421
}
14131422
BasicBlockGroupNode(BasicBlockGroupNode& BBGNode)
1414-
: parentNode(&BBGNode), data(BBGNode.data), blocks(BBGNode.blocks), isMultiHead(false), isReachable(false), start(nullptr), from(nullptr), visitingAll(false)
1423+
: parentNode(&BBGNode), data(BBGNode.data), blocks(BBGNode.blocks), isMultiHead(false), isReachable(false), SCCProgress(false), start(nullptr), from(nullptr), visitingAll(false)
14151424
{
14161425
}
14171426
void addIncomingEdge(llvm::BasicBlock* comingFrom, uint32_t currIter, llvm::BasicBlock* target)
@@ -1442,13 +1451,13 @@ class BasicBlockGroupNode
14421451
// Do the visit of the BB, with 'from' (possibly nullptr if unknown) as predecessor
14431452
// Loop backs will be directed to another BBgroup
14441453
// The visit will return the set of reachable BBs, to be added into visitNext
1445-
void runVisitBasicBlock(FunctionData& data, llvm::BasicBlock& BB, llvm::SmallVectorImpl<llvm::BasicBlock*>& visitNext)
1454+
void runVisitBasicBlock(FunctionData& data, llvm::BasicBlock& BB, llvm::SmallVectorImpl<llvm::BasicBlock*>& visitNext, bool& BBProgress)
14461455
{
14471456
assert(visitNext.empty());
14481457

14491458
PartialInterpreter& interpreter = data.getInterpreter();
14501459
interpreter.incomingBB = from;
1451-
BasicBlock* ret = interpreter.visitBasicBlock(data, BB);
1460+
BasicBlock* ret = interpreter.visitBasicBlock(data, BB, BBProgress);
14521461

14531462
if (ret)
14541463
{
@@ -1509,10 +1518,11 @@ class BasicBlockGroupNode
15091518
registerEdge(bb, succ);
15101519
}
15111520
}
1512-
void registerEdge(llvm::BasicBlock* from, llvm::BasicBlock* to)
1521+
bool registerEdge(llvm::BasicBlock* from, llvm::BasicBlock* to)
15131522
{
1514-
data.registerEdge(from, to);
1523+
bool is_inserted = data.registerEdge(from, to);
15151524
notifySuccessor(from, currIter, to);
1525+
return is_inserted;
15161526
}
15171527
void cleanUp(llvm::BasicBlock* block)
15181528
{
@@ -1525,14 +1535,14 @@ class BasicBlockGroupNode
15251535
}
15261536
}
15271537
// Visit the tree of BasicBlockGroupNodes, starting from the root and visiting children depth-first
1528-
void recursiveVisit()
1538+
bool recursiveVisit()
15291539
{
15301540
if (isMultiHead)
15311541
{
15321542
// There are multiple BasicBlock that are reacheable from outside
15331543
// --> Mark everything as reachable
15341544
visitAll();
1535-
return;
1545+
return false;
15361546
}
15371547
assert(start); //isReachable && !isMultiHead implies start being defined
15381548
currIter = data.getVisitCounter(start);
@@ -1543,7 +1553,7 @@ class BasicBlockGroupNode
15431553
// Since terminability is basically unprovable in general, we give up with the visit
15441554
// --> Mark everything as reachable
15451555
visitAll();
1546-
return;
1556+
return false;
15471557
}
15481558
if (parentNode)
15491559
{
@@ -1559,20 +1569,38 @@ class BasicBlockGroupNode
15591569

15601570
llvm::SmallVector<llvm::BasicBlock*, 4> visitNext;
15611571

1562-
// Do the actual visit for start, while populating visitNext
1563-
runVisitBasicBlock(data, *start, visitNext);
1564-
for (llvm::BasicBlock* succ : visitNext)
1565-
registerEdge(start, succ);
1572+
bool BBProgress = false;
1573+
runVisitBasicBlock(data, *start, visitNext, BBProgress);
1574+
for (llvm::BasicBlock* succ : visitNext){
1575+
if (registerEdge(start, succ)){
1576+
BBProgress = true;
1577+
}
1578+
}
15661579

1567-
// First has been already done
1580+
// The first SCC (start) has already been visited
1581+
// This updates SCCProgress in case progress was made while visiting the start
1582+
if (BBProgress)
1583+
SCCProgress = true;
15681584
childrenNodes.pop_back();
15691585
while (!childrenNodes.empty())
15701586
{
15711587
auto& child = childrenNodes.back();
15721588
if (child.isReachable)
1573-
child.recursiveVisit();
1589+
{
1590+
// If childrenNodes size is 1, that means that we are visiting the copy of all basic blocks in the curret set of SCC
1591+
// Because the copy is reachable, it means that we are in a loop
1592+
// By this point we have run and visit all the SCC of a parent. If no progress was found there is no point to continue with the loop
1593+
if (childrenNodes.size() == 1 && !SCCProgress)
1594+
{
1595+
visitAll();
1596+
return false;
1597+
}
1598+
if (child.recursiveVisit())
1599+
SCCProgress = true;
1600+
}
15741601
childrenNodes.pop_back();
15751602
}
1603+
return BBProgress;
15761604
}
15771605
};
15781606

@@ -1636,7 +1664,7 @@ void FunctionData::actualVisit()
16361664
groupData.recursiveVisit();
16371665
}
16381666

1639-
void PartialInterpreter::visitOuter(FunctionData& data, llvm::Instruction& I)
1667+
void PartialInterpreter::visitOuter(FunctionData& data, llvm::Instruction& I, bool& BBProgress)
16401668
{
16411669
if (PHINode* phi = dyn_cast<PHINode>(&I))
16421670
{
@@ -1650,6 +1678,7 @@ void PartialInterpreter::visitOuter(FunctionData& data, llvm::Instruction& I)
16501678
if (isValueComputed(incomingVal))
16511679
{
16521680
computedPhisValues.push_back({phi, incomingVal});
1681+
BBProgress = true;
16531682
return;
16541683
}
16551684
}
@@ -1724,7 +1753,7 @@ void PartialInterpreter::visitOuter(FunctionData& data, llvm::Instruction& I)
17241753
getTopCallFrame().CurBB = next;
17251754
getTopCallFrame().CurInst = getTopCallFrame().CurBB->begin();
17261755

1727-
// Also here we have set the proper state for the execution so we can return
1756+
BBProgress = true;
17281757
return;
17291758
}
17301759
skip = true;
@@ -1745,7 +1774,7 @@ void PartialInterpreter::visitOuter(FunctionData& data, llvm::Instruction& I)
17451774
}
17461775
//If we are here it means we have to actually perform the execution via Interpreter
17471776

1748-
//Iff it's a call, set up the next stack frame
1777+
//If it's a call, set up the next stack frame
17491778
if (CallInst* CI = dyn_cast<CallInst>(&I))
17501779
{
17511780
const Function* calledFunc = dyn_cast_or_null<Function>(cast<CallInst>(I).getCalledFunction());
@@ -1772,7 +1801,10 @@ void PartialInterpreter::visitOuter(FunctionData& data, llvm::Instruction& I)
17721801
BitMask strongBits = computeStronglyKnownBits(I.getOpcode(), I);
17731802

17741803
if(isInitialCallFrame())
1775-
data.registerValueForInst(I, getOperandValue(&I), strongBits);
1804+
{
1805+
if (data.registerValueForInst(I, getOperandValue(&I), strongBits))
1806+
BBProgress = true;
1807+
}
17761808

17771809
if (!isa<CallInst>(I))
17781810
{

0 commit comments

Comments
 (0)