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