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