Edit

kc3-lang/angle/src/compiler/translator/tree_util/IntermNode_util.cpp

Branch :

  • Show log

    Commit

  • Author : Jamie Madill
    Date : 2021-08-26 13:11:29
    Hash : a29b07d8
    Message : InitializeVariables: Init shader IO block outputs. These variables were not handled in the pass because we had no prior test coverage of them. Some frame capture testing uncovered this gap. The variables must be initialized field-by-field, since there seems to be no defined way to initialize an entire block at once. Bug: angleproject:6326 Change-Id: Ib7aecfb76b97b4236d786b44b3dfb706c573e221 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3123228 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: Tim Van Patten <timvp@google.com> Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>

  • src/compiler/translator/tree_util/IntermNode_util.cpp
  • //
    // 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 *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 *CreateBuiltInUnaryFunctionCallNode(const char *name,
                                                     TIntermTyped *argument,
                                                     const TSymbolTable &symbolTable,
                                                     int shaderVersion)
    {
        TIntermSequence seq = {argument};
        return CreateBuiltInFunctionCallNode(name, &seq, symbolTable, shaderVersion);
    }
    
    }  // namespace sh