Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / angle / src / compiler / translator / Intermediate.cpp
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/RemoveTree.h"
17 #include "compiler/translator/SymbolTable.h"
18
19 ////////////////////////////////////////////////////////////////////////////
20 //
21 // First set of functions are to help build the intermediate representation.
22 // These functions are not member functions of the nodes.
23 // They are called from parser productions.
24 //
25 /////////////////////////////////////////////////////////////////////////////
26
27 //
28 // Add a terminal node for an identifier in an expression.
29 //
30 // Returns the added node.
31 //
32 TIntermSymbol *TIntermediate::addSymbol(
33     int id, const TString &name, const TType &type, const TSourceLoc &line)
34 {
35     TIntermSymbol *node = new TIntermSymbol(id, name, type);
36     node->setLine(line);
37
38     return node;
39 }
40
41 //
42 // Connect two nodes with a new parent that does a binary operation on the nodes.
43 //
44 // Returns the added node.
45 //
46 TIntermTyped *TIntermediate::addBinaryMath(
47     TOperator op, TIntermTyped *left, TIntermTyped *right, const TSourceLoc &line)
48 {
49     switch (op)
50     {
51       case EOpEqual:
52       case EOpNotEqual:
53         if (left->isArray())
54             return NULL;
55         break;
56       case EOpLessThan:
57       case EOpGreaterThan:
58       case EOpLessThanEqual:
59       case EOpGreaterThanEqual:
60         if (left->isMatrix() || left->isArray() || left->isVector() ||
61             left->getBasicType() == EbtStruct)
62         {
63             return NULL;
64         }
65         break;
66       case EOpLogicalOr:
67       case EOpLogicalXor:
68       case EOpLogicalAnd:
69         if (left->getBasicType() != EbtBool ||
70             left->isMatrix() || left->isArray() || left->isVector())
71         {
72             return NULL;
73         }
74         break;
75       case EOpAdd:
76       case EOpSub:
77       case EOpDiv:
78       case EOpMul:
79         if (left->getBasicType() == EbtStruct || left->getBasicType() == EbtBool)
80             return NULL;
81       default:
82         break;
83     }
84
85     if (left->getBasicType() != right->getBasicType())
86     {
87         return NULL;
88     }
89
90     //
91     // Need a new node holding things together then.  Make
92     // one and promote it to the right type.
93     //
94     TIntermBinary *node = new TIntermBinary(op);
95     node->setLine(line);
96
97     node->setLeft(left);
98     node->setRight(right);
99     if (!node->promote(mInfoSink))
100         return NULL;
101
102     //
103     // See if we can fold constants.
104     //
105     TIntermConstantUnion *leftTempConstant = left->getAsConstantUnion();
106     TIntermConstantUnion *rightTempConstant = right->getAsConstantUnion();
107     if (leftTempConstant && rightTempConstant)
108     {
109         TIntermTyped *typedReturnNode =
110             leftTempConstant->fold(node->getOp(), rightTempConstant, mInfoSink);
111
112         if (typedReturnNode)
113             return typedReturnNode;
114     }
115
116     return node;
117 }
118
119 //
120 // Connect two nodes through an assignment.
121 //
122 // Returns the added node.
123 //
124 TIntermTyped *TIntermediate::addAssign(
125     TOperator op, TIntermTyped *left, TIntermTyped *right, const TSourceLoc &line)
126 {
127     if (left->getType().getStruct() || right->getType().getStruct())
128     {
129         if (left->getType() != right->getType())
130         {
131             return NULL;
132         }
133     }
134
135     TIntermBinary *node = new TIntermBinary(op);
136     node->setLine(line);
137
138     node->setLeft(left);
139     node->setRight(right);
140     if (!node->promote(mInfoSink))
141         return NULL;
142
143     return node;
144 }
145
146 //
147 // Connect two nodes through an index operator, where the left node is the base
148 // of an array or struct, and the right node is a direct or indirect offset.
149 //
150 // Returns the added node.
151 // The caller should set the type of the returned node.
152 //
153 TIntermTyped *TIntermediate::addIndex(
154     TOperator op, TIntermTyped *base, TIntermTyped *index, const TSourceLoc &line)
155 {
156     TIntermBinary *node = new TIntermBinary(op);
157     node->setLine(line);
158     node->setLeft(base);
159     node->setRight(index);
160
161     // caller should set the type
162
163     return node;
164 }
165
166 //
167 // Add one node as the parent of another that it operates on.
168 //
169 // Returns the added node.
170 //
171 TIntermTyped *TIntermediate::addUnaryMath(
172     TOperator op, TIntermNode *childNode, const TSourceLoc &line)
173 {
174     TIntermUnary *node;
175     TIntermTyped *child = childNode->getAsTyped();
176
177     if (child == NULL)
178     {
179         mInfoSink.info.message(EPrefixInternalError, line,
180                                "Bad type in AddUnaryMath");
181         return NULL;
182     }
183
184     switch (op)
185     {
186       case EOpLogicalNot:
187         if (child->getType().getBasicType() != EbtBool ||
188             child->getType().isMatrix() ||
189             child->getType().isArray() ||
190             child->getType().isVector())
191         {
192             return NULL;
193         }
194         break;
195
196       case EOpPostIncrement:
197       case EOpPreIncrement:
198       case EOpPostDecrement:
199       case EOpPreDecrement:
200       case EOpNegative:
201       case EOpPositive:
202         if (child->getType().getBasicType() == EbtStruct ||
203             child->getType().isArray())
204         {
205             return NULL;
206         }
207       default:
208         break;
209     }
210
211     TIntermConstantUnion *childTempConstant = 0;
212     if (child->getAsConstantUnion())
213         childTempConstant = child->getAsConstantUnion();
214
215     //
216     // Make a new node for the operator.
217     //
218     node = new TIntermUnary(op);
219     node->setLine(line);
220     node->setOperand(child);
221
222     if (!node->promote(mInfoSink))
223         return 0;
224
225     if (childTempConstant)
226     {
227         TIntermTyped *newChild = childTempConstant->fold(op, 0, mInfoSink);
228
229         if (newChild)
230             return newChild;
231     }
232
233     return node;
234 }
235
236 //
237 // This is the safe way to change the operator on an aggregate, as it
238 // does lots of error checking and fixing.  Especially for establishing
239 // a function call's operation on it's set of parameters.  Sequences
240 // of instructions are also aggregates, but they just direnctly set
241 // their operator to EOpSequence.
242 //
243 // Returns an aggregate node, which could be the one passed in if
244 // it was already an aggregate but no operator was set.
245 //
246 TIntermAggregate *TIntermediate::setAggregateOperator(
247     TIntermNode *node, TOperator op, const TSourceLoc &line)
248 {
249     TIntermAggregate *aggNode;
250
251     //
252     // Make sure we have an aggregate.  If not turn it into one.
253     //
254     if (node)
255     {
256         aggNode = node->getAsAggregate();
257         if (aggNode == NULL || aggNode->getOp() != EOpNull)
258         {
259             //
260             // Make an aggregate containing this node.
261             //
262             aggNode = new TIntermAggregate();
263             aggNode->getSequence()->push_back(node);
264         }
265     }
266     else
267     {
268         aggNode = new TIntermAggregate();
269     }
270
271     //
272     // Set the operator.
273     //
274     aggNode->setOp(op);
275     aggNode->setLine(line);
276
277     return aggNode;
278 }
279
280 //
281 // Safe way to combine two nodes into an aggregate.  Works with null pointers,
282 // a node that's not a aggregate yet, etc.
283 //
284 // Returns the resulting aggregate, unless 0 was passed in for
285 // both existing nodes.
286 //
287 TIntermAggregate *TIntermediate::growAggregate(
288     TIntermNode *left, TIntermNode *right, const TSourceLoc &line)
289 {
290     if (left == NULL && right == NULL)
291         return NULL;
292
293     TIntermAggregate *aggNode = NULL;
294     if (left)
295         aggNode = left->getAsAggregate();
296     if (!aggNode || aggNode->getOp() != EOpNull)
297     {
298         aggNode = new TIntermAggregate;
299         if (left)
300             aggNode->getSequence()->push_back(left);
301     }
302
303     if (right)
304         aggNode->getSequence()->push_back(right);
305
306     aggNode->setLine(line);
307
308     return aggNode;
309 }
310
311 //
312 // Turn an existing node into an aggregate.
313 //
314 // Returns an aggregate, unless NULL was passed in for the existing node.
315 //
316 TIntermAggregate *TIntermediate::makeAggregate(
317     TIntermNode *node, const TSourceLoc &line)
318 {
319     if (node == NULL)
320         return NULL;
321
322     TIntermAggregate *aggNode = new TIntermAggregate;
323     aggNode->getSequence()->push_back(node);
324
325     aggNode->setLine(line);
326
327     return aggNode;
328 }
329
330 //
331 // For "if" test nodes.  There are three children; a condition,
332 // a true path, and a false path.  The two paths are in the
333 // nodePair.
334 //
335 // Returns the selection node created.
336 //
337 TIntermNode *TIntermediate::addSelection(
338     TIntermTyped *cond, TIntermNodePair nodePair, const TSourceLoc &line)
339 {
340     //
341     // For compile time constant selections, prune the code and
342     // test now.
343     //
344
345     if (cond->getAsTyped() && cond->getAsTyped()->getAsConstantUnion())
346     {
347         if (cond->getAsConstantUnion()->getBConst(0) == true)
348         {
349             return nodePair.node1 ? setAggregateOperator(
350                 nodePair.node1, EOpSequence, nodePair.node1->getLine()) : NULL;
351         }
352         else
353         {
354             return nodePair.node2 ? setAggregateOperator(
355                 nodePair.node2, EOpSequence, nodePair.node2->getLine()) : NULL;
356         }
357     }
358
359     TIntermSelection *node = new TIntermSelection(
360         cond, nodePair.node1, nodePair.node2);
361     node->setLine(line);
362
363     return node;
364 }
365
366 TIntermTyped *TIntermediate::addComma(
367     TIntermTyped *left, TIntermTyped *right, const TSourceLoc &line)
368 {
369     if (left->getType().getQualifier() == EvqConst &&
370         right->getType().getQualifier() == EvqConst)
371     {
372         return right;
373     }
374     else
375     {
376         TIntermTyped *commaAggregate = growAggregate(left, right, line);
377         commaAggregate->getAsAggregate()->setOp(EOpComma);
378         commaAggregate->setType(right->getType());
379         commaAggregate->getTypePointer()->setQualifier(EvqTemporary);
380         return commaAggregate;
381     }
382 }
383
384 //
385 // For "?:" test nodes.  There are three children; a condition,
386 // a true path, and a false path.  The two paths are specified
387 // as separate parameters.
388 //
389 // Returns the selection node created, or 0 if one could not be.
390 //
391 TIntermTyped *TIntermediate::addSelection(
392     TIntermTyped *cond, TIntermTyped *trueBlock, TIntermTyped *falseBlock,
393     const TSourceLoc &line)
394 {
395     if (!cond || !trueBlock || !falseBlock ||
396         trueBlock->getType() != falseBlock->getType())
397     {
398         return NULL;
399     }
400
401     //
402     // See if all the operands are constant, then fold it otherwise not.
403     //
404
405     if (cond->getAsConstantUnion() &&
406         trueBlock->getAsConstantUnion() &&
407         falseBlock->getAsConstantUnion())
408     {
409         if (cond->getAsConstantUnion()->getBConst(0))
410             return trueBlock;
411         else
412             return falseBlock;
413     }
414
415     //
416     // Make a selection node.
417     //
418     TIntermSelection *node = new TIntermSelection(
419         cond, trueBlock, falseBlock, trueBlock->getType());
420     node->getTypePointer()->setQualifier(EvqTemporary);
421     node->setLine(line);
422
423     return node;
424 }
425
426 //
427 // Constant terminal nodes.  Has a union that contains bool, float or int constants
428 //
429 // Returns the constant union node created.
430 //
431
432 TIntermConstantUnion *TIntermediate::addConstantUnion(
433     ConstantUnion *unionArrayPointer, const TType &t, const TSourceLoc &line)
434 {
435     TIntermConstantUnion *node = new TIntermConstantUnion(unionArrayPointer, t);
436     node->setLine(line);
437
438     return node;
439 }
440
441 TIntermTyped *TIntermediate::addSwizzle(
442     TVectorFields &fields, const TSourceLoc &line)
443 {
444
445     TIntermAggregate *node = new TIntermAggregate(EOpSequence);
446
447     node->setLine(line);
448     TIntermConstantUnion *constIntNode;
449     TIntermSequence *sequenceVector = node->getSequence();
450     ConstantUnion *unionArray;
451
452     for (int i = 0; i < fields.num; i++)
453     {
454         unionArray = new ConstantUnion[1];
455         unionArray->setIConst(fields.offsets[i]);
456         constIntNode = addConstantUnion(
457             unionArray, TType(EbtInt, EbpUndefined, EvqConst), line);
458         sequenceVector->push_back(constIntNode);
459     }
460
461     return node;
462 }
463
464 //
465 // Create loop nodes.
466 //
467 TIntermNode *TIntermediate::addLoop(
468     TLoopType type, TIntermNode *init, TIntermTyped *cond, TIntermTyped *expr,
469     TIntermNode *body, const TSourceLoc &line)
470 {
471     TIntermNode *node = new TIntermLoop(type, init, cond, expr, body);
472     node->setLine(line);
473
474     return node;
475 }
476
477 //
478 // Add branches.
479 //
480 TIntermBranch* TIntermediate::addBranch(
481     TOperator branchOp, const TSourceLoc &line)
482 {
483     return addBranch(branchOp, 0, line);
484 }
485
486 TIntermBranch* TIntermediate::addBranch(
487     TOperator branchOp, TIntermTyped *expression, const TSourceLoc &line)
488 {
489     TIntermBranch *node = new TIntermBranch(branchOp, expression);
490     node->setLine(line);
491
492     return node;
493 }
494
495 //
496 // This is to be executed once the final root is put on top by the parsing
497 // process.
498 //
499 bool TIntermediate::postProcess(TIntermNode *root)
500 {
501     if (root == NULL)
502         return true;
503
504     //
505     // First, finish off the top level sequence, if any
506     //
507     TIntermAggregate *aggRoot = root->getAsAggregate();
508     if (aggRoot && aggRoot->getOp() == EOpNull)
509         aggRoot->setOp(EOpSequence);
510
511     return true;
512 }
513
514 //
515 // This deletes the tree.
516 //
517 void TIntermediate::remove(TIntermNode *root)
518 {
519     if (root)
520         RemoveAllTreeNodes(root);
521 }