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