blob: 11ba6fb447499767fe4fa1ca4f213b1b54fbff68 [file] [log] [blame]
Zhenyao Mo4a667fe2014-02-11 12:35:01 -08001//
2// Copyright (c) 2002-2013 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 "compiler/translator/InitializeVariables.h"
Olli Etuahod57e0db2015-04-24 15:05:08 +03008
Zhenyao Mo72111912016-07-20 17:45:56 -07009#include "angle_gl.h"
Olli Etuahod57e0db2015-04-24 15:05:08 +030010#include "common/debug.h"
Olli Etuaho9cbc07c2017-05-10 18:22:01 +030011#include "compiler/translator/FindMain.h"
Zhenyao Mo72111912016-07-20 17:45:56 -070012#include "compiler/translator/IntermNode.h"
Zhenyao Mod7490962016-11-09 15:49:51 -080013#include "compiler/translator/SymbolTable.h"
Zhenyao Mo72111912016-07-20 17:45:56 -070014#include "compiler/translator/util.h"
Zhenyao Mo4a667fe2014-02-11 12:35:01 -080015
Jamie Madill45bcc782016-11-07 13:58:48 -050016namespace sh
17{
18
Zhenyao Mo4a667fe2014-02-11 12:35:01 -080019namespace
20{
21
Olli Etuaho9733cee2017-05-11 19:14:35 +030022bool IsNamelessStruct(const TIntermTyped *node)
23{
24 return (node->getBasicType() == EbtStruct && node->getType().getStruct()->name() == "");
25}
26
27void AddArrayZeroInitSequence(const TIntermTyped *initializedNode,
28 TIntermSequence *initSequenceOut);
29
30TIntermBinary *CreateZeroInitAssignment(const TIntermTyped *initializedNode)
31{
32 TIntermTyped *zero = TIntermTyped::CreateZero(initializedNode->getType());
33 return new TIntermBinary(EOpAssign, initializedNode->deepCopy(), zero);
34}
35
36void AddStructZeroInitSequence(const TIntermTyped *initializedNode,
37 TIntermSequence *initSequenceOut)
38{
39 ASSERT(initializedNode->getBasicType() == EbtStruct);
40 TStructure *structType = initializedNode->getType().getStruct();
41 for (int i = 0; i < static_cast<int>(structType->fields().size()); ++i)
42 {
43 TIntermBinary *element = new TIntermBinary(
44 EOpIndexDirectStruct, initializedNode->deepCopy(), TIntermTyped::CreateIndexNode(i));
45 if (element->isArray())
46 {
47 AddArrayZeroInitSequence(element, initSequenceOut);
48 }
49 else if (element->getType().isStructureContainingArrays())
50 {
51 AddStructZeroInitSequence(element, initSequenceOut);
52 }
53 else
54 {
55 // Structs can't be defined inside structs, so the type of a struct field can't be a
56 // nameless struct.
57 ASSERT(!IsNamelessStruct(element));
58 initSequenceOut->push_back(CreateZeroInitAssignment(element));
59 }
60 }
61}
62
63void AddArrayZeroInitSequence(const TIntermTyped *initializedNode, TIntermSequence *initSequenceOut)
64{
65 ASSERT(initializedNode->isArray());
66 // Assign the array elements one by one to keep the AST compatible with ESSL 1.00 which
67 // doesn't have array assignment.
68 // Note that it is important to have the array init in the right order to workaround
69 // http://crbug.com/709317
70 for (unsigned int i = 0; i < initializedNode->getArraySize(); ++i)
71 {
72 TIntermBinary *element = new TIntermBinary(EOpIndexDirect, initializedNode->deepCopy(),
73 TIntermTyped::CreateIndexNode(i));
74 if (element->getType().isStructureContainingArrays())
75 {
76 AddStructZeroInitSequence(element, initSequenceOut);
77 }
78 else
79 {
80 initSequenceOut->push_back(CreateZeroInitAssignment(element));
81 }
82 }
83}
84
85void InsertInitCode(TIntermSequence *mainBody,
Olli Etuaho9cbc07c2017-05-10 18:22:01 +030086 const InitVariableList &variables,
87 const TSymbolTable &symbolTable)
Zhenyao Mo72111912016-07-20 17:45:56 -070088{
Olli Etuaho9cbc07c2017-05-10 18:22:01 +030089 for (const auto &var : variables)
Zhenyao Mo4a667fe2014-02-11 12:35:01 -080090 {
Zhenyao Mo72111912016-07-20 17:45:56 -070091 TString name = TString(var.name.c_str());
Corentin Wallez509e4562016-08-25 14:55:44 -040092
Olli Etuaho9733cee2017-05-11 19:14:35 +030093 TIntermSymbol *initializedSymbol = nullptr;
Zhenyao Mo72111912016-07-20 17:45:56 -070094 if (var.isArray())
Zhenyao Mo4a667fe2014-02-11 12:35:01 -080095 {
Zhenyao Mo72111912016-07-20 17:45:56 -070096 size_t pos = name.find_last_of('[');
97 if (pos != TString::npos)
Corentin Wallez509e4562016-08-25 14:55:44 -040098 {
Zhenyao Mo72111912016-07-20 17:45:56 -070099 name = name.substr(0, pos);
Zhenyao Mo4a667fe2014-02-11 12:35:01 -0800100 }
Olli Etuaho9733cee2017-05-11 19:14:35 +0300101 TType arrayType = sh::GetShaderVariableBasicType(var);
Zhenyao Mod7490962016-11-09 15:49:51 -0800102 arrayType.setArraySize(var.elementCount());
Olli Etuaho9733cee2017-05-11 19:14:35 +0300103 initializedSymbol = new TIntermSymbol(0, name, arrayType);
Zhenyao Mof9312682016-07-22 12:51:31 -0700104 }
Zhenyao Mod7490962016-11-09 15:49:51 -0800105 else if (var.isStruct())
106 {
Olli Etuaho9cbc07c2017-05-10 18:22:01 +0300107 TVariable *structInfo = reinterpret_cast<TVariable *>(symbolTable.findGlobal(name));
Zhenyao Mod7490962016-11-09 15:49:51 -0800108 ASSERT(structInfo);
109
Olli Etuaho9733cee2017-05-11 19:14:35 +0300110 initializedSymbol = new TIntermSymbol(0, name, structInfo->getType());
Zhenyao Mod7490962016-11-09 15:49:51 -0800111 }
Zhenyao Mo4a667fe2014-02-11 12:35:01 -0800112 else
113 {
Olli Etuaho9733cee2017-05-11 19:14:35 +0300114 TType type = sh::GetShaderVariableBasicType(var);
115 initializedSymbol = new TIntermSymbol(0, name, type);
Corentin Wallez509e4562016-08-25 14:55:44 -0400116 }
Olli Etuaho9733cee2017-05-11 19:14:35 +0300117 TIntermSequence *initCode = CreateInitCode(initializedSymbol);
118 mainBody->insert(mainBody->begin(), initCode->begin(), initCode->end());
Zhenyao Mo4a667fe2014-02-11 12:35:01 -0800119 }
120}
121
Olli Etuaho9733cee2017-05-11 19:14:35 +0300122class InitializeLocalsTraverser : public TIntermTraverser
123{
124 public:
125 InitializeLocalsTraverser(int shaderVersion)
126 : TIntermTraverser(true, false, false), mShaderVersion(shaderVersion)
127 {
128 }
129
130 protected:
131 bool visitDeclaration(Visit visit, TIntermDeclaration *node) override
132 {
133 for (TIntermNode *declarator : *node->getSequence())
134 {
135 if (!mInGlobalScope && !declarator->getAsBinaryNode())
136 {
137 TIntermSymbol *symbol = declarator->getAsSymbolNode();
138 ASSERT(symbol);
139 if (symbol->getSymbol() == "")
140 {
141 continue;
142 }
143
144 // Arrays may need to be initialized one element at a time, since ESSL 1.00 does not
145 // support array constructors or assigning arrays.
146 bool arrayConstructorUnavailable =
147 (symbol->isArray() || symbol->getType().isStructureContainingArrays()) &&
148 mShaderVersion == 100;
149 // Nameless struct constructors can't be referred to, so they also need to be
150 // initialized one element at a time.
151 if (arrayConstructorUnavailable || IsNamelessStruct(symbol))
152 {
153 // SimplifyLoopConditions should have been run so the parent node of this node
154 // should not be a loop.
155 ASSERT(getParentNode()->getAsLoopNode() == nullptr);
156 // SeparateDeclarations should have already been run, so we don't need to worry
157 // about further declarators in this declaration depending on the effects of
158 // this declarator.
159 ASSERT(node->getSequence()->size() == 1);
160 insertStatementsInParentBlock(TIntermSequence(), *CreateInitCode(symbol));
161 }
162 else
163 {
164 TIntermBinary *init = new TIntermBinary(
165 EOpInitialize, symbol, TIntermTyped::CreateZero(symbol->getType()));
166 queueReplacementWithParent(node, symbol, init, OriginalNode::BECOMES_CHILD);
167 }
168 }
169 }
170 return false;
171 }
172
173 private:
174 int mShaderVersion;
175};
176
Zhenyao Mo72111912016-07-20 17:45:56 -0700177} // namespace anonymous
178
Olli Etuaho9733cee2017-05-11 19:14:35 +0300179TIntermSequence *CreateInitCode(const TIntermSymbol *initializedSymbol)
180{
181 TIntermSequence *initCode = new TIntermSequence();
182 if (initializedSymbol->isArray())
183 {
184 AddArrayZeroInitSequence(initializedSymbol, initCode);
185 }
186 else if (initializedSymbol->getType().isStructureContainingArrays() ||
187 IsNamelessStruct(initializedSymbol))
188 {
189 AddStructZeroInitSequence(initializedSymbol, initCode);
190 }
191 else
192 {
193 initCode->push_back(CreateZeroInitAssignment(initializedSymbol));
194 }
195 return initCode;
196}
197
198void InitializeUninitializedLocals(TIntermBlock *root, int shaderVersion)
199{
200 InitializeLocalsTraverser traverser(shaderVersion);
201 root->traverse(&traverser);
202 traverser.updateTree();
203}
204
Olli Etuaho9cbc07c2017-05-10 18:22:01 +0300205void InitializeVariables(TIntermBlock *root,
Zhenyao Mod7490962016-11-09 15:49:51 -0800206 const InitVariableList &vars,
207 const TSymbolTable &symbolTable)
Zhenyao Mo72111912016-07-20 17:45:56 -0700208{
Olli Etuaho9cbc07c2017-05-10 18:22:01 +0300209 TIntermFunctionDefinition *main = FindMain(root);
210 ASSERT(main != nullptr);
211 TIntermBlock *body = main->getBody();
212 InsertInitCode(body->getSequence(), vars, symbolTable);
Zhenyao Mo72111912016-07-20 17:45:56 -0700213}
Jamie Madill45bcc782016-11-07 13:58:48 -0500214
215} // namespace sh