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)
......
......@@ -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();
};
......
......@@ -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