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

          Line data    Source code
       1             : //
       2             : // Copyright (c) 2002-2015 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             : 
       7             : // Analysis of the AST needed for HLSL generation
       8             : 
       9             : #include "compiler/translator/ASTMetadataHLSL.h"
      10             : 
      11             : #include "compiler/translator/CallDAG.h"
      12             : #include "compiler/translator/SymbolTable.h"
      13             : 
      14             : namespace sh
      15             : {
      16             : 
      17             : namespace
      18             : {
      19             : 
      20             : // Class used to traverse the AST of a function definition, checking if the
      21             : // function uses a gradient, and writing the set of control flow using gradients.
      22             : // It assumes that the analysis has already been made for the function's
      23             : // callees.
      24           0 : class PullGradient : public TIntermTraverser
      25             : {
      26             :   public:
      27           0 :     PullGradient(MetadataList *metadataList, size_t index, const CallDAG &dag)
      28           0 :         : TIntermTraverser(true, false, true),
      29             :           mMetadataList(metadataList),
      30           0 :           mMetadata(&(*metadataList)[index]),
      31             :           mIndex(index),
      32           0 :           mDag(dag)
      33             :     {
      34           0 :         ASSERT(index < metadataList->size());
      35           0 :     }
      36             : 
      37           0 :     void traverse(TIntermFunctionDefinition *node)
      38             :     {
      39           0 :         node->traverse(this);
      40           0 :         ASSERT(mParents.empty());
      41           0 :     }
      42             : 
      43             :     // Called when a gradient operation or a call to a function using a gradient is found.
      44           0 :     void onGradient()
      45             :     {
      46           0 :         mMetadata->mUsesGradient = true;
      47             :         // Mark the latest control flow as using a gradient.
      48           0 :         if (!mParents.empty())
      49             :         {
      50           0 :             mMetadata->mControlFlowsContainingGradient.insert(mParents.back());
      51             :         }
      52           0 :     }
      53             : 
      54           0 :     void visitControlFlow(Visit visit, TIntermNode *node)
      55             :     {
      56           0 :         if (visit == PreVisit)
      57             :         {
      58           0 :             mParents.push_back(node);
      59             :         }
      60           0 :         else if (visit == PostVisit)
      61             :         {
      62           0 :             ASSERT(mParents.back() == node);
      63           0 :             mParents.pop_back();
      64             :             // A control flow's using a gradient means its parents are too.
      65           0 :             if (mMetadata->mControlFlowsContainingGradient.count(node)> 0 && !mParents.empty())
      66             :             {
      67           0 :                 mMetadata->mControlFlowsContainingGradient.insert(mParents.back());
      68             :             }
      69             :         }
      70           0 :     }
      71             : 
      72           0 :     bool visitLoop(Visit visit, TIntermLoop *loop) override
      73             :     {
      74           0 :         visitControlFlow(visit, loop);
      75           0 :         return true;
      76             :     }
      77             : 
      78           0 :     bool visitIfElse(Visit visit, TIntermIfElse *ifElse) override
      79             :     {
      80           0 :         visitControlFlow(visit, ifElse);
      81           0 :         return true;
      82             :     }
      83             : 
      84           0 :     bool visitUnary(Visit visit, TIntermUnary *node) override
      85             :     {
      86           0 :         if (visit == PreVisit)
      87             :         {
      88           0 :             switch (node->getOp())
      89             :             {
      90             :               case EOpDFdx:
      91             :               case EOpDFdy:
      92           0 :                 onGradient();
      93             :               default:
      94           0 :                 break;
      95             :             }
      96             :         }
      97             : 
      98           0 :         return true;
      99             :     }
     100             : 
     101           0 :     bool visitAggregate(Visit visit, TIntermAggregate *node) override
     102             :     {
     103           0 :         if (visit == PreVisit)
     104             :         {
     105           0 :             if (node->getOp() == EOpFunctionCall)
     106             :             {
     107           0 :                 if (node->isUserDefined())
     108             :                 {
     109           0 :                     size_t calleeIndex = mDag.findIndex(node->getFunctionSymbolInfo());
     110           0 :                     ASSERT(calleeIndex != CallDAG::InvalidIndex && calleeIndex < mIndex);
     111             : 
     112           0 :                     if ((*mMetadataList)[calleeIndex].mUsesGradient) {
     113           0 :                         onGradient();
     114             :                     }
     115             :                 }
     116             :                 else
     117             :                 {
     118             :                     TString name =
     119           0 :                         TFunction::unmangleName(node->getFunctionSymbolInfo()->getName());
     120             : 
     121           0 :                     if (name == "texture2D" ||
     122           0 :                         name == "texture2DProj" ||
     123           0 :                         name == "textureCube")
     124             :                     {
     125           0 :                         onGradient();
     126             :                     }
     127             :                 }
     128             :             }
     129             :         }
     130             : 
     131           0 :         return true;
     132             :     }
     133             : 
     134             :   private:
     135             :     MetadataList *mMetadataList;
     136             :     ASTMetadataHLSL *mMetadata;
     137             :     size_t mIndex;
     138             :     const CallDAG &mDag;
     139             : 
     140             :     // Contains a stack of the control flow nodes that are parents of the node being
     141             :     // currently visited. It is used to mark control flows using a gradient.
     142             :     std::vector<TIntermNode*> mParents;
     143             : };
     144             : 
     145             : // Traverses the AST of a function definition to compute the the discontinuous loops
     146             : // and the if statements containing gradient loops. It assumes that the gradient loops
     147             : // (loops that contain a gradient) have already been computed and that it has already
     148             : // traversed the current function's callees.
     149           0 : class PullComputeDiscontinuousAndGradientLoops : public TIntermTraverser
     150             : {
     151             :   public:
     152           0 :     PullComputeDiscontinuousAndGradientLoops(MetadataList *metadataList,
     153             :                                              size_t index,
     154             :                                              const CallDAG &dag)
     155           0 :         : TIntermTraverser(true, false, true),
     156             :           mMetadataList(metadataList),
     157           0 :           mMetadata(&(*metadataList)[index]),
     158             :           mIndex(index),
     159           0 :           mDag(dag)
     160             :     {
     161           0 :     }
     162             : 
     163           0 :     void traverse(TIntermFunctionDefinition *node)
     164             :     {
     165           0 :         node->traverse(this);
     166           0 :         ASSERT(mLoopsAndSwitches.empty());
     167           0 :         ASSERT(mIfs.empty());
     168           0 :     }
     169             : 
     170             :     // Called when traversing a gradient loop or a call to a function with a
     171             :     // gradient loop in its call graph.
     172           0 :     void onGradientLoop()
     173             :     {
     174           0 :         mMetadata->mHasGradientLoopInCallGraph = true;
     175             :         // Mark the latest if as using a discontinuous loop.
     176           0 :         if (!mIfs.empty())
     177             :         {
     178           0 :             mMetadata->mIfsContainingGradientLoop.insert(mIfs.back());
     179             :         }
     180           0 :     }
     181             : 
     182           0 :     bool visitLoop(Visit visit, TIntermLoop *loop) override
     183             :     {
     184           0 :         if (visit == PreVisit)
     185             :         {
     186           0 :             mLoopsAndSwitches.push_back(loop);
     187             : 
     188           0 :             if (mMetadata->hasGradientInCallGraph(loop))
     189             :             {
     190           0 :                 onGradientLoop();
     191             :             }
     192             :         }
     193           0 :         else if (visit == PostVisit)
     194             :         {
     195           0 :             ASSERT(mLoopsAndSwitches.back() == loop);
     196           0 :             mLoopsAndSwitches.pop_back();
     197             :         }
     198             : 
     199           0 :         return true;
     200             :     }
     201             : 
     202           0 :     bool visitIfElse(Visit visit, TIntermIfElse *node) override
     203             :     {
     204           0 :         if (visit == PreVisit)
     205             :         {
     206           0 :             mIfs.push_back(node);
     207             :         }
     208           0 :         else if (visit == PostVisit)
     209             :         {
     210           0 :             ASSERT(mIfs.back() == node);
     211           0 :             mIfs.pop_back();
     212             :             // An if using a discontinuous loop means its parents ifs are also discontinuous.
     213           0 :             if (mMetadata->mIfsContainingGradientLoop.count(node) > 0 && !mIfs.empty())
     214             :             {
     215           0 :                 mMetadata->mIfsContainingGradientLoop.insert(mIfs.back());
     216             :             }
     217             :         }
     218             : 
     219           0 :         return true;
     220             :     }
     221             : 
     222           0 :     bool visitBranch(Visit visit, TIntermBranch *node) override
     223             :     {
     224           0 :         if (visit == PreVisit)
     225             :         {
     226           0 :             switch (node->getFlowOp())
     227             :             {
     228             :               case EOpBreak:
     229             :                 {
     230           0 :                     ASSERT(!mLoopsAndSwitches.empty());
     231           0 :                     TIntermLoop *loop = mLoopsAndSwitches.back()->getAsLoopNode();
     232           0 :                     if (loop != nullptr)
     233             :                     {
     234           0 :                         mMetadata->mDiscontinuousLoops.insert(loop);
     235             :                     }
     236             :                 }
     237           0 :                 break;
     238             :               case EOpContinue:
     239             :                 {
     240           0 :                     ASSERT(!mLoopsAndSwitches.empty());
     241           0 :                     TIntermLoop *loop = nullptr;
     242           0 :                     size_t i = mLoopsAndSwitches.size();
     243           0 :                     while (loop == nullptr && i > 0)
     244             :                     {
     245           0 :                         --i;
     246           0 :                         loop = mLoopsAndSwitches.at(i)->getAsLoopNode();
     247             :                     }
     248           0 :                     ASSERT(loop != nullptr);
     249           0 :                     mMetadata->mDiscontinuousLoops.insert(loop);
     250             :                 }
     251           0 :                 break;
     252             :               case EOpKill:
     253             :               case EOpReturn:
     254             :                 // A return or discard jumps out of all the enclosing loops
     255           0 :                 if (!mLoopsAndSwitches.empty())
     256             :                 {
     257           0 :                     for (TIntermNode *intermNode : mLoopsAndSwitches)
     258             :                     {
     259           0 :                         TIntermLoop *loop = intermNode->getAsLoopNode();
     260           0 :                         if (loop)
     261             :                         {
     262           0 :                             mMetadata->mDiscontinuousLoops.insert(loop);
     263             :                         }
     264             :                     }
     265             :                 }
     266           0 :                 break;
     267             :               default:
     268           0 :                 UNREACHABLE();
     269             :             }
     270             :         }
     271             : 
     272           0 :         return true;
     273             :     }
     274             : 
     275           0 :     bool visitAggregate(Visit visit, TIntermAggregate *node) override
     276             :     {
     277           0 :         if (visit == PreVisit && node->getOp() == EOpFunctionCall)
     278             :         {
     279           0 :             if (node->isUserDefined())
     280             :             {
     281           0 :                 size_t calleeIndex = mDag.findIndex(node->getFunctionSymbolInfo());
     282           0 :                 ASSERT(calleeIndex != CallDAG::InvalidIndex && calleeIndex < mIndex);
     283             : 
     284           0 :                 if ((*mMetadataList)[calleeIndex].mHasGradientLoopInCallGraph)
     285             :                 {
     286           0 :                     onGradientLoop();
     287             :                 }
     288             :             }
     289             :         }
     290             : 
     291           0 :         return true;
     292             :     }
     293             : 
     294           0 :     bool visitSwitch(Visit visit, TIntermSwitch *node) override
     295             :     {
     296           0 :         if (visit == PreVisit)
     297             :         {
     298           0 :             mLoopsAndSwitches.push_back(node);
     299             :         }
     300           0 :         else if (visit == PostVisit)
     301             :         {
     302           0 :             ASSERT(mLoopsAndSwitches.back() == node);
     303           0 :             mLoopsAndSwitches.pop_back();
     304             :         }
     305           0 :         return true;
     306             :     }
     307             : 
     308             :   private:
     309             :     MetadataList *mMetadataList;
     310             :     ASTMetadataHLSL *mMetadata;
     311             :     size_t mIndex;
     312             :     const CallDAG &mDag;
     313             : 
     314             :     std::vector<TIntermNode*> mLoopsAndSwitches;
     315             :     std::vector<TIntermIfElse *> mIfs;
     316             : };
     317             : 
     318             : // Tags all the functions called in a discontinuous loop
     319           0 : class PushDiscontinuousLoops : public TIntermTraverser
     320             : {
     321             :   public:
     322           0 :     PushDiscontinuousLoops(MetadataList *metadataList, size_t index, const CallDAG &dag)
     323           0 :         : TIntermTraverser(true, true, true),
     324             :           mMetadataList(metadataList),
     325           0 :           mMetadata(&(*metadataList)[index]),
     326             :           mIndex(index),
     327             :           mDag(dag),
     328           0 :           mNestedDiscont(mMetadata->mCalledInDiscontinuousLoop ? 1 : 0)
     329             :     {
     330           0 :     }
     331             : 
     332           0 :     void traverse(TIntermFunctionDefinition *node)
     333             :     {
     334           0 :         node->traverse(this);
     335           0 :         ASSERT(mNestedDiscont == (mMetadata->mCalledInDiscontinuousLoop ? 1 : 0));
     336           0 :     }
     337             : 
     338           0 :     bool visitLoop(Visit visit, TIntermLoop *loop) override
     339             :     {
     340           0 :         bool isDiscontinuous = mMetadata->mDiscontinuousLoops.count(loop) > 0;
     341             : 
     342           0 :         if (visit == PreVisit && isDiscontinuous)
     343             :         {
     344           0 :             mNestedDiscont++;
     345             :         }
     346           0 :         else if (visit == PostVisit && isDiscontinuous)
     347             :         {
     348           0 :             mNestedDiscont--;
     349             :         }
     350             : 
     351           0 :         return true;
     352             :     }
     353             : 
     354           0 :     bool visitAggregate(Visit visit, TIntermAggregate *node) override
     355             :     {
     356           0 :         switch (node->getOp())
     357             :         {
     358             :           case EOpFunctionCall:
     359           0 :             if (visit == PreVisit && node->isUserDefined() && mNestedDiscont > 0)
     360             :             {
     361           0 :                 size_t calleeIndex = mDag.findIndex(node->getFunctionSymbolInfo());
     362           0 :                 ASSERT(calleeIndex != CallDAG::InvalidIndex && calleeIndex < mIndex);
     363             : 
     364           0 :                 (*mMetadataList)[calleeIndex].mCalledInDiscontinuousLoop = true;
     365             :             }
     366           0 :             break;
     367             :           default:
     368           0 :             break;
     369             :         }
     370           0 :         return true;
     371             :     }
     372             : 
     373             :   private:
     374             :     MetadataList *mMetadataList;
     375             :     ASTMetadataHLSL *mMetadata;
     376             :     size_t mIndex;
     377             :     const CallDAG &mDag;
     378             : 
     379             :     int mNestedDiscont;
     380             : };
     381             : 
     382             : }
     383             : 
     384           0 : bool ASTMetadataHLSL::hasGradientInCallGraph(TIntermLoop *node)
     385             : {
     386           0 :     return mControlFlowsContainingGradient.count(node) > 0;
     387             : }
     388             : 
     389           0 : bool ASTMetadataHLSL::hasGradientLoop(TIntermIfElse *node)
     390             : {
     391           0 :     return mIfsContainingGradientLoop.count(node) > 0;
     392             : }
     393             : 
     394           0 : MetadataList CreateASTMetadataHLSL(TIntermNode *root, const CallDAG &callDag)
     395             : {
     396           0 :     MetadataList metadataList(callDag.size());
     397             : 
     398             :     // Compute all the information related to when gradient operations are used.
     399             :     // We want to know for each function and control flow operation if they have
     400             :     // a gradient operation in their call graph (shortened to "using a gradient"
     401             :     // in the rest of the file).
     402             :     //
     403             :     // This computation is logically split in three steps:
     404             :     //  1 - For each function compute if it uses a gradient in its body, ignoring
     405             :     // calls to other user-defined functions.
     406             :     //  2 - For each function determine if it uses a gradient in its call graph,
     407             :     // using the result of step 1 and the CallDAG to know its callees.
     408             :     //  3 - For each control flow statement of each function, check if it uses a
     409             :     // gradient in the function's body, or if it calls a user-defined function that
     410             :     // uses a gradient.
     411             :     //
     412             :     // We take advantage of the call graph being a DAG and instead compute 1, 2 and 3
     413             :     // for leaves first, then going down the tree. This is correct because 1 doesn't
     414             :     // depend on other functions, and 2 and 3 depend only on callees.
     415           0 :     for (size_t i = 0; i < callDag.size(); i++)
     416             :     {
     417           0 :         PullGradient pull(&metadataList, i, callDag);
     418           0 :         pull.traverse(callDag.getRecordFromIndex(i).node);
     419             :     }
     420             : 
     421             :     // Compute which loops are discontinuous and which function are called in
     422             :     // these loops. The same way computing gradient usage is a "pull" process,
     423             :     // computing "bing used in a discont. loop" is a push process. However we also
     424             :     // need to know what ifs have a discontinuous loop inside so we do the same type
     425             :     // of callgraph analysis as for the gradient.
     426             : 
     427             :     // First compute which loops are discontinuous (no specific order) and pull
     428             :     // the ifs and functions using a gradient loop.
     429           0 :     for (size_t i = 0; i < callDag.size(); i++)
     430             :     {
     431           0 :         PullComputeDiscontinuousAndGradientLoops pull(&metadataList, i, callDag);
     432           0 :         pull.traverse(callDag.getRecordFromIndex(i).node);
     433             :     }
     434             : 
     435             :     // Then push the information to callees, either from the a local discontinuous
     436             :     // loop or from the caller being called in a discontinuous loop already
     437           0 :     for (size_t i = callDag.size(); i-- > 0;)
     438             :     {
     439           0 :         PushDiscontinuousLoops push(&metadataList, i, callDag);
     440           0 :         push.traverse(callDag.getRecordFromIndex(i).node);
     441             :     }
     442             : 
     443             :     // We create "Lod0" version of functions with the gradient operations replaced
     444             :     // by non-gradient operations so that the D3D compiler is happier with discont
     445             :     // loops.
     446           0 :     for (auto &metadata : metadataList)
     447             :     {
     448           0 :         metadata.mNeedsLod0 = metadata.mCalledInDiscontinuousLoop && metadata.mUsesGradient;
     449             :     }
     450             : 
     451           0 :     return metadataList;
     452             : }
     453             : 
     454             : }  // namespace sh

Generated by: LCOV version 1.13