blob: 3a822a20198ddfcc276c45fc90e4dc6ed17cea63 [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
Arun Patole1137a2a2015-05-05 13:33:30 +053017#include "common/mathutil.h"
Jamie Madillb1a85f42014-08-19 15:23:24 -040018#include "compiler/translator/HashNames.h"
19#include "compiler/translator/IntermNode.h"
20#include "compiler/translator/SymbolTable.h"
21
22namespace
23{
24
Arun Patole9dea48f2015-04-02 11:45:09 +053025const float kPi = 3.14159265358979323846f;
26const float kDegreesToRadiansMultiplier = kPi / 180.0f;
27const float kRadiansToDegreesMultiplier = 180.0f / kPi;
28
Jamie Madillb1a85f42014-08-19 15:23:24 -040029TPrecision GetHigherPrecision(TPrecision left, TPrecision right)
30{
31 return left > right ? left : right;
32}
33
34bool ValidateMultiplication(TOperator op, const TType &left, const TType &right)
35{
36 switch (op)
37 {
38 case EOpMul:
39 case EOpMulAssign:
40 return left.getNominalSize() == right.getNominalSize() &&
41 left.getSecondarySize() == right.getSecondarySize();
42 case EOpVectorTimesScalar:
43 case EOpVectorTimesScalarAssign:
44 return true;
45 case EOpVectorTimesMatrix:
46 return left.getNominalSize() == right.getRows();
47 case EOpVectorTimesMatrixAssign:
48 return left.getNominalSize() == right.getRows() &&
49 left.getNominalSize() == right.getCols();
50 case EOpMatrixTimesVector:
51 return left.getCols() == right.getNominalSize();
52 case EOpMatrixTimesScalar:
53 case EOpMatrixTimesScalarAssign:
54 return true;
55 case EOpMatrixTimesMatrix:
56 return left.getCols() == right.getRows();
57 case EOpMatrixTimesMatrixAssign:
58 return left.getCols() == right.getCols() &&
59 left.getRows() == right.getRows();
60
61 default:
62 UNREACHABLE();
63 return false;
64 }
65}
66
67bool CompareStructure(const TType& leftNodeType,
Jamie Madillb11e2482015-05-04 14:21:22 -040068 const TConstantUnion *rightUnionArray,
69 const TConstantUnion *leftUnionArray);
Jamie Madillb1a85f42014-08-19 15:23:24 -040070
71bool CompareStruct(const TType &leftNodeType,
Jamie Madillb11e2482015-05-04 14:21:22 -040072 const TConstantUnion *rightUnionArray,
73 const TConstantUnion *leftUnionArray)
Jamie Madillb1a85f42014-08-19 15:23:24 -040074{
75 const TFieldList &fields = leftNodeType.getStruct()->fields();
76
77 size_t structSize = fields.size();
78 size_t index = 0;
79
80 for (size_t j = 0; j < structSize; j++)
81 {
82 size_t size = fields[j]->type()->getObjectSize();
83 for (size_t i = 0; i < size; i++)
84 {
85 if (fields[j]->type()->getBasicType() == EbtStruct)
86 {
87 if (!CompareStructure(*fields[j]->type(),
88 &rightUnionArray[index],
89 &leftUnionArray[index]))
90 {
91 return false;
92 }
93 }
94 else
95 {
96 if (leftUnionArray[index] != rightUnionArray[index])
97 return false;
98 index++;
99 }
100 }
101 }
102 return true;
103}
104
105bool CompareStructure(const TType &leftNodeType,
Jamie Madillb11e2482015-05-04 14:21:22 -0400106 const TConstantUnion *rightUnionArray,
107 const TConstantUnion *leftUnionArray)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400108{
109 if (leftNodeType.isArray())
110 {
111 TType typeWithoutArrayness = leftNodeType;
112 typeWithoutArrayness.clearArrayness();
113
114 size_t arraySize = leftNodeType.getArraySize();
115
116 for (size_t i = 0; i < arraySize; ++i)
117 {
118 size_t offset = typeWithoutArrayness.getObjectSize() * i;
119 if (!CompareStruct(typeWithoutArrayness,
120 &rightUnionArray[offset],
121 &leftUnionArray[offset]))
122 {
123 return false;
124 }
125 }
126 }
127 else
128 {
129 return CompareStruct(leftNodeType, rightUnionArray, leftUnionArray);
130 }
131 return true;
132}
133
Arun Patole1137a2a2015-05-05 13:33:30 +0530134TConstantUnion *Vectorize(const TConstantUnion &constant, size_t size)
135{
136 TConstantUnion *constUnion = new TConstantUnion[size];
137 for (unsigned int i = 0; i < size; ++i)
138 constUnion[i] = constant;
139
140 return constUnion;
141}
142
Jamie Madillb1a85f42014-08-19 15:23:24 -0400143} // namespace anonymous
144
145
146////////////////////////////////////////////////////////////////
147//
148// Member functions of the nodes used for building the tree.
149//
150////////////////////////////////////////////////////////////////
151
Olli Etuahod2a67b92014-10-21 16:42:57 +0300152void TIntermTyped::setTypePreservePrecision(const TType &t)
153{
154 TPrecision precision = getPrecision();
155 mType = t;
156 ASSERT(mType.getBasicType() != EbtBool || precision == EbpUndefined);
157 mType.setPrecision(precision);
158}
159
Jamie Madillb1a85f42014-08-19 15:23:24 -0400160#define REPLACE_IF_IS(node, type, original, replacement) \
161 if (node == original) { \
162 node = static_cast<type *>(replacement); \
163 return true; \
164 }
165
166bool TIntermLoop::replaceChildNode(
167 TIntermNode *original, TIntermNode *replacement)
168{
169 REPLACE_IF_IS(mInit, TIntermNode, original, replacement);
170 REPLACE_IF_IS(mCond, TIntermTyped, original, replacement);
171 REPLACE_IF_IS(mExpr, TIntermTyped, original, replacement);
172 REPLACE_IF_IS(mBody, TIntermNode, original, replacement);
173 return false;
174}
175
Jamie Madillb1a85f42014-08-19 15:23:24 -0400176bool TIntermBranch::replaceChildNode(
177 TIntermNode *original, TIntermNode *replacement)
178{
179 REPLACE_IF_IS(mExpression, TIntermTyped, original, replacement);
180 return false;
181}
182
Jamie Madillb1a85f42014-08-19 15:23:24 -0400183bool TIntermBinary::replaceChildNode(
184 TIntermNode *original, TIntermNode *replacement)
185{
186 REPLACE_IF_IS(mLeft, TIntermTyped, original, replacement);
187 REPLACE_IF_IS(mRight, TIntermTyped, original, replacement);
188 return false;
189}
190
Jamie Madillb1a85f42014-08-19 15:23:24 -0400191bool TIntermUnary::replaceChildNode(
192 TIntermNode *original, TIntermNode *replacement)
193{
194 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
195 return false;
196}
197
Jamie Madillb1a85f42014-08-19 15:23:24 -0400198bool TIntermAggregate::replaceChildNode(
199 TIntermNode *original, TIntermNode *replacement)
200{
201 for (size_t ii = 0; ii < mSequence.size(); ++ii)
202 {
203 REPLACE_IF_IS(mSequence[ii], TIntermNode, original, replacement);
204 }
205 return false;
206}
207
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300208bool TIntermAggregate::replaceChildNodeWithMultiple(TIntermNode *original, TIntermSequence replacements)
209{
210 for (auto it = mSequence.begin(); it < mSequence.end(); ++it)
211 {
212 if (*it == original)
213 {
214 it = mSequence.erase(it);
Olli Etuaho8fee0ab2015-04-23 14:52:46 +0300215 mSequence.insert(it, replacements.begin(), replacements.end());
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300216 return true;
217 }
218 }
219 return false;
220}
221
Olli Etuahod2a67b92014-10-21 16:42:57 +0300222void TIntermAggregate::setPrecisionFromChildren()
223{
224 if (getBasicType() == EbtBool)
225 {
226 mType.setPrecision(EbpUndefined);
227 return;
228 }
229
230 TPrecision precision = EbpUndefined;
231 TIntermSequence::iterator childIter = mSequence.begin();
232 while (childIter != mSequence.end())
233 {
234 TIntermTyped *typed = (*childIter)->getAsTyped();
235 if (typed)
236 precision = GetHigherPrecision(typed->getPrecision(), precision);
237 ++childIter;
238 }
239 mType.setPrecision(precision);
240}
241
242void TIntermAggregate::setBuiltInFunctionPrecision()
243{
244 // All built-ins returning bool should be handled as ops, not functions.
245 ASSERT(getBasicType() != EbtBool);
246
247 TPrecision precision = EbpUndefined;
248 TIntermSequence::iterator childIter = mSequence.begin();
249 while (childIter != mSequence.end())
250 {
251 TIntermTyped *typed = (*childIter)->getAsTyped();
252 // ESSL spec section 8: texture functions get their precision from the sampler.
253 if (typed && IsSampler(typed->getBasicType()))
254 {
255 precision = typed->getPrecision();
256 break;
257 }
258 ++childIter;
259 }
260 // ESSL 3.0 spec section 8: textureSize always gets highp precision.
261 // All other functions that take a sampler are assumed to be texture functions.
262 if (mName.find("textureSize") == 0)
263 mType.setPrecision(EbpHigh);
264 else
265 mType.setPrecision(precision);
266}
267
Jamie Madillb1a85f42014-08-19 15:23:24 -0400268bool TIntermSelection::replaceChildNode(
269 TIntermNode *original, TIntermNode *replacement)
270{
271 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
272 REPLACE_IF_IS(mTrueBlock, TIntermNode, original, replacement);
273 REPLACE_IF_IS(mFalseBlock, TIntermNode, original, replacement);
274 return false;
275}
276
Olli Etuahoa3a36662015-02-17 13:46:51 +0200277bool TIntermSwitch::replaceChildNode(
278 TIntermNode *original, TIntermNode *replacement)
279{
280 REPLACE_IF_IS(mInit, TIntermTyped, original, replacement);
281 REPLACE_IF_IS(mStatementList, TIntermAggregate, original, replacement);
282 return false;
283}
284
285bool TIntermCase::replaceChildNode(
286 TIntermNode *original, TIntermNode *replacement)
287{
288 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
289 return false;
290}
291
Jamie Madillb1a85f42014-08-19 15:23:24 -0400292//
293// Say whether or not an operation node changes the value of a variable.
294//
295bool TIntermOperator::isAssignment() const
296{
297 switch (mOp)
298 {
299 case EOpPostIncrement:
300 case EOpPostDecrement:
301 case EOpPreIncrement:
302 case EOpPreDecrement:
303 case EOpAssign:
304 case EOpAddAssign:
305 case EOpSubAssign:
306 case EOpMulAssign:
307 case EOpVectorTimesMatrixAssign:
308 case EOpVectorTimesScalarAssign:
309 case EOpMatrixTimesScalarAssign:
310 case EOpMatrixTimesMatrixAssign:
311 case EOpDivAssign:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200312 case EOpIModAssign:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200313 case EOpBitShiftLeftAssign:
314 case EOpBitShiftRightAssign:
315 case EOpBitwiseAndAssign:
316 case EOpBitwiseXorAssign:
317 case EOpBitwiseOrAssign:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400318 return true;
319 default:
320 return false;
321 }
322}
323
324//
325// returns true if the operator is for one of the constructors
326//
327bool TIntermOperator::isConstructor() const
328{
329 switch (mOp)
330 {
331 case EOpConstructVec2:
332 case EOpConstructVec3:
333 case EOpConstructVec4:
334 case EOpConstructMat2:
335 case EOpConstructMat3:
336 case EOpConstructMat4:
337 case EOpConstructFloat:
338 case EOpConstructIVec2:
339 case EOpConstructIVec3:
340 case EOpConstructIVec4:
341 case EOpConstructInt:
342 case EOpConstructUVec2:
343 case EOpConstructUVec3:
344 case EOpConstructUVec4:
345 case EOpConstructUInt:
346 case EOpConstructBVec2:
347 case EOpConstructBVec3:
348 case EOpConstructBVec4:
349 case EOpConstructBool:
350 case EOpConstructStruct:
351 return true;
352 default:
353 return false;
354 }
355}
356
357//
358// Make sure the type of a unary operator is appropriate for its
359// combination of operation and operand type.
360//
Olli Etuahof6c694b2015-03-26 14:50:53 +0200361void TIntermUnary::promote(const TType *funcReturnType)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400362{
363 switch (mOp)
364 {
Olli Etuahodca3e792015-03-26 13:24:04 +0200365 case EOpFloatBitsToInt:
366 case EOpFloatBitsToUint:
Olli Etuahoe8d2c072015-01-08 16:33:54 +0200367 case EOpIntBitsToFloat:
368 case EOpUintBitsToFloat:
Olli Etuahodca3e792015-03-26 13:24:04 +0200369 case EOpPackSnorm2x16:
370 case EOpPackUnorm2x16:
371 case EOpPackHalf2x16:
Olli Etuaho7700ff62015-01-15 12:16:29 +0200372 case EOpUnpackSnorm2x16:
373 case EOpUnpackUnorm2x16:
Olli Etuahodca3e792015-03-26 13:24:04 +0200374 mType.setPrecision(EbpHigh);
Arun Patole6b19d762015-02-19 09:40:39 +0530375 break;
Olli Etuahodca3e792015-03-26 13:24:04 +0200376 case EOpUnpackHalf2x16:
377 mType.setPrecision(EbpMedium);
378 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400379 default:
Olli Etuahodca3e792015-03-26 13:24:04 +0200380 setType(mOperand->getType());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400381 }
382
Olli Etuahof6c694b2015-03-26 14:50:53 +0200383 if (funcReturnType != nullptr)
384 {
385 if (funcReturnType->getBasicType() == EbtBool)
386 {
387 // Bool types should not have precision.
388 setType(*funcReturnType);
389 }
390 else
391 {
392 // Precision of the node has been set based on the operand.
393 setTypePreservePrecision(*funcReturnType);
394 }
395 }
396
Jamie Madillb1a85f42014-08-19 15:23:24 -0400397 mType.setQualifier(EvqTemporary);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400398}
399
400//
401// Establishes the type of the resultant operation, as well as
402// makes the operator the correct one for the operands.
403//
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200404// For lots of operations it should already be established that the operand
405// combination is valid, but returns false if operator can't work on operands.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400406//
407bool TIntermBinary::promote(TInfoSink &infoSink)
408{
Olli Etuahoe79904c2015-03-18 16:56:42 +0200409 ASSERT(mLeft->isArray() == mRight->isArray());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400410
Jamie Madillb1a85f42014-08-19 15:23:24 -0400411 //
412 // Base assumption: just make the type the same as the left
413 // operand. Then only deviations from this need be coded.
414 //
415 setType(mLeft->getType());
416
417 // The result gets promoted to the highest precision.
418 TPrecision higherPrecision = GetHigherPrecision(
419 mLeft->getPrecision(), mRight->getPrecision());
420 getTypePointer()->setPrecision(higherPrecision);
421
422 // Binary operations results in temporary variables unless both
423 // operands are const.
424 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
425 {
426 getTypePointer()->setQualifier(EvqTemporary);
427 }
428
429 const int nominalSize =
430 std::max(mLeft->getNominalSize(), mRight->getNominalSize());
431
432 //
433 // All scalars or structs. Code after this test assumes this case is removed!
434 //
435 if (nominalSize == 1)
436 {
437 switch (mOp)
438 {
439 //
440 // Promote to conditional
441 //
442 case EOpEqual:
443 case EOpNotEqual:
444 case EOpLessThan:
445 case EOpGreaterThan:
446 case EOpLessThanEqual:
447 case EOpGreaterThanEqual:
448 setType(TType(EbtBool, EbpUndefined));
449 break;
450
451 //
452 // And and Or operate on conditionals
453 //
454 case EOpLogicalAnd:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200455 case EOpLogicalXor:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400456 case EOpLogicalOr:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200457 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400458 setType(TType(EbtBool, EbpUndefined));
459 break;
460
461 default:
462 break;
463 }
464 return true;
465 }
466
467 // If we reach here, at least one of the operands is vector or matrix.
468 // The other operand could be a scalar, vector, or matrix.
469 // Can these two operands be combined?
470 //
471 TBasicType basicType = mLeft->getBasicType();
472 switch (mOp)
473 {
474 case EOpMul:
475 if (!mLeft->isMatrix() && mRight->isMatrix())
476 {
477 if (mLeft->isVector())
478 {
479 mOp = EOpVectorTimesMatrix;
480 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700481 static_cast<unsigned char>(mRight->getCols()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400482 }
483 else
484 {
485 mOp = EOpMatrixTimesScalar;
486 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700487 static_cast<unsigned char>(mRight->getCols()), static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400488 }
489 }
490 else if (mLeft->isMatrix() && !mRight->isMatrix())
491 {
492 if (mRight->isVector())
493 {
494 mOp = EOpMatrixTimesVector;
495 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700496 static_cast<unsigned char>(mLeft->getRows()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400497 }
498 else
499 {
500 mOp = EOpMatrixTimesScalar;
501 }
502 }
503 else if (mLeft->isMatrix() && mRight->isMatrix())
504 {
505 mOp = EOpMatrixTimesMatrix;
506 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700507 static_cast<unsigned char>(mRight->getCols()), static_cast<unsigned char>(mLeft->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400508 }
509 else if (!mLeft->isMatrix() && !mRight->isMatrix())
510 {
511 if (mLeft->isVector() && mRight->isVector())
512 {
513 // leave as component product
514 }
515 else if (mLeft->isVector() || mRight->isVector())
516 {
517 mOp = EOpVectorTimesScalar;
518 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700519 static_cast<unsigned char>(nominalSize), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400520 }
521 }
522 else
523 {
524 infoSink.info.message(EPrefixInternalError, getLine(),
525 "Missing elses");
526 return false;
527 }
528
529 if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType()))
530 {
531 return false;
532 }
533 break;
534
535 case EOpMulAssign:
536 if (!mLeft->isMatrix() && mRight->isMatrix())
537 {
538 if (mLeft->isVector())
539 {
540 mOp = EOpVectorTimesMatrixAssign;
541 }
542 else
543 {
544 return false;
545 }
546 }
547 else if (mLeft->isMatrix() && !mRight->isMatrix())
548 {
549 if (mRight->isVector())
550 {
551 return false;
552 }
553 else
554 {
555 mOp = EOpMatrixTimesScalarAssign;
556 }
557 }
558 else if (mLeft->isMatrix() && mRight->isMatrix())
559 {
560 mOp = EOpMatrixTimesMatrixAssign;
561 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700562 static_cast<unsigned char>(mRight->getCols()), static_cast<unsigned char>(mLeft->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400563 }
564 else if (!mLeft->isMatrix() && !mRight->isMatrix())
565 {
566 if (mLeft->isVector() && mRight->isVector())
567 {
568 // leave as component product
569 }
570 else if (mLeft->isVector() || mRight->isVector())
571 {
572 if (!mLeft->isVector())
573 return false;
574 mOp = EOpVectorTimesScalarAssign;
575 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700576 static_cast<unsigned char>(mLeft->getNominalSize()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400577 }
578 }
579 else
580 {
581 infoSink.info.message(EPrefixInternalError, getLine(),
582 "Missing elses");
583 return false;
584 }
585
586 if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType()))
587 {
588 return false;
589 }
590 break;
591
592 case EOpAssign:
593 case EOpInitialize:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200594 // No more additional checks are needed.
595 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
596 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
597 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400598 case EOpAdd:
599 case EOpSub:
600 case EOpDiv:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200601 case EOpIMod:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200602 case EOpBitShiftLeft:
603 case EOpBitShiftRight:
604 case EOpBitwiseAnd:
605 case EOpBitwiseXor:
606 case EOpBitwiseOr:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400607 case EOpAddAssign:
608 case EOpSubAssign:
609 case EOpDivAssign:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200610 case EOpIModAssign:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200611 case EOpBitShiftLeftAssign:
612 case EOpBitShiftRightAssign:
613 case EOpBitwiseAndAssign:
614 case EOpBitwiseXorAssign:
615 case EOpBitwiseOrAssign:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400616 if ((mLeft->isMatrix() && mRight->isVector()) ||
617 (mLeft->isVector() && mRight->isMatrix()))
618 {
619 return false;
620 }
621
622 // Are the sizes compatible?
623 if (mLeft->getNominalSize() != mRight->getNominalSize() ||
624 mLeft->getSecondarySize() != mRight->getSecondarySize())
625 {
Olli Etuaho6c850472014-12-02 16:23:17 +0200626 // If the nominal sizes of operands do not match:
627 // One of them must be a scalar.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400628 if (!mLeft->isScalar() && !mRight->isScalar())
629 return false;
630
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200631 // In the case of compound assignment other than multiply-assign,
632 // the right side needs to be a scalar. Otherwise a vector/matrix
633 // would be assigned to a scalar. A scalar can't be shifted by a
634 // vector either.
Olli Etuaho6c850472014-12-02 16:23:17 +0200635 if (!mRight->isScalar() &&
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200636 (isAssignment() ||
637 mOp == EOpBitShiftLeft ||
638 mOp == EOpBitShiftRight))
Olli Etuaho6c850472014-12-02 16:23:17 +0200639 return false;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400640 }
641
642 {
643 const int secondarySize = std::max(
644 mLeft->getSecondarySize(), mRight->getSecondarySize());
645 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700646 static_cast<unsigned char>(nominalSize), static_cast<unsigned char>(secondarySize)));
Olli Etuahoe79904c2015-03-18 16:56:42 +0200647 if (mLeft->isArray())
648 {
649 ASSERT(mLeft->getArraySize() == mRight->getArraySize());
650 mType.setArraySize(mLeft->getArraySize());
651 }
Jamie Madillb1a85f42014-08-19 15:23:24 -0400652 }
653 break;
654
655 case EOpEqual:
656 case EOpNotEqual:
657 case EOpLessThan:
658 case EOpGreaterThan:
659 case EOpLessThanEqual:
660 case EOpGreaterThanEqual:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200661 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
662 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400663 setType(TType(EbtBool, EbpUndefined));
664 break;
665
666 default:
667 return false;
668 }
669 return true;
670}
671
672//
673// The fold functions see if an operation on a constant can be done in place,
674// without generating run-time code.
675//
676// Returns the node to keep using, which may or may not be the node passed in.
677//
678TIntermTyped *TIntermConstantUnion::fold(
Olli Etuaho2cb7b832015-04-23 20:27:44 +0300679 TOperator op, TIntermConstantUnion *rightNode, TInfoSink &infoSink)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400680{
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400681 TConstantUnion *unionArray = getUnionArrayPointer();
Jamie Madillb1a85f42014-08-19 15:23:24 -0400682
683 if (!unionArray)
Arun Patolefddc2112015-04-22 13:28:10 +0530684 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400685
686 size_t objectSize = getType().getObjectSize();
687
Olli Etuaho2cb7b832015-04-23 20:27:44 +0300688 if (rightNode)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400689 {
690 // binary operations
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400691 TConstantUnion *rightUnionArray = rightNode->getUnionArrayPointer();
Jamie Madillb1a85f42014-08-19 15:23:24 -0400692 TType returnType = getType();
693
694 if (!rightUnionArray)
Arun Patolefddc2112015-04-22 13:28:10 +0530695 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400696
Olli Etuaho2cb7b832015-04-23 20:27:44 +0300697 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
698 if (rightNode->getType().getObjectSize() == 1 && objectSize > 1)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400699 {
Arun Patole1137a2a2015-05-05 13:33:30 +0530700 rightUnionArray = Vectorize(*rightNode->getUnionArrayPointer(), objectSize);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400701 returnType = getType();
702 }
Olli Etuaho2cb7b832015-04-23 20:27:44 +0300703 else if (rightNode->getType().getObjectSize() > 1 && objectSize == 1)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400704 {
Olli Etuaho2cb7b832015-04-23 20:27:44 +0300705 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
Arun Patole1137a2a2015-05-05 13:33:30 +0530706 unionArray = Vectorize(*getUnionArrayPointer(), rightNode->getType().getObjectSize());
Olli Etuaho2cb7b832015-04-23 20:27:44 +0300707 returnType = rightNode->getType();
708 objectSize = rightNode->getType().getObjectSize();
Jamie Madillb1a85f42014-08-19 15:23:24 -0400709 }
710
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400711 TConstantUnion *tempConstArray = nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400712 TIntermConstantUnion *tempNode;
713
714 bool boolNodeFlag = false;
715 switch(op)
716 {
717 case EOpAdd:
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400718 tempConstArray = new TConstantUnion[objectSize];
Jamie Madillb1a85f42014-08-19 15:23:24 -0400719 for (size_t i = 0; i < objectSize; i++)
720 tempConstArray[i] = unionArray[i] + rightUnionArray[i];
721 break;
722 case EOpSub:
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400723 tempConstArray = new TConstantUnion[objectSize];
Jamie Madillb1a85f42014-08-19 15:23:24 -0400724 for (size_t i = 0; i < objectSize; i++)
725 tempConstArray[i] = unionArray[i] - rightUnionArray[i];
726 break;
727
728 case EOpMul:
729 case EOpVectorTimesScalar:
730 case EOpMatrixTimesScalar:
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
736 case EOpMatrixTimesMatrix:
737 {
738 if (getType().getBasicType() != EbtFloat ||
Olli Etuaho2cb7b832015-04-23 20:27:44 +0300739 rightNode->getBasicType() != EbtFloat)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400740 {
741 infoSink.info.message(
742 EPrefixInternalError, getLine(),
743 "Constant Folding cannot be done for matrix multiply");
Arun Patolefddc2112015-04-22 13:28:10 +0530744 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400745 }
746
747 const int leftCols = getCols();
748 const int leftRows = getRows();
Olli Etuaho2cb7b832015-04-23 20:27:44 +0300749 const int rightCols = rightNode->getType().getCols();
750 const int rightRows = rightNode->getType().getRows();
Jamie Madillb1a85f42014-08-19 15:23:24 -0400751 const int resultCols = rightCols;
752 const int resultRows = leftRows;
753
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400754 tempConstArray = new TConstantUnion[resultCols * resultRows];
Jamie Madillb1a85f42014-08-19 15:23:24 -0400755 for (int row = 0; row < resultRows; row++)
756 {
757 for (int column = 0; column < resultCols; column++)
758 {
759 tempConstArray[resultRows * column + row].setFConst(0.0f);
760 for (int i = 0; i < leftCols; i++)
761 {
762 tempConstArray[resultRows * column + row].setFConst(
763 tempConstArray[resultRows * column + row].getFConst() +
764 unionArray[i * leftRows + row].getFConst() *
765 rightUnionArray[column * rightRows + i].getFConst());
766 }
767 }
768 }
769
770 // update return type for matrix product
Minmin Gong794e0002015-04-07 18:31:54 -0700771 returnType.setPrimarySize(static_cast<unsigned char>(resultCols));
772 returnType.setSecondarySize(static_cast<unsigned char>(resultRows));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400773 }
774 break;
775
776 case EOpDiv:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200777 case EOpIMod:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400778 {
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400779 tempConstArray = new TConstantUnion[objectSize];
Jamie Madillb1a85f42014-08-19 15:23:24 -0400780 for (size_t i = 0; i < objectSize; i++)
781 {
782 switch (getType().getBasicType())
783 {
784 case EbtFloat:
785 if (rightUnionArray[i] == 0.0f)
786 {
787 infoSink.info.message(
788 EPrefixWarning, getLine(),
789 "Divide by zero error during constant folding");
790 tempConstArray[i].setFConst(
791 unionArray[i].getFConst() < 0 ? -FLT_MAX : FLT_MAX);
792 }
793 else
794 {
Olli Etuaho3eab00a2015-02-12 16:02:39 +0200795 ASSERT(op == EOpDiv);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400796 tempConstArray[i].setFConst(
797 unionArray[i].getFConst() /
798 rightUnionArray[i].getFConst());
799 }
800 break;
801
802 case EbtInt:
803 if (rightUnionArray[i] == 0)
804 {
805 infoSink.info.message(
806 EPrefixWarning, getLine(),
807 "Divide by zero error during constant folding");
808 tempConstArray[i].setIConst(INT_MAX);
809 }
810 else
811 {
Olli Etuaho3eab00a2015-02-12 16:02:39 +0200812 if (op == EOpDiv)
813 {
814 tempConstArray[i].setIConst(
815 unionArray[i].getIConst() /
816 rightUnionArray[i].getIConst());
817 }
818 else
819 {
820 ASSERT(op == EOpIMod);
821 tempConstArray[i].setIConst(
822 unionArray[i].getIConst() %
823 rightUnionArray[i].getIConst());
824 }
Jamie Madillb1a85f42014-08-19 15:23:24 -0400825 }
826 break;
827
828 case EbtUInt:
829 if (rightUnionArray[i] == 0)
830 {
831 infoSink.info.message(
832 EPrefixWarning, getLine(),
833 "Divide by zero error during constant folding");
834 tempConstArray[i].setUConst(UINT_MAX);
835 }
836 else
837 {
Olli Etuaho3eab00a2015-02-12 16:02:39 +0200838 if (op == EOpDiv)
839 {
840 tempConstArray[i].setUConst(
841 unionArray[i].getUConst() /
842 rightUnionArray[i].getUConst());
843 }
844 else
845 {
846 ASSERT(op == EOpIMod);
847 tempConstArray[i].setUConst(
848 unionArray[i].getUConst() %
849 rightUnionArray[i].getUConst());
850 }
Jamie Madillb1a85f42014-08-19 15:23:24 -0400851 }
852 break;
853
854 default:
855 infoSink.info.message(
856 EPrefixInternalError, getLine(),
857 "Constant folding cannot be done for \"/\"");
Arun Patolefddc2112015-04-22 13:28:10 +0530858 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400859 }
860 }
861 }
862 break;
863
864 case EOpMatrixTimesVector:
865 {
Olli Etuaho2cb7b832015-04-23 20:27:44 +0300866 if (rightNode->getBasicType() != EbtFloat)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400867 {
868 infoSink.info.message(
869 EPrefixInternalError, getLine(),
870 "Constant Folding cannot be done for matrix times vector");
Arun Patolefddc2112015-04-22 13:28:10 +0530871 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400872 }
873
874 const int matrixCols = getCols();
875 const int matrixRows = getRows();
876
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400877 tempConstArray = new TConstantUnion[matrixRows];
Jamie Madillb1a85f42014-08-19 15:23:24 -0400878
879 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
880 {
881 tempConstArray[matrixRow].setFConst(0.0f);
882 for (int col = 0; col < matrixCols; col++)
883 {
884 tempConstArray[matrixRow].setFConst(
885 tempConstArray[matrixRow].getFConst() +
886 unionArray[col * matrixRows + matrixRow].getFConst() *
887 rightUnionArray[col].getFConst());
888 }
889 }
890
Olli Etuaho2cb7b832015-04-23 20:27:44 +0300891 returnType = rightNode->getType();
Minmin Gong794e0002015-04-07 18:31:54 -0700892 returnType.setPrimarySize(static_cast<unsigned char>(matrixRows));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400893
894 tempNode = new TIntermConstantUnion(tempConstArray, returnType);
895 tempNode->setLine(getLine());
896
897 return tempNode;
898 }
899
900 case EOpVectorTimesMatrix:
901 {
902 if (getType().getBasicType() != EbtFloat)
903 {
904 infoSink.info.message(
905 EPrefixInternalError, getLine(),
906 "Constant Folding cannot be done for vector times matrix");
Arun Patolefddc2112015-04-22 13:28:10 +0530907 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400908 }
909
Olli Etuaho2cb7b832015-04-23 20:27:44 +0300910 const int matrixCols = rightNode->getType().getCols();
911 const int matrixRows = rightNode->getType().getRows();
Jamie Madillb1a85f42014-08-19 15:23:24 -0400912
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400913 tempConstArray = new TConstantUnion[matrixCols];
Jamie Madillb1a85f42014-08-19 15:23:24 -0400914
915 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
916 {
917 tempConstArray[matrixCol].setFConst(0.0f);
918 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
919 {
920 tempConstArray[matrixCol].setFConst(
921 tempConstArray[matrixCol].getFConst() +
922 unionArray[matrixRow].getFConst() *
923 rightUnionArray[matrixCol * matrixRows + matrixRow].getFConst());
924 }
925 }
926
Minmin Gong794e0002015-04-07 18:31:54 -0700927 returnType.setPrimarySize(static_cast<unsigned char>(matrixCols));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400928 }
929 break;
930
931 case EOpLogicalAnd:
932 // this code is written for possible future use,
933 // will not get executed currently
934 {
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400935 tempConstArray = new TConstantUnion[objectSize];
Jamie Madillb1a85f42014-08-19 15:23:24 -0400936 for (size_t i = 0; i < objectSize; i++)
937 {
938 tempConstArray[i] = unionArray[i] && rightUnionArray[i];
939 }
940 }
941 break;
942
943 case EOpLogicalOr:
944 // this code is written for possible future use,
945 // will not get executed currently
946 {
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400947 tempConstArray = new TConstantUnion[objectSize];
Jamie Madillb1a85f42014-08-19 15:23:24 -0400948 for (size_t i = 0; i < objectSize; i++)
949 {
950 tempConstArray[i] = unionArray[i] || rightUnionArray[i];
951 }
952 }
953 break;
954
955 case EOpLogicalXor:
956 {
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400957 tempConstArray = new TConstantUnion[objectSize];
Jamie Madillb1a85f42014-08-19 15:23:24 -0400958 for (size_t i = 0; i < objectSize; i++)
959 {
960 switch (getType().getBasicType())
961 {
962 case EbtBool:
963 tempConstArray[i].setBConst(
964 unionArray[i] == rightUnionArray[i] ? false : true);
965 break;
966 default:
967 UNREACHABLE();
968 break;
969 }
970 }
971 }
972 break;
973
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200974 case EOpBitwiseAnd:
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400975 tempConstArray = new TConstantUnion[objectSize];
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200976 for (size_t i = 0; i < objectSize; i++)
977 tempConstArray[i] = unionArray[i] & rightUnionArray[i];
978 break;
979 case EOpBitwiseXor:
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400980 tempConstArray = new TConstantUnion[objectSize];
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200981 for (size_t i = 0; i < objectSize; i++)
982 tempConstArray[i] = unionArray[i] ^ rightUnionArray[i];
983 break;
984 case EOpBitwiseOr:
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400985 tempConstArray = new TConstantUnion[objectSize];
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200986 for (size_t i = 0; i < objectSize; i++)
987 tempConstArray[i] = unionArray[i] | rightUnionArray[i];
988 break;
989 case EOpBitShiftLeft:
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400990 tempConstArray = new TConstantUnion[objectSize];
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200991 for (size_t i = 0; i < objectSize; i++)
992 tempConstArray[i] = unionArray[i] << rightUnionArray[i];
993 break;
994 case EOpBitShiftRight:
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400995 tempConstArray = new TConstantUnion[objectSize];
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200996 for (size_t i = 0; i < objectSize; i++)
997 tempConstArray[i] = unionArray[i] >> rightUnionArray[i];
998 break;
999
Jamie Madillb1a85f42014-08-19 15:23:24 -04001000 case EOpLessThan:
1001 ASSERT(objectSize == 1);
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001002 tempConstArray = new TConstantUnion[1];
Jamie Madillb1a85f42014-08-19 15:23:24 -04001003 tempConstArray->setBConst(*unionArray < *rightUnionArray);
1004 returnType = TType(EbtBool, EbpUndefined, EvqConst);
1005 break;
1006
1007 case EOpGreaterThan:
1008 ASSERT(objectSize == 1);
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001009 tempConstArray = new TConstantUnion[1];
Jamie Madillb1a85f42014-08-19 15:23:24 -04001010 tempConstArray->setBConst(*unionArray > *rightUnionArray);
1011 returnType = TType(EbtBool, EbpUndefined, EvqConst);
1012 break;
1013
1014 case EOpLessThanEqual:
1015 {
1016 ASSERT(objectSize == 1);
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001017 TConstantUnion constant;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001018 constant.setBConst(*unionArray > *rightUnionArray);
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001019 tempConstArray = new TConstantUnion[1];
Jamie Madillb1a85f42014-08-19 15:23:24 -04001020 tempConstArray->setBConst(!constant.getBConst());
1021 returnType = TType(EbtBool, EbpUndefined, EvqConst);
1022 break;
1023 }
1024
1025 case EOpGreaterThanEqual:
1026 {
1027 ASSERT(objectSize == 1);
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001028 TConstantUnion constant;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001029 constant.setBConst(*unionArray < *rightUnionArray);
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001030 tempConstArray = new TConstantUnion[1];
Jamie Madillb1a85f42014-08-19 15:23:24 -04001031 tempConstArray->setBConst(!constant.getBConst());
1032 returnType = TType(EbtBool, EbpUndefined, EvqConst);
1033 break;
1034 }
1035
1036 case EOpEqual:
1037 if (getType().getBasicType() == EbtStruct)
1038 {
Olli Etuaho2cb7b832015-04-23 20:27:44 +03001039 if (!CompareStructure(rightNode->getType(),
1040 rightNode->getUnionArrayPointer(),
Jamie Madillb1a85f42014-08-19 15:23:24 -04001041 unionArray))
1042 {
1043 boolNodeFlag = true;
1044 }
1045 }
1046 else
1047 {
1048 for (size_t i = 0; i < objectSize; i++)
1049 {
1050 if (unionArray[i] != rightUnionArray[i])
1051 {
1052 boolNodeFlag = true;
1053 break; // break out of for loop
1054 }
1055 }
1056 }
1057
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001058 tempConstArray = new TConstantUnion[1];
Jamie Madillb1a85f42014-08-19 15:23:24 -04001059 if (!boolNodeFlag)
1060 {
1061 tempConstArray->setBConst(true);
1062 }
1063 else
1064 {
1065 tempConstArray->setBConst(false);
1066 }
1067
1068 tempNode = new TIntermConstantUnion(
1069 tempConstArray, TType(EbtBool, EbpUndefined, EvqConst));
1070 tempNode->setLine(getLine());
1071
1072 return tempNode;
1073
1074 case EOpNotEqual:
1075 if (getType().getBasicType() == EbtStruct)
1076 {
Olli Etuaho2cb7b832015-04-23 20:27:44 +03001077 if (CompareStructure(rightNode->getType(),
1078 rightNode->getUnionArrayPointer(),
Jamie Madillb1a85f42014-08-19 15:23:24 -04001079 unionArray))
1080 {
1081 boolNodeFlag = true;
1082 }
1083 }
1084 else
1085 {
1086 for (size_t i = 0; i < objectSize; i++)
1087 {
1088 if (unionArray[i] == rightUnionArray[i])
1089 {
1090 boolNodeFlag = true;
1091 break; // break out of for loop
1092 }
1093 }
1094 }
1095
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001096 tempConstArray = new TConstantUnion[1];
Jamie Madillb1a85f42014-08-19 15:23:24 -04001097 if (!boolNodeFlag)
1098 {
1099 tempConstArray->setBConst(true);
1100 }
1101 else
1102 {
1103 tempConstArray->setBConst(false);
1104 }
1105
1106 tempNode = new TIntermConstantUnion(
1107 tempConstArray, TType(EbtBool, EbpUndefined, EvqConst));
1108 tempNode->setLine(getLine());
1109
1110 return tempNode;
1111
1112 default:
1113 infoSink.info.message(
1114 EPrefixInternalError, getLine(),
1115 "Invalid operator for constant folding");
Arun Patolefddc2112015-04-22 13:28:10 +05301116 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001117 }
1118 tempNode = new TIntermConstantUnion(tempConstArray, returnType);
1119 tempNode->setLine(getLine());
1120
1121 return tempNode;
1122 }
1123 else
1124 {
1125 //
1126 // Do unary operations
1127 //
1128 TIntermConstantUnion *newNode = 0;
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001129 TConstantUnion* tempConstArray = new TConstantUnion[objectSize];
Jamie Madillb1a85f42014-08-19 15:23:24 -04001130 for (size_t i = 0; i < objectSize; i++)
1131 {
1132 switch(op)
1133 {
1134 case EOpNegative:
1135 switch (getType().getBasicType())
1136 {
1137 case EbtFloat:
1138 tempConstArray[i].setFConst(-unionArray[i].getFConst());
1139 break;
1140 case EbtInt:
1141 tempConstArray[i].setIConst(-unionArray[i].getIConst());
1142 break;
1143 case EbtUInt:
1144 tempConstArray[i].setUConst(static_cast<unsigned int>(
1145 -static_cast<int>(unionArray[i].getUConst())));
1146 break;
1147 default:
1148 infoSink.info.message(
1149 EPrefixInternalError, getLine(),
1150 "Unary operation not folded into constant");
Arun Patolefddc2112015-04-22 13:28:10 +05301151 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001152 }
1153 break;
1154
Zhenyao Mode1e00e2014-10-09 16:55:32 -07001155 case EOpPositive:
1156 switch (getType().getBasicType())
1157 {
1158 case EbtFloat:
1159 tempConstArray[i].setFConst(unionArray[i].getFConst());
1160 break;
1161 case EbtInt:
1162 tempConstArray[i].setIConst(unionArray[i].getIConst());
1163 break;
1164 case EbtUInt:
1165 tempConstArray[i].setUConst(static_cast<unsigned int>(
1166 static_cast<int>(unionArray[i].getUConst())));
1167 break;
1168 default:
1169 infoSink.info.message(
1170 EPrefixInternalError, getLine(),
1171 "Unary operation not folded into constant");
Arun Patolefddc2112015-04-22 13:28:10 +05301172 return nullptr;
Zhenyao Mode1e00e2014-10-09 16:55:32 -07001173 }
1174 break;
1175
Jamie Madillb1a85f42014-08-19 15:23:24 -04001176 case EOpLogicalNot:
1177 // this code is written for possible future use,
1178 // will not get executed currently
1179 switch (getType().getBasicType())
1180 {
1181 case EbtBool:
1182 tempConstArray[i].setBConst(!unionArray[i].getBConst());
1183 break;
1184 default:
1185 infoSink.info.message(
1186 EPrefixInternalError, getLine(),
1187 "Unary operation not folded into constant");
Arun Patolefddc2112015-04-22 13:28:10 +05301188 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001189 }
1190 break;
1191
Olli Etuaho31b5fc62015-01-16 12:13:36 +02001192 case EOpBitwiseNot:
1193 switch (getType().getBasicType())
1194 {
1195 case EbtInt:
1196 tempConstArray[i].setIConst(~unionArray[i].getIConst());
1197 break;
1198 case EbtUInt:
1199 tempConstArray[i].setUConst(~unionArray[i].getUConst());
1200 break;
1201 default:
1202 infoSink.info.message(
1203 EPrefixInternalError, getLine(),
1204 "Unary operation not folded into constant");
Arun Patolefddc2112015-04-22 13:28:10 +05301205 return nullptr;
Olli Etuaho31b5fc62015-01-16 12:13:36 +02001206 }
1207 break;
1208
Arun Patole9dea48f2015-04-02 11:45:09 +05301209 case EOpRadians:
1210 if (getType().getBasicType() == EbtFloat)
1211 {
1212 tempConstArray[i].setFConst(kDegreesToRadiansMultiplier * unionArray[i].getFConst());
1213 break;
1214 }
1215 infoSink.info.message(
1216 EPrefixInternalError, getLine(),
1217 "Unary operation not folded into constant");
1218 return nullptr;
1219
1220 case EOpDegrees:
1221 if (getType().getBasicType() == EbtFloat)
1222 {
1223 tempConstArray[i].setFConst(kRadiansToDegreesMultiplier * unionArray[i].getFConst());
1224 break;
1225 }
1226 infoSink.info.message(
1227 EPrefixInternalError, getLine(),
1228 "Unary operation not folded into constant");
1229 return nullptr;
1230
1231 case EOpSin:
1232 if (!foldFloatTypeUnary(unionArray[i], &sinf, infoSink, &tempConstArray[i]))
1233 return nullptr;
1234 break;
1235
1236 case EOpCos:
1237 if (!foldFloatTypeUnary(unionArray[i], &cosf, infoSink, &tempConstArray[i]))
1238 return nullptr;
1239 break;
1240
1241 case EOpTan:
1242 if (!foldFloatTypeUnary(unionArray[i], &tanf, infoSink, &tempConstArray[i]))
1243 return nullptr;
1244 break;
1245
1246 case EOpAsin:
1247 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to 0.
1248 if (getType().getBasicType() == EbtFloat && fabsf(unionArray[i].getFConst()) > 1.0f)
1249 tempConstArray[i].setFConst(0.0f);
1250 else if (!foldFloatTypeUnary(unionArray[i], &asinf, infoSink, &tempConstArray[i]))
1251 return nullptr;
1252 break;
1253
1254 case EOpAcos:
1255 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to 0.
1256 if (getType().getBasicType() == EbtFloat && fabsf(unionArray[i].getFConst()) > 1.0f)
1257 tempConstArray[i].setFConst(0.0f);
1258 else if (!foldFloatTypeUnary(unionArray[i], &acosf, infoSink, &tempConstArray[i]))
1259 return nullptr;
1260 break;
1261
1262 case EOpAtan:
1263 if (!foldFloatTypeUnary(unionArray[i], &atanf, infoSink, &tempConstArray[i]))
1264 return nullptr;
1265 break;
1266
1267 case EOpSinh:
1268 if (!foldFloatTypeUnary(unionArray[i], &sinhf, infoSink, &tempConstArray[i]))
1269 return nullptr;
1270 break;
1271
1272 case EOpCosh:
1273 if (!foldFloatTypeUnary(unionArray[i], &coshf, infoSink, &tempConstArray[i]))
1274 return nullptr;
1275 break;
1276
1277 case EOpTanh:
1278 if (!foldFloatTypeUnary(unionArray[i], &tanhf, infoSink, &tempConstArray[i]))
1279 return nullptr;
1280 break;
1281
1282 case EOpAsinh:
1283 if (!foldFloatTypeUnary(unionArray[i], &asinhf, infoSink, &tempConstArray[i]))
1284 return nullptr;
1285 break;
1286
1287 case EOpAcosh:
1288 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
1289 if (getType().getBasicType() == EbtFloat && unionArray[i].getFConst() < 1.0f)
1290 tempConstArray[i].setFConst(0.0f);
1291 else if (!foldFloatTypeUnary(unionArray[i], &acoshf, infoSink, &tempConstArray[i]))
1292 return nullptr;
1293 break;
1294
1295 case EOpAtanh:
1296 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to 0.
1297 if (getType().getBasicType() == EbtFloat && fabsf(unionArray[i].getFConst()) >= 1.0f)
1298 tempConstArray[i].setFConst(0.0f);
1299 else if (!foldFloatTypeUnary(unionArray[i], &atanhf, infoSink, &tempConstArray[i]))
1300 return nullptr;
1301 break;
1302
Arun Patole97dc22e2015-04-06 17:35:38 +05301303 case EOpAbs:
1304 switch (getType().getBasicType())
1305 {
1306 case EbtFloat:
1307 tempConstArray[i].setFConst(fabsf(unionArray[i].getFConst()));
1308 break;
1309 case EbtInt:
1310 tempConstArray[i].setIConst(abs(unionArray[i].getIConst()));
1311 break;
1312 default:
1313 infoSink.info.message(
1314 EPrefixInternalError, getLine(),
1315 "Unary operation not folded into constant");
1316 return nullptr;
1317 }
1318 break;
1319
1320 case EOpSign:
1321 switch (getType().getBasicType())
1322 {
1323 case EbtFloat:
1324 {
1325 float fConst = unionArray[i].getFConst();
1326 float fResult = 0.0f;
1327 if (fConst > 0.0f)
1328 fResult = 1.0f;
1329 else if (fConst < 0.0f)
1330 fResult = -1.0f;
1331 tempConstArray[i].setFConst(fResult);
1332 }
1333 break;
1334 case EbtInt:
1335 {
1336 int iConst = unionArray[i].getIConst();
1337 int iResult = 0;
1338 if (iConst > 0)
1339 iResult = 1;
1340 else if (iConst < 0)
1341 iResult = -1;
1342 tempConstArray[i].setIConst(iResult);
1343 }
1344 break;
1345 default:
1346 infoSink.info.message(
1347 EPrefixInternalError, getLine(),
1348 "Unary operation not folded into constant");
1349 return nullptr;
1350 }
1351 break;
1352
1353 case EOpFloor:
1354 if (!foldFloatTypeUnary(unionArray[i], &floorf, infoSink, &tempConstArray[i]))
1355 return nullptr;
1356 break;
1357
1358 case EOpTrunc:
1359 if (!foldFloatTypeUnary(unionArray[i], &truncf, infoSink, &tempConstArray[i]))
1360 return nullptr;
1361 break;
1362
1363 case EOpRound:
1364 if (!foldFloatTypeUnary(unionArray[i], &roundf, infoSink, &tempConstArray[i]))
1365 return nullptr;
1366 break;
1367
1368 case EOpRoundEven:
1369 if (getType().getBasicType() == EbtFloat)
1370 {
1371 float x = unionArray[i].getFConst();
1372 float result;
1373 float fractPart = modff(x, &result);
1374 if (fabsf(fractPart) == 0.5f)
1375 result = 2.0f * roundf(x / 2.0f);
1376 else
1377 result = roundf(x);
1378 tempConstArray[i].setFConst(result);
1379 break;
1380 }
1381 infoSink.info.message(
1382 EPrefixInternalError, getLine(),
1383 "Unary operation not folded into constant");
1384 return nullptr;
1385
1386 case EOpCeil:
1387 if (!foldFloatTypeUnary(unionArray[i], &ceilf, infoSink, &tempConstArray[i]))
1388 return nullptr;
1389 break;
1390
1391 case EOpFract:
1392 if (getType().getBasicType() == EbtFloat)
1393 {
1394 float x = unionArray[i].getFConst();
1395 tempConstArray[i].setFConst(x - floorf(x));
1396 break;
1397 }
1398 infoSink.info.message(
1399 EPrefixInternalError, getLine(),
1400 "Unary operation not folded into constant");
1401 return nullptr;
1402
Arun Patole28eb65e2015-04-06 17:29:48 +05301403 case EOpExp:
1404 if (!foldFloatTypeUnary(unionArray[i], &expf, infoSink, &tempConstArray[i]))
1405 return nullptr;
1406 break;
1407
1408 case EOpLog:
1409 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
1410 if (getType().getBasicType() == EbtFloat && unionArray[i].getFConst() <= 0.0f)
1411 tempConstArray[i].setFConst(0.0f);
1412 else if (!foldFloatTypeUnary(unionArray[i], &logf, infoSink, &tempConstArray[i]))
1413 return nullptr;
1414 break;
1415
1416 case EOpExp2:
1417 if (!foldFloatTypeUnary(unionArray[i], &exp2f, infoSink, &tempConstArray[i]))
1418 return nullptr;
1419 break;
1420
1421 case EOpLog2:
1422 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
1423 // And log2f is not available on some plarforms like old android, so just using log(x)/log(2) here.
1424 if (getType().getBasicType() == EbtFloat && unionArray[i].getFConst() <= 0.0f)
1425 tempConstArray[i].setFConst(0.0f);
1426 else if (!foldFloatTypeUnary(unionArray[i], &logf, infoSink, &tempConstArray[i]))
1427 return nullptr;
1428 else
1429 tempConstArray[i].setFConst(tempConstArray[i].getFConst() / logf(2.0f));
1430 break;
1431
1432 case EOpSqrt:
1433 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
1434 if (getType().getBasicType() == EbtFloat && unionArray[i].getFConst() < 0.0f)
1435 tempConstArray[i].setFConst(0.0f);
1436 else if (!foldFloatTypeUnary(unionArray[i], &sqrtf, infoSink, &tempConstArray[i]))
1437 return nullptr;
1438 break;
1439
1440 case EOpInverseSqrt:
1441 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
1442 // so getting the square root first using builtin function sqrt() and then taking its inverse.
1443 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set result to 0.
1444 if (getType().getBasicType() == EbtFloat && unionArray[i].getFConst() <= 0.0f)
1445 tempConstArray[i].setFConst(0.0f);
1446 else if (!foldFloatTypeUnary(unionArray[i], &sqrtf, infoSink, &tempConstArray[i]))
1447 return nullptr;
1448 else
1449 tempConstArray[i].setFConst(1.0f / tempConstArray[i].getFConst());
1450 break;
1451
Jamie Madillb1a85f42014-08-19 15:23:24 -04001452 default:
Arun Patolefddc2112015-04-22 13:28:10 +05301453 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001454 }
1455 }
1456 newNode = new TIntermConstantUnion(tempConstArray, getType());
1457 newNode->setLine(getLine());
1458 return newNode;
1459 }
1460}
1461
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001462bool TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter, FloatTypeUnaryFunc builtinFunc,
1463 TInfoSink &infoSink, TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05301464{
1465 ASSERT(builtinFunc);
1466
1467 if (getType().getBasicType() == EbtFloat)
1468 {
1469 result->setFConst(builtinFunc(parameter.getFConst()));
1470 return true;
1471 }
1472
1473 infoSink.info.message(
1474 EPrefixInternalError, getLine(),
1475 "Unary operation not folded into constant");
1476 return false;
1477}
1478
Jamie Madillb1a85f42014-08-19 15:23:24 -04001479// static
Arun Patole1137a2a2015-05-05 13:33:30 +05301480TIntermTyped *TIntermConstantUnion::FoldAggregateBuiltIn(TOperator op, TIntermAggregate *aggregate)
1481{
1482 TIntermSequence *sequence = aggregate->getSequence();
1483 unsigned int paramsCount = sequence->size();
1484 TConstantUnion **unionArrays = new TConstantUnion*[paramsCount];
1485 size_t *objectSizes = new size_t[paramsCount];
1486 TType *maxSizeType = nullptr;
1487 TBasicType basicType = EbtVoid;
1488 TSourceLoc loc;
1489 for (unsigned int i = 0; i < paramsCount; i++)
1490 {
1491 TIntermConstantUnion *paramConstant = (*sequence)[i]->getAsConstantUnion();
1492 // Make sure that all params are constant before actual constant folding.
1493 if (!paramConstant)
1494 return nullptr;
1495
1496 if (i == 0)
1497 {
1498 basicType = paramConstant->getType().getBasicType();
1499 loc = paramConstant->getLine();
1500 }
1501 unionArrays[i] = paramConstant->getUnionArrayPointer();
1502 objectSizes[i] = paramConstant->getType().getObjectSize();
1503 if (maxSizeType == nullptr || (objectSizes[i] >= maxSizeType->getObjectSize()))
1504 maxSizeType = paramConstant->getTypePointer();
1505 }
1506
1507 size_t maxObjectSize = maxSizeType->getObjectSize();
1508 for (unsigned int i = 0; i < paramsCount; i++)
1509 if (objectSizes[i] != maxObjectSize)
1510 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
1511 SafeDeleteArray(objectSizes);
1512
1513 TConstantUnion *tempConstArray = nullptr;
1514 TIntermConstantUnion *tempNode = nullptr;
1515 TType returnType = *maxSizeType;
1516 if (paramsCount == 2)
1517 {
1518 //
1519 // Binary built-in
1520 //
1521 switch (op)
1522 {
1523 case EOpMin:
1524 {
1525 tempConstArray = new TConstantUnion[maxObjectSize];
1526 for (size_t i = 0; i < maxObjectSize; i++)
1527 {
1528 switch (basicType)
1529 {
1530 case EbtFloat:
1531 tempConstArray[i].setFConst(std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
1532 break;
1533 case EbtInt:
1534 tempConstArray[i].setIConst(std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
1535 break;
1536 case EbtUInt:
1537 tempConstArray[i].setUConst(std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
1538 break;
1539 default:
1540 UNREACHABLE();
1541 break;
1542 }
1543 }
1544 }
1545 break;
1546
1547 case EOpMax:
1548 {
1549 tempConstArray = new TConstantUnion[maxObjectSize];
1550 for (size_t i = 0; i < maxObjectSize; i++)
1551 {
1552 switch (basicType)
1553 {
1554 case EbtFloat:
1555 tempConstArray[i].setFConst(std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
1556 break;
1557 case EbtInt:
1558 tempConstArray[i].setIConst(std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
1559 break;
1560 case EbtUInt:
1561 tempConstArray[i].setUConst(std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
1562 break;
1563 default:
1564 UNREACHABLE();
1565 break;
1566 }
1567 }
1568 }
1569 break;
1570
1571 default:
1572 UNREACHABLE();
1573 // TODO: Add constant folding support for other built-in operations that take 2 parameters and not handled above.
1574 return nullptr;
1575 }
1576 }
1577 else if (paramsCount == 3)
1578 {
1579 //
1580 // Ternary built-in
1581 //
1582 switch (op)
1583 {
1584 case EOpClamp:
1585 {
1586 tempConstArray = new TConstantUnion[maxObjectSize];
1587 for (size_t i = 0; i < maxObjectSize; i++)
1588 {
1589 switch (basicType)
1590 {
1591 case EbtFloat:
1592 {
1593 float x = unionArrays[0][i].getFConst();
1594 float min = unionArrays[1][i].getFConst();
1595 float max = unionArrays[2][i].getFConst();
1596 // Results are undefined if min > max.
1597 if (min > max)
1598 tempConstArray[i].setFConst(0.0f);
1599 else
1600 tempConstArray[i].setFConst(gl::clamp(x, min, max));
1601 }
1602 break;
1603 case EbtInt:
1604 {
1605 int x = unionArrays[0][i].getIConst();
1606 int min = unionArrays[1][i].getIConst();
1607 int max = unionArrays[2][i].getIConst();
1608 // Results are undefined if min > max.
1609 if (min > max)
1610 tempConstArray[i].setIConst(0);
1611 else
1612 tempConstArray[i].setIConst(gl::clamp(x, min, max));
1613 }
1614 break;
1615 case EbtUInt:
1616 {
1617 unsigned int x = unionArrays[0][i].getUConst();
1618 unsigned int min = unionArrays[1][i].getUConst();
1619 unsigned int max = unionArrays[2][i].getUConst();
1620 // Results are undefined if min > max.
1621 if (min > max)
1622 tempConstArray[i].setUConst(0u);
1623 else
1624 tempConstArray[i].setUConst(gl::clamp(x, min, max));
1625 }
1626 break;
1627 default:
1628 UNREACHABLE();
1629 break;
1630 }
1631 }
1632 }
1633 break;
1634
1635 default:
1636 UNREACHABLE();
1637 // TODO: Add constant folding support for other built-in operations that take 3 parameters and not handled above.
1638 return nullptr;
1639 }
1640 }
1641
1642 if (tempConstArray)
1643 {
1644 tempNode = new TIntermConstantUnion(tempConstArray, returnType);
1645 tempNode->setLine(loc);
1646 }
1647 SafeDeleteArray(unionArrays);
1648 return tempNode;
1649}
1650
1651// static
Jamie Madillb1a85f42014-08-19 15:23:24 -04001652TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunction)
1653{
1654 if (hashFunction == NULL || name.empty())
1655 return name;
1656 khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
1657 TStringStream stream;
1658 stream << HASHED_NAME_PREFIX << std::hex << number;
1659 TString hashedName = stream.str();
1660 return hashedName;
1661}
Olli Etuaho853dc1a2014-11-06 17:25:48 +02001662
1663void TIntermTraverser::updateTree()
1664{
1665 for (size_t ii = 0; ii < mReplacements.size(); ++ii)
1666 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03001667 const NodeUpdateEntry &replacement = mReplacements[ii];
1668 ASSERT(replacement.parent);
1669 bool replaced = replacement.parent->replaceChildNode(
1670 replacement.original, replacement.replacement);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02001671 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03001672 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02001673
Olli Etuahocd94ef92015-04-16 19:18:10 +03001674 if (!replacement.originalBecomesChildOfReplacement)
Olli Etuaho853dc1a2014-11-06 17:25:48 +02001675 {
1676 // In AST traversing, a parent is visited before its children.
Olli Etuahocd94ef92015-04-16 19:18:10 +03001677 // After we replace a node, if its immediate child is to
Olli Etuaho853dc1a2014-11-06 17:25:48 +02001678 // be replaced, we need to make sure we don't update the replaced
1679 // node; instead, we update the replacement node.
1680 for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj)
1681 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03001682 NodeUpdateEntry &replacement2 = mReplacements[jj];
1683 if (replacement2.parent == replacement.original)
1684 replacement2.parent = replacement.replacement;
Olli Etuaho853dc1a2014-11-06 17:25:48 +02001685 }
1686 }
1687 }
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03001688 for (size_t ii = 0; ii < mMultiReplacements.size(); ++ii)
1689 {
1690 const NodeReplaceWithMultipleEntry &replacement = mMultiReplacements[ii];
1691 ASSERT(replacement.parent);
1692 bool replaced = replacement.parent->replaceChildNodeWithMultiple(
1693 replacement.original, replacement.replacements);
1694 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03001695 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03001696 }
Olli Etuaho853dc1a2014-11-06 17:25:48 +02001697}