Commit af6fc1b4 by Olli Etuaho Committed by Commit Bot

Make aggregate node creation more robust

Now aggregate nodes are always built with their return type, op and arguments set. They'll determine their qualifier and precision automatically. This fixes setting of gotPrecisionFromChildren in a few cases. This will also make it easier to split TIntermAggregate further into specialized classes if that is desired. BUG=angleproject:1490 TEST=angle_unittests Change-Id: I1fbe0c75679c517a22d44dfc1ea160ad7a7fdfda Reviewed-on: https://chromium-review.googlesource.com/433468Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
parent ccab69d6
......@@ -43,17 +43,17 @@ TIntermSymbol *CreateReturnValueOutSymbol(const TType &type)
TIntermAggregate *CreateReplacementCall(TIntermAggregate *originalCall,
TIntermTyped *returnValueTarget)
{
TIntermAggregate *replacementCall = new TIntermAggregate(EOpCallFunctionInAST);
replacementCall->setType(TType(EbtVoid));
*replacementCall->getFunctionSymbolInfo() = *originalCall->getFunctionSymbolInfo();
replacementCall->setLine(originalCall->getLine());
TIntermSequence *replacementParameters = replacementCall->getSequence();
TIntermSequence *originalParameters = originalCall->getSequence();
for (auto &param : *originalParameters)
TIntermSequence *replacementArguments = new TIntermSequence();
TIntermSequence *originalArguments = originalCall->getSequence();
for (auto &arg : *originalArguments)
{
replacementParameters->push_back(param);
replacementArguments->push_back(arg);
}
replacementParameters->push_back(returnValueTarget);
replacementArguments->push_back(returnValueTarget);
TIntermAggregate *replacementCall =
new TIntermAggregate(TType(EbtVoid), EOpCallFunctionInAST, replacementArguments);
*replacementCall->getFunctionSymbolInfo() = *originalCall->getFunctionSymbolInfo();
replacementCall->setLine(originalCall->getLine());
return replacementCall;
}
......
......@@ -50,10 +50,10 @@ TIntermFunctionDefinition *CreateFunctionDefinitionNode(const char *name,
TIntermAggregate *CreateFunctionCallNode(const char *name, const int functionId)
{
TIntermAggregate *functionNode = new TIntermAggregate(EOpCallFunctionInAST);
SetInternalFunctionName(functionNode->getFunctionSymbolInfo(), name);
TType returnType(EbtVoid);
functionNode->setType(returnType);
TIntermAggregate *functionNode =
new TIntermAggregate(returnType, EOpCallFunctionInAST, nullptr);
SetInternalFunctionName(functionNode->getFunctionSymbolInfo(), name);
functionNode->getFunctionSymbolInfo()->setId(functionId);
return functionNode;
}
......
......@@ -427,13 +427,14 @@ bool canRoundFloat(const TType &type)
(type.getPrecision() == EbpLow || type.getPrecision() == EbpMedium);
}
TIntermAggregate *createInternalFunctionCallNode(TString name, TIntermNode *child)
TIntermAggregate *createInternalFunctionCallNode(const TType &type,
TString name,
TIntermSequence *arguments)
{
TIntermAggregate *callNode = new TIntermAggregate(EOpCallInternalRawFunction);
TName nameObj(TFunction::mangleName(name));
TName nameObj(TFunction::GetMangledNameFromCall(name, *arguments));
nameObj.setInternal(true);
TIntermAggregate *callNode = new TIntermAggregate(type, EOpCallInternalRawFunction, arguments);
callNode->getFunctionSymbolInfo()->setNameObj(nameObj);
callNode->getSequence()->push_back(child);
return callNode;
}
......@@ -444,9 +445,9 @@ TIntermAggregate *createRoundingFunctionCallNode(TIntermTyped *roundedChild)
roundFunctionName = "angle_frm";
else
roundFunctionName = "angle_frl";
TIntermAggregate *callNode = createInternalFunctionCallNode(roundFunctionName, roundedChild);
callNode->setType(roundedChild->getType());
return callNode;
TIntermSequence *arguments = new TIntermSequence();
arguments->push_back(roundedChild);
return createInternalFunctionCallNode(roundedChild->getType(), roundFunctionName, arguments);
}
TIntermAggregate *createCompoundAssignmentFunctionCallNode(TIntermTyped *left,
......@@ -459,9 +460,10 @@ TIntermAggregate *createCompoundAssignmentFunctionCallNode(TIntermTyped *left,
else
strstr << "angle_compound_" << opNameStr << "_frl";
TString functionName = strstr.str().c_str();
TIntermAggregate *callNode = createInternalFunctionCallNode(functionName, left);
callNode->getSequence()->push_back(right);
return callNode;
TIntermSequence *arguments = new TIntermSequence();
arguments->push_back(left);
arguments->push_back(right);
return createInternalFunctionCallNode(TType(EbtVoid), functionName, arguments);
}
bool parentUsesResult(TIntermNode *parent, TIntermNode *node)
......
......@@ -272,12 +272,48 @@ bool TIntermAggregateBase::insertChildNodes(TIntermSequence::size_type position,
return true;
}
TIntermAggregate::TIntermAggregate(const TType &type, TOperator op, TIntermSequence *arguments)
: TIntermOperator(op), mUseEmulatedFunction(false), mGotPrecisionFromChildren(false)
{
if (arguments != nullptr)
{
mArguments.swap(*arguments);
}
setTypePrecisionAndQualifier(type);
}
void TIntermAggregate::setTypePrecisionAndQualifier(const TType &type)
{
setType(type);
mType.setQualifier(EvqTemporary);
if (!isFunctionCall())
{
if (isConstructor())
{
// Structs should not be precision qualified, the individual members may be.
// Built-in types on the other hand should be precision qualified.
if (mOp != EOpConstructStruct)
{
setPrecisionFromChildren();
}
}
else
{
setPrecisionForBuiltInOp();
}
if (areChildrenConstQualified())
{
mType.setQualifier(EvqConst);
}
}
}
bool TIntermAggregate::areChildrenConstQualified()
{
for (TIntermNode *&child : mSequence)
for (TIntermNode *&arg : mArguments)
{
TIntermTyped *typed = child->getAsTyped();
if (typed && typed->getQualifier() != EvqConst)
TIntermTyped *typedArg = arg->getAsTyped();
if (typedArg && typedArg->getQualifier() != EvqConst)
{
return false;
}
......@@ -295,8 +331,8 @@ void TIntermAggregate::setPrecisionFromChildren()
}
TPrecision precision = EbpUndefined;
TIntermSequence::iterator childIter = mSequence.begin();
while (childIter != mSequence.end())
TIntermSequence::iterator childIter = mArguments.begin();
while (childIter != mArguments.end())
{
TIntermTyped *typed = (*childIter)->getAsTyped();
if (typed)
......@@ -321,11 +357,13 @@ bool TIntermAggregate::setPrecisionForSpecialBuiltInOp()
switch (mOp)
{
case EOpBitfieldExtract:
mType.setPrecision(mSequence[0]->getAsTyped()->getPrecision());
mType.setPrecision(mArguments[0]->getAsTyped()->getPrecision());
mGotPrecisionFromChildren = true;
return true;
case EOpBitfieldInsert:
mType.setPrecision(GetHigherPrecision(mSequence[0]->getAsTyped()->getPrecision(),
mSequence[1]->getAsTyped()->getPrecision()));
mType.setPrecision(GetHigherPrecision(mArguments[0]->getAsTyped()->getPrecision(),
mArguments[1]->getAsTyped()->getPrecision()));
mGotPrecisionFromChildren = true;
return true;
case EOpUaddCarry:
case EOpUsubBorrow:
......@@ -342,18 +380,16 @@ void TIntermAggregate::setBuiltInFunctionPrecision()
ASSERT(getBasicType() != EbtBool);
ASSERT(mOp == EOpCallBuiltInFunction);
TPrecision precision = EbpUndefined;
TIntermSequence::iterator childIter = mSequence.begin();
while (childIter != mSequence.end())
TPrecision precision = EbpUndefined;
for (TIntermNode *arg : mArguments)
{
TIntermTyped *typed = (*childIter)->getAsTyped();
TIntermTyped *typed = arg->getAsTyped();
// ESSL spec section 8: texture functions get their precision from the sampler.
if (typed && IsSampler(typed->getBasicType()))
{
precision = typed->getPrecision();
break;
}
++childIter;
}
// ESSL 3.0 spec section 8: textureSize always gets highp precision.
// All other functions that take a sampler are assumed to be texture functions.
......@@ -497,8 +533,7 @@ TIntermTyped *TIntermTyped::CreateZero(const TType &type)
return node;
}
TIntermAggregate *constructor = new TIntermAggregate(sh::TypeToConstructorOperator(type));
constructor->setType(constType);
TIntermSequence *arguments = new TIntermSequence();
if (type.isArray())
{
......@@ -508,7 +543,7 @@ TIntermTyped *TIntermTyped::CreateZero(const TType &type)
size_t arraySize = type.getArraySize();
for (size_t i = 0; i < arraySize; ++i)
{
constructor->getSequence()->push_back(CreateZero(elementType));
arguments->push_back(CreateZero(elementType));
}
}
else
......@@ -518,11 +553,11 @@ TIntermTyped *TIntermTyped::CreateZero(const TType &type)
TStructure *structure = type.getStruct();
for (const auto &field : structure->fields())
{
constructor->getSequence()->push_back(CreateZero(*field->type()));
arguments->push_back(CreateZero(*field->type()));
}
}
return constructor;
return new TIntermAggregate(constType, sh::TypeToConstructorOperator(type), arguments);
}
// static
......@@ -553,12 +588,12 @@ TIntermAggregate::TIntermAggregate(const TIntermAggregate &node)
mGotPrecisionFromChildren(node.mGotPrecisionFromChildren),
mFunctionInfo(node.mFunctionInfo)
{
for (TIntermNode *child : node.mSequence)
for (TIntermNode *arg : node.mArguments)
{
TIntermTyped *typedChild = child->getAsTyped();
ASSERT(typedChild != nullptr);
TIntermTyped *childCopy = typedChild->deepCopy();
mSequence.push_back(childCopy);
TIntermTyped *typedArg = arg->getAsTyped();
ASSERT(typedArg != nullptr);
TIntermTyped *argCopy = typedArg->deepCopy();
mArguments.push_back(argCopy);
}
}
......@@ -1308,8 +1343,7 @@ TIntermTyped *TIntermAggregate::fold(TDiagnostics *diagnostics)
constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, diagnostics);
// Nodes may be constant folded without being qualified as constant.
TQualifier resultQualifier = areChildrenConstQualified() ? EvqConst : EvqTemporary;
return CreateFoldedNode(constArray, this, resultQualifier);
return CreateFoldedNode(constArray, this, getQualifier());
}
//
......@@ -2417,32 +2451,32 @@ TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *agg
TDiagnostics *diagnostics)
{
TOperator op = aggregate->getOp();
TIntermSequence *sequence = aggregate->getSequence();
unsigned int paramsCount = static_cast<unsigned int>(sequence->size());
std::vector<const TConstantUnion *> unionArrays(paramsCount);
std::vector<size_t> objectSizes(paramsCount);
TIntermSequence *arguments = aggregate->getSequence();
unsigned int argsCount = static_cast<unsigned int>(arguments->size());
std::vector<const TConstantUnion *> unionArrays(argsCount);
std::vector<size_t> objectSizes(argsCount);
size_t maxObjectSize = 0;
TBasicType basicType = EbtVoid;
TSourceLoc loc;
for (unsigned int i = 0; i < paramsCount; i++)
for (unsigned int i = 0; i < argsCount; i++)
{
TIntermConstantUnion *paramConstant = (*sequence)[i]->getAsConstantUnion();
ASSERT(paramConstant != nullptr); // Should be checked already.
TIntermConstantUnion *argConstant = (*arguments)[i]->getAsConstantUnion();
ASSERT(argConstant != nullptr); // Should be checked already.
if (i == 0)
{
basicType = paramConstant->getType().getBasicType();
loc = paramConstant->getLine();
basicType = argConstant->getType().getBasicType();
loc = argConstant->getLine();
}
unionArrays[i] = paramConstant->getUnionArrayPointer();
objectSizes[i] = paramConstant->getType().getObjectSize();
unionArrays[i] = argConstant->getUnionArrayPointer();
objectSizes[i] = argConstant->getType().getObjectSize();
if (objectSizes[i] > maxObjectSize)
maxObjectSize = objectSizes[i];
}
if (!(*sequence)[0]->getAsTyped()->isMatrix() && aggregate->getOp() != EOpOuterProduct)
if (!(*arguments)[0]->getAsTyped()->isMatrix() && aggregate->getOp() != EOpOuterProduct)
{
for (unsigned int i = 0; i < paramsCount; i++)
for (unsigned int i = 0; i < argsCount; i++)
if (objectSizes[i] != maxObjectSize)
unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
}
......@@ -2791,11 +2825,11 @@ TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *agg
case EOpMulMatrixComponentWise:
{
ASSERT(basicType == EbtFloat && (*sequence)[0]->getAsTyped()->isMatrix() &&
(*sequence)[1]->getAsTyped()->isMatrix());
ASSERT(basicType == EbtFloat && (*arguments)[0]->getAsTyped()->isMatrix() &&
(*arguments)[1]->getAsTyped()->isMatrix());
// Perform component-wise matrix multiplication.
resultArray = new TConstantUnion[maxObjectSize];
int size = (*sequence)[0]->getAsTyped()->getNominalSize();
int size = (*arguments)[0]->getAsTyped()->getNominalSize();
angle::Matrix<float> result =
GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size));
SetUnionArrayFromMatrix(result, resultArray);
......@@ -2805,8 +2839,8 @@ TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *agg
case EOpOuterProduct:
{
ASSERT(basicType == EbtFloat);
size_t numRows = (*sequence)[0]->getAsTyped()->getType().getObjectSize();
size_t numCols = (*sequence)[1]->getAsTyped()->getType().getObjectSize();
size_t numRows = (*arguments)[0]->getAsTyped()->getType().getObjectSize();
size_t numCols = (*arguments)[1]->getAsTyped()->getType().getObjectSize();
resultArray = new TConstantUnion[numRows * numCols];
angle::Matrix<float> result =
GetMatrix(unionArrays[0], static_cast<int>(numRows), 1)
......@@ -2878,7 +2912,7 @@ TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *agg
{
float x = unionArrays[0][i].getFConst();
float y = unionArrays[1][i].getFConst();
TBasicType type = (*sequence)[2]->getAsTyped()->getType().getBasicType();
TBasicType type = (*arguments)[2]->getAsTyped()->getType().getBasicType();
if (type == EbtFloat)
{
// Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
......
......@@ -136,15 +136,6 @@ struct TIntermNodePair
};
//
// This is just to help yacc.
//
struct TIntermFunctionCallOrMethod
{
TIntermAggregate *argumentsNode;
TIntermNode *thisNode;
};
//
// Intermediate class for nodes that have a type.
//
class TIntermTyped : public TIntermNode
......@@ -569,6 +560,15 @@ class TFunctionSymbolInfo
typedef TVector<TIntermNode *> TIntermSequence;
typedef TVector<int> TQualifierList;
//
// This is just to help yacc.
//
struct TIntermFunctionCallOrMethod
{
TIntermSequence *arguments;
TIntermNode *thisNode;
};
// Interface for node classes that have an arbitrarily sized set of children.
class TIntermAggregateBase
{
......@@ -593,19 +593,12 @@ class TIntermAggregateBase
class TIntermAggregate : public TIntermOperator, public TIntermAggregateBase
{
public:
TIntermAggregate(TOperator op)
: TIntermOperator(op),
mUseEmulatedFunction(false),
mGotPrecisionFromChildren(false)
{
}
TIntermAggregate(const TType &type, TOperator op, TIntermSequence *arguments);
~TIntermAggregate() {}
// Note: only supported for nodes that can be a part of an expression.
TIntermTyped *deepCopy() const override { return new TIntermAggregate(*this); }
void setOp(TOperator op) { mOp = op; }
TIntermAggregate *getAsAggregate() override { return this; }
void traverse(TIntermTraverser *it) override;
bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
......@@ -614,29 +607,24 @@ class TIntermAggregate : public TIntermOperator, public TIntermAggregateBase
bool hasSideEffects() const override { return true; }
TIntermTyped *fold(TDiagnostics *diagnostics);
TIntermSequence *getSequence() override { return &mSequence; }
const TIntermSequence *getSequence() const override { return &mSequence; }
TIntermSequence *getSequence() override { return &mArguments; }
const TIntermSequence *getSequence() const override { return &mArguments; }
void setUseEmulatedFunction() { mUseEmulatedFunction = true; }
bool getUseEmulatedFunction() { return mUseEmulatedFunction; }
bool areChildrenConstQualified();
void setPrecisionForBuiltInOp();
void setPrecisionFromChildren();
// Used for built-in functions under EOpCallBuiltInFunction.
void setBuiltInFunctionPrecision();
// Returns true if changing parameter precision may affect the return value.
bool gotPrecisionFromChildren() const { return mGotPrecisionFromChildren; }
TFunctionSymbolInfo *getFunctionSymbolInfo() { return &mFunctionInfo; }
const TFunctionSymbolInfo *getFunctionSymbolInfo() const { return &mFunctionInfo; }
// Used for built-in functions under EOpCallBuiltInFunction. The function name in the symbol
// info needs to be set before calling this.
void setBuiltInFunctionPrecision();
protected:
TIntermSequence mSequence;
TIntermSequence mArguments;
// If set to true, replace the built-in function call with an emulated one
// to work around driver bugs. Only for calls mapped to ops other than EOpCall*.
......@@ -649,6 +637,14 @@ class TIntermAggregate : public TIntermOperator, public TIntermAggregateBase
private:
TIntermAggregate(const TIntermAggregate &node); // note: not deleted, just private!
void setTypePrecisionAndQualifier(const TType &type);
bool areChildrenConstQualified();
void setPrecisionFromChildren();
void setPrecisionForBuiltInOp();
// Returns true if precision was set according to special rules for this built-in.
bool setPrecisionForSpecialBuiltInOp();
};
......
......@@ -552,7 +552,7 @@ bool TParseContext::checkIsNotReserved(const TSourceLoc &line, const TString &id
// something of the type of the constructor. Also returns the type of
// the constructor.
bool TParseContext::checkConstructorArguments(const TSourceLoc &line,
const TIntermAggregate *argumentsNode,
const TIntermSequence *arguments,
TOperator op,
const TType &type)
{
......@@ -585,7 +585,7 @@ bool TParseContext::checkConstructorArguments(const TSourceLoc &line,
bool overFull = false;
bool matrixInMatrix = false;
bool arrayArg = false;
for (TIntermNode *arg : *argumentsNode->getSequence())
for (TIntermNode *arg : *arguments)
{
const TIntermTyped *argTyped = arg->getAsTyped();
size += argTyped->getType().getObjectSize();
......@@ -604,7 +604,7 @@ bool TParseContext::checkConstructorArguments(const TSourceLoc &line,
{
// The size of an unsized constructor should already have been determined.
ASSERT(!type.isUnsizedArray());
if (static_cast<size_t>(type.getArraySize()) != argumentsNode->getSequence()->size())
if (static_cast<size_t>(type.getArraySize()) != arguments->size())
{
error(line, "array constructor needs one argument per array element", "constructor");
return false;
......@@ -619,7 +619,7 @@ bool TParseContext::checkConstructorArguments(const TSourceLoc &line,
if (matrixInMatrix && !type.isArray())
{
if (argumentsNode->getSequence()->size() != 1)
if (arguments->size() != 1)
{
error(line, "constructing matrix from matrix can only take one argument",
"constructor");
......@@ -634,7 +634,7 @@ bool TParseContext::checkConstructorArguments(const TSourceLoc &line,
}
if (op == EOpConstructStruct && !type.isArray() &&
type.getStruct()->fields().size() != argumentsNode->getSequence()->size())
type.getStruct()->fields().size() != arguments->size())
{
error(line,
"Number of constructor parameters does not match the number of structure fields",
......@@ -652,13 +652,13 @@ bool TParseContext::checkConstructorArguments(const TSourceLoc &line,
}
}
if (argumentsNode->getSequence()->empty())
if (arguments->empty())
{
error(line, "constructor does not have any arguments", "constructor");
return false;
}
for (TIntermNode *const &argNode : *argumentsNode->getSequence())
for (TIntermNode *const &argNode : *arguments)
{
TIntermTyped *argTyped = argNode->getAsTyped();
ASSERT(argTyped != nullptr);
......@@ -683,7 +683,7 @@ bool TParseContext::checkConstructorArguments(const TSourceLoc &line,
{
// GLSL ES 3.00 section 5.4.4: Each argument must be the same type as the element type of
// the array.
for (TIntermNode *const &argNode : *argumentsNode->getSequence())
for (TIntermNode *const &argNode : *arguments)
{
const TType &argType = argNode->getAsTyped()->getType();
// It has already been checked that the argument is not an array.
......@@ -698,11 +698,11 @@ bool TParseContext::checkConstructorArguments(const TSourceLoc &line,
else if (op == EOpConstructStruct)
{
const TFieldList &fields = type.getStruct()->fields();
const TIntermSequence *args = argumentsNode->getSequence();
for (size_t i = 0; i < fields.size(); i++)
{
if (i >= args->size() || (*args)[i]->getAsTyped()->getType() != *fields[i]->type())
if (i >= arguments->size() ||
(*arguments)[i]->getAsTyped()->getType() != *fields[i]->type())
{
error(line, "Structure constructor arguments do not match structure fields",
"constructor");
......@@ -1528,40 +1528,6 @@ TIntermTyped *TParseContext::parseVariableIdentifier(const TSourceLoc &location,
}
//
// Look up a function name in the symbol table, and make sure it is a function.
//
// Return the function symbol if found, otherwise 0.
//
const TFunction *TParseContext::findFunction(const TSourceLoc &line,
TFunction *call,
int inputShaderVersion,
bool *builtIn)
{
// First find by unmangled name to check whether the function name has been
// hidden by a variable name or struct typename.
// If a function is found, check for one with a matching argument list.
const TSymbol *symbol = symbolTable.find(call->getName(), inputShaderVersion, builtIn);
if (symbol == 0 || symbol->isFunction())
{
symbol = symbolTable.find(call->getMangledName(), inputShaderVersion, builtIn);
}
if (symbol == 0)
{
error(line, "no matching overloaded function found", call->getName().c_str());
return 0;
}
if (!symbol->isFunction())
{
error(line, "function name expected", call->getName().c_str());
return 0;
}
return static_cast<const TFunction *>(symbol);
}
//
// Initializers show up in several places in the grammar. Have one set of
// code to handle them here.
//
......@@ -2690,61 +2656,39 @@ TFunction *TParseContext::addConstructorFunc(const TPublicType &publicTypeIn)
//
// Returns a node to add to the tree regardless of if an error was generated or not.
//
TIntermTyped *TParseContext::addConstructor(TIntermAggregate *arguments,
TIntermTyped *TParseContext::addConstructor(TIntermSequence *arguments,
TOperator op,
TType type,
const TSourceLoc &line)
{
if (type.isUnsizedArray())
{
if (arguments->getSequence()->empty())
if (arguments->empty())
{
error(line, "implicitly sized array constructor must have at least one argument", "[]");
type.setArraySize(1u);
return TIntermTyped::CreateZero(type);
}
type.setArraySize(static_cast<unsigned int>(arguments->getSequence()->size()));
type.setArraySize(static_cast<unsigned int>(arguments->size()));
}
bool constType = true;
for (TIntermNode *arg : *arguments->getSequence())
{
TIntermTyped *argTyped = arg->getAsTyped();
ASSERT(argTyped);
if (argTyped->getQualifier() != EvqConst)
constType = false;
}
if (constType)
type.setQualifier(EvqConst);
if (!checkConstructorArguments(line, arguments, op, type))
{
return TIntermTyped::CreateZero(type);
}
// Turn the argument list itself into a constructor
arguments->setOp(op);
arguments->setLine(line);
ASSERT(arguments->isConstructor());
// Need to set type before setPrecisionFromChildren() because bool doesn't have precision.
arguments->setType(type);
// Structs should not be precision qualified, the individual members may be.
// Built-in types on the other hand should be precision qualified.
if (op != EOpConstructStruct)
{
arguments->setPrecisionFromChildren();
type.setPrecision(arguments->getPrecision());
}
TIntermAggregate *constructorNode = new TIntermAggregate(type, op, arguments);
constructorNode->setLine(line);
ASSERT(constructorNode->isConstructor());
arguments->setType(type);
TIntermTyped *constConstructor = intermediate.foldAggregateBuiltIn(arguments, mDiagnostics);
TIntermTyped *constConstructor =
intermediate.foldAggregateBuiltIn(constructorNode, mDiagnostics);
if (constConstructor)
{
return constConstructor;
}
return arguments;
return constructorNode;
}
//
......@@ -4320,83 +4264,102 @@ void TParseContext::checkImageMemoryAccessForUserDefinedFunctions(
}
}
TIntermAggregate *TParseContext::createEmptyArgumentsNode(const TSourceLoc &loc)
TIntermSequence *TParseContext::createEmptyArgumentsList()
{
TIntermAggregate *argumentsNode = new TIntermAggregate(EOpNull);
argumentsNode->setLine(loc);
return argumentsNode;
return new TIntermSequence();
}
TIntermTyped *TParseContext::addFunctionCallOrMethod(TFunction *fnCall,
TIntermAggregate *argumentsNode,
TIntermSequence *arguments,
TIntermNode *thisNode,
const TSourceLoc &loc)
{
TOperator op = fnCall->getBuiltInOp();
TIntermTyped *callNode = nullptr;
if (thisNode != nullptr)
{
TConstantUnion *unionArray = new TConstantUnion[1];
int arraySize = 0;
TIntermTyped *typedThis = thisNode->getAsTyped();
// It's possible for the name pointer in the TFunction to be null in case it gets parsed as
// a constructor. But such a TFunction can't reach here, since the lexer goes into FIELDS
// mode after a dot, which makes type identifiers to be parsed as FIELD_SELECTION instead.
// So accessing fnCall->getName() below is safe.
if (fnCall->getName() != "length")
{
error(loc, "invalid method", fnCall->getName().c_str());
}
else if (!argumentsNode->getSequence()->empty())
{
error(loc, "method takes no parameters", "length");
}
else if (typedThis == nullptr || !typedThis->isArray())
{
error(loc, "length can only be called on arrays", "length");
}
else
return addMethod(fnCall, arguments, thisNode, loc);
}
TOperator op = fnCall->getBuiltInOp();
if (op != EOpNull)
{
return addConstructor(arguments, op, fnCall->getReturnType(), loc);
}
else
{
return addNonConstructorFunctionCall(fnCall, arguments, loc);
}
}
TIntermTyped *TParseContext::addMethod(TFunction *fnCall,
TIntermSequence *arguments,
TIntermNode *thisNode,
const TSourceLoc &loc)
{
TConstantUnion *unionArray = new TConstantUnion[1];
int arraySize = 0;
TIntermTyped *typedThis = thisNode->getAsTyped();
// It's possible for the name pointer in the TFunction to be null in case it gets parsed as
// a constructor. But such a TFunction can't reach here, since the lexer goes into FIELDS
// mode after a dot, which makes type identifiers to be parsed as FIELD_SELECTION instead.
// So accessing fnCall->getName() below is safe.
if (fnCall->getName() != "length")
{
error(loc, "invalid method", fnCall->getName().c_str());
}
else if (!arguments->empty())
{
error(loc, "method takes no parameters", "length");
}
else if (typedThis == nullptr || !typedThis->isArray())
{
error(loc, "length can only be called on arrays", "length");
}
else
{
arraySize = typedThis->getArraySize();
if (typedThis->getAsSymbolNode() == nullptr)
{
arraySize = typedThis->getArraySize();
if (typedThis->getAsSymbolNode() == nullptr)
{
// This code path can be hit with expressions like these:
// (a = b).length()
// (func()).length()
// (int[3](0, 1, 2)).length()
// ESSL 3.00 section 5.9 defines expressions so that this is not actually a valid
// expression.
// It allows "An array name with the length method applied" in contrast to GLSL 4.4
// spec section 5.9 which allows "An array, vector or matrix expression with the
// length method applied".
error(loc, "length can only be called on array names, not on array expressions",
"length");
}
// This code path can be hit with expressions like these:
// (a = b).length()
// (func()).length()
// (int[3](0, 1, 2)).length()
// ESSL 3.00 section 5.9 defines expressions so that this is not actually a valid
// expression.
// It allows "An array name with the length method applied" in contrast to GLSL 4.4
// spec section 5.9 which allows "An array, vector or matrix expression with the
// length method applied".
error(loc, "length can only be called on array names, not on array expressions",
"length");
}
unionArray->setIConst(arraySize);
callNode =
intermediate.addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), loc);
}
else if (op != EOpNull)
unionArray->setIConst(arraySize);
return intermediate.addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), loc);
}
TIntermTyped *TParseContext::addNonConstructorFunctionCall(TFunction *fnCall,
TIntermSequence *arguments,
const TSourceLoc &loc)
{
// First find by unmangled name to check whether the function name has been
// hidden by a variable name or struct typename.
// If a function is found, check for one with a matching argument list.
bool builtIn;
const TSymbol *symbol = symbolTable.find(fnCall->getName(), mShaderVersion, &builtIn);
if (symbol != nullptr && !symbol->isFunction())
{
// Then this should be a constructor.
callNode = addConstructor(argumentsNode, op, fnCall->getReturnType(), loc);
error(loc, "function name expected", fnCall->getName().c_str());
}
else
{
//
// Not a constructor. Find it in the symbol table.
//
const TFunction *fnCandidate;
bool builtIn;
for (TIntermNode *arg : *argumentsNode->getSequence())
symbol = symbolTable.find(TFunction::GetMangledNameFromCall(fnCall->getName(), *arguments),
mShaderVersion, &builtIn);
if (symbol == nullptr)
{
fnCall->addParameter(TConstParameter(&arg->getAsTyped()->getType()));
error(loc, "no matching overloaded function found", fnCall->getName().c_str());
}
fnCandidate = findFunction(loc, fnCall, mShaderVersion, &builtIn);
if (fnCandidate)
else
{
const TFunction *fnCandidate = static_cast<const TFunction *>(symbol);
//
// A declared function.
//
......@@ -4404,51 +4367,42 @@ TIntermTyped *TParseContext::addFunctionCallOrMethod(TFunction *fnCall,
{
checkCanUseExtension(loc, fnCandidate->getExtension());
}
op = fnCandidate->getBuiltInOp();
TOperator op = fnCandidate->getBuiltInOp();
if (builtIn && op != EOpNull)
{
// A function call mapped to a built-in operation.
if (fnCandidate->getParamCount() == 1)
{
// Treat it like a built-in unary operator.
TIntermNode *unaryParamNode = argumentsNode->getSequence()->front();
callNode = createUnaryMath(op, unaryParamNode->getAsTyped(), loc);
TIntermNode *unaryParamNode = arguments->front();
TIntermTyped *callNode = createUnaryMath(op, unaryParamNode->getAsTyped(), loc);
ASSERT(callNode != nullptr);
return callNode;
}
else
{
ASSERT(argumentsNode->getOp() == EOpNull);
argumentsNode->setOp(op);
argumentsNode->setType(fnCandidate->getReturnType());
argumentsNode->setPrecisionForBuiltInOp();
if (argumentsNode->areChildrenConstQualified())
{
argumentsNode->getTypePointer()->setQualifier(EvqConst);
}
TIntermAggregate *callNode =
new TIntermAggregate(fnCandidate->getReturnType(), op, arguments);
callNode->setLine(loc);
// Some built-in functions have out parameters too.
functionCallLValueErrorCheck(fnCandidate, argumentsNode);
functionCallLValueErrorCheck(fnCandidate, callNode);
// See if we can constant fold a built-in. Note that this may be possible even
// if it is not const-qualified.
TIntermTyped *foldedNode =
intermediate.foldAggregateBuiltIn(argumentsNode, mDiagnostics);
intermediate.foldAggregateBuiltIn(callNode, mDiagnostics);
if (foldedNode)
{
callNode = foldedNode;
}
else
{
callNode = argumentsNode;
return foldedNode;
}
return callNode;
}
}
else
{
// This is a real function call
ASSERT(argumentsNode->getOp() == EOpNull);
argumentsNode->setType(fnCandidate->getReturnType());
argumentsNode->getFunctionSymbolInfo()->setFromFunction(*fnCandidate);
TIntermAggregate *callNode = nullptr;
// If builtIn == false, the function is user defined - could be an overloaded
// built-in as well.
......@@ -4456,31 +4410,33 @@ TIntermTyped *TParseContext::addFunctionCallOrMethod(TFunction *fnCall,
// This needs to happen after the function info including name is set.
if (builtIn)
{
argumentsNode->setOp(EOpCallBuiltInFunction);
argumentsNode->setBuiltInFunctionPrecision();
checkTextureOffsetConst(argumentsNode);
checkImageMemoryAccessForBuiltinFunctions(argumentsNode);
callNode = new TIntermAggregate(fnCandidate->getReturnType(),
EOpCallBuiltInFunction, arguments);
// Note that name needs to be set before texture function type is determined.
callNode->getFunctionSymbolInfo()->setFromFunction(*fnCandidate);
callNode->setBuiltInFunctionPrecision();
checkTextureOffsetConst(callNode);
checkImageMemoryAccessForBuiltinFunctions(callNode);
}
else
{
argumentsNode->setOp(EOpCallFunctionInAST);
checkImageMemoryAccessForUserDefinedFunctions(fnCandidate, argumentsNode);
callNode = new TIntermAggregate(fnCandidate->getReturnType(),
EOpCallFunctionInAST, arguments);
callNode->getFunctionSymbolInfo()->setFromFunction(*fnCandidate);
checkImageMemoryAccessForUserDefinedFunctions(fnCandidate, callNode);
}
callNode = argumentsNode;
functionCallLValueErrorCheck(fnCandidate, callNode);
callNode->setLine(loc);
functionCallLValueErrorCheck(fnCandidate, argumentsNode);
return callNode;
}
}
else
{
// error message was put out by findFunction()
// Put on a dummy node for error recovery
callNode = TIntermTyped::CreateZero(TType(EbtFloat, EbpMedium, EvqConst));
}
}
return callNode;
// Error message was already written. Put on a dummy node for error recovery.
return TIntermTyped::CreateZero(TType(EbtFloat, EbpMedium, EvqConst));
}
TIntermTyped *TParseContext::addTernarySelection(TIntermTyped *cond,
......
......@@ -112,7 +112,7 @@ class TParseContext : angle::NonCopyable
void checkIsScalarInteger(TIntermTyped *node, const char *token);
bool checkIsAtGlobalLevel(const TSourceLoc &line, const char *token);
bool checkConstructorArguments(const TSourceLoc &line,
const TIntermAggregate *argumentsNode,
const TIntermSequence *arguments,
TOperator op,
const TType &type);
......@@ -167,10 +167,6 @@ class TParseContext : angle::NonCopyable
const char *value,
bool stdgl);
const TFunction *findFunction(const TSourceLoc &line,
TFunction *pfnCall,
int inputShaderVersion,
bool *builtIn = 0);
bool executeInitializer(const TSourceLoc &line,
const TString &identifier,
const TPublicType &pType,
......@@ -252,10 +248,6 @@ class TParseContext : angle::NonCopyable
const TString *name,
const TSourceLoc &location);
TFunction *addConstructorFunc(const TPublicType &publicType);
TIntermTyped *addConstructor(TIntermAggregate *arguments,
TOperator op,
TType type,
const TSourceLoc &line);
TIntermTyped *addIndexExpression(TIntermTyped *baseExpression,
const TSourceLoc &location,
......@@ -345,12 +337,12 @@ class TParseContext : angle::NonCopyable
void checkImageMemoryAccessForBuiltinFunctions(TIntermAggregate *functionCall);
void checkImageMemoryAccessForUserDefinedFunctions(const TFunction *functionDefinition,
const TIntermAggregate *functionCall);
TIntermAggregate *createEmptyArgumentsNode(const TSourceLoc &loc);
TIntermSequence *createEmptyArgumentsList();
// fnCall is only storing the built-in op, and function name or constructor type. argumentsNode
// fnCall is only storing the built-in op, and function name or constructor type. arguments
// has the arguments.
TIntermTyped *addFunctionCallOrMethod(TFunction *fnCall,
TIntermAggregate *argumentsNode,
TIntermSequence *arguments,
TIntermNode *thisNode,
const TSourceLoc &loc);
......@@ -406,9 +398,19 @@ class TParseContext : angle::NonCopyable
TIntermTyped *left,
TIntermTyped *right,
const TSourceLoc &loc);
TIntermTyped *createUnaryMath(TOperator op,
TIntermTyped *child,
const TSourceLoc &loc);
TIntermTyped *createUnaryMath(TOperator op, TIntermTyped *child, const TSourceLoc &loc);
TIntermTyped *addMethod(TFunction *fnCall,
TIntermSequence *arguments,
TIntermNode *thisNode,
const TSourceLoc &loc);
TIntermTyped *addConstructor(TIntermSequence *arguments,
TOperator op,
TType type,
const TSourceLoc &line);
TIntermTyped *addNonConstructorFunctionCall(TFunction *fnCall,
TIntermSequence *arguments,
const TSourceLoc &loc);
// Return true if the checks pass
bool binaryOpCommonCheck(TOperator op,
......
......@@ -113,11 +113,9 @@ TIntermTyped *EnsureSignedInt(TIntermTyped *node)
if (node->getBasicType() == EbtInt)
return node;
TIntermAggregate *convertedNode = new TIntermAggregate(EOpConstructInt);
convertedNode->setType(TType(EbtInt));
convertedNode->getSequence()->push_back(node);
convertedNode->setPrecisionFromChildren();
return convertedNode;
TIntermSequence *arguments = new TIntermSequence();
arguments->push_back(node);
return new TIntermAggregate(TType(EbtInt), EOpConstructInt, arguments);
}
TType GetFieldType(const TType &indexedType)
......@@ -351,15 +349,16 @@ TIntermAggregate *CreateIndexFunctionCall(TIntermBinary *node,
TIntermTyped *index)
{
ASSERT(node->getOp() == EOpIndexIndirect);
TIntermAggregate *indexingCall = new TIntermAggregate(EOpCallFunctionInAST);
TIntermSequence *arguments = new TIntermSequence();
arguments->push_back(indexedNode);
arguments->push_back(index);
TType fieldType = GetFieldType(indexedNode->getType());
TIntermAggregate *indexingCall =
new TIntermAggregate(fieldType, EOpCallFunctionInAST, arguments);
indexingCall->setLine(node->getLine());
indexingCall->getFunctionSymbolInfo()->setNameObj(
GetIndexFunctionName(indexedNode->getType(), false));
indexingCall->getSequence()->push_back(indexedNode);
indexingCall->getSequence()->push_back(index);
TType fieldType = GetFieldType(indexedNode->getType());
indexingCall->setType(fieldType);
return indexingCall;
}
......
......@@ -94,14 +94,11 @@ bool Traverser::visitAggregate(Visit visit, TIntermAggregate *node)
// Create new node that represents the call of function texelFetch.
// Its argument list will be: texelFetch(sampler, Position+offset, lod).
TIntermAggregate *texelFetchNode = new TIntermAggregate(EOpCallBuiltInFunction);
texelFetchNode->getFunctionSymbolInfo()->setName(newName);
texelFetchNode->getFunctionSymbolInfo()->setId(uniqueId);
texelFetchNode->setType(node->getType());
texelFetchNode->setLine(node->getLine());
TIntermSequence *texelFetchArguments = new TIntermSequence();
// sampler
texelFetchNode->getSequence()->push_back(sequence->at(0));
texelFetchArguments->push_back(sequence->at(0));
// Position
TIntermTyped *texCoordNode = sequence->at(1)->getAsTyped();
......@@ -114,20 +111,15 @@ bool Traverser::visitAggregate(Visit visit, TIntermAggregate *node)
{
// For 2DArray samplers, Position is ivec3 and offset is ivec2;
// So offset must be converted into an ivec3 before being added to Position.
TIntermAggregate *constructIVec3Node = new TIntermAggregate(EOpConstructIVec3);
constructIVec3Node->setLine(texCoordNode->getLine());
constructIVec3Node->setType(texCoordNode->getType());
constructIVec3Node->getSequence()->push_back(sequence->at(3)->getAsTyped());
TIntermSequence *constructOffsetIvecArguments = new TIntermSequence();
constructOffsetIvecArguments->push_back(sequence->at(3)->getAsTyped());
TConstantUnion *zero = new TConstantUnion();
zero->setIConst(0);
TType *intType = new TType(EbtInt);
TIntermTyped *zeroNode = TIntermTyped::CreateZero(TType(EbtInt));
constructOffsetIvecArguments->push_back(zeroNode);
TIntermConstantUnion *zeroNode = new TIntermConstantUnion(zero, *intType);
constructIVec3Node->getSequence()->push_back(zeroNode);
offsetNode = constructIVec3Node;
offsetNode = new TIntermAggregate(texCoordNode->getType(), EOpConstructIVec3,
constructOffsetIvecArguments);
offsetNode->setLine(texCoordNode->getLine());
}
else
{
......@@ -137,12 +129,18 @@ bool Traverser::visitAggregate(Visit visit, TIntermAggregate *node)
// Position+offset
TIntermBinary *add = new TIntermBinary(EOpAdd, texCoordNode, offsetNode);
add->setLine(texCoordNode->getLine());
texelFetchNode->getSequence()->push_back(add);
texelFetchArguments->push_back(add);
// lod
texelFetchNode->getSequence()->push_back(sequence->at(2));
texelFetchArguments->push_back(sequence->at(2));
ASSERT(texelFetchArguments->size() == 3u);
ASSERT(texelFetchNode->getSequence()->size() == 3u);
TIntermAggregate *texelFetchNode =
new TIntermAggregate(node->getType(), EOpCallBuiltInFunction, texelFetchArguments);
texelFetchNode->getFunctionSymbolInfo()->setName(newName);
texelFetchNode->getFunctionSymbolInfo()->setId(uniqueId);
texelFetchNode->setLine(node->getLine());
// Replace the old node by this new node.
queueReplacement(node, texelFetchNode, OriginalNode::IS_DROPPED);
......
......@@ -58,10 +58,9 @@ TIntermBinary *CopyAssignmentNode(TIntermBinary *node)
// Performs a shallow copy of a constructor/function call node.
TIntermAggregate *CopyAggregateNode(TIntermAggregate *node)
{
TIntermAggregate *copyNode = new TIntermAggregate(node->getOp());
TIntermSequence *copySeq = copyNode->getSequence();
TIntermSequence *copySeq = new TIntermSequence();
copySeq->insert(copySeq->begin(), node->getSequence()->begin(), node->getSequence()->end());
copyNode->setType(node->getType());
TIntermAggregate *copyNode = new TIntermAggregate(node->getType(), node->getOp(), copySeq);
*copyNode->getFunctionSymbolInfo() = *node->getFunctionSymbolInfo();
return copyNode;
}
......
......@@ -67,6 +67,17 @@ const TString *TFunction::buildMangledName() const
return NewPoolTString(newName.c_str());
}
const TString &TFunction::GetMangledNameFromCall(const TString &unmangledFunctionName,
TIntermSequence &arguments)
{
std::string newName = mangleName(unmangledFunctionName).c_str();
for (TIntermNode *argument : arguments)
{
newName += argument->getAsTyped()->getType().getMangledName().c_str();
}
return *NewPoolTString(newName.c_str());
}
//
// Symbol table levels are a map of pointers to symbols that have to be deleted.
//
......@@ -160,22 +171,12 @@ TFunction *TSymbolTable::findBuiltInOp(TIntermAggregate *callNode, int shaderVer
ASSERT(!callNode->isConstructor());
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;
TFunction call(&opString, &dummyReturnType, callNode->getOp());
TIntermSequence *sequence = callNode->getSequence();
for (auto *child : *sequence)
{
TType *paramType = child->getAsTyped()->getTypePointer();
TConstParameter p(paramType);
call.addParameter(p);
}
TSymbol *sym = findBuiltIn(call.getMangledName(), shaderVersion);
TSymbol *sym = findBuiltIn(
TFunction::GetMangledNameFromCall(opString, *callNode->getSequence()), shaderVersion);
ASSERT(sym != nullptr && sym->isFunction());
TFunction *builtInFunc = static_cast<TFunction *>(sym);
ASSERT(builtInFunc->getParamCount() == sequence->size());
ASSERT(builtInFunc->getParamCount() == callNode->getSequence()->size());
return builtInFunc;
}
......
......@@ -41,8 +41,6 @@
namespace sh
{
class TIntermAggregate;
// Symbol base class. (Can build functions or variables out of these...)
class TSymbol : angle::NonCopyable
{
......@@ -182,6 +180,10 @@ class TFunction : public TSymbol
}
return *mangledName;
}
static const TString &GetMangledNameFromCall(const TString &unmangledFunctionName,
TIntermSequence &arguments);
const TType &getReturnType() const { return *returnType; }
TOperator getBuiltInOp() const { return op; }
......
......@@ -315,7 +315,7 @@ integer_expression
function_call
: function_call_or_method {
$$ = context->addFunctionCallOrMethod($1.function, $1.callOrMethodPair.argumentsNode, $1.callOrMethodPair.thisNode, @1);
$$ = context->addFunctionCallOrMethod($1.function, $1.callOrMethodPair.arguments, $1.callOrMethodPair.thisNode, @1);
}
;
......@@ -343,23 +343,23 @@ function_call_generic
function_call_header_no_parameters
: function_call_header VOID_TYPE {
$$.function = $1;
$$.callOrMethodPair.argumentsNode = context->createEmptyArgumentsNode(@1);
$$.callOrMethodPair.arguments = context->createEmptyArgumentsList();
}
| function_call_header {
$$.function = $1;
$$.callOrMethodPair.argumentsNode = context->createEmptyArgumentsNode(@1);
$$.callOrMethodPair.arguments = context->createEmptyArgumentsList();
}
;
function_call_header_with_parameters
: function_call_header assignment_expression {
$$.callOrMethodPair.argumentsNode = context->createEmptyArgumentsNode(@1);
$$.callOrMethodPair.arguments = context->createEmptyArgumentsList();
$$.function = $1;
$$.callOrMethodPair.argumentsNode->getSequence()->push_back($2);
$$.callOrMethodPair.arguments->push_back($2);
}
| function_call_header_with_parameters COMMA assignment_expression {
$$.function = $1.function;
$$.callOrMethodPair.argumentsNode->getSequence()->push_back($3);
$$.callOrMethodPair.arguments->push_back($3);
}
;
......
......@@ -2619,7 +2619,7 @@ yyreduce:
case 18:
{
(yyval.interm.intermTypedNode) = context->addFunctionCallOrMethod((yyvsp[0].interm).function, (yyvsp[0].interm).callOrMethodPair.argumentsNode, (yyvsp[0].interm).callOrMethodPair.thisNode, (yylsp[0]));
(yyval.interm.intermTypedNode) = context->addFunctionCallOrMethod((yyvsp[0].interm).function, (yyvsp[0].interm).callOrMethodPair.arguments, (yyvsp[0].interm).callOrMethodPair.thisNode, (yylsp[0]));
}
break;
......@@ -2663,7 +2663,7 @@ yyreduce:
{
(yyval.interm).function = (yyvsp[-1].interm.function);
(yyval.interm).callOrMethodPair.argumentsNode = context->createEmptyArgumentsNode((yylsp[-1]));
(yyval.interm).callOrMethodPair.arguments = context->createEmptyArgumentsList();
}
break;
......@@ -2672,7 +2672,7 @@ yyreduce:
{
(yyval.interm).function = (yyvsp[0].interm.function);
(yyval.interm).callOrMethodPair.argumentsNode = context->createEmptyArgumentsNode((yylsp[0]));
(yyval.interm).callOrMethodPair.arguments = context->createEmptyArgumentsList();
}
break;
......@@ -2680,9 +2680,9 @@ yyreduce:
case 25:
{
(yyval.interm).callOrMethodPair.argumentsNode = context->createEmptyArgumentsNode((yylsp[-1]));
(yyval.interm).callOrMethodPair.arguments = context->createEmptyArgumentsList();
(yyval.interm).function = (yyvsp[-1].interm.function);
(yyval.interm).callOrMethodPair.argumentsNode->getSequence()->push_back((yyvsp[0].interm.intermTypedNode));
(yyval.interm).callOrMethodPair.arguments->push_back((yyvsp[0].interm.intermTypedNode));
}
break;
......@@ -2691,7 +2691,7 @@ yyreduce:
{
(yyval.interm).function = (yyvsp[-2].interm).function;
(yyval.interm).callOrMethodPair.argumentsNode->getSequence()->push_back((yyvsp[0].interm.intermTypedNode));
(yyval.interm).callOrMethodPair.arguments->push_back((yyvsp[0].interm.intermTypedNode));
}
break;
......
......@@ -184,14 +184,14 @@ TEST_F(IntermNodeTest, DeepCopyUnaryNode)
// original. Child nodes also need to be copies with the same attributes as the original children.
TEST_F(IntermNodeTest, DeepCopyAggregateNode)
{
TType type(EbtFloat, EbpHigh);
TIntermAggregate *original = new TIntermAggregate(EOpMix);
original->setLine(getTestSourceLoc());
TIntermSequence *originalSeq = original->getSequence();
TIntermSequence *originalSeq = new TIntermSequence();
originalSeq->push_back(createTestSymbol());
originalSeq->push_back(createTestSymbol());
originalSeq->push_back(createTestSymbol());
TIntermAggregate *original =
new TIntermAggregate(originalSeq->at(0)->getAsTyped()->getType(), EOpMix, originalSeq);
original->setLine(getTestSourceLoc());
TIntermTyped *copyTyped = original->deepCopy();
TIntermAggregate *copy = copyTyped->getAsAggregate();
ASSERT_NE(nullptr, copy);
......@@ -203,7 +203,7 @@ TEST_F(IntermNodeTest, DeepCopyAggregateNode)
TIntermSequence::size_type i = 0;
for (auto *copyChild : *copy->getSequence())
{
TIntermNode *originalChild = originalSeq->at(i);
TIntermNode *originalChild = original->getSequence()->at(i);
checkSymbolCopy(originalChild, copyChild);
++i;
}
......
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