1 //
2 // Copyright (c) 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/IntermNode_util.h"
10 
11 #include "compiler/translator/SymbolTable.h"
12 
13 namespace sh
14 {
15 
16 namespace
17 {
18 
GetInternalFunctionName(const char * name)19 TName GetInternalFunctionName(const char *name)
20 {
21     TString nameStr(name);
22     TName nameObj(nameStr);
23     nameObj.setInternal(true);
24     return nameObj;
25 }
26 
LookUpBuiltInFunction(const TString & name,const TIntermSequence * arguments,const TSymbolTable & symbolTable,int shaderVersion)27 const TFunction *LookUpBuiltInFunction(const TString &name,
28                                        const TIntermSequence *arguments,
29                                        const TSymbolTable &symbolTable,
30                                        int shaderVersion)
31 {
32     TString mangledName = TFunction::GetMangledNameFromCall(name, *arguments);
33     TSymbol *symbol     = symbolTable.findBuiltIn(mangledName, shaderVersion);
34     if (symbol)
35     {
36         ASSERT(symbol->isFunction());
37         return static_cast<const TFunction *>(symbol);
38     }
39     return nullptr;
40 }
41 
42 }  // anonymous namespace
43 
CreateInternalFunctionPrototypeNode(const TType & returnType,const char * name,const TSymbolUniqueId & functionId)44 TIntermFunctionPrototype *CreateInternalFunctionPrototypeNode(const TType &returnType,
45                                                               const char *name,
46                                                               const TSymbolUniqueId &functionId)
47 {
48     TIntermFunctionPrototype *functionNode = new TIntermFunctionPrototype(returnType, functionId);
49     functionNode->getFunctionSymbolInfo()->setNameObj(GetInternalFunctionName(name));
50     return functionNode;
51 }
52 
CreateInternalFunctionDefinitionNode(const TType & returnType,const char * name,TIntermBlock * functionBody,const TSymbolUniqueId & functionId)53 TIntermFunctionDefinition *CreateInternalFunctionDefinitionNode(const TType &returnType,
54                                                                 const char *name,
55                                                                 TIntermBlock *functionBody,
56                                                                 const TSymbolUniqueId &functionId)
57 {
58     TIntermFunctionPrototype *prototypeNode =
59         CreateInternalFunctionPrototypeNode(returnType, name, functionId);
60     return new TIntermFunctionDefinition(prototypeNode, functionBody);
61 }
62 
CreateInternalFunctionCallNode(const TType & returnType,const char * name,const TSymbolUniqueId & functionId,TIntermSequence * arguments)63 TIntermAggregate *CreateInternalFunctionCallNode(const TType &returnType,
64                                                  const char *name,
65                                                  const TSymbolUniqueId &functionId,
66                                                  TIntermSequence *arguments)
67 {
68     TIntermAggregate *functionNode = TIntermAggregate::CreateFunctionCall(
69         returnType, functionId, GetInternalFunctionName(name), arguments);
70     return functionNode;
71 }
72 
CreateZeroNode(const TType & type)73 TIntermTyped *CreateZeroNode(const TType &type)
74 {
75     TType constType(type);
76     constType.setQualifier(EvqConst);
77 
78     if (!type.isArray() && type.getBasicType() != EbtStruct)
79     {
80         size_t size       = constType.getObjectSize();
81         TConstantUnion *u = new TConstantUnion[size];
82         for (size_t i = 0; i < size; ++i)
83         {
84             switch (type.getBasicType())
85             {
86                 case EbtFloat:
87                     u[i].setFConst(0.0f);
88                     break;
89                 case EbtInt:
90                     u[i].setIConst(0);
91                     break;
92                 case EbtUInt:
93                     u[i].setUConst(0u);
94                     break;
95                 case EbtBool:
96                     u[i].setBConst(false);
97                     break;
98                 default:
99                     // CreateZeroNode is called by ParseContext that keeps parsing even when an
100                     // error occurs, so it is possible for CreateZeroNode to be called with
101                     // non-basic types. This happens only on error condition but CreateZeroNode
102                     // needs to return a value with the correct type to continue the typecheck.
103                     // That's why we handle non-basic type by setting whatever value, we just need
104                     // the type to be right.
105                     u[i].setIConst(42);
106                     break;
107             }
108         }
109 
110         TIntermConstantUnion *node = new TIntermConstantUnion(u, constType);
111         return node;
112     }
113 
114     if (type.getBasicType() == EbtVoid)
115     {
116         // Void array. This happens only on error condition, similarly to the case above. We don't
117         // have a constructor operator for void, so this needs special handling. We'll end up with a
118         // value without the array type, but that should not be a problem.
119         while (constType.isArray())
120         {
121             constType.toArrayElementType();
122         }
123         return CreateZeroNode(constType);
124     }
125 
126     TIntermSequence *arguments = new TIntermSequence();
127 
128     if (type.isArray())
129     {
130         TType elementType(type);
131         elementType.toArrayElementType();
132 
133         size_t arraySize = type.getOutermostArraySize();
134         for (size_t i = 0; i < arraySize; ++i)
135         {
136             arguments->push_back(CreateZeroNode(elementType));
137         }
138     }
139     else
140     {
141         ASSERT(type.getBasicType() == EbtStruct);
142 
143         const TStructure *structure = type.getStruct();
144         for (const auto &field : structure->fields())
145         {
146             arguments->push_back(CreateZeroNode(*field->type()));
147         }
148     }
149 
150     return TIntermAggregate::CreateConstructor(constType, arguments);
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, EbpUndefined, EvqConst, 1);
159     TIntermConstantUnion *node = new TIntermConstantUnion(u, type);
160     return node;
161 }
162 
CreateBoolNode(bool value)163 TIntermConstantUnion *CreateBoolNode(bool value)
164 {
165     TConstantUnion *u = new TConstantUnion[1];
166     u[0].setBConst(value);
167 
168     TType type(EbtBool, EbpUndefined, EvqConst, 1);
169     TIntermConstantUnion *node = new TIntermConstantUnion(u, type);
170     return node;
171 }
172 
CreateTempSymbolNode(const TSymbolUniqueId & id,const TType & type,TQualifier qualifier)173 TIntermSymbol *CreateTempSymbolNode(const TSymbolUniqueId &id,
174                                     const TType &type,
175                                     TQualifier qualifier)
176 {
177     TInfoSinkBase symbolNameOut;
178     symbolNameOut << "s" << id.get();
179     TString symbolName = symbolNameOut.c_str();
180 
181     TIntermSymbol *node = new TIntermSymbol(id, symbolName, type);
182     node->setInternal(true);
183 
184     ASSERT(qualifier == EvqTemporary || qualifier == EvqConst || qualifier == EvqGlobal);
185     node->getTypePointer()->setQualifier(qualifier);
186 
187     // TODO(oetuaho): Might be useful to sanitize layout qualifier etc. on the type of the created
188     // symbol. This might need to be done in other places as well.
189     return node;
190 }
191 
CreateTempInitDeclarationNode(const TSymbolUniqueId & id,TIntermTyped * initializer,TQualifier qualifier)192 TIntermDeclaration *CreateTempInitDeclarationNode(const TSymbolUniqueId &id,
193                                                   TIntermTyped *initializer,
194                                                   TQualifier qualifier)
195 {
196     ASSERT(initializer != nullptr);
197     TIntermSymbol *tempSymbol = CreateTempSymbolNode(id, initializer->getType(), qualifier);
198     TIntermDeclaration *tempDeclaration = new TIntermDeclaration();
199     TIntermBinary *tempInit             = new TIntermBinary(EOpInitialize, tempSymbol, initializer);
200     tempDeclaration->appendDeclarator(tempInit);
201     return tempDeclaration;
202 }
203 
EnsureBlock(TIntermNode * node)204 TIntermBlock *EnsureBlock(TIntermNode *node)
205 {
206     if (node == nullptr)
207         return nullptr;
208     TIntermBlock *blockNode = node->getAsBlock();
209     if (blockNode != nullptr)
210         return blockNode;
211 
212     blockNode = new TIntermBlock();
213     blockNode->setLine(node->getLine());
214     blockNode->appendStatement(node);
215     return blockNode;
216 }
217 
ReferenceGlobalVariable(const TString & name,const TSymbolTable & symbolTable)218 TIntermSymbol *ReferenceGlobalVariable(const TString &name, const TSymbolTable &symbolTable)
219 {
220     TVariable *var = reinterpret_cast<TVariable *>(symbolTable.findGlobal(name));
221     ASSERT(var);
222     return new TIntermSymbol(var->getUniqueId(), name, var->getType());
223 }
224 
ReferenceBuiltInVariable(const TString & name,const TSymbolTable & symbolTable,int shaderVersion)225 TIntermSymbol *ReferenceBuiltInVariable(const TString &name,
226                                         const TSymbolTable &symbolTable,
227                                         int shaderVersion)
228 {
229     const TVariable *var =
230         reinterpret_cast<const TVariable *>(symbolTable.findBuiltIn(name, shaderVersion, true));
231     ASSERT(var);
232     return new TIntermSymbol(var->getUniqueId(), name, var->getType());
233 }
234 
CreateBuiltInFunctionCallNode(const TString & name,TIntermSequence * arguments,const TSymbolTable & symbolTable,int shaderVersion)235 TIntermTyped *CreateBuiltInFunctionCallNode(const TString &name,
236                                             TIntermSequence *arguments,
237                                             const TSymbolTable &symbolTable,
238                                             int shaderVersion)
239 {
240     const TFunction *fn = LookUpBuiltInFunction(name, arguments, symbolTable, shaderVersion);
241     ASSERT(fn);
242     TOperator op = fn->getBuiltInOp();
243     if (op != EOpNull)
244     {
245         if (arguments->size() == 1)
246         {
247             return new TIntermUnary(op, arguments->at(0)->getAsTyped());
248         }
249         return TIntermAggregate::Create(fn->getReturnType(), op, arguments);
250     }
251     return TIntermAggregate::CreateBuiltInFunctionCall(*fn, arguments);
252 }
253 
254 }  // namespace sh
255