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