blob: 9d4cbbbd18f4e07295b842e80cbc9afc9389e541 [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
Jamie Madill45bcc782016-11-07 13:58:48 -050026namespace sh
27{
28
Jamie Madillb1a85f42014-08-19 15:23:24 -040029namespace
30{
31
Arun Patole9dea48f2015-04-02 11:45:09 +053032const float kPi = 3.14159265358979323846f;
33const float kDegreesToRadiansMultiplier = kPi / 180.0f;
34const float kRadiansToDegreesMultiplier = 180.0f / kPi;
35
Jamie Madillb1a85f42014-08-19 15:23:24 -040036TPrecision GetHigherPrecision(TPrecision left, TPrecision right)
37{
38 return left > right ? left : right;
39}
40
Arun Patole274f0702015-05-05 13:33:30 +053041TConstantUnion *Vectorize(const TConstantUnion &constant, size_t size)
42{
43 TConstantUnion *constUnion = new TConstantUnion[size];
44 for (unsigned int i = 0; i < size; ++i)
45 constUnion[i] = constant;
46
47 return constUnion;
48}
49
Olli Etuahof119a262016-08-19 15:54:22 +030050void UndefinedConstantFoldingError(const TSourceLoc &loc,
51 TOperator op,
52 TBasicType basicType,
53 TDiagnostics *diagnostics,
54 TConstantUnion *result)
Arun Patolebf790422015-05-18 17:53:04 +053055{
Olli Etuahof119a262016-08-19 15:54:22 +030056 diagnostics->warning(loc, "operation result is undefined for the values passed in",
57 GetOperatorString(op), "");
Arun Patolebf790422015-05-18 17:53:04 +053058
59 switch (basicType)
60 {
61 case EbtFloat :
62 result->setFConst(0.0f);
63 break;
64 case EbtInt:
65 result->setIConst(0);
66 break;
67 case EbtUInt:
68 result->setUConst(0u);
69 break;
70 case EbtBool:
71 result->setBConst(false);
72 break;
73 default:
74 break;
75 }
76}
77
Olli Etuaho5c0e0232015-11-11 15:55:59 +020078float VectorLength(const TConstantUnion *paramArray, size_t paramArraySize)
Arun Patole1155ddd2015-06-05 18:04:36 +053079{
80 float result = 0.0f;
81 for (size_t i = 0; i < paramArraySize; i++)
82 {
83 float f = paramArray[i].getFConst();
84 result += f * f;
85 }
86 return sqrtf(result);
87}
88
Olli Etuaho5c0e0232015-11-11 15:55:59 +020089float VectorDotProduct(const TConstantUnion *paramArray1,
90 const TConstantUnion *paramArray2,
91 size_t paramArraySize)
Arun Patole1155ddd2015-06-05 18:04:36 +053092{
93 float result = 0.0f;
94 for (size_t i = 0; i < paramArraySize; i++)
95 result += paramArray1[i].getFConst() * paramArray2[i].getFConst();
96 return result;
97}
98
Olli Etuaho3272a6d2016-08-29 17:54:50 +030099TIntermTyped *CreateFoldedNode(const TConstantUnion *constArray,
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200100 const TIntermTyped *originalNode,
101 TQualifier qualifier)
Olli Etuahob43846e2015-06-02 18:18:57 +0300102{
103 if (constArray == nullptr)
104 {
105 return nullptr;
106 }
107 TIntermTyped *folded = new TIntermConstantUnion(constArray, originalNode->getType());
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200108 folded->getTypePointer()->setQualifier(qualifier);
Olli Etuahob43846e2015-06-02 18:18:57 +0300109 folded->setLine(originalNode->getLine());
110 return folded;
111}
112
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200113angle::Matrix<float> GetMatrix(const TConstantUnion *paramArray,
114 const unsigned int &rows,
115 const unsigned int &cols)
Arun Patole7fa33552015-06-10 15:15:18 +0530116{
117 std::vector<float> elements;
118 for (size_t i = 0; i < rows * cols; i++)
119 elements.push_back(paramArray[i].getFConst());
120 // Transpose is used since the Matrix constructor expects arguments in row-major order,
Olli Etuahod5da5052016-08-29 13:16:55 +0300121 // whereas the paramArray is in column-major order. Rows/cols parameters are also flipped below
122 // so that the created matrix will have the expected dimensions after the transpose.
123 return angle::Matrix<float>(elements, cols, rows).transpose();
Arun Patole7fa33552015-06-10 15:15:18 +0530124}
125
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200126angle::Matrix<float> GetMatrix(const TConstantUnion *paramArray, const unsigned int &size)
Arun Patole7fa33552015-06-10 15:15:18 +0530127{
128 std::vector<float> elements;
129 for (size_t i = 0; i < size * size; i++)
130 elements.push_back(paramArray[i].getFConst());
131 // Transpose is used since the Matrix constructor expects arguments in row-major order,
132 // whereas the paramArray is in column-major order.
133 return angle::Matrix<float>(elements, size).transpose();
134}
135
136void SetUnionArrayFromMatrix(const angle::Matrix<float> &m, TConstantUnion *resultArray)
137{
138 // Transpose is used since the input Matrix is in row-major order,
139 // whereas the actual result should be in column-major order.
140 angle::Matrix<float> result = m.transpose();
141 std::vector<float> resultElements = result.elements();
142 for (size_t i = 0; i < resultElements.size(); i++)
143 resultArray[i].setFConst(resultElements[i]);
144}
145
Jamie Madillb1a85f42014-08-19 15:23:24 -0400146} // namespace anonymous
147
148
149////////////////////////////////////////////////////////////////
150//
151// Member functions of the nodes used for building the tree.
152//
153////////////////////////////////////////////////////////////////
154
Olli Etuahod2a67b92014-10-21 16:42:57 +0300155void TIntermTyped::setTypePreservePrecision(const TType &t)
156{
157 TPrecision precision = getPrecision();
158 mType = t;
159 ASSERT(mType.getBasicType() != EbtBool || precision == EbpUndefined);
160 mType.setPrecision(precision);
161}
162
Jamie Madillb1a85f42014-08-19 15:23:24 -0400163#define REPLACE_IF_IS(node, type, original, replacement) \
164 if (node == original) { \
165 node = static_cast<type *>(replacement); \
166 return true; \
167 }
168
169bool TIntermLoop::replaceChildNode(
170 TIntermNode *original, TIntermNode *replacement)
171{
Olli Etuaho3cbb27a2016-07-14 11:55:48 +0300172 ASSERT(original != nullptr); // This risks replacing multiple children.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400173 REPLACE_IF_IS(mInit, TIntermNode, original, replacement);
174 REPLACE_IF_IS(mCond, TIntermTyped, original, replacement);
175 REPLACE_IF_IS(mExpr, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100176 REPLACE_IF_IS(mBody, TIntermBlock, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400177 return false;
178}
179
Jamie Madillb1a85f42014-08-19 15:23:24 -0400180bool TIntermBranch::replaceChildNode(
181 TIntermNode *original, TIntermNode *replacement)
182{
183 REPLACE_IF_IS(mExpression, TIntermTyped, original, replacement);
184 return false;
185}
186
Olli Etuahob6fa0432016-09-28 16:28:05 +0100187bool TIntermSwizzle::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
188{
189 ASSERT(original->getAsTyped()->getType() == replacement->getAsTyped()->getType());
190 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
191 return false;
192}
193
Jamie Madillb1a85f42014-08-19 15:23:24 -0400194bool TIntermBinary::replaceChildNode(
195 TIntermNode *original, TIntermNode *replacement)
196{
197 REPLACE_IF_IS(mLeft, TIntermTyped, original, replacement);
198 REPLACE_IF_IS(mRight, TIntermTyped, original, replacement);
199 return false;
200}
201
Jamie Madillb1a85f42014-08-19 15:23:24 -0400202bool TIntermUnary::replaceChildNode(
203 TIntermNode *original, TIntermNode *replacement)
204{
Olli Etuahoa2234302016-08-31 12:05:39 +0300205 ASSERT(original->getAsTyped()->getType() == replacement->getAsTyped()->getType());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400206 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
207 return false;
208}
209
Olli Etuaho336b1472016-10-05 16:37:55 +0100210bool TIntermFunctionDefinition::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
211{
212 REPLACE_IF_IS(mParameters, TIntermAggregate, original, replacement);
213 REPLACE_IF_IS(mBody, TIntermBlock, original, replacement);
214 return false;
215}
216
Jamie Madillb1a85f42014-08-19 15:23:24 -0400217bool TIntermAggregate::replaceChildNode(
218 TIntermNode *original, TIntermNode *replacement)
219{
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100220 return replaceChildNodeInternal(original, replacement);
221}
222
223bool TIntermBlock::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
224{
225 return replaceChildNodeInternal(original, replacement);
226}
227
Olli Etuaho13389b62016-10-16 11:48:18 +0100228bool TIntermDeclaration::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
229{
230 return replaceChildNodeInternal(original, replacement);
231}
232
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100233bool TIntermAggregateBase::replaceChildNodeInternal(TIntermNode *original, TIntermNode *replacement)
234{
235 for (size_t ii = 0; ii < getSequence()->size(); ++ii)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400236 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100237 REPLACE_IF_IS((*getSequence())[ii], TIntermNode, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400238 }
239 return false;
240}
241
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100242bool TIntermAggregateBase::replaceChildNodeWithMultiple(TIntermNode *original,
243 const TIntermSequence &replacements)
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300244{
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100245 for (auto it = getSequence()->begin(); it < getSequence()->end(); ++it)
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300246 {
247 if (*it == original)
248 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100249 it = getSequence()->erase(it);
250 getSequence()->insert(it, replacements.begin(), replacements.end());
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300251 return true;
252 }
253 }
254 return false;
255}
256
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100257bool TIntermAggregateBase::insertChildNodes(TIntermSequence::size_type position,
258 const TIntermSequence &insertions)
Olli Etuahoa6f22092015-05-08 18:31:10 +0300259{
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100260 if (position > getSequence()->size())
Olli Etuahoa6f22092015-05-08 18:31:10 +0300261 {
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300262 return false;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300263 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100264 auto it = getSequence()->begin() + position;
265 getSequence()->insert(it, insertions.begin(), insertions.end());
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300266 return true;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300267}
268
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200269bool TIntermAggregate::areChildrenConstQualified()
270{
271 for (TIntermNode *&child : mSequence)
272 {
273 TIntermTyped *typed = child->getAsTyped();
274 if (typed && typed->getQualifier() != EvqConst)
275 {
276 return false;
277 }
278 }
279 return true;
280}
281
Olli Etuahod2a67b92014-10-21 16:42:57 +0300282void TIntermAggregate::setPrecisionFromChildren()
283{
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300284 mGotPrecisionFromChildren = true;
Olli Etuahod2a67b92014-10-21 16:42:57 +0300285 if (getBasicType() == EbtBool)
286 {
287 mType.setPrecision(EbpUndefined);
288 return;
289 }
290
291 TPrecision precision = EbpUndefined;
292 TIntermSequence::iterator childIter = mSequence.begin();
293 while (childIter != mSequence.end())
294 {
295 TIntermTyped *typed = (*childIter)->getAsTyped();
296 if (typed)
297 precision = GetHigherPrecision(typed->getPrecision(), precision);
298 ++childIter;
299 }
300 mType.setPrecision(precision);
301}
302
303void TIntermAggregate::setBuiltInFunctionPrecision()
304{
305 // All built-ins returning bool should be handled as ops, not functions.
306 ASSERT(getBasicType() != EbtBool);
307
308 TPrecision precision = EbpUndefined;
309 TIntermSequence::iterator childIter = mSequence.begin();
310 while (childIter != mSequence.end())
311 {
312 TIntermTyped *typed = (*childIter)->getAsTyped();
313 // ESSL spec section 8: texture functions get their precision from the sampler.
314 if (typed && IsSampler(typed->getBasicType()))
315 {
316 precision = typed->getPrecision();
317 break;
318 }
319 ++childIter;
320 }
321 // ESSL 3.0 spec section 8: textureSize always gets highp precision.
322 // All other functions that take a sampler are assumed to be texture functions.
Olli Etuahobd674552016-10-06 13:28:42 +0100323 if (mFunctionInfo.getName().find("textureSize") == 0)
Olli Etuahod2a67b92014-10-21 16:42:57 +0300324 mType.setPrecision(EbpHigh);
325 else
326 mType.setPrecision(precision);
327}
328
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100329void TIntermBlock::appendStatement(TIntermNode *statement)
330{
Olli Etuaho13389b62016-10-16 11:48:18 +0100331 // Declaration nodes with no children can appear if all the declarators just added constants to
332 // the symbol table instead of generating code. They're no-ops so they aren't added to blocks.
333 if (statement != nullptr && (statement->getAsDeclarationNode() == nullptr ||
334 !statement->getAsDeclarationNode()->getSequence()->empty()))
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100335 {
336 mStatements.push_back(statement);
337 }
338}
339
Olli Etuaho13389b62016-10-16 11:48:18 +0100340void TIntermDeclaration::appendDeclarator(TIntermTyped *declarator)
341{
342 ASSERT(declarator != nullptr);
343 ASSERT(declarator->getAsSymbolNode() != nullptr ||
344 (declarator->getAsBinaryNode() != nullptr &&
345 declarator->getAsBinaryNode()->getOp() == EOpInitialize));
346 ASSERT(mDeclarators.empty() ||
347 declarator->getType().sameElementType(mDeclarators.back()->getAsTyped()->getType()));
348 mDeclarators.push_back(declarator);
349}
350
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300351bool TIntermTernary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
352{
353 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
354 REPLACE_IF_IS(mTrueExpression, TIntermTyped, original, replacement);
355 REPLACE_IF_IS(mFalseExpression, TIntermTyped, original, replacement);
356 return false;
357}
358
Olli Etuaho57961272016-09-14 13:57:46 +0300359bool TIntermIfElse::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400360{
361 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100362 REPLACE_IF_IS(mTrueBlock, TIntermBlock, original, replacement);
363 REPLACE_IF_IS(mFalseBlock, TIntermBlock, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400364 return false;
365}
366
Olli Etuahoa3a36662015-02-17 13:46:51 +0200367bool TIntermSwitch::replaceChildNode(
368 TIntermNode *original, TIntermNode *replacement)
369{
370 REPLACE_IF_IS(mInit, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100371 REPLACE_IF_IS(mStatementList, TIntermBlock, original, replacement);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200372 return false;
373}
374
375bool TIntermCase::replaceChildNode(
376 TIntermNode *original, TIntermNode *replacement)
377{
378 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
379 return false;
380}
381
Olli Etuahod7a25242015-08-18 13:49:45 +0300382TIntermTyped::TIntermTyped(const TIntermTyped &node) : TIntermNode(), mType(node.mType)
383{
384 // Copy constructor is disallowed for TIntermNode in order to disallow it for subclasses that
385 // don't explicitly allow it, so normal TIntermNode constructor is used to construct the copy.
386 // We need to manually copy any fields of TIntermNode besides handling fields in TIntermTyped.
387 mLine = node.mLine;
388}
389
Olli Etuahod4f4c112016-04-15 15:11:24 +0300390bool TIntermTyped::isConstructorWithOnlyConstantUnionParameters()
391{
392 TIntermAggregate *constructor = getAsAggregate();
393 if (!constructor || !constructor->isConstructor())
394 {
395 return false;
396 }
397 for (TIntermNode *&node : *constructor->getSequence())
398 {
399 if (!node->getAsConstantUnion())
400 return false;
401 }
402 return true;
403}
404
Corentin Wallez509e4562016-08-25 14:55:44 -0400405// static
406TIntermTyped *TIntermTyped::CreateIndexNode(int index)
407{
408 TConstantUnion *u = new TConstantUnion[1];
409 u[0].setIConst(index);
410
411 TType type(EbtInt, EbpUndefined, EvqConst, 1);
412 TIntermConstantUnion *node = new TIntermConstantUnion(u, type);
413 return node;
414}
415
416// static
417TIntermTyped *TIntermTyped::CreateZero(const TType &type)
418{
419 TType constType(type);
420 constType.setQualifier(EvqConst);
421
422 if (!type.isArray() && type.getBasicType() != EbtStruct)
423 {
424 ASSERT(type.isScalar() || type.isVector() || type.isMatrix());
425
426 size_t size = constType.getObjectSize();
427 TConstantUnion *u = new TConstantUnion[size];
428 for (size_t i = 0; i < size; ++i)
429 {
430 switch (type.getBasicType())
431 {
432 case EbtFloat:
433 u[i].setFConst(0.0f);
434 break;
435 case EbtInt:
436 u[i].setIConst(0);
437 break;
438 case EbtUInt:
439 u[i].setUConst(0u);
440 break;
441 case EbtBool:
442 u[i].setBConst(false);
443 break;
444 default:
445 UNREACHABLE();
446 return nullptr;
447 }
448 }
449
450 TIntermConstantUnion *node = new TIntermConstantUnion(u, constType);
451 return node;
452 }
453
454 TIntermAggregate *constructor = new TIntermAggregate(sh::TypeToConstructorOperator(type));
455 constructor->setType(constType);
456
457 if (type.isArray())
458 {
459 TType elementType(type);
460 elementType.clearArrayness();
461
462 size_t arraySize = type.getArraySize();
463 for (size_t i = 0; i < arraySize; ++i)
464 {
465 constructor->getSequence()->push_back(CreateZero(elementType));
466 }
467 }
468 else
469 {
470 ASSERT(type.getBasicType() == EbtStruct);
471
472 TStructure *structure = type.getStruct();
473 for (const auto &field : structure->fields())
474 {
475 constructor->getSequence()->push_back(CreateZero(*field->type()));
476 }
477 }
478
479 return constructor;
480}
481
Corentin Wallez36fd1002016-12-08 11:30:44 -0500482// static
483TIntermTyped *TIntermTyped::CreateBool(bool value)
484{
485 TConstantUnion *u = new TConstantUnion[1];
486 u[0].setBConst(value);
487
488 TType type(EbtBool, EbpUndefined, EvqConst, 1);
489 TIntermConstantUnion *node = new TIntermConstantUnion(u, type);
490 return node;
491}
492
Olli Etuahod7a25242015-08-18 13:49:45 +0300493TIntermConstantUnion::TIntermConstantUnion(const TIntermConstantUnion &node) : TIntermTyped(node)
494{
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200495 mUnionArrayPointer = node.mUnionArrayPointer;
Olli Etuahod7a25242015-08-18 13:49:45 +0300496}
497
Olli Etuahobd674552016-10-06 13:28:42 +0100498void TFunctionSymbolInfo::setFromFunction(const TFunction &function)
499{
500 setName(function.getMangledName());
501 setId(function.getUniqueId());
502}
503
Olli Etuahod7a25242015-08-18 13:49:45 +0300504TIntermAggregate::TIntermAggregate(const TIntermAggregate &node)
505 : TIntermOperator(node),
Olli Etuahod7a25242015-08-18 13:49:45 +0300506 mUserDefined(node.mUserDefined),
Olli Etuahod7a25242015-08-18 13:49:45 +0300507 mUseEmulatedFunction(node.mUseEmulatedFunction),
Olli Etuahobd674552016-10-06 13:28:42 +0100508 mGotPrecisionFromChildren(node.mGotPrecisionFromChildren),
509 mFunctionInfo(node.mFunctionInfo)
Olli Etuahod7a25242015-08-18 13:49:45 +0300510{
511 for (TIntermNode *child : node.mSequence)
512 {
513 TIntermTyped *typedChild = child->getAsTyped();
514 ASSERT(typedChild != nullptr);
515 TIntermTyped *childCopy = typedChild->deepCopy();
516 mSequence.push_back(childCopy);
517 }
518}
519
Olli Etuahob6fa0432016-09-28 16:28:05 +0100520TIntermSwizzle::TIntermSwizzle(const TIntermSwizzle &node) : TIntermTyped(node)
521{
522 TIntermTyped *operandCopy = node.mOperand->deepCopy();
523 ASSERT(operandCopy != nullptr);
524 mOperand = operandCopy;
525}
526
Olli Etuahod7a25242015-08-18 13:49:45 +0300527TIntermBinary::TIntermBinary(const TIntermBinary &node)
528 : TIntermOperator(node), mAddIndexClamp(node.mAddIndexClamp)
529{
530 TIntermTyped *leftCopy = node.mLeft->deepCopy();
531 TIntermTyped *rightCopy = node.mRight->deepCopy();
532 ASSERT(leftCopy != nullptr && rightCopy != nullptr);
533 mLeft = leftCopy;
534 mRight = rightCopy;
535}
536
537TIntermUnary::TIntermUnary(const TIntermUnary &node)
538 : TIntermOperator(node), mUseEmulatedFunction(node.mUseEmulatedFunction)
539{
540 TIntermTyped *operandCopy = node.mOperand->deepCopy();
541 ASSERT(operandCopy != nullptr);
542 mOperand = operandCopy;
543}
544
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300545TIntermTernary::TIntermTernary(const TIntermTernary &node) : TIntermTyped(node)
Olli Etuahod7a25242015-08-18 13:49:45 +0300546{
Olli Etuahod7a25242015-08-18 13:49:45 +0300547 TIntermTyped *conditionCopy = node.mCondition->deepCopy();
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300548 TIntermTyped *trueCopy = node.mTrueExpression->deepCopy();
549 TIntermTyped *falseCopy = node.mFalseExpression->deepCopy();
Olli Etuahod7a25242015-08-18 13:49:45 +0300550 ASSERT(conditionCopy != nullptr && trueCopy != nullptr && falseCopy != nullptr);
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300551 mCondition = conditionCopy;
552 mTrueExpression = trueCopy;
553 mFalseExpression = falseCopy;
Olli Etuahod7a25242015-08-18 13:49:45 +0300554}
555
Jamie Madillb1a85f42014-08-19 15:23:24 -0400556bool TIntermOperator::isAssignment() const
557{
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300558 return IsAssignment(mOp);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400559}
560
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300561bool TIntermOperator::isMultiplication() const
562{
563 switch (mOp)
564 {
565 case EOpMul:
566 case EOpMatrixTimesMatrix:
567 case EOpMatrixTimesVector:
568 case EOpMatrixTimesScalar:
569 case EOpVectorTimesMatrix:
570 case EOpVectorTimesScalar:
571 return true;
572 default:
573 return false;
574 }
575}
576
Jamie Madillb1a85f42014-08-19 15:23:24 -0400577//
578// returns true if the operator is for one of the constructors
579//
580bool TIntermOperator::isConstructor() const
581{
582 switch (mOp)
583 {
584 case EOpConstructVec2:
585 case EOpConstructVec3:
586 case EOpConstructVec4:
587 case EOpConstructMat2:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400588 case EOpConstructMat2x3:
589 case EOpConstructMat2x4:
590 case EOpConstructMat3x2:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400591 case EOpConstructMat3:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400592 case EOpConstructMat3x4:
593 case EOpConstructMat4x2:
594 case EOpConstructMat4x3:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400595 case EOpConstructMat4:
596 case EOpConstructFloat:
597 case EOpConstructIVec2:
598 case EOpConstructIVec3:
599 case EOpConstructIVec4:
600 case EOpConstructInt:
601 case EOpConstructUVec2:
602 case EOpConstructUVec3:
603 case EOpConstructUVec4:
604 case EOpConstructUInt:
605 case EOpConstructBVec2:
606 case EOpConstructBVec3:
607 case EOpConstructBVec4:
608 case EOpConstructBool:
609 case EOpConstructStruct:
610 return true;
611 default:
612 return false;
613 }
614}
615
Olli Etuaho1dded802016-08-18 18:13:13 +0300616TOperator TIntermBinary::GetMulOpBasedOnOperands(const TType &left, const TType &right)
617{
618 if (left.isMatrix())
619 {
620 if (right.isMatrix())
621 {
622 return EOpMatrixTimesMatrix;
623 }
624 else
625 {
626 if (right.isVector())
627 {
628 return EOpMatrixTimesVector;
629 }
630 else
631 {
632 return EOpMatrixTimesScalar;
633 }
634 }
635 }
636 else
637 {
638 if (right.isMatrix())
639 {
640 if (left.isVector())
641 {
642 return EOpVectorTimesMatrix;
643 }
644 else
645 {
646 return EOpMatrixTimesScalar;
647 }
648 }
649 else
650 {
651 // Neither operand is a matrix.
652 if (left.isVector() == right.isVector())
653 {
654 // Leave as component product.
655 return EOpMul;
656 }
657 else
658 {
659 return EOpVectorTimesScalar;
660 }
661 }
662 }
663}
664
665TOperator TIntermBinary::GetMulAssignOpBasedOnOperands(const TType &left, const TType &right)
666{
667 if (left.isMatrix())
668 {
669 if (right.isMatrix())
670 {
671 return EOpMatrixTimesMatrixAssign;
672 }
673 else
674 {
675 // right should be scalar, but this may not be validated yet.
676 return EOpMatrixTimesScalarAssign;
677 }
678 }
679 else
680 {
681 if (right.isMatrix())
682 {
683 // Left should be a vector, but this may not be validated yet.
684 return EOpVectorTimesMatrixAssign;
685 }
686 else
687 {
688 // Neither operand is a matrix.
689 if (left.isVector() == right.isVector())
690 {
691 // Leave as component product.
692 return EOpMulAssign;
693 }
694 else
695 {
696 // left should be vector and right should be scalar, but this may not be validated
697 // yet.
698 return EOpVectorTimesScalarAssign;
699 }
700 }
701 }
702}
703
Jamie Madillb1a85f42014-08-19 15:23:24 -0400704//
705// Make sure the type of a unary operator is appropriate for its
706// combination of operation and operand type.
707//
Olli Etuahoa2234302016-08-31 12:05:39 +0300708void TIntermUnary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -0400709{
Olli Etuahoa2234302016-08-31 12:05:39 +0300710 TQualifier resultQualifier = EvqTemporary;
711 if (mOperand->getQualifier() == EvqConst)
712 resultQualifier = EvqConst;
713
714 unsigned char operandPrimarySize =
715 static_cast<unsigned char>(mOperand->getType().getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400716 switch (mOp)
717 {
Olli Etuahoa2234302016-08-31 12:05:39 +0300718 case EOpFloatBitsToInt:
719 setType(TType(EbtInt, EbpHigh, resultQualifier, operandPrimarySize));
720 break;
721 case EOpFloatBitsToUint:
722 setType(TType(EbtUInt, EbpHigh, resultQualifier, operandPrimarySize));
723 break;
724 case EOpIntBitsToFloat:
725 case EOpUintBitsToFloat:
726 setType(TType(EbtFloat, EbpHigh, resultQualifier, operandPrimarySize));
727 break;
728 case EOpPackSnorm2x16:
729 case EOpPackUnorm2x16:
730 case EOpPackHalf2x16:
731 setType(TType(EbtUInt, EbpHigh, resultQualifier));
732 break;
733 case EOpUnpackSnorm2x16:
734 case EOpUnpackUnorm2x16:
735 setType(TType(EbtFloat, EbpHigh, resultQualifier, 2));
736 break;
737 case EOpUnpackHalf2x16:
738 setType(TType(EbtFloat, EbpMedium, resultQualifier, 2));
739 break;
740 case EOpAny:
741 case EOpAll:
742 setType(TType(EbtBool, EbpUndefined, resultQualifier));
743 break;
744 case EOpLength:
745 case EOpDeterminant:
746 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier));
747 break;
748 case EOpTranspose:
749 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier,
750 static_cast<unsigned char>(mOperand->getType().getRows()),
751 static_cast<unsigned char>(mOperand->getType().getCols())));
752 break;
753 case EOpIsInf:
754 case EOpIsNan:
755 setType(TType(EbtBool, EbpUndefined, resultQualifier, operandPrimarySize));
756 break;
757 default:
758 setType(mOperand->getType());
759 mType.setQualifier(resultQualifier);
760 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400761 }
Olli Etuahoa2234302016-08-31 12:05:39 +0300762}
Jamie Madillb1a85f42014-08-19 15:23:24 -0400763
Olli Etuahob6fa0432016-09-28 16:28:05 +0100764TIntermSwizzle::TIntermSwizzle(TIntermTyped *operand, const TVector<int> &swizzleOffsets)
765 : TIntermTyped(TType(EbtFloat, EbpUndefined)),
766 mOperand(operand),
767 mSwizzleOffsets(swizzleOffsets)
768{
769 ASSERT(mSwizzleOffsets.size() <= 4);
770 promote();
771}
772
Olli Etuahoa2234302016-08-31 12:05:39 +0300773TIntermUnary::TIntermUnary(TOperator op, TIntermTyped *operand)
774 : TIntermOperator(op), mOperand(operand), mUseEmulatedFunction(false)
775{
776 promote();
Jamie Madillb1a85f42014-08-19 15:23:24 -0400777}
778
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300779TIntermBinary::TIntermBinary(TOperator op, TIntermTyped *left, TIntermTyped *right)
780 : TIntermOperator(op), mLeft(left), mRight(right), mAddIndexClamp(false)
781{
782 promote();
783}
784
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300785TIntermTernary::TIntermTernary(TIntermTyped *cond,
786 TIntermTyped *trueExpression,
787 TIntermTyped *falseExpression)
788 : TIntermTyped(trueExpression->getType()),
789 mCondition(cond),
790 mTrueExpression(trueExpression),
791 mFalseExpression(falseExpression)
792{
793 getTypePointer()->setQualifier(
794 TIntermTernary::DetermineQualifier(cond, trueExpression, falseExpression));
795}
796
797// static
798TQualifier TIntermTernary::DetermineQualifier(TIntermTyped *cond,
799 TIntermTyped *trueExpression,
800 TIntermTyped *falseExpression)
801{
802 if (cond->getQualifier() == EvqConst && trueExpression->getQualifier() == EvqConst &&
803 falseExpression->getQualifier() == EvqConst)
804 {
805 return EvqConst;
806 }
807 return EvqTemporary;
808}
809
Olli Etuahob6fa0432016-09-28 16:28:05 +0100810void TIntermSwizzle::promote()
811{
812 TQualifier resultQualifier = EvqTemporary;
813 if (mOperand->getQualifier() == EvqConst)
814 resultQualifier = EvqConst;
815
816 auto numFields = mSwizzleOffsets.size();
817 setType(TType(mOperand->getBasicType(), mOperand->getPrecision(), resultQualifier,
818 static_cast<unsigned char>(numFields)));
819}
820
821bool TIntermSwizzle::hasDuplicateOffsets() const
822{
823 int offsetCount[4] = {0u, 0u, 0u, 0u};
824 for (const auto offset : mSwizzleOffsets)
825 {
826 offsetCount[offset]++;
827 if (offsetCount[offset] > 1)
828 {
829 return true;
830 }
831 }
832 return false;
833}
834
835void TIntermSwizzle::writeOffsetsAsXYZW(TInfoSinkBase *out) const
836{
837 for (const int offset : mSwizzleOffsets)
838 {
839 switch (offset)
840 {
841 case 0:
842 *out << "x";
843 break;
844 case 1:
845 *out << "y";
846 break;
847 case 2:
848 *out << "z";
849 break;
850 case 3:
851 *out << "w";
852 break;
853 default:
854 UNREACHABLE();
855 }
856 }
857}
858
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100859TQualifier TIntermBinary::GetCommaQualifier(int shaderVersion,
860 const TIntermTyped *left,
861 const TIntermTyped *right)
862{
863 // ESSL3.00 section 12.43: The result of a sequence operator is not a constant-expression.
864 if (shaderVersion >= 300 || left->getQualifier() != EvqConst ||
865 right->getQualifier() != EvqConst)
866 {
867 return EvqTemporary;
868 }
869 return EvqConst;
870}
Olli Etuahob6fa0432016-09-28 16:28:05 +0100871
872// Establishes the type of the result of the binary operation.
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300873void TIntermBinary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -0400874{
Olli Etuaho1dded802016-08-18 18:13:13 +0300875 ASSERT(!isMultiplication() ||
876 mOp == GetMulOpBasedOnOperands(mLeft->getType(), mRight->getType()));
877
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100878 // Comma is handled as a special case.
879 if (mOp == EOpComma)
880 {
881 setType(mRight->getType());
882 return;
883 }
884
Jamie Madillb1a85f42014-08-19 15:23:24 -0400885 // Base assumption: just make the type the same as the left
886 // operand. Then only deviations from this need be coded.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400887 setType(mLeft->getType());
888
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200889 TQualifier resultQualifier = EvqConst;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400890 // Binary operations results in temporary variables unless both
891 // operands are const.
892 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
893 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200894 resultQualifier = EvqTemporary;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400895 getTypePointer()->setQualifier(EvqTemporary);
896 }
897
Olli Etuaho3272a6d2016-08-29 17:54:50 +0300898 // Handle indexing ops.
899 switch (mOp)
900 {
901 case EOpIndexDirect:
902 case EOpIndexIndirect:
903 if (mLeft->isArray())
904 {
905 mType.clearArrayness();
906 }
907 else if (mLeft->isMatrix())
908 {
909 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier,
910 static_cast<unsigned char>(mLeft->getRows())));
911 }
912 else if (mLeft->isVector())
913 {
914 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier));
915 }
916 else
917 {
918 UNREACHABLE();
919 }
920 return;
921 case EOpIndexDirectStruct:
922 {
923 const TFieldList &fields = mLeft->getType().getStruct()->fields();
924 const int i = mRight->getAsConstantUnion()->getIConst(0);
925 setType(*fields[i]->type());
926 getTypePointer()->setQualifier(resultQualifier);
927 return;
928 }
929 case EOpIndexDirectInterfaceBlock:
930 {
931 const TFieldList &fields = mLeft->getType().getInterfaceBlock()->fields();
932 const int i = mRight->getAsConstantUnion()->getIConst(0);
933 setType(*fields[i]->type());
934 getTypePointer()->setQualifier(resultQualifier);
935 return;
936 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +0300937 default:
938 break;
939 }
940
941 ASSERT(mLeft->isArray() == mRight->isArray());
942
943 // The result gets promoted to the highest precision.
944 TPrecision higherPrecision = GetHigherPrecision(mLeft->getPrecision(), mRight->getPrecision());
945 getTypePointer()->setPrecision(higherPrecision);
946
Jamie Madillb1a85f42014-08-19 15:23:24 -0400947 const int nominalSize =
948 std::max(mLeft->getNominalSize(), mRight->getNominalSize());
949
950 //
951 // All scalars or structs. Code after this test assumes this case is removed!
952 //
953 if (nominalSize == 1)
954 {
955 switch (mOp)
956 {
957 //
958 // Promote to conditional
959 //
960 case EOpEqual:
961 case EOpNotEqual:
962 case EOpLessThan:
963 case EOpGreaterThan:
964 case EOpLessThanEqual:
965 case EOpGreaterThanEqual:
Olli Etuaho3272a6d2016-08-29 17:54:50 +0300966 setType(TType(EbtBool, EbpUndefined, resultQualifier));
967 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400968
969 //
970 // And and Or operate on conditionals
971 //
972 case EOpLogicalAnd:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200973 case EOpLogicalXor:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400974 case EOpLogicalOr:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200975 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
Olli Etuahoc9550582016-08-29 17:56:22 +0300976 setType(TType(EbtBool, EbpUndefined, resultQualifier));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400977 break;
978
979 default:
980 break;
981 }
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300982 return;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400983 }
984
985 // If we reach here, at least one of the operands is vector or matrix.
986 // The other operand could be a scalar, vector, or matrix.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400987 TBasicType basicType = mLeft->getBasicType();
Olli Etuaho1dded802016-08-18 18:13:13 +0300988
Jamie Madillb1a85f42014-08-19 15:23:24 -0400989 switch (mOp)
990 {
Olli Etuaho1dded802016-08-18 18:13:13 +0300991 case EOpMul:
992 break;
993 case EOpMatrixTimesScalar:
994 if (mRight->isMatrix())
Jamie Madillb1a85f42014-08-19 15:23:24 -0400995 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200996 setType(TType(basicType, higherPrecision, resultQualifier,
997 static_cast<unsigned char>(mRight->getCols()),
998 static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400999 }
Olli Etuaho1dded802016-08-18 18:13:13 +03001000 break;
1001 case EOpMatrixTimesVector:
1002 setType(TType(basicType, higherPrecision, resultQualifier,
1003 static_cast<unsigned char>(mLeft->getRows()), 1));
1004 break;
1005 case EOpMatrixTimesMatrix:
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001006 setType(TType(basicType, higherPrecision, resultQualifier,
1007 static_cast<unsigned char>(mRight->getCols()),
1008 static_cast<unsigned char>(mLeft->getRows())));
Olli Etuaho1dded802016-08-18 18:13:13 +03001009 break;
1010 case EOpVectorTimesScalar:
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001011 setType(TType(basicType, higherPrecision, resultQualifier,
Olli Etuaho1dded802016-08-18 18:13:13 +03001012 static_cast<unsigned char>(nominalSize), 1));
1013 break;
1014 case EOpVectorTimesMatrix:
1015 setType(TType(basicType, higherPrecision, resultQualifier,
1016 static_cast<unsigned char>(mRight->getCols()), 1));
1017 break;
1018 case EOpMulAssign:
1019 case EOpVectorTimesScalarAssign:
1020 case EOpVectorTimesMatrixAssign:
1021 case EOpMatrixTimesScalarAssign:
1022 case EOpMatrixTimesMatrixAssign:
1023 ASSERT(mOp == GetMulAssignOpBasedOnOperands(mLeft->getType(), mRight->getType()));
1024 break;
1025 case EOpAssign:
1026 case EOpInitialize:
Olli Etuaho1dded802016-08-18 18:13:13 +03001027 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1028 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
1029 break;
1030 case EOpAdd:
1031 case EOpSub:
1032 case EOpDiv:
1033 case EOpIMod:
1034 case EOpBitShiftLeft:
1035 case EOpBitShiftRight:
1036 case EOpBitwiseAnd:
1037 case EOpBitwiseXor:
1038 case EOpBitwiseOr:
1039 case EOpAddAssign:
1040 case EOpSubAssign:
1041 case EOpDivAssign:
1042 case EOpIModAssign:
1043 case EOpBitShiftLeftAssign:
1044 case EOpBitShiftRightAssign:
1045 case EOpBitwiseAndAssign:
1046 case EOpBitwiseXorAssign:
1047 case EOpBitwiseOrAssign:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001048 {
1049 const int secondarySize =
1050 std::max(mLeft->getSecondarySize(), mRight->getSecondarySize());
1051 setType(TType(basicType, higherPrecision, resultQualifier,
1052 static_cast<unsigned char>(nominalSize),
1053 static_cast<unsigned char>(secondarySize)));
1054 ASSERT(!mLeft->isArray() && !mRight->isArray());
Olli Etuaho1dded802016-08-18 18:13:13 +03001055 break;
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001056 }
Olli Etuaho1dded802016-08-18 18:13:13 +03001057 case EOpEqual:
1058 case EOpNotEqual:
1059 case EOpLessThan:
1060 case EOpGreaterThan:
1061 case EOpLessThanEqual:
1062 case EOpGreaterThanEqual:
1063 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1064 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001065 setType(TType(EbtBool, EbpUndefined, resultQualifier));
Olli Etuaho1dded802016-08-18 18:13:13 +03001066 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001067
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001068 case EOpIndexDirect:
1069 case EOpIndexIndirect:
1070 case EOpIndexDirectInterfaceBlock:
1071 case EOpIndexDirectStruct:
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001072 // These ops should be already fully handled.
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001073 UNREACHABLE();
1074 break;
Olli Etuaho1dded802016-08-18 18:13:13 +03001075 default:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001076 UNREACHABLE();
1077 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001078 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04001079}
1080
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001081const TConstantUnion *TIntermConstantUnion::foldIndexing(int index)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001082{
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001083 if (isArray())
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001084 {
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001085 ASSERT(index < static_cast<int>(getType().getArraySize()));
1086 TType arrayElementType = getType();
1087 arrayElementType.clearArrayness();
1088 size_t arrayElementSize = arrayElementType.getObjectSize();
1089 return &mUnionArrayPointer[arrayElementSize * index];
1090 }
1091 else if (isMatrix())
1092 {
1093 ASSERT(index < getType().getCols());
1094 int size = getType().getRows();
1095 return &mUnionArrayPointer[size * index];
1096 }
1097 else if (isVector())
1098 {
1099 ASSERT(index < getType().getNominalSize());
1100 return &mUnionArrayPointer[index];
1101 }
1102 else
1103 {
1104 UNREACHABLE();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001105 return nullptr;
1106 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001107}
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001108
Olli Etuahob6fa0432016-09-28 16:28:05 +01001109TIntermTyped *TIntermSwizzle::fold()
1110{
1111 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1112 if (operandConstant == nullptr)
1113 {
1114 return nullptr;
1115 }
1116
1117 TConstantUnion *constArray = new TConstantUnion[mSwizzleOffsets.size()];
1118 for (size_t i = 0; i < mSwizzleOffsets.size(); ++i)
1119 {
1120 constArray[i] = *operandConstant->foldIndexing(mSwizzleOffsets.at(i));
1121 }
1122 return CreateFoldedNode(constArray, this, mType.getQualifier());
1123}
1124
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001125TIntermTyped *TIntermBinary::fold(TDiagnostics *diagnostics)
1126{
1127 TIntermConstantUnion *leftConstant = mLeft->getAsConstantUnion();
1128 TIntermConstantUnion *rightConstant = mRight->getAsConstantUnion();
1129 switch (mOp)
1130 {
1131 case EOpIndexDirect:
1132 {
1133 if (leftConstant == nullptr || rightConstant == nullptr)
1134 {
1135 return nullptr;
1136 }
1137 int index = rightConstant->getIConst(0);
1138
1139 const TConstantUnion *constArray = leftConstant->foldIndexing(index);
1140 return CreateFoldedNode(constArray, this, mType.getQualifier());
1141 }
1142 case EOpIndexDirectStruct:
1143 {
1144 if (leftConstant == nullptr || rightConstant == nullptr)
1145 {
1146 return nullptr;
1147 }
1148 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1149 size_t index = static_cast<size_t>(rightConstant->getIConst(0));
1150
1151 size_t previousFieldsSize = 0;
1152 for (size_t i = 0; i < index; ++i)
1153 {
1154 previousFieldsSize += fields[i]->type()->getObjectSize();
1155 }
1156
1157 const TConstantUnion *constArray = leftConstant->getUnionArrayPointer();
1158 return CreateFoldedNode(constArray + previousFieldsSize, this, mType.getQualifier());
1159 }
1160 case EOpIndexIndirect:
1161 case EOpIndexDirectInterfaceBlock:
1162 // Can never be constant folded.
1163 return nullptr;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001164 default:
1165 {
1166 if (leftConstant == nullptr || rightConstant == nullptr)
1167 {
1168 return nullptr;
1169 }
Jamie Madill5db69f52016-09-15 12:47:32 -04001170 TConstantUnion *constArray =
1171 leftConstant->foldBinary(mOp, rightConstant, diagnostics, mLeft->getLine());
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001172
1173 // Nodes may be constant folded without being qualified as constant.
1174 return CreateFoldedNode(constArray, this, mType.getQualifier());
1175 }
1176 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001177}
1178
Olli Etuahof119a262016-08-19 15:54:22 +03001179TIntermTyped *TIntermUnary::fold(TDiagnostics *diagnostics)
Olli Etuaho95310b02015-06-02 17:43:38 +03001180{
1181 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1182 if (operandConstant == nullptr)
1183 {
1184 return nullptr;
1185 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301186
1187 TConstantUnion *constArray = nullptr;
1188 switch (mOp)
1189 {
1190 case EOpAny:
1191 case EOpAll:
1192 case EOpLength:
1193 case EOpTranspose:
1194 case EOpDeterminant:
1195 case EOpInverse:
1196 case EOpPackSnorm2x16:
1197 case EOpUnpackSnorm2x16:
1198 case EOpPackUnorm2x16:
1199 case EOpUnpackUnorm2x16:
1200 case EOpPackHalf2x16:
1201 case EOpUnpackHalf2x16:
Olli Etuahof119a262016-08-19 15:54:22 +03001202 constArray = operandConstant->foldUnaryNonComponentWise(mOp);
1203 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301204 default:
Olli Etuahof119a262016-08-19 15:54:22 +03001205 constArray = operandConstant->foldUnaryComponentWise(mOp, diagnostics);
1206 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301207 }
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001208
1209 // Nodes may be constant folded without being qualified as constant.
Olli Etuahoc9550582016-08-29 17:56:22 +03001210 return CreateFoldedNode(constArray, this, mType.getQualifier());
Olli Etuahob43846e2015-06-02 18:18:57 +03001211}
1212
Olli Etuahof119a262016-08-19 15:54:22 +03001213TIntermTyped *TIntermAggregate::fold(TDiagnostics *diagnostics)
Olli Etuahob43846e2015-06-02 18:18:57 +03001214{
1215 // Make sure that all params are constant before actual constant folding.
1216 for (auto *param : *getSequence())
Olli Etuaho95310b02015-06-02 17:43:38 +03001217 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001218 if (param->getAsConstantUnion() == nullptr)
1219 {
1220 return nullptr;
1221 }
Olli Etuaho95310b02015-06-02 17:43:38 +03001222 }
Olli Etuaho1d122782015-11-06 15:35:17 +02001223 TConstantUnion *constArray = nullptr;
1224 if (isConstructor())
Olli Etuahof119a262016-08-19 15:54:22 +03001225 constArray = TIntermConstantUnion::FoldAggregateConstructor(this);
Olli Etuaho1d122782015-11-06 15:35:17 +02001226 else
Olli Etuahof119a262016-08-19 15:54:22 +03001227 constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, diagnostics);
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001228
1229 // Nodes may be constant folded without being qualified as constant.
1230 TQualifier resultQualifier = areChildrenConstQualified() ? EvqConst : EvqTemporary;
1231 return CreateFoldedNode(constArray, this, resultQualifier);
Olli Etuaho95310b02015-06-02 17:43:38 +03001232}
1233
Jamie Madillb1a85f42014-08-19 15:23:24 -04001234//
1235// The fold functions see if an operation on a constant can be done in place,
1236// without generating run-time code.
1237//
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001238// Returns the constant value to keep using or nullptr.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001239//
Olli Etuaho3fdec912016-08-18 15:08:06 +03001240TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op,
1241 TIntermConstantUnion *rightNode,
Jamie Madill5db69f52016-09-15 12:47:32 -04001242 TDiagnostics *diagnostics,
1243 const TSourceLoc &line)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001244{
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001245 const TConstantUnion *leftArray = getUnionArrayPointer();
1246 const TConstantUnion *rightArray = rightNode->getUnionArrayPointer();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001247
Olli Etuahof119a262016-08-19 15:54:22 +03001248 ASSERT(leftArray && rightArray);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001249
1250 size_t objectSize = getType().getObjectSize();
1251
1252 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
1253 if (rightNode->getType().getObjectSize() == 1 && objectSize > 1)
1254 {
1255 rightArray = Vectorize(*rightNode->getUnionArrayPointer(), objectSize);
1256 }
1257 else if (rightNode->getType().getObjectSize() > 1 && objectSize == 1)
1258 {
1259 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
1260 leftArray = Vectorize(*getUnionArrayPointer(), rightNode->getType().getObjectSize());
1261 objectSize = rightNode->getType().getObjectSize();
1262 }
1263
1264 TConstantUnion *resultArray = nullptr;
1265
1266 switch(op)
1267 {
1268 case EOpAdd:
1269 resultArray = new TConstantUnion[objectSize];
1270 for (size_t i = 0; i < objectSize; i++)
Jamie Madill5db69f52016-09-15 12:47:32 -04001271 resultArray[i] = TConstantUnion::add(leftArray[i], rightArray[i], diagnostics, line);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001272 break;
1273 case EOpSub:
1274 resultArray = new TConstantUnion[objectSize];
1275 for (size_t i = 0; i < objectSize; i++)
Jamie Madill5db69f52016-09-15 12:47:32 -04001276 resultArray[i] = TConstantUnion::sub(leftArray[i], rightArray[i], diagnostics, line);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001277 break;
1278
1279 case EOpMul:
1280 case EOpVectorTimesScalar:
1281 case EOpMatrixTimesScalar:
1282 resultArray = new TConstantUnion[objectSize];
1283 for (size_t i = 0; i < objectSize; i++)
Jamie Madill5db69f52016-09-15 12:47:32 -04001284 resultArray[i] = TConstantUnion::mul(leftArray[i], rightArray[i], diagnostics, line);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001285 break;
1286
1287 case EOpMatrixTimesMatrix:
1288 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001289 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001290 ASSERT(getType().getBasicType() == EbtFloat && rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001291
1292 const int leftCols = getCols();
1293 const int leftRows = getRows();
1294 const int rightCols = rightNode->getType().getCols();
1295 const int rightRows = rightNode->getType().getRows();
1296 const int resultCols = rightCols;
1297 const int resultRows = leftRows;
1298
1299 resultArray = new TConstantUnion[resultCols * resultRows];
1300 for (int row = 0; row < resultRows; row++)
1301 {
1302 for (int column = 0; column < resultCols; column++)
1303 {
1304 resultArray[resultRows * column + row].setFConst(0.0f);
1305 for (int i = 0; i < leftCols; i++)
1306 {
1307 resultArray[resultRows * column + row].setFConst(
1308 resultArray[resultRows * column + row].getFConst() +
1309 leftArray[i * leftRows + row].getFConst() *
1310 rightArray[column * rightRows + i].getFConst());
1311 }
1312 }
1313 }
1314 }
1315 break;
1316
1317 case EOpDiv:
1318 case EOpIMod:
1319 {
1320 resultArray = new TConstantUnion[objectSize];
1321 for (size_t i = 0; i < objectSize; i++)
1322 {
1323 switch (getType().getBasicType())
1324 {
1325 case EbtFloat:
Olli Etuaho2d736652016-11-30 10:37:49 +00001326 {
1327 ASSERT(op == EOpDiv);
1328 float dividend = leftArray[i].getFConst();
1329 float divisor = rightArray[i].getFConst();
1330 if (divisor == 0.0f)
1331 {
1332 if (dividend == 0.0f)
1333 {
1334 diagnostics->warning(
1335 getLine(),
1336 "Zero divided by zero during constant folding generated NaN", "/",
1337 "");
1338 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
1339 }
1340 else
1341 {
1342 diagnostics->warning(
1343 getLine(), "Divide by zero during constant folding", "/", "");
1344 bool negativeResult = std::signbit(dividend) != std::signbit(divisor);
1345 resultArray[i].setFConst(
1346 negativeResult ? -std::numeric_limits<float>::infinity()
1347 : std::numeric_limits<float>::infinity());
1348 }
1349 }
1350 else if (gl::isInf(dividend) && gl::isInf(divisor))
1351 {
1352 diagnostics->warning(
1353 getLine(),
1354 "Infinity divided by infinity during constant folding generated NaN",
1355 "/", "");
1356 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
1357 }
1358 else
1359 {
1360 float result = dividend / divisor;
1361 if (!gl::isInf(dividend) && gl::isInf(result))
1362 {
1363 diagnostics->warning(
1364 getLine(), "Constant folded division overflowed to infinity", "/",
1365 "");
1366 }
1367 resultArray[i].setFConst(result);
1368 }
1369 break;
1370 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001371 case EbtInt:
1372 if (rightArray[i] == 0)
1373 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001374 diagnostics->warning(
1375 getLine(), "Divide by zero error during constant folding", "/", "");
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001376 resultArray[i].setIConst(INT_MAX);
1377 }
1378 else
1379 {
Olli Etuahod4453572016-09-27 13:21:46 +01001380 int lhs = leftArray[i].getIConst();
1381 int divisor = rightArray[i].getIConst();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001382 if (op == EOpDiv)
1383 {
Olli Etuahod4453572016-09-27 13:21:46 +01001384 // Check for the special case where the minimum representable number is
1385 // divided by -1. If left alone this leads to integer overflow in C++.
1386 // ESSL 3.00.6 section 4.1.3 Integers:
1387 // "However, for the case where the minimum representable value is
1388 // divided by -1, it is allowed to return either the minimum
1389 // representable value or the maximum representable value."
1390 if (lhs == -0x7fffffff - 1 && divisor == -1)
1391 {
1392 resultArray[i].setIConst(0x7fffffff);
1393 }
1394 else
1395 {
1396 resultArray[i].setIConst(lhs / divisor);
1397 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001398 }
1399 else
1400 {
1401 ASSERT(op == EOpIMod);
Olli Etuahod4453572016-09-27 13:21:46 +01001402 if (lhs < 0 || divisor < 0)
1403 {
1404 // ESSL 3.00.6 section 5.9: Results of modulus are undefined when
1405 // either one of the operands is negative.
1406 diagnostics->warning(getLine(),
1407 "Negative modulus operator operand "
1408 "encountered during constant folding",
1409 "%", "");
1410 resultArray[i].setIConst(0);
1411 }
1412 else
1413 {
1414 resultArray[i].setIConst(lhs % divisor);
1415 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001416 }
1417 }
1418 break;
1419
1420 case EbtUInt:
1421 if (rightArray[i] == 0)
1422 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001423 diagnostics->warning(
1424 getLine(), "Divide by zero error during constant folding", "/", "");
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001425 resultArray[i].setUConst(UINT_MAX);
1426 }
1427 else
1428 {
1429 if (op == EOpDiv)
1430 {
1431 resultArray[i].setUConst(leftArray[i].getUConst() / rightArray[i].getUConst());
1432 }
1433 else
1434 {
1435 ASSERT(op == EOpIMod);
1436 resultArray[i].setUConst(leftArray[i].getUConst() % rightArray[i].getUConst());
1437 }
1438 }
1439 break;
1440
1441 default:
Olli Etuaho3fdec912016-08-18 15:08:06 +03001442 UNREACHABLE();
1443 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001444 }
1445 }
1446 }
1447 break;
1448
1449 case EOpMatrixTimesVector:
1450 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001451 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001452 ASSERT(rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001453
1454 const int matrixCols = getCols();
1455 const int matrixRows = getRows();
1456
1457 resultArray = new TConstantUnion[matrixRows];
1458
1459 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1460 {
1461 resultArray[matrixRow].setFConst(0.0f);
1462 for (int col = 0; col < matrixCols; col++)
1463 {
1464 resultArray[matrixRow].setFConst(resultArray[matrixRow].getFConst() +
1465 leftArray[col * matrixRows + matrixRow].getFConst() *
1466 rightArray[col].getFConst());
1467 }
1468 }
1469 }
1470 break;
1471
1472 case EOpVectorTimesMatrix:
1473 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001474 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001475 ASSERT(getType().getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001476
1477 const int matrixCols = rightNode->getType().getCols();
1478 const int matrixRows = rightNode->getType().getRows();
1479
1480 resultArray = new TConstantUnion[matrixCols];
1481
1482 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
1483 {
1484 resultArray[matrixCol].setFConst(0.0f);
1485 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1486 {
1487 resultArray[matrixCol].setFConst(resultArray[matrixCol].getFConst() +
1488 leftArray[matrixRow].getFConst() *
1489 rightArray[matrixCol * matrixRows + matrixRow].getFConst());
1490 }
1491 }
1492 }
1493 break;
1494
1495 case EOpLogicalAnd:
1496 {
1497 resultArray = new TConstantUnion[objectSize];
1498 for (size_t i = 0; i < objectSize; i++)
1499 {
1500 resultArray[i] = leftArray[i] && rightArray[i];
1501 }
1502 }
1503 break;
1504
1505 case EOpLogicalOr:
1506 {
1507 resultArray = new TConstantUnion[objectSize];
1508 for (size_t i = 0; i < objectSize; i++)
1509 {
1510 resultArray[i] = leftArray[i] || rightArray[i];
1511 }
1512 }
1513 break;
1514
1515 case EOpLogicalXor:
1516 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001517 ASSERT(getType().getBasicType() == EbtBool);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001518 resultArray = new TConstantUnion[objectSize];
1519 for (size_t i = 0; i < objectSize; i++)
1520 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001521 resultArray[i].setBConst(leftArray[i] != rightArray[i]);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001522 }
1523 }
1524 break;
1525
1526 case EOpBitwiseAnd:
1527 resultArray = new TConstantUnion[objectSize];
1528 for (size_t i = 0; i < objectSize; i++)
1529 resultArray[i] = leftArray[i] & rightArray[i];
1530 break;
1531 case EOpBitwiseXor:
1532 resultArray = new TConstantUnion[objectSize];
1533 for (size_t i = 0; i < objectSize; i++)
1534 resultArray[i] = leftArray[i] ^ rightArray[i];
1535 break;
1536 case EOpBitwiseOr:
1537 resultArray = new TConstantUnion[objectSize];
1538 for (size_t i = 0; i < objectSize; i++)
1539 resultArray[i] = leftArray[i] | rightArray[i];
1540 break;
1541 case EOpBitShiftLeft:
1542 resultArray = new TConstantUnion[objectSize];
1543 for (size_t i = 0; i < objectSize; i++)
Jamie Madill596018c2016-09-21 12:57:03 -04001544 resultArray[i] = TConstantUnion::lshift(leftArray[i], rightArray[i], diagnostics, line);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001545 break;
1546 case EOpBitShiftRight:
1547 resultArray = new TConstantUnion[objectSize];
1548 for (size_t i = 0; i < objectSize; i++)
Jamie Madill596018c2016-09-21 12:57:03 -04001549 resultArray[i] = TConstantUnion::rshift(leftArray[i], rightArray[i], diagnostics, line);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001550 break;
1551
1552 case EOpLessThan:
1553 ASSERT(objectSize == 1);
1554 resultArray = new TConstantUnion[1];
1555 resultArray->setBConst(*leftArray < *rightArray);
1556 break;
1557
1558 case EOpGreaterThan:
1559 ASSERT(objectSize == 1);
1560 resultArray = new TConstantUnion[1];
1561 resultArray->setBConst(*leftArray > *rightArray);
1562 break;
1563
1564 case EOpLessThanEqual:
1565 ASSERT(objectSize == 1);
1566 resultArray = new TConstantUnion[1];
1567 resultArray->setBConst(!(*leftArray > *rightArray));
1568 break;
1569
1570 case EOpGreaterThanEqual:
1571 ASSERT(objectSize == 1);
1572 resultArray = new TConstantUnion[1];
1573 resultArray->setBConst(!(*leftArray < *rightArray));
1574 break;
1575
1576 case EOpEqual:
1577 case EOpNotEqual:
1578 {
1579 resultArray = new TConstantUnion[1];
1580 bool equal = true;
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001581 for (size_t i = 0; i < objectSize; i++)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001582 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001583 if (leftArray[i] != rightArray[i])
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001584 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001585 equal = false;
1586 break; // break out of for loop
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001587 }
1588 }
1589 if (op == EOpEqual)
1590 {
1591 resultArray->setBConst(equal);
1592 }
1593 else
1594 {
1595 resultArray->setBConst(!equal);
1596 }
1597 }
1598 break;
1599
1600 default:
Olli Etuaho3fdec912016-08-18 15:08:06 +03001601 UNREACHABLE();
1602 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001603 }
1604 return resultArray;
1605}
1606
Olli Etuahof119a262016-08-19 15:54:22 +03001607// The fold functions do operations on a constant at GLSL compile time, without generating run-time
1608// code. Returns the constant value to keep using. Nullptr should not be returned.
1609TConstantUnion *TIntermConstantUnion::foldUnaryNonComponentWise(TOperator op)
Jamie Madillb1a85f42014-08-19 15:23:24 -04001610{
Olli Etuahof119a262016-08-19 15:54:22 +03001611 // Do operations where the return type may have a different number of components compared to the
1612 // operand type.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001613
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001614 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuahof119a262016-08-19 15:54:22 +03001615 ASSERT(operandArray);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301616
1617 size_t objectSize = getType().getObjectSize();
1618 TConstantUnion *resultArray = nullptr;
1619 switch (op)
1620 {
Olli Etuahof119a262016-08-19 15:54:22 +03001621 case EOpAny:
1622 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301623 resultArray = new TConstantUnion();
1624 resultArray->setBConst(false);
1625 for (size_t i = 0; i < objectSize; i++)
1626 {
1627 if (operandArray[i].getBConst())
1628 {
1629 resultArray->setBConst(true);
1630 break;
1631 }
1632 }
1633 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301634
Olli Etuahof119a262016-08-19 15:54:22 +03001635 case EOpAll:
1636 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301637 resultArray = new TConstantUnion();
1638 resultArray->setBConst(true);
1639 for (size_t i = 0; i < objectSize; i++)
1640 {
1641 if (!operandArray[i].getBConst())
1642 {
1643 resultArray->setBConst(false);
1644 break;
1645 }
1646 }
1647 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301648
Olli Etuahof119a262016-08-19 15:54:22 +03001649 case EOpLength:
1650 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301651 resultArray = new TConstantUnion();
1652 resultArray->setFConst(VectorLength(operandArray, objectSize));
1653 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301654
Olli Etuahof119a262016-08-19 15:54:22 +03001655 case EOpTranspose:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301656 {
Olli Etuahof119a262016-08-19 15:54:22 +03001657 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301658 resultArray = new TConstantUnion[objectSize];
1659 angle::Matrix<float> result =
Olli Etuahod5da5052016-08-29 13:16:55 +03001660 GetMatrix(operandArray, getType().getRows(), getType().getCols()).transpose();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301661 SetUnionArrayFromMatrix(result, resultArray);
1662 break;
1663 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301664
Olli Etuahof119a262016-08-19 15:54:22 +03001665 case EOpDeterminant:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301666 {
Olli Etuahof119a262016-08-19 15:54:22 +03001667 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301668 unsigned int size = getType().getNominalSize();
1669 ASSERT(size >= 2 && size <= 4);
1670 resultArray = new TConstantUnion();
1671 resultArray->setFConst(GetMatrix(operandArray, size).determinant());
1672 break;
1673 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301674
Olli Etuahof119a262016-08-19 15:54:22 +03001675 case EOpInverse:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301676 {
Olli Etuahof119a262016-08-19 15:54:22 +03001677 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301678 unsigned int size = getType().getNominalSize();
1679 ASSERT(size >= 2 && size <= 4);
Olli Etuahof119a262016-08-19 15:54:22 +03001680 resultArray = new TConstantUnion[objectSize];
Arun Patoleab2b9a22015-07-06 18:27:56 +05301681 angle::Matrix<float> result = GetMatrix(operandArray, size).inverse();
1682 SetUnionArrayFromMatrix(result, resultArray);
1683 break;
1684 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301685
Olli Etuahof119a262016-08-19 15:54:22 +03001686 case EOpPackSnorm2x16:
1687 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301688 ASSERT(getType().getNominalSize() == 2);
1689 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001690 resultArray->setUConst(
1691 gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301692 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301693
Olli Etuahof119a262016-08-19 15:54:22 +03001694 case EOpUnpackSnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301695 {
Olli Etuahof119a262016-08-19 15:54:22 +03001696 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301697 resultArray = new TConstantUnion[2];
1698 float f1, f2;
1699 gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1700 resultArray[0].setFConst(f1);
1701 resultArray[1].setFConst(f2);
1702 break;
1703 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301704
Olli Etuahof119a262016-08-19 15:54:22 +03001705 case EOpPackUnorm2x16:
1706 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301707 ASSERT(getType().getNominalSize() == 2);
1708 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001709 resultArray->setUConst(
1710 gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301711 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301712
Olli Etuahof119a262016-08-19 15:54:22 +03001713 case EOpUnpackUnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301714 {
Olli Etuahof119a262016-08-19 15:54:22 +03001715 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301716 resultArray = new TConstantUnion[2];
1717 float f1, f2;
1718 gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1719 resultArray[0].setFConst(f1);
1720 resultArray[1].setFConst(f2);
1721 break;
1722 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301723
Olli Etuahof119a262016-08-19 15:54:22 +03001724 case EOpPackHalf2x16:
1725 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301726 ASSERT(getType().getNominalSize() == 2);
1727 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001728 resultArray->setUConst(
1729 gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301730 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301731
Olli Etuahof119a262016-08-19 15:54:22 +03001732 case EOpUnpackHalf2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301733 {
Olli Etuahof119a262016-08-19 15:54:22 +03001734 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301735 resultArray = new TConstantUnion[2];
1736 float f1, f2;
1737 gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2);
1738 resultArray[0].setFConst(f1);
1739 resultArray[1].setFConst(f2);
1740 break;
1741 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301742
Olli Etuahof119a262016-08-19 15:54:22 +03001743 default:
1744 UNREACHABLE();
1745 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301746 }
1747
1748 return resultArray;
1749}
1750
Olli Etuahof119a262016-08-19 15:54:22 +03001751TConstantUnion *TIntermConstantUnion::foldUnaryComponentWise(TOperator op,
1752 TDiagnostics *diagnostics)
Arun Patoleab2b9a22015-07-06 18:27:56 +05301753{
Olli Etuahof119a262016-08-19 15:54:22 +03001754 // Do unary operations where each component of the result is computed based on the corresponding
1755 // component of the operand. Also folds normalize, though the divisor in that case takes all
1756 // components into account.
Arun Patoleab2b9a22015-07-06 18:27:56 +05301757
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001758 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuahof119a262016-08-19 15:54:22 +03001759 ASSERT(operandArray);
Jamie Madillb1a85f42014-08-19 15:23:24 -04001760
1761 size_t objectSize = getType().getObjectSize();
1762
Arun Patoleab2b9a22015-07-06 18:27:56 +05301763 TConstantUnion *resultArray = new TConstantUnion[objectSize];
1764 for (size_t i = 0; i < objectSize; i++)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301765 {
Arun Patoleab2b9a22015-07-06 18:27:56 +05301766 switch(op)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301767 {
Olli Etuahof119a262016-08-19 15:54:22 +03001768 case EOpNegative:
1769 switch (getType().getBasicType())
1770 {
1771 case EbtFloat:
1772 resultArray[i].setFConst(-operandArray[i].getFConst());
1773 break;
1774 case EbtInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01001775 if (operandArray[i] == std::numeric_limits<int>::min())
1776 {
1777 // The minimum representable integer doesn't have a positive
1778 // counterpart, rather the negation overflows and in ESSL is supposed to
1779 // wrap back to the minimum representable integer. Make sure that we
1780 // don't actually let the negation overflow, which has undefined
1781 // behavior in C++.
1782 resultArray[i].setIConst(std::numeric_limits<int>::min());
1783 }
1784 else
1785 {
1786 resultArray[i].setIConst(-operandArray[i].getIConst());
1787 }
Olli Etuahof119a262016-08-19 15:54:22 +03001788 break;
1789 case EbtUInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01001790 if (operandArray[i] == 0x80000000u)
1791 {
1792 resultArray[i].setUConst(0x80000000u);
1793 }
1794 else
1795 {
1796 resultArray[i].setUConst(static_cast<unsigned int>(
1797 -static_cast<int>(operandArray[i].getUConst())));
1798 }
Olli Etuahof119a262016-08-19 15:54:22 +03001799 break;
1800 default:
1801 UNREACHABLE();
1802 return nullptr;
1803 }
Arun Patole1155ddd2015-06-05 18:04:36 +05301804 break;
Arun Patolecdfa8f52015-06-30 17:48:25 +05301805
Olli Etuahof119a262016-08-19 15:54:22 +03001806 case EOpPositive:
1807 switch (getType().getBasicType())
1808 {
1809 case EbtFloat:
1810 resultArray[i].setFConst(operandArray[i].getFConst());
1811 break;
1812 case EbtInt:
1813 resultArray[i].setIConst(operandArray[i].getIConst());
1814 break;
1815 case EbtUInt:
1816 resultArray[i].setUConst(static_cast<unsigned int>(
1817 static_cast<int>(operandArray[i].getUConst())));
1818 break;
1819 default:
1820 UNREACHABLE();
1821 return nullptr;
1822 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301823 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301824
Olli Etuahof119a262016-08-19 15:54:22 +03001825 case EOpLogicalNot:
1826 switch (getType().getBasicType())
1827 {
1828 case EbtBool:
1829 resultArray[i].setBConst(!operandArray[i].getBConst());
1830 break;
1831 default:
1832 UNREACHABLE();
1833 return nullptr;
1834 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301835 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301836
Olli Etuahof119a262016-08-19 15:54:22 +03001837 case EOpBitwiseNot:
1838 switch (getType().getBasicType())
1839 {
1840 case EbtInt:
1841 resultArray[i].setIConst(~operandArray[i].getIConst());
1842 break;
1843 case EbtUInt:
1844 resultArray[i].setUConst(~operandArray[i].getUConst());
1845 break;
1846 default:
1847 UNREACHABLE();
1848 return nullptr;
1849 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301850 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301851
Olli Etuahof119a262016-08-19 15:54:22 +03001852 case EOpRadians:
1853 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301854 resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
1855 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301856
Olli Etuahof119a262016-08-19 15:54:22 +03001857 case EOpDegrees:
1858 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301859 resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
1860 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301861
Olli Etuahof119a262016-08-19 15:54:22 +03001862 case EOpSin:
1863 foldFloatTypeUnary(operandArray[i], &sinf, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301864 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301865
Olli Etuahof119a262016-08-19 15:54:22 +03001866 case EOpCos:
1867 foldFloatTypeUnary(operandArray[i], &cosf, &resultArray[i]);
1868 break;
1869
1870 case EOpTan:
1871 foldFloatTypeUnary(operandArray[i], &tanf, &resultArray[i]);
1872 break;
1873
1874 case EOpAsin:
1875 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to
1876 // 0.
1877 if (fabsf(operandArray[i].getFConst()) > 1.0f)
1878 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1879 diagnostics, &resultArray[i]);
1880 else
1881 foldFloatTypeUnary(operandArray[i], &asinf, &resultArray[i]);
1882 break;
1883
1884 case EOpAcos:
1885 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to
1886 // 0.
1887 if (fabsf(operandArray[i].getFConst()) > 1.0f)
1888 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1889 diagnostics, &resultArray[i]);
1890 else
1891 foldFloatTypeUnary(operandArray[i], &acosf, &resultArray[i]);
1892 break;
1893
1894 case EOpAtan:
1895 foldFloatTypeUnary(operandArray[i], &atanf, &resultArray[i]);
1896 break;
1897
1898 case EOpSinh:
1899 foldFloatTypeUnary(operandArray[i], &sinhf, &resultArray[i]);
1900 break;
1901
1902 case EOpCosh:
1903 foldFloatTypeUnary(operandArray[i], &coshf, &resultArray[i]);
1904 break;
1905
1906 case EOpTanh:
1907 foldFloatTypeUnary(operandArray[i], &tanhf, &resultArray[i]);
1908 break;
1909
1910 case EOpAsinh:
1911 foldFloatTypeUnary(operandArray[i], &asinhf, &resultArray[i]);
1912 break;
1913
1914 case EOpAcosh:
1915 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
1916 if (operandArray[i].getFConst() < 1.0f)
1917 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1918 diagnostics, &resultArray[i]);
1919 else
1920 foldFloatTypeUnary(operandArray[i], &acoshf, &resultArray[i]);
1921 break;
1922
1923 case EOpAtanh:
1924 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to
1925 // 0.
1926 if (fabsf(operandArray[i].getFConst()) >= 1.0f)
1927 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1928 diagnostics, &resultArray[i]);
1929 else
1930 foldFloatTypeUnary(operandArray[i], &atanhf, &resultArray[i]);
1931 break;
1932
1933 case EOpAbs:
1934 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05301935 {
Olli Etuahof119a262016-08-19 15:54:22 +03001936 case EbtFloat:
1937 resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
1938 break;
1939 case EbtInt:
1940 resultArray[i].setIConst(abs(operandArray[i].getIConst()));
1941 break;
1942 default:
1943 UNREACHABLE();
1944 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301945 }
1946 break;
Olli Etuahof119a262016-08-19 15:54:22 +03001947
1948 case EOpSign:
1949 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05301950 {
Olli Etuahof119a262016-08-19 15:54:22 +03001951 case EbtFloat:
1952 {
1953 float fConst = operandArray[i].getFConst();
1954 float fResult = 0.0f;
1955 if (fConst > 0.0f)
1956 fResult = 1.0f;
1957 else if (fConst < 0.0f)
1958 fResult = -1.0f;
1959 resultArray[i].setFConst(fResult);
1960 break;
1961 }
1962 case EbtInt:
1963 {
1964 int iConst = operandArray[i].getIConst();
1965 int iResult = 0;
1966 if (iConst > 0)
1967 iResult = 1;
1968 else if (iConst < 0)
1969 iResult = -1;
1970 resultArray[i].setIConst(iResult);
1971 break;
1972 }
1973 default:
1974 UNREACHABLE();
1975 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301976 }
1977 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301978
Olli Etuahof119a262016-08-19 15:54:22 +03001979 case EOpFloor:
1980 foldFloatTypeUnary(operandArray[i], &floorf, &resultArray[i]);
1981 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301982
Olli Etuahof119a262016-08-19 15:54:22 +03001983 case EOpTrunc:
1984 foldFloatTypeUnary(operandArray[i], &truncf, &resultArray[i]);
1985 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301986
Olli Etuahof119a262016-08-19 15:54:22 +03001987 case EOpRound:
1988 foldFloatTypeUnary(operandArray[i], &roundf, &resultArray[i]);
1989 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301990
Olli Etuahof119a262016-08-19 15:54:22 +03001991 case EOpRoundEven:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301992 {
Olli Etuahof119a262016-08-19 15:54:22 +03001993 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301994 float x = operandArray[i].getFConst();
1995 float result;
1996 float fractPart = modff(x, &result);
1997 if (fabsf(fractPart) == 0.5f)
1998 result = 2.0f * roundf(x / 2.0f);
1999 else
2000 result = roundf(x);
2001 resultArray[i].setFConst(result);
2002 break;
2003 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302004
Olli Etuahof119a262016-08-19 15:54:22 +03002005 case EOpCeil:
2006 foldFloatTypeUnary(operandArray[i], &ceilf, &resultArray[i]);
2007 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302008
Olli Etuahof119a262016-08-19 15:54:22 +03002009 case EOpFract:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302010 {
Olli Etuahof119a262016-08-19 15:54:22 +03002011 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302012 float x = operandArray[i].getFConst();
2013 resultArray[i].setFConst(x - floorf(x));
2014 break;
2015 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302016
Olli Etuahof119a262016-08-19 15:54:22 +03002017 case EOpIsNan:
2018 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302019 resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst()));
2020 break;
Arun Patole551279e2015-07-07 18:18:23 +05302021
Olli Etuahof119a262016-08-19 15:54:22 +03002022 case EOpIsInf:
2023 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302024 resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst()));
2025 break;
Arun Patole551279e2015-07-07 18:18:23 +05302026
Olli Etuahof119a262016-08-19 15:54:22 +03002027 case EOpFloatBitsToInt:
2028 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302029 resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst()));
2030 break;
Arun Patole551279e2015-07-07 18:18:23 +05302031
Olli Etuahof119a262016-08-19 15:54:22 +03002032 case EOpFloatBitsToUint:
2033 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302034 resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst()));
2035 break;
Arun Patole551279e2015-07-07 18:18:23 +05302036
Olli Etuahof119a262016-08-19 15:54:22 +03002037 case EOpIntBitsToFloat:
2038 ASSERT(getType().getBasicType() == EbtInt);
Arun Patole551279e2015-07-07 18:18:23 +05302039 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst()));
2040 break;
Arun Patole551279e2015-07-07 18:18:23 +05302041
Olli Etuahof119a262016-08-19 15:54:22 +03002042 case EOpUintBitsToFloat:
2043 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patole551279e2015-07-07 18:18:23 +05302044 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst()));
2045 break;
Arun Patole551279e2015-07-07 18:18:23 +05302046
Olli Etuahof119a262016-08-19 15:54:22 +03002047 case EOpExp:
2048 foldFloatTypeUnary(operandArray[i], &expf, &resultArray[i]);
2049 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302050
Olli Etuahof119a262016-08-19 15:54:22 +03002051 case EOpLog:
2052 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
2053 if (operandArray[i].getFConst() <= 0.0f)
2054 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2055 diagnostics, &resultArray[i]);
2056 else
2057 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2058 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302059
Olli Etuahof119a262016-08-19 15:54:22 +03002060 case EOpExp2:
2061 foldFloatTypeUnary(operandArray[i], &exp2f, &resultArray[i]);
2062 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302063
Olli Etuahof119a262016-08-19 15:54:22 +03002064 case EOpLog2:
2065 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
2066 // And log2f is not available on some plarforms like old android, so just using
2067 // log(x)/log(2) here.
2068 if (operandArray[i].getFConst() <= 0.0f)
2069 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2070 diagnostics, &resultArray[i]);
2071 else
2072 {
2073 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2074 resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
2075 }
2076 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302077
Olli Etuahof119a262016-08-19 15:54:22 +03002078 case EOpSqrt:
2079 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
2080 if (operandArray[i].getFConst() < 0.0f)
2081 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2082 diagnostics, &resultArray[i]);
2083 else
2084 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2085 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302086
Olli Etuahof119a262016-08-19 15:54:22 +03002087 case EOpInverseSqrt:
2088 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
2089 // so getting the square root first using builtin function sqrt() and then taking
2090 // its inverse.
2091 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set
2092 // result to 0.
2093 if (operandArray[i].getFConst() <= 0.0f)
2094 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2095 diagnostics, &resultArray[i]);
2096 else
2097 {
2098 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2099 resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
2100 }
2101 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302102
Olli Etuahof119a262016-08-19 15:54:22 +03002103 case EOpVectorLogicalNot:
2104 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302105 resultArray[i].setBConst(!operandArray[i].getBConst());
2106 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302107
Olli Etuahof119a262016-08-19 15:54:22 +03002108 case EOpNormalize:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302109 {
Olli Etuahof119a262016-08-19 15:54:22 +03002110 ASSERT(getType().getBasicType() == EbtFloat);
2111 float x = operandArray[i].getFConst();
Arun Patoleab2b9a22015-07-06 18:27:56 +05302112 float length = VectorLength(operandArray, objectSize);
2113 if (length)
2114 resultArray[i].setFConst(x / length);
2115 else
Olli Etuahof119a262016-08-19 15:54:22 +03002116 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2117 diagnostics, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302118 break;
2119 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302120
Olli Etuahof119a262016-08-19 15:54:22 +03002121 case EOpDFdx:
2122 case EOpDFdy:
2123 case EOpFwidth:
2124 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole0c5409f2015-07-08 15:17:53 +05302125 // Derivatives of constant arguments should be 0.
2126 resultArray[i].setFConst(0.0f);
2127 break;
Arun Patole0c5409f2015-07-08 15:17:53 +05302128
Olli Etuahof119a262016-08-19 15:54:22 +03002129 default:
2130 return nullptr;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302131 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302132 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04002133
Arun Patoleab2b9a22015-07-06 18:27:56 +05302134 return resultArray;
Jamie Madillb1a85f42014-08-19 15:23:24 -04002135}
2136
Olli Etuahof119a262016-08-19 15:54:22 +03002137void TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter,
2138 FloatTypeUnaryFunc builtinFunc,
2139 TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05302140{
2141 ASSERT(builtinFunc);
2142
Olli Etuahof119a262016-08-19 15:54:22 +03002143 ASSERT(getType().getBasicType() == EbtFloat);
2144 result->setFConst(builtinFunc(parameter.getFConst()));
Arun Patole9dea48f2015-04-02 11:45:09 +05302145}
2146
Jamie Madillb1a85f42014-08-19 15:23:24 -04002147// static
Olli Etuahof119a262016-08-19 15:54:22 +03002148TConstantUnion *TIntermConstantUnion::FoldAggregateConstructor(TIntermAggregate *aggregate)
Olli Etuaho1d122782015-11-06 15:35:17 +02002149{
2150 ASSERT(aggregate->getSequence()->size() > 0u);
2151 size_t resultSize = aggregate->getType().getObjectSize();
2152 TConstantUnion *resultArray = new TConstantUnion[resultSize];
2153 TBasicType basicType = aggregate->getBasicType();
2154
2155 size_t resultIndex = 0u;
2156
2157 if (aggregate->getSequence()->size() == 1u)
2158 {
2159 TIntermNode *argument = aggregate->getSequence()->front();
2160 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
2161 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
2162 // Check the special case of constructing a matrix diagonal from a single scalar,
2163 // or a vector from a single scalar.
2164 if (argumentConstant->getType().getObjectSize() == 1u)
2165 {
2166 if (aggregate->isMatrix())
2167 {
2168 int resultCols = aggregate->getType().getCols();
2169 int resultRows = aggregate->getType().getRows();
2170 for (int col = 0; col < resultCols; ++col)
2171 {
2172 for (int row = 0; row < resultRows; ++row)
2173 {
2174 if (col == row)
2175 {
2176 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
2177 }
2178 else
2179 {
2180 resultArray[resultIndex].setFConst(0.0f);
2181 }
2182 ++resultIndex;
2183 }
2184 }
2185 }
2186 else
2187 {
2188 while (resultIndex < resultSize)
2189 {
2190 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
2191 ++resultIndex;
2192 }
2193 }
2194 ASSERT(resultIndex == resultSize);
2195 return resultArray;
2196 }
2197 else if (aggregate->isMatrix() && argumentConstant->isMatrix())
2198 {
2199 // The special case of constructing a matrix from a matrix.
2200 int argumentCols = argumentConstant->getType().getCols();
2201 int argumentRows = argumentConstant->getType().getRows();
2202 int resultCols = aggregate->getType().getCols();
2203 int resultRows = aggregate->getType().getRows();
2204 for (int col = 0; col < resultCols; ++col)
2205 {
2206 for (int row = 0; row < resultRows; ++row)
2207 {
2208 if (col < argumentCols && row < argumentRows)
2209 {
2210 resultArray[resultIndex].cast(basicType,
2211 argumentUnionArray[col * argumentRows + row]);
2212 }
2213 else if (col == row)
2214 {
2215 resultArray[resultIndex].setFConst(1.0f);
2216 }
2217 else
2218 {
2219 resultArray[resultIndex].setFConst(0.0f);
2220 }
2221 ++resultIndex;
2222 }
2223 }
2224 ASSERT(resultIndex == resultSize);
2225 return resultArray;
2226 }
2227 }
2228
2229 for (TIntermNode *&argument : *aggregate->getSequence())
2230 {
2231 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
2232 size_t argumentSize = argumentConstant->getType().getObjectSize();
2233 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
2234 for (size_t i = 0u; i < argumentSize; ++i)
2235 {
2236 if (resultIndex >= resultSize)
2237 break;
2238 resultArray[resultIndex].cast(basicType, argumentUnionArray[i]);
2239 ++resultIndex;
2240 }
2241 }
2242 ASSERT(resultIndex == resultSize);
2243 return resultArray;
2244}
2245
2246// static
Olli Etuahof119a262016-08-19 15:54:22 +03002247TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate,
2248 TDiagnostics *diagnostics)
Arun Patole274f0702015-05-05 13:33:30 +05302249{
Olli Etuahob43846e2015-06-02 18:18:57 +03002250 TOperator op = aggregate->getOp();
Arun Patole274f0702015-05-05 13:33:30 +05302251 TIntermSequence *sequence = aggregate->getSequence();
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002252 unsigned int paramsCount = static_cast<unsigned int>(sequence->size());
Olli Etuaho5c0e0232015-11-11 15:55:59 +02002253 std::vector<const TConstantUnion *> unionArrays(paramsCount);
Arun Patole274f0702015-05-05 13:33:30 +05302254 std::vector<size_t> objectSizes(paramsCount);
Olli Etuahob43846e2015-06-02 18:18:57 +03002255 size_t maxObjectSize = 0;
Arun Patole274f0702015-05-05 13:33:30 +05302256 TBasicType basicType = EbtVoid;
2257 TSourceLoc loc;
2258 for (unsigned int i = 0; i < paramsCount; i++)
2259 {
2260 TIntermConstantUnion *paramConstant = (*sequence)[i]->getAsConstantUnion();
Olli Etuahob43846e2015-06-02 18:18:57 +03002261 ASSERT(paramConstant != nullptr); // Should be checked already.
Arun Patole274f0702015-05-05 13:33:30 +05302262
2263 if (i == 0)
2264 {
2265 basicType = paramConstant->getType().getBasicType();
2266 loc = paramConstant->getLine();
2267 }
2268 unionArrays[i] = paramConstant->getUnionArrayPointer();
2269 objectSizes[i] = paramConstant->getType().getObjectSize();
Olli Etuahob43846e2015-06-02 18:18:57 +03002270 if (objectSizes[i] > maxObjectSize)
2271 maxObjectSize = objectSizes[i];
Arun Patole274f0702015-05-05 13:33:30 +05302272 }
2273
Olli Etuahod5da5052016-08-29 13:16:55 +03002274 if (!(*sequence)[0]->getAsTyped()->isMatrix() && aggregate->getOp() != EOpOuterProduct)
Arun Patole7fa33552015-06-10 15:15:18 +05302275 {
2276 for (unsigned int i = 0; i < paramsCount; i++)
2277 if (objectSizes[i] != maxObjectSize)
2278 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
2279 }
Arun Patole274f0702015-05-05 13:33:30 +05302280
Olli Etuahob43846e2015-06-02 18:18:57 +03002281 TConstantUnion *resultArray = nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05302282 if (paramsCount == 2)
2283 {
2284 //
2285 // Binary built-in
2286 //
2287 switch (op)
2288 {
Olli Etuahof119a262016-08-19 15:54:22 +03002289 case EOpAtan:
Arun Patolebf790422015-05-18 17:53:04 +05302290 {
Olli Etuahof119a262016-08-19 15:54:22 +03002291 ASSERT(basicType == EbtFloat);
2292 resultArray = new TConstantUnion[maxObjectSize];
2293 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302294 {
Olli Etuahof119a262016-08-19 15:54:22 +03002295 float y = unionArrays[0][i].getFConst();
2296 float x = unionArrays[1][i].getFConst();
2297 // Results are undefined if x and y are both 0.
2298 if (x == 0.0f && y == 0.0f)
2299 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2300 &resultArray[i]);
2301 else
2302 resultArray[i].setFConst(atan2f(y, x));
Arun Patolebf790422015-05-18 17:53:04 +05302303 }
Olli Etuahof119a262016-08-19 15:54:22 +03002304 break;
Arun Patolebf790422015-05-18 17:53:04 +05302305 }
Arun Patolebf790422015-05-18 17:53:04 +05302306
Olli Etuahof119a262016-08-19 15:54:22 +03002307 case EOpPow:
Arun Patolebf790422015-05-18 17:53:04 +05302308 {
Olli Etuahof119a262016-08-19 15:54:22 +03002309 ASSERT(basicType == EbtFloat);
2310 resultArray = new TConstantUnion[maxObjectSize];
2311 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302312 {
Olli Etuahof119a262016-08-19 15:54:22 +03002313 float x = unionArrays[0][i].getFConst();
2314 float y = unionArrays[1][i].getFConst();
2315 // Results are undefined if x < 0.
2316 // Results are undefined if x = 0 and y <= 0.
2317 if (x < 0.0f)
2318 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2319 &resultArray[i]);
2320 else if (x == 0.0f && y <= 0.0f)
2321 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2322 &resultArray[i]);
2323 else
2324 resultArray[i].setFConst(powf(x, y));
Arun Patolebf790422015-05-18 17:53:04 +05302325 }
Olli Etuahof119a262016-08-19 15:54:22 +03002326 break;
Arun Patolebf790422015-05-18 17:53:04 +05302327 }
Arun Patolebf790422015-05-18 17:53:04 +05302328
Olli Etuahof119a262016-08-19 15:54:22 +03002329 case EOpMod:
Arun Patolebf790422015-05-18 17:53:04 +05302330 {
Olli Etuahof119a262016-08-19 15:54:22 +03002331 ASSERT(basicType == EbtFloat);
2332 resultArray = new TConstantUnion[maxObjectSize];
2333 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302334 {
Olli Etuahof119a262016-08-19 15:54:22 +03002335 float x = unionArrays[0][i].getFConst();
2336 float y = unionArrays[1][i].getFConst();
2337 resultArray[i].setFConst(x - y * floorf(x / y));
Arun Patolebf790422015-05-18 17:53:04 +05302338 }
Olli Etuahof119a262016-08-19 15:54:22 +03002339 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 EOpMin:
Arun Patole274f0702015-05-05 13:33:30 +05302343 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002344 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +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].setFConst(std::min(unionArrays[0][i].getFConst(),
2351 unionArrays[1][i].getFConst()));
2352 break;
2353 case EbtInt:
2354 resultArray[i].setIConst(std::min(unionArrays[0][i].getIConst(),
2355 unionArrays[1][i].getIConst()));
2356 break;
2357 case EbtUInt:
2358 resultArray[i].setUConst(std::min(unionArrays[0][i].getUConst(),
2359 unionArrays[1][i].getUConst()));
2360 break;
2361 default:
2362 UNREACHABLE();
2363 break;
Arun Patole274f0702015-05-05 13:33:30 +05302364 }
2365 }
Olli Etuahof119a262016-08-19 15:54:22 +03002366 break;
Arun Patole274f0702015-05-05 13:33:30 +05302367 }
Arun Patole274f0702015-05-05 13:33:30 +05302368
Olli Etuahof119a262016-08-19 15:54:22 +03002369 case EOpMax:
Arun Patole274f0702015-05-05 13:33:30 +05302370 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002371 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +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].setFConst(std::max(unionArrays[0][i].getFConst(),
2378 unionArrays[1][i].getFConst()));
2379 break;
2380 case EbtInt:
2381 resultArray[i].setIConst(std::max(unionArrays[0][i].getIConst(),
2382 unionArrays[1][i].getIConst()));
2383 break;
2384 case EbtUInt:
2385 resultArray[i].setUConst(std::max(unionArrays[0][i].getUConst(),
2386 unionArrays[1][i].getUConst()));
2387 break;
2388 default:
2389 UNREACHABLE();
2390 break;
Arun Patole274f0702015-05-05 13:33:30 +05302391 }
2392 }
Olli Etuahof119a262016-08-19 15:54:22 +03002393 break;
Arun Patole274f0702015-05-05 13:33:30 +05302394 }
Arun Patole274f0702015-05-05 13:33:30 +05302395
Olli Etuahof119a262016-08-19 15:54:22 +03002396 case EOpStep:
Arun Patolebf790422015-05-18 17:53:04 +05302397 {
Olli Etuahof119a262016-08-19 15:54:22 +03002398 ASSERT(basicType == EbtFloat);
2399 resultArray = new TConstantUnion[maxObjectSize];
2400 for (size_t i = 0; i < maxObjectSize; i++)
2401 resultArray[i].setFConst(
2402 unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f
2403 : 1.0f);
2404 break;
Arun Patolebf790422015-05-18 17:53:04 +05302405 }
Arun Patolebf790422015-05-18 17:53:04 +05302406
Olli Etuahof119a262016-08-19 15:54:22 +03002407 case EOpLessThan:
Arun Patole9d0b1f92015-05-20 14:27:17 +05302408 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002409 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302410 for (size_t i = 0; i < maxObjectSize; i++)
2411 {
2412 switch (basicType)
2413 {
Olli Etuahof119a262016-08-19 15:54:22 +03002414 case EbtFloat:
2415 resultArray[i].setBConst(unionArrays[0][i].getFConst() <
2416 unionArrays[1][i].getFConst());
2417 break;
2418 case EbtInt:
2419 resultArray[i].setBConst(unionArrays[0][i].getIConst() <
2420 unionArrays[1][i].getIConst());
2421 break;
2422 case EbtUInt:
2423 resultArray[i].setBConst(unionArrays[0][i].getUConst() <
2424 unionArrays[1][i].getUConst());
2425 break;
2426 default:
2427 UNREACHABLE();
2428 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302429 }
2430 }
Olli Etuahof119a262016-08-19 15:54:22 +03002431 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302432 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302433
Olli Etuahof119a262016-08-19 15:54:22 +03002434 case EOpLessThanEqual:
Arun Patole9d0b1f92015-05-20 14:27:17 +05302435 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002436 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302437 for (size_t i = 0; i < maxObjectSize; i++)
2438 {
2439 switch (basicType)
2440 {
Olli Etuahof119a262016-08-19 15:54:22 +03002441 case EbtFloat:
2442 resultArray[i].setBConst(unionArrays[0][i].getFConst() <=
2443 unionArrays[1][i].getFConst());
2444 break;
2445 case EbtInt:
2446 resultArray[i].setBConst(unionArrays[0][i].getIConst() <=
2447 unionArrays[1][i].getIConst());
2448 break;
2449 case EbtUInt:
2450 resultArray[i].setBConst(unionArrays[0][i].getUConst() <=
2451 unionArrays[1][i].getUConst());
2452 break;
2453 default:
2454 UNREACHABLE();
2455 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302456 }
2457 }
Olli Etuahof119a262016-08-19 15:54:22 +03002458 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302459 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302460
Olli Etuahof119a262016-08-19 15:54:22 +03002461 case EOpGreaterThan:
Arun Patole9d0b1f92015-05-20 14:27:17 +05302462 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002463 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302464 for (size_t i = 0; i < maxObjectSize; i++)
2465 {
2466 switch (basicType)
2467 {
Olli Etuahof119a262016-08-19 15:54:22 +03002468 case EbtFloat:
2469 resultArray[i].setBConst(unionArrays[0][i].getFConst() >
2470 unionArrays[1][i].getFConst());
2471 break;
2472 case EbtInt:
2473 resultArray[i].setBConst(unionArrays[0][i].getIConst() >
2474 unionArrays[1][i].getIConst());
2475 break;
2476 case EbtUInt:
2477 resultArray[i].setBConst(unionArrays[0][i].getUConst() >
2478 unionArrays[1][i].getUConst());
2479 break;
2480 default:
2481 UNREACHABLE();
2482 break;
Olli Etuahob43846e2015-06-02 18:18:57 +03002483 }
2484 }
Olli Etuahof119a262016-08-19 15:54:22 +03002485 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302486 }
Olli Etuahof119a262016-08-19 15:54:22 +03002487 case EOpGreaterThanEqual:
Arun Patole9d0b1f92015-05-20 14:27:17 +05302488 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002489 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302490 for (size_t i = 0; i < maxObjectSize; i++)
2491 {
2492 switch (basicType)
2493 {
Olli Etuahof119a262016-08-19 15:54:22 +03002494 case EbtFloat:
2495 resultArray[i].setBConst(unionArrays[0][i].getFConst() >=
2496 unionArrays[1][i].getFConst());
2497 break;
2498 case EbtInt:
2499 resultArray[i].setBConst(unionArrays[0][i].getIConst() >=
2500 unionArrays[1][i].getIConst());
2501 break;
2502 case EbtUInt:
2503 resultArray[i].setBConst(unionArrays[0][i].getUConst() >=
2504 unionArrays[1][i].getUConst());
2505 break;
2506 default:
2507 UNREACHABLE();
2508 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302509 }
2510 }
2511 }
2512 break;
2513
Olli Etuahof119a262016-08-19 15:54:22 +03002514 case EOpVectorEqual:
Arun Patole9d0b1f92015-05-20 14:27:17 +05302515 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002516 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302517 for (size_t i = 0; i < maxObjectSize; i++)
2518 {
2519 switch (basicType)
2520 {
Olli Etuahof119a262016-08-19 15:54:22 +03002521 case EbtFloat:
2522 resultArray[i].setBConst(unionArrays[0][i].getFConst() ==
2523 unionArrays[1][i].getFConst());
2524 break;
2525 case EbtInt:
2526 resultArray[i].setBConst(unionArrays[0][i].getIConst() ==
2527 unionArrays[1][i].getIConst());
2528 break;
2529 case EbtUInt:
2530 resultArray[i].setBConst(unionArrays[0][i].getUConst() ==
2531 unionArrays[1][i].getUConst());
2532 break;
2533 case EbtBool:
2534 resultArray[i].setBConst(unionArrays[0][i].getBConst() ==
2535 unionArrays[1][i].getBConst());
2536 break;
2537 default:
2538 UNREACHABLE();
2539 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302540 }
2541 }
Olli Etuahof119a262016-08-19 15:54:22 +03002542 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302543 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302544
Olli Etuahof119a262016-08-19 15:54:22 +03002545 case EOpVectorNotEqual:
Arun Patole9d0b1f92015-05-20 14:27:17 +05302546 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002547 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302548 for (size_t i = 0; i < maxObjectSize; i++)
2549 {
2550 switch (basicType)
2551 {
Olli Etuahof119a262016-08-19 15:54:22 +03002552 case EbtFloat:
2553 resultArray[i].setBConst(unionArrays[0][i].getFConst() !=
2554 unionArrays[1][i].getFConst());
2555 break;
2556 case EbtInt:
2557 resultArray[i].setBConst(unionArrays[0][i].getIConst() !=
2558 unionArrays[1][i].getIConst());
2559 break;
2560 case EbtUInt:
2561 resultArray[i].setBConst(unionArrays[0][i].getUConst() !=
2562 unionArrays[1][i].getUConst());
2563 break;
2564 case EbtBool:
2565 resultArray[i].setBConst(unionArrays[0][i].getBConst() !=
2566 unionArrays[1][i].getBConst());
2567 break;
2568 default:
2569 UNREACHABLE();
2570 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302571 }
2572 }
Olli Etuahof119a262016-08-19 15:54:22 +03002573 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302574 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302575
Olli Etuahof119a262016-08-19 15:54:22 +03002576 case EOpDistance:
Arun Patole1155ddd2015-06-05 18:04:36 +05302577 {
Olli Etuahof119a262016-08-19 15:54:22 +03002578 ASSERT(basicType == EbtFloat);
Arun Patole1155ddd2015-06-05 18:04:36 +05302579 TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
Olli Etuahof119a262016-08-19 15:54:22 +03002580 resultArray = new TConstantUnion();
Arun Patole1155ddd2015-06-05 18:04:36 +05302581 for (size_t i = 0; i < maxObjectSize; i++)
2582 {
2583 float x = unionArrays[0][i].getFConst();
2584 float y = unionArrays[1][i].getFConst();
2585 distanceArray[i].setFConst(x - y);
2586 }
Olli Etuahob43846e2015-06-02 18:18:57 +03002587 resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
Olli Etuahof119a262016-08-19 15:54:22 +03002588 break;
Arun Patole1155ddd2015-06-05 18:04:36 +05302589 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302590
Olli Etuahof119a262016-08-19 15:54:22 +03002591 case EOpDot:
2592 ASSERT(basicType == EbtFloat);
Olli Etuahob43846e2015-06-02 18:18:57 +03002593 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03002594 resultArray->setFConst(
2595 VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
2596 break;
Arun Patole1155ddd2015-06-05 18:04:36 +05302597
Olli Etuahof119a262016-08-19 15:54:22 +03002598 case EOpCross:
Arun Patole1155ddd2015-06-05 18:04:36 +05302599 {
Olli Etuahof119a262016-08-19 15:54:22 +03002600 ASSERT(basicType == EbtFloat && maxObjectSize == 3);
Olli Etuahob43846e2015-06-02 18:18:57 +03002601 resultArray = new TConstantUnion[maxObjectSize];
Olli Etuahof119a262016-08-19 15:54:22 +03002602 float x0 = unionArrays[0][0].getFConst();
2603 float x1 = unionArrays[0][1].getFConst();
2604 float x2 = unionArrays[0][2].getFConst();
2605 float y0 = unionArrays[1][0].getFConst();
2606 float y1 = unionArrays[1][1].getFConst();
2607 float y2 = unionArrays[1][2].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002608 resultArray[0].setFConst(x1 * y2 - y1 * x2);
2609 resultArray[1].setFConst(x2 * y0 - y2 * x0);
2610 resultArray[2].setFConst(x0 * y1 - y0 * x1);
Olli Etuahof119a262016-08-19 15:54:22 +03002611 break;
Arun Patole1155ddd2015-06-05 18:04:36 +05302612 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302613
Olli Etuahof119a262016-08-19 15:54:22 +03002614 case EOpReflect:
Arun Patole1155ddd2015-06-05 18:04:36 +05302615 {
Olli Etuahof119a262016-08-19 15:54:22 +03002616 ASSERT(basicType == EbtFloat);
Arun Patole1155ddd2015-06-05 18:04:36 +05302617 // genType reflect (genType I, genType N) :
Olli Etuahof119a262016-08-19 15:54:22 +03002618 // For the incident vector I and surface orientation N, returns the reflection
2619 // direction:
Arun Patole1155ddd2015-06-05 18:04:36 +05302620 // I - 2 * dot(N, I) * N.
Olli Etuahof119a262016-08-19 15:54:22 +03002621 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302622 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2623 for (size_t i = 0; i < maxObjectSize; i++)
2624 {
2625 float result = unionArrays[0][i].getFConst() -
2626 2.0f * dotProduct * unionArrays[1][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002627 resultArray[i].setFConst(result);
Arun Patole1155ddd2015-06-05 18:04:36 +05302628 }
Olli Etuahof119a262016-08-19 15:54:22 +03002629 break;
Arun Patole1155ddd2015-06-05 18:04:36 +05302630 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302631
Olli Etuahof119a262016-08-19 15:54:22 +03002632 case EOpMul:
Arun Patole7fa33552015-06-10 15:15:18 +05302633 {
Olli Etuahof119a262016-08-19 15:54:22 +03002634 ASSERT(basicType == EbtFloat && (*sequence)[0]->getAsTyped()->isMatrix() &&
2635 (*sequence)[1]->getAsTyped()->isMatrix());
Arun Patole7fa33552015-06-10 15:15:18 +05302636 // Perform component-wise matrix multiplication.
2637 resultArray = new TConstantUnion[maxObjectSize];
Olli Etuahof119a262016-08-19 15:54:22 +03002638 int size = (*sequence)[0]->getAsTyped()->getNominalSize();
Arun Patole7fa33552015-06-10 15:15:18 +05302639 angle::Matrix<float> result =
2640 GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size));
2641 SetUnionArrayFromMatrix(result, resultArray);
Olli Etuahof119a262016-08-19 15:54:22 +03002642 break;
Arun Patole7fa33552015-06-10 15:15:18 +05302643 }
Arun Patole7fa33552015-06-10 15:15:18 +05302644
Olli Etuahof119a262016-08-19 15:54:22 +03002645 case EOpOuterProduct:
Arun Patole7fa33552015-06-10 15:15:18 +05302646 {
Olli Etuahof119a262016-08-19 15:54:22 +03002647 ASSERT(basicType == EbtFloat);
Arun Patole7fa33552015-06-10 15:15:18 +05302648 size_t numRows = (*sequence)[0]->getAsTyped()->getType().getObjectSize();
2649 size_t numCols = (*sequence)[1]->getAsTyped()->getType().getObjectSize();
Olli Etuahof119a262016-08-19 15:54:22 +03002650 resultArray = new TConstantUnion[numRows * numCols];
Arun Patole7fa33552015-06-10 15:15:18 +05302651 angle::Matrix<float> result =
Olli Etuahod5da5052016-08-29 13:16:55 +03002652 GetMatrix(unionArrays[0], static_cast<int>(numRows), 1)
2653 .outerProduct(GetMatrix(unionArrays[1], 1, static_cast<int>(numCols)));
Arun Patole7fa33552015-06-10 15:15:18 +05302654 SetUnionArrayFromMatrix(result, resultArray);
Olli Etuahof119a262016-08-19 15:54:22 +03002655 break;
Arun Patole7fa33552015-06-10 15:15:18 +05302656 }
Arun Patole7fa33552015-06-10 15:15:18 +05302657
Olli Etuahof119a262016-08-19 15:54:22 +03002658 default:
2659 UNREACHABLE();
2660 // TODO: Add constant folding support for other built-in operations that take 2
2661 // parameters and not handled above.
2662 return nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05302663 }
2664 }
2665 else if (paramsCount == 3)
2666 {
2667 //
2668 // Ternary built-in
2669 //
2670 switch (op)
2671 {
Olli Etuahof119a262016-08-19 15:54:22 +03002672 case EOpClamp:
Arun Patole274f0702015-05-05 13:33:30 +05302673 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002674 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302675 for (size_t i = 0; i < maxObjectSize; i++)
2676 {
2677 switch (basicType)
2678 {
Olli Etuahof119a262016-08-19 15:54:22 +03002679 case EbtFloat:
Arun Patole274f0702015-05-05 13:33:30 +05302680 {
Olli Etuahof119a262016-08-19 15:54:22 +03002681 float x = unionArrays[0][i].getFConst();
Arun Patole274f0702015-05-05 13:33:30 +05302682 float min = unionArrays[1][i].getFConst();
2683 float max = unionArrays[2][i].getFConst();
2684 // Results are undefined if min > max.
2685 if (min > max)
Olli Etuahof119a262016-08-19 15:54:22 +03002686 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2687 &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302688 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002689 resultArray[i].setFConst(gl::clamp(x, min, max));
Olli Etuahof119a262016-08-19 15:54:22 +03002690 break;
Arun Patole274f0702015-05-05 13:33:30 +05302691 }
Olli Etuahof119a262016-08-19 15:54:22 +03002692
2693 case EbtInt:
Arun Patole274f0702015-05-05 13:33:30 +05302694 {
Olli Etuahof119a262016-08-19 15:54:22 +03002695 int x = unionArrays[0][i].getIConst();
Arun Patole274f0702015-05-05 13:33:30 +05302696 int min = unionArrays[1][i].getIConst();
2697 int max = unionArrays[2][i].getIConst();
2698 // Results are undefined if min > max.
2699 if (min > max)
Olli Etuahof119a262016-08-19 15:54:22 +03002700 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2701 &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302702 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002703 resultArray[i].setIConst(gl::clamp(x, min, max));
Olli Etuahof119a262016-08-19 15:54:22 +03002704 break;
Arun Patole274f0702015-05-05 13:33:30 +05302705 }
Olli Etuahof119a262016-08-19 15:54:22 +03002706 case EbtUInt:
Arun Patole274f0702015-05-05 13:33:30 +05302707 {
Olli Etuahof119a262016-08-19 15:54:22 +03002708 unsigned int x = unionArrays[0][i].getUConst();
Arun Patole274f0702015-05-05 13:33:30 +05302709 unsigned int min = unionArrays[1][i].getUConst();
2710 unsigned int max = unionArrays[2][i].getUConst();
2711 // Results are undefined if min > max.
2712 if (min > max)
Olli Etuahof119a262016-08-19 15:54:22 +03002713 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2714 &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302715 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002716 resultArray[i].setUConst(gl::clamp(x, min, max));
Olli Etuahof119a262016-08-19 15:54:22 +03002717 break;
Arun Patole274f0702015-05-05 13:33:30 +05302718 }
Olli Etuahof119a262016-08-19 15:54:22 +03002719 default:
2720 UNREACHABLE();
2721 break;
Arun Patole274f0702015-05-05 13:33:30 +05302722 }
2723 }
Olli Etuahof119a262016-08-19 15:54:22 +03002724 break;
Arun Patole274f0702015-05-05 13:33:30 +05302725 }
Arun Patole274f0702015-05-05 13:33:30 +05302726
Olli Etuahof119a262016-08-19 15:54:22 +03002727 case EOpMix:
Arun Patolebf790422015-05-18 17:53:04 +05302728 {
Olli Etuahof119a262016-08-19 15:54:22 +03002729 ASSERT(basicType == EbtFloat);
2730 resultArray = new TConstantUnion[maxObjectSize];
2731 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302732 {
Olli Etuahof119a262016-08-19 15:54:22 +03002733 float x = unionArrays[0][i].getFConst();
2734 float y = unionArrays[1][i].getFConst();
2735 TBasicType type = (*sequence)[2]->getAsTyped()->getType().getBasicType();
2736 if (type == EbtFloat)
Arun Patolebf790422015-05-18 17:53:04 +05302737 {
Olli Etuahof119a262016-08-19 15:54:22 +03002738 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
2739 float a = unionArrays[2][i].getFConst();
2740 resultArray[i].setFConst(x * (1.0f - a) + y * a);
2741 }
2742 else // 3rd parameter is EbtBool
2743 {
2744 ASSERT(type == EbtBool);
2745 // Selects which vector each returned component comes from.
2746 // For a component of a that is false, the corresponding component of x is
2747 // returned.
2748 // For a component of a that is true, the corresponding component of y is
2749 // returned.
2750 bool a = unionArrays[2][i].getBConst();
2751 resultArray[i].setFConst(a ? y : x);
Arun Patolebf790422015-05-18 17:53:04 +05302752 }
2753 }
Olli Etuahof119a262016-08-19 15:54:22 +03002754 break;
Arun Patolebf790422015-05-18 17:53:04 +05302755 }
Arun Patolebf790422015-05-18 17:53:04 +05302756
Olli Etuahof119a262016-08-19 15:54:22 +03002757 case EOpSmoothStep:
Arun Patolebf790422015-05-18 17:53:04 +05302758 {
Olli Etuahof119a262016-08-19 15:54:22 +03002759 ASSERT(basicType == EbtFloat);
2760 resultArray = new TConstantUnion[maxObjectSize];
2761 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302762 {
Olli Etuahof119a262016-08-19 15:54:22 +03002763 float edge0 = unionArrays[0][i].getFConst();
2764 float edge1 = unionArrays[1][i].getFConst();
2765 float x = unionArrays[2][i].getFConst();
2766 // Results are undefined if edge0 >= edge1.
2767 if (edge0 >= edge1)
Arun Patolebf790422015-05-18 17:53:04 +05302768 {
Olli Etuahof119a262016-08-19 15:54:22 +03002769 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2770 &resultArray[i]);
2771 }
2772 else
2773 {
2774 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
2775 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
2776 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
2777 resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
Arun Patolebf790422015-05-18 17:53:04 +05302778 }
2779 }
Olli Etuahof119a262016-08-19 15:54:22 +03002780 break;
Arun Patolebf790422015-05-18 17:53:04 +05302781 }
Arun Patolebf790422015-05-18 17:53:04 +05302782
Olli Etuahof119a262016-08-19 15:54:22 +03002783 case EOpFaceForward:
Arun Patole1155ddd2015-06-05 18:04:36 +05302784 {
Olli Etuahof119a262016-08-19 15:54:22 +03002785 ASSERT(basicType == EbtFloat);
Arun Patole1155ddd2015-06-05 18:04:36 +05302786 // genType faceforward(genType N, genType I, genType Nref) :
2787 // If dot(Nref, I) < 0 return N, otherwise return -N.
Olli Etuahof119a262016-08-19 15:54:22 +03002788 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302789 float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
2790 for (size_t i = 0; i < maxObjectSize; i++)
2791 {
2792 if (dotProduct < 0)
Olli Etuahob43846e2015-06-02 18:18:57 +03002793 resultArray[i].setFConst(unionArrays[0][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302794 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002795 resultArray[i].setFConst(-unionArrays[0][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302796 }
Olli Etuahof119a262016-08-19 15:54:22 +03002797 break;
Arun Patole1155ddd2015-06-05 18:04:36 +05302798 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302799
Olli Etuahof119a262016-08-19 15:54:22 +03002800 case EOpRefract:
Arun Patole1155ddd2015-06-05 18:04:36 +05302801 {
Olli Etuahof119a262016-08-19 15:54:22 +03002802 ASSERT(basicType == EbtFloat);
Arun Patole1155ddd2015-06-05 18:04:36 +05302803 // genType refract(genType I, genType N, float eta) :
Olli Etuahof119a262016-08-19 15:54:22 +03002804 // For the incident vector I and surface normal N, and the ratio of indices of
2805 // refraction eta,
Arun Patole1155ddd2015-06-05 18:04:36 +05302806 // return the refraction vector. The result is computed by
2807 // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
2808 // if (k < 0.0)
2809 // return genType(0.0)
2810 // else
2811 // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
Olli Etuahof119a262016-08-19 15:54:22 +03002812 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302813 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2814 for (size_t i = 0; i < maxObjectSize; i++)
2815 {
2816 float eta = unionArrays[2][i].getFConst();
Olli Etuahof119a262016-08-19 15:54:22 +03002817 float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
Arun Patole1155ddd2015-06-05 18:04:36 +05302818 if (k < 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03002819 resultArray[i].setFConst(0.0f);
Arun Patole1155ddd2015-06-05 18:04:36 +05302820 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002821 resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
Olli Etuahof119a262016-08-19 15:54:22 +03002822 (eta * dotProduct + sqrtf(k)) *
2823 unionArrays[1][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302824 }
Olli Etuahof119a262016-08-19 15:54:22 +03002825 break;
Arun Patole1155ddd2015-06-05 18:04:36 +05302826 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302827
Olli Etuahof119a262016-08-19 15:54:22 +03002828 default:
2829 UNREACHABLE();
2830 // TODO: Add constant folding support for other built-in operations that take 3
2831 // parameters and not handled above.
2832 return nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05302833 }
2834 }
Olli Etuahob43846e2015-06-02 18:18:57 +03002835 return resultArray;
Arun Patole274f0702015-05-05 13:33:30 +05302836}
2837
2838// static
Jamie Madillb1a85f42014-08-19 15:23:24 -04002839TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunction)
2840{
2841 if (hashFunction == NULL || name.empty())
2842 return name;
2843 khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
2844 TStringStream stream;
2845 stream << HASHED_NAME_PREFIX << std::hex << number;
2846 TString hashedName = stream.str();
2847 return hashedName;
2848}
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002849
2850void TIntermTraverser::updateTree()
2851{
Olli Etuahoa6f22092015-05-08 18:31:10 +03002852 for (size_t ii = 0; ii < mInsertions.size(); ++ii)
2853 {
2854 const NodeInsertMultipleEntry &insertion = mInsertions[ii];
2855 ASSERT(insertion.parent);
Olli Etuaho5d91dda2015-06-18 15:47:46 +03002856 if (!insertion.insertionsAfter.empty())
2857 {
2858 bool inserted = insertion.parent->insertChildNodes(insertion.position + 1,
2859 insertion.insertionsAfter);
2860 ASSERT(inserted);
Olli Etuaho5d91dda2015-06-18 15:47:46 +03002861 }
2862 if (!insertion.insertionsBefore.empty())
2863 {
2864 bool inserted =
2865 insertion.parent->insertChildNodes(insertion.position, insertion.insertionsBefore);
2866 ASSERT(inserted);
Olli Etuaho5d91dda2015-06-18 15:47:46 +03002867 }
Olli Etuahoa6f22092015-05-08 18:31:10 +03002868 }
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002869 for (size_t ii = 0; ii < mReplacements.size(); ++ii)
2870 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002871 const NodeUpdateEntry &replacement = mReplacements[ii];
2872 ASSERT(replacement.parent);
2873 bool replaced = replacement.parent->replaceChildNode(
2874 replacement.original, replacement.replacement);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002875 ASSERT(replaced);
2876
Olli Etuahocd94ef92015-04-16 19:18:10 +03002877 if (!replacement.originalBecomesChildOfReplacement)
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002878 {
2879 // In AST traversing, a parent is visited before its children.
Olli Etuahocd94ef92015-04-16 19:18:10 +03002880 // After we replace a node, if its immediate child is to
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002881 // be replaced, we need to make sure we don't update the replaced
2882 // node; instead, we update the replacement node.
2883 for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj)
2884 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002885 NodeUpdateEntry &replacement2 = mReplacements[jj];
2886 if (replacement2.parent == replacement.original)
2887 replacement2.parent = replacement.replacement;
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002888 }
2889 }
2890 }
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002891 for (size_t ii = 0; ii < mMultiReplacements.size(); ++ii)
2892 {
2893 const NodeReplaceWithMultipleEntry &replacement = mMultiReplacements[ii];
2894 ASSERT(replacement.parent);
2895 bool replaced = replacement.parent->replaceChildNodeWithMultiple(
2896 replacement.original, replacement.replacements);
2897 ASSERT(replaced);
2898 }
Olli Etuahod4f303e2015-05-20 17:09:06 +03002899
Jamie Madill03d863c2016-07-27 18:15:53 -04002900 clearReplacementQueue();
2901}
2902
2903void TIntermTraverser::clearReplacementQueue()
2904{
Olli Etuahod4f303e2015-05-20 17:09:06 +03002905 mReplacements.clear();
2906 mMultiReplacements.clear();
Jamie Madill03d863c2016-07-27 18:15:53 -04002907 mInsertions.clear();
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002908}
Jamie Madill1048e432016-07-23 18:51:28 -04002909
Jamie Madill03d863c2016-07-27 18:15:53 -04002910void TIntermTraverser::queueReplacement(TIntermNode *original,
2911 TIntermNode *replacement,
2912 OriginalNode originalStatus)
Jamie Madill1048e432016-07-23 18:51:28 -04002913{
Jamie Madill03d863c2016-07-27 18:15:53 -04002914 queueReplacementWithParent(getParentNode(), original, replacement, originalStatus);
Jamie Madill1048e432016-07-23 18:51:28 -04002915}
2916
Jamie Madill03d863c2016-07-27 18:15:53 -04002917void TIntermTraverser::queueReplacementWithParent(TIntermNode *parent,
2918 TIntermNode *original,
2919 TIntermNode *replacement,
2920 OriginalNode originalStatus)
Jamie Madill1048e432016-07-23 18:51:28 -04002921{
Jamie Madill03d863c2016-07-27 18:15:53 -04002922 bool originalBecomesChild = (originalStatus == OriginalNode::BECOMES_CHILD);
2923 mReplacements.push_back(NodeUpdateEntry(parent, original, replacement, originalBecomesChild));
Jamie Madill1048e432016-07-23 18:51:28 -04002924}
Jamie Madill45bcc782016-11-07 13:58:48 -05002925
2926} // namespace sh