• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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