blob: de9050cd80a0d9a60cb95a7fafefa3534e560ee8 [file] [log] [blame]
Olli Etuaho822fa842015-04-16 14:26:10 +03001//
2// Copyright (c) 2002-2015 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// The SeparateArrayInitialization function splits each array initialization into a declaration and an assignment.
7// Example:
8// type[n] a = initializer;
9// will effectively become
10// type[n] a;
11// a = initializer;
Olli Etuahob1edc4f2015-11-02 17:20:03 +020012//
Olli Etuaho18b9deb2015-11-05 12:14:50 +020013// Note that if the array is declared as const, the initialization may still be split, making the
14// AST technically invalid. Because of that this transformation should only be used when subsequent
15// stages don't care about const qualifiers. However, the initialization will not be split if the
16// initializer can be written as a HLSL literal.
Olli Etuaho822fa842015-04-16 14:26:10 +030017
18#include "compiler/translator/SeparateArrayInitialization.h"
19
20#include "compiler/translator/IntermNode.h"
Olli Etuaho18b9deb2015-11-05 12:14:50 +020021#include "compiler/translator/OutputHLSL.h"
Olli Etuaho822fa842015-04-16 14:26:10 +030022
23namespace
24{
25
26class SeparateArrayInitTraverser : private TIntermTraverser
27{
28 public:
29 static void apply(TIntermNode *root);
30 private:
31 SeparateArrayInitTraverser();
32 bool visitAggregate(Visit, TIntermAggregate *node) override;
33};
34
35void SeparateArrayInitTraverser::apply(TIntermNode *root)
36{
37 SeparateArrayInitTraverser separateInit;
38 root->traverse(&separateInit);
39 separateInit.updateTree();
40}
41
42SeparateArrayInitTraverser::SeparateArrayInitTraverser()
43 : TIntermTraverser(true, false, false)
44{
45}
46
47bool SeparateArrayInitTraverser::visitAggregate(Visit, TIntermAggregate *node)
48{
49 if (node->getOp() == EOpDeclaration)
50 {
51 TIntermSequence *sequence = node->getSequence();
52 TIntermBinary *initNode = sequence->back()->getAsBinaryNode();
53 if (initNode != nullptr && initNode->getOp() == EOpInitialize)
54 {
55 TIntermTyped *initializer = initNode->getRight();
Olli Etuaho18b9deb2015-11-05 12:14:50 +020056 if (initializer->isArray() && !sh::OutputHLSL::canWriteAsHLSLLiteral(initializer))
Olli Etuaho822fa842015-04-16 14:26:10 +030057 {
58 // We rely on that array declarations have been isolated to single declarations.
59 ASSERT(sequence->size() == 1);
60 TIntermTyped *symbol = initNode->getLeft();
61 TIntermAggregate *parentAgg = getParentNode()->getAsAggregate();
62 ASSERT(parentAgg != nullptr);
63
64 TIntermSequence replacements;
65
66 TIntermAggregate *replacementDeclaration = new TIntermAggregate;
67 replacementDeclaration->setOp(EOpDeclaration);
68 replacementDeclaration->getSequence()->push_back(symbol);
69 replacementDeclaration->setLine(symbol->getLine());
70 replacements.push_back(replacementDeclaration);
71
72 TIntermBinary *replacementAssignment = new TIntermBinary(EOpAssign);
73 replacementAssignment->setLeft(symbol);
74 replacementAssignment->setRight(initializer);
75 replacementAssignment->setType(initializer->getType());
76 replacementAssignment->setLine(symbol->getLine());
77 replacements.push_back(replacementAssignment);
78
79 mMultiReplacements.push_back(NodeReplaceWithMultipleEntry(parentAgg, node, replacements));
80 }
81 }
82 return false;
83 }
84 return true;
85}
86
87} // namespace
88
89void SeparateArrayInitialization(TIntermNode *root)
90{
91 SeparateArrayInitTraverser::apply(root);
92}