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 | |
14 | namespace sh |
15 | { |
16 | |
17 | namespace |
18 | { |
19 | |
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 | |
37 | TIntermFunctionPrototype *CreateInternalFunctionPrototypeNode(const TFunction &func) |
38 | { |
39 | return new TIntermFunctionPrototype(&func); |
40 | } |
41 | |
42 | TIntermFunctionDefinition *CreateInternalFunctionDefinitionNode(const TFunction &func, |
43 | TIntermBlock *functionBody) |
44 | { |
45 | return new TIntermFunctionDefinition(new TIntermFunctionPrototype(&func), functionBody); |
46 | } |
47 | |
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 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 | |
116 | TIntermConstantUnion *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 | |
126 | TIntermConstantUnion *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 | |
136 | TVariable *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 | |
144 | TVariable *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 | |
156 | TIntermSymbol *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 | |
165 | TIntermDeclaration *CreateTempDeclarationNode(const TVariable *tempVariable) |
166 | { |
167 | TIntermDeclaration *tempDeclaration = new TIntermDeclaration(); |
168 | tempDeclaration->appendDeclarator(CreateTempSymbolNode(tempVariable)); |
169 | return tempDeclaration; |
170 | } |
171 | |
172 | TIntermDeclaration *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 | |
183 | TIntermBinary *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 | |
190 | TVariable *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 | |
200 | TVariable *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 | |
211 | TIntermBlock *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 | |
225 | TIntermSymbol *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 | |
232 | TIntermSymbol *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 | |
242 | TIntermTyped *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 | |