blob: 49bf8cf09f9bb434e7fbc14cfeb7dd9788ca8906 [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 ||
Olli Etuahod68157f2015-01-16 12:24:17 +0200587 mOp == EOpDivAssign ||
588 mOp == EOpModAssign))
Olli Etuaho6c850472014-12-02 16:23:17 +0200589 return false;
590
Jamie Madillb1a85f42014-08-19 15:23:24 -0400591 // Operator cannot be of type pure assignment.
592 if (mOp == EOpAssign || mOp == EOpInitialize)
593 return false;
594 }
595
596 {
597 const int secondarySize = std::max(
598 mLeft->getSecondarySize(), mRight->getSecondarySize());
599 setType(TType(basicType, higherPrecision, EvqTemporary,
600 nominalSize, secondarySize));
601 }
602 break;
603
604 case EOpEqual:
605 case EOpNotEqual:
606 case EOpLessThan:
607 case EOpGreaterThan:
608 case EOpLessThanEqual:
609 case EOpGreaterThanEqual:
610 if ((mLeft->getNominalSize() != mRight->getNominalSize()) ||
611 (mLeft->getSecondarySize() != mRight->getSecondarySize()))
612 {
613 return false;
614 }
615 setType(TType(EbtBool, EbpUndefined));
616 break;
617
618 default:
619 return false;
620 }
621 return true;
622}
623
624//
625// The fold functions see if an operation on a constant can be done in place,
626// without generating run-time code.
627//
628// Returns the node to keep using, which may or may not be the node passed in.
629//
630TIntermTyped *TIntermConstantUnion::fold(
631 TOperator op, TIntermTyped *constantNode, TInfoSink &infoSink)
632{
633 ConstantUnion *unionArray = getUnionArrayPointer();
634
635 if (!unionArray)
636 return NULL;
637
638 size_t objectSize = getType().getObjectSize();
639
640 if (constantNode)
641 {
642 // binary operations
643 TIntermConstantUnion *node = constantNode->getAsConstantUnion();
644 ConstantUnion *rightUnionArray = node->getUnionArrayPointer();
645 TType returnType = getType();
646
647 if (!rightUnionArray)
648 return NULL;
649
650 // for a case like float f = 1.2 + vec4(2,3,4,5);
651 if (constantNode->getType().getObjectSize() == 1 && objectSize > 1)
652 {
653 rightUnionArray = new ConstantUnion[objectSize];
654 for (size_t i = 0; i < objectSize; ++i)
655 {
656 rightUnionArray[i] = *node->getUnionArrayPointer();
657 }
658 returnType = getType();
659 }
660 else if (constantNode->getType().getObjectSize() > 1 && objectSize == 1)
661 {
662 // for a case like float f = vec4(2,3,4,5) + 1.2;
663 unionArray = new ConstantUnion[constantNode->getType().getObjectSize()];
664 for (size_t i = 0; i < constantNode->getType().getObjectSize(); ++i)
665 {
666 unionArray[i] = *getUnionArrayPointer();
667 }
668 returnType = node->getType();
669 objectSize = constantNode->getType().getObjectSize();
670 }
671
672 ConstantUnion *tempConstArray = NULL;
673 TIntermConstantUnion *tempNode;
674
675 bool boolNodeFlag = false;
676 switch(op)
677 {
678 case EOpAdd:
679 tempConstArray = new ConstantUnion[objectSize];
680 for (size_t i = 0; i < objectSize; i++)
681 tempConstArray[i] = unionArray[i] + rightUnionArray[i];
682 break;
683 case EOpSub:
684 tempConstArray = new ConstantUnion[objectSize];
685 for (size_t i = 0; i < objectSize; i++)
686 tempConstArray[i] = unionArray[i] - rightUnionArray[i];
687 break;
688
689 case EOpMul:
690 case EOpVectorTimesScalar:
691 case EOpMatrixTimesScalar:
692 tempConstArray = new ConstantUnion[objectSize];
693 for (size_t i = 0; i < objectSize; i++)
694 tempConstArray[i] = unionArray[i] * rightUnionArray[i];
695 break;
696
697 case EOpMatrixTimesMatrix:
698 {
699 if (getType().getBasicType() != EbtFloat ||
700 node->getBasicType() != EbtFloat)
701 {
702 infoSink.info.message(
703 EPrefixInternalError, getLine(),
704 "Constant Folding cannot be done for matrix multiply");
705 return NULL;
706 }
707
708 const int leftCols = getCols();
709 const int leftRows = getRows();
710 const int rightCols = constantNode->getType().getCols();
711 const int rightRows = constantNode->getType().getRows();
712 const int resultCols = rightCols;
713 const int resultRows = leftRows;
714
715 tempConstArray = new ConstantUnion[resultCols*resultRows];
716 for (int row = 0; row < resultRows; row++)
717 {
718 for (int column = 0; column < resultCols; column++)
719 {
720 tempConstArray[resultRows * column + row].setFConst(0.0f);
721 for (int i = 0; i < leftCols; i++)
722 {
723 tempConstArray[resultRows * column + row].setFConst(
724 tempConstArray[resultRows * column + row].getFConst() +
725 unionArray[i * leftRows + row].getFConst() *
726 rightUnionArray[column * rightRows + i].getFConst());
727 }
728 }
729 }
730
731 // update return type for matrix product
732 returnType.setPrimarySize(resultCols);
733 returnType.setSecondarySize(resultRows);
734 }
735 break;
736
737 case EOpDiv:
Gregoire Payen de La Garanderiebe954a22014-12-23 00:05:28 +0000738 case EOpMod:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400739 {
740 tempConstArray = new ConstantUnion[objectSize];
741 for (size_t i = 0; i < objectSize; i++)
742 {
743 switch (getType().getBasicType())
744 {
745 case EbtFloat:
746 if (rightUnionArray[i] == 0.0f)
747 {
748 infoSink.info.message(
749 EPrefixWarning, getLine(),
750 "Divide by zero error during constant folding");
751 tempConstArray[i].setFConst(
752 unionArray[i].getFConst() < 0 ? -FLT_MAX : FLT_MAX);
753 }
754 else
755 {
756 tempConstArray[i].setFConst(
757 unionArray[i].getFConst() /
758 rightUnionArray[i].getFConst());
759 }
760 break;
761
762 case EbtInt:
763 if (rightUnionArray[i] == 0)
764 {
765 infoSink.info.message(
766 EPrefixWarning, getLine(),
767 "Divide by zero error during constant folding");
768 tempConstArray[i].setIConst(INT_MAX);
769 }
770 else
771 {
772 tempConstArray[i].setIConst(
773 unionArray[i].getIConst() /
774 rightUnionArray[i].getIConst());
775 }
776 break;
777
778 case EbtUInt:
779 if (rightUnionArray[i] == 0)
780 {
781 infoSink.info.message(
782 EPrefixWarning, getLine(),
783 "Divide by zero error during constant folding");
784 tempConstArray[i].setUConst(UINT_MAX);
785 }
786 else
787 {
788 tempConstArray[i].setUConst(
789 unionArray[i].getUConst() /
790 rightUnionArray[i].getUConst());
791 }
792 break;
793
794 default:
795 infoSink.info.message(
796 EPrefixInternalError, getLine(),
797 "Constant folding cannot be done for \"/\"");
798 return NULL;
799 }
800 }
801 }
802 break;
803
804 case EOpMatrixTimesVector:
805 {
806 if (node->getBasicType() != EbtFloat)
807 {
808 infoSink.info.message(
809 EPrefixInternalError, getLine(),
810 "Constant Folding cannot be done for matrix times vector");
811 return NULL;
812 }
813
814 const int matrixCols = getCols();
815 const int matrixRows = getRows();
816
817 tempConstArray = new ConstantUnion[matrixRows];
818
819 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
820 {
821 tempConstArray[matrixRow].setFConst(0.0f);
822 for (int col = 0; col < matrixCols; col++)
823 {
824 tempConstArray[matrixRow].setFConst(
825 tempConstArray[matrixRow].getFConst() +
826 unionArray[col * matrixRows + matrixRow].getFConst() *
827 rightUnionArray[col].getFConst());
828 }
829 }
830
831 returnType = node->getType();
832 returnType.setPrimarySize(matrixRows);
833
834 tempNode = new TIntermConstantUnion(tempConstArray, returnType);
835 tempNode->setLine(getLine());
836
837 return tempNode;
838 }
839
840 case EOpVectorTimesMatrix:
841 {
842 if (getType().getBasicType() != EbtFloat)
843 {
844 infoSink.info.message(
845 EPrefixInternalError, getLine(),
846 "Constant Folding cannot be done for vector times matrix");
847 return NULL;
848 }
849
850 const int matrixCols = constantNode->getType().getCols();
851 const int matrixRows = constantNode->getType().getRows();
852
853 tempConstArray = new ConstantUnion[matrixCols];
854
855 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
856 {
857 tempConstArray[matrixCol].setFConst(0.0f);
858 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
859 {
860 tempConstArray[matrixCol].setFConst(
861 tempConstArray[matrixCol].getFConst() +
862 unionArray[matrixRow].getFConst() *
863 rightUnionArray[matrixCol * matrixRows + matrixRow].getFConst());
864 }
865 }
866
867 returnType.setPrimarySize(matrixCols);
868 }
869 break;
870
871 case EOpLogicalAnd:
872 // this code is written for possible future use,
873 // will not get executed currently
874 {
875 tempConstArray = new ConstantUnion[objectSize];
876 for (size_t i = 0; i < objectSize; i++)
877 {
878 tempConstArray[i] = unionArray[i] && rightUnionArray[i];
879 }
880 }
881 break;
882
883 case EOpLogicalOr:
884 // this code is written for possible future use,
885 // will not get executed currently
886 {
887 tempConstArray = new ConstantUnion[objectSize];
888 for (size_t i = 0; i < objectSize; i++)
889 {
890 tempConstArray[i] = unionArray[i] || rightUnionArray[i];
891 }
892 }
893 break;
894
895 case EOpLogicalXor:
896 {
897 tempConstArray = new ConstantUnion[objectSize];
898 for (size_t i = 0; i < objectSize; i++)
899 {
900 switch (getType().getBasicType())
901 {
902 case EbtBool:
903 tempConstArray[i].setBConst(
904 unionArray[i] == rightUnionArray[i] ? false : true);
905 break;
906 default:
907 UNREACHABLE();
908 break;
909 }
910 }
911 }
912 break;
913
914 case EOpLessThan:
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 EOpGreaterThan:
922 ASSERT(objectSize == 1);
923 tempConstArray = new ConstantUnion[1];
924 tempConstArray->setBConst(*unionArray > *rightUnionArray);
925 returnType = TType(EbtBool, EbpUndefined, EvqConst);
926 break;
927
928 case EOpLessThanEqual:
929 {
930 ASSERT(objectSize == 1);
931 ConstantUnion constant;
932 constant.setBConst(*unionArray > *rightUnionArray);
933 tempConstArray = new ConstantUnion[1];
934 tempConstArray->setBConst(!constant.getBConst());
935 returnType = TType(EbtBool, EbpUndefined, EvqConst);
936 break;
937 }
938
939 case EOpGreaterThanEqual:
940 {
941 ASSERT(objectSize == 1);
942 ConstantUnion constant;
943 constant.setBConst(*unionArray < *rightUnionArray);
944 tempConstArray = new ConstantUnion[1];
945 tempConstArray->setBConst(!constant.getBConst());
946 returnType = TType(EbtBool, EbpUndefined, EvqConst);
947 break;
948 }
949
950 case EOpEqual:
951 if (getType().getBasicType() == EbtStruct)
952 {
953 if (!CompareStructure(node->getType(),
954 node->getUnionArrayPointer(),
955 unionArray))
956 {
957 boolNodeFlag = true;
958 }
959 }
960 else
961 {
962 for (size_t i = 0; i < objectSize; i++)
963 {
964 if (unionArray[i] != rightUnionArray[i])
965 {
966 boolNodeFlag = true;
967 break; // break out of for loop
968 }
969 }
970 }
971
972 tempConstArray = new ConstantUnion[1];
973 if (!boolNodeFlag)
974 {
975 tempConstArray->setBConst(true);
976 }
977 else
978 {
979 tempConstArray->setBConst(false);
980 }
981
982 tempNode = new TIntermConstantUnion(
983 tempConstArray, TType(EbtBool, EbpUndefined, EvqConst));
984 tempNode->setLine(getLine());
985
986 return tempNode;
987
988 case EOpNotEqual:
989 if (getType().getBasicType() == EbtStruct)
990 {
991 if (CompareStructure(node->getType(),
992 node->getUnionArrayPointer(),
993 unionArray))
994 {
995 boolNodeFlag = true;
996 }
997 }
998 else
999 {
1000 for (size_t i = 0; i < objectSize; i++)
1001 {
1002 if (unionArray[i] == rightUnionArray[i])
1003 {
1004 boolNodeFlag = true;
1005 break; // break out of for loop
1006 }
1007 }
1008 }
1009
1010 tempConstArray = new ConstantUnion[1];
1011 if (!boolNodeFlag)
1012 {
1013 tempConstArray->setBConst(true);
1014 }
1015 else
1016 {
1017 tempConstArray->setBConst(false);
1018 }
1019
1020 tempNode = new TIntermConstantUnion(
1021 tempConstArray, TType(EbtBool, EbpUndefined, EvqConst));
1022 tempNode->setLine(getLine());
1023
1024 return tempNode;
1025
1026 default:
1027 infoSink.info.message(
1028 EPrefixInternalError, getLine(),
1029 "Invalid operator for constant folding");
1030 return NULL;
1031 }
1032 tempNode = new TIntermConstantUnion(tempConstArray, returnType);
1033 tempNode->setLine(getLine());
1034
1035 return tempNode;
1036 }
1037 else
1038 {
1039 //
1040 // Do unary operations
1041 //
1042 TIntermConstantUnion *newNode = 0;
1043 ConstantUnion* tempConstArray = new ConstantUnion[objectSize];
1044 for (size_t i = 0; i < objectSize; i++)
1045 {
1046 switch(op)
1047 {
1048 case EOpNegative:
1049 switch (getType().getBasicType())
1050 {
1051 case EbtFloat:
1052 tempConstArray[i].setFConst(-unionArray[i].getFConst());
1053 break;
1054 case EbtInt:
1055 tempConstArray[i].setIConst(-unionArray[i].getIConst());
1056 break;
1057 case EbtUInt:
1058 tempConstArray[i].setUConst(static_cast<unsigned int>(
1059 -static_cast<int>(unionArray[i].getUConst())));
1060 break;
1061 default:
1062 infoSink.info.message(
1063 EPrefixInternalError, getLine(),
1064 "Unary operation not folded into constant");
1065 return NULL;
1066 }
1067 break;
1068
Zhenyao Mode1e00e2014-10-09 16:55:32 -07001069 case EOpPositive:
1070 switch (getType().getBasicType())
1071 {
1072 case EbtFloat:
1073 tempConstArray[i].setFConst(unionArray[i].getFConst());
1074 break;
1075 case EbtInt:
1076 tempConstArray[i].setIConst(unionArray[i].getIConst());
1077 break;
1078 case EbtUInt:
1079 tempConstArray[i].setUConst(static_cast<unsigned int>(
1080 static_cast<int>(unionArray[i].getUConst())));
1081 break;
1082 default:
1083 infoSink.info.message(
1084 EPrefixInternalError, getLine(),
1085 "Unary operation not folded into constant");
1086 return NULL;
1087 }
1088 break;
1089
Jamie Madillb1a85f42014-08-19 15:23:24 -04001090 case EOpLogicalNot:
1091 // this code is written for possible future use,
1092 // will not get executed currently
1093 switch (getType().getBasicType())
1094 {
1095 case EbtBool:
1096 tempConstArray[i].setBConst(!unionArray[i].getBConst());
1097 break;
1098 default:
1099 infoSink.info.message(
1100 EPrefixInternalError, getLine(),
1101 "Unary operation not folded into constant");
1102 return NULL;
1103 }
1104 break;
1105
1106 default:
1107 return NULL;
1108 }
1109 }
1110 newNode = new TIntermConstantUnion(tempConstArray, getType());
1111 newNode->setLine(getLine());
1112 return newNode;
1113 }
1114}
1115
1116// static
1117TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunction)
1118{
1119 if (hashFunction == NULL || name.empty())
1120 return name;
1121 khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
1122 TStringStream stream;
1123 stream << HASHED_NAME_PREFIX << std::hex << number;
1124 TString hashedName = stream.str();
1125 return hashedName;
1126}
Olli Etuaho853dc1a2014-11-06 17:25:48 +02001127
1128void TIntermTraverser::updateTree()
1129{
1130 for (size_t ii = 0; ii < mReplacements.size(); ++ii)
1131 {
1132 const NodeUpdateEntry& entry = mReplacements[ii];
1133 ASSERT(entry.parent);
1134 bool replaced = entry.parent->replaceChildNode(
1135 entry.original, entry.replacement);
1136 ASSERT(replaced);
1137
1138 if (!entry.originalBecomesChildOfReplacement)
1139 {
1140 // In AST traversing, a parent is visited before its children.
1141 // After we replace a node, if an immediate child is to
1142 // be replaced, we need to make sure we don't update the replaced
1143 // node; instead, we update the replacement node.
1144 for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj)
1145 {
1146 NodeUpdateEntry& entry2 = mReplacements[jj];
1147 if (entry2.parent == entry.original)
1148 entry2.parent = entry.replacement;
1149 }
1150 }
1151 }
1152}