Commit c33f1e8c by Olli Etuaho Committed by Commit Bot

Simplify creating the call DAG

Don't copy function name strings unnecessarily and traverse function body nodes manually to avoid some extra traversal steps. BUG=angleproject:2267 TEST=angle_unittests Change-Id: Ie010aabcb8bc78fa6abce397ea2bdd9092e74187 Reviewed-on: https://chromium-review.googlesource.com/847552Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
parent d078c681
...@@ -23,7 +23,7 @@ class CallDAG::CallDAGCreator : public TIntermTraverser ...@@ -23,7 +23,7 @@ class CallDAG::CallDAGCreator : public TIntermTraverser
{ {
public: public:
CallDAGCreator(TDiagnostics *diagnostics) CallDAGCreator(TDiagnostics *diagnostics)
: TIntermTraverser(true, false, true), : TIntermTraverser(true, false, false),
mDiagnostics(diagnostics), mDiagnostics(diagnostics),
mCurrentFunction(nullptr), mCurrentFunction(nullptr),
mCurrentIndex(0) mCurrentIndex(0)
...@@ -36,7 +36,7 @@ class CallDAG::CallDAGCreator : public TIntermTraverser ...@@ -36,7 +36,7 @@ class CallDAG::CallDAGCreator : public TIntermTraverser
for (auto &it : mFunctions) for (auto &it : mFunctions)
{ {
// Skip unimplemented functions // Skip unimplemented functions
if (it.second.node) if (it.second.definitionNode)
{ {
InitResult result = assignIndicesInternal(&it.second); InitResult result = assignIndicesInternal(&it.second);
if (result != INITDAG_SUCCESS) if (result != INITDAG_SUCCESS)
...@@ -65,15 +65,14 @@ class CallDAG::CallDAGCreator : public TIntermTraverser ...@@ -65,15 +65,14 @@ class CallDAG::CallDAGCreator : public TIntermTraverser
{ {
CreatorFunctionData &data = it.second; CreatorFunctionData &data = it.second;
// Skip unimplemented functions // Skip unimplemented functions
if (!data.node) if (!data.definitionNode)
{ {
continue; continue;
} }
ASSERT(data.index < records->size()); ASSERT(data.index < records->size());
Record &record = (*records)[data.index]; Record &record = (*records)[data.index];
record.name = data.name.data(); record.node = data.definitionNode;
record.node = data.node;
record.callees.reserve(data.callees.size()); record.callees.reserve(data.callees.size());
for (auto &callee : data.callees) for (auto &callee : data.callees)
...@@ -81,18 +80,25 @@ class CallDAG::CallDAGCreator : public TIntermTraverser ...@@ -81,18 +80,25 @@ class CallDAG::CallDAGCreator : public TIntermTraverser
record.callees.push_back(static_cast<int>(callee->index)); record.callees.push_back(static_cast<int>(callee->index));
} }
(*idToIndex)[data.node->getFunction()->uniqueId().get()] = static_cast<int>(data.index); (*idToIndex)[it.first] = static_cast<int>(data.index);
} }
} }
private: private:
struct CreatorFunctionData struct CreatorFunctionData
{ {
CreatorFunctionData() : node(nullptr), index(0), indexAssigned(false), visiting(false) {} CreatorFunctionData()
: definitionNode(nullptr),
name(nullptr),
index(0),
indexAssigned(false),
visiting(false)
{
}
std::set<CreatorFunctionData *> callees; std::set<CreatorFunctionData *> callees;
TIntermFunctionDefinition *node; TIntermFunctionDefinition *definitionNode;
TString name; const TString *name;
size_t index; size_t index;
bool indexAssigned; bool indexAssigned;
bool visiting; bool visiting;
...@@ -100,51 +106,36 @@ class CallDAG::CallDAGCreator : public TIntermTraverser ...@@ -100,51 +106,36 @@ class CallDAG::CallDAGCreator : public TIntermTraverser
bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) override bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) override
{ {
// Create the record if need be and remember the node. // Create the record if need be and remember the definition node.
if (visit == PreVisit) mCurrentFunction = &mFunctions[node->getFunction()->uniqueId().get()];
{ // Name will be overwritten here. If we've already traversed the prototype of this function,
auto it = mFunctions.find(node->getFunction()->uniqueId().get()); // it should have had the same name.
ASSERT(mCurrentFunction->name == nullptr ||
if (it == mFunctions.end()) *mCurrentFunction->name == node->getFunction()->name());
{ mCurrentFunction->name = &node->getFunction()->name();
mCurrentFunction = &mFunctions[node->getFunction()->uniqueId().get()]; mCurrentFunction->definitionNode = node;
mCurrentFunction->name = node->getFunction()->name();
} node->getBody()->traverse(this);
else mCurrentFunction = nullptr;
{ return false;
mCurrentFunction = &it->second;
ASSERT(mCurrentFunction->name == node->getFunction()->name());
}
mCurrentFunction->node = node;
}
else if (visit == PostVisit)
{
mCurrentFunction = nullptr;
}
return true;
} }
bool visitFunctionPrototype(Visit visit, TIntermFunctionPrototype *node) override bool visitFunctionPrototype(Visit visit, TIntermFunctionPrototype *node) override
{ {
ASSERT(visit == PreVisit); ASSERT(mCurrentFunction == nullptr);
if (mCurrentFunction != nullptr)
{
return false;
}
// Function declaration, create an empty record. // Function declaration, create an empty record.
auto &record = mFunctions[node->getFunction()->uniqueId().get()]; auto &record = mFunctions[node->getFunction()->uniqueId().get()];
record.name = node->getFunction()->name(); record.name = &node->getFunction()->name();
// No need to traverse the parameters. // No need to traverse the parameters.
return false; return false;
} }
// Aggregates the AST node for each function as well as the name of the functions called by it // Track functions called from another function.
bool visitAggregate(Visit visit, TIntermAggregate *node) override bool visitAggregate(Visit visit, TIntermAggregate *node) override
{ {
if (visit == PreVisit && node->getOp() == EOpCallFunctionInAST) if (node->getOp() == EOpCallFunctionInAST)
{ {
// Function call, add the callees // Function call, add the callees
auto it = mFunctions.find(node->getFunction()->uniqueId().get()); auto it = mFunctions.find(node->getFunction()->uniqueId().get());
...@@ -205,9 +196,9 @@ class CallDAG::CallDAGCreator : public TIntermTraverser ...@@ -205,9 +196,9 @@ class CallDAG::CallDAGCreator : public TIntermTraverser
continue; continue;
} }
if (!function->node) if (!function->definitionNode)
{ {
errorStream << "Undefined function '" << function->name errorStream << "Undefined function '" << *function->name
<< ")' used in the following call chain:"; << ")' used in the following call chain:";
result = INITDAG_UNDEFINED; result = INITDAG_UNDEFINED;
break; break;
...@@ -253,7 +244,7 @@ class CallDAG::CallDAGCreator : public TIntermTraverser ...@@ -253,7 +244,7 @@ class CallDAG::CallDAGCreator : public TIntermTraverser
{ {
errorStream << " -> "; errorStream << " -> ";
} }
errorStream << function->name << ")"; errorStream << *function->name << ")";
first = false; first = false;
} }
} }
......
...@@ -24,10 +24,10 @@ namespace sh ...@@ -24,10 +24,10 @@ namespace sh
// This class is used to precompute that function call DAG so that it // This class is used to precompute that function call DAG so that it
// can be reused by multiple analyses. // can be reused by multiple analyses.
// //
// It stores a vector of function records, with one record per function. // It stores a vector of function records, with one record per defined function.
// Records are accessed by index but a function symbol id can be converted // Records are accessed by index but a function symbol id can be converted
// to the index of the corresponding record. The records mostly contain the // to the index of the corresponding record. The records contain the AST node
// AST node of the function and the indices of the function's callees. // of the function definition and the indices of the function's callees.
// //
// In addition, records are in reverse topological order: a function F being // In addition, records are in reverse topological order: a function F being
// called by a function G will have index index(F) < index(G), that way // called by a function G will have index index(F) < index(G), that way
...@@ -41,8 +41,7 @@ class CallDAG : angle::NonCopyable ...@@ -41,8 +41,7 @@ class CallDAG : angle::NonCopyable
struct Record struct Record
{ {
std::string name; TIntermFunctionDefinition *node; // Guaranteed to be non-null.
TIntermFunctionDefinition *node;
std::vector<int> callees; std::vector<int> callees;
}; };
......
...@@ -916,14 +916,17 @@ bool TCompiler::checkCallDepth() ...@@ -916,14 +916,17 @@ bool TCompiler::checkCallDepth()
// Trace back the function chain to have a meaningful info log. // Trace back the function chain to have a meaningful info log.
std::stringstream errorStream; std::stringstream errorStream;
errorStream << "Call stack too deep (larger than " << maxCallStackDepth errorStream << "Call stack too deep (larger than " << maxCallStackDepth
<< ") with the following call chain: " << record.name; << ") with the following call chain: "
<< record.node->getFunction()->name();
int currentFunction = static_cast<int>(i); int currentFunction = static_cast<int>(i);
int currentDepth = depth; int currentDepth = depth;
while (currentFunction != -1) while (currentFunction != -1)
{ {
errorStream << " -> " << mCallDag.getRecordFromIndex(currentFunction).name; errorStream
<< " -> "
<< mCallDag.getRecordFromIndex(currentFunction).node->getFunction()->name();
int nextFunction = -1; int nextFunction = -1;
for (auto &calleeIndex : mCallDag.getRecordFromIndex(currentFunction).callees) for (auto &calleeIndex : mCallDag.getRecordFromIndex(currentFunction).callees)
...@@ -953,7 +956,7 @@ bool TCompiler::tagUsedFunctions() ...@@ -953,7 +956,7 @@ bool TCompiler::tagUsedFunctions()
// Search from main, starting from the end of the DAG as it usually is the root. // Search from main, starting from the end of the DAG as it usually is the root.
for (size_t i = mCallDag.size(); i-- > 0;) for (size_t i = mCallDag.size(); i-- > 0;)
{ {
if (mCallDag.getRecordFromIndex(i).name == "main") if (mCallDag.getRecordFromIndex(i).node->getFunction()->isMain())
{ {
internalTagUsedFunction(i); internalTagUsedFunction(i);
return true; return true;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment