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
21namespace sh
22{
23
24namespace
25{
26
27class 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
45void 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
56RewriteAssignToSwizzledTraverser::RewriteAssignToSwizzledTraverser()
57 : TIntermTraverser(true, false, false), mDidRewrite(false)
58{}
59
60void RewriteAssignToSwizzledTraverser::nextIteration()
61{
62 mDidRewrite = false;
63}
64
65bool 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
87void RewriteRepeatedAssignToSwizzled(TIntermBlock *root)
88{
89 RewriteAssignToSwizzledTraverser::rewrite(root);
90}
91
92} // namespace sh
93