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