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