tor-browser

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

DeferGlobalInitializers.cpp (7607B)


      1 //
      2 // Copyright 2016 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 // DeferGlobalInitializers is an AST traverser that moves global initializers into a separate
      7 // function that is called in the beginning of main(). This enables initialization of globals with
      8 // uniforms or non-constant globals, as allowed by the WebGL spec. Some initializers referencing
      9 // non-constants may need to be unfolded into if statements in HLSL - this kind of steps should be
     10 // done after DeferGlobalInitializers is run. Note that it's important that the function definition
     11 // is at the end of the shader, as some globals may be declared after main().
     12 //
     13 // It can also initialize all uninitialized globals.
     14 //
     15 
     16 #include "compiler/translator/tree_ops/DeferGlobalInitializers.h"
     17 
     18 #include <vector>
     19 
     20 #include "compiler/translator/Compiler.h"
     21 #include "compiler/translator/IntermNode.h"
     22 #include "compiler/translator/StaticType.h"
     23 #include "compiler/translator/SymbolTable.h"
     24 #include "compiler/translator/tree_ops/InitializeVariables.h"
     25 #include "compiler/translator/tree_util/FindMain.h"
     26 #include "compiler/translator/tree_util/IntermNode_util.h"
     27 #include "compiler/translator/tree_util/ReplaceVariable.h"
     28 
     29 namespace sh
     30 {
     31 
     32 namespace
     33 {
     34 
     35 constexpr const ImmutableString kInitGlobalsString("initGlobals");
     36 
     37 void GetDeferredInitializers(TIntermDeclaration *declaration,
     38                             bool initializeUninitializedGlobals,
     39                             bool canUseLoopsToInitialize,
     40                             bool highPrecisionSupported,
     41                             bool forceDeferGlobalInitializers,
     42                             TIntermSequence *deferredInitializersOut,
     43                             std::vector<const TVariable *> *variablesToReplaceOut,
     44                             TSymbolTable *symbolTable)
     45 {
     46    // SeparateDeclarations should have already been run.
     47    ASSERT(declaration->getSequence()->size() == 1);
     48 
     49    TIntermNode *declarator = declaration->getSequence()->back();
     50    TIntermBinary *init     = declarator->getAsBinaryNode();
     51    if (init)
     52    {
     53        TIntermSymbol *symbolNode = init->getLeft()->getAsSymbolNode();
     54        ASSERT(symbolNode);
     55        TIntermTyped *expression = init->getRight();
     56 
     57        if (expression->getQualifier() != EvqConst || !expression->hasConstantValue() ||
     58            forceDeferGlobalInitializers)
     59        {
     60            // For variables which are not constant, defer their real initialization until
     61            // after we initialize uniforms.
     62            // Deferral is done also in any cases where the variable can not be converted to a
     63            // constant union, since otherwise there's a chance that HLSL output will generate extra
     64            // statements from the initializer expression.
     65 
     66            // Change const global to a regular global if its initialization is deferred.
     67            // This can happen if ANGLE has not been able to fold the constant expression used
     68            // as an initializer.
     69            ASSERT(symbolNode->getQualifier() == EvqConst ||
     70                   symbolNode->getQualifier() == EvqGlobal);
     71            if (symbolNode->getQualifier() == EvqConst)
     72            {
     73                variablesToReplaceOut->push_back(&symbolNode->variable());
     74            }
     75 
     76            TIntermBinary *deferredInit =
     77                new TIntermBinary(EOpAssign, symbolNode->deepCopy(), init->getRight());
     78            deferredInitializersOut->push_back(deferredInit);
     79 
     80            // Remove the initializer from the global scope and just declare the global instead.
     81            declaration->replaceChildNode(init, symbolNode);
     82        }
     83    }
     84    else if (initializeUninitializedGlobals)
     85    {
     86        TIntermSymbol *symbolNode = declarator->getAsSymbolNode();
     87        ASSERT(symbolNode);
     88 
     89        // Ignore ANGLE internal variables and nameless declarations.
     90        if (symbolNode->variable().symbolType() == SymbolType::AngleInternal ||
     91            symbolNode->variable().symbolType() == SymbolType::Empty)
     92            return;
     93 
     94        if (symbolNode->getQualifier() == EvqGlobal)
     95        {
     96            TIntermSequence initCode;
     97            CreateInitCode(symbolNode, canUseLoopsToInitialize, highPrecisionSupported, &initCode,
     98                           symbolTable);
     99            deferredInitializersOut->insert(deferredInitializersOut->end(), initCode.begin(),
    100                                            initCode.end());
    101        }
    102    }
    103 }
    104 
    105 void InsertInitCallToMain(TIntermBlock *root,
    106                          TIntermSequence *deferredInitializers,
    107                          TSymbolTable *symbolTable)
    108 {
    109    TIntermBlock *initGlobalsBlock = new TIntermBlock();
    110    initGlobalsBlock->getSequence()->swap(*deferredInitializers);
    111 
    112    TFunction *initGlobalsFunction =
    113        new TFunction(symbolTable, kInitGlobalsString, SymbolType::AngleInternal,
    114                      StaticType::GetBasic<EbtVoid, EbpUndefined>(), false);
    115 
    116    TIntermFunctionPrototype *initGlobalsFunctionPrototype =
    117        CreateInternalFunctionPrototypeNode(*initGlobalsFunction);
    118    root->getSequence()->insert(root->getSequence()->begin(), initGlobalsFunctionPrototype);
    119    TIntermFunctionDefinition *initGlobalsFunctionDefinition =
    120        CreateInternalFunctionDefinitionNode(*initGlobalsFunction, initGlobalsBlock);
    121    root->appendStatement(initGlobalsFunctionDefinition);
    122 
    123    TIntermSequence emptySequence;
    124    TIntermAggregate *initGlobalsCall =
    125        TIntermAggregate::CreateFunctionCall(*initGlobalsFunction, &emptySequence);
    126 
    127    TIntermBlock *mainBody = FindMainBody(root);
    128    mainBody->getSequence()->insert(mainBody->getSequence()->begin(), initGlobalsCall);
    129 }
    130 
    131 }  // namespace
    132 
    133 bool DeferGlobalInitializers(TCompiler *compiler,
    134                             TIntermBlock *root,
    135                             bool initializeUninitializedGlobals,
    136                             bool canUseLoopsToInitialize,
    137                             bool highPrecisionSupported,
    138                             bool forceDeferGlobalInitializers,
    139                             TSymbolTable *symbolTable)
    140 {
    141    TIntermSequence deferredInitializers;
    142    std::vector<const TVariable *> variablesToReplace;
    143 
    144    // Loop over all global statements and process the declarations. This is simpler than using a
    145    // traverser.
    146    for (TIntermNode *statement : *root->getSequence())
    147    {
    148        TIntermDeclaration *declaration = statement->getAsDeclarationNode();
    149        if (declaration)
    150        {
    151            GetDeferredInitializers(declaration, initializeUninitializedGlobals,
    152                                    canUseLoopsToInitialize, highPrecisionSupported,
    153                                    forceDeferGlobalInitializers, &deferredInitializers,
    154                                    &variablesToReplace, symbolTable);
    155        }
    156    }
    157 
    158    // Add the function with initialization and the call to that.
    159    if (!deferredInitializers.empty())
    160    {
    161        InsertInitCallToMain(root, &deferredInitializers, symbolTable);
    162    }
    163 
    164    // Replace constant variables with non-constant global variables.
    165    for (const TVariable *var : variablesToReplace)
    166    {
    167        TType *replacementType = new TType(var->getType());
    168        replacementType->setQualifier(EvqGlobal);
    169        TVariable *replacement =
    170            new TVariable(symbolTable, var->name(), replacementType, var->symbolType());
    171        if (!ReplaceVariable(compiler, root, var, replacement))
    172        {
    173            return false;
    174        }
    175    }
    176 
    177    return true;
    178 }
    179 
    180 }  // namespace sh