1 //
2 // Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6
7 //
8 // Build the intermediate representation.
9 //
10
11 #include <float.h>
12 #include <limits.h>
13 #include <algorithm>
14
15 #include "compiler/translator/HashNames.h"
16 #include "compiler/translator/IntermNode.h"
17 #include "compiler/translator/SymbolTable.h"
18
19 namespace
20 {
21
GetHigherPrecision(TPrecision left,TPrecision right)22 TPrecision GetHigherPrecision(TPrecision left, TPrecision right)
23 {
24 return left > right ? left : right;
25 }
26
ValidateMultiplication(TOperator op,const TType & left,const TType & right)27 bool ValidateMultiplication(TOperator op, const TType &left, const TType &right)
28 {
29 switch (op)
30 {
31 case EOpMul:
32 case EOpMulAssign:
33 return left.getNominalSize() == right.getNominalSize() &&
34 left.getSecondarySize() == right.getSecondarySize();
35 case EOpVectorTimesScalar:
36 case EOpVectorTimesScalarAssign:
37 return true;
38 case EOpVectorTimesMatrix:
39 return left.getNominalSize() == right.getRows();
40 case EOpVectorTimesMatrixAssign:
41 return left.getNominalSize() == right.getRows() &&
42 left.getNominalSize() == right.getCols();
43 case EOpMatrixTimesVector:
44 return left.getCols() == right.getNominalSize();
45 case EOpMatrixTimesScalar:
46 case EOpMatrixTimesScalarAssign:
47 return true;
48 case EOpMatrixTimesMatrix:
49 return left.getCols() == right.getRows();
50 case EOpMatrixTimesMatrixAssign:
51 return left.getCols() == right.getCols() &&
52 left.getRows() == right.getRows();
53
54 default:
55 UNREACHABLE();
56 return false;
57 }
58 }
59
60 bool CompareStructure(const TType& leftNodeType,
61 ConstantUnion *rightUnionArray,
62 ConstantUnion *leftUnionArray);
63
CompareStruct(const TType & leftNodeType,ConstantUnion * rightUnionArray,ConstantUnion * leftUnionArray)64 bool CompareStruct(const TType &leftNodeType,
65 ConstantUnion *rightUnionArray,
66 ConstantUnion *leftUnionArray)
67 {
68 const TFieldList &fields = leftNodeType.getStruct()->fields();
69
70 size_t structSize = fields.size();
71 size_t index = 0;
72
73 for (size_t j = 0; j < structSize; j++)
74 {
75 size_t size = fields[j]->type()->getObjectSize();
76 for (size_t i = 0; i < size; i++)
77 {
78 if (fields[j]->type()->getBasicType() == EbtStruct)
79 {
80 if (!CompareStructure(*fields[j]->type(),
81 &rightUnionArray[index],
82 &leftUnionArray[index]))
83 {
84 return false;
85 }
86 }
87 else
88 {
89 if (leftUnionArray[index] != rightUnionArray[index])
90 return false;
91 index++;
92 }
93 }
94 }
95 return true;
96 }
97
CompareStructure(const TType & leftNodeType,ConstantUnion * rightUnionArray,ConstantUnion * leftUnionArray)98 bool CompareStructure(const TType &leftNodeType,
99 ConstantUnion *rightUnionArray,
100 ConstantUnion *leftUnionArray)
101 {
102 if (leftNodeType.isArray())
103 {
104 TType typeWithoutArrayness = leftNodeType;
105 typeWithoutArrayness.clearArrayness();
106
107 size_t arraySize = leftNodeType.getArraySize();
108
109 for (size_t i = 0; i < arraySize; ++i)
110 {
111 size_t offset = typeWithoutArrayness.getObjectSize() * i;
112 if (!CompareStruct(typeWithoutArrayness,
113 &rightUnionArray[offset],
114 &leftUnionArray[offset]))
115 {
116 return false;
117 }
118 }
119 }
120 else
121 {
122 return CompareStruct(leftNodeType, rightUnionArray, leftUnionArray);
123 }
124 return true;
125 }
126
127 } // namespace anonymous
128
129
130 ////////////////////////////////////////////////////////////////
131 //
132 // Member functions of the nodes used for building the tree.
133 //
134 ////////////////////////////////////////////////////////////////
135
136 #define REPLACE_IF_IS(node, type, original, replacement) \
137 if (node == original) { \
138 node = static_cast<type *>(replacement); \
139 return true; \
140 }
141
replaceChildNode(TIntermNode * original,TIntermNode * replacement)142 bool TIntermLoop::replaceChildNode(
143 TIntermNode *original, TIntermNode *replacement)
144 {
145 REPLACE_IF_IS(mInit, TIntermNode, original, replacement);
146 REPLACE_IF_IS(mCond, TIntermTyped, original, replacement);
147 REPLACE_IF_IS(mExpr, TIntermTyped, original, replacement);
148 REPLACE_IF_IS(mBody, TIntermNode, original, replacement);
149 return false;
150 }
151
enqueueChildren(std::queue<TIntermNode * > * nodeQueue) const152 void TIntermLoop::enqueueChildren(std::queue<TIntermNode *> *nodeQueue) const
153 {
154 if (mInit)
155 {
156 nodeQueue->push(mInit);
157 }
158 if (mCond)
159 {
160 nodeQueue->push(mCond);
161 }
162 if (mExpr)
163 {
164 nodeQueue->push(mExpr);
165 }
166 if (mBody)
167 {
168 nodeQueue->push(mBody);
169 }
170 }
171
replaceChildNode(TIntermNode * original,TIntermNode * replacement)172 bool TIntermBranch::replaceChildNode(
173 TIntermNode *original, TIntermNode *replacement)
174 {
175 REPLACE_IF_IS(mExpression, TIntermTyped, original, replacement);
176 return false;
177 }
178
enqueueChildren(std::queue<TIntermNode * > * nodeQueue) const179 void TIntermBranch::enqueueChildren(std::queue<TIntermNode *> *nodeQueue) const
180 {
181 if (mExpression)
182 {
183 nodeQueue->push(mExpression);
184 }
185 }
186
replaceChildNode(TIntermNode * original,TIntermNode * replacement)187 bool TIntermBinary::replaceChildNode(
188 TIntermNode *original, TIntermNode *replacement)
189 {
190 REPLACE_IF_IS(mLeft, TIntermTyped, original, replacement);
191 REPLACE_IF_IS(mRight, TIntermTyped, original, replacement);
192 return false;
193 }
194
enqueueChildren(std::queue<TIntermNode * > * nodeQueue) const195 void TIntermBinary::enqueueChildren(std::queue<TIntermNode *> *nodeQueue) const
196 {
197 if (mLeft)
198 {
199 nodeQueue->push(mLeft);
200 }
201 if (mRight)
202 {
203 nodeQueue->push(mRight);
204 }
205 }
206
replaceChildNode(TIntermNode * original,TIntermNode * replacement)207 bool TIntermUnary::replaceChildNode(
208 TIntermNode *original, TIntermNode *replacement)
209 {
210 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
211 return false;
212 }
213
enqueueChildren(std::queue<TIntermNode * > * nodeQueue) const214 void TIntermUnary::enqueueChildren(std::queue<TIntermNode *> *nodeQueue) const
215 {
216 if (mOperand)
217 {
218 nodeQueue->push(mOperand);
219 }
220 }
221
replaceChildNode(TIntermNode * original,TIntermNode * replacement)222 bool TIntermAggregate::replaceChildNode(
223 TIntermNode *original, TIntermNode *replacement)
224 {
225 for (size_t ii = 0; ii < mSequence.size(); ++ii)
226 {
227 REPLACE_IF_IS(mSequence[ii], TIntermNode, original, replacement);
228 }
229 return false;
230 }
231
enqueueChildren(std::queue<TIntermNode * > * nodeQueue) const232 void TIntermAggregate::enqueueChildren(std::queue<TIntermNode *> *nodeQueue) const
233 {
234 for (size_t childIndex = 0; childIndex < mSequence.size(); childIndex++)
235 {
236 nodeQueue->push(mSequence[childIndex]);
237 }
238 }
239
replaceChildNode(TIntermNode * original,TIntermNode * replacement)240 bool TIntermSelection::replaceChildNode(
241 TIntermNode *original, TIntermNode *replacement)
242 {
243 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
244 REPLACE_IF_IS(mTrueBlock, TIntermNode, original, replacement);
245 REPLACE_IF_IS(mFalseBlock, TIntermNode, original, replacement);
246 return false;
247 }
248
enqueueChildren(std::queue<TIntermNode * > * nodeQueue) const249 void TIntermSelection::enqueueChildren(std::queue<TIntermNode *> *nodeQueue) const
250 {
251 if (mCondition)
252 {
253 nodeQueue->push(mCondition);
254 }
255 if (mTrueBlock)
256 {
257 nodeQueue->push(mTrueBlock);
258 }
259 if (mFalseBlock)
260 {
261 nodeQueue->push(mFalseBlock);
262 }
263 }
264
265 //
266 // Say whether or not an operation node changes the value of a variable.
267 //
isAssignment() const268 bool TIntermOperator::isAssignment() const
269 {
270 switch (mOp)
271 {
272 case EOpPostIncrement:
273 case EOpPostDecrement:
274 case EOpPreIncrement:
275 case EOpPreDecrement:
276 case EOpAssign:
277 case EOpAddAssign:
278 case EOpSubAssign:
279 case EOpMulAssign:
280 case EOpVectorTimesMatrixAssign:
281 case EOpVectorTimesScalarAssign:
282 case EOpMatrixTimesScalarAssign:
283 case EOpMatrixTimesMatrixAssign:
284 case EOpDivAssign:
285 return true;
286 default:
287 return false;
288 }
289 }
290
291 //
292 // returns true if the operator is for one of the constructors
293 //
isConstructor() const294 bool TIntermOperator::isConstructor() const
295 {
296 switch (mOp)
297 {
298 case EOpConstructVec2:
299 case EOpConstructVec3:
300 case EOpConstructVec4:
301 case EOpConstructMat2:
302 case EOpConstructMat3:
303 case EOpConstructMat4:
304 case EOpConstructFloat:
305 case EOpConstructIVec2:
306 case EOpConstructIVec3:
307 case EOpConstructIVec4:
308 case EOpConstructInt:
309 case EOpConstructUVec2:
310 case EOpConstructUVec3:
311 case EOpConstructUVec4:
312 case EOpConstructUInt:
313 case EOpConstructBVec2:
314 case EOpConstructBVec3:
315 case EOpConstructBVec4:
316 case EOpConstructBool:
317 case EOpConstructStruct:
318 return true;
319 default:
320 return false;
321 }
322 }
323
324 //
325 // Make sure the type of a unary operator is appropriate for its
326 // combination of operation and operand type.
327 //
328 // Returns false in nothing makes sense.
329 //
promote(TInfoSink &)330 bool TIntermUnary::promote(TInfoSink &)
331 {
332 switch (mOp)
333 {
334 case EOpLogicalNot:
335 if (mOperand->getBasicType() != EbtBool)
336 return false;
337 break;
338 case EOpNegative:
339 case EOpPostIncrement:
340 case EOpPostDecrement:
341 case EOpPreIncrement:
342 case EOpPreDecrement:
343 if (mOperand->getBasicType() == EbtBool)
344 return false;
345 break;
346
347 // operators for built-ins are already type checked against their prototype
348 case EOpAny:
349 case EOpAll:
350 case EOpVectorLogicalNot:
351 return true;
352
353 default:
354 if (mOperand->getBasicType() != EbtFloat)
355 return false;
356 }
357
358 setType(mOperand->getType());
359 mType.setQualifier(EvqTemporary);
360
361 return true;
362 }
363
364 //
365 // Establishes the type of the resultant operation, as well as
366 // makes the operator the correct one for the operands.
367 //
368 // Returns false if operator can't work on operands.
369 //
promote(TInfoSink & infoSink)370 bool TIntermBinary::promote(TInfoSink &infoSink)
371 {
372 // This function only handles scalars, vectors, and matrices.
373 if (mLeft->isArray() || mRight->isArray())
374 {
375 infoSink.info.message(EPrefixInternalError, getLine(),
376 "Invalid operation for arrays");
377 return false;
378 }
379
380 // GLSL ES 2.0 does not support implicit type casting.
381 // So the basic type should always match.
382 if (mLeft->getBasicType() != mRight->getBasicType())
383 {
384 return false;
385 }
386
387 //
388 // Base assumption: just make the type the same as the left
389 // operand. Then only deviations from this need be coded.
390 //
391 setType(mLeft->getType());
392
393 // The result gets promoted to the highest precision.
394 TPrecision higherPrecision = GetHigherPrecision(
395 mLeft->getPrecision(), mRight->getPrecision());
396 getTypePointer()->setPrecision(higherPrecision);
397
398 // Binary operations results in temporary variables unless both
399 // operands are const.
400 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
401 {
402 getTypePointer()->setQualifier(EvqTemporary);
403 }
404
405 const int nominalSize =
406 std::max(mLeft->getNominalSize(), mRight->getNominalSize());
407
408 //
409 // All scalars or structs. Code after this test assumes this case is removed!
410 //
411 if (nominalSize == 1)
412 {
413 switch (mOp)
414 {
415 //
416 // Promote to conditional
417 //
418 case EOpEqual:
419 case EOpNotEqual:
420 case EOpLessThan:
421 case EOpGreaterThan:
422 case EOpLessThanEqual:
423 case EOpGreaterThanEqual:
424 setType(TType(EbtBool, EbpUndefined));
425 break;
426
427 //
428 // And and Or operate on conditionals
429 //
430 case EOpLogicalAnd:
431 case EOpLogicalOr:
432 // Both operands must be of type bool.
433 if (mLeft->getBasicType() != EbtBool || mRight->getBasicType() != EbtBool)
434 {
435 return false;
436 }
437 setType(TType(EbtBool, EbpUndefined));
438 break;
439
440 default:
441 break;
442 }
443 return true;
444 }
445
446 // If we reach here, at least one of the operands is vector or matrix.
447 // The other operand could be a scalar, vector, or matrix.
448 // Can these two operands be combined?
449 //
450 TBasicType basicType = mLeft->getBasicType();
451 switch (mOp)
452 {
453 case EOpMul:
454 if (!mLeft->isMatrix() && mRight->isMatrix())
455 {
456 if (mLeft->isVector())
457 {
458 mOp = EOpVectorTimesMatrix;
459 setType(TType(basicType, higherPrecision, EvqTemporary,
460 mRight->getCols(), 1));
461 }
462 else
463 {
464 mOp = EOpMatrixTimesScalar;
465 setType(TType(basicType, higherPrecision, EvqTemporary,
466 mRight->getCols(), mRight->getRows()));
467 }
468 }
469 else if (mLeft->isMatrix() && !mRight->isMatrix())
470 {
471 if (mRight->isVector())
472 {
473 mOp = EOpMatrixTimesVector;
474 setType(TType(basicType, higherPrecision, EvqTemporary,
475 mLeft->getRows(), 1));
476 }
477 else
478 {
479 mOp = EOpMatrixTimesScalar;
480 }
481 }
482 else if (mLeft->isMatrix() && mRight->isMatrix())
483 {
484 mOp = EOpMatrixTimesMatrix;
485 setType(TType(basicType, higherPrecision, EvqTemporary,
486 mRight->getCols(), mLeft->getRows()));
487 }
488 else if (!mLeft->isMatrix() && !mRight->isMatrix())
489 {
490 if (mLeft->isVector() && mRight->isVector())
491 {
492 // leave as component product
493 }
494 else if (mLeft->isVector() || mRight->isVector())
495 {
496 mOp = EOpVectorTimesScalar;
497 setType(TType(basicType, higherPrecision, EvqTemporary,
498 nominalSize, 1));
499 }
500 }
501 else
502 {
503 infoSink.info.message(EPrefixInternalError, getLine(),
504 "Missing elses");
505 return false;
506 }
507
508 if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType()))
509 {
510 return false;
511 }
512 break;
513
514 case EOpMulAssign:
515 if (!mLeft->isMatrix() && mRight->isMatrix())
516 {
517 if (mLeft->isVector())
518 {
519 mOp = EOpVectorTimesMatrixAssign;
520 }
521 else
522 {
523 return false;
524 }
525 }
526 else if (mLeft->isMatrix() && !mRight->isMatrix())
527 {
528 if (mRight->isVector())
529 {
530 return false;
531 }
532 else
533 {
534 mOp = EOpMatrixTimesScalarAssign;
535 }
536 }
537 else if (mLeft->isMatrix() && mRight->isMatrix())
538 {
539 mOp = EOpMatrixTimesMatrixAssign;
540 setType(TType(basicType, higherPrecision, EvqTemporary,
541 mRight->getCols(), mLeft->getRows()));
542 }
543 else if (!mLeft->isMatrix() && !mRight->isMatrix())
544 {
545 if (mLeft->isVector() && mRight->isVector())
546 {
547 // leave as component product
548 }
549 else if (mLeft->isVector() || mRight->isVector())
550 {
551 if (!mLeft->isVector())
552 return false;
553 mOp = EOpVectorTimesScalarAssign;
554 setType(TType(basicType, higherPrecision, EvqTemporary,
555 mLeft->getNominalSize(), 1));
556 }
557 }
558 else
559 {
560 infoSink.info.message(EPrefixInternalError, getLine(),
561 "Missing elses");
562 return false;
563 }
564
565 if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType()))
566 {
567 return false;
568 }
569 break;
570
571 case EOpAssign:
572 case EOpInitialize:
573 case EOpAdd:
574 case EOpSub:
575 case EOpDiv:
576 case EOpAddAssign:
577 case EOpSubAssign:
578 case EOpDivAssign:
579 if ((mLeft->isMatrix() && mRight->isVector()) ||
580 (mLeft->isVector() && mRight->isMatrix()))
581 {
582 return false;
583 }
584
585 // Are the sizes compatible?
586 if (mLeft->getNominalSize() != mRight->getNominalSize() ||
587 mLeft->getSecondarySize() != mRight->getSecondarySize())
588 {
589 // If the nominal size of operands do not match:
590 // One of them must be scalar.
591 if (!mLeft->isScalar() && !mRight->isScalar())
592 return false;
593
594 // Operator cannot be of type pure assignment.
595 if (mOp == EOpAssign || mOp == EOpInitialize)
596 return false;
597 }
598
599 {
600 const int secondarySize = std::max(
601 mLeft->getSecondarySize(), mRight->getSecondarySize());
602 setType(TType(basicType, higherPrecision, EvqTemporary,
603 nominalSize, secondarySize));
604 }
605 break;
606
607 case EOpEqual:
608 case EOpNotEqual:
609 case EOpLessThan:
610 case EOpGreaterThan:
611 case EOpLessThanEqual:
612 case EOpGreaterThanEqual:
613 if ((mLeft->getNominalSize() != mRight->getNominalSize()) ||
614 (mLeft->getSecondarySize() != mRight->getSecondarySize()))
615 {
616 return false;
617 }
618 setType(TType(EbtBool, EbpUndefined));
619 break;
620
621 default:
622 return false;
623 }
624 return true;
625 }
626
627 //
628 // The fold functions see if an operation on a constant can be done in place,
629 // without generating run-time code.
630 //
631 // Returns the node to keep using, which may or may not be the node passed in.
632 //
fold(TOperator op,TIntermTyped * constantNode,TInfoSink & infoSink)633 TIntermTyped *TIntermConstantUnion::fold(
634 TOperator op, TIntermTyped *constantNode, TInfoSink &infoSink)
635 {
636 ConstantUnion *unionArray = getUnionArrayPointer();
637
638 if (!unionArray)
639 return NULL;
640
641 size_t objectSize = getType().getObjectSize();
642
643 if (constantNode)
644 {
645 // binary operations
646 TIntermConstantUnion *node = constantNode->getAsConstantUnion();
647 ConstantUnion *rightUnionArray = node->getUnionArrayPointer();
648 TType returnType = getType();
649
650 if (!rightUnionArray)
651 return NULL;
652
653 // for a case like float f = 1.2 + vec4(2,3,4,5);
654 if (constantNode->getType().getObjectSize() == 1 && objectSize > 1)
655 {
656 rightUnionArray = new ConstantUnion[objectSize];
657 for (size_t i = 0; i < objectSize; ++i)
658 {
659 rightUnionArray[i] = *node->getUnionArrayPointer();
660 }
661 returnType = getType();
662 }
663 else if (constantNode->getType().getObjectSize() > 1 && objectSize == 1)
664 {
665 // for a case like float f = vec4(2,3,4,5) + 1.2;
666 unionArray = new ConstantUnion[constantNode->getType().getObjectSize()];
667 for (size_t i = 0; i < constantNode->getType().getObjectSize(); ++i)
668 {
669 unionArray[i] = *getUnionArrayPointer();
670 }
671 returnType = node->getType();
672 objectSize = constantNode->getType().getObjectSize();
673 }
674
675 ConstantUnion *tempConstArray = NULL;
676 TIntermConstantUnion *tempNode;
677
678 bool boolNodeFlag = false;
679 switch(op)
680 {
681 case EOpAdd:
682 tempConstArray = new ConstantUnion[objectSize];
683 for (size_t i = 0; i < objectSize; i++)
684 tempConstArray[i] = unionArray[i] + rightUnionArray[i];
685 break;
686 case EOpSub:
687 tempConstArray = new ConstantUnion[objectSize];
688 for (size_t i = 0; i < objectSize; i++)
689 tempConstArray[i] = unionArray[i] - rightUnionArray[i];
690 break;
691
692 case EOpMul:
693 case EOpVectorTimesScalar:
694 case EOpMatrixTimesScalar:
695 tempConstArray = new ConstantUnion[objectSize];
696 for (size_t i = 0; i < objectSize; i++)
697 tempConstArray[i] = unionArray[i] * rightUnionArray[i];
698 break;
699
700 case EOpMatrixTimesMatrix:
701 {
702 if (getType().getBasicType() != EbtFloat ||
703 node->getBasicType() != EbtFloat)
704 {
705 infoSink.info.message(
706 EPrefixInternalError, getLine(),
707 "Constant Folding cannot be done for matrix multiply");
708 return NULL;
709 }
710
711 const int leftCols = getCols();
712 const int leftRows = getRows();
713 const int rightCols = constantNode->getType().getCols();
714 const int rightRows = constantNode->getType().getRows();
715 const int resultCols = rightCols;
716 const int resultRows = leftRows;
717
718 tempConstArray = new ConstantUnion[resultCols*resultRows];
719 for (int row = 0; row < resultRows; row++)
720 {
721 for (int column = 0; column < resultCols; column++)
722 {
723 tempConstArray[resultRows * column + row].setFConst(0.0f);
724 for (int i = 0; i < leftCols; i++)
725 {
726 tempConstArray[resultRows * column + row].setFConst(
727 tempConstArray[resultRows * column + row].getFConst() +
728 unionArray[i * leftRows + row].getFConst() *
729 rightUnionArray[column * rightRows + i].getFConst());
730 }
731 }
732 }
733
734 // update return type for matrix product
735 returnType.setPrimarySize(resultCols);
736 returnType.setSecondarySize(resultRows);
737 }
738 break;
739
740 case EOpDiv:
741 {
742 tempConstArray = new ConstantUnion[objectSize];
743 for (size_t i = 0; i < objectSize; i++)
744 {
745 switch (getType().getBasicType())
746 {
747 case EbtFloat:
748 if (rightUnionArray[i] == 0.0f)
749 {
750 infoSink.info.message(
751 EPrefixWarning, getLine(),
752 "Divide by zero error during constant folding");
753 tempConstArray[i].setFConst(
754 unionArray[i].getFConst() < 0 ? -FLT_MAX : FLT_MAX);
755 }
756 else
757 {
758 tempConstArray[i].setFConst(
759 unionArray[i].getFConst() /
760 rightUnionArray[i].getFConst());
761 }
762 break;
763
764 case EbtInt:
765 if (rightUnionArray[i] == 0)
766 {
767 infoSink.info.message(
768 EPrefixWarning, getLine(),
769 "Divide by zero error during constant folding");
770 tempConstArray[i].setIConst(INT_MAX);
771 }
772 else
773 {
774 tempConstArray[i].setIConst(
775 unionArray[i].getIConst() /
776 rightUnionArray[i].getIConst());
777 }
778 break;
779
780 case EbtUInt:
781 if (rightUnionArray[i] == 0)
782 {
783 infoSink.info.message(
784 EPrefixWarning, getLine(),
785 "Divide by zero error during constant folding");
786 tempConstArray[i].setUConst(UINT_MAX);
787 }
788 else
789 {
790 tempConstArray[i].setUConst(
791 unionArray[i].getUConst() /
792 rightUnionArray[i].getUConst());
793 }
794 break;
795
796 default:
797 infoSink.info.message(
798 EPrefixInternalError, getLine(),
799 "Constant folding cannot be done for \"/\"");
800 return NULL;
801 }
802 }
803 }
804 break;
805
806 case EOpMatrixTimesVector:
807 {
808 if (node->getBasicType() != EbtFloat)
809 {
810 infoSink.info.message(
811 EPrefixInternalError, getLine(),
812 "Constant Folding cannot be done for matrix times vector");
813 return NULL;
814 }
815
816 const int matrixCols = getCols();
817 const int matrixRows = getRows();
818
819 tempConstArray = new ConstantUnion[matrixRows];
820
821 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
822 {
823 tempConstArray[matrixRow].setFConst(0.0f);
824 for (int col = 0; col < matrixCols; col++)
825 {
826 tempConstArray[matrixRow].setFConst(
827 tempConstArray[matrixRow].getFConst() +
828 unionArray[col * matrixRows + matrixRow].getFConst() *
829 rightUnionArray[col].getFConst());
830 }
831 }
832
833 returnType = node->getType();
834 returnType.setPrimarySize(matrixRows);
835
836 tempNode = new TIntermConstantUnion(tempConstArray, returnType);
837 tempNode->setLine(getLine());
838
839 return tempNode;
840 }
841
842 case EOpVectorTimesMatrix:
843 {
844 if (getType().getBasicType() != EbtFloat)
845 {
846 infoSink.info.message(
847 EPrefixInternalError, getLine(),
848 "Constant Folding cannot be done for vector times matrix");
849 return NULL;
850 }
851
852 const int matrixCols = constantNode->getType().getCols();
853 const int matrixRows = constantNode->getType().getRows();
854
855 tempConstArray = new ConstantUnion[matrixCols];
856
857 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
858 {
859 tempConstArray[matrixCol].setFConst(0.0f);
860 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
861 {
862 tempConstArray[matrixCol].setFConst(
863 tempConstArray[matrixCol].getFConst() +
864 unionArray[matrixRow].getFConst() *
865 rightUnionArray[matrixCol * matrixRows + matrixRow].getFConst());
866 }
867 }
868
869 returnType.setPrimarySize(matrixCols);
870 }
871 break;
872
873 case EOpLogicalAnd:
874 // this code is written for possible future use,
875 // will not get executed currently
876 {
877 tempConstArray = new ConstantUnion[objectSize];
878 for (size_t i = 0; i < objectSize; i++)
879 {
880 tempConstArray[i] = unionArray[i] && rightUnionArray[i];
881 }
882 }
883 break;
884
885 case EOpLogicalOr:
886 // this code is written for possible future use,
887 // will not get executed currently
888 {
889 tempConstArray = new ConstantUnion[objectSize];
890 for (size_t i = 0; i < objectSize; i++)
891 {
892 tempConstArray[i] = unionArray[i] || rightUnionArray[i];
893 }
894 }
895 break;
896
897 case EOpLogicalXor:
898 {
899 tempConstArray = new ConstantUnion[objectSize];
900 for (size_t i = 0; i < objectSize; i++)
901 {
902 switch (getType().getBasicType())
903 {
904 case EbtBool:
905 tempConstArray[i].setBConst(
906 unionArray[i] == rightUnionArray[i] ? false : true);
907 break;
908 default:
909 UNREACHABLE();
910 break;
911 }
912 }
913 }
914 break;
915
916 case EOpLessThan:
917 ASSERT(objectSize == 1);
918 tempConstArray = new ConstantUnion[1];
919 tempConstArray->setBConst(*unionArray < *rightUnionArray);
920 returnType = TType(EbtBool, EbpUndefined, EvqConst);
921 break;
922
923 case EOpGreaterThan:
924 ASSERT(objectSize == 1);
925 tempConstArray = new ConstantUnion[1];
926 tempConstArray->setBConst(*unionArray > *rightUnionArray);
927 returnType = TType(EbtBool, EbpUndefined, EvqConst);
928 break;
929
930 case EOpLessThanEqual:
931 {
932 ASSERT(objectSize == 1);
933 ConstantUnion constant;
934 constant.setBConst(*unionArray > *rightUnionArray);
935 tempConstArray = new ConstantUnion[1];
936 tempConstArray->setBConst(!constant.getBConst());
937 returnType = TType(EbtBool, EbpUndefined, EvqConst);
938 break;
939 }
940
941 case EOpGreaterThanEqual:
942 {
943 ASSERT(objectSize == 1);
944 ConstantUnion constant;
945 constant.setBConst(*unionArray < *rightUnionArray);
946 tempConstArray = new ConstantUnion[1];
947 tempConstArray->setBConst(!constant.getBConst());
948 returnType = TType(EbtBool, EbpUndefined, EvqConst);
949 break;
950 }
951
952 case EOpEqual:
953 if (getType().getBasicType() == EbtStruct)
954 {
955 if (!CompareStructure(node->getType(),
956 node->getUnionArrayPointer(),
957 unionArray))
958 {
959 boolNodeFlag = true;
960 }
961 }
962 else
963 {
964 for (size_t i = 0; i < objectSize; i++)
965 {
966 if (unionArray[i] != rightUnionArray[i])
967 {
968 boolNodeFlag = true;
969 break; // break out of for loop
970 }
971 }
972 }
973
974 tempConstArray = new ConstantUnion[1];
975 if (!boolNodeFlag)
976 {
977 tempConstArray->setBConst(true);
978 }
979 else
980 {
981 tempConstArray->setBConst(false);
982 }
983
984 tempNode = new TIntermConstantUnion(
985 tempConstArray, TType(EbtBool, EbpUndefined, EvqConst));
986 tempNode->setLine(getLine());
987
988 return tempNode;
989
990 case EOpNotEqual:
991 if (getType().getBasicType() == EbtStruct)
992 {
993 if (CompareStructure(node->getType(),
994 node->getUnionArrayPointer(),
995 unionArray))
996 {
997 boolNodeFlag = true;
998 }
999 }
1000 else
1001 {
1002 for (size_t i = 0; i < objectSize; i++)
1003 {
1004 if (unionArray[i] == rightUnionArray[i])
1005 {
1006 boolNodeFlag = true;
1007 break; // break out of for loop
1008 }
1009 }
1010 }
1011
1012 tempConstArray = new ConstantUnion[1];
1013 if (!boolNodeFlag)
1014 {
1015 tempConstArray->setBConst(true);
1016 }
1017 else
1018 {
1019 tempConstArray->setBConst(false);
1020 }
1021
1022 tempNode = new TIntermConstantUnion(
1023 tempConstArray, TType(EbtBool, EbpUndefined, EvqConst));
1024 tempNode->setLine(getLine());
1025
1026 return tempNode;
1027
1028 default:
1029 infoSink.info.message(
1030 EPrefixInternalError, getLine(),
1031 "Invalid operator for constant folding");
1032 return NULL;
1033 }
1034 tempNode = new TIntermConstantUnion(tempConstArray, returnType);
1035 tempNode->setLine(getLine());
1036
1037 return tempNode;
1038 }
1039 else
1040 {
1041 //
1042 // Do unary operations
1043 //
1044 TIntermConstantUnion *newNode = 0;
1045 ConstantUnion* tempConstArray = new ConstantUnion[objectSize];
1046 for (size_t i = 0; i < objectSize; i++)
1047 {
1048 switch(op)
1049 {
1050 case EOpNegative:
1051 switch (getType().getBasicType())
1052 {
1053 case EbtFloat:
1054 tempConstArray[i].setFConst(-unionArray[i].getFConst());
1055 break;
1056 case EbtInt:
1057 tempConstArray[i].setIConst(-unionArray[i].getIConst());
1058 break;
1059 case EbtUInt:
1060 tempConstArray[i].setUConst(static_cast<unsigned int>(
1061 -static_cast<int>(unionArray[i].getUConst())));
1062 break;
1063 default:
1064 infoSink.info.message(
1065 EPrefixInternalError, getLine(),
1066 "Unary operation not folded into constant");
1067 return NULL;
1068 }
1069 break;
1070
1071 case EOpLogicalNot:
1072 // this code is written for possible future use,
1073 // will not get executed currently
1074 switch (getType().getBasicType())
1075 {
1076 case EbtBool:
1077 tempConstArray[i].setBConst(!unionArray[i].getBConst());
1078 break;
1079 default:
1080 infoSink.info.message(
1081 EPrefixInternalError, getLine(),
1082 "Unary operation not folded into constant");
1083 return NULL;
1084 }
1085 break;
1086
1087 default:
1088 return NULL;
1089 }
1090 }
1091 newNode = new TIntermConstantUnion(tempConstArray, getType());
1092 newNode->setLine(getLine());
1093 return newNode;
1094 }
1095 }
1096
1097 // static
hash(const TString & name,ShHashFunction64 hashFunction)1098 TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunction)
1099 {
1100 if (hashFunction == NULL || name.empty())
1101 return name;
1102 khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
1103 TStringStream stream;
1104 stream << HASHED_NAME_PREFIX << std::hex << number;
1105 TString hashedName = stream.str();
1106 return hashedName;
1107 }
1108