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