Add a compiler option to prune unused function and prototypes
Also adds a simple unit test checking the pruning
BUG=angleproject:937
BUG=395048
Change-Id: I88440378f66178dcebebcd596f8f80235903f20e
Reviewed-on: https://chromium-review.googlesource.com/264568
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Tested-by: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/compiler/translator/Compiler.cpp b/src/compiler/translator/Compiler.cpp
index 8c5e50f..ad3dfc5 100644
--- a/src/compiler/translator/Compiler.cpp
+++ b/src/compiler/translator/Compiler.cpp
@@ -246,6 +246,9 @@
success = tagUsedFunctions();
}
+ if (success && !(compileOptions & SH_DONT_PRUNE_UNUSED_FUNCTIONS))
+ success = pruneUnusedFunctions(root);
+
if (success && shaderVersion == 300 && shaderType == GL_FRAGMENT_SHADER)
success = validateOutputs(root);
@@ -572,6 +575,59 @@
}
}
+// A predicate for the stl that returns if a top-level node is unused
+class TCompiler::UnusedPredicate
+{
+ public:
+ UnusedPredicate(const CallDAG *callDag, const std::vector<FunctionMetadata> *metadatas)
+ : mCallDag(callDag),
+ mMetadatas(metadatas)
+ {
+ }
+
+ bool operator ()(TIntermNode *node)
+ {
+ const TIntermAggregate *asAggregate = node->getAsAggregate();
+
+ if (asAggregate == nullptr)
+ {
+ return false;
+ }
+
+ if (!(asAggregate->getOp() == EOpFunction || asAggregate->getOp() == EOpPrototype))
+ {
+ return false;
+ }
+
+ size_t callDagIndex = mCallDag->findIndex(asAggregate);
+ if (callDagIndex == CallDAG::InvalidIndex)
+ {
+ // This happens only for unimplemented prototypes which are thus unused
+ ASSERT(asAggregate->getOp() == EOpPrototype);
+ return true;
+ }
+
+ ASSERT(callDagIndex < mMetadatas->size());
+ return !(*mMetadatas)[callDagIndex].used;
+ }
+
+ private:
+ const CallDAG *mCallDag;
+ const std::vector<FunctionMetadata> *mMetadatas;
+};
+
+bool TCompiler::pruneUnusedFunctions(TIntermNode *root)
+{
+ TIntermAggregate *rootNode = root->getAsAggregate();
+ ASSERT(rootNode != nullptr);
+
+ UnusedPredicate isUnused(&mCallDag, &functionMetadata);
+ TIntermSequence *sequence = rootNode->getSequence();
+ sequence->erase(std::remove_if(sequence->begin(), sequence->end(), isUnused), sequence->end());
+
+ return true;
+}
+
bool TCompiler::validateOutputs(TIntermNode* root)
{
ValidateOutputs validateOutputs(infoSink.info, compileResources.MaxDrawBuffers);