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/tree_util/IntermNode_util.h"
10
11#include "compiler/translator/FunctionLookup.h"
12#include "compiler/translator/SymbolTable.h"
13
14namespace sh
15{
16
17namespace
18{
19
20const 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
37TIntermFunctionPrototype *CreateInternalFunctionPrototypeNode(const TFunction &func)
38{
39 return new TIntermFunctionPrototype(&func);
40}
41
42TIntermFunctionDefinition *CreateInternalFunctionDefinitionNode(const TFunction &func,
43 TIntermBlock *functionBody)
44{
45 return new TIntermFunctionDefinition(new TIntermFunctionPrototype(&func), functionBody);
46}
47
48TIntermTyped *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 = new TIntermSequence();
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
116TIntermConstantUnion *CreateIndexNode(int index)
117{
118 TConstantUnion *u = new TConstantUnion[1];
119 u[0].setIConst(index);
120
121 TType type(EbtInt, EbpUndefined, EvqConst, 1);
122 TIntermConstantUnion *node = new TIntermConstantUnion(u, type);
123 return node;
124}
125
126TIntermConstantUnion *CreateBoolNode(bool value)
127{
128 TConstantUnion *u = new TConstantUnion[1];
129 u[0].setBConst(value);
130
131 TType type(EbtBool, EbpUndefined, EvqConst, 1);
132 TIntermConstantUnion *node = new TIntermConstantUnion(u, type);
133 return node;
134}
135
136TVariable *CreateTempVariable(TSymbolTable *symbolTable, const TType *type)
137{
138 ASSERT(symbolTable != nullptr);
139 // TODO(oetuaho): Might be useful to sanitize layout qualifier etc. on the type of the created
140 // variable. This might need to be done in other places as well.
141 return new TVariable(symbolTable, kEmptyImmutableString, type, SymbolType::AngleInternal);
142}
143
144TVariable *CreateTempVariable(TSymbolTable *symbolTable, const TType *type, TQualifier qualifier)
145{
146 ASSERT(symbolTable != nullptr);
147 if (type->getQualifier() == qualifier)
148 {
149 return CreateTempVariable(symbolTable, type);
150 }
151 TType *typeWithQualifier = new TType(*type);
152 typeWithQualifier->setQualifier(qualifier);
153 return CreateTempVariable(symbolTable, typeWithQualifier);
154}
155
156TIntermSymbol *CreateTempSymbolNode(const TVariable *tempVariable)
157{
158 ASSERT(tempVariable->symbolType() == SymbolType::AngleInternal);
159 ASSERT(tempVariable->getType().getQualifier() == EvqTemporary ||
160 tempVariable->getType().getQualifier() == EvqConst ||
161 tempVariable->getType().getQualifier() == EvqGlobal);
162 return new TIntermSymbol(tempVariable);
163}
164
165TIntermDeclaration *CreateTempDeclarationNode(const TVariable *tempVariable)
166{
167 TIntermDeclaration *tempDeclaration = new TIntermDeclaration();
168 tempDeclaration->appendDeclarator(CreateTempSymbolNode(tempVariable));
169 return tempDeclaration;
170}
171
172TIntermDeclaration *CreateTempInitDeclarationNode(const TVariable *tempVariable,
173 TIntermTyped *initializer)
174{
175 ASSERT(initializer != nullptr);
176 TIntermSymbol *tempSymbol = CreateTempSymbolNode(tempVariable);
177 TIntermDeclaration *tempDeclaration = new TIntermDeclaration();
178 TIntermBinary *tempInit = new TIntermBinary(EOpInitialize, tempSymbol, initializer);
179 tempDeclaration->appendDeclarator(tempInit);
180 return tempDeclaration;
181}
182
183TIntermBinary *CreateTempAssignmentNode(const TVariable *tempVariable, TIntermTyped *rightNode)
184{
185 ASSERT(rightNode != nullptr);
186 TIntermSymbol *tempSymbol = CreateTempSymbolNode(tempVariable);
187 return new TIntermBinary(EOpAssign, tempSymbol, rightNode);
188}
189
190TVariable *DeclareTempVariable(TSymbolTable *symbolTable,
191 const TType *type,
192 TQualifier qualifier,
193 TIntermDeclaration **declarationOut)
194{
195 TVariable *variable = CreateTempVariable(symbolTable, type, qualifier);
196 *declarationOut = CreateTempDeclarationNode(variable);
197 return variable;
198}
199
200TVariable *DeclareTempVariable(TSymbolTable *symbolTable,
201 TIntermTyped *initializer,
202 TQualifier qualifier,
203 TIntermDeclaration **declarationOut)
204{
205 TVariable *variable =
206 CreateTempVariable(symbolTable, new TType(initializer->getType()), qualifier);
207 *declarationOut = CreateTempInitDeclarationNode(variable, initializer);
208 return variable;
209}
210
211TIntermBlock *EnsureBlock(TIntermNode *node)
212{
213 if (node == nullptr)
214 return nullptr;
215 TIntermBlock *blockNode = node->getAsBlock();
216 if (blockNode != nullptr)
217 return blockNode;
218
219 blockNode = new TIntermBlock();
220 blockNode->setLine(node->getLine());
221 blockNode->appendStatement(node);
222 return blockNode;
223}
224
225TIntermSymbol *ReferenceGlobalVariable(const ImmutableString &name, const TSymbolTable &symbolTable)
226{
227 const TVariable *var = static_cast<const TVariable *>(symbolTable.findGlobal(name));
228 ASSERT(var);
229 return new TIntermSymbol(var);
230}
231
232TIntermSymbol *ReferenceBuiltInVariable(const ImmutableString &name,
233 const TSymbolTable &symbolTable,
234 int shaderVersion)
235{
236 const TVariable *var =
237 static_cast<const TVariable *>(symbolTable.findBuiltIn(name, shaderVersion));
238 ASSERT(var);
239 return new TIntermSymbol(var);
240}
241
242TIntermTyped *CreateBuiltInFunctionCallNode(const char *name,
243 TIntermSequence *arguments,
244 const TSymbolTable &symbolTable,
245 int shaderVersion)
246{
247 const TFunction *fn = LookUpBuiltInFunction(name, arguments, symbolTable, shaderVersion);
248 ASSERT(fn);
249 TOperator op = fn->getBuiltInOp();
250 if (op != EOpCallBuiltInFunction && arguments->size() == 1)
251 {
252 return new TIntermUnary(op, arguments->at(0)->getAsTyped(), fn);
253 }
254 return TIntermAggregate::CreateBuiltInFunctionCall(*fn, arguments);
255}
256
257} // namespace sh
258