Commit a7ecec38 by Olli Etuaho Committed by Commit Bot

GLSL: Simplify constructor parsing

Constructor argument checking rules are reorganized to make them easier to understand and constructor node creation is made simpler. This removes usage of constructor op codes from ParseContext. This paves the way for getting rid of constructor op codes entirely, which will remove duplicate information from the AST and simplify lots of code. This refactoring will make adding arrays of arrays slightly easier. BUG=angleproject:1490 TEST=angle_unittests Change-Id: I4053afec55111b629353b4ff7cb0451c1ae3511c Reviewed-on: https://chromium-review.googlesource.com/498767 Commit-Queue: Olli Etuaho <oetuaho@nvidia.com> Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org>
parent 73fa4b83
...@@ -304,10 +304,10 @@ TIntermAggregate *TIntermAggregate::CreateBuiltInFunctionCall(const TFunction &f ...@@ -304,10 +304,10 @@ TIntermAggregate *TIntermAggregate::CreateBuiltInFunctionCall(const TFunction &f
} }
TIntermAggregate *TIntermAggregate::CreateConstructor(const TType &type, TIntermAggregate *TIntermAggregate::CreateConstructor(const TType &type,
TOperator op,
TIntermSequence *arguments) TIntermSequence *arguments)
{ {
TIntermAggregate *constructorNode = new TIntermAggregate(type, op, arguments); TIntermAggregate *constructorNode =
new TIntermAggregate(type, sh::TypeToConstructorOperator(type), arguments);
ASSERT(constructorNode->isConstructor()); ASSERT(constructorNode->isConstructor());
return constructorNode; return constructorNode;
} }
...@@ -630,8 +630,7 @@ TIntermTyped *TIntermTyped::CreateZero(const TType &type) ...@@ -630,8 +630,7 @@ TIntermTyped *TIntermTyped::CreateZero(const TType &type)
} }
} }
return TIntermAggregate::CreateConstructor(constType, sh::TypeToConstructorOperator(type), return TIntermAggregate::CreateConstructor(constType, arguments);
arguments);
} }
// static // static
...@@ -777,9 +776,7 @@ bool TIntermOperator::isMultiplication() const ...@@ -777,9 +776,7 @@ bool TIntermOperator::isMultiplication() const
} }
} }
// // Returns true if the operator is for one of the constructors.
// returns true if the operator is for one of the constructors
//
bool TIntermOperator::isConstructor() const bool TIntermOperator::isConstructor() const
{ {
switch (mOp) switch (mOp)
...@@ -812,6 +809,8 @@ bool TIntermOperator::isConstructor() const ...@@ -812,6 +809,8 @@ bool TIntermOperator::isConstructor() const
case EOpConstructStruct: case EOpConstructStruct:
return true; return true;
default: default:
// EOpConstruct is not supposed to be used in the AST.
ASSERT(mOp != EOpConstruct);
return false; return false;
} }
} }
......
...@@ -604,7 +604,6 @@ class TIntermAggregate : public TIntermOperator, public TIntermAggregateBase ...@@ -604,7 +604,6 @@ class TIntermAggregate : public TIntermOperator, public TIntermAggregateBase
static TIntermAggregate *CreateBuiltInFunctionCall(const TFunction &func, static TIntermAggregate *CreateBuiltInFunctionCall(const TFunction &func,
TIntermSequence *arguments); TIntermSequence *arguments);
static TIntermAggregate *CreateConstructor(const TType &type, static TIntermAggregate *CreateConstructor(const TType &type,
TOperator op,
TIntermSequence *arguments); TIntermSequence *arguments);
static TIntermAggregate *Create(const TType &type, TOperator op, TIntermSequence *arguments); static TIntermAggregate *Create(const TType &type, TOperator op, TIntermSequence *arguments);
~TIntermAggregate() {} ~TIntermAggregate() {}
......
...@@ -205,6 +205,10 @@ enum TOperator ...@@ -205,6 +205,10 @@ enum TOperator
// Constructors // Constructors
// //
// Used by ParseContext to denote any constructor.
EOpConstruct,
// In the AST, constructors are stored using the below more specific op codes.
EOpConstructInt, EOpConstructInt,
EOpConstructUInt, EOpConstructUInt,
EOpConstructBool, EOpConstructBool,
......
...@@ -546,121 +546,22 @@ bool TParseContext::checkIsNotReserved(const TSourceLoc &line, const TString &id ...@@ -546,121 +546,22 @@ bool TParseContext::checkIsNotReserved(const TSourceLoc &line, const TString &id
return true; return true;
} }
// Make sure there is enough data provided to the constructor to build // Make sure the argument types are correct for constructing a specific type.
// something of the type of the constructor. Also returns the type of
// the constructor.
bool TParseContext::checkConstructorArguments(const TSourceLoc &line, bool TParseContext::checkConstructorArguments(const TSourceLoc &line,
const TIntermSequence *arguments, const TIntermSequence *arguments,
TOperator op,
const TType &type) const TType &type)
{ {
bool constructingMatrix = false;
switch (op)
{
case EOpConstructMat2:
case EOpConstructMat2x3:
case EOpConstructMat2x4:
case EOpConstructMat3x2:
case EOpConstructMat3:
case EOpConstructMat3x4:
case EOpConstructMat4x2:
case EOpConstructMat4x3:
case EOpConstructMat4:
constructingMatrix = true;
break;
default:
break;
}
//
// Note: It's okay to have too many components available, but not okay to have unused
// arguments. 'full' will go to true when enough args have been seen. If we loop
// again, there is an extra argument, so 'overfull' will become true.
//
size_t size = 0;
bool full = false;
bool overFull = false;
bool matrixInMatrix = false;
bool arrayArg = false;
for (TIntermNode *arg : *arguments)
{
const TIntermTyped *argTyped = arg->getAsTyped();
size += argTyped->getType().getObjectSize();
if (constructingMatrix && argTyped->getType().isMatrix())
matrixInMatrix = true;
if (full)
overFull = true;
if (op != EOpConstructStruct && !type.isArray() && size >= type.getObjectSize())
full = true;
if (argTyped->getType().isArray())
arrayArg = true;
}
if (type.isArray())
{
// The size of an unsized constructor should already have been determined.
ASSERT(!type.isUnsizedArray());
if (static_cast<size_t>(type.getArraySize()) != arguments->size())
{
error(line, "array constructor needs one argument per array element", "constructor");
return false;
}
}
if (arrayArg && op != EOpConstructStruct)
{
error(line, "constructing from a non-dereferenced array", "constructor");
return false;
}
if (matrixInMatrix && !type.isArray())
{
if (arguments->size() != 1)
{
error(line, "constructing matrix from matrix can only take one argument",
"constructor");
return false;
}
}
if (overFull)
{
error(line, "too many arguments", "constructor");
return false;
}
if (op == EOpConstructStruct && !type.isArray() &&
type.getStruct()->fields().size() != arguments->size())
{
error(line,
"Number of constructor parameters does not match the number of structure fields",
"constructor");
return false;
}
if (!type.isMatrix() || !matrixInMatrix)
{
if ((op != EOpConstructStruct && size != 1 && size < type.getObjectSize()) ||
(op == EOpConstructStruct && size < type.getObjectSize()))
{
error(line, "not enough data provided for construction", "constructor");
return false;
}
}
if (arguments->empty()) if (arguments->empty())
{ {
error(line, "constructor does not have any arguments", "constructor"); error(line, "constructor does not have any arguments", "constructor");
return false; return false;
} }
for (TIntermNode *const &argNode : *arguments) for (TIntermNode *arg : *arguments)
{ {
TIntermTyped *argTyped = argNode->getAsTyped(); const TIntermTyped *argTyped = arg->getAsTyped();
ASSERT(argTyped != nullptr); ASSERT(argTyped != nullptr);
if (op != EOpConstructStruct && IsOpaqueType(argTyped->getBasicType())) if (type.getBasicType() != EbtStruct && IsOpaqueType(argTyped->getBasicType()))
{ {
std::string reason("cannot convert a variable with type "); std::string reason("cannot convert a variable with type ");
reason += getBasicString(argTyped->getBasicType()); reason += getBasicString(argTyped->getBasicType());
...@@ -676,15 +577,21 @@ bool TParseContext::checkConstructorArguments(const TSourceLoc &line, ...@@ -676,15 +577,21 @@ bool TParseContext::checkConstructorArguments(const TSourceLoc &line,
if (type.isArray()) if (type.isArray())
{ {
// The size of an unsized constructor should already have been determined.
ASSERT(!type.isUnsizedArray());
if (static_cast<size_t>(type.getArraySize()) != arguments->size())
{
error(line, "array constructor needs one argument per array element", "constructor");
return false;
}
// GLSL ES 3.00 section 5.4.4: Each argument must be the same type as the element type of // GLSL ES 3.00 section 5.4.4: Each argument must be the same type as the element type of
// the array. // the array.
for (TIntermNode *const &argNode : *arguments) for (TIntermNode *const &argNode : *arguments)
{ {
const TType &argType = argNode->getAsTyped()->getType(); const TType &argType = argNode->getAsTyped()->getType();
// It has already been checked that the argument is not an array, but we can arrive
// here due to prior error conditions.
if (argType.isArray()) if (argType.isArray())
{ {
error(line, "constructing from a non-dereferenced array", "constructor");
return false; return false;
} }
if (!argType.sameElementType(type)) if (!argType.sameElementType(type))
...@@ -694,9 +601,16 @@ bool TParseContext::checkConstructorArguments(const TSourceLoc &line, ...@@ -694,9 +601,16 @@ bool TParseContext::checkConstructorArguments(const TSourceLoc &line,
} }
} }
} }
else if (op == EOpConstructStruct) else if (type.getBasicType() == EbtStruct)
{ {
const TFieldList &fields = type.getStruct()->fields(); const TFieldList &fields = type.getStruct()->fields();
if (fields.size() != arguments->size())
{
error(line,
"Number of constructor parameters does not match the number of structure fields",
"constructor");
return false;
}
for (size_t i = 0; i < fields.size(); i++) for (size_t i = 0; i < fields.size(); i++)
{ {
...@@ -709,6 +623,67 @@ bool TParseContext::checkConstructorArguments(const TSourceLoc &line, ...@@ -709,6 +623,67 @@ bool TParseContext::checkConstructorArguments(const TSourceLoc &line,
} }
} }
} }
else
{
// We're constructing a scalar, vector, or matrix.
// Note: It's okay to have too many components available, but not okay to have unused
// arguments. 'full' will go to true when enough args have been seen. If we loop again,
// there is an extra argument, so 'overFull' will become true.
size_t size = 0;
bool full = false;
bool overFull = false;
bool matrixArg = false;
for (TIntermNode *arg : *arguments)
{
const TIntermTyped *argTyped = arg->getAsTyped();
ASSERT(argTyped != nullptr);
if (argTyped->getType().isArray())
{
error(line, "constructing from a non-dereferenced array", "constructor");
return false;
}
if (argTyped->getType().isMatrix())
{
matrixArg = true;
}
size += argTyped->getType().getObjectSize();
if (full)
{
overFull = true;
}
if (type.getBasicType() != EbtStruct && !type.isArray() && size >= type.getObjectSize())
{
full = true;
}
}
if (type.isMatrix() && matrixArg)
{
if (arguments->size() != 1)
{
error(line, "constructing matrix from matrix can only take one argument",
"constructor");
return false;
}
}
else
{
if (size != 1 && size < type.getObjectSize())
{
error(line, "not enough data provided for construction", "constructor");
return false;
}
if (overFull)
{
error(line, "too many arguments", "constructor");
return false;
}
}
}
return true; return true;
} }
...@@ -2698,34 +2673,23 @@ TFunction *TParseContext::parseFunctionHeader(const TPublicType &type, ...@@ -2698,34 +2673,23 @@ TFunction *TParseContext::parseFunctionHeader(const TPublicType &type,
return new TFunction(name, new TType(type)); return new TFunction(name, new TType(type));
} }
TFunction *TParseContext::addConstructorFunc(const TPublicType &publicTypeIn) TFunction *TParseContext::addConstructorFunc(const TPublicType &publicType)
{ {
TPublicType publicType = publicTypeIn;
if (publicType.isStructSpecifier()) if (publicType.isStructSpecifier())
{ {
error(publicType.getLine(), "constructor can't be a structure definition", error(publicType.getLine(), "constructor can't be a structure definition",
getBasicString(publicType.getBasicType())); getBasicString(publicType.getBasicType()));
} }
TOperator op = EOpNull; TType *type = new TType(publicType);
if (publicType.getUserDef()) if (!type->canBeConstructed())
{ {
op = EOpConstructStruct; error(publicType.getLine(), "cannot construct this type",
} getBasicString(publicType.getBasicType()));
else type->setBasicType(EbtFloat);
{
op = sh::TypeToConstructorOperator(TType(publicType));
if (op == EOpNull)
{
error(publicType.getLine(), "cannot construct this type",
getBasicString(publicType.getBasicType()));
publicType.setBasicType(EbtFloat);
op = EOpConstructFloat;
}
} }
const TType *type = new TType(publicType); return new TFunction(nullptr, type, EOpConstruct);
return new TFunction(nullptr, type, op);
} }
// This function is used to test for the correctness of the parameters passed to various constructor // This function is used to test for the correctness of the parameters passed to various constructor
...@@ -2734,7 +2698,6 @@ TFunction *TParseContext::addConstructorFunc(const TPublicType &publicTypeIn) ...@@ -2734,7 +2698,6 @@ TFunction *TParseContext::addConstructorFunc(const TPublicType &publicTypeIn)
// Returns a node to add to the tree regardless of if an error was generated or not. // Returns a node to add to the tree regardless of if an error was generated or not.
// //
TIntermTyped *TParseContext::addConstructor(TIntermSequence *arguments, TIntermTyped *TParseContext::addConstructor(TIntermSequence *arguments,
TOperator op,
TType type, TType type,
const TSourceLoc &line) const TSourceLoc &line)
{ {
...@@ -2749,12 +2712,12 @@ TIntermTyped *TParseContext::addConstructor(TIntermSequence *arguments, ...@@ -2749,12 +2712,12 @@ TIntermTyped *TParseContext::addConstructor(TIntermSequence *arguments,
type.setArraySize(static_cast<unsigned int>(arguments->size())); type.setArraySize(static_cast<unsigned int>(arguments->size()));
} }
if (!checkConstructorArguments(line, arguments, op, type)) if (!checkConstructorArguments(line, arguments, type))
{ {
return TIntermTyped::CreateZero(type); return TIntermTyped::CreateZero(type);
} }
TIntermAggregate *constructorNode = TIntermAggregate::CreateConstructor(type, op, arguments); TIntermAggregate *constructorNode = TIntermAggregate::CreateConstructor(type, arguments);
constructorNode->setLine(line); constructorNode->setLine(line);
TIntermTyped *constConstructor = TIntermTyped *constConstructor =
...@@ -4383,12 +4346,13 @@ TIntermTyped *TParseContext::addFunctionCallOrMethod(TFunction *fnCall, ...@@ -4383,12 +4346,13 @@ TIntermTyped *TParseContext::addFunctionCallOrMethod(TFunction *fnCall,
} }
TOperator op = fnCall->getBuiltInOp(); TOperator op = fnCall->getBuiltInOp();
if (op != EOpNull) if (op == EOpConstruct)
{ {
return addConstructor(arguments, op, fnCall->getReturnType(), loc); return addConstructor(arguments, fnCall->getReturnType(), loc);
} }
else else
{ {
ASSERT(op == EOpNull);
return addNonConstructorFunctionCall(fnCall, arguments, loc); return addNonConstructorFunctionCall(fnCall, arguments, loc);
} }
} }
......
...@@ -113,7 +113,6 @@ class TParseContext : angle::NonCopyable ...@@ -113,7 +113,6 @@ class TParseContext : angle::NonCopyable
bool checkIsAtGlobalLevel(const TSourceLoc &line, const char *token); bool checkIsAtGlobalLevel(const TSourceLoc &line, const char *token);
bool checkConstructorArguments(const TSourceLoc &line, bool checkConstructorArguments(const TSourceLoc &line,
const TIntermSequence *arguments, const TIntermSequence *arguments,
TOperator op,
const TType &type); const TType &type);
// Returns a sanitized array size to use (the size is at least 1). // Returns a sanitized array size to use (the size is at least 1).
...@@ -415,7 +414,6 @@ class TParseContext : angle::NonCopyable ...@@ -415,7 +414,6 @@ class TParseContext : angle::NonCopyable
TIntermNode *thisNode, TIntermNode *thisNode,
const TSourceLoc &loc); const TSourceLoc &loc);
TIntermTyped *addConstructor(TIntermSequence *arguments, TIntermTyped *addConstructor(TIntermSequence *arguments,
TOperator op,
TType type, TType type,
const TSourceLoc &line); const TSourceLoc &line);
TIntermTyped *addNonConstructorFunctionCall(TFunction *fnCall, TIntermTyped *addNonConstructorFunctionCall(TFunction *fnCall,
......
...@@ -110,7 +110,7 @@ TIntermTyped *EnsureSignedInt(TIntermTyped *node) ...@@ -110,7 +110,7 @@ TIntermTyped *EnsureSignedInt(TIntermTyped *node)
TIntermSequence *arguments = new TIntermSequence(); TIntermSequence *arguments = new TIntermSequence();
arguments->push_back(node); arguments->push_back(node);
return TIntermAggregate::CreateConstructor(TType(EbtInt), EOpConstructInt, arguments); return TIntermAggregate::CreateConstructor(TType(EbtInt), arguments);
} }
TType GetFieldType(const TType &indexedType) TType GetFieldType(const TType &indexedType)
......
...@@ -110,7 +110,7 @@ bool Traverser::visitAggregate(Visit visit, TIntermAggregate *node) ...@@ -110,7 +110,7 @@ bool Traverser::visitAggregate(Visit visit, TIntermAggregate *node)
TIntermTyped *zeroNode = TIntermTyped::CreateZero(TType(EbtInt)); TIntermTyped *zeroNode = TIntermTyped::CreateZero(TType(EbtInt));
constructOffsetIvecArguments->push_back(zeroNode); constructOffsetIvecArguments->push_back(zeroNode);
offsetNode = TIntermAggregate::CreateConstructor(texCoordNode->getType(), EOpConstructIVec3, offsetNode = TIntermAggregate::CreateConstructor(texCoordNode->getType(),
constructOffsetIvecArguments); constructOffsetIvecArguments);
offsetNode->setLine(texCoordNode->getLine()); offsetNode->setLine(texCoordNode->getLine());
} }
......
...@@ -125,6 +125,8 @@ TType::TType(const TPublicType &p) ...@@ -125,6 +125,8 @@ TType::TType(const TPublicType &p)
interfaceBlock(0), interfaceBlock(0),
structure(0) structure(0)
{ {
ASSERT(primarySize <= 4);
ASSERT(secondarySize <= 4);
if (p.getUserDef()) if (p.getUserDef())
structure = p.getUserDef()->getStruct(); structure = p.getUserDef()->getStruct();
} }
...@@ -134,6 +136,21 @@ bool TStructure::equals(const TStructure &other) const ...@@ -134,6 +136,21 @@ bool TStructure::equals(const TStructure &other) const
return (uniqueId() == other.uniqueId()); return (uniqueId() == other.uniqueId());
} }
bool TType::canBeConstructed() const
{
switch (type)
{
case EbtFloat:
case EbtInt:
case EbtUInt:
case EbtBool:
case EbtStruct:
return true;
default:
return false;
}
}
const char *TType::getBuiltInTypeNameString() const const char *TType::getBuiltInTypeNameString() const
{ {
if (isMatrix()) if (isMatrix())
......
...@@ -318,6 +318,7 @@ class TType ...@@ -318,6 +318,7 @@ class TType
{ {
if (primarySize != ps) if (primarySize != ps)
{ {
ASSERT(ps <= 4);
primarySize = ps; primarySize = ps;
invalidateMangledName(); invalidateMangledName();
} }
...@@ -326,6 +327,7 @@ class TType ...@@ -326,6 +327,7 @@ class TType
{ {
if (secondarySize != ss) if (secondarySize != ss)
{ {
ASSERT(ss <= 4);
secondarySize = ss; secondarySize = ss;
invalidateMangledName(); invalidateMangledName();
} }
...@@ -377,6 +379,8 @@ class TType ...@@ -377,6 +379,8 @@ class TType
bool isScalarFloat() const { return isScalar() && type == EbtFloat; } bool isScalarFloat() const { return isScalar() && type == EbtFloat; }
bool isScalarInt() const { return isScalar() && (type == EbtInt || type == EbtUInt); } bool isScalarInt() const { return isScalar() && (type == EbtInt || type == EbtUInt); }
bool canBeConstructed() const;
TStructure *getStruct() const { return structure; } TStructure *getStruct() const { return structure; }
void setStruct(TStructure *s) void setStruct(TStructure *s)
{ {
......
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