blob: d9658d4e852133479aca7afdf34a0f0d8f144d5c [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:
60 return left.getCols() == right.getCols() &&
61 left.getRows() == right.getRows();
62
63 default:
64 UNREACHABLE();
65 return false;
66 }
67}
68
69bool CompareStructure(const TType& leftNodeType,
Jamie Madillb11e2482015-05-04 14:21:22 -040070 const TConstantUnion *rightUnionArray,
71 const TConstantUnion *leftUnionArray);
Jamie Madillb1a85f42014-08-19 15:23:24 -040072
73bool CompareStruct(const TType &leftNodeType,
Jamie Madillb11e2482015-05-04 14:21:22 -040074 const TConstantUnion *rightUnionArray,
75 const TConstantUnion *leftUnionArray)
Jamie Madillb1a85f42014-08-19 15:23:24 -040076{
77 const TFieldList &fields = leftNodeType.getStruct()->fields();
78
79 size_t structSize = fields.size();
80 size_t index = 0;
81
82 for (size_t j = 0; j < structSize; j++)
83 {
84 size_t size = fields[j]->type()->getObjectSize();
85 for (size_t i = 0; i < size; i++)
86 {
87 if (fields[j]->type()->getBasicType() == EbtStruct)
88 {
89 if (!CompareStructure(*fields[j]->type(),
90 &rightUnionArray[index],
91 &leftUnionArray[index]))
92 {
93 return false;
94 }
95 }
96 else
97 {
98 if (leftUnionArray[index] != rightUnionArray[index])
99 return false;
100 index++;
101 }
102 }
103 }
104 return true;
105}
106
107bool CompareStructure(const TType &leftNodeType,
Jamie Madillb11e2482015-05-04 14:21:22 -0400108 const TConstantUnion *rightUnionArray,
109 const TConstantUnion *leftUnionArray)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400110{
111 if (leftNodeType.isArray())
112 {
113 TType typeWithoutArrayness = leftNodeType;
114 typeWithoutArrayness.clearArrayness();
115
116 size_t arraySize = leftNodeType.getArraySize();
117
118 for (size_t i = 0; i < arraySize; ++i)
119 {
120 size_t offset = typeWithoutArrayness.getObjectSize() * i;
121 if (!CompareStruct(typeWithoutArrayness,
122 &rightUnionArray[offset],
123 &leftUnionArray[offset]))
124 {
125 return false;
126 }
127 }
128 }
129 else
130 {
131 return CompareStruct(leftNodeType, rightUnionArray, leftUnionArray);
132 }
133 return true;
134}
135
Arun Patole274f0702015-05-05 13:33:30 +0530136TConstantUnion *Vectorize(const TConstantUnion &constant, size_t size)
137{
138 TConstantUnion *constUnion = new TConstantUnion[size];
139 for (unsigned int i = 0; i < size; ++i)
140 constUnion[i] = constant;
141
142 return constUnion;
143}
144
Arun Patolebf790422015-05-18 17:53:04 +0530145void UndefinedConstantFoldingError(const TSourceLoc &loc, TOperator op, TBasicType basicType,
146 TInfoSink &infoSink, TConstantUnion *result)
147{
148 std::stringstream constantFoldingErrorStream;
149 constantFoldingErrorStream << "'" << GetOperatorString(op)
150 << "' operation result is undefined for the values passed in";
151 infoSink.info.message(EPrefixWarning, loc, constantFoldingErrorStream.str().c_str());
152
153 switch (basicType)
154 {
155 case EbtFloat :
156 result->setFConst(0.0f);
157 break;
158 case EbtInt:
159 result->setIConst(0);
160 break;
161 case EbtUInt:
162 result->setUConst(0u);
163 break;
164 case EbtBool:
165 result->setBConst(false);
166 break;
167 default:
168 break;
169 }
170}
171
Arun Patole1155ddd2015-06-05 18:04:36 +0530172float VectorLength(TConstantUnion *paramArray, size_t paramArraySize)
173{
174 float result = 0.0f;
175 for (size_t i = 0; i < paramArraySize; i++)
176 {
177 float f = paramArray[i].getFConst();
178 result += f * f;
179 }
180 return sqrtf(result);
181}
182
183float VectorDotProduct(TConstantUnion *paramArray1, TConstantUnion *paramArray2, size_t paramArraySize)
184{
185 float result = 0.0f;
186 for (size_t i = 0; i < paramArraySize; i++)
187 result += paramArray1[i].getFConst() * paramArray2[i].getFConst();
188 return result;
189}
190
Olli Etuahob43846e2015-06-02 18:18:57 +0300191TIntermTyped *CreateFoldedNode(TConstantUnion *constArray, const TIntermTyped *originalNode)
192{
193 if (constArray == nullptr)
194 {
195 return nullptr;
196 }
197 TIntermTyped *folded = new TIntermConstantUnion(constArray, originalNode->getType());
198 folded->getTypePointer()->setQualifier(EvqConst);
199 folded->setLine(originalNode->getLine());
200 return folded;
201}
202
Arun Patole7fa33552015-06-10 15:15:18 +0530203angle::Matrix<float> GetMatrix(TConstantUnion *paramArray, const unsigned int &rows, const unsigned int &cols)
204{
205 std::vector<float> elements;
206 for (size_t i = 0; i < rows * cols; i++)
207 elements.push_back(paramArray[i].getFConst());
208 // Transpose is used since the Matrix constructor expects arguments in row-major order,
209 // whereas the paramArray is in column-major order.
210 return angle::Matrix<float>(elements, rows, cols).transpose();
211}
212
213angle::Matrix<float> GetMatrix(TConstantUnion *paramArray, const unsigned int &size)
214{
215 std::vector<float> elements;
216 for (size_t i = 0; i < size * size; i++)
217 elements.push_back(paramArray[i].getFConst());
218 // Transpose is used since the Matrix constructor expects arguments in row-major order,
219 // whereas the paramArray is in column-major order.
220 return angle::Matrix<float>(elements, size).transpose();
221}
222
223void SetUnionArrayFromMatrix(const angle::Matrix<float> &m, TConstantUnion *resultArray)
224{
225 // Transpose is used since the input Matrix is in row-major order,
226 // whereas the actual result should be in column-major order.
227 angle::Matrix<float> result = m.transpose();
228 std::vector<float> resultElements = result.elements();
229 for (size_t i = 0; i < resultElements.size(); i++)
230 resultArray[i].setFConst(resultElements[i]);
231}
232
Jamie Madillb1a85f42014-08-19 15:23:24 -0400233} // namespace anonymous
234
235
236////////////////////////////////////////////////////////////////
237//
238// Member functions of the nodes used for building the tree.
239//
240////////////////////////////////////////////////////////////////
241
Olli Etuahod2a67b92014-10-21 16:42:57 +0300242void TIntermTyped::setTypePreservePrecision(const TType &t)
243{
244 TPrecision precision = getPrecision();
245 mType = t;
246 ASSERT(mType.getBasicType() != EbtBool || precision == EbpUndefined);
247 mType.setPrecision(precision);
248}
249
Jamie Madillb1a85f42014-08-19 15:23:24 -0400250#define REPLACE_IF_IS(node, type, original, replacement) \
251 if (node == original) { \
252 node = static_cast<type *>(replacement); \
253 return true; \
254 }
255
256bool TIntermLoop::replaceChildNode(
257 TIntermNode *original, TIntermNode *replacement)
258{
259 REPLACE_IF_IS(mInit, TIntermNode, original, replacement);
260 REPLACE_IF_IS(mCond, TIntermTyped, original, replacement);
261 REPLACE_IF_IS(mExpr, TIntermTyped, original, replacement);
262 REPLACE_IF_IS(mBody, TIntermNode, original, replacement);
263 return false;
264}
265
Jamie Madillb1a85f42014-08-19 15:23:24 -0400266bool TIntermBranch::replaceChildNode(
267 TIntermNode *original, TIntermNode *replacement)
268{
269 REPLACE_IF_IS(mExpression, TIntermTyped, original, replacement);
270 return false;
271}
272
Jamie Madillb1a85f42014-08-19 15:23:24 -0400273bool TIntermBinary::replaceChildNode(
274 TIntermNode *original, TIntermNode *replacement)
275{
276 REPLACE_IF_IS(mLeft, TIntermTyped, original, replacement);
277 REPLACE_IF_IS(mRight, TIntermTyped, original, replacement);
278 return false;
279}
280
Jamie Madillb1a85f42014-08-19 15:23:24 -0400281bool TIntermUnary::replaceChildNode(
282 TIntermNode *original, TIntermNode *replacement)
283{
284 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
285 return false;
286}
287
Jamie Madillb1a85f42014-08-19 15:23:24 -0400288bool TIntermAggregate::replaceChildNode(
289 TIntermNode *original, TIntermNode *replacement)
290{
291 for (size_t ii = 0; ii < mSequence.size(); ++ii)
292 {
293 REPLACE_IF_IS(mSequence[ii], TIntermNode, original, replacement);
294 }
295 return false;
296}
297
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300298bool TIntermAggregate::replaceChildNodeWithMultiple(TIntermNode *original, TIntermSequence replacements)
299{
300 for (auto it = mSequence.begin(); it < mSequence.end(); ++it)
301 {
302 if (*it == original)
303 {
304 it = mSequence.erase(it);
Olli Etuaho8fee0ab2015-04-23 14:52:46 +0300305 mSequence.insert(it, replacements.begin(), replacements.end());
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300306 return true;
307 }
308 }
309 return false;
310}
311
Olli Etuahoa6f22092015-05-08 18:31:10 +0300312bool TIntermAggregate::insertChildNodes(TIntermSequence::size_type position, TIntermSequence insertions)
313{
Jamie Madilla5f64de2015-10-30 12:31:00 +0000314 TIntermSequence::size_type itPosition = 0;
315 for (auto it = mSequence.begin(); it < mSequence.end(); ++it)
Olli Etuahoa6f22092015-05-08 18:31:10 +0300316 {
Jamie Madilla5f64de2015-10-30 12:31:00 +0000317 if (itPosition == position)
318 {
319 mSequence.insert(it, insertions.begin(), insertions.end());
320 return true;
321 }
322 ++itPosition;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300323 }
Jamie Madilla5f64de2015-10-30 12:31:00 +0000324 return false;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300325}
326
Olli Etuahod2a67b92014-10-21 16:42:57 +0300327void TIntermAggregate::setPrecisionFromChildren()
328{
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300329 mGotPrecisionFromChildren = true;
Olli Etuahod2a67b92014-10-21 16:42:57 +0300330 if (getBasicType() == EbtBool)
331 {
332 mType.setPrecision(EbpUndefined);
333 return;
334 }
335
336 TPrecision precision = EbpUndefined;
337 TIntermSequence::iterator childIter = mSequence.begin();
338 while (childIter != mSequence.end())
339 {
340 TIntermTyped *typed = (*childIter)->getAsTyped();
341 if (typed)
342 precision = GetHigherPrecision(typed->getPrecision(), precision);
343 ++childIter;
344 }
345 mType.setPrecision(precision);
346}
347
348void TIntermAggregate::setBuiltInFunctionPrecision()
349{
350 // All built-ins returning bool should be handled as ops, not functions.
351 ASSERT(getBasicType() != EbtBool);
352
353 TPrecision precision = EbpUndefined;
354 TIntermSequence::iterator childIter = mSequence.begin();
355 while (childIter != mSequence.end())
356 {
357 TIntermTyped *typed = (*childIter)->getAsTyped();
358 // ESSL spec section 8: texture functions get their precision from the sampler.
359 if (typed && IsSampler(typed->getBasicType()))
360 {
361 precision = typed->getPrecision();
362 break;
363 }
364 ++childIter;
365 }
366 // ESSL 3.0 spec section 8: textureSize always gets highp precision.
367 // All other functions that take a sampler are assumed to be texture functions.
Olli Etuaho59f9a642015-08-06 20:38:26 +0300368 if (mName.getString().find("textureSize") == 0)
Olli Etuahod2a67b92014-10-21 16:42:57 +0300369 mType.setPrecision(EbpHigh);
370 else
371 mType.setPrecision(precision);
372}
373
Jamie Madillb1a85f42014-08-19 15:23:24 -0400374bool TIntermSelection::replaceChildNode(
375 TIntermNode *original, TIntermNode *replacement)
376{
377 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
378 REPLACE_IF_IS(mTrueBlock, TIntermNode, original, replacement);
379 REPLACE_IF_IS(mFalseBlock, TIntermNode, original, replacement);
380 return false;
381}
382
Olli Etuahoa3a36662015-02-17 13:46:51 +0200383bool TIntermSwitch::replaceChildNode(
384 TIntermNode *original, TIntermNode *replacement)
385{
386 REPLACE_IF_IS(mInit, TIntermTyped, original, replacement);
387 REPLACE_IF_IS(mStatementList, TIntermAggregate, original, replacement);
388 return false;
389}
390
391bool TIntermCase::replaceChildNode(
392 TIntermNode *original, TIntermNode *replacement)
393{
394 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
395 return false;
396}
397
Olli Etuahod7a25242015-08-18 13:49:45 +0300398TIntermTyped::TIntermTyped(const TIntermTyped &node) : TIntermNode(), mType(node.mType)
399{
400 // Copy constructor is disallowed for TIntermNode in order to disallow it for subclasses that
401 // don't explicitly allow it, so normal TIntermNode constructor is used to construct the copy.
402 // We need to manually copy any fields of TIntermNode besides handling fields in TIntermTyped.
403 mLine = node.mLine;
404}
405
406TIntermConstantUnion::TIntermConstantUnion(const TIntermConstantUnion &node) : TIntermTyped(node)
407{
408 size_t arraySize = mType.getObjectSize();
409 mUnionArrayPointer = new TConstantUnion[arraySize];
410 for (size_t i = 0u; i < arraySize; ++i)
411 {
412 mUnionArrayPointer[i] = node.mUnionArrayPointer[i];
413 }
414}
415
416TIntermAggregate::TIntermAggregate(const TIntermAggregate &node)
417 : TIntermOperator(node),
418 mName(node.mName),
419 mUserDefined(node.mUserDefined),
420 mFunctionId(node.mFunctionId),
Olli Etuahod7a25242015-08-18 13:49:45 +0300421 mUseEmulatedFunction(node.mUseEmulatedFunction),
422 mGotPrecisionFromChildren(node.mGotPrecisionFromChildren)
423{
424 for (TIntermNode *child : node.mSequence)
425 {
426 TIntermTyped *typedChild = child->getAsTyped();
427 ASSERT(typedChild != nullptr);
428 TIntermTyped *childCopy = typedChild->deepCopy();
429 mSequence.push_back(childCopy);
430 }
431}
432
433TIntermBinary::TIntermBinary(const TIntermBinary &node)
434 : TIntermOperator(node), mAddIndexClamp(node.mAddIndexClamp)
435{
436 TIntermTyped *leftCopy = node.mLeft->deepCopy();
437 TIntermTyped *rightCopy = node.mRight->deepCopy();
438 ASSERT(leftCopy != nullptr && rightCopy != nullptr);
439 mLeft = leftCopy;
440 mRight = rightCopy;
441}
442
443TIntermUnary::TIntermUnary(const TIntermUnary &node)
444 : TIntermOperator(node), mUseEmulatedFunction(node.mUseEmulatedFunction)
445{
446 TIntermTyped *operandCopy = node.mOperand->deepCopy();
447 ASSERT(operandCopy != nullptr);
448 mOperand = operandCopy;
449}
450
451TIntermSelection::TIntermSelection(const TIntermSelection &node) : TIntermTyped(node)
452{
453 // Only supported for ternary nodes, not if statements.
454 TIntermTyped *trueTyped = node.mTrueBlock->getAsTyped();
455 TIntermTyped *falseTyped = node.mFalseBlock->getAsTyped();
456 ASSERT(trueTyped != nullptr);
457 ASSERT(falseTyped != nullptr);
458 TIntermTyped *conditionCopy = node.mCondition->deepCopy();
459 TIntermTyped *trueCopy = trueTyped->deepCopy();
460 TIntermTyped *falseCopy = falseTyped->deepCopy();
461 ASSERT(conditionCopy != nullptr && trueCopy != nullptr && falseCopy != nullptr);
462 mCondition = conditionCopy;
463 mTrueBlock = trueCopy;
464 mFalseBlock = falseCopy;
465}
466
Jamie Madillb1a85f42014-08-19 15:23:24 -0400467//
468// Say whether or not an operation node changes the value of a variable.
469//
470bool TIntermOperator::isAssignment() const
471{
472 switch (mOp)
473 {
474 case EOpPostIncrement:
475 case EOpPostDecrement:
476 case EOpPreIncrement:
477 case EOpPreDecrement:
478 case EOpAssign:
479 case EOpAddAssign:
480 case EOpSubAssign:
481 case EOpMulAssign:
482 case EOpVectorTimesMatrixAssign:
483 case EOpVectorTimesScalarAssign:
484 case EOpMatrixTimesScalarAssign:
485 case EOpMatrixTimesMatrixAssign:
486 case EOpDivAssign:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200487 case EOpIModAssign:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200488 case EOpBitShiftLeftAssign:
489 case EOpBitShiftRightAssign:
490 case EOpBitwiseAndAssign:
491 case EOpBitwiseXorAssign:
492 case EOpBitwiseOrAssign:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400493 return true;
494 default:
495 return false;
496 }
497}
498
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300499bool TIntermOperator::isMultiplication() const
500{
501 switch (mOp)
502 {
503 case EOpMul:
504 case EOpMatrixTimesMatrix:
505 case EOpMatrixTimesVector:
506 case EOpMatrixTimesScalar:
507 case EOpVectorTimesMatrix:
508 case EOpVectorTimesScalar:
509 return true;
510 default:
511 return false;
512 }
513}
514
Jamie Madillb1a85f42014-08-19 15:23:24 -0400515//
516// returns true if the operator is for one of the constructors
517//
518bool TIntermOperator::isConstructor() const
519{
520 switch (mOp)
521 {
522 case EOpConstructVec2:
523 case EOpConstructVec3:
524 case EOpConstructVec4:
525 case EOpConstructMat2:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400526 case EOpConstructMat2x3:
527 case EOpConstructMat2x4:
528 case EOpConstructMat3x2:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400529 case EOpConstructMat3:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400530 case EOpConstructMat3x4:
531 case EOpConstructMat4x2:
532 case EOpConstructMat4x3:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400533 case EOpConstructMat4:
534 case EOpConstructFloat:
535 case EOpConstructIVec2:
536 case EOpConstructIVec3:
537 case EOpConstructIVec4:
538 case EOpConstructInt:
539 case EOpConstructUVec2:
540 case EOpConstructUVec3:
541 case EOpConstructUVec4:
542 case EOpConstructUInt:
543 case EOpConstructBVec2:
544 case EOpConstructBVec3:
545 case EOpConstructBVec4:
546 case EOpConstructBool:
547 case EOpConstructStruct:
548 return true;
549 default:
550 return false;
551 }
552}
553
554//
555// Make sure the type of a unary operator is appropriate for its
556// combination of operation and operand type.
557//
Olli Etuahof6c694b2015-03-26 14:50:53 +0200558void TIntermUnary::promote(const TType *funcReturnType)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400559{
560 switch (mOp)
561 {
Olli Etuahodca3e792015-03-26 13:24:04 +0200562 case EOpFloatBitsToInt:
563 case EOpFloatBitsToUint:
Olli Etuahoe8d2c072015-01-08 16:33:54 +0200564 case EOpIntBitsToFloat:
565 case EOpUintBitsToFloat:
Olli Etuahodca3e792015-03-26 13:24:04 +0200566 case EOpPackSnorm2x16:
567 case EOpPackUnorm2x16:
568 case EOpPackHalf2x16:
Olli Etuaho7700ff62015-01-15 12:16:29 +0200569 case EOpUnpackSnorm2x16:
570 case EOpUnpackUnorm2x16:
Olli Etuahodca3e792015-03-26 13:24:04 +0200571 mType.setPrecision(EbpHigh);
Arun Patole6b19d762015-02-19 09:40:39 +0530572 break;
Olli Etuahodca3e792015-03-26 13:24:04 +0200573 case EOpUnpackHalf2x16:
574 mType.setPrecision(EbpMedium);
575 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400576 default:
Olli Etuahodca3e792015-03-26 13:24:04 +0200577 setType(mOperand->getType());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400578 }
579
Olli Etuahof6c694b2015-03-26 14:50:53 +0200580 if (funcReturnType != nullptr)
581 {
582 if (funcReturnType->getBasicType() == EbtBool)
583 {
584 // Bool types should not have precision.
585 setType(*funcReturnType);
586 }
587 else
588 {
589 // Precision of the node has been set based on the operand.
590 setTypePreservePrecision(*funcReturnType);
591 }
592 }
593
Jamie Madillb1a85f42014-08-19 15:23:24 -0400594 mType.setQualifier(EvqTemporary);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400595}
596
597//
598// Establishes the type of the resultant operation, as well as
599// makes the operator the correct one for the operands.
600//
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200601// For lots of operations it should already be established that the operand
602// combination is valid, but returns false if operator can't work on operands.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400603//
604bool TIntermBinary::promote(TInfoSink &infoSink)
605{
Olli Etuahoe79904c2015-03-18 16:56:42 +0200606 ASSERT(mLeft->isArray() == mRight->isArray());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400607
Jamie Madillb1a85f42014-08-19 15:23:24 -0400608 //
609 // Base assumption: just make the type the same as the left
610 // operand. Then only deviations from this need be coded.
611 //
612 setType(mLeft->getType());
613
614 // The result gets promoted to the highest precision.
615 TPrecision higherPrecision = GetHigherPrecision(
616 mLeft->getPrecision(), mRight->getPrecision());
617 getTypePointer()->setPrecision(higherPrecision);
618
619 // Binary operations results in temporary variables unless both
620 // operands are const.
621 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
622 {
623 getTypePointer()->setQualifier(EvqTemporary);
624 }
625
626 const int nominalSize =
627 std::max(mLeft->getNominalSize(), mRight->getNominalSize());
628
629 //
630 // All scalars or structs. Code after this test assumes this case is removed!
631 //
632 if (nominalSize == 1)
633 {
634 switch (mOp)
635 {
636 //
637 // Promote to conditional
638 //
639 case EOpEqual:
640 case EOpNotEqual:
641 case EOpLessThan:
642 case EOpGreaterThan:
643 case EOpLessThanEqual:
644 case EOpGreaterThanEqual:
645 setType(TType(EbtBool, EbpUndefined));
646 break;
647
648 //
649 // And and Or operate on conditionals
650 //
651 case EOpLogicalAnd:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200652 case EOpLogicalXor:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400653 case EOpLogicalOr:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200654 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400655 setType(TType(EbtBool, EbpUndefined));
656 break;
657
658 default:
659 break;
660 }
661 return true;
662 }
663
664 // If we reach here, at least one of the operands is vector or matrix.
665 // The other operand could be a scalar, vector, or matrix.
666 // Can these two operands be combined?
667 //
668 TBasicType basicType = mLeft->getBasicType();
669 switch (mOp)
670 {
671 case EOpMul:
672 if (!mLeft->isMatrix() && mRight->isMatrix())
673 {
674 if (mLeft->isVector())
675 {
676 mOp = EOpVectorTimesMatrix;
677 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700678 static_cast<unsigned char>(mRight->getCols()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400679 }
680 else
681 {
682 mOp = EOpMatrixTimesScalar;
683 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700684 static_cast<unsigned char>(mRight->getCols()), static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400685 }
686 }
687 else if (mLeft->isMatrix() && !mRight->isMatrix())
688 {
689 if (mRight->isVector())
690 {
691 mOp = EOpMatrixTimesVector;
692 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700693 static_cast<unsigned char>(mLeft->getRows()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400694 }
695 else
696 {
697 mOp = EOpMatrixTimesScalar;
698 }
699 }
700 else if (mLeft->isMatrix() && mRight->isMatrix())
701 {
702 mOp = EOpMatrixTimesMatrix;
703 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700704 static_cast<unsigned char>(mRight->getCols()), static_cast<unsigned char>(mLeft->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400705 }
706 else if (!mLeft->isMatrix() && !mRight->isMatrix())
707 {
708 if (mLeft->isVector() && mRight->isVector())
709 {
710 // leave as component product
711 }
712 else if (mLeft->isVector() || mRight->isVector())
713 {
714 mOp = EOpVectorTimesScalar;
715 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700716 static_cast<unsigned char>(nominalSize), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400717 }
718 }
719 else
720 {
721 infoSink.info.message(EPrefixInternalError, getLine(),
722 "Missing elses");
723 return false;
724 }
725
726 if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType()))
727 {
728 return false;
729 }
730 break;
731
732 case EOpMulAssign:
733 if (!mLeft->isMatrix() && mRight->isMatrix())
734 {
735 if (mLeft->isVector())
736 {
737 mOp = EOpVectorTimesMatrixAssign;
738 }
739 else
740 {
741 return false;
742 }
743 }
744 else if (mLeft->isMatrix() && !mRight->isMatrix())
745 {
746 if (mRight->isVector())
747 {
748 return false;
749 }
750 else
751 {
752 mOp = EOpMatrixTimesScalarAssign;
753 }
754 }
755 else if (mLeft->isMatrix() && mRight->isMatrix())
756 {
757 mOp = EOpMatrixTimesMatrixAssign;
758 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700759 static_cast<unsigned char>(mRight->getCols()), static_cast<unsigned char>(mLeft->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400760 }
761 else if (!mLeft->isMatrix() && !mRight->isMatrix())
762 {
763 if (mLeft->isVector() && mRight->isVector())
764 {
765 // leave as component product
766 }
767 else if (mLeft->isVector() || mRight->isVector())
768 {
769 if (!mLeft->isVector())
770 return false;
771 mOp = EOpVectorTimesScalarAssign;
772 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700773 static_cast<unsigned char>(mLeft->getNominalSize()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400774 }
775 }
776 else
777 {
778 infoSink.info.message(EPrefixInternalError, getLine(),
779 "Missing elses");
780 return false;
781 }
782
783 if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType()))
784 {
785 return false;
786 }
787 break;
788
789 case EOpAssign:
790 case EOpInitialize:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200791 // No more additional checks are needed.
792 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
793 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
794 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400795 case EOpAdd:
796 case EOpSub:
797 case EOpDiv:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200798 case EOpIMod:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200799 case EOpBitShiftLeft:
800 case EOpBitShiftRight:
801 case EOpBitwiseAnd:
802 case EOpBitwiseXor:
803 case EOpBitwiseOr:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400804 case EOpAddAssign:
805 case EOpSubAssign:
806 case EOpDivAssign:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200807 case EOpIModAssign:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200808 case EOpBitShiftLeftAssign:
809 case EOpBitShiftRightAssign:
810 case EOpBitwiseAndAssign:
811 case EOpBitwiseXorAssign:
812 case EOpBitwiseOrAssign:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400813 if ((mLeft->isMatrix() && mRight->isVector()) ||
814 (mLeft->isVector() && mRight->isMatrix()))
815 {
816 return false;
817 }
818
819 // Are the sizes compatible?
820 if (mLeft->getNominalSize() != mRight->getNominalSize() ||
821 mLeft->getSecondarySize() != mRight->getSecondarySize())
822 {
Olli Etuaho6c850472014-12-02 16:23:17 +0200823 // If the nominal sizes of operands do not match:
824 // One of them must be a scalar.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400825 if (!mLeft->isScalar() && !mRight->isScalar())
826 return false;
827
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200828 // In the case of compound assignment other than multiply-assign,
829 // the right side needs to be a scalar. Otherwise a vector/matrix
830 // would be assigned to a scalar. A scalar can't be shifted by a
831 // vector either.
Olli Etuaho6c850472014-12-02 16:23:17 +0200832 if (!mRight->isScalar() &&
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200833 (isAssignment() ||
834 mOp == EOpBitShiftLeft ||
835 mOp == EOpBitShiftRight))
Olli Etuaho6c850472014-12-02 16:23:17 +0200836 return false;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400837 }
838
839 {
840 const int secondarySize = std::max(
841 mLeft->getSecondarySize(), mRight->getSecondarySize());
842 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700843 static_cast<unsigned char>(nominalSize), static_cast<unsigned char>(secondarySize)));
Olli Etuahoe79904c2015-03-18 16:56:42 +0200844 if (mLeft->isArray())
845 {
846 ASSERT(mLeft->getArraySize() == mRight->getArraySize());
847 mType.setArraySize(mLeft->getArraySize());
848 }
Jamie Madillb1a85f42014-08-19 15:23:24 -0400849 }
850 break;
851
852 case EOpEqual:
853 case EOpNotEqual:
854 case EOpLessThan:
855 case EOpGreaterThan:
856 case EOpLessThanEqual:
857 case EOpGreaterThanEqual:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200858 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
859 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400860 setType(TType(EbtBool, EbpUndefined));
861 break;
862
863 default:
864 return false;
865 }
866 return true;
867}
868
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300869TIntermTyped *TIntermBinary::fold(TInfoSink &infoSink)
870{
871 TIntermConstantUnion *leftConstant = mLeft->getAsConstantUnion();
872 TIntermConstantUnion *rightConstant = mRight->getAsConstantUnion();
873 if (leftConstant == nullptr || rightConstant == nullptr)
874 {
875 return nullptr;
876 }
877 TConstantUnion *constArray = leftConstant->foldBinary(mOp, rightConstant, infoSink);
Olli Etuahob43846e2015-06-02 18:18:57 +0300878 return CreateFoldedNode(constArray, this);
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300879}
880
Olli Etuaho95310b02015-06-02 17:43:38 +0300881TIntermTyped *TIntermUnary::fold(TInfoSink &infoSink)
882{
883 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
884 if (operandConstant == nullptr)
885 {
886 return nullptr;
887 }
Arun Patoleab2b9a22015-07-06 18:27:56 +0530888
889 TConstantUnion *constArray = nullptr;
890 switch (mOp)
891 {
892 case EOpAny:
893 case EOpAll:
894 case EOpLength:
895 case EOpTranspose:
896 case EOpDeterminant:
897 case EOpInverse:
898 case EOpPackSnorm2x16:
899 case EOpUnpackSnorm2x16:
900 case EOpPackUnorm2x16:
901 case EOpUnpackUnorm2x16:
902 case EOpPackHalf2x16:
903 case EOpUnpackHalf2x16:
904 constArray = operandConstant->foldUnaryWithDifferentReturnType(mOp, infoSink);
905 break;
906 default:
907 constArray = operandConstant->foldUnaryWithSameReturnType(mOp, infoSink);
908 break;
909 }
Olli Etuahob43846e2015-06-02 18:18:57 +0300910 return CreateFoldedNode(constArray, this);
911}
912
913TIntermTyped *TIntermAggregate::fold(TInfoSink &infoSink)
914{
915 // Make sure that all params are constant before actual constant folding.
916 for (auto *param : *getSequence())
Olli Etuaho95310b02015-06-02 17:43:38 +0300917 {
Olli Etuahob43846e2015-06-02 18:18:57 +0300918 if (param->getAsConstantUnion() == nullptr)
919 {
920 return nullptr;
921 }
Olli Etuaho95310b02015-06-02 17:43:38 +0300922 }
Olli Etuahob43846e2015-06-02 18:18:57 +0300923 TConstantUnion *constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, infoSink);
924 return CreateFoldedNode(constArray, this);
Olli Etuaho95310b02015-06-02 17:43:38 +0300925}
926
Jamie Madillb1a85f42014-08-19 15:23:24 -0400927//
928// The fold functions see if an operation on a constant can be done in place,
929// without generating run-time code.
930//
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300931// Returns the constant value to keep using or nullptr.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400932//
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300933TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op, TIntermConstantUnion *rightNode, TInfoSink &infoSink)
934{
935 TConstantUnion *leftArray = getUnionArrayPointer();
936 TConstantUnion *rightArray = rightNode->getUnionArrayPointer();
937
938 if (!leftArray)
939 return nullptr;
940 if (!rightArray)
941 return nullptr;
942
943 size_t objectSize = getType().getObjectSize();
944
945 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
946 if (rightNode->getType().getObjectSize() == 1 && objectSize > 1)
947 {
948 rightArray = Vectorize(*rightNode->getUnionArrayPointer(), objectSize);
949 }
950 else if (rightNode->getType().getObjectSize() > 1 && objectSize == 1)
951 {
952 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
953 leftArray = Vectorize(*getUnionArrayPointer(), rightNode->getType().getObjectSize());
954 objectSize = rightNode->getType().getObjectSize();
955 }
956
957 TConstantUnion *resultArray = nullptr;
958
959 switch(op)
960 {
961 case EOpAdd:
962 resultArray = new TConstantUnion[objectSize];
963 for (size_t i = 0; i < objectSize; i++)
964 resultArray[i] = leftArray[i] + rightArray[i];
965 break;
966 case EOpSub:
967 resultArray = new TConstantUnion[objectSize];
968 for (size_t i = 0; i < objectSize; i++)
969 resultArray[i] = leftArray[i] - rightArray[i];
970 break;
971
972 case EOpMul:
973 case EOpVectorTimesScalar:
974 case EOpMatrixTimesScalar:
975 resultArray = new TConstantUnion[objectSize];
976 for (size_t i = 0; i < objectSize; i++)
977 resultArray[i] = leftArray[i] * rightArray[i];
978 break;
979
980 case EOpMatrixTimesMatrix:
981 {
982 if (getType().getBasicType() != EbtFloat ||
983 rightNode->getBasicType() != EbtFloat)
984 {
985 infoSink.info.message(
986 EPrefixInternalError, getLine(),
987 "Constant Folding cannot be done for matrix multiply");
988 return nullptr;
989 }
990
991 const int leftCols = getCols();
992 const int leftRows = getRows();
993 const int rightCols = rightNode->getType().getCols();
994 const int rightRows = rightNode->getType().getRows();
995 const int resultCols = rightCols;
996 const int resultRows = leftRows;
997
998 resultArray = new TConstantUnion[resultCols * resultRows];
999 for (int row = 0; row < resultRows; row++)
1000 {
1001 for (int column = 0; column < resultCols; column++)
1002 {
1003 resultArray[resultRows * column + row].setFConst(0.0f);
1004 for (int i = 0; i < leftCols; i++)
1005 {
1006 resultArray[resultRows * column + row].setFConst(
1007 resultArray[resultRows * column + row].getFConst() +
1008 leftArray[i * leftRows + row].getFConst() *
1009 rightArray[column * rightRows + i].getFConst());
1010 }
1011 }
1012 }
1013 }
1014 break;
1015
1016 case EOpDiv:
1017 case EOpIMod:
1018 {
1019 resultArray = new TConstantUnion[objectSize];
1020 for (size_t i = 0; i < objectSize; i++)
1021 {
1022 switch (getType().getBasicType())
1023 {
1024 case EbtFloat:
1025 if (rightArray[i] == 0.0f)
1026 {
1027 infoSink.info.message(EPrefixWarning, getLine(),
1028 "Divide by zero error during constant folding");
1029 resultArray[i].setFConst(leftArray[i].getFConst() < 0 ? -FLT_MAX : FLT_MAX);
1030 }
1031 else
1032 {
1033 ASSERT(op == EOpDiv);
1034 resultArray[i].setFConst(leftArray[i].getFConst() / rightArray[i].getFConst());
1035 }
1036 break;
1037
1038 case EbtInt:
1039 if (rightArray[i] == 0)
1040 {
1041 infoSink.info.message(EPrefixWarning, getLine(),
1042 "Divide by zero error during constant folding");
1043 resultArray[i].setIConst(INT_MAX);
1044 }
1045 else
1046 {
1047 if (op == EOpDiv)
1048 {
1049 resultArray[i].setIConst(leftArray[i].getIConst() / rightArray[i].getIConst());
1050 }
1051 else
1052 {
1053 ASSERT(op == EOpIMod);
1054 resultArray[i].setIConst(leftArray[i].getIConst() % rightArray[i].getIConst());
1055 }
1056 }
1057 break;
1058
1059 case EbtUInt:
1060 if (rightArray[i] == 0)
1061 {
1062 infoSink.info.message(EPrefixWarning, getLine(),
1063 "Divide by zero error during constant folding");
1064 resultArray[i].setUConst(UINT_MAX);
1065 }
1066 else
1067 {
1068 if (op == EOpDiv)
1069 {
1070 resultArray[i].setUConst(leftArray[i].getUConst() / rightArray[i].getUConst());
1071 }
1072 else
1073 {
1074 ASSERT(op == EOpIMod);
1075 resultArray[i].setUConst(leftArray[i].getUConst() % rightArray[i].getUConst());
1076 }
1077 }
1078 break;
1079
1080 default:
1081 infoSink.info.message(EPrefixInternalError, getLine(),
1082 "Constant folding cannot be done for \"/\"");
1083 return nullptr;
1084 }
1085 }
1086 }
1087 break;
1088
1089 case EOpMatrixTimesVector:
1090 {
1091 if (rightNode->getBasicType() != EbtFloat)
1092 {
1093 infoSink.info.message(EPrefixInternalError, getLine(),
1094 "Constant Folding cannot be done for matrix times vector");
1095 return nullptr;
1096 }
1097
1098 const int matrixCols = getCols();
1099 const int matrixRows = getRows();
1100
1101 resultArray = new TConstantUnion[matrixRows];
1102
1103 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1104 {
1105 resultArray[matrixRow].setFConst(0.0f);
1106 for (int col = 0; col < matrixCols; col++)
1107 {
1108 resultArray[matrixRow].setFConst(resultArray[matrixRow].getFConst() +
1109 leftArray[col * matrixRows + matrixRow].getFConst() *
1110 rightArray[col].getFConst());
1111 }
1112 }
1113 }
1114 break;
1115
1116 case EOpVectorTimesMatrix:
1117 {
1118 if (getType().getBasicType() != EbtFloat)
1119 {
1120 infoSink.info.message(EPrefixInternalError, getLine(),
1121 "Constant Folding cannot be done for vector times matrix");
1122 return nullptr;
1123 }
1124
1125 const int matrixCols = rightNode->getType().getCols();
1126 const int matrixRows = rightNode->getType().getRows();
1127
1128 resultArray = new TConstantUnion[matrixCols];
1129
1130 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
1131 {
1132 resultArray[matrixCol].setFConst(0.0f);
1133 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1134 {
1135 resultArray[matrixCol].setFConst(resultArray[matrixCol].getFConst() +
1136 leftArray[matrixRow].getFConst() *
1137 rightArray[matrixCol * matrixRows + matrixRow].getFConst());
1138 }
1139 }
1140 }
1141 break;
1142
1143 case EOpLogicalAnd:
1144 {
1145 resultArray = new TConstantUnion[objectSize];
1146 for (size_t i = 0; i < objectSize; i++)
1147 {
1148 resultArray[i] = leftArray[i] && rightArray[i];
1149 }
1150 }
1151 break;
1152
1153 case EOpLogicalOr:
1154 {
1155 resultArray = new TConstantUnion[objectSize];
1156 for (size_t i = 0; i < objectSize; i++)
1157 {
1158 resultArray[i] = leftArray[i] || rightArray[i];
1159 }
1160 }
1161 break;
1162
1163 case EOpLogicalXor:
1164 {
1165 resultArray = new TConstantUnion[objectSize];
1166 for (size_t i = 0; i < objectSize; i++)
1167 {
1168 switch (getType().getBasicType())
1169 {
1170 case EbtBool:
1171 resultArray[i].setBConst(leftArray[i] != rightArray[i]);
1172 break;
1173 default:
1174 UNREACHABLE();
1175 break;
1176 }
1177 }
1178 }
1179 break;
1180
1181 case EOpBitwiseAnd:
1182 resultArray = new TConstantUnion[objectSize];
1183 for (size_t i = 0; i < objectSize; i++)
1184 resultArray[i] = leftArray[i] & rightArray[i];
1185 break;
1186 case EOpBitwiseXor:
1187 resultArray = new TConstantUnion[objectSize];
1188 for (size_t i = 0; i < objectSize; i++)
1189 resultArray[i] = leftArray[i] ^ rightArray[i];
1190 break;
1191 case EOpBitwiseOr:
1192 resultArray = new TConstantUnion[objectSize];
1193 for (size_t i = 0; i < objectSize; i++)
1194 resultArray[i] = leftArray[i] | rightArray[i];
1195 break;
1196 case EOpBitShiftLeft:
1197 resultArray = new TConstantUnion[objectSize];
1198 for (size_t i = 0; i < objectSize; i++)
1199 resultArray[i] = leftArray[i] << rightArray[i];
1200 break;
1201 case EOpBitShiftRight:
1202 resultArray = new TConstantUnion[objectSize];
1203 for (size_t i = 0; i < objectSize; i++)
1204 resultArray[i] = leftArray[i] >> rightArray[i];
1205 break;
1206
1207 case EOpLessThan:
1208 ASSERT(objectSize == 1);
1209 resultArray = new TConstantUnion[1];
1210 resultArray->setBConst(*leftArray < *rightArray);
1211 break;
1212
1213 case EOpGreaterThan:
1214 ASSERT(objectSize == 1);
1215 resultArray = new TConstantUnion[1];
1216 resultArray->setBConst(*leftArray > *rightArray);
1217 break;
1218
1219 case EOpLessThanEqual:
1220 ASSERT(objectSize == 1);
1221 resultArray = new TConstantUnion[1];
1222 resultArray->setBConst(!(*leftArray > *rightArray));
1223 break;
1224
1225 case EOpGreaterThanEqual:
1226 ASSERT(objectSize == 1);
1227 resultArray = new TConstantUnion[1];
1228 resultArray->setBConst(!(*leftArray < *rightArray));
1229 break;
1230
1231 case EOpEqual:
1232 case EOpNotEqual:
1233 {
1234 resultArray = new TConstantUnion[1];
1235 bool equal = true;
1236 if (getType().getBasicType() == EbtStruct)
1237 {
1238 equal = CompareStructure(getType(), rightArray, leftArray);
1239 }
1240 else
1241 {
1242 for (size_t i = 0; i < objectSize; i++)
1243 {
1244 if (leftArray[i] != rightArray[i])
1245 {
1246 equal = false;
1247 break; // break out of for loop
1248 }
1249 }
1250 }
1251 if (op == EOpEqual)
1252 {
1253 resultArray->setBConst(equal);
1254 }
1255 else
1256 {
1257 resultArray->setBConst(!equal);
1258 }
1259 }
1260 break;
1261
1262 default:
1263 infoSink.info.message(
1264 EPrefixInternalError, getLine(),
1265 "Invalid operator for constant folding");
1266 return nullptr;
1267 }
1268 return resultArray;
1269}
1270
1271//
1272// The fold functions see if an operation on a constant can be done in place,
1273// without generating run-time code.
1274//
Olli Etuaho95310b02015-06-02 17:43:38 +03001275// Returns the constant value to keep using or nullptr.
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001276//
Arun Patoleab2b9a22015-07-06 18:27:56 +05301277TConstantUnion *TIntermConstantUnion::foldUnaryWithDifferentReturnType(TOperator op, TInfoSink &infoSink)
Jamie Madillb1a85f42014-08-19 15:23:24 -04001278{
Arun Patoleab2b9a22015-07-06 18:27:56 +05301279 //
1280 // Do operations where the return type has a different number of components compared to the operand type.
1281 //
Jamie Madillb1a85f42014-08-19 15:23:24 -04001282
Arun Patoleab2b9a22015-07-06 18:27:56 +05301283 TConstantUnion *operandArray = getUnionArrayPointer();
1284 if (!operandArray)
1285 return nullptr;
1286
1287 size_t objectSize = getType().getObjectSize();
1288 TConstantUnion *resultArray = nullptr;
1289 switch (op)
1290 {
1291 case EOpAny:
1292 if (getType().getBasicType() == EbtBool)
1293 {
1294 resultArray = new TConstantUnion();
1295 resultArray->setBConst(false);
1296 for (size_t i = 0; i < objectSize; i++)
1297 {
1298 if (operandArray[i].getBConst())
1299 {
1300 resultArray->setBConst(true);
1301 break;
1302 }
1303 }
1304 break;
1305 }
1306 else
1307 {
1308 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1309 return nullptr;
1310 }
1311
1312 case EOpAll:
1313 if (getType().getBasicType() == EbtBool)
1314 {
1315 resultArray = new TConstantUnion();
1316 resultArray->setBConst(true);
1317 for (size_t i = 0; i < objectSize; i++)
1318 {
1319 if (!operandArray[i].getBConst())
1320 {
1321 resultArray->setBConst(false);
1322 break;
1323 }
1324 }
1325 break;
1326 }
1327 else
1328 {
1329 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1330 return nullptr;
1331 }
1332
1333 case EOpLength:
1334 if (getType().getBasicType() == EbtFloat)
1335 {
1336 resultArray = new TConstantUnion();
1337 resultArray->setFConst(VectorLength(operandArray, objectSize));
1338 break;
1339 }
1340 else
1341 {
1342 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1343 return nullptr;
1344 }
1345
1346 case EOpTranspose:
1347 if (getType().getBasicType() == EbtFloat)
1348 {
1349 resultArray = new TConstantUnion[objectSize];
1350 angle::Matrix<float> result =
1351 GetMatrix(operandArray, getType().getNominalSize(), getType().getSecondarySize()).transpose();
1352 SetUnionArrayFromMatrix(result, resultArray);
1353 break;
1354 }
1355 else
1356 {
1357 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1358 return nullptr;
1359 }
1360
1361 case EOpDeterminant:
1362 if (getType().getBasicType() == EbtFloat)
1363 {
1364 unsigned int size = getType().getNominalSize();
1365 ASSERT(size >= 2 && size <= 4);
1366 resultArray = new TConstantUnion();
1367 resultArray->setFConst(GetMatrix(operandArray, size).determinant());
1368 break;
1369 }
1370 else
1371 {
1372 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1373 return nullptr;
1374 }
1375
1376 case EOpInverse:
1377 if (getType().getBasicType() == EbtFloat)
1378 {
1379 unsigned int size = getType().getNominalSize();
1380 ASSERT(size >= 2 && size <= 4);
1381 resultArray = new TConstantUnion[objectSize];
1382 angle::Matrix<float> result = GetMatrix(operandArray, size).inverse();
1383 SetUnionArrayFromMatrix(result, resultArray);
1384 break;
1385 }
1386 else
1387 {
1388 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1389 return nullptr;
1390 }
1391
1392 case EOpPackSnorm2x16:
1393 if (getType().getBasicType() == EbtFloat)
1394 {
1395 ASSERT(getType().getNominalSize() == 2);
1396 resultArray = new TConstantUnion();
1397 resultArray->setUConst(gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
1398 break;
1399 }
1400 else
1401 {
1402 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1403 return nullptr;
1404 }
1405
1406 case EOpUnpackSnorm2x16:
1407 if (getType().getBasicType() == EbtUInt)
1408 {
1409 resultArray = new TConstantUnion[2];
1410 float f1, f2;
1411 gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1412 resultArray[0].setFConst(f1);
1413 resultArray[1].setFConst(f2);
1414 break;
1415 }
1416 else
1417 {
1418 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1419 return nullptr;
1420 }
1421
1422 case EOpPackUnorm2x16:
1423 if (getType().getBasicType() == EbtFloat)
1424 {
1425 ASSERT(getType().getNominalSize() == 2);
1426 resultArray = new TConstantUnion();
1427 resultArray->setUConst(gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
1428 break;
1429 }
1430 else
1431 {
1432 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1433 return nullptr;
1434 }
1435
1436 case EOpUnpackUnorm2x16:
1437 if (getType().getBasicType() == EbtUInt)
1438 {
1439 resultArray = new TConstantUnion[2];
1440 float f1, f2;
1441 gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1442 resultArray[0].setFConst(f1);
1443 resultArray[1].setFConst(f2);
1444 break;
1445 }
1446 else
1447 {
1448 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1449 return nullptr;
1450 }
1451
1452 case EOpPackHalf2x16:
1453 if (getType().getBasicType() == EbtFloat)
1454 {
1455 ASSERT(getType().getNominalSize() == 2);
1456 resultArray = new TConstantUnion();
1457 resultArray->setUConst(gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
1458 break;
1459 }
1460 else
1461 {
1462 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1463 return nullptr;
1464 }
1465
1466 case EOpUnpackHalf2x16:
1467 if (getType().getBasicType() == EbtUInt)
1468 {
1469 resultArray = new TConstantUnion[2];
1470 float f1, f2;
1471 gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2);
1472 resultArray[0].setFConst(f1);
1473 resultArray[1].setFConst(f2);
1474 break;
1475 }
1476 else
1477 {
1478 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1479 return nullptr;
1480 }
1481 break;
1482
1483 default:
1484 break;
1485 }
1486
1487 return resultArray;
1488}
1489
1490TConstantUnion *TIntermConstantUnion::foldUnaryWithSameReturnType(TOperator op, TInfoSink &infoSink)
1491{
1492 //
1493 // Do unary operations where the return type is the same as operand type.
1494 //
1495
1496 TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuaho95310b02015-06-02 17:43:38 +03001497 if (!operandArray)
Arun Patolefddc2112015-04-22 13:28:10 +05301498 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001499
1500 size_t objectSize = getType().getObjectSize();
1501
Arun Patoleab2b9a22015-07-06 18:27:56 +05301502 TConstantUnion *resultArray = new TConstantUnion[objectSize];
1503 for (size_t i = 0; i < objectSize; i++)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301504 {
Arun Patoleab2b9a22015-07-06 18:27:56 +05301505 switch(op)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301506 {
Arun Patoleab2b9a22015-07-06 18:27:56 +05301507 case EOpNegative:
1508 switch (getType().getBasicType())
Arun Patole9d0b1f92015-05-20 14:27:17 +05301509 {
Arun Patoleab2b9a22015-07-06 18:27:56 +05301510 case EbtFloat:
1511 resultArray[i].setFConst(-operandArray[i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05301512 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301513 case EbtInt:
1514 resultArray[i].setIConst(-operandArray[i].getIConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05301515 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301516 case EbtUInt:
1517 resultArray[i].setUConst(static_cast<unsigned int>(
1518 -static_cast<int>(operandArray[i].getUConst())));
Arun Patole1155ddd2015-06-05 18:04:36 +05301519 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301520 default:
1521 infoSink.info.message(
1522 EPrefixInternalError, getLine(),
1523 "Unary operation not folded into constant");
Arun Patolecdfa8f52015-06-30 17:48:25 +05301524 return nullptr;
1525 }
1526 break;
1527
Arun Patoleab2b9a22015-07-06 18:27:56 +05301528 case EOpPositive:
1529 switch (getType().getBasicType())
1530 {
1531 case EbtFloat:
1532 resultArray[i].setFConst(operandArray[i].getFConst());
1533 break;
1534 case EbtInt:
1535 resultArray[i].setIConst(operandArray[i].getIConst());
1536 break;
1537 case EbtUInt:
1538 resultArray[i].setUConst(static_cast<unsigned int>(
1539 static_cast<int>(operandArray[i].getUConst())));
1540 break;
1541 default:
1542 infoSink.info.message(
1543 EPrefixInternalError, getLine(),
1544 "Unary operation not folded into constant");
1545 return nullptr;
1546 }
1547 break;
1548
1549 case EOpLogicalNot:
1550 // this code is written for possible future use,
1551 // will not get executed currently
1552 switch (getType().getBasicType())
1553 {
1554 case EbtBool:
1555 resultArray[i].setBConst(!operandArray[i].getBConst());
1556 break;
1557 default:
1558 infoSink.info.message(
1559 EPrefixInternalError, getLine(),
1560 "Unary operation not folded into constant");
1561 return nullptr;
1562 }
1563 break;
1564
1565 case EOpBitwiseNot:
1566 switch (getType().getBasicType())
1567 {
1568 case EbtInt:
1569 resultArray[i].setIConst(~operandArray[i].getIConst());
1570 break;
1571 case EbtUInt:
1572 resultArray[i].setUConst(~operandArray[i].getUConst());
1573 break;
1574 default:
1575 infoSink.info.message(
1576 EPrefixInternalError, getLine(),
1577 "Unary operation not folded into constant");
1578 return nullptr;
1579 }
1580 break;
1581
1582 case EOpRadians:
1583 if (getType().getBasicType() == EbtFloat)
1584 {
1585 resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
1586 break;
1587 }
1588 infoSink.info.message(
1589 EPrefixInternalError, getLine(),
1590 "Unary operation not folded into constant");
1591 return nullptr;
1592
1593 case EOpDegrees:
1594 if (getType().getBasicType() == EbtFloat)
1595 {
1596 resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
1597 break;
1598 }
1599 infoSink.info.message(
1600 EPrefixInternalError, getLine(),
1601 "Unary operation not folded into constant");
1602 return nullptr;
1603
1604 case EOpSin:
1605 if (!foldFloatTypeUnary(operandArray[i], &sinf, infoSink, &resultArray[i]))
1606 return nullptr;
1607 break;
1608
1609 case EOpCos:
1610 if (!foldFloatTypeUnary(operandArray[i], &cosf, infoSink, &resultArray[i]))
1611 return nullptr;
1612 break;
1613
1614 case EOpTan:
1615 if (!foldFloatTypeUnary(operandArray[i], &tanf, infoSink, &resultArray[i]))
1616 return nullptr;
1617 break;
1618
1619 case EOpAsin:
1620 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to 0.
1621 if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) > 1.0f)
1622 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1623 else if (!foldFloatTypeUnary(operandArray[i], &asinf, infoSink, &resultArray[i]))
1624 return nullptr;
1625 break;
1626
1627 case EOpAcos:
1628 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to 0.
1629 if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) > 1.0f)
1630 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1631 else if (!foldFloatTypeUnary(operandArray[i], &acosf, infoSink, &resultArray[i]))
1632 return nullptr;
1633 break;
1634
1635 case EOpAtan:
1636 if (!foldFloatTypeUnary(operandArray[i], &atanf, infoSink, &resultArray[i]))
1637 return nullptr;
1638 break;
1639
1640 case EOpSinh:
1641 if (!foldFloatTypeUnary(operandArray[i], &sinhf, infoSink, &resultArray[i]))
1642 return nullptr;
1643 break;
1644
1645 case EOpCosh:
1646 if (!foldFloatTypeUnary(operandArray[i], &coshf, infoSink, &resultArray[i]))
1647 return nullptr;
1648 break;
1649
1650 case EOpTanh:
1651 if (!foldFloatTypeUnary(operandArray[i], &tanhf, infoSink, &resultArray[i]))
1652 return nullptr;
1653 break;
1654
1655 case EOpAsinh:
1656 if (!foldFloatTypeUnary(operandArray[i], &asinhf, infoSink, &resultArray[i]))
1657 return nullptr;
1658 break;
1659
1660 case EOpAcosh:
1661 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
1662 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() < 1.0f)
1663 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1664 else if (!foldFloatTypeUnary(operandArray[i], &acoshf, infoSink, &resultArray[i]))
1665 return nullptr;
1666 break;
1667
1668 case EOpAtanh:
1669 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to 0.
1670 if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) >= 1.0f)
1671 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1672 else if (!foldFloatTypeUnary(operandArray[i], &atanhf, infoSink, &resultArray[i]))
1673 return nullptr;
1674 break;
1675
1676 case EOpAbs:
1677 switch (getType().getBasicType())
1678 {
1679 case EbtFloat:
1680 resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
1681 break;
1682 case EbtInt:
1683 resultArray[i].setIConst(abs(operandArray[i].getIConst()));
1684 break;
1685 default:
1686 infoSink.info.message(
1687 EPrefixInternalError, getLine(),
1688 "Unary operation not folded into constant");
1689 return nullptr;
1690 }
1691 break;
1692
1693 case EOpSign:
1694 switch (getType().getBasicType())
1695 {
1696 case EbtFloat:
1697 {
1698 float fConst = operandArray[i].getFConst();
1699 float fResult = 0.0f;
1700 if (fConst > 0.0f)
1701 fResult = 1.0f;
1702 else if (fConst < 0.0f)
1703 fResult = -1.0f;
1704 resultArray[i].setFConst(fResult);
1705 }
1706 break;
1707 case EbtInt:
1708 {
1709 int iConst = operandArray[i].getIConst();
1710 int iResult = 0;
1711 if (iConst > 0)
1712 iResult = 1;
1713 else if (iConst < 0)
1714 iResult = -1;
1715 resultArray[i].setIConst(iResult);
1716 }
1717 break;
1718 default:
1719 infoSink.info.message(
1720 EPrefixInternalError, getLine(),
1721 "Unary operation not folded into constant");
1722 return nullptr;
1723 }
1724 break;
1725
1726 case EOpFloor:
1727 if (!foldFloatTypeUnary(operandArray[i], &floorf, infoSink, &resultArray[i]))
1728 return nullptr;
1729 break;
1730
1731 case EOpTrunc:
1732 if (!foldFloatTypeUnary(operandArray[i], &truncf, infoSink, &resultArray[i]))
1733 return nullptr;
1734 break;
1735
1736 case EOpRound:
1737 if (!foldFloatTypeUnary(operandArray[i], &roundf, infoSink, &resultArray[i]))
1738 return nullptr;
1739 break;
1740
1741 case EOpRoundEven:
1742 if (getType().getBasicType() == EbtFloat)
1743 {
1744 float x = operandArray[i].getFConst();
1745 float result;
1746 float fractPart = modff(x, &result);
1747 if (fabsf(fractPart) == 0.5f)
1748 result = 2.0f * roundf(x / 2.0f);
1749 else
1750 result = roundf(x);
1751 resultArray[i].setFConst(result);
1752 break;
1753 }
1754 infoSink.info.message(
1755 EPrefixInternalError, getLine(),
1756 "Unary operation not folded into constant");
1757 return nullptr;
1758
1759 case EOpCeil:
1760 if (!foldFloatTypeUnary(operandArray[i], &ceilf, infoSink, &resultArray[i]))
1761 return nullptr;
1762 break;
1763
1764 case EOpFract:
1765 if (getType().getBasicType() == EbtFloat)
1766 {
1767 float x = operandArray[i].getFConst();
1768 resultArray[i].setFConst(x - floorf(x));
1769 break;
1770 }
1771 infoSink.info.message(
1772 EPrefixInternalError, getLine(),
1773 "Unary operation not folded into constant");
1774 return nullptr;
1775
Arun Patole551279e2015-07-07 18:18:23 +05301776 case EOpIsNan:
1777 if (getType().getBasicType() == EbtFloat)
1778 {
1779 resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst()));
1780 break;
1781 }
1782 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1783 return nullptr;
1784
1785 case EOpIsInf:
1786 if (getType().getBasicType() == EbtFloat)
1787 {
1788 resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst()));
1789 break;
1790 }
1791 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1792 return nullptr;
1793
1794 case EOpFloatBitsToInt:
1795 if (getType().getBasicType() == EbtFloat)
1796 {
1797 resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst()));
1798 break;
1799 }
1800 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1801 return nullptr;
1802
1803 case EOpFloatBitsToUint:
1804 if (getType().getBasicType() == EbtFloat)
1805 {
1806 resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst()));
1807 break;
1808 }
1809 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1810 return nullptr;
1811
1812 case EOpIntBitsToFloat:
1813 if (getType().getBasicType() == EbtInt)
1814 {
1815 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst()));
1816 break;
1817 }
1818 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1819 return nullptr;
1820
1821 case EOpUintBitsToFloat:
1822 if (getType().getBasicType() == EbtUInt)
1823 {
1824 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst()));
1825 break;
1826 }
1827 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1828 return nullptr;
1829
Arun Patoleab2b9a22015-07-06 18:27:56 +05301830 case EOpExp:
1831 if (!foldFloatTypeUnary(operandArray[i], &expf, infoSink, &resultArray[i]))
1832 return nullptr;
1833 break;
1834
1835 case EOpLog:
1836 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
1837 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
1838 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1839 else if (!foldFloatTypeUnary(operandArray[i], &logf, infoSink, &resultArray[i]))
1840 return nullptr;
1841 break;
1842
1843 case EOpExp2:
1844 if (!foldFloatTypeUnary(operandArray[i], &exp2f, infoSink, &resultArray[i]))
1845 return nullptr;
1846 break;
1847
1848 case EOpLog2:
1849 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
1850 // And log2f is not available on some plarforms like old android, so just using log(x)/log(2) here.
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], &logf, infoSink, &resultArray[i]))
1854 return nullptr;
1855 else
1856 resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
1857 break;
1858
1859 case EOpSqrt:
1860 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
1861 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() < 0.0f)
1862 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1863 else if (!foldFloatTypeUnary(operandArray[i], &sqrtf, infoSink, &resultArray[i]))
1864 return nullptr;
1865 break;
1866
1867 case EOpInverseSqrt:
1868 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
1869 // so getting the square root first using builtin function sqrt() and then taking its inverse.
1870 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set result to 0.
1871 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
1872 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1873 else if (!foldFloatTypeUnary(operandArray[i], &sqrtf, infoSink, &resultArray[i]))
1874 return nullptr;
1875 else
1876 resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
1877 break;
1878
1879 case EOpVectorLogicalNot:
1880 if (getType().getBasicType() == EbtBool)
1881 {
1882 resultArray[i].setBConst(!operandArray[i].getBConst());
1883 break;
1884 }
1885 infoSink.info.message(
1886 EPrefixInternalError, getLine(),
1887 "Unary operation not folded into constant");
1888 return nullptr;
1889
1890 case EOpNormalize:
1891 if (getType().getBasicType() == EbtFloat)
1892 {
1893 float x = operandArray[i].getFConst();
1894 float length = VectorLength(operandArray, objectSize);
1895 if (length)
1896 resultArray[i].setFConst(x / length);
1897 else
1898 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink,
1899 &resultArray[i]);
1900 break;
1901 }
1902 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1903 return nullptr;
1904
Arun Patole0c5409f2015-07-08 15:17:53 +05301905 case EOpDFdx:
1906 case EOpDFdy:
1907 case EOpFwidth:
1908 if (getType().getBasicType() == EbtFloat)
1909 {
1910 // Derivatives of constant arguments should be 0.
1911 resultArray[i].setFConst(0.0f);
1912 break;
1913 }
1914 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1915 return nullptr;
1916
Arun Patole1155ddd2015-06-05 18:04:36 +05301917 default:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301918 return nullptr;
Arun Patole9d0b1f92015-05-20 14:27:17 +05301919 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05301920 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04001921
Arun Patoleab2b9a22015-07-06 18:27:56 +05301922 return resultArray;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001923}
1924
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001925bool TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter, FloatTypeUnaryFunc builtinFunc,
1926 TInfoSink &infoSink, TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05301927{
1928 ASSERT(builtinFunc);
1929
1930 if (getType().getBasicType() == EbtFloat)
1931 {
1932 result->setFConst(builtinFunc(parameter.getFConst()));
1933 return true;
1934 }
1935
1936 infoSink.info.message(
1937 EPrefixInternalError, getLine(),
1938 "Unary operation not folded into constant");
1939 return false;
1940}
1941
Jamie Madillb1a85f42014-08-19 15:23:24 -04001942// static
Olli Etuahob43846e2015-06-02 18:18:57 +03001943TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate, TInfoSink &infoSink)
Arun Patole274f0702015-05-05 13:33:30 +05301944{
Olli Etuahob43846e2015-06-02 18:18:57 +03001945 TOperator op = aggregate->getOp();
Arun Patole274f0702015-05-05 13:33:30 +05301946 TIntermSequence *sequence = aggregate->getSequence();
Cooper Partin4d61f7e2015-08-12 10:56:50 -07001947 unsigned int paramsCount = static_cast<unsigned int>(sequence->size());
Arun Patole274f0702015-05-05 13:33:30 +05301948 std::vector<TConstantUnion *> unionArrays(paramsCount);
1949 std::vector<size_t> objectSizes(paramsCount);
Olli Etuahob43846e2015-06-02 18:18:57 +03001950 size_t maxObjectSize = 0;
Arun Patole274f0702015-05-05 13:33:30 +05301951 TBasicType basicType = EbtVoid;
1952 TSourceLoc loc;
1953 for (unsigned int i = 0; i < paramsCount; i++)
1954 {
1955 TIntermConstantUnion *paramConstant = (*sequence)[i]->getAsConstantUnion();
Olli Etuahob43846e2015-06-02 18:18:57 +03001956 ASSERT(paramConstant != nullptr); // Should be checked already.
Arun Patole274f0702015-05-05 13:33:30 +05301957
1958 if (i == 0)
1959 {
1960 basicType = paramConstant->getType().getBasicType();
1961 loc = paramConstant->getLine();
1962 }
1963 unionArrays[i] = paramConstant->getUnionArrayPointer();
1964 objectSizes[i] = paramConstant->getType().getObjectSize();
Olli Etuahob43846e2015-06-02 18:18:57 +03001965 if (objectSizes[i] > maxObjectSize)
1966 maxObjectSize = objectSizes[i];
Arun Patole274f0702015-05-05 13:33:30 +05301967 }
1968
Arun Patole7fa33552015-06-10 15:15:18 +05301969 if (!(*sequence)[0]->getAsTyped()->isMatrix())
1970 {
1971 for (unsigned int i = 0; i < paramsCount; i++)
1972 if (objectSizes[i] != maxObjectSize)
1973 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
1974 }
Arun Patole274f0702015-05-05 13:33:30 +05301975
Olli Etuahob43846e2015-06-02 18:18:57 +03001976 TConstantUnion *resultArray = nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05301977 if (paramsCount == 2)
1978 {
1979 //
1980 // Binary built-in
1981 //
1982 switch (op)
1983 {
Arun Patolebf790422015-05-18 17:53:04 +05301984 case EOpAtan:
1985 {
1986 if (basicType == EbtFloat)
1987 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001988 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05301989 for (size_t i = 0; i < maxObjectSize; i++)
1990 {
1991 float y = unionArrays[0][i].getFConst();
1992 float x = unionArrays[1][i].getFConst();
1993 // Results are undefined if x and y are both 0.
1994 if (x == 0.0f && y == 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03001995 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05301996 else
Olli Etuahob43846e2015-06-02 18:18:57 +03001997 resultArray[i].setFConst(atan2f(y, x));
Arun Patolebf790422015-05-18 17:53:04 +05301998 }
1999 }
2000 else
2001 UNREACHABLE();
2002 }
2003 break;
2004
2005 case EOpPow:
2006 {
2007 if (basicType == EbtFloat)
2008 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002009 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302010 for (size_t i = 0; i < maxObjectSize; i++)
2011 {
2012 float x = unionArrays[0][i].getFConst();
2013 float y = unionArrays[1][i].getFConst();
2014 // Results are undefined if x < 0.
2015 // Results are undefined if x = 0 and y <= 0.
2016 if (x < 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03002017 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05302018 else if (x == 0.0f && y <= 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03002019 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05302020 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002021 resultArray[i].setFConst(powf(x, y));
Arun Patolebf790422015-05-18 17:53:04 +05302022 }
2023 }
2024 else
2025 UNREACHABLE();
2026 }
2027 break;
2028
2029 case EOpMod:
2030 {
2031 if (basicType == EbtFloat)
2032 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002033 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302034 for (size_t i = 0; i < maxObjectSize; i++)
2035 {
2036 float x = unionArrays[0][i].getFConst();
2037 float y = unionArrays[1][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002038 resultArray[i].setFConst(x - y * floorf(x / y));
Arun Patolebf790422015-05-18 17:53:04 +05302039 }
2040 }
2041 else
2042 UNREACHABLE();
2043 }
2044 break;
2045
Arun Patole274f0702015-05-05 13:33:30 +05302046 case EOpMin:
2047 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002048 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302049 for (size_t i = 0; i < maxObjectSize; i++)
2050 {
2051 switch (basicType)
2052 {
2053 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002054 resultArray[i].setFConst(std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302055 break;
2056 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002057 resultArray[i].setIConst(std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302058 break;
2059 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002060 resultArray[i].setUConst(std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302061 break;
2062 default:
2063 UNREACHABLE();
2064 break;
2065 }
2066 }
2067 }
2068 break;
2069
2070 case EOpMax:
2071 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002072 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302073 for (size_t i = 0; i < maxObjectSize; i++)
2074 {
2075 switch (basicType)
2076 {
2077 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002078 resultArray[i].setFConst(std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302079 break;
2080 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002081 resultArray[i].setIConst(std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302082 break;
2083 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002084 resultArray[i].setUConst(std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302085 break;
2086 default:
2087 UNREACHABLE();
2088 break;
2089 }
2090 }
2091 }
2092 break;
2093
Arun Patolebf790422015-05-18 17:53:04 +05302094 case EOpStep:
2095 {
2096 if (basicType == EbtFloat)
2097 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002098 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302099 for (size_t i = 0; i < maxObjectSize; i++)
Olli Etuahob43846e2015-06-02 18:18:57 +03002100 resultArray[i].setFConst(unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f : 1.0f);
Arun Patolebf790422015-05-18 17:53:04 +05302101 }
2102 else
2103 UNREACHABLE();
2104 }
2105 break;
2106
Arun Patole9d0b1f92015-05-20 14:27:17 +05302107 case EOpLessThan:
2108 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002109 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302110 for (size_t i = 0; i < maxObjectSize; i++)
2111 {
2112 switch (basicType)
2113 {
2114 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002115 resultArray[i].setBConst(unionArrays[0][i].getFConst() < unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302116 break;
2117 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002118 resultArray[i].setBConst(unionArrays[0][i].getIConst() < unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302119 break;
2120 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002121 resultArray[i].setBConst(unionArrays[0][i].getUConst() < unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302122 break;
2123 default:
2124 UNREACHABLE();
2125 break;
2126 }
2127 }
2128 }
2129 break;
2130
2131 case EOpLessThanEqual:
2132 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002133 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302134 for (size_t i = 0; i < maxObjectSize; i++)
2135 {
2136 switch (basicType)
2137 {
2138 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002139 resultArray[i].setBConst(unionArrays[0][i].getFConst() <= unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302140 break;
2141 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002142 resultArray[i].setBConst(unionArrays[0][i].getIConst() <= unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302143 break;
2144 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002145 resultArray[i].setBConst(unionArrays[0][i].getUConst() <= unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302146 break;
2147 default:
2148 UNREACHABLE();
2149 break;
2150 }
2151 }
2152 }
2153 break;
2154
2155 case EOpGreaterThan:
2156 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002157 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302158 for (size_t i = 0; i < maxObjectSize; i++)
2159 {
2160 switch (basicType)
2161 {
2162 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002163 resultArray[i].setBConst(unionArrays[0][i].getFConst() > unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302164 break;
2165 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002166 resultArray[i].setBConst(unionArrays[0][i].getIConst() > unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302167 break;
2168 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002169 resultArray[i].setBConst(unionArrays[0][i].getUConst() > unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302170 break;
2171 default:
2172 UNREACHABLE();
2173 break;
Olli Etuahob43846e2015-06-02 18:18:57 +03002174 }
2175 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302176 }
2177 break;
2178
2179 case EOpGreaterThanEqual:
2180 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002181 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302182 for (size_t i = 0; i < maxObjectSize; i++)
2183 {
2184 switch (basicType)
2185 {
2186 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002187 resultArray[i].setBConst(unionArrays[0][i].getFConst() >= unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302188 break;
2189 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002190 resultArray[i].setBConst(unionArrays[0][i].getIConst() >= unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302191 break;
2192 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002193 resultArray[i].setBConst(unionArrays[0][i].getUConst() >= unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302194 break;
2195 default:
2196 UNREACHABLE();
2197 break;
2198 }
2199 }
2200 }
2201 break;
2202
2203 case EOpVectorEqual:
2204 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002205 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302206 for (size_t i = 0; i < maxObjectSize; i++)
2207 {
2208 switch (basicType)
2209 {
2210 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002211 resultArray[i].setBConst(unionArrays[0][i].getFConst() == unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302212 break;
2213 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002214 resultArray[i].setBConst(unionArrays[0][i].getIConst() == unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302215 break;
2216 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002217 resultArray[i].setBConst(unionArrays[0][i].getUConst() == unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302218 break;
2219 case EbtBool:
Olli Etuahob43846e2015-06-02 18:18:57 +03002220 resultArray[i].setBConst(unionArrays[0][i].getBConst() == unionArrays[1][i].getBConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302221 break;
2222 default:
2223 UNREACHABLE();
2224 break;
2225 }
2226 }
2227 }
2228 break;
2229
2230 case EOpVectorNotEqual:
2231 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002232 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302233 for (size_t i = 0; i < maxObjectSize; i++)
2234 {
2235 switch (basicType)
2236 {
2237 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002238 resultArray[i].setBConst(unionArrays[0][i].getFConst() != unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302239 break;
2240 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002241 resultArray[i].setBConst(unionArrays[0][i].getIConst() != unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302242 break;
2243 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002244 resultArray[i].setBConst(unionArrays[0][i].getUConst() != unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302245 break;
2246 case EbtBool:
Olli Etuahob43846e2015-06-02 18:18:57 +03002247 resultArray[i].setBConst(unionArrays[0][i].getBConst() != unionArrays[1][i].getBConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302248 break;
2249 default:
2250 UNREACHABLE();
2251 break;
2252 }
2253 }
2254 }
2255 break;
2256
Arun Patole1155ddd2015-06-05 18:04:36 +05302257 case EOpDistance:
2258 if (basicType == EbtFloat)
2259 {
2260 TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
Olli Etuahob43846e2015-06-02 18:18:57 +03002261 resultArray = new TConstantUnion();
Arun Patole1155ddd2015-06-05 18:04:36 +05302262 for (size_t i = 0; i < maxObjectSize; i++)
2263 {
2264 float x = unionArrays[0][i].getFConst();
2265 float y = unionArrays[1][i].getFConst();
2266 distanceArray[i].setFConst(x - y);
2267 }
Olli Etuahob43846e2015-06-02 18:18:57 +03002268 resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
Arun Patole1155ddd2015-06-05 18:04:36 +05302269 }
2270 else
2271 UNREACHABLE();
2272 break;
2273
2274 case EOpDot:
Olli Etuahob43846e2015-06-02 18:18:57 +03002275
Arun Patole1155ddd2015-06-05 18:04:36 +05302276 if (basicType == EbtFloat)
2277 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002278 resultArray = new TConstantUnion();
2279 resultArray->setFConst(VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
Arun Patole1155ddd2015-06-05 18:04:36 +05302280 }
2281 else
2282 UNREACHABLE();
2283 break;
2284
2285 case EOpCross:
2286 if (basicType == EbtFloat && maxObjectSize == 3)
2287 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002288 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302289 float x0 = unionArrays[0][0].getFConst();
2290 float x1 = unionArrays[0][1].getFConst();
2291 float x2 = unionArrays[0][2].getFConst();
2292 float y0 = unionArrays[1][0].getFConst();
2293 float y1 = unionArrays[1][1].getFConst();
2294 float y2 = unionArrays[1][2].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002295 resultArray[0].setFConst(x1 * y2 - y1 * x2);
2296 resultArray[1].setFConst(x2 * y0 - y2 * x0);
2297 resultArray[2].setFConst(x0 * y1 - y0 * x1);
Arun Patole1155ddd2015-06-05 18:04:36 +05302298 }
2299 else
2300 UNREACHABLE();
2301 break;
2302
2303 case EOpReflect:
2304 if (basicType == EbtFloat)
2305 {
2306 // genType reflect (genType I, genType N) :
2307 // For the incident vector I and surface orientation N, returns the reflection direction:
2308 // I - 2 * dot(N, I) * N.
Olli Etuahob43846e2015-06-02 18:18:57 +03002309 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302310 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2311 for (size_t i = 0; i < maxObjectSize; i++)
2312 {
2313 float result = unionArrays[0][i].getFConst() -
2314 2.0f * dotProduct * unionArrays[1][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002315 resultArray[i].setFConst(result);
Arun Patole1155ddd2015-06-05 18:04:36 +05302316 }
2317 }
2318 else
2319 UNREACHABLE();
2320 break;
2321
Arun Patole7fa33552015-06-10 15:15:18 +05302322 case EOpMul:
2323 if (basicType == EbtFloat && (*sequence)[0]->getAsTyped()->isMatrix() &&
2324 (*sequence)[1]->getAsTyped()->isMatrix())
2325 {
2326 // Perform component-wise matrix multiplication.
2327 resultArray = new TConstantUnion[maxObjectSize];
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002328 int size = (*sequence)[0]->getAsTyped()->getNominalSize();
Arun Patole7fa33552015-06-10 15:15:18 +05302329 angle::Matrix<float> result =
2330 GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size));
2331 SetUnionArrayFromMatrix(result, resultArray);
2332 }
2333 else
2334 UNREACHABLE();
2335 break;
2336
2337 case EOpOuterProduct:
2338 if (basicType == EbtFloat)
2339 {
2340 size_t numRows = (*sequence)[0]->getAsTyped()->getType().getObjectSize();
2341 size_t numCols = (*sequence)[1]->getAsTyped()->getType().getObjectSize();
2342 resultArray = new TConstantUnion[numRows * numCols];
2343 angle::Matrix<float> result =
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002344 GetMatrix(unionArrays[0], 1, static_cast<int>(numCols))
2345 .outerProduct(GetMatrix(unionArrays[1], static_cast<int>(numRows), 1));
Arun Patole7fa33552015-06-10 15:15:18 +05302346 SetUnionArrayFromMatrix(result, resultArray);
2347 }
2348 else
2349 UNREACHABLE();
2350 break;
2351
Arun Patole274f0702015-05-05 13:33:30 +05302352 default:
2353 UNREACHABLE();
2354 // TODO: Add constant folding support for other built-in operations that take 2 parameters and not handled above.
2355 return nullptr;
2356 }
2357 }
2358 else if (paramsCount == 3)
2359 {
2360 //
2361 // Ternary built-in
2362 //
2363 switch (op)
2364 {
2365 case EOpClamp:
2366 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002367 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302368 for (size_t i = 0; i < maxObjectSize; i++)
2369 {
2370 switch (basicType)
2371 {
2372 case EbtFloat:
2373 {
2374 float x = unionArrays[0][i].getFConst();
2375 float min = unionArrays[1][i].getFConst();
2376 float max = unionArrays[2][i].getFConst();
2377 // Results are undefined if min > max.
2378 if (min > max)
Olli Etuahob43846e2015-06-02 18:18:57 +03002379 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302380 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002381 resultArray[i].setFConst(gl::clamp(x, min, max));
Arun Patole274f0702015-05-05 13:33:30 +05302382 }
2383 break;
2384 case EbtInt:
2385 {
2386 int x = unionArrays[0][i].getIConst();
2387 int min = unionArrays[1][i].getIConst();
2388 int max = unionArrays[2][i].getIConst();
2389 // Results are undefined if min > max.
2390 if (min > max)
Olli Etuahob43846e2015-06-02 18:18:57 +03002391 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302392 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002393 resultArray[i].setIConst(gl::clamp(x, min, max));
Arun Patole274f0702015-05-05 13:33:30 +05302394 }
2395 break;
2396 case EbtUInt:
2397 {
2398 unsigned int x = unionArrays[0][i].getUConst();
2399 unsigned int min = unionArrays[1][i].getUConst();
2400 unsigned int max = unionArrays[2][i].getUConst();
2401 // Results are undefined if min > max.
2402 if (min > max)
Olli Etuahob43846e2015-06-02 18:18:57 +03002403 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302404 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002405 resultArray[i].setUConst(gl::clamp(x, min, max));
Arun Patole274f0702015-05-05 13:33:30 +05302406 }
2407 break;
2408 default:
2409 UNREACHABLE();
2410 break;
2411 }
2412 }
2413 }
2414 break;
2415
Arun Patolebf790422015-05-18 17:53:04 +05302416 case EOpMix:
2417 {
2418 if (basicType == EbtFloat)
2419 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002420 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302421 for (size_t i = 0; i < maxObjectSize; i++)
2422 {
2423 float x = unionArrays[0][i].getFConst();
2424 float y = unionArrays[1][i].getFConst();
2425 TBasicType type = (*sequence)[2]->getAsTyped()->getType().getBasicType();
2426 if (type == EbtFloat)
2427 {
2428 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
2429 float a = unionArrays[2][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002430 resultArray[i].setFConst(x * (1.0f - a) + y * a);
Arun Patolebf790422015-05-18 17:53:04 +05302431 }
2432 else // 3rd parameter is EbtBool
2433 {
2434 ASSERT(type == EbtBool);
2435 // Selects which vector each returned component comes from.
2436 // For a component of a that is false, the corresponding component of x is returned.
2437 // For a component of a that is true, the corresponding component of y is returned.
2438 bool a = unionArrays[2][i].getBConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002439 resultArray[i].setFConst(a ? y : x);
Arun Patolebf790422015-05-18 17:53:04 +05302440 }
2441 }
2442 }
2443 else
2444 UNREACHABLE();
2445 }
2446 break;
2447
2448 case EOpSmoothStep:
2449 {
2450 if (basicType == EbtFloat)
2451 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002452 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302453 for (size_t i = 0; i < maxObjectSize; i++)
2454 {
2455 float edge0 = unionArrays[0][i].getFConst();
2456 float edge1 = unionArrays[1][i].getFConst();
2457 float x = unionArrays[2][i].getFConst();
2458 // Results are undefined if edge0 >= edge1.
2459 if (edge0 >= edge1)
2460 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002461 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05302462 }
2463 else
2464 {
2465 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
2466 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
2467 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
Olli Etuahob43846e2015-06-02 18:18:57 +03002468 resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
Arun Patolebf790422015-05-18 17:53:04 +05302469 }
2470 }
2471 }
2472 else
2473 UNREACHABLE();
2474 }
2475 break;
2476
Arun Patole1155ddd2015-06-05 18:04:36 +05302477 case EOpFaceForward:
2478 if (basicType == EbtFloat)
2479 {
2480 // genType faceforward(genType N, genType I, genType Nref) :
2481 // If dot(Nref, I) < 0 return N, otherwise return -N.
Olli Etuahob43846e2015-06-02 18:18:57 +03002482 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302483 float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
2484 for (size_t i = 0; i < maxObjectSize; i++)
2485 {
2486 if (dotProduct < 0)
Olli Etuahob43846e2015-06-02 18:18:57 +03002487 resultArray[i].setFConst(unionArrays[0][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302488 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002489 resultArray[i].setFConst(-unionArrays[0][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302490 }
2491 }
2492 else
2493 UNREACHABLE();
2494 break;
2495
2496 case EOpRefract:
2497 if (basicType == EbtFloat)
2498 {
2499 // genType refract(genType I, genType N, float eta) :
2500 // For the incident vector I and surface normal N, and the ratio of indices of refraction eta,
2501 // return the refraction vector. The result is computed by
2502 // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
2503 // if (k < 0.0)
2504 // return genType(0.0)
2505 // else
2506 // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
Olli Etuahob43846e2015-06-02 18:18:57 +03002507 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302508 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2509 for (size_t i = 0; i < maxObjectSize; i++)
2510 {
2511 float eta = unionArrays[2][i].getFConst();
2512 float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
2513 if (k < 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03002514 resultArray[i].setFConst(0.0f);
Arun Patole1155ddd2015-06-05 18:04:36 +05302515 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002516 resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
Arun Patole1155ddd2015-06-05 18:04:36 +05302517 (eta * dotProduct + sqrtf(k)) * unionArrays[1][i].getFConst());
2518 }
2519 }
2520 else
2521 UNREACHABLE();
2522 break;
2523
Arun Patole274f0702015-05-05 13:33:30 +05302524 default:
2525 UNREACHABLE();
2526 // TODO: Add constant folding support for other built-in operations that take 3 parameters and not handled above.
2527 return nullptr;
2528 }
2529 }
Olli Etuahob43846e2015-06-02 18:18:57 +03002530 return resultArray;
Arun Patole274f0702015-05-05 13:33:30 +05302531}
2532
2533// static
Jamie Madillb1a85f42014-08-19 15:23:24 -04002534TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunction)
2535{
2536 if (hashFunction == NULL || name.empty())
2537 return name;
2538 khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
2539 TStringStream stream;
2540 stream << HASHED_NAME_PREFIX << std::hex << number;
2541 TString hashedName = stream.str();
2542 return hashedName;
2543}
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002544
2545void TIntermTraverser::updateTree()
2546{
Olli Etuahoa6f22092015-05-08 18:31:10 +03002547 for (size_t ii = 0; ii < mInsertions.size(); ++ii)
2548 {
2549 const NodeInsertMultipleEntry &insertion = mInsertions[ii];
2550 ASSERT(insertion.parent);
Jamie Madilla5f64de2015-10-30 12:31:00 +00002551 bool inserted = insertion.parent->insertChildNodes(insertion.position, insertion.insertions);
2552 ASSERT(inserted);
2553 UNUSED_ASSERTION_VARIABLE(inserted);
Olli Etuahoa6f22092015-05-08 18:31:10 +03002554 }
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002555 for (size_t ii = 0; ii < mReplacements.size(); ++ii)
2556 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002557 const NodeUpdateEntry &replacement = mReplacements[ii];
2558 ASSERT(replacement.parent);
2559 bool replaced = replacement.parent->replaceChildNode(
2560 replacement.original, replacement.replacement);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002561 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03002562 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002563
Olli Etuahocd94ef92015-04-16 19:18:10 +03002564 if (!replacement.originalBecomesChildOfReplacement)
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002565 {
2566 // In AST traversing, a parent is visited before its children.
Olli Etuahocd94ef92015-04-16 19:18:10 +03002567 // After we replace a node, if its immediate child is to
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002568 // be replaced, we need to make sure we don't update the replaced
2569 // node; instead, we update the replacement node.
2570 for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj)
2571 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002572 NodeUpdateEntry &replacement2 = mReplacements[jj];
2573 if (replacement2.parent == replacement.original)
2574 replacement2.parent = replacement.replacement;
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002575 }
2576 }
2577 }
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002578 for (size_t ii = 0; ii < mMultiReplacements.size(); ++ii)
2579 {
2580 const NodeReplaceWithMultipleEntry &replacement = mMultiReplacements[ii];
2581 ASSERT(replacement.parent);
2582 bool replaced = replacement.parent->replaceChildNodeWithMultiple(
2583 replacement.original, replacement.replacements);
2584 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03002585 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002586 }
Olli Etuahod4f303e2015-05-20 17:09:06 +03002587
2588 mInsertions.clear();
2589 mReplacements.clear();
2590 mMultiReplacements.clear();
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002591}