// // 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.h: High-level utilities for creating AST nodes and node hierarchies. Mostly meant // to be used in AST transforms. #ifndef COMPILER_TRANSLATOR_INTERMNODEUTIL_H_ #define COMPILER_TRANSLATOR_INTERMNODEUTIL_H_ #include #include "compiler/translator/IntermNode.h" #include "compiler/translator/Name.h" #include "compiler/translator/tree_util/FindFunction.h" namespace sh { class TSymbolTable; class TVariable; TIntermFunctionPrototype *CreateInternalFunctionPrototypeNode(const TFunction &func); TIntermFunctionDefinition *CreateInternalFunctionDefinitionNode(const TFunction &func, TIntermBlock *functionBody); TIntermTyped *CreateZeroNode(const TType &type); TIntermConstantUnion *CreateFloatNode(float value, TPrecision precision); TIntermConstantUnion *CreateVecNode(const float values[], unsigned int vecSize, TPrecision precision); TIntermConstantUnion *CreateUVecNode(const unsigned int values[], unsigned int vecSize, TPrecision precision); TIntermConstantUnion *CreateIndexNode(int index); TIntermConstantUnion *CreateUIntNode(unsigned int value); TIntermConstantUnion *CreateBoolNode(bool value); TIntermConstantUnion *CreateYuvCscNode(TYuvCscStandardEXT value); // Create temporary variable of known type |type|. TVariable *CreateTempVariable(TSymbolTable *symbolTable, const TType *type); // Create temporary variable compatible with user-provide type |type|. // Possibly creates a new type. The qualifer of the new type of the new variable is |qualifier|. TVariable *CreateTempVariable(TSymbolTable *symbolTable, const TType *type, TQualifier qualifier); TIntermSymbol *CreateTempSymbolNode(const TVariable *tempVariable); TIntermDeclaration *CreateTempDeclarationNode(const TVariable *tempVariable); TIntermDeclaration *CreateTempInitDeclarationNode(const TVariable *tempVariable, TIntermTyped *initializer); TIntermBinary *CreateTempAssignmentNode(const TVariable *tempVariable, TIntermTyped *rightNode); TVariable *DeclareTempVariable(TSymbolTable *symbolTable, const TType *type, TQualifier qualifier, TIntermDeclaration **declarationOut); TVariable *DeclareTempVariable(TSymbolTable *symbolTable, TIntermTyped *initializer, TQualifier qualifier, TIntermDeclaration **declarationOut); std::pair DeclareStructure( TIntermBlock *root, TSymbolTable *symbolTable, TFieldList *fieldList, TQualifier qualifier, const TMemoryQualifier &memoryQualifier, uint32_t arraySize, const ImmutableString &structTypeName, const ImmutableString *structInstanceName); TInterfaceBlock *DeclareInterfaceBlock(TSymbolTable *symbolTable, TFieldList *fieldList, const TLayoutQualifier &layoutQualifier, const ImmutableString &blockTypeName); const TVariable *DeclareInterfaceBlockVariable(TIntermBlock *root, TSymbolTable *symbolTable, TQualifier qualifier, const TInterfaceBlock *interfaceBlock, const TLayoutQualifier &layoutQualifier, const TMemoryQualifier &memoryQualifier, uint32_t arraySize, const ImmutableString &blockVariableName); // `expr` must be an lvalue. This will return the root variable, e.g. the root variable of // `a[0].b[0].xy` is `a`, const TVariable *FindRootVariable(TIntermNode *expr); // Creates a variable for a struct type. const TVariable &CreateStructTypeVariable(TSymbolTable &symbolTable, const TStructure &structure); // Creates a variable for a struct instance. const TVariable &CreateInstanceVariable( TSymbolTable &symbolTable, const TStructure &structure, const Name &name, TQualifier qualifier = TQualifier::EvqTemporary, const angle::Span *arraySizes = nullptr); // Accesses a field for the given node with the given field name. // The node must be a struct instance. TIntermBinary &AccessField(const TVariable &structInstanceVar, const Name &field); // Accesses a field for the given node with the given field name. // The node must be a struct instance. TIntermBinary &AccessField(TIntermTyped &object, const Name &field); // Accesses a field for the given node by its field index. // The node must be a struct instance. TIntermBinary &AccessFieldByIndex(TIntermTyped &object, int index); // Accesses `object` by index, returning a binary referencing the field of the named interface // block. // Note: nameless interface blocks' fields are represented by individual TVariables, and so this // helper cannot generate an access to them. TIntermBinary *AccessFieldOfNamedInterfaceBlock(const TVariable *object, int index); // If the input node is nullptr, return nullptr. // If the input node is a block node, return it. // If the input node is not a block node, put it inside a block node and return that. TIntermBlock *EnsureBlock(TIntermNode *node); // If the input node is nullptr, return a new block. // If the input node is a block node, return it. // If the input node is not a block node, put it inside a block node and return that. TIntermBlock *EnsureLoopBodyBlock(TIntermNode *node); // Should be called from inside Compiler::compileTreeImpl() where the global level is in scope. TIntermSymbol *ReferenceGlobalVariable(const ImmutableString &name, const TSymbolTable &symbolTable); TIntermSymbol *ReferenceBuiltInVariable(const ImmutableString &name, const TSymbolTable &symbolTable, int shaderVersion); TIntermTyped *CreateBuiltInFunctionCallNode(const char *name, TIntermSequence *arguments, const TSymbolTable &symbolTable, int shaderVersion); TIntermTyped *CreateBuiltInFunctionCallNode(const char *name, const std::initializer_list &arguments, const TSymbolTable &symbolTable, int shaderVersion); TIntermTyped *CreateBuiltInUnaryFunctionCallNode(const char *name, TIntermTyped *argument, const TSymbolTable &symbolTable, int shaderVersion); inline void GetSwizzleIndex(TVector *indexOut) {} template void GetSwizzleIndex(TVector *indexOut, T arg, ArgsT... args) { indexOut->push_back(arg); GetSwizzleIndex(indexOut, args...); } template TIntermSwizzle *CreateSwizzle(TIntermTyped *reference, ArgsT... args) { TVector swizzleIndex; GetSwizzleIndex(&swizzleIndex, args...); return new TIntermSwizzle(reference, swizzleIndex); } // 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); // Cast a scalar to the basic type of type. No-ops if scalar is already the right type. TIntermNode *CastScalar(const TType &type, TIntermTyped *scalar); } // namespace sh #endif // COMPILER_TRANSLATOR_INTERMNODEUTIL_H_