xref: /aosp_15_r20/external/angle/src/compiler/translator/tree_ops/hlsl/RewriteUnaryMinusOperatorInt.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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/hlsl/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     [[nodiscard]] 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     TType *oneType = new TType(opr->getType());
95     oneType->setQualifier(EvqConst);
96 
97     TIntermConstantUnion *oneNode = new TIntermConstantUnion(one, *oneType);
98     oneNode->setLine(opr->getLine());
99 
100     // ~(int) + 1
101     TIntermBinary *add = new TIntermBinary(EOpAdd, bitwiseNot, oneNode);
102     add->setLine(opr->getLine());
103 
104     queueReplacement(add, OriginalNode::IS_DROPPED);
105 
106     mFound = true;
107     return false;
108 }
109 
110 }  // anonymous namespace
111 
RewriteUnaryMinusOperatorInt(TCompiler * compiler,TIntermNode * root)112 bool RewriteUnaryMinusOperatorInt(TCompiler *compiler, TIntermNode *root)
113 {
114     return Traverser::Apply(compiler, root);
115 }
116 
117 }  // namespace sh
118