Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 70 additions & 23 deletions llvm/lib/CheerpWriter/PartialExecuter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,13 @@ typedef llvm::DenseSet<std::pair<GlobalVariable*, uint32_t> > NewAlignmentData;

namespace cheerp {

const uint32_t MAX_NUMBER_OF_VISITS_PER_BB = 100u;
const uint32_t MAX_INSTRUCTIONS_PER_FUNCTION = 3000u;
const uint32_t MAX_INSTRUCTIONS_PER_SCC = 2300u;
const uint32_t MAX_CALL_SITES = 100u;

class FunctionData;
class ModuleData;
class BasicBlockGroupNode;

class PartialInterpreter : public llvm::Interpreter {
friend FunctionData;
Expand Down Expand Up @@ -301,7 +304,7 @@ class PartialInterpreter : public llvm::Interpreter {
}
return nullptr;
}
llvm::BasicBlock* visitBasicBlock(FunctionData& data, llvm::BasicBlock& BB, bool& BBProgress);
llvm::BasicBlock* visitBasicBlock(FunctionData& data, BasicBlockGroupNode& BBGN, llvm::BasicBlock& BB, bool& BBProgress);
explicit PartialInterpreter(std::unique_ptr<llvm::Module> M)
: llvm::Interpreter(std::move(M), /*preExecute*/false)
{
Expand Down Expand Up @@ -630,11 +633,7 @@ class PartialInterpreter : public llvm::Interpreter {
}
return nullptr;
}
bool addToCounter(const llvm::Function* F)
{
return (++functionCounters[F] > 0x1000);
}
void visitOuter(FunctionData& data, llvm::Instruction& I, bool& BBProgress);
void visitOuter(FunctionData& data, BasicBlockGroupNode& BBGN, llvm::Instruction& I, bool& BBProgress);
bool replaceKnownCEs()
{
if(fullyKnownCEs.empty())
Expand Down Expand Up @@ -789,7 +788,7 @@ static void removeEdgeBetweenBlocks(llvm::BasicBlock* from, llvm::BasicBlock* to
}
}

llvm::BasicBlock* PartialInterpreter::visitBasicBlock(FunctionData& data, llvm::BasicBlock& BB, bool& BBProgress)
llvm::BasicBlock* PartialInterpreter::visitBasicBlock(FunctionData& data, BasicBlockGroupNode& BBGN, llvm::BasicBlock& BB, bool& BBProgress)
{
ExecutionContext& executionContext = getTopCallFrame();
executionContext.CurBB = &BB;
Expand All @@ -800,7 +799,7 @@ llvm::BasicBlock* PartialInterpreter::visitBasicBlock(FunctionData& data, llvm::
// Note that here we could also execute a Call, and that implies adding a CallFrame
// executing there (possibly also in depth)
// So getTopCallFrame() has to be called since it will possibly change
visitOuter(data, *getTopCallFrame().CurInst++, BBProgress);
visitOuter(data, BBGN, *getTopCallFrame().CurInst++, BBProgress);
}

// Find (if there are enough information) the next BB to be visited
Expand Down Expand Up @@ -891,12 +890,14 @@ class FunctionData
typedef std::vector<Value*> VectorOfArgs;

llvm::DenseMap<const llvm::BasicBlock*, int> visitCounter;
llvm::DenseSet<llvm::BasicBlock*> visitedBasicBlocks;
llvm::DenseSet<std::pair<const llvm::BasicBlock*, const llvm::BasicBlock*> > visitedEdges;
llvm::DenseMap<llvm::Instruction*, KnownValue> knownValues;
ModuleData& moduleData;

std::vector<VectorOfArgs> callEquivalentQueue;
PartialInterpreter* currentEE;
uint32_t functionInstructionCounter;

VectorOfArgs getArguments(const llvm::CallBase* callBase)
{
Expand Down Expand Up @@ -972,7 +973,7 @@ class FunctionData
}
public:
explicit FunctionData(llvm::Function& F, ModuleData& moduleData)
: F(F), moduleData(moduleData), currentEE(nullptr)
: F(F), moduleData(moduleData), currentEE(nullptr), functionInstructionCounter(0)
{
}
llvm::Function* getFunction()
Expand All @@ -987,6 +988,18 @@ class FunctionData
{
visitCounter[BB]++;
}
uint32_t getFunctionInstructionCounter()
{
return functionInstructionCounter;
}
void incrementFunctionInstructionCounter()
{
functionInstructionCounter++;
}
void markVisited(llvm::BasicBlock* BB)
{
visitedBasicBlocks.insert(BB);
}
PartialInterpreter& getInterpreter()
{
// currentEE will be non-null while visiting a Call Equivalent
Expand Down Expand Up @@ -1024,6 +1037,8 @@ class FunctionData
}
void visitCallEquivalent(const VectorOfArgs& arguments)
{
// Reset per-visit instruction counter
functionInstructionCounter = 0;
currentEE = moduleData.setUpPartialInterpreter(F);

// Insert the arguments in the map
Expand Down Expand Up @@ -1100,7 +1115,7 @@ class FunctionData
if (hasNoInfo(toBeVisited))
needsNoInfoCallSite = true;

if (callEquivalentQueue.size() >= MAX_NUMBER_OF_VISITS_PER_BB)
if (callEquivalentQueue.size() >= MAX_CALL_SITES)
needsNoInfoCallSite = true;

if (needsNoInfoCallSite)
Expand All @@ -1120,6 +1135,8 @@ class FunctionData
{
visitCounter.clear();
visitCallEquivalent(toBeVisited);
if (visitedBasicBlocks.size() == F.size())
break;
}
}
void visitCallBase(const llvm::CallBase* callBase)
Expand Down Expand Up @@ -1386,6 +1403,7 @@ class BasicBlockGroupNode
llvm::BasicBlock* start;
llvm::BasicBlock* from;
uint32_t currIter;
uint32_t sccInstructionCounter;
llvm::DenseMap<llvm::BasicBlock*, uint32_t> minVisitIndex;
// TODO(carlo): an optmization might be having from be a set<BasicBlock>, conserving the phi that are equals

Expand All @@ -1410,7 +1428,7 @@ class BasicBlockGroupNode
void splitIntoSCCs(std::list<BasicBlockGroupNode>& queueToBePopulated, ReverseMapBBToGroup& blockToGroupMap);
public:
BasicBlockGroupNode(FunctionData& data, BasicBlockGroupNode* parentBBGNode, const DeterministicBBSet& OWNEDblocks, llvm::BasicBlock* start = nullptr)
: parentNode(parentBBGNode), data(data), ownedBlocks(OWNEDblocks), blocks(ownedBlocks), isMultiHead(false), isReachable(parentNode == nullptr), SCCProgress(false), start(start), from(nullptr), visitingAll(false)
: parentNode(parentBBGNode), data(data), ownedBlocks(OWNEDblocks), blocks(ownedBlocks), isMultiHead(false), isReachable(parentNode == nullptr), SCCProgress(false), start(start), from(nullptr), sccInstructionCounter(0), visitingAll(false)
{
if (start)
assert(start->getParent() == data.getFunction());
Expand All @@ -1420,7 +1438,7 @@ class BasicBlockGroupNode
{
}
BasicBlockGroupNode(BasicBlockGroupNode& BBGNode)
: parentNode(&BBGNode), data(BBGNode.data), blocks(BBGNode.blocks), isMultiHead(false), isReachable(false), SCCProgress(false), start(nullptr), from(nullptr), visitingAll(false)
: parentNode(&BBGNode), data(BBGNode.data), blocks(BBGNode.blocks), isMultiHead(false), isReachable(false), SCCProgress(false), start(nullptr), from(nullptr), sccInstructionCounter(0), visitingAll(false)
{
}
void addIncomingEdge(llvm::BasicBlock* comingFrom, uint32_t currIter, llvm::BasicBlock* target)
Expand Down Expand Up @@ -1457,7 +1475,7 @@ class BasicBlockGroupNode

PartialInterpreter& interpreter = data.getInterpreter();
interpreter.incomingBB = from;
BasicBlock* ret = interpreter.visitBasicBlock(data, BB, BBProgress);
BasicBlock* ret = interpreter.visitBasicBlock(data, *this, BB, BBProgress);

if (ret)
{
Expand Down Expand Up @@ -1508,6 +1526,7 @@ class BasicBlockGroupNode
interpreter.incomingBB = nullptr;
for (llvm::BasicBlock* bb : blocks)
{
data.markVisited(bb);
for (llvm::Instruction& I : *bb)
{
interpreter.removeFromMaps(&I);
Expand All @@ -1534,6 +1553,28 @@ class BasicBlockGroupNode
interpreter.removeFromMaps(&I);
}
}
BasicBlockGroupNode* getParent()
{
return parentNode;
}
void incrementSCCInstructionCounter()
{
sccInstructionCounter++;
if (parentNode)
parentNode->incrementSCCInstructionCounter();
}
uint32_t getSCCInstructionCounter()
{
if (parentNode)
return parentNode->getSCCInstructionCounter();
return sccInstructionCounter;
}
void resetSCCInstructionCounter()
{
sccInstructionCounter = 0;
if (parentNode)
parentNode->resetSCCInstructionCounter();
}
// Visit the tree of BasicBlockGroupNodes, starting from the root and visiting children depth-first
bool recursiveVisit()
{
Expand All @@ -1544,17 +1585,23 @@ class BasicBlockGroupNode
visitAll();
return false;
}

assert(start); //isReachable && !isMultiHead implies start being defined
currIter = data.getVisitCounter(start);

if (currIter >= MAX_NUMBER_OF_VISITS_PER_BB)
if (data.getFunctionInstructionCounter() >= MAX_INSTRUCTIONS_PER_FUNCTION)
{
// We are visiting a given BasicBlock many times
// Since terminability is basically unprovable in general, we give up with the visit
// --> Mark everything as reachable
visitAll();
return false;
}

if (parentNode && parentNode->getSCCInstructionCounter() >= MAX_INSTRUCTIONS_PER_SCC)
{
visitAll();
resetSCCInstructionCounter();
return false;
}

if (parentNode)
{
for (auto& p : minVisitIndex)
Expand Down Expand Up @@ -1664,8 +1711,11 @@ void FunctionData::actualVisit()
groupData.recursiveVisit();
}

void PartialInterpreter::visitOuter(FunctionData& data, llvm::Instruction& I, bool& BBProgress)
void PartialInterpreter::visitOuter(FunctionData& data, BasicBlockGroupNode& BBGN, llvm::Instruction& I, bool& BBProgress)
{
data.incrementFunctionInstructionCounter();
BBGN.incrementSCCInstructionCounter();

if (PHINode* phi = dyn_cast<PHINode>(&I))
{
// PHI have to be execute concurrently (since they may cross-reference themselves)
Expand Down Expand Up @@ -1744,7 +1794,7 @@ void PartialInterpreter::visitOuter(FunctionData& data, llvm::Instruction& I, bo
{
BasicBlock* next = findNextBasicBlock(I);

if (next && data.getVisitCounter(next) < MAX_NUMBER_OF_VISITS_PER_BB)
if (next && BBGN.getParent() && BBGN.getParent()->getSCCInstructionCounter() < MAX_INSTRUCTIONS_PER_SCC)
{
data.incrementVisitCounter(next);

Expand All @@ -1759,9 +1809,6 @@ void PartialInterpreter::visitOuter(FunctionData& data, llvm::Instruction& I, bo
skip = true;
}

if (addToCounter(I.getFunction()))
skip = true;

//We are inside a call, here we assume all failure to execute are non-recoverable (as in no information could be gained)
if (skip)
{
Expand Down
Loading