1 //
2 // Copyright 2020 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
7 #include <algorithm>
8
9 #include "compiler/translator/msl/AstHelpers.h"
10 #include "compiler/translator/tree_ops/SeparateDeclarations.h"
11 #include "compiler/translator/tree_ops/msl/SeparateCompoundStructDeclarations.h"
12 #include "compiler/translator/tree_util/IntermTraverse.h"
13
14 using namespace sh;
15
16 ////////////////////////////////////////////////////////////////////////////////
17
18 namespace
19 {
20
21 class Separator : public TIntermTraverser
22 {
23 public:
24 std::unordered_map<int, TIntermSymbol *> replacementMap;
Separator(TSymbolTable & symbolTable,IdGen & idGen)25 Separator(TSymbolTable &symbolTable, IdGen &idGen)
26 : TIntermTraverser(false, false, true, &symbolTable), mIdGen(idGen)
27 {}
28 IdGen &mIdGen;
visitDeclaration(Visit,TIntermDeclaration * declNode)29 bool visitDeclaration(Visit, TIntermDeclaration *declNode) override
30 {
31 ASSERT(declNode->getChildCount() == 1);
32 Declaration declaration = ViewDeclaration(*declNode);
33
34 const TVariable &var = declaration.symbol.variable();
35 const TType &type = var.getType();
36 const SymbolType symbolType = var.symbolType();
37 if (type.isStructSpecifier() && symbolType != SymbolType::Empty)
38 {
39 const TStructure *structure = type.getStruct();
40 TVariable *structVar = nullptr;
41 TType *instanceType = nullptr;
42 // Name unnamed inline structs
43 if (structure->symbolType() == SymbolType::Empty)
44 {
45 const TStructure *structDefn =
46 new TStructure(mSymbolTable, mIdGen.createNewName().rawName(),
47 &structure->fields(), SymbolType::AngleInternal);
48 structVar = new TVariable(mSymbolTable, ImmutableString(""),
49 new TType(structDefn, true), SymbolType::Empty);
50 instanceType = new TType(structDefn, false);
51 }
52 else
53 {
54 structVar = new TVariable(mSymbolTable, ImmutableString(""),
55 new TType(structure, true), SymbolType::Empty);
56 instanceType = new TType(structure, false);
57 }
58 if (type.isArray())
59 {
60 instanceType->makeArrays(type.getArraySizes());
61 }
62 instanceType->setQualifier(type.getQualifier());
63 auto *instanceVar =
64 new TVariable(mSymbolTable, var.name(), instanceType, symbolType, var.extensions());
65
66 TIntermSequence replacements;
67 replacements.push_back(new TIntermDeclaration({structVar}));
68
69 TIntermSymbol *instanceSymbol = new TIntermSymbol(instanceVar);
70 TIntermDeclaration *instanceDecl = new TIntermDeclaration;
71 if (declaration.initExpr)
72 {
73 instanceDecl->appendDeclarator(new TIntermBinary(
74 TOperator::EOpInitialize, instanceSymbol, declaration.initExpr));
75 }
76 else
77 {
78 instanceDecl->appendDeclarator(instanceSymbol);
79 }
80 replacements.push_back(instanceDecl);
81
82 replacementMap[declaration.symbol.uniqueId().get()] = instanceSymbol;
83 ASSERT(getParentNode() != nullptr);
84 ASSERT(getParentNode()->getAsBlock() != nullptr);
85 mMultiReplacements.push_back(NodeReplaceWithMultipleEntry(
86 getParentNode()->getAsBlock(), declNode, std::move(replacements)));
87 }
88
89 return false;
90 }
91
visitSymbol(TIntermSymbol * decl)92 void visitSymbol(TIntermSymbol *decl) override
93 {
94 auto symbol = replacementMap.find(decl->uniqueId().get());
95 if (symbol != replacementMap.end())
96 {
97 queueReplacement(symbol->second->deepCopy(), OriginalNode::IS_DROPPED);
98 }
99 }
100 };
101
102 } // anonymous namespace
103
104 ////////////////////////////////////////////////////////////////////////////////
105
SeparateCompoundStructDeclarations(TCompiler & compiler,IdGen & idGen,TIntermBlock & root,TSymbolTable * symbolTable)106 bool sh::SeparateCompoundStructDeclarations(TCompiler &compiler,
107 IdGen &idGen,
108 TIntermBlock &root,
109 TSymbolTable *symbolTable)
110 {
111 Separator separator(compiler.getSymbolTable(), idGen);
112 root.traverse(&separator);
113 if (!separator.updateTree(&compiler, &root))
114 {
115 return false;
116 }
117
118 if (!SeparateDeclarations(&compiler, &root, symbolTable))
119 {
120 return false;
121 }
122
123 return true;
124 }
125