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