Skip to content

Commit e0cfe14

Browse files
author
Andres Madrid Ucha
committed
Partial Exectuer: 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 37bccbb commit e0cfe14

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
{
@@ -631,7 +631,7 @@ class PartialInterpreter : public llvm::Interpreter {
631631
{
632632
return (++functionCounters[F] > 0x1000);
633633
}
634-
void visitOuter(FunctionData& data, llvm::Instruction& I);
634+
void visitOuter(FunctionData& data, llvm::Instruction& I, bool& BBProgress);
635635
bool replaceKnownCEs()
636636
{
637637
if(fullyKnownCEs.empty())
@@ -786,7 +786,7 @@ static void removeEdgeBetweenBlocks(llvm::BasicBlock* from, llvm::BasicBlock* to
786786
}
787787
}
788788

789-
llvm::BasicBlock* PartialInterpreter::visitBasicBlock(FunctionData& data, llvm::BasicBlock& BB)
789+
llvm::BasicBlock* PartialInterpreter::visitBasicBlock(FunctionData& data, llvm::BasicBlock& BB, bool& BBProgress)
790790
{
791791
ExecutionContext& executionContext = getTopCallFrame();
792792
executionContext.CurBB = &BB;
@@ -797,7 +797,7 @@ llvm::BasicBlock* PartialInterpreter::visitBasicBlock(FunctionData& data, llvm::
797797
// Note that here we could also execute a Call, and that implies adding a CallFrame
798798
// executing there (possibly also in depth)
799799
// So getTopCallFrame() has to be called since it will possibly change
800-
visitOuter(data, *getTopCallFrame().CurInst++);
800+
visitOuter(data, *getTopCallFrame().CurInst++, BBProgress);
801801
}
802802

803803
// Find (if there are enough information) the next BB to be visited
@@ -990,9 +990,10 @@ class FunctionData
990990
assert(currentEE);
991991
return *currentEE;
992992
}
993-
void registerEdge(const llvm::BasicBlock* from, const llvm::BasicBlock* to)
993+
bool registerEdge(const llvm::BasicBlock* from, const llvm::BasicBlock* to)
994994
{
995-
visitedEdges.insert({from, to});
995+
auto [it, is_inserted] = visitedEdges.insert({from, to});
996+
return is_inserted;
996997
}
997998
bool hasNoInfo(const VectorOfArgs& arguments) const
998999
{
@@ -1178,29 +1179,36 @@ class FunctionData
11781179
{
11791180
knownValues[&I].everSkipped = true;
11801181
}
1181-
void registerValueForInst(llvm::Instruction& I, const GenericValue& GV, PartialInterpreter::BitMask strongBits)
1182+
bool registerValueForInst(llvm::Instruction& I, const GenericValue& GV, PartialInterpreter::BitMask strongBits)
11821183
{
11831184
// Only support integers for now, to simplify the handling of GVs
11841185
if(!I.getType()->isIntegerTy())
1185-
return;
1186+
return false;
11861187
// Do not attempt tracking of partially known values
11871188
if(strongBits != PartialInterpreter::BitMask::ALL)
1188-
return markInstSkipped(I);
1189+
{
1190+
markInstSkipped(I);
1191+
return false;
1192+
}
11891193
auto it = knownValues.find(&I);
11901194
if(it == knownValues.end())
11911195
{
11921196
// Never registered any value before, save the current one
11931197
knownValues[&I].value = GV;
1198+
return true;
11941199
}
11951200
else if(it->second.everSkipped)
11961201
{
11971202
// Nothing we can do anymore
1203+
return false;
11981204
}
11991205
else if(it->second.value.IntVal != GV.IntVal)
12001206
{
12011207
// Different value observed, bailout
12021208
it->second.everSkipped = true;
1209+
return false;
12031210
}
1211+
return false;
12041212
}
12051213
void replaceKnownValues() const
12061214
{
@@ -1371,6 +1379,7 @@ class BasicBlockGroupNode
13711379
const DeterministicBBSet& blocks;
13721380
bool isMultiHead;
13731381
bool isReachable;
1382+
bool SCCProgress;
13741383
llvm::BasicBlock* start;
13751384
llvm::BasicBlock* from;
13761385
uint32_t currIter;
@@ -1398,7 +1407,7 @@ class BasicBlockGroupNode
13981407
void splitIntoSCCs(std::list<BasicBlockGroupNode>& queueToBePopulated, ReverseMapBBToGroup& blockToGroupMap);
13991408
public:
14001409
BasicBlockGroupNode(FunctionData& data, BasicBlockGroupNode* parentBBGNode, const DeterministicBBSet& OWNEDblocks, llvm::BasicBlock* start = nullptr)
1401-
: parentNode(parentBBGNode), data(data), ownedBlocks(OWNEDblocks), blocks(ownedBlocks), isMultiHead(false), isReachable(parentNode == nullptr), start(start), from(nullptr), visitingAll(false)
1410+
: parentNode(parentBBGNode), data(data), ownedBlocks(OWNEDblocks), blocks(ownedBlocks), isMultiHead(false), isReachable(parentNode == nullptr), SCCProgress(false), start(start), from(nullptr), visitingAll(false)
14021411
{
14031412
if (start)
14041413
assert(start->getParent() == data.getFunction());
@@ -1408,7 +1417,7 @@ class BasicBlockGroupNode
14081417
{
14091418
}
14101419
BasicBlockGroupNode(BasicBlockGroupNode& BBGNode)
1411-
: parentNode(&BBGNode), data(BBGNode.data), blocks(BBGNode.blocks), isMultiHead(false), isReachable(false), start(nullptr), from(nullptr), visitingAll(false)
1420+
: parentNode(&BBGNode), data(BBGNode.data), blocks(BBGNode.blocks), isMultiHead(false), isReachable(false), SCCProgress(false), start(nullptr), from(nullptr), visitingAll(false)
14121421
{
14131422
}
14141423
void addIncomingEdge(llvm::BasicBlock* comingFrom, uint32_t currIter, llvm::BasicBlock* target)
@@ -1439,13 +1448,13 @@ class BasicBlockGroupNode
14391448
// Do the visit of the BB, with 'from' (possibly nullptr if unknown) as predecessor
14401449
// Loop backs will be directed to another BBgroup
14411450
// The visit will return the set of reachable BBs, to be added into visitNext
1442-
void runVisitBasicBlock(FunctionData& data, llvm::BasicBlock& BB, llvm::SmallVectorImpl<llvm::BasicBlock*>& visitNext)
1451+
void runVisitBasicBlock(FunctionData& data, llvm::BasicBlock& BB, llvm::SmallVectorImpl<llvm::BasicBlock*>& visitNext, bool& BBProgress)
14431452
{
14441453
assert(visitNext.empty());
14451454

14461455
PartialInterpreter& interpreter = data.getInterpreter();
14471456
interpreter.incomingBB = from;
1448-
BasicBlock* ret = interpreter.visitBasicBlock(data, BB);
1457+
BasicBlock* ret = interpreter.visitBasicBlock(data, BB, BBProgress);
14491458

14501459
if (ret)
14511460
{
@@ -1506,10 +1515,11 @@ class BasicBlockGroupNode
15061515
registerEdge(bb, succ);
15071516
}
15081517
}
1509-
void registerEdge(llvm::BasicBlock* from, llvm::BasicBlock* to)
1518+
bool registerEdge(llvm::BasicBlock* from, llvm::BasicBlock* to)
15101519
{
1511-
data.registerEdge(from, to);
1520+
bool is_inserted = data.registerEdge(from, to);
15121521
notifySuccessor(from, currIter, to);
1522+
return is_inserted;
15131523
}
15141524
void cleanUp(llvm::BasicBlock* block)
15151525
{
@@ -1522,14 +1532,14 @@ class BasicBlockGroupNode
15221532
}
15231533
}
15241534
// Visit the tree of BasicBlockGroupNodes, starting from the root and visiting children depth-first
1525-
void recursiveVisit()
1535+
bool recursiveVisit()
15261536
{
15271537
if (isMultiHead)
15281538
{
15291539
// There are multiple BasicBlock that are reacheable from outside
15301540
// --> Mark everything as reachable
15311541
visitAll();
1532-
return;
1542+
return false;
15331543
}
15341544
assert(start); //isReachable && !isMultiHead implies start being defined
15351545
currIter = data.getVisitCounter(start);
@@ -1540,7 +1550,7 @@ class BasicBlockGroupNode
15401550
// Since terminability is basically unprovable in general, we give up with the visit
15411551
// --> Mark everything as reachable
15421552
visitAll();
1543-
return;
1553+
return false;
15441554
}
15451555
if (parentNode)
15461556
{
@@ -1556,20 +1566,38 @@ class BasicBlockGroupNode
15561566

15571567
llvm::SmallVector<llvm::BasicBlock*, 4> visitNext;
15581568

1559-
// Do the actual visit for start, while populating visitNext
1560-
runVisitBasicBlock(data, *start, visitNext);
1561-
for (llvm::BasicBlock* succ : visitNext)
1562-
registerEdge(start, succ);
1569+
bool BBProgress = false;
1570+
runVisitBasicBlock(data, *start, visitNext, BBProgress);
1571+
for (llvm::BasicBlock* succ : visitNext){
1572+
if (registerEdge(start, succ)){
1573+
BBProgress = true;
1574+
}
1575+
}
15631576

1564-
// First has been already done
1577+
// The first SCC (start) has already been visited
1578+
// This updates SCCProgress in case progress was made while visiting the start
1579+
if (BBProgress)
1580+
SCCProgress = true;
15651581
childrenNodes.pop_back();
15661582
while (!childrenNodes.empty())
15671583
{
15681584
auto& child = childrenNodes.back();
15691585
if (child.isReachable)
1570-
child.recursiveVisit();
1586+
{
1587+
// If childrenNodes size is 1, that means that we are visiting the copy of all basic blocks in the curret set of SCC
1588+
// Because the copy is reachable, it means that we are in a loop
1589+
// 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
1590+
if (childrenNodes.size() == 1 && !SCCProgress)
1591+
{
1592+
visitAll();
1593+
return false;
1594+
}
1595+
if (child.recursiveVisit())
1596+
SCCProgress = true;
1597+
}
15711598
childrenNodes.pop_back();
15721599
}
1600+
return BBProgress;
15731601
}
15741602
};
15751603

@@ -1633,7 +1661,7 @@ void FunctionData::actualVisit()
16331661
groupData.recursiveVisit();
16341662
}
16351663

1636-
void PartialInterpreter::visitOuter(FunctionData& data, llvm::Instruction& I)
1664+
void PartialInterpreter::visitOuter(FunctionData& data, llvm::Instruction& I, bool& BBProgress)
16371665
{
16381666
if (PHINode* phi = dyn_cast<PHINode>(&I))
16391667
{
@@ -1647,6 +1675,7 @@ void PartialInterpreter::visitOuter(FunctionData& data, llvm::Instruction& I)
16471675
if (isValueComputed(incomingVal))
16481676
{
16491677
computedPhisValues.push_back({phi, incomingVal});
1678+
BBProgress = true;
16501679
return;
16511680
}
16521681
}
@@ -1721,7 +1750,7 @@ void PartialInterpreter::visitOuter(FunctionData& data, llvm::Instruction& I)
17211750
getTopCallFrame().CurBB = next;
17221751
getTopCallFrame().CurInst = getTopCallFrame().CurBB->begin();
17231752

1724-
// Also here we have set the proper state for the execution so we can return
1753+
BBProgress = true;
17251754
return;
17261755
}
17271756
skip = true;
@@ -1742,7 +1771,7 @@ void PartialInterpreter::visitOuter(FunctionData& data, llvm::Instruction& I)
17421771
}
17431772
//If we are here it means we have to actually perform the execution via Interpreter
17441773

1745-
//Iff it's a call, set up the next stack frame
1774+
//If it's a call, set up the next stack frame
17461775
if (CallInst* CI = dyn_cast<CallInst>(&I))
17471776
forwardArgumentsToNextFrame(*CI);
17481777

@@ -1752,7 +1781,10 @@ void PartialInterpreter::visitOuter(FunctionData& data, llvm::Instruction& I)
17521781
BitMask strongBits = computeStronglyKnownBits(I.getOpcode(), I);
17531782

17541783
if(isInitialCallFrame())
1755-
data.registerValueForInst(I, getOperandValue(&I), strongBits);
1784+
{
1785+
if (data.registerValueForInst(I, getOperandValue(&I), strongBits))
1786+
BBProgress = true;
1787+
}
17561788

17571789
if (!isa<CallInst>(I))
17581790
{

0 commit comments

Comments
 (0)