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