1e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill//
2e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved.
3e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill// Use of this source code is governed by a BSD-style license that can be
4e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill// found in the LICENSE file.
5e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill//
6e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill// RewriteElseBlocks.cpp: Implementation for tree transform to change
7e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill//   all if-else blocks to if-if blocks.
8e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill//
9e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill
10e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill#include "compiler/translator/RewriteElseBlocks.h"
11e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill#include "compiler/translator/NodeSearch.h"
12e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill#include "compiler/translator/SymbolTable.h"
13e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill
14e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madillnamespace sh
15e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill{
16e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill
17e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie MadillTIntermSymbol *MakeNewTemporary(const TString &name, TBasicType type)
18e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill{
19e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill    TType variableType(type, EbpHigh, EvqInternal);
20e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill    return new TIntermSymbol(-1, name, variableType);
21e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill}
22e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill
23e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie MadillTIntermBinary *MakeNewBinary(TOperator op, TIntermTyped *left, TIntermTyped *right, const TType &resultType)
24e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill{
25e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill    TIntermBinary *binary = new TIntermBinary(op);
26e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill    binary->setLeft(left);
27e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill    binary->setRight(right);
28e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill    binary->setType(resultType);
29e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill    return binary;
30e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill}
31e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill
32e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie MadillTIntermUnary *MakeNewUnary(TOperator op, TIntermTyped *operand)
33e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill{
34e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill    TIntermUnary *unary = new TIntermUnary(op, operand->getType());
35e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill    unary->setOperand(operand);
36e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill    return unary;
37e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill}
38e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill
39ebba7d306b34a56f57ff1b87682bdc67cc9c50f8Jamie MadillElseBlockRewriter::ElseBlockRewriter()
40ebba7d306b34a56f57ff1b87682bdc67cc9c50f8Jamie Madill    : TIntermTraverser(true, false, true, false),
41ebba7d306b34a56f57ff1b87682bdc67cc9c50f8Jamie Madill      mTemporaryIndex(0),
42ebba7d306b34a56f57ff1b87682bdc67cc9c50f8Jamie Madill      mFunctionType(NULL)
43ebba7d306b34a56f57ff1b87682bdc67cc9c50f8Jamie Madill{}
44ebba7d306b34a56f57ff1b87682bdc67cc9c50f8Jamie Madill
45e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madillbool ElseBlockRewriter::visitAggregate(Visit visit, TIntermAggregate *node)
46e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill{
47e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill    switch (node->getOp())
48e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill    {
49e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill      case EOpSequence:
50ebba7d306b34a56f57ff1b87682bdc67cc9c50f8Jamie Madill        if (visit == PostVisit)
51e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill        {
52e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill            for (size_t statementIndex = 0; statementIndex != node->getSequence().size(); statementIndex++)
53e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill            {
54e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill                TIntermNode *statement = node->getSequence()[statementIndex];
55e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill                TIntermSelection *selection = statement->getAsSelectionNode();
56e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill                if (selection && selection->getFalseBlock() != NULL)
57e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill                {
585ec99a794952ac04e89bac86b3a6acc50667be71Jamie Madill                    // Check for if / else if
595ec99a794952ac04e89bac86b3a6acc50667be71Jamie Madill                    TIntermSelection *elseIfBranch = selection->getFalseBlock()->getAsSelectionNode();
605ec99a794952ac04e89bac86b3a6acc50667be71Jamie Madill                    if (elseIfBranch)
615ec99a794952ac04e89bac86b3a6acc50667be71Jamie Madill                    {
625ec99a794952ac04e89bac86b3a6acc50667be71Jamie Madill                        selection->replaceChildNode(elseIfBranch, rewriteSelection(elseIfBranch));
635ec99a794952ac04e89bac86b3a6acc50667be71Jamie Madill                        delete elseIfBranch;
645ec99a794952ac04e89bac86b3a6acc50667be71Jamie Madill                    }
655ec99a794952ac04e89bac86b3a6acc50667be71Jamie Madill
66e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill                    node->getSequence()[statementIndex] = rewriteSelection(selection);
67e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill                    delete selection;
68e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill                }
69e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill            }
70e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill        }
71e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill        break;
72e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill
73ebba7d306b34a56f57ff1b87682bdc67cc9c50f8Jamie Madill      case EOpFunction:
74ebba7d306b34a56f57ff1b87682bdc67cc9c50f8Jamie Madill        // Store the current function context (see comment below)
75ebba7d306b34a56f57ff1b87682bdc67cc9c50f8Jamie Madill        mFunctionType = ((visit == PreVisit) ? &node->getType() : NULL);
76ebba7d306b34a56f57ff1b87682bdc67cc9c50f8Jamie Madill        break;
77ebba7d306b34a56f57ff1b87682bdc67cc9c50f8Jamie Madill
78e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill      default: break;
79e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill    }
80e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill
81e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill    return true;
82e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill}
83e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill
84e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie MadillTIntermNode *ElseBlockRewriter::rewriteSelection(TIntermSelection *selection)
85e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill{
86e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill    ASSERT(selection->getFalseBlock() != NULL);
87e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill
88e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill    TString temporaryName = "cond_" + str(mTemporaryIndex++);
89e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill    TIntermTyped *typedCondition = selection->getCondition()->getAsTyped();
90e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill    TType resultType(EbtBool, EbpUndefined);
91e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill    TIntermSymbol *conditionSymbolA = MakeNewTemporary(temporaryName, EbtBool);
92e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill    TIntermSymbol *conditionSymbolB = MakeNewTemporary(temporaryName, EbtBool);
93e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill    TIntermSymbol *conditionSymbolC = MakeNewTemporary(temporaryName, EbtBool);
94e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill    TIntermBinary *storeCondition = MakeNewBinary(EOpInitialize, conditionSymbolA,
95e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill                                                  typedCondition, resultType);
96e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill    TIntermUnary *negatedCondition = MakeNewUnary(EOpLogicalNot, conditionSymbolB);
97ebba7d306b34a56f57ff1b87682bdc67cc9c50f8Jamie Madill    TIntermNode *negatedElse = NULL;
98ebba7d306b34a56f57ff1b87682bdc67cc9c50f8Jamie Madill
99ebba7d306b34a56f57ff1b87682bdc67cc9c50f8Jamie Madill    // crbug.com/346463
100ebba7d306b34a56f57ff1b87682bdc67cc9c50f8Jamie Madill    // D3D generates error messages claiming a function has no return value, when rewriting
101ebba7d306b34a56f57ff1b87682bdc67cc9c50f8Jamie Madill    // an if-else clause that returns something non-void in a function. By appending dummy
102ebba7d306b34a56f57ff1b87682bdc67cc9c50f8Jamie Madill    // returns (that are unreachable) we can silence this compile error.
103ebba7d306b34a56f57ff1b87682bdc67cc9c50f8Jamie Madill    if (mFunctionType && mFunctionType->getBasicType() != EbtVoid)
104ebba7d306b34a56f57ff1b87682bdc67cc9c50f8Jamie Madill    {
105ebba7d306b34a56f57ff1b87682bdc67cc9c50f8Jamie Madill        TString typeString = mFunctionType->getStruct() ? mFunctionType->getStruct()->name() :
106ebba7d306b34a56f57ff1b87682bdc67cc9c50f8Jamie Madill            mFunctionType->getBasicString();
107ebba7d306b34a56f57ff1b87682bdc67cc9c50f8Jamie Madill        TString rawText = "return (" + typeString + ")0";
108ebba7d306b34a56f57ff1b87682bdc67cc9c50f8Jamie Madill        negatedElse = new TIntermRaw(*mFunctionType, rawText);
109ebba7d306b34a56f57ff1b87682bdc67cc9c50f8Jamie Madill    }
110ebba7d306b34a56f57ff1b87682bdc67cc9c50f8Jamie Madill
111e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill    TIntermSelection *falseBlock = new TIntermSelection(negatedCondition,
112ebba7d306b34a56f57ff1b87682bdc67cc9c50f8Jamie Madill                                                        selection->getFalseBlock(), negatedElse);
113e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill    TIntermSelection *newIfElse = new TIntermSelection(conditionSymbolC,
114e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill                                                       selection->getTrueBlock(), falseBlock);
115e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill
116e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill    TIntermAggregate *declaration = new TIntermAggregate(EOpDeclaration);
117e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill    declaration->getSequence().push_back(storeCondition);
118e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill
119e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill    TIntermAggregate *block = new TIntermAggregate(EOpSequence);
120e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill    block->getSequence().push_back(declaration);
121e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill    block->getSequence().push_back(newIfElse);
122e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill
123e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill    return block;
124e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill}
125e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill
126e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madillvoid RewriteElseBlocks(TIntermNode *node)
127e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill{
128e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill    ElseBlockRewriter rewriter;
129e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill    node->traverse(&rewriter);
130e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill}
131e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill
132e53c98ba6cd85074d8f2dae76b34321c7786da3aJamie Madill}
133