Line data Source code
1 : //
2 : // Copyright (c) 2002-2014 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 :
7 : //
8 : // Build the intermediate representation.
9 : //
10 :
11 : #include <float.h>
12 : #include <limits.h>
13 : #include <algorithm>
14 :
15 : #include "compiler/translator/Intermediate.h"
16 : #include "compiler/translator/SymbolTable.h"
17 :
18 : namespace sh
19 : {
20 :
21 : ////////////////////////////////////////////////////////////////////////////
22 : //
23 : // First set of functions are to help build the intermediate representation.
24 : // These functions are not member functions of the nodes.
25 : // They are called from parser productions.
26 : //
27 : /////////////////////////////////////////////////////////////////////////////
28 :
29 : //
30 : // Add a terminal node for an identifier in an expression.
31 : //
32 : // Returns the added node.
33 : //
34 0 : TIntermSymbol *TIntermediate::addSymbol(
35 : int id, const TString &name, const TType &type, const TSourceLoc &line)
36 : {
37 0 : TIntermSymbol *node = new TIntermSymbol(id, name, type);
38 0 : node->setLine(line);
39 :
40 0 : return node;
41 : }
42 :
43 : //
44 : // Connect two nodes through an index operator, where the left node is the base
45 : // of an array or struct, and the right node is a direct or indirect offset.
46 : //
47 : // Returns the added node.
48 : // The caller should set the type of the returned node.
49 : //
50 0 : TIntermTyped *TIntermediate::addIndex(TOperator op,
51 : TIntermTyped *base,
52 : TIntermTyped *index,
53 : const TSourceLoc &line,
54 : TDiagnostics *diagnostics)
55 : {
56 0 : TIntermBinary *node = new TIntermBinary(op, base, index);
57 0 : node->setLine(line);
58 :
59 0 : TIntermTyped *folded = node->fold(diagnostics);
60 0 : if (folded)
61 : {
62 0 : return folded;
63 : }
64 :
65 0 : return node;
66 : }
67 :
68 : // This is the safe way to change the operator on an aggregate, as it
69 : // does lots of error checking and fixing. Especially for establishing
70 : // a function call's operation on it's set of parameters.
71 : //
72 : // Returns an aggregate node, which could be the one passed in if
73 : // it was already an aggregate but no operator was set.
74 0 : TIntermAggregate *TIntermediate::setAggregateOperator(
75 : TIntermNode *node, TOperator op, const TSourceLoc &line)
76 : {
77 : TIntermAggregate *aggNode;
78 :
79 : //
80 : // Make sure we have an aggregate. If not turn it into one.
81 : //
82 0 : if (node)
83 : {
84 0 : aggNode = node->getAsAggregate();
85 0 : if (aggNode == NULL || aggNode->getOp() != EOpNull)
86 : {
87 : //
88 : // Make an aggregate containing this node.
89 : //
90 0 : aggNode = new TIntermAggregate();
91 0 : aggNode->getSequence()->push_back(node);
92 : }
93 : }
94 : else
95 : {
96 0 : aggNode = new TIntermAggregate();
97 : }
98 :
99 : //
100 : // Set the operator.
101 : //
102 0 : aggNode->setOp(op);
103 0 : aggNode->setLine(line);
104 :
105 0 : return aggNode;
106 : }
107 :
108 : //
109 : // Safe way to combine two nodes into an aggregate. Works with null pointers,
110 : // a node that's not a aggregate yet, etc.
111 : //
112 : // Returns the resulting aggregate, unless 0 was passed in for
113 : // both existing nodes.
114 : //
115 0 : TIntermAggregate *TIntermediate::growAggregate(
116 : TIntermNode *left, TIntermNode *right, const TSourceLoc &line)
117 : {
118 0 : if (left == NULL && right == NULL)
119 0 : return NULL;
120 :
121 0 : TIntermAggregate *aggNode = NULL;
122 0 : if (left)
123 0 : aggNode = left->getAsAggregate();
124 0 : if (!aggNode || aggNode->getOp() != EOpNull)
125 : {
126 0 : aggNode = new TIntermAggregate;
127 0 : if (left)
128 0 : aggNode->getSequence()->push_back(left);
129 : }
130 :
131 0 : if (right)
132 0 : aggNode->getSequence()->push_back(right);
133 :
134 0 : aggNode->setLine(line);
135 :
136 0 : return aggNode;
137 : }
138 :
139 : //
140 : // Turn an existing node into an aggregate.
141 : //
142 : // Returns an aggregate, unless NULL was passed in for the existing node.
143 : //
144 0 : TIntermAggregate *TIntermediate::MakeAggregate(TIntermNode *node, const TSourceLoc &line)
145 : {
146 0 : if (node == nullptr)
147 0 : return nullptr;
148 :
149 0 : TIntermAggregate *aggNode = new TIntermAggregate;
150 0 : aggNode->getSequence()->push_back(node);
151 :
152 0 : aggNode->setLine(line);
153 :
154 0 : return aggNode;
155 : }
156 :
157 : // If the input node is nullptr, return nullptr.
158 : // If the input node is a block node, return it.
159 : // If the input node is not a block node, put it inside a block node and return that.
160 0 : TIntermBlock *TIntermediate::EnsureBlock(TIntermNode *node)
161 : {
162 0 : if (node == nullptr)
163 0 : return nullptr;
164 0 : TIntermBlock *blockNode = node->getAsBlock();
165 0 : if (blockNode != nullptr)
166 0 : return blockNode;
167 :
168 0 : blockNode = new TIntermBlock();
169 0 : blockNode->setLine(node->getLine());
170 0 : blockNode->getSequence()->push_back(node);
171 0 : return blockNode;
172 : }
173 :
174 : // For "if" test nodes. There are three children; a condition,
175 : // a true path, and a false path. The two paths are in the
176 : // nodePair.
177 : //
178 : // Returns the node created.
179 0 : TIntermNode *TIntermediate::addIfElse(TIntermTyped *cond,
180 : TIntermNodePair nodePair,
181 : const TSourceLoc &line)
182 : {
183 : // For compile time constant conditions, prune the code now.
184 :
185 0 : if (cond->getAsConstantUnion())
186 : {
187 0 : if (cond->getAsConstantUnion()->getBConst(0) == true)
188 : {
189 0 : return EnsureBlock(nodePair.node1);
190 : }
191 : else
192 : {
193 0 : return EnsureBlock(nodePair.node2);
194 : }
195 : }
196 :
197 : TIntermIfElse *node =
198 0 : new TIntermIfElse(cond, EnsureBlock(nodePair.node1), EnsureBlock(nodePair.node2));
199 0 : node->setLine(line);
200 :
201 0 : return node;
202 : }
203 :
204 0 : TIntermTyped *TIntermediate::AddComma(TIntermTyped *left,
205 : TIntermTyped *right,
206 : const TSourceLoc &line,
207 : int shaderVersion)
208 : {
209 0 : TIntermTyped *commaNode = nullptr;
210 0 : if (!left->hasSideEffects())
211 : {
212 0 : commaNode = right;
213 : }
214 : else
215 : {
216 0 : commaNode = new TIntermBinary(EOpComma, left, right);
217 0 : commaNode->setLine(line);
218 : }
219 0 : TQualifier resultQualifier = TIntermBinary::GetCommaQualifier(shaderVersion, left, right);
220 0 : commaNode->getTypePointer()->setQualifier(resultQualifier);
221 0 : return commaNode;
222 : }
223 :
224 : // For "?:" test nodes. There are three children; a condition,
225 : // a true path, and a false path. The two paths are specified
226 : // as separate parameters.
227 : //
228 : // Returns the ternary node created, or one of trueExpression and falseExpression if the expression
229 : // could be folded.
230 0 : TIntermTyped *TIntermediate::AddTernarySelection(TIntermTyped *cond,
231 : TIntermTyped *trueExpression,
232 : TIntermTyped *falseExpression,
233 : const TSourceLoc &line)
234 : {
235 : // Note that the node resulting from here can be a constant union without being qualified as
236 : // constant.
237 0 : if (cond->getAsConstantUnion())
238 : {
239 : TQualifier resultQualifier =
240 0 : TIntermTernary::DetermineQualifier(cond, trueExpression, falseExpression);
241 0 : if (cond->getAsConstantUnion()->getBConst(0))
242 : {
243 0 : trueExpression->getTypePointer()->setQualifier(resultQualifier);
244 0 : return trueExpression;
245 : }
246 : else
247 : {
248 0 : falseExpression->getTypePointer()->setQualifier(resultQualifier);
249 0 : return falseExpression;
250 : }
251 : }
252 :
253 : // Make a ternary node.
254 0 : TIntermTernary *node = new TIntermTernary(cond, trueExpression, falseExpression);
255 0 : node->setLine(line);
256 :
257 0 : return node;
258 : }
259 :
260 0 : TIntermSwitch *TIntermediate::addSwitch(TIntermTyped *init,
261 : TIntermBlock *statementList,
262 : const TSourceLoc &line)
263 : {
264 0 : TIntermSwitch *node = new TIntermSwitch(init, statementList);
265 0 : node->setLine(line);
266 :
267 0 : return node;
268 : }
269 :
270 0 : TIntermCase *TIntermediate::addCase(
271 : TIntermTyped *condition, const TSourceLoc &line)
272 : {
273 0 : TIntermCase *node = new TIntermCase(condition);
274 0 : node->setLine(line);
275 :
276 0 : return node;
277 : }
278 :
279 : //
280 : // Constant terminal nodes. Has a union that contains bool, float or int constants
281 : //
282 : // Returns the constant union node created.
283 : //
284 :
285 0 : TIntermConstantUnion *TIntermediate::addConstantUnion(const TConstantUnion *constantUnion,
286 : const TType &type,
287 : const TSourceLoc &line)
288 : {
289 0 : TIntermConstantUnion *node = new TIntermConstantUnion(constantUnion, type);
290 0 : node->setLine(line);
291 :
292 0 : return node;
293 : }
294 :
295 0 : TIntermTyped *TIntermediate::AddSwizzle(TIntermTyped *baseExpression,
296 : const TVectorFields &fields,
297 : const TSourceLoc &dotLocation)
298 : {
299 0 : TVector<int> fieldsVector;
300 0 : for (int i = 0; i < fields.num; ++i)
301 : {
302 0 : fieldsVector.push_back(fields.offsets[i]);
303 : }
304 0 : TIntermSwizzle *node = new TIntermSwizzle(baseExpression, fieldsVector);
305 0 : node->setLine(dotLocation);
306 :
307 0 : TIntermTyped *folded = node->fold();
308 0 : if (folded)
309 : {
310 0 : return folded;
311 : }
312 :
313 0 : return node;
314 : }
315 :
316 : //
317 : // Create loop nodes.
318 : //
319 0 : TIntermNode *TIntermediate::addLoop(
320 : TLoopType type, TIntermNode *init, TIntermTyped *cond, TIntermTyped *expr,
321 : TIntermNode *body, const TSourceLoc &line)
322 : {
323 0 : TIntermNode *node = new TIntermLoop(type, init, cond, expr, EnsureBlock(body));
324 0 : node->setLine(line);
325 :
326 0 : return node;
327 : }
328 :
329 : //
330 : // Add branches.
331 : //
332 0 : TIntermBranch* TIntermediate::addBranch(
333 : TOperator branchOp, const TSourceLoc &line)
334 : {
335 0 : return addBranch(branchOp, 0, line);
336 : }
337 :
338 0 : TIntermBranch* TIntermediate::addBranch(
339 : TOperator branchOp, TIntermTyped *expression, const TSourceLoc &line)
340 : {
341 0 : TIntermBranch *node = new TIntermBranch(branchOp, expression);
342 0 : node->setLine(line);
343 :
344 0 : return node;
345 : }
346 :
347 0 : TIntermTyped *TIntermediate::foldAggregateBuiltIn(TIntermAggregate *aggregate,
348 : TDiagnostics *diagnostics)
349 : {
350 0 : switch (aggregate->getOp())
351 : {
352 : case EOpAtan:
353 : case EOpPow:
354 : case EOpMod:
355 : case EOpMin:
356 : case EOpMax:
357 : case EOpClamp:
358 : case EOpMix:
359 : case EOpStep:
360 : case EOpSmoothStep:
361 : case EOpMul:
362 : case EOpOuterProduct:
363 : case EOpLessThan:
364 : case EOpLessThanEqual:
365 : case EOpGreaterThan:
366 : case EOpGreaterThanEqual:
367 : case EOpVectorEqual:
368 : case EOpVectorNotEqual:
369 : case EOpDistance:
370 : case EOpDot:
371 : case EOpCross:
372 : case EOpFaceForward:
373 : case EOpReflect:
374 : case EOpRefract:
375 0 : return aggregate->fold(diagnostics);
376 : default:
377 : // TODO: Add support for folding array constructors
378 0 : if (aggregate->isConstructor() && !aggregate->isArray())
379 : {
380 0 : return aggregate->fold(diagnostics);
381 : }
382 : // Constant folding not supported for the built-in.
383 0 : return nullptr;
384 : }
385 : }
386 :
387 : } // namespace sh
|