LCOV - code coverage report
Current view: top level - gfx/angle/src/compiler/translator - DeferGlobalInitializers.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 81 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 10 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //
       2             : // Copyright (c) 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 function, and
       7             : // adds a function call to that function in the beginning of main().
       8             : // This enables initialization of globals with uniforms or non-constant globals, as allowed by
       9             : // the WebGL spec. Some initializers referencing non-constants may need to be unfolded into if
      10             : // statements in HLSL - this kind of steps should be done after DeferGlobalInitializers is run.
      11             : //
      12             : 
      13             : #include "compiler/translator/DeferGlobalInitializers.h"
      14             : 
      15             : #include "compiler/translator/IntermNode.h"
      16             : #include "compiler/translator/SymbolTable.h"
      17             : 
      18             : namespace sh
      19             : {
      20             : 
      21             : namespace
      22             : {
      23             : 
      24           0 : void SetInternalFunctionName(TFunctionSymbolInfo *functionInfo, const char *name)
      25             : {
      26           0 :     TString nameStr(name);
      27           0 :     nameStr = TFunction::mangleName(nameStr);
      28           0 :     TName nameObj(nameStr);
      29           0 :     nameObj.setInternal(true);
      30           0 :     functionInfo->setNameObj(nameObj);
      31           0 : }
      32             : 
      33           0 : TIntermAggregate *CreateFunctionPrototypeNode(const char *name, const int functionId)
      34             : {
      35           0 :     TIntermAggregate *functionNode = new TIntermAggregate(EOpPrototype);
      36             : 
      37           0 :     SetInternalFunctionName(functionNode->getFunctionSymbolInfo(), name);
      38           0 :     TType returnType(EbtVoid);
      39           0 :     functionNode->setType(returnType);
      40           0 :     functionNode->getFunctionSymbolInfo()->setId(functionId);
      41           0 :     return functionNode;
      42             : }
      43             : 
      44           0 : TIntermFunctionDefinition *CreateFunctionDefinitionNode(const char *name,
      45             :                                                         TIntermBlock *functionBody,
      46             :                                                         const int functionId)
      47             : {
      48           0 :     TType returnType(EbtVoid);
      49           0 :     TIntermAggregate *paramsNode = new TIntermAggregate(EOpParameters);
      50             :     TIntermFunctionDefinition *functionNode =
      51           0 :         new TIntermFunctionDefinition(returnType, paramsNode, functionBody);
      52             : 
      53           0 :     SetInternalFunctionName(functionNode->getFunctionSymbolInfo(), name);
      54           0 :     functionNode->getFunctionSymbolInfo()->setId(functionId);
      55           0 :     return functionNode;
      56             : }
      57             : 
      58           0 : TIntermAggregate *CreateFunctionCallNode(const char *name, const int functionId)
      59             : {
      60           0 :     TIntermAggregate *functionNode = new TIntermAggregate(EOpFunctionCall);
      61             : 
      62           0 :     functionNode->setUserDefined();
      63           0 :     SetInternalFunctionName(functionNode->getFunctionSymbolInfo(), name);
      64           0 :     TType returnType(EbtVoid);
      65           0 :     functionNode->setType(returnType);
      66           0 :     functionNode->getFunctionSymbolInfo()->setId(functionId);
      67           0 :     return functionNode;
      68             : }
      69             : 
      70           0 : class DeferGlobalInitializersTraverser : public TIntermTraverser
      71             : {
      72             :   public:
      73             :     DeferGlobalInitializersTraverser();
      74             : 
      75             :     bool visitBinary(Visit visit, TIntermBinary *node) override;
      76             : 
      77             :     void insertInitFunction(TIntermBlock *root);
      78             : 
      79             :   private:
      80             :     TIntermSequence mDeferredInitializers;
      81             : };
      82             : 
      83           0 : DeferGlobalInitializersTraverser::DeferGlobalInitializersTraverser()
      84           0 :     : TIntermTraverser(true, false, false)
      85             : {
      86           0 : }
      87             : 
      88           0 : bool DeferGlobalInitializersTraverser::visitBinary(Visit visit, TIntermBinary *node)
      89             : {
      90           0 :     if (node->getOp() == EOpInitialize)
      91             :     {
      92           0 :         TIntermSymbol *symbolNode = node->getLeft()->getAsSymbolNode();
      93           0 :         ASSERT(symbolNode);
      94           0 :         TIntermTyped *expression = node->getRight();
      95             : 
      96           0 :         if (mInGlobalScope && (expression->getQualifier() != EvqConst ||
      97           0 :                                (expression->getAsConstantUnion() == nullptr &&
      98           0 :                                 !expression->isConstructorWithOnlyConstantUnionParameters())))
      99             :         {
     100             :             // For variables which are not constant, defer their real initialization until
     101             :             // after we initialize uniforms.
     102             :             // Deferral is done also in any cases where the variable has not been constant folded,
     103             :             // since otherwise there's a chance that HLSL output will generate extra statements
     104             :             // from the initializer expression.
     105             :             TIntermBinary *deferredInit =
     106           0 :                 new TIntermBinary(EOpAssign, symbolNode->deepCopy(), node->getRight());
     107           0 :             mDeferredInitializers.push_back(deferredInit);
     108             : 
     109             :             // Change const global to a regular global if its initialization is deferred.
     110             :             // This can happen if ANGLE has not been able to fold the constant expression used
     111             :             // as an initializer.
     112           0 :             ASSERT(symbolNode->getQualifier() == EvqConst ||
     113             :                    symbolNode->getQualifier() == EvqGlobal);
     114           0 :             if (symbolNode->getQualifier() == EvqConst)
     115             :             {
     116             :                 // All of the siblings in the same declaration need to have consistent qualifiers.
     117           0 :                 auto *siblings = getParentNode()->getAsDeclarationNode()->getSequence();
     118           0 :                 for (TIntermNode *siblingNode : *siblings)
     119             :                 {
     120           0 :                     TIntermBinary *siblingBinary = siblingNode->getAsBinaryNode();
     121           0 :                     if (siblingBinary)
     122             :                     {
     123           0 :                         ASSERT(siblingBinary->getOp() == EOpInitialize);
     124           0 :                         siblingBinary->getLeft()->getTypePointer()->setQualifier(EvqGlobal);
     125             :                     }
     126           0 :                     siblingNode->getAsTyped()->getTypePointer()->setQualifier(EvqGlobal);
     127             :                 }
     128             :                 // This node is one of the siblings.
     129           0 :                 ASSERT(symbolNode->getQualifier() == EvqGlobal);
     130             :             }
     131             :             // Remove the initializer from the global scope and just declare the global instead.
     132           0 :             queueReplacement(node, symbolNode, OriginalNode::IS_DROPPED);
     133             :         }
     134             :     }
     135           0 :     return false;
     136             : }
     137             : 
     138           0 : void DeferGlobalInitializersTraverser::insertInitFunction(TIntermBlock *root)
     139             : {
     140           0 :     if (mDeferredInitializers.empty())
     141             :     {
     142           0 :         return;
     143             :     }
     144           0 :     const int initFunctionId  = TSymbolTable::nextUniqueId();
     145             : 
     146           0 :     const char *functionName = "initializeDeferredGlobals";
     147             : 
     148             :     // Add function prototype to the beginning of the shader
     149             :     TIntermAggregate *functionPrototypeNode =
     150           0 :         CreateFunctionPrototypeNode(functionName, initFunctionId);
     151           0 :     root->getSequence()->insert(root->getSequence()->begin(), functionPrototypeNode);
     152             : 
     153             :     // Add function definition to the end of the shader
     154           0 :     TIntermBlock *functionBodyNode = new TIntermBlock();
     155           0 :     TIntermSequence *functionBody = functionBodyNode->getSequence();
     156           0 :     for (const auto &deferredInit : mDeferredInitializers)
     157             :     {
     158           0 :         functionBody->push_back(deferredInit);
     159             :     }
     160             :     TIntermFunctionDefinition *functionDefinition =
     161           0 :         CreateFunctionDefinitionNode(functionName, functionBodyNode, initFunctionId);
     162           0 :     root->getSequence()->push_back(functionDefinition);
     163             : 
     164             :     // Insert call into main function
     165           0 :     for (TIntermNode *node : *root->getSequence())
     166             :     {
     167           0 :         TIntermFunctionDefinition *nodeFunction = node->getAsFunctionDefinition();
     168           0 :         if (nodeFunction != nullptr && nodeFunction->getFunctionSymbolInfo()->isMain())
     169             :         {
     170             :             TIntermAggregate *functionCallNode =
     171           0 :                 CreateFunctionCallNode(functionName, initFunctionId);
     172             : 
     173           0 :             TIntermBlock *mainBody = nodeFunction->getBody();
     174           0 :             ASSERT(mainBody != nullptr);
     175           0 :             mainBody->getSequence()->insert(mainBody->getSequence()->begin(), functionCallNode);
     176             :         }
     177             :     }
     178             : }
     179             : 
     180             : }  // namespace
     181             : 
     182           0 : void DeferGlobalInitializers(TIntermBlock *root)
     183             : {
     184           0 :     DeferGlobalInitializersTraverser traverser;
     185           0 :     root->traverse(&traverser);
     186             : 
     187             :     // Replace the initializers of the global variables.
     188           0 :     traverser.updateTree();
     189             : 
     190             :     // Add the function with initialization and the call to that.
     191           0 :     traverser.insertInitFunction(root);
     192           0 : }
     193             : 
     194             : }  // namespace sh

Generated by: LCOV version 1.13