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 // SeparateArrayConstructorStatements splits statements that are array constructors and drops all of
7 // their constant arguments. For example, a statement like:
8 //   int[2](0, i++);
9 // Will be changed to:
10 //   i++;
11 
12 #include "compiler/translator/tree_ops/hlsl/SeparateArrayConstructorStatements.h"
13 
14 #include "compiler/translator/tree_util/IntermTraverse.h"
15 
16 namespace sh
17 {
18 
19 namespace
20 {
21 
SplitConstructorArgs(const TIntermSequence & originalArgs,TIntermSequence * argsOut)22 void SplitConstructorArgs(const TIntermSequence &originalArgs, TIntermSequence *argsOut)
23 {
24     for (TIntermNode *arg : originalArgs)
25     {
26         TIntermTyped *argTyped = arg->getAsTyped();
27         if (argTyped->hasSideEffects())
28         {
29             TIntermAggregate *argAggregate = argTyped->getAsAggregate();
30             if (argTyped->isArray() && argAggregate && argAggregate->isConstructor())
31             {
32                 SplitConstructorArgs(*argAggregate->getSequence(), argsOut);
33             }
34             else
35             {
36                 argsOut->push_back(argTyped);
37             }
38         }
39     }
40 }
41 
42 class SeparateArrayConstructorStatementsTraverser : public TIntermTraverser
43 {
44   public:
45     SeparateArrayConstructorStatementsTraverser();
46 
47     bool visitAggregate(Visit visit, TIntermAggregate *node) override;
48 };
49 
SeparateArrayConstructorStatementsTraverser()50 SeparateArrayConstructorStatementsTraverser::SeparateArrayConstructorStatementsTraverser()
51     : TIntermTraverser(true, false, false)
52 {}
53 
visitAggregate(Visit visit,TIntermAggregate * node)54 bool SeparateArrayConstructorStatementsTraverser::visitAggregate(Visit visit,
55                                                                  TIntermAggregate *node)
56 {
57     TIntermBlock *parentAsBlock = getParentNode()->getAsBlock();
58     if (!parentAsBlock)
59     {
60         return false;
61     }
62     if (!node->isArray() || !node->isConstructor())
63     {
64         return false;
65     }
66 
67     TIntermSequence constructorArgs;
68     SplitConstructorArgs(*node->getSequence(), &constructorArgs);
69     mMultiReplacements.emplace_back(parentAsBlock, node, std::move(constructorArgs));
70 
71     return false;
72 }
73 
74 }  // namespace
75 
SeparateArrayConstructorStatements(TCompiler * compiler,TIntermBlock * root)76 bool SeparateArrayConstructorStatements(TCompiler *compiler, TIntermBlock *root)
77 {
78     SeparateArrayConstructorStatementsTraverser traverser;
79     root->traverse(&traverser);
80     return traverser.updateTree(compiler, root);
81 }
82 
83 }  // namespace sh
84