1 //
2 // Copyright 2002 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 SeparateDeclarations function processes declarations, so that in the end each declaration
7 // contains only one declarator.
8 // This is useful as an intermediate step when initialization needs to be separated from
9 // declaration, or when things need to be unfolded out of the initializer.
10 // Example:
11 // int a[1] = int[1](1), b[1] = int[1](2);
12 // gets transformed when run through this class into the AST equivalent of:
13 // int a[1] = int[1](1);
14 // int b[1] = int[1](2);
15
16 #include "compiler/translator/tree_ops/SeparateDeclarations.h"
17
18 #include "compiler/translator/SymbolTable.h"
19 #include "compiler/translator/tree_util/IntermTraverse.h"
20 #include "compiler/translator/tree_util/ReplaceVariable.h"
21
22 namespace sh
23 {
24
25 namespace
26 {
27
28 class SeparateDeclarationsTraverser : private TIntermTraverser
29 {
30 public:
31 [[nodiscard]] static bool apply(TCompiler *compiler,
32 TIntermNode *root,
33 TSymbolTable *symbolTable);
34
35 private:
36 SeparateDeclarationsTraverser(TSymbolTable *symbolTable);
37 bool visitDeclaration(Visit, TIntermDeclaration *node) override;
38 void visitSymbol(TIntermSymbol *symbol) override;
39
40 void separateDeclarator(TIntermSequence *sequence,
41 size_t index,
42 TIntermSequence *replacementDeclarations,
43 const TStructure **replacementStructure);
44
45 VariableReplacementMap mVariableMap;
46 };
47
apply(TCompiler * compiler,TIntermNode * root,TSymbolTable * symbolTable)48 bool SeparateDeclarationsTraverser::apply(TCompiler *compiler,
49 TIntermNode *root,
50 TSymbolTable *symbolTable)
51 {
52 SeparateDeclarationsTraverser separateDecl(symbolTable);
53 root->traverse(&separateDecl);
54 return separateDecl.updateTree(compiler, root);
55 }
56
SeparateDeclarationsTraverser(TSymbolTable * symbolTable)57 SeparateDeclarationsTraverser::SeparateDeclarationsTraverser(TSymbolTable *symbolTable)
58 : TIntermTraverser(true, false, false, symbolTable)
59 {}
60
visitDeclaration(Visit,TIntermDeclaration * node)61 bool SeparateDeclarationsTraverser::visitDeclaration(Visit, TIntermDeclaration *node)
62 {
63 TIntermSequence *sequence = node->getSequence();
64 if (sequence->size() <= 1)
65 {
66 return true;
67 }
68
69 TIntermBlock *parentBlock = getParentNode()->getAsBlock();
70 ASSERT(parentBlock != nullptr);
71
72 TIntermSequence replacementDeclarations;
73 const TStructure *replacementStructure = nullptr;
74 for (size_t ii = 0; ii < sequence->size(); ++ii)
75 {
76 separateDeclarator(sequence, ii, &replacementDeclarations, &replacementStructure);
77 }
78
79 mMultiReplacements.emplace_back(parentBlock, node, std::move(replacementDeclarations));
80 return false;
81 }
82
visitSymbol(TIntermSymbol * symbol)83 void SeparateDeclarationsTraverser::visitSymbol(TIntermSymbol *symbol)
84 {
85 const TVariable *variable = &symbol->variable();
86 if (mVariableMap.count(variable) > 0)
87 {
88 queueAccessChainReplacement(mVariableMap[variable]->deepCopy());
89 }
90 }
91
separateDeclarator(TIntermSequence * sequence,size_t index,TIntermSequence * replacementDeclarations,const TStructure ** replacementStructure)92 void SeparateDeclarationsTraverser::separateDeclarator(TIntermSequence *sequence,
93 size_t index,
94 TIntermSequence *replacementDeclarations,
95 const TStructure **replacementStructure)
96 {
97 TIntermTyped *declarator = sequence->at(index)->getAsTyped();
98 const TType &declaratorType = declarator->getType();
99
100 // If the declaration is not simultaneously declaring a struct, can use the same declarator.
101 // Otherwise, the first declarator is taken as-is if the struct has a name.
102 const TStructure *structure = declaratorType.getStruct();
103 const bool isStructSpecifier = declaratorType.isStructSpecifier();
104 if (!isStructSpecifier || (index == 0 && structure->symbolType() != SymbolType::Empty))
105 {
106 TIntermDeclaration *replacementDeclaration = new TIntermDeclaration;
107
108 // Make sure to update the declarator's initializers if any.
109 declarator->traverse(this);
110
111 replacementDeclaration->appendDeclarator(declarator);
112 replacementDeclaration->setLine(declarator->getLine());
113 replacementDeclarations->push_back(replacementDeclaration);
114 return;
115 }
116
117 // If the struct is nameless, split it out first.
118 if (structure->symbolType() == SymbolType::Empty)
119 {
120 if (*replacementStructure == nullptr)
121 {
122 TStructure *newStructure =
123 new TStructure(mSymbolTable, kEmptyImmutableString, &structure->fields(),
124 SymbolType::AngleInternal);
125 newStructure->setAtGlobalScope(structure->atGlobalScope());
126 *replacementStructure = structure = newStructure;
127
128 TType *namedType = new TType(structure, true);
129 namedType->setQualifier(EvqGlobal);
130
131 TVariable *structVariable =
132 new TVariable(mSymbolTable, kEmptyImmutableString, namedType, SymbolType::Empty);
133
134 TIntermDeclaration *structDeclaration = new TIntermDeclaration;
135 structDeclaration->appendDeclarator(new TIntermSymbol(structVariable));
136 structDeclaration->setLine(declarator->getLine());
137 replacementDeclarations->push_back(structDeclaration);
138 }
139 else
140 {
141 structure = *replacementStructure;
142 }
143 }
144
145 // Redeclare the declarator but not as a struct specifier.
146 TIntermSymbol *asSymbol = declarator->getAsSymbolNode();
147 TIntermTyped *initializer = nullptr;
148 if (asSymbol == nullptr)
149 {
150 TIntermBinary *asBinary = declarator->getAsBinaryNode();
151 ASSERT(asBinary->getOp() == EOpInitialize);
152 asSymbol = asBinary->getLeft()->getAsSymbolNode();
153 initializer = asBinary->getRight();
154
155 // Make sure the initializer itself has its variables replaced if necessary.
156 if (initializer->getAsSymbolNode())
157 {
158 const TVariable *initializerVariable = &initializer->getAsSymbolNode()->variable();
159 if (mVariableMap.count(initializerVariable) > 0)
160 {
161 initializer = mVariableMap[initializerVariable]->deepCopy();
162 }
163 }
164 else
165 {
166 initializer->traverse(this);
167 }
168 }
169
170 ASSERT(asSymbol && asSymbol->variable().symbolType() != SymbolType::Empty);
171
172 TType *newType = new TType(structure, false);
173 newType->setQualifier(asSymbol->getType().getQualifier());
174 newType->makeArrays(asSymbol->getType().getArraySizes());
175
176 TVariable *replacementVar = new TVariable(mSymbolTable, asSymbol->getName(), newType,
177 asSymbol->variable().symbolType());
178 TIntermSymbol *replacementSymbol = new TIntermSymbol(replacementVar);
179 TIntermTyped *replacement = replacementSymbol;
180 if (initializer)
181 {
182 replacement = new TIntermBinary(EOpInitialize, replacement, initializer);
183 }
184
185 TIntermDeclaration *replacementDeclaration = new TIntermDeclaration;
186 replacementDeclaration->appendDeclarator(replacement);
187 replacementDeclaration->setLine(declarator->getLine());
188 replacementDeclarations->push_back(replacementDeclaration);
189
190 mVariableMap[&asSymbol->variable()] = replacementSymbol;
191 }
192 } // namespace
193
SeparateDeclarations(TCompiler * compiler,TIntermNode * root,TSymbolTable * symbolTable)194 bool SeparateDeclarations(TCompiler *compiler, TIntermNode *root, TSymbolTable *symbolTable)
195 {
196 return SeparateDeclarationsTraverser::apply(compiler, root, symbolTable);
197 }
198
199 } // namespace sh
200