1 //
2 // Copyright 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 ANGLE_NO_DISCARD static bool rewrite(TCompiler *compiler, TIntermBlock *root);
31
32 private:
33 RewriteAssignToSwizzledTraverser();
34
35 bool visitBinary(Visit, TIntermBinary *node) override;
36
37 void nextIteration();
38
didRewrite()39 bool didRewrite() { return mDidRewrite; }
40
41 bool mDidRewrite;
42 };
43
44 // static
rewrite(TCompiler * compiler,TIntermBlock * root)45 bool RewriteAssignToSwizzledTraverser::rewrite(TCompiler *compiler, TIntermBlock *root)
46 {
47 RewriteAssignToSwizzledTraverser rewrite;
48 do
49 {
50 rewrite.nextIteration();
51 root->traverse(&rewrite);
52 if (!rewrite.updateTree(compiler, root))
53 {
54 return false;
55 }
56 } while (rewrite.didRewrite());
57
58 return true;
59 }
60
RewriteAssignToSwizzledTraverser()61 RewriteAssignToSwizzledTraverser::RewriteAssignToSwizzledTraverser()
62 : TIntermTraverser(true, false, false), mDidRewrite(false)
63 {}
64
nextIteration()65 void RewriteAssignToSwizzledTraverser::nextIteration()
66 {
67 mDidRewrite = false;
68 }
69
visitBinary(Visit,TIntermBinary * node)70 bool RewriteAssignToSwizzledTraverser::visitBinary(Visit, TIntermBinary *node)
71 {
72 TIntermBinary *rightBinary = node->getRight()->getAsBinaryNode();
73 TIntermBlock *parentBlock = getParentNode()->getAsBlock();
74 if (parentBlock && node->isAssignment() && node->getLeft()->getAsSwizzleNode() && rightBinary &&
75 rightBinary->isAssignment())
76 {
77 TIntermSequence replacements;
78 replacements.push_back(rightBinary);
79 TIntermTyped *rightAssignmentTargetCopy = rightBinary->getLeft()->deepCopy();
80 TIntermBinary *lastAssign =
81 new TIntermBinary(EOpAssign, node->getLeft(), rightAssignmentTargetCopy);
82 replacements.push_back(lastAssign);
83 mMultiReplacements.push_back(NodeReplaceWithMultipleEntry(parentBlock, node, replacements));
84 mDidRewrite = true;
85 return false;
86 }
87 return true;
88 }
89
90 } // anonymous namespace
91
RewriteRepeatedAssignToSwizzled(TCompiler * compiler,TIntermBlock * root)92 bool RewriteRepeatedAssignToSwizzled(TCompiler *compiler, TIntermBlock *root)
93 {
94 return RewriteAssignToSwizzledTraverser::rewrite(compiler, root);
95 }
96
97 } // namespace sh
98