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