• 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 #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