tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

IntermNode_util.cpp (15649B)


      1 //
      2 // Copyright 2017 The ANGLE Project Authors. All rights reserved.
      3 // Use of this source code is governed by a BSD-style license that can be
      4 // found in the LICENSE file.
      5 //
      6 // IntermNode_util.cpp: High-level utilities for creating AST nodes and node hierarchies. Mostly
      7 // meant to be used in AST transforms.
      8 
      9 #include "compiler/translator/tree_util/IntermNode_util.h"
     10 
     11 #include "compiler/translator/FunctionLookup.h"
     12 #include "compiler/translator/SymbolTable.h"
     13 
     14 namespace sh
     15 {
     16 
     17 namespace
     18 {
     19 
     20 const TFunction *LookUpBuiltInFunction(const char *name,
     21                                       const TIntermSequence *arguments,
     22                                       const TSymbolTable &symbolTable,
     23                                       int shaderVersion)
     24 {
     25    const ImmutableString &mangledName = TFunctionLookup::GetMangledName(name, *arguments);
     26    const TSymbol *symbol              = symbolTable.findBuiltIn(mangledName, shaderVersion);
     27    if (symbol)
     28    {
     29        ASSERT(symbol->isFunction());
     30        return static_cast<const TFunction *>(symbol);
     31    }
     32    return nullptr;
     33 }
     34 
     35 }  // anonymous namespace
     36 
     37 TIntermFunctionPrototype *CreateInternalFunctionPrototypeNode(const TFunction &func)
     38 {
     39    return new TIntermFunctionPrototype(&func);
     40 }
     41 
     42 TIntermFunctionDefinition *CreateInternalFunctionDefinitionNode(const TFunction &func,
     43                                                                TIntermBlock *functionBody)
     44 {
     45    return new TIntermFunctionDefinition(new TIntermFunctionPrototype(&func), functionBody);
     46 }
     47 
     48 TIntermTyped *CreateZeroNode(const TType &type)
     49 {
     50    TType constType(type);
     51    constType.setQualifier(EvqConst);
     52 
     53    if (!type.isArray() && type.getBasicType() != EbtStruct)
     54    {
     55        size_t size       = constType.getObjectSize();
     56        TConstantUnion *u = new TConstantUnion[size];
     57        for (size_t i = 0; i < size; ++i)
     58        {
     59            switch (type.getBasicType())
     60            {
     61                case EbtFloat:
     62                    u[i].setFConst(0.0f);
     63                    break;
     64                case EbtInt:
     65                    u[i].setIConst(0);
     66                    break;
     67                case EbtUInt:
     68                    u[i].setUConst(0u);
     69                    break;
     70                case EbtBool:
     71                    u[i].setBConst(false);
     72                    break;
     73                default:
     74                    // CreateZeroNode is called by ParseContext that keeps parsing even when an
     75                    // error occurs, so it is possible for CreateZeroNode to be called with
     76                    // non-basic types. This happens only on error condition but CreateZeroNode
     77                    // needs to return a value with the correct type to continue the type check.
     78                    // That's why we handle non-basic type by setting whatever value, we just need
     79                    // the type to be right.
     80                    u[i].setIConst(42);
     81                    break;
     82            }
     83        }
     84 
     85        TIntermConstantUnion *node = new TIntermConstantUnion(u, constType);
     86        return node;
     87    }
     88 
     89    TIntermSequence arguments;
     90 
     91    if (type.isArray())
     92    {
     93        TType elementType(type);
     94        elementType.toArrayElementType();
     95 
     96        size_t arraySize = type.getOutermostArraySize();
     97        for (size_t i = 0; i < arraySize; ++i)
     98        {
     99            arguments.push_back(CreateZeroNode(elementType));
    100        }
    101    }
    102    else
    103    {
    104        ASSERT(type.getBasicType() == EbtStruct);
    105 
    106        const TStructure *structure = type.getStruct();
    107        for (const auto &field : structure->fields())
    108        {
    109            arguments.push_back(CreateZeroNode(*field->type()));
    110        }
    111    }
    112 
    113    return TIntermAggregate::CreateConstructor(constType, &arguments);
    114 }
    115 
    116 TIntermConstantUnion *CreateFloatNode(float value, TPrecision precision)
    117 {
    118    TConstantUnion *u = new TConstantUnion[1];
    119    u[0].setFConst(value);
    120 
    121    TType type(EbtFloat, precision, EvqConst, 1);
    122    return new TIntermConstantUnion(u, type);
    123 }
    124 
    125 TIntermConstantUnion *CreateVecNode(const float values[],
    126                                    unsigned int vecSize,
    127                                    TPrecision precision)
    128 {
    129    TConstantUnion *u = new TConstantUnion[vecSize];
    130    for (unsigned int channel = 0; channel < vecSize; ++channel)
    131    {
    132        u[channel].setFConst(values[channel]);
    133    }
    134 
    135    TType type(EbtFloat, precision, EvqConst, static_cast<uint8_t>(vecSize));
    136    return new TIntermConstantUnion(u, type);
    137 }
    138 
    139 TIntermConstantUnion *CreateUVecNode(const unsigned int values[],
    140                                     unsigned int vecSize,
    141                                     TPrecision precision)
    142 {
    143    TConstantUnion *u = new TConstantUnion[vecSize];
    144    for (unsigned int channel = 0; channel < vecSize; ++channel)
    145    {
    146        u[channel].setUConst(values[channel]);
    147    }
    148 
    149    TType type(EbtUInt, precision, EvqConst, static_cast<uint8_t>(vecSize));
    150    return new TIntermConstantUnion(u, type);
    151 }
    152 
    153 TIntermConstantUnion *CreateIndexNode(int index)
    154 {
    155    TConstantUnion *u = new TConstantUnion[1];
    156    u[0].setIConst(index);
    157 
    158    TType type(EbtInt, EbpHigh, EvqConst, 1);
    159    return new TIntermConstantUnion(u, type);
    160 }
    161 
    162 TIntermConstantUnion *CreateUIntNode(unsigned int value)
    163 {
    164    TConstantUnion *u = new TConstantUnion[1];
    165    u[0].setUConst(value);
    166 
    167    TType type(EbtUInt, EbpHigh, EvqConst, 1);
    168    return new TIntermConstantUnion(u, type);
    169 }
    170 
    171 TIntermConstantUnion *CreateBoolNode(bool value)
    172 {
    173    TConstantUnion *u = new TConstantUnion[1];
    174    u[0].setBConst(value);
    175 
    176    TType type(EbtBool, EbpUndefined, EvqConst, 1);
    177    return new TIntermConstantUnion(u, type);
    178 }
    179 
    180 TVariable *CreateTempVariable(TSymbolTable *symbolTable, const TType *type)
    181 {
    182    ASSERT(symbolTable != nullptr);
    183    // TODO(oetuaho): Might be useful to sanitize layout qualifier etc. on the type of the created
    184    // variable. This might need to be done in other places as well.
    185    return new TVariable(symbolTable, kEmptyImmutableString, type, SymbolType::AngleInternal);
    186 }
    187 
    188 TVariable *CreateTempVariable(TSymbolTable *symbolTable, const TType *type, TQualifier qualifier)
    189 {
    190    ASSERT(symbolTable != nullptr);
    191    if (type->getQualifier() == qualifier)
    192    {
    193        return CreateTempVariable(symbolTable, type);
    194    }
    195    TType *typeWithQualifier = new TType(*type);
    196    typeWithQualifier->setQualifier(qualifier);
    197    return CreateTempVariable(symbolTable, typeWithQualifier);
    198 }
    199 
    200 TIntermSymbol *CreateTempSymbolNode(const TVariable *tempVariable)
    201 {
    202    ASSERT(tempVariable->symbolType() == SymbolType::AngleInternal);
    203    ASSERT(tempVariable->getType().getQualifier() == EvqTemporary ||
    204           tempVariable->getType().getQualifier() == EvqConst ||
    205           tempVariable->getType().getQualifier() == EvqGlobal);
    206    return new TIntermSymbol(tempVariable);
    207 }
    208 
    209 TIntermDeclaration *CreateTempDeclarationNode(const TVariable *tempVariable)
    210 {
    211    TIntermDeclaration *tempDeclaration = new TIntermDeclaration();
    212    tempDeclaration->appendDeclarator(CreateTempSymbolNode(tempVariable));
    213    return tempDeclaration;
    214 }
    215 
    216 TIntermDeclaration *CreateTempInitDeclarationNode(const TVariable *tempVariable,
    217                                                  TIntermTyped *initializer)
    218 {
    219    ASSERT(initializer != nullptr);
    220    TIntermSymbol *tempSymbol           = CreateTempSymbolNode(tempVariable);
    221    TIntermDeclaration *tempDeclaration = new TIntermDeclaration();
    222    TIntermBinary *tempInit             = new TIntermBinary(EOpInitialize, tempSymbol, initializer);
    223    tempDeclaration->appendDeclarator(tempInit);
    224    return tempDeclaration;
    225 }
    226 
    227 TIntermBinary *CreateTempAssignmentNode(const TVariable *tempVariable, TIntermTyped *rightNode)
    228 {
    229    ASSERT(rightNode != nullptr);
    230    TIntermSymbol *tempSymbol = CreateTempSymbolNode(tempVariable);
    231    return new TIntermBinary(EOpAssign, tempSymbol, rightNode);
    232 }
    233 
    234 TVariable *DeclareTempVariable(TSymbolTable *symbolTable,
    235                               const TType *type,
    236                               TQualifier qualifier,
    237                               TIntermDeclaration **declarationOut)
    238 {
    239    TVariable *variable = CreateTempVariable(symbolTable, type, qualifier);
    240    *declarationOut     = CreateTempDeclarationNode(variable);
    241    return variable;
    242 }
    243 
    244 TVariable *DeclareTempVariable(TSymbolTable *symbolTable,
    245                               TIntermTyped *initializer,
    246                               TQualifier qualifier,
    247                               TIntermDeclaration **declarationOut)
    248 {
    249    TVariable *variable =
    250        CreateTempVariable(symbolTable, new TType(initializer->getType()), qualifier);
    251    *declarationOut = CreateTempInitDeclarationNode(variable, initializer);
    252    return variable;
    253 }
    254 
    255 std::pair<const TVariable *, const TVariable *> DeclareStructure(
    256    TIntermBlock *root,
    257    TSymbolTable *symbolTable,
    258    TFieldList *fieldList,
    259    TQualifier qualifier,
    260    const TMemoryQualifier &memoryQualifier,
    261    uint32_t arraySize,
    262    const ImmutableString &structTypeName,
    263    const ImmutableString *structInstanceName)
    264 {
    265    TStructure *structure =
    266        new TStructure(symbolTable, structTypeName, fieldList, SymbolType::AngleInternal);
    267 
    268    auto makeStructureType = [&](bool isStructSpecifier) {
    269        TType *structureType = new TType(structure, isStructSpecifier);
    270        structureType->setQualifier(qualifier);
    271        structureType->setMemoryQualifier(memoryQualifier);
    272        if (arraySize > 0)
    273        {
    274            structureType->makeArray(arraySize);
    275        }
    276        return structureType;
    277    };
    278 
    279    TIntermSequence insertSequence;
    280 
    281    TVariable *typeVar = new TVariable(symbolTable, kEmptyImmutableString, makeStructureType(true),
    282                                       SymbolType::Empty);
    283    insertSequence.push_back(new TIntermDeclaration{typeVar});
    284 
    285    TVariable *instanceVar = nullptr;
    286    if (structInstanceName)
    287    {
    288        instanceVar = new TVariable(symbolTable, *structInstanceName, makeStructureType(false),
    289                                    SymbolType::AngleInternal);
    290        insertSequence.push_back(new TIntermDeclaration{instanceVar});
    291    }
    292 
    293    size_t firstFunctionIndex = FindFirstFunctionDefinitionIndex(root);
    294    root->insertChildNodes(firstFunctionIndex, insertSequence);
    295 
    296    return {typeVar, instanceVar};
    297 }
    298 
    299 const TVariable *DeclareInterfaceBlock(TIntermBlock *root,
    300                                       TSymbolTable *symbolTable,
    301                                       TFieldList *fieldList,
    302                                       TQualifier qualifier,
    303                                       const TLayoutQualifier &layoutQualifier,
    304                                       const TMemoryQualifier &memoryQualifier,
    305                                       uint32_t arraySize,
    306                                       const ImmutableString &blockTypeName,
    307                                       const ImmutableString &blockVariableName)
    308 {
    309    // Define an interface block.
    310    TInterfaceBlock *interfaceBlock = new TInterfaceBlock(
    311        symbolTable, blockTypeName, fieldList, layoutQualifier, SymbolType::AngleInternal);
    312 
    313    // Turn the inteface block into a declaration.
    314    TType *interfaceBlockType = new TType(interfaceBlock, qualifier, layoutQualifier);
    315    interfaceBlockType->setMemoryQualifier(memoryQualifier);
    316    if (arraySize > 0)
    317    {
    318        interfaceBlockType->makeArray(arraySize);
    319    }
    320 
    321    TIntermDeclaration *interfaceBlockDecl = new TIntermDeclaration;
    322    TVariable *interfaceBlockVar =
    323        new TVariable(symbolTable, blockVariableName, interfaceBlockType,
    324                      blockVariableName.empty() ? SymbolType::Empty : SymbolType::AngleInternal);
    325    TIntermSymbol *interfaceBlockDeclarator = new TIntermSymbol(interfaceBlockVar);
    326    interfaceBlockDecl->appendDeclarator(interfaceBlockDeclarator);
    327 
    328    // Insert the declarations before the first function.
    329    TIntermSequence insertSequence;
    330    insertSequence.push_back(interfaceBlockDecl);
    331 
    332    size_t firstFunctionIndex = FindFirstFunctionDefinitionIndex(root);
    333    root->insertChildNodes(firstFunctionIndex, insertSequence);
    334 
    335    return interfaceBlockVar;
    336 }
    337 
    338 TIntermBlock *EnsureBlock(TIntermNode *node)
    339 {
    340    if (node == nullptr)
    341        return nullptr;
    342    TIntermBlock *blockNode = node->getAsBlock();
    343    if (blockNode != nullptr)
    344        return blockNode;
    345 
    346    blockNode = new TIntermBlock();
    347    blockNode->setLine(node->getLine());
    348    blockNode->appendStatement(node);
    349    return blockNode;
    350 }
    351 
    352 TIntermSymbol *ReferenceGlobalVariable(const ImmutableString &name, const TSymbolTable &symbolTable)
    353 {
    354    const TSymbol *symbol = symbolTable.findGlobal(name);
    355    ASSERT(symbol && symbol->isVariable());
    356    return new TIntermSymbol(static_cast<const TVariable *>(symbol));
    357 }
    358 
    359 TIntermSymbol *ReferenceBuiltInVariable(const ImmutableString &name,
    360                                        const TSymbolTable &symbolTable,
    361                                        int shaderVersion)
    362 {
    363    const TVariable *var =
    364        static_cast<const TVariable *>(symbolTable.findBuiltIn(name, shaderVersion));
    365    ASSERT(var);
    366    return new TIntermSymbol(var);
    367 }
    368 
    369 TIntermTyped *CreateBuiltInFunctionCallNode(const char *name,
    370                                            TIntermSequence *arguments,
    371                                            const TSymbolTable &symbolTable,
    372                                            int shaderVersion)
    373 {
    374    const TFunction *fn = LookUpBuiltInFunction(name, arguments, symbolTable, shaderVersion);
    375    ASSERT(fn);
    376    TOperator op = fn->getBuiltInOp();
    377    if (BuiltInGroup::IsMath(op) && arguments->size() == 1)
    378    {
    379        return new TIntermUnary(op, arguments->at(0)->getAsTyped(), fn);
    380    }
    381    return TIntermAggregate::CreateBuiltInFunctionCall(*fn, arguments);
    382 }
    383 
    384 TIntermTyped *CreateBuiltInFunctionCallNode(const char *name,
    385                                            const std::initializer_list<TIntermNode *> &arguments,
    386                                            const TSymbolTable &symbolTable,
    387                                            int shaderVersion)
    388 {
    389    TIntermSequence argSequence(arguments);
    390    return CreateBuiltInFunctionCallNode(name, &argSequence, symbolTable, shaderVersion);
    391 }
    392 
    393 TIntermTyped *CreateBuiltInUnaryFunctionCallNode(const char *name,
    394                                                 TIntermTyped *argument,
    395                                                 const TSymbolTable &symbolTable,
    396                                                 int shaderVersion)
    397 {
    398    return CreateBuiltInFunctionCallNode(name, {argument}, symbolTable, shaderVersion);
    399 }
    400 
    401 int GetESSLOrGLSLVersion(ShShaderSpec spec, int esslVersion, int glslVersion)
    402 {
    403    return IsDesktopGLSpec(spec) ? glslVersion : esslVersion;
    404 }
    405 
    406 // Returns true if a block ends in a branch (break, continue, return, etc).  This is only correct
    407 // after PruneNoOps, because it expects empty blocks after a branch to have been already pruned,
    408 // i.e. a block can only end in a branch if its last statement is a branch or is a block ending in
    409 // branch.
    410 bool EndsInBranch(TIntermBlock *block)
    411 {
    412    while (block != nullptr)
    413    {
    414        // Get the last statement of the block.
    415        TIntermSequence &statements = *block->getSequence();
    416        if (statements.empty())
    417        {
    418            return false;
    419        }
    420 
    421        TIntermNode *lastStatement = statements.back();
    422 
    423        // If it's a branch itself, we have the answer.
    424        if (lastStatement->getAsBranchNode())
    425        {
    426            return true;
    427        }
    428 
    429        // Otherwise, see if it's a block that ends in a branch
    430        block = lastStatement->getAsBlock();
    431    }
    432 
    433    return false;
    434 }
    435 
    436 }  // namespace sh