LCOV - code coverage report
Current view: top level - gfx/angle/src/compiler/translator - ArrayReturnValueToOutParameter.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 100 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 13 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             : // The ArrayReturnValueToOutParameter function changes return values of an array type to out parameters in
       7             : // function definitions, prototypes, and call sites.
       8             : 
       9             : #include "compiler/translator/ArrayReturnValueToOutParameter.h"
      10             : 
      11             : #include "compiler/translator/IntermNode.h"
      12             : 
      13             : namespace sh
      14             : {
      15             : 
      16             : namespace
      17             : {
      18             : 
      19           0 : void CopyAggregateChildren(TIntermAggregate *from, TIntermAggregate *to)
      20             : {
      21           0 :     const TIntermSequence *fromSequence = from->getSequence();
      22           0 :     for (size_t ii = 0; ii < fromSequence->size(); ++ii)
      23             :     {
      24           0 :         to->getSequence()->push_back(fromSequence->at(ii));
      25             :     }
      26           0 : }
      27             : 
      28           0 : TIntermSymbol *CreateReturnValueSymbol(const TType &type)
      29             : {
      30           0 :     TIntermSymbol *node = new TIntermSymbol(0, "angle_return", type);
      31           0 :     node->setInternal(true);
      32           0 :     return node;
      33             : }
      34             : 
      35           0 : TIntermSymbol *CreateReturnValueOutSymbol(const TType &type)
      36             : {
      37           0 :     TType outType(type);
      38           0 :     outType.setQualifier(EvqOut);
      39           0 :     return CreateReturnValueSymbol(outType);
      40             : }
      41             : 
      42           0 : TIntermAggregate *CreateReplacementCall(TIntermAggregate *originalCall, TIntermTyped *returnValueTarget)
      43             : {
      44           0 :     TIntermAggregate *replacementCall = new TIntermAggregate(EOpFunctionCall);
      45           0 :     replacementCall->setType(TType(EbtVoid));
      46           0 :     replacementCall->setUserDefined();
      47           0 :     *replacementCall->getFunctionSymbolInfo() = *originalCall->getFunctionSymbolInfo();
      48           0 :     replacementCall->setLine(originalCall->getLine());
      49           0 :     TIntermSequence *replacementParameters = replacementCall->getSequence();
      50           0 :     TIntermSequence *originalParameters = originalCall->getSequence();
      51           0 :     for (auto &param : *originalParameters)
      52             :     {
      53           0 :         replacementParameters->push_back(param);
      54             :     }
      55           0 :     replacementParameters->push_back(returnValueTarget);
      56           0 :     return replacementCall;
      57             : }
      58             : 
      59           0 : class ArrayReturnValueToOutParameterTraverser : private TIntermTraverser
      60             : {
      61             :   public:
      62             :     static void apply(TIntermNode *root, unsigned int *temporaryIndex);
      63             :   private:
      64             :     ArrayReturnValueToOutParameterTraverser();
      65             : 
      66             :     bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) override;
      67             :     bool visitAggregate(Visit visit, TIntermAggregate *node) override;
      68             :     bool visitBranch(Visit visit, TIntermBranch *node) override;
      69             :     bool visitBinary(Visit visit, TIntermBinary *node) override;
      70             : 
      71             :     bool mInFunctionWithArrayReturnValue;
      72             : };
      73             : 
      74           0 : void ArrayReturnValueToOutParameterTraverser::apply(TIntermNode *root, unsigned int *temporaryIndex)
      75             : {
      76           0 :     ArrayReturnValueToOutParameterTraverser arrayReturnValueToOutParam;
      77           0 :     arrayReturnValueToOutParam.useTemporaryIndex(temporaryIndex);
      78           0 :     root->traverse(&arrayReturnValueToOutParam);
      79           0 :     arrayReturnValueToOutParam.updateTree();
      80           0 : }
      81             : 
      82           0 : ArrayReturnValueToOutParameterTraverser::ArrayReturnValueToOutParameterTraverser()
      83             :     : TIntermTraverser(true, false, true),
      84           0 :       mInFunctionWithArrayReturnValue(false)
      85             : {
      86           0 : }
      87             : 
      88           0 : bool ArrayReturnValueToOutParameterTraverser::visitFunctionDefinition(
      89             :     Visit visit,
      90             :     TIntermFunctionDefinition *node)
      91             : {
      92           0 :     if (node->isArray() && visit == PreVisit)
      93             :     {
      94             :         // Replace the parameters child node of the function definition with another node
      95             :         // that has the out parameter added.
      96             :         // Also set the function to return void.
      97             : 
      98           0 :         TIntermAggregate *params = node->getFunctionParameters();
      99           0 :         ASSERT(params != nullptr && params->getOp() == EOpParameters);
     100             : 
     101           0 :         TIntermAggregate *replacementParams = new TIntermAggregate;
     102           0 :         replacementParams->setOp(EOpParameters);
     103           0 :         CopyAggregateChildren(params, replacementParams);
     104           0 :         replacementParams->getSequence()->push_back(CreateReturnValueOutSymbol(node->getType()));
     105           0 :         replacementParams->setLine(params->getLine());
     106             : 
     107           0 :         queueReplacementWithParent(node, params, replacementParams, OriginalNode::IS_DROPPED);
     108             : 
     109           0 :         node->setType(TType(EbtVoid));
     110             : 
     111           0 :         mInFunctionWithArrayReturnValue = true;
     112             :     }
     113           0 :     if (visit == PostVisit)
     114             :     {
     115             :         // This isn't conditional on node->isArray() since the type has already been changed on
     116             :         // PreVisit.
     117           0 :         mInFunctionWithArrayReturnValue = false;
     118             :     }
     119           0 :     return true;
     120             : }
     121             : 
     122           0 : bool ArrayReturnValueToOutParameterTraverser::visitAggregate(Visit visit, TIntermAggregate *node)
     123             : {
     124           0 :     if (visit == PreVisit)
     125             :     {
     126           0 :         if (node->isArray())
     127             :         {
     128           0 :             if (node->getOp() == EOpPrototype)
     129             :             {
     130             :                 // Replace the whole prototype node with another node that has the out parameter added.
     131           0 :                 TIntermAggregate *replacement = new TIntermAggregate;
     132           0 :                 replacement->setOp(EOpPrototype);
     133           0 :                 CopyAggregateChildren(node, replacement);
     134           0 :                 replacement->getSequence()->push_back(CreateReturnValueOutSymbol(node->getType()));
     135           0 :                 replacement->setUserDefined();
     136           0 :                 *replacement->getFunctionSymbolInfo() = *node->getFunctionSymbolInfo();
     137           0 :                 replacement->setLine(node->getLine());
     138           0 :                 replacement->setType(TType(EbtVoid));
     139             : 
     140           0 :                 queueReplacement(node, replacement, OriginalNode::IS_DROPPED);
     141             :             }
     142           0 :             else if (node->getOp() == EOpFunctionCall)
     143             :             {
     144             :                 // Handle call sites where the returned array is not assigned.
     145             :                 // Examples where f() is a function returning an array:
     146             :                 // 1. f();
     147             :                 // 2. another_array == f();
     148             :                 // 3. another_function(f());
     149             :                 // 4. return f();
     150             :                 // Cases 2 to 4 are already converted to simpler cases by SeparateExpressionsReturningArrays, so we
     151             :                 // only need to worry about the case where a function call returning an array forms an expression by
     152             :                 // itself.
     153           0 :                 TIntermBlock *parentBlock = getParentNode()->getAsBlock();
     154           0 :                 if (parentBlock)
     155             :                 {
     156           0 :                     nextTemporaryIndex();
     157           0 :                     TIntermSequence replacements;
     158           0 :                     replacements.push_back(createTempDeclaration(node->getType()));
     159           0 :                     TIntermSymbol *returnSymbol = createTempSymbol(node->getType());
     160           0 :                     replacements.push_back(CreateReplacementCall(node, returnSymbol));
     161           0 :                     mMultiReplacements.push_back(
     162           0 :                         NodeReplaceWithMultipleEntry(parentBlock, node, replacements));
     163             :                 }
     164           0 :                 return false;
     165             :             }
     166             :         }
     167             :     }
     168           0 :     return true;
     169             : }
     170             : 
     171           0 : bool ArrayReturnValueToOutParameterTraverser::visitBranch(Visit visit, TIntermBranch *node)
     172             : {
     173           0 :     if (mInFunctionWithArrayReturnValue && node->getFlowOp() == EOpReturn)
     174             :     {
     175             :         // Instead of returning a value, assign to the out parameter and then return.
     176           0 :         TIntermSequence replacements;
     177             : 
     178           0 :         TIntermTyped *expression = node->getExpression();
     179           0 :         ASSERT(expression != nullptr);
     180           0 :         TIntermSymbol *returnValueSymbol = CreateReturnValueSymbol(expression->getType());
     181             :         TIntermBinary *replacementAssignment =
     182           0 :             new TIntermBinary(EOpAssign, returnValueSymbol, expression);
     183           0 :         replacementAssignment->setLine(expression->getLine());
     184           0 :         replacements.push_back(replacementAssignment);
     185             : 
     186           0 :         TIntermBranch *replacementBranch = new TIntermBranch(EOpReturn, nullptr);
     187           0 :         replacementBranch->setLine(node->getLine());
     188           0 :         replacements.push_back(replacementBranch);
     189             : 
     190           0 :         mMultiReplacements.push_back(
     191           0 :             NodeReplaceWithMultipleEntry(getParentNode()->getAsBlock(), node, replacements));
     192             :     }
     193           0 :     return false;
     194             : }
     195             : 
     196           0 : bool ArrayReturnValueToOutParameterTraverser::visitBinary(Visit visit, TIntermBinary *node)
     197             : {
     198           0 :     if (node->getOp() == EOpAssign && node->getLeft()->isArray())
     199             :     {
     200           0 :         TIntermAggregate *rightAgg = node->getRight()->getAsAggregate();
     201           0 :         if (rightAgg != nullptr && rightAgg->getOp() == EOpFunctionCall && rightAgg->isUserDefined())
     202             :         {
     203           0 :             TIntermAggregate *replacementCall = CreateReplacementCall(rightAgg, node->getLeft());
     204           0 :             queueReplacement(node, replacementCall, OriginalNode::IS_DROPPED);
     205             :         }
     206             :     }
     207           0 :     return false;
     208             : }
     209             : 
     210             : } // namespace
     211             : 
     212           0 : void ArrayReturnValueToOutParameter(TIntermNode *root, unsigned int *temporaryIndex)
     213             : {
     214           0 :     ArrayReturnValueToOutParameterTraverser::apply(root, temporaryIndex);
     215           0 : }
     216             : 
     217             : }  // namespace sh

Generated by: LCOV version 1.13