blob: 3a32aa1a5145955525346024e04e85aea868de9d [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
17TIntermSymbol *MakeNewTemporary(const TString &name, TBasicType type)
18{
19 TType variableType(type, EbpHigh, EvqInternal);
20 return new TIntermSymbol(-1, name, variableType);
21}
22
23TIntermBinary *MakeNewBinary(TOperator op, TIntermTyped *left, TIntermTyped *right, const TType &resultType)
24{
25 TIntermBinary *binary = new TIntermBinary(op);
26 binary->setLeft(left);
27 binary->setRight(right);
28 binary->setType(resultType);
29 return binary;
30}
31
32TIntermUnary *MakeNewUnary(TOperator op, TIntermTyped *operand)
33{
34 TIntermUnary *unary = new TIntermUnary(op, operand->getType());
35 unary->setOperand(operand);
36 return unary;
37}
38
Jamie Madill787fc032014-07-07 12:49:45 -040039ElseBlockRewriter::ElseBlockRewriter()
40 : TIntermTraverser(true, false, true, false),
41 mTemporaryIndex(0),
42 mFunctionType(NULL)
43{}
44
Jamie Madille53c98b2014-02-03 11:57:13 -050045bool ElseBlockRewriter::visitAggregate(Visit visit, TIntermAggregate *node)
46{
47 switch (node->getOp())
48 {
49 case EOpSequence:
Jamie Madill787fc032014-07-07 12:49:45 -040050 if (visit == PostVisit)
Jamie Madille53c98b2014-02-03 11:57:13 -050051 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -070052 for (size_t statementIndex = 0; statementIndex != node->getSequence()->size(); statementIndex++)
Jamie Madille53c98b2014-02-03 11:57:13 -050053 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -070054 TIntermNode *statement = (*node->getSequence())[statementIndex];
Jamie Madille53c98b2014-02-03 11:57:13 -050055 TIntermSelection *selection = statement->getAsSelectionNode();
56 if (selection && selection->getFalseBlock() != NULL)
57 {
Jamie Madilled3eef12014-02-26 09:47:11 -050058 // Check for if / else if
59 TIntermSelection *elseIfBranch = selection->getFalseBlock()->getAsSelectionNode();
60 if (elseIfBranch)
61 {
62 selection->replaceChildNode(elseIfBranch, rewriteSelection(elseIfBranch));
63 delete elseIfBranch;
64 }
65
Zhenyao Moe40d1e92014-07-16 17:40:36 -070066 (*node->getSequence())[statementIndex] = rewriteSelection(selection);
Jamie Madille53c98b2014-02-03 11:57:13 -050067 delete selection;
68 }
69 }
70 }
71 break;
72
Jamie Madill787fc032014-07-07 12:49:45 -040073 case EOpFunction:
74 // Store the current function context (see comment below)
75 mFunctionType = ((visit == PreVisit) ? &node->getType() : NULL);
76 break;
77
Jamie Madille53c98b2014-02-03 11:57:13 -050078 default: break;
79 }
80
81 return true;
82}
83
84TIntermNode *ElseBlockRewriter::rewriteSelection(TIntermSelection *selection)
85{
86 ASSERT(selection->getFalseBlock() != NULL);
87
88 TString temporaryName = "cond_" + str(mTemporaryIndex++);
89 TIntermTyped *typedCondition = selection->getCondition()->getAsTyped();
90 TType resultType(EbtBool, EbpUndefined);
91 TIntermSymbol *conditionSymbolA = MakeNewTemporary(temporaryName, EbtBool);
92 TIntermSymbol *conditionSymbolB = MakeNewTemporary(temporaryName, EbtBool);
93 TIntermSymbol *conditionSymbolC = MakeNewTemporary(temporaryName, EbtBool);
94 TIntermBinary *storeCondition = MakeNewBinary(EOpInitialize, conditionSymbolA,
95 typedCondition, resultType);
96 TIntermUnary *negatedCondition = MakeNewUnary(EOpLogicalNot, conditionSymbolB);
Jamie Madill787fc032014-07-07 12:49:45 -040097 TIntermNode *negatedElse = NULL;
98
99 // crbug.com/346463
100 // D3D generates error messages claiming a function has no return value, when rewriting
101 // an if-else clause that returns something non-void in a function. By appending dummy
102 // returns (that are unreachable) we can silence this compile error.
103 if (mFunctionType && mFunctionType->getBasicType() != EbtVoid)
104 {
105 TString typeString = mFunctionType->getStruct() ? mFunctionType->getStruct()->name() :
106 mFunctionType->getBasicString();
107 TString rawText = "return (" + typeString + ")0";
108 negatedElse = new TIntermRaw(*mFunctionType, rawText);
109 }
110
Jamie Madille53c98b2014-02-03 11:57:13 -0500111 TIntermSelection *falseBlock = new TIntermSelection(negatedCondition,
Jamie Madill787fc032014-07-07 12:49:45 -0400112 selection->getFalseBlock(), negatedElse);
Jamie Madille53c98b2014-02-03 11:57:13 -0500113 TIntermSelection *newIfElse = new TIntermSelection(conditionSymbolC,
114 selection->getTrueBlock(), falseBlock);
115
116 TIntermAggregate *declaration = new TIntermAggregate(EOpDeclaration);
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700117 declaration->getSequence()->push_back(storeCondition);
Jamie Madille53c98b2014-02-03 11:57:13 -0500118
119 TIntermAggregate *block = new TIntermAggregate(EOpSequence);
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700120 block->getSequence()->push_back(declaration);
121 block->getSequence()->push_back(newIfElse);
Jamie Madille53c98b2014-02-03 11:57:13 -0500122
123 return block;
124}
125
126void RewriteElseBlocks(TIntermNode *node)
127{
128 ElseBlockRewriter rewriter;
129 node->traverse(&rewriter);
130}
131
132}