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