4646#include " llvm/Cheerp/DeterministicUnorderedSet.h"
4747#include " llvm/Cheerp/PartialExecuter.h"
4848#include " llvm/ExecutionEngine/GenericValue.h"
49+ #include " llvm/IR/Dominators.h"
4950#include " llvm/IR/Operator.h"
5051#include " llvm/IR/InstIterator.h"
5152#include " llvm/IR/ValueMap.h"
@@ -304,6 +305,7 @@ class PartialInterpreter : public llvm::Interpreter {
304305 }
305306 return nullptr ;
306307 }
308+ bool checkDominator (FunctionData& data, llvm::BasicBlock* BB );
307309 llvm::BasicBlock* visitBasicBlock (FunctionData& data, BasicBlockGroupNode& BBGN , llvm::BasicBlock& BB , bool & BBProgress);
308310 explicit PartialInterpreter (std::unique_ptr<llvm::Module> M)
309311 : llvm::Interpreter(std::move(M), /* preExecute*/ false)
@@ -392,7 +394,7 @@ class PartialInterpreter : public llvm::Interpreter {
392394 return stronglyKnownBits.back ().count (V);
393395 return false ;
394396 }
395- bool areOperandsComputed (const llvm::Instruction& I)
397+ bool areOperandsComputed (const llvm::Instruction& I, bool hasKnownValues )
396398 {
397399 if (isa<SelectInst>(I))
398400 {
@@ -413,6 +415,8 @@ class PartialInterpreter : public llvm::Interpreter {
413415 }
414416 for (auto & op : I.operands ())
415417 {
418+ if (!hasKnownValues && (!isa<llvm::Constant>(op) && !isa<llvm::Argument>(op) && !isa<BasicBlock>(op)))
419+ return false ;
416420 if (!isValueComputed (op))
417421 return false ;
418422 }
@@ -436,10 +440,10 @@ class PartialInterpreter : public llvm::Interpreter {
436440 newAlignmentData.clear ();
437441 }
438442 // We are going to interpret a CallInst, we need to add a stack frame and forward the known arguments
439- void forwardArgumentsToNextFrame (CallInst& CI )
443+ void forwardArgumentsToNextFrame (CallInst& CI , bool hasKnownValues )
440444 {
441445 // This logic should work similarly for generic CallBase when those are allowed
442- assert (!hasToBeSkipped (CI ));
446+ assert (!hasToBeSkipped (CI , hasKnownValues ));
443447
444448 const Function& calledFunc = *cast<Function>(CI .getCalledFunction ());
445449 const uint32_t numFixedParams = calledFunc.getFunctionType ()->getNumParams ();
@@ -463,9 +467,9 @@ class PartialInterpreter : public llvm::Interpreter {
463467 assignToMaps (pair.first , pair.second , nullptr );
464468 }
465469
466- bool hasToBeSkipped (llvm::Instruction& I)
470+ bool hasToBeSkipped (llvm::Instruction& I, bool hasKnownValues )
467471 {
468- if (!areOperandsComputed (I))
472+ if (!areOperandsComputed (I, hasKnownValues ))
469473 return true ;
470474
471475 switch (I.getOpcode ())
@@ -641,7 +645,7 @@ class PartialInterpreter : public llvm::Interpreter {
641645 }
642646 return nullptr ;
643647 }
644- void visitOuter (FunctionData& data, BasicBlockGroupNode& BBGN , llvm::Instruction& I, bool & BBProgress);
648+ void visitOuter (FunctionData& data, BasicBlockGroupNode& BBGN , llvm::Instruction& I, bool & BBProgress, bool & hasKnownValues );
645649 bool replaceKnownCEs ()
646650 {
647651 if (fullyKnownCEs.empty ())
@@ -796,25 +800,6 @@ static void removeEdgeBetweenBlocks(llvm::BasicBlock* from, llvm::BasicBlock* to
796800 }
797801}
798802
799- llvm::BasicBlock* PartialInterpreter::visitBasicBlock (FunctionData& data, BasicBlockGroupNode& BBGN , llvm::BasicBlock& BB , bool & BBProgress)
800- {
801- ExecutionContext& executionContext = getTopCallFrame ();
802- executionContext.CurBB = &BB ;
803- executionContext.CurInst = executionContext.CurBB ->begin ();
804-
805- while (getTopCallFrame ().CurInst != BB .end ())
806- {
807- // Note that here we could also execute a Call, and that implies adding a CallFrame
808- // executing there (possibly also in depth)
809- // So getTopCallFrame() has to be called since it will possibly change
810- visitOuter (data, BBGN , *getTopCallFrame ().CurInst ++, BBProgress);
811- }
812-
813- // Find (if there are enough information) the next BB to be visited
814- // nullptr otherwise means failure to do so, and will fall back to visit all successors
815- return findNextBasicBlock (*BB .getTerminator ());
816- }
817-
818803class FunctionData ;
819804
820805class ModuleData
@@ -901,8 +886,11 @@ class FunctionData
901886 llvm::DenseSet<llvm::BasicBlock*> visitedBasicBlocks;
902887 llvm::DenseSet<std::pair<const llvm::BasicBlock*, const llvm::BasicBlock*> > visitedEdges;
903888 llvm::DenseMap<llvm::Instruction*, KnownValue> knownValues;
889+ llvm::DenseSet<llvm::BasicBlock*> blockHasKnownValues;
904890 ModuleData& moduleData;
905891
892+ llvm::DominatorTree DT ;
893+
906894 std::vector<VectorOfArgs> callEquivalentQueue;
907895 PartialInterpreter* currentEE;
908896 uint32_t functionInstructionCounter;
@@ -983,11 +971,21 @@ class FunctionData
983971 explicit FunctionData (llvm::Function& F, ModuleData& moduleData)
984972 : F(F), moduleData(moduleData), currentEE(nullptr ), functionInstructionCounter(0 )
985973 {
974+ if (!F.isDeclaration ())
975+ DT .recalculate (F);
986976 }
987977 llvm::Function* getFunction ()
988978 {
989979 return &F;
990980 }
981+ llvm::DominatorTree& getDT ()
982+ {
983+ return DT ;
984+ }
985+ llvm::DenseSet<llvm::BasicBlock*>& getBlockHasKnownValues ()
986+ {
987+ return blockHasKnownValues;
988+ }
991989 uint32_t getVisitCounter (const llvm::BasicBlock* BB )
992990 {
993991 return visitCounter[BB ];
@@ -1008,6 +1006,10 @@ class FunctionData
10081006 {
10091007 visitedBasicBlocks.insert (BB );
10101008 }
1009+ void markBlockHasKnownValues (llvm::BasicBlock* BB )
1010+ {
1011+ blockHasKnownValues.insert (BB );
1012+ }
10111013 PartialInterpreter& getInterpreter ()
10121014 {
10131015 // currentEE will be non-null while visiting a Call Equivalent
@@ -1142,6 +1144,7 @@ class FunctionData
11421144 for (const FunctionData::VectorOfArgs& toBeVisited : callEquivalentQueue)
11431145 {
11441146 visitCounter.clear ();
1147+ blockHasKnownValues.clear ();
11451148 visitCallEquivalent (toBeVisited);
11461149 if (visitedBasicBlocks.size () == F.size ())
11471150 break ;
@@ -1254,6 +1257,39 @@ class FunctionData
12541257 }
12551258};
12561259
1260+ llvm::BasicBlock* PartialInterpreter::visitBasicBlock (FunctionData& data, BasicBlockGroupNode& BBGN , llvm::BasicBlock& BB , bool & BBProgress)
1261+ {
1262+ ExecutionContext& executionContext = getTopCallFrame ();
1263+ executionContext.CurBB = &BB ;
1264+ executionContext.CurInst = executionContext.CurBB ->begin ();
1265+
1266+ bool hasKnownValues = checkDominator (data, &BB );
1267+ while (getTopCallFrame ().CurInst != BB .end ())
1268+ {
1269+ // Note that here we could also execute a Call, and that implies adding a CallFrame
1270+ // executing there (possibly also in depth)
1271+ // So getTopCallFrame() has to be called since it will possibly change
1272+ visitOuter (data, BBGN , *getTopCallFrame ().CurInst ++, BBProgress, hasKnownValues);
1273+ }
1274+ if (hasKnownValues)
1275+ data.markBlockHasKnownValues (&BB );
1276+ // Find (if there are enough information) the next BB to be visited
1277+ // nullptr otherwise means failure to do so, and will fall back to visit all successors
1278+ return findNextBasicBlock (*BB .getTerminator ());
1279+ }
1280+
1281+ bool PartialInterpreter::checkDominator (FunctionData& data, llvm::BasicBlock* BB )
1282+ {
1283+ if (auto * DomNode = data.getDT ().getNode (BB )) {
1284+ if (auto * IDom = DomNode->getIDom ()) {
1285+ if (data.getBlockHasKnownValues ().count (IDom->getBlock ())) {
1286+ return true ;
1287+ }
1288+ }
1289+ }
1290+ return false ;
1291+ }
1292+
12571293void ModuleData::initFunctionData ()
12581294{
12591295 assert (functionData.empty ());
@@ -1618,6 +1654,7 @@ class BasicBlockGroupNode
16181654 parentNode->cleanUp (p.first );
16191655 }
16201656 }
1657+
16211658 data.incrementVisitCounter (start);
16221659
16231660 splitIntoSCCs (childrenNodes, reverseMappingBBToGroup); // These should be partially ordered with the last one possibly being the replica of the current one
@@ -1719,7 +1756,7 @@ void FunctionData::actualVisit()
17191756 groupData.recursiveVisit ();
17201757}
17211758
1722- void PartialInterpreter::visitOuter (FunctionData& data, BasicBlockGroupNode& BBGN , llvm::Instruction& I, bool & BBProgress)
1759+ void PartialInterpreter::visitOuter (FunctionData& data, BasicBlockGroupNode& BBGN , llvm::Instruction& I, bool & BBProgress, bool & hasKnownValues )
17231760{
17241761 data.incrementFunctionInstructionCounter ();
17251762 BBGN .incrementSCCInstructionCounter ();
@@ -1737,6 +1774,7 @@ void PartialInterpreter::visitOuter(FunctionData& data, BasicBlockGroupNode& BBG
17371774 {
17381775 computedPhisValues.push_back ({phi, incomingVal});
17391776 BBProgress = true ;
1777+ hasKnownValues = true ;
17401778 return ;
17411779 }
17421780 }
@@ -1761,7 +1799,7 @@ void PartialInterpreter::visitOuter(FunctionData& data, BasicBlockGroupNode& BBG
17611799
17621800 // Here PHI have been properly processed
17631801
1764- bool skip = hasToBeSkipped (I);
1802+ bool skip = hasToBeSkipped (I, hasKnownValues );
17651803
17661804 if (isInitialCallFrame ())
17671805 {
@@ -1847,7 +1885,7 @@ void PartialInterpreter::visitOuter(FunctionData& data, BasicBlockGroupNode& BBG
18471885 assignToMaps (&I, strongBits, ptrBase);
18481886 return ;
18491887 }
1850- forwardArgumentsToNextFrame (*CI );
1888+ forwardArgumentsToNextFrame (*CI , hasKnownValues );
18511889 }
18521890
18531891 // Dispatch to the Interpreter's visitor for the given Instructon
@@ -1858,7 +1896,10 @@ void PartialInterpreter::visitOuter(FunctionData& data, BasicBlockGroupNode& BBG
18581896 if (isInitialCallFrame ())
18591897 {
18601898 if (data.registerValueForInst (I, getOperandValue (&I), strongBits))
1899+ {
1900+ hasKnownValues = true ;
18611901 BBProgress = true ;
1902+ }
18621903 }
18631904
18641905 if (!isa<CallInst>(I))
0 commit comments