• 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     // Make sure as a constructor, the type does not inherit qualifiers that are otherwise specified
54     // on interface blocks and varyings.
55     constType.setInvariant(false);
56     constType.setPrecise(false);
57     constType.setInterpolant(false);
58     constType.setMemoryQualifier(TMemoryQualifier::Create());
59     constType.setLayoutQualifier(TLayoutQualifier::Create());
60     constType.setInterfaceBlock(nullptr);
61 
62     if (!type.isArray() && type.getBasicType() != EbtStruct)
63     {
64         size_t size       = constType.getObjectSize();
65         TConstantUnion *u = new TConstantUnion[size];
66         for (size_t i = 0; i < size; ++i)
67         {
68             switch (type.getBasicType())
69             {
70                 case EbtFloat:
71                     u[i].setFConst(0.0f);
72                     break;
73                 case EbtInt:
74                     u[i].setIConst(0);
75                     break;
76                 case EbtUInt:
77                     u[i].setUConst(0u);
78                     break;
79                 case EbtBool:
80                     u[i].setBConst(false);
81                     break;
82                 default:
83                     // CreateZeroNode is called by ParseContext that keeps parsing even when an
84                     // error occurs, so it is possible for CreateZeroNode to be called with
85                     // non-basic types. This happens only on error condition but CreateZeroNode
86                     // needs to return a value with the correct type to continue the type check.
87                     // That's why we handle non-basic type by setting whatever value, we just need
88                     // the type to be right.
89                     u[i].setIConst(42);
90                     break;
91             }
92         }
93 
94         TIntermConstantUnion *node = new TIntermConstantUnion(u, constType);
95         return node;
96     }
97 
98     TIntermSequence arguments;
99 
100     if (type.isArray())
101     {
102         TType elementType(type);
103         elementType.toArrayElementType();
104 
105         size_t arraySize = type.getOutermostArraySize();
106         for (size_t i = 0; i < arraySize; ++i)
107         {
108             arguments.push_back(CreateZeroNode(elementType));
109         }
110     }
111     else
112     {
113         ASSERT(type.getBasicType() == EbtStruct);
114 
115         const TStructure *structure = type.getStruct();
116         for (const auto &field : structure->fields())
117         {
118             arguments.push_back(CreateZeroNode(*field->type()));
119         }
120     }
121 
122     return TIntermAggregate::CreateConstructor(constType, &arguments);
123 }
124 
CreateFloatNode(float value,TPrecision precision)125 TIntermConstantUnion *CreateFloatNode(float value, TPrecision precision)
126 {
127     TConstantUnion *u = new TConstantUnion[1];
128     u[0].setFConst(value);
129 
130     TType type(EbtFloat, precision, EvqConst, 1);
131     return new TIntermConstantUnion(u, type);
132 }
133 
CreateVecNode(const float values[],unsigned int vecSize,TPrecision precision)134 TIntermConstantUnion *CreateVecNode(const float values[],
135                                     unsigned int vecSize,
136                                     TPrecision precision)
137 {
138     TConstantUnion *u = new TConstantUnion[vecSize];
139     for (unsigned int channel = 0; channel < vecSize; ++channel)
140     {
141         u[channel].setFConst(values[channel]);
142     }
143 
144     TType type(EbtFloat, precision, EvqConst, static_cast<uint8_t>(vecSize));
145     return new TIntermConstantUnion(u, type);
146 }
147 
CreateUVecNode(const unsigned int values[],unsigned int vecSize,TPrecision precision)148 TIntermConstantUnion *CreateUVecNode(const unsigned int values[],
149                                      unsigned int vecSize,
150                                      TPrecision precision)
151 {
152     TConstantUnion *u = new TConstantUnion[vecSize];
153     for (unsigned int channel = 0; channel < vecSize; ++channel)
154     {
155         u[channel].setUConst(values[channel]);
156     }
157 
158     TType type(EbtUInt, precision, EvqConst, static_cast<uint8_t>(vecSize));
159     return new TIntermConstantUnion(u, type);
160 }
161 
CreateIndexNode(int index)162 TIntermConstantUnion *CreateIndexNode(int index)
163 {
164     TConstantUnion *u = new TConstantUnion[1];
165     u[0].setIConst(index);
166 
167     TType type(EbtInt, EbpHigh, EvqConst, 1);
168     return new TIntermConstantUnion(u, type);
169 }
170 
CreateUIntNode(unsigned int value)171 TIntermConstantUnion *CreateUIntNode(unsigned int value)
172 {
173     TConstantUnion *u = new TConstantUnion[1];
174     u[0].setUConst(value);
175 
176     TType type(EbtUInt, EbpHigh, EvqConst, 1);
177     return new TIntermConstantUnion(u, type);
178 }
179 
CreateBoolNode(bool value)180 TIntermConstantUnion *CreateBoolNode(bool value)
181 {
182     TConstantUnion *u = new TConstantUnion[1];
183     u[0].setBConst(value);
184 
185     TType type(EbtBool, EbpUndefined, EvqConst, 1);
186     return new TIntermConstantUnion(u, type);
187 }
188 
CreateTempVariable(TSymbolTable * symbolTable,const TType * type)189 TVariable *CreateTempVariable(TSymbolTable *symbolTable, const TType *type)
190 {
191     ASSERT(symbolTable != nullptr);
192     // TODO(oetuaho): Might be useful to sanitize layout qualifier etc. on the type of the created
193     // variable. This might need to be done in other places as well.
194     return new TVariable(symbolTable, kEmptyImmutableString, type, SymbolType::AngleInternal);
195 }
196 
CreateTempVariable(TSymbolTable * symbolTable,const TType * type,TQualifier qualifier)197 TVariable *CreateTempVariable(TSymbolTable *symbolTable, const TType *type, TQualifier qualifier)
198 {
199     ASSERT(symbolTable != nullptr);
200     if (type->getQualifier() == qualifier)
201     {
202         return CreateTempVariable(symbolTable, type);
203     }
204     TType *typeWithQualifier = new TType(*type);
205     typeWithQualifier->setQualifier(qualifier);
206     return CreateTempVariable(symbolTable, typeWithQualifier);
207 }
208 
CreateTempSymbolNode(const TVariable * tempVariable)209 TIntermSymbol *CreateTempSymbolNode(const TVariable *tempVariable)
210 {
211     ASSERT(tempVariable->symbolType() == SymbolType::AngleInternal);
212     ASSERT(tempVariable->getType().getQualifier() == EvqTemporary ||
213            tempVariable->getType().getQualifier() == EvqConst ||
214            tempVariable->getType().getQualifier() == EvqGlobal);
215     return new TIntermSymbol(tempVariable);
216 }
217 
CreateTempDeclarationNode(const TVariable * tempVariable)218 TIntermDeclaration *CreateTempDeclarationNode(const TVariable *tempVariable)
219 {
220     TIntermDeclaration *tempDeclaration = new TIntermDeclaration();
221     tempDeclaration->appendDeclarator(CreateTempSymbolNode(tempVariable));
222     return tempDeclaration;
223 }
224 
CreateTempInitDeclarationNode(const TVariable * tempVariable,TIntermTyped * initializer)225 TIntermDeclaration *CreateTempInitDeclarationNode(const TVariable *tempVariable,
226                                                   TIntermTyped *initializer)
227 {
228     ASSERT(initializer != nullptr);
229     TIntermSymbol *tempSymbol           = CreateTempSymbolNode(tempVariable);
230     TIntermDeclaration *tempDeclaration = new TIntermDeclaration();
231     TIntermBinary *tempInit             = new TIntermBinary(EOpInitialize, tempSymbol, initializer);
232     tempDeclaration->appendDeclarator(tempInit);
233     return tempDeclaration;
234 }
235 
CreateTempAssignmentNode(const TVariable * tempVariable,TIntermTyped * rightNode)236 TIntermBinary *CreateTempAssignmentNode(const TVariable *tempVariable, TIntermTyped *rightNode)
237 {
238     ASSERT(rightNode != nullptr);
239     TIntermSymbol *tempSymbol = CreateTempSymbolNode(tempVariable);
240     return new TIntermBinary(EOpAssign, tempSymbol, rightNode);
241 }
242 
DeclareTempVariable(TSymbolTable * symbolTable,const TType * type,TQualifier qualifier,TIntermDeclaration ** declarationOut)243 TVariable *DeclareTempVariable(TSymbolTable *symbolTable,
244                                const TType *type,
245                                TQualifier qualifier,
246                                TIntermDeclaration **declarationOut)
247 {
248     TVariable *variable = CreateTempVariable(symbolTable, type, qualifier);
249     *declarationOut     = CreateTempDeclarationNode(variable);
250     return variable;
251 }
252 
DeclareTempVariable(TSymbolTable * symbolTable,TIntermTyped * initializer,TQualifier qualifier,TIntermDeclaration ** declarationOut)253 TVariable *DeclareTempVariable(TSymbolTable *symbolTable,
254                                TIntermTyped *initializer,
255                                TQualifier qualifier,
256                                TIntermDeclaration **declarationOut)
257 {
258     TVariable *variable =
259         CreateTempVariable(symbolTable, new TType(initializer->getType()), qualifier);
260     *declarationOut = CreateTempInitDeclarationNode(variable, initializer);
261     return variable;
262 }
263 
DeclareStructure(TIntermBlock * root,TSymbolTable * symbolTable,TFieldList * fieldList,TQualifier qualifier,const TMemoryQualifier & memoryQualifier,uint32_t arraySize,const ImmutableString & structTypeName,const ImmutableString * structInstanceName)264 std::pair<const TVariable *, const TVariable *> DeclareStructure(
265     TIntermBlock *root,
266     TSymbolTable *symbolTable,
267     TFieldList *fieldList,
268     TQualifier qualifier,
269     const TMemoryQualifier &memoryQualifier,
270     uint32_t arraySize,
271     const ImmutableString &structTypeName,
272     const ImmutableString *structInstanceName)
273 {
274     TStructure *structure =
275         new TStructure(symbolTable, structTypeName, fieldList, SymbolType::AngleInternal);
276 
277     auto makeStructureType = [&](bool isStructSpecifier) {
278         TType *structureType = new TType(structure, isStructSpecifier);
279         structureType->setQualifier(qualifier);
280         structureType->setMemoryQualifier(memoryQualifier);
281         if (arraySize > 0)
282         {
283             structureType->makeArray(arraySize);
284         }
285         return structureType;
286     };
287 
288     TIntermSequence insertSequence;
289 
290     TVariable *typeVar = new TVariable(symbolTable, kEmptyImmutableString, makeStructureType(true),
291                                        SymbolType::Empty);
292     insertSequence.push_back(new TIntermDeclaration{typeVar});
293 
294     TVariable *instanceVar = nullptr;
295     if (structInstanceName)
296     {
297         instanceVar = new TVariable(symbolTable, *structInstanceName, makeStructureType(false),
298                                     SymbolType::AngleInternal);
299         insertSequence.push_back(new TIntermDeclaration{instanceVar});
300     }
301 
302     size_t firstFunctionIndex = FindFirstFunctionDefinitionIndex(root);
303     root->insertChildNodes(firstFunctionIndex, insertSequence);
304 
305     return {typeVar, instanceVar};
306 }
307 
DeclareInterfaceBlock(TIntermBlock * root,TSymbolTable * symbolTable,TFieldList * fieldList,TQualifier qualifier,const TLayoutQualifier & layoutQualifier,const TMemoryQualifier & memoryQualifier,uint32_t arraySize,const ImmutableString & blockTypeName,const ImmutableString & blockVariableName)308 const TVariable *DeclareInterfaceBlock(TIntermBlock *root,
309                                        TSymbolTable *symbolTable,
310                                        TFieldList *fieldList,
311                                        TQualifier qualifier,
312                                        const TLayoutQualifier &layoutQualifier,
313                                        const TMemoryQualifier &memoryQualifier,
314                                        uint32_t arraySize,
315                                        const ImmutableString &blockTypeName,
316                                        const ImmutableString &blockVariableName)
317 {
318     // Define an interface block.
319     TInterfaceBlock *interfaceBlock = new TInterfaceBlock(
320         symbolTable, blockTypeName, fieldList, layoutQualifier, SymbolType::AngleInternal);
321 
322     // Turn the inteface block into a declaration.
323     TType *interfaceBlockType = new TType(interfaceBlock, qualifier, layoutQualifier);
324     interfaceBlockType->setMemoryQualifier(memoryQualifier);
325     if (arraySize > 0)
326     {
327         interfaceBlockType->makeArray(arraySize);
328     }
329 
330     TIntermDeclaration *interfaceBlockDecl = new TIntermDeclaration;
331     TVariable *interfaceBlockVar =
332         new TVariable(symbolTable, blockVariableName, interfaceBlockType,
333                       blockVariableName.empty() ? SymbolType::Empty : SymbolType::AngleInternal);
334     TIntermSymbol *interfaceBlockDeclarator = new TIntermSymbol(interfaceBlockVar);
335     interfaceBlockDecl->appendDeclarator(interfaceBlockDeclarator);
336 
337     // Insert the declarations before the first function.
338     TIntermSequence insertSequence;
339     insertSequence.push_back(interfaceBlockDecl);
340 
341     size_t firstFunctionIndex = FindFirstFunctionDefinitionIndex(root);
342     root->insertChildNodes(firstFunctionIndex, insertSequence);
343 
344     return interfaceBlockVar;
345 }
346 
EnsureBlock(TIntermNode * node)347 TIntermBlock *EnsureBlock(TIntermNode *node)
348 {
349     if (node == nullptr)
350         return nullptr;
351     TIntermBlock *blockNode = node->getAsBlock();
352     if (blockNode != nullptr)
353     {
354         return blockNode;
355     }
356     blockNode = new TIntermBlock();
357     blockNode->setLine(node->getLine());
358     blockNode->appendStatement(node);
359     return blockNode;
360 }
361 
EnsureLoopBodyBlock(TIntermNode * node)362 TIntermBlock *EnsureLoopBodyBlock(TIntermNode *node)
363 {
364     if (node == nullptr)
365     {
366         return new TIntermBlock();
367     }
368     return EnsureBlock(node);
369 }
370 
ReferenceGlobalVariable(const ImmutableString & name,const TSymbolTable & symbolTable)371 TIntermSymbol *ReferenceGlobalVariable(const ImmutableString &name, const TSymbolTable &symbolTable)
372 {
373     const TSymbol *symbol = symbolTable.findGlobal(name);
374     ASSERT(symbol && symbol->isVariable());
375     return new TIntermSymbol(static_cast<const TVariable *>(symbol));
376 }
377 
ReferenceBuiltInVariable(const ImmutableString & name,const TSymbolTable & symbolTable,int shaderVersion)378 TIntermSymbol *ReferenceBuiltInVariable(const ImmutableString &name,
379                                         const TSymbolTable &symbolTable,
380                                         int shaderVersion)
381 {
382     const TVariable *var =
383         static_cast<const TVariable *>(symbolTable.findBuiltIn(name, shaderVersion));
384     ASSERT(var);
385     return new TIntermSymbol(var);
386 }
387 
CreateBuiltInFunctionCallNode(const char * name,TIntermSequence * arguments,const TSymbolTable & symbolTable,int shaderVersion)388 TIntermTyped *CreateBuiltInFunctionCallNode(const char *name,
389                                             TIntermSequence *arguments,
390                                             const TSymbolTable &symbolTable,
391                                             int shaderVersion)
392 {
393     const TFunction *fn = LookUpBuiltInFunction(name, arguments, symbolTable, shaderVersion);
394     ASSERT(fn);
395     TOperator op = fn->getBuiltInOp();
396     if (BuiltInGroup::IsMath(op) && arguments->size() == 1)
397     {
398         return new TIntermUnary(op, arguments->at(0)->getAsTyped(), fn);
399     }
400     return TIntermAggregate::CreateBuiltInFunctionCall(*fn, arguments);
401 }
402 
CreateBuiltInFunctionCallNode(const char * name,const std::initializer_list<TIntermNode * > & arguments,const TSymbolTable & symbolTable,int shaderVersion)403 TIntermTyped *CreateBuiltInFunctionCallNode(const char *name,
404                                             const std::initializer_list<TIntermNode *> &arguments,
405                                             const TSymbolTable &symbolTable,
406                                             int shaderVersion)
407 {
408     TIntermSequence argSequence(arguments);
409     return CreateBuiltInFunctionCallNode(name, &argSequence, symbolTable, shaderVersion);
410 }
411 
CreateBuiltInUnaryFunctionCallNode(const char * name,TIntermTyped * argument,const TSymbolTable & symbolTable,int shaderVersion)412 TIntermTyped *CreateBuiltInUnaryFunctionCallNode(const char *name,
413                                                  TIntermTyped *argument,
414                                                  const TSymbolTable &symbolTable,
415                                                  int shaderVersion)
416 {
417     return CreateBuiltInFunctionCallNode(name, {argument}, symbolTable, shaderVersion);
418 }
419 
GetESSLOrGLSLVersion(ShShaderSpec spec,int esslVersion,int glslVersion)420 int GetESSLOrGLSLVersion(ShShaderSpec spec, int esslVersion, int glslVersion)
421 {
422     return IsDesktopGLSpec(spec) ? glslVersion : esslVersion;
423 }
424 
425 // Returns true if a block ends in a branch (break, continue, return, etc).  This is only correct
426 // after PruneNoOps, because it expects empty blocks after a branch to have been already pruned,
427 // i.e. a block can only end in a branch if its last statement is a branch or is a block ending in
428 // branch.
EndsInBranch(TIntermBlock * block)429 bool EndsInBranch(TIntermBlock *block)
430 {
431     while (block != nullptr)
432     {
433         // Get the last statement of the block.
434         TIntermSequence &statements = *block->getSequence();
435         if (statements.empty())
436         {
437             return false;
438         }
439 
440         TIntermNode *lastStatement = statements.back();
441 
442         // If it's a branch itself, we have the answer.
443         if (lastStatement->getAsBranchNode())
444         {
445             return true;
446         }
447 
448         // Otherwise, see if it's a block that ends in a branch
449         block = lastStatement->getAsBlock();
450     }
451 
452     return false;
453 }
454 
455 }  // namespace sh
456