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