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