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 #include "compiler/translator/tree_ops/SeparateDeclarations.h"
7
8 #include <unordered_map>
9 #include "compiler/translator/SymbolTable.h"
10
11 #include "compiler/translator/IntermRebuild.h"
12 #include "compiler/translator/util.h"
13
14 namespace sh
15 {
16 namespace
17 {
18
19 class Separator final : private TIntermRebuild
20 {
21 public:
Separator(TCompiler & compiler)22 Separator(TCompiler &compiler) : TIntermRebuild(compiler, true, true) {}
23 using TIntermRebuild::rebuildRoot;
24
25 private:
recordModifiedStructVariables(TIntermDeclaration & node)26 void recordModifiedStructVariables(TIntermDeclaration &node)
27 {
28 ASSERT(!mNewStructure); // No nested struct declarations.
29 TIntermSequence &sequence = *node.getSequence();
30 if (sequence.size() <= 1)
31 {
32 return;
33 }
34 TIntermTyped *declarator = sequence.at(0)->getAsTyped();
35 const TType &declaratorType = declarator->getType();
36 const TStructure *structure = declaratorType.getStruct();
37 // Rewrite variable declarations that specify structs AND multiple variables at the same
38 // time. Only one variable can specify the struct and rest must be rewritten with new
39 // type.
40 if (!structure || !declaratorType.isStructSpecifier())
41 {
42 return;
43 }
44 // Struct specifier changes for all variables except the first one.
45 uint32_t index = 1;
46 if (structure->symbolType() == SymbolType::Empty)
47 {
48
49 TStructure *newStructure =
50 new TStructure(&mSymbolTable, kEmptyImmutableString, &structure->fields(),
51 SymbolType::AngleInternal);
52 newStructure->setAtGlobalScope(structure->atGlobalScope());
53 structure = newStructure;
54 mNewStructure = newStructure;
55 // Adding name causes the struct type to change, so all variables need rewriting.
56 index = 0;
57 }
58 for (; index < sequence.size(); ++index)
59 {
60 Declaration decl = ViewDeclaration(node, index);
61 const TVariable &var = decl.symbol.variable();
62 const TType &varType = var.getType();
63 const bool newTypeIsSpecifier = index == 0;
64 TType *newType = new TType(structure, newTypeIsSpecifier);
65 newType->setQualifier(varType.getQualifier());
66 newType->makeArrays(varType.getArraySizes());
67 TVariable *newVar = new TVariable(&mSymbolTable, var.name(), newType, var.symbolType());
68 mStructVariables.insert(std::make_pair(&var, newVar));
69 }
70 }
71
visitDeclarationPre(TIntermDeclaration & node)72 PreResult visitDeclarationPre(TIntermDeclaration &node) override
73 {
74 recordModifiedStructVariables(node);
75 return node;
76 }
77
visitDeclarationPost(TIntermDeclaration & node)78 PostResult visitDeclarationPost(TIntermDeclaration &node) override
79 {
80 TIntermSequence &sequence = *node.getSequence();
81 if (sequence.size() <= 1)
82 {
83 return node;
84 }
85 std::vector<TIntermNode *> replacements;
86 uint32_t index = 0;
87 if (mNewStructure)
88 {
89 TType *namedType = new TType(mNewStructure, true);
90 namedType->setQualifier(EvqGlobal);
91 TIntermDeclaration *replacement = new TIntermDeclaration;
92 replacement->appendDeclarator(sequence.at(0)->getAsTyped());
93 replacement->setLine(node.getLine());
94 replacements.push_back(replacement);
95 mNewStructure = nullptr;
96 index = 1;
97 }
98 for (; index < sequence.size(); ++index)
99 {
100 TIntermDeclaration *replacement = new TIntermDeclaration;
101 TIntermTyped *declarator = sequence.at(index)->getAsTyped();
102 replacement->appendDeclarator(declarator);
103 replacement->setLine(declarator->getLine());
104 replacements.push_back(replacement);
105 }
106 return PostResult::Multi(std::move(replacements));
107 }
108
visitSymbolPre(TIntermSymbol & symbolNode)109 PreResult visitSymbolPre(TIntermSymbol &symbolNode) override
110 {
111 auto it = mStructVariables.find(&symbolNode.variable());
112 if (it == mStructVariables.end())
113 {
114 return symbolNode;
115 }
116 return *new TIntermSymbol(it->second);
117 }
118
119 const TStructure *mNewStructure = nullptr;
120 // Old struct variable to new struct variable mapping.
121 std::unordered_map<const TVariable *, TVariable *> mStructVariables;
122 };
123
124 } // namespace
125
SeparateDeclarations(TCompiler & compiler,TIntermBlock & root)126 bool SeparateDeclarations(TCompiler &compiler, TIntermBlock &root)
127 {
128 Separator separator(compiler);
129 return separator.rebuildRoot(root);
130 }
131
132 } // namespace sh
133