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