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