Skip to content

Commit 7bc3a88

Browse files
author
Andres Madrid Ucha
committed
PartialExecuter: Dominators optimization (draft)
This is a draft PR to mainly confirm if what I implemented is along the right lines, or if I misunderstood the idea. Right now it seems that this optimization is actually slower than what is currently in master, so if I did not misunderstood the idea, it would not be good to merge this.
1 parent 3f89ae7 commit 7bc3a88

1 file changed

Lines changed: 69 additions & 28 deletions

File tree

llvm/lib/CheerpWriter/PartialExecuter.cpp

Lines changed: 69 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
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-
818803
class FunctionData;
819804

820805
class 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+
12571293
void 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

Comments
 (0)