1 //
2 // Copyright 2018 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 // SeparateStructFromUniformDeclarations: Separate struct declarations from uniform declarations.
7 //
8 
9 #include "compiler/translator/tree_ops/SeparateStructFromUniformDeclarations.h"
10 #include "compiler/translator/SymbolTable.h"
11 #include "compiler/translator/tree_util/IntermTraverse.h"
12 #include "compiler/translator/tree_util/ReplaceVariable.h"
13 
14 namespace sh
15 {
16 namespace
17 {
18 // This traverser translates embedded uniform structs into a specifier and declaration.
19 // This makes the declarations easier to move into uniform blocks.
20 class Traverser : public TIntermTraverser
21 {
22   public:
Traverser(TSymbolTable * symbolTable)23     explicit Traverser(TSymbolTable *symbolTable)
24         : TIntermTraverser(true, false, false, symbolTable)
25     {}
26 
visitDeclaration(Visit visit,TIntermDeclaration * decl)27     bool visitDeclaration(Visit visit, TIntermDeclaration *decl) override
28     {
29         ASSERT(visit == PreVisit);
30 
31         if (!mInGlobalScope)
32         {
33             return true;
34         }
35 
36         const TIntermSequence &sequence = *(decl->getSequence());
37         ASSERT(sequence.size() == 1);
38         TIntermTyped *declarator = sequence.front()->getAsTyped();
39         const TType &type        = declarator->getType();
40 
41         if (type.isStructSpecifier() && type.getQualifier() == EvqUniform)
42         {
43             doReplacement(decl, declarator, type);
44             return false;
45         }
46 
47         return true;
48     }
49 
visitSymbol(TIntermSymbol * symbol)50     void visitSymbol(TIntermSymbol *symbol) override
51     {
52         const TVariable *variable = &symbol->variable();
53         if (mVariableMap.count(variable) > 0)
54         {
55             queueAccessChainReplacement(mVariableMap[variable]->deepCopy());
56         }
57     }
58 
59   private:
doReplacement(TIntermDeclaration * decl,TIntermTyped * declarator,const TType & oldType)60     void doReplacement(TIntermDeclaration *decl, TIntermTyped *declarator, const TType &oldType)
61     {
62         const TStructure *structure = oldType.getStruct();
63         if (structure->symbolType() == SymbolType::Empty)
64         {
65             // Handle nameless structs: uniform struct { ... } variable;
66             structure = new TStructure(mSymbolTable, kEmptyImmutableString, &structure->fields(),
67                                        SymbolType::AngleInternal);
68         }
69         TType *namedType = new TType(structure, true);
70         namedType->setQualifier(EvqGlobal);
71 
72         TVariable *structVariable =
73             new TVariable(mSymbolTable, kEmptyImmutableString, namedType, SymbolType::Empty);
74         TIntermSymbol *structDeclarator       = new TIntermSymbol(structVariable);
75         TIntermDeclaration *structDeclaration = new TIntermDeclaration;
76         structDeclaration->appendDeclarator(structDeclarator);
77 
78         TIntermSequence newSequence;
79         newSequence.push_back(structDeclaration);
80 
81         // Redeclare the uniform with the (potentially) new struct type
82         TIntermSymbol *asSymbol = declarator->getAsSymbolNode();
83         ASSERT(asSymbol && asSymbol->variable().symbolType() != SymbolType::Empty);
84 
85         TIntermDeclaration *namedDecl = new TIntermDeclaration;
86         TType *uniformType            = new TType(structure, false);
87         uniformType->setQualifier(EvqUniform);
88         uniformType->makeArrays(oldType.getArraySizes());
89 
90         TVariable *newVar        = new TVariable(mSymbolTable, asSymbol->getName(), uniformType,
91                                           asSymbol->variable().symbolType());
92         TIntermSymbol *newSymbol = new TIntermSymbol(newVar);
93         namedDecl->appendDeclarator(newSymbol);
94 
95         newSequence.push_back(namedDecl);
96 
97         mVariableMap[&asSymbol->variable()] = newSymbol;
98 
99         mMultiReplacements.emplace_back(getParentNode()->getAsBlock(), decl,
100                                         std::move(newSequence));
101     }
102 
103     VariableReplacementMap mVariableMap;
104 };
105 }  // anonymous namespace
106 
SeparateStructFromUniformDeclarations(TCompiler * compiler,TIntermBlock * root,TSymbolTable * symbolTable)107 bool SeparateStructFromUniformDeclarations(TCompiler *compiler,
108                                            TIntermBlock *root,
109                                            TSymbolTable *symbolTable)
110 {
111     Traverser separateStructDecls(symbolTable);
112     root->traverse(&separateStructDecls);
113     return separateStructDecls.updateTree(compiler, root);
114 }
115 }  // namespace sh
116