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