blob: 2c291448509cdc9241f91e0a7cd8711395dca847 [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>
Arun Patole9dea48f2015-04-02 11:45:09 +053013#include <math.h>
Arun Patole97dc22e2015-04-06 17:35:38 +053014#include <stdlib.h>
Jamie Madillb1a85f42014-08-19 15:23:24 -040015#include <algorithm>
16
17#include "compiler/translator/HashNames.h"
18#include "compiler/translator/IntermNode.h"
19#include "compiler/translator/SymbolTable.h"
20
21namespace
22{
23
Arun Patole9dea48f2015-04-02 11:45:09 +053024const float kPi = 3.14159265358979323846f;
25const float kDegreesToRadiansMultiplier = kPi / 180.0f;
26const float kRadiansToDegreesMultiplier = 180.0f / kPi;
27
Jamie Madillb1a85f42014-08-19 15:23:24 -040028TPrecision GetHigherPrecision(TPrecision left, TPrecision right)
29{
30 return left > right ? left : right;
31}
32
33bool ValidateMultiplication(TOperator op, const TType &left, const TType &right)
34{
35 switch (op)
36 {
37 case EOpMul:
38 case EOpMulAssign:
39 return left.getNominalSize() == right.getNominalSize() &&
40 left.getSecondarySize() == right.getSecondarySize();
41 case EOpVectorTimesScalar:
42 case EOpVectorTimesScalarAssign:
43 return true;
44 case EOpVectorTimesMatrix:
45 return left.getNominalSize() == right.getRows();
46 case EOpVectorTimesMatrixAssign:
47 return left.getNominalSize() == right.getRows() &&
48 left.getNominalSize() == right.getCols();
49 case EOpMatrixTimesVector:
50 return left.getCols() == right.getNominalSize();
51 case EOpMatrixTimesScalar:
52 case EOpMatrixTimesScalarAssign:
53 return true;
54 case EOpMatrixTimesMatrix:
55 return left.getCols() == right.getRows();
56 case EOpMatrixTimesMatrixAssign:
57 return left.getCols() == right.getCols() &&
58 left.getRows() == right.getRows();
59
60 default:
61 UNREACHABLE();
62 return false;
63 }
64}
65
66bool CompareStructure(const TType& leftNodeType,
Jamie Madillb11e2482015-05-04 14:21:22 -040067 const TConstantUnion *rightUnionArray,
68 const TConstantUnion *leftUnionArray);
Jamie Madillb1a85f42014-08-19 15:23:24 -040069
70bool CompareStruct(const TType &leftNodeType,
Jamie Madillb11e2482015-05-04 14:21:22 -040071 const TConstantUnion *rightUnionArray,
72 const TConstantUnion *leftUnionArray)
Jamie Madillb1a85f42014-08-19 15:23:24 -040073{
74 const TFieldList &fields = leftNodeType.getStruct()->fields();
75
76 size_t structSize = fields.size();
77 size_t index = 0;
78
79 for (size_t j = 0; j < structSize; j++)
80 {
81 size_t size = fields[j]->type()->getObjectSize();
82 for (size_t i = 0; i < size; i++)
83 {
84 if (fields[j]->type()->getBasicType() == EbtStruct)
85 {
86 if (!CompareStructure(*fields[j]->type(),
87 &rightUnionArray[index],
88 &leftUnionArray[index]))
89 {
90 return false;
91 }
92 }
93 else
94 {
95 if (leftUnionArray[index] != rightUnionArray[index])
96 return false;
97 index++;
98 }
99 }
100 }
101 return true;
102}
103
104bool CompareStructure(const TType &leftNodeType,
Jamie Madillb11e2482015-05-04 14:21:22 -0400105 const TConstantUnion *rightUnionArray,
106 const TConstantUnion *leftUnionArray)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400107{
108 if (leftNodeType.isArray())
109 {
110 TType typeWithoutArrayness = leftNodeType;
111 typeWithoutArrayness.clearArrayness();
112
113 size_t arraySize = leftNodeType.getArraySize();
114
115 for (size_t i = 0; i < arraySize; ++i)
116 {
117 size_t offset = typeWithoutArrayness.getObjectSize() * i;
118 if (!CompareStruct(typeWithoutArrayness,
119 &rightUnionArray[offset],
120 &leftUnionArray[offset]))
121 {
122 return false;
123 }
124 }
125 }
126 else
127 {
128 return CompareStruct(leftNodeType, rightUnionArray, leftUnionArray);
129 }
130 return true;
131}
132
133} // namespace anonymous
134
135
136////////////////////////////////////////////////////////////////
137//
138// Member functions of the nodes used for building the tree.
139//
140////////////////////////////////////////////////////////////////
141
Olli Etuahod2a67b92014-10-21 16:42:57 +0300142void TIntermTyped::setTypePreservePrecision(const TType &t)
143{
144 TPrecision precision = getPrecision();
145 mType = t;
146 ASSERT(mType.getBasicType() != EbtBool || precision == EbpUndefined);
147 mType.setPrecision(precision);
148}
149
Jamie Madillb1a85f42014-08-19 15:23:24 -0400150#define REPLACE_IF_IS(node, type, original, replacement) \
151 if (node == original) { \
152 node = static_cast<type *>(replacement); \
153 return true; \
154 }
155
156bool TIntermLoop::replaceChildNode(
157 TIntermNode *original, TIntermNode *replacement)
158{
159 REPLACE_IF_IS(mInit, TIntermNode, original, replacement);
160 REPLACE_IF_IS(mCond, TIntermTyped, original, replacement);
161 REPLACE_IF_IS(mExpr, TIntermTyped, original, replacement);
162 REPLACE_IF_IS(mBody, TIntermNode, original, replacement);
163 return false;
164}
165
Jamie Madillb1a85f42014-08-19 15:23:24 -0400166bool TIntermBranch::replaceChildNode(
167 TIntermNode *original, TIntermNode *replacement)
168{
169 REPLACE_IF_IS(mExpression, TIntermTyped, original, replacement);
170 return false;
171}
172
Jamie Madillb1a85f42014-08-19 15:23:24 -0400173bool TIntermBinary::replaceChildNode(
174 TIntermNode *original, TIntermNode *replacement)
175{
176 REPLACE_IF_IS(mLeft, TIntermTyped, original, replacement);
177 REPLACE_IF_IS(mRight, TIntermTyped, original, replacement);
178 return false;
179}
180
Jamie Madillb1a85f42014-08-19 15:23:24 -0400181bool TIntermUnary::replaceChildNode(
182 TIntermNode *original, TIntermNode *replacement)
183{
184 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
185 return false;
186}
187
Jamie Madillb1a85f42014-08-19 15:23:24 -0400188bool TIntermAggregate::replaceChildNode(
189 TIntermNode *original, TIntermNode *replacement)
190{
191 for (size_t ii = 0; ii < mSequence.size(); ++ii)
192 {
193 REPLACE_IF_IS(mSequence[ii], TIntermNode, original, replacement);
194 }
195 return false;
196}
197
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300198bool TIntermAggregate::replaceChildNodeWithMultiple(TIntermNode *original, TIntermSequence replacements)
199{
200 for (auto it = mSequence.begin(); it < mSequence.end(); ++it)
201 {
202 if (*it == original)
203 {
204 it = mSequence.erase(it);
Olli Etuaho8fee0ab2015-04-23 14:52:46 +0300205 mSequence.insert(it, replacements.begin(), replacements.end());
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300206 return true;
207 }
208 }
209 return false;
210}
211
Olli Etuahoa6f22092015-05-08 18:31:10 +0300212bool TIntermAggregate::insertChildNodes(TIntermSequence::size_type position, TIntermSequence insertions)
213{
214 TIntermSequence::size_type itPosition = 0;
215 for (auto it = mSequence.begin(); it < mSequence.end(); ++it)
216 {
217 if (itPosition == position)
218 {
219 mSequence.insert(it, insertions.begin(), insertions.end());
220 return true;
221 }
222 ++itPosition;
223 }
224 return false;
225}
226
Olli Etuahod2a67b92014-10-21 16:42:57 +0300227void TIntermAggregate::setPrecisionFromChildren()
228{
229 if (getBasicType() == EbtBool)
230 {
231 mType.setPrecision(EbpUndefined);
232 return;
233 }
234
235 TPrecision precision = EbpUndefined;
236 TIntermSequence::iterator childIter = mSequence.begin();
237 while (childIter != mSequence.end())
238 {
239 TIntermTyped *typed = (*childIter)->getAsTyped();
240 if (typed)
241 precision = GetHigherPrecision(typed->getPrecision(), precision);
242 ++childIter;
243 }
244 mType.setPrecision(precision);
245}
246
247void TIntermAggregate::setBuiltInFunctionPrecision()
248{
249 // All built-ins returning bool should be handled as ops, not functions.
250 ASSERT(getBasicType() != EbtBool);
251
252 TPrecision precision = EbpUndefined;
253 TIntermSequence::iterator childIter = mSequence.begin();
254 while (childIter != mSequence.end())
255 {
256 TIntermTyped *typed = (*childIter)->getAsTyped();
257 // ESSL spec section 8: texture functions get their precision from the sampler.
258 if (typed && IsSampler(typed->getBasicType()))
259 {
260 precision = typed->getPrecision();
261 break;
262 }
263 ++childIter;
264 }
265 // ESSL 3.0 spec section 8: textureSize always gets highp precision.
266 // All other functions that take a sampler are assumed to be texture functions.
267 if (mName.find("textureSize") == 0)
268 mType.setPrecision(EbpHigh);
269 else
270 mType.setPrecision(precision);
271}
272
Jamie Madillb1a85f42014-08-19 15:23:24 -0400273bool TIntermSelection::replaceChildNode(
274 TIntermNode *original, TIntermNode *replacement)
275{
276 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
277 REPLACE_IF_IS(mTrueBlock, TIntermNode, original, replacement);
278 REPLACE_IF_IS(mFalseBlock, TIntermNode, original, replacement);
279 return false;
280}
281
Olli Etuahoa3a36662015-02-17 13:46:51 +0200282bool TIntermSwitch::replaceChildNode(
283 TIntermNode *original, TIntermNode *replacement)
284{
285 REPLACE_IF_IS(mInit, TIntermTyped, original, replacement);
286 REPLACE_IF_IS(mStatementList, TIntermAggregate, original, replacement);
287 return false;
288}
289
290bool TIntermCase::replaceChildNode(
291 TIntermNode *original, TIntermNode *replacement)
292{
293 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
294 return false;
295}
296
Jamie Madillb1a85f42014-08-19 15:23:24 -0400297//
298// Say whether or not an operation node changes the value of a variable.
299//
300bool TIntermOperator::isAssignment() const
301{
302 switch (mOp)
303 {
304 case EOpPostIncrement:
305 case EOpPostDecrement:
306 case EOpPreIncrement:
307 case EOpPreDecrement:
308 case EOpAssign:
309 case EOpAddAssign:
310 case EOpSubAssign:
311 case EOpMulAssign:
312 case EOpVectorTimesMatrixAssign:
313 case EOpVectorTimesScalarAssign:
314 case EOpMatrixTimesScalarAssign:
315 case EOpMatrixTimesMatrixAssign:
316 case EOpDivAssign:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200317 case EOpIModAssign:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200318 case EOpBitShiftLeftAssign:
319 case EOpBitShiftRightAssign:
320 case EOpBitwiseAndAssign:
321 case EOpBitwiseXorAssign:
322 case EOpBitwiseOrAssign:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400323 return true;
324 default:
325 return false;
326 }
327}
328
329//
330// returns true if the operator is for one of the constructors
331//
332bool TIntermOperator::isConstructor() const
333{
334 switch (mOp)
335 {
336 case EOpConstructVec2:
337 case EOpConstructVec3:
338 case EOpConstructVec4:
339 case EOpConstructMat2:
340 case EOpConstructMat3:
341 case EOpConstructMat4:
342 case EOpConstructFloat:
343 case EOpConstructIVec2:
344 case EOpConstructIVec3:
345 case EOpConstructIVec4:
346 case EOpConstructInt:
347 case EOpConstructUVec2:
348 case EOpConstructUVec3:
349 case EOpConstructUVec4:
350 case EOpConstructUInt:
351 case EOpConstructBVec2:
352 case EOpConstructBVec3:
353 case EOpConstructBVec4:
354 case EOpConstructBool:
355 case EOpConstructStruct:
356 return true;
357 default:
358 return false;
359 }
360}
361
362//
363// Make sure the type of a unary operator is appropriate for its
364// combination of operation and operand type.
365//
Olli Etuahof6c694b2015-03-26 14:50:53 +0200366void TIntermUnary::promote(const TType *funcReturnType)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400367{
368 switch (mOp)
369 {
Olli Etuahodca3e792015-03-26 13:24:04 +0200370 case EOpFloatBitsToInt:
371 case EOpFloatBitsToUint:
Olli Etuahoe8d2c072015-01-08 16:33:54 +0200372 case EOpIntBitsToFloat:
373 case EOpUintBitsToFloat:
Olli Etuahodca3e792015-03-26 13:24:04 +0200374 case EOpPackSnorm2x16:
375 case EOpPackUnorm2x16:
376 case EOpPackHalf2x16:
Olli Etuaho7700ff62015-01-15 12:16:29 +0200377 case EOpUnpackSnorm2x16:
378 case EOpUnpackUnorm2x16:
Olli Etuahodca3e792015-03-26 13:24:04 +0200379 mType.setPrecision(EbpHigh);
Arun Patole6b19d762015-02-19 09:40:39 +0530380 break;
Olli Etuahodca3e792015-03-26 13:24:04 +0200381 case EOpUnpackHalf2x16:
382 mType.setPrecision(EbpMedium);
383 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400384 default:
Olli Etuahodca3e792015-03-26 13:24:04 +0200385 setType(mOperand->getType());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400386 }
387
Olli Etuahof6c694b2015-03-26 14:50:53 +0200388 if (funcReturnType != nullptr)
389 {
390 if (funcReturnType->getBasicType() == EbtBool)
391 {
392 // Bool types should not have precision.
393 setType(*funcReturnType);
394 }
395 else
396 {
397 // Precision of the node has been set based on the operand.
398 setTypePreservePrecision(*funcReturnType);
399 }
400 }
401
Jamie Madillb1a85f42014-08-19 15:23:24 -0400402 mType.setQualifier(EvqTemporary);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400403}
404
405//
406// Establishes the type of the resultant operation, as well as
407// makes the operator the correct one for the operands.
408//
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200409// For lots of operations it should already be established that the operand
410// combination is valid, but returns false if operator can't work on operands.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400411//
412bool TIntermBinary::promote(TInfoSink &infoSink)
413{
Olli Etuahoe79904c2015-03-18 16:56:42 +0200414 ASSERT(mLeft->isArray() == mRight->isArray());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400415
Jamie Madillb1a85f42014-08-19 15:23:24 -0400416 //
417 // Base assumption: just make the type the same as the left
418 // operand. Then only deviations from this need be coded.
419 //
420 setType(mLeft->getType());
421
422 // The result gets promoted to the highest precision.
423 TPrecision higherPrecision = GetHigherPrecision(
424 mLeft->getPrecision(), mRight->getPrecision());
425 getTypePointer()->setPrecision(higherPrecision);
426
427 // Binary operations results in temporary variables unless both
428 // operands are const.
429 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
430 {
431 getTypePointer()->setQualifier(EvqTemporary);
432 }
433
434 const int nominalSize =
435 std::max(mLeft->getNominalSize(), mRight->getNominalSize());
436
437 //
438 // All scalars or structs. Code after this test assumes this case is removed!
439 //
440 if (nominalSize == 1)
441 {
442 switch (mOp)
443 {
444 //
445 // Promote to conditional
446 //
447 case EOpEqual:
448 case EOpNotEqual:
449 case EOpLessThan:
450 case EOpGreaterThan:
451 case EOpLessThanEqual:
452 case EOpGreaterThanEqual:
453 setType(TType(EbtBool, EbpUndefined));
454 break;
455
456 //
457 // And and Or operate on conditionals
458 //
459 case EOpLogicalAnd:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200460 case EOpLogicalXor:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400461 case EOpLogicalOr:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200462 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400463 setType(TType(EbtBool, EbpUndefined));
464 break;
465
466 default:
467 break;
468 }
469 return true;
470 }
471
472 // If we reach here, at least one of the operands is vector or matrix.
473 // The other operand could be a scalar, vector, or matrix.
474 // Can these two operands be combined?
475 //
476 TBasicType basicType = mLeft->getBasicType();
477 switch (mOp)
478 {
479 case EOpMul:
480 if (!mLeft->isMatrix() && mRight->isMatrix())
481 {
482 if (mLeft->isVector())
483 {
484 mOp = EOpVectorTimesMatrix;
485 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700486 static_cast<unsigned char>(mRight->getCols()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400487 }
488 else
489 {
490 mOp = EOpMatrixTimesScalar;
491 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700492 static_cast<unsigned char>(mRight->getCols()), static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400493 }
494 }
495 else if (mLeft->isMatrix() && !mRight->isMatrix())
496 {
497 if (mRight->isVector())
498 {
499 mOp = EOpMatrixTimesVector;
500 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700501 static_cast<unsigned char>(mLeft->getRows()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400502 }
503 else
504 {
505 mOp = EOpMatrixTimesScalar;
506 }
507 }
508 else if (mLeft->isMatrix() && mRight->isMatrix())
509 {
510 mOp = EOpMatrixTimesMatrix;
511 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700512 static_cast<unsigned char>(mRight->getCols()), static_cast<unsigned char>(mLeft->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400513 }
514 else if (!mLeft->isMatrix() && !mRight->isMatrix())
515 {
516 if (mLeft->isVector() && mRight->isVector())
517 {
518 // leave as component product
519 }
520 else if (mLeft->isVector() || mRight->isVector())
521 {
522 mOp = EOpVectorTimesScalar;
523 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700524 static_cast<unsigned char>(nominalSize), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400525 }
526 }
527 else
528 {
529 infoSink.info.message(EPrefixInternalError, getLine(),
530 "Missing elses");
531 return false;
532 }
533
534 if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType()))
535 {
536 return false;
537 }
538 break;
539
540 case EOpMulAssign:
541 if (!mLeft->isMatrix() && mRight->isMatrix())
542 {
543 if (mLeft->isVector())
544 {
545 mOp = EOpVectorTimesMatrixAssign;
546 }
547 else
548 {
549 return false;
550 }
551 }
552 else if (mLeft->isMatrix() && !mRight->isMatrix())
553 {
554 if (mRight->isVector())
555 {
556 return false;
557 }
558 else
559 {
560 mOp = EOpMatrixTimesScalarAssign;
561 }
562 }
563 else if (mLeft->isMatrix() && mRight->isMatrix())
564 {
565 mOp = EOpMatrixTimesMatrixAssign;
566 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700567 static_cast<unsigned char>(mRight->getCols()), static_cast<unsigned char>(mLeft->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400568 }
569 else if (!mLeft->isMatrix() && !mRight->isMatrix())
570 {
571 if (mLeft->isVector() && mRight->isVector())
572 {
573 // leave as component product
574 }
575 else if (mLeft->isVector() || mRight->isVector())
576 {
577 if (!mLeft->isVector())
578 return false;
579 mOp = EOpVectorTimesScalarAssign;
580 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700581 static_cast<unsigned char>(mLeft->getNominalSize()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400582 }
583 }
584 else
585 {
586 infoSink.info.message(EPrefixInternalError, getLine(),
587 "Missing elses");
588 return false;
589 }
590
591 if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType()))
592 {
593 return false;
594 }
595 break;
596
597 case EOpAssign:
598 case EOpInitialize:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200599 // No more additional checks are needed.
600 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
601 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
602 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400603 case EOpAdd:
604 case EOpSub:
605 case EOpDiv:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200606 case EOpIMod:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200607 case EOpBitShiftLeft:
608 case EOpBitShiftRight:
609 case EOpBitwiseAnd:
610 case EOpBitwiseXor:
611 case EOpBitwiseOr:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400612 case EOpAddAssign:
613 case EOpSubAssign:
614 case EOpDivAssign:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200615 case EOpIModAssign:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200616 case EOpBitShiftLeftAssign:
617 case EOpBitShiftRightAssign:
618 case EOpBitwiseAndAssign:
619 case EOpBitwiseXorAssign:
620 case EOpBitwiseOrAssign:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400621 if ((mLeft->isMatrix() && mRight->isVector()) ||
622 (mLeft->isVector() && mRight->isMatrix()))
623 {
624 return false;
625 }
626
627 // Are the sizes compatible?
628 if (mLeft->getNominalSize() != mRight->getNominalSize() ||
629 mLeft->getSecondarySize() != mRight->getSecondarySize())
630 {
Olli Etuaho6c850472014-12-02 16:23:17 +0200631 // If the nominal sizes of operands do not match:
632 // One of them must be a scalar.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400633 if (!mLeft->isScalar() && !mRight->isScalar())
634 return false;
635
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200636 // In the case of compound assignment other than multiply-assign,
637 // the right side needs to be a scalar. Otherwise a vector/matrix
638 // would be assigned to a scalar. A scalar can't be shifted by a
639 // vector either.
Olli Etuaho6c850472014-12-02 16:23:17 +0200640 if (!mRight->isScalar() &&
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200641 (isAssignment() ||
642 mOp == EOpBitShiftLeft ||
643 mOp == EOpBitShiftRight))
Olli Etuaho6c850472014-12-02 16:23:17 +0200644 return false;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400645 }
646
647 {
648 const int secondarySize = std::max(
649 mLeft->getSecondarySize(), mRight->getSecondarySize());
650 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700651 static_cast<unsigned char>(nominalSize), static_cast<unsigned char>(secondarySize)));
Olli Etuahoe79904c2015-03-18 16:56:42 +0200652 if (mLeft->isArray())
653 {
654 ASSERT(mLeft->getArraySize() == mRight->getArraySize());
655 mType.setArraySize(mLeft->getArraySize());
656 }
Jamie Madillb1a85f42014-08-19 15:23:24 -0400657 }
658 break;
659
660 case EOpEqual:
661 case EOpNotEqual:
662 case EOpLessThan:
663 case EOpGreaterThan:
664 case EOpLessThanEqual:
665 case EOpGreaterThanEqual:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200666 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
667 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400668 setType(TType(EbtBool, EbpUndefined));
669 break;
670
671 default:
672 return false;
673 }
674 return true;
675}
676
677//
678// The fold functions see if an operation on a constant can be done in place,
679// without generating run-time code.
680//
681// Returns the node to keep using, which may or may not be the node passed in.
682//
683TIntermTyped *TIntermConstantUnion::fold(
Olli Etuaho2cb7b832015-04-23 20:27:44 +0300684 TOperator op, TIntermConstantUnion *rightNode, TInfoSink &infoSink)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400685{
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400686 TConstantUnion *unionArray = getUnionArrayPointer();
Jamie Madillb1a85f42014-08-19 15:23:24 -0400687
688 if (!unionArray)
Arun Patolefddc2112015-04-22 13:28:10 +0530689 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400690
691 size_t objectSize = getType().getObjectSize();
692
Olli Etuaho2cb7b832015-04-23 20:27:44 +0300693 if (rightNode)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400694 {
695 // binary operations
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400696 TConstantUnion *rightUnionArray = rightNode->getUnionArrayPointer();
Jamie Madillb1a85f42014-08-19 15:23:24 -0400697 TType returnType = getType();
698
699 if (!rightUnionArray)
Arun Patolefddc2112015-04-22 13:28:10 +0530700 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400701
Olli Etuaho2cb7b832015-04-23 20:27:44 +0300702 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
703 if (rightNode->getType().getObjectSize() == 1 && objectSize > 1)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400704 {
Geoff Lang95d34aa2015-05-13 19:44:31 +0000705 rightUnionArray = new TConstantUnion[objectSize];
706 for (size_t i = 0; i < objectSize; ++i)
707 {
708 rightUnionArray[i] = *rightNode->getUnionArrayPointer();
709 }
Jamie Madillb1a85f42014-08-19 15:23:24 -0400710 returnType = getType();
711 }
Olli Etuaho2cb7b832015-04-23 20:27:44 +0300712 else if (rightNode->getType().getObjectSize() > 1 && objectSize == 1)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400713 {
Olli Etuaho2cb7b832015-04-23 20:27:44 +0300714 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
Geoff Lang95d34aa2015-05-13 19:44:31 +0000715 unionArray = new TConstantUnion[rightNode->getType().getObjectSize()];
716 for (size_t i = 0; i < rightNode->getType().getObjectSize(); ++i)
717 {
718 unionArray[i] = *getUnionArrayPointer();
719 }
Olli Etuaho2cb7b832015-04-23 20:27:44 +0300720 returnType = rightNode->getType();
721 objectSize = rightNode->getType().getObjectSize();
Jamie Madillb1a85f42014-08-19 15:23:24 -0400722 }
723
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400724 TConstantUnion *tempConstArray = nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400725 TIntermConstantUnion *tempNode;
726
727 bool boolNodeFlag = false;
728 switch(op)
729 {
730 case EOpAdd:
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400731 tempConstArray = new TConstantUnion[objectSize];
Jamie Madillb1a85f42014-08-19 15:23:24 -0400732 for (size_t i = 0; i < objectSize; i++)
733 tempConstArray[i] = unionArray[i] + rightUnionArray[i];
734 break;
735 case EOpSub:
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400736 tempConstArray = new TConstantUnion[objectSize];
Jamie Madillb1a85f42014-08-19 15:23:24 -0400737 for (size_t i = 0; i < objectSize; i++)
738 tempConstArray[i] = unionArray[i] - rightUnionArray[i];
739 break;
740
741 case EOpMul:
742 case EOpVectorTimesScalar:
743 case EOpMatrixTimesScalar:
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400744 tempConstArray = new TConstantUnion[objectSize];
Jamie Madillb1a85f42014-08-19 15:23:24 -0400745 for (size_t i = 0; i < objectSize; i++)
746 tempConstArray[i] = unionArray[i] * rightUnionArray[i];
747 break;
748
749 case EOpMatrixTimesMatrix:
750 {
751 if (getType().getBasicType() != EbtFloat ||
Olli Etuaho2cb7b832015-04-23 20:27:44 +0300752 rightNode->getBasicType() != EbtFloat)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400753 {
754 infoSink.info.message(
755 EPrefixInternalError, getLine(),
756 "Constant Folding cannot be done for matrix multiply");
Arun Patolefddc2112015-04-22 13:28:10 +0530757 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400758 }
759
760 const int leftCols = getCols();
761 const int leftRows = getRows();
Olli Etuaho2cb7b832015-04-23 20:27:44 +0300762 const int rightCols = rightNode->getType().getCols();
763 const int rightRows = rightNode->getType().getRows();
Jamie Madillb1a85f42014-08-19 15:23:24 -0400764 const int resultCols = rightCols;
765 const int resultRows = leftRows;
766
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400767 tempConstArray = new TConstantUnion[resultCols * resultRows];
Jamie Madillb1a85f42014-08-19 15:23:24 -0400768 for (int row = 0; row < resultRows; row++)
769 {
770 for (int column = 0; column < resultCols; column++)
771 {
772 tempConstArray[resultRows * column + row].setFConst(0.0f);
773 for (int i = 0; i < leftCols; i++)
774 {
775 tempConstArray[resultRows * column + row].setFConst(
776 tempConstArray[resultRows * column + row].getFConst() +
777 unionArray[i * leftRows + row].getFConst() *
778 rightUnionArray[column * rightRows + i].getFConst());
779 }
780 }
781 }
782
783 // update return type for matrix product
Minmin Gong794e0002015-04-07 18:31:54 -0700784 returnType.setPrimarySize(static_cast<unsigned char>(resultCols));
785 returnType.setSecondarySize(static_cast<unsigned char>(resultRows));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400786 }
787 break;
788
789 case EOpDiv:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200790 case EOpIMod:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400791 {
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400792 tempConstArray = new TConstantUnion[objectSize];
Jamie Madillb1a85f42014-08-19 15:23:24 -0400793 for (size_t i = 0; i < objectSize; i++)
794 {
795 switch (getType().getBasicType())
796 {
797 case EbtFloat:
798 if (rightUnionArray[i] == 0.0f)
799 {
800 infoSink.info.message(
801 EPrefixWarning, getLine(),
802 "Divide by zero error during constant folding");
803 tempConstArray[i].setFConst(
804 unionArray[i].getFConst() < 0 ? -FLT_MAX : FLT_MAX);
805 }
806 else
807 {
Olli Etuaho3eab00a2015-02-12 16:02:39 +0200808 ASSERT(op == EOpDiv);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400809 tempConstArray[i].setFConst(
810 unionArray[i].getFConst() /
811 rightUnionArray[i].getFConst());
812 }
813 break;
814
815 case EbtInt:
816 if (rightUnionArray[i] == 0)
817 {
818 infoSink.info.message(
819 EPrefixWarning, getLine(),
820 "Divide by zero error during constant folding");
821 tempConstArray[i].setIConst(INT_MAX);
822 }
823 else
824 {
Olli Etuaho3eab00a2015-02-12 16:02:39 +0200825 if (op == EOpDiv)
826 {
827 tempConstArray[i].setIConst(
828 unionArray[i].getIConst() /
829 rightUnionArray[i].getIConst());
830 }
831 else
832 {
833 ASSERT(op == EOpIMod);
834 tempConstArray[i].setIConst(
835 unionArray[i].getIConst() %
836 rightUnionArray[i].getIConst());
837 }
Jamie Madillb1a85f42014-08-19 15:23:24 -0400838 }
839 break;
840
841 case EbtUInt:
842 if (rightUnionArray[i] == 0)
843 {
844 infoSink.info.message(
845 EPrefixWarning, getLine(),
846 "Divide by zero error during constant folding");
847 tempConstArray[i].setUConst(UINT_MAX);
848 }
849 else
850 {
Olli Etuaho3eab00a2015-02-12 16:02:39 +0200851 if (op == EOpDiv)
852 {
853 tempConstArray[i].setUConst(
854 unionArray[i].getUConst() /
855 rightUnionArray[i].getUConst());
856 }
857 else
858 {
859 ASSERT(op == EOpIMod);
860 tempConstArray[i].setUConst(
861 unionArray[i].getUConst() %
862 rightUnionArray[i].getUConst());
863 }
Jamie Madillb1a85f42014-08-19 15:23:24 -0400864 }
865 break;
866
867 default:
868 infoSink.info.message(
869 EPrefixInternalError, getLine(),
870 "Constant folding cannot be done for \"/\"");
Arun Patolefddc2112015-04-22 13:28:10 +0530871 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400872 }
873 }
874 }
875 break;
876
877 case EOpMatrixTimesVector:
878 {
Olli Etuaho2cb7b832015-04-23 20:27:44 +0300879 if (rightNode->getBasicType() != EbtFloat)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400880 {
881 infoSink.info.message(
882 EPrefixInternalError, getLine(),
883 "Constant Folding cannot be done for matrix times vector");
Arun Patolefddc2112015-04-22 13:28:10 +0530884 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400885 }
886
887 const int matrixCols = getCols();
888 const int matrixRows = getRows();
889
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400890 tempConstArray = new TConstantUnion[matrixRows];
Jamie Madillb1a85f42014-08-19 15:23:24 -0400891
892 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
893 {
894 tempConstArray[matrixRow].setFConst(0.0f);
895 for (int col = 0; col < matrixCols; col++)
896 {
897 tempConstArray[matrixRow].setFConst(
898 tempConstArray[matrixRow].getFConst() +
899 unionArray[col * matrixRows + matrixRow].getFConst() *
900 rightUnionArray[col].getFConst());
901 }
902 }
903
Olli Etuaho2cb7b832015-04-23 20:27:44 +0300904 returnType = rightNode->getType();
Minmin Gong794e0002015-04-07 18:31:54 -0700905 returnType.setPrimarySize(static_cast<unsigned char>(matrixRows));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400906
907 tempNode = new TIntermConstantUnion(tempConstArray, returnType);
908 tempNode->setLine(getLine());
909
910 return tempNode;
911 }
912
913 case EOpVectorTimesMatrix:
914 {
915 if (getType().getBasicType() != EbtFloat)
916 {
917 infoSink.info.message(
918 EPrefixInternalError, getLine(),
919 "Constant Folding cannot be done for vector times matrix");
Arun Patolefddc2112015-04-22 13:28:10 +0530920 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400921 }
922
Olli Etuaho2cb7b832015-04-23 20:27:44 +0300923 const int matrixCols = rightNode->getType().getCols();
924 const int matrixRows = rightNode->getType().getRows();
Jamie Madillb1a85f42014-08-19 15:23:24 -0400925
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400926 tempConstArray = new TConstantUnion[matrixCols];
Jamie Madillb1a85f42014-08-19 15:23:24 -0400927
928 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
929 {
930 tempConstArray[matrixCol].setFConst(0.0f);
931 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
932 {
933 tempConstArray[matrixCol].setFConst(
934 tempConstArray[matrixCol].getFConst() +
935 unionArray[matrixRow].getFConst() *
936 rightUnionArray[matrixCol * matrixRows + matrixRow].getFConst());
937 }
938 }
939
Minmin Gong794e0002015-04-07 18:31:54 -0700940 returnType.setPrimarySize(static_cast<unsigned char>(matrixCols));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400941 }
942 break;
943
944 case EOpLogicalAnd:
945 // this code is written for possible future use,
946 // will not get executed currently
947 {
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400948 tempConstArray = new TConstantUnion[objectSize];
Jamie Madillb1a85f42014-08-19 15:23:24 -0400949 for (size_t i = 0; i < objectSize; i++)
950 {
951 tempConstArray[i] = unionArray[i] && rightUnionArray[i];
952 }
953 }
954 break;
955
956 case EOpLogicalOr:
957 // this code is written for possible future use,
958 // will not get executed currently
959 {
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400960 tempConstArray = new TConstantUnion[objectSize];
Jamie Madillb1a85f42014-08-19 15:23:24 -0400961 for (size_t i = 0; i < objectSize; i++)
962 {
963 tempConstArray[i] = unionArray[i] || rightUnionArray[i];
964 }
965 }
966 break;
967
968 case EOpLogicalXor:
969 {
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400970 tempConstArray = new TConstantUnion[objectSize];
Jamie Madillb1a85f42014-08-19 15:23:24 -0400971 for (size_t i = 0; i < objectSize; i++)
972 {
973 switch (getType().getBasicType())
974 {
975 case EbtBool:
976 tempConstArray[i].setBConst(
977 unionArray[i] == rightUnionArray[i] ? false : true);
978 break;
979 default:
980 UNREACHABLE();
981 break;
982 }
983 }
984 }
985 break;
986
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200987 case EOpBitwiseAnd:
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400988 tempConstArray = new TConstantUnion[objectSize];
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200989 for (size_t i = 0; i < objectSize; i++)
990 tempConstArray[i] = unionArray[i] & rightUnionArray[i];
991 break;
992 case EOpBitwiseXor:
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400993 tempConstArray = new TConstantUnion[objectSize];
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200994 for (size_t i = 0; i < objectSize; i++)
995 tempConstArray[i] = unionArray[i] ^ rightUnionArray[i];
996 break;
997 case EOpBitwiseOr:
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400998 tempConstArray = new TConstantUnion[objectSize];
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200999 for (size_t i = 0; i < objectSize; i++)
1000 tempConstArray[i] = unionArray[i] | rightUnionArray[i];
1001 break;
1002 case EOpBitShiftLeft:
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001003 tempConstArray = new TConstantUnion[objectSize];
Olli Etuaho31b5fc62015-01-16 12:13:36 +02001004 for (size_t i = 0; i < objectSize; i++)
1005 tempConstArray[i] = unionArray[i] << rightUnionArray[i];
1006 break;
1007 case EOpBitShiftRight:
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001008 tempConstArray = new TConstantUnion[objectSize];
Olli Etuaho31b5fc62015-01-16 12:13:36 +02001009 for (size_t i = 0; i < objectSize; i++)
1010 tempConstArray[i] = unionArray[i] >> rightUnionArray[i];
1011 break;
1012
Jamie Madillb1a85f42014-08-19 15:23:24 -04001013 case EOpLessThan:
1014 ASSERT(objectSize == 1);
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001015 tempConstArray = new TConstantUnion[1];
Jamie Madillb1a85f42014-08-19 15:23:24 -04001016 tempConstArray->setBConst(*unionArray < *rightUnionArray);
1017 returnType = TType(EbtBool, EbpUndefined, EvqConst);
1018 break;
1019
1020 case EOpGreaterThan:
1021 ASSERT(objectSize == 1);
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001022 tempConstArray = new TConstantUnion[1];
Jamie Madillb1a85f42014-08-19 15:23:24 -04001023 tempConstArray->setBConst(*unionArray > *rightUnionArray);
1024 returnType = TType(EbtBool, EbpUndefined, EvqConst);
1025 break;
1026
1027 case EOpLessThanEqual:
1028 {
1029 ASSERT(objectSize == 1);
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001030 TConstantUnion constant;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001031 constant.setBConst(*unionArray > *rightUnionArray);
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001032 tempConstArray = new TConstantUnion[1];
Jamie Madillb1a85f42014-08-19 15:23:24 -04001033 tempConstArray->setBConst(!constant.getBConst());
1034 returnType = TType(EbtBool, EbpUndefined, EvqConst);
1035 break;
1036 }
1037
1038 case EOpGreaterThanEqual:
1039 {
1040 ASSERT(objectSize == 1);
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001041 TConstantUnion constant;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001042 constant.setBConst(*unionArray < *rightUnionArray);
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001043 tempConstArray = new TConstantUnion[1];
Jamie Madillb1a85f42014-08-19 15:23:24 -04001044 tempConstArray->setBConst(!constant.getBConst());
1045 returnType = TType(EbtBool, EbpUndefined, EvqConst);
1046 break;
1047 }
1048
1049 case EOpEqual:
1050 if (getType().getBasicType() == EbtStruct)
1051 {
Olli Etuaho2cb7b832015-04-23 20:27:44 +03001052 if (!CompareStructure(rightNode->getType(),
1053 rightNode->getUnionArrayPointer(),
Jamie Madillb1a85f42014-08-19 15:23:24 -04001054 unionArray))
1055 {
1056 boolNodeFlag = true;
1057 }
1058 }
1059 else
1060 {
1061 for (size_t i = 0; i < objectSize; i++)
1062 {
1063 if (unionArray[i] != rightUnionArray[i])
1064 {
1065 boolNodeFlag = true;
1066 break; // break out of for loop
1067 }
1068 }
1069 }
1070
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001071 tempConstArray = new TConstantUnion[1];
Jamie Madillb1a85f42014-08-19 15:23:24 -04001072 if (!boolNodeFlag)
1073 {
1074 tempConstArray->setBConst(true);
1075 }
1076 else
1077 {
1078 tempConstArray->setBConst(false);
1079 }
1080
1081 tempNode = new TIntermConstantUnion(
1082 tempConstArray, TType(EbtBool, EbpUndefined, EvqConst));
1083 tempNode->setLine(getLine());
1084
1085 return tempNode;
1086
1087 case EOpNotEqual:
1088 if (getType().getBasicType() == EbtStruct)
1089 {
Olli Etuaho2cb7b832015-04-23 20:27:44 +03001090 if (CompareStructure(rightNode->getType(),
1091 rightNode->getUnionArrayPointer(),
Jamie Madillb1a85f42014-08-19 15:23:24 -04001092 unionArray))
1093 {
1094 boolNodeFlag = true;
1095 }
1096 }
1097 else
1098 {
1099 for (size_t i = 0; i < objectSize; i++)
1100 {
1101 if (unionArray[i] == rightUnionArray[i])
1102 {
1103 boolNodeFlag = true;
1104 break; // break out of for loop
1105 }
1106 }
1107 }
1108
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001109 tempConstArray = new TConstantUnion[1];
Jamie Madillb1a85f42014-08-19 15:23:24 -04001110 if (!boolNodeFlag)
1111 {
1112 tempConstArray->setBConst(true);
1113 }
1114 else
1115 {
1116 tempConstArray->setBConst(false);
1117 }
1118
1119 tempNode = new TIntermConstantUnion(
1120 tempConstArray, TType(EbtBool, EbpUndefined, EvqConst));
1121 tempNode->setLine(getLine());
1122
1123 return tempNode;
1124
1125 default:
1126 infoSink.info.message(
1127 EPrefixInternalError, getLine(),
1128 "Invalid operator for constant folding");
Arun Patolefddc2112015-04-22 13:28:10 +05301129 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001130 }
1131 tempNode = new TIntermConstantUnion(tempConstArray, returnType);
1132 tempNode->setLine(getLine());
1133
1134 return tempNode;
1135 }
1136 else
1137 {
1138 //
1139 // Do unary operations
1140 //
1141 TIntermConstantUnion *newNode = 0;
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001142 TConstantUnion* tempConstArray = new TConstantUnion[objectSize];
Jamie Madillb1a85f42014-08-19 15:23:24 -04001143 for (size_t i = 0; i < objectSize; i++)
1144 {
1145 switch(op)
1146 {
1147 case EOpNegative:
1148 switch (getType().getBasicType())
1149 {
1150 case EbtFloat:
1151 tempConstArray[i].setFConst(-unionArray[i].getFConst());
1152 break;
1153 case EbtInt:
1154 tempConstArray[i].setIConst(-unionArray[i].getIConst());
1155 break;
1156 case EbtUInt:
1157 tempConstArray[i].setUConst(static_cast<unsigned int>(
1158 -static_cast<int>(unionArray[i].getUConst())));
1159 break;
1160 default:
1161 infoSink.info.message(
1162 EPrefixInternalError, getLine(),
1163 "Unary operation not folded into constant");
Arun Patolefddc2112015-04-22 13:28:10 +05301164 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001165 }
1166 break;
1167
Zhenyao Mode1e00e2014-10-09 16:55:32 -07001168 case EOpPositive:
1169 switch (getType().getBasicType())
1170 {
1171 case EbtFloat:
1172 tempConstArray[i].setFConst(unionArray[i].getFConst());
1173 break;
1174 case EbtInt:
1175 tempConstArray[i].setIConst(unionArray[i].getIConst());
1176 break;
1177 case EbtUInt:
1178 tempConstArray[i].setUConst(static_cast<unsigned int>(
1179 static_cast<int>(unionArray[i].getUConst())));
1180 break;
1181 default:
1182 infoSink.info.message(
1183 EPrefixInternalError, getLine(),
1184 "Unary operation not folded into constant");
Arun Patolefddc2112015-04-22 13:28:10 +05301185 return nullptr;
Zhenyao Mode1e00e2014-10-09 16:55:32 -07001186 }
1187 break;
1188
Jamie Madillb1a85f42014-08-19 15:23:24 -04001189 case EOpLogicalNot:
1190 // this code is written for possible future use,
1191 // will not get executed currently
1192 switch (getType().getBasicType())
1193 {
1194 case EbtBool:
1195 tempConstArray[i].setBConst(!unionArray[i].getBConst());
1196 break;
1197 default:
1198 infoSink.info.message(
1199 EPrefixInternalError, getLine(),
1200 "Unary operation not folded into constant");
Arun Patolefddc2112015-04-22 13:28:10 +05301201 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001202 }
1203 break;
1204
Olli Etuaho31b5fc62015-01-16 12:13:36 +02001205 case EOpBitwiseNot:
1206 switch (getType().getBasicType())
1207 {
1208 case EbtInt:
1209 tempConstArray[i].setIConst(~unionArray[i].getIConst());
1210 break;
1211 case EbtUInt:
1212 tempConstArray[i].setUConst(~unionArray[i].getUConst());
1213 break;
1214 default:
1215 infoSink.info.message(
1216 EPrefixInternalError, getLine(),
1217 "Unary operation not folded into constant");
Arun Patolefddc2112015-04-22 13:28:10 +05301218 return nullptr;
Olli Etuaho31b5fc62015-01-16 12:13:36 +02001219 }
1220 break;
1221
Arun Patole9dea48f2015-04-02 11:45:09 +05301222 case EOpRadians:
1223 if (getType().getBasicType() == EbtFloat)
1224 {
1225 tempConstArray[i].setFConst(kDegreesToRadiansMultiplier * unionArray[i].getFConst());
1226 break;
1227 }
1228 infoSink.info.message(
1229 EPrefixInternalError, getLine(),
1230 "Unary operation not folded into constant");
1231 return nullptr;
1232
1233 case EOpDegrees:
1234 if (getType().getBasicType() == EbtFloat)
1235 {
1236 tempConstArray[i].setFConst(kRadiansToDegreesMultiplier * unionArray[i].getFConst());
1237 break;
1238 }
1239 infoSink.info.message(
1240 EPrefixInternalError, getLine(),
1241 "Unary operation not folded into constant");
1242 return nullptr;
1243
1244 case EOpSin:
1245 if (!foldFloatTypeUnary(unionArray[i], &sinf, infoSink, &tempConstArray[i]))
1246 return nullptr;
1247 break;
1248
1249 case EOpCos:
1250 if (!foldFloatTypeUnary(unionArray[i], &cosf, infoSink, &tempConstArray[i]))
1251 return nullptr;
1252 break;
1253
1254 case EOpTan:
1255 if (!foldFloatTypeUnary(unionArray[i], &tanf, infoSink, &tempConstArray[i]))
1256 return nullptr;
1257 break;
1258
1259 case EOpAsin:
1260 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to 0.
1261 if (getType().getBasicType() == EbtFloat && fabsf(unionArray[i].getFConst()) > 1.0f)
1262 tempConstArray[i].setFConst(0.0f);
1263 else if (!foldFloatTypeUnary(unionArray[i], &asinf, infoSink, &tempConstArray[i]))
1264 return nullptr;
1265 break;
1266
1267 case EOpAcos:
1268 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to 0.
1269 if (getType().getBasicType() == EbtFloat && fabsf(unionArray[i].getFConst()) > 1.0f)
1270 tempConstArray[i].setFConst(0.0f);
1271 else if (!foldFloatTypeUnary(unionArray[i], &acosf, infoSink, &tempConstArray[i]))
1272 return nullptr;
1273 break;
1274
1275 case EOpAtan:
1276 if (!foldFloatTypeUnary(unionArray[i], &atanf, infoSink, &tempConstArray[i]))
1277 return nullptr;
1278 break;
1279
1280 case EOpSinh:
1281 if (!foldFloatTypeUnary(unionArray[i], &sinhf, infoSink, &tempConstArray[i]))
1282 return nullptr;
1283 break;
1284
1285 case EOpCosh:
1286 if (!foldFloatTypeUnary(unionArray[i], &coshf, infoSink, &tempConstArray[i]))
1287 return nullptr;
1288 break;
1289
1290 case EOpTanh:
1291 if (!foldFloatTypeUnary(unionArray[i], &tanhf, infoSink, &tempConstArray[i]))
1292 return nullptr;
1293 break;
1294
1295 case EOpAsinh:
1296 if (!foldFloatTypeUnary(unionArray[i], &asinhf, infoSink, &tempConstArray[i]))
1297 return nullptr;
1298 break;
1299
1300 case EOpAcosh:
1301 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
1302 if (getType().getBasicType() == EbtFloat && unionArray[i].getFConst() < 1.0f)
1303 tempConstArray[i].setFConst(0.0f);
1304 else if (!foldFloatTypeUnary(unionArray[i], &acoshf, infoSink, &tempConstArray[i]))
1305 return nullptr;
1306 break;
1307
1308 case EOpAtanh:
1309 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to 0.
1310 if (getType().getBasicType() == EbtFloat && fabsf(unionArray[i].getFConst()) >= 1.0f)
1311 tempConstArray[i].setFConst(0.0f);
1312 else if (!foldFloatTypeUnary(unionArray[i], &atanhf, infoSink, &tempConstArray[i]))
1313 return nullptr;
1314 break;
1315
Arun Patole97dc22e2015-04-06 17:35:38 +05301316 case EOpAbs:
1317 switch (getType().getBasicType())
1318 {
1319 case EbtFloat:
1320 tempConstArray[i].setFConst(fabsf(unionArray[i].getFConst()));
1321 break;
1322 case EbtInt:
1323 tempConstArray[i].setIConst(abs(unionArray[i].getIConst()));
1324 break;
1325 default:
1326 infoSink.info.message(
1327 EPrefixInternalError, getLine(),
1328 "Unary operation not folded into constant");
1329 return nullptr;
1330 }
1331 break;
1332
1333 case EOpSign:
1334 switch (getType().getBasicType())
1335 {
1336 case EbtFloat:
1337 {
1338 float fConst = unionArray[i].getFConst();
1339 float fResult = 0.0f;
1340 if (fConst > 0.0f)
1341 fResult = 1.0f;
1342 else if (fConst < 0.0f)
1343 fResult = -1.0f;
1344 tempConstArray[i].setFConst(fResult);
1345 }
1346 break;
1347 case EbtInt:
1348 {
1349 int iConst = unionArray[i].getIConst();
1350 int iResult = 0;
1351 if (iConst > 0)
1352 iResult = 1;
1353 else if (iConst < 0)
1354 iResult = -1;
1355 tempConstArray[i].setIConst(iResult);
1356 }
1357 break;
1358 default:
1359 infoSink.info.message(
1360 EPrefixInternalError, getLine(),
1361 "Unary operation not folded into constant");
1362 return nullptr;
1363 }
1364 break;
1365
1366 case EOpFloor:
1367 if (!foldFloatTypeUnary(unionArray[i], &floorf, infoSink, &tempConstArray[i]))
1368 return nullptr;
1369 break;
1370
1371 case EOpTrunc:
1372 if (!foldFloatTypeUnary(unionArray[i], &truncf, infoSink, &tempConstArray[i]))
1373 return nullptr;
1374 break;
1375
1376 case EOpRound:
1377 if (!foldFloatTypeUnary(unionArray[i], &roundf, infoSink, &tempConstArray[i]))
1378 return nullptr;
1379 break;
1380
1381 case EOpRoundEven:
1382 if (getType().getBasicType() == EbtFloat)
1383 {
1384 float x = unionArray[i].getFConst();
1385 float result;
1386 float fractPart = modff(x, &result);
1387 if (fabsf(fractPart) == 0.5f)
1388 result = 2.0f * roundf(x / 2.0f);
1389 else
1390 result = roundf(x);
1391 tempConstArray[i].setFConst(result);
1392 break;
1393 }
1394 infoSink.info.message(
1395 EPrefixInternalError, getLine(),
1396 "Unary operation not folded into constant");
1397 return nullptr;
1398
1399 case EOpCeil:
1400 if (!foldFloatTypeUnary(unionArray[i], &ceilf, infoSink, &tempConstArray[i]))
1401 return nullptr;
1402 break;
1403
1404 case EOpFract:
1405 if (getType().getBasicType() == EbtFloat)
1406 {
1407 float x = unionArray[i].getFConst();
1408 tempConstArray[i].setFConst(x - floorf(x));
1409 break;
1410 }
1411 infoSink.info.message(
1412 EPrefixInternalError, getLine(),
1413 "Unary operation not folded into constant");
1414 return nullptr;
1415
Arun Patole28eb65e2015-04-06 17:29:48 +05301416 case EOpExp:
1417 if (!foldFloatTypeUnary(unionArray[i], &expf, infoSink, &tempConstArray[i]))
1418 return nullptr;
1419 break;
1420
1421 case EOpLog:
1422 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
1423 if (getType().getBasicType() == EbtFloat && unionArray[i].getFConst() <= 0.0f)
1424 tempConstArray[i].setFConst(0.0f);
1425 else if (!foldFloatTypeUnary(unionArray[i], &logf, infoSink, &tempConstArray[i]))
1426 return nullptr;
1427 break;
1428
1429 case EOpExp2:
1430 if (!foldFloatTypeUnary(unionArray[i], &exp2f, infoSink, &tempConstArray[i]))
1431 return nullptr;
1432 break;
1433
1434 case EOpLog2:
1435 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
1436 // And log2f is not available on some plarforms like old android, so just using log(x)/log(2) here.
1437 if (getType().getBasicType() == EbtFloat && unionArray[i].getFConst() <= 0.0f)
1438 tempConstArray[i].setFConst(0.0f);
1439 else if (!foldFloatTypeUnary(unionArray[i], &logf, infoSink, &tempConstArray[i]))
1440 return nullptr;
1441 else
1442 tempConstArray[i].setFConst(tempConstArray[i].getFConst() / logf(2.0f));
1443 break;
1444
1445 case EOpSqrt:
1446 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
1447 if (getType().getBasicType() == EbtFloat && unionArray[i].getFConst() < 0.0f)
1448 tempConstArray[i].setFConst(0.0f);
1449 else if (!foldFloatTypeUnary(unionArray[i], &sqrtf, infoSink, &tempConstArray[i]))
1450 return nullptr;
1451 break;
1452
1453 case EOpInverseSqrt:
1454 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
1455 // so getting the square root first using builtin function sqrt() and then taking its inverse.
1456 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set result to 0.
1457 if (getType().getBasicType() == EbtFloat && unionArray[i].getFConst() <= 0.0f)
1458 tempConstArray[i].setFConst(0.0f);
1459 else if (!foldFloatTypeUnary(unionArray[i], &sqrtf, infoSink, &tempConstArray[i]))
1460 return nullptr;
1461 else
1462 tempConstArray[i].setFConst(1.0f / tempConstArray[i].getFConst());
1463 break;
1464
Jamie Madillb1a85f42014-08-19 15:23:24 -04001465 default:
Arun Patolefddc2112015-04-22 13:28:10 +05301466 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001467 }
1468 }
1469 newNode = new TIntermConstantUnion(tempConstArray, getType());
1470 newNode->setLine(getLine());
1471 return newNode;
1472 }
1473}
1474
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001475bool TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter, FloatTypeUnaryFunc builtinFunc,
1476 TInfoSink &infoSink, TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05301477{
1478 ASSERT(builtinFunc);
1479
1480 if (getType().getBasicType() == EbtFloat)
1481 {
1482 result->setFConst(builtinFunc(parameter.getFConst()));
1483 return true;
1484 }
1485
1486 infoSink.info.message(
1487 EPrefixInternalError, getLine(),
1488 "Unary operation not folded into constant");
1489 return false;
1490}
1491
Jamie Madillb1a85f42014-08-19 15:23:24 -04001492// static
1493TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunction)
1494{
1495 if (hashFunction == NULL || name.empty())
1496 return name;
1497 khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
1498 TStringStream stream;
1499 stream << HASHED_NAME_PREFIX << std::hex << number;
1500 TString hashedName = stream.str();
1501 return hashedName;
1502}
Olli Etuaho853dc1a2014-11-06 17:25:48 +02001503
1504void TIntermTraverser::updateTree()
1505{
Olli Etuahoa6f22092015-05-08 18:31:10 +03001506 for (size_t ii = 0; ii < mInsertions.size(); ++ii)
1507 {
1508 const NodeInsertMultipleEntry &insertion = mInsertions[ii];
1509 ASSERT(insertion.parent);
1510 bool inserted = insertion.parent->insertChildNodes(insertion.position, insertion.insertions);
1511 ASSERT(inserted);
1512 UNUSED_ASSERTION_VARIABLE(inserted);
1513 }
Olli Etuaho853dc1a2014-11-06 17:25:48 +02001514 for (size_t ii = 0; ii < mReplacements.size(); ++ii)
1515 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03001516 const NodeUpdateEntry &replacement = mReplacements[ii];
1517 ASSERT(replacement.parent);
1518 bool replaced = replacement.parent->replaceChildNode(
1519 replacement.original, replacement.replacement);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02001520 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03001521 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02001522
Olli Etuahocd94ef92015-04-16 19:18:10 +03001523 if (!replacement.originalBecomesChildOfReplacement)
Olli Etuaho853dc1a2014-11-06 17:25:48 +02001524 {
1525 // In AST traversing, a parent is visited before its children.
Olli Etuahocd94ef92015-04-16 19:18:10 +03001526 // After we replace a node, if its immediate child is to
Olli Etuaho853dc1a2014-11-06 17:25:48 +02001527 // be replaced, we need to make sure we don't update the replaced
1528 // node; instead, we update the replacement node.
1529 for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj)
1530 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03001531 NodeUpdateEntry &replacement2 = mReplacements[jj];
1532 if (replacement2.parent == replacement.original)
1533 replacement2.parent = replacement.replacement;
Olli Etuaho853dc1a2014-11-06 17:25:48 +02001534 }
1535 }
1536 }
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03001537 for (size_t ii = 0; ii < mMultiReplacements.size(); ++ii)
1538 {
1539 const NodeReplaceWithMultipleEntry &replacement = mMultiReplacements[ii];
1540 ASSERT(replacement.parent);
1541 bool replaced = replacement.parent->replaceChildNodeWithMultiple(
1542 replacement.original, replacement.replacements);
1543 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03001544 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03001545 }
Olli Etuaho853dc1a2014-11-06 17:25:48 +02001546}