1 //
2 // Copyright 2017 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 // IntermNode_util.cpp: High-level utilities for creating AST nodes and node hierarchies. Mostly
7 // meant to be used in AST transforms.
8
9 #include "compiler/translator/tree_util/IntermNode_util.h"
10
11 #include "compiler/translator/FunctionLookup.h"
12 #include "compiler/translator/SymbolTable.h"
13
14 namespace sh
15 {
16
17 namespace
18 {
19
LookUpBuiltInFunction(const char * name,const TIntermSequence * arguments,const TSymbolTable & symbolTable,int shaderVersion)20 const TFunction *LookUpBuiltInFunction(const char *name,
21 const TIntermSequence *arguments,
22 const TSymbolTable &symbolTable,
23 int shaderVersion)
24 {
25 const ImmutableString &mangledName = TFunctionLookup::GetMangledName(name, *arguments);
26 const TSymbol *symbol = symbolTable.findBuiltIn(mangledName, shaderVersion);
27 if (symbol)
28 {
29 ASSERT(symbol->isFunction());
30 return static_cast<const TFunction *>(symbol);
31 }
32 return nullptr;
33 }
34
35 } // anonymous namespace
36
CreateInternalFunctionPrototypeNode(const TFunction & func)37 TIntermFunctionPrototype *CreateInternalFunctionPrototypeNode(const TFunction &func)
38 {
39 return new TIntermFunctionPrototype(&func);
40 }
41
CreateInternalFunctionDefinitionNode(const TFunction & func,TIntermBlock * functionBody)42 TIntermFunctionDefinition *CreateInternalFunctionDefinitionNode(const TFunction &func,
43 TIntermBlock *functionBody)
44 {
45 return new TIntermFunctionDefinition(new TIntermFunctionPrototype(&func), functionBody);
46 }
47
CreateZeroNode(const TType & type)48 TIntermTyped *CreateZeroNode(const TType &type)
49 {
50 TType constType(type);
51 constType.setQualifier(EvqConst);
52
53 if (!type.isArray() && type.getBasicType() != EbtStruct)
54 {
55 size_t size = constType.getObjectSize();
56 TConstantUnion *u = new TConstantUnion[size];
57 for (size_t i = 0; i < size; ++i)
58 {
59 switch (type.getBasicType())
60 {
61 case EbtFloat:
62 u[i].setFConst(0.0f);
63 break;
64 case EbtInt:
65 u[i].setIConst(0);
66 break;
67 case EbtUInt:
68 u[i].setUConst(0u);
69 break;
70 case EbtBool:
71 u[i].setBConst(false);
72 break;
73 default:
74 // CreateZeroNode is called by ParseContext that keeps parsing even when an
75 // error occurs, so it is possible for CreateZeroNode to be called with
76 // non-basic types. This happens only on error condition but CreateZeroNode
77 // needs to return a value with the correct type to continue the typecheck.
78 // That's why we handle non-basic type by setting whatever value, we just need
79 // the type to be right.
80 u[i].setIConst(42);
81 break;
82 }
83 }
84
85 TIntermConstantUnion *node = new TIntermConstantUnion(u, constType);
86 return node;
87 }
88
89 TIntermSequence arguments;
90
91 if (type.isArray())
92 {
93 TType elementType(type);
94 elementType.toArrayElementType();
95
96 size_t arraySize = type.getOutermostArraySize();
97 for (size_t i = 0; i < arraySize; ++i)
98 {
99 arguments.push_back(CreateZeroNode(elementType));
100 }
101 }
102 else
103 {
104 ASSERT(type.getBasicType() == EbtStruct);
105
106 const TStructure *structure = type.getStruct();
107 for (const auto &field : structure->fields())
108 {
109 arguments.push_back(CreateZeroNode(*field->type()));
110 }
111 }
112
113 return TIntermAggregate::CreateConstructor(constType, &arguments);
114 }
115
CreateFloatNode(float value)116 TIntermConstantUnion *CreateFloatNode(float value)
117 {
118 TConstantUnion *u = new TConstantUnion[1];
119 u[0].setFConst(value);
120
121 TType type(EbtFloat, EbpUndefined, EvqConst, 1);
122 return new TIntermConstantUnion(u, type);
123 }
124
CreateIndexNode(int index)125 TIntermConstantUnion *CreateIndexNode(int index)
126 {
127 TConstantUnion *u = new TConstantUnion[1];
128 u[0].setIConst(index);
129
130 TType type(EbtInt, EbpUndefined, EvqConst, 1);
131 return new TIntermConstantUnion(u, type);
132 }
133
CreateUIntNode(unsigned int value)134 TIntermConstantUnion *CreateUIntNode(unsigned int value)
135 {
136 TConstantUnion *u = new TConstantUnion[1];
137 u[0].setUConst(value);
138
139 TType type(EbtUInt, EbpUndefined, EvqConst, 1);
140 return new TIntermConstantUnion(u, type);
141 }
142
CreateBoolNode(bool value)143 TIntermConstantUnion *CreateBoolNode(bool value)
144 {
145 TConstantUnion *u = new TConstantUnion[1];
146 u[0].setBConst(value);
147
148 TType type(EbtBool, EbpUndefined, EvqConst, 1);
149 return new TIntermConstantUnion(u, type);
150 }
151
CreateTempVariable(TSymbolTable * symbolTable,const TType * type)152 TVariable *CreateTempVariable(TSymbolTable *symbolTable, const TType *type)
153 {
154 ASSERT(symbolTable != nullptr);
155 // TODO(oetuaho): Might be useful to sanitize layout qualifier etc. on the type of the created
156 // variable. This might need to be done in other places as well.
157 return new TVariable(symbolTable, kEmptyImmutableString, type, SymbolType::AngleInternal);
158 }
159
CreateTempVariable(TSymbolTable * symbolTable,const TType * type,TQualifier qualifier)160 TVariable *CreateTempVariable(TSymbolTable *symbolTable, const TType *type, TQualifier qualifier)
161 {
162 ASSERT(symbolTable != nullptr);
163 if (type->getQualifier() == qualifier)
164 {
165 return CreateTempVariable(symbolTable, type);
166 }
167 TType *typeWithQualifier = new TType(*type);
168 typeWithQualifier->setQualifier(qualifier);
169 return CreateTempVariable(symbolTable, typeWithQualifier);
170 }
171
CreateTempSymbolNode(const TVariable * tempVariable)172 TIntermSymbol *CreateTempSymbolNode(const TVariable *tempVariable)
173 {
174 ASSERT(tempVariable->symbolType() == SymbolType::AngleInternal);
175 ASSERT(tempVariable->getType().getQualifier() == EvqTemporary ||
176 tempVariable->getType().getQualifier() == EvqConst ||
177 tempVariable->getType().getQualifier() == EvqGlobal);
178 return new TIntermSymbol(tempVariable);
179 }
180
CreateTempDeclarationNode(const TVariable * tempVariable)181 TIntermDeclaration *CreateTempDeclarationNode(const TVariable *tempVariable)
182 {
183 TIntermDeclaration *tempDeclaration = new TIntermDeclaration();
184 tempDeclaration->appendDeclarator(CreateTempSymbolNode(tempVariable));
185 return tempDeclaration;
186 }
187
CreateTempInitDeclarationNode(const TVariable * tempVariable,TIntermTyped * initializer)188 TIntermDeclaration *CreateTempInitDeclarationNode(const TVariable *tempVariable,
189 TIntermTyped *initializer)
190 {
191 ASSERT(initializer != nullptr);
192 TIntermSymbol *tempSymbol = CreateTempSymbolNode(tempVariable);
193 TIntermDeclaration *tempDeclaration = new TIntermDeclaration();
194 TIntermBinary *tempInit = new TIntermBinary(EOpInitialize, tempSymbol, initializer);
195 tempDeclaration->appendDeclarator(tempInit);
196 return tempDeclaration;
197 }
198
CreateTempAssignmentNode(const TVariable * tempVariable,TIntermTyped * rightNode)199 TIntermBinary *CreateTempAssignmentNode(const TVariable *tempVariable, TIntermTyped *rightNode)
200 {
201 ASSERT(rightNode != nullptr);
202 TIntermSymbol *tempSymbol = CreateTempSymbolNode(tempVariable);
203 return new TIntermBinary(EOpAssign, tempSymbol, rightNode);
204 }
205
DeclareTempVariable(TSymbolTable * symbolTable,const TType * type,TQualifier qualifier,TIntermDeclaration ** declarationOut)206 TVariable *DeclareTempVariable(TSymbolTable *symbolTable,
207 const TType *type,
208 TQualifier qualifier,
209 TIntermDeclaration **declarationOut)
210 {
211 TVariable *variable = CreateTempVariable(symbolTable, type, qualifier);
212 *declarationOut = CreateTempDeclarationNode(variable);
213 return variable;
214 }
215
DeclareTempVariable(TSymbolTable * symbolTable,TIntermTyped * initializer,TQualifier qualifier,TIntermDeclaration ** declarationOut)216 TVariable *DeclareTempVariable(TSymbolTable *symbolTable,
217 TIntermTyped *initializer,
218 TQualifier qualifier,
219 TIntermDeclaration **declarationOut)
220 {
221 TVariable *variable =
222 CreateTempVariable(symbolTable, new TType(initializer->getType()), qualifier);
223 *declarationOut = CreateTempInitDeclarationNode(variable, initializer);
224 return variable;
225 }
226
DeclareStructure(TIntermBlock * root,TSymbolTable * symbolTable,TFieldList * fieldList,TQualifier qualifier,const TMemoryQualifier & memoryQualifier,uint32_t arraySize,const ImmutableString & structTypeName,const ImmutableString * structInstanceName)227 std::pair<const TVariable *, const TVariable *> DeclareStructure(
228 TIntermBlock *root,
229 TSymbolTable *symbolTable,
230 TFieldList *fieldList,
231 TQualifier qualifier,
232 const TMemoryQualifier &memoryQualifier,
233 uint32_t arraySize,
234 const ImmutableString &structTypeName,
235 const ImmutableString *structInstanceName)
236 {
237 TStructure *structure =
238 new TStructure(symbolTable, structTypeName, fieldList, SymbolType::AngleInternal);
239
240 auto makeStructureType = [&](bool isStructSpecifier) {
241 TType *structureType = new TType(structure, isStructSpecifier);
242 structureType->setQualifier(qualifier);
243 structureType->setMemoryQualifier(memoryQualifier);
244 if (arraySize > 0)
245 {
246 structureType->makeArray(arraySize);
247 }
248 return structureType;
249 };
250
251 TIntermSequence insertSequence;
252
253 TVariable *typeVar = new TVariable(symbolTable, kEmptyImmutableString, makeStructureType(true),
254 SymbolType::Empty);
255 insertSequence.push_back(new TIntermDeclaration{typeVar});
256
257 TVariable *instanceVar = nullptr;
258 if (structInstanceName)
259 {
260 instanceVar = new TVariable(symbolTable, *structInstanceName, makeStructureType(false),
261 SymbolType::AngleInternal);
262 insertSequence.push_back(new TIntermDeclaration{instanceVar});
263 }
264
265 size_t firstFunctionIndex = FindFirstFunctionDefinitionIndex(root);
266 root->insertChildNodes(firstFunctionIndex, insertSequence);
267
268 return {typeVar, instanceVar};
269 }
270
DeclareInterfaceBlock(TIntermBlock * root,TSymbolTable * symbolTable,TFieldList * fieldList,TQualifier qualifier,const TLayoutQualifier & layoutQualifier,const TMemoryQualifier & memoryQualifier,uint32_t arraySize,const ImmutableString & blockTypeName,const ImmutableString & blockVariableName)271 const TVariable *DeclareInterfaceBlock(TIntermBlock *root,
272 TSymbolTable *symbolTable,
273 TFieldList *fieldList,
274 TQualifier qualifier,
275 const TLayoutQualifier &layoutQualifier,
276 const TMemoryQualifier &memoryQualifier,
277 uint32_t arraySize,
278 const ImmutableString &blockTypeName,
279 const ImmutableString &blockVariableName)
280 {
281 // Define an interface block.
282 TInterfaceBlock *interfaceBlock = new TInterfaceBlock(
283 symbolTable, blockTypeName, fieldList, layoutQualifier, SymbolType::AngleInternal);
284
285 // Turn the inteface block into a declaration.
286 TType *interfaceBlockType = new TType(interfaceBlock, qualifier, layoutQualifier);
287 interfaceBlockType->setMemoryQualifier(memoryQualifier);
288 if (arraySize > 0)
289 {
290 interfaceBlockType->makeArray(arraySize);
291 }
292
293 TIntermDeclaration *interfaceBlockDecl = new TIntermDeclaration;
294 TVariable *interfaceBlockVar =
295 new TVariable(symbolTable, blockVariableName, interfaceBlockType,
296 blockVariableName.empty() ? SymbolType::Empty : SymbolType::AngleInternal);
297 TIntermSymbol *interfaceBlockDeclarator = new TIntermSymbol(interfaceBlockVar);
298 interfaceBlockDecl->appendDeclarator(interfaceBlockDeclarator);
299
300 // Insert the declarations before the first function.
301 TIntermSequence insertSequence;
302 insertSequence.push_back(interfaceBlockDecl);
303
304 size_t firstFunctionIndex = FindFirstFunctionDefinitionIndex(root);
305 root->insertChildNodes(firstFunctionIndex, insertSequence);
306
307 return interfaceBlockVar;
308 }
309
EnsureBlock(TIntermNode * node)310 TIntermBlock *EnsureBlock(TIntermNode *node)
311 {
312 if (node == nullptr)
313 return nullptr;
314 TIntermBlock *blockNode = node->getAsBlock();
315 if (blockNode != nullptr)
316 return blockNode;
317
318 blockNode = new TIntermBlock();
319 blockNode->setLine(node->getLine());
320 blockNode->appendStatement(node);
321 return blockNode;
322 }
323
ReferenceGlobalVariable(const ImmutableString & name,const TSymbolTable & symbolTable)324 TIntermSymbol *ReferenceGlobalVariable(const ImmutableString &name, const TSymbolTable &symbolTable)
325 {
326 const TVariable *var = static_cast<const TVariable *>(symbolTable.findGlobal(name));
327 ASSERT(var);
328 return new TIntermSymbol(var);
329 }
330
ReferenceBuiltInVariable(const ImmutableString & name,const TSymbolTable & symbolTable,int shaderVersion)331 TIntermSymbol *ReferenceBuiltInVariable(const ImmutableString &name,
332 const TSymbolTable &symbolTable,
333 int shaderVersion)
334 {
335 const TVariable *var =
336 static_cast<const TVariable *>(symbolTable.findBuiltIn(name, shaderVersion));
337 ASSERT(var);
338 return new TIntermSymbol(var);
339 }
340
CreateBuiltInFunctionCallNode(const char * name,TIntermSequence * arguments,const TSymbolTable & symbolTable,int shaderVersion)341 TIntermTyped *CreateBuiltInFunctionCallNode(const char *name,
342 TIntermSequence *arguments,
343 const TSymbolTable &symbolTable,
344 int shaderVersion)
345 {
346 const TFunction *fn = LookUpBuiltInFunction(name, arguments, symbolTable, shaderVersion);
347 ASSERT(fn);
348 TOperator op = fn->getBuiltInOp();
349 if (BuiltInGroup::IsMath(op) && arguments->size() == 1)
350 {
351 return new TIntermUnary(op, arguments->at(0)->getAsTyped(), fn);
352 }
353 return TIntermAggregate::CreateBuiltInFunctionCall(*fn, arguments);
354 }
355
CreateBuiltInUnaryFunctionCallNode(const char * name,TIntermTyped * argument,const TSymbolTable & symbolTable,int shaderVersion)356 TIntermTyped *CreateBuiltInUnaryFunctionCallNode(const char *name,
357 TIntermTyped *argument,
358 const TSymbolTable &symbolTable,
359 int shaderVersion)
360 {
361 TIntermSequence seq = {argument};
362 return CreateBuiltInFunctionCallNode(name, &seq, symbolTable, shaderVersion);
363 }
364
365 } // namespace sh
366