blob: 4631b5d58e17c8beca948541f92d1ad303c8f619 [file] [log] [blame]
Jamie Madille53c98b2014-02-03 11:57:13 -05001//
2// Copyright (c) 2014 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// RewriteElseBlocks.cpp: Implementation for tree transform to change
7// all if-else blocks to if-if blocks.
8//
9
10#include "compiler/translator/RewriteElseBlocks.h"
11#include "compiler/translator/NodeSearch.h"
12#include "compiler/translator/SymbolTable.h"
13
14namespace sh
15{
16
Jamie Madill4836d222014-07-24 06:55:51 -040017namespace
18{
19
20class ElseBlockRewriter : public TIntermTraverser
21{
22 public:
23 ElseBlockRewriter();
24
25 protected:
26 bool visitAggregate(Visit visit, TIntermAggregate *aggregate);
27
28 private:
29 int mTemporaryIndex;
30 const TType *mFunctionType;
31
32 TIntermNode *rewriteSelection(TIntermSelection *selection);
33};
34
Jamie Madille53c98b2014-02-03 11:57:13 -050035TIntermSymbol *MakeNewTemporary(const TString &name, TBasicType type)
36{
Olli Etuaho78174db2015-04-21 16:14:00 +030037 TType variableType(type, EbpHigh, EvqTemporary);
38 TIntermSymbol *node = new TIntermSymbol(-1, name, variableType);
39 node->setInternal(true);
40 return node;
Jamie Madille53c98b2014-02-03 11:57:13 -050041}
42
43TIntermBinary *MakeNewBinary(TOperator op, TIntermTyped *left, TIntermTyped *right, const TType &resultType)
44{
45 TIntermBinary *binary = new TIntermBinary(op);
46 binary->setLeft(left);
47 binary->setRight(right);
48 binary->setType(resultType);
49 return binary;
50}
51
52TIntermUnary *MakeNewUnary(TOperator op, TIntermTyped *operand)
53{
54 TIntermUnary *unary = new TIntermUnary(op, operand->getType());
55 unary->setOperand(operand);
56 return unary;
57}
58
Jamie Madill787fc032014-07-07 12:49:45 -040059ElseBlockRewriter::ElseBlockRewriter()
60 : TIntermTraverser(true, false, true, false),
61 mTemporaryIndex(0),
62 mFunctionType(NULL)
63{}
64
Jamie Madille53c98b2014-02-03 11:57:13 -050065bool ElseBlockRewriter::visitAggregate(Visit visit, TIntermAggregate *node)
66{
67 switch (node->getOp())
68 {
69 case EOpSequence:
Jamie Madill787fc032014-07-07 12:49:45 -040070 if (visit == PostVisit)
Jamie Madille53c98b2014-02-03 11:57:13 -050071 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -070072 for (size_t statementIndex = 0; statementIndex != node->getSequence()->size(); statementIndex++)
Jamie Madille53c98b2014-02-03 11:57:13 -050073 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -070074 TIntermNode *statement = (*node->getSequence())[statementIndex];
Jamie Madille53c98b2014-02-03 11:57:13 -050075 TIntermSelection *selection = statement->getAsSelectionNode();
76 if (selection && selection->getFalseBlock() != NULL)
77 {
Jamie Madilled3eef12014-02-26 09:47:11 -050078 // Check for if / else if
79 TIntermSelection *elseIfBranch = selection->getFalseBlock()->getAsSelectionNode();
80 if (elseIfBranch)
81 {
82 selection->replaceChildNode(elseIfBranch, rewriteSelection(elseIfBranch));
83 delete elseIfBranch;
84 }
85
Zhenyao Moe40d1e92014-07-16 17:40:36 -070086 (*node->getSequence())[statementIndex] = rewriteSelection(selection);
Jamie Madille53c98b2014-02-03 11:57:13 -050087 delete selection;
88 }
89 }
90 }
91 break;
92
Jamie Madill787fc032014-07-07 12:49:45 -040093 case EOpFunction:
94 // Store the current function context (see comment below)
95 mFunctionType = ((visit == PreVisit) ? &node->getType() : NULL);
96 break;
97
Jamie Madille53c98b2014-02-03 11:57:13 -050098 default: break;
99 }
100
101 return true;
102}
103
104TIntermNode *ElseBlockRewriter::rewriteSelection(TIntermSelection *selection)
105{
Jamie Madill4836d222014-07-24 06:55:51 -0400106 ASSERT(selection != NULL);
Jamie Madille53c98b2014-02-03 11:57:13 -0500107
108 TString temporaryName = "cond_" + str(mTemporaryIndex++);
109 TIntermTyped *typedCondition = selection->getCondition()->getAsTyped();
110 TType resultType(EbtBool, EbpUndefined);
Jamie Madill4836d222014-07-24 06:55:51 -0400111 TIntermSymbol *conditionSymbolInit = MakeNewTemporary(temporaryName, EbtBool);
112 TIntermBinary *storeCondition = MakeNewBinary(EOpInitialize, conditionSymbolInit,
Jamie Madille53c98b2014-02-03 11:57:13 -0500113 typedCondition, resultType);
Jamie Madill787fc032014-07-07 12:49:45 -0400114 TIntermNode *negatedElse = NULL;
115
Jamie Madill4836d222014-07-24 06:55:51 -0400116 TIntermSelection *falseBlock = NULL;
117
118 if (selection->getFalseBlock())
Jamie Madill787fc032014-07-07 12:49:45 -0400119 {
Jamie Madill4836d222014-07-24 06:55:51 -0400120 // crbug.com/346463
121 // D3D generates error messages claiming a function has no return value, when rewriting
122 // an if-else clause that returns something non-void in a function. By appending dummy
123 // returns (that are unreachable) we can silence this compile error.
124 if (mFunctionType && mFunctionType->getBasicType() != EbtVoid)
125 {
126 TString typeString = mFunctionType->getStruct() ? mFunctionType->getStruct()->name() :
127 mFunctionType->getBasicString();
128 TString rawText = "return (" + typeString + ")0";
129 negatedElse = new TIntermRaw(*mFunctionType, rawText);
130 }
131
132 TIntermSymbol *conditionSymbolElse = MakeNewTemporary(temporaryName, EbtBool);
133 TIntermUnary *negatedCondition = MakeNewUnary(EOpLogicalNot, conditionSymbolElse);
134 falseBlock = new TIntermSelection(negatedCondition,
135 selection->getFalseBlock(), negatedElse);
Jamie Madill787fc032014-07-07 12:49:45 -0400136 }
137
Jamie Madill4836d222014-07-24 06:55:51 -0400138 TIntermSymbol *conditionSymbolSel = MakeNewTemporary(temporaryName, EbtBool);
139 TIntermSelection *newSelection = new TIntermSelection(conditionSymbolSel,
140 selection->getTrueBlock(), falseBlock);
Jamie Madille53c98b2014-02-03 11:57:13 -0500141
142 TIntermAggregate *declaration = new TIntermAggregate(EOpDeclaration);
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700143 declaration->getSequence()->push_back(storeCondition);
Jamie Madille53c98b2014-02-03 11:57:13 -0500144
145 TIntermAggregate *block = new TIntermAggregate(EOpSequence);
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700146 block->getSequence()->push_back(declaration);
Jamie Madill4836d222014-07-24 06:55:51 -0400147 block->getSequence()->push_back(newSelection);
Jamie Madille53c98b2014-02-03 11:57:13 -0500148
149 return block;
150}
151
Jamie Madill4836d222014-07-24 06:55:51 -0400152}
153
Jamie Madille53c98b2014-02-03 11:57:13 -0500154void RewriteElseBlocks(TIntermNode *node)
155{
156 ElseBlockRewriter rewriter;
157 node->traverse(&rewriter);
158}
159
160}