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