Split TIntermFunctionPrototype from TIntermAggregate
Function prototypes now have their own class TIntermFunctionPrototype.
It's only used for prototypes, not function parameter lists.
TIntermAggregate is still used for parameter lists and function calls.
BUGS=angleproject:1490
TEST=angle_unittests
Change-Id: I6e246ad00a29c2335bd2ab7f61cf73fe463b74bb
Reviewed-on: https://chromium-review.googlesource.com/427944
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
diff --git a/src/compiler/translator/ArrayReturnValueToOutParameter.cpp b/src/compiler/translator/ArrayReturnValueToOutParameter.cpp
index 68e9d68..99f5719 100644
--- a/src/compiler/translator/ArrayReturnValueToOutParameter.cpp
+++ b/src/compiler/translator/ArrayReturnValueToOutParameter.cpp
@@ -17,7 +17,7 @@
namespace
{
-void CopyAggregateChildren(TIntermAggregate *from, TIntermAggregate *to)
+void CopyAggregateChildren(TIntermAggregateBase *from, TIntermAggregateBase *to)
{
const TIntermSequence *fromSequence = from->getSequence();
for (size_t ii = 0; ii < fromSequence->size(); ++ii)
@@ -66,6 +66,7 @@
private:
ArrayReturnValueToOutParameterTraverser();
+ bool visitFunctionPrototype(Visit visit, TIntermFunctionPrototype *node) override;
bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) override;
bool visitAggregate(Visit visit, TIntermAggregate *node) override;
bool visitBranch(Visit visit, TIntermBranch *node) override;
@@ -121,54 +122,49 @@
return true;
}
+bool ArrayReturnValueToOutParameterTraverser::visitFunctionPrototype(Visit visit,
+ TIntermFunctionPrototype *node)
+{
+ if (visit == PreVisit && node->isArray())
+ {
+ // Replace the whole prototype node with another node that has the out parameter
+ // added.
+ TIntermFunctionPrototype *replacement = new TIntermFunctionPrototype(TType(EbtVoid));
+ CopyAggregateChildren(node, replacement);
+ replacement->getSequence()->push_back(CreateReturnValueOutSymbol(node->getType()));
+ *replacement->getFunctionSymbolInfo() = *node->getFunctionSymbolInfo();
+ replacement->setLine(node->getLine());
+
+ queueReplacement(node, replacement, OriginalNode::IS_DROPPED);
+ }
+ return false;
+}
+
bool ArrayReturnValueToOutParameterTraverser::visitAggregate(Visit visit, TIntermAggregate *node)
{
- if (visit == PreVisit)
+ if (visit == PreVisit && node->isArray() && node->getOp() == EOpFunctionCall)
{
- if (node->isArray())
+ // Handle call sites where the returned array is not assigned.
+ // Examples where f() is a function returning an array:
+ // 1. f();
+ // 2. another_array == f();
+ // 3. another_function(f());
+ // 4. return f();
+ // Cases 2 to 4 are already converted to simpler cases by
+ // SeparateExpressionsReturningArrays, so we only need to worry about the case where a
+ // function call returning an array forms an expression by itself.
+ TIntermBlock *parentBlock = getParentNode()->getAsBlock();
+ if (parentBlock)
{
- if (node->getOp() == EOpPrototype)
- {
- // Replace the whole prototype node with another node that has the out parameter
- // added.
- TIntermAggregate *replacement = new TIntermAggregate;
- replacement->setOp(EOpPrototype);
- CopyAggregateChildren(node, replacement);
- replacement->getSequence()->push_back(CreateReturnValueOutSymbol(node->getType()));
- replacement->setUserDefined();
- *replacement->getFunctionSymbolInfo() = *node->getFunctionSymbolInfo();
- replacement->setLine(node->getLine());
- replacement->setType(TType(EbtVoid));
-
- queueReplacement(node, replacement, OriginalNode::IS_DROPPED);
- }
- else if (node->getOp() == EOpFunctionCall)
- {
- // Handle call sites where the returned array is not assigned.
- // Examples where f() is a function returning an array:
- // 1. f();
- // 2. another_array == f();
- // 3. another_function(f());
- // 4. return f();
- // Cases 2 to 4 are already converted to simpler cases by
- // SeparateExpressionsReturningArrays, so we
- // only need to worry about the case where a function call returning an array forms
- // an expression by
- // itself.
- TIntermBlock *parentBlock = getParentNode()->getAsBlock();
- if (parentBlock)
- {
- nextTemporaryIndex();
- TIntermSequence replacements;
- replacements.push_back(createTempDeclaration(node->getType()));
- TIntermSymbol *returnSymbol = createTempSymbol(node->getType());
- replacements.push_back(CreateReplacementCall(node, returnSymbol));
- mMultiReplacements.push_back(
- NodeReplaceWithMultipleEntry(parentBlock, node, replacements));
- }
- return false;
- }
+ nextTemporaryIndex();
+ TIntermSequence replacements;
+ replacements.push_back(createTempDeclaration(node->getType()));
+ TIntermSymbol *returnSymbol = createTempSymbol(node->getType());
+ replacements.push_back(CreateReplacementCall(node, returnSymbol));
+ mMultiReplacements.push_back(
+ NodeReplaceWithMultipleEntry(parentBlock, node, replacements));
}
+ return false;
}
return true;
}
diff --git a/src/compiler/translator/CallDAG.cpp b/src/compiler/translator/CallDAG.cpp
index 45273a0..e09f8c9 100644
--- a/src/compiler/translator/CallDAG.cpp
+++ b/src/compiler/translator/CallDAG.cpp
@@ -122,19 +122,22 @@
return true;
}
+ bool visitFunctionPrototype(Visit visit, TIntermFunctionPrototype *node) override
+ {
+ ASSERT(visit == PreVisit);
+ // Function declaration, create an empty record.
+ auto &record = mFunctions[node->getFunctionSymbolInfo()->getName()];
+ record.name = node->getFunctionSymbolInfo()->getName();
+
+ // No need to traverse the parameters.
+ return false;
+ }
+
// Aggregates the AST node for each function as well as the name of the functions called by it
bool visitAggregate(Visit visit, TIntermAggregate *node) override
{
switch (node->getOp())
{
- case EOpPrototype:
- if (visit == PreVisit)
- {
- // Function declaration, create an empty record.
- auto &record = mFunctions[node->getFunctionSymbolInfo()->getName()];
- record.name = node->getFunctionSymbolInfo()->getName();
- }
- break;
case EOpFunctionCall:
{
// Function call, add the callees
diff --git a/src/compiler/translator/Compiler.cpp b/src/compiler/translator/Compiler.cpp
index 212aa0d..11f63a9 100644
--- a/src/compiler/translator/Compiler.cpp
+++ b/src/compiler/translator/Compiler.cpp
@@ -791,21 +791,18 @@
bool operator()(TIntermNode *node)
{
- const TIntermAggregate *asAggregate = node->getAsAggregate();
- const TIntermFunctionDefinition *asFunction = node->getAsFunctionDefinition();
+ const TIntermFunctionPrototype *asFunctionPrototype = node->getAsFunctionPrototypeNode();
+ const TIntermFunctionDefinition *asFunctionDefinition = node->getAsFunctionDefinition();
const TFunctionSymbolInfo *functionInfo = nullptr;
- if (asFunction)
+ if (asFunctionDefinition)
{
- functionInfo = asFunction->getFunctionSymbolInfo();
+ functionInfo = asFunctionDefinition->getFunctionSymbolInfo();
}
- else if (asAggregate)
+ else if (asFunctionPrototype)
{
- if (asAggregate->getOp() == EOpPrototype)
- {
- functionInfo = asAggregate->getFunctionSymbolInfo();
- }
+ functionInfo = asFunctionPrototype->getFunctionSymbolInfo();
}
if (functionInfo == nullptr)
{
@@ -816,7 +813,7 @@
if (callDagIndex == CallDAG::InvalidIndex)
{
// This happens only for unimplemented prototypes which are thus unused
- ASSERT(asAggregate && asAggregate->getOp() == EOpPrototype);
+ ASSERT(asFunctionPrototype);
return true;
}
diff --git a/src/compiler/translator/DeferGlobalInitializers.cpp b/src/compiler/translator/DeferGlobalInitializers.cpp
index 8f6b862..a48ee81 100644
--- a/src/compiler/translator/DeferGlobalInitializers.cpp
+++ b/src/compiler/translator/DeferGlobalInitializers.cpp
@@ -30,13 +30,12 @@
functionInfo->setNameObj(nameObj);
}
-TIntermAggregate *CreateFunctionPrototypeNode(const char *name, const int functionId)
+TIntermFunctionPrototype *CreateFunctionPrototypeNode(const char *name, const int functionId)
{
- TIntermAggregate *functionNode = new TIntermAggregate(EOpPrototype);
+ TType returnType(EbtVoid);
+ TIntermFunctionPrototype *functionNode = new TIntermFunctionPrototype(returnType);
SetInternalFunctionName(functionNode->getFunctionSymbolInfo(), name);
- TType returnType(EbtVoid);
- functionNode->setType(returnType);
functionNode->getFunctionSymbolInfo()->setId(functionId);
return functionNode;
}
@@ -146,7 +145,7 @@
const char *functionName = "initializeDeferredGlobals";
// Add function prototype to the beginning of the shader
- TIntermAggregate *functionPrototypeNode =
+ TIntermFunctionPrototype *functionPrototypeNode =
CreateFunctionPrototypeNode(functionName, initFunctionId);
root->getSequence()->insert(root->getSequence()->begin(), functionPrototypeNode);
diff --git a/src/compiler/translator/EmulatePrecision.cpp b/src/compiler/translator/EmulatePrecision.cpp
index 780728b..715de90 100644
--- a/src/compiler/translator/EmulatePrecision.cpp
+++ b/src/compiler/translator/EmulatePrecision.cpp
@@ -628,6 +628,11 @@
return false;
}
+bool EmulatePrecision::visitFunctionPrototype(Visit visit, TIntermFunctionPrototype *node)
+{
+ return false;
+}
+
bool EmulatePrecision::visitAggregate(Visit visit, TIntermAggregate *node)
{
bool visitChildren = true;
@@ -635,9 +640,6 @@
{
case EOpConstructStruct:
break;
- case EOpPrototype:
- visitChildren = false;
- break;
case EOpParameters:
visitChildren = false;
break;
diff --git a/src/compiler/translator/EmulatePrecision.h b/src/compiler/translator/EmulatePrecision.h
index 6642140..ed15395 100644
--- a/src/compiler/translator/EmulatePrecision.h
+++ b/src/compiler/translator/EmulatePrecision.h
@@ -32,6 +32,7 @@
bool visitAggregate(Visit visit, TIntermAggregate *node) override;
bool visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node) override;
bool visitDeclaration(Visit visit, TIntermDeclaration *node) override;
+ bool visitFunctionPrototype(Visit visit, TIntermFunctionPrototype *node) override;
void writeEmulationHelpers(TInfoSinkBase &sink,
const int shaderVersion,
diff --git a/src/compiler/translator/IntermNode.cpp b/src/compiler/translator/IntermNode.cpp
index 61fcb40..a1602b4 100644
--- a/src/compiler/translator/IntermNode.cpp
+++ b/src/compiler/translator/IntermNode.cpp
@@ -226,6 +226,11 @@
return replaceChildNodeInternal(original, replacement);
}
+bool TIntermFunctionPrototype::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
+{
+ return replaceChildNodeInternal(original, replacement);
+}
+
bool TIntermDeclaration::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
{
return replaceChildNodeInternal(original, replacement);
@@ -338,6 +343,12 @@
}
}
+void TIntermFunctionPrototype::appendParameter(TIntermSymbol *parameter)
+{
+ ASSERT(parameter != nullptr);
+ mParameters.push_back(parameter);
+}
+
void TIntermDeclaration::appendDeclarator(TIntermTyped *declarator)
{
ASSERT(declarator != nullptr);
diff --git a/src/compiler/translator/IntermNode.h b/src/compiler/translator/IntermNode.h
index 2490136..068016a 100644
--- a/src/compiler/translator/IntermNode.h
+++ b/src/compiler/translator/IntermNode.h
@@ -37,6 +37,7 @@
class TIntermBlock;
class TIntermInvariantDeclaration;
class TIntermDeclaration;
+class TIntermFunctionPrototype;
class TIntermFunctionDefinition;
class TIntermSwizzle;
class TIntermBinary;
@@ -103,6 +104,7 @@
virtual TIntermFunctionDefinition *getAsFunctionDefinition() { return nullptr; }
virtual TIntermAggregate *getAsAggregate() { return 0; }
virtual TIntermBlock *getAsBlock() { return nullptr; }
+ virtual TIntermFunctionPrototype *getAsFunctionPrototypeNode() { return nullptr; }
virtual TIntermDeclaration *getAsDeclarationNode() { return nullptr; }
virtual TIntermSwizzle *getAsSwizzleNode() { return nullptr; }
virtual TIntermBinary *getAsBinaryNode() { return 0; }
@@ -704,6 +706,43 @@
TIntermSequence mStatements;
};
+// Function prototype declaration. The type of the node is the function return type.
+class TIntermFunctionPrototype : public TIntermTyped, public TIntermAggregateBase
+{
+ public:
+ TIntermFunctionPrototype(const TType &type) : TIntermTyped(type) {}
+ ~TIntermFunctionPrototype() {}
+
+ TIntermFunctionPrototype *getAsFunctionPrototypeNode() override { return this; }
+ void traverse(TIntermTraverser *it) override;
+ bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
+
+ TIntermTyped *deepCopy() const override
+ {
+ UNREACHABLE();
+ return nullptr;
+ }
+ bool hasSideEffects() const override
+ {
+ UNREACHABLE();
+ return true;
+ }
+
+ // Only intended for initially building the declaration.
+ void appendParameter(TIntermSymbol *parameter);
+
+ TIntermSequence *getSequence() override { return &mParameters; }
+ const TIntermSequence *getSequence() const override { return &mParameters; }
+
+ TFunctionSymbolInfo *getFunctionSymbolInfo() { return &mFunctionInfo; }
+ const TFunctionSymbolInfo *getFunctionSymbolInfo() const { return &mFunctionInfo; }
+
+ protected:
+ TIntermSequence mParameters;
+
+ TFunctionSymbolInfo mFunctionInfo;
+};
+
// Struct, interface block or variable declaration. Can contain multiple variable declarators.
class TIntermDeclaration : public TIntermNode, public TIntermAggregateBase
{
@@ -877,6 +916,10 @@
virtual bool visitIfElse(Visit visit, TIntermIfElse *node) { return true; }
virtual bool visitSwitch(Visit visit, TIntermSwitch *node) { return true; }
virtual bool visitCase(Visit visit, TIntermCase *node) { return true; }
+ virtual bool visitFunctionPrototype(Visit visit, TIntermFunctionPrototype *node)
+ {
+ return true;
+ }
virtual bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
{
return true;
@@ -904,6 +947,7 @@
virtual void traverseIfElse(TIntermIfElse *node);
virtual void traverseSwitch(TIntermSwitch *node);
virtual void traverseCase(TIntermCase *node);
+ virtual void traverseFunctionPrototype(TIntermFunctionPrototype *node);
virtual void traverseFunctionDefinition(TIntermFunctionDefinition *node);
virtual void traverseAggregate(TIntermAggregate *node);
virtual void traverseBlock(TIntermBlock *node);
@@ -1123,6 +1167,7 @@
void traverseBinary(TIntermBinary *node) final;
void traverseUnary(TIntermUnary *node) final;
+ void traverseFunctionPrototype(TIntermFunctionPrototype *node) final;
void traverseFunctionDefinition(TIntermFunctionDefinition *node) final;
void traverseAggregate(TIntermAggregate *node) final;
diff --git a/src/compiler/translator/IntermTraverse.cpp b/src/compiler/translator/IntermTraverse.cpp
index ab3ad15..2ccf5aa 100644
--- a/src/compiler/translator/IntermTraverse.cpp
+++ b/src/compiler/translator/IntermTraverse.cpp
@@ -81,6 +81,11 @@
it->traverseDeclaration(this);
}
+void TIntermFunctionPrototype::traverse(TIntermTraverser *it)
+{
+ it->traverseFunctionPrototype(this);
+}
+
void TIntermAggregate::traverse(TIntermTraverser *it)
{
it->traverseAggregate(this);
@@ -559,6 +564,36 @@
visitDeclaration(PostVisit, node);
}
+void TIntermTraverser::traverseFunctionPrototype(TIntermFunctionPrototype *node)
+{
+ bool visit = true;
+
+ TIntermSequence *sequence = node->getSequence();
+
+ if (preVisit)
+ visit = visitFunctionPrototype(PreVisit, node);
+
+ if (visit)
+ {
+ incrementDepth(node);
+
+ for (auto *child : *sequence)
+ {
+ child->traverse(this);
+ if (visit && inVisit)
+ {
+ if (child != sequence->back())
+ visit = visitFunctionPrototype(InVisit, node);
+ }
+ }
+
+ decrementDepth();
+ }
+
+ if (visit && postVisit)
+ visitFunctionPrototype(PostVisit, node);
+}
+
// Traverse an aggregate node. Same comments in binary node apply here.
void TIntermTraverser::traverseAggregate(TIntermAggregate *node)
{
@@ -600,15 +635,19 @@
TIntermTraverser::traverseFunctionDefinition(node);
}
+void TLValueTrackingTraverser::traverseFunctionPrototype(TIntermFunctionPrototype *node)
+{
+ TIntermSequence *sequence = node->getSequence();
+ addToFunctionMap(node->getFunctionSymbolInfo()->getNameObj(), sequence);
+
+ TIntermTraverser::traverseFunctionPrototype(node);
+}
+
void TLValueTrackingTraverser::traverseAggregate(TIntermAggregate *node)
{
bool visit = true;
TIntermSequence *sequence = node->getSequence();
- if (node->getOp() == EOpPrototype)
- {
- addToFunctionMap(node->getFunctionSymbolInfo()->getNameObj(), sequence);
- }
if (preVisit)
visit = visitAggregate(PreVisit, node);
diff --git a/src/compiler/translator/Operator.cpp b/src/compiler/translator/Operator.cpp
index 9044340..82936d9 100644
--- a/src/compiler/translator/Operator.cpp
+++ b/src/compiler/translator/Operator.cpp
@@ -10,7 +10,7 @@
{
switch (op)
{
- // Note: ops from EOpNull to EOpPrototype can't be handled here.
+ // Note: ops from EOpNull to EOpParameters can't be handled here.
case EOpNegative:
return "-";
diff --git a/src/compiler/translator/Operator.h b/src/compiler/translator/Operator.h
index 0415070..2c5acb7 100644
--- a/src/compiler/translator/Operator.h
+++ b/src/compiler/translator/Operator.h
@@ -16,8 +16,6 @@
EOpFunctionCall,
EOpParameters, // an aggregate listing the parameters to a function
- EOpPrototype,
-
//
// Unary operators
//
diff --git a/src/compiler/translator/OutputGLSLBase.cpp b/src/compiler/translator/OutputGLSLBase.cpp
index 18afc83..785eaed 100644
--- a/src/compiler/translator/OutputGLSLBase.cpp
+++ b/src/compiler/translator/OutputGLSLBase.cpp
@@ -871,30 +871,31 @@
return false;
}
+bool TOutputGLSLBase::visitFunctionPrototype(Visit visit, TIntermFunctionPrototype *node)
+{
+ TInfoSinkBase &out = objSink();
+ ASSERT(visit == PreVisit);
+
+ const TType &type = node->getType();
+ writeVariableType(type);
+ if (type.isArray())
+ out << arrayBrackets(type);
+
+ out << " " << hashFunctionNameIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
+
+ out << "(";
+ writeFunctionParameters(*(node->getSequence()));
+ out << ")";
+
+ return false;
+}
+
bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node)
{
bool visitChildren = true;
TInfoSinkBase &out = objSink();
switch (node->getOp())
{
- case EOpPrototype:
- // Function declaration.
- ASSERT(visit == PreVisit);
- {
- const TType &type = node->getType();
- writeVariableType(type);
- if (type.isArray())
- out << arrayBrackets(type);
- }
-
- out << " " << hashFunctionNameIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
-
- out << "(";
- writeFunctionParameters(*(node->getSequence()));
- out << ")";
-
- visitChildren = false;
- break;
case EOpFunctionCall:
// Function call.
if (visit == PreVisit)
diff --git a/src/compiler/translator/OutputGLSLBase.h b/src/compiler/translator/OutputGLSLBase.h
index 45090b0..5f7d7d9 100644
--- a/src/compiler/translator/OutputGLSLBase.h
+++ b/src/compiler/translator/OutputGLSLBase.h
@@ -57,6 +57,7 @@
bool visitIfElse(Visit visit, TIntermIfElse *node) override;
bool visitSwitch(Visit visit, TIntermSwitch *node) override;
bool visitCase(Visit visit, TIntermCase *node) override;
+ bool visitFunctionPrototype(Visit visit, TIntermFunctionPrototype *node) override;
bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) override;
bool visitAggregate(Visit visit, TIntermAggregate *node) override;
bool visitBlock(Visit visit, TIntermBlock *node) override;
diff --git a/src/compiler/translator/OutputHLSL.cpp b/src/compiler/translator/OutputHLSL.cpp
index eda90a0..f562b65 100644
--- a/src/compiler/translator/OutputHLSL.cpp
+++ b/src/compiler/translator/OutputHLSL.cpp
@@ -1601,60 +1601,57 @@
return false;
}
+bool OutputHLSL::visitFunctionPrototype(Visit visit, TIntermFunctionPrototype *node)
+{
+ TInfoSinkBase &out = getInfoSink();
+
+ ASSERT(visit == PreVisit);
+ size_t index = mCallDag.findIndex(node->getFunctionSymbolInfo());
+ // Skip the prototype if it is not implemented (and thus not used)
+ if (index == CallDAG::InvalidIndex)
+ {
+ return false;
+ }
+
+ TIntermSequence *arguments = node->getSequence();
+
+ TString name = DecorateFunctionIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
+ out << TypeString(node->getType()) << " " << name << DisambiguateFunctionName(arguments)
+ << (mOutputLod0Function ? "Lod0(" : "(");
+
+ for (unsigned int i = 0; i < arguments->size(); i++)
+ {
+ TIntermSymbol *symbol = (*arguments)[i]->getAsSymbolNode();
+ ASSERT(symbol != nullptr);
+
+ out << argumentString(symbol);
+
+ if (i < arguments->size() - 1)
+ {
+ out << ", ";
+ }
+ }
+
+ out << ");\n";
+
+ // Also prototype the Lod0 variant if needed
+ bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
+ if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
+ {
+ mOutputLod0Function = true;
+ node->traverse(this);
+ mOutputLod0Function = false;
+ }
+
+ return false;
+}
+
bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
{
TInfoSinkBase &out = getInfoSink();
switch (node->getOp())
{
- case EOpPrototype:
- if (visit == PreVisit)
- {
- size_t index = mCallDag.findIndex(node->getFunctionSymbolInfo());
- // Skip the prototype if it is not implemented (and thus not used)
- if (index == CallDAG::InvalidIndex)
- {
- return false;
- }
-
- TIntermSequence *arguments = node->getSequence();
-
- TString name =
- DecorateFunctionIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
- out << TypeString(node->getType()) << " " << name
- << DisambiguateFunctionName(arguments) << (mOutputLod0Function ? "Lod0(" : "(");
-
- for (unsigned int i = 0; i < arguments->size(); i++)
- {
- TIntermSymbol *symbol = (*arguments)[i]->getAsSymbolNode();
-
- if (symbol)
- {
- out << argumentString(symbol);
-
- if (i < arguments->size() - 1)
- {
- out << ", ";
- }
- }
- else
- UNREACHABLE();
- }
-
- out << ");\n";
-
- // Also prototype the Lod0 variant if needed
- bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
- if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
- {
- mOutputLod0Function = true;
- node->traverse(this);
- mOutputLod0Function = false;
- }
-
- return false;
- }
- break;
case EOpFunctionCall:
{
TIntermSequence *arguments = node->getSequence();
diff --git a/src/compiler/translator/OutputHLSL.h b/src/compiler/translator/OutputHLSL.h
index 0c7d482..120226f 100644
--- a/src/compiler/translator/OutputHLSL.h
+++ b/src/compiler/translator/OutputHLSL.h
@@ -76,6 +76,7 @@
bool visitIfElse(Visit visit, TIntermIfElse *);
bool visitSwitch(Visit visit, TIntermSwitch *);
bool visitCase(Visit visit, TIntermCase *);
+ bool visitFunctionPrototype(Visit visit, TIntermFunctionPrototype *node) override;
bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) override;
bool visitAggregate(Visit visit, TIntermAggregate *);
bool visitBlock(Visit visit, TIntermBlock *node);
diff --git a/src/compiler/translator/ParseContext.cpp b/src/compiler/translator/ParseContext.cpp
index 2616692..43fab6c 100644
--- a/src/compiler/translator/ParseContext.cpp
+++ b/src/compiler/translator/ParseContext.cpp
@@ -2395,8 +2395,9 @@
}
}
-TIntermAggregate *TParseContext::addFunctionPrototypeDeclaration(const TFunction &parsedFunction,
- const TSourceLoc &location)
+TIntermFunctionPrototype *TParseContext::addFunctionPrototypeDeclaration(
+ const TFunction &parsedFunction,
+ const TSourceLoc &location)
{
// Note: function found from the symbol table could be the same as parsedFunction if this is the
// first declaration. Either way the instance in the symbol table is used to track whether the
@@ -2411,11 +2412,11 @@
}
function->setHasPrototypeDeclaration();
- TIntermAggregate *prototype = new TIntermAggregate;
+ TIntermFunctionPrototype *prototype = new TIntermFunctionPrototype(function->getReturnType());
// TODO(oetuaho@nvidia.com): Instead of converting the function information here, the node could
// point to the data that already exists in the symbol table.
- prototype->setType(function->getReturnType());
prototype->getFunctionSymbolInfo()->setFromFunction(*function);
+ prototype->setLine(location);
for (size_t i = 0; i < function->getParamCount(); i++)
{
@@ -2426,17 +2427,15 @@
TIntermSymbol *paramSymbol = intermediate.addSymbol(
variable.getUniqueId(), variable.getName(), variable.getType(), location);
- prototype = intermediate.growAggregate(prototype, paramSymbol, location);
+ prototype->appendParameter(paramSymbol);
}
else
{
TIntermSymbol *paramSymbol = intermediate.addSymbol(0, "", *param.type, location);
- prototype = intermediate.growAggregate(prototype, paramSymbol, location);
+ prototype->appendParameter(paramSymbol);
}
}
- prototype->setOp(EOpPrototype);
-
symbolTable.pop();
if (!symbolTable.atGlobalLevel())
diff --git a/src/compiler/translator/ParseContext.h b/src/compiler/translator/ParseContext.h
index 17dbece..1ed76a3 100644
--- a/src/compiler/translator/ParseContext.h
+++ b/src/compiler/translator/ParseContext.h
@@ -240,8 +240,8 @@
TIntermDeclaration *declarationOut);
void parseGlobalLayoutQualifier(const TTypeQualifierBuilder &typeQualifierBuilder);
- TIntermAggregate *addFunctionPrototypeDeclaration(const TFunction &parsedFunction,
- const TSourceLoc &location);
+ TIntermFunctionPrototype *addFunctionPrototypeDeclaration(const TFunction &parsedFunction,
+ const TSourceLoc &location);
TIntermFunctionDefinition *addFunctionDefinition(const TFunction &function,
TIntermAggregate *functionParameters,
TIntermBlock *functionBody,
diff --git a/src/compiler/translator/intermOut.cpp b/src/compiler/translator/intermOut.cpp
index 088448b..b538f2b 100644
--- a/src/compiler/translator/intermOut.cpp
+++ b/src/compiler/translator/intermOut.cpp
@@ -49,6 +49,7 @@
bool visitIfElse(Visit visit, TIntermIfElse *node) override;
bool visitSwitch(Visit visit, TIntermSwitch *node) override;
bool visitCase(Visit visit, TIntermCase *node) override;
+ bool visitFunctionPrototype(Visit visit, TIntermFunctionPrototype *node) override;
bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) override;
bool visitAggregate(Visit visit, TIntermAggregate *) override;
bool visitBlock(Visit visit, TIntermBlock *) override;
@@ -506,6 +507,18 @@
return true;
}
+bool TOutputTraverser::visitFunctionPrototype(Visit visit, TIntermFunctionPrototype *node)
+{
+ TInfoSinkBase &out = sink;
+
+ OutputTreeText(out, node, mDepth);
+ OutputFunction(out, "Function Prototype", node->getFunctionSymbolInfo());
+ out << " (" << node->getCompleteString() << ")";
+ out << "\n";
+
+ return true;
+}
+
bool TOutputTraverser::visitAggregate(Visit visit, TIntermAggregate *node)
{
TInfoSinkBase &out = sink;
@@ -527,9 +540,6 @@
case EOpParameters:
out << "Function Parameters: ";
break;
- case EOpPrototype:
- OutputFunction(out, "Function Prototype", node->getFunctionSymbolInfo());
- break;
case EOpConstructFloat:
out << "Construct float";