• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 type check.
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,TPrecision precision)116 TIntermConstantUnion *CreateFloatNode(float value, TPrecision precision)
117 {
118     TConstantUnion *u = new TConstantUnion[1];
119     u[0].setFConst(value);
120 
121     TType type(EbtFloat, precision, EvqConst, 1);
122     return new TIntermConstantUnion(u, type);
123 }
124 
CreateVecNode(const float values[],unsigned int vecSize,TPrecision precision)125 TIntermConstantUnion *CreateVecNode(const float values[],
126                                     unsigned int vecSize,
127                                     TPrecision precision)
128 {
129     TConstantUnion *u = new TConstantUnion[vecSize];
130     for (unsigned int channel = 0; channel < vecSize; ++channel)
131     {
132         u[channel].setFConst(values[channel]);
133     }
134 
135     TType type(EbtFloat, precision, EvqConst, static_cast<uint8_t>(vecSize));
136     return new TIntermConstantUnion(u, type);
137 }
138 
CreateUVecNode(const unsigned int values[],unsigned int vecSize,TPrecision precision)139 TIntermConstantUnion *CreateUVecNode(const unsigned int values[],
140                                      unsigned int vecSize,
141                                      TPrecision precision)
142 {
143     TConstantUnion *u = new TConstantUnion[vecSize];
144     for (unsigned int channel = 0; channel < vecSize; ++channel)
145     {
146         u[channel].setUConst(values[channel]);
147     }
148 
149     TType type(EbtUInt, precision, EvqConst, static_cast<uint8_t>(vecSize));
150     return new TIntermConstantUnion(u, type);
151 }
152 
CreateIndexNode(int index)153 TIntermConstantUnion *CreateIndexNode(int index)
154 {
155     TConstantUnion *u = new TConstantUnion[1];
156     u[0].setIConst(index);
157 
158     TType type(EbtInt, EbpHigh, EvqConst, 1);
159     return new TIntermConstantUnion(u, type);
160 }
161 
CreateUIntNode(unsigned int value)162 TIntermConstantUnion *CreateUIntNode(unsigned int value)
163 {
164     TConstantUnion *u = new TConstantUnion[1];
165     u[0].setUConst(value);
166 
167     TType type(EbtUInt, EbpHigh, EvqConst, 1);
168     return new TIntermConstantUnion(u, type);
169 }
170 
CreateBoolNode(bool value)171 TIntermConstantUnion *CreateBoolNode(bool value)
172 {
173     TConstantUnion *u = new TConstantUnion[1];
174     u[0].setBConst(value);
175 
176     TType type(EbtBool, EbpUndefined, EvqConst, 1);
177     return new TIntermConstantUnion(u, type);
178 }
179 
CreateTempVariable(TSymbolTable * symbolTable,const TType * type)180 TVariable *CreateTempVariable(TSymbolTable *symbolTable, const TType *type)
181 {
182     ASSERT(symbolTable != nullptr);
183     // TODO(oetuaho): Might be useful to sanitize layout qualifier etc. on the type of the created
184     // variable. This might need to be done in other places as well.
185     return new TVariable(symbolTable, kEmptyImmutableString, type, SymbolType::AngleInternal);
186 }
187 
CreateTempVariable(TSymbolTable * symbolTable,const TType * type,TQualifier qualifier)188 TVariable *CreateTempVariable(TSymbolTable *symbolTable, const TType *type, TQualifier qualifier)
189 {
190     ASSERT(symbolTable != nullptr);
191     if (type->getQualifier() == qualifier)
192     {
193         return CreateTempVariable(symbolTable, type);
194     }
195     TType *typeWithQualifier = new TType(*type);
196     typeWithQualifier->setQualifier(qualifier);
197     return CreateTempVariable(symbolTable, typeWithQualifier);
198 }
199 
CreateTempSymbolNode(const TVariable * tempVariable)200 TIntermSymbol *CreateTempSymbolNode(const TVariable *tempVariable)
201 {
202     ASSERT(tempVariable->symbolType() == SymbolType::AngleInternal);
203     ASSERT(tempVariable->getType().getQualifier() == EvqTemporary ||
204            tempVariable->getType().getQualifier() == EvqConst ||
205            tempVariable->getType().getQualifier() == EvqGlobal);
206     return new TIntermSymbol(tempVariable);
207 }
208 
CreateTempDeclarationNode(const TVariable * tempVariable)209 TIntermDeclaration *CreateTempDeclarationNode(const TVariable *tempVariable)
210 {
211     TIntermDeclaration *tempDeclaration = new TIntermDeclaration();
212     tempDeclaration->appendDeclarator(CreateTempSymbolNode(tempVariable));
213     return tempDeclaration;
214 }
215 
CreateTempInitDeclarationNode(const TVariable * tempVariable,TIntermTyped * initializer)216 TIntermDeclaration *CreateTempInitDeclarationNode(const TVariable *tempVariable,
217                                                   TIntermTyped *initializer)
218 {
219     ASSERT(initializer != nullptr);
220     TIntermSymbol *tempSymbol           = CreateTempSymbolNode(tempVariable);
221     TIntermDeclaration *tempDeclaration = new TIntermDeclaration();
222     TIntermBinary *tempInit             = new TIntermBinary(EOpInitialize, tempSymbol, initializer);
223     tempDeclaration->appendDeclarator(tempInit);
224     return tempDeclaration;
225 }
226 
CreateTempAssignmentNode(const TVariable * tempVariable,TIntermTyped * rightNode)227 TIntermBinary *CreateTempAssignmentNode(const TVariable *tempVariable, TIntermTyped *rightNode)
228 {
229     ASSERT(rightNode != nullptr);
230     TIntermSymbol *tempSymbol = CreateTempSymbolNode(tempVariable);
231     return new TIntermBinary(EOpAssign, tempSymbol, rightNode);
232 }
233 
DeclareTempVariable(TSymbolTable * symbolTable,const TType * type,TQualifier qualifier,TIntermDeclaration ** declarationOut)234 TVariable *DeclareTempVariable(TSymbolTable *symbolTable,
235                                const TType *type,
236                                TQualifier qualifier,
237                                TIntermDeclaration **declarationOut)
238 {
239     TVariable *variable = CreateTempVariable(symbolTable, type, qualifier);
240     *declarationOut     = CreateTempDeclarationNode(variable);
241     return variable;
242 }
243 
DeclareTempVariable(TSymbolTable * symbolTable,TIntermTyped * initializer,TQualifier qualifier,TIntermDeclaration ** declarationOut)244 TVariable *DeclareTempVariable(TSymbolTable *symbolTable,
245                                TIntermTyped *initializer,
246                                TQualifier qualifier,
247                                TIntermDeclaration **declarationOut)
248 {
249     TVariable *variable =
250         CreateTempVariable(symbolTable, new TType(initializer->getType()), qualifier);
251     *declarationOut = CreateTempInitDeclarationNode(variable, initializer);
252     return variable;
253 }
254 
DeclareStructure(TIntermBlock * root,TSymbolTable * symbolTable,TFieldList * fieldList,TQualifier qualifier,const TMemoryQualifier & memoryQualifier,uint32_t arraySize,const ImmutableString & structTypeName,const ImmutableString * structInstanceName)255 std::pair<const TVariable *, const TVariable *> DeclareStructure(
256     TIntermBlock *root,
257     TSymbolTable *symbolTable,
258     TFieldList *fieldList,
259     TQualifier qualifier,
260     const TMemoryQualifier &memoryQualifier,
261     uint32_t arraySize,
262     const ImmutableString &structTypeName,
263     const ImmutableString *structInstanceName)
264 {
265     TStructure *structure =
266         new TStructure(symbolTable, structTypeName, fieldList, SymbolType::AngleInternal);
267 
268     auto makeStructureType = [&](bool isStructSpecifier) {
269         TType *structureType = new TType(structure, isStructSpecifier);
270         structureType->setQualifier(qualifier);
271         structureType->setMemoryQualifier(memoryQualifier);
272         if (arraySize > 0)
273         {
274             structureType->makeArray(arraySize);
275         }
276         return structureType;
277     };
278 
279     TIntermSequence insertSequence;
280 
281     TVariable *typeVar = new TVariable(symbolTable, kEmptyImmutableString, makeStructureType(true),
282                                        SymbolType::Empty);
283     insertSequence.push_back(new TIntermDeclaration{typeVar});
284 
285     TVariable *instanceVar = nullptr;
286     if (structInstanceName)
287     {
288         instanceVar = new TVariable(symbolTable, *structInstanceName, makeStructureType(false),
289                                     SymbolType::AngleInternal);
290         insertSequence.push_back(new TIntermDeclaration{instanceVar});
291     }
292 
293     size_t firstFunctionIndex = FindFirstFunctionDefinitionIndex(root);
294     root->insertChildNodes(firstFunctionIndex, insertSequence);
295 
296     return {typeVar, instanceVar};
297 }
298 
DeclareInterfaceBlock(TIntermBlock * root,TSymbolTable * symbolTable,TFieldList * fieldList,TQualifier qualifier,const TLayoutQualifier & layoutQualifier,const TMemoryQualifier & memoryQualifier,uint32_t arraySize,const ImmutableString & blockTypeName,const ImmutableString & blockVariableName)299 const TVariable *DeclareInterfaceBlock(TIntermBlock *root,
300                                        TSymbolTable *symbolTable,
301                                        TFieldList *fieldList,
302                                        TQualifier qualifier,
303                                        const TLayoutQualifier &layoutQualifier,
304                                        const TMemoryQualifier &memoryQualifier,
305                                        uint32_t arraySize,
306                                        const ImmutableString &blockTypeName,
307                                        const ImmutableString &blockVariableName)
308 {
309     // Define an interface block.
310     TInterfaceBlock *interfaceBlock = new TInterfaceBlock(
311         symbolTable, blockTypeName, fieldList, layoutQualifier, SymbolType::AngleInternal);
312 
313     // Turn the inteface block into a declaration.
314     TType *interfaceBlockType = new TType(interfaceBlock, qualifier, layoutQualifier);
315     interfaceBlockType->setMemoryQualifier(memoryQualifier);
316     if (arraySize > 0)
317     {
318         interfaceBlockType->makeArray(arraySize);
319     }
320 
321     TIntermDeclaration *interfaceBlockDecl = new TIntermDeclaration;
322     TVariable *interfaceBlockVar =
323         new TVariable(symbolTable, blockVariableName, interfaceBlockType,
324                       blockVariableName.empty() ? SymbolType::Empty : SymbolType::AngleInternal);
325     TIntermSymbol *interfaceBlockDeclarator = new TIntermSymbol(interfaceBlockVar);
326     interfaceBlockDecl->appendDeclarator(interfaceBlockDeclarator);
327 
328     // Insert the declarations before the first function.
329     TIntermSequence insertSequence;
330     insertSequence.push_back(interfaceBlockDecl);
331 
332     size_t firstFunctionIndex = FindFirstFunctionDefinitionIndex(root);
333     root->insertChildNodes(firstFunctionIndex, insertSequence);
334 
335     return interfaceBlockVar;
336 }
337 
EnsureBlock(TIntermNode * node)338 TIntermBlock *EnsureBlock(TIntermNode *node)
339 {
340     if (node == nullptr)
341         return nullptr;
342     TIntermBlock *blockNode = node->getAsBlock();
343     if (blockNode != nullptr)
344         return blockNode;
345 
346     blockNode = new TIntermBlock();
347     blockNode->setLine(node->getLine());
348     blockNode->appendStatement(node);
349     return blockNode;
350 }
351 
ReferenceGlobalVariable(const ImmutableString & name,const TSymbolTable & symbolTable)352 TIntermSymbol *ReferenceGlobalVariable(const ImmutableString &name, const TSymbolTable &symbolTable)
353 {
354     const TSymbol *symbol = symbolTable.findGlobal(name);
355     ASSERT(symbol && symbol->isVariable());
356     return new TIntermSymbol(static_cast<const TVariable *>(symbol));
357 }
358 
ReferenceBuiltInVariable(const ImmutableString & name,const TSymbolTable & symbolTable,int shaderVersion)359 TIntermSymbol *ReferenceBuiltInVariable(const ImmutableString &name,
360                                         const TSymbolTable &symbolTable,
361                                         int shaderVersion)
362 {
363     const TVariable *var =
364         static_cast<const TVariable *>(symbolTable.findBuiltIn(name, shaderVersion));
365     ASSERT(var);
366     return new TIntermSymbol(var);
367 }
368 
CreateBuiltInFunctionCallNode(const char * name,TIntermSequence * arguments,const TSymbolTable & symbolTable,int shaderVersion)369 TIntermTyped *CreateBuiltInFunctionCallNode(const char *name,
370                                             TIntermSequence *arguments,
371                                             const TSymbolTable &symbolTable,
372                                             int shaderVersion)
373 {
374     const TFunction *fn = LookUpBuiltInFunction(name, arguments, symbolTable, shaderVersion);
375     ASSERT(fn);
376     TOperator op = fn->getBuiltInOp();
377     if (BuiltInGroup::IsMath(op) && arguments->size() == 1)
378     {
379         return new TIntermUnary(op, arguments->at(0)->getAsTyped(), fn);
380     }
381     return TIntermAggregate::CreateBuiltInFunctionCall(*fn, arguments);
382 }
383 
CreateBuiltInFunctionCallNode(const char * name,const std::initializer_list<TIntermNode * > & arguments,const TSymbolTable & symbolTable,int shaderVersion)384 TIntermTyped *CreateBuiltInFunctionCallNode(const char *name,
385                                             const std::initializer_list<TIntermNode *> &arguments,
386                                             const TSymbolTable &symbolTable,
387                                             int shaderVersion)
388 {
389     TIntermSequence argSequence(arguments);
390     return CreateBuiltInFunctionCallNode(name, &argSequence, symbolTable, shaderVersion);
391 }
392 
CreateBuiltInUnaryFunctionCallNode(const char * name,TIntermTyped * argument,const TSymbolTable & symbolTable,int shaderVersion)393 TIntermTyped *CreateBuiltInUnaryFunctionCallNode(const char *name,
394                                                  TIntermTyped *argument,
395                                                  const TSymbolTable &symbolTable,
396                                                  int shaderVersion)
397 {
398     return CreateBuiltInFunctionCallNode(name, {argument}, symbolTable, shaderVersion);
399 }
400 
GetESSLOrGLSLVersion(ShShaderSpec spec,int esslVersion,int glslVersion)401 int GetESSLOrGLSLVersion(ShShaderSpec spec, int esslVersion, int glslVersion)
402 {
403     return IsDesktopGLSpec(spec) ? glslVersion : esslVersion;
404 }
405 
406 // Returns true if a block ends in a branch (break, continue, return, etc).  This is only correct
407 // after PruneNoOps, because it expects empty blocks after a branch to have been already pruned,
408 // i.e. a block can only end in a branch if its last statement is a branch or is a block ending in
409 // branch.
EndsInBranch(TIntermBlock * block)410 bool EndsInBranch(TIntermBlock *block)
411 {
412     while (block != nullptr)
413     {
414         // Get the last statement of the block.
415         TIntermSequence &statements = *block->getSequence();
416         if (statements.empty())
417         {
418             return false;
419         }
420 
421         TIntermNode *lastStatement = statements.back();
422 
423         // If it's a branch itself, we have the answer.
424         if (lastStatement->getAsBranchNode())
425         {
426             return true;
427         }
428 
429         // Otherwise, see if it's a block that ends in a branch
430         block = lastStatement->getAsBlock();
431     }
432 
433     return false;
434 }
435 
436 }  // namespace sh
437