5353#include < map>
5454#include < unordered_map>
5555#include < vector>
56+ #include < stack>
5657#include " llvm/Cheerp/Utility.h"
5758#include " llvm/Cheerp/BuiltinInstructions.h"
5859
@@ -301,7 +302,7 @@ class PartialInterpreter : public llvm::Interpreter {
301302 }
302303 return nullptr ;
303304 }
304- llvm::BasicBlock* visitBasicBlock (FunctionData& data, llvm::BasicBlock& BB);
305+ llvm::BasicBlock* visitBasicBlock (FunctionData& data, llvm::BasicBlock& BB, bool & madeProgress );
305306 explicit PartialInterpreter (std::unique_ptr<llvm::Module> M)
306307 : llvm::Interpreter(std::move(M), /* preExecute*/ false)
307308 {
@@ -631,7 +632,7 @@ class PartialInterpreter : public llvm::Interpreter {
631632 {
632633 return (++functionCounters[F] > 0x1000 );
633634 }
634- void visitOuter (FunctionData& data, llvm::Instruction& I);
635+ void visitOuter (FunctionData& data, llvm::Instruction& I, bool & madeProgress );
635636 bool replaceKnownCEs ()
636637 {
637638 if (fullyKnownCEs.empty ())
@@ -786,7 +787,7 @@ static void removeEdgeBetweenBlocks(llvm::BasicBlock* from, llvm::BasicBlock* to
786787 }
787788}
788789
789- llvm::BasicBlock* PartialInterpreter::visitBasicBlock (FunctionData& data, llvm::BasicBlock& BB)
790+ llvm::BasicBlock* PartialInterpreter::visitBasicBlock (FunctionData& data, llvm::BasicBlock& BB, bool & madeProgress )
790791{
791792 ExecutionContext& executionContext = getTopCallFrame ();
792793 executionContext.CurBB = &BB;
@@ -797,7 +798,7 @@ llvm::BasicBlock* PartialInterpreter::visitBasicBlock(FunctionData& data, llvm::
797798 // Note that here we could also execute a Call, and that implies adding a CallFrame
798799 // executing there (possibly also in depth)
799800 // So getTopCallFrame() has to be called since it will possibly change
800- visitOuter (data, *getTopCallFrame ().CurInst ++);
801+ visitOuter (data, *getTopCallFrame ().CurInst ++, madeProgress );
801802 }
802803
803804 // Find (if there are enough information) the next BB to be visited
@@ -885,6 +886,7 @@ class FunctionData
885886 };
886887 llvm::Function& F;
887888 std::vector<std::pair<llvm::BasicBlock*, llvm::BasicBlock*>> existingEdges;
889+
888890 typedef std::vector<Value*> VectorOfArgs;
889891
890892 llvm::DenseMap<const llvm::BasicBlock*, int > visitCounter;
@@ -990,9 +992,10 @@ class FunctionData
990992 assert (currentEE);
991993 return *currentEE;
992994 }
993- void registerEdge (const llvm::BasicBlock* from, const llvm::BasicBlock* to)
995+ bool registerEdge (const llvm::BasicBlock* from, const llvm::BasicBlock* to)
994996 {
995- visitedEdges.insert ({from, to});
997+ auto [it, is_inserted] = visitedEdges.insert ({from, to});
998+ return is_inserted;
996999 }
9971000 bool hasNoInfo (const VectorOfArgs& arguments) const
9981001 {
@@ -1178,29 +1181,36 @@ class FunctionData
11781181 {
11791182 knownValues[&I].everSkipped = true ;
11801183 }
1181- void registerValueForInst (llvm::Instruction& I, const GenericValue& GV, PartialInterpreter::BitMask strongBits)
1184+ bool registerValueForInst (llvm::Instruction& I, const GenericValue& GV, PartialInterpreter::BitMask strongBits)
11821185 {
11831186 // Only support integers for now, to simplify the handling of GVs
11841187 if (!I.getType ()->isIntegerTy ())
1185- return ;
1188+ return false ;
11861189 // Do not attempt tracking of partially known values
11871190 if (strongBits != PartialInterpreter::BitMask::ALL)
1188- return markInstSkipped (I);
1191+ {
1192+ markInstSkipped (I);
1193+ return false ;
1194+ }
11891195 auto it = knownValues.find (&I);
11901196 if (it == knownValues.end ())
11911197 {
11921198 // Never registered any value before, save the current one
11931199 knownValues[&I].value = GV;
1200+ return true ;
11941201 }
11951202 else if (it->second .everSkipped )
11961203 {
11971204 // Nothing we can do anymore
1205+ return false ;
11981206 }
11991207 else if (it->second .value .IntVal != GV.IntVal )
12001208 {
12011209 // Different value observed, bailout
12021210 it->second .everSkipped = true ;
1211+ return false ;
12031212 }
1213+ return false ;
12041214 }
12051215 void replaceKnownValues () const
12061216 {
@@ -1363,6 +1373,7 @@ class BasicBlockGroupNode
13631373 // Implicit tree structure
13641374 BasicBlockGroupNode* parentNode;
13651375 std::list<BasicBlockGroupNode> childrenNodes;
1376+ std::stack<bool > SCCProgress;
13661377
13671378 // Other metadata
13681379 FunctionData& data;
@@ -1439,14 +1450,13 @@ class BasicBlockGroupNode
14391450 // Do the visit of the BB, with 'from' (possibly nullptr if unknown) as predecessor
14401451 // Loop backs will be directed to another BBgroup
14411452 // 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)
1453+ void runVisitBasicBlock (FunctionData& data, llvm::BasicBlock& BB, llvm::SmallVectorImpl<llvm::BasicBlock*>& visitNext, bool & madeProgress )
14431454 {
14441455 assert (visitNext.empty ());
14451456
14461457 PartialInterpreter& interpreter = data.getInterpreter ();
14471458 interpreter.incomingBB = from;
1448- BasicBlock* ret = interpreter.visitBasicBlock (data, BB);
1449-
1459+ BasicBlock* ret = interpreter.visitBasicBlock (data, BB, madeProgress);
14501460 if (ret)
14511461 {
14521462 visitNext.push_back (ret);
@@ -1506,10 +1516,11 @@ class BasicBlockGroupNode
15061516 registerEdge (bb, succ);
15071517 }
15081518 }
1509- void registerEdge (llvm::BasicBlock* from, llvm::BasicBlock* to)
1519+ bool registerEdge (llvm::BasicBlock* from, llvm::BasicBlock* to)
15101520 {
1511- data.registerEdge (from, to);
1521+ bool is_inserted = data.registerEdge (from, to);
15121522 notifySuccessor (from, currIter, to);
1523+ return is_inserted;
15131524 }
15141525 void cleanUp (llvm::BasicBlock* block)
15151526 {
@@ -1555,12 +1566,40 @@ class BasicBlockGroupNode
15551566 splitIntoSCCs (childrenNodes, reverseMappingBBToGroup); // These should be partially ordered with the last one possibly being the replica of the current one
15561567
15571568 llvm::SmallVector<llvm::BasicBlock*, 4 > visitNext;
1569+
1570+ bool madeProgress = false ;
1571+ runVisitBasicBlock (data, *start, visitNext, madeProgress);
1572+ for (llvm::BasicBlock* succ : visitNext){
1573+ if (registerEdge (start, succ))
1574+ madeProgress = true ;
1575+ }
15581576
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);
1563-
1577+ if (parentNode)
1578+ {
1579+ // Track progress for this BB into the parent's stack
1580+ parentNode->SCCProgress .push (madeProgress);
1581+ if (parentNode->childrenNodes .size () == 1 )
1582+ {
1583+ // If we are here, it means that we have analyzed all the SCCs of a parent
1584+ // and we can now check if for the current SCCs, there was any progress made
1585+ bool foundProgressInStack = false ;
1586+ while (!parentNode->SCCProgress .empty ())
1587+ {
1588+ if (parentNode->SCCProgress .top ())
1589+ foundProgressInStack = true ;
1590+ parentNode->SCCProgress .pop ();
1591+ }
1592+ // If we there was progress, we allow recursion to continue on this group of SCCs
1593+ // until they resolve themselves or they hit the top iteration limit.
1594+ // Otherwise, when progress has stale, we give up on this group of SCC and allow their parent
1595+ // to continue with the rest of its children
1596+ if (!foundProgressInStack)
1597+ {
1598+ visitAll ();
1599+ return ;
1600+ }
1601+ }
1602+ }
15641603 // First has been already done
15651604 childrenNodes.pop_back ();
15661605 while (!childrenNodes.empty ())
@@ -1633,7 +1672,7 @@ void FunctionData::actualVisit()
16331672 groupData.recursiveVisit ();
16341673}
16351674
1636- void PartialInterpreter::visitOuter (FunctionData& data, llvm::Instruction& I)
1675+ void PartialInterpreter::visitOuter (FunctionData& data, llvm::Instruction& I, bool & madeProgress )
16371676{
16381677 if (PHINode* phi = dyn_cast<PHINode>(&I))
16391678 {
@@ -1647,6 +1686,7 @@ void PartialInterpreter::visitOuter(FunctionData& data, llvm::Instruction& I)
16471686 if (isValueComputed (incomingVal))
16481687 {
16491688 computedPhisValues.push_back ({phi, incomingVal});
1689+ madeProgress = true ;
16501690 return ;
16511691 }
16521692 }
@@ -1715,18 +1755,17 @@ void PartialInterpreter::visitOuter(FunctionData& data, llvm::Instruction& I)
17151755 if (next && data.getVisitCounter (next) < MAX_NUMBER_OF_VISITS_PER_BB)
17161756 {
17171757 data.incrementVisitCounter (next);
1718-
17191758 // We know where execution should proceed
17201759 incomingBB = I.getParent ();
17211760 getTopCallFrame ().CurBB = next;
17221761 getTopCallFrame ().CurInst = getTopCallFrame ().CurBB ->begin ();
17231762
17241763 // Also here we have set the proper state for the execution so we can return
1764+ madeProgress = true ;
17251765 return ;
17261766 }
17271767 skip = true ;
17281768 }
1729-
17301769 if (addToCounter (I.getFunction ()))
17311770 skip = true ;
17321771
@@ -1736,13 +1775,12 @@ void PartialInterpreter::visitOuter(FunctionData& data, llvm::Instruction& I)
17361775 // Pop current stack (will happen recursively over the call-stack)
17371776 popStackFrame ();
17381777 removeFromMaps (getTopCallFrame ().Caller );
1739-
17401778 return ;
17411779 }
17421780 }
17431781 // If we are here it means we have to actually perform the execution via Interpreter
17441782
1745- // Iff it's a call, set up the next stack frame
1783+ // If it's a call, set up the next stack frame
17461784 if (CallInst* CI = dyn_cast<CallInst>(&I))
17471785 forwardArgumentsToNextFrame (*CI);
17481786
@@ -1752,7 +1790,10 @@ void PartialInterpreter::visitOuter(FunctionData& data, llvm::Instruction& I)
17521790 BitMask strongBits = computeStronglyKnownBits (I.getOpcode (), I);
17531791
17541792 if (isInitialCallFrame ())
1755- data.registerValueForInst (I, getOperandValue (&I), strongBits);
1793+ {
1794+ if (data.registerValueForInst (I, getOperandValue (&I), strongBits))
1795+ madeProgress = true ;
1796+ }
17561797
17571798 if (!isa<CallInst>(I))
17581799 {
0 commit comments