blob: 2ce85e0fb0c98565b2f4b8bc4c06f2b28301ba4b [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>
Arun Patole274f0702015-05-05 13:33:30 +053016#include <vector>
Jamie Madillb1a85f42014-08-19 15:23:24 -040017
Arun Patole274f0702015-05-05 13:33:30 +053018#include "common/mathutil.h"
Arun Patole7fa33552015-06-10 15:15:18 +053019#include "common/matrix_utils.h"
Jamie Madillb1a85f42014-08-19 15:23:24 -040020#include "compiler/translator/HashNames.h"
21#include "compiler/translator/IntermNode.h"
22#include "compiler/translator/SymbolTable.h"
23
24namespace
25{
26
Arun Patole9dea48f2015-04-02 11:45:09 +053027const float kPi = 3.14159265358979323846f;
28const float kDegreesToRadiansMultiplier = kPi / 180.0f;
29const float kRadiansToDegreesMultiplier = 180.0f / kPi;
30
Jamie Madillb1a85f42014-08-19 15:23:24 -040031TPrecision GetHigherPrecision(TPrecision left, TPrecision right)
32{
33 return left > right ? left : right;
34}
35
36bool ValidateMultiplication(TOperator op, const TType &left, const TType &right)
37{
38 switch (op)
39 {
40 case EOpMul:
41 case EOpMulAssign:
42 return left.getNominalSize() == right.getNominalSize() &&
43 left.getSecondarySize() == right.getSecondarySize();
44 case EOpVectorTimesScalar:
45 case EOpVectorTimesScalarAssign:
46 return true;
47 case EOpVectorTimesMatrix:
48 return left.getNominalSize() == right.getRows();
49 case EOpVectorTimesMatrixAssign:
50 return left.getNominalSize() == right.getRows() &&
51 left.getNominalSize() == right.getCols();
52 case EOpMatrixTimesVector:
53 return left.getCols() == right.getNominalSize();
54 case EOpMatrixTimesScalar:
55 case EOpMatrixTimesScalarAssign:
56 return true;
57 case EOpMatrixTimesMatrix:
58 return left.getCols() == right.getRows();
59 case EOpMatrixTimesMatrixAssign:
Olli Etuahodcf12c72016-06-28 15:03:06 +030060 // We need to check two things:
61 // 1. The matrix multiplication step is valid.
62 // 2. The result will have the same number of columns as the lvalue.
63 return left.getCols() == right.getRows() && left.getCols() == right.getCols();
Jamie Madillb1a85f42014-08-19 15:23:24 -040064
65 default:
66 UNREACHABLE();
67 return false;
68 }
69}
70
Arun Patole274f0702015-05-05 13:33:30 +053071TConstantUnion *Vectorize(const TConstantUnion &constant, size_t size)
72{
73 TConstantUnion *constUnion = new TConstantUnion[size];
74 for (unsigned int i = 0; i < size; ++i)
75 constUnion[i] = constant;
76
77 return constUnion;
78}
79
Arun Patolebf790422015-05-18 17:53:04 +053080void UndefinedConstantFoldingError(const TSourceLoc &loc, TOperator op, TBasicType basicType,
81 TInfoSink &infoSink, TConstantUnion *result)
82{
83 std::stringstream constantFoldingErrorStream;
84 constantFoldingErrorStream << "'" << GetOperatorString(op)
85 << "' operation result is undefined for the values passed in";
86 infoSink.info.message(EPrefixWarning, loc, constantFoldingErrorStream.str().c_str());
87
88 switch (basicType)
89 {
90 case EbtFloat :
91 result->setFConst(0.0f);
92 break;
93 case EbtInt:
94 result->setIConst(0);
95 break;
96 case EbtUInt:
97 result->setUConst(0u);
98 break;
99 case EbtBool:
100 result->setBConst(false);
101 break;
102 default:
103 break;
104 }
105}
106
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200107float VectorLength(const TConstantUnion *paramArray, size_t paramArraySize)
Arun Patole1155ddd2015-06-05 18:04:36 +0530108{
109 float result = 0.0f;
110 for (size_t i = 0; i < paramArraySize; i++)
111 {
112 float f = paramArray[i].getFConst();
113 result += f * f;
114 }
115 return sqrtf(result);
116}
117
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200118float VectorDotProduct(const TConstantUnion *paramArray1,
119 const TConstantUnion *paramArray2,
120 size_t paramArraySize)
Arun Patole1155ddd2015-06-05 18:04:36 +0530121{
122 float result = 0.0f;
123 for (size_t i = 0; i < paramArraySize; i++)
124 result += paramArray1[i].getFConst() * paramArray2[i].getFConst();
125 return result;
126}
127
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200128TIntermTyped *CreateFoldedNode(TConstantUnion *constArray,
129 const TIntermTyped *originalNode,
130 TQualifier qualifier)
Olli Etuahob43846e2015-06-02 18:18:57 +0300131{
132 if (constArray == nullptr)
133 {
134 return nullptr;
135 }
136 TIntermTyped *folded = new TIntermConstantUnion(constArray, originalNode->getType());
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200137 folded->getTypePointer()->setQualifier(qualifier);
Olli Etuahob43846e2015-06-02 18:18:57 +0300138 folded->setLine(originalNode->getLine());
139 return folded;
140}
141
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200142angle::Matrix<float> GetMatrix(const TConstantUnion *paramArray,
143 const unsigned int &rows,
144 const unsigned int &cols)
Arun Patole7fa33552015-06-10 15:15:18 +0530145{
146 std::vector<float> elements;
147 for (size_t i = 0; i < rows * cols; i++)
148 elements.push_back(paramArray[i].getFConst());
149 // Transpose is used since the Matrix constructor expects arguments in row-major order,
150 // whereas the paramArray is in column-major order.
151 return angle::Matrix<float>(elements, rows, cols).transpose();
152}
153
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200154angle::Matrix<float> GetMatrix(const TConstantUnion *paramArray, const unsigned int &size)
Arun Patole7fa33552015-06-10 15:15:18 +0530155{
156 std::vector<float> elements;
157 for (size_t i = 0; i < size * size; i++)
158 elements.push_back(paramArray[i].getFConst());
159 // Transpose is used since the Matrix constructor expects arguments in row-major order,
160 // whereas the paramArray is in column-major order.
161 return angle::Matrix<float>(elements, size).transpose();
162}
163
164void SetUnionArrayFromMatrix(const angle::Matrix<float> &m, TConstantUnion *resultArray)
165{
166 // Transpose is used since the input Matrix is in row-major order,
167 // whereas the actual result should be in column-major order.
168 angle::Matrix<float> result = m.transpose();
169 std::vector<float> resultElements = result.elements();
170 for (size_t i = 0; i < resultElements.size(); i++)
171 resultArray[i].setFConst(resultElements[i]);
172}
173
Jamie Madillb1a85f42014-08-19 15:23:24 -0400174} // namespace anonymous
175
176
177////////////////////////////////////////////////////////////////
178//
179// Member functions of the nodes used for building the tree.
180//
181////////////////////////////////////////////////////////////////
182
Olli Etuahod2a67b92014-10-21 16:42:57 +0300183void TIntermTyped::setTypePreservePrecision(const TType &t)
184{
185 TPrecision precision = getPrecision();
186 mType = t;
187 ASSERT(mType.getBasicType() != EbtBool || precision == EbpUndefined);
188 mType.setPrecision(precision);
189}
190
Jamie Madillb1a85f42014-08-19 15:23:24 -0400191#define REPLACE_IF_IS(node, type, original, replacement) \
192 if (node == original) { \
193 node = static_cast<type *>(replacement); \
194 return true; \
195 }
196
197bool TIntermLoop::replaceChildNode(
198 TIntermNode *original, TIntermNode *replacement)
199{
Olli Etuaho3cbb27a2016-07-14 11:55:48 +0300200 ASSERT(original != nullptr); // This risks replacing multiple children.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400201 REPLACE_IF_IS(mInit, TIntermNode, original, replacement);
202 REPLACE_IF_IS(mCond, TIntermTyped, original, replacement);
203 REPLACE_IF_IS(mExpr, TIntermTyped, original, replacement);
Olli Etuaho3fed4302015-11-02 12:26:02 +0200204 REPLACE_IF_IS(mBody, TIntermAggregate, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400205 return false;
206}
207
Jamie Madillb1a85f42014-08-19 15:23:24 -0400208bool TIntermBranch::replaceChildNode(
209 TIntermNode *original, TIntermNode *replacement)
210{
211 REPLACE_IF_IS(mExpression, TIntermTyped, original, replacement);
212 return false;
213}
214
Jamie Madillb1a85f42014-08-19 15:23:24 -0400215bool TIntermBinary::replaceChildNode(
216 TIntermNode *original, TIntermNode *replacement)
217{
218 REPLACE_IF_IS(mLeft, TIntermTyped, original, replacement);
219 REPLACE_IF_IS(mRight, TIntermTyped, original, replacement);
220 return false;
221}
222
Jamie Madillb1a85f42014-08-19 15:23:24 -0400223bool TIntermUnary::replaceChildNode(
224 TIntermNode *original, TIntermNode *replacement)
225{
226 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
227 return false;
228}
229
Jamie Madillb1a85f42014-08-19 15:23:24 -0400230bool TIntermAggregate::replaceChildNode(
231 TIntermNode *original, TIntermNode *replacement)
232{
233 for (size_t ii = 0; ii < mSequence.size(); ++ii)
234 {
235 REPLACE_IF_IS(mSequence[ii], TIntermNode, original, replacement);
236 }
237 return false;
238}
239
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300240bool TIntermAggregate::replaceChildNodeWithMultiple(TIntermNode *original, TIntermSequence replacements)
241{
242 for (auto it = mSequence.begin(); it < mSequence.end(); ++it)
243 {
244 if (*it == original)
245 {
246 it = mSequence.erase(it);
Olli Etuaho8fee0ab2015-04-23 14:52:46 +0300247 mSequence.insert(it, replacements.begin(), replacements.end());
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300248 return true;
249 }
250 }
251 return false;
252}
253
Olli Etuahoa6f22092015-05-08 18:31:10 +0300254bool TIntermAggregate::insertChildNodes(TIntermSequence::size_type position, TIntermSequence insertions)
255{
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300256 if (position > mSequence.size())
Olli Etuahoa6f22092015-05-08 18:31:10 +0300257 {
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300258 return false;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300259 }
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300260 auto it = mSequence.begin() + position;
261 mSequence.insert(it, insertions.begin(), insertions.end());
262 return true;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300263}
264
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200265bool TIntermAggregate::areChildrenConstQualified()
266{
267 for (TIntermNode *&child : mSequence)
268 {
269 TIntermTyped *typed = child->getAsTyped();
270 if (typed && typed->getQualifier() != EvqConst)
271 {
272 return false;
273 }
274 }
275 return true;
276}
277
Olli Etuahod2a67b92014-10-21 16:42:57 +0300278void TIntermAggregate::setPrecisionFromChildren()
279{
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300280 mGotPrecisionFromChildren = true;
Olli Etuahod2a67b92014-10-21 16:42:57 +0300281 if (getBasicType() == EbtBool)
282 {
283 mType.setPrecision(EbpUndefined);
284 return;
285 }
286
287 TPrecision precision = EbpUndefined;
288 TIntermSequence::iterator childIter = mSequence.begin();
289 while (childIter != mSequence.end())
290 {
291 TIntermTyped *typed = (*childIter)->getAsTyped();
292 if (typed)
293 precision = GetHigherPrecision(typed->getPrecision(), precision);
294 ++childIter;
295 }
296 mType.setPrecision(precision);
297}
298
299void TIntermAggregate::setBuiltInFunctionPrecision()
300{
301 // All built-ins returning bool should be handled as ops, not functions.
302 ASSERT(getBasicType() != EbtBool);
303
304 TPrecision precision = EbpUndefined;
305 TIntermSequence::iterator childIter = mSequence.begin();
306 while (childIter != mSequence.end())
307 {
308 TIntermTyped *typed = (*childIter)->getAsTyped();
309 // ESSL spec section 8: texture functions get their precision from the sampler.
310 if (typed && IsSampler(typed->getBasicType()))
311 {
312 precision = typed->getPrecision();
313 break;
314 }
315 ++childIter;
316 }
317 // ESSL 3.0 spec section 8: textureSize always gets highp precision.
318 // All other functions that take a sampler are assumed to be texture functions.
Olli Etuaho59f9a642015-08-06 20:38:26 +0300319 if (mName.getString().find("textureSize") == 0)
Olli Etuahod2a67b92014-10-21 16:42:57 +0300320 mType.setPrecision(EbpHigh);
321 else
322 mType.setPrecision(precision);
323}
324
Jamie Madillb1a85f42014-08-19 15:23:24 -0400325bool TIntermSelection::replaceChildNode(
326 TIntermNode *original, TIntermNode *replacement)
327{
328 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
329 REPLACE_IF_IS(mTrueBlock, TIntermNode, original, replacement);
330 REPLACE_IF_IS(mFalseBlock, TIntermNode, original, replacement);
331 return false;
332}
333
Olli Etuahoa3a36662015-02-17 13:46:51 +0200334bool TIntermSwitch::replaceChildNode(
335 TIntermNode *original, TIntermNode *replacement)
336{
337 REPLACE_IF_IS(mInit, TIntermTyped, original, replacement);
338 REPLACE_IF_IS(mStatementList, TIntermAggregate, original, replacement);
339 return false;
340}
341
342bool TIntermCase::replaceChildNode(
343 TIntermNode *original, TIntermNode *replacement)
344{
345 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
346 return false;
347}
348
Olli Etuahod7a25242015-08-18 13:49:45 +0300349TIntermTyped::TIntermTyped(const TIntermTyped &node) : TIntermNode(), mType(node.mType)
350{
351 // Copy constructor is disallowed for TIntermNode in order to disallow it for subclasses that
352 // don't explicitly allow it, so normal TIntermNode constructor is used to construct the copy.
353 // We need to manually copy any fields of TIntermNode besides handling fields in TIntermTyped.
354 mLine = node.mLine;
355}
356
Olli Etuahod4f4c112016-04-15 15:11:24 +0300357bool TIntermTyped::isConstructorWithOnlyConstantUnionParameters()
358{
359 TIntermAggregate *constructor = getAsAggregate();
360 if (!constructor || !constructor->isConstructor())
361 {
362 return false;
363 }
364 for (TIntermNode *&node : *constructor->getSequence())
365 {
366 if (!node->getAsConstantUnion())
367 return false;
368 }
369 return true;
370}
371
Olli Etuahod7a25242015-08-18 13:49:45 +0300372TIntermConstantUnion::TIntermConstantUnion(const TIntermConstantUnion &node) : TIntermTyped(node)
373{
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200374 mUnionArrayPointer = node.mUnionArrayPointer;
Olli Etuahod7a25242015-08-18 13:49:45 +0300375}
376
377TIntermAggregate::TIntermAggregate(const TIntermAggregate &node)
378 : TIntermOperator(node),
379 mName(node.mName),
380 mUserDefined(node.mUserDefined),
381 mFunctionId(node.mFunctionId),
Olli Etuahod7a25242015-08-18 13:49:45 +0300382 mUseEmulatedFunction(node.mUseEmulatedFunction),
383 mGotPrecisionFromChildren(node.mGotPrecisionFromChildren)
384{
385 for (TIntermNode *child : node.mSequence)
386 {
387 TIntermTyped *typedChild = child->getAsTyped();
388 ASSERT(typedChild != nullptr);
389 TIntermTyped *childCopy = typedChild->deepCopy();
390 mSequence.push_back(childCopy);
391 }
392}
393
394TIntermBinary::TIntermBinary(const TIntermBinary &node)
395 : TIntermOperator(node), mAddIndexClamp(node.mAddIndexClamp)
396{
397 TIntermTyped *leftCopy = node.mLeft->deepCopy();
398 TIntermTyped *rightCopy = node.mRight->deepCopy();
399 ASSERT(leftCopy != nullptr && rightCopy != nullptr);
400 mLeft = leftCopy;
401 mRight = rightCopy;
402}
403
404TIntermUnary::TIntermUnary(const TIntermUnary &node)
405 : TIntermOperator(node), mUseEmulatedFunction(node.mUseEmulatedFunction)
406{
407 TIntermTyped *operandCopy = node.mOperand->deepCopy();
408 ASSERT(operandCopy != nullptr);
409 mOperand = operandCopy;
410}
411
412TIntermSelection::TIntermSelection(const TIntermSelection &node) : TIntermTyped(node)
413{
414 // Only supported for ternary nodes, not if statements.
415 TIntermTyped *trueTyped = node.mTrueBlock->getAsTyped();
416 TIntermTyped *falseTyped = node.mFalseBlock->getAsTyped();
417 ASSERT(trueTyped != nullptr);
418 ASSERT(falseTyped != nullptr);
419 TIntermTyped *conditionCopy = node.mCondition->deepCopy();
420 TIntermTyped *trueCopy = trueTyped->deepCopy();
421 TIntermTyped *falseCopy = falseTyped->deepCopy();
422 ASSERT(conditionCopy != nullptr && trueCopy != nullptr && falseCopy != nullptr);
423 mCondition = conditionCopy;
424 mTrueBlock = trueCopy;
425 mFalseBlock = falseCopy;
426}
427
Jamie Madillb1a85f42014-08-19 15:23:24 -0400428//
429// Say whether or not an operation node changes the value of a variable.
430//
431bool TIntermOperator::isAssignment() const
432{
433 switch (mOp)
434 {
435 case EOpPostIncrement:
436 case EOpPostDecrement:
437 case EOpPreIncrement:
438 case EOpPreDecrement:
439 case EOpAssign:
440 case EOpAddAssign:
441 case EOpSubAssign:
442 case EOpMulAssign:
443 case EOpVectorTimesMatrixAssign:
444 case EOpVectorTimesScalarAssign:
445 case EOpMatrixTimesScalarAssign:
446 case EOpMatrixTimesMatrixAssign:
447 case EOpDivAssign:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200448 case EOpIModAssign:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200449 case EOpBitShiftLeftAssign:
450 case EOpBitShiftRightAssign:
451 case EOpBitwiseAndAssign:
452 case EOpBitwiseXorAssign:
453 case EOpBitwiseOrAssign:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400454 return true;
455 default:
456 return false;
457 }
458}
459
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300460bool TIntermOperator::isMultiplication() const
461{
462 switch (mOp)
463 {
464 case EOpMul:
465 case EOpMatrixTimesMatrix:
466 case EOpMatrixTimesVector:
467 case EOpMatrixTimesScalar:
468 case EOpVectorTimesMatrix:
469 case EOpVectorTimesScalar:
470 return true;
471 default:
472 return false;
473 }
474}
475
Jamie Madillb1a85f42014-08-19 15:23:24 -0400476//
477// returns true if the operator is for one of the constructors
478//
479bool TIntermOperator::isConstructor() const
480{
481 switch (mOp)
482 {
483 case EOpConstructVec2:
484 case EOpConstructVec3:
485 case EOpConstructVec4:
486 case EOpConstructMat2:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400487 case EOpConstructMat2x3:
488 case EOpConstructMat2x4:
489 case EOpConstructMat3x2:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400490 case EOpConstructMat3:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400491 case EOpConstructMat3x4:
492 case EOpConstructMat4x2:
493 case EOpConstructMat4x3:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400494 case EOpConstructMat4:
495 case EOpConstructFloat:
496 case EOpConstructIVec2:
497 case EOpConstructIVec3:
498 case EOpConstructIVec4:
499 case EOpConstructInt:
500 case EOpConstructUVec2:
501 case EOpConstructUVec3:
502 case EOpConstructUVec4:
503 case EOpConstructUInt:
504 case EOpConstructBVec2:
505 case EOpConstructBVec3:
506 case EOpConstructBVec4:
507 case EOpConstructBool:
508 case EOpConstructStruct:
509 return true;
510 default:
511 return false;
512 }
513}
514
515//
516// Make sure the type of a unary operator is appropriate for its
517// combination of operation and operand type.
518//
Olli Etuahof6c694b2015-03-26 14:50:53 +0200519void TIntermUnary::promote(const TType *funcReturnType)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400520{
521 switch (mOp)
522 {
Olli Etuahodca3e792015-03-26 13:24:04 +0200523 case EOpFloatBitsToInt:
524 case EOpFloatBitsToUint:
Olli Etuahoe8d2c072015-01-08 16:33:54 +0200525 case EOpIntBitsToFloat:
526 case EOpUintBitsToFloat:
Olli Etuahodca3e792015-03-26 13:24:04 +0200527 case EOpPackSnorm2x16:
528 case EOpPackUnorm2x16:
529 case EOpPackHalf2x16:
Olli Etuaho7700ff62015-01-15 12:16:29 +0200530 case EOpUnpackSnorm2x16:
531 case EOpUnpackUnorm2x16:
Olli Etuahodca3e792015-03-26 13:24:04 +0200532 mType.setPrecision(EbpHigh);
Arun Patole6b19d762015-02-19 09:40:39 +0530533 break;
Olli Etuahodca3e792015-03-26 13:24:04 +0200534 case EOpUnpackHalf2x16:
535 mType.setPrecision(EbpMedium);
536 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400537 default:
Olli Etuahodca3e792015-03-26 13:24:04 +0200538 setType(mOperand->getType());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400539 }
540
Olli Etuahof6c694b2015-03-26 14:50:53 +0200541 if (funcReturnType != nullptr)
542 {
543 if (funcReturnType->getBasicType() == EbtBool)
544 {
545 // Bool types should not have precision.
546 setType(*funcReturnType);
547 }
548 else
549 {
550 // Precision of the node has been set based on the operand.
551 setTypePreservePrecision(*funcReturnType);
552 }
553 }
554
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200555 if (mOperand->getQualifier() == EvqConst)
556 mType.setQualifier(EvqConst);
557 else
558 mType.setQualifier(EvqTemporary);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400559}
560
561//
562// Establishes the type of the resultant operation, as well as
563// makes the operator the correct one for the operands.
564//
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200565// For lots of operations it should already be established that the operand
566// combination is valid, but returns false if operator can't work on operands.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400567//
568bool TIntermBinary::promote(TInfoSink &infoSink)
569{
Olli Etuahoe79904c2015-03-18 16:56:42 +0200570 ASSERT(mLeft->isArray() == mRight->isArray());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400571
Jamie Madillb1a85f42014-08-19 15:23:24 -0400572 //
573 // Base assumption: just make the type the same as the left
574 // operand. Then only deviations from this need be coded.
575 //
576 setType(mLeft->getType());
577
578 // The result gets promoted to the highest precision.
579 TPrecision higherPrecision = GetHigherPrecision(
580 mLeft->getPrecision(), mRight->getPrecision());
581 getTypePointer()->setPrecision(higherPrecision);
582
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200583 TQualifier resultQualifier = EvqConst;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400584 // Binary operations results in temporary variables unless both
585 // operands are const.
586 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
587 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200588 resultQualifier = EvqTemporary;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400589 getTypePointer()->setQualifier(EvqTemporary);
590 }
591
592 const int nominalSize =
593 std::max(mLeft->getNominalSize(), mRight->getNominalSize());
594
595 //
596 // All scalars or structs. Code after this test assumes this case is removed!
597 //
598 if (nominalSize == 1)
599 {
600 switch (mOp)
601 {
602 //
603 // Promote to conditional
604 //
605 case EOpEqual:
606 case EOpNotEqual:
607 case EOpLessThan:
608 case EOpGreaterThan:
609 case EOpLessThanEqual:
610 case EOpGreaterThanEqual:
611 setType(TType(EbtBool, EbpUndefined));
612 break;
613
614 //
615 // And and Or operate on conditionals
616 //
617 case EOpLogicalAnd:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200618 case EOpLogicalXor:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400619 case EOpLogicalOr:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200620 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400621 setType(TType(EbtBool, EbpUndefined));
622 break;
623
624 default:
625 break;
626 }
627 return true;
628 }
629
630 // If we reach here, at least one of the operands is vector or matrix.
631 // The other operand could be a scalar, vector, or matrix.
632 // Can these two operands be combined?
633 //
634 TBasicType basicType = mLeft->getBasicType();
635 switch (mOp)
636 {
637 case EOpMul:
638 if (!mLeft->isMatrix() && mRight->isMatrix())
639 {
640 if (mLeft->isVector())
641 {
642 mOp = EOpVectorTimesMatrix;
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200643 setType(TType(basicType, higherPrecision, resultQualifier,
Minmin Gong794e0002015-04-07 18:31:54 -0700644 static_cast<unsigned char>(mRight->getCols()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400645 }
646 else
647 {
648 mOp = EOpMatrixTimesScalar;
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200649 setType(TType(basicType, higherPrecision, resultQualifier,
650 static_cast<unsigned char>(mRight->getCols()),
651 static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400652 }
653 }
654 else if (mLeft->isMatrix() && !mRight->isMatrix())
655 {
656 if (mRight->isVector())
657 {
658 mOp = EOpMatrixTimesVector;
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200659 setType(TType(basicType, higherPrecision, resultQualifier,
Minmin Gong794e0002015-04-07 18:31:54 -0700660 static_cast<unsigned char>(mLeft->getRows()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400661 }
662 else
663 {
664 mOp = EOpMatrixTimesScalar;
665 }
666 }
667 else if (mLeft->isMatrix() && mRight->isMatrix())
668 {
669 mOp = EOpMatrixTimesMatrix;
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200670 setType(TType(basicType, higherPrecision, resultQualifier,
671 static_cast<unsigned char>(mRight->getCols()),
672 static_cast<unsigned char>(mLeft->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400673 }
674 else if (!mLeft->isMatrix() && !mRight->isMatrix())
675 {
676 if (mLeft->isVector() && mRight->isVector())
677 {
678 // leave as component product
679 }
680 else if (mLeft->isVector() || mRight->isVector())
681 {
682 mOp = EOpVectorTimesScalar;
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200683 setType(TType(basicType, higherPrecision, resultQualifier,
Minmin Gong794e0002015-04-07 18:31:54 -0700684 static_cast<unsigned char>(nominalSize), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400685 }
686 }
687 else
688 {
689 infoSink.info.message(EPrefixInternalError, getLine(),
690 "Missing elses");
691 return false;
692 }
693
694 if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType()))
695 {
696 return false;
697 }
698 break;
699
700 case EOpMulAssign:
701 if (!mLeft->isMatrix() && mRight->isMatrix())
702 {
703 if (mLeft->isVector())
704 {
705 mOp = EOpVectorTimesMatrixAssign;
706 }
707 else
708 {
709 return false;
710 }
711 }
712 else if (mLeft->isMatrix() && !mRight->isMatrix())
713 {
714 if (mRight->isVector())
715 {
716 return false;
717 }
718 else
719 {
720 mOp = EOpMatrixTimesScalarAssign;
721 }
722 }
723 else if (mLeft->isMatrix() && mRight->isMatrix())
724 {
725 mOp = EOpMatrixTimesMatrixAssign;
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200726 setType(TType(basicType, higherPrecision, resultQualifier,
727 static_cast<unsigned char>(mRight->getCols()),
728 static_cast<unsigned char>(mLeft->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400729 }
730 else if (!mLeft->isMatrix() && !mRight->isMatrix())
731 {
732 if (mLeft->isVector() && mRight->isVector())
733 {
734 // leave as component product
735 }
736 else if (mLeft->isVector() || mRight->isVector())
737 {
738 if (!mLeft->isVector())
739 return false;
740 mOp = EOpVectorTimesScalarAssign;
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200741 setType(TType(basicType, higherPrecision, resultQualifier,
Minmin Gong794e0002015-04-07 18:31:54 -0700742 static_cast<unsigned char>(mLeft->getNominalSize()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400743 }
744 }
745 else
746 {
747 infoSink.info.message(EPrefixInternalError, getLine(),
748 "Missing elses");
749 return false;
750 }
751
752 if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType()))
753 {
754 return false;
755 }
756 break;
757
758 case EOpAssign:
759 case EOpInitialize:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200760 // No more additional checks are needed.
761 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
762 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
763 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400764 case EOpAdd:
765 case EOpSub:
766 case EOpDiv:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200767 case EOpIMod:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200768 case EOpBitShiftLeft:
769 case EOpBitShiftRight:
770 case EOpBitwiseAnd:
771 case EOpBitwiseXor:
772 case EOpBitwiseOr:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400773 case EOpAddAssign:
774 case EOpSubAssign:
775 case EOpDivAssign:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200776 case EOpIModAssign:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200777 case EOpBitShiftLeftAssign:
778 case EOpBitShiftRightAssign:
779 case EOpBitwiseAndAssign:
780 case EOpBitwiseXorAssign:
781 case EOpBitwiseOrAssign:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400782 if ((mLeft->isMatrix() && mRight->isVector()) ||
783 (mLeft->isVector() && mRight->isMatrix()))
784 {
785 return false;
786 }
787
788 // Are the sizes compatible?
789 if (mLeft->getNominalSize() != mRight->getNominalSize() ||
790 mLeft->getSecondarySize() != mRight->getSecondarySize())
791 {
Olli Etuaho6c850472014-12-02 16:23:17 +0200792 // If the nominal sizes of operands do not match:
793 // One of them must be a scalar.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400794 if (!mLeft->isScalar() && !mRight->isScalar())
795 return false;
796
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200797 // In the case of compound assignment other than multiply-assign,
798 // the right side needs to be a scalar. Otherwise a vector/matrix
799 // would be assigned to a scalar. A scalar can't be shifted by a
800 // vector either.
Olli Etuaho6c850472014-12-02 16:23:17 +0200801 if (!mRight->isScalar() &&
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200802 (isAssignment() ||
803 mOp == EOpBitShiftLeft ||
804 mOp == EOpBitShiftRight))
Olli Etuaho6c850472014-12-02 16:23:17 +0200805 return false;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400806 }
807
808 {
809 const int secondarySize = std::max(
810 mLeft->getSecondarySize(), mRight->getSecondarySize());
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200811 setType(TType(basicType, higherPrecision, resultQualifier,
812 static_cast<unsigned char>(nominalSize),
813 static_cast<unsigned char>(secondarySize)));
Olli Etuahoe79904c2015-03-18 16:56:42 +0200814 if (mLeft->isArray())
815 {
816 ASSERT(mLeft->getArraySize() == mRight->getArraySize());
817 mType.setArraySize(mLeft->getArraySize());
818 }
Jamie Madillb1a85f42014-08-19 15:23:24 -0400819 }
820 break;
821
822 case EOpEqual:
823 case EOpNotEqual:
824 case EOpLessThan:
825 case EOpGreaterThan:
826 case EOpLessThanEqual:
827 case EOpGreaterThanEqual:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200828 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
829 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400830 setType(TType(EbtBool, EbpUndefined));
831 break;
832
833 default:
834 return false;
835 }
836 return true;
837}
838
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300839TIntermTyped *TIntermBinary::fold(TInfoSink &infoSink)
840{
841 TIntermConstantUnion *leftConstant = mLeft->getAsConstantUnion();
842 TIntermConstantUnion *rightConstant = mRight->getAsConstantUnion();
843 if (leftConstant == nullptr || rightConstant == nullptr)
844 {
845 return nullptr;
846 }
847 TConstantUnion *constArray = leftConstant->foldBinary(mOp, rightConstant, infoSink);
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200848
849 // Nodes may be constant folded without being qualified as constant.
850 TQualifier resultQualifier = EvqConst;
851 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
852 {
853 resultQualifier = EvqTemporary;
854 }
855 return CreateFoldedNode(constArray, this, resultQualifier);
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300856}
857
Olli Etuaho95310b02015-06-02 17:43:38 +0300858TIntermTyped *TIntermUnary::fold(TInfoSink &infoSink)
859{
860 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
861 if (operandConstant == nullptr)
862 {
863 return nullptr;
864 }
Arun Patoleab2b9a22015-07-06 18:27:56 +0530865
866 TConstantUnion *constArray = nullptr;
867 switch (mOp)
868 {
869 case EOpAny:
870 case EOpAll:
871 case EOpLength:
872 case EOpTranspose:
873 case EOpDeterminant:
874 case EOpInverse:
875 case EOpPackSnorm2x16:
876 case EOpUnpackSnorm2x16:
877 case EOpPackUnorm2x16:
878 case EOpUnpackUnorm2x16:
879 case EOpPackHalf2x16:
880 case EOpUnpackHalf2x16:
881 constArray = operandConstant->foldUnaryWithDifferentReturnType(mOp, infoSink);
882 break;
883 default:
884 constArray = operandConstant->foldUnaryWithSameReturnType(mOp, infoSink);
885 break;
886 }
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200887
888 // Nodes may be constant folded without being qualified as constant.
889 TQualifier resultQualifier = mOperand->getQualifier() == EvqConst ? EvqConst : EvqTemporary;
890 return CreateFoldedNode(constArray, this, resultQualifier);
Olli Etuahob43846e2015-06-02 18:18:57 +0300891}
892
893TIntermTyped *TIntermAggregate::fold(TInfoSink &infoSink)
894{
895 // Make sure that all params are constant before actual constant folding.
896 for (auto *param : *getSequence())
Olli Etuaho95310b02015-06-02 17:43:38 +0300897 {
Olli Etuahob43846e2015-06-02 18:18:57 +0300898 if (param->getAsConstantUnion() == nullptr)
899 {
900 return nullptr;
901 }
Olli Etuaho95310b02015-06-02 17:43:38 +0300902 }
Olli Etuaho1d122782015-11-06 15:35:17 +0200903 TConstantUnion *constArray = nullptr;
904 if (isConstructor())
905 constArray = TIntermConstantUnion::FoldAggregateConstructor(this, infoSink);
906 else
907 constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, infoSink);
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200908
909 // Nodes may be constant folded without being qualified as constant.
910 TQualifier resultQualifier = areChildrenConstQualified() ? EvqConst : EvqTemporary;
911 return CreateFoldedNode(constArray, this, resultQualifier);
Olli Etuaho95310b02015-06-02 17:43:38 +0300912}
913
Jamie Madillb1a85f42014-08-19 15:23:24 -0400914//
915// The fold functions see if an operation on a constant can be done in place,
916// without generating run-time code.
917//
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300918// Returns the constant value to keep using or nullptr.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400919//
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300920TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op, TIntermConstantUnion *rightNode, TInfoSink &infoSink)
921{
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200922 const TConstantUnion *leftArray = getUnionArrayPointer();
923 const TConstantUnion *rightArray = rightNode->getUnionArrayPointer();
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300924
925 if (!leftArray)
926 return nullptr;
927 if (!rightArray)
928 return nullptr;
929
930 size_t objectSize = getType().getObjectSize();
931
932 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
933 if (rightNode->getType().getObjectSize() == 1 && objectSize > 1)
934 {
935 rightArray = Vectorize(*rightNode->getUnionArrayPointer(), objectSize);
936 }
937 else if (rightNode->getType().getObjectSize() > 1 && objectSize == 1)
938 {
939 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
940 leftArray = Vectorize(*getUnionArrayPointer(), rightNode->getType().getObjectSize());
941 objectSize = rightNode->getType().getObjectSize();
942 }
943
944 TConstantUnion *resultArray = nullptr;
945
946 switch(op)
947 {
948 case EOpAdd:
949 resultArray = new TConstantUnion[objectSize];
950 for (size_t i = 0; i < objectSize; i++)
951 resultArray[i] = leftArray[i] + rightArray[i];
952 break;
953 case EOpSub:
954 resultArray = new TConstantUnion[objectSize];
955 for (size_t i = 0; i < objectSize; i++)
956 resultArray[i] = leftArray[i] - rightArray[i];
957 break;
958
959 case EOpMul:
960 case EOpVectorTimesScalar:
961 case EOpMatrixTimesScalar:
962 resultArray = new TConstantUnion[objectSize];
963 for (size_t i = 0; i < objectSize; i++)
964 resultArray[i] = leftArray[i] * rightArray[i];
965 break;
966
967 case EOpMatrixTimesMatrix:
968 {
969 if (getType().getBasicType() != EbtFloat ||
970 rightNode->getBasicType() != EbtFloat)
971 {
972 infoSink.info.message(
973 EPrefixInternalError, getLine(),
974 "Constant Folding cannot be done for matrix multiply");
975 return nullptr;
976 }
977
978 const int leftCols = getCols();
979 const int leftRows = getRows();
980 const int rightCols = rightNode->getType().getCols();
981 const int rightRows = rightNode->getType().getRows();
982 const int resultCols = rightCols;
983 const int resultRows = leftRows;
984
985 resultArray = new TConstantUnion[resultCols * resultRows];
986 for (int row = 0; row < resultRows; row++)
987 {
988 for (int column = 0; column < resultCols; column++)
989 {
990 resultArray[resultRows * column + row].setFConst(0.0f);
991 for (int i = 0; i < leftCols; i++)
992 {
993 resultArray[resultRows * column + row].setFConst(
994 resultArray[resultRows * column + row].getFConst() +
995 leftArray[i * leftRows + row].getFConst() *
996 rightArray[column * rightRows + i].getFConst());
997 }
998 }
999 }
1000 }
1001 break;
1002
1003 case EOpDiv:
1004 case EOpIMod:
1005 {
1006 resultArray = new TConstantUnion[objectSize];
1007 for (size_t i = 0; i < objectSize; i++)
1008 {
1009 switch (getType().getBasicType())
1010 {
1011 case EbtFloat:
1012 if (rightArray[i] == 0.0f)
1013 {
1014 infoSink.info.message(EPrefixWarning, getLine(),
1015 "Divide by zero error during constant folding");
1016 resultArray[i].setFConst(leftArray[i].getFConst() < 0 ? -FLT_MAX : FLT_MAX);
1017 }
1018 else
1019 {
1020 ASSERT(op == EOpDiv);
1021 resultArray[i].setFConst(leftArray[i].getFConst() / rightArray[i].getFConst());
1022 }
1023 break;
1024
1025 case EbtInt:
1026 if (rightArray[i] == 0)
1027 {
1028 infoSink.info.message(EPrefixWarning, getLine(),
1029 "Divide by zero error during constant folding");
1030 resultArray[i].setIConst(INT_MAX);
1031 }
1032 else
1033 {
1034 if (op == EOpDiv)
1035 {
1036 resultArray[i].setIConst(leftArray[i].getIConst() / rightArray[i].getIConst());
1037 }
1038 else
1039 {
1040 ASSERT(op == EOpIMod);
1041 resultArray[i].setIConst(leftArray[i].getIConst() % rightArray[i].getIConst());
1042 }
1043 }
1044 break;
1045
1046 case EbtUInt:
1047 if (rightArray[i] == 0)
1048 {
1049 infoSink.info.message(EPrefixWarning, getLine(),
1050 "Divide by zero error during constant folding");
1051 resultArray[i].setUConst(UINT_MAX);
1052 }
1053 else
1054 {
1055 if (op == EOpDiv)
1056 {
1057 resultArray[i].setUConst(leftArray[i].getUConst() / rightArray[i].getUConst());
1058 }
1059 else
1060 {
1061 ASSERT(op == EOpIMod);
1062 resultArray[i].setUConst(leftArray[i].getUConst() % rightArray[i].getUConst());
1063 }
1064 }
1065 break;
1066
1067 default:
1068 infoSink.info.message(EPrefixInternalError, getLine(),
1069 "Constant folding cannot be done for \"/\"");
1070 return nullptr;
1071 }
1072 }
1073 }
1074 break;
1075
1076 case EOpMatrixTimesVector:
1077 {
1078 if (rightNode->getBasicType() != EbtFloat)
1079 {
1080 infoSink.info.message(EPrefixInternalError, getLine(),
1081 "Constant Folding cannot be done for matrix times vector");
1082 return nullptr;
1083 }
1084
1085 const int matrixCols = getCols();
1086 const int matrixRows = getRows();
1087
1088 resultArray = new TConstantUnion[matrixRows];
1089
1090 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1091 {
1092 resultArray[matrixRow].setFConst(0.0f);
1093 for (int col = 0; col < matrixCols; col++)
1094 {
1095 resultArray[matrixRow].setFConst(resultArray[matrixRow].getFConst() +
1096 leftArray[col * matrixRows + matrixRow].getFConst() *
1097 rightArray[col].getFConst());
1098 }
1099 }
1100 }
1101 break;
1102
1103 case EOpVectorTimesMatrix:
1104 {
1105 if (getType().getBasicType() != EbtFloat)
1106 {
1107 infoSink.info.message(EPrefixInternalError, getLine(),
1108 "Constant Folding cannot be done for vector times matrix");
1109 return nullptr;
1110 }
1111
1112 const int matrixCols = rightNode->getType().getCols();
1113 const int matrixRows = rightNode->getType().getRows();
1114
1115 resultArray = new TConstantUnion[matrixCols];
1116
1117 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
1118 {
1119 resultArray[matrixCol].setFConst(0.0f);
1120 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1121 {
1122 resultArray[matrixCol].setFConst(resultArray[matrixCol].getFConst() +
1123 leftArray[matrixRow].getFConst() *
1124 rightArray[matrixCol * matrixRows + matrixRow].getFConst());
1125 }
1126 }
1127 }
1128 break;
1129
1130 case EOpLogicalAnd:
1131 {
1132 resultArray = new TConstantUnion[objectSize];
1133 for (size_t i = 0; i < objectSize; i++)
1134 {
1135 resultArray[i] = leftArray[i] && rightArray[i];
1136 }
1137 }
1138 break;
1139
1140 case EOpLogicalOr:
1141 {
1142 resultArray = new TConstantUnion[objectSize];
1143 for (size_t i = 0; i < objectSize; i++)
1144 {
1145 resultArray[i] = leftArray[i] || rightArray[i];
1146 }
1147 }
1148 break;
1149
1150 case EOpLogicalXor:
1151 {
1152 resultArray = new TConstantUnion[objectSize];
1153 for (size_t i = 0; i < objectSize; i++)
1154 {
1155 switch (getType().getBasicType())
1156 {
1157 case EbtBool:
1158 resultArray[i].setBConst(leftArray[i] != rightArray[i]);
1159 break;
1160 default:
1161 UNREACHABLE();
1162 break;
1163 }
1164 }
1165 }
1166 break;
1167
1168 case EOpBitwiseAnd:
1169 resultArray = new TConstantUnion[objectSize];
1170 for (size_t i = 0; i < objectSize; i++)
1171 resultArray[i] = leftArray[i] & rightArray[i];
1172 break;
1173 case EOpBitwiseXor:
1174 resultArray = new TConstantUnion[objectSize];
1175 for (size_t i = 0; i < objectSize; i++)
1176 resultArray[i] = leftArray[i] ^ rightArray[i];
1177 break;
1178 case EOpBitwiseOr:
1179 resultArray = new TConstantUnion[objectSize];
1180 for (size_t i = 0; i < objectSize; i++)
1181 resultArray[i] = leftArray[i] | rightArray[i];
1182 break;
1183 case EOpBitShiftLeft:
1184 resultArray = new TConstantUnion[objectSize];
1185 for (size_t i = 0; i < objectSize; i++)
1186 resultArray[i] = leftArray[i] << rightArray[i];
1187 break;
1188 case EOpBitShiftRight:
1189 resultArray = new TConstantUnion[objectSize];
1190 for (size_t i = 0; i < objectSize; i++)
1191 resultArray[i] = leftArray[i] >> rightArray[i];
1192 break;
1193
1194 case EOpLessThan:
1195 ASSERT(objectSize == 1);
1196 resultArray = new TConstantUnion[1];
1197 resultArray->setBConst(*leftArray < *rightArray);
1198 break;
1199
1200 case EOpGreaterThan:
1201 ASSERT(objectSize == 1);
1202 resultArray = new TConstantUnion[1];
1203 resultArray->setBConst(*leftArray > *rightArray);
1204 break;
1205
1206 case EOpLessThanEqual:
1207 ASSERT(objectSize == 1);
1208 resultArray = new TConstantUnion[1];
1209 resultArray->setBConst(!(*leftArray > *rightArray));
1210 break;
1211
1212 case EOpGreaterThanEqual:
1213 ASSERT(objectSize == 1);
1214 resultArray = new TConstantUnion[1];
1215 resultArray->setBConst(!(*leftArray < *rightArray));
1216 break;
1217
1218 case EOpEqual:
1219 case EOpNotEqual:
1220 {
1221 resultArray = new TConstantUnion[1];
1222 bool equal = true;
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001223 for (size_t i = 0; i < objectSize; i++)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001224 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001225 if (leftArray[i] != rightArray[i])
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001226 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001227 equal = false;
1228 break; // break out of for loop
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001229 }
1230 }
1231 if (op == EOpEqual)
1232 {
1233 resultArray->setBConst(equal);
1234 }
1235 else
1236 {
1237 resultArray->setBConst(!equal);
1238 }
1239 }
1240 break;
1241
1242 default:
1243 infoSink.info.message(
1244 EPrefixInternalError, getLine(),
1245 "Invalid operator for constant folding");
1246 return nullptr;
1247 }
1248 return resultArray;
1249}
1250
1251//
1252// The fold functions see if an operation on a constant can be done in place,
1253// without generating run-time code.
1254//
Olli Etuaho95310b02015-06-02 17:43:38 +03001255// Returns the constant value to keep using or nullptr.
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001256//
Arun Patoleab2b9a22015-07-06 18:27:56 +05301257TConstantUnion *TIntermConstantUnion::foldUnaryWithDifferentReturnType(TOperator op, TInfoSink &infoSink)
Jamie Madillb1a85f42014-08-19 15:23:24 -04001258{
Arun Patoleab2b9a22015-07-06 18:27:56 +05301259 //
1260 // Do operations where the return type has a different number of components compared to the operand type.
1261 //
Jamie Madillb1a85f42014-08-19 15:23:24 -04001262
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001263 const TConstantUnion *operandArray = getUnionArrayPointer();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301264 if (!operandArray)
1265 return nullptr;
1266
1267 size_t objectSize = getType().getObjectSize();
1268 TConstantUnion *resultArray = nullptr;
1269 switch (op)
1270 {
1271 case EOpAny:
1272 if (getType().getBasicType() == EbtBool)
1273 {
1274 resultArray = new TConstantUnion();
1275 resultArray->setBConst(false);
1276 for (size_t i = 0; i < objectSize; i++)
1277 {
1278 if (operandArray[i].getBConst())
1279 {
1280 resultArray->setBConst(true);
1281 break;
1282 }
1283 }
1284 break;
1285 }
1286 else
1287 {
1288 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1289 return nullptr;
1290 }
1291
1292 case EOpAll:
1293 if (getType().getBasicType() == EbtBool)
1294 {
1295 resultArray = new TConstantUnion();
1296 resultArray->setBConst(true);
1297 for (size_t i = 0; i < objectSize; i++)
1298 {
1299 if (!operandArray[i].getBConst())
1300 {
1301 resultArray->setBConst(false);
1302 break;
1303 }
1304 }
1305 break;
1306 }
1307 else
1308 {
1309 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1310 return nullptr;
1311 }
1312
1313 case EOpLength:
1314 if (getType().getBasicType() == EbtFloat)
1315 {
1316 resultArray = new TConstantUnion();
1317 resultArray->setFConst(VectorLength(operandArray, objectSize));
1318 break;
1319 }
1320 else
1321 {
1322 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1323 return nullptr;
1324 }
1325
1326 case EOpTranspose:
1327 if (getType().getBasicType() == EbtFloat)
1328 {
1329 resultArray = new TConstantUnion[objectSize];
1330 angle::Matrix<float> result =
1331 GetMatrix(operandArray, getType().getNominalSize(), getType().getSecondarySize()).transpose();
1332 SetUnionArrayFromMatrix(result, resultArray);
1333 break;
1334 }
1335 else
1336 {
1337 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1338 return nullptr;
1339 }
1340
1341 case EOpDeterminant:
1342 if (getType().getBasicType() == EbtFloat)
1343 {
1344 unsigned int size = getType().getNominalSize();
1345 ASSERT(size >= 2 && size <= 4);
1346 resultArray = new TConstantUnion();
1347 resultArray->setFConst(GetMatrix(operandArray, size).determinant());
1348 break;
1349 }
1350 else
1351 {
1352 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1353 return nullptr;
1354 }
1355
1356 case EOpInverse:
1357 if (getType().getBasicType() == EbtFloat)
1358 {
1359 unsigned int size = getType().getNominalSize();
1360 ASSERT(size >= 2 && size <= 4);
1361 resultArray = new TConstantUnion[objectSize];
1362 angle::Matrix<float> result = GetMatrix(operandArray, size).inverse();
1363 SetUnionArrayFromMatrix(result, resultArray);
1364 break;
1365 }
1366 else
1367 {
1368 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1369 return nullptr;
1370 }
1371
1372 case EOpPackSnorm2x16:
1373 if (getType().getBasicType() == EbtFloat)
1374 {
1375 ASSERT(getType().getNominalSize() == 2);
1376 resultArray = new TConstantUnion();
1377 resultArray->setUConst(gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
1378 break;
1379 }
1380 else
1381 {
1382 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1383 return nullptr;
1384 }
1385
1386 case EOpUnpackSnorm2x16:
1387 if (getType().getBasicType() == EbtUInt)
1388 {
1389 resultArray = new TConstantUnion[2];
1390 float f1, f2;
1391 gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1392 resultArray[0].setFConst(f1);
1393 resultArray[1].setFConst(f2);
1394 break;
1395 }
1396 else
1397 {
1398 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1399 return nullptr;
1400 }
1401
1402 case EOpPackUnorm2x16:
1403 if (getType().getBasicType() == EbtFloat)
1404 {
1405 ASSERT(getType().getNominalSize() == 2);
1406 resultArray = new TConstantUnion();
1407 resultArray->setUConst(gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
1408 break;
1409 }
1410 else
1411 {
1412 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1413 return nullptr;
1414 }
1415
1416 case EOpUnpackUnorm2x16:
1417 if (getType().getBasicType() == EbtUInt)
1418 {
1419 resultArray = new TConstantUnion[2];
1420 float f1, f2;
1421 gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1422 resultArray[0].setFConst(f1);
1423 resultArray[1].setFConst(f2);
1424 break;
1425 }
1426 else
1427 {
1428 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1429 return nullptr;
1430 }
1431
1432 case EOpPackHalf2x16:
1433 if (getType().getBasicType() == EbtFloat)
1434 {
1435 ASSERT(getType().getNominalSize() == 2);
1436 resultArray = new TConstantUnion();
1437 resultArray->setUConst(gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
1438 break;
1439 }
1440 else
1441 {
1442 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1443 return nullptr;
1444 }
1445
1446 case EOpUnpackHalf2x16:
1447 if (getType().getBasicType() == EbtUInt)
1448 {
1449 resultArray = new TConstantUnion[2];
1450 float f1, f2;
1451 gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2);
1452 resultArray[0].setFConst(f1);
1453 resultArray[1].setFConst(f2);
1454 break;
1455 }
1456 else
1457 {
1458 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1459 return nullptr;
1460 }
1461 break;
1462
1463 default:
1464 break;
1465 }
1466
1467 return resultArray;
1468}
1469
1470TConstantUnion *TIntermConstantUnion::foldUnaryWithSameReturnType(TOperator op, TInfoSink &infoSink)
1471{
1472 //
1473 // Do unary operations where the return type is the same as operand type.
1474 //
1475
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001476 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuaho95310b02015-06-02 17:43:38 +03001477 if (!operandArray)
Arun Patolefddc2112015-04-22 13:28:10 +05301478 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001479
1480 size_t objectSize = getType().getObjectSize();
1481
Arun Patoleab2b9a22015-07-06 18:27:56 +05301482 TConstantUnion *resultArray = new TConstantUnion[objectSize];
1483 for (size_t i = 0; i < objectSize; i++)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301484 {
Arun Patoleab2b9a22015-07-06 18:27:56 +05301485 switch(op)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301486 {
Arun Patoleab2b9a22015-07-06 18:27:56 +05301487 case EOpNegative:
1488 switch (getType().getBasicType())
Arun Patole9d0b1f92015-05-20 14:27:17 +05301489 {
Arun Patoleab2b9a22015-07-06 18:27:56 +05301490 case EbtFloat:
1491 resultArray[i].setFConst(-operandArray[i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05301492 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301493 case EbtInt:
1494 resultArray[i].setIConst(-operandArray[i].getIConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05301495 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301496 case EbtUInt:
1497 resultArray[i].setUConst(static_cast<unsigned int>(
1498 -static_cast<int>(operandArray[i].getUConst())));
Arun Patole1155ddd2015-06-05 18:04:36 +05301499 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301500 default:
1501 infoSink.info.message(
1502 EPrefixInternalError, getLine(),
1503 "Unary operation not folded into constant");
Arun Patolecdfa8f52015-06-30 17:48:25 +05301504 return nullptr;
1505 }
1506 break;
1507
Arun Patoleab2b9a22015-07-06 18:27:56 +05301508 case EOpPositive:
1509 switch (getType().getBasicType())
1510 {
1511 case EbtFloat:
1512 resultArray[i].setFConst(operandArray[i].getFConst());
1513 break;
1514 case EbtInt:
1515 resultArray[i].setIConst(operandArray[i].getIConst());
1516 break;
1517 case EbtUInt:
1518 resultArray[i].setUConst(static_cast<unsigned int>(
1519 static_cast<int>(operandArray[i].getUConst())));
1520 break;
1521 default:
1522 infoSink.info.message(
1523 EPrefixInternalError, getLine(),
1524 "Unary operation not folded into constant");
1525 return nullptr;
1526 }
1527 break;
1528
1529 case EOpLogicalNot:
1530 // this code is written for possible future use,
1531 // will not get executed currently
1532 switch (getType().getBasicType())
1533 {
1534 case EbtBool:
1535 resultArray[i].setBConst(!operandArray[i].getBConst());
1536 break;
1537 default:
1538 infoSink.info.message(
1539 EPrefixInternalError, getLine(),
1540 "Unary operation not folded into constant");
1541 return nullptr;
1542 }
1543 break;
1544
1545 case EOpBitwiseNot:
1546 switch (getType().getBasicType())
1547 {
1548 case EbtInt:
1549 resultArray[i].setIConst(~operandArray[i].getIConst());
1550 break;
1551 case EbtUInt:
1552 resultArray[i].setUConst(~operandArray[i].getUConst());
1553 break;
1554 default:
1555 infoSink.info.message(
1556 EPrefixInternalError, getLine(),
1557 "Unary operation not folded into constant");
1558 return nullptr;
1559 }
1560 break;
1561
1562 case EOpRadians:
1563 if (getType().getBasicType() == EbtFloat)
1564 {
1565 resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
1566 break;
1567 }
1568 infoSink.info.message(
1569 EPrefixInternalError, getLine(),
1570 "Unary operation not folded into constant");
1571 return nullptr;
1572
1573 case EOpDegrees:
1574 if (getType().getBasicType() == EbtFloat)
1575 {
1576 resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
1577 break;
1578 }
1579 infoSink.info.message(
1580 EPrefixInternalError, getLine(),
1581 "Unary operation not folded into constant");
1582 return nullptr;
1583
1584 case EOpSin:
1585 if (!foldFloatTypeUnary(operandArray[i], &sinf, infoSink, &resultArray[i]))
1586 return nullptr;
1587 break;
1588
1589 case EOpCos:
1590 if (!foldFloatTypeUnary(operandArray[i], &cosf, infoSink, &resultArray[i]))
1591 return nullptr;
1592 break;
1593
1594 case EOpTan:
1595 if (!foldFloatTypeUnary(operandArray[i], &tanf, infoSink, &resultArray[i]))
1596 return nullptr;
1597 break;
1598
1599 case EOpAsin:
1600 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to 0.
1601 if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) > 1.0f)
1602 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1603 else if (!foldFloatTypeUnary(operandArray[i], &asinf, infoSink, &resultArray[i]))
1604 return nullptr;
1605 break;
1606
1607 case EOpAcos:
1608 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to 0.
1609 if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) > 1.0f)
1610 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1611 else if (!foldFloatTypeUnary(operandArray[i], &acosf, infoSink, &resultArray[i]))
1612 return nullptr;
1613 break;
1614
1615 case EOpAtan:
1616 if (!foldFloatTypeUnary(operandArray[i], &atanf, infoSink, &resultArray[i]))
1617 return nullptr;
1618 break;
1619
1620 case EOpSinh:
1621 if (!foldFloatTypeUnary(operandArray[i], &sinhf, infoSink, &resultArray[i]))
1622 return nullptr;
1623 break;
1624
1625 case EOpCosh:
1626 if (!foldFloatTypeUnary(operandArray[i], &coshf, infoSink, &resultArray[i]))
1627 return nullptr;
1628 break;
1629
1630 case EOpTanh:
1631 if (!foldFloatTypeUnary(operandArray[i], &tanhf, infoSink, &resultArray[i]))
1632 return nullptr;
1633 break;
1634
1635 case EOpAsinh:
1636 if (!foldFloatTypeUnary(operandArray[i], &asinhf, infoSink, &resultArray[i]))
1637 return nullptr;
1638 break;
1639
1640 case EOpAcosh:
1641 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
1642 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() < 1.0f)
1643 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1644 else if (!foldFloatTypeUnary(operandArray[i], &acoshf, infoSink, &resultArray[i]))
1645 return nullptr;
1646 break;
1647
1648 case EOpAtanh:
1649 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to 0.
1650 if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) >= 1.0f)
1651 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1652 else if (!foldFloatTypeUnary(operandArray[i], &atanhf, infoSink, &resultArray[i]))
1653 return nullptr;
1654 break;
1655
1656 case EOpAbs:
1657 switch (getType().getBasicType())
1658 {
1659 case EbtFloat:
1660 resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
1661 break;
1662 case EbtInt:
1663 resultArray[i].setIConst(abs(operandArray[i].getIConst()));
1664 break;
1665 default:
1666 infoSink.info.message(
1667 EPrefixInternalError, getLine(),
1668 "Unary operation not folded into constant");
1669 return nullptr;
1670 }
1671 break;
1672
1673 case EOpSign:
1674 switch (getType().getBasicType())
1675 {
1676 case EbtFloat:
1677 {
1678 float fConst = operandArray[i].getFConst();
1679 float fResult = 0.0f;
1680 if (fConst > 0.0f)
1681 fResult = 1.0f;
1682 else if (fConst < 0.0f)
1683 fResult = -1.0f;
1684 resultArray[i].setFConst(fResult);
1685 }
1686 break;
1687 case EbtInt:
1688 {
1689 int iConst = operandArray[i].getIConst();
1690 int iResult = 0;
1691 if (iConst > 0)
1692 iResult = 1;
1693 else if (iConst < 0)
1694 iResult = -1;
1695 resultArray[i].setIConst(iResult);
1696 }
1697 break;
1698 default:
1699 infoSink.info.message(
1700 EPrefixInternalError, getLine(),
1701 "Unary operation not folded into constant");
1702 return nullptr;
1703 }
1704 break;
1705
1706 case EOpFloor:
1707 if (!foldFloatTypeUnary(operandArray[i], &floorf, infoSink, &resultArray[i]))
1708 return nullptr;
1709 break;
1710
1711 case EOpTrunc:
1712 if (!foldFloatTypeUnary(operandArray[i], &truncf, infoSink, &resultArray[i]))
1713 return nullptr;
1714 break;
1715
1716 case EOpRound:
1717 if (!foldFloatTypeUnary(operandArray[i], &roundf, infoSink, &resultArray[i]))
1718 return nullptr;
1719 break;
1720
1721 case EOpRoundEven:
1722 if (getType().getBasicType() == EbtFloat)
1723 {
1724 float x = operandArray[i].getFConst();
1725 float result;
1726 float fractPart = modff(x, &result);
1727 if (fabsf(fractPart) == 0.5f)
1728 result = 2.0f * roundf(x / 2.0f);
1729 else
1730 result = roundf(x);
1731 resultArray[i].setFConst(result);
1732 break;
1733 }
1734 infoSink.info.message(
1735 EPrefixInternalError, getLine(),
1736 "Unary operation not folded into constant");
1737 return nullptr;
1738
1739 case EOpCeil:
1740 if (!foldFloatTypeUnary(operandArray[i], &ceilf, infoSink, &resultArray[i]))
1741 return nullptr;
1742 break;
1743
1744 case EOpFract:
1745 if (getType().getBasicType() == EbtFloat)
1746 {
1747 float x = operandArray[i].getFConst();
1748 resultArray[i].setFConst(x - floorf(x));
1749 break;
1750 }
1751 infoSink.info.message(
1752 EPrefixInternalError, getLine(),
1753 "Unary operation not folded into constant");
1754 return nullptr;
1755
Arun Patole551279e2015-07-07 18:18:23 +05301756 case EOpIsNan:
1757 if (getType().getBasicType() == EbtFloat)
1758 {
1759 resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst()));
1760 break;
1761 }
1762 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1763 return nullptr;
1764
1765 case EOpIsInf:
1766 if (getType().getBasicType() == EbtFloat)
1767 {
1768 resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst()));
1769 break;
1770 }
1771 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1772 return nullptr;
1773
1774 case EOpFloatBitsToInt:
1775 if (getType().getBasicType() == EbtFloat)
1776 {
1777 resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst()));
1778 break;
1779 }
1780 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1781 return nullptr;
1782
1783 case EOpFloatBitsToUint:
1784 if (getType().getBasicType() == EbtFloat)
1785 {
1786 resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst()));
1787 break;
1788 }
1789 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1790 return nullptr;
1791
1792 case EOpIntBitsToFloat:
1793 if (getType().getBasicType() == EbtInt)
1794 {
1795 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst()));
1796 break;
1797 }
1798 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1799 return nullptr;
1800
1801 case EOpUintBitsToFloat:
1802 if (getType().getBasicType() == EbtUInt)
1803 {
1804 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst()));
1805 break;
1806 }
1807 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1808 return nullptr;
1809
Arun Patoleab2b9a22015-07-06 18:27:56 +05301810 case EOpExp:
1811 if (!foldFloatTypeUnary(operandArray[i], &expf, infoSink, &resultArray[i]))
1812 return nullptr;
1813 break;
1814
1815 case EOpLog:
1816 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
1817 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
1818 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1819 else if (!foldFloatTypeUnary(operandArray[i], &logf, infoSink, &resultArray[i]))
1820 return nullptr;
1821 break;
1822
1823 case EOpExp2:
1824 if (!foldFloatTypeUnary(operandArray[i], &exp2f, infoSink, &resultArray[i]))
1825 return nullptr;
1826 break;
1827
1828 case EOpLog2:
1829 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
1830 // And log2f is not available on some plarforms like old android, so just using log(x)/log(2) here.
1831 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
1832 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1833 else if (!foldFloatTypeUnary(operandArray[i], &logf, infoSink, &resultArray[i]))
1834 return nullptr;
1835 else
1836 resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
1837 break;
1838
1839 case EOpSqrt:
1840 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
1841 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() < 0.0f)
1842 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1843 else if (!foldFloatTypeUnary(operandArray[i], &sqrtf, infoSink, &resultArray[i]))
1844 return nullptr;
1845 break;
1846
1847 case EOpInverseSqrt:
1848 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
1849 // so getting the square root first using builtin function sqrt() and then taking its inverse.
1850 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set result to 0.
1851 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
1852 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1853 else if (!foldFloatTypeUnary(operandArray[i], &sqrtf, infoSink, &resultArray[i]))
1854 return nullptr;
1855 else
1856 resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
1857 break;
1858
1859 case EOpVectorLogicalNot:
1860 if (getType().getBasicType() == EbtBool)
1861 {
1862 resultArray[i].setBConst(!operandArray[i].getBConst());
1863 break;
1864 }
1865 infoSink.info.message(
1866 EPrefixInternalError, getLine(),
1867 "Unary operation not folded into constant");
1868 return nullptr;
1869
1870 case EOpNormalize:
1871 if (getType().getBasicType() == EbtFloat)
1872 {
1873 float x = operandArray[i].getFConst();
1874 float length = VectorLength(operandArray, objectSize);
1875 if (length)
1876 resultArray[i].setFConst(x / length);
1877 else
1878 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink,
1879 &resultArray[i]);
1880 break;
1881 }
1882 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1883 return nullptr;
1884
Arun Patole0c5409f2015-07-08 15:17:53 +05301885 case EOpDFdx:
1886 case EOpDFdy:
1887 case EOpFwidth:
1888 if (getType().getBasicType() == EbtFloat)
1889 {
1890 // Derivatives of constant arguments should be 0.
1891 resultArray[i].setFConst(0.0f);
1892 break;
1893 }
1894 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1895 return nullptr;
1896
Arun Patole1155ddd2015-06-05 18:04:36 +05301897 default:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301898 return nullptr;
Arun Patole9d0b1f92015-05-20 14:27:17 +05301899 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05301900 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04001901
Arun Patoleab2b9a22015-07-06 18:27:56 +05301902 return resultArray;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001903}
1904
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001905bool TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter, FloatTypeUnaryFunc builtinFunc,
1906 TInfoSink &infoSink, TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05301907{
1908 ASSERT(builtinFunc);
1909
1910 if (getType().getBasicType() == EbtFloat)
1911 {
1912 result->setFConst(builtinFunc(parameter.getFConst()));
1913 return true;
1914 }
1915
1916 infoSink.info.message(
1917 EPrefixInternalError, getLine(),
1918 "Unary operation not folded into constant");
1919 return false;
1920}
1921
Jamie Madillb1a85f42014-08-19 15:23:24 -04001922// static
Olli Etuaho1d122782015-11-06 15:35:17 +02001923TConstantUnion *TIntermConstantUnion::FoldAggregateConstructor(TIntermAggregate *aggregate,
1924 TInfoSink &infoSink)
1925{
1926 ASSERT(aggregate->getSequence()->size() > 0u);
1927 size_t resultSize = aggregate->getType().getObjectSize();
1928 TConstantUnion *resultArray = new TConstantUnion[resultSize];
1929 TBasicType basicType = aggregate->getBasicType();
1930
1931 size_t resultIndex = 0u;
1932
1933 if (aggregate->getSequence()->size() == 1u)
1934 {
1935 TIntermNode *argument = aggregate->getSequence()->front();
1936 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
1937 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
1938 // Check the special case of constructing a matrix diagonal from a single scalar,
1939 // or a vector from a single scalar.
1940 if (argumentConstant->getType().getObjectSize() == 1u)
1941 {
1942 if (aggregate->isMatrix())
1943 {
1944 int resultCols = aggregate->getType().getCols();
1945 int resultRows = aggregate->getType().getRows();
1946 for (int col = 0; col < resultCols; ++col)
1947 {
1948 for (int row = 0; row < resultRows; ++row)
1949 {
1950 if (col == row)
1951 {
1952 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
1953 }
1954 else
1955 {
1956 resultArray[resultIndex].setFConst(0.0f);
1957 }
1958 ++resultIndex;
1959 }
1960 }
1961 }
1962 else
1963 {
1964 while (resultIndex < resultSize)
1965 {
1966 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
1967 ++resultIndex;
1968 }
1969 }
1970 ASSERT(resultIndex == resultSize);
1971 return resultArray;
1972 }
1973 else if (aggregate->isMatrix() && argumentConstant->isMatrix())
1974 {
1975 // The special case of constructing a matrix from a matrix.
1976 int argumentCols = argumentConstant->getType().getCols();
1977 int argumentRows = argumentConstant->getType().getRows();
1978 int resultCols = aggregate->getType().getCols();
1979 int resultRows = aggregate->getType().getRows();
1980 for (int col = 0; col < resultCols; ++col)
1981 {
1982 for (int row = 0; row < resultRows; ++row)
1983 {
1984 if (col < argumentCols && row < argumentRows)
1985 {
1986 resultArray[resultIndex].cast(basicType,
1987 argumentUnionArray[col * argumentRows + row]);
1988 }
1989 else if (col == row)
1990 {
1991 resultArray[resultIndex].setFConst(1.0f);
1992 }
1993 else
1994 {
1995 resultArray[resultIndex].setFConst(0.0f);
1996 }
1997 ++resultIndex;
1998 }
1999 }
2000 ASSERT(resultIndex == resultSize);
2001 return resultArray;
2002 }
2003 }
2004
2005 for (TIntermNode *&argument : *aggregate->getSequence())
2006 {
2007 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
2008 size_t argumentSize = argumentConstant->getType().getObjectSize();
2009 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
2010 for (size_t i = 0u; i < argumentSize; ++i)
2011 {
2012 if (resultIndex >= resultSize)
2013 break;
2014 resultArray[resultIndex].cast(basicType, argumentUnionArray[i]);
2015 ++resultIndex;
2016 }
2017 }
2018 ASSERT(resultIndex == resultSize);
2019 return resultArray;
2020}
2021
2022// static
Olli Etuahob43846e2015-06-02 18:18:57 +03002023TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate, TInfoSink &infoSink)
Arun Patole274f0702015-05-05 13:33:30 +05302024{
Olli Etuahob43846e2015-06-02 18:18:57 +03002025 TOperator op = aggregate->getOp();
Arun Patole274f0702015-05-05 13:33:30 +05302026 TIntermSequence *sequence = aggregate->getSequence();
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002027 unsigned int paramsCount = static_cast<unsigned int>(sequence->size());
Olli Etuaho5c0e0232015-11-11 15:55:59 +02002028 std::vector<const TConstantUnion *> unionArrays(paramsCount);
Arun Patole274f0702015-05-05 13:33:30 +05302029 std::vector<size_t> objectSizes(paramsCount);
Olli Etuahob43846e2015-06-02 18:18:57 +03002030 size_t maxObjectSize = 0;
Arun Patole274f0702015-05-05 13:33:30 +05302031 TBasicType basicType = EbtVoid;
2032 TSourceLoc loc;
2033 for (unsigned int i = 0; i < paramsCount; i++)
2034 {
2035 TIntermConstantUnion *paramConstant = (*sequence)[i]->getAsConstantUnion();
Olli Etuahob43846e2015-06-02 18:18:57 +03002036 ASSERT(paramConstant != nullptr); // Should be checked already.
Arun Patole274f0702015-05-05 13:33:30 +05302037
2038 if (i == 0)
2039 {
2040 basicType = paramConstant->getType().getBasicType();
2041 loc = paramConstant->getLine();
2042 }
2043 unionArrays[i] = paramConstant->getUnionArrayPointer();
2044 objectSizes[i] = paramConstant->getType().getObjectSize();
Olli Etuahob43846e2015-06-02 18:18:57 +03002045 if (objectSizes[i] > maxObjectSize)
2046 maxObjectSize = objectSizes[i];
Arun Patole274f0702015-05-05 13:33:30 +05302047 }
2048
Arun Patole7fa33552015-06-10 15:15:18 +05302049 if (!(*sequence)[0]->getAsTyped()->isMatrix())
2050 {
2051 for (unsigned int i = 0; i < paramsCount; i++)
2052 if (objectSizes[i] != maxObjectSize)
2053 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
2054 }
Arun Patole274f0702015-05-05 13:33:30 +05302055
Olli Etuahob43846e2015-06-02 18:18:57 +03002056 TConstantUnion *resultArray = nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05302057 if (paramsCount == 2)
2058 {
2059 //
2060 // Binary built-in
2061 //
2062 switch (op)
2063 {
Arun Patolebf790422015-05-18 17:53:04 +05302064 case EOpAtan:
2065 {
2066 if (basicType == EbtFloat)
2067 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002068 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302069 for (size_t i = 0; i < maxObjectSize; i++)
2070 {
2071 float y = unionArrays[0][i].getFConst();
2072 float x = unionArrays[1][i].getFConst();
2073 // Results are undefined if x and y are both 0.
2074 if (x == 0.0f && y == 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03002075 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05302076 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002077 resultArray[i].setFConst(atan2f(y, x));
Arun Patolebf790422015-05-18 17:53:04 +05302078 }
2079 }
2080 else
2081 UNREACHABLE();
2082 }
2083 break;
2084
2085 case EOpPow:
2086 {
2087 if (basicType == EbtFloat)
2088 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002089 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302090 for (size_t i = 0; i < maxObjectSize; i++)
2091 {
2092 float x = unionArrays[0][i].getFConst();
2093 float y = unionArrays[1][i].getFConst();
2094 // Results are undefined if x < 0.
2095 // Results are undefined if x = 0 and y <= 0.
2096 if (x < 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03002097 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05302098 else if (x == 0.0f && y <= 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03002099 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05302100 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002101 resultArray[i].setFConst(powf(x, y));
Arun Patolebf790422015-05-18 17:53:04 +05302102 }
2103 }
2104 else
2105 UNREACHABLE();
2106 }
2107 break;
2108
2109 case EOpMod:
2110 {
2111 if (basicType == EbtFloat)
2112 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002113 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302114 for (size_t i = 0; i < maxObjectSize; i++)
2115 {
2116 float x = unionArrays[0][i].getFConst();
2117 float y = unionArrays[1][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002118 resultArray[i].setFConst(x - y * floorf(x / y));
Arun Patolebf790422015-05-18 17:53:04 +05302119 }
2120 }
2121 else
2122 UNREACHABLE();
2123 }
2124 break;
2125
Arun Patole274f0702015-05-05 13:33:30 +05302126 case EOpMin:
2127 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002128 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302129 for (size_t i = 0; i < maxObjectSize; i++)
2130 {
2131 switch (basicType)
2132 {
2133 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002134 resultArray[i].setFConst(std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302135 break;
2136 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002137 resultArray[i].setIConst(std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302138 break;
2139 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002140 resultArray[i].setUConst(std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302141 break;
2142 default:
2143 UNREACHABLE();
2144 break;
2145 }
2146 }
2147 }
2148 break;
2149
2150 case EOpMax:
2151 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002152 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302153 for (size_t i = 0; i < maxObjectSize; i++)
2154 {
2155 switch (basicType)
2156 {
2157 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002158 resultArray[i].setFConst(std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302159 break;
2160 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002161 resultArray[i].setIConst(std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302162 break;
2163 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002164 resultArray[i].setUConst(std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302165 break;
2166 default:
2167 UNREACHABLE();
2168 break;
2169 }
2170 }
2171 }
2172 break;
2173
Arun Patolebf790422015-05-18 17:53:04 +05302174 case EOpStep:
2175 {
2176 if (basicType == EbtFloat)
2177 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002178 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302179 for (size_t i = 0; i < maxObjectSize; i++)
Olli Etuahob43846e2015-06-02 18:18:57 +03002180 resultArray[i].setFConst(unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f : 1.0f);
Arun Patolebf790422015-05-18 17:53:04 +05302181 }
2182 else
2183 UNREACHABLE();
2184 }
2185 break;
2186
Arun Patole9d0b1f92015-05-20 14:27:17 +05302187 case EOpLessThan:
2188 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002189 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302190 for (size_t i = 0; i < maxObjectSize; i++)
2191 {
2192 switch (basicType)
2193 {
2194 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002195 resultArray[i].setBConst(unionArrays[0][i].getFConst() < unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302196 break;
2197 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002198 resultArray[i].setBConst(unionArrays[0][i].getIConst() < unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302199 break;
2200 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002201 resultArray[i].setBConst(unionArrays[0][i].getUConst() < unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302202 break;
2203 default:
2204 UNREACHABLE();
2205 break;
2206 }
2207 }
2208 }
2209 break;
2210
2211 case EOpLessThanEqual:
2212 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002213 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302214 for (size_t i = 0; i < maxObjectSize; i++)
2215 {
2216 switch (basicType)
2217 {
2218 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002219 resultArray[i].setBConst(unionArrays[0][i].getFConst() <= unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302220 break;
2221 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002222 resultArray[i].setBConst(unionArrays[0][i].getIConst() <= unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302223 break;
2224 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002225 resultArray[i].setBConst(unionArrays[0][i].getUConst() <= unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302226 break;
2227 default:
2228 UNREACHABLE();
2229 break;
2230 }
2231 }
2232 }
2233 break;
2234
2235 case EOpGreaterThan:
2236 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002237 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302238 for (size_t i = 0; i < maxObjectSize; i++)
2239 {
2240 switch (basicType)
2241 {
2242 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002243 resultArray[i].setBConst(unionArrays[0][i].getFConst() > unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302244 break;
2245 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002246 resultArray[i].setBConst(unionArrays[0][i].getIConst() > unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302247 break;
2248 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002249 resultArray[i].setBConst(unionArrays[0][i].getUConst() > unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302250 break;
2251 default:
2252 UNREACHABLE();
2253 break;
Olli Etuahob43846e2015-06-02 18:18:57 +03002254 }
2255 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302256 }
2257 break;
2258
2259 case EOpGreaterThanEqual:
2260 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002261 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302262 for (size_t i = 0; i < maxObjectSize; i++)
2263 {
2264 switch (basicType)
2265 {
2266 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002267 resultArray[i].setBConst(unionArrays[0][i].getFConst() >= unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302268 break;
2269 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002270 resultArray[i].setBConst(unionArrays[0][i].getIConst() >= unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302271 break;
2272 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002273 resultArray[i].setBConst(unionArrays[0][i].getUConst() >= unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302274 break;
2275 default:
2276 UNREACHABLE();
2277 break;
2278 }
2279 }
2280 }
2281 break;
2282
2283 case EOpVectorEqual:
2284 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002285 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302286 for (size_t i = 0; i < maxObjectSize; i++)
2287 {
2288 switch (basicType)
2289 {
2290 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002291 resultArray[i].setBConst(unionArrays[0][i].getFConst() == unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302292 break;
2293 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002294 resultArray[i].setBConst(unionArrays[0][i].getIConst() == unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302295 break;
2296 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002297 resultArray[i].setBConst(unionArrays[0][i].getUConst() == unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302298 break;
2299 case EbtBool:
Olli Etuahob43846e2015-06-02 18:18:57 +03002300 resultArray[i].setBConst(unionArrays[0][i].getBConst() == unionArrays[1][i].getBConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302301 break;
2302 default:
2303 UNREACHABLE();
2304 break;
2305 }
2306 }
2307 }
2308 break;
2309
2310 case EOpVectorNotEqual:
2311 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002312 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302313 for (size_t i = 0; i < maxObjectSize; i++)
2314 {
2315 switch (basicType)
2316 {
2317 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002318 resultArray[i].setBConst(unionArrays[0][i].getFConst() != unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302319 break;
2320 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002321 resultArray[i].setBConst(unionArrays[0][i].getIConst() != unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302322 break;
2323 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002324 resultArray[i].setBConst(unionArrays[0][i].getUConst() != unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302325 break;
2326 case EbtBool:
Olli Etuahob43846e2015-06-02 18:18:57 +03002327 resultArray[i].setBConst(unionArrays[0][i].getBConst() != unionArrays[1][i].getBConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302328 break;
2329 default:
2330 UNREACHABLE();
2331 break;
2332 }
2333 }
2334 }
2335 break;
2336
Arun Patole1155ddd2015-06-05 18:04:36 +05302337 case EOpDistance:
2338 if (basicType == EbtFloat)
2339 {
2340 TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
Olli Etuahob43846e2015-06-02 18:18:57 +03002341 resultArray = new TConstantUnion();
Arun Patole1155ddd2015-06-05 18:04:36 +05302342 for (size_t i = 0; i < maxObjectSize; i++)
2343 {
2344 float x = unionArrays[0][i].getFConst();
2345 float y = unionArrays[1][i].getFConst();
2346 distanceArray[i].setFConst(x - y);
2347 }
Olli Etuahob43846e2015-06-02 18:18:57 +03002348 resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
Arun Patole1155ddd2015-06-05 18:04:36 +05302349 }
2350 else
2351 UNREACHABLE();
2352 break;
2353
2354 case EOpDot:
Olli Etuahob43846e2015-06-02 18:18:57 +03002355
Arun Patole1155ddd2015-06-05 18:04:36 +05302356 if (basicType == EbtFloat)
2357 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002358 resultArray = new TConstantUnion();
2359 resultArray->setFConst(VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
Arun Patole1155ddd2015-06-05 18:04:36 +05302360 }
2361 else
2362 UNREACHABLE();
2363 break;
2364
2365 case EOpCross:
2366 if (basicType == EbtFloat && maxObjectSize == 3)
2367 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002368 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302369 float x0 = unionArrays[0][0].getFConst();
2370 float x1 = unionArrays[0][1].getFConst();
2371 float x2 = unionArrays[0][2].getFConst();
2372 float y0 = unionArrays[1][0].getFConst();
2373 float y1 = unionArrays[1][1].getFConst();
2374 float y2 = unionArrays[1][2].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002375 resultArray[0].setFConst(x1 * y2 - y1 * x2);
2376 resultArray[1].setFConst(x2 * y0 - y2 * x0);
2377 resultArray[2].setFConst(x0 * y1 - y0 * x1);
Arun Patole1155ddd2015-06-05 18:04:36 +05302378 }
2379 else
2380 UNREACHABLE();
2381 break;
2382
2383 case EOpReflect:
2384 if (basicType == EbtFloat)
2385 {
2386 // genType reflect (genType I, genType N) :
2387 // For the incident vector I and surface orientation N, returns the reflection direction:
2388 // I - 2 * dot(N, I) * N.
Olli Etuahob43846e2015-06-02 18:18:57 +03002389 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302390 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2391 for (size_t i = 0; i < maxObjectSize; i++)
2392 {
2393 float result = unionArrays[0][i].getFConst() -
2394 2.0f * dotProduct * unionArrays[1][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002395 resultArray[i].setFConst(result);
Arun Patole1155ddd2015-06-05 18:04:36 +05302396 }
2397 }
2398 else
2399 UNREACHABLE();
2400 break;
2401
Arun Patole7fa33552015-06-10 15:15:18 +05302402 case EOpMul:
2403 if (basicType == EbtFloat && (*sequence)[0]->getAsTyped()->isMatrix() &&
2404 (*sequence)[1]->getAsTyped()->isMatrix())
2405 {
2406 // Perform component-wise matrix multiplication.
2407 resultArray = new TConstantUnion[maxObjectSize];
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002408 int size = (*sequence)[0]->getAsTyped()->getNominalSize();
Arun Patole7fa33552015-06-10 15:15:18 +05302409 angle::Matrix<float> result =
2410 GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size));
2411 SetUnionArrayFromMatrix(result, resultArray);
2412 }
2413 else
2414 UNREACHABLE();
2415 break;
2416
2417 case EOpOuterProduct:
2418 if (basicType == EbtFloat)
2419 {
2420 size_t numRows = (*sequence)[0]->getAsTyped()->getType().getObjectSize();
2421 size_t numCols = (*sequence)[1]->getAsTyped()->getType().getObjectSize();
2422 resultArray = new TConstantUnion[numRows * numCols];
2423 angle::Matrix<float> result =
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002424 GetMatrix(unionArrays[0], 1, static_cast<int>(numCols))
2425 .outerProduct(GetMatrix(unionArrays[1], static_cast<int>(numRows), 1));
Arun Patole7fa33552015-06-10 15:15:18 +05302426 SetUnionArrayFromMatrix(result, resultArray);
2427 }
2428 else
2429 UNREACHABLE();
2430 break;
2431
Arun Patole274f0702015-05-05 13:33:30 +05302432 default:
2433 UNREACHABLE();
2434 // TODO: Add constant folding support for other built-in operations that take 2 parameters and not handled above.
2435 return nullptr;
2436 }
2437 }
2438 else if (paramsCount == 3)
2439 {
2440 //
2441 // Ternary built-in
2442 //
2443 switch (op)
2444 {
2445 case EOpClamp:
2446 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002447 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302448 for (size_t i = 0; i < maxObjectSize; i++)
2449 {
2450 switch (basicType)
2451 {
2452 case EbtFloat:
2453 {
2454 float x = unionArrays[0][i].getFConst();
2455 float min = unionArrays[1][i].getFConst();
2456 float max = unionArrays[2][i].getFConst();
2457 // Results are undefined if min > max.
2458 if (min > max)
Olli Etuahob43846e2015-06-02 18:18:57 +03002459 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302460 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002461 resultArray[i].setFConst(gl::clamp(x, min, max));
Arun Patole274f0702015-05-05 13:33:30 +05302462 }
2463 break;
2464 case EbtInt:
2465 {
2466 int x = unionArrays[0][i].getIConst();
2467 int min = unionArrays[1][i].getIConst();
2468 int max = unionArrays[2][i].getIConst();
2469 // Results are undefined if min > max.
2470 if (min > max)
Olli Etuahob43846e2015-06-02 18:18:57 +03002471 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302472 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002473 resultArray[i].setIConst(gl::clamp(x, min, max));
Arun Patole274f0702015-05-05 13:33:30 +05302474 }
2475 break;
2476 case EbtUInt:
2477 {
2478 unsigned int x = unionArrays[0][i].getUConst();
2479 unsigned int min = unionArrays[1][i].getUConst();
2480 unsigned int max = unionArrays[2][i].getUConst();
2481 // Results are undefined if min > max.
2482 if (min > max)
Olli Etuahob43846e2015-06-02 18:18:57 +03002483 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302484 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002485 resultArray[i].setUConst(gl::clamp(x, min, max));
Arun Patole274f0702015-05-05 13:33:30 +05302486 }
2487 break;
2488 default:
2489 UNREACHABLE();
2490 break;
2491 }
2492 }
2493 }
2494 break;
2495
Arun Patolebf790422015-05-18 17:53:04 +05302496 case EOpMix:
2497 {
2498 if (basicType == EbtFloat)
2499 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002500 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302501 for (size_t i = 0; i < maxObjectSize; i++)
2502 {
2503 float x = unionArrays[0][i].getFConst();
2504 float y = unionArrays[1][i].getFConst();
2505 TBasicType type = (*sequence)[2]->getAsTyped()->getType().getBasicType();
2506 if (type == EbtFloat)
2507 {
2508 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
2509 float a = unionArrays[2][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002510 resultArray[i].setFConst(x * (1.0f - a) + y * a);
Arun Patolebf790422015-05-18 17:53:04 +05302511 }
2512 else // 3rd parameter is EbtBool
2513 {
2514 ASSERT(type == EbtBool);
2515 // Selects which vector each returned component comes from.
2516 // For a component of a that is false, the corresponding component of x is returned.
2517 // For a component of a that is true, the corresponding component of y is returned.
2518 bool a = unionArrays[2][i].getBConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002519 resultArray[i].setFConst(a ? y : x);
Arun Patolebf790422015-05-18 17:53:04 +05302520 }
2521 }
2522 }
2523 else
2524 UNREACHABLE();
2525 }
2526 break;
2527
2528 case EOpSmoothStep:
2529 {
2530 if (basicType == EbtFloat)
2531 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002532 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302533 for (size_t i = 0; i < maxObjectSize; i++)
2534 {
2535 float edge0 = unionArrays[0][i].getFConst();
2536 float edge1 = unionArrays[1][i].getFConst();
2537 float x = unionArrays[2][i].getFConst();
2538 // Results are undefined if edge0 >= edge1.
2539 if (edge0 >= edge1)
2540 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002541 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05302542 }
2543 else
2544 {
2545 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
2546 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
2547 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
Olli Etuahob43846e2015-06-02 18:18:57 +03002548 resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
Arun Patolebf790422015-05-18 17:53:04 +05302549 }
2550 }
2551 }
2552 else
2553 UNREACHABLE();
2554 }
2555 break;
2556
Arun Patole1155ddd2015-06-05 18:04:36 +05302557 case EOpFaceForward:
2558 if (basicType == EbtFloat)
2559 {
2560 // genType faceforward(genType N, genType I, genType Nref) :
2561 // If dot(Nref, I) < 0 return N, otherwise return -N.
Olli Etuahob43846e2015-06-02 18:18:57 +03002562 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302563 float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
2564 for (size_t i = 0; i < maxObjectSize; i++)
2565 {
2566 if (dotProduct < 0)
Olli Etuahob43846e2015-06-02 18:18:57 +03002567 resultArray[i].setFConst(unionArrays[0][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302568 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002569 resultArray[i].setFConst(-unionArrays[0][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302570 }
2571 }
2572 else
2573 UNREACHABLE();
2574 break;
2575
2576 case EOpRefract:
2577 if (basicType == EbtFloat)
2578 {
2579 // genType refract(genType I, genType N, float eta) :
2580 // For the incident vector I and surface normal N, and the ratio of indices of refraction eta,
2581 // return the refraction vector. The result is computed by
2582 // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
2583 // if (k < 0.0)
2584 // return genType(0.0)
2585 // else
2586 // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
Olli Etuahob43846e2015-06-02 18:18:57 +03002587 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302588 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2589 for (size_t i = 0; i < maxObjectSize; i++)
2590 {
2591 float eta = unionArrays[2][i].getFConst();
2592 float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
2593 if (k < 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03002594 resultArray[i].setFConst(0.0f);
Arun Patole1155ddd2015-06-05 18:04:36 +05302595 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002596 resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
Arun Patole1155ddd2015-06-05 18:04:36 +05302597 (eta * dotProduct + sqrtf(k)) * unionArrays[1][i].getFConst());
2598 }
2599 }
2600 else
2601 UNREACHABLE();
2602 break;
2603
Arun Patole274f0702015-05-05 13:33:30 +05302604 default:
2605 UNREACHABLE();
2606 // TODO: Add constant folding support for other built-in operations that take 3 parameters and not handled above.
2607 return nullptr;
2608 }
2609 }
Olli Etuahob43846e2015-06-02 18:18:57 +03002610 return resultArray;
Arun Patole274f0702015-05-05 13:33:30 +05302611}
2612
2613// static
Jamie Madillb1a85f42014-08-19 15:23:24 -04002614TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunction)
2615{
2616 if (hashFunction == NULL || name.empty())
2617 return name;
2618 khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
2619 TStringStream stream;
2620 stream << HASHED_NAME_PREFIX << std::hex << number;
2621 TString hashedName = stream.str();
2622 return hashedName;
2623}
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002624
2625void TIntermTraverser::updateTree()
2626{
Olli Etuahoa6f22092015-05-08 18:31:10 +03002627 for (size_t ii = 0; ii < mInsertions.size(); ++ii)
2628 {
2629 const NodeInsertMultipleEntry &insertion = mInsertions[ii];
2630 ASSERT(insertion.parent);
Olli Etuaho5d91dda2015-06-18 15:47:46 +03002631 if (!insertion.insertionsAfter.empty())
2632 {
2633 bool inserted = insertion.parent->insertChildNodes(insertion.position + 1,
2634 insertion.insertionsAfter);
2635 ASSERT(inserted);
2636 UNUSED_ASSERTION_VARIABLE(inserted);
2637 }
2638 if (!insertion.insertionsBefore.empty())
2639 {
2640 bool inserted =
2641 insertion.parent->insertChildNodes(insertion.position, insertion.insertionsBefore);
2642 ASSERT(inserted);
2643 UNUSED_ASSERTION_VARIABLE(inserted);
2644 }
Olli Etuahoa6f22092015-05-08 18:31:10 +03002645 }
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002646 for (size_t ii = 0; ii < mReplacements.size(); ++ii)
2647 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002648 const NodeUpdateEntry &replacement = mReplacements[ii];
2649 ASSERT(replacement.parent);
2650 bool replaced = replacement.parent->replaceChildNode(
2651 replacement.original, replacement.replacement);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002652 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03002653 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002654
Olli Etuahocd94ef92015-04-16 19:18:10 +03002655 if (!replacement.originalBecomesChildOfReplacement)
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002656 {
2657 // In AST traversing, a parent is visited before its children.
Olli Etuahocd94ef92015-04-16 19:18:10 +03002658 // After we replace a node, if its immediate child is to
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002659 // be replaced, we need to make sure we don't update the replaced
2660 // node; instead, we update the replacement node.
2661 for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj)
2662 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002663 NodeUpdateEntry &replacement2 = mReplacements[jj];
2664 if (replacement2.parent == replacement.original)
2665 replacement2.parent = replacement.replacement;
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002666 }
2667 }
2668 }
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002669 for (size_t ii = 0; ii < mMultiReplacements.size(); ++ii)
2670 {
2671 const NodeReplaceWithMultipleEntry &replacement = mMultiReplacements[ii];
2672 ASSERT(replacement.parent);
2673 bool replaced = replacement.parent->replaceChildNodeWithMultiple(
2674 replacement.original, replacement.replacements);
2675 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03002676 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002677 }
Olli Etuahod4f303e2015-05-20 17:09:06 +03002678
Jamie Madill03d863c2016-07-27 18:15:53 -04002679 clearReplacementQueue();
2680}
2681
2682void TIntermTraverser::clearReplacementQueue()
2683{
Olli Etuahod4f303e2015-05-20 17:09:06 +03002684 mReplacements.clear();
2685 mMultiReplacements.clear();
Jamie Madill03d863c2016-07-27 18:15:53 -04002686 mInsertions.clear();
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002687}
Jamie Madill1048e432016-07-23 18:51:28 -04002688
Jamie Madill03d863c2016-07-27 18:15:53 -04002689void TIntermTraverser::queueReplacement(TIntermNode *original,
2690 TIntermNode *replacement,
2691 OriginalNode originalStatus)
Jamie Madill1048e432016-07-23 18:51:28 -04002692{
Jamie Madill03d863c2016-07-27 18:15:53 -04002693 queueReplacementWithParent(getParentNode(), original, replacement, originalStatus);
Jamie Madill1048e432016-07-23 18:51:28 -04002694}
2695
Jamie Madill03d863c2016-07-27 18:15:53 -04002696void TIntermTraverser::queueReplacementWithParent(TIntermNode *parent,
2697 TIntermNode *original,
2698 TIntermNode *replacement,
2699 OriginalNode originalStatus)
Jamie Madill1048e432016-07-23 18:51:28 -04002700{
Jamie Madill03d863c2016-07-27 18:15:53 -04002701 bool originalBecomesChild = (originalStatus == OriginalNode::BECOMES_CHILD);
2702 mReplacements.push_back(NodeUpdateEntry(parent, original, replacement, originalBecomesChild));
Jamie Madill1048e432016-07-23 18:51:28 -04002703}