blob: 0acfe40e7e7e2e709e6e8317a54042b43285b60e [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"
Olli Etuaho3fdec912016-08-18 15:08:06 +030020#include "compiler/translator/Diagnostics.h"
Jamie Madillb1a85f42014-08-19 15:23:24 -040021#include "compiler/translator/HashNames.h"
22#include "compiler/translator/IntermNode.h"
23#include "compiler/translator/SymbolTable.h"
Corentin Wallez509e4562016-08-25 14:55:44 -040024#include "compiler/translator/util.h"
Jamie Madillb1a85f42014-08-19 15:23:24 -040025
26namespace
27{
28
Arun Patole9dea48f2015-04-02 11:45:09 +053029const float kPi = 3.14159265358979323846f;
30const float kDegreesToRadiansMultiplier = kPi / 180.0f;
31const float kRadiansToDegreesMultiplier = 180.0f / kPi;
32
Jamie Madillb1a85f42014-08-19 15:23:24 -040033TPrecision GetHigherPrecision(TPrecision left, TPrecision right)
34{
35 return left > right ? left : right;
36}
37
Arun Patole274f0702015-05-05 13:33:30 +053038TConstantUnion *Vectorize(const TConstantUnion &constant, size_t size)
39{
40 TConstantUnion *constUnion = new TConstantUnion[size];
41 for (unsigned int i = 0; i < size; ++i)
42 constUnion[i] = constant;
43
44 return constUnion;
45}
46
Olli Etuahof119a262016-08-19 15:54:22 +030047void UndefinedConstantFoldingError(const TSourceLoc &loc,
48 TOperator op,
49 TBasicType basicType,
50 TDiagnostics *diagnostics,
51 TConstantUnion *result)
Arun Patolebf790422015-05-18 17:53:04 +053052{
Olli Etuahof119a262016-08-19 15:54:22 +030053 diagnostics->warning(loc, "operation result is undefined for the values passed in",
54 GetOperatorString(op), "");
Arun Patolebf790422015-05-18 17:53:04 +053055
56 switch (basicType)
57 {
58 case EbtFloat :
59 result->setFConst(0.0f);
60 break;
61 case EbtInt:
62 result->setIConst(0);
63 break;
64 case EbtUInt:
65 result->setUConst(0u);
66 break;
67 case EbtBool:
68 result->setBConst(false);
69 break;
70 default:
71 break;
72 }
73}
74
Olli Etuaho5c0e0232015-11-11 15:55:59 +020075float VectorLength(const TConstantUnion *paramArray, size_t paramArraySize)
Arun Patole1155ddd2015-06-05 18:04:36 +053076{
77 float result = 0.0f;
78 for (size_t i = 0; i < paramArraySize; i++)
79 {
80 float f = paramArray[i].getFConst();
81 result += f * f;
82 }
83 return sqrtf(result);
84}
85
Olli Etuaho5c0e0232015-11-11 15:55:59 +020086float VectorDotProduct(const TConstantUnion *paramArray1,
87 const TConstantUnion *paramArray2,
88 size_t paramArraySize)
Arun Patole1155ddd2015-06-05 18:04:36 +053089{
90 float result = 0.0f;
91 for (size_t i = 0; i < paramArraySize; i++)
92 result += paramArray1[i].getFConst() * paramArray2[i].getFConst();
93 return result;
94}
95
Olli Etuaho3272a6d2016-08-29 17:54:50 +030096TIntermTyped *CreateFoldedNode(const TConstantUnion *constArray,
Olli Etuaho7c3848e2015-11-04 13:19:17 +020097 const TIntermTyped *originalNode,
98 TQualifier qualifier)
Olli Etuahob43846e2015-06-02 18:18:57 +030099{
100 if (constArray == nullptr)
101 {
102 return nullptr;
103 }
104 TIntermTyped *folded = new TIntermConstantUnion(constArray, originalNode->getType());
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200105 folded->getTypePointer()->setQualifier(qualifier);
Olli Etuahob43846e2015-06-02 18:18:57 +0300106 folded->setLine(originalNode->getLine());
107 return folded;
108}
109
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200110angle::Matrix<float> GetMatrix(const TConstantUnion *paramArray,
111 const unsigned int &rows,
112 const unsigned int &cols)
Arun Patole7fa33552015-06-10 15:15:18 +0530113{
114 std::vector<float> elements;
115 for (size_t i = 0; i < rows * cols; i++)
116 elements.push_back(paramArray[i].getFConst());
117 // Transpose is used since the Matrix constructor expects arguments in row-major order,
Olli Etuahod5da5052016-08-29 13:16:55 +0300118 // whereas the paramArray is in column-major order. Rows/cols parameters are also flipped below
119 // so that the created matrix will have the expected dimensions after the transpose.
120 return angle::Matrix<float>(elements, cols, rows).transpose();
Arun Patole7fa33552015-06-10 15:15:18 +0530121}
122
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200123angle::Matrix<float> GetMatrix(const TConstantUnion *paramArray, const unsigned int &size)
Arun Patole7fa33552015-06-10 15:15:18 +0530124{
125 std::vector<float> elements;
126 for (size_t i = 0; i < size * size; i++)
127 elements.push_back(paramArray[i].getFConst());
128 // Transpose is used since the Matrix constructor expects arguments in row-major order,
129 // whereas the paramArray is in column-major order.
130 return angle::Matrix<float>(elements, size).transpose();
131}
132
133void SetUnionArrayFromMatrix(const angle::Matrix<float> &m, TConstantUnion *resultArray)
134{
135 // Transpose is used since the input Matrix is in row-major order,
136 // whereas the actual result should be in column-major order.
137 angle::Matrix<float> result = m.transpose();
138 std::vector<float> resultElements = result.elements();
139 for (size_t i = 0; i < resultElements.size(); i++)
140 resultArray[i].setFConst(resultElements[i]);
141}
142
Jamie Madillb1a85f42014-08-19 15:23:24 -0400143} // namespace anonymous
144
145
146////////////////////////////////////////////////////////////////
147//
148// Member functions of the nodes used for building the tree.
149//
150////////////////////////////////////////////////////////////////
151
Olli Etuahod2a67b92014-10-21 16:42:57 +0300152void TIntermTyped::setTypePreservePrecision(const TType &t)
153{
154 TPrecision precision = getPrecision();
155 mType = t;
156 ASSERT(mType.getBasicType() != EbtBool || precision == EbpUndefined);
157 mType.setPrecision(precision);
158}
159
Jamie Madillb1a85f42014-08-19 15:23:24 -0400160#define REPLACE_IF_IS(node, type, original, replacement) \
161 if (node == original) { \
162 node = static_cast<type *>(replacement); \
163 return true; \
164 }
165
166bool TIntermLoop::replaceChildNode(
167 TIntermNode *original, TIntermNode *replacement)
168{
Olli Etuaho3cbb27a2016-07-14 11:55:48 +0300169 ASSERT(original != nullptr); // This risks replacing multiple children.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400170 REPLACE_IF_IS(mInit, TIntermNode, original, replacement);
171 REPLACE_IF_IS(mCond, TIntermTyped, original, replacement);
172 REPLACE_IF_IS(mExpr, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100173 REPLACE_IF_IS(mBody, TIntermBlock, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400174 return false;
175}
176
Jamie Madillb1a85f42014-08-19 15:23:24 -0400177bool TIntermBranch::replaceChildNode(
178 TIntermNode *original, TIntermNode *replacement)
179{
180 REPLACE_IF_IS(mExpression, TIntermTyped, original, replacement);
181 return false;
182}
183
Olli Etuahob6fa0432016-09-28 16:28:05 +0100184bool TIntermSwizzle::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
185{
186 ASSERT(original->getAsTyped()->getType() == replacement->getAsTyped()->getType());
187 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
188 return false;
189}
190
Jamie Madillb1a85f42014-08-19 15:23:24 -0400191bool TIntermBinary::replaceChildNode(
192 TIntermNode *original, TIntermNode *replacement)
193{
194 REPLACE_IF_IS(mLeft, TIntermTyped, original, replacement);
195 REPLACE_IF_IS(mRight, TIntermTyped, original, replacement);
196 return false;
197}
198
Jamie Madillb1a85f42014-08-19 15:23:24 -0400199bool TIntermUnary::replaceChildNode(
200 TIntermNode *original, TIntermNode *replacement)
201{
Olli Etuahoa2234302016-08-31 12:05:39 +0300202 ASSERT(original->getAsTyped()->getType() == replacement->getAsTyped()->getType());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400203 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
204 return false;
205}
206
Olli Etuaho336b1472016-10-05 16:37:55 +0100207bool TIntermFunctionDefinition::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
208{
209 REPLACE_IF_IS(mParameters, TIntermAggregate, original, replacement);
210 REPLACE_IF_IS(mBody, TIntermBlock, original, replacement);
211 return false;
212}
213
Jamie Madillb1a85f42014-08-19 15:23:24 -0400214bool TIntermAggregate::replaceChildNode(
215 TIntermNode *original, TIntermNode *replacement)
216{
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100217 return replaceChildNodeInternal(original, replacement);
218}
219
220bool TIntermBlock::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
221{
222 return replaceChildNodeInternal(original, replacement);
223}
224
225bool TIntermAggregateBase::replaceChildNodeInternal(TIntermNode *original, TIntermNode *replacement)
226{
227 for (size_t ii = 0; ii < getSequence()->size(); ++ii)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400228 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100229 REPLACE_IF_IS((*getSequence())[ii], TIntermNode, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400230 }
231 return false;
232}
233
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100234bool TIntermAggregateBase::replaceChildNodeWithMultiple(TIntermNode *original,
235 const TIntermSequence &replacements)
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300236{
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100237 for (auto it = getSequence()->begin(); it < getSequence()->end(); ++it)
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300238 {
239 if (*it == original)
240 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100241 it = getSequence()->erase(it);
242 getSequence()->insert(it, replacements.begin(), replacements.end());
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300243 return true;
244 }
245 }
246 return false;
247}
248
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100249bool TIntermAggregateBase::insertChildNodes(TIntermSequence::size_type position,
250 const TIntermSequence &insertions)
Olli Etuahoa6f22092015-05-08 18:31:10 +0300251{
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100252 if (position > getSequence()->size())
Olli Etuahoa6f22092015-05-08 18:31:10 +0300253 {
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300254 return false;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300255 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100256 auto it = getSequence()->begin() + position;
257 getSequence()->insert(it, insertions.begin(), insertions.end());
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300258 return true;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300259}
260
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200261bool TIntermAggregate::areChildrenConstQualified()
262{
263 for (TIntermNode *&child : mSequence)
264 {
265 TIntermTyped *typed = child->getAsTyped();
266 if (typed && typed->getQualifier() != EvqConst)
267 {
268 return false;
269 }
270 }
271 return true;
272}
273
Olli Etuahod2a67b92014-10-21 16:42:57 +0300274void TIntermAggregate::setPrecisionFromChildren()
275{
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300276 mGotPrecisionFromChildren = true;
Olli Etuahod2a67b92014-10-21 16:42:57 +0300277 if (getBasicType() == EbtBool)
278 {
279 mType.setPrecision(EbpUndefined);
280 return;
281 }
282
283 TPrecision precision = EbpUndefined;
284 TIntermSequence::iterator childIter = mSequence.begin();
285 while (childIter != mSequence.end())
286 {
287 TIntermTyped *typed = (*childIter)->getAsTyped();
288 if (typed)
289 precision = GetHigherPrecision(typed->getPrecision(), precision);
290 ++childIter;
291 }
292 mType.setPrecision(precision);
293}
294
295void TIntermAggregate::setBuiltInFunctionPrecision()
296{
297 // All built-ins returning bool should be handled as ops, not functions.
298 ASSERT(getBasicType() != EbtBool);
299
300 TPrecision precision = EbpUndefined;
301 TIntermSequence::iterator childIter = mSequence.begin();
302 while (childIter != mSequence.end())
303 {
304 TIntermTyped *typed = (*childIter)->getAsTyped();
305 // ESSL spec section 8: texture functions get their precision from the sampler.
306 if (typed && IsSampler(typed->getBasicType()))
307 {
308 precision = typed->getPrecision();
309 break;
310 }
311 ++childIter;
312 }
313 // ESSL 3.0 spec section 8: textureSize always gets highp precision.
314 // All other functions that take a sampler are assumed to be texture functions.
Olli Etuahobd674552016-10-06 13:28:42 +0100315 if (mFunctionInfo.getName().find("textureSize") == 0)
Olli Etuahod2a67b92014-10-21 16:42:57 +0300316 mType.setPrecision(EbpHigh);
317 else
318 mType.setPrecision(precision);
319}
320
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100321void TIntermBlock::appendStatement(TIntermNode *statement)
322{
323 if (statement != nullptr)
324 {
325 mStatements.push_back(statement);
326 }
327}
328
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300329bool TIntermTernary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
330{
331 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
332 REPLACE_IF_IS(mTrueExpression, TIntermTyped, original, replacement);
333 REPLACE_IF_IS(mFalseExpression, TIntermTyped, original, replacement);
334 return false;
335}
336
Olli Etuaho57961272016-09-14 13:57:46 +0300337bool TIntermIfElse::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400338{
339 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100340 REPLACE_IF_IS(mTrueBlock, TIntermBlock, original, replacement);
341 REPLACE_IF_IS(mFalseBlock, TIntermBlock, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400342 return false;
343}
344
Olli Etuahoa3a36662015-02-17 13:46:51 +0200345bool TIntermSwitch::replaceChildNode(
346 TIntermNode *original, TIntermNode *replacement)
347{
348 REPLACE_IF_IS(mInit, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100349 REPLACE_IF_IS(mStatementList, TIntermBlock, original, replacement);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200350 return false;
351}
352
353bool TIntermCase::replaceChildNode(
354 TIntermNode *original, TIntermNode *replacement)
355{
356 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
357 return false;
358}
359
Olli Etuahod7a25242015-08-18 13:49:45 +0300360TIntermTyped::TIntermTyped(const TIntermTyped &node) : TIntermNode(), mType(node.mType)
361{
362 // Copy constructor is disallowed for TIntermNode in order to disallow it for subclasses that
363 // don't explicitly allow it, so normal TIntermNode constructor is used to construct the copy.
364 // We need to manually copy any fields of TIntermNode besides handling fields in TIntermTyped.
365 mLine = node.mLine;
366}
367
Olli Etuahod4f4c112016-04-15 15:11:24 +0300368bool TIntermTyped::isConstructorWithOnlyConstantUnionParameters()
369{
370 TIntermAggregate *constructor = getAsAggregate();
371 if (!constructor || !constructor->isConstructor())
372 {
373 return false;
374 }
375 for (TIntermNode *&node : *constructor->getSequence())
376 {
377 if (!node->getAsConstantUnion())
378 return false;
379 }
380 return true;
381}
382
Corentin Wallez509e4562016-08-25 14:55:44 -0400383// static
384TIntermTyped *TIntermTyped::CreateIndexNode(int index)
385{
386 TConstantUnion *u = new TConstantUnion[1];
387 u[0].setIConst(index);
388
389 TType type(EbtInt, EbpUndefined, EvqConst, 1);
390 TIntermConstantUnion *node = new TIntermConstantUnion(u, type);
391 return node;
392}
393
394// static
395TIntermTyped *TIntermTyped::CreateZero(const TType &type)
396{
397 TType constType(type);
398 constType.setQualifier(EvqConst);
399
400 if (!type.isArray() && type.getBasicType() != EbtStruct)
401 {
402 ASSERT(type.isScalar() || type.isVector() || type.isMatrix());
403
404 size_t size = constType.getObjectSize();
405 TConstantUnion *u = new TConstantUnion[size];
406 for (size_t i = 0; i < size; ++i)
407 {
408 switch (type.getBasicType())
409 {
410 case EbtFloat:
411 u[i].setFConst(0.0f);
412 break;
413 case EbtInt:
414 u[i].setIConst(0);
415 break;
416 case EbtUInt:
417 u[i].setUConst(0u);
418 break;
419 case EbtBool:
420 u[i].setBConst(false);
421 break;
422 default:
423 UNREACHABLE();
424 return nullptr;
425 }
426 }
427
428 TIntermConstantUnion *node = new TIntermConstantUnion(u, constType);
429 return node;
430 }
431
432 TIntermAggregate *constructor = new TIntermAggregate(sh::TypeToConstructorOperator(type));
433 constructor->setType(constType);
434
435 if (type.isArray())
436 {
437 TType elementType(type);
438 elementType.clearArrayness();
439
440 size_t arraySize = type.getArraySize();
441 for (size_t i = 0; i < arraySize; ++i)
442 {
443 constructor->getSequence()->push_back(CreateZero(elementType));
444 }
445 }
446 else
447 {
448 ASSERT(type.getBasicType() == EbtStruct);
449
450 TStructure *structure = type.getStruct();
451 for (const auto &field : structure->fields())
452 {
453 constructor->getSequence()->push_back(CreateZero(*field->type()));
454 }
455 }
456
457 return constructor;
458}
459
Olli Etuahod7a25242015-08-18 13:49:45 +0300460TIntermConstantUnion::TIntermConstantUnion(const TIntermConstantUnion &node) : TIntermTyped(node)
461{
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200462 mUnionArrayPointer = node.mUnionArrayPointer;
Olli Etuahod7a25242015-08-18 13:49:45 +0300463}
464
Olli Etuahobd674552016-10-06 13:28:42 +0100465void TFunctionSymbolInfo::setFromFunction(const TFunction &function)
466{
467 setName(function.getMangledName());
468 setId(function.getUniqueId());
469}
470
Olli Etuahod7a25242015-08-18 13:49:45 +0300471TIntermAggregate::TIntermAggregate(const TIntermAggregate &node)
472 : TIntermOperator(node),
Olli Etuahod7a25242015-08-18 13:49:45 +0300473 mUserDefined(node.mUserDefined),
Olli Etuahod7a25242015-08-18 13:49:45 +0300474 mUseEmulatedFunction(node.mUseEmulatedFunction),
Olli Etuahobd674552016-10-06 13:28:42 +0100475 mGotPrecisionFromChildren(node.mGotPrecisionFromChildren),
476 mFunctionInfo(node.mFunctionInfo)
Olli Etuahod7a25242015-08-18 13:49:45 +0300477{
478 for (TIntermNode *child : node.mSequence)
479 {
480 TIntermTyped *typedChild = child->getAsTyped();
481 ASSERT(typedChild != nullptr);
482 TIntermTyped *childCopy = typedChild->deepCopy();
483 mSequence.push_back(childCopy);
484 }
485}
486
Olli Etuahob6fa0432016-09-28 16:28:05 +0100487TIntermSwizzle::TIntermSwizzle(const TIntermSwizzle &node) : TIntermTyped(node)
488{
489 TIntermTyped *operandCopy = node.mOperand->deepCopy();
490 ASSERT(operandCopy != nullptr);
491 mOperand = operandCopy;
492}
493
Olli Etuahod7a25242015-08-18 13:49:45 +0300494TIntermBinary::TIntermBinary(const TIntermBinary &node)
495 : TIntermOperator(node), mAddIndexClamp(node.mAddIndexClamp)
496{
497 TIntermTyped *leftCopy = node.mLeft->deepCopy();
498 TIntermTyped *rightCopy = node.mRight->deepCopy();
499 ASSERT(leftCopy != nullptr && rightCopy != nullptr);
500 mLeft = leftCopy;
501 mRight = rightCopy;
502}
503
504TIntermUnary::TIntermUnary(const TIntermUnary &node)
505 : TIntermOperator(node), mUseEmulatedFunction(node.mUseEmulatedFunction)
506{
507 TIntermTyped *operandCopy = node.mOperand->deepCopy();
508 ASSERT(operandCopy != nullptr);
509 mOperand = operandCopy;
510}
511
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300512TIntermTernary::TIntermTernary(const TIntermTernary &node) : TIntermTyped(node)
Olli Etuahod7a25242015-08-18 13:49:45 +0300513{
Olli Etuahod7a25242015-08-18 13:49:45 +0300514 TIntermTyped *conditionCopy = node.mCondition->deepCopy();
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300515 TIntermTyped *trueCopy = node.mTrueExpression->deepCopy();
516 TIntermTyped *falseCopy = node.mFalseExpression->deepCopy();
Olli Etuahod7a25242015-08-18 13:49:45 +0300517 ASSERT(conditionCopy != nullptr && trueCopy != nullptr && falseCopy != nullptr);
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300518 mCondition = conditionCopy;
519 mTrueExpression = trueCopy;
520 mFalseExpression = falseCopy;
Olli Etuahod7a25242015-08-18 13:49:45 +0300521}
522
Jamie Madillb1a85f42014-08-19 15:23:24 -0400523bool TIntermOperator::isAssignment() const
524{
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300525 return IsAssignment(mOp);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400526}
527
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300528bool TIntermOperator::isMultiplication() const
529{
530 switch (mOp)
531 {
532 case EOpMul:
533 case EOpMatrixTimesMatrix:
534 case EOpMatrixTimesVector:
535 case EOpMatrixTimesScalar:
536 case EOpVectorTimesMatrix:
537 case EOpVectorTimesScalar:
538 return true;
539 default:
540 return false;
541 }
542}
543
Jamie Madillb1a85f42014-08-19 15:23:24 -0400544//
545// returns true if the operator is for one of the constructors
546//
547bool TIntermOperator::isConstructor() const
548{
549 switch (mOp)
550 {
551 case EOpConstructVec2:
552 case EOpConstructVec3:
553 case EOpConstructVec4:
554 case EOpConstructMat2:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400555 case EOpConstructMat2x3:
556 case EOpConstructMat2x4:
557 case EOpConstructMat3x2:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400558 case EOpConstructMat3:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400559 case EOpConstructMat3x4:
560 case EOpConstructMat4x2:
561 case EOpConstructMat4x3:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400562 case EOpConstructMat4:
563 case EOpConstructFloat:
564 case EOpConstructIVec2:
565 case EOpConstructIVec3:
566 case EOpConstructIVec4:
567 case EOpConstructInt:
568 case EOpConstructUVec2:
569 case EOpConstructUVec3:
570 case EOpConstructUVec4:
571 case EOpConstructUInt:
572 case EOpConstructBVec2:
573 case EOpConstructBVec3:
574 case EOpConstructBVec4:
575 case EOpConstructBool:
576 case EOpConstructStruct:
577 return true;
578 default:
579 return false;
580 }
581}
582
Olli Etuaho1dded802016-08-18 18:13:13 +0300583TOperator TIntermBinary::GetMulOpBasedOnOperands(const TType &left, const TType &right)
584{
585 if (left.isMatrix())
586 {
587 if (right.isMatrix())
588 {
589 return EOpMatrixTimesMatrix;
590 }
591 else
592 {
593 if (right.isVector())
594 {
595 return EOpMatrixTimesVector;
596 }
597 else
598 {
599 return EOpMatrixTimesScalar;
600 }
601 }
602 }
603 else
604 {
605 if (right.isMatrix())
606 {
607 if (left.isVector())
608 {
609 return EOpVectorTimesMatrix;
610 }
611 else
612 {
613 return EOpMatrixTimesScalar;
614 }
615 }
616 else
617 {
618 // Neither operand is a matrix.
619 if (left.isVector() == right.isVector())
620 {
621 // Leave as component product.
622 return EOpMul;
623 }
624 else
625 {
626 return EOpVectorTimesScalar;
627 }
628 }
629 }
630}
631
632TOperator TIntermBinary::GetMulAssignOpBasedOnOperands(const TType &left, const TType &right)
633{
634 if (left.isMatrix())
635 {
636 if (right.isMatrix())
637 {
638 return EOpMatrixTimesMatrixAssign;
639 }
640 else
641 {
642 // right should be scalar, but this may not be validated yet.
643 return EOpMatrixTimesScalarAssign;
644 }
645 }
646 else
647 {
648 if (right.isMatrix())
649 {
650 // Left should be a vector, but this may not be validated yet.
651 return EOpVectorTimesMatrixAssign;
652 }
653 else
654 {
655 // Neither operand is a matrix.
656 if (left.isVector() == right.isVector())
657 {
658 // Leave as component product.
659 return EOpMulAssign;
660 }
661 else
662 {
663 // left should be vector and right should be scalar, but this may not be validated
664 // yet.
665 return EOpVectorTimesScalarAssign;
666 }
667 }
668 }
669}
670
Jamie Madillb1a85f42014-08-19 15:23:24 -0400671//
672// Make sure the type of a unary operator is appropriate for its
673// combination of operation and operand type.
674//
Olli Etuahoa2234302016-08-31 12:05:39 +0300675void TIntermUnary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -0400676{
Olli Etuahoa2234302016-08-31 12:05:39 +0300677 TQualifier resultQualifier = EvqTemporary;
678 if (mOperand->getQualifier() == EvqConst)
679 resultQualifier = EvqConst;
680
681 unsigned char operandPrimarySize =
682 static_cast<unsigned char>(mOperand->getType().getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400683 switch (mOp)
684 {
Olli Etuahoa2234302016-08-31 12:05:39 +0300685 case EOpFloatBitsToInt:
686 setType(TType(EbtInt, EbpHigh, resultQualifier, operandPrimarySize));
687 break;
688 case EOpFloatBitsToUint:
689 setType(TType(EbtUInt, EbpHigh, resultQualifier, operandPrimarySize));
690 break;
691 case EOpIntBitsToFloat:
692 case EOpUintBitsToFloat:
693 setType(TType(EbtFloat, EbpHigh, resultQualifier, operandPrimarySize));
694 break;
695 case EOpPackSnorm2x16:
696 case EOpPackUnorm2x16:
697 case EOpPackHalf2x16:
698 setType(TType(EbtUInt, EbpHigh, resultQualifier));
699 break;
700 case EOpUnpackSnorm2x16:
701 case EOpUnpackUnorm2x16:
702 setType(TType(EbtFloat, EbpHigh, resultQualifier, 2));
703 break;
704 case EOpUnpackHalf2x16:
705 setType(TType(EbtFloat, EbpMedium, resultQualifier, 2));
706 break;
707 case EOpAny:
708 case EOpAll:
709 setType(TType(EbtBool, EbpUndefined, resultQualifier));
710 break;
711 case EOpLength:
712 case EOpDeterminant:
713 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier));
714 break;
715 case EOpTranspose:
716 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier,
717 static_cast<unsigned char>(mOperand->getType().getRows()),
718 static_cast<unsigned char>(mOperand->getType().getCols())));
719 break;
720 case EOpIsInf:
721 case EOpIsNan:
722 setType(TType(EbtBool, EbpUndefined, resultQualifier, operandPrimarySize));
723 break;
724 default:
725 setType(mOperand->getType());
726 mType.setQualifier(resultQualifier);
727 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400728 }
Olli Etuahoa2234302016-08-31 12:05:39 +0300729}
Jamie Madillb1a85f42014-08-19 15:23:24 -0400730
Olli Etuahob6fa0432016-09-28 16:28:05 +0100731TIntermSwizzle::TIntermSwizzle(TIntermTyped *operand, const TVector<int> &swizzleOffsets)
732 : TIntermTyped(TType(EbtFloat, EbpUndefined)),
733 mOperand(operand),
734 mSwizzleOffsets(swizzleOffsets)
735{
736 ASSERT(mSwizzleOffsets.size() <= 4);
737 promote();
738}
739
Olli Etuahoa2234302016-08-31 12:05:39 +0300740TIntermUnary::TIntermUnary(TOperator op, TIntermTyped *operand)
741 : TIntermOperator(op), mOperand(operand), mUseEmulatedFunction(false)
742{
743 promote();
Jamie Madillb1a85f42014-08-19 15:23:24 -0400744}
745
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300746TIntermBinary::TIntermBinary(TOperator op, TIntermTyped *left, TIntermTyped *right)
747 : TIntermOperator(op), mLeft(left), mRight(right), mAddIndexClamp(false)
748{
749 promote();
750}
751
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300752TIntermTernary::TIntermTernary(TIntermTyped *cond,
753 TIntermTyped *trueExpression,
754 TIntermTyped *falseExpression)
755 : TIntermTyped(trueExpression->getType()),
756 mCondition(cond),
757 mTrueExpression(trueExpression),
758 mFalseExpression(falseExpression)
759{
760 getTypePointer()->setQualifier(
761 TIntermTernary::DetermineQualifier(cond, trueExpression, falseExpression));
762}
763
764// static
765TQualifier TIntermTernary::DetermineQualifier(TIntermTyped *cond,
766 TIntermTyped *trueExpression,
767 TIntermTyped *falseExpression)
768{
769 if (cond->getQualifier() == EvqConst && trueExpression->getQualifier() == EvqConst &&
770 falseExpression->getQualifier() == EvqConst)
771 {
772 return EvqConst;
773 }
774 return EvqTemporary;
775}
776
Olli Etuahob6fa0432016-09-28 16:28:05 +0100777void TIntermSwizzle::promote()
778{
779 TQualifier resultQualifier = EvqTemporary;
780 if (mOperand->getQualifier() == EvqConst)
781 resultQualifier = EvqConst;
782
783 auto numFields = mSwizzleOffsets.size();
784 setType(TType(mOperand->getBasicType(), mOperand->getPrecision(), resultQualifier,
785 static_cast<unsigned char>(numFields)));
786}
787
788bool TIntermSwizzle::hasDuplicateOffsets() const
789{
790 int offsetCount[4] = {0u, 0u, 0u, 0u};
791 for (const auto offset : mSwizzleOffsets)
792 {
793 offsetCount[offset]++;
794 if (offsetCount[offset] > 1)
795 {
796 return true;
797 }
798 }
799 return false;
800}
801
802void TIntermSwizzle::writeOffsetsAsXYZW(TInfoSinkBase *out) const
803{
804 for (const int offset : mSwizzleOffsets)
805 {
806 switch (offset)
807 {
808 case 0:
809 *out << "x";
810 break;
811 case 1:
812 *out << "y";
813 break;
814 case 2:
815 *out << "z";
816 break;
817 case 3:
818 *out << "w";
819 break;
820 default:
821 UNREACHABLE();
822 }
823 }
824}
825
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100826TQualifier TIntermBinary::GetCommaQualifier(int shaderVersion,
827 const TIntermTyped *left,
828 const TIntermTyped *right)
829{
830 // ESSL3.00 section 12.43: The result of a sequence operator is not a constant-expression.
831 if (shaderVersion >= 300 || left->getQualifier() != EvqConst ||
832 right->getQualifier() != EvqConst)
833 {
834 return EvqTemporary;
835 }
836 return EvqConst;
837}
Olli Etuahob6fa0432016-09-28 16:28:05 +0100838
839// Establishes the type of the result of the binary operation.
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300840void TIntermBinary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -0400841{
Olli Etuaho1dded802016-08-18 18:13:13 +0300842 ASSERT(!isMultiplication() ||
843 mOp == GetMulOpBasedOnOperands(mLeft->getType(), mRight->getType()));
844
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100845 // Comma is handled as a special case.
846 if (mOp == EOpComma)
847 {
848 setType(mRight->getType());
849 return;
850 }
851
Jamie Madillb1a85f42014-08-19 15:23:24 -0400852 // Base assumption: just make the type the same as the left
853 // operand. Then only deviations from this need be coded.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400854 setType(mLeft->getType());
855
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200856 TQualifier resultQualifier = EvqConst;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400857 // Binary operations results in temporary variables unless both
858 // operands are const.
859 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
860 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200861 resultQualifier = EvqTemporary;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400862 getTypePointer()->setQualifier(EvqTemporary);
863 }
864
Olli Etuaho3272a6d2016-08-29 17:54:50 +0300865 // Handle indexing ops.
866 switch (mOp)
867 {
868 case EOpIndexDirect:
869 case EOpIndexIndirect:
870 if (mLeft->isArray())
871 {
872 mType.clearArrayness();
873 }
874 else if (mLeft->isMatrix())
875 {
876 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier,
877 static_cast<unsigned char>(mLeft->getRows())));
878 }
879 else if (mLeft->isVector())
880 {
881 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier));
882 }
883 else
884 {
885 UNREACHABLE();
886 }
887 return;
888 case EOpIndexDirectStruct:
889 {
890 const TFieldList &fields = mLeft->getType().getStruct()->fields();
891 const int i = mRight->getAsConstantUnion()->getIConst(0);
892 setType(*fields[i]->type());
893 getTypePointer()->setQualifier(resultQualifier);
894 return;
895 }
896 case EOpIndexDirectInterfaceBlock:
897 {
898 const TFieldList &fields = mLeft->getType().getInterfaceBlock()->fields();
899 const int i = mRight->getAsConstantUnion()->getIConst(0);
900 setType(*fields[i]->type());
901 getTypePointer()->setQualifier(resultQualifier);
902 return;
903 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +0300904 default:
905 break;
906 }
907
908 ASSERT(mLeft->isArray() == mRight->isArray());
909
910 // The result gets promoted to the highest precision.
911 TPrecision higherPrecision = GetHigherPrecision(mLeft->getPrecision(), mRight->getPrecision());
912 getTypePointer()->setPrecision(higherPrecision);
913
Jamie Madillb1a85f42014-08-19 15:23:24 -0400914 const int nominalSize =
915 std::max(mLeft->getNominalSize(), mRight->getNominalSize());
916
917 //
918 // All scalars or structs. Code after this test assumes this case is removed!
919 //
920 if (nominalSize == 1)
921 {
922 switch (mOp)
923 {
924 //
925 // Promote to conditional
926 //
927 case EOpEqual:
928 case EOpNotEqual:
929 case EOpLessThan:
930 case EOpGreaterThan:
931 case EOpLessThanEqual:
932 case EOpGreaterThanEqual:
Olli Etuaho3272a6d2016-08-29 17:54:50 +0300933 setType(TType(EbtBool, EbpUndefined, resultQualifier));
934 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400935
936 //
937 // And and Or operate on conditionals
938 //
939 case EOpLogicalAnd:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200940 case EOpLogicalXor:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400941 case EOpLogicalOr:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200942 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
Olli Etuahoc9550582016-08-29 17:56:22 +0300943 setType(TType(EbtBool, EbpUndefined, resultQualifier));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400944 break;
945
946 default:
947 break;
948 }
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300949 return;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400950 }
951
952 // If we reach here, at least one of the operands is vector or matrix.
953 // The other operand could be a scalar, vector, or matrix.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400954 TBasicType basicType = mLeft->getBasicType();
Olli Etuaho1dded802016-08-18 18:13:13 +0300955
Jamie Madillb1a85f42014-08-19 15:23:24 -0400956 switch (mOp)
957 {
Olli Etuaho1dded802016-08-18 18:13:13 +0300958 case EOpMul:
959 break;
960 case EOpMatrixTimesScalar:
961 if (mRight->isMatrix())
Jamie Madillb1a85f42014-08-19 15:23:24 -0400962 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200963 setType(TType(basicType, higherPrecision, resultQualifier,
964 static_cast<unsigned char>(mRight->getCols()),
965 static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400966 }
Olli Etuaho1dded802016-08-18 18:13:13 +0300967 break;
968 case EOpMatrixTimesVector:
969 setType(TType(basicType, higherPrecision, resultQualifier,
970 static_cast<unsigned char>(mLeft->getRows()), 1));
971 break;
972 case EOpMatrixTimesMatrix:
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200973 setType(TType(basicType, higherPrecision, resultQualifier,
974 static_cast<unsigned char>(mRight->getCols()),
975 static_cast<unsigned char>(mLeft->getRows())));
Olli Etuaho1dded802016-08-18 18:13:13 +0300976 break;
977 case EOpVectorTimesScalar:
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200978 setType(TType(basicType, higherPrecision, resultQualifier,
Olli Etuaho1dded802016-08-18 18:13:13 +0300979 static_cast<unsigned char>(nominalSize), 1));
980 break;
981 case EOpVectorTimesMatrix:
982 setType(TType(basicType, higherPrecision, resultQualifier,
983 static_cast<unsigned char>(mRight->getCols()), 1));
984 break;
985 case EOpMulAssign:
986 case EOpVectorTimesScalarAssign:
987 case EOpVectorTimesMatrixAssign:
988 case EOpMatrixTimesScalarAssign:
989 case EOpMatrixTimesMatrixAssign:
990 ASSERT(mOp == GetMulAssignOpBasedOnOperands(mLeft->getType(), mRight->getType()));
991 break;
992 case EOpAssign:
993 case EOpInitialize:
Olli Etuaho1dded802016-08-18 18:13:13 +0300994 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
995 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
996 break;
997 case EOpAdd:
998 case EOpSub:
999 case EOpDiv:
1000 case EOpIMod:
1001 case EOpBitShiftLeft:
1002 case EOpBitShiftRight:
1003 case EOpBitwiseAnd:
1004 case EOpBitwiseXor:
1005 case EOpBitwiseOr:
1006 case EOpAddAssign:
1007 case EOpSubAssign:
1008 case EOpDivAssign:
1009 case EOpIModAssign:
1010 case EOpBitShiftLeftAssign:
1011 case EOpBitShiftRightAssign:
1012 case EOpBitwiseAndAssign:
1013 case EOpBitwiseXorAssign:
1014 case EOpBitwiseOrAssign:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001015 {
1016 const int secondarySize =
1017 std::max(mLeft->getSecondarySize(), mRight->getSecondarySize());
1018 setType(TType(basicType, higherPrecision, resultQualifier,
1019 static_cast<unsigned char>(nominalSize),
1020 static_cast<unsigned char>(secondarySize)));
1021 ASSERT(!mLeft->isArray() && !mRight->isArray());
Olli Etuaho1dded802016-08-18 18:13:13 +03001022 break;
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001023 }
Olli Etuaho1dded802016-08-18 18:13:13 +03001024 case EOpEqual:
1025 case EOpNotEqual:
1026 case EOpLessThan:
1027 case EOpGreaterThan:
1028 case EOpLessThanEqual:
1029 case EOpGreaterThanEqual:
1030 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1031 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001032 setType(TType(EbtBool, EbpUndefined, resultQualifier));
Olli Etuaho1dded802016-08-18 18:13:13 +03001033 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001034
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001035 case EOpIndexDirect:
1036 case EOpIndexIndirect:
1037 case EOpIndexDirectInterfaceBlock:
1038 case EOpIndexDirectStruct:
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001039 // These ops should be already fully handled.
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001040 UNREACHABLE();
1041 break;
Olli Etuaho1dded802016-08-18 18:13:13 +03001042 default:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001043 UNREACHABLE();
1044 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001045 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04001046}
1047
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001048const TConstantUnion *TIntermConstantUnion::foldIndexing(int index)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001049{
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001050 if (isArray())
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001051 {
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001052 ASSERT(index < static_cast<int>(getType().getArraySize()));
1053 TType arrayElementType = getType();
1054 arrayElementType.clearArrayness();
1055 size_t arrayElementSize = arrayElementType.getObjectSize();
1056 return &mUnionArrayPointer[arrayElementSize * index];
1057 }
1058 else if (isMatrix())
1059 {
1060 ASSERT(index < getType().getCols());
1061 int size = getType().getRows();
1062 return &mUnionArrayPointer[size * index];
1063 }
1064 else if (isVector())
1065 {
1066 ASSERT(index < getType().getNominalSize());
1067 return &mUnionArrayPointer[index];
1068 }
1069 else
1070 {
1071 UNREACHABLE();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001072 return nullptr;
1073 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001074}
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001075
Olli Etuahob6fa0432016-09-28 16:28:05 +01001076TIntermTyped *TIntermSwizzle::fold()
1077{
1078 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1079 if (operandConstant == nullptr)
1080 {
1081 return nullptr;
1082 }
1083
1084 TConstantUnion *constArray = new TConstantUnion[mSwizzleOffsets.size()];
1085 for (size_t i = 0; i < mSwizzleOffsets.size(); ++i)
1086 {
1087 constArray[i] = *operandConstant->foldIndexing(mSwizzleOffsets.at(i));
1088 }
1089 return CreateFoldedNode(constArray, this, mType.getQualifier());
1090}
1091
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001092TIntermTyped *TIntermBinary::fold(TDiagnostics *diagnostics)
1093{
1094 TIntermConstantUnion *leftConstant = mLeft->getAsConstantUnion();
1095 TIntermConstantUnion *rightConstant = mRight->getAsConstantUnion();
1096 switch (mOp)
1097 {
1098 case EOpIndexDirect:
1099 {
1100 if (leftConstant == nullptr || rightConstant == nullptr)
1101 {
1102 return nullptr;
1103 }
1104 int index = rightConstant->getIConst(0);
1105
1106 const TConstantUnion *constArray = leftConstant->foldIndexing(index);
1107 return CreateFoldedNode(constArray, this, mType.getQualifier());
1108 }
1109 case EOpIndexDirectStruct:
1110 {
1111 if (leftConstant == nullptr || rightConstant == nullptr)
1112 {
1113 return nullptr;
1114 }
1115 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1116 size_t index = static_cast<size_t>(rightConstant->getIConst(0));
1117
1118 size_t previousFieldsSize = 0;
1119 for (size_t i = 0; i < index; ++i)
1120 {
1121 previousFieldsSize += fields[i]->type()->getObjectSize();
1122 }
1123
1124 const TConstantUnion *constArray = leftConstant->getUnionArrayPointer();
1125 return CreateFoldedNode(constArray + previousFieldsSize, this, mType.getQualifier());
1126 }
1127 case EOpIndexIndirect:
1128 case EOpIndexDirectInterfaceBlock:
1129 // Can never be constant folded.
1130 return nullptr;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001131 default:
1132 {
1133 if (leftConstant == nullptr || rightConstant == nullptr)
1134 {
1135 return nullptr;
1136 }
Jamie Madill5db69f52016-09-15 12:47:32 -04001137 TConstantUnion *constArray =
1138 leftConstant->foldBinary(mOp, rightConstant, diagnostics, mLeft->getLine());
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001139
1140 // Nodes may be constant folded without being qualified as constant.
1141 return CreateFoldedNode(constArray, this, mType.getQualifier());
1142 }
1143 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001144}
1145
Olli Etuahof119a262016-08-19 15:54:22 +03001146TIntermTyped *TIntermUnary::fold(TDiagnostics *diagnostics)
Olli Etuaho95310b02015-06-02 17:43:38 +03001147{
1148 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1149 if (operandConstant == nullptr)
1150 {
1151 return nullptr;
1152 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301153
1154 TConstantUnion *constArray = nullptr;
1155 switch (mOp)
1156 {
1157 case EOpAny:
1158 case EOpAll:
1159 case EOpLength:
1160 case EOpTranspose:
1161 case EOpDeterminant:
1162 case EOpInverse:
1163 case EOpPackSnorm2x16:
1164 case EOpUnpackSnorm2x16:
1165 case EOpPackUnorm2x16:
1166 case EOpUnpackUnorm2x16:
1167 case EOpPackHalf2x16:
1168 case EOpUnpackHalf2x16:
Olli Etuahof119a262016-08-19 15:54:22 +03001169 constArray = operandConstant->foldUnaryNonComponentWise(mOp);
1170 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301171 default:
Olli Etuahof119a262016-08-19 15:54:22 +03001172 constArray = operandConstant->foldUnaryComponentWise(mOp, diagnostics);
1173 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301174 }
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001175
1176 // Nodes may be constant folded without being qualified as constant.
Olli Etuahoc9550582016-08-29 17:56:22 +03001177 return CreateFoldedNode(constArray, this, mType.getQualifier());
Olli Etuahob43846e2015-06-02 18:18:57 +03001178}
1179
Olli Etuahof119a262016-08-19 15:54:22 +03001180TIntermTyped *TIntermAggregate::fold(TDiagnostics *diagnostics)
Olli Etuahob43846e2015-06-02 18:18:57 +03001181{
1182 // Make sure that all params are constant before actual constant folding.
1183 for (auto *param : *getSequence())
Olli Etuaho95310b02015-06-02 17:43:38 +03001184 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001185 if (param->getAsConstantUnion() == nullptr)
1186 {
1187 return nullptr;
1188 }
Olli Etuaho95310b02015-06-02 17:43:38 +03001189 }
Olli Etuaho1d122782015-11-06 15:35:17 +02001190 TConstantUnion *constArray = nullptr;
1191 if (isConstructor())
Olli Etuahof119a262016-08-19 15:54:22 +03001192 constArray = TIntermConstantUnion::FoldAggregateConstructor(this);
Olli Etuaho1d122782015-11-06 15:35:17 +02001193 else
Olli Etuahof119a262016-08-19 15:54:22 +03001194 constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, diagnostics);
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001195
1196 // Nodes may be constant folded without being qualified as constant.
1197 TQualifier resultQualifier = areChildrenConstQualified() ? EvqConst : EvqTemporary;
1198 return CreateFoldedNode(constArray, this, resultQualifier);
Olli Etuaho95310b02015-06-02 17:43:38 +03001199}
1200
Jamie Madillb1a85f42014-08-19 15:23:24 -04001201//
1202// The fold functions see if an operation on a constant can be done in place,
1203// without generating run-time code.
1204//
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001205// Returns the constant value to keep using or nullptr.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001206//
Olli Etuaho3fdec912016-08-18 15:08:06 +03001207TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op,
1208 TIntermConstantUnion *rightNode,
Jamie Madill5db69f52016-09-15 12:47:32 -04001209 TDiagnostics *diagnostics,
1210 const TSourceLoc &line)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001211{
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001212 const TConstantUnion *leftArray = getUnionArrayPointer();
1213 const TConstantUnion *rightArray = rightNode->getUnionArrayPointer();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001214
Olli Etuahof119a262016-08-19 15:54:22 +03001215 ASSERT(leftArray && rightArray);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001216
1217 size_t objectSize = getType().getObjectSize();
1218
1219 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
1220 if (rightNode->getType().getObjectSize() == 1 && objectSize > 1)
1221 {
1222 rightArray = Vectorize(*rightNode->getUnionArrayPointer(), objectSize);
1223 }
1224 else if (rightNode->getType().getObjectSize() > 1 && objectSize == 1)
1225 {
1226 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
1227 leftArray = Vectorize(*getUnionArrayPointer(), rightNode->getType().getObjectSize());
1228 objectSize = rightNode->getType().getObjectSize();
1229 }
1230
1231 TConstantUnion *resultArray = nullptr;
1232
1233 switch(op)
1234 {
1235 case EOpAdd:
1236 resultArray = new TConstantUnion[objectSize];
1237 for (size_t i = 0; i < objectSize; i++)
Jamie Madill5db69f52016-09-15 12:47:32 -04001238 resultArray[i] = TConstantUnion::add(leftArray[i], rightArray[i], diagnostics, line);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001239 break;
1240 case EOpSub:
1241 resultArray = new TConstantUnion[objectSize];
1242 for (size_t i = 0; i < objectSize; i++)
Jamie Madill5db69f52016-09-15 12:47:32 -04001243 resultArray[i] = TConstantUnion::sub(leftArray[i], rightArray[i], diagnostics, line);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001244 break;
1245
1246 case EOpMul:
1247 case EOpVectorTimesScalar:
1248 case EOpMatrixTimesScalar:
1249 resultArray = new TConstantUnion[objectSize];
1250 for (size_t i = 0; i < objectSize; i++)
Jamie Madill5db69f52016-09-15 12:47:32 -04001251 resultArray[i] = TConstantUnion::mul(leftArray[i], rightArray[i], diagnostics, line);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001252 break;
1253
1254 case EOpMatrixTimesMatrix:
1255 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001256 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001257 ASSERT(getType().getBasicType() == EbtFloat && rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001258
1259 const int leftCols = getCols();
1260 const int leftRows = getRows();
1261 const int rightCols = rightNode->getType().getCols();
1262 const int rightRows = rightNode->getType().getRows();
1263 const int resultCols = rightCols;
1264 const int resultRows = leftRows;
1265
1266 resultArray = new TConstantUnion[resultCols * resultRows];
1267 for (int row = 0; row < resultRows; row++)
1268 {
1269 for (int column = 0; column < resultCols; column++)
1270 {
1271 resultArray[resultRows * column + row].setFConst(0.0f);
1272 for (int i = 0; i < leftCols; i++)
1273 {
1274 resultArray[resultRows * column + row].setFConst(
1275 resultArray[resultRows * column + row].getFConst() +
1276 leftArray[i * leftRows + row].getFConst() *
1277 rightArray[column * rightRows + i].getFConst());
1278 }
1279 }
1280 }
1281 }
1282 break;
1283
1284 case EOpDiv:
1285 case EOpIMod:
1286 {
1287 resultArray = new TConstantUnion[objectSize];
1288 for (size_t i = 0; i < objectSize; i++)
1289 {
1290 switch (getType().getBasicType())
1291 {
1292 case EbtFloat:
1293 if (rightArray[i] == 0.0f)
1294 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001295 diagnostics->warning(
1296 getLine(), "Divide by zero error during constant folding", "/", "");
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001297 resultArray[i].setFConst(leftArray[i].getFConst() < 0 ? -FLT_MAX : FLT_MAX);
1298 }
1299 else
1300 {
1301 ASSERT(op == EOpDiv);
1302 resultArray[i].setFConst(leftArray[i].getFConst() / rightArray[i].getFConst());
1303 }
1304 break;
1305
1306 case EbtInt:
1307 if (rightArray[i] == 0)
1308 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001309 diagnostics->warning(
1310 getLine(), "Divide by zero error during constant folding", "/", "");
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001311 resultArray[i].setIConst(INT_MAX);
1312 }
1313 else
1314 {
Olli Etuahod4453572016-09-27 13:21:46 +01001315 int lhs = leftArray[i].getIConst();
1316 int divisor = rightArray[i].getIConst();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001317 if (op == EOpDiv)
1318 {
Olli Etuahod4453572016-09-27 13:21:46 +01001319 // Check for the special case where the minimum representable number is
1320 // divided by -1. If left alone this leads to integer overflow in C++.
1321 // ESSL 3.00.6 section 4.1.3 Integers:
1322 // "However, for the case where the minimum representable value is
1323 // divided by -1, it is allowed to return either the minimum
1324 // representable value or the maximum representable value."
1325 if (lhs == -0x7fffffff - 1 && divisor == -1)
1326 {
1327 resultArray[i].setIConst(0x7fffffff);
1328 }
1329 else
1330 {
1331 resultArray[i].setIConst(lhs / divisor);
1332 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001333 }
1334 else
1335 {
1336 ASSERT(op == EOpIMod);
Olli Etuahod4453572016-09-27 13:21:46 +01001337 if (lhs < 0 || divisor < 0)
1338 {
1339 // ESSL 3.00.6 section 5.9: Results of modulus are undefined when
1340 // either one of the operands is negative.
1341 diagnostics->warning(getLine(),
1342 "Negative modulus operator operand "
1343 "encountered during constant folding",
1344 "%", "");
1345 resultArray[i].setIConst(0);
1346 }
1347 else
1348 {
1349 resultArray[i].setIConst(lhs % divisor);
1350 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001351 }
1352 }
1353 break;
1354
1355 case EbtUInt:
1356 if (rightArray[i] == 0)
1357 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001358 diagnostics->warning(
1359 getLine(), "Divide by zero error during constant folding", "/", "");
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001360 resultArray[i].setUConst(UINT_MAX);
1361 }
1362 else
1363 {
1364 if (op == EOpDiv)
1365 {
1366 resultArray[i].setUConst(leftArray[i].getUConst() / rightArray[i].getUConst());
1367 }
1368 else
1369 {
1370 ASSERT(op == EOpIMod);
1371 resultArray[i].setUConst(leftArray[i].getUConst() % rightArray[i].getUConst());
1372 }
1373 }
1374 break;
1375
1376 default:
Olli Etuaho3fdec912016-08-18 15:08:06 +03001377 UNREACHABLE();
1378 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001379 }
1380 }
1381 }
1382 break;
1383
1384 case EOpMatrixTimesVector:
1385 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001386 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001387 ASSERT(rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001388
1389 const int matrixCols = getCols();
1390 const int matrixRows = getRows();
1391
1392 resultArray = new TConstantUnion[matrixRows];
1393
1394 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1395 {
1396 resultArray[matrixRow].setFConst(0.0f);
1397 for (int col = 0; col < matrixCols; col++)
1398 {
1399 resultArray[matrixRow].setFConst(resultArray[matrixRow].getFConst() +
1400 leftArray[col * matrixRows + matrixRow].getFConst() *
1401 rightArray[col].getFConst());
1402 }
1403 }
1404 }
1405 break;
1406
1407 case EOpVectorTimesMatrix:
1408 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001409 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001410 ASSERT(getType().getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001411
1412 const int matrixCols = rightNode->getType().getCols();
1413 const int matrixRows = rightNode->getType().getRows();
1414
1415 resultArray = new TConstantUnion[matrixCols];
1416
1417 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
1418 {
1419 resultArray[matrixCol].setFConst(0.0f);
1420 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1421 {
1422 resultArray[matrixCol].setFConst(resultArray[matrixCol].getFConst() +
1423 leftArray[matrixRow].getFConst() *
1424 rightArray[matrixCol * matrixRows + matrixRow].getFConst());
1425 }
1426 }
1427 }
1428 break;
1429
1430 case EOpLogicalAnd:
1431 {
1432 resultArray = new TConstantUnion[objectSize];
1433 for (size_t i = 0; i < objectSize; i++)
1434 {
1435 resultArray[i] = leftArray[i] && rightArray[i];
1436 }
1437 }
1438 break;
1439
1440 case EOpLogicalOr:
1441 {
1442 resultArray = new TConstantUnion[objectSize];
1443 for (size_t i = 0; i < objectSize; i++)
1444 {
1445 resultArray[i] = leftArray[i] || rightArray[i];
1446 }
1447 }
1448 break;
1449
1450 case EOpLogicalXor:
1451 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001452 ASSERT(getType().getBasicType() == EbtBool);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001453 resultArray = new TConstantUnion[objectSize];
1454 for (size_t i = 0; i < objectSize; i++)
1455 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001456 resultArray[i].setBConst(leftArray[i] != rightArray[i]);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001457 }
1458 }
1459 break;
1460
1461 case EOpBitwiseAnd:
1462 resultArray = new TConstantUnion[objectSize];
1463 for (size_t i = 0; i < objectSize; i++)
1464 resultArray[i] = leftArray[i] & rightArray[i];
1465 break;
1466 case EOpBitwiseXor:
1467 resultArray = new TConstantUnion[objectSize];
1468 for (size_t i = 0; i < objectSize; i++)
1469 resultArray[i] = leftArray[i] ^ rightArray[i];
1470 break;
1471 case EOpBitwiseOr:
1472 resultArray = new TConstantUnion[objectSize];
1473 for (size_t i = 0; i < objectSize; i++)
1474 resultArray[i] = leftArray[i] | rightArray[i];
1475 break;
1476 case EOpBitShiftLeft:
1477 resultArray = new TConstantUnion[objectSize];
1478 for (size_t i = 0; i < objectSize; i++)
Jamie Madill596018c2016-09-21 12:57:03 -04001479 resultArray[i] = TConstantUnion::lshift(leftArray[i], rightArray[i], diagnostics, line);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001480 break;
1481 case EOpBitShiftRight:
1482 resultArray = new TConstantUnion[objectSize];
1483 for (size_t i = 0; i < objectSize; i++)
Jamie Madill596018c2016-09-21 12:57:03 -04001484 resultArray[i] = TConstantUnion::rshift(leftArray[i], rightArray[i], diagnostics, line);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001485 break;
1486
1487 case EOpLessThan:
1488 ASSERT(objectSize == 1);
1489 resultArray = new TConstantUnion[1];
1490 resultArray->setBConst(*leftArray < *rightArray);
1491 break;
1492
1493 case EOpGreaterThan:
1494 ASSERT(objectSize == 1);
1495 resultArray = new TConstantUnion[1];
1496 resultArray->setBConst(*leftArray > *rightArray);
1497 break;
1498
1499 case EOpLessThanEqual:
1500 ASSERT(objectSize == 1);
1501 resultArray = new TConstantUnion[1];
1502 resultArray->setBConst(!(*leftArray > *rightArray));
1503 break;
1504
1505 case EOpGreaterThanEqual:
1506 ASSERT(objectSize == 1);
1507 resultArray = new TConstantUnion[1];
1508 resultArray->setBConst(!(*leftArray < *rightArray));
1509 break;
1510
1511 case EOpEqual:
1512 case EOpNotEqual:
1513 {
1514 resultArray = new TConstantUnion[1];
1515 bool equal = true;
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001516 for (size_t i = 0; i < objectSize; i++)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001517 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001518 if (leftArray[i] != rightArray[i])
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001519 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001520 equal = false;
1521 break; // break out of for loop
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001522 }
1523 }
1524 if (op == EOpEqual)
1525 {
1526 resultArray->setBConst(equal);
1527 }
1528 else
1529 {
1530 resultArray->setBConst(!equal);
1531 }
1532 }
1533 break;
1534
1535 default:
Olli Etuaho3fdec912016-08-18 15:08:06 +03001536 UNREACHABLE();
1537 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001538 }
1539 return resultArray;
1540}
1541
Olli Etuahof119a262016-08-19 15:54:22 +03001542// The fold functions do operations on a constant at GLSL compile time, without generating run-time
1543// code. Returns the constant value to keep using. Nullptr should not be returned.
1544TConstantUnion *TIntermConstantUnion::foldUnaryNonComponentWise(TOperator op)
Jamie Madillb1a85f42014-08-19 15:23:24 -04001545{
Olli Etuahof119a262016-08-19 15:54:22 +03001546 // Do operations where the return type may have a different number of components compared to the
1547 // operand type.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001548
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001549 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuahof119a262016-08-19 15:54:22 +03001550 ASSERT(operandArray);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301551
1552 size_t objectSize = getType().getObjectSize();
1553 TConstantUnion *resultArray = nullptr;
1554 switch (op)
1555 {
Olli Etuahof119a262016-08-19 15:54:22 +03001556 case EOpAny:
1557 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301558 resultArray = new TConstantUnion();
1559 resultArray->setBConst(false);
1560 for (size_t i = 0; i < objectSize; i++)
1561 {
1562 if (operandArray[i].getBConst())
1563 {
1564 resultArray->setBConst(true);
1565 break;
1566 }
1567 }
1568 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301569
Olli Etuahof119a262016-08-19 15:54:22 +03001570 case EOpAll:
1571 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301572 resultArray = new TConstantUnion();
1573 resultArray->setBConst(true);
1574 for (size_t i = 0; i < objectSize; i++)
1575 {
1576 if (!operandArray[i].getBConst())
1577 {
1578 resultArray->setBConst(false);
1579 break;
1580 }
1581 }
1582 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301583
Olli Etuahof119a262016-08-19 15:54:22 +03001584 case EOpLength:
1585 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301586 resultArray = new TConstantUnion();
1587 resultArray->setFConst(VectorLength(operandArray, objectSize));
1588 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301589
Olli Etuahof119a262016-08-19 15:54:22 +03001590 case EOpTranspose:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301591 {
Olli Etuahof119a262016-08-19 15:54:22 +03001592 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301593 resultArray = new TConstantUnion[objectSize];
1594 angle::Matrix<float> result =
Olli Etuahod5da5052016-08-29 13:16:55 +03001595 GetMatrix(operandArray, getType().getRows(), getType().getCols()).transpose();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301596 SetUnionArrayFromMatrix(result, resultArray);
1597 break;
1598 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301599
Olli Etuahof119a262016-08-19 15:54:22 +03001600 case EOpDeterminant:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301601 {
Olli Etuahof119a262016-08-19 15:54:22 +03001602 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301603 unsigned int size = getType().getNominalSize();
1604 ASSERT(size >= 2 && size <= 4);
1605 resultArray = new TConstantUnion();
1606 resultArray->setFConst(GetMatrix(operandArray, size).determinant());
1607 break;
1608 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301609
Olli Etuahof119a262016-08-19 15:54:22 +03001610 case EOpInverse:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301611 {
Olli Etuahof119a262016-08-19 15:54:22 +03001612 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301613 unsigned int size = getType().getNominalSize();
1614 ASSERT(size >= 2 && size <= 4);
Olli Etuahof119a262016-08-19 15:54:22 +03001615 resultArray = new TConstantUnion[objectSize];
Arun Patoleab2b9a22015-07-06 18:27:56 +05301616 angle::Matrix<float> result = GetMatrix(operandArray, size).inverse();
1617 SetUnionArrayFromMatrix(result, resultArray);
1618 break;
1619 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301620
Olli Etuahof119a262016-08-19 15:54:22 +03001621 case EOpPackSnorm2x16:
1622 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301623 ASSERT(getType().getNominalSize() == 2);
1624 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001625 resultArray->setUConst(
1626 gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301627 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301628
Olli Etuahof119a262016-08-19 15:54:22 +03001629 case EOpUnpackSnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301630 {
Olli Etuahof119a262016-08-19 15:54:22 +03001631 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301632 resultArray = new TConstantUnion[2];
1633 float f1, f2;
1634 gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1635 resultArray[0].setFConst(f1);
1636 resultArray[1].setFConst(f2);
1637 break;
1638 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301639
Olli Etuahof119a262016-08-19 15:54:22 +03001640 case EOpPackUnorm2x16:
1641 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301642 ASSERT(getType().getNominalSize() == 2);
1643 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001644 resultArray->setUConst(
1645 gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301646 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301647
Olli Etuahof119a262016-08-19 15:54:22 +03001648 case EOpUnpackUnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301649 {
Olli Etuahof119a262016-08-19 15:54:22 +03001650 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301651 resultArray = new TConstantUnion[2];
1652 float f1, f2;
1653 gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1654 resultArray[0].setFConst(f1);
1655 resultArray[1].setFConst(f2);
1656 break;
1657 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301658
Olli Etuahof119a262016-08-19 15:54:22 +03001659 case EOpPackHalf2x16:
1660 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301661 ASSERT(getType().getNominalSize() == 2);
1662 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001663 resultArray->setUConst(
1664 gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301665 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301666
Olli Etuahof119a262016-08-19 15:54:22 +03001667 case EOpUnpackHalf2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301668 {
Olli Etuahof119a262016-08-19 15:54:22 +03001669 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301670 resultArray = new TConstantUnion[2];
1671 float f1, f2;
1672 gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2);
1673 resultArray[0].setFConst(f1);
1674 resultArray[1].setFConst(f2);
1675 break;
1676 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301677
Olli Etuahof119a262016-08-19 15:54:22 +03001678 default:
1679 UNREACHABLE();
1680 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301681 }
1682
1683 return resultArray;
1684}
1685
Olli Etuahof119a262016-08-19 15:54:22 +03001686TConstantUnion *TIntermConstantUnion::foldUnaryComponentWise(TOperator op,
1687 TDiagnostics *diagnostics)
Arun Patoleab2b9a22015-07-06 18:27:56 +05301688{
Olli Etuahof119a262016-08-19 15:54:22 +03001689 // Do unary operations where each component of the result is computed based on the corresponding
1690 // component of the operand. Also folds normalize, though the divisor in that case takes all
1691 // components into account.
Arun Patoleab2b9a22015-07-06 18:27:56 +05301692
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001693 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuahof119a262016-08-19 15:54:22 +03001694 ASSERT(operandArray);
Jamie Madillb1a85f42014-08-19 15:23:24 -04001695
1696 size_t objectSize = getType().getObjectSize();
1697
Arun Patoleab2b9a22015-07-06 18:27:56 +05301698 TConstantUnion *resultArray = new TConstantUnion[objectSize];
1699 for (size_t i = 0; i < objectSize; i++)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301700 {
Arun Patoleab2b9a22015-07-06 18:27:56 +05301701 switch(op)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301702 {
Olli Etuahof119a262016-08-19 15:54:22 +03001703 case EOpNegative:
1704 switch (getType().getBasicType())
1705 {
1706 case EbtFloat:
1707 resultArray[i].setFConst(-operandArray[i].getFConst());
1708 break;
1709 case EbtInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01001710 if (operandArray[i] == std::numeric_limits<int>::min())
1711 {
1712 // The minimum representable integer doesn't have a positive
1713 // counterpart, rather the negation overflows and in ESSL is supposed to
1714 // wrap back to the minimum representable integer. Make sure that we
1715 // don't actually let the negation overflow, which has undefined
1716 // behavior in C++.
1717 resultArray[i].setIConst(std::numeric_limits<int>::min());
1718 }
1719 else
1720 {
1721 resultArray[i].setIConst(-operandArray[i].getIConst());
1722 }
Olli Etuahof119a262016-08-19 15:54:22 +03001723 break;
1724 case EbtUInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01001725 if (operandArray[i] == 0x80000000u)
1726 {
1727 resultArray[i].setUConst(0x80000000u);
1728 }
1729 else
1730 {
1731 resultArray[i].setUConst(static_cast<unsigned int>(
1732 -static_cast<int>(operandArray[i].getUConst())));
1733 }
Olli Etuahof119a262016-08-19 15:54:22 +03001734 break;
1735 default:
1736 UNREACHABLE();
1737 return nullptr;
1738 }
Arun Patole1155ddd2015-06-05 18:04:36 +05301739 break;
Arun Patolecdfa8f52015-06-30 17:48:25 +05301740
Olli Etuahof119a262016-08-19 15:54:22 +03001741 case EOpPositive:
1742 switch (getType().getBasicType())
1743 {
1744 case EbtFloat:
1745 resultArray[i].setFConst(operandArray[i].getFConst());
1746 break;
1747 case EbtInt:
1748 resultArray[i].setIConst(operandArray[i].getIConst());
1749 break;
1750 case EbtUInt:
1751 resultArray[i].setUConst(static_cast<unsigned int>(
1752 static_cast<int>(operandArray[i].getUConst())));
1753 break;
1754 default:
1755 UNREACHABLE();
1756 return nullptr;
1757 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301758 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301759
Olli Etuahof119a262016-08-19 15:54:22 +03001760 case EOpLogicalNot:
1761 switch (getType().getBasicType())
1762 {
1763 case EbtBool:
1764 resultArray[i].setBConst(!operandArray[i].getBConst());
1765 break;
1766 default:
1767 UNREACHABLE();
1768 return nullptr;
1769 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301770 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301771
Olli Etuahof119a262016-08-19 15:54:22 +03001772 case EOpBitwiseNot:
1773 switch (getType().getBasicType())
1774 {
1775 case EbtInt:
1776 resultArray[i].setIConst(~operandArray[i].getIConst());
1777 break;
1778 case EbtUInt:
1779 resultArray[i].setUConst(~operandArray[i].getUConst());
1780 break;
1781 default:
1782 UNREACHABLE();
1783 return nullptr;
1784 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301785 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301786
Olli Etuahof119a262016-08-19 15:54:22 +03001787 case EOpRadians:
1788 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301789 resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
1790 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301791
Olli Etuahof119a262016-08-19 15:54:22 +03001792 case EOpDegrees:
1793 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301794 resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
1795 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301796
Olli Etuahof119a262016-08-19 15:54:22 +03001797 case EOpSin:
1798 foldFloatTypeUnary(operandArray[i], &sinf, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301799 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301800
Olli Etuahof119a262016-08-19 15:54:22 +03001801 case EOpCos:
1802 foldFloatTypeUnary(operandArray[i], &cosf, &resultArray[i]);
1803 break;
1804
1805 case EOpTan:
1806 foldFloatTypeUnary(operandArray[i], &tanf, &resultArray[i]);
1807 break;
1808
1809 case EOpAsin:
1810 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to
1811 // 0.
1812 if (fabsf(operandArray[i].getFConst()) > 1.0f)
1813 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1814 diagnostics, &resultArray[i]);
1815 else
1816 foldFloatTypeUnary(operandArray[i], &asinf, &resultArray[i]);
1817 break;
1818
1819 case EOpAcos:
1820 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to
1821 // 0.
1822 if (fabsf(operandArray[i].getFConst()) > 1.0f)
1823 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1824 diagnostics, &resultArray[i]);
1825 else
1826 foldFloatTypeUnary(operandArray[i], &acosf, &resultArray[i]);
1827 break;
1828
1829 case EOpAtan:
1830 foldFloatTypeUnary(operandArray[i], &atanf, &resultArray[i]);
1831 break;
1832
1833 case EOpSinh:
1834 foldFloatTypeUnary(operandArray[i], &sinhf, &resultArray[i]);
1835 break;
1836
1837 case EOpCosh:
1838 foldFloatTypeUnary(operandArray[i], &coshf, &resultArray[i]);
1839 break;
1840
1841 case EOpTanh:
1842 foldFloatTypeUnary(operandArray[i], &tanhf, &resultArray[i]);
1843 break;
1844
1845 case EOpAsinh:
1846 foldFloatTypeUnary(operandArray[i], &asinhf, &resultArray[i]);
1847 break;
1848
1849 case EOpAcosh:
1850 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
1851 if (operandArray[i].getFConst() < 1.0f)
1852 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1853 diagnostics, &resultArray[i]);
1854 else
1855 foldFloatTypeUnary(operandArray[i], &acoshf, &resultArray[i]);
1856 break;
1857
1858 case EOpAtanh:
1859 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to
1860 // 0.
1861 if (fabsf(operandArray[i].getFConst()) >= 1.0f)
1862 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1863 diagnostics, &resultArray[i]);
1864 else
1865 foldFloatTypeUnary(operandArray[i], &atanhf, &resultArray[i]);
1866 break;
1867
1868 case EOpAbs:
1869 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05301870 {
Olli Etuahof119a262016-08-19 15:54:22 +03001871 case EbtFloat:
1872 resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
1873 break;
1874 case EbtInt:
1875 resultArray[i].setIConst(abs(operandArray[i].getIConst()));
1876 break;
1877 default:
1878 UNREACHABLE();
1879 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301880 }
1881 break;
Olli Etuahof119a262016-08-19 15:54:22 +03001882
1883 case EOpSign:
1884 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05301885 {
Olli Etuahof119a262016-08-19 15:54:22 +03001886 case EbtFloat:
1887 {
1888 float fConst = operandArray[i].getFConst();
1889 float fResult = 0.0f;
1890 if (fConst > 0.0f)
1891 fResult = 1.0f;
1892 else if (fConst < 0.0f)
1893 fResult = -1.0f;
1894 resultArray[i].setFConst(fResult);
1895 break;
1896 }
1897 case EbtInt:
1898 {
1899 int iConst = operandArray[i].getIConst();
1900 int iResult = 0;
1901 if (iConst > 0)
1902 iResult = 1;
1903 else if (iConst < 0)
1904 iResult = -1;
1905 resultArray[i].setIConst(iResult);
1906 break;
1907 }
1908 default:
1909 UNREACHABLE();
1910 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301911 }
1912 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301913
Olli Etuahof119a262016-08-19 15:54:22 +03001914 case EOpFloor:
1915 foldFloatTypeUnary(operandArray[i], &floorf, &resultArray[i]);
1916 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301917
Olli Etuahof119a262016-08-19 15:54:22 +03001918 case EOpTrunc:
1919 foldFloatTypeUnary(operandArray[i], &truncf, &resultArray[i]);
1920 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301921
Olli Etuahof119a262016-08-19 15:54:22 +03001922 case EOpRound:
1923 foldFloatTypeUnary(operandArray[i], &roundf, &resultArray[i]);
1924 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301925
Olli Etuahof119a262016-08-19 15:54:22 +03001926 case EOpRoundEven:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301927 {
Olli Etuahof119a262016-08-19 15:54:22 +03001928 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301929 float x = operandArray[i].getFConst();
1930 float result;
1931 float fractPart = modff(x, &result);
1932 if (fabsf(fractPart) == 0.5f)
1933 result = 2.0f * roundf(x / 2.0f);
1934 else
1935 result = roundf(x);
1936 resultArray[i].setFConst(result);
1937 break;
1938 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301939
Olli Etuahof119a262016-08-19 15:54:22 +03001940 case EOpCeil:
1941 foldFloatTypeUnary(operandArray[i], &ceilf, &resultArray[i]);
1942 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301943
Olli Etuahof119a262016-08-19 15:54:22 +03001944 case EOpFract:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301945 {
Olli Etuahof119a262016-08-19 15:54:22 +03001946 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301947 float x = operandArray[i].getFConst();
1948 resultArray[i].setFConst(x - floorf(x));
1949 break;
1950 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301951
Olli Etuahof119a262016-08-19 15:54:22 +03001952 case EOpIsNan:
1953 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05301954 resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst()));
1955 break;
Arun Patole551279e2015-07-07 18:18:23 +05301956
Olli Etuahof119a262016-08-19 15:54:22 +03001957 case EOpIsInf:
1958 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05301959 resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst()));
1960 break;
Arun Patole551279e2015-07-07 18:18:23 +05301961
Olli Etuahof119a262016-08-19 15:54:22 +03001962 case EOpFloatBitsToInt:
1963 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05301964 resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst()));
1965 break;
Arun Patole551279e2015-07-07 18:18:23 +05301966
Olli Etuahof119a262016-08-19 15:54:22 +03001967 case EOpFloatBitsToUint:
1968 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05301969 resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst()));
1970 break;
Arun Patole551279e2015-07-07 18:18:23 +05301971
Olli Etuahof119a262016-08-19 15:54:22 +03001972 case EOpIntBitsToFloat:
1973 ASSERT(getType().getBasicType() == EbtInt);
Arun Patole551279e2015-07-07 18:18:23 +05301974 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst()));
1975 break;
Arun Patole551279e2015-07-07 18:18:23 +05301976
Olli Etuahof119a262016-08-19 15:54:22 +03001977 case EOpUintBitsToFloat:
1978 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patole551279e2015-07-07 18:18:23 +05301979 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst()));
1980 break;
Arun Patole551279e2015-07-07 18:18:23 +05301981
Olli Etuahof119a262016-08-19 15:54:22 +03001982 case EOpExp:
1983 foldFloatTypeUnary(operandArray[i], &expf, &resultArray[i]);
1984 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301985
Olli Etuahof119a262016-08-19 15:54:22 +03001986 case EOpLog:
1987 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
1988 if (operandArray[i].getFConst() <= 0.0f)
1989 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1990 diagnostics, &resultArray[i]);
1991 else
1992 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
1993 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301994
Olli Etuahof119a262016-08-19 15:54:22 +03001995 case EOpExp2:
1996 foldFloatTypeUnary(operandArray[i], &exp2f, &resultArray[i]);
1997 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301998
Olli Etuahof119a262016-08-19 15:54:22 +03001999 case EOpLog2:
2000 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
2001 // And log2f is not available on some plarforms like old android, so just using
2002 // log(x)/log(2) here.
2003 if (operandArray[i].getFConst() <= 0.0f)
2004 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2005 diagnostics, &resultArray[i]);
2006 else
2007 {
2008 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2009 resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
2010 }
2011 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302012
Olli Etuahof119a262016-08-19 15:54:22 +03002013 case EOpSqrt:
2014 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
2015 if (operandArray[i].getFConst() < 0.0f)
2016 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2017 diagnostics, &resultArray[i]);
2018 else
2019 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2020 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302021
Olli Etuahof119a262016-08-19 15:54:22 +03002022 case EOpInverseSqrt:
2023 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
2024 // so getting the square root first using builtin function sqrt() and then taking
2025 // its inverse.
2026 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set
2027 // result to 0.
2028 if (operandArray[i].getFConst() <= 0.0f)
2029 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2030 diagnostics, &resultArray[i]);
2031 else
2032 {
2033 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2034 resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
2035 }
2036 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302037
Olli Etuahof119a262016-08-19 15:54:22 +03002038 case EOpVectorLogicalNot:
2039 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302040 resultArray[i].setBConst(!operandArray[i].getBConst());
2041 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302042
Olli Etuahof119a262016-08-19 15:54:22 +03002043 case EOpNormalize:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302044 {
Olli Etuahof119a262016-08-19 15:54:22 +03002045 ASSERT(getType().getBasicType() == EbtFloat);
2046 float x = operandArray[i].getFConst();
Arun Patoleab2b9a22015-07-06 18:27:56 +05302047 float length = VectorLength(operandArray, objectSize);
2048 if (length)
2049 resultArray[i].setFConst(x / length);
2050 else
Olli Etuahof119a262016-08-19 15:54:22 +03002051 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2052 diagnostics, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302053 break;
2054 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302055
Olli Etuahof119a262016-08-19 15:54:22 +03002056 case EOpDFdx:
2057 case EOpDFdy:
2058 case EOpFwidth:
2059 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole0c5409f2015-07-08 15:17:53 +05302060 // Derivatives of constant arguments should be 0.
2061 resultArray[i].setFConst(0.0f);
2062 break;
Arun Patole0c5409f2015-07-08 15:17:53 +05302063
Olli Etuahof119a262016-08-19 15:54:22 +03002064 default:
2065 return nullptr;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302066 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302067 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04002068
Arun Patoleab2b9a22015-07-06 18:27:56 +05302069 return resultArray;
Jamie Madillb1a85f42014-08-19 15:23:24 -04002070}
2071
Olli Etuahof119a262016-08-19 15:54:22 +03002072void TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter,
2073 FloatTypeUnaryFunc builtinFunc,
2074 TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05302075{
2076 ASSERT(builtinFunc);
2077
Olli Etuahof119a262016-08-19 15:54:22 +03002078 ASSERT(getType().getBasicType() == EbtFloat);
2079 result->setFConst(builtinFunc(parameter.getFConst()));
Arun Patole9dea48f2015-04-02 11:45:09 +05302080}
2081
Jamie Madillb1a85f42014-08-19 15:23:24 -04002082// static
Olli Etuahof119a262016-08-19 15:54:22 +03002083TConstantUnion *TIntermConstantUnion::FoldAggregateConstructor(TIntermAggregate *aggregate)
Olli Etuaho1d122782015-11-06 15:35:17 +02002084{
2085 ASSERT(aggregate->getSequence()->size() > 0u);
2086 size_t resultSize = aggregate->getType().getObjectSize();
2087 TConstantUnion *resultArray = new TConstantUnion[resultSize];
2088 TBasicType basicType = aggregate->getBasicType();
2089
2090 size_t resultIndex = 0u;
2091
2092 if (aggregate->getSequence()->size() == 1u)
2093 {
2094 TIntermNode *argument = aggregate->getSequence()->front();
2095 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
2096 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
2097 // Check the special case of constructing a matrix diagonal from a single scalar,
2098 // or a vector from a single scalar.
2099 if (argumentConstant->getType().getObjectSize() == 1u)
2100 {
2101 if (aggregate->isMatrix())
2102 {
2103 int resultCols = aggregate->getType().getCols();
2104 int resultRows = aggregate->getType().getRows();
2105 for (int col = 0; col < resultCols; ++col)
2106 {
2107 for (int row = 0; row < resultRows; ++row)
2108 {
2109 if (col == row)
2110 {
2111 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
2112 }
2113 else
2114 {
2115 resultArray[resultIndex].setFConst(0.0f);
2116 }
2117 ++resultIndex;
2118 }
2119 }
2120 }
2121 else
2122 {
2123 while (resultIndex < resultSize)
2124 {
2125 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
2126 ++resultIndex;
2127 }
2128 }
2129 ASSERT(resultIndex == resultSize);
2130 return resultArray;
2131 }
2132 else if (aggregate->isMatrix() && argumentConstant->isMatrix())
2133 {
2134 // The special case of constructing a matrix from a matrix.
2135 int argumentCols = argumentConstant->getType().getCols();
2136 int argumentRows = argumentConstant->getType().getRows();
2137 int resultCols = aggregate->getType().getCols();
2138 int resultRows = aggregate->getType().getRows();
2139 for (int col = 0; col < resultCols; ++col)
2140 {
2141 for (int row = 0; row < resultRows; ++row)
2142 {
2143 if (col < argumentCols && row < argumentRows)
2144 {
2145 resultArray[resultIndex].cast(basicType,
2146 argumentUnionArray[col * argumentRows + row]);
2147 }
2148 else if (col == row)
2149 {
2150 resultArray[resultIndex].setFConst(1.0f);
2151 }
2152 else
2153 {
2154 resultArray[resultIndex].setFConst(0.0f);
2155 }
2156 ++resultIndex;
2157 }
2158 }
2159 ASSERT(resultIndex == resultSize);
2160 return resultArray;
2161 }
2162 }
2163
2164 for (TIntermNode *&argument : *aggregate->getSequence())
2165 {
2166 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
2167 size_t argumentSize = argumentConstant->getType().getObjectSize();
2168 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
2169 for (size_t i = 0u; i < argumentSize; ++i)
2170 {
2171 if (resultIndex >= resultSize)
2172 break;
2173 resultArray[resultIndex].cast(basicType, argumentUnionArray[i]);
2174 ++resultIndex;
2175 }
2176 }
2177 ASSERT(resultIndex == resultSize);
2178 return resultArray;
2179}
2180
2181// static
Olli Etuahof119a262016-08-19 15:54:22 +03002182TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate,
2183 TDiagnostics *diagnostics)
Arun Patole274f0702015-05-05 13:33:30 +05302184{
Olli Etuahob43846e2015-06-02 18:18:57 +03002185 TOperator op = aggregate->getOp();
Arun Patole274f0702015-05-05 13:33:30 +05302186 TIntermSequence *sequence = aggregate->getSequence();
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002187 unsigned int paramsCount = static_cast<unsigned int>(sequence->size());
Olli Etuaho5c0e0232015-11-11 15:55:59 +02002188 std::vector<const TConstantUnion *> unionArrays(paramsCount);
Arun Patole274f0702015-05-05 13:33:30 +05302189 std::vector<size_t> objectSizes(paramsCount);
Olli Etuahob43846e2015-06-02 18:18:57 +03002190 size_t maxObjectSize = 0;
Arun Patole274f0702015-05-05 13:33:30 +05302191 TBasicType basicType = EbtVoid;
2192 TSourceLoc loc;
2193 for (unsigned int i = 0; i < paramsCount; i++)
2194 {
2195 TIntermConstantUnion *paramConstant = (*sequence)[i]->getAsConstantUnion();
Olli Etuahob43846e2015-06-02 18:18:57 +03002196 ASSERT(paramConstant != nullptr); // Should be checked already.
Arun Patole274f0702015-05-05 13:33:30 +05302197
2198 if (i == 0)
2199 {
2200 basicType = paramConstant->getType().getBasicType();
2201 loc = paramConstant->getLine();
2202 }
2203 unionArrays[i] = paramConstant->getUnionArrayPointer();
2204 objectSizes[i] = paramConstant->getType().getObjectSize();
Olli Etuahob43846e2015-06-02 18:18:57 +03002205 if (objectSizes[i] > maxObjectSize)
2206 maxObjectSize = objectSizes[i];
Arun Patole274f0702015-05-05 13:33:30 +05302207 }
2208
Olli Etuahod5da5052016-08-29 13:16:55 +03002209 if (!(*sequence)[0]->getAsTyped()->isMatrix() && aggregate->getOp() != EOpOuterProduct)
Arun Patole7fa33552015-06-10 15:15:18 +05302210 {
2211 for (unsigned int i = 0; i < paramsCount; i++)
2212 if (objectSizes[i] != maxObjectSize)
2213 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
2214 }
Arun Patole274f0702015-05-05 13:33:30 +05302215
Olli Etuahob43846e2015-06-02 18:18:57 +03002216 TConstantUnion *resultArray = nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05302217 if (paramsCount == 2)
2218 {
2219 //
2220 // Binary built-in
2221 //
2222 switch (op)
2223 {
Olli Etuahof119a262016-08-19 15:54:22 +03002224 case EOpAtan:
Arun Patolebf790422015-05-18 17:53:04 +05302225 {
Olli Etuahof119a262016-08-19 15:54:22 +03002226 ASSERT(basicType == EbtFloat);
2227 resultArray = new TConstantUnion[maxObjectSize];
2228 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302229 {
Olli Etuahof119a262016-08-19 15:54:22 +03002230 float y = unionArrays[0][i].getFConst();
2231 float x = unionArrays[1][i].getFConst();
2232 // Results are undefined if x and y are both 0.
2233 if (x == 0.0f && y == 0.0f)
2234 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2235 &resultArray[i]);
2236 else
2237 resultArray[i].setFConst(atan2f(y, x));
Arun Patolebf790422015-05-18 17:53:04 +05302238 }
Olli Etuahof119a262016-08-19 15:54:22 +03002239 break;
Arun Patolebf790422015-05-18 17:53:04 +05302240 }
Arun Patolebf790422015-05-18 17:53:04 +05302241
Olli Etuahof119a262016-08-19 15:54:22 +03002242 case EOpPow:
Arun Patolebf790422015-05-18 17:53:04 +05302243 {
Olli Etuahof119a262016-08-19 15:54:22 +03002244 ASSERT(basicType == EbtFloat);
2245 resultArray = new TConstantUnion[maxObjectSize];
2246 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302247 {
Olli Etuahof119a262016-08-19 15:54:22 +03002248 float x = unionArrays[0][i].getFConst();
2249 float y = unionArrays[1][i].getFConst();
2250 // Results are undefined if x < 0.
2251 // Results are undefined if x = 0 and y <= 0.
2252 if (x < 0.0f)
2253 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2254 &resultArray[i]);
2255 else if (x == 0.0f && y <= 0.0f)
2256 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2257 &resultArray[i]);
2258 else
2259 resultArray[i].setFConst(powf(x, y));
Arun Patolebf790422015-05-18 17:53:04 +05302260 }
Olli Etuahof119a262016-08-19 15:54:22 +03002261 break;
Arun Patolebf790422015-05-18 17:53:04 +05302262 }
Arun Patolebf790422015-05-18 17:53:04 +05302263
Olli Etuahof119a262016-08-19 15:54:22 +03002264 case EOpMod:
Arun Patolebf790422015-05-18 17:53:04 +05302265 {
Olli Etuahof119a262016-08-19 15:54:22 +03002266 ASSERT(basicType == EbtFloat);
2267 resultArray = new TConstantUnion[maxObjectSize];
2268 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302269 {
Olli Etuahof119a262016-08-19 15:54:22 +03002270 float x = unionArrays[0][i].getFConst();
2271 float y = unionArrays[1][i].getFConst();
2272 resultArray[i].setFConst(x - y * floorf(x / y));
Arun Patolebf790422015-05-18 17:53:04 +05302273 }
Olli Etuahof119a262016-08-19 15:54:22 +03002274 break;
Arun Patolebf790422015-05-18 17:53:04 +05302275 }
Arun Patolebf790422015-05-18 17:53:04 +05302276
Olli Etuahof119a262016-08-19 15:54:22 +03002277 case EOpMin:
Arun Patole274f0702015-05-05 13:33:30 +05302278 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002279 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302280 for (size_t i = 0; i < maxObjectSize; i++)
2281 {
2282 switch (basicType)
2283 {
Olli Etuahof119a262016-08-19 15:54:22 +03002284 case EbtFloat:
2285 resultArray[i].setFConst(std::min(unionArrays[0][i].getFConst(),
2286 unionArrays[1][i].getFConst()));
2287 break;
2288 case EbtInt:
2289 resultArray[i].setIConst(std::min(unionArrays[0][i].getIConst(),
2290 unionArrays[1][i].getIConst()));
2291 break;
2292 case EbtUInt:
2293 resultArray[i].setUConst(std::min(unionArrays[0][i].getUConst(),
2294 unionArrays[1][i].getUConst()));
2295 break;
2296 default:
2297 UNREACHABLE();
2298 break;
Arun Patole274f0702015-05-05 13:33:30 +05302299 }
2300 }
Olli Etuahof119a262016-08-19 15:54:22 +03002301 break;
Arun Patole274f0702015-05-05 13:33:30 +05302302 }
Arun Patole274f0702015-05-05 13:33:30 +05302303
Olli Etuahof119a262016-08-19 15:54:22 +03002304 case EOpMax:
Arun Patole274f0702015-05-05 13:33:30 +05302305 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002306 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302307 for (size_t i = 0; i < maxObjectSize; i++)
2308 {
2309 switch (basicType)
2310 {
Olli Etuahof119a262016-08-19 15:54:22 +03002311 case EbtFloat:
2312 resultArray[i].setFConst(std::max(unionArrays[0][i].getFConst(),
2313 unionArrays[1][i].getFConst()));
2314 break;
2315 case EbtInt:
2316 resultArray[i].setIConst(std::max(unionArrays[0][i].getIConst(),
2317 unionArrays[1][i].getIConst()));
2318 break;
2319 case EbtUInt:
2320 resultArray[i].setUConst(std::max(unionArrays[0][i].getUConst(),
2321 unionArrays[1][i].getUConst()));
2322 break;
2323 default:
2324 UNREACHABLE();
2325 break;
Arun Patole274f0702015-05-05 13:33:30 +05302326 }
2327 }
Olli Etuahof119a262016-08-19 15:54:22 +03002328 break;
Arun Patole274f0702015-05-05 13:33:30 +05302329 }
Arun Patole274f0702015-05-05 13:33:30 +05302330
Olli Etuahof119a262016-08-19 15:54:22 +03002331 case EOpStep:
Arun Patolebf790422015-05-18 17:53:04 +05302332 {
Olli Etuahof119a262016-08-19 15:54:22 +03002333 ASSERT(basicType == EbtFloat);
2334 resultArray = new TConstantUnion[maxObjectSize];
2335 for (size_t i = 0; i < maxObjectSize; i++)
2336 resultArray[i].setFConst(
2337 unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f
2338 : 1.0f);
2339 break;
Arun Patolebf790422015-05-18 17:53:04 +05302340 }
Arun Patolebf790422015-05-18 17:53:04 +05302341
Olli Etuahof119a262016-08-19 15:54:22 +03002342 case EOpLessThan:
Arun Patole9d0b1f92015-05-20 14:27:17 +05302343 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002344 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302345 for (size_t i = 0; i < maxObjectSize; i++)
2346 {
2347 switch (basicType)
2348 {
Olli Etuahof119a262016-08-19 15:54:22 +03002349 case EbtFloat:
2350 resultArray[i].setBConst(unionArrays[0][i].getFConst() <
2351 unionArrays[1][i].getFConst());
2352 break;
2353 case EbtInt:
2354 resultArray[i].setBConst(unionArrays[0][i].getIConst() <
2355 unionArrays[1][i].getIConst());
2356 break;
2357 case EbtUInt:
2358 resultArray[i].setBConst(unionArrays[0][i].getUConst() <
2359 unionArrays[1][i].getUConst());
2360 break;
2361 default:
2362 UNREACHABLE();
2363 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302364 }
2365 }
Olli Etuahof119a262016-08-19 15:54:22 +03002366 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302367 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302368
Olli Etuahof119a262016-08-19 15:54:22 +03002369 case EOpLessThanEqual:
Arun Patole9d0b1f92015-05-20 14:27:17 +05302370 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002371 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302372 for (size_t i = 0; i < maxObjectSize; i++)
2373 {
2374 switch (basicType)
2375 {
Olli Etuahof119a262016-08-19 15:54:22 +03002376 case EbtFloat:
2377 resultArray[i].setBConst(unionArrays[0][i].getFConst() <=
2378 unionArrays[1][i].getFConst());
2379 break;
2380 case EbtInt:
2381 resultArray[i].setBConst(unionArrays[0][i].getIConst() <=
2382 unionArrays[1][i].getIConst());
2383 break;
2384 case EbtUInt:
2385 resultArray[i].setBConst(unionArrays[0][i].getUConst() <=
2386 unionArrays[1][i].getUConst());
2387 break;
2388 default:
2389 UNREACHABLE();
2390 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302391 }
2392 }
Olli Etuahof119a262016-08-19 15:54:22 +03002393 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302394 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302395
Olli Etuahof119a262016-08-19 15:54:22 +03002396 case EOpGreaterThan:
Arun Patole9d0b1f92015-05-20 14:27:17 +05302397 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002398 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302399 for (size_t i = 0; i < maxObjectSize; i++)
2400 {
2401 switch (basicType)
2402 {
Olli Etuahof119a262016-08-19 15:54:22 +03002403 case EbtFloat:
2404 resultArray[i].setBConst(unionArrays[0][i].getFConst() >
2405 unionArrays[1][i].getFConst());
2406 break;
2407 case EbtInt:
2408 resultArray[i].setBConst(unionArrays[0][i].getIConst() >
2409 unionArrays[1][i].getIConst());
2410 break;
2411 case EbtUInt:
2412 resultArray[i].setBConst(unionArrays[0][i].getUConst() >
2413 unionArrays[1][i].getUConst());
2414 break;
2415 default:
2416 UNREACHABLE();
2417 break;
Olli Etuahob43846e2015-06-02 18:18:57 +03002418 }
2419 }
Olli Etuahof119a262016-08-19 15:54:22 +03002420 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302421 }
Olli Etuahof119a262016-08-19 15:54:22 +03002422 case EOpGreaterThanEqual:
Arun Patole9d0b1f92015-05-20 14:27:17 +05302423 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002424 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302425 for (size_t i = 0; i < maxObjectSize; i++)
2426 {
2427 switch (basicType)
2428 {
Olli Etuahof119a262016-08-19 15:54:22 +03002429 case EbtFloat:
2430 resultArray[i].setBConst(unionArrays[0][i].getFConst() >=
2431 unionArrays[1][i].getFConst());
2432 break;
2433 case EbtInt:
2434 resultArray[i].setBConst(unionArrays[0][i].getIConst() >=
2435 unionArrays[1][i].getIConst());
2436 break;
2437 case EbtUInt:
2438 resultArray[i].setBConst(unionArrays[0][i].getUConst() >=
2439 unionArrays[1][i].getUConst());
2440 break;
2441 default:
2442 UNREACHABLE();
2443 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302444 }
2445 }
2446 }
2447 break;
2448
Olli Etuahof119a262016-08-19 15:54:22 +03002449 case EOpVectorEqual:
Arun Patole9d0b1f92015-05-20 14:27:17 +05302450 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002451 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302452 for (size_t i = 0; i < maxObjectSize; i++)
2453 {
2454 switch (basicType)
2455 {
Olli Etuahof119a262016-08-19 15:54:22 +03002456 case EbtFloat:
2457 resultArray[i].setBConst(unionArrays[0][i].getFConst() ==
2458 unionArrays[1][i].getFConst());
2459 break;
2460 case EbtInt:
2461 resultArray[i].setBConst(unionArrays[0][i].getIConst() ==
2462 unionArrays[1][i].getIConst());
2463 break;
2464 case EbtUInt:
2465 resultArray[i].setBConst(unionArrays[0][i].getUConst() ==
2466 unionArrays[1][i].getUConst());
2467 break;
2468 case EbtBool:
2469 resultArray[i].setBConst(unionArrays[0][i].getBConst() ==
2470 unionArrays[1][i].getBConst());
2471 break;
2472 default:
2473 UNREACHABLE();
2474 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302475 }
2476 }
Olli Etuahof119a262016-08-19 15:54:22 +03002477 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302478 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302479
Olli Etuahof119a262016-08-19 15:54:22 +03002480 case EOpVectorNotEqual:
Arun Patole9d0b1f92015-05-20 14:27:17 +05302481 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002482 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302483 for (size_t i = 0; i < maxObjectSize; i++)
2484 {
2485 switch (basicType)
2486 {
Olli Etuahof119a262016-08-19 15:54:22 +03002487 case EbtFloat:
2488 resultArray[i].setBConst(unionArrays[0][i].getFConst() !=
2489 unionArrays[1][i].getFConst());
2490 break;
2491 case EbtInt:
2492 resultArray[i].setBConst(unionArrays[0][i].getIConst() !=
2493 unionArrays[1][i].getIConst());
2494 break;
2495 case EbtUInt:
2496 resultArray[i].setBConst(unionArrays[0][i].getUConst() !=
2497 unionArrays[1][i].getUConst());
2498 break;
2499 case EbtBool:
2500 resultArray[i].setBConst(unionArrays[0][i].getBConst() !=
2501 unionArrays[1][i].getBConst());
2502 break;
2503 default:
2504 UNREACHABLE();
2505 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302506 }
2507 }
Olli Etuahof119a262016-08-19 15:54:22 +03002508 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302509 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302510
Olli Etuahof119a262016-08-19 15:54:22 +03002511 case EOpDistance:
Arun Patole1155ddd2015-06-05 18:04:36 +05302512 {
Olli Etuahof119a262016-08-19 15:54:22 +03002513 ASSERT(basicType == EbtFloat);
Arun Patole1155ddd2015-06-05 18:04:36 +05302514 TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
Olli Etuahof119a262016-08-19 15:54:22 +03002515 resultArray = new TConstantUnion();
Arun Patole1155ddd2015-06-05 18:04:36 +05302516 for (size_t i = 0; i < maxObjectSize; i++)
2517 {
2518 float x = unionArrays[0][i].getFConst();
2519 float y = unionArrays[1][i].getFConst();
2520 distanceArray[i].setFConst(x - y);
2521 }
Olli Etuahob43846e2015-06-02 18:18:57 +03002522 resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
Olli Etuahof119a262016-08-19 15:54:22 +03002523 break;
Arun Patole1155ddd2015-06-05 18:04:36 +05302524 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302525
Olli Etuahof119a262016-08-19 15:54:22 +03002526 case EOpDot:
2527 ASSERT(basicType == EbtFloat);
Olli Etuahob43846e2015-06-02 18:18:57 +03002528 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03002529 resultArray->setFConst(
2530 VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
2531 break;
Arun Patole1155ddd2015-06-05 18:04:36 +05302532
Olli Etuahof119a262016-08-19 15:54:22 +03002533 case EOpCross:
Arun Patole1155ddd2015-06-05 18:04:36 +05302534 {
Olli Etuahof119a262016-08-19 15:54:22 +03002535 ASSERT(basicType == EbtFloat && maxObjectSize == 3);
Olli Etuahob43846e2015-06-02 18:18:57 +03002536 resultArray = new TConstantUnion[maxObjectSize];
Olli Etuahof119a262016-08-19 15:54:22 +03002537 float x0 = unionArrays[0][0].getFConst();
2538 float x1 = unionArrays[0][1].getFConst();
2539 float x2 = unionArrays[0][2].getFConst();
2540 float y0 = unionArrays[1][0].getFConst();
2541 float y1 = unionArrays[1][1].getFConst();
2542 float y2 = unionArrays[1][2].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002543 resultArray[0].setFConst(x1 * y2 - y1 * x2);
2544 resultArray[1].setFConst(x2 * y0 - y2 * x0);
2545 resultArray[2].setFConst(x0 * y1 - y0 * x1);
Olli Etuahof119a262016-08-19 15:54:22 +03002546 break;
Arun Patole1155ddd2015-06-05 18:04:36 +05302547 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302548
Olli Etuahof119a262016-08-19 15:54:22 +03002549 case EOpReflect:
Arun Patole1155ddd2015-06-05 18:04:36 +05302550 {
Olli Etuahof119a262016-08-19 15:54:22 +03002551 ASSERT(basicType == EbtFloat);
Arun Patole1155ddd2015-06-05 18:04:36 +05302552 // genType reflect (genType I, genType N) :
Olli Etuahof119a262016-08-19 15:54:22 +03002553 // For the incident vector I and surface orientation N, returns the reflection
2554 // direction:
Arun Patole1155ddd2015-06-05 18:04:36 +05302555 // I - 2 * dot(N, I) * N.
Olli Etuahof119a262016-08-19 15:54:22 +03002556 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302557 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2558 for (size_t i = 0; i < maxObjectSize; i++)
2559 {
2560 float result = unionArrays[0][i].getFConst() -
2561 2.0f * dotProduct * unionArrays[1][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002562 resultArray[i].setFConst(result);
Arun Patole1155ddd2015-06-05 18:04:36 +05302563 }
Olli Etuahof119a262016-08-19 15:54:22 +03002564 break;
Arun Patole1155ddd2015-06-05 18:04:36 +05302565 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302566
Olli Etuahof119a262016-08-19 15:54:22 +03002567 case EOpMul:
Arun Patole7fa33552015-06-10 15:15:18 +05302568 {
Olli Etuahof119a262016-08-19 15:54:22 +03002569 ASSERT(basicType == EbtFloat && (*sequence)[0]->getAsTyped()->isMatrix() &&
2570 (*sequence)[1]->getAsTyped()->isMatrix());
Arun Patole7fa33552015-06-10 15:15:18 +05302571 // Perform component-wise matrix multiplication.
2572 resultArray = new TConstantUnion[maxObjectSize];
Olli Etuahof119a262016-08-19 15:54:22 +03002573 int size = (*sequence)[0]->getAsTyped()->getNominalSize();
Arun Patole7fa33552015-06-10 15:15:18 +05302574 angle::Matrix<float> result =
2575 GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size));
2576 SetUnionArrayFromMatrix(result, resultArray);
Olli Etuahof119a262016-08-19 15:54:22 +03002577 break;
Arun Patole7fa33552015-06-10 15:15:18 +05302578 }
Arun Patole7fa33552015-06-10 15:15:18 +05302579
Olli Etuahof119a262016-08-19 15:54:22 +03002580 case EOpOuterProduct:
Arun Patole7fa33552015-06-10 15:15:18 +05302581 {
Olli Etuahof119a262016-08-19 15:54:22 +03002582 ASSERT(basicType == EbtFloat);
Arun Patole7fa33552015-06-10 15:15:18 +05302583 size_t numRows = (*sequence)[0]->getAsTyped()->getType().getObjectSize();
2584 size_t numCols = (*sequence)[1]->getAsTyped()->getType().getObjectSize();
Olli Etuahof119a262016-08-19 15:54:22 +03002585 resultArray = new TConstantUnion[numRows * numCols];
Arun Patole7fa33552015-06-10 15:15:18 +05302586 angle::Matrix<float> result =
Olli Etuahod5da5052016-08-29 13:16:55 +03002587 GetMatrix(unionArrays[0], static_cast<int>(numRows), 1)
2588 .outerProduct(GetMatrix(unionArrays[1], 1, static_cast<int>(numCols)));
Arun Patole7fa33552015-06-10 15:15:18 +05302589 SetUnionArrayFromMatrix(result, resultArray);
Olli Etuahof119a262016-08-19 15:54:22 +03002590 break;
Arun Patole7fa33552015-06-10 15:15:18 +05302591 }
Arun Patole7fa33552015-06-10 15:15:18 +05302592
Olli Etuahof119a262016-08-19 15:54:22 +03002593 default:
2594 UNREACHABLE();
2595 // TODO: Add constant folding support for other built-in operations that take 2
2596 // parameters and not handled above.
2597 return nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05302598 }
2599 }
2600 else if (paramsCount == 3)
2601 {
2602 //
2603 // Ternary built-in
2604 //
2605 switch (op)
2606 {
Olli Etuahof119a262016-08-19 15:54:22 +03002607 case EOpClamp:
Arun Patole274f0702015-05-05 13:33:30 +05302608 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002609 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302610 for (size_t i = 0; i < maxObjectSize; i++)
2611 {
2612 switch (basicType)
2613 {
Olli Etuahof119a262016-08-19 15:54:22 +03002614 case EbtFloat:
Arun Patole274f0702015-05-05 13:33:30 +05302615 {
Olli Etuahof119a262016-08-19 15:54:22 +03002616 float x = unionArrays[0][i].getFConst();
Arun Patole274f0702015-05-05 13:33:30 +05302617 float min = unionArrays[1][i].getFConst();
2618 float max = unionArrays[2][i].getFConst();
2619 // Results are undefined if min > max.
2620 if (min > max)
Olli Etuahof119a262016-08-19 15:54:22 +03002621 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2622 &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302623 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002624 resultArray[i].setFConst(gl::clamp(x, min, max));
Olli Etuahof119a262016-08-19 15:54:22 +03002625 break;
Arun Patole274f0702015-05-05 13:33:30 +05302626 }
Olli Etuahof119a262016-08-19 15:54:22 +03002627
2628 case EbtInt:
Arun Patole274f0702015-05-05 13:33:30 +05302629 {
Olli Etuahof119a262016-08-19 15:54:22 +03002630 int x = unionArrays[0][i].getIConst();
Arun Patole274f0702015-05-05 13:33:30 +05302631 int min = unionArrays[1][i].getIConst();
2632 int max = unionArrays[2][i].getIConst();
2633 // Results are undefined if min > max.
2634 if (min > max)
Olli Etuahof119a262016-08-19 15:54:22 +03002635 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2636 &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302637 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002638 resultArray[i].setIConst(gl::clamp(x, min, max));
Olli Etuahof119a262016-08-19 15:54:22 +03002639 break;
Arun Patole274f0702015-05-05 13:33:30 +05302640 }
Olli Etuahof119a262016-08-19 15:54:22 +03002641 case EbtUInt:
Arun Patole274f0702015-05-05 13:33:30 +05302642 {
Olli Etuahof119a262016-08-19 15:54:22 +03002643 unsigned int x = unionArrays[0][i].getUConst();
Arun Patole274f0702015-05-05 13:33:30 +05302644 unsigned int min = unionArrays[1][i].getUConst();
2645 unsigned int max = unionArrays[2][i].getUConst();
2646 // Results are undefined if min > max.
2647 if (min > max)
Olli Etuahof119a262016-08-19 15:54:22 +03002648 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2649 &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302650 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002651 resultArray[i].setUConst(gl::clamp(x, min, max));
Olli Etuahof119a262016-08-19 15:54:22 +03002652 break;
Arun Patole274f0702015-05-05 13:33:30 +05302653 }
Olli Etuahof119a262016-08-19 15:54:22 +03002654 default:
2655 UNREACHABLE();
2656 break;
Arun Patole274f0702015-05-05 13:33:30 +05302657 }
2658 }
Olli Etuahof119a262016-08-19 15:54:22 +03002659 break;
Arun Patole274f0702015-05-05 13:33:30 +05302660 }
Arun Patole274f0702015-05-05 13:33:30 +05302661
Olli Etuahof119a262016-08-19 15:54:22 +03002662 case EOpMix:
Arun Patolebf790422015-05-18 17:53:04 +05302663 {
Olli Etuahof119a262016-08-19 15:54:22 +03002664 ASSERT(basicType == EbtFloat);
2665 resultArray = new TConstantUnion[maxObjectSize];
2666 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302667 {
Olli Etuahof119a262016-08-19 15:54:22 +03002668 float x = unionArrays[0][i].getFConst();
2669 float y = unionArrays[1][i].getFConst();
2670 TBasicType type = (*sequence)[2]->getAsTyped()->getType().getBasicType();
2671 if (type == EbtFloat)
Arun Patolebf790422015-05-18 17:53:04 +05302672 {
Olli Etuahof119a262016-08-19 15:54:22 +03002673 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
2674 float a = unionArrays[2][i].getFConst();
2675 resultArray[i].setFConst(x * (1.0f - a) + y * a);
2676 }
2677 else // 3rd parameter is EbtBool
2678 {
2679 ASSERT(type == EbtBool);
2680 // Selects which vector each returned component comes from.
2681 // For a component of a that is false, the corresponding component of x is
2682 // returned.
2683 // For a component of a that is true, the corresponding component of y is
2684 // returned.
2685 bool a = unionArrays[2][i].getBConst();
2686 resultArray[i].setFConst(a ? y : x);
Arun Patolebf790422015-05-18 17:53:04 +05302687 }
2688 }
Olli Etuahof119a262016-08-19 15:54:22 +03002689 break;
Arun Patolebf790422015-05-18 17:53:04 +05302690 }
Arun Patolebf790422015-05-18 17:53:04 +05302691
Olli Etuahof119a262016-08-19 15:54:22 +03002692 case EOpSmoothStep:
Arun Patolebf790422015-05-18 17:53:04 +05302693 {
Olli Etuahof119a262016-08-19 15:54:22 +03002694 ASSERT(basicType == EbtFloat);
2695 resultArray = new TConstantUnion[maxObjectSize];
2696 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302697 {
Olli Etuahof119a262016-08-19 15:54:22 +03002698 float edge0 = unionArrays[0][i].getFConst();
2699 float edge1 = unionArrays[1][i].getFConst();
2700 float x = unionArrays[2][i].getFConst();
2701 // Results are undefined if edge0 >= edge1.
2702 if (edge0 >= edge1)
Arun Patolebf790422015-05-18 17:53:04 +05302703 {
Olli Etuahof119a262016-08-19 15:54:22 +03002704 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2705 &resultArray[i]);
2706 }
2707 else
2708 {
2709 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
2710 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
2711 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
2712 resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
Arun Patolebf790422015-05-18 17:53:04 +05302713 }
2714 }
Olli Etuahof119a262016-08-19 15:54:22 +03002715 break;
Arun Patolebf790422015-05-18 17:53:04 +05302716 }
Arun Patolebf790422015-05-18 17:53:04 +05302717
Olli Etuahof119a262016-08-19 15:54:22 +03002718 case EOpFaceForward:
Arun Patole1155ddd2015-06-05 18:04:36 +05302719 {
Olli Etuahof119a262016-08-19 15:54:22 +03002720 ASSERT(basicType == EbtFloat);
Arun Patole1155ddd2015-06-05 18:04:36 +05302721 // genType faceforward(genType N, genType I, genType Nref) :
2722 // If dot(Nref, I) < 0 return N, otherwise return -N.
Olli Etuahof119a262016-08-19 15:54:22 +03002723 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302724 float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
2725 for (size_t i = 0; i < maxObjectSize; i++)
2726 {
2727 if (dotProduct < 0)
Olli Etuahob43846e2015-06-02 18:18:57 +03002728 resultArray[i].setFConst(unionArrays[0][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302729 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002730 resultArray[i].setFConst(-unionArrays[0][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302731 }
Olli Etuahof119a262016-08-19 15:54:22 +03002732 break;
Arun Patole1155ddd2015-06-05 18:04:36 +05302733 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302734
Olli Etuahof119a262016-08-19 15:54:22 +03002735 case EOpRefract:
Arun Patole1155ddd2015-06-05 18:04:36 +05302736 {
Olli Etuahof119a262016-08-19 15:54:22 +03002737 ASSERT(basicType == EbtFloat);
Arun Patole1155ddd2015-06-05 18:04:36 +05302738 // genType refract(genType I, genType N, float eta) :
Olli Etuahof119a262016-08-19 15:54:22 +03002739 // For the incident vector I and surface normal N, and the ratio of indices of
2740 // refraction eta,
Arun Patole1155ddd2015-06-05 18:04:36 +05302741 // return the refraction vector. The result is computed by
2742 // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
2743 // if (k < 0.0)
2744 // return genType(0.0)
2745 // else
2746 // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
Olli Etuahof119a262016-08-19 15:54:22 +03002747 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302748 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2749 for (size_t i = 0; i < maxObjectSize; i++)
2750 {
2751 float eta = unionArrays[2][i].getFConst();
Olli Etuahof119a262016-08-19 15:54:22 +03002752 float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
Arun Patole1155ddd2015-06-05 18:04:36 +05302753 if (k < 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03002754 resultArray[i].setFConst(0.0f);
Arun Patole1155ddd2015-06-05 18:04:36 +05302755 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002756 resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
Olli Etuahof119a262016-08-19 15:54:22 +03002757 (eta * dotProduct + sqrtf(k)) *
2758 unionArrays[1][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302759 }
Olli Etuahof119a262016-08-19 15:54:22 +03002760 break;
Arun Patole1155ddd2015-06-05 18:04:36 +05302761 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302762
Olli Etuahof119a262016-08-19 15:54:22 +03002763 default:
2764 UNREACHABLE();
2765 // TODO: Add constant folding support for other built-in operations that take 3
2766 // parameters and not handled above.
2767 return nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05302768 }
2769 }
Olli Etuahob43846e2015-06-02 18:18:57 +03002770 return resultArray;
Arun Patole274f0702015-05-05 13:33:30 +05302771}
2772
2773// static
Jamie Madillb1a85f42014-08-19 15:23:24 -04002774TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunction)
2775{
2776 if (hashFunction == NULL || name.empty())
2777 return name;
2778 khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
2779 TStringStream stream;
2780 stream << HASHED_NAME_PREFIX << std::hex << number;
2781 TString hashedName = stream.str();
2782 return hashedName;
2783}
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002784
2785void TIntermTraverser::updateTree()
2786{
Olli Etuahoa6f22092015-05-08 18:31:10 +03002787 for (size_t ii = 0; ii < mInsertions.size(); ++ii)
2788 {
2789 const NodeInsertMultipleEntry &insertion = mInsertions[ii];
2790 ASSERT(insertion.parent);
Olli Etuaho5d91dda2015-06-18 15:47:46 +03002791 if (!insertion.insertionsAfter.empty())
2792 {
2793 bool inserted = insertion.parent->insertChildNodes(insertion.position + 1,
2794 insertion.insertionsAfter);
2795 ASSERT(inserted);
2796 UNUSED_ASSERTION_VARIABLE(inserted);
2797 }
2798 if (!insertion.insertionsBefore.empty())
2799 {
2800 bool inserted =
2801 insertion.parent->insertChildNodes(insertion.position, insertion.insertionsBefore);
2802 ASSERT(inserted);
2803 UNUSED_ASSERTION_VARIABLE(inserted);
2804 }
Olli Etuahoa6f22092015-05-08 18:31:10 +03002805 }
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002806 for (size_t ii = 0; ii < mReplacements.size(); ++ii)
2807 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002808 const NodeUpdateEntry &replacement = mReplacements[ii];
2809 ASSERT(replacement.parent);
2810 bool replaced = replacement.parent->replaceChildNode(
2811 replacement.original, replacement.replacement);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002812 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03002813 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002814
Olli Etuahocd94ef92015-04-16 19:18:10 +03002815 if (!replacement.originalBecomesChildOfReplacement)
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002816 {
2817 // In AST traversing, a parent is visited before its children.
Olli Etuahocd94ef92015-04-16 19:18:10 +03002818 // After we replace a node, if its immediate child is to
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002819 // be replaced, we need to make sure we don't update the replaced
2820 // node; instead, we update the replacement node.
2821 for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj)
2822 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002823 NodeUpdateEntry &replacement2 = mReplacements[jj];
2824 if (replacement2.parent == replacement.original)
2825 replacement2.parent = replacement.replacement;
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002826 }
2827 }
2828 }
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002829 for (size_t ii = 0; ii < mMultiReplacements.size(); ++ii)
2830 {
2831 const NodeReplaceWithMultipleEntry &replacement = mMultiReplacements[ii];
2832 ASSERT(replacement.parent);
2833 bool replaced = replacement.parent->replaceChildNodeWithMultiple(
2834 replacement.original, replacement.replacements);
2835 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03002836 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002837 }
Olli Etuahod4f303e2015-05-20 17:09:06 +03002838
Jamie Madill03d863c2016-07-27 18:15:53 -04002839 clearReplacementQueue();
2840}
2841
2842void TIntermTraverser::clearReplacementQueue()
2843{
Olli Etuahod4f303e2015-05-20 17:09:06 +03002844 mReplacements.clear();
2845 mMultiReplacements.clear();
Jamie Madill03d863c2016-07-27 18:15:53 -04002846 mInsertions.clear();
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002847}
Jamie Madill1048e432016-07-23 18:51:28 -04002848
Jamie Madill03d863c2016-07-27 18:15:53 -04002849void TIntermTraverser::queueReplacement(TIntermNode *original,
2850 TIntermNode *replacement,
2851 OriginalNode originalStatus)
Jamie Madill1048e432016-07-23 18:51:28 -04002852{
Jamie Madill03d863c2016-07-27 18:15:53 -04002853 queueReplacementWithParent(getParentNode(), original, replacement, originalStatus);
Jamie Madill1048e432016-07-23 18:51:28 -04002854}
2855
Jamie Madill03d863c2016-07-27 18:15:53 -04002856void TIntermTraverser::queueReplacementWithParent(TIntermNode *parent,
2857 TIntermNode *original,
2858 TIntermNode *replacement,
2859 OriginalNode originalStatus)
Jamie Madill1048e432016-07-23 18:51:28 -04002860{
Jamie Madill03d863c2016-07-27 18:15:53 -04002861 bool originalBecomesChild = (originalStatus == OriginalNode::BECOMES_CHILD);
2862 mReplacements.push_back(NodeUpdateEntry(parent, original, replacement, originalBecomesChild));
Jamie Madill1048e432016-07-23 18:51:28 -04002863}