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