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 // Implementation of evaluating unary integer variable bug workaround.
7 // See header for more info.
8 
9 #include "compiler/translator/RewriteUnaryMinusOperatorInt.h"
10 
11 #include "compiler/translator/IntermTraverse.h"
12 
13 namespace sh
14 {
15 
16 namespace
17 {
18 
19 class Traverser : public TIntermTraverser
20 {
21   public:
22     static void Apply(TIntermNode *root);
23 
24   private:
25     Traverser();
26     bool visitUnary(Visit visit, TIntermUnary *node) override;
27     void nextIteration();
28 
29     bool mFound = false;
30 };
31 
32 // static
Apply(TIntermNode * root)33 void Traverser::Apply(TIntermNode *root)
34 {
35     Traverser traverser;
36     do
37     {
38         traverser.nextIteration();
39         root->traverse(&traverser);
40         if (traverser.mFound)
41         {
42             traverser.updateTree();
43         }
44     } while (traverser.mFound);
45 }
46 
Traverser()47 Traverser::Traverser() : TIntermTraverser(true, false, false)
48 {
49 }
50 
nextIteration()51 void Traverser::nextIteration()
52 {
53     mFound = false;
54 }
55 
visitUnary(Visit visit,TIntermUnary * node)56 bool Traverser::visitUnary(Visit visit, TIntermUnary *node)
57 {
58     if (mFound)
59     {
60         return false;
61     }
62 
63     // Decide if the current unary operator is unary minus.
64     if (node->getOp() != EOpNegative)
65     {
66         return true;
67     }
68 
69     // Decide if the current operand is an integer variable.
70     TIntermTyped *opr = node->getOperand();
71     if (!opr->getType().isScalarInt())
72     {
73         return true;
74     }
75 
76     // Potential problem case detected, apply workaround: -(int) -> ~(int) + 1.
77     // ~(int)
78     TIntermUnary *bitwiseNot = new TIntermUnary(EOpBitwiseNot, opr);
79     bitwiseNot->setLine(opr->getLine());
80 
81     // Constant 1 (or 1u)
82     TConstantUnion *one = new TConstantUnion();
83     if (opr->getType().getBasicType() == EbtInt)
84     {
85         one->setIConst(1);
86     }
87     else
88     {
89         one->setUConst(1u);
90     }
91     TIntermConstantUnion *oneNode = new TIntermConstantUnion(one, opr->getType());
92     oneNode->getTypePointer()->setQualifier(EvqConst);
93     oneNode->setLine(opr->getLine());
94 
95     // ~(int) + 1
96     TIntermBinary *add = new TIntermBinary(EOpAdd, bitwiseNot, oneNode);
97     add->setLine(opr->getLine());
98 
99     queueReplacement(add, OriginalNode::IS_DROPPED);
100 
101     mFound = true;
102     return false;
103 }
104 
105 }  // anonymous namespace
106 
RewriteUnaryMinusOperatorInt(TIntermNode * root)107 void RewriteUnaryMinusOperatorInt(TIntermNode *root)
108 {
109     Traverser::Apply(root);
110 }
111 
112 }  // namespace sh