1 //
2 // Copyright (c) 2016 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 
7 #include "compiler/translator/RewriteUnaryMinusOperatorFloat.h"
8 
9 #include "compiler/translator/IntermNode_util.h"
10 #include "compiler/translator/IntermTraverse.h"
11 
12 namespace sh
13 {
14 
15 namespace
16 {
17 
18 class Traverser : public TIntermTraverser
19 {
20   public:
21     static void Apply(TIntermNode *root);
22 
23   private:
24     Traverser();
25     bool visitUnary(Visit visit, TIntermUnary *node) override;
26     void nextIteration();
27 
28     bool mFound = false;
29 };
30 
31 // static
Apply(TIntermNode * root)32 void Traverser::Apply(TIntermNode *root)
33 {
34     Traverser traverser;
35     do
36     {
37         traverser.nextIteration();
38         root->traverse(&traverser);
39         if (traverser.mFound)
40         {
41             traverser.updateTree();
42         }
43     } while (traverser.mFound);
44 }
45 
Traverser()46 Traverser::Traverser() : TIntermTraverser(true, false, false)
47 {
48 }
49 
nextIteration()50 void Traverser::nextIteration()
51 {
52     mFound = false;
53 }
54 
visitUnary(Visit visit,TIntermUnary * node)55 bool Traverser::visitUnary(Visit visit, TIntermUnary *node)
56 {
57     if (mFound)
58     {
59         return false;
60     }
61 
62     // Detect if the current operator is unary minus operator.
63     if (node->getOp() != EOpNegative)
64     {
65         return true;
66     }
67 
68     // Detect if the current operand is a float variable.
69     TIntermTyped *fValue = node->getOperand();
70     if (!fValue->getType().isScalarFloat())
71     {
72         return true;
73     }
74 
75     // 0.0 - float
76     TIntermTyped *zero = CreateZeroNode(fValue->getType());
77     zero->setLine(fValue->getLine());
78     TIntermBinary *sub = new TIntermBinary(EOpSub, zero, fValue);
79     sub->setLine(fValue->getLine());
80 
81     queueReplacement(sub, OriginalNode::IS_DROPPED);
82 
83     mFound = true;
84     return false;
85 }
86 
87 }  // anonymous namespace
88 
RewriteUnaryMinusOperatorFloat(TIntermNode * root)89 void RewriteUnaryMinusOperatorFloat(TIntermNode *root)
90 {
91     Traverser::Apply(root);
92 }
93 
94 }  // namespace sh
95