1 | // |
2 | // Copyright (c) 2018 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 | // RewriteRepeatedAssignToSwizzled.cpp: Rewrite expressions that assign an assignment to a swizzled |
7 | // vector, like: |
8 | // v.x = z = expression; |
9 | // to: |
10 | // z = expression; |
11 | // v.x = z; |
12 | // |
13 | // Note that this doesn't handle some corner cases: expressions nested inside other expressions, |
14 | // inside loop headers, or inside if conditions. |
15 | |
16 | #include "compiler/translator/tree_ops/RewriteRepeatedAssignToSwizzled.h" |
17 | |
18 | #include "compiler/translator/tree_util/IntermNode_util.h" |
19 | #include "compiler/translator/tree_util/IntermTraverse.h" |
20 | |
21 | namespace sh |
22 | { |
23 | |
24 | namespace |
25 | { |
26 | |
27 | class RewriteAssignToSwizzledTraverser : public TIntermTraverser |
28 | { |
29 | public: |
30 | static void rewrite(TIntermBlock *root); |
31 | |
32 | private: |
33 | RewriteAssignToSwizzledTraverser(); |
34 | |
35 | bool visitBinary(Visit, TIntermBinary *node) override; |
36 | |
37 | void nextIteration(); |
38 | |
39 | bool didRewrite() { return mDidRewrite; } |
40 | |
41 | bool mDidRewrite; |
42 | }; |
43 | |
44 | // static |
45 | void RewriteAssignToSwizzledTraverser::rewrite(TIntermBlock *root) |
46 | { |
47 | RewriteAssignToSwizzledTraverser rewrite; |
48 | do |
49 | { |
50 | rewrite.nextIteration(); |
51 | root->traverse(&rewrite); |
52 | rewrite.updateTree(); |
53 | } while (rewrite.didRewrite()); |
54 | } |
55 | |
56 | RewriteAssignToSwizzledTraverser::RewriteAssignToSwizzledTraverser() |
57 | : TIntermTraverser(true, false, false), mDidRewrite(false) |
58 | {} |
59 | |
60 | void RewriteAssignToSwizzledTraverser::nextIteration() |
61 | { |
62 | mDidRewrite = false; |
63 | } |
64 | |
65 | bool RewriteAssignToSwizzledTraverser::visitBinary(Visit, TIntermBinary *node) |
66 | { |
67 | TIntermBinary *rightBinary = node->getRight()->getAsBinaryNode(); |
68 | TIntermBlock *parentBlock = getParentNode()->getAsBlock(); |
69 | if (parentBlock && node->isAssignment() && node->getLeft()->getAsSwizzleNode() && rightBinary && |
70 | rightBinary->isAssignment()) |
71 | { |
72 | TIntermSequence replacements; |
73 | replacements.push_back(rightBinary); |
74 | TIntermTyped *rightAssignmentTargetCopy = rightBinary->getLeft()->deepCopy(); |
75 | TIntermBinary *lastAssign = |
76 | new TIntermBinary(EOpAssign, node->getLeft(), rightAssignmentTargetCopy); |
77 | replacements.push_back(lastAssign); |
78 | mMultiReplacements.push_back(NodeReplaceWithMultipleEntry(parentBlock, node, replacements)); |
79 | mDidRewrite = true; |
80 | return false; |
81 | } |
82 | return true; |
83 | } |
84 | |
85 | } // anonymous namespace |
86 | |
87 | void RewriteRepeatedAssignToSwizzled(TIntermBlock *root) |
88 | { |
89 | RewriteAssignToSwizzledTraverser::rewrite(root); |
90 | } |
91 | |
92 | } // namespace sh |
93 | |