diff options
Diffstat (limited to '')
-rw-r--r-- | gfx/angle/checkout/src/compiler/translator/tree_util/IntermNode_util.cpp | 436 |
1 files changed, 436 insertions, 0 deletions
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_util/IntermNode_util.cpp b/gfx/angle/checkout/src/compiler/translator/tree_util/IntermNode_util.cpp new file mode 100644 index 0000000000..a7bb211425 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_util/IntermNode_util.cpp @@ -0,0 +1,436 @@ +// +// Copyright 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// IntermNode_util.cpp: High-level utilities for creating AST nodes and node hierarchies. Mostly +// meant to be used in AST transforms. + +#include "compiler/translator/tree_util/IntermNode_util.h" + +#include "compiler/translator/FunctionLookup.h" +#include "compiler/translator/SymbolTable.h" + +namespace sh +{ + +namespace +{ + +const TFunction *LookUpBuiltInFunction(const char *name, + const TIntermSequence *arguments, + const TSymbolTable &symbolTable, + int shaderVersion) +{ + const ImmutableString &mangledName = TFunctionLookup::GetMangledName(name, *arguments); + const TSymbol *symbol = symbolTable.findBuiltIn(mangledName, shaderVersion); + if (symbol) + { + ASSERT(symbol->isFunction()); + return static_cast<const TFunction *>(symbol); + } + return nullptr; +} + +} // anonymous namespace + +TIntermFunctionPrototype *CreateInternalFunctionPrototypeNode(const TFunction &func) +{ + return new TIntermFunctionPrototype(&func); +} + +TIntermFunctionDefinition *CreateInternalFunctionDefinitionNode(const TFunction &func, + TIntermBlock *functionBody) +{ + return new TIntermFunctionDefinition(new TIntermFunctionPrototype(&func), functionBody); +} + +TIntermTyped *CreateZeroNode(const TType &type) +{ + TType constType(type); + constType.setQualifier(EvqConst); + + if (!type.isArray() && type.getBasicType() != EbtStruct) + { + size_t size = constType.getObjectSize(); + TConstantUnion *u = new TConstantUnion[size]; + for (size_t i = 0; i < size; ++i) + { + switch (type.getBasicType()) + { + case EbtFloat: + u[i].setFConst(0.0f); + break; + case EbtInt: + u[i].setIConst(0); + break; + case EbtUInt: + u[i].setUConst(0u); + break; + case EbtBool: + u[i].setBConst(false); + break; + default: + // CreateZeroNode is called by ParseContext that keeps parsing even when an + // error occurs, so it is possible for CreateZeroNode to be called with + // non-basic types. This happens only on error condition but CreateZeroNode + // needs to return a value with the correct type to continue the type check. + // That's why we handle non-basic type by setting whatever value, we just need + // the type to be right. + u[i].setIConst(42); + break; + } + } + + TIntermConstantUnion *node = new TIntermConstantUnion(u, constType); + return node; + } + + TIntermSequence arguments; + + if (type.isArray()) + { + TType elementType(type); + elementType.toArrayElementType(); + + size_t arraySize = type.getOutermostArraySize(); + for (size_t i = 0; i < arraySize; ++i) + { + arguments.push_back(CreateZeroNode(elementType)); + } + } + else + { + ASSERT(type.getBasicType() == EbtStruct); + + const TStructure *structure = type.getStruct(); + for (const auto &field : structure->fields()) + { + arguments.push_back(CreateZeroNode(*field->type())); + } + } + + return TIntermAggregate::CreateConstructor(constType, &arguments); +} + +TIntermConstantUnion *CreateFloatNode(float value, TPrecision precision) +{ + TConstantUnion *u = new TConstantUnion[1]; + u[0].setFConst(value); + + TType type(EbtFloat, precision, EvqConst, 1); + return new TIntermConstantUnion(u, type); +} + +TIntermConstantUnion *CreateVecNode(const float values[], + unsigned int vecSize, + TPrecision precision) +{ + TConstantUnion *u = new TConstantUnion[vecSize]; + for (unsigned int channel = 0; channel < vecSize; ++channel) + { + u[channel].setFConst(values[channel]); + } + + TType type(EbtFloat, precision, EvqConst, static_cast<uint8_t>(vecSize)); + return new TIntermConstantUnion(u, type); +} + +TIntermConstantUnion *CreateUVecNode(const unsigned int values[], + unsigned int vecSize, + TPrecision precision) +{ + TConstantUnion *u = new TConstantUnion[vecSize]; + for (unsigned int channel = 0; channel < vecSize; ++channel) + { + u[channel].setUConst(values[channel]); + } + + TType type(EbtUInt, precision, EvqConst, static_cast<uint8_t>(vecSize)); + return new TIntermConstantUnion(u, type); +} + +TIntermConstantUnion *CreateIndexNode(int index) +{ + TConstantUnion *u = new TConstantUnion[1]; + u[0].setIConst(index); + + TType type(EbtInt, EbpHigh, EvqConst, 1); + return new TIntermConstantUnion(u, type); +} + +TIntermConstantUnion *CreateUIntNode(unsigned int value) +{ + TConstantUnion *u = new TConstantUnion[1]; + u[0].setUConst(value); + + TType type(EbtUInt, EbpHigh, EvqConst, 1); + return new TIntermConstantUnion(u, type); +} + +TIntermConstantUnion *CreateBoolNode(bool value) +{ + TConstantUnion *u = new TConstantUnion[1]; + u[0].setBConst(value); + + TType type(EbtBool, EbpUndefined, EvqConst, 1); + return new TIntermConstantUnion(u, type); +} + +TVariable *CreateTempVariable(TSymbolTable *symbolTable, const TType *type) +{ + ASSERT(symbolTable != nullptr); + // TODO(oetuaho): Might be useful to sanitize layout qualifier etc. on the type of the created + // variable. This might need to be done in other places as well. + return new TVariable(symbolTable, kEmptyImmutableString, type, SymbolType::AngleInternal); +} + +TVariable *CreateTempVariable(TSymbolTable *symbolTable, const TType *type, TQualifier qualifier) +{ + ASSERT(symbolTable != nullptr); + if (type->getQualifier() == qualifier) + { + return CreateTempVariable(symbolTable, type); + } + TType *typeWithQualifier = new TType(*type); + typeWithQualifier->setQualifier(qualifier); + return CreateTempVariable(symbolTable, typeWithQualifier); +} + +TIntermSymbol *CreateTempSymbolNode(const TVariable *tempVariable) +{ + ASSERT(tempVariable->symbolType() == SymbolType::AngleInternal); + ASSERT(tempVariable->getType().getQualifier() == EvqTemporary || + tempVariable->getType().getQualifier() == EvqConst || + tempVariable->getType().getQualifier() == EvqGlobal); + return new TIntermSymbol(tempVariable); +} + +TIntermDeclaration *CreateTempDeclarationNode(const TVariable *tempVariable) +{ + TIntermDeclaration *tempDeclaration = new TIntermDeclaration(); + tempDeclaration->appendDeclarator(CreateTempSymbolNode(tempVariable)); + return tempDeclaration; +} + +TIntermDeclaration *CreateTempInitDeclarationNode(const TVariable *tempVariable, + TIntermTyped *initializer) +{ + ASSERT(initializer != nullptr); + TIntermSymbol *tempSymbol = CreateTempSymbolNode(tempVariable); + TIntermDeclaration *tempDeclaration = new TIntermDeclaration(); + TIntermBinary *tempInit = new TIntermBinary(EOpInitialize, tempSymbol, initializer); + tempDeclaration->appendDeclarator(tempInit); + return tempDeclaration; +} + +TIntermBinary *CreateTempAssignmentNode(const TVariable *tempVariable, TIntermTyped *rightNode) +{ + ASSERT(rightNode != nullptr); + TIntermSymbol *tempSymbol = CreateTempSymbolNode(tempVariable); + return new TIntermBinary(EOpAssign, tempSymbol, rightNode); +} + +TVariable *DeclareTempVariable(TSymbolTable *symbolTable, + const TType *type, + TQualifier qualifier, + TIntermDeclaration **declarationOut) +{ + TVariable *variable = CreateTempVariable(symbolTable, type, qualifier); + *declarationOut = CreateTempDeclarationNode(variable); + return variable; +} + +TVariable *DeclareTempVariable(TSymbolTable *symbolTable, + TIntermTyped *initializer, + TQualifier qualifier, + TIntermDeclaration **declarationOut) +{ + TVariable *variable = + CreateTempVariable(symbolTable, new TType(initializer->getType()), qualifier); + *declarationOut = CreateTempInitDeclarationNode(variable, initializer); + return variable; +} + +std::pair<const TVariable *, const TVariable *> DeclareStructure( + TIntermBlock *root, + TSymbolTable *symbolTable, + TFieldList *fieldList, + TQualifier qualifier, + const TMemoryQualifier &memoryQualifier, + uint32_t arraySize, + const ImmutableString &structTypeName, + const ImmutableString *structInstanceName) +{ + TStructure *structure = + new TStructure(symbolTable, structTypeName, fieldList, SymbolType::AngleInternal); + + auto makeStructureType = [&](bool isStructSpecifier) { + TType *structureType = new TType(structure, isStructSpecifier); + structureType->setQualifier(qualifier); + structureType->setMemoryQualifier(memoryQualifier); + if (arraySize > 0) + { + structureType->makeArray(arraySize); + } + return structureType; + }; + + TIntermSequence insertSequence; + + TVariable *typeVar = new TVariable(symbolTable, kEmptyImmutableString, makeStructureType(true), + SymbolType::Empty); + insertSequence.push_back(new TIntermDeclaration{typeVar}); + + TVariable *instanceVar = nullptr; + if (structInstanceName) + { + instanceVar = new TVariable(symbolTable, *structInstanceName, makeStructureType(false), + SymbolType::AngleInternal); + insertSequence.push_back(new TIntermDeclaration{instanceVar}); + } + + size_t firstFunctionIndex = FindFirstFunctionDefinitionIndex(root); + root->insertChildNodes(firstFunctionIndex, insertSequence); + + return {typeVar, instanceVar}; +} + +const TVariable *DeclareInterfaceBlock(TIntermBlock *root, + TSymbolTable *symbolTable, + TFieldList *fieldList, + TQualifier qualifier, + const TLayoutQualifier &layoutQualifier, + const TMemoryQualifier &memoryQualifier, + uint32_t arraySize, + const ImmutableString &blockTypeName, + const ImmutableString &blockVariableName) +{ + // Define an interface block. + TInterfaceBlock *interfaceBlock = new TInterfaceBlock( + symbolTable, blockTypeName, fieldList, layoutQualifier, SymbolType::AngleInternal); + + // Turn the inteface block into a declaration. + TType *interfaceBlockType = new TType(interfaceBlock, qualifier, layoutQualifier); + interfaceBlockType->setMemoryQualifier(memoryQualifier); + if (arraySize > 0) + { + interfaceBlockType->makeArray(arraySize); + } + + TIntermDeclaration *interfaceBlockDecl = new TIntermDeclaration; + TVariable *interfaceBlockVar = + new TVariable(symbolTable, blockVariableName, interfaceBlockType, + blockVariableName.empty() ? SymbolType::Empty : SymbolType::AngleInternal); + TIntermSymbol *interfaceBlockDeclarator = new TIntermSymbol(interfaceBlockVar); + interfaceBlockDecl->appendDeclarator(interfaceBlockDeclarator); + + // Insert the declarations before the first function. + TIntermSequence insertSequence; + insertSequence.push_back(interfaceBlockDecl); + + size_t firstFunctionIndex = FindFirstFunctionDefinitionIndex(root); + root->insertChildNodes(firstFunctionIndex, insertSequence); + + return interfaceBlockVar; +} + +TIntermBlock *EnsureBlock(TIntermNode *node) +{ + if (node == nullptr) + return nullptr; + TIntermBlock *blockNode = node->getAsBlock(); + if (blockNode != nullptr) + return blockNode; + + blockNode = new TIntermBlock(); + blockNode->setLine(node->getLine()); + blockNode->appendStatement(node); + return blockNode; +} + +TIntermSymbol *ReferenceGlobalVariable(const ImmutableString &name, const TSymbolTable &symbolTable) +{ + const TSymbol *symbol = symbolTable.findGlobal(name); + ASSERT(symbol && symbol->isVariable()); + return new TIntermSymbol(static_cast<const TVariable *>(symbol)); +} + +TIntermSymbol *ReferenceBuiltInVariable(const ImmutableString &name, + const TSymbolTable &symbolTable, + int shaderVersion) +{ + const TVariable *var = + static_cast<const TVariable *>(symbolTable.findBuiltIn(name, shaderVersion)); + ASSERT(var); + return new TIntermSymbol(var); +} + +TIntermTyped *CreateBuiltInFunctionCallNode(const char *name, + TIntermSequence *arguments, + const TSymbolTable &symbolTable, + int shaderVersion) +{ + const TFunction *fn = LookUpBuiltInFunction(name, arguments, symbolTable, shaderVersion); + ASSERT(fn); + TOperator op = fn->getBuiltInOp(); + if (BuiltInGroup::IsMath(op) && arguments->size() == 1) + { + return new TIntermUnary(op, arguments->at(0)->getAsTyped(), fn); + } + return TIntermAggregate::CreateBuiltInFunctionCall(*fn, arguments); +} + +TIntermTyped *CreateBuiltInFunctionCallNode(const char *name, + const std::initializer_list<TIntermNode *> &arguments, + const TSymbolTable &symbolTable, + int shaderVersion) +{ + TIntermSequence argSequence(arguments); + return CreateBuiltInFunctionCallNode(name, &argSequence, symbolTable, shaderVersion); +} + +TIntermTyped *CreateBuiltInUnaryFunctionCallNode(const char *name, + TIntermTyped *argument, + const TSymbolTable &symbolTable, + int shaderVersion) +{ + return CreateBuiltInFunctionCallNode(name, {argument}, symbolTable, shaderVersion); +} + +int GetESSLOrGLSLVersion(ShShaderSpec spec, int esslVersion, int glslVersion) +{ + return IsDesktopGLSpec(spec) ? glslVersion : esslVersion; +} + +// Returns true if a block ends in a branch (break, continue, return, etc). This is only correct +// after PruneNoOps, because it expects empty blocks after a branch to have been already pruned, +// i.e. a block can only end in a branch if its last statement is a branch or is a block ending in +// branch. +bool EndsInBranch(TIntermBlock *block) +{ + while (block != nullptr) + { + // Get the last statement of the block. + TIntermSequence &statements = *block->getSequence(); + if (statements.empty()) + { + return false; + } + + TIntermNode *lastStatement = statements.back(); + + // If it's a branch itself, we have the answer. + if (lastStatement->getAsBranchNode()) + { + return true; + } + + // Otherwise, see if it's a block that ends in a branch + block = lastStatement->getAsBlock(); + } + + return false; +} + +} // namespace sh |