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