LCOV - code coverage report
Current view: top level - gfx/angle/src/compiler/translator - RecordConstantPrecision.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 57 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 8 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             : // During parsing, all constant expressions are folded to constant union nodes. The expressions that have been
       7             : // folded may have had precision qualifiers, which should affect the precision of the consuming operation.
       8             : // If the folded constant union nodes are written to output as such they won't have any precision qualifiers,
       9             : // and their effect on the precision of the consuming operation is lost.
      10             : //
      11             : // RecordConstantPrecision is an AST traverser that inspects the precision qualifiers of constants and hoists
      12             : // the constants outside the containing expression as precision qualified named variables in case that is
      13             : // required for correct precision propagation.
      14             : //
      15             : 
      16             : #include "compiler/translator/RecordConstantPrecision.h"
      17             : 
      18             : #include "compiler/translator/InfoSink.h"
      19             : #include "compiler/translator/IntermNode.h"
      20             : 
      21             : namespace sh
      22             : {
      23             : 
      24             : namespace
      25             : {
      26             : 
      27           0 : class RecordConstantPrecisionTraverser : public TIntermTraverser
      28             : {
      29             :   public:
      30             :     RecordConstantPrecisionTraverser();
      31             : 
      32             :     void visitConstantUnion(TIntermConstantUnion *node) override;
      33             : 
      34             :     void nextIteration();
      35             : 
      36           0 :     bool foundHigherPrecisionConstant() const { return mFoundHigherPrecisionConstant; }
      37             :   protected:
      38             :     bool operandAffectsParentOperationPrecision(TIntermTyped *operand);
      39             : 
      40             :     bool mFoundHigherPrecisionConstant;
      41             : };
      42             : 
      43           0 : RecordConstantPrecisionTraverser::RecordConstantPrecisionTraverser()
      44             :     : TIntermTraverser(true, false, true),
      45           0 :       mFoundHigherPrecisionConstant(false)
      46             : {
      47           0 : }
      48             : 
      49           0 : bool RecordConstantPrecisionTraverser::operandAffectsParentOperationPrecision(TIntermTyped *operand)
      50             : {
      51           0 :     if (getParentNode()->getAsCaseNode() || getParentNode()->getAsBlock())
      52             :     {
      53           0 :         return false;
      54             :     }
      55             : 
      56           0 :     const TIntermBinary *parentAsBinary = getParentNode()->getAsBinaryNode();
      57           0 :     if (parentAsBinary != nullptr)
      58             :     {
      59             :         // If the constant is assigned or is used to initialize a variable, or if it's an index,
      60             :         // its precision has no effect.
      61           0 :         switch (parentAsBinary->getOp())
      62             :         {
      63             :           case EOpInitialize:
      64             :           case EOpAssign:
      65             :           case EOpIndexDirect:
      66             :           case EOpIndexDirectStruct:
      67             :           case EOpIndexDirectInterfaceBlock:
      68             :           case EOpIndexIndirect:
      69           0 :             return false;
      70             :           default:
      71           0 :             break;
      72             :         }
      73             : 
      74           0 :         TIntermTyped *otherOperand = parentAsBinary->getRight();
      75           0 :         if (otherOperand == operand)
      76             :         {
      77           0 :             otherOperand = parentAsBinary->getLeft();
      78             :         }
      79             :         // If the precision of the other child is at least as high as the precision of the constant, the precision of
      80             :         // the constant has no effect.
      81           0 :         if (otherOperand->getAsConstantUnion() == nullptr && otherOperand->getPrecision() >= operand->getPrecision())
      82             :         {
      83           0 :             return false;
      84             :         }
      85             :     }
      86             : 
      87           0 :     TIntermAggregate *parentAsAggregate = getParentNode()->getAsAggregate();
      88           0 :     if (parentAsAggregate != nullptr)
      89             :     {
      90           0 :         if (!parentAsAggregate->gotPrecisionFromChildren())
      91             :         {
      92             :             // This can be either:
      93             :             // * a call to an user-defined function
      94             :             // * a call to a texture function
      95             :             // * some other kind of aggregate
      96             :             // In any of these cases the constant precision has no effect.
      97           0 :             return false;
      98             :         }
      99           0 :         if (parentAsAggregate->isConstructor() && parentAsAggregate->getBasicType() == EbtBool)
     100             :         {
     101           0 :             return false;
     102             :         }
     103             :         // If the precision of operands does affect the result, but the precision of any of the other children
     104             :         // has a precision that's at least as high as the precision of the constant, the precision of the constant
     105             :         // has no effect.
     106           0 :         TIntermSequence *parameters = parentAsAggregate->getSequence();
     107           0 :         for (TIntermNode *parameter : *parameters)
     108             :         {
     109           0 :             const TIntermTyped *typedParameter = parameter->getAsTyped();
     110           0 :             if (parameter != operand && typedParameter != nullptr && parameter->getAsConstantUnion() == nullptr &&
     111           0 :                 typedParameter->getPrecision() >= operand->getPrecision())
     112             :             {
     113           0 :                 return false;
     114             :             }
     115             :         }
     116             :     }
     117           0 :     return true;
     118             : }
     119             : 
     120           0 : void RecordConstantPrecisionTraverser::visitConstantUnion(TIntermConstantUnion *node)
     121             : {
     122           0 :     if (mFoundHigherPrecisionConstant)
     123           0 :         return;
     124             : 
     125             :     // If the constant has lowp or undefined precision, it can't increase the precision of consuming operations.
     126           0 :     if (node->getPrecision() < EbpMedium)
     127           0 :         return;
     128             : 
     129             :     // It's possible the node has no effect on the precision of the consuming expression, depending on the
     130             :     // consuming expression, and the precision of the other parameters of the expression.
     131           0 :     if (!operandAffectsParentOperationPrecision(node))
     132           0 :         return;
     133             : 
     134             :     // Make the constant a precision-qualified named variable to make sure it affects the precision of the consuming
     135             :     // expression.
     136           0 :     TIntermSequence insertions;
     137           0 :     insertions.push_back(createTempInitDeclaration(node, EvqConst));
     138           0 :     insertStatementsInParentBlock(insertions);
     139           0 :     queueReplacement(node, createTempSymbol(node->getType()), OriginalNode::IS_DROPPED);
     140           0 :     mFoundHigherPrecisionConstant = true;
     141             : }
     142             : 
     143           0 : void RecordConstantPrecisionTraverser::nextIteration()
     144             : {
     145           0 :     nextTemporaryIndex();
     146           0 :     mFoundHigherPrecisionConstant = false;
     147           0 : }
     148             : 
     149             : } // namespace
     150             : 
     151           0 : void RecordConstantPrecision(TIntermNode *root, unsigned int *temporaryIndex)
     152             : {
     153           0 :     RecordConstantPrecisionTraverser traverser;
     154           0 :     ASSERT(temporaryIndex != nullptr);
     155           0 :     traverser.useTemporaryIndex(temporaryIndex);
     156             :     // Iterate as necessary, and reset the traverser between iterations.
     157           0 :     do
     158             :     {
     159           0 :         traverser.nextIteration();
     160           0 :         root->traverse(&traverser);
     161           0 :         if (traverser.foundHigherPrecisionConstant())
     162           0 :             traverser.updateTree();
     163             :     }
     164             :     while (traverser.foundHigherPrecisionConstant());
     165           0 : }
     166             : 
     167             : }  // namespace sh

Generated by: LCOV version 1.13