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