Fold user-definedness of function nodes into TOperator
Whether a function call is user-defined is not orthogonal to TOperator
associated with the call node - other ops than function calls can't be
user-defined. Because of this it makes sense to store the user-
definedness by having different TOperator enums for different types of
calls.
This patch also tags internal helper functions that have a raw
definition outside the AST with a separate TOperator enum. This way
they can be handled with logic that is easy to understand. Before this,
function calls like this left the user-defined bit unset, despite not
really being built-ins either. The EmulatePrecision traverser uses
this. This is also something that could be used to clean up built-in
emulation in the future.
BUG=angleproject:1490
TEST=angle_unittests
Change-Id: I597fcd9789d0cc22b689ef3ce5a0cc3f621d4859
Reviewed-on: https://chromium-review.googlesource.com/433443
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
diff --git a/src/compiler/translator/ASTMetadataHLSL.cpp b/src/compiler/translator/ASTMetadataHLSL.cpp
index 5301b04..d37b3dc 100644
--- a/src/compiler/translator/ASTMetadataHLSL.cpp
+++ b/src/compiler/translator/ASTMetadataHLSL.cpp
@@ -102,27 +102,23 @@
{
if (visit == PreVisit)
{
- if (node->getOp() == EOpFunctionCall)
+ if (node->getOp() == EOpCallFunctionInAST)
{
- if (node->isUserDefined())
- {
- size_t calleeIndex = mDag.findIndex(node->getFunctionSymbolInfo());
- ASSERT(calleeIndex != CallDAG::InvalidIndex && calleeIndex < mIndex);
+ size_t calleeIndex = mDag.findIndex(node->getFunctionSymbolInfo());
+ ASSERT(calleeIndex != CallDAG::InvalidIndex && calleeIndex < mIndex);
- if ((*mMetadataList)[calleeIndex].mUsesGradient)
- {
- onGradient();
- }
+ if ((*mMetadataList)[calleeIndex].mUsesGradient)
+ {
+ onGradient();
}
- else
- {
- TString name =
- TFunction::unmangleName(node->getFunctionSymbolInfo()->getName());
+ }
+ else if (node->getOp() == EOpCallBuiltInFunction)
+ {
+ TString name = TFunction::unmangleName(node->getFunctionSymbolInfo()->getName());
- if (name == "texture2D" || name == "texture2DProj" || name == "textureCube")
- {
- onGradient();
- }
+ if (name == "texture2D" || name == "texture2DProj" || name == "textureCube")
+ {
+ onGradient();
}
}
}
@@ -273,17 +269,14 @@
bool visitAggregate(Visit visit, TIntermAggregate *node) override
{
- if (visit == PreVisit && node->getOp() == EOpFunctionCall)
+ if (visit == PreVisit && node->getOp() == EOpCallFunctionInAST)
{
- if (node->isUserDefined())
- {
- size_t calleeIndex = mDag.findIndex(node->getFunctionSymbolInfo());
- ASSERT(calleeIndex != CallDAG::InvalidIndex && calleeIndex < mIndex);
+ size_t calleeIndex = mDag.findIndex(node->getFunctionSymbolInfo());
+ ASSERT(calleeIndex != CallDAG::InvalidIndex && calleeIndex < mIndex);
- if ((*mMetadataList)[calleeIndex].mHasGradientLoopInCallGraph)
- {
- onGradientLoop();
- }
+ if ((*mMetadataList)[calleeIndex].mHasGradientLoopInCallGraph)
+ {
+ onGradientLoop();
}
}
@@ -354,8 +347,8 @@
{
switch (node->getOp())
{
- case EOpFunctionCall:
- if (visit == PreVisit && node->isUserDefined() && mNestedDiscont > 0)
+ case EOpCallFunctionInAST:
+ if (visit == PreVisit && mNestedDiscont > 0)
{
size_t calleeIndex = mDag.findIndex(node->getFunctionSymbolInfo());
ASSERT(calleeIndex != CallDAG::InvalidIndex && calleeIndex < mIndex);
diff --git a/src/compiler/translator/ArrayReturnValueToOutParameter.cpp b/src/compiler/translator/ArrayReturnValueToOutParameter.cpp
index 4a16936..3f0952f 100644
--- a/src/compiler/translator/ArrayReturnValueToOutParameter.cpp
+++ b/src/compiler/translator/ArrayReturnValueToOutParameter.cpp
@@ -43,9 +43,8 @@
TIntermAggregate *CreateReplacementCall(TIntermAggregate *originalCall,
TIntermTyped *returnValueTarget)
{
- TIntermAggregate *replacementCall = new TIntermAggregate(EOpFunctionCall);
+ TIntermAggregate *replacementCall = new TIntermAggregate(EOpCallFunctionInAST);
replacementCall->setType(TType(EbtVoid));
- replacementCall->setUserDefined();
*replacementCall->getFunctionSymbolInfo() = *originalCall->getFunctionSymbolInfo();
replacementCall->setLine(originalCall->getLine());
TIntermSequence *replacementParameters = replacementCall->getSequence();
@@ -124,7 +123,8 @@
bool ArrayReturnValueToOutParameterTraverser::visitAggregate(Visit visit, TIntermAggregate *node)
{
- if (visit == PreVisit && node->isArray() && node->getOp() == EOpFunctionCall)
+ ASSERT(!node->isArray() || node->getOp() != EOpCallInternalRawFunction);
+ if (visit == PreVisit && node->isArray() && node->getOp() == EOpCallFunctionInAST)
{
// Handle call sites where the returned array is not assigned.
// Examples where f() is a function returning an array:
@@ -181,8 +181,8 @@
if (node->getOp() == EOpAssign && node->getLeft()->isArray())
{
TIntermAggregate *rightAgg = node->getRight()->getAsAggregate();
- if (rightAgg != nullptr && rightAgg->getOp() == EOpFunctionCall &&
- rightAgg->isUserDefined())
+ ASSERT(rightAgg == nullptr || rightAgg->getOp() != EOpCallInternalRawFunction);
+ if (rightAgg != nullptr && rightAgg->getOp() == EOpCallFunctionInAST)
{
TIntermAggregate *replacementCall = CreateReplacementCall(rightAgg, node->getLeft());
queueReplacement(node, replacementCall, OriginalNode::IS_DROPPED);
diff --git a/src/compiler/translator/BuiltInFunctionEmulator.cpp b/src/compiler/translator/BuiltInFunctionEmulator.cpp
index 64f0b86..8b7d9f8 100644
--- a/src/compiler/translator/BuiltInFunctionEmulator.cpp
+++ b/src/compiler/translator/BuiltInFunctionEmulator.cpp
@@ -38,7 +38,7 @@
{
// Here we handle all the built-in functions mapped to ops, not just the ones that are
// currently identified as problematic.
- if (node->isConstructor() || node->getOp() == EOpFunctionCall)
+ if (node->isConstructor() || node->isFunctionCall())
{
return true;
}
diff --git a/src/compiler/translator/CallDAG.cpp b/src/compiler/translator/CallDAG.cpp
index e09f8c9..6daa778 100644
--- a/src/compiler/translator/CallDAG.cpp
+++ b/src/compiler/translator/CallDAG.cpp
@@ -136,30 +136,17 @@
// 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())
+ if (visit == PreVisit && node->getOp() == EOpCallFunctionInAST)
{
- case EOpFunctionCall:
- {
- // Function call, add the callees
- if (visit == PreVisit)
- {
- // Do not handle calls to builtin functions
- if (node->isUserDefined())
- {
- auto it = mFunctions.find(node->getFunctionSymbolInfo()->getName());
- ASSERT(it != mFunctions.end());
+ // Function call, add the callees
+ auto it = mFunctions.find(node->getFunctionSymbolInfo()->getName());
+ ASSERT(it != mFunctions.end());
- // We might be in a top-level function call to set a global variable
- if (mCurrentFunction)
- {
- mCurrentFunction->callees.insert(&it->second);
- }
- }
- }
- break;
+ // We might be in a top-level function call to set a global variable
+ if (mCurrentFunction)
+ {
+ mCurrentFunction->callees.insert(&it->second);
}
- default:
- break;
}
return true;
}
diff --git a/src/compiler/translator/DeferGlobalInitializers.cpp b/src/compiler/translator/DeferGlobalInitializers.cpp
index ffb149a..3e2224b 100644
--- a/src/compiler/translator/DeferGlobalInitializers.cpp
+++ b/src/compiler/translator/DeferGlobalInitializers.cpp
@@ -50,9 +50,7 @@
TIntermAggregate *CreateFunctionCallNode(const char *name, const int functionId)
{
- TIntermAggregate *functionNode = new TIntermAggregate(EOpFunctionCall);
-
- functionNode->setUserDefined();
+ TIntermAggregate *functionNode = new TIntermAggregate(EOpCallFunctionInAST);
SetInternalFunctionName(functionNode->getFunctionSymbolInfo(), name);
TType returnType(EbtVoid);
functionNode->setType(returnType);
diff --git a/src/compiler/translator/EmulatePrecision.cpp b/src/compiler/translator/EmulatePrecision.cpp
index 6ae74a3..1c9dc39 100644
--- a/src/compiler/translator/EmulatePrecision.cpp
+++ b/src/compiler/translator/EmulatePrecision.cpp
@@ -429,7 +429,7 @@
TIntermAggregate *createInternalFunctionCallNode(TString name, TIntermNode *child)
{
- TIntermAggregate *callNode = new TIntermAggregate(EOpFunctionCall);
+ TIntermAggregate *callNode = new TIntermAggregate(EOpCallInternalRawFunction);
TName nameObj(TFunction::mangleName(name));
nameObj.setInternal(true);
callNode->getFunctionSymbolInfo()->setNameObj(nameObj);
@@ -638,24 +638,11 @@
switch (node->getOp())
{
case EOpConstructStruct:
+ case EOpCallInternalRawFunction:
+ case EOpCallFunctionInAST:
+ // User-defined function return values are not rounded. The calculations that produced
+ // the value inside the function definition should have been rounded.
break;
- case EOpFunctionCall:
- {
- // Function call.
- if (visit == PreVisit)
- {
- // User-defined function return values are not rounded, this relies on that
- // calculations producing the value were rounded.
- TIntermNode *parent = getParentNode();
- if (canRoundFloat(node->getType()) && !isInFunctionMap(node) &&
- parentUsesResult(parent, node))
- {
- TIntermNode *replacement = createRoundingFunctionCallNode(node);
- queueReplacement(node, replacement, OriginalNode::BECOMES_CHILD);
- }
- }
- break;
- }
default:
TIntermNode *parent = getParentNode();
if (canRoundFloat(node->getType()) && visit == PreVisit &&
diff --git a/src/compiler/translator/IntermNode.cpp b/src/compiler/translator/IntermNode.cpp
index 2c85e4f..6bf2aa8 100644
--- a/src/compiler/translator/IntermNode.cpp
+++ b/src/compiler/translator/IntermNode.cpp
@@ -309,7 +309,7 @@
void TIntermAggregate::setPrecisionForBuiltInOp()
{
ASSERT(!isConstructor());
- ASSERT(mOp != EOpFunctionCall);
+ ASSERT(!isFunctionCall());
if (!setPrecisionForSpecialBuiltInOp())
{
setPrecisionFromChildren();
@@ -340,7 +340,7 @@
{
// All built-ins returning bool should be handled as ops, not functions.
ASSERT(getBasicType() != EbtBool);
- ASSERT(getOp() == EOpFunctionCall);
+ ASSERT(mOp == EOpCallBuiltInFunction);
TPrecision precision = EbpUndefined;
TIntermSequence::iterator childIter = mSequence.begin();
@@ -549,7 +549,6 @@
TIntermAggregate::TIntermAggregate(const TIntermAggregate &node)
: TIntermOperator(node),
- mUserDefined(node.mUserDefined),
mUseEmulatedFunction(node.mUseEmulatedFunction),
mGotPrecisionFromChildren(node.mGotPrecisionFromChildren),
mFunctionInfo(node.mFunctionInfo)
@@ -659,6 +658,19 @@
}
}
+bool TIntermOperator::isFunctionCall() const
+{
+ switch (mOp)
+ {
+ case EOpCallFunctionInAST:
+ case EOpCallBuiltInFunction:
+ case EOpCallInternalRawFunction:
+ return true;
+ default:
+ return false;
+ }
+}
+
TOperator TIntermBinary::GetMulOpBasedOnOperands(const TType &left, const TType &right)
{
if (left.isMatrix())
diff --git a/src/compiler/translator/IntermNode.h b/src/compiler/translator/IntermNode.h
index d75ba6c..b90ef61 100644
--- a/src/compiler/translator/IntermNode.h
+++ b/src/compiler/translator/IntermNode.h
@@ -411,6 +411,10 @@
bool isMultiplication() const;
bool isConstructor() const;
+ // Returns true for calls mapped to EOpCall*, false for built-ins that have their own specific
+ // ops.
+ bool isFunctionCall() const;
+
bool hasSideEffects() const override { return isAssignment(); }
protected:
@@ -547,6 +551,7 @@
void setFromFunction(const TFunction &function);
+ // The name stored here should always be mangled.
void setNameObj(const TName &name) { mName = name; }
const TName &getNameObj() const { return mName; }
@@ -590,7 +595,6 @@
public:
TIntermAggregate(TOperator op)
: TIntermOperator(op),
- mUserDefined(false),
mUseEmulatedFunction(false),
mGotPrecisionFromChildren(false)
{
@@ -613,9 +617,6 @@
TIntermSequence *getSequence() override { return &mSequence; }
const TIntermSequence *getSequence() const override { return &mSequence; }
- void setUserDefined() { mUserDefined = true; }
- bool isUserDefined() const { return mUserDefined; }
-
void setUseEmulatedFunction() { mUseEmulatedFunction = true; }
bool getUseEmulatedFunction() { return mUseEmulatedFunction; }
@@ -625,7 +626,7 @@
void setPrecisionFromChildren();
- // Used for built-in functions under EOpFunctionCall.
+ // Used for built-in functions under EOpCallBuiltInFunction.
void setBuiltInFunctionPrecision();
// Returns true if changing parameter precision may affect the return value.
@@ -636,10 +637,9 @@
protected:
TIntermSequence mSequence;
- bool mUserDefined; // used for user defined function names
// If set to true, replace the built-in function call with an emulated one
- // to work around driver bugs.
+ // to work around driver bugs. Only for calls mapped to ops other than EOpCall*.
bool mUseEmulatedFunction;
bool mGotPrecisionFromChildren;
@@ -1188,10 +1188,6 @@
return mOperatorRequiresLValue || mInFunctionCallOutParameter;
}
- // Return true if the prototype or definition of the function being called has been encountered
- // during traversal.
- bool isInFunctionMap(const TIntermAggregate *callNode) const;
-
private:
// Track whether an l-value is required in the node that is currently being traversed by the
// surrounding operator.
@@ -1205,6 +1201,10 @@
// Add a function encountered during traversal to the function map.
void addToFunctionMap(const TName &name, TIntermSequence *paramSequence);
+ // Return true if the prototype or definition of the function being called has been encountered
+ // during traversal.
+ bool isInFunctionMap(const TIntermAggregate *callNode) const;
+
// Return the parameters sequence from the function definition or prototype.
TIntermSequence *getFunctionParameters(const TIntermAggregate *callNode);
diff --git a/src/compiler/translator/IntermNodePatternMatcher.cpp b/src/compiler/translator/IntermNodePatternMatcher.cpp
index 6996c45..bc0847d 100644
--- a/src/compiler/translator/IntermNodePatternMatcher.cpp
+++ b/src/compiler/translator/IntermNodePatternMatcher.cpp
@@ -87,8 +87,7 @@
(parentBinary->getOp() == EOpAssign || parentBinary->getOp() == EOpInitialize));
if (node->getType().isArray() && !parentIsAssignment &&
- (node->isConstructor() || node->getOp() == EOpFunctionCall) &&
- !parentNode->getAsBlock())
+ (node->isConstructor() || node->isFunctionCall()) && !parentNode->getAsBlock())
{
return true;
}
diff --git a/src/compiler/translator/IntermTraverse.cpp b/src/compiler/translator/IntermTraverse.cpp
index b58b27c..8980e69 100644
--- a/src/compiler/translator/IntermTraverse.cpp
+++ b/src/compiler/translator/IntermTraverse.cpp
@@ -235,7 +235,7 @@
bool TLValueTrackingTraverser::isInFunctionMap(const TIntermAggregate *callNode) const
{
- ASSERT(callNode->getOp() == EOpFunctionCall);
+ ASSERT(callNode->getOp() == EOpCallFunctionInAST);
return (mFunctionMap.find(callNode->getFunctionSymbolInfo()->getNameObj()) !=
mFunctionMap.end());
}
@@ -641,36 +641,43 @@
if (visit)
{
- bool inFunctionMap = false;
- if (node->getOp() == EOpFunctionCall)
+ if (node->getOp() == EOpCallFunctionInAST)
{
- inFunctionMap = isInFunctionMap(node);
- if (!inFunctionMap)
+ if (isInFunctionMap(node))
{
- // The function is not user-defined - it is likely built-in texture function.
- // Assume that those do not have out parameters.
- setInFunctionCallOutParameter(false);
- }
- }
-
- if (inFunctionMap)
- {
- TIntermSequence *params = getFunctionParameters(node);
- TIntermSequence::iterator paramIter = params->begin();
- for (auto *child : *sequence)
- {
- ASSERT(paramIter != params->end());
- TQualifier qualifier = (*paramIter)->getAsTyped()->getQualifier();
- setInFunctionCallOutParameter(qualifier == EvqOut || qualifier == EvqInOut);
-
- child->traverse(this);
- if (visit && inVisit)
+ TIntermSequence *params = getFunctionParameters(node);
+ TIntermSequence::iterator paramIter = params->begin();
+ for (auto *child : *sequence)
{
- if (child != sequence->back())
- visit = visitAggregate(InVisit, node);
- }
+ ASSERT(paramIter != params->end());
+ TQualifier qualifier = (*paramIter)->getAsTyped()->getQualifier();
+ setInFunctionCallOutParameter(qualifier == EvqOut || qualifier == EvqInOut);
- ++paramIter;
+ child->traverse(this);
+ if (visit && inVisit)
+ {
+ if (child != sequence->back())
+ visit = visitAggregate(InVisit, node);
+ }
+
+ ++paramIter;
+ }
+ }
+ else
+ {
+ // The node might not be in the function map in case we're in the middle of
+ // transforming the AST, and have inserted function call nodes without inserting the
+ // function definitions yet.
+ setInFunctionCallOutParameter(false);
+ for (auto *child : *sequence)
+ {
+ child->traverse(this);
+ if (visit && inVisit)
+ {
+ if (child != sequence->back())
+ visit = visitAggregate(InVisit, node);
+ }
+ }
}
setInFunctionCallOutParameter(false);
@@ -680,7 +687,7 @@
// Find the built-in function corresponding to this op so that we can determine the
// in/out qualifiers of its parameters.
TFunction *builtInFunc = nullptr;
- if (!node->isConstructor() && node->getOp() != EOpFunctionCall)
+ if (!node->isFunctionCall() && !node->isConstructor())
{
builtInFunc = mSymbolTable.findBuiltInOp(node, mShaderVersion);
}
@@ -689,6 +696,8 @@
for (auto *child : *sequence)
{
+ // This assumes that raw functions called with
+ // EOpCallInternalRawFunction don't have out parameters.
TQualifier qualifier = EvqIn;
if (builtInFunc != nullptr)
qualifier = builtInFunc->getParam(paramIndex).type->getQualifier();
diff --git a/src/compiler/translator/Operator.cpp b/src/compiler/translator/Operator.cpp
index 79b193f..12ae1a9 100644
--- a/src/compiler/translator/Operator.cpp
+++ b/src/compiler/translator/Operator.cpp
@@ -10,7 +10,7 @@
{
switch (op)
{
- // Note: EOpNull and EOpFunctionCall can't be handled here.
+ // Note: EOpNull and EOpCall* can't be handled here.
case EOpNegative:
return "-";
diff --git a/src/compiler/translator/Operator.h b/src/compiler/translator/Operator.h
index c185573..968dbac 100644
--- a/src/compiler/translator/Operator.h
+++ b/src/compiler/translator/Operator.h
@@ -13,7 +13,20 @@
enum TOperator
{
EOpNull, // if in a node, should only mean a node is still being built
- EOpFunctionCall,
+
+ // Call a function defined in the AST. This might be a user-defined function or a function
+ // inserted by an AST transformation.
+ EOpCallFunctionInAST,
+
+ // Call an internal helper function with a raw implementation - the implementation can't be
+ // subject to AST transformations. Raw functions have a few constraints to keep them compatible
+ // with AST traversers:
+ // * They should not return arrays.
+ // * They should not have out parameters.
+ EOpCallInternalRawFunction,
+
+ // Call a built-in function like a texture or image function.
+ EOpCallBuiltInFunction,
//
// Unary operators
diff --git a/src/compiler/translator/OutputGLSLBase.cpp b/src/compiler/translator/OutputGLSLBase.cpp
index 0c3b501..3a2a757 100644
--- a/src/compiler/translator/OutputGLSLBase.cpp
+++ b/src/compiler/translator/OutputGLSLBase.cpp
@@ -877,7 +877,9 @@
TInfoSinkBase &out = objSink();
switch (node->getOp())
{
- case EOpFunctionCall:
+ case EOpCallFunctionInAST:
+ case EOpCallInternalRawFunction:
+ case EOpCallBuiltInFunction:
// Function call.
if (visit == PreVisit)
out << hashFunctionNameIfNeeded(node->getFunctionSymbolInfo()->getNameObj()) << "(";
diff --git a/src/compiler/translator/OutputHLSL.cpp b/src/compiler/translator/OutputHLSL.cpp
index 5539a99..8a3794d 100644
--- a/src/compiler/translator/OutputHLSL.cpp
+++ b/src/compiler/translator/OutputHLSL.cpp
@@ -1000,7 +1000,7 @@
}
// ArrayReturnValueToOutParameter should have eliminated expressions where a
// function call is assigned.
- ASSERT(rightAgg == nullptr || rightAgg->getOp() != EOpFunctionCall);
+ ASSERT(rightAgg == nullptr);
const TString &functionName = addArrayAssignmentFunction(node->getType());
outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
@@ -1755,12 +1755,14 @@
switch (node->getOp())
{
- case EOpFunctionCall:
+ case EOpCallBuiltInFunction:
+ case EOpCallFunctionInAST:
+ case EOpCallInternalRawFunction:
{
TIntermSequence *arguments = node->getSequence();
bool lod0 = mInsideDiscontinuousLoop || mOutputLod0Function;
- if (node->isUserDefined())
+ if (node->getOp() == EOpCallFunctionInAST)
{
if (node->isArray())
{
@@ -1774,7 +1776,7 @@
out << DisambiguateFunctionName(node->getSequence());
out << (lod0 ? "Lod0(" : "(");
}
- else if (node->getFunctionSymbolInfo()->getNameObj().isInternal())
+ else if (node->getOp() == EOpCallInternalRawFunction)
{
// This path is used for internal functions that don't have their definitions in the
// AST, such as precision emulation functions.
diff --git a/src/compiler/translator/ParseContext.cpp b/src/compiler/translator/ParseContext.cpp
index 41b58d4..918dd85 100644
--- a/src/compiler/translator/ParseContext.cpp
+++ b/src/compiler/translator/ParseContext.cpp
@@ -4180,7 +4180,7 @@
void TParseContext::checkTextureOffsetConst(TIntermAggregate *functionCall)
{
- ASSERT(!functionCall->isUserDefined());
+ ASSERT(functionCall->getOp() == EOpCallBuiltInFunction);
const TString &name = functionCall->getFunctionSymbolInfo()->getName();
TIntermNode *offset = nullptr;
TIntermSequence *arguments = functionCall->getSequence();
@@ -4232,7 +4232,7 @@
// GLSL ES 3.10 Revision 4, 4.9 Memory Access Qualifiers
void TParseContext::checkImageMemoryAccessForBuiltinFunctions(TIntermAggregate *functionCall)
{
- ASSERT(!functionCall->isUserDefined());
+ ASSERT(functionCall->getOp() == EOpCallBuiltInFunction);
const TString &name = functionCall->getFunctionSymbolInfo()->getName();
if (name.compare(0, 5, "image") == 0)
@@ -4269,7 +4269,7 @@
const TFunction *functionDefinition,
const TIntermAggregate *functionCall)
{
- ASSERT(functionCall->isUserDefined());
+ ASSERT(functionCall->getOp() == EOpCallFunctionInAST);
const TIntermSequence &arguments = *functionCall->getSequence();
@@ -4463,29 +4463,24 @@
{
// This is a real function call
ASSERT(argumentsNode->getOp() == EOpNull);
- argumentsNode->setOp(EOpFunctionCall);
argumentsNode->setType(fnCandidate->getReturnType());
-
- // this is how we know whether the given function is a builtIn function or a user
- // defined function
- // if builtIn == false, it's a userDefined -> could be an overloaded
- // builtIn function also
- // if builtIn == true, it's definitely a builtIn function with EOpNull
- if (!builtIn)
- argumentsNode->setUserDefined();
argumentsNode->getFunctionSymbolInfo()->setFromFunction(*fnCandidate);
- // This needs to happen after the function info including name is set
+ // If builtIn == false, the function is user defined - could be an overloaded
+ // built-in as well.
+ // if builtIn == true, it's a builtIn function with no op associated with it.
+ // This needs to happen after the function info including name is set.
if (builtIn)
{
+ argumentsNode->setOp(EOpCallBuiltInFunction);
argumentsNode->setBuiltInFunctionPrecision();
checkTextureOffsetConst(argumentsNode);
-
checkImageMemoryAccessForBuiltinFunctions(argumentsNode);
}
else
{
+ argumentsNode->setOp(EOpCallFunctionInAST);
checkImageMemoryAccessForUserDefinedFunctions(fnCandidate, argumentsNode);
}
diff --git a/src/compiler/translator/RemoveDynamicIndexing.cpp b/src/compiler/translator/RemoveDynamicIndexing.cpp
index 41aaced..fbe0264 100644
--- a/src/compiler/translator/RemoveDynamicIndexing.cpp
+++ b/src/compiler/translator/RemoveDynamicIndexing.cpp
@@ -55,6 +55,8 @@
}
TString nameString = TFunction::mangleName(nameSink.c_str());
TName name(nameString);
+ // TODO(oetuaho@nvidia.com): would be better to have the parameter types in the mangled name as
+ // well.
name.setInternal(true);
return name;
}
@@ -349,9 +351,8 @@
TIntermTyped *index)
{
ASSERT(node->getOp() == EOpIndexIndirect);
- TIntermAggregate *indexingCall = new TIntermAggregate(EOpFunctionCall);
+ TIntermAggregate *indexingCall = new TIntermAggregate(EOpCallFunctionInAST);
indexingCall->setLine(node->getLine());
- indexingCall->setUserDefined();
indexingCall->getFunctionSymbolInfo()->setNameObj(
GetIndexFunctionName(indexedNode->getType(), false));
indexingCall->getSequence()->push_back(indexedNode);
@@ -520,6 +521,11 @@
root->traverse(&traverser);
traverser.updateTree();
} while (traverser.usedTreeInsertion());
+ // TOOD(oetuaho@nvidia.com): It might be nicer to add the helper definitions also in the middle
+ // of traversal. Now the tree ends up in an inconsistent state in the middle, since there are
+ // function call nodes with no corresponding definition nodes. This needs special handling in
+ // TIntermLValueTrackingTraverser, and creates intricacies that are not easily apparent from a
+ // superficial reading of the code.
traverser.insertHelperDefinitions(root);
traverser.updateTree();
}
diff --git a/src/compiler/translator/RewriteTexelFetchOffset.cpp b/src/compiler/translator/RewriteTexelFetchOffset.cpp
index cd57c97..96e7db6 100644
--- a/src/compiler/translator/RewriteTexelFetchOffset.cpp
+++ b/src/compiler/translator/RewriteTexelFetchOffset.cpp
@@ -66,7 +66,7 @@
}
// Decide if the node represents the call of texelFetchOffset.
- if (node->getOp() != EOpFunctionCall || node->isUserDefined())
+ if (node->getOp() != EOpCallBuiltInFunction)
{
return true;
}
@@ -94,7 +94,7 @@
// Create new node that represents the call of function texelFetch.
// Its argument list will be: texelFetch(sampler, Position+offset, lod).
- TIntermAggregate *texelFetchNode = new TIntermAggregate(EOpFunctionCall);
+ TIntermAggregate *texelFetchNode = new TIntermAggregate(EOpCallBuiltInFunction);
texelFetchNode->getFunctionSymbolInfo()->setName(newName);
texelFetchNode->getFunctionSymbolInfo()->setId(uniqueId);
texelFetchNode->setType(node->getType());
diff --git a/src/compiler/translator/SeparateExpressionsReturningArrays.cpp b/src/compiler/translator/SeparateExpressionsReturningArrays.cpp
index 61a1874..ddce9c3 100644
--- a/src/compiler/translator/SeparateExpressionsReturningArrays.cpp
+++ b/src/compiler/translator/SeparateExpressionsReturningArrays.cpp
@@ -63,10 +63,6 @@
copySeq->insert(copySeq->begin(), node->getSequence()->begin(), node->getSequence()->end());
copyNode->setType(node->getType());
*copyNode->getFunctionSymbolInfo() = *node->getFunctionSymbolInfo();
- if (node->isUserDefined())
- {
- copyNode->setUserDefined();
- }
return copyNode;
}
@@ -104,7 +100,7 @@
if (!mPatternToSeparateMatcher.match(node, getParentNode()))
return true;
- ASSERT(node->isConstructor() || node->getOp() == EOpFunctionCall);
+ ASSERT(node->isConstructor() || node->getOp() == EOpCallFunctionInAST);
mFoundArrayExpression = true;
diff --git a/src/compiler/translator/SymbolTable.cpp b/src/compiler/translator/SymbolTable.cpp
index c9ccd2b..3ba0223 100644
--- a/src/compiler/translator/SymbolTable.cpp
+++ b/src/compiler/translator/SymbolTable.cpp
@@ -158,7 +158,7 @@
TFunction *TSymbolTable::findBuiltInOp(TIntermAggregate *callNode, int shaderVersion) const
{
ASSERT(!callNode->isConstructor());
- ASSERT(callNode->getOp() != EOpFunctionCall);
+ ASSERT(!callNode->isFunctionCall());
TString opString = GetOperatorString(callNode->getOp());
// The return type doesn't affect the mangled name of the function, which is used to look it up.
TType dummyReturnType;
diff --git a/src/compiler/translator/ValidateGlobalInitializer.cpp b/src/compiler/translator/ValidateGlobalInitializer.cpp
index c4caa29..10a3e51 100644
--- a/src/compiler/translator/ValidateGlobalInitializer.cpp
+++ b/src/compiler/translator/ValidateGlobalInitializer.cpp
@@ -72,8 +72,8 @@
// Disallow calls to user-defined functions and texture lookup functions in global variable
// initializers.
// This is done simply by disabling all function calls - built-in math functions don't use
- // EOpFunctionCall.
- if (node->getOp() == EOpFunctionCall)
+ // the function call ops.
+ if (node->isFunctionCall())
{
mIsValid = false;
}
diff --git a/src/compiler/translator/ValidateLimitations.cpp b/src/compiler/translator/ValidateLimitations.cpp
index 3a88d38..0369eaa 100644
--- a/src/compiler/translator/ValidateLimitations.cpp
+++ b/src/compiler/translator/ValidateLimitations.cpp
@@ -108,7 +108,8 @@
{
switch (node->getOp())
{
- case EOpFunctionCall:
+ case EOpCallFunctionInAST:
+ case EOpCallBuiltInFunction:
validateFunctionCall(node);
break;
default:
@@ -378,7 +379,7 @@
bool ValidateLimitations::validateFunctionCall(TIntermAggregate *node)
{
- ASSERT(node->getOp() == EOpFunctionCall);
+ ASSERT(node->getOp() == EOpCallFunctionInAST || node->getOp() == EOpCallBuiltInFunction);
// If not within loop body, there is nothing to check.
if (!withinLoopBody())
diff --git a/src/compiler/translator/ValidateMultiviewWebGL.cpp b/src/compiler/translator/ValidateMultiviewWebGL.cpp
index 08ae816..fa6cf02 100644
--- a/src/compiler/translator/ValidateMultiviewWebGL.cpp
+++ b/src/compiler/translator/ValidateMultiviewWebGL.cpp
@@ -354,27 +354,24 @@
{
// Check if the node is an user-defined function call or if an l-value is required, or if
// there are possible visible side effects, such as image writes.
- if (node->getOp() == EOpFunctionCall)
+ if (node->getOp() == EOpCallFunctionInAST)
{
- if (node->isUserDefined())
- {
- mDiagnostics->error(node->getLine(),
- "Disallowed user defined function call inside assignment to "
- "gl_Position.x when using OVR_multiview",
- GetOperatorString(node->getOp()));
- mValid = false;
- }
- else if (TFunction::unmangleName(node->getFunctionSymbolInfo()->getName()) ==
- "imageStore")
- {
- // TODO(oetuaho@nvidia.com): Record which built-in functions have side effects in
- // the symbol info instead.
- mDiagnostics->error(node->getLine(),
- "Disallowed function call with side effects inside assignment "
- "to gl_Position.x when using OVR_multiview",
- GetOperatorString(node->getOp()));
- mValid = false;
- }
+ mDiagnostics->error(node->getLine(),
+ "Disallowed user defined function call inside assignment to "
+ "gl_Position.x when using OVR_multiview",
+ GetOperatorString(node->getOp()));
+ mValid = false;
+ }
+ else if (node->getOp() == EOpCallBuiltInFunction &&
+ TFunction::unmangleName(node->getFunctionSymbolInfo()->getName()) == "imageStore")
+ {
+ // TODO(oetuaho@nvidia.com): Record which built-in functions have side effects in
+ // the symbol info instead.
+ mDiagnostics->error(node->getLine(),
+ "Disallowed function call with side effects inside assignment "
+ "to gl_Position.x when using OVR_multiview",
+ GetOperatorString(node->getOp()));
+ mValid = false;
}
else if (!node->isConstructor())
{
diff --git a/src/compiler/translator/intermOut.cpp b/src/compiler/translator/intermOut.cpp
index d4edd6e..6312ef7 100644
--- a/src/compiler/translator/intermOut.cpp
+++ b/src/compiler/translator/intermOut.cpp
@@ -403,8 +403,15 @@
// mostly use GLSL names for functions.
switch (node->getOp())
{
- case EOpFunctionCall:
- OutputFunction(out, "Function Call", node->getFunctionSymbolInfo());
+ case EOpCallFunctionInAST:
+ OutputFunction(out, "Call an user-defined function", node->getFunctionSymbolInfo());
+ break;
+ case EOpCallInternalRawFunction:
+ OutputFunction(out, "Call an internal function with raw implementation",
+ node->getFunctionSymbolInfo());
+ break;
+ case EOpCallBuiltInFunction:
+ OutputFunction(out, "Call a built-in function", node->getFunctionSymbolInfo());
break;
case EOpEqualComponentWise: