1 : //
2 : // Copyright (c) 2002-2010 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/localintermediate.h"
16 : #include "compiler/QualifierAlive.h"
17 : #include "compiler/RemoveTree.h"
18 :
19 : bool CompareStructure(const TType& leftNodeType, ConstantUnion* rightUnionArray, ConstantUnion* leftUnionArray);
20 :
21 0 : static TPrecision GetHigherPrecision( TPrecision left, TPrecision right ){
22 0 : return left > right ? left : right;
23 : }
24 :
25 0 : const char* getOperatorString(TOperator op) {
26 0 : switch (op) {
27 0 : case EOpInitialize: return "=";
28 0 : case EOpAssign: return "=";
29 0 : case EOpAddAssign: return "+=";
30 0 : case EOpSubAssign: return "-=";
31 0 : case EOpDivAssign: return "/=";
32 :
33 : // Fall-through.
34 : case EOpMulAssign:
35 : case EOpVectorTimesMatrixAssign:
36 : case EOpVectorTimesScalarAssign:
37 : case EOpMatrixTimesScalarAssign:
38 0 : case EOpMatrixTimesMatrixAssign: return "*=";
39 :
40 : // Fall-through.
41 : case EOpIndexDirect:
42 0 : case EOpIndexIndirect: return "[]";
43 :
44 0 : case EOpIndexDirectStruct: return ".";
45 0 : case EOpVectorSwizzle: return ".";
46 0 : case EOpAdd: return "+";
47 0 : case EOpSub: return "-";
48 0 : case EOpMul: return "*";
49 0 : case EOpDiv: return "/";
50 0 : case EOpMod: UNIMPLEMENTED(); break;
51 0 : case EOpEqual: return "==";
52 0 : case EOpNotEqual: return "!=";
53 0 : case EOpLessThan: return "<";
54 0 : case EOpGreaterThan: return ">";
55 0 : case EOpLessThanEqual: return "<=";
56 0 : case EOpGreaterThanEqual: return ">=";
57 :
58 : // Fall-through.
59 : case EOpVectorTimesScalar:
60 : case EOpVectorTimesMatrix:
61 : case EOpMatrixTimesVector:
62 : case EOpMatrixTimesScalar:
63 0 : case EOpMatrixTimesMatrix: return "*";
64 :
65 0 : case EOpLogicalOr: return "||";
66 0 : case EOpLogicalXor: return "^^";
67 0 : case EOpLogicalAnd: return "&&";
68 0 : case EOpNegative: return "-";
69 0 : case EOpVectorLogicalNot: return "not";
70 0 : case EOpLogicalNot: return "!";
71 0 : case EOpPostIncrement: return "++";
72 0 : case EOpPostDecrement: return "--";
73 0 : case EOpPreIncrement: return "++";
74 0 : case EOpPreDecrement: return "--";
75 :
76 : // Fall-through.
77 : case EOpConvIntToBool:
78 0 : case EOpConvFloatToBool: return "bool";
79 :
80 : // Fall-through.
81 : case EOpConvBoolToFloat:
82 0 : case EOpConvIntToFloat: return "float";
83 :
84 : // Fall-through.
85 : case EOpConvFloatToInt:
86 0 : case EOpConvBoolToInt: return "int";
87 :
88 0 : case EOpRadians: return "radians";
89 0 : case EOpDegrees: return "degrees";
90 0 : case EOpSin: return "sin";
91 0 : case EOpCos: return "cos";
92 0 : case EOpTan: return "tan";
93 0 : case EOpAsin: return "asin";
94 0 : case EOpAcos: return "acos";
95 0 : case EOpAtan: return "atan";
96 0 : case EOpExp: return "exp";
97 0 : case EOpLog: return "log";
98 0 : case EOpExp2: return "exp2";
99 0 : case EOpLog2: return "log2";
100 0 : case EOpSqrt: return "sqrt";
101 0 : case EOpInverseSqrt: return "inversesqrt";
102 0 : case EOpAbs: return "abs";
103 0 : case EOpSign: return "sign";
104 0 : case EOpFloor: return "floor";
105 0 : case EOpCeil: return "ceil";
106 0 : case EOpFract: return "fract";
107 0 : case EOpLength: return "length";
108 0 : case EOpNormalize: return "normalize";
109 0 : case EOpDFdx: return "dFdx";
110 0 : case EOpDFdy: return "dFdy";
111 0 : case EOpFwidth: return "fwidth";
112 0 : case EOpAny: return "any";
113 0 : case EOpAll: return "all";
114 :
115 : default: break;
116 : }
117 0 : return "";
118 : }
119 :
120 : ////////////////////////////////////////////////////////////////////////////
121 : //
122 : // First set of functions are to help build the intermediate representation.
123 : // These functions are not member functions of the nodes.
124 : // They are called from parser productions.
125 : //
126 : /////////////////////////////////////////////////////////////////////////////
127 :
128 : //
129 : // Add a terminal node for an identifier in an expression.
130 : //
131 : // Returns the added node.
132 : //
133 0 : TIntermSymbol* TIntermediate::addSymbol(int id, const TString& name, const TType& type, TSourceLoc line)
134 : {
135 0 : TIntermSymbol* node = new TIntermSymbol(id, name, type);
136 0 : node->setLine(line);
137 :
138 0 : return node;
139 : }
140 :
141 : //
142 : // Connect two nodes with a new parent that does a binary operation on the nodes.
143 : //
144 : // Returns the added node.
145 : //
146 0 : TIntermTyped* TIntermediate::addBinaryMath(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc line, TSymbolTable& symbolTable)
147 : {
148 0 : switch (op) {
149 : case EOpEqual:
150 : case EOpNotEqual:
151 0 : if (left->isArray())
152 0 : return 0;
153 0 : break;
154 : case EOpLessThan:
155 : case EOpGreaterThan:
156 : case EOpLessThanEqual:
157 : case EOpGreaterThanEqual:
158 0 : if (left->isMatrix() || left->isArray() || left->isVector() || left->getBasicType() == EbtStruct) {
159 0 : return 0;
160 : }
161 0 : break;
162 : case EOpLogicalOr:
163 : case EOpLogicalXor:
164 : case EOpLogicalAnd:
165 0 : if (left->getBasicType() != EbtBool || left->isMatrix() || left->isArray() || left->isVector()) {
166 0 : return 0;
167 : }
168 0 : break;
169 : case EOpAdd:
170 : case EOpSub:
171 : case EOpDiv:
172 : case EOpMul:
173 0 : if (left->getBasicType() == EbtStruct || left->getBasicType() == EbtBool)
174 0 : return 0;
175 0 : default: break;
176 : }
177 :
178 : //
179 : // First try converting the children to compatible types.
180 : //
181 0 : if (left->getType().getStruct() && right->getType().getStruct()) {
182 0 : if (left->getType() != right->getType())
183 0 : return 0;
184 : } else {
185 0 : TIntermTyped* child = addConversion(op, left->getType(), right);
186 0 : if (child)
187 0 : right = child;
188 : else {
189 0 : child = addConversion(op, right->getType(), left);
190 0 : if (child)
191 0 : left = child;
192 : else
193 0 : return 0;
194 : }
195 : }
196 :
197 : //
198 : // Need a new node holding things together then. Make
199 : // one and promote it to the right type.
200 : //
201 0 : TIntermBinary* node = new TIntermBinary(op);
202 0 : if (line == 0)
203 0 : line = right->getLine();
204 0 : node->setLine(line);
205 :
206 0 : node->setLeft(left);
207 0 : node->setRight(right);
208 0 : if (!node->promote(infoSink))
209 0 : return 0;
210 :
211 : //
212 : // See if we can fold constants.
213 : //
214 0 : TIntermTyped* typedReturnNode = 0;
215 0 : TIntermConstantUnion *leftTempConstant = left->getAsConstantUnion();
216 0 : TIntermConstantUnion *rightTempConstant = right->getAsConstantUnion();
217 0 : if (leftTempConstant && rightTempConstant) {
218 0 : typedReturnNode = leftTempConstant->fold(node->getOp(), rightTempConstant, infoSink);
219 :
220 0 : if (typedReturnNode)
221 0 : return typedReturnNode;
222 : }
223 :
224 0 : return node;
225 : }
226 :
227 : //
228 : // Connect two nodes through an assignment.
229 : //
230 : // Returns the added node.
231 : //
232 0 : TIntermTyped* TIntermediate::addAssign(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc line)
233 : {
234 : //
235 : // Like adding binary math, except the conversion can only go
236 : // from right to left.
237 : //
238 0 : TIntermBinary* node = new TIntermBinary(op);
239 0 : if (line == 0)
240 0 : line = left->getLine();
241 0 : node->setLine(line);
242 :
243 0 : TIntermTyped* child = addConversion(op, left->getType(), right);
244 0 : if (child == 0)
245 0 : return 0;
246 :
247 0 : node->setLeft(left);
248 0 : node->setRight(child);
249 0 : if (! node->promote(infoSink))
250 0 : return 0;
251 :
252 0 : return node;
253 : }
254 :
255 : //
256 : // Connect two nodes through an index operator, where the left node is the base
257 : // of an array or struct, and the right node is a direct or indirect offset.
258 : //
259 : // Returns the added node.
260 : // The caller should set the type of the returned node.
261 : //
262 0 : TIntermTyped* TIntermediate::addIndex(TOperator op, TIntermTyped* base, TIntermTyped* index, TSourceLoc line)
263 : {
264 0 : TIntermBinary* node = new TIntermBinary(op);
265 0 : if (line == 0)
266 0 : line = index->getLine();
267 0 : node->setLine(line);
268 0 : node->setLeft(base);
269 0 : node->setRight(index);
270 :
271 : // caller should set the type
272 :
273 0 : return node;
274 : }
275 :
276 : //
277 : // Add one node as the parent of another that it operates on.
278 : //
279 : // Returns the added node.
280 : //
281 0 : TIntermTyped* TIntermediate::addUnaryMath(TOperator op, TIntermNode* childNode, TSourceLoc line, TSymbolTable& symbolTable)
282 : {
283 : TIntermUnary* node;
284 0 : TIntermTyped* child = childNode->getAsTyped();
285 :
286 0 : if (child == 0) {
287 0 : infoSink.info.message(EPrefixInternalError, "Bad type in AddUnaryMath", line);
288 0 : return 0;
289 : }
290 :
291 0 : switch (op) {
292 : case EOpLogicalNot:
293 0 : if (child->getType().getBasicType() != EbtBool || child->getType().isMatrix() || child->getType().isArray() || child->getType().isVector()) {
294 0 : return 0;
295 : }
296 0 : break;
297 :
298 : case EOpPostIncrement:
299 : case EOpPreIncrement:
300 : case EOpPostDecrement:
301 : case EOpPreDecrement:
302 : case EOpNegative:
303 0 : if (child->getType().getBasicType() == EbtStruct || child->getType().isArray())
304 0 : return 0;
305 0 : default: break;
306 : }
307 :
308 : //
309 : // Do we need to promote the operand?
310 : //
311 : // Note: Implicit promotions were removed from the language.
312 : //
313 0 : TBasicType newType = EbtVoid;
314 0 : switch (op) {
315 0 : case EOpConstructInt: newType = EbtInt; break;
316 0 : case EOpConstructBool: newType = EbtBool; break;
317 0 : case EOpConstructFloat: newType = EbtFloat; break;
318 0 : default: break;
319 : }
320 :
321 0 : if (newType != EbtVoid) {
322 : child = addConversion(op, TType(newType, child->getPrecision(), EvqTemporary,
323 : child->getNominalSize(),
324 0 : child->isMatrix(),
325 0 : child->isArray()),
326 0 : child);
327 0 : if (child == 0)
328 0 : return 0;
329 : }
330 :
331 : //
332 : // For constructors, we are now done, it's all in the conversion.
333 : //
334 0 : switch (op) {
335 : case EOpConstructInt:
336 : case EOpConstructBool:
337 : case EOpConstructFloat:
338 0 : return child;
339 : default: break;
340 : }
341 :
342 0 : TIntermConstantUnion *childTempConstant = 0;
343 0 : if (child->getAsConstantUnion())
344 0 : childTempConstant = child->getAsConstantUnion();
345 :
346 : //
347 : // Make a new node for the operator.
348 : //
349 0 : node = new TIntermUnary(op);
350 0 : if (line == 0)
351 0 : line = child->getLine();
352 0 : node->setLine(line);
353 0 : node->setOperand(child);
354 :
355 0 : if (! node->promote(infoSink))
356 0 : return 0;
357 :
358 0 : if (childTempConstant) {
359 0 : TIntermTyped* newChild = childTempConstant->fold(op, 0, infoSink);
360 :
361 0 : if (newChild)
362 0 : return newChild;
363 : }
364 :
365 0 : return node;
366 : }
367 :
368 : //
369 : // This is the safe way to change the operator on an aggregate, as it
370 : // does lots of error checking and fixing. Especially for establishing
371 : // a function call's operation on it's set of parameters. Sequences
372 : // of instructions are also aggregates, but they just direnctly set
373 : // their operator to EOpSequence.
374 : //
375 : // Returns an aggregate node, which could be the one passed in if
376 : // it was already an aggregate.
377 : //
378 0 : TIntermAggregate* TIntermediate::setAggregateOperator(TIntermNode* node, TOperator op, TSourceLoc line)
379 : {
380 : TIntermAggregate* aggNode;
381 :
382 : //
383 : // Make sure we have an aggregate. If not turn it into one.
384 : //
385 0 : if (node) {
386 0 : aggNode = node->getAsAggregate();
387 0 : if (aggNode == 0 || aggNode->getOp() != EOpNull) {
388 : //
389 : // Make an aggregate containing this node.
390 : //
391 0 : aggNode = new TIntermAggregate();
392 0 : aggNode->getSequence().push_back(node);
393 0 : if (line == 0)
394 0 : line = node->getLine();
395 : }
396 : } else
397 0 : aggNode = new TIntermAggregate();
398 :
399 : //
400 : // Set the operator.
401 : //
402 0 : aggNode->setOp(op);
403 0 : if (line != 0)
404 0 : aggNode->setLine(line);
405 :
406 0 : return aggNode;
407 : }
408 :
409 : //
410 : // Convert one type to another.
411 : //
412 : // Returns the node representing the conversion, which could be the same
413 : // node passed in if no conversion was needed.
414 : //
415 : // Return 0 if a conversion can't be done.
416 : //
417 0 : TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TIntermTyped* node)
418 : {
419 : //
420 : // Does the base type allow operation?
421 : //
422 0 : switch (node->getBasicType()) {
423 : case EbtVoid:
424 : case EbtSampler2D:
425 : case EbtSamplerCube:
426 0 : return 0;
427 : default: break;
428 : }
429 :
430 : //
431 : // Otherwise, if types are identical, no problem
432 : //
433 0 : if (type == node->getType())
434 0 : return node;
435 :
436 : //
437 : // If one's a structure, then no conversions.
438 : //
439 0 : if (type.getStruct() || node->getType().getStruct())
440 0 : return 0;
441 :
442 : //
443 : // If one's an array, then no conversions.
444 : //
445 0 : if (type.isArray() || node->getType().isArray())
446 0 : return 0;
447 :
448 : TBasicType promoteTo;
449 :
450 0 : switch (op) {
451 : //
452 : // Explicit conversions
453 : //
454 : case EOpConstructBool:
455 0 : promoteTo = EbtBool;
456 0 : break;
457 : case EOpConstructFloat:
458 0 : promoteTo = EbtFloat;
459 0 : break;
460 : case EOpConstructInt:
461 0 : promoteTo = EbtInt;
462 0 : break;
463 : default:
464 : //
465 : // implicit conversions were removed from the language.
466 : //
467 0 : if (type.getBasicType() != node->getType().getBasicType())
468 0 : return 0;
469 : //
470 : // Size and structure could still differ, but that's
471 : // handled by operator promotion.
472 : //
473 0 : return node;
474 : }
475 :
476 0 : if (node->getAsConstantUnion()) {
477 :
478 0 : return (promoteConstantUnion(promoteTo, node->getAsConstantUnion()));
479 : } else {
480 :
481 : //
482 : // Add a new newNode for the conversion.
483 : //
484 0 : TIntermUnary* newNode = 0;
485 :
486 0 : TOperator newOp = EOpNull;
487 0 : switch (promoteTo) {
488 : case EbtFloat:
489 0 : switch (node->getBasicType()) {
490 0 : case EbtInt: newOp = EOpConvIntToFloat; break;
491 0 : case EbtBool: newOp = EOpConvBoolToFloat; break;
492 : default:
493 0 : infoSink.info.message(EPrefixInternalError, "Bad promotion node", node->getLine());
494 0 : return 0;
495 : }
496 0 : break;
497 : case EbtBool:
498 0 : switch (node->getBasicType()) {
499 0 : case EbtInt: newOp = EOpConvIntToBool; break;
500 0 : case EbtFloat: newOp = EOpConvFloatToBool; break;
501 : default:
502 0 : infoSink.info.message(EPrefixInternalError, "Bad promotion node", node->getLine());
503 0 : return 0;
504 : }
505 0 : break;
506 : case EbtInt:
507 0 : switch (node->getBasicType()) {
508 0 : case EbtBool: newOp = EOpConvBoolToInt; break;
509 0 : case EbtFloat: newOp = EOpConvFloatToInt; break;
510 : default:
511 0 : infoSink.info.message(EPrefixInternalError, "Bad promotion node", node->getLine());
512 0 : return 0;
513 : }
514 0 : break;
515 : default:
516 0 : infoSink.info.message(EPrefixInternalError, "Bad promotion type", node->getLine());
517 0 : return 0;
518 : }
519 :
520 0 : TType type(promoteTo, node->getPrecision(), EvqTemporary, node->getNominalSize(), node->isMatrix(), node->isArray());
521 0 : newNode = new TIntermUnary(newOp, type);
522 0 : newNode->setLine(node->getLine());
523 0 : newNode->setOperand(node);
524 :
525 0 : return newNode;
526 : }
527 : }
528 :
529 : //
530 : // Safe way to combine two nodes into an aggregate. Works with null pointers,
531 : // a node that's not a aggregate yet, etc.
532 : //
533 : // Returns the resulting aggregate, unless 0 was passed in for
534 : // both existing nodes.
535 : //
536 0 : TIntermAggregate* TIntermediate::growAggregate(TIntermNode* left, TIntermNode* right, TSourceLoc line)
537 : {
538 0 : if (left == 0 && right == 0)
539 0 : return 0;
540 :
541 0 : TIntermAggregate* aggNode = 0;
542 0 : if (left)
543 0 : aggNode = left->getAsAggregate();
544 0 : if (!aggNode || aggNode->getOp() != EOpNull) {
545 0 : aggNode = new TIntermAggregate;
546 0 : if (left)
547 0 : aggNode->getSequence().push_back(left);
548 : }
549 :
550 0 : if (right)
551 0 : aggNode->getSequence().push_back(right);
552 :
553 0 : if (line != 0)
554 0 : aggNode->setLine(line);
555 :
556 0 : return aggNode;
557 : }
558 :
559 : //
560 : // Turn an existing node into an aggregate.
561 : //
562 : // Returns an aggregate, unless 0 was passed in for the existing node.
563 : //
564 0 : TIntermAggregate* TIntermediate::makeAggregate(TIntermNode* node, TSourceLoc line)
565 : {
566 0 : if (node == 0)
567 0 : return 0;
568 :
569 0 : TIntermAggregate* aggNode = new TIntermAggregate;
570 0 : aggNode->getSequence().push_back(node);
571 :
572 0 : if (line != 0)
573 0 : aggNode->setLine(line);
574 : else
575 0 : aggNode->setLine(node->getLine());
576 :
577 0 : return aggNode;
578 : }
579 :
580 : //
581 : // For "if" test nodes. There are three children; a condition,
582 : // a true path, and a false path. The two paths are in the
583 : // nodePair.
584 : //
585 : // Returns the selection node created.
586 : //
587 0 : TIntermNode* TIntermediate::addSelection(TIntermTyped* cond, TIntermNodePair nodePair, TSourceLoc line)
588 : {
589 : //
590 : // For compile time constant selections, prune the code and
591 : // test now.
592 : //
593 :
594 0 : if (cond->getAsTyped() && cond->getAsTyped()->getAsConstantUnion()) {
595 0 : if (cond->getAsTyped()->getAsConstantUnion()->getUnionArrayPointer()->getBConst())
596 0 : return nodePair.node1;
597 : else
598 0 : return nodePair.node2;
599 : }
600 :
601 0 : TIntermSelection* node = new TIntermSelection(cond, nodePair.node1, nodePair.node2);
602 0 : node->setLine(line);
603 :
604 0 : return node;
605 : }
606 :
607 :
608 0 : TIntermTyped* TIntermediate::addComma(TIntermTyped* left, TIntermTyped* right, TSourceLoc line)
609 : {
610 0 : if (left->getType().getQualifier() == EvqConst && right->getType().getQualifier() == EvqConst) {
611 0 : return right;
612 : } else {
613 0 : TIntermTyped *commaAggregate = growAggregate(left, right, line);
614 0 : commaAggregate->getAsAggregate()->setOp(EOpComma);
615 0 : commaAggregate->setType(right->getType());
616 0 : commaAggregate->getTypePointer()->setQualifier(EvqTemporary);
617 0 : return commaAggregate;
618 : }
619 : }
620 :
621 : //
622 : // For "?:" test nodes. There are three children; a condition,
623 : // a true path, and a false path. The two paths are specified
624 : // as separate parameters.
625 : //
626 : // Returns the selection node created, or 0 if one could not be.
627 : //
628 0 : TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, TSourceLoc line)
629 : {
630 : //
631 : // Get compatible types.
632 : //
633 0 : TIntermTyped* child = addConversion(EOpSequence, trueBlock->getType(), falseBlock);
634 0 : if (child)
635 0 : falseBlock = child;
636 : else {
637 0 : child = addConversion(EOpSequence, falseBlock->getType(), trueBlock);
638 0 : if (child)
639 0 : trueBlock = child;
640 : else
641 0 : return 0;
642 : }
643 :
644 : //
645 : // See if all the operands are constant, then fold it otherwise not.
646 : //
647 :
648 0 : if (cond->getAsConstantUnion() && trueBlock->getAsConstantUnion() && falseBlock->getAsConstantUnion()) {
649 0 : if (cond->getAsConstantUnion()->getUnionArrayPointer()->getBConst())
650 0 : return trueBlock;
651 : else
652 0 : return falseBlock;
653 : }
654 :
655 : //
656 : // Make a selection node.
657 : //
658 0 : TIntermSelection* node = new TIntermSelection(cond, trueBlock, falseBlock, trueBlock->getType());
659 0 : node->setLine(line);
660 :
661 0 : return node;
662 : }
663 :
664 : //
665 : // Constant terminal nodes. Has a union that contains bool, float or int constants
666 : //
667 : // Returns the constant union node created.
668 : //
669 :
670 0 : TIntermConstantUnion* TIntermediate::addConstantUnion(ConstantUnion* unionArrayPointer, const TType& t, TSourceLoc line)
671 : {
672 0 : TIntermConstantUnion* node = new TIntermConstantUnion(unionArrayPointer, t);
673 0 : node->setLine(line);
674 :
675 0 : return node;
676 : }
677 :
678 0 : TIntermTyped* TIntermediate::addSwizzle(TVectorFields& fields, TSourceLoc line)
679 : {
680 :
681 0 : TIntermAggregate* node = new TIntermAggregate(EOpSequence);
682 :
683 0 : node->setLine(line);
684 : TIntermConstantUnion* constIntNode;
685 0 : TIntermSequence &sequenceVector = node->getSequence();
686 : ConstantUnion* unionArray;
687 :
688 0 : for (int i = 0; i < fields.num; i++) {
689 0 : unionArray = new ConstantUnion[1];
690 0 : unionArray->setIConst(fields.offsets[i]);
691 0 : constIntNode = addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), line);
692 0 : sequenceVector.push_back(constIntNode);
693 : }
694 :
695 0 : return node;
696 : }
697 :
698 : //
699 : // Create loop nodes.
700 : //
701 0 : TIntermNode* TIntermediate::addLoop(TLoopType type, TIntermNode* init, TIntermTyped* cond, TIntermTyped* expr, TIntermNode* body, TSourceLoc line)
702 : {
703 0 : TIntermNode* node = new TIntermLoop(type, init, cond, expr, body);
704 0 : node->setLine(line);
705 :
706 0 : return node;
707 : }
708 :
709 : //
710 : // Add branches.
711 : //
712 0 : TIntermBranch* TIntermediate::addBranch(TOperator branchOp, TSourceLoc line)
713 : {
714 0 : return addBranch(branchOp, 0, line);
715 : }
716 :
717 0 : TIntermBranch* TIntermediate::addBranch(TOperator branchOp, TIntermTyped* expression, TSourceLoc line)
718 : {
719 0 : TIntermBranch* node = new TIntermBranch(branchOp, expression);
720 0 : node->setLine(line);
721 :
722 0 : return node;
723 : }
724 :
725 : //
726 : // This is to be executed once the final root is put on top by the parsing
727 : // process.
728 : //
729 0 : bool TIntermediate::postProcess(TIntermNode* root)
730 : {
731 0 : if (root == 0)
732 0 : return true;
733 :
734 : //
735 : // First, finish off the top level sequence, if any
736 : //
737 0 : TIntermAggregate* aggRoot = root->getAsAggregate();
738 0 : if (aggRoot && aggRoot->getOp() == EOpNull)
739 0 : aggRoot->setOp(EOpSequence);
740 :
741 0 : return true;
742 : }
743 :
744 : //
745 : // This deletes the tree.
746 : //
747 0 : void TIntermediate::remove(TIntermNode* root)
748 : {
749 0 : if (root)
750 0 : RemoveAllTreeNodes(root);
751 0 : }
752 :
753 : ////////////////////////////////////////////////////////////////
754 : //
755 : // Member functions of the nodes used for building the tree.
756 : //
757 : ////////////////////////////////////////////////////////////////
758 :
759 : //
760 : // Say whether or not an operation node changes the value of a variable.
761 : //
762 : // Returns true if state is modified.
763 : //
764 0 : bool TIntermOperator::modifiesState() const
765 : {
766 0 : switch (op) {
767 : case EOpPostIncrement:
768 : case EOpPostDecrement:
769 : case EOpPreIncrement:
770 : case EOpPreDecrement:
771 : case EOpAssign:
772 : case EOpAddAssign:
773 : case EOpSubAssign:
774 : case EOpMulAssign:
775 : case EOpVectorTimesMatrixAssign:
776 : case EOpVectorTimesScalarAssign:
777 : case EOpMatrixTimesScalarAssign:
778 : case EOpMatrixTimesMatrixAssign:
779 : case EOpDivAssign:
780 0 : return true;
781 : default:
782 0 : return false;
783 : }
784 : }
785 :
786 : //
787 : // returns true if the operator is for one of the constructors
788 : //
789 0 : bool TIntermOperator::isConstructor() const
790 : {
791 0 : switch (op) {
792 : case EOpConstructVec2:
793 : case EOpConstructVec3:
794 : case EOpConstructVec4:
795 : case EOpConstructMat2:
796 : case EOpConstructMat3:
797 : case EOpConstructMat4:
798 : case EOpConstructFloat:
799 : case EOpConstructIVec2:
800 : case EOpConstructIVec3:
801 : case EOpConstructIVec4:
802 : case EOpConstructInt:
803 : case EOpConstructBVec2:
804 : case EOpConstructBVec3:
805 : case EOpConstructBVec4:
806 : case EOpConstructBool:
807 : case EOpConstructStruct:
808 0 : return true;
809 : default:
810 0 : return false;
811 : }
812 : }
813 : //
814 : // Make sure the type of a unary operator is appropriate for its
815 : // combination of operation and operand type.
816 : //
817 : // Returns false in nothing makes sense.
818 : //
819 0 : bool TIntermUnary::promote(TInfoSink&)
820 : {
821 0 : switch (op) {
822 : case EOpLogicalNot:
823 0 : if (operand->getBasicType() != EbtBool)
824 0 : return false;
825 0 : break;
826 : case EOpNegative:
827 : case EOpPostIncrement:
828 : case EOpPostDecrement:
829 : case EOpPreIncrement:
830 : case EOpPreDecrement:
831 0 : if (operand->getBasicType() == EbtBool)
832 0 : return false;
833 0 : break;
834 :
835 : // operators for built-ins are already type checked against their prototype
836 : case EOpAny:
837 : case EOpAll:
838 : case EOpVectorLogicalNot:
839 0 : return true;
840 :
841 : default:
842 0 : if (operand->getBasicType() != EbtFloat)
843 0 : return false;
844 : }
845 :
846 0 : setType(operand->getType());
847 :
848 0 : return true;
849 : }
850 :
851 : //
852 : // Establishes the type of the resultant operation, as well as
853 : // makes the operator the correct one for the operands.
854 : //
855 : // Returns false if operator can't work on operands.
856 : //
857 0 : bool TIntermBinary::promote(TInfoSink& infoSink)
858 : {
859 : // This function only handles scalars, vectors, and matrices.
860 0 : if (left->isArray() || right->isArray()) {
861 0 : infoSink.info.message(EPrefixInternalError, "Invalid operation for arrays", getLine());
862 0 : return false;
863 : }
864 :
865 : // GLSL ES 2.0 does not support implicit type casting.
866 : // So the basic type should always match.
867 0 : if (left->getBasicType() != right->getBasicType())
868 0 : return false;
869 :
870 : //
871 : // Base assumption: just make the type the same as the left
872 : // operand. Then only deviations from this need be coded.
873 : //
874 0 : setType(left->getType());
875 :
876 : // The result gets promoted to the highest precision.
877 0 : TPrecision higherPrecision = GetHigherPrecision(left->getPrecision(), right->getPrecision());
878 0 : getTypePointer()->setPrecision(higherPrecision);
879 :
880 : // Binary operations results in temporary variables unless both
881 : // operands are const.
882 0 : if (left->getQualifier() != EvqConst || right->getQualifier() != EvqConst) {
883 0 : getTypePointer()->setQualifier(EvqTemporary);
884 : }
885 :
886 0 : int size = std::max(left->getNominalSize(), right->getNominalSize());
887 :
888 : //
889 : // All scalars. Code after this test assumes this case is removed!
890 : //
891 0 : if (size == 1) {
892 0 : switch (op) {
893 : //
894 : // Promote to conditional
895 : //
896 : case EOpEqual:
897 : case EOpNotEqual:
898 : case EOpLessThan:
899 : case EOpGreaterThan:
900 : case EOpLessThanEqual:
901 : case EOpGreaterThanEqual:
902 0 : setType(TType(EbtBool, EbpUndefined));
903 0 : break;
904 :
905 : //
906 : // And and Or operate on conditionals
907 : //
908 : case EOpLogicalAnd:
909 : case EOpLogicalOr:
910 : // Both operands must be of type bool.
911 0 : if (left->getBasicType() != EbtBool || right->getBasicType() != EbtBool)
912 0 : return false;
913 0 : setType(TType(EbtBool, EbpUndefined));
914 0 : break;
915 :
916 : default:
917 0 : break;
918 : }
919 0 : return true;
920 : }
921 :
922 : // If we reach here, at least one of the operands is vector or matrix.
923 : // The other operand could be a scalar, vector, or matrix.
924 : // Are the sizes compatible?
925 : //
926 0 : if (left->getNominalSize() != right->getNominalSize()) {
927 : // If the nominal size of operands do not match:
928 : // One of them must be scalar.
929 0 : if (left->getNominalSize() != 1 && right->getNominalSize() != 1)
930 0 : return false;
931 : // Operator cannot be of type pure assignment.
932 0 : if (op == EOpAssign || op == EOpInitialize)
933 0 : return false;
934 : }
935 :
936 : //
937 : // Can these two operands be combined?
938 : //
939 0 : TBasicType basicType = left->getBasicType();
940 0 : switch (op) {
941 : case EOpMul:
942 0 : if (!left->isMatrix() && right->isMatrix()) {
943 0 : if (left->isVector())
944 0 : op = EOpVectorTimesMatrix;
945 : else {
946 0 : op = EOpMatrixTimesScalar;
947 0 : setType(TType(basicType, higherPrecision, EvqTemporary, size, true));
948 : }
949 0 : } else if (left->isMatrix() && !right->isMatrix()) {
950 0 : if (right->isVector()) {
951 0 : op = EOpMatrixTimesVector;
952 0 : setType(TType(basicType, higherPrecision, EvqTemporary, size, false));
953 : } else {
954 0 : op = EOpMatrixTimesScalar;
955 : }
956 0 : } else if (left->isMatrix() && right->isMatrix()) {
957 0 : op = EOpMatrixTimesMatrix;
958 0 : } else if (!left->isMatrix() && !right->isMatrix()) {
959 0 : if (left->isVector() && right->isVector()) {
960 : // leave as component product
961 0 : } else if (left->isVector() || right->isVector()) {
962 0 : op = EOpVectorTimesScalar;
963 0 : setType(TType(basicType, higherPrecision, EvqTemporary, size, false));
964 : }
965 : } else {
966 0 : infoSink.info.message(EPrefixInternalError, "Missing elses", getLine());
967 0 : return false;
968 : }
969 0 : break;
970 : case EOpMulAssign:
971 0 : if (!left->isMatrix() && right->isMatrix()) {
972 0 : if (left->isVector())
973 0 : op = EOpVectorTimesMatrixAssign;
974 : else {
975 0 : return false;
976 : }
977 0 : } else if (left->isMatrix() && !right->isMatrix()) {
978 0 : if (right->isVector()) {
979 0 : return false;
980 : } else {
981 0 : op = EOpMatrixTimesScalarAssign;
982 : }
983 0 : } else if (left->isMatrix() && right->isMatrix()) {
984 0 : op = EOpMatrixTimesMatrixAssign;
985 0 : } else if (!left->isMatrix() && !right->isMatrix()) {
986 0 : if (left->isVector() && right->isVector()) {
987 : // leave as component product
988 0 : } else if (left->isVector() || right->isVector()) {
989 0 : if (! left->isVector())
990 0 : return false;
991 0 : op = EOpVectorTimesScalarAssign;
992 0 : setType(TType(basicType, higherPrecision, EvqTemporary, size, false));
993 : }
994 : } else {
995 0 : infoSink.info.message(EPrefixInternalError, "Missing elses", getLine());
996 0 : return false;
997 : }
998 0 : break;
999 :
1000 : case EOpAssign:
1001 : case EOpInitialize:
1002 : case EOpAdd:
1003 : case EOpSub:
1004 : case EOpDiv:
1005 : case EOpAddAssign:
1006 : case EOpSubAssign:
1007 : case EOpDivAssign:
1008 0 : if ((left->isMatrix() && right->isVector()) ||
1009 0 : (left->isVector() && right->isMatrix()))
1010 0 : return false;
1011 0 : setType(TType(basicType, higherPrecision, EvqTemporary, size, left->isMatrix() || right->isMatrix()));
1012 0 : break;
1013 :
1014 : case EOpEqual:
1015 : case EOpNotEqual:
1016 : case EOpLessThan:
1017 : case EOpGreaterThan:
1018 : case EOpLessThanEqual:
1019 : case EOpGreaterThanEqual:
1020 0 : if ((left->isMatrix() && right->isVector()) ||
1021 0 : (left->isVector() && right->isMatrix()))
1022 0 : return false;
1023 0 : setType(TType(EbtBool, EbpUndefined));
1024 0 : break;
1025 :
1026 : default:
1027 0 : return false;
1028 : }
1029 :
1030 0 : return true;
1031 : }
1032 :
1033 0 : bool CompareStruct(const TType& leftNodeType, ConstantUnion* rightUnionArray, ConstantUnion* leftUnionArray)
1034 : {
1035 0 : const TTypeList* fields = leftNodeType.getStruct();
1036 :
1037 0 : size_t structSize = fields->size();
1038 0 : int index = 0;
1039 :
1040 0 : for (size_t j = 0; j < structSize; j++) {
1041 0 : int size = (*fields)[j].type->getObjectSize();
1042 0 : for (int i = 0; i < size; i++) {
1043 0 : if ((*fields)[j].type->getBasicType() == EbtStruct) {
1044 0 : if (!CompareStructure(*(*fields)[j].type, &rightUnionArray[index], &leftUnionArray[index]))
1045 0 : return false;
1046 : } else {
1047 0 : if (leftUnionArray[index] != rightUnionArray[index])
1048 0 : return false;
1049 0 : index++;
1050 : }
1051 :
1052 : }
1053 : }
1054 0 : return true;
1055 : }
1056 :
1057 0 : bool CompareStructure(const TType& leftNodeType, ConstantUnion* rightUnionArray, ConstantUnion* leftUnionArray)
1058 : {
1059 0 : if (leftNodeType.isArray()) {
1060 0 : TType typeWithoutArrayness = leftNodeType;
1061 0 : typeWithoutArrayness.clearArrayness();
1062 :
1063 0 : int arraySize = leftNodeType.getArraySize();
1064 :
1065 0 : for (int i = 0; i < arraySize; ++i) {
1066 0 : int offset = typeWithoutArrayness.getObjectSize() * i;
1067 0 : if (!CompareStruct(typeWithoutArrayness, &rightUnionArray[offset], &leftUnionArray[offset]))
1068 0 : return false;
1069 : }
1070 : } else
1071 0 : return CompareStruct(leftNodeType, rightUnionArray, leftUnionArray);
1072 :
1073 0 : return true;
1074 : }
1075 :
1076 : //
1077 : // The fold functions see if an operation on a constant can be done in place,
1078 : // without generating run-time code.
1079 : //
1080 : // Returns the node to keep using, which may or may not be the node passed in.
1081 : //
1082 :
1083 0 : TIntermTyped* TIntermConstantUnion::fold(TOperator op, TIntermTyped* constantNode, TInfoSink& infoSink)
1084 : {
1085 0 : ConstantUnion *unionArray = getUnionArrayPointer();
1086 0 : int objectSize = getType().getObjectSize();
1087 :
1088 0 : if (constantNode) { // binary operations
1089 0 : TIntermConstantUnion *node = constantNode->getAsConstantUnion();
1090 0 : ConstantUnion *rightUnionArray = node->getUnionArrayPointer();
1091 0 : TType returnType = getType();
1092 :
1093 : // for a case like float f = 1.2 + vec4(2,3,4,5);
1094 0 : if (constantNode->getType().getObjectSize() == 1 && objectSize > 1) {
1095 0 : rightUnionArray = new ConstantUnion[objectSize];
1096 0 : for (int i = 0; i < objectSize; ++i)
1097 0 : rightUnionArray[i] = *node->getUnionArrayPointer();
1098 0 : returnType = getType();
1099 0 : } else if (constantNode->getType().getObjectSize() > 1 && objectSize == 1) {
1100 : // for a case like float f = vec4(2,3,4,5) + 1.2;
1101 0 : unionArray = new ConstantUnion[constantNode->getType().getObjectSize()];
1102 0 : for (int i = 0; i < constantNode->getType().getObjectSize(); ++i)
1103 0 : unionArray[i] = *getUnionArrayPointer();
1104 0 : returnType = node->getType();
1105 0 : objectSize = constantNode->getType().getObjectSize();
1106 : }
1107 :
1108 0 : ConstantUnion* tempConstArray = 0;
1109 : TIntermConstantUnion *tempNode;
1110 :
1111 0 : bool boolNodeFlag = false;
1112 0 : switch(op) {
1113 : case EOpAdd:
1114 0 : tempConstArray = new ConstantUnion[objectSize];
1115 : {// support MSVC++6.0
1116 0 : for (int i = 0; i < objectSize; i++)
1117 0 : tempConstArray[i] = unionArray[i] + rightUnionArray[i];
1118 : }
1119 0 : break;
1120 : case EOpSub:
1121 0 : tempConstArray = new ConstantUnion[objectSize];
1122 : {// support MSVC++6.0
1123 0 : for (int i = 0; i < objectSize; i++)
1124 0 : tempConstArray[i] = unionArray[i] - rightUnionArray[i];
1125 : }
1126 0 : break;
1127 :
1128 : case EOpMul:
1129 : case EOpVectorTimesScalar:
1130 : case EOpMatrixTimesScalar:
1131 0 : tempConstArray = new ConstantUnion[objectSize];
1132 : {// support MSVC++6.0
1133 0 : for (int i = 0; i < objectSize; i++)
1134 0 : tempConstArray[i] = unionArray[i] * rightUnionArray[i];
1135 : }
1136 0 : break;
1137 : case EOpMatrixTimesMatrix:
1138 0 : if (getType().getBasicType() != EbtFloat || node->getBasicType() != EbtFloat) {
1139 0 : infoSink.info.message(EPrefixInternalError, "Constant Folding cannot be done for matrix multiply", getLine());
1140 0 : return 0;
1141 : }
1142 : {// support MSVC++6.0
1143 0 : int size = getNominalSize();
1144 0 : tempConstArray = new ConstantUnion[size*size];
1145 0 : for (int row = 0; row < size; row++) {
1146 0 : for (int column = 0; column < size; column++) {
1147 0 : tempConstArray[size * column + row].setFConst(0.0f);
1148 0 : for (int i = 0; i < size; i++) {
1149 0 : tempConstArray[size * column + row].setFConst(tempConstArray[size * column + row].getFConst() + unionArray[i * size + row].getFConst() * (rightUnionArray[column * size + i].getFConst()));
1150 : }
1151 : }
1152 : }
1153 : }
1154 0 : break;
1155 : case EOpDiv:
1156 0 : tempConstArray = new ConstantUnion[objectSize];
1157 : {// support MSVC++6.0
1158 0 : for (int i = 0; i < objectSize; i++) {
1159 0 : switch (getType().getBasicType()) {
1160 : case EbtFloat:
1161 0 : if (rightUnionArray[i] == 0.0f) {
1162 0 : infoSink.info.message(EPrefixWarning, "Divide by zero error during constant folding", getLine());
1163 0 : tempConstArray[i].setFConst(FLT_MAX);
1164 : } else
1165 0 : tempConstArray[i].setFConst(unionArray[i].getFConst() / rightUnionArray[i].getFConst());
1166 0 : break;
1167 :
1168 : case EbtInt:
1169 0 : if (rightUnionArray[i] == 0) {
1170 0 : infoSink.info.message(EPrefixWarning, "Divide by zero error during constant folding", getLine());
1171 0 : tempConstArray[i].setIConst(INT_MAX);
1172 : } else
1173 0 : tempConstArray[i].setIConst(unionArray[i].getIConst() / rightUnionArray[i].getIConst());
1174 0 : break;
1175 : default:
1176 0 : infoSink.info.message(EPrefixInternalError, "Constant folding cannot be done for \"/\"", getLine());
1177 0 : return 0;
1178 : }
1179 : }
1180 : }
1181 0 : break;
1182 :
1183 : case EOpMatrixTimesVector:
1184 0 : if (node->getBasicType() != EbtFloat) {
1185 0 : infoSink.info.message(EPrefixInternalError, "Constant Folding cannot be done for matrix times vector", getLine());
1186 0 : return 0;
1187 : }
1188 0 : tempConstArray = new ConstantUnion[getNominalSize()];
1189 :
1190 : {// support MSVC++6.0
1191 0 : for (int size = getNominalSize(), i = 0; i < size; i++) {
1192 0 : tempConstArray[i].setFConst(0.0f);
1193 0 : for (int j = 0; j < size; j++) {
1194 0 : tempConstArray[i].setFConst(tempConstArray[i].getFConst() + ((unionArray[j*size + i].getFConst()) * rightUnionArray[j].getFConst()));
1195 : }
1196 : }
1197 : }
1198 :
1199 0 : tempNode = new TIntermConstantUnion(tempConstArray, node->getType());
1200 0 : tempNode->setLine(getLine());
1201 :
1202 0 : return tempNode;
1203 :
1204 : case EOpVectorTimesMatrix:
1205 0 : if (getType().getBasicType() != EbtFloat) {
1206 0 : infoSink.info.message(EPrefixInternalError, "Constant Folding cannot be done for vector times matrix", getLine());
1207 0 : return 0;
1208 : }
1209 :
1210 0 : tempConstArray = new ConstantUnion[getNominalSize()];
1211 : {// support MSVC++6.0
1212 0 : for (int size = getNominalSize(), i = 0; i < size; i++) {
1213 0 : tempConstArray[i].setFConst(0.0f);
1214 0 : for (int j = 0; j < size; j++) {
1215 0 : tempConstArray[i].setFConst(tempConstArray[i].getFConst() + ((unionArray[j].getFConst()) * rightUnionArray[i*size + j].getFConst()));
1216 : }
1217 : }
1218 : }
1219 0 : break;
1220 :
1221 : case EOpLogicalAnd: // this code is written for possible future use, will not get executed currently
1222 0 : tempConstArray = new ConstantUnion[objectSize];
1223 : {// support MSVC++6.0
1224 0 : for (int i = 0; i < objectSize; i++)
1225 0 : tempConstArray[i] = unionArray[i] && rightUnionArray[i];
1226 : }
1227 0 : break;
1228 :
1229 : case EOpLogicalOr: // this code is written for possible future use, will not get executed currently
1230 0 : tempConstArray = new ConstantUnion[objectSize];
1231 : {// support MSVC++6.0
1232 0 : for (int i = 0; i < objectSize; i++)
1233 0 : tempConstArray[i] = unionArray[i] || rightUnionArray[i];
1234 : }
1235 0 : break;
1236 :
1237 : case EOpLogicalXor:
1238 0 : tempConstArray = new ConstantUnion[objectSize];
1239 : {// support MSVC++6.0
1240 0 : for (int i = 0; i < objectSize; i++)
1241 0 : switch (getType().getBasicType()) {
1242 0 : case EbtBool: tempConstArray[i].setBConst((unionArray[i] == rightUnionArray[i]) ? false : true); break;
1243 0 : default: assert(false && "Default missing");
1244 : }
1245 : }
1246 0 : break;
1247 :
1248 : case EOpLessThan:
1249 0 : assert(objectSize == 1);
1250 0 : tempConstArray = new ConstantUnion[1];
1251 0 : tempConstArray->setBConst(*unionArray < *rightUnionArray);
1252 0 : returnType = TType(EbtBool, EbpUndefined, EvqConst);
1253 0 : break;
1254 : case EOpGreaterThan:
1255 0 : assert(objectSize == 1);
1256 0 : tempConstArray = new ConstantUnion[1];
1257 0 : tempConstArray->setBConst(*unionArray > *rightUnionArray);
1258 0 : returnType = TType(EbtBool, EbpUndefined, EvqConst);
1259 0 : break;
1260 : case EOpLessThanEqual:
1261 : {
1262 0 : assert(objectSize == 1);
1263 : ConstantUnion constant;
1264 0 : constant.setBConst(*unionArray > *rightUnionArray);
1265 0 : tempConstArray = new ConstantUnion[1];
1266 0 : tempConstArray->setBConst(!constant.getBConst());
1267 0 : returnType = TType(EbtBool, EbpUndefined, EvqConst);
1268 0 : break;
1269 : }
1270 : case EOpGreaterThanEqual:
1271 : {
1272 0 : assert(objectSize == 1);
1273 : ConstantUnion constant;
1274 0 : constant.setBConst(*unionArray < *rightUnionArray);
1275 0 : tempConstArray = new ConstantUnion[1];
1276 0 : tempConstArray->setBConst(!constant.getBConst());
1277 0 : returnType = TType(EbtBool, EbpUndefined, EvqConst);
1278 0 : break;
1279 : }
1280 :
1281 : case EOpEqual:
1282 0 : if (getType().getBasicType() == EbtStruct) {
1283 0 : if (!CompareStructure(node->getType(), node->getUnionArrayPointer(), unionArray))
1284 0 : boolNodeFlag = true;
1285 : } else {
1286 0 : for (int i = 0; i < objectSize; i++) {
1287 0 : if (unionArray[i] != rightUnionArray[i]) {
1288 0 : boolNodeFlag = true;
1289 0 : break; // break out of for loop
1290 : }
1291 : }
1292 : }
1293 :
1294 0 : tempConstArray = new ConstantUnion[1];
1295 0 : if (!boolNodeFlag) {
1296 0 : tempConstArray->setBConst(true);
1297 : }
1298 : else {
1299 0 : tempConstArray->setBConst(false);
1300 : }
1301 :
1302 0 : tempNode = new TIntermConstantUnion(tempConstArray, TType(EbtBool, EbpUndefined, EvqConst));
1303 0 : tempNode->setLine(getLine());
1304 :
1305 0 : return tempNode;
1306 :
1307 : case EOpNotEqual:
1308 0 : if (getType().getBasicType() == EbtStruct) {
1309 0 : if (CompareStructure(node->getType(), node->getUnionArrayPointer(), unionArray))
1310 0 : boolNodeFlag = true;
1311 : } else {
1312 0 : for (int i = 0; i < objectSize; i++) {
1313 0 : if (unionArray[i] == rightUnionArray[i]) {
1314 0 : boolNodeFlag = true;
1315 0 : break; // break out of for loop
1316 : }
1317 : }
1318 : }
1319 :
1320 0 : tempConstArray = new ConstantUnion[1];
1321 0 : if (!boolNodeFlag) {
1322 0 : tempConstArray->setBConst(true);
1323 : }
1324 : else {
1325 0 : tempConstArray->setBConst(false);
1326 : }
1327 :
1328 0 : tempNode = new TIntermConstantUnion(tempConstArray, TType(EbtBool, EbpUndefined, EvqConst));
1329 0 : tempNode->setLine(getLine());
1330 :
1331 0 : return tempNode;
1332 :
1333 : default:
1334 0 : infoSink.info.message(EPrefixInternalError, "Invalid operator for constant folding", getLine());
1335 0 : return 0;
1336 : }
1337 0 : tempNode = new TIntermConstantUnion(tempConstArray, returnType);
1338 0 : tempNode->setLine(getLine());
1339 :
1340 0 : return tempNode;
1341 : } else {
1342 : //
1343 : // Do unary operations
1344 : //
1345 0 : TIntermConstantUnion *newNode = 0;
1346 0 : ConstantUnion* tempConstArray = new ConstantUnion[objectSize];
1347 0 : for (int i = 0; i < objectSize; i++) {
1348 0 : switch(op) {
1349 : case EOpNegative:
1350 0 : switch (getType().getBasicType()) {
1351 0 : case EbtFloat: tempConstArray[i].setFConst(-unionArray[i].getFConst()); break;
1352 0 : case EbtInt: tempConstArray[i].setIConst(-unionArray[i].getIConst()); break;
1353 : default:
1354 0 : infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
1355 0 : return 0;
1356 : }
1357 0 : break;
1358 : case EOpLogicalNot: // this code is written for possible future use, will not get executed currently
1359 0 : switch (getType().getBasicType()) {
1360 0 : case EbtBool: tempConstArray[i].setBConst(!unionArray[i].getBConst()); break;
1361 : default:
1362 0 : infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
1363 0 : return 0;
1364 : }
1365 0 : break;
1366 : default:
1367 0 : return 0;
1368 : }
1369 : }
1370 0 : newNode = new TIntermConstantUnion(tempConstArray, getType());
1371 0 : newNode->setLine(getLine());
1372 0 : return newNode;
1373 : }
1374 :
1375 : return this;
1376 : }
1377 :
1378 0 : TIntermTyped* TIntermediate::promoteConstantUnion(TBasicType promoteTo, TIntermConstantUnion* node)
1379 : {
1380 0 : ConstantUnion *rightUnionArray = node->getUnionArrayPointer();
1381 0 : int size = node->getType().getObjectSize();
1382 :
1383 0 : ConstantUnion *leftUnionArray = new ConstantUnion[size];
1384 :
1385 0 : for (int i=0; i < size; i++) {
1386 :
1387 0 : switch (promoteTo) {
1388 : case EbtFloat:
1389 0 : switch (node->getType().getBasicType()) {
1390 : case EbtInt:
1391 0 : leftUnionArray[i].setFConst(static_cast<float>(rightUnionArray[i].getIConst()));
1392 0 : break;
1393 : case EbtBool:
1394 0 : leftUnionArray[i].setFConst(static_cast<float>(rightUnionArray[i].getBConst()));
1395 0 : break;
1396 : case EbtFloat:
1397 0 : leftUnionArray[i] = rightUnionArray[i];
1398 0 : break;
1399 : default:
1400 0 : infoSink.info.message(EPrefixInternalError, "Cannot promote", node->getLine());
1401 0 : return 0;
1402 : }
1403 0 : break;
1404 : case EbtInt:
1405 0 : switch (node->getType().getBasicType()) {
1406 : case EbtInt:
1407 0 : leftUnionArray[i] = rightUnionArray[i];
1408 0 : break;
1409 : case EbtBool:
1410 0 : leftUnionArray[i].setIConst(static_cast<int>(rightUnionArray[i].getBConst()));
1411 0 : break;
1412 : case EbtFloat:
1413 0 : leftUnionArray[i].setIConst(static_cast<int>(rightUnionArray[i].getFConst()));
1414 0 : break;
1415 : default:
1416 0 : infoSink.info.message(EPrefixInternalError, "Cannot promote", node->getLine());
1417 0 : return 0;
1418 : }
1419 0 : break;
1420 : case EbtBool:
1421 0 : switch (node->getType().getBasicType()) {
1422 : case EbtInt:
1423 0 : leftUnionArray[i].setBConst(rightUnionArray[i].getIConst() != 0);
1424 0 : break;
1425 : case EbtBool:
1426 0 : leftUnionArray[i] = rightUnionArray[i];
1427 0 : break;
1428 : case EbtFloat:
1429 0 : leftUnionArray[i].setBConst(rightUnionArray[i].getFConst() != 0.0f);
1430 0 : break;
1431 : default:
1432 0 : infoSink.info.message(EPrefixInternalError, "Cannot promote", node->getLine());
1433 0 : return 0;
1434 : }
1435 :
1436 0 : break;
1437 : default:
1438 0 : infoSink.info.message(EPrefixInternalError, "Incorrect data type found", node->getLine());
1439 0 : return 0;
1440 : }
1441 :
1442 : }
1443 :
1444 0 : const TType& t = node->getType();
1445 :
1446 0 : return addConstantUnion(leftUnionArray, TType(promoteTo, t.getPrecision(), t.getQualifier(), t.getNominalSize(), t.isMatrix(), t.isArray()), node->getLine());
1447 : }
1448 :
1449 0 : void TIntermAggregate::addToPragmaTable(const TPragmaTable& pTable)
1450 : {
1451 0 : assert(!pragmaTable);
1452 0 : pragmaTable = new TPragmaTable();
1453 0 : *pragmaTable = pTable;
1454 0 : }
|